diff options
| -rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 87 |
1 files changed, 63 insertions, 24 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index bcbf22ee0aa7..1b5b0c730054 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
| @@ -586,24 +586,62 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, | |||
| 586 | scmnd->sc_data_direction); | 586 | scmnd->sc_data_direction); |
| 587 | } | 587 | } |
| 588 | 588 | ||
| 589 | static void srp_remove_req(struct srp_target_port *target, | 589 | /** |
| 590 | struct srp_request *req, s32 req_lim_delta) | 590 | * srp_claim_req - Take ownership of the scmnd associated with a request. |
| 591 | * @target: SRP target port. | ||
| 592 | * @req: SRP request. | ||
| 593 | * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take | ||
| 594 | * ownership of @req->scmnd if it equals @scmnd. | ||
| 595 | * | ||
| 596 | * Return value: | ||
| 597 | * Either NULL or a pointer to the SCSI command the caller became owner of. | ||
| 598 | */ | ||
| 599 | static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, | ||
| 600 | struct srp_request *req, | ||
| 601 | struct scsi_cmnd *scmnd) | ||
| 602 | { | ||
| 603 | unsigned long flags; | ||
| 604 | |||
| 605 | spin_lock_irqsave(&target->lock, flags); | ||
| 606 | if (!scmnd) { | ||
| 607 | scmnd = req->scmnd; | ||
| 608 | req->scmnd = NULL; | ||
| 609 | } else if (req->scmnd == scmnd) { | ||
| 610 | req->scmnd = NULL; | ||
| 611 | } else { | ||
| 612 | scmnd = NULL; | ||
| 613 | } | ||
| 614 | spin_unlock_irqrestore(&target->lock, flags); | ||
| 615 | |||
| 616 | return scmnd; | ||
| 617 | } | ||
| 618 | |||
| 619 | /** | ||
| 620 | * srp_free_req() - Unmap data and add request to the free request list. | ||
| 621 | */ | ||
| 622 | static void srp_free_req(struct srp_target_port *target, | ||
| 623 | struct srp_request *req, struct scsi_cmnd *scmnd, | ||
| 624 | s32 req_lim_delta) | ||
| 591 | { | 625 | { |
| 592 | unsigned long flags; | 626 | unsigned long flags; |
| 593 | 627 | ||
| 594 | srp_unmap_data(req->scmnd, target, req); | 628 | srp_unmap_data(scmnd, target, req); |
| 629 | |||
| 595 | spin_lock_irqsave(&target->lock, flags); | 630 | spin_lock_irqsave(&target->lock, flags); |
| 596 | target->req_lim += req_lim_delta; | 631 | target->req_lim += req_lim_delta; |
| 597 | req->scmnd = NULL; | ||
| 598 | list_add_tail(&req->list, &target->free_reqs); | 632 | list_add_tail(&req->list, &target->free_reqs); |
| 599 | spin_unlock_irqrestore(&target->lock, flags); | 633 | spin_unlock_irqrestore(&target->lock, flags); |
| 600 | } | 634 | } |
| 601 | 635 | ||
| 602 | static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) | 636 | static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) |
| 603 | { | 637 | { |
| 604 | req->scmnd->result = DID_RESET << 16; | 638 | struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); |
| 605 | req->scmnd->scsi_done(req->scmnd); | 639 | |
| 606 | srp_remove_req(target, req, 0); | 640 | if (scmnd) { |
| 641 | scmnd->result = DID_RESET << 16; | ||
| 642 | scmnd->scsi_done(scmnd); | ||
| 643 | srp_free_req(target, req, scmnd, 0); | ||
| 644 | } | ||
| 607 | } | 645 | } |
| 608 | 646 | ||
| 609 | static int srp_reconnect_target(struct srp_target_port *target) | 647 | static int srp_reconnect_target(struct srp_target_port *target) |
| @@ -1073,11 +1111,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
| 1073 | complete(&target->tsk_mgmt_done); | 1111 | complete(&target->tsk_mgmt_done); |
| 1074 | } else { | 1112 | } else { |
| 1075 | req = &target->req_ring[rsp->tag]; | 1113 | req = &target->req_ring[rsp->tag]; |
| 1076 | scmnd = req->scmnd; | 1114 | scmnd = srp_claim_req(target, req, NULL); |
| 1077 | if (!scmnd) | 1115 | if (!scmnd) { |
| 1078 | shost_printk(KERN_ERR, target->scsi_host, | 1116 | shost_printk(KERN_ERR, target->scsi_host, |
| 1079 | "Null scmnd for RSP w/tag %016llx\n", | 1117 | "Null scmnd for RSP w/tag %016llx\n", |
| 1080 | (unsigned long long) rsp->tag); | 1118 | (unsigned long long) rsp->tag); |
| 1119 | |||
| 1120 | spin_lock_irqsave(&target->lock, flags); | ||
| 1121 | target->req_lim += be32_to_cpu(rsp->req_lim_delta); | ||
| 1122 | spin_unlock_irqrestore(&target->lock, flags); | ||
| 1123 | |||
| 1124 | return; | ||
| 1125 | } | ||
| 1081 | scmnd->result = rsp->status; | 1126 | scmnd->result = rsp->status; |
| 1082 | 1127 | ||
| 1083 | if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { | 1128 | if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { |
| @@ -1092,7 +1137,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
| 1092 | else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) | 1137 | else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) |
| 1093 | scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); | 1138 | scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); |
| 1094 | 1139 | ||
| 1095 | srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta)); | 1140 | srp_free_req(target, req, scmnd, |
| 1141 | be32_to_cpu(rsp->req_lim_delta)); | ||
| 1142 | |||
| 1096 | scmnd->host_scribble = NULL; | 1143 | scmnd->host_scribble = NULL; |
| 1097 | scmnd->scsi_done(scmnd); | 1144 | scmnd->scsi_done(scmnd); |
| 1098 | } | 1145 | } |
| @@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd) | |||
| 1631 | { | 1678 | { |
| 1632 | struct srp_target_port *target = host_to_target(scmnd->device->host); | 1679 | struct srp_target_port *target = host_to_target(scmnd->device->host); |
| 1633 | struct srp_request *req = (struct srp_request *) scmnd->host_scribble; | 1680 | struct srp_request *req = (struct srp_request *) scmnd->host_scribble; |
| 1634 | int ret = SUCCESS; | ||
| 1635 | 1681 | ||
| 1636 | shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); | 1682 | shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); |
| 1637 | 1683 | ||
| 1638 | if (!req || target->qp_in_error) | 1684 | if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd)) |
| 1639 | return FAILED; | 1685 | return FAILED; |
| 1640 | if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, | 1686 | srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, |
| 1641 | SRP_TSK_ABORT_TASK)) | 1687 | SRP_TSK_ABORT_TASK); |
| 1642 | return FAILED; | 1688 | srp_free_req(target, req, scmnd, 0); |
| 1643 | 1689 | scmnd->result = DID_ABORT << 16; | |
| 1644 | if (req->scmnd) { | ||
| 1645 | if (!target->tsk_mgmt_status) { | ||
| 1646 | srp_remove_req(target, req, 0); | ||
| 1647 | scmnd->result = DID_ABORT << 16; | ||
| 1648 | } else | ||
| 1649 | ret = FAILED; | ||
| 1650 | } | ||
| 1651 | 1690 | ||
| 1652 | return ret; | 1691 | return SUCCESS; |
| 1653 | } | 1692 | } |
| 1654 | 1693 | ||
| 1655 | static int srp_reset_device(struct scsi_cmnd *scmnd) | 1694 | static int srp_reset_device(struct scsi_cmnd *scmnd) |
