}
/* retrieves a MCTP-messsage-sized chunk of log page data. offset and len are
- * specified within the args->data area */
+ * specified within the args->data area. The `offset` parameter is a relative
+ * offset to the args->lpo !
+ *
+ * What's more, we change the LPO of original command to chunk the request
+ * message into proper size which is allowed by MI interface. One reason is that
+ * this option seems to be supported better by devices. For more information
+ * about this option, please check https://github.com/linux-nvme/libnvme/pull/539
+ * */
static int __nvme_mi_admin_get_log(nvme_mi_ctrl_t ctrl,
const struct nvme_get_log_args *args,
off_t offset, size_t *lenp, bool final)
{
+ __u64 log_page_offset = args->lpo + offset;
struct nvme_mi_admin_resp_hdr resp_hdr;
struct nvme_mi_admin_req_hdr req_hdr;
struct nvme_mi_resp resp;
(args->lid & 0xff));
req_hdr.cdw11 = cpu_to_le32(args->lsi << 16 |
ndw >> 16);
- req_hdr.cdw12 = cpu_to_le32(args->lpo & 0xffffffff);
- req_hdr.cdw13 = cpu_to_le32(args->lpo >> 32);
+ req_hdr.cdw12 = cpu_to_le32(log_page_offset & 0xffffffff);
+ req_hdr.cdw13 = cpu_to_le32(log_page_offset >> 32);
req_hdr.cdw14 = cpu_to_le32(args->csi << 24 |
(args->ot ? 1 : 0) << 23 |
args->uuidx);
req_hdr.flags = 0x1;
req_hdr.dlen = cpu_to_le32(len & 0xffffffff);
- if (offset) {
- req_hdr.flags |= 0x2;
- req_hdr.doff = cpu_to_le32(offset);
- }
nvme_mi_calc_req_mic(&req);
return -1;
}
+ if (args->ot && (args->len > max_xfer_size)) {
+ errno = EINVAL;
+ return -1;
+ }
+
for (xfer_offset = 0; xfer_offset < args->len;) {
size_t xfered_size, cur_xfer_size = max_xfer_size;
bool final;
struct nvme_mi_resp *resp,
void *data)
{
+ uint32_t log_page_offset_lower;
struct log_data *ldata = data;
uint32_t len, off;
__u8 *rq_hdr;
off = rq_hdr[31] << 24 | rq_hdr[30] << 16 | rq_hdr[29] << 8 | rq_hdr[28];
len = rq_hdr[35] << 24 | rq_hdr[34] << 16 | rq_hdr[33] << 8 | rq_hdr[32];
+ /* From the MI message's Command Dword 12 */
+ log_page_offset_lower = rq_hdr[55] << 24 | rq_hdr[54] << 16 | rq_hdr[53] << 8 | rq_hdr[52];
+
/* we should have a full-sized start and middle, and a short end */
switch (ldata->n) {
case 0:
+ assert(log_page_offset_lower == 0);
assert(len == 4096);
assert(off == 0);
break;
case 1:
+ assert(log_page_offset_lower == 4096);
assert(len == 4096);
- assert(off == 4096);
+ assert(off == 0);
break;
case 2:
+ assert(log_page_offset_lower == 8192);
assert(len == 4);
- assert(off == 4096 * 2);
+ assert(off == 0);
break;
default:
assert(0);
args.lid = 1;
args.log = buf;
args.len = sizeof(buf);
+ args.lpo = 0;
+ args.ot = false;
rc = nvme_mi_admin_get_log(ctrl, &args);