Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 172cd6e1 authored by Brian King's avatar Brian King Committed by James Bottomley
Browse files

[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: default avatarBrian King <brking@linux.vnet.ibm.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 00bfef2c
Loading
Loading
Loading
Loading
+46 −14
Original line number Diff line number Diff line
@@ -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)
#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_cmd:	ipr command struct
@@ -611,11 +628,13 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
 * Return value:
 * 	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_cmd->u.scratch = 0;
	ipr_cmd->sibling = NULL;
	ipr_cmd->fast_done = fast_done;
	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_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;
}

@@ -5130,8 +5149,9 @@ static irqreturn_t ipr_isr(int irq, void *devp)
	u16 cmd_index;
	int num_hrrq = 0;
	int irq_none = 0;
	struct ipr_cmnd *ipr_cmd;
	struct ipr_cmnd *ipr_cmd, *temp;
	irqreturn_t rc = IRQ_NONE;
	LIST_HEAD(doneq);

	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)) {
				ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
				return IRQ_HANDLED;
				rc = IRQ_HANDLED;
				goto unlock_out;
			}

			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);

			list_del(&ipr_cmd->queue);
			del_timer(&ipr_cmd->timer);
			ipr_cmd->done(ipr_cmd);
			list_move_tail(&ipr_cmd->queue, &doneq);

			rc = IRQ_HANDLED;

@@ -5194,8 +5212,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
		} else if (num_hrrq == IPR_MAX_HRRQ_RETRIES &&
			   int_reg & IPR_PCII_HRRQ_UPDATED) {
			ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
			return IRQ_HANDLED;
			rc = IRQ_HANDLED;
			goto unlock_out;
		} else
			break;
	}
@@ -5203,7 +5221,14 @@ static irqreturn_t ipr_isr(int irq, void *devp)
	if (unlikely(rc == IRQ_NONE))
		rc = ipr_handle_other_interrupt(ioa_cfg, int_reg);

unlock_out:
	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;
}

@@ -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 scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
	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));

	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);
		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);
		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);
	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;

	memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len);
	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 (scsi_cmd->underflow == 0)
+1 −0
Original line number Diff line number Diff line
@@ -1525,6 +1525,7 @@ struct ipr_cmnd {
	struct ata_queued_cmd *qc;
	struct completion completion;
	struct timer_list timer;
	void (*fast_done) (struct ipr_cmnd *);
	void (*done) (struct ipr_cmnd *);
	int (*job_step) (struct ipr_cmnd *);
	int (*job_step_failed) (struct ipr_cmnd *);