Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

nvmet: Do not require SGL for PCI target controller commands

Support for SGL is optional for the PCI transport. Modify
nvmet_req_init() to not require the NVME_CMD_SGL_METABUF command flag to
be set if the target controller transport type is NVMF_TRTYPE_PCI.
In addition to this, the NVMe base specification v2.1 mandate that all
admin commands use PRP, that is, have CDW0.PSDT cleared to 0. Modify
nvmet_parse_admin_cmd() to check this.

Finally, modify nvmet_check_transfer_len() and
nvmet_check_data_len_lte() to return the appropriate error status
depending on the command using SGL or PRP. Since for fabrics
nvmet_req_init() checks that a command uses SGL, always, this change
affects only PCI target controllers.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>

authored by

Damien Le Moal and committed by
Keith Busch
1ad8630f 60d3cd85

+26 -6
+5
drivers/nvme/target/admin-cmd.c
··· 1478 1478 if (unlikely(ret)) 1479 1479 return ret; 1480 1480 1481 + /* For PCI controllers, admin commands shall not use SGL. */ 1482 + if (nvmet_is_pci_ctrl(req->sq->ctrl) && !req->sq->qid && 1483 + cmd->common.flags & NVME_CMD_SGL_ALL) 1484 + return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; 1485 + 1481 1486 if (nvmet_is_passthru_req(req)) 1482 1487 return nvmet_parse_passthru_admin_cmd(req); 1483 1488
+21 -6
drivers/nvme/target/core.c
··· 1122 1122 /* 1123 1123 * For fabrics, PSDT field shall describe metadata pointer (MPTR) that 1124 1124 * contains an address of a single contiguous physical buffer that is 1125 - * byte aligned. 1125 + * byte aligned. For PCI controllers, this is optional so not enforced. 1126 1126 */ 1127 1127 if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) { 1128 - req->error_loc = offsetof(struct nvme_common_command, flags); 1129 - status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; 1130 - goto fail; 1128 + if (!req->sq->ctrl || !nvmet_is_pci_ctrl(req->sq->ctrl)) { 1129 + req->error_loc = 1130 + offsetof(struct nvme_common_command, flags); 1131 + status = NVME_SC_INVALID_FIELD | NVME_STATUS_DNR; 1132 + goto fail; 1133 + } 1131 1134 } 1132 1135 1133 1136 if (unlikely(!req->sq->ctrl)) ··· 1185 1182 bool nvmet_check_transfer_len(struct nvmet_req *req, size_t len) 1186 1183 { 1187 1184 if (unlikely(len != req->transfer_len)) { 1185 + u16 status; 1186 + 1188 1187 req->error_loc = offsetof(struct nvme_common_command, dptr); 1189 - nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR); 1188 + if (req->cmd->common.flags & NVME_CMD_SGL_ALL) 1189 + status = NVME_SC_SGL_INVALID_DATA; 1190 + else 1191 + status = NVME_SC_INVALID_FIELD; 1192 + nvmet_req_complete(req, status | NVME_STATUS_DNR); 1190 1193 return false; 1191 1194 } 1192 1195 ··· 1203 1194 bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len) 1204 1195 { 1205 1196 if (unlikely(data_len > req->transfer_len)) { 1197 + u16 status; 1198 + 1206 1199 req->error_loc = offsetof(struct nvme_common_command, dptr); 1207 - nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_STATUS_DNR); 1200 + if (req->cmd->common.flags & NVME_CMD_SGL_ALL) 1201 + status = NVME_SC_SGL_INVALID_DATA; 1202 + else 1203 + status = NVME_SC_INVALID_FIELD; 1204 + nvmet_req_complete(req, status | NVME_STATUS_DNR); 1208 1205 return false; 1209 1206 } 1210 1207