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; 78*a108557bSHannes Reinecke sg_io_hdr_t *io_hdr = &r->io_header; 7949ab747fSPaolo Bonzini 80fa0d653bSPaolo Bonzini assert(r->req.aiocb == NULL); 81fa0d653bSPaolo Bonzini 826c25fa6cSFam Zheng if (r->req.io_canceled) { 83d5776465SFam Zheng scsi_req_cancel_complete(&r->req); 846c25fa6cSFam Zheng goto done; 856c25fa6cSFam Zheng } 86*a108557bSHannes Reinecke if (ret < 0) { 87*a108557bSHannes Reinecke status = scsi_sense_from_errno(-ret, &sense); 881ead6b4eSPaolo Bonzini if (status == CHECK_CONDITION) { 891ead6b4eSPaolo Bonzini scsi_req_build_sense(&r->req, sense); 901ead6b4eSPaolo Bonzini } 91*a108557bSHannes Reinecke } else if (io_hdr->host_status != SCSI_HOST_OK) { 92*a108557bSHannes Reinecke status = scsi_sense_from_host_status(io_hdr->host_status, &sense); 93*a108557bSHannes Reinecke if (status == CHECK_CONDITION) { 94*a108557bSHannes Reinecke scsi_req_build_sense(&r->req, sense); 9549ab747fSPaolo Bonzini } 96*a108557bSHannes Reinecke } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { 97*a108557bSHannes Reinecke status = BUSY; 98*a108557bSHannes Reinecke } else { 99*a108557bSHannes Reinecke status = io_hdr->status; 100*a108557bSHannes Reinecke if (io_hdr->driver_status & SG_ERR_DRIVER_SENSE) { 101*a108557bSHannes Reinecke r->req.sense_len = io_hdr->sb_len_wr; 102*a108557bSHannes Reinecke } 103*a108557bSHannes Reinecke } 10456853498SLaurent Vivier trace_scsi_generic_command_complete_noio(r, r->req.tag, status); 10549ab747fSPaolo Bonzini 10649ab747fSPaolo Bonzini scsi_req_complete(&r->req, status); 1076c25fa6cSFam Zheng done: 10849ab747fSPaolo Bonzini scsi_req_unref(&r->req); 10949ab747fSPaolo Bonzini } 11049ab747fSPaolo Bonzini 111fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret) 112fa0d653bSPaolo Bonzini { 113fa0d653bSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 114b9e413ddSPaolo Bonzini SCSIDevice *s = r->req.dev; 115fa0d653bSPaolo Bonzini 116fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 117fa0d653bSPaolo Bonzini r->req.aiocb = NULL; 118b9e413ddSPaolo Bonzini 119b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 120fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 121b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 122fa0d653bSPaolo Bonzini } 123fa0d653bSPaolo Bonzini 1244be74634SMarkus Armbruster static int execute_command(BlockBackend *blk, 12549ab747fSPaolo Bonzini SCSIGenericReq *r, int direction, 126097310b5SMarkus Armbruster BlockCompletionFunc *complete) 12749ab747fSPaolo Bonzini { 128c9b6609bSHannes Reinecke SCSIDevice *s = r->req.dev; 129c9b6609bSHannes Reinecke 13049ab747fSPaolo Bonzini r->io_header.interface_id = 'S'; 13149ab747fSPaolo Bonzini r->io_header.dxfer_direction = direction; 13249ab747fSPaolo Bonzini r->io_header.dxferp = r->buf; 13349ab747fSPaolo Bonzini r->io_header.dxfer_len = r->buflen; 13449ab747fSPaolo Bonzini r->io_header.cmdp = r->req.cmd.buf; 13549ab747fSPaolo Bonzini r->io_header.cmd_len = r->req.cmd.len; 13649ab747fSPaolo Bonzini r->io_header.mx_sb_len = sizeof(r->req.sense); 13749ab747fSPaolo Bonzini r->io_header.sbp = r->req.sense; 138c9b6609bSHannes Reinecke r->io_header.timeout = s->io_timeout * 1000; 13949ab747fSPaolo Bonzini r->io_header.usr_ptr = r; 14049ab747fSPaolo Bonzini r->io_header.flags |= SG_FLAG_DIRECT_IO; 14149ab747fSPaolo Bonzini 142b2d50a33SHannes Reinecke trace_scsi_generic_aio_sgio_command(r->req.tag, r->req.cmd.buf[0], 143b2d50a33SHannes Reinecke r->io_header.timeout); 1444be74634SMarkus Armbruster r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r); 145d836f8d3SPavel Hrdina if (r->req.aiocb == NULL) { 146d836f8d3SPavel Hrdina return -EIO; 147d836f8d3SPavel Hrdina } 14849ab747fSPaolo Bonzini 14949ab747fSPaolo Bonzini return 0; 15049ab747fSPaolo Bonzini } 15149ab747fSPaolo Bonzini 1520a96ca24SDaniel Henrique Barboza static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) 1530a96ca24SDaniel Henrique Barboza { 1546c219fc8SPaolo Bonzini uint8_t page, page_idx; 155a71c775bSDaniel Henrique Barboza 1560a96ca24SDaniel Henrique Barboza /* 1570a96ca24SDaniel Henrique Barboza * EVPD set to zero returns the standard INQUIRY data. 1580a96ca24SDaniel Henrique Barboza * 1590a96ca24SDaniel Henrique Barboza * Check if scsi_version is unset (-1) to avoid re-defining it 1600a96ca24SDaniel Henrique Barboza * each time an INQUIRY with standard data is received. 1610a96ca24SDaniel Henrique Barboza * scsi_version is initialized with -1 in scsi_generic_reset 1620a96ca24SDaniel Henrique Barboza * and scsi_disk_reset, making sure that we'll set the 1630a96ca24SDaniel Henrique Barboza * scsi_version after a reset. If the version field of the 1640a96ca24SDaniel Henrique Barboza * INQUIRY response somehow changes after a guest reboot, 1650a96ca24SDaniel Henrique Barboza * we'll be able to keep track of it. 1660a96ca24SDaniel Henrique Barboza * 1670a96ca24SDaniel Henrique Barboza * On SCSI-2 and older, first 3 bits of byte 2 is the 1680a96ca24SDaniel Henrique Barboza * ANSI-approved version, while on later versions the 1690a96ca24SDaniel Henrique Barboza * whole byte 2 contains the version. Check if we're dealing 1700a96ca24SDaniel Henrique Barboza * with a newer version and, in that case, assign the 1710a96ca24SDaniel Henrique Barboza * whole byte. 1720a96ca24SDaniel Henrique Barboza */ 1730a96ca24SDaniel Henrique Barboza if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) { 1740a96ca24SDaniel Henrique Barboza s->scsi_version = r->buf[2] & 0x07; 1750a96ca24SDaniel Henrique Barboza if (s->scsi_version > 2) { 1760a96ca24SDaniel Henrique Barboza s->scsi_version = r->buf[2]; 1770a96ca24SDaniel Henrique Barboza } 1780a96ca24SDaniel Henrique Barboza } 179a71c775bSDaniel Henrique Barboza 180afff2db6SDmitry Fomichev if ((s->type == TYPE_DISK || s->type == TYPE_ZBC) && 181afff2db6SDmitry Fomichev (r->req.cmd.buf[1] & 0x01)) { 182a71c775bSDaniel Henrique Barboza page = r->req.cmd.buf[2]; 183a71c775bSDaniel Henrique Barboza if (page == 0xb0) { 1840a96ca24SDaniel Henrique Barboza uint32_t max_transfer = 1850a96ca24SDaniel Henrique Barboza blk_get_max_transfer(s->conf.blk) / s->blocksize; 1860a96ca24SDaniel Henrique Barboza 1870a96ca24SDaniel Henrique Barboza assert(max_transfer); 1880a96ca24SDaniel Henrique Barboza stl_be_p(&r->buf[8], max_transfer); 1890a96ca24SDaniel Henrique Barboza /* Also take care of the opt xfer len. */ 1900a96ca24SDaniel Henrique Barboza stl_be_p(&r->buf[12], 1910a96ca24SDaniel Henrique Barboza MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); 192e909ff93SPaolo Bonzini } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) { 193a71c775bSDaniel Henrique Barboza /* 194a71c775bSDaniel Henrique Barboza * Now we're capable of supplying the VPD Block Limits 195a71c775bSDaniel Henrique Barboza * response if the hardware can't. Add it in the INQUIRY 196a71c775bSDaniel Henrique Barboza * Supported VPD pages response in case we are using the 197a71c775bSDaniel Henrique Barboza * emulation for this device. 198a71c775bSDaniel Henrique Barboza * 199a71c775bSDaniel Henrique Barboza * This way, the guest kernel will be aware of the support 200a71c775bSDaniel Henrique Barboza * and will use it to proper setup the SCSI device. 2016c219fc8SPaolo Bonzini * 2026c219fc8SPaolo Bonzini * VPD page numbers must be sorted, so insert 0xb0 at the 203e909ff93SPaolo Bonzini * right place with an in-place insert. When the while loop 204e909ff93SPaolo Bonzini * begins the device response is at r[0] to r[page_idx - 1]. 205a71c775bSDaniel Henrique Barboza */ 206e909ff93SPaolo Bonzini page_idx = lduw_be_p(r->buf + 2) + 4; 207e909ff93SPaolo Bonzini page_idx = MIN(page_idx, r->buflen); 208e909ff93SPaolo Bonzini while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) { 2096c219fc8SPaolo Bonzini if (page_idx < r->buflen) { 2106c219fc8SPaolo Bonzini r->buf[page_idx] = r->buf[page_idx - 1]; 2116c219fc8SPaolo Bonzini } 212e909ff93SPaolo Bonzini page_idx--; 2136c219fc8SPaolo Bonzini } 214e909ff93SPaolo Bonzini if (page_idx < r->buflen) { 2156c219fc8SPaolo Bonzini r->buf[page_idx] = 0xb0; 216e909ff93SPaolo Bonzini } 2176c219fc8SPaolo Bonzini stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1); 2180a96ca24SDaniel Henrique Barboza } 2190a96ca24SDaniel Henrique Barboza } 220a71c775bSDaniel Henrique Barboza } 221a71c775bSDaniel Henrique Barboza 2223d4a8bf0SPaolo Bonzini static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) 223a71c775bSDaniel Henrique Barboza { 2243d4a8bf0SPaolo Bonzini int len; 2253d4a8bf0SPaolo Bonzini uint8_t buf[64]; 2263d4a8bf0SPaolo Bonzini 2273d4a8bf0SPaolo Bonzini SCSIBlockLimits bl = { 2283d4a8bf0SPaolo Bonzini .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize 2293d4a8bf0SPaolo Bonzini }; 2303d4a8bf0SPaolo Bonzini 2313d4a8bf0SPaolo Bonzini memset(r->buf, 0, r->buflen); 2323d4a8bf0SPaolo Bonzini stb_p(buf, s->type); 2333d4a8bf0SPaolo Bonzini stb_p(buf + 1, 0xb0); 2343d4a8bf0SPaolo Bonzini len = scsi_emulate_block_limits(buf + 4, &bl); 2353d4a8bf0SPaolo Bonzini assert(len <= sizeof(buf) - 4); 2363d4a8bf0SPaolo Bonzini stw_be_p(buf + 2, len); 2373d4a8bf0SPaolo Bonzini 2383d4a8bf0SPaolo Bonzini memcpy(r->buf, buf, MIN(r->buflen, len + 4)); 2393d4a8bf0SPaolo Bonzini 240a71c775bSDaniel Henrique Barboza r->io_header.sb_len_wr = 0; 241a71c775bSDaniel Henrique Barboza 242a71c775bSDaniel Henrique Barboza /* 243a71c775bSDaniel Henrique Barboza * We have valid contents in the reply buffer but the 244a71c775bSDaniel Henrique Barboza * io_header can report a sense error coming from 245a71c775bSDaniel Henrique Barboza * the hardware in scsi_command_complete_noio. Clean 246a71c775bSDaniel Henrique Barboza * up the io_header to avoid reporting it. 247a71c775bSDaniel Henrique Barboza */ 248a71c775bSDaniel Henrique Barboza r->io_header.driver_status = 0; 249a71c775bSDaniel Henrique Barboza r->io_header.status = 0; 250a71c775bSDaniel Henrique Barboza 251a71c775bSDaniel Henrique Barboza return r->buflen; 252a71c775bSDaniel Henrique Barboza } 2530a96ca24SDaniel Henrique Barboza 25449ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret) 25549ab747fSPaolo Bonzini { 25649ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 25749ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 25849ab747fSPaolo Bonzini int len; 25949ab747fSPaolo Bonzini 260fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 26149ab747fSPaolo Bonzini r->req.aiocb = NULL; 262fa0d653bSPaolo Bonzini 263b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 264b9e413ddSPaolo Bonzini 2656c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 266fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 267b9e413ddSPaolo Bonzini goto done; 26849ab747fSPaolo Bonzini } 269fa0d653bSPaolo Bonzini 27049ab747fSPaolo Bonzini len = r->io_header.dxfer_len - r->io_header.resid; 27156853498SLaurent Vivier trace_scsi_generic_read_complete(r->req.tag, len); 27249ab747fSPaolo Bonzini 27349ab747fSPaolo Bonzini r->len = -1; 274a71c775bSDaniel Henrique Barboza 2751849f297SShin'ichiro Kawasaki if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 2761849f297SShin'ichiro Kawasaki SCSISense sense = 2771849f297SShin'ichiro Kawasaki scsi_parse_sense_buf(r->req.sense, r->io_header.sb_len_wr); 2781849f297SShin'ichiro Kawasaki 279a71c775bSDaniel Henrique Barboza /* 280a71c775bSDaniel Henrique Barboza * Check if this is a VPD Block Limits request that 281a71c775bSDaniel Henrique Barboza * resulted in sense error but would need emulation. 282a71c775bSDaniel Henrique Barboza * In this case, emulate a valid VPD response. 283a71c775bSDaniel Henrique Barboza */ 2841849f297SShin'ichiro Kawasaki if (sense.key == ILLEGAL_REQUEST && 2851849f297SShin'ichiro Kawasaki s->needs_vpd_bl_emulation && 2863d4a8bf0SPaolo Bonzini r->req.cmd.buf[0] == INQUIRY && 2873d4a8bf0SPaolo Bonzini (r->req.cmd.buf[1] & 0x01) && 2883d4a8bf0SPaolo Bonzini r->req.cmd.buf[2] == 0xb0) { 2893d4a8bf0SPaolo Bonzini len = scsi_generic_emulate_block_limits(r, s); 290a71c775bSDaniel Henrique Barboza /* 2911849f297SShin'ichiro Kawasaki * It's okay to jup to req_complete: no need to 2921849f297SShin'ichiro Kawasaki * let scsi_handle_inquiry_reply handle an 293a71c775bSDaniel Henrique Barboza * INQUIRY VPD BL request we created manually. 294a71c775bSDaniel Henrique Barboza */ 2951849f297SShin'ichiro Kawasaki } 2961849f297SShin'ichiro Kawasaki if (sense.key) { 297a71c775bSDaniel Henrique Barboza goto req_complete; 298a71c775bSDaniel Henrique Barboza } 299a71c775bSDaniel Henrique Barboza } 300a71c775bSDaniel Henrique Barboza 3019738c657SPaolo Bonzini if (r->io_header.host_status != SCSI_HOST_OK || 3029738c657SPaolo Bonzini (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) || 3039738c657SPaolo Bonzini r->io_header.status != GOOD || 3049738c657SPaolo Bonzini len == 0) { 305fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 306b9e413ddSPaolo Bonzini goto done; 307fa0d653bSPaolo Bonzini } 308fa0d653bSPaolo Bonzini 30949ab747fSPaolo Bonzini /* Snoop READ CAPACITY output to set the blocksize. */ 31053254e56SPaolo Bonzini if (r->req.cmd.buf[0] == READ_CAPACITY_10 && 31153254e56SPaolo Bonzini (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { 31249ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[4]); 31353254e56SPaolo Bonzini s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; 31449ab747fSPaolo Bonzini } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && 31549ab747fSPaolo Bonzini (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { 31649ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[8]); 31749ab747fSPaolo Bonzini s->max_lba = ldq_be_p(&r->buf[0]); 31849ab747fSPaolo Bonzini } 3194be74634SMarkus Armbruster blk_set_guest_block_size(s->conf.blk, s->blocksize); 32049ab747fSPaolo Bonzini 321afff2db6SDmitry Fomichev /* 322afff2db6SDmitry Fomichev * Patch MODE SENSE device specific parameters if the BDS is opened 3230eb2baebSPaolo Bonzini * readonly. 3240eb2baebSPaolo Bonzini */ 325afff2db6SDmitry Fomichev if ((s->type == TYPE_DISK || s->type == TYPE_TAPE || s->type == TYPE_ZBC) && 32686b1cf32SKevin Wolf !blk_is_writable(s->conf.blk) && 3270eb2baebSPaolo Bonzini (r->req.cmd.buf[0] == MODE_SENSE || 3280eb2baebSPaolo Bonzini r->req.cmd.buf[0] == MODE_SENSE_10) && 3290eb2baebSPaolo Bonzini (r->req.cmd.buf[1] & 0x8) == 0) { 3300eb2baebSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SENSE) { 3310eb2baebSPaolo Bonzini r->buf[2] |= 0x80; 3320eb2baebSPaolo Bonzini } else { 3330eb2baebSPaolo Bonzini r->buf[3] |= 0x80; 3340eb2baebSPaolo Bonzini } 3350eb2baebSPaolo Bonzini } 33629e560f0SDaniel Henrique Barboza if (r->req.cmd.buf[0] == INQUIRY) { 3370a96ca24SDaniel Henrique Barboza scsi_handle_inquiry_reply(r, s); 33829e560f0SDaniel Henrique Barboza } 339a71c775bSDaniel Henrique Barboza 340a71c775bSDaniel Henrique Barboza req_complete: 34149ab747fSPaolo Bonzini scsi_req_data(&r->req, len); 34249ab747fSPaolo Bonzini scsi_req_unref(&r->req); 343b9e413ddSPaolo Bonzini 344b9e413ddSPaolo Bonzini done: 345b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 34649ab747fSPaolo Bonzini } 34749ab747fSPaolo Bonzini 34849ab747fSPaolo Bonzini /* Read more data from scsi device into buffer. */ 34949ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req) 35049ab747fSPaolo Bonzini { 35149ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 35249ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 35349ab747fSPaolo Bonzini int ret; 35449ab747fSPaolo Bonzini 35556853498SLaurent Vivier trace_scsi_generic_read_data(req->tag); 35649ab747fSPaolo Bonzini 35749ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 35849ab747fSPaolo Bonzini scsi_req_ref(&r->req); 35949ab747fSPaolo Bonzini if (r->len == -1) { 360fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 36149ab747fSPaolo Bonzini return; 36249ab747fSPaolo Bonzini } 36349ab747fSPaolo Bonzini 3644be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV, 3654be74634SMarkus Armbruster scsi_read_complete); 36649ab747fSPaolo Bonzini if (ret < 0) { 367fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 36849ab747fSPaolo Bonzini } 36949ab747fSPaolo Bonzini } 37049ab747fSPaolo Bonzini 37149ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret) 37249ab747fSPaolo Bonzini { 37349ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 37449ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 37549ab747fSPaolo Bonzini 37656853498SLaurent Vivier trace_scsi_generic_write_complete(ret); 377fa0d653bSPaolo Bonzini 378fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 37949ab747fSPaolo Bonzini r->req.aiocb = NULL; 380fa0d653bSPaolo Bonzini 381b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 382b9e413ddSPaolo Bonzini 3836c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 384fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 385b9e413ddSPaolo Bonzini goto done; 38649ab747fSPaolo Bonzini } 38749ab747fSPaolo Bonzini 38849ab747fSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && 38949ab747fSPaolo Bonzini s->type == TYPE_TAPE) { 39049ab747fSPaolo Bonzini s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; 39156853498SLaurent Vivier trace_scsi_generic_write_complete_blocksize(s->blocksize); 39249ab747fSPaolo Bonzini } 39349ab747fSPaolo Bonzini 394fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 395b9e413ddSPaolo Bonzini 396b9e413ddSPaolo Bonzini done: 397b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 39849ab747fSPaolo Bonzini } 39949ab747fSPaolo Bonzini 40049ab747fSPaolo Bonzini /* Write data to a scsi device. Returns nonzero on failure. 40149ab747fSPaolo Bonzini The transfer may complete asynchronously. */ 40249ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req) 40349ab747fSPaolo Bonzini { 40449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 40549ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 40649ab747fSPaolo Bonzini int ret; 40749ab747fSPaolo Bonzini 40856853498SLaurent Vivier trace_scsi_generic_write_data(req->tag); 40949ab747fSPaolo Bonzini if (r->len == 0) { 41049ab747fSPaolo Bonzini r->len = r->buflen; 41149ab747fSPaolo Bonzini scsi_req_data(&r->req, r->len); 41249ab747fSPaolo Bonzini return; 41349ab747fSPaolo Bonzini } 41449ab747fSPaolo Bonzini 41549ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 41649ab747fSPaolo Bonzini scsi_req_ref(&r->req); 4174be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete); 41849ab747fSPaolo Bonzini if (ret < 0) { 419fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 42049ab747fSPaolo Bonzini } 42149ab747fSPaolo Bonzini } 42249ab747fSPaolo Bonzini 42349ab747fSPaolo Bonzini /* Return a pointer to the data buffer. */ 42449ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req) 42549ab747fSPaolo Bonzini { 42649ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 42749ab747fSPaolo Bonzini 42849ab747fSPaolo Bonzini return r->buf; 42949ab747fSPaolo Bonzini } 43049ab747fSPaolo Bonzini 43156853498SLaurent Vivier static void scsi_generic_command_dump(uint8_t *cmd, int len) 43256853498SLaurent Vivier { 43356853498SLaurent Vivier int i; 43456853498SLaurent Vivier char *line_buffer, *p; 43556853498SLaurent Vivier 43656853498SLaurent Vivier line_buffer = g_malloc(len * 5 + 1); 43756853498SLaurent Vivier 43856853498SLaurent Vivier for (i = 0, p = line_buffer; i < len; i++) { 43956853498SLaurent Vivier p += sprintf(p, " 0x%02x", cmd[i]); 44056853498SLaurent Vivier } 44156853498SLaurent Vivier trace_scsi_generic_send_command(line_buffer); 44256853498SLaurent Vivier 44356853498SLaurent Vivier g_free(line_buffer); 44456853498SLaurent Vivier } 44556853498SLaurent Vivier 44649ab747fSPaolo Bonzini /* Execute a scsi command. Returns the length of the data expected by the 44749ab747fSPaolo Bonzini command. This will be Positive for data transfers from the device 44849ab747fSPaolo Bonzini (eg. disk reads), negative for transfers to the device (eg. disk writes), 44949ab747fSPaolo Bonzini and zero if the command does not transfer any data. */ 45049ab747fSPaolo Bonzini 45149ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) 45249ab747fSPaolo Bonzini { 45349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 45449ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 45549ab747fSPaolo Bonzini int ret; 45649ab747fSPaolo Bonzini 45756853498SLaurent Vivier if (trace_event_get_state_backends(TRACE_SCSI_GENERIC_SEND_COMMAND)) { 45856853498SLaurent Vivier scsi_generic_command_dump(cmd, r->req.cmd.len); 45949ab747fSPaolo Bonzini } 46049ab747fSPaolo Bonzini 46149ab747fSPaolo Bonzini if (r->req.cmd.xfer == 0) { 46249ab747fSPaolo Bonzini g_free(r->buf); 46349ab747fSPaolo Bonzini r->buflen = 0; 46449ab747fSPaolo Bonzini r->buf = NULL; 46549ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 46649ab747fSPaolo Bonzini scsi_req_ref(&r->req); 4674be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_NONE, 4684be74634SMarkus Armbruster scsi_command_complete); 46949ab747fSPaolo Bonzini if (ret < 0) { 470fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 47149ab747fSPaolo Bonzini return 0; 47249ab747fSPaolo Bonzini } 47349ab747fSPaolo Bonzini return 0; 47449ab747fSPaolo Bonzini } 47549ab747fSPaolo Bonzini 47649ab747fSPaolo Bonzini if (r->buflen != r->req.cmd.xfer) { 47749ab747fSPaolo Bonzini g_free(r->buf); 47849ab747fSPaolo Bonzini r->buf = g_malloc(r->req.cmd.xfer); 47949ab747fSPaolo Bonzini r->buflen = r->req.cmd.xfer; 48049ab747fSPaolo Bonzini } 48149ab747fSPaolo Bonzini 48249ab747fSPaolo Bonzini memset(r->buf, 0, r->buflen); 48349ab747fSPaolo Bonzini r->len = r->req.cmd.xfer; 48449ab747fSPaolo Bonzini if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { 48549ab747fSPaolo Bonzini r->len = 0; 48649ab747fSPaolo Bonzini return -r->req.cmd.xfer; 48749ab747fSPaolo Bonzini } else { 48849ab747fSPaolo Bonzini return r->req.cmd.xfer; 48949ab747fSPaolo Bonzini } 49049ab747fSPaolo Bonzini } 49149ab747fSPaolo Bonzini 4929fd7e859SPaolo Bonzini static int read_naa_id(const uint8_t *p, uint64_t *p_wwn) 4939fd7e859SPaolo Bonzini { 4949fd7e859SPaolo Bonzini int i; 4959fd7e859SPaolo Bonzini 4969fd7e859SPaolo Bonzini if ((p[1] & 0xF) == 3) { 4979fd7e859SPaolo Bonzini /* NAA designator type */ 4989fd7e859SPaolo Bonzini if (p[3] != 8) { 4999fd7e859SPaolo Bonzini return -EINVAL; 5009fd7e859SPaolo Bonzini } 5019fd7e859SPaolo Bonzini *p_wwn = ldq_be_p(p + 4); 5029fd7e859SPaolo Bonzini return 0; 5039fd7e859SPaolo Bonzini } 5049fd7e859SPaolo Bonzini 5059fd7e859SPaolo Bonzini if ((p[1] & 0xF) == 8) { 5069fd7e859SPaolo Bonzini /* SCSI name string designator type */ 5079fd7e859SPaolo Bonzini if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) { 5089fd7e859SPaolo Bonzini return -EINVAL; 5099fd7e859SPaolo Bonzini } 5109fd7e859SPaolo Bonzini if (p[3] > 20 && p[24] != ',') { 5119fd7e859SPaolo Bonzini return -EINVAL; 5129fd7e859SPaolo Bonzini } 5139fd7e859SPaolo Bonzini *p_wwn = 0; 5149fd7e859SPaolo Bonzini for (i = 8; i < 24; i++) { 51595a5befcSPeter Maydell char c = qemu_toupper(p[i]); 5169fd7e859SPaolo Bonzini c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10); 5179fd7e859SPaolo Bonzini *p_wwn = (*p_wwn << 4) | c; 5189fd7e859SPaolo Bonzini } 5199fd7e859SPaolo Bonzini return 0; 5209fd7e859SPaolo Bonzini } 5219fd7e859SPaolo Bonzini 5229fd7e859SPaolo Bonzini return -EINVAL; 5239fd7e859SPaolo Bonzini } 5249fd7e859SPaolo Bonzini 525a0c7e35bSDaniel Henrique Barboza int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size, 526c9b6609bSHannes Reinecke uint8_t *buf, uint8_t buf_size, uint32_t timeout) 527a0c7e35bSDaniel Henrique Barboza { 528a0c7e35bSDaniel Henrique Barboza sg_io_hdr_t io_header; 529a0c7e35bSDaniel Henrique Barboza uint8_t sensebuf[8]; 530a0c7e35bSDaniel Henrique Barboza int ret; 531a0c7e35bSDaniel Henrique Barboza 532a0c7e35bSDaniel Henrique Barboza memset(&io_header, 0, sizeof(io_header)); 533a0c7e35bSDaniel Henrique Barboza io_header.interface_id = 'S'; 534a0c7e35bSDaniel Henrique Barboza io_header.dxfer_direction = SG_DXFER_FROM_DEV; 535a0c7e35bSDaniel Henrique Barboza io_header.dxfer_len = buf_size; 536a0c7e35bSDaniel Henrique Barboza io_header.dxferp = buf; 537a0c7e35bSDaniel Henrique Barboza io_header.cmdp = cmd; 538a0c7e35bSDaniel Henrique Barboza io_header.cmd_len = cmd_size; 539a0c7e35bSDaniel Henrique Barboza io_header.mx_sb_len = sizeof(sensebuf); 540a0c7e35bSDaniel Henrique Barboza io_header.sbp = sensebuf; 541c9b6609bSHannes Reinecke io_header.timeout = timeout * 1000; 542a0c7e35bSDaniel Henrique Barboza 543b2d50a33SHannes Reinecke trace_scsi_generic_ioctl_sgio_command(cmd[0], io_header.timeout); 544a0c7e35bSDaniel Henrique Barboza ret = blk_ioctl(blk, SG_IO, &io_header); 545b2d50a33SHannes Reinecke if (ret < 0 || io_header.status || 546b2d50a33SHannes Reinecke io_header.driver_status || io_header.host_status) { 547b2d50a33SHannes Reinecke trace_scsi_generic_ioctl_sgio_done(cmd[0], ret, io_header.status, 548b2d50a33SHannes Reinecke io_header.host_status); 549a0c7e35bSDaniel Henrique Barboza return -1; 550a0c7e35bSDaniel Henrique Barboza } 551a0c7e35bSDaniel Henrique Barboza return 0; 552a0c7e35bSDaniel Henrique Barboza } 553a0c7e35bSDaniel Henrique Barboza 554a71c775bSDaniel Henrique Barboza /* 555a71c775bSDaniel Henrique Barboza * Executes an INQUIRY request with EVPD set to retrieve the 556a71c775bSDaniel Henrique Barboza * available VPD pages of the device. If the device does 557a71c775bSDaniel Henrique Barboza * not support the Block Limits page (page 0xb0), set 558a71c775bSDaniel Henrique Barboza * the needs_vpd_bl_emulation flag for future use. 559a71c775bSDaniel Henrique Barboza */ 560a71c775bSDaniel Henrique Barboza static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s) 561a71c775bSDaniel Henrique Barboza { 562a71c775bSDaniel Henrique Barboza uint8_t cmd[6]; 563a71c775bSDaniel Henrique Barboza uint8_t buf[250]; 564a71c775bSDaniel Henrique Barboza uint8_t page_len; 565a71c775bSDaniel Henrique Barboza int ret, i; 566a71c775bSDaniel Henrique Barboza 567a71c775bSDaniel Henrique Barboza memset(cmd, 0, sizeof(cmd)); 568a71c775bSDaniel Henrique Barboza memset(buf, 0, sizeof(buf)); 569a71c775bSDaniel Henrique Barboza cmd[0] = INQUIRY; 570a71c775bSDaniel Henrique Barboza cmd[1] = 1; 571a71c775bSDaniel Henrique Barboza cmd[2] = 0x00; 572a71c775bSDaniel Henrique Barboza cmd[4] = sizeof(buf); 573a71c775bSDaniel Henrique Barboza 574a71c775bSDaniel Henrique Barboza ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), 575c9b6609bSHannes Reinecke buf, sizeof(buf), s->io_timeout); 576a71c775bSDaniel Henrique Barboza if (ret < 0) { 577a71c775bSDaniel Henrique Barboza /* 578a71c775bSDaniel Henrique Barboza * Do not assume anything if we can't retrieve the 579a71c775bSDaniel Henrique Barboza * INQUIRY response to assert the VPD Block Limits 580a71c775bSDaniel Henrique Barboza * support. 581a71c775bSDaniel Henrique Barboza */ 582a71c775bSDaniel Henrique Barboza s->needs_vpd_bl_emulation = false; 583a71c775bSDaniel Henrique Barboza return; 584a71c775bSDaniel Henrique Barboza } 585a71c775bSDaniel Henrique Barboza 586a71c775bSDaniel Henrique Barboza page_len = buf[3]; 58757dbb58dSPaolo Bonzini for (i = 4; i < MIN(sizeof(buf), page_len + 4); i++) { 588a71c775bSDaniel Henrique Barboza if (buf[i] == 0xb0) { 589a71c775bSDaniel Henrique Barboza s->needs_vpd_bl_emulation = false; 590a71c775bSDaniel Henrique Barboza return; 591a71c775bSDaniel Henrique Barboza } 592a71c775bSDaniel Henrique Barboza } 593a71c775bSDaniel Henrique Barboza s->needs_vpd_bl_emulation = true; 594a71c775bSDaniel Henrique Barboza } 595a71c775bSDaniel Henrique Barboza 596a71c775bSDaniel Henrique Barboza static void scsi_generic_read_device_identification(SCSIDevice *s) 5979fd7e859SPaolo Bonzini { 5989fd7e859SPaolo Bonzini uint8_t cmd[6]; 5999fd7e859SPaolo Bonzini uint8_t buf[250]; 6009fd7e859SPaolo Bonzini int ret; 6019fd7e859SPaolo Bonzini int i, len; 6029fd7e859SPaolo Bonzini 6039fd7e859SPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 6049fd7e859SPaolo Bonzini memset(buf, 0, sizeof(buf)); 6059fd7e859SPaolo Bonzini cmd[0] = INQUIRY; 6069fd7e859SPaolo Bonzini cmd[1] = 1; 6079fd7e859SPaolo Bonzini cmd[2] = 0x83; 6089fd7e859SPaolo Bonzini cmd[4] = sizeof(buf); 6099fd7e859SPaolo Bonzini 610a0c7e35bSDaniel Henrique Barboza ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd), 611c9b6609bSHannes Reinecke buf, sizeof(buf), s->io_timeout); 612a0c7e35bSDaniel Henrique Barboza if (ret < 0) { 6139fd7e859SPaolo Bonzini return; 6149fd7e859SPaolo Bonzini } 6159fd7e859SPaolo Bonzini 6169fd7e859SPaolo Bonzini len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4); 6179fd7e859SPaolo Bonzini for (i = 0; i + 3 <= len; ) { 6189fd7e859SPaolo Bonzini const uint8_t *p = &buf[i + 4]; 6199fd7e859SPaolo Bonzini uint64_t wwn; 6209fd7e859SPaolo Bonzini 6219fd7e859SPaolo Bonzini if (i + (p[3] + 4) > len) { 6229fd7e859SPaolo Bonzini break; 6239fd7e859SPaolo Bonzini } 6249fd7e859SPaolo Bonzini 6259fd7e859SPaolo Bonzini if ((p[1] & 0x10) == 0) { 6269fd7e859SPaolo Bonzini /* Associated with the logical unit */ 6279fd7e859SPaolo Bonzini if (read_naa_id(p, &wwn) == 0) { 6289fd7e859SPaolo Bonzini s->wwn = wwn; 6299fd7e859SPaolo Bonzini } 6309fd7e859SPaolo Bonzini } else if ((p[1] & 0x10) == 0x10) { 6319fd7e859SPaolo Bonzini /* Associated with the target port */ 6329fd7e859SPaolo Bonzini if (read_naa_id(p, &wwn) == 0) { 6339fd7e859SPaolo Bonzini s->port_wwn = wwn; 6349fd7e859SPaolo Bonzini } 6359fd7e859SPaolo Bonzini } 6369fd7e859SPaolo Bonzini 6379fd7e859SPaolo Bonzini i += p[3] + 4; 6389fd7e859SPaolo Bonzini } 6399fd7e859SPaolo Bonzini } 6409fd7e859SPaolo Bonzini 641a71c775bSDaniel Henrique Barboza void scsi_generic_read_device_inquiry(SCSIDevice *s) 642a71c775bSDaniel Henrique Barboza { 643a71c775bSDaniel Henrique Barboza scsi_generic_read_device_identification(s); 644afff2db6SDmitry Fomichev if (s->type == TYPE_DISK || s->type == TYPE_ZBC) { 645a71c775bSDaniel Henrique Barboza scsi_generic_set_vpd_bl_emulation(s); 646a71c775bSDaniel Henrique Barboza } else { 647a71c775bSDaniel Henrique Barboza s->needs_vpd_bl_emulation = false; 648a71c775bSDaniel Henrique Barboza } 649a71c775bSDaniel Henrique Barboza } 650a71c775bSDaniel Henrique Barboza 6514be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk) 65249ab747fSPaolo Bonzini { 65349ab747fSPaolo Bonzini uint8_t cmd[6]; 65449ab747fSPaolo Bonzini uint8_t buf[12]; 65549ab747fSPaolo Bonzini int ret; 65649ab747fSPaolo Bonzini 65749ab747fSPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 65849ab747fSPaolo Bonzini memset(buf, 0, sizeof(buf)); 65949ab747fSPaolo Bonzini cmd[0] = MODE_SENSE; 66049ab747fSPaolo Bonzini cmd[4] = sizeof(buf); 66149ab747fSPaolo Bonzini 662c9b6609bSHannes Reinecke ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf), 6); 663a0c7e35bSDaniel Henrique Barboza if (ret < 0) { 66449ab747fSPaolo Bonzini return -1; 66549ab747fSPaolo Bonzini } 666a0c7e35bSDaniel Henrique Barboza 66749ab747fSPaolo Bonzini return (buf[9] << 16) | (buf[10] << 8) | buf[11]; 66849ab747fSPaolo Bonzini } 66949ab747fSPaolo Bonzini 67049ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev) 67149ab747fSPaolo Bonzini { 67249ab747fSPaolo Bonzini SCSIDevice *s = SCSI_DEVICE(dev); 67349ab747fSPaolo Bonzini 6742343be0dSPaolo Bonzini s->scsi_version = s->default_scsi_version; 67549ab747fSPaolo Bonzini scsi_device_purge_requests(s, SENSE_CODE(RESET)); 67649ab747fSPaolo Bonzini } 67749ab747fSPaolo Bonzini 678a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp) 67949ab747fSPaolo Bonzini { 6806ee143a0SPaolo Bonzini int rc; 68149ab747fSPaolo Bonzini int sg_version; 68249ab747fSPaolo Bonzini struct sg_scsi_id scsiid; 68349ab747fSPaolo Bonzini 6844be74634SMarkus Armbruster if (!s->conf.blk) { 685a818a4b6SFam Zheng error_setg(errp, "drive property not set"); 686a818a4b6SFam Zheng return; 68749ab747fSPaolo Bonzini } 68849ab747fSPaolo Bonzini 689166854f7SZihao Chang if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC && 690166854f7SZihao Chang blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) { 691a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option werror"); 692a818a4b6SFam Zheng return; 69349ab747fSPaolo Bonzini } 6944be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { 695a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option rerror"); 696a818a4b6SFam Zheng return; 69749ab747fSPaolo Bonzini } 69849ab747fSPaolo Bonzini 69949ab747fSPaolo Bonzini /* check we are using a driver managing SG_IO (version 3 and after */ 7004be74634SMarkus Armbruster rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); 7016ee143a0SPaolo Bonzini if (rc < 0) { 70209c2c6ffSPaolo Bonzini error_setg_errno(errp, -rc, "cannot get SG_IO version number"); 70309c2c6ffSPaolo Bonzini if (rc != -EPERM) { 70409c2c6ffSPaolo Bonzini error_append_hint(errp, "Is this a SCSI device?\n"); 70509c2c6ffSPaolo Bonzini } 706a818a4b6SFam Zheng return; 70749ab747fSPaolo Bonzini } 70849ab747fSPaolo Bonzini if (sg_version < 30000) { 709a818a4b6SFam Zheng error_setg(errp, "scsi generic interface too old"); 710a818a4b6SFam Zheng return; 71149ab747fSPaolo Bonzini } 71249ab747fSPaolo Bonzini 71349ab747fSPaolo Bonzini /* get LUN of the /dev/sg? */ 7144be74634SMarkus Armbruster if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { 715a818a4b6SFam Zheng error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); 716a818a4b6SFam Zheng return; 71749ab747fSPaolo Bonzini } 718c6caae55SFam Zheng if (!blkconf_apply_backend_options(&s->conf, 71986b1cf32SKevin Wolf !blk_supports_write_perm(s->conf.blk), 720c6caae55SFam Zheng true, errp)) { 721d9bcd6f7SFam Zheng return; 722d9bcd6f7SFam Zheng } 72349ab747fSPaolo Bonzini 72449ab747fSPaolo Bonzini /* define device state */ 72549ab747fSPaolo Bonzini s->type = scsiid.scsi_type; 72656853498SLaurent Vivier trace_scsi_generic_realize_type(s->type); 72749ab747fSPaolo Bonzini 72849ab747fSPaolo Bonzini switch (s->type) { 72949ab747fSPaolo Bonzini case TYPE_TAPE: 7304be74634SMarkus Armbruster s->blocksize = get_stream_blocksize(s->conf.blk); 73149ab747fSPaolo Bonzini if (s->blocksize == -1) { 73249ab747fSPaolo Bonzini s->blocksize = 0; 73349ab747fSPaolo Bonzini } 73449ab747fSPaolo Bonzini break; 73549ab747fSPaolo Bonzini 73649ab747fSPaolo Bonzini /* Make a guess for block devices, we'll fix it when the guest sends. 73749ab747fSPaolo Bonzini * READ CAPACITY. If they don't, they likely would assume these sizes 73849ab747fSPaolo Bonzini * anyway. (TODO: they could also send MODE SENSE). 73949ab747fSPaolo Bonzini */ 74049ab747fSPaolo Bonzini case TYPE_ROM: 74149ab747fSPaolo Bonzini case TYPE_WORM: 74249ab747fSPaolo Bonzini s->blocksize = 2048; 74349ab747fSPaolo Bonzini break; 74449ab747fSPaolo Bonzini default: 74549ab747fSPaolo Bonzini s->blocksize = 512; 74649ab747fSPaolo Bonzini break; 74749ab747fSPaolo Bonzini } 74849ab747fSPaolo Bonzini 74956853498SLaurent Vivier trace_scsi_generic_realize_blocksize(s->blocksize); 7509fd7e859SPaolo Bonzini 75129e560f0SDaniel Henrique Barboza /* Only used by scsi-block, but initialize it nevertheless to be clean. */ 75229e560f0SDaniel Henrique Barboza s->default_scsi_version = -1; 753c9b6609bSHannes Reinecke s->io_timeout = DEFAULT_IO_TIMEOUT; 754a71c775bSDaniel Henrique Barboza scsi_generic_read_device_inquiry(s); 75549ab747fSPaolo Bonzini } 75649ab747fSPaolo Bonzini 75749ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = { 75849ab747fSPaolo Bonzini .size = sizeof(SCSIGenericReq), 75949ab747fSPaolo Bonzini .free_req = scsi_free_request, 76049ab747fSPaolo Bonzini .send_command = scsi_send_command, 76149ab747fSPaolo Bonzini .read_data = scsi_read_data, 76249ab747fSPaolo Bonzini .write_data = scsi_write_data, 76349ab747fSPaolo Bonzini .get_buf = scsi_get_buf, 76449ab747fSPaolo Bonzini .load_request = scsi_generic_load_request, 76549ab747fSPaolo Bonzini .save_request = scsi_generic_save_request, 76649ab747fSPaolo Bonzini }; 76749ab747fSPaolo Bonzini 76849ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, 76949ab747fSPaolo Bonzini uint8_t *buf, void *hba_private) 77049ab747fSPaolo Bonzini { 7719be38598SEduardo Habkost return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); 77249ab747fSPaolo Bonzini } 77349ab747fSPaolo Bonzini 77449ab747fSPaolo Bonzini static Property scsi_generic_properties[] = { 7754be74634SMarkus Armbruster DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), 776d9bcd6f7SFam Zheng DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false), 777c9b6609bSHannes Reinecke DEFINE_PROP_UINT32("io_timeout", SCSIDevice, io_timeout, 778c9b6609bSHannes Reinecke DEFAULT_IO_TIMEOUT), 77949ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 78049ab747fSPaolo Bonzini }; 78149ab747fSPaolo Bonzini 7823e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, 7833e7e180aSPaolo Bonzini uint8_t *buf, void *hba_private) 7843e7e180aSPaolo Bonzini { 7853e7e180aSPaolo Bonzini return scsi_bus_parse_cdb(dev, cmd, buf, hba_private); 7863e7e180aSPaolo Bonzini } 7873e7e180aSPaolo Bonzini 78849ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data) 78949ab747fSPaolo Bonzini { 79049ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 79149ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); 79249ab747fSPaolo Bonzini 793a818a4b6SFam Zheng sc->realize = scsi_generic_realize; 79449ab747fSPaolo Bonzini sc->alloc_req = scsi_new_request; 7953e7e180aSPaolo Bonzini sc->parse_cdb = scsi_generic_parse_cdb; 79649ab747fSPaolo Bonzini dc->fw_name = "disk"; 79749ab747fSPaolo Bonzini dc->desc = "pass through generic scsi device (/dev/sg*)"; 79849ab747fSPaolo Bonzini dc->reset = scsi_generic_reset; 7994f67d30bSMarc-André Lureau device_class_set_props(dc, scsi_generic_properties); 80049ab747fSPaolo Bonzini dc->vmsd = &vmstate_scsi_device; 80149ab747fSPaolo Bonzini } 80249ab747fSPaolo Bonzini 80349ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = { 80449ab747fSPaolo Bonzini .name = "scsi-generic", 80549ab747fSPaolo Bonzini .parent = TYPE_SCSI_DEVICE, 80649ab747fSPaolo Bonzini .instance_size = sizeof(SCSIDevice), 80749ab747fSPaolo Bonzini .class_init = scsi_generic_class_initfn, 80849ab747fSPaolo Bonzini }; 80949ab747fSPaolo Bonzini 81049ab747fSPaolo Bonzini static void scsi_generic_register_types(void) 81149ab747fSPaolo Bonzini { 81249ab747fSPaolo Bonzini type_register_static(&scsi_generic_info); 81349ab747fSPaolo Bonzini } 81449ab747fSPaolo Bonzini 81549ab747fSPaolo Bonzini type_init(scsi_generic_register_types) 81649ab747fSPaolo Bonzini 81749ab747fSPaolo Bonzini #endif /* __linux__ */ 818