/*
* QLogic iSCSI HBA Driver
* Copyright (c) 2003-2010 QLogic Corporation
*
* See LICENSE.qla4xxx for copyright and licensing details.
*/
#include "ql4_def.h"
#include "ql4_glbl.h"
#include "ql4_dbg.h"
#include "ql4_inline.h"
/**
* 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 isssue mailbox commands and waits for completion.
* If outCount is 0, this routine completes successfully WITHOUT waiting
* for the mailbox command to complete.
**/
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;
}
if (is_qla8022(ha) &&
test_bit(AF_FW_RECOVERY, &ha->flags)) {
DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: prematurely "
"completing mbx cmd as firmware recovery detected\n",
ha->host_no, __func__));
return status;
}
if ((is_aer_supported(ha)) &&
(test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) {
DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, "
"timeout MBX Exiting.\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 an active command
* (AEN, IOCB, etc.) is interrupting, then service it.
* -----------------------------------------------------------------
*/
spin_lock_irqsave(&ha->hardware_lock, flags);
if (!is_qla8022(ha)) {
intr_status = readl(&ha->reg->ctrl_status);
if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
/* Service existing interrupt */
ha->isp_ops->interrupt_service_routine(ha, intr_status);
clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
}
}
ha->mbox_status_count = outCount;
for (i = 0; i < outCount; i++)
ha->mbox_status[i] = 0;
if (is_qla8022(ha)) {
/* Load all mailbox registers, except mailbox 0. */
DEBUG5(
printk("scsi%ld: %s: Cmd ", ha->host_no, __func__);
for (i = 0; i < inCount; i++)
printk("mb%d=%04x ", i, mbx_cmd[i]);
printk("\n"));
for (