1dbf9bfe6Sjack wang /* 2e5742101SSakthivel K * PMC-Sierra 8001/8081/8088/8089 SAS/SATA based host adapters driver 3dbf9bfe6Sjack wang * 4dbf9bfe6Sjack wang * Copyright (c) 2008-2009 USI Co., Ltd. 5dbf9bfe6Sjack wang * All rights reserved. 6dbf9bfe6Sjack wang * 7dbf9bfe6Sjack wang * Redistribution and use in source and binary forms, with or without 8dbf9bfe6Sjack wang * modification, are permitted provided that the following conditions 9dbf9bfe6Sjack wang * are met: 10dbf9bfe6Sjack wang * 1. Redistributions of source code must retain the above copyright 11dbf9bfe6Sjack wang * notice, this list of conditions, and the following disclaimer, 12dbf9bfe6Sjack wang * without modification. 13dbf9bfe6Sjack wang * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14dbf9bfe6Sjack wang * substantially similar to the "NO WARRANTY" disclaimer below 15dbf9bfe6Sjack wang * ("Disclaimer") and any redistribution must be conditioned upon 16dbf9bfe6Sjack wang * including a substantially similar Disclaimer requirement for further 17dbf9bfe6Sjack wang * binary redistribution. 18dbf9bfe6Sjack wang * 3. Neither the names of the above-listed copyright holders nor the names 19dbf9bfe6Sjack wang * of any contributors may be used to endorse or promote products derived 20dbf9bfe6Sjack wang * from this software without specific prior written permission. 21dbf9bfe6Sjack wang * 22dbf9bfe6Sjack wang * Alternatively, this software may be distributed under the terms of the 23dbf9bfe6Sjack wang * GNU General Public License ("GPL") version 2 as published by the Free 24dbf9bfe6Sjack wang * Software Foundation. 25dbf9bfe6Sjack wang * 26dbf9bfe6Sjack wang * NO WARRANTY 27dbf9bfe6Sjack wang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28dbf9bfe6Sjack wang * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29dbf9bfe6Sjack wang * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 30dbf9bfe6Sjack wang * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31dbf9bfe6Sjack wang * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32dbf9bfe6Sjack wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33dbf9bfe6Sjack wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34dbf9bfe6Sjack wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 35dbf9bfe6Sjack wang * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 36dbf9bfe6Sjack wang * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37dbf9bfe6Sjack wang * POSSIBILITY OF SUCH DAMAGES. 38dbf9bfe6Sjack wang * 39dbf9bfe6Sjack wang */ 40dbf9bfe6Sjack wang #include <linux/firmware.h> 415a0e3ad6STejun Heo #include <linux/slab.h> 42dbf9bfe6Sjack wang #include "pm8001_sas.h" 43dbf9bfe6Sjack wang #include "pm8001_ctl.h" 444ddbea1bSVishakha Channapattan #include "pm8001_chips.h" 45dbf9bfe6Sjack wang 46dbf9bfe6Sjack wang /* scsi host attributes */ 47dbf9bfe6Sjack wang 48dbf9bfe6Sjack wang /** 49dbf9bfe6Sjack wang * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number 50dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 51e1c3e0f8SLee Jones * @attr: device attribute (unused) 52dbf9bfe6Sjack wang * @buf: the buffer returned 53dbf9bfe6Sjack wang * 54dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 55dbf9bfe6Sjack wang */ 56dbf9bfe6Sjack wang static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev, 57dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 58dbf9bfe6Sjack wang { 59dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 60dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 61dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 62dbf9bfe6Sjack wang 63e5742101SSakthivel K if (pm8001_ha->chip_id == chip_8001) { 64dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "%d\n", 65e5742101SSakthivel K pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev); 66e5742101SSakthivel K } else { 67e5742101SSakthivel K return snprintf(buf, PAGE_SIZE, "%d\n", 68e5742101SSakthivel K pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev); 69e5742101SSakthivel K } 70dbf9bfe6Sjack wang } 71dbf9bfe6Sjack wang static 72dbf9bfe6Sjack wang DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL); 73dbf9bfe6Sjack wang 74dbf9bfe6Sjack wang /** 75e2773c67SDeepak Ukey * controller_fatal_error_show - check controller is under fatal err 76e2773c67SDeepak Ukey * @cdev: pointer to embedded class device 77e1c3e0f8SLee Jones * @attr: device attribute (unused) 78e2773c67SDeepak Ukey * @buf: the buffer returned 79e2773c67SDeepak Ukey * 80e2773c67SDeepak Ukey * A sysfs 'read only' shost attribute. 81e2773c67SDeepak Ukey */ 82e2773c67SDeepak Ukey static ssize_t controller_fatal_error_show(struct device *cdev, 83e2773c67SDeepak Ukey struct device_attribute *attr, char *buf) 84e2773c67SDeepak Ukey { 85e2773c67SDeepak Ukey struct Scsi_Host *shost = class_to_shost(cdev); 86e2773c67SDeepak Ukey struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 87e2773c67SDeepak Ukey struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 88e2773c67SDeepak Ukey 89e2773c67SDeepak Ukey return snprintf(buf, PAGE_SIZE, "%d\n", 90e2773c67SDeepak Ukey pm8001_ha->controller_fatal_error); 91e2773c67SDeepak Ukey } 92e2773c67SDeepak Ukey static DEVICE_ATTR_RO(controller_fatal_error); 93e2773c67SDeepak Ukey 94e2773c67SDeepak Ukey /** 95dbf9bfe6Sjack wang * pm8001_ctl_fw_version_show - firmware version 96dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 97cd2eebfdSLee Jones * @attr: device attribute (unused) 98dbf9bfe6Sjack wang * @buf: the buffer returned 99dbf9bfe6Sjack wang * 100dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 101dbf9bfe6Sjack wang */ 102dbf9bfe6Sjack wang static ssize_t pm8001_ctl_fw_version_show(struct device *cdev, 103dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 104dbf9bfe6Sjack wang { 105dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 106dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 107dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 108dbf9bfe6Sjack wang 109e5742101SSakthivel K if (pm8001_ha->chip_id == chip_8001) { 110dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 111e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 24), 112e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 16), 113e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev >> 8), 114e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev)); 115e5742101SSakthivel K } else { 116e5742101SSakthivel K return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 117e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 24), 118e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 16), 119e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev >> 8), 120e5742101SSakthivel K (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev)); 121e5742101SSakthivel K } 122dbf9bfe6Sjack wang } 123dbf9bfe6Sjack wang static DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL); 12424fff017SViswas G 12524fff017SViswas G /** 12624fff017SViswas G * pm8001_ctl_ila_version_show - ila version 12724fff017SViswas G * @cdev: pointer to embedded class device 128e1c3e0f8SLee Jones * @attr: device attribute (unused) 12924fff017SViswas G * @buf: the buffer returned 13024fff017SViswas G * 13124fff017SViswas G * A sysfs 'read-only' shost attribute. 13224fff017SViswas G */ 13324fff017SViswas G static ssize_t pm8001_ctl_ila_version_show(struct device *cdev, 13424fff017SViswas G struct device_attribute *attr, char *buf) 13524fff017SViswas G { 13624fff017SViswas G struct Scsi_Host *shost = class_to_shost(cdev); 13724fff017SViswas G struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 13824fff017SViswas G struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 13924fff017SViswas G 14024fff017SViswas G if (pm8001_ha->chip_id != chip_8001) { 14124fff017SViswas G return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 14224fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 24), 14324fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 16), 14424fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version >> 8), 14524fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version)); 14624fff017SViswas G } 14724fff017SViswas G return 0; 14824fff017SViswas G } 14924fff017SViswas G static DEVICE_ATTR(ila_version, 0444, pm8001_ctl_ila_version_show, NULL); 15024fff017SViswas G 15124fff017SViswas G /** 15224fff017SViswas G * pm8001_ctl_inactive_fw_version_show - Inacative firmware version number 15324fff017SViswas G * @cdev: pointer to embedded class device 154e1c3e0f8SLee Jones * @attr: device attribute (unused) 15524fff017SViswas G * @buf: the buffer returned 15624fff017SViswas G * 15724fff017SViswas G * A sysfs 'read-only' shost attribute. 15824fff017SViswas G */ 15924fff017SViswas G static ssize_t pm8001_ctl_inactive_fw_version_show(struct device *cdev, 16024fff017SViswas G struct device_attribute *attr, char *buf) 16124fff017SViswas G { 16224fff017SViswas G struct Scsi_Host *shost = class_to_shost(cdev); 16324fff017SViswas G struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 16424fff017SViswas G struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 16524fff017SViswas G 16624fff017SViswas G if (pm8001_ha->chip_id != chip_8001) { 16724fff017SViswas G return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", 16824fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 24), 16924fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 16), 17024fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version >> 8), 17124fff017SViswas G (u8)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version)); 17224fff017SViswas G } 17324fff017SViswas G return 0; 17424fff017SViswas G } 17524fff017SViswas G static 17624fff017SViswas G DEVICE_ATTR(inc_fw_ver, 0444, pm8001_ctl_inactive_fw_version_show, NULL); 17724fff017SViswas G 178dbf9bfe6Sjack wang /** 179dbf9bfe6Sjack wang * pm8001_ctl_max_out_io_show - max outstanding io supported 180dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 181e1c3e0f8SLee Jones * @attr: device attribute (unused) 182dbf9bfe6Sjack wang * @buf: the buffer returned 183dbf9bfe6Sjack wang * 184dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 185dbf9bfe6Sjack wang */ 186dbf9bfe6Sjack wang static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev, 187dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 188dbf9bfe6Sjack wang { 189dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 190dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 191dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 192dbf9bfe6Sjack wang 193e5742101SSakthivel K if (pm8001_ha->chip_id == chip_8001) { 194dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "%d\n", 195e5742101SSakthivel K pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io); 196e5742101SSakthivel K } else { 197e5742101SSakthivel K return snprintf(buf, PAGE_SIZE, "%d\n", 198e5742101SSakthivel K pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io); 199e5742101SSakthivel K } 200dbf9bfe6Sjack wang } 201dbf9bfe6Sjack wang static DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL); 202dbf9bfe6Sjack wang /** 203dbf9bfe6Sjack wang * pm8001_ctl_max_devices_show - max devices support 204dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 205e1c3e0f8SLee Jones * @attr: device attribute (unused) 206dbf9bfe6Sjack wang * @buf: the buffer returned 207dbf9bfe6Sjack wang * 208dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 209dbf9bfe6Sjack wang */ 210dbf9bfe6Sjack wang static ssize_t pm8001_ctl_max_devices_show(struct device *cdev, 211dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 212dbf9bfe6Sjack wang { 213dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 214dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 215dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 216dbf9bfe6Sjack wang 217e5742101SSakthivel K if (pm8001_ha->chip_id == chip_8001) { 218dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "%04d\n", 219e5742101SSakthivel K (u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16) 220e5742101SSakthivel K ); 221e5742101SSakthivel K } else { 222e5742101SSakthivel K return snprintf(buf, PAGE_SIZE, "%04d\n", 223e5742101SSakthivel K (u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16) 224e5742101SSakthivel K ); 225e5742101SSakthivel K } 226dbf9bfe6Sjack wang } 227dbf9bfe6Sjack wang static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL); 228dbf9bfe6Sjack wang /** 229dbf9bfe6Sjack wang * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no 230dbf9bfe6Sjack wang * hardware limitation 231dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 232e1c3e0f8SLee Jones * @attr: device attribute (unused) 233dbf9bfe6Sjack wang * @buf: the buffer returned 234dbf9bfe6Sjack wang * 235dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 236dbf9bfe6Sjack wang */ 237dbf9bfe6Sjack wang static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev, 238dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 239dbf9bfe6Sjack wang { 240dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 241dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 242dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 243dbf9bfe6Sjack wang 244e5742101SSakthivel K if (pm8001_ha->chip_id == chip_8001) { 245dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "%04d\n", 246e5742101SSakthivel K pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF 247e5742101SSakthivel K ); 248e5742101SSakthivel K } else { 249e5742101SSakthivel K return snprintf(buf, PAGE_SIZE, "%04d\n", 250e5742101SSakthivel K pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF 251e5742101SSakthivel K ); 252e5742101SSakthivel K } 253dbf9bfe6Sjack wang } 254dbf9bfe6Sjack wang static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL); 255dbf9bfe6Sjack wang 256dbf9bfe6Sjack wang #define SAS_1_0 0x1 257dbf9bfe6Sjack wang #define SAS_1_1 0x2 258dbf9bfe6Sjack wang #define SAS_2_0 0x4 259dbf9bfe6Sjack wang 260dbf9bfe6Sjack wang static ssize_t 261dbf9bfe6Sjack wang show_sas_spec_support_status(unsigned int mode, char *buf) 262dbf9bfe6Sjack wang { 263dbf9bfe6Sjack wang ssize_t len = 0; 264dbf9bfe6Sjack wang 265dbf9bfe6Sjack wang if (mode & SAS_1_1) 266dbf9bfe6Sjack wang len = sprintf(buf, "%s", "SAS1.1"); 267dbf9bfe6Sjack wang if (mode & SAS_2_0) 268dbf9bfe6Sjack wang len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0"); 269dbf9bfe6Sjack wang len += sprintf(buf + len, "\n"); 270dbf9bfe6Sjack wang 271dbf9bfe6Sjack wang return len; 272dbf9bfe6Sjack wang } 273dbf9bfe6Sjack wang 274dbf9bfe6Sjack wang /** 275dbf9bfe6Sjack wang * pm8001_ctl_sas_spec_support_show - sas spec supported 276dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 277e1c3e0f8SLee Jones * @attr: device attribute (unused) 278dbf9bfe6Sjack wang * @buf: the buffer returned 279dbf9bfe6Sjack wang * 280dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 281dbf9bfe6Sjack wang */ 282dbf9bfe6Sjack wang static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev, 283dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 284dbf9bfe6Sjack wang { 285dbf9bfe6Sjack wang unsigned int mode; 286dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 287dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 288dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 289e5742101SSakthivel K /* fe000000 means supports SAS2.1 */ 290e5742101SSakthivel K if (pm8001_ha->chip_id == chip_8001) 291e5742101SSakthivel K mode = (pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag & 292e5742101SSakthivel K 0xfe000000)>>25; 293e5742101SSakthivel K else 294e5742101SSakthivel K /* fe000000 means supports SAS2.1 */ 295e5742101SSakthivel K mode = (pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag & 296e5742101SSakthivel K 0xfe000000)>>25; 297dbf9bfe6Sjack wang return show_sas_spec_support_status(mode, buf); 298dbf9bfe6Sjack wang } 299dbf9bfe6Sjack wang static DEVICE_ATTR(sas_spec_support, S_IRUGO, 300dbf9bfe6Sjack wang pm8001_ctl_sas_spec_support_show, NULL); 301dbf9bfe6Sjack wang 302dbf9bfe6Sjack wang /** 3033978e59bSLee Jones * pm8001_ctl_host_sas_address_show - sas address 304dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 305e1c3e0f8SLee Jones * @attr: device attribute (unused) 306dbf9bfe6Sjack wang * @buf: the buffer returned 307dbf9bfe6Sjack wang * 308dbf9bfe6Sjack wang * This is the controller sas address 309dbf9bfe6Sjack wang * 310dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 311dbf9bfe6Sjack wang */ 312dbf9bfe6Sjack wang static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev, 313dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 314dbf9bfe6Sjack wang { 315dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 316dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 317dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 318dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "0x%016llx\n", 319dbf9bfe6Sjack wang be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr)); 320dbf9bfe6Sjack wang } 321dbf9bfe6Sjack wang static DEVICE_ATTR(host_sas_address, S_IRUGO, 322dbf9bfe6Sjack wang pm8001_ctl_host_sas_address_show, NULL); 323dbf9bfe6Sjack wang 324dbf9bfe6Sjack wang /** 325dbf9bfe6Sjack wang * pm8001_ctl_logging_level_show - logging level 326dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 327cd2eebfdSLee Jones * @attr: device attribute (unused) 328dbf9bfe6Sjack wang * @buf: the buffer returned 329dbf9bfe6Sjack wang * 330dbf9bfe6Sjack wang * A sysfs 'read/write' shost attribute. 331dbf9bfe6Sjack wang */ 332dbf9bfe6Sjack wang static ssize_t pm8001_ctl_logging_level_show(struct device *cdev, 333dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 334dbf9bfe6Sjack wang { 335dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 336dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 337dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 338dbf9bfe6Sjack wang 339dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level); 340dbf9bfe6Sjack wang } 341cd2eebfdSLee Jones 342dbf9bfe6Sjack wang static ssize_t pm8001_ctl_logging_level_store(struct device *cdev, 343dbf9bfe6Sjack wang struct device_attribute *attr, const char *buf, size_t count) 344dbf9bfe6Sjack wang { 345dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 346dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 347dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 348dbf9bfe6Sjack wang int val = 0; 349dbf9bfe6Sjack wang 350dbf9bfe6Sjack wang if (sscanf(buf, "%x", &val) != 1) 351dbf9bfe6Sjack wang return -EINVAL; 352dbf9bfe6Sjack wang 353dbf9bfe6Sjack wang pm8001_ha->logging_level = val; 354dbf9bfe6Sjack wang return strlen(buf); 355dbf9bfe6Sjack wang } 356dbf9bfe6Sjack wang 357dbf9bfe6Sjack wang static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, 358dbf9bfe6Sjack wang pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store); 359dbf9bfe6Sjack wang /** 360dbf9bfe6Sjack wang * pm8001_ctl_aap_log_show - aap1 event log 361dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 362e1c3e0f8SLee Jones * @attr: device attribute (unused) 363dbf9bfe6Sjack wang * @buf: the buffer returned 364dbf9bfe6Sjack wang * 365dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 366dbf9bfe6Sjack wang */ 367dbf9bfe6Sjack wang static ssize_t pm8001_ctl_aap_log_show(struct device *cdev, 368dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 369dbf9bfe6Sjack wang { 370dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 371dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 372dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 3738a23dbc6SLuo Jiaxing u8 *ptr = (u8 *)pm8001_ha->memoryMap.region[AAP1].virt_ptr; 374dbf9bfe6Sjack wang int i; 375dbf9bfe6Sjack wang 376dbf9bfe6Sjack wang char *str = buf; 377dbf9bfe6Sjack wang int max = 2; 378dbf9bfe6Sjack wang for (i = 0; i < max; i++) { 379dbf9bfe6Sjack wang str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" 380dbf9bfe6Sjack wang "0x%08x 0x%08x\n", 3818a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 0), 3828a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 4), 3838a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 8), 3848a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 12), 3858a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 16), 3868a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 20), 3878a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 24), 3888a23dbc6SLuo Jiaxing pm8001_ctl_aap1_memmap(ptr, i, 28)); 389dbf9bfe6Sjack wang } 390dbf9bfe6Sjack wang 391dbf9bfe6Sjack wang return str - buf; 392dbf9bfe6Sjack wang } 393dbf9bfe6Sjack wang static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL); 394dbf9bfe6Sjack wang /** 395d078b511SAnand Kumar Santhanam * pm8001_ctl_ib_queue_log_show - Out bound Queue log 396d078b511SAnand Kumar Santhanam * @cdev:pointer to embedded class device 397cd2eebfdSLee Jones * @attr: device attribute (unused) 398d078b511SAnand Kumar Santhanam * @buf: the buffer returned 399d078b511SAnand Kumar Santhanam * A sysfs 'read-only' shost attribute. 400d078b511SAnand Kumar Santhanam */ 401d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev, 402d078b511SAnand Kumar Santhanam struct device_attribute *attr, char *buf) 403d078b511SAnand Kumar Santhanam { 404d078b511SAnand Kumar Santhanam struct Scsi_Host *shost = class_to_shost(cdev); 405d078b511SAnand Kumar Santhanam struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 406d078b511SAnand Kumar Santhanam struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 407d078b511SAnand Kumar Santhanam int offset; 408d078b511SAnand Kumar Santhanam char *str = buf; 409d078b511SAnand Kumar Santhanam int start = 0; 41005c6c029SViswas G u32 ib_offset = pm8001_ha->ib_offset; 411d078b511SAnand Kumar Santhanam #define IB_MEMMAP(c) \ 412d078b511SAnand Kumar Santhanam (*(u32 *)((u8 *)pm8001_ha-> \ 41305c6c029SViswas G memoryMap.region[ib_offset].virt_ptr + \ 414d078b511SAnand Kumar Santhanam pm8001_ha->evtlog_ib_offset + (c))) 415d078b511SAnand Kumar Santhanam 416d078b511SAnand Kumar Santhanam for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { 417d078b511SAnand Kumar Santhanam str += sprintf(str, "0x%08x\n", IB_MEMMAP(start)); 418d078b511SAnand Kumar Santhanam start = start + 4; 419d078b511SAnand Kumar Santhanam } 420d078b511SAnand Kumar Santhanam pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET; 421859b5d10SViswas G if (((pm8001_ha->evtlog_ib_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) 422d078b511SAnand Kumar Santhanam pm8001_ha->evtlog_ib_offset = 0; 423d078b511SAnand Kumar Santhanam 424d078b511SAnand Kumar Santhanam return str - buf; 425d078b511SAnand Kumar Santhanam } 426d078b511SAnand Kumar Santhanam 427d078b511SAnand Kumar Santhanam static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL); 428d078b511SAnand Kumar Santhanam /** 429d078b511SAnand Kumar Santhanam * pm8001_ctl_ob_queue_log_show - Out bound Queue log 430d078b511SAnand Kumar Santhanam * @cdev:pointer to embedded class device 431cd2eebfdSLee Jones * @attr: device attribute (unused) 432d078b511SAnand Kumar Santhanam * @buf: the buffer returned 433d078b511SAnand Kumar Santhanam * A sysfs 'read-only' shost attribute. 434d078b511SAnand Kumar Santhanam */ 435d078b511SAnand Kumar Santhanam 436d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev, 437d078b511SAnand Kumar Santhanam struct device_attribute *attr, char *buf) 438d078b511SAnand Kumar Santhanam { 439d078b511SAnand Kumar Santhanam struct Scsi_Host *shost = class_to_shost(cdev); 440d078b511SAnand Kumar Santhanam struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 441d078b511SAnand Kumar Santhanam struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 442d078b511SAnand Kumar Santhanam int offset; 443d078b511SAnand Kumar Santhanam char *str = buf; 444d078b511SAnand Kumar Santhanam int start = 0; 44505c6c029SViswas G u32 ob_offset = pm8001_ha->ob_offset; 446d078b511SAnand Kumar Santhanam #define OB_MEMMAP(c) \ 447d078b511SAnand Kumar Santhanam (*(u32 *)((u8 *)pm8001_ha-> \ 44805c6c029SViswas G memoryMap.region[ob_offset].virt_ptr + \ 449d078b511SAnand Kumar Santhanam pm8001_ha->evtlog_ob_offset + (c))) 450d078b511SAnand Kumar Santhanam 451d078b511SAnand Kumar Santhanam for (offset = 0; offset < IB_OB_READ_TIMES; offset++) { 452d078b511SAnand Kumar Santhanam str += sprintf(str, "0x%08x\n", OB_MEMMAP(start)); 453d078b511SAnand Kumar Santhanam start = start + 4; 454d078b511SAnand Kumar Santhanam } 455d078b511SAnand Kumar Santhanam pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET; 456859b5d10SViswas G if (((pm8001_ha->evtlog_ob_offset) % (PM80XX_IB_OB_QUEUE_SIZE)) == 0) 457d078b511SAnand Kumar Santhanam pm8001_ha->evtlog_ob_offset = 0; 458d078b511SAnand Kumar Santhanam 459d078b511SAnand Kumar Santhanam return str - buf; 460d078b511SAnand Kumar Santhanam } 461d078b511SAnand Kumar Santhanam static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL); 462d078b511SAnand Kumar Santhanam /** 463966fdcffSAnand Kumar Santhanam * pm8001_ctl_bios_version_show - Bios version Display 464966fdcffSAnand Kumar Santhanam * @cdev:pointer to embedded class device 465cd2eebfdSLee Jones * @attr: device attribute (unused) 466966fdcffSAnand Kumar Santhanam * @buf:the buffer returned 467966fdcffSAnand Kumar Santhanam * A sysfs 'read-only' shost attribute. 468966fdcffSAnand Kumar Santhanam */ 469966fdcffSAnand Kumar Santhanam static ssize_t pm8001_ctl_bios_version_show(struct device *cdev, 470966fdcffSAnand Kumar Santhanam struct device_attribute *attr, char *buf) 471966fdcffSAnand Kumar Santhanam { 472966fdcffSAnand Kumar Santhanam struct Scsi_Host *shost = class_to_shost(cdev); 473966fdcffSAnand Kumar Santhanam struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 474966fdcffSAnand Kumar Santhanam struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 475966fdcffSAnand Kumar Santhanam char *str = buf; 476966fdcffSAnand Kumar Santhanam int bios_index; 477966fdcffSAnand Kumar Santhanam DECLARE_COMPLETION_ONSTACK(completion); 478966fdcffSAnand Kumar Santhanam struct pm8001_ioctl_payload payload; 479966fdcffSAnand Kumar Santhanam 480966fdcffSAnand Kumar Santhanam pm8001_ha->nvmd_completion = &completion; 481966fdcffSAnand Kumar Santhanam payload.minor_function = 7; 482966fdcffSAnand Kumar Santhanam payload.offset = 0; 4839b889846SViswas G payload.rd_length = 4096; 484966fdcffSAnand Kumar Santhanam payload.func_specific = kzalloc(4096, GFP_KERNEL); 485b42939aaSSuresh Thiagarajan if (!payload.func_specific) 486b42939aaSSuresh Thiagarajan return -ENOMEM; 4875b4ce882STomas Henzl if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) { 4885b4ce882STomas Henzl kfree(payload.func_specific); 4895b4ce882STomas Henzl return -ENOMEM; 4905b4ce882STomas Henzl } 491966fdcffSAnand Kumar Santhanam wait_for_completion(&completion); 492966fdcffSAnand Kumar Santhanam for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT; 493966fdcffSAnand Kumar Santhanam bios_index++) 494966fdcffSAnand Kumar Santhanam str += sprintf(str, "%c", 4959e032845SSuresh Thiagarajan *(payload.func_specific+bios_index)); 496b42939aaSSuresh Thiagarajan kfree(payload.func_specific); 497966fdcffSAnand Kumar Santhanam return str - buf; 498966fdcffSAnand Kumar Santhanam } 499966fdcffSAnand Kumar Santhanam static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL); 500966fdcffSAnand Kumar Santhanam /** 5012040a857SDeepak Ukey * event_log_size_show - event log size 5022040a857SDeepak Ukey * @cdev: pointer to embedded class device 503e1c3e0f8SLee Jones * @attr: device attribute (unused) 5042040a857SDeepak Ukey * @buf: the buffer returned 5052040a857SDeepak Ukey * 5062040a857SDeepak Ukey * A sysfs read shost attribute. 5072040a857SDeepak Ukey */ 5082040a857SDeepak Ukey static ssize_t event_log_size_show(struct device *cdev, 5092040a857SDeepak Ukey struct device_attribute *attr, char *buf) 5102040a857SDeepak Ukey { 5112040a857SDeepak Ukey struct Scsi_Host *shost = class_to_shost(cdev); 5122040a857SDeepak Ukey struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 5132040a857SDeepak Ukey struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 5142040a857SDeepak Ukey 5152040a857SDeepak Ukey return snprintf(buf, PAGE_SIZE, "%d\n", 5162040a857SDeepak Ukey pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size); 5172040a857SDeepak Ukey } 5182040a857SDeepak Ukey static DEVICE_ATTR_RO(event_log_size); 5192040a857SDeepak Ukey /** 5203978e59bSLee Jones * pm8001_ctl_iop_log_show - IOP event log 521dbf9bfe6Sjack wang * @cdev: pointer to embedded class device 522e1c3e0f8SLee Jones * @attr: device attribute (unused) 523dbf9bfe6Sjack wang * @buf: the buffer returned 524dbf9bfe6Sjack wang * 525dbf9bfe6Sjack wang * A sysfs 'read-only' shost attribute. 526dbf9bfe6Sjack wang */ 527dbf9bfe6Sjack wang static ssize_t pm8001_ctl_iop_log_show(struct device *cdev, 528dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 529dbf9bfe6Sjack wang { 530dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 531dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 532dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 533dbf9bfe6Sjack wang char *str = buf; 5345f0bd875SDeepak Ukey u32 read_size = 5355f0bd875SDeepak Ukey pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024; 5365f0bd875SDeepak Ukey static u32 start, end, count; 5375f0bd875SDeepak Ukey u32 max_read_times = 32; 5385f0bd875SDeepak Ukey u32 max_count = (read_size * 1024) / (max_read_times * 4); 5395f0bd875SDeepak Ukey u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr; 5405f0bd875SDeepak Ukey 5415f0bd875SDeepak Ukey if ((count % max_count) == 0) { 5425f0bd875SDeepak Ukey start = 0; 5435f0bd875SDeepak Ukey end = max_read_times; 5445f0bd875SDeepak Ukey count = 0; 5455f0bd875SDeepak Ukey } else { 5465f0bd875SDeepak Ukey start = end; 5475f0bd875SDeepak Ukey end = end + max_read_times; 548dbf9bfe6Sjack wang } 549dbf9bfe6Sjack wang 5505f0bd875SDeepak Ukey for (; start < end; start++) 5515f0bd875SDeepak Ukey str += sprintf(str, "%08x ", *(temp+start)); 5525f0bd875SDeepak Ukey count++; 553dbf9bfe6Sjack wang return str - buf; 554dbf9bfe6Sjack wang } 555dbf9bfe6Sjack wang static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); 556dbf9bfe6Sjack wang 557d078b511SAnand Kumar Santhanam /** 558d078b511SAnand Kumar Santhanam ** pm8001_ctl_fatal_log_show - fatal error logging 559d078b511SAnand Kumar Santhanam ** @cdev:pointer to embedded class device 560e1c3e0f8SLee Jones ** @attr: device attribute 561d078b511SAnand Kumar Santhanam ** @buf: the buffer returned 562d078b511SAnand Kumar Santhanam ** 563d078b511SAnand Kumar Santhanam ** A sysfs 'read-only' shost attribute. 564d078b511SAnand Kumar Santhanam **/ 565d078b511SAnand Kumar Santhanam 566d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev, 567d078b511SAnand Kumar Santhanam struct device_attribute *attr, char *buf) 568d078b511SAnand Kumar Santhanam { 569cf370066SViswas G ssize_t count; 570d078b511SAnand Kumar Santhanam 571d078b511SAnand Kumar Santhanam count = pm80xx_get_fatal_dump(cdev, attr, buf); 572d078b511SAnand Kumar Santhanam return count; 573d078b511SAnand Kumar Santhanam } 574d078b511SAnand Kumar Santhanam 575d078b511SAnand Kumar Santhanam static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL); 576d078b511SAnand Kumar Santhanam 577dba2cc03SDeepak Ukey /** 578dba2cc03SDeepak Ukey ** non_fatal_log_show - non fatal error logging 579dba2cc03SDeepak Ukey ** @cdev:pointer to embedded class device 580e1c3e0f8SLee Jones ** @attr: device attribute 581dba2cc03SDeepak Ukey ** @buf: the buffer returned 582dba2cc03SDeepak Ukey ** 583dba2cc03SDeepak Ukey ** A sysfs 'read-only' shost attribute. 584dba2cc03SDeepak Ukey **/ 585dba2cc03SDeepak Ukey static ssize_t non_fatal_log_show(struct device *cdev, 586dba2cc03SDeepak Ukey struct device_attribute *attr, char *buf) 587dba2cc03SDeepak Ukey { 588dba2cc03SDeepak Ukey u32 count; 589dba2cc03SDeepak Ukey 590dba2cc03SDeepak Ukey count = pm80xx_get_non_fatal_dump(cdev, attr, buf); 591dba2cc03SDeepak Ukey return count; 592dba2cc03SDeepak Ukey } 593dba2cc03SDeepak Ukey static DEVICE_ATTR_RO(non_fatal_log); 594dba2cc03SDeepak Ukey 595dba2cc03SDeepak Ukey static ssize_t non_fatal_count_show(struct device *cdev, 596dba2cc03SDeepak Ukey struct device_attribute *attr, char *buf) 597dba2cc03SDeepak Ukey { 598dba2cc03SDeepak Ukey struct Scsi_Host *shost = class_to_shost(cdev); 599dba2cc03SDeepak Ukey struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 600dba2cc03SDeepak Ukey struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 601dba2cc03SDeepak Ukey 602dba2cc03SDeepak Ukey return snprintf(buf, PAGE_SIZE, "%08x", 603dba2cc03SDeepak Ukey pm8001_ha->non_fatal_count); 604dba2cc03SDeepak Ukey } 605dba2cc03SDeepak Ukey 606dba2cc03SDeepak Ukey static ssize_t non_fatal_count_store(struct device *cdev, 607dba2cc03SDeepak Ukey struct device_attribute *attr, const char *buf, size_t count) 608dba2cc03SDeepak Ukey { 609dba2cc03SDeepak Ukey struct Scsi_Host *shost = class_to_shost(cdev); 610dba2cc03SDeepak Ukey struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 611dba2cc03SDeepak Ukey struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 612dba2cc03SDeepak Ukey int val = 0; 613dba2cc03SDeepak Ukey 614dba2cc03SDeepak Ukey if (kstrtoint(buf, 16, &val) != 0) 615dba2cc03SDeepak Ukey return -EINVAL; 616dba2cc03SDeepak Ukey 617dba2cc03SDeepak Ukey pm8001_ha->non_fatal_count = val; 618dba2cc03SDeepak Ukey return strlen(buf); 619dba2cc03SDeepak Ukey } 620dba2cc03SDeepak Ukey static DEVICE_ATTR_RW(non_fatal_count); 621d078b511SAnand Kumar Santhanam 622d078b511SAnand Kumar Santhanam /** 623d078b511SAnand Kumar Santhanam ** pm8001_ctl_gsm_log_show - gsm dump collection 624d078b511SAnand Kumar Santhanam ** @cdev:pointer to embedded class device 625cd2eebfdSLee Jones ** @attr: device attribute (unused) 626d078b511SAnand Kumar Santhanam ** @buf: the buffer returned 627d078b511SAnand Kumar Santhanam ** A sysfs 'read-only' shost attribute. 628d078b511SAnand Kumar Santhanam **/ 629d078b511SAnand Kumar Santhanam static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev, 630d078b511SAnand Kumar Santhanam struct device_attribute *attr, char *buf) 631d078b511SAnand Kumar Santhanam { 632cf370066SViswas G ssize_t count; 633d078b511SAnand Kumar Santhanam 634d078b511SAnand Kumar Santhanam count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf); 635d078b511SAnand Kumar Santhanam return count; 636d078b511SAnand Kumar Santhanam } 637d078b511SAnand Kumar Santhanam 638d078b511SAnand Kumar Santhanam static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL); 639d078b511SAnand Kumar Santhanam 640dbf9bfe6Sjack wang #define FLASH_CMD_NONE 0x00 641dbf9bfe6Sjack wang #define FLASH_CMD_UPDATE 0x01 642dbf9bfe6Sjack wang #define FLASH_CMD_SET_NVMD 0x02 643dbf9bfe6Sjack wang 644dbf9bfe6Sjack wang struct flash_command { 645dbf9bfe6Sjack wang u8 command[8]; 646dbf9bfe6Sjack wang int code; 647dbf9bfe6Sjack wang }; 648dbf9bfe6Sjack wang 649fa5ac2beSLuo Jiaxing static const struct flash_command flash_command_table[] = { 650dbf9bfe6Sjack wang {"set_nvmd", FLASH_CMD_SET_NVMD}, 651dbf9bfe6Sjack wang {"update", FLASH_CMD_UPDATE}, 652dbf9bfe6Sjack wang {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ 653dbf9bfe6Sjack wang }; 654dbf9bfe6Sjack wang 655dbf9bfe6Sjack wang struct error_fw { 656dbf9bfe6Sjack wang char *reason; 657dbf9bfe6Sjack wang int err_code; 658dbf9bfe6Sjack wang }; 659dbf9bfe6Sjack wang 660fa5ac2beSLuo Jiaxing static const struct error_fw flash_error_table[] = { 661dbf9bfe6Sjack wang {"Failed to open fw image file", FAIL_OPEN_BIOS_FILE}, 662dbf9bfe6Sjack wang {"image header mismatch", FLASH_UPDATE_HDR_ERR}, 663dbf9bfe6Sjack wang {"image offset mismatch", FLASH_UPDATE_OFFSET_ERR}, 664dbf9bfe6Sjack wang {"image CRC Error", FLASH_UPDATE_CRC_ERR}, 665dbf9bfe6Sjack wang {"image length Error.", FLASH_UPDATE_LENGTH_ERR}, 666dbf9bfe6Sjack wang {"Failed to program flash chip", FLASH_UPDATE_HW_ERR}, 667dbf9bfe6Sjack wang {"Flash chip not supported.", FLASH_UPDATE_DNLD_NOT_SUPPORTED}, 668dbf9bfe6Sjack wang {"Flash update disabled.", FLASH_UPDATE_DISABLED}, 669dbf9bfe6Sjack wang {"Flash in progress", FLASH_IN_PROGRESS}, 670dbf9bfe6Sjack wang {"Image file size Error", FAIL_FILE_SIZE}, 671dbf9bfe6Sjack wang {"Input parameter error", FAIL_PARAMETERS}, 672dbf9bfe6Sjack wang {"Out of memory", FAIL_OUT_MEMORY}, 673dbf9bfe6Sjack wang {"OK", 0} /* Last entry err_code = 0. */ 674dbf9bfe6Sjack wang }; 675dbf9bfe6Sjack wang 676dbf9bfe6Sjack wang static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) 677dbf9bfe6Sjack wang { 678dbf9bfe6Sjack wang struct pm8001_ioctl_payload *payload; 679dbf9bfe6Sjack wang DECLARE_COMPLETION_ONSTACK(completion); 6806f8f31c7STomas Henzl u8 *ioctlbuffer; 6816f8f31c7STomas Henzl u32 ret; 6826f8f31c7STomas Henzl u32 length = 1024 * 5 + sizeof(*payload) - 1; 683dbf9bfe6Sjack wang 6846f8f31c7STomas Henzl if (pm8001_ha->fw_image->size > 4096) { 6856f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_FILE_SIZE; 6866f8f31c7STomas Henzl return -EFAULT; 6876f8f31c7STomas Henzl } 6886f8f31c7STomas Henzl 689dbf9bfe6Sjack wang ioctlbuffer = kzalloc(length, GFP_KERNEL); 6906f8f31c7STomas Henzl if (!ioctlbuffer) { 6916f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_OUT_MEMORY; 692dbf9bfe6Sjack wang return -ENOMEM; 693dbf9bfe6Sjack wang } 694dbf9bfe6Sjack wang payload = (struct pm8001_ioctl_payload *)ioctlbuffer; 6951c75a679SSakthivel K memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data, 696dbf9bfe6Sjack wang pm8001_ha->fw_image->size); 6979b889846SViswas G payload->wr_length = pm8001_ha->fw_image->size; 698dbf9bfe6Sjack wang payload->id = 0; 6991c75a679SSakthivel K payload->minor_function = 0x1; 700dbf9bfe6Sjack wang pm8001_ha->nvmd_completion = &completion; 701dbf9bfe6Sjack wang ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload); 7026f8f31c7STomas Henzl if (ret) { 7036f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_OUT_MEMORY; 7046f8f31c7STomas Henzl goto out; 7056f8f31c7STomas Henzl } 706dbf9bfe6Sjack wang wait_for_completion(&completion); 707dbf9bfe6Sjack wang out: 708dbf9bfe6Sjack wang kfree(ioctlbuffer); 709dbf9bfe6Sjack wang return ret; 710dbf9bfe6Sjack wang } 711dbf9bfe6Sjack wang 712dbf9bfe6Sjack wang static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha) 713dbf9bfe6Sjack wang { 714dbf9bfe6Sjack wang struct pm8001_ioctl_payload *payload; 715dbf9bfe6Sjack wang DECLARE_COMPLETION_ONSTACK(completion); 7166f8f31c7STomas Henzl u8 *ioctlbuffer; 717dbf9bfe6Sjack wang struct fw_control_info *fwControl; 718dbf9bfe6Sjack wang u32 partitionSize, partitionSizeTmp; 7196f8f31c7STomas Henzl u32 loopNumber, loopcount; 720dbf9bfe6Sjack wang struct pm8001_fw_image_header *image_hdr; 7216f8f31c7STomas Henzl u32 sizeRead = 0; 7226f8f31c7STomas Henzl u32 ret = 0; 7236f8f31c7STomas Henzl u32 length = 1024 * 16 + sizeof(*payload) - 1; 724dbf9bfe6Sjack wang 725dbf9bfe6Sjack wang if (pm8001_ha->fw_image->size < 28) { 7266f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_FILE_SIZE; 7276f8f31c7STomas Henzl return -EFAULT; 728dbf9bfe6Sjack wang } 7296f8f31c7STomas Henzl ioctlbuffer = kzalloc(length, GFP_KERNEL); 7306f8f31c7STomas Henzl if (!ioctlbuffer) { 7316f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_OUT_MEMORY; 7326f8f31c7STomas Henzl return -ENOMEM; 7336f8f31c7STomas Henzl } 7346f8f31c7STomas Henzl image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data; 735dbf9bfe6Sjack wang while (sizeRead < pm8001_ha->fw_image->size) { 736dbf9bfe6Sjack wang partitionSizeTmp = 737dbf9bfe6Sjack wang *(u32 *)((u8 *)&image_hdr->image_length + sizeRead); 738dbf9bfe6Sjack wang partitionSize = be32_to_cpu(partitionSizeTmp); 7395bd355eeSTomas Henzl loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN, 7405bd355eeSTomas Henzl IOCTL_BUF_SIZE); 741dbf9bfe6Sjack wang for (loopNumber = 0; loopNumber < loopcount; loopNumber++) { 742dbf9bfe6Sjack wang payload = (struct pm8001_ioctl_payload *)ioctlbuffer; 7439b889846SViswas G payload->wr_length = 1024*16; 744dbf9bfe6Sjack wang payload->id = 0; 745dbf9bfe6Sjack wang fwControl = 7461c75a679SSakthivel K (struct fw_control_info *)&payload->func_specific; 747dbf9bfe6Sjack wang fwControl->len = IOCTL_BUF_SIZE; /* IN */ 748dbf9bfe6Sjack wang fwControl->size = partitionSize + HEADER_LEN;/* IN */ 749dbf9bfe6Sjack wang fwControl->retcode = 0;/* OUT */ 750dbf9bfe6Sjack wang fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */ 751dbf9bfe6Sjack wang 752dbf9bfe6Sjack wang /* for the last chunk of data in case file size is not even with 753dbf9bfe6Sjack wang 4k, load only the rest*/ 754dbf9bfe6Sjack wang if (((loopcount-loopNumber) == 1) && 755dbf9bfe6Sjack wang ((partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE)) { 756dbf9bfe6Sjack wang fwControl->len = 757dbf9bfe6Sjack wang (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE; 758dbf9bfe6Sjack wang memcpy((u8 *)fwControl->buffer, 759dbf9bfe6Sjack wang (u8 *)pm8001_ha->fw_image->data + sizeRead, 760dbf9bfe6Sjack wang (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE); 761dbf9bfe6Sjack wang sizeRead += 762dbf9bfe6Sjack wang (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE; 763dbf9bfe6Sjack wang } else { 764dbf9bfe6Sjack wang memcpy((u8 *)fwControl->buffer, 765dbf9bfe6Sjack wang (u8 *)pm8001_ha->fw_image->data + sizeRead, 766dbf9bfe6Sjack wang IOCTL_BUF_SIZE); 767dbf9bfe6Sjack wang sizeRead += IOCTL_BUF_SIZE; 768dbf9bfe6Sjack wang } 769dbf9bfe6Sjack wang 770dbf9bfe6Sjack wang pm8001_ha->nvmd_completion = &completion; 771dbf9bfe6Sjack wang ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload); 7726f8f31c7STomas Henzl if (ret) { 7736f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_OUT_MEMORY; 7746f8f31c7STomas Henzl goto out; 7756f8f31c7STomas Henzl } 776dbf9bfe6Sjack wang wait_for_completion(&completion); 77731d05e5bSTomas Henzl if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) { 7786f8f31c7STomas Henzl pm8001_ha->fw_status = fwControl->retcode; 7796f8f31c7STomas Henzl ret = -EFAULT; 7806f8f31c7STomas Henzl goto out; 781dbf9bfe6Sjack wang } 782dbf9bfe6Sjack wang } 783dbf9bfe6Sjack wang } 784dbf9bfe6Sjack wang out: 785dbf9bfe6Sjack wang kfree(ioctlbuffer); 786dbf9bfe6Sjack wang return ret; 787dbf9bfe6Sjack wang } 788dbf9bfe6Sjack wang static ssize_t pm8001_store_update_fw(struct device *cdev, 789dbf9bfe6Sjack wang struct device_attribute *attr, 790dbf9bfe6Sjack wang const char *buf, size_t count) 791dbf9bfe6Sjack wang { 792dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 793dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 794dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 795dbf9bfe6Sjack wang char *cmd_ptr, *filename_ptr; 796dbf9bfe6Sjack wang int res, i; 797dbf9bfe6Sjack wang int flash_command = FLASH_CMD_NONE; 7986f8f31c7STomas Henzl int ret; 7996f8f31c7STomas Henzl 800dbf9bfe6Sjack wang if (!capable(CAP_SYS_ADMIN)) 801dbf9bfe6Sjack wang return -EACCES; 802dbf9bfe6Sjack wang 8036f8f31c7STomas Henzl /* this test protects us from running two flash processes at once, 8046f8f31c7STomas Henzl * so we should start with this test */ 8056f8f31c7STomas Henzl if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) 8066f8f31c7STomas Henzl return -EINPROGRESS; 8076f8f31c7STomas Henzl pm8001_ha->fw_status = FLASH_IN_PROGRESS; 808dbf9bfe6Sjack wang 8096396bb22SKees Cook cmd_ptr = kcalloc(count, 2, GFP_KERNEL); 810dbf9bfe6Sjack wang if (!cmd_ptr) { 8116f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_OUT_MEMORY; 8126f8f31c7STomas Henzl return -ENOMEM; 813dbf9bfe6Sjack wang } 814dbf9bfe6Sjack wang 815dbf9bfe6Sjack wang filename_ptr = cmd_ptr + count; 816dbf9bfe6Sjack wang res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); 817dbf9bfe6Sjack wang if (res != 2) { 8186f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_PARAMETERS; 8196f8f31c7STomas Henzl ret = -EINVAL; 8206f8f31c7STomas Henzl goto out; 821dbf9bfe6Sjack wang } 822dbf9bfe6Sjack wang 823dbf9bfe6Sjack wang for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { 824dbf9bfe6Sjack wang if (!memcmp(flash_command_table[i].command, 825dbf9bfe6Sjack wang cmd_ptr, strlen(cmd_ptr))) { 826dbf9bfe6Sjack wang flash_command = flash_command_table[i].code; 827dbf9bfe6Sjack wang break; 828dbf9bfe6Sjack wang } 829dbf9bfe6Sjack wang } 830dbf9bfe6Sjack wang if (flash_command == FLASH_CMD_NONE) { 8316f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_PARAMETERS; 8326f8f31c7STomas Henzl ret = -EINVAL; 8336f8f31c7STomas Henzl goto out; 834dbf9bfe6Sjack wang } 835dbf9bfe6Sjack wang 8366f8f31c7STomas Henzl ret = request_firmware(&pm8001_ha->fw_image, 837dbf9bfe6Sjack wang filename_ptr, 838dbf9bfe6Sjack wang pm8001_ha->dev); 839dbf9bfe6Sjack wang 8406f8f31c7STomas Henzl if (ret) { 8411b5d2793SJoe Perches pm8001_dbg(pm8001_ha, FAIL, 8426f8f31c7STomas Henzl "Failed to load firmware image file %s, error %d\n", 8431b5d2793SJoe Perches filename_ptr, ret); 8446f8f31c7STomas Henzl pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE; 8456f8f31c7STomas Henzl goto out; 846dbf9bfe6Sjack wang } 847dbf9bfe6Sjack wang 8486f8f31c7STomas Henzl if (FLASH_CMD_UPDATE == flash_command) 8496f8f31c7STomas Henzl ret = pm8001_update_flash(pm8001_ha); 850dbf9bfe6Sjack wang else 8516f8f31c7STomas Henzl ret = pm8001_set_nvmd(pm8001_ha); 8526f8f31c7STomas Henzl 8536f8f31c7STomas Henzl release_firmware(pm8001_ha->fw_image); 8546f8f31c7STomas Henzl out: 8556f8f31c7STomas Henzl kfree(cmd_ptr); 8566f8f31c7STomas Henzl 8576f8f31c7STomas Henzl if (ret) 8586f8f31c7STomas Henzl return ret; 8596f8f31c7STomas Henzl 8606f8f31c7STomas Henzl pm8001_ha->fw_status = FLASH_OK; 8616f8f31c7STomas Henzl return count; 862dbf9bfe6Sjack wang } 863dbf9bfe6Sjack wang 864dbf9bfe6Sjack wang static ssize_t pm8001_show_update_fw(struct device *cdev, 865dbf9bfe6Sjack wang struct device_attribute *attr, char *buf) 866dbf9bfe6Sjack wang { 867dbf9bfe6Sjack wang int i; 868dbf9bfe6Sjack wang struct Scsi_Host *shost = class_to_shost(cdev); 869dbf9bfe6Sjack wang struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 870dbf9bfe6Sjack wang struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 871dbf9bfe6Sjack wang 872dbf9bfe6Sjack wang for (i = 0; flash_error_table[i].err_code != 0; i++) { 873dbf9bfe6Sjack wang if (flash_error_table[i].err_code == pm8001_ha->fw_status) 874dbf9bfe6Sjack wang break; 875dbf9bfe6Sjack wang } 876dbf9bfe6Sjack wang if (pm8001_ha->fw_status != FLASH_IN_PROGRESS) 877dbf9bfe6Sjack wang pm8001_ha->fw_status = FLASH_OK; 878dbf9bfe6Sjack wang 879dbf9bfe6Sjack wang return snprintf(buf, PAGE_SIZE, "status=%x %s\n", 880dbf9bfe6Sjack wang flash_error_table[i].err_code, 881dbf9bfe6Sjack wang flash_error_table[i].reason); 882dbf9bfe6Sjack wang } 883332e2b4fSRusty Russell static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP, 884dbf9bfe6Sjack wang pm8001_show_update_fw, pm8001_store_update_fw); 8854ddbea1bSVishakha Channapattan 8864ddbea1bSVishakha Channapattan /** 8874ddbea1bSVishakha Channapattan * ctl_mpi_state_show - controller MPI state check 8884ddbea1bSVishakha Channapattan * @cdev: pointer to embedded class device 8894ddbea1bSVishakha Channapattan * @buf: the buffer returned 8904ddbea1bSVishakha Channapattan * 8914ddbea1bSVishakha Channapattan * A sysfs 'read-only' shost attribute. 8924ddbea1bSVishakha Channapattan */ 8934ddbea1bSVishakha Channapattan 8944ddbea1bSVishakha Channapattan static const char *const mpiStateText[] = { 8954ddbea1bSVishakha Channapattan "MPI is not initialized", 8964ddbea1bSVishakha Channapattan "MPI is successfully initialized", 8974ddbea1bSVishakha Channapattan "MPI termination is in progress", 8984ddbea1bSVishakha Channapattan "MPI initialization failed with error in [31:16]" 8994ddbea1bSVishakha Channapattan }; 9004ddbea1bSVishakha Channapattan 9014ddbea1bSVishakha Channapattan static ssize_t ctl_mpi_state_show(struct device *cdev, 9024ddbea1bSVishakha Channapattan struct device_attribute *attr, char *buf) 9034ddbea1bSVishakha Channapattan { 9044ddbea1bSVishakha Channapattan struct Scsi_Host *shost = class_to_shost(cdev); 9054ddbea1bSVishakha Channapattan struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 9064ddbea1bSVishakha Channapattan struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 9074ddbea1bSVishakha Channapattan unsigned int mpidw0; 9084ddbea1bSVishakha Channapattan 9094ddbea1bSVishakha Channapattan mpidw0 = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 0); 9104ddbea1bSVishakha Channapattan return sysfs_emit(buf, "%s\n", mpiStateText[mpidw0 & 0x0003]); 9114ddbea1bSVishakha Channapattan } 9124ddbea1bSVishakha Channapattan static DEVICE_ATTR_RO(ctl_mpi_state); 9134ddbea1bSVishakha Channapattan 914*a4c55e16SVishakha Channapattan /** 915*a4c55e16SVishakha Channapattan * ctl_hmi_error_show - controller MPI initialization fails 916*a4c55e16SVishakha Channapattan * @cdev: pointer to embedded class device 917*a4c55e16SVishakha Channapattan * @buf: the buffer returned 918*a4c55e16SVishakha Channapattan * 919*a4c55e16SVishakha Channapattan * A sysfs 'read-only' shost attribute. 920*a4c55e16SVishakha Channapattan */ 921*a4c55e16SVishakha Channapattan 922*a4c55e16SVishakha Channapattan static ssize_t ctl_hmi_error_show(struct device *cdev, 923*a4c55e16SVishakha Channapattan struct device_attribute *attr, char *buf) 924*a4c55e16SVishakha Channapattan { 925*a4c55e16SVishakha Channapattan struct Scsi_Host *shost = class_to_shost(cdev); 926*a4c55e16SVishakha Channapattan struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 927*a4c55e16SVishakha Channapattan struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; 928*a4c55e16SVishakha Channapattan unsigned int mpidw0; 929*a4c55e16SVishakha Channapattan 930*a4c55e16SVishakha Channapattan mpidw0 = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 0); 931*a4c55e16SVishakha Channapattan return sysfs_emit(buf, "0x%08x\n", (mpidw0 >> 16)); 932*a4c55e16SVishakha Channapattan } 933*a4c55e16SVishakha Channapattan static DEVICE_ATTR_RO(ctl_hmi_error); 934*a4c55e16SVishakha Channapattan 935dbf9bfe6Sjack wang struct device_attribute *pm8001_host_attrs[] = { 936dbf9bfe6Sjack wang &dev_attr_interface_rev, 937e2773c67SDeepak Ukey &dev_attr_controller_fatal_error, 938dbf9bfe6Sjack wang &dev_attr_fw_version, 939dbf9bfe6Sjack wang &dev_attr_update_fw, 940dbf9bfe6Sjack wang &dev_attr_aap_log, 941dbf9bfe6Sjack wang &dev_attr_iop_log, 942d078b511SAnand Kumar Santhanam &dev_attr_fatal_log, 943dba2cc03SDeepak Ukey &dev_attr_non_fatal_log, 944dba2cc03SDeepak Ukey &dev_attr_non_fatal_count, 945d078b511SAnand Kumar Santhanam &dev_attr_gsm_log, 946dbf9bfe6Sjack wang &dev_attr_max_out_io, 947dbf9bfe6Sjack wang &dev_attr_max_devices, 948dbf9bfe6Sjack wang &dev_attr_max_sg_list, 949dbf9bfe6Sjack wang &dev_attr_sas_spec_support, 950dbf9bfe6Sjack wang &dev_attr_logging_level, 9512040a857SDeepak Ukey &dev_attr_event_log_size, 952dbf9bfe6Sjack wang &dev_attr_host_sas_address, 953966fdcffSAnand Kumar Santhanam &dev_attr_bios_version, 954d078b511SAnand Kumar Santhanam &dev_attr_ib_log, 955d078b511SAnand Kumar Santhanam &dev_attr_ob_log, 95624fff017SViswas G &dev_attr_ila_version, 95724fff017SViswas G &dev_attr_inc_fw_ver, 9584ddbea1bSVishakha Channapattan &dev_attr_ctl_mpi_state, 959*a4c55e16SVishakha Channapattan &dev_attr_ctl_hmi_error, 960dbf9bfe6Sjack wang NULL, 961dbf9bfe6Sjack wang }; 962dbf9bfe6Sjack wang 963