On 09/08/2016 12:23 PM, Gabriel Krisman Bertazi wrote:
>> @@ -1868,6 +1872,48 @@ static inline void ipr_free_cmd(struct i
>>                ipr_cmd->hrrq->active_map);
>>  }
>>
>> +static inline void ipr_hrrq_activate(struct ipr_hrr_queue *hrrq)
>> +{
>> +    if (!hrrq->is_active) {
>> +            atomic_inc(&hrrq->active);
>> +            atomic_inc(&hrrq->ioa_cfg->hrrq_active);
>> +            hrrq->is_active = 1;
>> +    }
>> +}
>> +
>> +static inline void ipr_hrrq_deactivate(struct ipr_hrr_queue *hrrq)
>> +{
>> +    if (hrrq->is_active) {
>> +            hrrq->is_active = 0;
>> +
>> +            if (!atomic_dec_return(&hrrq->active))
> 
> Shouldn't this set hrrq->active back to 0, instead?

Not sure I follow. When an HRRQ is available for use, the hrrq->active refcount 
is
set to 1. It gets incremented by ipr_hrrq_enter and decremented by 
ipr_hrrq_exit.
So its either ipr_hrrq_deactivate that decrements hrrq->active to zero, in which
case, we can then decrement ioa_cfg->hrrq_active, or we have to wait for one
or more ipr_hrrq_exit calls to decrement httq->active to zero so that we can
proceed with the reset job.

> 
>> +                    atomic_dec(&hrrq->ioa_cfg->hrrq_active);
>> +    }
>> +}
>> +
>> +static inline int ipr_hrrq_enter(struct ipr_hrr_queue *hrrq)
>> +{
>> +    return atomic_inc_not_zero(&hrrq->active);
>> +}
>> +
>> +static void ipr_reset_ioa_job(struct ipr_cmnd *);
>> +
>> +static inline void ipr_hrrq_exit(struct ipr_hrr_queue *hrrq)
>> +{
>> +    unsigned long flags;
>> +    struct ipr_ioa_cfg *ioa_cfg;
>> +
>> +    if (!atomic_dec_return(&hrrq->active)) {
>> +            ioa_cfg = hrrq->ioa_cfg;
>> +
>> +            if (!atomic_dec_return(&ioa_cfg->hrrq_active)) {
>> +                    spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
>> +                    ipr_reset_ioa_job(ioa_cfg->reset_cmd);
>> +                    spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
>> +            }
>> +    }
>> +}
>> +
>>  static inline struct ipr_cmnd* ipr_first_active_cmd(struct ipr_hrr_queue 
>> *hrrq)
>>  {
>>      int i = find_first_bit(hrrq->active_map, hrrq->size);
>> diff -puN drivers/scsi/ipr.c~ipr_lockless_atomic drivers/scsi/ipr.c
>> --- linux-2.6.git/drivers/scsi/ipr.c~ipr_lockless_atomic     2016-09-06 
>> 21:01:16.264239271 -0500
>> +++ linux-2.6.git-bjking1/drivers/scsi/ipr.c 2016-09-06 21:07:15.311878103 
>> -0500
>> @@ -6455,10 +6455,8 @@ static void ipr_scsi_done(struct ipr_cmn
>>
>>      if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
>>              scsi_dma_unmap(scsi_cmd);
>> -            spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags);
>>              ipr_free_cmd(ipr_cmd);
>>              scsi_cmd->scsi_done(scsi_cmd);
>> -            spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags);
>>      } else {
>>              spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
>>              spin_lock(&ipr_cmd->hrrq->_lock);
>> @@ -6513,9 +6511,27 @@ static int ipr_queuecommand(struct Scsi_
>>
>>      hrrq = &ioa_cfg->hrrq[hrrq_id];
>>
>> +    if (!ipr_hrrq_enter(hrrq)) {
>> +            dev_info(&ioa_cfg->pdev->dev, "Failed to get a ref\n");
>> +
>> +            spin_lock_irqsave(hrrq->lock, hrrq_flags);
>> +            if (hrrq->ioa_is_dead || hrrq->removing_ioa) {
>> +                    spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
>> +                    memset(scsi_cmd->sense_buffer, 0, 
>> SCSI_SENSE_BUFFERSIZE);
>> +                    scsi_cmd->result = (DID_NO_CONNECT << 16);
>> +                    scsi_cmd->scsi_done(scsi_cmd);
>> +                    return 0;
>> +            }
>> +
>> +            spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
>> +            return SCSI_MLQUEUE_HOST_BUSY;
>> +    }
>> +
>>      ipr_cmd = __ipr_get_free_ipr_cmnd(hrrq);
>> -    if (ipr_cmd == NULL)
>> +    if (ipr_cmd == NULL) {
>> +            ipr_hrrq_exit(hrrq);
>>              return SCSI_MLQUEUE_HOST_BUSY;
>> +    }
> 
> 
> ipr_cmd is associated with hrrq.  Does it make sense to get a free ipr
> cmnd without holding a reference to the hrrq?  If not, I think it makes
> sense move the reference acquisition code to that function and simplify
> the logic in the queuecommand function.

Yes, it does. We do it a bunch of other places while holding a lock. I tried to
adopt the philosophy here of optimize the hot path and minimize changes outside
the hot path.



>> @@ -6560,38 +6586,20 @@ static int ipr_queuecommand(struct Scsi_
>>      else
>>              rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
>>
>> -    spin_lock_irqsave(hrrq->lock, hrrq_flags);
>> -    if (unlikely(rc || (!hrrq->allow_cmds && !hrrq->ioa_is_dead && 
>> !hrrq->removing_ioa))) {
>> -            ipr_free_cmd(ipr_cmd);
>> -            spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
>> -            if (!rc)
>> +    if (rc) {
>> +            if (!ipr_cmnd_complete(ipr_cmd)) {
>> +                    ipr_free_cmd(ipr_cmd);
>>                      scsi_dma_unmap(scsi_cmd);
>> +            }
>> +            ipr_hrrq_exit(hrrq);
>>              return SCSI_MLQUEUE_HOST_BUSY;
>>      }
>>
>> -    if (unlikely(hrrq->ioa_is_dead || hrrq->removing_ioa)) {
>> -            ipr_free_cmd(ipr_cmd);
>> -            spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
>> -            scsi_dma_unmap(scsi_cmd);
>> -            goto err_nodev;
>> -    }
>> -
>>      ioarcb->res_handle = res->res_handle;
>> -    if (res->needs_sync_complete) {
>> -            ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
>> -            res->needs_sync_complete = 0;
>> -    }
>> +
>>      ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
>>      ipr_send_command(ipr_cmd);
>> -    spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
>> -    return 0;
>> -
>> -err_nodev:
>> -    spin_lock_irqsave(hrrq->lock, hrrq_flags);
>> -    memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
>> -    scsi_cmd->result = (DID_NO_CONNECT << 16);
>> -    scsi_cmd->scsi_done(scsi_cmd);
>> -    spin_unlock_irqrestore(hrrq->lock, hrrq_flags);
>> +    ipr_hrrq_exit(hrrq);
> 
> Shouldn't we hold the hrrq until completing the request?

No. If we did that it would cause issues for our adapter reset job which
might be resetting the adapter because I/O is wedged. The ipr_hrrq_enter/exit
code is really needed to simply ensure we don't reset the adapter while
we are:

1. Referencing any resource entries. 
2. Sending new commands to the adapter. If we were to call ipr_send_command
   at the same time as we were running BIST on the adapter, it would EEH.


Thanks,

Brian


-- 
Brian King
Power Linux I/O
IBM Linux Technology Center


------------------------------------------------------------------------------
_______________________________________________
Iprdd-devel mailing list
Iprdd-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/iprdd-devel

Reply via email to