Brian King <brk...@linux.vnet.ibm.com> writes:

> This patch removes all spinlocks from ipr's queuecommand path.
>
> Signed-off-by: Brian King <brk...@linux.vnet.ibm.com>
> ---
>
>  drivers/scsi/ipr.c |   70 
> +++++++++++++++++++++++++++++++----------------------
>  drivers/scsi/ipr.h |   52 +++++++++++++++++++++++++++++++++++++--
>  2 files changed, 91 insertions(+), 31 deletions(-)
>
> diff -puN drivers/scsi/ipr.h~ipr_lockless_atomic drivers/scsi/ipr.h
> --- linux-2.6.git/drivers/scsi/ipr.h~ipr_lockless_atomic      2016-09-06 
> 21:01:16.260239296 -0500
> +++ linux-2.6.git-bjking1/drivers/scsi/ipr.h  2016-09-06 21:07:15.309878131 
> -0500
> @@ -512,6 +512,7 @@ struct ipr_hrr_queue {
>       struct list_head hrrq_error_q;
>       spinlock_t _lock;
>       spinlock_t *lock;
> +     atomic_t active;
>
>       volatile u32 toggle_bit;
>       u32 size;
> @@ -521,6 +522,7 @@ struct ipr_hrr_queue {
>       u8 ioa_is_dead:1;
>       u8 allow_cmds:1;
>       u8 removing_ioa:1;
> +     u8 is_active:1;
>
>       struct irq_poll iopoll;
>  };
> @@ -1293,13 +1295,13 @@ struct ipr_sata_port {
>  };
>
>  struct ipr_resource_entry {
> -     u8 needs_sync_complete:1;
> +     u8 needs_sync_complete:1; /* atomic? gscsi and vset */
>       u8 in_erp:1;
>       u8 add_to_ml:1;
>       u8 del_from_ml:1;
>       u8 resetting_device:1;
> -     u8 reset_occurred:1;
> -     u8 raw_mode:1;
> +     u8 reset_occurred:1; /* atomic? gscsi only */
> +     u8 raw_mode:1; /* atomic? AF DASD only */
>
>       u32 bus;                /* AKA channel */
>       u32 target;             /* AKA id */
> @@ -1492,6 +1494,7 @@ struct ipr_ioa_cfg {
>       u8 cfg_locked:1;
>       u8 clear_isr:1;
>       u8 probe_done:1;
> +     u8 allow_cmds:1;
>
>       u8 revid;
>
> @@ -1544,6 +1547,7 @@ struct ipr_ioa_cfg {
>       struct ipr_hrr_queue hrrq[IPR_MAX_HRRQ_NUM];
>       u32 hrrq_num;
>       atomic_t  hrrq_index;
> +     atomic_t  hrrq_active;
>       u16 identify_hrrq_index;
>
>       struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
> @@ -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?

> +                     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.

>
>       ipr_init_ipr_cmnd(ipr_cmd, ipr_scsi_done);
>       ioarcb = &ipr_cmd->ioarcb;
> @@ -6529,7 +6545,10 @@ static int ipr_queuecommand(struct Scsi_
>                       ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
>
>               if (res->reset_occurred) {
> +                     spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
>                       res->reset_occurred = 0;
> +                     spin_unlock_irqrestore(ioa_cfg->host->host_lock, 
> lock_flags);
> +
>                       ioarcb->cmd_pkt.flags_lo |= 
> IPR_FLAGS_LO_DELAY_AFTER_RST;
>               }
>       }
> @@ -6542,6 +6561,13 @@ static int ipr_queuecommand(struct Scsi_
>                       ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK;
>               else
>                       ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_UNTAGGED_TASK;
> +
> +             if (res->needs_sync_complete) {
> +                     ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
> +                     spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
> +                     res->needs_sync_complete = 0;
> +                     spin_unlock_irqrestore(ioa_cfg->host->host_lock, 
> lock_flags);
> +             }
>       }
>
>       if (scsi_cmd->cmnd[0] >= 0xC0 &&
> @@ -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?

>       return 0;
>  }
>
> @@ -7160,6 +7168,7 @@ static int ipr_ioa_reset_done(struct ipr
>       for (j = 0; j < ioa_cfg->hrrq_num; j++) {
>               spin_lock(&ioa_cfg->hrrq[j]._lock);
>               ioa_cfg->hrrq[j].allow_cmds = 1;
> +             ipr_hrrq_activate(&ioa_cfg->hrrq[j]);
>               spin_unlock(&ioa_cfg->hrrq[j]._lock);
>       }
>       wmb();
> @@ -9110,6 +9119,9 @@ static void ipr_reset_ioa_job(struct ipr
>                       return;
>               }
>
> +             if (atomic_read(&ioa_cfg->hrrq_active))
> +                     return;
> +
>               if (IPR_IOASC_SENSE_KEY(ioasc)) {
>                       rc = ipr_cmd->job_step_failed(ipr_cmd);
>                       if (rc == IPR_RC_JOB_RETURN)
> @@ -9147,6 +9159,7 @@ static void _ipr_initiate_ioa_reset(stru
>       for (i = 0; i < ioa_cfg->hrrq_num; i++) {
>               spin_lock(&ioa_cfg->hrrq[i]._lock);
>               ioa_cfg->hrrq[i].allow_cmds = 0;
> +             ipr_hrrq_deactivate(&ioa_cfg->hrrq[i]);
>               spin_unlock(&ioa_cfg->hrrq[i]._lock);
>       }
>       wmb();
> @@ -9333,6 +9346,7 @@ static void ipr_pci_perm_failure(struct
>               for (i = 0; i < ioa_cfg->hrrq_num; i++) {
>                       spin_lock(&ioa_cfg->hrrq[i]._lock);
>                       ioa_cfg->hrrq[i].allow_cmds = 0;
> +                     ipr_hrrq_deactivate(&ioa_cfg->hrrq[i]);
>                       spin_unlock(&ioa_cfg->hrrq[i]._lock);
>               }
>               wmb();
> _
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Iprdd-devel mailing list
> Iprdd-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/iprdd-devel
>

-- 
Gabriel Krisman Bertazi


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

Reply via email to