149ab747fSPaolo Bonzini /* 249ab747fSPaolo Bonzini * Generic SCSI Device support 349ab747fSPaolo Bonzini * 449ab747fSPaolo Bonzini * Copyright (c) 2007 Bull S.A.S. 549ab747fSPaolo Bonzini * Based on code by Paul Brook 649ab747fSPaolo Bonzini * Based on code by Fabrice Bellard 749ab747fSPaolo Bonzini * 849ab747fSPaolo Bonzini * Written by Laurent Vivier <Laurent.Vivier@bull.net> 949ab747fSPaolo Bonzini * 1049ab747fSPaolo Bonzini * This code is licensed under the LGPL. 1149ab747fSPaolo Bonzini * 1249ab747fSPaolo Bonzini */ 1349ab747fSPaolo Bonzini 14a4ab4792SPeter Maydell #include "qemu/osdep.h" 15da34e65cSMarkus Armbruster #include "qapi/error.h" 1649ab747fSPaolo Bonzini #include "qemu-common.h" 1749ab747fSPaolo Bonzini #include "qemu/error-report.h" 1849ab747fSPaolo Bonzini #include "hw/scsi/scsi.h" 194be74634SMarkus Armbruster #include "sysemu/block-backend.h" 2049ab747fSPaolo Bonzini #include "sysemu/blockdev.h" 2149ab747fSPaolo Bonzini 2249ab747fSPaolo Bonzini #ifdef __linux__ 2349ab747fSPaolo Bonzini 2449ab747fSPaolo Bonzini //#define DEBUG_SCSI 2549ab747fSPaolo Bonzini 2649ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 2749ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) \ 2849ab747fSPaolo Bonzini do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0) 2949ab747fSPaolo Bonzini #else 3049ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) do {} while(0) 3149ab747fSPaolo Bonzini #endif 3249ab747fSPaolo Bonzini 3349ab747fSPaolo Bonzini #define BADF(fmt, ...) \ 3449ab747fSPaolo Bonzini do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) 3549ab747fSPaolo Bonzini 3649ab747fSPaolo Bonzini #include <scsi/sg.h> 37*08e2c9f1SPaolo Bonzini #include "scsi/constants.h" 3849ab747fSPaolo Bonzini 3949ab747fSPaolo Bonzini #ifndef MAX_UINT 4049ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1) 4149ab747fSPaolo Bonzini #endif 4249ab747fSPaolo Bonzini 4349ab747fSPaolo Bonzini typedef struct SCSIGenericReq { 4449ab747fSPaolo Bonzini SCSIRequest req; 4549ab747fSPaolo Bonzini uint8_t *buf; 4649ab747fSPaolo Bonzini int buflen; 4749ab747fSPaolo Bonzini int len; 4849ab747fSPaolo Bonzini sg_io_hdr_t io_header; 4949ab747fSPaolo Bonzini } SCSIGenericReq; 5049ab747fSPaolo Bonzini 5149ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) 5249ab747fSPaolo Bonzini { 5349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 5449ab747fSPaolo Bonzini 5549ab747fSPaolo Bonzini qemu_put_sbe32s(f, &r->buflen); 5649ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 5749ab747fSPaolo Bonzini assert(!r->req.sg); 5849ab747fSPaolo Bonzini qemu_put_buffer(f, r->buf, r->req.cmd.xfer); 5949ab747fSPaolo Bonzini } 6049ab747fSPaolo Bonzini } 6149ab747fSPaolo Bonzini 6249ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) 6349ab747fSPaolo Bonzini { 6449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 6549ab747fSPaolo Bonzini 6649ab747fSPaolo Bonzini qemu_get_sbe32s(f, &r->buflen); 6749ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 6849ab747fSPaolo Bonzini assert(!r->req.sg); 6949ab747fSPaolo Bonzini qemu_get_buffer(f, r->buf, r->req.cmd.xfer); 7049ab747fSPaolo Bonzini } 7149ab747fSPaolo Bonzini } 7249ab747fSPaolo Bonzini 7349ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req) 7449ab747fSPaolo Bonzini { 7549ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 7649ab747fSPaolo Bonzini 7749ab747fSPaolo Bonzini g_free(r->buf); 7849ab747fSPaolo Bonzini } 7949ab747fSPaolo Bonzini 8049ab747fSPaolo Bonzini /* Helper function for command completion. */ 81fa0d653bSPaolo Bonzini static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) 8249ab747fSPaolo Bonzini { 8349ab747fSPaolo Bonzini int status; 841ead6b4eSPaolo Bonzini SCSISense sense; 8549ab747fSPaolo Bonzini 86fa0d653bSPaolo Bonzini assert(r->req.aiocb == NULL); 87fa0d653bSPaolo Bonzini 886c25fa6cSFam Zheng if (r->req.io_canceled) { 89d5776465SFam Zheng scsi_req_cancel_complete(&r->req); 906c25fa6cSFam Zheng goto done; 916c25fa6cSFam Zheng } 921ead6b4eSPaolo Bonzini status = sg_io_sense_from_errno(-ret, &r->io_header, &sense); 931ead6b4eSPaolo Bonzini if (status == CHECK_CONDITION) { 9449ab747fSPaolo Bonzini if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 9549ab747fSPaolo Bonzini r->req.sense_len = r->io_header.sb_len_wr; 961ead6b4eSPaolo Bonzini } else { 971ead6b4eSPaolo Bonzini scsi_req_build_sense(&r->req, sense); 981ead6b4eSPaolo Bonzini } 9949ab747fSPaolo Bonzini } 10049ab747fSPaolo Bonzini 10149ab747fSPaolo Bonzini DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", 10249ab747fSPaolo Bonzini r, r->req.tag, status); 10349ab747fSPaolo Bonzini 10449ab747fSPaolo Bonzini scsi_req_complete(&r->req, status); 1056c25fa6cSFam Zheng done: 10649ab747fSPaolo Bonzini scsi_req_unref(&r->req); 10749ab747fSPaolo Bonzini } 10849ab747fSPaolo Bonzini 109fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret) 110fa0d653bSPaolo Bonzini { 111fa0d653bSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 112b9e413ddSPaolo Bonzini SCSIDevice *s = r->req.dev; 113fa0d653bSPaolo Bonzini 114fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 115fa0d653bSPaolo Bonzini r->req.aiocb = NULL; 116b9e413ddSPaolo Bonzini 117b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 118fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 119b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 120fa0d653bSPaolo Bonzini } 121fa0d653bSPaolo Bonzini 1224be74634SMarkus Armbruster static int execute_command(BlockBackend *blk, 12349ab747fSPaolo Bonzini SCSIGenericReq *r, int direction, 124097310b5SMarkus Armbruster BlockCompletionFunc *complete) 12549ab747fSPaolo Bonzini { 12649ab747fSPaolo Bonzini r->io_header.interface_id = 'S'; 12749ab747fSPaolo Bonzini r->io_header.dxfer_direction = direction; 12849ab747fSPaolo Bonzini r->io_header.dxferp = r->buf; 12949ab747fSPaolo Bonzini r->io_header.dxfer_len = r->buflen; 13049ab747fSPaolo Bonzini r->io_header.cmdp = r->req.cmd.buf; 13149ab747fSPaolo Bonzini r->io_header.cmd_len = r->req.cmd.len; 13249ab747fSPaolo Bonzini r->io_header.mx_sb_len = sizeof(r->req.sense); 13349ab747fSPaolo Bonzini r->io_header.sbp = r->req.sense; 13449ab747fSPaolo Bonzini r->io_header.timeout = MAX_UINT; 13549ab747fSPaolo Bonzini r->io_header.usr_ptr = r; 13649ab747fSPaolo Bonzini r->io_header.flags |= SG_FLAG_DIRECT_IO; 13749ab747fSPaolo Bonzini 1384be74634SMarkus Armbruster r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r); 139d836f8d3SPavel Hrdina if (r->req.aiocb == NULL) { 140d836f8d3SPavel Hrdina return -EIO; 141d836f8d3SPavel Hrdina } 14249ab747fSPaolo Bonzini 14349ab747fSPaolo Bonzini return 0; 14449ab747fSPaolo Bonzini } 14549ab747fSPaolo Bonzini 14649ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret) 14749ab747fSPaolo Bonzini { 14849ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 14949ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 15049ab747fSPaolo Bonzini int len; 15149ab747fSPaolo Bonzini 152fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 15349ab747fSPaolo Bonzini r->req.aiocb = NULL; 154fa0d653bSPaolo Bonzini 155b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 156b9e413ddSPaolo Bonzini 1576c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 158fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 159b9e413ddSPaolo Bonzini goto done; 16049ab747fSPaolo Bonzini } 161fa0d653bSPaolo Bonzini 16249ab747fSPaolo Bonzini len = r->io_header.dxfer_len - r->io_header.resid; 16349ab747fSPaolo Bonzini DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); 16449ab747fSPaolo Bonzini 16549ab747fSPaolo Bonzini r->len = -1; 16649ab747fSPaolo Bonzini if (len == 0) { 167fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 168b9e413ddSPaolo Bonzini goto done; 169fa0d653bSPaolo Bonzini } 170fa0d653bSPaolo Bonzini 17149ab747fSPaolo Bonzini /* Snoop READ CAPACITY output to set the blocksize. */ 17253254e56SPaolo Bonzini if (r->req.cmd.buf[0] == READ_CAPACITY_10 && 17353254e56SPaolo Bonzini (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { 17449ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[4]); 17553254e56SPaolo Bonzini s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; 17649ab747fSPaolo Bonzini } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && 17749ab747fSPaolo Bonzini (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { 17849ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[8]); 17949ab747fSPaolo Bonzini s->max_lba = ldq_be_p(&r->buf[0]); 18049ab747fSPaolo Bonzini } 1814be74634SMarkus Armbruster blk_set_guest_block_size(s->conf.blk, s->blocksize); 18249ab747fSPaolo Bonzini 1830eb2baebSPaolo Bonzini /* Patch MODE SENSE device specific parameters if the BDS is opened 1840eb2baebSPaolo Bonzini * readonly. 1850eb2baebSPaolo Bonzini */ 1860eb2baebSPaolo Bonzini if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) && 1870eb2baebSPaolo Bonzini blk_is_read_only(s->conf.blk) && 1880eb2baebSPaolo Bonzini (r->req.cmd.buf[0] == MODE_SENSE || 1890eb2baebSPaolo Bonzini r->req.cmd.buf[0] == MODE_SENSE_10) && 1900eb2baebSPaolo Bonzini (r->req.cmd.buf[1] & 0x8) == 0) { 1910eb2baebSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SENSE) { 1920eb2baebSPaolo Bonzini r->buf[2] |= 0x80; 1930eb2baebSPaolo Bonzini } else { 1940eb2baebSPaolo Bonzini r->buf[3] |= 0x80; 1950eb2baebSPaolo Bonzini } 1960eb2baebSPaolo Bonzini } 197063143d5SFam Zheng if (s->type == TYPE_DISK && 198063143d5SFam Zheng r->req.cmd.buf[0] == INQUIRY && 199063143d5SFam Zheng r->req.cmd.buf[2] == 0xb0) { 2005def6b80SEric Blake uint32_t max_transfer = 2015def6b80SEric Blake blk_get_max_transfer(s->conf.blk) / s->blocksize; 20224ce9a20SEric Blake 2035def6b80SEric Blake assert(max_transfer); 2045def6b80SEric Blake stl_be_p(&r->buf[8], max_transfer); 205063143d5SFam Zheng /* Also take care of the opt xfer len. */ 206bed58b44SFam Zheng stl_be_p(&r->buf[12], 207bed58b44SFam Zheng MIN_NON_ZERO(max_transfer, ldl_be_p(&r->buf[12]))); 208063143d5SFam Zheng } 20949ab747fSPaolo Bonzini scsi_req_data(&r->req, len); 21049ab747fSPaolo Bonzini scsi_req_unref(&r->req); 211b9e413ddSPaolo Bonzini 212b9e413ddSPaolo Bonzini done: 213b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 21449ab747fSPaolo Bonzini } 21549ab747fSPaolo Bonzini 21649ab747fSPaolo Bonzini /* Read more data from scsi device into buffer. */ 21749ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req) 21849ab747fSPaolo Bonzini { 21949ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 22049ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 22149ab747fSPaolo Bonzini int ret; 22249ab747fSPaolo Bonzini 2232e144aa7SEric Farman DPRINTF("scsi_read_data tag=0x%x\n", req->tag); 22449ab747fSPaolo Bonzini 22549ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 22649ab747fSPaolo Bonzini scsi_req_ref(&r->req); 22749ab747fSPaolo Bonzini if (r->len == -1) { 228fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 22949ab747fSPaolo Bonzini return; 23049ab747fSPaolo Bonzini } 23149ab747fSPaolo Bonzini 2324be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV, 2334be74634SMarkus Armbruster scsi_read_complete); 23449ab747fSPaolo Bonzini if (ret < 0) { 235fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 23649ab747fSPaolo Bonzini } 23749ab747fSPaolo Bonzini } 23849ab747fSPaolo Bonzini 23949ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret) 24049ab747fSPaolo Bonzini { 24149ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 24249ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 24349ab747fSPaolo Bonzini 24449ab747fSPaolo Bonzini DPRINTF("scsi_write_complete() ret = %d\n", ret); 245fa0d653bSPaolo Bonzini 246fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 24749ab747fSPaolo Bonzini r->req.aiocb = NULL; 248fa0d653bSPaolo Bonzini 249b9e413ddSPaolo Bonzini aio_context_acquire(blk_get_aio_context(s->conf.blk)); 250b9e413ddSPaolo Bonzini 2516c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 252fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 253b9e413ddSPaolo Bonzini goto done; 25449ab747fSPaolo Bonzini } 25549ab747fSPaolo Bonzini 25649ab747fSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && 25749ab747fSPaolo Bonzini s->type == TYPE_TAPE) { 25849ab747fSPaolo Bonzini s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; 25949ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 26049ab747fSPaolo Bonzini } 26149ab747fSPaolo Bonzini 262fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 263b9e413ddSPaolo Bonzini 264b9e413ddSPaolo Bonzini done: 265b9e413ddSPaolo Bonzini aio_context_release(blk_get_aio_context(s->conf.blk)); 26649ab747fSPaolo Bonzini } 26749ab747fSPaolo Bonzini 26849ab747fSPaolo Bonzini /* Write data to a scsi device. Returns nonzero on failure. 26949ab747fSPaolo Bonzini The transfer may complete asynchronously. */ 27049ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req) 27149ab747fSPaolo Bonzini { 27249ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 27349ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 27449ab747fSPaolo Bonzini int ret; 27549ab747fSPaolo Bonzini 2762e144aa7SEric Farman DPRINTF("scsi_write_data tag=0x%x\n", req->tag); 27749ab747fSPaolo Bonzini if (r->len == 0) { 27849ab747fSPaolo Bonzini r->len = r->buflen; 27949ab747fSPaolo Bonzini scsi_req_data(&r->req, r->len); 28049ab747fSPaolo Bonzini return; 28149ab747fSPaolo Bonzini } 28249ab747fSPaolo Bonzini 28349ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 28449ab747fSPaolo Bonzini scsi_req_ref(&r->req); 2854be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete); 28649ab747fSPaolo Bonzini if (ret < 0) { 287fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 28849ab747fSPaolo Bonzini } 28949ab747fSPaolo Bonzini } 29049ab747fSPaolo Bonzini 29149ab747fSPaolo Bonzini /* Return a pointer to the data buffer. */ 29249ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req) 29349ab747fSPaolo Bonzini { 29449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 29549ab747fSPaolo Bonzini 29649ab747fSPaolo Bonzini return r->buf; 29749ab747fSPaolo Bonzini } 29849ab747fSPaolo Bonzini 29949ab747fSPaolo Bonzini /* Execute a scsi command. Returns the length of the data expected by the 30049ab747fSPaolo Bonzini command. This will be Positive for data transfers from the device 30149ab747fSPaolo Bonzini (eg. disk reads), negative for transfers to the device (eg. disk writes), 30249ab747fSPaolo Bonzini and zero if the command does not transfer any data. */ 30349ab747fSPaolo Bonzini 30449ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) 30549ab747fSPaolo Bonzini { 30649ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 30749ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 30849ab747fSPaolo Bonzini int ret; 30949ab747fSPaolo Bonzini 31049ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 3112e144aa7SEric Farman DPRINTF("Command: data=0x%02x", cmd[0]); 31249ab747fSPaolo Bonzini { 31349ab747fSPaolo Bonzini int i; 31449ab747fSPaolo Bonzini for (i = 1; i < r->req.cmd.len; i++) { 31549ab747fSPaolo Bonzini printf(" 0x%02x", cmd[i]); 31649ab747fSPaolo Bonzini } 31749ab747fSPaolo Bonzini printf("\n"); 31849ab747fSPaolo Bonzini } 31949ab747fSPaolo Bonzini #endif 32049ab747fSPaolo Bonzini 32149ab747fSPaolo Bonzini if (r->req.cmd.xfer == 0) { 32249ab747fSPaolo Bonzini g_free(r->buf); 32349ab747fSPaolo Bonzini r->buflen = 0; 32449ab747fSPaolo Bonzini r->buf = NULL; 32549ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 32649ab747fSPaolo Bonzini scsi_req_ref(&r->req); 3274be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_NONE, 3284be74634SMarkus Armbruster scsi_command_complete); 32949ab747fSPaolo Bonzini if (ret < 0) { 330fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 33149ab747fSPaolo Bonzini return 0; 33249ab747fSPaolo Bonzini } 33349ab747fSPaolo Bonzini return 0; 33449ab747fSPaolo Bonzini } 33549ab747fSPaolo Bonzini 33649ab747fSPaolo Bonzini if (r->buflen != r->req.cmd.xfer) { 33749ab747fSPaolo Bonzini g_free(r->buf); 33849ab747fSPaolo Bonzini r->buf = g_malloc(r->req.cmd.xfer); 33949ab747fSPaolo Bonzini r->buflen = r->req.cmd.xfer; 34049ab747fSPaolo Bonzini } 34149ab747fSPaolo Bonzini 34249ab747fSPaolo Bonzini memset(r->buf, 0, r->buflen); 34349ab747fSPaolo Bonzini r->len = r->req.cmd.xfer; 34449ab747fSPaolo Bonzini if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { 34549ab747fSPaolo Bonzini r->len = 0; 34649ab747fSPaolo Bonzini return -r->req.cmd.xfer; 34749ab747fSPaolo Bonzini } else { 34849ab747fSPaolo Bonzini return r->req.cmd.xfer; 34949ab747fSPaolo Bonzini } 35049ab747fSPaolo Bonzini } 35149ab747fSPaolo Bonzini 3529fd7e859SPaolo Bonzini static int read_naa_id(const uint8_t *p, uint64_t *p_wwn) 3539fd7e859SPaolo Bonzini { 3549fd7e859SPaolo Bonzini int i; 3559fd7e859SPaolo Bonzini 3569fd7e859SPaolo Bonzini if ((p[1] & 0xF) == 3) { 3579fd7e859SPaolo Bonzini /* NAA designator type */ 3589fd7e859SPaolo Bonzini if (p[3] != 8) { 3599fd7e859SPaolo Bonzini return -EINVAL; 3609fd7e859SPaolo Bonzini } 3619fd7e859SPaolo Bonzini *p_wwn = ldq_be_p(p + 4); 3629fd7e859SPaolo Bonzini return 0; 3639fd7e859SPaolo Bonzini } 3649fd7e859SPaolo Bonzini 3659fd7e859SPaolo Bonzini if ((p[1] & 0xF) == 8) { 3669fd7e859SPaolo Bonzini /* SCSI name string designator type */ 3679fd7e859SPaolo Bonzini if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) { 3689fd7e859SPaolo Bonzini return -EINVAL; 3699fd7e859SPaolo Bonzini } 3709fd7e859SPaolo Bonzini if (p[3] > 20 && p[24] != ',') { 3719fd7e859SPaolo Bonzini return -EINVAL; 3729fd7e859SPaolo Bonzini } 3739fd7e859SPaolo Bonzini *p_wwn = 0; 3749fd7e859SPaolo Bonzini for (i = 8; i < 24; i++) { 37595a5befcSPeter Maydell char c = qemu_toupper(p[i]); 3769fd7e859SPaolo Bonzini c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10); 3779fd7e859SPaolo Bonzini *p_wwn = (*p_wwn << 4) | c; 3789fd7e859SPaolo Bonzini } 3799fd7e859SPaolo Bonzini return 0; 3809fd7e859SPaolo Bonzini } 3819fd7e859SPaolo Bonzini 3829fd7e859SPaolo Bonzini return -EINVAL; 3839fd7e859SPaolo Bonzini } 3849fd7e859SPaolo Bonzini 3859fd7e859SPaolo Bonzini void scsi_generic_read_device_identification(SCSIDevice *s) 3869fd7e859SPaolo Bonzini { 3879fd7e859SPaolo Bonzini uint8_t cmd[6]; 3889fd7e859SPaolo Bonzini uint8_t buf[250]; 3899fd7e859SPaolo Bonzini uint8_t sensebuf[8]; 3909fd7e859SPaolo Bonzini sg_io_hdr_t io_header; 3919fd7e859SPaolo Bonzini int ret; 3929fd7e859SPaolo Bonzini int i, len; 3939fd7e859SPaolo Bonzini 3949fd7e859SPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 3959fd7e859SPaolo Bonzini memset(buf, 0, sizeof(buf)); 3969fd7e859SPaolo Bonzini cmd[0] = INQUIRY; 3979fd7e859SPaolo Bonzini cmd[1] = 1; 3989fd7e859SPaolo Bonzini cmd[2] = 0x83; 3999fd7e859SPaolo Bonzini cmd[4] = sizeof(buf); 4009fd7e859SPaolo Bonzini 4019fd7e859SPaolo Bonzini memset(&io_header, 0, sizeof(io_header)); 4029fd7e859SPaolo Bonzini io_header.interface_id = 'S'; 4039fd7e859SPaolo Bonzini io_header.dxfer_direction = SG_DXFER_FROM_DEV; 4049fd7e859SPaolo Bonzini io_header.dxfer_len = sizeof(buf); 4059fd7e859SPaolo Bonzini io_header.dxferp = buf; 4069fd7e859SPaolo Bonzini io_header.cmdp = cmd; 4079fd7e859SPaolo Bonzini io_header.cmd_len = sizeof(cmd); 4089fd7e859SPaolo Bonzini io_header.mx_sb_len = sizeof(sensebuf); 4099fd7e859SPaolo Bonzini io_header.sbp = sensebuf; 4109fd7e859SPaolo Bonzini io_header.timeout = 6000; /* XXX */ 4119fd7e859SPaolo Bonzini 4129fd7e859SPaolo Bonzini ret = blk_ioctl(s->conf.blk, SG_IO, &io_header); 4139fd7e859SPaolo Bonzini if (ret < 0 || io_header.driver_status || io_header.host_status) { 4149fd7e859SPaolo Bonzini return; 4159fd7e859SPaolo Bonzini } 4169fd7e859SPaolo Bonzini 4179fd7e859SPaolo Bonzini len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4); 4189fd7e859SPaolo Bonzini for (i = 0; i + 3 <= len; ) { 4199fd7e859SPaolo Bonzini const uint8_t *p = &buf[i + 4]; 4209fd7e859SPaolo Bonzini uint64_t wwn; 4219fd7e859SPaolo Bonzini 4229fd7e859SPaolo Bonzini if (i + (p[3] + 4) > len) { 4239fd7e859SPaolo Bonzini break; 4249fd7e859SPaolo Bonzini } 4259fd7e859SPaolo Bonzini 4269fd7e859SPaolo Bonzini if ((p[1] & 0x10) == 0) { 4279fd7e859SPaolo Bonzini /* Associated with the logical unit */ 4289fd7e859SPaolo Bonzini if (read_naa_id(p, &wwn) == 0) { 4299fd7e859SPaolo Bonzini s->wwn = wwn; 4309fd7e859SPaolo Bonzini } 4319fd7e859SPaolo Bonzini } else if ((p[1] & 0x10) == 0x10) { 4329fd7e859SPaolo Bonzini /* Associated with the target port */ 4339fd7e859SPaolo Bonzini if (read_naa_id(p, &wwn) == 0) { 4349fd7e859SPaolo Bonzini s->port_wwn = wwn; 4359fd7e859SPaolo Bonzini } 4369fd7e859SPaolo Bonzini } 4379fd7e859SPaolo Bonzini 4389fd7e859SPaolo Bonzini i += p[3] + 4; 4399fd7e859SPaolo Bonzini } 4409fd7e859SPaolo Bonzini } 4419fd7e859SPaolo Bonzini 4424be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk) 44349ab747fSPaolo Bonzini { 44449ab747fSPaolo Bonzini uint8_t cmd[6]; 44549ab747fSPaolo Bonzini uint8_t buf[12]; 44649ab747fSPaolo Bonzini uint8_t sensebuf[8]; 44749ab747fSPaolo Bonzini sg_io_hdr_t io_header; 44849ab747fSPaolo Bonzini int ret; 44949ab747fSPaolo Bonzini 45049ab747fSPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 45149ab747fSPaolo Bonzini memset(buf, 0, sizeof(buf)); 45249ab747fSPaolo Bonzini cmd[0] = MODE_SENSE; 45349ab747fSPaolo Bonzini cmd[4] = sizeof(buf); 45449ab747fSPaolo Bonzini 45549ab747fSPaolo Bonzini memset(&io_header, 0, sizeof(io_header)); 45649ab747fSPaolo Bonzini io_header.interface_id = 'S'; 45749ab747fSPaolo Bonzini io_header.dxfer_direction = SG_DXFER_FROM_DEV; 45849ab747fSPaolo Bonzini io_header.dxfer_len = sizeof(buf); 45949ab747fSPaolo Bonzini io_header.dxferp = buf; 46049ab747fSPaolo Bonzini io_header.cmdp = cmd; 46149ab747fSPaolo Bonzini io_header.cmd_len = sizeof(cmd); 46249ab747fSPaolo Bonzini io_header.mx_sb_len = sizeof(sensebuf); 46349ab747fSPaolo Bonzini io_header.sbp = sensebuf; 46449ab747fSPaolo Bonzini io_header.timeout = 6000; /* XXX */ 46549ab747fSPaolo Bonzini 4664be74634SMarkus Armbruster ret = blk_ioctl(blk, SG_IO, &io_header); 46749ab747fSPaolo Bonzini if (ret < 0 || io_header.driver_status || io_header.host_status) { 46849ab747fSPaolo Bonzini return -1; 46949ab747fSPaolo Bonzini } 47049ab747fSPaolo Bonzini return (buf[9] << 16) | (buf[10] << 8) | buf[11]; 47149ab747fSPaolo Bonzini } 47249ab747fSPaolo Bonzini 47349ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev) 47449ab747fSPaolo Bonzini { 47549ab747fSPaolo Bonzini SCSIDevice *s = SCSI_DEVICE(dev); 47649ab747fSPaolo Bonzini 47749ab747fSPaolo Bonzini scsi_device_purge_requests(s, SENSE_CODE(RESET)); 47849ab747fSPaolo Bonzini } 47949ab747fSPaolo Bonzini 480a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp) 48149ab747fSPaolo Bonzini { 4826ee143a0SPaolo Bonzini int rc; 48349ab747fSPaolo Bonzini int sg_version; 48449ab747fSPaolo Bonzini struct sg_scsi_id scsiid; 48549ab747fSPaolo Bonzini 4864be74634SMarkus Armbruster if (!s->conf.blk) { 487a818a4b6SFam Zheng error_setg(errp, "drive property not set"); 488a818a4b6SFam Zheng return; 48949ab747fSPaolo Bonzini } 49049ab747fSPaolo Bonzini 4914be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { 492a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option werror"); 493a818a4b6SFam Zheng return; 49449ab747fSPaolo Bonzini } 4954be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { 496a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option rerror"); 497a818a4b6SFam Zheng return; 49849ab747fSPaolo Bonzini } 49949ab747fSPaolo Bonzini 50049ab747fSPaolo Bonzini /* check we are using a driver managing SG_IO (version 3 and after */ 5014be74634SMarkus Armbruster rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); 5026ee143a0SPaolo Bonzini if (rc < 0) { 503a818a4b6SFam Zheng error_setg(errp, "cannot get SG_IO version number: %s. " 5046ee143a0SPaolo Bonzini "Is this a SCSI device?", 5056ee143a0SPaolo Bonzini strerror(-rc)); 506a818a4b6SFam Zheng return; 50749ab747fSPaolo Bonzini } 50849ab747fSPaolo Bonzini if (sg_version < 30000) { 509a818a4b6SFam Zheng error_setg(errp, "scsi generic interface too old"); 510a818a4b6SFam Zheng return; 51149ab747fSPaolo Bonzini } 51249ab747fSPaolo Bonzini 51349ab747fSPaolo Bonzini /* get LUN of the /dev/sg? */ 5144be74634SMarkus Armbruster if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { 515a818a4b6SFam Zheng error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); 516a818a4b6SFam Zheng return; 51749ab747fSPaolo Bonzini } 51849ab747fSPaolo Bonzini 51949ab747fSPaolo Bonzini /* define device state */ 52049ab747fSPaolo Bonzini s->type = scsiid.scsi_type; 52149ab747fSPaolo Bonzini DPRINTF("device type %d\n", s->type); 52249ab747fSPaolo Bonzini 52349ab747fSPaolo Bonzini switch (s->type) { 52449ab747fSPaolo Bonzini case TYPE_TAPE: 5254be74634SMarkus Armbruster s->blocksize = get_stream_blocksize(s->conf.blk); 52649ab747fSPaolo Bonzini if (s->blocksize == -1) { 52749ab747fSPaolo Bonzini s->blocksize = 0; 52849ab747fSPaolo Bonzini } 52949ab747fSPaolo Bonzini break; 53049ab747fSPaolo Bonzini 53149ab747fSPaolo Bonzini /* Make a guess for block devices, we'll fix it when the guest sends. 53249ab747fSPaolo Bonzini * READ CAPACITY. If they don't, they likely would assume these sizes 53349ab747fSPaolo Bonzini * anyway. (TODO: they could also send MODE SENSE). 53449ab747fSPaolo Bonzini */ 53549ab747fSPaolo Bonzini case TYPE_ROM: 53649ab747fSPaolo Bonzini case TYPE_WORM: 53749ab747fSPaolo Bonzini s->blocksize = 2048; 53849ab747fSPaolo Bonzini break; 53949ab747fSPaolo Bonzini default: 54049ab747fSPaolo Bonzini s->blocksize = 512; 54149ab747fSPaolo Bonzini break; 54249ab747fSPaolo Bonzini } 54349ab747fSPaolo Bonzini 54449ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 5459fd7e859SPaolo Bonzini 5469fd7e859SPaolo Bonzini scsi_generic_read_device_identification(s); 54749ab747fSPaolo Bonzini } 54849ab747fSPaolo Bonzini 54949ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = { 55049ab747fSPaolo Bonzini .size = sizeof(SCSIGenericReq), 55149ab747fSPaolo Bonzini .free_req = scsi_free_request, 55249ab747fSPaolo Bonzini .send_command = scsi_send_command, 55349ab747fSPaolo Bonzini .read_data = scsi_read_data, 55449ab747fSPaolo Bonzini .write_data = scsi_write_data, 55549ab747fSPaolo Bonzini .get_buf = scsi_get_buf, 55649ab747fSPaolo Bonzini .load_request = scsi_generic_load_request, 55749ab747fSPaolo Bonzini .save_request = scsi_generic_save_request, 55849ab747fSPaolo Bonzini }; 55949ab747fSPaolo Bonzini 56049ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, 56149ab747fSPaolo Bonzini uint8_t *buf, void *hba_private) 56249ab747fSPaolo Bonzini { 5639be38598SEduardo Habkost return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); 56449ab747fSPaolo Bonzini } 56549ab747fSPaolo Bonzini 56649ab747fSPaolo Bonzini static Property scsi_generic_properties[] = { 5674be74634SMarkus Armbruster DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), 56849ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 56949ab747fSPaolo Bonzini }; 57049ab747fSPaolo Bonzini 5713e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, 5723e7e180aSPaolo Bonzini uint8_t *buf, void *hba_private) 5733e7e180aSPaolo Bonzini { 5743e7e180aSPaolo Bonzini return scsi_bus_parse_cdb(dev, cmd, buf, hba_private); 5753e7e180aSPaolo Bonzini } 5763e7e180aSPaolo Bonzini 57749ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data) 57849ab747fSPaolo Bonzini { 57949ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 58049ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); 58149ab747fSPaolo Bonzini 582a818a4b6SFam Zheng sc->realize = scsi_generic_realize; 58349ab747fSPaolo Bonzini sc->alloc_req = scsi_new_request; 5843e7e180aSPaolo Bonzini sc->parse_cdb = scsi_generic_parse_cdb; 58549ab747fSPaolo Bonzini dc->fw_name = "disk"; 58649ab747fSPaolo Bonzini dc->desc = "pass through generic scsi device (/dev/sg*)"; 58749ab747fSPaolo Bonzini dc->reset = scsi_generic_reset; 58849ab747fSPaolo Bonzini dc->props = scsi_generic_properties; 58949ab747fSPaolo Bonzini dc->vmsd = &vmstate_scsi_device; 59049ab747fSPaolo Bonzini } 59149ab747fSPaolo Bonzini 59249ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = { 59349ab747fSPaolo Bonzini .name = "scsi-generic", 59449ab747fSPaolo Bonzini .parent = TYPE_SCSI_DEVICE, 59549ab747fSPaolo Bonzini .instance_size = sizeof(SCSIDevice), 59649ab747fSPaolo Bonzini .class_init = scsi_generic_class_initfn, 59749ab747fSPaolo Bonzini }; 59849ab747fSPaolo Bonzini 59949ab747fSPaolo Bonzini static void scsi_generic_register_types(void) 60049ab747fSPaolo Bonzini { 60149ab747fSPaolo Bonzini type_register_static(&scsi_generic_info); 60249ab747fSPaolo Bonzini } 60349ab747fSPaolo Bonzini 60449ab747fSPaolo Bonzini type_init(scsi_generic_register_types) 60549ab747fSPaolo Bonzini 60649ab747fSPaolo Bonzini #endif /* __linux__ */ 607