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 1449ab747fSPaolo Bonzini #include "qemu-common.h" 1549ab747fSPaolo Bonzini #include "qemu/error-report.h" 1649ab747fSPaolo Bonzini #include "hw/scsi/scsi.h" 174be74634SMarkus Armbruster #include "sysemu/block-backend.h" 1849ab747fSPaolo Bonzini #include "sysemu/blockdev.h" 1949ab747fSPaolo Bonzini 2049ab747fSPaolo Bonzini #ifdef __linux__ 2149ab747fSPaolo Bonzini 2249ab747fSPaolo Bonzini //#define DEBUG_SCSI 2349ab747fSPaolo Bonzini 2449ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 2549ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) \ 2649ab747fSPaolo Bonzini do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0) 2749ab747fSPaolo Bonzini #else 2849ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) do {} while(0) 2949ab747fSPaolo Bonzini #endif 3049ab747fSPaolo Bonzini 3149ab747fSPaolo Bonzini #define BADF(fmt, ...) \ 3249ab747fSPaolo Bonzini do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) 3349ab747fSPaolo Bonzini 3449ab747fSPaolo Bonzini #include <stdio.h> 3549ab747fSPaolo Bonzini #include <sys/types.h> 3649ab747fSPaolo Bonzini #include <sys/stat.h> 3749ab747fSPaolo Bonzini #include <unistd.h> 3849ab747fSPaolo Bonzini #include <scsi/sg.h> 3949ab747fSPaolo Bonzini #include "block/scsi.h" 4049ab747fSPaolo Bonzini 4149ab747fSPaolo Bonzini #define SG_ERR_DRIVER_TIMEOUT 0x06 4249ab747fSPaolo Bonzini #define SG_ERR_DRIVER_SENSE 0x08 4349ab747fSPaolo Bonzini 4449ab747fSPaolo Bonzini #define SG_ERR_DID_OK 0x00 4549ab747fSPaolo Bonzini #define SG_ERR_DID_NO_CONNECT 0x01 4649ab747fSPaolo Bonzini #define SG_ERR_DID_BUS_BUSY 0x02 4749ab747fSPaolo Bonzini #define SG_ERR_DID_TIME_OUT 0x03 4849ab747fSPaolo Bonzini 4949ab747fSPaolo Bonzini #ifndef MAX_UINT 5049ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1) 5149ab747fSPaolo Bonzini #endif 5249ab747fSPaolo Bonzini 5349ab747fSPaolo Bonzini typedef struct SCSIGenericReq { 5449ab747fSPaolo Bonzini SCSIRequest req; 5549ab747fSPaolo Bonzini uint8_t *buf; 5649ab747fSPaolo Bonzini int buflen; 5749ab747fSPaolo Bonzini int len; 5849ab747fSPaolo Bonzini sg_io_hdr_t io_header; 5949ab747fSPaolo Bonzini } SCSIGenericReq; 6049ab747fSPaolo Bonzini 6149ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) 6249ab747fSPaolo Bonzini { 6349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 6449ab747fSPaolo Bonzini 6549ab747fSPaolo Bonzini qemu_put_sbe32s(f, &r->buflen); 6649ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 6749ab747fSPaolo Bonzini assert(!r->req.sg); 6849ab747fSPaolo Bonzini qemu_put_buffer(f, r->buf, r->req.cmd.xfer); 6949ab747fSPaolo Bonzini } 7049ab747fSPaolo Bonzini } 7149ab747fSPaolo Bonzini 7249ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) 7349ab747fSPaolo Bonzini { 7449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 7549ab747fSPaolo Bonzini 7649ab747fSPaolo Bonzini qemu_get_sbe32s(f, &r->buflen); 7749ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 7849ab747fSPaolo Bonzini assert(!r->req.sg); 7949ab747fSPaolo Bonzini qemu_get_buffer(f, r->buf, r->req.cmd.xfer); 8049ab747fSPaolo Bonzini } 8149ab747fSPaolo Bonzini } 8249ab747fSPaolo Bonzini 8349ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req) 8449ab747fSPaolo Bonzini { 8549ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 8649ab747fSPaolo Bonzini 8749ab747fSPaolo Bonzini g_free(r->buf); 8849ab747fSPaolo Bonzini } 8949ab747fSPaolo Bonzini 9049ab747fSPaolo Bonzini /* Helper function for command completion. */ 91*fa0d653bSPaolo Bonzini static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) 9249ab747fSPaolo Bonzini { 9349ab747fSPaolo Bonzini int status; 9449ab747fSPaolo Bonzini 95*fa0d653bSPaolo Bonzini assert(r->req.aiocb == NULL); 96*fa0d653bSPaolo Bonzini 976c25fa6cSFam Zheng if (r->req.io_canceled) { 98d5776465SFam Zheng scsi_req_cancel_complete(&r->req); 996c25fa6cSFam Zheng goto done; 1006c25fa6cSFam Zheng } 10149ab747fSPaolo Bonzini if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 10249ab747fSPaolo Bonzini r->req.sense_len = r->io_header.sb_len_wr; 10349ab747fSPaolo Bonzini } 10449ab747fSPaolo Bonzini 10549ab747fSPaolo Bonzini if (ret != 0) { 10649ab747fSPaolo Bonzini switch (ret) { 10749ab747fSPaolo Bonzini case -EDOM: 10849ab747fSPaolo Bonzini status = TASK_SET_FULL; 10949ab747fSPaolo Bonzini break; 11049ab747fSPaolo Bonzini case -ENOMEM: 11149ab747fSPaolo Bonzini status = CHECK_CONDITION; 11249ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE)); 11349ab747fSPaolo Bonzini break; 11449ab747fSPaolo Bonzini default: 11549ab747fSPaolo Bonzini status = CHECK_CONDITION; 11649ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR)); 11749ab747fSPaolo Bonzini break; 11849ab747fSPaolo Bonzini } 11949ab747fSPaolo Bonzini } else { 12049ab747fSPaolo Bonzini if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT || 12149ab747fSPaolo Bonzini r->io_header.host_status == SG_ERR_DID_BUS_BUSY || 12249ab747fSPaolo Bonzini r->io_header.host_status == SG_ERR_DID_TIME_OUT || 12349ab747fSPaolo Bonzini (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) { 12449ab747fSPaolo Bonzini status = BUSY; 12549ab747fSPaolo Bonzini BADF("Driver Timeout\n"); 12649ab747fSPaolo Bonzini } else if (r->io_header.host_status) { 12749ab747fSPaolo Bonzini status = CHECK_CONDITION; 12849ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS)); 12949ab747fSPaolo Bonzini } else if (r->io_header.status) { 13049ab747fSPaolo Bonzini status = r->io_header.status; 13149ab747fSPaolo Bonzini } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 13249ab747fSPaolo Bonzini status = CHECK_CONDITION; 13349ab747fSPaolo Bonzini } else { 13449ab747fSPaolo Bonzini status = GOOD; 13549ab747fSPaolo Bonzini } 13649ab747fSPaolo Bonzini } 13749ab747fSPaolo Bonzini DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", 13849ab747fSPaolo Bonzini r, r->req.tag, status); 13949ab747fSPaolo Bonzini 14049ab747fSPaolo Bonzini scsi_req_complete(&r->req, status); 1416c25fa6cSFam Zheng done: 14249ab747fSPaolo Bonzini scsi_req_unref(&r->req); 14349ab747fSPaolo Bonzini } 14449ab747fSPaolo Bonzini 145*fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret) 146*fa0d653bSPaolo Bonzini { 147*fa0d653bSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 148*fa0d653bSPaolo Bonzini 149*fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 150*fa0d653bSPaolo Bonzini r->req.aiocb = NULL; 151*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 152*fa0d653bSPaolo Bonzini } 153*fa0d653bSPaolo Bonzini 1544be74634SMarkus Armbruster static int execute_command(BlockBackend *blk, 15549ab747fSPaolo Bonzini SCSIGenericReq *r, int direction, 156097310b5SMarkus Armbruster BlockCompletionFunc *complete) 15749ab747fSPaolo Bonzini { 15849ab747fSPaolo Bonzini r->io_header.interface_id = 'S'; 15949ab747fSPaolo Bonzini r->io_header.dxfer_direction = direction; 16049ab747fSPaolo Bonzini r->io_header.dxferp = r->buf; 16149ab747fSPaolo Bonzini r->io_header.dxfer_len = r->buflen; 16249ab747fSPaolo Bonzini r->io_header.cmdp = r->req.cmd.buf; 16349ab747fSPaolo Bonzini r->io_header.cmd_len = r->req.cmd.len; 16449ab747fSPaolo Bonzini r->io_header.mx_sb_len = sizeof(r->req.sense); 16549ab747fSPaolo Bonzini r->io_header.sbp = r->req.sense; 16649ab747fSPaolo Bonzini r->io_header.timeout = MAX_UINT; 16749ab747fSPaolo Bonzini r->io_header.usr_ptr = r; 16849ab747fSPaolo Bonzini r->io_header.flags |= SG_FLAG_DIRECT_IO; 16949ab747fSPaolo Bonzini 1704be74634SMarkus Armbruster r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r); 171d836f8d3SPavel Hrdina if (r->req.aiocb == NULL) { 172d836f8d3SPavel Hrdina return -EIO; 173d836f8d3SPavel Hrdina } 17449ab747fSPaolo Bonzini 17549ab747fSPaolo Bonzini return 0; 17649ab747fSPaolo Bonzini } 17749ab747fSPaolo Bonzini 17849ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret) 17949ab747fSPaolo Bonzini { 18049ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 18149ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 18249ab747fSPaolo Bonzini int len; 18349ab747fSPaolo Bonzini 184*fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 18549ab747fSPaolo Bonzini r->req.aiocb = NULL; 186*fa0d653bSPaolo Bonzini 1876c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 188*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 18949ab747fSPaolo Bonzini return; 19049ab747fSPaolo Bonzini } 191*fa0d653bSPaolo Bonzini 19249ab747fSPaolo Bonzini len = r->io_header.dxfer_len - r->io_header.resid; 19349ab747fSPaolo Bonzini DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); 19449ab747fSPaolo Bonzini 19549ab747fSPaolo Bonzini r->len = -1; 19649ab747fSPaolo Bonzini if (len == 0) { 197*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 198*fa0d653bSPaolo Bonzini return; 199*fa0d653bSPaolo Bonzini } 200*fa0d653bSPaolo Bonzini 20149ab747fSPaolo Bonzini /* Snoop READ CAPACITY output to set the blocksize. */ 20253254e56SPaolo Bonzini if (r->req.cmd.buf[0] == READ_CAPACITY_10 && 20353254e56SPaolo Bonzini (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { 20449ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[4]); 20553254e56SPaolo Bonzini s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; 20649ab747fSPaolo Bonzini } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && 20749ab747fSPaolo Bonzini (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { 20849ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[8]); 20949ab747fSPaolo Bonzini s->max_lba = ldq_be_p(&r->buf[0]); 21049ab747fSPaolo Bonzini } 2114be74634SMarkus Armbruster blk_set_guest_block_size(s->conf.blk, s->blocksize); 21249ab747fSPaolo Bonzini 21349ab747fSPaolo Bonzini scsi_req_data(&r->req, len); 21449ab747fSPaolo Bonzini scsi_req_unref(&r->req); 21549ab747fSPaolo Bonzini } 21649ab747fSPaolo Bonzini 21749ab747fSPaolo Bonzini /* Read more data from scsi device into buffer. */ 21849ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req) 21949ab747fSPaolo Bonzini { 22049ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 22149ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 22249ab747fSPaolo Bonzini int ret; 22349ab747fSPaolo Bonzini 22449ab747fSPaolo Bonzini DPRINTF("scsi_read_data 0x%x\n", req->tag); 22549ab747fSPaolo Bonzini 22649ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 22749ab747fSPaolo Bonzini scsi_req_ref(&r->req); 22849ab747fSPaolo Bonzini if (r->len == -1) { 229*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 23049ab747fSPaolo Bonzini return; 23149ab747fSPaolo Bonzini } 23249ab747fSPaolo Bonzini 2334be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV, 2344be74634SMarkus Armbruster scsi_read_complete); 23549ab747fSPaolo Bonzini if (ret < 0) { 236*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 23749ab747fSPaolo Bonzini } 23849ab747fSPaolo Bonzini } 23949ab747fSPaolo Bonzini 24049ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret) 24149ab747fSPaolo Bonzini { 24249ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 24349ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 24449ab747fSPaolo Bonzini 24549ab747fSPaolo Bonzini DPRINTF("scsi_write_complete() ret = %d\n", ret); 246*fa0d653bSPaolo Bonzini 247*fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 24849ab747fSPaolo Bonzini r->req.aiocb = NULL; 249*fa0d653bSPaolo Bonzini 2506c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 251*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 25249ab747fSPaolo Bonzini return; 25349ab747fSPaolo Bonzini } 25449ab747fSPaolo Bonzini 25549ab747fSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && 25649ab747fSPaolo Bonzini s->type == TYPE_TAPE) { 25749ab747fSPaolo Bonzini s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; 25849ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 25949ab747fSPaolo Bonzini } 26049ab747fSPaolo Bonzini 261*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 26249ab747fSPaolo Bonzini } 26349ab747fSPaolo Bonzini 26449ab747fSPaolo Bonzini /* Write data to a scsi device. Returns nonzero on failure. 26549ab747fSPaolo Bonzini The transfer may complete asynchronously. */ 26649ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req) 26749ab747fSPaolo Bonzini { 26849ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 26949ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 27049ab747fSPaolo Bonzini int ret; 27149ab747fSPaolo Bonzini 27249ab747fSPaolo Bonzini DPRINTF("scsi_write_data 0x%x\n", req->tag); 27349ab747fSPaolo Bonzini if (r->len == 0) { 27449ab747fSPaolo Bonzini r->len = r->buflen; 27549ab747fSPaolo Bonzini scsi_req_data(&r->req, r->len); 27649ab747fSPaolo Bonzini return; 27749ab747fSPaolo Bonzini } 27849ab747fSPaolo Bonzini 27949ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 28049ab747fSPaolo Bonzini scsi_req_ref(&r->req); 2814be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete); 28249ab747fSPaolo Bonzini if (ret < 0) { 283*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 28449ab747fSPaolo Bonzini } 28549ab747fSPaolo Bonzini } 28649ab747fSPaolo Bonzini 28749ab747fSPaolo Bonzini /* Return a pointer to the data buffer. */ 28849ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req) 28949ab747fSPaolo Bonzini { 29049ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 29149ab747fSPaolo Bonzini 29249ab747fSPaolo Bonzini return r->buf; 29349ab747fSPaolo Bonzini } 29449ab747fSPaolo Bonzini 29549ab747fSPaolo Bonzini /* Execute a scsi command. Returns the length of the data expected by the 29649ab747fSPaolo Bonzini command. This will be Positive for data transfers from the device 29749ab747fSPaolo Bonzini (eg. disk reads), negative for transfers to the device (eg. disk writes), 29849ab747fSPaolo Bonzini and zero if the command does not transfer any data. */ 29949ab747fSPaolo Bonzini 30049ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) 30149ab747fSPaolo Bonzini { 30249ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 30349ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 30449ab747fSPaolo Bonzini int ret; 30549ab747fSPaolo Bonzini 30649ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 30749ab747fSPaolo Bonzini { 30849ab747fSPaolo Bonzini int i; 30949ab747fSPaolo Bonzini for (i = 1; i < r->req.cmd.len; i++) { 31049ab747fSPaolo Bonzini printf(" 0x%02x", cmd[i]); 31149ab747fSPaolo Bonzini } 31249ab747fSPaolo Bonzini printf("\n"); 31349ab747fSPaolo Bonzini } 31449ab747fSPaolo Bonzini #endif 31549ab747fSPaolo Bonzini 31649ab747fSPaolo Bonzini if (r->req.cmd.xfer == 0) { 31749ab747fSPaolo Bonzini g_free(r->buf); 31849ab747fSPaolo Bonzini r->buflen = 0; 31949ab747fSPaolo Bonzini r->buf = NULL; 32049ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 32149ab747fSPaolo Bonzini scsi_req_ref(&r->req); 3224be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_NONE, 3234be74634SMarkus Armbruster scsi_command_complete); 32449ab747fSPaolo Bonzini if (ret < 0) { 325*fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 32649ab747fSPaolo Bonzini return 0; 32749ab747fSPaolo Bonzini } 32849ab747fSPaolo Bonzini return 0; 32949ab747fSPaolo Bonzini } 33049ab747fSPaolo Bonzini 33149ab747fSPaolo Bonzini if (r->buflen != r->req.cmd.xfer) { 33249ab747fSPaolo Bonzini g_free(r->buf); 33349ab747fSPaolo Bonzini r->buf = g_malloc(r->req.cmd.xfer); 33449ab747fSPaolo Bonzini r->buflen = r->req.cmd.xfer; 33549ab747fSPaolo Bonzini } 33649ab747fSPaolo Bonzini 33749ab747fSPaolo Bonzini memset(r->buf, 0, r->buflen); 33849ab747fSPaolo Bonzini r->len = r->req.cmd.xfer; 33949ab747fSPaolo Bonzini if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { 34049ab747fSPaolo Bonzini r->len = 0; 34149ab747fSPaolo Bonzini return -r->req.cmd.xfer; 34249ab747fSPaolo Bonzini } else { 34349ab747fSPaolo Bonzini return r->req.cmd.xfer; 34449ab747fSPaolo Bonzini } 34549ab747fSPaolo Bonzini } 34649ab747fSPaolo Bonzini 3474be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk) 34849ab747fSPaolo Bonzini { 34949ab747fSPaolo Bonzini uint8_t cmd[6]; 35049ab747fSPaolo Bonzini uint8_t buf[12]; 35149ab747fSPaolo Bonzini uint8_t sensebuf[8]; 35249ab747fSPaolo Bonzini sg_io_hdr_t io_header; 35349ab747fSPaolo Bonzini int ret; 35449ab747fSPaolo Bonzini 35549ab747fSPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 35649ab747fSPaolo Bonzini memset(buf, 0, sizeof(buf)); 35749ab747fSPaolo Bonzini cmd[0] = MODE_SENSE; 35849ab747fSPaolo Bonzini cmd[4] = sizeof(buf); 35949ab747fSPaolo Bonzini 36049ab747fSPaolo Bonzini memset(&io_header, 0, sizeof(io_header)); 36149ab747fSPaolo Bonzini io_header.interface_id = 'S'; 36249ab747fSPaolo Bonzini io_header.dxfer_direction = SG_DXFER_FROM_DEV; 36349ab747fSPaolo Bonzini io_header.dxfer_len = sizeof(buf); 36449ab747fSPaolo Bonzini io_header.dxferp = buf; 36549ab747fSPaolo Bonzini io_header.cmdp = cmd; 36649ab747fSPaolo Bonzini io_header.cmd_len = sizeof(cmd); 36749ab747fSPaolo Bonzini io_header.mx_sb_len = sizeof(sensebuf); 36849ab747fSPaolo Bonzini io_header.sbp = sensebuf; 36949ab747fSPaolo Bonzini io_header.timeout = 6000; /* XXX */ 37049ab747fSPaolo Bonzini 3714be74634SMarkus Armbruster ret = blk_ioctl(blk, SG_IO, &io_header); 37249ab747fSPaolo Bonzini if (ret < 0 || io_header.driver_status || io_header.host_status) { 37349ab747fSPaolo Bonzini return -1; 37449ab747fSPaolo Bonzini } 37549ab747fSPaolo Bonzini return (buf[9] << 16) | (buf[10] << 8) | buf[11]; 37649ab747fSPaolo Bonzini } 37749ab747fSPaolo Bonzini 37849ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev) 37949ab747fSPaolo Bonzini { 38049ab747fSPaolo Bonzini SCSIDevice *s = SCSI_DEVICE(dev); 38149ab747fSPaolo Bonzini 38249ab747fSPaolo Bonzini scsi_device_purge_requests(s, SENSE_CODE(RESET)); 38349ab747fSPaolo Bonzini } 38449ab747fSPaolo Bonzini 385a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp) 38649ab747fSPaolo Bonzini { 3876ee143a0SPaolo Bonzini int rc; 38849ab747fSPaolo Bonzini int sg_version; 38949ab747fSPaolo Bonzini struct sg_scsi_id scsiid; 39049ab747fSPaolo Bonzini 3914be74634SMarkus Armbruster if (!s->conf.blk) { 392a818a4b6SFam Zheng error_setg(errp, "drive property not set"); 393a818a4b6SFam Zheng return; 39449ab747fSPaolo Bonzini } 39549ab747fSPaolo Bonzini 3964be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { 397a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option werror"); 398a818a4b6SFam Zheng return; 39949ab747fSPaolo Bonzini } 4004be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { 401a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option rerror"); 402a818a4b6SFam Zheng return; 40349ab747fSPaolo Bonzini } 40449ab747fSPaolo Bonzini 40549ab747fSPaolo Bonzini /* check we are using a driver managing SG_IO (version 3 and after */ 4064be74634SMarkus Armbruster rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); 4076ee143a0SPaolo Bonzini if (rc < 0) { 408a818a4b6SFam Zheng error_setg(errp, "cannot get SG_IO version number: %s. " 4096ee143a0SPaolo Bonzini "Is this a SCSI device?", 4106ee143a0SPaolo Bonzini strerror(-rc)); 411a818a4b6SFam Zheng return; 41249ab747fSPaolo Bonzini } 41349ab747fSPaolo Bonzini if (sg_version < 30000) { 414a818a4b6SFam Zheng error_setg(errp, "scsi generic interface too old"); 415a818a4b6SFam Zheng return; 41649ab747fSPaolo Bonzini } 41749ab747fSPaolo Bonzini 41849ab747fSPaolo Bonzini /* get LUN of the /dev/sg? */ 4194be74634SMarkus Armbruster if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { 420a818a4b6SFam Zheng error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); 421a818a4b6SFam Zheng return; 42249ab747fSPaolo Bonzini } 42349ab747fSPaolo Bonzini 42449ab747fSPaolo Bonzini /* define device state */ 42549ab747fSPaolo Bonzini s->type = scsiid.scsi_type; 42649ab747fSPaolo Bonzini DPRINTF("device type %d\n", s->type); 42749ab747fSPaolo Bonzini 42849ab747fSPaolo Bonzini switch (s->type) { 42949ab747fSPaolo Bonzini case TYPE_TAPE: 4304be74634SMarkus Armbruster s->blocksize = get_stream_blocksize(s->conf.blk); 43149ab747fSPaolo Bonzini if (s->blocksize == -1) { 43249ab747fSPaolo Bonzini s->blocksize = 0; 43349ab747fSPaolo Bonzini } 43449ab747fSPaolo Bonzini break; 43549ab747fSPaolo Bonzini 43649ab747fSPaolo Bonzini /* Make a guess for block devices, we'll fix it when the guest sends. 43749ab747fSPaolo Bonzini * READ CAPACITY. If they don't, they likely would assume these sizes 43849ab747fSPaolo Bonzini * anyway. (TODO: they could also send MODE SENSE). 43949ab747fSPaolo Bonzini */ 44049ab747fSPaolo Bonzini case TYPE_ROM: 44149ab747fSPaolo Bonzini case TYPE_WORM: 44249ab747fSPaolo Bonzini s->blocksize = 2048; 44349ab747fSPaolo Bonzini break; 44449ab747fSPaolo Bonzini default: 44549ab747fSPaolo Bonzini s->blocksize = 512; 44649ab747fSPaolo Bonzini break; 44749ab747fSPaolo Bonzini } 44849ab747fSPaolo Bonzini 44949ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 45049ab747fSPaolo Bonzini } 45149ab747fSPaolo Bonzini 45249ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = { 45349ab747fSPaolo Bonzini .size = sizeof(SCSIGenericReq), 45449ab747fSPaolo Bonzini .free_req = scsi_free_request, 45549ab747fSPaolo Bonzini .send_command = scsi_send_command, 45649ab747fSPaolo Bonzini .read_data = scsi_read_data, 45749ab747fSPaolo Bonzini .write_data = scsi_write_data, 45849ab747fSPaolo Bonzini .get_buf = scsi_get_buf, 45949ab747fSPaolo Bonzini .load_request = scsi_generic_load_request, 46049ab747fSPaolo Bonzini .save_request = scsi_generic_save_request, 46149ab747fSPaolo Bonzini }; 46249ab747fSPaolo Bonzini 46349ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, 46449ab747fSPaolo Bonzini uint8_t *buf, void *hba_private) 46549ab747fSPaolo Bonzini { 46649ab747fSPaolo Bonzini SCSIRequest *req; 46749ab747fSPaolo Bonzini 46849ab747fSPaolo Bonzini req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); 46949ab747fSPaolo Bonzini return req; 47049ab747fSPaolo Bonzini } 47149ab747fSPaolo Bonzini 47249ab747fSPaolo Bonzini static Property scsi_generic_properties[] = { 4734be74634SMarkus Armbruster DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), 47449ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 47549ab747fSPaolo Bonzini }; 47649ab747fSPaolo Bonzini 4773e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, 4783e7e180aSPaolo Bonzini uint8_t *buf, void *hba_private) 4793e7e180aSPaolo Bonzini { 4803e7e180aSPaolo Bonzini return scsi_bus_parse_cdb(dev, cmd, buf, hba_private); 4813e7e180aSPaolo Bonzini } 4823e7e180aSPaolo Bonzini 48349ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data) 48449ab747fSPaolo Bonzini { 48549ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 48649ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); 48749ab747fSPaolo Bonzini 488a818a4b6SFam Zheng sc->realize = scsi_generic_realize; 48949ab747fSPaolo Bonzini sc->alloc_req = scsi_new_request; 4903e7e180aSPaolo Bonzini sc->parse_cdb = scsi_generic_parse_cdb; 49149ab747fSPaolo Bonzini dc->fw_name = "disk"; 49249ab747fSPaolo Bonzini dc->desc = "pass through generic scsi device (/dev/sg*)"; 49349ab747fSPaolo Bonzini dc->reset = scsi_generic_reset; 49449ab747fSPaolo Bonzini dc->props = scsi_generic_properties; 49549ab747fSPaolo Bonzini dc->vmsd = &vmstate_scsi_device; 49649ab747fSPaolo Bonzini } 49749ab747fSPaolo Bonzini 49849ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = { 49949ab747fSPaolo Bonzini .name = "scsi-generic", 50049ab747fSPaolo Bonzini .parent = TYPE_SCSI_DEVICE, 50149ab747fSPaolo Bonzini .instance_size = sizeof(SCSIDevice), 50249ab747fSPaolo Bonzini .class_init = scsi_generic_class_initfn, 50349ab747fSPaolo Bonzini }; 50449ab747fSPaolo Bonzini 50549ab747fSPaolo Bonzini static void scsi_generic_register_types(void) 50649ab747fSPaolo Bonzini { 50749ab747fSPaolo Bonzini type_register_static(&scsi_generic_info); 50849ab747fSPaolo Bonzini } 50949ab747fSPaolo Bonzini 51049ab747fSPaolo Bonzini type_init(scsi_generic_register_types) 51149ab747fSPaolo Bonzini 51249ab747fSPaolo Bonzini #endif /* __linux__ */ 513