diff options
author | Roland Dreier <rolandd@cisco.com> | 2006-05-09 13:50:28 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-05-09 13:50:28 -0400 |
commit | d945e1df28ca07642b3e1a9b9d07074ba5f76be0 (patch) | |
tree | ff392416f1339dd222b9470c24db1ec4defc1bf5 /drivers/infiniband | |
parent | d8b9f23b23e080d820e3c0aa5ccd7834c26ebf96 (diff) |
IB/srp: Fix tracking of pending requests during error handling
If a SCSI abort completes, or the command completes successfully, then
the driver must remove the command from its queue of pending
commands. Similarly, if a device reset succeeds, then all commands
queued for the given device must be removed from the queue.
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 195 | ||||
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.h | 4 |
2 files changed, 115 insertions, 84 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5bb55742ada6..c32ce4348e1b 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
@@ -409,6 +409,34 @@ static int srp_connect_target(struct srp_target_port *target) | |||
409 | } | 409 | } |
410 | } | 410 | } |
411 | 411 | ||
412 | static void srp_unmap_data(struct scsi_cmnd *scmnd, | ||
413 | struct srp_target_port *target, | ||
414 | struct srp_request *req) | ||
415 | { | ||
416 | struct scatterlist *scat; | ||
417 | int nents; | ||
418 | |||
419 | if (!scmnd->request_buffer || | ||
420 | (scmnd->sc_data_direction != DMA_TO_DEVICE && | ||
421 | scmnd->sc_data_direction != DMA_FROM_DEVICE)) | ||
422 | return; | ||
423 | |||
424 | /* | ||
425 | * This handling of non-SG commands can be killed when the | ||
426 | * SCSI midlayer no longer generates non-SG commands. | ||
427 | */ | ||
428 | if (likely(scmnd->use_sg)) { | ||
429 | nents = scmnd->use_sg; | ||
430 | scat = scmnd->request_buffer; | ||
431 | } else { | ||
432 | nents = 1; | ||
433 | scat = &req->fake_sg; | ||
434 | } | ||
435 | |||
436 | dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, | ||
437 | scmnd->sc_data_direction); | ||
438 | } | ||
439 | |||
412 | static int srp_reconnect_target(struct srp_target_port *target) | 440 | static int srp_reconnect_target(struct srp_target_port *target) |
413 | { | 441 | { |
414 | struct ib_cm_id *new_cm_id; | 442 | struct ib_cm_id *new_cm_id; |
@@ -455,16 +483,16 @@ static int srp_reconnect_target(struct srp_target_port *target) | |||
455 | list_for_each_entry(req, &target->req_queue, list) { | 483 | list_for_each_entry(req, &target->req_queue, list) { |
456 | req->scmnd->result = DID_RESET << 16; | 484 | req->scmnd->result = DID_RESET << 16; |
457 | req->scmnd->scsi_done(req->scmnd); | 485 | req->scmnd->scsi_done(req->scmnd); |
486 | srp_unmap_data(req->scmnd, target, req); | ||
458 | } | 487 | } |
459 | 488 | ||
460 | target->rx_head = 0; | 489 | target->rx_head = 0; |
461 | target->tx_head = 0; | 490 | target->tx_head = 0; |
462 | target->tx_tail = 0; | 491 | target->tx_tail = 0; |
463 | target->req_head = 0; | 492 | INIT_LIST_HEAD(&target->free_reqs); |
464 | for (i = 0; i < SRP_SQ_SIZE - 1; ++i) | ||
465 | target->req_ring[i].next = i + 1; | ||
466 | target->req_ring[SRP_SQ_SIZE - 1].next = -1; | ||
467 | INIT_LIST_HEAD(&target->req_queue); | 493 | INIT_LIST_HEAD(&target->req_queue); |
494 | for (i = 0; i < SRP_SQ_SIZE; ++i) | ||
495 | list_add_tail(&target->req_ring[i].list, &target->free_reqs); | ||
468 | 496 | ||
469 | ret = srp_connect_target(target); | 497 | ret = srp_connect_target(target); |
470 | if (ret) | 498 | if (ret) |
@@ -589,40 +617,10 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, | |||
589 | return len; | 617 | return len; |
590 | } | 618 | } |
591 | 619 | ||
592 | static void srp_unmap_data(struct scsi_cmnd *scmnd, | 620 | static void srp_remove_req(struct srp_target_port *target, struct srp_request *req) |
593 | struct srp_target_port *target, | ||
594 | struct srp_request *req) | ||
595 | { | ||
596 | struct scatterlist *scat; | ||
597 | int nents; | ||
598 | |||
599 | if (!scmnd->request_buffer || | ||
600 | (scmnd->sc_data_direction != DMA_TO_DEVICE && | ||
601 | scmnd->sc_data_direction != DMA_FROM_DEVICE)) | ||
602 | return; | ||
603 | |||
604 | /* | ||
605 | * This handling of non-SG commands can be killed when the | ||
606 | * SCSI midlayer no longer generates non-SG commands. | ||
607 | */ | ||
608 | if (likely(scmnd->use_sg)) { | ||
609 | nents = scmnd->use_sg; | ||
610 | scat = scmnd->request_buffer; | ||
611 | } else { | ||
612 | nents = 1; | ||
613 | scat = &req->fake_sg; | ||
614 | } | ||
615 | |||
616 | dma_unmap_sg(target->srp_host->dev->dma_device, scat, nents, | ||
617 | scmnd->sc_data_direction); | ||
618 | } | ||
619 | |||
620 | static void srp_remove_req(struct srp_target_port *target, struct srp_request *req, | ||
621 | int index) | ||
622 | { | 621 | { |
623 | list_del(&req->list); | 622 | srp_unmap_data(req->scmnd, target, req); |
624 | req->next = target->req_head; | 623 | list_move_tail(&req->list, &target->free_reqs); |
625 | target->req_head = index; | ||
626 | } | 624 | } |
627 | 625 | ||
628 | static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | 626 | static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) |
@@ -647,7 +645,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
647 | req->tsk_status = rsp->data[3]; | 645 | req->tsk_status = rsp->data[3]; |
648 | complete(&req->done); | 646 | complete(&req->done); |
649 | } else { | 647 | } else { |
650 | scmnd = req->scmnd; | 648 | scmnd = req->scmnd; |
651 | if (!scmnd) | 649 | if (!scmnd) |
652 | printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n", | 650 | printk(KERN_ERR "Null scmnd for RSP w/tag %016llx\n", |
653 | (unsigned long long) rsp->tag); | 651 | (unsigned long long) rsp->tag); |
@@ -665,14 +663,11 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
665 | else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) | 663 | else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) |
666 | scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt); | 664 | scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt); |
667 | 665 | ||
668 | srp_unmap_data(scmnd, target, req); | ||
669 | |||
670 | if (!req->tsk_mgmt) { | 666 | if (!req->tsk_mgmt) { |
671 | req->scmnd = NULL; | ||
672 | scmnd->host_scribble = (void *) -1L; | 667 | scmnd->host_scribble = (void *) -1L; |
673 | scmnd->scsi_done(scmnd); | 668 | scmnd->scsi_done(scmnd); |
674 | 669 | ||
675 | srp_remove_req(target, req, rsp->tag & ~SRP_TAG_TSK_MGMT); | 670 | srp_remove_req(target, req); |
676 | } else | 671 | } else |
677 | req->cmd_done = 1; | 672 | req->cmd_done = 1; |
678 | } | 673 | } |
@@ -859,7 +854,6 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, | |||
859 | struct srp_request *req; | 854 | struct srp_request *req; |
860 | struct srp_iu *iu; | 855 | struct srp_iu *iu; |
861 | struct srp_cmd *cmd; | 856 | struct srp_cmd *cmd; |
862 | long req_index; | ||
863 | int len; | 857 | int len; |
864 | 858 | ||
865 | if (target->state == SRP_TARGET_CONNECTING) | 859 | if (target->state == SRP_TARGET_CONNECTING) |
@@ -879,22 +873,20 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, | |||
879 | dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma, | 873 | dma_sync_single_for_cpu(target->srp_host->dev->dma_device, iu->dma, |
880 | SRP_MAX_IU_LEN, DMA_TO_DEVICE); | 874 | SRP_MAX_IU_LEN, DMA_TO_DEVICE); |
881 | 875 | ||
882 | req_index = target->req_head; | 876 | req = list_entry(target->free_reqs.next, struct srp_request, list); |
883 | 877 | ||
884 | scmnd->scsi_done = done; | 878 | scmnd->scsi_done = done; |
885 | scmnd->result = 0; | 879 | scmnd->result = 0; |
886 | scmnd->host_scribble = (void *) req_index; | 880 | scmnd->host_scribble = (void *) (long) req->index; |
887 | 881 | ||
888 | cmd = iu->buf; | 882 | cmd = iu->buf; |
889 | memset(cmd, 0, sizeof *cmd); | 883 | memset(cmd, 0, sizeof *cmd); |
890 | 884 | ||
891 | cmd->opcode = SRP_CMD; | 885 | cmd->opcode = SRP_CMD; |
892 | cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); | 886 | cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48); |
893 | cmd->tag = req_index; | 887 | cmd->tag = req->index; |
894 | memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); | 888 | memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len); |
895 | 889 | ||
896 | req = &target->req_ring[req_index]; | ||
897 | |||
898 | req->scmnd = scmnd; | 890 | req->scmnd = scmnd; |
899 | req->cmd = iu; | 891 | req->cmd = iu; |
900 | req->cmd_done = 0; | 892 | req->cmd_done = 0; |
@@ -919,8 +911,7 @@ static int srp_queuecommand(struct scsi_cmnd *scmnd, | |||
919 | goto err_unmap; | 911 | goto err_unmap; |
920 | } | 912 | } |
921 | 913 | ||
922 | target->req_head = req->next; | 914 | list_move_tail(&req->list, &target->req_queue); |
923 | list_add_tail(&req->list, &target->req_queue); | ||
924 | 915 | ||
925 | return 0; | 916 | return 0; |
926 | 917 | ||
@@ -1143,30 +1134,20 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) | |||
1143 | return 0; | 1134 | return 0; |
1144 | } | 1135 | } |
1145 | 1136 | ||
1146 | static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) | 1137 | static int srp_send_tsk_mgmt(struct srp_target_port *target, |
1138 | struct srp_request *req, u8 func) | ||
1147 | { | 1139 | { |
1148 | struct srp_target_port *target = host_to_target(scmnd->device->host); | ||
1149 | struct srp_request *req; | ||
1150 | struct srp_iu *iu; | 1140 | struct srp_iu *iu; |
1151 | struct srp_tsk_mgmt *tsk_mgmt; | 1141 | struct srp_tsk_mgmt *tsk_mgmt; |
1152 | int req_index; | ||
1153 | int ret = FAILED; | ||
1154 | 1142 | ||
1155 | spin_lock_irq(target->scsi_host->host_lock); | 1143 | spin_lock_irq(target->scsi_host->host_lock); |
1156 | 1144 | ||
1157 | if (target->state == SRP_TARGET_DEAD || | 1145 | if (target->state == SRP_TARGET_DEAD || |
1158 | target->state == SRP_TARGET_REMOVED) { | 1146 | target->state == SRP_TARGET_REMOVED) { |
1159 | scmnd->result = DID_BAD_TARGET << 16; | 1147 | req->scmnd->result = DID_BAD_TARGET << 16; |
1160 | goto out; | 1148 | goto out; |
1161 | } | 1149 | } |
1162 | 1150 | ||
1163 | if (scmnd->host_scribble == (void *) -1L) | ||
1164 | goto out; | ||
1165 | |||
1166 | req_index = (long) scmnd->host_scribble; | ||
1167 | printk(KERN_ERR "Abort for req_index %d\n", req_index); | ||
1168 | |||
1169 | req = &target->req_ring[req_index]; | ||
1170 | init_completion(&req->done); | 1151 | init_completion(&req->done); |
1171 | 1152 | ||
1172 | iu = __srp_get_tx_iu(target); | 1153 | iu = __srp_get_tx_iu(target); |
@@ -1177,10 +1158,10 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) | |||
1177 | memset(tsk_mgmt, 0, sizeof *tsk_mgmt); | 1158 | memset(tsk_mgmt, 0, sizeof *tsk_mgmt); |
1178 | 1159 | ||
1179 | tsk_mgmt->opcode = SRP_TSK_MGMT; | 1160 | tsk_mgmt->opcode = SRP_TSK_MGMT; |
1180 | tsk_mgmt->lun = cpu_to_be64((u64) scmnd->device->lun << 48); | 1161 | tsk_mgmt->lun = cpu_to_be64((u64) req->scmnd->device->lun << 48); |
1181 | tsk_mgmt->tag = req_index | SRP_TAG_TSK_MGMT; | 1162 | tsk_mgmt->tag = req->index | SRP_TAG_TSK_MGMT; |
1182 | tsk_mgmt->tsk_mgmt_func = func; | 1163 | tsk_mgmt->tsk_mgmt_func = func; |
1183 | tsk_mgmt->task_tag = req_index; | 1164 | tsk_mgmt->task_tag = req->index; |
1184 | 1165 | ||
1185 | if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) | 1166 | if (__srp_post_send(target, iu, sizeof *tsk_mgmt)) |
1186 | goto out; | 1167 | goto out; |
@@ -1188,37 +1169,85 @@ static int srp_send_tsk_mgmt(struct scsi_cmnd *scmnd, u8 func) | |||
1188 | req->tsk_mgmt = iu; | 1169 | req->tsk_mgmt = iu; |
1189 | 1170 | ||
1190 | spin_unlock_irq(target->scsi_host->host_lock); | 1171 | spin_unlock_irq(target->scsi_host->host_lock); |
1172 | |||
1191 | if (!wait_for_completion_timeout(&req->done, | 1173 | if (!wait_for_completion_timeout(&req->done, |
1192 | msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) | 1174 | msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS))) |
1193 | return FAILED; | 1175 | return -1; |
1194 | spin_lock_irq(target->scsi_host->host_lock); | ||
1195 | 1176 | ||
1196 | if (req->cmd_done) { | 1177 | return 0; |
1197 | srp_remove_req(target, req, req_index); | ||
1198 | scmnd->scsi_done(scmnd); | ||
1199 | } else if (!req->tsk_status) { | ||
1200 | srp_remove_req(target, req, req_index); | ||
1201 | scmnd->result = DID_ABORT << 16; | ||
1202 | ret = SUCCESS; | ||
1203 | } | ||
1204 | 1178 | ||
1205 | out: | 1179 | out: |
1206 | spin_unlock_irq(target->scsi_host->host_lock); | 1180 | spin_unlock_irq(target->scsi_host->host_lock); |
1207 | return ret; | 1181 | return -1; |
1182 | } | ||
1183 | |||
1184 | static int srp_find_req(struct srp_target_port *target, | ||
1185 | struct scsi_cmnd *scmnd, | ||
1186 | struct srp_request **req) | ||
1187 | { | ||
1188 | if (scmnd->host_scribble == (void *) -1L) | ||
1189 | return -1; | ||
1190 | |||
1191 | *req = &target->req_ring[(long) scmnd->host_scribble]; | ||
1192 | |||
1193 | return 0; | ||
1208 | } | 1194 | } |
1209 | 1195 | ||
1210 | static int srp_abort(struct scsi_cmnd *scmnd) | 1196 | static int srp_abort(struct scsi_cmnd *scmnd) |
1211 | { | 1197 | { |
1198 | struct srp_target_port *target = host_to_target(scmnd->device->host); | ||
1199 | struct srp_request *req; | ||
1200 | int ret = SUCCESS; | ||
1201 | |||
1212 | printk(KERN_ERR "SRP abort called\n"); | 1202 | printk(KERN_ERR "SRP abort called\n"); |
1213 | 1203 | ||
1214 | return srp_send_tsk_mgmt(scmnd, SRP_TSK_ABORT_TASK); | 1204 | if (srp_find_req(target, scmnd, &req)) |
1205 | return FAILED; | ||
1206 | if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK)) | ||
1207 | return FAILED; | ||
1208 | |||
1209 | spin_lock_irq(target->scsi_host->host_lock); | ||
1210 | |||
1211 | if (req->cmd_done) { | ||
1212 | srp_remove_req(target, req); | ||
1213 | scmnd->scsi_done(scmnd); | ||
1214 | } else if (!req->tsk_status) { | ||
1215 | srp_remove_req(target, req); | ||
1216 | scmnd->result = DID_ABORT << 16; | ||
1217 | } else | ||
1218 | ret = FAILED; | ||
1219 | |||
1220 | spin_unlock_irq(target->scsi_host->host_lock); | ||
1221 | |||
1222 | return ret; | ||
1215 | } | 1223 | } |
1216 | 1224 | ||
1217 | static int srp_reset_device(struct scsi_cmnd *scmnd) | 1225 | static int srp_reset_device(struct scsi_cmnd *scmnd) |
1218 | { | 1226 | { |
1227 | struct srp_target_port *target = host_to_target(scmnd->device->host); | ||
1228 | struct srp_request *req, *tmp; | ||
1229 | |||
1219 | printk(KERN_ERR "SRP reset_device called\n"); | 1230 | printk(KERN_ERR "SRP reset_device called\n"); |
1220 | 1231 | ||
1221 | return srp_send_tsk_mgmt(scmnd, SRP_TSK_LUN_RESET); | 1232 | if (srp_find_req(target, scmnd, &req)) |
1233 | return FAILED; | ||
1234 | if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET)) | ||
1235 | return FAILED; | ||
1236 | if (req->tsk_status) | ||
1237 | return FAILED; | ||
1238 | |||
1239 | spin_lock_irq(target->scsi_host->host_lock); | ||
1240 | |||
1241 | list_for_each_entry_safe(req, tmp, &target->req_queue, list) | ||
1242 | if (req->scmnd->device == scmnd->device) { | ||
1243 | req->scmnd->result = DID_RESET << 16; | ||
1244 | scmnd->scsi_done(scmnd); | ||
1245 | srp_remove_req(target, req); | ||
1246 | } | ||
1247 | |||
1248 | spin_unlock_irq(target->scsi_host->host_lock); | ||
1249 | |||
1250 | return SUCCESS; | ||
1222 | } | 1251 | } |
1223 | 1252 | ||
1224 | static int srp_reset_host(struct scsi_cmnd *scmnd) | 1253 | static int srp_reset_host(struct scsi_cmnd *scmnd) |
@@ -1518,10 +1547,12 @@ static ssize_t srp_create_target(struct class_device *class_dev, | |||
1518 | 1547 | ||
1519 | INIT_WORK(&target->work, srp_reconnect_work, target); | 1548 | INIT_WORK(&target->work, srp_reconnect_work, target); |
1520 | 1549 | ||
1521 | for (i = 0; i < SRP_SQ_SIZE - 1; ++i) | 1550 | INIT_LIST_HEAD(&target->free_reqs); |
1522 | target->req_ring[i].next = i + 1; | ||
1523 | target->req_ring[SRP_SQ_SIZE - 1].next = -1; | ||
1524 | INIT_LIST_HEAD(&target->req_queue); | 1551 | INIT_LIST_HEAD(&target->req_queue); |
1552 | for (i = 0; i < SRP_SQ_SIZE; ++i) { | ||
1553 | target->req_ring[i].index = i; | ||
1554 | list_add_tail(&target->req_ring[i].list, &target->free_reqs); | ||
1555 | } | ||
1525 | 1556 | ||
1526 | ret = srp_parse_options(buf, target); | 1557 | ret = srp_parse_options(buf, target); |
1527 | if (ret) | 1558 | if (ret) |
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index bd7f7c3115de..c5cd43aae860 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h | |||
@@ -101,7 +101,7 @@ struct srp_request { | |||
101 | */ | 101 | */ |
102 | struct scatterlist fake_sg; | 102 | struct scatterlist fake_sg; |
103 | struct completion done; | 103 | struct completion done; |
104 | short next; | 104 | short index; |
105 | u8 cmd_done; | 105 | u8 cmd_done; |
106 | u8 tsk_status; | 106 | u8 tsk_status; |
107 | }; | 107 | }; |
@@ -133,7 +133,7 @@ struct srp_target_port { | |||
133 | unsigned tx_tail; | 133 | unsigned tx_tail; |
134 | struct srp_iu *tx_ring[SRP_SQ_SIZE + 1]; | 134 | struct srp_iu *tx_ring[SRP_SQ_SIZE + 1]; |
135 | 135 | ||
136 | int req_head; | 136 | struct list_head free_reqs; |
137 | struct list_head req_queue; | 137 | struct list_head req_queue; |
138 | struct srp_request req_ring[SRP_SQ_SIZE]; | 138 | struct srp_request req_ring[SRP_SQ_SIZE]; |
139 | 139 | ||