diff options
| author | Jens Axboe <axboe@kernel.dk> | 2019-04-11 11:36:41 -0400 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2019-04-11 11:36:41 -0400 |
| commit | c0c14e935032abd6ee6828840a83df1de49d4838 (patch) | |
| tree | 6e5d46c670e1ed35f4cddadfec3f7b8c563d23cb | |
| parent | a3761c3c91209b58b6f33bf69dd8bb8ec0c9d925 (diff) | |
| parent | d808b7f759b50acf0784ce6230ffa63e12ef465d (diff) | |
Merge branch 'nvme-5.1' of git://git.infradead.org/nvme into for-linus
Pull NVMe fixes from Christoph:
"Two nvme fixes for 5.1 - fixing the initial CSN for nvme-fc, and handle
log page offsets properly in the target."
* 'nvme-5.1' of git://git.infradead.org/nvme:
nvmet: fix discover log page when offsets are used
nvme-fc: correct csn initialization and increments on error
| -rw-r--r-- | drivers/nvme/host/fc.c | 20 | ||||
| -rw-r--r-- | drivers/nvme/target/admin-cmd.c | 5 | ||||
| -rw-r--r-- | drivers/nvme/target/discovery.c | 68 | ||||
| -rw-r--r-- | drivers/nvme/target/nvmet.h | 1 | ||||
| -rw-r--r-- | include/linux/nvme.h | 9 |
5 files changed, 73 insertions, 30 deletions
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index f3b9d91ba0df..6d8451356eac 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c | |||
| @@ -1845,7 +1845,7 @@ nvme_fc_init_queue(struct nvme_fc_ctrl *ctrl, int idx) | |||
| 1845 | memset(queue, 0, sizeof(*queue)); | 1845 | memset(queue, 0, sizeof(*queue)); |
| 1846 | queue->ctrl = ctrl; | 1846 | queue->ctrl = ctrl; |
| 1847 | queue->qnum = idx; | 1847 | queue->qnum = idx; |
| 1848 | atomic_set(&queue->csn, 1); | 1848 | atomic_set(&queue->csn, 0); |
| 1849 | queue->dev = ctrl->dev; | 1849 | queue->dev = ctrl->dev; |
| 1850 | 1850 | ||
| 1851 | if (idx > 0) | 1851 | if (idx > 0) |
| @@ -1887,7 +1887,7 @@ nvme_fc_free_queue(struct nvme_fc_queue *queue) | |||
| 1887 | */ | 1887 | */ |
| 1888 | 1888 | ||
| 1889 | queue->connection_id = 0; | 1889 | queue->connection_id = 0; |
| 1890 | atomic_set(&queue->csn, 1); | 1890 | atomic_set(&queue->csn, 0); |
| 1891 | } | 1891 | } |
| 1892 | 1892 | ||
| 1893 | static void | 1893 | static void |
| @@ -2183,7 +2183,6 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, | |||
| 2183 | { | 2183 | { |
| 2184 | struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu; | 2184 | struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu; |
| 2185 | struct nvme_command *sqe = &cmdiu->sqe; | 2185 | struct nvme_command *sqe = &cmdiu->sqe; |
| 2186 | u32 csn; | ||
| 2187 | int ret, opstate; | 2186 | int ret, opstate; |
| 2188 | 2187 | ||
| 2189 | /* | 2188 | /* |
| @@ -2198,8 +2197,6 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, | |||
| 2198 | 2197 | ||
| 2199 | /* format the FC-NVME CMD IU and fcp_req */ | 2198 | /* format the FC-NVME CMD IU and fcp_req */ |
| 2200 | cmdiu->connection_id = cpu_to_be64(queue->connection_id); | 2199 | cmdiu->connection_id = cpu_to_be64(queue->connection_id); |
| 2201 | csn = atomic_inc_return(&queue->csn); | ||
| 2202 | cmdiu->csn = cpu_to_be32(csn); | ||
| 2203 | cmdiu->data_len = cpu_to_be32(data_len); | 2200 | cmdiu->data_len = cpu_to_be32(data_len); |
| 2204 | switch (io_dir) { | 2201 | switch (io_dir) { |
| 2205 | case NVMEFC_FCP_WRITE: | 2202 | case NVMEFC_FCP_WRITE: |
| @@ -2257,11 +2254,24 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, | |||
| 2257 | if (!(op->flags & FCOP_FLAGS_AEN)) | 2254 | if (!(op->flags & FCOP_FLAGS_AEN)) |
| 2258 | blk_mq_start_request(op->rq); | 2255 | blk_mq_start_request(op->rq); |
| 2259 | 2256 | ||
| 2257 | cmdiu->csn = cpu_to_be32(atomic_inc_return(&queue->csn)); | ||
| 2260 | ret = ctrl->lport->ops->fcp_io(&ctrl->lport->localport, | 2258 | ret = ctrl->lport->ops->fcp_io(&ctrl->lport->localport, |
| 2261 | &ctrl->rport->remoteport, | 2259 | &ctrl->rport->remoteport, |
| 2262 | queue->lldd_handle, &op->fcp_req); | 2260 | queue->lldd_handle, &op->fcp_req); |
| 2263 | 2261 | ||
| 2264 | if (ret) { | 2262 | if (ret) { |
| 2263 | /* | ||
| 2264 | * If the lld fails to send the command is there an issue with | ||
| 2265 | * the csn value? If the command that fails is the Connect, | ||
| 2266 | * no - as the connection won't be live. If it is a command | ||
| 2267 | * post-connect, it's possible a gap in csn may be created. | ||
| 2268 | * Does this matter? As Linux initiators don't send fused | ||
| 2269 | * commands, no. The gap would exist, but as there's nothing | ||
| 2270 | * that depends on csn order to be delivered on the target | ||
| 2271 | * side, it shouldn't hurt. It would be difficult for a | ||
| 2272 | * target to even detect the csn gap as it has no idea when the | ||
| 2273 | * cmd with the csn was supposed to arrive. | ||
| 2274 | */ | ||
| 2265 | opstate = atomic_xchg(&op->state, FCPOP_STATE_COMPLETE); | 2275 | opstate = atomic_xchg(&op->state, FCPOP_STATE_COMPLETE); |
| 2266 | __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); | 2276 | __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate); |
| 2267 | 2277 | ||
diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index 76250181fee0..9f72d515fc4b 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c | |||
| @@ -24,6 +24,11 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd) | |||
| 24 | return len; | 24 | return len; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | u64 nvmet_get_log_page_offset(struct nvme_command *cmd) | ||
| 28 | { | ||
| 29 | return le64_to_cpu(cmd->get_log_page.lpo); | ||
| 30 | } | ||
| 31 | |||
| 27 | static void nvmet_execute_get_log_page_noop(struct nvmet_req *req) | 32 | static void nvmet_execute_get_log_page_noop(struct nvmet_req *req) |
| 28 | { | 33 | { |
| 29 | nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->data_len)); | 34 | nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->data_len)); |
diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c index c872b47a88f3..33ed95e72d6b 100644 --- a/drivers/nvme/target/discovery.c +++ b/drivers/nvme/target/discovery.c | |||
| @@ -131,54 +131,76 @@ static void nvmet_set_disc_traddr(struct nvmet_req *req, struct nvmet_port *port | |||
| 131 | memcpy(traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE); | 131 | memcpy(traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static size_t discovery_log_entries(struct nvmet_req *req) | ||
| 135 | { | ||
| 136 | struct nvmet_ctrl *ctrl = req->sq->ctrl; | ||
| 137 | struct nvmet_subsys_link *p; | ||
| 138 | struct nvmet_port *r; | ||
| 139 | size_t entries = 0; | ||
| 140 | |||
| 141 | list_for_each_entry(p, &req->port->subsystems, entry) { | ||
| 142 | if (!nvmet_host_allowed(p->subsys, ctrl->hostnqn)) | ||
| 143 | continue; | ||
| 144 | entries++; | ||
| 145 | } | ||
| 146 | list_for_each_entry(r, &req->port->referrals, entry) | ||
| 147 | entries++; | ||
| 148 | return entries; | ||
| 149 | } | ||
| 150 | |||
| 134 | static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) | 151 | static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) |
| 135 | { | 152 | { |
| 136 | const int entry_size = sizeof(struct nvmf_disc_rsp_page_entry); | 153 | const int entry_size = sizeof(struct nvmf_disc_rsp_page_entry); |
| 137 | struct nvmet_ctrl *ctrl = req->sq->ctrl; | 154 | struct nvmet_ctrl *ctrl = req->sq->ctrl; |
| 138 | struct nvmf_disc_rsp_page_hdr *hdr; | 155 | struct nvmf_disc_rsp_page_hdr *hdr; |
| 156 | u64 offset = nvmet_get_log_page_offset(req->cmd); | ||
| 139 | size_t data_len = nvmet_get_log_page_len(req->cmd); | 157 | size_t data_len = nvmet_get_log_page_len(req->cmd); |
| 140 | size_t alloc_len = max(data_len, sizeof(*hdr)); | 158 | size_t alloc_len; |
| 141 | int residual_len = data_len - sizeof(*hdr); | ||
| 142 | struct nvmet_subsys_link *p; | 159 | struct nvmet_subsys_link *p; |
| 143 | struct nvmet_port *r; | 160 | struct nvmet_port *r; |
| 144 | u32 numrec = 0; | 161 | u32 numrec = 0; |
| 145 | u16 status = 0; | 162 | u16 status = 0; |
| 163 | void *buffer; | ||
| 164 | |||
| 165 | /* Spec requires dword aligned offsets */ | ||
| 166 | if (offset & 0x3) { | ||
| 167 | status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; | ||
| 168 | goto out; | ||
| 169 | } | ||
| 146 | 170 | ||
| 147 | /* | 171 | /* |
| 148 | * Make sure we're passing at least a buffer of response header size. | 172 | * Make sure we're passing at least a buffer of response header size. |
| 149 | * If host provided data len is less than the header size, only the | 173 | * If host provided data len is less than the header size, only the |
| 150 | * number of bytes requested by host will be sent to host. | 174 | * number of bytes requested by host will be sent to host. |
| 151 | */ | 175 | */ |
| 152 | hdr = kzalloc(alloc_len, GFP_KERNEL); | 176 | down_read(&nvmet_config_sem); |
| 153 | if (!hdr) { | 177 | alloc_len = sizeof(*hdr) + entry_size * discovery_log_entries(req); |
| 178 | buffer = kzalloc(alloc_len, GFP_KERNEL); | ||
| 179 | if (!buffer) { | ||
| 180 | up_read(&nvmet_config_sem); | ||
| 154 | status = NVME_SC_INTERNAL; | 181 | status = NVME_SC_INTERNAL; |
| 155 | goto out; | 182 | goto out; |
| 156 | } | 183 | } |
| 157 | 184 | ||
| 158 | down_read(&nvmet_config_sem); | 185 | hdr = buffer; |
| 159 | list_for_each_entry(p, &req->port->subsystems, entry) { | 186 | list_for_each_entry(p, &req->port->subsystems, entry) { |
| 187 | char traddr[NVMF_TRADDR_SIZE]; | ||
| 188 | |||
| 160 | if (!nvmet_host_allowed(p->subsys, ctrl->hostnqn)) | 189 | if (!nvmet_host_allowed(p->subsys, ctrl->hostnqn)) |
| 161 | continue; | 190 | continue; |
| 162 | if (residual_len >= entry_size) { | 191 | |
| 163 | char traddr[NVMF_TRADDR_SIZE]; | 192 | nvmet_set_disc_traddr(req, req->port, traddr); |
| 164 | 193 | nvmet_format_discovery_entry(hdr, req->port, | |
| 165 | nvmet_set_disc_traddr(req, req->port, traddr); | 194 | p->subsys->subsysnqn, traddr, |
| 166 | nvmet_format_discovery_entry(hdr, req->port, | 195 | NVME_NQN_NVME, numrec); |
| 167 | p->subsys->subsysnqn, traddr, | ||
| 168 | NVME_NQN_NVME, numrec); | ||
| 169 | residual_len -= entry_size; | ||
| 170 | } | ||
| 171 | numrec++; | 196 | numrec++; |
| 172 | } | 197 | } |
| 173 | 198 | ||
| 174 | list_for_each_entry(r, &req->port->referrals, entry) { | 199 | list_for_each_entry(r, &req->port->referrals, entry) { |
| 175 | if (residual_len >= entry_size) { | 200 | nvmet_format_discovery_entry(hdr, r, |
| 176 | nvmet_format_discovery_entry(hdr, r, | 201 | NVME_DISC_SUBSYS_NAME, |
| 177 | NVME_DISC_SUBSYS_NAME, | 202 | r->disc_addr.traddr, |
| 178 | r->disc_addr.traddr, | 203 | NVME_NQN_DISC, numrec); |
| 179 | NVME_NQN_DISC, numrec); | ||
| 180 | residual_len -= entry_size; | ||
| 181 | } | ||
| 182 | numrec++; | 204 | numrec++; |
| 183 | } | 205 | } |
| 184 | 206 | ||
| @@ -190,8 +212,8 @@ static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) | |||
| 190 | 212 | ||
| 191 | up_read(&nvmet_config_sem); | 213 | up_read(&nvmet_config_sem); |
| 192 | 214 | ||
| 193 | status = nvmet_copy_to_sgl(req, 0, hdr, data_len); | 215 | status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len); |
| 194 | kfree(hdr); | 216 | kfree(buffer); |
| 195 | out: | 217 | out: |
| 196 | nvmet_req_complete(req, status); | 218 | nvmet_req_complete(req, status); |
| 197 | } | 219 | } |
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 51e49efd7849..1653d19b187f 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h | |||
| @@ -428,6 +428,7 @@ u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf, | |||
| 428 | u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len); | 428 | u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len); |
| 429 | 429 | ||
| 430 | u32 nvmet_get_log_page_len(struct nvme_command *cmd); | 430 | u32 nvmet_get_log_page_len(struct nvme_command *cmd); |
| 431 | u64 nvmet_get_log_page_offset(struct nvme_command *cmd); | ||
| 431 | 432 | ||
| 432 | extern struct list_head *nvmet_ports; | 433 | extern struct list_head *nvmet_ports; |
| 433 | void nvmet_port_disc_changed(struct nvmet_port *port, | 434 | void nvmet_port_disc_changed(struct nvmet_port *port, |
diff --git a/include/linux/nvme.h b/include/linux/nvme.h index baa49e6a23cc..c40720cb59ac 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h | |||
| @@ -967,8 +967,13 @@ struct nvme_get_log_page_command { | |||
| 967 | __le16 numdl; | 967 | __le16 numdl; |
| 968 | __le16 numdu; | 968 | __le16 numdu; |
| 969 | __u16 rsvd11; | 969 | __u16 rsvd11; |
| 970 | __le32 lpol; | 970 | union { |
| 971 | __le32 lpou; | 971 | struct { |
| 972 | __le32 lpol; | ||
| 973 | __le32 lpou; | ||
| 974 | }; | ||
| 975 | __le64 lpo; | ||
| 976 | }; | ||
| 972 | __u32 rsvd14[2]; | 977 | __u32 rsvd14[2]; |
| 973 | }; | 978 | }; |
| 974 | 979 | ||
