123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Samsung Specific feature : sysfs-nodes
- *
- * Copyright (C) 2023 Samsung Electronics Co., Ltd.
- *
- * Authors:
- * Storage Driver <[email protected]>
- */
- #include "ufs-sec-sysfs.h"
- #include <linux/sysfs.h>
- #include <linux/blk-pm.h>
- #include <linux/blkdev.h>
- #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_dbg.h>
- #include <scsi/scsi_device.h>
- #include <linux/bitfield.h>
- #include "ufs-qcom.h"
- /* sec specific vendor sysfs nodes */
- struct device *sec_ufs_node_dev;
- /* SEC next WB : begin */
- static void ufs_sec_wb_info_backup(struct ufs_sec_wb_info *backup)
- {
- SEC_UFS_WB_INFO_BACKUP(enable_cnt);
- SEC_UFS_WB_INFO_BACKUP(disable_cnt);
- SEC_UFS_WB_INFO_BACKUP(amount_kb);
- SEC_UFS_WB_INFO_BACKUP(err_cnt);
- backup->state_ts = jiffies;
- }
- static ssize_t ufs_sec_wb_info_show(struct device *dev, struct device_attribute *attr, char *buf)
- {
- struct ufs_sec_wb_info *wb_info_backup = ufs_sec_features.ufs_wb_backup;
- struct ufs_sec_wb_info *wb_info = ufs_sec_features.ufs_wb;
- long hours = 0;
- int len = 0;
- wb_info->state_ts = jiffies;
- hours = jiffies_to_msecs(wb_info->state_ts - wb_info_backup->state_ts) / 1000; /* sec */
- hours = (hours + 60) / (60 * 60); /* round up to hours */
- len = sprintf(buf, "\"TWCTRLCNT\":\"%llu\","
- "\"TWCTRLERRCNT\":\"%llu\","
- "\"TWDAILYMB\":\"%llu\","
- "\"TWTOTALMB\":\"%llu\","
- "\"TWhours\":\"%ld\"\n",
- (wb_info->enable_cnt + wb_info->disable_cnt),
- wb_info->err_cnt, /* total error count */
- (wb_info->amount_kb >> 10), /* WB write daily : MB */
- (wb_info_backup->amount_kb >> 10), /* WB write total : MB */
- hours);
-
- ufs_sec_wb_info_backup(wb_info_backup);
- return len;
- }
- static DEVICE_ATTR(SEC_UFS_TW_info, 0444, ufs_sec_wb_info_show, NULL);
- /* SEC next WB : end */
- /* UFS info nodes : begin */
- static ssize_t ufs_sec_unique_number_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return snprintf(buf, PAGE_SIZE, "%s\n", get_vdi_member(unique_number));
- }
- static DEVICE_ATTR(un, 0440, ufs_sec_unique_number_show, NULL);
- static ssize_t ufs_sec_lt_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ufs_hba *hba = get_vdi_member(hba);
- if (!hba) {
- dev_err(dev, "skipping ufs lt read\n");
- get_vdi_member(lt) = 0;
- } else if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
- ufshcd_rpm_get_sync(hba);
- ufs_sec_get_health_desc(hba);
- ufshcd_rpm_put(hba);
- } else {
- /* return previous LT value if not operational */
- dev_info(hba->dev, "ufshcd_state: %d, old LT: %01x\n",
- hba->ufshcd_state, get_vdi_member(lt));
- }
- return snprintf(buf, PAGE_SIZE, "%01x\n", get_vdi_member(lt));
- }
- static DEVICE_ATTR(lt, 0444, ufs_sec_lt_show, NULL);
- static ssize_t ufs_sec_flt_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ufs_hba *hba = get_vdi_member(hba);
- if (!hba) {
- dev_err(dev, "skipping ufs flt read\n");
- get_vdi_member(flt) = 0;
- } else if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
- ufshcd_rpm_get_sync(hba);
- ufs_sec_get_health_desc(hba);
- ufshcd_rpm_put(hba);
- } else {
- /* return previous FLT value if not operational */
- dev_info(hba->dev, "ufshcd_state : %d, old FLT: %u\n",
- hba->ufshcd_state, get_vdi_member(flt));
- }
- return snprintf(buf, PAGE_SIZE, "%u\n", get_vdi_member(flt));
- }
- static DEVICE_ATTR(flt, 0444, ufs_sec_flt_show, NULL);
- static ssize_t ufs_sec_eli_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ufs_hba *hba = get_vdi_member(hba);
- if (!hba) {
- dev_err(dev, "skipping ufs eli read\n");
- get_vdi_member(eli) = 0;
- } else if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
- ufshcd_rpm_get_sync(hba);
- ufs_sec_get_health_desc(hba);
- ufshcd_rpm_put(hba);
- } else {
- /* return previous ELI value if not operational */
- dev_info(hba->dev, "ufshcd_state: %d, old eli: %01x\n",
- hba->ufshcd_state, get_vdi_member(eli));
- }
- return sprintf(buf, "%u\n", get_vdi_member(eli));
- }
- static DEVICE_ATTR(eli, 0444, ufs_sec_eli_show, NULL);
- static ssize_t ufs_sec_ic_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%u\n", get_vdi_member(ic));
- }
- static ssize_t ufs_sec_ic_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- unsigned int value;
- if (kstrtou32(buf, 0, &value))
- return -EINVAL;
- get_vdi_member(ic) = value;
- return count;
- }
- static DEVICE_ATTR(ic, 0664, ufs_sec_ic_show, ufs_sec_ic_store);
- static ssize_t ufs_sec_shi_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return sprintf(buf, "%s\n", get_vdi_member(shi));
- }
- static ssize_t ufs_sec_shi_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int ret;
- char shi_buf[256] = {0, };
- ret = sscanf(buf, "%255[^\n]%*c", shi_buf);
- if (ret != 1)
- return -EINVAL;
- snprintf(get_vdi_member(shi), 256, "%s", shi_buf);
- return count;
- }
- static DEVICE_ATTR(shi, 0664, ufs_sec_shi_show, ufs_sec_shi_store);
- static ssize_t ufs_sec_hist_info_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- return SEC_UFS_ERR_HIST_SUM(buf);
- }
- static bool is_valid_hist_info(const char *buf, size_t count)
- {
- int i;
- if (count != ERR_SUM_SIZE)
- return false;
- if (buf[0] != 'U' || buf[2] != 'I' || buf[4] != 'H' ||
- buf[6] != 'L' || buf[8] != 'X' || buf[10] != 'Q' ||
- buf[12] != 'R' || buf[14] != 'W' || buf[16] != 'F' ||
- buf[18] != 'S' || buf[19] != 'M' || buf[21] != 'S' ||
- buf[22] != 'H')
- return false;
- for (i = 1; i < ERR_SUM_SIZE; i += 2) {
- if (buf[i] - '0' < 0 || buf[i] - '0' >= 10)
- return false;
- /* increase index for "SM", "SH" */
- if (i == 17 || i == 20)
- i++;
- }
- return true;
- }
- static ssize_t ufs_sec_hist_info_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if (!is_valid_hist_info(buf, count)) {
- pr_err("%s: %s, len(%lu)\n", __func__, buf, count);
- return -EINVAL;
- }
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(UTP_cnt, UTP_err, buf[1]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(UIC_err_cnt, UIC_err, buf[3]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(op_cnt, HW_RESET_cnt, buf[5]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(op_cnt, link_startup_cnt, buf[7]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(Fatal_err_cnt, LLE, buf[9]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(UTP_cnt, UTMR_query_task_cnt, buf[11]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(UTP_cnt, UTR_read_err, buf[13]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(UTP_cnt, UTR_write_err, buf[15]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(Fatal_err_cnt, DFE, buf[17]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(sense_cnt, scsi_medium_err, buf[20]);
- SEC_UFS_ERR_INFO_HIST_SET_VALUE(sense_cnt, scsi_hw_err, buf[23]);
- return count;
- }
- static DEVICE_ATTR(hist, 0664, ufs_sec_hist_info_show, ufs_sec_hist_info_store);
- static ssize_t ufs_sec_man_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ufs_hba *hba = get_vdi_member(hba);
- if (!hba) {
- dev_err(dev, "skipping ufs manid read\n");
- return -EINVAL;
- }
- return snprintf(buf, PAGE_SIZE, "%04x\n", hba->dev_info.wmanufacturerid);
- }
- static DEVICE_ATTR(man_id, 0444, ufs_sec_man_id_show, NULL);
- static bool ufs_sec_wait_for_clear_pending(struct ufs_hba *hba, u64 timeout_us)
- {
- struct scsi_device *sdp;
- unsigned long flags;
- unsigned int tm_pending = 0;
- unsigned int tr_pending = 0;
- bool timeout = true;
- ktime_t start;
- ufshcd_hold(hba, false);
- start = ktime_get();
- do {
- spin_lock_irqsave(hba->host->host_lock, flags);
- tr_pending = 0;
- tm_pending = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
- __shost_for_each_device(sdp, hba->host)
- tr_pending += sbitmap_weight(&sdp->budget_map);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- if (!tm_pending && !tr_pending) {
- dev_info(hba->dev, "doorbell clr complete.\n");
- timeout = false;
- break;
- }
- usleep_range(5000, 5100);
- } while (ktime_to_us(ktime_sub(ktime_get(), start)) < timeout_us);
- ufshcd_release(hba);
- return timeout;
- }
- static int ufs_sec_send_pon(struct ufs_hba *hba)
- {
- struct scsi_device *sdp = hba->ufs_device_wlun;
- const unsigned char cdb[6] = { START_STOP, 0, 0, 0, UFS_POWERDOWN_PWR_MODE << 4, 0 };
- struct scsi_sense_hdr sshdr;
- const struct scsi_exec_args args = {
- .sshdr = &sshdr,
- .req_flags = BLK_MQ_REQ_PM,
- .scmd_flags = SCMD_FAIL_IF_RECOVERING,
- };
- int retries;
- int ret;
- for (retries = 3; retries > 0; --retries) {
- ret = scsi_execute_cmd(sdp, cdb, REQ_OP_DRV_IN, NULL,
- 0, 10 * HZ, 0, &args);
- if (ret <= 0)
- break;
- }
- if (ret) {
- if (ret > 0) {
- if (scsi_sense_valid(&sshdr))
- scsi_print_sense_hdr(sdp, NULL, &sshdr);
- }
- } else {
- dev_info(hba->dev, "pon done.\n");
- hba->curr_dev_pwr_mode = UFS_POWERDOWN_PWR_MODE;
- }
- return ret;
- }
- static void ufs_sec_reset_device(struct ufs_hba *hba)
- {
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- unsigned long flags;
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->force_reset = true;
- host->skip_flush = true;
- hba->ufshcd_state = UFSHCD_STATE_EH_SCHEDULED_FATAL;
- queue_work(hba->eh_wq, &hba->eh_work);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- flush_work(&hba->eh_work);
- dev_info(hba->dev, "reset done.\n");
- if (host->skip_flush)
- host->skip_flush = false;
- }
- static ssize_t ufs_sec_post_ffu_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- struct ufs_hba *hba = get_vdi_member(hba);
- struct scsi_device *sdp_wlu = hba->ufs_device_wlun;
- struct scsi_device *sdp;
- u32 ahit_backup = hba->ahit;
- unsigned long flags;
- int ret;
- /* check product name string */
- if (strncmp(buf, (char *)hba->dev_info.model, strlen(hba->dev_info.model)))
- return -EINVAL;
- dev_info(hba->dev, "post_ffu start\n");
- ufshcd_rpm_get_sync(hba);
- spin_lock_irqsave(hba->host->host_lock, flags);
- if (sdp_wlu && scsi_device_online(sdp_wlu))
- ret = scsi_device_get(sdp_wlu);
- else
- ret = -ENODEV;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
- if (ret) {
- ufshcd_rpm_put(hba);
- return ret;
- }
- /* set SDEV_QUIESCE */
- shost_for_each_device(sdp, hba->host)
- scsi_device_quiesce(sdp);
- /* wait for clear outstanding requests after queue quiesce */
- if (ufs_sec_wait_for_clear_pending(hba, USEC_PER_SEC))
- dev_err(dev, "post_ffu: doorbell clr timedout 1s.\n");
- /* disable AH8 */
- ufshcd_auto_hibern8_update(hba, 0);
- /* reset and recovery UFS, even if the PON fails */
- if (ufs_sec_send_pon(hba))
- dev_err(dev, "post_ffu: pon failed.\n");
- /* reset UFS by eh_work */
- ufs_sec_reset_device(hba);
- /* enable AH8 after UFS reset */
- ufshcd_auto_hibern8_update(hba, ahit_backup);
- /* set SDEV_RUNNING */
- shost_for_each_device(sdp, hba->host)
- scsi_device_resume(sdp);
- scsi_device_put(sdp_wlu);
- ufshcd_rpm_put(hba);
- dev_info(hba->dev, "post_ffu finish\n");
- return count;
- }
- static DEVICE_ATTR(post_ffu, 0220, NULL, ufs_sec_post_ffu_store);
- static struct attribute *sec_ufs_info_attributes[] = {
- &dev_attr_un.attr,
- &dev_attr_lt.attr,
- &dev_attr_flt.attr,
- &dev_attr_eli.attr,
- &dev_attr_ic.attr,
- &dev_attr_shi.attr,
- &dev_attr_hist.attr,
- &dev_attr_man_id.attr,
- &dev_attr_post_ffu.attr,
- NULL
- };
- static struct attribute_group sec_ufs_info_attribute_group = {
- .attrs = sec_ufs_info_attributes,
- };
- /* UFS info nodes : end */
- /* SEC s_info : begin */
- static ssize_t SEC_UFS_s_info_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int ret;
- char s_buf[512] = {0, };
- ret = sscanf(buf, "%511s", s_buf);
- if (ret != 1)
- return -EINVAL;
- snprintf(get_vdi_member(s_info), 512, "%s", s_buf);
- return count;
- }
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_s_info, "%s\n", get_vdi_member(s_info));
- /* SEC s_info : end */
- /* SEC error info : begin */
- static ssize_t SEC_UFS_op_cnt_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(op_cnt, HW_RESET_cnt);
- SEC_UFS_ERR_INFO_BACKUP(op_cnt, link_startup_cnt);
- SEC_UFS_ERR_INFO_BACKUP(op_cnt, Hibern8_enter_cnt);
- SEC_UFS_ERR_INFO_BACKUP(op_cnt, Hibern8_exit_cnt);
- SEC_UFS_ERR_INFO_BACKUP(op_cnt, AH8_err_cnt);
- return count;
- }
- static ssize_t SEC_UFS_uic_cmd_cnt_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_TEST_MODE_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_GET_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_SET_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_PEER_GET_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_PEER_SET_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_POWERON_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_POWEROFF_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_ENABLE_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_RESET_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_END_PT_RST_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_LINK_STARTUP_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_HIBER_ENTER_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, DME_HIBER_EXIT_err);
- return count;
- }
- static ssize_t SEC_UFS_uic_err_cnt_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, PAERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, DLERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, DL_PA_INIT_ERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, DL_NAC_RCVD_ERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, DL_TC_REPLAY_ERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, DL_FC_PROTECT_ERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, NLERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, TLERR_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, DMEERR_cnt);
- return count;
- }
- static ssize_t SEC_UFS_fatal_cnt_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(Fatal_err_cnt, DFE);
- SEC_UFS_ERR_INFO_BACKUP(Fatal_err_cnt, CFE);
- SEC_UFS_ERR_INFO_BACKUP(Fatal_err_cnt, SBFE);
- SEC_UFS_ERR_INFO_BACKUP(Fatal_err_cnt, CEFE);
- SEC_UFS_ERR_INFO_BACKUP(Fatal_err_cnt, LLE);
- return count;
- }
- static ssize_t SEC_UFS_utp_cnt_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTMR_query_task_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTMR_abort_task_cnt);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTR_read_err);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTR_write_err);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTR_sync_cache_err);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTR_unmap_err);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTR_etc_err);
- return count;
- }
- static ssize_t SEC_UFS_query_cnt_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, NOP_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, R_Desc_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, W_Desc_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, R_Attr_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, W_Attr_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, R_Flag_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, Set_Flag_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, Clear_Flag_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, Toggle_Flag_err);
- return count;
- }
- static ssize_t SEC_UFS_err_sum_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(op_cnt, op_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_cmd_cnt, UIC_cmd_err);
- SEC_UFS_ERR_INFO_BACKUP(UIC_err_cnt, UIC_err);
- SEC_UFS_ERR_INFO_BACKUP(Fatal_err_cnt, Fatal_err);
- SEC_UFS_ERR_INFO_BACKUP(UTP_cnt, UTP_err);
- SEC_UFS_ERR_INFO_BACKUP(Query_cnt, Query_err);
- return count;
- }
- static ssize_t sense_err_count_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
- return -EINVAL;
- SEC_UFS_ERR_INFO_BACKUP(sense_cnt, scsi_medium_err);
- SEC_UFS_ERR_INFO_BACKUP(sense_cnt, scsi_hw_err);
- return count;
- }
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_op_cnt, "\"HWRESET\":\"%u\",\"LINKFAIL\":\"%u\""
- ",\"H8ENTERFAIL\":\"%u\",\"H8EXITFAIL\":\"%u\""
- ",\"AH8ERR\":\"%u\"\n",
- get_err_member(op_cnt).HW_RESET_cnt,
- get_err_member(op_cnt).link_startup_cnt,
- get_err_member(op_cnt).Hibern8_enter_cnt,
- get_err_member(op_cnt).Hibern8_exit_cnt,
- get_err_member(op_cnt).AH8_err_cnt);
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_uic_cmd_cnt, "\"TESTMODE\":\"%u\""
- ",\"DME_GET\":\"%u\",\"DME_SET\":\"%u\",\"DME_PGET\":\"%u\""
- ",\"DME_PSET\":\"%u\",\"PWRON\":\"%u\",\"PWROFF\":\"%u\""
- ",\"DME_EN\":\"%u\",\"DME_RST\":\"%u\",\"EPRST\":\"%u\""
- ",\"LINKSTARTUP\":\"%u\",\"H8ENTER\":\"%u\""
- ",\"H8EXIT\":\"%u\"\n",
- get_err_member(UIC_cmd_cnt).DME_TEST_MODE_err,
- get_err_member(UIC_cmd_cnt).DME_GET_err,
- get_err_member(UIC_cmd_cnt).DME_SET_err,
- get_err_member(UIC_cmd_cnt).DME_PEER_GET_err,
- get_err_member(UIC_cmd_cnt).DME_PEER_SET_err,
- get_err_member(UIC_cmd_cnt).DME_POWERON_err,
- get_err_member(UIC_cmd_cnt).DME_POWEROFF_err,
- get_err_member(UIC_cmd_cnt).DME_ENABLE_err,
- get_err_member(UIC_cmd_cnt).DME_RESET_err,
- get_err_member(UIC_cmd_cnt).DME_END_PT_RST_err,
- get_err_member(UIC_cmd_cnt).DME_LINK_STARTUP_err,
- get_err_member(UIC_cmd_cnt).DME_HIBER_ENTER_err,
- get_err_member(UIC_cmd_cnt).DME_HIBER_EXIT_err);
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_uic_err_cnt, "\"PAERR\":\"%u\""
- ",\"DLERR\":\"%u\""
- ",\"DLPAINITERROR\":\"%u\",\"DLNAC\":\"%u\""
- ",\"DLTCREPLAY\":\"%u\",\"DLFCX\":\"%u\""
- ",\"NLERR\":\"%u\",\"TLERR\":\"%u\""
- ",\"DMEERR\":\"%u\"\n",
- get_err_member(UIC_err_cnt).PAERR_cnt,
- get_err_member(UIC_err_cnt).DLERR_cnt,
- get_err_member(UIC_err_cnt).DL_PA_INIT_ERR_cnt,
- get_err_member(UIC_err_cnt).DL_NAC_RCVD_ERR_cnt,
- get_err_member(UIC_err_cnt).DL_TC_REPLAY_ERR_cnt,
- get_err_member(UIC_err_cnt).DL_FC_PROTECT_ERR_cnt,
- get_err_member(UIC_err_cnt).NLERR_cnt,
- get_err_member(UIC_err_cnt).TLERR_cnt,
- get_err_member(UIC_err_cnt).DMEERR_cnt);
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_fatal_cnt, "\"DFE\":\"%u\",\"CFE\":\"%u\""
- ",\"SBFE\":\"%u\",\"CEFE\":\"%u\",\"LLE\":\"%u\"\n",
- get_err_member(Fatal_err_cnt).DFE,
- get_err_member(Fatal_err_cnt).CFE,
- get_err_member(Fatal_err_cnt).SBFE,
- get_err_member(Fatal_err_cnt).CEFE,
- get_err_member(Fatal_err_cnt).LLE);
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_utp_cnt, "\"UTMRQTASK\":\"%u\""
- ",\"UTMRATASK\":\"%u\",\"UTRR\":\"%u\",\"UTRW\":\"%u\""
- ",\"UTRSYNCCACHE\":\"%u\",\"UTRUNMAP\":\"%u\""
- ",\"UTRETC\":\"%u\"\n",
- get_err_member(UTP_cnt).UTMR_query_task_cnt,
- get_err_member(UTP_cnt).UTMR_abort_task_cnt,
- get_err_member(UTP_cnt).UTR_read_err,
- get_err_member(UTP_cnt).UTR_write_err,
- get_err_member(UTP_cnt).UTR_sync_cache_err,
- get_err_member(UTP_cnt).UTR_unmap_err,
- get_err_member(UTP_cnt).UTR_etc_err);
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_query_cnt, "\"NOPERR\":\"%u\",\"R_DESC\":\"%u\""
- ",\"W_DESC\":\"%u\",\"R_ATTR\":\"%u\",\"W_ATTR\":\"%u\""
- ",\"R_FLAG\":\"%u\",\"S_FLAG\":\"%u\",\"C_FLAG\":\"%u\""
- ",\"T_FLAG\":\"%u\"\n",
- get_err_member(Query_cnt).NOP_err,
- get_err_member(Query_cnt).R_Desc_err,
- get_err_member(Query_cnt).W_Desc_err,
- get_err_member(Query_cnt).R_Attr_err,
- get_err_member(Query_cnt).W_Attr_err,
- get_err_member(Query_cnt).R_Flag_err,
- get_err_member(Query_cnt).Set_Flag_err,
- get_err_member(Query_cnt).Clear_Flag_err,
- get_err_member(Query_cnt).Toggle_Flag_err);
- /* daily err sum */
- SEC_UFS_DATA_ATTR_RW(SEC_UFS_err_sum, "\"OPERR\":\"%u\",\"UICCMD\":\"%u\""
- ",\"UICERR\":\"%u\",\"FATALERR\":\"%u\",\"UTPERR\":\"%u\""
- ",\"QUERYERR\":\"%u\"\n",
- get_err_member(op_cnt).op_err,
- get_err_member(UIC_cmd_cnt).UIC_cmd_err,
- get_err_member(UIC_err_cnt).UIC_err,
- get_err_member(Fatal_err_cnt).Fatal_err,
- get_err_member(UTP_cnt).UTP_err,
- get_err_member(Query_cnt).Query_err);
- SEC_UFS_DATA_ATTR_RW(sense_err_count, "\"MEDIUM\":\"%u\",\"HWERR\":\"%u\"\n",
- get_err_member(sense_cnt).scsi_medium_err,
- get_err_member(sense_cnt).scsi_hw_err);
- /* accumulated err sum */
- SEC_UFS_DATA_ATTR_RO(SEC_UFS_err_summary,
- "OPERR : %u, UICCMD : %u, UICERR : %u, FATALERR : %u"
- ", UTPERR : %u, QUERYERR : %u\n"
- "MEDIUM : %u, HWERR : %u\n",
- SEC_UFS_ERR_INFO_GET_VALUE(op_cnt, op_err),
- SEC_UFS_ERR_INFO_GET_VALUE(UIC_cmd_cnt, UIC_cmd_err),
- SEC_UFS_ERR_INFO_GET_VALUE(UIC_err_cnt, UIC_err),
- SEC_UFS_ERR_INFO_GET_VALUE(Fatal_err_cnt, Fatal_err),
- SEC_UFS_ERR_INFO_GET_VALUE(UTP_cnt, UTP_err),
- SEC_UFS_ERR_INFO_GET_VALUE(Query_cnt, Query_err),
- SEC_UFS_ERR_INFO_GET_VALUE(sense_cnt, scsi_medium_err),
- SEC_UFS_ERR_INFO_GET_VALUE(sense_cnt, scsi_hw_err));
- static struct attribute *sec_ufs_error_attributes[] = {
- &dev_attr_SEC_UFS_op_cnt.attr,
- &dev_attr_SEC_UFS_uic_cmd_cnt.attr,
- &dev_attr_SEC_UFS_uic_err_cnt.attr,
- &dev_attr_SEC_UFS_fatal_cnt.attr,
- &dev_attr_SEC_UFS_utp_cnt.attr,
- &dev_attr_SEC_UFS_query_cnt.attr,
- &dev_attr_SEC_UFS_err_sum.attr,
- &dev_attr_sense_err_count.attr,
- &dev_attr_SEC_UFS_err_summary.attr,
- &dev_attr_SEC_UFS_TW_info.attr,
- &dev_attr_SEC_UFS_s_info.attr,
- NULL
- };
- static struct attribute_group sec_ufs_error_attribute_group = {
- .attrs = sec_ufs_error_attributes,
- };
- /* SEC error info : end */
- /* SEC cmd log : begin */
- static ssize_t ufs_sec_cmd_log_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct ufs_sec_cmd_log_info *ufs_cmd_log =
- ufs_sec_features.ufs_cmd_log;
- struct ufs_sec_cmd_log_entry *entry = NULL;
- int i = (ufs_cmd_log->pos + UFS_SEC_CMD_LOGGING_MAX
- - UFS_SEC_CMD_LOGNODE_MAX);
- int idx = 0;
- int len = 0;
- len += snprintf(buf + len, PAGE_SIZE - len,
- "%2s: %10s: %2s %3s %4s %9s %6s %16s\n",
- "No", "log string", "lu", "tag",
- "c_id", "lba", "length", "time");
- for (idx = 0; idx < UFS_SEC_CMD_LOGNODE_MAX; idx++, i++) {
- i %= UFS_SEC_CMD_LOGGING_MAX;
- entry = &ufs_cmd_log->entries[i];
- len += snprintf(buf + len, PAGE_SIZE - len,
- "%2d: %10s: %2d %3d 0x%02x %9u %6d %16llu\n",
- idx,
- entry->str, entry->lun, entry->tag,
- entry->cmd_id, entry->lba,
- entry->transfer_len, entry->tstamp);
- }
- return len;
- }
- static DEVICE_ATTR(cmd_log, 0440, ufs_sec_cmd_log_show, NULL);
- static struct attribute *sec_ufs_cmd_log_attributes[] = {
- &dev_attr_cmd_log.attr,
- NULL
- };
- static struct attribute_group sec_ufs_cmd_log_attribute_group = {
- .attrs = sec_ufs_cmd_log_attributes,
- };
- /* SEC cmd log : end */
- static int ufs_sec_create_sysfs_dev(struct ufs_hba *hba)
- {
- /* sec specific vendor sysfs nodes */
- if (!sec_ufs_node_dev) {
- #if IS_ENABLED(CONFIG_DRV_SAMSUNG)
- sec_ufs_node_dev = sec_device_create(hba, "ufs");
- #else
- pr_err("Fail to create dev node\n");
- #endif
- }
- if (IS_ERR(sec_ufs_node_dev)) {
- pr_err("Fail to create sysfs dev\n");
- return -ENODEV;
- }
- return 0;
- }
- static void ufs_sec_create_sysfs_group(struct ufs_hba *hba, struct device **dev,
- const struct attribute_group *dev_attr_group, const char *group_name)
- {
- int ret = 0;
- ret = sysfs_create_group(&(*dev)->kobj, dev_attr_group);
- if (ret)
- dev_err(hba->dev, "%s: Failed to create %s sysfs group (err = %d)\n",
- __func__, group_name, ret);
- }
- void ufs_sec_add_sysfs_nodes(struct ufs_hba *hba)
- {
- struct device *shost_dev = &(hba->host->shost_dev);
- if (ufs_sec_is_err_cnt_allowed())
- ufs_sec_create_sysfs_group(hba, &shost_dev,
- &sec_ufs_error_attribute_group, "sec_ufs_err");
- if (!ufs_sec_create_sysfs_dev(hba)) {
- ufs_sec_create_sysfs_group(hba, &sec_ufs_node_dev,
- &sec_ufs_info_attribute_group, "sec_ufs_info");
- if (ufs_sec_features.ufs_cmd_log)
- ufs_sec_create_sysfs_group(hba, &sec_ufs_node_dev,
- &sec_ufs_cmd_log_attribute_group,
- "sec_ufs_cmd_log");
- }
- }
- void ufs_sec_remove_sysfs_nodes(struct ufs_hba *hba)
- {
- struct device *shost_dev = &(hba->host->shost_dev);
- if (sec_ufs_node_dev) {
- sysfs_remove_group(&sec_ufs_node_dev->kobj,
- &sec_ufs_info_attribute_group);
- sysfs_remove_group(&sec_ufs_node_dev->kobj,
- &sec_ufs_cmd_log_attribute_group);
- }
- if (shost_dev)
- sysfs_remove_group(&shost_dev->kobj,
- &sec_ufs_error_attribute_group);
- }
|