qla_isr.c

来自「linux 内核源代码」· C语言 代码 · 共 1,902 行 · 第 1/4 页

C
1,902
字号
/** * qla24xx_process_response_queue() - Process response queue entries. * @ha: SCSI driver HA context */voidqla24xx_process_response_queue(struct scsi_qla_host *ha){	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;	struct sts_entry_24xx *pkt;	if (!ha->flags.online)		return;	while (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {		pkt = (struct sts_entry_24xx *)ha->response_ring_ptr;		ha->rsp_ring_index++;		if (ha->rsp_ring_index == ha->response_q_length) {			ha->rsp_ring_index = 0;			ha->response_ring_ptr = ha->response_ring;		} else {			ha->response_ring_ptr++;		}		if (pkt->entry_status != 0) {			DEBUG3(printk(KERN_INFO			    "scsi(%ld): Process error entry.\n", ha->host_no));			qla2x00_error_entry(ha, (sts_entry_t *) pkt);			((response_t *)pkt)->signature = RESPONSE_PROCESSED;			wmb();			continue;		}		switch (pkt->entry_type) {		case STATUS_TYPE:			qla2x00_status_entry(ha, pkt);			break;		case STATUS_CONT_TYPE:			qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt);			break;		case MS_IOCB_TYPE:			qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt);			break;		case VP_RPT_ID_IOCB_TYPE:			qla24xx_report_id_acquisition(ha,			    (struct vp_rpt_id_entry_24xx *)pkt);			break;		default:			/* Type Not Supported. */			DEBUG4(printk(KERN_WARNING			    "scsi(%ld): Received unknown response pkt type %x "			    "entry status=%x.\n",			    ha->host_no, pkt->entry_type, pkt->entry_status));			break;		}		((response_t *)pkt)->signature = RESPONSE_PROCESSED;		wmb();	}	/* Adjust ring index */	WRT_REG_DWORD(&reg->rsp_q_out, ha->rsp_ring_index);}static voidqla2xxx_check_risc_status(scsi_qla_host_t *ha){	int rval;	uint32_t cnt;	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;	if (!IS_QLA25XX(ha))		return;	rval = QLA_SUCCESS;	WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);	RD_REG_DWORD(&reg->iobase_addr);	WRT_REG_DWORD(&reg->iobase_window, 0x0001);	for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&	    rval == QLA_SUCCESS; cnt--) {		if (cnt) {			WRT_REG_DWORD(&reg->iobase_window, 0x0001);			udelay(10);		} else			rval = QLA_FUNCTION_TIMEOUT;	}	if (rval == QLA_SUCCESS)		goto next_test;	WRT_REG_DWORD(&reg->iobase_window, 0x0003);	for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&	    rval == QLA_SUCCESS; cnt--) {		if (cnt) {			WRT_REG_DWORD(&reg->iobase_window, 0x0003);			udelay(10);		} else			rval = QLA_FUNCTION_TIMEOUT;	}	if (rval != QLA_SUCCESS)		goto done;next_test:	if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)		qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");done:	WRT_REG_DWORD(&reg->iobase_window, 0x0000);	RD_REG_DWORD(&reg->iobase_window);}/** * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. * @irq: * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. * * Returns handled flag. */irqreturn_tqla24xx_intr_handler(int irq, void *dev_id){	scsi_qla_host_t	*ha;	struct device_reg_24xx __iomem *reg;	int		status;	unsigned long	flags;	unsigned long	iter;	uint32_t	stat;	uint32_t	hccr;	uint16_t	mb[4];	ha = (scsi_qla_host_t *) dev_id;	if (!ha) {		printk(KERN_INFO		    "%s(): NULL host pointer\n", __func__);		return IRQ_NONE;	}	reg = &ha->iobase->isp24;	status = 0;	spin_lock_irqsave(&ha->hardware_lock, flags);	for (iter = 50; iter--; ) {		stat = RD_REG_DWORD(&reg->host_status);		if (stat & HSRX_RISC_PAUSED) {			if (pci_channel_offline(ha->pdev))				break;			hccr = RD_REG_DWORD(&reg->hccr);			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "			    "Dumping firmware!\n", hccr);			qla2xxx_check_risc_status(ha);			ha->isp_ops->fw_dump(ha, 1);			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);			break;		} else if ((stat & HSRX_RISC_INT) == 0)			break;		switch (stat & 0xff) {		case 0x1:		case 0x2:		case 0x10:		case 0x11:			qla24xx_mbx_completion(ha, MSW(stat));			status |= MBX_INTERRUPT;			break;		case 0x12:			mb[0] = MSW(stat);			mb[1] = RD_REG_WORD(&reg->mailbox1);			mb[2] = RD_REG_WORD(&reg->mailbox2);			mb[3] = RD_REG_WORD(&reg->mailbox3);			qla2x00_async_event(ha, mb);			break;		case 0x13:			qla24xx_process_response_queue(ha);			break;		default:			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "			    "(%d).\n",			    ha->host_no, stat & 0xff));			break;		}		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);		RD_REG_DWORD_RELAXED(&reg->hccr);	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);		up(&ha->mbx_intr_sem);	}	return IRQ_HANDLED;}/** * qla24xx_ms_entry() - Process a Management Server entry. * @ha: SCSI driver HA context * @index: Response queue out pointer */static voidqla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt){	srb_t          *sp;	DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",	    __func__, ha->host_no, pkt, pkt->handle));	DEBUG9(printk("%s: ct pkt dump:\n", __func__));	DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx)));	/* Validate handle. */ 	if (pkt->handle < MAX_OUTSTANDING_COMMANDS) 		sp = ha->outstanding_cmds[pkt->handle];	else		sp = NULL;	if (sp == NULL) {		DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n",		    ha->host_no));		DEBUG10(printk("scsi(%ld): MS entry - invalid handle\n",		    ha->host_no));		qla_printk(KERN_WARNING, ha, "MS entry - invalid handle %d\n",		    pkt->handle);		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);		return;	}	CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->comp_status);	CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status;	/* Free outstanding command slot. */	ha->outstanding_cmds[pkt->handle] = NULL;	qla2x00_sp_compl(ha, sp);}static irqreturn_tqla24xx_msix_rsp_q(int irq, void *dev_id){	scsi_qla_host_t	*ha;	struct device_reg_24xx __iomem *reg;	unsigned long flags;	ha = dev_id;	reg = &ha->iobase->isp24;	spin_lock_irqsave(&ha->hardware_lock, flags);	qla24xx_process_response_queue(ha);	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	return IRQ_HANDLED;}static irqreturn_tqla24xx_msix_default(int irq, void *dev_id){	scsi_qla_host_t	*ha;	struct device_reg_24xx __iomem *reg;	int		status;	unsigned long	flags;	uint32_t	stat;	uint32_t	hccr;	uint16_t	mb[4];	ha = dev_id;	reg = &ha->iobase->isp24;	status = 0;	spin_lock_irqsave(&ha->hardware_lock, flags);	do {		stat = RD_REG_DWORD(&reg->host_status);		if (stat & HSRX_RISC_PAUSED) {			if (pci_channel_offline(ha->pdev))				break;			hccr = RD_REG_DWORD(&reg->hccr);			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "			    "Dumping firmware!\n", hccr);			qla2xxx_check_risc_status(ha);			ha->isp_ops->fw_dump(ha, 1);			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);			break;		} else if ((stat & HSRX_RISC_INT) == 0)			break;		switch (stat & 0xff) {		case 0x1:		case 0x2:		case 0x10:		case 0x11:			qla24xx_mbx_completion(ha, MSW(stat));			status |= MBX_INTERRUPT;			break;		case 0x12:			mb[0] = MSW(stat);			mb[1] = RD_REG_WORD(&reg->mailbox1);			mb[2] = RD_REG_WORD(&reg->mailbox2);			mb[3] = RD_REG_WORD(&reg->mailbox3);			qla2x00_async_event(ha, mb);			break;		case 0x13:			qla24xx_process_response_queue(ha);			break;		default:			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "			    "(%d).\n",			    ha->host_no, stat & 0xff));			break;		}		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);	} while (0);	spin_unlock_irqrestore(&ha->hardware_lock, flags);	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);		up(&ha->mbx_intr_sem);	}	return IRQ_HANDLED;}/* Interrupt handling helpers. */struct qla_init_msix_entry {	uint16_t entry;	uint16_t index;	const char *name;	irq_handler_t handler;};static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {	{ QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,		"qla2xxx (default)", qla24xx_msix_default },	{ QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,		"qla2xxx (rsp_q)", qla24xx_msix_rsp_q },};static voidqla24xx_disable_msix(scsi_qla_host_t *ha){	int i;	struct qla_msix_entry *qentry;	for (i = 0; i < QLA_MSIX_ENTRIES; i++) {		qentry = &ha->msix_entries[imsix_entries[i].index];		if (qentry->have_irq)			free_irq(qentry->msix_vector, ha);	}	pci_disable_msix(ha->pdev);}static intqla24xx_enable_msix(scsi_qla_host_t *ha){	int i, ret;	struct msix_entry entries[QLA_MSIX_ENTRIES];	struct qla_msix_entry *qentry;	for (i = 0; i < QLA_MSIX_ENTRIES; i++)		entries[i].entry = imsix_entries[i].entry;	ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));	if (ret) {		qla_printk(KERN_WARNING, ha,		    "MSI-X: Failed to enable support -- %d/%d\n",		    QLA_MSIX_ENTRIES, ret);		goto msix_out;	}	ha->flags.msix_enabled = 1;	for (i = 0; i < QLA_MSIX_ENTRIES; i++) {		qentry = &ha->msix_entries[imsix_entries[i].index];		qentry->msix_vector = entries[i].vector;		qentry->msix_entry = entries[i].entry;		qentry->have_irq = 0;		ret = request_irq(qentry->msix_vector,		    imsix_entries[i].handler, 0, imsix_entries[i].name, ha);		if (ret) {			qla_printk(KERN_WARNING, ha,			    "MSI-X: Unable to register handler -- %x/%d.\n",			    imsix_entries[i].index, ret);			qla24xx_disable_msix(ha);			goto msix_out;		}		qentry->have_irq = 1;	}msix_out:	return ret;}intqla2x00_request_irqs(scsi_qla_host_t *ha){	int ret;	/* If possible, enable MSI-X. */	if (!IS_QLA2432(ha) && !IS_QLA2532(ha))		goto skip_msix;        if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||	    !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {		DEBUG2(qla_printk(KERN_WARNING, ha,		    "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",		    ha->chip_revision, ha->fw_attributes));		goto skip_msix;	}	ret = qla24xx_enable_msix(ha);	if (!ret) {		DEBUG2(qla_printk(KERN_INFO, ha,		    "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,		    ha->fw_attributes));		return ret;	}	qla_printk(KERN_WARNING, ha,	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);skip_msix:	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha))		goto skip_msi;	ret = pci_enable_msi(ha->pdev);	if (!ret) {		DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));		ha->flags.msi_enabled = 1;	}skip_msi:	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,	    IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);	if (!ret) {		ha->flags.inta_enabled = 1;		ha->host->irq = ha->pdev->irq;	} else {		qla_printk(KERN_WARNING, ha,		    "Failed to reserve interrupt %d already in use.\n",		    ha->pdev->irq);	}	return ret;}voidqla2x00_free_irqs(scsi_qla_host_t *ha){	if (ha->flags.msix_enabled)		qla24xx_disable_msix(ha);	else if (ha->flags.inta_enabled) {		free_irq(ha->host->irq, ha);		pci_disable_msi(ha->pdev);	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?