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" 16*856dfd8aSMarkus Armbruster #include "qemu/ctype.h" 1749ab747fSPaolo Bonzini #include "qemu/error-report.h" 1849ab747fSPaolo Bonzini #include "hw/scsi/scsi.h" 193d4a8bf0SPaolo Bonzini #include "hw/scsi/emulation.h" 204be74634SMarkus Armbruster #include "sysemu/block-backend.h" 2156853498SLaurent Vivier #include "trace.h" 2249ab747fSPaolo Bonzini 2349ab747fSPaolo Bonzini #ifdef __linux__ 2449ab747fSPaolo Bonzini 2549ab747fSPaolo Bonzini #include <scsi/sg.h> 2608e2c9f1SPaolo Bonzini #include "scsi/constants.h" 2749ab747fSPaolo Bonzini 2849ab747fSPaolo Bonzini #ifndef MAX_UINT 2949ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1) 3049ab747fSPaolo Bonzini #endif 3149ab747fSPaolo Bonzini 3249ab747fSPaolo Bonzini typedef struct SCSIGenericReq { 3349ab747fSPaolo Bonzini SCSIRequest req; 3449ab747fSPaolo Bonzini uint8_t *buf; 3549ab747fSPaolo Bonzini int buflen; 3649ab747fSPaolo Bonzini int len; 3749ab747fSPaolo Bonzini sg_io_hdr_t io_header; 3849ab747fSPaolo Bonzini } SCSIGenericReq; 3949ab747fSPaolo Bonzini 4049ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) 4149ab747fSPaolo Bonzini { 4249ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 4349ab747fSPaolo Bonzini 4449ab747fSPaolo Bonzini qemu_put_sbe32s(f, &r->buflen); 4549ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 4649ab747fSPaolo Bonzini assert(!r->req.sg); 4749ab747fSPaolo Bonzini qemu_put_buffer(f, r->buf, r->req.cmd.xfer); 4849ab747fSPaolo Bonzini } 4949ab747fSPaolo Bonzini } 5049ab747fSPaolo Bonzini 5149ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) 5249ab747fSPaolo Bonzini { 5349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 5449ab747fSPaolo Bonzini 5549ab747fSPaolo Bonzini qemu_get_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_get_buffer(f, r->buf, r->req.cmd.xfer); 5949ab747fSPaolo Bonzini } 6049ab747fSPaolo Bonzini } 6149ab747fSPaolo Bonzini 6249ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req) 6349ab747fSPaolo Bonzini { 6449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 6549ab747fSPaolo Bonzini 6649ab747fSPaolo Bonzini g_free(r->buf); 6749ab747fSPaolo Bonzini } 6849ab747fSPaolo Bonzini 6949ab747fSPaolo Bonzini /* Helper function for command completion. */ 70fa0d653bSPaolo Bonzini static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) 7149ab747fSPaolo Bonzini { 7249ab747fSPaolo Bonzini int status; 731ead6b4eSPaolo Bonzini SCSISense sense; 7449ab747fSPaolo Bonzini 75fa0d653bSPaolo Bonzini assert(r->req.aiocb == NULL); 76fa0d653bSPaolo Bonzini 776c25fa6cSFam Zheng if (r->req.io_canceled) { 78d5776465SFam Zheng scsi_req_cancel_complete(&r->req); 796c25fa6cSFam Zheng goto done; 806c25fa6cSFam Zheng } 811ead6b4eSPaolo Bonzini status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); 821ead6b4eSPaolo Bonzini if (status == CHECK_CONDITION) { 8349ab747fSPaolo Bonzini if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 8449ab747fSPaolo Bonzini r->req.sense_len = r->io_header.sb_len_wr; 851ead6b4eSPaolo Bonzini } else { 861ead6b4eSPaolo Bonzini scsi_req_build_sense(&r->req, sense); 871ead6b4eSPaolo Bonzini } 8849ab747fSPaolo Bonzini } 8949ab747fSPaolo Bonzini 9056853498SLaurent Vivier trace_scsi_generic_command_complete_noio(r, r->req.tag, status); 9149ab747fSPaolo Bonzini 9249ab747fSPaolo Bonzini scsi_req_complete(&r->req, status); 936c25fa6cSFam Zheng done: 9449ab747fSPaolo Bonzini scsi_req_unref(&r->req); 9549ab747fSPaolo Bonzini } 9649ab747fSPaolo Bonzini 97fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret) 98fa0d653bSPaolo Bonzini { 99fa0d653bSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 100b9e413ddSPaolo Bonzini SCSIDevice *s = r->req.dev; 101fa0d653bSPaolo Bonzini 102fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 103fa0d653bSPaolo Bonzini r->req.aiocb = NULL; 104b9e413ddSPaolo Bonzini 105b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 106fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 107b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 108fa0d653bSPaolo Bonzini } 109fa0d653bSPaolo Bonzini 1104be74634SMarkus Armbruster static int execute_command(BlockBackend *blk, 11149ab747fSPaolo Bonzini SCSIGenericReq *r, int direction, 112097310b5SMarkus Armbruster BlockCompletionFunc *complete) 11349ab747fSPaolo Bonzini { 11449ab747fSPaolo Bonzini r->io_header.interface_id = 'S'; 11549ab747fSPaolo Bonzini r->io_header.dxfer_direction = direction; 11649ab747fSPaolo Bonzini r->io_header.dxferp = r->buf; 11749ab747fSPaolo Bonzini r->io_header.dxfer_len = r->buflen; 11849ab747fSPaolo Bonzini r->io_header.cmdp = r->req.cmd.buf; 11949ab747fSPaolo Bonzini r->io_header.cmd_len = r->req.cmd.len; 12049ab747fSPaolo Bonzini r->io_header.mx_sb_len = sizeof(r->req.sense); 12149ab747fSPaolo Bonzini r->io_header.sbp = r->req.sense; 12249ab747fSPaolo Bonzini r->io_header.timeout = MAX_UINT; 12349ab747fSPaolo Bonzini r->io_header.usr_ptr = r; 12449ab747fSPaolo Bonzini r->io_header.flags |= SG_FLAG_DIRECT_IO; 12549ab747fSPaolo Bonzini 1264be74634SMarkus Armbruster r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r); 127d836f8d3SPavel Hrdina if (r->req.aiocb == NULL) { 128d836f8d3SPavel Hrdina return -EIO; 129d836f8d3SPavel Hrdina } 13049ab747fSPaolo Bonzini 13149ab747fSPaolo Bonzini return 0; 13249ab747fSPaolo Bonzini } 13349ab747fSPaolo Bonzini 1340a96ca24SDaniel Henrique Barboza static void scsi_handle_inquiry_reply(SCSIGenericReq *r, SCSIDevice *s) 1350a96ca24SDaniel Henrique Barboza { 1366c219fc8SPaolo Bonzini uint8_t page, page_idx; 137a71c775bSDaniel Henrique Barboza 1380a96ca24SDaniel Henrique Barboza /* 1390a96ca24SDaniel Henrique Barboza * EVPD set to zero returns the standard INQUIRY data. 1400a96ca24SDaniel Henrique Barboza * 1410a96ca24SDaniel Henrique Barboza * Check if scsi_version is unset (-1) to avoid re-defining it 1420a96ca24SDaniel Henrique Barboza * each time an INQUIRY with standard data is received. 1430a96ca24SDaniel Henrique Barboza * scsi_version is initialized with -1 in scsi_generic_reset 1440a96ca24SDaniel Henrique Barboza * and scsi_disk_reset, making sure that we'll set the 1450a96ca24SDaniel Henrique Barboza * scsi_version after a reset. If the version field of the 1460a96ca24SDaniel Henrique Barboza * INQUIRY response somehow changes after a guest reboot, 1470a96ca24SDaniel Henrique Barboza * we'll be able to keep track of it. 1480a96ca24SDaniel Henrique Barboza * 1490a96ca24SDaniel Henrique Barboza * On SCSI-2 and older, first 3 bits of byte 2 is the 1500a96ca24SDaniel Henrique Barboza * ANSI-approved version, while on later versions the 1510a96ca24SDaniel Henrique Barboza * whole byte 2 contains the version. Check if we're dealing 1520a96ca24SDaniel Henrique Barboza * with a newer version and, in that case, assign the 1530a96ca24SDaniel Henrique Barboza * whole byte. 1540a96ca24SDaniel Henrique Barboza */ 1550a96ca24SDaniel Henrique Barboza if (s->scsi_version == -1 && !(r->req.cmd.buf[1] & 0x01)) { 1560a96ca24SDaniel Henrique Barboza s->scsi_version = r->buf[2] & 0x07; 1570a96ca24SDaniel Henrique Barboza if (s->scsi_version > 2) { 1580a96ca24SDaniel Henrique Barboza s->scsi_version = r->buf[2]; 1590a96ca24SDaniel Henrique Barboza } 1600a96ca24SDaniel Henrique Barboza } 161a71c775bSDaniel Henrique Barboza 162a71c775bSDaniel Henrique Barboza if (s->type == TYPE_DISK && (r->req.cmd.buf[1] & 0x01)) { 163a71c775bSDaniel Henrique Barboza page = r->req.cmd.buf[2]; 164a71c775bSDaniel Henrique Barboza if (page == 0xb0) { 1650a96ca24SDaniel Henrique Barboza uint32_t max_transfer = 1660a96ca24SDaniel Henrique Barboza blk_get_max_transfer(s->conf.blk) / s->blocksize; 1670a96ca24SDaniel Henrique Barboza 1680a96ca24SDaniel Henrique Barboza assert(max_transfer); 1690a96ca24SDaniel Henrique Barboza stl_be_p(&r->buf[8], max_transfer); 1700a96ca24SDaniel Henrique Barboza /* Also take care of the opt xfer len. */ 1710a96ca24SDaniel Henrique Barboza stl_be_p(&r->buf[12], 1720a96ca24SDaniel Henrique Barboza MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); 173e909ff93SPaolo Bonzini } else if (s->needs_vpd_bl_emulation && page == 0x00 && r->buflen >= 4) { 174a71c775bSDaniel Henrique Barboza /* 175a71c775bSDaniel Henrique Barboza * Now we're capable of supplying the VPD Block Limits 176a71c775bSDaniel Henrique Barboza * response if the hardware can't. Add it in the INQUIRY 177a71c775bSDaniel Henrique Barboza * Supported VPD pages response in case we are using the 178a71c775bSDaniel Henrique Barboza * emulation for this device. 179a71c775bSDaniel Henrique Barboza * 180a71c775bSDaniel Henrique Barboza * This way, the guest kernel will be aware of the support 181a71c775bSDaniel Henrique Barboza * and will use it to proper setup the SCSI device. 1826c219fc8SPaolo Bonzini * 1836c219fc8SPaolo Bonzini * VPD page numbers must be sorted, so insert 0xb0 at the 184e909ff93SPaolo Bonzini * right place with an in-place insert. When the while loop 185e909ff93SPaolo Bonzini * begins the device response is at r[0] to r[page_idx - 1]. 186a71c775bSDaniel Henrique Barboza */ 187e909ff93SPaolo Bonzini page_idx = lduw_be_p(r->buf + 2) + 4; 188e909ff93SPaolo Bonzini page_idx = MIN(page_idx, r->buflen); 189e909ff93SPaolo Bonzini while (page_idx > 4 && r->buf[page_idx - 1] >= 0xb0) { 1906c219fc8SPaolo Bonzini if (page_idx < r->buflen) { 1916c219fc8SPaolo Bonzini r->buf[page_idx] = r->buf[page_idx - 1]; 1926c219fc8SPaolo Bonzini } 193e909ff93SPaolo Bonzini page_idx--; 1946c219fc8SPaolo Bonzini } 195e909ff93SPaolo Bonzini if (page_idx < r->buflen) { 1966c219fc8SPaolo Bonzini r->buf[page_idx] = 0xb0; 197e909ff93SPaolo Bonzini } 1986c219fc8SPaolo Bonzini stw_be_p(r->buf + 2, lduw_be_p(r->buf + 2) + 1); 1990a96ca24SDaniel Henrique Barboza } 2000a96ca24SDaniel Henrique Barboza } 201a71c775bSDaniel Henrique Barboza } 202a71c775bSDaniel Henrique Barboza 2033d4a8bf0SPaolo Bonzini static int scsi_generic_emulate_block_limits(SCSIGenericReq *r, SCSIDevice *s) 204a71c775bSDaniel Henrique Barboza { 2053d4a8bf0SPaolo Bonzini int len; 2063d4a8bf0SPaolo Bonzini uint8_t buf[64]; 2073d4a8bf0SPaolo Bonzini 2083d4a8bf0SPaolo Bonzini SCSIBlockLimits bl = { 2093d4a8bf0SPaolo Bonzini .max_io_sectors = blk_get_max_transfer(s->conf.blk) / s->blocksize 2103d4a8bf0SPaolo Bonzini }; 2113d4a8bf0SPaolo Bonzini 2123d4a8bf0SPaolo Bonzini memset(r->buf, 0, r->buflen); 2133d4a8bf0SPaolo Bonzini stb_p(buf, s->type); 2143d4a8bf0SPaolo Bonzini stb_p(buf + 1, 0xb0); 2153d4a8bf0SPaolo Bonzini len = scsi_emulate_block_limits(buf + 4, &bl); 2163d4a8bf0SPaolo Bonzini assert(len <= sizeof(buf) - 4); 2173d4a8bf0SPaolo Bonzini stw_be_p(buf + 2, len); 2183d4a8bf0SPaolo Bonzini 2193d4a8bf0SPaolo Bonzini memcpy(r->buf, buf, MIN(r->buflen, len + 4)); 2203d4a8bf0SPaolo Bonzini 221a71c775bSDaniel Henrique Barboza r->io_header.sb_len_wr = 0; 222a71c775bSDaniel Henrique Barboza 223a71c775bSDaniel Henrique Barboza /* 224a71c775bSDaniel Henrique Barboza * We have valid contents in the reply buffer but the 225a71c775bSDaniel Henrique Barboza * io_header can report a sense error coming from 226a71c775bSDaniel Henrique Barboza * the hardware in scsi_command_complete_noio. Clean 227a71c775bSDaniel Henrique Barboza * up the io_header to avoid reporting it. 228a71c775bSDaniel Henrique Barboza */ 229a71c775bSDaniel Henrique Barboza r->io_header.driver_status = 0; 230a71c775bSDaniel Henrique Barboza r->io_header.status = 0; 231a71c775bSDaniel Henrique Barboza 232a71c775bSDaniel Henrique Barboza return r->buflen; 233a71c775bSDaniel Henrique Barboza } 2340a96ca24SDaniel Henrique Barboza 23549ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret) 23649ab747fSPaolo Bonzini { 23749ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 23849ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 23949ab747fSPaolo Bonzini int len; 24049ab747fSPaolo Bonzini 241fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 24249ab747fSPaolo Bonzini r->req.aiocb = NULL; 243fa0d653bSPaolo Bonzini 244b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 245b9e413ddSPaolo Bonzini 2466c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 247fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 248b9e413ddSPaolo Bonzini goto done; 24949ab747fSPaolo Bonzini } 250fa0d653bSPaolo Bonzini 25149ab747fSPaolo Bonzini len = r->io_header.dxfer_len - r->io_header.resid; 25256853498SLaurent Vivier trace_scsi_generic_read_complete(r->req.tag, len); 25349ab747fSPaolo Bonzini 25449ab747fSPaolo Bonzini r->len = -1; 255a71c775bSDaniel Henrique Barboza 256a71c775bSDaniel Henrique Barboza /* 257a71c775bSDaniel Henrique Barboza * Check if this is a VPD Block Limits request that 258a71c775bSDaniel Henrique Barboza * resulted in sense error but would need emulation. 259a71c775bSDaniel Henrique Barboza * In this case, emulate a valid VPD response. 260a71c775bSDaniel Henrique Barboza */ 261763c5687SPaolo Bonzini if (s->needs_vpd_bl_emulation && ret == 0 && 262763c5687SPaolo Bonzini (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) && 2633d4a8bf0SPaolo Bonzini r->req.cmd.buf[0] == INQUIRY && 2643d4a8bf0SPaolo Bonzini (r->req.cmd.buf[1] & 0x01) && 2653d4a8bf0SPaolo Bonzini r->req.cmd.buf[2] == 0xb0) { 266763c5687SPaolo Bonzini SCSISense sense = 267763c5687SPaolo Bonzini scsi_parse_sense_buf(r->req.sense, r->io_header.sb_len_wr); 268763c5687SPaolo Bonzini if (sense.key == ILLEGAL_REQUEST) { 2693d4a8bf0SPaolo Bonzini len = scsi_generic_emulate_block_limits(r, s); 270a71c775bSDaniel Henrique Barboza /* 271a71c775bSDaniel Henrique Barboza * No need to let scsi_read_complete go on and handle an 272a71c775bSDaniel Henrique Barboza * INQUIRY VPD BL request we created manually. 273a71c775bSDaniel Henrique Barboza */ 274a71c775bSDaniel Henrique Barboza goto req_complete; 275a71c775bSDaniel Henrique Barboza } 276a71c775bSDaniel Henrique Barboza } 277a71c775bSDaniel Henrique Barboza 27849ab747fSPaolo Bonzini if (len == 0) { 279fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 280b9e413ddSPaolo Bonzini goto done; 281fa0d653bSPaolo Bonzini } 282fa0d653bSPaolo Bonzini 28349ab747fSPaolo Bonzini /* Snoop READ CAPACITY output to set the blocksize. */ 28453254e56SPaolo Bonzini if (r->req.cmd.buf[0] == READ_CAPACITY_10 && 28553254e56SPaolo Bonzini (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { 28649ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[4]); 28753254e56SPaolo Bonzini s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; 28849ab747fSPaolo Bonzini } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && 28949ab747fSPaolo Bonzini (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { 29049ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[8]); 29149ab747fSPaolo Bonzini s->max_lba = ldq_be_p(&r->buf[0]); 29249ab747fSPaolo Bonzini } 2934be74634SMarkus Armbruster blk_set_guest_block_size(s->conf.blk, s->blocksize); 29449ab747fSPaolo Bonzini 2950eb2baebSPaolo Bonzini /* Patch MODE SENSE device specific parameters if the BDS is opened 2960eb2baebSPaolo Bonzini * readonly. 2970eb2baebSPaolo Bonzini */ 2980eb2baebSPaolo Bonzini if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) && 2990eb2baebSPaolo Bonzini blk_is_read_only(s->conf.blk) && 3000eb2baebSPaolo Bonzini (r->req.cmd.buf[0] == MODE_SENSE || 3010eb2baebSPaolo Bonzini r->req.cmd.buf[0] == MODE_SENSE_10) && 3020eb2baebSPaolo Bonzini (r->req.cmd.buf[1] & 0x8) == 0) { 3030eb2baebSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SENSE) { 3040eb2baebSPaolo Bonzini r->buf[2] |= 0x80; 3050eb2baebSPaolo Bonzini } else { 3060eb2baebSPaolo Bonzini r->buf[3] |= 0x80; 3070eb2baebSPaolo Bonzini } 3080eb2baebSPaolo Bonzini } 30929e560f0SDaniel Henrique Barboza if (r->req.cmd.buf[0] == INQUIRY) { 3100a96ca24SDaniel Henrique Barboza scsi_handle_inquiry_reply(r, s); 31129e560f0SDaniel Henrique Barboza } 312a71c775bSDaniel Henrique Barboza 313a71c775bSDaniel Henrique Barboza req_complete: 31449ab747fSPaolo Bonzini scsi_req_data(&r->req, len); 31549ab747fSPaolo Bonzini scsi_req_unref(&r->req); 316b9e413ddSPaolo Bonzini 317b9e413ddSPaolo Bonzini done: 318b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 31949ab747fSPaolo Bonzini } 32049ab747fSPaolo Bonzini 32149ab747fSPaolo Bonzini /* Read more data from scsi device into buffer. */ 32249ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req) 32349ab747fSPaolo Bonzini { 32449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 32549ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 32649ab747fSPaolo Bonzini int ret; 32749ab747fSPaolo Bonzini 32856853498SLaurent Vivier trace_scsi_generic_read_data(req->tag); 32949ab747fSPaolo Bonzini 33049ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 33149ab747fSPaolo Bonzini scsi_req_ref(&r->req); 33249ab747fSPaolo Bonzini if (r->len == -1) { 333fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 33449ab747fSPaolo Bonzini return; 33549ab747fSPaolo Bonzini } 33649ab747fSPaolo Bonzini 3374be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV, 3384be74634SMarkus Armbruster scsi_read_complete); 33949ab747fSPaolo Bonzini if (ret < 0) { 340fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 34149ab747fSPaolo Bonzini } 34249ab747fSPaolo Bonzini } 34349ab747fSPaolo Bonzini 34449ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret) 34549ab747fSPaolo Bonzini { 34649ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 34749ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 34849ab747fSPaolo Bonzini 34956853498SLaurent Vivier trace_scsi_generic_write_complete(ret); 350fa0d653bSPaolo Bonzini 351fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 35249ab747fSPaolo Bonzini r->req.aiocb = NULL; 353fa0d653bSPaolo Bonzini 354b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 355b9e413ddSPaolo Bonzini 3566c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 357fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 358b9e413ddSPaolo Bonzini goto done; 35949ab747fSPaolo Bonzini } 36049ab747fSPaolo Bonzini 36149ab747fSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && 36249ab747fSPaolo Bonzini s->type == TYPE_TAPE) { 36349ab747fSPaolo Bonzini s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; 36456853498SLaurent Vivier trace_scsi_generic_write_complete_blocksize(s->blocksize); 36549ab747fSPaolo Bonzini } 36649ab747fSPaolo Bonzini 367fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 368b9e413ddSPaolo Bonzini 369b9e413ddSPaolo Bonzini done: 370b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 37149ab747fSPaolo Bonzini } 37249ab747fSPaolo Bonzini 37349ab747fSPaolo Bonzini /* Write data to a scsi device. Returns nonzero on failure. 37449ab747fSPaolo Bonzini The transfer may complete asynchronously. */ 37549ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req) 37649ab747fSPaolo Bonzini { 37749ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 37849ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 37949ab747fSPaolo Bonzini int ret; 38049ab747fSPaolo Bonzini 38156853498SLaurent Vivier trace_scsi_generic_write_data(req->tag); 38249ab747fSPaolo Bonzini if (r->len == 0) { 38349ab747fSPaolo Bonzini r->len = r->buflen; 38449ab747fSPaolo Bonzini scsi_req_data(&r->req, r->len); 38549ab747fSPaolo Bonzini return; 38649ab747fSPaolo Bonzini } 38749ab747fSPaolo Bonzini 38849ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 38949ab747fSPaolo Bonzini scsi_req_ref(&r->req); 3904be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete); 39149ab747fSPaolo Bonzini if (ret < 0) { 392fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 39349ab747fSPaolo Bonzini } 39449ab747fSPaolo Bonzini } 39549ab747fSPaolo Bonzini 39649ab747fSPaolo Bonzini /* Return a pointer to the data buffer. */ 39749ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req) 39849ab747fSPaolo Bonzini { 39949ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 40049ab747fSPaolo Bonzini 40149ab747fSPaolo Bonzini return r->buf; 40249ab747fSPaolo Bonzini } 40349ab747fSPaolo Bonzini 40456853498SLaurent Vivier static void scsi_generic_command_dump(uint8_t *cmd, int len) 40556853498SLaurent Vivier { 40656853498SLaurent Vivier int i; 40756853498SLaurent Vivier char *line_buffer, *p; 40856853498SLaurent Vivier 40956853498SLaurent Vivier line_buffer = g_malloc(len * 5 + 1); 41056853498SLaurent Vivier 41156853498SLaurent Vivier for (i = 0, p = line_buffer; i < len; i++) { 41256853498SLaurent Vivier p += sprintf(p, " 0x%02x", cmd[i]); 41356853498SLaurent Vivier } 41456853498SLaurent Vivier trace_scsi_generic_send_command(line_buffer); 41556853498SLaurent Vivier 41656853498SLaurent Vivier g_free(line_buffer); 41756853498SLaurent Vivier } 41856853498SLaurent Vivier 41949ab747fSPaolo Bonzini /* Execute a scsi command. Returns the length of the data expected by the 42049ab747fSPaolo Bonzini command. This will be Positive for data transfers from the device 42149ab747fSPaolo Bonzini (eg. disk reads), negative for transfers to the device (eg. disk writes), 42249ab747fSPaolo Bonzini and zero if the command does not transfer any data. */ 42349ab747fSPaolo Bonzini 42449ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) 42549ab747fSPaolo Bonzini { 42649ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 42749ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 42849ab747fSPaolo Bonzini int ret; 42949ab747fSPaolo Bonzini 43056853498SLaurent Vivier if (trace_event_get_state_backends(TRACE_SCSI_GENERIC_SEND_COMMAND)) { 43156853498SLaurent Vivier scsi_generic_command_dump(cmd, r->req.cmd.len); 43249ab747fSPaolo Bonzini } 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; 69456853498SLaurent Vivier trace_scsi_generic_realize_type(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 71756853498SLaurent Vivier trace_scsi_generic_realize_blocksize(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