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
This commit is contained in:
parent
624a7e1f4f
commit
16969d1448
@ -155,21 +155,29 @@ read_image_file(const char *path, void **buf, int32_t *size)
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -56,6 +56,7 @@ nvme_print_controller(struct nvme_controller_data *cdata)
|
||||
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 *cdata)
|
||||
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 *cdata)
|
||||
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",
|
||||
|
Loading…
Reference in New Issue
Block a user