cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pm8001_ctl.c (32165B)


      1/*
      2 * PMC-Sierra 8001/8081/8088/8089 SAS/SATA based host adapters driver
      3 *
      4 * Copyright (c) 2008-2009 USI Co., Ltd.
      5 * All rights reserved.
      6 *
      7 * Redistribution and use in source and binary forms, with or without
      8 * modification, are permitted provided that the following conditions
      9 * are met:
     10 * 1. Redistributions of source code must retain the above copyright
     11 *    notice, this list of conditions, and the following disclaimer,
     12 *    without modification.
     13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     14 *    substantially similar to the "NO WARRANTY" disclaimer below
     15 *    ("Disclaimer") and any redistribution must be conditioned upon
     16 *    including a substantially similar Disclaimer requirement for further
     17 *    binary redistribution.
     18 * 3. Neither the names of the above-listed copyright holders nor the names
     19 *    of any contributors may be used to endorse or promote products derived
     20 *    from this software without specific prior written permission.
     21 *
     22 * Alternatively, this software may be distributed under the terms of the
     23 * GNU General Public License ("GPL") version 2 as published by the Free
     24 * Software Foundation.
     25 *
     26 * NO WARRANTY
     27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     31 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37 * POSSIBILITY OF SUCH DAMAGES.
     38 *
     39 */
     40#include <linux/firmware.h>
     41#include <linux/slab.h>
     42#include "pm8001_sas.h"
     43#include "pm8001_ctl.h"
     44#include "pm8001_chips.h"
     45
     46/* scsi host attributes */
     47
     48/**
     49 * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number
     50 * @cdev: pointer to embedded class device
     51 * @attr: device attribute (unused)
     52 * @buf: the buffer returned
     53 *
     54 * A sysfs 'read-only' shost attribute.
     55 */
     56static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev,
     57	struct device_attribute *attr, char *buf)
     58{
     59	struct Scsi_Host *shost = class_to_shost(cdev);
     60	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
     61	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
     62
     63	if (pm8001_ha->chip_id == chip_8001) {
     64		return snprintf(buf, PAGE_SIZE, "%d\n",
     65			pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev);
     66	} else {
     67		return snprintf(buf, PAGE_SIZE, "%d\n",
     68			pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev);
     69	}
     70}
     71static
     72DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);
     73
     74/**
     75 * controller_fatal_error_show - check controller is under fatal err
     76 * @cdev: pointer to embedded class device
     77 * @attr: device attribute (unused)
     78 * @buf: the buffer returned
     79 *
     80 * A sysfs 'read-only' shost attribute.
     81 */
     82static ssize_t controller_fatal_error_show(struct device *cdev,
     83		struct device_attribute *attr, char *buf)
     84{
     85	struct Scsi_Host *shost = class_to_shost(cdev);
     86	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
     87	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
     88
     89	return snprintf(buf, PAGE_SIZE, "%d\n",
     90			pm8001_ha->controller_fatal_error);
     91}
     92static DEVICE_ATTR_RO(controller_fatal_error);
     93
     94/**
     95 * pm8001_ctl_fw_version_show - firmware version
     96 * @cdev: pointer to embedded class device
     97 * @attr: device attribute (unused)
     98 * @buf: the buffer returned
     99 *
    100 * A sysfs 'read-only' shost attribute.
    101 */
    102static ssize_t pm8001_ctl_fw_version_show(struct device *cdev,
    103	struct device_attribute *attr, char *buf)
    104{
    105	struct Scsi_Host *shost = class_to_shost(cdev);
    106	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    107	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    108
    109	if (pm8001_ha->chip_id == chip_8001) {
    110		return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
    111		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 24),
    112		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 16),
    113		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 8),
    114		(u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev));
    115	} else {
    116		return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
    117		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 24),
    118		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 16),
    119		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 8),
    120		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev));
    121	}
    122}
    123static DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL);
    124
    125/**
    126 * pm8001_ctl_ila_version_show - ila version
    127 * @cdev: pointer to embedded class device
    128 * @attr: device attribute (unused)
    129 * @buf: the buffer returned
    130 *
    131 * A sysfs 'read-only' shost attribute.
    132 */
    133static ssize_t pm8001_ctl_ila_version_show(struct device *cdev,
    134	struct device_attribute *attr, char *buf)
    135{
    136	struct Scsi_Host *shost = class_to_shost(cdev);
    137	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    138	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    139
    140	if (pm8001_ha->chip_id != chip_8001) {
    141		return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
    142		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 24),
    143		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 16),
    144		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 8),
    145		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version));
    146	}
    147	return 0;
    148}
    149static DEVICE_ATTR(ila_version, 0444, pm8001_ctl_ila_version_show, NULL);
    150
    151/**
    152 * pm8001_ctl_inactive_fw_version_show - Inactive firmware version number
    153 * @cdev: pointer to embedded class device
    154 * @attr: device attribute (unused)
    155 * @buf: the buffer returned
    156 *
    157 * A sysfs 'read-only' shost attribute.
    158 */
    159static ssize_t pm8001_ctl_inactive_fw_version_show(struct device *cdev,
    160	struct device_attribute *attr, char *buf)
    161{
    162	struct Scsi_Host *shost = class_to_shost(cdev);
    163	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    164	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    165
    166	if (pm8001_ha->chip_id != chip_8001) {
    167		return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
    168		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 24),
    169		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 16),
    170		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 8),
    171		(u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version));
    172	}
    173	return 0;
    174}
    175static
    176DEVICE_ATTR(inc_fw_ver, 0444, pm8001_ctl_inactive_fw_version_show, NULL);
    177
    178/**
    179 * pm8001_ctl_max_out_io_show - max outstanding io supported
    180 * @cdev: pointer to embedded class device
    181 * @attr: device attribute (unused)
    182 * @buf: the buffer returned
    183 *
    184 * A sysfs 'read-only' shost attribute.
    185 */
    186static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev,
    187	struct device_attribute *attr, char *buf)
    188{
    189	struct Scsi_Host *shost = class_to_shost(cdev);
    190	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    191	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    192
    193	if (pm8001_ha->chip_id == chip_8001) {
    194		return snprintf(buf, PAGE_SIZE, "%d\n",
    195			pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io);
    196	} else {
    197		return snprintf(buf, PAGE_SIZE, "%d\n",
    198			pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io);
    199	}
    200}
    201static DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL);
    202/**
    203 * pm8001_ctl_max_devices_show - max devices support
    204 * @cdev: pointer to embedded class device
    205 * @attr: device attribute (unused)
    206 * @buf: the buffer returned
    207 *
    208 * A sysfs 'read-only' shost attribute.
    209 */
    210static ssize_t pm8001_ctl_max_devices_show(struct device *cdev,
    211	struct device_attribute *attr, char *buf)
    212{
    213	struct Scsi_Host *shost = class_to_shost(cdev);
    214	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    215	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    216
    217	if (pm8001_ha->chip_id == chip_8001) {
    218		return snprintf(buf, PAGE_SIZE, "%04d\n",
    219			(u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16)
    220			);
    221	} else {
    222		return snprintf(buf, PAGE_SIZE, "%04d\n",
    223			(u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16)
    224			);
    225	}
    226}
    227static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL);
    228/**
    229 * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no
    230 * hardware limitation
    231 * @cdev: pointer to embedded class device
    232 * @attr: device attribute (unused)
    233 * @buf: the buffer returned
    234 *
    235 * A sysfs 'read-only' shost attribute.
    236 */
    237static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev,
    238	struct device_attribute *attr, char *buf)
    239{
    240	struct Scsi_Host *shost = class_to_shost(cdev);
    241	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    242	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    243
    244	if (pm8001_ha->chip_id == chip_8001) {
    245		return snprintf(buf, PAGE_SIZE, "%04d\n",
    246			pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF
    247			);
    248	} else {
    249		return snprintf(buf, PAGE_SIZE, "%04d\n",
    250			pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF
    251			);
    252	}
    253}
    254static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL);
    255
    256#define SAS_1_0 0x1
    257#define SAS_1_1 0x2
    258#define SAS_2_0 0x4
    259
    260static ssize_t
    261show_sas_spec_support_status(unsigned int mode, char *buf)
    262{
    263	ssize_t len = 0;
    264
    265	if (mode & SAS_1_1)
    266		len = sprintf(buf, "%s", "SAS1.1");
    267	if (mode & SAS_2_0)
    268		len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0");
    269	len += sprintf(buf + len, "\n");
    270
    271	return len;
    272}
    273
    274/**
    275 * pm8001_ctl_sas_spec_support_show - sas spec supported
    276 * @cdev: pointer to embedded class device
    277 * @attr: device attribute (unused)
    278 * @buf: the buffer returned
    279 *
    280 * A sysfs 'read-only' shost attribute.
    281 */
    282static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev,
    283	struct device_attribute *attr, char *buf)
    284{
    285	unsigned int mode;
    286	struct Scsi_Host *shost = class_to_shost(cdev);
    287	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    288	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    289	/* fe000000 means supports SAS2.1 */
    290	if (pm8001_ha->chip_id == chip_8001)
    291		mode = (pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag &
    292							0xfe000000)>>25;
    293	else
    294		/* fe000000 means supports SAS2.1 */
    295		mode = (pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag &
    296							0xfe000000)>>25;
    297	return show_sas_spec_support_status(mode, buf);
    298}
    299static DEVICE_ATTR(sas_spec_support, S_IRUGO,
    300		   pm8001_ctl_sas_spec_support_show, NULL);
    301
    302/**
    303 * pm8001_ctl_host_sas_address_show - sas address
    304 * @cdev: pointer to embedded class device
    305 * @attr: device attribute (unused)
    306 * @buf: the buffer returned
    307 *
    308 * This is the controller sas address
    309 *
    310 * A sysfs 'read-only' shost attribute.
    311 */
    312static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev,
    313	struct device_attribute *attr, char *buf)
    314{
    315	struct Scsi_Host *shost = class_to_shost(cdev);
    316	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    317	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    318	return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
    319			be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr));
    320}
    321static DEVICE_ATTR(host_sas_address, S_IRUGO,
    322		   pm8001_ctl_host_sas_address_show, NULL);
    323
    324/**
    325 * pm8001_ctl_logging_level_show - logging level
    326 * @cdev: pointer to embedded class device
    327 * @attr: device attribute (unused)
    328 * @buf: the buffer returned
    329 *
    330 * A sysfs 'read/write' shost attribute.
    331 */
    332static ssize_t pm8001_ctl_logging_level_show(struct device *cdev,
    333	struct device_attribute *attr, char *buf)
    334{
    335	struct Scsi_Host *shost = class_to_shost(cdev);
    336	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    337	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    338
    339	return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level);
    340}
    341
    342static ssize_t pm8001_ctl_logging_level_store(struct device *cdev,
    343	struct device_attribute *attr, const char *buf, size_t count)
    344{
    345	struct Scsi_Host *shost = class_to_shost(cdev);
    346	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    347	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    348	int val = 0;
    349
    350	if (sscanf(buf, "%x", &val) != 1)
    351		return -EINVAL;
    352
    353	pm8001_ha->logging_level = val;
    354	return strlen(buf);
    355}
    356
    357static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
    358	pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store);
    359/**
    360 * pm8001_ctl_aap_log_show - aap1 event log
    361 * @cdev: pointer to embedded class device
    362 * @attr: device attribute (unused)
    363 * @buf: the buffer returned
    364 *
    365 * A sysfs 'read-only' shost attribute.
    366 */
    367static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
    368	struct device_attribute *attr, char *buf)
    369{
    370	struct Scsi_Host *shost = class_to_shost(cdev);
    371	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    372	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    373	u8 *ptr = (u8 *)pm8001_ha->memoryMap.region[AAP1].virt_ptr;
    374	int i;
    375
    376	char *str = buf;
    377	int max = 2;
    378	for (i = 0; i < max; i++) {
    379		str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"
    380			       "0x%08x 0x%08x\n",
    381			       pm8001_ctl_aap1_memmap(ptr, i, 0),
    382			       pm8001_ctl_aap1_memmap(ptr, i, 4),
    383			       pm8001_ctl_aap1_memmap(ptr, i, 8),
    384			       pm8001_ctl_aap1_memmap(ptr, i, 12),
    385			       pm8001_ctl_aap1_memmap(ptr, i, 16),
    386			       pm8001_ctl_aap1_memmap(ptr, i, 20),
    387			       pm8001_ctl_aap1_memmap(ptr, i, 24),
    388			       pm8001_ctl_aap1_memmap(ptr, i, 28));
    389	}
    390
    391	return str - buf;
    392}
    393static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
    394/**
    395 * pm8001_ctl_ib_queue_log_show - Out bound Queue log
    396 * @cdev:pointer to embedded class device
    397 * @attr: device attribute (unused)
    398 * @buf: the buffer returned
    399 *
    400 * A sysfs 'read-only' shost attribute.
    401 */
    402static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,
    403	struct device_attribute *attr, char *buf)
    404{
    405	struct Scsi_Host *shost = class_to_shost(cdev);
    406	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    407	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    408	int offset;
    409	char *str = buf;
    410	int start = 0;
    411	u32 ib_offset = pm8001_ha->ib_offset;
    412	u32 queue_size = pm8001_ha->max_q_num * PM8001_MPI_QUEUE * 128;
    413#define IB_MEMMAP(c)	\
    414		(*(u32 *)((u8 *)pm8001_ha->	\
    415		memoryMap.region[ib_offset].virt_ptr +	\
    416		pm8001_ha->evtlog_ib_offset + (c)))
    417
    418	for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
    419		str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));
    420		start = start + 4;
    421	}
    422	pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;
    423	if (((pm8001_ha->evtlog_ib_offset) % queue_size) == 0)
    424		pm8001_ha->evtlog_ib_offset = 0;
    425
    426	return str - buf;
    427}
    428
    429static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);
    430/**
    431 * pm8001_ctl_ob_queue_log_show - Out bound Queue log
    432 * @cdev:pointer to embedded class device
    433 * @attr: device attribute (unused)
    434 * @buf: the buffer returned
    435 *
    436 * A sysfs 'read-only' shost attribute.
    437 */
    438
    439static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev,
    440	struct device_attribute *attr, char *buf)
    441{
    442	struct Scsi_Host *shost = class_to_shost(cdev);
    443	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    444	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    445	int offset;
    446	char *str = buf;
    447	int start = 0;
    448	u32 ob_offset = pm8001_ha->ob_offset;
    449	u32 queue_size = pm8001_ha->max_q_num * PM8001_MPI_QUEUE * 128;
    450#define OB_MEMMAP(c)	\
    451		(*(u32 *)((u8 *)pm8001_ha->	\
    452		memoryMap.region[ob_offset].virt_ptr +	\
    453		pm8001_ha->evtlog_ob_offset + (c)))
    454
    455	for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {
    456		str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));
    457		start = start + 4;
    458	}
    459	pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;
    460	if (((pm8001_ha->evtlog_ob_offset) % queue_size) == 0)
    461		pm8001_ha->evtlog_ob_offset = 0;
    462
    463	return str - buf;
    464}
    465static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);
    466/**
    467 * pm8001_ctl_bios_version_show - Bios version Display
    468 * @cdev:pointer to embedded class device
    469 * @attr: device attribute (unused)
    470 * @buf:the buffer returned
    471 *
    472 * A sysfs 'read-only' shost attribute.
    473 */
    474static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
    475	struct device_attribute *attr, char *buf)
    476{
    477	struct Scsi_Host *shost = class_to_shost(cdev);
    478	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    479	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    480	char *str = buf;
    481	int bios_index;
    482	DECLARE_COMPLETION_ONSTACK(completion);
    483	struct pm8001_ioctl_payload payload;
    484
    485	pm8001_ha->nvmd_completion = &completion;
    486	payload.minor_function = 7;
    487	payload.offset = 0;
    488	payload.rd_length = 4096;
    489	payload.func_specific = kzalloc(4096, GFP_KERNEL);
    490	if (!payload.func_specific)
    491		return -ENOMEM;
    492	if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) {
    493		kfree(payload.func_specific);
    494		return -ENOMEM;
    495	}
    496	wait_for_completion(&completion);
    497	for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT;
    498		bios_index++)
    499		str += sprintf(str, "%c",
    500			*(payload.func_specific+bios_index));
    501	kfree(payload.func_specific);
    502	return str - buf;
    503}
    504static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);
    505/**
    506 * event_log_size_show - event log size
    507 * @cdev: pointer to embedded class device
    508 * @attr: device attribute (unused)
    509 * @buf: the buffer returned
    510 *
    511 * A sysfs read  shost attribute.
    512 */
    513static ssize_t event_log_size_show(struct device *cdev,
    514	struct device_attribute *attr, char *buf)
    515{
    516	struct Scsi_Host *shost = class_to_shost(cdev);
    517	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    518	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    519
    520	return snprintf(buf, PAGE_SIZE, "%d\n",
    521		pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);
    522}
    523static DEVICE_ATTR_RO(event_log_size);
    524/**
    525 * pm8001_ctl_iop_log_show - IOP event log
    526 * @cdev: pointer to embedded class device
    527 * @attr: device attribute (unused)
    528 * @buf: the buffer returned
    529 *
    530 * A sysfs 'read-only' shost attribute.
    531 */
    532static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
    533	struct device_attribute *attr, char *buf)
    534{
    535	struct Scsi_Host *shost = class_to_shost(cdev);
    536	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    537	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    538	char *str = buf;
    539	u32 read_size =
    540		pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024;
    541	static u32 start, end, count;
    542	u32 max_read_times = 32;
    543	u32 max_count = (read_size * 1024) / (max_read_times * 4);
    544	u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr;
    545
    546	if ((count % max_count) == 0) {
    547		start = 0;
    548		end = max_read_times;
    549		count = 0;
    550	} else {
    551		start = end;
    552		end = end + max_read_times;
    553	}
    554
    555	for (; start < end; start++)
    556		str += sprintf(str, "%08x ", *(temp+start));
    557	count++;
    558	return str - buf;
    559}
    560static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
    561
    562/**
    563 * pm8001_ctl_fatal_log_show - fatal error logging
    564 * @cdev:pointer to embedded class device
    565 * @attr: device attribute
    566 * @buf: the buffer returned
    567 *
    568 * A sysfs 'read-only' shost attribute.
    569 */
    570
    571static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
    572	struct device_attribute *attr, char *buf)
    573{
    574	ssize_t count;
    575
    576	count = pm80xx_get_fatal_dump(cdev, attr, buf);
    577	return count;
    578}
    579
    580static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
    581
    582/**
    583 * non_fatal_log_show - non fatal error logging
    584 * @cdev:pointer to embedded class device
    585 * @attr: device attribute
    586 * @buf: the buffer returned
    587 *
    588 * A sysfs 'read-only' shost attribute.
    589 */
    590static ssize_t non_fatal_log_show(struct device *cdev,
    591	struct device_attribute *attr, char *buf)
    592{
    593	u32 count;
    594
    595	count = pm80xx_get_non_fatal_dump(cdev, attr, buf);
    596	return count;
    597}
    598static DEVICE_ATTR_RO(non_fatal_log);
    599
    600static ssize_t non_fatal_count_show(struct device *cdev,
    601		struct device_attribute *attr, char *buf)
    602{
    603	struct Scsi_Host *shost = class_to_shost(cdev);
    604	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    605	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    606
    607	return snprintf(buf, PAGE_SIZE, "%08x",
    608			pm8001_ha->non_fatal_count);
    609}
    610
    611static ssize_t non_fatal_count_store(struct device *cdev,
    612		struct device_attribute *attr, const char *buf, size_t count)
    613{
    614	struct Scsi_Host *shost = class_to_shost(cdev);
    615	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    616	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    617	int val = 0;
    618
    619	if (kstrtoint(buf, 16, &val) != 0)
    620		return -EINVAL;
    621
    622	pm8001_ha->non_fatal_count = val;
    623	return strlen(buf);
    624}
    625static DEVICE_ATTR_RW(non_fatal_count);
    626
    627/**
    628 * pm8001_ctl_gsm_log_show - gsm dump collection
    629 * @cdev:pointer to embedded class device
    630 * @attr: device attribute (unused)
    631 * @buf: the buffer returned
    632 *
    633 * A sysfs 'read-only' shost attribute.
    634 */
    635static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,
    636	struct device_attribute *attr, char *buf)
    637{
    638	ssize_t count;
    639
    640	count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);
    641	return count;
    642}
    643
    644static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);
    645
    646#define FLASH_CMD_NONE      0x00
    647#define FLASH_CMD_UPDATE    0x01
    648#define FLASH_CMD_SET_NVMD    0x02
    649
    650struct flash_command {
    651     u8      command[8];
    652     int     code;
    653};
    654
    655static const struct flash_command flash_command_table[] = {
    656     {"set_nvmd",    FLASH_CMD_SET_NVMD},
    657     {"update",      FLASH_CMD_UPDATE},
    658     {"",            FLASH_CMD_NONE} /* Last entry should be NULL. */
    659};
    660
    661struct error_fw {
    662     char    *reason;
    663     int     err_code;
    664};
    665
    666static const struct error_fw flash_error_table[] = {
    667     {"Failed to open fw image file",	FAIL_OPEN_BIOS_FILE},
    668     {"image header mismatch",		FLASH_UPDATE_HDR_ERR},
    669     {"image offset mismatch",		FLASH_UPDATE_OFFSET_ERR},
    670     {"image CRC Error",		FLASH_UPDATE_CRC_ERR},
    671     {"image length Error.",		FLASH_UPDATE_LENGTH_ERR},
    672     {"Failed to program flash chip",	FLASH_UPDATE_HW_ERR},
    673     {"Flash chip not supported.",	FLASH_UPDATE_DNLD_NOT_SUPPORTED},
    674     {"Flash update disabled.",		FLASH_UPDATE_DISABLED},
    675     {"Flash in progress",		FLASH_IN_PROGRESS},
    676     {"Image file size Error",		FAIL_FILE_SIZE},
    677     {"Input parameter error",		FAIL_PARAMETERS},
    678     {"Out of memory",			FAIL_OUT_MEMORY},
    679     {"OK", 0}	/* Last entry err_code = 0. */
    680};
    681
    682static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
    683{
    684	struct pm8001_ioctl_payload	*payload;
    685	DECLARE_COMPLETION_ONSTACK(completion);
    686	u8		*ioctlbuffer;
    687	u32		ret;
    688	u32		length = 1024 * 5 + sizeof(*payload) - 1;
    689
    690	if (pm8001_ha->fw_image->size > 4096) {
    691		pm8001_ha->fw_status = FAIL_FILE_SIZE;
    692		return -EFAULT;
    693	}
    694
    695	ioctlbuffer = kzalloc(length, GFP_KERNEL);
    696	if (!ioctlbuffer) {
    697		pm8001_ha->fw_status = FAIL_OUT_MEMORY;
    698		return -ENOMEM;
    699	}
    700	payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
    701	memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
    702				pm8001_ha->fw_image->size);
    703	payload->wr_length = pm8001_ha->fw_image->size;
    704	payload->id = 0;
    705	payload->minor_function = 0x1;
    706	pm8001_ha->nvmd_completion = &completion;
    707	ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);
    708	if (ret) {
    709		pm8001_ha->fw_status = FAIL_OUT_MEMORY;
    710		goto out;
    711	}
    712	wait_for_completion(&completion);
    713out:
    714	kfree(ioctlbuffer);
    715	return ret;
    716}
    717
    718static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
    719{
    720	struct pm8001_ioctl_payload	*payload;
    721	DECLARE_COMPLETION_ONSTACK(completion);
    722	u8		*ioctlbuffer;
    723	struct fw_control_info	*fwControl;
    724	__be32		partitionSizeTmp;
    725	u32		partitionSize;
    726	u32		loopNumber, loopcount;
    727	struct pm8001_fw_image_header *image_hdr;
    728	u32		sizeRead = 0;
    729	u32		ret = 0;
    730	u32		length = 1024 * 16 + sizeof(*payload) - 1;
    731	u32		fc_len;
    732	u8		*read_buf;
    733
    734	if (pm8001_ha->fw_image->size < 28) {
    735		pm8001_ha->fw_status = FAIL_FILE_SIZE;
    736		return -EFAULT;
    737	}
    738	ioctlbuffer = kzalloc(length, GFP_KERNEL);
    739	if (!ioctlbuffer) {
    740		pm8001_ha->fw_status = FAIL_OUT_MEMORY;
    741		return -ENOMEM;
    742	}
    743	image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;
    744	while (sizeRead < pm8001_ha->fw_image->size) {
    745		partitionSizeTmp =
    746			*(__be32 *)((u8 *)&image_hdr->image_length + sizeRead);
    747		partitionSize = be32_to_cpu(partitionSizeTmp);
    748		loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN,
    749					IOCTL_BUF_SIZE);
    750		for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
    751			payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
    752			payload->wr_length = 1024*16;
    753			payload->id = 0;
    754			fwControl =
    755			      (struct fw_control_info *)&payload->func_specific;
    756			fwControl->len = IOCTL_BUF_SIZE;   /* IN */
    757			fwControl->size = partitionSize + HEADER_LEN;/* IN */
    758			fwControl->retcode = 0;/* OUT */
    759			fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */
    760
    761			/*
    762			 * for the last chunk of data in case file size is
    763			 * not even with 4k, load only the rest
    764			 */
    765
    766			read_buf  = (u8 *)pm8001_ha->fw_image->data + sizeRead;
    767			fc_len = (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;
    768
    769			if (loopcount - loopNumber == 1 && fc_len) {
    770				fwControl->len = fc_len;
    771				memcpy((u8 *)fwControl->buffer, read_buf, fc_len);
    772				sizeRead += fc_len;
    773			} else {
    774				memcpy((u8 *)fwControl->buffer, read_buf, IOCTL_BUF_SIZE);
    775				sizeRead += IOCTL_BUF_SIZE;
    776			}
    777
    778			pm8001_ha->nvmd_completion = &completion;
    779			ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);
    780			if (ret) {
    781				pm8001_ha->fw_status = FAIL_OUT_MEMORY;
    782				goto out;
    783			}
    784			wait_for_completion(&completion);
    785			if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) {
    786				pm8001_ha->fw_status = fwControl->retcode;
    787				ret = -EFAULT;
    788				goto out;
    789			}
    790		}
    791	}
    792out:
    793	kfree(ioctlbuffer);
    794	return ret;
    795}
    796static ssize_t pm8001_store_update_fw(struct device *cdev,
    797				      struct device_attribute *attr,
    798				      const char *buf, size_t count)
    799{
    800	struct Scsi_Host *shost = class_to_shost(cdev);
    801	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    802	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    803	char *cmd_ptr, *filename_ptr;
    804	int res, i;
    805	int flash_command = FLASH_CMD_NONE;
    806	int ret;
    807
    808	if (!capable(CAP_SYS_ADMIN))
    809		return -EACCES;
    810
    811	/* this test protects us from running two flash processes at once,
    812	 * so we should start with this test */
    813	if (pm8001_ha->fw_status == FLASH_IN_PROGRESS)
    814		return -EINPROGRESS;
    815	pm8001_ha->fw_status = FLASH_IN_PROGRESS;
    816
    817	cmd_ptr = kcalloc(count, 2, GFP_KERNEL);
    818	if (!cmd_ptr) {
    819		pm8001_ha->fw_status = FAIL_OUT_MEMORY;
    820		return -ENOMEM;
    821	}
    822
    823	filename_ptr = cmd_ptr + count;
    824	res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);
    825	if (res != 2) {
    826		pm8001_ha->fw_status = FAIL_PARAMETERS;
    827		ret = -EINVAL;
    828		goto out;
    829	}
    830
    831	for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {
    832		if (!memcmp(flash_command_table[i].command,
    833				 cmd_ptr, strlen(cmd_ptr))) {
    834			flash_command = flash_command_table[i].code;
    835			break;
    836		}
    837	}
    838	if (flash_command == FLASH_CMD_NONE) {
    839		pm8001_ha->fw_status = FAIL_PARAMETERS;
    840		ret = -EINVAL;
    841		goto out;
    842	}
    843
    844	ret = request_firmware(&pm8001_ha->fw_image,
    845			       filename_ptr,
    846			       pm8001_ha->dev);
    847
    848	if (ret) {
    849		pm8001_dbg(pm8001_ha, FAIL,
    850			   "Failed to load firmware image file %s, error %d\n",
    851			   filename_ptr, ret);
    852		pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE;
    853		goto out;
    854	}
    855
    856	if (FLASH_CMD_UPDATE == flash_command)
    857		ret = pm8001_update_flash(pm8001_ha);
    858	else
    859		ret = pm8001_set_nvmd(pm8001_ha);
    860
    861	release_firmware(pm8001_ha->fw_image);
    862out:
    863	kfree(cmd_ptr);
    864
    865	if (ret)
    866		return ret;
    867
    868	pm8001_ha->fw_status = FLASH_OK;
    869	return count;
    870}
    871
    872static ssize_t pm8001_show_update_fw(struct device *cdev,
    873				     struct device_attribute *attr, char *buf)
    874{
    875	int i;
    876	struct Scsi_Host *shost = class_to_shost(cdev);
    877	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    878	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    879
    880	for (i = 0; flash_error_table[i].err_code != 0; i++) {
    881		if (flash_error_table[i].err_code == pm8001_ha->fw_status)
    882			break;
    883	}
    884	if (pm8001_ha->fw_status != FLASH_IN_PROGRESS)
    885		pm8001_ha->fw_status = FLASH_OK;
    886
    887	return snprintf(buf, PAGE_SIZE, "status=%x %s\n",
    888			flash_error_table[i].err_code,
    889			flash_error_table[i].reason);
    890}
    891static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP,
    892	pm8001_show_update_fw, pm8001_store_update_fw);
    893
    894static const char *const mpiStateText[] = {
    895	"MPI is not initialized",
    896	"MPI is successfully initialized",
    897	"MPI termination is in progress",
    898	"MPI initialization failed with error in [31:16]"
    899};
    900
    901/**
    902 * ctl_mpi_state_show - controller MPI state check
    903 * @cdev: pointer to embedded class device
    904 * @attr: device attribute (unused)
    905 * @buf: the buffer returned
    906 *
    907 * A sysfs 'read-only' shost attribute.
    908 */
    909static ssize_t ctl_mpi_state_show(struct device *cdev,
    910		struct device_attribute *attr, char *buf)
    911{
    912	struct Scsi_Host *shost = class_to_shost(cdev);
    913	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    914	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    915	unsigned int mpidw0;
    916
    917	mpidw0 = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 0);
    918	return sysfs_emit(buf, "%s\n", mpiStateText[mpidw0 & 0x0003]);
    919}
    920static DEVICE_ATTR_RO(ctl_mpi_state);
    921
    922/**
    923 * ctl_hmi_error_show - controller MPI initialization fails
    924 * @cdev: pointer to embedded class device
    925 * @attr: device attribute (unused)
    926 * @buf: the buffer returned
    927 *
    928 * A sysfs 'read-only' shost attribute.
    929 */
    930static ssize_t ctl_hmi_error_show(struct device *cdev,
    931		struct device_attribute *attr, char *buf)
    932{
    933	struct Scsi_Host *shost = class_to_shost(cdev);
    934	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    935	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    936	unsigned int mpidw0;
    937
    938	mpidw0 = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 0);
    939	return sysfs_emit(buf, "0x%08x\n", (mpidw0 >> 16));
    940}
    941static DEVICE_ATTR_RO(ctl_hmi_error);
    942
    943/**
    944 * ctl_raae_count_show - controller raae count check
    945 * @cdev: pointer to embedded class device
    946 * @attr: device attribute (unused)
    947 * @buf: the buffer returned
    948 *
    949 * A sysfs 'read-only' shost attribute.
    950 */
    951static ssize_t ctl_raae_count_show(struct device *cdev,
    952		struct device_attribute *attr, char *buf)
    953{
    954	struct Scsi_Host *shost = class_to_shost(cdev);
    955	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    956	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    957	unsigned int raaecnt;
    958
    959	raaecnt = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 12);
    960	return sysfs_emit(buf, "0x%08x\n", raaecnt);
    961}
    962static DEVICE_ATTR_RO(ctl_raae_count);
    963
    964/**
    965 * ctl_iop0_count_show - controller iop0 count check
    966 * @cdev: pointer to embedded class device
    967 * @attr: device attribute (unused)
    968 * @buf: the buffer returned
    969 *
    970 * A sysfs 'read-only' shost attribute.
    971 */
    972static ssize_t ctl_iop0_count_show(struct device *cdev,
    973		struct device_attribute *attr, char *buf)
    974{
    975	struct Scsi_Host *shost = class_to_shost(cdev);
    976	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    977	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    978	unsigned int iop0cnt;
    979
    980	iop0cnt = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 16);
    981	return sysfs_emit(buf, "0x%08x\n", iop0cnt);
    982}
    983static DEVICE_ATTR_RO(ctl_iop0_count);
    984
    985/**
    986 * ctl_iop1_count_show - controller iop1 count check
    987 * @cdev: pointer to embedded class device
    988 * @attr: device attribute (unused)
    989 * @buf: the buffer returned
    990 *
    991 * A sysfs 'read-only' shost attribute.
    992 */
    993static ssize_t ctl_iop1_count_show(struct device *cdev,
    994		struct device_attribute *attr, char *buf)
    995{
    996	struct Scsi_Host *shost = class_to_shost(cdev);
    997	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
    998	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
    999	unsigned int iop1cnt;
   1000
   1001	iop1cnt = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 20);
   1002	return sysfs_emit(buf, "0x%08x\n", iop1cnt);
   1003
   1004}
   1005static DEVICE_ATTR_RO(ctl_iop1_count);
   1006
   1007static struct attribute *pm8001_host_attrs[] = {
   1008	&dev_attr_interface_rev.attr,
   1009	&dev_attr_controller_fatal_error.attr,
   1010	&dev_attr_fw_version.attr,
   1011	&dev_attr_update_fw.attr,
   1012	&dev_attr_aap_log.attr,
   1013	&dev_attr_iop_log.attr,
   1014	&dev_attr_fatal_log.attr,
   1015	&dev_attr_non_fatal_log.attr,
   1016	&dev_attr_non_fatal_count.attr,
   1017	&dev_attr_gsm_log.attr,
   1018	&dev_attr_max_out_io.attr,
   1019	&dev_attr_max_devices.attr,
   1020	&dev_attr_max_sg_list.attr,
   1021	&dev_attr_sas_spec_support.attr,
   1022	&dev_attr_logging_level.attr,
   1023	&dev_attr_event_log_size.attr,
   1024	&dev_attr_host_sas_address.attr,
   1025	&dev_attr_bios_version.attr,
   1026	&dev_attr_ib_log.attr,
   1027	&dev_attr_ob_log.attr,
   1028	&dev_attr_ila_version.attr,
   1029	&dev_attr_inc_fw_ver.attr,
   1030	&dev_attr_ctl_mpi_state.attr,
   1031	&dev_attr_ctl_hmi_error.attr,
   1032	&dev_attr_ctl_raae_count.attr,
   1033	&dev_attr_ctl_iop0_count.attr,
   1034	&dev_attr_ctl_iop1_count.attr,
   1035	NULL,
   1036};
   1037
   1038static const struct attribute_group pm8001_host_attr_group = {
   1039	.attrs = pm8001_host_attrs
   1040};
   1041
   1042const struct attribute_group *pm8001_host_groups[] = {
   1043	&pm8001_host_attr_group,
   1044	NULL
   1045};