예제 #1
0
/**
 * qla4xxx_mailbox_command - issues mailbox commands
 * @ha: Pointer to host adapter structure.
 * @inCount: number of mailbox registers to load.
 * @outCount: number of mailbox registers to return.
 * @mbx_cmd: data pointer for mailbox in registers.
 * @mbx_sts: data pointer for mailbox out registers.
 *
 * This routine sssue mailbox commands and waits for completion.
 * If outCount is 0, this routine completes successfully WITHOUT waiting
 * for the mailbox command to complete.
 **/
static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
				   uint8_t outCount, uint32_t *mbx_cmd,
				   uint32_t *mbx_sts)
{
	int status = QLA_ERROR;
	uint8_t i;
	u_long wait_count;
	uint32_t intr_status;
	unsigned long flags = 0;

	/* Make sure that pointers are valid */
	if (!mbx_cmd || !mbx_sts) {
		DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts "
			      "pointer\n", ha->host_no, __func__));
		return status;
	}
	/* Mailbox code active */
	wait_count = MBOX_TOV * 100;

	while (wait_count--) {
		mutex_lock(&ha->mbox_sem);
		if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) {
			set_bit(AF_MBOX_COMMAND, &ha->flags);
			mutex_unlock(&ha->mbox_sem);
			break;
		}
		mutex_unlock(&ha->mbox_sem);
		if (!wait_count) {
			DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n",
				ha->host_no, __func__));
			return status;
		}
		msleep(10);
	}

	/* To prevent overwriting mailbox registers for a command that has
	 * not yet been serviced, check to see if a previously issued
	 * mailbox command is interrupting.
	 * -----------------------------------------------------------------
	 */
	spin_lock_irqsave(&ha->hardware_lock, flags);
	intr_status = readl(&ha->reg->ctrl_status);
	if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
		/* Service existing interrupt */
		qla4xxx_interrupt_service_routine(ha, intr_status);
		clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
	}

	/* Send the mailbox command to the firmware */
	ha->mbox_status_count = outCount;
	for (i = 0; i < outCount; i++)
		ha->mbox_status[i] = 0;

	/* Load all mailbox registers, except mailbox 0. */
	for (i = 1; i < inCount; i++)
		writel(mbx_cmd[i], &ha->reg->mailbox[i]);

	/* Wakeup firmware  */
	writel(mbx_cmd[0], &ha->reg->mailbox[0]);
	readl(&ha->reg->mailbox[0]);
	writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
	readl(&ha->reg->ctrl_status);
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	/* Wait for completion */

	/*
	 * If we don't want status, don't wait for the mailbox command to
	 * complete.  For example, MBOX_CMD_RESET_FW doesn't return status,
	 * you must poll the inbound Interrupt Mask for completion.
	 */
	if (outCount == 0) {
		status = QLA_SUCCESS;
		goto mbox_exit;
	}
	/* Wait for command to complete */
	wait_count = jiffies + MBOX_TOV * HZ;
	while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
		if (time_after_eq(jiffies, wait_count))
			break;

		spin_lock_irqsave(&ha->hardware_lock, flags);
		intr_status = readl(&ha->reg->ctrl_status);
		if (intr_status & INTR_PENDING) {
			/*
			 * Service the interrupt.
			 * The ISR will save the mailbox status registers
			 * to a temporary storage location in the adapter
			 * structure.
			 */
			ha->mbox_status_count = outCount;
			qla4xxx_interrupt_service_routine(ha, intr_status);
		}
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
		msleep(10);
	}

	/* Check for mailbox timeout. */
	if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
		DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
			      " Scheduling Adapter Reset\n", ha->host_no,
			      mbx_cmd[0]));
		ha->mailbox_timeout_count++;
		mbx_sts[0] = (-1);
		set_bit(DPC_RESET_HA, &ha->dpc_flags);
		goto mbox_exit;
	}

	/*
	 * Copy the mailbox out registers to the caller's mailbox in/out
	 * structure.
	 */
	spin_lock_irqsave(&ha->hardware_lock, flags);
	for (i = 0; i < outCount; i++)
		mbx_sts[i] = ha->mbox_status[i];

	/* Set return status and error flags (if applicable). */
	switch (ha->mbox_status[0]) {
	case MBOX_STS_COMMAND_COMPLETE:
		status = QLA_SUCCESS;
		break;

	case MBOX_STS_INTERMEDIATE_COMPLETION:
		status = QLA_SUCCESS;
		break;

	case MBOX_STS_BUSY:
		DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
			       ha->host_no, __func__, mbx_cmd[0]));
		ha->mailbox_timeout_count++;
		break;

	default:
		DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
			      "sts = %08X ****\n", ha->host_no, __func__,
			      mbx_cmd[0], mbx_sts[0]));
		break;
	}
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

