diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/9pfs/virtio-9p.c | 126 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p.h | 4 | ||||
| -rw-r--r-- | hw/fdc.c | 4 | ||||
| -rw-r--r-- | hw/ide/ahci.c | 2 | ||||
| -rw-r--r-- | hw/ide/ahci.h | 1 | ||||
| -rw-r--r-- | hw/ide/atapi.c | 58 | ||||
| -rw-r--r-- | hw/ide/cmd646.c | 1 | ||||
| -rw-r--r-- | hw/ide/core.c | 160 | ||||
| -rw-r--r-- | hw/ide/ich.c | 1 | ||||
| -rw-r--r-- | hw/ide/internal.h | 3 | ||||
| -rw-r--r-- | hw/ide/isa.c | 1 | ||||
| -rw-r--r-- | hw/ide/macio.c | 1 | ||||
| -rw-r--r-- | hw/ide/microdrive.c | 1 | ||||
| -rw-r--r-- | hw/ide/mmio.c | 1 | ||||
| -rw-r--r-- | hw/ide/pci.c | 1 | ||||
| -rw-r--r-- | hw/ide/via.c | 1 | ||||
| -rw-r--r-- | hw/lsi53c895a.c | 1 | ||||
| -rw-r--r-- | hw/scsi-bus.c | 10 | ||||
| -rw-r--r-- | hw/scsi-disk.c | 69 | ||||
| -rw-r--r-- | hw/scsi-generic.c | 1 | ||||
| -rw-r--r-- | hw/scsi.h | 5 | ||||
| -rw-r--r-- | hw/sd.c | 2 | ||||
| -rw-r--r-- | hw/virtio-blk.c | 3 | ||||
| -rw-r--r-- | hw/virtio.h | 2 |
24 files changed, 368 insertions, 91 deletions
diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 94b7090e7d..d28edb799a 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -543,6 +543,7 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp) { size_t size; + memset(&qidp->path, 0, sizeof(qidp->path)); size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path)); memcpy(&qidp->path, &stbuf->st_ino, size); qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8); @@ -2106,6 +2107,7 @@ static void v9fs_create(void *opaque) if (err < 0) { goto out; } + v9fs_string_copy(&fidp->path, &fullname); err = v9fs_co_opendir(pdu->s, fidp); if (err < 0) { goto out; @@ -2336,6 +2338,45 @@ out_nofid: complete_pdu(pdu->s, pdu, err); } +static void v9fs_unlinkat(void *opaque) +{ + int err = 0; + V9fsString name; + int32_t dfid, flags; + size_t offset = 7; + V9fsFidState *dfidp; + V9fsPDU *pdu = opaque; + V9fsString full_name; + + pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags); + + dfidp = get_fid(pdu->s, dfid); + if (dfidp == NULL) { + err = -EINVAL; + goto out_nofid; + } + v9fs_string_init(&full_name); + v9fs_string_sprintf(&full_name, "%s/%s", dfidp->path.data, name.data); + /* + * IF the file is unlinked, we cannot reopen + * the file later. So don't reclaim fd + */ + err = v9fs_mark_fids_unreclaim(pdu->s, &full_name); + if (err < 0) { + goto out_err; + } + err = v9fs_co_remove(pdu->s, &full_name); + if (!err) { + err = offset; + } +out_err: + put_fid(pdu->s, dfidp); + v9fs_string_free(&full_name); +out_nofid: + complete_pdu(pdu->s, pdu, err); + v9fs_string_free(&name); +} + static int v9fs_complete_rename(V9fsState *s, V9fsFidState *fidp, int32_t newdirfid, V9fsString *name) { @@ -2438,6 +2479,87 @@ out_nofid: v9fs_string_free(&name); } +static int v9fs_complete_renameat(V9fsState *s, int32_t olddirfid, + V9fsString *old_name, int32_t newdirfid, + V9fsString *new_name) +{ + int err = 0; + V9fsString old_full_name, new_full_name; + V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL; + + olddirfidp = get_fid(s, olddirfid); + if (olddirfidp == NULL) { + err = -ENOENT; + goto out; + } + v9fs_string_init(&old_full_name); + v9fs_string_init(&new_full_name); + + v9fs_string_sprintf(&old_full_name, "%s/%s", + olddirfidp->path.data, old_name->data); + if (newdirfid != -1) { + newdirfidp = get_fid(s, newdirfid); + if (newdirfidp == NULL) { + err = -ENOENT; + goto out; + } + v9fs_string_sprintf(&new_full_name, "%s/%s", + newdirfidp->path.data, new_name->data); + } else { + v9fs_string_sprintf(&new_full_name, "%s/%s", + olddirfidp->path.data, new_name->data); + } + + if (strcmp(old_full_name.data, new_full_name.data) != 0) { + V9fsFidState *tfidp; + err = v9fs_co_rename(s, &old_full_name, &new_full_name); + if (err < 0) { + goto out; + } + /* + * Fixup fid's pointing to the old name to + * start pointing to the new name + */ + for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) { + if (v9fs_path_is_ancestor(&old_full_name, &tfidp->path)) { + /* replace the name */ + v9fs_fix_path(&tfidp->path, &new_full_name, old_full_name.size); + } + } + } +out: + if (olddirfidp) { + put_fid(s, olddirfidp); + } + if (newdirfidp) { + put_fid(s, newdirfidp); + } + v9fs_string_free(&old_full_name); + v9fs_string_free(&new_full_name); + return err; +} + +static void v9fs_renameat(void *opaque) +{ + ssize_t err = 0; + size_t offset = 7; + V9fsPDU *pdu = opaque; + V9fsState *s = pdu->s; + int32_t olddirfid, newdirfid; + V9fsString old_name, new_name; + + pdu_unmarshal(pdu, offset, "dsds", &olddirfid, + &old_name, &newdirfid, &new_name); + + err = v9fs_complete_renameat(s, olddirfid, &old_name, newdirfid, &new_name); + if (!err) { + err = offset; + } + complete_pdu(s, pdu, err); + v9fs_string_free(&old_name); + v9fs_string_free(&new_name); +} + static void v9fs_wstat(void *opaque) { int32_t fid; @@ -2694,6 +2816,7 @@ out_nofid: err = offset; err += pdu_marshal(pdu, offset, "b", status); complete_pdu(s, pdu, err); + v9fs_string_free(&flock->client_id); g_free(flock); } @@ -2734,6 +2857,7 @@ out: put_fid(s, fidp); out_nofid: complete_pdu(s, pdu, err); + v9fs_string_free(&glock->client_id); g_free(glock); } @@ -2953,7 +3077,9 @@ static CoroutineEntry *pdu_co_handlers[] = { [P9_TRENAME] = v9fs_rename, [P9_TLOCK] = v9fs_lock, [P9_TGETLOCK] = v9fs_getlock, + [P9_TRENAMEAT] = v9fs_renameat, [P9_TREADLINK] = v9fs_readlink, + [P9_TUNLINKAT] = v9fs_unlinkat, [P9_TMKDIR] = v9fs_mkdir, [P9_TVERSION] = v9fs_version, [P9_TLOPEN] = v9fs_open, diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 9d1b508e16..17d44b41ca 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -50,6 +50,10 @@ enum { P9_RLINK, P9_TMKDIR = 72, P9_RMKDIR, + P9_TRENAMEAT = 74, + P9_RRENAMEAT, + P9_TUNLINKAT = 76, + P9_RUNLINKAT, P9_TVERSION = 100, P9_RVERSION, P9_TAUTH = 102, diff --git a/hw/fdc.c b/hw/fdc.c index 1d44bbd1e3..433af73ad7 100644 --- a/hw/fdc.c +++ b/hw/fdc.c @@ -36,7 +36,6 @@ #include "qdev-addr.h" #include "blockdev.h" #include "sysemu.h" -#include "block_int.h" /********************************************************/ /* debug Floppy devices */ @@ -1778,7 +1777,7 @@ static void fdctrl_result_timer(void *opaque) fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); } -static void fdctrl_change_cb(void *opaque) +static void fdctrl_change_cb(void *opaque, bool load) { FDrive *drive = opaque; @@ -1813,7 +1812,6 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) fd_revalidate(drive); if (drive->bs) { drive->media_changed = 1; - bdrv_set_removable(drive->bs, 1); bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive); } } diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index f4fa1545bd..a8659cf8b9 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -754,7 +754,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, case READ_FPDMA_QUEUED: DPRINTF(port, "NCQ reading %d sectors from LBA %ld, tag %d\n", ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag); - ncq_tfs->is_read = 1; DPRINTF(port, "tag %d aio read %ld\n", ncq_tfs->tag, ncq_tfs->lba); @@ -768,7 +767,6 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, case WRITE_FPDMA_QUEUED: DPRINTF(port, "NCQ writing %d sectors to LBA %ld, tag %d\n", ncq_tfs->sector_count-1, ncq_tfs->lba, ncq_tfs->tag); - ncq_tfs->is_read = 0; DPRINTF(port, "tag %d aio write %ld\n", ncq_tfs->tag, ncq_tfs->lba); diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 3c29d93b47..5de986c90f 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -259,7 +259,6 @@ typedef struct NCQTransferState { BlockDriverAIOCB *aiocb; QEMUSGList sglist; BlockAcctCookie acct; - int is_read; uint16_t sector_count; uint64_t lba; uint8_t tag; diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c index f38d2896ae..3f909c3a99 100644 --- a/hw/ide/atapi.c +++ b/hw/ide/atapi.c @@ -73,7 +73,7 @@ static void lba_to_msf(uint8_t *buf, int lba) static inline int media_present(IDEState *s) { - return (s->nb_sectors > 0); + return !s->tray_open && s->nb_sectors > 0; } /* XXX: DVDs that could fit on a CD will be reported as a CD */ @@ -521,7 +521,7 @@ static unsigned int event_status_media(IDEState *s, uint8_t event_code, media_status; media_status = 0; - if (s->bs->tray_open) { + if (s->tray_open) { media_status = MS_TRAY_OPEN; } else if (bdrv_is_inserted(s->bs)) { media_status = MS_MEDIA_PRESENT; @@ -788,8 +788,9 @@ static void cmd_mode_sense(IDEState *s, uint8_t *buf) buf[12] = 0x71; buf[13] = 3 << 5; buf[14] = (1 << 0) | (1 << 3) | (1 << 5); - if (bdrv_is_locked(s->bs)) + if (s->tray_locked) { buf[6] |= 1 << 1; + } buf[15] = 0x00; cpu_to_ube16(&buf[16], 706); buf[18] = 0; @@ -831,7 +832,8 @@ static void cmd_test_unit_ready(IDEState *s, uint8_t *buf) static void cmd_prevent_allow_medium_removal(IDEState *s, uint8_t* buf) { - bdrv_set_locked(s->bs, buf[4] & 1); + s->tray_locked = buf[4] & 1; + bdrv_lock_medium(s->bs, buf[4] & 1); ide_atapi_cmd_ok(s); } @@ -903,29 +905,22 @@ static void cmd_seek(IDEState *s, uint8_t* buf) static void cmd_start_stop_unit(IDEState *s, uint8_t* buf) { - int start, eject, sense, err = 0; - start = buf[4] & 1; - eject = (buf[4] >> 1) & 1; - - if (eject) { - err = bdrv_eject(s->bs, !start); - } - - switch (err) { - case 0: - ide_atapi_cmd_ok(s); - break; - case -EBUSY: - sense = SENSE_NOT_READY; - if (bdrv_is_inserted(s->bs)) { - sense = SENSE_ILLEGAL_REQUEST; + int sense; + bool start = buf[4] & 1; + bool loej = buf[4] & 2; /* load on start, eject on !start */ + + if (loej) { + if (!start && !s->tray_open && s->tray_locked) { + sense = bdrv_is_inserted(s->bs) + ? SENSE_NOT_READY : SENSE_ILLEGAL_REQUEST; + ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); + return; } - ide_atapi_cmd_error(s, sense, ASC_MEDIA_REMOVAL_PREVENTED); - break; - default: - ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - break; + bdrv_eject(s->bs, !start); + s->tray_open = !start; } + + ide_atapi_cmd_ok(s); } static void cmd_mechanism_status(IDEState *s, uint8_t* buf) @@ -1073,20 +1068,21 @@ static const struct { [ 0x03 ] = { cmd_request_sense, ALLOW_UA }, [ 0x12 ] = { cmd_inquiry, ALLOW_UA }, [ 0x1a ] = { cmd_mode_sense, /* (6) */ 0 }, - [ 0x1b ] = { cmd_start_stop_unit, 0 }, + [ 0x1b ] = { cmd_start_stop_unit, 0 }, /* [1] */ [ 0x1e ] = { cmd_prevent_allow_medium_removal, 0 }, [ 0x25 ] = { cmd_read_cdvd_capacity, CHECK_READY }, - [ 0x28 ] = { cmd_read, /* (10) */ 0 }, + [ 0x28 ] = { cmd_read, /* (10) */ CHECK_READY }, [ 0x2b ] = { cmd_seek, CHECK_READY }, [ 0x43 ] = { cmd_read_toc_pma_atip, CHECK_READY }, [ 0x46 ] = { cmd_get_configuration, ALLOW_UA }, [ 0x4a ] = { cmd_get_event_status_notification, ALLOW_UA }, [ 0x5a ] = { cmd_mode_sense, /* (10) */ 0 }, - [ 0xa8 ] = { cmd_read, /* (12) */ 0 }, - [ 0xad ] = { cmd_read_dvd_structure, 0 }, + [ 0xa8 ] = { cmd_read, /* (12) */ CHECK_READY }, + [ 0xad ] = { cmd_read_dvd_structure, CHECK_READY }, [ 0xbb ] = { cmd_set_speed, 0 }, [ 0xbd ] = { cmd_mechanism_status, 0 }, - [ 0xbe ] = { cmd_read_cd, 0 }, + [ 0xbe ] = { cmd_read_cd, CHECK_READY }, + /* [1] handler detects and reports not ready condition itself */ }; void ide_atapi_cmd(IDEState *s) @@ -1122,7 +1118,7 @@ void ide_atapi_cmd(IDEState *s) * GET_EVENT_STATUS_NOTIFICATION to detect such tray open/close * states rely on this behavior. */ - if (bdrv_is_inserted(s->bs) && s->cdrom_changed) { + if (!s->tray_open && bdrv_is_inserted(s->bs) && s->cdrom_changed) { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); s->cdrom_changed = 0; diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 4d91e2c642..5fe98b1bb3 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -27,7 +27,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/ide/core.c b/hw/ide/core.c index 1806e008bc..9297b9e657 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -30,6 +30,7 @@ #include "sysemu.h" #include "dma.h" #include "blockdev.h" +#include "block_int.h" #include <hw/ide/internal.h> @@ -783,11 +784,12 @@ static void ide_cfata_metadata_write(IDEState *s) } /* called when the inserted state of the media has changed */ -static void ide_cd_change_cb(void *opaque) +static void ide_cd_change_cb(void *opaque, bool load) { IDEState *s = opaque; uint64_t nb_sectors; + s->tray_open = !load; bdrv_get_geometry(s->bs, &nb_sectors); s->nb_sectors = nb_sectors; @@ -901,6 +903,78 @@ void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val) } } +#define HD_OK (1u << IDE_HD) +#define CD_OK (1u << IDE_CD) +#define CFA_OK (1u << IDE_CFATA) +#define HD_CFA_OK (HD_OK | CFA_OK) +#define ALL_OK (HD_OK | CD_OK | CFA_OK) + +/* See ACS-2 T13/2015-D Table B.2 Command codes */ +static const uint8_t ide_cmd_table[0x100] = { + /* NOP not implemented, mandatory for CD */ + [CFA_REQ_EXT_ERROR_CODE] = CFA_OK, + [WIN_DSM] = ALL_OK, + [WIN_DEVICE_RESET] = CD_OK, + [WIN_RECAL] = HD_CFA_OK, + [WIN_READ] = ALL_OK, + [WIN_READ_ONCE] = ALL_OK, + [WIN_READ_EXT] = HD_CFA_OK, + [WIN_READDMA_EXT] = HD_CFA_OK, + [WIN_READ_NATIVE_MAX_EXT] = HD_CFA_OK, + [WIN_MULTREAD_EXT] = HD_CFA_OK, + [WIN_WRITE] = HD_CFA_OK, + [WIN_WRITE_ONCE] = HD_CFA_OK, + [WIN_WRITE_EXT] = HD_CFA_OK, + [WIN_WRITEDMA_EXT] = HD_CFA_OK, + [CFA_WRITE_SECT_WO_ERASE] = CFA_OK, + [WIN_MULTWRITE_EXT] = HD_CFA_OK, + [WIN_WRITE_VERIFY] = HD_CFA_OK, + [WIN_VERIFY] = HD_CFA_OK, + [WIN_VERIFY_ONCE] = HD_CFA_OK, + [WIN_VERIFY_EXT] = HD_CFA_OK, + [WIN_SEEK] = HD_CFA_OK, + [CFA_TRANSLATE_SECTOR] = CFA_OK, + [WIN_DIAGNOSE] = ALL_OK, + [WIN_SPECIFY] = HD_CFA_OK, + [WIN_STANDBYNOW2] = ALL_OK, + [WIN_IDLEIMMEDIATE2] = ALL_OK, + [WIN_STANDBY2] = ALL_OK, + [WIN_SETIDLE2] = ALL_OK, + [WIN_CHECKPOWERMODE2] = ALL_OK, + [WIN_SLEEPNOW2] = ALL_OK, + [WIN_PACKETCMD] = CD_OK, + [WIN_PIDENTIFY] = CD_OK, + [WIN_SMART] = HD_CFA_OK, + [CFA_ACCESS_METADATA_STORAGE] = CFA_OK, + [CFA_ERASE_SECTORS] = CFA_OK, + [WIN_MULTREAD] = HD_CFA_OK, + [WIN_MULTWRITE] = HD_CFA_OK, + [WIN_SETMULT] = HD_CFA_OK, + [WIN_READDMA] = HD_CFA_OK, + [WIN_READDMA_ONCE] = HD_CFA_OK, + [WIN_WRITEDMA] = HD_CFA_OK, + [WIN_WRITEDMA_ONCE] = HD_CFA_OK, + [CFA_WRITE_MULTI_WO_ERASE] = CFA_OK, + [WIN_STANDBYNOW1] = ALL_OK, + [WIN_IDLEIMMEDIATE] = ALL_OK, + [WIN_STANDBY] = ALL_OK, + [WIN_SETIDLE1] = ALL_OK, + [WIN_CHECKPOWERMODE1] = ALL_OK, + [WIN_SLEEPNOW1] = ALL_OK, + [WIN_FLUSH_CACHE] = ALL_OK, + [WIN_FLUSH_CACHE_EXT] = HD_CFA_OK, + [WIN_IDENTIFY] = ALL_OK, + [WIN_SETFEATURES] = ALL_OK, + [IBM_SENSE_CONDITION] = CFA_OK, + [CFA_WEAR_LEVEL] = CFA_OK, + [WIN_READ_NATIVE_MAX] = ALL_OK, +}; + +static bool ide_cmd_permitted(IDEState *s, uint32_t cmd) +{ + return cmd < ARRAY_SIZE(ide_cmd_table) + && (ide_cmd_table[cmd] & (1u << s->drive_kind)); +} void ide_exec_cmd(IDEBus *bus, uint32_t val) { @@ -920,6 +994,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) if ((s->status & (BUSY_STAT|DRQ_STAT)) && val != WIN_DEVICE_RESET) return; + if (!ide_cmd_permitted(s, val)) { + goto abort_cmd; + } + switch(val) { case WIN_DSM: switch (s->feature) { @@ -983,8 +1061,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) lba48 = 1; case WIN_READ: case WIN_READ_ONCE: - if (!s->bs) + if (s->drive_kind == IDE_CD) { + ide_set_signature(s); /* odd, but ATA4 8.27.5.2 requires it */ goto abort_cmd; + } ide_cmd_lba48_transform(s, lba48); s->req_nb_sectors = 1; ide_sector_read(s); @@ -1138,21 +1218,15 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case WIN_SEEK: - if(s->drive_kind == IDE_CD) - goto abort_cmd; /* XXX: Check that seek is within bounds */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; /* ATAPI commands */ case WIN_PIDENTIFY: - if (s->drive_kind == IDE_CD) { - ide_atapi_identify(s); - s->status = READY_STAT | SEEK_STAT; - ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); - } else { - ide_abort_command(s); - } + ide_atapi_identify(s); + s->status = READY_STAT | SEEK_STAT; + ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop); ide_set_irq(s->bus); break; case WIN_DIAGNOSE: @@ -1169,15 +1243,11 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case WIN_DEVICE_RESET: - if (s->drive_kind != IDE_CD) - goto abort_cmd; ide_set_signature(s); s->status = 0x00; /* NOTE: READY is _not_ set */ s->error = 0x01; break; case WIN_PACKETCMD: - if (s->drive_kind != IDE_CD) - goto abort_cmd; /* overlapping commands not supported */ if (s->feature & 0x02) goto abort_cmd; @@ -1189,16 +1259,12 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) break; /* CF-ATA commands */ case CFA_REQ_EXT_ERROR_CODE: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; s->error = 0x09; /* miscellaneous error */ s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; case CFA_ERASE_SECTORS: case CFA_WEAR_LEVEL: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; if (val == CFA_WEAR_LEVEL) s->nsector = 0; if (val == CFA_ERASE_SECTORS) @@ -1208,8 +1274,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case CFA_TRANSLATE_SECTOR: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; s->error = 0x00; s->status = READY_STAT | SEEK_STAT; memset(s->io_buffer, 0, 0x200); @@ -1228,8 +1292,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case CFA_ACCESS_METADATA_STORAGE: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; switch (s->feature) { case 0x02: /* Inquiry Metadata Storage */ ide_cfata_metadata_inquiry(s); @@ -1248,8 +1310,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_set_irq(s->bus); break; case IBM_SENSE_CONDITION: - if (s->drive_kind != IDE_CFATA) - goto abort_cmd; switch (s->feature) { case 0x01: /* sense temperature in device */ s->nsector = 0x50; /* +20 C */ @@ -1262,8 +1322,6 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) break; case WIN_SMART: - if (s->drive_kind == IDE_CD) - goto abort_cmd; if (s->hcyl != 0xc2 || s->lcyl != 0x4f) goto abort_cmd; if (!s->smart_enabled && s->feature != SMART_ENABLE) @@ -1418,6 +1476,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) } break; default: + /* should not be reachable */ abort_cmd: ide_abort_command(s); ide_set_irq(s->bus); @@ -1738,8 +1797,20 @@ void ide_bus_reset(IDEBus *bus) bus->dma->ops->reset(bus->dma); } +static bool ide_cd_is_tray_open(void *opaque) +{ + return ((IDEState *)opaque)->tray_open; +} + +static bool ide_cd_is_medium_locked(void *opaque) +{ + return ((IDEState *)opaque)->tray_locked; +} + static const BlockDevOps ide_cd_block_ops = { .change_media_cb = ide_cd_change_cb, + .is_tray_open = ide_cd_is_tray_open, + .is_medium_locked = ide_cd_is_medium_locked, }; int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, @@ -1777,7 +1848,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, s->smart_selftest_count = 0; if (kind == IDE_CD) { bdrv_set_dev_ops(bs, &ide_cd_block_ops, s); - bs->buffer_alignment = 2048; + bdrv_set_buffer_alignment(bs, 2048); } else { if (!bdrv_is_inserted(s->bs)) { error_report("Device needs media, but drive is empty"); @@ -1801,7 +1872,6 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, } ide_reset(s); - bdrv_set_removable(bs, s->drive_kind == IDE_CD); return 0; } @@ -1995,6 +2065,22 @@ static bool ide_drive_pio_state_needed(void *opaque) || (s->bus->error_status & BM_STATUS_PIO_RETRY); } +static int ide_tray_state_post_load(void *opaque, int version_id) +{ + IDEState *s = opaque; + + bdrv_eject(s->bs, s->tray_open); + bdrv_lock_medium(s->bs, s->tray_locked); + return 0; +} + +static bool ide_tray_state_needed(void *opaque) +{ + IDEState *s = opaque; + + return s->tray_open || s->tray_locked; +} + static bool ide_atapi_gesn_needed(void *opaque) { IDEState *s = opaque; @@ -2022,6 +2108,19 @@ static const VMStateDescription vmstate_ide_atapi_gesn_state = { } }; +static const VMStateDescription vmstate_ide_tray_state = { + .name = "ide_drive/tray_state", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ide_tray_state_post_load, + .fields = (VMStateField[]) { + VMSTATE_BOOL(tray_open, IDEState), + VMSTATE_BOOL(tray_locked, IDEState), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_ide_drive_pio_state = { .name = "ide_drive/pio_state", .version_id = 1, @@ -2076,6 +2175,9 @@ const VMStateDescription vmstate_ide_drive = { .vmsd = &vmstate_ide_drive_pio_state, .needed = ide_drive_pio_state_needed, }, { + .vmsd = &vmstate_ide_tray_state, + .needed = ide_tray_state_needed, + }, { .vmsd = &vmstate_ide_atapi_gesn_state, .needed = ide_atapi_gesn_needed, }, { diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 5278bc4d6c..0327d0ee72 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -66,7 +66,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/pci.h> diff --git a/hw/ide/internal.h b/hw/ide/internal.h index 111785294d..233915ce0d 100644 --- a/hw/ide/internal.h +++ b/hw/ide/internal.h @@ -7,7 +7,6 @@ * non-internal declarations are in hw/ide.h */ #include <hw/ide.h> -#include "block_int.h" #include "iorange.h" #include "dma.h" @@ -442,6 +441,8 @@ struct IDEState { struct unreported_events events; uint8_t sense_key; uint8_t asc; + bool tray_open; + bool tray_locked; uint8_t cdrom_changed; int packet_transfer_size; int elementary_transfer_size; diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 4ac745324c..28b69d2cc3 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -26,7 +26,6 @@ #include <hw/pc.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/macio.c b/hw/ide/macio.c index fdf5d75082..c1844cb738 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -26,7 +26,6 @@ #include <hw/ppc_mac.h> #include <hw/mac_dbdma.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/microdrive.c b/hw/ide/microdrive.c index 91c0e3c89d..9eee5b50ba 100644 --- a/hw/ide/microdrive.c +++ b/hw/ide/microdrive.c @@ -26,7 +26,6 @@ #include <hw/pc.h> #include <hw/pcmcia.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 132b7517ba..2ec21b0163 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -24,7 +24,6 @@ */ #include <hw/hw.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/internal.h> diff --git a/hw/ide/pci.c b/hw/ide/pci.c index d1a14d7cc1..9fded02954 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -27,7 +27,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "dma.h" #include <hw/ide/pci.h> diff --git a/hw/ide/via.c b/hw/ide/via.c index c0b9d43827..dab8a39f57 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -28,7 +28,6 @@ #include <hw/pci.h> #include <hw/isa.h> #include "block.h" -#include "block_int.h" #include "sysemu.h" #include "dma.h" diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index ac284e9609..dbb3bdf2ce 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -15,7 +15,6 @@ #include "hw.h" #include "pci.h" #include "scsi.h" -#include "block_int.h" //#define DEBUG_LSI //#define DEBUG_LSI_REG diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 59d6adafa0..02482947ca 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -772,6 +772,11 @@ const struct SCSISense sense_code_NO_MEDIUM = { .key = NOT_READY, .asc = 0x3a, .ascq = 0x00 }; +/* LUN not ready, medium removal prevented */ +const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = { + .key = NOT_READY, .asc = 0x53, .ascq = 0x00 +}; + /* Hardware error, internal target failure */ const struct SCSISense sense_code_TARGET_FAILURE = { .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00 @@ -807,6 +812,11 @@ const struct SCSISense sense_code_INCOMPATIBLE_MEDIUM = { .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00 }; +/* Illegal request, medium removal prevented */ +const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { + .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00 +}; + /* Command aborted, I/O process terminated */ const struct SCSISense sense_code_IO_ERROR = { .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 9724d0fe9a..4a60820b18 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -37,6 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include "scsi-defs.h" #include "sysemu.h" #include "blockdev.h" +#include "block_int.h" #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 @@ -72,6 +73,8 @@ struct SCSIDiskState QEMUBH *bh; char *version; char *serial; + bool tray_open; + bool tray_locked; }; static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); @@ -182,6 +185,9 @@ static void scsi_read_data(SCSIRequest *req) if (n > SCSI_DMA_BUF_SIZE / 512) n = SCSI_DMA_BUF_SIZE / 512; + if (s->tray_open) { + scsi_read_complete(r, -ENOMEDIUM); + } r->iov.iov_len = n * 512; qemu_iovec_init_external(&r->qiov, &r->iov, 1); @@ -280,6 +286,9 @@ static void scsi_write_data(SCSIRequest *req) n = r->iov.iov_len / 512; if (n) { + if (s->tray_open) { + scsi_write_complete(r, -ENOMEDIUM); + } qemu_iovec_init_external(&r->qiov, &r->iov, 1); bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE); @@ -664,7 +673,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, p[5] = 0xff; /* CD DA, DA accurate, RW supported, RW corrected, C2 errors, ISRC, UPC, Bar code */ - p[6] = 0x2d | (bdrv_is_locked(s->bs)? 2 : 0); + p[6] = 0x2d | (s->tray_locked ? 2 : 0); /* Locking supported, jumper present, eject, tray */ p[7] = 0; /* no volume & mute control, no changer */ @@ -814,6 +823,27 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf) return toclen; } +static int scsi_disk_emulate_start_stop(SCSIDiskReq *r) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + bool start = req->cmd.buf[4] & 1; + bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */ + + if (s->qdev.type == TYPE_ROM && loej) { + if (!start && !s->tray_open && s->tray_locked) { + scsi_check_condition(r, + bdrv_is_inserted(s->bs) + ? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED) + : SENSE_CODE(NOT_READY_REMOVAL_PREVENTED)); + return -1; + } + bdrv_eject(s->bs, !start); + s->tray_open = !start; + } + return 0; +} + static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) { SCSIRequest *req = &r->req; @@ -823,7 +853,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) switch (req->cmd.buf[0]) { case TEST_UNIT_READY: - if (!bdrv_is_inserted(s->bs)) + if (s->tray_open || !bdrv_is_inserted(s->bs)) goto not_ready; break; case INQUIRY: @@ -859,13 +889,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) goto illegal_request; break; case START_STOP: - if (s->qdev.type == TYPE_ROM && (req->cmd.buf[4] & 2)) { - /* load/eject medium */ - bdrv_eject(s->bs, !(req->cmd.buf[4] & 1)); + if (scsi_disk_emulate_start_stop(r) < 0) { + return -1; } break; case ALLOW_MEDIUM_REMOVAL: - bdrv_set_locked(s->bs, req->cmd.buf[4] & 1); + s->tray_locked = req->cmd.buf[4] & 1; + bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1); break; case READ_CAPACITY_10: /* The normal LEN field for this command is zero. */ @@ -946,7 +976,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) return buflen; not_ready: - if (!bdrv_is_inserted(s->bs)) { + if (s->tray_open || !bdrv_is_inserted(s->bs)) { scsi_check_condition(r, SENSE_CODE(NO_MEDIUM)); } else { scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); @@ -1143,6 +1173,27 @@ static void scsi_destroy(SCSIDevice *dev) blockdev_mark_auto_del(s->qdev.conf.bs); } +static void scsi_cd_change_media_cb(void *opaque, bool load) +{ + ((SCSIDiskState *)opaque)->tray_open = !load; +} + +static bool scsi_cd_is_tray_open(void *opaque) +{ + return ((SCSIDiskState *)opaque)->tray_open; +} + +static bool scsi_cd_is_medium_locked(void *opaque) +{ + return ((SCSIDiskState *)opaque)->tray_locked; +} + +static const BlockDevOps scsi_cd_block_ops = { + .change_media_cb = scsi_cd_change_media_cb, + .is_tray_open = scsi_cd_is_tray_open, + .is_medium_locked = scsi_cd_is_medium_locked, +}; + static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) { SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev); @@ -1177,6 +1228,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) } if (scsi_type == TYPE_ROM) { + bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s); s->qdev.blocksize = 2048; } else if (scsi_type == TYPE_DISK) { s->qdev.blocksize = s->qdev.conf.logical_block_size; @@ -1185,11 +1237,10 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type) return -1; } s->cluster_size = s->qdev.blocksize / 512; - s->bs->buffer_alignment = s->qdev.blocksize; + bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize); s->qdev.type = scsi_type; qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); - bdrv_set_removable(s->bs, scsi_type == TYPE_ROM); add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0"); return 0; } diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c index cb5d4f125d..5ce01afdce 100644 --- a/hw/scsi-generic.c +++ b/hw/scsi-generic.c @@ -450,7 +450,6 @@ static int scsi_generic_initfn(SCSIDevice *dev) } } DPRINTF("block size %d\n", s->qdev.blocksize); - bdrv_set_removable(s->bs, 0); return 0; } diff --git a/hw/scsi.h b/hw/scsi.h index 98fd689859..e8dcabfa28 100644 --- a/hw/scsi.h +++ b/hw/scsi.h @@ -3,7 +3,6 @@ #include "qdev.h" #include "block.h" -#include "block_int.h" #define MAX_SCSI_DEVS 255 @@ -136,6 +135,8 @@ extern const struct SCSISense sense_code_NO_SENSE; extern const struct SCSISense sense_code_LUN_NOT_READY; /* LUN not ready, Medium not present */ extern const struct SCSISense sense_code_NO_MEDIUM; +/* LUN not ready, medium removal prevented */ +extern const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED; /* Hardware error, internal target failure */ extern const struct SCSISense sense_code_TARGET_FAILURE; /* Illegal request, invalid command operation code */ @@ -150,6 +151,8 @@ extern const struct SCSISense sense_code_LUN_NOT_SUPPORTED; extern const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED; /* Illegal request, Incompatible format */ extern const struct SCSISense sense_code_INCOMPATIBLE_FORMAT; +/* Illegal request, medium removal prevented */ +extern const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED; /* Command aborted, I/O process terminated */ extern const struct SCSISense sense_code_IO_ERROR; /* Command aborted, I_T Nexus loss occurred */ diff --git a/hw/sd.c b/hw/sd.c index 1af62b23c6..10e26ade58 100644 --- a/hw/sd.c +++ b/hw/sd.c @@ -419,7 +419,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) sd->pwd_len = 0; } -static void sd_cardchange(void *opaque) +static void sd_cardchange(void *opaque, bool load) { SDState *sd = opaque; diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index d5d4757f62..c2ee0001eb 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -599,9 +599,8 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, s->qdev = dev; register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); - bdrv_set_removable(s->bs, 0); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); - s->bs->buffer_alignment = conf->logical_block_size; + bdrv_set_buffer_alignment(s->bs, conf->logical_block_size); add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); diff --git a/hw/virtio.h b/hw/virtio.h index c1292647fe..4d20d9b8f4 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -18,7 +18,7 @@ #include "net.h" #include "qdev.h" #include "sysemu.h" -#include "block_int.h" +#include "block.h" #include "event_notifier.h" #ifdef CONFIG_LINUX #include "9p.h" |