diff options
-rw-r--r-- | drivers/nvme/host/fc.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 5b14cbefb724..2edae54688e8 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c | |||
@@ -1139,6 +1139,7 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) | |||
1139 | /* *********************** NVME Ctrl Routines **************************** */ | 1139 | /* *********************** NVME Ctrl Routines **************************** */ |
1140 | 1140 | ||
1141 | static void __nvme_fc_final_op_cleanup(struct request *rq); | 1141 | static void __nvme_fc_final_op_cleanup(struct request *rq); |
1142 | static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg); | ||
1142 | 1143 | ||
1143 | static int | 1144 | static int |
1144 | nvme_fc_reinit_request(void *data, struct request *rq) | 1145 | nvme_fc_reinit_request(void *data, struct request *rq) |
@@ -1265,7 +1266,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) | |||
1265 | struct nvme_command *sqe = &op->cmd_iu.sqe; | 1266 | struct nvme_command *sqe = &op->cmd_iu.sqe; |
1266 | __le16 status = cpu_to_le16(NVME_SC_SUCCESS << 1); | 1267 | __le16 status = cpu_to_le16(NVME_SC_SUCCESS << 1); |
1267 | union nvme_result result; | 1268 | union nvme_result result; |
1268 | bool complete_rq; | 1269 | bool complete_rq, terminate_assoc = true; |
1269 | 1270 | ||
1270 | /* | 1271 | /* |
1271 | * WARNING: | 1272 | * WARNING: |
@@ -1294,6 +1295,14 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) | |||
1294 | * fabricate a CQE, the following fields will not be set as they | 1295 | * fabricate a CQE, the following fields will not be set as they |
1295 | * are not referenced: | 1296 | * are not referenced: |
1296 | * cqe.sqid, cqe.sqhd, cqe.command_id | 1297 | * cqe.sqid, cqe.sqhd, cqe.command_id |
1298 | * | ||
1299 | * Failure or error of an individual i/o, in a transport | ||
1300 | * detected fashion unrelated to the nvme completion status, | ||
1301 | * potentially cause the initiator and target sides to get out | ||
1302 | * of sync on SQ head/tail (aka outstanding io count allowed). | ||
1303 | * Per FC-NVME spec, failure of an individual command requires | ||
1304 | * the connection to be terminated, which in turn requires the | ||
1305 | * association to be terminated. | ||
1297 | */ | 1306 | */ |
1298 | 1307 | ||
1299 | fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma, | 1308 | fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma, |
@@ -1359,6 +1368,8 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) | |||
1359 | goto done; | 1368 | goto done; |
1360 | } | 1369 | } |
1361 | 1370 | ||
1371 | terminate_assoc = false; | ||
1372 | |||
1362 | done: | 1373 | done: |
1363 | if (op->flags & FCOP_FLAGS_AEN) { | 1374 | if (op->flags & FCOP_FLAGS_AEN) { |
1364 | nvme_complete_async_event(&queue->ctrl->ctrl, status, &result); | 1375 | nvme_complete_async_event(&queue->ctrl->ctrl, status, &result); |
@@ -1366,7 +1377,7 @@ done: | |||
1366 | atomic_set(&op->state, FCPOP_STATE_IDLE); | 1377 | atomic_set(&op->state, FCPOP_STATE_IDLE); |
1367 | op->flags = FCOP_FLAGS_AEN; /* clear other flags */ | 1378 | op->flags = FCOP_FLAGS_AEN; /* clear other flags */ |
1368 | nvme_fc_ctrl_put(ctrl); | 1379 | nvme_fc_ctrl_put(ctrl); |
1369 | return; | 1380 | goto check_error; |
1370 | } | 1381 | } |
1371 | 1382 | ||
1372 | complete_rq = __nvme_fc_fcpop_chk_teardowns(ctrl, op); | 1383 | complete_rq = __nvme_fc_fcpop_chk_teardowns(ctrl, op); |
@@ -1379,6 +1390,10 @@ done: | |||
1379 | nvme_end_request(rq, status, result); | 1390 | nvme_end_request(rq, status, result); |
1380 | } else | 1391 | } else |
1381 | __nvme_fc_final_op_cleanup(rq); | 1392 | __nvme_fc_final_op_cleanup(rq); |
1393 | |||
1394 | check_error: | ||
1395 | if (terminate_assoc) | ||
1396 | nvme_fc_error_recovery(ctrl, "transport detected io error"); | ||
1382 | } | 1397 | } |
1383 | 1398 | ||
1384 | static int | 1399 | static int |