mbox_exit:
	mutex_lock(&ha->mbox_sem);
	clear_bit(AF_MBOX_COMMAND, &ha->flags);
	mutex_unlock(&ha->mbox_sem);
	clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);

	return status;
}
예제 #2
0
/**************************************************************************
 * qla4xxx_mailbox_command
 *	This routine sssue mailbox commands and waits for completion.
 *
 * Input:
 * 	ha - Pointer to host adapter structure.
 *	inCount	 - number of mailbox registers to load.
 *      outCount - number of mailbox registers to return.
 *      mbx_cmd  - data pointer for mailbox in registers.
 *      mbx_sts  - data pointer for mailbox out registers.
 *
 * Output:
 *      mbx_sts - returned mailbox out data.
 *
 * Remarks:
 *	If outCount is 0, this routine completes successfully WITHOUT waiting
 *	for the mailbox command to complete.
 *
 * Returns:
 *	QLA_SUCCESS - Mailbox command completed successfully
 *	QLA_ERROR   - Mailbox command competed in error.
 *
 * Context:
 *	Kernel context.
 **************************************************************************/
uint8_t
qla4xxx_mailbox_command(scsi_qla_host_t *ha,
			uint8_t inCount,
			uint8_t outCount,
			uint32_t *mbx_cmd,
			uint32_t *mbx_sts)
{
	uint8_t      status = QLA_ERROR;
	uint8_t      i;
	u_long     wait_count;
	uint32_t     intr_status;
	unsigned long flags = 0;
	DECLARE_WAITQUEUE(wait, current);


	down(&ha->mbox_sem);
	set_bit(AF_MBOX_COMMAND, &ha->flags);

	/* Make sure that pointers are valid */
	if (!mbx_cmd || !mbx_sts) {
		QL4PRINT(QLP2,
			 printk("scsi%d: %s: Invalid mbx_cmd or mbx_sts pointer\n",
				ha->host_no, __func__));

		goto mbox_exit;
	}

	/* To prevent overwriting mailbox registers for a command that has
	 * not yet been serviced, check to see if a previously issued
	 * mailbox command is interrupting.
	 * -----------------------------------------------------------------
	 */
	spin_lock_irqsave(&ha->hardware_lock, flags);
	intr_status = RD_REG_DWORD(&ha->reg->ctrl_status);
	if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
		QL4PRINT(QLP5,
			 printk("scsi%d: %s: Trying to execute a mailbox request, "
				"while another one is interrupting\n"
				"Service existing interrupt first\n",
				ha->host_no, __func__));

		/* Service existing interrupt */
		qla4xxx_interrupt_service_routine(ha, intr_status);

		clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
	}


	/* Send the mailbox command to the firmware
	 * ----------------------------------------
	 */
	ha->f_start = jiffies;
	ha->mbox_status_count = outCount;
	for (i=0; i < MBOX_REG_COUNT; i++) {
		ha->mbox_status[i] = 0;
	}

	for (i=0; i<inCount; i++) {
		QL4PRINT(QLP11, printk("scsi%d: %s: Mailbox In[%d]  0x%08X\n",
				       ha->host_no, __func__, i, mbx_cmd[i]));
	}

	/* Load all mailbox registers, except mailbox 0.*/
	for (i = 1; i < inCount; i++) {
		WRT_REG_DWORD(&ha->reg->mailbox[i], mbx_cmd[i]);
	}
	for (i = inCount; i < MBOX_REG_COUNT; i++) {
		WRT_REG_DWORD(&ha->reg->mailbox[i], 0);
	}

	/* Write Mailbox 0 to alert the firmware that the mailbox registers
	 * contain a command to be processed.  NOTE: We could be interrupted
	 * here if system interrupts are enabled */
	WRT_REG_DWORD(&ha->reg->mailbox[0], mbx_cmd[0]);
	PCI_POSTING(&ha->reg->mailbox[0]);
	WRT_REG_DWORD(&ha->reg->ctrl_status, SET_RMASK(CSR_INTR_RISC));
	PCI_POSTING(&ha->reg->ctrl_status);

	spin_unlock_irqrestore(&ha->hardware_lock, flags);
	add_wait_queue(&ha->mailbox_wait_queue,&wait);

	/*
	 * If we don't want status, don't wait for the mailbox command to
	 * complete.  For example, MBOX_CMD_RESET_FW doesn't return status,
	 * you must poll the inbound Interrupt Mask for completion.
	 */
	if (outCount == 0) {
		status = QLA_SUCCESS;
		remove_wait_queue(&ha->mailbox_wait_queue,&wait);
		ha->f_end = jiffies;
		goto mbox_exit;
	}

	/*
	 * Wait for command to complete
	 * -----------------------------
	 */
	wait_count = jiffies + MBOX_TOV * HZ;
	while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
		if (time_after_eq(jiffies, wait_count)) {	
			break;
		}

		spin_lock_irqsave(&ha->hardware_lock, flags);

		intr_status = RD_REG_DWORD(&ha->reg->ctrl_status);

		QL4PRINT(QLP11, printk("scsi%d: %s: INTR_STATUS = 0x%X\n",
				       ha->host_no, __func__, intr_status));

		if (intr_status & INTR_PENDING) {
			/*
			 * Service the interrupt.
			 * The ISR will save the mailbox status registers
			 * to a temporary storage location in the adapter
			 * structure.
			 */
			ha->mbox_status_count = outCount;
			qla4xxx_interrupt_service_routine(ha, intr_status);
			
			if (!list_empty(&ha->done_srb_q))
				qla4xxx_done(ha);
		}
		spin_unlock_irqrestore(&ha->hardware_lock, flags);

				/*
		 * Delay for 10 microseconds
		 * NOTE: Interrupt_handler may be called here,
		 *       if interrupts are enabled
		 */
                 mdelay(10);
	} /* wait loop */

	remove_wait_queue(&ha->mailbox_wait_queue,&wait);

	/*
	 * Check for mailbox timeout
	 */
	if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
		QL4PRINT(QLP2,
			 printk("scsi%d: Mailbox Cmd 0x%08X timed out ...,"
				" Scheduling Adapter Reset\n",
				ha->host_no, mbx_cmd[0]));

		ha->mailbox_timeout_count++;
		mbx_sts[0] = (-1);

		/*
		 * If the mailbox timed out due to CSR_SCSI_RESET_INTR,
		 * then the adapter will simply reinitialize, otherwise,
		 * a full on adapter reset will be done.
		 */
		if (qla4xxx_poll_and_ack_scsi_reset(ha) == QLA_ERROR)
			set_bit(DPC_RESET_HA, &ha->dpc_flags);
		goto mbox_exit;
	}

	QL4PRINT(QLP11,
		 printk("scsi%d: %s: mailbox cmd done!\n",
			ha->host_no, __func__));

	/*
	 * Copy the mailbox out registers to the caller's mailbox in/out
	 * structure.
	 */
	spin_lock_irqsave(&ha->hardware_lock, flags);
	for (i=0; i < outCount; i++) {
		mbx_sts[i] = ha->mbox_status[i];
		QL4PRINT(QLP11,
			 printk("scsi%d: %s: Mailbox Status[%d]  0x%08X\n",
				ha->host_no, __func__, i, mbx_sts[i]));
	}

	/*
	 * Set return status and error flags (if applicable)
	 */
	switch (ha->mbox_status[0]) {
	
	case MBOX_STS_COMMAND_COMPLETE:
		status = QLA_SUCCESS;
		break;

	case MBOX_STS_INTERMEDIATE_COMPLETION:
		status = QLA_SUCCESS;
		QL4PRINT(QLP5,
			 printk("scsi%d: %s: Cmd = %08X, Intermediate completion\n",
				ha->host_no, __func__, mbx_cmd[0]));
		break;

	case MBOX_STS_BUSY:
		QL4PRINT(QLP2, printk("scsi%d: %s: Cmd = %08X, ISP BUSY\n",
				      ha->host_no, __func__, mbx_cmd[0]));

		ha->mailbox_timeout_count++;
		break;

	case MBOX_STS_COMMAND_PARAMETER_ERROR:
		break;

	case MBOX_STS_INVALID_COMMAND:
	case MBOX_STS_HOST_INTERFACE_ERROR:
	case MBOX_STS_TEST_FAILED:
	case MBOX_STS_COMMAND_ERROR:
	default:
		QL4PRINT(QLP2,
			 printk("scsi%d: %s: **** FAILED, cmd = %08X, "
				"sts = %08X ****\n",
				ha->host_no, __func__, mbx_cmd[0], mbx_sts[0]));


		__dump_registers(QLP2, ha);
		break;
	} /* switch mbox status */
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	mbox_exit:
	clear_bit(AF_MBOX_COMMAND, &ha->flags);
	clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
	up(&ha->mbox_sem);

	return(status);
}