nvmet: export I/O characteristics attributes in Identify
authorBart Van Assche <bvanassche@acm.org>
Fri, 28 Jun 2019 16:53:30 +0000 (09:53 -0700)
committerChristoph Hellwig <hch@lst.de>
Tue, 9 Jul 2019 21:15:37 +0000 (14:15 -0700)
Make the NVMe NAWUN, NAWUPF, NACWU, NPWG, NPWA, NPDG and NOWS attributes
available to initator systems for the block backend.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/io-cmd-bdev.c
drivers/nvme/target/nvmet.h

index 9f72d515fc4b30a3785b396910660074ad076cf4..4dc12ea52f23cbdd970428daf36b66ed694adfd3 100644 (file)
@@ -442,6 +442,9 @@ static void nvmet_execute_identify_ns(struct nvmet_req *req)
                break;
         }
 
+       if (ns->bdev)
+               nvmet_bdev_set_limits(ns->bdev, id);
+
        /*
         * We just provide a single LBA format that matches what the
         * underlying device reports.
index 7a1cf6437a6a528c48964b65025b7851902bdcd5..de0bff70ebb68b963880724d6bdc052a14cb6ea5 100644 (file)
@@ -8,6 +8,45 @@
 #include <linux/module.h>
 #include "nvmet.h"
 
+void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id)
+{
+       const struct queue_limits *ql = &bdev_get_queue(bdev)->limits;
+       /* Number of physical blocks per logical block. */
+       const u32 ppl = ql->physical_block_size / ql->logical_block_size;
+       /* Physical blocks per logical block, 0's based. */
+       const __le16 ppl0b = to0based(ppl);
+
+       /*
+        * For NVMe 1.2 and later, bit 1 indicates that the fields NAWUN,
+        * NAWUPF, and NACWU are defined for this namespace and should be
+        * used by the host for this namespace instead of the AWUN, AWUPF,
+        * and ACWU fields in the Identify Controller data structure. If
+        * any of these fields are zero that means that the corresponding
+        * field from the identify controller data structure should be used.
+        */
+       id->nsfeat |= 1 << 1;
+       id->nawun = ppl0b;
+       id->nawupf = ppl0b;
+       id->nacwu = ppl0b;
+
+       /*
+        * Bit 4 indicates that the fields NPWG, NPWA, NPDG, NPDA, and
+        * NOWS are defined for this namespace and should be used by
+        * the host for I/O optimization.
+        */
+       id->nsfeat |= 1 << 4;
+       /* NPWG = Namespace Preferred Write Granularity. 0's based */
+       id->npwg = ppl0b;
+       /* NPWA = Namespace Preferred Write Alignment. 0's based */
+       id->npwa = id->npwg;
+       /* NPDG = Namespace Preferred Deallocate Granularity. 0's based */
+       id->npdg = to0based(ql->discard_granularity / ql->logical_block_size);
+       /* NPDG = Namespace Preferred Deallocate Alignment */
+       id->npda = id->npdg;
+       /* NOWS = Namespace Optimal Write Size */
+       id->nows = to0based(ql->io_opt / ql->logical_block_size);
+}
+
 int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
 {
        int ret;
index dc270944bb25253e629700dc696d1aa342f05443..6ee66c6107391899898f812a4b4347b284d6c333 100644 (file)
@@ -365,6 +365,7 @@ u16 nvmet_set_feat_async_event(struct nvmet_req *req, u32 mask);
 void nvmet_execute_async_event(struct nvmet_req *req);
 
 u16 nvmet_parse_connect_cmd(struct nvmet_req *req);
+void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id);
 u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req);
 u16 nvmet_file_parse_io_cmd(struct nvmet_req *req);
 u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
@@ -492,4 +493,11 @@ static inline u32 nvmet_rw_len(struct nvmet_req *req)
 }
 
 u16 errno_to_nvme_status(struct nvmet_req *req, int errno);
+
+/* Convert a 32-bit number to a 16-bit 0's based number */
+static inline __le16 to0based(u32 a)
+{
+       return cpu_to_le16(max(1U, min(1U << 16, a)) - 1);
+}
+
 #endif /* _NVMET_H */