[SCSI] ipr: Reduce interrupt lock time
Reduce the amount of time the host lock is held in the interrupt handler for improved performance. [jejb: fix up checkpatch noise] Signed-off-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:

committed by
James Bottomley

parent
00bfef2cc1
commit
172cd6e187
@@ -565,6 +565,23 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
|
|||||||
#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
|
#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipr_lock_and_done - Acquire lock and complete command
|
||||||
|
* @ipr_cmd: ipr command struct
|
||||||
|
*
|
||||||
|
* Return value:
|
||||||
|
* none
|
||||||
|
**/
|
||||||
|
static void ipr_lock_and_done(struct ipr_cmnd *ipr_cmd)
|
||||||
|
{
|
||||||
|
unsigned long lock_flags;
|
||||||
|
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
||||||
|
|
||||||
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
ipr_cmd->done(ipr_cmd);
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse
|
* ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse
|
||||||
* @ipr_cmd: ipr command struct
|
* @ipr_cmd: ipr command struct
|
||||||
@@ -611,11 +628,13 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
|
|||||||
* Return value:
|
* Return value:
|
||||||
* none
|
* none
|
||||||
**/
|
**/
|
||||||
static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
|
static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd,
|
||||||
|
void (*fast_done) (struct ipr_cmnd *))
|
||||||
{
|
{
|
||||||
ipr_reinit_ipr_cmnd(ipr_cmd);
|
ipr_reinit_ipr_cmnd(ipr_cmd);
|
||||||
ipr_cmd->u.scratch = 0;
|
ipr_cmd->u.scratch = 0;
|
||||||
ipr_cmd->sibling = NULL;
|
ipr_cmd->sibling = NULL;
|
||||||
|
ipr_cmd->fast_done = fast_done;
|
||||||
init_timer(&ipr_cmd->timer);
|
init_timer(&ipr_cmd->timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,7 +667,7 @@ static
|
|||||||
struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
|
struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
|
||||||
{
|
{
|
||||||
struct ipr_cmnd *ipr_cmd = __ipr_get_free_ipr_cmnd(ioa_cfg);
|
struct ipr_cmnd *ipr_cmd = __ipr_get_free_ipr_cmnd(ioa_cfg);
|
||||||
ipr_init_ipr_cmnd(ipr_cmd);
|
ipr_init_ipr_cmnd(ipr_cmd, ipr_lock_and_done);
|
||||||
return ipr_cmd;
|
return ipr_cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5130,8 +5149,9 @@ static irqreturn_t ipr_isr(int irq, void *devp)
|
|||||||
u16 cmd_index;
|
u16 cmd_index;
|
||||||
int num_hrrq = 0;
|
int num_hrrq = 0;
|
||||||
int irq_none = 0;
|
int irq_none = 0;
|
||||||
struct ipr_cmnd *ipr_cmd;
|
struct ipr_cmnd *ipr_cmd, *temp;
|
||||||
irqreturn_t rc = IRQ_NONE;
|
irqreturn_t rc = IRQ_NONE;
|
||||||
|
LIST_HEAD(doneq);
|
||||||
|
|
||||||
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
|
||||||
@@ -5152,8 +5172,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
|
|||||||
|
|
||||||
if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
|
if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
|
||||||
ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
|
ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
rc = IRQ_HANDLED;
|
||||||
return IRQ_HANDLED;
|
goto unlock_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index];
|
ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index];
|
||||||
@@ -5162,9 +5182,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
|
|||||||
|
|
||||||
ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc);
|
ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc);
|
||||||
|
|
||||||
list_del(&ipr_cmd->queue);
|
list_move_tail(&ipr_cmd->queue, &doneq);
|
||||||
del_timer(&ipr_cmd->timer);
|
|
||||||
ipr_cmd->done(ipr_cmd);
|
|
||||||
|
|
||||||
rc = IRQ_HANDLED;
|
rc = IRQ_HANDLED;
|
||||||
|
|
||||||
@@ -5194,8 +5212,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
|
|||||||
} else if (num_hrrq == IPR_MAX_HRRQ_RETRIES &&
|
} else if (num_hrrq == IPR_MAX_HRRQ_RETRIES &&
|
||||||
int_reg & IPR_PCII_HRRQ_UPDATED) {
|
int_reg & IPR_PCII_HRRQ_UPDATED) {
|
||||||
ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
|
ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
rc = IRQ_HANDLED;
|
||||||
return IRQ_HANDLED;
|
goto unlock_out;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -5203,7 +5221,14 @@ static irqreturn_t ipr_isr(int irq, void *devp)
|
|||||||
if (unlikely(rc == IRQ_NONE))
|
if (unlikely(rc == IRQ_NONE))
|
||||||
rc = ipr_handle_other_interrupt(ioa_cfg, int_reg);
|
rc = ipr_handle_other_interrupt(ioa_cfg, int_reg);
|
||||||
|
|
||||||
|
unlock_out:
|
||||||
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) {
|
||||||
|
list_del(&ipr_cmd->queue);
|
||||||
|
del_timer(&ipr_cmd->timer);
|
||||||
|
ipr_cmd->fast_done(ipr_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5784,15 +5809,22 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
|
|||||||
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
|
||||||
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
|
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
|
||||||
u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
|
u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
|
||||||
|
unsigned long lock_flags;
|
||||||
|
|
||||||
scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len));
|
scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len));
|
||||||
|
|
||||||
if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
|
if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
|
||||||
scsi_dma_unmap(ipr_cmd->scsi_cmd);
|
scsi_dma_unmap(scsi_cmd);
|
||||||
|
|
||||||
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
|
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
|
||||||
scsi_cmd->scsi_done(scsi_cmd);
|
scsi_cmd->scsi_done(scsi_cmd);
|
||||||
} else
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
} else {
|
||||||
|
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
|
||||||
ipr_erp_start(ioa_cfg, ipr_cmd);
|
ipr_erp_start(ioa_cfg, ipr_cmd);
|
||||||
|
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5848,12 +5880,12 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
|
|||||||
ipr_cmd = __ipr_get_free_ipr_cmnd(ioa_cfg);
|
ipr_cmd = __ipr_get_free_ipr_cmnd(ioa_cfg);
|
||||||
spin_unlock_irqrestore(shost->host_lock, lock_flags);
|
spin_unlock_irqrestore(shost->host_lock, lock_flags);
|
||||||
|
|
||||||
ipr_init_ipr_cmnd(ipr_cmd);
|
ipr_init_ipr_cmnd(ipr_cmd, ipr_scsi_done);
|
||||||
ioarcb = &ipr_cmd->ioarcb;
|
ioarcb = &ipr_cmd->ioarcb;
|
||||||
|
|
||||||
memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len);
|
memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len);
|
||||||
ipr_cmd->scsi_cmd = scsi_cmd;
|
ipr_cmd->scsi_cmd = scsi_cmd;
|
||||||
ipr_cmd->done = ipr_scsi_done;
|
ipr_cmd->done = ipr_scsi_eh_done;
|
||||||
|
|
||||||
if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
|
if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
|
||||||
if (scsi_cmd->underflow == 0)
|
if (scsi_cmd->underflow == 0)
|
||||||
|
@@ -1525,6 +1525,7 @@ struct ipr_cmnd {
|
|||||||
struct ata_queued_cmd *qc;
|
struct ata_queued_cmd *qc;
|
||||||
struct completion completion;
|
struct completion completion;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
|
void (*fast_done) (struct ipr_cmnd *);
|
||||||
void (*done) (struct ipr_cmnd *);
|
void (*done) (struct ipr_cmnd *);
|
||||||
int (*job_step) (struct ipr_cmnd *);
|
int (*job_step) (struct ipr_cmnd *);
|
||||||
int (*job_step_failed) (struct ipr_cmnd *);
|
int (*job_step_failed) (struct ipr_cmnd *);
|
||||||
|
Reference in New Issue
Block a user