qla_init.c
来自「linux 内核源代码」· C语言 代码 · 共 2,472 行 · 第 1/5 页
C
2,472 行
* @ha: HA context * * Returns 0 on success. */static inline voidqla24xx_reset_risc(scsi_qla_host_t *ha){ unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t cnt, d2; uint16_t wd; 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(); } WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); RD_REG_DWORD(®->hccr); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); RD_REG_DWORD(®->hccr); d2 = (uint32_t) RD_REG_WORD(®->mailbox0); for (cnt = 6000000 ; cnt && d2; cnt--) { udelay(5); d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } spin_unlock_irqrestore(&ha->hardware_lock, flags);}/** * qla24xx_reset_chip() - Reset ISP24xx chip. * @ha: HA context * * Returns 0 on success. */voidqla24xx_reset_chip(scsi_qla_host_t *ha){ ha->isp_ops->disable_intrs(ha); /* Perform RISC reset. */ qla24xx_reset_risc(ha);}/** * qla2x00_chip_diag() - Test chip for proper operation. * @ha: HA context * * Returns 0 on success. */intqla2x00_chip_diag(scsi_qla_host_t *ha){ int rval; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; unsigned long flags = 0; uint16_t data; uint32_t cnt; uint16_t mb[5]; /* Assume a failed state */ rval = QLA_FUNCTION_FAILED; DEBUG3(printk("scsi(%ld): Testing device at %lx.\n", ha->host_no, (u_long)®->flash_address)); spin_lock_irqsave(&ha->hardware_lock, flags); /* Reset ISP chip. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); /* * We need to have a delay here since the card will not respond while * in reset causing an MCA on some architectures. */ udelay(20); data = qla2x00_debounce_register(®->ctrl_status); for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) { udelay(5); data = RD_REG_WORD(®->ctrl_status); barrier(); } if (!cnt) goto chip_diag_failed; DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n", ha->host_no)); /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); /* Workaround for QLA2312 PCI parity error */ if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0)); for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) { udelay(5); data = RD_MAILBOX_REG(ha, reg, 0); barrier(); } } else udelay(10); if (!cnt) goto chip_diag_failed; /* Check product ID of chip */ DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no)); mb[1] = RD_MAILBOX_REG(ha, reg, 1); mb[2] = RD_MAILBOX_REG(ha, reg, 2); mb[3] = RD_MAILBOX_REG(ha, reg, 3); mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4)); if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) || mb[3] != PROD_ID_3) { qla_printk(KERN_WARNING, ha, "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]); goto chip_diag_failed; } ha->product_id[0] = mb[1]; ha->product_id[1] = mb[2]; ha->product_id[2] = mb[3]; ha->product_id[3] = mb[4]; /* Adjust fw RISC transfer size */ if (ha->request_q_length > 1024) ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; else ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length; if (IS_QLA2200(ha) && RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) { /* Limit firmware transfer size with a 2200A */ DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n", ha->host_no)); ha->device_type |= DT_ISP2200A; ha->fw_transfer_size = 128; } /* Wrap Incoming Mailboxes Test. */ spin_unlock_irqrestore(&ha->hardware_lock, flags); DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", ha->host_no)); rval = qla2x00_mbx_reg_test(ha); if (rval) { DEBUG(printk("scsi(%ld): Failed mailbox send register test\n", ha->host_no)); qla_printk(KERN_WARNING, ha, "Failed mailbox send register test\n"); } else { /* Flag a successful rval */ rval = QLA_SUCCESS; } spin_lock_irqsave(&ha->hardware_lock, flags);chip_diag_failed: if (rval) DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED " "****\n", ha->host_no)); spin_unlock_irqrestore(&ha->hardware_lock, flags); return (rval);}/** * qla24xx_chip_diag() - Test ISP24xx for proper operation. * @ha: HA context * * Returns 0 on success. */intqla24xx_chip_diag(scsi_qla_host_t *ha){ int rval; /* Perform RISC reset. */ qla24xx_reset_risc(ha); ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; rval = qla2x00_mbx_reg_test(ha); if (rval) { DEBUG(printk("scsi(%ld): Failed mailbox send register test\n", ha->host_no)); qla_printk(KERN_WARNING, ha, "Failed mailbox send register test\n"); } else { /* Flag a successful rval */ rval = QLA_SUCCESS; } return rval;}voidqla2x00_alloc_fw_dump(scsi_qla_host_t *ha){ int rval; uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, eft_size; dma_addr_t eft_dma; void *eft; if (ha->fw_dump) { qla_printk(KERN_WARNING, ha, "Firmware dump previously allocated.\n"); return; } ha->fw_dumped = 0; fixed_size = mem_size = eft_size = 0; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { fixed_size = sizeof(struct qla2100_fw_dump); } else if (IS_QLA23XX(ha)) { fixed_size = offsetof(struct qla2300_fw_dump, data_ram); mem_size = (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { fixed_size = IS_QLA25XX(ha) ? offsetof(struct qla25xx_fw_dump, ext_mem): offsetof(struct qla24xx_fw_dump, ext_mem); mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); /* Allocate memory for Extended Trace Buffer. */ eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma, GFP_KERNEL); if (!eft) { qla_printk(KERN_WARNING, ha, "Unable to allocate " "(%d KB) for EFT.\n", EFT_SIZE / 1024); goto cont_alloc; } rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma, EFT_NUM_BUFFERS); if (rval) { qla_printk(KERN_WARNING, ha, "Unable to initialize " "EFT (%d).\n", rval); dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft, eft_dma); goto cont_alloc; } qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", EFT_SIZE / 1024); eft_size = EFT_SIZE; memset(eft, 0, eft_size); ha->eft_dma = eft_dma; ha->eft = eft; }cont_alloc: req_q_size = ha->request_q_length * sizeof(request_t); rsp_q_size = ha->response_q_length * sizeof(response_t); dump_size = offsetof(struct qla2xxx_fw_dump, isp); dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size; ha->fw_dump = vmalloc(dump_size); if (!ha->fw_dump) { qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for " "firmware dump!!!\n", dump_size / 1024); if (ha->eft) { dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft, ha->eft_dma); ha->eft = NULL; ha->eft_dma = 0; } return; } qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n", dump_size / 1024); ha->fw_dump_len = dump_size; ha->fw_dump->signature[0] = 'Q'; ha->fw_dump->signature[1] = 'L'; ha->fw_dump->signature[2] = 'G'; ha->fw_dump->signature[3] = 'C'; ha->fw_dump->version = __constant_htonl(1); ha->fw_dump->fixed_size = htonl(fixed_size); ha->fw_dump->mem_size = htonl(mem_size); ha->fw_dump->req_q_size = htonl(req_q_size); ha->fw_dump->rsp_q_size = htonl(rsp_q_size); ha->fw_dump->eft_size = htonl(eft_size); ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma)); ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma)); ha->fw_dump->header_size = htonl(offsetof(struct qla2xxx_fw_dump, isp));}/** * qla2x00_resize_request_q() - Resize request queue given available ISP memory. * @ha: HA context * * Returns 0 on success. */static voidqla2x00_resize_request_q(scsi_qla_host_t *ha){ int rval; uint16_t fw_iocb_cnt = 0; uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM; dma_addr_t request_dma; request_t *request_ring; /* Valid only on recent ISPs. */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) return; /* Retrieve IOCB counts available to the firmware. */ rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt, &ha->max_npiv_vports); if (rval) return; /* No point in continuing if current settings are sufficient. */ if (fw_iocb_cnt < 1024) return; if (ha->request_q_length >= request_q_length) return; /* Attempt to claim larger area for request queue. */ request_ring = dma_alloc_coherent(&ha->pdev->dev, (request_q_length + 1) * sizeof(request_t), &request_dma, GFP_KERNEL); if (request_ring == NULL) return; /* Resize successful, report extensions. */ qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n", (ha->fw_memory_size + 1) / 1024); qla_printk(KERN_INFO, ha, "Resizing request queue depth " "(%d -> %d)...\n", ha->request_q_length, request_q_length); /* Clear old allocations. */ dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); /* Begin using larger queue. */ ha->request_q_length = request_q_length; ha->request_ring = request_ring; ha->request_dma = request_dma;}/** * qla2x00_setup_chip() - Load and start RISC firmware. * @ha: HA context * * Returns 0 on success. */static intqla2x00_setup_chip(scsi_qla_host_t *ha){ int rval; uint32_t srisc_address = 0; /* Load firmware sequences */ rval = ha->isp_ops->load_risc(ha, &srisc_address); if (rval == QLA_SUCCESS) { DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC " "code.\n", ha->host_no)); rval = qla2x00_verify_checksum(ha, srisc_address); if (rval == QLA_SUCCESS) { /* Start firmware execution. */ DEBUG(printk("scsi(%ld): Checksum OK, start " "firmware.\n", ha->host_no)); rval = qla2x00_execute_fw(ha, srisc_address); /* Retrieve firmware information. */ if (rval == QLA_SUCCESS && ha->fw_major_version == 0) { qla2x00_get_fw_version(ha, &ha->fw_major_version, &ha->fw_minor_version, &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); qla2x00_resize_request_q(ha); ha->flags.npiv_supported = 0; if ((IS_QLA24XX(ha) || IS_QLA25XX(ha)) && (ha->fw_attributes & BIT_2)) { ha->flags.npiv_supported = 1; if ((!ha->max_npiv_vports) || ((ha->max_npiv_vports + 1) % MAX_MULTI_ID_FABRIC)) ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC; } if (ql2xallocfwdump) qla2x00_alloc_fw_dump(ha); } } else { DEBUG2(printk(KERN_INFO "scsi(%ld): ISP Firmware failed checksum.\n", ha->host_no)); } } if (rval) { DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", ha->host_no)); } return (rval);}/** * qla2x00_init_response_q_entries() - Initializes response queue entries. * @ha: HA context * * Beginning of request ring has initialization control block already built * by nvram config routine. * * Returns 0 on success. */static voidqla2x00_init_response_q_entries(scsi_qla_host_t *ha){ uint16_t cnt; response_t *pkt; pkt = ha->response_ring_ptr; for (cnt = 0; cnt < ha->response_q_length; cnt++) { pkt->signature = RESPONSE_PROCESSED; pkt++; }}/** * qla2x00_update_fw_options() - Read and process firmware options. * @ha: HA context * * Returns 0 on success. */voidqla2x00_update_fw_options(scsi_qla_host_t *ha){ uint16_t swing, emphasis, tx_sens, rx_sens; memset(ha->fw_options, 0, sizeof(ha->fw_options)); qla2x00_get_fw_options(ha, ha->fw_options); if (IS_QLA2100(ha) || IS_QLA2200(ha)) return; /* Serial Link options. */ DEBUG3(printk("scsi(%ld): Serial link options:\n", ha->host_no));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?