diff options
Diffstat (limited to 'drivers/infiniband/ulp/srp/ib_srp.c')
| -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 bcbf22ee0aa..1b5b0c73005 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,  			scmnd->sc_data_direction);  } -static void srp_remove_req(struct srp_target_port *target, -			   struct srp_request *req, s32 req_lim_delta) +/** + * srp_claim_req - Take ownership of the scmnd associated with a request. + * @target: SRP target port. + * @req: SRP request. + * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take + *         ownership of @req->scmnd if it equals @scmnd. + * + * Return value: + * Either NULL or a pointer to the SCSI command the caller became owner of. + */ +static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, +				       struct srp_request *req, +				       struct scsi_cmnd *scmnd) +{ +	unsigned long flags; + +	spin_lock_irqsave(&target->lock, flags); +	if (!scmnd) { +		scmnd = req->scmnd; +		req->scmnd = NULL; +	} else if (req->scmnd == scmnd) { +		req->scmnd = NULL; +	} else { +		scmnd = NULL; +	} +	spin_unlock_irqrestore(&target->lock, flags); + +	return scmnd; +} + +/** + * srp_free_req() - Unmap data and add request to the free request list. + */ +static void srp_free_req(struct srp_target_port *target, +			 struct srp_request *req, struct scsi_cmnd *scmnd, +			 s32 req_lim_delta)  {  	unsigned long flags; -	srp_unmap_data(req->scmnd, target, req); +	srp_unmap_data(scmnd, target, req); +  	spin_lock_irqsave(&target->lock, flags);  	target->req_lim += req_lim_delta; -	req->scmnd = NULL;  	list_add_tail(&req->list, &target->free_reqs);  	spin_unlock_irqrestore(&target->lock, flags);  }  static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)  { -	req->scmnd->result = DID_RESET << 16; -	req->scmnd->scsi_done(req->scmnd); -	srp_remove_req(target, req, 0); +	struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); + +	if (scmnd) { +		scmnd->result = DID_RESET << 16; +		scmnd->scsi_done(scmnd); +		srp_free_req(target, req, scmnd, 0); +	}  }  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)  		complete(&target->tsk_mgmt_done);  	} else {  		req = &target->req_ring[rsp->tag]; -		scmnd = req->scmnd; -		if (!scmnd) +		scmnd = srp_claim_req(target, req, NULL); +		if (!scmnd) {  			shost_printk(KERN_ERR, target->scsi_host,  				     "Null scmnd for RSP w/tag %016llx\n",  				     (unsigned long long) rsp->tag); + +			spin_lock_irqsave(&target->lock, flags); +			target->req_lim += be32_to_cpu(rsp->req_lim_delta); +			spin_unlock_irqrestore(&target->lock, flags); + +			return; +		}  		scmnd->result = rsp->status;  		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)  		else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))  			scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); -		srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta)); +		srp_free_req(target, req, scmnd, +			     be32_to_cpu(rsp->req_lim_delta)); +  		scmnd->host_scribble = NULL;  		scmnd->scsi_done(scmnd);  	} @@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd)  {  	struct srp_target_port *target = host_to_target(scmnd->device->host);  	struct srp_request *req = (struct srp_request *) scmnd->host_scribble; -	int ret = SUCCESS;  	shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); -	if (!req || target->qp_in_error) +	if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd))  		return FAILED; -	if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, -			      SRP_TSK_ABORT_TASK)) -		return FAILED; - -	if (req->scmnd) { -		if (!target->tsk_mgmt_status) { -			srp_remove_req(target, req, 0); -			scmnd->result = DID_ABORT << 16; -		} else -			ret = FAILED; -	} +	srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, +			  SRP_TSK_ABORT_TASK); +	srp_free_req(target, req, scmnd, 0); +	scmnd->result = DID_ABORT << 16; -	return ret; +	return SUCCESS;  }  static int srp_reset_device(struct scsi_cmnd *scmnd)  |