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

Commit 6b393722 authored by Ching Huang's avatar Ching Huang Committed by Christoph Hellwig
Browse files

arcmsr: fix command timeout under heavy load



This patch rewrites the interrupt service routine relate function to fix
a command timeout under heavy controller load.

Signed-off-by: default avatarChing Huang <ching2048@areca.com.tw>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 0d9d8b9f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ struct device_attribute;
#else
	#define ARCMSR_MAX_FREECCB_NUM	320
#endif
#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15 2010/08/05"
#define ARCMSR_DRIVER_VERSION		"v1.30.00.04-20140428"
#define ARCMSR_SCSI_INITIATOR_ID						255
#define ARCMSR_MAX_XFER_SECTORS							512
#define ARCMSR_MAX_XFER_SECTORS_B						4096
+97 −101
Original line number Diff line number Diff line
@@ -1441,14 +1441,15 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
	uint32_t outbound_doorbell;
	struct MessageUnit_A __iomem *reg = acb->pmuA;
	outbound_doorbell = readl(&reg->outbound_doorbell);
	do {
		writel(outbound_doorbell, &reg->outbound_doorbell);
	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
		if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
			arcmsr_iop2drv_data_wrote_handle(acb);
	}

	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
		if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
			arcmsr_iop2drv_data_read_handle(acb);
	}
		outbound_doorbell = readl(&reg->outbound_doorbell);
	} while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
		| ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
}
static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
{
@@ -1462,17 +1463,19 @@ static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
	*******************************************************************
	*/
	outbound_doorbell = readl(&reg->outbound_doorbell);
	writel(outbound_doorbell, &reg->outbound_doorbell_clear);/*clear interrupt*/
	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
	do {
		writel(outbound_doorbell, &reg->outbound_doorbell_clear);
		readl(&reg->outbound_doorbell_clear);
		if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK)
			arcmsr_iop2drv_data_wrote_handle(pACB);
	}
	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
		if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK)
			arcmsr_iop2drv_data_read_handle(pACB);
	}
	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
		arcmsr_hbc_message_isr(pACB);    /* messenger of "driver to iop commands" */
	}
	return;
		if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE)
			arcmsr_hbc_message_isr(pACB);
		outbound_doorbell = readl(&reg->outbound_doorbell);
	} while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK
		| ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK
		| ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE));
}
static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
{
@@ -1521,21 +1524,23 @@ static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
	/* areca cdb command done */
	/* Use correct offset and size for syncing */

	while (readl(&phbcmu->host_int_status) &
	ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){
	/* check if command done with no error*/
	flag_ccb = readl(&phbcmu->outbound_queueport_low);
	ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/
	arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
	ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
	error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
	while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) !=
			0xFFFFFFFF) {
		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
			+ ccb_cdb_phy);
		ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
			arcmsr_cdb);
		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
			? true : false;
		/* check if command done with no error */
		arcmsr_drain_donequeue(acb, ccb, error);
		throttling++;
		if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
		writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell);
		break;
			writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING,
				&phbcmu->inbound_doorbell);
			throttling = 0;
		}
	throttling++;
	}
}
/*
@@ -1584,21 +1589,22 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
	struct MessageUnit_A __iomem *reg = acb->pmuA;
	outbound_intstatus = readl(&reg->outbound_intstatus) &
		acb->outbound_int_enable;
	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))	{
		return 1;
	}
	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
		return IRQ_NONE;
	do {
		writel(outbound_intstatus, &reg->outbound_intstatus);
	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)	{
		if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
			arcmsr_hba_doorbell_isr(acb);
	}
	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
		if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
			arcmsr_hba_postqueue_isr(acb);
	}
	if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) 	{
		/* messenger of "driver to iop commands" */
		if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
			arcmsr_hba_message_isr(acb);
	}
	return 0;
		outbound_intstatus = readl(&reg->outbound_intstatus) &
			acb->outbound_int_enable;
	} while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT
		| ARCMSR_MU_OUTBOUND_POSTQUEUE_INT
		| ARCMSR_MU_OUTBOUND_MESSAGE0_INT));
	return IRQ_HANDLED;
}

static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
@@ -1608,27 +1614,25 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
	outbound_doorbell = readl(reg->iop2drv_doorbell) &
				acb->outbound_int_enable;
	if (!outbound_doorbell)
		return 1;

		return IRQ_NONE;
	do {
		writel(~outbound_doorbell, reg->iop2drv_doorbell);
	/*in case the last action of doorbell interrupt clearance is cached,
	this action can push HW to write down the clear bit*/
	readl(reg->iop2drv_doorbell);
		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
		if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
			arcmsr_iop2drv_data_wrote_handle(acb);
	}
	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
		if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
			arcmsr_iop2drv_data_read_handle(acb);
	}
	if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
		if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
			arcmsr_hbb_postqueue_isr(acb);
	}
	if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
		/* messenger of "driver to iop commands" */
		if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)
			arcmsr_hbb_message_isr(acb);
	}
	return 0;
		outbound_doorbell = readl(reg->iop2drv_doorbell) &
			acb->outbound_int_enable;
	} while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK
		| ARCMSR_IOP2DRV_DATA_READ_OK
		| ARCMSR_IOP2DRV_CDB_DONE
		| ARCMSR_IOP2DRV_MESSAGE_CMD_DONE));
	return IRQ_HANDLED;
}

static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
@@ -1640,45 +1644,37 @@ static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
	**   check outbound intstatus
	*********************************************
	*/
	host_interrupt_status = readl(&phbcmu->host_int_status);
	if (!host_interrupt_status) {
		/*it must be share irq*/
		return 1;
	}
	/* MU ioctl transfer doorbell interrupts*/
	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
		arcmsr_hbc_doorbell_isr(pACB);   /* messenger of "ioctl message read write" */
	}
	host_interrupt_status = readl(&phbcmu->host_int_status) &
		(ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
		ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR);
	if (!host_interrupt_status)
		return IRQ_NONE;
	do {
		if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR)
			arcmsr_hbc_doorbell_isr(pACB);
		/* MU post queue interrupts*/
	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
		arcmsr_hbc_postqueue_isr(pACB);  /* messenger of "scsi commands" */
	}
	return 0;
		if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)
			arcmsr_hbc_postqueue_isr(pACB);
		host_interrupt_status = readl(&phbcmu->host_int_status);
	} while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
		ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
	return IRQ_HANDLED;
}
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
{
	switch (acb->adapter_type) {
	case ACB_ADAPTER_TYPE_A: {
		if (arcmsr_handle_hba_isr(acb)) {
			return IRQ_NONE;
		}
		}
	case ACB_ADAPTER_TYPE_A:
		return arcmsr_handle_hba_isr(acb);
		break;

	case ACB_ADAPTER_TYPE_B: {
		if (arcmsr_handle_hbb_isr(acb)) {
			return IRQ_NONE;
		}
		}
	case ACB_ADAPTER_TYPE_B:
		return arcmsr_handle_hbb_isr(acb);
		break;
	 case ACB_ADAPTER_TYPE_C: {
		if (arcmsr_handle_hbc_isr(acb)) {
	case ACB_ADAPTER_TYPE_C:
		return arcmsr_handle_hbc_isr(acb);
	default:
		return IRQ_NONE;
	}
}
	}
	return IRQ_HANDLED;
}

static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
{