aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2019-04-11 11:36:41 -0400
committerJens Axboe <axboe@kernel.dk>2019-04-11 11:36:41 -0400
commitc0c14e935032abd6ee6828840a83df1de49d4838 (patch)
tree6e5d46c670e1ed35f4cddadfec3f7b8c563d23cb
parenta3761c3c91209b58b6f33bf69dd8bb8ec0c9d925 (diff)
parentd808b7f759b50acf0784ce6230ffa63e12ef465d (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.c20
-rw-r--r--drivers/nvme/target/admin-cmd.c5
-rw-r--r--drivers/nvme/target/discovery.c68
-rw-r--r--drivers/nvme/target/nvmet.h1
-rw-r--r--include/linux/nvme.h9
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
1893static void 1893static 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
27u64 nvmet_get_log_page_offset(struct nvme_command *cmd)
28{
29 return le64_to_cpu(cmd->get_log_page.lpo);
30}
31
27static void nvmet_execute_get_log_page_noop(struct nvmet_req *req) 32static 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
134static 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
134static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) 151static 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);
195out: 217out:
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,
428u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len); 428u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len);
429 429
430u32 nvmet_get_log_page_len(struct nvme_command *cmd); 430u32 nvmet_get_log_page_len(struct nvme_command *cmd);
431u64 nvmet_get_log_page_offset(struct nvme_command *cmd);
431 432
432extern struct list_head *nvmet_ports; 433extern struct list_head *nvmet_ports;
433void nvmet_port_disc_changed(struct nvmet_port *port, 434void 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