18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * PMC-Sierra SPCv/ve 8088/8089 SAS/SATA based host adapters driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 PMC-Sierra, Inc., 58c2ecf20Sopenharmony_ci * All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer 148c2ecf20Sopenharmony_ci * substantially similar to the "NO WARRANTY" disclaimer below 158c2ecf20Sopenharmony_ci * ("Disclaimer") and any redistribution must be conditioned upon 168c2ecf20Sopenharmony_ci * including a substantially similar Disclaimer requirement for further 178c2ecf20Sopenharmony_ci * binary redistribution. 188c2ecf20Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names 198c2ecf20Sopenharmony_ci * of any contributors may be used to endorse or promote products derived 208c2ecf20Sopenharmony_ci * from this software without specific prior written permission. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 238c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free 248c2ecf20Sopenharmony_ci * Software Foundation. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * NO WARRANTY 278c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 288c2ecf20Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 298c2ecf20Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 308c2ecf20Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 318c2ecf20Sopenharmony_ci * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 328c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 338c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 348c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 358c2ecf20Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 368c2ecf20Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 378c2ecf20Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGES. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci #include <linux/slab.h> 418c2ecf20Sopenharmony_ci #include "pm8001_sas.h" 428c2ecf20Sopenharmony_ci #include "pm80xx_hwi.h" 438c2ecf20Sopenharmony_ci #include "pm8001_chips.h" 448c2ecf20Sopenharmony_ci #include "pm8001_ctl.h" 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define SMP_DIRECT 1 478c2ecf20Sopenharmony_ci#define SMP_INDIRECT 2 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciint pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci u32 reg_val; 538c2ecf20Sopenharmony_ci unsigned long start; 548c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, shift_value); 558c2ecf20Sopenharmony_ci /* confirm the setting is written */ 568c2ecf20Sopenharmony_ci start = jiffies + HZ; /* 1 sec */ 578c2ecf20Sopenharmony_ci do { 588c2ecf20Sopenharmony_ci reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER); 598c2ecf20Sopenharmony_ci } while ((reg_val != shift_value) && time_before(jiffies, start)); 608c2ecf20Sopenharmony_ci if (reg_val != shift_value) { 618c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MEMBASE_II_SHIFT_REGISTER = 0x%x\n", 628c2ecf20Sopenharmony_ci reg_val); 638c2ecf20Sopenharmony_ci return -1; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset, 698c2ecf20Sopenharmony_ci __le32 *destination, 708c2ecf20Sopenharmony_ci u32 dw_count, u32 bus_base_number) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci u32 index, value, offset; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (index = 0; index < dw_count; index += 4, destination++) { 758c2ecf20Sopenharmony_ci offset = (soffset + index); 768c2ecf20Sopenharmony_ci if (offset < (64 * 1024)) { 778c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, bus_base_number, offset); 788c2ecf20Sopenharmony_ci *destination = cpu_to_le32(value); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci return; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cissize_t pm80xx_get_fatal_dump(struct device *cdev, 858c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 888c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 898c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 908c2ecf20Sopenharmony_ci void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; 918c2ecf20Sopenharmony_ci u32 accum_len , reg_val, index, *temp; 928c2ecf20Sopenharmony_ci u32 status = 1; 938c2ecf20Sopenharmony_ci unsigned long start; 948c2ecf20Sopenharmony_ci u8 *direct_data; 958c2ecf20Sopenharmony_ci char *fatal_error_data = buf; 968c2ecf20Sopenharmony_ci u32 length_to_read; 978c2ecf20Sopenharmony_ci u32 offset; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data = buf; 1008c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 1018c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 1028c2ecf20Sopenharmony_ci sprintf(pm8001_ha->forensic_info.data_buf.direct_data, 1038c2ecf20Sopenharmony_ci "Not supported for SPC controller"); 1048c2ecf20Sopenharmony_ci return (char *)pm8001_ha->forensic_info.data_buf.direct_data - 1058c2ecf20Sopenharmony_ci (char *)buf; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci /* initialize variables for very first call from host application */ 1088c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { 1098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 1108c2ecf20Sopenharmony_ci "forensic_info TYPE_NON_FATAL..............\n"); 1118c2ecf20Sopenharmony_ci direct_data = (u8 *)fatal_error_data; 1128c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; 1138c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; 1148c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_offset = 0; 1158c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.read_len = 0; 1168c2ecf20Sopenharmony_ci pm8001_ha->forensic_preserved_accumulated_transfer = 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Write signature to fatal dump table */ 1198c2ecf20Sopenharmony_ci pm8001_mw32(fatal_table_address, 1208c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_SIGNATURE, 0x1234abcd); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data = direct_data; 1238c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "ossaHwCB: status1 %d\n", status); 1248c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "ossaHwCB: read_len 0x%x\n", 1258c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.read_len); 1268c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_len 0x%x\n", 1278c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len); 1288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_offset 0x%x\n", 1298c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_offset); 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { 1328c2ecf20Sopenharmony_ci /* start to get data */ 1338c2ecf20Sopenharmony_ci /* Program the MEMBASE II Shifting Register with 0x00.*/ 1348c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, 1358c2ecf20Sopenharmony_ci pm8001_ha->fatal_forensic_shift_offset); 1368c2ecf20Sopenharmony_ci pm8001_ha->forensic_last_offset = 0; 1378c2ecf20Sopenharmony_ci pm8001_ha->forensic_fatal_step = 0; 1388c2ecf20Sopenharmony_ci pm8001_ha->fatal_bar_loc = 0; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* Read until accum_len is retrived */ 1428c2ecf20Sopenharmony_ci accum_len = pm8001_mr32(fatal_table_address, 1438c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); 1448c2ecf20Sopenharmony_ci /* Determine length of data between previously stored transfer length 1458c2ecf20Sopenharmony_ci * and current accumulated transfer length 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci length_to_read = 1488c2ecf20Sopenharmony_ci accum_len - pm8001_ha->forensic_preserved_accumulated_transfer; 1498c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: accum_len 0x%x\n", 1508c2ecf20Sopenharmony_ci accum_len); 1518c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: length_to_read 0x%x\n", 1528c2ecf20Sopenharmony_ci length_to_read); 1538c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: last_offset 0x%x\n", 1548c2ecf20Sopenharmony_ci pm8001_ha->forensic_last_offset); 1558c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: read_len 0x%x\n", 1568c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.read_len); 1578c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_len 0x%x\n", 1588c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len); 1598c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_offset 0x%x\n", 1608c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_offset); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* If accumulated length failed to read correctly fail the attempt.*/ 1638c2ecf20Sopenharmony_ci if (accum_len == 0xFFFFFFFF) { 1648c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 1658c2ecf20Sopenharmony_ci "Possible PCI issue 0x%x not expected\n", 1668c2ecf20Sopenharmony_ci accum_len); 1678c2ecf20Sopenharmony_ci return status; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci /* If accumulated length is zero fail the attempt */ 1708c2ecf20Sopenharmony_ci if (accum_len == 0) { 1718c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 1728c2ecf20Sopenharmony_ci sprintf(pm8001_ha->forensic_info.data_buf.direct_data, 1738c2ecf20Sopenharmony_ci "%08x ", 0xFFFFFFFF); 1748c2ecf20Sopenharmony_ci return (char *)pm8001_ha->forensic_info.data_buf.direct_data - 1758c2ecf20Sopenharmony_ci (char *)buf; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci /* Accumulated length is good so start capturing the first data */ 1788c2ecf20Sopenharmony_ci temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; 1798c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_fatal_step == 0) { 1808c2ecf20Sopenharmony_cimoreData: 1818c2ecf20Sopenharmony_ci /* If data to read is less than SYSFS_OFFSET then reduce the 1828c2ecf20Sopenharmony_ci * length of dataLen 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_last_offset + SYSFS_OFFSET 1858c2ecf20Sopenharmony_ci > length_to_read) { 1868c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len = 1878c2ecf20Sopenharmony_ci length_to_read - 1888c2ecf20Sopenharmony_ci pm8001_ha->forensic_last_offset; 1898c2ecf20Sopenharmony_ci } else { 1908c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len = 1918c2ecf20Sopenharmony_ci SYSFS_OFFSET; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_info.data_buf.direct_data) { 1948c2ecf20Sopenharmony_ci /* Data is in bar, copy to host memory */ 1958c2ecf20Sopenharmony_ci pm80xx_pci_mem_copy(pm8001_ha, 1968c2ecf20Sopenharmony_ci pm8001_ha->fatal_bar_loc, 1978c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, 1988c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len, 1); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci pm8001_ha->fatal_bar_loc += 2018c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len; 2028c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_offset += 2038c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len; 2048c2ecf20Sopenharmony_ci pm8001_ha->forensic_last_offset += 2058c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len; 2068c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.read_len = 2078c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_last_offset >= length_to_read) { 2108c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 2118c2ecf20Sopenharmony_ci sprintf(pm8001_ha->forensic_info.data_buf.direct_data, 2128c2ecf20Sopenharmony_ci "%08x ", 3); 2138c2ecf20Sopenharmony_ci for (index = 0; index < 2148c2ecf20Sopenharmony_ci (pm8001_ha->forensic_info.data_buf.direct_len 2158c2ecf20Sopenharmony_ci / 4); index++) { 2168c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 2178c2ecf20Sopenharmony_ci sprintf( 2188c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data, 2198c2ecf20Sopenharmony_ci "%08x ", *(temp + index)); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci pm8001_ha->fatal_bar_loc = 0; 2238c2ecf20Sopenharmony_ci pm8001_ha->forensic_fatal_step = 1; 2248c2ecf20Sopenharmony_ci pm8001_ha->fatal_forensic_shift_offset = 0; 2258c2ecf20Sopenharmony_ci pm8001_ha->forensic_last_offset = 0; 2268c2ecf20Sopenharmony_ci status = 0; 2278c2ecf20Sopenharmony_ci offset = (int) 2288c2ecf20Sopenharmony_ci ((char *)pm8001_ha->forensic_info.data_buf.direct_data 2298c2ecf20Sopenharmony_ci - (char *)buf); 2308c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 2318c2ecf20Sopenharmony_ci "get_fatal_spcv:return1 0x%x\n", offset); 2328c2ecf20Sopenharmony_ci return (char *)pm8001_ha-> 2338c2ecf20Sopenharmony_ci forensic_info.data_buf.direct_data - 2348c2ecf20Sopenharmony_ci (char *)buf; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci if (pm8001_ha->fatal_bar_loc < (64 * 1024)) { 2378c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 2388c2ecf20Sopenharmony_ci sprintf(pm8001_ha-> 2398c2ecf20Sopenharmony_ci forensic_info.data_buf.direct_data, 2408c2ecf20Sopenharmony_ci "%08x ", 2); 2418c2ecf20Sopenharmony_ci for (index = 0; index < 2428c2ecf20Sopenharmony_ci (pm8001_ha->forensic_info.data_buf.direct_len 2438c2ecf20Sopenharmony_ci / 4); index++) { 2448c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data 2458c2ecf20Sopenharmony_ci += sprintf(pm8001_ha-> 2468c2ecf20Sopenharmony_ci forensic_info.data_buf.direct_data, 2478c2ecf20Sopenharmony_ci "%08x ", *(temp + index)); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci status = 0; 2508c2ecf20Sopenharmony_ci offset = (int) 2518c2ecf20Sopenharmony_ci ((char *)pm8001_ha->forensic_info.data_buf.direct_data 2528c2ecf20Sopenharmony_ci - (char *)buf); 2538c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 2548c2ecf20Sopenharmony_ci "get_fatal_spcv:return2 0x%x\n", offset); 2558c2ecf20Sopenharmony_ci return (char *)pm8001_ha-> 2568c2ecf20Sopenharmony_ci forensic_info.data_buf.direct_data - 2578c2ecf20Sopenharmony_ci (char *)buf; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* Increment the MEMBASE II Shifting Register value by 0x100.*/ 2618c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 2628c2ecf20Sopenharmony_ci sprintf(pm8001_ha->forensic_info.data_buf.direct_data, 2638c2ecf20Sopenharmony_ci "%08x ", 2); 2648c2ecf20Sopenharmony_ci for (index = 0; index < 2658c2ecf20Sopenharmony_ci (pm8001_ha->forensic_info.data_buf.direct_len 2668c2ecf20Sopenharmony_ci / 4) ; index++) { 2678c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 2688c2ecf20Sopenharmony_ci sprintf(pm8001_ha-> 2698c2ecf20Sopenharmony_ci forensic_info.data_buf.direct_data, 2708c2ecf20Sopenharmony_ci "%08x ", *(temp + index)); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci pm8001_ha->fatal_forensic_shift_offset += 0x100; 2738c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, 2748c2ecf20Sopenharmony_ci pm8001_ha->fatal_forensic_shift_offset); 2758c2ecf20Sopenharmony_ci pm8001_ha->fatal_bar_loc = 0; 2768c2ecf20Sopenharmony_ci status = 0; 2778c2ecf20Sopenharmony_ci offset = (int) 2788c2ecf20Sopenharmony_ci ((char *)pm8001_ha->forensic_info.data_buf.direct_data 2798c2ecf20Sopenharmony_ci - (char *)buf); 2808c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return3 0x%x\n", 2818c2ecf20Sopenharmony_ci offset); 2828c2ecf20Sopenharmony_ci return (char *)pm8001_ha->forensic_info.data_buf.direct_data - 2838c2ecf20Sopenharmony_ci (char *)buf; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci if (pm8001_ha->forensic_fatal_step == 1) { 2868c2ecf20Sopenharmony_ci /* store previous accumulated length before triggering next 2878c2ecf20Sopenharmony_ci * accumulated length update 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci pm8001_ha->forensic_preserved_accumulated_transfer = 2908c2ecf20Sopenharmony_ci pm8001_mr32(fatal_table_address, 2918c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* continue capturing the fatal log until Dump status is 0x3 */ 2948c2ecf20Sopenharmony_ci if (pm8001_mr32(fatal_table_address, 2958c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_STATUS) < 2968c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* reset fddstat bit by writing to zero*/ 2998c2ecf20Sopenharmony_ci pm8001_mw32(fatal_table_address, 3008c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_STATUS, 0x0); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* set dump control value to '1' so that new data will 3038c2ecf20Sopenharmony_ci * be transferred to shared memory 3048c2ecf20Sopenharmony_ci */ 3058c2ecf20Sopenharmony_ci pm8001_mw32(fatal_table_address, 3068c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 3078c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_HANDSHAKE_RDY); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci /*Poll FDDHSHK until clear */ 3108c2ecf20Sopenharmony_ci start = jiffies + (2 * HZ); /* 2 sec */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci do { 3138c2ecf20Sopenharmony_ci reg_val = pm8001_mr32(fatal_table_address, 3148c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_HANDSHAKE); 3158c2ecf20Sopenharmony_ci } while ((reg_val) && time_before(jiffies, start)); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (reg_val != 0) { 3188c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 3198c2ecf20Sopenharmony_ci "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n", 3208c2ecf20Sopenharmony_ci reg_val); 3218c2ecf20Sopenharmony_ci /* Fail the dump if a timeout occurs */ 3228c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 3238c2ecf20Sopenharmony_ci sprintf( 3248c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data, 3258c2ecf20Sopenharmony_ci "%08x ", 0xFFFFFFFF); 3268c2ecf20Sopenharmony_ci return((char *) 3278c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data 3288c2ecf20Sopenharmony_ci - (char *)buf); 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci /* Poll status register until set to 2 or 3318c2ecf20Sopenharmony_ci * 3 for up to 2 seconds 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_ci start = jiffies + (2 * HZ); /* 2 sec */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci do { 3368c2ecf20Sopenharmony_ci reg_val = pm8001_mr32(fatal_table_address, 3378c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_STATUS); 3388c2ecf20Sopenharmony_ci } while (((reg_val != 2) && (reg_val != 3)) && 3398c2ecf20Sopenharmony_ci time_before(jiffies, start)); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (reg_val < 2) { 3428c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 3438c2ecf20Sopenharmony_ci "TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n", 3448c2ecf20Sopenharmony_ci reg_val); 3458c2ecf20Sopenharmony_ci /* Fail the dump if a timeout occurs */ 3468c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 3478c2ecf20Sopenharmony_ci sprintf( 3488c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data, 3498c2ecf20Sopenharmony_ci "%08x ", 0xFFFFFFFF); 3508c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, 3518c2ecf20Sopenharmony_ci MEMBASE_II_SHIFT_REGISTER, 3528c2ecf20Sopenharmony_ci pm8001_ha->fatal_forensic_shift_offset); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci /* Read the next block of the debug data.*/ 3558c2ecf20Sopenharmony_ci length_to_read = pm8001_mr32(fatal_table_address, 3568c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_ACCUM_LEN) - 3578c2ecf20Sopenharmony_ci pm8001_ha->forensic_preserved_accumulated_transfer; 3588c2ecf20Sopenharmony_ci if (length_to_read != 0x0) { 3598c2ecf20Sopenharmony_ci pm8001_ha->forensic_fatal_step = 0; 3608c2ecf20Sopenharmony_ci goto moreData; 3618c2ecf20Sopenharmony_ci } else { 3628c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data += 3638c2ecf20Sopenharmony_ci sprintf( 3648c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_data, 3658c2ecf20Sopenharmony_ci "%08x ", 4); 3668c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.read_len 3678c2ecf20Sopenharmony_ci = 0xFFFFFFFF; 3688c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_len 3698c2ecf20Sopenharmony_ci = 0; 3708c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.direct_offset 3718c2ecf20Sopenharmony_ci = 0; 3728c2ecf20Sopenharmony_ci pm8001_ha->forensic_info.data_buf.read_len = 0; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data 3778c2ecf20Sopenharmony_ci - (char *)buf); 3788c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return4 0x%x\n", offset); 3798c2ecf20Sopenharmony_ci return (char *)pm8001_ha->forensic_info.data_buf.direct_data - 3808c2ecf20Sopenharmony_ci (char *)buf; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci/* pm80xx_get_non_fatal_dump - dump the nonfatal data from the dma 3848c2ecf20Sopenharmony_ci * location by the firmware. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_cissize_t pm80xx_get_non_fatal_dump(struct device *cdev, 3878c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 3908c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 3918c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 3928c2ecf20Sopenharmony_ci void __iomem *nonfatal_table_address = pm8001_ha->fatal_tbl_addr; 3938c2ecf20Sopenharmony_ci u32 accum_len = 0; 3948c2ecf20Sopenharmony_ci u32 total_len = 0; 3958c2ecf20Sopenharmony_ci u32 reg_val = 0; 3968c2ecf20Sopenharmony_ci u32 *temp = NULL; 3978c2ecf20Sopenharmony_ci u32 index = 0; 3988c2ecf20Sopenharmony_ci u32 output_length; 3998c2ecf20Sopenharmony_ci unsigned long start = 0; 4008c2ecf20Sopenharmony_ci char *buf_copy = buf; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; 4038c2ecf20Sopenharmony_ci if (++pm8001_ha->non_fatal_count == 1) { 4048c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 4058c2ecf20Sopenharmony_ci snprintf(pm8001_ha->forensic_info.data_buf.direct_data, 4068c2ecf20Sopenharmony_ci PAGE_SIZE, "Not supported for SPC controller"); 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "forensic_info TYPE_NON_FATAL...\n"); 4108c2ecf20Sopenharmony_ci /* 4118c2ecf20Sopenharmony_ci * Step 1: Write the host buffer parameters in the MPI Fatal and 4128c2ecf20Sopenharmony_ci * Non-Fatal Error Dump Capture Table.This is the buffer 4138c2ecf20Sopenharmony_ci * where debug data will be DMAed to. 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_ci pm8001_mw32(nonfatal_table_address, 4168c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_LO_OFFSET, 4178c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_lo); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci pm8001_mw32(nonfatal_table_address, 4208c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_HI_OFFSET, 4218c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_hi); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci pm8001_mw32(nonfatal_table_address, 4248c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_LENGTH, SYSFS_OFFSET); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Optionally, set the DUMPCTRL bit to 1 if the host 4278c2ecf20Sopenharmony_ci * keeps sending active I/Os while capturing the non-fatal 4288c2ecf20Sopenharmony_ci * debug data. Otherwise, leave this bit set to zero 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci pm8001_mw32(nonfatal_table_address, 4318c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* 4348c2ecf20Sopenharmony_ci * Step 2: Clear Accumulative Length of Debug Data Transferred 4358c2ecf20Sopenharmony_ci * [ACCDDLEN] field in the MPI Fatal and Non-Fatal Error Dump 4368c2ecf20Sopenharmony_ci * Capture Table to zero. 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci pm8001_mw32(nonfatal_table_address, 4398c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_ACCUM_LEN, 0); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* initiallize previous accumulated length to 0 */ 4428c2ecf20Sopenharmony_ci pm8001_ha->forensic_preserved_accumulated_transfer = 0; 4438c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_read_length = 0; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci total_len = pm8001_mr32(nonfatal_table_address, 4478c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_TOTAL_LEN); 4488c2ecf20Sopenharmony_ci /* 4498c2ecf20Sopenharmony_ci * Step 3:Clear Fatal/Non-Fatal Debug Data Transfer Status [FDDTSTAT] 4508c2ecf20Sopenharmony_ci * field and then request that the SPCv controller transfer the debug 4518c2ecf20Sopenharmony_ci * data by setting bit 7 of the Inbound Doorbell Set Register. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci pm8001_mw32(nonfatal_table_address, MPI_FATAL_EDUMP_TABLE_STATUS, 0); 4548c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, 4558c2ecf20Sopenharmony_ci SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* 4588c2ecf20Sopenharmony_ci * Step 4.1: Read back the Inbound Doorbell Set Register (by polling for 4598c2ecf20Sopenharmony_ci * 2 seconds) until register bit 7 is cleared. 4608c2ecf20Sopenharmony_ci * This step only indicates the request is accepted by the controller. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_ci start = jiffies + (2 * HZ); /* 2 sec */ 4638c2ecf20Sopenharmony_ci do { 4648c2ecf20Sopenharmony_ci reg_val = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET) & 4658c2ecf20Sopenharmony_ci SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP; 4668c2ecf20Sopenharmony_ci } while ((reg_val != 0) && time_before(jiffies, start)); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Step 4.2: To check the completion of the transfer, poll the Fatal/Non 4698c2ecf20Sopenharmony_ci * Fatal Debug Data Transfer Status [FDDTSTAT] field for 2 seconds in 4708c2ecf20Sopenharmony_ci * the MPI Fatal and Non-Fatal Error Dump Capture Table. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci start = jiffies + (2 * HZ); /* 2 sec */ 4738c2ecf20Sopenharmony_ci do { 4748c2ecf20Sopenharmony_ci reg_val = pm8001_mr32(nonfatal_table_address, 4758c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_STATUS); 4768c2ecf20Sopenharmony_ci } while ((!reg_val) && time_before(jiffies, start)); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if ((reg_val == 0x00) || 4798c2ecf20Sopenharmony_ci (reg_val == MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED) || 4808c2ecf20Sopenharmony_ci (reg_val > MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE)) { 4818c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_read_length = 0; 4828c2ecf20Sopenharmony_ci buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 0xFFFFFFFF); 4838c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_count = 0; 4848c2ecf20Sopenharmony_ci return (buf_copy - buf); 4858c2ecf20Sopenharmony_ci } else if (reg_val == 4868c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA) { 4878c2ecf20Sopenharmony_ci buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 2); 4888c2ecf20Sopenharmony_ci } else if ((reg_val == MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) || 4898c2ecf20Sopenharmony_ci (pm8001_ha->non_fatal_read_length >= total_len)) { 4908c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_read_length = 0; 4918c2ecf20Sopenharmony_ci buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 4); 4928c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_count = 0; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci accum_len = pm8001_mr32(nonfatal_table_address, 4958c2ecf20Sopenharmony_ci MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); 4968c2ecf20Sopenharmony_ci output_length = accum_len - 4978c2ecf20Sopenharmony_ci pm8001_ha->forensic_preserved_accumulated_transfer; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci for (index = 0; index < output_length/4; index++) 5008c2ecf20Sopenharmony_ci buf_copy += snprintf(buf_copy, PAGE_SIZE, 5018c2ecf20Sopenharmony_ci "%08x ", *(temp+index)); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_read_length += output_length; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* store current accumulated length to use in next iteration as 5068c2ecf20Sopenharmony_ci * the previous accumulated length 5078c2ecf20Sopenharmony_ci */ 5088c2ecf20Sopenharmony_ci pm8001_ha->forensic_preserved_accumulated_transfer = accum_len; 5098c2ecf20Sopenharmony_ci return (buf_copy - buf); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/** 5138c2ecf20Sopenharmony_ci * read_main_config_table - read the configure table and save it. 5148c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_cistatic void read_main_config_table(struct pm8001_hba_info *pm8001_ha) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->main_cfg_tbl_addr; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature = 5218c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_SIGNATURE_OFFSET); 5228c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev = 5238c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_INTERFACE_REVISION); 5248c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev = 5258c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_FW_REVISION); 5268c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io = 5278c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_MAX_OUTSTANDING_IO_OFFSET); 5288c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl = 5298c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_MAX_SGL_OFFSET); 5308c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag = 5318c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_CNTRL_CAP_OFFSET); 5328c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset = 5338c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_GST_OFFSET); 5348c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset = 5358c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_IBQ_OFFSET); 5368c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset = 5378c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_OBQ_OFFSET); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* read Error Dump Offset and Length */ 5408c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_offset0 = 5418c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_OFFSET); 5428c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_length0 = 5438c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_LENGTH); 5448c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_offset1 = 5458c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_OFFSET); 5468c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_length1 = 5478c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_LENGTH); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* read GPIO LED settings from the configuration table */ 5508c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping = 5518c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* read analog Setting offset from the configuration table */ 5548c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.analog_setup_table_offset = 5558c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_ANALOG_SETUP_OFFSET); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset = 5588c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_INT_VECTOR_TABLE_OFFSET); 5598c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset = 5608c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_SAS_PHY_ATTR_TABLE_OFFSET); 5618c2ecf20Sopenharmony_ci /* read port recover and reset timeout */ 5628c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer = 5638c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_PORT_RECOVERY_TIMER); 5648c2ecf20Sopenharmony_ci /* read ILA and inactive firmware version */ 5658c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version = 5668c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_MPI_ILA_RELEASE_TYPE); 5678c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version = 5688c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_MPI_INACTIVE_FW_VERSION); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 5718c2ecf20Sopenharmony_ci "Main cfg table: sign:%x interface rev:%x fw_rev:%x\n", 5728c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature, 5738c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev, 5748c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 5778c2ecf20Sopenharmony_ci "table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n", 5788c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset, 5798c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset, 5808c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset, 5818c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset, 5828c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 5858c2ecf20Sopenharmony_ci "Main cfg table; ila rev:%x Inactive fw rev:%x\n", 5868c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version, 5878c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version); 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/** 5918c2ecf20Sopenharmony_ci * read_general_status_table - read the general status table and save it. 5928c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_cistatic void read_general_status_table(struct pm8001_hba_info *pm8001_ha) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->general_stat_tbl_addr; 5978c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.gst_len_mpistate = 5988c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_GSTLEN_MPIS_OFFSET); 5998c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.iq_freeze_state0 = 6008c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_IQ_FREEZE_STATE0_OFFSET); 6018c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.iq_freeze_state1 = 6028c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_IQ_FREEZE_STATE1_OFFSET); 6038c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.msgu_tcnt = 6048c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_MSGUTCNT_OFFSET); 6058c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.iop_tcnt = 6068c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_IOPTCNT_OFFSET); 6078c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.gpio_input_val = 6088c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_GPIO_INPUT_VAL); 6098c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[0] = 6108c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET0); 6118c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[1] = 6128c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET1); 6138c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[2] = 6148c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET2); 6158c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[3] = 6168c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET3); 6178c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[4] = 6188c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET4); 6198c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[5] = 6208c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET5); 6218c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[6] = 6228c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET6); 6238c2ecf20Sopenharmony_ci pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[7] = 6248c2ecf20Sopenharmony_ci pm8001_mr32(address, GST_RERRINFO_OFFSET7); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci/** 6278c2ecf20Sopenharmony_ci * read_phy_attr_table - read the phy attribute table and save it. 6288c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_cistatic void read_phy_attr_table(struct pm8001_hba_info *pm8001_ha) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->pspa_q_tbl_addr; 6338c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[0] = 6348c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE0_OFFSET); 6358c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[1] = 6368c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE1_OFFSET); 6378c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[2] = 6388c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE2_OFFSET); 6398c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[3] = 6408c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE3_OFFSET); 6418c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[4] = 6428c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE4_OFFSET); 6438c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[5] = 6448c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE5_OFFSET); 6458c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[6] = 6468c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE6_OFFSET); 6478c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[7] = 6488c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE7_OFFSET); 6498c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[8] = 6508c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE8_OFFSET); 6518c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[9] = 6528c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE9_OFFSET); 6538c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[10] = 6548c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE10_OFFSET); 6558c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[11] = 6568c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE11_OFFSET); 6578c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[12] = 6588c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE12_OFFSET); 6598c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[13] = 6608c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE13_OFFSET); 6618c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[14] = 6628c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE14_OFFSET); 6638c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.phystart1_16[15] = 6648c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_PHYSTATE15_OFFSET); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[0] = 6678c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID0_OFFSET); 6688c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[1] = 6698c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID1_OFFSET); 6708c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[2] = 6718c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID2_OFFSET); 6728c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[3] = 6738c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID3_OFFSET); 6748c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[4] = 6758c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID4_OFFSET); 6768c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[5] = 6778c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID5_OFFSET); 6788c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[6] = 6798c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID6_OFFSET); 6808c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[7] = 6818c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID7_OFFSET); 6828c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[8] = 6838c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID8_OFFSET); 6848c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[9] = 6858c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID9_OFFSET); 6868c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[10] = 6878c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID10_OFFSET); 6888c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[11] = 6898c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID11_OFFSET); 6908c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[12] = 6918c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID12_OFFSET); 6928c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[13] = 6938c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID13_OFFSET); 6948c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[14] = 6958c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID14_OFFSET); 6968c2ecf20Sopenharmony_ci pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[15] = 6978c2ecf20Sopenharmony_ci pm8001_mr32(address, PSPA_OB_HW_EVENT_PID15_OFFSET); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci/** 7028c2ecf20Sopenharmony_ci * read_inbnd_queue_table - read the inbound queue table and save it. 7038c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_cistatic void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci int i; 7088c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->inbnd_q_tbl_addr; 7098c2ecf20Sopenharmony_ci for (i = 0; i < PM8001_MAX_INB_NUM; i++) { 7108c2ecf20Sopenharmony_ci u32 offset = i * 0x20; 7118c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].pi_pci_bar = 7128c2ecf20Sopenharmony_ci get_pci_bar_index(pm8001_mr32(address, 7138c2ecf20Sopenharmony_ci (offset + IB_PIPCI_BAR))); 7148c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].pi_offset = 7158c2ecf20Sopenharmony_ci pm8001_mr32(address, (offset + IB_PIPCI_BAR_OFFSET)); 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci/** 7208c2ecf20Sopenharmony_ci * read_outbnd_queue_table - read the outbound queue table and save it. 7218c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_cistatic void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci int i; 7268c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->outbnd_q_tbl_addr; 7278c2ecf20Sopenharmony_ci for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) { 7288c2ecf20Sopenharmony_ci u32 offset = i * 0x24; 7298c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].ci_pci_bar = 7308c2ecf20Sopenharmony_ci get_pci_bar_index(pm8001_mr32(address, 7318c2ecf20Sopenharmony_ci (offset + OB_CIPCI_BAR))); 7328c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].ci_offset = 7338c2ecf20Sopenharmony_ci pm8001_mr32(address, (offset + OB_CIPCI_BAR_OFFSET)); 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci/** 7388c2ecf20Sopenharmony_ci * init_default_table_values - init the default table. 7398c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 7408c2ecf20Sopenharmony_ci */ 7418c2ecf20Sopenharmony_cistatic void init_default_table_values(struct pm8001_hba_info *pm8001_ha) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci int i; 7448c2ecf20Sopenharmony_ci u32 offsetib, offsetob; 7458c2ecf20Sopenharmony_ci void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr; 7468c2ecf20Sopenharmony_ci void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr; 7478c2ecf20Sopenharmony_ci u32 ib_offset = pm8001_ha->ib_offset; 7488c2ecf20Sopenharmony_ci u32 ob_offset = pm8001_ha->ob_offset; 7498c2ecf20Sopenharmony_ci u32 ci_offset = pm8001_ha->ci_offset; 7508c2ecf20Sopenharmony_ci u32 pi_offset = pm8001_ha->pi_offset; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_event_log_addr = 7538c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[AAP1].phys_addr_hi; 7548c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_event_log_addr = 7558c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[AAP1].phys_addr_lo; 7568c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size = 7578c2ecf20Sopenharmony_ci PM8001_EVENT_LOG_SIZE; 7588c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_severity = 0x01; 7598c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_pcs_event_log_addr = 7608c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[IOP].phys_addr_hi; 7618c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_pcs_event_log_addr = 7628c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[IOP].phys_addr_lo; 7638c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size = 7648c2ecf20Sopenharmony_ci PM8001_EVENT_LOG_SIZE; 7658c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01; 7668c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci /* Enable higher IQs and OQs, 32 to 63, bit 16 */ 7698c2ecf20Sopenharmony_ci if (pm8001_ha->max_q_num > 32) 7708c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= 7718c2ecf20Sopenharmony_ci 1 << 16; 7728c2ecf20Sopenharmony_ci /* Disable end to end CRC checking */ 7738c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump = (0x1 << 16); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->max_q_num; i++) { 7768c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt = 7778c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30); 7788c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].upper_base_addr = 7798c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_hi; 7808c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].lower_base_addr = 7818c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_lo; 7828c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].base_virt = 7838c2ecf20Sopenharmony_ci (u8 *)pm8001_ha->memoryMap.region[ib_offset + i].virt_ptr; 7848c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].total_length = 7858c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ib_offset + i].total_len; 7868c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr = 7878c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_hi; 7888c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr = 7898c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_lo; 7908c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].ci_virt = 7918c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ci_offset + i].virt_ptr; 7928c2ecf20Sopenharmony_ci offsetib = i * 0x20; 7938c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].pi_pci_bar = 7948c2ecf20Sopenharmony_ci get_pci_bar_index(pm8001_mr32(addressib, 7958c2ecf20Sopenharmony_ci (offsetib + 0x14))); 7968c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].pi_offset = 7978c2ecf20Sopenharmony_ci pm8001_mr32(addressib, (offsetib + 0x18)); 7988c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].producer_idx = 0; 7998c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].consumer_index = 0; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 8028c2ecf20Sopenharmony_ci "IQ %d pi_bar 0x%x pi_offset 0x%x\n", i, 8038c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].pi_pci_bar, 8048c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[i].pi_offset); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->max_q_num; i++) { 8078c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].element_size_cnt = 8088c2ecf20Sopenharmony_ci PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30); 8098c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].upper_base_addr = 8108c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_hi; 8118c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].lower_base_addr = 8128c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_lo; 8138c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].base_virt = 8148c2ecf20Sopenharmony_ci (u8 *)pm8001_ha->memoryMap.region[ob_offset + i].virt_ptr; 8158c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].total_length = 8168c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[ob_offset + i].total_len; 8178c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr = 8188c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_hi; 8198c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr = 8208c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_lo; 8218c2ecf20Sopenharmony_ci /* interrupt vector based on oq */ 8228c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay = (i << 24); 8238c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].pi_virt = 8248c2ecf20Sopenharmony_ci pm8001_ha->memoryMap.region[pi_offset + i].virt_ptr; 8258c2ecf20Sopenharmony_ci offsetob = i * 0x24; 8268c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].ci_pci_bar = 8278c2ecf20Sopenharmony_ci get_pci_bar_index(pm8001_mr32(addressob, 8288c2ecf20Sopenharmony_ci offsetob + 0x14)); 8298c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].ci_offset = 8308c2ecf20Sopenharmony_ci pm8001_mr32(addressob, (offsetob + 0x18)); 8318c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].consumer_idx = 0; 8328c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].producer_index = 0; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 8358c2ecf20Sopenharmony_ci "OQ %d ci_bar 0x%x ci_offset 0x%x\n", i, 8368c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].ci_pci_bar, 8378c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[i].ci_offset); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci} 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci/** 8428c2ecf20Sopenharmony_ci * update_main_config_table - update the main default table to the HBA. 8438c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_cistatic void update_main_config_table(struct pm8001_hba_info *pm8001_ha) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->main_cfg_tbl_addr; 8488c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_IQNPPD_HPPD_OFFSET, 8498c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_q_nppd_hppd); 8508c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_EVENT_LOG_ADDR_HI, 8518c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_event_log_addr); 8528c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_EVENT_LOG_ADDR_LO, 8538c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_event_log_addr); 8548c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_EVENT_LOG_BUFF_SIZE, 8558c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size); 8568c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_EVENT_LOG_OPTION, 8578c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_severity); 8588c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_PCS_EVENT_LOG_ADDR_HI, 8598c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_pcs_event_log_addr); 8608c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_PCS_EVENT_LOG_ADDR_LO, 8618c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_pcs_event_log_addr); 8628c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_PCS_EVENT_LOG_BUFF_SIZE, 8638c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size); 8648c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION, 8658c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); 8668c2ecf20Sopenharmony_ci /* Update Fatal error interrupt vector */ 8678c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= 8688c2ecf20Sopenharmony_ci ((pm8001_ha->max_q_num - 1) << 8); 8698c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, 8708c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); 8718c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 8728c2ecf20Sopenharmony_ci "Updated Fatal error interrupt vector 0x%x\n", 8738c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT)); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, 8768c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* SPCv specific */ 8798c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping &= 0xCFFFFFFF; 8808c2ecf20Sopenharmony_ci /* Set GPIOLED to 0x2 for LED indicator */ 8818c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping |= 0x20000000; 8828c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_GPIO_LED_FLAGS_OFFSET, 8838c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping); 8848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 8858c2ecf20Sopenharmony_ci "Programming DW 0x21 in main cfg table with 0x%x\n", 8868c2ecf20Sopenharmony_ci pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET)); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, 8898c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); 8908c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_INT_REASSERTION_DELAY, 8918c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.interrupt_reassertion_delay); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 0xffff0000; 8948c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= 8958c2ecf20Sopenharmony_ci PORT_RECOVERY_TIMEOUT; 8968c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8006) { 8978c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 8988c2ecf20Sopenharmony_ci 0x0000ffff; 8998c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= 9008c2ecf20Sopenharmony_ci CHIP_8006_PORT_RECOVERY_TIMEOUT; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, 9038c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/** 9078c2ecf20Sopenharmony_ci * update_inbnd_queue_table - update the inbound queue table to the HBA. 9088c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 9098c2ecf20Sopenharmony_ci * @number: entry in the queue 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, 9128c2ecf20Sopenharmony_ci int number) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->inbnd_q_tbl_addr; 9158c2ecf20Sopenharmony_ci u16 offset = number * 0x20; 9168c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + IB_PROPERITY_OFFSET, 9178c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt); 9188c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + IB_BASE_ADDR_HI_OFFSET, 9198c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].upper_base_addr); 9208c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + IB_BASE_ADDR_LO_OFFSET, 9218c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].lower_base_addr); 9228c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + IB_CI_BASE_ADDR_HI_OFFSET, 9238c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr); 9248c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + IB_CI_BASE_ADDR_LO_OFFSET, 9258c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 9288c2ecf20Sopenharmony_ci "IQ %d: Element pri size 0x%x\n", 9298c2ecf20Sopenharmony_ci number, 9308c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 9338c2ecf20Sopenharmony_ci "IQ upr base addr 0x%x IQ lwr base addr 0x%x\n", 9348c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].upper_base_addr, 9358c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].lower_base_addr); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 9388c2ecf20Sopenharmony_ci "CI upper base addr 0x%x CI lower base addr 0x%x\n", 9398c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr, 9408c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/** 9448c2ecf20Sopenharmony_ci * update_outbnd_queue_table - update the outbound queue table to the HBA. 9458c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 9468c2ecf20Sopenharmony_ci * @number: entry in the queue 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_cistatic void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, 9498c2ecf20Sopenharmony_ci int number) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci void __iomem *address = pm8001_ha->outbnd_q_tbl_addr; 9528c2ecf20Sopenharmony_ci u16 offset = number * 0x24; 9538c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + OB_PROPERITY_OFFSET, 9548c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].element_size_cnt); 9558c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + OB_BASE_ADDR_HI_OFFSET, 9568c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].upper_base_addr); 9578c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + OB_BASE_ADDR_LO_OFFSET, 9588c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].lower_base_addr); 9598c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + OB_PI_BASE_ADDR_HI_OFFSET, 9608c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr); 9618c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + OB_PI_BASE_ADDR_LO_OFFSET, 9628c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); 9638c2ecf20Sopenharmony_ci pm8001_mw32(address, offset + OB_INTERRUPT_COALES_OFFSET, 9648c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 9678c2ecf20Sopenharmony_ci "OQ %d: Element pri size 0x%x\n", 9688c2ecf20Sopenharmony_ci number, 9698c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].element_size_cnt); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 9728c2ecf20Sopenharmony_ci "OQ upr base addr 0x%x OQ lwr base addr 0x%x\n", 9738c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].upper_base_addr, 9748c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].lower_base_addr); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 9778c2ecf20Sopenharmony_ci "PI upper base addr 0x%x PI lower base addr 0x%x\n", 9788c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr, 9798c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci/** 9838c2ecf20Sopenharmony_ci * mpi_init_check - check firmware initialization status. 9848c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_cistatic int mpi_init_check(struct pm8001_hba_info *pm8001_ha) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci u32 max_wait_count; 9898c2ecf20Sopenharmony_ci u32 value; 9908c2ecf20Sopenharmony_ci u32 gst_len_mpistate; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Write bit0=1 to Inbound DoorBell Register to tell the SPC FW the 9938c2ecf20Sopenharmony_ci table is updated */ 9948c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_UPDATE); 9958c2ecf20Sopenharmony_ci /* wait until Inbound DoorBell Clear Register toggled */ 9968c2ecf20Sopenharmony_ci if (IS_SPCV_12G(pm8001_ha->pdev)) { 9978c2ecf20Sopenharmony_ci max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT; 9988c2ecf20Sopenharmony_ci } else { 9998c2ecf20Sopenharmony_ci max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci do { 10028c2ecf20Sopenharmony_ci udelay(1); 10038c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET); 10048c2ecf20Sopenharmony_ci value &= SPCv_MSGU_CFG_TABLE_UPDATE; 10058c2ecf20Sopenharmony_ci } while ((value != 0) && (--max_wait_count)); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (!max_wait_count) { 10088c2ecf20Sopenharmony_ci /* additional check */ 10098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 10108c2ecf20Sopenharmony_ci "Inb doorbell clear not toggled[value:%x]\n", 10118c2ecf20Sopenharmony_ci value); 10128c2ecf20Sopenharmony_ci return -EBUSY; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci /* check the MPI-State for initialization upto 100ms*/ 10158c2ecf20Sopenharmony_ci max_wait_count = 100 * 1000;/* 100 msec */ 10168c2ecf20Sopenharmony_ci do { 10178c2ecf20Sopenharmony_ci udelay(1); 10188c2ecf20Sopenharmony_ci gst_len_mpistate = 10198c2ecf20Sopenharmony_ci pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 10208c2ecf20Sopenharmony_ci GST_GSTLEN_MPIS_OFFSET); 10218c2ecf20Sopenharmony_ci } while ((GST_MPI_STATE_INIT != 10228c2ecf20Sopenharmony_ci (gst_len_mpistate & GST_MPI_STATE_MASK)) && (--max_wait_count)); 10238c2ecf20Sopenharmony_ci if (!max_wait_count) 10248c2ecf20Sopenharmony_ci return -EBUSY; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci /* check MPI Initialization error */ 10278c2ecf20Sopenharmony_ci gst_len_mpistate = gst_len_mpistate >> 16; 10288c2ecf20Sopenharmony_ci if (0x0000 != gst_len_mpistate) 10298c2ecf20Sopenharmony_ci return -EBUSY; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* 10328c2ecf20Sopenharmony_ci * As per controller datasheet, after successful MPI 10338c2ecf20Sopenharmony_ci * initialization minimum 500ms delay is required before 10348c2ecf20Sopenharmony_ci * issuing commands. 10358c2ecf20Sopenharmony_ci */ 10368c2ecf20Sopenharmony_ci msleep(500); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci return 0; 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci/** 10428c2ecf20Sopenharmony_ci * check_fw_ready - The LLDD check if the FW is ready, if not, return error. 10438c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_cistatic int check_fw_ready(struct pm8001_hba_info *pm8001_ha) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci u32 value; 10488c2ecf20Sopenharmony_ci u32 max_wait_count; 10498c2ecf20Sopenharmony_ci u32 max_wait_time; 10508c2ecf20Sopenharmony_ci int ret = 0; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* reset / PCIe ready */ 10538c2ecf20Sopenharmony_ci max_wait_time = max_wait_count = 100 * 1000; /* 100 milli sec */ 10548c2ecf20Sopenharmony_ci do { 10558c2ecf20Sopenharmony_ci udelay(1); 10568c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 10578c2ecf20Sopenharmony_ci } while ((value == 0xFFFFFFFF) && (--max_wait_count)); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci /* check ila status */ 10608c2ecf20Sopenharmony_ci max_wait_time = max_wait_count = 1000 * 1000; /* 1000 milli sec */ 10618c2ecf20Sopenharmony_ci do { 10628c2ecf20Sopenharmony_ci udelay(1); 10638c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 10648c2ecf20Sopenharmony_ci } while (((value & SCRATCH_PAD_ILA_READY) != 10658c2ecf20Sopenharmony_ci SCRATCH_PAD_ILA_READY) && (--max_wait_count)); 10668c2ecf20Sopenharmony_ci if (!max_wait_count) 10678c2ecf20Sopenharmony_ci ret = -1; 10688c2ecf20Sopenharmony_ci else { 10698c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 10708c2ecf20Sopenharmony_ci " ila ready status in %d millisec\n", 10718c2ecf20Sopenharmony_ci (max_wait_time - max_wait_count)); 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci /* check RAAE status */ 10758c2ecf20Sopenharmony_ci max_wait_time = max_wait_count = 1800 * 1000; /* 1800 milli sec */ 10768c2ecf20Sopenharmony_ci do { 10778c2ecf20Sopenharmony_ci udelay(1); 10788c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 10798c2ecf20Sopenharmony_ci } while (((value & SCRATCH_PAD_RAAE_READY) != 10808c2ecf20Sopenharmony_ci SCRATCH_PAD_RAAE_READY) && (--max_wait_count)); 10818c2ecf20Sopenharmony_ci if (!max_wait_count) 10828c2ecf20Sopenharmony_ci ret = -1; 10838c2ecf20Sopenharmony_ci else { 10848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 10858c2ecf20Sopenharmony_ci " raae ready status in %d millisec\n", 10868c2ecf20Sopenharmony_ci (max_wait_time - max_wait_count)); 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* check iop0 status */ 10908c2ecf20Sopenharmony_ci max_wait_time = max_wait_count = 600 * 1000; /* 600 milli sec */ 10918c2ecf20Sopenharmony_ci do { 10928c2ecf20Sopenharmony_ci udelay(1); 10938c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 10948c2ecf20Sopenharmony_ci } while (((value & SCRATCH_PAD_IOP0_READY) != SCRATCH_PAD_IOP0_READY) && 10958c2ecf20Sopenharmony_ci (--max_wait_count)); 10968c2ecf20Sopenharmony_ci if (!max_wait_count) 10978c2ecf20Sopenharmony_ci ret = -1; 10988c2ecf20Sopenharmony_ci else { 10998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 11008c2ecf20Sopenharmony_ci " iop0 ready status in %d millisec\n", 11018c2ecf20Sopenharmony_ci (max_wait_time - max_wait_count)); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* check iop1 status only for 16 port controllers */ 11058c2ecf20Sopenharmony_ci if ((pm8001_ha->chip_id != chip_8008) && 11068c2ecf20Sopenharmony_ci (pm8001_ha->chip_id != chip_8009)) { 11078c2ecf20Sopenharmony_ci /* 200 milli sec */ 11088c2ecf20Sopenharmony_ci max_wait_time = max_wait_count = 200 * 1000; 11098c2ecf20Sopenharmony_ci do { 11108c2ecf20Sopenharmony_ci udelay(1); 11118c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 11128c2ecf20Sopenharmony_ci } while (((value & SCRATCH_PAD_IOP1_READY) != 11138c2ecf20Sopenharmony_ci SCRATCH_PAD_IOP1_READY) && (--max_wait_count)); 11148c2ecf20Sopenharmony_ci if (!max_wait_count) 11158c2ecf20Sopenharmony_ci ret = -1; 11168c2ecf20Sopenharmony_ci else { 11178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 11188c2ecf20Sopenharmony_ci "iop1 ready status in %d millisec\n", 11198c2ecf20Sopenharmony_ci (max_wait_time - max_wait_count)); 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci return ret; 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci void __iomem *base_addr; 11298c2ecf20Sopenharmony_ci u32 value; 11308c2ecf20Sopenharmony_ci u32 offset; 11318c2ecf20Sopenharmony_ci u32 pcibar; 11328c2ecf20Sopenharmony_ci u32 pcilogic; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); 11358c2ecf20Sopenharmony_ci offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */ 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, "Scratchpad 0 Offset: 0x%x value 0x%x\n", 11388c2ecf20Sopenharmony_ci offset, value); 11398c2ecf20Sopenharmony_ci pcilogic = (value & 0xFC000000) >> 26; 11408c2ecf20Sopenharmony_ci pcibar = get_pci_bar_index(pcilogic); 11418c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar); 11428c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl_addr = base_addr = 11438c2ecf20Sopenharmony_ci pm8001_ha->io_mem[pcibar].memvirtaddr + offset; 11448c2ecf20Sopenharmony_ci pm8001_ha->general_stat_tbl_addr = 11458c2ecf20Sopenharmony_ci base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x18) & 11468c2ecf20Sopenharmony_ci 0xFFFFFF); 11478c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl_addr = 11488c2ecf20Sopenharmony_ci base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C) & 11498c2ecf20Sopenharmony_ci 0xFFFFFF); 11508c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl_addr = 11518c2ecf20Sopenharmony_ci base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x20) & 11528c2ecf20Sopenharmony_ci 0xFFFFFF); 11538c2ecf20Sopenharmony_ci pm8001_ha->ivt_tbl_addr = 11548c2ecf20Sopenharmony_ci base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C) & 11558c2ecf20Sopenharmony_ci 0xFFFFFF); 11568c2ecf20Sopenharmony_ci pm8001_ha->pspa_q_tbl_addr = 11578c2ecf20Sopenharmony_ci base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) & 11588c2ecf20Sopenharmony_ci 0xFFFFFF); 11598c2ecf20Sopenharmony_ci pm8001_ha->fatal_tbl_addr = 11608c2ecf20Sopenharmony_ci base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) & 11618c2ecf20Sopenharmony_ci 0xFFFFFF); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "GST OFFSET 0x%x\n", 11648c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, pcibar, offset + 0x18)); 11658c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "INBND OFFSET 0x%x\n", 11668c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C)); 11678c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "OBND OFFSET 0x%x\n", 11688c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, pcibar, offset + 0x20)); 11698c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "IVT OFFSET 0x%x\n", 11708c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C)); 11718c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "PSPA OFFSET 0x%x\n", 11728c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, pcibar, offset + 0x90)); 11738c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "addr - main cfg %p general status %p\n", 11748c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl_addr, 11758c2ecf20Sopenharmony_ci pm8001_ha->general_stat_tbl_addr); 11768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "addr - inbnd %p obnd %p\n", 11778c2ecf20Sopenharmony_ci pm8001_ha->inbnd_q_tbl_addr, 11788c2ecf20Sopenharmony_ci pm8001_ha->outbnd_q_tbl_addr); 11798c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "addr - pspa %p ivt %p\n", 11808c2ecf20Sopenharmony_ci pm8001_ha->pspa_q_tbl_addr, 11818c2ecf20Sopenharmony_ci pm8001_ha->ivt_tbl_addr); 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci/** 11858c2ecf20Sopenharmony_ci * pm80xx_set_thermal_config - support the thermal configuration 11868c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 11878c2ecf20Sopenharmony_ci */ 11888c2ecf20Sopenharmony_ciint 11898c2ecf20Sopenharmony_cipm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct set_ctrl_cfg_req payload; 11928c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 11938c2ecf20Sopenharmony_ci int rc; 11948c2ecf20Sopenharmony_ci u32 tag; 11958c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; 11968c2ecf20Sopenharmony_ci u32 page_code; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); 11998c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 12008c2ecf20Sopenharmony_ci if (rc) 12018c2ecf20Sopenharmony_ci return -1; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 12048c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci if (IS_SPCV_12G(pm8001_ha->pdev)) 12078c2ecf20Sopenharmony_ci page_code = THERMAL_PAGE_CODE_7H; 12088c2ecf20Sopenharmony_ci else 12098c2ecf20Sopenharmony_ci page_code = THERMAL_PAGE_CODE_8H; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci payload.cfg_pg[0] = 12128c2ecf20Sopenharmony_ci cpu_to_le32((THERMAL_LOG_ENABLE << 9) | 12138c2ecf20Sopenharmony_ci (THERMAL_ENABLE << 8) | page_code); 12148c2ecf20Sopenharmony_ci payload.cfg_pg[1] = 12158c2ecf20Sopenharmony_ci cpu_to_le32((LTEMPHIL << 24) | (RTEMPHIL << 8)); 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 12188c2ecf20Sopenharmony_ci "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", 12198c2ecf20Sopenharmony_ci payload.cfg_pg[0], payload.cfg_pg[1]); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 12228c2ecf20Sopenharmony_ci sizeof(payload), 0); 12238c2ecf20Sopenharmony_ci if (rc) 12248c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 12258c2ecf20Sopenharmony_ci return rc; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci} 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci/** 12308c2ecf20Sopenharmony_ci* pm80xx_set_sas_protocol_timer_config - support the SAS Protocol 12318c2ecf20Sopenharmony_ci* Timer configuration page 12328c2ecf20Sopenharmony_ci* @pm8001_ha: our hba card information. 12338c2ecf20Sopenharmony_ci*/ 12348c2ecf20Sopenharmony_cistatic int 12358c2ecf20Sopenharmony_cipm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct set_ctrl_cfg_req payload; 12388c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 12398c2ecf20Sopenharmony_ci SASProtocolTimerConfig_t SASConfigPage; 12408c2ecf20Sopenharmony_ci int rc; 12418c2ecf20Sopenharmony_ci u32 tag; 12428c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); 12458c2ecf20Sopenharmony_ci memset(&SASConfigPage, 0, sizeof(SASProtocolTimerConfig_t)); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (rc) 12508c2ecf20Sopenharmony_ci return -1; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 12538c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci SASConfigPage.pageCode = cpu_to_le32(SAS_PROTOCOL_TIMER_CONFIG_PAGE); 12568c2ecf20Sopenharmony_ci SASConfigPage.MST_MSI = cpu_to_le32(3 << 15); 12578c2ecf20Sopenharmony_ci SASConfigPage.STP_SSP_MCT_TMO = 12588c2ecf20Sopenharmony_ci cpu_to_le32((STP_MCT_TMO << 16) | SSP_MCT_TMO); 12598c2ecf20Sopenharmony_ci SASConfigPage.STP_FRM_TMO = 12608c2ecf20Sopenharmony_ci cpu_to_le32((SAS_MAX_OPEN_TIME << 24) | 12618c2ecf20Sopenharmony_ci (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER); 12628c2ecf20Sopenharmony_ci SASConfigPage.STP_IDLE_TMO = cpu_to_le32(STP_IDLE_TIME); 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci SASConfigPage.OPNRJT_RTRY_INTVL = 12658c2ecf20Sopenharmony_ci cpu_to_le32((SAS_MFD << 16) | SAS_OPNRJT_RTRY_INTVL); 12668c2ecf20Sopenharmony_ci SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = 12678c2ecf20Sopenharmony_ci cpu_to_le32((SAS_DOPNRJT_RTRY_TMO << 16) | SAS_COPNRJT_RTRY_TMO); 12688c2ecf20Sopenharmony_ci SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = 12698c2ecf20Sopenharmony_ci cpu_to_le32((SAS_DOPNRJT_RTRY_THR << 16) | SAS_COPNRJT_RTRY_THR); 12708c2ecf20Sopenharmony_ci SASConfigPage.MAX_AIP = cpu_to_le32(SAS_MAX_AIP); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n", 12738c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.pageCode)); 12748c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n", 12758c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.MST_MSI)); 12768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n", 12778c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.STP_SSP_MCT_TMO)); 12788c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n", 12798c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.STP_FRM_TMO)); 12808c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n", 12818c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.STP_IDLE_TMO)); 12828c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n", 12838c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.OPNRJT_RTRY_INTVL)); 12848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%08x\n", 12858c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO)); 12868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%08x\n", 12878c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR)); 12888c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n", 12898c2ecf20Sopenharmony_ci le32_to_cpu(SASConfigPage.MAX_AIP)); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci memcpy(&payload.cfg_pg, &SASConfigPage, 12928c2ecf20Sopenharmony_ci sizeof(SASProtocolTimerConfig_t)); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 12958c2ecf20Sopenharmony_ci sizeof(payload), 0); 12968c2ecf20Sopenharmony_ci if (rc) 12978c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci return rc; 13008c2ecf20Sopenharmony_ci} 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci/** 13038c2ecf20Sopenharmony_ci * pm80xx_get_encrypt_info - Check for encryption 13048c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 13058c2ecf20Sopenharmony_ci */ 13068c2ecf20Sopenharmony_cistatic int 13078c2ecf20Sopenharmony_cipm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci u32 scratch3_value; 13108c2ecf20Sopenharmony_ci int ret = -1; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Read encryption status from SCRATCH PAD 3 */ 13138c2ecf20Sopenharmony_ci scratch3_value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == 13168c2ecf20Sopenharmony_ci SCRATCH_PAD3_ENC_READY) { 13178c2ecf20Sopenharmony_ci if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED) 13188c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS; 13198c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13208c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMF_ENABLED) 13218c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF; 13228c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13238c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMA_ENABLED) 13248c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA; 13258c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13268c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMB_ENABLED) 13278c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; 13288c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status = 0; 13298c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 13308c2ecf20Sopenharmony_ci "Encryption: SCRATCH_PAD3_ENC_READY 0x%08X.Cipher mode 0x%x Sec mode 0x%x status 0x%x\n", 13318c2ecf20Sopenharmony_ci scratch3_value, 13328c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode, 13338c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode, 13348c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status); 13358c2ecf20Sopenharmony_ci ret = 0; 13368c2ecf20Sopenharmony_ci } else if ((scratch3_value & SCRATCH_PAD3_ENC_READY) == 13378c2ecf20Sopenharmony_ci SCRATCH_PAD3_ENC_DISABLED) { 13388c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 13398c2ecf20Sopenharmony_ci "Encryption: SCRATCH_PAD3_ENC_DISABLED 0x%08X\n", 13408c2ecf20Sopenharmony_ci scratch3_value); 13418c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status = 0xFFFFFFFF; 13428c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode = 0; 13438c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = 0; 13448c2ecf20Sopenharmony_ci ret = 0; 13458c2ecf20Sopenharmony_ci } else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == 13468c2ecf20Sopenharmony_ci SCRATCH_PAD3_ENC_DIS_ERR) { 13478c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status = 13488c2ecf20Sopenharmony_ci (scratch3_value & SCRATCH_PAD3_ERR_CODE) >> 16; 13498c2ecf20Sopenharmony_ci if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED) 13508c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS; 13518c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13528c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMF_ENABLED) 13538c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF; 13548c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13558c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMA_ENABLED) 13568c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA; 13578c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13588c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMB_ENABLED) 13598c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; 13608c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 13618c2ecf20Sopenharmony_ci "Encryption: SCRATCH_PAD3_DIS_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n", 13628c2ecf20Sopenharmony_ci scratch3_value, 13638c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode, 13648c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode, 13658c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status); 13668c2ecf20Sopenharmony_ci } else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == 13678c2ecf20Sopenharmony_ci SCRATCH_PAD3_ENC_ENA_ERR) { 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status = 13708c2ecf20Sopenharmony_ci (scratch3_value & SCRATCH_PAD3_ERR_CODE) >> 16; 13718c2ecf20Sopenharmony_ci if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED) 13728c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS; 13738c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13748c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMF_ENABLED) 13758c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF; 13768c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13778c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMA_ENABLED) 13788c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA; 13798c2ecf20Sopenharmony_ci if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == 13808c2ecf20Sopenharmony_ci SCRATCH_PAD3_SMB_ENABLED) 13818c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 13848c2ecf20Sopenharmony_ci "Encryption: SCRATCH_PAD3_ENA_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n", 13858c2ecf20Sopenharmony_ci scratch3_value, 13868c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.cipher_mode, 13878c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.sec_mode, 13888c2ecf20Sopenharmony_ci pm8001_ha->encrypt_info.status); 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci return ret; 13918c2ecf20Sopenharmony_ci} 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci/** 13948c2ecf20Sopenharmony_ci * pm80xx_encrypt_update - update flash with encryption informtion 13958c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 13968c2ecf20Sopenharmony_ci */ 13978c2ecf20Sopenharmony_cistatic int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct kek_mgmt_req payload; 14008c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 14018c2ecf20Sopenharmony_ci int rc; 14028c2ecf20Sopenharmony_ci u32 tag; 14038c2ecf20Sopenharmony_ci u32 opc = OPC_INB_KEK_MANAGEMENT; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(struct kek_mgmt_req)); 14068c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 14078c2ecf20Sopenharmony_ci if (rc) 14088c2ecf20Sopenharmony_ci return -1; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 14118c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 14128c2ecf20Sopenharmony_ci /* Currently only one key is used. New KEK index is 1. 14138c2ecf20Sopenharmony_ci * Current KEK index is 1. Store KEK to NVRAM is 1. 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_ci payload.new_curidx_ksop = 14168c2ecf20Sopenharmony_ci cpu_to_le32(((1 << 24) | (1 << 16) | (1 << 8) | 14178c2ecf20Sopenharmony_ci KEK_MGMT_SUBOP_KEYCARDUPDATE)); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 14208c2ecf20Sopenharmony_ci "Saving Encryption info to flash. payload 0x%x\n", 14218c2ecf20Sopenharmony_ci le32_to_cpu(payload.new_curidx_ksop)); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 14248c2ecf20Sopenharmony_ci sizeof(payload), 0); 14258c2ecf20Sopenharmony_ci if (rc) 14268c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci return rc; 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci/** 14328c2ecf20Sopenharmony_ci * pm8001_chip_init - the main init function that initialize whole PM8001 chip. 14338c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 14348c2ecf20Sopenharmony_ci */ 14358c2ecf20Sopenharmony_cistatic int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci int ret; 14388c2ecf20Sopenharmony_ci u8 i = 0; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci /* check the firmware status */ 14418c2ecf20Sopenharmony_ci if (-1 == check_fw_ready(pm8001_ha)) { 14428c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n"); 14438c2ecf20Sopenharmony_ci return -EBUSY; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci /* Initialize the controller fatal error flag */ 14478c2ecf20Sopenharmony_ci pm8001_ha->controller_fatal_error = false; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* Initialize pci space address eg: mpi offset */ 14508c2ecf20Sopenharmony_ci init_pci_device_addresses(pm8001_ha); 14518c2ecf20Sopenharmony_ci init_default_table_values(pm8001_ha); 14528c2ecf20Sopenharmony_ci read_main_config_table(pm8001_ha); 14538c2ecf20Sopenharmony_ci read_general_status_table(pm8001_ha); 14548c2ecf20Sopenharmony_ci read_inbnd_queue_table(pm8001_ha); 14558c2ecf20Sopenharmony_ci read_outbnd_queue_table(pm8001_ha); 14568c2ecf20Sopenharmony_ci read_phy_attr_table(pm8001_ha); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* update main config table ,inbound table and outbound table */ 14598c2ecf20Sopenharmony_ci update_main_config_table(pm8001_ha); 14608c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->max_q_num; i++) { 14618c2ecf20Sopenharmony_ci update_inbnd_queue_table(pm8001_ha, i); 14628c2ecf20Sopenharmony_ci update_outbnd_queue_table(pm8001_ha, i); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci /* notify firmware update finished and check initialization status */ 14658c2ecf20Sopenharmony_ci if (0 == mpi_init_check(pm8001_ha)) { 14668c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n"); 14678c2ecf20Sopenharmony_ci } else 14688c2ecf20Sopenharmony_ci return -EBUSY; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* send SAS protocol timer configuration page to FW */ 14718c2ecf20Sopenharmony_ci ret = pm80xx_set_sas_protocol_timer_config(pm8001_ha); 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci /* Check for encryption */ 14748c2ecf20Sopenharmony_ci if (pm8001_ha->chip->encrypt) { 14758c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "Checking for encryption\n"); 14768c2ecf20Sopenharmony_ci ret = pm80xx_get_encrypt_info(pm8001_ha); 14778c2ecf20Sopenharmony_ci if (ret == -1) { 14788c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "Encryption error !!\n"); 14798c2ecf20Sopenharmony_ci if (pm8001_ha->encrypt_info.status == 0x81) { 14808c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 14818c2ecf20Sopenharmony_ci "Encryption enabled with error.Saving encryption key to flash\n"); 14828c2ecf20Sopenharmony_ci pm80xx_encrypt_update(pm8001_ha); 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci } 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci return 0; 14878c2ecf20Sopenharmony_ci} 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_cistatic int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) 14908c2ecf20Sopenharmony_ci{ 14918c2ecf20Sopenharmony_ci u32 max_wait_count; 14928c2ecf20Sopenharmony_ci u32 value; 14938c2ecf20Sopenharmony_ci u32 gst_len_mpistate; 14948c2ecf20Sopenharmony_ci init_pci_device_addresses(pm8001_ha); 14958c2ecf20Sopenharmony_ci /* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the 14968c2ecf20Sopenharmony_ci table is stop */ 14978c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_RESET); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* wait until Inbound DoorBell Clear Register toggled */ 15008c2ecf20Sopenharmony_ci if (IS_SPCV_12G(pm8001_ha->pdev)) { 15018c2ecf20Sopenharmony_ci max_wait_count = 30 * 1000 * 1000; /* 30 sec */ 15028c2ecf20Sopenharmony_ci } else { 15038c2ecf20Sopenharmony_ci max_wait_count = 15 * 1000 * 1000; /* 15 sec */ 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci do { 15068c2ecf20Sopenharmony_ci udelay(1); 15078c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET); 15088c2ecf20Sopenharmony_ci value &= SPCv_MSGU_CFG_TABLE_RESET; 15098c2ecf20Sopenharmony_ci } while ((value != 0) && (--max_wait_count)); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci if (!max_wait_count) { 15128c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=%x\n", value); 15138c2ecf20Sopenharmony_ci return -1; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci /* check the MPI-State for termination in progress */ 15178c2ecf20Sopenharmony_ci /* wait until Inbound DoorBell Clear Register toggled */ 15188c2ecf20Sopenharmony_ci max_wait_count = 2 * 1000 * 1000; /* 2 sec for spcv/ve */ 15198c2ecf20Sopenharmony_ci do { 15208c2ecf20Sopenharmony_ci udelay(1); 15218c2ecf20Sopenharmony_ci gst_len_mpistate = 15228c2ecf20Sopenharmony_ci pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 15238c2ecf20Sopenharmony_ci GST_GSTLEN_MPIS_OFFSET); 15248c2ecf20Sopenharmony_ci if (GST_MPI_STATE_UNINIT == 15258c2ecf20Sopenharmony_ci (gst_len_mpistate & GST_MPI_STATE_MASK)) 15268c2ecf20Sopenharmony_ci break; 15278c2ecf20Sopenharmony_ci } while (--max_wait_count); 15288c2ecf20Sopenharmony_ci if (!max_wait_count) { 15298c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n", 15308c2ecf20Sopenharmony_ci gst_len_mpistate & GST_MPI_STATE_MASK); 15318c2ecf20Sopenharmony_ci return -1; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci return 0; 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci/** 15388c2ecf20Sopenharmony_ci * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all 15398c2ecf20Sopenharmony_ci * the FW register status to the originated status. 15408c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 15418c2ecf20Sopenharmony_ci */ 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int 15448c2ecf20Sopenharmony_cipm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci u32 regval; 15478c2ecf20Sopenharmony_ci u32 bootloader_state; 15488c2ecf20Sopenharmony_ci u32 ibutton0, ibutton1; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci /* Process MPI table uninitialization only if FW is ready */ 15518c2ecf20Sopenharmony_ci if (!pm8001_ha->controller_fatal_error) { 15528c2ecf20Sopenharmony_ci /* Check if MPI is in ready state to reset */ 15538c2ecf20Sopenharmony_ci if (mpi_uninit_check(pm8001_ha) != 0) { 15548c2ecf20Sopenharmony_ci u32 r0 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); 15558c2ecf20Sopenharmony_ci u32 r1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 15568c2ecf20Sopenharmony_ci u32 r2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); 15578c2ecf20Sopenharmony_ci u32 r3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3); 15588c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 15598c2ecf20Sopenharmony_ci "MPI state is not ready scratch: %x:%x:%x:%x\n", 15608c2ecf20Sopenharmony_ci r0, r1, r2, r3); 15618c2ecf20Sopenharmony_ci /* if things aren't ready but the bootloader is ok then 15628c2ecf20Sopenharmony_ci * try the reset anyway. 15638c2ecf20Sopenharmony_ci */ 15648c2ecf20Sopenharmony_ci if (r1 & SCRATCH_PAD1_BOOTSTATE_MASK) 15658c2ecf20Sopenharmony_ci return -1; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci /* checked for reset register normal state; 0x0 */ 15698c2ecf20Sopenharmony_ci regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); 15708c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "reset register before write : 0x%x\n", 15718c2ecf20Sopenharmony_ci regval); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, SPCv_NORMAL_RESET_VALUE); 15748c2ecf20Sopenharmony_ci msleep(500); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); 15778c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "reset register after write 0x%x\n", 15788c2ecf20Sopenharmony_ci regval); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci if ((regval & SPCv_SOFT_RESET_READ_MASK) == 15818c2ecf20Sopenharmony_ci SPCv_SOFT_RESET_NORMAL_RESET_OCCURED) { 15828c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 15838c2ecf20Sopenharmony_ci " soft reset successful [regval: 0x%x]\n", 15848c2ecf20Sopenharmony_ci regval); 15858c2ecf20Sopenharmony_ci } else { 15868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 15878c2ecf20Sopenharmony_ci " soft reset failed [regval: 0x%x]\n", 15888c2ecf20Sopenharmony_ci regval); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci /* check bootloader is successfully executed or in HDA mode */ 15918c2ecf20Sopenharmony_ci bootloader_state = 15928c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) & 15938c2ecf20Sopenharmony_ci SCRATCH_PAD1_BOOTSTATE_MASK; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_HDA_SEEPROM) { 15968c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 15978c2ecf20Sopenharmony_ci "Bootloader state - HDA mode SEEPROM\n"); 15988c2ecf20Sopenharmony_ci } else if (bootloader_state == 15998c2ecf20Sopenharmony_ci SCRATCH_PAD1_BOOTSTATE_HDA_BOOTSTRAP) { 16008c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 16018c2ecf20Sopenharmony_ci "Bootloader state - HDA mode Bootstrap Pin\n"); 16028c2ecf20Sopenharmony_ci } else if (bootloader_state == 16038c2ecf20Sopenharmony_ci SCRATCH_PAD1_BOOTSTATE_HDA_SOFTRESET) { 16048c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 16058c2ecf20Sopenharmony_ci "Bootloader state - HDA mode soft reset\n"); 16068c2ecf20Sopenharmony_ci } else if (bootloader_state == 16078c2ecf20Sopenharmony_ci SCRATCH_PAD1_BOOTSTATE_CRIT_ERROR) { 16088c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 16098c2ecf20Sopenharmony_ci "Bootloader state-HDA mode critical error\n"); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci return -EBUSY; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* check the firmware status after reset */ 16158c2ecf20Sopenharmony_ci if (-1 == check_fw_ready(pm8001_ha)) { 16168c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n"); 16178c2ecf20Sopenharmony_ci /* check iButton feature support for motherboard controller */ 16188c2ecf20Sopenharmony_ci if (pm8001_ha->pdev->subsystem_vendor != 16198c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ADAPTEC2 && 16208c2ecf20Sopenharmony_ci pm8001_ha->pdev->subsystem_vendor != 16218c2ecf20Sopenharmony_ci PCI_VENDOR_ID_ATTO && 16228c2ecf20Sopenharmony_ci pm8001_ha->pdev->subsystem_vendor != 0) { 16238c2ecf20Sopenharmony_ci ibutton0 = pm8001_cr32(pm8001_ha, 0, 16248c2ecf20Sopenharmony_ci MSGU_HOST_SCRATCH_PAD_6); 16258c2ecf20Sopenharmony_ci ibutton1 = pm8001_cr32(pm8001_ha, 0, 16268c2ecf20Sopenharmony_ci MSGU_HOST_SCRATCH_PAD_7); 16278c2ecf20Sopenharmony_ci if (!ibutton0 && !ibutton1) { 16288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 16298c2ecf20Sopenharmony_ci "iButton Feature is not Available!!!\n"); 16308c2ecf20Sopenharmony_ci return -EBUSY; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci if (ibutton0 == 0xdeadbeef && ibutton1 == 0xdeadbeef) { 16338c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 16348c2ecf20Sopenharmony_ci "CRC Check for iButton Feature Failed!!!\n"); 16358c2ecf20Sopenharmony_ci return -EBUSY; 16368c2ecf20Sopenharmony_ci } 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SPCv soft reset Complete\n"); 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci u32 i; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "chip reset start\n"); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* do SPCv chip reset. */ 16508c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, 0x11); 16518c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n"); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci /* Check this ..whether delay is required or no */ 16548c2ecf20Sopenharmony_ci /* delay 10 usec */ 16558c2ecf20Sopenharmony_ci udelay(10); 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci /* wait for 20 msec until the firmware gets reloaded */ 16588c2ecf20Sopenharmony_ci i = 20; 16598c2ecf20Sopenharmony_ci do { 16608c2ecf20Sopenharmony_ci mdelay(1); 16618c2ecf20Sopenharmony_ci } while ((--i) != 0); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n"); 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/** 16678c2ecf20Sopenharmony_ci * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt 16688c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 16698c2ecf20Sopenharmony_ci */ 16708c2ecf20Sopenharmony_cistatic void 16718c2ecf20Sopenharmony_cipm80xx_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha) 16728c2ecf20Sopenharmony_ci{ 16738c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL); 16748c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL); 16758c2ecf20Sopenharmony_ci} 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci/** 16788c2ecf20Sopenharmony_ci * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt 16798c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 16808c2ecf20Sopenharmony_ci */ 16818c2ecf20Sopenharmony_cistatic void 16828c2ecf20Sopenharmony_cipm80xx_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR, ODMR_MASK_ALL); 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci/** 16888c2ecf20Sopenharmony_ci * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt 16898c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 16908c2ecf20Sopenharmony_ci * @vec: interrupt number to enable 16918c2ecf20Sopenharmony_ci */ 16928c2ecf20Sopenharmony_cistatic void 16938c2ecf20Sopenharmony_cipm80xx_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec) 16948c2ecf20Sopenharmony_ci{ 16958c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 16968c2ecf20Sopenharmony_ci if (vec < 32) 16978c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR, 1U << vec); 16988c2ecf20Sopenharmony_ci else 16998c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR_U, 17008c2ecf20Sopenharmony_ci 1U << (vec - 32)); 17018c2ecf20Sopenharmony_ci return; 17028c2ecf20Sopenharmony_ci#endif 17038c2ecf20Sopenharmony_ci pm80xx_chip_intx_interrupt_enable(pm8001_ha); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci} 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci/** 17088c2ecf20Sopenharmony_ci * pm8001_chip_interrupt_disable- disable PM8001 chip interrupt 17098c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 17108c2ecf20Sopenharmony_ci * @vec: interrupt number to disable 17118c2ecf20Sopenharmony_ci */ 17128c2ecf20Sopenharmony_cistatic void 17138c2ecf20Sopenharmony_cipm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) 17148c2ecf20Sopenharmony_ci{ 17158c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 17168c2ecf20Sopenharmony_ci if (vec == 0xFF) { 17178c2ecf20Sopenharmony_ci /* disable all vectors 0-31, 32-63 */ 17188c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, 0xFFFFFFFF); 17198c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_U, 0xFFFFFFFF); 17208c2ecf20Sopenharmony_ci } else if (vec < 32) 17218c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, 1U << vec); 17228c2ecf20Sopenharmony_ci else 17238c2ecf20Sopenharmony_ci pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_U, 17248c2ecf20Sopenharmony_ci 1U << (vec - 32)); 17258c2ecf20Sopenharmony_ci return; 17268c2ecf20Sopenharmony_ci#endif 17278c2ecf20Sopenharmony_ci pm80xx_chip_intx_interrupt_disable(pm8001_ha); 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_cistatic void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, 17318c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_ha_dev) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci int res; 17348c2ecf20Sopenharmony_ci u32 ccb_tag; 17358c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 17368c2ecf20Sopenharmony_ci struct sas_task *task = NULL; 17378c2ecf20Sopenharmony_ci struct task_abort_req task_abort; 17388c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 17398c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SATA_ABORT; 17408c2ecf20Sopenharmony_ci int ret; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci if (!pm8001_ha_dev) { 17438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "dev is null\n"); 17448c2ecf20Sopenharmony_ci return; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci task = sas_alloc_slow_task(GFP_ATOMIC); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci if (!task) { 17508c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task\n"); 17518c2ecf20Sopenharmony_ci return; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci task->task_done = pm8001_task_done; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); 17578c2ecf20Sopenharmony_ci if (res) { 17588c2ecf20Sopenharmony_ci sas_free_task(task); 17598c2ecf20Sopenharmony_ci return; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[ccb_tag]; 17638c2ecf20Sopenharmony_ci ccb->device = pm8001_ha_dev; 17648c2ecf20Sopenharmony_ci ccb->ccb_tag = ccb_tag; 17658c2ecf20Sopenharmony_ci ccb->task = task; 17668c2ecf20Sopenharmony_ci ccb->n_elem = 0; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci memset(&task_abort, 0, sizeof(task_abort)); 17718c2ecf20Sopenharmony_ci task_abort.abort_all = cpu_to_le32(1); 17728c2ecf20Sopenharmony_ci task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id); 17738c2ecf20Sopenharmony_ci task_abort.tag = cpu_to_le32(ccb_tag); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 17768c2ecf20Sopenharmony_ci sizeof(task_abort), 0); 17778c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "Executing abort task end\n"); 17788c2ecf20Sopenharmony_ci if (ret) { 17798c2ecf20Sopenharmony_ci sas_free_task(task); 17808c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, ccb_tag); 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci} 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cistatic void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, 17858c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_ha_dev) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci struct sata_start_req sata_cmd; 17888c2ecf20Sopenharmony_ci int res; 17898c2ecf20Sopenharmony_ci u32 ccb_tag; 17908c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 17918c2ecf20Sopenharmony_ci struct sas_task *task = NULL; 17928c2ecf20Sopenharmony_ci struct host_to_dev_fis fis; 17938c2ecf20Sopenharmony_ci struct domain_device *dev; 17948c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 17958c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SATA_HOST_OPSTART; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci task = sas_alloc_slow_task(GFP_ATOMIC); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci if (!task) { 18008c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task !!!\n"); 18018c2ecf20Sopenharmony_ci return; 18028c2ecf20Sopenharmony_ci } 18038c2ecf20Sopenharmony_ci task->task_done = pm8001_task_done; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); 18068c2ecf20Sopenharmony_ci if (res) { 18078c2ecf20Sopenharmony_ci sas_free_task(task); 18088c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "cannot allocate tag !!!\n"); 18098c2ecf20Sopenharmony_ci return; 18108c2ecf20Sopenharmony_ci } 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci /* allocate domain device by ourselves as libsas 18138c2ecf20Sopenharmony_ci * is not going to provide any 18148c2ecf20Sopenharmony_ci */ 18158c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC); 18168c2ecf20Sopenharmony_ci if (!dev) { 18178c2ecf20Sopenharmony_ci sas_free_task(task); 18188c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, ccb_tag); 18198c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 18208c2ecf20Sopenharmony_ci "Domain device cannot be allocated\n"); 18218c2ecf20Sopenharmony_ci return; 18228c2ecf20Sopenharmony_ci } 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci task->dev = dev; 18258c2ecf20Sopenharmony_ci task->dev->lldd_dev = pm8001_ha_dev; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[ccb_tag]; 18288c2ecf20Sopenharmony_ci ccb->device = pm8001_ha_dev; 18298c2ecf20Sopenharmony_ci ccb->ccb_tag = ccb_tag; 18308c2ecf20Sopenharmony_ci ccb->task = task; 18318c2ecf20Sopenharmony_ci ccb->n_elem = 0; 18328c2ecf20Sopenharmony_ci pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG; 18338c2ecf20Sopenharmony_ci pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci memset(&sata_cmd, 0, sizeof(sata_cmd)); 18368c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* construct read log FIS */ 18398c2ecf20Sopenharmony_ci memset(&fis, 0, sizeof(struct host_to_dev_fis)); 18408c2ecf20Sopenharmony_ci fis.fis_type = 0x27; 18418c2ecf20Sopenharmony_ci fis.flags = 0x80; 18428c2ecf20Sopenharmony_ci fis.command = ATA_CMD_READ_LOG_EXT; 18438c2ecf20Sopenharmony_ci fis.lbal = 0x10; 18448c2ecf20Sopenharmony_ci fis.sector_count = 0x1; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci sata_cmd.tag = cpu_to_le32(ccb_tag); 18478c2ecf20Sopenharmony_ci sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); 18488c2ecf20Sopenharmony_ci sata_cmd.ncqtag_atap_dir_m_dad = cpu_to_le32(((0x1 << 7) | (0x5 << 9))); 18498c2ecf20Sopenharmony_ci memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 18528c2ecf20Sopenharmony_ci sizeof(sata_cmd), 0); 18538c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "Executing read log end\n"); 18548c2ecf20Sopenharmony_ci if (res) { 18558c2ecf20Sopenharmony_ci sas_free_task(task); 18568c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, ccb_tag); 18578c2ecf20Sopenharmony_ci kfree(dev); 18588c2ecf20Sopenharmony_ci } 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci/** 18628c2ecf20Sopenharmony_ci * mpi_ssp_completion- process the event that FW response to the SSP request. 18638c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 18648c2ecf20Sopenharmony_ci * @piomb: the message contents of this outbound message. 18658c2ecf20Sopenharmony_ci * 18668c2ecf20Sopenharmony_ci * When FW has completed a ssp request for example a IO request, after it has 18678c2ecf20Sopenharmony_ci * filled the SG data with the data, it will trigger this event represent 18688c2ecf20Sopenharmony_ci * that he has finished the job,please check the coresponding buffer. 18698c2ecf20Sopenharmony_ci * So we will tell the caller who maybe waiting the result to tell upper layer 18708c2ecf20Sopenharmony_ci * that the task has been finished. 18718c2ecf20Sopenharmony_ci */ 18728c2ecf20Sopenharmony_cistatic void 18738c2ecf20Sopenharmony_cimpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) 18748c2ecf20Sopenharmony_ci{ 18758c2ecf20Sopenharmony_ci struct sas_task *t; 18768c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 18778c2ecf20Sopenharmony_ci unsigned long flags; 18788c2ecf20Sopenharmony_ci u32 status; 18798c2ecf20Sopenharmony_ci u32 param; 18808c2ecf20Sopenharmony_ci u32 tag; 18818c2ecf20Sopenharmony_ci struct ssp_completion_resp *psspPayload; 18828c2ecf20Sopenharmony_ci struct task_status_struct *ts; 18838c2ecf20Sopenharmony_ci struct ssp_response_iu *iu; 18848c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev; 18858c2ecf20Sopenharmony_ci psspPayload = (struct ssp_completion_resp *)(piomb + 4); 18868c2ecf20Sopenharmony_ci status = le32_to_cpu(psspPayload->status); 18878c2ecf20Sopenharmony_ci tag = le32_to_cpu(psspPayload->tag); 18888c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[tag]; 18898c2ecf20Sopenharmony_ci if ((status == IO_ABORTED) && ccb->open_retry) { 18908c2ecf20Sopenharmony_ci /* Being completed by another */ 18918c2ecf20Sopenharmony_ci ccb->open_retry = 0; 18928c2ecf20Sopenharmony_ci return; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci pm8001_dev = ccb->device; 18958c2ecf20Sopenharmony_ci param = le32_to_cpu(psspPayload->param); 18968c2ecf20Sopenharmony_ci t = ccb->task; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci if (status && status != IO_UNDERFLOW) 18998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", status); 19008c2ecf20Sopenharmony_ci if (unlikely(!t || !t->lldd_task || !t->dev)) 19018c2ecf20Sopenharmony_ci return; 19028c2ecf20Sopenharmony_ci ts = &t->task_status; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 19058c2ecf20Sopenharmony_ci "tag::0x%x, status::0x%x task::0x%p\n", tag, status, t); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* Print sas address of IO failed device */ 19088c2ecf20Sopenharmony_ci if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && 19098c2ecf20Sopenharmony_ci (status != IO_UNDERFLOW)) 19108c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n", 19118c2ecf20Sopenharmony_ci SAS_ADDR(t->dev->sas_addr)); 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci switch (status) { 19148c2ecf20Sopenharmony_ci case IO_SUCCESS: 19158c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS ,param = 0x%x\n", 19168c2ecf20Sopenharmony_ci param); 19178c2ecf20Sopenharmony_ci if (param == 0) { 19188c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19198c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_GOOD; 19208c2ecf20Sopenharmony_ci } else { 19218c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19228c2ecf20Sopenharmony_ci ts->stat = SAS_PROTO_RESPONSE; 19238c2ecf20Sopenharmony_ci ts->residual = param; 19248c2ecf20Sopenharmony_ci iu = &psspPayload->ssp_resp_iu; 19258c2ecf20Sopenharmony_ci sas_ssp_task_response(pm8001_ha->dev, t, iu); 19268c2ecf20Sopenharmony_ci } 19278c2ecf20Sopenharmony_ci if (pm8001_dev) 19288c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19298c2ecf20Sopenharmony_ci break; 19308c2ecf20Sopenharmony_ci case IO_ABORTED: 19318c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n"); 19328c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19338c2ecf20Sopenharmony_ci ts->stat = SAS_ABORTED_TASK; 19348c2ecf20Sopenharmony_ci if (pm8001_dev) 19358c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19368c2ecf20Sopenharmony_ci break; 19378c2ecf20Sopenharmony_ci case IO_UNDERFLOW: 19388c2ecf20Sopenharmony_ci /* SSP Completion with error */ 19398c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW ,param = 0x%x\n", 19408c2ecf20Sopenharmony_ci param); 19418c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19428c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_UNDERRUN; 19438c2ecf20Sopenharmony_ci ts->residual = param; 19448c2ecf20Sopenharmony_ci if (pm8001_dev) 19458c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19468c2ecf20Sopenharmony_ci break; 19478c2ecf20Sopenharmony_ci case IO_NO_DEVICE: 19488c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); 19498c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 19508c2ecf20Sopenharmony_ci ts->stat = SAS_PHY_DOWN; 19518c2ecf20Sopenharmony_ci if (pm8001_dev) 19528c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19538c2ecf20Sopenharmony_ci break; 19548c2ecf20Sopenharmony_ci case IO_XFER_ERROR_BREAK: 19558c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); 19568c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19578c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 19588c2ecf20Sopenharmony_ci /* Force the midlayer to retry */ 19598c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 19608c2ecf20Sopenharmony_ci if (pm8001_dev) 19618c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19628c2ecf20Sopenharmony_ci break; 19638c2ecf20Sopenharmony_ci case IO_XFER_ERROR_PHY_NOT_READY: 19648c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); 19658c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19668c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 19678c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 19688c2ecf20Sopenharmony_ci if (pm8001_dev) 19698c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19708c2ecf20Sopenharmony_ci break; 19718c2ecf20Sopenharmony_ci case IO_XFER_ERROR_INVALID_SSP_RSP_FRAME: 19728c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 19738c2ecf20Sopenharmony_ci "IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n"); 19748c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19758c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 19768c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 19778c2ecf20Sopenharmony_ci if (pm8001_dev) 19788c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19798c2ecf20Sopenharmony_ci break; 19808c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: 19818c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 19828c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); 19838c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19848c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 19858c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_EPROTO; 19868c2ecf20Sopenharmony_ci if (pm8001_dev) 19878c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19888c2ecf20Sopenharmony_ci break; 19898c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: 19908c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 19918c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); 19928c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 19938c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 19948c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 19958c2ecf20Sopenharmony_ci if (pm8001_dev) 19968c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 19978c2ecf20Sopenharmony_ci break; 19988c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BREAK: 19998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); 20008c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20018c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20028c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 20038c2ecf20Sopenharmony_ci if (pm8001_dev) 20048c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20058c2ecf20Sopenharmony_ci break; 20068c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 20078c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: 20088c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: 20098c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: 20108c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: 20118c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: 20128c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); 20138c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20148c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20158c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 20168c2ecf20Sopenharmony_ci if (!t->uldd_task) 20178c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 20188c2ecf20Sopenharmony_ci pm8001_dev, 20198c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); 20208c2ecf20Sopenharmony_ci break; 20218c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BAD_DESTINATION: 20228c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 20238c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); 20248c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20258c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20268c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_BAD_DEST; 20278c2ecf20Sopenharmony_ci if (pm8001_dev) 20288c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20298c2ecf20Sopenharmony_ci break; 20308c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: 20318c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 20328c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); 20338c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20348c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20358c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_CONN_RATE; 20368c2ecf20Sopenharmony_ci if (pm8001_dev) 20378c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20388c2ecf20Sopenharmony_ci break; 20398c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: 20408c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 20418c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); 20428c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 20438c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20448c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_WRONG_DEST; 20458c2ecf20Sopenharmony_ci if (pm8001_dev) 20468c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20478c2ecf20Sopenharmony_ci break; 20488c2ecf20Sopenharmony_ci case IO_XFER_ERROR_NAK_RECEIVED: 20498c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); 20508c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20518c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20528c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 20538c2ecf20Sopenharmony_ci if (pm8001_dev) 20548c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20558c2ecf20Sopenharmony_ci break; 20568c2ecf20Sopenharmony_ci case IO_XFER_ERROR_ACK_NAK_TIMEOUT: 20578c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); 20588c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20598c2ecf20Sopenharmony_ci ts->stat = SAS_NAK_R_ERR; 20608c2ecf20Sopenharmony_ci if (pm8001_dev) 20618c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20628c2ecf20Sopenharmony_ci break; 20638c2ecf20Sopenharmony_ci case IO_XFER_ERROR_DMA: 20648c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n"); 20658c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20668c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20678c2ecf20Sopenharmony_ci if (pm8001_dev) 20688c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20698c2ecf20Sopenharmony_ci break; 20708c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_TIMEOUT: 20718c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); 20728c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20738c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20748c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 20758c2ecf20Sopenharmony_ci if (pm8001_dev) 20768c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20778c2ecf20Sopenharmony_ci break; 20788c2ecf20Sopenharmony_ci case IO_XFER_ERROR_OFFSET_MISMATCH: 20798c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); 20808c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20818c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20828c2ecf20Sopenharmony_ci if (pm8001_dev) 20838c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20848c2ecf20Sopenharmony_ci break; 20858c2ecf20Sopenharmony_ci case IO_PORT_IN_RESET: 20868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); 20878c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20888c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20898c2ecf20Sopenharmony_ci if (pm8001_dev) 20908c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 20918c2ecf20Sopenharmony_ci break; 20928c2ecf20Sopenharmony_ci case IO_DS_NON_OPERATIONAL: 20938c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); 20948c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 20958c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 20968c2ecf20Sopenharmony_ci if (!t->uldd_task) 20978c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 20988c2ecf20Sopenharmony_ci pm8001_dev, 20998c2ecf20Sopenharmony_ci IO_DS_NON_OPERATIONAL); 21008c2ecf20Sopenharmony_ci break; 21018c2ecf20Sopenharmony_ci case IO_DS_IN_RECOVERY: 21028c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); 21038c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 21048c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 21058c2ecf20Sopenharmony_ci if (pm8001_dev) 21068c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 21078c2ecf20Sopenharmony_ci break; 21088c2ecf20Sopenharmony_ci case IO_TM_TAG_NOT_FOUND: 21098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n"); 21108c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 21118c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 21128c2ecf20Sopenharmony_ci if (pm8001_dev) 21138c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 21148c2ecf20Sopenharmony_ci break; 21158c2ecf20Sopenharmony_ci case IO_SSP_EXT_IU_ZERO_LEN_ERROR: 21168c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n"); 21178c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 21188c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 21198c2ecf20Sopenharmony_ci if (pm8001_dev) 21208c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 21218c2ecf20Sopenharmony_ci break; 21228c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: 21238c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 21248c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); 21258c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 21268c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 21278c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 21288c2ecf20Sopenharmony_ci if (pm8001_dev) 21298c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 21308c2ecf20Sopenharmony_ci break; 21318c2ecf20Sopenharmony_ci default: 21328c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); 21338c2ecf20Sopenharmony_ci /* not allowed case. Therefore, return failed status */ 21348c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 21358c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 21368c2ecf20Sopenharmony_ci if (pm8001_dev) 21378c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 21388c2ecf20Sopenharmony_ci break; 21398c2ecf20Sopenharmony_ci } 21408c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "scsi_status = 0x%x\n ", 21418c2ecf20Sopenharmony_ci psspPayload->ssp_resp_iu.status); 21428c2ecf20Sopenharmony_ci spin_lock_irqsave(&t->task_state_lock, flags); 21438c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_STATE_PENDING; 21448c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 21458c2ecf20Sopenharmony_ci t->task_state_flags |= SAS_TASK_STATE_DONE; 21468c2ecf20Sopenharmony_ci if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { 21478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 21488c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 21498c2ecf20Sopenharmony_ci "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", 21508c2ecf20Sopenharmony_ci t, status, ts->resp, ts->stat); 21518c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 21528c2ecf20Sopenharmony_ci if (t->slow_task) 21538c2ecf20Sopenharmony_ci complete(&t->slow_task->completion); 21548c2ecf20Sopenharmony_ci } else { 21558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 21568c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 21578c2ecf20Sopenharmony_ci mb();/* in order to force CPU ordering */ 21588c2ecf20Sopenharmony_ci t->task_done(t); 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci} 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci/*See the comments for mpi_ssp_completion */ 21638c2ecf20Sopenharmony_cistatic void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) 21648c2ecf20Sopenharmony_ci{ 21658c2ecf20Sopenharmony_ci struct sas_task *t; 21668c2ecf20Sopenharmony_ci unsigned long flags; 21678c2ecf20Sopenharmony_ci struct task_status_struct *ts; 21688c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 21698c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev; 21708c2ecf20Sopenharmony_ci struct ssp_event_resp *psspPayload = 21718c2ecf20Sopenharmony_ci (struct ssp_event_resp *)(piomb + 4); 21728c2ecf20Sopenharmony_ci u32 event = le32_to_cpu(psspPayload->event); 21738c2ecf20Sopenharmony_ci u32 tag = le32_to_cpu(psspPayload->tag); 21748c2ecf20Sopenharmony_ci u32 port_id = le32_to_cpu(psspPayload->port_id); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[tag]; 21778c2ecf20Sopenharmony_ci t = ccb->task; 21788c2ecf20Sopenharmony_ci pm8001_dev = ccb->device; 21798c2ecf20Sopenharmony_ci if (event) 21808c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", event); 21818c2ecf20Sopenharmony_ci if (unlikely(!t || !t->lldd_task || !t->dev)) 21828c2ecf20Sopenharmony_ci return; 21838c2ecf20Sopenharmony_ci ts = &t->task_status; 21848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n", 21858c2ecf20Sopenharmony_ci port_id, tag, event); 21868c2ecf20Sopenharmony_ci switch (event) { 21878c2ecf20Sopenharmony_ci case IO_OVERFLOW: 21888c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); 21898c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 21908c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 21918c2ecf20Sopenharmony_ci ts->residual = 0; 21928c2ecf20Sopenharmony_ci if (pm8001_dev) 21938c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 21948c2ecf20Sopenharmony_ci break; 21958c2ecf20Sopenharmony_ci case IO_XFER_ERROR_BREAK: 21968c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); 21978c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK); 21988c2ecf20Sopenharmony_ci return; 21998c2ecf20Sopenharmony_ci case IO_XFER_ERROR_PHY_NOT_READY: 22008c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); 22018c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22028c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22038c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 22048c2ecf20Sopenharmony_ci break; 22058c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: 22068c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22078c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); 22088c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22098c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22108c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_EPROTO; 22118c2ecf20Sopenharmony_ci break; 22128c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: 22138c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22148c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); 22158c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22168c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22178c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 22188c2ecf20Sopenharmony_ci break; 22198c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BREAK: 22208c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); 22218c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22228c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22238c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 22248c2ecf20Sopenharmony_ci break; 22258c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 22268c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: 22278c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: 22288c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: 22298c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: 22308c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: 22318c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); 22328c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22338c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22348c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 22358c2ecf20Sopenharmony_ci if (!t->uldd_task) 22368c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 22378c2ecf20Sopenharmony_ci pm8001_dev, 22388c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); 22398c2ecf20Sopenharmony_ci break; 22408c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BAD_DESTINATION: 22418c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22428c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); 22438c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22448c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22458c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_BAD_DEST; 22468c2ecf20Sopenharmony_ci break; 22478c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: 22488c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22498c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); 22508c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22518c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22528c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_CONN_RATE; 22538c2ecf20Sopenharmony_ci break; 22548c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: 22558c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22568c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); 22578c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22588c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22598c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_WRONG_DEST; 22608c2ecf20Sopenharmony_ci break; 22618c2ecf20Sopenharmony_ci case IO_XFER_ERROR_NAK_RECEIVED: 22628c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); 22638c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22648c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 22658c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 22668c2ecf20Sopenharmony_ci break; 22678c2ecf20Sopenharmony_ci case IO_XFER_ERROR_ACK_NAK_TIMEOUT: 22688c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); 22698c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22708c2ecf20Sopenharmony_ci ts->stat = SAS_NAK_R_ERR; 22718c2ecf20Sopenharmony_ci break; 22728c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_TIMEOUT: 22738c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); 22748c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT); 22758c2ecf20Sopenharmony_ci return; 22768c2ecf20Sopenharmony_ci case IO_XFER_ERROR_UNEXPECTED_PHASE: 22778c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n"); 22788c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22798c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 22808c2ecf20Sopenharmony_ci break; 22818c2ecf20Sopenharmony_ci case IO_XFER_ERROR_XFER_RDY_OVERRUN: 22828c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n"); 22838c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22848c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: 22878c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22888c2ecf20Sopenharmony_ci "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"); 22898c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22908c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 22918c2ecf20Sopenharmony_ci break; 22928c2ecf20Sopenharmony_ci case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT: 22938c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 22948c2ecf20Sopenharmony_ci "IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n"); 22958c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 22968c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 22978c2ecf20Sopenharmony_ci break; 22988c2ecf20Sopenharmony_ci case IO_XFER_ERROR_OFFSET_MISMATCH: 22998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); 23008c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 23018c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 23028c2ecf20Sopenharmony_ci break; 23038c2ecf20Sopenharmony_ci case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: 23048c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 23058c2ecf20Sopenharmony_ci "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"); 23068c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 23078c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 23088c2ecf20Sopenharmony_ci break; 23098c2ecf20Sopenharmony_ci case IO_XFER_ERROR_INTERNAL_CRC_ERROR: 23108c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IOERR, 23118c2ecf20Sopenharmony_ci "IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"); 23128c2ecf20Sopenharmony_ci /* TBC: used default set values */ 23138c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 23148c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 23158c2ecf20Sopenharmony_ci break; 23168c2ecf20Sopenharmony_ci case IO_XFER_CMD_FRAME_ISSUED: 23178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n"); 23188c2ecf20Sopenharmony_ci return; 23198c2ecf20Sopenharmony_ci default: 23208c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event); 23218c2ecf20Sopenharmony_ci /* not allowed case. Therefore, return failed status */ 23228c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 23238c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 23248c2ecf20Sopenharmony_ci break; 23258c2ecf20Sopenharmony_ci } 23268c2ecf20Sopenharmony_ci spin_lock_irqsave(&t->task_state_lock, flags); 23278c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_STATE_PENDING; 23288c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 23298c2ecf20Sopenharmony_ci t->task_state_flags |= SAS_TASK_STATE_DONE; 23308c2ecf20Sopenharmony_ci if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { 23318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 23328c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 23338c2ecf20Sopenharmony_ci "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", 23348c2ecf20Sopenharmony_ci t, event, ts->resp, ts->stat); 23358c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 23368c2ecf20Sopenharmony_ci } else { 23378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 23388c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 23398c2ecf20Sopenharmony_ci mb();/* in order to force CPU ordering */ 23408c2ecf20Sopenharmony_ci t->task_done(t); 23418c2ecf20Sopenharmony_ci } 23428c2ecf20Sopenharmony_ci} 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci/*See the comments for mpi_ssp_completion */ 23458c2ecf20Sopenharmony_cistatic void 23468c2ecf20Sopenharmony_cimpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) 23478c2ecf20Sopenharmony_ci{ 23488c2ecf20Sopenharmony_ci struct sas_task *t; 23498c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 23508c2ecf20Sopenharmony_ci u32 param; 23518c2ecf20Sopenharmony_ci u32 status; 23528c2ecf20Sopenharmony_ci u32 tag; 23538c2ecf20Sopenharmony_ci int i, j; 23548c2ecf20Sopenharmony_ci u8 sata_addr_low[4]; 23558c2ecf20Sopenharmony_ci u32 temp_sata_addr_low, temp_sata_addr_hi; 23568c2ecf20Sopenharmony_ci u8 sata_addr_hi[4]; 23578c2ecf20Sopenharmony_ci struct sata_completion_resp *psataPayload; 23588c2ecf20Sopenharmony_ci struct task_status_struct *ts; 23598c2ecf20Sopenharmony_ci struct ata_task_resp *resp ; 23608c2ecf20Sopenharmony_ci u32 *sata_resp; 23618c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev; 23628c2ecf20Sopenharmony_ci unsigned long flags; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci psataPayload = (struct sata_completion_resp *)(piomb + 4); 23658c2ecf20Sopenharmony_ci status = le32_to_cpu(psataPayload->status); 23668c2ecf20Sopenharmony_ci tag = le32_to_cpu(psataPayload->tag); 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if (!tag) { 23698c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "tag null\n"); 23708c2ecf20Sopenharmony_ci return; 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[tag]; 23738c2ecf20Sopenharmony_ci param = le32_to_cpu(psataPayload->param); 23748c2ecf20Sopenharmony_ci if (ccb) { 23758c2ecf20Sopenharmony_ci t = ccb->task; 23768c2ecf20Sopenharmony_ci pm8001_dev = ccb->device; 23778c2ecf20Sopenharmony_ci } else { 23788c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "ccb null\n"); 23798c2ecf20Sopenharmony_ci return; 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci if (t) { 23838c2ecf20Sopenharmony_ci if (t->dev && (t->dev->lldd_dev)) 23848c2ecf20Sopenharmony_ci pm8001_dev = t->dev->lldd_dev; 23858c2ecf20Sopenharmony_ci } else { 23868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "task null\n"); 23878c2ecf20Sopenharmony_ci return; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG)) 23918c2ecf20Sopenharmony_ci && unlikely(!t || !t->lldd_task || !t->dev)) { 23928c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); 23938c2ecf20Sopenharmony_ci return; 23948c2ecf20Sopenharmony_ci } 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci ts = &t->task_status; 23978c2ecf20Sopenharmony_ci if (!ts) { 23988c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "ts null\n"); 23998c2ecf20Sopenharmony_ci return; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci if (unlikely(status)) 24038c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IOERR, 24048c2ecf20Sopenharmony_ci "status:0x%x, tag:0x%x, task::0x%p\n", 24058c2ecf20Sopenharmony_ci status, tag, t); 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci /* Print sas address of IO failed device */ 24088c2ecf20Sopenharmony_ci if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && 24098c2ecf20Sopenharmony_ci (status != IO_UNDERFLOW)) { 24108c2ecf20Sopenharmony_ci if (!((t->dev->parent) && 24118c2ecf20Sopenharmony_ci (dev_is_expander(t->dev->parent->dev_type)))) { 24128c2ecf20Sopenharmony_ci for (i = 0 , j = 4; i <= 3 && j <= 7; i++ , j++) 24138c2ecf20Sopenharmony_ci sata_addr_low[i] = pm8001_ha->sas_addr[j]; 24148c2ecf20Sopenharmony_ci for (i = 0 , j = 0; i <= 3 && j <= 3; i++ , j++) 24158c2ecf20Sopenharmony_ci sata_addr_hi[i] = pm8001_ha->sas_addr[j]; 24168c2ecf20Sopenharmony_ci memcpy(&temp_sata_addr_low, sata_addr_low, 24178c2ecf20Sopenharmony_ci sizeof(sata_addr_low)); 24188c2ecf20Sopenharmony_ci memcpy(&temp_sata_addr_hi, sata_addr_hi, 24198c2ecf20Sopenharmony_ci sizeof(sata_addr_hi)); 24208c2ecf20Sopenharmony_ci temp_sata_addr_hi = (((temp_sata_addr_hi >> 24) & 0xff) 24218c2ecf20Sopenharmony_ci |((temp_sata_addr_hi << 8) & 24228c2ecf20Sopenharmony_ci 0xff0000) | 24238c2ecf20Sopenharmony_ci ((temp_sata_addr_hi >> 8) 24248c2ecf20Sopenharmony_ci & 0xff00) | 24258c2ecf20Sopenharmony_ci ((temp_sata_addr_hi << 24) & 24268c2ecf20Sopenharmony_ci 0xff000000)); 24278c2ecf20Sopenharmony_ci temp_sata_addr_low = ((((temp_sata_addr_low >> 24) 24288c2ecf20Sopenharmony_ci & 0xff) | 24298c2ecf20Sopenharmony_ci ((temp_sata_addr_low << 8) 24308c2ecf20Sopenharmony_ci & 0xff0000) | 24318c2ecf20Sopenharmony_ci ((temp_sata_addr_low >> 8) 24328c2ecf20Sopenharmony_ci & 0xff00) | 24338c2ecf20Sopenharmony_ci ((temp_sata_addr_low << 24) 24348c2ecf20Sopenharmony_ci & 0xff000000)) + 24358c2ecf20Sopenharmony_ci pm8001_dev->attached_phy + 24368c2ecf20Sopenharmony_ci 0x10); 24378c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 24388c2ecf20Sopenharmony_ci "SAS Address of IO Failure Drive:%08x%08x\n", 24398c2ecf20Sopenharmony_ci temp_sata_addr_hi, 24408c2ecf20Sopenharmony_ci temp_sata_addr_low); 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci } else { 24438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 24448c2ecf20Sopenharmony_ci "SAS Address of IO Failure Drive:%016llx\n", 24458c2ecf20Sopenharmony_ci SAS_ADDR(t->dev->sas_addr)); 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci } 24488c2ecf20Sopenharmony_ci switch (status) { 24498c2ecf20Sopenharmony_ci case IO_SUCCESS: 24508c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n"); 24518c2ecf20Sopenharmony_ci if (param == 0) { 24528c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 24538c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_GOOD; 24548c2ecf20Sopenharmony_ci /* check if response is for SEND READ LOG */ 24558c2ecf20Sopenharmony_ci if (pm8001_dev && 24568c2ecf20Sopenharmony_ci (pm8001_dev->id & NCQ_READ_LOG_FLAG)) { 24578c2ecf20Sopenharmony_ci /* set new bit for abort_all */ 24588c2ecf20Sopenharmony_ci pm8001_dev->id |= NCQ_ABORT_ALL_FLAG; 24598c2ecf20Sopenharmony_ci /* clear bit for read log */ 24608c2ecf20Sopenharmony_ci pm8001_dev->id = pm8001_dev->id & 0x7FFFFFFF; 24618c2ecf20Sopenharmony_ci pm80xx_send_abort_all(pm8001_ha, pm8001_dev); 24628c2ecf20Sopenharmony_ci /* Free the tag */ 24638c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 24648c2ecf20Sopenharmony_ci sas_free_task(t); 24658c2ecf20Sopenharmony_ci return; 24668c2ecf20Sopenharmony_ci } 24678c2ecf20Sopenharmony_ci } else { 24688c2ecf20Sopenharmony_ci u8 len; 24698c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 24708c2ecf20Sopenharmony_ci ts->stat = SAS_PROTO_RESPONSE; 24718c2ecf20Sopenharmony_ci ts->residual = param; 24728c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 24738c2ecf20Sopenharmony_ci "SAS_PROTO_RESPONSE len = %d\n", 24748c2ecf20Sopenharmony_ci param); 24758c2ecf20Sopenharmony_ci sata_resp = &psataPayload->sata_resp[0]; 24768c2ecf20Sopenharmony_ci resp = (struct ata_task_resp *)ts->buf; 24778c2ecf20Sopenharmony_ci if (t->ata_task.dma_xfer == 0 && 24788c2ecf20Sopenharmony_ci t->data_dir == DMA_FROM_DEVICE) { 24798c2ecf20Sopenharmony_ci len = sizeof(struct pio_setup_fis); 24808c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 24818c2ecf20Sopenharmony_ci "PIO read len = %d\n", len); 24828c2ecf20Sopenharmony_ci } else if (t->ata_task.use_ncq && 24838c2ecf20Sopenharmony_ci t->data_dir != DMA_NONE) { 24848c2ecf20Sopenharmony_ci len = sizeof(struct set_dev_bits_fis); 24858c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n", 24868c2ecf20Sopenharmony_ci len); 24878c2ecf20Sopenharmony_ci } else { 24888c2ecf20Sopenharmony_ci len = sizeof(struct dev_to_host_fis); 24898c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "other len = %d\n", 24908c2ecf20Sopenharmony_ci len); 24918c2ecf20Sopenharmony_ci } 24928c2ecf20Sopenharmony_ci if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { 24938c2ecf20Sopenharmony_ci resp->frame_len = len; 24948c2ecf20Sopenharmony_ci memcpy(&resp->ending_fis[0], sata_resp, len); 24958c2ecf20Sopenharmony_ci ts->buf_valid_size = sizeof(*resp); 24968c2ecf20Sopenharmony_ci } else 24978c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 24988c2ecf20Sopenharmony_ci "response too large\n"); 24998c2ecf20Sopenharmony_ci } 25008c2ecf20Sopenharmony_ci if (pm8001_dev) 25018c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25028c2ecf20Sopenharmony_ci break; 25038c2ecf20Sopenharmony_ci case IO_ABORTED: 25048c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n"); 25058c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25068c2ecf20Sopenharmony_ci ts->stat = SAS_ABORTED_TASK; 25078c2ecf20Sopenharmony_ci if (pm8001_dev) 25088c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25098c2ecf20Sopenharmony_ci break; 25108c2ecf20Sopenharmony_ci /* following cases are to do cases */ 25118c2ecf20Sopenharmony_ci case IO_UNDERFLOW: 25128c2ecf20Sopenharmony_ci /* SATA Completion with error */ 25138c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n", param); 25148c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25158c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_UNDERRUN; 25168c2ecf20Sopenharmony_ci ts->residual = param; 25178c2ecf20Sopenharmony_ci if (pm8001_dev) 25188c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25198c2ecf20Sopenharmony_ci break; 25208c2ecf20Sopenharmony_ci case IO_NO_DEVICE: 25218c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); 25228c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 25238c2ecf20Sopenharmony_ci ts->stat = SAS_PHY_DOWN; 25248c2ecf20Sopenharmony_ci if (pm8001_dev) 25258c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25268c2ecf20Sopenharmony_ci break; 25278c2ecf20Sopenharmony_ci case IO_XFER_ERROR_BREAK: 25288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); 25298c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25308c2ecf20Sopenharmony_ci ts->stat = SAS_INTERRUPTED; 25318c2ecf20Sopenharmony_ci if (pm8001_dev) 25328c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25338c2ecf20Sopenharmony_ci break; 25348c2ecf20Sopenharmony_ci case IO_XFER_ERROR_PHY_NOT_READY: 25358c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); 25368c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25378c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 25388c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 25398c2ecf20Sopenharmony_ci if (pm8001_dev) 25408c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25418c2ecf20Sopenharmony_ci break; 25428c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: 25438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 25448c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); 25458c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25468c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 25478c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_EPROTO; 25488c2ecf20Sopenharmony_ci if (pm8001_dev) 25498c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25508c2ecf20Sopenharmony_ci break; 25518c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: 25528c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 25538c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); 25548c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25558c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 25568c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 25578c2ecf20Sopenharmony_ci if (pm8001_dev) 25588c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25598c2ecf20Sopenharmony_ci break; 25608c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BREAK: 25618c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); 25628c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25638c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 25648c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; 25658c2ecf20Sopenharmony_ci if (pm8001_dev) 25668c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 25678c2ecf20Sopenharmony_ci break; 25688c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 25698c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: 25708c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: 25718c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: 25728c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: 25738c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: 25748c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); 25758c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 25768c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 25778c2ecf20Sopenharmony_ci if (!t->uldd_task) { 25788c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 25798c2ecf20Sopenharmony_ci pm8001_dev, 25808c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); 25818c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 25828c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 25838c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 25848c2ecf20Sopenharmony_ci return; 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci break; 25878c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BAD_DESTINATION: 25888c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 25898c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); 25908c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 25918c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 25928c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_BAD_DEST; 25938c2ecf20Sopenharmony_ci if (!t->uldd_task) { 25948c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 25958c2ecf20Sopenharmony_ci pm8001_dev, 25968c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); 25978c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 25988c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 25998c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 26008c2ecf20Sopenharmony_ci return; 26018c2ecf20Sopenharmony_ci } 26028c2ecf20Sopenharmony_ci break; 26038c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: 26048c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 26058c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); 26068c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26078c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 26088c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_CONN_RATE; 26098c2ecf20Sopenharmony_ci if (pm8001_dev) 26108c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26118c2ecf20Sopenharmony_ci break; 26128c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: 26138c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 26148c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n"); 26158c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26168c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 26178c2ecf20Sopenharmony_ci if (!t->uldd_task) { 26188c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 26198c2ecf20Sopenharmony_ci pm8001_dev, 26208c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY); 26218c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 26228c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 26238c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 26248c2ecf20Sopenharmony_ci return; 26258c2ecf20Sopenharmony_ci } 26268c2ecf20Sopenharmony_ci break; 26278c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: 26288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 26298c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); 26308c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26318c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 26328c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_WRONG_DEST; 26338c2ecf20Sopenharmony_ci if (pm8001_dev) 26348c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26358c2ecf20Sopenharmony_ci break; 26368c2ecf20Sopenharmony_ci case IO_XFER_ERROR_NAK_RECEIVED: 26378c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); 26388c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26398c2ecf20Sopenharmony_ci ts->stat = SAS_NAK_R_ERR; 26408c2ecf20Sopenharmony_ci if (pm8001_dev) 26418c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26428c2ecf20Sopenharmony_ci break; 26438c2ecf20Sopenharmony_ci case IO_XFER_ERROR_ACK_NAK_TIMEOUT: 26448c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n"); 26458c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26468c2ecf20Sopenharmony_ci ts->stat = SAS_NAK_R_ERR; 26478c2ecf20Sopenharmony_ci if (pm8001_dev) 26488c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26498c2ecf20Sopenharmony_ci break; 26508c2ecf20Sopenharmony_ci case IO_XFER_ERROR_DMA: 26518c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n"); 26528c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26538c2ecf20Sopenharmony_ci ts->stat = SAS_ABORTED_TASK; 26548c2ecf20Sopenharmony_ci if (pm8001_dev) 26558c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26568c2ecf20Sopenharmony_ci break; 26578c2ecf20Sopenharmony_ci case IO_XFER_ERROR_SATA_LINK_TIMEOUT: 26588c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n"); 26598c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 26608c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 26618c2ecf20Sopenharmony_ci if (pm8001_dev) 26628c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26638c2ecf20Sopenharmony_ci break; 26648c2ecf20Sopenharmony_ci case IO_XFER_ERROR_REJECTED_NCQ_MODE: 26658c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n"); 26668c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26678c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_UNDERRUN; 26688c2ecf20Sopenharmony_ci if (pm8001_dev) 26698c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26708c2ecf20Sopenharmony_ci break; 26718c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_TIMEOUT: 26728c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); 26738c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26748c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 26758c2ecf20Sopenharmony_ci if (pm8001_dev) 26768c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26778c2ecf20Sopenharmony_ci break; 26788c2ecf20Sopenharmony_ci case IO_PORT_IN_RESET: 26798c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); 26808c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26818c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 26828c2ecf20Sopenharmony_ci if (pm8001_dev) 26838c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 26848c2ecf20Sopenharmony_ci break; 26858c2ecf20Sopenharmony_ci case IO_DS_NON_OPERATIONAL: 26868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); 26878c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 26888c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 26898c2ecf20Sopenharmony_ci if (!t->uldd_task) { 26908c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, pm8001_dev, 26918c2ecf20Sopenharmony_ci IO_DS_NON_OPERATIONAL); 26928c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 26938c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 26948c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 26958c2ecf20Sopenharmony_ci return; 26968c2ecf20Sopenharmony_ci } 26978c2ecf20Sopenharmony_ci break; 26988c2ecf20Sopenharmony_ci case IO_DS_IN_RECOVERY: 26998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); 27008c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 27018c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 27028c2ecf20Sopenharmony_ci if (pm8001_dev) 27038c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 27048c2ecf20Sopenharmony_ci break; 27058c2ecf20Sopenharmony_ci case IO_DS_IN_ERROR: 27068c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n"); 27078c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 27088c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 27098c2ecf20Sopenharmony_ci if (!t->uldd_task) { 27108c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, pm8001_dev, 27118c2ecf20Sopenharmony_ci IO_DS_IN_ERROR); 27128c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 27138c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 27148c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 27158c2ecf20Sopenharmony_ci return; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci break; 27188c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: 27198c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 27208c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); 27218c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 27228c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 27238c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 27248c2ecf20Sopenharmony_ci if (pm8001_dev) 27258c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 27268c2ecf20Sopenharmony_ci break; 27278c2ecf20Sopenharmony_ci default: 27288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); 27298c2ecf20Sopenharmony_ci /* not allowed case. Therefore, return failed status */ 27308c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 27318c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 27328c2ecf20Sopenharmony_ci if (pm8001_dev) 27338c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 27348c2ecf20Sopenharmony_ci break; 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci spin_lock_irqsave(&t->task_state_lock, flags); 27378c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_STATE_PENDING; 27388c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 27398c2ecf20Sopenharmony_ci t->task_state_flags |= SAS_TASK_STATE_DONE; 27408c2ecf20Sopenharmony_ci if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { 27418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 27428c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 27438c2ecf20Sopenharmony_ci "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", 27448c2ecf20Sopenharmony_ci t, status, ts->resp, ts->stat); 27458c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 27468c2ecf20Sopenharmony_ci if (t->slow_task) 27478c2ecf20Sopenharmony_ci complete(&t->slow_task->completion); 27488c2ecf20Sopenharmony_ci } else { 27498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 27508c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci} 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci/*See the comments for mpi_ssp_completion */ 27558c2ecf20Sopenharmony_cistatic void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) 27568c2ecf20Sopenharmony_ci{ 27578c2ecf20Sopenharmony_ci struct sas_task *t; 27588c2ecf20Sopenharmony_ci struct task_status_struct *ts; 27598c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 27608c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev; 27618c2ecf20Sopenharmony_ci struct sata_event_resp *psataPayload = 27628c2ecf20Sopenharmony_ci (struct sata_event_resp *)(piomb + 4); 27638c2ecf20Sopenharmony_ci u32 event = le32_to_cpu(psataPayload->event); 27648c2ecf20Sopenharmony_ci u32 tag = le32_to_cpu(psataPayload->tag); 27658c2ecf20Sopenharmony_ci u32 port_id = le32_to_cpu(psataPayload->port_id); 27668c2ecf20Sopenharmony_ci u32 dev_id = le32_to_cpu(psataPayload->device_id); 27678c2ecf20Sopenharmony_ci unsigned long flags; 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[tag]; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci if (ccb) { 27728c2ecf20Sopenharmony_ci t = ccb->task; 27738c2ecf20Sopenharmony_ci pm8001_dev = ccb->device; 27748c2ecf20Sopenharmony_ci } else { 27758c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "No CCB !!!. returning\n"); 27768c2ecf20Sopenharmony_ci return; 27778c2ecf20Sopenharmony_ci } 27788c2ecf20Sopenharmony_ci if (event) 27798c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci /* Check if this is NCQ error */ 27828c2ecf20Sopenharmony_ci if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { 27838c2ecf20Sopenharmony_ci /* find device using device id */ 27848c2ecf20Sopenharmony_ci pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id); 27858c2ecf20Sopenharmony_ci /* send read log extension */ 27868c2ecf20Sopenharmony_ci if (pm8001_dev) 27878c2ecf20Sopenharmony_ci pm80xx_send_read_log(pm8001_ha, pm8001_dev); 27888c2ecf20Sopenharmony_ci return; 27898c2ecf20Sopenharmony_ci } 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci if (unlikely(!t || !t->lldd_task || !t->dev)) { 27928c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n"); 27938c2ecf20Sopenharmony_ci return; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci ts = &t->task_status; 27978c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n", 27988c2ecf20Sopenharmony_ci port_id, tag, event); 27998c2ecf20Sopenharmony_ci switch (event) { 28008c2ecf20Sopenharmony_ci case IO_OVERFLOW: 28018c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); 28028c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28038c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 28048c2ecf20Sopenharmony_ci ts->residual = 0; 28058c2ecf20Sopenharmony_ci if (pm8001_dev) 28068c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 28078c2ecf20Sopenharmony_ci break; 28088c2ecf20Sopenharmony_ci case IO_XFER_ERROR_BREAK: 28098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); 28108c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28118c2ecf20Sopenharmony_ci ts->stat = SAS_INTERRUPTED; 28128c2ecf20Sopenharmony_ci break; 28138c2ecf20Sopenharmony_ci case IO_XFER_ERROR_PHY_NOT_READY: 28148c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); 28158c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28168c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28178c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 28188c2ecf20Sopenharmony_ci break; 28198c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: 28208c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 28218c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); 28228c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28238c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28248c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_EPROTO; 28258c2ecf20Sopenharmony_ci break; 28268c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: 28278c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 28288c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); 28298c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28308c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28318c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 28328c2ecf20Sopenharmony_ci break; 28338c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BREAK: 28348c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); 28358c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28368c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28378c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; 28388c2ecf20Sopenharmony_ci break; 28398c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 28408c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: 28418c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: 28428c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: 28438c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: 28448c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: 28458c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 28468c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); 28478c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 28488c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 28498c2ecf20Sopenharmony_ci if (!t->uldd_task) { 28508c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 28518c2ecf20Sopenharmony_ci pm8001_dev, 28528c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); 28538c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28548c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 28558c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 28568c2ecf20Sopenharmony_ci return; 28578c2ecf20Sopenharmony_ci } 28588c2ecf20Sopenharmony_ci break; 28598c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BAD_DESTINATION: 28608c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 28618c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); 28628c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 28638c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28648c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_BAD_DEST; 28658c2ecf20Sopenharmony_ci break; 28668c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: 28678c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 28688c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); 28698c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28708c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28718c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_CONN_RATE; 28728c2ecf20Sopenharmony_ci break; 28738c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: 28748c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 28758c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); 28768c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28778c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 28788c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_WRONG_DEST; 28798c2ecf20Sopenharmony_ci break; 28808c2ecf20Sopenharmony_ci case IO_XFER_ERROR_NAK_RECEIVED: 28818c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n"); 28828c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28838c2ecf20Sopenharmony_ci ts->stat = SAS_NAK_R_ERR; 28848c2ecf20Sopenharmony_ci break; 28858c2ecf20Sopenharmony_ci case IO_XFER_ERROR_PEER_ABORTED: 28868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n"); 28878c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28888c2ecf20Sopenharmony_ci ts->stat = SAS_NAK_R_ERR; 28898c2ecf20Sopenharmony_ci break; 28908c2ecf20Sopenharmony_ci case IO_XFER_ERROR_REJECTED_NCQ_MODE: 28918c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n"); 28928c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28938c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_UNDERRUN; 28948c2ecf20Sopenharmony_ci break; 28958c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_TIMEOUT: 28968c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); 28978c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 28988c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 28998c2ecf20Sopenharmony_ci break; 29008c2ecf20Sopenharmony_ci case IO_XFER_ERROR_UNEXPECTED_PHASE: 29018c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n"); 29028c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29038c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29048c2ecf20Sopenharmony_ci break; 29058c2ecf20Sopenharmony_ci case IO_XFER_ERROR_XFER_RDY_OVERRUN: 29068c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n"); 29078c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29088c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29098c2ecf20Sopenharmony_ci break; 29108c2ecf20Sopenharmony_ci case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: 29118c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 29128c2ecf20Sopenharmony_ci "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n"); 29138c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29148c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29158c2ecf20Sopenharmony_ci break; 29168c2ecf20Sopenharmony_ci case IO_XFER_ERROR_OFFSET_MISMATCH: 29178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n"); 29188c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29198c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29208c2ecf20Sopenharmony_ci break; 29218c2ecf20Sopenharmony_ci case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: 29228c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 29238c2ecf20Sopenharmony_ci "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n"); 29248c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29258c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29268c2ecf20Sopenharmony_ci break; 29278c2ecf20Sopenharmony_ci case IO_XFER_CMD_FRAME_ISSUED: 29288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n"); 29298c2ecf20Sopenharmony_ci break; 29308c2ecf20Sopenharmony_ci case IO_XFER_PIO_SETUP_ERROR: 29318c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n"); 29328c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29338c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29348c2ecf20Sopenharmony_ci break; 29358c2ecf20Sopenharmony_ci case IO_XFER_ERROR_INTERNAL_CRC_ERROR: 29368c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 29378c2ecf20Sopenharmony_ci "IO_XFR_ERROR_INTERNAL_CRC_ERROR\n"); 29388c2ecf20Sopenharmony_ci /* TBC: used default set values */ 29398c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29408c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29418c2ecf20Sopenharmony_ci break; 29428c2ecf20Sopenharmony_ci case IO_XFER_DMA_ACTIVATE_TIMEOUT: 29438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "IO_XFR_DMA_ACTIVATE_TIMEOUT\n"); 29448c2ecf20Sopenharmony_ci /* TBC: used default set values */ 29458c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29468c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29478c2ecf20Sopenharmony_ci break; 29488c2ecf20Sopenharmony_ci default: 29498c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "Unknown status 0x%x\n", event); 29508c2ecf20Sopenharmony_ci /* not allowed case. Therefore, return failed status */ 29518c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 29528c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_TO; 29538c2ecf20Sopenharmony_ci break; 29548c2ecf20Sopenharmony_ci } 29558c2ecf20Sopenharmony_ci spin_lock_irqsave(&t->task_state_lock, flags); 29568c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_STATE_PENDING; 29578c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 29588c2ecf20Sopenharmony_ci t->task_state_flags |= SAS_TASK_STATE_DONE; 29598c2ecf20Sopenharmony_ci if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { 29608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 29618c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 29628c2ecf20Sopenharmony_ci "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n", 29638c2ecf20Sopenharmony_ci t, event, ts->resp, ts->stat); 29648c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 29658c2ecf20Sopenharmony_ci } else { 29668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 29678c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag); 29688c2ecf20Sopenharmony_ci } 29698c2ecf20Sopenharmony_ci} 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci/*See the comments for mpi_ssp_completion */ 29728c2ecf20Sopenharmony_cistatic void 29738c2ecf20Sopenharmony_cimpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) 29748c2ecf20Sopenharmony_ci{ 29758c2ecf20Sopenharmony_ci u32 param, i; 29768c2ecf20Sopenharmony_ci struct sas_task *t; 29778c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 29788c2ecf20Sopenharmony_ci unsigned long flags; 29798c2ecf20Sopenharmony_ci u32 status; 29808c2ecf20Sopenharmony_ci u32 tag; 29818c2ecf20Sopenharmony_ci struct smp_completion_resp *psmpPayload; 29828c2ecf20Sopenharmony_ci struct task_status_struct *ts; 29838c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev; 29848c2ecf20Sopenharmony_ci char *pdma_respaddr = NULL; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci psmpPayload = (struct smp_completion_resp *)(piomb + 4); 29878c2ecf20Sopenharmony_ci status = le32_to_cpu(psmpPayload->status); 29888c2ecf20Sopenharmony_ci tag = le32_to_cpu(psmpPayload->tag); 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[tag]; 29918c2ecf20Sopenharmony_ci param = le32_to_cpu(psmpPayload->param); 29928c2ecf20Sopenharmony_ci t = ccb->task; 29938c2ecf20Sopenharmony_ci ts = &t->task_status; 29948c2ecf20Sopenharmony_ci pm8001_dev = ccb->device; 29958c2ecf20Sopenharmony_ci if (status) 29968c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n", status); 29978c2ecf20Sopenharmony_ci if (unlikely(!t || !t->lldd_task || !t->dev)) 29988c2ecf20Sopenharmony_ci return; 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, "tag::0x%x status::0x%x\n", tag, status); 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ci switch (status) { 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci case IO_SUCCESS: 30058c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n"); 30068c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30078c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_GOOD; 30088c2ecf20Sopenharmony_ci if (pm8001_dev) 30098c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 30108c2ecf20Sopenharmony_ci if (pm8001_ha->smp_exp_mode == SMP_DIRECT) { 30118c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 30128c2ecf20Sopenharmony_ci "DIRECT RESPONSE Length:%d\n", 30138c2ecf20Sopenharmony_ci param); 30148c2ecf20Sopenharmony_ci pdma_respaddr = (char *)(phys_to_virt(cpu_to_le64 30158c2ecf20Sopenharmony_ci ((u64)sg_dma_address 30168c2ecf20Sopenharmony_ci (&t->smp_task.smp_resp)))); 30178c2ecf20Sopenharmony_ci for (i = 0; i < param; i++) { 30188c2ecf20Sopenharmony_ci *(pdma_respaddr+i) = psmpPayload->_r_a[i]; 30198c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 30208c2ecf20Sopenharmony_ci "SMP Byte%d DMA data 0x%x psmp 0x%x\n", 30218c2ecf20Sopenharmony_ci i, *(pdma_respaddr + i), 30228c2ecf20Sopenharmony_ci psmpPayload->_r_a[i]); 30238c2ecf20Sopenharmony_ci } 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci break; 30268c2ecf20Sopenharmony_ci case IO_ABORTED: 30278c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n"); 30288c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30298c2ecf20Sopenharmony_ci ts->stat = SAS_ABORTED_TASK; 30308c2ecf20Sopenharmony_ci if (pm8001_dev) 30318c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 30328c2ecf20Sopenharmony_ci break; 30338c2ecf20Sopenharmony_ci case IO_OVERFLOW: 30348c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n"); 30358c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30368c2ecf20Sopenharmony_ci ts->stat = SAS_DATA_OVERRUN; 30378c2ecf20Sopenharmony_ci ts->residual = 0; 30388c2ecf20Sopenharmony_ci if (pm8001_dev) 30398c2ecf20Sopenharmony_ci atomic_dec(&pm8001_dev->running_req); 30408c2ecf20Sopenharmony_ci break; 30418c2ecf20Sopenharmony_ci case IO_NO_DEVICE: 30428c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n"); 30438c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30448c2ecf20Sopenharmony_ci ts->stat = SAS_PHY_DOWN; 30458c2ecf20Sopenharmony_ci break; 30468c2ecf20Sopenharmony_ci case IO_ERROR_HW_TIMEOUT: 30478c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n"); 30488c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30498c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_BUSY; 30508c2ecf20Sopenharmony_ci break; 30518c2ecf20Sopenharmony_ci case IO_XFER_ERROR_BREAK: 30528c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n"); 30538c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30548c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_BUSY; 30558c2ecf20Sopenharmony_ci break; 30568c2ecf20Sopenharmony_ci case IO_XFER_ERROR_PHY_NOT_READY: 30578c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n"); 30588c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30598c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_BUSY; 30608c2ecf20Sopenharmony_ci break; 30618c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: 30628c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 30638c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n"); 30648c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30658c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 30668c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 30678c2ecf20Sopenharmony_ci break; 30688c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: 30698c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 30708c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n"); 30718c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30728c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 30738c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 30748c2ecf20Sopenharmony_ci break; 30758c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BREAK: 30768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n"); 30778c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30788c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 30798c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; 30808c2ecf20Sopenharmony_ci break; 30818c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: 30828c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: 30838c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: 30848c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: 30858c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: 30868c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: 30878c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n"); 30888c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30898c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 30908c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_UNKNOWN; 30918c2ecf20Sopenharmony_ci pm8001_handle_event(pm8001_ha, 30928c2ecf20Sopenharmony_ci pm8001_dev, 30938c2ecf20Sopenharmony_ci IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); 30948c2ecf20Sopenharmony_ci break; 30958c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_BAD_DESTINATION: 30968c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 30978c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n"); 30988c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 30998c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31008c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_BAD_DEST; 31018c2ecf20Sopenharmony_ci break; 31028c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: 31038c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 31048c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n"); 31058c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31068c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31078c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_CONN_RATE; 31088c2ecf20Sopenharmony_ci break; 31098c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: 31108c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 31118c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n"); 31128c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31138c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31148c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_WRONG_DEST; 31158c2ecf20Sopenharmony_ci break; 31168c2ecf20Sopenharmony_ci case IO_XFER_ERROR_RX_FRAME: 31178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n"); 31188c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31198c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 31208c2ecf20Sopenharmony_ci break; 31218c2ecf20Sopenharmony_ci case IO_XFER_OPEN_RETRY_TIMEOUT: 31228c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n"); 31238c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31248c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31258c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 31268c2ecf20Sopenharmony_ci break; 31278c2ecf20Sopenharmony_ci case IO_ERROR_INTERNAL_SMP_RESOURCE: 31288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n"); 31298c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31308c2ecf20Sopenharmony_ci ts->stat = SAS_QUEUE_FULL; 31318c2ecf20Sopenharmony_ci break; 31328c2ecf20Sopenharmony_ci case IO_PORT_IN_RESET: 31338c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n"); 31348c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31358c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31368c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 31378c2ecf20Sopenharmony_ci break; 31388c2ecf20Sopenharmony_ci case IO_DS_NON_OPERATIONAL: 31398c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n"); 31408c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31418c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 31428c2ecf20Sopenharmony_ci break; 31438c2ecf20Sopenharmony_ci case IO_DS_IN_RECOVERY: 31448c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n"); 31458c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31468c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31478c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 31488c2ecf20Sopenharmony_ci break; 31498c2ecf20Sopenharmony_ci case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: 31508c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 31518c2ecf20Sopenharmony_ci "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n"); 31528c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31538c2ecf20Sopenharmony_ci ts->stat = SAS_OPEN_REJECT; 31548c2ecf20Sopenharmony_ci ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; 31558c2ecf20Sopenharmony_ci break; 31568c2ecf20Sopenharmony_ci default: 31578c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status); 31588c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 31598c2ecf20Sopenharmony_ci ts->stat = SAS_DEV_NO_RESPONSE; 31608c2ecf20Sopenharmony_ci /* not allowed case. Therefore, return failed status */ 31618c2ecf20Sopenharmony_ci break; 31628c2ecf20Sopenharmony_ci } 31638c2ecf20Sopenharmony_ci spin_lock_irqsave(&t->task_state_lock, flags); 31648c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_STATE_PENDING; 31658c2ecf20Sopenharmony_ci t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 31668c2ecf20Sopenharmony_ci t->task_state_flags |= SAS_TASK_STATE_DONE; 31678c2ecf20Sopenharmony_ci if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { 31688c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 31698c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 31708c2ecf20Sopenharmony_ci "task 0x%p done with io_status 0x%x resp 0x%xstat 0x%x but aborted by upper layer!\n", 31718c2ecf20Sopenharmony_ci t, status, ts->resp, ts->stat); 31728c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 31738c2ecf20Sopenharmony_ci } else { 31748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&t->task_state_lock, flags); 31758c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); 31768c2ecf20Sopenharmony_ci mb();/* in order to force CPU ordering */ 31778c2ecf20Sopenharmony_ci t->task_done(t); 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci} 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci/** 31828c2ecf20Sopenharmony_ci * pm80xx_hw_event_ack_req- For PM8001,some events need to acknowage to FW. 31838c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 31848c2ecf20Sopenharmony_ci * @Qnum: the outbound queue message number. 31858c2ecf20Sopenharmony_ci * @SEA: source of event to ack 31868c2ecf20Sopenharmony_ci * @port_id: port id. 31878c2ecf20Sopenharmony_ci * @phyId: phy id. 31888c2ecf20Sopenharmony_ci * @param0: parameter 0. 31898c2ecf20Sopenharmony_ci * @param1: parameter 1. 31908c2ecf20Sopenharmony_ci */ 31918c2ecf20Sopenharmony_cistatic void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, 31928c2ecf20Sopenharmony_ci u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1) 31938c2ecf20Sopenharmony_ci{ 31948c2ecf20Sopenharmony_ci struct hw_event_ack_req payload; 31958c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SAS_HW_EVENT_ACK; 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci memset((u8 *)&payload, 0, sizeof(payload)); 32008c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[Qnum]; 32018c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(1); 32028c2ecf20Sopenharmony_ci payload.phyid_sea_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) | 32038c2ecf20Sopenharmony_ci ((phyId & 0xFF) << 24) | (port_id & 0xFF)); 32048c2ecf20Sopenharmony_ci payload.param0 = cpu_to_le32(param0); 32058c2ecf20Sopenharmony_ci payload.param1 = cpu_to_le32(param1); 32068c2ecf20Sopenharmony_ci pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 32078c2ecf20Sopenharmony_ci sizeof(payload), 0); 32088c2ecf20Sopenharmony_ci} 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_cistatic int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, 32118c2ecf20Sopenharmony_ci u32 phyId, u32 phy_op); 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_cistatic void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha, 32148c2ecf20Sopenharmony_ci void *piomb) 32158c2ecf20Sopenharmony_ci{ 32168c2ecf20Sopenharmony_ci struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4); 32178c2ecf20Sopenharmony_ci u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); 32188c2ecf20Sopenharmony_ci u8 phy_id = (u8)((phyid_npip_portstate & 0xFF0000) >> 16); 32198c2ecf20Sopenharmony_ci u32 lr_status_evt_portid = 32208c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->lr_status_evt_portid); 32218c2ecf20Sopenharmony_ci u8 deviceType = pPayload->sas_identify.dev_type; 32228c2ecf20Sopenharmony_ci u8 link_rate = (u8)((lr_status_evt_portid & 0xF0000000) >> 28); 32238c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 32248c2ecf20Sopenharmony_ci u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); 32258c2ecf20Sopenharmony_ci struct pm8001_port *port = &pm8001_ha->port[port_id]; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci if (deviceType == SAS_END_DEVICE) { 32288c2ecf20Sopenharmony_ci pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, 32298c2ecf20Sopenharmony_ci PHY_NOTIFY_ENABLE_SPINUP); 32308c2ecf20Sopenharmony_ci } 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci port->wide_port_phymap |= (1U << phy_id); 32338c2ecf20Sopenharmony_ci pm8001_get_lrate_mode(phy, link_rate); 32348c2ecf20Sopenharmony_ci phy->sas_phy.oob_mode = SAS_OOB_MODE; 32358c2ecf20Sopenharmony_ci phy->phy_state = PHY_STATE_LINK_UP_SPCV; 32368c2ecf20Sopenharmony_ci phy->phy_attached = 1; 32378c2ecf20Sopenharmony_ci} 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci/** 32408c2ecf20Sopenharmony_ci * hw_event_sas_phy_up -FW tells me a SAS phy up event. 32418c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 32428c2ecf20Sopenharmony_ci * @piomb: IO message buffer 32438c2ecf20Sopenharmony_ci */ 32448c2ecf20Sopenharmony_cistatic void 32458c2ecf20Sopenharmony_cihw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) 32468c2ecf20Sopenharmony_ci{ 32478c2ecf20Sopenharmony_ci struct hw_event_resp *pPayload = 32488c2ecf20Sopenharmony_ci (struct hw_event_resp *)(piomb + 4); 32498c2ecf20Sopenharmony_ci u32 lr_status_evt_portid = 32508c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->lr_status_evt_portid); 32518c2ecf20Sopenharmony_ci u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci u8 link_rate = 32548c2ecf20Sopenharmony_ci (u8)((lr_status_evt_portid & 0xF0000000) >> 28); 32558c2ecf20Sopenharmony_ci u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); 32568c2ecf20Sopenharmony_ci u8 phy_id = 32578c2ecf20Sopenharmony_ci (u8)((phyid_npip_portstate & 0xFF0000) >> 16); 32588c2ecf20Sopenharmony_ci u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci struct pm8001_port *port = &pm8001_ha->port[port_id]; 32618c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 32628c2ecf20Sopenharmony_ci unsigned long flags; 32638c2ecf20Sopenharmony_ci u8 deviceType = pPayload->sas_identify.dev_type; 32648c2ecf20Sopenharmony_ci port->port_state = portstate; 32658c2ecf20Sopenharmony_ci port->wide_port_phymap |= (1U << phy_id); 32668c2ecf20Sopenharmony_ci phy->phy_state = PHY_STATE_LINK_UP_SPCV; 32678c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 32688c2ecf20Sopenharmony_ci "portid:%d; phyid:%d; linkrate:%d; portstate:%x; devicetype:%x\n", 32698c2ecf20Sopenharmony_ci port_id, phy_id, link_rate, portstate, deviceType); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci switch (deviceType) { 32728c2ecf20Sopenharmony_ci case SAS_PHY_UNUSED: 32738c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "device type no device.\n"); 32748c2ecf20Sopenharmony_ci break; 32758c2ecf20Sopenharmony_ci case SAS_END_DEVICE: 32768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "end device.\n"); 32778c2ecf20Sopenharmony_ci pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, 32788c2ecf20Sopenharmony_ci PHY_NOTIFY_ENABLE_SPINUP); 32798c2ecf20Sopenharmony_ci port->port_attached = 1; 32808c2ecf20Sopenharmony_ci pm8001_get_lrate_mode(phy, link_rate); 32818c2ecf20Sopenharmony_ci break; 32828c2ecf20Sopenharmony_ci case SAS_EDGE_EXPANDER_DEVICE: 32838c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "expander device.\n"); 32848c2ecf20Sopenharmony_ci port->port_attached = 1; 32858c2ecf20Sopenharmony_ci pm8001_get_lrate_mode(phy, link_rate); 32868c2ecf20Sopenharmony_ci break; 32878c2ecf20Sopenharmony_ci case SAS_FANOUT_EXPANDER_DEVICE: 32888c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n"); 32898c2ecf20Sopenharmony_ci port->port_attached = 1; 32908c2ecf20Sopenharmony_ci pm8001_get_lrate_mode(phy, link_rate); 32918c2ecf20Sopenharmony_ci break; 32928c2ecf20Sopenharmony_ci default: 32938c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n", 32948c2ecf20Sopenharmony_ci deviceType); 32958c2ecf20Sopenharmony_ci break; 32968c2ecf20Sopenharmony_ci } 32978c2ecf20Sopenharmony_ci phy->phy_type |= PORT_TYPE_SAS; 32988c2ecf20Sopenharmony_ci phy->identify.device_type = deviceType; 32998c2ecf20Sopenharmony_ci phy->phy_attached = 1; 33008c2ecf20Sopenharmony_ci if (phy->identify.device_type == SAS_END_DEVICE) 33018c2ecf20Sopenharmony_ci phy->identify.target_port_protocols = SAS_PROTOCOL_SSP; 33028c2ecf20Sopenharmony_ci else if (phy->identify.device_type != SAS_PHY_UNUSED) 33038c2ecf20Sopenharmony_ci phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; 33048c2ecf20Sopenharmony_ci phy->sas_phy.oob_mode = SAS_OOB_MODE; 33058c2ecf20Sopenharmony_ci sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); 33068c2ecf20Sopenharmony_ci spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); 33078c2ecf20Sopenharmony_ci memcpy(phy->frame_rcvd, &pPayload->sas_identify, 33088c2ecf20Sopenharmony_ci sizeof(struct sas_identify_frame)-4); 33098c2ecf20Sopenharmony_ci phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4; 33108c2ecf20Sopenharmony_ci pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); 33118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); 33128c2ecf20Sopenharmony_ci if (pm8001_ha->flags == PM8001F_RUN_TIME) 33138c2ecf20Sopenharmony_ci mdelay(200); /* delay a moment to wait for disk to spin up */ 33148c2ecf20Sopenharmony_ci pm8001_bytes_dmaed(pm8001_ha, phy_id); 33158c2ecf20Sopenharmony_ci} 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci/** 33188c2ecf20Sopenharmony_ci * hw_event_sata_phy_up -FW tells me a SATA phy up event. 33198c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 33208c2ecf20Sopenharmony_ci * @piomb: IO message buffer 33218c2ecf20Sopenharmony_ci */ 33228c2ecf20Sopenharmony_cistatic void 33238c2ecf20Sopenharmony_cihw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) 33248c2ecf20Sopenharmony_ci{ 33258c2ecf20Sopenharmony_ci struct hw_event_resp *pPayload = 33268c2ecf20Sopenharmony_ci (struct hw_event_resp *)(piomb + 4); 33278c2ecf20Sopenharmony_ci u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); 33288c2ecf20Sopenharmony_ci u32 lr_status_evt_portid = 33298c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->lr_status_evt_portid); 33308c2ecf20Sopenharmony_ci u8 link_rate = 33318c2ecf20Sopenharmony_ci (u8)((lr_status_evt_portid & 0xF0000000) >> 28); 33328c2ecf20Sopenharmony_ci u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); 33338c2ecf20Sopenharmony_ci u8 phy_id = 33348c2ecf20Sopenharmony_ci (u8)((phyid_npip_portstate & 0xFF0000) >> 16); 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci struct pm8001_port *port = &pm8001_ha->port[port_id]; 33398c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 33408c2ecf20Sopenharmony_ci unsigned long flags; 33418c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, 33428c2ecf20Sopenharmony_ci "port id %d, phy id %d link_rate %d portstate 0x%x\n", 33438c2ecf20Sopenharmony_ci port_id, phy_id, link_rate, portstate); 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci port->port_state = portstate; 33468c2ecf20Sopenharmony_ci phy->phy_state = PHY_STATE_LINK_UP_SPCV; 33478c2ecf20Sopenharmony_ci port->port_attached = 1; 33488c2ecf20Sopenharmony_ci pm8001_get_lrate_mode(phy, link_rate); 33498c2ecf20Sopenharmony_ci phy->phy_type |= PORT_TYPE_SATA; 33508c2ecf20Sopenharmony_ci phy->phy_attached = 1; 33518c2ecf20Sopenharmony_ci phy->sas_phy.oob_mode = SATA_OOB_MODE; 33528c2ecf20Sopenharmony_ci sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); 33538c2ecf20Sopenharmony_ci spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); 33548c2ecf20Sopenharmony_ci memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4), 33558c2ecf20Sopenharmony_ci sizeof(struct dev_to_host_fis)); 33568c2ecf20Sopenharmony_ci phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); 33578c2ecf20Sopenharmony_ci phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; 33588c2ecf20Sopenharmony_ci phy->identify.device_type = SAS_SATA_DEV; 33598c2ecf20Sopenharmony_ci pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); 33608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); 33618c2ecf20Sopenharmony_ci pm8001_bytes_dmaed(pm8001_ha, phy_id); 33628c2ecf20Sopenharmony_ci} 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci/** 33658c2ecf20Sopenharmony_ci * hw_event_phy_down -we should notify the libsas the phy is down. 33668c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 33678c2ecf20Sopenharmony_ci * @piomb: IO message buffer 33688c2ecf20Sopenharmony_ci */ 33698c2ecf20Sopenharmony_cistatic void 33708c2ecf20Sopenharmony_cihw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) 33718c2ecf20Sopenharmony_ci{ 33728c2ecf20Sopenharmony_ci struct hw_event_resp *pPayload = 33738c2ecf20Sopenharmony_ci (struct hw_event_resp *)(piomb + 4); 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci u32 lr_status_evt_portid = 33768c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->lr_status_evt_portid); 33778c2ecf20Sopenharmony_ci u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); 33788c2ecf20Sopenharmony_ci u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); 33798c2ecf20Sopenharmony_ci u8 phy_id = 33808c2ecf20Sopenharmony_ci (u8)((phyid_npip_portstate & 0xFF0000) >> 16); 33818c2ecf20Sopenharmony_ci u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci struct pm8001_port *port = &pm8001_ha->port[port_id]; 33848c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 33858c2ecf20Sopenharmony_ci u32 port_sata = (phy->phy_type & PORT_TYPE_SATA); 33868c2ecf20Sopenharmony_ci port->port_state = portstate; 33878c2ecf20Sopenharmony_ci phy->identify.device_type = 0; 33888c2ecf20Sopenharmony_ci phy->phy_attached = 0; 33898c2ecf20Sopenharmony_ci switch (portstate) { 33908c2ecf20Sopenharmony_ci case PORT_VALID: 33918c2ecf20Sopenharmony_ci break; 33928c2ecf20Sopenharmony_ci case PORT_INVALID: 33938c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n", 33948c2ecf20Sopenharmony_ci port_id); 33958c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 33968c2ecf20Sopenharmony_ci " Last phy Down and port invalid\n"); 33978c2ecf20Sopenharmony_ci if (port_sata) { 33988c2ecf20Sopenharmony_ci phy->phy_type = 0; 33998c2ecf20Sopenharmony_ci port->port_attached = 0; 34008c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, 34018c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci sas_phy_disconnected(&phy->sas_phy); 34048c2ecf20Sopenharmony_ci break; 34058c2ecf20Sopenharmony_ci case PORT_IN_RESET: 34068c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n", 34078c2ecf20Sopenharmony_ci port_id); 34088c2ecf20Sopenharmony_ci break; 34098c2ecf20Sopenharmony_ci case PORT_NOT_ESTABLISHED: 34108c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 34118c2ecf20Sopenharmony_ci " Phy Down and PORT_NOT_ESTABLISHED\n"); 34128c2ecf20Sopenharmony_ci port->port_attached = 0; 34138c2ecf20Sopenharmony_ci break; 34148c2ecf20Sopenharmony_ci case PORT_LOSTCOMM: 34158c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " Phy Down and PORT_LOSTCOMM\n"); 34168c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 34178c2ecf20Sopenharmony_ci " Last phy Down and port invalid\n"); 34188c2ecf20Sopenharmony_ci if (port_sata) { 34198c2ecf20Sopenharmony_ci port->port_attached = 0; 34208c2ecf20Sopenharmony_ci phy->phy_type = 0; 34218c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, 34228c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 34238c2ecf20Sopenharmony_ci } 34248c2ecf20Sopenharmony_ci sas_phy_disconnected(&phy->sas_phy); 34258c2ecf20Sopenharmony_ci break; 34268c2ecf20Sopenharmony_ci default: 34278c2ecf20Sopenharmony_ci port->port_attached = 0; 34288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, 34298c2ecf20Sopenharmony_ci " Phy Down and(default) = 0x%x\n", 34308c2ecf20Sopenharmony_ci portstate); 34318c2ecf20Sopenharmony_ci break; 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci } 34348c2ecf20Sopenharmony_ci if (port_sata && (portstate != PORT_IN_RESET)) 34358c2ecf20Sopenharmony_ci sas_notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); 34368c2ecf20Sopenharmony_ci} 34378c2ecf20Sopenharmony_ci 34388c2ecf20Sopenharmony_cistatic int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) 34398c2ecf20Sopenharmony_ci{ 34408c2ecf20Sopenharmony_ci struct phy_start_resp *pPayload = 34418c2ecf20Sopenharmony_ci (struct phy_start_resp *)(piomb + 4); 34428c2ecf20Sopenharmony_ci u32 status = 34438c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->status); 34448c2ecf20Sopenharmony_ci u32 phy_id = 34458c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->phyid); 34468c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 34478c2ecf20Sopenharmony_ci 34488c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 34498c2ecf20Sopenharmony_ci "phy start resp status:0x%x, phyid:0x%x\n", 34508c2ecf20Sopenharmony_ci status, phy_id); 34518c2ecf20Sopenharmony_ci if (status == 0) 34528c2ecf20Sopenharmony_ci phy->phy_state = PHY_LINK_DOWN; 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci if (pm8001_ha->flags == PM8001F_RUN_TIME && 34558c2ecf20Sopenharmony_ci phy->enable_completion != NULL) { 34568c2ecf20Sopenharmony_ci complete(phy->enable_completion); 34578c2ecf20Sopenharmony_ci phy->enable_completion = NULL; 34588c2ecf20Sopenharmony_ci } 34598c2ecf20Sopenharmony_ci return 0; 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci} 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ci/** 34648c2ecf20Sopenharmony_ci * mpi_thermal_hw_event -The hw event has come. 34658c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 34668c2ecf20Sopenharmony_ci * @piomb: IO message buffer 34678c2ecf20Sopenharmony_ci */ 34688c2ecf20Sopenharmony_cistatic int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) 34698c2ecf20Sopenharmony_ci{ 34708c2ecf20Sopenharmony_ci struct thermal_hw_event *pPayload = 34718c2ecf20Sopenharmony_ci (struct thermal_hw_event *)(piomb + 4); 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci u32 thermal_event = le32_to_cpu(pPayload->thermal_event); 34748c2ecf20Sopenharmony_ci u32 rht_lht = le32_to_cpu(pPayload->rht_lht); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci if (thermal_event & 0x40) { 34778c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 34788c2ecf20Sopenharmony_ci "Thermal Event: Local high temperature violated!\n"); 34798c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 34808c2ecf20Sopenharmony_ci "Thermal Event: Measured local high temperature %d\n", 34818c2ecf20Sopenharmony_ci ((rht_lht & 0xFF00) >> 8)); 34828c2ecf20Sopenharmony_ci } 34838c2ecf20Sopenharmony_ci if (thermal_event & 0x10) { 34848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 34858c2ecf20Sopenharmony_ci "Thermal Event: Remote high temperature violated!\n"); 34868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 34878c2ecf20Sopenharmony_ci "Thermal Event: Measured remote high temperature %d\n", 34888c2ecf20Sopenharmony_ci ((rht_lht & 0xFF000000) >> 24)); 34898c2ecf20Sopenharmony_ci } 34908c2ecf20Sopenharmony_ci return 0; 34918c2ecf20Sopenharmony_ci} 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci/** 34948c2ecf20Sopenharmony_ci * mpi_hw_event -The hw event has come. 34958c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 34968c2ecf20Sopenharmony_ci * @piomb: IO message buffer 34978c2ecf20Sopenharmony_ci */ 34988c2ecf20Sopenharmony_cistatic int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) 34998c2ecf20Sopenharmony_ci{ 35008c2ecf20Sopenharmony_ci unsigned long flags, i; 35018c2ecf20Sopenharmony_ci struct hw_event_resp *pPayload = 35028c2ecf20Sopenharmony_ci (struct hw_event_resp *)(piomb + 4); 35038c2ecf20Sopenharmony_ci u32 lr_status_evt_portid = 35048c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->lr_status_evt_portid); 35058c2ecf20Sopenharmony_ci u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); 35068c2ecf20Sopenharmony_ci u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); 35078c2ecf20Sopenharmony_ci u8 phy_id = 35088c2ecf20Sopenharmony_ci (u8)((phyid_npip_portstate & 0xFF0000) >> 16); 35098c2ecf20Sopenharmony_ci u16 eventType = 35108c2ecf20Sopenharmony_ci (u16)((lr_status_evt_portid & 0x00FFFF00) >> 8); 35118c2ecf20Sopenharmony_ci u8 status = 35128c2ecf20Sopenharmony_ci (u8)((lr_status_evt_portid & 0x0F000000) >> 24); 35138c2ecf20Sopenharmony_ci struct sas_ha_struct *sas_ha = pm8001_ha->sas; 35148c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; 35158c2ecf20Sopenharmony_ci struct pm8001_port *port = &pm8001_ha->port[port_id]; 35168c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; 35178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEV, 35188c2ecf20Sopenharmony_ci "portid:%d phyid:%d event:0x%x status:0x%x\n", 35198c2ecf20Sopenharmony_ci port_id, phy_id, eventType, status); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci switch (eventType) { 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci case HW_EVENT_SAS_PHY_UP: 35248c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS\n"); 35258c2ecf20Sopenharmony_ci hw_event_sas_phy_up(pm8001_ha, piomb); 35268c2ecf20Sopenharmony_ci break; 35278c2ecf20Sopenharmony_ci case HW_EVENT_SATA_PHY_UP: 35288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_PHY_UP\n"); 35298c2ecf20Sopenharmony_ci hw_event_sata_phy_up(pm8001_ha, piomb); 35308c2ecf20Sopenharmony_ci break; 35318c2ecf20Sopenharmony_ci case HW_EVENT_SATA_SPINUP_HOLD: 35328c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_SPINUP_HOLD\n"); 35338c2ecf20Sopenharmony_ci sas_notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); 35348c2ecf20Sopenharmony_ci break; 35358c2ecf20Sopenharmony_ci case HW_EVENT_PHY_DOWN: 35368c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n"); 35378c2ecf20Sopenharmony_ci hw_event_phy_down(pm8001_ha, piomb); 35388c2ecf20Sopenharmony_ci if (pm8001_ha->reset_in_progress) { 35398c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "Reset in progress\n"); 35408c2ecf20Sopenharmony_ci return 0; 35418c2ecf20Sopenharmony_ci } 35428c2ecf20Sopenharmony_ci phy->phy_attached = 0; 35438c2ecf20Sopenharmony_ci phy->phy_state = PHY_LINK_DISABLE; 35448c2ecf20Sopenharmony_ci break; 35458c2ecf20Sopenharmony_ci case HW_EVENT_PORT_INVALID: 35468c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_INVALID\n"); 35478c2ecf20Sopenharmony_ci sas_phy_disconnected(sas_phy); 35488c2ecf20Sopenharmony_ci phy->phy_attached = 0; 35498c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); 35508c2ecf20Sopenharmony_ci break; 35518c2ecf20Sopenharmony_ci /* the broadcast change primitive received, tell the LIBSAS this event 35528c2ecf20Sopenharmony_ci to revalidate the sas domain*/ 35538c2ecf20Sopenharmony_ci case HW_EVENT_BROADCAST_CHANGE: 35548c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n"); 35558c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE, 35568c2ecf20Sopenharmony_ci port_id, phy_id, 1, 0); 35578c2ecf20Sopenharmony_ci spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); 35588c2ecf20Sopenharmony_ci sas_phy->sas_prim = HW_EVENT_BROADCAST_CHANGE; 35598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); 35608c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); 35618c2ecf20Sopenharmony_ci break; 35628c2ecf20Sopenharmony_ci case HW_EVENT_PHY_ERROR: 35638c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_ERROR\n"); 35648c2ecf20Sopenharmony_ci sas_phy_disconnected(&phy->sas_phy); 35658c2ecf20Sopenharmony_ci phy->phy_attached = 0; 35668c2ecf20Sopenharmony_ci sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR); 35678c2ecf20Sopenharmony_ci break; 35688c2ecf20Sopenharmony_ci case HW_EVENT_BROADCAST_EXP: 35698c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n"); 35708c2ecf20Sopenharmony_ci spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); 35718c2ecf20Sopenharmony_ci sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP; 35728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); 35738c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); 35748c2ecf20Sopenharmony_ci break; 35758c2ecf20Sopenharmony_ci case HW_EVENT_LINK_ERR_INVALID_DWORD: 35768c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 35778c2ecf20Sopenharmony_ci "HW_EVENT_LINK_ERR_INVALID_DWORD\n"); 35788c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 35798c2ecf20Sopenharmony_ci HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0); 35808c2ecf20Sopenharmony_ci break; 35818c2ecf20Sopenharmony_ci case HW_EVENT_LINK_ERR_DISPARITY_ERROR: 35828c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 35838c2ecf20Sopenharmony_ci "HW_EVENT_LINK_ERR_DISPARITY_ERROR\n"); 35848c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 35858c2ecf20Sopenharmony_ci HW_EVENT_LINK_ERR_DISPARITY_ERROR, 35868c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 35878c2ecf20Sopenharmony_ci break; 35888c2ecf20Sopenharmony_ci case HW_EVENT_LINK_ERR_CODE_VIOLATION: 35898c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 35908c2ecf20Sopenharmony_ci "HW_EVENT_LINK_ERR_CODE_VIOLATION\n"); 35918c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 35928c2ecf20Sopenharmony_ci HW_EVENT_LINK_ERR_CODE_VIOLATION, 35938c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 35948c2ecf20Sopenharmony_ci break; 35958c2ecf20Sopenharmony_ci case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: 35968c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 35978c2ecf20Sopenharmony_ci "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n"); 35988c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 35998c2ecf20Sopenharmony_ci HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, 36008c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 36018c2ecf20Sopenharmony_ci break; 36028c2ecf20Sopenharmony_ci case HW_EVENT_MALFUNCTION: 36038c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_MALFUNCTION\n"); 36048c2ecf20Sopenharmony_ci break; 36058c2ecf20Sopenharmony_ci case HW_EVENT_BROADCAST_SES: 36068c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n"); 36078c2ecf20Sopenharmony_ci spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); 36088c2ecf20Sopenharmony_ci sas_phy->sas_prim = HW_EVENT_BROADCAST_SES; 36098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); 36108c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); 36118c2ecf20Sopenharmony_ci break; 36128c2ecf20Sopenharmony_ci case HW_EVENT_INBOUND_CRC_ERROR: 36138c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_INBOUND_CRC_ERROR\n"); 36148c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 36158c2ecf20Sopenharmony_ci HW_EVENT_INBOUND_CRC_ERROR, 36168c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 36178c2ecf20Sopenharmony_ci break; 36188c2ecf20Sopenharmony_ci case HW_EVENT_HARD_RESET_RECEIVED: 36198c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_HARD_RESET_RECEIVED\n"); 36208c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_HARD_RESET); 36218c2ecf20Sopenharmony_ci break; 36228c2ecf20Sopenharmony_ci case HW_EVENT_ID_FRAME_TIMEOUT: 36238c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_ID_FRAME_TIMEOUT\n"); 36248c2ecf20Sopenharmony_ci sas_phy_disconnected(sas_phy); 36258c2ecf20Sopenharmony_ci phy->phy_attached = 0; 36268c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); 36278c2ecf20Sopenharmony_ci break; 36288c2ecf20Sopenharmony_ci case HW_EVENT_LINK_ERR_PHY_RESET_FAILED: 36298c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 36308c2ecf20Sopenharmony_ci "HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n"); 36318c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 36328c2ecf20Sopenharmony_ci HW_EVENT_LINK_ERR_PHY_RESET_FAILED, 36338c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 36348c2ecf20Sopenharmony_ci sas_phy_disconnected(sas_phy); 36358c2ecf20Sopenharmony_ci phy->phy_attached = 0; 36368c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); 36378c2ecf20Sopenharmony_ci break; 36388c2ecf20Sopenharmony_ci case HW_EVENT_PORT_RESET_TIMER_TMO: 36398c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n"); 36408c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, 36418c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 36428c2ecf20Sopenharmony_ci sas_phy_disconnected(sas_phy); 36438c2ecf20Sopenharmony_ci phy->phy_attached = 0; 36448c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); 36458c2ecf20Sopenharmony_ci if (pm8001_ha->phy[phy_id].reset_completion) { 36468c2ecf20Sopenharmony_ci pm8001_ha->phy[phy_id].port_reset_status = 36478c2ecf20Sopenharmony_ci PORT_RESET_TMO; 36488c2ecf20Sopenharmony_ci complete(pm8001_ha->phy[phy_id].reset_completion); 36498c2ecf20Sopenharmony_ci pm8001_ha->phy[phy_id].reset_completion = NULL; 36508c2ecf20Sopenharmony_ci } 36518c2ecf20Sopenharmony_ci break; 36528c2ecf20Sopenharmony_ci case HW_EVENT_PORT_RECOVERY_TIMER_TMO: 36538c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 36548c2ecf20Sopenharmony_ci "HW_EVENT_PORT_RECOVERY_TIMER_TMO\n"); 36558c2ecf20Sopenharmony_ci pm80xx_hw_event_ack_req(pm8001_ha, 0, 36568c2ecf20Sopenharmony_ci HW_EVENT_PORT_RECOVERY_TIMER_TMO, 36578c2ecf20Sopenharmony_ci port_id, phy_id, 0, 0); 36588c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 36598c2ecf20Sopenharmony_ci if (port->wide_port_phymap & (1 << i)) { 36608c2ecf20Sopenharmony_ci phy = &pm8001_ha->phy[i]; 36618c2ecf20Sopenharmony_ci sas_notify_phy_event(&phy->sas_phy, 36628c2ecf20Sopenharmony_ci PHYE_LOSS_OF_SIGNAL); 36638c2ecf20Sopenharmony_ci port->wide_port_phymap &= ~(1 << i); 36648c2ecf20Sopenharmony_ci } 36658c2ecf20Sopenharmony_ci } 36668c2ecf20Sopenharmony_ci break; 36678c2ecf20Sopenharmony_ci case HW_EVENT_PORT_RECOVER: 36688c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RECOVER\n"); 36698c2ecf20Sopenharmony_ci hw_event_port_recover(pm8001_ha, piomb); 36708c2ecf20Sopenharmony_ci break; 36718c2ecf20Sopenharmony_ci case HW_EVENT_PORT_RESET_COMPLETE: 36728c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_COMPLETE\n"); 36738c2ecf20Sopenharmony_ci if (pm8001_ha->phy[phy_id].reset_completion) { 36748c2ecf20Sopenharmony_ci pm8001_ha->phy[phy_id].port_reset_status = 36758c2ecf20Sopenharmony_ci PORT_RESET_SUCCESS; 36768c2ecf20Sopenharmony_ci complete(pm8001_ha->phy[phy_id].reset_completion); 36778c2ecf20Sopenharmony_ci pm8001_ha->phy[phy_id].reset_completion = NULL; 36788c2ecf20Sopenharmony_ci } 36798c2ecf20Sopenharmony_ci break; 36808c2ecf20Sopenharmony_ci case EVENT_BROADCAST_ASYNCH_EVENT: 36818c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n"); 36828c2ecf20Sopenharmony_ci break; 36838c2ecf20Sopenharmony_ci default: 36848c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type 0x%x\n", 36858c2ecf20Sopenharmony_ci eventType); 36868c2ecf20Sopenharmony_ci break; 36878c2ecf20Sopenharmony_ci } 36888c2ecf20Sopenharmony_ci return 0; 36898c2ecf20Sopenharmony_ci} 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci/** 36928c2ecf20Sopenharmony_ci * mpi_phy_stop_resp - SPCv specific 36938c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 36948c2ecf20Sopenharmony_ci * @piomb: IO message buffer 36958c2ecf20Sopenharmony_ci */ 36968c2ecf20Sopenharmony_cistatic int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) 36978c2ecf20Sopenharmony_ci{ 36988c2ecf20Sopenharmony_ci struct phy_stop_resp *pPayload = 36998c2ecf20Sopenharmony_ci (struct phy_stop_resp *)(piomb + 4); 37008c2ecf20Sopenharmony_ci u32 status = 37018c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->status); 37028c2ecf20Sopenharmony_ci u32 phyid = 37038c2ecf20Sopenharmony_ci le32_to_cpu(pPayload->phyid) & 0xFF; 37048c2ecf20Sopenharmony_ci struct pm8001_phy *phy = &pm8001_ha->phy[phyid]; 37058c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n", 37068c2ecf20Sopenharmony_ci phyid, status); 37078c2ecf20Sopenharmony_ci if (status == PHY_STOP_SUCCESS || 37088c2ecf20Sopenharmony_ci status == PHY_STOP_ERR_DEVICE_ATTACHED) 37098c2ecf20Sopenharmony_ci phy->phy_state = PHY_LINK_DISABLE; 37108c2ecf20Sopenharmony_ci return 0; 37118c2ecf20Sopenharmony_ci} 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci/** 37148c2ecf20Sopenharmony_ci * mpi_set_controller_config_resp - SPCv specific 37158c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 37168c2ecf20Sopenharmony_ci * @piomb: IO message buffer 37178c2ecf20Sopenharmony_ci */ 37188c2ecf20Sopenharmony_cistatic int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha, 37198c2ecf20Sopenharmony_ci void *piomb) 37208c2ecf20Sopenharmony_ci{ 37218c2ecf20Sopenharmony_ci struct set_ctrl_cfg_resp *pPayload = 37228c2ecf20Sopenharmony_ci (struct set_ctrl_cfg_resp *)(piomb + 4); 37238c2ecf20Sopenharmony_ci u32 status = le32_to_cpu(pPayload->status); 37248c2ecf20Sopenharmony_ci u32 err_qlfr_pgcd = le32_to_cpu(pPayload->err_qlfr_pgcd); 37258c2ecf20Sopenharmony_ci u32 tag = le32_to_cpu(pPayload->tag); 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 37288c2ecf20Sopenharmony_ci "SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n", 37298c2ecf20Sopenharmony_ci status, err_qlfr_pgcd); 37308c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci return 0; 37338c2ecf20Sopenharmony_ci} 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci/** 37368c2ecf20Sopenharmony_ci * mpi_get_controller_config_resp - SPCv specific 37378c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 37388c2ecf20Sopenharmony_ci * @piomb: IO message buffer 37398c2ecf20Sopenharmony_ci */ 37408c2ecf20Sopenharmony_cistatic int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha, 37418c2ecf20Sopenharmony_ci void *piomb) 37428c2ecf20Sopenharmony_ci{ 37438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci return 0; 37468c2ecf20Sopenharmony_ci} 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci/** 37498c2ecf20Sopenharmony_ci * mpi_get_phy_profile_resp - SPCv specific 37508c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 37518c2ecf20Sopenharmony_ci * @piomb: IO message buffer 37528c2ecf20Sopenharmony_ci */ 37538c2ecf20Sopenharmony_cistatic int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, 37548c2ecf20Sopenharmony_ci void *piomb) 37558c2ecf20Sopenharmony_ci{ 37568c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci return 0; 37598c2ecf20Sopenharmony_ci} 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci/** 37628c2ecf20Sopenharmony_ci * mpi_flash_op_ext_resp - SPCv specific 37638c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 37648c2ecf20Sopenharmony_ci * @piomb: IO message buffer 37658c2ecf20Sopenharmony_ci */ 37668c2ecf20Sopenharmony_cistatic int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) 37678c2ecf20Sopenharmony_ci{ 37688c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); 37698c2ecf20Sopenharmony_ci 37708c2ecf20Sopenharmony_ci return 0; 37718c2ecf20Sopenharmony_ci} 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci/** 37748c2ecf20Sopenharmony_ci * mpi_set_phy_profile_resp - SPCv specific 37758c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 37768c2ecf20Sopenharmony_ci * @piomb: IO message buffer 37778c2ecf20Sopenharmony_ci */ 37788c2ecf20Sopenharmony_cistatic int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, 37798c2ecf20Sopenharmony_ci void *piomb) 37808c2ecf20Sopenharmony_ci{ 37818c2ecf20Sopenharmony_ci u32 tag; 37828c2ecf20Sopenharmony_ci u8 page_code; 37838c2ecf20Sopenharmony_ci int rc = 0; 37848c2ecf20Sopenharmony_ci struct set_phy_profile_resp *pPayload = 37858c2ecf20Sopenharmony_ci (struct set_phy_profile_resp *)(piomb + 4); 37868c2ecf20Sopenharmony_ci u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid); 37878c2ecf20Sopenharmony_ci u32 status = le32_to_cpu(pPayload->status); 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci tag = le32_to_cpu(pPayload->tag); 37908c2ecf20Sopenharmony_ci page_code = (u8)((ppc_phyid & 0xFF00) >> 8); 37918c2ecf20Sopenharmony_ci if (status) { 37928c2ecf20Sopenharmony_ci /* status is FAILED */ 37938c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 37948c2ecf20Sopenharmony_ci "PhyProfile command failed with status 0x%08X\n", 37958c2ecf20Sopenharmony_ci status); 37968c2ecf20Sopenharmony_ci rc = -1; 37978c2ecf20Sopenharmony_ci } else { 37988c2ecf20Sopenharmony_ci if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) { 37998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "Invalid page code 0x%X\n", 38008c2ecf20Sopenharmony_ci page_code); 38018c2ecf20Sopenharmony_ci rc = -1; 38028c2ecf20Sopenharmony_ci } 38038c2ecf20Sopenharmony_ci } 38048c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 38058c2ecf20Sopenharmony_ci return rc; 38068c2ecf20Sopenharmony_ci} 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci/** 38098c2ecf20Sopenharmony_ci * mpi_kek_management_resp - SPCv specific 38108c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 38118c2ecf20Sopenharmony_ci * @piomb: IO message buffer 38128c2ecf20Sopenharmony_ci */ 38138c2ecf20Sopenharmony_cistatic int mpi_kek_management_resp(struct pm8001_hba_info *pm8001_ha, 38148c2ecf20Sopenharmony_ci void *piomb) 38158c2ecf20Sopenharmony_ci{ 38168c2ecf20Sopenharmony_ci struct kek_mgmt_resp *pPayload = (struct kek_mgmt_resp *)(piomb + 4); 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci u32 status = le32_to_cpu(pPayload->status); 38198c2ecf20Sopenharmony_ci u32 kidx_new_curr_ksop = le32_to_cpu(pPayload->kidx_new_curr_ksop); 38208c2ecf20Sopenharmony_ci u32 err_qlfr = le32_to_cpu(pPayload->err_qlfr); 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 38238c2ecf20Sopenharmony_ci "KEK MGMT RESP. Status 0x%x idx_ksop 0x%x err_qlfr 0x%x\n", 38248c2ecf20Sopenharmony_ci status, kidx_new_curr_ksop, err_qlfr); 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci return 0; 38278c2ecf20Sopenharmony_ci} 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci/** 38308c2ecf20Sopenharmony_ci * mpi_dek_management_resp - SPCv specific 38318c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 38328c2ecf20Sopenharmony_ci * @piomb: IO message buffer 38338c2ecf20Sopenharmony_ci */ 38348c2ecf20Sopenharmony_cistatic int mpi_dek_management_resp(struct pm8001_hba_info *pm8001_ha, 38358c2ecf20Sopenharmony_ci void *piomb) 38368c2ecf20Sopenharmony_ci{ 38378c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_ci return 0; 38408c2ecf20Sopenharmony_ci} 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci/** 38438c2ecf20Sopenharmony_ci * ssp_coalesced_comp_resp - SPCv specific 38448c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 38458c2ecf20Sopenharmony_ci * @piomb: IO message buffer 38468c2ecf20Sopenharmony_ci */ 38478c2ecf20Sopenharmony_cistatic int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha, 38488c2ecf20Sopenharmony_ci void *piomb) 38498c2ecf20Sopenharmony_ci{ 38508c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n"); 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci return 0; 38538c2ecf20Sopenharmony_ci} 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci/** 38568c2ecf20Sopenharmony_ci * process_one_iomb - process one outbound Queue memory block 38578c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information 38588c2ecf20Sopenharmony_ci * @piomb: IO message buffer 38598c2ecf20Sopenharmony_ci */ 38608c2ecf20Sopenharmony_cistatic void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) 38618c2ecf20Sopenharmony_ci{ 38628c2ecf20Sopenharmony_ci __le32 pHeader = *(__le32 *)piomb; 38638c2ecf20Sopenharmony_ci u32 opc = (u32)((le32_to_cpu(pHeader)) & 0xFFF); 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci switch (opc) { 38668c2ecf20Sopenharmony_ci case OPC_OUB_ECHO: 38678c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n"); 38688c2ecf20Sopenharmony_ci break; 38698c2ecf20Sopenharmony_ci case OPC_OUB_HW_EVENT: 38708c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n"); 38718c2ecf20Sopenharmony_ci mpi_hw_event(pm8001_ha, piomb); 38728c2ecf20Sopenharmony_ci break; 38738c2ecf20Sopenharmony_ci case OPC_OUB_THERM_HW_EVENT: 38748c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_THERMAL_EVENT\n"); 38758c2ecf20Sopenharmony_ci mpi_thermal_hw_event(pm8001_ha, piomb); 38768c2ecf20Sopenharmony_ci break; 38778c2ecf20Sopenharmony_ci case OPC_OUB_SSP_COMP: 38788c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n"); 38798c2ecf20Sopenharmony_ci mpi_ssp_completion(pm8001_ha, piomb); 38808c2ecf20Sopenharmony_ci break; 38818c2ecf20Sopenharmony_ci case OPC_OUB_SMP_COMP: 38828c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n"); 38838c2ecf20Sopenharmony_ci mpi_smp_completion(pm8001_ha, piomb); 38848c2ecf20Sopenharmony_ci break; 38858c2ecf20Sopenharmony_ci case OPC_OUB_LOCAL_PHY_CNTRL: 38868c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n"); 38878c2ecf20Sopenharmony_ci pm8001_mpi_local_phy_ctl(pm8001_ha, piomb); 38888c2ecf20Sopenharmony_ci break; 38898c2ecf20Sopenharmony_ci case OPC_OUB_DEV_REGIST: 38908c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n"); 38918c2ecf20Sopenharmony_ci pm8001_mpi_reg_resp(pm8001_ha, piomb); 38928c2ecf20Sopenharmony_ci break; 38938c2ecf20Sopenharmony_ci case OPC_OUB_DEREG_DEV: 38948c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "unregister the device\n"); 38958c2ecf20Sopenharmony_ci pm8001_mpi_dereg_resp(pm8001_ha, piomb); 38968c2ecf20Sopenharmony_ci break; 38978c2ecf20Sopenharmony_ci case OPC_OUB_GET_DEV_HANDLE: 38988c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n"); 38998c2ecf20Sopenharmony_ci break; 39008c2ecf20Sopenharmony_ci case OPC_OUB_SATA_COMP: 39018c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n"); 39028c2ecf20Sopenharmony_ci mpi_sata_completion(pm8001_ha, piomb); 39038c2ecf20Sopenharmony_ci break; 39048c2ecf20Sopenharmony_ci case OPC_OUB_SATA_EVENT: 39058c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n"); 39068c2ecf20Sopenharmony_ci mpi_sata_event(pm8001_ha, piomb); 39078c2ecf20Sopenharmony_ci break; 39088c2ecf20Sopenharmony_ci case OPC_OUB_SSP_EVENT: 39098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n"); 39108c2ecf20Sopenharmony_ci mpi_ssp_event(pm8001_ha, piomb); 39118c2ecf20Sopenharmony_ci break; 39128c2ecf20Sopenharmony_ci case OPC_OUB_DEV_HANDLE_ARRIV: 39138c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n"); 39148c2ecf20Sopenharmony_ci /*This is for target*/ 39158c2ecf20Sopenharmony_ci break; 39168c2ecf20Sopenharmony_ci case OPC_OUB_SSP_RECV_EVENT: 39178c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n"); 39188c2ecf20Sopenharmony_ci /*This is for target*/ 39198c2ecf20Sopenharmony_ci break; 39208c2ecf20Sopenharmony_ci case OPC_OUB_FW_FLASH_UPDATE: 39218c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n"); 39228c2ecf20Sopenharmony_ci pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb); 39238c2ecf20Sopenharmony_ci break; 39248c2ecf20Sopenharmony_ci case OPC_OUB_GPIO_RESPONSE: 39258c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n"); 39268c2ecf20Sopenharmony_ci break; 39278c2ecf20Sopenharmony_ci case OPC_OUB_GPIO_EVENT: 39288c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n"); 39298c2ecf20Sopenharmony_ci break; 39308c2ecf20Sopenharmony_ci case OPC_OUB_GENERAL_EVENT: 39318c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n"); 39328c2ecf20Sopenharmony_ci pm8001_mpi_general_event(pm8001_ha, piomb); 39338c2ecf20Sopenharmony_ci break; 39348c2ecf20Sopenharmony_ci case OPC_OUB_SSP_ABORT_RSP: 39358c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n"); 39368c2ecf20Sopenharmony_ci pm8001_mpi_task_abort_resp(pm8001_ha, piomb); 39378c2ecf20Sopenharmony_ci break; 39388c2ecf20Sopenharmony_ci case OPC_OUB_SATA_ABORT_RSP: 39398c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n"); 39408c2ecf20Sopenharmony_ci pm8001_mpi_task_abort_resp(pm8001_ha, piomb); 39418c2ecf20Sopenharmony_ci break; 39428c2ecf20Sopenharmony_ci case OPC_OUB_SAS_DIAG_MODE_START_END: 39438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 39448c2ecf20Sopenharmony_ci "OPC_OUB_SAS_DIAG_MODE_START_END\n"); 39458c2ecf20Sopenharmony_ci break; 39468c2ecf20Sopenharmony_ci case OPC_OUB_SAS_DIAG_EXECUTE: 39478c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n"); 39488c2ecf20Sopenharmony_ci break; 39498c2ecf20Sopenharmony_ci case OPC_OUB_GET_TIME_STAMP: 39508c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n"); 39518c2ecf20Sopenharmony_ci break; 39528c2ecf20Sopenharmony_ci case OPC_OUB_SAS_HW_EVENT_ACK: 39538c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n"); 39548c2ecf20Sopenharmony_ci break; 39558c2ecf20Sopenharmony_ci case OPC_OUB_PORT_CONTROL: 39568c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n"); 39578c2ecf20Sopenharmony_ci break; 39588c2ecf20Sopenharmony_ci case OPC_OUB_SMP_ABORT_RSP: 39598c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n"); 39608c2ecf20Sopenharmony_ci pm8001_mpi_task_abort_resp(pm8001_ha, piomb); 39618c2ecf20Sopenharmony_ci break; 39628c2ecf20Sopenharmony_ci case OPC_OUB_GET_NVMD_DATA: 39638c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n"); 39648c2ecf20Sopenharmony_ci pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb); 39658c2ecf20Sopenharmony_ci break; 39668c2ecf20Sopenharmony_ci case OPC_OUB_SET_NVMD_DATA: 39678c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n"); 39688c2ecf20Sopenharmony_ci pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb); 39698c2ecf20Sopenharmony_ci break; 39708c2ecf20Sopenharmony_ci case OPC_OUB_DEVICE_HANDLE_REMOVAL: 39718c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n"); 39728c2ecf20Sopenharmony_ci break; 39738c2ecf20Sopenharmony_ci case OPC_OUB_SET_DEVICE_STATE: 39748c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n"); 39758c2ecf20Sopenharmony_ci pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb); 39768c2ecf20Sopenharmony_ci break; 39778c2ecf20Sopenharmony_ci case OPC_OUB_GET_DEVICE_STATE: 39788c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n"); 39798c2ecf20Sopenharmony_ci break; 39808c2ecf20Sopenharmony_ci case OPC_OUB_SET_DEV_INFO: 39818c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n"); 39828c2ecf20Sopenharmony_ci break; 39838c2ecf20Sopenharmony_ci /* spcv specifc commands */ 39848c2ecf20Sopenharmony_ci case OPC_OUB_PHY_START_RESP: 39858c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 39868c2ecf20Sopenharmony_ci "OPC_OUB_PHY_START_RESP opcode:%x\n", opc); 39878c2ecf20Sopenharmony_ci mpi_phy_start_resp(pm8001_ha, piomb); 39888c2ecf20Sopenharmony_ci break; 39898c2ecf20Sopenharmony_ci case OPC_OUB_PHY_STOP_RESP: 39908c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 39918c2ecf20Sopenharmony_ci "OPC_OUB_PHY_STOP_RESP opcode:%x\n", opc); 39928c2ecf20Sopenharmony_ci mpi_phy_stop_resp(pm8001_ha, piomb); 39938c2ecf20Sopenharmony_ci break; 39948c2ecf20Sopenharmony_ci case OPC_OUB_SET_CONTROLLER_CONFIG: 39958c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 39968c2ecf20Sopenharmony_ci "OPC_OUB_SET_CONTROLLER_CONFIG opcode:%x\n", opc); 39978c2ecf20Sopenharmony_ci mpi_set_controller_config_resp(pm8001_ha, piomb); 39988c2ecf20Sopenharmony_ci break; 39998c2ecf20Sopenharmony_ci case OPC_OUB_GET_CONTROLLER_CONFIG: 40008c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40018c2ecf20Sopenharmony_ci "OPC_OUB_GET_CONTROLLER_CONFIG opcode:%x\n", opc); 40028c2ecf20Sopenharmony_ci mpi_get_controller_config_resp(pm8001_ha, piomb); 40038c2ecf20Sopenharmony_ci break; 40048c2ecf20Sopenharmony_ci case OPC_OUB_GET_PHY_PROFILE: 40058c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40068c2ecf20Sopenharmony_ci "OPC_OUB_GET_PHY_PROFILE opcode:%x\n", opc); 40078c2ecf20Sopenharmony_ci mpi_get_phy_profile_resp(pm8001_ha, piomb); 40088c2ecf20Sopenharmony_ci break; 40098c2ecf20Sopenharmony_ci case OPC_OUB_FLASH_OP_EXT: 40108c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40118c2ecf20Sopenharmony_ci "OPC_OUB_FLASH_OP_EXT opcode:%x\n", opc); 40128c2ecf20Sopenharmony_ci mpi_flash_op_ext_resp(pm8001_ha, piomb); 40138c2ecf20Sopenharmony_ci break; 40148c2ecf20Sopenharmony_ci case OPC_OUB_SET_PHY_PROFILE: 40158c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40168c2ecf20Sopenharmony_ci "OPC_OUB_SET_PHY_PROFILE opcode:%x\n", opc); 40178c2ecf20Sopenharmony_ci mpi_set_phy_profile_resp(pm8001_ha, piomb); 40188c2ecf20Sopenharmony_ci break; 40198c2ecf20Sopenharmony_ci case OPC_OUB_KEK_MANAGEMENT_RESP: 40208c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40218c2ecf20Sopenharmony_ci "OPC_OUB_KEK_MANAGEMENT_RESP opcode:%x\n", opc); 40228c2ecf20Sopenharmony_ci mpi_kek_management_resp(pm8001_ha, piomb); 40238c2ecf20Sopenharmony_ci break; 40248c2ecf20Sopenharmony_ci case OPC_OUB_DEK_MANAGEMENT_RESP: 40258c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40268c2ecf20Sopenharmony_ci "OPC_OUB_DEK_MANAGEMENT_RESP opcode:%x\n", opc); 40278c2ecf20Sopenharmony_ci mpi_dek_management_resp(pm8001_ha, piomb); 40288c2ecf20Sopenharmony_ci break; 40298c2ecf20Sopenharmony_ci case OPC_OUB_SSP_COALESCED_COMP_RESP: 40308c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, MSG, 40318c2ecf20Sopenharmony_ci "OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n", opc); 40328c2ecf20Sopenharmony_ci ssp_coalesced_comp_resp(pm8001_ha, piomb); 40338c2ecf20Sopenharmony_ci break; 40348c2ecf20Sopenharmony_ci default: 40358c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, 40368c2ecf20Sopenharmony_ci "Unknown outbound Queue IOMB OPC = 0x%x\n", opc); 40378c2ecf20Sopenharmony_ci break; 40388c2ecf20Sopenharmony_ci } 40398c2ecf20Sopenharmony_ci} 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_cistatic void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) 40428c2ecf20Sopenharmony_ci{ 40438c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_0: 0x%x\n", 40448c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)); 40458c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_1:0x%x\n", 40468c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)); 40478c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_2: 0x%x\n", 40488c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)); 40498c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_3: 0x%x\n", 40508c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)); 40518c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_0: 0x%x\n", 40528c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0)); 40538c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_1: 0x%x\n", 40548c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1)); 40558c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_2: 0x%x\n", 40568c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2)); 40578c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_3: 0x%x\n", 40588c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3)); 40598c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_4: 0x%x\n", 40608c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4)); 40618c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_5: 0x%x\n", 40628c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5)); 40638c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n", 40648c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6)); 40658c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n", 40668c2ecf20Sopenharmony_ci pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7)); 40678c2ecf20Sopenharmony_ci} 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_cistatic int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) 40708c2ecf20Sopenharmony_ci{ 40718c2ecf20Sopenharmony_ci struct outbound_queue_table *circularQ; 40728c2ecf20Sopenharmony_ci void *pMsg1 = NULL; 40738c2ecf20Sopenharmony_ci u8 bc; 40748c2ecf20Sopenharmony_ci u32 ret = MPI_IO_STATUS_FAIL; 40758c2ecf20Sopenharmony_ci unsigned long flags; 40768c2ecf20Sopenharmony_ci u32 regval; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci /* 40798c2ecf20Sopenharmony_ci * Fatal errors are programmed to be signalled in irq vector 40808c2ecf20Sopenharmony_ci * pm8001_ha->max_q_num - 1 through pm8001_ha->main_cfg_tbl.pm80xx_tbl. 40818c2ecf20Sopenharmony_ci * fatal_err_interrupt 40828c2ecf20Sopenharmony_ci */ 40838c2ecf20Sopenharmony_ci if (vec == (pm8001_ha->max_q_num - 1)) { 40848c2ecf20Sopenharmony_ci u32 mipsall_ready; 40858c2ecf20Sopenharmony_ci 40868c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8008 || 40878c2ecf20Sopenharmony_ci pm8001_ha->chip_id == chip_8009) 40888c2ecf20Sopenharmony_ci mipsall_ready = SCRATCH_PAD_MIPSALL_READY_8PORT; 40898c2ecf20Sopenharmony_ci else 40908c2ecf20Sopenharmony_ci mipsall_ready = SCRATCH_PAD_MIPSALL_READY_16PORT; 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ci regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); 40938c2ecf20Sopenharmony_ci if ((regval & mipsall_ready) != mipsall_ready) { 40948c2ecf20Sopenharmony_ci pm8001_ha->controller_fatal_error = true; 40958c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 40968c2ecf20Sopenharmony_ci "Firmware Fatal error! Regval:0x%x\n", 40978c2ecf20Sopenharmony_ci regval); 40988c2ecf20Sopenharmony_ci print_scratchpad_registers(pm8001_ha); 40998c2ecf20Sopenharmony_ci return ret; 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci } 41028c2ecf20Sopenharmony_ci spin_lock_irqsave(&pm8001_ha->lock, flags); 41038c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->outbnd_q_tbl[vec]; 41048c2ecf20Sopenharmony_ci do { 41058c2ecf20Sopenharmony_ci /* spurious interrupt during setup if kexec-ing and 41068c2ecf20Sopenharmony_ci * driver doing a doorbell access w/ the pre-kexec oq 41078c2ecf20Sopenharmony_ci * interrupt setup. 41088c2ecf20Sopenharmony_ci */ 41098c2ecf20Sopenharmony_ci if (!circularQ->pi_virt) 41108c2ecf20Sopenharmony_ci break; 41118c2ecf20Sopenharmony_ci ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); 41128c2ecf20Sopenharmony_ci if (MPI_IO_STATUS_SUCCESS == ret) { 41138c2ecf20Sopenharmony_ci /* process the outbound message */ 41148c2ecf20Sopenharmony_ci process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4)); 41158c2ecf20Sopenharmony_ci /* free the message from the outbound circular buffer */ 41168c2ecf20Sopenharmony_ci pm8001_mpi_msg_free_set(pm8001_ha, pMsg1, 41178c2ecf20Sopenharmony_ci circularQ, bc); 41188c2ecf20Sopenharmony_ci } 41198c2ecf20Sopenharmony_ci if (MPI_IO_STATUS_BUSY == ret) { 41208c2ecf20Sopenharmony_ci /* Update the producer index from SPC */ 41218c2ecf20Sopenharmony_ci circularQ->producer_index = 41228c2ecf20Sopenharmony_ci cpu_to_le32(pm8001_read_32(circularQ->pi_virt)); 41238c2ecf20Sopenharmony_ci if (le32_to_cpu(circularQ->producer_index) == 41248c2ecf20Sopenharmony_ci circularQ->consumer_idx) 41258c2ecf20Sopenharmony_ci /* OQ is empty */ 41268c2ecf20Sopenharmony_ci break; 41278c2ecf20Sopenharmony_ci } 41288c2ecf20Sopenharmony_ci } while (1); 41298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&pm8001_ha->lock, flags); 41308c2ecf20Sopenharmony_ci return ret; 41318c2ecf20Sopenharmony_ci} 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci/* DMA_... to our direction translation. */ 41348c2ecf20Sopenharmony_cistatic const u8 data_dir_flags[] = { 41358c2ecf20Sopenharmony_ci [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ 41368c2ecf20Sopenharmony_ci [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */ 41378c2ecf20Sopenharmony_ci [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */ 41388c2ecf20Sopenharmony_ci [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ 41398c2ecf20Sopenharmony_ci}; 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_cistatic void build_smp_cmd(u32 deviceID, __le32 hTag, 41428c2ecf20Sopenharmony_ci struct smp_req *psmp_cmd, int mode, int length) 41438c2ecf20Sopenharmony_ci{ 41448c2ecf20Sopenharmony_ci psmp_cmd->tag = hTag; 41458c2ecf20Sopenharmony_ci psmp_cmd->device_id = cpu_to_le32(deviceID); 41468c2ecf20Sopenharmony_ci if (mode == SMP_DIRECT) { 41478c2ecf20Sopenharmony_ci length = length - 4; /* subtract crc */ 41488c2ecf20Sopenharmony_ci psmp_cmd->len_ip_ir = cpu_to_le32(length << 16); 41498c2ecf20Sopenharmony_ci } else { 41508c2ecf20Sopenharmony_ci psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1)); 41518c2ecf20Sopenharmony_ci } 41528c2ecf20Sopenharmony_ci} 41538c2ecf20Sopenharmony_ci 41548c2ecf20Sopenharmony_ci/** 41558c2ecf20Sopenharmony_ci * pm8001_chip_smp_req - send a SMP task to FW 41568c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 41578c2ecf20Sopenharmony_ci * @ccb: the ccb information this request used. 41588c2ecf20Sopenharmony_ci */ 41598c2ecf20Sopenharmony_cistatic int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, 41608c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb) 41618c2ecf20Sopenharmony_ci{ 41628c2ecf20Sopenharmony_ci int elem, rc; 41638c2ecf20Sopenharmony_ci struct sas_task *task = ccb->task; 41648c2ecf20Sopenharmony_ci struct domain_device *dev = task->dev; 41658c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev = dev->lldd_dev; 41668c2ecf20Sopenharmony_ci struct scatterlist *sg_req, *sg_resp; 41678c2ecf20Sopenharmony_ci u32 req_len, resp_len; 41688c2ecf20Sopenharmony_ci struct smp_req smp_cmd; 41698c2ecf20Sopenharmony_ci u32 opc; 41708c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 41718c2ecf20Sopenharmony_ci char *preq_dma_addr = NULL; 41728c2ecf20Sopenharmony_ci __le64 tmp_addr; 41738c2ecf20Sopenharmony_ci u32 i, length; 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci memset(&smp_cmd, 0, sizeof(smp_cmd)); 41768c2ecf20Sopenharmony_ci /* 41778c2ecf20Sopenharmony_ci * DMA-map SMP request, response buffers 41788c2ecf20Sopenharmony_ci */ 41798c2ecf20Sopenharmony_ci sg_req = &task->smp_task.smp_req; 41808c2ecf20Sopenharmony_ci elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE); 41818c2ecf20Sopenharmony_ci if (!elem) 41828c2ecf20Sopenharmony_ci return -ENOMEM; 41838c2ecf20Sopenharmony_ci req_len = sg_dma_len(sg_req); 41848c2ecf20Sopenharmony_ci 41858c2ecf20Sopenharmony_ci sg_resp = &task->smp_task.smp_resp; 41868c2ecf20Sopenharmony_ci elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE); 41878c2ecf20Sopenharmony_ci if (!elem) { 41888c2ecf20Sopenharmony_ci rc = -ENOMEM; 41898c2ecf20Sopenharmony_ci goto err_out; 41908c2ecf20Sopenharmony_ci } 41918c2ecf20Sopenharmony_ci resp_len = sg_dma_len(sg_resp); 41928c2ecf20Sopenharmony_ci /* must be in dwords */ 41938c2ecf20Sopenharmony_ci if ((req_len & 0x3) || (resp_len & 0x3)) { 41948c2ecf20Sopenharmony_ci rc = -EINVAL; 41958c2ecf20Sopenharmony_ci goto err_out_2; 41968c2ecf20Sopenharmony_ci } 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci opc = OPC_INB_SMP_REQUEST; 41998c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 42008c2ecf20Sopenharmony_ci smp_cmd.tag = cpu_to_le32(ccb->ccb_tag); 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci length = sg_req->length; 42038c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "SMP Frame Length %d\n", sg_req->length); 42048c2ecf20Sopenharmony_ci if (!(length - 8)) 42058c2ecf20Sopenharmony_ci pm8001_ha->smp_exp_mode = SMP_DIRECT; 42068c2ecf20Sopenharmony_ci else 42078c2ecf20Sopenharmony_ci pm8001_ha->smp_exp_mode = SMP_INDIRECT; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci tmp_addr = cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req)); 42118c2ecf20Sopenharmony_ci preq_dma_addr = (char *)phys_to_virt(tmp_addr); 42128c2ecf20Sopenharmony_ci 42138c2ecf20Sopenharmony_ci /* INDIRECT MODE command settings. Use DMA */ 42148c2ecf20Sopenharmony_ci if (pm8001_ha->smp_exp_mode == SMP_INDIRECT) { 42158c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "SMP REQUEST INDIRECT MODE\n"); 42168c2ecf20Sopenharmony_ci /* for SPCv indirect mode. Place the top 4 bytes of 42178c2ecf20Sopenharmony_ci * SMP Request header here. */ 42188c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 42198c2ecf20Sopenharmony_ci smp_cmd.smp_req16[i] = *(preq_dma_addr + i); 42208c2ecf20Sopenharmony_ci /* exclude top 4 bytes for SMP req header */ 42218c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_req_addr = 42228c2ecf20Sopenharmony_ci cpu_to_le64((u64)sg_dma_address 42238c2ecf20Sopenharmony_ci (&task->smp_task.smp_req) + 4); 42248c2ecf20Sopenharmony_ci /* exclude 4 bytes for SMP req header and CRC */ 42258c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_req_size = 42268c2ecf20Sopenharmony_ci cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-8); 42278c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_resp_addr = 42288c2ecf20Sopenharmony_ci cpu_to_le64((u64)sg_dma_address 42298c2ecf20Sopenharmony_ci (&task->smp_task.smp_resp)); 42308c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_resp_size = 42318c2ecf20Sopenharmony_ci cpu_to_le32((u32)sg_dma_len 42328c2ecf20Sopenharmony_ci (&task->smp_task.smp_resp)-4); 42338c2ecf20Sopenharmony_ci } else { /* DIRECT MODE */ 42348c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_req_addr = 42358c2ecf20Sopenharmony_ci cpu_to_le64((u64)sg_dma_address 42368c2ecf20Sopenharmony_ci (&task->smp_task.smp_req)); 42378c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_req_size = 42388c2ecf20Sopenharmony_ci cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4); 42398c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_resp_addr = 42408c2ecf20Sopenharmony_ci cpu_to_le64((u64)sg_dma_address 42418c2ecf20Sopenharmony_ci (&task->smp_task.smp_resp)); 42428c2ecf20Sopenharmony_ci smp_cmd.long_smp_req.long_resp_size = 42438c2ecf20Sopenharmony_ci cpu_to_le32 42448c2ecf20Sopenharmony_ci ((u32)sg_dma_len(&task->smp_task.smp_resp)-4); 42458c2ecf20Sopenharmony_ci } 42468c2ecf20Sopenharmony_ci if (pm8001_ha->smp_exp_mode == SMP_DIRECT) { 42478c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "SMP REQUEST DIRECT MODE\n"); 42488c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) 42498c2ecf20Sopenharmony_ci if (i < 16) { 42508c2ecf20Sopenharmony_ci smp_cmd.smp_req16[i] = *(preq_dma_addr+i); 42518c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 42528c2ecf20Sopenharmony_ci "Byte[%d]:%x (DMA data:%x)\n", 42538c2ecf20Sopenharmony_ci i, smp_cmd.smp_req16[i], 42548c2ecf20Sopenharmony_ci *(preq_dma_addr)); 42558c2ecf20Sopenharmony_ci } else { 42568c2ecf20Sopenharmony_ci smp_cmd.smp_req[i] = *(preq_dma_addr+i); 42578c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 42588c2ecf20Sopenharmony_ci "Byte[%d]:%x (DMA data:%x)\n", 42598c2ecf20Sopenharmony_ci i, smp_cmd.smp_req[i], 42608c2ecf20Sopenharmony_ci *(preq_dma_addr)); 42618c2ecf20Sopenharmony_ci } 42628c2ecf20Sopenharmony_ci } 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, 42658c2ecf20Sopenharmony_ci &smp_cmd, pm8001_ha->smp_exp_mode, length); 42668c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &smp_cmd, 42678c2ecf20Sopenharmony_ci sizeof(smp_cmd), 0); 42688c2ecf20Sopenharmony_ci if (rc) 42698c2ecf20Sopenharmony_ci goto err_out_2; 42708c2ecf20Sopenharmony_ci return 0; 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_cierr_out_2: 42738c2ecf20Sopenharmony_ci dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1, 42748c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 42758c2ecf20Sopenharmony_cierr_out: 42768c2ecf20Sopenharmony_ci dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1, 42778c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 42788c2ecf20Sopenharmony_ci return rc; 42798c2ecf20Sopenharmony_ci} 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_cistatic int check_enc_sas_cmd(struct sas_task *task) 42828c2ecf20Sopenharmony_ci{ 42838c2ecf20Sopenharmony_ci u8 cmd = task->ssp_task.cmd->cmnd[0]; 42848c2ecf20Sopenharmony_ci 42858c2ecf20Sopenharmony_ci if (cmd == READ_10 || cmd == WRITE_10 || cmd == WRITE_VERIFY) 42868c2ecf20Sopenharmony_ci return 1; 42878c2ecf20Sopenharmony_ci else 42888c2ecf20Sopenharmony_ci return 0; 42898c2ecf20Sopenharmony_ci} 42908c2ecf20Sopenharmony_ci 42918c2ecf20Sopenharmony_cistatic int check_enc_sat_cmd(struct sas_task *task) 42928c2ecf20Sopenharmony_ci{ 42938c2ecf20Sopenharmony_ci int ret = 0; 42948c2ecf20Sopenharmony_ci switch (task->ata_task.fis.command) { 42958c2ecf20Sopenharmony_ci case ATA_CMD_FPDMA_READ: 42968c2ecf20Sopenharmony_ci case ATA_CMD_READ_EXT: 42978c2ecf20Sopenharmony_ci case ATA_CMD_READ: 42988c2ecf20Sopenharmony_ci case ATA_CMD_FPDMA_WRITE: 42998c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_EXT: 43008c2ecf20Sopenharmony_ci case ATA_CMD_WRITE: 43018c2ecf20Sopenharmony_ci case ATA_CMD_PIO_READ: 43028c2ecf20Sopenharmony_ci case ATA_CMD_PIO_READ_EXT: 43038c2ecf20Sopenharmony_ci case ATA_CMD_PIO_WRITE: 43048c2ecf20Sopenharmony_ci case ATA_CMD_PIO_WRITE_EXT: 43058c2ecf20Sopenharmony_ci ret = 1; 43068c2ecf20Sopenharmony_ci break; 43078c2ecf20Sopenharmony_ci default: 43088c2ecf20Sopenharmony_ci ret = 0; 43098c2ecf20Sopenharmony_ci break; 43108c2ecf20Sopenharmony_ci } 43118c2ecf20Sopenharmony_ci return ret; 43128c2ecf20Sopenharmony_ci} 43138c2ecf20Sopenharmony_ci 43148c2ecf20Sopenharmony_ci/** 43158c2ecf20Sopenharmony_ci * pm80xx_chip_ssp_io_req - send a SSP task to FW 43168c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 43178c2ecf20Sopenharmony_ci * @ccb: the ccb information this request used. 43188c2ecf20Sopenharmony_ci */ 43198c2ecf20Sopenharmony_cistatic int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, 43208c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb) 43218c2ecf20Sopenharmony_ci{ 43228c2ecf20Sopenharmony_ci struct sas_task *task = ccb->task; 43238c2ecf20Sopenharmony_ci struct domain_device *dev = task->dev; 43248c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev = dev->lldd_dev; 43258c2ecf20Sopenharmony_ci struct ssp_ini_io_start_req ssp_cmd; 43268c2ecf20Sopenharmony_ci u32 tag = ccb->ccb_tag; 43278c2ecf20Sopenharmony_ci int ret; 43288c2ecf20Sopenharmony_ci u64 phys_addr, end_addr; 43298c2ecf20Sopenharmony_ci u32 end_addr_high, end_addr_low; 43308c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 43318c2ecf20Sopenharmony_ci u32 q_index, cpu_id; 43328c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SSPINIIOSTART; 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci memset(&ssp_cmd, 0, sizeof(ssp_cmd)); 43358c2ecf20Sopenharmony_ci memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); 43368c2ecf20Sopenharmony_ci 43378c2ecf20Sopenharmony_ci /* data address domain added for spcv; set to 0 by host, 43388c2ecf20Sopenharmony_ci * used internally by controller 43398c2ecf20Sopenharmony_ci * 0 for SAS 1.1 and SAS 2.0 compatible TLR 43408c2ecf20Sopenharmony_ci */ 43418c2ecf20Sopenharmony_ci ssp_cmd.dad_dir_m_tlr = 43428c2ecf20Sopenharmony_ci cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0); 43438c2ecf20Sopenharmony_ci ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len); 43448c2ecf20Sopenharmony_ci ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id); 43458c2ecf20Sopenharmony_ci ssp_cmd.tag = cpu_to_le32(tag); 43468c2ecf20Sopenharmony_ci if (task->ssp_task.enable_first_burst) 43478c2ecf20Sopenharmony_ci ssp_cmd.ssp_iu.efb_prio_attr = 0x80; 43488c2ecf20Sopenharmony_ci ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3); 43498c2ecf20Sopenharmony_ci ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7); 43508c2ecf20Sopenharmony_ci memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd, 43518c2ecf20Sopenharmony_ci task->ssp_task.cmd->cmd_len); 43528c2ecf20Sopenharmony_ci cpu_id = smp_processor_id(); 43538c2ecf20Sopenharmony_ci q_index = (u32) (cpu_id) % (pm8001_ha->max_q_num); 43548c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[q_index]; 43558c2ecf20Sopenharmony_ci 43568c2ecf20Sopenharmony_ci /* Check if encryption is set */ 43578c2ecf20Sopenharmony_ci if (pm8001_ha->chip->encrypt && 43588c2ecf20Sopenharmony_ci !(pm8001_ha->encrypt_info.status) && check_enc_sas_cmd(task)) { 43598c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 43608c2ecf20Sopenharmony_ci "Encryption enabled.Sending Encrypt SAS command 0x%x\n", 43618c2ecf20Sopenharmony_ci task->ssp_task.cmd->cmnd[0]); 43628c2ecf20Sopenharmony_ci opc = OPC_INB_SSP_INI_DIF_ENC_IO; 43638c2ecf20Sopenharmony_ci /* enable encryption. 0 for SAS 1.1 and SAS 2.0 compatible TLR*/ 43648c2ecf20Sopenharmony_ci ssp_cmd.dad_dir_m_tlr = cpu_to_le32 43658c2ecf20Sopenharmony_ci ((data_dir_flags[task->data_dir] << 8) | 0x20 | 0x0); 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 43688c2ecf20Sopenharmony_ci if (task->num_scatter > 1) { 43698c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 43708c2ecf20Sopenharmony_ci ccb->n_elem, ccb->buf_prd); 43718c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 43728c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_low = 43738c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(phys_addr)); 43748c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_high = 43758c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(phys_addr)); 43768c2ecf20Sopenharmony_ci ssp_cmd.enc_esgl = cpu_to_le32(1<<31); 43778c2ecf20Sopenharmony_ci } else if (task->num_scatter == 1) { 43788c2ecf20Sopenharmony_ci u64 dma_addr = sg_dma_address(task->scatter); 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_low = 43818c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_addr)); 43828c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_high = 43838c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_addr)); 43848c2ecf20Sopenharmony_ci ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); 43858c2ecf20Sopenharmony_ci ssp_cmd.enc_esgl = 0; 43868c2ecf20Sopenharmony_ci 43878c2ecf20Sopenharmony_ci /* Check 4G Boundary */ 43888c2ecf20Sopenharmony_ci end_addr = dma_addr + le32_to_cpu(ssp_cmd.enc_len) - 1; 43898c2ecf20Sopenharmony_ci end_addr_low = lower_32_bits(end_addr); 43908c2ecf20Sopenharmony_ci end_addr_high = upper_32_bits(end_addr); 43918c2ecf20Sopenharmony_ci 43928c2ecf20Sopenharmony_ci if (end_addr_high != le32_to_cpu(ssp_cmd.enc_addr_high)) { 43938c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 43948c2ecf20Sopenharmony_ci "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", 43958c2ecf20Sopenharmony_ci dma_addr, 43968c2ecf20Sopenharmony_ci le32_to_cpu(ssp_cmd.enc_len), 43978c2ecf20Sopenharmony_ci end_addr_high, end_addr_low); 43988c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 1, 43998c2ecf20Sopenharmony_ci ccb->buf_prd); 44008c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 44018c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_low = 44028c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(phys_addr)); 44038c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_high = 44048c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(phys_addr)); 44058c2ecf20Sopenharmony_ci ssp_cmd.enc_esgl = cpu_to_le32(1U<<31); 44068c2ecf20Sopenharmony_ci } 44078c2ecf20Sopenharmony_ci } else if (task->num_scatter == 0) { 44088c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_low = 0; 44098c2ecf20Sopenharmony_ci ssp_cmd.enc_addr_high = 0; 44108c2ecf20Sopenharmony_ci ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); 44118c2ecf20Sopenharmony_ci ssp_cmd.enc_esgl = 0; 44128c2ecf20Sopenharmony_ci } 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ci /* XTS mode. All other fields are 0 */ 44158c2ecf20Sopenharmony_ci ssp_cmd.key_cmode = cpu_to_le32(0x6 << 4); 44168c2ecf20Sopenharmony_ci 44178c2ecf20Sopenharmony_ci /* set tweak values. Should be the start lba */ 44188c2ecf20Sopenharmony_ci ssp_cmd.twk_val0 = cpu_to_le32((task->ssp_task.cmd->cmnd[2] << 24) | 44198c2ecf20Sopenharmony_ci (task->ssp_task.cmd->cmnd[3] << 16) | 44208c2ecf20Sopenharmony_ci (task->ssp_task.cmd->cmnd[4] << 8) | 44218c2ecf20Sopenharmony_ci (task->ssp_task.cmd->cmnd[5])); 44228c2ecf20Sopenharmony_ci } else { 44238c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 44248c2ecf20Sopenharmony_ci "Sending Normal SAS command 0x%x inb q %x\n", 44258c2ecf20Sopenharmony_ci task->ssp_task.cmd->cmnd[0], q_index); 44268c2ecf20Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 44278c2ecf20Sopenharmony_ci if (task->num_scatter > 1) { 44288c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, ccb->n_elem, 44298c2ecf20Sopenharmony_ci ccb->buf_prd); 44308c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 44318c2ecf20Sopenharmony_ci ssp_cmd.addr_low = 44328c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(phys_addr)); 44338c2ecf20Sopenharmony_ci ssp_cmd.addr_high = 44348c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(phys_addr)); 44358c2ecf20Sopenharmony_ci ssp_cmd.esgl = cpu_to_le32(1<<31); 44368c2ecf20Sopenharmony_ci } else if (task->num_scatter == 1) { 44378c2ecf20Sopenharmony_ci u64 dma_addr = sg_dma_address(task->scatter); 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ci ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr)); 44408c2ecf20Sopenharmony_ci ssp_cmd.addr_high = 44418c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_addr)); 44428c2ecf20Sopenharmony_ci ssp_cmd.len = cpu_to_le32(task->total_xfer_len); 44438c2ecf20Sopenharmony_ci ssp_cmd.esgl = 0; 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci /* Check 4G Boundary */ 44468c2ecf20Sopenharmony_ci end_addr = dma_addr + le32_to_cpu(ssp_cmd.len) - 1; 44478c2ecf20Sopenharmony_ci end_addr_low = lower_32_bits(end_addr); 44488c2ecf20Sopenharmony_ci end_addr_high = upper_32_bits(end_addr); 44498c2ecf20Sopenharmony_ci if (end_addr_high != le32_to_cpu(ssp_cmd.addr_high)) { 44508c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 44518c2ecf20Sopenharmony_ci "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", 44528c2ecf20Sopenharmony_ci dma_addr, 44538c2ecf20Sopenharmony_ci le32_to_cpu(ssp_cmd.len), 44548c2ecf20Sopenharmony_ci end_addr_high, end_addr_low); 44558c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 1, 44568c2ecf20Sopenharmony_ci ccb->buf_prd); 44578c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 44588c2ecf20Sopenharmony_ci ssp_cmd.addr_low = 44598c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(phys_addr)); 44608c2ecf20Sopenharmony_ci ssp_cmd.addr_high = 44618c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(phys_addr)); 44628c2ecf20Sopenharmony_ci ssp_cmd.esgl = cpu_to_le32(1<<31); 44638c2ecf20Sopenharmony_ci } 44648c2ecf20Sopenharmony_ci } else if (task->num_scatter == 0) { 44658c2ecf20Sopenharmony_ci ssp_cmd.addr_low = 0; 44668c2ecf20Sopenharmony_ci ssp_cmd.addr_high = 0; 44678c2ecf20Sopenharmony_ci ssp_cmd.len = cpu_to_le32(task->total_xfer_len); 44688c2ecf20Sopenharmony_ci ssp_cmd.esgl = 0; 44698c2ecf20Sopenharmony_ci } 44708c2ecf20Sopenharmony_ci } 44718c2ecf20Sopenharmony_ci ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, 44728c2ecf20Sopenharmony_ci &ssp_cmd, sizeof(ssp_cmd), q_index); 44738c2ecf20Sopenharmony_ci return ret; 44748c2ecf20Sopenharmony_ci} 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_cistatic int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, 44778c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb) 44788c2ecf20Sopenharmony_ci{ 44798c2ecf20Sopenharmony_ci struct sas_task *task = ccb->task; 44808c2ecf20Sopenharmony_ci struct domain_device *dev = task->dev; 44818c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_ha_dev = dev->lldd_dev; 44828c2ecf20Sopenharmony_ci u32 tag = ccb->ccb_tag; 44838c2ecf20Sopenharmony_ci int ret; 44848c2ecf20Sopenharmony_ci u32 q_index, cpu_id; 44858c2ecf20Sopenharmony_ci struct sata_start_req sata_cmd; 44868c2ecf20Sopenharmony_ci u32 hdr_tag, ncg_tag = 0; 44878c2ecf20Sopenharmony_ci u64 phys_addr, end_addr; 44888c2ecf20Sopenharmony_ci u32 end_addr_high, end_addr_low; 44898c2ecf20Sopenharmony_ci u32 ATAP = 0x0; 44908c2ecf20Sopenharmony_ci u32 dir; 44918c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 44928c2ecf20Sopenharmony_ci unsigned long flags; 44938c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SATA_HOST_OPSTART; 44948c2ecf20Sopenharmony_ci memset(&sata_cmd, 0, sizeof(sata_cmd)); 44958c2ecf20Sopenharmony_ci cpu_id = smp_processor_id(); 44968c2ecf20Sopenharmony_ci q_index = (u32) (cpu_id) % (pm8001_ha->max_q_num); 44978c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[q_index]; 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) { 45008c2ecf20Sopenharmony_ci ATAP = 0x04; /* no data*/ 45018c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "no data\n"); 45028c2ecf20Sopenharmony_ci } else if (likely(!task->ata_task.device_control_reg_update)) { 45038c2ecf20Sopenharmony_ci if (task->ata_task.use_ncq && 45048c2ecf20Sopenharmony_ci dev->sata_dev.class != ATA_DEV_ATAPI) { 45058c2ecf20Sopenharmony_ci ATAP = 0x07; /* FPDMA */ 45068c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "FPDMA\n"); 45078c2ecf20Sopenharmony_ci } else if (task->ata_task.dma_xfer) { 45088c2ecf20Sopenharmony_ci ATAP = 0x06; /* DMA */ 45098c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "DMA\n"); 45108c2ecf20Sopenharmony_ci } else { 45118c2ecf20Sopenharmony_ci ATAP = 0x05; /* PIO*/ 45128c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, "PIO\n"); 45138c2ecf20Sopenharmony_ci } 45148c2ecf20Sopenharmony_ci } 45158c2ecf20Sopenharmony_ci if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) { 45168c2ecf20Sopenharmony_ci task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); 45178c2ecf20Sopenharmony_ci ncg_tag = hdr_tag; 45188c2ecf20Sopenharmony_ci } 45198c2ecf20Sopenharmony_ci dir = data_dir_flags[task->data_dir] << 8; 45208c2ecf20Sopenharmony_ci sata_cmd.tag = cpu_to_le32(tag); 45218c2ecf20Sopenharmony_ci sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); 45228c2ecf20Sopenharmony_ci sata_cmd.data_len = cpu_to_le32(task->total_xfer_len); 45238c2ecf20Sopenharmony_ci 45248c2ecf20Sopenharmony_ci sata_cmd.sata_fis = task->ata_task.fis; 45258c2ecf20Sopenharmony_ci if (likely(!task->ata_task.device_control_reg_update)) 45268c2ecf20Sopenharmony_ci sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */ 45278c2ecf20Sopenharmony_ci sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */ 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci /* Check if encryption is set */ 45308c2ecf20Sopenharmony_ci if (pm8001_ha->chip->encrypt && 45318c2ecf20Sopenharmony_ci !(pm8001_ha->encrypt_info.status) && check_enc_sat_cmd(task)) { 45328c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 45338c2ecf20Sopenharmony_ci "Encryption enabled.Sending Encrypt SATA cmd 0x%x\n", 45348c2ecf20Sopenharmony_ci sata_cmd.sata_fis.command); 45358c2ecf20Sopenharmony_ci opc = OPC_INB_SATA_DIF_ENC_IO; 45368c2ecf20Sopenharmony_ci 45378c2ecf20Sopenharmony_ci /* set encryption bit */ 45388c2ecf20Sopenharmony_ci sata_cmd.ncqtag_atap_dir_m_dad = 45398c2ecf20Sopenharmony_ci cpu_to_le32(((ncg_tag & 0xff)<<16)| 45408c2ecf20Sopenharmony_ci ((ATAP & 0x3f) << 10) | 0x20 | dir); 45418c2ecf20Sopenharmony_ci /* dad (bit 0-1) is 0 */ 45428c2ecf20Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 45438c2ecf20Sopenharmony_ci if (task->num_scatter > 1) { 45448c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 45458c2ecf20Sopenharmony_ci ccb->n_elem, ccb->buf_prd); 45468c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 45478c2ecf20Sopenharmony_ci sata_cmd.enc_addr_low = 45488c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(phys_addr)); 45498c2ecf20Sopenharmony_ci sata_cmd.enc_addr_high = 45508c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(phys_addr)); 45518c2ecf20Sopenharmony_ci sata_cmd.enc_esgl = cpu_to_le32(1 << 31); 45528c2ecf20Sopenharmony_ci } else if (task->num_scatter == 1) { 45538c2ecf20Sopenharmony_ci u64 dma_addr = sg_dma_address(task->scatter); 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci sata_cmd.enc_addr_low = 45568c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(dma_addr)); 45578c2ecf20Sopenharmony_ci sata_cmd.enc_addr_high = 45588c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(dma_addr)); 45598c2ecf20Sopenharmony_ci sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); 45608c2ecf20Sopenharmony_ci sata_cmd.enc_esgl = 0; 45618c2ecf20Sopenharmony_ci 45628c2ecf20Sopenharmony_ci /* Check 4G Boundary */ 45638c2ecf20Sopenharmony_ci end_addr = dma_addr + le32_to_cpu(sata_cmd.enc_len) - 1; 45648c2ecf20Sopenharmony_ci end_addr_low = lower_32_bits(end_addr); 45658c2ecf20Sopenharmony_ci end_addr_high = upper_32_bits(end_addr); 45668c2ecf20Sopenharmony_ci if (end_addr_high != le32_to_cpu(sata_cmd.enc_addr_high)) { 45678c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 45688c2ecf20Sopenharmony_ci "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", 45698c2ecf20Sopenharmony_ci dma_addr, 45708c2ecf20Sopenharmony_ci le32_to_cpu(sata_cmd.enc_len), 45718c2ecf20Sopenharmony_ci end_addr_high, end_addr_low); 45728c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 1, 45738c2ecf20Sopenharmony_ci ccb->buf_prd); 45748c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 45758c2ecf20Sopenharmony_ci sata_cmd.enc_addr_low = 45768c2ecf20Sopenharmony_ci cpu_to_le32(lower_32_bits(phys_addr)); 45778c2ecf20Sopenharmony_ci sata_cmd.enc_addr_high = 45788c2ecf20Sopenharmony_ci cpu_to_le32(upper_32_bits(phys_addr)); 45798c2ecf20Sopenharmony_ci sata_cmd.enc_esgl = 45808c2ecf20Sopenharmony_ci cpu_to_le32(1 << 31); 45818c2ecf20Sopenharmony_ci } 45828c2ecf20Sopenharmony_ci } else if (task->num_scatter == 0) { 45838c2ecf20Sopenharmony_ci sata_cmd.enc_addr_low = 0; 45848c2ecf20Sopenharmony_ci sata_cmd.enc_addr_high = 0; 45858c2ecf20Sopenharmony_ci sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); 45868c2ecf20Sopenharmony_ci sata_cmd.enc_esgl = 0; 45878c2ecf20Sopenharmony_ci } 45888c2ecf20Sopenharmony_ci /* XTS mode. All other fields are 0 */ 45898c2ecf20Sopenharmony_ci sata_cmd.key_index_mode = cpu_to_le32(0x6 << 4); 45908c2ecf20Sopenharmony_ci 45918c2ecf20Sopenharmony_ci /* set tweak values. Should be the start lba */ 45928c2ecf20Sopenharmony_ci sata_cmd.twk_val0 = 45938c2ecf20Sopenharmony_ci cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) | 45948c2ecf20Sopenharmony_ci (sata_cmd.sata_fis.lbah << 16) | 45958c2ecf20Sopenharmony_ci (sata_cmd.sata_fis.lbam << 8) | 45968c2ecf20Sopenharmony_ci (sata_cmd.sata_fis.lbal)); 45978c2ecf20Sopenharmony_ci sata_cmd.twk_val1 = 45988c2ecf20Sopenharmony_ci cpu_to_le32((sata_cmd.sata_fis.lbah_exp << 8) | 45998c2ecf20Sopenharmony_ci (sata_cmd.sata_fis.lbam_exp)); 46008c2ecf20Sopenharmony_ci } else { 46018c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, IO, 46028c2ecf20Sopenharmony_ci "Sending Normal SATA command 0x%x inb %x\n", 46038c2ecf20Sopenharmony_ci sata_cmd.sata_fis.command, q_index); 46048c2ecf20Sopenharmony_ci /* dad (bit 0-1) is 0 */ 46058c2ecf20Sopenharmony_ci sata_cmd.ncqtag_atap_dir_m_dad = 46068c2ecf20Sopenharmony_ci cpu_to_le32(((ncg_tag & 0xff)<<16) | 46078c2ecf20Sopenharmony_ci ((ATAP & 0x3f) << 10) | dir); 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_ci /* fill in PRD (scatter/gather) table, if any */ 46108c2ecf20Sopenharmony_ci if (task->num_scatter > 1) { 46118c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 46128c2ecf20Sopenharmony_ci ccb->n_elem, ccb->buf_prd); 46138c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 46148c2ecf20Sopenharmony_ci sata_cmd.addr_low = lower_32_bits(phys_addr); 46158c2ecf20Sopenharmony_ci sata_cmd.addr_high = upper_32_bits(phys_addr); 46168c2ecf20Sopenharmony_ci sata_cmd.esgl = cpu_to_le32(1U << 31); 46178c2ecf20Sopenharmony_ci } else if (task->num_scatter == 1) { 46188c2ecf20Sopenharmony_ci u64 dma_addr = sg_dma_address(task->scatter); 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ci sata_cmd.addr_low = lower_32_bits(dma_addr); 46218c2ecf20Sopenharmony_ci sata_cmd.addr_high = upper_32_bits(dma_addr); 46228c2ecf20Sopenharmony_ci sata_cmd.len = cpu_to_le32(task->total_xfer_len); 46238c2ecf20Sopenharmony_ci sata_cmd.esgl = 0; 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci /* Check 4G Boundary */ 46268c2ecf20Sopenharmony_ci end_addr = dma_addr + le32_to_cpu(sata_cmd.len) - 1; 46278c2ecf20Sopenharmony_ci end_addr_low = lower_32_bits(end_addr); 46288c2ecf20Sopenharmony_ci end_addr_high = upper_32_bits(end_addr); 46298c2ecf20Sopenharmony_ci if (end_addr_high != sata_cmd.addr_high) { 46308c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 46318c2ecf20Sopenharmony_ci "The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n", 46328c2ecf20Sopenharmony_ci dma_addr, 46338c2ecf20Sopenharmony_ci le32_to_cpu(sata_cmd.len), 46348c2ecf20Sopenharmony_ci end_addr_high, end_addr_low); 46358c2ecf20Sopenharmony_ci pm8001_chip_make_sg(task->scatter, 1, 46368c2ecf20Sopenharmony_ci ccb->buf_prd); 46378c2ecf20Sopenharmony_ci phys_addr = ccb->ccb_dma_handle; 46388c2ecf20Sopenharmony_ci sata_cmd.addr_low = lower_32_bits(phys_addr); 46398c2ecf20Sopenharmony_ci sata_cmd.addr_high = upper_32_bits(phys_addr); 46408c2ecf20Sopenharmony_ci sata_cmd.esgl = cpu_to_le32(1U << 31); 46418c2ecf20Sopenharmony_ci } 46428c2ecf20Sopenharmony_ci } else if (task->num_scatter == 0) { 46438c2ecf20Sopenharmony_ci sata_cmd.addr_low = 0; 46448c2ecf20Sopenharmony_ci sata_cmd.addr_high = 0; 46458c2ecf20Sopenharmony_ci sata_cmd.len = cpu_to_le32(task->total_xfer_len); 46468c2ecf20Sopenharmony_ci sata_cmd.esgl = 0; 46478c2ecf20Sopenharmony_ci } 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_ci /* scsi cdb */ 46508c2ecf20Sopenharmony_ci sata_cmd.atapi_scsi_cdb[0] = 46518c2ecf20Sopenharmony_ci cpu_to_le32(((task->ata_task.atapi_packet[0]) | 46528c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[1] << 8) | 46538c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[2] << 16) | 46548c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[3] << 24))); 46558c2ecf20Sopenharmony_ci sata_cmd.atapi_scsi_cdb[1] = 46568c2ecf20Sopenharmony_ci cpu_to_le32(((task->ata_task.atapi_packet[4]) | 46578c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[5] << 8) | 46588c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[6] << 16) | 46598c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[7] << 24))); 46608c2ecf20Sopenharmony_ci sata_cmd.atapi_scsi_cdb[2] = 46618c2ecf20Sopenharmony_ci cpu_to_le32(((task->ata_task.atapi_packet[8]) | 46628c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[9] << 8) | 46638c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[10] << 16) | 46648c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[11] << 24))); 46658c2ecf20Sopenharmony_ci sata_cmd.atapi_scsi_cdb[3] = 46668c2ecf20Sopenharmony_ci cpu_to_le32(((task->ata_task.atapi_packet[12]) | 46678c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[13] << 8) | 46688c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[14] << 16) | 46698c2ecf20Sopenharmony_ci (task->ata_task.atapi_packet[15] << 24))); 46708c2ecf20Sopenharmony_ci } 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci /* Check for read log for failed drive and return */ 46738c2ecf20Sopenharmony_ci if (sata_cmd.sata_fis.command == 0x2f) { 46748c2ecf20Sopenharmony_ci if (pm8001_ha_dev && ((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) || 46758c2ecf20Sopenharmony_ci (pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) || 46768c2ecf20Sopenharmony_ci (pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) { 46778c2ecf20Sopenharmony_ci struct task_status_struct *ts; 46788c2ecf20Sopenharmony_ci 46798c2ecf20Sopenharmony_ci pm8001_ha_dev->id &= 0xDFFFFFFF; 46808c2ecf20Sopenharmony_ci ts = &task->task_status; 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 46838c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 46848c2ecf20Sopenharmony_ci ts->stat = SAS_SAM_STAT_GOOD; 46858c2ecf20Sopenharmony_ci task->task_state_flags &= ~SAS_TASK_STATE_PENDING; 46868c2ecf20Sopenharmony_ci task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 46878c2ecf20Sopenharmony_ci task->task_state_flags |= SAS_TASK_STATE_DONE; 46888c2ecf20Sopenharmony_ci if (unlikely((task->task_state_flags & 46898c2ecf20Sopenharmony_ci SAS_TASK_STATE_ABORTED))) { 46908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, 46918c2ecf20Sopenharmony_ci flags); 46928c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 46938c2ecf20Sopenharmony_ci "task 0x%p resp 0x%x stat 0x%x but aborted by upper layer\n", 46948c2ecf20Sopenharmony_ci task, ts->resp, 46958c2ecf20Sopenharmony_ci ts->stat); 46968c2ecf20Sopenharmony_ci pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); 46978c2ecf20Sopenharmony_ci return 0; 46988c2ecf20Sopenharmony_ci } else { 46998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, 47008c2ecf20Sopenharmony_ci flags); 47018c2ecf20Sopenharmony_ci pm8001_ccb_task_free_done(pm8001_ha, task, 47028c2ecf20Sopenharmony_ci ccb, tag); 47038c2ecf20Sopenharmony_ci atomic_dec(&pm8001_ha_dev->running_req); 47048c2ecf20Sopenharmony_ci return 0; 47058c2ecf20Sopenharmony_ci } 47068c2ecf20Sopenharmony_ci } 47078c2ecf20Sopenharmony_ci } 47088c2ecf20Sopenharmony_ci ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, 47098c2ecf20Sopenharmony_ci &sata_cmd, sizeof(sata_cmd), q_index); 47108c2ecf20Sopenharmony_ci return ret; 47118c2ecf20Sopenharmony_ci} 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci/** 47148c2ecf20Sopenharmony_ci * pm80xx_chip_phy_start_req - start phy via PHY_START COMMAND 47158c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 47168c2ecf20Sopenharmony_ci * @phy_id: the phy id which we wanted to start up. 47178c2ecf20Sopenharmony_ci */ 47188c2ecf20Sopenharmony_cistatic int 47198c2ecf20Sopenharmony_cipm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) 47208c2ecf20Sopenharmony_ci{ 47218c2ecf20Sopenharmony_ci struct phy_start_req payload; 47228c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 47238c2ecf20Sopenharmony_ci int ret; 47248c2ecf20Sopenharmony_ci u32 tag = 0x01; 47258c2ecf20Sopenharmony_ci u32 opcode = OPC_INB_PHYSTART; 47268c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 47278c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 47288c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 47298c2ecf20Sopenharmony_ci 47308c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "PHY START REQ for phy_id %d\n", phy_id); 47318c2ecf20Sopenharmony_ci 47328c2ecf20Sopenharmony_ci payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | 47338c2ecf20Sopenharmony_ci LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); 47348c2ecf20Sopenharmony_ci /* SSC Disable and SAS Analog ST configuration */ 47358c2ecf20Sopenharmony_ci /** 47368c2ecf20Sopenharmony_ci payload.ase_sh_lm_slr_phyid = 47378c2ecf20Sopenharmony_ci cpu_to_le32(SSC_DISABLE_30 | SAS_ASE | SPINHOLD_DISABLE | 47388c2ecf20Sopenharmony_ci LINKMODE_AUTO | LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | 47398c2ecf20Sopenharmony_ci phy_id); 47408c2ecf20Sopenharmony_ci Have to add "SAS PHY Analog Setup SPASTI 1 Byte" Based on need 47418c2ecf20Sopenharmony_ci **/ 47428c2ecf20Sopenharmony_ci 47438c2ecf20Sopenharmony_ci payload.sas_identify.dev_type = SAS_END_DEVICE; 47448c2ecf20Sopenharmony_ci payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL; 47458c2ecf20Sopenharmony_ci memcpy(payload.sas_identify.sas_addr, 47468c2ecf20Sopenharmony_ci &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); 47478c2ecf20Sopenharmony_ci payload.sas_identify.phy_id = phy_id; 47488c2ecf20Sopenharmony_ci ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 47498c2ecf20Sopenharmony_ci sizeof(payload), 0); 47508c2ecf20Sopenharmony_ci return ret; 47518c2ecf20Sopenharmony_ci} 47528c2ecf20Sopenharmony_ci 47538c2ecf20Sopenharmony_ci/** 47548c2ecf20Sopenharmony_ci * pm8001_chip_phy_stop_req - start phy via PHY_STOP COMMAND 47558c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 47568c2ecf20Sopenharmony_ci * @phy_id: the phy id which we wanted to start up. 47578c2ecf20Sopenharmony_ci */ 47588c2ecf20Sopenharmony_cistatic int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, 47598c2ecf20Sopenharmony_ci u8 phy_id) 47608c2ecf20Sopenharmony_ci{ 47618c2ecf20Sopenharmony_ci struct phy_stop_req payload; 47628c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 47638c2ecf20Sopenharmony_ci int ret; 47648c2ecf20Sopenharmony_ci u32 tag = 0x01; 47658c2ecf20Sopenharmony_ci u32 opcode = OPC_INB_PHYSTOP; 47668c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 47678c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 47688c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 47698c2ecf20Sopenharmony_ci payload.phy_id = cpu_to_le32(phy_id); 47708c2ecf20Sopenharmony_ci ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 47718c2ecf20Sopenharmony_ci sizeof(payload), 0); 47728c2ecf20Sopenharmony_ci return ret; 47738c2ecf20Sopenharmony_ci} 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ci/* 47768c2ecf20Sopenharmony_ci * see comments on pm8001_mpi_reg_resp. 47778c2ecf20Sopenharmony_ci */ 47788c2ecf20Sopenharmony_cistatic int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, 47798c2ecf20Sopenharmony_ci struct pm8001_device *pm8001_dev, u32 flag) 47808c2ecf20Sopenharmony_ci{ 47818c2ecf20Sopenharmony_ci struct reg_dev_req payload; 47828c2ecf20Sopenharmony_ci u32 opc; 47838c2ecf20Sopenharmony_ci u32 stp_sspsmp_sata = 0x4; 47848c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 47858c2ecf20Sopenharmony_ci u32 linkrate, phy_id; 47868c2ecf20Sopenharmony_ci int rc, tag = 0xdeadbeef; 47878c2ecf20Sopenharmony_ci struct pm8001_ccb_info *ccb; 47888c2ecf20Sopenharmony_ci u8 retryFlag = 0x1; 47898c2ecf20Sopenharmony_ci u16 firstBurstSize = 0; 47908c2ecf20Sopenharmony_ci u16 ITNT = 2000; 47918c2ecf20Sopenharmony_ci struct domain_device *dev = pm8001_dev->sas_device; 47928c2ecf20Sopenharmony_ci struct domain_device *parent_dev = dev->parent; 47938c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 47948c2ecf20Sopenharmony_ci 47958c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 47968c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 47978c2ecf20Sopenharmony_ci if (rc) 47988c2ecf20Sopenharmony_ci return rc; 47998c2ecf20Sopenharmony_ci ccb = &pm8001_ha->ccb_info[tag]; 48008c2ecf20Sopenharmony_ci ccb->device = pm8001_dev; 48018c2ecf20Sopenharmony_ci ccb->ccb_tag = tag; 48028c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 48038c2ecf20Sopenharmony_ci 48048c2ecf20Sopenharmony_ci if (flag == 1) { 48058c2ecf20Sopenharmony_ci stp_sspsmp_sata = 0x02; /*direct attached sata */ 48068c2ecf20Sopenharmony_ci } else { 48078c2ecf20Sopenharmony_ci if (pm8001_dev->dev_type == SAS_SATA_DEV) 48088c2ecf20Sopenharmony_ci stp_sspsmp_sata = 0x00; /* stp*/ 48098c2ecf20Sopenharmony_ci else if (pm8001_dev->dev_type == SAS_END_DEVICE || 48108c2ecf20Sopenharmony_ci pm8001_dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || 48118c2ecf20Sopenharmony_ci pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE) 48128c2ecf20Sopenharmony_ci stp_sspsmp_sata = 0x01; /*ssp or smp*/ 48138c2ecf20Sopenharmony_ci } 48148c2ecf20Sopenharmony_ci if (parent_dev && dev_is_expander(parent_dev->dev_type)) 48158c2ecf20Sopenharmony_ci phy_id = parent_dev->ex_dev.ex_phy->phy_id; 48168c2ecf20Sopenharmony_ci else 48178c2ecf20Sopenharmony_ci phy_id = pm8001_dev->attached_phy; 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci opc = OPC_INB_REG_DEV; 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? 48228c2ecf20Sopenharmony_ci pm8001_dev->sas_device->linkrate : dev->port->linkrate; 48238c2ecf20Sopenharmony_ci 48248c2ecf20Sopenharmony_ci payload.phyid_portid = 48258c2ecf20Sopenharmony_ci cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0xFF) | 48268c2ecf20Sopenharmony_ci ((phy_id & 0xFF) << 8)); 48278c2ecf20Sopenharmony_ci 48288c2ecf20Sopenharmony_ci payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & 0x01) | 48298c2ecf20Sopenharmony_ci ((linkrate & 0x0F) << 24) | 48308c2ecf20Sopenharmony_ci ((stp_sspsmp_sata & 0x03) << 28)); 48318c2ecf20Sopenharmony_ci payload.firstburstsize_ITNexustimeout = 48328c2ecf20Sopenharmony_ci cpu_to_le32(ITNT | (firstBurstSize * 0x10000)); 48338c2ecf20Sopenharmony_ci 48348c2ecf20Sopenharmony_ci memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr, 48358c2ecf20Sopenharmony_ci SAS_ADDR_SIZE); 48368c2ecf20Sopenharmony_ci 48378c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 48388c2ecf20Sopenharmony_ci sizeof(payload), 0); 48398c2ecf20Sopenharmony_ci if (rc) 48408c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 48418c2ecf20Sopenharmony_ci 48428c2ecf20Sopenharmony_ci return rc; 48438c2ecf20Sopenharmony_ci} 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci/** 48468c2ecf20Sopenharmony_ci * pm80xx_chip_phy_ctl_req - support the local phy operation 48478c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 48488c2ecf20Sopenharmony_ci * @phyId: the phy id which we wanted to operate 48498c2ecf20Sopenharmony_ci * @phy_op: phy operation to request 48508c2ecf20Sopenharmony_ci */ 48518c2ecf20Sopenharmony_cistatic int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, 48528c2ecf20Sopenharmony_ci u32 phyId, u32 phy_op) 48538c2ecf20Sopenharmony_ci{ 48548c2ecf20Sopenharmony_ci u32 tag; 48558c2ecf20Sopenharmony_ci int rc; 48568c2ecf20Sopenharmony_ci struct local_phy_ctl_req payload; 48578c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 48588c2ecf20Sopenharmony_ci u32 opc = OPC_INB_LOCAL_PHY_CONTROL; 48598c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 48608c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 48618c2ecf20Sopenharmony_ci if (rc) 48628c2ecf20Sopenharmony_ci return rc; 48638c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 48648c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 48658c2ecf20Sopenharmony_ci payload.phyop_phyid = 48668c2ecf20Sopenharmony_ci cpu_to_le32(((phy_op & 0xFF) << 8) | (phyId & 0xFF)); 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 48698c2ecf20Sopenharmony_ci sizeof(payload), 0); 48708c2ecf20Sopenharmony_ci if (rc) 48718c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci return rc; 48748c2ecf20Sopenharmony_ci} 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_cistatic u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) 48778c2ecf20Sopenharmony_ci{ 48788c2ecf20Sopenharmony_ci#ifdef PM8001_USE_MSIX 48798c2ecf20Sopenharmony_ci return 1; 48808c2ecf20Sopenharmony_ci#else 48818c2ecf20Sopenharmony_ci u32 value; 48828c2ecf20Sopenharmony_ci 48838c2ecf20Sopenharmony_ci value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR); 48848c2ecf20Sopenharmony_ci if (value) 48858c2ecf20Sopenharmony_ci return 1; 48868c2ecf20Sopenharmony_ci return 0; 48878c2ecf20Sopenharmony_ci#endif 48888c2ecf20Sopenharmony_ci} 48898c2ecf20Sopenharmony_ci 48908c2ecf20Sopenharmony_ci/** 48918c2ecf20Sopenharmony_ci * pm8001_chip_isr - PM8001 isr handler. 48928c2ecf20Sopenharmony_ci * @pm8001_ha: our hba card information. 48938c2ecf20Sopenharmony_ci * @vec: irq number. 48948c2ecf20Sopenharmony_ci */ 48958c2ecf20Sopenharmony_cistatic irqreturn_t 48968c2ecf20Sopenharmony_cipm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) 48978c2ecf20Sopenharmony_ci{ 48988c2ecf20Sopenharmony_ci pm80xx_chip_interrupt_disable(pm8001_ha, vec); 48998c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, DEVIO, 49008c2ecf20Sopenharmony_ci "irq vec %d, ODMR:0x%x\n", 49018c2ecf20Sopenharmony_ci vec, pm8001_cr32(pm8001_ha, 0, 0x30)); 49028c2ecf20Sopenharmony_ci process_oq(pm8001_ha, vec); 49038c2ecf20Sopenharmony_ci pm80xx_chip_interrupt_enable(pm8001_ha, vec); 49048c2ecf20Sopenharmony_ci return IRQ_HANDLED; 49058c2ecf20Sopenharmony_ci} 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_cistatic void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, 49088c2ecf20Sopenharmony_ci u32 operation, u32 phyid, 49098c2ecf20Sopenharmony_ci u32 length, u32 *buf) 49108c2ecf20Sopenharmony_ci{ 49118c2ecf20Sopenharmony_ci u32 tag , i, j = 0; 49128c2ecf20Sopenharmony_ci int rc; 49138c2ecf20Sopenharmony_ci struct set_phy_profile_req payload; 49148c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 49158c2ecf20Sopenharmony_ci u32 opc = OPC_INB_SET_PHY_PROFILE; 49168c2ecf20Sopenharmony_ci 49178c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 49188c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 49198c2ecf20Sopenharmony_ci if (rc) 49208c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, "Invalid tag\n"); 49218c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 49228c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 49238c2ecf20Sopenharmony_ci payload.ppc_phyid = (((operation & 0xF) << 8) | (phyid & 0xFF)); 49248c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, 49258c2ecf20Sopenharmony_ci " phy profile command for phy %x ,length is %d\n", 49268c2ecf20Sopenharmony_ci payload.ppc_phyid, length); 49278c2ecf20Sopenharmony_ci for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) { 49288c2ecf20Sopenharmony_ci payload.reserved[j] = cpu_to_le32(*((u32 *)buf + i)); 49298c2ecf20Sopenharmony_ci j++; 49308c2ecf20Sopenharmony_ci } 49318c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 49328c2ecf20Sopenharmony_ci sizeof(payload), 0); 49338c2ecf20Sopenharmony_ci if (rc) 49348c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 49358c2ecf20Sopenharmony_ci} 49368c2ecf20Sopenharmony_ci 49378c2ecf20Sopenharmony_civoid pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, 49388c2ecf20Sopenharmony_ci u32 length, u8 *buf) 49398c2ecf20Sopenharmony_ci{ 49408c2ecf20Sopenharmony_ci u32 i; 49418c2ecf20Sopenharmony_ci 49428c2ecf20Sopenharmony_ci for (i = 0; i < pm8001_ha->chip->n_phy; i++) { 49438c2ecf20Sopenharmony_ci mpi_set_phy_profile_req(pm8001_ha, 49448c2ecf20Sopenharmony_ci SAS_PHY_ANALOG_SETTINGS_PAGE, i, length, (u32 *)buf); 49458c2ecf20Sopenharmony_ci length = length + PHY_DWORD_LENGTH; 49468c2ecf20Sopenharmony_ci } 49478c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "phy settings completed\n"); 49488c2ecf20Sopenharmony_ci} 49498c2ecf20Sopenharmony_ci 49508c2ecf20Sopenharmony_civoid pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, 49518c2ecf20Sopenharmony_ci u32 phy, u32 length, u32 *buf) 49528c2ecf20Sopenharmony_ci{ 49538c2ecf20Sopenharmony_ci u32 tag, opc; 49548c2ecf20Sopenharmony_ci int rc, i; 49558c2ecf20Sopenharmony_ci struct set_phy_profile_req payload; 49568c2ecf20Sopenharmony_ci struct inbound_queue_table *circularQ; 49578c2ecf20Sopenharmony_ci 49588c2ecf20Sopenharmony_ci memset(&payload, 0, sizeof(payload)); 49598c2ecf20Sopenharmony_ci 49608c2ecf20Sopenharmony_ci rc = pm8001_tag_alloc(pm8001_ha, &tag); 49618c2ecf20Sopenharmony_ci if (rc) 49628c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "Invalid tag\n"); 49638c2ecf20Sopenharmony_ci 49648c2ecf20Sopenharmony_ci circularQ = &pm8001_ha->inbnd_q_tbl[0]; 49658c2ecf20Sopenharmony_ci opc = OPC_INB_SET_PHY_PROFILE; 49668c2ecf20Sopenharmony_ci 49678c2ecf20Sopenharmony_ci payload.tag = cpu_to_le32(tag); 49688c2ecf20Sopenharmony_ci payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8) 49698c2ecf20Sopenharmony_ci | (phy & 0xFF)); 49708c2ecf20Sopenharmony_ci 49718c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) 49728c2ecf20Sopenharmony_ci payload.reserved[i] = cpu_to_le32(*(buf + i)); 49738c2ecf20Sopenharmony_ci 49748c2ecf20Sopenharmony_ci rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 49758c2ecf20Sopenharmony_ci sizeof(payload), 0); 49768c2ecf20Sopenharmony_ci if (rc) 49778c2ecf20Sopenharmony_ci pm8001_tag_free(pm8001_ha, tag); 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, INIT, "PHY %d settings applied\n", phy); 49808c2ecf20Sopenharmony_ci} 49818c2ecf20Sopenharmony_ciconst struct pm8001_dispatch pm8001_80xx_dispatch = { 49828c2ecf20Sopenharmony_ci .name = "pmc80xx", 49838c2ecf20Sopenharmony_ci .chip_init = pm80xx_chip_init, 49848c2ecf20Sopenharmony_ci .chip_soft_rst = pm80xx_chip_soft_rst, 49858c2ecf20Sopenharmony_ci .chip_rst = pm80xx_hw_chip_rst, 49868c2ecf20Sopenharmony_ci .chip_iounmap = pm8001_chip_iounmap, 49878c2ecf20Sopenharmony_ci .isr = pm80xx_chip_isr, 49888c2ecf20Sopenharmony_ci .is_our_interrupt = pm80xx_chip_is_our_interrupt, 49898c2ecf20Sopenharmony_ci .isr_process_oq = process_oq, 49908c2ecf20Sopenharmony_ci .interrupt_enable = pm80xx_chip_interrupt_enable, 49918c2ecf20Sopenharmony_ci .interrupt_disable = pm80xx_chip_interrupt_disable, 49928c2ecf20Sopenharmony_ci .make_prd = pm8001_chip_make_sg, 49938c2ecf20Sopenharmony_ci .smp_req = pm80xx_chip_smp_req, 49948c2ecf20Sopenharmony_ci .ssp_io_req = pm80xx_chip_ssp_io_req, 49958c2ecf20Sopenharmony_ci .sata_req = pm80xx_chip_sata_req, 49968c2ecf20Sopenharmony_ci .phy_start_req = pm80xx_chip_phy_start_req, 49978c2ecf20Sopenharmony_ci .phy_stop_req = pm80xx_chip_phy_stop_req, 49988c2ecf20Sopenharmony_ci .reg_dev_req = pm80xx_chip_reg_dev_req, 49998c2ecf20Sopenharmony_ci .dereg_dev_req = pm8001_chip_dereg_dev_req, 50008c2ecf20Sopenharmony_ci .phy_ctl_req = pm80xx_chip_phy_ctl_req, 50018c2ecf20Sopenharmony_ci .task_abort = pm8001_chip_abort_task, 50028c2ecf20Sopenharmony_ci .ssp_tm_req = pm8001_chip_ssp_tm_req, 50038c2ecf20Sopenharmony_ci .get_nvmd_req = pm8001_chip_get_nvmd_req, 50048c2ecf20Sopenharmony_ci .set_nvmd_req = pm8001_chip_set_nvmd_req, 50058c2ecf20Sopenharmony_ci .fw_flash_update_req = pm8001_chip_fw_flash_update_req, 50068c2ecf20Sopenharmony_ci .set_dev_state_req = pm8001_chip_set_dev_state_req, 50078c2ecf20Sopenharmony_ci}; 5008