18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * PMC-Sierra 8001/8081/8088/8089 SAS/SATA based host adapters driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2008-2009 USI Co., Ltd. 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/firmware.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include "pm8001_sas.h" 438c2ecf20Sopenharmony_ci#include "pm8001_ctl.h" 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* scsi host attributes */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number 498c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 508c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 518c2ecf20Sopenharmony_ci * @buf: the buffer returned 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev, 568c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 598c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 608c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 638c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 648c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev); 658c2ecf20Sopenharmony_ci } else { 668c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 678c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev); 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_cistatic 718c2ecf20Sopenharmony_ciDEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/** 748c2ecf20Sopenharmony_ci * controller_fatal_error_show - check controller is under fatal err 758c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 768c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 778c2ecf20Sopenharmony_ci * @buf: the buffer returned 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * A sysfs 'read only' shost attribute. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_cistatic ssize_t controller_fatal_error_show(struct device *cdev, 828c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 858c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 868c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 898c2ecf20Sopenharmony_ci pm8001_ha->controller_fatal_error); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(controller_fatal_error); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/** 948c2ecf20Sopenharmony_ci * pm8001_ctl_fw_version_show - firmware version 958c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 968c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 978c2ecf20Sopenharmony_ci * @buf: the buffer returned 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 1008c2ecf20Sopenharmony_ci */ 1018c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_fw_version_show(struct device *cdev, 1028c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 1058c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 1068c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 1098c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 1108c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 24), 1118c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 16), 1128c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 8), 1138c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev)); 1148c2ecf20Sopenharmony_ci } else { 1158c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 1168c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 24), 1178c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 16), 1188c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 8), 1198c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev)); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_cistatic DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/** 1258c2ecf20Sopenharmony_ci * pm8001_ctl_ila_version_show - ila version 1268c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 1278c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 1288c2ecf20Sopenharmony_ci * @buf: the buffer returned 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_ila_version_show(struct device *cdev, 1338c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 1368c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 1378c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id != chip_8001) { 1408c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 1418c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 24), 1428c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 16), 1438c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 8), 1448c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version)); 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ila_version, 0444, pm8001_ctl_ila_version_show, NULL); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci/** 1518c2ecf20Sopenharmony_ci * pm8001_ctl_inactive_fw_version_show - Inacative firmware version number 1528c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 1538c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 1548c2ecf20Sopenharmony_ci * @buf: the buffer returned 1558c2ecf20Sopenharmony_ci * 1568c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_inactive_fw_version_show(struct device *cdev, 1598c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 1628c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 1638c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id != chip_8001) { 1668c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 1678c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 24), 1688c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 16), 1698c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 8), 1708c2ecf20Sopenharmony_ci (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version)); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_cistatic 1758c2ecf20Sopenharmony_ciDEVICE_ATTR(inc_fw_ver, 0444, pm8001_ctl_inactive_fw_version_show, NULL); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/** 1788c2ecf20Sopenharmony_ci * pm8001_ctl_max_out_io_show - max outstanding io supported 1798c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 1808c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 1818c2ecf20Sopenharmony_ci * @buf: the buffer returned 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_max_out_io_show(struct device *cdev, 1868c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 1898c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 1908c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 1938c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 1948c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io); 1958c2ecf20Sopenharmony_ci } else { 1968c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 1978c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io); 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL); 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * pm8001_ctl_max_devices_show - max devices support 2038c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 2048c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 2058c2ecf20Sopenharmony_ci * @buf: the buffer returned 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_max_devices_show(struct device *cdev, 2108c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 2138c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 2148c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 2178c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%04d\n", 2188c2ecf20Sopenharmony_ci (u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16) 2198c2ecf20Sopenharmony_ci ); 2208c2ecf20Sopenharmony_ci } else { 2218c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%04d\n", 2228c2ecf20Sopenharmony_ci (u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16) 2238c2ecf20Sopenharmony_ci ); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_cistatic DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL); 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no 2298c2ecf20Sopenharmony_ci * hardware limitation 2308c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 2318c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 2328c2ecf20Sopenharmony_ci * @buf: the buffer returned 2338c2ecf20Sopenharmony_ci * 2348c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev, 2378c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 2408c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 2418c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) { 2448c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%04d\n", 2458c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF 2468c2ecf20Sopenharmony_ci ); 2478c2ecf20Sopenharmony_ci } else { 2488c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%04d\n", 2498c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF 2508c2ecf20Sopenharmony_ci ); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_cistatic DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci#define SAS_1_0 0x1 2568c2ecf20Sopenharmony_ci#define SAS_1_1 0x2 2578c2ecf20Sopenharmony_ci#define SAS_2_0 0x4 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic ssize_t 2608c2ecf20Sopenharmony_cishow_sas_spec_support_status(unsigned int mode, char *buf) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci ssize_t len = 0; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (mode & SAS_1_1) 2658c2ecf20Sopenharmony_ci len = sprintf(buf, "%s", "SAS1.1"); 2668c2ecf20Sopenharmony_ci if (mode & SAS_2_0) 2678c2ecf20Sopenharmony_ci len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0"); 2688c2ecf20Sopenharmony_ci len += sprintf(buf + len, "\n"); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return len; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/** 2748c2ecf20Sopenharmony_ci * pm8001_ctl_sas_spec_support_show - sas spec supported 2758c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 2768c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 2778c2ecf20Sopenharmony_ci * @buf: the buffer returned 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev, 2828c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci unsigned int mode; 2858c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 2868c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 2878c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 2888c2ecf20Sopenharmony_ci /* fe000000 means supports SAS2.1 */ 2898c2ecf20Sopenharmony_ci if (pm8001_ha->chip_id == chip_8001) 2908c2ecf20Sopenharmony_ci mode = (pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag & 2918c2ecf20Sopenharmony_ci 0xfe000000)>>25; 2928c2ecf20Sopenharmony_ci else 2938c2ecf20Sopenharmony_ci /* fe000000 means supports SAS2.1 */ 2948c2ecf20Sopenharmony_ci mode = (pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag & 2958c2ecf20Sopenharmony_ci 0xfe000000)>>25; 2968c2ecf20Sopenharmony_ci return show_sas_spec_support_status(mode, buf); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_cistatic DEVICE_ATTR(sas_spec_support, S_IRUGO, 2998c2ecf20Sopenharmony_ci pm8001_ctl_sas_spec_support_show, NULL); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/** 3028c2ecf20Sopenharmony_ci * pm8001_ctl_sas_address_show - sas address 3038c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 3048c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 3058c2ecf20Sopenharmony_ci * @buf: the buffer returned 3068c2ecf20Sopenharmony_ci * 3078c2ecf20Sopenharmony_ci * This is the controller sas address 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev, 3128c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 3158c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 3168c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 3178c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "0x%016llx\n", 3188c2ecf20Sopenharmony_ci be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr)); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_cistatic DEVICE_ATTR(host_sas_address, S_IRUGO, 3218c2ecf20Sopenharmony_ci pm8001_ctl_host_sas_address_show, NULL); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci/** 3248c2ecf20Sopenharmony_ci * pm8001_ctl_logging_level_show - logging level 3258c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 3268c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 3278c2ecf20Sopenharmony_ci * @buf: the buffer returned 3288c2ecf20Sopenharmony_ci * 3298c2ecf20Sopenharmony_ci * A sysfs 'read/write' shost attribute. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_logging_level_show(struct device *cdev, 3328c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 3358c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 3368c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_logging_level_store(struct device *cdev, 3428c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 3458c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 3468c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 3478c2ecf20Sopenharmony_ci int val = 0; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (sscanf(buf, "%x", &val) != 1) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci pm8001_ha->logging_level = val; 3538c2ecf20Sopenharmony_ci return strlen(buf); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, 3578c2ecf20Sopenharmony_ci pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store); 3588c2ecf20Sopenharmony_ci/** 3598c2ecf20Sopenharmony_ci * pm8001_ctl_aap_log_show - aap1 event log 3608c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 3618c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 3628c2ecf20Sopenharmony_ci * @buf: the buffer returned 3638c2ecf20Sopenharmony_ci * 3648c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_aap_log_show(struct device *cdev, 3678c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 3708c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 3718c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 3728c2ecf20Sopenharmony_ci int i; 3738c2ecf20Sopenharmony_ci#define AAP1_MEMMAP(r, c) \ 3748c2ecf20Sopenharmony_ci (*(u32 *)((u8*)pm8001_ha->memoryMap.region[AAP1].virt_ptr + (r) * 32 \ 3758c2ecf20Sopenharmony_ci + (c))) 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci char *str = buf; 3788c2ecf20Sopenharmony_ci int max = 2; 3798c2ecf20Sopenharmony_ci for (i = 0; i < max; i++) { 3808c2ecf20Sopenharmony_ci str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" 3818c2ecf20Sopenharmony_ci "0x%08x 0x%08x\n", 3828c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 0), 3838c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 4), 3848c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 8), 3858c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 12), 3868c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 16), 3878c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 20), 3888c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 24), 3898c2ecf20Sopenharmony_ci AAP1_MEMMAP(i, 28)); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return str - buf; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_cistatic DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL); 3958c2ecf20Sopenharmony_ci/** 3968c2ecf20Sopenharmony_ci * pm8001_ctl_ib_queue_log_show - Out bound Queue log 3978c2ecf20Sopenharmony_ci * @cdev:pointer to embedded class device 3988c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 3998c2ecf20Sopenharmony_ci * @buf: the buffer returned 4008c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev, 4038c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 4068c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 4078c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 4088c2ecf20Sopenharmony_ci int offset; 4098c2ecf20Sopenharmony_ci char *str = buf; 4108c2ecf20Sopenharmony_ci int start = 0; 4118c2ecf20Sopenharmony_ci u32 ib_offset = pm8001_ha->ib_offset; 4128c2ecf20Sopenharmony_ci#define IB_MEMMAP(c) \ 4138c2ecf20Sopenharmony_ci (*(u32 *)((u8 *)pm8001_ha-> \ 4148c2ecf20Sopenharmony_ci memoryMap.region[ib_offset].virt_ptr + \ 4158c2ecf20Sopenharmony_ci pm8001_ha->evtlog_ib_offset + (c))) 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { 4188c2ecf20Sopenharmony_ci str += sprintf(str, "0x%08x\n", IB_MEMMAP(start)); 4198c2ecf20Sopenharmony_ci start = start + 4; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET; 4228c2ecf20Sopenharmony_ci if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) 4238c2ecf20Sopenharmony_ci pm8001_ha->evtlog_ib_offset = 0; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci return str - buf; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL); 4298c2ecf20Sopenharmony_ci/** 4308c2ecf20Sopenharmony_ci * pm8001_ctl_ob_queue_log_show - Out bound Queue log 4318c2ecf20Sopenharmony_ci * @cdev:pointer to embedded class device 4328c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 4338c2ecf20Sopenharmony_ci * @buf: the buffer returned 4348c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 4358c2ecf20Sopenharmony_ci */ 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev, 4388c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 4418c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 4428c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 4438c2ecf20Sopenharmony_ci int offset; 4448c2ecf20Sopenharmony_ci char *str = buf; 4458c2ecf20Sopenharmony_ci int start = 0; 4468c2ecf20Sopenharmony_ci u32 ob_offset = pm8001_ha->ob_offset; 4478c2ecf20Sopenharmony_ci#define OB_MEMMAP(c) \ 4488c2ecf20Sopenharmony_ci (*(u32 *)((u8 *)pm8001_ha-> \ 4498c2ecf20Sopenharmony_ci memoryMap.region[ob_offset].virt_ptr + \ 4508c2ecf20Sopenharmony_ci pm8001_ha->evtlog_ob_offset + (c))) 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { 4538c2ecf20Sopenharmony_ci str += sprintf(str, "0x%08x\n", OB_MEMMAP(start)); 4548c2ecf20Sopenharmony_ci start = start + 4; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET; 4578c2ecf20Sopenharmony_ci if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) 4588c2ecf20Sopenharmony_ci pm8001_ha->evtlog_ob_offset = 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return str - buf; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL); 4638c2ecf20Sopenharmony_ci/** 4648c2ecf20Sopenharmony_ci * pm8001_ctl_bios_version_show - Bios version Display 4658c2ecf20Sopenharmony_ci * @cdev:pointer to embedded class device 4668c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 4678c2ecf20Sopenharmony_ci * @buf:the buffer returned 4688c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 4698c2ecf20Sopenharmony_ci */ 4708c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_bios_version_show(struct device *cdev, 4718c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 4748c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 4758c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 4768c2ecf20Sopenharmony_ci char *str = buf; 4778c2ecf20Sopenharmony_ci int bios_index; 4788c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 4798c2ecf20Sopenharmony_ci struct pm8001_ioctl_payload payload; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci pm8001_ha->nvmd_completion = &completion; 4828c2ecf20Sopenharmony_ci payload.minor_function = 7; 4838c2ecf20Sopenharmony_ci payload.offset = 0; 4848c2ecf20Sopenharmony_ci payload.rd_length = 4096; 4858c2ecf20Sopenharmony_ci payload.func_specific = kzalloc(4096, GFP_KERNEL); 4868c2ecf20Sopenharmony_ci if (!payload.func_specific) 4878c2ecf20Sopenharmony_ci return -ENOMEM; 4888c2ecf20Sopenharmony_ci if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) { 4898c2ecf20Sopenharmony_ci kfree(payload.func_specific); 4908c2ecf20Sopenharmony_ci return -ENOMEM; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci wait_for_completion(&completion); 4938c2ecf20Sopenharmony_ci for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT; 4948c2ecf20Sopenharmony_ci bios_index++) 4958c2ecf20Sopenharmony_ci str += sprintf(str, "%c", 4968c2ecf20Sopenharmony_ci *(payload.func_specific+bios_index)); 4978c2ecf20Sopenharmony_ci kfree(payload.func_specific); 4988c2ecf20Sopenharmony_ci return str - buf; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_cistatic DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL); 5018c2ecf20Sopenharmony_ci/** 5028c2ecf20Sopenharmony_ci * event_log_size_show - event log size 5038c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 5048c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 5058c2ecf20Sopenharmony_ci * @buf: the buffer returned 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * A sysfs read shost attribute. 5088c2ecf20Sopenharmony_ci */ 5098c2ecf20Sopenharmony_cistatic ssize_t event_log_size_show(struct device *cdev, 5108c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 5138c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 5148c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", 5178c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(event_log_size); 5208c2ecf20Sopenharmony_ci/** 5218c2ecf20Sopenharmony_ci * pm8001_ctl_aap_log_show - IOP event log 5228c2ecf20Sopenharmony_ci * @cdev: pointer to embedded class device 5238c2ecf20Sopenharmony_ci * @attr: device attribute (unused) 5248c2ecf20Sopenharmony_ci * @buf: the buffer returned 5258c2ecf20Sopenharmony_ci * 5268c2ecf20Sopenharmony_ci * A sysfs 'read-only' shost attribute. 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_iop_log_show(struct device *cdev, 5298c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 5328c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 5338c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 5348c2ecf20Sopenharmony_ci char *str = buf; 5358c2ecf20Sopenharmony_ci u32 read_size = 5368c2ecf20Sopenharmony_ci pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024; 5378c2ecf20Sopenharmony_ci static u32 start, end, count; 5388c2ecf20Sopenharmony_ci u32 max_read_times = 32; 5398c2ecf20Sopenharmony_ci u32 max_count = (read_size * 1024) / (max_read_times * 4); 5408c2ecf20Sopenharmony_ci u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if ((count % max_count) == 0) { 5438c2ecf20Sopenharmony_ci start = 0; 5448c2ecf20Sopenharmony_ci end = max_read_times; 5458c2ecf20Sopenharmony_ci count = 0; 5468c2ecf20Sopenharmony_ci } else { 5478c2ecf20Sopenharmony_ci start = end; 5488c2ecf20Sopenharmony_ci end = end + max_read_times; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci for (; start < end; start++) 5528c2ecf20Sopenharmony_ci str += sprintf(str, "%08x ", *(temp+start)); 5538c2ecf20Sopenharmony_ci count++; 5548c2ecf20Sopenharmony_ci return str - buf; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_cistatic DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci/** 5598c2ecf20Sopenharmony_ci ** pm8001_ctl_fatal_log_show - fatal error logging 5608c2ecf20Sopenharmony_ci ** @cdev:pointer to embedded class device 5618c2ecf20Sopenharmony_ci ** @attr: device attribute 5628c2ecf20Sopenharmony_ci ** @buf: the buffer returned 5638c2ecf20Sopenharmony_ci ** 5648c2ecf20Sopenharmony_ci ** A sysfs 'read-only' shost attribute. 5658c2ecf20Sopenharmony_ci **/ 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_fatal_log_show(struct device *cdev, 5688c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci ssize_t count; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci count = pm80xx_get_fatal_dump(cdev, attr, buf); 5738c2ecf20Sopenharmony_ci return count; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/** 5798c2ecf20Sopenharmony_ci ** non_fatal_log_show - non fatal error logging 5808c2ecf20Sopenharmony_ci ** @cdev:pointer to embedded class device 5818c2ecf20Sopenharmony_ci ** @attr: device attribute 5828c2ecf20Sopenharmony_ci ** @buf: the buffer returned 5838c2ecf20Sopenharmony_ci ** 5848c2ecf20Sopenharmony_ci ** A sysfs 'read-only' shost attribute. 5858c2ecf20Sopenharmony_ci **/ 5868c2ecf20Sopenharmony_cistatic ssize_t non_fatal_log_show(struct device *cdev, 5878c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci u32 count; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci count = pm80xx_get_non_fatal_dump(cdev, attr, buf); 5928c2ecf20Sopenharmony_ci return count; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(non_fatal_log); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_cistatic ssize_t non_fatal_count_show(struct device *cdev, 5978c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 6008c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 6018c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%08x", 6048c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_count); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic ssize_t non_fatal_count_store(struct device *cdev, 6088c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 6118c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 6128c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 6138c2ecf20Sopenharmony_ci int val = 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci if (kstrtoint(buf, 16, &val) != 0) 6168c2ecf20Sopenharmony_ci return -EINVAL; 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci pm8001_ha->non_fatal_count = val; 6198c2ecf20Sopenharmony_ci return strlen(buf); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(non_fatal_count); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/** 6248c2ecf20Sopenharmony_ci ** pm8001_ctl_gsm_log_show - gsm dump collection 6258c2ecf20Sopenharmony_ci ** @cdev:pointer to embedded class device 6268c2ecf20Sopenharmony_ci ** @attr: device attribute (unused) 6278c2ecf20Sopenharmony_ci ** @buf: the buffer returned 6288c2ecf20Sopenharmony_ci ** A sysfs 'read-only' shost attribute. 6298c2ecf20Sopenharmony_ci **/ 6308c2ecf20Sopenharmony_cistatic ssize_t pm8001_ctl_gsm_log_show(struct device *cdev, 6318c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci ssize_t count; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf); 6368c2ecf20Sopenharmony_ci return count; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci#define FLASH_CMD_NONE 0x00 6428c2ecf20Sopenharmony_ci#define FLASH_CMD_UPDATE 0x01 6438c2ecf20Sopenharmony_ci#define FLASH_CMD_SET_NVMD 0x02 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_cistruct flash_command { 6468c2ecf20Sopenharmony_ci u8 command[8]; 6478c2ecf20Sopenharmony_ci int code; 6488c2ecf20Sopenharmony_ci}; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic struct flash_command flash_command_table[] = 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci {"set_nvmd", FLASH_CMD_SET_NVMD}, 6538c2ecf20Sopenharmony_ci {"update", FLASH_CMD_UPDATE}, 6548c2ecf20Sopenharmony_ci {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ 6558c2ecf20Sopenharmony_ci}; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistruct error_fw { 6588c2ecf20Sopenharmony_ci char *reason; 6598c2ecf20Sopenharmony_ci int err_code; 6608c2ecf20Sopenharmony_ci}; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic struct error_fw flash_error_table[] = 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci {"Failed to open fw image file", FAIL_OPEN_BIOS_FILE}, 6658c2ecf20Sopenharmony_ci {"image header mismatch", FLASH_UPDATE_HDR_ERR}, 6668c2ecf20Sopenharmony_ci {"image offset mismatch", FLASH_UPDATE_OFFSET_ERR}, 6678c2ecf20Sopenharmony_ci {"image CRC Error", FLASH_UPDATE_CRC_ERR}, 6688c2ecf20Sopenharmony_ci {"image length Error.", FLASH_UPDATE_LENGTH_ERR}, 6698c2ecf20Sopenharmony_ci {"Failed to program flash chip", FLASH_UPDATE_HW_ERR}, 6708c2ecf20Sopenharmony_ci {"Flash chip not supported.", FLASH_UPDATE_DNLD_NOT_SUPPORTED}, 6718c2ecf20Sopenharmony_ci {"Flash update disabled.", FLASH_UPDATE_DISABLED}, 6728c2ecf20Sopenharmony_ci {"Flash in progress", FLASH_IN_PROGRESS}, 6738c2ecf20Sopenharmony_ci {"Image file size Error", FAIL_FILE_SIZE}, 6748c2ecf20Sopenharmony_ci {"Input parameter error", FAIL_PARAMETERS}, 6758c2ecf20Sopenharmony_ci {"Out of memory", FAIL_OUT_MEMORY}, 6768c2ecf20Sopenharmony_ci {"OK", 0} /* Last entry err_code = 0. */ 6778c2ecf20Sopenharmony_ci}; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci struct pm8001_ioctl_payload *payload; 6828c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 6838c2ecf20Sopenharmony_ci u8 *ioctlbuffer; 6848c2ecf20Sopenharmony_ci u32 ret; 6858c2ecf20Sopenharmony_ci u32 length = 1024 * 5 + sizeof(*payload) - 1; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci if (pm8001_ha->fw_image->size > 4096) { 6888c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_FILE_SIZE; 6898c2ecf20Sopenharmony_ci return -EFAULT; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci ioctlbuffer = kzalloc(length, GFP_KERNEL); 6938c2ecf20Sopenharmony_ci if (!ioctlbuffer) { 6948c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_OUT_MEMORY; 6958c2ecf20Sopenharmony_ci return -ENOMEM; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci payload = (struct pm8001_ioctl_payload *)ioctlbuffer; 6988c2ecf20Sopenharmony_ci memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data, 6998c2ecf20Sopenharmony_ci pm8001_ha->fw_image->size); 7008c2ecf20Sopenharmony_ci payload->wr_length = pm8001_ha->fw_image->size; 7018c2ecf20Sopenharmony_ci payload->id = 0; 7028c2ecf20Sopenharmony_ci payload->minor_function = 0x1; 7038c2ecf20Sopenharmony_ci pm8001_ha->nvmd_completion = &completion; 7048c2ecf20Sopenharmony_ci ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload); 7058c2ecf20Sopenharmony_ci if (ret) { 7068c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_OUT_MEMORY; 7078c2ecf20Sopenharmony_ci goto out; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci wait_for_completion(&completion); 7108c2ecf20Sopenharmony_ciout: 7118c2ecf20Sopenharmony_ci kfree(ioctlbuffer); 7128c2ecf20Sopenharmony_ci return ret; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct pm8001_ioctl_payload *payload; 7188c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(completion); 7198c2ecf20Sopenharmony_ci u8 *ioctlbuffer; 7208c2ecf20Sopenharmony_ci struct fw_control_info *fwControl; 7218c2ecf20Sopenharmony_ci u32 partitionSize, partitionSizeTmp; 7228c2ecf20Sopenharmony_ci u32 loopNumber, loopcount; 7238c2ecf20Sopenharmony_ci struct pm8001_fw_image_header *image_hdr; 7248c2ecf20Sopenharmony_ci u32 sizeRead = 0; 7258c2ecf20Sopenharmony_ci u32 ret = 0; 7268c2ecf20Sopenharmony_ci u32 length = 1024 * 16 + sizeof(*payload) - 1; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (pm8001_ha->fw_image->size < 28) { 7298c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_FILE_SIZE; 7308c2ecf20Sopenharmony_ci return -EFAULT; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci ioctlbuffer = kzalloc(length, GFP_KERNEL); 7338c2ecf20Sopenharmony_ci if (!ioctlbuffer) { 7348c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_OUT_MEMORY; 7358c2ecf20Sopenharmony_ci return -ENOMEM; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data; 7388c2ecf20Sopenharmony_ci while (sizeRead < pm8001_ha->fw_image->size) { 7398c2ecf20Sopenharmony_ci partitionSizeTmp = 7408c2ecf20Sopenharmony_ci *(u32 *)((u8 *)&image_hdr->image_length + sizeRead); 7418c2ecf20Sopenharmony_ci partitionSize = be32_to_cpu(partitionSizeTmp); 7428c2ecf20Sopenharmony_ci loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN, 7438c2ecf20Sopenharmony_ci IOCTL_BUF_SIZE); 7448c2ecf20Sopenharmony_ci for (loopNumber = 0; loopNumber < loopcount; loopNumber++) { 7458c2ecf20Sopenharmony_ci payload = (struct pm8001_ioctl_payload *)ioctlbuffer; 7468c2ecf20Sopenharmony_ci payload->wr_length = 1024*16; 7478c2ecf20Sopenharmony_ci payload->id = 0; 7488c2ecf20Sopenharmony_ci fwControl = 7498c2ecf20Sopenharmony_ci (struct fw_control_info *)&payload->func_specific; 7508c2ecf20Sopenharmony_ci fwControl->len = IOCTL_BUF_SIZE; /* IN */ 7518c2ecf20Sopenharmony_ci fwControl->size = partitionSize + HEADER_LEN;/* IN */ 7528c2ecf20Sopenharmony_ci fwControl->retcode = 0;/* OUT */ 7538c2ecf20Sopenharmony_ci fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */ 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* for the last chunk of data in case file size is not even with 7568c2ecf20Sopenharmony_ci 4k, load only the rest*/ 7578c2ecf20Sopenharmony_ci if (((loopcount-loopNumber) == 1) && 7588c2ecf20Sopenharmony_ci ((partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE)) { 7598c2ecf20Sopenharmony_ci fwControl->len = 7608c2ecf20Sopenharmony_ci (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE; 7618c2ecf20Sopenharmony_ci memcpy((u8 *)fwControl->buffer, 7628c2ecf20Sopenharmony_ci (u8 *)pm8001_ha->fw_image->data + sizeRead, 7638c2ecf20Sopenharmony_ci (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE); 7648c2ecf20Sopenharmony_ci sizeRead += 7658c2ecf20Sopenharmony_ci (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE; 7668c2ecf20Sopenharmony_ci } else { 7678c2ecf20Sopenharmony_ci memcpy((u8 *)fwControl->buffer, 7688c2ecf20Sopenharmony_ci (u8 *)pm8001_ha->fw_image->data + sizeRead, 7698c2ecf20Sopenharmony_ci IOCTL_BUF_SIZE); 7708c2ecf20Sopenharmony_ci sizeRead += IOCTL_BUF_SIZE; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci pm8001_ha->nvmd_completion = &completion; 7748c2ecf20Sopenharmony_ci ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload); 7758c2ecf20Sopenharmony_ci if (ret) { 7768c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_OUT_MEMORY; 7778c2ecf20Sopenharmony_ci goto out; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci wait_for_completion(&completion); 7808c2ecf20Sopenharmony_ci if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) { 7818c2ecf20Sopenharmony_ci pm8001_ha->fw_status = fwControl->retcode; 7828c2ecf20Sopenharmony_ci ret = -EFAULT; 7838c2ecf20Sopenharmony_ci goto out; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ciout: 7888c2ecf20Sopenharmony_ci kfree(ioctlbuffer); 7898c2ecf20Sopenharmony_ci return ret; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_cistatic ssize_t pm8001_store_update_fw(struct device *cdev, 7928c2ecf20Sopenharmony_ci struct device_attribute *attr, 7938c2ecf20Sopenharmony_ci const char *buf, size_t count) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 7968c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 7978c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 7988c2ecf20Sopenharmony_ci char *cmd_ptr, *filename_ptr; 7998c2ecf20Sopenharmony_ci int res, i; 8008c2ecf20Sopenharmony_ci int flash_command = FLASH_CMD_NONE; 8018c2ecf20Sopenharmony_ci int ret; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 8048c2ecf20Sopenharmony_ci return -EACCES; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci /* this test protects us from running two flash processes at once, 8078c2ecf20Sopenharmony_ci * so we should start with this test */ 8088c2ecf20Sopenharmony_ci if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) 8098c2ecf20Sopenharmony_ci return -EINPROGRESS; 8108c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FLASH_IN_PROGRESS; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci cmd_ptr = kcalloc(count, 2, GFP_KERNEL); 8138c2ecf20Sopenharmony_ci if (!cmd_ptr) { 8148c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_OUT_MEMORY; 8158c2ecf20Sopenharmony_ci return -ENOMEM; 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci filename_ptr = cmd_ptr + count; 8198c2ecf20Sopenharmony_ci res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); 8208c2ecf20Sopenharmony_ci if (res != 2) { 8218c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_PARAMETERS; 8228c2ecf20Sopenharmony_ci ret = -EINVAL; 8238c2ecf20Sopenharmony_ci goto out; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { 8278c2ecf20Sopenharmony_ci if (!memcmp(flash_command_table[i].command, 8288c2ecf20Sopenharmony_ci cmd_ptr, strlen(cmd_ptr))) { 8298c2ecf20Sopenharmony_ci flash_command = flash_command_table[i].code; 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci if (flash_command == FLASH_CMD_NONE) { 8348c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_PARAMETERS; 8358c2ecf20Sopenharmony_ci ret = -EINVAL; 8368c2ecf20Sopenharmony_ci goto out; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci ret = request_firmware(&pm8001_ha->fw_image, 8408c2ecf20Sopenharmony_ci filename_ptr, 8418c2ecf20Sopenharmony_ci pm8001_ha->dev); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (ret) { 8448c2ecf20Sopenharmony_ci pm8001_dbg(pm8001_ha, FAIL, 8458c2ecf20Sopenharmony_ci "Failed to load firmware image file %s, error %d\n", 8468c2ecf20Sopenharmony_ci filename_ptr, ret); 8478c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE; 8488c2ecf20Sopenharmony_ci goto out; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (FLASH_CMD_UPDATE == flash_command) 8528c2ecf20Sopenharmony_ci ret = pm8001_update_flash(pm8001_ha); 8538c2ecf20Sopenharmony_ci else 8548c2ecf20Sopenharmony_ci ret = pm8001_set_nvmd(pm8001_ha); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci release_firmware(pm8001_ha->fw_image); 8578c2ecf20Sopenharmony_ciout: 8588c2ecf20Sopenharmony_ci kfree(cmd_ptr); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (ret) 8618c2ecf20Sopenharmony_ci return ret; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FLASH_OK; 8648c2ecf20Sopenharmony_ci return count; 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic ssize_t pm8001_show_update_fw(struct device *cdev, 8688c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci int i; 8718c2ecf20Sopenharmony_ci struct Scsi_Host *shost = class_to_shost(cdev); 8728c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 8738c2ecf20Sopenharmony_ci struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci for (i = 0; flash_error_table[i].err_code != 0; i++) { 8768c2ecf20Sopenharmony_ci if (flash_error_table[i].err_code == pm8001_ha->fw_status) 8778c2ecf20Sopenharmony_ci break; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci if (pm8001_ha->fw_status != FLASH_IN_PROGRESS) 8808c2ecf20Sopenharmony_ci pm8001_ha->fw_status = FLASH_OK; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "status=%x %s\n", 8838c2ecf20Sopenharmony_ci flash_error_table[i].err_code, 8848c2ecf20Sopenharmony_ci flash_error_table[i].reason); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP, 8888c2ecf20Sopenharmony_ci pm8001_show_update_fw, pm8001_store_update_fw); 8898c2ecf20Sopenharmony_cistruct device_attribute *pm8001_host_attrs[] = { 8908c2ecf20Sopenharmony_ci &dev_attr_interface_rev, 8918c2ecf20Sopenharmony_ci &dev_attr_controller_fatal_error, 8928c2ecf20Sopenharmony_ci &dev_attr_fw_version, 8938c2ecf20Sopenharmony_ci &dev_attr_update_fw, 8948c2ecf20Sopenharmony_ci &dev_attr_aap_log, 8958c2ecf20Sopenharmony_ci &dev_attr_iop_log, 8968c2ecf20Sopenharmony_ci &dev_attr_fatal_log, 8978c2ecf20Sopenharmony_ci &dev_attr_non_fatal_log, 8988c2ecf20Sopenharmony_ci &dev_attr_non_fatal_count, 8998c2ecf20Sopenharmony_ci &dev_attr_gsm_log, 9008c2ecf20Sopenharmony_ci &dev_attr_max_out_io, 9018c2ecf20Sopenharmony_ci &dev_attr_max_devices, 9028c2ecf20Sopenharmony_ci &dev_attr_max_sg_list, 9038c2ecf20Sopenharmony_ci &dev_attr_sas_spec_support, 9048c2ecf20Sopenharmony_ci &dev_attr_logging_level, 9058c2ecf20Sopenharmony_ci &dev_attr_event_log_size, 9068c2ecf20Sopenharmony_ci &dev_attr_host_sas_address, 9078c2ecf20Sopenharmony_ci &dev_attr_bios_version, 9088c2ecf20Sopenharmony_ci &dev_attr_ib_log, 9098c2ecf20Sopenharmony_ci &dev_attr_ob_log, 9108c2ecf20Sopenharmony_ci &dev_attr_ila_version, 9118c2ecf20Sopenharmony_ci &dev_attr_inc_fw_ver, 9128c2ecf20Sopenharmony_ci NULL, 9138c2ecf20Sopenharmony_ci}; 9148c2ecf20Sopenharmony_ci 915