summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'block-raw-posix.c')
-rw-r--r--block-raw-posix.c195
1 files changed, 172 insertions, 23 deletions
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 9b1a7ee6b..2c2e48840 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -56,6 +56,7 @@
#ifdef __FreeBSD__
#include <signal.h>
#include <sys/disk.h>
+#include <sys/cdio.h>
#endif
#ifdef __OpenBSD__
@@ -111,6 +112,9 @@ typedef struct BDRVRawState {
int fd_got_error;
int fd_media_changed;
#endif
+#if defined(__FreeBSD__)
+ int cd_open_flags;
+#endif
uint8_t* aligned_buf;
} BDRVRawState;
@@ -118,6 +122,12 @@ static int posix_aio_init(void);
static int fd_open(BlockDriverState *bs);
+#if defined(__FreeBSD__)
+static int cd_open(BlockDriverState *bs);
+#endif
+
+static int raw_is_inserted(BlockDriverState *bs);
+
static int raw_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVRawState *s = bs->opaque;
@@ -770,6 +780,9 @@ static int64_t raw_getlength(BlockDriverState *bs)
int64_t size;
#ifdef HOST_BSD
struct stat sb;
+#ifdef __FreeBSD__
+ int reopened = 0;
+#endif
#endif
#ifdef __sun__
struct dk_minfo minfo;
@@ -782,6 +795,9 @@ static int64_t raw_getlength(BlockDriverState *bs)
return ret;
#ifdef HOST_BSD
+#ifdef __FreeBSD__
+again:
+#endif
if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
#ifdef DIOCGMEDIASIZE
if (ioctl(fd, DIOCGMEDIASIZE, (off_t *)&size))
@@ -800,6 +816,19 @@ static int64_t raw_getlength(BlockDriverState *bs)
#else
size = lseek(fd, 0LL, SEEK_END);
#endif
+#ifdef __FreeBSD__
+ switch(s->type) {
+ case FTYPE_CD:
+ /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
+ if (size == 2048LL * (unsigned)-1)
+ size = 0;
+ /* XXX no disc? maybe we need to reopen... */
+ if (size <= 0 && !reopened && cd_open(bs) >= 0) {
+ reopened = 1;
+ goto again;
+ }
+ }
+#endif
} else
#endif
#ifdef __sun__
@@ -990,6 +1019,14 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
bs->sg = 1;
}
#endif
+#if defined(__FreeBSD__)
+ if (strstart(filename, "/dev/cd", NULL) ||
+ strstart(filename, "/dev/acd", NULL)) {
+ s->type = FTYPE_CD;
+ s->cd_open_flags = open_flags;
+ }
+#endif
+ s->fd = -1;
fd = open(filename, open_flags, 0644);
if (fd < 0) {
ret = -errno;
@@ -998,6 +1035,11 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
return ret;
}
s->fd = fd;
+#if defined(__FreeBSD__)
+ /* make sure the door isnt locked at this time */
+ if (s->type == FTYPE_CD)
+ ioctl (s->fd, CDIOCALLOW);
+#endif
#if defined(__linux__)
/* close fd so that we can reopen it as needed */
if (s->type == FTYPE_FD) {
@@ -1164,16 +1206,76 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
return ioctl(s->fd, req, buf);
}
-#else
+
+static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+ unsigned long int req, void *buf,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ RawAIOCB *acb;
+
+ acb = raw_aio_setup(bs, 0, buf, 0, cb, opaque);
+ if (!acb)
+ return NULL;
+
+ acb->aiocb.aio_ioctl_cmd = req;
+ if (qemu_paio_ioctl(&acb->aiocb) < 0) {
+ raw_aio_remove(acb);
+ return NULL;
+ }
+
+ return &acb->common;
+}
+
+#elif defined(__FreeBSD__)
static int fd_open(BlockDriverState *bs)
{
+ BDRVRawState *s = bs->opaque;
+
+ /* this is just to ensure s->fd is sane (its called by io ops) */
+ if (s->fd >= 0)
+ return 0;
+ return -EIO;
+}
+
+static int cd_open(BlockDriverState *bs)
+{
+#if defined(__FreeBSD__)
+ BDRVRawState *s = bs->opaque;
+ int fd;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ /* XXX force reread of possibly changed/newly loaded disc,
+ * FreeBSD seems to not notice sometimes... */
+ if (s->fd >= 0)
+ close (s->fd);
+ fd = open(bs->filename, s->cd_open_flags, 0644);
+ if (fd < 0) {
+ s->fd = -1;
+ return -EIO;
+ }
+ s->fd = fd;
+ /* make sure the door isnt locked at this time */
+ ioctl (s->fd, CDIOCALLOW);
+ }
+#endif
return 0;
}
static int raw_is_inserted(BlockDriverState *bs)
{
- return 1;
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ return (raw_getlength(bs) > 0);
+ case FTYPE_FD:
+ /* XXX handle this */
+ /* FALLTHRU */
+ default:
+ return 1;
+ }
}
static int raw_media_changed(BlockDriverState *bs)
@@ -1183,45 +1285,95 @@ static int raw_media_changed(BlockDriverState *bs)
static int raw_eject(BlockDriverState *bs, int eject_flag)
{
- return -ENOTSUP;
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (s->fd < 0)
+ return -ENOTSUP;
+ (void) ioctl (s->fd, CDIOCALLOW);
+ if (eject_flag) {
+ if (ioctl (s->fd, CDIOCEJECT) < 0)
+ perror("CDIOCEJECT");
+ } else {
+ if (ioctl (s->fd, CDIOCCLOSE) < 0)
+ perror("CDIOCCLOSE");
+ }
+ if (cd_open(bs) < 0)
+ return -ENOTSUP;
+ break;
+ case FTYPE_FD:
+ /* XXX handle this */
+ /* FALLTHRU */
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
}
static int raw_set_locked(BlockDriverState *bs, int locked)
{
- return -ENOTSUP;
+ BDRVRawState *s = bs->opaque;
+
+ switch(s->type) {
+ case FTYPE_CD:
+ if (s->fd < 0)
+ return -ENOTSUP;
+ if (ioctl (s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) {
+ /* Note: an error can happen if the distribution automatically
+ mounts the CD-ROM */
+ // perror("CDROM_LOCKDOOR");
+ }
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
}
static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
return -ENOTSUP;
}
-#endif /* !linux */
+#else /* !linux && !FreeBSD */
+
+static int fd_open(BlockDriverState *bs)
+{
+ return 0;
+}
+
+static int raw_is_inserted(BlockDriverState *bs)
+{
+ return 1;
+}
+
+static int raw_media_changed(BlockDriverState *bs)
+{
+ return -ENOTSUP;
+}
-static int raw_sg_send_command(BlockDriverState *bs, void *buf, int count)
+static int raw_eject(BlockDriverState *bs, int eject_flag)
{
- return raw_pwrite(bs, -1, buf, count);
+ return -ENOTSUP;
}
-static int raw_sg_recv_response(BlockDriverState *bs, void *buf, int count)
+static int raw_set_locked(BlockDriverState *bs, int locked)
{
- return raw_pread(bs, -1, buf, count);
+ return -ENOTSUP;
}
-static BlockDriverAIOCB *raw_sg_aio_read(BlockDriverState *bs,
- void *buf, int count,
- BlockDriverCompletionFunc *cb,
- void *opaque)
+static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
{
- return raw_aio_read(bs, 0, buf, -(int64_t)count, cb, opaque);
+ return -ENOTSUP;
}
-static BlockDriverAIOCB *raw_sg_aio_write(BlockDriverState *bs,
- void *buf, int count,
- BlockDriverCompletionFunc *cb,
- void *opaque)
+static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+ unsigned long int req, void *buf,
+ BlockDriverCompletionFunc *cb, void *opaque)
{
- return raw_aio_write(bs, 0, buf, -(int64_t)count, cb, opaque);
+ return -ENOTSUP;
}
+#endif /* !linux && !FreeBSD */
BlockDriver bdrv_host_device = {
.format_name = "host_device",
@@ -1248,8 +1400,5 @@ BlockDriver bdrv_host_device = {
.bdrv_set_locked = raw_set_locked,
/* generic scsi device */
.bdrv_ioctl = raw_ioctl,
- .bdrv_sg_send_command = raw_sg_send_command,
- .bdrv_sg_recv_response = raw_sg_recv_response,
- .bdrv_sg_aio_read = raw_sg_aio_read,
- .bdrv_sg_aio_write = raw_sg_aio_write,
+ .bdrv_aio_ioctl = raw_aio_ioctl,
};