kernel_samsung_a53x/drivers/scsi/ufs/ufs-sec-feature.h
2024-06-15 16:02:09 -03:00

206 lines
5.4 KiB
C
Executable file

// SPDX-License-Identifier: GPL-2.0
/*
* Samsung Specific feature
*
* Copyright (C) 2021 Samsung Electronics Co., Ltd.
*
* Authors:
* Storage Driver <storage.sec@samsung.com>
*/
#ifndef __UFS_SEC_FEATURE_H__
#define __UFS_SEC_FEATURE_H__
#include "ufshcd.h"
#include "ufshci.h"
#include <linux/notifier.h>
#if IS_ENABLED(CONFIG_SEC_ABC)
#include <linux/sti/abc_common.h>
#endif
/*unique number*/
#define UFS_UN_20_DIGITS 20
#define UFS_UN_MAX_DIGITS 21 //current max digit + 1
#define SERIAL_NUM_SIZE 7
#define TOSHIBA_SERIAL_NUM_SIZE 10
#define SCSI_UFS_TIMEOUT (10 * HZ)
#define UFS_SEC_MAX_LUN_ID 8
/*device desc dExtenedUFSFeaturesSupport bit*/
#define UFS_SEC_DEV_STREAMID_SUP (1 << 15)
/*device desc wStreamIDVersion offset*/
#define DEVICE_DESC_PARAM_STREAMID_VER 0x63
/*fStreamIDEn flag offset*/
#define QUERY_FLAG_IDN_STREAMID_EN 0x15
/*unit desc wContextCapabilities offset*/
#define UNIT_DESC_PARAM_CONTEXT_CAP 0x0B
/*wContextConf attribute offset*/
#define QUERY_ATTR_IDN_CONTEXTCONF 0x10
struct ufs_vendor_dev_info {
struct ufs_hba *hba;
char unique_number[UFS_UN_MAX_DIGITS];
u8 lifetime;
unsigned int lc_info;
/*context id*/
u16 conid_cap[UFS_SEC_MAX_LUN_ID];
bool conid_support;
/*stream id*/
bool stid_support;
bool stid_en;
bool stid_dt;
/*device stuck*/
bool device_stuck;
};
struct ufs_sec_cmd_info {
u8 opcode;
u32 lba;
int transfer_len;
u8 lun;
};
enum ufs_sec_log_str_t {
UFS_SEC_CMD_SEND,
UFS_SEC_CMD_COMP,
UFS_SEC_QUERY_SEND,
UFS_SEC_QUERY_COMP,
UFS_SEC_NOP_SEND,
UFS_SEC_NOP_COMP,
UFS_SEC_TM_SEND,
UFS_SEC_TM_COMP,
UFS_SEC_TM_ERR,
UFS_SEC_UIC_SEND,
UFS_SEC_UIC_COMP,
};
static const char * const ufs_sec_log_str[] = {
[UFS_SEC_CMD_SEND] = "scsi_send",
[UFS_SEC_CMD_COMP] = "scsi_cmpl",
[UFS_SEC_QUERY_SEND] = "query_send",
[UFS_SEC_QUERY_COMP] = "query_cmpl",
[UFS_SEC_NOP_SEND] = "nop_send",
[UFS_SEC_NOP_COMP] = "nop_cmpl",
[UFS_SEC_TM_SEND] = "tm_send",
[UFS_SEC_TM_COMP] = "tm_cmpl",
[UFS_SEC_TM_ERR] = "tm_err",
[UFS_SEC_UIC_SEND] = "uic_send",
[UFS_SEC_UIC_COMP] = "uic_cmpl",
};
struct ufs_sec_cmd_log_entry {
const char *str; /* ufs_sec_log_str */
u8 lun;
u8 cmd_id;
u32 lba;
int transfer_len;
u8 idn; /* used only for query idn */
unsigned long outstanding_reqs;
unsigned int tag;
u64 tstamp;
};
#define UFS_SEC_CMD_LOGGING_MAX 200
#define UFS_SEC_CMD_LOGNODE_MAX 64
struct ufs_sec_cmd_log_info {
struct ufs_sec_cmd_log_entry *entries;
int pos;
};
struct ufs_sec_feature_info {
struct ufs_sec_cmd_log_info *ufs_cmd_log;
u32 last_ucmd;
bool ucmd_complete;
struct notifier_block reboot_notify;
struct delayed_work noti_work;
enum query_opcode last_qcmd;
enum dev_cmd_type qcmd_type;
bool qcmd_complete;
};
extern struct device *sec_ufs_cmd_dev;
enum ufs_sec_wb_state {
WB_OFF = 0,
WB_ON_READY,
WB_OFF_READY,
WB_ON,
NR_WB_STATE
};
struct ufs_sec_wb_info {
struct ufs_hba *hba;
bool wb_support; /* feature support and enabled */
bool wb_setup_done; /* setup is done or not */
bool wb_off; /* WB off or not */
atomic_t wb_off_cnt; /* WB off count */
enum ufs_sec_wb_state state; /* current state */
unsigned long state_ts; /* current state timestamp */
int up_threshold_block; /* threshold for WB on : block(4KB) count */
int up_threshold_rqs; /* WB on : request count */
int down_threshold_block; /* threshold for WB off : block count */
int down_threshold_rqs; /* WB off : request count */
int wb_disable_threshold_lt; /* LT threshold that WB is not allowed */
int on_delay; /* WB on delay for WB_ON_READY -> WB_ON */
int off_delay; /* WB off delay for WB_OFF_READY -> WB_OFF */
/* below values will be used when (wb_off == true) */
int lp_up_threshold_block; /* threshold for WB on : block(4KB) count */
int lp_up_threshold_rqs; /* WB on : request count */
int lp_down_threshold_block; /* threshold for WB off : block count */
int lp_down_threshold_rqs; /* WB off : request count */
int lp_on_delay; /* on_delay multiplier when (wb_off == true) */
int lp_off_delay; /* off_delay multiplier when (wb_off == true) */
int wb_current_block; /* current block counts in WB_ON state */
int wb_current_rqs; /* request counts in WB_ON */
int wb_curr_issued_min_block; /* min. issued block count */
int wb_curr_issued_max_block; /* max. issued block count */
unsigned int wb_curr_issued_block; /* amount issued block count during current WB_ON session */
unsigned int wb_issued_size_cnt[4]; /* volume count of amount issued block per WB_ON session */
unsigned int wb_total_issued_mb; /* amount issued Write Size(MB) in all WB_ON */
struct workqueue_struct *wb_workq;
struct work_struct wb_on_work;
struct work_struct wb_off_work;
};
void ufs_sec_init_logging(struct device *dev);
void ufs_set_sec_features(struct ufs_hba *hba);
void ufs_remove_sec_features(struct ufs_hba *hba);
void ufs_sec_feature_config(struct ufs_hba *hba);
void ufs_sec_create_sysfs(struct ufs_hba *hba);
void ufs_sec_check_hwrst_cnt(void);
void ufs_sec_register_vendor_hooks(void);
void ufs_sec_check_op_err(struct ufs_hba *hba, enum ufs_event_type evt, void *data);
void ufs_sec_print_err_info(struct ufs_hba *hba);
void ufs_sec_get_health_desc(struct ufs_hba *hba);
inline bool ufs_sec_is_wb_allowed(void);
void ufs_sec_wb_force_off(struct ufs_hba *hba);
inline bool streamid_is_enabled(void);
int ufs_sec_streamid_ctrl(struct ufs_hba *hba, bool value);
void ufs_sec_check_device_stuck(void);
void ufs_sec_print_err(void);
#endif