From: Martin George Date: Tue, 21 Mar 2023 08:49:11 +0000 (+0530) Subject: nvme: fix block count and data size logic X-Git-Tag: v2.4~26 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=8a2bfa5be4d3;p=users%2Fsagi%2Fnvme-cli.git nvme: fix block count and data size logic The required block count and data size is not automatically set for a namespace device in submit_io(). Also it is the user specified block count and not the actual required block count that is passed to the ioctl data structure, often leading to nvme passthrough io errors. For e.g. an nvme read on a 512b block size namespace device with data size set to 4K ends up with the below error: nvme read /dev/nvme0n1 -s 0 -z 4096 NVMe status: Data SGL Length Invalid: The length of a Data SGL is too short or too long and the controller does not support SGL transfers longer than the amount of data to be transferred(0x400f) This read is successful only when the appropriate block count is passed from the command line: nvme read /dev/nvme0n1 -s 0 -z 4096 -c 7 read: Success So fix this by deriving the required block count and data size based on the logical block size and passing them appropriately to the respective ioctl data structure. And while we are at it, remove a couple of superfluous braces in this part of the code. Signed-off-by: Martin George --- diff --git a/nvme.c b/nvme.c index c852f69e..52b10d3b 100644 --- a/nvme.c +++ b/nvme.c @@ -7213,7 +7213,7 @@ static int submit_io(int opcode, char *command, const char *desc, int dfd, mfd; int flags = opcode & 1 ? O_RDONLY : O_WRONLY | O_CREAT; int mode = S_IRUSR | S_IWUSR |S_IRGRP | S_IWGRP| S_IROTH; - __u16 control = 0; + __u16 control = 0, nblocks = 0; __u32 dsmgmt = 0; int logical_block_size = 0; unsigned long long buffer_size = 0, mbuffer_size = 0; @@ -7403,9 +7403,14 @@ static int submit_io(int opcode, char *command, const char *desc, if (cfg.data_size < buffer_size) { fprintf(stderr, "Rounding data size to fit block count (%lld bytes)\n", buffer_size); - } else { + } else buffer_size = cfg.data_size; - } + + /* Get the required block count. Note this is a zeroes based value. */ + nblocks = ((buffer_size + (logical_block_size - 1)) / logical_block_size) - 1; + + /* Update the data size based on the required block count */ + buffer_size = (nblocks + 1) * logical_block_size; buffer = nvme_alloc(buffer_size, &huge); if (!buffer) { @@ -7478,7 +7483,7 @@ static int submit_io(int opcode, char *command, const char *desc, printf("nsid : %02x\n", cfg.namespace_id); printf("flags : %02x\n", 0); printf("control : %04x\n", control); - printf("nblocks : %04x\n", cfg.block_count); + printf("nblocks : %04x\n", nblocks); printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)mbuffer); printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)buffer); printf("slba : %"PRIx64"\n", (uint64_t)cfg.start_block); @@ -7499,7 +7504,7 @@ static int submit_io(int opcode, char *command, const char *desc, .fd = dev_fd(dev), .nsid = cfg.namespace_id, .slba = cfg.start_block, - .nlb = cfg.block_count, + .nlb = nblocks, .control = control, .dsm = cfg.dsmgmt, .sts = sts,