162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic iSCSI HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2013 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <scsi/iscsi_if.h> 862306a36Sopenharmony_ci#include "ql4_def.h" 962306a36Sopenharmony_ci#include "ql4_glbl.h" 1062306a36Sopenharmony_ci#include "ql4_dbg.h" 1162306a36Sopenharmony_ci#include "ql4_inline.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic void ql4xxx_set_mac_number(struct scsi_qla_host *ha) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci uint32_t value; 1662306a36Sopenharmony_ci unsigned long flags; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci /* Get the function number */ 1962306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 2062306a36Sopenharmony_ci value = readw(&ha->reg->ctrl_status); 2162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci switch (value & ISP_CONTROL_FN_MASK) { 2462306a36Sopenharmony_ci case ISP_CONTROL_FN0_SCSI: 2562306a36Sopenharmony_ci ha->mac_index = 1; 2662306a36Sopenharmony_ci break; 2762306a36Sopenharmony_ci case ISP_CONTROL_FN1_SCSI: 2862306a36Sopenharmony_ci ha->mac_index = 3; 2962306a36Sopenharmony_ci break; 3062306a36Sopenharmony_ci default: 3162306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Invalid function number, " 3262306a36Sopenharmony_ci "ispControlStatus = 0x%x\n", ha->host_no, 3362306a36Sopenharmony_ci __func__, value)); 3462306a36Sopenharmony_ci break; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__, 3762306a36Sopenharmony_ci ha->mac_index)); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * qla4xxx_free_ddb - deallocate ddb 4262306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 4362306a36Sopenharmony_ci * @ddb_entry: pointer to device database entry 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * This routine marks a DDB entry INVALID 4662306a36Sopenharmony_ci **/ 4762306a36Sopenharmony_civoid qla4xxx_free_ddb(struct scsi_qla_host *ha, 4862306a36Sopenharmony_ci struct ddb_entry *ddb_entry) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci /* Remove device pointer from index mapping arrays */ 5162306a36Sopenharmony_ci ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = 5262306a36Sopenharmony_ci (struct ddb_entry *) INVALID_ENTRY; 5362306a36Sopenharmony_ci ha->tot_ddbs--; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/** 5762306a36Sopenharmony_ci * qla4xxx_init_response_q_entries() - Initializes response queue entries. 5862306a36Sopenharmony_ci * @ha: HA context 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * Beginning of request ring has initialization control block already built 6162306a36Sopenharmony_ci * by nvram config routine. 6262306a36Sopenharmony_ci **/ 6362306a36Sopenharmony_cistatic void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci uint16_t cnt; 6662306a36Sopenharmony_ci struct response *pkt; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci pkt = (struct response *)ha->response_ptr; 6962306a36Sopenharmony_ci for (cnt = 0; cnt < RESPONSE_QUEUE_DEPTH; cnt++) { 7062306a36Sopenharmony_ci pkt->signature = RESPONSE_PROCESSED; 7162306a36Sopenharmony_ci pkt++; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * qla4xxx_init_rings - initialize hw queues 7762306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * This routine initializes the internal queues for the specified adapter. 8062306a36Sopenharmony_ci * The QLA4010 requires us to restart the queues at index 0. 8162306a36Sopenharmony_ci * The QLA4000 doesn't care, so just default to QLA4010's requirement. 8262306a36Sopenharmony_ci **/ 8362306a36Sopenharmony_ciint qla4xxx_init_rings(struct scsi_qla_host *ha) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci unsigned long flags = 0; 8662306a36Sopenharmony_ci int i; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* Initialize request queue. */ 8962306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 9062306a36Sopenharmony_ci ha->request_out = 0; 9162306a36Sopenharmony_ci ha->request_in = 0; 9262306a36Sopenharmony_ci ha->request_ptr = &ha->request_ring[ha->request_in]; 9362306a36Sopenharmony_ci ha->req_q_count = REQUEST_QUEUE_DEPTH; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Initialize response queue. */ 9662306a36Sopenharmony_ci ha->response_in = 0; 9762306a36Sopenharmony_ci ha->response_out = 0; 9862306a36Sopenharmony_ci ha->response_ptr = &ha->response_ring[ha->response_out]; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (is_qla8022(ha)) { 10162306a36Sopenharmony_ci writel(0, 10262306a36Sopenharmony_ci (unsigned long __iomem *)&ha->qla4_82xx_reg->req_q_out); 10362306a36Sopenharmony_ci writel(0, 10462306a36Sopenharmony_ci (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_in); 10562306a36Sopenharmony_ci writel(0, 10662306a36Sopenharmony_ci (unsigned long __iomem *)&ha->qla4_82xx_reg->rsp_q_out); 10762306a36Sopenharmony_ci } else if (is_qla8032(ha) || is_qla8042(ha)) { 10862306a36Sopenharmony_ci writel(0, 10962306a36Sopenharmony_ci (unsigned long __iomem *)&ha->qla4_83xx_reg->req_q_in); 11062306a36Sopenharmony_ci writel(0, 11162306a36Sopenharmony_ci (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_in); 11262306a36Sopenharmony_ci writel(0, 11362306a36Sopenharmony_ci (unsigned long __iomem *)&ha->qla4_83xx_reg->rsp_q_out); 11462306a36Sopenharmony_ci } else { 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Initialize DMA Shadow registers. The firmware is really 11762306a36Sopenharmony_ci * supposed to take care of this, but on some uniprocessor 11862306a36Sopenharmony_ci * systems, the shadow registers aren't cleared-- causing 11962306a36Sopenharmony_ci * the interrupt_handler to think there are responses to be 12062306a36Sopenharmony_ci * processed when there aren't. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci ha->shadow_regs->req_q_out = cpu_to_le32(0); 12362306a36Sopenharmony_ci ha->shadow_regs->rsp_q_in = cpu_to_le32(0); 12462306a36Sopenharmony_ci wmb(); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci writel(0, &ha->reg->req_q_in); 12762306a36Sopenharmony_ci writel(0, &ha->reg->rsp_q_out); 12862306a36Sopenharmony_ci readl(&ha->reg->rsp_q_out); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci qla4xxx_init_response_q_entries(ha); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* Initialize mailbox active array */ 13462306a36Sopenharmony_ci for (i = 0; i < MAX_MRB; i++) 13562306a36Sopenharmony_ci ha->active_mrb_array[i] = NULL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci return QLA_SUCCESS; 14062306a36Sopenharmony_ci} 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/** 14362306a36Sopenharmony_ci * qla4xxx_get_sys_info - validate adapter MAC address(es) 14462306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci **/ 14762306a36Sopenharmony_ciint qla4xxx_get_sys_info(struct scsi_qla_host *ha) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct flash_sys_info *sys_info; 15062306a36Sopenharmony_ci dma_addr_t sys_info_dma; 15162306a36Sopenharmony_ci int status = QLA_ERROR; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), 15462306a36Sopenharmony_ci &sys_info_dma, GFP_KERNEL); 15562306a36Sopenharmony_ci if (sys_info == NULL) { 15662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", 15762306a36Sopenharmony_ci ha->host_no, __func__)); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci goto exit_get_sys_info_no_free; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Get flash sys info */ 16362306a36Sopenharmony_ci if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO, 16462306a36Sopenharmony_ci sizeof(*sys_info)) != QLA_SUCCESS) { 16562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO " 16662306a36Sopenharmony_ci "failed\n", ha->host_no, __func__)); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci goto exit_get_sys_info; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* Save M.A.C. address & serial_number */ 17262306a36Sopenharmony_ci memcpy(ha->my_mac, &sys_info->physAddr[0].address[0], 17362306a36Sopenharmony_ci min(sizeof(ha->my_mac), 17462306a36Sopenharmony_ci sizeof(sys_info->physAddr[0].address))); 17562306a36Sopenharmony_ci memcpy(ha->serial_number, &sys_info->acSerialNumber, 17662306a36Sopenharmony_ci min(sizeof(ha->serial_number), 17762306a36Sopenharmony_ci sizeof(sys_info->acSerialNumber))); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci status = QLA_SUCCESS; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciexit_get_sys_info: 18262306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info, 18362306a36Sopenharmony_ci sys_info_dma); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ciexit_get_sys_info_no_free: 18662306a36Sopenharmony_ci return status; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci/** 19062306a36Sopenharmony_ci * qla4xxx_init_local_data - initialize adapter specific local data 19162306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci **/ 19462306a36Sopenharmony_cistatic void qla4xxx_init_local_data(struct scsi_qla_host *ha) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci /* Initialize aen queue */ 19762306a36Sopenharmony_ci ha->aen_q_count = MAX_AEN_ENTRIES; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic uint8_t 20162306a36Sopenharmony_ciqla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci uint8_t ipv4_wait = 0; 20462306a36Sopenharmony_ci uint8_t ipv6_wait = 0; 20562306a36Sopenharmony_ci int8_t ip_address[IPv6_ADDR_LEN] = {0} ; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* If both IPv4 & IPv6 are enabled, possibly only one 20862306a36Sopenharmony_ci * IP address may be acquired, so check to see if we 20962306a36Sopenharmony_ci * need to wait for another */ 21062306a36Sopenharmony_ci if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) { 21162306a36Sopenharmony_ci if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) && 21262306a36Sopenharmony_ci ((ha->addl_fw_state & 21362306a36Sopenharmony_ci FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) { 21462306a36Sopenharmony_ci ipv4_wait = 1; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci if (((ha->ip_config.ipv6_addl_options & 21762306a36Sopenharmony_ci IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) && 21862306a36Sopenharmony_ci ((ha->ip_config.ipv6_link_local_state == 21962306a36Sopenharmony_ci IP_ADDRSTATE_ACQUIRING) || 22062306a36Sopenharmony_ci (ha->ip_config.ipv6_addr0_state == 22162306a36Sopenharmony_ci IP_ADDRSTATE_ACQUIRING) || 22262306a36Sopenharmony_ci (ha->ip_config.ipv6_addr1_state == 22362306a36Sopenharmony_ci IP_ADDRSTATE_ACQUIRING))) { 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci ipv6_wait = 1; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if ((ha->ip_config.ipv6_link_local_state == 22862306a36Sopenharmony_ci IP_ADDRSTATE_PREFERRED) || 22962306a36Sopenharmony_ci (ha->ip_config.ipv6_addr0_state == 23062306a36Sopenharmony_ci IP_ADDRSTATE_PREFERRED) || 23162306a36Sopenharmony_ci (ha->ip_config.ipv6_addr1_state == 23262306a36Sopenharmony_ci IP_ADDRSTATE_PREFERRED)) { 23362306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: " 23462306a36Sopenharmony_ci "Preferred IP configured." 23562306a36Sopenharmony_ci " Don't wait!\n", ha->host_no, 23662306a36Sopenharmony_ci __func__)); 23762306a36Sopenharmony_ci ipv6_wait = 0; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci if (memcmp(&ha->ip_config.ipv6_default_router_addr, 24062306a36Sopenharmony_ci ip_address, IPv6_ADDR_LEN) == 0) { 24162306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: " 24262306a36Sopenharmony_ci "No Router configured. " 24362306a36Sopenharmony_ci "Don't wait!\n", ha->host_no, 24462306a36Sopenharmony_ci __func__)); 24562306a36Sopenharmony_ci ipv6_wait = 0; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci if ((ha->ip_config.ipv6_default_router_state == 24862306a36Sopenharmony_ci IPV6_RTRSTATE_MANUAL) && 24962306a36Sopenharmony_ci (ha->ip_config.ipv6_link_local_state == 25062306a36Sopenharmony_ci IP_ADDRSTATE_TENTATIVE) && 25162306a36Sopenharmony_ci (memcmp(&ha->ip_config.ipv6_link_local_addr, 25262306a36Sopenharmony_ci &ha->ip_config.ipv6_default_router_addr, 4) == 25362306a36Sopenharmony_ci 0)) { 25462306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: LinkLocal Router & " 25562306a36Sopenharmony_ci "IP configured. Don't wait!\n", 25662306a36Sopenharmony_ci ha->host_no, __func__)); 25762306a36Sopenharmony_ci ipv6_wait = 0; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci if (ipv4_wait || ipv6_wait) { 26162306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Wait for additional " 26262306a36Sopenharmony_ci "IP(s) \"", ha->host_no, __func__)); 26362306a36Sopenharmony_ci if (ipv4_wait) 26462306a36Sopenharmony_ci DEBUG2(printk("IPv4 ")); 26562306a36Sopenharmony_ci if (ha->ip_config.ipv6_link_local_state == 26662306a36Sopenharmony_ci IP_ADDRSTATE_ACQUIRING) 26762306a36Sopenharmony_ci DEBUG2(printk("IPv6LinkLocal ")); 26862306a36Sopenharmony_ci if (ha->ip_config.ipv6_addr0_state == 26962306a36Sopenharmony_ci IP_ADDRSTATE_ACQUIRING) 27062306a36Sopenharmony_ci DEBUG2(printk("IPv6Addr0 ")); 27162306a36Sopenharmony_ci if (ha->ip_config.ipv6_addr1_state == 27262306a36Sopenharmony_ci IP_ADDRSTATE_ACQUIRING) 27362306a36Sopenharmony_ci DEBUG2(printk("IPv6Addr1 ")); 27462306a36Sopenharmony_ci DEBUG2(printk("\"\n")); 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return ipv4_wait|ipv6_wait; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic int qla4_80xx_is_minidump_dma_capable(struct scsi_qla_host *ha, 28262306a36Sopenharmony_ci struct qla4_8xxx_minidump_template_hdr *md_hdr) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci int offset = (is_qla8022(ha)) ? QLA8022_TEMPLATE_CAP_OFFSET : 28562306a36Sopenharmony_ci QLA83XX_TEMPLATE_CAP_OFFSET; 28662306a36Sopenharmony_ci int rval = 1; 28762306a36Sopenharmony_ci uint32_t *cap_offset; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci cap_offset = (uint32_t *)((char *)md_hdr + offset); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (!(le32_to_cpu(*cap_offset) & BIT_0)) { 29262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "PEX DMA Not supported %d\n", 29362306a36Sopenharmony_ci *cap_offset); 29462306a36Sopenharmony_ci rval = 0; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return rval; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/** 30162306a36Sopenharmony_ci * qla4xxx_alloc_fw_dump - Allocate memory for minidump data. 30262306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 30362306a36Sopenharmony_ci **/ 30462306a36Sopenharmony_civoid qla4xxx_alloc_fw_dump(struct scsi_qla_host *ha) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int status; 30762306a36Sopenharmony_ci uint32_t capture_debug_level; 30862306a36Sopenharmony_ci int hdr_entry_bit, k; 30962306a36Sopenharmony_ci void *md_tmp; 31062306a36Sopenharmony_ci dma_addr_t md_tmp_dma; 31162306a36Sopenharmony_ci struct qla4_8xxx_minidump_template_hdr *md_hdr; 31262306a36Sopenharmony_ci int dma_capable; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (ha->fw_dump) { 31562306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 31662306a36Sopenharmony_ci "Firmware dump previously allocated.\n"); 31762306a36Sopenharmony_ci return; 31862306a36Sopenharmony_ci } 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci status = qla4xxx_req_template_size(ha); 32162306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 32262306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 32362306a36Sopenharmony_ci "scsi%ld: Failed to get template size\n", 32462306a36Sopenharmony_ci ha->host_no); 32562306a36Sopenharmony_ci return; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci clear_bit(AF_82XX_FW_DUMPED, &ha->flags); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Allocate memory for saving the template */ 33162306a36Sopenharmony_ci md_tmp = dma_alloc_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, 33262306a36Sopenharmony_ci &md_tmp_dma, GFP_KERNEL); 33362306a36Sopenharmony_ci if (!md_tmp) { 33462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 33562306a36Sopenharmony_ci "scsi%ld: Failed to allocate DMA memory\n", 33662306a36Sopenharmony_ci ha->host_no); 33762306a36Sopenharmony_ci return; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* Request template */ 34162306a36Sopenharmony_ci status = qla4xxx_get_minidump_template(ha, md_tmp_dma); 34262306a36Sopenharmony_ci if (status != QLA_SUCCESS) { 34362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 34462306a36Sopenharmony_ci "scsi%ld: Failed to get minidump template\n", 34562306a36Sopenharmony_ci ha->host_no); 34662306a36Sopenharmony_ci goto alloc_cleanup; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci md_hdr = (struct qla4_8xxx_minidump_template_hdr *)md_tmp; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci dma_capable = qla4_80xx_is_minidump_dma_capable(ha, md_hdr); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci capture_debug_level = md_hdr->capture_debug_level; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Get capture mask based on module loadtime setting. */ 35662306a36Sopenharmony_ci if ((ql4xmdcapmask >= 0x3 && ql4xmdcapmask <= 0x7F) || 35762306a36Sopenharmony_ci (ql4xmdcapmask == 0xFF && dma_capable)) { 35862306a36Sopenharmony_ci ha->fw_dump_capture_mask = ql4xmdcapmask; 35962306a36Sopenharmony_ci } else { 36062306a36Sopenharmony_ci if (ql4xmdcapmask == 0xFF) 36162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Falling back to default capture mask, as PEX DMA is not supported\n"); 36262306a36Sopenharmony_ci ha->fw_dump_capture_mask = capture_debug_level; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci md_hdr->driver_capture_mask = ha->fw_dump_capture_mask; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Minimum num of entries = %d\n", 36862306a36Sopenharmony_ci md_hdr->num_of_entries)); 36962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Dump template size = %d\n", 37062306a36Sopenharmony_ci ha->fw_dump_tmplt_size)); 37162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Selected Capture mask =0x%x\n", 37262306a36Sopenharmony_ci ha->fw_dump_capture_mask)); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Calculate fw_dump_size */ 37562306a36Sopenharmony_ci for (hdr_entry_bit = 0x2, k = 1; (hdr_entry_bit & 0xFF); 37662306a36Sopenharmony_ci hdr_entry_bit <<= 1, k++) { 37762306a36Sopenharmony_ci if (hdr_entry_bit & ha->fw_dump_capture_mask) 37862306a36Sopenharmony_ci ha->fw_dump_size += md_hdr->capture_size_array[k]; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci /* Total firmware dump size including command header */ 38262306a36Sopenharmony_ci ha->fw_dump_size += ha->fw_dump_tmplt_size; 38362306a36Sopenharmony_ci ha->fw_dump = vmalloc(ha->fw_dump_size); 38462306a36Sopenharmony_ci if (!ha->fw_dump) 38562306a36Sopenharmony_ci goto alloc_cleanup; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 38862306a36Sopenharmony_ci "Minidump Template Size = 0x%x KB\n", 38962306a36Sopenharmony_ci ha->fw_dump_tmplt_size)); 39062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 39162306a36Sopenharmony_ci "Total Minidump size = 0x%x KB\n", ha->fw_dump_size)); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci memcpy(ha->fw_dump, md_tmp, ha->fw_dump_tmplt_size); 39462306a36Sopenharmony_ci ha->fw_dump_tmplt_hdr = ha->fw_dump; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cialloc_cleanup: 39762306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, ha->fw_dump_tmplt_size, 39862306a36Sopenharmony_ci md_tmp, md_tmp_dma); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int qla4xxx_fw_ready(struct scsi_qla_host *ha) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci uint32_t timeout_count; 40462306a36Sopenharmony_ci int ready = 0; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Waiting for Firmware Ready..\n")); 40762306a36Sopenharmony_ci for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0; 40862306a36Sopenharmony_ci timeout_count--) { 40962306a36Sopenharmony_ci if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) 41062306a36Sopenharmony_ci qla4xxx_get_dhcp_ip_address(ha); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* Get firmware state. */ 41362306a36Sopenharmony_ci if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) { 41462306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: unable to get firmware " 41562306a36Sopenharmony_ci "state\n", ha->host_no, __func__)); 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (ha->firmware_state & FW_STATE_ERROR) { 42062306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: an unrecoverable error has" 42162306a36Sopenharmony_ci " occurred\n", ha->host_no, __func__)); 42262306a36Sopenharmony_ci break; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci if (ha->firmware_state & FW_STATE_CONFIG_WAIT) { 42662306a36Sopenharmony_ci /* 42762306a36Sopenharmony_ci * The firmware has not yet been issued an Initialize 42862306a36Sopenharmony_ci * Firmware command, so issue it now. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* Go back and test for ready state - no wait. */ 43462306a36Sopenharmony_ci continue; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { 43862306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" 43962306a36Sopenharmony_ci "AUTOCONNECT in progress\n", 44062306a36Sopenharmony_ci ha->host_no, __func__)); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { 44462306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" 44562306a36Sopenharmony_ci " CONFIGURING IP\n", 44662306a36Sopenharmony_ci ha->host_no, __func__)); 44762306a36Sopenharmony_ci /* 44862306a36Sopenharmony_ci * Check for link state after 15 secs and if link is 44962306a36Sopenharmony_ci * still DOWN then, cable is unplugged. Ignore "DHCP 45062306a36Sopenharmony_ci * in Progress/CONFIGURING IP" bit to check if firmware 45162306a36Sopenharmony_ci * is in ready state or not after 15 secs. 45262306a36Sopenharmony_ci * This is applicable for both 2.x & 3.x firmware 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci if (timeout_count <= (ADAPTER_INIT_TOV - 15)) { 45562306a36Sopenharmony_ci if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) { 45662306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s:" 45762306a36Sopenharmony_ci " LINK UP (Cable plugged)\n", 45862306a36Sopenharmony_ci ha->host_no, __func__)); 45962306a36Sopenharmony_ci } else if (ha->firmware_state & 46062306a36Sopenharmony_ci (FW_STATE_CONFIGURING_IP | 46162306a36Sopenharmony_ci FW_STATE_READY)) { 46262306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: " 46362306a36Sopenharmony_ci "LINK DOWN (Cable unplugged)\n", 46462306a36Sopenharmony_ci ha->host_no, __func__)); 46562306a36Sopenharmony_ci ha->firmware_state = FW_STATE_READY; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (ha->firmware_state == FW_STATE_READY) { 47162306a36Sopenharmony_ci /* If DHCP IP Addr is available, retrieve it now. */ 47262306a36Sopenharmony_ci if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, 47362306a36Sopenharmony_ci &ha->dpc_flags)) 47462306a36Sopenharmony_ci qla4xxx_get_dhcp_ip_address(ha); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (!qla4xxx_wait_for_ip_config(ha) || 47762306a36Sopenharmony_ci timeout_count == 1) { 47862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 47962306a36Sopenharmony_ci "Firmware Ready..\n")); 48062306a36Sopenharmony_ci /* The firmware is ready to process SCSI 48162306a36Sopenharmony_ci commands. */ 48262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 48362306a36Sopenharmony_ci "scsi%ld: %s: MEDIA TYPE" 48462306a36Sopenharmony_ci " - %s\n", ha->host_no, 48562306a36Sopenharmony_ci __func__, (ha->addl_fw_state & 48662306a36Sopenharmony_ci FW_ADDSTATE_OPTICAL_MEDIA) 48762306a36Sopenharmony_ci != 0 ? "OPTICAL" : "COPPER")); 48862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 48962306a36Sopenharmony_ci "scsi%ld: %s: DHCPv4 STATE" 49062306a36Sopenharmony_ci " Enabled %s\n", ha->host_no, 49162306a36Sopenharmony_ci __func__, (ha->addl_fw_state & 49262306a36Sopenharmony_ci FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? 49362306a36Sopenharmony_ci "YES" : "NO")); 49462306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 49562306a36Sopenharmony_ci "scsi%ld: %s: LINK %s\n", 49662306a36Sopenharmony_ci ha->host_no, __func__, 49762306a36Sopenharmony_ci (ha->addl_fw_state & 49862306a36Sopenharmony_ci FW_ADDSTATE_LINK_UP) != 0 ? 49962306a36Sopenharmony_ci "UP" : "DOWN")); 50062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 50162306a36Sopenharmony_ci "scsi%ld: %s: iSNS Service " 50262306a36Sopenharmony_ci "Started %s\n", 50362306a36Sopenharmony_ci ha->host_no, __func__, 50462306a36Sopenharmony_ci (ha->addl_fw_state & 50562306a36Sopenharmony_ci FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? 50662306a36Sopenharmony_ci "YES" : "NO")); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ready = 1; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " 51362306a36Sopenharmony_ci "seconds expired= %d\n", ha->host_no, __func__, 51462306a36Sopenharmony_ci ha->firmware_state, ha->addl_fw_state, 51562306a36Sopenharmony_ci timeout_count)); 51662306a36Sopenharmony_ci if (is_qla4032(ha) && 51762306a36Sopenharmony_ci !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && 51862306a36Sopenharmony_ci (timeout_count < ADAPTER_INIT_TOV - 5)) { 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci msleep(1000); 52362306a36Sopenharmony_ci } /* end of for */ 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci if (timeout_count <= 0) 52662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", 52762306a36Sopenharmony_ci ha->host_no, __func__)); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { 53062306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting " 53162306a36Sopenharmony_ci "it's waiting to configure an IP address\n", 53262306a36Sopenharmony_ci ha->host_no, __func__)); 53362306a36Sopenharmony_ci ready = 1; 53462306a36Sopenharmony_ci } else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { 53562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: FW initialized, but " 53662306a36Sopenharmony_ci "auto-discovery still in process\n", 53762306a36Sopenharmony_ci ha->host_no, __func__)); 53862306a36Sopenharmony_ci ready = 1; 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return ready; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci/** 54562306a36Sopenharmony_ci * qla4xxx_init_firmware - initializes the firmware. 54662306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci **/ 54962306a36Sopenharmony_cistatic int qla4xxx_init_firmware(struct scsi_qla_host *ha) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci int status = QLA_ERROR; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (is_aer_supported(ha) && 55462306a36Sopenharmony_ci test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) 55562306a36Sopenharmony_ci return status; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* For 82xx, stop firmware before initializing because if BIOS 55862306a36Sopenharmony_ci * has previously initialized firmware, then driver's initialize 55962306a36Sopenharmony_ci * firmware will fail. */ 56062306a36Sopenharmony_ci if (is_qla80XX(ha)) 56162306a36Sopenharmony_ci qla4_8xxx_stop_firmware(ha); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); 56462306a36Sopenharmony_ci if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) { 56562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware " 56662306a36Sopenharmony_ci "control block\n", ha->host_no, __func__)); 56762306a36Sopenharmony_ci return status; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (!qla4xxx_fw_ready(ha)) 57162306a36Sopenharmony_ci return status; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (is_qla80XX(ha) && !test_bit(AF_INIT_DONE, &ha->flags)) 57462306a36Sopenharmony_ci qla4xxx_alloc_fw_dump(ha); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci return qla4xxx_get_firmware_status(ha); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void qla4xxx_set_model_info(struct scsi_qla_host *ha) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci uint16_t board_id_string[8]; 58262306a36Sopenharmony_ci int i; 58362306a36Sopenharmony_ci int size = sizeof(ha->nvram->isp4022.boardIdStr); 58462306a36Sopenharmony_ci int offset = offsetof(struct eeprom_data, isp4022.boardIdStr) / 2; 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci for (i = 0; i < (size / 2) ; i++) { 58762306a36Sopenharmony_ci board_id_string[i] = rd_nvram_word(ha, offset); 58862306a36Sopenharmony_ci offset += 1; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci memcpy(ha->model_name, board_id_string, size); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic int qla4xxx_config_nvram(struct scsi_qla_host *ha) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci unsigned long flags; 59762306a36Sopenharmony_ci union external_hw_config_reg extHwConfig; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no, 60062306a36Sopenharmony_ci __func__)); 60162306a36Sopenharmony_ci if (ql4xxx_lock_flash(ha) != QLA_SUCCESS) 60262306a36Sopenharmony_ci return QLA_ERROR; 60362306a36Sopenharmony_ci if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) { 60462306a36Sopenharmony_ci ql4xxx_unlock_flash(ha); 60562306a36Sopenharmony_ci return QLA_ERROR; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* Get EEPRom Parameters from NVRAM and validate */ 60962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Configuring NVRAM ...\n"); 61062306a36Sopenharmony_ci if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) { 61162306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 61262306a36Sopenharmony_ci extHwConfig.Asuint32_t = 61362306a36Sopenharmony_ci rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha)); 61462306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 61562306a36Sopenharmony_ci } else { 61662306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 61762306a36Sopenharmony_ci "scsi%ld: %s: EEProm checksum invalid. " 61862306a36Sopenharmony_ci "Please update your EEPROM\n", ha->host_no, 61962306a36Sopenharmony_ci __func__); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* Attempt to set defaults */ 62262306a36Sopenharmony_ci if (is_qla4010(ha)) 62362306a36Sopenharmony_ci extHwConfig.Asuint32_t = 0x1912; 62462306a36Sopenharmony_ci else if (is_qla4022(ha) | is_qla4032(ha)) 62562306a36Sopenharmony_ci extHwConfig.Asuint32_t = 0x0023; 62662306a36Sopenharmony_ci else 62762306a36Sopenharmony_ci return QLA_ERROR; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (is_qla4022(ha) || is_qla4032(ha)) 63162306a36Sopenharmony_ci qla4xxx_set_model_info(ha); 63262306a36Sopenharmony_ci else 63362306a36Sopenharmony_ci strcpy(ha->model_name, "QLA4010"); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n", 63662306a36Sopenharmony_ci ha->host_no, __func__, extHwConfig.Asuint32_t)); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 63962306a36Sopenharmony_ci writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha)); 64062306a36Sopenharmony_ci readl(isp_ext_hw_conf(ha)); 64162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ql4xxx_unlock_nvram(ha); 64462306a36Sopenharmony_ci ql4xxx_unlock_flash(ha); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return QLA_SUCCESS; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/** 65062306a36Sopenharmony_ci * qla4_8xxx_pci_config() - Setup ISP82xx PCI configuration registers. 65162306a36Sopenharmony_ci * @ha: HA context 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_civoid qla4_8xxx_pci_config(struct scsi_qla_host *ha) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci pci_set_master(ha->pdev); 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_civoid qla4xxx_pci_config(struct scsi_qla_host *ha) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci uint16_t w; 66162306a36Sopenharmony_ci int status; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n"); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci pci_set_master(ha->pdev); 66662306a36Sopenharmony_ci status = pci_set_mwi(ha->pdev); 66762306a36Sopenharmony_ci if (status) 66862306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Failed to set MWI\n"); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* 67162306a36Sopenharmony_ci * We want to respect framework's setting of PCI configuration space 67262306a36Sopenharmony_ci * command register and also want to make sure that all bits of 67362306a36Sopenharmony_ci * interest to us are properly set in command register. 67462306a36Sopenharmony_ci */ 67562306a36Sopenharmony_ci pci_read_config_word(ha->pdev, PCI_COMMAND, &w); 67662306a36Sopenharmony_ci w |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; 67762306a36Sopenharmony_ci w &= ~PCI_COMMAND_INTX_DISABLE; 67862306a36Sopenharmony_ci pci_write_config_word(ha->pdev, PCI_COMMAND, w); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci int status = QLA_ERROR; 68462306a36Sopenharmony_ci unsigned long max_wait_time; 68562306a36Sopenharmony_ci unsigned long flags; 68662306a36Sopenharmony_ci uint32_t mbox_status; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Starting firmware ...\n"); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* 69162306a36Sopenharmony_ci * Start firmware from flash ROM 69262306a36Sopenharmony_ci * 69362306a36Sopenharmony_ci * WORKAROUND: Stuff a non-constant value that the firmware can 69462306a36Sopenharmony_ci * use as a seed for a random number generator in MB7 prior to 69562306a36Sopenharmony_ci * setting BOOT_ENABLE. Fixes problem where the TCP 69662306a36Sopenharmony_ci * connections use the same TCP ports after each reboot, 69762306a36Sopenharmony_ci * causing some connections to not get re-established. 69862306a36Sopenharmony_ci */ 69962306a36Sopenharmony_ci DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n", 70062306a36Sopenharmony_ci ha->host_no, __func__)); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 70362306a36Sopenharmony_ci writel(jiffies, &ha->reg->mailbox[7]); 70462306a36Sopenharmony_ci if (is_qla4022(ha) | is_qla4032(ha)) 70562306a36Sopenharmony_ci writel(set_rmask(NVR_WRITE_ENABLE), 70662306a36Sopenharmony_ci &ha->reg->u1.isp4022.nvram); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci writel(2, &ha->reg->mailbox[6]); 70962306a36Sopenharmony_ci readl(&ha->reg->mailbox[6]); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status); 71262306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 71362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* Wait for firmware to come UP. */ 71662306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: Wait up to %d seconds for " 71762306a36Sopenharmony_ci "boot firmware to complete...\n", 71862306a36Sopenharmony_ci ha->host_no, __func__, FIRMWARE_UP_TOV)); 71962306a36Sopenharmony_ci max_wait_time = jiffies + (FIRMWARE_UP_TOV * HZ); 72062306a36Sopenharmony_ci do { 72162306a36Sopenharmony_ci uint32_t ctrl_status; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 72462306a36Sopenharmony_ci ctrl_status = readw(&ha->reg->ctrl_status); 72562306a36Sopenharmony_ci mbox_status = readw(&ha->reg->mailbox[0]); 72662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR)) 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci if (mbox_status == MBOX_STS_COMMAND_COMPLETE) 73162306a36Sopenharmony_ci break; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot " 73462306a36Sopenharmony_ci "firmware to complete... ctrl_sts=0x%x, remaining=%ld\n", 73562306a36Sopenharmony_ci ha->host_no, __func__, ctrl_status, max_wait_time)); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci msleep_interruptible(250); 73862306a36Sopenharmony_ci } while (!time_after_eq(jiffies, max_wait_time)); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { 74162306a36Sopenharmony_ci DEBUG(printk(KERN_INFO "scsi%ld: %s: Firmware has started\n", 74262306a36Sopenharmony_ci ha->host_no, __func__)); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 74562306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), 74662306a36Sopenharmony_ci &ha->reg->ctrl_status); 74762306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 74862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci status = QLA_SUCCESS; 75162306a36Sopenharmony_ci } else { 75262306a36Sopenharmony_ci printk(KERN_INFO "scsi%ld: %s: Boot firmware failed " 75362306a36Sopenharmony_ci "- mbox status 0x%x\n", ha->host_no, __func__, 75462306a36Sopenharmony_ci mbox_status); 75562306a36Sopenharmony_ci status = QLA_ERROR; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci return status; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ciint ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci#define QL4_LOCK_DRVR_WAIT 60 76362306a36Sopenharmony_ci#define QL4_LOCK_DRVR_SLEEP 1 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci int drvr_wait = QL4_LOCK_DRVR_WAIT; 76662306a36Sopenharmony_ci while (drvr_wait) { 76762306a36Sopenharmony_ci if (ql4xxx_lock_drvr(a) == 0) { 76862306a36Sopenharmony_ci ssleep(QL4_LOCK_DRVR_SLEEP); 76962306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Waiting for " 77062306a36Sopenharmony_ci "Global Init Semaphore(%d)...\n", 77162306a36Sopenharmony_ci a->host_no, 77262306a36Sopenharmony_ci __func__, drvr_wait)); 77362306a36Sopenharmony_ci drvr_wait -= QL4_LOCK_DRVR_SLEEP; 77462306a36Sopenharmony_ci } else { 77562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " 77662306a36Sopenharmony_ci "acquired\n", a->host_no, __func__)); 77762306a36Sopenharmony_ci return QLA_SUCCESS; 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci return QLA_ERROR; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/** 78462306a36Sopenharmony_ci * qla4xxx_start_firmware - starts qla4xxx firmware 78562306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 78662306a36Sopenharmony_ci * 78762306a36Sopenharmony_ci * This routine performs the necessary steps to start the firmware for 78862306a36Sopenharmony_ci * the QLA4010 adapter. 78962306a36Sopenharmony_ci **/ 79062306a36Sopenharmony_ciint qla4xxx_start_firmware(struct scsi_qla_host *ha) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci unsigned long flags = 0; 79362306a36Sopenharmony_ci uint32_t mbox_status; 79462306a36Sopenharmony_ci int status = QLA_ERROR; 79562306a36Sopenharmony_ci int soft_reset = 1; 79662306a36Sopenharmony_ci int config_chip = 0; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci if (is_qla4022(ha) | is_qla4032(ha)) 79962306a36Sopenharmony_ci ql4xxx_set_mac_number(ha); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 80262306a36Sopenharmony_ci return QLA_ERROR; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no, 80762306a36Sopenharmony_ci __func__, readw(isp_port_ctrl(ha)))); 80862306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no, 80962306a36Sopenharmony_ci __func__, readw(isp_port_status(ha)))); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* Is Hardware already initialized? */ 81262306a36Sopenharmony_ci if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) { 81362306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: Hardware has already been " 81462306a36Sopenharmony_ci "initialized\n", ha->host_no, __func__)); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* Receive firmware boot acknowledgement */ 81762306a36Sopenharmony_ci mbox_status = readw(&ha->reg->mailbox[0]); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= " 82062306a36Sopenharmony_ci "0x%x\n", ha->host_no, __func__, mbox_status)); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* Is firmware already booted? */ 82362306a36Sopenharmony_ci if (mbox_status == 0) { 82462306a36Sopenharmony_ci /* F/W not running, must be config by net driver */ 82562306a36Sopenharmony_ci config_chip = 1; 82662306a36Sopenharmony_ci soft_reset = 0; 82762306a36Sopenharmony_ci } else { 82862306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), 82962306a36Sopenharmony_ci &ha->reg->ctrl_status); 83062306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 83162306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_COMPLETION_INTR), 83262306a36Sopenharmony_ci &ha->reg->ctrl_status); 83362306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 83462306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 83562306a36Sopenharmony_ci if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { 83662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Get firmware " 83762306a36Sopenharmony_ci "state -- state = 0x%x\n", 83862306a36Sopenharmony_ci ha->host_no, 83962306a36Sopenharmony_ci __func__, ha->firmware_state)); 84062306a36Sopenharmony_ci /* F/W is running */ 84162306a36Sopenharmony_ci if (ha->firmware_state & 84262306a36Sopenharmony_ci FW_STATE_CONFIG_WAIT) { 84362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Firmware " 84462306a36Sopenharmony_ci "in known state -- " 84562306a36Sopenharmony_ci "config and " 84662306a36Sopenharmony_ci "boot, state = 0x%x\n", 84762306a36Sopenharmony_ci ha->host_no, __func__, 84862306a36Sopenharmony_ci ha->firmware_state)); 84962306a36Sopenharmony_ci config_chip = 1; 85062306a36Sopenharmony_ci soft_reset = 0; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci } else { 85362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Firmware in " 85462306a36Sopenharmony_ci "unknown state -- resetting," 85562306a36Sopenharmony_ci " state = " 85662306a36Sopenharmony_ci "0x%x\n", ha->host_no, __func__, 85762306a36Sopenharmony_ci ha->firmware_state)); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci } else { 86262306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been " 86362306a36Sopenharmony_ci "started - resetting\n", ha->host_no, __func__)); 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ", 86862306a36Sopenharmony_ci ha->host_no, __func__, soft_reset, config_chip)); 86962306a36Sopenharmony_ci if (soft_reset) { 87062306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no, 87162306a36Sopenharmony_ci __func__)); 87262306a36Sopenharmony_ci status = qla4xxx_soft_reset(ha); /* NOTE: acquires drvr 87362306a36Sopenharmony_ci * lock again, but ok */ 87462306a36Sopenharmony_ci if (status == QLA_ERROR) { 87562306a36Sopenharmony_ci DEBUG(printk("scsi%d: %s: Soft Reset failed!\n", 87662306a36Sopenharmony_ci ha->host_no, __func__)); 87762306a36Sopenharmony_ci ql4xxx_unlock_drvr(ha); 87862306a36Sopenharmony_ci return QLA_ERROR; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci config_chip = 1; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* Reset clears the semaphore, so acquire again */ 88362306a36Sopenharmony_ci if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) 88462306a36Sopenharmony_ci return QLA_ERROR; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (config_chip) { 88862306a36Sopenharmony_ci if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS) 88962306a36Sopenharmony_ci status = qla4xxx_start_firmware_from_flash(ha); 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci ql4xxx_unlock_drvr(ha); 89362306a36Sopenharmony_ci if (status == QLA_SUCCESS) { 89462306a36Sopenharmony_ci if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags)) 89562306a36Sopenharmony_ci qla4xxx_get_crash_record(ha); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci qla4xxx_init_rings(ha); 89862306a36Sopenharmony_ci } else { 89962306a36Sopenharmony_ci DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n", 90062306a36Sopenharmony_ci ha->host_no, __func__)); 90162306a36Sopenharmony_ci } 90262306a36Sopenharmony_ci return status; 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci/** 90562306a36Sopenharmony_ci * qla4xxx_free_ddb_index - Free DDBs reserved by firmware 90662306a36Sopenharmony_ci * @ha: pointer to adapter structure 90762306a36Sopenharmony_ci * 90862306a36Sopenharmony_ci * Since firmware is not running in autoconnect mode the DDB indices should 90962306a36Sopenharmony_ci * be freed so that when login happens from user space there are free DDB 91062306a36Sopenharmony_ci * indices available. 91162306a36Sopenharmony_ci **/ 91262306a36Sopenharmony_civoid qla4xxx_free_ddb_index(struct scsi_qla_host *ha) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci int max_ddbs; 91562306a36Sopenharmony_ci int ret; 91662306a36Sopenharmony_ci uint32_t idx = 0, next_idx = 0; 91762306a36Sopenharmony_ci uint32_t state = 0, conn_err = 0; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : 92062306a36Sopenharmony_ci MAX_DEV_DB_ENTRIES; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci for (idx = 0; idx < max_ddbs; idx = next_idx) { 92362306a36Sopenharmony_ci ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, 92462306a36Sopenharmony_ci &next_idx, &state, &conn_err, 92562306a36Sopenharmony_ci NULL, NULL); 92662306a36Sopenharmony_ci if (ret == QLA_ERROR) { 92762306a36Sopenharmony_ci next_idx++; 92862306a36Sopenharmony_ci continue; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci if (state == DDB_DS_NO_CONNECTION_ACTIVE || 93162306a36Sopenharmony_ci state == DDB_DS_SESSION_FAILED) { 93262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 93362306a36Sopenharmony_ci "Freeing DDB index = 0x%x\n", idx)); 93462306a36Sopenharmony_ci ret = qla4xxx_clear_ddb_entry(ha, idx); 93562306a36Sopenharmony_ci if (ret == QLA_ERROR) 93662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 93762306a36Sopenharmony_ci "Unable to clear DDB index = " 93862306a36Sopenharmony_ci "0x%x\n", idx); 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci if (next_idx == 0) 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci/** 94662306a36Sopenharmony_ci * qla4xxx_initialize_adapter - initiailizes hba 94762306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 94862306a36Sopenharmony_ci * @is_reset: Is this init path or reset path 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * This routine parforms all of the steps necessary to initialize the adapter. 95162306a36Sopenharmony_ci * 95262306a36Sopenharmony_ci **/ 95362306a36Sopenharmony_ciint qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci int status = QLA_ERROR; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci ha->eeprom_cmd_data = 0; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n"); 96062306a36Sopenharmony_ci ha->isp_ops->pci_config(ha); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ha->isp_ops->disable_intrs(ha); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Initialize the Host adapter request/response queues and firmware */ 96562306a36Sopenharmony_ci if (ha->isp_ops->start_firmware(ha) == QLA_ERROR) 96662306a36Sopenharmony_ci goto exit_init_hba; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * For ISP83XX, mailbox and IOCB interrupts are enabled separately. 97062306a36Sopenharmony_ci * Mailbox interrupts must be enabled prior to issuing any mailbox 97162306a36Sopenharmony_ci * command in order to prevent the possibility of losing interrupts 97262306a36Sopenharmony_ci * while switching from polling to interrupt mode. IOCB interrupts are 97362306a36Sopenharmony_ci * enabled via isp_ops->enable_intrs. 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) 97662306a36Sopenharmony_ci qla4_83xx_enable_mbox_intrs(ha); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (qla4xxx_about_firmware(ha) == QLA_ERROR) 97962306a36Sopenharmony_ci goto exit_init_hba; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR) 98262306a36Sopenharmony_ci goto exit_init_hba; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci qla4xxx_init_local_data(ha); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci status = qla4xxx_init_firmware(ha); 98762306a36Sopenharmony_ci if (status == QLA_ERROR) 98862306a36Sopenharmony_ci goto exit_init_hba; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci if (is_reset == RESET_ADAPTER) 99162306a36Sopenharmony_ci qla4xxx_build_ddb_list(ha, is_reset); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci set_bit(AF_ONLINE, &ha->flags); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ciexit_init_hba: 99662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no, 99762306a36Sopenharmony_ci status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); 99862306a36Sopenharmony_ci return status; 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ciint qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, 100262306a36Sopenharmony_ci struct ddb_entry *ddb_entry, uint32_t state) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci uint32_t old_fw_ddb_device_state; 100562306a36Sopenharmony_ci int status = QLA_ERROR; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; 100862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 100962306a36Sopenharmony_ci "%s: DDB - old state = 0x%x, new state = 0x%x for " 101062306a36Sopenharmony_ci "index [%d]\n", __func__, 101162306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = state; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci switch (old_fw_ddb_device_state) { 101662306a36Sopenharmony_ci case DDB_DS_LOGIN_IN_PROCESS: 101762306a36Sopenharmony_ci switch (state) { 101862306a36Sopenharmony_ci case DDB_DS_SESSION_ACTIVE: 101962306a36Sopenharmony_ci case DDB_DS_DISCOVERY: 102062306a36Sopenharmony_ci qla4xxx_update_session_conn_param(ha, ddb_entry); 102162306a36Sopenharmony_ci ddb_entry->unblock_sess(ddb_entry->sess); 102262306a36Sopenharmony_ci status = QLA_SUCCESS; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 102562306a36Sopenharmony_ci case DDB_DS_NO_CONNECTION_ACTIVE: 102662306a36Sopenharmony_ci iscsi_conn_login_event(ddb_entry->conn, 102762306a36Sopenharmony_ci ISCSI_CONN_STATE_FREE); 102862306a36Sopenharmony_ci status = QLA_SUCCESS; 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci case DDB_DS_SESSION_ACTIVE: 103362306a36Sopenharmony_ci case DDB_DS_DISCOVERY: 103462306a36Sopenharmony_ci switch (state) { 103562306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 103662306a36Sopenharmony_ci /* 103762306a36Sopenharmony_ci * iscsi_session failure will cause userspace to 103862306a36Sopenharmony_ci * stop the connection which in turn would block the 103962306a36Sopenharmony_ci * iscsi_session and start relogin 104062306a36Sopenharmony_ci */ 104162306a36Sopenharmony_ci iscsi_session_failure(ddb_entry->sess->dd_data, 104262306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 104362306a36Sopenharmony_ci status = QLA_SUCCESS; 104462306a36Sopenharmony_ci break; 104562306a36Sopenharmony_ci case DDB_DS_NO_CONNECTION_ACTIVE: 104662306a36Sopenharmony_ci clear_bit(fw_ddb_index, ha->ddb_idx_map); 104762306a36Sopenharmony_ci status = QLA_SUCCESS; 104862306a36Sopenharmony_ci break; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci break; 105162306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 105262306a36Sopenharmony_ci switch (state) { 105362306a36Sopenharmony_ci case DDB_DS_SESSION_ACTIVE: 105462306a36Sopenharmony_ci case DDB_DS_DISCOVERY: 105562306a36Sopenharmony_ci ddb_entry->unblock_sess(ddb_entry->sess); 105662306a36Sopenharmony_ci qla4xxx_update_session_conn_param(ha, ddb_entry); 105762306a36Sopenharmony_ci status = QLA_SUCCESS; 105862306a36Sopenharmony_ci break; 105962306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 106062306a36Sopenharmony_ci iscsi_session_failure(ddb_entry->sess->dd_data, 106162306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 106262306a36Sopenharmony_ci status = QLA_SUCCESS; 106362306a36Sopenharmony_ci break; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci default: 106762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", 106862306a36Sopenharmony_ci __func__)); 106962306a36Sopenharmony_ci break; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci return status; 107262306a36Sopenharmony_ci} 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_civoid qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci /* 107762306a36Sopenharmony_ci * This triggers a relogin. After the relogin_timer 107862306a36Sopenharmony_ci * expires, the relogin gets scheduled. We must wait a 107962306a36Sopenharmony_ci * minimum amount of time since receiving an 0x8014 AEN 108062306a36Sopenharmony_ci * with failed device_state or a logout response before 108162306a36Sopenharmony_ci * we can issue another relogin. 108262306a36Sopenharmony_ci * 108362306a36Sopenharmony_ci * Firmware pads this timeout: (time2wait +1). 108462306a36Sopenharmony_ci * Driver retry to login should be longer than F/W. 108562306a36Sopenharmony_ci * Otherwise F/W will fail 108662306a36Sopenharmony_ci * set_ddb() mbx cmd with 0x4005 since it still 108762306a36Sopenharmony_ci * counting down its time2wait. 108862306a36Sopenharmony_ci */ 108962306a36Sopenharmony_ci atomic_set(&ddb_entry->relogin_timer, 0); 109062306a36Sopenharmony_ci atomic_set(&ddb_entry->retry_relogin_timer, 109162306a36Sopenharmony_ci ddb_entry->default_time2wait + 4); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ciint qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, 109662306a36Sopenharmony_ci struct ddb_entry *ddb_entry, uint32_t state) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci uint32_t old_fw_ddb_device_state; 109962306a36Sopenharmony_ci int status = QLA_ERROR; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; 110262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 110362306a36Sopenharmony_ci "%s: DDB - old state = 0x%x, new state = 0x%x for " 110462306a36Sopenharmony_ci "index [%d]\n", __func__, 110562306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = state; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci switch (old_fw_ddb_device_state) { 111062306a36Sopenharmony_ci case DDB_DS_LOGIN_IN_PROCESS: 111162306a36Sopenharmony_ci case DDB_DS_NO_CONNECTION_ACTIVE: 111262306a36Sopenharmony_ci switch (state) { 111362306a36Sopenharmony_ci case DDB_DS_SESSION_ACTIVE: 111462306a36Sopenharmony_ci ddb_entry->unblock_sess(ddb_entry->sess); 111562306a36Sopenharmony_ci qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); 111662306a36Sopenharmony_ci status = QLA_SUCCESS; 111762306a36Sopenharmony_ci break; 111862306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 111962306a36Sopenharmony_ci iscsi_block_session(ddb_entry->sess); 112062306a36Sopenharmony_ci if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) 112162306a36Sopenharmony_ci qla4xxx_arm_relogin_timer(ddb_entry); 112262306a36Sopenharmony_ci status = QLA_SUCCESS; 112362306a36Sopenharmony_ci break; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci break; 112662306a36Sopenharmony_ci case DDB_DS_SESSION_ACTIVE: 112762306a36Sopenharmony_ci switch (state) { 112862306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 112962306a36Sopenharmony_ci iscsi_block_session(ddb_entry->sess); 113062306a36Sopenharmony_ci if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) 113162306a36Sopenharmony_ci qla4xxx_arm_relogin_timer(ddb_entry); 113262306a36Sopenharmony_ci status = QLA_SUCCESS; 113362306a36Sopenharmony_ci break; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 113762306a36Sopenharmony_ci switch (state) { 113862306a36Sopenharmony_ci case DDB_DS_SESSION_ACTIVE: 113962306a36Sopenharmony_ci ddb_entry->unblock_sess(ddb_entry->sess); 114062306a36Sopenharmony_ci qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); 114162306a36Sopenharmony_ci status = QLA_SUCCESS; 114262306a36Sopenharmony_ci break; 114362306a36Sopenharmony_ci case DDB_DS_SESSION_FAILED: 114462306a36Sopenharmony_ci if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) 114562306a36Sopenharmony_ci qla4xxx_arm_relogin_timer(ddb_entry); 114662306a36Sopenharmony_ci status = QLA_SUCCESS; 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci break; 115062306a36Sopenharmony_ci default: 115162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", 115262306a36Sopenharmony_ci __func__)); 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci return status; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci/** 115962306a36Sopenharmony_ci * qla4xxx_process_ddb_changed - process ddb state change 116062306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 116162306a36Sopenharmony_ci * @fw_ddb_index: Firmware's device database index 116262306a36Sopenharmony_ci * @state: Device state 116362306a36Sopenharmony_ci * @conn_err: Unused 116462306a36Sopenharmony_ci * 116562306a36Sopenharmony_ci * This routine processes a Decive Database Changed AEN Event. 116662306a36Sopenharmony_ci **/ 116762306a36Sopenharmony_ciint qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, 116862306a36Sopenharmony_ci uint32_t fw_ddb_index, 116962306a36Sopenharmony_ci uint32_t state, uint32_t conn_err) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci /* check for out of range index */ 117462306a36Sopenharmony_ci if (fw_ddb_index >= MAX_DDB_ENTRIES) 117562306a36Sopenharmony_ci goto exit_ddb_event; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* Get the corresponging ddb entry */ 117862306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); 117962306a36Sopenharmony_ci /* Device does not currently exist in our database. */ 118062306a36Sopenharmony_ci if (ddb_entry == NULL) { 118162306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", 118262306a36Sopenharmony_ci __func__, fw_ddb_index); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (state == DDB_DS_NO_CONNECTION_ACTIVE) 118562306a36Sopenharmony_ci clear_bit(fw_ddb_index, ha->ddb_idx_map); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci goto exit_ddb_event; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ciexit_ddb_event: 119362306a36Sopenharmony_ci return QLA_ERROR; 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci/** 119762306a36Sopenharmony_ci * qla4xxx_login_flash_ddb - Login to target (DDB) 119862306a36Sopenharmony_ci * @cls_session: Pointer to the session to login 119962306a36Sopenharmony_ci * 120062306a36Sopenharmony_ci * This routine logins to the target. 120162306a36Sopenharmony_ci * Issues setddb and conn open mbx 120262306a36Sopenharmony_ci **/ 120362306a36Sopenharmony_civoid qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci struct iscsi_session *sess; 120662306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 120762306a36Sopenharmony_ci struct scsi_qla_host *ha; 120862306a36Sopenharmony_ci struct dev_db_entry *fw_ddb_entry = NULL; 120962306a36Sopenharmony_ci dma_addr_t fw_ddb_dma; 121062306a36Sopenharmony_ci uint32_t mbx_sts = 0; 121162306a36Sopenharmony_ci int ret; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci sess = cls_session->dd_data; 121462306a36Sopenharmony_ci ddb_entry = sess->dd_data; 121562306a36Sopenharmony_ci ha = ddb_entry->ha; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (!test_bit(AF_LINK_UP, &ha->flags)) 121862306a36Sopenharmony_ci return; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (ddb_entry->ddb_type != FLASH_DDB) { 122162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 122262306a36Sopenharmony_ci "Skipping login to non FLASH DB")); 122362306a36Sopenharmony_ci goto exit_login; 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, 122762306a36Sopenharmony_ci &fw_ddb_dma); 122862306a36Sopenharmony_ci if (fw_ddb_entry == NULL) { 122962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); 123062306a36Sopenharmony_ci goto exit_login; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { 123462306a36Sopenharmony_ci ret = qla4xxx_get_ddb_index(ha, &ddb_entry->fw_ddb_index); 123562306a36Sopenharmony_ci if (ret == QLA_ERROR) 123662306a36Sopenharmony_ci goto exit_login; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; 123962306a36Sopenharmony_ci ha->tot_ddbs++; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, 124362306a36Sopenharmony_ci sizeof(struct dev_db_entry)); 124462306a36Sopenharmony_ci ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci ret = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 124762306a36Sopenharmony_ci fw_ddb_dma, &mbx_sts); 124862306a36Sopenharmony_ci if (ret == QLA_ERROR) { 124962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n")); 125062306a36Sopenharmony_ci goto exit_login; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; 125462306a36Sopenharmony_ci ret = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); 125562306a36Sopenharmony_ci if (ret == QLA_ERROR) { 125662306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, 125762306a36Sopenharmony_ci sess->targetname); 125862306a36Sopenharmony_ci goto exit_login; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ciexit_login: 126262306a36Sopenharmony_ci if (fw_ddb_entry) 126362306a36Sopenharmony_ci dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 1266