diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2011-11-18 13:30:08 -0600 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2011-11-18 13:30:08 -0600 |
commit | 54dcd0b37e3e4e9fb25cb4e9965d6ba45eb0d2b4 (patch) | |
tree | 4a182ca92348e6bf0b1293e9142d0496d3b661a7 /hw | |
parent | 7197390a0b6e38017af94135b6055d8b7c6c2370 (diff) | |
parent | 33ebad12637a2e1503247fbb4d2960eaaff084ee (diff) |
Merge remote-tracking branch 'kwolf/block-stable' into staging
Diffstat (limited to 'hw')
-rw-r--r-- | hw/ide/atapi.c | 20 | ||||
-rw-r--r-- | hw/scsi-bus.c | 128 | ||||
-rw-r--r-- | hw/scsi-defs.h | 10 | ||||
-rw-r--r-- | hw/scsi-disk.c | 37 | ||||
-rw-r--r-- | hw/scsi.h | 2 |
5 files changed, 153 insertions, 44 deletions
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index 1fed359ab1..8af1cfdd7e 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -695,12 +695,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) int action, code; int max_len; - if (buf[0] == GPCMD_MODE_SENSE_10) { - max_len = ube16_to_cpu(buf + 7); - } else { - max_len = buf[4]; - } - + max_len = ube16_to_cpu(buf + 7); action = buf[2] >> 6; code = buf[2] & 0x3f; @@ -708,7 +703,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) case 0: /* current values */ switch(code) { case MODE_PAGE_R_W_ERROR: /* error recovery */ - cpu_to_ube16(&buf[0], 16 + 6); + cpu_to_ube16(&buf[0], 16 - 2); buf[2] = 0x70; buf[3] = 0; buf[4] = 0; @@ -727,7 +722,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) ide_atapi_cmd_reply(s, 16, max_len); break; case MODE_PAGE_AUDIO_CTL: - cpu_to_ube16(&buf[0], 24 + 6); + cpu_to_ube16(&buf[0], 24 - 2); buf[2] = 0x70; buf[3] = 0; buf[4] = 0; @@ -746,7 +741,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) ide_atapi_cmd_reply(s, 24, max_len); break; case MODE_PAGE_CAPABILITIES: - cpu_to_ube16(&buf[0], 28 + 6); + cpu_to_ube16(&buf[0], 30 - 2); buf[2] = 0x70; buf[3] = 0; buf[4] = 0; @@ -755,7 +750,7 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) buf[7] = 0; buf[8] = MODE_PAGE_CAPABILITIES; - buf[9] = 28 - 10; + buf[9] = 30 - 10; buf[10] = 0x3b; /* read CDR/CDRW/DVDROM/DVDR/DVDRAM */ buf[11] = 0x00; @@ -777,7 +772,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) buf[25] = 0; buf[26] = 0; buf[27] = 0; - ide_atapi_cmd_reply(s, 28, max_len); + buf[28] = 0; + buf[29] = 0; + ide_atapi_cmd_reply(s, 30, max_len); break; default: goto error_cmd; @@ -1043,7 +1040,6 @@ static const struct { [ 0x00 ] = { cmd_test_unit_ready, CHECK_READY }, [ 0x03 ] = { cmd_request_sense, ALLOW_UA }, [ 0x12 ] = { cmd_inquiry, ALLOW_UA }, - [ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 }, [ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */ [ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 }, [ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY }, diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index e6ebbd594e..3a2a7bb72c 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -9,8 +9,6 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev); static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); static void scsi_req_dequeue(SCSIRequest *req); -static int scsi_build_sense(uint8_t *in_buf, int in_len, - uint8_t *buf, int len, bool fixed); static struct BusInfo scsi_bus_info = { .name = "SCSI", @@ -502,7 +500,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, hba_private); } else if (lun != d->lun || buf[0] == REPORT_LUNS || - buf[0] == REQUEST_SENSE) { + (buf[0] == REQUEST_SENSE && (d->sense_len || cmd.xfer < 4))) { req = scsi_req_alloc(&reqops_target_command, d, tag, lun, hba_private); } else { @@ -649,6 +647,31 @@ static void scsi_req_dequeue(SCSIRequest *req) } } +static int scsi_get_performance_length(int num_desc, int type, int data_type) +{ + /* MMC-6, paragraph 6.7. */ + switch (type) { + case 0: + if ((data_type & 3) == 0) { + /* Each descriptor is as in Table 295 - Nominal performance. */ + return 16 * num_desc + 8; + } else { + /* Each descriptor is as in Table 296 - Exceptions. */ + return 6 * num_desc + 8; + } + case 1: + case 4: + case 5: + return 8 * num_desc + 8; + case 2: + return 2048 * num_desc + 8; + case 3: + return 16 * num_desc + 8; + default: + return 8; + } +} + static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) { switch (buf[0] >> 5) { @@ -666,11 +689,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) cmd->len = 10; break; case 4: - cmd->xfer = ldl_be_p(&buf[10]); + cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL; cmd->len = 16; break; case 5: - cmd->xfer = ldl_be_p(&buf[6]); + cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL; cmd->len = 12; break; default: @@ -681,8 +704,9 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case TEST_UNIT_READY: case REWIND: case START_STOP: - case SEEK_6: + case SET_CAPACITY: case WRITE_FILEMARKS: + case WRITE_FILEMARKS_16: case SPACE: case RESERVE: case RELEASE: @@ -691,6 +715,8 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case VERIFY_10: case SEEK_10: case SYNCHRONIZE_CACHE: + case SYNCHRONIZE_CACHE_16: + case LOCATE_16: case LOCK_UNLOCK_CACHE: case LOAD_UNLOAD: case SET_CD_SPEED: @@ -698,6 +724,11 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case WRITE_LONG_10: case MOVE_MEDIUM: case UPDATE_BLOCK: + case RESERVE_TRACK: + case SET_READ_AHEAD: + case PRE_FETCH: + case PRE_FETCH_16: + case ALLOW_OVERWRITE: cmd->xfer = 0; break; case MODE_SENSE: @@ -711,14 +742,13 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case READ_BLOCK_LIMITS: cmd->xfer = 6; break; - case READ_POSITION: - cmd->xfer = 20; - break; case SEND_VOLUME_TAG: - cmd->xfer *= 40; - break; - case MEDIUM_SCAN: - cmd->xfer *= 8; + /* GPCMD_SET_STREAMING from multimedia commands. */ + if (dev->type == TYPE_ROM) { + cmd->xfer = buf[10] | (buf[9] << 8); + } else { + cmd->xfer = buf[9] | (buf[8] << 8); + } break; case WRITE_10: case WRITE_VERIFY_10: @@ -737,9 +767,39 @@ static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf) case READ_16: cmd->xfer *= dev->blocksize; break; + case FORMAT_UNIT: + /* MMC mandates the parameter list to be 12-bytes long. Parameters + * for block devices are restricted to the header right now. */ + if (dev->type == TYPE_ROM && (buf[1] & 16)) { + cmd->xfer = 12; + } else { + cmd->xfer = (buf[1] & 16) == 0 ? 0 : (buf[1] & 32 ? 8 : 4); + } + break; case INQUIRY: + case RECEIVE_DIAGNOSTIC: + case SEND_DIAGNOSTIC: cmd->xfer = buf[4] | (buf[3] << 8); break; + case READ_CD: + case READ_BUFFER: + case WRITE_BUFFER: + case SEND_CUE_SHEET: + cmd->xfer = buf[8] | (buf[7] << 8) | (buf[6] << 16); + break; + case PERSISTENT_RESERVE_OUT: + cmd->xfer = ldl_be_p(&buf[5]) & 0xffffffffULL; + break; + case ERASE_12: + if (dev->type == TYPE_ROM) { + /* MMC command GET PERFORMANCE. */ + cmd->xfer = scsi_get_performance_length(buf[9] | (buf[8] << 8), + buf[10], buf[1] & 0x1f); + } + break; + case MECHANISM_STATUS: + case READ_DVD_STRUCTURE: + case SEND_DVD_STRUCTURE: case MAINTENANCE_OUT: case MAINTENANCE_IN: if (dev->type == TYPE_ROM) { @@ -755,6 +815,10 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu { switch (buf[0]) { /* stream commands */ + case ERASE_12: + case ERASE_16: + cmd->xfer = 0; + break; case READ_6: case READ_REVERSE: case RECOVER_BUFFERED_DATA: @@ -770,6 +834,15 @@ static int scsi_req_stream_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *bu cmd->len = 6; cmd->xfer = 0; break; + case SPACE_16: + cmd->xfer = buf[13] | (buf[12] << 8); + break; + case READ_POSITION: + cmd->xfer = buf[8] | (buf[7] << 8); + break; + case FORMAT_UNIT: + cmd->xfer = buf[4] | (buf[3] << 8); + break; /* generic commands */ default: return scsi_req_length(cmd, dev, buf); @@ -809,6 +882,8 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd) case SEARCH_LOW_12: case MEDIUM_SCAN: case SEND_VOLUME_TAG: + case SEND_CUE_SHEET: + case SEND_DVD_STRUCTURE: case PERSISTENT_RESERVE_OUT: case MAINTENANCE_OUT: cmd->mode = SCSI_XFER_TO_DEV; @@ -835,7 +910,7 @@ static uint64_t scsi_cmd_lba(SCSICommand *cmd) case 1: case 2: case 5: - lba = ldl_be_p(&buf[2]); + lba = ldl_be_p(&buf[2]) & 0xffffffffULL; break; case 4: lba = ldq_be_p(&buf[2]); @@ -1036,7 +1111,7 @@ static const char *scsi_command_name(uint8_t cmd) [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS", [ READ_6 ] = "READ_6", [ WRITE_6 ] = "WRITE_6", - [ SEEK_6 ] = "SEEK_6", + [ SET_CAPACITY ] = "SET_CAPACITY", [ READ_REVERSE ] = "READ_REVERSE", [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS", [ SPACE ] = "SPACE", @@ -1064,7 +1139,7 @@ static const char *scsi_command_name(uint8_t cmd) [ SEARCH_EQUAL ] = "SEARCH_EQUAL", [ SEARCH_LOW ] = "SEARCH_LOW", [ SET_LIMITS ] = "SET_LIMITS", - [ PRE_FETCH ] = "PRE_FETCH", + [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION", /* READ_POSITION and PRE_FETCH use the same operation code */ [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE", [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE", @@ -1101,9 +1176,11 @@ static const char *scsi_command_name(uint8_t cmd) [ WRITE_16 ] = "WRITE_16", [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16", [ VERIFY_16 ] = "VERIFY_16", - [ SYNCHRONIZE_CACHE_16 ] = "SYNCHRONIZE_CACHE_16", + [ PRE_FETCH_16 ] = "PRE_FETCH_16", + [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16", + /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */ [ LOCATE_16 ] = "LOCATE_16", - [ WRITE_SAME_16 ] = "WRITE_SAME_16", + [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16", /* ERASE_16 and WRITE_SAME_16 use the same operation code */ [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16", [ WRITE_LONG_16 ] = "WRITE_LONG_16", @@ -1113,6 +1190,8 @@ static const char *scsi_command_name(uint8_t cmd) [ LOAD_UNLOAD ] = "LOAD_UNLOAD", [ READ_12 ] = "READ_12", [ WRITE_12 ] = "WRITE_12", + [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE", + /* ERASE_12 and GET_PERFORMANCE use the same operation code */ [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12", [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12", [ VERIFY_12 ] = "VERIFY_12", @@ -1120,9 +1199,18 @@ static const char *scsi_command_name(uint8_t cmd) [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12", [ SEARCH_LOW_12 ] = "SEARCH_LOW_12", [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS", - [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG", + [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING", + /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */ + [ READ_CD ] = "READ_CD", [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12", + [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE", + [ RESERVE_TRACK ] = "RESERVE_TRACK", + [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET", + [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE", [ SET_CD_SPEED ] = "SET_CD_SPEED", + [ SET_READ_AHEAD ] = "SET_READ_AHEAD", + [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE", + [ MECHANISM_STATUS ] = "MECHANISM_STATUS", }; if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL) @@ -1279,7 +1367,7 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev) SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev); char path[100]; - snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev), + snprintf(path, sizeof(path), "%s@%d,%d,%d", qdev_fw_name(dev), d->channel, d->id, d->lun); return strdup(path); diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h index d0a467aab7..354ed7b55b 100644 --- a/hw/scsi-defs.h +++ b/hw/scsi-defs.h @@ -32,7 +32,7 @@ #define REASSIGN_BLOCKS 0x07 #define READ_6 0x08 #define WRITE_6 0x0a -#define SEEK_6 0x0b +#define SET_CAPACITY 0x0b #define READ_REVERSE 0x0f #define WRITE_FILEMARKS 0x10 #define SPACE 0x11 @@ -81,14 +81,17 @@ #define GET_EVENT_STATUS_NOTIFICATION 0x4a #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d +#define RESERVE_TRACK 0x53 #define MODE_SELECT_10 0x55 #define RESERVE_10 0x56 #define RELEASE_10 0x57 #define MODE_SENSE_10 0x5a +#define SEND_CUE_SHEET 0x5d #define PERSISTENT_RESERVE_IN 0x5e #define PERSISTENT_RESERVE_OUT 0x5f #define VARLENGTH_CDB 0x7f #define WRITE_FILEMARKS_16 0x80 +#define ALLOW_OVERWRITE 0x82 #define EXTENDED_COPY 0x83 #define ATA_PASSTHROUGH 0x85 #define ACCESS_CONTROL_IN 0x86 @@ -98,6 +101,8 @@ #define WRITE_16 0x8a #define WRITE_VERIFY_16 0x8e #define VERIFY_16 0x8f +#define PRE_FETCH_16 0x90 +#define SPACE_16 0x91 #define SYNCHRONIZE_CACHE_16 0x91 #define LOCATE_16 0x92 #define WRITE_SAME_16 0x93 @@ -110,9 +115,11 @@ #define MAINTENANCE_OUT 0xa4 #define MOVE_MEDIUM 0xa5 #define LOAD_UNLOAD 0xa6 +#define SET_READ_AHEAD 0xa7 #define READ_12 0xa8 #define WRITE_12 0xaa #define SERVICE_ACTION_IN_12 0xab +#define ERASE_12 0xac #define READ_DVD_STRUCTURE 0xad #define WRITE_VERIFY_12 0xae #define VERIFY_12 0xaf @@ -125,6 +132,7 @@ #define SET_CD_SPEED 0xbb #define MECHANISM_STATUS 0xbd #define READ_CD 0xbe +#define SEND_DVD_STRUCTURE 0xbf /* * SERVICE ACTION IN subcodes diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 62f538f4f8..673948c51f 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -797,7 +797,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, break; } /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs); + bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs); p[2] = (cylinders >> 16) & 0xff; p[3] = (cylinders >> 8) & 0xff; p[4] = cylinders & 0xff; @@ -831,7 +831,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, p[2] = 5000 >> 8; p[3] = 5000 & 0xff; /* if a geometry hint is available, use it */ - bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs); + bdrv_guess_geometry(bdrv, &cylinders, &heads, &secs); p[4] = heads & 0xff; p[5] = secs & 0xff; p[6] = s->qdev.blocksize >> 8; @@ -956,8 +956,9 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) p += 8; } + /* MMC prescribes that CD/DVD drives have no block descriptors. */ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); - if (!dbd && nb_sectors) { + if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) { if (r->req.cmd.buf[0] == MODE_SENSE) { outbuf[3] = 8; /* Block descriptor length */ } else { /* MODE_SENSE_10 */ @@ -1178,6 +1179,11 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r) outbuf[7] = 0; buflen = 8; break; + case REQUEST_SENSE: + /* Just return "NO SENSE". */ + buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen, + (req->cmd.buf[1] & 1) == 0); + break; case MECHANISM_STATUS: buflen = scsi_emulate_mechanism_status(s, outbuf); if (buflen < 0) { @@ -1312,6 +1318,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) case GET_EVENT_STATUS_NOTIFICATION: case MECHANISM_STATUS: case SERVICE_ACTION_IN_16: + case REQUEST_SENSE: case VERIFY_10: rc = scsi_disk_emulate_command(r); if (rc < 0) { @@ -1374,10 +1381,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) goto fail; } break; - case SEEK_6: case SEEK_10: - DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10, - r->req.cmd.lba); + DPRINTF("Seek(10) (sector %" PRId64 ")\n", r->req.cmd.lba); if (r->req.cmd.lba > s->qdev.max_lba) { goto illegal_lba; } @@ -1408,8 +1413,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) } break; - case REQUEST_SENSE: - abort(); default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); @@ -1553,7 +1556,7 @@ static int scsi_initfn(SCSIDevice *dev) bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize); bdrv_iostatus_enable(s->qdev.conf.bs); - add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0"); + add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, NULL); return 0; } @@ -1700,8 +1703,20 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, case WRITE_VERIFY_10: case WRITE_VERIFY_12: case WRITE_VERIFY_16: - return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, - hba_private); + /* MMC writing cannot be done via pread/pwrite, because it sometimes + * involves writing beyond the maximum LBA or to negative LBA (lead-in). + * And once you do these writes, reading from the block device is + * unreliable, too. It is even possible that reads deliver random data + * from the host page cache (this is probably a Linux bug). + * + * We might use scsi_disk_reqops as long as no writing commands are + * seen, but performance usually isn't paramount on optical media. So, + * just make scsi-block operate the same as scsi-generic for them. + */ + if (s->qdev.type != TYPE_ROM) { + return scsi_req_alloc(&scsi_disk_reqops, &s->qdev, tag, lun, + hba_private); + } } return scsi_req_alloc(&scsi_generic_req_ops, &s->qdev, tag, lun, @@ -179,6 +179,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET; #define SENSE_CODE(x) sense_code_ ## x int scsi_sense_valid(SCSISense sense); +int scsi_build_sense(uint8_t *in_buf, int in_len, + uint8_t *buf, int len, bool fixed); SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag, uint32_t lun, void *hba_private); |