static void qla4xxx_isr_decode_mailbox()

in qla4xxx/ql4_isr.c [658:1024]


static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
				       uint32_t mbox_status)
{
	int i;
	uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
	__le32 __iomem *mailbox_out;
	uint32_t opcode = 0;

	if (is_qla8032(ha) || is_qla8042(ha))
		mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0];
	else if (is_qla8022(ha))
		mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0];
	else
		mailbox_out = &ha->reg->mailbox[0];

	if ((mbox_status == MBOX_STS_BUSY) ||
	    (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
	    (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) {
		ha->mbox_status[0] = mbox_status;

		if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {
			/*
			 * Copy all mailbox registers to a temporary
			 * location and set mailbox command done flag
			 */
			for (i = 0; i < ha->mbox_status_count; i++)
				ha->mbox_status[i] = readl(&mailbox_out[i]);

			set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);

			if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags))
				complete(&ha->mbx_intr_comp);
		}
	} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
		for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
			mbox_sts[i] = readl(&mailbox_out[i]);

		/* Immediately process the AENs that don't require much work.
		 * Only queue the database_changed AENs */
		if (ha->aen_log.count < MAX_AEN_ENTRIES) {
			for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
				ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =
				    mbox_sts[i];
			ha->aen_log.count++;
		}
		switch (mbox_status) {
		case MBOX_ASTS_SYSTEM_ERROR:
			/* Log Mailbox registers */
			ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);
			qla4xxx_dump_registers(ha);

			if ((is_qla8022(ha) && ql4xdontresethba) ||
			    ((is_qla8032(ha) || is_qla8042(ha)) &&
			     qla4_83xx_idc_dontreset(ha))) {
				DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",
				    ha->host_no, __func__));
			} else {
				set_bit(AF_GET_CRASH_RECORD, &ha->flags);
				set_bit(DPC_RESET_HA, &ha->dpc_flags);
			}
			break;

		case MBOX_ASTS_REQUEST_TRANSFER_ERROR:
		case MBOX_ASTS_RESPONSE_TRANSFER_ERROR:
		case MBOX_ASTS_NVRAM_INVALID:
		case MBOX_ASTS_IP_ADDRESS_CHANGED:
		case MBOX_ASTS_DHCP_LEASE_EXPIRED:
			DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "
				      "Reset HA\n", ha->host_no, mbox_status));
			if (is_qla80XX(ha))
				set_bit(DPC_RESET_HA_FW_CONTEXT,
					&ha->dpc_flags);
			else
				set_bit(DPC_RESET_HA, &ha->dpc_flags);
			break;

		case MBOX_ASTS_LINK_UP:
			set_bit(AF_LINK_UP, &ha->flags);
			if (test_bit(AF_INIT_DONE, &ha->flags))
				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);

			ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__);
			qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP,
					      sizeof(mbox_sts),
					      (uint8_t *) mbox_sts);

			if ((is_qla8032(ha) || is_qla8042(ha)) &&
			    ha->notify_link_up_comp)
				complete(&ha->link_up_comp);

			break;

		case MBOX_ASTS_LINK_DOWN:
			clear_bit(AF_LINK_UP, &ha->flags);
			if (test_bit(AF_INIT_DONE, &ha->flags)) {
				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);
				qla4xxx_wake_dpc(ha);
			}

			ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__);
			qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN,
					      sizeof(mbox_sts),
					      (uint8_t *) mbox_sts);
			break;

		case MBOX_ASTS_HEARTBEAT:
			ha->seconds_since_last_heartbeat = 0;
			break;

		case MBOX_ASTS_DHCP_LEASE_ACQUIRED:
			DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE "
				      "ACQUIRED\n", ha->host_no, mbox_status));
			set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
			break;

		case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM:
		case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target
							   * mode
							   * only */
		case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED:  /* Connection mode */
		case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:
		case MBOX_ASTS_SUBNET_STATE_CHANGE:
		case MBOX_ASTS_DUPLICATE_IP:
			/* No action */
			DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,
				      mbox_status));
			break;

		case MBOX_ASTS_IP_ADDR_STATE_CHANGED:
			printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, "
			    "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0],
			    mbox_sts[2], mbox_sts[3]);

			qla4xxx_update_ipaddr_state(ha, mbox_sts[5],
						    mbox_sts[3]);
			/* mbox_sts[2] = Old ACB state
			 * mbox_sts[3] = new ACB state */
			if ((mbox_sts[3] == IP_ADDRSTATE_PREFERRED) &&
			    ((mbox_sts[2] == IP_ADDRSTATE_TENTATIVE) ||
			     (mbox_sts[2] == IP_ADDRSTATE_ACQUIRING))) {
				set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
			} else if ((mbox_sts[3] == IP_ADDRSTATE_ACQUIRING) &&
				   (mbox_sts[2] == IP_ADDRSTATE_PREFERRED)) {
				if (is_qla80XX(ha))
					set_bit(DPC_RESET_HA_FW_CONTEXT,
						&ha->dpc_flags);
				else
					set_bit(DPC_RESET_HA, &ha->dpc_flags);
			} else if (mbox_sts[3] == IP_ADDRSTATE_DISABLING) {
				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB in disabling state\n",
					   ha->host_no, __func__);
			} else if (mbox_sts[3] == IP_ADDRSTATE_UNCONFIGURED) {
				complete(&ha->disable_acb_comp);
				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB state unconfigured\n",
					   ha->host_no, __func__);
			}
			break;

		case MBOX_ASTS_IPV6_LINK_MTU_CHANGE:
		case MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED:
		case MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED:
			/* No action */
			DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: AEN %04x\n",
					  ha->host_no, mbox_status));
			break;

		case MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD:
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x, IPv6 ERROR, "
					  "mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3}=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
					  ha->host_no, mbox_sts[0], mbox_sts[1],
					  mbox_sts[2], mbox_sts[3], mbox_sts[4],
					  mbox_sts[5]));
			break;

		case MBOX_ASTS_MAC_ADDRESS_CHANGED:
		case MBOX_ASTS_DNS:
			/* No action */
			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
				      "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
				      ha->host_no, mbox_sts[0],
				      mbox_sts[1], mbox_sts[2]));
			break;

		case MBOX_ASTS_SELF_TEST_FAILED:
		case MBOX_ASTS_LOGIN_FAILED:
			/* No action */
			DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
				      "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
				      ha->host_no, mbox_sts[0], mbox_sts[1],
				      mbox_sts[2], mbox_sts[3]));
			break;

		case MBOX_ASTS_DATABASE_CHANGED:
			/* Queue AEN information and process it in the DPC
			 * routine */
			if (ha->aen_q_count > 0) {

				/* decrement available counter */
				ha->aen_q_count--;

				for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
					ha->aen_q[ha->aen_in].mbox_sts[i] =
					    mbox_sts[i];

				/* print debug message */
				DEBUG2(printk("scsi%ld: AEN[%d] %04x queued "
					      "mb1:0x%x mb2:0x%x mb3:0x%x "
					      "mb4:0x%x mb5:0x%x\n",
					      ha->host_no, ha->aen_in,
					      mbox_sts[0], mbox_sts[1],
					      mbox_sts[2], mbox_sts[3],
					      mbox_sts[4], mbox_sts[5]));

				/* advance pointer */
				ha->aen_in++;
				if (ha->aen_in == MAX_AEN_ENTRIES)
					ha->aen_in = 0;

				/* The DPC routine will process the aen */
				set_bit(DPC_AEN, &ha->dpc_flags);
			} else {
				DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
					      "overflowed!  AEN LOST!!\n",
					      ha->host_no, __func__,
					      mbox_sts[0]));

				DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
					      ha->host_no));

				for (i = 0; i < MAX_AEN_ENTRIES; i++) {
					DEBUG2(printk("AEN[%d] %04x %04x %04x "
						      "%04x\n", i, mbox_sts[0],
						      mbox_sts[1], mbox_sts[2],
						      mbox_sts[3]));
				}
			}
			break;

		case MBOX_ASTS_TXSCVR_INSERTED:
			DEBUG2(printk(KERN_WARNING
			    "scsi%ld: AEN %04x Transceiver"
			    " inserted\n",  ha->host_no, mbox_sts[0]));
			break;

		case MBOX_ASTS_TXSCVR_REMOVED:
			DEBUG2(printk(KERN_WARNING
			    "scsi%ld: AEN %04x Transceiver"
			    " removed\n",  ha->host_no, mbox_sts[0]));
			break;

		case MBOX_ASTS_IDC_REQUEST_NOTIFICATION:
			if (is_qla8032(ha) || is_qla8042(ha)) {
				DEBUG2(ql4_printk(KERN_INFO, ha,
						  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",
						  ha->host_no, mbox_sts[0],
						  mbox_sts[1], mbox_sts[2],
						  mbox_sts[3], mbox_sts[4]));
				opcode = mbox_sts[1] >> 16;
				if ((opcode == MBOX_CMD_SET_PORT_CONFIG) ||
				    (opcode == MBOX_CMD_PORT_RESET)) {
					set_bit(DPC_POST_IDC_ACK,
						&ha->dpc_flags);
					ha->idc_info.request_desc = mbox_sts[1];
					ha->idc_info.info1 = mbox_sts[2];
					ha->idc_info.info2 = mbox_sts[3];
					ha->idc_info.info3 = mbox_sts[4];
					qla4xxx_wake_dpc(ha);
				}
			}
			break;

		case MBOX_ASTS_IDC_COMPLETE:
			if (is_qla8032(ha) || is_qla8042(ha)) {
				DEBUG2(ql4_printk(KERN_INFO, ha,
						  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",
						  ha->host_no, mbox_sts[0],
						  mbox_sts[1], mbox_sts[2],
						  mbox_sts[3], mbox_sts[4]));
				DEBUG2(ql4_printk(KERN_INFO, ha,
						  "scsi:%ld: AEN %04x IDC Complete notification\n",
						  ha->host_no, mbox_sts[0]));

				opcode = mbox_sts[1] >> 16;
				if (ha->notify_idc_comp)
					complete(&ha->idc_comp);

				if ((opcode == MBOX_CMD_SET_PORT_CONFIG) ||
				    (opcode == MBOX_CMD_PORT_RESET))
					ha->idc_info.info2 = mbox_sts[3];

				if (qla4_83xx_loopback_in_progress(ha)) {
					set_bit(AF_LOOPBACK, &ha->flags);
				} else {
					clear_bit(AF_LOOPBACK, &ha->flags);
					if (ha->saved_acb)
						set_bit(DPC_RESTORE_ACB,
							&ha->dpc_flags);
				}
				qla4xxx_wake_dpc(ha);
			}
			break;

		case MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED:
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
					  ha->host_no, mbox_sts[0], mbox_sts[1],
					  mbox_sts[2], mbox_sts[3], mbox_sts[4],
					  mbox_sts[5]));
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x Received IPv6 default router changed notification\n",
					  ha->host_no, mbox_sts[0]));
			qla4xxx_default_router_changed(ha, mbox_sts);
			break;

		case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION:
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
					  ha->host_no, mbox_sts[0], mbox_sts[1],
					  mbox_sts[2], mbox_sts[3], mbox_sts[4],
					  mbox_sts[5]));
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x Received IDC Extend Timeout notification\n",
					  ha->host_no, mbox_sts[0]));
			/* new IDC timeout */
			ha->idc_extend_tmo = mbox_sts[1];
			break;

		case MBOX_ASTS_INITIALIZATION_FAILED:
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n",
					  ha->host_no, mbox_sts[0],
					  mbox_sts[3]));
			break;

		case MBOX_ASTS_SYSTEM_WARNING_EVENT:
			DEBUG2(ql4_printk(KERN_WARNING, ha,
					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
					  ha->host_no, mbox_sts[0], mbox_sts[1],
					  mbox_sts[2], mbox_sts[3], mbox_sts[4],
					  mbox_sts[5]));
			break;

		case MBOX_ASTS_DCBX_CONF_CHANGE:
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",
					  ha->host_no, mbox_sts[0], mbox_sts[1],
					  mbox_sts[2], mbox_sts[3], mbox_sts[4],
					  mbox_sts[5]));
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld: AEN %04x Received DCBX configuration changed notification\n",
					  ha->host_no, mbox_sts[0]));
			break;

		default:
			DEBUG2(printk(KERN_WARNING
				      "scsi%ld: AEN %04x UNKNOWN\n",
				      ha->host_no, mbox_sts[0]));
			break;
		}
	} else {
		DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n",
			      ha->host_no, mbox_status));

		ha->mbox_status[0] = mbox_status;
	}
}