1047 lines · c
1/*2 * PMC-Sierra 8001/8081/8088/8089 SAS/SATA based host adapters driver3 *4 * Copyright (c) 2008-2009 USI Co., Ltd.5 * All rights reserved.6 *7 * Redistribution and use in source and binary forms, with or without8 * modification, are permitted provided that the following conditions9 * are met:10 * 1. Redistributions of source code must retain the above copyright11 * notice, this list of conditions, and the following disclaimer,12 * without modification.13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer14 * substantially similar to the "NO WARRANTY" disclaimer below15 * ("Disclaimer") and any redistribution must be conditioned upon16 * including a substantially similar Disclaimer requirement for further17 * binary redistribution.18 * 3. Neither the names of the above-listed copyright holders nor the names19 * of any contributors may be used to endorse or promote products derived20 * from this software without specific prior written permission.21 *22 * Alternatively, this software may be distributed under the terms of the23 * GNU General Public License ("GPL") version 2 as published by the Free24 * Software Foundation.25 *26 * NO WARRANTY27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT31 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS33 * 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) ARISING36 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE37 * 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 number50 * @cdev: pointer to embedded class device51 * @attr: device attribute (unused)52 * @buf: the buffer returned53 *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 sysfs_emit(buf, "%d\n",65 pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev);66 } else {67 return sysfs_emit(buf, "%d\n",68 pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev);69 }70}71static72DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL);73 74/**75 * controller_fatal_error_show - check controller is under fatal err76 * @cdev: pointer to embedded class device77 * @attr: device attribute (unused)78 * @buf: the buffer returned79 *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 sysfs_emit(buf, "%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 version96 * @cdev: pointer to embedded class device97 * @attr: device attribute (unused)98 * @buf: the buffer returned99 *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 sysfs_emit(buf, "%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 sysfs_emit(buf, "%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 version127 * @cdev: pointer to embedded class device128 * @attr: device attribute (unused)129 * @buf: the buffer returned130 *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 sysfs_emit(buf, "%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 number153 * @cdev: pointer to embedded class device154 * @attr: device attribute (unused)155 * @buf: the buffer returned156 *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 sysfs_emit(buf, "%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}175static176DEVICE_ATTR(inc_fw_ver, 0444, pm8001_ctl_inactive_fw_version_show, NULL);177 178/**179 * pm8001_ctl_max_out_io_show - max outstanding io supported180 * @cdev: pointer to embedded class device181 * @attr: device attribute (unused)182 * @buf: the buffer returned183 *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 sysfs_emit(buf, "%d\n",195 pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io);196 } else {197 return sysfs_emit(buf, "%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 support204 * @cdev: pointer to embedded class device205 * @attr: device attribute (unused)206 * @buf: the buffer returned207 *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 sysfs_emit(buf, "%04d\n",219 (u16)(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16));220 } else {221 return sysfs_emit(buf, "%04d\n",222 (u16)(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16));223 }224}225static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL);226/**227 * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no228 * hardware limitation229 * @cdev: pointer to embedded class device230 * @attr: device attribute (unused)231 * @buf: the buffer returned232 *233 * A sysfs 'read-only' shost attribute.234 */235static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev,236 struct device_attribute *attr, char *buf)237{238 struct Scsi_Host *shost = class_to_shost(cdev);239 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);240 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;241 242 if (pm8001_ha->chip_id == chip_8001) {243 return sysfs_emit(buf, "%04d\n",244 pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl & 0x0000FFFF);245 } else {246 return sysfs_emit(buf, "%04d\n",247 pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl & 0x0000FFFF);248 }249}250static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL);251 252#define SAS_1_0 0x1253#define SAS_1_1 0x2254#define SAS_2_0 0x4255 256static ssize_t257show_sas_spec_support_status(unsigned int mode, char *buf)258{259 ssize_t len = 0;260 261 if (mode & SAS_1_1)262 len = sprintf(buf, "%s", "SAS1.1");263 if (mode & SAS_2_0)264 len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0");265 len += sprintf(buf + len, "\n");266 267 return len;268}269 270/**271 * pm8001_ctl_sas_spec_support_show - sas spec supported272 * @cdev: pointer to embedded class device273 * @attr: device attribute (unused)274 * @buf: the buffer returned275 *276 * A sysfs 'read-only' shost attribute.277 */278static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev,279 struct device_attribute *attr, char *buf)280{281 unsigned int mode;282 struct Scsi_Host *shost = class_to_shost(cdev);283 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);284 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;285 /* fe000000 means supports SAS2.1 */286 if (pm8001_ha->chip_id == chip_8001)287 mode = (pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag &288 0xfe000000)>>25;289 else290 /* fe000000 means supports SAS2.1 */291 mode = (pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag &292 0xfe000000)>>25;293 return show_sas_spec_support_status(mode, buf);294}295static DEVICE_ATTR(sas_spec_support, S_IRUGO,296 pm8001_ctl_sas_spec_support_show, NULL);297 298/**299 * pm8001_ctl_host_sas_address_show - sas address300 * @cdev: pointer to embedded class device301 * @attr: device attribute (unused)302 * @buf: the buffer returned303 *304 * This is the controller sas address305 *306 * A sysfs 'read-only' shost attribute.307 */308static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev,309 struct device_attribute *attr, char *buf)310{311 struct Scsi_Host *shost = class_to_shost(cdev);312 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);313 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;314 return sysfs_emit(buf, "0x%016llx\n",315 be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr));316}317static DEVICE_ATTR(host_sas_address, S_IRUGO,318 pm8001_ctl_host_sas_address_show, NULL);319 320/**321 * pm8001_ctl_logging_level_show - logging level322 * @cdev: pointer to embedded class device323 * @attr: device attribute (unused)324 * @buf: the buffer returned325 *326 * A sysfs 'read/write' shost attribute.327 */328static ssize_t pm8001_ctl_logging_level_show(struct device *cdev,329 struct device_attribute *attr, char *buf)330{331 struct Scsi_Host *shost = class_to_shost(cdev);332 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);333 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;334 335 return sysfs_emit(buf, "%08xh\n", pm8001_ha->logging_level);336}337 338static ssize_t pm8001_ctl_logging_level_store(struct device *cdev,339 struct device_attribute *attr, const char *buf, size_t count)340{341 struct Scsi_Host *shost = class_to_shost(cdev);342 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);343 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;344 int val = 0;345 346 if (sscanf(buf, "%x", &val) != 1)347 return -EINVAL;348 349 pm8001_ha->logging_level = val;350 return strlen(buf);351}352 353static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,354 pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store);355/**356 * pm8001_ctl_aap_log_show - aap1 event log357 * @cdev: pointer to embedded class device358 * @attr: device attribute (unused)359 * @buf: the buffer returned360 *361 * A sysfs 'read-only' shost attribute.362 */363static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,364 struct device_attribute *attr, char *buf)365{366 struct Scsi_Host *shost = class_to_shost(cdev);367 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);368 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;369 u8 *ptr = (u8 *)pm8001_ha->memoryMap.region[AAP1].virt_ptr;370 int i;371 372 char *str = buf;373 int max = 2;374 for (i = 0; i < max; i++) {375 str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x"376 "0x%08x 0x%08x\n",377 pm8001_ctl_aap1_memmap(ptr, i, 0),378 pm8001_ctl_aap1_memmap(ptr, i, 4),379 pm8001_ctl_aap1_memmap(ptr, i, 8),380 pm8001_ctl_aap1_memmap(ptr, i, 12),381 pm8001_ctl_aap1_memmap(ptr, i, 16),382 pm8001_ctl_aap1_memmap(ptr, i, 20),383 pm8001_ctl_aap1_memmap(ptr, i, 24),384 pm8001_ctl_aap1_memmap(ptr, i, 28));385 }386 387 return str - buf;388}389static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);390/**391 * pm8001_ctl_ib_queue_log_show - Out bound Queue log392 * @cdev:pointer to embedded class device393 * @attr: device attribute (unused)394 * @buf: the buffer returned395 *396 * A sysfs 'read-only' shost attribute.397 */398static ssize_t pm8001_ctl_ib_queue_log_show(struct device *cdev,399 struct device_attribute *attr, char *buf)400{401 struct Scsi_Host *shost = class_to_shost(cdev);402 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);403 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;404 int offset;405 char *str = buf;406 int start = 0;407 u32 ib_offset = pm8001_ha->ib_offset;408 u32 queue_size = pm8001_ha->max_q_num * PM8001_MPI_QUEUE * 128;409#define IB_MEMMAP(c) \410 (*(u32 *)((u8 *)pm8001_ha-> \411 memoryMap.region[ib_offset].virt_ptr + \412 pm8001_ha->evtlog_ib_offset + (c)))413 414 for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {415 str += sprintf(str, "0x%08x\n", IB_MEMMAP(start));416 start = start + 4;417 }418 pm8001_ha->evtlog_ib_offset += SYSFS_OFFSET;419 if (((pm8001_ha->evtlog_ib_offset) % queue_size) == 0)420 pm8001_ha->evtlog_ib_offset = 0;421 422 return str - buf;423}424 425static DEVICE_ATTR(ib_log, S_IRUGO, pm8001_ctl_ib_queue_log_show, NULL);426/**427 * pm8001_ctl_ob_queue_log_show - Out bound Queue log428 * @cdev:pointer to embedded class device429 * @attr: device attribute (unused)430 * @buf: the buffer returned431 *432 * A sysfs 'read-only' shost attribute.433 */434 435static ssize_t pm8001_ctl_ob_queue_log_show(struct device *cdev,436 struct device_attribute *attr, char *buf)437{438 struct Scsi_Host *shost = class_to_shost(cdev);439 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);440 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;441 int offset;442 char *str = buf;443 int start = 0;444 u32 ob_offset = pm8001_ha->ob_offset;445 u32 queue_size = pm8001_ha->max_q_num * PM8001_MPI_QUEUE * 128;446#define OB_MEMMAP(c) \447 (*(u32 *)((u8 *)pm8001_ha-> \448 memoryMap.region[ob_offset].virt_ptr + \449 pm8001_ha->evtlog_ob_offset + (c)))450 451 for (offset = 0; offset < IB_OB_READ_TIMES; offset++) {452 str += sprintf(str, "0x%08x\n", OB_MEMMAP(start));453 start = start + 4;454 }455 pm8001_ha->evtlog_ob_offset += SYSFS_OFFSET;456 if (((pm8001_ha->evtlog_ob_offset) % queue_size) == 0)457 pm8001_ha->evtlog_ob_offset = 0;458 459 return str - buf;460}461static DEVICE_ATTR(ob_log, S_IRUGO, pm8001_ctl_ob_queue_log_show, NULL);462/**463 * pm8001_ctl_bios_version_show - Bios version Display464 * @cdev:pointer to embedded class device465 * @attr: device attribute (unused)466 * @buf:the buffer returned467 *468 * A sysfs 'read-only' shost attribute.469 */470static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,471 struct device_attribute *attr, char *buf)472{473 struct Scsi_Host *shost = class_to_shost(cdev);474 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);475 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;476 char *str = buf;477 int bios_index;478 DECLARE_COMPLETION_ONSTACK(completion);479 struct pm8001_ioctl_payload payload;480 481 pm8001_ha->nvmd_completion = &completion;482 payload.minor_function = 7;483 payload.offset = 0;484 payload.rd_length = 4096;485 payload.func_specific = kzalloc(4096, GFP_KERNEL);486 if (!payload.func_specific)487 return -ENOMEM;488 if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) {489 kfree(payload.func_specific);490 return -ENOMEM;491 }492 wait_for_completion(&completion);493 for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT;494 bios_index++)495 str += sprintf(str, "%c",496 *(payload.func_specific+bios_index));497 kfree(payload.func_specific);498 return str - buf;499}500static DEVICE_ATTR(bios_version, S_IRUGO, pm8001_ctl_bios_version_show, NULL);501/**502 * event_log_size_show - event log size503 * @cdev: pointer to embedded class device504 * @attr: device attribute (unused)505 * @buf: the buffer returned506 *507 * A sysfs read shost attribute.508 */509static ssize_t event_log_size_show(struct device *cdev,510 struct device_attribute *attr, char *buf)511{512 struct Scsi_Host *shost = class_to_shost(cdev);513 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);514 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;515 516 return sysfs_emit(buf, "%d\n",517 pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);518}519static DEVICE_ATTR_RO(event_log_size);520/**521 * pm8001_ctl_iop_log_show - IOP event log522 * @cdev: pointer to embedded class device523 * @attr: device attribute (unused)524 * @buf: the buffer returned525 *526 * A sysfs 'read-only' shost attribute.527 */528static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,529 struct device_attribute *attr, char *buf)530{531 struct Scsi_Host *shost = class_to_shost(cdev);532 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);533 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;534 char *str = buf;535 u32 read_size =536 pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size / 1024;537 static u32 start, end, count;538 u32 max_read_times = 32;539 u32 max_count = (read_size * 1024) / (max_read_times * 4);540 u32 *temp = (u32 *)pm8001_ha->memoryMap.region[IOP].virt_ptr;541 542 if ((count % max_count) == 0) {543 start = 0;544 end = max_read_times;545 count = 0;546 } else {547 start = end;548 end = end + max_read_times;549 }550 551 for (; start < end; start++)552 str += sprintf(str, "%08x ", *(temp+start));553 count++;554 return str - buf;555}556static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);557 558/**559 * pm8001_ctl_fatal_log_show - fatal error logging560 * @cdev:pointer to embedded class device561 * @attr: device attribute562 * @buf: the buffer returned563 *564 * A sysfs 'read-only' shost attribute.565 */566 567static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,568 struct device_attribute *attr, char *buf)569{570 ssize_t count;571 572 count = pm80xx_get_fatal_dump(cdev, attr, buf);573 return count;574}575 576static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);577 578/**579 * non_fatal_log_show - non fatal error logging580 * @cdev:pointer to embedded class device581 * @attr: device attribute582 * @buf: the buffer returned583 *584 * A sysfs 'read-only' shost attribute.585 */586static ssize_t non_fatal_log_show(struct device *cdev,587 struct device_attribute *attr, char *buf)588{589 u32 count;590 591 count = pm80xx_get_non_fatal_dump(cdev, attr, buf);592 return count;593}594static DEVICE_ATTR_RO(non_fatal_log);595 596static ssize_t non_fatal_count_show(struct device *cdev,597 struct device_attribute *attr, char *buf)598{599 struct Scsi_Host *shost = class_to_shost(cdev);600 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);601 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;602 603 return sysfs_emit(buf, "%08x\n",604 pm8001_ha->non_fatal_count);605}606 607static ssize_t non_fatal_count_store(struct device *cdev,608 struct device_attribute *attr, const char *buf, size_t count)609{610 struct Scsi_Host *shost = class_to_shost(cdev);611 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);612 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;613 int val = 0;614 615 if (kstrtoint(buf, 16, &val) != 0)616 return -EINVAL;617 618 pm8001_ha->non_fatal_count = val;619 return strlen(buf);620}621static DEVICE_ATTR_RW(non_fatal_count);622 623/**624 * pm8001_ctl_gsm_log_show - gsm dump collection625 * @cdev:pointer to embedded class device626 * @attr: device attribute (unused)627 * @buf: the buffer returned628 *629 * A sysfs 'read-only' shost attribute.630 */631static ssize_t pm8001_ctl_gsm_log_show(struct device *cdev,632 struct device_attribute *attr, char *buf)633{634 ssize_t count;635 636 count = pm8001_get_gsm_dump(cdev, SYSFS_OFFSET, buf);637 return count;638}639 640static DEVICE_ATTR(gsm_log, S_IRUGO, pm8001_ctl_gsm_log_show, NULL);641 642#define FLASH_CMD_NONE 0x00643#define FLASH_CMD_UPDATE 0x01644#define FLASH_CMD_SET_NVMD 0x02645 646struct flash_command {647 u8 command[8];648 int code;649};650 651static const struct flash_command flash_command_table[] = {652 {"set_nvmd", FLASH_CMD_SET_NVMD},653 {"update", FLASH_CMD_UPDATE},654 {"", FLASH_CMD_NONE} /* Last entry should be NULL. */655};656 657struct error_fw {658 char *reason;659 int err_code;660};661 662static const struct error_fw flash_error_table[] = {663 {"Failed to open fw image file", FAIL_OPEN_BIOS_FILE},664 {"image header mismatch", FLASH_UPDATE_HDR_ERR},665 {"image offset mismatch", FLASH_UPDATE_OFFSET_ERR},666 {"image CRC Error", FLASH_UPDATE_CRC_ERR},667 {"image length Error.", FLASH_UPDATE_LENGTH_ERR},668 {"Failed to program flash chip", FLASH_UPDATE_HW_ERR},669 {"Flash chip not supported.", FLASH_UPDATE_DNLD_NOT_SUPPORTED},670 {"Flash update disabled.", FLASH_UPDATE_DISABLED},671 {"Flash in progress", FLASH_IN_PROGRESS},672 {"Image file size Error", FAIL_FILE_SIZE},673 {"Input parameter error", FAIL_PARAMETERS},674 {"Out of memory", FAIL_OUT_MEMORY},675 {"OK", 0} /* Last entry err_code = 0. */676};677 678static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)679{680 struct pm8001_ioctl_payload *payload;681 DECLARE_COMPLETION_ONSTACK(completion);682 u8 *ioctlbuffer;683 u32 ret;684 u32 length = 1024 * 5 + sizeof(*payload) - 1;685 686 if (pm8001_ha->fw_image->size > 4096) {687 pm8001_ha->fw_status = FAIL_FILE_SIZE;688 return -EFAULT;689 }690 691 ioctlbuffer = kzalloc(length, GFP_KERNEL);692 if (!ioctlbuffer) {693 pm8001_ha->fw_status = FAIL_OUT_MEMORY;694 return -ENOMEM;695 }696 payload = (struct pm8001_ioctl_payload *)ioctlbuffer;697 memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,698 pm8001_ha->fw_image->size);699 payload->wr_length = pm8001_ha->fw_image->size;700 payload->id = 0;701 payload->minor_function = 0x1;702 pm8001_ha->nvmd_completion = &completion;703 ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload);704 if (ret) {705 pm8001_ha->fw_status = FAIL_OUT_MEMORY;706 goto out;707 }708 wait_for_completion(&completion);709out:710 kfree(ioctlbuffer);711 return ret;712}713 714static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)715{716 struct pm8001_ioctl_payload *payload;717 DECLARE_COMPLETION_ONSTACK(completion);718 u8 *ioctlbuffer;719 struct fw_control_info *fwControl;720 __be32 partitionSizeTmp;721 u32 partitionSize;722 u32 loopNumber, loopcount;723 struct pm8001_fw_image_header *image_hdr;724 u32 sizeRead = 0;725 u32 ret = 0;726 u32 length = 1024 * 16 + sizeof(*payload) - 1;727 u32 fc_len;728 u8 *read_buf;729 730 if (pm8001_ha->fw_image->size < 28) {731 pm8001_ha->fw_status = FAIL_FILE_SIZE;732 return -EFAULT;733 }734 ioctlbuffer = kzalloc(length, GFP_KERNEL);735 if (!ioctlbuffer) {736 pm8001_ha->fw_status = FAIL_OUT_MEMORY;737 return -ENOMEM;738 }739 image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;740 while (sizeRead < pm8001_ha->fw_image->size) {741 partitionSizeTmp =742 *(__be32 *)((u8 *)&image_hdr->image_length + sizeRead);743 partitionSize = be32_to_cpu(partitionSizeTmp);744 loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN,745 IOCTL_BUF_SIZE);746 for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {747 payload = (struct pm8001_ioctl_payload *)ioctlbuffer;748 payload->wr_length = 1024*16;749 payload->id = 0;750 fwControl =751 (struct fw_control_info *)&payload->func_specific;752 fwControl->len = IOCTL_BUF_SIZE; /* IN */753 fwControl->size = partitionSize + HEADER_LEN;/* IN */754 fwControl->retcode = 0;/* OUT */755 fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */756 757 /*758 * for the last chunk of data in case file size is759 * not even with 4k, load only the rest760 */761 762 read_buf = (u8 *)pm8001_ha->fw_image->data + sizeRead;763 fc_len = (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE;764 765 if (loopcount - loopNumber == 1 && fc_len) {766 fwControl->len = fc_len;767 memcpy((u8 *)fwControl->buffer, read_buf, fc_len);768 sizeRead += fc_len;769 } else {770 memcpy((u8 *)fwControl->buffer, read_buf, IOCTL_BUF_SIZE);771 sizeRead += IOCTL_BUF_SIZE;772 }773 774 pm8001_ha->nvmd_completion = &completion;775 ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload);776 if (ret) {777 pm8001_ha->fw_status = FAIL_OUT_MEMORY;778 goto out;779 }780 wait_for_completion(&completion);781 if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) {782 pm8001_ha->fw_status = fwControl->retcode;783 ret = -EFAULT;784 goto out;785 }786 }787 }788out:789 kfree(ioctlbuffer);790 return ret;791}792static ssize_t pm8001_store_update_fw(struct device *cdev,793 struct device_attribute *attr,794 const char *buf, size_t count)795{796 struct Scsi_Host *shost = class_to_shost(cdev);797 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);798 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;799 char *cmd_ptr, *filename_ptr;800 int res, i;801 int flash_command = FLASH_CMD_NONE;802 int ret;803 804 if (!capable(CAP_SYS_ADMIN))805 return -EACCES;806 807 /* this test protects us from running two flash processes at once,808 * so we should start with this test */809 if (pm8001_ha->fw_status == FLASH_IN_PROGRESS)810 return -EINPROGRESS;811 pm8001_ha->fw_status = FLASH_IN_PROGRESS;812 813 cmd_ptr = kcalloc(count, 2, GFP_KERNEL);814 if (!cmd_ptr) {815 pm8001_ha->fw_status = FAIL_OUT_MEMORY;816 return -ENOMEM;817 }818 819 filename_ptr = cmd_ptr + count;820 res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);821 if (res != 2) {822 pm8001_ha->fw_status = FAIL_PARAMETERS;823 ret = -EINVAL;824 goto out;825 }826 827 for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) {828 if (!memcmp(flash_command_table[i].command,829 cmd_ptr, strlen(cmd_ptr))) {830 flash_command = flash_command_table[i].code;831 break;832 }833 }834 if (flash_command == FLASH_CMD_NONE) {835 pm8001_ha->fw_status = FAIL_PARAMETERS;836 ret = -EINVAL;837 goto out;838 }839 840 ret = request_firmware(&pm8001_ha->fw_image,841 filename_ptr,842 pm8001_ha->dev);843 844 if (ret) {845 pm8001_dbg(pm8001_ha, FAIL,846 "Failed to load firmware image file %s, error %d\n",847 filename_ptr, ret);848 pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE;849 goto out;850 }851 852 if (FLASH_CMD_UPDATE == flash_command)853 ret = pm8001_update_flash(pm8001_ha);854 else855 ret = pm8001_set_nvmd(pm8001_ha);856 857 release_firmware(pm8001_ha->fw_image);858out:859 kfree(cmd_ptr);860 861 if (ret)862 return ret;863 864 pm8001_ha->fw_status = FLASH_OK;865 return count;866}867 868static ssize_t pm8001_show_update_fw(struct device *cdev,869 struct device_attribute *attr, char *buf)870{871 int i;872 struct Scsi_Host *shost = class_to_shost(cdev);873 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);874 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;875 876 for (i = 0; flash_error_table[i].err_code != 0; i++) {877 if (flash_error_table[i].err_code == pm8001_ha->fw_status)878 break;879 }880 if (pm8001_ha->fw_status != FLASH_IN_PROGRESS)881 pm8001_ha->fw_status = FLASH_OK;882 883 return sysfs_emit(buf, "status=%x %s\n",884 flash_error_table[i].err_code,885 flash_error_table[i].reason);886}887static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP,888 pm8001_show_update_fw, pm8001_store_update_fw);889 890static const char *const mpiStateText[] = {891 "MPI is not initialized",892 "MPI is successfully initialized",893 "MPI termination is in progress",894 "MPI initialization failed with error in [31:16]"895};896 897/**898 * ctl_mpi_state_show - controller MPI state check899 * @cdev: pointer to embedded class device900 * @attr: device attribute (unused)901 * @buf: the buffer returned902 *903 * A sysfs 'read-only' shost attribute.904 */905static ssize_t ctl_mpi_state_show(struct device *cdev,906 struct device_attribute *attr, char *buf)907{908 struct Scsi_Host *shost = class_to_shost(cdev);909 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);910 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;911 unsigned int mpidw0;912 913 mpidw0 = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 0);914 return sysfs_emit(buf, "%s\n", mpiStateText[mpidw0 & 0x0003]);915}916static DEVICE_ATTR_RO(ctl_mpi_state);917 918/**919 * ctl_hmi_error_show - controller MPI initialization fails920 * @cdev: pointer to embedded class device921 * @attr: device attribute (unused)922 * @buf: the buffer returned923 *924 * A sysfs 'read-only' shost attribute.925 */926static ssize_t ctl_hmi_error_show(struct device *cdev,927 struct device_attribute *attr, char *buf)928{929 struct Scsi_Host *shost = class_to_shost(cdev);930 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);931 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;932 unsigned int mpidw0;933 934 mpidw0 = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 0);935 return sysfs_emit(buf, "0x%08x\n", (mpidw0 >> 16));936}937static DEVICE_ATTR_RO(ctl_hmi_error);938 939/**940 * ctl_raae_count_show - controller raae count check941 * @cdev: pointer to embedded class device942 * @attr: device attribute (unused)943 * @buf: the buffer returned944 *945 * A sysfs 'read-only' shost attribute.946 */947static ssize_t ctl_raae_count_show(struct device *cdev,948 struct device_attribute *attr, char *buf)949{950 struct Scsi_Host *shost = class_to_shost(cdev);951 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);952 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;953 unsigned int raaecnt;954 955 raaecnt = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 12);956 return sysfs_emit(buf, "0x%08x\n", raaecnt);957}958static DEVICE_ATTR_RO(ctl_raae_count);959 960/**961 * ctl_iop0_count_show - controller iop0 count check962 * @cdev: pointer to embedded class device963 * @attr: device attribute (unused)964 * @buf: the buffer returned965 *966 * A sysfs 'read-only' shost attribute.967 */968static ssize_t ctl_iop0_count_show(struct device *cdev,969 struct device_attribute *attr, char *buf)970{971 struct Scsi_Host *shost = class_to_shost(cdev);972 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);973 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;974 unsigned int iop0cnt;975 976 iop0cnt = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 16);977 return sysfs_emit(buf, "0x%08x\n", iop0cnt);978}979static DEVICE_ATTR_RO(ctl_iop0_count);980 981/**982 * ctl_iop1_count_show - controller iop1 count check983 * @cdev: pointer to embedded class device984 * @attr: device attribute (unused)985 * @buf: the buffer returned986 *987 * A sysfs 'read-only' shost attribute.988 */989static ssize_t ctl_iop1_count_show(struct device *cdev,990 struct device_attribute *attr, char *buf)991{992 struct Scsi_Host *shost = class_to_shost(cdev);993 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);994 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;995 unsigned int iop1cnt;996 997 iop1cnt = pm8001_mr32(pm8001_ha->general_stat_tbl_addr, 20);998 return sysfs_emit(buf, "0x%08x\n", iop1cnt);999 1000}1001static DEVICE_ATTR_RO(ctl_iop1_count);1002 1003static struct attribute *pm8001_host_attrs[] = {1004 &dev_attr_interface_rev.attr,1005 &dev_attr_controller_fatal_error.attr,1006 &dev_attr_fw_version.attr,1007 &dev_attr_update_fw.attr,1008 &dev_attr_aap_log.attr,1009 &dev_attr_iop_log.attr,1010 &dev_attr_fatal_log.attr,1011 &dev_attr_non_fatal_log.attr,1012 &dev_attr_non_fatal_count.attr,1013 &dev_attr_gsm_log.attr,1014 &dev_attr_max_out_io.attr,1015 &dev_attr_max_devices.attr,1016 &dev_attr_max_sg_list.attr,1017 &dev_attr_sas_spec_support.attr,1018 &dev_attr_logging_level.attr,1019 &dev_attr_event_log_size.attr,1020 &dev_attr_host_sas_address.attr,1021 &dev_attr_bios_version.attr,1022 &dev_attr_ib_log.attr,1023 &dev_attr_ob_log.attr,1024 &dev_attr_ila_version.attr,1025 &dev_attr_inc_fw_ver.attr,1026 &dev_attr_ctl_mpi_state.attr,1027 &dev_attr_ctl_hmi_error.attr,1028 &dev_attr_ctl_raae_count.attr,1029 &dev_attr_ctl_iop0_count.attr,1030 &dev_attr_ctl_iop1_count.attr,1031 NULL,1032};1033 1034static const struct attribute_group pm8001_host_attr_group = {1035 .attrs = pm8001_host_attrs1036};1037 1038const struct attribute_group *pm8001_host_groups[] = {1039 &pm8001_host_attr_group,1040 NULL1041};1042 1043const struct attribute_group *pm8001_sdev_groups[] = {1044 &sas_ata_sdev_attr_group,1045 NULL1046};1047