/** * 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; 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(®->istatus) & ISR_RISC_INT) == 0) break; if (RD_REG_WORD(®->semaphore) & BIT_0) { WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->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(®->semaphore, 0); RD_REG_WORD(®->semaphore); } else { qla2x00_process_response_queue(ha); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->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_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(®->istatus) & ISR_RISC_INT) == 0) break; if (RD_REG_WORD(®->semaphore) & BIT_0) { WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->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(®->semaphore, 0); /* Workaround for ISP2100 chip. */ if (IS_QLA2100(ha)) RD_REG_WORD(®->semaphore); } else { qla2x00_process_response_queue(ha); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); } } else /* IS_QLA23XX(ha) */ { stat = RD_REG_DWORD(®->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(®->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(®->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(®->hccr, HCCR_RESET_RISC); RD_REG_WORD(®->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(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->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); }
/** * 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; 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(®->u.isp2300.host_status); if (stat & HSR_RISC_PAUSED) { hccr = RD_REG_WORD(®->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(®->hccr, HCCR_RESET_RISC); RD_REG_WORD(®->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(®->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(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD_RELAXED(®->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); }