bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 1 | /* |
ths | 223d467 | 2007-12-15 17:28:36 +0000 | [diff] [blame] | 2 | * Block driver for RAW files (posix) |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 3 | * |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 4 | * Copyright (c) 2006 Fabrice Bellard |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 5 | * |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | * of this software and associated documentation files (the "Software"), to deal |
| 8 | * in the Software without restriction, including without limitation the rights |
| 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 10 | * copies of the Software, and to permit persons to whom the Software is |
| 11 | * furnished to do so, subject to the following conditions: |
| 12 | * |
| 13 | * The above copyright notice and this permission notice shall be included in |
| 14 | * all copies or substantial portions of the Software. |
| 15 | * |
| 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 22 | * THE SOFTWARE. |
| 23 | */ |
pbrook | faf0796 | 2007-11-11 02:51:17 +0000 | [diff] [blame] | 24 | #include "qemu-common.h" |
pbrook | 87ecb68 | 2007-11-17 17:14:51 +0000 | [diff] [blame] | 25 | #ifndef QEMU_IMG |
| 26 | #include "qemu-timer.h" |
pbrook | ae5fc45 | 2007-11-11 11:43:27 +0000 | [diff] [blame] | 27 | #include "exec-all.h" |
pbrook | faf0796 | 2007-11-11 02:51:17 +0000 | [diff] [blame] | 28 | #endif |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 29 | #include "block_int.h" |
| 30 | #include <assert.h> |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 31 | #include <aio.h> |
| 32 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 33 | #ifdef CONFIG_COCOA |
| 34 | #include <paths.h> |
| 35 | #include <sys/param.h> |
| 36 | #include <IOKit/IOKitLib.h> |
| 37 | #include <IOKit/IOBSD.h> |
| 38 | #include <IOKit/storage/IOMediaBSDClient.h> |
| 39 | #include <IOKit/storage/IOMedia.h> |
| 40 | #include <IOKit/storage/IOCDMedia.h> |
| 41 | //#include <IOKit/storage/IOCDTypes.h> |
| 42 | #include <CoreFoundation/CoreFoundation.h> |
| 43 | #endif |
| 44 | |
| 45 | #ifdef __sun__ |
ths | 2e9671d | 2007-01-05 17:44:41 +0000 | [diff] [blame] | 46 | #define _POSIX_PTHREAD_SEMANTICS 1 |
| 47 | #include <signal.h> |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 48 | #include <sys/dkio.h> |
| 49 | #endif |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 50 | #ifdef __linux__ |
| 51 | #include <sys/ioctl.h> |
| 52 | #include <linux/cdrom.h> |
| 53 | #include <linux/fd.h> |
| 54 | #endif |
ths | 1cb6c3f | 2006-12-21 19:14:11 +0000 | [diff] [blame] | 55 | #ifdef __FreeBSD__ |
| 56 | #include <sys/disk.h> |
| 57 | #endif |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 58 | |
| 59 | //#define DEBUG_FLOPPY |
| 60 | |
pbrook | faf0796 | 2007-11-11 02:51:17 +0000 | [diff] [blame] | 61 | //#define DEBUG_BLOCK |
| 62 | #if defined(DEBUG_BLOCK) && !defined(QEMU_IMG) |
balrog | a50a628 | 2007-09-20 12:42:24 +0000 | [diff] [blame] | 63 | #define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0) \ |
balrog | 2e03286 | 2007-09-20 13:24:53 +0000 | [diff] [blame] | 64 | { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0) |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 65 | #else |
| 66 | #define DEBUG_BLOCK_PRINT(formatCstr, args...) |
| 67 | #endif |
| 68 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 69 | #define FTYPE_FILE 0 |
| 70 | #define FTYPE_CD 1 |
| 71 | #define FTYPE_FD 2 |
| 72 | |
| 73 | /* if the FD is not accessed during that time (in ms), we try to |
| 74 | reopen it to see if the disk has been changed */ |
| 75 | #define FD_OPEN_TIMEOUT 1000 |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 76 | |
| 77 | typedef struct BDRVRawState { |
| 78 | int fd; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 79 | int type; |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 80 | unsigned int lseek_err_cnt; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 81 | #if defined(__linux__) |
| 82 | /* linux floppy specific */ |
| 83 | int fd_open_flags; |
| 84 | int64_t fd_open_time; |
| 85 | int64_t fd_error_time; |
| 86 | int fd_got_error; |
| 87 | int fd_media_changed; |
| 88 | #endif |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 89 | } BDRVRawState; |
| 90 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 91 | static int fd_open(BlockDriverState *bs); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 92 | |
| 93 | static int raw_open(BlockDriverState *bs, const char *filename, int flags) |
| 94 | { |
| 95 | BDRVRawState *s = bs->opaque; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 96 | int fd, open_flags, ret; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 97 | |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 98 | s->lseek_err_cnt = 0; |
| 99 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 100 | open_flags = O_BINARY; |
| 101 | if ((flags & BDRV_O_ACCESS) == O_RDWR) { |
| 102 | open_flags |= O_RDWR; |
| 103 | } else { |
| 104 | open_flags |= O_RDONLY; |
| 105 | bs->read_only = 1; |
| 106 | } |
| 107 | if (flags & BDRV_O_CREAT) |
| 108 | open_flags |= O_CREAT | O_TRUNC; |
balrog | 33f0027 | 2007-12-24 14:33:24 +0000 | [diff] [blame] | 109 | #ifdef O_DIRECT |
| 110 | if (flags & BDRV_O_DIRECT) |
| 111 | open_flags |= O_DIRECT; |
| 112 | #endif |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 113 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 114 | s->type = FTYPE_FILE; |
| 115 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 116 | fd = open(filename, open_flags, 0644); |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 117 | if (fd < 0) { |
| 118 | ret = -errno; |
| 119 | if (ret == -EROFS) |
| 120 | ret = -EACCES; |
| 121 | return ret; |
| 122 | } |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 123 | s->fd = fd; |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | /* XXX: use host sector size if necessary with: |
| 128 | #ifdef DIOCGSECTORSIZE |
| 129 | { |
| 130 | unsigned int sectorsize = 512; |
| 131 | if (!ioctl(fd, DIOCGSECTORSIZE, §orsize) && |
| 132 | sectorsize > bufsize) |
| 133 | bufsize = sectorsize; |
| 134 | } |
| 135 | #endif |
| 136 | #ifdef CONFIG_COCOA |
| 137 | u_int32_t blockSize = 512; |
| 138 | if ( !ioctl( fd, DKIOCGETBLOCKSIZE, &blockSize ) && blockSize > bufsize) { |
| 139 | bufsize = blockSize; |
| 140 | } |
| 141 | #endif |
| 142 | */ |
| 143 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 144 | static int raw_pread(BlockDriverState *bs, int64_t offset, |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 145 | uint8_t *buf, int count) |
| 146 | { |
| 147 | BDRVRawState *s = bs->opaque; |
| 148 | int ret; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 149 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 150 | ret = fd_open(bs); |
| 151 | if (ret < 0) |
| 152 | return ret; |
| 153 | |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 154 | if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 155 | ++(s->lseek_err_cnt); |
| 156 | if(s->lseek_err_cnt <= 10) { |
j_mayer | 9286841 | 2007-09-21 06:09:39 +0000 | [diff] [blame] | 157 | DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 |
| 158 | "] lseek failed : %d = %s\n", |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 159 | s->fd, bs->filename, offset, buf, count, |
| 160 | bs->total_sectors, errno, strerror(errno)); |
| 161 | } |
| 162 | return -1; |
| 163 | } |
| 164 | s->lseek_err_cnt=0; |
| 165 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 166 | ret = read(s->fd, buf, count); |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 167 | if (ret == count) |
| 168 | goto label__raw_read__success; |
| 169 | |
j_mayer | 9286841 | 2007-09-21 06:09:39 +0000 | [diff] [blame] | 170 | DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 |
| 171 | "] read failed %d : %d = %s\n", |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 172 | s->fd, bs->filename, offset, buf, count, |
| 173 | bs->total_sectors, ret, errno, strerror(errno)); |
| 174 | |
| 175 | /* Try harder for CDrom. */ |
| 176 | if (bs->type == BDRV_TYPE_CDROM) { |
| 177 | lseek(s->fd, offset, SEEK_SET); |
| 178 | ret = read(s->fd, buf, count); |
| 179 | if (ret == count) |
| 180 | goto label__raw_read__success; |
| 181 | lseek(s->fd, offset, SEEK_SET); |
| 182 | ret = read(s->fd, buf, count); |
| 183 | if (ret == count) |
| 184 | goto label__raw_read__success; |
| 185 | |
j_mayer | 9286841 | 2007-09-21 06:09:39 +0000 | [diff] [blame] | 186 | DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 |
| 187 | "] retry read failed %d : %d = %s\n", |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 188 | s->fd, bs->filename, offset, buf, count, |
| 189 | bs->total_sectors, ret, errno, strerror(errno)); |
| 190 | } |
| 191 | |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 192 | label__raw_read__success: |
| 193 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 194 | return ret; |
| 195 | } |
| 196 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 197 | static int raw_pwrite(BlockDriverState *bs, int64_t offset, |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 198 | const uint8_t *buf, int count) |
| 199 | { |
| 200 | BDRVRawState *s = bs->opaque; |
| 201 | int ret; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 202 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 203 | ret = fd_open(bs); |
| 204 | if (ret < 0) |
| 205 | return ret; |
| 206 | |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 207 | if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 208 | ++(s->lseek_err_cnt); |
| 209 | if(s->lseek_err_cnt) { |
j_mayer | 9286841 | 2007-09-21 06:09:39 +0000 | [diff] [blame] | 210 | DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" |
| 211 | PRId64 "] lseek failed : %d = %s\n", |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 212 | s->fd, bs->filename, offset, buf, count, |
| 213 | bs->total_sectors, errno, strerror(errno)); |
| 214 | } |
| 215 | return -1; |
| 216 | } |
| 217 | s->lseek_err_cnt = 0; |
| 218 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 219 | ret = write(s->fd, buf, count); |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 220 | if (ret == count) |
| 221 | goto label__raw_write__success; |
| 222 | |
j_mayer | 9286841 | 2007-09-21 06:09:39 +0000 | [diff] [blame] | 223 | DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 |
| 224 | "] write failed %d : %d = %s\n", |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 225 | s->fd, bs->filename, offset, buf, count, |
| 226 | bs->total_sectors, ret, errno, strerror(errno)); |
| 227 | |
ths | 8c05dbf | 2007-09-13 12:29:23 +0000 | [diff] [blame] | 228 | label__raw_write__success: |
| 229 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 230 | return ret; |
| 231 | } |
| 232 | |
| 233 | /***********************************************************/ |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 234 | /* Unix AIO using POSIX AIO */ |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 235 | |
| 236 | typedef struct RawAIOCB { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 237 | BlockDriverAIOCB common; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 238 | struct aiocb aiocb; |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 239 | struct RawAIOCB *next; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 240 | } RawAIOCB; |
| 241 | |
| 242 | static int aio_sig_num = SIGUSR2; |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 243 | static RawAIOCB *first_aio; /* AIO issued */ |
bellard | 979b67a | 2006-08-02 22:02:08 +0000 | [diff] [blame] | 244 | static int aio_initialized = 0; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 245 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 246 | static void aio_signal_handler(int signum) |
| 247 | { |
pbrook | faf0796 | 2007-11-11 02:51:17 +0000 | [diff] [blame] | 248 | #ifndef QEMU_IMG |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 249 | CPUState *env = cpu_single_env; |
| 250 | if (env) { |
| 251 | /* stop the currently executing cpu because a timer occured */ |
| 252 | cpu_interrupt(env, CPU_INTERRUPT_EXIT); |
| 253 | #ifdef USE_KQEMU |
| 254 | if (env->kqemu_enabled) { |
| 255 | kqemu_cpu_interrupt(env); |
| 256 | } |
| 257 | #endif |
| 258 | } |
bellard | 979b67a | 2006-08-02 22:02:08 +0000 | [diff] [blame] | 259 | #endif |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 260 | } |
| 261 | |
| 262 | void qemu_aio_init(void) |
| 263 | { |
| 264 | struct sigaction act; |
bellard | 979b67a | 2006-08-02 22:02:08 +0000 | [diff] [blame] | 265 | |
| 266 | aio_initialized = 1; |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 267 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 268 | sigfillset(&act.sa_mask); |
| 269 | act.sa_flags = 0; /* do not restart syscalls to interrupt select() */ |
| 270 | act.sa_handler = aio_signal_handler; |
| 271 | sigaction(aio_sig_num, &act, NULL); |
| 272 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 273 | #if defined(__GLIBC__) && defined(__linux__) |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 274 | { |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 275 | /* XXX: aio thread exit seems to hang on RedHat 9 and this init |
| 276 | seems to fix the problem. */ |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 277 | struct aioinit ai; |
| 278 | memset(&ai, 0, sizeof(ai)); |
bellard | 01534fe | 2008-01-06 18:53:07 +0000 | [diff] [blame] | 279 | ai.aio_threads = 1; |
| 280 | ai.aio_num = 1; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 281 | ai.aio_idle_time = 365 * 100000; |
| 282 | aio_init(&ai); |
| 283 | } |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 284 | #endif |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 285 | } |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 286 | |
| 287 | void qemu_aio_poll(void) |
| 288 | { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 289 | RawAIOCB *acb, **pacb; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 290 | int ret; |
| 291 | |
| 292 | for(;;) { |
| 293 | pacb = &first_aio; |
| 294 | for(;;) { |
| 295 | acb = *pacb; |
| 296 | if (!acb) |
| 297 | goto the_end; |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 298 | ret = aio_error(&acb->aiocb); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 299 | if (ret == ECANCELED) { |
| 300 | /* remove the request */ |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 301 | *pacb = acb->next; |
| 302 | qemu_aio_release(acb); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 303 | } else if (ret != EINPROGRESS) { |
| 304 | /* end of aio */ |
| 305 | if (ret == 0) { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 306 | ret = aio_return(&acb->aiocb); |
| 307 | if (ret == acb->aiocb.aio_nbytes) |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 308 | ret = 0; |
| 309 | else |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 310 | ret = -EINVAL; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 311 | } else { |
| 312 | ret = -ret; |
| 313 | } |
| 314 | /* remove the request */ |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 315 | *pacb = acb->next; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 316 | /* call the callback */ |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 317 | acb->common.cb(acb->common.opaque, ret); |
| 318 | qemu_aio_release(acb); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 319 | break; |
| 320 | } else { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 321 | pacb = &acb->next; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 322 | } |
| 323 | } |
| 324 | } |
| 325 | the_end: ; |
| 326 | } |
| 327 | |
pbrook | 6192bc3 | 2006-09-03 12:08:37 +0000 | [diff] [blame] | 328 | /* Wait for all IO requests to complete. */ |
| 329 | void qemu_aio_flush(void) |
| 330 | { |
| 331 | qemu_aio_wait_start(); |
| 332 | qemu_aio_poll(); |
| 333 | while (first_aio) { |
| 334 | qemu_aio_wait(); |
| 335 | } |
| 336 | qemu_aio_wait_end(); |
| 337 | } |
| 338 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 339 | /* wait until at least one AIO was handled */ |
| 340 | static sigset_t wait_oset; |
| 341 | |
| 342 | void qemu_aio_wait_start(void) |
| 343 | { |
| 344 | sigset_t set; |
bellard | 979b67a | 2006-08-02 22:02:08 +0000 | [diff] [blame] | 345 | |
| 346 | if (!aio_initialized) |
| 347 | qemu_aio_init(); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 348 | sigemptyset(&set); |
| 349 | sigaddset(&set, aio_sig_num); |
| 350 | sigprocmask(SIG_BLOCK, &set, &wait_oset); |
| 351 | } |
| 352 | |
| 353 | void qemu_aio_wait(void) |
| 354 | { |
| 355 | sigset_t set; |
| 356 | int nb_sigs; |
bellard | 6eb5733 | 2006-08-06 09:51:25 +0000 | [diff] [blame] | 357 | |
pbrook | faf0796 | 2007-11-11 02:51:17 +0000 | [diff] [blame] | 358 | #ifndef QEMU_IMG |
bellard | 6eb5733 | 2006-08-06 09:51:25 +0000 | [diff] [blame] | 359 | if (qemu_bh_poll()) |
| 360 | return; |
| 361 | #endif |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 362 | sigemptyset(&set); |
| 363 | sigaddset(&set, aio_sig_num); |
| 364 | sigwait(&set, &nb_sigs); |
| 365 | qemu_aio_poll(); |
| 366 | } |
| 367 | |
| 368 | void qemu_aio_wait_end(void) |
| 369 | { |
| 370 | sigprocmask(SIG_SETMASK, &wait_oset, NULL); |
| 371 | } |
| 372 | |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 373 | static RawAIOCB *raw_aio_setup(BlockDriverState *bs, |
| 374 | int64_t sector_num, uint8_t *buf, int nb_sectors, |
| 375 | BlockDriverCompletionFunc *cb, void *opaque) |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 376 | { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 377 | BDRVRawState *s = bs->opaque; |
| 378 | RawAIOCB *acb; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 379 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 380 | if (fd_open(bs) < 0) |
| 381 | return NULL; |
| 382 | |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 383 | acb = qemu_aio_get(bs, cb, opaque); |
| 384 | if (!acb) |
| 385 | return NULL; |
| 386 | acb->aiocb.aio_fildes = s->fd; |
| 387 | acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num; |
| 388 | acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL; |
| 389 | acb->aiocb.aio_buf = buf; |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 390 | if (nb_sectors < 0) |
| 391 | acb->aiocb.aio_nbytes = -nb_sectors; |
| 392 | else |
| 393 | acb->aiocb.aio_nbytes = nb_sectors * 512; |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 394 | acb->aiocb.aio_offset = sector_num * 512; |
| 395 | acb->next = first_aio; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 396 | first_aio = acb; |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 397 | return acb; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 398 | } |
| 399 | |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 400 | static BlockDriverAIOCB *raw_aio_read(BlockDriverState *bs, |
| 401 | int64_t sector_num, uint8_t *buf, int nb_sectors, |
| 402 | BlockDriverCompletionFunc *cb, void *opaque) |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 403 | { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 404 | RawAIOCB *acb; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 405 | |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 406 | acb = raw_aio_setup(bs, sector_num, buf, nb_sectors, cb, opaque); |
| 407 | if (!acb) |
| 408 | return NULL; |
| 409 | if (aio_read(&acb->aiocb) < 0) { |
| 410 | qemu_aio_release(acb); |
| 411 | return NULL; |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 412 | } |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 413 | return &acb->common; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 414 | } |
| 415 | |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 416 | static BlockDriverAIOCB *raw_aio_write(BlockDriverState *bs, |
| 417 | int64_t sector_num, const uint8_t *buf, int nb_sectors, |
| 418 | BlockDriverCompletionFunc *cb, void *opaque) |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 419 | { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 420 | RawAIOCB *acb; |
| 421 | |
| 422 | acb = raw_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque); |
| 423 | if (!acb) |
| 424 | return NULL; |
| 425 | if (aio_write(&acb->aiocb) < 0) { |
| 426 | qemu_aio_release(acb); |
| 427 | return NULL; |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 428 | } |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 429 | return &acb->common; |
| 430 | } |
| 431 | |
| 432 | static void raw_aio_cancel(BlockDriverAIOCB *blockacb) |
| 433 | { |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 434 | int ret; |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 435 | RawAIOCB *acb = (RawAIOCB *)blockacb; |
| 436 | RawAIOCB **pacb; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 437 | |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 438 | ret = aio_cancel(acb->aiocb.aio_fildes, &acb->aiocb); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 439 | if (ret == AIO_NOTCANCELED) { |
| 440 | /* fail safe: if the aio could not be canceled, we wait for |
| 441 | it */ |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 442 | while (aio_error(&acb->aiocb) == EINPROGRESS); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 443 | } |
| 444 | |
| 445 | /* remove the callback from the queue */ |
| 446 | pacb = &first_aio; |
| 447 | for(;;) { |
| 448 | if (*pacb == NULL) { |
| 449 | break; |
| 450 | } else if (*pacb == acb) { |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 451 | *pacb = acb->next; |
| 452 | qemu_aio_release(acb); |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 453 | break; |
| 454 | } |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 455 | pacb = &acb->next; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 456 | } |
| 457 | } |
| 458 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 459 | static void raw_close(BlockDriverState *bs) |
| 460 | { |
| 461 | BDRVRawState *s = bs->opaque; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 462 | if (s->fd >= 0) { |
| 463 | close(s->fd); |
| 464 | s->fd = -1; |
| 465 | } |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 466 | } |
| 467 | |
| 468 | static int raw_truncate(BlockDriverState *bs, int64_t offset) |
| 469 | { |
| 470 | BDRVRawState *s = bs->opaque; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 471 | if (s->type != FTYPE_FILE) |
| 472 | return -ENOTSUP; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 473 | if (ftruncate(s->fd, offset) < 0) |
| 474 | return -errno; |
| 475 | return 0; |
| 476 | } |
| 477 | |
| 478 | static int64_t raw_getlength(BlockDriverState *bs) |
| 479 | { |
| 480 | BDRVRawState *s = bs->opaque; |
| 481 | int fd = s->fd; |
| 482 | int64_t size; |
| 483 | #ifdef _BSD |
| 484 | struct stat sb; |
| 485 | #endif |
| 486 | #ifdef __sun__ |
| 487 | struct dk_minfo minfo; |
| 488 | int rv; |
| 489 | #endif |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 490 | int ret; |
| 491 | |
| 492 | ret = fd_open(bs); |
| 493 | if (ret < 0) |
| 494 | return ret; |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 495 | |
| 496 | #ifdef _BSD |
| 497 | if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) { |
| 498 | #ifdef DIOCGMEDIASIZE |
| 499 | if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size)) |
| 500 | #endif |
| 501 | #ifdef CONFIG_COCOA |
| 502 | size = LONG_LONG_MAX; |
| 503 | #else |
| 504 | size = lseek(fd, 0LL, SEEK_END); |
| 505 | #endif |
| 506 | } else |
| 507 | #endif |
| 508 | #ifdef __sun__ |
| 509 | /* |
| 510 | * use the DKIOCGMEDIAINFO ioctl to read the size. |
| 511 | */ |
| 512 | rv = ioctl ( fd, DKIOCGMEDIAINFO, &minfo ); |
| 513 | if ( rv != -1 ) { |
| 514 | size = minfo.dki_lbsize * minfo.dki_capacity; |
| 515 | } else /* there are reports that lseek on some devices |
| 516 | fails, but irc discussion said that contingency |
| 517 | on contingency was overkill */ |
| 518 | #endif |
| 519 | { |
| 520 | size = lseek(fd, 0, SEEK_END); |
| 521 | } |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 522 | return size; |
| 523 | } |
| 524 | |
| 525 | static int raw_create(const char *filename, int64_t total_size, |
| 526 | const char *backing_file, int flags) |
| 527 | { |
| 528 | int fd; |
| 529 | |
| 530 | if (flags || backing_file) |
| 531 | return -ENOTSUP; |
| 532 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 533 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 534 | 0644); |
| 535 | if (fd < 0) |
| 536 | return -EIO; |
| 537 | ftruncate(fd, total_size * 512); |
| 538 | close(fd); |
| 539 | return 0; |
| 540 | } |
| 541 | |
| 542 | static void raw_flush(BlockDriverState *bs) |
| 543 | { |
| 544 | BDRVRawState *s = bs->opaque; |
| 545 | fsync(s->fd); |
| 546 | } |
| 547 | |
| 548 | BlockDriver bdrv_raw = { |
| 549 | "raw", |
| 550 | sizeof(BDRVRawState), |
| 551 | NULL, /* no probe for protocols */ |
| 552 | raw_open, |
| 553 | NULL, |
| 554 | NULL, |
| 555 | raw_close, |
| 556 | raw_create, |
| 557 | raw_flush, |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 558 | |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 559 | .bdrv_aio_read = raw_aio_read, |
| 560 | .bdrv_aio_write = raw_aio_write, |
| 561 | .bdrv_aio_cancel = raw_aio_cancel, |
pbrook | ce1a14d | 2006-08-07 02:38:06 +0000 | [diff] [blame] | 562 | .aiocb_size = sizeof(RawAIOCB), |
bellard | 83f6409 | 2006-08-01 16:21:11 +0000 | [diff] [blame] | 563 | .protocol_name = "file", |
| 564 | .bdrv_pread = raw_pread, |
| 565 | .bdrv_pwrite = raw_pwrite, |
| 566 | .bdrv_truncate = raw_truncate, |
| 567 | .bdrv_getlength = raw_getlength, |
| 568 | }; |
| 569 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 570 | /***********************************************/ |
| 571 | /* host device */ |
| 572 | |
| 573 | #ifdef CONFIG_COCOA |
| 574 | static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ); |
| 575 | static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ); |
| 576 | |
| 577 | kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator ) |
| 578 | { |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 579 | kern_return_t kernResult; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 580 | mach_port_t masterPort; |
| 581 | CFMutableDictionaryRef classesToMatch; |
| 582 | |
| 583 | kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort ); |
| 584 | if ( KERN_SUCCESS != kernResult ) { |
| 585 | printf( "IOMasterPort returned %d\n", kernResult ); |
| 586 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 587 | |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 588 | classesToMatch = IOServiceMatching( kIOCDMediaClass ); |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 589 | if ( classesToMatch == NULL ) { |
| 590 | printf( "IOServiceMatching returned a NULL dictionary.\n" ); |
| 591 | } else { |
| 592 | CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue ); |
| 593 | } |
| 594 | kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator ); |
| 595 | if ( KERN_SUCCESS != kernResult ) |
| 596 | { |
| 597 | printf( "IOServiceGetMatchingServices returned %d\n", kernResult ); |
| 598 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 599 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 600 | return kernResult; |
| 601 | } |
| 602 | |
| 603 | kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize ) |
| 604 | { |
| 605 | io_object_t nextMedia; |
| 606 | kern_return_t kernResult = KERN_FAILURE; |
| 607 | *bsdPath = '\0'; |
| 608 | nextMedia = IOIteratorNext( mediaIterator ); |
| 609 | if ( nextMedia ) |
| 610 | { |
| 611 | CFTypeRef bsdPathAsCFString; |
| 612 | bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia, CFSTR( kIOBSDNameKey ), kCFAllocatorDefault, 0 ); |
| 613 | if ( bsdPathAsCFString ) { |
| 614 | size_t devPathLength; |
| 615 | strcpy( bsdPath, _PATH_DEV ); |
| 616 | strcat( bsdPath, "r" ); |
| 617 | devPathLength = strlen( bsdPath ); |
| 618 | if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) { |
| 619 | kernResult = KERN_SUCCESS; |
| 620 | } |
| 621 | CFRelease( bsdPathAsCFString ); |
| 622 | } |
| 623 | IOObjectRelease( nextMedia ); |
| 624 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 625 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 626 | return kernResult; |
| 627 | } |
| 628 | |
| 629 | #endif |
| 630 | |
| 631 | static int hdev_open(BlockDriverState *bs, const char *filename, int flags) |
| 632 | { |
| 633 | BDRVRawState *s = bs->opaque; |
| 634 | int fd, open_flags, ret; |
| 635 | |
| 636 | #ifdef CONFIG_COCOA |
| 637 | if (strstart(filename, "/dev/cdrom", NULL)) { |
| 638 | kern_return_t kernResult; |
| 639 | io_iterator_t mediaIterator; |
| 640 | char bsdPath[ MAXPATHLEN ]; |
| 641 | int fd; |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 642 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 643 | kernResult = FindEjectableCDMedia( &mediaIterator ); |
| 644 | kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) ); |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 645 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 646 | if ( bsdPath[ 0 ] != '\0' ) { |
| 647 | strcat(bsdPath,"s0"); |
| 648 | /* some CDs don't have a partition 0 */ |
| 649 | fd = open(bsdPath, O_RDONLY | O_BINARY | O_LARGEFILE); |
| 650 | if (fd < 0) { |
| 651 | bsdPath[strlen(bsdPath)-1] = '1'; |
| 652 | } else { |
| 653 | close(fd); |
| 654 | } |
| 655 | filename = bsdPath; |
| 656 | } |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 657 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 658 | if ( mediaIterator ) |
| 659 | IOObjectRelease( mediaIterator ); |
| 660 | } |
| 661 | #endif |
| 662 | open_flags = O_BINARY; |
| 663 | if ((flags & BDRV_O_ACCESS) == O_RDWR) { |
| 664 | open_flags |= O_RDWR; |
| 665 | } else { |
| 666 | open_flags |= O_RDONLY; |
| 667 | bs->read_only = 1; |
| 668 | } |
balrog | 33f0027 | 2007-12-24 14:33:24 +0000 | [diff] [blame] | 669 | #ifdef O_DIRECT |
| 670 | if (flags & BDRV_O_DIRECT) |
| 671 | open_flags |= O_DIRECT; |
| 672 | #endif |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 673 | |
| 674 | s->type = FTYPE_FILE; |
| 675 | #if defined(__linux__) |
| 676 | if (strstart(filename, "/dev/cd", NULL)) { |
| 677 | /* open will not fail even if no CD is inserted */ |
| 678 | open_flags |= O_NONBLOCK; |
| 679 | s->type = FTYPE_CD; |
| 680 | } else if (strstart(filename, "/dev/fd", NULL)) { |
| 681 | s->type = FTYPE_FD; |
| 682 | s->fd_open_flags = open_flags; |
| 683 | /* open will not fail even if no floppy is inserted */ |
| 684 | open_flags |= O_NONBLOCK; |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 685 | } else if (strstart(filename, "/dev/sg", NULL)) { |
| 686 | bs->sg = 1; |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 687 | } |
| 688 | #endif |
| 689 | fd = open(filename, open_flags, 0644); |
| 690 | if (fd < 0) { |
| 691 | ret = -errno; |
| 692 | if (ret == -EROFS) |
| 693 | ret = -EACCES; |
| 694 | return ret; |
| 695 | } |
| 696 | s->fd = fd; |
| 697 | #if defined(__linux__) |
| 698 | /* close fd so that we can reopen it as needed */ |
| 699 | if (s->type == FTYPE_FD) { |
| 700 | close(s->fd); |
| 701 | s->fd = -1; |
| 702 | s->fd_media_changed = 1; |
| 703 | } |
| 704 | #endif |
| 705 | return 0; |
| 706 | } |
| 707 | |
pbrook | faf0796 | 2007-11-11 02:51:17 +0000 | [diff] [blame] | 708 | #if defined(__linux__) && !defined(QEMU_IMG) |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 709 | |
| 710 | /* Note: we do not have a reliable method to detect if the floppy is |
| 711 | present. The current method is to try to open the floppy at every |
| 712 | I/O and to keep it opened during a few hundreds of ms. */ |
| 713 | static int fd_open(BlockDriverState *bs) |
| 714 | { |
| 715 | BDRVRawState *s = bs->opaque; |
| 716 | int last_media_present; |
| 717 | |
| 718 | if (s->type != FTYPE_FD) |
| 719 | return 0; |
| 720 | last_media_present = (s->fd >= 0); |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 721 | if (s->fd >= 0 && |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 722 | (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) { |
| 723 | close(s->fd); |
| 724 | s->fd = -1; |
| 725 | #ifdef DEBUG_FLOPPY |
| 726 | printf("Floppy closed\n"); |
| 727 | #endif |
| 728 | } |
| 729 | if (s->fd < 0) { |
ths | 5fafdf2 | 2007-09-16 21:08:06 +0000 | [diff] [blame] | 730 | if (s->fd_got_error && |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 731 | (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) { |
| 732 | #ifdef DEBUG_FLOPPY |
| 733 | printf("No floppy (open delayed)\n"); |
| 734 | #endif |
| 735 | return -EIO; |
| 736 | } |
| 737 | s->fd = open(bs->filename, s->fd_open_flags); |
| 738 | if (s->fd < 0) { |
| 739 | s->fd_error_time = qemu_get_clock(rt_clock); |
| 740 | s->fd_got_error = 1; |
| 741 | if (last_media_present) |
| 742 | s->fd_media_changed = 1; |
| 743 | #ifdef DEBUG_FLOPPY |
| 744 | printf("No floppy\n"); |
| 745 | #endif |
| 746 | return -EIO; |
| 747 | } |
| 748 | #ifdef DEBUG_FLOPPY |
| 749 | printf("Floppy opened\n"); |
| 750 | #endif |
| 751 | } |
| 752 | if (!last_media_present) |
| 753 | s->fd_media_changed = 1; |
| 754 | s->fd_open_time = qemu_get_clock(rt_clock); |
| 755 | s->fd_got_error = 0; |
| 756 | return 0; |
| 757 | } |
| 758 | #else |
| 759 | static int fd_open(BlockDriverState *bs) |
| 760 | { |
| 761 | return 0; |
| 762 | } |
| 763 | #endif |
| 764 | |
| 765 | #if defined(__linux__) |
| 766 | |
| 767 | static int raw_is_inserted(BlockDriverState *bs) |
| 768 | { |
| 769 | BDRVRawState *s = bs->opaque; |
| 770 | int ret; |
| 771 | |
| 772 | switch(s->type) { |
| 773 | case FTYPE_CD: |
| 774 | ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); |
| 775 | if (ret == CDS_DISC_OK) |
| 776 | return 1; |
| 777 | else |
| 778 | return 0; |
| 779 | break; |
| 780 | case FTYPE_FD: |
| 781 | ret = fd_open(bs); |
| 782 | return (ret >= 0); |
| 783 | default: |
| 784 | return 1; |
| 785 | } |
| 786 | } |
| 787 | |
| 788 | /* currently only used by fdc.c, but a CD version would be good too */ |
| 789 | static int raw_media_changed(BlockDriverState *bs) |
| 790 | { |
| 791 | BDRVRawState *s = bs->opaque; |
| 792 | |
| 793 | switch(s->type) { |
| 794 | case FTYPE_FD: |
| 795 | { |
| 796 | int ret; |
| 797 | /* XXX: we do not have a true media changed indication. It |
| 798 | does not work if the floppy is changed without trying |
| 799 | to read it */ |
| 800 | fd_open(bs); |
| 801 | ret = s->fd_media_changed; |
| 802 | s->fd_media_changed = 0; |
| 803 | #ifdef DEBUG_FLOPPY |
| 804 | printf("Floppy changed=%d\n", ret); |
| 805 | #endif |
| 806 | return ret; |
| 807 | } |
| 808 | default: |
| 809 | return -ENOTSUP; |
| 810 | } |
| 811 | } |
| 812 | |
| 813 | static int raw_eject(BlockDriverState *bs, int eject_flag) |
| 814 | { |
| 815 | BDRVRawState *s = bs->opaque; |
| 816 | |
| 817 | switch(s->type) { |
| 818 | case FTYPE_CD: |
| 819 | if (eject_flag) { |
| 820 | if (ioctl (s->fd, CDROMEJECT, NULL) < 0) |
| 821 | perror("CDROMEJECT"); |
| 822 | } else { |
| 823 | if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0) |
| 824 | perror("CDROMEJECT"); |
| 825 | } |
| 826 | break; |
| 827 | case FTYPE_FD: |
| 828 | { |
| 829 | int fd; |
| 830 | if (s->fd >= 0) { |
| 831 | close(s->fd); |
| 832 | s->fd = -1; |
| 833 | } |
| 834 | fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); |
| 835 | if (fd >= 0) { |
| 836 | if (ioctl(fd, FDEJECT, 0) < 0) |
| 837 | perror("FDEJECT"); |
| 838 | close(fd); |
| 839 | } |
| 840 | } |
| 841 | break; |
| 842 | default: |
| 843 | return -ENOTSUP; |
| 844 | } |
| 845 | return 0; |
| 846 | } |
| 847 | |
| 848 | static int raw_set_locked(BlockDriverState *bs, int locked) |
| 849 | { |
| 850 | BDRVRawState *s = bs->opaque; |
| 851 | |
| 852 | switch(s->type) { |
| 853 | case FTYPE_CD: |
| 854 | if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) { |
| 855 | /* Note: an error can happen if the distribution automatically |
| 856 | mounts the CD-ROM */ |
| 857 | // perror("CDROM_LOCKDOOR"); |
| 858 | } |
| 859 | break; |
| 860 | default: |
| 861 | return -ENOTSUP; |
| 862 | } |
| 863 | return 0; |
| 864 | } |
| 865 | |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 866 | static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
| 867 | { |
| 868 | BDRVRawState *s = bs->opaque; |
| 869 | |
| 870 | return ioctl(s->fd, req, buf); |
| 871 | } |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 872 | #else |
| 873 | |
| 874 | static int raw_is_inserted(BlockDriverState *bs) |
| 875 | { |
| 876 | return 1; |
| 877 | } |
| 878 | |
| 879 | static int raw_media_changed(BlockDriverState *bs) |
| 880 | { |
| 881 | return -ENOTSUP; |
| 882 | } |
| 883 | |
| 884 | static int raw_eject(BlockDriverState *bs, int eject_flag) |
| 885 | { |
| 886 | return -ENOTSUP; |
| 887 | } |
| 888 | |
| 889 | static int raw_set_locked(BlockDriverState *bs, int locked) |
| 890 | { |
| 891 | return -ENOTSUP; |
| 892 | } |
| 893 | |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 894 | static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) |
| 895 | { |
| 896 | return -ENOTSUP; |
| 897 | } |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 898 | #endif /* !linux */ |
| 899 | |
| 900 | BlockDriver bdrv_host_device = { |
| 901 | "host_device", |
| 902 | sizeof(BDRVRawState), |
| 903 | NULL, /* no probe for protocols */ |
| 904 | hdev_open, |
| 905 | NULL, |
| 906 | NULL, |
| 907 | raw_close, |
| 908 | NULL, |
| 909 | raw_flush, |
ths | 3b46e62 | 2007-09-17 08:09:54 +0000 | [diff] [blame] | 910 | |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 911 | .bdrv_aio_read = raw_aio_read, |
| 912 | .bdrv_aio_write = raw_aio_write, |
| 913 | .bdrv_aio_cancel = raw_aio_cancel, |
| 914 | .aiocb_size = sizeof(RawAIOCB), |
| 915 | .bdrv_pread = raw_pread, |
| 916 | .bdrv_pwrite = raw_pwrite, |
| 917 | .bdrv_getlength = raw_getlength, |
| 918 | |
| 919 | /* removable device support */ |
| 920 | .bdrv_is_inserted = raw_is_inserted, |
| 921 | .bdrv_media_changed = raw_media_changed, |
| 922 | .bdrv_eject = raw_eject, |
| 923 | .bdrv_set_locked = raw_set_locked, |
ths | 985a03b | 2007-12-24 16:10:43 +0000 | [diff] [blame] | 924 | /* generic scsi device */ |
| 925 | .bdrv_ioctl = raw_ioctl, |
bellard | 19cb373 | 2006-08-19 11:45:59 +0000 | [diff] [blame] | 926 | }; |