diff options
Diffstat (limited to 'Documentation/lguest/lguest.c')
-rw-r--r-- | Documentation/lguest/lguest.c | 62 |
1 files changed, 41 insertions, 21 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 4c1fc65a8b3d..3be8ab2a886a 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c | |||
@@ -131,6 +131,9 @@ struct device | |||
131 | /* Any queues attached to this device */ | 131 | /* Any queues attached to this device */ |
132 | struct virtqueue *vq; | 132 | struct virtqueue *vq; |
133 | 133 | ||
134 | /* Handle status being finalized (ie. feature bits stable). */ | ||
135 | void (*ready)(struct device *me); | ||
136 | |||
134 | /* Device-specific data. */ | 137 | /* Device-specific data. */ |
135 | void *priv; | 138 | void *priv; |
136 | }; | 139 | }; |
@@ -925,24 +928,40 @@ static void enable_fd(int fd, struct virtqueue *vq) | |||
925 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); | 928 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); |
926 | } | 929 | } |
927 | 930 | ||
928 | /* When the Guest asks us to reset a device, it's is fairly easy. */ | 931 | /* When the Guest tells us they updated the status field, we handle it. */ |
929 | static void reset_device(struct device *dev) | 932 | static void update_device_status(struct device *dev) |
930 | { | 933 | { |
931 | struct virtqueue *vq; | 934 | struct virtqueue *vq; |
932 | 935 | ||
933 | verbose("Resetting device %s\n", dev->name); | 936 | /* This is a reset. */ |
934 | /* Clear the status. */ | 937 | if (dev->desc->status == 0) { |
935 | dev->desc->status = 0; | 938 | verbose("Resetting device %s\n", dev->name); |
936 | 939 | ||
937 | /* Clear any features they've acked. */ | 940 | /* Clear any features they've acked. */ |
938 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, | 941 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, |
939 | dev->desc->feature_len); | 942 | dev->desc->feature_len); |
940 | 943 | ||
941 | /* Zero out the virtqueues. */ | 944 | /* Zero out the virtqueues. */ |
942 | for (vq = dev->vq; vq; vq = vq->next) { | 945 | for (vq = dev->vq; vq; vq = vq->next) { |
943 | memset(vq->vring.desc, 0, | 946 | memset(vq->vring.desc, 0, |
944 | vring_size(vq->config.num, getpagesize())); | 947 | vring_size(vq->config.num, getpagesize())); |
945 | vq->last_avail_idx = 0; | 948 | vq->last_avail_idx = 0; |
949 | } | ||
950 | } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { | ||
951 | warnx("Device %s configuration FAILED", dev->name); | ||
952 | } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { | ||
953 | unsigned int i; | ||
954 | |||
955 | verbose("Device %s OK: offered", dev->name); | ||
956 | for (i = 0; i < dev->desc->feature_len; i++) | ||
957 | verbose(" %08x", get_feature_bits(dev)[i]); | ||
958 | verbose(", accepted"); | ||
959 | for (i = 0; i < dev->desc->feature_len; i++) | ||
960 | verbose(" %08x", get_feature_bits(dev) | ||
961 | [dev->desc->feature_len+i]); | ||
962 | |||
963 | if (dev->ready) | ||
964 | dev->ready(dev); | ||
946 | } | 965 | } |
947 | } | 966 | } |
948 | 967 | ||
@@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr) | |||
954 | 973 | ||
955 | /* Check each device and virtqueue. */ | 974 | /* Check each device and virtqueue. */ |
956 | for (i = devices.dev; i; i = i->next) { | 975 | for (i = devices.dev; i; i = i->next) { |
957 | /* Notifications to device descriptors reset the device. */ | 976 | /* Notifications to device descriptors update device status. */ |
958 | if (from_guest_phys(addr) == i->desc) { | 977 | if (from_guest_phys(addr) == i->desc) { |
959 | reset_device(i); | 978 | update_device_status(i); |
960 | return; | 979 | return; |
961 | } | 980 | } |
962 | 981 | ||
@@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd, | |||
1170 | dev->handle_input = handle_input; | 1189 | dev->handle_input = handle_input; |
1171 | dev->name = name; | 1190 | dev->name = name; |
1172 | dev->vq = NULL; | 1191 | dev->vq = NULL; |
1192 | dev->ready = NULL; | ||
1173 | 1193 | ||
1174 | /* Append to device list. Prepending to a single-linked list is | 1194 | /* Append to device list. Prepending to a single-linked list is |
1175 | * easier, but the user expects the devices to be arranged on the bus | 1195 | * easier, but the user expects the devices to be arranged on the bus |
@@ -1398,7 +1418,7 @@ static bool service_io(struct device *dev) | |||
1398 | struct vblk_info *vblk = dev->priv; | 1418 | struct vblk_info *vblk = dev->priv; |
1399 | unsigned int head, out_num, in_num, wlen; | 1419 | unsigned int head, out_num, in_num, wlen; |
1400 | int ret; | 1420 | int ret; |
1401 | struct virtio_blk_inhdr *in; | 1421 | u8 *in; |
1402 | struct virtio_blk_outhdr *out; | 1422 | struct virtio_blk_outhdr *out; |
1403 | struct iovec iov[dev->vq->vring.num]; | 1423 | struct iovec iov[dev->vq->vring.num]; |
1404 | off64_t off; | 1424 | off64_t off; |
@@ -1416,7 +1436,7 @@ static bool service_io(struct device *dev) | |||
1416 | head, out_num, in_num); | 1436 | head, out_num, in_num); |
1417 | 1437 | ||
1418 | out = convert(&iov[0], struct virtio_blk_outhdr); | 1438 | out = convert(&iov[0], struct virtio_blk_outhdr); |
1419 | in = convert(&iov[out_num+in_num-1], struct virtio_blk_inhdr); | 1439 | in = convert(&iov[out_num+in_num-1], u8); |
1420 | off = out->sector * 512; | 1440 | off = out->sector * 512; |
1421 | 1441 | ||
1422 | /* The block device implements "barriers", where the Guest indicates | 1442 | /* The block device implements "barriers", where the Guest indicates |
@@ -1430,7 +1450,7 @@ static bool service_io(struct device *dev) | |||
1430 | * It'd be nice if we supported eject, for example, but we don't. */ | 1450 | * It'd be nice if we supported eject, for example, but we don't. */ |
1431 | if (out->type & VIRTIO_BLK_T_SCSI_CMD) { | 1451 | if (out->type & VIRTIO_BLK_T_SCSI_CMD) { |
1432 | fprintf(stderr, "Scsi commands unsupported\n"); | 1452 | fprintf(stderr, "Scsi commands unsupported\n"); |
1433 | in->status = VIRTIO_BLK_S_UNSUPP; | 1453 | *in = VIRTIO_BLK_S_UNSUPP; |
1434 | wlen = sizeof(*in); | 1454 | wlen = sizeof(*in); |
1435 | } else if (out->type & VIRTIO_BLK_T_OUT) { | 1455 | } else if (out->type & VIRTIO_BLK_T_OUT) { |
1436 | /* Write */ | 1456 | /* Write */ |
@@ -1453,7 +1473,7 @@ static bool service_io(struct device *dev) | |||
1453 | errx(1, "Write past end %llu+%u", off, ret); | 1473 | errx(1, "Write past end %llu+%u", off, ret); |
1454 | } | 1474 | } |
1455 | wlen = sizeof(*in); | 1475 | wlen = sizeof(*in); |
1456 | in->status = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); | 1476 | *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR); |
1457 | } else { | 1477 | } else { |
1458 | /* Read */ | 1478 | /* Read */ |
1459 | 1479 | ||
@@ -1466,10 +1486,10 @@ static bool service_io(struct device *dev) | |||
1466 | verbose("READ from sector %llu: %i\n", out->sector, ret); | 1486 | verbose("READ from sector %llu: %i\n", out->sector, ret); |
1467 | if (ret >= 0) { | 1487 | if (ret >= 0) { |
1468 | wlen = sizeof(*in) + ret; | 1488 | wlen = sizeof(*in) + ret; |
1469 | in->status = VIRTIO_BLK_S_OK; | 1489 | *in = VIRTIO_BLK_S_OK; |
1470 | } else { | 1490 | } else { |
1471 | wlen = sizeof(*in); | 1491 | wlen = sizeof(*in); |
1472 | in->status = VIRTIO_BLK_S_IOERR; | 1492 | *in = VIRTIO_BLK_S_IOERR; |
1473 | } | 1493 | } |
1474 | } | 1494 | } |
1475 | 1495 | ||