It is not possible to get 64-bit results from the passthru commands, what prevents from getting for the Capabilities (CAP) property value. As a result, it is not possible to implement IOL's NVMe Conformance test 4.3 Case 1 for Fabrics targets [1] (page 123). This issue has been already discussed [2], but without a solution. This patch solves the problem by adding new ioctls with a new passthru structure, including 64-bit results. The older ioctls stay unchanged. [1] https://www.iol.unh.edu/sites/default/files/testsuites/nvme/UNH-IOL_NVMe_Conformance_Test_Suite_v11.0.pdf [2] http://lists.infradead.org/pipermail/linux-nvme/2018-June/018791.html
Unified · Split
| @@ -850,7 +850,7 @@ out: · 849 unmodified lines | |||
| 850 | static int nvme_submit_user_cmd(struct request_queue *q, | 850 | static int nvme_submit_user_cmd(struct request_queue *q, |
| 851 | struct nvme_command *cmd, void __user *ubuffer, | 851 | struct nvme_command *cmd, void __user *ubuffer, |
| 852 | unsigned bufflen, void __user *meta_buffer, unsigned meta_len, | 852 | unsigned bufflen, void __user *meta_buffer, unsigned meta_len, |
| 853 | u32 meta_seed, u32 *result, unsigned timeout) | 853 | u32 meta_seed, u64 *result, unsigned timeout) |
| 854 | { | 854 | { |
| 855 | bool write = nvme_is_write(cmd); | 855 | bool write = nvme_is_write(cmd); |
| 856 | struct nvme_ns *ns = q->queuedata; | 856 | struct nvme_ns *ns = q->queuedata; |
| @@ -891,7 +891,7 @@ static int nvme_submit_user_cmd(struct request_queue *q, · 34 unmodified lines | |||
| 891 | else | 891 | else |
| 892 | ret = nvme_req(req)->status; | 892 | ret = nvme_req(req)->status; |
| 893 | if (result) | 893 | if (result) |
| 894 | *result = le32_to_cpu(nvme_req(req)->result.u32); | 894 | *result = le64_to_cpu(nvme_req(req)->result.u64); |
| 895 | if (meta && !ret && !write) { | 895 | if (meta && !ret && !write) { |
| 896 | if (copy_to_user(meta_buffer, meta, meta_len)) | 896 | if (copy_to_user(meta_buffer, meta, meta_len)) |
| 897 | ret = -EFAULT; | 897 | ret = -EFAULT; |
| @@ -1338,6 +1338,54 @@ static int nvme_user_cmd(struct nvme_ctrl *ctrl, struct nvme_ns *ns, · 440 unmodified lines | |||
| 1338 | struct nvme_command c; | 1338 | struct nvme_command c; |
| 1339 | unsigned timeout = 0; | 1339 | unsigned timeout = 0; |
| 1340 | u32 effects; | 1340 | u32 effects; |
| 1341 | u64 result; | ||
| 1342 | int status; | ||
| 1343 | |||
| 1344 | if (!capable(CAP_SYS_ADMIN)) | ||
| 1345 | return -EACCES; | ||
| 1346 | if (copy_from_user(&cmd, ucmd, sizeof(cmd))) | ||
| 1347 | return -EFAULT; | ||
| 1348 | if (cmd.flags) | ||
| 1349 | return -EINVAL; | ||
| 1350 | |||
| 1351 | memset(&c, 0, sizeof(c)); | ||
| 1352 | c.common.opcode = cmd.opcode; | ||
| 1353 | c.common.flags = cmd.flags; | ||
| 1354 | c.common.nsid = cpu_to_le32(cmd.nsid); | ||
| 1355 | c.common.cdw2[0] = cpu_to_le32(cmd.cdw2); | ||
| 1356 | c.common.cdw2[1] = cpu_to_le32(cmd.cdw3); | ||
| 1357 | c.common.cdw10 = cpu_to_le32(cmd.cdw10); | ||
| 1358 | c.common.cdw11 = cpu_to_le32(cmd.cdw11); | ||
| 1359 | c.common.cdw12 = cpu_to_le32(cmd.cdw12); | ||
| 1360 | c.common.cdw13 = cpu_to_le32(cmd.cdw13); | ||
| 1361 | c.common.cdw14 = cpu_to_le32(cmd.cdw14); | ||
| 1362 | c.common.cdw15 = cpu_to_le32(cmd.cdw15); | ||
| 1363 | |||
| 1364 | if (cmd.timeout_ms) | ||
| 1365 | timeout = msecs_to_jiffies(cmd.timeout_ms); | ||
| 1366 | |||
| 1367 | effects = nvme_passthru_start(ctrl, ns, cmd.opcode); | ||
| 1368 | status = nvme_submit_user_cmd(ns ? ns->queue : ctrl->admin_q, &c, | ||
| 1369 | (void __user *)(uintptr_t)cmd.addr, cmd.data_len, | ||
| 1370 | (void __user *)(uintptr_t)cmd.metadata, | ||
| 1371 | cmd.metadata_len, 0, &result, timeout); | ||
| 1372 | nvme_passthru_end(ctrl, effects); | ||
| 1373 | |||
| 1374 | if (status >= 0) { | ||
| 1375 | if (put_user(result, &ucmd->result)) | ||
| 1376 | return -EFAULT; | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | return status; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | static int nvme_user_cmd64(struct nvme_ctrl *ctrl, struct nvme_ns *ns, | ||
| 1383 | struct nvme_passthru_cmd64 __user *ucmd) | ||
| 1384 | { | ||
| 1385 | struct nvme_passthru_cmd64 cmd; | ||
| 1386 | struct nvme_command c; | ||
| 1387 | unsigned timeout = 0; | ||
| 1388 | u32 effects; | ||
| 1341 | int status; | 1389 | int status; |
| 1342 | 1390 | ||
| 1343 | if (!capable(CAP_SYS_ADMIN)) | 1391 | if (!capable(CAP_SYS_ADMIN)) |
| @@ -1408,6 +1456,41 @@ static void nvme_put_ns_from_disk(struct nvme_ns_head *head, int idx) · 64 unmodified lines | |||
| 1408 | srcu_read_unlock(&head->srcu, idx); | 1456 | srcu_read_unlock(&head->srcu, idx); |
| 1409 | } | 1457 | } |
| 1410 | 1458 | ||
| 1459 | static bool is_ctrl_ioctl(unsigned int cmd) | ||
| 1460 | { | ||
| 1461 | if (cmd == NVME_IOCTL_ADMIN_CMD || cmd == NVME_IOCTL_ADMIN64_CMD) | ||
| 1462 | return true; | ||
| 1463 | if (is_sed_ioctl(cmd)) | ||
| 1464 | return true; | ||
| 1465 | return false; | ||
| 1466 | } | ||
| 1467 | |||
| 1468 | static int nvme_handle_ctrl_ioctl(struct nvme_ns *ns, unsigned int cmd, | ||
| 1469 | void __user *argp, | ||
| 1470 | struct nvme_ns_head *head, | ||
| 1471 | int srcu_idx) | ||
| 1472 | { | ||
| 1473 | struct nvme_ctrl *ctrl = ns->ctrl; | ||
| 1474 | int ret; | ||
| 1475 | |||
| 1476 | nvme_get_ctrl(ns->ctrl); | ||
| 1477 | nvme_put_ns_from_disk(head, srcu_idx); | ||
| 1478 | |||
| 1479 | switch (cmd) { | ||
| 1480 | case NVME_IOCTL_ADMIN_CMD: | ||
| 1481 | ret = nvme_user_cmd(ctrl, NULL, argp); | ||
| 1482 | break; | ||
| 1483 | case NVME_IOCTL_ADMIN64_CMD: | ||
| 1484 | ret = nvme_user_cmd64(ctrl, NULL, argp); | ||
| 1485 | break; | ||
| 1486 | default: | ||
| 1487 | ret = sed_ioctl(ctrl->opal_dev, cmd, argp); | ||
| 1488 | break; | ||
| 1489 | } | ||
| 1490 | nvme_put_ctrl(ctrl); | ||
| 1491 | return ret; | ||
| 1492 | } | ||
| 1493 | |||
| 1411 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, | 1494 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, |
| 1412 | unsigned int cmd, unsigned long arg) | 1495 | unsigned int cmd, unsigned long arg) |
| 1413 | { | 1496 | { |
| @@ -1425,20 +1508,8 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, · 11 unmodified lines | |||
| 1425 | * seperately and drop the ns SRCU reference early. This avoids a | 1508 | * seperately and drop the ns SRCU reference early. This avoids a |
| 1426 | * deadlock when deleting namespaces using the passthrough interface. | 1509 | * deadlock when deleting namespaces using the passthrough interface. |
| 1427 | */ | 1510 | */ |
| 1428 | if (cmd == NVME_IOCTL_ADMIN_CMD || is_sed_ioctl(cmd)) { | 1511 | if (is_ctrl_ioctl(cmd)) |
| 1429 | struct nvme_ctrl *ctrl = ns->ctrl; | 1512 | return nvme_handle_ctrl_ioctl(ns, cmd, argp, head, srcu_idx); |
| 1430 | |||
| 1431 | nvme_get_ctrl(ns->ctrl); | ||
| 1432 | nvme_put_ns_from_disk(head, srcu_idx); | ||
| 1433 | |||
| 1434 | if (cmd == NVME_IOCTL_ADMIN_CMD) | ||
| 1435 | ret = nvme_user_cmd(ctrl, NULL, argp); | ||
| 1436 | else | ||
| 1437 | ret = sed_ioctl(ctrl->opal_dev, cmd, argp); | ||
| 1438 | |||
| 1439 | nvme_put_ctrl(ctrl); | ||
| 1440 | return ret; | ||
| 1441 | } | ||
| 1442 | 1513 | ||
| 1443 | switch (cmd) { | 1514 | switch (cmd) { |
| 1444 | case NVME_IOCTL_ID: | 1515 | case NVME_IOCTL_ID: |
| @@ -1451,6 +1522,9 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, · 6 unmodified lines | |||
| 1451 | case NVME_IOCTL_SUBMIT_IO: | 1522 | case NVME_IOCTL_SUBMIT_IO: |
| 1452 | ret = nvme_submit_io(ns, argp); | 1523 | ret = nvme_submit_io(ns, argp); |
| 1453 | break; | 1524 | break; |
| 1525 | case NVME_IOCTL_IO64_CMD: | ||
| 1526 | ret = nvme_user_cmd64(ns->ctrl, ns, argp); | ||
| 1527 | break; | ||
| 1454 | default: | 1528 | default: |
| 1455 | if (ns->ndev) | 1529 | if (ns->ndev) |
| 1456 | ret = nvme_nvm_ioctl(ns, cmd, arg); | 1530 | ret = nvme_nvm_ioctl(ns, cmd, arg); |
| @@ -2852,6 +2926,8 @@ static long nvme_dev_ioctl(struct file *file, unsigned int cmd, · 1395 unmodified lines | |||
| 2852 | switch (cmd) { | 2926 | switch (cmd) { |
| 2853 | case NVME_IOCTL_ADMIN_CMD: | 2927 | case NVME_IOCTL_ADMIN_CMD: |
| 2854 | return nvme_user_cmd(ctrl, NULL, argp); | 2928 | return nvme_user_cmd(ctrl, NULL, argp); |
| 2929 | case NVME_IOCTL_ADMIN64_CMD: | ||
| 2930 | return nvme_user_cmd64(ctrl, NULL, argp); | ||
| 2855 | case NVME_IOCTL_IO_CMD: | 2931 | case NVME_IOCTL_IO_CMD: |
| 2856 | return nvme_dev_user_cmd(ctrl, argp); | 2932 | return nvme_dev_user_cmd(ctrl, argp); |
| 2857 | case NVME_IOCTL_RESET: | 2933 | case NVME_IOCTL_RESET: |
| @@ -45,6 +45,27 @@ struct nvme_passthru_cmd { · 44 unmodified lines | |||
| 45 | __u32 result; | 45 | __u32 result; |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | struct nvme_passthru_cmd64 { | ||
| 49 | __u8 opcode; | ||
| 50 | __u8 flags; | ||
| 51 | __u16 rsvd1; | ||
| 52 | __u32 nsid; | ||
| 53 | __u32 cdw2; | ||
| 54 | __u32 cdw3; | ||
| 55 | __u64 metadata; | ||
| 56 | __u64 addr; | ||
| 57 | __u32 metadata_len; | ||
| 58 | __u32 data_len; | ||
| 59 | __u32 cdw10; | ||
| 60 | __u32 cdw11; | ||
| 61 | __u32 cdw12; | ||
| 62 | __u32 cdw13; | ||
| 63 | __u32 cdw14; | ||
| 64 | __u32 cdw15; | ||
| 65 | __u32 timeout_ms; | ||
| 66 | __u64 result; | ||
| 67 | }; | ||
| 68 | |||
| 48 | #define nvme_admin_cmd nvme_passthru_cmd | 69 | #define nvme_admin_cmd nvme_passthru_cmd |
| 49 | 70 | ||
| 50 | #define NVME_IOCTL_ID _IO('N', 0x40) | 71 | #define NVME_IOCTL_ID _IO('N', 0x40) |
| @@ -54,5 +75,7 @@ struct nvme_passthru_cmd { · 3 unmodified lines | |||
| 54 | #define NVME_IOCTL_RESET _IO('N', 0x44) | 75 | #define NVME_IOCTL_RESET _IO('N', 0x44) |
| 55 | #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) | 76 | #define NVME_IOCTL_SUBSYS_RESET _IO('N', 0x45) |
| 56 | #define NVME_IOCTL_RESCAN _IO('N', 0x46) | 77 | #define NVME_IOCTL_RESCAN _IO('N', 0x46) |
| 78 | #define NVME_IOCTL_ADMIN64_CMD _IOWR('N', 0x47, struct nvme_passthru_cmd64) | ||
| 79 | #define NVME_IOCTL_IO64_CMD _IOWR('N', 0x48, struct nvme_passthru_cmd64) | ||
| 57 | 80 | ||
| 58 | #endif /* _UAPI_LINUX_NVME_IOCTL_H */ | 81 | #endif /* _UAPI_LINUX_NVME_IOCTL_H */ |