/** * qla2x00_write_flash_byte() - Write a byte to flash * @ha: HA context * @addr: Address in flash to write * @data: Data to write */ static void qla2x00_write_flash_byte(scsi_qla_host_t *ha, uint32_t addr, uint8_t data) { uint16_t bank_select; device_reg_t *reg = ha->iobase; /* Setup bit 16 of flash address. */ bank_select = RD_REG_WORD(®->ctrl_status); if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) { bank_select |= CSR_FLASH_64K_BANK; WRT_REG_WORD(®->ctrl_status, bank_select); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ } else if (((addr & BIT_16) == 0) && (bank_select & CSR_FLASH_64K_BANK)) { bank_select &= ~(CSR_FLASH_64K_BANK); WRT_REG_WORD(®->ctrl_status, bank_select); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ } /* The ISP2312 v2 chip cannot access the FLASH registers via MMIO. */ if (IS_QLA2312(ha) && ha->product_id[3] == 0x2 && ha->pio_address) { reg = (device_reg_t *)ha->pio_address; outw((uint16_t)addr, (unsigned long)(®->flash_address)); outw((uint16_t)data, (unsigned long)(®->flash_data)); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ WRT_REG_WORD(®->flash_data, (uint16_t)data); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ } }
/** * qla2x00_lock_nvram_access() - * @ha: HA context */ void qla2x00_lock_nvram_access(scsi_qla_host_t *ha) { uint16_t data; device_reg_t *reg; reg = ha->iobase; if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) { data = RD_REG_WORD(®->nvram); while (data & NVR_BUSY) { udelay(100); data = RD_REG_WORD(®->nvram); } /* Lock resource */ WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); udelay(5); data = RD_REG_WORD(®->u.isp2300.host_semaphore); while ((data & BIT_0) == 0) { /* Lock failed */ udelay(100); WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); udelay(5); data = RD_REG_WORD(®->u.isp2300.host_semaphore); } } }
/** * qla2x00_flash_disable() - Disable flash and allow RISC to run. * @ha: HA context */ void qla2x00_flash_disable(scsi_qla_host_t *ha) { uint16_t data; device_reg_t *reg = ha->iobase; data = RD_REG_WORD(®->ctrl_status); data &= ~(CSR_FLASH_ENABLE); WRT_REG_WORD(®->ctrl_status, data); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ }
static int qla24xx_soft_reset(scsi_qla_host_t *ha) { int rval = QLA_SUCCESS; uint32_t cnt; uint16_t mb0, wd; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; /* Reset RISC. */ WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) break; udelay(10); } WRT_REG_DWORD(®->ctrl_status, CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); udelay(100); /* Wait for firmware to complete NVRAM accesses. */ mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); for (cnt = 10000 ; cnt && mb0; cnt--) { udelay(5); mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } /* Wait for soft-reset to complete. */ for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_DWORD(®->ctrl_status) & CSRX_ISP_SOFT_RESET) == 0) break; udelay(10); } WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); RD_REG_DWORD(®->hccr); /* PCI Posting. */ for (cnt = 30000; RD_REG_WORD(®->mailbox0) != 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } return rval; }
/** * qla2x00_nv_write() - Prepare for NVRAM read/write operation. * @ha: HA context * @data: Serial interface selector */ void qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data) { device_reg_t *reg = ha->iobase; WRT_REG_WORD(®->nvram, data | NVR_SELECT); NVRAM_DELAY(); RD_REG_WORD(®->nvram); /* PCI Posting. */ WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_CLOCK); NVRAM_DELAY(); RD_REG_WORD(®->nvram); /* PCI Posting. */ WRT_REG_WORD(®->nvram, data | NVR_SELECT); NVRAM_DELAY(); RD_REG_WORD(®->nvram); /* PCI Posting. */ }
/** * qla2x00_mbx_completion() - Process mailbox command completions. * @ha: SCSI driver HA context * @mb0: Mailbox0 register */ static void qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0) { uint16_t cnt; uint16_t *wptr; device_reg_t *reg = ha->iobase; /* Load return mailbox registers. */ ha->flags.mbox_int = TRUE; ha->mailbox_out[0] = mb0; wptr = (uint16_t *)MAILBOX_REG(ha, reg, 1); for (cnt = 1; cnt < ha->mbx_count; cnt++) { if (IS_QLA2200(ha) && cnt == 8) wptr = (uint16_t *)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)); } }
/** * qla24xx_mbx_completion() - Process mailbox command completions. * @ha: SCSI driver HA context * @mb0: Mailbox0 register */ static void qla24xx_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0) { uint16_t cnt; uint16_t __iomem *wptr; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; /* Load return mailbox registers. */ ha->flags.mbox_int = 1; ha->mailbox_out[0] = mb0; wptr = (uint16_t __iomem *)®->mailbox1; for (cnt = 1; cnt < ha->mbx_count; cnt++) { 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)); } }
/** * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC. * @ha: HA context * * Returns 0 on success. */ static inline void qla24xx_reset_risc(scsi_qla_host_t *vha) { unsigned long flags = 0; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t cnt, d2; uint16_t wd; static int abts_cnt; /* ISP abort retry counts */ spin_lock_irqsave(&ha->hardware_lock, flags); /* Reset RISC. */ WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) break; udelay(10); } WRT_REG_DWORD(®->ctrl_status, CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); udelay(100); /* Wait for firmware to complete NVRAM accesses. */ d2 = (uint32_t) RD_REG_WORD(®->mailbox0); for (cnt = 10000 ; cnt && d2; cnt--) { udelay(5); d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } /* Wait for soft-reset to complete. */ d2 = RD_REG_DWORD(®->ctrl_status); for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) { udelay(5); d2 = RD_REG_DWORD(®->ctrl_status); barrier(); } /* If required, do an MPI FW reset now */ if (test_and_clear_bit(MPI_RESET_NEEDED, &vha->dpc_flags)) { if (qla81xx_reset_mpi(vha) != QLA_SUCCESS) { if
/** * qla2x00_nv_write() - Clean NVRAM operations. * @ha: HA context */ void qla2x00_nv_deselect(scsi_qla_host_t *ha) { device_reg_t *reg = ha->iobase; WRT_REG_WORD(®->nvram, NVR_DESELECT); NVRAM_DELAY(); RD_REG_WORD(®->nvram); /* PCI Posting. */ }
static inline void qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count, uint16_t *buf) { uint16_t __iomem *dmp_reg = ®->u.isp2300.fb_cmd; while (count--) *buf++ = htons(RD_REG_WORD(dmp_reg++)); }
static inline void qla27xx_read16(void __iomem *window, void *buf, ulong *len) { uint16_t value = ~0; if (buf) { value = RD_REG_WORD(window); } qla27xx_insert32(value, buf, len); }
/** * qla2x00_read_flash_byte() - Reads a byte from flash * @ha: HA context * @addr: Address in flash to read * * A word is read from the chip, but, only the lower byte is valid. * * Returns the byte read from flash @addr. */ uint8_t qla2x00_read_flash_byte(scsi_qla_host_t *ha, uint32_t addr) { uint16_t data; uint16_t bank_select; device_reg_t *reg = ha->iobase; /* Setup bit 16 of flash address. */ bank_select = RD_REG_WORD(®->ctrl_status); if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) { bank_select |= CSR_FLASH_64K_BANK; WRT_REG_WORD(®->ctrl_status, bank_select); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ } else if (((addr & BIT_16) == 0) && (bank_select & CSR_FLASH_64K_BANK)) { bank_select &= ~(CSR_FLASH_64K_BANK); WRT_REG_WORD(®->ctrl_status, bank_select); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ } /* The ISP2312 v2 chip cannot access the FLASH registers via MMIO. */ if (IS_QLA2312(ha) && ha->product_id[3] == 0x2 && ha->pio_address) { uint16_t data2; reg = (device_reg_t *)ha->pio_address; outw((uint16_t)addr, (unsigned long)(®->flash_address)); do { data = inw((unsigned long)(®->flash_data)); barrier(); cpu_relax(); data2 = inw((unsigned long)(®->flash_data)); } while (data != data2); } else { WRT_REG_WORD(®->flash_address, (uint16_t)addr); data = qla2x00_debounce_register(®->flash_data); } return ((uint8_t)data); }
/** * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from * NVRAM. * @ha: HA context * @nv_cmd: NVRAM command * * Bit definitions for NVRAM command: * * Bit 26 = start bit * Bit 25, 24 = opcode * Bit 23-16 = address * Bit 15-0 = write data * * Returns the word read from nvram @addr. */ static uint16_t qla2x00_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd) { uint8_t cnt; device_reg_t *reg = ha->iobase; uint16_t data = 0; uint16_t reg_data; /* Send command to NVRAM. */ nv_cmd <<= 5; for (cnt = 0; cnt < 11; cnt++) { if (nv_cmd & BIT_31) qla2x00_nv_write(ha, NVR_DATA_OUT); else qla2x00_nv_write(ha, 0); nv_cmd <<= 1; } /* Read data from NVRAM. */ for (cnt = 0; cnt < 16; cnt++) { WRT_REG_WORD(®->nvram, NVR_SELECT | NVR_CLOCK); NVRAM_DELAY(); data <<= 1; reg_data = RD_REG_WORD(®->nvram); if (reg_data & NVR_DATA_IN) data |= BIT_0; WRT_REG_WORD(®->nvram, NVR_SELECT); NVRAM_DELAY(); RD_REG_WORD(®->nvram); /* PCI Posting. */ } /* Deselect chip. */ WRT_REG_WORD(®->nvram, NVR_DESELECT); NVRAM_DELAY(); RD_REG_WORD(®->nvram); /* PCI Posting. */ return (data); }
void qla2x00_dump_regs(scsi_qla_host_t *ha) { int i; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; uint16_t __iomem *mbx_reg; mbx_reg = IS_FWI2_CAPABLE(ha) ? ®24->mailbox0: MAILBOX_REG(ha, reg, 0); printk("Mailbox registers:\n"); for (i = 0; i < 6; i++) printk("scsi(%ld): mbox %d 0x%04x \n", ha->host_no, i, RD_REG_WORD(mbx_reg++)); }
/** * qla2x00_get_flash_image() - Read image from flash chip. * @ha: HA context * @image: Buffer to receive flash image * * Returns 0 on success, else non-zero. */ uint16_t qla2x00_get_flash_image(scsi_qla_host_t *ha, uint8_t *image) { uint32_t addr; uint32_t midpoint; uint8_t *data; device_reg_t *reg = ha->iobase; midpoint = FLASH_IMAGE_SIZE / 2; qla2x00_flash_enable(ha); WRT_REG_WORD(®->nvram, 0); RD_REG_WORD(®->nvram); /* PCI Posting. */ for (addr = 0, data = image; addr < FLASH_IMAGE_SIZE; addr++, data++) { if (addr == midpoint) WRT_REG_WORD(®->nvram, NVR_SELECT); *data = qla2x00_read_flash_byte(ha, addr); } qla2x00_flash_disable(ha); return (0); }
/** * qla2100_pci_config() - Setup ISP21xx PCI configuration registers. * @ha: HA context * * Returns 0 on success. */ int qla2100_pci_config(scsi_qla_host_t *vha) { uint16_t w; unsigned long flags; struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; pci_set_master(ha->pdev); pci_try_set_mwi(ha->pdev); pci_read_config_word(ha->pdev, PCI_COMMAND, &w); w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); pci_write_config_word(ha->pdev, PCI_COMMAND, w); pci_disable_rom(ha->pdev); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->pci_attr = RD_REG_WORD(®->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; }
/** * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. * @ha: HA context * @hardware_locked: Called with the hardware_lock */ void qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { int rval; uint32_t cnt, timer; uint16_t risc_address; uint16_t mb0, mb2; device_reg_t __iomem *reg = ha->iobase; uint16_t __iomem *dmp_reg; unsigned long flags; struct qla2100_fw_dump *fw; risc_address = 0; mb0 = mb2 = 0; flags = 0; if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); if (ha->fw_dump != NULL) { qla_printk(KERN_WARNING, ha, "Firmware has been previously dumped (%p) -- ignoring " "request...\n", ha->fw_dump); goto qla2100_fw_dump_failed; } /* Allocate (large) dump buffer. */ ha->fw_dump_order = get_order(sizeof(struct qla2100_fw_dump)); ha->fw_dump = (struct qla2100_fw_dump *) __get_free_pages(GFP_ATOMIC, ha->fw_dump_order); if (ha->fw_dump == NULL) { qla_printk(KERN_WARNING, ha, "Unable to allocated memory for firmware dump (%d/%Zd).\n", ha->fw_dump_order, sizeof(struct qla2100_fw_dump)); goto qla2100_fw_dump_failed; } fw = ha->fw_dump; rval = QLA_SUCCESS; fw->hccr = RD_REG_WORD(®->hccr); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < ha->mbx_count; cnt++) { if (cnt == 8) { dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0); } fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); } dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2100); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2300); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2500); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2700); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); /* Reset the ISP. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); } for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } /* Pause RISC. */ if (rval == QLA_SUCCESS && (IS_QLA2200(ha) || (IS_QLA2100(ha) && (RD_REG_WORD(®->mctr) & (BIT_1 | BIT_0)) != 0))) { WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } if (rval == QLA_SUCCESS) { /* Set memory configuration and timing. */ if (IS_QLA2100(ha)) WRT_REG_WORD(®->mctr, 0xf1); else WRT_REG_WORD(®->mctr, 0xf2); RD_REG_WORD(®->mctr); /* PCI Posting. */ /* Release RISC. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); } } if (rval == QLA_SUCCESS) { /* Get RISC SRAM. */ risc_address = 0x1000; WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); } for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_MAILBOX_REG(ha, reg, 1, risc_address); WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); for (timer = 6000000; timer != 0; timer--) { /* Check for pending interrupts. */ if (RD_REG_WORD(®->istatus) & ISR_RISC_INT) { if (RD_REG_WORD(®->semaphore) & BIT_0) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); WRT_REG_WORD(®->semaphore, 0); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; fw->risc_ram[cnt] = mb2; } else { rval = QLA_FUNCTION_FAILED; } } if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); ha->fw_dump = NULL; } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", ha->host_no, ha->fw_dump); } qla2100_fw_dump_failed: if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); }
/** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. * @ha: HA context * @hardware_locked: Called with the hardware_lock */ void qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { int rval; uint32_t cnt, timer; uint32_t risc_address; uint16_t mb0, mb2; uint32_t stat; device_reg_t __iomem *reg = ha->iobase; uint16_t __iomem *dmp_reg; unsigned long flags; struct qla2300_fw_dump *fw; uint32_t dump_size, data_ram_cnt; risc_address = data_ram_cnt = 0; mb0 = mb2 = 0; flags = 0; if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); if (ha->fw_dump != NULL) { qla_printk(KERN_WARNING, ha, "Firmware has been previously dumped (%p) -- ignoring " "request...\n", ha->fw_dump); goto qla2300_fw_dump_failed; } /* Allocate (large) dump buffer. */ dump_size = sizeof(struct qla2300_fw_dump); dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t); ha->fw_dump_order = get_order(dump_size); ha->fw_dump = (struct qla2300_fw_dump *) __get_free_pages(GFP_ATOMIC, ha->fw_dump_order); if (ha->fw_dump == NULL) { qla_printk(KERN_WARNING, ha, "Unable to allocated memory for firmware dump (%d/%d).\n", ha->fw_dump_order, dump_size); goto qla2300_fw_dump_failed; } fw = ha->fw_dump; rval = QLA_SUCCESS; fw->hccr = RD_REG_WORD(®->hccr); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); if (IS_QLA2300(ha)) { for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } } else { RD_REG_WORD(®->hccr); /* PCI Posting. */ udelay(10); } if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x40); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x50); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2800); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2A00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2C00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->pcr, 0x2E00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); /* Reset RISC. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(®->ctrl_status) & CSR_ISP_SOFT_RESET) == 0) break; udelay(10); } } if (!IS_QLA2300(ha)) { for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } } if (rval == QLA_SUCCESS) { /* Get RISC SRAM. */ risc_address = 0x800; WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); } for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_MAILBOX_REG(ha, reg, 1, (uint16_t)risc_address); WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); for (timer = 6000000; timer; timer--) { /* Check for pending interrupts. */ stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_INT) { stat &= 0xff; if (stat == 0x1 || stat == 0x2) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); /* Release mailbox registers. */ WRT_REG_WORD(®->semaphore, 0); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } else if (stat == 0x10 || stat == 0x11) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } /* clear this intr; it wasn't a mailbox intr */ WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; fw->risc_ram[cnt] = mb2; } else { rval = QLA_FUNCTION_FAILED; } } if (rval == QLA_SUCCESS) { /* Get stack SRAM. */ risc_address = 0x10000; WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); } for (cnt = 0; cnt < sizeof(fw->stack_ram) / 2 && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address)); WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address)); WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); for (timer = 6000000; timer; timer--) { /* Check for pending interrupts. */ stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_INT) { stat &= 0xff; if (stat == 0x1 || stat == 0x2) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); /* Release mailbox registers. */ WRT_REG_WORD(®->semaphore, 0); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } else if (stat == 0x10 || stat == 0x11) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } /* clear this intr; it wasn't a mailbox intr */ WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; fw->stack_ram[cnt] = mb2; } else { rval = QLA_FUNCTION_FAILED; } } if (rval == QLA_SUCCESS) { /* Get data SRAM. */ risc_address = 0x11000; data_ram_cnt = ha->fw_memory_size - risc_address + 1; WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); } for (cnt = 0; cnt < data_ram_cnt && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address)); WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address)); WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); for (timer = 6000000; timer; timer--) { /* Check for pending interrupts. */ stat = RD_REG_DWORD(®->u.isp2300.host_status); if (stat & HSR_RISC_INT) { stat &= 0xff; if (stat == 0x1 || stat == 0x2) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); /* Release mailbox registers. */ WRT_REG_WORD(®->semaphore, 0); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } else if (stat == 0x10 || stat == 0x11) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } /* clear this intr; it wasn't a mailbox intr */ WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; fw->data_ram[cnt] = mb2; } else { rval = QLA_FUNCTION_FAILED; } } if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); ha->fw_dump = NULL; } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", ha->host_no, ha->fw_dump); } qla2300_fw_dump_failed: if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); }
static int qla24xx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram, uint32_t cram_size, uint32_t *ext_mem, void **nxt) { int rval; uint32_t cnt, stat, timer, risc_address, ext_mem_cnt; uint16_t mb[4]; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; rval = QLA_SUCCESS; risc_address = ext_mem_cnt = 0; memset(mb, 0, sizeof(mb)); /* Code RAM. */ risc_address = 0x20000; WRT_REG_WORD(®->mailbox0, MBC_READ_RAM_EXTENDED); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); for (cnt = 0; cnt < cram_size / 4 && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_REG_WORD(®->mailbox1, LSW(risc_address)); WRT_REG_WORD(®->mailbox8, MSW(risc_address)); RD_REG_WORD(®->mailbox8); WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); for (timer = 6000000; timer; timer--) { /* Check for pending interrupts. */ stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_INT) { stat &= 0xff; if (stat == 0x1 || stat == 0x2 || stat == 0x10 || stat == 0x11) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb[0] = RD_REG_WORD(®->mailbox0); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->mailbox3); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD(®->hccr); break; } /* Clear this intr; it wasn't a mailbox intr */ WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; code_ram[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } } if (rval == QLA_SUCCESS) { /* External Memory. */ risc_address = 0x100000; ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1; WRT_REG_WORD(®->mailbox0, MBC_READ_RAM_EXTENDED); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); } for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_REG_WORD(®->mailbox1, LSW(risc_address)); WRT_REG_WORD(®->mailbox8, MSW(risc_address)); RD_REG_WORD(®->mailbox8); WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); for (timer = 6000000; timer; timer--) { /* Check for pending interrupts. */ stat = RD_REG_DWORD(®->host_status); if (stat & HSRX_RISC_INT) { stat &= 0xff; if (stat == 0x1 || stat == 0x2 || stat == 0x10 || stat == 0x11) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb[0] = RD_REG_WORD(®->mailbox0); mb[2] = RD_REG_WORD(®->mailbox2); mb[3] = RD_REG_WORD(®->mailbox3); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD(®->hccr); break; } /* Clear this intr; it wasn't a mailbox intr */ WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } } *nxt = rval == QLA_SUCCESS ? &ext_mem[cnt]: NULL; return rval; }
/** * qla2x00_reset_chip() - Reset ISP chip. * @ha: HA context * * Returns 0 on success. */ void qla2x00_reset_chip(scsi_qla_host_t *vha) { unsigned long flags = 0; struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint32_t cnt; uint16_t cmd; if (unlikely(pci_channel_offline(ha->pdev))) return; ha->isp_ops->disable_intrs(ha); spin_lock_irqsave(&ha->hardware_lock, flags); /* Turn off master enable */ cmd = 0; pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd); cmd &= ~PCI_COMMAND_MASTER; pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); if (!IS_QLA2100(ha)) { /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); if (IS_QLA2200(ha) || IS_QLA2300(ha)) { for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) != 0) break; udelay(100); } } else { RD_REG_WORD(®->hccr); /* PCI Posting. */ udelay(10); } /* Select FPM registers. */ WRT_REG_WORD(®->ctrl_status, 0x20); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ /* FPM Soft Reset. */ WRT_REG_WORD(®->fpm_diag_config, 0x100); RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */ /* Toggle Fpm Reset. */ if (!IS_QLA2200(ha)) { WRT_REG_WORD(®->fpm_diag_config, 0x0); RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */ } /* Select frame buffer registers. */ WRT_REG_WORD(®->ctrl_status, 0x10); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ /* Reset frame buffer FIFOs. */ if (IS_QLA2200(ha)) { WRT_FB_CMD_REG(ha, reg, 0xa000); RD_FB_CMD_REG(ha, reg); /* PCI Posting. */ } else { WRT_FB_CMD_REG(ha, reg, 0x00fc); /* Read back fb_cmd until zero or 3 seconds max */ for (cnt = 0; cnt < 3000; cnt++) { if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0) break; udelay(100); } } /* Select RISC module registers. */ WRT_REG_WORD(®->ctrl_status, 0); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ /* Release RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ } WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); /* Reset ISP chip. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); /* Wait for RISC to recover from reset. */ if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { /* * It is necessary to for a delay here since the card doesn't * respond to PCI reads during a reset. On some architectures * this will result in an MCA. */ udelay(20); for (cnt = 30000; cnt; cnt--) { if ((RD_REG_WORD(®->ctrl_status) & CSR_ISP_SOFT_RESET) == 0) break; udelay(100); } } else udelay(10); /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); WRT_REG_WORD(®->semaphore, 0); /* Release RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); RD_REG_WORD(®->hccr); /* PCI Posting. */ if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { for (cnt = 0; cnt < 30000; cnt++) { if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY) break; udelay(100); } } else udelay(100); /* Turn on master enable */ cmd |= PCI_COMMAND_MASTER; pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); /* Disable RISC pause on FPM parity error. */ if (!IS_QLA2100(ha)) { WRT_REG_WORD(®->hccr, HCCR_DISABLE_PARITY_PAUSE); RD_REG_WORD(®->hccr); /* PCI Posting. */ } spin_unlock_irqrestore(&ha->hardware_lock, flags); }
/** * qla2300_pci_config() - Setup ISP23xx PCI configuration registers. * @ha: HA context * * Returns 0 on success. */ int qla2300_pci_config(scsi_qla_host_t *vha) { uint16_t w; unsigned long flags = 0; uint32_t cnt; struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; pci_set_master(ha->pdev); pci_try_set_mwi(ha->pdev); pci_read_config_word(ha->pdev, PCI_COMMAND, &w); w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); if (IS_QLA2322(ha) || IS_QLA6322(ha)) w &= ~PCI_COMMAND_INTX_DISABLE; pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* * If this is a 2300 card and not 2312, reset the * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately, * the 2310 also reports itself as a 2300 so we need to get the * fb revision level -- a 6 indicates it really is a 2300 and * not a 2310. */ if (IS_QLA2300(ha)) { spin_lock_irqsave(&ha->hardware_lock, flags); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) != 0) break; udelay(10); } /* Select FPM registers. */ WRT_REG_WORD(®->ctrl_status, 0x20); RD_REG_WORD(®->ctrl_status); /* Get the fb rev level */ ha->fb_rev = RD_FB_CMD_REG(ha, reg); if (ha->fb_rev == FPM_2300) pci_clear_mwi(ha->pdev); /* Deselect FPM registers. */ WRT_REG_WORD(®->ctrl_status, 0x0); RD_REG_WORD(®->ctrl_status); /* Release RISC module. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); for (cnt = 0; cnt < 30000; cnt++) { if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0) break; udelay(10); } spin_unlock_irqrestore(&ha->hardware_lock, flags); } pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); pci_disable_rom(ha->pdev); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->pci_attr = RD_REG_WORD(®->ctrl_status); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_SUCCESS; }
/** * qla2x00_set_flash_image() - Write image to flash chip. * @ha: HA context * @image: Source image to write to flash * * Returns 0 on success, else non-zero. */ uint16_t qla2x00_set_flash_image(scsi_qla_host_t *ha, uint8_t *image) { uint16_t status; uint32_t addr; uint32_t midpoint; uint32_t sec_mask; uint32_t rest_addr; uint8_t mid; uint8_t sec_number; uint8_t data; device_reg_t *reg = ha->iobase; status = 0; sec_number = 0; /* Reset ISP chip. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ qla2x00_flash_enable(ha); do { /* Loop once to provide quick error exit */ /* Structure of flash memory based on manufacturer */ mid = qla2x00_get_flash_manufacturer(ha); if (mid == 0x6d) { // Am29LV001 part rest_addr = 0x1fff; sec_mask = 0x1e000; } else if (mid == 0x40) { // Mostel v29c51001 part rest_addr = 0x1ff; sec_mask = 0x1fe00; } else if (mid == 0xbf) { // SST39sf10 part rest_addr = 0xfff; sec_mask = 0x1f000; } else if (mid == 0xda) { // Winbond W29EE011 part rest_addr = 0x7f; sec_mask = 0x1ff80; addr = 0; if (qla2x00_erase_flash_sector(ha, addr, sec_mask, mid)) { status = 1; break; } } else { // Am29F010 part rest_addr = 0x3fff; sec_mask = 0x1c000; } midpoint = FLASH_IMAGE_SIZE / 2; for (addr = 0; addr < FLASH_IMAGE_SIZE; addr++) { data = *image++; /* Are we at the beginning of a sector? */ if (!(addr & rest_addr)) { if (addr == midpoint) WRT_REG_WORD(®->nvram, NVR_SELECT); /* Then erase it */ if (qla2x00_erase_flash_sector(ha, addr, sec_mask, mid)) { status = 1; break; } sec_number++; } if (mid == 0x6d) { if (sec_number == 1 && (addr == (rest_addr - 1))) { rest_addr = 0x0fff; sec_mask = 0x1f000; } else if (sec_number == 3 && (addr & 0x7ffe)) { rest_addr = 0x3fff; sec_mask = 0x1c000; } } if (qla2x00_program_flash_address(ha, addr, data, mid)) { status = 1; break; } } } while (0); qla2x00_flash_disable(ha); return (status); }
void qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { int rval; uint32_t cnt; uint32_t risc_address; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; uint32_t *iter_reg; uint16_t __iomem *mbx_reg; unsigned long flags; struct qla24xx_fw_dump *fw; uint32_t ext_mem_cnt; void *nxt; risc_address = ext_mem_cnt = 0; flags = 0; if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); if (!ha->fw_dump) { qla_printk(KERN_WARNING, ha, "No buffer available for dump!!!\n"); goto qla24xx_fw_dump_failed; } if (ha->fw_dumped) { qla_printk(KERN_WARNING, ha, "Firmware has been previously dumped (%p) -- ignoring " "request...\n", ha->fw_dump); goto qla24xx_fw_dump_failed; } fw = &ha->fw_dump->isp.isp24; qla2xxx_prep_dump(ha, ha->fw_dump); fw->host_status = htonl(RD_REG_DWORD(®->host_status)); /* Pause RISC. */ rval = qla24xx_pause_risc(reg); if (rval != QLA_SUCCESS) goto qla24xx_fw_dump_failed_0; /* Host interface registers. */ dmp_reg = ®->flash_addr; for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Disable interrupts. */ WRT_REG_DWORD(®->ictrl, 0); RD_REG_DWORD(®->ictrl); /* Shadow registers. */ WRT_REG_DWORD(®->iobase_addr, 0x0F70); RD_REG_DWORD(®->iobase_addr); WRT_REG_DWORD(®->iobase_select, 0xB0000000); fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); WRT_REG_DWORD(®->iobase_select, 0xB0100000); fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); WRT_REG_DWORD(®->iobase_select, 0xB0200000); fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); WRT_REG_DWORD(®->iobase_select, 0xB0300000); fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); WRT_REG_DWORD(®->iobase_select, 0xB0400000); fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); WRT_REG_DWORD(®->iobase_select, 0xB0500000); fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); WRT_REG_DWORD(®->iobase_select, 0xB0600000); fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); /* Mailbox registers. */ mbx_reg = ®->mailbox0; for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); /* Transfer sequence registers. */ iter_reg = fw->xseq_gp_reg; iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); qla24xx_read_window(reg, 0xBF70, 16, iter_reg); qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg); qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); /* Receive sequence registers. */ iter_reg = fw->rseq_gp_reg; iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); qla24xx_read_window(reg, 0xFF70, 16, iter_reg); qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg); qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); /* Command DMA registers. */ qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); /* Queues. */ iter_reg = fw->req0_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); dmp_reg = ®->iobase_q; for (cnt = 0; cnt < 7; cnt++) *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->resp0_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); dmp_reg = ®->iobase_q; for (cnt = 0; cnt < 7; cnt++) *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->req1_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); dmp_reg = ®->iobase_q; for (cnt = 0; cnt < 7; cnt++) *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Transmit DMA registers. */ iter_reg = fw->xmt0_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); qla24xx_read_window(reg, 0x7610, 16, iter_reg); iter_reg = fw->xmt1_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); qla24xx_read_window(reg, 0x7630, 16, iter_reg); iter_reg = fw->xmt2_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); qla24xx_read_window(reg, 0x7650, 16, iter_reg); iter_reg = fw->xmt3_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); qla24xx_read_window(reg, 0x7670, 16, iter_reg); iter_reg = fw->xmt4_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); qla24xx_read_window(reg, 0x7690, 16, iter_reg); qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); /* Receive DMA registers. */ iter_reg = fw->rcvt0_data_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); qla24xx_read_window(reg, 0x7710, 16, iter_reg); iter_reg = fw->rcvt1_data_dma_reg; iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); qla24xx_read_window(reg, 0x7730, 16, iter_reg); /* RISC registers. */ iter_reg = fw->risc_gp_reg; iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); qla24xx_read_window(reg, 0x0F70, 16, iter_reg); /* Local memory controller registers. */ iter_reg = fw->lmc_reg; iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); qla24xx_read_window(reg, 0x3060, 16, iter_reg); /* Fibre Protocol Module registers. */ iter_reg = fw->fpm_hdw_reg; iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); qla24xx_read_window(reg, 0x40B0, 16, iter_reg); /* Frame Buffer registers. */ iter_reg = fw->fb_hdw_reg; iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); qla24xx_read_window(reg, 0x61B0, 16, iter_reg); rval = qla24xx_soft_reset(ha); if (rval != QLA_SUCCESS) goto qla24xx_fw_dump_failed_0; rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), fw->ext_mem, &nxt); if (rval != QLA_SUCCESS) goto qla24xx_fw_dump_failed_0; nxt = qla2xxx_copy_queues(ha, nxt); if (ha->eft) memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); qla24xx_fw_dump_failed_0: if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); ha->fw_dumped = 0; } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", ha->host_no, ha->fw_dump); ha->fw_dumped = 1; } qla24xx_fw_dump_failed: if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); }
/** * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. * @ha: HA context * @hardware_locked: Called with the hardware_lock */ void qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { int rval; uint32_t cnt, timer; uint16_t risc_address; uint16_t mb0, mb2; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; uint16_t __iomem *dmp_reg; unsigned long flags; struct qla2100_fw_dump *fw; risc_address = 0; mb0 = mb2 = 0; flags = 0; if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); if (!ha->fw_dump) { qla_printk(KERN_WARNING, ha, "No buffer available for dump!!!\n"); goto qla2100_fw_dump_failed; } if (ha->fw_dumped) { qla_printk(KERN_WARNING, ha, "Firmware has been previously dumped (%p) -- ignoring " "request...\n", ha->fw_dump); goto qla2100_fw_dump_failed; } fw = &ha->fw_dump->isp.isp21; qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } if (rval == QLA_SUCCESS) { dmp_reg = ®->flash_address; for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = ®->u.isp2100.mailbox0; for (cnt = 0; cnt < ha->mbx_count; cnt++) { if (cnt == 8) dmp_reg = ®->u_end.isp2200.mailbox8; fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); } dmp_reg = ®->u.isp2100.unused_2[0]; for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = ®->risc_hw; for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); qla2xxx_read_window(reg, 16, fw->risc_gp0_reg); WRT_REG_WORD(®->pcr, 0x2100); qla2xxx_read_window(reg, 16, fw->risc_gp1_reg); WRT_REG_WORD(®->pcr, 0x2200); qla2xxx_read_window(reg, 16, fw->risc_gp2_reg); WRT_REG_WORD(®->pcr, 0x2300); qla2xxx_read_window(reg, 16, fw->risc_gp3_reg); WRT_REG_WORD(®->pcr, 0x2400); qla2xxx_read_window(reg, 16, fw->risc_gp4_reg); WRT_REG_WORD(®->pcr, 0x2500); qla2xxx_read_window(reg, 16, fw->risc_gp5_reg); WRT_REG_WORD(®->pcr, 0x2600); qla2xxx_read_window(reg, 16, fw->risc_gp6_reg); WRT_REG_WORD(®->pcr, 0x2700); qla2xxx_read_window(reg, 16, fw->risc_gp7_reg); WRT_REG_WORD(®->ctrl_status, 0x10); qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg); WRT_REG_WORD(®->ctrl_status, 0x20); qla2xxx_read_window(reg, 64, fw->fpm_b0_reg); WRT_REG_WORD(®->ctrl_status, 0x30); qla2xxx_read_window(reg, 64, fw->fpm_b1_reg); /* Reset the ISP. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); } for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } /* Pause RISC. */ if (rval == QLA_SUCCESS && (IS_QLA2200(ha) || (IS_QLA2100(ha) && (RD_REG_WORD(®->mctr) & (BIT_1 | BIT_0)) != 0))) { WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && rval == QLA_SUCCESS; cnt--) { if (cnt) udelay(100); else rval = QLA_FUNCTION_TIMEOUT; } if (rval == QLA_SUCCESS) { /* Set memory configuration and timing. */ if (IS_QLA2100(ha)) WRT_REG_WORD(®->mctr, 0xf1); else WRT_REG_WORD(®->mctr, 0xf2); RD_REG_WORD(®->mctr); /* PCI Posting. */ /* Release RISC. */ WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); } } if (rval == QLA_SUCCESS) { /* Get RISC SRAM. */ risc_address = 0x1000; WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD); clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); } for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS; cnt++, risc_address++) { WRT_MAILBOX_REG(ha, reg, 1, risc_address); WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); for (timer = 6000000; timer != 0; timer--) { /* Check for pending interrupts. */ if (RD_REG_WORD(®->istatus) & ISR_RISC_INT) { if (RD_REG_WORD(®->semaphore) & BIT_0) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); mb0 = RD_MAILBOX_REG(ha, reg, 0); mb2 = RD_MAILBOX_REG(ha, reg, 2); WRT_REG_WORD(®->semaphore, 0); WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); break; } WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD(®->hccr); } udelay(5); } if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } if (rval == QLA_SUCCESS) qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]); if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); ha->fw_dumped = 0; } else { qla_printk(KERN_INFO, ha, "Firmware dump saved to temp buffer (%ld/%p).\n", ha->host_no, ha->fw_dump); ha->fw_dumped = 1; } qla2100_fw_dump_failed: if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); }
/** * 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(®->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; 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(®->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(®->hccr, HCCR_CLR_RISC_INT); RD_REG_WORD_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); }
/** * 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(®->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); 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(®->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; }
/** * 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(®->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. */ 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(®->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); 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); }
/** * 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); }
/** * qla2x00_write_nvram_word() - Write NVRAM data. * @ha: HA context * @addr: Address in NVRAM to write * @data: word to program */ void qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) { int count; uint16_t word; uint32_t nv_cmd; device_reg_t *reg = ha->iobase; qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_write(ha, 0); qla2x00_nv_write(ha, 0); for (word = 0; word < 8; word++) qla2x00_nv_write(ha, NVR_DATA_OUT); qla2x00_nv_deselect(ha); /* Erase Location */ nv_cmd = (addr << 16) | NV_ERASE_OP; nv_cmd <<= 5; for (count = 0; count < 11; count++) { if (nv_cmd & BIT_31) qla2x00_nv_write(ha, NVR_DATA_OUT); else qla2x00_nv_write(ha, 0); nv_cmd <<= 1; } qla2x00_nv_deselect(ha); /* Wait for Erase to Finish */ WRT_REG_WORD(®->nvram, NVR_SELECT); do { NVRAM_DELAY(); word = RD_REG_WORD(®->nvram); } while ((word & NVR_DATA_IN) == 0); qla2x00_nv_deselect(ha); /* Write data */ nv_cmd = (addr << 16) | NV_WRITE_OP; nv_cmd |= data; nv_cmd <<= 5; for (count = 0; count < 27; count++) { if (nv_cmd & BIT_31) qla2x00_nv_write(ha, NVR_DATA_OUT); else qla2x00_nv_write(ha, 0); nv_cmd <<= 1; } qla2x00_nv_deselect(ha); /* Wait for NVRAM to become ready */ WRT_REG_WORD(®->nvram, NVR_SELECT); do { NVRAM_DELAY(); word = RD_REG_WORD(®->nvram); } while ((word & NVR_DATA_IN) == 0); qla2x00_nv_deselect(ha); /* Disable writes */ qla2x00_nv_write(ha, NVR_DATA_OUT); for (count = 0; count < 10; count++) qla2x00_nv_write(ha, 0); qla2x00_nv_deselect(ha); }