]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
virtio: blk: introduce virtio-block erase support
authorDmitrii Merkurev <dimorinny@google.com>
Wed, 6 Mar 2024 18:59:18 +0000 (18:59 +0000)
committerSimon Glass <sjg@chromium.org>
Fri, 18 Oct 2024 20:10:21 +0000 (14:10 -0600)
Co-developed-by: Cody Schuffelen <schuffelen@google.com>
Signed-off-by: Cody Schuffelen <schuffelen@google.com>
Signed-off-by: Dmitrii Merkurev <dimorinny@google.com>
Cc: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
Cc: Simon Glass <sjg@chromium.org>
Cc: Mattijs Korpershoek <mkorpershoek@baylibre.com>
Cc: Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
Tested-by: Mattijs Korpershoek <mkorpershoek@baylibre.com> # sandbox
drivers/virtio/virtio_blk.c
drivers/virtio/virtio_blk.h

index 3404f61eba5ffdb10f9ec64631c1c51e2eece2d5..2f999fc8bbecf8d2d9f61c60990a442f3d54c9a6 100644 (file)
@@ -18,30 +18,82 @@ struct virtio_blk_priv {
        struct virtqueue *vq;
 };
 
+static const u32 feature[] = {
+       VIRTIO_BLK_F_WRITE_ZEROES
+};
+
+static void virtio_blk_init_header_sg(struct udevice *dev, u64 sector, u32 type,
+                                     struct virtio_blk_outhdr *out_hdr, struct virtio_sg *sg)
+{
+       const bool sector_is_needed = type == VIRTIO_BLK_T_IN ||
+                                     type == VIRTIO_BLK_T_OUT;
+
+       out_hdr->type = cpu_to_virtio32(dev, type);
+       out_hdr->sector = cpu_to_virtio64(dev, sector_is_needed ? sector : 0);
+
+       sg->addr = out_hdr;
+       sg->length = sizeof(*out_hdr);
+}
+
+static void virtio_blk_init_write_zeroes_sg(struct udevice *dev, u64 sector, lbaint_t blkcnt,
+                                           struct virtio_blk_discard_write_zeroes *wz,
+                                           struct virtio_sg *sg)
+{
+       wz->sector = cpu_to_virtio64(dev, sector);
+       wz->num_sectors = cpu_to_virtio32(dev, blkcnt);
+       wz->flags = cpu_to_virtio32(dev, 0);
+
+       sg->addr = wz;
+       sg->length = sizeof(*wz);
+}
+
+static void virtio_blk_init_status_sg(u8 *status, struct virtio_sg *sg)
+{
+       sg->addr = status;
+       sg->length = sizeof(*status);
+}
+
+static void virtio_blk_init_data_sg(void *buffer, lbaint_t blkcnt, struct virtio_sg *sg)
+{
+       sg->addr = buffer;
+       sg->length = blkcnt * 512;
+}
+
 static ulong virtio_blk_do_req(struct udevice *dev, u64 sector,
                               lbaint_t blkcnt, void *buffer, u32 type)
 {
        struct virtio_blk_priv *priv = dev_get_priv(dev);
+       struct virtio_blk_outhdr out_hdr;
+       struct virtio_blk_discard_write_zeroes wz_hdr;
        unsigned int num_out = 0, num_in = 0;
+       struct virtio_sg hdr_sg, wz_sg, data_sg, status_sg;
        struct virtio_sg *sgs[3];
        u8 status;
        int ret;
 
-       struct virtio_blk_outhdr out_hdr = {
-               .type = cpu_to_virtio32(dev, type),
-               .sector = cpu_to_virtio64(dev, sector),
-       };
-       struct virtio_sg hdr_sg = { &out_hdr, sizeof(out_hdr) };
-       struct virtio_sg data_sg = { buffer, blkcnt * 512 };
-       struct virtio_sg status_sg = { &status, sizeof(status) };
-
+       virtio_blk_init_header_sg(dev, sector, type, &out_hdr, &hdr_sg);
        sgs[num_out++] = &hdr_sg;
 
-       if (type & VIRTIO_BLK_T_OUT)
-               sgs[num_out++] = &data_sg;
-       else
-               sgs[num_out + num_in++] = &data_sg;
-
+       switch (type) {
+       case VIRTIO_BLK_T_IN:
+       case VIRTIO_BLK_T_OUT:
+               virtio_blk_init_data_sg(buffer, blkcnt, &data_sg);
+               if (type & VIRTIO_BLK_T_OUT)
+                       sgs[num_out++] = &data_sg;
+               else
+                       sgs[num_out + num_in++] = &data_sg;
+               break;
+
+       case VIRTIO_BLK_T_WRITE_ZEROES:
+               virtio_blk_init_write_zeroes_sg(dev, sector, blkcnt, &wz_hdr, &wz_sg);
+               sgs[num_out++] = &wz_sg;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       virtio_blk_init_status_sg(&status, &status_sg);
        sgs[num_out + num_in++] = &status_sg;
        log_debug("dev=%s, active=%d, priv=%p, priv->vq=%p\n", dev->name,
                  device_active(dev), priv, priv->vq);
@@ -75,6 +127,15 @@ static ulong virtio_blk_write(struct udevice *dev, lbaint_t start,
                                 VIRTIO_BLK_T_OUT);
 }
 
+static ulong virtio_blk_erase(struct udevice *dev, lbaint_t start,
+                             lbaint_t blkcnt)
+{
+       if (!virtio_has_feature(dev, VIRTIO_BLK_F_WRITE_ZEROES))
+               return -EOPNOTSUPP;
+
+       return virtio_blk_do_req(dev, start, blkcnt, NULL, VIRTIO_BLK_T_WRITE_ZEROES);
+}
+
 static int virtio_blk_bind(struct udevice *dev)
 {
        struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
@@ -104,7 +165,8 @@ static int virtio_blk_bind(struct udevice *dev)
        desc->bdev = dev;
 
        /* Indicate what driver features we support */
-       virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0);
+       virtio_driver_features_init(uc_priv, feature, ARRAY_SIZE(feature),
+                                   NULL, 0);
 
        return 0;
 }
