⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qla_isr.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *                  QLOGIC LINUX SOFTWARE * * QLogic ISP2x00 device driver for Linux 2.6.x * Copyright (C) 2003-2004 QLogic Corporation * (www.qlogic.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * */#include "qla_def.h"static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);static void qla2x00_async_event(scsi_qla_host_t *, uint32_t);static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);void qla2x00_process_response_queue(struct scsi_qla_host *);static void qla2x00_status_entry(scsi_qla_host_t *, sts_entry_t *);static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *);static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *);static int qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *);/** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. * @irq: * @dev_id: SCSI driver HA context * @regs: * * Called by system whenever the host adapter generates an interrupt. * * Returns handled flag. */irqreturn_tqla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs){	scsi_qla_host_t	*ha;	device_reg_t __iomem *reg;	int		status;	unsigned long	flags;	unsigned long	iter;	uint32_t	mbx;	ha = (scsi_qla_host_t *) dev_id;	if (!ha) {		printk(KERN_INFO		    "%s(): NULL host pointer\n", __func__);		return (IRQ_NONE);	}	reg = ha->iobase;	status = 0;	spin_lock_irqsave(&ha->hardware_lock, flags);	for (iter = 50; iter--; ) {		if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)			break;		if (RD_REG_WORD(&reg->semaphore) & BIT_0) {			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);			RD_REG_WORD(&reg->hccr);			/* Get mailbox data. */			mbx = RD_MAILBOX_REG(ha, reg, 0);			if (mbx > 0x3fff && mbx < 0x8000) {				qla2x00_mbx_completion(ha, (uint16_t)mbx);				status |= MBX_INTERRUPT;			} else if (mbx > 0x7fff && mbx < 0xc000) {				qla2x00_async_event(ha, mbx);			} else {				/*EMPTY*/				DEBUG2(printk("scsi(%ld): Unrecognized "				    "interrupt type (%d)\n",				    ha->host_no, mbx));			}			/* Release mailbox registers. */			WRT_REG_WORD(&reg->semaphore, 0);			RD_REG_WORD(&reg->semaphore);		} else {			qla2x00_process_response_queue(ha);			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);			RD_REG_WORD(&reg->hccr);		}	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);	qla2x00_next(ha);	ha->last_irq_cpu = _smp_processor_id();	ha->total_isr_cnt++;	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {		spin_lock_irqsave(&ha->mbx_reg_lock, flags);		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);		up(&ha->mbx_intr_sem);		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);	}	if (!list_empty(&ha->done_queue))		qla2x00_done(ha);	return (IRQ_HANDLED);}/** * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. * @irq: * @dev_id: SCSI driver HA context * @regs: * * Called by system whenever the host adapter generates an interrupt. * * Returns handled flag. */irqreturn_tqla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs){	scsi_qla_host_t	*ha;	device_reg_t __iomem *reg;	int		status;	unsigned long	flags;	unsigned long	iter;	uint32_t	stat;	uint32_t	mbx;	uint16_t	hccr;	ha = (scsi_qla_host_t *) dev_id;	if (!ha) {		printk(KERN_INFO		    "%s(): NULL host pointer\n", __func__);		return (IRQ_NONE);	}	reg = ha->iobase;	status = 0;	spin_lock_irqsave(&ha->hardware_lock, flags);	for (iter = 50; iter--; ) {		stat = RD_REG_DWORD(&reg->u.isp2300.host_status);		if (stat & HSR_RISC_PAUSED) {			hccr = RD_REG_WORD(&reg->hccr);			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))				qla_printk(KERN_INFO, ha,				    "Parity error -- HCCR=%x.\n", hccr);			else				qla_printk(KERN_INFO, ha,				    "RISC paused -- HCCR=%x\n", hccr);			/*			 * Issue a "HARD" reset in order for the RISC			 * interrupt bit to be cleared.  Schedule a big			 * hammmer to get out of the RISC PAUSED state.			 */			WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);			RD_REG_WORD(&reg->hccr);			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);			break;		} else if ((stat & HSR_RISC_INT) == 0)			break;		mbx = MSW(stat);		switch (stat & 0xff) {		case 0x13:			qla2x00_process_response_queue(ha);			break;		case 0x1:		case 0x2:		case 0x10:		case 0x11:			qla2x00_mbx_completion(ha, (uint16_t)mbx);			status |= MBX_INTERRUPT;			/* Release mailbox registers. */			WRT_REG_WORD(&reg->semaphore, 0);			break;		case 0x12:			qla2x00_async_event(ha, mbx);			break;		case 0x15:			mbx = mbx << 16 | MBA_CMPLT_1_16BIT;			qla2x00_async_event(ha, mbx);			break;		case 0x16:			mbx = mbx << 16 | MBA_SCSI_COMPLETION;			qla2x00_async_event(ha, mbx);			break;		default:			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "			    "(%d)\n",			    ha->host_no, stat & 0xff));			break;		}		WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);		RD_REG_WORD_RELAXED(&reg->hccr);	}	spin_unlock_irqrestore(&ha->hardware_lock, flags);	qla2x00_next(ha);	ha->last_irq_cpu = _smp_processor_id();	ha->total_isr_cnt++;	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {		spin_lock_irqsave(&ha->mbx_reg_lock, flags);		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);		up(&ha->mbx_intr_sem);		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);	}	if (!list_empty(&ha->done_queue))		qla2x00_done(ha);	return (IRQ_HANDLED);}/** * qla2x00_mbx_completion() - Process mailbox command completions. * @ha: SCSI driver HA context * @mb0: Mailbox0 register */static voidqla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0){	uint16_t	cnt;	uint16_t __iomem *wptr;	device_reg_t __iomem *reg = ha->iobase;	/* Load return mailbox registers. */	ha->flags.mbox_int = 1;	ha->mailbox_out[0] = mb0;	wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);	for (cnt = 1; cnt < ha->mbx_count; cnt++) {		if (IS_QLA2200(ha) && cnt == 8) 			wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);		if (cnt == 4 || cnt == 5)			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);		else			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);			wptr++;	}	if (ha->mcp) {		DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",		    __func__, ha->host_no, ha->mcp->mb[0]));	} else {		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",		    __func__, ha->host_no));	}}/** * qla2x00_async_event() - Process aynchronous events. * @ha: SCSI driver HA context * @mb0: Mailbox0 register */static voidqla2x00_async_event(scsi_qla_host_t *ha, uint32_t mbx){	static char	*link_speeds[5] = { "1", "2", "4", "?", "10" };	char		*link_speed;	uint16_t	mb[4];	uint16_t	handle_cnt;	uint16_t	cnt;	uint32_t	handles[5];	device_reg_t __iomem *reg = ha->iobase;	uint32_t	rscn_entry, host_pid;	uint8_t		rscn_queue_index;	/* Setup to process RIO completion. */	handle_cnt = 0;	mb[0] = LSW(mbx);	switch (mb[0]) {	case MBA_SCSI_COMPLETION:		if (IS_QLA2100(ha) || IS_QLA2200(ha))			handles[0] = le32_to_cpu(			    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16)) |			    RD_MAILBOX_REG(ha, reg, 1));		else			handles[0] = le32_to_cpu(			    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16)) |			    MSW(mbx));		handle_cnt = 1;		break;	case MBA_CMPLT_1_16BIT:		if (IS_QLA2100(ha) || IS_QLA2200(ha))			handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);		else			handles[0] = MSW(mbx);		handle_cnt = 1;		mb[0] = MBA_SCSI_COMPLETION;		break;	case MBA_CMPLT_2_16BIT:		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);		handle_cnt = 2;		mb[0] = MBA_SCSI_COMPLETION;		break;	case MBA_CMPLT_3_16BIT:		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);		handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3);		handle_cnt = 3;		mb[0] = MBA_SCSI_COMPLETION;		break;	case MBA_CMPLT_4_16BIT:		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);		handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3);		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);		handle_cnt = 4;		mb[0] = MBA_SCSI_COMPLETION;		break;	case MBA_CMPLT_5_16BIT:		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);		handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3);		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);		handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);		handle_cnt = 5;		mb[0] = MBA_SCSI_COMPLETION;		break;	case MBA_CMPLT_2_32BIT:		handles[0] = le32_to_cpu(		    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16)) |		    RD_MAILBOX_REG(ha, reg, 1));		handles[1] = le32_to_cpu(		    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |		    RD_MAILBOX_REG(ha, reg, 6));		handle_cnt = 2;		mb[0] = MBA_SCSI_COMPLETION;		break;	default:		break;	}	switch (mb[0]) {	case MBA_SCSI_COMPLETION:	/* Fast Post */		if (!ha->flags.online)			break;		for (cnt = 0; cnt < handle_cnt; cnt++)			qla2x00_process_completed_request(ha, handles[cnt]);		break;	case MBA_RESET:			/* Reset */		DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n", ha->host_no));		set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);		break;	case MBA_SYSTEM_ERR:		/* System Error */		mb[1] = RD_MAILBOX_REG(ha, reg, 1);		mb[2] = RD_MAILBOX_REG(ha, reg, 2);		mb[3] = RD_MAILBOX_REG(ha, reg, 3);		qla_printk(KERN_INFO, ha,		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",		    mb[1], mb[2], mb[3]);		if (IS_QLA2100(ha) || IS_QLA2200(ha))			qla2100_fw_dump(ha, 1);		else	    		qla2300_fw_dump(ha, 1);		if (mb[1] == 0) {			qla_printk(KERN_INFO, ha,			    "Unrecoverable Hardware Error: adapter marked "			    "OFFLINE!\n");			ha->flags.online = 0;		} else			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);		break;	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */		DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n",		    ha->host_no));		qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);		break;	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */		DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",		    ha->host_no));		qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);		break;	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */		DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",		    ha->host_no));		break;	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */		mb[1] = RD_MAILBOX_REG(ha, reg, 1);		DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no,		    mb[1]));		qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]);		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {			atomic_set(&ha->loop_state, LOOP_DOWN);			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);			qla2x00_mark_all_devices_lost(ha);		}		set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);		ha->flags.management_server_logged_in = 0;		/* Update AEN queue. */		qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL);		ha->total_lip_cnt++;		break;	case MBA_LOOP_UP:		/* Loop Up Event */		mb[1] = RD_MAILBOX_REG(ha, reg, 1);		ha->link_data_rate = 0;		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {			link_speed = link_speeds[0];		} else {			link_speed = link_speeds[3];			if (mb[1] < 5)				link_speed = link_speeds[mb[1]];			ha->link_data_rate = mb[1];		}		DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",		    ha->host_no, link_speed));		qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",		    link_speed);		ha->flags.management_server_logged_in = 0;		/* Update AEN queue. */		qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL);		break;	case MBA_LOOP_DOWN:		/* Loop Down Event */		DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN.\n",		    ha->host_no));		qla_printk(KERN_INFO, ha, "LOOP DOWN detected.\n");		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {			atomic_set(&ha->loop_state, LOOP_DOWN);			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);			ha->device_flags |= DFLG_NO_CABLE;			qla2x00_mark_all_devices_lost(ha);		}		ha->flags.management_server_logged_in = 0;		ha->link_data_rate = 0;		/* Update AEN queue. */		qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL);		break;	case MBA_LIP_RESET:		/* LIP reset occurred */		mb[1] = RD_MAILBOX_REG(ha, reg, 1);		DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",		    ha->host_no, mb[1]));		qla_printk(KERN_INFO, ha,		    "LIP reset occured (%x).\n", mb[1]);		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {			atomic_set(&ha->loop_state, LOOP_DOWN);			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);			qla2x00_mark_all_devices_lost(ha);		}

⌨️ 快捷键说明

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