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> 3749ab747fSPaolo Bonzini #include "block/scsi.h" 3849ab747fSPaolo Bonzini 3949ab747fSPaolo Bonzini #define SG_ERR_DRIVER_TIMEOUT 0x06 4049ab747fSPaolo Bonzini #define SG_ERR_DRIVER_SENSE 0x08 4149ab747fSPaolo Bonzini 4249ab747fSPaolo Bonzini #define SG_ERR_DID_OK 0x00 4349ab747fSPaolo Bonzini #define SG_ERR_DID_NO_CONNECT 0x01 4449ab747fSPaolo Bonzini #define SG_ERR_DID_BUS_BUSY 0x02 4549ab747fSPaolo Bonzini #define SG_ERR_DID_TIME_OUT 0x03 4649ab747fSPaolo Bonzini 4749ab747fSPaolo Bonzini #ifndef MAX_UINT 4849ab747fSPaolo Bonzini #define MAX_UINT ((unsigned int)-1) 4949ab747fSPaolo Bonzini #endif 5049ab747fSPaolo Bonzini 5149ab747fSPaolo Bonzini typedef struct SCSIGenericReq { 5249ab747fSPaolo Bonzini SCSIRequest req; 5349ab747fSPaolo Bonzini uint8_t *buf; 5449ab747fSPaolo Bonzini int buflen; 5549ab747fSPaolo Bonzini int len; 5649ab747fSPaolo Bonzini sg_io_hdr_t io_header; 5749ab747fSPaolo Bonzini } SCSIGenericReq; 5849ab747fSPaolo Bonzini 5949ab747fSPaolo Bonzini static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) 6049ab747fSPaolo Bonzini { 6149ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 6249ab747fSPaolo Bonzini 6349ab747fSPaolo Bonzini qemu_put_sbe32s(f, &r->buflen); 6449ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 6549ab747fSPaolo Bonzini assert(!r->req.sg); 6649ab747fSPaolo Bonzini qemu_put_buffer(f, r->buf, r->req.cmd.xfer); 6749ab747fSPaolo Bonzini } 6849ab747fSPaolo Bonzini } 6949ab747fSPaolo Bonzini 7049ab747fSPaolo Bonzini static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) 7149ab747fSPaolo Bonzini { 7249ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 7349ab747fSPaolo Bonzini 7449ab747fSPaolo Bonzini qemu_get_sbe32s(f, &r->buflen); 7549ab747fSPaolo Bonzini if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { 7649ab747fSPaolo Bonzini assert(!r->req.sg); 7749ab747fSPaolo Bonzini qemu_get_buffer(f, r->buf, r->req.cmd.xfer); 7849ab747fSPaolo Bonzini } 7949ab747fSPaolo Bonzini } 8049ab747fSPaolo Bonzini 8149ab747fSPaolo Bonzini static void scsi_free_request(SCSIRequest *req) 8249ab747fSPaolo Bonzini { 8349ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 8449ab747fSPaolo Bonzini 8549ab747fSPaolo Bonzini g_free(r->buf); 8649ab747fSPaolo Bonzini } 8749ab747fSPaolo Bonzini 8849ab747fSPaolo Bonzini /* Helper function for command completion. */ 89fa0d653bSPaolo Bonzini static void scsi_command_complete_noio(SCSIGenericReq *r, int ret) 9049ab747fSPaolo Bonzini { 9149ab747fSPaolo Bonzini int status; 9249ab747fSPaolo Bonzini 93fa0d653bSPaolo Bonzini assert(r->req.aiocb == NULL); 94fa0d653bSPaolo Bonzini 956c25fa6cSFam Zheng if (r->req.io_canceled) { 96d5776465SFam Zheng scsi_req_cancel_complete(&r->req); 976c25fa6cSFam Zheng goto done; 986c25fa6cSFam Zheng } 9949ab747fSPaolo Bonzini if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 10049ab747fSPaolo Bonzini r->req.sense_len = r->io_header.sb_len_wr; 10149ab747fSPaolo Bonzini } 10249ab747fSPaolo Bonzini 10349ab747fSPaolo Bonzini if (ret != 0) { 10449ab747fSPaolo Bonzini switch (ret) { 10549ab747fSPaolo Bonzini case -EDOM: 10649ab747fSPaolo Bonzini status = TASK_SET_FULL; 10749ab747fSPaolo Bonzini break; 10849ab747fSPaolo Bonzini case -ENOMEM: 10949ab747fSPaolo Bonzini status = CHECK_CONDITION; 11049ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE)); 11149ab747fSPaolo Bonzini break; 11249ab747fSPaolo Bonzini default: 11349ab747fSPaolo Bonzini status = CHECK_CONDITION; 11449ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR)); 11549ab747fSPaolo Bonzini break; 11649ab747fSPaolo Bonzini } 11749ab747fSPaolo Bonzini } else { 11849ab747fSPaolo Bonzini if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT || 11949ab747fSPaolo Bonzini r->io_header.host_status == SG_ERR_DID_BUS_BUSY || 12049ab747fSPaolo Bonzini r->io_header.host_status == SG_ERR_DID_TIME_OUT || 12149ab747fSPaolo Bonzini (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) { 12249ab747fSPaolo Bonzini status = BUSY; 12349ab747fSPaolo Bonzini BADF("Driver Timeout\n"); 12449ab747fSPaolo Bonzini } else if (r->io_header.host_status) { 12549ab747fSPaolo Bonzini status = CHECK_CONDITION; 12649ab747fSPaolo Bonzini scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS)); 12749ab747fSPaolo Bonzini } else if (r->io_header.status) { 12849ab747fSPaolo Bonzini status = r->io_header.status; 12949ab747fSPaolo Bonzini } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) { 13049ab747fSPaolo Bonzini status = CHECK_CONDITION; 13149ab747fSPaolo Bonzini } else { 13249ab747fSPaolo Bonzini status = GOOD; 13349ab747fSPaolo Bonzini } 13449ab747fSPaolo Bonzini } 13549ab747fSPaolo Bonzini DPRINTF("Command complete 0x%p tag=0x%x status=%d\n", 13649ab747fSPaolo Bonzini r, r->req.tag, status); 13749ab747fSPaolo Bonzini 13849ab747fSPaolo Bonzini scsi_req_complete(&r->req, status); 1396c25fa6cSFam Zheng done: 14049ab747fSPaolo Bonzini scsi_req_unref(&r->req); 14149ab747fSPaolo Bonzini } 14249ab747fSPaolo Bonzini 143fa0d653bSPaolo Bonzini static void scsi_command_complete(void *opaque, int ret) 144fa0d653bSPaolo Bonzini { 145fa0d653bSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 146fa0d653bSPaolo Bonzini 147fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 148fa0d653bSPaolo Bonzini r->req.aiocb = NULL; 149fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 150fa0d653bSPaolo Bonzini } 151fa0d653bSPaolo Bonzini 1524be74634SMarkus Armbruster static int execute_command(BlockBackend *blk, 15349ab747fSPaolo Bonzini SCSIGenericReq *r, int direction, 154097310b5SMarkus Armbruster BlockCompletionFunc *complete) 15549ab747fSPaolo Bonzini { 15649ab747fSPaolo Bonzini r->io_header.interface_id = 'S'; 15749ab747fSPaolo Bonzini r->io_header.dxfer_direction = direction; 15849ab747fSPaolo Bonzini r->io_header.dxferp = r->buf; 15949ab747fSPaolo Bonzini r->io_header.dxfer_len = r->buflen; 16049ab747fSPaolo Bonzini r->io_header.cmdp = r->req.cmd.buf; 16149ab747fSPaolo Bonzini r->io_header.cmd_len = r->req.cmd.len; 16249ab747fSPaolo Bonzini r->io_header.mx_sb_len = sizeof(r->req.sense); 16349ab747fSPaolo Bonzini r->io_header.sbp = r->req.sense; 16449ab747fSPaolo Bonzini r->io_header.timeout = MAX_UINT; 16549ab747fSPaolo Bonzini r->io_header.usr_ptr = r; 16649ab747fSPaolo Bonzini r->io_header.flags |= SG_FLAG_DIRECT_IO; 16749ab747fSPaolo Bonzini 1684be74634SMarkus Armbruster r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r); 169d836f8d3SPavel Hrdina if (r->req.aiocb == NULL) { 170d836f8d3SPavel Hrdina return -EIO; 171d836f8d3SPavel Hrdina } 17249ab747fSPaolo Bonzini 17349ab747fSPaolo Bonzini return 0; 17449ab747fSPaolo Bonzini } 17549ab747fSPaolo Bonzini 17649ab747fSPaolo Bonzini static void scsi_read_complete(void * opaque, int ret) 17749ab747fSPaolo Bonzini { 17849ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 17949ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 18049ab747fSPaolo Bonzini int len; 18149ab747fSPaolo Bonzini 182fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 18349ab747fSPaolo Bonzini r->req.aiocb = NULL; 184fa0d653bSPaolo Bonzini 1856c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 186fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 18749ab747fSPaolo Bonzini return; 18849ab747fSPaolo Bonzini } 189fa0d653bSPaolo Bonzini 19049ab747fSPaolo Bonzini len = r->io_header.dxfer_len - r->io_header.resid; 19149ab747fSPaolo Bonzini DPRINTF("Data ready tag=0x%x len=%d\n", r->req.tag, len); 19249ab747fSPaolo Bonzini 19349ab747fSPaolo Bonzini r->len = -1; 19449ab747fSPaolo Bonzini if (len == 0) { 195fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 196fa0d653bSPaolo Bonzini return; 197fa0d653bSPaolo Bonzini } 198fa0d653bSPaolo Bonzini 19949ab747fSPaolo Bonzini /* Snoop READ CAPACITY output to set the blocksize. */ 20053254e56SPaolo Bonzini if (r->req.cmd.buf[0] == READ_CAPACITY_10 && 20153254e56SPaolo Bonzini (ldl_be_p(&r->buf[0]) != 0xffffffffU || s->max_lba == 0)) { 20249ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[4]); 20353254e56SPaolo Bonzini s->max_lba = ldl_be_p(&r->buf[0]) & 0xffffffffULL; 20449ab747fSPaolo Bonzini } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 && 20549ab747fSPaolo Bonzini (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { 20649ab747fSPaolo Bonzini s->blocksize = ldl_be_p(&r->buf[8]); 20749ab747fSPaolo Bonzini s->max_lba = ldq_be_p(&r->buf[0]); 20849ab747fSPaolo Bonzini } 2094be74634SMarkus Armbruster blk_set_guest_block_size(s->conf.blk, s->blocksize); 21049ab747fSPaolo Bonzini 2110eb2baebSPaolo Bonzini /* Patch MODE SENSE device specific parameters if the BDS is opened 2120eb2baebSPaolo Bonzini * readonly. 2130eb2baebSPaolo Bonzini */ 2140eb2baebSPaolo Bonzini if ((s->type == TYPE_DISK || s->type == TYPE_TAPE) && 2150eb2baebSPaolo Bonzini blk_is_read_only(s->conf.blk) && 2160eb2baebSPaolo Bonzini (r->req.cmd.buf[0] == MODE_SENSE || 2170eb2baebSPaolo Bonzini r->req.cmd.buf[0] == MODE_SENSE_10) && 2180eb2baebSPaolo Bonzini (r->req.cmd.buf[1] & 0x8) == 0) { 2190eb2baebSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SENSE) { 2200eb2baebSPaolo Bonzini r->buf[2] |= 0x80; 2210eb2baebSPaolo Bonzini } else { 2220eb2baebSPaolo Bonzini r->buf[3] |= 0x80; 2230eb2baebSPaolo Bonzini } 2240eb2baebSPaolo Bonzini } 225063143d5SFam Zheng if (s->type == TYPE_DISK && 226063143d5SFam Zheng r->req.cmd.buf[0] == INQUIRY && 227063143d5SFam Zheng r->req.cmd.buf[2] == 0xb0) { 228063143d5SFam Zheng uint32_t max_xfer_len = blk_get_max_transfer_length(s->conf.blk); 229063143d5SFam Zheng if (max_xfer_len) { 230063143d5SFam Zheng stl_be_p(&r->buf[8], max_xfer_len); 231063143d5SFam Zheng /* Also take care of the opt xfer len. */ 232063143d5SFam Zheng if (ldl_be_p(&r->buf[12]) > max_xfer_len) { 233063143d5SFam Zheng stl_be_p(&r->buf[12], max_xfer_len); 234063143d5SFam Zheng } 235063143d5SFam Zheng } 236063143d5SFam Zheng } 23749ab747fSPaolo Bonzini scsi_req_data(&r->req, len); 23849ab747fSPaolo Bonzini scsi_req_unref(&r->req); 23949ab747fSPaolo Bonzini } 24049ab747fSPaolo Bonzini 24149ab747fSPaolo Bonzini /* Read more data from scsi device into buffer. */ 24249ab747fSPaolo Bonzini static void scsi_read_data(SCSIRequest *req) 24349ab747fSPaolo Bonzini { 24449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 24549ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 24649ab747fSPaolo Bonzini int ret; 24749ab747fSPaolo Bonzini 24849ab747fSPaolo Bonzini DPRINTF("scsi_read_data 0x%x\n", req->tag); 24949ab747fSPaolo Bonzini 25049ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 25149ab747fSPaolo Bonzini scsi_req_ref(&r->req); 25249ab747fSPaolo Bonzini if (r->len == -1) { 253fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, 0); 25449ab747fSPaolo Bonzini return; 25549ab747fSPaolo Bonzini } 25649ab747fSPaolo Bonzini 2574be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_FROM_DEV, 2584be74634SMarkus Armbruster scsi_read_complete); 25949ab747fSPaolo Bonzini if (ret < 0) { 260fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 26149ab747fSPaolo Bonzini } 26249ab747fSPaolo Bonzini } 26349ab747fSPaolo Bonzini 26449ab747fSPaolo Bonzini static void scsi_write_complete(void * opaque, int ret) 26549ab747fSPaolo Bonzini { 26649ab747fSPaolo Bonzini SCSIGenericReq *r = (SCSIGenericReq *)opaque; 26749ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 26849ab747fSPaolo Bonzini 26949ab747fSPaolo Bonzini DPRINTF("scsi_write_complete() ret = %d\n", ret); 270fa0d653bSPaolo Bonzini 271fa0d653bSPaolo Bonzini assert(r->req.aiocb != NULL); 27249ab747fSPaolo Bonzini r->req.aiocb = NULL; 273fa0d653bSPaolo Bonzini 2746c25fa6cSFam Zheng if (ret || r->req.io_canceled) { 275fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 27649ab747fSPaolo Bonzini return; 27749ab747fSPaolo Bonzini } 27849ab747fSPaolo Bonzini 27949ab747fSPaolo Bonzini if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 && 28049ab747fSPaolo Bonzini s->type == TYPE_TAPE) { 28149ab747fSPaolo Bonzini s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11]; 28249ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 28349ab747fSPaolo Bonzini } 28449ab747fSPaolo Bonzini 285fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 28649ab747fSPaolo Bonzini } 28749ab747fSPaolo Bonzini 28849ab747fSPaolo Bonzini /* Write data to a scsi device. Returns nonzero on failure. 28949ab747fSPaolo Bonzini The transfer may complete asynchronously. */ 29049ab747fSPaolo Bonzini static void scsi_write_data(SCSIRequest *req) 29149ab747fSPaolo Bonzini { 29249ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 29349ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 29449ab747fSPaolo Bonzini int ret; 29549ab747fSPaolo Bonzini 29649ab747fSPaolo Bonzini DPRINTF("scsi_write_data 0x%x\n", req->tag); 29749ab747fSPaolo Bonzini if (r->len == 0) { 29849ab747fSPaolo Bonzini r->len = r->buflen; 29949ab747fSPaolo Bonzini scsi_req_data(&r->req, r->len); 30049ab747fSPaolo Bonzini return; 30149ab747fSPaolo Bonzini } 30249ab747fSPaolo Bonzini 30349ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 30449ab747fSPaolo Bonzini scsi_req_ref(&r->req); 3054be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_TO_DEV, scsi_write_complete); 30649ab747fSPaolo Bonzini if (ret < 0) { 307fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 30849ab747fSPaolo Bonzini } 30949ab747fSPaolo Bonzini } 31049ab747fSPaolo Bonzini 31149ab747fSPaolo Bonzini /* Return a pointer to the data buffer. */ 31249ab747fSPaolo Bonzini static uint8_t *scsi_get_buf(SCSIRequest *req) 31349ab747fSPaolo Bonzini { 31449ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 31549ab747fSPaolo Bonzini 31649ab747fSPaolo Bonzini return r->buf; 31749ab747fSPaolo Bonzini } 31849ab747fSPaolo Bonzini 31949ab747fSPaolo Bonzini /* Execute a scsi command. Returns the length of the data expected by the 32049ab747fSPaolo Bonzini command. This will be Positive for data transfers from the device 32149ab747fSPaolo Bonzini (eg. disk reads), negative for transfers to the device (eg. disk writes), 32249ab747fSPaolo Bonzini and zero if the command does not transfer any data. */ 32349ab747fSPaolo Bonzini 32449ab747fSPaolo Bonzini static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd) 32549ab747fSPaolo Bonzini { 32649ab747fSPaolo Bonzini SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); 32749ab747fSPaolo Bonzini SCSIDevice *s = r->req.dev; 32849ab747fSPaolo Bonzini int ret; 32949ab747fSPaolo Bonzini 33049ab747fSPaolo Bonzini #ifdef DEBUG_SCSI 33149ab747fSPaolo Bonzini { 33249ab747fSPaolo Bonzini int i; 33349ab747fSPaolo Bonzini for (i = 1; i < r->req.cmd.len; i++) { 33449ab747fSPaolo Bonzini printf(" 0x%02x", cmd[i]); 33549ab747fSPaolo Bonzini } 33649ab747fSPaolo Bonzini printf("\n"); 33749ab747fSPaolo Bonzini } 33849ab747fSPaolo Bonzini #endif 33949ab747fSPaolo Bonzini 34049ab747fSPaolo Bonzini if (r->req.cmd.xfer == 0) { 34149ab747fSPaolo Bonzini g_free(r->buf); 34249ab747fSPaolo Bonzini r->buflen = 0; 34349ab747fSPaolo Bonzini r->buf = NULL; 34449ab747fSPaolo Bonzini /* The request is used as the AIO opaque value, so add a ref. */ 34549ab747fSPaolo Bonzini scsi_req_ref(&r->req); 3464be74634SMarkus Armbruster ret = execute_command(s->conf.blk, r, SG_DXFER_NONE, 3474be74634SMarkus Armbruster scsi_command_complete); 34849ab747fSPaolo Bonzini if (ret < 0) { 349fa0d653bSPaolo Bonzini scsi_command_complete_noio(r, ret); 35049ab747fSPaolo Bonzini return 0; 35149ab747fSPaolo Bonzini } 35249ab747fSPaolo Bonzini return 0; 35349ab747fSPaolo Bonzini } 35449ab747fSPaolo Bonzini 35549ab747fSPaolo Bonzini if (r->buflen != r->req.cmd.xfer) { 35649ab747fSPaolo Bonzini g_free(r->buf); 35749ab747fSPaolo Bonzini r->buf = g_malloc(r->req.cmd.xfer); 35849ab747fSPaolo Bonzini r->buflen = r->req.cmd.xfer; 35949ab747fSPaolo Bonzini } 36049ab747fSPaolo Bonzini 36149ab747fSPaolo Bonzini memset(r->buf, 0, r->buflen); 36249ab747fSPaolo Bonzini r->len = r->req.cmd.xfer; 36349ab747fSPaolo Bonzini if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { 36449ab747fSPaolo Bonzini r->len = 0; 36549ab747fSPaolo Bonzini return -r->req.cmd.xfer; 36649ab747fSPaolo Bonzini } else { 36749ab747fSPaolo Bonzini return r->req.cmd.xfer; 36849ab747fSPaolo Bonzini } 36949ab747fSPaolo Bonzini } 37049ab747fSPaolo Bonzini 3719fd7e859SPaolo Bonzini static int read_naa_id(const uint8_t *p, uint64_t *p_wwn) 3729fd7e859SPaolo Bonzini { 3739fd7e859SPaolo Bonzini int i; 3749fd7e859SPaolo Bonzini 3759fd7e859SPaolo Bonzini if ((p[1] & 0xF) == 3) { 3769fd7e859SPaolo Bonzini /* NAA designator type */ 3779fd7e859SPaolo Bonzini if (p[3] != 8) { 3789fd7e859SPaolo Bonzini return -EINVAL; 3799fd7e859SPaolo Bonzini } 3809fd7e859SPaolo Bonzini *p_wwn = ldq_be_p(p + 4); 3819fd7e859SPaolo Bonzini return 0; 3829fd7e859SPaolo Bonzini } 3839fd7e859SPaolo Bonzini 3849fd7e859SPaolo Bonzini if ((p[1] & 0xF) == 8) { 3859fd7e859SPaolo Bonzini /* SCSI name string designator type */ 3869fd7e859SPaolo Bonzini if (p[3] < 20 || memcmp(&p[4], "naa.", 4)) { 3879fd7e859SPaolo Bonzini return -EINVAL; 3889fd7e859SPaolo Bonzini } 3899fd7e859SPaolo Bonzini if (p[3] > 20 && p[24] != ',') { 3909fd7e859SPaolo Bonzini return -EINVAL; 3919fd7e859SPaolo Bonzini } 3929fd7e859SPaolo Bonzini *p_wwn = 0; 3939fd7e859SPaolo Bonzini for (i = 8; i < 24; i++) { 3949fd7e859SPaolo Bonzini char c = toupper(p[i]); 3959fd7e859SPaolo Bonzini c -= (c >= '0' && c <= '9' ? '0' : 'A' - 10); 3969fd7e859SPaolo Bonzini *p_wwn = (*p_wwn << 4) | c; 3979fd7e859SPaolo Bonzini } 3989fd7e859SPaolo Bonzini return 0; 3999fd7e859SPaolo Bonzini } 4009fd7e859SPaolo Bonzini 4019fd7e859SPaolo Bonzini return -EINVAL; 4029fd7e859SPaolo Bonzini } 4039fd7e859SPaolo Bonzini 4049fd7e859SPaolo Bonzini void scsi_generic_read_device_identification(SCSIDevice *s) 4059fd7e859SPaolo Bonzini { 4069fd7e859SPaolo Bonzini uint8_t cmd[6]; 4079fd7e859SPaolo Bonzini uint8_t buf[250]; 4089fd7e859SPaolo Bonzini uint8_t sensebuf[8]; 4099fd7e859SPaolo Bonzini sg_io_hdr_t io_header; 4109fd7e859SPaolo Bonzini int ret; 4119fd7e859SPaolo Bonzini int i, len; 4129fd7e859SPaolo Bonzini 4139fd7e859SPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 4149fd7e859SPaolo Bonzini memset(buf, 0, sizeof(buf)); 4159fd7e859SPaolo Bonzini cmd[0] = INQUIRY; 4169fd7e859SPaolo Bonzini cmd[1] = 1; 4179fd7e859SPaolo Bonzini cmd[2] = 0x83; 4189fd7e859SPaolo Bonzini cmd[4] = sizeof(buf); 4199fd7e859SPaolo Bonzini 4209fd7e859SPaolo Bonzini memset(&io_header, 0, sizeof(io_header)); 4219fd7e859SPaolo Bonzini io_header.interface_id = 'S'; 4229fd7e859SPaolo Bonzini io_header.dxfer_direction = SG_DXFER_FROM_DEV; 4239fd7e859SPaolo Bonzini io_header.dxfer_len = sizeof(buf); 4249fd7e859SPaolo Bonzini io_header.dxferp = buf; 4259fd7e859SPaolo Bonzini io_header.cmdp = cmd; 4269fd7e859SPaolo Bonzini io_header.cmd_len = sizeof(cmd); 4279fd7e859SPaolo Bonzini io_header.mx_sb_len = sizeof(sensebuf); 4289fd7e859SPaolo Bonzini io_header.sbp = sensebuf; 4299fd7e859SPaolo Bonzini io_header.timeout = 6000; /* XXX */ 4309fd7e859SPaolo Bonzini 4319fd7e859SPaolo Bonzini ret = blk_ioctl(s->conf.blk, SG_IO, &io_header); 4329fd7e859SPaolo Bonzini if (ret < 0 || io_header.driver_status || io_header.host_status) { 4339fd7e859SPaolo Bonzini return; 4349fd7e859SPaolo Bonzini } 4359fd7e859SPaolo Bonzini 4369fd7e859SPaolo Bonzini len = MIN((buf[2] << 8) | buf[3], sizeof(buf) - 4); 4379fd7e859SPaolo Bonzini for (i = 0; i + 3 <= len; ) { 4389fd7e859SPaolo Bonzini const uint8_t *p = &buf[i + 4]; 4399fd7e859SPaolo Bonzini uint64_t wwn; 4409fd7e859SPaolo Bonzini 4419fd7e859SPaolo Bonzini if (i + (p[3] + 4) > len) { 4429fd7e859SPaolo Bonzini break; 4439fd7e859SPaolo Bonzini } 4449fd7e859SPaolo Bonzini 4459fd7e859SPaolo Bonzini if ((p[1] & 0x10) == 0) { 4469fd7e859SPaolo Bonzini /* Associated with the logical unit */ 4479fd7e859SPaolo Bonzini if (read_naa_id(p, &wwn) == 0) { 4489fd7e859SPaolo Bonzini s->wwn = wwn; 4499fd7e859SPaolo Bonzini } 4509fd7e859SPaolo Bonzini } else if ((p[1] & 0x10) == 0x10) { 4519fd7e859SPaolo Bonzini /* Associated with the target port */ 4529fd7e859SPaolo Bonzini if (read_naa_id(p, &wwn) == 0) { 4539fd7e859SPaolo Bonzini s->port_wwn = wwn; 4549fd7e859SPaolo Bonzini } 4559fd7e859SPaolo Bonzini } 4569fd7e859SPaolo Bonzini 4579fd7e859SPaolo Bonzini i += p[3] + 4; 4589fd7e859SPaolo Bonzini } 4599fd7e859SPaolo Bonzini } 4609fd7e859SPaolo Bonzini 4614be74634SMarkus Armbruster static int get_stream_blocksize(BlockBackend *blk) 46249ab747fSPaolo Bonzini { 46349ab747fSPaolo Bonzini uint8_t cmd[6]; 46449ab747fSPaolo Bonzini uint8_t buf[12]; 46549ab747fSPaolo Bonzini uint8_t sensebuf[8]; 46649ab747fSPaolo Bonzini sg_io_hdr_t io_header; 46749ab747fSPaolo Bonzini int ret; 46849ab747fSPaolo Bonzini 46949ab747fSPaolo Bonzini memset(cmd, 0, sizeof(cmd)); 47049ab747fSPaolo Bonzini memset(buf, 0, sizeof(buf)); 47149ab747fSPaolo Bonzini cmd[0] = MODE_SENSE; 47249ab747fSPaolo Bonzini cmd[4] = sizeof(buf); 47349ab747fSPaolo Bonzini 47449ab747fSPaolo Bonzini memset(&io_header, 0, sizeof(io_header)); 47549ab747fSPaolo Bonzini io_header.interface_id = 'S'; 47649ab747fSPaolo Bonzini io_header.dxfer_direction = SG_DXFER_FROM_DEV; 47749ab747fSPaolo Bonzini io_header.dxfer_len = sizeof(buf); 47849ab747fSPaolo Bonzini io_header.dxferp = buf; 47949ab747fSPaolo Bonzini io_header.cmdp = cmd; 48049ab747fSPaolo Bonzini io_header.cmd_len = sizeof(cmd); 48149ab747fSPaolo Bonzini io_header.mx_sb_len = sizeof(sensebuf); 48249ab747fSPaolo Bonzini io_header.sbp = sensebuf; 48349ab747fSPaolo Bonzini io_header.timeout = 6000; /* XXX */ 48449ab747fSPaolo Bonzini 4854be74634SMarkus Armbruster ret = blk_ioctl(blk, SG_IO, &io_header); 48649ab747fSPaolo Bonzini if (ret < 0 || io_header.driver_status || io_header.host_status) { 48749ab747fSPaolo Bonzini return -1; 48849ab747fSPaolo Bonzini } 48949ab747fSPaolo Bonzini return (buf[9] << 16) | (buf[10] << 8) | buf[11]; 49049ab747fSPaolo Bonzini } 49149ab747fSPaolo Bonzini 49249ab747fSPaolo Bonzini static void scsi_generic_reset(DeviceState *dev) 49349ab747fSPaolo Bonzini { 49449ab747fSPaolo Bonzini SCSIDevice *s = SCSI_DEVICE(dev); 49549ab747fSPaolo Bonzini 49649ab747fSPaolo Bonzini scsi_device_purge_requests(s, SENSE_CODE(RESET)); 49749ab747fSPaolo Bonzini } 49849ab747fSPaolo Bonzini 499a818a4b6SFam Zheng static void scsi_generic_realize(SCSIDevice *s, Error **errp) 50049ab747fSPaolo Bonzini { 5016ee143a0SPaolo Bonzini int rc; 50249ab747fSPaolo Bonzini int sg_version; 50349ab747fSPaolo Bonzini struct sg_scsi_id scsiid; 50449ab747fSPaolo Bonzini 5054be74634SMarkus Armbruster if (!s->conf.blk) { 506a818a4b6SFam Zheng error_setg(errp, "drive property not set"); 507a818a4b6SFam Zheng return; 50849ab747fSPaolo Bonzini } 50949ab747fSPaolo Bonzini 5104be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) { 511a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option werror"); 512a818a4b6SFam Zheng return; 51349ab747fSPaolo Bonzini } 5144be74634SMarkus Armbruster if (blk_get_on_error(s->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) { 515a818a4b6SFam Zheng error_setg(errp, "Device doesn't support drive option rerror"); 516a818a4b6SFam Zheng return; 51749ab747fSPaolo Bonzini } 51849ab747fSPaolo Bonzini 51949ab747fSPaolo Bonzini /* check we are using a driver managing SG_IO (version 3 and after */ 5204be74634SMarkus Armbruster rc = blk_ioctl(s->conf.blk, SG_GET_VERSION_NUM, &sg_version); 5216ee143a0SPaolo Bonzini if (rc < 0) { 522a818a4b6SFam Zheng error_setg(errp, "cannot get SG_IO version number: %s. " 5236ee143a0SPaolo Bonzini "Is this a SCSI device?", 5246ee143a0SPaolo Bonzini strerror(-rc)); 525a818a4b6SFam Zheng return; 52649ab747fSPaolo Bonzini } 52749ab747fSPaolo Bonzini if (sg_version < 30000) { 528a818a4b6SFam Zheng error_setg(errp, "scsi generic interface too old"); 529a818a4b6SFam Zheng return; 53049ab747fSPaolo Bonzini } 53149ab747fSPaolo Bonzini 53249ab747fSPaolo Bonzini /* get LUN of the /dev/sg? */ 5334be74634SMarkus Armbruster if (blk_ioctl(s->conf.blk, SG_GET_SCSI_ID, &scsiid)) { 534a818a4b6SFam Zheng error_setg(errp, "SG_GET_SCSI_ID ioctl failed"); 535a818a4b6SFam Zheng return; 53649ab747fSPaolo Bonzini } 53749ab747fSPaolo Bonzini 53849ab747fSPaolo Bonzini /* define device state */ 53949ab747fSPaolo Bonzini s->type = scsiid.scsi_type; 54049ab747fSPaolo Bonzini DPRINTF("device type %d\n", s->type); 54149ab747fSPaolo Bonzini 54249ab747fSPaolo Bonzini switch (s->type) { 54349ab747fSPaolo Bonzini case TYPE_TAPE: 5444be74634SMarkus Armbruster s->blocksize = get_stream_blocksize(s->conf.blk); 54549ab747fSPaolo Bonzini if (s->blocksize == -1) { 54649ab747fSPaolo Bonzini s->blocksize = 0; 54749ab747fSPaolo Bonzini } 54849ab747fSPaolo Bonzini break; 54949ab747fSPaolo Bonzini 55049ab747fSPaolo Bonzini /* Make a guess for block devices, we'll fix it when the guest sends. 55149ab747fSPaolo Bonzini * READ CAPACITY. If they don't, they likely would assume these sizes 55249ab747fSPaolo Bonzini * anyway. (TODO: they could also send MODE SENSE). 55349ab747fSPaolo Bonzini */ 55449ab747fSPaolo Bonzini case TYPE_ROM: 55549ab747fSPaolo Bonzini case TYPE_WORM: 55649ab747fSPaolo Bonzini s->blocksize = 2048; 55749ab747fSPaolo Bonzini break; 55849ab747fSPaolo Bonzini default: 55949ab747fSPaolo Bonzini s->blocksize = 512; 56049ab747fSPaolo Bonzini break; 56149ab747fSPaolo Bonzini } 56249ab747fSPaolo Bonzini 56349ab747fSPaolo Bonzini DPRINTF("block size %d\n", s->blocksize); 5649fd7e859SPaolo Bonzini 5659fd7e859SPaolo Bonzini scsi_generic_read_device_identification(s); 56649ab747fSPaolo Bonzini } 56749ab747fSPaolo Bonzini 56849ab747fSPaolo Bonzini const SCSIReqOps scsi_generic_req_ops = { 56949ab747fSPaolo Bonzini .size = sizeof(SCSIGenericReq), 57049ab747fSPaolo Bonzini .free_req = scsi_free_request, 57149ab747fSPaolo Bonzini .send_command = scsi_send_command, 57249ab747fSPaolo Bonzini .read_data = scsi_read_data, 57349ab747fSPaolo Bonzini .write_data = scsi_write_data, 57449ab747fSPaolo Bonzini .get_buf = scsi_get_buf, 57549ab747fSPaolo Bonzini .load_request = scsi_generic_load_request, 57649ab747fSPaolo Bonzini .save_request = scsi_generic_save_request, 57749ab747fSPaolo Bonzini }; 57849ab747fSPaolo Bonzini 57949ab747fSPaolo Bonzini static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, 58049ab747fSPaolo Bonzini uint8_t *buf, void *hba_private) 58149ab747fSPaolo Bonzini { 582*9be38598SEduardo Habkost return scsi_req_alloc(&scsi_generic_req_ops, d, tag, lun, hba_private); 58349ab747fSPaolo Bonzini } 58449ab747fSPaolo Bonzini 58549ab747fSPaolo Bonzini static Property scsi_generic_properties[] = { 5864be74634SMarkus Armbruster DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk), 58749ab747fSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 58849ab747fSPaolo Bonzini }; 58949ab747fSPaolo Bonzini 5903e7e180aSPaolo Bonzini static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, 5913e7e180aSPaolo Bonzini uint8_t *buf, void *hba_private) 5923e7e180aSPaolo Bonzini { 5933e7e180aSPaolo Bonzini return scsi_bus_parse_cdb(dev, cmd, buf, hba_private); 5943e7e180aSPaolo Bonzini } 5953e7e180aSPaolo Bonzini 59649ab747fSPaolo Bonzini static void scsi_generic_class_initfn(ObjectClass *klass, void *data) 59749ab747fSPaolo Bonzini { 59849ab747fSPaolo Bonzini DeviceClass *dc = DEVICE_CLASS(klass); 59949ab747fSPaolo Bonzini SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); 60049ab747fSPaolo Bonzini 601a818a4b6SFam Zheng sc->realize = scsi_generic_realize; 60249ab747fSPaolo Bonzini sc->alloc_req = scsi_new_request; 6033e7e180aSPaolo Bonzini sc->parse_cdb = scsi_generic_parse_cdb; 60449ab747fSPaolo Bonzini dc->fw_name = "disk"; 60549ab747fSPaolo Bonzini dc->desc = "pass through generic scsi device (/dev/sg*)"; 60649ab747fSPaolo Bonzini dc->reset = scsi_generic_reset; 60749ab747fSPaolo Bonzini dc->props = scsi_generic_properties; 60849ab747fSPaolo Bonzini dc->vmsd = &vmstate_scsi_device; 60949ab747fSPaolo Bonzini } 61049ab747fSPaolo Bonzini 61149ab747fSPaolo Bonzini static const TypeInfo scsi_generic_info = { 61249ab747fSPaolo Bonzini .name = "scsi-generic", 61349ab747fSPaolo Bonzini .parent = TYPE_SCSI_DEVICE, 61449ab747fSPaolo Bonzini .instance_size = sizeof(SCSIDevice), 61549ab747fSPaolo Bonzini .class_init = scsi_generic_class_initfn, 61649ab747fSPaolo Bonzini }; 61749ab747fSPaolo Bonzini 61849ab747fSPaolo Bonzini static void scsi_generic_register_types(void) 61949ab747fSPaolo Bonzini { 62049ab747fSPaolo Bonzini type_register_static(&scsi_generic_info); 62149ab747fSPaolo Bonzini } 62249ab747fSPaolo Bonzini 62349ab747fSPaolo Bonzini type_init(scsi_generic_register_types) 62449ab747fSPaolo Bonzini 62549ab747fSPaolo Bonzini #endif /* __linux__ */ 626