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" 1749ab747fSPaolo Bonzini #include "sysemu/blockdev.h" 1849ab747fSPaolo Bonzini 1949ab747fSPaolo Bonzini #ifdef __linux__ 2049ab747fSPaolo Bonzini 2149ab747fSPaolo Bonzini //#define DEBUG_SCSI 2249ab747fSPaolo Bonzini 2349ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 2449ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) \ 2549ab747fSPaolo Bonzini do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0) 2649ab747fSPaolo Bonzini #else 2749ab747fSPaolo Bonzini #define DPRINTF(fmt, ...) do {} while(0) 2849ab747fSPaolo Bonzini #endif 2949ab747fSPaolo Bonzini 3049ab747fSPaolo Bonzini #define BADF(fmt, ...) \ 3149ab747fSPaolo Bonzini do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0) 3249ab747fSPaolo Bonzini 3349ab747fSPaolo Bonzini #include <stdio.h> 3449ab747fSPaolo Bonzini #include <sys/types.h> 3549ab747fSPaolo Bonzini #include <sys/stat.h> 3649ab747fSPaolo Bonzini #include <unistd.h> 3749ab747fSPaolo Bonzini #include <scsi/sg.h> 3849ab747fSPaolo Bonzini #include "block/scsi.h" 3949ab747fSPaolo Bonzini 4049ab747fSPaolo Bonzini #define SG_ERR_DRIVER_TIMEOUT 0x06 4149ab747fSPaolo Bonzini #define SG_ERR_DRIVER_SENSE 0x08 4249ab747fSPaolo Bonzini 4349ab747fSPaolo Bonzini #define SG_ERR_DID_OK 0x00 4449ab747fSPaolo Bonzini #define SG_ERR_DID_NO_CONNECT 0x01 4549ab747fSPaolo Bonzini #define SG_ERR_DID_BUS_BUSY 0x02 4649ab747fSPaolo Bonzini #define SG_ERR_DID_TIME_OUT 0x03 4749ab747fSPaolo Bonzini 4849ab747fSPaolo Bonzini #ifndef MAX_UINT 4949ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1) 5049ab747fSPaolo Bonzini #endif 5149ab747fSPaolo Bonzini 5249ab747fSPaolo Bonzini typedef struct SCSIGenericReq { 5349ab747fSPaolo Bonzini SCSIRequest req; 5449ab747fSPaolo Bonzini uint8_t *buf; 5549ab747fSPaolo Bonzini int buflen; 5649ab747fSPaolo Bonzini int len; 5749ab747fSPaolo Bonzini sg_io_hdr_t io_header; 5849ab747fSPaolo Bonzini } SCSIGenericReq; 5949ab747fSPaolo Bonzini 6049ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) 6149ab747fSPaolo Bonzini { 6249ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 6349ab747fSPaolo Bonzini 6449ab747fSPaolo Bonzini qemu_put_sbe32s(f, &r->buflen); 6549ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 6649ab747fSPaolo Bonzini assert(!r->req.sg); 6749ab747fSPaolo Bonzini qemu_put_buffer(f, r->buf, r->req.cmd.xfer); 6849ab747fSPaolo Bonzini } 6949ab747fSPaolo Bonzini } 7049ab747fSPaolo Bonzini 7149ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) 7249ab747fSPaolo Bonzini { 7349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 7449ab747fSPaolo Bonzini 7549ab747fSPaolo Bonzini qemu_get_sbe32s(f, &r->buflen); 7649ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 7749ab747fSPaolo Bonzini assert(!r->req.sg); 7849ab747fSPaolo Bonzini qemu_get_buffer(f, r->buf, r->req.cmd.xfer); 7949ab747fSPaolo Bonzini } 8049ab747fSPaolo Bonzini } 8149ab747fSPaolo Bonzini 8249ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req) 8349ab747fSPaolo Bonzini { 8449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 8549ab747fSPaolo Bonzini 8649ab747fSPaolo Bonzini g_free(r->buf); 8749ab747fSPaolo Bonzini } 8849ab747fSPaolo Bonzini 8949ab747fSPaolo Bonzini /* Helper function for command completion. */ 9049ab747fSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret) 9149ab747fSPaolo Bonzini { 9249ab747fSPaolo Bonzini int status; 9349ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 9449ab747fSPaolo Bonzini 9549ab747fSPaolo Bonzini r->req.aiocb = NULL; 9649ab747fSPaolo Bonzini if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 9749ab747fSPaolo Bonzini r->req.sense_len = r->io_header.sb_len_wr; 9849ab747fSPaolo Bonzini } 9949ab747fSPaolo Bonzini 10049ab747fSPaolo Bonzini if (ret != 0) { 10149ab747fSPaolo Bonzini switch (ret) { 10249ab747fSPaolo Bonzini case -EDOM: 10349ab747fSPaolo Bonzini status = TASK_SET_FULL; 10449ab747fSPaolo Bonzini break; 10549ab747fSPaolo Bonzini case -ENOMEM: 10649ab747fSPaolo Bonzini status = CHECK_CONDITION; 10749ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE)); 10849ab747fSPaolo Bonzini break; 10949ab747fSPaolo Bonzini default: 11049ab747fSPaolo Bonzini status = CHECK_CONDITION; 11149ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR)); 11249ab747fSPaolo Bonzini break; 11349ab747fSPaolo Bonzini } 11449ab747fSPaolo Bonzini } else { 11549ab747fSPaolo Bonzini if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT || 11649ab747fSPaolo Bonzini r->io_header.host_status == SG_ERR_DID_BUS_BUSY || 11749ab747fSPaolo Bonzini r->io_header.host_status == SG_ERR_DID_TIME_OUT || 11849ab747fSPaolo Bonzini (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) { 11949ab747fSPaolo Bonzini status = BUSY; 12049ab747fSPaolo Bonzini BADF("Driver Timeout\n"); 12149ab747fSPaolo Bonzini } else if (r->io_header.host_status) { 12249ab747fSPaolo Bonzini status = CHECK_CONDITION; 12349ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS)); 12449ab747fSPaolo Bonzini } else if (r->io_header.status) { 12549ab747fSPaolo Bonzini status = r->io_header.status; 12649ab747fSPaolo Bonzini } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 12749ab747fSPaolo Bonzini status = CHECK_CONDITION; 12849ab747fSPaolo Bonzini } else { 12949ab747fSPaolo Bonzini status = GOOD; 13049ab747fSPaolo Bonzini } 13149ab747fSPaolo Bonzini } 13249ab747fSPaolo Bonzini DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", 13349ab747fSPaolo Bonzini r, r->req.tag, status); 13449ab747fSPaolo Bonzini 13549ab747fSPaolo Bonzini scsi_req_complete(&r->req, status); 13649ab747fSPaolo Bonzini if (!r->req.io_canceled) { 13749ab747fSPaolo Bonzini scsi_req_unref(&r->req); 13849ab747fSPaolo Bonzini } 13949ab747fSPaolo Bonzini } 14049ab747fSPaolo Bonzini 14149ab747fSPaolo Bonzini /* Cancel a pending data transfer. */ 14249ab747fSPaolo Bonzini static void scsi_cancel_io(SCSIRequest *req) 14349ab747fSPaolo Bonzini { 14449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 14549ab747fSPaolo Bonzini 14649ab747fSPaolo Bonzini DPRINTF("Cancel tag=0x%x\n", req->tag); 14749ab747fSPaolo Bonzini if (r->req.aiocb) { 14849ab747fSPaolo Bonzini bdrv_aio_cancel(r->req.aiocb); 14949ab747fSPaolo Bonzini 15049ab747fSPaolo Bonzini /* This reference was left in by scsi_*_data. We take ownership of 15149ab747fSPaolo Bonzini * it independent of whether bdrv_aio_cancel completes the request 15249ab747fSPaolo Bonzini * or not. */ 15349ab747fSPaolo Bonzini scsi_req_unref(&r->req); 15449ab747fSPaolo Bonzini } 15549ab747fSPaolo Bonzini r->req.aiocb = NULL; 15649ab747fSPaolo Bonzini } 15749ab747fSPaolo Bonzini 15849ab747fSPaolo Bonzini static int execute_command(BlockDriverState *bdrv, 15949ab747fSPaolo Bonzini SCSIGenericReq *r, int direction, 16049ab747fSPaolo Bonzini BlockDriverCompletionFunc *complete) 16149ab747fSPaolo Bonzini { 16249ab747fSPaolo Bonzini r->io_header.interface_id = 'S'; 16349ab747fSPaolo Bonzini r->io_header.dxfer_direction = direction; 16449ab747fSPaolo Bonzini r->io_header.dxferp = r->buf; 16549ab747fSPaolo Bonzini r->io_header.dxfer_len = r->buflen; 16649ab747fSPaolo Bonzini r->io_header.cmdp = r->req.cmd.buf; 16749ab747fSPaolo Bonzini r->io_header.cmd_len = r->req.cmd.len; 16849ab747fSPaolo Bonzini r->io_header.mx_sb_len = sizeof(r->req.sense); 16949ab747fSPaolo Bonzini r->io_header.sbp = r->req.sense; 17049ab747fSPaolo Bonzini r->io_header.timeout = MAX_UINT; 17149ab747fSPaolo Bonzini r->io_header.usr_ptr = r; 17249ab747fSPaolo Bonzini r->io_header.flags |= SG_FLAG_DIRECT_IO; 17349ab747fSPaolo Bonzini 17449ab747fSPaolo Bonzini r->req.aiocb = bdrv_aio_ioctl(bdrv, SG_IO, &r->io_header, complete, r); 175d836f8d3SPavel Hrdina if (r->req.aiocb == NULL) { 176d836f8d3SPavel Hrdina return -EIO; 177d836f8d3SPavel Hrdina } 17849ab747fSPaolo Bonzini 17949ab747fSPaolo Bonzini return 0; 18049ab747fSPaolo Bonzini } 18149ab747fSPaolo Bonzini 18249ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret) 18349ab747fSPaolo Bonzini { 18449ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 18549ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 18649ab747fSPaolo Bonzini int len; 18749ab747fSPaolo Bonzini 18849ab747fSPaolo Bonzini r->req.aiocb = NULL; 18949ab747fSPaolo Bonzini if (ret) { 19049ab747fSPaolo Bonzini DPRINTF("IO error ret %d\n", ret); 19149ab747fSPaolo Bonzini scsi_command_complete(r, ret); 19249ab747fSPaolo Bonzini return; 19349ab747fSPaolo Bonzini } 19449ab747fSPaolo Bonzini len = r->io_header.dxfer_len - r->io_header.resid; 19549ab747fSPaolo Bonzini DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); 19649ab747fSPaolo Bonzini 19749ab747fSPaolo Bonzini r->len = -1; 19849ab747fSPaolo Bonzini if (len == 0) { 19949ab747fSPaolo Bonzini scsi_command_complete(r, 0); 20049ab747fSPaolo Bonzini } else { 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 } 2111b7fd729SPaolo Bonzini bdrv_set_guest_block_size(s->conf.bs, s->blocksize); 21249ab747fSPaolo Bonzini 21349ab747fSPaolo Bonzini scsi_req_data(&r->req, len); 21449ab747fSPaolo Bonzini if (!r->req.io_canceled) { 21549ab747fSPaolo Bonzini scsi_req_unref(&r->req); 21649ab747fSPaolo Bonzini } 21749ab747fSPaolo Bonzini } 21849ab747fSPaolo Bonzini } 21949ab747fSPaolo Bonzini 22049ab747fSPaolo Bonzini /* Read more data from scsi device into buffer. */ 22149ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req) 22249ab747fSPaolo Bonzini { 22349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 22449ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 22549ab747fSPaolo Bonzini int ret; 22649ab747fSPaolo Bonzini 22749ab747fSPaolo Bonzini DPRINTF("scsi_read_data 0x%x\n", req->tag); 22849ab747fSPaolo Bonzini 22949ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 23049ab747fSPaolo Bonzini scsi_req_ref(&r->req); 23149ab747fSPaolo Bonzini if (r->len == -1) { 23249ab747fSPaolo Bonzini scsi_command_complete(r, 0); 23349ab747fSPaolo Bonzini return; 23449ab747fSPaolo Bonzini } 23549ab747fSPaolo Bonzini 23649ab747fSPaolo Bonzini ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete); 23749ab747fSPaolo Bonzini if (ret < 0) { 23849ab747fSPaolo Bonzini scsi_command_complete(r, ret); 23949ab747fSPaolo Bonzini } 24049ab747fSPaolo Bonzini } 24149ab747fSPaolo Bonzini 24249ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret) 24349ab747fSPaolo Bonzini { 24449ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 24549ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 24649ab747fSPaolo Bonzini 24749ab747fSPaolo Bonzini DPRINTF("scsi_write_complete() ret = %d\n", ret); 24849ab747fSPaolo Bonzini r->req.aiocb = NULL; 24949ab747fSPaolo Bonzini if (ret) { 25049ab747fSPaolo Bonzini DPRINTF("IO error\n"); 25149ab747fSPaolo Bonzini scsi_command_complete(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 26149ab747fSPaolo Bonzini scsi_command_complete(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); 28149ab747fSPaolo Bonzini ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete); 28249ab747fSPaolo Bonzini if (ret < 0) { 28349ab747fSPaolo Bonzini scsi_command_complete(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 DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag, 30749ab747fSPaolo Bonzini r->req.cmd.xfer, cmd[0]); 30849ab747fSPaolo Bonzini 30949ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 31049ab747fSPaolo Bonzini { 31149ab747fSPaolo Bonzini int i; 31249ab747fSPaolo Bonzini for (i = 1; i < r->req.cmd.len; i++) { 31349ab747fSPaolo Bonzini printf(" 0x%02x", cmd[i]); 31449ab747fSPaolo Bonzini } 31549ab747fSPaolo Bonzini printf("\n"); 31649ab747fSPaolo Bonzini } 31749ab747fSPaolo Bonzini #endif 31849ab747fSPaolo Bonzini 31949ab747fSPaolo Bonzini if (r->req.cmd.xfer == 0) { 32049ab747fSPaolo Bonzini if (r->buf != NULL) 32149ab747fSPaolo Bonzini g_free(r->buf); 32249ab747fSPaolo Bonzini r->buflen = 0; 32349ab747fSPaolo Bonzini r->buf = NULL; 32449ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 32549ab747fSPaolo Bonzini scsi_req_ref(&r->req); 32649ab747fSPaolo Bonzini ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete); 32749ab747fSPaolo Bonzini if (ret < 0) { 32849ab747fSPaolo Bonzini scsi_command_complete(r, ret); 32949ab747fSPaolo Bonzini return 0; 33049ab747fSPaolo Bonzini } 33149ab747fSPaolo Bonzini return 0; 33249ab747fSPaolo Bonzini } 33349ab747fSPaolo Bonzini 33449ab747fSPaolo Bonzini if (r->buflen != r->req.cmd.xfer) { 33549ab747fSPaolo Bonzini if (r->buf != NULL) 33649ab747fSPaolo Bonzini g_free(r->buf); 33749ab747fSPaolo Bonzini r->buf = g_malloc(r->req.cmd.xfer); 33849ab747fSPaolo Bonzini r->buflen = r->req.cmd.xfer; 33949ab747fSPaolo Bonzini } 34049ab747fSPaolo Bonzini 34149ab747fSPaolo Bonzini memset(r->buf, 0, r->buflen); 34249ab747fSPaolo Bonzini r->len = r->req.cmd.xfer; 34349ab747fSPaolo Bonzini if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { 34449ab747fSPaolo Bonzini r->len = 0; 34549ab747fSPaolo Bonzini return -r->req.cmd.xfer; 34649ab747fSPaolo Bonzini } else { 34749ab747fSPaolo Bonzini return r->req.cmd.xfer; 34849ab747fSPaolo Bonzini } 34949ab747fSPaolo Bonzini } 35049ab747fSPaolo Bonzini 35149ab747fSPaolo Bonzini static int get_stream_blocksize(BlockDriverState *bdrv) 35249ab747fSPaolo Bonzini { 35349ab747fSPaolo Bonzini uint8_t cmd[6]; 35449ab747fSPaolo Bonzini uint8_t buf[12]; 35549ab747fSPaolo Bonzini uint8_t sensebuf[8]; 35649ab747fSPaolo Bonzini sg_io_hdr_t io_header; 35749ab747fSPaolo Bonzini int ret; 35849ab747fSPaolo Bonzini 35949ab747fSPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 36049ab747fSPaolo Bonzini memset(buf, 0, sizeof(buf)); 36149ab747fSPaolo Bonzini cmd[0] = MODE_SENSE; 36249ab747fSPaolo Bonzini cmd[4] = sizeof(buf); 36349ab747fSPaolo Bonzini 36449ab747fSPaolo Bonzini memset(&io_header, 0, sizeof(io_header)); 36549ab747fSPaolo Bonzini io_header.interface_id = 'S'; 36649ab747fSPaolo Bonzini io_header.dxfer_direction = SG_DXFER_FROM_DEV; 36749ab747fSPaolo Bonzini io_header.dxfer_len = sizeof(buf); 36849ab747fSPaolo Bonzini io_header.dxferp = buf; 36949ab747fSPaolo Bonzini io_header.cmdp = cmd; 37049ab747fSPaolo Bonzini io_header.cmd_len = sizeof(cmd); 37149ab747fSPaolo Bonzini io_header.mx_sb_len = sizeof(sensebuf); 37249ab747fSPaolo Bonzini io_header.sbp = sensebuf; 37349ab747fSPaolo Bonzini io_header.timeout = 6000; /* XXX */ 37449ab747fSPaolo Bonzini 37549ab747fSPaolo Bonzini ret = bdrv_ioctl(bdrv, SG_IO, &io_header); 37649ab747fSPaolo Bonzini if (ret < 0 || io_header.driver_status || io_header.host_status) { 37749ab747fSPaolo Bonzini return -1; 37849ab747fSPaolo Bonzini } 37949ab747fSPaolo Bonzini return (buf[9] << 16) | (buf[10] << 8) | buf[11]; 38049ab747fSPaolo Bonzini } 38149ab747fSPaolo Bonzini 38249ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev) 38349ab747fSPaolo Bonzini { 38449ab747fSPaolo Bonzini SCSIDevice *s = SCSI_DEVICE(dev); 38549ab747fSPaolo Bonzini 38649ab747fSPaolo Bonzini scsi_device_purge_requests(s, SENSE_CODE(RESET)); 38749ab747fSPaolo Bonzini } 38849ab747fSPaolo Bonzini 38949ab747fSPaolo Bonzini static void scsi_destroy(SCSIDevice *s) 39049ab747fSPaolo Bonzini { 39149ab747fSPaolo Bonzini scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE)); 39249ab747fSPaolo Bonzini blockdev_mark_auto_del(s->conf.bs); 39349ab747fSPaolo Bonzini } 39449ab747fSPaolo Bonzini 39549ab747fSPaolo Bonzini static int scsi_generic_initfn(SCSIDevice *s) 39649ab747fSPaolo Bonzini { 397*6ee143a0SPaolo Bonzini int rc; 39849ab747fSPaolo Bonzini int sg_version; 39949ab747fSPaolo Bonzini struct sg_scsi_id scsiid; 40049ab747fSPaolo Bonzini 40149ab747fSPaolo Bonzini if (!s->conf.bs) { 40249ab747fSPaolo Bonzini error_report("drive property not set"); 40349ab747fSPaolo Bonzini return -1; 40449ab747fSPaolo Bonzini } 40549ab747fSPaolo Bonzini 40649ab747fSPaolo Bonzini if (bdrv_get_on_error(s->conf.bs, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { 40749ab747fSPaolo Bonzini error_report("Device doesn't support drive option werror"); 40849ab747fSPaolo Bonzini return -1; 40949ab747fSPaolo Bonzini } 41049ab747fSPaolo Bonzini if (bdrv_get_on_error(s->conf.bs, 1) != BLOCKDEV_ON_ERROR_REPORT) { 41149ab747fSPaolo Bonzini error_report("Device doesn't support drive option rerror"); 41249ab747fSPaolo Bonzini return -1; 41349ab747fSPaolo Bonzini } 41449ab747fSPaolo Bonzini 41549ab747fSPaolo Bonzini /* check we are using a driver managing SG_IO (version 3 and after */ 416*6ee143a0SPaolo Bonzini rc = bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version); 417*6ee143a0SPaolo Bonzini if (rc < 0) { 418*6ee143a0SPaolo Bonzini error_report("cannot get SG_IO version number: %s. " 419*6ee143a0SPaolo Bonzini "Is this a SCSI device?", 420*6ee143a0SPaolo Bonzini strerror(-rc)); 42149ab747fSPaolo Bonzini return -1; 42249ab747fSPaolo Bonzini } 42349ab747fSPaolo Bonzini if (sg_version < 30000) { 42449ab747fSPaolo Bonzini error_report("scsi generic interface too old"); 42549ab747fSPaolo Bonzini return -1; 42649ab747fSPaolo Bonzini } 42749ab747fSPaolo Bonzini 42849ab747fSPaolo Bonzini /* get LUN of the /dev/sg? */ 42949ab747fSPaolo Bonzini if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) { 43049ab747fSPaolo Bonzini error_report("SG_GET_SCSI_ID ioctl failed"); 43149ab747fSPaolo Bonzini return -1; 43249ab747fSPaolo Bonzini } 43349ab747fSPaolo Bonzini 43449ab747fSPaolo Bonzini /* define device state */ 43549ab747fSPaolo Bonzini s->type = scsiid.scsi_type; 43649ab747fSPaolo Bonzini DPRINTF("device type %d\n", s->type); 43749ab747fSPaolo Bonzini if (s->type == TYPE_DISK || s->type == TYPE_ROM) { 43849ab747fSPaolo Bonzini add_boot_device_path(s->conf.bootindex, &s->qdev, NULL); 43949ab747fSPaolo Bonzini } 44049ab747fSPaolo Bonzini 44149ab747fSPaolo Bonzini switch (s->type) { 44249ab747fSPaolo Bonzini case TYPE_TAPE: 44349ab747fSPaolo Bonzini s->blocksize = get_stream_blocksize(s->conf.bs); 44449ab747fSPaolo Bonzini if (s->blocksize == -1) { 44549ab747fSPaolo Bonzini s->blocksize = 0; 44649ab747fSPaolo Bonzini } 44749ab747fSPaolo Bonzini break; 44849ab747fSPaolo Bonzini 44949ab747fSPaolo Bonzini /* Make a guess for block devices, we'll fix it when the guest sends. 45049ab747fSPaolo Bonzini * READ CAPACITY. If they don't, they likely would assume these sizes 45149ab747fSPaolo Bonzini * anyway. (TODO: they could also send MODE SENSE). 45249ab747fSPaolo Bonzini */ 45349ab747fSPaolo Bonzini case TYPE_ROM: 45449ab747fSPaolo Bonzini case TYPE_WORM: 45549ab747fSPaolo Bonzini s->blocksize = 2048; 45649ab747fSPaolo Bonzini break; 45749ab747fSPaolo Bonzini default: 45849ab747fSPaolo Bonzini s->blocksize = 512; 45949ab747fSPaolo Bonzini break; 46049ab747fSPaolo Bonzini } 46149ab747fSPaolo Bonzini 46249ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 46349ab747fSPaolo Bonzini return 0; 46449ab747fSPaolo Bonzini } 46549ab747fSPaolo Bonzini 46649ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = { 46749ab747fSPaolo Bonzini .size = sizeof(SCSIGenericReq), 46849ab747fSPaolo Bonzini .free_req = scsi_free_request, 46949ab747fSPaolo Bonzini .send_command = scsi_send_command, 47049ab747fSPaolo Bonzini .read_data = scsi_read_data, 47149ab747fSPaolo Bonzini .write_data = scsi_write_data, 47249ab747fSPaolo Bonzini .cancel_io = scsi_cancel_io, 47349ab747fSPaolo Bonzini .get_buf = scsi_get_buf, 47449ab747fSPaolo Bonzini .load_request = scsi_generic_load_request, 47549ab747fSPaolo Bonzini .save_request = scsi_generic_save_request, 47649ab747fSPaolo Bonzini }; 47749ab747fSPaolo Bonzini 47849ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, 47949ab747fSPaolo Bonzini uint8_t *buf, void *hba_private) 48049ab747fSPaolo Bonzini { 48149ab747fSPaolo Bonzini SCSIRequest *req; 48249ab747fSPaolo Bonzini 48349ab747fSPaolo Bonzini req = scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); 48449ab747fSPaolo Bonzini return req; 48549ab747fSPaolo Bonzini } 48649ab747fSPaolo Bonzini 48749ab747fSPaolo Bonzini static Property scsi_generic_properties[] = { 48849ab747fSPaolo Bonzini DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs), 48949ab747fSPaolo Bonzini DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1), 49049ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 49149ab747fSPaolo Bonzini }; 49249ab747fSPaolo Bonzini 49349ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data) 49449ab747fSPaolo Bonzini { 49549ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 49649ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); 49749ab747fSPaolo Bonzini 49849ab747fSPaolo Bonzini sc->init = scsi_generic_initfn; 49949ab747fSPaolo Bonzini sc->destroy = scsi_destroy; 50049ab747fSPaolo Bonzini sc->alloc_req = scsi_new_request; 50149ab747fSPaolo Bonzini dc->fw_name = "disk"; 50249ab747fSPaolo Bonzini dc->desc = "pass through generic scsi device (/dev/sg*)"; 50349ab747fSPaolo Bonzini dc->reset = scsi_generic_reset; 50449ab747fSPaolo Bonzini dc->props = scsi_generic_properties; 50549ab747fSPaolo Bonzini dc->vmsd = &vmstate_scsi_device; 50649ab747fSPaolo Bonzini } 50749ab747fSPaolo Bonzini 50849ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = { 50949ab747fSPaolo Bonzini .name = "scsi-generic", 51049ab747fSPaolo Bonzini .parent = TYPE_SCSI_DEVICE, 51149ab747fSPaolo Bonzini .instance_size = sizeof(SCSIDevice), 51249ab747fSPaolo Bonzini .class_init = scsi_generic_class_initfn, 51349ab747fSPaolo Bonzini }; 51449ab747fSPaolo Bonzini 51549ab747fSPaolo Bonzini static void scsi_generic_register_types(void) 51649ab747fSPaolo Bonzini { 51749ab747fSPaolo Bonzini type_register_static(&scsi_generic_info); 51849ab747fSPaolo Bonzini } 51949ab747fSPaolo Bonzini 52049ab747fSPaolo Bonzini type_init(scsi_generic_register_types) 52149ab747fSPaolo Bonzini 52249ab747fSPaolo Bonzini #endif /* __linux__ */ 523