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