Loading drivers/scsi/qla2xxx/qla_def.h +24 −0 Original line number Diff line number Diff line Loading @@ -2046,6 +2046,27 @@ struct isp_operations { uint32_t); }; /* MSI-X Support *************************************************************/ #define QLA_MSIX_CHIP_REV_24XX 3 #define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7) #define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1) #define QLA_MSIX_DEFAULT 0x00 #define QLA_MSIX_RSP_Q 0x01 #define QLA_MSIX_ENTRIES 2 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 struct scsi_qla_host; struct qla_msix_entry { int have_irq; uint16_t msix_vector; uint16_t msix_entry; }; /* * Linux Host Adapter structure */ Loading Loading @@ -2356,6 +2377,7 @@ typedef struct scsi_qla_host { uint8_t host_str[16]; uint32_t pci_attr; uint16_t chip_revision; uint16_t product_id[4]; Loading Loading @@ -2389,6 +2411,8 @@ typedef struct scsi_qla_host { uint16_t zio_mode; uint16_t zio_timer; struct fc_host_statistics fc_host_stat; struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES]; } scsi_qla_host_t; Loading drivers/scsi/qla2xxx/qla_gbl.h +3 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,9 @@ extern irqreturn_t qla24xx_intr_handler(int, void *); extern void qla2x00_process_response_queue(struct scsi_qla_host *); extern void qla24xx_process_response_queue(struct scsi_qla_host *); extern int qla2x00_request_irqs(scsi_qla_host_t *); extern void qla2x00_free_irqs(scsi_qla_host_t *); /* * Global Function Prototypes in qla_sup.c source file. */ Loading drivers/scsi/qla2xxx/qla_init.c +2 −0 Original line number Diff line number Diff line Loading @@ -293,6 +293,8 @@ qla24xx_pci_config(scsi_qla_host_t *ha) d &= ~PCI_ROM_ADDRESS_ENABLE; pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->pci_attr = RD_REG_DWORD(®->ctrl_status); Loading drivers/scsi/qla2xxx/qla_isr.c +215 −0 Original line number Diff line number Diff line Loading @@ -1529,3 +1529,218 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) qla2x00_sp_compl(ha, sp); } static irqreturn_t qla24xx_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(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); spin_unlock_irqrestore(&ha->hardware_lock, flags); return IRQ_HANDLED; } static irqreturn_t qla24xx_msix_default(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 = dev_id; reg = &ha->iobase->isp24; status = 0; spin_lock_irqsave(&ha->hardware_lock, flags); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " "Dumping firmware!\n", hccr); 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(®->mailbox1); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->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(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->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; } /* Interrupt handling helpers. */ struct qla_init_msix_entry { uint16_t entry; uint16_t index; const char *name; irqreturn_t (*handler)(int, void *); }; 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 void qla24xx_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 int qla24xx_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; } int qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha)) goto skip_msix; if (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: ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", ha->pdev->irq); } ha->host->irq = ha->pdev->irq; return ret; } void qla2x00_free_irqs(scsi_qla_host_t *ha) { if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); else if (ha->host->irq) free_irq(ha->host->irq, ha); } drivers/scsi/qla2xxx/qla_os.c +3 −11 Original line number Diff line number Diff line Loading @@ -1612,15 +1612,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; ret = request_irq(pdev->irq, ha->isp_ops.intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", pdev->irq); ret = qla2x00_request_irqs(ha); if (ret) goto probe_failed; } host->irq = pdev->irq; /* Initialized the timer */ qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); Loading Loading @@ -1750,9 +1744,7 @@ qla2x00_free_device(scsi_qla_host_t *ha) qla2x00_mem_free(ha); /* Detach interrupts */ if (ha->host->irq) free_irq(ha->host->irq, ha); qla2x00_free_irqs(ha); /* release io space registers */ if (ha->iobase) Loading Loading
drivers/scsi/qla2xxx/qla_def.h +24 −0 Original line number Diff line number Diff line Loading @@ -2046,6 +2046,27 @@ struct isp_operations { uint32_t); }; /* MSI-X Support *************************************************************/ #define QLA_MSIX_CHIP_REV_24XX 3 #define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7) #define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1) #define QLA_MSIX_DEFAULT 0x00 #define QLA_MSIX_RSP_Q 0x01 #define QLA_MSIX_ENTRIES 2 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 struct scsi_qla_host; struct qla_msix_entry { int have_irq; uint16_t msix_vector; uint16_t msix_entry; }; /* * Linux Host Adapter structure */ Loading Loading @@ -2356,6 +2377,7 @@ typedef struct scsi_qla_host { uint8_t host_str[16]; uint32_t pci_attr; uint16_t chip_revision; uint16_t product_id[4]; Loading Loading @@ -2389,6 +2411,8 @@ typedef struct scsi_qla_host { uint16_t zio_mode; uint16_t zio_timer; struct fc_host_statistics fc_host_stat; struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES]; } scsi_qla_host_t; Loading
drivers/scsi/qla2xxx/qla_gbl.h +3 −0 Original line number Diff line number Diff line Loading @@ -225,6 +225,9 @@ extern irqreturn_t qla24xx_intr_handler(int, void *); extern void qla2x00_process_response_queue(struct scsi_qla_host *); extern void qla24xx_process_response_queue(struct scsi_qla_host *); extern int qla2x00_request_irqs(scsi_qla_host_t *); extern void qla2x00_free_irqs(scsi_qla_host_t *); /* * Global Function Prototypes in qla_sup.c source file. */ Loading
drivers/scsi/qla2xxx/qla_init.c +2 −0 Original line number Diff line number Diff line Loading @@ -293,6 +293,8 @@ qla24xx_pci_config(scsi_qla_host_t *ha) d &= ~PCI_ROM_ADDRESS_ENABLE; pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->pci_attr = RD_REG_DWORD(®->ctrl_status); Loading
drivers/scsi/qla2xxx/qla_isr.c +215 −0 Original line number Diff line number Diff line Loading @@ -1529,3 +1529,218 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) qla2x00_sp_compl(ha, sp); } static irqreturn_t qla24xx_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(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); spin_unlock_irqrestore(&ha->hardware_lock, flags); return IRQ_HANDLED; } static irqreturn_t qla24xx_msix_default(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 = dev_id; reg = &ha->iobase->isp24; status = 0; spin_lock_irqsave(&ha->hardware_lock, flags); for (iter = 50; iter--; ) { stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_PAUSED) { hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " "Dumping firmware!\n", hccr); 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(®->mailbox1); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->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(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->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; } /* Interrupt handling helpers. */ struct qla_init_msix_entry { uint16_t entry; uint16_t index; const char *name; irqreturn_t (*handler)(int, void *); }; 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 void qla24xx_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 int qla24xx_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; } int qla2x00_request_irqs(scsi_qla_host_t *ha) { int ret; /* If possible, enable MSI-X. */ if (!IS_QLA2432(ha)) goto skip_msix; if (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: ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", ha->pdev->irq); } ha->host->irq = ha->pdev->irq; return ret; } void qla2x00_free_irqs(scsi_qla_host_t *ha) { if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); else if (ha->host->irq) free_irq(ha->host->irq, ha); }
drivers/scsi/qla2xxx/qla_os.c +3 −11 Original line number Diff line number Diff line Loading @@ -1612,15 +1612,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; ret = request_irq(pdev->irq, ha->isp_ops.intr_handler, IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", pdev->irq); ret = qla2x00_request_irqs(ha); if (ret) goto probe_failed; } host->irq = pdev->irq; /* Initialized the timer */ qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); Loading Loading @@ -1750,9 +1744,7 @@ qla2x00_free_device(scsi_qla_host_t *ha) qla2x00_mem_free(ha); /* Detach interrupts */ if (ha->host->irq) free_irq(ha->host->irq, ha); qla2x00_free_irqs(ha); /* release io space registers */ if (ha->iobase) Loading