From: Ana Bobillo <[email protected]>

nvme_blk_probe() takes the LBA data size (log2 of the block size) of the
namespace's current LBA format as the device reports it, and shifts by
it: 1 << ns->lba_shift is undefined for a value of 31 or more, and
nvme_blk_rw() sizes each transfer with
1 << (dev->max_transfer_shift - ns->lba_shift), a negative shift for a
block larger than the maximum transfer size of the controller.

Check it, through a new nvme_lba_shift(), against the block sizes
blk_valid_blksz() accepts and the maximum transfer size. nvme_init()
skips a namespace with an unsupported LBA data size, as it skips an
inactive one, rather than create a block device for it that then fails
to probe, failing nvme_init() and leaving the namespaces it has already
probed on a controller that failed to probe. nvme_blk_probe() checks the
value it uses again.

Signed-off-by: Ana Bobillo <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
---
(no changes since v1)

 drivers/nvme/nvme.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index c815a967137..3df9b531bfd 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -15,6 +15,7 @@
 #include <time.h>
 #include <dm/device-internal.h>
 #include <linux/compat.h>
+#include <linux/log2.h>
 #include "nvme.h"
 
 #define NVME_Q_DEPTH           2
@@ -701,6 +702,26 @@ int nvme_scan_namespace(void)
        return 0;
 }
 
+/**
+ * nvme_lba_shift() - Get the LBA data size of a namespace
+ *
+ * @dev: NVMe controller
+ * @id: Identify Namespace data of the namespace
+ * Return: log2 of its block size, or -EINVAL if that size is not supported
+ */
+static int nvme_lba_shift(struct nvme_dev *dev, struct nvme_id_ns *id)
+{
+       u8 ds = id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ds;
+
+       if (ds < ilog2(DEFAULT_BLKSZ) || ds > ilog2(BLK_MAX_BLKSZ) ||
+           ds > dev->max_transfer_shift) {
+               log_err("Unsupported LBA data size 2^%d\n", ds);
+               return -EINVAL;
+       }
+
+       return ds;
+}
+
 static int nvme_blk_probe(struct udevice *udev)
 {
        struct nvme_dev *ndev = dev_get_priv(udev->parent);
@@ -708,6 +729,7 @@ static int nvme_blk_probe(struct udevice *udev)
        struct nvme_ns *ns = dev_get_priv(udev);
        u8 flbas;
        struct nvme_id_ns *id;
+       int ret;
 
        id = memalign(ndev->page_size, sizeof(struct nvme_id_ns));
        if (!id)
@@ -724,7 +746,12 @@ static int nvme_blk_probe(struct udevice *udev)
        memcpy(&ns->eui64, &id->eui64, sizeof(id->eui64));
        flbas = id->flbas & NVME_NS_FLBAS_LBA_MASK;
        ns->flbas = flbas;
-       ns->lba_shift = id->lbaf[flbas].ds;
+       ret = nvme_lba_shift(ndev, id);
+       if (ret < 0) {
+               free(id);
+               return ret;
+       }
+       ns->lba_shift = ret;
        list_add(&ns->list, &ndev->namespaces);
 
        desc->lba = le64_to_cpu(id->nsze);
@@ -899,6 +926,10 @@ int nvme_init(struct udevice *udev)
                if (!id->nsze)
                        continue;
 
+               /* skip a namespace whose block size is not supported */
+               if (nvme_lba_shift(ndev, id) < 0)
+                       continue;
+
                /*
                 * Encode the namespace id to the device name so that
                 * we can extract it when doing the probe.

Reply via email to