@@ -131,6 +193,7 @@ static int virtio_blk_probe(struct udevice *dev)
 static const struct blk_ops virtio_blk_ops = {
        .read   = virtio_blk_read,
        .write  = virtio_blk_write,
+       .erase  = virtio_blk_erase,
 };
 
 U_BOOT_DRIVER(virtio_blk) = {
index 8d8e02fa2eab9aadbd1d3dd2ee39e3e4279541a4..b37ba264df4b6ab6d7ed4c2cbfe580a58710799e 100644 (file)
@@ -17,6 +17,8 @@
 #define VIRTIO_BLK_F_BLK_SIZE  6       /* Block size of disk is available */
 #define VIRTIO_BLK_F_TOPOLOGY  10      /* Topology information is available */
 #define VIRTIO_BLK_F_MQ                12      /* Support more than one vq */
+#define VIRTIO_BLK_F_DISCARD   13      /* Discard is supported */
+#define VIRTIO_BLK_F_WRITE_ZEROES      14      /* Write zeroes is supported */
 
 /* Legacy feature bits */
 #ifndef VIRTIO_BLK_NO_LEGACY
@@ -65,6 +67,39 @@ struct __packed virtio_blk_config {
 
        /* number of vqs, only available when VIRTIO_BLK_F_MQ is set */
        __u16 num_queues;
+
+       /* the next 3 entries are guarded by VIRTIO_BLK_F_DISCARD */
+       /*
+        * The maximum discard sectors (in 512-byte sectors) for
+        * one segment.
+        */
+       __u32 max_discard_sectors;
+       /*
+        * The maximum number of discard segments in a
+        * discard command.
+        */
+       __u32 max_discard_seg;
+       /* Discard commands must be aligned to this number of sectors. */
+       __u32 discard_sector_alignment;
+
+       /* the next 3 entries are guarded by VIRTIO_BLK_F_WRITE_ZEROES */
+       /*
+        * The maximum number of write zeroes sectors (in 512-byte sectors) in
+        * one segment.
+        */
+       __u32 max_write_zeroes_sectors;
+       /*
+        * The maximum number of segments in a write zeroes
+        * command.
+        */
+       __u32 max_write_zeroes_seg;
+       /*
+        * Set if a VIRTIO_BLK_T_WRITE_ZEROES request may result in the
+        * deallocation of one or more of the sectors.
+        */
+       __u8 write_zeroes_may_unmap;
+
+       __u8 unused1[3];
 };
 
 /*
@@ -93,6 +128,9 @@ struct __packed virtio_blk_config {
 /* Get device ID command */
 #define VIRTIO_BLK_T_GET_ID    8
 
+/* Write zeroes command */
+#define VIRTIO_BLK_T_WRITE_ZEROES 13
+
 #ifndef VIRTIO_BLK_NO_LEGACY
 /* Barrier before this op */
 #define VIRTIO_BLK_T_BARRIER   0x80000000
@@ -112,6 +150,15 @@ struct virtio_blk_outhdr {
        __virtio64 sector;
 };
 
+struct virtio_blk_discard_write_zeroes {
+       /* discard/write zeroes start sector */
+       __virtio64 sector;
+       /* number of discard/write zeroes sectors */
+       __virtio32 num_sectors;
+       /* flags for this range */
+       __virtio32 flags;
+};
+
 #ifndef VIRTIO_BLK_NO_LEGACY
 struct virtio_scsi_inhdr {
        __virtio32 errors;