Пример #1
0
/**
 * qla2x00_intr_handler() - Process interrupts for the ISP.
 * @irq:
 * @dev_id: SCSI driver HA context
 * @regs:
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
qla2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	scsi_qla_host_t	*ha;
	device_reg_t	*reg;
	uint32_t	mbx;
	int		status = 0;
	unsigned long	flags = 0;
	unsigned long	mbx_flags = 0;
	unsigned long	intr_iter;
	uint32_t	stat;
	uint16_t	hccr;

	/* Don't loop forever, interrupt are OFF */
	intr_iter = 50; 

	ha = (scsi_qla_host_t *) dev_id;
	if (!ha) {
		printk(KERN_INFO
		    "%s(): NULL host pointer\n", __func__);
		return (IRQ_NONE);
	}

	reg = ha->iobase;

	spin_lock_irqsave(&ha->hardware_lock, flags);

	for (;;) {
		/* Relax CPU! */
		if (!(intr_iter--))
			break;

		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
			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);
				/* Workaround for ISP2100 chip. */
				if (IS_QLA2100(ha))
					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);
			}
		} else /* IS_QLA23XX(ha) */ {
			stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
			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:
				hccr = RD_REG_WORD(&reg->hccr);
				if (hccr & HCCR_RISC_PAUSE) {
					qla_printk(KERN_INFO, ha,
					    "RISC paused, dumping 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 {
					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(&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) {

		/* There was a mailbox completion */
		DEBUG3(printk("%s(%ld): Going to get mbx reg lock.\n",
		    __func__, ha->host_no));

		spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);

		if (ha->mcp == NULL) {
			DEBUG3(printk("%s(%ld): Error mbx pointer.\n",
			    __func__, ha->host_no));
		} else {
			DEBUG3(printk("%s(%ld): Going to set mbx intr flags. "
			    "cmd=%x.\n",
			    __func__, ha->host_no, ha->mcp->mb[0]));
		}
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);

		DEBUG3(printk("%s(%ld): Going to wake up mbx function for "
		    "completion.\n",
		    __func__, ha->host_no));

		up(&ha->mbx_intr_sem);

		DEBUG3(printk("%s(%ld): Going to release mbx reg lock.\n",
		    __func__, ha->host_no));

		spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
	}

	if (!list_empty(&ha->done_queue))
		qla2x00_done(ha);

	/* Wakeup the DPC routine */
	if ((!ha->flags.mbox_busy &&
	    (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
		test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
		test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))) &&
		    ha->dpc_wait && !ha->dpc_active) {

		up(ha->dpc_wait);
	}

	return (IRQ_HANDLED);
}
Пример #2
0
/**
 * qla24xx_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_t
qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	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) {
			hccr = RD_REG_DWORD(&reg->hccr);

			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
			    "Dumping firmware!\n", hccr);
			qla24xx_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) {
		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);
	}

	return IRQ_HANDLED;
}
Пример #3
0
/**
 * 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_t
qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	scsi_qla_host_t	*ha;
	struct device_reg_2xxx __iomem *reg;
	int		status;
	unsigned long	flags;
	unsigned long	iter;
	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->isp;
	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. */
			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
				qla2x00_mbx_completion(ha, mb[0]);
				status |= MBX_INTERRUPT;
			} else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
				mb[1] = RD_MAILBOX_REG(ha, reg, 1);
				mb[2] = RD_MAILBOX_REG(ha, reg, 2);
				mb[3] = RD_MAILBOX_REG(ha, reg, 3);
				qla2x00_async_event(ha, mb);
			} else {
				/*EMPTY*/
				DEBUG2(printk("scsi(%ld): Unrecognized "
				    "interrupt type (%d).\n",
				    ha->host_no, mb[0]));
			}
			/* 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);

	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);
	}

	return (IRQ_HANDLED);
}
Пример #4
0
/**
 * 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_t
qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
	scsi_qla_host_t	*ha;
	struct device_reg_2xxx __iomem *reg;
	int		status;
	unsigned long	flags;
	unsigned long	iter;
	uint32_t	stat;
	uint16_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->isp;
	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;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
			qla2x00_mbx_completion(ha, MSW(stat));
			status |= MBX_INTERRUPT;

			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			break;
		case 0x12:
			mb[0] = MSW(stat);
			mb[1] = RD_MAILBOX_REG(ha, reg, 1);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
			mb[3] = RD_MAILBOX_REG(ha, reg, 3);
			qla2x00_async_event(ha, mb);
			break;
		case 0x13:
			qla2x00_process_response_queue(ha);
			break;
		case 0x15:
			mb[0] = MBA_CMPLT_1_16BIT;
			mb[1] = MSW(stat);
			qla2x00_async_event(ha, mb);
			break;
		case 0x16:
			mb[0] = MBA_SCSI_COMPLETION;
			mb[1] = MSW(stat);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
			qla2x00_async_event(ha, mb);
			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);

	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);
	}

	return (IRQ_HANDLED);
}