Merge remote-tracking branch 'kwolf/for-anthony' into staging
This commit is contained in:
		
						commit
						220724ca4a
					
				
							
								
								
									
										24
									
								
								async.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								async.c
									
									
									
									
									
								
							| @ -55,6 +55,9 @@ int qemu_bh_poll(void) | ||||
| { | ||||
|     QEMUBH *bh, **bhp, *next; | ||||
|     int ret; | ||||
|     static int nesting = 0; | ||||
| 
 | ||||
|     nesting++; | ||||
| 
 | ||||
|     ret = 0; | ||||
|     for (bh = first_bh; bh; bh = next) { | ||||
| @ -68,15 +71,20 @@ int qemu_bh_poll(void) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     nesting--; | ||||
| 
 | ||||
|     /* remove deleted bhs */ | ||||
|     bhp = &first_bh; | ||||
|     while (*bhp) { | ||||
|         bh = *bhp; | ||||
|         if (bh->deleted) { | ||||
|             *bhp = bh->next; | ||||
|             g_free(bh); | ||||
|         } else | ||||
|             bhp = &bh->next; | ||||
|     if (!nesting) { | ||||
|         bhp = &first_bh; | ||||
|         while (*bhp) { | ||||
|             bh = *bhp; | ||||
|             if (bh->deleted) { | ||||
|                 *bhp = bh->next; | ||||
|                 g_free(bh); | ||||
|             } else { | ||||
|                 bhp = &bh->next; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return ret; | ||||
|  | ||||
							
								
								
									
										104
									
								
								block.c
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								block.c
									
									
									
									
									
								
							| @ -44,6 +44,7 @@ | ||||
| #include <windows.h> | ||||
| #endif | ||||
| 
 | ||||
| static void bdrv_dev_change_media_cb(BlockDriverState *bs); | ||||
| static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, | ||||
|         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, | ||||
|         BlockDriverCompletionFunc *cb, void *opaque); | ||||
| @ -688,10 +689,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, | ||||
|     } | ||||
| 
 | ||||
|     if (!bdrv_key_required(bs)) { | ||||
|         /* call the change callback */ | ||||
|         bs->media_changed = 1; | ||||
|         if (bs->change_cb) | ||||
|             bs->change_cb(bs->change_opaque, CHANGE_MEDIA); | ||||
|         bdrv_dev_change_media_cb(bs); | ||||
|     } | ||||
| 
 | ||||
|     return 0; | ||||
| @ -727,10 +725,7 @@ void bdrv_close(BlockDriverState *bs) | ||||
|             bdrv_close(bs->file); | ||||
|         } | ||||
| 
 | ||||
|         /* call the change callback */ | ||||
|         bs->media_changed = 1; | ||||
|         if (bs->change_cb) | ||||
|             bs->change_cb(bs->change_opaque, CHANGE_MEDIA); | ||||
|         bdrv_dev_change_media_cb(bs); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -755,7 +750,7 @@ void bdrv_make_anon(BlockDriverState *bs) | ||||
| 
 | ||||
| void bdrv_delete(BlockDriverState *bs) | ||||
| { | ||||
|     assert(!bs->peer); | ||||
|     assert(!bs->dev); | ||||
| 
 | ||||
|     /* remove from list, if necessary */ | ||||
|     bdrv_make_anon(bs); | ||||
| @ -769,26 +764,58 @@ void bdrv_delete(BlockDriverState *bs) | ||||
|     g_free(bs); | ||||
| } | ||||
| 
 | ||||
| int bdrv_attach(BlockDriverState *bs, DeviceState *qdev) | ||||
| int bdrv_attach_dev(BlockDriverState *bs, void *dev) | ||||
| /* TODO change to DeviceState *dev when all users are qdevified */ | ||||
| { | ||||
|     if (bs->peer) { | ||||
|     if (bs->dev) { | ||||
|         return -EBUSY; | ||||
|     } | ||||
|     bs->peer = qdev; | ||||
|     bs->dev = dev; | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void bdrv_detach(BlockDriverState *bs, DeviceState *qdev) | ||||
| /* TODO qdevified devices don't use this, remove when devices are qdevified */ | ||||
| void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev) | ||||
| { | ||||
|     assert(bs->peer == qdev); | ||||
|     bs->peer = NULL; | ||||
|     bs->change_cb = NULL; | ||||
|     bs->change_opaque = NULL; | ||||
|     if (bdrv_attach_dev(bs, dev) < 0) { | ||||
|         abort(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| DeviceState *bdrv_get_attached(BlockDriverState *bs) | ||||
| void bdrv_detach_dev(BlockDriverState *bs, void *dev) | ||||
| /* TODO change to DeviceState *dev when all users are qdevified */ | ||||
| { | ||||
|     return bs->peer; | ||||
|     assert(bs->dev == dev); | ||||
|     bs->dev = NULL; | ||||
|     bs->dev_ops = NULL; | ||||
|     bs->dev_opaque = NULL; | ||||
| } | ||||
| 
 | ||||
| /* TODO change to return DeviceState * when all users are qdevified */ | ||||
| void *bdrv_get_attached_dev(BlockDriverState *bs) | ||||
| { | ||||
|     return bs->dev; | ||||
| } | ||||
| 
 | ||||
| void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, | ||||
|                       void *opaque) | ||||
| { | ||||
|     bs->dev_ops = ops; | ||||
|     bs->dev_opaque = opaque; | ||||
| } | ||||
| 
 | ||||
| static void bdrv_dev_change_media_cb(BlockDriverState *bs) | ||||
| { | ||||
|     if (bs->dev_ops && bs->dev_ops->change_media_cb) { | ||||
|         bs->dev_ops->change_media_cb(bs->dev_opaque); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void bdrv_dev_resize_cb(BlockDriverState *bs) | ||||
| { | ||||
|     if (bs->dev_ops && bs->dev_ops->resize_cb) { | ||||
|         bs->dev_ops->resize_cb(bs->dev_opaque); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -1261,9 +1288,7 @@ int bdrv_truncate(BlockDriverState *bs, int64_t offset) | ||||
|     ret = drv->bdrv_truncate(bs, offset); | ||||
|     if (ret == 0) { | ||||
|         ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); | ||||
|         if (bs->change_cb) { | ||||
|             bs->change_cb(bs->change_opaque, CHANGE_SIZE); | ||||
|         } | ||||
|         bdrv_dev_resize_cb(bs); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| @ -1601,15 +1626,6 @@ int bdrv_enable_write_cache(BlockDriverState *bs) | ||||
|     return bs->enable_write_cache; | ||||
| } | ||||
| 
 | ||||
| /* XXX: no longer used */ | ||||
| void bdrv_set_change_cb(BlockDriverState *bs, | ||||
|                         void (*change_cb)(void *opaque, int reason), | ||||
|                         void *opaque) | ||||
| { | ||||
|     bs->change_cb = change_cb; | ||||
|     bs->change_opaque = opaque; | ||||
| } | ||||
| 
 | ||||
| int bdrv_is_encrypted(BlockDriverState *bs) | ||||
| { | ||||
|     if (bs->backing_hd && bs->backing_hd->encrypted) | ||||
| @ -1647,9 +1663,7 @@ int bdrv_set_key(BlockDriverState *bs, const char *key) | ||||
|     } else if (!bs->valid_key) { | ||||
|         bs->valid_key = 1; | ||||
|         /* call the change callback now, we skipped it on open */ | ||||
|         bs->media_changed = 1; | ||||
|         if (bs->change_cb) | ||||
|             bs->change_cb(bs->change_opaque, CHANGE_MEDIA); | ||||
|         bdrv_dev_change_media_cb(bs); | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| @ -1739,8 +1753,7 @@ void bdrv_flush_all(void) | ||||
|     BlockDriverState *bs; | ||||
| 
 | ||||
|     QTAILQ_FOREACH(bs, &bdrv_states, list) { | ||||
|         if (bs->drv && !bdrv_is_read_only(bs) && | ||||
|             (!bdrv_is_removable(bs) || bdrv_is_inserted(bs))) { | ||||
|         if (!bdrv_is_read_only(bs) && bdrv_is_inserted(bs)) { | ||||
|             bdrv_flush(bs); | ||||
|         } | ||||
|     } | ||||
| @ -2084,7 +2097,7 @@ void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event) | ||||
| int bdrv_can_snapshot(BlockDriverState *bs) | ||||
| { | ||||
|     BlockDriver *drv = bs->drv; | ||||
|     if (!drv || bdrv_is_removable(bs) || bdrv_is_read_only(bs)) { | ||||
|     if (!drv || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
| @ -3023,22 +3036,17 @@ int bdrv_is_inserted(BlockDriverState *bs) | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Return TRUE if the media changed since the last call to this | ||||
|  * function. It is currently only used for floppy disks | ||||
|  * Return whether the media changed since the last call to this | ||||
|  * function, or -ENOTSUP if we don't know.  Most drivers don't know. | ||||
|  */ | ||||
| int bdrv_media_changed(BlockDriverState *bs) | ||||
| { | ||||
|     BlockDriver *drv = bs->drv; | ||||
|     int ret; | ||||
| 
 | ||||
|     if (!drv || !drv->bdrv_media_changed) | ||||
|         ret = -ENOTSUP; | ||||
|     else | ||||
|         ret = drv->bdrv_media_changed(bs); | ||||
|     if (ret == -ENOTSUP) | ||||
|         ret = bs->media_changed; | ||||
|     bs->media_changed = 0; | ||||
|     return ret; | ||||
|     if (drv && drv->bdrv_media_changed) { | ||||
|         return drv->bdrv_media_changed(bs); | ||||
|     } | ||||
|     return -ENOTSUP; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | ||||
							
								
								
									
										28
									
								
								block.h
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								block.h
									
									
									
									
									
								
							| @ -28,6 +28,20 @@ typedef struct QEMUSnapshotInfo { | ||||
|     uint64_t vm_clock_nsec; /* VM clock relative to boot */ | ||||
| } QEMUSnapshotInfo; | ||||
| 
 | ||||
| /* Callbacks for block device models */ | ||||
| typedef struct BlockDevOps { | ||||
|     /*
 | ||||
|      * Runs when virtual media changed (monitor commands eject, change) | ||||
|      * Beware: doesn't run when a host device's physical media | ||||
|      * changes.  Sure would be useful if it did. | ||||
|      */ | ||||
|     void (*change_media_cb)(void *opaque); | ||||
|     /*
 | ||||
|      * Runs when the size changed (e.g. monitor command block_resize) | ||||
|      */ | ||||
|     void (*resize_cb)(void *opaque); | ||||
| } BlockDevOps; | ||||
| 
 | ||||
| #define BDRV_O_RDWR        0x0002 | ||||
| #define BDRV_O_SNAPSHOT    0x0008 /* open the file read only and save writes in a snapshot */ | ||||
| #define BDRV_O_NOCACHE     0x0020 /* do not use the host page cache */ | ||||
| @ -74,9 +88,12 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); | ||||
| int bdrv_open(BlockDriverState *bs, const char *filename, int flags, | ||||
|               BlockDriver *drv); | ||||
| void bdrv_close(BlockDriverState *bs); | ||||
| int bdrv_attach(BlockDriverState *bs, DeviceState *qdev); | ||||
| void bdrv_detach(BlockDriverState *bs, DeviceState *qdev); | ||||
| DeviceState *bdrv_get_attached(BlockDriverState *bs); | ||||
| int bdrv_attach_dev(BlockDriverState *bs, void *dev); | ||||
| void bdrv_attach_dev_nofail(BlockDriverState *bs, void *dev); | ||||
| void bdrv_detach_dev(BlockDriverState *bs, void *dev); | ||||
| void *bdrv_get_attached_dev(BlockDriverState *bs); | ||||
| void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops, | ||||
|                       void *opaque); | ||||
| int bdrv_read(BlockDriverState *bs, int64_t sector_num, | ||||
|               uint8_t *buf, int nb_sectors); | ||||
| int bdrv_write(BlockDriverState *bs, int64_t sector_num, | ||||
| @ -192,9 +209,6 @@ int bdrv_media_changed(BlockDriverState *bs); | ||||
| int bdrv_is_locked(BlockDriverState *bs); | ||||
| void bdrv_set_locked(BlockDriverState *bs, int locked); | ||||
| int bdrv_eject(BlockDriverState *bs, int eject_flag); | ||||
| void bdrv_set_change_cb(BlockDriverState *bs, | ||||
|                         void (*change_cb)(void *opaque, int reason), | ||||
|                         void *opaque); | ||||
| void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size); | ||||
| BlockDriverState *bdrv_find(const char *name); | ||||
| BlockDriverState *bdrv_next(BlockDriverState *bs); | ||||
| @ -244,6 +258,8 @@ int bdrv_img_create(const char *filename, const char *fmt, | ||||
|                     const char *base_filename, const char *base_fmt, | ||||
|                     char *options, uint64_t img_size, int flags); | ||||
| 
 | ||||
| void *qemu_blockalign(BlockDriverState *bs, size_t size); | ||||
| 
 | ||||
| #define BDRV_SECTORS_PER_DIRTY_CHUNK 2048 | ||||
| 
 | ||||
| void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable); | ||||
|  | ||||
| @ -526,13 +526,14 @@ static int qcow2_co_writev(BlockDriverState *bs, | ||||
|     int n_end; | ||||
|     int ret; | ||||
|     int cur_nr_sectors; /* number of sectors in current iteration */ | ||||
|     QCowL2Meta l2meta; | ||||
|     uint64_t cluster_offset; | ||||
|     QEMUIOVector hd_qiov; | ||||
|     uint64_t bytes_done = 0; | ||||
|     uint8_t *cluster_data = NULL; | ||||
|     QCowL2Meta l2meta = { | ||||
|         .nb_clusters = 0, | ||||
|     }; | ||||
| 
 | ||||
|     l2meta.nb_clusters = 0; | ||||
|     qemu_co_queue_init(&l2meta.dependent_requests); | ||||
| 
 | ||||
|     qemu_iovec_init(&hd_qiov, qiov->niov); | ||||
| @ -592,13 +593,12 @@ static int qcow2_co_writev(BlockDriverState *bs, | ||||
|         } | ||||
| 
 | ||||
|         ret = qcow2_alloc_cluster_link_l2(bs, &l2meta); | ||||
| 
 | ||||
|         run_dependent_requests(s, &l2meta); | ||||
| 
 | ||||
|         if (ret < 0) { | ||||
|             goto fail; | ||||
|         } | ||||
| 
 | ||||
|         run_dependent_requests(s, &l2meta); | ||||
| 
 | ||||
|         remaining_sectors -= cur_nr_sectors; | ||||
|         sector_num += cur_nr_sectors; | ||||
|         bytes_done += cur_nr_sectors * 512; | ||||
| @ -606,6 +606,8 @@ static int qcow2_co_writev(BlockDriverState *bs, | ||||
|     ret = 0; | ||||
| 
 | ||||
| fail: | ||||
|     run_dependent_requests(s, &l2meta); | ||||
| 
 | ||||
|     qemu_co_mutex_unlock(&s->lock); | ||||
| 
 | ||||
|     qemu_iovec_destroy(&hd_qiov); | ||||
|  | ||||
| @ -236,6 +236,10 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, | ||||
|     } | ||||
| 
 | ||||
| #ifdef CONFIG_LINUX_AIO | ||||
|     /*
 | ||||
|      * Currently Linux do AIO only for files opened with O_DIRECT | ||||
|      * specified so check NOCACHE flag too | ||||
|      */ | ||||
|     if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) == | ||||
|                       (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) { | ||||
| 
 | ||||
|  | ||||
| @ -75,6 +75,11 @@ static int raw_is_inserted(BlockDriverState *bs) | ||||
|     return bdrv_is_inserted(bs->file); | ||||
| } | ||||
| 
 | ||||
| static int raw_media_changed(BlockDriverState *bs) | ||||
| { | ||||
|     return bdrv_media_changed(bs->file); | ||||
| } | ||||
| 
 | ||||
| static void raw_eject(BlockDriverState *bs, int eject_flag) | ||||
| { | ||||
|     bdrv_eject(bs->file, eject_flag); | ||||
| @ -137,8 +142,10 @@ static BlockDriver bdrv_raw = { | ||||
|     .bdrv_discard       = raw_discard, | ||||
| 
 | ||||
|     .bdrv_is_inserted   = raw_is_inserted, | ||||
|     .bdrv_media_changed = raw_media_changed, | ||||
|     .bdrv_eject         = raw_eject, | ||||
|     .bdrv_set_locked    = raw_set_locked, | ||||
| 
 | ||||
|     .bdrv_ioctl         = raw_ioctl, | ||||
|     .bdrv_aio_ioctl     = raw_aio_ioctl, | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										348
									
								
								block/vmdk.c
									
									
									
									
									
								
							
							
						
						
									
										348
									
								
								block/vmdk.c
									
									
									
									
									
								
							| @ -26,9 +26,14 @@ | ||||
| #include "qemu-common.h" | ||||
| #include "block_int.h" | ||||
| #include "module.h" | ||||
| #include "zlib.h" | ||||
| 
 | ||||
| #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') | ||||
| #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') | ||||
| #define VMDK4_COMPRESSION_DEFLATE 1 | ||||
| #define VMDK4_FLAG_RGD (1 << 1) | ||||
| #define VMDK4_FLAG_COMPRESS (1 << 16) | ||||
| #define VMDK4_FLAG_MARKER (1 << 17) | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t version; | ||||
| @ -51,11 +56,12 @@ typedef struct { | ||||
|     int64_t desc_offset; | ||||
|     int64_t desc_size; | ||||
|     int32_t num_gtes_per_gte; | ||||
|     int64_t rgd_offset; | ||||
|     int64_t gd_offset; | ||||
|     int64_t rgd_offset; | ||||
|     int64_t grain_offset; | ||||
|     char filler[1]; | ||||
|     char check_bytes[4]; | ||||
|     uint16_t compressAlgorithm; | ||||
| } QEMU_PACKED VMDK4Header; | ||||
| 
 | ||||
| #define L2_CACHE_SIZE 16 | ||||
| @ -63,6 +69,8 @@ typedef struct { | ||||
| typedef struct VmdkExtent { | ||||
|     BlockDriverState *file; | ||||
|     bool flat; | ||||
|     bool compressed; | ||||
|     bool has_marker; | ||||
|     int64_t sectors; | ||||
|     int64_t end_sector; | ||||
|     int64_t flat_start_offset; | ||||
| @ -98,6 +106,12 @@ typedef struct VmdkMetaData { | ||||
|     int valid; | ||||
| } VmdkMetaData; | ||||
| 
 | ||||
| typedef struct VmdkGrainMarker { | ||||
|     uint64_t lba; | ||||
|     uint32_t size; | ||||
|     uint8_t  data[0]; | ||||
| } VmdkGrainMarker; | ||||
| 
 | ||||
| static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) | ||||
| { | ||||
|     uint32_t magic; | ||||
| @ -174,6 +188,17 @@ static void vmdk_free_extents(BlockDriverState *bs) | ||||
|     g_free(s->extents); | ||||
| } | ||||
| 
 | ||||
| static void vmdk_free_last_extent(BlockDriverState *bs) | ||||
| { | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
| 
 | ||||
|     if (s->num_extents == 0) { | ||||
|         return; | ||||
|     } | ||||
|     s->num_extents--; | ||||
|     s->extents = g_realloc(s->extents, s->num_extents * sizeof(VmdkExtent)); | ||||
| } | ||||
| 
 | ||||
| static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) | ||||
| { | ||||
|     char desc[DESC_SIZE]; | ||||
| @ -357,18 +382,18 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent) | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int vmdk_open_vmdk3(BlockDriverState *bs, int flags) | ||||
| static int vmdk_open_vmdk3(BlockDriverState *bs, | ||||
|                            BlockDriverState *file, | ||||
|                            int flags) | ||||
| { | ||||
|     int ret; | ||||
|     uint32_t magic; | ||||
|     VMDK3Header header; | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
|     VmdkExtent *extent; | ||||
| 
 | ||||
|     s->desc_offset = 0x200; | ||||
|     ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)); | ||||
|     ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); | ||||
|     if (ret < 0) { | ||||
|         goto fail; | ||||
|         return ret; | ||||
|     } | ||||
|     extent = vmdk_add_extent(bs, | ||||
|                              bs->file, false, | ||||
| @ -378,58 +403,58 @@ static int vmdk_open_vmdk3(BlockDriverState *bs, int flags) | ||||
|                              le32_to_cpu(header.granularity)); | ||||
|     ret = vmdk_init_tables(bs, extent); | ||||
|     if (ret) { | ||||
|         /* vmdk_init_tables cleans up on fail, so only free allocation of
 | ||||
|          * vmdk_add_extent here. */ | ||||
|         goto fail; | ||||
|         /* free extent allocated by vmdk_add_extent */ | ||||
|         vmdk_free_last_extent(bs); | ||||
|     } | ||||
|     return 0; | ||||
|  fail: | ||||
|     vmdk_free_extents(bs); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int vmdk_open_vmdk4(BlockDriverState *bs, int flags) | ||||
| static int vmdk_open_desc_file(BlockDriverState *bs, int flags, | ||||
|                                int64_t desc_offset); | ||||
| 
 | ||||
| static int vmdk_open_vmdk4(BlockDriverState *bs, | ||||
|                            BlockDriverState *file, | ||||
|                            int flags) | ||||
| { | ||||
|     int ret; | ||||
|     uint32_t magic; | ||||
|     uint32_t l1_size, l1_entry_sectors; | ||||
|     VMDK4Header header; | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
|     VmdkExtent *extent; | ||||
|     int64_t l1_backup_offset = 0; | ||||
| 
 | ||||
|     s->desc_offset = 0x200; | ||||
|     ret = bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)); | ||||
|     ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); | ||||
|     if (ret < 0) { | ||||
|         goto fail; | ||||
|         return ret; | ||||
|     } | ||||
|     if (header.capacity == 0 && header.desc_offset) { | ||||
|         return vmdk_open_desc_file(bs, flags, header.desc_offset << 9); | ||||
|     } | ||||
|     l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte) | ||||
|                         * le64_to_cpu(header.granularity); | ||||
|     if (l1_entry_sectors <= 0) { | ||||
|         return -EINVAL; | ||||
|     } | ||||
|     l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) | ||||
|                 / l1_entry_sectors; | ||||
|     extent = vmdk_add_extent(bs, bs->file, false, | ||||
|     if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { | ||||
|         l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; | ||||
|     } | ||||
|     extent = vmdk_add_extent(bs, file, false, | ||||
|                           le64_to_cpu(header.capacity), | ||||
|                           le64_to_cpu(header.gd_offset) << 9, | ||||
|                           le64_to_cpu(header.rgd_offset) << 9, | ||||
|                           l1_backup_offset, | ||||
|                           l1_size, | ||||
|                           le32_to_cpu(header.num_gtes_per_gte), | ||||
|                           le64_to_cpu(header.granularity)); | ||||
|     if (extent->l1_entry_sectors <= 0) { | ||||
|         ret = -EINVAL; | ||||
|         goto fail; | ||||
|     } | ||||
|     /* try to open parent images, if exist */ | ||||
|     ret = vmdk_parent_open(bs); | ||||
|     if (ret) { | ||||
|         goto fail; | ||||
|     } | ||||
|     s->parent_cid = vmdk_read_cid(bs, 1); | ||||
|     extent->compressed = | ||||
|         le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; | ||||
|     extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; | ||||
|     ret = vmdk_init_tables(bs, extent); | ||||
|     if (ret) { | ||||
|         goto fail; | ||||
|         /* free extent allocated by vmdk_add_extent */ | ||||
|         vmdk_free_last_extent(bs); | ||||
|     } | ||||
|     return 0; | ||||
|  fail: | ||||
|     vmdk_free_extents(bs); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| @ -460,6 +485,31 @@ static int vmdk_parse_description(const char *desc, const char *opt_name, | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| /* Open an extent file and append to bs array */ | ||||
| static int vmdk_open_sparse(BlockDriverState *bs, | ||||
|                             BlockDriverState *file, | ||||
|                             int flags) | ||||
| { | ||||
|     uint32_t magic; | ||||
| 
 | ||||
|     if (bdrv_pread(file, 0, &magic, sizeof(magic)) != sizeof(magic)) { | ||||
|         return -EIO; | ||||
|     } | ||||
| 
 | ||||
|     magic = be32_to_cpu(magic); | ||||
|     switch (magic) { | ||||
|         case VMDK3_MAGIC: | ||||
|             return vmdk_open_vmdk3(bs, file, flags); | ||||
|             break; | ||||
|         case VMDK4_MAGIC: | ||||
|             return vmdk_open_vmdk4(bs, file, flags); | ||||
|             break; | ||||
|         default: | ||||
|             return -EINVAL; | ||||
|             break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|         const char *desc_file_path) | ||||
| { | ||||
| @ -470,6 +520,8 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|     const char *p = desc; | ||||
|     int64_t sectors = 0; | ||||
|     int64_t flat_offset; | ||||
|     char extent_path[PATH_MAX]; | ||||
|     BlockDriverState *extent_file; | ||||
| 
 | ||||
|     while (*p) { | ||||
|         /* parse extent line:
 | ||||
| @ -504,24 +556,29 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, | ||||
|             goto next_line; | ||||
|         } | ||||
| 
 | ||||
|         path_combine(extent_path, sizeof(extent_path), | ||||
|                 desc_file_path, fname); | ||||
|         ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags); | ||||
|         if (ret) { | ||||
|             return ret; | ||||
|         } | ||||
| 
 | ||||
|         /* save to extents array */ | ||||
|         if (!strcmp(type, "FLAT")) { | ||||
|             /* FLAT extent */ | ||||
|             char extent_path[PATH_MAX]; | ||||
|             BlockDriverState *extent_file; | ||||
|             VmdkExtent *extent; | ||||
| 
 | ||||
|             path_combine(extent_path, sizeof(extent_path), | ||||
|                     desc_file_path, fname); | ||||
|             ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags); | ||||
|             if (ret) { | ||||
|                 return ret; | ||||
|             } | ||||
|             extent = vmdk_add_extent(bs, extent_file, true, sectors, | ||||
|                             0, 0, 0, 0, sectors); | ||||
|             extent->flat_start_offset = flat_offset; | ||||
|             extent->flat_start_offset = flat_offset << 9; | ||||
|         } else if (!strcmp(type, "SPARSE")) { | ||||
|             /* SPARSE extent */ | ||||
|             ret = vmdk_open_sparse(bs, extent_file, bs->open_flags); | ||||
|             if (ret) { | ||||
|                 bdrv_delete(extent_file); | ||||
|                 return ret; | ||||
|             } | ||||
|         } else { | ||||
|             /* SPARSE extent, not supported for now */ | ||||
|             fprintf(stderr, | ||||
|                 "VMDK: Not supported extent type \"%s\""".\n", type); | ||||
|             return -ENOTSUP; | ||||
| @ -536,14 +593,15 @@ next_line: | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static int vmdk_open_desc_file(BlockDriverState *bs, int flags) | ||||
| static int vmdk_open_desc_file(BlockDriverState *bs, int flags, | ||||
|                                int64_t desc_offset) | ||||
| { | ||||
|     int ret; | ||||
|     char buf[2048]; | ||||
|     char ct[128]; | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
| 
 | ||||
|     ret = bdrv_pread(bs->file, 0, buf, sizeof(buf)); | ||||
|     ret = bdrv_pread(bs->file, desc_offset, buf, sizeof(buf)); | ||||
|     if (ret < 0) { | ||||
|         return ret; | ||||
|     } | ||||
| @ -551,7 +609,9 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags) | ||||
|     if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { | ||||
|         return -EINVAL; | ||||
|     } | ||||
|     if (strcmp(ct, "monolithicFlat")) { | ||||
|     if (strcmp(ct, "monolithicFlat") && | ||||
|         strcmp(ct, "twoGbMaxExtentSparse") && | ||||
|         strcmp(ct, "twoGbMaxExtentFlat")) { | ||||
|         fprintf(stderr, | ||||
|                 "VMDK: Not supported image type \"%s\""".\n", ct); | ||||
|         return -ENOTSUP; | ||||
| @ -573,19 +633,21 @@ static int vmdk_open_desc_file(BlockDriverState *bs, int flags) | ||||
| 
 | ||||
| static int vmdk_open(BlockDriverState *bs, int flags) | ||||
| { | ||||
|     uint32_t magic; | ||||
|     int ret; | ||||
|     BDRVVmdkState *s = bs->opaque; | ||||
| 
 | ||||
|     if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) { | ||||
|         return -EIO; | ||||
|     } | ||||
| 
 | ||||
|     magic = be32_to_cpu(magic); | ||||
|     if (magic == VMDK3_MAGIC) { | ||||
|         return vmdk_open_vmdk3(bs, flags); | ||||
|     } else if (magic == VMDK4_MAGIC) { | ||||
|         return vmdk_open_vmdk4(bs, flags); | ||||
|     if (vmdk_open_sparse(bs, bs->file, flags) == 0) { | ||||
|         s->desc_offset = 0x200; | ||||
|         /* try to open parent images, if exist */ | ||||
|         ret = vmdk_parent_open(bs); | ||||
|         if (ret) { | ||||
|             vmdk_free_extents(bs); | ||||
|             return ret; | ||||
|         } | ||||
|         s->parent_cid = vmdk_read_cid(bs, 1); | ||||
|         return 0; | ||||
|     } else { | ||||
|         return vmdk_open_desc_file(bs, flags); | ||||
|         return vmdk_open_desc_file(bs, flags, 0); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -672,6 +734,7 @@ static int get_cluster_offset(BlockDriverState *bs, | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE; | ||||
|     l1_index = (offset >> 9) / extent->l1_entry_sectors; | ||||
|     if (l1_index >= extent->l1_size) { | ||||
|         return -1; | ||||
| @ -724,10 +787,12 @@ static int get_cluster_offset(BlockDriverState *bs, | ||||
| 
 | ||||
|         /* Avoid the L2 tables update for the images that have snapshots. */ | ||||
|         *cluster_offset = bdrv_getlength(extent->file); | ||||
|         bdrv_truncate( | ||||
|             extent->file, | ||||
|             *cluster_offset + (extent->cluster_sectors << 9) | ||||
|         ); | ||||
|         if (!extent->compressed) { | ||||
|             bdrv_truncate( | ||||
|                 extent->file, | ||||
|                 *cluster_offset + (extent->cluster_sectors << 9) | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         *cluster_offset >>= 9; | ||||
|         tmp = cpu_to_le32(*cluster_offset); | ||||
| @ -798,6 +863,113 @@ static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, | ||||
|                             int64_t offset_in_cluster, const uint8_t *buf, | ||||
|                             int nb_sectors, int64_t sector_num) | ||||
| { | ||||
|     int ret; | ||||
|     VmdkGrainMarker *data = NULL; | ||||
|     uLongf buf_len; | ||||
|     const uint8_t *write_buf = buf; | ||||
|     int write_len = nb_sectors * 512; | ||||
| 
 | ||||
|     if (extent->compressed) { | ||||
|         if (!extent->has_marker) { | ||||
|             ret = -EINVAL; | ||||
|             goto out; | ||||
|         } | ||||
|         buf_len = (extent->cluster_sectors << 9) * 2; | ||||
|         data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); | ||||
|         if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK || | ||||
|                 buf_len == 0) { | ||||
|             ret = -EINVAL; | ||||
|             goto out; | ||||
|         } | ||||
|         data->lba = sector_num; | ||||
|         data->size = buf_len; | ||||
|         write_buf = (uint8_t *)data; | ||||
|         write_len = buf_len + sizeof(VmdkGrainMarker); | ||||
|     } | ||||
|     ret = bdrv_pwrite(extent->file, | ||||
|                         cluster_offset + offset_in_cluster, | ||||
|                         write_buf, | ||||
|                         write_len); | ||||
|     if (ret != write_len) { | ||||
|         ret = ret < 0 ? ret : -EIO; | ||||
|         goto out; | ||||
|     } | ||||
|     ret = 0; | ||||
|  out: | ||||
|     g_free(data); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, | ||||
|                             int64_t offset_in_cluster, uint8_t *buf, | ||||
|                             int nb_sectors) | ||||
| { | ||||
|     int ret; | ||||
|     int cluster_bytes, buf_bytes; | ||||
|     uint8_t *cluster_buf, *compressed_data; | ||||
|     uint8_t *uncomp_buf; | ||||
|     uint32_t data_len; | ||||
|     VmdkGrainMarker *marker; | ||||
|     uLongf buf_len; | ||||
| 
 | ||||
| 
 | ||||
|     if (!extent->compressed) { | ||||
|         ret = bdrv_pread(extent->file, | ||||
|                           cluster_offset + offset_in_cluster, | ||||
|                           buf, nb_sectors * 512); | ||||
|         if (ret == nb_sectors * 512) { | ||||
|             return 0; | ||||
|         } else { | ||||
|             return -EIO; | ||||
|         } | ||||
|     } | ||||
|     cluster_bytes = extent->cluster_sectors * 512; | ||||
|     /* Read two clusters in case GrainMarker + compressed data > one cluster */ | ||||
|     buf_bytes = cluster_bytes * 2; | ||||
|     cluster_buf = g_malloc(buf_bytes); | ||||
|     uncomp_buf = g_malloc(cluster_bytes); | ||||
|     ret = bdrv_pread(extent->file, | ||||
|                 cluster_offset, | ||||
|                 cluster_buf, buf_bytes); | ||||
|     if (ret < 0) { | ||||
|         goto out; | ||||
|     } | ||||
|     compressed_data = cluster_buf; | ||||
|     buf_len = cluster_bytes; | ||||
|     data_len = cluster_bytes; | ||||
|     if (extent->has_marker) { | ||||
|         marker = (VmdkGrainMarker *)cluster_buf; | ||||
|         compressed_data = marker->data; | ||||
|         data_len = le32_to_cpu(marker->size); | ||||
|     } | ||||
|     if (!data_len || data_len > buf_bytes) { | ||||
|         ret = -EINVAL; | ||||
|         goto out; | ||||
|     } | ||||
|     ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len); | ||||
|     if (ret != Z_OK) { | ||||
|         ret = -EINVAL; | ||||
|         goto out; | ||||
| 
 | ||||
|     } | ||||
|     if (offset_in_cluster < 0 || | ||||
|             offset_in_cluster + nb_sectors * 512 > buf_len) { | ||||
|         ret = -EINVAL; | ||||
|         goto out; | ||||
|     } | ||||
|     memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512); | ||||
|     ret = 0; | ||||
| 
 | ||||
|  out: | ||||
|     g_free(uncomp_buf); | ||||
|     g_free(cluster_buf); | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static int vmdk_read(BlockDriverState *bs, int64_t sector_num, | ||||
|                     uint8_t *buf, int nb_sectors) | ||||
| { | ||||
| @ -834,10 +1006,10 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, | ||||
|                 memset(buf, 0, 512 * n); | ||||
|             } | ||||
|         } else { | ||||
|             ret = bdrv_pread(extent->file, | ||||
|                             cluster_offset + index_in_cluster * 512, | ||||
|                             buf, n * 512); | ||||
|             if (ret < 0) { | ||||
|             ret = vmdk_read_extent(extent, | ||||
|                             cluster_offset, index_in_cluster * 512, | ||||
|                             buf, n); | ||||
|             if (ret) { | ||||
|                 return ret; | ||||
|             } | ||||
|         } | ||||
| @ -875,8 +1047,25 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, | ||||
|                                 bs, | ||||
|                                 extent, | ||||
|                                 &m_data, | ||||
|                                 sector_num << 9, 1, | ||||
|                                 sector_num << 9, !extent->compressed, | ||||
|                                 &cluster_offset); | ||||
|         if (extent->compressed) { | ||||
|             if (ret == 0) { | ||||
|                 /* Refuse write to allocated cluster for streamOptimized */ | ||||
|                 fprintf(stderr, | ||||
|                         "VMDK: can't write to allocated cluster" | ||||
|                         " for streamOptimized\n"); | ||||
|                 return -EIO; | ||||
|             } else { | ||||
|                 /* allocate */ | ||||
|                 ret = get_cluster_offset( | ||||
|                                         bs, | ||||
|                                         extent, | ||||
|                                         &m_data, | ||||
|                                         sector_num << 9, 1, | ||||
|                                         &cluster_offset); | ||||
|             } | ||||
|         } | ||||
|         if (ret) { | ||||
|             return -EINVAL; | ||||
|         } | ||||
| @ -886,11 +1075,10 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, | ||||
|             n = nb_sectors; | ||||
|         } | ||||
| 
 | ||||
|         ret = bdrv_pwrite(extent->file, | ||||
|                         cluster_offset + index_in_cluster * 512, | ||||
|                         buf, | ||||
|                         n * 512); | ||||
|         if (ret < 0) { | ||||
|         ret = vmdk_write_extent(extent, | ||||
|                         cluster_offset, index_in_cluster * 512, | ||||
|                         buf, n, sector_num); | ||||
|         if (ret) { | ||||
|             return ret; | ||||
|         } | ||||
|         if (m_data.valid) { | ||||
| @ -914,7 +1102,8 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat) | ||||
| static int vmdk_create_extent(const char *filename, int64_t filesize, | ||||
|                               bool flat, bool compress) | ||||
| { | ||||
|     int ret, i; | ||||
|     int fd = 0; | ||||
| @ -938,7 +1127,9 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat) | ||||
|     magic = cpu_to_be32(VMDK4_MAGIC); | ||||
|     memset(&header, 0, sizeof(header)); | ||||
|     header.version = 1; | ||||
|     header.flags = 3; /* ?? */ | ||||
|     header.flags = | ||||
|         3 | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0); | ||||
|     header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; | ||||
|     header.capacity = filesize / 512; | ||||
|     header.granularity = 128; | ||||
|     header.num_gtes_per_gte = 512; | ||||
| @ -968,6 +1159,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize, bool flat) | ||||
|     header.rgd_offset = cpu_to_le64(header.rgd_offset); | ||||
|     header.gd_offset = cpu_to_le64(header.gd_offset); | ||||
|     header.grain_offset = cpu_to_le64(header.grain_offset); | ||||
|     header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm); | ||||
| 
 | ||||
|     header.check_bytes[0] = 0xa; | ||||
|     header.check_bytes[1] = 0x20; | ||||
| @ -1109,7 +1301,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) | ||||
|     const char *fmt = NULL; | ||||
|     int flags = 0; | ||||
|     int ret = 0; | ||||
|     bool flat, split; | ||||
|     bool flat, split, compress; | ||||
|     char ext_desc_lines[BUF_SIZE] = ""; | ||||
|     char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX]; | ||||
|     const int64_t split_size = 0x80000000;  /* VMDK has constant split size */ | ||||
| @ -1158,7 +1350,8 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) | ||||
|     } else if (strcmp(fmt, "monolithicFlat") && | ||||
|                strcmp(fmt, "monolithicSparse") && | ||||
|                strcmp(fmt, "twoGbMaxExtentSparse") && | ||||
|                strcmp(fmt, "twoGbMaxExtentFlat")) { | ||||
|                strcmp(fmt, "twoGbMaxExtentFlat") && | ||||
|                strcmp(fmt, "streamOptimized")) { | ||||
|         fprintf(stderr, "VMDK: Unknown subformat: %s\n", fmt); | ||||
|         return -EINVAL; | ||||
|     } | ||||
| @ -1166,6 +1359,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) | ||||
|               strcmp(fmt, "twoGbMaxExtentSparse")); | ||||
|     flat = !(strcmp(fmt, "monolithicFlat") && | ||||
|              strcmp(fmt, "twoGbMaxExtentFlat")); | ||||
|     compress = !strcmp(fmt, "streamOptimized"); | ||||
|     if (flat) { | ||||
|         desc_extent_line = "RW %lld FLAT \"%s\" 0\n"; | ||||
|     } else { | ||||
| @ -1220,7 +1414,7 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) | ||||
|         snprintf(ext_filename, sizeof(ext_filename), "%s%s", | ||||
|                 path, desc_filename); | ||||
| 
 | ||||
|         if (vmdk_create_extent(ext_filename, size, flat)) { | ||||
|         if (vmdk_create_extent(ext_filename, size, flat, compress)) { | ||||
|             return -EINVAL; | ||||
|         } | ||||
|         filesize -= size; | ||||
| @ -1334,7 +1528,7 @@ static QEMUOptionParameter vmdk_create_options[] = { | ||||
|         .type = OPT_STRING, | ||||
|         .help = | ||||
|             "VMDK flat extent format, can be one of " | ||||
|             "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat} " | ||||
|             "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " | ||||
|     }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
							
								
								
									
										14
									
								
								block_int.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								block_int.h
									
									
									
									
									
								
							| @ -161,21 +161,20 @@ struct BlockDriverState { | ||||
|     int encrypted; /* if true, the media is encrypted */ | ||||
|     int valid_key; /* if true, a valid encryption key has been set */ | ||||
|     int sg;        /* if true, the device is a /dev/sg* */ | ||||
|     /* event callback when inserting/removing */ | ||||
|     void (*change_cb)(void *opaque, int reason); | ||||
|     void *change_opaque; | ||||
| 
 | ||||
|     BlockDriver *drv; /* NULL means no media */ | ||||
|     void *opaque; | ||||
| 
 | ||||
|     DeviceState *peer; | ||||
|     void *dev;                  /* attached device model, if any */ | ||||
|     /* TODO change to DeviceState when all users are qdevified */ | ||||
|     const BlockDevOps *dev_ops; | ||||
|     void *dev_opaque; | ||||
| 
 | ||||
|     char filename[1024]; | ||||
|     char backing_file[1024]; /* if non zero, the image is a diff of
 | ||||
|                                 this file image */ | ||||
|     char backing_format[16]; /* if non-zero and backing_file exists */ | ||||
|     int is_temporary; | ||||
|     int media_changed; | ||||
| 
 | ||||
|     BlockDriverState *backing_hd; | ||||
|     BlockDriverState *file; | ||||
| @ -211,9 +210,6 @@ struct BlockDriverState { | ||||
|     void *private; | ||||
| }; | ||||
| 
 | ||||
| #define CHANGE_MEDIA    0x01 | ||||
| #define CHANGE_SIZE     0x02 | ||||
| 
 | ||||
| struct BlockDriverAIOCB { | ||||
|     AIOPool *pool; | ||||
|     BlockDriverState *bs; | ||||
| @ -228,8 +224,6 @@ void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs, | ||||
|                    BlockDriverCompletionFunc *cb, void *opaque); | ||||
| void qemu_aio_release(void *p); | ||||
| 
 | ||||
| void *qemu_blockalign(BlockDriverState *bs, size_t size); | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| int is_windows_drive(const char *filename); | ||||
| #endif | ||||
|  | ||||
| @ -14,7 +14,6 @@ | ||||
| #include "qemu-option.h" | ||||
| #include "qemu-config.h" | ||||
| #include "sysemu.h" | ||||
| #include "hw/qdev.h" | ||||
| #include "block_int.h" | ||||
| 
 | ||||
| static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); | ||||
| @ -738,12 +737,12 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data) | ||||
|     bdrv_flush(bs); | ||||
|     bdrv_close(bs); | ||||
| 
 | ||||
|     /* if we have a device associated with this BlockDriverState (bs->peer)
 | ||||
|     /* if we have a device attached to this BlockDriverState
 | ||||
|      * then we need to make the drive anonymous until the device | ||||
|      * can be removed.  If this is a drive with no device backing | ||||
|      * then we can just get rid of the block driver state right here. | ||||
|      */ | ||||
|     if (bs->peer) { | ||||
|     if (bdrv_get_attached_dev(bs)) { | ||||
|         bdrv_make_anon(bs); | ||||
|     } else { | ||||
|         drive_uninit(drive_get_by_blockdev(bs)); | ||||
|  | ||||
							
								
								
									
										46
									
								
								hw/fdc.c
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								hw/fdc.c
									
									
									
									
									
								
							| @ -535,30 +535,11 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = { | ||||
|     NULL, | ||||
| }; | ||||
| 
 | ||||
| static void fdrive_media_changed_pre_save(void *opaque) | ||||
| { | ||||
|     FDrive *drive = opaque; | ||||
| 
 | ||||
|     drive->media_changed = drive->bs->media_changed; | ||||
| } | ||||
| 
 | ||||
| static int fdrive_media_changed_post_load(void *opaque, int version_id) | ||||
| { | ||||
|     FDrive *drive = opaque; | ||||
| 
 | ||||
|     if (drive->bs != NULL) { | ||||
|         drive->bs->media_changed = drive->media_changed; | ||||
|     } | ||||
| 
 | ||||
|     /* User ejected the floppy when drive->bs == NULL */ | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static bool fdrive_media_changed_needed(void *opaque) | ||||
| { | ||||
|     FDrive *drive = opaque; | ||||
| 
 | ||||
|     return (drive->bs != NULL && drive->bs->media_changed != 1); | ||||
|     return (drive->bs != NULL && drive->media_changed != 1); | ||||
| } | ||||
| 
 | ||||
| static const VMStateDescription vmstate_fdrive_media_changed = { | ||||
| @ -566,8 +547,6 @@ static const VMStateDescription vmstate_fdrive_media_changed = { | ||||
|     .version_id = 1, | ||||
|     .minimum_version_id = 1, | ||||
|     .minimum_version_id_old = 1, | ||||
|     .pre_save = fdrive_media_changed_pre_save, | ||||
|     .post_load = fdrive_media_changed_post_load, | ||||
|     .fields      = (VMStateField[]) { | ||||
|         VMSTATE_UINT8(media_changed, FDrive), | ||||
|         VMSTATE_END_OF_LIST() | ||||
| @ -919,7 +898,15 @@ static int fdctrl_media_changed(FDrive *drv) | ||||
| 
 | ||||
|     if (!drv->bs) | ||||
|         return 0; | ||||
|     ret = bdrv_media_changed(drv->bs); | ||||
|     if (drv->media_changed) { | ||||
|         drv->media_changed = 0; | ||||
|         ret = 1; | ||||
|     } else { | ||||
|         ret = bdrv_media_changed(drv->bs); | ||||
|         if (ret < 0) { | ||||
|             ret = 0;            /* we don't know, assume no */ | ||||
|         } | ||||
|     } | ||||
|     if (ret) { | ||||
|         fd_revalidate(drv); | ||||
|     } | ||||
| @ -1791,6 +1778,17 @@ static void fdctrl_result_timer(void *opaque) | ||||
|     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00); | ||||
| } | ||||
| 
 | ||||
| static void fdctrl_change_cb(void *opaque) | ||||
| { | ||||
|     FDrive *drive = opaque; | ||||
| 
 | ||||
|     drive->media_changed = 1; | ||||
| } | ||||
| 
 | ||||
| static const BlockDevOps fdctrl_block_ops = { | ||||
|     .change_media_cb = fdctrl_change_cb, | ||||
| }; | ||||
| 
 | ||||
| /* Init functions */ | ||||
| static int fdctrl_connect_drives(FDCtrl *fdctrl) | ||||
| { | ||||
| @ -1814,7 +1812,9 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl) | ||||
|         fd_init(drive); | ||||
|         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); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
|  | ||||
| @ -783,15 +783,11 @@ static void ide_cfata_metadata_write(IDEState *s) | ||||
| } | ||||
| 
 | ||||
| /* called when the inserted state of the media has changed */ | ||||
| static void cdrom_change_cb(void *opaque, int reason) | ||||
| static void ide_cd_change_cb(void *opaque) | ||||
| { | ||||
|     IDEState *s = opaque; | ||||
|     uint64_t nb_sectors; | ||||
| 
 | ||||
|     if (!(reason & CHANGE_MEDIA)) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     bdrv_get_geometry(s->bs, &nb_sectors); | ||||
|     s->nb_sectors = nb_sectors; | ||||
| 
 | ||||
| @ -983,7 +979,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|         s->status = READY_STAT | SEEK_STAT; | ||||
|         ide_set_irq(s->bus); | ||||
|         break; | ||||
| 	case WIN_READ_EXT: | ||||
|     case WIN_READ_EXT: | ||||
| 	lba48 = 1; | ||||
|     case WIN_READ: | ||||
|     case WIN_READ_ONCE: | ||||
| @ -993,7 +989,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|         s->req_nb_sectors = 1; | ||||
|         ide_sector_read(s); | ||||
|         break; | ||||
| 	case WIN_WRITE_EXT: | ||||
|     case WIN_WRITE_EXT: | ||||
| 	lba48 = 1; | ||||
|     case WIN_WRITE: | ||||
|     case WIN_WRITE_ONCE: | ||||
| @ -1006,7 +1002,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|         ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); | ||||
|         s->media_changed = 1; | ||||
|         break; | ||||
| 	case WIN_MULTREAD_EXT: | ||||
|     case WIN_MULTREAD_EXT: | ||||
| 	lba48 = 1; | ||||
|     case WIN_MULTREAD: | ||||
|         if (!s->mult_sectors) | ||||
| @ -1031,7 +1027,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|         ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); | ||||
|         s->media_changed = 1; | ||||
|         break; | ||||
| 	case WIN_READDMA_EXT: | ||||
|     case WIN_READDMA_EXT: | ||||
| 	lba48 = 1; | ||||
|     case WIN_READDMA: | ||||
|     case WIN_READDMA_ONCE: | ||||
| @ -1040,7 +1036,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
| 	ide_cmd_lba48_transform(s, lba48); | ||||
|         ide_sector_start_dma(s, IDE_DMA_READ); | ||||
|         break; | ||||
| 	case WIN_WRITEDMA_EXT: | ||||
|     case WIN_WRITEDMA_EXT: | ||||
| 	lba48 = 1; | ||||
|     case WIN_WRITEDMA: | ||||
|     case WIN_WRITEDMA_ONCE: | ||||
| @ -1133,7 +1129,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|     case WIN_STANDBYNOW1: | ||||
|     case WIN_STANDBYNOW2: | ||||
|     case WIN_IDLEIMMEDIATE: | ||||
|     case CFA_IDLEIMMEDIATE: | ||||
|     case WIN_IDLEIMMEDIATE2: | ||||
|     case WIN_SETIDLE1: | ||||
|     case WIN_SETIDLE2: | ||||
|     case WIN_SLEEPNOW1: | ||||
| @ -1172,7 +1168,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|                           */ | ||||
|         ide_set_irq(s->bus); | ||||
|         break; | ||||
|     case WIN_SRST: | ||||
|     case WIN_DEVICE_RESET: | ||||
|         if (s->drive_kind != IDE_CD) | ||||
|             goto abort_cmd; | ||||
|         ide_set_signature(s); | ||||
| @ -1265,7 +1261,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) | ||||
|         ide_set_irq(s->bus); | ||||
|         break; | ||||
| 
 | ||||
| 	case WIN_SMART: | ||||
|     case WIN_SMART: | ||||
| 	if (s->drive_kind == IDE_CD) | ||||
| 		goto abort_cmd; | ||||
| 	if (s->hcyl != 0xc2 || s->lcyl != 0x4f) | ||||
| @ -1742,6 +1738,10 @@ void ide_bus_reset(IDEBus *bus) | ||||
|     bus->dma->ops->reset(bus->dma); | ||||
| } | ||||
| 
 | ||||
| static const BlockDevOps ide_cd_block_ops = { | ||||
|     .change_media_cb = ide_cd_change_cb, | ||||
| }; | ||||
| 
 | ||||
| int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, | ||||
|                    const char *version, const char *serial) | ||||
| { | ||||
| @ -1776,7 +1776,7 @@ int ide_init_drive(IDEState *s, BlockDriverState *bs, IDEDriveKind kind, | ||||
|     s->smart_errors = 0; | ||||
|     s->smart_selftest_count = 0; | ||||
|     if (kind == IDE_CD) { | ||||
|         bdrv_set_change_cb(bs, cdrom_change_cb, s); | ||||
|         bdrv_set_dev_ops(bs, &ide_cd_block_ops, s); | ||||
|         bs->buffer_alignment = 2048; | ||||
|     } else { | ||||
|         if (!bdrv_is_inserted(s->bs)) { | ||||
| @ -1890,6 +1890,7 @@ void ide_init2_with_non_qdev_drives(IDEBus *bus, DriveInfo *hd0, | ||||
|                 error_report("Can't set up IDE drive %s", dinfo->id); | ||||
|                 exit(1); | ||||
|             } | ||||
|             bdrv_attach_dev_nofail(dinfo->bdrv, &bus->ifs[i]); | ||||
|         } else { | ||||
|             ide_reset(&bus->ifs[i]); | ||||
|         } | ||||
| @ -2009,7 +2010,7 @@ static bool ide_error_needed(void *opaque) | ||||
| } | ||||
| 
 | ||||
| /* Fields for GET_EVENT_STATUS_NOTIFICATION ATAPI command */ | ||||
| const VMStateDescription vmstate_ide_atapi_gesn_state = { | ||||
| static const VMStateDescription vmstate_ide_atapi_gesn_state = { | ||||
|     .name ="ide_drive/atapi/gesn_state", | ||||
|     .version_id = 1, | ||||
|     .minimum_version_id = 1, | ||||
| @ -2021,7 +2022,7 @@ const VMStateDescription vmstate_ide_atapi_gesn_state = { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const VMStateDescription vmstate_ide_drive_pio_state = { | ||||
| static const VMStateDescription vmstate_ide_drive_pio_state = { | ||||
|     .name = "ide_drive/pio_state", | ||||
|     .version_id = 1, | ||||
|     .minimum_version_id = 1, | ||||
| @ -2083,7 +2084,7 @@ const VMStateDescription vmstate_ide_drive = { | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| const VMStateDescription vmstate_ide_error_status = { | ||||
| static const VMStateDescription vmstate_ide_error_status = { | ||||
|     .name ="ide_bus/error", | ||||
|     .version_id = 1, | ||||
|     .minimum_version_id = 1, | ||||
|  | ||||
| @ -55,111 +55,120 @@ typedef struct IDEDMAOps IDEDMAOps; | ||||
| #define IDE_CMD_RESET           0x04 | ||||
| #define IDE_CMD_DISABLE_IRQ     0x02 | ||||
| 
 | ||||
| /* ATA/ATAPI Commands pre T13 Spec */ | ||||
| /* ACS-2 T13/2015-D Table B.2 Command codes */ | ||||
| #define WIN_NOP				0x00 | ||||
| /*
 | ||||
|  *	0x01->0x02 Reserved | ||||
|  */ | ||||
| /* reserved                             0x01..0x02 */ | ||||
| #define CFA_REQ_EXT_ERROR_CODE		0x03 /* CFA Request Extended Error Code */ | ||||
| /*
 | ||||
|  *      0x04->0x05 Reserved | ||||
|  */ | ||||
| /* reserved                             0x04..0x05 */ | ||||
| #define WIN_DSM                         0x06 | ||||
| /*
 | ||||
|  *      0x07 Reserved | ||||
|  */ | ||||
| #define WIN_SRST			0x08 /* ATAPI soft reset command */ | ||||
| /* reserved                             0x07 */ | ||||
| #define WIN_DEVICE_RESET		0x08 | ||||
| /*
 | ||||
|  *	0x09->0x0F Reserved | ||||
|  */ | ||||
| #define WIN_RECAL			0x10 | ||||
| #define WIN_RESTORE			WIN_RECAL | ||||
| /*
 | ||||
|  *	0x10->0x1F Reserved | ||||
|  */ | ||||
| /* reserved                             0x09..0x0a */ | ||||
| /* REQUEST SENSE DATA EXT               0x0B */ | ||||
| /* reserved                             0x0C..0x0F */ | ||||
| #define WIN_RECAL                       0x10 /* obsolete since ATA4 */ | ||||
| /* obsolete since ATA3, retired in ATA4 0x11..0x1F */ | ||||
| #define WIN_READ			0x20 /* 28-Bit */ | ||||
| #define WIN_READ_ONCE			0x21 /* 28-Bit without retries */ | ||||
| #define WIN_READ_LONG			0x22 /* 28-Bit */ | ||||
| #define WIN_READ_LONG_ONCE		0x23 /* 28-Bit without retries */ | ||||
| #define WIN_READ_ONCE                   0x21 /* 28-Bit w/o retries, obsolete since ATA5 */ | ||||
| /* obsolete since ATA4                  0x22..0x23 */ | ||||
| #define WIN_READ_EXT			0x24 /* 48-Bit */ | ||||
| #define WIN_READDMA_EXT			0x25 /* 48-Bit */ | ||||
| #define WIN_READDMA_QUEUED_EXT		0x26 /* 48-Bit */ | ||||
| #define WIN_READDMA_QUEUED_EXT          0x26 /* 48-Bit, obsolete since ACS2 */ | ||||
| #define WIN_READ_NATIVE_MAX_EXT		0x27 /* 48-Bit */ | ||||
| /*
 | ||||
|  *	0x28 | ||||
|  */ | ||||
| /* reserved                             0x28 */ | ||||
| #define WIN_MULTREAD_EXT		0x29 /* 48-Bit */ | ||||
| /*
 | ||||
|  *	0x2A->0x2F Reserved | ||||
|  */ | ||||
| /* READ STREAM DMA EXT                  0x2A */ | ||||
| /* READ STREAM EXT                      0x2B */ | ||||
| /* reserved                             0x2C..0x2E */ | ||||
| /* READ LOG EXT                         0x2F */ | ||||
| #define WIN_WRITE			0x30 /* 28-Bit */ | ||||
| #define WIN_WRITE_ONCE			0x31 /* 28-Bit without retries */ | ||||
| #define WIN_WRITE_LONG			0x32 /* 28-Bit */ | ||||
| #define WIN_WRITE_LONG_ONCE		0x33 /* 28-Bit without retries */ | ||||
| #define WIN_WRITE_ONCE                  0x31 /* 28-Bit w/o retries, obsolete since ATA5 */ | ||||
| /* obsolete since ATA4                  0x32..0x33 */ | ||||
| #define WIN_WRITE_EXT			0x34 /* 48-Bit */ | ||||
| #define WIN_WRITEDMA_EXT		0x35 /* 48-Bit */ | ||||
| #define WIN_WRITEDMA_QUEUED_EXT		0x36 /* 48-Bit */ | ||||
| #define WIN_SET_MAX_EXT                 0x37 /* 48-Bit, obsolete since ACS2 */ | ||||
| #define WIN_SET_MAX_EXT			0x37 /* 48-Bit */ | ||||
| #define CFA_WRITE_SECT_WO_ERASE		0x38 /* CFA Write Sectors without erase */ | ||||
| #define WIN_MULTWRITE_EXT		0x39 /* 48-Bit */ | ||||
| /*
 | ||||
|  *	0x3A->0x3B Reserved | ||||
|  */ | ||||
| #define WIN_WRITE_VERIFY		0x3C /* 28-Bit */ | ||||
| /*
 | ||||
|  *	0x3D->0x3F Reserved | ||||
|  */ | ||||
| /* WRITE STREAM DMA EXT                 0x3A */ | ||||
| /* WRITE STREAM EXT                     0x3B */ | ||||
| #define WIN_WRITE_VERIFY                0x3C /* 28-Bit, obsolete since ATA4 */ | ||||
| /* WRITE DMA FUA EXT                    0x3D */ | ||||
| /* obsolete since ACS2                  0x3E */ | ||||
| /* WRITE LOG EXT                        0x3F */ | ||||
| #define WIN_VERIFY			0x40 /* 28-Bit - Read Verify Sectors */ | ||||
| #define WIN_VERIFY_ONCE			0x41 /* 28-Bit - without retries */ | ||||
| #define WIN_VERIFY_ONCE                 0x41 /* 28-Bit - w/o retries, obsolete since ATA5 */ | ||||
| #define WIN_VERIFY_EXT			0x42 /* 48-Bit */ | ||||
| /*
 | ||||
|  *	0x43->0x4F Reserved | ||||
|  */ | ||||
| #define WIN_FORMAT			0x50 | ||||
| /*
 | ||||
|  *	0x51->0x5F Reserved | ||||
|  */ | ||||
| #define WIN_INIT			0x60 | ||||
| /*
 | ||||
|  *	0x61->0x5F Reserved | ||||
|  */ | ||||
| #define WIN_SEEK			0x70 /* 0x70-0x7F Reserved */ | ||||
| /* reserved                             0x43..0x44 */ | ||||
| /* WRITE UNCORRECTABLE EXT              0x45 */ | ||||
| /* reserved                             0x46 */ | ||||
| /* READ LOG DMA EXT                     0x47 */ | ||||
| /* reserved                             0x48..0x4F */ | ||||
| /* obsolete since ATA4                  0x50 */ | ||||
| /* CONFIGURE STREAM                     0x51 */ | ||||
| /* reserved                             0x52..0x56 */ | ||||
| /* WRITE LOG DMA EXT                    0x57 */ | ||||
| /* reserved                             0x58..0x5A */ | ||||
| /* TRUSTED NON DATA                     0x5B */ | ||||
| /* TRUSTED RECEIVE                      0x5C */ | ||||
| /* TRUSTED RECEIVE DMA                  0x5D */ | ||||
| /* TRUSTED SEND                         0x5E */ | ||||
| /* TRUSTED SEND DMA                     0x5F */ | ||||
| /* READ FPDMA QUEUED                    0x60 */ | ||||
| /* WRITE FPDMA QUEUED                   0x61 */ | ||||
| /* reserved                             0x62->0x6F */ | ||||
| #define WIN_SEEK                        0x70 /* obsolete since ATA7 */ | ||||
| /* reserved                             0x71-0x7F */ | ||||
| /* vendor specific                      0x80-0x86 */ | ||||
| #define CFA_TRANSLATE_SECTOR		0x87 /* CFA Translate Sector */ | ||||
| /* vendor specific                      0x88-0x8F */ | ||||
| #define WIN_DIAGNOSE			0x90 | ||||
| #define WIN_SPECIFY			0x91 /* set drive geometry translation */ | ||||
| #define WIN_SPECIFY                     0x91 /* set drive geometry translation, obsolete since ATA6 */ | ||||
| #define WIN_DOWNLOAD_MICROCODE		0x92 | ||||
| #define WIN_STANDBYNOW2			0x94 | ||||
| #define CFA_IDLEIMMEDIATE		0x95 /* force drive to become "ready" */ | ||||
| #define WIN_STANDBY2			0x96 | ||||
| #define WIN_SETIDLE2			0x97 | ||||
| #define WIN_CHECKPOWERMODE2		0x98 | ||||
| #define WIN_SLEEPNOW2			0x99 | ||||
| /*
 | ||||
|  *	0x9A VENDOR | ||||
|  */ | ||||
| /* DOWNLOAD MICROCODE DMA               0x93 */ | ||||
| #define WIN_STANDBYNOW2                 0x94 /* retired in ATA4 */ | ||||
| #define WIN_IDLEIMMEDIATE2              0x95 /* force drive to become "ready", retired in ATA4 */ | ||||
| #define WIN_STANDBY2                    0x96 /* retired in ATA4 */ | ||||
| #define WIN_SETIDLE2                    0x97 /* retired in ATA4 */ | ||||
| #define WIN_CHECKPOWERMODE2             0x98 /* retired in ATA4 */ | ||||
| #define WIN_SLEEPNOW2                   0x99 /* retired in ATA4 */ | ||||
| /* vendor specific                      0x9A */ | ||||
| /* reserved                             0x9B..0x9F */ | ||||
| #define WIN_PACKETCMD			0xA0 /* Send a packet command. */ | ||||
| #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/ | ||||
| #define WIN_QUEUED_SERVICE		0xA2 | ||||
| #define WIN_QUEUED_SERVICE              0xA2 /* obsolete since ACS2 */ | ||||
| /* reserved                             0xA3..0xAF */ | ||||
| #define WIN_SMART			0xB0 /* self-monitoring and reporting */ | ||||
| /* Device Configuration Overlay         0xB1 */ | ||||
| /* reserved                             0xB2..0xB3 */ | ||||
| /* Sanitize Device                      0xB4 */ | ||||
| /* reserved                             0xB5 */ | ||||
| /* NV Cache                             0xB6 */ | ||||
| /* reserved for CFA                     0xB7..0xBB */ | ||||
| #define CFA_ACCESS_METADATA_STORAGE	0xB8 | ||||
| /* reserved                             0xBC..0xBF */ | ||||
| #define CFA_ERASE_SECTORS       	0xC0 /* microdrives implement as NOP */ | ||||
| /* vendor specific                      0xC1..0xC3 */ | ||||
| #define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/ | ||||
| #define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */ | ||||
| #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */ | ||||
| #define WIN_READDMA_QUEUED		0xC7 /* read sectors using Queued DMA transfers */ | ||||
| #define WIN_READDMA_QUEUED              0xC7 /* read sectors using Queued DMA transfers, obsolete since ACS2 */ | ||||
| #define WIN_READDMA			0xC8 /* read sectors using DMA transfers */ | ||||
| #define WIN_READDMA_ONCE		0xC9 /* 28-Bit - without retries */ | ||||
| #define WIN_READDMA_ONCE                0xC9 /* 28-Bit - w/o retries, obsolete since ATA5 */ | ||||
| #define WIN_WRITEDMA			0xCA /* write sectors using DMA transfers */ | ||||
| #define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */ | ||||
| #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */ | ||||
| #define WIN_WRITEDMA_ONCE               0xCB /* 28-Bit - w/o retries, obsolete since ATA5 */ | ||||
| #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers, obsolete since ACS2 */ | ||||
| #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */ | ||||
| #define WIN_GETMEDIASTATUS		0xDA | ||||
| #define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */ | ||||
| #define WIN_POSTBOOT			0xDC | ||||
| #define WIN_PREBOOT			0xDD | ||||
| #define WIN_DOORLOCK			0xDE /* lock door on removable drives */ | ||||
| #define WIN_DOORUNLOCK			0xDF /* unlock door on removable drives */ | ||||
| /* WRITE MULTIPLE FUA EXT               0xCE */ | ||||
| /* reserved                             0xCF..0xDO */ | ||||
| /* CHECK MEDIA CARD TYPE                0xD1 */ | ||||
| /* reserved for media card pass through 0xD2..0xD4 */ | ||||
| /* reserved                             0xD5..0xD9 */ | ||||
| #define WIN_GETMEDIASTATUS              0xDA /* obsolete since ATA8 */ | ||||
| /* obsolete since ATA3, retired in ATA4 0xDB..0xDD */ | ||||
| #define WIN_DOORLOCK                    0xDE /* lock door on removable drives, obsolete since ATA8 */ | ||||
| #define WIN_DOORUNLOCK                  0xDF /* unlock door on removable drives, obsolete since ATA8 */ | ||||
| #define WIN_STANDBYNOW1			0xE0 | ||||
| #define WIN_IDLEIMMEDIATE		0xE1 /* force drive to become "ready" */ | ||||
| #define WIN_STANDBY             	0xE2 /* Set device in Standby Mode */ | ||||
| @ -169,25 +178,25 @@ typedef struct IDEDMAOps IDEDMAOps; | ||||
| #define WIN_SLEEPNOW1			0xE6 | ||||
| #define WIN_FLUSH_CACHE			0xE7 | ||||
| #define WIN_WRITE_BUFFER		0xE8 /* force write only 1 sector */ | ||||
| #define WIN_WRITE_SAME			0xE9 /* read ata-2 to use */ | ||||
| 	/* SET_FEATURES 0x22 or 0xDD */ | ||||
| /* READ BUFFER DMA                      0xE9 */ | ||||
| #define WIN_FLUSH_CACHE_EXT		0xEA /* 48-Bit */ | ||||
| /* WRITE BUFFER DMA                     0xEB */ | ||||
| #define WIN_IDENTIFY			0xEC /* ask drive to identify itself	*/ | ||||
| #define WIN_MEDIAEJECT			0xED | ||||
| #define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */ | ||||
| #define WIN_MEDIAEJECT                  0xED /* obsolete since ATA8 */ | ||||
| /* obsolete since ATA4                  0xEE */ | ||||
| #define WIN_SETFEATURES			0xEF /* set special drive features */ | ||||
| #define EXABYTE_ENABLE_NEST		0xF0 | ||||
| #define IBM_SENSE_CONDITION		0xF0 /* measure disk temperature */ | ||||
| #define IBM_SENSE_CONDITION             0xF0 /* measure disk temperature, vendor specific */ | ||||
| #define WIN_SECURITY_SET_PASS		0xF1 | ||||
| #define WIN_SECURITY_UNLOCK		0xF2 | ||||
| #define WIN_SECURITY_ERASE_PREPARE	0xF3 | ||||
| #define WIN_SECURITY_ERASE_UNIT		0xF4 | ||||
| #define WIN_SECURITY_FREEZE_LOCK	0xF5 | ||||
| #define CFA_WEAR_LEVEL			0xF5 /* microdrives implement as NOP */ | ||||
| #define CFA_WEAR_LEVEL                  0xF5 /* microdrives implement as NOP; not specified in T13! */ | ||||
| #define WIN_SECURITY_DISABLE		0xF6 | ||||
| /* vendor specific                      0xF7 */ | ||||
| #define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */ | ||||
| #define WIN_SET_MAX			0xF9 | ||||
| #define DISABLE_SEAGATE			0xFB | ||||
| /* vendor specific                      0xFA..0xFF */ | ||||
| 
 | ||||
| /* set to 1 set disable mult support */ | ||||
| #define MAX_MULT_SECTORS 16 | ||||
|  | ||||
| @ -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" | ||||
| 
 | ||||
| @ -176,10 +175,10 @@ static int pci_piix3_xen_ide_unplug(DeviceState *dev) | ||||
| 
 | ||||
|     for (; i < 3; i++) { | ||||
|         di = drive_get_by_index(IF_IDE, i); | ||||
|         if (di != NULL && di->bdrv != NULL && !di->bdrv->removable) { | ||||
|             DeviceState *ds = bdrv_get_attached(di->bdrv); | ||||
|         if (di != NULL && !di->media_cd) { | ||||
|             DeviceState *ds = bdrv_get_attached_dev(di->bdrv); | ||||
|             if (ds) { | ||||
|                 bdrv_detach(di->bdrv, ds); | ||||
|                 bdrv_detach_dev(di->bdrv, ds); | ||||
|             } | ||||
|             bdrv_close(di->bdrv); | ||||
|             pci_ide->bus[di->bus].ifs[di->unit].bs = NULL; | ||||
|  | ||||
| @ -603,6 +603,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, | ||||
|             g_free(pfl); | ||||
|             return NULL; | ||||
|         } | ||||
|         bdrv_attach_dev_nofail(pfl->bs, pfl); | ||||
|     } | ||||
| #if 0 /* XXX: there should be a bit to set up read-only,
 | ||||
|        *      the same way the hardware does (with WP pin). | ||||
|  | ||||
| @ -641,6 +641,7 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base, | ||||
|             g_free(pfl); | ||||
|             return NULL; | ||||
|         } | ||||
|         bdrv_attach_dev_nofail(pfl->bs, pfl); | ||||
|     } | ||||
|     pflash_setup_mappings(pfl); | ||||
|     pfl->rom_mode = 1; | ||||
|  | ||||
| @ -312,7 +312,7 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str) | ||||
|     bs = bdrv_find(str); | ||||
|     if (bs == NULL) | ||||
|         return -ENOENT; | ||||
|     if (bdrv_attach(bs, dev) < 0) | ||||
|     if (bdrv_attach_dev(bs, dev) < 0) | ||||
|         return -EEXIST; | ||||
|     *ptr = bs; | ||||
|     return 0; | ||||
| @ -323,7 +323,7 @@ static void free_drive(DeviceState *dev, Property *prop) | ||||
|     BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); | ||||
| 
 | ||||
|     if (*ptr) { | ||||
|         bdrv_detach(*ptr, dev); | ||||
|         bdrv_detach_dev(*ptr, dev); | ||||
|         blockdev_auto_del(*ptr); | ||||
|     } | ||||
| } | ||||
| @ -678,7 +678,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va | ||||
| { | ||||
|     int res; | ||||
| 
 | ||||
|     res = bdrv_attach(value, dev); | ||||
|     res = bdrv_attach_dev(value, dev); | ||||
|     if (res < 0) { | ||||
|         error_report("Can't attach drive %s to %s.%s: %s", | ||||
|                      bdrv_get_device_name(value), | ||||
|  | ||||
| @ -498,6 +498,7 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) | ||||
|     memset(req->sense, 0, 18); | ||||
|     req->sense[0] = 0xf0; | ||||
|     req->sense[2] = sense.key; | ||||
|     req->sense[7] = 10; | ||||
|     req->sense[12] = sense.asc; | ||||
|     req->sense[13] = sense.ascq; | ||||
|     req->sense_len = 18; | ||||
| @ -883,7 +884,7 @@ int scsi_build_sense(uint8_t *in_buf, int in_len, | ||||
|         /* Return fixed format sense buffer */ | ||||
|         buf[0] = 0xf0; | ||||
|         buf[2] = sense.key; | ||||
|         buf[7] = 7; | ||||
|         buf[7] = 10; | ||||
|         buf[12] = sense.asc; | ||||
|         buf[13] = sense.ascq; | ||||
|         return MIN(len, 18); | ||||
| @ -977,7 +978,7 @@ static const char *scsi_command_name(uint8_t cmd) | ||||
|         [ LOCATE_16                ] = "LOCATE_16", | ||||
|         [ WRITE_SAME_16            ] = "WRITE_SAME_16", | ||||
|         [ ERASE_16                 ] = "ERASE_16", | ||||
|         [ SERVICE_ACTION_IN        ] = "SERVICE_ACTION_IN", | ||||
|         [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16", | ||||
|         [ WRITE_LONG_16            ] = "WRITE_LONG_16", | ||||
|         [ REPORT_LUNS              ] = "REPORT_LUNS", | ||||
|         [ BLANK                    ] = "BLANK", | ||||
| @ -987,6 +988,7 @@ static const char *scsi_command_name(uint8_t cmd) | ||||
|         [ LOAD_UNLOAD              ] = "LOAD_UNLOAD", | ||||
|         [ READ_12                  ] = "READ_12", | ||||
|         [ WRITE_12                 ] = "WRITE_12", | ||||
|         [ SERVICE_ACTION_IN_12     ] = "SERVICE_ACTION_IN_12", | ||||
|         [ WRITE_VERIFY_12          ] = "WRITE_VERIFY_12", | ||||
|         [ VERIFY_12                ] = "VERIFY_12", | ||||
|         [ SEARCH_HIGH_12           ] = "SEARCH_HIGH_12", | ||||
|  | ||||
| @ -102,7 +102,7 @@ | ||||
| #define LOCATE_16             0x92 | ||||
| #define WRITE_SAME_16         0x93 | ||||
| #define ERASE_16              0x93 | ||||
| #define SERVICE_ACTION_IN     0x9e | ||||
| #define SERVICE_ACTION_IN_16  0x9e | ||||
| #define WRITE_LONG_16         0x9f | ||||
| #define REPORT_LUNS           0xa0 | ||||
| #define BLANK                 0xa1 | ||||
| @ -112,6 +112,7 @@ | ||||
| #define LOAD_UNLOAD           0xa6 | ||||
| #define READ_12               0xa8 | ||||
| #define WRITE_12              0xaa | ||||
| #define SERVICE_ACTION_IN_12  0xab | ||||
| #define WRITE_VERIFY_12       0xae | ||||
| #define VERIFY_12             0xaf | ||||
| #define SEARCH_HIGH_12        0xb0 | ||||
| @ -122,6 +123,11 @@ | ||||
| #define READ_DEFECT_DATA_12   0xb7 | ||||
| #define SET_CD_SPEED          0xbb | ||||
| 
 | ||||
| /*
 | ||||
|  * SERVICE ACTION IN subcodes | ||||
|  */ | ||||
| #define SAI_READ_CAPACITY_16  0x10 | ||||
| 
 | ||||
| /*
 | ||||
|  *  SAM Status codes | ||||
|  */ | ||||
|  | ||||
							
								
								
									
										157
									
								
								hw/scsi-disk.c
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								hw/scsi-disk.c
									
									
									
									
									
								
							| @ -111,9 +111,10 @@ static void scsi_read_complete(void * opaque, int ret) | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||||
|     int n; | ||||
| 
 | ||||
|     r->req.aiocb = NULL; | ||||
| 
 | ||||
|     bdrv_acct_done(s->bs, &r->acct); | ||||
|     if (r->req.aiocb != NULL) { | ||||
|         r->req.aiocb = NULL; | ||||
|         bdrv_acct_done(s->bs, &r->acct); | ||||
|     } | ||||
| 
 | ||||
|     if (ret) { | ||||
|         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) { | ||||
| @ -129,6 +130,24 @@ static void scsi_read_complete(void * opaque, int ret) | ||||
|     scsi_req_data(&r->req, r->iov.iov_len); | ||||
| } | ||||
| 
 | ||||
| static void scsi_flush_complete(void * opaque, int ret) | ||||
| { | ||||
|     SCSIDiskReq *r = (SCSIDiskReq *)opaque; | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||||
| 
 | ||||
|     if (r->req.aiocb != NULL) { | ||||
|         r->req.aiocb = NULL; | ||||
|         bdrv_acct_done(s->bs, &r->acct); | ||||
|     } | ||||
| 
 | ||||
|     if (ret < 0) { | ||||
|         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     scsi_req_complete(&r->req, GOOD); | ||||
| } | ||||
| 
 | ||||
| /* Read more data from scsi device into buffer.  */ | ||||
| static void scsi_read_data(SCSIRequest *req) | ||||
| @ -217,9 +236,10 @@ static void scsi_write_complete(void * opaque, int ret) | ||||
|     uint32_t len; | ||||
|     uint32_t n; | ||||
| 
 | ||||
|     r->req.aiocb = NULL; | ||||
| 
 | ||||
|     bdrv_acct_done(s->bs, &r->acct); | ||||
|     if (r->req.aiocb != NULL) { | ||||
|         r->req.aiocb = NULL; | ||||
|         bdrv_acct_done(s->bs, &r->acct); | ||||
|     } | ||||
| 
 | ||||
|     if (ret) { | ||||
|         if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) { | ||||
| @ -526,12 +546,12 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) | ||||
|     return buflen; | ||||
| } | ||||
| 
 | ||||
| static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p, | ||||
| static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, | ||||
|                            int page_control) | ||||
| { | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); | ||||
|     BlockDriverState *bdrv = s->bs; | ||||
|     int cylinders, heads, secs; | ||||
|     uint8_t *p = *p_outbuf; | ||||
| 
 | ||||
|     /*
 | ||||
|      * If Changeable Values are requested, a mask denoting those mode parameters | ||||
| @ -541,10 +561,13 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p, | ||||
|      */ | ||||
|     switch (page) { | ||||
|     case 4: /* Rigid disk device geometry page. */ | ||||
|         if (s->qdev.type == TYPE_ROM) { | ||||
|             return -1; | ||||
|         } | ||||
|         p[0] = 4; | ||||
|         p[1] = 0x16; | ||||
|         if (page_control == 1) { /* Changeable Values */ | ||||
|             return p[1] + 2; | ||||
|             break; | ||||
|         } | ||||
|         /* if a geometry hint is available, use it */ | ||||
|         bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs); | ||||
| @ -570,13 +593,16 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p, | ||||
|         /* Medium rotation rate [rpm], 5400 rpm */ | ||||
|         p[20] = (5400 >> 8) & 0xff; | ||||
|         p[21] = 5400 & 0xff; | ||||
|         return p[1] + 2; | ||||
|         break; | ||||
| 
 | ||||
|     case 5: /* Flexible disk device geometry page. */ | ||||
|         if (s->qdev.type == TYPE_ROM) { | ||||
|             return -1; | ||||
|         } | ||||
|         p[0] = 5; | ||||
|         p[1] = 0x1e; | ||||
|         if (page_control == 1) { /* Changeable Values */ | ||||
|             return p[1] + 2; | ||||
|             break; | ||||
|         } | ||||
|         /* Transfer rate [kbit/s], 5Mbit/s */ | ||||
|         p[2] = 5000 >> 8; | ||||
| @ -609,26 +635,27 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p, | ||||
|         /* Medium rotation rate [rpm], 5400 rpm */ | ||||
|         p[28] = (5400 >> 8) & 0xff; | ||||
|         p[29] = 5400 & 0xff; | ||||
|         return p[1] + 2; | ||||
|         break; | ||||
| 
 | ||||
|     case 8: /* Caching page.  */ | ||||
|         p[0] = 8; | ||||
|         p[1] = 0x12; | ||||
|         if (page_control == 1) { /* Changeable Values */ | ||||
|             return p[1] + 2; | ||||
|             break; | ||||
|         } | ||||
|         if (bdrv_enable_write_cache(s->bs)) { | ||||
|             p[2] = 4; /* WCE */ | ||||
|         } | ||||
|         return p[1] + 2; | ||||
|         break; | ||||
| 
 | ||||
|     case 0x2a: /* CD Capabilities and Mechanical Status page. */ | ||||
|         if (s->qdev.type != TYPE_ROM) | ||||
|             return 0; | ||||
|         if (s->qdev.type != TYPE_ROM) { | ||||
|             return -1; | ||||
|         } | ||||
|         p[0] = 0x2a; | ||||
|         p[1] = 0x14; | ||||
|         if (page_control == 1) { /* Changeable Values */ | ||||
|             return p[1] + 2; | ||||
|             break; | ||||
|         } | ||||
|         p[2] = 3; // CD-R & CD-RW read
 | ||||
|         p[3] = 0; // Writing not supported
 | ||||
| @ -653,27 +680,30 @@ static int mode_sense_page(SCSIRequest *req, int page, uint8_t *p, | ||||
|         p[19] = (16 * 176) & 0xff; | ||||
|         p[20] = (16 * 176) >> 8; // 16x write speed current
 | ||||
|         p[21] = (16 * 176) & 0xff; | ||||
|         return p[1] + 2; | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         return 0; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     *p_outbuf += p[1] + 2; | ||||
|     return p[1] + 2; | ||||
| } | ||||
| 
 | ||||
| static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) | ||||
| static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) | ||||
| { | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); | ||||
|     uint64_t nb_sectors; | ||||
|     int page, dbd, buflen, page_control; | ||||
|     int page, dbd, buflen, ret, page_control; | ||||
|     uint8_t *p; | ||||
|     uint8_t dev_specific_param; | ||||
| 
 | ||||
|     dbd = req->cmd.buf[1]  & 0x8; | ||||
|     page = req->cmd.buf[2] & 0x3f; | ||||
|     page_control = (req->cmd.buf[2] & 0xc0) >> 6; | ||||
|     dbd = r->req.cmd.buf[1]  & 0x8; | ||||
|     page = r->req.cmd.buf[2] & 0x3f; | ||||
|     page_control = (r->req.cmd.buf[2] & 0xc0) >> 6; | ||||
|     DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n", | ||||
|         (req->cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, req->cmd.xfer, page_control); | ||||
|     memset(outbuf, 0, req->cmd.xfer); | ||||
|         (r->req.cmd.buf[0] == MODE_SENSE) ? 6 : 10, page, r->req.cmd.xfer, page_control); | ||||
|     memset(outbuf, 0, r->req.cmd.xfer); | ||||
|     p = outbuf; | ||||
| 
 | ||||
|     if (bdrv_is_read_only(s->bs)) { | ||||
| @ -682,7 +712,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) | ||||
|         dev_specific_param = 0x00; | ||||
|     } | ||||
| 
 | ||||
|     if (req->cmd.buf[0] == MODE_SENSE) { | ||||
|     if (r->req.cmd.buf[0] == MODE_SENSE) { | ||||
|         p[1] = 0; /* Default media type.  */ | ||||
|         p[2] = dev_specific_param; | ||||
|         p[3] = 0; /* Block descriptor length.  */ | ||||
| @ -696,7 +726,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) | ||||
| 
 | ||||
|     bdrv_get_geometry(s->bs, &nb_sectors); | ||||
|     if (!dbd && nb_sectors) { | ||||
|         if (req->cmd.buf[0] == MODE_SENSE) { | ||||
|         if (r->req.cmd.buf[0] == MODE_SENSE) { | ||||
|             outbuf[3] = 8; /* Block descriptor length  */ | ||||
|         } else { /* MODE_SENSE_10 */ | ||||
|             outbuf[7] = 8; /* Block descriptor length  */ | ||||
| @ -715,23 +745,21 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) | ||||
|         p += 8; | ||||
|     } | ||||
| 
 | ||||
|     if (page_control == 3) { /* Saved Values */ | ||||
|         return -1; /* ILLEGAL_REQUEST */ | ||||
|     if (page_control == 3) { | ||||
|         /* Saved Values */ | ||||
|         scsi_check_condition(r, SENSE_CODE(SAVING_PARAMS_NOT_SUPPORTED)); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     switch (page) { | ||||
|     case 0x04: | ||||
|     case 0x05: | ||||
|     case 0x08: | ||||
|     case 0x2a: | ||||
|         p += mode_sense_page(req, page, p, page_control); | ||||
|         break; | ||||
|     case 0x3f: | ||||
|         p += mode_sense_page(req, 0x08, p, page_control); | ||||
|         p += mode_sense_page(req, 0x2a, p, page_control); | ||||
|         break; | ||||
|     default: | ||||
|         return -1; /* ILLEGAL_REQUEST */ | ||||
|     if (page == 0x3f) { | ||||
|         for (page = 0; page <= 0x3e; page++) { | ||||
|             mode_sense_page(s, page, &p, page_control); | ||||
|         } | ||||
|     } else { | ||||
|         ret = mode_sense_page(s, page, &p, page_control); | ||||
|         if (ret == -1) { | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     buflen = p - outbuf; | ||||
| @ -740,14 +768,14 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf) | ||||
|      * following data that is available to be transferred. The mode data | ||||
|      * length does not include itself. | ||||
|      */ | ||||
|     if (req->cmd.buf[0] == MODE_SENSE) { | ||||
|     if (r->req.cmd.buf[0] == MODE_SENSE) { | ||||
|         outbuf[0] = buflen - 1; | ||||
|     } else { /* MODE_SENSE_10 */ | ||||
|         outbuf[0] = ((buflen - 2) >> 8) & 0xff; | ||||
|         outbuf[1] = (buflen - 2) & 0xff; | ||||
|     } | ||||
|     if (buflen > req->cmd.xfer) | ||||
|         buflen = req->cmd.xfer; | ||||
|     if (buflen > r->req.cmd.xfer) | ||||
|         buflen = r->req.cmd.xfer; | ||||
|     return buflen; | ||||
| } | ||||
| 
 | ||||
| @ -792,7 +820,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) | ||||
|     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); | ||||
|     uint64_t nb_sectors; | ||||
|     int buflen = 0; | ||||
|     int ret; | ||||
| 
 | ||||
|     switch (req->cmd.buf[0]) { | ||||
|     case TEST_UNIT_READY: | ||||
| @ -806,7 +833,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) | ||||
|         break; | ||||
|     case MODE_SENSE: | ||||
|     case MODE_SENSE_10: | ||||
|         buflen = scsi_disk_emulate_mode_sense(req, outbuf); | ||||
|         buflen = scsi_disk_emulate_mode_sense(r, outbuf); | ||||
|         if (buflen < 0) | ||||
|             goto illegal_request; | ||||
|         break; | ||||
| @ -864,20 +891,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) | ||||
|         outbuf[7] = 0; | ||||
|         buflen = 8; | ||||
|         break; | ||||
|     case SYNCHRONIZE_CACHE: | ||||
|     { | ||||
|         BlockAcctCookie acct; | ||||
| 
 | ||||
|         bdrv_acct_start(s->bs, &acct, 0, BDRV_ACCT_FLUSH); | ||||
|         ret = bdrv_flush(s->bs); | ||||
|         bdrv_acct_done(s->bs, &acct); | ||||
|         if (ret < 0) { | ||||
|             if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) { | ||||
|                 return -1; | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     case GET_CONFIGURATION: | ||||
|         memset(outbuf, 0, 8); | ||||
|         /* ??? This should probably return much more information.  For now
 | ||||
| @ -885,9 +898,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf) | ||||
|         outbuf[7] = 8; // CD-ROM
 | ||||
|         buflen = 8; | ||||
|         break; | ||||
|     case SERVICE_ACTION_IN: | ||||
|     case SERVICE_ACTION_IN_16: | ||||
|         /* Service Action In subcommands. */ | ||||
|         if ((req->cmd.buf[1] & 31) == 0x10) { | ||||
|         if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) { | ||||
|             DPRINTF("SAI READ CAPACITY(16)\n"); | ||||
|             memset(outbuf, 0, req->cmd.xfer); | ||||
|             bdrv_get_geometry(s->bs, &nb_sectors); | ||||
| @ -941,7 +954,9 @@ not_ready: | ||||
|     return -1; | ||||
| 
 | ||||
| illegal_request: | ||||
|     scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); | ||||
|     if (r->req.status == -1) { | ||||
|         scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| @ -985,10 +1000,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) | ||||
|     case START_STOP: | ||||
|     case ALLOW_MEDIUM_REMOVAL: | ||||
|     case READ_CAPACITY_10: | ||||
|     case SYNCHRONIZE_CACHE: | ||||
|     case READ_TOC: | ||||
|     case GET_CONFIGURATION: | ||||
|     case SERVICE_ACTION_IN: | ||||
|     case SERVICE_ACTION_IN_16: | ||||
|     case VERIFY_10: | ||||
|         rc = scsi_disk_emulate_command(r, outbuf); | ||||
|         if (rc < 0) { | ||||
| @ -997,6 +1011,13 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf) | ||||
| 
 | ||||
|         r->iov.iov_len = rc; | ||||
|         break; | ||||
|     case SYNCHRONIZE_CACHE: | ||||
|         bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH); | ||||
|         r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r); | ||||
|         if (r->req.aiocb == NULL) { | ||||
|             scsi_flush_complete(r, -EIO); | ||||
|         } | ||||
|         return 0; | ||||
|     case READ_6: | ||||
|     case READ_10: | ||||
|     case READ_12: | ||||
|  | ||||
							
								
								
									
										14
									
								
								hw/sd.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								hw/sd.c
									
									
									
									
									
								
							| @ -31,7 +31,6 @@ | ||||
| 
 | ||||
| #include "hw.h" | ||||
| #include "block.h" | ||||
| #include "block_int.h" | ||||
| #include "sd.h" | ||||
| 
 | ||||
| //#define DEBUG_SD 1
 | ||||
| @ -420,14 +419,10 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) | ||||
|     sd->pwd_len = 0; | ||||
| } | ||||
| 
 | ||||
| static void sd_cardchange(void *opaque, int reason) | ||||
| static void sd_cardchange(void *opaque) | ||||
| { | ||||
|     SDState *sd = opaque; | ||||
| 
 | ||||
|     if (!(reason & CHANGE_MEDIA)) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     qemu_set_irq(sd->inserted_cb, bdrv_is_inserted(sd->bdrv)); | ||||
|     if (bdrv_is_inserted(sd->bdrv)) { | ||||
|         sd_reset(sd, sd->bdrv); | ||||
| @ -435,6 +430,10 @@ static void sd_cardchange(void *opaque, int reason) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static const BlockDevOps sd_block_ops = { | ||||
|     .change_media_cb = sd_cardchange, | ||||
| }; | ||||
| 
 | ||||
| /* We do not model the chip select pin, so allow the board to select
 | ||||
|    whether card should be in SSI or MMC/SD mode.  It is also up to the | ||||
|    board to ensure that ssi transfers only occur when the chip select | ||||
| @ -449,7 +448,8 @@ SDState *sd_init(BlockDriverState *bs, int is_spi) | ||||
|     sd->enable = 1; | ||||
|     sd_reset(sd, bs); | ||||
|     if (sd->bdrv) { | ||||
|         bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd); | ||||
|         bdrv_attach_dev_nofail(sd->bdrv, sd); | ||||
|         bdrv_set_dev_ops(sd->bdrv, &sd_block_ops, sd); | ||||
|     } | ||||
|     return sd; | ||||
| } | ||||
|  | ||||
							
								
								
									
										10
									
								
								hw/spitz.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								hw/spitz.c
									
									
									
									
									
								
							| @ -708,17 +708,13 @@ static void spitz_ssp_attach(PXA2xxState *cpu) | ||||
| static void spitz_microdrive_attach(PXA2xxState *cpu, int slot) | ||||
| { | ||||
|     PCMCIACardState *md; | ||||
|     BlockDriverState *bs; | ||||
|     DriveInfo *dinfo; | ||||
| 
 | ||||
|     dinfo = drive_get(IF_IDE, 0, 0); | ||||
|     if (!dinfo) | ||||
|     if (!dinfo || dinfo->media_cd) | ||||
|         return; | ||||
|     bs = dinfo->bdrv; | ||||
|     if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { | ||||
|         md = dscm1xxxx_init(dinfo); | ||||
|         pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md); | ||||
|     } | ||||
|     md = dscm1xxxx_init(dinfo); | ||||
|     pxa2xx_pcmcia_attach(cpu->pcmcia[slot], md); | ||||
| } | ||||
| 
 | ||||
| /* Wm8750 and Max7310 on I2C */ | ||||
|  | ||||
							
								
								
									
										10
									
								
								hw/tosa.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								hw/tosa.c
									
									
									
									
									
								
							| @ -51,17 +51,13 @@ | ||||
| static void tosa_microdrive_attach(PXA2xxState *cpu) | ||||
| { | ||||
|     PCMCIACardState *md; | ||||
|     BlockDriverState *bs; | ||||
|     DriveInfo *dinfo; | ||||
| 
 | ||||
|     dinfo = drive_get(IF_IDE, 0, 0); | ||||
|     if (!dinfo) | ||||
|     if (!dinfo || dinfo->media_cd) | ||||
|         return; | ||||
|     bs = dinfo->bdrv; | ||||
|     if (bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) { | ||||
|         md = dscm1xxxx_init(dinfo); | ||||
|         pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); | ||||
|     } | ||||
|     md = dscm1xxxx_init(dinfo); | ||||
|     pxa2xx_pcmcia_attach(cpu->pcmcia[0], md); | ||||
| } | ||||
| 
 | ||||
| static void tosa_out_switch(void *opaque, int line, int level) | ||||
|  | ||||
| @ -518,7 +518,7 @@ static int usb_msd_initfn(USBDevice *dev) | ||||
|      * | ||||
|      * The hack is probably a bad idea. | ||||
|      */ | ||||
|     bdrv_detach(bs, &s->dev.qdev); | ||||
|     bdrv_detach_dev(bs, &s->dev.qdev); | ||||
|     s->conf.bs = NULL; | ||||
| 
 | ||||
|     if (!s->serial) { | ||||
|  | ||||
| @ -543,15 +543,17 @@ static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id) | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| static void virtio_blk_change_cb(void *opaque, int reason) | ||||
| static void virtio_blk_resize(void *opaque) | ||||
| { | ||||
|     VirtIOBlock *s = opaque; | ||||
| 
 | ||||
|     if (reason & CHANGE_SIZE) { | ||||
|         virtio_notify_config(&s->vdev); | ||||
|     } | ||||
|     virtio_notify_config(&s->vdev); | ||||
| } | ||||
| 
 | ||||
| static const BlockDevOps virtio_block_ops = { | ||||
|     .resize_cb = virtio_blk_resize, | ||||
| }; | ||||
| 
 | ||||
| VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, | ||||
|                               char **serial) | ||||
| { | ||||
| @ -598,7 +600,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf, | ||||
|     register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, | ||||
|                     virtio_blk_save, virtio_blk_load, s); | ||||
|     bdrv_set_removable(s->bs, 0); | ||||
|     bdrv_set_change_cb(s->bs, virtio_blk_change_cb, s); | ||||
|     bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); | ||||
|     s->bs->buffer_alignment = conf->logical_block_size; | ||||
| 
 | ||||
|     add_boot_device_path(conf->bootindex, dev, "/disk@0,0"); | ||||
|  | ||||
| @ -697,6 +697,7 @@ static int blk_init(struct XenDevice *xendev) | ||||
|         xen_be_printf(&blkdev->xendev, 2, "get configured bdrv (cmdline setup)\n"); | ||||
|         blkdev->bs = blkdev->dinfo->bdrv; | ||||
|     } | ||||
|     bdrv_attach_dev_nofail(blkdev->bs, blkdev); | ||||
|     blkdev->file_blk  = BLOCK_SIZE; | ||||
|     blkdev->file_size = bdrv_getlength(blkdev->bs); | ||||
|     if (blkdev->file_size < 0) { | ||||
|  | ||||
| @ -181,6 +181,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd, | ||||
|     case QEMU_AIO_READ: | ||||
|         io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset); | ||||
| 	break; | ||||
|     /* Currently Linux kernel does not support other operations */ | ||||
|     default: | ||||
|         fprintf(stderr, "%s: invalid AIO request type 0x%x.\n", | ||||
|                         __func__, type); | ||||
|  | ||||
							
								
								
									
										4
									
								
								savevm.c
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								savevm.c
									
									
									
									
									
								
							| @ -1914,7 +1914,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) | ||||
|     bs = NULL; | ||||
|     while ((bs = bdrv_next(bs))) { | ||||
| 
 | ||||
|         if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) { | ||||
|         if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
| @ -2034,7 +2034,7 @@ int load_vmstate(const char *name) | ||||
|     bs = NULL; | ||||
|     while ((bs = bdrv_next(bs))) { | ||||
| 
 | ||||
|         if (bdrv_is_removable(bs) || bdrv_is_read_only(bs)) { | ||||
|         if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs)) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Anthony Liguori
						Anthony Liguori