Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 21 Sep 2020 15:45:49 +0000 (UTC)
From:      David Bright <dab@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r365948 - head/sbin/nvmecontrol
Message-ID:  <202009211545.08LFjnXg004155@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dab
Date: Mon Sep 21 15:45:49 2020
New Revision: 365948
URL: https://svnweb.freebsd.org/changeset/base/365948

Log:
  Honor the FWUG value of some drives in nvmecontrol
  
  nvmecontrol tries to upload firmware in chunks as large as it thinks
  the device permits. It fails to take into account the FWUG value used
  by some drives to advertise the size and alignment limits for firmware
  chunks.
  
    - Use the firwmare update granularity value from the
    - If the granularity is not reported or not restricted, fall back to
      the previously existing logic that calculates the max transfer
      size based on MDTS.
    - Add firmware update granularity to the identify-controller output.
  
  Reviewed by:	imp (previous version), chuck
  Obtained from:	Dell EMC Isilon
  MFC after:	1 week
  Sponsored by:	Dell EMC Isilon
  Differential Revision:	https://reviews.freebsd.org/D26390

Modified:
  head/sbin/nvmecontrol/firmware.c
  head/sbin/nvmecontrol/identify_ext.c

Modified: head/sbin/nvmecontrol/firmware.c
==============================================================================
--- head/sbin/nvmecontrol/firmware.c	Mon Sep 21 15:44:23 2020	(r365947)
+++ head/sbin/nvmecontrol/firmware.c	Mon Sep 21 15:45:49 2020	(r365948)
@@ -155,21 +155,29 @@ read_image_file(const char *path, void **buf, int32_t 
 }
 
 static void
-update_firmware(int fd, uint8_t *payload, int32_t payload_size)
+update_firmware(int fd, uint8_t *payload, int32_t payload_size, uint8_t fwug)
 {
 	struct nvme_pt_command	pt;
+	uint64_t                max_xfer_size;
 	int32_t			off, resid, size;
 	void			*chunk;
 
 	off = 0;
 	resid = payload_size;
 
-	if ((chunk = aligned_alloc(PAGE_SIZE, NVME_MAX_XFER_SIZE)) == NULL)
-		errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE);
+	if (fwug != 0 && fwug != 0xFF)
+		max_xfer_size = ((uint64_t)fwug << 12);
+	else if (ioctl(fd, NVME_GET_MAX_XFER_SIZE, &max_xfer_size) < 0)
+ 		err(1, "query max transfer size failed");
+ 	if (max_xfer_size > NVME_MAX_XFER_SIZE)
+ 		max_xfer_size = NVME_MAX_XFER_SIZE;
 
+	if ((chunk = aligned_alloc(PAGE_SIZE, max_xfer_size)) == NULL)
+		errx(1, "unable to malloc %zd bytes", (size_t)max_xfer_size);
+
 	while (resid > 0) {
-		size = (resid >= NVME_MAX_XFER_SIZE) ?
-		    NVME_MAX_XFER_SIZE : resid;
+		size = (resid >= (int32_t)max_xfer_size) ?
+		    max_xfer_size : resid;
 		memcpy(chunk, payload + off, size);
 
 		memset(&pt, 0, sizeof(pt));
@@ -333,7 +341,7 @@ firmware(const struct cmd *f, int argc, char *argv[])
 	}
 
 	if (opt.fw_img != NULL) {
-		update_firmware(fd, buf, size);
+		update_firmware(fd, buf, size, cdata.fwug);
 		if (opt.activate)
 			activate_action = NVME_AA_REPLACE_ACTIVATE;
 		else

Modified: head/sbin/nvmecontrol/identify_ext.c
==============================================================================
--- head/sbin/nvmecontrol/identify_ext.c	Mon Sep 21 15:44:23 2020	(r365947)
+++ head/sbin/nvmecontrol/identify_ext.c	Mon Sep 21 15:45:49 2020	(r365948)
@@ -56,6 +56,7 @@ nvme_print_controller(struct nvme_controller_data *cda
 	uint8_t ns_smart;
 	uint8_t sqes_max, sqes_min;
 	uint8_t cqes_max, cqes_min;
+	uint8_t fwug;
 
 	oncs = cdata->oncs;
 	compare = (oncs >> NVME_CTRLR_DATA_ONCS_COMPARE_SHIFT) &
@@ -79,6 +80,7 @@ nvme_print_controller(struct nvme_controller_data *cda
 		NVME_CTRLR_DATA_FRMW_NUM_SLOTS_MASK;
 	fw_slot1_ro = (cdata->frmw >> NVME_CTRLR_DATA_FRMW_SLOT1_RO_SHIFT) &
 		NVME_CTRLR_DATA_FRMW_SLOT1_RO_MASK;
+	fwug = cdata->fwug;
 
 	ns_smart = (cdata->lpa >> NVME_CTRLR_DATA_LPA_NS_SMART_SHIFT) &
 		NVME_CTRLR_DATA_LPA_NS_SMART_MASK;
@@ -192,6 +194,13 @@ nvme_print_controller(struct nvme_controller_data *cda
 		    uint128_to_str(to128(cdata->untncap.unvmcap),
 		    cbuf, sizeof(cbuf)));
 	}
+	printf("Firmware Update Granularity: %02x ", fwug);
+	if (fwug == 0)
+		printf("(Not Reported)\n");
+	else if (fwug == 0xFF)
+		printf("(No Granularity)\n");
+	else
+		printf("(%d bytes)\n", ((uint32_t)fwug << 12));
 	printf("Host Buffer Preferred Size:  %llu bytes\n",
 	    (long long unsigned)cdata->hmpre * 4096);
 	printf("Host Buffer Minimum Size:    %llu bytes\n",



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202009211545.08LFjnXg004155>