diff --git a/arch/arm64/configs/tencent.config b/arch/arm64/configs/tencent.config index dcfd3e97e9a488233856ddaca7ac609ae803f3d9..2241d968bd44af72a4e8999e5f674b27fbfe76d9 100644 --- a/arch/arm64/configs/tencent.config +++ b/arch/arm64/configs/tencent.config @@ -1274,6 +1274,7 @@ CONFIG_THIRDPARTY_MPT3SAS=m CONFIG_THIRDPARTY_SMARTPQI=m CONFIG_THIRDPARTY_LPFC=m CONFIG_THIRDPARTY_MEGARAID_SAS=m +CONFIG_SCSI_PS3STOR=m CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y diff --git a/arch/mips/configs/loongson3_defconfig b/arch/mips/configs/loongson3_defconfig index e41f4841cb4d58d210acc7732984510e12a60a31..6ceca4f93775e8dfa0cb6adfa0aaf42be710d76d 100644 --- a/arch/mips/configs/loongson3_defconfig +++ b/arch/mips/configs/loongson3_defconfig @@ -119,6 +119,7 @@ CONFIG_MEGARAID_MM=y CONFIG_MEGARAID_MAILBOX=y CONFIG_MEGARAID_LEGACY=y CONFIG_MEGARAID_SAS=y +CONFIG_SCSI_PS3STOR=m CONFIG_ATA=y CONFIG_SATA_AHCI=y CONFIG_PATA_ATIIXP=y diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig index 2e25b264f70fb55b15f6b99e6e1b71b3c4aa2a6d..35cb3fdf8b50eb00bd69ba5226cc836c21e8eaec 100644 --- a/arch/powerpc/configs/skiroot_defconfig +++ b/arch/powerpc/configs/skiroot_defconfig @@ -96,6 +96,7 @@ CONFIG_MEGARAID_MM=m CONFIG_MEGARAID_MAILBOX=m CONFIG_MEGARAID_SAS=m CONFIG_SCSI_MPT2SAS=m +CONFIG_SCSI_PS3STOR=m CONFIG_SCSI_IPR=m # CONFIG_SCSI_IPR_TRACE is not set # CONFIG_SCSI_IPR_DUMP is not set diff --git a/arch/x86/configs/config.pswitch b/arch/x86/configs/config.pswitch index e688f34d1dc0699f5f52835d641f2f662f8cab91..069739354ce975ad041687e8fe0127c7026feae3 100644 --- a/arch/x86/configs/config.pswitch +++ b/arch/x86/configs/config.pswitch @@ -2168,6 +2168,7 @@ CONFIG_MEGARAID_MAILBOX=y CONFIG_MEGARAID_LEGACY=y CONFIG_MEGARAID_SAS=m CONFIG_SCSI_MPT3SAS=m +CONFIG_SCSI_PS3STOR=m CONFIG_SCSI_MPT2SAS_MAX_SGE=128 CONFIG_SCSI_MPT3SAS_MAX_SGE=128 CONFIG_SCSI_SMARTPQI=m diff --git a/arch/x86/configs/tencent.config b/arch/x86/configs/tencent.config index f6ec17e7ea2c8913a53e33cd5c44adf691aceac8..4c0665d5b26c42a35415ca4956907800ab353458 100644 --- a/arch/x86/configs/tencent.config +++ b/arch/x86/configs/tencent.config @@ -1296,6 +1296,7 @@ CONFIG_THIRDPARTY_MPT3SAS=m CONFIG_THIRDPARTY_SMARTPQI=m CONFIG_THIRDPARTY_LPFC=m CONFIG_THIRDPARTY_MEGARAID_SAS=m +CONFIG_SCSI_PS3STOR=m CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index f6c30e7ddc5277ff1805a3802afc51d3fb4838ab..08ae83233bfd397aef6c50c1ac1c77dd3b7fe397 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -481,6 +481,7 @@ config SCSI_ARCMSR source "drivers/scsi/esas2r/Kconfig" source "drivers/scsi/megaraid/Kconfig.megaraid" source "drivers/scsi/mpt3sas/Kconfig" +source "drivers/scsi/ps3stor/Kconfig" source "drivers/scsi/smartpqi/Kconfig" source "drivers/scsi/ufs/Kconfig" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index c00e3dd57990cd297401c8332c22054d86cca88b..ac051e18c0447563e91a7b7cd68721bca5f1cf0d 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ obj-$(CONFIG_MEGARAID_SAS) += megaraid/ obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/ +obj-$(CONFIG_SCSI_PS3STOR) += ps3stor/ obj-$(CONFIG_SCSI_UFSHCD) += ufs/ obj-$(CONFIG_SCSI_ACARD) += atp870u.o obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o diff --git a/drivers/scsi/ps3stor/Kconfig b/drivers/scsi/ps3stor/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..aeae25f3da5a624d1020fbddee4b512247ba00c5 --- /dev/null +++ b/drivers/scsi/ps3stor/Kconfig @@ -0,0 +1,8 @@ +config SCSI_PS3STOR + tristate "Linkdata ps3stor Storage Controller Device Driver" + depends on PCI && SCSI + select SCSI_SAS_ATTRS + select RAID_ATTRS + select IRQ_POLL + help + This driver supports Linkdata HBA & RAID controllers. \ No newline at end of file diff --git a/drivers/scsi/ps3stor/Makefile b/drivers/scsi/ps3stor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..7078aa7c6944efde3e0e20ef5507081c6db0aa1a --- /dev/null +++ b/drivers/scsi/ps3stor/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 +EXTRA_CFLAGS += -DPS3_CFG_RELEASE +EXTRA_CFLAGS += -DPS3_HARDWARE_ASIC +EXTRA_CFLAGS += -DPS3_MODEL_V200 + +ifneq ($(KERNELRELEASE),) +CONFIG_MODULE_SIG=n +obj-m += ps3stor.o + +ps3stor-objs := $(patsubst %.c, %.o, $(notdir $(wildcard $(src)/*.c))) +ps3stor-objs += $(patsubst %.c, linux/%.o, $(notdir $(wildcard $(src)/linux/*.c))) + +ccflags-y += -Werror -Wmaybe-uninitialized -frecord-gcc-switches +ccflags-y += -I$(src) -I$(src)/linux -I$(src)/include/htp_v200 -I$(src)/include/ +else + KDIR ?= /lib/modules/`uname -r`/build + +all: + @echo "ARCH=$(ARCH)" + @echo "KDIR=$(KDIR)" + @echo "OS=$(OS_SYSTEM)" + @echo "EXTRA_CFLAGS=$(EXTRA_CFLAGS)" + @$(MAKE) -C $(KDIR) M=$(PWD) INCDIR=$(PWD)/linux modules +clean: + @rm -rf *.o *.d *.ko Module.* modules.* *.mod.* .*.d .*.cmd .tmp_versions *.o.ur-safe + @rm -rf ./linux/*.o + @rm -rf ./tags + @rm -rf ./output.log +endif + diff --git a/drivers/scsi/ps3stor/clean.sh b/drivers/scsi/ps3stor/clean.sh new file mode 100644 index 0000000000000000000000000000000000000000..2e10af5963ccec418a959acf305ef79023404188 --- /dev/null +++ b/drivers/scsi/ps3stor/clean.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# clean.sh: a script clean the driver. +# + +make clean + +exit 0 diff --git a/drivers/scsi/ps3stor/compile.sh b/drivers/scsi/ps3stor/compile.sh new file mode 100644 index 0000000000000000000000000000000000000000..5a0001923e0071d117333f2dfb6221da5b92b669 --- /dev/null +++ b/drivers/scsi/ps3stor/compile.sh @@ -0,0 +1,249 @@ +#!/bin/bash +install_module=0 +is_pkg_install="" +pkg_mode="" +ramfs_file="" +ramfs_bak_file="" +timestamp="" +rpm_initrd="/boot/initramfs-$(uname -r).img" +dpkg_initrd="/boot/initrd.img-$(uname -r)" +driverDesDir="/lib/modules/$(uname -r)/kernel/drivers/scsi/" +print_usage() { + echo "Usage: $0 [-install|-auto] [-help]" + echo "" + echo "Options:" + echo " -install|-i: compile and install the driver immediately" + echo " -auto|-a: compile and install the driver, effective on next reboot" + echo " -help|-h: print usage message" + echo "" + echo "Performs the compilation and installation of a driver. If no options given then does compilation only." + exit 1 +} + +find_rpm_or_deb() { + is_pkg_install=$1 + pkg_mode=$2 + ramfs_file=$3 + + if [ -f "$rpm_initrd" ]; then + ramfs_file=$rpm_initrd + pkg_mode="rpm" + if rpm -qa |grep ps3stor &> /dev/null ; then + is_pkg_install="pkg" + elif lsinitrd "$ramfs_file" | grep -q "ps3stor" ; then + is_pkg_install="auto" + elif lsmod | grep -q ps3stor; then + is_pkg_install="install" + else + is_pkg_install="no" + fi + + elif [ -f "$dpkg_initrd" ]; then + ramfs_file=$dpkg_initrd + pkg_mode="deb" + dpkg_status=$(dpkg -l | grep ps3stor | awk '{ print $1 }') + if [ "$dpkg_status" == "ii" ]; then + is_pkg_install="pkg" + elif lsinitramfs -l "$ramfs_file" | grep -q "ps3stor" ; then + is_pkg_install="auto" + elif lsmod | grep -q ps3stor; then + is_pkg_install="install" + else + is_pkg_install="no" + fi + else + is_pkg_install="no" + fi +} + +backup_restore(){ + if [ -e "${driverDesDir}/ps3stor.ko.$timestamp" ]; then + cp -f ${driverDesDir}/ps3stor.ko.$timestamp ${driverDesDir}/ps3stor.ko + fi + if [ -e "${driverDesDir}/ps3stor.ko.xz.$timestamp" ]; then + cp -f ${driverDesDir}/ps3stor.ko.xz.$timestamp ${driverDesDir}/ps3stor.ko.xz + fi + if [ -e "$ramfs_bak_file" ]; then + echo "The backup file for boot is $ramfs_bak_file, please use the backup file to restore the system environment." + fi + echo "The ps3stor.ko deployed failed." +} + +check_return(){ + if [ $? -ne 0 ]; then + backup_restore + exit 1; + fi +} + +ko_install(){ + if !(lsmod |grep -q scsi_transport_sas); then + modprobe scsi_transport_sas + fi + if [ $? -eq 0 ]; then + insmod ps3stor.ko + if [ $? -eq 0 ]; then + echo "The ps3stor.ko module has been loaded successfully." + else + echo "The ps3stor.ko module has been loaded failed." + exit 1 + fi + else + echo "The scsi_transport_sas module has been loaded failed." + exit 1 + fi +} +auto_install(){ + if [ $pkg_mode != "rpm" ] && [ $pkg_mode != "deb" ]; then + echo "Cannot find initrd file." + exit 1 + fi + timestamp=$(date +"%Y%m%d%H%M%S") + if [ -e "${driverDesDir}/ps3stor.ko" ]; then + cp -f ${driverDesDir}/ps3stor.ko ${driverDesDir}/ps3stor.ko.$timestamp + fi + if [ -e "${driverDesDir}/ps3stor.ko.xz" ]; then + cp -f ${driverDesDir}/ps3stor.ko.xz ${driverDesDir}/ps3stor.ko.xz.$timestamp + fi + ramfs_bak_file=$ramfs_file.${timestamp} + if [ -e "$ramfs_file" ]; then + cp -f "$ramfs_file" "$ramfs_bak_file" + fi + if [ $? -ne 0 ]; then + echo "Initramfs backup failed, please check permissions and disk space." + exit 1 + fi + md5_sum_of_ramfs_back=$(md5sum "$ramfs_file" | awk '{print $1}') + + cp -f ps3stor.ko $driverDesDir + xz -f ps3stor.ko + cp -f ps3stor.ko.xz $driverDesDir + if [ $? -ne 0 ]; then + echo "Failed to store ps3stor file, please check permissions and disk space." + exit 1 + fi + + depmod -a + check_return + + sleep 1s + + if [ "$pkg_mode" == "rpm" ]; then + dracut -v -f + elif [ "$pkg_mode" == "deb" ]; then + mkinitramfs -o $ramfs_file + fi + check_return + sleep 1s + + max_retries=30 + retry_interval=1 + attempt=0 + while [ $attempt -lt $max_retries ]; do + md5_sum_of_ramfs=$(md5sum "$ramfs_file" | awk '{print $1}') + echo "The ps3stor.ko is being deployed, please wait." + if [ "$pkg_mode" == "rpm" ] ; then + if lsinitrd "$ramfs_file" | grep -q "ps3stor" && [ $md5_sum_of_ramfs != $md5_sum_of_ramfs_back ]; then + echo "The ps3stor.ko has been deployed. For immediate effect, please reboot or shutdown." + break + fi + elif [ "$pkg_mode" == "deb" ] ; then + if lsinitramfs -l "$ramfs_file" | grep -q "ps3stor" && [ $md5_sum_of_ramfs != $md5_sum_of_ramfs_back ]; then + echo "The ps3stor.ko has been deployed. For immediate effect, please reboot or shutdown." + break + fi + fi + attempt=$((attempt + 1)) + sleep $retry_interval + done + if [ $attempt -ge $max_retries ]; then + backup_restore + exit 1 + fi + +} +while [[ $# -gt 0 ]]; do + case "$1" in + -install|-i) + if [ $install_module -ne 0 ];then + print_usage + exit 1 + else + install_module=1 + shift + fi + ;; + -auto|-a) + if [ $install_module -ne 0 ];then + print_usage + exit 1 + else + install_module=2 + shift + fi + ;; + -help|-h) + print_usage + exit 0 + shift + ;; + *) + echo "Invalid argument: $1" + print_usage + exit 1 + ;; + esac +done +output_filename="output.log" +if [ -e "$output_filename" ]; then + rm -rf output_filename +fi +chmod a+x clean.sh +./clean.sh + +if ! command -v gcc &> /dev/null; then + echo "Error: The gcc compiler is not installed in the system." + echo "Please install gcc before running this script." + exit 1 +fi + +kernel_source_dir="/lib/modules/`uname -r`/build" + +make -j4 -C $kernel_source_dir M=$PWD 2>&1 | tee output_filename + +ko_filename="ps3stor.ko" +if [ ! -f "$ko_filename" ]; then + echo "The compilation execution failed." + exit 1 +fi + +if [ $install_module == 0 ]; then + exit 0 +fi +find_rpm_or_deb $is_pkg_install $pkg_mode $ramfs_file +if [ "$is_pkg_install" == "pkg" ]; then + echo "The ps3stor.ko module has been loaded in rpm/deb format. Please unload the current driver pkg first." + exit 1 +elif [ "$is_pkg_install" = "auto" ]; then + echo "Already have a ps3stor.ko loaded in auto. Please unload first." + exit 1 +elif [ "$is_pkg_install" = "install" ]; then + if [ $install_module == 2 ]; then + auto_install + else + echo "Already have a ps3stor.ko loaded. Please unload first." + exit 1 + fi +elif [ "$is_pkg_install" = "no" ]; then + if [ $install_module == 1 ]; then + ko_install + elif [ $install_module == 2 ]; then + ko_install + auto_install + fi +else + echo "unknown err" + exit 1 +fi + +exit 0 \ No newline at end of file diff --git a/drivers/scsi/ps3stor/dkms.conf b/drivers/scsi/ps3stor/dkms.conf new file mode 100644 index 0000000000000000000000000000000000000000..45a3478172460c4c5398a402d2bec153c465dc3f --- /dev/null +++ b/drivers/scsi/ps3stor/dkms.conf @@ -0,0 +1,17 @@ +# +# Master copy of dkms.conf for ps3stor. +# Dont edit this file manually. Auto build script makes necessary changes. +# + +PACKAGE_NAME="ps3stor" +PACKAGE_VERSION=0.0.0.0 +MOD_PATH=${dkms_tree}/${PACKAGE_NAME}/${PACKAGE_VERSION} + +MAKE[0]="make -C ${kernel_source_dir} SUBDIRS=${MOD_PATH}/build modules" +CLEAN="make -C ${kernel_source_dir} SUBDIRS=${MOD_PATH}/build clean" + +BUILT_MODULE_NAME[0]="ps3stor" +DEST_MODULE_LOCATION[0]="/kernel/drivers/scsi/" +MODULES_CONF_ALIAS_TYPE[0]="scsi_hostadapter" + +REMAKE_INITRD="yes" diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp.h new file mode 100644 index 0000000000000000000000000000000000000000..7167a29982152e8fb5c22d82c9808fab4b8d2e6b --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp.h @@ -0,0 +1,278 @@ + +#ifndef _PS3_HTP_H_ +#define _PS3_HTP_H_ + +#include "ps3_htp_def.h" +#include "ps3_htp_dev.h" +#include "ps3_htp_req_frame_hw.h" + +#define PS3_DUMP_CTRL_COPY_FINISH 0x1 +#define PS3_DUMP_CTRL_DUMP_ABORT 0x2 +#define PS3_DUMP_CTRL_DUMP_FW_LOG 0x3 +#define PS3_DUMP_CTRL_DUMP_BAR_DATA 0x4 +#define PS3_DUMP_CTRL_DUMP_CORE_FILE 0x5 +#define PS3_DUMP_CTRL_DUMP_END 0x6 +#define PS3_DUMP_CTRL_DUMP_INT_READY 0x7 +#define PS3_DUMP_DMA_DONE (0x1) +#define PS3_DUMP_DMA_ABORT (0x1 << 6) +#define PS3_DUMP_DATA_UNIT_SIZE (0x400) +#define PS3_DREICT_SENSE_DATA_BUF_SIZE 72 + +#define PS3_ATU_FLAG_LOW_BITS_MASK (0x0000FFFF) +#define PS3_ATU_FLAG_HIGH_BITS_MASK (0xFFFFFFFFFFFF0000) +#define PS3_ATU_FLAG_DRIVER_SET (0xC0DE) + +#define PS3_IOCTL_VERSION (0x2000000) + +typedef enum{ + HIL_MODEL_SW = 0, + HIL_MODEL_HW, + HIL_MODEL_HW_ENHANCED, + HIL_MODEL_SW_ASSIST, +}hilModel_e; + +enum Ps3DumpType{ + PS3_DUMP_TYPE_UNKNOWN = 0, + PS3_DUMP_TYPE_CRASH = 1, + PS3_DUMP_TYPE_FW_LOG = 2, + PS3_DUMP_TYPE_BAR_DATA = 3, +}; + +enum Ps3DumpState { + PS3_DUMP_STATE_INVALID = 0, + PS3_DUMP_STATE_PRE_ABORT, + PS3_DUMP_STATE_ABORTED, + PS3_DUMP_STATE_START, + PS3_DUMP_STATE_COPYING, + PS3_DUMP_STATE_COPY_DONE, + PS3_DUMP_STATE_READY = 7, +}; +enum Ps3CtrlSecurityState { + PS3_CTRL_SECURITY_STATE_DECRYPT = 0, + PS3_CTRL_SECURITY_STATE_ENCRYPT, +}; + +struct Ps3DumpNotifyInfo { + S32 dumpType; +}; + + +struct PS3LinkErrInfo { + U32 invalidDwordCount; + U32 runningDisparityErrCount; + U32 lossOfDwordSyncCount; + U32 phyResetProblemCount; +}; + +enum PhyCtrl { + PS3_SAS_CTRL_UNKNOWN = 0, + PS3_SAS_CTRL_RESET = 1, + PS3_SAS_CTRL_RESET_HARD = 2, + PS3_SAS_CTRL_DISABLE = 3 +}; + + +enum { + PS3_UNLOAD_SUB_TYPE_RESERVED = 0, + PS3_UNLOAD_SUB_TYPE_REMOVE = 1, + PS3_UNLOAD_SUB_TYPE_SHUTDOWN = 2, + PS3_UNLOAD_SUB_TYPE_SUSPEND = 3, +}; + + +enum { + PS3_SUSPEND_TYPE_NONE = 0, + PS3_SUSPEND_TYPE_SLEEP = 1, + PS3_SUSPEND_TYPE_HIBERNATE = 2, +}; + +static inline const S8 * namePhyCtrl(enum PhyCtrl e) +{ + static const S8 *myNames[] = { + [PS3_SAS_CTRL_UNKNOWN] = "PS3_SAS_CTRL_UNKNOWN", + [PS3_SAS_CTRL_RESET] = "PS3_SAS_CTRL_RESET", + [PS3_SAS_CTRL_RESET_HARD] = "PS3_SAS_CTRL_RESET_HARD", + [PS3_SAS_CTRL_DISABLE] = "PS3_SAS_CTRL_DISABLE" + }; + + return myNames[e]; +} + + +struct PS3InitCmdWord { + union { + struct { + U32 type : 2; + U32 reserved1 : 1; + U32 direct : 2; + U32 reserved2 : 27; + }; + U32 lowAddr; + }; + + U32 highAddr; +}; + +typedef struct PS3CmdWord { + U16 type : 2; + U16 reserved1 : 2; + U16 direct : 2; + U16 isrSN : 8; + U16 reserved2 : 2; + U16 cmdFrameID : 13; + U16 reserved3 : 3; + U16 phyDiskID : 12; + U16 reserved4 : 4; + U16 virtDiskID : 8; + U16 reserved5 : 4; + U16 qMask : 4; +} PS3CmdWord_s; + + +struct PS3CmdWordSw { + U32 type : 2; + U32 noReplyWord : 1; + U32 cmdFrameID : 13; + U32 isrSN : 8; + U32 cmdIndex : 8; +}; + + +union PS3CmdWordU32 { + struct PS3CmdWordSw cmdWord; + U32 val; +}; + + +union PS3DefaultCmdWord { + struct PS3CmdWord cmdWord; + union { + struct{ + U32 low; + U32 high; + } u; + U64 words; + }; +}; + +enum{ + PS3_ISR_ACC_MODE_LATENCY = 0, + PS3_ISR_ACC_MODE_SSD_IOPS, + PS3_ISR_ACC_MODE_HDD_IOPS, + PS3_ISR_ACC_MODE_IOPS_VER0 = 2, + PS3_ISR_ACC_MODE_DEV_IOPS, + PS3_ISR_ACC_MODE_MAX, +}; +struct PS3ReplyFifoDesc { + U64 ReplyFifoBaseAddr; + U32 irqNo; + U16 depthReplyFifo; + U8 isrAccMode; + U8 reserved; +}; + +typedef struct PS3ReplyWord { + U16 type : 2; + U16 diskType : 1; + U16 reserved1 : 1; + U16 mode : 2; + U16 reserved2 : 10; + U16 cmdFrameID : 13; + U16 reserved3 : 2; + U16 reserved4 : 1; + U16 retStatus : 15; + U16 retType : 1; + U16 reserved5 : 12; + U16 qMask : 4; +} PS3ReplyWord_s; + + +struct PS3MgrTaskRespInfo { + U8 iocStatus; + U8 reserved1; + U16 iocLogInfo; + U32 terminationCnt; + U32 respInfo; + U32 reserved2; +}; + + +struct PS3MgrCmdReplyRespInfo { + U8 cmdReplyStatus; + U8 reserved[15]; +}; + + +union PS3RespDetails { + U32 xfer_cnt; + U32 respData[4]; + struct PS3MgrTaskRespInfo taskMgrRespInfo; + struct PS3MgrCmdReplyRespInfo replyCmdRespInfo; +}; + + +typedef struct PS3SasDirectRespStatus { + U32 status:8; + U32 dataPres:2; + U32 reserved:22; +} PS3SasStatus_s; + + +typedef struct Ps3SasDirectRespFrameIU { + union { + U8 reserved0[8]; + U64 mediumErrorLba; + }; + U8 reserved1[2]; + U8 dataPres; + U8 status; + union { + U32 reserved2; + U32 xfer_cnt; + }; + U32 senseDataLen; + U32 respDataLen; + U8 data[PS3_SENSE_BUFFER_SIZE]; + U8 reserved3[8]; +} Ps3SasDirectRespFrameIU_s; + + +typedef struct PS3NormalRespFrame { + union PS3RespDetails respDetail; + U8 reserved1[8]; + U8 sense[PS3_SENSE_BUFFER_SIZE]; + U8 type; + U8 reserved2[3]; + U8 respStatus; + U8 dataPre; + U8 reserved3[2]; +} PS3NormalRespFrame_s; + +typedef union PS3RespFrame{ + Ps3SasDirectRespFrameIU_s sasRespFrame; + PS3NormalRespFrame_s normalRespFrame; +}PS3RespFrame_u; + + +typedef struct Ps3DebugMemEntry { + U64 debugMemAddr; + U32 debugMemSize; + U32 reserved; +} Ps3DebugMemEntry_s; + + +typedef struct PS3NvmeCmdStatus { + union { + struct { + U16 sc : 8; + U16 sct : 3; + U16 crd : 2; + U16 m : 1; + U16 dnr : 1; + U16 p : 1; + }; + U16 cmdStatus; + }; +} PS3NvmeCmdStatus_s; + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_def.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_def.h new file mode 100644 index 0000000000000000000000000000000000000000..c59080cc7e9ed13906e83bee6d87b2431fcfc214 --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_def.h @@ -0,0 +1,559 @@ + +#ifndef _PS3_HTP_DEF_H_ +#define _PS3_HTP_DEF_H_ + +#include "ps3_types.h" + +typedef unsigned char Bool; + + + + +#define PCIE_DMA_HOST_ADDR_BIT_POS (44) + +#define PCIE_DMA_HOST_ADDR_BIT_POS_SET(addr) \ + (((1ULL) << (PCIE_DMA_HOST_ADDR_BIT_POS)) | (addr)) + +#define PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR(addr) \ + ((~((1ULL) << (PCIE_DMA_HOST_ADDR_BIT_POS))) & (addr)) + +#define PCIE_DMA_HOST_ADDR_BIT_POS_F0 (54) +#define PCIE_DMA_HOST_ADDR_BIT_POS_F1 (53) +#define PCIE_DMA_HOST_ADDR_BIT_POS_VALID (52) + +#define PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(bit_pos, addr) \ + ((addr) + ((1ULL) << (bit_pos))) + +#define PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, addr) \ + ((addr) - ((1ULL) << (bit_pos))) + + +enum PS3FWDiagKey { + PS3_FW_DIAG_FLUSH = 0X00, + PS3_FW_DIAG_1ST_KEY = 0x52, + PS3_FW_DIAG_2ND_KEY = 0x5F, + PS3_FW_DIAG_3RD_KEY = 0x55, + PS3_FW_DIAG_4TH_KEY = 0x5F, + PS3_FW_DIAG_5TH_KEY = 0x52, + PS3_FW_DIAG_6TH_KEY = 0x45, + PS3_FW_DIAG_7TH_KEY = 0x41, + PS3_FW_DIAG_8TH_KEY = 0x44, + PS3_FW_DIAG_9TH_KEY = 0x59, +}; + + +enum PS3FWStateAct { + PS3_FW_STATE_ACT_INIT_READY = 0X00000001, +}; + + +enum PS3RegDoorBellType { + PS3_REG_DOORBELL_STATE_TO_READY = 1, + PS3_REG_DOORBELL_STATE_TO_FAULT = 2, + PS3_REG_DOORBELL_STATE_TO_HALT = 3, +}; + + +enum PS3FWSoftResetAct { + PS3_FW_STATE_ACT_SHALLOW_SOFT_RESET = 0X00000001, + PS3_FW_STATE_ACT_DEEP_SOFT_RESET = 0X00000002, +}; + +enum PS3PerfModeType { + PS3_PERF_MODE_BALANCE = 0, + PS3_PERF_MODE_IOPS = 1, + PS3_PERF_MODE_LATENCY = 2, +}; + + +enum PS3BitPos { + PS3_BIT_POS_DEFAULT = 0, + PS3_BIT_POS_44 = 1, + PS3_BIT_POS_45 = 2, + PS3_BIT_POS_46 = 3, + PS3_BIT_POS_47 = 4, + PS3_BIT_POS_48 = 5, + PS3_BIT_POS_49 = 6, + PS3_BIT_POS_50 = 7, + PS3_BIT_POS_51 = 8, + PS3_BIT_POS_52 = 9, + PS3_BIT_POS_53 = 10, + PS3_BIT_POS_54 = 11, +}; + + +enum PS3CmdType { + PS3_CMD_INIT_IOC = 0x0, + PS3_CMD_VD_SCSI_IO_RW = 0x1, + PS3_CMD_VD_SCSI_IO_NORW = 0x2, + PS3_CMD_PD_SCSI_IO_RW = 0x3, + PS3_CMD_PD_SCSI_IO_NORW = 0x4, + PS3_CMD_MANAGEMENT = 0x5, + PS3_CMD_SCSI_TASK_MANAGEMENT = 0x6, + PS3_CMD_IOCTL = 0x7, + PS3_CMD_SAS_MANAGEMENT = 0x8, + PS3_CMD_COUNT = 0x9, + PS3_CMD_INVALID = 0xff, +}; + +enum { + PS3_SGL = 0x0, + PS3_PRP = 0x1, +}; + +enum { + PS3_CMD_OPERATOR_TYPE_HOST = 0x0, + PS3_CMD_OPERATOR_TYPE_UEFI = 0x1, + PS3_CMD_OPERATOR_TYPE_IOC = 0x2, +}; + + +enum { + PS3_PCI_IRQ_LEGACY = 0, + PS3_PCI_IRQ_MSI = 1, + PS3_PCI_IRQ_MSIX = 2, +}; + +#define PS3_DRV_SYSTEM_ID_MAX_LEN 64 +#define PS3_SENSE_BUFFER_SIZE (96) +#define PS3_RESP_FRAME_BUFFER_SIZE (128) + + +#define PS3_REQUEST_CONTROL_DIR_NONE 0x00 +#define PS3_REQUEST_CONTROL_DIR_READ 0x01 +#define PS3_REQUEST_CONTROL_DIR_WRITE 0x02 +#define PS3_REQUEST_CONTROL_DIR_BOTH 0x03 + + +#define PS3_MAX_PD_COUNT_IN_SPAN 32 +#define PS3_MAX_SPAN_IN_VD 8 + +#define PS3_IOC_INIT_STATE_MASK 0xFFFF +#define PS3_IOC_RECOVERY_COUNT_MASK 0xFFFFFFFF + + +#define PS3_START_STATE_SPACE 0x0100 + + +#define PS3_DRV_MGR_FLUSH_RETRY_MAX_COUNT 1 + + +#define MAX_MGR_CMD_TOTAL_COUNT (16) + +#define PS3_HOT_RESET_OFFSET (HIL_REG1_PS3_REGISTER_F_PS3_DEBUG10_ADDR - HIL_REG1_PS3_REGISTER_F_BASEADDR) + +typedef union HilRegPs3RegisterHotReset{ + U64 val; + struct{ + + U8 isHotReset : 1; + U8 reserved0 : 7; + U8 reserved1[7] ; + }reg; +}HilRegPs3RegisterHotReset_u; + + +#define PS3_ATU_SUPPORT_OFFSET (HIL_REG1_PS3_REGISTER_F_PS3_DEBUG8_ADDR - HIL_REG1_PS3_REGISTER_F_BASEADDR) + +typedef union HilRegPs3RegisterFPs3AtuSupport{ + volatile U64 val; + struct{ + + U8 bitPos ; + U8 reserved[7] ; + }reg; +}HilRegPs3RegisterFPs3AtuSupport_u; + + +#define PS3_CAN_HARD_RESET_OFFSET (HIL_REG1_PS3_REGISTER_F_PS3_DEBUG9_ADDR - HIL_REG1_PS3_REGISTER_F_BASEADDR) + +typedef union HilRegPs3RegisterFPs3CanHardReset{ + volatile U64 val; + struct{ + + U8 canHardReset : 1; + U8 reserved0 : 7; + U8 reserved1[7] ; + }reg; +}HilRegPs3RegisterFPs3CanHardReset_u; + + +typedef enum PS3FWRunState { + PS3_FW_STATE_UNDEFINED = 0x00, + PS3_FW_STATE_START = 0x01, + PS3_FW_STATE_READY = 0x02, + PS3_FW_STATE_WAIT = 0x03, + PS3_FW_STATE_RUNNING = 0x04, + PS3_FW_STATE_FLUSHING = 0x05, + PS3_FW_STATE_RESET = 0x06, + PS3_FW_STATE_CRITICAL = 0x09, + PS3_FW_STATE_FAULT = 0xE0, + PS3_FW_STATE_HALT = 0xF0, + PS3_FW_STATE_END, + PS3_FW_STATE_MASK = 0xFF, + PS3_FW_STATE_WDT_MASK = 0xFF0000FF, +}PS3FWRunState_e; + + +typedef enum PS3FWStartState { + PS3_START_STATE_UNDEFINED = 0x0000, + PS3_START_STATE_INIT_BASE = 0x0100, + PS3_START_STATE_INIT_HARDWARE = 0x0200, + PS3_START_STATE_INIT_SOFTWARE = 0x0300, + PS3_START_STATE_INIT_DATAPATH = 0x0400, + PS3_START_STATE_INIT_THREAD = 0x0500, + PS3_START_STATE_SCAN_DEVICE = 0x0600, + PS3_START_STATE_FLUSH_CACHE = 0x0700, + PS3_START_STATE_INIT_RESET = 0x0800, + PS3_START_STATE_FINISHED = 0x0900, + PS3_START_STATE_MASK = 0xFF00, + PS3_START_STATE_WDT_MASK = 0xFF00FF00, +}PS3FWStartState_e; + + +#define PS3_FW_RESET_FLAG (0X00000001) +#define PS3_FW_DIAG_ENABLE (0X00000001) +#define PS3_FW_HARD_RESET_ACT (0X00000001) + + +#define PS3_FW_MAX_CMD_MASK (0X0000FFFF) +#define PS3_FW_MAX_MSIX_VECTORS_MASK (0X0000FFFF) +#define PS3_FW_MAX_CHAIN_SIZE_MASK (0XFFFFFFFF) +#define PS3_FW_MAX_RAID_MAP_SIZE_MASK (0XFFFFFFFF) +#define PS3_FW_MAX_NVME_PAGE_SIZE_MASK (0xFFFFFFFF) + + +#define PS3_FW_INTERRUPT_STATUS_MASK (0X00000001) +#define PS3_FW_INTERRUPT_CMD_INTR_CAP_MASK (0X00000004) +#define PS3_FW_INTERRUPT_CMD_MSI_CAP_MASK (0X00000002) +#define PS3_FW_INTERRUPT_CMD_MSIX_CAP_MASK (0X00000001) +#define PS3_FW_INTERRUPT_CLEAR_MASK (0X00000001) + + +enum PS3FWFeatureSupportMask { + PS3_FW_FEATURE_SUPPORT_SYNC_CACHE = 0X00000001, + PS3_FW_FEATURE_SUPPORT_DMA64 = 0X00000002, +}; + + +enum PS3FWCtrlMask { + PS3_FW_CTRL_CMD_TRIGGER_SNAPSHOT = 0X00000001, + PS3_FW_CTRL_CMD_CRASHDUMP_COLLECTION_DONE = 0X00000002, + PS3_FW_CTRL_CMD_CRASHDUMP_DMA_CLEAR = 0X00000004, +}; + + +enum PS3FWCtrlStatusMask { + PS3_FW_CTRL_STATUS_CRASHDUMP_DONE = 0X00000001, + PS3_FW_CTRL_STATUS_RSVR = 0X00000002, + PS3_FW_CTRL_STATUS_CRASHDUMP_MAP = 0X00000004, +}; + + +enum PS3CmdTrigger { + PS3_CMD_TRIGGER_UNLOAD = 0X0001, + PS3_CMD_TRIGGER_UNLOAD_SUSPEND = 0X0002, +}; + + +enum PS3RegCmdState { + PS3_DOORBELL_DONE = 0X0001, +}; + + +enum PS3Debug12Mask { + PS3_DEBUG12__HOT_RESET = 0X00000001, +}; + + +enum PS3MgrControlFlag { + PS3_REQUEST_CONTROL_SKIP_REFIRE = 0x0, + PS3_REQUEST_CONTROL_SENSE32 = 0x1, + PS3_REQUEST_CONTROL_SENSE64 = 0x2, +}; + + +enum PS3TaskCmdSubType { + PS3_TASK_CMD_SCSI_TASK_ABORT, + PS3_TASK_CMD_SCSI_TASK_RESET, + PS3_TASK_CMD_COUNT, + + PS3_TASK_CMD_INVALID = 0xffff, +}; + + +enum PS3MgrCmdSubType { + PS3_MGR_CMD_GET_CTRL_INFO = 0x0, + PS3_MGR_CMD_UNLOAD, + PS3_MGR_CMD_SUBSCRIBE_EVENT, + PS3_MGR_CMD_GET_VD_LIST, + PS3_MGR_CMD_GET_PD_LIST, + PS3_MGR_CMD_GET_VD_INFO, + PS3_MGR_CMD_GET_PD_INFO, + PS3_MGR_CMD_GET_BOOTDRIVE_INFO, + PS3_MGR_CMD_GET_BIOS_INFO, + + PS3_MGR_CMD_GET_SNAPSHOT_ATTR, + PS3_MGR_CMD_SET_CRASH_DUMP, + PS3_MGR_CMD_CANCEL, + PS3_MGR_CMD_ABORT, + PS3_MGR_CMD_DEV_ADD_ACK, + PS3_MGR_CMD_DEV_DEL_DONE, + + PS3_SAS_SMP_REQUEST, + PS3_SAS_GET_LINK_ERR, + PS3_SAS_PHY_CTRL, + PS3_SAS_GET_EXPANDERS, + PS3_SAS_GET_PHY_INFO, + PS3_SAS_GET_EXPANDER_INFO, + + PS3_MGR_CMD_AUTODUMP_NOTIFY, + + PS3_MGR_CMD_SECURITY_RANDOM_GET, + PS3_MGR_CMD_SECURITY_PASSWORD, + PS3_MGR_CMD_WEBSUBSCRIBE_EVENT, + + PS3_MGR_CMD_PRESERVED_INFO_GET, + PS3_MGR_CMD_GET_PD_SN_LIST, + PS3_MGR_CMD_PD_REF_CLEAR, + PS3_MGR_CMD_COUNT, + PS3_MGR_CMD_INVALID = 0xff +}; + +static inline const S8 * namePS3MgrCmdSubType(enum PS3MgrCmdSubType type) +{ + static const S8 *myNames[] = { + [PS3_MGR_CMD_GET_CTRL_INFO] = "PS3_MGR_CMD_GET_CTRL_INFO", + [PS3_MGR_CMD_UNLOAD] = "PS3_MGR_CMD_UNLOAD", + [PS3_MGR_CMD_SUBSCRIBE_EVENT] = "PS3_MGR_CMD_SUBSCRIBE_EVENT", + [PS3_MGR_CMD_GET_VD_LIST] = "PS3_MGR_CMD_GET_VD_LIST", + [PS3_MGR_CMD_GET_PD_LIST] = "PS3_MGR_CMD_GET_PD_LIST", + [PS3_MGR_CMD_GET_VD_INFO] = "PS3_MGR_CMD_GET_VD_INFO", + [PS3_MGR_CMD_GET_PD_INFO] = "PS3_MGR_CMD_GET_PD_INFO", + [PS3_MGR_CMD_GET_BOOTDRIVE_INFO] = "PS3_MGR_CMD_GET_BOOTDRIVE_INFO", + [PS3_MGR_CMD_GET_BIOS_INFO] = "PS3_MGR_CMD_GET_BIOS_INFO", + + [PS3_MGR_CMD_GET_SNAPSHOT_ATTR] = "PS3_MGR_CMD_GET_SNAPSHOT_ATTR", + [PS3_MGR_CMD_SET_CRASH_DUMP] = "PS3_MGR_CMD_SET_CRASH_DUMP", + [PS3_MGR_CMD_CANCEL] = "PS3_MGR_CMD_CANCEL", + [PS3_MGR_CMD_ABORT] = "PS3_MGR_CMD_ABORT", + [PS3_MGR_CMD_DEV_ADD_ACK] = "PS3_MGR_CMD_DEV_ADD_ACK", + [PS3_MGR_CMD_DEV_DEL_DONE] = "PS3_MGR_CMD_DEV_DEL_DONE", + + [PS3_SAS_SMP_REQUEST] = "PS3_SAS_SMP_REQUEST", + [PS3_SAS_GET_LINK_ERR] = "PS3_SAS_GET_LINK_ERR", + [PS3_SAS_PHY_CTRL] = "PS3_SAS_PHY_CTRL", + [PS3_SAS_GET_EXPANDERS] = "PS3_SAS_GET_EXPANDERS", + [PS3_SAS_GET_PHY_INFO] = "PS3_SAS_GET_PHY_INFO", + [PS3_SAS_GET_EXPANDER_INFO] = "PS3_SAS_GET_EXPANDER_INFO", + [PS3_MGR_CMD_AUTODUMP_NOTIFY] = "PS3_MGR_CMD_AUTODUMP_NOTIFY", + + [PS3_MGR_CMD_SECURITY_RANDOM_GET] = "PS3_MGR_CMD_SECURITY_RANDOM_GET", + [PS3_MGR_CMD_SECURITY_PASSWORD] = "PS3_MGR_CMD_SECURITY_PASSWORD", + [PS3_MGR_CMD_WEBSUBSCRIBE_EVENT] = "PS3_MGR_CMD_WEBSUBSCRIBE_EVENT", + + [PS3_MGR_CMD_PRESERVED_INFO_GET] = "PS3_MGR_CMD_PRESERVED_INFO_GET", + [PS3_MGR_CMD_GET_PD_SN_LIST] = "PS3_MGR_CMD_GET_PD_SN_LIST", + [PS3_MGR_CMD_PD_REF_CLEAR] = "PS3_MGR_CMD_PD_REF_CLEAR", + [PS3_MGR_CMD_COUNT] = "PS3_MGR_CMD_INVALID", + }; + + if (type < PS3_MGR_CMD_COUNT && type < (sizeof(myNames) / sizeof(myNames[0]))) { + return myNames[type]; + } + + return "PS3_MGR_CMD_INVALID"; + +} + + +enum PS3CmdIocErrCode { + PS3_IOC_ERR_CODE_OK = 0x00, + PS3_IOC_ERR_CODE_ERR = 0x01, + PS3_IOC_STATE_INVALID_STATUS = 0xFFFF, +}; + +typedef enum PS3CmdStatusCode { + SCSI_STATUS_GOOD = 0x00, + SCSI_STATUS_CHECK_CONDITION = 0x02, + SCSI_STATUS_CONDITION_MET = 0x04, + SCSI_STATUS_BUSY = 0x08, + SCSI_STATUS_RESERVATION_CONFLICT = 0x18, + SCSI_STATUS_TASK_SET_FULL = 0x28, + SCSI_STATUS_ACA_ACTIVE = 0x30, + SCSI_STATUS_TASK_ABORTED = 0x40, + + PS3_STATUS_DEVICE_NOT_FOUND = 0x80, + PS3_STATUS_IO_ABORTED = 0x81, + PS3_STATUS_REQ_ILLEGAL = 0x82, + PS3_STATUS_RESET_FAIL = 0x83, + PS3_STATUS_VD_OFFLINE = 0x84, + PS3_STATUS_ACCESS_BLOCK = 0x85, + PS3_STATUS_INTERNAL_SOFT_ERR = 0x86, + PS3_STATUS_INTERNAL_ERR = 0x87, + PS3_STATUS_HOST_NOT_FOUND = 0x88, + PS3_STATUS_HOST_RESET = 0x89, + PS3_STATUS_PCI_RECOVERY = 0x8A, + PS3_STATUS_VD_MEMBER_OFFLINE = 0x8B, + PS3_STATUS_UNDERRUN = 0x8C, + PS3_STATUS_OVERRUN = 0x8D, + PS3_STATUS_DIF_GRD_ERROR = 0x8E, + PS3_STATUS_DIF_REF_ERROR = 0x8F, + PS3_STATUS_DIF_APP_ERROR = 0x90, + PS3_STATUS_ACCESS_RO = 0x91, +} PS3CmdStatusCode_e; + + +enum PS3CmdWordType { + PS3_CMDWORD_TYPE_INIT = 0x00, + PS3_CMDWORD_TYPE_ABORT = 0x00, + PS3_CMDWORD_TYPE_MGR = 0x01, + PS3_CMDWORD_TYPE_READ = 0x02, + PS3_CMDWORD_TYPE_WRITE = 0x03, +}; + +#define PS3_CMD_TYPE_IS_RW(type) \ + ((type) == PS3_CMDWORD_TYPE_READ || (type) == PS3_CMDWORD_TYPE_WRITE) + +enum PS3ReqFrameCtrl { + PS3_DATA_BUF_SGL = 0x00, + + PS3_DATA_BUF_PRP = 0x02, +}; + +enum PS3CmdWordDirect { + PS3_CMDWORD_DIRECT_NORMAL = 0x00, + PS3_CMDWORD_DIRECT_RESERVE = 0x01, + PS3_CMDWORD_DIRECT_OK = 0x02, + PS3_CMDWORD_DIRECT_ADVICE = 0x03, +}; + +enum PS3CmdWordPort { + PS3_CMDWORD_PORT_SAS0 = 0x00, + PS3_CMDWORD_PORT_SAS1 = 0x01, + PS3_CMDWORD_PORT_NVME = 0x02, + PS3_CMDWORD_PORT_RESERVE = 0x03, +}; + +enum PS3CmdWordFormat { + PS3_CMDWORD_FORMAT_FRONTEND = 0x00, + PS3_CMDWORD_FORMAT_HARDWARE = 0x01, +}; + +enum PS3ReplyWordFlag { + PS3_REPLY_WORD_FLAG_SUCCESS = 0x00, + PS3_REPLY_WORD_FLAG_FAIL = 0X01, + PS3_REPLY_WORD_FLAG_REPEAT_REPLY = 0x0F, + PS3_REPLY_WORD_FLAG_INVALID = 0X7FFF, +}; + +enum PS3ReplyWordMask { + PS3_REPLY_WORD_MASK_FLAG = 0X7FFF, +}; + +enum PS3ReplyWordMode{ + PS3_REPLY_WORD_MODE_NORMAL = 0x00, + PS3_REPLY_WORD_MODE_DIRECT_ADVICE_TO_NORMAL = 0X01, + PS3_REPLY_WORD_MODE_DIRECT_OK = 0X02, + PS3_REPLY_WORD_MODE_DIRECT_ADVICE_TO_DIRECT = 0X03, +}; + +enum PS3RetType{ + PS3_NOT_HARD_RET = 0x00, + PS3_HARD_RET = 0X01, +}; + +enum PS3CmdWordVer { + PS3_CMDWORD_VER_0 = 0x0, + PS3_CMDWORD_VER_1 = 0x1, + PS3_CMDWORD_VER_UPDATING = 0x2, + PS3_CMDWORD_VER_INVALID = 0x3, +}; + +enum PS3CmdWordNoReplyWord { + PS3_CMD_WORD_NEED_REPLY_WORD = 0, + PS3_CMD_WORD_NO_REPLY_WORD = 1, +}; + +enum PS3ChannelType { + PS3_CHAN_TYPE_UNKNOWN = 0, + PS3_CHAN_TYPE_VD = 1, + PS3_CHAN_TYPE_PD = 2, +}; + +enum PS3DiskType { + PS3_DISK_TYPE_UNKNOWN = 0, + PS3_DISK_TYPE_VD = 1, + PS3_DISK_TYPE_PD = 2, +}; + +#define PS3_CONTROL_PAGE_TYPE_BIT_OFFSET (0x1) +#define PS3_CONTROL_PAGE_TYPE_BIT_NUM (0x1) +#define PS3_CONTROL_PAGE_TYPE_MASK (0x1) + +enum PS3PageType { + PS3_CONTROL_PAGE_TYPE_OF_SGE = 0, + PS3_CONTROL_PAGE_TYPE_OF_PRP = 1, + PS3_CONTROL_PAGE_TYPE_MAX = 2, +}; +static inline const S8 * namePS3DiskType(enum PS3DiskType e) +{ + static const S8 *myNames[] = { + [PS3_DISK_TYPE_UNKNOWN] = "PS3_DISK_TYPE_UNKNOWN", + [PS3_DISK_TYPE_VD] = "PS3_DISK_TYPE_VD", + [PS3_DISK_TYPE_PD] = "PS3_DISK_TYPE_PD" + }; + + return myNames[e]; +} + +static inline const S8 * namePS3ChannelType(enum PS3ChannelType e) +{ + static const S8 *myNames[] = { + [PS3_CHAN_TYPE_UNKNOWN] = "PS3_CHAN_TYPE_UNKNOWN", + [PS3_CHAN_TYPE_VD] = "PS3_CHAN_TYPE_VD", + [PS3_CHAN_TYPE_PD] = "PS3_CHAN_TYPE_PD" + }; + + return myNames[e]; +} + + +enum PS3DrvMgrErrorCode { + PS3_DRV_MGR_TIMEOUT = 1, + PS3_DRV_MGR_UNRUNING, + PS3_DRV_MGR_INVAL_CMD, + PS3_DRV_MGR_NORESOURCE, + PS3_DRV_MGR_INVAL_PARAM, + PS3_DRV_MGR_DEV_NOEXIST, + PS3_DRV_MGR_DEV_DATA_ERR, + PS3_DRV_MGR_BUSY, + PS3_DRV_MGR_EVT_REPEAT, + PS3_DRV_MGR_EVT_CANCLE_ERR, + PS3_DRV_MGR_FLUSH_FAIELD, + PS3_DRV_MGR_SMP_BACKEND_ERR, + PS3_DRV_MGR_LINK_GET_BACKEND_ERR, + PS3_DRV_MGR_PHY_CTL_BACKEND_ERR, + PS3_DRV_MGR_RESTART_COMMAND_RSP, + PS3_DRV_MGR_TM_FAILED, +}; + + +enum PS3IoctlRetCode { + PS3_IOCTL_STATUS_OK = 0, + PS3_IOCTL_STATUS_INVALID_REQ = 1, + PS3_IOCTL_STATUS_NO_HBA = 2, + PS3_IOCTL_STATUS_BUSY = 3, + PS3_IOCTL_STATUS_NOT_READY = 4, + PS3_IOCTL_STATUS_INVALIED_PARAM = 5, + PS3_IOCTL_STATUS_REQ_ERR = 6, + PS3_IOCTL_STATUS_NEED_RETRY = 7, +}; + + +enum PS3HwVdMaxIOSize { + PS3_ENUM_HW_VD_MAX_IO_SIZE_1M = 0, + PS3_ENUM_HW_VD_MAX_IO_SIZE_OTHER, +}; + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_dev.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..cd230dda1e45805b337cdba2467b7c6f91f15ada --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_dev.h @@ -0,0 +1,333 @@ + +#ifndef _PS3_HTP_DEV_H_ +#define _PS3_HTP_DEV_H_ + +#include "ps3_htp_def.h" + +#define PS3_MAX_CHANNEL_NUM 15 +#define PS3_MAX_RANDOM_NUM 32 +#define PS3_MAX_IV_NUM 16 +#define PS3_SECURITY_CIPHER_NUM_MAX 2 +#define PS3_STABLE_WRITES_MASK (0x1) + + +struct PS3IocCtrlProp { + U32 enableSnapshot : 1; + U32 enableSoftReset : 1; + U32 reserved1:30; + U32 reserved2; +}; + + +struct PS3IocCtrlCapable { + U32 supportUnevenSpans : 1; + U32 supportJbodSecure : 1; + U32 supportNvmePassthru : 1; + U32 supportDirectCmd : 1; + U32 supportAcceleration : 1; + U32 supportSataDirectCmd: 1; + U32 supportSataNcq : 1; + U32 reserved1 : 25; + U32 reserved2[3]; +}; + +#define PS3_IOC_CLUSTER_SERIAL_NO_SIZE 16 + +struct PS3ChannelAttr { + U16 channelType : 4; + U16 maxDevNum : 12; +}; + +struct PS3ChannelInfo { + U8 channelNum; + U8 reserved; + struct PS3ChannelAttr channels[PS3_MAX_CHANNEL_NUM]; +}; + +struct PS3QosInfo { + U16 tfifoDepth; + U16 sataHddQuota; + U16 sataSsdQuota; + U16 sasHddQuota; + U16 sasSsdQuota; + U16 nvmeVdQuota; + U16 nvmeDirectQuota; + U16 nvmeNormalQuota; +}; + + +struct PS3IocCtrlInfo { + + U16 maxVdCount; + + U16 maxPdCount; + + + U32 maxSectors; + struct PS3IocCtrlProp properties; + struct PS3IocCtrlCapable capabilities; + + U8 scsiTaskAbortTimeout; + U8 scsiTaskResetTimeout; + + U16 offsetOfVDID; + U8 reserved1[2]; + + U16 cancelTimeOut; + + + U32 vdIOThreshold; + + U8 iocPerfMode; + + U8 vdQueueNum; + + U8 ioTimeOut; + U8 hwVdMaxIOSize:4; + U8 reserved2:4; + + struct PS3ChannelInfo channelInfo; + + struct PS3QosInfo qosInfo; + U16 isotoneTimeOut; + U8 reserved3[2]; + + + U8 reserved4[32]; + +}; + +struct PS3Dev { + union { + U16 phyDiskID; + U16 virtDiskID; + }; + U16 softChan : 4; + U16 devID : 12; +}; + +typedef union PS3DiskDev { + U32 diskID; + struct PS3Dev ps3Dev; +}PS3DiskDev_u; + + +struct PS3DiskDevPos { + union { + struct { + U8 checkSum; + U8 enclId; + U8 phyId; + }; + U32 diskMagicNum; + }; + PS3DiskDev_u diskDev; +}; + + +struct PS3PhyDevice { + struct PS3DiskDevPos diskPos; + U8 diskState; + U8 configFlag; + U8 driverType:4; + U8 mediumType:4; + U8 reserved; + U8 reserved1[4]; +}; + + +struct PS3VirtDevice { + struct PS3DiskDevPos diskPos; + U8 accessPolicy; + U8 isHidden; + U8 diskState; + U8 reserved; + U8 reserved1[4]; +}; + +union PS3Device { + struct PS3PhyDevice pd; + struct PS3VirtDevice vd; +}; + +struct PS3DevList { + U16 count; + U8 reserved[6]; + union PS3Device devs[0]; +}; + +struct PS3PDInfo { + struct PS3DiskDevPos diskPos; + U8 diskState; + U8 configFlag; + U8 driverType:4; + U8 mediumType:4; + U8 scsiInterfaceType; + U8 taskAbortTimeout; + U8 taskResetTimeout; + union { + struct { + U8 supportNCQ:1; + U8 protect:1; + U8 isDirectDisable:1; + U8 reserved:5; + }; + U8 pdFlags; + }; + U8 reserved1; + U16 sectorSize; + U8 reserved2[2]; + U8 enclId; + U8 phyId; + U8 dmaAddrAlignShift; + U8 dmaLenAlignShift; + U8 reserved3[4]; + U32 maxIOSize; + U32 devQueDepth; + U16 normalQuota; + U16 directQuota; + U8 reserved4[20]; +}; + + +struct PS3Extent { + PS3DiskDev_u phyDiskID; + U8 state; + U8 reserved[3]; +}; + +struct PS3Span { + U32 spanStripeDataSize; + U8 spanState; + U8 spanPdNum; + U8 reserved[2]; + struct PS3Extent extent[PS3_MAX_PD_COUNT_IN_SPAN]; +}; + +struct PS3VDEntry { + struct PS3DiskDevPos diskPos; + U16 sectorSize; + U16 stripSize; + U32 stripeDataSize; + U16 physDrvCnt; + U16 diskGrpId; + U8 accessPolicy; + + U8 reserved1; + U8 dmaAddrAlignShift; + U8 dmaLenAlignShift; + U8 isDirectEnable:1; + U8 isHidden:1; + U8 isNvme:1; + U8 isSsd:1; + U8 bdev_bdi_cap:2; + U8 isWriteDirectEnable:1; + U8 reserved2:1; + U8 raidLevel; + U8 spanCount; + U8 diskState; + U16 umapBlkDescCnt:3; + U16 umapNumblk:13; + U16 dev_busy_scale; + U64 startLBA; + U64 extentSize; + U64 mapBlock; + U64 capacity; + U8 isTaskMgmtEnable; + U8 taskAbortTimeout; + U8 taskResetTimeout; + U8 mapBlockVer; + U32 maxIOSize; + U32 devQueDepth; + U16 virtDiskSeq; + U16 normalQuota; + U16 directQuota; + U16 reserved4[21]; + struct PS3Span span[PS3_MAX_SPAN_IN_VD]; + +}; + +struct PS3VDInfo { + U16 count; + U8 reserved[6]; + struct PS3VDEntry vds[0]; +}; + +struct PS3DrvSysInfo { + U8 version; + U8 systemIDLen; + U8 reserved[6]; + U8 systemID[PS3_DRV_SYSTEM_ID_MAX_LEN]; +}; + + +struct PS3PhyInfo { + U64 sasAddr; + U64 attachedSasAddr; + U8 phyId; + U8 negLinkRate; + U8 slotId; + U8 attachDevType; + U8 initiatorPortProtocol:4; + U8 targetPortProtocols:4; + U8 attachInitiatorPortProtocol:4; + U8 attachTargetPortProtocols:4; + U8 minLinkRateHw:4; + U8 maxLinkRateHw:4; + U8 minLinkRate:4; + U8 maxLinkRate:4; + U8 enable:1; + U8 reserve:7; + U8 reserved[7]; +}; + + +struct PS3ExpanderInfo { + U64 sasAddr; + U64 parentSasAddr; + U8 parentId; + U8 enclID; + U8 devType; + U8 phyCount; + U8 reserved[4]; +}; + + +struct PS3Expanders { + U8 count; + U8 reserved[7]; + U64 hbaSasAddr[3]; + struct PS3ExpanderInfo expanders[0]; +}; + +struct PS3BiosInfo { + U8 biosState; + U8 biosMode; + + U8 biosAbs; + U8 devMaxNum; +}; + +struct PS3BootDriveInfo { + U8 hasBootDrive :1; + U8 isPD :1; + U8 reserved_9 :6; + U8 enclID ; + U16 slotID ; + U16 vdID ; + U8 pad[2]; +}; + +struct PS3RandomInfo { + U8 randomNum[PS3_MAX_RANDOM_NUM]; + U8 iv[PS3_MAX_IV_NUM]; +}; + +struct PS3SecurityPwHead { + U8 cipherNum; + U32 cipherLegth[PS3_SECURITY_CIPHER_NUM_MAX]; + U32 cipherOffset[PS3_SECURITY_CIPHER_NUM_MAX]; + U8 iv[PS3_MAX_IV_NUM]; +}; + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_event.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_event.h new file mode 100644 index 0000000000000000000000000000000000000000..2b0fa7e8ed3a8551309d920b765e90485e10c7d8 --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_event.h @@ -0,0 +1,76 @@ + +#ifndef _PS3_HTP_EVENT_H_ +#define _PS3_HTP_EVENT_H_ + +#include "ps3_htp_def.h" +#include "ps3_htp_dev.h" +#include "ps3_mgr_evt.h" +#include "ps3_evtcode_trans.h" + +#define PS3_EVENT_DETAIL_BUF_MAX (20) + + +enum PS3EventLevel { + PS3_EVENT_LEVEL_INFO, + PS3_EVENT_LEVEL_WARN, + PS3_EVENT_LEVEL_CRITICAL, +}; + +#if 0 + +MgrEvtType_e { + PS3_EVENT_TYPE_NONE = 0X00000000, + + PS3_EVENT_TYPE_PD_COUNT_CHANGE = 0X00000001, + + PS3_EVENT_TYPE_VD_COUNT_CHANGE = 0X00000002, + PS3_EVENT_TYPE_CTRL_INFO_CHANGE = 0X00000004, + PS3_EVENT_TYPE_PD_ATTR_CHANGE = 0X00000008, + PS3_EVENT_TYPE_VD_ATTR_CHANGE = 0X00000010, + PS3_EVENT_TYPE_OTHER = 0X00000020, + PS3_EVENT_TYPE_ALL = 0XFFFFFFFF, +}; +#endif + + +struct PS3EventDetail { + U32 eventCode; + U32 timestamp; + MgrEvtType_e eventType; + union { + struct PS3DiskDevPos devicePos; + U8 EnclId; + }; +}; + +struct PS3EventInfo { + U32 eventTypeMap; + U32 eventCount; + + struct PS3EventDetail eventDetail[PS3_EVENT_DETAIL_BUF_MAX]; + U8 reserved[8]; +}; +#if 0 + +enum PS3EventCode { + PS3_EVENT_CODE_NONE = 0X00000000, + + PS3_EVENT_CODE_PD_ADD = 0X00000001, + PS3_EVENT_CODE_PD_DEL = 0X00000002, + PS3_EVENT_CODE_PD_CHANGE = 0X00000003, + PS3_EVENT_CODE_SES_ADD = 0X00000004, + PS3_EVENT_CODE_SES_DEL = 0X00000005, + PS3_EVENT_CODE_PD_COUNT_CHANGE = 0X00000006, + + PS3_EVENT_CODE_VD_ADD = 0X00000011, + PS3_EVENT_CODE_VD_DEL = 0X00000012, + PS3_EVENT_CODE_VD_COUNT_CHANGE = 0X00000013, + + PS3_EVENT_CODE_PD_ATTR_CHANGE = 0X00000021, + + PS3_EVENT_CODE_PD_INFO_CHANGE = 0X00000022, + + PS3_EVENT_CODE_OTHER = 0X00000040, +}; +#endif +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_ioctl.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..9e7824fecbddb545baecb390767cf3dd63c03e16 --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_ioctl.h @@ -0,0 +1,114 @@ + +#ifndef _PS3_HTP_IOCTL_H_ +#define _PS3_HTP_IOCTL_H_ + +#include "ps3_htp.h" +#include "ps3_htp_reqframe.h" + + + +#define PS3_MAX_IOCTL_SGE_NUM 16 +#define PS3_IOCTL_SENSE_SIZE 96 +#define PS3_IOCTL_MAX_FRAME_SIZE 128 + +#ifndef PS3_SCSI_HOST_PROC_NAME +#define PS3_SCSI_HOST_PROC_NAME "ps3stor" +#endif + +#define PS3_PRODUCT_MODEL "ps3stor" + +#ifndef PS3_SCSI_HOST_PROC_NAME_V100 +#define PS3_SCSI_HOST_PROC_NAME_V100 "ps3" +#endif +#define PS3_PRODUCT_MODEL_V100 "ps3" + +#define PS3_PSW_PRODUCT_MODEL "psw" + +struct PS3CmdIoctlHeader { + U8 cmdType; + U8 version; + U16 deviceId; + U16 cmdSubType; + U8 cmdResult; + U8 sglOffset; + U16 index; + U16 control; + U32 sgeCount; + U16 timeout; + U8 sglChainOffset; + U8 syncFlag; + U32 abortCmdFrameId; +}; + +union PS3IoctlFrame { + U8 value[PS3_IOCTL_MAX_FRAME_SIZE]; + struct PS3CmdIoctlHeader header; +}; + +#ifdef _WINDOWS + +#define PS3_IOCTL_SIG "ps3stor" +#define PS3_IOCTL_FUNCTION 0x801 +#define PS3_DEBUG_CLI_FUNCTION 0x802 + +#define PS3_CTL_CODE CTL_CODE(FILE_DEVICE_MASS_STORAGE, PS3_IOCTL_FUNCTION, \ + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define PS3_DBG_CLI_CODE CTL_CODE(FILE_DEVICE_MASS_STORAGE, PS3_DEBUG_CLI_FUNCTION, \ + METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +struct PS3IoctlSyncCmd { + U16 hostId; + U16 sglOffset; + U16 sgeCount; + U16 reserved; + U64 traceId; + struct PS3Sge Sgl[PS3_MAX_IOCTL_SGE_NUM]; + UCHAR data[0]; +}; + +typedef struct _PS3_IO_CONTROL { + SRB_IO_CONTROL SrbHeader; + ULONG reserved; + struct PS3IoctlSyncCmd ps3Ioctl; +}PS3_IO_CONTRL, * PPS3_IO_CONTROL; +#else + +#define PS3_CMD_IOCTL_SYNC_CMD _IOWR('M', 1, struct PS3IoctlSyncCmd) + +#ifndef __WIN32__ +#define PS3_EVENT_NOTICE_SIG (SIGRTMIN+7) +enum{ + PS3_IOCTL_CMD_NORMAL = 0, + PS3_IOCTL_CMD_WEB_SUBSCRIBE, +}; + +struct PS3IoctlSyncCmd { + U16 hostId; + U16 sglOffset; + U16 sgeCount; + U16 reserved1; + U32 resultCode; + U8 reserved2[4]; + U8 sense[PS3_IOCTL_SENSE_SIZE]; + U64 traceId; + U8 reserved3[120]; + union PS3IoctlFrame msg; + struct PS3Sge sgl[PS3_MAX_IOCTL_SGE_NUM]; +}; +#endif + +struct PS3IoctlAsynCmd { + U16 hostId; + U16 reserved1; + + U32 seqNum; + + U16 eventLevel; + + U16 eventType; + U8 reserved2[4]; +}; + +#endif + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_pci.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_pci.h new file mode 100644 index 0000000000000000000000000000000000000000..29ecf508cfa2a4bcefc2bcfe82c0848396f7de66 --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_pci.h @@ -0,0 +1,53 @@ + +#ifndef _PS3_HTP_PCI_H_ +#define _PS3_HTP_PCI_H_ + +#define PCI_DEVICE_ID 0x02 + +enum { + PCI_VENDOR_ID_STARS = 0x1eb6, + PCI_VENDOR_ID_PS3_FPGA = 0x1eb6, + PCI_VENDOR_ID_PS3_SWITCH_FPGA = 0x1eb6, + PCI_VENDOR_ID_PS3_ASIC = 0x1666, + PCI_VENDOR_ID_PS3 = 0x1ff2, + PCI_DEVICE_ID_PS3_RAID = 0x0001, + PCI_DEVICE_ID_PS3_HBA = 0x0002, + PCI_DEVICE_ID_PS3_SWITCH = 0x0003, + PCI_DEVICE_ID_PS3_SWITCH_FPGA = 0x6004, + PCI_DEVICE_ID_PS3_RAID_FPGA = 0xabcd, + PCI_DEVICE_ID_STARS_HBA_2120_16i = 0x20a1, + PCI_DEVICE_ID_STARS_IOC_2020_18i = 0x20a2, + PCI_DEVICE_ID_STARS_IOC_2213_16i = 0x20a3, + PCI_DEVICE_ID_STARS_ROC_2020_10i = 0x30a2, + PCI_SUBVERDOR_PS3_SWITCH_FPGA = 0x1eb6, + PCI_SUBSYSTEM_PS3_SWITCH_FPGA = 0x6004, + PCI_CLASS_CODE_PS3_SWITCH_FPGA = 0x058000, +}; + +static inline const S8 * namePciDevType(U16 e) +{ + switch (e) { + case PCI_DEVICE_ID_PS3_RAID: + return "PCI_DEVICE_ID_PS3_RAID"; + case PCI_DEVICE_ID_PS3_RAID_FPGA: + return "PCI_DEVICE_ID_PS3_RAID_FPGA"; + case PCI_DEVICE_ID_PS3_HBA: + return "PCI_DEVICE_ID_PS3_HBA"; + case PCI_DEVICE_ID_PS3_SWITCH: + return "PCI_DEVICE_ID_PS3_SWITCH"; + case PCI_DEVICE_ID_PS3_SWITCH_FPGA: + return "PCI_DEVICE_ID_PS3_SWITCH_FPGA"; + case PCI_DEVICE_ID_STARS_HBA_2120_16i: + return "PCI_DEVICE_ID_STARS_HBA_2120_16i"; + case PCI_DEVICE_ID_STARS_IOC_2020_18i: + return "PCI_DEVICE_ID_STARS_IOC_2020_18i"; + case PCI_DEVICE_ID_STARS_ROC_2020_10i: + return "PCI_DEVICE_ID_STARS_ROC_2020_10i"; + case PCI_DEVICE_ID_STARS_IOC_2213_16i: + return "PCI_DEVICE_ID_STARS_IOC_2213_16i"; + default: + return "PCI_DEVICE_ID_INVALID"; + } +} + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_req_frame_hw.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_req_frame_hw.h new file mode 100644 index 0000000000000000000000000000000000000000..196995c8312d604c75e281c65af20e464c70f178 --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_req_frame_hw.h @@ -0,0 +1,98 @@ +#ifndef _PS3_HTP_REQ_FRAME_HW_H_ +#define _PS3_HTP_REQ_FRAME_HW_H_ + +#include "ps3_htp_def.h" + +#define ENCODE_CCS_XFERLEN(x) (((U32)(x) >> 2)) +#define DECODE_CCS_XFERLEN(x) (((U32)(x) << 2)) + +#ifdef _WINDOWS +#define __attribute__(x) +#pragma pack(push, 1) +#endif + + +struct PS3NvmeSglDesc { + U64 addr; + union { + struct { + U8 reserved[7]; + U8 subtype : 4; + U8 type : 4; + } generic; + + struct { + U32 length; + U8 reserved[3]; + U8 subtype : 4; + U8 type : 4; + } unkeyed; + + struct { + U64 length : 24; + U64 key : 32; + U64 subtype : 4; + U64 type : 4; + } keyed; + }; +}; + +struct PS3NvmeCmdDw0_9 { + U16 opcode : 8; + U16 fuse : 2; + U16 reserved1 : 4; + U16 psdt : 2; + U16 cID; + + U32 nsID; + + U32 reserved2; + U32 reserved3; + + U64 mPtr; + + + union { + struct { + U64 prp1; + U64 prp2; + } prp; + struct PS3NvmeSglDesc sgl1; + + } dPtr; +}; + + +typedef struct PS3NvmeCommonCmd { + struct PS3NvmeCmdDw0_9 cDW0_9; + + U32 cDW10; + U32 cDW11; + U32 cDW12; + U32 cDW13; + U32 cDW14; + U32 cDW15; +} PS3NvmeCommonCmd_s; + +typedef struct PS3NvmeRWCmd { + struct PS3NvmeCmdDw0_9 cDW0_9; + + U32 sLbaLo; + U32 sLbaHi; + U32 numLba; + U32 cDW13; + U32 cDW14; + U32 cDW15; +} PS3NvmeRWCmd_s; + + +typedef union PS3NvmeReqFrame { + PS3NvmeCommonCmd_s commonReqFrame; + PS3NvmeRWCmd_s rwReqFrame; +} PS3NvmeReqFrame_u; + +#ifdef _WINDOWS +#pragma pack(pop) +#endif + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_reqframe.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_reqframe.h new file mode 100644 index 0000000000000000000000000000000000000000..75ec4804090769261a86ae70321e0cdb06d8ba66 --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_reqframe.h @@ -0,0 +1,296 @@ + +#ifndef _PS3_HTP_REQFRAME_H_ +#define _PS3_HTP_REQFRAME_H_ + +#include "ps3_htp_def.h" +#include "ps3_htp_dev.h" +#include "ps3_htp_sas.h" +#include "ps3_htp_req_frame_hw.h" + +enum { + PS3_FRAME_SGE_BUFSIZE = 4096, + PS3_FRAME_SGE_SHIFT = 12, + PS3_FRAME_REQ_SGE_NUM_FE = 8, + PS3_FRAME_REQ_PRP_NUM_FE = 2, + PS3_FRAME_REQ_SGE_NUM_HW = 8, + PS3_FRAME_REQ_PRP_NUM_HW = 2, + PS3_FRAME_REQ_SGE_NUM_MGR = 11, + PS3_FRAME_REQ_EXT_SGE_MIN = 2, + PS3_FRAME_CDB_BUFLEN = 32, + PS3_FRAME_LUN_BUFLEN = 8, + PS3_DEBUG_MEM_ARRAY_MAX_NUM = 16, + PS3_MAX_DMA_MEM_SIZE = 4096, + PS3_MAX_DEBUG_MEM_SIZE_PARA = 65536, + PS3_DRV_NAME_MAX_LEN = 32, + PS3_DRV_VERSION_MAX_LEN = 24, +}; + +enum { + PS3_DATA_DIRECTION_WRITE = 0, + PS3_DATA_DIRECTION_READ = 1, +}; + +enum { + PS3_REQFRAME_FORMAT_FRONTEND = 0, + PS3_REQFRAME_FORMAT_SAS = 1, + PS3_REQFRAME_FORMAT_SATA = 2, + PS3_REQFRAME_FORMAT_NVME = 3, +}; + +enum { + PS3_LINUX_FRAME = 0, + PS3_WINDOWS_FRAME = 1, +}; + +enum { + PS3_COMPAT_VER_DEFAULT = 0, + PS3_COMPAT_VER_1 = 1, + PS3_COMPAT_VER_MAX = 0xffff, +}; + +typedef struct PS3Sge { + U64 addr; + U32 length; + U32 reserved1 : 30; + U32 lastSge : 1; + U32 ext : 1; +} PS3Sge_s; + +typedef struct PS3Prp { + U64 prp1; + U64 prp2; +} PS3Prp_s; + + + +typedef struct PS3SoftwareZone { + U64 virtDiskLba; + U32 numBlocks; + U8 opcode; + U8 sglOffset; + U8 sglFormat : 2; + U8 isResendCmd : 1; + U8 reserved1 : 5; + U8 reserved2; + U16 subOpcode; + U16 sgeCount : 9; + U16 reserved3 : 7; + U8 reserved4[4]; +} PS3SoftwareZone_s; + +typedef struct PS3ReqFrameHead +{ + U8 cmdType; + U8 cmdSubType; + U16 cmdFrameID; + union{ + struct { + U32 noReplyWord : 1; + U32 dataFormat : 1; + U32 reqFrameFormat : 2; + U32 mapBlockVer : 2; + U32 isWrite : 1; + U32 isStream1 : 1; + U32 reserved : 24; + }; + U32 control; + }; + PS3DiskDev_u devID; + U16 timeout; + U16 virtDiskSeq; + U16 reserved1[4]; + U64 traceID; +} PS3ReqFrameHead_s; + +typedef struct PS3HwReqFrame { + PS3ReqFrameHead_s reqHead; + PS3SoftwareZone_s softwareZone; + U8 reserved[8]; + union { + IODT_V1_s sasReqFrame; + PS3NvmeReqFrame_u nvmeReqFrame; + }; + PS3Sge_s sgl[PS3_FRAME_REQ_SGE_NUM_FE]; +} PS3HwReqFrame_s; + +typedef struct PS3VDAccAttr { + U64 firstPdStartLba; + U8 firstSpanNo; + U8 fisrtSeqInSpan; + U8 secondSeqInSapn; + U8 thirdSeqInSapn; + U8 clineCount; + U8 isAccActive : 1; + U8 isStream : 1; + U8 reserved1 : 6; + U16 ioOutStandingCnt; + U8 reserved2[16]; +} PS3VDAccAttr_s; + + +typedef struct PS3FrontEndReqFrame { + PS3ReqFrameHead_s reqHead; + U8 cdb[PS3_FRAME_CDB_BUFLEN]; + PS3VDAccAttr_s vdAccAttr; + U32 dataXferLen; + U8 reserved[25]; + U8 sgeOffset; + U16 sgeCount; + union { + PS3Sge_s sgl[PS3_FRAME_REQ_SGE_NUM_FE]; + PS3Prp_s prp; + }; +} PS3FrontEndReqFrame_s; + +struct PS3MgrDev { + struct PS3DiskDevPos devID; + U16 num; + U8 devType; + U8 reserved[17]; +}; + +struct PS3MgrEvent { + U32 eventTypeMap; + U32 eventTypeMapProcResult; + U32 eventLevel; + U8 reserved[20]; +}; + + +struct PS3SasMgr { + U64 sasAddr; + U8 enclID; + U8 startPhyID; + U8 phyCount; + U8 reserved1; + U16 reqLen; + U8 reserved2[2]; +}; + + +struct PS3SasPhySet { + U64 sasAddr; + U8 phyID; + U8 minLinkRate; + U8 maxLinkRate; + U8 phyCtrl; + U8 reserved[3]; +}; + +union PS3MgrReqDiffValue { + U8 word[32]; + U16 originalCmdFrameID; + U8 eventStart; + struct PS3MgrDev dev; + struct PS3MgrEvent event; + struct PS3SasMgr sasMgr; + struct PS3SasPhySet phySet; + U8 unLoadType; + BOOL isRetry; +}; + + +typedef struct PS3MgrReqFrame { + PS3ReqFrameHead_s reqHead; + U16 sgeCount; + U8 sgeOffset; + U8 syncFlag; + U16 timeout; + U8 abortFlag; + U8 pendingFlag; + union PS3MgrReqDiffValue value; + U8 osType; + U8 suspend_type; + U8 reserved[6]; + struct PS3Sge sgl[PS3_FRAME_REQ_SGE_NUM_MGR]; +}PS3MgrReqFrame_s; + + +typedef struct PS3MgrTaskReqFrame { + PS3ReqFrameHead_s reqHead; + U16 taskID; + U8 lun[PS3_FRAME_LUN_BUFLEN]; + U8 abortedCmdType; + U8 reserved[5]; +} PS3MgrTaskReqFrame_s; + + +union PS3ReqFrame { + PS3MgrTaskReqFrame_s taskReq; + PS3MgrReqFrame_s mgrReq; + PS3FrontEndReqFrame_s frontendReq; + PS3HwReqFrame_s hwReq; + U8 word[256]; +}; + + +typedef struct PS3DrvInfo { + char drvName[PS3_DRV_NAME_MAX_LEN]; + char drvVersion[PS3_DRV_VERSION_MAX_LEN]; + U64 bus; + U8 dev:5; + U8 func:3; + U8 domain_support:1; + U8 reserved:7; + U16 compatVer; + U32 domain; + U8 reserved1[56]; +} PS3DrvInfo_s; + + +enum { + PS3_MEM_TYPE_UNKNOWN = 0, + PS3_MEM_TYPE_SO = 1, + PS3_MEM_TYPE_RO = 2, +}; + + +typedef struct PS3HostMemInfo { + U64 startAddr; + U64 endAddr; + U8 type; + U8 reserved[7]; +} PS3HostMemInfo_s; + +struct PS3InitReqFrame { + PS3ReqFrameHead_s reqHead; + U8 ver; + U8 reserved0; + U16 length; + U8 operater; + U8 pageSize; + U8 pciIrqType; + U8 osType; + U8 reserved1[6]; + U16 msixVector; + U64 timeStamp; + U64 reqFrameBufBaseAddr; + U64 hostMemInfoBaseAddr; + U32 hostMemInfoNum; + U8 reserved2[20]; + + U64 replyFifoDescBaseAddr; + + U64 respFrameBaseAddr; + U32 eventTypeMap; + U16 reqFrameMaxNum; + U16 respFrameMaxNum; + U64 filterTableAddr; + U32 filterTableLen; + U16 bufSizePerRespFrame; + U8 hilMode; + U8 reserved3[33]; + U64 systemInfoBufAddr; + U64 debugMemArrayAddr; + U32 debugMemArrayNum; + U32 dumpDmaBufLen; + U64 dumpDmaBufAddr; + U32 dumpIsrSN; + U16 drvInfoBufLen; + U8 reserverd4[2]; + U64 drvInfoBufAddr; + U8 reserved5[36]; + U32 respStatus; +}; + +#endif diff --git a/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_sas.h b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_sas.h new file mode 100644 index 0000000000000000000000000000000000000000..06c976e5db921e36d40f3f473a53d6d64e0f92ff --- /dev/null +++ b/drivers/scsi/ps3stor/include/htp_v200/ps3_htp_sas.h @@ -0,0 +1,325 @@ +#ifndef _PS3_IODT_H_ +#define _PS3_IODT_H_ + +#include "ps3_htp_def.h" + + +enum IodtProtocolType { + PROTOCOL_SMP = 0b000, + PROTOCOL_SSP = 0b001, + PROTOCOL_STP = 0b010, + PROTOCOL_DIRT = 0b111, +}; + +enum IodtFrameType { + FRAMETYPE_SSP_CMD = 0b001, + FRAMETYPE_SSP_SMP = 0b001, + FRAMETYPE_SATA_NONDATA = 0b001, + + FRAMETYPE_SSP_TASK = 0b010, + FRAMETYPE_SATA_PIO = 0b010, + + FRAMETYPE_SATA_DMA = 0b011, + + FRAMETYPE_SATA_FPDMA = 0b100, + + FRAMETYPE_SATA_ATAPI = 0b101, + FRAMETYPE_DIRECT = 0b111, +}; + +enum IodtIuSrc { + IU_SRC_MEM = 0b00, + IU_SRC_IODT = 0b01, + IU_SRC_TUPLE = 0b10, + IU_SRC_SATA = 0b11, +}; + +enum IodtSgeMode { + IODT_SGEMODE_DIRECT = 0x0, + IODT_SGEMODE_SGL = 0x1, +}; + +enum IodtEedpMode { + EEDP_MODE_CHECK = 0x0, + EEDP_MODE_INSERT = 0x1, + EEDP_MODE_REPLACE = 0x2, + EEDP_MODE_RMV = 0x3, +}; + +enum AbortCtrl { + + ABT_SASSATA_TASK = 0b00, + ABT_SAS_TASKSET = 0b01, + ABT_LOCAL_BY_DISK = 0b10, + ABT_LOCAL_BY_PORT = 0b11, + + ABT_MGT_IO = 0b00, + ABT_SOFTRESET = 0b01, + ABT_READ_NCQ_ERR_LOG = 0b10, + ABT_SMP = 0b11, +}; + +enum DirectFlag { + DIRECT_FLAG_NORMAL = 0b00, + DIRECT_FLAG_DIRECT = 0b10, +}; + +enum CmdWordType { + CMD_WORD_TYPE_ABORT = 0b00, + CMD_WORD_TYPE_MGT = 0b01, + CMD_WORD_TYPE_READ = 0b10, + CMD_WORD_TYPE_WRITE = 0b11, +}; + +enum SmpFrameType { + SMP_REQ = 0x40, + SMP_RESP = 0x41, +}; + +enum eedpMode { + EEDP_NONE = 0b0000, + EEDP_CHK = 0b0001, + EEDP_INST = 0b0010, + EEDP_REPL = 0b0100, + EEDP_RMV = 0b1000, +}; + +typedef union IoDmaCfg { + struct { + U8 eedpEn : 1; + U8 eedpSgMod : 1; + U8 twoSglMod : 1; + U8 sgMode : 1; + U8 eedpMode : 4; + }; + U8 byte; +} IoDmaCfg_u; + + +typedef struct __attribute__((packed)) SspTaskFrameIu { + U64 LUN; + U16 reserved0; + U8 function; + U8 reserved1; + U16 manageTag; + U8 reserved2[14]; +} SspTaskFrameIu_s; + + +typedef union __attribute__((packed)) SmpFrameIu { + struct { + U8 frameType; + U8 reqestBytes[31]; + }; + U8 smpIURaw[32]; +} SmpFrameIu_s; + + +typedef struct __attribute__((packed)) DfifoWordCommon { + + union { + struct { + U16 type : 2; + U16 rsv1 : 2; + U16 direct : 2; + U16 rFifoID : 4; + U16 rsv2 : 6; + }; + U16 WD0; + }; + + + union{ + + struct { + union{ + + struct { + U16 darID : 13; + U16 rsv3 : 2; + + U16 function : 1; + }; + + struct{ + U16 manageIptt : 13; + }; + }; + }; + + struct { + union{ + + struct{ + U16 reqFrameID : 13; + }; + + + struct{ + U16 manageReqFrameID : 13; + }; + }; + }; + U16 WD1; + }; + + + union { + struct { + U16 phyDiskID : 12; + U16 rsv4 : 2; + U16 abortCtrl : 2; + }; + U16 WD2; + }; +}DfifoWordCommon_s; + +typedef struct __attribute__((packed)) IODT_V1 { + union { + + struct __attribute__((packed)) { + union { + struct { + union { + struct { + U8 protocolType : 3; + U8 frameType : 3; + U8 iuSrc : 2; + }; + U8 byte0; + }; + + IoDmaCfg_u dmaCfg; + }; + U16 config; + }; + + + + + U16 cmdLen : 9; + U16 rsv0 : 7; + + union { + struct { + U32 taskDarID : 13; + U32 : 19; + }; + struct { + U32 dataBufLenDWAlign : 24; + + U32 rsvd0 : 1; + U32 cmdDir : 1; + U32 refTagEn : 1; + U32 appTagEn : 1; + U32 guardTagEn : 1; + U32 refTagInc : 1; + U32 rsv1 : 1; + U32 aborted : 1; + }; + }; + }; + U64 QW0; + }; + + + union { + struct __attribute__((packed)) { + DfifoWordCommon_s commonWord; + U16 rsv2 : 1; + U16 sataCtl : 1; + U16 rsv3 : 2; + U16 sasCtl : 1; + U16 sataByteBlock0 : 1; + U16 sataByteBlock1 : 1; + U16 rsv4 : 9; + }; + U64 QW1; + }; + + + union { + U64 dataBaseAddr; + U64 QW2; + }; + + + union { + U64 eedpBaseAddr; + U64 QW3; + }; + + + union { + + struct { + U64 cmdIUAddr; + U64 rsv9; + + U64 refTag : 32; + U64 appTag : 16; + U64 rsv10 : 16; + + U64 rsv11; + } A; + + union { + U8 cdb[32]; + SspTaskFrameIu_s taskIU; + SmpFrameIu_s smpIU; + } B; + + + struct { + U64 opCode : 8; + U64 rsv12 : 56; + + U64 lba : 48; + U64 rsv13 : 16; + + U64 refTag : 32; + U64 appTag : 16; + U64 rsv14 : 16; + + U64 rsv15; + } C; + + struct { + U32 ataCmd : 8; + U32 ataDev : 8; + U32 ataCtl : 8; + U32 ataIcc : 8; + U32 ataSecCnt : 16; + U32 ataFeature : 16; + + union { + struct { + U64 ataLba : 48; + U64 rsv16 : 16; + }; + struct { + U8 lba0; + U8 lba1; + U8 lba2; + U8 lba3; + U8 lba4; + U8 lba5; + }; + U8 lba[6]; + }; + + U32 ataAuxiliary; + U32 rsv17; + + U64 rsv18; + } D; + }; +} IODT_V1_s; + +enum { + CMD_LEN_THR = 32, + CMD_LEN_S = 7, + CMD_LEN_L = 11, +}; + +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_global_baseaddr.h b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_global_baseaddr.h new file mode 100644 index 0000000000000000000000000000000000000000..23e352b2c1c3b6519594e7976de35ccc4d0f7857 --- /dev/null +++ b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_global_baseaddr.h @@ -0,0 +1,8 @@ +#ifndef __S1861_GLOBAL_BASEADDR_REG_H__ +#define __S1861_GLOBAL_BASEADDR_REG_H__ +#define HIL_REG0_PS3_REGISTER_F_BASEADDR 0x24000000UL +#define HIL_REG0_PS3_REGISTER_F_SIZE 0x10000UL +#define HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR 0x24010000UL +#define HIL_REG0_PS3_REQUEST_QUEUE_SIZE 0x200UL +#define HIL_REG0_PS3_REGISTER_S_SIZE 0x1FE00UL +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_f_reg.h b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_f_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..a7f4a47bcce6d31979954cc185f756721d787312 --- /dev/null +++ b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_f_reg.h @@ -0,0 +1,1053 @@ +#ifndef __S1861_HIL_REG0_PS3_REGISTER_F_REG_H__ +#define __S1861_HIL_REG0_PS3_REGISTER_F_REG_H__ +#include "s1861_global_baseaddr.h" +#ifndef __S1861_HIL_REG0_PS3_REGISTER_F_REG_MACRO__ +#define HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x40) +#define HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x48) +#define HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x50) +#define HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_IRQ_CONTROL_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x58) +#define HIL_REG0_PS3_REGISTER_F_PS3_IRQ_CONTROL_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x100) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_STATE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x108) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_STATE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x110) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x118) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x120) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_SHIFT_REG_LOW_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x128) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_SHIFT_REG_LOW_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_SHIFT_REG_HIGH_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x130) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_SHIFT_REG_HIGH_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_TIME_CNT_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x138) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_TIME_CNT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_TIME_OUT_EN_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x140) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_TIME_OUT_EN_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x200) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_STATE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x208) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_STATE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x210) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_SHIFT_REG_LOW_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x218) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_SHIFT_REG_LOW_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_SHIFT_REG_HIGH_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x220) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_SHIFT_REG_HIGH_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_TIME_CNT_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x228) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_TIME_CNT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_TIME_OUT_EN_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x230) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_TIME_OUT_EN_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_KEY_GAP_CFG_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x238) +#define HIL_REG0_PS3_REGISTER_F_PS3_KEY_GAP_CFG_RST (0x0000000002FAF080) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x240) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x248) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_IRQ_MASK_RST (0x0000000000000001) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOC_FW_STATE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x300) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOC_FW_STATE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_FW_CMD_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x308) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_FW_CMD_RST (0x0000000000001FFF) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_CHAIN_SIZE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x310) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_CHAIN_SIZE_RST (0x0000000000000FFF) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_VD_INFO_SIZE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x318) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_VD_INFO_SIZE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_NVME_PAGE_SIZE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x320) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_NVME_PAGE_SIZE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_FEATURE_SUPPORT_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x328) +#define HIL_REG0_PS3_REGISTER_F_PS3_FEATURE_SUPPORT_RST (0x0000000000000007) +#define HIL_REG0_PS3_REGISTER_F_PS3_FIRMWARE_VERSION_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x330) +#define HIL_REG0_PS3_REGISTER_F_PS3_FIRMWARE_VERSION_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_REPLYQUE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x338) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_REPLYQUE_RST (0x000000000000007F) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDWARE_VERSION_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x340) +#define HIL_REG0_PS3_REGISTER_F_PS3_HARDWARE_VERSION_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_MGR_QUEUE_DEPTH_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x348) +#define HIL_REG0_PS3_REGISTER_F_PS3_MGR_QUEUE_DEPTH_RST (0x0000000000000400) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_QUEUE_DEPTH_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x350) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_QUEUE_DEPTH_RST (0x0000000000001000) +#define HIL_REG0_PS3_REGISTER_F_PS3_TFIFO_DEPTH_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x358) +#define HIL_REG0_PS3_REGISTER_F_PS3_TFIFO_DEPTH_RST (0x0000000000000400) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_SEC_R1X_CMDS_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x360) +#define HIL_REG0_PS3_REGISTER_F_PS3_MAX_SEC_R1X_CMDS_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT0_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x400) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT0_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT1_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x408) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT1_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT2_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x410) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT2_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT3_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x418) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT3_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT_ALL_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x420) +#define HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT_ALL_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_IRQ_STATUS_RPT_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x440) +#define HIL_REG0_PS3_REGISTER_F_PS3_IRQ_STATUS_RPT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x500) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x508) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x510) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_STATUS_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x518) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_STATUS_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_DATA_SIZE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x520) +#define HIL_REG0_PS3_REGISTER_F_PS3_DUMP_DATA_SIZE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x600) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x608) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x610) +#define HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_COUNTER_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x618) +#define HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_COUNTER_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_REG_CMD_STATE_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x620) +#define HIL_REG0_PS3_REGISTER_F_PS3_REG_CMD_STATE_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x628) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x630) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x638) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x640) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x648) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x650) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x658) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x660) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x668) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x670) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x678) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x680) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x688) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x690) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x698) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_IRQ_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG5_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6a0) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG5_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG6_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6a8) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG6_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG7_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6b0) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG7_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG8_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6b8) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG8_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG9_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6c0) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG9_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG10_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6c8) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG10_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG11_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6d0) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG11_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG12_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x6d8) +#define HIL_REG0_PS3_REGISTER_F_PS3_DEBUG12_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x700) +#define HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_RST (0xFFFFFFFFFFFFFFFF) +#define HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_IRQ_CLEAR_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x708) +#define HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_IRQ_CLEAR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_IRQ_MASK_ADDR (HIL_REG0_PS3_REGISTER_F_BASEADDR + 0x710) +#define HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_IRQ_MASK_RST (0x0000000000000000) +#endif + +#ifndef __S1861_HIL_REG0_PS3_REGISTER_F_REG_STRUCT__ +typedef union HilReg0Ps3RegisterFPs3Doorbell{ + + volatile U64 val; + struct{ + + U64 cmd : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3Doorbell_u; + +typedef union HilReg0Ps3RegisterFPs3DoorbellIrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3DoorbellIrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3DoorbellIrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3DoorbellIrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3IrqControl{ + + volatile U64 val; + struct{ + + U64 global : 1; + U64 fwState : 1; + U64 tbd : 30; + U64 reserved3 : 32; + }reg; +}HilReg0Ps3RegisterFPs3IrqControl_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetKey{ + + volatile U64 val; + struct{ + + U64 ps3SoftresetKey : 8; + U64 reserved1 : 56; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetKey_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetState{ + + volatile U64 val; + struct{ + + U64 rpt : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetState_u; + +typedef union HilReg0Ps3RegisterFPs3Softreset{ + + volatile U64 val; + struct{ + + U64 cmd : 8; + U64 reserved1 : 56; + }reg; +}HilReg0Ps3RegisterFPs3Softreset_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetIrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetIrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetIrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetIrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetKeyShiftRegLow{ + + volatile U64 val; + struct{ + + U64 rpt : 64; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetKeyShiftRegLow_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetKeyShiftRegHigh{ + + volatile U64 val; + struct{ + + U64 rpt : 8; + U64 reserved1 : 56; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetKeyShiftRegHigh_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetTimeCnt{ + + volatile U64 val; + struct{ + + U64 rpt : 64; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetTimeCnt_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetTimeOutEn{ + + volatile U64 val; + struct{ + + U64 rpt : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetTimeOutEn_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetKey{ + + volatile U64 val; + struct{ + + U64 ps3HardresetKey : 8; + U64 reserved1 : 56; + }reg; +}HilReg0Ps3RegisterFPs3HardresetKey_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetState{ + + volatile U64 val; + struct{ + + U64 rpt : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3HardresetState_u; + +typedef union HilReg0Ps3RegisterFPs3Hardreset{ + + volatile U64 val; + struct{ + + U64 config : 8; + U64 reserved1 : 56; + }reg; +}HilReg0Ps3RegisterFPs3Hardreset_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetKeyShiftRegLow{ + + volatile U64 val; + struct{ + + U64 rpt : 64; + }reg; +}HilReg0Ps3RegisterFPs3HardresetKeyShiftRegLow_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetKeyShiftRegHigh{ + + volatile U64 val; + struct{ + + U64 rpt : 8; + U64 reserved1 : 56; + }reg; +}HilReg0Ps3RegisterFPs3HardresetKeyShiftRegHigh_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetTimeCnt{ + + volatile U64 val; + struct{ + + U64 rpt : 64; + }reg; +}HilReg0Ps3RegisterFPs3HardresetTimeCnt_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetTimeOutEn{ + + volatile U64 val; + struct{ + + U64 rpt : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3HardresetTimeOutEn_u; + +typedef union HilReg0Ps3RegisterFPs3KeyGapCfg{ + + volatile U64 val; + struct{ + + U64 ps3KeyGapCfg : 64; + }reg; +}HilReg0Ps3RegisterFPs3KeyGapCfg_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetIrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3HardresetIrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3HardresetIrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3HardresetIrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3SocFwState{ + + volatile U64 val; + struct{ + + U64 ps3SocFwState : 8; + U64 ps3SocFwStartState : 8; + U64 ps3SocBootState : 8; + U64 tbd : 8; + U64 reserved4 : 32; + }reg; +}HilReg0Ps3RegisterFPs3SocFwState_u; + +typedef union HilReg0Ps3RegisterFPs3MaxFwCmd{ + + volatile U64 val; + struct{ + + U64 ps3MaxFwCmd : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3MaxFwCmd_u; + +typedef union HilReg0Ps3RegisterFPs3MaxChainSize{ + + volatile U64 val; + struct{ + + U64 ps3MaxChainSize : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3MaxChainSize_u; + +typedef union HilReg0Ps3RegisterFPs3MaxVdInfoSize{ + + volatile U64 val; + struct{ + + U64 ps3MaxVdInfoSize : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3MaxVdInfoSize_u; + +typedef union HilReg0Ps3RegisterFPs3MaxNvmePageSize{ + + volatile U64 val; + struct{ + + U64 ps3MaxNvmePageSize : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3MaxNvmePageSize_u; + +typedef union HilReg0Ps3RegisterFPs3FeatureSupport{ + + volatile U64 val; + struct{ + + U64 multiDevfnSupport : 1; + U64 dmaBit64Support : 1; + U64 debugOcmSupport : 1; + U64 tbd1 : 13; + U64 fwHaltSupport : 1; + U64 sglModeSupport : 1; + U64 dumpCrashSupport : 1; + U64 shallowSoftRecoverySupport : 1; + U64 deepSoftRecoverySupport : 1; + U64 hardRecoverySupport : 1; + U64 tbd2 : 42; + }reg; +}HilReg0Ps3RegisterFPs3FeatureSupport_u; + +typedef union HilReg0Ps3RegisterFPs3FirmwareVersion{ + + volatile U64 val; + struct{ + + U64 ps3FmVer : 8; + U64 tbd : 24; + U64 reserved2 : 32; + }reg; +}HilReg0Ps3RegisterFPs3FirmwareVersion_u; + +typedef union HilReg0Ps3RegisterFPs3MaxReplyque{ + + volatile U64 val; + struct{ + + U64 ps3MaxReplyque : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3MaxReplyque_u; + +typedef union HilReg0Ps3RegisterFPs3HardwareVersion{ + + volatile U64 val; + struct{ + + U64 chipId : 64; + }reg; +}HilReg0Ps3RegisterFPs3HardwareVersion_u; + +typedef union HilReg0Ps3RegisterFPs3MgrQueueDepth{ + + volatile U64 val; + struct{ + + U64 ps3MgrQueueDepth : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3MgrQueueDepth_u; + +typedef union HilReg0Ps3RegisterFPs3CmdQueueDepth{ + + volatile U64 val; + struct{ + + U64 ps3CmdQueueDepth : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3CmdQueueDepth_u; + +typedef union HilReg0Ps3RegisterFPs3TfifoDepth{ + + volatile U64 val; + struct{ + + U64 ps3TfifoDepth : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3TfifoDepth_u; + +typedef union HilReg0Ps3RegisterFPs3MaxSecR1xCmds{ + + volatile U64 val; + struct{ + + U64 ps3MaxSecR1xCmds : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3MaxSecR1xCmds_u; + +typedef union HilReg0Ps3RegisterFPs3HilAdvice2directCnt0{ + + volatile U64 val; + struct{ + + U64 rpt : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3HilAdvice2directCnt0_u; + +typedef union HilReg0Ps3RegisterFPs3HilAdvice2directCnt1{ + + volatile U64 val; + struct{ + + U64 rpt : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3HilAdvice2directCnt1_u; + +typedef union HilReg0Ps3RegisterFPs3HilAdvice2directCnt2{ + + volatile U64 val; + struct{ + + U64 rpt : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3HilAdvice2directCnt2_u; + +typedef union HilReg0Ps3RegisterFPs3HilAdvice2directCnt3{ + + volatile U64 val; + struct{ + + U64 rpt : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3HilAdvice2directCnt3_u; + +typedef union HilReg0Ps3RegisterFPs3HilAdvice2directCntAll{ + + volatile U64 val; + struct{ + + U64 rpt : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3HilAdvice2directCntAll_u; + +typedef union HilReg0Ps3RegisterFPs3IrqStatusRpt{ + + volatile U64 val; + struct{ + + U64 doorbell : 1; + U64 reserved1 : 3; + U64 softreset : 1; + U64 reserved3 : 3; + U64 dumpCtrl : 1; + U64 reserved5 : 3; + U64 debug0 : 1; + U64 reserved7 : 3; + U64 debug1 : 1; + U64 reserved9 : 3; + U64 debug2 : 1; + U64 reserved11 : 3; + U64 debug3 : 1; + U64 reserved13 : 3; + U64 debug4 : 1; + U64 reserved15 : 3; + U64 cmdTrigger : 1; + U64 reserved17 : 3; + U64 hardreset : 1; + U64 reserved19 : 3; + U64 sessioncmdAddr : 1; + U64 reserved21 : 23; + }reg; +}HilReg0Ps3RegisterFPs3IrqStatusRpt_u; + +typedef union HilReg0Ps3RegisterFPs3DumpCtrl{ + + volatile U64 val; + struct{ + + U64 cmd : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RegisterFPs3DumpCtrl_u; + +typedef union HilReg0Ps3RegisterFPs3DumpCtrlIrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3DumpCtrlIrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3DumpCtrlIrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3DumpCtrlIrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3DumpStatus{ + + volatile U64 val; + struct{ + + U64 dmaFinish : 1; + U64 hasCrashDump : 1; + U64 hasFwDump : 1; + U64 hasBarDump : 1; + U64 hasAutoDump : 2; + U64 tbd : 10; + U64 reserved6 : 48; + }reg; +}HilReg0Ps3RegisterFPs3DumpStatus_u; + +typedef union HilReg0Ps3RegisterFPs3DumpDataSize{ + + volatile U64 val; + struct{ + + U64 ps3DumpDataSize : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RegisterFPs3DumpDataSize_u; + +typedef union HilReg0Ps3RegisterFPs3CmdTrigger{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3CmdTrigger_u; + +typedef union HilReg0Ps3RegisterFPs3CmdTriggerIrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3CmdTriggerIrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3CmdTriggerIrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3CmdTriggerIrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3SoftresetCounter{ + + volatile U64 val; + struct{ + + U64 rpt : 32; + U64 tbd : 32; + }reg; +}HilReg0Ps3RegisterFPs3SoftresetCounter_u; + +typedef union HilReg0Ps3RegisterFPs3RegCmdState{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3RegCmdState_u; + +typedef union HilReg0Ps3RegisterFPs3Debug0{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug0_u; + +typedef union HilReg0Ps3RegisterFPs3Debug0IrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug0IrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3Debug0IrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug0IrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3Debug1{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug1_u; + +typedef union HilReg0Ps3RegisterFPs3Debug1IrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug1IrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3Debug1IrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug1IrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3Debug2{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug2_u; + +typedef union HilReg0Ps3RegisterFPs3Debug2IrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug2IrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3Debug2IrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug2IrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3Debug3{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug3_u; + +typedef union HilReg0Ps3RegisterFPs3Debug3IrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug3IrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3Debug3IrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug3IrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3Debug4{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug4_u; + +typedef union HilReg0Ps3RegisterFPs3Debug4IrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug4IrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3Debug4IrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3Debug4IrqMask_u; + +typedef union HilReg0Ps3RegisterFPs3Debug5{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug5_u; + +typedef union HilReg0Ps3RegisterFPs3Debug6{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug6_u; + +typedef union HilReg0Ps3RegisterFPs3Debug7{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug7_u; + +typedef union HilReg0Ps3RegisterFPs3Debug8{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug8_u; + +typedef union HilReg0Ps3RegisterFPs3Debug9{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug9_u; + +typedef union HilReg0Ps3RegisterFPs3Debug10{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug10_u; + +typedef union HilReg0Ps3RegisterFPs3Debug11{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug11_u; + +typedef union HilReg0Ps3RegisterFPs3Debug12{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3Debug12_u; + +typedef union HilReg0Ps3RegisterFPs3SessioncmdAddr{ + + volatile U64 val; + struct{ + + U64 cmd : 64; + }reg; +}HilReg0Ps3RegisterFPs3SessioncmdAddr_u; + +typedef union HilReg0Ps3RegisterFPs3SessioncmdAddrIrqClear{ + + volatile U64 val; + struct{ + + U64 pulse : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3SessioncmdAddrIrqClear_u; + +typedef union HilReg0Ps3RegisterFPs3SessioncmdAddrIrqMask{ + + volatile U64 val; + struct{ + + U64 level : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterFPs3SessioncmdAddrIrqMask_u; + +typedef struct HilReg0Ps3RegisterF{ + + U64 reserved0[8]; + HilReg0Ps3RegisterFPs3Doorbell_u ps3Doorbell; + HilReg0Ps3RegisterFPs3DoorbellIrqClear_u ps3DoorbellIrqClear; + HilReg0Ps3RegisterFPs3DoorbellIrqMask_u ps3DoorbellIrqMask; + HilReg0Ps3RegisterFPs3IrqControl_u ps3IrqControl; + U64 reserved1[20]; + HilReg0Ps3RegisterFPs3SoftresetKey_u ps3SoftresetKey; + HilReg0Ps3RegisterFPs3SoftresetState_u ps3SoftresetState; + HilReg0Ps3RegisterFPs3Softreset_u ps3Softreset; + HilReg0Ps3RegisterFPs3SoftresetIrqClear_u ps3SoftresetIrqClear; + HilReg0Ps3RegisterFPs3SoftresetIrqMask_u ps3SoftresetIrqMask; + HilReg0Ps3RegisterFPs3SoftresetKeyShiftRegLow_u ps3SoftresetKeyShiftRegLow; + HilReg0Ps3RegisterFPs3SoftresetKeyShiftRegHigh_u ps3SoftresetKeyShiftRegHigh; + HilReg0Ps3RegisterFPs3SoftresetTimeCnt_u ps3SoftresetTimeCnt; + HilReg0Ps3RegisterFPs3SoftresetTimeOutEn_u ps3SoftresetTimeOutEn; + U64 reserved2[23]; + HilReg0Ps3RegisterFPs3HardresetKey_u ps3HardresetKey; + HilReg0Ps3RegisterFPs3HardresetState_u ps3HardresetState; + HilReg0Ps3RegisterFPs3Hardreset_u ps3Hardreset; + HilReg0Ps3RegisterFPs3HardresetKeyShiftRegLow_u ps3HardresetKeyShiftRegLow; + HilReg0Ps3RegisterFPs3HardresetKeyShiftRegHigh_u ps3HardresetKeyShiftRegHigh; + HilReg0Ps3RegisterFPs3HardresetTimeCnt_u ps3HardresetTimeCnt; + HilReg0Ps3RegisterFPs3HardresetTimeOutEn_u ps3HardresetTimeOutEn; + HilReg0Ps3RegisterFPs3KeyGapCfg_u ps3KeyGapCfg; + HilReg0Ps3RegisterFPs3HardresetIrqClear_u ps3HardresetIrqClear; + HilReg0Ps3RegisterFPs3HardresetIrqMask_u ps3HardresetIrqMask; + U64 reserved3[22]; + HilReg0Ps3RegisterFPs3SocFwState_u ps3SocFwState; + HilReg0Ps3RegisterFPs3MaxFwCmd_u ps3MaxFwCmd; + HilReg0Ps3RegisterFPs3MaxChainSize_u ps3MaxChainSize; + HilReg0Ps3RegisterFPs3MaxVdInfoSize_u ps3MaxVdInfoSize; + HilReg0Ps3RegisterFPs3MaxNvmePageSize_u ps3MaxNvmePageSize; + HilReg0Ps3RegisterFPs3FeatureSupport_u ps3FeatureSupport; + HilReg0Ps3RegisterFPs3FirmwareVersion_u ps3FirmwareVersion; + HilReg0Ps3RegisterFPs3MaxReplyque_u ps3MaxReplyque; + HilReg0Ps3RegisterFPs3HardwareVersion_u ps3HardwareVersion; + HilReg0Ps3RegisterFPs3MgrQueueDepth_u ps3MgrQueueDepth; + HilReg0Ps3RegisterFPs3CmdQueueDepth_u ps3CmdQueueDepth; + HilReg0Ps3RegisterFPs3TfifoDepth_u ps3TfifoDepth; + HilReg0Ps3RegisterFPs3MaxSecR1xCmds_u ps3MaxSecR1xCmds; + U64 reserved4[19]; + HilReg0Ps3RegisterFPs3HilAdvice2directCnt0_u ps3HilAdvice2directCnt0; + HilReg0Ps3RegisterFPs3HilAdvice2directCnt1_u ps3HilAdvice2directCnt1; + HilReg0Ps3RegisterFPs3HilAdvice2directCnt2_u ps3HilAdvice2directCnt2; + HilReg0Ps3RegisterFPs3HilAdvice2directCnt3_u ps3HilAdvice2directCnt3; + HilReg0Ps3RegisterFPs3HilAdvice2directCntAll_u ps3HilAdvice2directCntAll; + U64 reserved5[3]; + HilReg0Ps3RegisterFPs3IrqStatusRpt_u ps3IrqStatusRpt; + U64 reserved6[23]; + HilReg0Ps3RegisterFPs3DumpCtrl_u ps3DumpCtrl; + HilReg0Ps3RegisterFPs3DumpCtrlIrqClear_u ps3DumpCtrlIrqClear; + HilReg0Ps3RegisterFPs3DumpCtrlIrqMask_u ps3DumpCtrlIrqMask; + HilReg0Ps3RegisterFPs3DumpStatus_u ps3DumpStatus; + HilReg0Ps3RegisterFPs3DumpDataSize_u ps3DumpDataSize; + U64 reserved7[27]; + HilReg0Ps3RegisterFPs3CmdTrigger_u ps3CmdTrigger; + HilReg0Ps3RegisterFPs3CmdTriggerIrqClear_u ps3CmdTriggerIrqClear; + HilReg0Ps3RegisterFPs3CmdTriggerIrqMask_u ps3CmdTriggerIrqMask; + HilReg0Ps3RegisterFPs3SoftresetCounter_u ps3SoftresetCounter; + HilReg0Ps3RegisterFPs3RegCmdState_u ps3RegCmdState; + HilReg0Ps3RegisterFPs3Debug0_u ps3Debug0; + HilReg0Ps3RegisterFPs3Debug0IrqClear_u ps3Debug0IrqClear; + HilReg0Ps3RegisterFPs3Debug0IrqMask_u ps3Debug0IrqMask; + HilReg0Ps3RegisterFPs3Debug1_u ps3Debug1; + HilReg0Ps3RegisterFPs3Debug1IrqClear_u ps3Debug1IrqClear; + HilReg0Ps3RegisterFPs3Debug1IrqMask_u ps3Debug1IrqMask; + HilReg0Ps3RegisterFPs3Debug2_u ps3Debug2; + HilReg0Ps3RegisterFPs3Debug2IrqClear_u ps3Debug2IrqClear; + HilReg0Ps3RegisterFPs3Debug2IrqMask_u ps3Debug2IrqMask; + HilReg0Ps3RegisterFPs3Debug3_u ps3Debug3; + HilReg0Ps3RegisterFPs3Debug3IrqClear_u ps3Debug3IrqClear; + HilReg0Ps3RegisterFPs3Debug3IrqMask_u ps3Debug3IrqMask; + HilReg0Ps3RegisterFPs3Debug4_u ps3Debug4; + HilReg0Ps3RegisterFPs3Debug4IrqClear_u ps3Debug4IrqClear; + HilReg0Ps3RegisterFPs3Debug4IrqMask_u ps3Debug4IrqMask; + HilReg0Ps3RegisterFPs3Debug5_u ps3Debug5; + HilReg0Ps3RegisterFPs3Debug6_u ps3Debug6; + HilReg0Ps3RegisterFPs3Debug7_u ps3Debug7; + HilReg0Ps3RegisterFPs3Debug8_u ps3Debug8; + HilReg0Ps3RegisterFPs3Debug9_u ps3Debug9; + HilReg0Ps3RegisterFPs3Debug10_u ps3Debug10; + HilReg0Ps3RegisterFPs3Debug11_u ps3Debug11; + HilReg0Ps3RegisterFPs3Debug12_u ps3Debug12; + U64 reserved8[4]; + HilReg0Ps3RegisterFPs3SessioncmdAddr_u ps3SessioncmdAddr; + HilReg0Ps3RegisterFPs3SessioncmdAddrIrqClear_u ps3SessioncmdAddrIrqClear; + HilReg0Ps3RegisterFPs3SessioncmdAddrIrqMask_u ps3SessioncmdAddrIrqMask; +}HilReg0Ps3RegisterF_s; +#endif +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_s_reg.h b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_s_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..e8593293b75475124e35091cd0b0a4e172ac32b6 --- /dev/null +++ b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_s_reg.h @@ -0,0 +1,38 @@ +#ifndef __S1861_HIL_REG0_PS3_REGISTER_S_REG_H__ +#define __S1861_HIL_REG0_PS3_REGISTER_S_REG_H__ +#include "s1861_global_baseaddr.h" +#ifndef __S1861_HIL_REG0_PS3_REGISTER_S_REG_MACRO__ +#define HIL_REG0_PS3_REGISTER_S_PS3_FUCNTION_LOCK_ADDR (HIL_REG0_PS3_REGISTER_S_BASEADDR + 0x0) +#define HIL_REG0_PS3_REGISTER_S_PS3_FUCNTION_LOCK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REGISTER_S_PS3_FUNCTION_LOCK_OWNER_ADDR (HIL_REG0_PS3_REGISTER_S_BASEADDR + 0x8) +#define HIL_REG0_PS3_REGISTER_S_PS3_FUNCTION_LOCK_OWNER_RST (0x0000000000000003) +#endif + +#ifndef __S1861_HIL_REG0_PS3_REGISTER_S_REG_STRUCT__ +typedef union HilReg0Ps3RegisterSPs3FucntionLock{ + + volatile U64 val; + struct{ + + U64 lock : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RegisterSPs3FucntionLock_u; + +typedef union HilReg0Ps3RegisterSPs3FunctionLockOwner{ + + volatile U64 val; + struct{ + + U64 display : 2; + U64 reserved1 : 62; + }reg; +}HilReg0Ps3RegisterSPs3FunctionLockOwner_u; + +typedef struct HilReg0Ps3RegisterS{ + + HilReg0Ps3RegisterSPs3FucntionLock_u ps3FucntionLock; + HilReg0Ps3RegisterSPs3FunctionLockOwner_u ps3FunctionLockOwner; +}HilReg0Ps3RegisterS_s; +#endif +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_request_queue_reg.h b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_request_queue_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..688575a7ec4e42c7d2b308888581709de11622e7 --- /dev/null +++ b/drivers/scsi/ps3stor/include/hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_request_queue_reg.h @@ -0,0 +1,420 @@ +#ifndef __S1861_HIL_REG0_PS3_REQUEST_QUEUE_REG_H__ +#define __S1861_HIL_REG0_PS3_REQUEST_QUEUE_REG_H__ +#include "s1861_global_baseaddr.h" +#ifndef __S1861_HIL_REG0_PS3_REQUEST_QUEUE_REG_MACRO__ +#define HIL_REG0_PS3_REQUEST_QUEUE_PS3_REQUEST_QUEUE_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x0) +#define HIL_REG0_PS3_REQUEST_QUEUE_PS3_REQUEST_QUEUE_RST (0xFFFFFFFFFFFFFFFF) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOERRCNT_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOERRCNT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x10) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_RST (0x0000000C1FFF0000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELCONFIG_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x18) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELCONFIG_RST (0x0000000300000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFORST_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x20) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFORST_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOIOCNT_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x28) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOIOCNT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOFLOWCNT_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x30) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOFLOWCNT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_STATUS_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x38) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_STATUS_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_SET_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x40) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_SET_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_CLR_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x48) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_CLR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_MASK_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x50) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_INT_MASK_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_CNT_CLR_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x58) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_CNT_CLR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOORDERERROR_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x60) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOORDERERROR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFODINSHIFT_ADDR(_n) (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x68 + (_n)*0x8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFODINSHIFT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFODOUTSHIFT_ADDR(_n) (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x88 + (_n)*0x8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFODOUTSHIFT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_MAXLEVEL_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xa8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_MAXLEVEL_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOINIT_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xb0) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOINIT_RST (0x0000000000000002) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOINIT_EN_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xb8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOINIT_EN_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOINIT_MAX_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xc0) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOINIT_MAX_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_ECC_CNT_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xc8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_ECC_CNT_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_ECC_ADDR_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xd0) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOSTATUS_ECC_ADDR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_DECODER_OVERFLOW_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xd8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_DECODER_OVERFLOW_RST (0x000000000000003F) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_ECC_BAD_PROJECT_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xe0) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFO_ECC_BAD_PROJECT_RST (0x0000000000000001) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOOVERFLOW_WORD_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xe8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOOVERFLOW_WORD_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORCTL_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xf0) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORCTL_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORCNTCLR_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0xf8) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORCNTCLR_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORLOW_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x100) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORLOW_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORMID_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x108) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORMID_RST (0x0000000000000000) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORHIGH_ADDR (HIL_REG0_PS3_REQUEST_QUEUE_BASEADDR + 0x110) +#define HIL_REG0_PS3_REQUEST_QUEUE_FIFOLEVELMONITORHIGH_RST (0x0000000000000000) +#endif + +#ifndef __S1861_HIL_REG0_PS3_REQUEST_QUEUE_REG_STRUCT__ +typedef union HilReg0Ps3RequestQueuePs3RequestQueue{ + + volatile U64 val; + struct{ + + U64 port : 64; + }reg; +}HilReg0Ps3RequestQueuePs3RequestQueue_u; + +typedef union HilReg0Ps3RequestQueueFifoErrCnt{ + + volatile U64 val; + struct{ + + U64 waddrerr : 32; + U64 reserved1 : 32; + }reg; +}HilReg0Ps3RequestQueueFifoErrCnt_u; + +typedef union HilReg0Ps3RequestQueueFifoStatus{ + + volatile U64 val; + struct{ + + U64 filled : 16; + U64 fifoDepth : 16; + U64 almostfull : 1; + U64 full : 1; + U64 almostempty : 1; + U64 empty : 1; + U64 reserved6 : 28; + }reg; +}HilReg0Ps3RequestQueueFifoStatus_u; + +typedef union HilReg0Ps3RequestQueueFifoLevelConfig{ + + volatile U64 val; + struct{ + + U64 cfgAempty : 16; + U64 cfgAfull : 16; + U64 emptyProtect : 1; + U64 fullProtect : 1; + U64 reserved4 : 30; + }reg; +}HilReg0Ps3RequestQueueFifoLevelConfig_u; + +typedef union HilReg0Ps3RequestQueueFifoRst{ + + volatile U64 val; + struct{ + + U64 resetPls : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RequestQueueFifoRst_u; + +typedef union HilReg0Ps3RequestQueueFifoIOCnt{ + + volatile U64 val; + struct{ + + U64 wr : 32; + U64 rd : 32; + }reg; +}HilReg0Ps3RequestQueueFifoIOCnt_u; + +typedef union HilReg0Ps3RequestQueueFifoFlowCnt{ + + volatile U64 val; + struct{ + + U64 overflow : 32; + U64 underflow : 32; + }reg; +}HilReg0Ps3RequestQueueFifoFlowCnt_u; + +typedef union HilReg0Ps3RequestQueueFifoIntStatus{ + + volatile U64 val; + struct{ + + U64 overflowStatus : 1; + U64 underflowStatus : 1; + U64 nemptyStatus : 1; + U64 eccBadStatus : 1; + U64 reserved4 : 60; + }reg; +}HilReg0Ps3RequestQueueFifoIntStatus_u; + +typedef union HilReg0Ps3RequestQueueFifoIntSet{ + + volatile U64 val; + struct{ + + U64 overflowSet : 1; + U64 underflowSet : 1; + U64 nemptySet : 1; + U64 eccBadSet : 1; + U64 reserved4 : 60; + }reg; +}HilReg0Ps3RequestQueueFifoIntSet_u; + +typedef union HilReg0Ps3RequestQueueFifoIntClr{ + + volatile U64 val; + struct{ + + U64 overflowClr : 1; + U64 underflowClr : 1; + U64 nemptyClr : 1; + U64 eccBadClr : 1; + U64 reserved4 : 60; + }reg; +}HilReg0Ps3RequestQueueFifoIntClr_u; + +typedef union HilReg0Ps3RequestQueueFifoIntMask{ + + volatile U64 val; + struct{ + + U64 overflowMask : 1; + U64 underflowMask : 1; + U64 nemptyMask : 1; + U64 eccBadMask : 1; + U64 reserved4 : 60; + }reg; +}HilReg0Ps3RequestQueueFifoIntMask_u; + +typedef union HilReg0Ps3RequestQueueFifoCntClr{ + + volatile U64 val; + struct{ + + U64 fifowrcntClr : 1; + U64 fifordcntClr : 1; + U64 fifoerrcntClr : 1; + U64 fifoordererrwrcntClr : 1; + U64 fifoordererrrdcntClr : 1; + U64 fifobit1errcntClr : 1; + U64 fifobit2errcntClr : 1; + U64 reserved7 : 57; + }reg; +}HilReg0Ps3RequestQueueFifoCntClr_u; + +typedef union HilReg0Ps3RequestQueueFifoOrderError{ + + volatile U64 val; + struct{ + + U64 wrcnt : 32; + U64 rdcnt : 32; + }reg; +}HilReg0Ps3RequestQueueFifoOrderError_u; + +typedef union HilReg0Ps3RequestQueueFifoDinShift{ + + volatile U64 val; + struct{ + + U64 val : 64; + }reg; +}HilReg0Ps3RequestQueueFifoDinShift_u; + +typedef union HilReg0Ps3RequestQueueFifoDoutShift{ + + volatile U64 val; + struct{ + + U64 val : 64; + }reg; +}HilReg0Ps3RequestQueueFifoDoutShift_u; + +typedef union HilReg0Ps3RequestQueueFifostatusMaxlevel{ + + volatile U64 val; + struct{ + + U64 val : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RequestQueueFifostatusMaxlevel_u; + +typedef union HilReg0Ps3RequestQueueFifoInit{ + + volatile U64 val; + struct{ + + U64 stat : 2; + U64 reserved1 : 62; + }reg; +}HilReg0Ps3RequestQueueFifoInit_u; + +typedef union HilReg0Ps3RequestQueueFifoinitEn{ + + volatile U64 val; + struct{ + + U64 start : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RequestQueueFifoinitEn_u; + +typedef union HilReg0Ps3RequestQueueFifoinitMax{ + + volatile U64 val; + struct{ + + U64 num : 16; + U64 reserved1 : 48; + }reg; +}HilReg0Ps3RequestQueueFifoinitMax_u; + +typedef union HilReg0Ps3RequestQueueFifostatusEccCnt{ + + volatile U64 val; + struct{ + + U64 bit1Err : 32; + U64 bit2Err : 32; + }reg; +}HilReg0Ps3RequestQueueFifostatusEccCnt_u; + +typedef union HilReg0Ps3RequestQueueFifostatusEccAddr{ + + volatile U64 val; + struct{ + + U64 errPoint : 64; + }reg; +}HilReg0Ps3RequestQueueFifostatusEccAddr_u; + +typedef union HilReg0Ps3RequestQueueFifoDecoderOverflow{ + + volatile U64 val; + struct{ + + U64 rCmdwordEmpty : 1; + U64 rPortindexEmpty : 1; + U64 rCmdbackEmpty : 1; + U64 wCmdwordEmpty : 1; + U64 wPortindexEmpty : 1; + U64 wCmdbackEmpty : 1; + U64 rCmdwordFull : 1; + U64 rPortindexFull : 1; + U64 rCmdbackFull : 1; + U64 wCmdwordFull : 1; + U64 wPortindexFull : 1; + U64 wCmdbackFull : 1; + U64 reserved12 : 52; + }reg; +}HilReg0Ps3RequestQueueFifoDecoderOverflow_u; + +typedef union HilReg0Ps3RequestQueueFifoEccBadProject{ + + volatile U64 val; + struct{ + + U64 en : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RequestQueueFifoEccBadProject_u; + +typedef union HilReg0Ps3RequestQueueFifooverflowWord{ + + volatile U64 val; + struct{ + + U64 record : 64; + }reg; +}HilReg0Ps3RequestQueueFifooverflowWord_u; + +typedef union HilReg0Ps3RequestQueueFifoLevelMonitorCtl{ + + volatile U64 val; + struct{ + + U64 low : 16; + U64 high : 16; + U64 en : 1; + U64 reserved3 : 31; + }reg; +}HilReg0Ps3RequestQueueFifoLevelMonitorCtl_u; + +typedef union HilReg0Ps3RequestQueueFifoLevelMonitorCntClr{ + + volatile U64 val; + struct{ + + U64 en : 1; + U64 reserved1 : 63; + }reg; +}HilReg0Ps3RequestQueueFifoLevelMonitorCntClr_u; + +typedef union HilReg0Ps3RequestQueueFifoLevelMonitorLow{ + + volatile U64 val; + struct{ + + U64 cnt : 64; + }reg; +}HilReg0Ps3RequestQueueFifoLevelMonitorLow_u; + +typedef union HilReg0Ps3RequestQueueFifoLevelMonitorMid{ + + volatile U64 val; + struct{ + + U64 cnt : 64; + }reg; +}HilReg0Ps3RequestQueueFifoLevelMonitorMid_u; + +typedef union HilReg0Ps3RequestQueueFifoLevelMonitorHigh{ + + volatile U64 val; + struct{ + + U64 cnt : 64; + }reg; +}HilReg0Ps3RequestQueueFifoLevelMonitorHigh_u; + +typedef struct HilReg0Ps3RequestQueue{ + + HilReg0Ps3RequestQueuePs3RequestQueue_u ps3RequestQueue; + HilReg0Ps3RequestQueueFifoErrCnt_u fifoErrCnt; + HilReg0Ps3RequestQueueFifoStatus_u fifoStatus; + HilReg0Ps3RequestQueueFifoLevelConfig_u fifoLevelConfig; + HilReg0Ps3RequestQueueFifoRst_u fifoRst; + HilReg0Ps3RequestQueueFifoIOCnt_u fifoIOCnt; + HilReg0Ps3RequestQueueFifoFlowCnt_u fifoFlowCnt; + HilReg0Ps3RequestQueueFifoIntStatus_u fifoIntStatus; + HilReg0Ps3RequestQueueFifoIntSet_u fifoIntSet; + HilReg0Ps3RequestQueueFifoIntClr_u fifoIntClr; + HilReg0Ps3RequestQueueFifoIntMask_u fifoIntMask; + HilReg0Ps3RequestQueueFifoCntClr_u fifoCntClr; + HilReg0Ps3RequestQueueFifoOrderError_u fifoOrderError; + HilReg0Ps3RequestQueueFifoDinShift_u fifoDinShift[4]; + HilReg0Ps3RequestQueueFifoDoutShift_u fifoDoutShift[4]; + HilReg0Ps3RequestQueueFifostatusMaxlevel_u fifoStatusMaxLevel; + HilReg0Ps3RequestQueueFifoInit_u fifoInit; + HilReg0Ps3RequestQueueFifoinitEn_u fifoinitEn; + HilReg0Ps3RequestQueueFifoinitMax_u fifoinitMax; + HilReg0Ps3RequestQueueFifostatusEccCnt_u fifoStatusEccCnt; + HilReg0Ps3RequestQueueFifostatusEccAddr_u fifoStatusEccAddr; + HilReg0Ps3RequestQueueFifoDecoderOverflow_u fifoDecoderOverflow; + HilReg0Ps3RequestQueueFifoEccBadProject_u fifoEccBadProject; + HilReg0Ps3RequestQueueFifooverflowWord_u fifoOverFlowWord; + HilReg0Ps3RequestQueueFifoLevelMonitorCtl_u fifoLevelMonitorCtl; + HilReg0Ps3RequestQueueFifoLevelMonitorCntClr_u fifoLevelMonitorCntClr; + HilReg0Ps3RequestQueueFifoLevelMonitorLow_u fifoLevelMonitorLow; + HilReg0Ps3RequestQueueFifoLevelMonitorMid_u fifoLevelMonitorMid; + HilReg0Ps3RequestQueueFifoLevelMonitorHigh_u fifoLevelMonitorHigh; +}HilReg0Ps3RequestQueue_s; +#endif +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/include/ps3_define.h b/drivers/scsi/ps3stor/include/ps3_define.h new file mode 100644 index 0000000000000000000000000000000000000000..d53dfac46439db1e89ed4da64bcb7c18e4d5c4db --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_define.h @@ -0,0 +1,244 @@ + +#ifndef __PS3_DEFINE_H__ +#define __PS3_DEFINE_H__ + +#include "ps3_types.h" + +#define PS3_ASM __asm__ volatile + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef INVALID_U4 +#define INVALID_U4 0xF +#endif + +#ifndef INVALID_U8 +#define INVALID_U8 0xFF +#endif + +#ifndef INVALID_U16 +#define INVALID_U16 0xFFFF +#endif + +#ifndef INVALID_U16_1 +#define INVALID_U16_1 0xFFFE +#endif + +#ifndef INVALID_U16_2 +#define INVALID_U16_2 0xFFFD +#endif + +#ifndef INVALID_U32 +#define INVALID_U32 0xFFFFFFFF +#endif + +#ifndef INVALID_U64 +#define INVALID_U64 0xFFFFFFFFFFFFFFFF +#endif + +#ifdef __aarch64__ +#define __arm64__ +#endif + + +#ifndef INVALID_ULONG +#if defined (__arm64__) || defined (__x86_64__) +#define INVALID_ULONG 0xFFFFFFFFFFFFFFFF +#elif defined(__arm__) || defined (__i386__) +#define INVALID_ULONG 0xFFFFFFFF +#endif +#endif + +#ifndef INVALID_S8 +#define INVALID_S8 0xFF +#endif + +#ifndef INVALID_S16 +#define INVALID_S16 0xFFFF +#endif + +#ifndef INVALID_S32 +#define INVALID_S32 ((S32)(-1)) +#endif + +#ifndef INVALID_S64 +#define INVALID_S64 0xFFFFFFFFFFFFFFFF +#endif + +#ifndef INVALID_LONG +#if defined (__arm64__) || defined (__x86_64__) +#define INVALID_LONG 0xFFFFFFFFFFFFFFFF +#elif defined(__arm__) || defined (__i386__) +#define INVALID_LONG 0xFFFFFFFF +#endif +#endif + + +#ifndef MACRO_64_BIT +#if defined (__arm64__) || defined (__x86_64__) +#define MACRO_64_BIT +#endif +#endif + +#ifndef MACRO_32_BIT +#if defined (__arm__) || defined (__i386__) +#define MACRO_32_BIT +#endif +#endif + +#ifndef MACRO_ARM +#if defined (__arm64__) || defined (__arm__) +#define MACRO_ARM +#endif +#endif + +#ifndef MACRO_X86 +#if defined (__x86_64__) || defined (__i386__) +#define MACRO_X86 +#endif +#endif + +#ifndef LOCK_PREFIX +#define LOCK_PREFIX "lock ; " +#endif + +#ifndef BITS_PER_LONG +#ifdef MACRO_64_BIT +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif +#endif + +#ifdef MACRO_64_BIT +#define BITS_PER_LONG_SHIFT 6 +#else +#define BITS_PER_LONG_SHIFT 5 +#endif + +#ifndef BIT +#define BIT(nr) (1UL << (nr)) +#endif + +#ifndef BIT_MASK +#define BIT_MASK(nr) (1UL << ((nr) & ((BITS_PER_LONG) - 1))) +#endif +#ifndef BIT_WORD +#define BIT_WORD(nr) ((nr) >> (BITS_PER_LONG_SHIFT)) +#endif + +#define BIT_MASK_32(nr) (1UL << ((nr) & (32 - 1))) +#define BIT_WORD_32(nr) ((nr) >> 5) + +#ifndef BITS_PER_BYTE +#define BITS_PER_BYTE 8 +#endif + + +#ifndef PS3_BITIDX_INVALID +#define PS3_BITIDX_INVALID (-1) +#endif + + +#define SECTOR_SIZE_512 (512) +#define SECTOR_SIZE_4096 (4096) +#define SECTOR_SIZE_512_BYTES_SHIFT (9) +#define SECTOR_SIZE_4096_BYTES_SHIFT (12) +#define SECTOR_512_TO_BYTES(lba) ((lba) << SECTOR_SIZE_512_BYTES_SHIFT) +#define BYTES_TO_SECTOR_512(byte) ((byte) >> SECTOR_SIZE_512_BYTES_SHIFT) +#define SECTOR_512_TO_4K_SHIFT (3) +#define SECTOR4K_512COUNT (8) + +#define SECTOR4K_INDEX(offset) ((offset) >> SECTOR_512_TO_4K_SHIFT) +#define SECTOR4K_ALIGN(offset) ((offset) & ~(SECTOR4K_512COUNT - 1)) +#define SECTOR4K_MOD(offset) ((offset) & (SECTOR4K_512COUNT - 1)) + +#ifndef CACHE_ALIGNED +#define CACHE_ALIGNED __attribute__((__aligned__(64))) +#endif + +#ifndef ALIGNED +#define ALIGNED(a) __attribute__((__aligned__(a))) +#endif + + + +#ifndef RING_NAMESIZE +#define RING_NAMESIZE (32) +#endif + +#ifndef RING_F_SP_ENQ +#define RING_F_SP_ENQ 0x0001 +#endif +#ifndef RING_F_SC_DEQ +#define RING_F_SC_DEQ 0x0002 +#endif +#ifndef RING_F_EXACT_SZ +#define RING_F_EXACT_SZ 0x0004 +#endif +#ifndef RING_SZ_MASK +#define RING_SZ_MASK (0x7fffffffU) +#endif + + +#ifndef RING_F_MASK +#define RING_F_MASK (RING_F_SP_ENQ | RING_F_SC_DEQ | RING_F_EXACT_SZ) +#endif + +#ifndef RING_CACHE_LINE_SIZE +#define RING_CACHE_LINE_SIZE (64) +#endif +#ifndef RING_CACHE_LINE_MASK +#define RING_CACHE_LINE_MASK (RING_CACHE_LINE_SIZE - 1) +#endif + +#ifndef ALIGN_FLOOR +#define ALIGN_FLOOR(val, cacheLineSize) \ + val & (~(cacheLineSize - 1)) +#endif +#ifndef ALIGN +#define ALIGN(val, cacheLineSize) \ + ALIGN_FLOOR((val + cacheLineSize - 1), (cacheLineSize)) +#endif + +#if !defined(PCLINT) + + +#define PS3_SIZE_OF_TYPE_IS_ALIGN_OF(type, alignSize) \ +static inline char size_of_##type##_is_align_of_##alignSize() \ +{ \ + char __dummy1[0 - (sizeof(type) & (alignSize - 1))]; \ + return __dummy1[-1]; \ +} + + +#define PS3_SIZE_OF_TYPE_NOT_LARGER_THAN(type, size) \ +static inline char size_of_##type##_not_larger_than_##size() \ +{ \ + char __dummy1[size - sizeof(type)]; \ + return __dummy1[-1]; \ +} + +#define PS3_SIZE_OF_TYPE_EQUAL_WITH(type, size) \ +static inline char size_of_##type##_equal_with_##size1() \ +{ \ + char __dummy1[size - sizeof(type)]; \ + return __dummy1[-1]; \ +} \ +static inline char size_of_##type##_equal_with_##size2() \ +{ \ + char __dummy2[sizeof(type) - size]; \ + return __dummy2[-1]; \ +} +#else + +#define PS3_SIZE_OF_TYPE_IS_ALIGN_OF(type, alignSize) +#define PS3_SIZE_OF_TYPE_NOT_LARGER_THAN(type, size) +#define PS3_SIZE_OF_TYPE_EQUAL_WITH(type, size) + +#endif + +#endif + diff --git a/drivers/scsi/ps3stor/include/ps3_dev_type.h b/drivers/scsi/ps3stor/include/ps3_dev_type.h new file mode 100644 index 0000000000000000000000000000000000000000..6cee7d7d0c54f148902a7c87090940eae181d63a --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_dev_type.h @@ -0,0 +1,98 @@ + +#ifndef __PS3_DEV_TYPE_H__ +#define __PS3_DEV_TYPE_H__ + +typedef enum DriverType { + DRIVER_TYPE_UNKNOWN = 0, + DRIVER_TYPE_SAS, + DRIVER_TYPE_SATA, + DRIVER_TYPE_SES, + DRIVER_TYPE_NVME, + DRIVER_TYPE_EXP_SAS, + DRIVER_TYPE_VEP, + DRIVER_TYPE_CHASSIS, + DRIVER_TYPE_BACKPLANE, + DRIVER_TYPE_MAX, +} DriverType_e; + +static inline const char *getDriverTypeName(DriverType_e driverType) +{ + static const char *driverTypeName[] = { + [DRIVER_TYPE_UNKNOWN] = "DRIVER_TYPE_UNKNOWN", + [DRIVER_TYPE_SAS] = "DRIVER_TYPE_SAS", + [DRIVER_TYPE_SATA] = "DRIVER_TYPE_SATA", + [DRIVER_TYPE_SES] = "DRIVER_TYPE_SES", + [DRIVER_TYPE_NVME] = "DRIVER_TYPE_NVME", + [DRIVER_TYPE_EXP_SAS] = "DRIVER_TYPE_EXP_SAS", + [DRIVER_TYPE_VEP] = "DRIVER_TYPE_VEP", + [DRIVER_TYPE_CHASSIS] = "DRIVER_TYPE_CHASSIS", + [DRIVER_TYPE_BACKPLANE] = "DRIVER_TYPE_BACKPLANE", + [DRIVER_TYPE_MAX] = "DRIVER_TYPE_MAX", + }; + + return driverTypeName[driverType]; +} + + +typedef enum MediumType { + DEVICE_TYPE_UNKNOWN = 0, + DEVICE_TYPE_HDD, + DEVICE_TYPE_SSD, + DEVICE_TYPE_ENCLOSURE, + DEVICE_TYPE_MAX, +} MediumType_e; + +static inline const char *getMediumTypeName(MediumType_e mediumType) +{ + static const char *mediumTypeName[] = { + [DEVICE_TYPE_UNKNOWN] = "DEVICE_TYPE_UNKNOWN", + [DEVICE_TYPE_HDD] = "DEVICE_TYPE_HDD", + [DEVICE_TYPE_SSD] = "DEVICE_TYPE_SSD", + [DEVICE_TYPE_ENCLOSURE] = "DEVICE_TYPE_ENCLOSURE", + [DEVICE_TYPE_MAX] = "DEVICE_TYPE_MAX", + }; + + return mediumTypeName[mediumType]; +} + + +typedef enum DiskSpinUpState { + DISK_SPIN_INVALID = 0, + DISK_SPIN_UP = 1, + DISK_SPIN_TRANS = 2, + DISK_SPIN_DOWN = 3, +} DiskSpinUpState_e; + + +typedef enum DeviceState { + DEVICE_STATE_FREE = 0x0, + DEVICE_STATE_INSERTING, + DEVICE_STATE_ONLINE, + DEVICE_STATE_WAIT, + DEVICE_STATE_RECOVER, + DEVICE_STATE_PREONLINE, + DEVICE_STATE_OUTING, + DEVICE_STATE_MAX, +} DeviceState_e; + +static inline const char *getDeviceStateName(DeviceState_e pdState) +{ + static const char *pdStateName[] = { + [DEVICE_STATE_FREE] = "DEVICE_STATE_FREE", + [DEVICE_STATE_INSERTING] = "DEVICE_STATE_INSERTING", + [DEVICE_STATE_ONLINE] = "DEVICE_STATE_ONLINE", + [DEVICE_STATE_WAIT] = "DEVICE_STATE_WAIT", + [DEVICE_STATE_RECOVER] = "DEVICE_STATE_RECOVER", + [DEVICE_STATE_PREONLINE] = "DEVICE_STATE_PREONLINE", + [DEVICE_STATE_OUTING] = "DEVICE_STATE_OUTING", + [DEVICE_STATE_MAX] = "DEVICE_STATE_MAX", + }; + + return pdStateName[pdState]; +} + +#define DEVICE_NOT_RUNNING(state) \ + ((state != DEVICE_STATE_ONLINE) && (state != DEVICE_STATE_WAIT) && \ + (state != DEVICE_STATE_RECOVER) && (state != DEVICE_STATE_PREONLINE)) + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_evtcode_trans.h b/drivers/scsi/ps3stor/include/ps3_evtcode_trans.h new file mode 100644 index 0000000000000000000000000000000000000000..955541851967fbd2b6c115bc783fdaf30615d808 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_evtcode_trans.h @@ -0,0 +1,493 @@ +#ifndef __PS3_EVTCODE_TRANS_H__ +#define __PS3_EVTCODE_TRANS_H__ + +#include "ps3_types.h" +#if !(defined(PS3_PRODUCT_EXPANDER) || defined(PS3_PRODUCT_SWITCH)) +#include "ps3_mgr_evt_raidhba.h" + +static inline S8 const *mgrEvtCodeTrans(U32 opCode) +{ + U32 typeIndex = 0; + U32 codeIndex = 0; + const S8* pEvtTransStr = NULL; + static S8 const *pEvtCodeInfo[PS3_EVT_MAX_TYPE_LOCAL][MGR_EVT_TYPE_OFFSET] = { + { + "MGR_EVT_SAS_START", + "MGR_EVT_SAS_EXPANDER_IN", + "MGR_EVT_SAS_EXPANDER_OUT", + "MGR_EVT_SAS_EXPANDER_UPDATE", + "MGR_EVT_SAS_EXPANDER_CHANGE", + "MGR_EVT_ENCL_TEMP_NORMAL", + "MGR_EVT_ENCL_TEMP_WARNING", + "MGR_EVT_ENCL_TEMP_CRITICAL", + "MGR_EVT_TOPO_LOOP", + "MGR_EVT_LOOP_RESOLUTION", + "MGR_EVT_CASCADED_SCAN_SMP_FAIL", + "MGR_EVT_ENCL_EXCEED", + "MGR_EVT_TRI_MODE_SWITCH", + "MGR_EVT_CHANGE_PHY_BY_USER", + "MGR_EVT_REV_HIBERNATE_CMD", + "MGR_EVT_PHY_CHANGE", + "MGR_EVT_INQUIRY_INFO", + "MGR_EVT_SAS_SATA_LINK_SPEED_NOMATCH", + "MGR_EVT_SAS_SATA_LN_EXCEPTION", + "MGR_EVT_SAS_SATA_DRIVER_INFO", + }, + { + "MGR_EVT_PD_COUNT_START", + "MGR_EVT_DEVM_DISK_IN", + "MGR_EVT_DEVM_DISK_OUT", + "MGR_EVT_MULITPILE_PD_IN", + "MGR_EVT_MULITPILE_PD_OUT", + "MGR_EVT_DEVM_JBOD", + "MGR_EVT_DEVM_READY", + "MGR_EVT_MULITPILE_JBOD", + "MGR_EVT_MULITPILE_READY", + "MGR_EVT_BACKPLANE_ON", + "MGR_EVT_BACKPLANE_OFF", + "MGR_EVT_MULITPILE_PD_STATE_CHANGE", + "MGR_EVT_DEVM_DISK_CHANGE", + "MGR_EVT_DEFAULT_UNUSED", + "MGR_EVT_PD_PRE_READY", + }, + { + "MGR_EVT_VD_COUNT_START", + "MGR_EVT_VD_OPTIMAL", + "MGR_EVT_VD_PARTIAL_DEGRADE", + "MGR_EVT_VD_DEGRADE", + "MGR_EVT_VD_CREATED", + "MGR_EVT_VD_DELETED", + "MGR_EVT_VD_HIDDEN_CHANGE", + "MGR_EVT_MULITPILE_VD_IN", + "MGR_EVT_MULITPILE_VD_OUT", + "MGR_EVT_VD_UNLOCK", + "MGR_EVT_VD_OFFLINE", + }, + { + "MGR_EVT_CTRL_INFO_START", + "MGR_EVT_CTRL_REBOOT", + "MGR_EVT_CTRL_SHUTDOWN", + "MGR_EVT_CTRL_TIME_CHANGE", + "MGR_EVT_CTRL_EVENT_LOG_CLEARED", + "MGR_EVT_CTRL_RBLD_RATE_CHANGED", + "MGR_EVT_CTRL_ENABLEMOVEBACK_CHANGED", + "MGR_EVT_CTRL_ENABLENCQ_CHANGED", + "MGR_EVT_CTRL_AUTO_REBUILD_CHANGED", + "MGR_EVT_CTRL_EGHS_READY_CHANGED", + "MGR_EVT_CTRL_EGHS_SPARE_CHANGED", + "MGR_EVT_CTRL_BGI_RATE_CHANGED", + "MGR_EVT_CTRL_MIGRATE_RATE_CHANGED", + "MGR_EVT_CTRL_CC_RATE_CHANGED", + "MGR_EVT_CTRL_DIRECT_CHANGE", + "MGR_EVT_CTRL_PR_START", + "MGR_EVT_CTRL_PR_PAUSE", + "MGR_EVT_CTRL_PR_REMINDER_PAUSE", + "MGR_EVT_CTRL_PR_RESUME", + "MGR_EVT_CTRL_PR_DONE", + "MGR_EVT_CTRL_PR_RATE_CHANGED", + "MGR_EVT_CTRL_PR_CANT_START", + "MGR_EVT_CTRL_PR_PROP_CHANGED", + "MGR_EVT_CTRL_PARAM_CHANGE", + "MGR_EVT_CTRL_AUTO_CC_PARAM_CHANGE", + "MGR_EVT_CTRL_RECOVERY_FACTORY", + "MGR_EVT_CTRL_PROFILEID_CHANGED", + "MGR_EVT_CTRL_SANPSHOT_CREATE", + "MGR_EVT_CTRL_SANPSHOT_DELETE", + "MGR_EVT_CTRL_ENABLEPDM_CHANGED", + "MGR_EVT_CTRL_PDMSUPPORTREADYPD", + "MGR_EVT_CTRL_PDMTIMERINTERVAL", + "MGR_EVT_CTRL_SECURITY_KEY_CHANGE", + "MGR_EVT_CTRL_SECURITY_KEY_CREATE", + "MGR_EVT_CTRL_SECURITY_KEY_DESTROY", + "MGR_EVT_CTRL_SECURITY_KEY_ESCROW", + "MGR_EVT_CTRL_SECURITY_KEY_FAILED", + "MGR_EVT_CTRL_SECURITY_KEY_INVALID", + "MGR_EVT_AUTOCONFIG", + "MGR_EVT_CTRL_FOREIGN_IMPORTED_ALL", + "MGR_EVT_CTRL_FOREIGN_CLEAR", + "MGR_EVT_CTRL_FOREIGN_IMPORT_FAIL", + "MGR_EVT_CTRL_FOREIGN_IMPORT_PART_FAIL", + "MGR_EVT_CTRL_FOREIGN_IMPORT_FAIL_PDS", + "MGR_EVT_CTRL_FOREIGN_PD_DETECTED", + "MGR_EVT_PD_INSERT_TO_DG", + "MGR_EVT_PD_IMPORT_TO_DG", + "MGR_EVT_HARD_RESET", + "MGR_EVT_DPF_CFG_MODIFY", + "MGR_EVT_SPOR", + "MGR_EVT_ONF_ABNORMAL", + "MGR_EVT_CTRL_LOADED", + "MGR_EVT_MAIN_MEDIUM_NOT_AVAILABLE", + "MGR_EVT_BACKUP_MEDIUM_NOT_AVAILABLE", + "MGR_EVT_MEDIUM_DATA_RECOVER", + "MGR_EVT_CACHE_PROTECTION_CMPT_READY", + "MGR_EVT_CACHE_PROTECTION_CMPT_NOT_READY", + "MGR_EVT_CACHE_PROTECTION_CMPT_INSTABLE", + "MGR_EVT_INIT_FAIL", + "MGR_EVT_CTRL_POWER_MODE_CHANGED", + }, + { + "MGR_EVT_PD_ATTR_START", + "MGR_EVT_PD_INFO_CHANGE", + "MGR_EVT_PD_STATE_CHANGE", + "MGR_EVT_PD_MARKED_JBOD", + "MGR_EVT_PD_MARKED_READY", + "MGR_EVT_PD_MARKED_ONLINE", + "MGR_EVT_PD_MARKED_OFFLINE", + "MGR_EVT_PD_MARKED_FAILED", + "MGR_EVT_PD_MARKED_MISSING", + "MGR_EVT_PD_MARKED_REBUILD", + "MGR_EVT_PD_MARKED_REPLACE", + "MGR_EVT_PD_MARKED_UNCONFIGUREDBAD", + "MGR_EVT_PD_MARKED_FOREIGN", + "MGR_EVT_PD_NR_GLOBAL_SPARE_ADDED", + "MGR_EVT_PD_NR_GLOBAL_SPARE_DELETED", + "MGR_EVT_PD_NR_DEDICATED_SPARE_ADDED", + "MGR_EVT_PD_NR_DEDICATED_SPARE_DELETED", + "MGR_EVT_PD_R_GLOBAL_SPARE_ADDED", + "MGR_EVT_PD_R_GLOBAL_SPARE_DELETED", + "MGR_EVT_PD_R_DEDICATED_SPARE_ADDED", + "MGR_EVT_PD_R_DEDICATED_SPARE_DELETED", + "MGR_EVT_PD_RBLD_ABORT_BY_USER", + "MGR_EVT_PD_RBLD_DONE_PD", + "MGR_EVT_PD_RBLD_FAILED_BAD_SOURCE", + "MGR_EVT_PD_RBLD_FAILED_BAD_TARGET", + "MGR_EVT_PD_RBLD_PROGRESS", + "MGR_EVT_PD_RBLD_SUSPENDED_REMINDER", + "MGR_EVT_PD_RBLD_SUSPENDED", + "MGR_EVT_PD_RBLD_RESUME", + "MGR_EVT_PD_RBLD_START", + "MGR_EVT_PD_RBLD_START_AUTO", + "MGR_EVT_PD_RBLD_MEDIUM_ERROR", + "MGR_EVT_PD_EMERGENCY_SPARE", + "MGR_EVT_PD_RECOVER_MEDIUM_ERROR", + "MGR_EVT_PD_MOVEBACK_START", + "MGR_EVT_PD_MOVEBACK_ABORT", + "MGR_EVT_PD_MOVEBACK_ABORT_FOR_REBUILD", + "MGR_EVT_PD_MOVEBACK_DONE", + "MGR_EVT_PD_MOVEBACK_PROGRESS", + "MGR_EVT_PD_MOVEBACK_SUSPENDED", + "MGR_EVT_PD_MOVEBACK_SUSPENDED_REMINDER", + "MGR_EVT_PD_MOVEBACK_RESUME", + "MGR_EVT_PD_MOVEBACK_START_AUTO", + "MGR_EVT_PD_MOVEBACK_FAILED_BAD_SOURCE", + "MGR_EVT_PD_MOVEBACK_FAILED_BAD_TARGET", + "MGR_EVT_PD_MOVEBACK_ABORT_BY_USER", + "MGR_EVT_PD_MOVEBACK_MEDIUM_ERROR", + "MGR_EVT_PD_FGI_START", + "MGR_EVT_PD_FGI_COMPLETE", + "MGR_EVT_PD_FGI_FAILED", + "MGR_EVT_PD_FGI_PROGRESS", + "MGR_EVT_PD_FGI_ABORT", + "MGR_EVT_PD_PR_ABORTED", + "MGR_EVT_PD_PR_CORRECTED", + "MGR_EVT_PD_PR_UNCORRECTABLE", + "MGR_EVT_PD_PR_FOUND_MEDIUM_ERROR", + "MGR_EVT_PD_PR_PROGRESS", + "MGR_EVT_PD_SET_BOOT_DRIVE", + "MGR_EVT_PD_RESET_BOOT_DRIVE", + "MGR_EVT_PD_RESET_BOOT_DRIVE_WITH_DISK_OUT", + "MGR_EVT_PD_SET_BOOT_DRIVE_WITH_DISK_IN", + "MGR_EVT_PD_POWERSAVE_TO_ON", + "MGR_EVT_PD_POWERSAVE_TO_TRANSITION", + "MGR_EVT_PD_TRANSITION_TO_ON", + "MGR_EVT_PD_TRANSITION_TO_POWERSAVE", + "MGR_EVT_PD_ON_TO_POWERSAVE", + "MGR_EVT_PD_START_LOCATE", + "MGR_EVT_PD_STOP_LOCATE", + "MGR_EVT_PD_PFA_ERROR", + "MGR_EVT_PD_NOT_PRESENT", + "MGR_EVT_DEVM_DISK_FAULT", + "MGR_EVT_PHY_FLASHOFFLINE", + "MGR_EVT_PHY_FLASHONLINE", + "MGR_EVT_NFR_DONE", + "MGR_EVT_NFR_REPAIRED", + "MGR_EVT_NFR_REPORT", + "MGR_EVT_NFR_STOP", + "MGR_EVT_PD_DOWNLOAD_DONE", + "MGR_EVT_PD_DOWNLOAD_START", + "MGR_EVT_NVME_PHY_BAD", + }, + { + "MGR_EVT_VD_ATTR_START", + "MGR_EVT_MULITPILE_VD_STATE_CHANGE", + "MGR_EVT_VD_OFFLINE_OLD", + "MGR_EVT_VD_LOCK", + "MGR_EVT_VD_PASSWD_CHANGED", + "MGR_EVT_VD_SETTINGS_CHANGE", + "MGR_EVT_VD_PD_CHANGE", + "MGR_EVT_VD_STATE_CHANGE", + "MGR_EVT_PD_RBLD_DONE_LD", + "MGR_EVT_VD_FGI_START", + "MGR_EVT_VD_FGI_COMPLETE", + "MGR_EVT_VD_FGI_FAILED", + "MGR_EVT_VD_FGI_PROGRESS", + "MGR_EVT_VD_FGI_ABORT", + "MGR_EVT_VD_BGI_START", + "MGR_EVT_VD_BGI_COMPLETE", + "MGR_EVT_VD_BGI_FAILED", + "MGR_EVT_VD_BGI_PROGRESS", + "MGR_EVT_VD_BGI_ABORT", + "MGR_EVT_VD_BGI_PAUSE", + "MGR_EVT_VD_BGI_REMINDER_PAUSE", + "MGR_EVT_VD_BGI_RESUME", + "MGR_EVT_VD_BGI_CORRECTABLE_ERROR", + "MGR_EVT_VD_BGI_UNCORRECTABLE_ERROR", + "MGR_EVT_VD_ALTER_ATTR_BY_MIGRATION", + "MGR_EVT_VD_BBM_CLEARED", + "MGR_EVT_VD_BBM_PERCENT_FULL", + "MGR_EVT_VD_BBM_100_FULL", + "MGR_EVT_VD_BBM_LOG_FULL", + "MGR_EVT_VD_BBM_LOG_RCT", + "MGR_EVT_VD_BBM_LOG_WCT", + "MGR_EVT_VD_BBM_DEL_RCT", + "MGR_EVT_VD_CC_ABORTED", + "MGR_EVT_VD_CC_CORRECTED_MEDIUM_ERROR", + "MGR_EVT_VD_CC_DOUBLE_MEDIUM_ERRORS", + "MGR_EVT_VD_CC_DONE", + "MGR_EVT_VD_CC_DONE_INCON", + "MGR_EVT_VD_CC_FAILED", + "MGR_EVT_VD_CC_FAILED_UNCOR", + "MGR_EVT_VD_CC_INCONSISTENT_PARITY", + "MGR_EVT_VD_CC_INCONSISTENT_PARITY_LOGGING_DISABLED", + "MGR_EVT_VD_CC_PROGRESS", + "MGR_EVT_VD_CC_START", + "MGR_EVT_VD_CC_PAUSE", + "MGR_EVT_VD_CC_REMINDER_PAUSE", + "MGR_EVT_VD_CC_RESUME", + "MGR_EVT_VD_RW_RAID1X_WRITE_CARDBUSY", + "MGR_EVT_VD_SET_BOOT_DRIVE", + "MGR_EVT_VD_RESET_BOOT_DRIVE", + "MGR_EVT_VD_RESET_BOOT_DRIVE_WITH_DISK_OUT", + "MGR_EVT_VD_SET_BOOT_DRIVE_WITH_DISK_IN", + "MGR_EVT_ALL_CONFIGS_MISSING", + "MGR_EVT_PDS_MISSING", + "MGR_EVT_NVSRAM_RECOVER_FAIL", + "MGR_EVT_NVSRAM_UPDATE_FAIL", + "MGR_EVT_VD_ERASE_ABORT", + "MGR_EVT_VD_ERASE_COMPLETE", + "MGR_EVT_VD_ERASE_DISK_FAILED", + "MGR_EVT_VD_ERASE_FAILED", + "MGR_EVT_VD_ERASE_PROGRESS", + "MGR_EVT_VD_ERASE_START", + "MGR_EVT_VD_EXPAND_FINISH", + "MGR_EVT_VD_EXPAND_START", + "MGR_EVT_VD_FLUSH_CLEAR_FAILED", + "MGR_EVT_VD_FLUSH_RECORD_FAILED", + "MGR_EVT_VD_FLUSH_SET_INCONSIST", + "MGR_EVT_VDS_MISSING", + "MGR_EVT_VD_BBM_UNCORRECTABLE_LOGGED", + "MGR_EVT_VD_FLUSH_CACHE_PINNED", + "MGR_EVT_VD_FLUSH_OCR_CACHE_PINNED", + "MGR_EVT_VD_FLUSH_CACHE_DISCARDED", + "MGR_EVT_VD_FLUSH_CACHE_DISCARDED_DEL", + "MGR_EVT_VD_FLUSH_CACHE_DESTAGED", + "MGR_EVT_VD_CM_RECOVERY_CRC_FAIL", + "MGR_EVT_VD_BGI_COMPLETE_UNCOR", + }, + { + "MGR_EVT_DG_INFO_START", + "MGR_EVT_DG_CREATED", + "MGR_EVT_DG_DELETED", + "MGR_EVT_DG_SETTING_CHANGE", + "MGR_EVT_DG_MIGRATION_START", + "MGR_EVT_DG_MIGRATION_RECOVER", + "MGR_EVT_DG_MIGRATION_SUCCESS", + "MGR_EVT_DG_MIGRATION_ALLOC_RESOURCE_FAILED", + "MGR_EVT_DG_MIGRATION_FAILED", + "MGR_EVT_DG_MIGRATION_RECOVER_FAILED", + "MGR_EVT_DG_MIGRATION_PROGRESS", + "MGR_EVT_DG_MIGRATION_INTERNAL_WARNING", + "MGR_EVT_DG_PRSWITCH_CHANGE", + "MGR_EVT_DG_PR_ABORTED_WM_FAILED", + "MGR_EVT_DG_PR_ABORTED_SPINUP_FAILED", + }, + { + "MGR_EVT_BBU_START", + "MGR_EVT_BBU_PRESENT", + "MGR_EVT_BBU_NOT_PRESENT", + "MGR_EVT_BBU_GOOD", + "MGR_EVT_BBU_BAD", + "MGR_EVT_BBU_CAP_BELOW_THRESHOLD", + "MGR_EVT_BBU_CAP_ABOVE_THRESHOLD", + "MGR_EVT_BBU_CHARGE_STATUS", + "MGR_EVT_BBU_CHARGE_COMPLETE", + "MGR_EVT_BBU_INSERT", + "MGR_EVT_BBU_ABSENT", + "MGR_EVT_BBU_TEMPERATURE_NORMAL", + "MGR_EVT_BBU_TEMPERATURE_HIGH", + "MGR_EVT_BBU_VOLTAGE_NORMAL", + "MGR_EVT_BBU_VOLTAGE_HIGH", + "MGR_EVT_BBU_CURRENT_NORMAL", + "MGR_EVT_BBU_CURRENT_HIGH", + "MGR_EVT_BBU_LOAD_NORMAL", + "MGR_EVT_BBU_VOLTAGE_LOW", + "MGR_EVT_BBU_BATTERY_CAP_ABOVE_SOH_THRESHOLD", + "MGR_EVT_BBU_BATTERY_CAP_BELOW_SOH_THRESHOLD", + "MGR_EVT_BBU_LEARN_STAGE", + "MGR_EVT_BBU_LEARN_REQUESTED", + "MGR_EVT_BBU_LEARN_POSTPONED", + "MGR_EVT_BBU_LEARN_TIMEOUT", + "MGR_EVT_BBU_LEARN_MANUAL", + "MGR_EVT_BBU_LEARN_RESCHEDULED", + "MGR_EVT_BBU_PROPERTIES_CHANGED", + }, + { + "MGR_EVT_CONFIG_START", + "MGR_EVT_CONFIG_INFO", + "MGR_EVT_CONFIG_FLASH_READ_FAIL", + "MGR_EVT_CONFIG_FLASH_WRITE_FAIL", + "MGR_EVT_CONFIG_NVSRAM_READ_FAIL", + "MGR_EVT_CONFIG_NVSRAM_WRITE_FAIL", + "MGR_EVT_CONFIG_VERSION_MISMATCH", + "MGR_EVT_CONFIG_MEDIA_VALUE_CHECK_FAIL", + "MGR_EVT_CONFIG_ERASE_NVSRAM", + "MGR_EVT_PHY_LINKSPEED_CFG_CHANGE", + }, + { + "MGR_EVT_IO_START", + "MGR_EVT_IO_TEST", + "MGR_EVT_IO_SENSE_DATA", + "MGR_EVT_DEVICE_RESET", + "MGR_EVT_NVME_DEVICE_RESET", + "MGR_EVT_DEVICE_ABNORMAL", + "MGR_EVT_IO_SENSE", + }, + { + "MGR_EVT_UKEY_START", + "MGR_EVT_UKEY_INSERT", + "MGR_EVT_UKEY_DEGRADE", + "MGR_EVT_RAID_KEY_OVERCURRENT", + "MGR_EVT_RAID_KEY_OVERCURRENT_RECOVER", + }, + { + "MGR_EVT_HWR_START", + "MGR_EVT_HWR_HAC_RESET_BEGIN", + "MGR_EVT_HWR_HAC_RESET_END", + "MGR_EVT_REPORT_HAC_ECC", + }, + { + "MGR_EVT_ALARM_START", + "MGR_EVT_ALARM_ENABLED", + "MGR_EVT_ALARM_DISABLED", + }, + { + "MGR_EVT_ECC_START", + "MGR_EVT_ECC_CNT_EXCEED", + "MGR_EVT_ECC_ERR_INTR", + "MGR_EVT_ECC_CNT_CLEAR", + "MGR_EVT_ECC_CLI_CHANGE", + "MGR_EVT_ECC_FACTORY_CHANGE", + }, + { + "MGR_EVT_UPGRADE_START", + "MGR_EVT_IMAGE_DOWNLOAD_ERROR", + "MGR_EVT_IMAGE_AUTHENTICATION_FAIL", + "MGR_EVT_IMAGE_VERSION_CHECK_FAIL", + "MGR_EVT_IMAGE_CHECKSUM_CHECK_FAIL", + "MGR_EVT_IMAGE_FROM_BACKUP", + "MGR_EVT_DEV_OPEN_ERROR", + "MGR_EVT_DEV_FLASH_ERROR", + "MGR_EVT_DEV_ERASE_ERROR", + "MGR_EVT_DEV_CLOSE_ERROR", + "MGR_EVT_FLASH_GENERAL_ERROR", + "MGR_EVT_FLASH_TIMEOUT", + "MGR_EVT_UPGRADE_SUCCESS", + "MGR_EVT_UPGRADE_SYNC_START", + "MGR_EVT_UPGRADE_SYNC_FAILED", + "MGR_EVT_UPGRADE_SYNC_SUCCESS", + }, + { + "MGR_EVT_TEMP_START", + "MGR_EVT_TEMP_WITHIN_OPTIMAL_RANGE", + "MGR_EVT_TEMP_ABOVE_OPTIMAL_RANGE", + "MGR_EVT_TEMP_WARNING", + "MGR_EVT_TEMP_CRITICAL", + }, + { + "MGR_EVT_PD_ATTR_EXTEND_START_START", + "MGR_EVT_PD_NVME_CMD_ERR", + "MGR_EVT_PD_NVME_CMD_TO", + "MGR_EVT_PD_NVME_INSERT_FAIL", + "MGR_EVT_PD_ERASE_ABORT", + "MGR_EVT_PD_ERASE_COMPLETE", + "MGR_EVT_PD_ERASE_FAILED", + "MGR_EVT_PD_ERASE_PROGRESS", + "MGR_EVT_PD_ERASE_START", + "MGR_EVT_PD_PDM_ABORT_BY_USER", + "MGR_EVT_PD_PDM_ABORT_FOR_REBUILD", + "MGR_EVT_PD_PDM_ABORT", + "MGR_EVT_PD_PDM_DONE", + "MGR_EVT_PD_PDM_FAILED_BAD_SOURCE", + "MGR_EVT_PD_PDM_FAILED_BAD_TARGET", + "MGR_EVT_PD_PDM_MEDIUM_ERROR", + "MGR_EVT_PD_PDM_PROGRESS", + "MGR_EVT_PD_PDM_REPLACED_SOURCE", + "MGR_EVT_PD_PDM_RESUME", + "MGR_EVT_PD_PDM_START_AUTO", + "MGR_EVT_PD_PDM_START", + "MGR_EVT_PD_PDM_SUSPENDED_REMINDER", + "MGR_EVT_PD_PDM_SUSPENDED", + "MGR_EVT_PD_PFA_ERROR_CLEAR", + "MGR_EVT_PD_SANITIZE_START", + "MGR_EVT_PD_FORMAT_START", + "MGR_EVT_PD_SANITIZE_PROGRESS", + "MGR_EVT_PD_SANITIZE_DONE", + "MGR_EVT_PD_FORMAT_DONE", + "MGR_EVT_PD_DPF_ERROR", + "MGR_EVT_PD_MARKED_SHIELD", + "MGR_EVT_PD_BBM_CORRECTED", + "MGR_EVT_PD_BBM_UNRECOVERABLE", + "MGR_EVT_PD_BBM_PUNCTURING", + "MGR_EVT_PD_BBM_REASSIGN_WR_ERROR", + "MGR_EVT_PD_UNABLE_ACCESS", + "MGR_EVT_MULITPILE_PD_UNABLE_ACCESS", + "MGR_EVT_PD_INSERT_FAIL", + "MGR_EVT_PHY_SATA_D2H_FAIL", + "MGR_EVT_PD_NOT_INSERTED", + "MGR_EVT_PD_NOT_SUPPORT", + "MGR_EVT_MULITPILE_PD_NOT_SUPPORT", + "MGR_EVT_NVDATA_INVAILD", + "MGR_EVT_PD_RBLD_NON_UNMAP_PD", + "MGR_EVT_PD_MOVEBACK_NON_UNMAP_PD", + "MGR_EVT_PD_PDM_NON_UNMAP_PD", + "MGR_EVT_PD_RBLD_FAILED", + "MGR_EVT_PD_SANITIZE_FAILED", + "MGR_EVT_PD_SPIN_FAIL", + "MGR_EVT_PD_RBLD_MEDIA_MIX_NOT_SUPPORT", + "MGR_EVT_PD_RBLD_DRIVE_MIX_NOT_SUPPORT", + "MGR_EVT_PD_PDM_MEDIA_MIX_NOT_SUPPORT", + "MGR_EVT_PD_PDM_DRIVE_MIX_NOT_SUPPORT", + "MGR_EVT_PD_MOVEBACK_MEDIA_MIX_NOT_SUPPORT", + "MGR_EVT_PD_MOVEBACK_DRIVE_MIX_NOT_SUPPORT", + "MGR_EVT_NFR_FAILED", + "MGR_EVT_PD_RBLD_SMALL_SIZE", + "MGR_EVT_PD_MOVEBACK_SMALL_SIZE", + "MGR_EVT_NEGO_LOWER_LINK_SPEED", + "MGR_EVT_PCIE_LINK_NEGO_ABNORMAL", + "MGR_EVT_PD_ISOLATION", + "MGR_EVT_PD_REPAIR_FAILED", + "MGR_EVT_PD_PCIE_LINK_UP_WITHOUT_I2C", + "MGR_EVT_PD_PCIE_ENUMERATE_FAILED", + "MGR_EVT_PD_MISS_LIGHTING", + }, +}; + + if (opCode >= ((MGR_EVT_EXTEND_TYPE_START - 1) * MGR_EVT_TYPE_OFFSET) + \ + (PS3_EVT_MAX_TYPE_LOCAL - MGR_EVT_EXTEND_TYPE_START) * MGR_EVT_TYPE_EXTEND_OFFSET) { + goto end; + }; + typeIndex = opCode / MGR_EVT_TYPE_OFFSET; + codeIndex = opCode % MGR_EVT_TYPE_OFFSET; + pEvtTransStr = pEvtCodeInfo[typeIndex][codeIndex]; +end: + return pEvtTransStr; +} + +#else +static inline S8 const *mgrEvtCodeTrans(U32 opCode) +{ + const S8* pEvtTransStr = NULL; + return pEvtTransStr; +} +#endif +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_meta.h b/drivers/scsi/ps3stor/include/ps3_meta.h new file mode 100644 index 0000000000000000000000000000000000000000..d49d813ab3e4e99261fc0f94fd1091e348cae924 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_meta.h @@ -0,0 +1,166 @@ + +#ifndef __PS3_META_H__ +#define __PS3_META_H__ + + +typedef enum MicPdState { + MIC_PD_STATE_UNKNOWN = 0, + MIC_PD_STATE_READY = 1, + MIC_PD_STATE_UBAD = 2, + MIC_PD_STATE_DSPARE = 3, + MIC_PD_STATE_GSPARE = 4, + MIC_PD_STATE_OFFLINE = 5, + MIC_PD_STATE_ONLINE = 6, + MIC_PD_STATE_MISSING = 7, + MIC_PD_STATE_FAILED = 8, + MIC_PD_STATE_REBUILD = 9, + MIC_PD_STATE_REPLACE = 10, + MIC_PD_STATE_FOREIGN = 11, + MIC_PD_STATE_JBOD = 12, + MIC_PD_STATE_UNSUPPORT = 13, + MIC_PD_STATE_PDM = 14, + MIC_PD_STATE_CFSHLD = 15, + MIC_PD_STATE_HSPSHLD = 16, + MIC_PD_STATE_RUNSP = 17, + MIC_PD_STATE_UBUNSP = 18, + MIC_PD_STATE_MAX +}MicPdState_e; + + +typedef enum PhyProtoType { + PHY_PROTO_SAS_SATA, + PHY_PROTO_PCIE, + PHY_PROTO_BOTTOM, +}PhyProtoType_e; + + +static inline const char *getPdStateName(MicPdState_e pdSate, unsigned char isRaid) +{ + static const char *raidPdName[] = { + [MIC_PD_STATE_UNKNOWN] = "UNKNOWN", + [MIC_PD_STATE_READY] = "UGOOD", + [MIC_PD_STATE_UBAD] = "UBAD", + [MIC_PD_STATE_DSPARE] = "DSPARE", + [MIC_PD_STATE_GSPARE] = "GSPARE", + [MIC_PD_STATE_OFFLINE] = "OFFLINE", + [MIC_PD_STATE_ONLINE] = "ONLINE", + [MIC_PD_STATE_MISSING] = "MISSING", + [MIC_PD_STATE_FAILED] = "FAILED", + [MIC_PD_STATE_REBUILD] = "REBUILD", + [MIC_PD_STATE_REPLACE] = "REPLACE", + [MIC_PD_STATE_FOREIGN] = "FOREIGN", + [MIC_PD_STATE_JBOD] = "JBOD", + [MIC_PD_STATE_UNSUPPORT] = "UNSUPPORT", + [MIC_PD_STATE_PDM] = "PDM", + [MIC_PD_STATE_CFSHLD] = "CFSHLD", + [MIC_PD_STATE_HSPSHLD] = "HSPSHLD", + [MIC_PD_STATE_RUNSP] = "UGUNSP", + [MIC_PD_STATE_UBUNSP] = "UBUNSP", + }; + + static const char *hbaPdName[] = { + [MIC_PD_STATE_UNKNOWN] = "UNKNOWN", + [MIC_PD_STATE_READY] = "READY", + [MIC_PD_STATE_UBAD] = "UBAD", + [MIC_PD_STATE_DSPARE] = "DSPARE", + [MIC_PD_STATE_GSPARE] = "GSPARE", + [MIC_PD_STATE_OFFLINE] = "OFFLINE", + [MIC_PD_STATE_ONLINE] = "ONLINE", + [MIC_PD_STATE_MISSING] = "MISSING", + [MIC_PD_STATE_FAILED] = "FAILED", + [MIC_PD_STATE_REBUILD] = "REBUILD", + [MIC_PD_STATE_REPLACE] = "REPLACE", + [MIC_PD_STATE_FOREIGN] = "FOREIGN", + [MIC_PD_STATE_JBOD] = "JBOD", + [MIC_PD_STATE_UNSUPPORT] = "UNSUPPORT", + [MIC_PD_STATE_PDM] = "PDM", + [MIC_PD_STATE_CFSHLD] = "CFSHLD", + [MIC_PD_STATE_HSPSHLD] = "HSPSHLD", + [MIC_PD_STATE_RUNSP] = "RUNSP", + [MIC_PD_STATE_UBUNSP] = "UBUNSP", + }; + + if (isRaid) { + return raidPdName[pdSate]; + } else { + return hbaPdName[pdSate]; + } +} + + +typedef enum MicVdState { + MIC_VD_STATE_UNKNOWN = 0, + MIC_VD_STATE_OFFLINE, + MIC_VD_STATE_OPTIMAL, + MIC_VD_STATE_PARTIAL_DEGRADE, + MIC_VD_STATE_DEGRADE +}MicVdState_e; + + +typedef enum InquiryFailReason { + INSERT_INQUIRY_ERR = 0, + INSERT_TUR_ERR = 1, +}InquiryFailReason_e; + + +typedef enum pdUnspReason { + PD_UNSP_EXCEED_MAX_SIZE = 0, + PD_UNSP_EXCEED_MAX_NUM = 1, + PD_UNSP_TUR_ERR, + PD_UNSP_SANITIZE, + PD_UNSP_INQUIRY_FAIL, + PD_UNSP_RESET_FAIL, +}pdUnspReason_e; + +static inline const char *getVdStateName(MicVdState_e vdSate) +{ + static const char *vdStateName[] = { + [MIC_VD_STATE_UNKNOWN] = "UNKNOWN", + [MIC_VD_STATE_OFFLINE] = "OFFLINE", + [MIC_VD_STATE_OPTIMAL] = "OPTIMAL", + [MIC_VD_STATE_PARTIAL_DEGRADE] = "PARTIALLY DEGRADED", + [MIC_VD_STATE_DEGRADE] = "DEGRADED" + }; + + return vdStateName[vdSate]; +} + +static inline const char *triModeNameGet(PhyProtoType_e protoType) +{ + static const char *protoTypeName[] = { + [PHY_PROTO_SAS_SATA] = "SAS/SATA", + [PHY_PROTO_PCIE] = "PCIe", + [PHY_PROTO_BOTTOM] = "DEFAULT", + }; + return protoTypeName[protoType]; +} + + +typedef enum RaidLevel { + RAID0 = 0x00, + RAID1 = 0x01, + RAID5 = 0x05, + RAID6 = 0x06, + JBOD = 0x0A, + RAID10 = 0x10, + RAID1E = 0x11, + RAID00 = 0x20, + RAID50 = 0x50, + RAID60 = 0x60, + RAID_UNKNOWN = 0xFF +}RaidLevel_e; + +typedef enum VDAccessPolicy { + VD_ACCESS_POLICY_READ_WRITE = 0, + VD_ACCESS_POLICY_READ_ONLY, + VD_ACCESS_POLICY_BLOCK, + VD_ACCESS_POLICY_REMOVE_ACCESS +} VDAccessPolicy_e; + + +typedef enum VDBgt { + VD_BGT_IDLE_READY = 0, + VD_BGT_FULL_INIT = 1, +} VDBgt_e; + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_mgr_evt.h b/drivers/scsi/ps3stor/include/ps3_mgr_evt.h new file mode 100644 index 0000000000000000000000000000000000000000..4bf433df43516b7cf633e83c0a09b0ceea4f4a78 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_mgr_evt.h @@ -0,0 +1,198 @@ +#ifndef __PS3_MGR_EVT__ +#define __PS3_MGR_EVT__ + +#include "ps3_mgr_evt_raidhba.h" +#include "ps3_mgr_evt_swexp.h" +#include "ps3lib/ps3lib_event.h" + + +#pragma pack(1) + +#if (defined(PS3_PRODUCT_EXPANDER) || defined(PS3_PRODUCT_SWITCH)) +#define PS3_EVT_ATTR(evtcode) (PS3_EVT_ATTR_EXTEND(evtcode)) +#else +#define PS3_EVT_ATTR(evtcode) (ps3EvtCodeExtendToNormal(PS3_EVT_ATTR_EXTEND(evtcode))) +#endif + + +typedef Ps3LibPdAttrInfo_s MgrPdAttrInfo_s; + +typedef Ps3LibPdPreFailInfo_s MgrPdPreFailInfo_s; + +typedef Ps3LibSparePdInfo_s MgrSparePdInfo_s; + +typedef Ps3LibVdAttrInfo_s MgrVdAttrInfo_s; + +typedef Ps3LibDiskPFCfgModifyEvtInfo_s MgrDiskPFCfgModifyEvtInfo_s; + + +#define MAX_VD_NAME_BYTES (16) +typedef Ps3LibVdBaseSetting_s MgrVdBaseSetting_s; + +typedef Ps3LibVdPropertiesInfo_s MgrVdPropertiesInfo_s; + +typedef Ps3LibVdStateChangeInfo_s MgrVdStateChangeInfo_s; + +typedef Ps3LibVdCreateEvtInfo_s MgrVdCreateInfo_s; + +typedef Ps3LibDgAttrInfo_s MgrDgAttrInfo_s; + +typedef Ps3LibExpanderInfo_s MgrExpanderInfo_s; + +enum { + MGR_EVT_FUNCTION0 = 0, + MGR_EVT_FUNCTION1 = 1, + MGR_EVT_FUNCTION_COMMON = 250, +}; + +typedef Ps3LibCtrlAttrInfo_s MgrCtrlAttrInfo_s; + + +typedef Ps3LibCtrlRebootInfo_s MgrCtrlRebootInfo_s; + + +typedef Ps3LibPdBatchEvtInfo_s MgrPdBatchEvtInfo_s; + + +typedef Ps3LibVdBatchEvtInfo_s MgrVdBatchEvtInfo_s; + + +typedef Ps3LibVdBbmBatchEvtInfo_s MgrVdBbmBatchEvtInfo_s; + + +typedef Ps3LibCtrlBatchEvtInfo_s MgrCtrlBatchEvtInfo_s; + + +typedef Ps3LibCfgAttrInfo_s MgrCfgAttrInfo_s; +#define MGR_CTRL_AUTOCONFIG_EVTDATA_SIZE PS3LIB_CTRL_AUTOCONFIG_EVTDATA_SIZE +typedef Ps3LibCfgAutoConfig_s MgrCfgAutoConfig_s; + + +typedef Ps3LibBgtRebuildInfo_s MgrBgtRebuildInfo_s; + + +#define FGI_MODE_LEN PS3LIB_FGI_MODE_LEN +typedef Ps3LibBgtInitEvtInfo_s MgrBgtInitEvtInfo_s; + + +typedef Ps3LibBgtEraseEvtInfo_s MgrBgtEraseEvtInfo_s; + + +typedef Ps3LibPhyEvtInfo_s MgrPhyEvtInfo_s; + +#define BBM_ERRTBL_NAME_LEN PS3LIB_BBM_ERRTBL_NAME_LEN + +typedef Ps3LibVdBbmEvtInfo_s MgrVdBbmEvtInfo_s; + +typedef Ps3LibRwDdtEvtInfo_s MgrRwDdtEvtInfo_s; + +typedef Ps3LibFlushEvtInfo_s MgrFlushEvtInfo_s; + +typedef Ps3LibBgtCcEvtInfo_s MgrBgtCcEvtInfo_s; + +typedef Ps3LibBgtPrEvtInfo_s MgrBgtPrEvtInfo_s; + + +typedef Ps3LibBbuEvtInfo_s MgrBbuEvtInfo_s; + +typedef Ps3LibMigrationInfo_s MgrMigrationInfo_s; + + +typedef Ps3LibUkeyEvtInfo_s MgrUkeyEvtInfo_s; + + +typedef Ps3LibExpEvtInfo_s MgrExpEvtInfo_s; + + +typedef Ps3LibOemInfo_s MgrOemInfo_s; + + +typedef Ps3LibBplaneEvtInfo_s BplaneEvtInfo_s; + +typedef Ps3LibEccEvtInfo_s MgrEccEvtInfo_s; + + +typedef Ps3LibTempEvtInfo_s MgrTempEvtInfo_s; + +typedef Ps3LibIoCmdType_s IoCmdType_s; + + +typedef Ps3LibSenseDataEvtInfo_s MgrSenseDataEvtInfo_s; +typedef Ps3LibErrSenseEvtInfo_s MgrErrSenseEvtInfo_s; + +typedef Ps3LibPdDownloadInfo_s MgrPdDownloadInfo_s; + +typedef Ps3LibSanitizeEvtInfo_s MgrSanitizeEvtInfo_s; + +typedef Ps3LibFormatEvtInfo_s MgrFormatEvtInfo_s; + +typedef Ps3LibSnapshotEvtInfo_s MgrSnapshotEvtInfo_s; + +typedef Ps3LibReportEvtData_u MgrReportEvtData_u; + +typedef enum Ps3HardResetEvtMoudle +{ + HARD_RESET_BY_HOST = 0, + HARD_RESET_BY_BACKEND, + HARD_RESET_BY_FRONTEND, +} Ps3HardResetEvtMoudle_e; + +typedef enum SporStatus { + SPOR_DUMP_SUCCESS, + SPOR_DUMP_RUNNING, + SPOR_DUMP_NVSRAM_INIT_FAILED, + SPOR_DUMP_NVSRAM_WR_FAILED, + SPOR_DUMP_ONF_INIT_FAILED, + SPOR_DUMP_MM_INIT_FAILED, + SPOR_DUMP_CM_INIT_FAILED, + SPOR_DUMP_FAILED, + SPOR_LOAD_SUCCESS, + SPOR_LOAD_NVSRAM_INIT_FAILED, + SPOR_LOAD_NVSRAM_WR_FAILED, + SPOR_LOAD_ONF_INIT_FAILED, + SPOR_LOAD_MM_INIT_FAILED, + SPOR_LOAD_CM_INIT_FAILED, + SPOR_LOAD_FAILED, + SPOR_STATUS_NULL = 0xFF, +}SporStatus_e; + +#pragma pack() + + +typedef enum MgrEventModule +{ + PS3_EVT_HOST_DRV_X2 = 1, + PS3_EVT_HOST_DRV_X16, + PS3_EVT_HOST_DRV_VD_X2, + PS3_EVT_HOST_DRV_VD_X16, + PS3_EVT_METDATA, + PS3_EVT_DEV_MANAGE, + PS3_EVT_IOC_ALARM_PWM, + PS3_EVT_IOC_ALARM_LED, + PS3_EVT_IOC_ALARM, + PS3_EVT_IOC_MGR, + PS3_EVT_HOST_SIM, + PS3_EVT_HOST_SIM_X2, + PS3_EVT_HOST_SIM_X16, + PS3_EVT_MODULE_MAX, +}MgrEventModule_e; + +typedef struct PS3EventFilter +{ + U8 eventType; + U8 eventCodeCnt; + U8 reserved[6]; + U16 eventCodeTable[0]; +}PS3EventFilter_s; + +typedef void (* eventNoticeCb)(void *pCtxt); + +typedef S32 (* mgrEventNoticeFunc)(U32 eventCode, MgrReportEvtData_u *pEventDesc, + void *pCtxt, eventNoticeCb noticeCountOp); +typedef void (* eventPublishCb)(void *pPublishInfo); + +S32 mgrEvtCancleSubscribe(U8 moduleId); + +S32 mgrDrvEvtWebSubsCancel(U8 funcType); + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_mgr_evt_common.h b/drivers/scsi/ps3stor/include/ps3_mgr_evt_common.h new file mode 100644 index 0000000000000000000000000000000000000000..088f73210a57dd90d87de03a45161a6a47131876 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_mgr_evt_common.h @@ -0,0 +1,83 @@ +#ifndef __PS3_MGR_EVT_COMMON_H__ +#define __PS3_MGR_EVT_COMMON_H__ + +#define MGR_EVT_TYPE_OFFSET (80) +#define MGR_EVT_LOG_INFO_MAX_SIZE (116) + +#if !(defined(PS3_PRODUCT_EXPANDER) || defined(PS3_PRODUCT_SWITCH)) +#define MGR_EVT_TYPE_EXTEND_OFFSET (200) +#define MGR_EVT_EXTEND_TYPE_START (17) + + +#define MGR_EVT_TYPE_BASE_LOCAL(sn) (sn < MGR_EVT_EXTEND_TYPE_START ? (sn - 1) * MGR_EVT_TYPE_OFFSET : \ + MGR_EVT_TYPE_OFFSET * (MGR_EVT_EXTEND_TYPE_START - 1) \ + + MGR_EVT_TYPE_EXTEND_OFFSET * (sn - MGR_EVT_EXTEND_TYPE_START)) + + + +#define MGR_EVENT_CODE_2_TYPE(code) (code <= MGR_EVT_TYPE_OFFSET * (MGR_EVT_EXTEND_TYPE_START - 1) ? \ + ((code) / MGR_EVT_TYPE_OFFSET + 1) : \ + (code - MGR_EVT_TYPE_OFFSET * (MGR_EVT_EXTEND_TYPE_START - 1)) / MGR_EVT_TYPE_EXTEND_OFFSET \ + + MGR_EVT_EXTEND_TYPE_START) + +#else +#define MGR_EVT_TYPE_BASE_LOCAL(sn) ((sn - 1) * MGR_EVT_TYPE_OFFSET) +#define MGR_EVENT_CODE_2_TYPE(code) ((code) / MGR_EVT_TYPE_OFFSET + 1) +#endif + +#define PS3_EVT_TYPE_OFFSET (30) +#define PS3_EVT_EXPOSE_OFFSET (28) +#define PS3_EVT_BATCH_OFFSET (27) +#define PS3_EVT_ATTR_OFFSET (16) +#define PS3_EVT_LEVEL_OFFSET (12) +#define PS3_EVT_CODE_OFFSET (0) + +#define PS3_MAKE_EVT_CODE(type, expose, batch, attr, level, code) \ + ((((type)&0b11) << PS3_EVT_TYPE_OFFSET) | (((expose)&0b11) << PS3_EVT_EXPOSE_OFFSET) | \ + (((batch)&0b1) << PS3_EVT_BATCH_OFFSET) | (((attr)&0x3F) << PS3_EVT_ATTR_OFFSET) | \ + (((level)&0xF) << PS3_EVT_LEVEL_OFFSET) | ((code)&0xFFF) << PS3_EVT_CODE_OFFSET) +#define PS3_MK_EVT(type, expose, batch, attr, level, code) \ + (PS3_MAKE_EVT_CODE(type, expose, batch, attr, level, code)) + +#define PS3_EVT_TYPE(evtcode) ((evtcode >> PS3_EVT_TYPE_OFFSET) & 0b11) +#define PS3_EVT_EXPOSE(evtcode) ((evtcode >> PS3_EVT_EXPOSE_OFFSET) & 0b11) +#define PS3_EVT_IS_BATCH(evtcode) ((evtcode >> PS3_EVT_BATCH_OFFSET) & 0b1) +#define PS3_EVT_ATTR_EXTEND(evtcode) ((U8)((evtcode >> PS3_EVT_ATTR_OFFSET) & 0x3F)) +#define PS3_EVT_LEVEL(evtcode) ((evtcode >> PS3_EVT_LEVEL_OFFSET) & 0xF) +#define PS3_EVT_CODE(evtcode) (((U32)evtcode >> PS3_EVT_CODE_OFFSET) & 0xFFF) + +typedef enum Ps3EventType +{ + PS3_EVT_TYPE_UNKNOWN = 0b0000, + PS3_EVT_TYPE_RAIDHBA = 0b0001, + PS3_EVT_TYPE_EXPANDER = 0b0010, + PS3_EVT_TYPE_PCIESWITCH = 0b0011, +}Ps3EventType_e; + +typedef enum Ps3EventExpose +{ + PS3_EVT_EXP_UNKNOWN = 0b0000, + PS3_EVT_EXP_EXTERNAL = 0b0001, + PS3_EVT_EXP_INTERNAL = 0b0010, + PS3_EVT_EXP_MAX = 0b0011, +}Ps3EventExpose_e; + +typedef enum MgrEventLevel +{ + PS3_EVT_CLASS_UNKNOWN = 0b0000, + PS3_EVT_CLASS_DEBUG = 0b0011, + PS3_EVT_CLASS_PROCESS = 0b0101, + PS3_EVT_CLASS_INFO = 0b0001, + PS3_EVT_CLASS_WARNING = 0b0010, + PS3_EVT_CLASS_CRITICAL = 0b0100, + PS3_EVT_CLASS_FATAL = 0b1000, + PS3_EVT_CLASS_MAX, +}MgrEventLevel_e; + +typedef enum MgrEventIsBatch +{ + PS3_EVT_IS_BATCH_FALSE = 0b0, + PS3_EVT_IS_BATCH_TRUE = 0b1, +}MgrEventIsBatch_e; + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_mgr_evt_raidhba.h b/drivers/scsi/ps3stor/include/ps3_mgr_evt_raidhba.h new file mode 100644 index 0000000000000000000000000000000000000000..9e6cdf658a6a32651d85ef2818a1958a977e9948 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_mgr_evt_raidhba.h @@ -0,0 +1,1509 @@ +#ifndef __PS3_MGR_EVT_RAIDHBA_H__ +#define __PS3_MGR_EVT_RAIDHBA_H__ +#include "ps3_mgr_evt_common.h" + +typedef enum MgrEvtType +{ + PS3_EVT_ILLEGAL_TYPE = 0, + PS3_EVT_SAS_INFO = 0x1, + PS3_EVT_PD_COUNT = 0x2, + PS3_EVT_VD_COUNT = 0x4, + PS3_EVT_CTRL_INFO = 0x8, + PS3_EVT_PD_ATTR = 0x10, + PS3_EVT_VD_ATTR = 0x20, + PS3_EVT_DG_INFO = 0x40, + PS3_EVT_BBU_INFO = 0x80, + PS3_EVT_CONFIG = 0x100, + PS3_EVT_IO_INFO = 0x200, + PS3_EVT_UKEY_INFO = 0x400, + PS3_EVT_HWR_INFO = 0x800, + PS3_EVT_ALARM_INFO = 0x1000, + PS3_EVT_ECC_INFO = 0x2000, + PS3_EVT_UPGRADE_INFO = 0x4000, + PS3_EVT_TEMP_INFO = 0x8000, + PS3_EVT_PD_ATTR_EXTEND = 0x10000, +}MgrEvtType_e; + +static inline const S8 * nameMgrEvtType(U32 e) +{ + switch(e) { + case PS3_EVT_SAS_INFO: + return "PS3_EVT_SAS_INFO"; + break; + case PS3_EVT_PD_COUNT: + return "PS3_EVT_PD_COUNT"; + break; + case PS3_EVT_VD_COUNT: + return "PS3_EVT_VD_COUNT"; + break; + case PS3_EVT_CTRL_INFO: + return "PS3_EVT_CTRL_INFO"; + break; + case PS3_EVT_PD_ATTR: + return "PS3_EVT_PD_ATTR"; + break; + case PS3_EVT_VD_ATTR: + return "PS3_EVT_VD_ATTR"; + break; + case PS3_EVT_DG_INFO: + return "PS3_EVT_DG_INFO"; + break; + case PS3_EVT_BBU_INFO: + return "PS3_EVT_BBU_INFO"; + break; + case PS3_EVT_CONFIG: + return "PS3_EVT_CONFIG"; + break; + case PS3_EVT_IO_INFO: + return "PS3_EVT_IO_INFO"; + break; + case PS3_EVT_UKEY_INFO: + return "PS3_EVT_UKEY_INFO"; + break; + case PS3_EVT_HWR_INFO: + return "PS3_EVT_HWR_INFO"; + break; + case PS3_EVT_ALARM_INFO: + return "PS3_EVT_ALARM_INFO"; + break; + case PS3_EVT_ECC_INFO: + return "PS3_EVT_ECC_INFO"; + break; + case PS3_EVT_UPGRADE_INFO: + return "PS3_EVT_UPGRADE_INFO"; + break; + case PS3_EVT_TEMP_INFO: + return "PS3_EVT_TEMP_INFO"; + break; + case PS3_EVT_PD_ATTR_EXTEND: + return "PS3_EVT_PD_ATTR_EXTEND"; + break; + default : + return "PS3_EVT_ILLEGAL_TYPE"; + break; + } +} + +enum +{ + PS3_EVT_SAS_INFO_LOCAL = 1, + PS3_EVT_PD_COUNT_LOCAL = 2, + PS3_EVT_VD_COUNT_LOCAL = 3, + PS3_EVT_CTRL_INFO_LOCAL = 4, + PS3_EVT_PD_ATTR_LOCAL = 5, + PS3_EVT_VD_ATTR_LOCAL = 6, + PS3_EVT_DG_INFO_LOCAL = 7, + PS3_EVT_BBU_INFO_LOCAL = 8, + PS3_EVT_CONFIG_LOCAL = 9, + PS3_EVT_IO_INFO_LOCAL = 10, + PS3_EVT_UKEY_INFO_LOCAL = 11, + PS3_EVT_HWR_INFO_LOCAL = 12, + PS3_EVT_ALARM_INFO_LOCAL = 13, + PS3_EVT_ECC_INFO_LOCAL = 14, + PS3_EVT_UPGRADE_INFO_LOCAL = 15, + PS3_EVT_TEMP_INFO_LOCAL = 16, + PS3_EVT_PD_ATTR_EXTEND_LOCAL = 17, + PS3_EVT_DEFAULT_UNUSED_LOCAL, + PS3_EVT_MAX_TYPE_LOCAL, +}; + +static inline const S8 * nameMgrEvtLocalType(U32 e) +{ + switch(e) { + case PS3_EVT_SAS_INFO_LOCAL: + return "PS3_EVT_SAS_INFO_LOCAL"; + break; + case PS3_EVT_PD_COUNT_LOCAL: + return "PS3_EVT_PD_COUNT_LOCAL"; + break; + case PS3_EVT_VD_COUNT_LOCAL: + return "PS3_EVT_VD_COUNT_LOCAL"; + break; + case PS3_EVT_CTRL_INFO_LOCAL: + return "PS3_EVT_CTRL_INFO_LOCAL"; + break; + case PS3_EVT_PD_ATTR_LOCAL: + return "PS3_EVT_PD_ATTR_LOCAL"; + break; + case PS3_EVT_VD_ATTR_LOCAL: + return "PS3_EVT_VD_ATTR_LOCAL"; + break; + case PS3_EVT_DG_INFO_LOCAL: + return "PS3_EVT_DG_INFO_LOCAL"; + break; + case PS3_EVT_BBU_INFO_LOCAL: + return "PS3_EVT_BBU_INFO_LOCAL"; + break; + case PS3_EVT_CONFIG_LOCAL: + return "PS3_EVT_CONFIG_LOCAL"; + break; + case PS3_EVT_IO_INFO_LOCAL: + return "PS3_EVT_IO_INFO_LOCAL"; + break; + case PS3_EVT_UKEY_INFO_LOCAL: + return "PS3_EVT_UKEY_INFO_LOCAL"; + break; + case PS3_EVT_HWR_INFO_LOCAL: + return "PS3_EVT_HWR_INFO_LOCAL"; + break; + case PS3_EVT_ALARM_INFO_LOCAL: + return "PS3_EVT_ALARM_INFO_LOCAL"; + break; + case PS3_EVT_ECC_INFO_LOCAL: + return "PS3_EVT_ECC_INFO_LOCAL"; + break; + case PS3_EVT_UPGRADE_INFO_LOCAL: + return "PS3_EVT_UPGRADE_INFO_LOCAL"; + break; + case PS3_EVT_TEMP_INFO_LOCAL: + return "PS3_EVT_TEMP_INFO_LOCAL"; + break; + case PS3_EVT_PD_ATTR_EXTEND_LOCAL: + return "PS3_EVT_PD_ATTR_EXTEND_LOCAL"; + break; + default : + return "PS3_EVT_ILLEGAL_TYPE"; + break; + } +} + +enum MgrEvtSASInfoCode +{ + MGR_EVT_SAS_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_SAS_INFO_LOCAL), + MGR_EVT_SAS_EXPANDER_IN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x1), + MGR_EVT_SAS_EXPANDER_OUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_SAS_START + 0x2), + MGR_EVT_SAS_EXPANDER_UPDATE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x3), + MGR_EVT_SAS_EXPANDER_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x4), + MGR_EVT_ENCL_TEMP_NORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x5), + MGR_EVT_ENCL_TEMP_WARNING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_SAS_START + 0x6), + MGR_EVT_ENCL_TEMP_CRITICAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_SAS_START + 0x7), + MGR_EVT_TOPO_LOOP = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_SAS_START + 0x8), + MGR_EVT_LOOP_RESOLUTION = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x9), + MGR_EVT_CASCADED_SCAN_SMP_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_SAS_START + 0xa), + MGR_EVT_ENCL_EXCEED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0xb), + MGR_EVT_TRI_MODE_SWITCH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0xc), + MGR_EVT_CHANGE_PHY_BY_USER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0xd), + MGR_EVT_REV_HIBERNATE_CMD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0xe), + MGR_EVT_PHY_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_SAS_START + 0xf), + MGR_EVT_INQUIRY_INFO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x10), + MGR_EVT_SAS_SATA_LINK_SPEED_NOMATCH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_SAS_START + 0x11), + MGR_EVT_SAS_SATA_LN_EXCEPTION = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_SAS_START + 0x12), + MGR_EVT_SAS_SATA_DRIVER_INFO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_SAS_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_SAS_START + 0x13), + MGR_EVT_SAS_END = (MGR_EVT_SAS_START+0x14), +}; + +enum MgrEvtPdCountCode +{ + MGR_EVT_PD_COUNT_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_PD_COUNT_LOCAL), + MGR_EVT_DEVM_DISK_IN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x1), + MGR_EVT_DEVM_DISK_OUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x2), + MGR_EVT_MULITPILE_PD_IN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x3), + MGR_EVT_MULITPILE_PD_OUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x4), + MGR_EVT_DEVM_JBOD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x5), + MGR_EVT_DEVM_READY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x6), + MGR_EVT_MULITPILE_JBOD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x7), + MGR_EVT_MULITPILE_READY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x8), + MGR_EVT_BACKPLANE_ON = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0x9), + MGR_EVT_BACKPLANE_OFF = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0xa), + MGR_EVT_MULITPILE_PD_STATE_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0xb), + MGR_EVT_DEVM_DISK_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0xc), + MGR_EVT_DEFAULT_UNUSED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0xd), + MGR_EVT_PD_PRE_READY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_INTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_COUNT_START + 0xe), + MGR_EVT_PD_COUNT_END = (MGR_EVT_PD_COUNT_START+0xf), +}; + +enum MgrEvtVdCountCode +{ + MGR_EVT_VD_COUNT_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_VD_COUNT_LOCAL), + MGR_EVT_VD_OPTIMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x1), + MGR_EVT_VD_PARTIAL_DEGRADE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_COUNT_START + 0x2), + MGR_EVT_VD_DEGRADE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_COUNT_START + 0x3), + MGR_EVT_VD_CREATED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x4), + MGR_EVT_VD_DELETED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x5), + MGR_EVT_VD_HIDDEN_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x6), + MGR_EVT_MULITPILE_VD_IN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x7), + MGR_EVT_MULITPILE_VD_OUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x8), + MGR_EVT_VD_UNLOCK = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_COUNT_START + 0x9), + MGR_EVT_VD_OFFLINE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_COUNT_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_COUNT_START + 0xa), + MGR_EVT_VD_COUNT_END = (MGR_EVT_VD_COUNT_START+0xb), +}; + +enum MgrEvtCtrlInfoCode +{ + MGR_EVT_CTRL_INFO_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_CTRL_INFO_LOCAL), + MGR_EVT_CTRL_REBOOT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1), + MGR_EVT_CTRL_SHUTDOWN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2), + MGR_EVT_CTRL_TIME_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x3), + MGR_EVT_CTRL_EVENT_LOG_CLEARED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x4), + MGR_EVT_CTRL_RBLD_RATE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x5), + MGR_EVT_CTRL_ENABLEMOVEBACK_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x6), + MGR_EVT_CTRL_ENABLENCQ_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x7), + MGR_EVT_CTRL_AUTO_REBUILD_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x8), + MGR_EVT_CTRL_EGHS_READY_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x9), + MGR_EVT_CTRL_EGHS_SPARE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0xa), + MGR_EVT_CTRL_BGI_RATE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0xb), + MGR_EVT_CTRL_MIGRATE_RATE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0xc), + MGR_EVT_CTRL_CC_RATE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0xd), + MGR_EVT_CTRL_DIRECT_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0xe), + MGR_EVT_CTRL_PR_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0xf), + MGR_EVT_CTRL_PR_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x10), + MGR_EVT_CTRL_PR_REMINDER_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x11), + MGR_EVT_CTRL_PR_RESUME = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x12), + MGR_EVT_CTRL_PR_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x13), + MGR_EVT_CTRL_PR_RATE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x14), + MGR_EVT_CTRL_PR_CANT_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x15), + MGR_EVT_CTRL_PR_PROP_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x16), + MGR_EVT_CTRL_PARAM_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x17), + MGR_EVT_CTRL_AUTO_CC_PARAM_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x18), + MGR_EVT_CTRL_RECOVERY_FACTORY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x19), + MGR_EVT_CTRL_PROFILEID_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1a), + MGR_EVT_CTRL_SANPSHOT_CREATE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1b), + MGR_EVT_CTRL_SANPSHOT_DELETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1c), + MGR_EVT_CTRL_ENABLEPDM_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1d), + MGR_EVT_CTRL_PDMSUPPORTREADYPD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1e), + MGR_EVT_CTRL_PDMTIMERINTERVAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x1f), + MGR_EVT_CTRL_SECURITY_KEY_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x20), + MGR_EVT_CTRL_SECURITY_KEY_CREATE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x21), + MGR_EVT_CTRL_SECURITY_KEY_DESTROY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x22), + MGR_EVT_CTRL_SECURITY_KEY_ESCROW = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x23), + MGR_EVT_CTRL_SECURITY_KEY_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x24), + MGR_EVT_CTRL_SECURITY_KEY_INVALID = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x25), + MGR_EVT_AUTOCONFIG = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x26), + MGR_EVT_CTRL_FOREIGN_IMPORTED_ALL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x27), + MGR_EVT_CTRL_FOREIGN_CLEAR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x28), + MGR_EVT_CTRL_FOREIGN_IMPORT_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x29), + MGR_EVT_CTRL_FOREIGN_IMPORT_PART_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2a), + MGR_EVT_CTRL_FOREIGN_IMPORT_FAIL_PDS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2b), + MGR_EVT_CTRL_FOREIGN_PD_DETECTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2c), + MGR_EVT_PD_INSERT_TO_DG = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2d), + MGR_EVT_PD_IMPORT_TO_DG = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2e), + MGR_EVT_HARD_RESET = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x2f), + MGR_EVT_DPF_CFG_MODIFY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x30), + MGR_EVT_SPOR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x31), + MGR_EVT_ONF_ABNORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_CTRL_INFO_START + 0x32), + MGR_EVT_CTRL_LOADED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x33), + MGR_EVT_MAIN_MEDIUM_NOT_AVAILABLE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_CTRL_INFO_START + 0x34), + MGR_EVT_BACKUP_MEDIUM_NOT_AVAILABLE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_CTRL_INFO_START + 0x35), + MGR_EVT_MEDIUM_DATA_RECOVER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x36), + MGR_EVT_CACHE_PROTECTION_CMPT_READY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x37), + MGR_EVT_CACHE_PROTECTION_CMPT_NOT_READY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x38), + MGR_EVT_CACHE_PROTECTION_CMPT_INSTABLE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_CTRL_INFO_START + 0x39), + MGR_EVT_INIT_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x3a), + MGR_EVT_CTRL_POWER_MODE_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CTRL_INFO_START + 0x3b), + MGR_EVT_CTRL_INFO_END = (MGR_EVT_CTRL_INFO_START+0x3c), +}; + +enum MgrEvtPdAttrCode +{ + MGR_EVT_PD_ATTR_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_PD_ATTR_LOCAL), + MGR_EVT_PD_INFO_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x1), + MGR_EVT_PD_STATE_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x2), + MGR_EVT_PD_MARKED_JBOD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3), + MGR_EVT_PD_MARKED_READY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4), + MGR_EVT_PD_MARKED_ONLINE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x5), + MGR_EVT_PD_MARKED_OFFLINE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x6), + MGR_EVT_PD_MARKED_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x7), + MGR_EVT_PD_MARKED_MISSING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x8), + MGR_EVT_PD_MARKED_REBUILD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x9), + MGR_EVT_PD_MARKED_REPLACE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0xa), + MGR_EVT_PD_MARKED_UNCONFIGUREDBAD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0xb), + MGR_EVT_PD_MARKED_FOREIGN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0xc), + MGR_EVT_PD_NR_GLOBAL_SPARE_ADDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0xd), + MGR_EVT_PD_NR_GLOBAL_SPARE_DELETED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0xe), + MGR_EVT_PD_NR_DEDICATED_SPARE_ADDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0xf), + MGR_EVT_PD_NR_DEDICATED_SPARE_DELETED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x10), + MGR_EVT_PD_R_GLOBAL_SPARE_ADDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x11), + MGR_EVT_PD_R_GLOBAL_SPARE_DELETED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x12), + MGR_EVT_PD_R_DEDICATED_SPARE_ADDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x13), + MGR_EVT_PD_R_DEDICATED_SPARE_DELETED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x14), + MGR_EVT_PD_RBLD_ABORT_BY_USER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x15), + MGR_EVT_PD_RBLD_DONE_PD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x16), + MGR_EVT_PD_RBLD_FAILED_BAD_SOURCE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x17), + MGR_EVT_PD_RBLD_FAILED_BAD_TARGET = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x18), + MGR_EVT_PD_RBLD_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_START + 0x19), + MGR_EVT_PD_RBLD_SUSPENDED_REMINDER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x1a), + MGR_EVT_PD_RBLD_SUSPENDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x1b), + MGR_EVT_PD_RBLD_RESUME = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x1c), + MGR_EVT_PD_RBLD_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x1d), + MGR_EVT_PD_RBLD_START_AUTO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x1e), + MGR_EVT_PD_RBLD_MEDIUM_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_START + 0x1f), + MGR_EVT_PD_EMERGENCY_SPARE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x20), + MGR_EVT_PD_RECOVER_MEDIUM_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_START + 0x21), + MGR_EVT_PD_MOVEBACK_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x22), + MGR_EVT_PD_MOVEBACK_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x23), + MGR_EVT_PD_MOVEBACK_ABORT_FOR_REBUILD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x24), + MGR_EVT_PD_MOVEBACK_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x25), + MGR_EVT_PD_MOVEBACK_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_START + 0x26), + MGR_EVT_PD_MOVEBACK_SUSPENDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x27), + MGR_EVT_PD_MOVEBACK_SUSPENDED_REMINDER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x28), + MGR_EVT_PD_MOVEBACK_RESUME = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x29), + MGR_EVT_PD_MOVEBACK_START_AUTO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x2a), + MGR_EVT_PD_MOVEBACK_FAILED_BAD_SOURCE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x2b), + MGR_EVT_PD_MOVEBACK_FAILED_BAD_TARGET = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x2c), + MGR_EVT_PD_MOVEBACK_ABORT_BY_USER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x2d), + MGR_EVT_PD_MOVEBACK_MEDIUM_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_START + 0x2e), + MGR_EVT_PD_FGI_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x2f), + MGR_EVT_PD_FGI_COMPLETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x30), + MGR_EVT_PD_FGI_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x31), + MGR_EVT_PD_FGI_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_START + 0x32), + MGR_EVT_PD_FGI_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x33), + MGR_EVT_PD_PR_ABORTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_START + 0x34), + MGR_EVT_PD_PR_CORRECTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x35), + MGR_EVT_PD_PR_UNCORRECTABLE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_START + 0x36), + MGR_EVT_PD_PR_FOUND_MEDIUM_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_START + 0x37), + MGR_EVT_PD_PR_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_START + 0x38), + MGR_EVT_PD_SET_BOOT_DRIVE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x39), + MGR_EVT_PD_RESET_BOOT_DRIVE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3a), + MGR_EVT_PD_RESET_BOOT_DRIVE_WITH_DISK_OUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3b), + MGR_EVT_PD_SET_BOOT_DRIVE_WITH_DISK_IN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3c), + MGR_EVT_PD_POWERSAVE_TO_ON = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3d), + MGR_EVT_PD_POWERSAVE_TO_TRANSITION = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3e), + MGR_EVT_PD_TRANSITION_TO_ON = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x3f), + MGR_EVT_PD_TRANSITION_TO_POWERSAVE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x40), + MGR_EVT_PD_ON_TO_POWERSAVE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x41), + MGR_EVT_PD_START_LOCATE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x42), + MGR_EVT_PD_STOP_LOCATE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x43), + MGR_EVT_PD_PFA_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_START + 0x44), + MGR_EVT_PD_NOT_PRESENT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_START + 0x45), + MGR_EVT_DEVM_DISK_FAULT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_START + 0x46), + MGR_EVT_PHY_FLASHOFFLINE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_START + 0x47), + MGR_EVT_PHY_FLASHONLINE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x48), + MGR_EVT_NFR_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x49), + MGR_EVT_NFR_REPAIRED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4a), + MGR_EVT_NFR_REPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4b), + MGR_EVT_NFR_STOP = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4c), + MGR_EVT_PD_DOWNLOAD_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4d), + MGR_EVT_PD_DOWNLOAD_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4e), + MGR_EVT_NVME_PHY_BAD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_START + 0x4f), + MGR_EVT_PD_ATTR_END = (MGR_EVT_PD_ATTR_START+0x50), +}; + +enum MgrEvtVdAttrCode +{ + MGR_EVT_VD_ATTR_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_VD_ATTR_LOCAL), + MGR_EVT_MULITPILE_VD_STATE_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x1), + MGR_EVT_VD_OFFLINE_OLD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x2), + MGR_EVT_VD_LOCK = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x3), + MGR_EVT_VD_PASSWD_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x4), + MGR_EVT_VD_SETTINGS_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x5), + MGR_EVT_VD_PD_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_INTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x6), + MGR_EVT_VD_STATE_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x7), + MGR_EVT_PD_RBLD_DONE_LD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x8), + MGR_EVT_VD_FGI_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x9), + MGR_EVT_VD_FGI_COMPLETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0xa), + MGR_EVT_VD_FGI_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_ATTR_START + 0xb), + MGR_EVT_VD_FGI_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_VD_ATTR_START + 0xc), + MGR_EVT_VD_FGI_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0xd), + MGR_EVT_VD_BGI_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0xe), + MGR_EVT_VD_BGI_COMPLETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0xf), + MGR_EVT_VD_BGI_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_ATTR_START + 0x10), + MGR_EVT_VD_BGI_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_VD_ATTR_START + 0x11), + MGR_EVT_VD_BGI_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x12), + MGR_EVT_VD_BGI_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x13), + MGR_EVT_VD_BGI_REMINDER_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x14), + MGR_EVT_VD_BGI_RESUME = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x15), + MGR_EVT_VD_BGI_CORRECTABLE_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x16), + MGR_EVT_VD_BGI_UNCORRECTABLE_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x17), + MGR_EVT_VD_ALTER_ATTR_BY_MIGRATION = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x18), + MGR_EVT_VD_BBM_CLEARED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x19), + MGR_EVT_VD_BBM_PERCENT_FULL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x1a), + MGR_EVT_VD_BBM_100_FULL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x1b), + MGR_EVT_VD_BBM_LOG_FULL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x1c), + MGR_EVT_VD_BBM_LOG_RCT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x1d), + MGR_EVT_VD_BBM_LOG_WCT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_ATTR_START + 0x1e), + MGR_EVT_VD_BBM_DEL_RCT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x1f), + MGR_EVT_VD_CC_ABORTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x20), + MGR_EVT_VD_CC_CORRECTED_MEDIUM_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x21), + MGR_EVT_VD_CC_DOUBLE_MEDIUM_ERRORS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x22), + MGR_EVT_VD_CC_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x23), + MGR_EVT_VD_CC_DONE_INCON = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x24), + MGR_EVT_VD_CC_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_ATTR_START + 0x25), + MGR_EVT_VD_CC_FAILED_UNCOR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x26), + MGR_EVT_VD_CC_INCONSISTENT_PARITY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x27), + MGR_EVT_VD_CC_INCONSISTENT_PARITY_LOGGING_DISABLED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x28), + MGR_EVT_VD_CC_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_VD_ATTR_START + 0x29), + MGR_EVT_VD_CC_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x2a), + MGR_EVT_VD_CC_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x2b), + MGR_EVT_VD_CC_REMINDER_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x2c), + MGR_EVT_VD_CC_RESUME = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x2d), + MGR_EVT_VD_RW_RAID1X_WRITE_CARDBUSY = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x2e), + MGR_EVT_VD_SET_BOOT_DRIVE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x2f), + MGR_EVT_VD_RESET_BOOT_DRIVE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x30), + MGR_EVT_VD_RESET_BOOT_DRIVE_WITH_DISK_OUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x31), + MGR_EVT_VD_SET_BOOT_DRIVE_WITH_DISK_IN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x32), + MGR_EVT_ALL_CONFIGS_MISSING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x33), + MGR_EVT_PDS_MISSING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x34), + MGR_EVT_NVSRAM_RECOVER_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x35), + MGR_EVT_NVSRAM_UPDATE_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x36), + MGR_EVT_VD_ERASE_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x37), + MGR_EVT_VD_ERASE_COMPLETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x38), + MGR_EVT_VD_ERASE_DISK_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x39), + MGR_EVT_VD_ERASE_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_VD_ATTR_START + 0x3a), + MGR_EVT_VD_ERASE_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_VD_ATTR_START + 0x3b), + MGR_EVT_VD_ERASE_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x3c), + MGR_EVT_VD_EXPAND_FINISH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x3d), + MGR_EVT_VD_EXPAND_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x3e), + MGR_EVT_VD_FLUSH_CLEAR_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x3f), + MGR_EVT_VD_FLUSH_RECORD_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x40), + MGR_EVT_VD_FLUSH_SET_INCONSIST = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x41), + MGR_EVT_VDS_MISSING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x42), + MGR_EVT_VD_BBM_UNCORRECTABLE_LOGGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x43), + MGR_EVT_VD_FLUSH_CACHE_PINNED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x44), + MGR_EVT_VD_FLUSH_OCR_CACHE_PINNED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x45), + MGR_EVT_VD_FLUSH_CACHE_DISCARDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x46), + MGR_EVT_VD_FLUSH_CACHE_DISCARDED_DEL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x47), + MGR_EVT_VD_FLUSH_CACHE_DESTAGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_VD_ATTR_START + 0x48), + MGR_EVT_VD_CM_RECOVERY_CRC_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_VD_ATTR_START + 0x49), + MGR_EVT_VD_BGI_COMPLETE_UNCOR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_VD_ATTR_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_VD_ATTR_START + 0x4a), + MGR_EVT_VD_ATTR_END = (MGR_EVT_VD_ATTR_START+0x4b), +}; + +enum MgrEvtDgInfoCode +{ + MGR_EVT_DG_INFO_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_DG_INFO_LOCAL), + MGR_EVT_DG_CREATED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0x1), + MGR_EVT_DG_DELETED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0x2), + MGR_EVT_DG_SETTING_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0x3), + MGR_EVT_DG_MIGRATION_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0x4), + MGR_EVT_DG_MIGRATION_RECOVER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0x5), + MGR_EVT_DG_MIGRATION_SUCCESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0x6), + MGR_EVT_DG_MIGRATION_ALLOC_RESOURCE_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_DG_INFO_START + 0x7), + MGR_EVT_DG_MIGRATION_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_DG_INFO_START + 0x8), + MGR_EVT_DG_MIGRATION_RECOVER_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_DG_INFO_START + 0x9), + MGR_EVT_DG_MIGRATION_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_DG_INFO_START + 0xa), + MGR_EVT_DG_MIGRATION_INTERNAL_WARNING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_DG_INFO_START + 0xb), + MGR_EVT_DG_PRSWITCH_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_DG_INFO_START + 0xc), + MGR_EVT_DG_PR_ABORTED_WM_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_DG_INFO_START + 0xd), + MGR_EVT_DG_PR_ABORTED_SPINUP_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_DG_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_DG_INFO_START + 0xe), + MGR_EVT_DG_INFO_END = (MGR_EVT_DG_INFO_START+0xf), +}; + +enum MgrEvtBbuInfoCode +{ + MGR_EVT_BBU_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_BBU_INFO_LOCAL), + MGR_EVT_BBU_PRESENT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x1), + MGR_EVT_BBU_NOT_PRESENT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x2), + MGR_EVT_BBU_GOOD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x3), + MGR_EVT_BBU_BAD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0x4), + MGR_EVT_BBU_CAP_BELOW_THRESHOLD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x5), + MGR_EVT_BBU_CAP_ABOVE_THRESHOLD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x6), + MGR_EVT_BBU_CHARGE_STATUS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x7), + MGR_EVT_BBU_CHARGE_COMPLETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x8), + MGR_EVT_BBU_INSERT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x9), + MGR_EVT_BBU_ABSENT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0xa), + MGR_EVT_BBU_TEMPERATURE_NORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0xb), + MGR_EVT_BBU_TEMPERATURE_HIGH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_BBU_START + 0xc), + MGR_EVT_BBU_VOLTAGE_NORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0xd), + MGR_EVT_BBU_VOLTAGE_HIGH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0xe), + MGR_EVT_BBU_CURRENT_NORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0xf), + MGR_EVT_BBU_CURRENT_HIGH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0x10), + MGR_EVT_BBU_LOAD_NORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x11), + MGR_EVT_BBU_VOLTAGE_LOW = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0x12), + MGR_EVT_BBU_BATTERY_CAP_ABOVE_SOH_THRESHOLD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x13), + MGR_EVT_BBU_BATTERY_CAP_BELOW_SOH_THRESHOLD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_BBU_START + 0x14), + MGR_EVT_BBU_LEARN_STAGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x15), + MGR_EVT_BBU_LEARN_REQUESTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0x16), + MGR_EVT_BBU_LEARN_POSTPONED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x17), + MGR_EVT_BBU_LEARN_TIMEOUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_BBU_START + 0x18), + MGR_EVT_BBU_LEARN_MANUAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_BBU_START + 0x19), + MGR_EVT_BBU_LEARN_RESCHEDULED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x1a), + MGR_EVT_BBU_PROPERTIES_CHANGED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_BBU_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_BBU_START + 0x1b), + MGR_EVT_BBU_END = (MGR_EVT_BBU_START+0x1c), +}; + +enum MgrEvtConfigCode +{ + MGR_EVT_CONFIG_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_CONFIG_LOCAL), + MGR_EVT_CONFIG_INFO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x1), + MGR_EVT_CONFIG_FLASH_READ_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x2), + MGR_EVT_CONFIG_FLASH_WRITE_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x3), + MGR_EVT_CONFIG_NVSRAM_READ_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x4), + MGR_EVT_CONFIG_NVSRAM_WRITE_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x5), + MGR_EVT_CONFIG_VERSION_MISMATCH = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x6), + MGR_EVT_CONFIG_MEDIA_VALUE_CHECK_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x7), + MGR_EVT_CONFIG_ERASE_NVSRAM = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x8), + MGR_EVT_PHY_LINKSPEED_CFG_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_CONFIG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_CONFIG_START + 0x9), + MGR_EVT_CONFIG_END = (MGR_EVT_CONFIG_START+0xa), +}; + +enum MgrEvtIoInfoCode +{ + MGR_EVT_IO_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_IO_INFO_LOCAL), + MGR_EVT_IO_TEST = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_IO_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_IO_START + 0x1), + MGR_EVT_IO_SENSE_DATA = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_IO_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_IO_START + 0x2), + MGR_EVT_DEVICE_RESET = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_IO_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_IO_START + 0x3), + MGR_EVT_NVME_DEVICE_RESET = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_IO_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_IO_START + 0x4), + MGR_EVT_DEVICE_ABNORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_IO_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_IO_START + 0x5), + MGR_EVT_IO_SENSE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_IO_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_IO_START + 0x6), + MGR_EVT_IO_END = (MGR_EVT_IO_START+0x7), +}; + +enum MgrEvtUkeyInfoCode +{ + MGR_EVT_UKEY_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_UKEY_INFO_LOCAL), + MGR_EVT_UKEY_INSERT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UKEY_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UKEY_START + 0x1), + MGR_EVT_UKEY_DEGRADE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UKEY_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UKEY_START + 0x2), + MGR_EVT_RAID_KEY_OVERCURRENT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UKEY_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_UKEY_START + 0x3), + MGR_EVT_RAID_KEY_OVERCURRENT_RECOVER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UKEY_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UKEY_START + 0x4), + MGR_EVT_UKEY_END = (MGR_EVT_UKEY_START+0x5), +}; + +enum MgrEvtHwRInfoCode +{ + MGR_EVT_HWR_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_HWR_INFO_LOCAL), + MGR_EVT_HWR_HAC_RESET_BEGIN = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_HWR_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_HWR_START + 0x1), + MGR_EVT_HWR_HAC_RESET_END = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_HWR_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_HWR_START + 0x2), + MGR_EVT_REPORT_HAC_ECC = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_HWR_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_HWR_START + 0x3), + MGR_EVT_HWR_END = (MGR_EVT_HWR_START+0x4), +}; + +enum MgrEvtAlarmInfoCode +{ + MGR_EVT_ALARM_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_ALARM_INFO_LOCAL), + MGR_EVT_ALARM_ENABLED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ALARM_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_ALARM_START + 0x1), + MGR_EVT_ALARM_DISABLED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ALARM_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_ALARM_START + 0x2), + MGR_EVT_ALARM_END = (MGR_EVT_ALARM_START+0x3), +}; + +enum MgrEvtEccInfoCode +{ + MGR_EVT_ECC_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_ECC_INFO_LOCAL), + MGR_EVT_ECC_CNT_EXCEED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ECC_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_ECC_START + 0x1), + MGR_EVT_ECC_ERR_INTR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ECC_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_ECC_START + 0x2), + MGR_EVT_ECC_CNT_CLEAR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ECC_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_ECC_START + 0x3), + MGR_EVT_ECC_CLI_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ECC_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_ECC_START + 0x4), + MGR_EVT_ECC_FACTORY_CHANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_INTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_ECC_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_ECC_START + 0x5), + MGR_EVT_ECC_END = (MGR_EVT_ECC_START+0x6), +}; + +enum MgrEvtUpgradeInfoCode +{ + MGR_EVT_UPGRADE_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_UPGRADE_INFO_LOCAL), + MGR_EVT_IMAGE_DOWNLOAD_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x1), + MGR_EVT_IMAGE_AUTHENTICATION_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x2), + MGR_EVT_IMAGE_VERSION_CHECK_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x3), + MGR_EVT_IMAGE_CHECKSUM_CHECK_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x4), + MGR_EVT_IMAGE_FROM_BACKUP = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_UPGRADE_START + 0x5), + MGR_EVT_DEV_OPEN_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x6), + MGR_EVT_DEV_FLASH_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x7), + MGR_EVT_DEV_ERASE_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x8), + MGR_EVT_DEV_CLOSE_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0x9), + MGR_EVT_FLASH_GENERAL_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0xa), + MGR_EVT_FLASH_TIMEOUT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_UPGRADE_START + 0xb), + MGR_EVT_UPGRADE_SUCCESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UPGRADE_START + 0xc), + MGR_EVT_UPGRADE_SYNC_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UPGRADE_START + 0xd), + MGR_EVT_UPGRADE_SYNC_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UPGRADE_START + 0xe), + MGR_EVT_UPGRADE_SYNC_SUCCESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_UPGRADE_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_UPGRADE_START + 0xf), + MGR_EVT_UPGRADE_END = (MGR_EVT_UPGRADE_START+0x10), +}; + +enum MgrEvtTempInfoCode +{ + MGR_EVT_TEMP_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_TEMP_INFO_LOCAL), + MGR_EVT_TEMP_WITHIN_OPTIMAL_RANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_TEMP_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_TEMP_START + 0x1), + MGR_EVT_TEMP_ABOVE_OPTIMAL_RANGE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_TEMP_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_TEMP_START + 0x2), + MGR_EVT_TEMP_WARNING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_TEMP_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_TEMP_START + 0x3), + MGR_EVT_TEMP_CRITICAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_TEMP_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_TEMP_START + 0x4), + MGR_EVT_TEMP_END = (MGR_EVT_TEMP_START+0x5), +}; + +enum MgrEvtPdAttrExtendCode +{ + MGR_EVT_PD_ATTR_EXTEND_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_PD_ATTR_EXTEND_LOCAL), + MGR_EVT_PD_NVME_CMD_ERR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1), + MGR_EVT_PD_NVME_CMD_TO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2), + MGR_EVT_PD_NVME_INSERT_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3), + MGR_EVT_PD_ERASE_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x4), + MGR_EVT_PD_ERASE_COMPLETE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x5), + MGR_EVT_PD_ERASE_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x6), + MGR_EVT_PD_ERASE_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_EXTEND_START + 0x7), + MGR_EVT_PD_ERASE_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x8), + MGR_EVT_PD_PDM_ABORT_BY_USER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x9), + MGR_EVT_PD_PDM_ABORT_FOR_REBUILD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0xa), + MGR_EVT_PD_PDM_ABORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0xb), + MGR_EVT_PD_PDM_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0xc), + MGR_EVT_PD_PDM_FAILED_BAD_SOURCE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0xd), + MGR_EVT_PD_PDM_FAILED_BAD_TARGET = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0xe), + MGR_EVT_PD_PDM_MEDIUM_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0xf), + MGR_EVT_PD_PDM_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_EXTEND_START + 0x10), + MGR_EVT_PD_PDM_REPLACED_SOURCE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x11), + MGR_EVT_PD_PDM_RESUME = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x12), + MGR_EVT_PD_PDM_START_AUTO = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x13), + MGR_EVT_PD_PDM_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x14), + MGR_EVT_PD_PDM_SUSPENDED_REMINDER = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x15), + MGR_EVT_PD_PDM_SUSPENDED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x16), + MGR_EVT_PD_PFA_ERROR_CLEAR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x17), + MGR_EVT_PD_SANITIZE_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x18), + MGR_EVT_PD_FORMAT_START = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x19), + MGR_EVT_PD_SANITIZE_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_PROCESS, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1a), + MGR_EVT_PD_SANITIZE_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1b), + MGR_EVT_PD_FORMAT_DONE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1c), + MGR_EVT_PD_DPF_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1d), + MGR_EVT_PD_MARKED_SHIELD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1e), + MGR_EVT_PD_BBM_CORRECTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x1f), + MGR_EVT_PD_BBM_UNRECOVERABLE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x20), + MGR_EVT_PD_BBM_PUNCTURING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x21), + MGR_EVT_PD_BBM_REASSIGN_WR_ERROR = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x22), + MGR_EVT_PD_UNABLE_ACCESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x23), + MGR_EVT_MULITPILE_PD_UNABLE_ACCESS = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x24), + MGR_EVT_PD_INSERT_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x25), + MGR_EVT_PHY_SATA_D2H_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x26), + MGR_EVT_PD_NOT_INSERTED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x27), + MGR_EVT_PD_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x28), + MGR_EVT_MULITPILE_PD_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_TRUE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x29), + MGR_EVT_NVDATA_INVAILD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2a), + MGR_EVT_PD_RBLD_NON_UNMAP_PD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2b), + MGR_EVT_PD_MOVEBACK_NON_UNMAP_PD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2c), + MGR_EVT_PD_PDM_NON_UNMAP_PD = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2d), + MGR_EVT_PD_RBLD_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2e), + MGR_EVT_PD_SANITIZE_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_PD_ATTR_EXTEND_START + 0x2f), + MGR_EVT_PD_SPIN_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x30), + MGR_EVT_PD_RBLD_MEDIA_MIX_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x31), + MGR_EVT_PD_RBLD_DRIVE_MIX_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x32), + MGR_EVT_PD_PDM_MEDIA_MIX_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x33), + MGR_EVT_PD_PDM_DRIVE_MIX_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x34), + MGR_EVT_PD_MOVEBACK_MEDIA_MIX_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x35), + MGR_EVT_PD_MOVEBACK_DRIVE_MIX_NOT_SUPPORT = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x36), + MGR_EVT_NFR_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x37), + MGR_EVT_PD_RBLD_SMALL_SIZE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x38), + MGR_EVT_PD_MOVEBACK_SMALL_SIZE = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x39), + MGR_EVT_NEGO_LOWER_LINK_SPEED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3a), + MGR_EVT_PCIE_LINK_NEGO_ABNORMAL = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3b), + MGR_EVT_PD_ISOLATION = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3c), + MGR_EVT_PD_REPAIR_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3d), + MGR_EVT_PD_PCIE_LINK_UP_WITHOUT_I2C = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3e), + MGR_EVT_PD_PCIE_ENUMERATE_FAILED = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_PD_ATTR_EXTEND_START + 0x3f), + MGR_EVT_PD_MISS_LIGHTING = PS3_MK_EVT(PS3_EVT_TYPE_RAIDHBA, PS3_EVT_EXP_INTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_PD_ATTR_EXTEND_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_PD_ATTR_EXTEND_START + 0x40), + MGR_EVT_PD_ATTR_EXTEND_END = (MGR_EVT_PD_ATTR_EXTEND_START+0x41), +}; + +static inline U32 ps3EvtCodeExtendToNormal(U32 evtcode) +{ + U32 event = 0; + switch (evtcode){ + case PS3_EVT_PD_ATTR_EXTEND_LOCAL: + event = PS3_EVT_PD_ATTR_LOCAL; + break; + default: + event = evtcode; + } + return event; +} + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_mgr_evt_swexp.h b/drivers/scsi/ps3stor/include/ps3_mgr_evt_swexp.h new file mode 100644 index 0000000000000000000000000000000000000000..f6fd2adf8c397f14174b87687b85ee9f9389c214 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_mgr_evt_swexp.h @@ -0,0 +1,477 @@ +#ifndef __PS3_MGR_EVT_SWEXP_H__ +#define __PS3_MGR_EVT_SWEXP_H__ +#include "ps3_mgr_evt_common.h" + +enum +{ + PS3_EVTLOG_LOCAL = 1, + PS3_EVTLOG_PD_COUNT_LOCAL = 2, + PS3_EVTLOG_CTRL_INFO_LOCAL = 3, + PS3_EVT_EXP_LOCAL = 4, + PS3_EVT_EXP_PHY_LOCAL = 5, + PS3_EVT_EXP_CONN_LOCAL = 6, + PS3_EVTLOG_SW_CTRL_INFO_LOCAL = 7, + PS3_EVTLOG_MAX_TYPE_LOCAL, +}; + +static inline const S8 * nameMgrEvtSwExpType(U32 e) +{ + switch(e) { + case PS3_EVTLOG_LOCAL: + return "PS3_EVTLOG_LOCAL"; + break; + case PS3_EVTLOG_PD_COUNT_LOCAL: + return "PS3_EVTLOG_PD_COUNT_LOCAL"; + break; + case PS3_EVTLOG_CTRL_INFO_LOCAL: + return "PS3_EVTLOG_CTRL_INFO_LOCAL"; + break; + case PS3_EVT_EXP_LOCAL: + return "PS3_EVT_EXP_LOCAL"; + break; + case PS3_EVT_EXP_PHY_LOCAL: + return "PS3_EVT_EXP_PHY_LOCAL"; + break; + case PS3_EVT_EXP_CONN_LOCAL: + return "PS3_EVT_EXP_CONN_LOCAL"; + break; + case PS3_EVTLOG_SW_CTRL_INFO_LOCAL: + return "PS3_EVTLOG_SW_CTRL_INFO_LOCAL"; + break; + default : + return "PS3_EVTLOG_MAX_TYPE_LOCAL"; + break; + } +} + +enum MgrEvtLogCode +{ + MGR_EVTLOG_EVTLOG_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVTLOG_LOCAL), + MGR_SWITCH_EVTLOG_READY = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_EVTLOG_START + 0x1), + MGR_SWITCH_EVTLOG_TEST = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_EVTLOG_START + 0x2), + MGR_SWITCH_EVTLOG_OEM = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_EVTLOG_START + 0x3), + MGR_SWITCH_EVTLOG_BPLANE = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_EVTLOG_START + 0x4), + MGR_SWITCH_EVTLOG_SES = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_EVTLOG_START + 0x5), + MGR_SWITCH_EVTLOG_SCSI = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_EVTLOG_START + 0x6), + MGR_EVTLOG_EVTLOG_END = (MGR_EVTLOG_EVTLOG_START+0x7), +}; + +enum MgrEvtLogPdCountCode +{ + MGR_EVTLOG_PD_COUNT_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVTLOG_PD_COUNT_LOCAL), + MGR_EVTLOG_PD_COUNT_END = (MGR_EVTLOG_PD_COUNT_START+0x1), +}; + +enum MgrEvtLogCtrlInfoCode +{ + MGR_EVTLOG_CTRL_INFO_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVTLOG_CTRL_INFO_LOCAL), + MGR_EVT_EXP_UNUSED1 = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_CTRL_INFO_START + 0x1), + MGR_EVT_EXP_UNUSED2 = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_CTRL_INFO_START + 0x2), + MGR_EVT_EXP_UNUSED3 = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_CTRL_INFO_START + 0x3), + MGR_EVT_EXP_REBOOT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_CTRL_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVTLOG_CTRL_INFO_START + 0x4), + MGR_EVT_EXP_SHUTDOWN = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_CTRL_INFO_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVTLOG_CTRL_INFO_START + 0x5), + MGR_EVT_EXP_EVENT_LOG_CLEARD = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_CTRL_INFO_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVTLOG_CTRL_INFO_START + 0x6), + MGR_EVTLOG_CTRL_INFO_END = (MGR_EVTLOG_CTRL_INFO_START+0x7), +}; + +enum MgrEvtLogExpInfoCode +{ + MGR_EVT_EXP_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_EXP_LOCAL), + MGR_EVT_EXP_CFG_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x1), + MGR_EVT_EXP_CLI_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x2), + MGR_EVT_EXP_SES_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x3), + MGR_EVT_EXP_SMPI_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x4), + MGR_EVT_EXP_SMPT_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x5), + MGR_EVT_EXP_SSPI_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x6), + MGR_EVT_EXP_SSPT_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x7), + MGR_EVT_EXP_SCE_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x8), + MGR_EVT_EXP_TEST_LOG = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x9), + MGR_EVT_EXP_TEST_WARN_LOG = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_WARNING, + MGR_EVT_EXP_START + 0xa), + MGR_EVT_EXP_TEST_CRIT_LOG = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0xb), + MGR_EVT_EXP_TEST_FATAL_LOG = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_EXP_START + 0xc), + MGR_EVT_EXP_CEVA_INIT_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0xd), + MGR_EVT_EXP_CEVA_QUEUE_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0xe), + MGR_EVT_EXP_CEVA_MUTEX_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0xf), + MGR_EVT_EXP_CEVA_FUNC_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x10), + MGR_EVT_EXP_CEVA_READY = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x11), + MGR_EVT_EXP_CEVA_NOT_READY = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x12), + MGR_EVT_EXP_CEVA_SMP_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x13), + MGR_EVT_EXP_CEVA_DMA_RX_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x14), + MGR_EVT_EXP_CEVA_DMA_TX_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x15), + MGR_EVT_EXP_SCE_ERR_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x16), + MGR_EVT_EXP_SCE_ERR_NO_MEM = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x17), + MGR_EVT_EXP_SCE_ERR_NO_SPC_EXP = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x18), + MGR_EVT_EXP_SCE_ERR_NO_SPC_PHY = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x19), + MGR_EVT_EXP_SCE_ERR_NO_SPC_PNED = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x1a), + MGR_EVT_EXP_SCE_ERR_NO_SPC_REMOVE = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x1b), + MGR_EVT_EXP_SCE_ERR_NO_SPC_DOWN = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x1c), + MGR_EVT_EXP_SCE_ERR_BUSY = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x1d), + MGR_EVT_EXP_SCE_ERR_LOOP = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x1e), + MGR_EVT_EXP_SCE_ERR_T2T = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x1f), + MGR_EVT_EXP_SCE_ERR_S2S = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x20), + MGR_EVT_EXP_SCE_ERR_EXP_ON_DIRECT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x21), + MGR_EVT_EXP_SCE_ERR_MULTIPLE_SUB = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x22), + MGR_EVT_EXP_SCE_ERR_SMP_REQ = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x23), + MGR_EVT_EXP_SCE_ERR_SMP_RSP = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x24), + MGR_EVT_EXP_BPP_ERR_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x25), + MGR_EVT_EXP_BPP_ERR_STORM = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x26), + MGR_EVT_EXP_BPP_ERR_SOFT_SEND = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x27), + MGR_EVT_EXP_SMPI_ERR_INIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x28), + MGR_EVT_EXP_SMPI_ERR_TRANSMIT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x29), + MGR_EVT_EXP_SMPI_ERR_RECV_TIMEOUT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x2a), + MGR_EVT_EXP_SMPI_ERR_RECV_DMA = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x2b), + MGR_EVT_EXP_SMPI_ERR_DO_RESET = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x2c), + MGR_EVT_EXP_SMPI_ERR_OTHER = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x2d), + MGR_EVT_EXP_SSPT_I_TIMEOUT_HW = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x2e), + MGR_EVT_EXP_SSPT_I_TIMEOUT_SW = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x2f), + MGR_EVT_EXP_SSPT_RX_DMA_IN_PROGRESS = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x30), + MGR_EVT_EXP_SSPT_START_RX_DMA_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x31), + MGR_EVT_EXP_SSPT_RX_CMD_LEN_ERR = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x32), + MGR_EVT_EXP_SSPT_IO_FULL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x33), + MGR_EVT_EXP_SSPT_IM_FULL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x34), + MGR_EVT_EXP_SSPT_RX_DATA_ERR = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x35), + MGR_EVT_EXP_SSPT_RX_TASK_ERR = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x36), + MGR_EVT_EXP_SSPT_NOT_SUPPORT_TASK_FUNCTION = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x37), + MGR_EVT_EXP_SSPT_NOT_SUPPORT_FRM_TYPE = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x38), + MGR_EVT_EXP_SSPT_TX_PAUSE = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x39), + MGR_EVT_EXP_SSPT_HARD_RESET = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x3a), + MGR_EVT_EXP_SSPT_SOFT_RESET = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x3b), + MGR_EVT_EXP_SSPT_INIT_FAIL = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVT_EXP_START + 0x3c), + MGR_EVT_EXP_SSPT_SET_TIME = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_START + 0x3d), + MGR_EVT_EXP_DOUBLE_BIT_ECC_ERR = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_LOCAL, PS3_EVT_CLASS_FATAL, + MGR_EVT_EXP_START + 0x3e), + MGR_EVT_EXP_END = (MGR_EVT_EXP_START+0x3f), +}; + +enum MgrEvtLogExpPhyInfoCode +{ + MGR_EVT_EXP_PHY_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_EXP_PHY_LOCAL), + MGR_EVT_EXP_DISCONNECT_RAID_HBA = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x1), + MGR_EVT_EXP_DISCONNECT_EXP = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x2), + MGR_EVT_EXP_DISK_OUT = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x3), + MGR_EVT_EXP_PHY_ENABLE = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x4), + MGR_EVT_EXP_PHY_DISABLE = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x5), + MGR_EVT_EXP_PHY_HARD_RESET = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x6), + MGR_EVT_EXP_PHY_LINK_RESET = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_PHY_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_PHY_START + 0x7), + MGR_EVT_EXP_PHY_END = (MGR_EVT_EXP_PHY_START+0x8), +}; + +enum MgrEvtLogExpConnInfoCode +{ + MGR_EVT_EXP_CONN_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVT_EXP_CONN_LOCAL), + MGR_EVT_EXP_CONNECT_RAID_HBA = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_CONN_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_CONN_START + 0x1), + MGR_EVT_EXP_CONNECT_EXP = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_CONN_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_CONN_START + 0x2), + MGR_EVT_EXP_DISK_IN = PS3_MK_EVT(PS3_EVT_TYPE_EXPANDER, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVT_EXP_CONN_LOCAL, PS3_EVT_CLASS_INFO, + MGR_EVT_EXP_CONN_START + 0x3), + MGR_EVT_EXP_CONN_END = (MGR_EVT_EXP_CONN_START+0x4), +}; + +enum MgrEvtLogSwCtrlInfoCode +{ + MGR_EVTLOG_SW_CTRL_INFO_START = MGR_EVT_TYPE_BASE_LOCAL(PS3_EVTLOG_SW_CTRL_INFO_LOCAL), + MGR_SWITCH_EVTLOG_CTRL_REBOOT = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_SW_CTRL_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVTLOG_SW_CTRL_INFO_START + 0x1), + MGR_SWITCH_EVTLOG_CTRL_SHUTDOWN = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_SW_CTRL_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVTLOG_SW_CTRL_INFO_START + 0x2), + MGR_SWITCH_EVTLOG_CTRL_EVENT_LOG_CLEARED = PS3_MK_EVT(PS3_EVT_TYPE_PCIESWITCH, PS3_EVT_EXP_EXTERNAL, + PS3_EVT_IS_BATCH_FALSE, PS3_EVTLOG_SW_CTRL_INFO_LOCAL, PS3_EVT_CLASS_CRITICAL, + MGR_EVTLOG_SW_CTRL_INFO_START + 0x3), + MGR_EVTLOG_SW_CTRL_INFO_END = (MGR_EVTLOG_SW_CTRL_INFO_START+0x4), +}; + +static inline S8 const *swexpEvtLogCodeTrans(U32 opCode) +{ + U32 typeIndex = 0; + U32 codeIndex = 0; + const S8* pEvtTransStr = NULL; + static S8 const *pEvtLogCodeInfo[PS3_EVTLOG_MAX_TYPE_LOCAL][MGR_EVT_TYPE_OFFSET] = { + { + "MGR_EVTLOG_EVTLOG_START", + "MGR_SWITCH_EVTLOG_READY", + "MGR_SWITCH_EVTLOG_TEST", + "MGR_SWITCH_EVTLOG_OEM", + "MGR_SWITCH_EVTLOG_BPLANE", + "MGR_SWITCH_EVTLOG_SES", + "MGR_SWITCH_EVTLOG_SCSI", + }, + { + "MGR_EVTLOG_PD_COUNT_START", + }, + { + "MGR_EVTLOG_CTRL_INFO_START", + "MGR_EVT_EXP_UNUSED1", + "MGR_EVT_EXP_UNUSED2", + "MGR_EVT_EXP_UNUSED3", + "MGR_EVT_EXP_REBOOT", + "MGR_EVT_EXP_SHUTDOWN", + "MGR_EVT_EXP_EVENT_LOG_CLEARD", + }, + { + "MGR_EVT_EXP_START", + "MGR_EVT_EXP_CFG_INIT", + "MGR_EVT_EXP_CLI_INIT", + "MGR_EVT_EXP_SES_INIT", + "MGR_EVT_EXP_SMPI_INIT", + "MGR_EVT_EXP_SMPT_INIT", + "MGR_EVT_EXP_SSPI_INIT", + "MGR_EVT_EXP_SSPT_INIT", + "MGR_EVT_EXP_SCE_INIT", + "MGR_EVT_EXP_TEST_LOG", + "MGR_EVT_EXP_TEST_WARN_LOG", + "MGR_EVT_EXP_TEST_CRIT_LOG", + "MGR_EVT_EXP_TEST_FATAL_LOG", + "MGR_EVT_EXP_CEVA_INIT_FAIL", + "MGR_EVT_EXP_CEVA_QUEUE_FAIL", + "MGR_EVT_EXP_CEVA_MUTEX_FAIL", + "MGR_EVT_EXP_CEVA_FUNC_FAIL", + "MGR_EVT_EXP_CEVA_READY", + "MGR_EVT_EXP_CEVA_NOT_READY", + "MGR_EVT_EXP_CEVA_SMP_FAIL", + "MGR_EVT_EXP_CEVA_DMA_RX_FAIL", + "MGR_EVT_EXP_CEVA_DMA_TX_FAIL", + "MGR_EVT_EXP_SCE_ERR_INIT", + "MGR_EVT_EXP_SCE_ERR_NO_MEM", + "MGR_EVT_EXP_SCE_ERR_NO_SPC_EXP", + "MGR_EVT_EXP_SCE_ERR_NO_SPC_PHY", + "MGR_EVT_EXP_SCE_ERR_NO_SPC_PNED", + "MGR_EVT_EXP_SCE_ERR_NO_SPC_REMOVE", + "MGR_EVT_EXP_SCE_ERR_NO_SPC_DOWN", + "MGR_EVT_EXP_SCE_ERR_BUSY", + "MGR_EVT_EXP_SCE_ERR_LOOP", + "MGR_EVT_EXP_SCE_ERR_T2T", + "MGR_EVT_EXP_SCE_ERR_S2S", + "MGR_EVT_EXP_SCE_ERR_EXP_ON_DIRECT", + "MGR_EVT_EXP_SCE_ERR_MULTIPLE_SUB", + "MGR_EVT_EXP_SCE_ERR_SMP_REQ", + "MGR_EVT_EXP_SCE_ERR_SMP_RSP", + "MGR_EVT_EXP_BPP_ERR_INIT", + "MGR_EVT_EXP_BPP_ERR_STORM", + "MGR_EVT_EXP_BPP_ERR_SOFT_SEND", + "MGR_EVT_EXP_SMPI_ERR_INIT", + "MGR_EVT_EXP_SMPI_ERR_TRANSMIT", + "MGR_EVT_EXP_SMPI_ERR_RECV_TIMEOUT", + "MGR_EVT_EXP_SMPI_ERR_RECV_DMA", + "MGR_EVT_EXP_SMPI_ERR_DO_RESET", + "MGR_EVT_EXP_SMPI_ERR_OTHER", + "MGR_EVT_EXP_SSPT_I_TIMEOUT_HW", + "MGR_EVT_EXP_SSPT_I_TIMEOUT_SW", + "MGR_EVT_EXP_SSPT_RX_DMA_IN_PROGRESS", + "MGR_EVT_EXP_SSPT_START_RX_DMA_FAIL", + "MGR_EVT_EXP_SSPT_RX_CMD_LEN_ERR", + "MGR_EVT_EXP_SSPT_IO_FULL", + "MGR_EVT_EXP_SSPT_IM_FULL", + "MGR_EVT_EXP_SSPT_RX_DATA_ERR", + "MGR_EVT_EXP_SSPT_RX_TASK_ERR", + "MGR_EVT_EXP_SSPT_NOT_SUPPORT_TASK_FUNCTION", + "MGR_EVT_EXP_SSPT_NOT_SUPPORT_FRM_TYPE", + "MGR_EVT_EXP_SSPT_TX_PAUSE", + "MGR_EVT_EXP_SSPT_HARD_RESET", + "MGR_EVT_EXP_SSPT_SOFT_RESET", + "MGR_EVT_EXP_SSPT_INIT_FAIL", + "MGR_EVT_EXP_SSPT_SET_TIME", + "MGR_EVT_EXP_DOUBLE_BIT_ECC_ERR", + }, + { + "MGR_EVT_EXP_PHY_START", + "MGR_EVT_EXP_DISCONNECT_RAID_HBA", + "MGR_EVT_EXP_DISCONNECT_EXP", + "MGR_EVT_EXP_DISK_OUT", + "MGR_EVT_EXP_PHY_ENABLE", + "MGR_EVT_EXP_PHY_DISABLE", + "MGR_EVT_EXP_PHY_HARD_RESET", + "MGR_EVT_EXP_PHY_LINK_RESET", + }, + { + "MGR_EVT_EXP_CONN_START", + "MGR_EVT_EXP_CONNECT_RAID_HBA", + "MGR_EVT_EXP_CONNECT_EXP", + "MGR_EVT_EXP_DISK_IN", + }, + { + "MGR_EVTLOG_SW_CTRL_INFO_START", + "MGR_SWITCH_EVTLOG_CTRL_REBOOT", + "MGR_SWITCH_EVTLOG_CTRL_SHUTDOWN", + "MGR_SWITCH_EVTLOG_CTRL_EVENT_LOG_CLEARED", + }, + }; + + if (opCode >= (PS3_EVTLOG_MAX_TYPE_LOCAL * MGR_EVT_TYPE_OFFSET)) { + goto end; + }; + + typeIndex = opCode / MGR_EVT_TYPE_OFFSET; + codeIndex = opCode % MGR_EVT_TYPE_OFFSET; + pEvtTransStr = pEvtLogCodeInfo[typeIndex][codeIndex]; +end: + return pEvtTransStr; +} + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_nvme_spec.h b/drivers/scsi/ps3stor/include/ps3_nvme_spec.h new file mode 100644 index 0000000000000000000000000000000000000000..644ed582d34731fd651a6c414f38b353282dc8a6 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_nvme_spec.h @@ -0,0 +1,2215 @@ + +#ifndef _NVME_SPEC_H +#define _NVME_SPEC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define NVME_REG32_ERR_VAL ((U32)(-1)) +#define NVME_REG64_ERR_VAL ((U64)(-1)) +#define NVME_MAX_IO_QUEUES (65536) +#define NVME_MAX_NUM_ADMIN_QD (4096) +#define NVME_MAX_NUM_IO_QD (65536) +#define NVME_MIN_NUM_ADMIN_QD (2) +#define NVME_MIN_NUM_IO_QD (MASK#define NVME_NSSR_VAL (0x4e564d65) +#define NVME_CMD_SET_SUPPORT BIT(0) +#define NVME_INVALID_CID (0xFFFF) +#define NVME_MAX_WRITE_ZEROES (0xFFFF) +#define NVME_NSID_MASK (0xFFFFFFFF) + +#define NVME_GET_SECTOR_SIZE(data) (1 << (data)->lbaf[(data)->flbas.format].lbads) + + +#define NVME_GET_SQ_DOOR_BELL_OFFSET(qid, strd) (0x1000 + 2 * (qid) * (4 << (strd))) + +#define NVME_GET_CQ_DOOR_BELL_OFFSET(qid, strd) (0x1000 + (2 * (qid) + 1) * (4 << (strd))) + +#define NVME_SANITIZE_MAX_PROG 0xFFFF + +#define NVME_CAP_CSS_NVM 1 + +#define NVME_MPS_TO_PAGESIZE(mpsMin) (1u << (12 + (mpsMin))) + +#define NVME_PAGESIZE_TO_MPS(pageSize) (nvmeU64Log2(pageSize) - 12) + + +typedef union NvmeCapReg { + U64 rawVal; + struct { + U32 mqes : 16; + U32 cqr : 1; + U32 ams : 2; + U32 rsvd : 5; + U32 timeout : 8; + U32 dbStride : 4; + + U32 nssrSupport : 1; + U32 cmdSetSupport : 8; + U32 bootPartSupport : 1; + U32 rsvd1 : 2; + U32 mpsMin : 4; + U32 mpsMax : 4; + U32 pmrSupport : 1; + U32 cmbSupport : 1; + U32 rsvd3 : 6; + }; +} NvmeCapReg_u; + + +typedef union NvmeVsReg { + U32 rawVal; + struct { + U8 vsTerity; + U8 vsMinorNum; + U16 vsMajorNum; + }; +} NvmeVsReg_u; + + + +#define NVME_VERSION(mjr, mnr, ter) \ + (((uint32_s)(mjr) << 16) | ((uint32_s)(mnr) << 8) | (uint32_s)(ter)) + + +#define NVME_IO_SQ_ENTRY_SIZE 6 + +#define NVME_IO_CQ_ENTRY_SIZE 4 + + +#define NVME_SHUT_DOWN_NO_EFFECT 0x0 + +#define NVME_SHUT_DOWN_NOTIFY 0x1 + +#define NVME_SHUT_DOWN_ABRUT_NOTIFY 0x2 + +#define NVME_CSS_NVM_CMD_SET 0x0 + +typedef union NvmeCCReg { + U32 rawVal; + struct { + + U32 en : 1; + U32 rsvd : 3; + U32 css : 3; + U32 mps : 4; + U32 ams : 3; + U32 shutdownNotify : 2; + + U32 ioSqEntrySz : 4; + U32 ioCqEntrySz : 4; + U32 rsvd1 : 8; + }; +} NvmeCCReg_u; + + +#define NVME_SHST_NORMAL 0x0 +#define NVME_SHST_OCCURRING 0x1 +#define NVME_SHST_COMPLETE 0x2 + +typedef union NvmeCstsReg { + U32 rawVal; + struct { + U32 rdy : 1; + U32 cfs : 1; + U32 shutdownStatus : 2; + U32 nssrOccur : 1; + U32 proccessPaused : 1; + U32 rsvd : 26; + }; +} NvmeCstsReg_u; + + +typedef union NvmeAqaReg { + U32 rawVal; + struct { + U32 adminSqSz : 12; + U32 rsvd : 4; + U32 adminCqSz : 12; + U32 rsvd1 : 4; + }; +} NvmeAqaReg_u; + + +typedef union NvmeCmbLocReg { + U32 rawVal; + struct { + U32 bir : 3; + U32 cmbQMixMemSupport : 1; + U32 cmbQPhyDiscontiSupport : 1; + U32 cmbDataPtrMixLocSupport : 1; + U32 cmbDataPtrCmdIndentLocSupport : 1; + U32 cmbDataMetaMemMixSupport : 1; + U32 cmbQDwordAlignSupport : 1; + U32 rsvd : 3; + U32 offset : 20; + }; +} NvmeCmbLocReg_u; + + +typedef union NvmeCmbSzReg { + U32 rawVal; + struct { + U32 sqSupport : 1; + U32 cqSupport : 1; + U32 prpListSupport : 1; + U32 readSupport : 1; + U32 writeSupport : 1; + U32 rsvd : 3; + U32 szUnit : 4; + U32 size : 20; + }; +} NvmeCmbSzReg_u; + + +typedef struct NvmeControllerReg { + NvmeCapReg_u cap; + NvmeVsReg_u vs; + U32 intmskSet; + U32 intmskClr; + NvmeCCReg_u cc; + U32 rsvd0; + NvmeCstsReg_u csts; + U32 nssrCtrl; + NvmeAqaReg_u aqa; + U64 asq; + U64 acq; + NvmeCmbLocReg_u cmbLoc; + NvmeCmbSzReg_u cmbSz; + + + +} NvmeControllerReg_s; + + +typedef struct DBEntry { + U32 sqT; + U32 cqH; +} DBEntry_s; + + +enum NvmeSglDescSubType { + NVME_SGL_SUBTYPE_ADDRESS = 0x0, + NVME_SGL_SUBTYPE_OFFSET = 0x1, + NVME_SGL_SUBTYPE_TRANSPORT = 0xa, +}; + +typedef struct GenericSglDesc{ + U32 rsvd; + U32 rsvd1 : 24; + U32 subType : 4; + U32 type : 4; +} GenericSglDesc_s; + + +typedef struct UnKeyedSglDesc{ + U32 len; + U32 rsvd : 24; + U32 subType : 4; + U32 type : 4; +} UnKeyedSglDesc_s; + + +typedef struct KeyedSglDesc{ + U64 len : 24; + U64 key : 32; + U64 subType : 4; + U64 type : 4; +} KeyedSglDesc_s; + + +typedef struct NvmeSglDesc { + U64 addr; + union { + GenericSglDesc_s genSgl; + UnKeyedSglDesc_s unkeyedSgl; + KeyedSglDesc_s keyedSgl; + }; +} NvmeSglDesc_s; + + + + +struct NvmeSanitize { + + U32 sanact : 3; + + U32 ause : 1; + + U32 owpass : 4; + + U32 oipbp : 1; + + U32 ndas : 1; + + U32 reserved : 22; +}; + + + +enum NvmeSanitizeAction { + + NVME_SANITIZE_EXIT_FAILURE_MODE = 0x1, + + NVME_SANITIZE_BLOCK_ERASE = 0x2, + + NVME_SANITIZE_OVERWRITE = 0x3, + + NVME_SANITIZE_CRYPTO_ERASE = 0x4, +}; + +typedef struct NvmeCommonCmdEntry { + + U16 opc : 8; + U16 fuse : 2; + U16 rsvd : 4; + U16 psdt : 2; + U16 cid; + + + U32 nsId; + + + U64 rsvd1; + + + U64 metaPtr; + + + union { + struct { + U64 prp1; + union { + U64 prp2; + struct { + U32 metaDataLen; + U32 dataLen; + }; + }; + }; + NvmeSglDesc_s sgl; + }; + + + union { + + struct { + U64 slba; + U32 nlba : 16; + U32 res1 : 8; + U32 stc : 1; + U32 res2 : 1; + U32 prinfo : 4; + U32 fua : 1; + U32 lr : 1; + }; + + struct { + struct NvmeSanitize sanitizeDw10; + U32 overwritePattern; + }; + struct { + U32 dw10; + U32 dw11; + U32 dw12; + U32 dw13; + U32 dw14; + U32 dw15; + }; + }; +} NvmeCommonCmdEntry_s; + +#ifndef _WINDOWS +typedef struct __attribute__((packed)) NvmeCmdStatus { +#else +#pragma pack(1) +typedef struct NvmeCmdStatus { +#endif + union { + struct { + U16 p : 1; + U16 sc : 8; + U16 sct : 3; + U16 crd : 2; + U16 m : 1; + U16 dnr : 1; + }; + U16 cmdStatus; + }; +} NvmeCmdStatus_s; + +#ifdef _WINDOWS +#pragma pack() +#endif + + +#define NVME_GET_IO_SQ_NUM(cmdSpec) (((cmdSpec) & 0xFFFF) + 1) + +#define NVME_GET_IO_CQ_NUM(cmdSpec) (((cmdSpec) >> 16) + 1) + + +#define NVME_GET_POWER_STATE(cmdSpec) (((cmdSpec) & 0X1F)) + +typedef struct NvmeCplEntry { + + U32 cmdSpec; + + U32 rsvd; + + U16 sqHead; + U16 sqId; + + U16 cid; + NvmeCmdStatus_s status; +} NvmeCplEntry_s; + + +enum NvmeAdminOpcode { + NVME_OPC_DELETE_IO_SQ = 0x00, + NVME_OPC_CREATE_IO_SQ = 0x01, + NVME_OPC_GET_LOG_PAGE = 0x02, + + NVME_OPC_DELETE_IO_CQ = 0x04, + NVME_OPC_CREATE_IO_CQ = 0x05, + NVME_OPC_IDENTIFY = 0x06, + + NVME_OPC_ABORT = 0x08, + NVME_OPC_SET_FEATURES = 0x09, + NVME_OPC_GET_FEATURES = 0x0a, + + NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c, + NVME_OPC_NS_MANAGEMENT = 0x0d, + + NVME_OPC_FIRMWARE_COMMIT = 0x10, + NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11, + NVME_OPC_DEVICE_SELF_TEST = 0x14, + NVME_OPC_NS_ATTACHMENT = 0x15, + NVME_OPC_KEEP_ALIVE = 0x18, + NVME_OPC_DIRECTIVE_SEND = 0x19, + NVME_OPC_DIRECTIVE_RECEIVE = 0x1a, + NVME_OPC_VIRTUALIZATION_MANAGEMENT = 0x1c, + NVME_OPC_NVME_MI_SEND = 0x1d, + NVME_OPC_NVME_MI_RECEIVE = 0x1e, + NVME_OPC_DOORBELL_BUFFER_CONFIG = 0x7c, + NVME_OPC_FORMAT_NVM = 0x80, + NVME_OPC_SECURITY_SEND = 0x81, + NVME_OPC_SECURITY_RECEIVE = 0x82, + NVME_OPC_SANITIZE = 0x84, +}; + + +enum NvmeIOOpcode { + NVME_OPC_FLUSH = 0x00, + NVME_OPC_WRITE = 0x01, + NVME_OPC_READ = 0x02, + + NVME_OPC_WRITE_UNCORRECTABLE = 0x04, + NVME_OPC_COMPARE = 0x05, + + NVME_OPC_WRITE_ZEROES = 0x08, + NVME_OPC_DATASET_MANAGEMENT = 0x09, + NVME_OPC_VERIFY = 0x0C, + + NVME_OPC_RESERVATION_REGISTER = 0x0d, + NVME_OPC_RESERVATION_REPORT = 0x0e, + + NVME_OPC_RESERVATION_ACQUIRE = 0x11, + NVME_OPC_RESERVATION_RELEASE = 0x15, +}; + + +enum NvmeStatusCodeType { + NVME_SCT_GENERIC = 0x0, + NVME_SCT_COMMAND_SPECIFIC = 0x1, + NVME_SCT_MEDIA_ERROR = 0x2, + NVME_SCT_PATH = 0x3, + + NVME_SCT_VENDOR_SPECIFIC = 0x7, +}; + + +enum NvmeGenCmdSC { + NVME_SC_SUCCESS = 0x00, + NVME_SC_INVALID_OPCODE = 0x01, + NVME_SC_INVALID_FIELD = 0x02, + NVME_SC_COMMAND_ID_CONFLICT = 0x03, + NVME_SC_DATA_TRANSFER_ERROR = 0x04, + NVME_SC_ABORTED_POWER_LOSS = 0x05, + NVME_SC_INTERNAL_DEVICE_ERROR = 0x06, + NVME_SC_ABORTED_BY_REQUEST = 0x07, + NVME_SC_ABORTED_SQ_DELETION = 0x08, + NVME_SC_ABORTED_FAILED_FUSED = 0x09, + NVME_SC_ABORTED_MISSING_FUSED = 0x0a, + NVME_SC_INVALID_NAMESPACE_OR_FORMAT = 0x0b, + NVME_SC_COMMAND_SEQUENCE_ERROR = 0x0c, + NVME_SC_INVALID_SGL_SEG_DESCRIPTOR = 0x0d, + NVME_SC_INVALID_NUM_SGL_DESCIRPTORS = 0x0e, + NVME_SC_DATA_SGL_LENGTH_INVALID = 0x0f, + NVME_SC_METADATA_SGL_LENGTH_INVALID = 0x10, + NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID = 0x11, + NVME_SC_INVALID_CONTROLLER_MEM_BUF = 0x12, + NVME_SC_INVALID_PRP_OFFSET = 0x13, + NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED = 0x14, + NVME_SC_OPERATION_DENIED = 0x15, + NVME_SC_INVALID_SGL_OFFSET = 0x16, + + NVME_SC_HOSTID_INCONSISTENT_FORMAT = 0x18, + NVME_SC_KEEP_ALIVE_EXPIRED = 0x19, + NVME_SC_KEEP_ALIVE_INVALID = 0x1a, + NVME_SC_ABORTED_PREEMPT = 0x1b, + NVME_SC_SANITIZE_FAILED = 0x1c, + NVME_SC_SANITIZE_IN_PROGRESS = 0x1d, + NVME_SC_SGL_DATA_BLOCK_GRANULARITY_INVALID = 0x1e, + NVME_SC_COMMAND_INVALID_IN_CMB = 0x1f, + NVME_SC_NAMESPACE_IS_WRITE_PROTECTED = 0x20, + NVME_SC_COMMAND_INTERRUPTED = 0x21, + NVME_SC_TRANSIENT_TRANSPORT_ERROR = 0x22, + + NVME_SC_LBA_OUT_OF_RANGE = 0x80, + NVME_SC_CAPACITY_EXCEEDED = 0x81, + NVME_SC_NAMESPACE_NOT_READY = 0x82, + NVME_SC_RESERVATION_CONFLICT = 0x83, + NVME_SC_FORMAT_IN_PROGRESS = 0x84, +}; + + +enum NvmeCmdSpecSC { + NVME_CSC_COMPLETION_QUEUE_INVALID = 0x00, + NVME_CSC_INVALID_QUEUE_IDENTIFIER = 0x01, + NVME_CSC_MAXIMUM_QUEUE_SIZE_EXCEEDED = 0x02, + NVME_CSC_ABORT_COMMAND_LIMIT_EXCEEDED = 0x03, + + NVME_CSC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05, + NVME_CSC_INVALID_FIRMWARE_SLOT = 0x06, + NVME_CSC_INVALID_FIRMWARE_IMAGE = 0x07, + NVME_CSC_INVALID_INTERRUPT_VECTOR = 0x08, + NVME_CSC_INVALID_LOG_PAGE = 0x09, + NVME_CSC_INVALID_FORMAT = 0x0a, + NVME_CSC_FIRMWARE_REQ_CONVENTIONAL_RESET = 0x0b, + NVME_CSC_INVALID_QUEUE_DELETION = 0x0c, + NVME_CSC_FEATURE_ID_NOT_SAVEABLE = 0x0d, + NVME_CSC_FEATURE_NOT_CHANGEABLE = 0x0e, + NVME_CSC_FEATURE_NOT_NAMESPACE_SPECIFIC = 0x0f, + NVME_CSC_FIRMWARE_REQ_NVM_RESET = 0x10, + NVME_CSC_FIRMWARE_REQ_RESET = 0x11, + NVME_CSC_FIRMWARE_REQ_MAX_TIME_VIOLATION = 0x12, + NVME_CSC_FIRMWARE_ACTIVATION_PROHIBITED = 0x13, + NVME_CSC_OVERLAPPING_RANGE = 0x14, + NVME_CSC_NAMESPACE_INSUFFICIENT_CAPACITY = 0x15, + NVME_CSC_NAMESPACE_ID_UNAVAILABLE = 0x16, + + NVME_CSC_NAMESPACE_ALREADY_ATTACHED = 0x18, + NVME_CSC_NAMESPACE_IS_PRIVATE = 0x19, + NVME_CSC_NAMESPACE_NOT_ATTACHED = 0x1a, + NVME_CSC_THINPROVISIONING_NOT_SUPPORTED = 0x1b, + NVME_CSC_CONTROLLER_LIST_INVALID = 0x1c, + NVME_CSC_DEVICE_SELF_TEST_IN_PROGRESS = 0x1d, + NVME_CSC_BOOT_PARTITION_WRITE_PROHIBITED = 0x1e, + NVME_CSC_INVALID_CTRLR_ID = 0x1f, + NVME_CSC_INVALID_SECONDARY_CTRLR_STATE = 0x20, + NVME_CSC_INVALID_NUM_CTRLR_RESOURCES = 0x21, + NVME_CSC_INVALID_RESOURCE_ID = 0x22, + + NVME_CSC_CONFLICTING_ATTRIBUTES = 0x80, + NVME_CSC_INVALID_PROTECTION_INFO = 0x81, + NVME_CSC_ATTEMPTED_WRITE_TO_RO_RANGE = 0x82, +}; + + +enum NvmeMediaErrSC { + NVME_MSC_WRITE_FAULTS = 0x80, + NVME_MSC_UNRECOVERED_READ_ERROR = 0x81, + NVME_MSC_GUARD_CHECK_ERROR = 0x82, + NVME_MSC_APPLICATION_TAG_CHECK_ERROR = 0x83, + NVME_MSC_REFERENCE_TAG_CHECK_ERROR = 0x84, + NVME_MSC_COMPARE_FAILURE = 0x85, + NVME_MSC_ACCESS_DENIED = 0x86, + NVME_MSC_DEALLOCATED_OR_UNWRITTEN_BLOCK = 0x87, +}; + +enum NvmeStatusCodes { + NVME_SUCCESS = 0x0000, + NVME_INVALID_OPCODE = 0x0001, + NVME_INVALID_FIELD = 0x0002, + NVME_CID_CONFLICT = 0x0003, + NVME_DATA_TRAS_ERROR = 0x0004, + NVME_POWER_LOSS_ABORT = 0x0005, + NVME_INTERNAL_DEV_ERROR = 0x0006, + NVME_CMD_ABORT_REQ = 0x0007, + NVME_CMD_ABORT_SQ_DEL = 0x0008, + NVME_CMD_ABORT_FAILED_FUSE = 0x0009, + NVME_CMD_ABORT_MISSING_FUSE = 0x000a, + NVME_INVALID_NSID = 0x000b, + NVME_CMD_SEQ_ERROR = 0x000c, + NVME_INVALID_SGL_SEG_DESCR = 0x000d, + NVME_INVALID_NUM_SGL_DESCRS = 0x000e, + NVME_DATA_SGL_LEN_INVALID = 0x000f, + NVME_MD_SGL_LEN_INVALID = 0x0010, + NVME_SGL_DESCR_TYPE_INVALID = 0x0011, + NVME_INVALID_USE_OF_CMB = 0x0012, + NVME_INVALID_PRP_OFFSET = 0x0013, + NVME_CMD_SET_CMB_REJECTED = 0x002b, + NVME_INVALID_CMD_SET = 0x002c, + NVME_LBA_RANGE = 0x0080, + NVME_CAP_EXCEEDED = 0x0081, + NVME_NS_NOT_READY = 0x0082, + NVME_NS_RESV_CONFLICT = 0x0083, + NVME_FORMAT_IN_PROGRESS = 0x0084, + NVME_INVALID_CQID = 0x0100, + NVME_INVALID_QID = 0x0101, + NVME_MAX_QSIZE_EXCEEDED = 0x0102, + NVME_ACL_EXCEEDED = 0x0103, + NVME_RESERVED = 0x0104, + NVME_AER_LIMIT_EXCEEDED = 0x0105, + NVME_INVALID_FW_SLOT = 0x0106, + NVME_INVALID_FW_IMAGE = 0x0107, + NVME_INVALID_IRQ_VECTOR = 0x0108, + NVME_INVALID_LOG_ID = 0x0109, + NVME_INVALID_FORMAT = 0x010a, + NVME_FW_REQ_RESET = 0x010b, + NVME_INVALID_QUEUE_DEL = 0x010c, + NVME_FID_NOT_SAVEABLE = 0x010d, + NVME_FEAT_NOT_CHANGEABLE = 0x010e, + NVME_FEAT_NOT_NS_SPEC = 0x010f, + NVME_FW_REQ_SUSYSTEM_RESET = 0x0110, + NVME_NS_ALREADY_ATTACHED = 0x0118, + NVME_NS_PRIVATE = 0x0119, + NVME_NS_NOT_ATTACHED = 0x011A, + NVME_NS_CTRL_LIST_INVALID = 0x011C, + NVME_CONFLICTING_ATTRS = 0x0180, + NVME_INVALID_PROT_INFO = 0x0181, + NVME_WRITE_TO_RO = 0x0182, + NVME_CMD_SIZE_LIMIT = 0x0183, + NVME_ZONE_BOUNDARY_ERROR = 0x01b8, + NVME_ZONE_FULL = 0x01b9, + NVME_ZONE_READ_ONLY = 0x01ba, + NVME_ZONE_OFFLINE = 0x01bb, + NVME_ZONE_INVALID_WRITE = 0x01bc, + NVME_ZONE_TOO_MANY_ACTIVE = 0x01bd, + NVME_ZONE_TOO_MANY_OPEN = 0x01be, + NVME_ZONE_INVAL_TRANSITION = 0x01bf, + NVME_WRITE_FAULT = 0x0280, + NVME_UNRECOVERED_READ = 0x0281, + NVME_E2E_GUARD_ERROR = 0x0282, + NVME_E2E_APP_ERROR = 0x0283, + NVME_E2E_REF_ERROR = 0x0284, + NVME_CMP_FAILURE = 0x0285, + NVME_ACCESS_DENIED = 0x0286, + NVME_DULB = 0x0287, + NVME_MORE = 0x2000, + NVME_DNR = 0x4000, + NVME_NO_COMPLETE = 0xffff, +}; + +enum NvmeQprio { + NVME_QPRIO_URGENT = 0x0, + NVME_QPRIO_HIGH = 0x1, + NVME_QPRIO_MEDIUM = 0x2, + NVME_QPRIO_LOW = 0x3 +}; + +enum NvmeDataTransfer { + + NVME_DATA_NONE = 0, + + NVME_DATA_HOST_TO_CONTROLLER = 1, + + NVME_DATA_CONTROLLER_TO_HOST = 2, + + NVME_DATA_BIDIRECTIONAL = 3 +}; + +static inline enum NvmeDataTransfer NvmeOpcGetDataTransfer(U8 opc) +{ + return (enum NvmeDataTransfer)(opc & 3); +} + +enum NvmeFeat { + + + + NVME_FEAT_ARBITRATION = 0x01, + + NVME_FEAT_POWER_MANAGEMENT = 0x02, + + NVME_FEAT_LBA_RANGE_TYPE = 0x03, + + NVME_FEAT_TEMPERATURE_THRESHOLD = 0x04, + + NVME_FEAT_ERROR_RECOVERY = 0x05, + + NVME_FEAT_VOLATILE_WRITE_CACHE = 0x06, + + NVME_FEAT_NUMBER_OF_QUEUES = 0x07, + + NVME_FEAT_INTERRUPT_COALESCING = 0x08, + + NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09, + + NVME_FEAT_WRITE_ATOMICITY = 0x0A, + + NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B, + + NVME_FEAT_AUTONOMOUS_POWER_STATE_TRANSITION = 0x0C, + + NVME_FEAT_HOST_MEM_BUFFER = 0x0D, + NVME_FEAT_TIMESTAMP = 0x0E, + + NVME_FEAT_KEEP_ALIVE_TIMER = 0x0F, + + NVME_FEAT_HOST_CONTROLLED_THERMAL_MANAGEMENT = 0x10, + + NVME_FEAT_NON_OPERATIONAL_POWER_STATE_CONFIG = 0x11, + + + + + + + NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80, + + + NVME_FEAT_HOST_IDENTIFIER = 0x81, + NVME_FEAT_HOST_RESERVE_MASK = 0x82, + NVME_FEAT_HOST_RESERVE_PERSIST = 0x83, + + + + +}; + + +enum NvmeGetFeatSel { + NVME_GET_FEA_SEL_CURRENT = 0x0, + NVME_GET_FEA_SEL_DEFAULT = 0x1, + NVME_GET_FEA_SEL_SAVED = 0x2, + NVME_GET_FEA_SEL_SUP_CAPABILITY = 0x3, +}; + + +enum NvmeDsmAttribute { + NVME_DSM_ATTR_INTEGRAL_READ = 0x1, + NVME_DSM_ATTR_INTEGRAL_WRITE = 0x2, + NVME_DSM_ATTR_DEALLOCATE = 0x4, +}; + +struct NvmePowerState { + U16 mp; + + U8 reserved1; + + U8 mps : 1; + U8 nops : 1; + U8 reserved2 : 6; + + U32 enlat; + U32 exlat; + + U8 rrt : 5; + U8 reserved3 : 3; + + U8 rrl : 5; + U8 reserved4 : 3; + + U8 rwt : 5; + U8 reserved5 : 3; + + U8 rwl : 5; + U8 reserved6 : 3; + + U8 reserved7[16]; +}; + + +typedef enum NvmeIdentifyCns { + + NVME_IDENTIFY_NS = 0x00, + + + NVME_IDENTIFY_CTRLR = 0x01, + + + NVME_IDENTIFY_ACTIVE_NS_LIST = 0x02, + + + NVME_IDENTIFY_NS_ID_DESCRIPTOR_LIST = 0x03, + + + NVME_IDENTIFY_ALLOCATED_NS_LIST = 0x10, + + + NVME_IDENTIFY_NS_ALLOCATED = 0x11, + + + + NVME_IDENTIFY_NS_ATTACHED_CTRLR_LIST = 0x12, + + + NVME_IDENTIFY_CTRLR_LIST = 0x13, + + + NVME_IDENTIFY_PRIMARY_CTRLR_CAP = 0x14, + + + NVME_IDENTIFY_SECONDARY_CTRLR_LIST = 0x15, + + + NVME_IDENTIFY_NS_GRANULARITY_LIST = 0x16, +} NvmeIdentifyCns_e; + + +enum NvmfCtrlrModel { + + NVMF_CTRLR_MODEL_DYNAMIC = 0, + + + NVMF_CTRLR_MODEL_STATIC = 1, +}; + +#define NVME_CTRLR_SN_LEN 20 +#define NVME_CTRLR_MN_LEN 40 +#define NVME_CTRLR_FR_LEN 8 + + +enum NvmeSglsSupported { + + NVME_SGLS_NOT_SUPPORTED = 0, + + + NVME_SGLS_SUPPORTED = 1, + + + NVME_SGLS_SUPPORTED_DWORD_PCIE_ALIGNED = 2, +}; + + +enum NvmeFlushBroadcast { + + NVME_FLUSH_BROADCAST_NOT_INDICATED = 0, + + + + + NVME_FLUSH_BROADCAST_NOT_SUPPORTED = 2, + + + NVME_FLUSH_BROADCAST_SUPPORTED = 3 +}; +#ifndef _WINDOWS +struct __attribute__((packed)) __attribute__((aligned)) NvmeCtrlrData { +#else +#pragma pack(1) +struct NvmeCtrlrData { +#endif + + + U16 vid; + + + U16 ssvid; + + + S8 sn[NVME_CTRLR_SN_LEN]; + + + S8 mn[NVME_CTRLR_MN_LEN]; + + + U8 fr[NVME_CTRLR_FR_LEN]; + + + U8 rab; + + + U8 ieee[3]; + + + + U8 cmic; + + + U8 mdts; + + + U16 cntlid; + + + union NvmeVsReg ver; + + + U32 rtd3r; + + + U32 rtd3e; + + + U32 oaes; + + + U32 ctratt; + + U8 reserved_100[12]; + + + U8 fguid[16]; + + U8 reserved_128[128]; + + + + + U16 oacs; + + + U8 acl; + + + U8 aerl; + + + U8 frmw; + + + U8 lpe; + + + U8 elpe; + + + U8 npss; + + + U8 avscc; + + + U8 apsta; + + + U16 wctemp; + + + U16 cctemp; + + + U16 mtfa; + + + U32 hmpre; + + + U32 hmmin; + + + U64 tnvmcap[2]; + + + U64 unvmcap[2]; + + + U32 rpmbs; + + + U16 edstt; + + + U8 dsto; + + U8 fwug; + + U16 kas; + + + U16 hctma; + + + U16 mntmt; + + + U16 mxtmt; + + + union { + U32 sanicap; + struct { + U32 ces:1; + U32 bes:1; + U32 ows:1; + U32 snicapRsvd1:26; + U32 ndi:1; + U32 nodmmas:2; + }; + }; + + U8 reserved3[180]; + + + + + U8 sqes; + + + U8 cqes; + + U16 maxcmd; + + + U32 nn; + + + U16 oncs; + + + U16 fuses; + + + U8 fna; + + + U8 vwc; + + + U16 awun; + + + U16 awupf; + + + U8 nvscc; + + U8 reserved531; + + + U16 acwu; + + U16 reserved534; + + + U32 sgls; + + U8 reserved4[228]; + + U8 subnqn[256]; + + U8 reserved5[768]; + + + struct { + + U32 ioccsz; + + + U32 iorcsz; + + + U16 icdoff; + + + U8 ctrattr; + + + U8 msdbd; + + U8 reserved[244]; + }; + + + struct NvmePowerState psd[32]; + + + U8 vs[1024]; +}; +#ifdef _WINDOWS +#pragma pack() +#endif + +#ifndef _WINDOWS +struct __attribute__((packed)) NvmePrimaryCtrlCapabilities { +#else +#pragma pack(1) +struct NvmePrimaryCtrlCapabilities { +#endif + + U16 cntlid; + + U16 portid; + + U8 crt; + U8 reserved[27]; + + U32 vqfrt; + + U32 vqrfa; + + U16 vqrfap; + + U16 vqprt; + + + U16 vqfrsm; + + U16 vqgran; + U8 reserved1[16]; + + + U32 vifrt; + + + U32 virfa; + + + U16 virfap; + + U16 viprt; + + + U16 vifrsm; + + U16 vigran; + U8 reserved2[4016]; +}; + + +#ifdef _WINDOWS +#pragma pack() +#endif +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeSecondaryCtrlEntry { +#else +#pragma pack(1) +struct NvmeSecondaryCtrlEntry { +#endif + + U16 scid; + + U16 pcid; + + U8 scs; + U8 reserved[3]; + + U16 vfn; + + + U16 nvq; + + + U16 nvi; + U8 reserved1[18]; +}; + +#ifdef _WINDOWS +#pragma pack() +#endif +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeSecondaryCtrlList { +#else +#pragma pack(1) +struct NvmeSecondaryCtrlList { +#endif + + U8 number; + U8 reserved[31]; + struct NvmeSecondaryCtrlEntry entries[127]; +}; + +#ifdef _WINDOWS +#pragma pack() +#endif +struct NvmeNsData { + + U64 nsze; + + + U64 ncap; + + + U64 nuse; + + + U8 nsfeat; + + + U8 nlbaf; + union { + struct { + U8 format : 4; + U8 extended : 1; + U8 reserved2 : 3; + } flbas; + U8 flbasRaw; + }; + + + U8 mc; + + + union { + struct { + U8 type1 : 1; + U8 type2 : 1; + U8 type3 : 1; + U8 piBeforeMeta : 1; + U8 piAfterMeta : 1; + U8 reserved2 : 3; + }; + U8 rawData; + } dpc; + + + union { + struct { + U8 type : 3; + U8 isPiBefore : 1; + U8 reserved2 : 4; + }; + U8 rawData; + } dps; + + + U8 nmic; + + + U8 nsrescap; + + U8 fpi; + + + U8 dlfeat; + + + U16 nawun; + + + U16 nawupf; + + + U16 nacwu; + + + U16 nabsn; + + + U16 nabo; + + + U16 nabspf; + + + U16 noiob; + + + U64 nvmcap[2]; + + U8 reserved64[40]; + + + U8 nguid[16]; + + + U64 eui64; + + struct { + U32 ms : 16; + U32 lbads : 8; + U32 rp : 2; + U32 reserved6 : 6; + } lbaf[16]; + + U8 reserved6[192]; + + U8 vendorSpecific[3712]; +}; + + + +enum NvmeDeallocLogicalBlockReadValue { + + NVME_DEALLOC_NOT_REPORTED = 0, + + + NVME_DEALLOC_READ_00 = 1, + + + NVME_DEALLOC_READ_FF = 2, +}; + + +enum NvmeReservationType { + + + + NVME_RESERVE_WRITE_EXCLUSIVE = 0x1, + + + NVME_RESERVE_EXCLUSIVE_ACCESS = 0x2, + + + NVME_RESERVE_WRITE_EXCLUSIVE_REG_ONLY = 0x3, + + + NVME_RESERVE_EXCLUSIVE_ACCESS_REG_ONLY = 0x4, + + + NVME_RESERVE_WRITE_EXCLUSIVE_ALL_REGS = 0x5, + + + NVME_RESERVE_EXCLUSIVE_ACCESS_ALL_REGS = 0x6, + + +}; + +struct NvmeReservationAcquireData { + + U64 crkey; + + U64 prkey; +}; + + + + +enum NvmeReservationAcquireAction { + NVME_RESERVE_ACQUIRE = 0x0, + NVME_RESERVE_PREEMPT = 0x1, + NVME_RESERVE_PREEMPT_ABORT = 0x2, +}; +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeReservationStatusData { +#else +#pragma pack(1) +struct NvmeReservationStatusData { +#endif + + U32 gen; + + U8 rtype; + + U16 regctl; + U16 reserved1; + + U8 ptpls; + U8 reserved[14]; +}; +#ifdef _WINDOWS +#pragma pack() +#endif + +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeReservationStatusExtendedData { +#else +#pragma pack(1) +struct NvmeReservationStatusExtendedData { +#endif + struct NvmeReservationStatusData data; + U8 reserved[40]; +}; + + +#ifdef _WINDOWS +#pragma pack() +#endif +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeRegisteredCtrlrData { +#else +#pragma pack(1) +struct NvmeRegisteredCtrlrData { +#endif + + U16 cntlid; + U8 rcsts; + U8 reserved2[5]; + + U64 hostid; + + U64 rkey; +}; + +#ifdef _WINDOWS +#pragma pack() +#endif +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeRegisteredCtrlrExtendedData { +#else +#pragma pack(1) +struct NvmeRegisteredCtrlrExtendedData { +#endif + + U16 cntlid; + + U8 rcsts; + U8 reserved2[5]; + + U64 rkey; + + U8 hostid[16]; + U8 reserved3[32]; +}; + + +#ifdef _WINDOWS +#pragma pack() +#endif + + +enum NvmeReservationRegisterCptpl { + NVME_RESERVE_PTPL_NO_CHANGES = 0x0, + NVME_RESERVE_PTPL_CLEAR_POWER_ON = 0x2, + NVME_RESERVE_PTPL_PERSIST_POWER_LOSS = 0x3, +}; + + +enum NvmeReservationRegisterAction { + NVME_RESERVE_REGISTER_KEY = 0x0, + NVME_RESERVE_UNREGISTER_KEY = 0x1, + NVME_RESERVE_REPLACE_KEY = 0x2, +}; + +struct NvmeReservationRegisterData { + + U64 crkey; + + U64 nrkey; +}; + + + +struct NvmeReservationKeyData { + + U64 crkey; +}; + + + +enum NvmeReservationReleaseAction { + NVME_RESERVE_RELEASE = 0x0, + NVME_RESERVE_CLEAR = 0x1, +}; + + +enum NvmeReservationNotificationLogPageType { + NVME_RESERVATION_LOG_PAGE_EMPTY = 0x0, + NVME_REGISTRATION_PREEMPTED = 0x1, + NVME_RESERVATION_RELEASED = 0x2, + NVME_RESERVATION_PREEMPTED = 0x3, +}; + + +struct NvmeReservationNotificationLog { + + U64 logPageCount; + + U8 type; + + U8 numAvailLogPages; + U8 reserved[2]; + U32 nsid; + U8 reserved1[48]; +}; + + + + +#define NVME_REGISTRATION_PREEMPTED_MASK (1U << 1) + +#define NVME_RESERVATION_RELEASED_MASK (1U << 2) + +#define NVME_RESERVATION_PREEMPTED_MASK (1U << 3) + + + + +#define NVME_LOG_PAGE_DW10_SPICE(dw10, lid, logLen) (dw10) = ((((logLen) >> 2) - 1) << 16) | (lid) +#define NVME_LOG_PAGE_RETAIN_BIT_SET(dw10) (dw10) |= 1UL << 15 + + +enum NvmeLogPage { + + + + NVME_LOG_ERROR = 0x01, + + + NVME_LOG_HEALTH_INFORMATION = 0x02, + + + NVME_LOG_FIRMWARE_SLOT = 0x03, + + + NVME_LOG_CHANGED_NS_LIST = 0x04, + + + NVME_LOG_COMMAND_EFFECTS_LOG = 0x05, + + + NVME_LOG_DEVICE_SELF_TEST = 0x06, + + + NVME_LOG_TELEMETRY_HOST_INITIATED = 0x07, + + + NVME_LOG_TELEMETRY_CTRLR_INITIATED = 0x08, + + + + + NVME_LOG_DISCOVERY = 0x70, + + + + + NVME_LOG_RESERVATION_NOTIFICATION = 0x80, + + + NVME_LOG_SANITIZE_STATUS = 0x81, + + + + +}; + +enum { + NVME_NO_LOG_LSP = 0x0, + NVME_NO_LOG_LPO = 0x0, + NVME_LOG_ANA_LSP_RGO = 0x1, + NVME_TELEM_LSP_CREATE = 0x1, +}; + + +struct NvmeErrorInformationEntry { + U64 errorCount; + U16 sqid; + U16 cid; + struct NvmeCmdStatus status; + U16 errorLocation; + U64 lba; + U32 nsid; + U8 vendorSpecific; + U8 trtype; + U8 reserved30[2]; + U64 commandSpecific; + U16 trtypeSpecific; + U8 reserved42[22]; +}; + + +union NvmeCriticalWarningState { + U8 raw; + + struct { + U8 availableSpare : 1, + temperature : 1, + deviceReliability : 1, + readOnly : 1, + volatileMemoryBackup : 1, + persistentMemRO : 1, + reserved : 2; + }; +}; + + + +#ifndef _WINDOWS +typedef struct __attribute__((packed)) __attribute__((aligned)) +NvmeHealthInformationPage { +#else +#pragma pack(1) +typedef struct NvmeHealthInformationPage { +#endif + union NvmeCriticalWarningState criticalWarning; + + U16 temperature; + U8 availableSpare; + U8 availableSpareThreshold; + U8 percentageUsed; + U8 enduGrpCritWarnSumry; + + U8 reserved[25]; + + + U64 dataUnitsRead[2]; + + U64 dataUnitsWritten[2]; + + U64 hostReadCommands[2]; + U64 hostWriteCommands[2]; + + U64 controllerBusyTime[2]; + U64 powerCycles[2]; + U64 powerOnHours[2]; + U64 unsafeShutdowns[2]; + U64 mediaErrors[2]; + U64 numErrorInfoLogEntries[2]; + + U32 warningTempTime; + U32 criticalTempTime; + U16 tempSensor[8]; + + U8 reserved2[296]; +}NvmeHealthInformationPage_s; + + +#ifdef _WINDOWS +#pragma pack() +#endif + +struct NvmeCmdsAndEffectEntry { + + U16 csupp : 1; + + + U16 lbcc : 1; + + + U16 ncc : 1; + + + U16 nic : 1; + + + U16 ccc : 1; + + U16 reserved1 : 11; + + U16 cse : 3; + + U16 reserved2 : 13; +}; + + +struct NvmeCmdsAndEffectLogPage { + + struct NvmeCmdsAndEffectEntry adminCmdsSupported[256]; + + + struct NvmeCmdsAndEffectEntry ioCmdsSupported[256]; + + U8 reserved0[2048]; +}; + + + +#ifndef _WINDOWS +struct __attribute__((packed)) NvmeSelfTestResEntry { +#else +#pragma pack(1) +struct NvmeSelfTestResEntry { +#endif + U8 operationRes : 4, + selfTestCode : 4; + U8 segmentNum; + U8 nsIdValid : 1, + flbaValid : 1, + sctValid : 1, + scValid : 1, + reserved1 : 4; + U8 reserved2; + U64 poh; + U32 nsId; + U64 failingLba; + U8 sct : 3, + reserved3 : 5; + U8 sc; + U16 vendorSpecific; +}; +#ifdef _WINDOWS +#pragma pack() +#endif +#ifndef _WINDOWS +typedef struct __attribute__((packed)) NvmeSelfTestLogPage { +#else +#pragma pack(1) +typedef struct NvmeSelfTestLogPage { +#endif + + U8 currtOpt : 4, + reserved1 : 4; + U8 currtComplt : 7, + reserved2 : 1; + U16 reserved3; + struct NvmeSelfTestResEntry newSelfTestRes[20]; +}NvmeSelfTestLogPage_s; +#ifdef _WINDOWS +#pragma pack() +#endif + + +struct NvmeTelemetryLogPageHdr { + + U8 lpi; + U8 rsvd[4]; + U8 ieeeOui[3]; + + U16 dalb1; + + U16 dalb2; + + U16 dalb3; + U8 rsvd1[368]; + + U8 ctrlrAvail; + + U8 ctrlrGen; + + U8 rsnident[128]; + U8 telemetryDatablock[0]; +}; + + + +enum NvmeSanitizeStatusType { + NVME_NEVER_BEEN_SANITIZED = 0x0, + NVME_RECENT_SANITIZE_SUCCESSFUL = 0x1, + NVME_SANITIZE_IN_PROGRESS = 0x2, + NVME_SANITIZE_FAILED = 0x3, +}; + + +struct NvmeSanitizeStatusSstat { + U16 status : 3; + U16 completePass : 5; + U16 globalDataErase : 1; + U16 reserved : 7; +}; + + +struct NvmeSanitizeStatusLogPage { + + U16 sprog; + + struct NvmeSanitizeStatusSstat sstat; + + U32 scdw10; + + U32 etOverwrite; + + U32 etBlockErase; + + U32 etCryptoErase; + U8 reserved[492]; +}; + + + + +enum NvmeAsyncEventType { + + NVME_ASYNC_EVENT_TYPE_ERROR = 0x0, + + NVME_ASYNC_EVENT_TYPE_SMART = 0x1, + + NVME_ASYNC_EVENT_TYPE_NOTICE = 0x2, + + + + NVME_ASYNC_EVENT_TYPE_IO = 0x6, + + NVME_ASYNC_EVENT_TYPE_VENDOR = 0x7, +}; + + +enum NvmeAsyncEventInfoError { + + NVME_ASYNC_EVENT_WRITE_INVALID_DB = 0x0, + + NVME_ASYNC_EVENT_INVALID_DB_WRITE = 0x1, + + NVME_ASYNC_EVENT_DIAGNOSTIC_FAILURE = 0x2, + + NVME_ASYNC_EVENT_PERSISTENT_INTERNAL = 0x3, + + NVME_ASYNC_EVENT_TRANSIENT_INTERNAL = 0x4, + + NVME_ASYNC_EVENT_FW_IMAGE_LOAD = 0x5, + + +}; + + +enum NvmeAsyncEventInfoSmart { + + NVME_ASYNC_EVENT_SUBSYSTEM_RELIABILITY = 0x0, + + NVME_ASYNC_EVENT_TEMPERATURE_THRESHOLD = 0x1, + + NVME_ASYNC_EVENT_SPARE_BELOW_THRESHOLD = 0x2, + + +}; + + +enum NvmeAsyncEventInfoNotice { + + NVME_ASYNC_EVENT_NS_ATTR_CHANGED = 0x0, + + NVME_ASYNC_EVENT_FW_ACTIVATION_START = 0x1, + + NVME_ASYNC_EVENT_TELEMETRY_LOG_CHANGED = 0x2, + + +}; + + +enum NvmeAsyncEventInfoNvmCommandSet { + + NVME_ASYNC_EVENT_RESERVATION_LOG_AVAIL = 0x0, + + NVME_ASYNC_EVENT_SANITIZE_COMPLETED = 0x1, + + +}; + + +union NvmeAsyncEventCompletion { + U32 raw; + struct { + U32 asyncEventType : 3; + U32 reserved1 : 5; + U32 asyncEventInfo : 8; + U32 logPageIdentifier : 8; + U32 reserved2 : 8; + }; +}; + + + +union NvmeFeatArbitration { + U32 raw; + struct { + + U32 ab : 3; + + U32 reserved : 5; + + + U32 lpw : 8; + + + U32 mpw : 8; + + + U32 hpw : 8; + }; +}; + + + +union NvmeFeatPowerManagement { + U32 raw; + struct { + + U32 ps : 5; + + + U32 wh : 3; + + U32 reserved : 24; + }; +}; + + + +union NvmeFeatLbaRangeType { + U32 raw; + struct { + + U32 num : 6; + + U32 reserved : 26; + }; +}; + + + +union NvmeFeatTemperatureThreshold { + U32 raw; + struct { + + U32 tmpth : 16; + + + U32 tmpsel : 4; + + + U32 thsel : 2; + + U32 reserved : 10; + }; +}; + + + + +union NvmeFeatErrorRecovery { + U32 raw; + struct { + + U32 tler : 16; + + + U32 dulbe : 1; + + U32 reserved : 15; + }; +}; + + + +union NvmeFeatVolatileWriteCache { + U32 raw; + struct { + + U32 wce : 1; + + U32 reserved : 31; + }; +}; + + + +union NvmeFeatNumberOfQueues { + U32 raw; + struct { + + U32 nsqr : 16; + + + U32 ncqr : 16; + }; +}; + + + +union NvmeFeatInterruptCoalescing { + U32 raw; + struct { + + U32 thr : 8; + + + U32 time : 8; + + U32 reserved : 16; + }; +}; + + + + +union NvmeFeatInterruptVectorConfiguration { + U32 raw; + struct { + + U32 iv : 16; + + + U32 cd : 1; + + U32 reserved : 15; + }; +}; + + + + +union NvmeFeatWriteAtomicity { + U32 raw; + struct { + + U32 dn : 1; + + U32 reserved : 31; + }; +}; + + + + +union NvmeFeatAsyncEventConfiguration { + U32 raw; + struct { + union NvmeCriticalWarningState critWarn; + U32 nsAttrNotice : 1; + U32 fwActivationNotice : 1; + U32 telemetryLogNotice : 1; + U32 reserved : 21; + }; +}; + + + +#define NvmeAsyncEventConfig NvmeFeatAsyncEventConfiguration + + + +union NvmeFeatAutonomousPowerStateTransition { + U32 raw; + struct { + + U32 apste : 1; + + U32 reserved : 31; + }; +}; + + + + +union NvmeFeatHostMemBuffer { + U32 raw; + struct { + + U32 ehm : 1; + + + U32 mr : 1; + + U32 reserved : 30; + }; +}; + + + +union NvmeFeatKeepAliveTimer { + + U32 kato; +}; + + + + +union NvmeFeatHostControlledThermalManagement { + U32 raw; + struct { + + U32 tmt2 : 16; + + + U32 tmt1 : 16; + }; +}; + + + + + +union NvmeFeatNonOperationalPowerStateConfig { + U32 raw; + struct { + + U32 noppme : 1; + + U32 reserved : 31; + }; +}; + + + + + +union NvmeFeatSoftwareProgressMarker { + U32 raw; + struct { + + U32 pbslc : 8; + U32 reserved : 24; + }; +}; + + + + +union NvmeFeatHostIdentifier { + U32 raw; + struct { + + U32 exhid : 1; + + U32 reserved : 31; + }; +}; + + + +struct NvmeFirmwarePage { + U8 afi; + + U8 reserved[7]; + U8 revision[7][8]; + U8 reserved2[448]; +}; + + + +enum NvmeNsAttachType { + + NVME_NS_CTRLR_ATTACH = 0x0, + + + NVME_NS_CTRLR_DETACH = 0x1, + + +}; + + +enum NvmeNsManagementType { + + NVME_NS_MANAGEMENT_CREATE = 0x0, + + + NVME_NS_MANAGEMENT_DELETE = 0x1, + + +}; + +struct NvmeNsList { + U32 nsList[1024]; +}; + + +enum NvmeNidt { + + NVME_NIDT_EUI64 = 0x01, + + + NVME_NIDT_NGUID = 0x02, + + + NVME_NIDT_UUID = 0x03, +}; + +struct NvmeNsIdDesc { + + U8 nidt; + + + U8 nidl; + + U8 reserved2; + U8 reserved3; + + + U8 nid[]; +}; + + +typedef struct NvmeCtrlrList { + U16 ctrlrCount; + U16 ctrlrList[2047]; +}NvmeCtrlrList_s; + + +enum NvmeSecureEraseSetting { + NVME_FMT_NVM_SES_NO_SECURE_ERASE = 0x0, + NVME_FMT_NVM_SES_USER_DATA_ERASE = 0x1, + NVME_FMT_NVM_SES_CRYPTO_ERASE = 0x2, +}; + +enum NvmePiLocation { + NVME_FMT_NVM_PROTECTION_AT_TAIL = 0x0, + NVME_FMT_NVM_PROTECTION_AT_HEAD = 0x1, +}; + +enum NvmePiType { + NVME_FMT_NVM_PROTECTION_DISABLE = 0x0, + NVME_FMT_NVM_PROTECTION_TYPE1 = 0x1, + NVME_FMT_NVM_PROTECTION_TYPE2 = 0x2, + NVME_FMT_NVM_PROTECTION_TYPE3 = 0x3, +}; + +enum NvmeMetadataSetting { + NVME_FMT_NVM_METADATA_TRANSFER_AS_BUFFER = 0x0, + NVME_FMT_NVM_METADATA_TRANSFER_AS_LBA = 0x1, +}; + +struct NvmeFormat { + U32 lbaf : 4; + U32 ms : 1; + U32 pi : 3; + U32 pil : 1; + U32 ses : 3; + U32 reserved : 20; +}; + + +struct NvmeProtectionInfo { + U16 guard; + U16 appTag; + U32 refTag; +}; + + + +enum NvmeFwCommitAction { + NVME_FW_COMMIT_REPLACE_IMG = 0x0, + NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG = 0x1, + NVME_FW_COMMIT_ENABLE_IMG = 0x2, + NVME_FW_COMMIT_RUN_IMG = 0x3, +}; + + +enum NvmeDeviceSelfTestCode { + NVME_SHORT_DEVICE_SELF_TEST_OPT = 0x1, + NVME_EXTENDED_DEVICE_SELF_TEST_OPT = 0x2, + NVME_ABORT_DEVICE_SELF_TEST_OPT = 0xF, +}; + + +struct NvmeFwCommit { + U32 fs : 3; + U32 ca : 3; + U32 reserved : 26; +}; + + +#define NVME_CPL_IS_SUCCESS(cpl) (!NVME_CMD_STATUS_NOT_SUCCESS(cpl)) + +#define NVME_CMD_STATUS_NOT_SUCCESS(cpl) \ + ((cpl)->status.sc != NVME_SC_SUCCESS || \ + (cpl)->status.sct != NVME_SCT_GENERIC) + +#define NVME_STATUS_CMD_ABORT_REQUEST(cpl) \ + ((cpl)->status.sc == NVME_SC_ABORTED_BY_REQUEST && \ + (cpl)->status.sct == NVME_SCT_GENERIC) + +#define NVME_CPL_PI_IS_ERROR(cpl) \ + ((cpl)->status.sct == NVME_SCT_MEDIA_ERROR && \ + ((cpl)->status.sc == NVME_SC_GUARD_CHECK_ERROR || \ + (cpl)->status.sc == NVME_SC_APPLICATION_TAG_CHECK_ERROR || \ + (cpl)->status.sc == NVME_SC_REFERENCE_TAG_CHECK_ERROR)) + + + +#define NVME_IO_FLAGS_PRCHK_REFTAG (1U << 26) + +#define NVME_IO_FLAGS_PRCHK_APPTAG (1U << 27) + +#define NVME_IO_FLAGS_PRCHK_GUARD (1U << 28) + +#define NVME_IO_FLAGS_PRACT (1U << 29) +#define NVME_IO_FLAGS_FORCE_UNIT_ACCESS (1U << 30) +#define NVME_IO_FLAGS_LIMITED_RETRY (1U << 31) + +#define NVME_FORMAT_SES_BIT_MASK 0x7UL +#define NVME_FORMAT_SES_BIT_SHIFT 9 +#define NVME_LBAF_MASK 0xFUL +#define NVME_FORMAT_SES_TYPE_NONE 0x0 +#define NVME_FORMAT_SES_TYPE_USER_DATA_ERASE 0x1 +#define NVME_FORMAT_SES_TYPE_CRYPTO_ERASE 0x2 +typedef union NvmeFormatCmdDw10 { + struct { + U32 lbaf:4; + U32 mset:1; + U32 pi:3; + U32 pil:1; + U32 ses:1; + U32 reseved:3; + }; + U32 rawVal; +} NvmeFormatCmdDw10_u; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_register_fifo.h b/drivers/scsi/ps3stor/include/ps3_register_fifo.h new file mode 100644 index 0000000000000000000000000000000000000000..3a1336af889a602c6d0614aa5fe1a88ffc0be801 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_register_fifo.h @@ -0,0 +1,38 @@ + +#ifndef __PS3_REGISTER_FIFO_H__ +#define __PS3_REGISTER_FIFO_H__ + +#include "hwapi/include_v200/s1861_regs/s1861_global_baseaddr.h" +#include "hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_request_queue_reg.h" +#include "hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_f_reg.h" +#include "hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_s_reg.h" + +#ifdef __cplusplus +extern "C" { +#endif +typedef union ps3RequestFifo { + U8 reserved0[HIL_REG0_PS3_REQUEST_QUEUE_SIZE]; + HilReg0Ps3RequestQueue_s request_fifo; +} ps3RequestFifo_u; + +typedef union ps3RegShare{ + U8 reserved0[HIL_REG0_PS3_REGISTER_S_SIZE]; + HilReg0Ps3RegisterS_s share_reg; +} ps3RegShare_u; + +typedef union ps3RegExclusive{ + U8 reserved0[HIL_REG0_PS3_REGISTER_F_SIZE]; + HilReg0Ps3RegisterF_s Excl_reg; +} ps3RegExclusive_u; + +typedef struct Ps3Fifo{ + ps3RegExclusive_u reg_f; + ps3RequestFifo_u cmd_fifo; + ps3RegShare_u reg_s; +} Ps3Fifo_s; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_trace_id.h b/drivers/scsi/ps3stor/include/ps3_trace_id.h new file mode 100644 index 0000000000000000000000000000000000000000..a442d81e62ff7a3ba2baac77987965e013b2f13e --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_trace_id.h @@ -0,0 +1,40 @@ + +#ifndef __PS3_TRACE_ID_H__ +#define __PS3_TRACE_ID_H__ + +#define TRACE_ID_CHIP_OUT_COUNT_MASK 0x000FFFFFFFFFFFFFLLU + +#define TRACE_ID_CHIP_OUT_CPUID_SHIFT 52 +#define TRACE_ID_CHIP_OUT_CPUID_MASK 0x7FFLLU + +static inline void traceIdCpuIdSet(unsigned long long *traceId, unsigned short cpuId) +{ + *traceId &= ~(TRACE_ID_CHIP_OUT_CPUID_MASK << TRACE_ID_CHIP_OUT_CPUID_SHIFT); + *traceId |= ((unsigned long long)cpuId & TRACE_ID_CHIP_OUT_CPUID_MASK) << \ + TRACE_ID_CHIP_OUT_CPUID_SHIFT; +} + +#define TRACE_ID_CLI_COUNT_MASK 0x00000000000000FFLLU +#define TRACE_ID_CLI_TID_MASK 0x0000000000FFFF00LLU +#define TRACE_ID_CLI_TIME_MASK 0x00FFFFFFFF000000LLU +#define TRACE_ID_CLI_FLAG 0xFF00000000000000LLU + +#define TRACE_ID_CLI_COUNT_SHIFT 0 +#define TRACE_ID_CLI_TID_SHIFT 8 +#define TRACE_ID_CLI_TIME_SHIFT 24 +#define TRACE_ID_CLI_FLAG_SHIFT 56 + +#define TRACE_ID_CHIP_IN_COUNT_MASK 0x00FFFFFFFFFFFFFFLLU +#define TRACE_ID_CHIP_IN_FLAG 0x8000000000000000LLU + +#define TRACE_ID_CHIP_IN_CONTEXTID_SHIFT 56 +#define TRACE_ID_CHIP_IN_CONTEXTID_MASK 0x7FLLU + +static inline void traceIdContextIdSet(unsigned long long *traceId, unsigned short contextId) +{ + *traceId &= ~(TRACE_ID_CHIP_IN_CONTEXTID_MASK << TRACE_ID_CHIP_IN_CONTEXTID_SHIFT); + *traceId |= ((unsigned long long)contextId & TRACE_ID_CHIP_IN_CONTEXTID_MASK) << \ + TRACE_ID_CHIP_IN_CONTEXTID_SHIFT; +} + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3_types.h b/drivers/scsi/ps3stor/include/ps3_types.h new file mode 100644 index 0000000000000000000000000000000000000000..4cae419780556fd13eb8f0f721b2262ab2961741 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3_types.h @@ -0,0 +1,123 @@ + +#ifndef __PS3_TYPES_H__ +#define __PS3_TYPES_H__ + +#ifdef __cplusplus +extern "C"{ +#endif + +#ifndef __KERNEL__ +#include +#endif + +typedef unsigned char U8; +typedef unsigned short U16; +typedef unsigned int U32; +typedef unsigned long ULong; +typedef unsigned long long U64; + +typedef char S8; +typedef short S16; +typedef int S32; +typedef long Long; +typedef long long S64; + +typedef U32 CtrlId_t; +typedef S32 Ps3Errno; +typedef U16 DgId_t; +typedef U16 VdId_t; +typedef U16 PdId_t; +typedef U8 EnclId_t; +typedef U16 SlotId_t; +typedef U8 PhyId_t; + +#define PS3_FALSE 0 +#define PS3_TRUE 1 +typedef int Ps3Bool_t; + +#ifndef BOOL +#define BOOL Ps3Bool_t +#endif + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif + +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t)(&((TYPE *)0)->MEMBER)) +#endif + + +#ifndef PS3_MIN +#define PS3_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + + +#ifndef PS3_MAX +#define PS3_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + + +#ifndef PS3_MIN_NON_ZERO +#define PS3_MIN_NON_ZERO(a, b) ((a) == 0 ? (b) : \ + ((b) == 0 ? (a) : (PS3_MIN(a, b)))) +#endif + +#ifndef TYPEOF +#ifdef __cplusplus +#define TYPEOF decltype +#else +#define TYPEOF typeof +#endif +#endif + +#ifndef container_of +#ifndef PCLINT +#define container_of(ptr, type, member) ({ \ + const TYPEOF( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#else +#define container_of(ptr, type, member) \ + ((type *)(void *)(char *)ptr) +#endif +#endif + +#ifndef PS3_DESC +#define PS3_DESC(a) 1 +#endif + + +#ifndef PS3_IN +#define PS3_IN +#endif + +#ifndef PS3_OUT +#define PS3_OUT +#endif + +typedef Ps3Bool_t (*RmCheckFunc)(void *pSubSchedTask); + +typedef union RmMiscInfo +{ + struct { + U8 idx; + U8 status; + U8 valid; + U8 hasInQueued; + }; + U32 val; +}RmMiscInfo_s; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/scsi/ps3stor/include/ps3lib/ps3lib_event.h b/drivers/scsi/ps3stor/include/ps3lib/ps3lib_event.h new file mode 100644 index 0000000000000000000000000000000000000000..624e4563b9924d02996edef7fee55bf33f07bcb2 --- /dev/null +++ b/drivers/scsi/ps3stor/include/ps3lib/ps3lib_event.h @@ -0,0 +1,789 @@ + +#ifndef __PS3LIB_EVENT_H__ +#define __PS3LIB_EVENT_H__ + +#if defined(__cplusplus) +extern "C" { +#endif + +#define PS3LIB_MAX_VD_NAME_BYTES (16) +#define PS3LIB_CTRL_AUTOCONFIG_EVTDATA_SIZE (8) +#define PS3LIB_BBM_ERRTBL_NAME_LEN (6) +#define PS3LIB_EVT_DESC_MAX_LEN (4096) +#define PS3LIB_FGI_MODE_LEN (5) +#define PS3LIB_EVT_LOG_INFO_MAX_SIZE (116) +#define PS3LIB_EXP_EVENT_DATA_COLLECT_MAX_NUM (256) +#define PS3LIB_MAX_EVENT_REG_CNT (128) + +enum { + PS3LIB_EVT_LOG_OLDEST, + PS3LIB_EVT_LOG_LATEST, + PS3LIB_EVT_LOG_LAST_CLEAR, + PS3LIB_EVT_LOG_LAST_REBOOT, + PS3LIB_EVT_LOG_LAST_SHUTDOWN, + PS3LIB_EVT_LOG_FATAL_OLDEST, + PS3LIB_EVT_LOG_FATAL_LATEST, + PS3LIB_EVT_LOG_LAST_MAX, +}; + +typedef enum Ps3LibEpEventLevel +{ + PS3LIB_EVT_CLASS_UNKNOWN = 0b0000, + PS3LIB_EVT_CLASS_DEBUG = 0b0011, + PS3LIB_EVT_CLASS_PROCESS = 0b0101, + PS3LIB_EVT_CLASS_INFO = 0b0001, + PS3LIB_EVT_CLASS_WARNING = 0b0010, + PS3LIB_EVT_CLASS_CRITICAL = 0b0100, + PS3LIB_EVT_CLASS_FATAL = 0b1000, + PS3LIB_EVT_CLASS_MAX, +} Ps3LibEpEventLevel_e; + +enum +{ + PS3LIB_CTRL_EVT_SAS_INFO_LOCAL = 1, + PS3LIB_CTRL_EVT_PD_COUNT_LOCAL = 2, + PS3LIB_CTRL_EVT_VD_COUNT_LOCAL = 3, + PS3LIB_CTRL_EVT_CTRL_INFO_LOCAL = 4, + PS3LIB_CTRL_EVT_PD_ATTR_LOCAL = 5, + PS3LIB_CTRL_EVT_VD_ATTR_LOCAL = 6, + PS3LIB_CTRL_EVT_DG_INFO_LOCAL = 7, + PS3LIB_CTRL_EVT_BBU_INFO_LOCAL = 8, + PS3LIB_CTRL_EVT_CONFIG_LOCAL = 9, + PS3LIB_CTRL_EVT_IO_INFO_LOCAL = 10, + PS3LIB_CTRL_EVT_UKEY_INFO_LOCAL = 11, + PS3LIB_CTRL_EVT_HWR_INFO_LOCAL = 12, + PS3LIB_CTRL_EVT_ALARM_INFO_LOCAL = 13, + PS3LIB_CTRL_EVT_ECC_INFO_LOCAL = 14, + PS3LIB_CTRL_EVT_UPGRADE_INFO_LOCAL = 15, + PS3LIB_CTRL_EVT_TEMP_INFO_LOCAL = 16, + PS3LIB_CTRL_EVT_PD_ATTR_EXTEND_LOCAL = 17, + PS3LIB_CTRL_EVT_DEFAULT_UNUSED_LOCAL, + PS3LIB_CTRL_EVT_MAX_TYPE_LOCAL, +}; + +typedef struct Ps3LibEvtLogRdEntry { + U32 loopCnt; + U32 seqNum; + U32 offset; + U32 timeStampBySec; + U32 size; +} Ps3LibEvtLogRdEntry_s; + +typedef struct Ps3LibEvtLogRdInfo { + Ps3LibEvtLogRdEntry_s persistInfo[PS3LIB_EVT_LOG_LAST_MAX]; +} Ps3LibEvtLogRdInfo_s; + +typedef struct Ps3LibEvtPersistInfo { + U32 regionSz[2]; + Ps3LibEvtLogRdInfo_s persist; +} Ps3LibEvtPersistInfo_s; + +typedef struct Ps3LibEvtLogHeader { + U32 magic; + U32 seqNum; + U32 size : 8; + U32 funcType : 2; + U32 conFlag : 1; + U32 evtCode : 12; + U32 level : 4; + U32 type : 5; + U32 timeStampBySec; +} Ps3LibEvtLogHeader_s; + +#pragma pack(1) + +typedef struct Ps3LibPdAttrInfo { + U32 checkSum : 8; + U32 enclosureId : 8; + U32 phyId : 8; + U32 evtVersion : 8; + U16 phyDiskID; + U16 softChan : 4; + U16 devID : 12; + U16 slotId; + U16 oldState : 4; + U16 newState : 4; + U16 isEnclPd : 1; + U16 longFault : 1; + U16 reason : 6; + U16 arrayId : 8; + U16 rowId : 8; + U16 prevState : 8; + U16 curState : 8; + U64 sasAddr; +}Ps3LibPdAttrInfo_s; + +typedef struct Ps3LibSparePdInfo { + Ps3LibPdAttrInfo_s baseInfo; + U8 dedicatedDgCnt; + U8 reserved[3]; + U16 dedicatedDgId[8]; +}Ps3LibSparePdInfo_s; + +typedef struct Ps3LibVdAttrInfo { + U32 magicNum; + U16 virtDiskID; + U16 softChan : 4, + devID : 12; + U16 diskGrpId; + U16 locked : 1, + pad : 15; +}Ps3LibVdAttrInfo_s; + +typedef struct Ps3LibDiskPFCfgModifyEvtInfo { + U8 modifyCfgDataType; + U8 funcIsEnable:1; + U8 pad : 7; + U16 preFailPollTimeMin; +}Ps3LibDiskPFCfgModifyEvtInfo_s; + +typedef struct Ps3LibVdBaseSetting { + U32 accessPolicy :2, + hidden :1, + defaultWriteCachePolicy :2, + currentWriteCachePolicy :1, + defaultReadCachePolicy :1, + currentReadCachePolicy :1, + diskCachePolicy :2, + ioPolicy :1, + noBgi :1, + emulationType :2, + unmap :1, + cbSize :2, + cbMode :3, + encryption :1, + rebootNoVerify :1, + rsv :10; + U8 vdName[PS3LIB_MAX_VD_NAME_BYTES]; + U64 size; +}Ps3LibVdBaseSetting_s; + +typedef struct Ps3LibVdPropertiesInfo { + Ps3LibVdAttrInfo_s baseInfo; + Ps3LibVdBaseSetting_s oldSetting; + Ps3LibVdBaseSetting_s newSetting; +}Ps3LibVdPropertiesInfo_s; + +typedef struct Ps3LibVdStateChangeInfo { + Ps3LibVdAttrInfo_s baseInfo; + U8 oldVdState; + U8 newVdState; + U8 reserved[2]; +}Ps3LibVdStateChangeInfo_s; + +typedef struct Ps3LibVdCreateEvtInfo { + Ps3LibVdAttrInfo_s baseInfo; + Ps3LibVdBaseSetting_s setting; +}Ps3LibVdCreateEvtInfo_s; + +typedef struct Ps3LibCtrlAttrInfo { + U32 supportUnevenSpans : 1; + U32 supportJbodSecure : 1; + U32 supportCrashDump : 1; + U32 supportNvmePassthru : 1; + U32 supportDirectCmd : 1; + U32 supportAcceleration : 1; + U32 supportNcq : 1; + U32 reserved1 : 25; + U32 reserved2[1]; + U64 oldSysTime; + U64 newSysTIme; + U64 monoSysTime; + U32 newSysTimeYear; + U32 newSysTimeMon; + U32 newSysTimeDay; + U32 newSysTimeHour; + U32 newSysTimeMin; + U32 newSysTimeSec; + U64 cfgNum; + U8 *pValue; + U32 len; +}Ps3LibCtrlAttrInfo_s; + +typedef struct Ps3LibCtrlRebootInfo { + U16 ctrlBootMode; + U16 ctrlShutDownReason; + + + + + + U32 regBootValue; +}Ps3LibCtrlRebootInfo_s; + +typedef struct Ps3LibDgAttrInfo { + U16 dgId; + U16 reserved[3]; +}Ps3LibDgAttrInfo_s; + +typedef struct Ps3LibExpanderInfo { + U8 EnclId; + U8 port; + U8 reserved[6]; +}Ps3LibExpanderInfo_s; + +typedef struct Ps3LibCfgAttrInfo { + U16 profileId; + U8 reserved[2]; +}Ps3LibCfgAttrInfo_s; + +typedef struct Ps3LibCfgAutoConfig { + S8 cfgName[PS3LIB_CTRL_AUTOCONFIG_EVTDATA_SIZE]; +}Ps3LibCfgAutoConfig_s; + +typedef struct Ps3LibCtrlPowerMode { + U8 mode; + U8 rsv[3]; +}Ps3LibCtrlPowerMode_s; + +typedef struct Ps3LibBgtRebuildInfo { + U16 newPDFlatId; + U16 newEnclosureId; + U16 newSlotId; + U16 oldPDFlatId; + U16 oldEnclosureId; + U16 oldSlotId; + U16 virtDiskId; + U16 devId; + U32 remainSecs; + U64 errorPba; + U64 errorLba; + U8 progressPercent; + U8 rebuildRate; + U8 enableMoveback; + U8 autoRebuild; + U8 eghs; + U8 enablePdm; + U8 pdmSupportReadyPd; + U8 reserved[1]; + U32 pdmTimerInterval; +} Ps3LibBgtRebuildInfo_s; + +typedef struct Ps3LibBgtInitEvtInfo { + U32 aliveSec; + U32 progressRate; + U16 dgId; + U16 virtDiskId; + U16 pdFlatId; + U16 enclosureId; + U16 slotId; + U8 cpuRate; + S8 mode[PS3LIB_FGI_MODE_LEN]; + U64 mediumErrLba; + U64 mediumErrPba; + U16 MediumErrPdFlatId; + U16 softChan : 4; + U16 devID : 12; +} Ps3LibBgtInitEvtInfo_s; + +typedef struct Ps3LibBgtEraseEvtInfo { + U32 aliveSec; + U32 progressRate; + U16 dgId; + U16 virtDiskId; + U16 pdFlatId; + U16 enclosureId; + U16 slotId; + U16 devId; +} Ps3LibBgtEraseEvtInfo_s; + +typedef struct Ps3LibBgtCcEvtInfo { + U32 aliveSecs; + U8 progressPercent; + U8 ccRate; + U8 mode; + U8 resered; + U16 virtDiskID; + U16 diskGroupID; + U32 inconsistStrip; + U16 devId; + U16 faultDiskID; + U16 enclosureId; + U16 slotId; + U64 pdErrLba; + U64 vdErrLba; +}Ps3LibBgtCcEvtInfo_s; + +typedef struct Ps3LibBgtPrEvtInfo { + U32 aliveSecs; + U16 enclosureId; + U16 slotId; + U8 progressPercent; + U8 prRate; + U16 virtDiskID; + U16 pdFlatId; + U16 diskGroupID; + U16 dgStatus; + U8 reserved[2]; + U64 errLba; +}Ps3LibBgtPrEvtInfo_s; + +typedef struct Ps3LibPhyEvtInfo { + U32 enclosureId:8, + slotId:8, + phyId:8, + reason:8; +} Ps3LibPhyEvtInfo_s; + +typedef struct Ps3LibVdBbmEvtInfo { + U64 lba; + U64 pba; + U16 lbaLen; + U16 dgId; + U16 virtDiskId; + U16 percentErrTbl; + U16 devId; + S8 errTblName[PS3LIB_BBM_ERRTBL_NAME_LEN]; + U16 pdFlatId; + U16 enclosureId; + U16 slotId; + U16 reserved; +} Ps3LibVdBbmEvtInfo_s; + +typedef struct Ps3LibRwDdtEvtInfo { + U16 virtDiskID; + U16 diskGroupID; + U32 vdLen; + U64 vdLba; +} Ps3LibRwDdtEvtInfo_s; + +typedef struct Ps3LibFlushEvtInfo { + U16 opcode; + U16 dgId; + U16 virtDiskId; + U16 minVdId; + U16 devId; + U8 reserved[6]; + U64 vdIdMap[3]; +} Ps3LibFlushEvtInfo_s; + +typedef struct Ps3LibMigrationInfo { + U8 migrRate; + U8 resv; + U16 diskGroupID; + U32 percent; + U32 aliveSec; + U16 currVdId; + U8 reserved[2]; +} Ps3LibMigrationInfo_s; + +typedef struct Ps3LibVdBbmBatchEvtInfo +{ + U32 count; + Ps3LibVdBbmEvtInfo_s vdBbmEvtInfo[0]; +} Ps3LibVdBbmBatchEvtInfo_s; + +typedef struct Ps3LibVdBatchEvtInfo +{ + U32 count; + Ps3LibVdAttrInfo_s vdInfo[0]; +}Ps3LibVdBatchEvtInfo_s; + +typedef struct Ps3LibPdBatchEvtInfo +{ + U32 count; + Ps3LibPdAttrInfo_s pdInfo[0]; +}Ps3LibPdBatchEvtInfo_s; + +typedef struct Ps3LibCtrlBatchEvtInfo +{ + U32 count; + Ps3LibCtrlAttrInfo_s ctrlInfo[0]; +}Ps3LibCtrlBatchEvtInfo_s; + +typedef struct Ps3libBatchEvtInfoCommon +{ + U32 count; + S8 batchInfo[0]; +}Ps3libBatchEvtInfoCommon_s; + +typedef struct Ps3LibBbuEvtInfo { + U8 absent : 1; + U8 overTemp : 1; + U8 overVol : 1; + U8 overCur : 1; + U8 overLoad : 1; + U8 lifeisOver : 1; + U8 reserved : 2; + U8 status; + U8 chargeStatus; + U8 learnStage; + S16 batTemperature; + U16 batVoltage; + S16 batCurrent; + U8 reserved1[2]; +} Ps3LibBbuEvtInfo_s; + +typedef struct Ps3LibUkeyEvtInfo { + U8 ukeyStatus; + U8 reserved[3]; +} Ps3LibUkeyEvtInfo_s; + +typedef struct Ps3LibExpEvtInfo { + U64 expanderSasAddr; + U64 attachedSasAddr; + U8 phyId[8]; +} Ps3LibExpEvtInfo_s; + +typedef struct Ps3LibEccEvtInfo { + U32 eccErrObj; + U32 eccSingleBitCntInc; + U8 eccErrCntThreshold; + U8 pad[3]; + U16 eccClearPeriod; + U8 eccType; + U8 eccErrSubObj; + U64 eccMutilErrAddr; + U32 eccEvtVersion; +} Ps3LibEccEvtInfo_s; + +typedef struct Ps3LibTempEvtInfo { + U32 tempType; + S32 tempErrThreshold[4]; + S32 temperature; +} Ps3LibTempEvtInfo_s; + +typedef struct Ps3LibIoCmdType { + U8 cmdType; + U8 rsv[9]; +} Ps3LibIoCmdType_s; + +typedef struct Ps3LibDeviceResetEvtInfo { + U16 enclosureId; + U16 slotId; + U16 phyDiskID; + U16 resetType; + U64 sasAddress; +} Ps3LibDeviceResetEvtInfo_s; + +typedef struct Ps3LibSenseDataEvtInfo { + U16 enclosureId; + U16 slotId; + U16 phyDiskID; + union { + U8 cdb[10]; + Ps3LibIoCmdType_s ioCmdType; + }; + U8 ioFormat; + U8 palErr; + U8 dataPre; + U8 scsiStatus; + U8 skStatus; + U8 sk; + U8 asc; + U8 ascq; + U64 path; +} Ps3LibSenseDataEvtInfo_s; + +typedef struct Ps3LibErrSenseEvtInfo { + U16 enclosureId; + U16 slotId; + U16 phyDiskID; + U8 CDBLen; + U8 senseLen; + U8 cdb[32]; + U8 senseData[56]; + U8 sk; + U8 asc; + U8 ascq; + U8 resv; + U64 path; +} Ps3LibErrSenseEvtInfo_s; + +typedef struct Ps3LibPdDownloadInfo { + U32 downloadMode; + S32 isSuccess; + U16 phyDiskID; + U16 softChan : 4; + U16 devID : 12; + U16 enclosureId; + U16 slotId; +}Ps3LibPdDownloadInfo_s; + +typedef struct Ps3LibSanitizeEvtInfo { + Ps3LibPdAttrInfo_s baseInfo; + U32 aliveSecs; + U8 progressPercent; + U8 pad[3]; +}Ps3LibSanitizeEvtInfo_s; + +typedef struct Ps3LibFormatEvtInfo { + Ps3LibPdAttrInfo_s baseInfo; + U32 aliveSecs; + U8 progressPercent; + U8 pad[3]; +}Ps3LibFormatEvtInfo_s; + +typedef struct Ps3LibSnapshotEvtInfo { + U8 snapCount; + U8 pad[3]; +}Ps3LibSnapshotEvtInfo_s; + +typedef struct Ps3LibPdPreFailInfo { + U32 checkSum : 8; + U32 oldState : 4; + U32 newState : 4; + U32 diskType : 4; + U32 pad : 12; + U16 phyDiskID; + U16 softChan : 4; + U16 devID : 12; + U16 enclosureId; + U16 slotId; + U32 historyErrBitMap; + U32 errBitMap; + S8 vendor[8]; + S8 diskSerialNum[24]; +}Ps3LibPdPreFailInfo_s; + +typedef struct Ps3LibNvDataInvaildInfo { + U32 nvDataIDBitMap[16]; + U16 bitmapSize; + U16 invaildCount; +} Ps3LibNvDataInvaildInfo_s; + +typedef struct Ps3LibSpeedNegoInfo { + U16 enclosureId; + U16 slotId; + S8 isPcie; + S8 speed; + U8 width; + U8 type; +}Ps3LibSpeedNegoInfo_s; + +typedef struct Ps3LibInitFailInfo { + U64 errCode; + U8 initFailCnt; + U8 pad[3]; +} Ps3LibInitFailInfo_s; + +typedef struct Ps3LibOemInfo { + S8 oemData[PS3LIB_EVT_LOG_INFO_MAX_SIZE]; +} Ps3LibOemInfo_s; + +typedef struct Ps3LibBplaneEvtInfo { + S8 bplaneData[PS3LIB_EVT_LOG_INFO_MAX_SIZE]; +} Ps3LibBplaneEvtInfo_s; + +typedef struct Ps3LibTriModeInfo { + U8 connectorId; + U8 subConnectorId; + U8 curMode; + U8 rev; +} Ps3LibTriModeInfo_s; + +typedef struct Ps3LibPhyChgInfo { + U8 portId; + U8 phyId; + U8 reason; + U8 rev; +} Ps3LibPhyChgInfo_s; + +typedef struct Ps3LibPhyInquiryInfo { + U32 pdId; + U16 slotId; + U16 enclosureId; + S8 vendor[9]; + S8 diskModelNum[41]; + S8 diskSerialNum[25]; + U8 rev; + U16 sectorSize; + U16 res; + U64 physicalSize; +} Ps3LibPhyInquiryInfo_s; + +typedef struct Ps3LibSmpFailInfo { + U8 enclId; + U8 function; + U8 rev[2]; + U32 code; +} Ps3LibSmpFailInfo_s; + +typedef union Ps3LibNvmeEvtInfo { + struct { + U8 sqe[64]; + U64 path; + U16 enclosureId; + U16 slotId; + U16 phyDiskId; + U16 sf; + U32 cmdSpecfic; + U32 type:8; + U32 isAdminCmd:1; + U32 rsvd:23; + }; +} Ps3LibNvmeEvtInfo_u; + +typedef struct Ps3LibSasSataLinkSpeedMatchInfo { + U8 channelId; + U8 lPhyId; + U8 linkSpeed; + U8 pad1; + U32 pad2; +} Ps3LibSasSataLinkSpeedMatchInfo_s; + +typedef struct Ps3LibSasSataLNExceptionInfo { + U8 channelId; + U8 lPhyId; + U16 pad1; + U32 type; + U32 status; + U32 pad2; +} Ps3LibSasSataLNExceptionInfo_s; + +typedef struct Ps3LibSasSataDriverInfo { + U8 channelId; + U8 lPhyId; + U16 pad1; + U32 type; + U32 status; + U32 pad2; +} Ps3LibSasSataDriverInfo_s; + +typedef union Ps3LibReportEvtData +{ + Ps3LibPdAttrInfo_s pdInfo; + Ps3LibSparePdInfo_s sparePdInfo; + Ps3LibVdAttrInfo_s vdInfo; + Ps3LibVdPropertiesInfo_s vdChange; + Ps3LibVdStateChangeInfo_s vdStateChangeInfo; + Ps3LibVdCreateEvtInfo_s vdCreate; + Ps3LibCtrlAttrInfo_s ctrlInfo; + Ps3LibCtrlRebootInfo_s ctrlRebootInfo; + Ps3LibDgAttrInfo_s dgInfo; + Ps3LibExpanderInfo_s expanderInfo; + Ps3LibCfgAttrInfo_s cfgInfo; + Ps3LibCfgAutoConfig_s autoConfigInfo; + + Ps3LibBgtRebuildInfo_s bgtRebuildInfo; + Ps3LibBgtInitEvtInfo_s bgtInitEvtInfo; + Ps3LibBgtEraseEvtInfo_s bgtEraseEvtInfo; + Ps3LibBgtCcEvtInfo_s bgtCcInfo; + + Ps3LibBgtPrEvtInfo_s bgtPrInfo; + + Ps3LibPhyEvtInfo_s phyInfo; + + Ps3LibVdBbmEvtInfo_s vdBbmEvtInfo; + Ps3LibRwDdtEvtInfo_s dataVdInfo; + + Ps3LibFlushEvtInfo_s flushEvtInfo; + + Ps3LibMigrationInfo_s bgtMigrInfo; + + Ps3LibVdBatchEvtInfo_s batchVdInfo; + Ps3LibPdBatchEvtInfo_s batchPdInfo; + Ps3LibCtrlBatchEvtInfo_s batchCtrlInfo; + Ps3LibVdBbmBatchEvtInfo_s batchBbmInfo; + Ps3libBatchEvtInfoCommon_s *pBatchCommonInfo; + Ps3LibBbuEvtInfo_s bbuEvtInfo; + Ps3LibUkeyEvtInfo_s ukeyInfo; + + Ps3LibExpEvtInfo_s expEvtInfo; + Ps3LibOemInfo_s oemEvtInfo; + Ps3LibBplaneEvtInfo_s bplaneEvtInfo; + Ps3LibEccEvtInfo_s eccEvtInfo; + Ps3LibTempEvtInfo_s tempEvtInfo; + Ps3LibDeviceResetEvtInfo_s deviceResetEvtInfo; + Ps3LibSenseDataEvtInfo_s senseDataEvtInfo; + Ps3LibErrSenseEvtInfo_s errSenseEvtInfo; + Ps3LibPdDownloadInfo_s pdDldEvtInfo; + Ps3LibSanitizeEvtInfo_s sanitizeInfo; + Ps3LibFormatEvtInfo_s formatInfo; + Ps3LibSnapshotEvtInfo_s snapShotInfo; + Ps3LibPdPreFailInfo_s pdPrefailInfo; + Ps3LibDiskPFCfgModifyEvtInfo_s diskPFCfgModifyEvtInfo; + Ps3LibNvDataInvaildInfo_s nvDataInvaildInfo; + Ps3LibCtrlPowerMode_s powerMode; + Ps3LibSpeedNegoInfo_s speedNegoInfo; + Ps3LibInitFailInfo_s initFailInfo; + Ps3LibTriModeInfo_s triModeInfo; + Ps3LibPhyChgInfo_s phyChgInfo; + Ps3LibPhyInquiryInfo_s phyInquiryInfo; + Ps3LibSmpFailInfo_s smpFailInfo; + Ps3LibNvmeEvtInfo_u nvmeInfo; + Ps3LibSasSataLinkSpeedMatchInfo_s sasSataLinkSpeedNoMatchInfo; + Ps3LibSasSataLNExceptionInfo_s sasSataLNExceptionInfo; + Ps3LibSasSataDriverInfo_s sasSataDriverInfo; + + + U64 value; + + + U8 data[PS3LIB_EVT_LOG_INFO_MAX_SIZE]; +}Ps3LibReportEvtData_u; +#pragma pack() + +typedef struct Ps3LibEvtLogEntry { + U32 seqNum; + Ps3LibEvtLogHeader_s head; + Ps3LibReportEvtData_u evtInfo; + CtrlId_t ctrlId; + CtrlId_t regCtrlId; + U32 registerId; + U32 pad; +} Ps3LibEvtLogEntry_s; + +typedef struct Ps3LibEvtLogList { + U32 count; + Ps3LibEvtLogEntry_s evtEntry[0]; +} Ps3LibEvtLogList_s; + +typedef struct Ps3LibEvtErrDataEntry { + U32 beforeSeqNum; + U32 errDataLen; + U8 *errData; +} Ps3LibEvtErrDataEntry_s; + +typedef struct Ps3LibEvtLog { + Ps3LibEvtPersistInfo_s evtPerInfo; + U32 evtCount; + U32 errCount; + Ps3LibEvtLogEntry_s * evtEntryList; + Ps3LibEvtErrDataEntry_s *errDataList; +} Ps3LibEvtLog_s; + +typedef struct Ps3LibEventDataCollectionKV { + char key[PS3LIB_EXP_EVENT_DATA_COLLECT_MAX_NUM]; + char val[PS3LIB_EXP_EVENT_DATA_COLLECT_MAX_NUM]; +} Ps3LibEventDataCollectionKV_s; + +typedef struct Ps3LibEventDataCollection { + struct Ps3LibEventDataCollectionKV kv[PS3LIB_EXP_EVENT_DATA_COLLECT_MAX_NUM]; +} Ps3LibEventDataCollection_s; + +enum { + PS3LIB_EXPANDER_EVENT_TYPE = 0, + PS3LIB_SWITCH_EVENT_TYPE = 1, + PS3LIB_RAID_HBA_EVENT_TYPE = 0xff, +}; + +typedef struct Ps3LibEvtPrintFunc{ + S8 const *(*evtCode2Str)(U32 opCode); + S8 const *(*evtLoca2Str)(U8 locate); + const S8 *(*getEvtDesc)(Ps3LibEvtLogEntry_s *event, S32 len, S8 *buff, S32 buffLen); + S32(*getEvtData) + (Ps3LibEventDataCollection_s *eventDataCollection, Ps3LibEvtLogEntry_s *event, S32 len, S8 *buff, S32 buffLen); +}Ps3LibEvtPrintFunc_t; + +Ps3LibEvtPrintFunc_t *ps3libEventPrintFunc(CtrlId_t ctrlId, U8 eventType); + +Ps3Errno ps3libCtrlEvtlogPerGet(CtrlId_t ctrlId, Ps3LibEvtPersistInfo_s *evtlogRdInfo); + +Ps3Errno ps3libEventLogGet(CtrlId_t ctrlId, U32 sinceSeqNum, Ps3LibEvtLog_s **ppEvtLog); + +void ps3libEventLogDestroy(Ps3LibEvtLog_s *pEvtLog); + +S32 ps3libEvtLevelCompare(U8 levelA, U8 levelB); + +Ps3Errno ps3libCtrlEventLogsDelete(CtrlId_t ctrlId); + +U32 ps3libEventUinqueIdToCtrlId(U32 uniqueId); + + + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/drivers/scsi/ps3stor/linux/ps3_base.c b/drivers/scsi/ps3stor/linux/ps3_base.c new file mode 100644 index 0000000000000000000000000000000000000000..6f63240186e84814045789a3ff013cb9113c2061 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_base.c @@ -0,0 +1,1957 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps3_htp_def.h" +#include "ps3_htp_event.h" +#include "ps3_htp_ioctl.h" +#include "ps3_cli.h" +#include "ps3_instance_manager.h" +#include "ps3_ioc_manager.h" +#include "ps3_ioc_state.h" +#include "ps3_scsih.h" +#include "ps3_driver_log.h" +#include "ps3_cmd_channel.h" +#include "ps3_mgr_cmd.h" +#include "ps3_event.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_device_manager.h" +#include "ps3_cmd_complete.h" +#include "ps3_device_update.h" +#include "ps3_debug.h" +#include "ps3_ioctl.h" +#include "ps3_driver_log.h" +#include "ps3_inner_data.h" +#include "ps3_cmd_statistics.h" +#include "ps3_trace_id_alloc.h" +#include "ps3_module_para.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_drv_ver.h" +#include "ps3_pcie_err_handle.h" +#include "ps3_err_inject.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_watchdog.h" +#if defined PS3_HARDWARE_ASIC +#include "ps3_pci.h" +#endif +#include "ps3_cli_debug.h" +#include "ps3_recovery.h" + +const char *const PS3_CHRDEV_NAME = "ps3stor-ioctl"; +#define PS3_PCI_DRIVER_NAME "ps3stor" +#define PS3_SCSI_HOST_NAME "ps3stor_scsi_host" +#define PS3_SCSI_DEFAULT_INIT_ID (-1) +#define PS3_SCSI_DEFAULT_CMD_PER_LUN (256) + +#define PS3_BIOS_PARAM_DEFAULT_HEADER (64) +#define PS3_BIOS_PARAM_DEFAULT_SECTORS (32) +#define PS3_BIOS_PARAM_MAX_HEADER (255) +#define PS3_BIOS_PARAM_MAX_SECTORS (63) +#define PS3_BIOS_PARAM_DEV_CAPCITY_THRESHOLD_1G (0x200000) + +#define IS_DMA64 (sizeof(dma_addr_t) == 8) +#define PS3_HOST_UUIID(_dev) (_dev->bus->number << 8 | _dev->devfn) +static const U8 DMA_MASK_BIT_44 = PCIE_DMA_HOST_ADDR_BIT_POS; +static const U8 DMA_MASK_BIT_52 = PCIE_DMA_HOST_ADDR_BIT_POS_VALID; +static const U8 DMA_MASK_BIT_32 = 32; +static const U32 PS3_REGISTER_BAR_INDEX = 0x02; + +static unsigned int ps3_mgmt_chrdev_major_no; + +#ifdef __KERNEL__ +#define PCI_DEVICE_SET(vend, dev, subven, subdev, cls, cls_mask) \ + .vendor = (vend), .device = (dev), \ + .subvendor = (subven), .subdevice = (subdev),\ + .class = (cls), .class_mask = (cls_mask) +#else +#define PCI_DEVICE_SET(vend, dev, subven, subdev, class, class_mask) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID +#endif + +static struct pci_device_id ps3_pci_table[] = { + {PCI_DEVICE(PCI_VENDOR_ID_PS3_FPGA, PCI_DEVICE_ID_PS3_RAID_FPGA)}, + {PCI_DEVICE(PCI_VENDOR_ID_PS3_FPGA, PCI_DEVICE_ID_PS3_HBA)}, + {PCI_DEVICE(PCI_VENDOR_ID_PS3_ASIC, PCI_DEVICE_ID_PS3_RAID_FPGA)}, + {PCI_DEVICE(PCI_VENDOR_ID_PS3_ASIC, PCI_DEVICE_ID_PS3_HBA)}, + {PCI_DEVICE(PCI_VENDOR_ID_STARS, PCI_DEVICE_ID_STARS_IOC_2020_18i)}, + {PCI_DEVICE(PCI_VENDOR_ID_STARS, PCI_DEVICE_ID_STARS_ROC_2020_10i)}, + {PCI_DEVICE(PCI_VENDOR_ID_PS3, PCI_DEVICE_ID_STARS_IOC_2020_18i)}, + {PCI_DEVICE(PCI_VENDOR_ID_PS3, PCI_DEVICE_ID_STARS_ROC_2020_10i)}, + {PCI_DEVICE(PCI_VENDOR_ID_PS3, PCI_DEVICE_ID_STARS_IOC_2213_16i)}, + {0, 0, 0, 0}}; + +MODULE_DEVICE_TABLE(pci, ps3_pci_table); + +static int ps3_mgmt_open(struct inode *pinode, struct file *filep) +{ + (void)pinode; + (void)filep; + if (!capable(CAP_SYS_ADMIN)) { + return -EACCES; + } + + return PS3_SUCCESS; +} + +static int ps3_bios_param(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int params[]) +{ + int heads = PS3_BIOS_PARAM_DEFAULT_HEADER; + int sectors = PS3_BIOS_PARAM_DEFAULT_SECTORS; + sector_t cylinders = capacity; + ULong dummy = heads * sectors; + (void)sdev; + (void)bdev; + + sector_div(cylinders, dummy); + + if ((ULong)capacity >= PS3_BIOS_PARAM_DEV_CAPCITY_THRESHOLD_1G) { + heads = PS3_BIOS_PARAM_MAX_HEADER; + sectors = PS3_BIOS_PARAM_MAX_SECTORS; + dummy = heads * sectors; + cylinders = capacity; + sector_div(cylinders, dummy); + } + + params[0] = heads; + params[1] = sectors; + params[2] = cylinders; + + return 0; +} + +#if defined(PS3_TAGSET_SUPPORT) +static MAP_QUEUES_RET_TYPE ps3_map_queues(struct Scsi_Host *shost) +{ + struct ps3_instance *instance = NULL; + S32 qoff = 0; + S32 offset = 0; + struct blk_mq_queue_map *map = NULL; + + instance = (struct ps3_instance *)shost->hostdata; + + if (shost->nr_hw_queues == 1) { + goto l_out; + } + + offset = instance->irq_context.high_iops_msix_vectors; + qoff = 0; + + map = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; + map->nr_queues = instance->irq_context.valid_msix_vector_count - offset; + map->queue_offset = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)) + (void)qoff; + MAP_QUEUES_RET_VAL(blk_mq_pci_map_queues(map, instance->pdev, offset)); +#else + blk_mq_pci_map_queues(map, instance->pdev, offset); + qoff += map->nr_queues; + + map = &shost->tag_set.map[HCTX_TYPE_POLL]; + map->nr_queues = 0; + if (map->nr_queues) { + map->queue_offset = qoff; + blk_mq_map_queues(map); + } +#endif +l_out: + MAP_QUEUES_RET_VAL(0); +} + +#endif + +static ssize_t page_size_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + if (buf == NULL) { + ret = 0; + goto l_out; + } + (void)cdev; + (void)attr; + + ret = snprintf(buf, PAGE_SIZE, "%ld\n", (ULong)PAGE_SIZE - 1); + +l_out: + return ret; +} + +static inline ssize_t vd_io_outstanding_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_vd_io_outstanding_show(cdev, attr, buf); +} + +static inline ssize_t io_outstanding_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_io_outstanding_show(cdev, attr, buf); +} + +static inline ssize_t is_load_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_is_load_show(cdev, attr, buf); +} + +static inline ssize_t dump_ioc_regs_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_dump_ioc_regs_show(cdev, attr, buf); +} + +static inline ssize_t max_scsi_cmds_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_max_scsi_cmds_show(cdev, attr, buf); +} + +static inline ssize_t event_subscribe_info_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_event_subscribe_info_show(cdev, attr, buf); +} + +static inline ssize_t ioc_state_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_ioc_state_show(cdev, attr, buf); +} + +static ssize_t log_level_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_log_level_store(cdev, attr, buf, count); +} + +static inline ssize_t log_level_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_log_level_show(cdev, attr, buf); +} + +static inline ssize_t io_trace_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_io_trace_switch_store(cdev, attr, buf, count); +} + +static inline ssize_t io_trace_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_io_trace_switch_show(cdev, attr, buf); +} + +static inline ssize_t dump_type_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_dump_type_show(cdev, attr, buf); +} + +static inline ssize_t dump_type_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_dump_type_store(cdev, attr, buf, count); +} + +static inline ssize_t dump_dir_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_dump_dir_show(cdev, attr, buf); +} + +static inline ssize_t dump_state_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_dump_state_show(cdev, attr, buf); +} + +static inline ssize_t dump_state_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_dump_state_store(cdev, attr, buf, count); +} + +static inline ssize_t soc_dead_reset_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_soc_dead_reset_store(cdev, attr, buf, count); +} +static inline ssize_t halt_support_cli_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_halt_support_cli_show(cdev, attr, buf); +} + +static inline ssize_t halt_support_cli_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_halt_support_cli_store(cdev, attr, buf, count); +} + +static inline ssize_t qos_switch_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_qos_switch_show(cdev, attr, buf); +} + +static ssize_t qos_switch_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_qos_switch_store(cdev, attr, buf, count); +} +static inline ssize_t product_model_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_product_model_show(cdev, attr, buf); +} + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else + +static inline ssize_t irq_prk_support_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + return ps3_irq_prk_support_show(cdev, attr, buf); +} + +static inline ssize_t irq_prk_support_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return ps3_irq_prk_support_store(cdev, attr, buf, count); +} +#endif + +static inline ssize_t cli_ver_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret= 0; + (void)cdev; + (void)attr; + if (buf != NULL) { + ret = snprintf(buf, PAGE_SIZE, "%d\n", PS3_IOCTL_VERSION); + } + + return ret; +} + +static DEVICE_ATTR_RO(page_size); +static DEVICE_ATTR_RO(vd_io_outstanding); +static DEVICE_ATTR_RO(io_outstanding); +static DEVICE_ATTR_RO(is_load); +static DEVICE_ATTR_RO(dump_ioc_regs); +static DEVICE_ATTR_RO(max_scsi_cmds); +static DEVICE_ATTR_RO(event_subscribe_info); +static DEVICE_ATTR_RO(ioc_state); +static DEVICE_ATTR_RW(log_level); +static DEVICE_ATTR_RW(io_trace); +static DEVICE_ATTR_RO(dump_dir); +static DEVICE_ATTR_RW(dump_type); +static DEVICE_ATTR_RW(dump_state); +static DEVICE_ATTR_WO(soc_dead_reset); +static DEVICE_ATTR_RW(halt_support_cli); +static DEVICE_ATTR_RW(qos_switch); +static DEVICE_ATTR_RO(product_model); +static DEVICE_ATTR_RO(cli_ver); + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else +static DEVICE_ATTR_RW(irq_prk_support); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)) +static struct attribute *ps3_host_attrs[] = { + &dev_attr_page_size.attr, + &dev_attr_vd_io_outstanding.attr, + &dev_attr_io_outstanding.attr, + &dev_attr_is_load.attr, + &dev_attr_dump_ioc_regs.attr, + &dev_attr_max_scsi_cmds.attr, + &dev_attr_event_subscribe_info.attr, + &dev_attr_ioc_state.attr, + &dev_attr_log_level.attr, + &dev_attr_io_trace.attr, + &dev_attr_dump_state.attr, + &dev_attr_dump_type.attr, + &dev_attr_dump_dir.attr, + &dev_attr_soc_dead_reset.attr, + &dev_attr_halt_support_cli.attr, + &dev_attr_qos_switch.attr, + &dev_attr_product_model.attr, + &dev_attr_cli_ver.attr, +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else + &dev_attr_irq_prk_support.attr, +#endif + NULL, +}; + +static const struct attribute_group ps3_host_attr_group = { + .attrs = ps3_host_attrs +}; + +const struct attribute_group *ps3_host_groups[] = { + &ps3_host_attr_group, + NULL +}; +#else +static struct device_attribute *ps3_host_attrs[] = { + &dev_attr_page_size, + &dev_attr_vd_io_outstanding, + &dev_attr_io_outstanding, + &dev_attr_is_load, + &dev_attr_dump_ioc_regs, + &dev_attr_max_scsi_cmds, + &dev_attr_event_subscribe_info, + &dev_attr_ioc_state, + &dev_attr_log_level, + &dev_attr_io_trace, + &dev_attr_dump_state, + &dev_attr_dump_type, + &dev_attr_dump_dir, + &dev_attr_soc_dead_reset, + &dev_attr_halt_support_cli, + &dev_attr_qos_switch, + &dev_attr_product_model, + &dev_attr_cli_ver, +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else + &dev_attr_irq_prk_support, +#endif + NULL, +}; +#endif +static struct scsi_host_template ps3_scsi_host_template = { + .module = THIS_MODULE, + .name = PS3_SCSI_HOST_NAME, + .proc_name = PS3_SCSI_HOST_PROC_NAME, + .queuecommand = ps3_scsih_queue_command, + .eh_abort_handler = ps3_err_scsi_task_mgr_abort, + .slave_alloc = ps3_scsi_slave_alloc, + .slave_configure = ps3_scsi_slave_configure, + .slave_destroy = ps3_scsi_slave_destroy, + .change_queue_depth = ps3_change_queue_depth, + .eh_device_reset_handler = ps3_device_reset_handler, + .eh_target_reset_handler = ps3_err_reset_target, + .eh_host_reset_handler = ps3_err_reset_host, + .eh_timed_out = ps3_err_reset_timer, + .bios_param = ps3_bios_param, +#if defined(PS3_TAGSET_SUPPORT) + .map_queues = ps3_map_queues, +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,19,0)) + .track_queue_depth = 1, +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)) + .shost_groups = ps3_host_groups, +#else + .shost_attrs = ps3_host_attrs, +#endif +}; + +static inline void ps3_set_product_model(struct ps3_instance * instance, const U16 id) +{ + if (PS3_DEVICE_IS_SWITCH(id)) { + instance->product_model = PS3_PSW_PRODUCT_MODEL; + } else { + instance->product_model = PS3_PRODUCT_MODEL; + } + return; +} + +static struct ps3_instance *ps3_instance_create(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct Scsi_Host *host = NULL; + struct ps3_instance *instance = NULL; + + if (pdev == NULL) { + LOG_ERROR("pci_dev is null!\n"); + return NULL; + } + + host = scsi_host_alloc(&ps3_scsi_host_template, + sizeof(struct ps3_instance)); + + if (!host) { + LOG_ERROR("pci_id[%u] scsi_host_alloc failed!\n", pdev->dev.id); + return NULL; + } + + host->unique_id = PS3_HOST_UUIID(pdev); + instance = (struct ps3_instance *)shost_priv(host); + memset(instance, 0, sizeof(*instance)); + + instance->pdev = pdev; + instance->host = host; + instance->peer_instance = NULL; + ps3_set_product_model(instance, id->device); + instance->dev_id = id->device; + instance->state_machine.can_hostreset = PS3_FALSE; + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_CLEAN; + mb(); + + if (ps3_instance_add(instance) != PS3_SUCCESS) { + scsi_remove_host(host); + scsi_host_put(host); + instance = NULL; + } + + LOG_INFO("hno:%u scsi_host_alloc [unique_id:%d]!\n", + PS3_HOST(instance), host->unique_id); + return instance; +} + +static inline void ps3_instance_put(struct ps3_instance *instance) +{ + if (ps3_instance_remove(instance) != PS3_SUCCESS) { + LOG_ERROR("ps3_instance remove NOK\n"); + } + return; +} + +S32 ps3_pci_init(struct pci_dev *pdev, struct ps3_instance *instance) +{ + resource_size_t base_addr = 0; + S32 ret = PS3_SUCCESS; + + ret = pci_enable_device_mem(pdev); + INJECT_START(PS3_ERR_IJ_FORCE_PCI_EN_MEM_FAILED, &ret) + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u pci id[%u] pci enable failed\n", + PS3_HOST(instance), pdev->dev.id); + goto l_pci_enable_device_mem_failed; + } + + pci_set_master(pdev); + + instance->reg_bar = PS3_REGISTER_BAR_INDEX; + ret = (pci_resource_flags(pdev, instance->reg_bar) & IORESOURCE_MEM); + INJECT_START(PS3_ERR_IJ_FORCE_PCI_RES_FLAGS_FAILED, &ret) + if (!ret) { + LOG_ERROR("hno:%u Bar %lu isnot IORESOURCE_MEM\n", + PS3_HOST(instance), instance->reg_bar); + goto l_bar_check_failed; + } + ret = pci_request_selected_regions(pdev, 1<reg_bar, + "PS3 pci regions"); + INJECT_START(PS3_ERR_IJ_FORCE_PCI_REQ_REGION_FAILED, &ret) + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u IO memory region busy\n", + PS3_HOST(instance)); + goto l_pci_request_selected_regions_failed; + } +#if ((defined(RHEL_MAJOR) && \ + ((RHEL_MAJOR == 8) || (RHEL_MAJOR == 9 && RHEL_MINOR < 4))) || \ + (!defined(RHEL_MAJOR) && LINUX_VERSION_CODE <= KERNEL_VERSION(6, 5, 13))) + pci_enable_pcie_error_reporting(pdev); +#endif + if (instance->ioc_adpter->reg_set) { + instance->reg_set = + (Ps3Fifo_s __iomem *)instance->ioc_adpter->reg_set(pdev, + instance->reg_bar); + } else { + instance->reg_set = + (Ps3Fifo_s __iomem *)ioremap( + pci_resource_start(pdev, instance->reg_bar), + PS3_REGISTER_SET_SIZE); + } + INJECT_START(PS3_ERR_IJ_FORCE_PCI_IOREMAP_FAILED, &instance->reg_set) + if (instance->reg_set == NULL) { + LOG_ERROR("hno:%u ioremap failed\n", PS3_HOST(instance)); + goto l_ioremap_failed; + } else { + pci_set_drvdata(pdev, instance); + } + + ps3_atomic_set(&instance->watchdog_reg_read_fail_count, 0); + LOG_INFO("reg_bar_idx = %lu, bar_base_paddr = 0x%llx, reg_set_vaddr = 0x%p\n", instance->reg_bar, + (U64)base_addr, instance->reg_set); + + return PS3_SUCCESS; +l_ioremap_failed: + pci_release_selected_regions(instance->pdev, 1<reg_bar); +#if ((defined(RHEL_MAJOR) && \ + ((RHEL_MAJOR == 8) || (RHEL_MAJOR == 9 && RHEL_MINOR < 4))) || \ + (!defined(RHEL_MAJOR) && LINUX_VERSION_CODE <= KERNEL_VERSION(6, 5, 13))) + pci_disable_pcie_error_reporting(pdev); +#endif +l_pci_request_selected_regions_failed: + pci_disable_device(instance->pdev); +l_bar_check_failed: +l_pci_enable_device_mem_failed: + return -PS3_FAILED; +} + +static void ps3_pci_exit(struct ps3_instance *instance) +{ + if (instance->reg_set != NULL) { + iounmap(instance->reg_set); + instance->reg_set = NULL; + } + + if (pci_is_enabled(instance->pdev)) { + pci_release_selected_regions(instance->pdev, 1<reg_bar); +#if ((defined(RHEL_MAJOR) && \ + ((RHEL_MAJOR == 8) || (RHEL_MAJOR == 9 && RHEL_MINOR < 4))) || \ + (!defined(RHEL_MAJOR) && LINUX_VERSION_CODE <= KERNEL_VERSION(6, 5, 13))) + pci_disable_pcie_error_reporting(instance->pdev); +#endif + pci_disable_device(instance->pdev); + } + + return; +} + +static S32 ps3_scsi_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct Scsi_Host *host = instance->host; + host->can_queue = instance->cmd_attr.cur_can_que; + host->this_id = PS3_SCSI_DEFAULT_INIT_ID; + host->sg_tablesize = instance->cmd_context.max_host_sge_count; + host->max_sectors = instance->ctrl_info.maxSectors; + host->cmd_per_lun = PS3_SCSI_DEFAULT_CMD_PER_LUN; + host->max_channel = instance->ctrl_info.channelInfo.channelNum - 1; + host->max_id = instance->dev_context.max_dev_per_channel; + host->max_lun = PS3_FRAME_LUN_BUFLEN; + host->max_cmd_len = PS3_FRAME_CDB_BUFLEN; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + host->use_clustering = instance->use_clusting; +#endif + + if (instance->ioc_adpter->sas_transport_get != NULL) { + host->transportt = instance->ioc_adpter->sas_transport_get(); + host->transportt->user_scan = ps3_sas_user_scan; + } + +#if defined(PS3_TAGSET_SUPPORT) + host->host_tagset = 0; + host->nr_hw_queues = 1; + + if ((instance->irq_context.valid_msix_vector_count > + instance->irq_context.high_iops_msix_vectors) && + ps3_tagset_enable_query() && + (instance->smp_affinity_enable)) { + host->host_tagset = 1; + host->nr_hw_queues = instance->irq_context.valid_msix_vector_count - + instance->irq_context.high_iops_msix_vectors; + } +#endif + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) + + ret = scsi_init_shared_tag_map(host, host->can_queue); + if (ret) { + LOG_ERROR("hno:%u Failed to shared tag from\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } +#endif + if (scsi_add_host(instance->host, &instance->pdev->dev)) { + LOG_ERROR("hno:%u Failed to add host\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + instance->is_host_added = PS3_TRUE; +l_out: + + return ret; +} + +static inline S32 __ps3_config_dma_mask32(struct ps3_instance *instance) +{ + if (dma_set_mask(&instance->pdev->dev, DMA_BIT_MASK(DMA_MASK_BIT_32)) || + dma_set_coherent_mask(&instance->pdev->dev, + DMA_BIT_MASK(DMA_MASK_BIT_32))) { + LOG_ERROR("hno:%u 32 dma mask set failed\n", + PS3_HOST(instance)); + return -PS3_FAILED; + } else { + instance->dma_mask = DMA_MASK_BIT_32; + LOG_INFO("hno:%u 32 dma mask set\n", + PS3_HOST(instance)); + } + + return PS3_SUCCESS; +} + +static inline U8 ps3_dma_mask_get(struct ps3_instance *instance) +{ + return ((instance->dma_addr_bit_pos > DMA_MASK_BIT_52) ? DMA_MASK_BIT_52 : DMA_MASK_BIT_44); +} + +static inline S32 __ps3_config_dma_mask(struct ps3_instance *instance) +{ + U8 dma_mask = 0; + dma_mask = ps3_dma_mask_get(instance); + if (dma_set_mask(&instance->pdev->dev, DMA_BIT_MASK(dma_mask)) || + dma_set_coherent_mask(&instance->pdev->dev, + DMA_BIT_MASK(dma_mask))) { + LOG_ERROR("hno:%u 62 dma mask set failed\n", + PS3_HOST(instance)); + return __ps3_config_dma_mask32(instance); + } else { + instance->dma_mask = dma_mask; + LOG_INFO("hno:%u dma mask set %u\n", + PS3_HOST(instance), instance->dma_mask); + } + return PS3_SUCCESS; +} + +static S32 ps3_config_dma_mask(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + Bool is_dma64_support = PS3_FALSE; + if (!ps3_ioc_mgr_is_dma64_support(instance, &is_dma64_support)) { + goto l_out; + } + if (is_dma64_support) { + if (IS_DMA64) { + ret = __ps3_config_dma_mask(instance); + } else { + LOG_ERROR("hno:%u unsupport 32bit system\n", + PS3_HOST(instance)); + } + } else { + LOG_ERROR("hno:%u soc unsupport 64bit dma\n", + PS3_HOST(instance)); + } +l_out: + return ret; +} + +static inline void ps3_device_busy_threshold_cfg(struct ps3_instance *instance) +{ + S32 device_busy = 0; + + device_busy = ps3_device_busy_threshold_query(); + if (device_busy <= 0 || + device_busy > instance->cmd_attr.cur_can_que) { + instance->device_busy_threshold = PS3_DEVICE_IO_BUSY_THRESHOLD; + } else { + instance->device_busy_threshold = device_busy; + } +} + +static void ps3_cmd_attr_context_init(struct ps3_instance *instance) +{ + U32 cmd_qdepth = ps3_throttle_qdepth_query(); + + instance->cmd_attr.cur_can_que = + instance->cmd_context.max_scsi_cmd_count - + instance->cmd_context.max_r1x_cmd_count; + + if ((cmd_qdepth != 0) && + cmd_qdepth <= (U32)instance->cmd_attr.cur_can_que) { + instance->cmd_attr.throttle_que_depth = cmd_qdepth; + } else { + instance->cmd_attr.throttle_que_depth = + PS3_DEVICE_QDEPTH_DEFAULT_VALUE; + } + + instance->cmd_attr.vd_io_threshold = 0; + instance->cmd_attr.is_support_direct_cmd = PS3_FALSE; + + ps3_device_busy_threshold_cfg(instance); +} + +static S32 ps3_init_ioc_prepare(struct ps3_instance *instance) +{ + ps3_ioc_mgr_req_queue_lock_init(instance); + instance->watchdog_context.is_stop = PS3_TRUE; + ps3_atomic_set(&instance->watchdog_ref, 0); + ps3_err_fault_context_init(instance); + + if (!ps3_ioc_fw_version_get(instance)) { + goto l_get_reg_failed; + } + + if (!ps3_feature_support_reg_get(instance)) { + goto l_get_reg_failed; + } + + if (ps3_ioc_init_cmd_context_init(instance) != PS3_SUCCESS) { + goto l_ioc_init_failed; + } + + if (ps3_ctrl_info_buf_alloc(instance) != PS3_SUCCESS) { + goto l_ctrl_info_init_failed; + } + + if (ps3_cmd_context_init(instance) != PS3_SUCCESS) { + goto l_cmd_context_init_failed; + } + + ps3_cmd_attr_context_init(instance); + + if (ps3_event_context_init(instance) != PS3_SUCCESS) { + goto l_event_context_init_failed; + } + + if (ps3_webSubscribe_context_init(instance) != PS3_SUCCESS) { + goto l_web_context_init_failed; + } + + if (ps3_cmd_statistics_init(instance) != PS3_SUCCESS) { + goto l_cmd_stat_failed; + } + + if (ps3_debug_mem_alloc(instance) != PS3_SUCCESS) { + goto l_debug_mem_failed; + } + + if (ps3_dump_init(instance) != PS3_SUCCESS) { + goto l_dump_init_failed; + } + + if (ps3_drv_info_buf_alloc(instance) != PS3_SUCCESS) { + goto l_drv_info_init_failed; + } + + if (ps3_host_mem_info_buf_alloc(instance) != PS3_SUCCESS) { + goto l_host_mem_init_failed; + } + return PS3_SUCCESS; + +l_host_mem_init_failed: + ps3_drv_info_buf_free(instance); +l_drv_info_init_failed: + ps3_dump_exit(instance); +l_dump_init_failed: + ps3_debug_mem_free(instance); +l_debug_mem_failed: + ps3_cmd_statistics_exit(instance); +l_cmd_stat_failed: + ps3_webSubscribe_context_exit(instance); +l_web_context_init_failed: + ps3_event_context_exit(instance); +l_event_context_init_failed: + ps3_cmd_context_exit(instance); +l_cmd_context_init_failed: + ps3_ctrl_info_buf_free(instance); +l_ctrl_info_init_failed: + ps3_ioc_init_cmd_context_exit(instance); +l_ioc_init_failed: + ps3_recovery_context_exit(instance); +l_get_reg_failed: + return -PS3_FAILED; +} + +static void ps3_init_ioc_prepare_exit(struct ps3_instance *instance) +{ + (void)ps3_debug_mem_free(instance); + ps3_cmd_statistics_exit(instance); + ps3_event_context_exit(instance); + ps3_webSubscribe_context_exit(instance); + ps3_ctrl_info_buf_free(instance); + ps3_ioc_init_cmd_context_exit(instance); + ps3_cmd_context_exit(instance); + ps3_recovery_context_exit(instance); + ps3_err_fault_context_exit(instance); + ps3_dump_dma_buf_free(instance); + ps3_dump_exit(instance); + ps3_drv_info_buf_free(instance); + ps3_host_mem_info_buf_free(instance); +} + +static S32 ps3_init_ioc_complete(struct ps3_instance *instance) +{ + if (ps3_mgr_cmd_init(instance) != PS3_SUCCESS) { + goto l_mgr_cmd_init_failed; + } + + if (ps3_device_mgr_init(instance) != PS3_SUCCESS) { + goto l_device_mgr_init_failed; + } + + if (ps3_sas_device_mgr_init(instance) != PS3_SUCCESS) { + goto l_sas_device_mgr_init_failed; + } + + if (ps3_qos_init(instance) != PS3_SUCCESS) { + goto l_qos_init_failed; + } + + return PS3_SUCCESS; +l_qos_init_failed: + ps3_sas_device_mgr_exit(instance); +l_sas_device_mgr_init_failed: + ps3_device_mgr_exit(instance); +l_device_mgr_init_failed: + ps3_mgr_cmd_exit(instance); +l_mgr_cmd_init_failed: + return -PS3_FAILED; +} + +static void ps3_init_ioc_complete_exit(struct ps3_instance *instance) +{ + ps3_sas_device_mgr_exit(instance); + ps3_device_mgr_exit(instance); + ps3_mgr_cmd_exit(instance); + + ps3_qos_exit(instance); + + return ; +} + +S32 ps3_pci_init_complete(struct ps3_instance *instance) +{ + if (ps3_config_dma_mask(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_irq_context_init(instance) != PS3_SUCCESS) { + goto l_failed; + } + if (instance->ioc_adpter->irq_init) { + if (instance->ioc_adpter->irq_init(instance) != PS3_SUCCESS) { + goto l_irqs_init_failed; + } + } else { + if (ps3_irqs_init(instance) != PS3_SUCCESS) { + goto l_irqs_init_failed; + } + } + + return PS3_SUCCESS; +l_irqs_init_failed: + ps3_irq_context_exit(instance); +l_failed: + return -PS3_FAILED; +} + +static S32 ps3_wait_reg_access_done(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 read_count = 0; + const U32 retry_max = 9000; + + ps3_wait_scsi_cmd_done(instance, PS3_TRUE); + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + while (ps3_atomic_read(&instance->reg_op_count) != 0){ + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + + if(read_count++ > retry_max){ + LOG_INFO("hno:%u wait reg op over:%d ms, failed\n", + PS3_HOST(instance), read_count*PS3_LOOP_TIME_INTERVAL_20MS); + ret = -PS3_FAILED; + goto l_out; + } + } + +l_out: + return ret; +} + +void ps3_pci_init_complete_exit(struct ps3_instance *instance) +{ + ps3_irqs_exit(instance); + + instance->is_pci_reset = PS3_TRUE; + mb(); + if (ps3_wait_reg_access_done(instance) != PS3_SUCCESS) { + LOG_ERROR("hno:%u wait reg access done NOK\n", PS3_HOST(instance)); + return; + } + + ps3_pci_exit(instance); + + if (!ps3_pci_err_recovery_get(instance) && + !instance->state_machine.is_suspend) { + pci_set_drvdata(instance->pdev, NULL); + } + + ps3_irq_context_exit(instance); +} + +static Bool ps3_bit_pos_set(struct ps3_instance *instance) +{ + U8 bit_pos = 0; + Bool ret = PS3_TRUE; + + if (!ps3_ioc_atu_support_retry_read(instance, &bit_pos)) { + ret = PS3_FALSE; + goto l_out; + } + if (bit_pos <= PS3_BIT_POS_44) { + instance->dma_addr_bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS; + goto l_out; + } + if (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_0) { + instance->dma_addr_bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS_F0; + } else { + instance->dma_addr_bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS_F1; + } +l_out: + mb(); + LOG_WARN("hno:%u set bit pos %u\n", + PS3_HOST(instance), instance->dma_addr_bit_pos); + return ret; +} + +static S32 ps3_firmware_init(struct pci_dev *pdev, struct ps3_instance *instance) +{ + S32 ret; + + if (ps3_recovery_context_init(instance) != PS3_SUCCESS) { + goto l_recovery_context_init_failed; + } + + if (ps3_pci_init(pdev, instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (!ps3_ioc_recovery_count_get(instance, + &instance->recovery_context->ioc_recovery_count)) { + goto l_failed; + } + + INJECT_START(PS3_ERR_IJ_SET_IOC_IN_SECURITY, instance) + if (instance->ioc_adpter->ioc_security_check && + instance->ioc_adpter->ioc_security_check(instance)) { + LOG_WARN("hno:%u:ioc is in security state\n", PS3_HOST(instance)); + goto l_failed; + } + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_B_READY, instance) + if (instance->ioc_adpter->ioc_init_state_to_ready(instance) != PS3_SUCCESS) { + goto l_failed; + } + atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_READY); + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_A_READY, instance); + if (!ps3_bit_pos_set(instance)) { + goto l_failed; + } + if (ps3_pci_init_complete(instance) != PS3_SUCCESS) { + goto l_failed; + } + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_NORMAL; + + pci_save_state(pdev); + ret = ps3_init_ioc_prepare(instance); + INJECT_START(PS3_ERR_IJ_FIRMWARE_INIT_FAIL, &ret) + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_B_INIT, instance) + if (instance->ioc_adpter->ioc_init_proc(instance) != PS3_SUCCESS) { + goto l_failed; + } + atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_PRE_OPERATIONAL); + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_CTRL_INFO, instance) + + if (ps3_ctrl_info_get(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_init_ioc_complete(instance) != PS3_SUCCESS) { + goto l_failed; + } + + return PS3_SUCCESS; + +l_failed: + ps3_recovery_context_exit(instance); +l_recovery_context_init_failed: + ps3_pci_init_complete_exit(instance); + ps3_init_ioc_prepare_exit(instance); + return -PS3_FAILED; +} + +static void ps3_firmware_exit(struct ps3_instance *instance) +{ + ps3_pci_init_complete_exit(instance); + ps3_init_ioc_complete_exit(instance); + ps3_init_ioc_prepare_exit(instance); + return; +} + +static void ps3_scsi_remove_host(struct ps3_instance *instance) +{ + if (ps3_sas_is_support_smp(instance)) { + sas_remove_host(instance->host); + scsi_remove_host(instance->host); + } else { + scsi_remove_host(instance->host); + } + return; +} + +static int ps3_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct ps3_instance *instance = NULL; + ULong flags = 0; + S32 ret; + +#ifdef PS3_SUPPORT_INJECT + U32 times = 180000; +#endif +#ifdef PS3_HARDWARE_ASIC + U16 real_dev_id = 0; + U32 check_count = ps3_hba_check_time_query() * 10 + 1; +#endif + LOG_INFO("device[%d] ps3_probe\n", pdev->dev.id); + + if (ps3_avaliable_func_id_query() >= PS3_FUNC_UNLIMITED) { + LOG2_WARN("PCI Device %04x:%02x:%02x:%x probe start.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + } else { + if ((U32)ps3_get_pci_function(pdev) != ps3_avaliable_func_id_query()) { + LOG2_WARN("Function %x not avaliable\n", ps3_get_pci_function(pdev)); + goto l_func_id_error; + } else { + LOG2_WARN("PCI Device %04x:%02x:%02x:%x probe start.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + } + } + + INJECT_INIT() + INJECT_PROBE_ACTIVE() + + instance = ps3_instance_create(pdev, id); + if (instance == NULL) { + goto l_ps3_instance_create_failed; + } + +#ifdef PS3_HARDWARE_ASIC + while(id->device == PCI_DEVICE_ID_PS3_RAID_FPGA && + check_count > 0) { + pci_read_config_word(pdev, PCI_DEVICE_ID, &real_dev_id); + LOG_INFO("get real device id is[0x%x] \n", real_dev_id); + if (real_dev_id == PCI_DEVICE_ID_PS3_HBA || + real_dev_id == PCI_DEVICE_ID_STARS_IOC_2020_18i || + real_dev_id == PCI_DEVICE_ID_STARS_ROC_2020_10i) { + ((struct pci_device_id *)id)->device = real_dev_id; + break; + } else { + check_count--; + ps3_msleep(100); + } + + }; +#endif + ps3_ioc_adp_init(instance, id); + instance->ioc_adpter->ioc_resource_prepare(instance); + ps3_debug_context_init(instance); + + device_disable_async_suspend(&pdev->dev); + + ret = ps3_firmware_init(pdev, instance); + if (ret != PS3_SUCCESS) { + LOG_WARN("ps3_firmware_init fail:%d\n", ret); + goto l_firmware_init_failed; + } + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_OPERATIONAL); + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_OPER, instance) + + instance->ioc_adpter->irq_enable(instance); + ps3_dump_ctrl_set_int_ready(instance); + + ps3_ioctl_init(instance, PS3_MAX_IOCTL_CMDS); + ps3_scsi_cmd_timeout_adjust(); + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_SCSI_INIT, instance) + + ret = ps3_scsi_init(instance); + if (ret != PS3_SUCCESS) { + goto l_scsi_init_failed; + } + instance->state_machine.is_load = PS3_TRUE; + mb(); + INJECT_START(PS3_ERR_IJ_FORCE_F1_LOAD_START_HARD, instance); + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_LOAD, instance) + ret = ps3_watchdog_start(instance); + if (ret != PS3_SUCCESS) { + goto l_watch_dog_start_failed; + } + INJECT_START(PS3_ERR_IJ_F1_PROBE_FORCE_IOC_FAULT, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_HOST_START_HARD, instance) + + ret = ps3_device_mgr_data_init(instance); + if (ret != PS3_SUCCESS) { + goto l_dev_info_get_failed; + } + ret = ps3_sas_device_data_init(instance); + if (ret != PS3_SUCCESS) { + goto l_expander_get_failed; + } + INJECT_START(PS3_ERR_IJ_FORCE_F1_SCAN_START_HARD, instance) + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_B_SCAN, instance) + instance->state_machine.can_hostreset = PS3_TRUE; + INJECT_START(PS3_ERR_IJ_FORCE_F0_WATCHDOG_START_HARD, instance) + + ps3_scsi_scan_host(instance); + + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_A_SCAN, instance) + INJECT_START(PS3_ERR_IJ_SCSI_SCAN_HOST_DELAY, ×) + INJECT_START(PS3_ERR_IJ_FORCE_F1_A_SCAN_START_HARD, instance) + + INJECT_START(PS3_ERR_IJ_PROBE_HOST_RESET, instance); + instance->is_scan_host_finish = PS3_TRUE; + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_SCAN_FINISH, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_A_SCAN_FINISH_HARD, instance) + + ret = ps3_event_subscribe(instance); + if (ret == -PS3_FAILED) { + goto l_event_subscribe_failed; + } else if (ret == -PS3_RECOVERED) { + LOG_INFO("device[%d] skip event/vd info subscribe due to recovery during probe\n", + pdev->dev.id); + goto l_event_subscribe_recovered; + } + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_EVENT, instance) + + ret = ps3_dev_mgr_vd_info_subscribe(instance); + if (ret != PS3_SUCCESS && ret != -PS3_RECOVERED) { + LOG_INFO("device[%d] vd info subscribe failed, ret: %d\n", + pdev->dev.id, ret); + goto l_vd_info_subscribe_failed; + } +l_event_subscribe_recovered: + INJECT_START(PS3_ERR_IJ_WAIT_HARDRESET, instance) + instance->is_probe_finish = PS3_TRUE; + mb(); +#if 0 + if (ps3_watchdog_start(instance) != PS3_SUCCESS) { + goto l_watch_dog_start_failed; + } +#endif + LOG2_WARN("PCI Device %04x:%02x:%02x:%x probe end.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + + ps3_ioc_can_hardreset_set(instance, PS3_IOC_CAN_HARDRESET); + return PS3_SUCCESS; + +l_vd_info_subscribe_failed: +l_event_subscribe_failed: + ps3_dev_mgr_vd_info_unsubscribe(instance); + ps3_event_unsubscribe(instance); + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + instance->event_context.abort_eventcmd = 0; + instance->dev_context.abort_vdpending_cmd = 0; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + ps3_sas_device_data_exit(instance); +l_expander_get_failed: +l_scsi_init_failed: + instance->state_machine.is_load = PS3_FALSE; + mb(); + ps3_device_mgr_data_exit(instance); +l_dev_info_get_failed: + ps3_watchdog_stop(instance); +l_watch_dog_start_failed: + ps3_scsi_remove_host(instance); + instance->state_machine.can_hostreset = PS3_FALSE; + mb(); + ps3_dump_work_stop(instance); + ps3_recovery_context_exit(instance); + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + + ps3_irqpolls_enable(instance); + ps3_firmware_exit(instance); +l_firmware_init_failed: + instance->is_probe_failed = PS3_TRUE; + mb(); + ps3_instance_put(instance); + scsi_host_put(instance->host); +l_ps3_instance_create_failed: + ps3_dma_dump_mapping(pdev); + l_func_id_error: + printk(KERN_WARNING "PCI Device %04x:%02x:%02x:%x probe failed.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + return -ENODEV; +} + +static S32 ps3_cancel_event_wk_in_unload(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 cur_state = 0; + U32 ioc_state = 0; + + cur_state = ps3_atomic_read(&instance->state_machine.state); + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_IOC_NOT_RUNNING, &ioc_state) + if((ioc_state != PS3_FW_STATE_RUNNING) || + (cur_state != PS3_INSTANCE_STATE_OPERATIONAL)){ + LOG_WARN("hno:%u goto half hard reset, cur_state:%s,IOC state is %s!\n", + PS3_HOST(instance), + namePS3InstanceState(cur_state),ps3_ioc_state_print(ioc_state)); + ret = -PS3_FAILED; + goto l_out; + } + cancel_delayed_work_sync(&instance->event_context.delay_work->event_work); + +l_out: + return ret; +} + +static void ps3_shutdown(struct pci_dev *pdev) +{ + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + if (instance == NULL) { + LOG_ERROR("device[%d] ps3_shutdown fail\n", pdev->dev.id); + return; + } + LOG2_WARN("PCI Device %04x:%02x:%02x:%x shutdown start.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + + instance->state_machine.is_load = PS3_FALSE; + mb(); + INJECT_START(PS3_ERR_IJ_SHUTDOWN_HARDRESET, instance) + ps3_recovery_cancel_work_sync(instance); + if (instance ->is_half_hard_reset) { + goto l_reset_to_ready; + } + + ps3_r1x_conflict_queue_clean_all(instance, + PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT), PS3_TRUE); + + ps3_qos_waitq_clear_all(instance, PS3_STATUS_HOST_NOT_FOUND); +#ifdef PS3_SUPPORT_INJECT + ps3_inject_clear(); +#endif + + if (ps3_cancel_event_wk_in_unload(instance) != PS3_SUCCESS) { + goto l_reset_to_ready; + } + + if (ps3_event_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] event unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + + if (ps3_dev_mgr_vd_info_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] vd unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + if (ps3_web_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] web unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + } + + instance->is_host_added = PS3_FALSE; + ps3_watchdog_stop(instance); + + ps3_dump_exit(instance); + + INJECT_START(PS3_ERR_IJ_HALF_HARD_RESET, &instance ->is_half_hard_reset) + if (instance ->is_half_hard_reset) { + goto l_release_res; + } + + if (ps3_soc_unload(instance, PS3_FALSE, PS3_UNLOAD_SUB_TYPE_SHUTDOWN, PS3_SUSPEND_TYPE_NONE) != PS3_SUCCESS) { + LOG_ERROR("device[%d] unload failed.\n", pdev->dev.id); + goto l_reset_to_ready; + } + + goto l_release_res; +l_reset_to_ready: + if (instance->is_host_added) { + ps3_watchdog_stop(instance); + ps3_dump_exit(instance); + if (instance ->is_half_hard_reset) { + goto l_release_res; + } + } + + if (ps3_hard_reset_to_ready_with_doorbell(instance) != + PS3_SUCCESS) { + LOG_ERROR("device[%d] hard reset NOK.\n", + PS3_HOST(instance)); + } +l_release_res: + while(atomic_read(&instance->cmd_statistics.io_outstanding) != 0) { + ps3_msleep(3000); + } + instance->state_machine.can_hostreset = PS3_FALSE; + ps3_check_and_wait_host_reset(instance); + if (!instance ->is_half_hard_reset) { + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + } + ps3_recovery_destory(instance); + + ps3_instance_state_transfer_to_quit(instance); + ps3_recovery_clean(instance); + + ps3_ioctl_clean(instance); + + ps3_firmware_exit(instance); + ps3_instance_put(instance); + LOG2_WARN("PCI Device %04x:%02x:%02x:%x shutdown end.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + return; +} + +void ps3_remove(struct pci_dev *pdev) +{ + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + if (instance == NULL) { + LOG_ERROR("device[%d] ps3_remove fail\n", pdev->dev.id); + return; + } + instance->state_machine.is_load = PS3_FALSE; + LOG2_WARN("PCI Device %04x:%02x:%02x:%x remove start\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + mb(); + ps3_recovery_cancel_work_sync(instance); + if (instance->pci_err_handle_state == PS3_DEVICE_ERR_STATE_CLEAN) { + ps3_dump_exit(instance); + while(ps3_atomic_read(&instance->is_err_scsi_processing) > 0) { + ps3_msleep(10); + } + + ps3_all_reply_fifo_complete(instance); + + ps3_cmd_force_stop(instance); + cancel_delayed_work_sync(&instance->event_context.delay_work->event_work); + + goto l_release_res; + } + if (instance ->is_half_hard_reset) { + goto l_reset_to_ready; + } + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_NOT_RUNNING, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_CANCEL_EVENT_WORK_FAIL_RESUME, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_CANCEL_EVENT_WORK_FAIL_RESUME, instance) + if (ps3_cancel_event_wk_in_unload(instance) != PS3_SUCCESS) { + goto l_reset_to_ready; + } + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_EVENT_FAIL, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_EVENT_FAIL_RESUME, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_EVENT_FAIL_RESUME, instance) + if (ps3_event_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] event unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_VDINFO_FAIL, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_VDINFO_FAIL_RESUME, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_VDINFO_FAIL_RESUME, instance) + if (ps3_dev_mgr_vd_info_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] vd unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_WEB_FAIL, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_WEB_FAIL_RESUME, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_WEB_FAIL_RESUME, instance) + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + if (ps3_web_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] web unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + } + + ps3_r1x_conflict_queue_clean_all(instance, + PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT), PS3_TRUE); + + ps3_qos_waitq_clear_all(instance, PS3_STATUS_HOST_NOT_FOUND); +#ifdef PS3_SUPPORT_INJECT + ps3_inject_clear(); +#endif + + ps3_scsi_remove_host(instance); + + instance->is_host_added = PS3_FALSE; + + ps3_watchdog_stop(instance); + ps3_dump_exit(instance); + + INJECT_START(PS3_ERR_IJ_HALF_HARD_RESET, &instance ->is_half_hard_reset) + if (instance ->is_half_hard_reset) { + goto l_release_res; + } + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_UNLOAD_FAIL, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_UNLOAD_FAIL_RESUME, instance) + INJECT_START(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_UNLOAD_FAIL_RESUME, instance) + if (ps3_soc_unload(instance, PS3_FALSE, PS3_UNLOAD_SUB_TYPE_REMOVE, PS3_SUSPEND_TYPE_NONE) != PS3_SUCCESS) { + LOG_ERROR("device[%d] unload failed.\n", pdev->dev.id); + goto l_reset_to_ready; + } + + goto l_release_res; +l_reset_to_ready: + if (instance->is_host_added) { + ps3_watchdog_stop(instance); + ps3_dump_exit(instance); + if (instance ->is_half_hard_reset) { + goto l_release_res; + } + } + if (ps3_hard_reset_to_ready_with_doorbell(instance) != + PS3_SUCCESS) { + LOG_ERROR("device[%d] hard reset NOK.\n", + PS3_HOST(instance)); + } + +l_release_res: + while(atomic_read(&instance->cmd_statistics.io_outstanding) != 0) { + ps3_msleep(3000); + } + instance->state_machine.can_hostreset = PS3_FALSE; + ps3_check_and_wait_host_reset(instance); + + ps3_instance_state_transfer_to_quit(instance); + ps3_recovery_destory(instance); + + if (instance->is_host_added) { + ps3_scsi_remove_host(instance); + } + + while(ps3_atomic_read(&instance->host_reset_processing) > 0) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + ps3_recovery_clean(instance); + if (!instance ->is_half_hard_reset) { + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + } + ps3_ioctl_clean(instance); + + ps3_firmware_exit(instance); + + ps3_instance_put(instance); + scsi_host_put(instance->host); + ps3_dma_dump_mapping(pdev); + LOG2_WARN("PCI Device %04x:%02x:%02x:%x remove end\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + return; +} + +#ifdef CONFIG_PM +static int ps3_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + U8 suspend_type = PS3_SUSPEND_TYPE_SLEEP; + + (void) state; + INJECT_START(PS3_ERR_IJ_WAIT_PM_INSTANCE_NULL, &instance); + if (instance == NULL) { + LOG2_ERROR("device[%d] ps3_suspend NOK\n", pdev->dev.id); + return PS3_SUCCESS; + } + + LOG2_WARN("PCI Device %04x:%02x:%02x:%x ps3_suspend start.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + instance->is_suspend = PS3_TRUE; + mb(); + instance->state_machine.is_suspend = PS3_TRUE; + mb(); + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_WAIT_RECOVERY_1, instance) + ps3_recovery_cancel_work_sync(instance); + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET, instance) + if (instance ->is_half_hard_reset) { + goto l_reset_to_ready; + } + + ps3_r1x_conflict_queue_clean_all(instance, + PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT), PS3_TRUE); + + ps3_qos_waitq_clear_all(instance, PS3_STATUS_HOST_NOT_FOUND); +#ifdef PS3_SUPPORT_INJECT + ps3_inject_clear(); +#endif + + if (ps3_cancel_event_wk_in_unload(instance) != PS3_SUCCESS) { + goto l_reset_to_ready; + } + + if (ps3_event_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] event unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + + if (ps3_dev_mgr_vd_info_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] vd unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED, instance) + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + if (ps3_web_unsubscribe(instance) != PS3_SUCCESS) { + LOG_ERROR("device[%d] web unsubscribe NOK.\n", pdev->dev.id); + goto l_reset_to_ready; + } + } + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + + ps3_irqpolls_enable(instance); + + ps3_dump_work_stop(instance); + ps3_watchdog_stop(instance); + ps3_recovery_cancel_work_sync(instance); + + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET_2, instance) + if (instance ->is_half_hard_reset) { + goto l_release_res; + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0)) + flush_scheduled_work(); +#endif + scsi_block_requests(instance->host); + + if (state.event == PM_EVENT_FREEZE) { + suspend_type = PS3_SUSPEND_TYPE_HIBERNATE; + } + LOG_INFO("event[%d] suspend_type[%d].\n", state.event, suspend_type); + if (ps3_soc_unload(instance, PS3_FALSE, PS3_UNLOAD_SUB_TYPE_SUSPEND, suspend_type) != PS3_SUCCESS) { + LOG_ERROR("device[%d] unload NOK.\n", pdev->dev.id); + if (ps3_hard_reset_to_ready_with_doorbell(instance) != + PS3_SUCCESS) { + LOG_ERROR("device[%d] hard reset NOK.\n", + PS3_HOST(instance)); + } + } + + goto l_release_res; +l_reset_to_ready: + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET_1, instance) + if (!instance ->is_half_hard_reset) { + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + + ps3_irqpolls_enable(instance); + } + ps3_dump_work_stop(instance); + ps3_watchdog_stop(instance); + ps3_recovery_cancel_work_sync(instance); + if (instance ->is_half_hard_reset) { + goto l_release_res; + } + + if (ps3_hard_reset_to_ready_with_doorbell(instance) != + PS3_SUCCESS) { + LOG_ERROR("device[%d] hard reset NOK.\n", + PS3_HOST(instance)); + } + + if (instance->event_context.event_cmd != NULL) { + cmd = instance->event_context.event_cmd; + instance->event_context.event_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + abort_cmd = instance->event_context.event_abort_cmd; + if (abort_cmd != NULL) { + instance->event_context.event_abort_cmd = NULL; + ps3_task_cmd_free(instance, abort_cmd); + } + instance->event_context.subwork = 0; + } + + ps3_dev_mgr_vd_info_clear(instance); + + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ps3_web_cmd_clear(instance); + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6,6,0)) + flush_scheduled_work(); +#endif + scsi_block_requests(instance->host); +l_release_res: + pci_set_drvdata(instance->pdev, instance); + pci_save_state(pdev); + instance ->is_half_hard_reset = PS3_FALSE; + ps3_base_free_resources(instance); + ps3_instance_put(instance); + + LOG2_WARN("PCI Device %04x:%02x:%02x:%x ps3_suspend end.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + instance->is_suspend = PS3_FALSE; + return PS3_SUCCESS; +} + +static int ps3_resume(struct pci_dev *pdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + + INJECT_START(PS3_ERR_IJ_WAIT_PM_INSTANCE_NULL, &instance); + if (instance == NULL) { + LOG2_ERROR("device[%d] ps3_resume NOK\n", pdev->dev.id); + return PS3_SUCCESS; + } + + LOG2_WARN("PCI Device %04x:%02x:%02x:%x ps3_resume start.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + instance->is_resume = PS3_TRUE; + mb(); + ps3_recovery_cancel_work_sync(instance); + pci_restore_state(pdev); + + instance->pdev = pdev; + if (ps3_instance_add(instance) != PS3_SUCCESS) { + goto l_out; + } + INJECT_START(PS3_ERR_IJ_WAIT_RESUME_FUNCID_INVALID, instance); + if (ps3_avaliable_func_id_query() < PS3_FUNC_UNLIMITED && + (U32)ps3_get_pci_function(pdev) != ps3_avaliable_func_id_query()) { + LOG2_WARN("Function %d not avaliable\n", ps3_get_pci_function(pdev)); + goto l_out; + } + + ret = ps3_base_init_resources(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u base init resources NOK, ret: %d\n", PS3_HOST(instance), ret); + goto l_out; + } + + if (instance->ioc_adpter->ioc_init_state_to_ready(instance) != PS3_SUCCESS) { + goto l_out; + } + + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_READY); + + ps3_all_reply_fifo_init(instance); + + if (instance->ioc_adpter->ioc_init_proc(instance) != PS3_SUCCESS) { + goto l_out; + } + + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_PRE_OPERATIONAL); + + instance->ioc_adpter->irq_enable(instance); + + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_OPERATIONAL); + + instance->state_machine.is_load = PS3_TRUE; + scsi_unblock_requests(instance->host); + + ps3_dump_ctrl_set_int_ready(instance); + INJECT_START(PS3_ERR_IJ_WAIT_RESUME_WAIT_RECOVERY, instance); + + ret = ps3_watchdog_start(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + instance->event_req_info.eventTypeMapProcResult = instance->event_req_info.eventTypeMap; + ret = ps3_event_subscribe(instance); + if (ret == -PS3_FAILED) { + goto l_out; + } else if (ret == -PS3_RECOVERED) { + LOG_INFO("device[%d] skip event/vd info subscribe due to recovery during probe\n", + pdev->dev.id); + goto l_event_subscribe_recovered; + } + + ret = ps3_dev_mgr_vd_info_subscribe(instance); + if (ret != PS3_SUCCESS && ret != -PS3_RECOVERED) { + LOG_INFO("device[%d] vd info subscribe NOK, ret: %d\n", + pdev->dev.id, ret); + goto l_out; + } + + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ret = ps3_web_subscribe(instance); + if (ret != PS3_SUCCESS && ret != -PS3_IN_UNLOAD) { + goto l_out; + } + } + +l_event_subscribe_recovered: + instance->state_machine.is_suspend = PS3_FALSE; + instance->is_probe_finish = PS3_TRUE; + instance->is_resume = PS3_FALSE; + LOG2_WARN("PCI Device %04x:%02x:%02x:%x ps3_resume end.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + + ps3_ioc_can_hardreset_set(instance, PS3_IOC_CAN_HARDRESET); + return PS3_SUCCESS; +l_out: + instance->state_machine.is_suspend = PS3_FALSE; + instance->is_resume = PS3_FALSE; + instance->state_machine.is_load = PS3_TRUE; + ps3_instance_state_transfer_to_dead(instance); + scsi_unblock_requests(instance->host); + ps3_dma_dump_mapping(pdev); + LOG2_WARN("PCI Device %04x:%02x:%02x:%x ps3_resume NOK.\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + return -ENODEV; +} +#endif + +static ssize_t version_show(struct device_driver *dd, char *buf) +{ + (void)dd; + return snprintf(buf, strlen(PS3_DRV_VERSION) + 2, "%s\n", PS3_DRV_VERSION); +} +static DRIVER_ATTR_RO(version); + +static ssize_t release_date_show(struct device_driver *dd, char *buf) +{ + (void)dd; + return snprintf(buf, strlen(PS3_DRV_BUILD_TIME) + 2, "%s\n", + PS3_DRV_BUILD_TIME); +} +static DRIVER_ATTR_RO(release_date); + +static const struct file_operations ps3_mgmt_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = ps3_ioctl_fops, + .open = ps3_mgmt_open, + .release = NULL, + .llseek = noop_llseek, + .read = NULL, + .write = NULL, + .fasync = ps3_fasync +}; + +static struct pci_driver ps3_pci_driver; +static void init_pci_driver(struct pci_driver *drv) +{ + drv->name = PS3_PCI_DRIVER_NAME; + drv->id_table = ps3_pci_table; + drv->probe = ps3_probe; + drv->remove = ps3_remove; +#ifdef CONFIG_PM + drv->suspend = ps3_suspend; + drv->resume = ps3_resume; +#endif + drv->shutdown = ps3_shutdown; + if (ps3_aer_handle_support_query()) { + ps3_pci_err_handler_init(drv); + } else { + LOG_INFO("aer handle not supported\n"); + } + + return; +} + +static int __init ps3stor_init(void) +{ + int ret = PS3_SUCCESS; + printk(KERN_WARNING "ps3stor driver init start, version[%s], commit_id[%s], " + "build_time[%s], toolchain_id[%s]\n", + PS3_DRV_VERSION, PS3_DRV_COMMIT_ID, + PS3_DRV_BUILD_TIME, PS3_DRV_TOOLCHAIN_ID); + + ret = ps3_debug_init(); + INJECT_START(PS3_ERR_IJ_FORCE_DEBUG_INIT_FAIL, &ret); + if (ret < 0) { + printk(KERN_ERR "ps3stor log init fail\n"); + goto l_debug_init_failed; + } + ps3_host_info_get(); + ps3cmd_init(); + ps3_mgmt_info_init(); + + LOG_FILE_WARN("ps3stor driver version[%s], commit_id[%s]," + "build_time[%s], toolchain_id[%s]\n", + PS3_DRV_VERSION, PS3_DRV_COMMIT_ID, + PS3_DRV_BUILD_TIME, PS3_DRV_TOOLCHAIN_ID); + + ret = ps3_sas_attach_transport(); + INJECT_START(PS3_ERR_IJ_FORCE_TRANSPORT_INIT_FAIL, &ret); + if (ret != PS3_SUCCESS) { + printk(KERN_ERR "ps3stor transport fail\n"); + ret = -ENODEV; + goto l_sas_transport_failed; + } + + ret = register_chrdev(0, PS3_CHRDEV_NAME, &ps3_mgmt_fops); + INJECT_START(PS3_ERR_IJ_FORCE_CHARDEV_INIT_FAIL, &ret); + if (ret < 0) { + LOG_ERROR("ps3stor: failed to open device node\n"); + goto l_register_chrdev_failed; + } + ps3_mgmt_chrdev_major_no = ret; + + init_pci_driver(&ps3_pci_driver); + ret = pci_register_driver(&ps3_pci_driver); + INJECT_START(PS3_ERR_IJ_FORCE_PCIDRV_INIT_FAIL, &ret); + if (ret) { + LOG_ERROR("ps3stor: PCI hotplug registration failed \n"); + goto l_pci_register_driver_failed; + } + + ret = driver_create_file(&ps3_pci_driver.driver, &driver_attr_version); + INJECT_START(PS3_ERR_IJ_FORCE_VERFILE_INIT_FAIL, &ret); + if (ret) { + goto l_attr_ver_failed; + } + ret = driver_create_file(&ps3_pci_driver.driver, + &driver_attr_release_date); + INJECT_START(PS3_ERR_IJ_FORCE_VERFILE2_INIT_FAIL, &ret); + if (ret) { + goto l_attr_release_date_failed; + } + + ps3_trace_id_init(); + ps3_version_verbose_fill(); + + return ret; + +l_attr_release_date_failed: + driver_remove_file(&ps3_pci_driver.driver, &driver_attr_version); +l_attr_ver_failed: + pci_unregister_driver(&ps3_pci_driver); +l_pci_register_driver_failed: + unregister_chrdev(ps3_mgmt_chrdev_major_no, PS3_CHRDEV_NAME); +l_register_chrdev_failed: + ps3_sas_release_transport(); +l_sas_transport_failed: + ps3_debug_exit(); + ps3cmd_exit(); + ps3_mgmt_exit(); +l_debug_init_failed: + return ret; +} + +static void __exit ps3stor_exit(void) +{ + driver_remove_file(&ps3_pci_driver.driver, &driver_attr_version); + driver_remove_file(&ps3_pci_driver.driver, &driver_attr_release_date); + + pci_unregister_driver(&ps3_pci_driver); + unregister_chrdev(ps3_mgmt_chrdev_major_no, PS3_CHRDEV_NAME); + + ps3_sas_release_transport(); + ps3_debug_exit(); + ps3cmd_exit(); + ps3_mgmt_exit(); + return; +} + +MODULE_INFO(private_version, PS3_PRIVATE_VERSION); +MODULE_INFO(product_support, PS3_DRV_PRODUCT_SUPPORT); +MODULE_INFO(build_time, PS3_DRV_BUILD_TIME); +MODULE_INFO(toolchain_id, PS3_DRV_TOOLCHAIN_ID); +MODULE_INFO(commit_id, PS3_DRV_COMMIT_ID); +MODULE_VERSION(PS3_DRV_VERSION); +MODULE_AUTHOR(PS3_DRV_AUTHOR); +MODULE_DESCRIPTION(PS3_DRV_DESCRIPTION); +MODULE_LICENSE(PS3_DRV_LICENSE); + +module_init(ps3stor_init); +module_exit(ps3stor_exit); diff --git a/drivers/scsi/ps3stor/linux/ps3_cli.c b/drivers/scsi/ps3stor/linux/ps3_cli.c new file mode 100644 index 0000000000000000000000000000000000000000..2981094df52cbfa9d7520a0d00f3f10c73565b44 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_cli.c @@ -0,0 +1,322 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ps3_cli.h" +#include "ps3_instance_manager.h" + +#define PS3_CLI_STATIC_MINOR 26 +#define PS3_CLI_DYNAMIC_MINOR MISC_DYNAMIC_MINOR +#define PS3_CLI_HASH_LEN 256 + +struct ps3_cli_cmd_s { + struct ps3_cli_cmd_s *next; + char cmd[PS3_CLI_CMD_MAXLEN]; + char help[PS3_CLI_HELP_LEN]; + ps3_cli_func_t func; +}; + +static int misc_registered; +static int dev_opened; +static int cmd_ready; +static char ps3_cli_input[PS3_CLI_INPUT_LEN]; +static char ps3_cli_output[PS3_CLI_OUTLINE_LEN]; +static char __user *read_buf; +static int read_buf_len; +static int read_buf_ptr; + +static struct ps3_cli_cmd_s *ps3_cli_cmd_head[PS3_CLI_HASH_LEN]; +static struct mutex ps3_cli_mutex; + +#if 0 +#define __pl() printk("func = %s, line = %d\n", __FUNCTION__, __LINE__) +#else +#define __pl() +#endif + +static ssize_t ps3_cli_write(struct file *fp, const char __user *buffer, + size_t nbytes, loff_t *ppos) +{ + __pl(); + (void)fp; + (void)ppos; + if (nbytes>PS3_CLI_INPUT_LEN-1) + return -EINVAL; + + if (copy_from_user(ps3_cli_input, buffer, nbytes)) + return -EFAULT; + ps3_cli_input[nbytes] = '\0'; + cmd_ready = 1; + __pl(); + return (ssize_t)nbytes; +} + +static u32 str_hash(const char *name) +{ + u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; + const signed char *scp = (const signed char*)name; + + while (*scp) { + hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); + + if (hash & 0x80000000) + hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } + return hash0 << 1; +} + +static struct ps3_cli_cmd_s *ps3_cli_find_cmd(const char *cmd) +{ + u32 idx = str_hash(cmd) & (PS3_CLI_HASH_LEN-1); + struct ps3_cli_cmd_s *p; + + for (p=ps3_cli_cmd_head[idx]; p; p=p->next) + if (!strcmp(p->cmd, cmd)) + return p; + return NULL; +} + +int ps3stor_cli_printf(const char *fmt, ...) +{ + va_list args; + int len, n, ret; + + __pl(); + + va_start(args, fmt); + len = vsnprintf(ps3_cli_output, PS3_CLI_OUTLINE_LEN, fmt, args); + va_end(args); + + if (read_buf_ptr>=read_buf_len) { + return read_buf_ptr; + } + + n = read_buf_len-read_buf_ptr; + if (n>len) + n = len; + + ret = copy_to_user(read_buf+read_buf_ptr, ps3_cli_output, n); + if (ret<0) { + pr_err("copy_to_user err=%d\n", ret); + return -1; + } + + read_buf_ptr += n; + + __pl(); + + return len; +} +EXPORT_SYMBOL(ps3stor_cli_printf); + +int ps3stor_cli_register(ps3_cli_func_t func, const char *cmd_str, const char *help) +{ + u32 idx = str_hash(cmd_str) & (PS3_CLI_HASH_LEN-1); + struct ps3_cli_cmd_s *cmd; + int ret; + + __pl(); + + ret = mutex_lock_killable(&ps3_cli_mutex); + if (ret!=0) { + pr_err("ps3stor_cli_register(): mutex_lock_killable return err = %d\n", ret); + return ret; + } + cmd = ps3_cli_find_cmd(cmd_str); + if (cmd) { + pr_err("cmd=['%s'] has already been registered\n", cmd_str); + mutex_unlock(&ps3_cli_mutex); + return -EEXIST; + } + + cmd = (struct ps3_cli_cmd_s *)kmalloc(sizeof(struct ps3_cli_cmd_s), GFP_KERNEL); + if (cmd==NULL) { + pr_err("out of memory\n"); + mutex_unlock(&ps3_cli_mutex); + return -ENOMEM; + } + + memset(cmd, 0, sizeof(struct ps3_cli_cmd_s)); + + strncpy(cmd->cmd, cmd_str, PS3_CLI_CMD_MAXLEN - 1); + strncpy(cmd->help, help, PS3_CLI_HELP_LEN - 1); + + cmd->func = func; + + cmd->next = ps3_cli_cmd_head[idx]; + ps3_cli_cmd_head[idx] = cmd; + + mutex_unlock(&ps3_cli_mutex); + __pl(); + return 0; +} +EXPORT_SYMBOL(ps3stor_cli_register); + +static void ps3_parse_cmd(char *cmdline, int *argc, char *argv[]) +{ + char *p = cmdline; + int i=0, spc=1; + while(*p) { + if (spc) { + if (*p!=' ') { + spc = 0; + argv[i] = p; + i++; + } else { + *p = '\0'; + } + } else { + if (*p==' ') { + spc = 1; + *p = '\0'; + } else { + } + } + p++; + } + *argc = i; +} + +static ssize_t ps3_cli_read(struct file *fp, char __user *buf, + size_t nbytes, loff_t *ppos) +{ + struct ps3_cli_cmd_s *cmd; + int argc; + char *argv[PS3_MAX_ARGV]; + int ret; + + (void)fp; + (void)ppos; + __pl(); + + if (!cmd_ready) { + pr_err("ps3_cli_write() must be called before ps_cli_read()\n"); + return -EINVAL; + } + read_buf = buf; + read_buf_len = (int)nbytes; + read_buf_ptr = 0; + + ps3_parse_cmd(ps3_cli_input, &argc, argv); + + ret = mutex_lock_killable(&ps3_cli_mutex); + if (ret!=0) { + pr_err("ps3stor_cli_register(): mutex_lock_killable return err = %d\n", ret); + return ret; + } + cmd = ps3_cli_find_cmd((const char*)argv[0]); + if (cmd!=NULL) { + cmd->func(argc, argv); + } + mutex_unlock(&ps3_cli_mutex); + + __pl(); + return read_buf_ptr; +} + +static int ps3_cli_open(struct inode *ip, struct file *fp) +{ + (void)ip; + (void)fp; + if (!__sync_bool_compare_and_swap(&dev_opened, 0, 1)) { + pr_err("/dev/ps3stor_cli has already been opened\n"); + return -EBUSY; + } + cmd_ready = 0; + return 0; +} + +static int ps3_cli_release(struct inode *ip, struct file *fp) +{ + (void)ip; + (void)fp; + dev_opened = 0; + return 0; +} + +static const struct file_operations ps3_cli_fops = { + .owner = NULL, + .unlocked_ioctl = NULL, + .open = ps3_cli_open, + .release = ps3_cli_release, + .llseek = NULL, + .read = ps3_cli_read, + .write = ps3_cli_write, + .fasync = NULL +}; + +static struct miscdevice ps3_cli_device = { + .minor = PS3_CLI_STATIC_MINOR, + .name = "ps3stor_cli", + .fops = &ps3_cli_fops, +}; + +static void ps3_cli_help(int argc, char *argv[]) +{ + int i; + struct ps3_cli_cmd_s *cmd; + (void)argc; + (void)argv; + __pl(); + for (i=0; inext) { + ps3stor_cli_printf("%20s -- %s\n", cmd->cmd, (const char*)cmd->help); + } + } + __pl(); +} + +static void ps3_free_cmds(void) +{ + int i; + struct ps3_cli_cmd_s *cmd; + for (i=0; inext; + kfree(cmd); + } + } +} + +int ps3cmd_init(void) +{ + int err; + + if (misc_registered != 0) + return -EBUSY; + + mutex_init(&ps3_cli_mutex); + + ps3_cli_device.minor = PS3_CLI_DYNAMIC_MINOR; + err = misc_register(&ps3_cli_device); + if (err) { + pr_warn("Couldn't initialize miscdevice /dev/ps3stor_cli.\n"); + return err; + } + misc_registered = 1; + ps3stor_cli_register(ps3_cli_help, "help", "show this help information"); + return 0; +} + +void ps3cmd_exit(void) +{ + if (!misc_registered) + return; + misc_deregister(&ps3_cli_device); + ps3_free_cmds(); + misc_registered = 0; + mutex_destroy(&ps3_cli_mutex); +} + diff --git a/drivers/scsi/ps3stor/linux/ps3_cli.h b/drivers/scsi/ps3stor/linux/ps3_cli.h new file mode 100644 index 0000000000000000000000000000000000000000..cb2a747257615b870688071cd71df13f171829b8 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_cli.h @@ -0,0 +1,24 @@ + +#ifndef _PS3_CLI_H_ +#define _PS3_CLI_H_ + +#define PS3_CLI_INPUT_LEN 2048 +#define PS3_CLI_OUTPUT_MAX (16*1024*1024) +#define PS3_CLI_OUTLINE_LEN 4096 +#define PS3_CLI_HELP_LEN 256 +#define PS3_CLI_CMD_MAXLEN 32 +#define PS3_MAX_ARGV 64 + +typedef void (*ps3_cli_func_t)(int argc, char *argv[]); + +int ps3stor_cli_register(ps3_cli_func_t func, const char *cmd_str, const char *help); + +int ps3stor_cli_printf(const char *fmt, ...); + +int ps3cmd_init(void); + +void ps3cmd_exit(void); + + +#endif + diff --git a/drivers/scsi/ps3stor/linux/ps3_cli_debug.c b/drivers/scsi/ps3stor/linux/ps3_cli_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..c67d5de7e8ccf4bcf273ef78cbe7862b589da66a --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_cli_debug.c @@ -0,0 +1,5334 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps3_cli_debug.h" +#include "ps3_cli.h" +#include "ps3_driver_log.h" +#include "ps3_ioc_manager.h" +#include "ps3_ioc_state.h" +#include "ps3_event.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_cmd_statistics.h" +#include "ps3_scsih.h" +#include "ps3_util.h" +#include "ps3_dump.h" +#include "ps3_recovery.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_irq.h" +#include "ps3_cmd_complete.h" +#include "ps3_qos.h" +#include "ps3_inject.h" +static void ps3_cli_host_and_instance_ls(int argc, char *argv[]); +static void ps3_cli_register_rw(int argc, char *argv[]); +static void ps3_cli_register_dump(int argc, char *argv[]); +static void ps3_cli_init_frame_dump(int argc, char *argv[]); +static void ps3_cli_event_subscirbe_info_dump(int argc, char *argv[]); +static void ps3_cli_dev_mgr_cli_base_dump(int argc, char *argv[]); +static void ps3_cli_dev_mgr_cli_detail_dump(int argc, char *argv[]); +static void ps3_cli_reply_fifo_dump(int argc, char *argv[]); +static void ps3_cli_cmd_dump(int argc, char *argv[]); +static void ps3_cli_event_delay_set(int argc, char *argv[]); +static void ps3_cli_crashdump_set(int argc, char *argv[]); +static void ps3_cli_force_to_stop(int argc, char *argv[]); +static void ps3_io_statis_dump_cli_cb(int argc, char *argv[]); +static void ps3_io_statis_clear_cli_cb(int argc, char *argv []); +static void ps3_debug_mem_rw_cli_cb(int argc, char *argv[]); +static void ps3_debug_mem_para_cli_cb(int argc, char *argv[]); +static void ps3_scsi_device_lookup_cb(int argc, char *argv[]); +static void ps3_hard_reset_cb(int argc, char *argv[]); +static void ps3_soc_halt_cb(int argc, char *argv[]); +static void ps3_cmd_stat_switch_store_cb(int argc, char *argv[]); +static void ps3_stat_total_show_cb(int argc, char *argv[]); +static void ps3_stat_buf_clr_cb(int argc, char *argv[]); +static void ps3_stat_interval_show_cb(int argc, char *argv[]); +static void ps3_stat_interval_store_cb(int argc, char *argv[]); +static void ps3_stat_inc_show_cb(int argc, char *argv[]); +static void ps3_cmd_stat_switch_show_cb(int argc, char *argv[]); +static void ps3_reply_fifo_reset_cb(int argc, char *argv[]); +static void ps3_cli_remove_host_force(int argc, char *argv[]); +static void ps3_hardreset_cnt_clear_cli_cb(int argc, char *argv[]); +static void ps3_hardreset_cnt_show_cli_cb(int argc, char *argv[]); +static void ps3_cli_ramfs_test_set(int argc, char *argv[]); +static void ps3_cli_err_inject_active(int argc, char *argv[]); +static void ps3_cli_err_inject_clear(int argc, char *argv[]); +static void ps3_no_wait_cli_cmd(int argc, char *argv[]); +static void ps3_cli_qos_info(int argc, char *argv[]); +static void ps3_cli_special_log(int argc, char *argv[]); + +static Bool ps3_cli_wait_flag = PS3_FALSE; +#ifdef PS3_SUPPORT_INJECT +static void ps3_show_inject_scsi_rw(int argc, char *argv[]); +static void ps3_show_inject_scsi_task(int argc, char *argv[]); +static void ps3_show_inject_mgr(int argc, char *argv[]); + +static void ps3_clear_all_inject(int argc, char *argv[]); +static void ps3_clear_inject_scsi_task(int argc, char *argv[]); +static void ps3_clear_inject_mgr(int argc, char *argv[]); + +static void ps3_clear_inject_scsi_rw(int argc, char *argv[]); +static void ps3_inject_scsi_task(int argc, char *argv[]); +static void ps3_inject_mgr(int argc, char *argv[]); +static void ps3_inject_scsi_rw(int argc, char *argv[]); +static void ps3_show_all_inject(int argc, char *argv[]); +static void ps3_clear_hit_cmd(int argc, char *argv[]); +#endif +struct ps3_cli_debug_cmd { + ps3_cli_func_t func; + const char *func_name; + const char *help; +}; + +static struct ps3_cli_debug_cmd g_ps3_cli_debug_cmd_table[] = { + {ps3_cli_host_and_instance_ls, "ls", "ls option[host][instance][all]"}, + {ps3_cli_register_rw, "register_rw", + "register_rw host_no xxx(host number) name/offset xxx(reg name/offset) read/write xxx(reg value)"}, + {ps3_cli_register_dump, "register_dump", + "register_dump host_no xxx(host number)"}, + {ps3_cli_init_frame_dump, "init_frame_dump", + "init_frame_dump host_no xxx(host number)"}, + {ps3_cli_event_subscirbe_info_dump, + "event_subscribe_dump", + "event_subscribe_dump host_no xxx(host number)"}, + {ps3_cli_event_delay_set, + "event_delay_set", + "event_delay_set host_no xxx(host number) delay xxx(seconds)"}, + {ps3_cli_crashdump_set, + "crashdump", + "crashdump host_no xxx(host number) wait xxx(seconds)"}, + {ps3_cli_dev_mgr_cli_base_dump, "dmbi", + "device manager base infomation: dmbi option[vd][pd][all]"}, + {ps3_cli_dev_mgr_cli_detail_dump, "dmdi", + "device manager detail infomation: dmdi "}, + {ps3_cli_reply_fifo_dump, "reply_fifo_dump", + "reply_fifo_dump host_no xxx(host number) isr_sn xxx(isr SN) \ + option[start_idx xxx default: last_reply_idx][count xxx default: 100]"}, + {ps3_cli_cmd_dump, "cmd_dump", + "cmd_dump host_no xxx(host number) cmd_frame_id xxx(cmd_frame_id)"}, + {ps3_io_statis_dump_cli_cb, "show", + "show io statis (detail|summary)"}, + {ps3_io_statis_clear_cli_cb, "clear", + "clear io statis "}, + {ps3_cli_force_to_stop, "force_to_stop", "force_to_stop"}, + {ps3_debug_mem_para_cli_cb, "debug_mem_para_dump", + "debug_mem_para_dump host_no xxx(host no)"}, + {ps3_debug_mem_rw_cli_cb, "debug_mem", + "debug_mem host_no (host no) entry_index(0--max entry count) dir(0 read/1 write) length(Bytes)"}, + {ps3_scsi_device_lookup_cb, + "scsi_device_dump", "scsi_device_dump host_no xxx(host number)"}, + {ps3_hard_reset_cb, + "hard_reset", "hard_reset host_no xxx(host number)"}, + {ps3_soc_halt_cb, + "soc_halt", "soc_halt host_no xxx(host number)"}, + {ps3_cmd_stat_switch_store_cb, "cmd_stat_switch_store", + "cmd_stat_switch_store host_no xxx(host number) value xxx mask xxx" + "[bit0:OUTSTAND_SWITCH_OPEN, bit1:INC_SWITCH_OPEN," + " bit2:LOG_SWITCH_OPEN, bit3:DEV_SWITCH_OPEN]"}, + {ps3_cmd_stat_switch_show_cb, + "cmd_stat_switch_show", "cmd_stat_switch_show host_no xxx"}, + {ps3_stat_total_show_cb, "cmd_stat_dump", "cmd_stat_dump host_no xxx"}, + {ps3_stat_inc_show_cb, "inc_stat_dump", "inc_stat_dump host_no xxx"}, + {ps3_stat_buf_clr_cb, "cmd_stat_clear", "cmd_stat_clear host_no xxx"}, + {ps3_stat_interval_show_cb, "cmd_stat_interval_show", + "cmd_stat_interval_show host_no xxx"}, + {ps3_stat_interval_store_cb, "cmd_stat_interval_store", + "cmd_stat_interval_store host_no xxx interval xxx(ms)"}, + {ps3_reply_fifo_reset_cb, "ps3_all_reply_fifo_reset", + "ps3_all_reply_fifo_reset host_no xxx"}, + {ps3_cli_remove_host_force, "remove_host", + "remove one host and free resource: (host number)"}, + {ps3_hardreset_cnt_clear_cli_cb, "hardreset_cnt_clear", + "hardreset_cnt_clear host_no xxx(host number)"}, + {ps3_hardreset_cnt_show_cli_cb, "hardreset_cnt_show", + "hardreset_cnt_show host_no xxx(host number)"}, + {ps3_cli_ramfs_test_set, "ramfs_test_set", + "set or clear filesystem type to ramfs: (0: clear, 1: set)"}, + {ps3_cli_err_inject_active, "err_inject", + "err_inject err_type count"}, + {ps3_cli_err_inject_clear, "cli_err_clear", + ""}, + {ps3_no_wait_cli_cmd, "ps3_no_wait_cli_cmd", + "clean_wait_cli_cmd flag xxx"}, + {ps3_cli_qos_info, "qos_dump", + "qos_dump host_no xxx(host number) pd/vd xxx(id) | all"}, + {ps3_cli_special_log, "spe_log", + "spe_log host_no xxx(host number) set xxx(0/1)"}, +#ifdef PS3_SUPPORT_INJECT + {ps3_inject_scsi_rw, "inject_rw", + "host_no xxx(host number) dev xxx xxx(channel id) lba xxx len xxx xxx(1 timeout_force_reply/2 error_reply)\ +result xxx(scsi->result) sense xxx(resp_code-key-asc-ascq) times xxx"}, + {ps3_show_inject_scsi_rw, "show_inject_rw", + "host_no xxx(host number) dev xxx xxx(channel id) lba xxx len xxx xxx"}, + {ps3_clear_inject_scsi_rw, "clear_inject_rw", + "host_no xxx(host number) dev xxx xxx(channel id) lba xxx len xxx xxx"}, + {ps3_inject_scsi_task, "inject_scsi_task", + "host_no xxx(host number) dev xxx xxx(channel id) abort/reset (3 timeout/4 error_reply) times xxx"}, + {ps3_inject_mgr, "inject_mgr", + "host_no xxx(host number) cmd_type xxx cmd_sub_type xxx xxx (7 timeout/8 error_reply xxx (errType)) times xxx"}, + {ps3_show_inject_scsi_task, "show_inject_scsi_task", + "host_no xxx(host number) dev xxx xxx(channel id)"}, + {ps3_show_inject_mgr, "show_inject_mgr", + "host_no xxx(host number) cmd_type xxx cmd_sub_type xxx"}, + {ps3_clear_inject_scsi_task, "clear_inject_scsi_task", + "host_no xxx(host number) dev xxx xxx(channel id)"}, + {ps3_clear_inject_mgr, "clear_inject_mgr", + "host_no xxx(host number) cmd_type xxx cmd_sub_type xxx"}, + {ps3_clear_all_inject, "clear_inject_all", + "clear_inject_all"}, + {ps3_show_all_inject, "show_inject_all", + "show_inject_all"}, + {ps3_clear_hit_cmd, "ps3_clear_hit_cmd", + "ps3_clear_hit_cmd"}, +#endif +}; + +#define DRIVER_REGISTER_DEBUG_SIMULATOR +#define REG_OFFSET(member) (offsetof(Ps3Fifo_s, member)) +struct ps3_reg_dump_desc { + const char *reg_name; + U32 reg_offset; + U32 reg_cnt; + Bool is_readable; +}; + +static struct ps3_reg_dump_desc g_reg_table[] = { + {"ps3RequestQueue", PS3_REG_OFFSET_REQUEST_QUE, 1, PS3_TRUE}, + {"ps3Doorbell", PS3_REG_OFFSET_DOORBELL, 1, PS3_FALSE}, + {"ps3DoorbellIrqClear", PS3_REG_OFFSET_DOORBELL_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3DoorbellIrqMask", PS3_REG_OFFSET_DOORBELL_IRQ_MASK, 1, PS3_TRUE}, + {"ps3IrqControl", PS3_REG_OFFSET_IRQ_CONTROL, 1, PS3_TRUE}, + {"ps3SoftresetKey", PS3_REG_OFFSET_SOFTRESET_KEY, 1, PS3_TRUE}, + {"ps3SoftresetState", PS3_REG_OFFSET_SOFTRESET_STATE, 1, PS3_TRUE}, + {"ps3Softreset", PS3_REG_OFFSET_SOFTRESET, 1, PS3_TRUE}, + {"ps3SoftresetIrqClear", PS3_REG_OFFSET_SOFTRESET_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3SoftresetIrqMask", PS3_REG_OFFSET_SOFTRESET_IRQ_MASK, 1, PS3_TRUE}, + {"ps3SoftresetKeyShiftRegLow", PS3_REG_OFFSET_SOFTRESET_KEY_SHIFT_REG_LOW, 1, PS3_TRUE}, + {"ps3SoftresetKeyShiftRegHigh", PS3_REG_OFFSET_SOFTRESET_KEY_SHIFT_REG_HIGH, 1, PS3_TRUE}, + {"ps3SoftresetTimeCnt", PS3_REG_OFFSET_SOFTRESET_TIME_CNT, 1, PS3_TRUE}, + {"ps3SoftresetTimeOutEn", PS3_REG_OFFSET_SOFTRESET_TIME_OUT_CNT, 1, PS3_TRUE}, + {"ps3HardresetKey", PS3_REG_OFFSET_HARDRESET_KEY, 1, PS3_TRUE}, + {"ps3HardresetState", PS3_REG_OFFSET_HARDRESET_STATE, 1, PS3_TRUE}, + {"ps3Hardreset", PS3_REG_OFFSET_HARDRESET, 1, PS3_TRUE}, + {"ps3HardresetKeyShiftRegLow", PS3_REG_OFFSET_HARDRESET_KEY_SHIFT_REG_LOW, 1, PS3_TRUE}, + {"ps3HardresetKeyShiftRegHigh", PS3_REG_OFFSET_HARDRESET_KEY_SHIFT_REG_HIGH, 1, PS3_TRUE}, + {"ps3HardresetTimeCnt", PS3_REG_OFFSET_HARDRESET_TIME_CNT, 1, PS3_TRUE}, + {"ps3HardresetTimeOutEn", PS3_REG_OFFSET_HARDRESET_TIME_OUT_CNT, 1, PS3_TRUE}, + {"ps3KeyGapCfg", PS3_REG_OFFSET_KEY_GAP_CFG, 1, PS3_TRUE}, + {"ps3HardresetIrqClear", PS3_REG_OFFSET_HARDRESET_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3HardresetIrqMask", PS3_REG_OFFSET_HARDRESET_IRQ_MASK, 1, PS3_TRUE}, + {"ps3SocFwState", PS3_REG_OFFSET_SOC_FW_STATE, 1, PS3_TRUE}, + {"ps3MaxFwCmd", PS3_REG_OFFSET_MAX_FW_CMD, 1, PS3_TRUE}, + {"ps3MaxChainSize", PS3_REG_OFFSET_MAX_CHAIN_SIZE, 1, PS3_TRUE}, + {"ps3MaxVdInfoSize", PS3_REG_OFFSET_MAX_VD_INFO_SIZE, 1, PS3_TRUE}, + {"ps3MaxNvmePageSize", PS3_REG_OFFSET_MAX_NVME_PAGE_SIZE, 1, PS3_TRUE}, + {"ps3FeatureSupport", PS3_REG_OFFSET_FEATURE_SUPPORT, 1, PS3_TRUE}, + {"ps3FirmwareVersion", PS3_REG_OFFSET_FIRMWARE_VERSION, 1, PS3_TRUE}, + {"ps3MaxReplyque", PS3_REG_OFFSET_REPLY_QUE, 1, PS3_TRUE}, + {"ps3HardwareVersion", PS3_REG_OFFSET_HARDWARE_VERSION, 1, PS3_TRUE}, + {"ps3MgrQueueDepth", PS3_REG_OFFSET_MGR_QUEUE_DEPTH, 1, PS3_TRUE}, + {"ps3CmdQueueDepth", PS3_REG_OFFSET_CMD_QUEUE_DEPTH, 1, PS3_TRUE}, + {"ps3TfifoDepth", PS3_REG_OFFSET_TFIFO_DEPTH, 1, PS3_TRUE}, + {"ps3MaxSecR1xCmds", PS3_REG_OFFSET_MAX_SEC_R1X_CMDS, 1, PS3_TRUE}, + {"ps3HilAdvice2directCnt0", PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT0, 1, PS3_TRUE}, + {"ps3HilAdvice2directCnt1", PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT1, 1, PS3_TRUE}, + {"ps3HilAdvice2directCnt2", PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT2, 1, PS3_TRUE}, + {"ps3HilAdvice2directCnt3", PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT3, 1, PS3_TRUE}, + {"ps3HilAdvice2directCntAll", PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT_ALL, 1, PS3_TRUE}, + {"ps3IrqStatusRpt", PS3_REG_OFFSET_IRQ_STATUS_RPT, 1, PS3_TRUE}, + {"ps3DumpCtrl", PS3_REG_OFFSET_DUMP_CTRL, 1, PS3_FALSE}, + {"ps3DumpCtrlIrqClear", PS3_REG_OFFSET_DUMP_CTRl_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3DumpCtrlIrqMask", PS3_REG_OFFSET_DUMP_CTRl_IRQ_MASK, 1, PS3_TRUE}, + {"ps3DumpStatus", PS3_REG_OFFSET_DUMP_STATUS, 1, PS3_TRUE}, + {"ps3DumpDataSize", PS3_REG_OFFSET_DUMP_DATA_SIZE, 1, PS3_TRUE}, + {"ps3CmdTrigger", PS3_REG_OFFSET_CMD_TRIGGER, 1, PS3_TRUE}, + {"ps3CmdTriggerIrqClear", PS3_REG_OFFSET_CMD_TRIGGER_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3CmdTriggerIrqMask", PS3_REG_OFFSET_CMD_TRIGGER_IRQ_MASK, 1, PS3_TRUE}, + {"ps3RegCmdState", PS3_REG_OFFSET_REG_CMD_STATE, 1, PS3_TRUE}, + {"ps3SoftresetCounter", PS3_REG_OFFSET_SOFTRESET_COUNTER, 1, PS3_TRUE}, + {"ps3Debug0", PS3_REG_OFFSET_DEBUG0, 1, PS3_TRUE}, + {"ps3Debug0IrqClear", PS3_REG_OFFSET_DEBUG0_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3Debug0IrqMask", PS3_REG_OFFSET_DEBUG0_IRQ_MASK, 1, PS3_TRUE}, + {"ps3Debug1", PS3_REG_OFFSET_DEBUG1, 1, PS3_TRUE}, + {"ps3Debug1IrqClear", PS3_REG_OFFSET_DEBUG1_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3Debug1IrqMask", PS3_REG_OFFSET_DEBUG1_IRQ_MASK, 1, PS3_TRUE}, + {"ps3Debug2", PS3_REG_OFFSET_DEBUG2, 1, PS3_TRUE}, + {"ps3Debug2IrqClear", PS3_REG_OFFSET_DEBUG2_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3Debug2IrqMask", PS3_REG_OFFSET_DEBUG2_IRQ_MASK, 1, PS3_TRUE}, + {"ps3Debug3", PS3_REG_OFFSET_DEBUG3, 1, PS3_TRUE}, + {"ps3Debug3IrqClear", PS3_REG_OFFSET_DEBUG3_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3Debug3IrqMask", PS3_REG_OFFSET_DEBUG3_IRQ_MASK, 1, PS3_TRUE}, + {"ps3Debug4", PS3_REG_OFFSET_DEBUG4, 1, PS3_TRUE}, + {"ps3Debug4IrqMask", PS3_REG_OFFSET_DEBUG4_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3Debug4IrqMask", PS3_REG_OFFSET_DEBUG4_IRQ_MASK, 1, PS3_TRUE}, + {"ps3Debug5", PS3_REG_OFFSET_DEBUG5, 1, PS3_TRUE}, + {"ps3Debug6", PS3_REG_OFFSET_DEBUG6, 1, PS3_TRUE}, + {"ps3Debug7", PS3_REG_OFFSET_DEBUG7, 1, PS3_TRUE}, + {"ps3Debug8", PS3_REG_OFFSET_DEBUG8, 1, PS3_TRUE}, + {"ps3Debug9", PS3_REG_OFFSET_DEBUG9, 1, PS3_TRUE}, + {"ps3Debug10", PS3_REG_OFFSET_DEBUG10, 1, PS3_TRUE}, + {"ps3Debug11", PS3_REG_OFFSET_DEBUG11, 1, PS3_TRUE}, + {"ps3Debug12", PS3_REG_OFFSET_DEBUG12, 1, PS3_TRUE}, + {"ps3SessioncmdAddr", PS3_REG_SESSION_ADDR, 1, PS3_TRUE}, + {"ps3SessioncmdAddrIrqClear", PS3_REG_SESSION_ADDR_IRQ_CLEAR, 1, PS3_TRUE}, + {"ps3SessioncmdAddrIrqMask", PS3_REG_SESSION_ADDR_IRQ_MASK, 1, PS3_TRUE}, +}; + +static void ps3_cli_register_dump(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + char *buf = NULL; + U16 host_no = 0; + S32 ret = 0; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed for register dump cli!\n"); + goto l_malloc_failed; + } + + if (argc < 3) { + ps3stor_cli_printf("Too few args for register dump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for register dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for register dump cmd!\n", + host_no); + goto l_out; + } + + if (instance->reg_set == NULL) { + ps3stor_cli_printf("ioc reg_set has not been alloc!\n"); + goto l_out; + } + + (void)ps3_ioc_reg_dump(instance, buf); + ps3stor_cli_printf(buf); + ps3stor_cli_printf("\n"); + +l_out: + kfree(buf); +l_malloc_failed: + return; +} + +static void ps3_cli_init_frame_dump(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + struct ps3_cmd_context *cmd_context = NULL; + struct PS3InitReqFrame *init_frame_msg = NULL; + U16 host_no = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args for init_frame_dump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for init_frame_dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for init_frame_dump cmd!\n", + host_no); + goto l_out; + } + + cmd_context = &instance->cmd_context; + init_frame_msg = (struct PS3InitReqFrame *)cmd_context->init_frame_buf; + + if (init_frame_msg == NULL) { + ps3stor_cli_printf("init frame has not been alloc!\n"); + goto l_out; + } + + ps3stor_cli_printf("init frame:\n"); + ps3stor_cli_printf("reqHead.cmdType:\t%u\n", + init_frame_msg->reqHead.cmdType); + ps3stor_cli_printf("length:\t%u\n", init_frame_msg->length); + ps3stor_cli_printf("operater:\t%u\n", init_frame_msg->operater); + ps3stor_cli_printf("pageSize:\t%u\n", init_frame_msg->pageSize); + ps3stor_cli_printf("pciIrqType:\t%u\n", init_frame_msg->pciIrqType); + ps3stor_cli_printf("msixVector:\t%u\n", init_frame_msg->msixVector); + ps3stor_cli_printf("timeStamp:\t%llu\n", init_frame_msg->timeStamp); + ps3stor_cli_printf("reqFrameBufBaseAddr:\t0x%llx\n", + init_frame_msg->reqFrameBufBaseAddr); + ps3stor_cli_printf("replyFifoDescBaseAddr:\t0x%llx\n", + init_frame_msg->replyFifoDescBaseAddr); + ps3stor_cli_printf("respFrameBaseAddr:\t0x%llx\n", + init_frame_msg->respFrameBaseAddr); + ps3stor_cli_printf("eventTypeMap:\t0x%08x\n", init_frame_msg->eventTypeMap); + ps3stor_cli_printf("reqFrameMaxNum:\t%u\n", init_frame_msg->reqFrameMaxNum); + ps3stor_cli_printf("respFrameMaxNum:\t%u\n", + init_frame_msg->respFrameMaxNum); + ps3stor_cli_printf("bufSizePerRespFrame:\t%u\n", + init_frame_msg->bufSizePerRespFrame); + ps3stor_cli_printf("hilMode:\t%u\n", + init_frame_msg->hilMode); + ps3stor_cli_printf("systemInfoBufAddr:\t0x%llx\n", + init_frame_msg->systemInfoBufAddr); + ps3stor_cli_printf("debugMemAddr:\t0x%llx\n", init_frame_msg->debugMemArrayAddr); + ps3stor_cli_printf("debugMemSize:\t%u\n", init_frame_msg->debugMemArrayNum); + ps3stor_cli_printf("filterTableAddr:\t0x%llx\n", init_frame_msg->filterTableAddr); + ps3stor_cli_printf("filterTableLen:\t%u\n", init_frame_msg->filterTableLen); + + ps3stor_cli_printf("respStatus:\t0x%08x\n", init_frame_msg->respStatus); + +l_out: + return; +} + +static S32 ps3_register_offset_lookup(const char *reg_name_string, + U32 *reg_offset) +{ + U32 idx = 0; + struct ps3_reg_dump_desc *reg_desc = NULL; + + for (idx = 0; idx < ARRAY_SIZE(g_reg_table); idx++) { + reg_desc = &g_reg_table[idx]; + + if (reg_desc->reg_cnt != 1) { + LOG_DEBUG("Reg %s is not a single register!\n", + reg_desc->reg_name); + continue; + } + + if (strcmp(reg_name_string, reg_desc->reg_name) == 0) { + *reg_offset = reg_desc->reg_offset; + return PS3_SUCCESS; + } + } + + return -PS3_FAILED; +} + +static void ps3_register_read_write(struct ps3_instance *instance, + int argc, char *argv[]) +{ + const char *reg_name_offset_string = argv[3]; + const char *reg_loc_string = argv[4]; + const char *state_ops_string = argv[5]; + U32 reg_value = 0; + U32 reg_offset = 0; + S32 ret = 0; + U64 value; + + if (strcmp(reg_name_offset_string, "offset") == 0) { + ret = kstrtouint(reg_loc_string, 0, ®_offset); + } else { + ret = ps3_register_offset_lookup(reg_loc_string, ®_offset); + } + + if (ret != PS3_SUCCESS) { + ps3stor_cli_printf("Reg %s not supported to read and write!\n", + reg_loc_string); + goto l_out; + } + + if (strcmp(state_ops_string, "read") == 0) { + PS3_IOC_REG_READ_OFFSET_WITCH_CHECK(instance, reg_offset, value); + ps3stor_cli_printf("0x%llx\n", value); + } else if (strcmp(state_ops_string, "write") == 0) { + if (argc < 7) { + ps3stor_cli_printf("No reg value for %s write cmd!\n", + reg_loc_string); + goto l_out; + } + + ret = kstrtouint(argv[6], 0, ®_value); + if (ret != 0) { + ps3stor_cli_printf("Invalid reg value for %s write cmd!\n", + reg_loc_string); + goto l_out; + } + + PS3_IOC_REG_WRITE_OFFSET_WITH_CHECK(instance, reg_offset, (U64)reg_value); + ps3stor_cli_printf("Write 0x%x to %s!\n", reg_value, + reg_loc_string); + } else { + ps3stor_cli_printf("Invalid ops for %s cmd!\n", reg_loc_string); + } + +l_out: + return; +} + +static void ps3_cli_register_rw(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = 0; + + if (argc < 6) { + ps3stor_cli_printf("Too few args for register cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for register cli cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for register cli cmd!\n", + host_no); + goto l_out; + } + + ps3_register_read_write(instance, argc, argv); +l_out: + return; +} + +ssize_t ps3_ioc_reg_dump(struct ps3_instance *instance, char *buf) +{ + ssize_t len = 0; + ssize_t total_len = PAGE_SIZE; + U32 idx = 0; + U64 value = 0; + struct ps3_reg_dump_desc *reg_desc = NULL; + + for (idx = 0; idx < ARRAY_SIZE(g_reg_table); idx++) { + reg_desc = &g_reg_table[idx]; + +#ifndef DRIVER_REGISTER_DEBUG_SIMULATOR + if (!reg_desc->is_readable) { + continue; + } +#endif + if (reg_desc->reg_cnt > 1) { + continue; + } + + PS3_IOC_REG_READ_OFFSET_WITCH_CHECK(instance, reg_desc->reg_offset, value); + len += snprintf(buf + len, total_len - len, "%s:\t0x%08llx\n", + reg_desc->reg_name, value); + } + + return len; +} + +static void ps3_dev_mgr_print_vd(struct PS3VDEntry *p_entry, Bool is_detail) +{ + U8 i = 0; + U8 j = 0; + ps3stor_cli_printf("vd channel, id, virtDiskId: [%u:%u:%u], magicNum:%#x\n", + PS3_CHANNEL(&p_entry->diskPos), PS3_TARGET(&p_entry->diskPos), + PS3_VDID(&p_entry->diskPos), p_entry->diskPos.diskMagicNum); + ps3stor_cli_printf("vd dev_type: PS3_DEV_TYPE_VD\n"); + ps3stor_cli_printf("vd isHidden: %s\n", + (p_entry->isHidden) ? "true" : "false"); + ps3stor_cli_printf("vd accessPolicy: %s\n", + ps3_get_vd_access_plolicy_str((VDAccessPolicy_e)p_entry->accessPolicy)); + ps3stor_cli_printf("vd diskGrpId: %u\n", p_entry->diskGrpId); + + if (!is_detail) { + return; + } + ps3stor_cli_printf("vd sectorSize: %u\n", p_entry->sectorSize); + ps3stor_cli_printf("vd stripeDataSize: %u\n", p_entry->stripeDataSize); + ps3stor_cli_printf("vd physDrvCnt: %u\n", p_entry->physDrvCnt); + ps3stor_cli_printf("vd stripSize: %u\n", p_entry->stripSize); + ps3stor_cli_printf("vd isDirectEnable: %s\n", + (p_entry->isDirectEnable) ? "true" : "false"); + ps3stor_cli_printf("vd isNvme: %s\n", + (p_entry->isNvme) ? "true" : "false"); + ps3stor_cli_printf("vd isSsd: %s\n", + (p_entry->isSsd) ? "true" : "false"); + ps3stor_cli_printf("vd isWriteDirectEnable: %s\n", + (p_entry->isWriteDirectEnable) ? "true" : "false"); + ps3stor_cli_printf("vd raidLevel: %u\n", p_entry->raidLevel); + ps3stor_cli_printf("vd spanCount: %u\n", p_entry->spanCount); + ps3stor_cli_printf("vd diskState: %u\n", p_entry->diskState); + ps3stor_cli_printf("vd startLBA: %llu\n", p_entry->startLBA); + ps3stor_cli_printf("vd extentSize: %llu\n", p_entry->extentSize); + ps3stor_cli_printf("vd isTaskMgmtEnable: %u\n", p_entry->isTaskMgmtEnable); + ps3stor_cli_printf("vd taskAbortTimeout: %u\n", p_entry->taskAbortTimeout); + ps3stor_cli_printf("vd taskResetTimeout: %u\n", p_entry->taskResetTimeout); + ps3stor_cli_printf("vd mapBlock: %llu\n", p_entry->mapBlock); + ps3stor_cli_printf("vd mapBlockVer: %u\n", p_entry->mapBlockVer); + ps3stor_cli_printf("vd maxIOSize: %u\n", p_entry->maxIOSize); + ps3stor_cli_printf("vd devQueDepth: %u\n", p_entry->devQueDepth); + ps3stor_cli_printf("vd dmaAddrAlignShift: %u\n", p_entry->dmaAddrAlignShift); + ps3stor_cli_printf("vd dmaLenAlignShift: %u\n", p_entry->dmaLenAlignShift); + ps3stor_cli_printf("vd capacity(sector): %llu\n", p_entry->capacity); + ps3stor_cli_printf("vd bdev_bdi_cap: %u\n", p_entry->bdev_bdi_cap); + ps3stor_cli_printf("vd umapBlkDescCnt: %u\n", p_entry->umapBlkDescCnt); + ps3stor_cli_printf("vd umapNumblk: %u\n", p_entry->umapNumblk); + ps3stor_cli_printf("vd virtDiskSeq: %llu\n", p_entry->virtDiskSeq); + ps3stor_cli_printf("vd normalQuota:%u directQuota:%u\n", + p_entry->normalQuota, p_entry->directQuota); + ps3stor_cli_printf("vd dev_busy_scale: %u\n", p_entry->dev_busy_scale); + + for (i = 0; i < p_entry->spanCount; i++) { + ps3stor_cli_printf(" span[%u].spanStripeDataSize: %u\n", i, + p_entry->span[i].spanStripeDataSize); + ps3stor_cli_printf(" span[%u].spanState: %u\n", i, + p_entry->span[i].spanState); + ps3stor_cli_printf(" span[%u].spanPdNum: %u\n", i, + p_entry->span[i].spanPdNum); + + for (j = 0; j < p_entry->span[i].spanPdNum; j++) { + ps3stor_cli_printf( + " span[%u].extent[%u] - member pd:[%u:%u:%u]\n", + i, j, + p_entry->span[i].extent[j].phyDiskID.ps3Dev.softChan, + p_entry->span[i].extent[j].phyDiskID.ps3Dev.devID, + p_entry->span[i].extent[j].phyDiskID.ps3Dev.phyDiskID); + ps3stor_cli_printf(" span[%u].extent[%u].state: %u\n", i, j, + p_entry->span[i].extent[j].state); + } + } +} + +static void ps3_dev_mgr_show_base_vd(struct ps3_instance *instance) +{ + U16 i = 0; + U16 j = 0; + U8 chan_id = 0; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_channel *vd_chan = p_dev_ctx->channel_vd; + U8 vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct ps3_vd_table *p_table = + &p_dev_ctx->vd_table[vd_table_idx]; + struct PS3VDEntry *p_entries = + p_dev_ctx->vd_entries_array[vd_table_idx]; + U16 vd_idx = PS3_INVALID_DEV_ID; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + ps3stor_cli_printf("\n===========start print VD base infomation=========\n"); + for (i = 0; i < p_dev_ctx->vd_channel_count; i++) { + chan_id = vd_chan[i].channel; + for (j = 0; j < vd_chan[i].max_dev_num; j++) { + vd_idx = p_table->vd_idxs[chan_id][j]; + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), vd_idx); + if (vd_idx != PS3_INVALID_DEV_ID) { + ps3_dev_mgr_print_vd(&p_entries[virtDiskIdx], PS3_FALSE); + } + } + } + ps3stor_cli_printf("\n============end print VD base infomation==========\n"); +} + +static void ps3_dev_mgr_print_pd(struct ps3_pd_entry *p_entry, Bool is_detail, Bool is_raid) +{ + ps3stor_cli_printf("pd channel, id, pdFlatId: [%u:%u:%u], magicNum: %#x\n", + PS3_CHANNEL(&p_entry->disk_pos), PS3_TARGET(&p_entry->disk_pos), + PS3_PDID(&p_entry->disk_pos), p_entry->disk_pos.diskMagicNum); + ps3stor_cli_printf("pd state: %s\n", + getDeviceStateName((DeviceState_e)p_entry->state)); + ps3stor_cli_printf("pd dev_type: %s\n", + namePS3DevType((enum PS3DevType)p_entry->dev_type)); + ps3stor_cli_printf("pd config_flag: %s\n", + getPdStateName((MicPdState_e)p_entry->config_flag, is_raid)); + ps3stor_cli_printf("pd pd_flags: 0x%02x\n", p_entry->pd_flags); + ps3stor_cli_printf("pd support_ncq: %d\n", p_entry->support_ncq); + + if (is_detail) { + ps3stor_cli_printf("pd RWCT: %u\n", + p_entry->RWCT); + ps3stor_cli_printf("pd scsi_interface_type: %u\n", + p_entry->scsi_interface_type); + ps3stor_cli_printf("pd task_abort_timeout: %u\n", + p_entry->task_abort_timeout); + ps3stor_cli_printf("pd task_reset_timeout: %u\n", + p_entry->task_reset_timeout); + ps3stor_cli_printf("pd max_io_size: %u\n", + p_entry->max_io_size); + ps3stor_cli_printf("pd is_direct_disable: %s\n", + (p_entry->is_direct_disable) ? "true" : "false"); + ps3stor_cli_printf("pd dev_queue_depth: %u\n", + p_entry->dev_queue_depth); + ps3stor_cli_printf("pd sector_size: %u\n", + p_entry->sector_size); + ps3stor_cli_printf("pd encl_id: %u\n", + p_entry->encl_id); + ps3stor_cli_printf("pd phy_id: %u\n", + p_entry->phy_id); + ps3stor_cli_printf("pd dma_addr_alignment: %u\n", + p_entry->dma_addr_alignment); + ps3stor_cli_printf("pd dma_len_alignment: %u\n", + p_entry->dma_len_alignment); + ps3stor_cli_printf("pd protect: %u\n", + p_entry->protect); + ps3stor_cli_printf("qos pd quota:normal[%u] direct[%u]\n", + p_entry->normal_quota, p_entry->direct_quota); + } +} + +static void ps3_dev_mgr_show_base_pd(struct ps3_instance *instance) +{ + U16 i = 0; + U16 j = 0; + U8 chan_id = 0; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_channel *pd_chan = p_dev_ctx->channel_pd; + struct ps3_pd_table *p_table = &p_dev_ctx->pd_table; + U16 pd_idx = PS3_INVALID_DEV_ID; + + ps3stor_cli_printf("\n===========start print PD base infomation=========\n"); + for (i = 0; i < p_dev_ctx->pd_channel_count; i++) { + chan_id = pd_chan[i].channel; + for (j = 0; j < pd_chan[i].max_dev_num; j++) { + pd_idx = p_table->pd_idxs[chan_id][j]; + if (pd_idx != PS3_INVALID_DEV_ID) { + ps3_dev_mgr_print_pd( + &p_dev_ctx->pd_entries_array[pd_idx], + PS3_DRV_FALSE, instance->is_raid); + } + } + } + ps3stor_cli_printf("\n============end print PD base infomation==========\n"); +} + +static void ps3_cli_dev_mgr_cli_base_dump(int argc, char *argv[]) +{ + S32 ret = 0; + U16 host_no = 0; + struct ps3_instance *instance = NULL; + + if (argc < 3) { + ps3stor_cli_printf("Too few args for dmbi!\n"); + goto l_out; + } + + ret = kstrtou16(argv[1], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no \"%s\" for dmbi cmd!\n", + argv[1]); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for dmbi cmd!\n", + host_no); + goto l_out; + } + + if (strcmp(argv[2], "vd") == 0) { + ps3_dev_mgr_show_base_vd(instance); + goto l_out; + } else if (strcmp(argv[2], "pd") == 0) { + ps3_dev_mgr_show_base_pd(instance); + goto l_out; + } else if (strcmp(argv[2], "all") == 0) { + ps3_dev_mgr_show_base_vd(instance); + ps3_dev_mgr_show_base_pd(instance); + goto l_out; + } else { + ps3stor_cli_printf("Invalid subtype \"%s\" for dmbi cmd!\n", + argv[2]); + } +l_out: + return; +} + +static void ps3_dev_mgr_show_detail_info(struct ps3_instance *instance, + U16 channel, U16 id) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_pd_table *p_pd_table = &p_dev_ctx->pd_table; + U8 vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct ps3_vd_table *p_vd_table = + &p_dev_ctx->vd_table[vd_table_idx]; + struct PS3VDEntry *p_vd_array = + p_dev_ctx->vd_entries_array[vd_table_idx]; + U16 disk_idx = 0; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + if (PS3_IS_VD_CHANNEL(instance, channel)) { + if (p_vd_table->vd_idxs[channel] == NULL) { + ps3stor_cli_printf("==error==invalid channel parameter: %d\n", + channel); + goto l_out; + } + + if (id >= p_dev_ctx->max_dev_in_channel[channel]) { + ps3stor_cli_printf("==error==invalid id parameter: %d\n", + id); + goto l_out; + } + + disk_idx = p_vd_table->vd_idxs[channel][id]; + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), disk_idx); + if (virtDiskIdx == PS3_INVALID_DEV_ID) { + ps3stor_cli_printf("==warn==vd is not exist: [%u:%u]\n", + channel, id); + goto l_out; + } + ps3stor_cli_printf("\n===========start print VD detail infomation=========\n"); + ps3_dev_mgr_print_vd(&p_vd_array[virtDiskIdx], PS3_DRV_TRUE); + ps3stor_cli_printf("\n============end print VD detail infomation==========\n"); + + } else { + if (p_pd_table->pd_idxs[channel] == NULL) { + ps3stor_cli_printf("==error==invalid channel parameter: %d\n", + channel); + goto l_out; + } + + if (id >= p_dev_ctx->max_dev_in_channel[channel]) { + ps3stor_cli_printf("==error==invalid id parameter: %d\n", + id); + goto l_out; + } + + disk_idx = p_pd_table->pd_idxs[channel][id]; + if (disk_idx == PS3_INVALID_DEV_ID) { + ps3stor_cli_printf("==warn==pd is not exist: [%u:%u]\n", + channel, id); + goto l_out; + } + ps3stor_cli_printf("\n===========start print PD detail infomation=========\n"); + ps3_dev_mgr_print_pd(&p_dev_ctx->pd_entries_array[disk_idx], + PS3_DRV_TRUE, instance->is_raid); + ps3stor_cli_printf("\n============end print PD detail infomation==========\n"); + } +l_out: + return; +} + +static void ps3_cli_dev_mgr_cli_detail_dump(int argc, char *argv[]) +{ + S32 ret = 0; + U16 host_no = 0; + U16 channel = 0; + U16 id = 0; + struct ps3_instance *instance = NULL; + + if (argc < 4) { + ps3stor_cli_printf("Too few args for dmdi!\n"); + goto l_out; + } + + ret = kstrtou16(argv[1], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no \"%s\" for dmdi cmd!\n", + argv[1]); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for dmdi cmd!\n", + host_no); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse chanel \"%s\" for dmdi cmd!\n", + argv[2]); + goto l_out; + } + + ret = kstrtou16(argv[3], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse targetId \"%s\" for dmdi cmd!\n", + argv[3]); + goto l_out; + } + + ps3_dev_mgr_show_detail_info(instance, channel, id); +l_out: + return; +} + +static void ps3_cli_event_subscirbe_info_dump(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + char *buf = NULL; + U16 host_no = 0; + S32 ret = 0; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed for event subscribe info cli!\n"); + goto l_malloc_failed; + } + + if (argc < 3) { + ps3stor_cli_printf("Too few args for event_subscribe_dump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for event_subscribe_dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for event_subscribe_dump cmd!\n", + host_no); + goto l_out; + } + + (void)ps3_event_subscribe_info_get(instance, buf, PAGE_SIZE); + ps3stor_cli_printf(buf); + +l_out: + kfree(buf); +l_malloc_failed: + return; +} + +static void ps3_cli_event_delay_set(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + U32 delay_seconds = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args for event_subscribe_dump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for event_subscribe_dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for event_subscribe_dump cmd!\n", + host_no); + goto l_out; + } + + if (strcmp(argv[3], "delay") == 0) { + ret = kstrtouint(argv[4], 0, &delay_seconds); + if (ret != 0) { + ps3stor_cli_printf("Can not parse delay seconds for event delay cmd!\n"); + goto l_out; + } + ret = ps3_event_delay_set(instance, delay_seconds); + if (ret != 0) { + ps3stor_cli_printf("Unable to config event delay ret %d\n", ret); + goto l_out; + } else { + ps3stor_cli_printf("Config event delay %d success\n", delay_seconds); + } + } + +l_out: + return; +} + +static void ps3_cli_crashdump_set(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + U32 delay_seconds = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args for crashdump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for event_subscribe_dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for event_subscribe_dump cmd!\n", + host_no); + goto l_out; + } + + if (strcmp(argv[3], "wait") == 0) { + ret = kstrtouint(argv[4], 0, &delay_seconds); + if (ret != 0) { + ps3stor_cli_printf("Can not parse delay seconds for event delay cmd!\n"); + goto l_out; + } + + if (delay_seconds < WAIT_DUMP_TIMES_MIN) { + ps3stor_cli_printf("min %d!\n", WAIT_DUMP_TIMES_MIN); + delay_seconds = WAIT_DUMP_TIMES_MIN; + } else if (delay_seconds > WAIT_DUMP_TIMES_MAX) { + ps3stor_cli_printf("max %d!\n", WAIT_DUMP_TIMES_MAX); + delay_seconds = WAIT_DUMP_TIMES_MAX; + } + + instance->dump_context.dump_dma_wait_times = delay_seconds; + ps3stor_cli_printf("set crashdump dma wait times %d success\n", delay_seconds); + } + +l_out: + return; +} + +S32 ps3_dump_context_show(const char *prefix, struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dump_context *ctxt = &instance->dump_context; + + ps3stor_cli_printf("%sdump_type : %d \n", prefix, ctxt->dump_type); + ps3stor_cli_printf("%sdump_state : %d \n", prefix,ctxt->dump_state); + ps3stor_cli_printf("%sdump_work_status : %d \n", prefix,ctxt->dump_work_status); + ps3stor_cli_printf("%sdump_env : %d \n", prefix,ctxt->dump_env); + ps3stor_cli_printf("%sdump_dma_vaddr : %p \n", prefix, ctxt->dump_dma_buf); + ps3stor_cli_printf("%sdump_dma_paddr : %llx \n", prefix, ctxt->dump_dma_addr); + ps3stor_cli_printf("%sdump_dma_buff_size : %#x \n", prefix, PS3_DUMP_DMA_BUF_SIZE); + ps3stor_cli_printf("%sdump_dma_wait_times : %#x \n", prefix, ctxt->dump_dma_wait_times); + ps3stor_cli_printf("%sdump_data_size : %llu \n", prefix,ctxt->dump_data_size); + ps3stor_cli_printf("%sdump_data_size_copyed: %llu \n", prefix, ctxt->copyed_data_size); + ps3stor_cli_printf("%sdump_dir : %s \n", prefix,ctxt->dump_dir); + ps3stor_cli_printf("%sdump_file : %s \n", prefix,ctxt->dump_out_file.filename); + ps3stor_cli_printf("%sdump_file_type : %d \n", prefix,ctxt->dump_out_file.type); + ps3stor_cli_printf("%sdump_file_size : %llu\n", prefix,ctxt->dump_out_file.file_size); + ps3stor_cli_printf("%sdump_file_write_cnt : %llu\n", prefix,ctxt->dump_out_file.file_w_cnt); + ps3stor_cli_printf("%sdump_file_status : %d\n", prefix,ctxt->dump_out_file.file_status); + ps3stor_cli_printf("%sdump_file_fp : %p\n", prefix,ctxt->dump_out_file.fp); + if (ctxt->dump_pending_cmd) { + ps3stor_cli_printf("%sdump_pending_cmd : [trace_id:0x%llx][CFID:%d]\n", prefix, + ctxt->dump_pending_cmd->trace_id, ctxt->dump_pending_cmd->cmd_word.cmdFrameID); + } + ps3stor_cli_printf("%sdump_notify_reg_times: %d\n", prefix,ctxt->dump_pending_send_times); + ps3stor_cli_printf("%sdump_type_times : %d\n", prefix,ctxt->dump_type_times); + ps3stor_cli_printf("%sdump_state_times : %d\n", prefix,ctxt->dump_state_times); + + return ret; +} + +static void ps3_host_info_detail_dump(void) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + struct Scsi_Host *phost = NULL; + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + phost = instance->host; + ps3stor_cli_printf("host_no:%d scsi_host detail info\n", phost->host_no); + ps3stor_cli_printf(" host_failed %d\n", phost->host_failed); + ps3stor_cli_printf(" host_eh_scheduled %d\n", phost->host_eh_scheduled); + ps3stor_cli_printf(" host_no %d\n", phost->host_no); + ps3stor_cli_printf(" eh_deadline %d\n", phost->eh_deadline); + ps3stor_cli_printf(" last_reset %ul\n", phost->last_reset); + ps3stor_cli_printf(" max_id %d\n", phost->max_id); + ps3stor_cli_printf(" max_lun %d\n", phost->max_lun); + ps3stor_cli_printf(" max_channel %d\n", phost->max_channel); + ps3stor_cli_printf(" unique_id %d\n", phost->unique_id); + ps3stor_cli_printf(" max_cmd_len %d\n", phost->max_cmd_len); + ps3stor_cli_printf(" can_queue %d\n", phost->can_queue); + ps3stor_cli_printf(" cmd_per_lun %d\n", phost->cmd_per_lun); + ps3stor_cli_printf(" sg_tablesize %d\n", phost->sg_tablesize); + ps3stor_cli_printf(" sg_prot_tablesize %d\n", phost->sg_prot_tablesize); + ps3stor_cli_printf(" max_sectors %d\n", phost->max_sectors); + ps3stor_cli_printf(" dma_boundary 0x%x\n", phost->dma_boundary); + + switch (phost->shost_state) + { + case SHOST_CREATED: + ps3stor_cli_printf(" shost_state SHOST_CREATED\n"); + break; + case SHOST_RUNNING: + ps3stor_cli_printf(" shost_state SHOST_RUNNING\n"); + break; + case SHOST_CANCEL: + ps3stor_cli_printf(" shost_state SHOST_CANCEL\n"); + break; + case SHOST_DEL: + ps3stor_cli_printf(" shost_state SHOST_DEL\n"); + break; + case SHOST_RECOVERY: + ps3stor_cli_printf(" shost_state SHOST_RECOVERY\n"); + break; + case SHOST_CANCEL_RECOVERY: + ps3stor_cli_printf(" shost_state SHOST_CANCEL_RECOVERY\n"); + break; + case SHOST_DEL_RECOVERY: + ps3stor_cli_printf(" shost_state SHOST_DEL_RECOVERY\n"); + break; + default: + break; + } + ps3stor_cli_printf("\n"); + } +} + +static void ps3_cmd_context_detail_dump(const char *format_space, + struct ps3_cmd_context *cmd_context) +{ + U32 i = 0; + ps3stor_cli_printf("%smax_cmd_count:%d\n", + format_space, cmd_context->max_cmd_count); + ps3stor_cli_printf("%smax_scsi_cmd_count:%d\n", + format_space, cmd_context->max_scsi_cmd_count); + ps3stor_cli_printf("%smax_mgr_cmd_count:%d\n", + format_space, cmd_context->max_mgr_cmd_count); + ps3stor_cli_printf("%sreq_frame_buf_phys:0x%llx\n", + format_space, cmd_context->req_frame_buf_phys); + ps3stor_cli_printf("%sresponse_frame_buf_phys:0x%llx\n", + format_space, cmd_context->response_frame_buf_phys); + ps3stor_cli_printf("%sinit_frame_buf_phys:0x%llx\n", + format_space, cmd_context->init_frame_buf_phys); + ps3stor_cli_printf("%sinit_frame_sys_info_phys:0x%llx\n", + format_space, cmd_context->init_frame_sys_info_phys); + ps3stor_cli_printf("%s sgl_mode_support: %u\n", + format_space, cmd_context->sgl_mode_support); + + if (cmd_context->cmd_buf == NULL) { + goto l_out; + } + for (i = cmd_context->max_scsi_cmd_count; + i < cmd_context->max_cmd_count; i++) { + if (cmd_context->cmd_buf[i]->cmd_state.state == PS3_CMD_STATE_INIT) { + continue; + } + ps3stor_cli_printf("%s pending cmd mgr : [trace_id:0x%llx][CFID:%d][type:%d]" + "[isrSN:%d][%s]\n", + format_space, + cmd_context->cmd_buf[i]->trace_id, + cmd_context->cmd_buf[i]->cmd_word.cmdFrameID, + cmd_context->cmd_buf[i]->cmd_word.type, + cmd_context->cmd_buf[i]->cmd_word.isrSN, + namePS3CmdState(cmd_context->cmd_buf[i]->cmd_state.state)); + } + for (i = 0; i < cmd_context->max_scsi_cmd_count; i++) { + if (cmd_context->cmd_buf[i]->cmd_state.state == PS3_CMD_STATE_INIT) { + continue; + } + ps3stor_cli_printf("%s pending cmd scsi: [trace_id:0x%llx][CFID:%d][type:%d]" + "[isrSN:%d][%s]\n", + format_space, + cmd_context->cmd_buf[i]->trace_id, + cmd_context->cmd_buf[i]->cmd_word.cmdFrameID, + cmd_context->cmd_buf[i]->cmd_word.type, + cmd_context->cmd_buf[i]->cmd_word.isrSN, + namePS3CmdState(cmd_context->cmd_buf[i]->cmd_state.state)); + } +l_out: + ps3stor_cli_printf("\n"); +} + +static void ps3_irq_context_detail_dump(const char *format_space, + struct ps3_irq_context *irq_context) +{ + U32 i = 0; + + ps3stor_cli_printf("%sreply_fifo_depth:%d\n", + format_space, irq_context->reply_fifo_depth); + ps3stor_cli_printf("%svalid_msix_vector_count:%d\n", + format_space, irq_context->valid_msix_vector_count); + ps3stor_cli_printf("%shigh_iops_msix_vectors:%d\n", + format_space, irq_context->high_iops_msix_vectors); + ps3stor_cli_printf("%sreply_fifo_desc_buf_phys:0x%llx\n", + format_space, irq_context->reply_fifo_desc_buf_phys); + for (i = 0; i < irq_context->valid_msix_vector_count; i++) { + ps3stor_cli_printf("%sreply_fifo_phys_base_addr_buf[%d]:0x%llx\n", + format_space, i, + irq_context->reply_fifo_phys_base_addr_buf[i]); + } + + for (i = 0; (S32)i < irq_context->cpu_msix_table_sz - 1; i++) { + if (irq_context->cpu_msix_table == NULL) { + break; + } + ps3stor_cli_printf("%scpu_msix_table[%d]:0x%llx\n", + format_space, i, irq_context->cpu_msix_table[i]); + } + + ps3stor_cli_printf("%shigh_iops_io_count:%d\n", + format_space, irq_context->high_iops_io_count.counter); + ps3stor_cli_printf("%sis_enable_interrupts:%s\n", + format_space, + irq_context->is_enable_interrupts ? "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sis_support_balance:%s\n", + format_space, + irq_context->is_support_balance ? "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sis_balance_current_perf_mode:%s\n", + format_space, + irq_context->is_balance_current_perf_mode ? + "PS3_TRUE" : "PS3_FALSE"); + switch (irq_context->pci_irq_type) { + case PS3_PCI_IRQ_LEGACY: + ps3stor_cli_printf("%spci_irq_type:PS3_PCI_IRQ_LEGACY\n", format_space); + break; + case PS3_PCI_IRQ_MSI: + ps3stor_cli_printf("%spci_irq_type:PS3_PCI_IRQ_MSI\n", format_space); + break; + case PS3_PCI_IRQ_MSIX: + ps3stor_cli_printf("%spci_irq_type:PS3_PCI_IRQ_MSIX\n", format_space); + break; + default: + break; + } + ps3stor_cli_printf("\n"); +} + +static void ps3_dev_context_detail_dump(const char *format_space, + struct ps3_dev_context *dev_context) +{ + ps3stor_cli_printf("%svd_table_idx:%d\n", format_space, dev_context->vd_table_idx); + ps3stor_cli_printf("%spd_channel_count:%d\n", + format_space, dev_context->pd_channel_count); + ps3stor_cli_printf("%svd_channel_count:%d\n", + format_space, dev_context->vd_channel_count); + ps3stor_cli_printf("%stotal_vd_count:%d\n", + format_space, dev_context->total_vd_count); + ps3stor_cli_printf("%stotal_pd_count:%d\n", + format_space, dev_context->total_pd_count); + ps3stor_cli_printf("%smax_dev_per_channel:%d\n", + format_space, dev_context->max_dev_per_channel); + ps3stor_cli_printf("%spd_list_buf_phys:0x%llx\n", + format_space, dev_context->pd_list_buf_phys); + ps3stor_cli_printf("%svd_list_buf_phys:0x%llx\n", + format_space, dev_context->vd_list_buf_phys); + ps3stor_cli_printf("%spd_info_buf_phys:0x%llx\n", + format_space, dev_context->pd_info_buf_phys); + ps3stor_cli_printf("%svd_info_buf_phys_sync:0x%llx\n", + format_space, dev_context->vd_info_buf_phys_sync); + ps3stor_cli_printf("%svd_info_buf_phys_async:0x%llx\n", + format_space, dev_context->vd_info_buf_phys_async); + ps3stor_cli_printf("\n"); +} + +static void ps3_event_context_detail_dump(const char *format_space, + struct ps3_event_context *event_context) +{ + if (event_context->delay_work) { + ps3stor_cli_printf("%sevent_delay:%d\n", + format_space, event_context->delay_work->event_delay); + } + ps3stor_cli_printf("\n"); +} + +static void ps3_fault_context_detail_dump(const char *format_space, + struct ps3_fault_context *fault_context) +{ + ps3stor_cli_printf("%sioc_busy:%d\n", + format_space, fault_context->ioc_busy); + ps3stor_cli_printf("%slast_time:%d\n", + format_space, fault_context->last_time); + ps3stor_cli_printf("\n"); +} + +static void ps3_ioc_ctrl_info_detail_dump(const char *format_space, + struct PS3IocCtrlInfo *ctrl_info) +{ + size_t i = 0; + ps3stor_cli_printf("%smaxVdCount:%d\n", + format_space, ctrl_info->maxVdCount); + ps3stor_cli_printf("%smaxPdCount:%d\n", + format_space, ctrl_info->maxPdCount); + ps3stor_cli_printf("%smaxSectors:%d\n", + format_space, ctrl_info->maxSectors); + ps3stor_cli_printf("%sPS3IocCtrlProp.enableSnapshot:%s\n", + format_space, + ctrl_info->properties.enableSnapshot ? "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlProp.enableSoftReset:%s\n", + format_space, + ctrl_info->properties.enableSoftReset ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportUnevenSpans:%s\n", + format_space, + ctrl_info->capabilities.supportUnevenSpans ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportJbodSecure:%s\n", + format_space, + ctrl_info->capabilities.supportJbodSecure ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportNvmePassthru:%s\n", + format_space, + ctrl_info->capabilities.supportNvmePassthru ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportDirectCmd:%s\n", + format_space, + ctrl_info->capabilities.supportDirectCmd ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportSataDirectCmd:%s\n", + format_space, + ctrl_info->capabilities.supportSataDirectCmd ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportSataNcq:%s\n", + format_space, + ctrl_info->capabilities.supportSataNcq ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sPS3IocCtrlCapable.supportAcceleration:%s\n", + format_space, + ctrl_info->capabilities.supportAcceleration ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%sscsiTaskAbortTimeout:%d\n", + format_space, ctrl_info->scsiTaskAbortTimeout); + ps3stor_cli_printf("%sscsiTaskResetTimeout:%d\n", + format_space, ctrl_info->scsiTaskResetTimeout); + ps3stor_cli_printf("%siocPerfMode:%d\n", + format_space, ctrl_info->iocPerfMode); + ps3stor_cli_printf("%svdQueueNum:%d\n", + format_space, ctrl_info->vdQueueNum); + ps3stor_cli_printf("%scancelTimeOut:%d\n", + format_space, ctrl_info->cancelTimeOut); + ps3stor_cli_printf("%schannelInfo channelNum:%d\n", + format_space, ctrl_info->channelInfo.channelNum); + for (i = 0; i < ctrl_info->channelInfo.channelNum; i++) { + ps3stor_cli_printf("%s channels[%d].channelType:%d\n", + format_space, i, + ctrl_info->channelInfo.channels[i].channelType); + ps3stor_cli_printf("%s channels[%d].maxDevNum:%d\n", + format_space, i, + ctrl_info->channelInfo.channels[i].maxDevNum); + } + + ps3stor_cli_printf("\n"); +} + +static void ps3_cmd_attr_context_detail_dump(const char *format_space, + struct ps3_cmd_attr_context *cmd_attr) +{ + ps3stor_cli_printf("%sthrottle_que_depth:%d\n", + format_space, cmd_attr->throttle_que_depth); + ps3stor_cli_printf("%scur_can_que:%d\n", + format_space, cmd_attr->cur_can_que); + ps3stor_cli_printf("%svd_io_threshold:%d\n", + format_space, cmd_attr->vd_io_threshold); + ps3stor_cli_printf("%sis_support_direct_cmd:%s\n", + format_space, cmd_attr->is_support_direct_cmd ? + "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf("%snvme_page_size:%d\n", + format_space, cmd_attr->nvme_page_size); + + ps3stor_cli_printf("\n"); +} + +static void ps3_instance_info_detail_dump(void) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + struct Scsi_Host *phost = NULL; + S32 instance_state = 0; + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + phost = instance->host; + instance_state = atomic_read(&instance->state_machine.state); + ps3stor_cli_printf("host_no:%d instance detail info\n", phost->host_no); + ps3stor_cli_printf(" %s\n", namePS3InstanceState(instance_state)); + ps3stor_cli_printf(" reg_bar:0x%x\n", instance->reg_bar); + ps3stor_cli_printf(" is_load:%s\n", + instance->state_machine.is_load ? "PS3_TRUE" : "PS3_FALSE"); + ps3stor_cli_printf(" is_support_sync_cache:%s\n", + instance->is_support_sync_cache ? "PS3_TRUE" : "PS3_FALSE"); + + ps3stor_cli_printf(" ps3_cmd_context detail info dump\n"); + ps3_cmd_context_detail_dump(" ", &instance->cmd_context); + + ps3stor_cli_printf(" ps3_irq_context detail info dump\n"); + ps3_irq_context_detail_dump(" ", &instance->irq_context); + + ps3stor_cli_printf(" ps3_dev_context detail info dump\n"); + ps3_dev_context_detail_dump(" ", &instance->dev_context); + + ps3stor_cli_printf(" ps3_event_context detail info dump\n"); + ps3_event_context_detail_dump(" ", &instance->event_context); + + ps3stor_cli_printf(" ps3_fault_context detail info dump\n"); + ps3_fault_context_detail_dump(" ", &instance->fault_context); + + ps3stor_cli_printf(" PS3IocCtrlInfo detail info dump\n"); + ps3_ioc_ctrl_info_detail_dump(" ", + &instance->ctrl_info); + + ps3stor_cli_printf(" ps3_cmd_attr_context detail info dump\n"); + ps3_cmd_attr_context_detail_dump(" ", + &instance->cmd_attr); + + ps3stor_cli_printf(" ps3_dump_context detail info dump\n"); + ps3_dump_context_show(" ", instance); + } +} + +static void ps3_cli_host_and_instance_ls(int argc, char *argv[]) +{ + if (argc < 2) { + ps3stor_cli_printf("ls host/instance/all\n"); + return ; + } + + ps3_mutex_lock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + if (strcmp(argv[1], "host") == 0) { + ps3_host_info_detail_dump(); + goto l_out; + } + + if (strcmp(argv[1], "instance") == 0) { + ps3_instance_info_detail_dump(); + goto l_out; + } + + if (strcmp(argv[1], "all") == 0) { + ps3_host_info_detail_dump(); + ps3_instance_info_detail_dump(); + goto l_out; + } + +l_out: + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + return ; +} + +static ssize_t ps3_reply_fifo_dump(struct ps3_instance *instance, U16 isr_sn, + char *buf, ssize_t total_len, U16 index, U16 count) +{ + ssize_t len = 0; + struct PS3ReplyWord *fifo = NULL; + U32 i = 0; + struct ps3_irq *irq = NULL; + U16 start_idx = 0; + U16 once_print_cnt = 0; + U16 cnt = 0; + + if (isr_sn >= instance->irq_context.valid_msix_vector_count) { + ps3stor_cli_printf("invalid isr_sn %d (max:%d)\n", isr_sn, + instance->irq_context.valid_msix_vector_count - 1); + return PS3_FAILED; + } + + irq = instance->irq_context.irqs + isr_sn; + if (irq == NULL) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "irq_name: %s\n", + irq->name); + len += snprintf(buf + len, total_len - len, "irqNo: %d\n", + irq->irqNo); + len += snprintf(buf + len, total_len - len, "isrSN: %d\n", + irq->isrSN); + len += snprintf(buf + len, total_len - len, "last_reply_idx: %d\n", + irq->last_reply_idx); + len += snprintf(buf + len, total_len - len, "irq_poll_th: %d\n", + irq->irq_poll_sched_threshold); + len += snprintf(buf + len, total_len - len, "is_sched_irq_poll: %d\n", + irq->is_sched_irq_poll); + len += snprintf(buf + len, total_len - len, "is_enable_irq: %d\n", + irq->is_enable_irq); + + if(index == 0) { + start_idx = irq->last_reply_idx; + } else { + start_idx = index; + } + + if(count == 0){ + once_print_cnt = 100; + } else { + once_print_cnt = count; + } + + while(cnt < once_print_cnt) { + if(i == instance->irq_context.reply_fifo_depth) { + i = 0; + } else { + i = start_idx; + } + for ( ; i < instance->irq_context.reply_fifo_depth; ++i, ++cnt) { + if (total_len - len < 100) { + ps3stor_cli_printf(buf); + memset(buf, 0, total_len); + len = 0; + } + fifo = irq->reply_fifo_virt_base_addr + i; + len += snprintf(buf + len, total_len - len, + "reply_word:index[%u], replyFlags[0x%x], CFID[0x%x], mode[%d], retType[%d] diskType[%d]\n", + i, fifo->retStatus, fifo->cmdFrameID, fifo->mode, fifo->retType, fifo->diskType); + if(cnt >= once_print_cnt) { + break; + } + } + } + ps3stor_cli_printf(buf); + + i = 0; + LOG_DEBUG("reply fifo[%d]", irq->isrSN); + while (i < instance->irq_context.reply_fifo_depth) { + fifo = irq->reply_fifo_virt_base_addr + i; + LOG_DEBUG("reply_word:index[%u], replyFlags[0x%x], CFID[0x%x] mode[%d] retType[%d] diskType[%d]\n", + i, fifo->retStatus, fifo->cmdFrameID, fifo->mode, fifo->retType, fifo->diskType); + ++i; + } + +l_out: + return len; +} + +static void ps3_cli_reply_fifo_dump(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + char *buf = NULL; + U16 host_no = 0; + U16 isr_sn = 0; + S32 ret = 0; + U16 start_idx = 0; + U16 count = 0; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_malloc_failed; + } + + if (argc < 5) { + ps3stor_cli_printf("Too few args, must input 5 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + if (strcmp(argv[3], "isr_sn") != 0) { + ps3stor_cli_printf("isr_sn is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[4], 0, &isr_sn); + if (ret != 0) { + ps3stor_cli_printf("Can not parse isr_sn!\n"); + goto l_out; + } + + if (isr_sn >= PS3_MAX_REPLY_QUE_COUNT) { + ps3stor_cli_printf("Invalid isr_sn %d, max isr_sn %d!\n", + isr_sn, PS3_MAX_REPLY_QUE_COUNT); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + if(argc == 7) { + if (strcmp(argv[5], "start_idx") == 0) { + ret = kstrtou16(argv[6], 0, &start_idx); + if (ret != 0) { + ps3stor_cli_printf("Can not parse start_idx!\n"); + goto l_out; + } + } else if (strcmp(argv[5], "count") == 0) { + ret = kstrtou16(argv[6], 0, &count); + if (ret != 0) { + ps3stor_cli_printf("Can not parse count!\n"); + goto l_out; + } + } + } else if (argc == 9) { + if (strcmp(argv[5], "start_idx") == 0) { + ret = kstrtou16(argv[6], 0, &start_idx); + if (ret != 0) { + ps3stor_cli_printf("Can not parse start_idx!\n"); + goto l_out; + } + } + if (strcmp(argv[7], "count") == 0) { + ret = kstrtou16(argv[8], 0, &count); + if (ret != 0) { + ps3stor_cli_printf("Can not parse count!\n"); + goto l_out; + } + } + } + + (void)ps3_reply_fifo_dump(instance, isr_sn, buf, PAGE_SIZE, start_idx, count); + +l_out: + kfree(buf); +l_malloc_failed: + return; +} + +static ssize_t ps3_req_head_dump(struct PS3ReqFrameHead *head, + char *buf, ssize_t total_len, size_t len) +{ + len += snprintf(buf + len, total_len - len, + "cmdType: %d\n", head->cmdType); + len += snprintf(buf + len, total_len - len, + "cmdSubType: %d\n", head->cmdSubType); + len += snprintf(buf + len, total_len - len, + "cmdFrameID: %d\n", head->cmdFrameID); + len += snprintf(buf + len, total_len - len, + "control: 0x%x\n", head->control); + len += snprintf(buf + len, total_len - len, + "noReplyWord: 0x%x\n", head->noReplyWord); + len += snprintf(buf + len, total_len - len, + "dataFormat: 0x%x\n", head->dataFormat); + len += snprintf(buf + len, total_len - len, + "reqFrameFormat: 0x%x\n", head->reqFrameFormat); + len += snprintf(buf + len, total_len - len, + "mapBlockVer: 0x%x\n", head->mapBlockVer); + len += snprintf(buf + len, total_len - len, + "isWrite: 0x%x\n", head->isWrite); + len += snprintf(buf + len, total_len - len, + "devID: 0x%x\n", head->devID.diskID); + len += snprintf(buf + len, total_len - len, + "traceID: %lld\n", head->traceID); + return len; +} + +static ssize_t ps3_mgr_req_frame_dump(struct ps3_cmd *cmd, + char *buf, ssize_t total_len, size_t len) +{ + PS3MgrReqFrame_s *mgr_req = (PS3MgrReqFrame_s*)cmd->req_frame; + if (mgr_req->reqHead.cmdType == PS3_CMD_MANAGEMENT || + mgr_req->reqHead.cmdType == PS3_CMD_IOCTL) { + len = ps3_req_head_dump(&mgr_req->reqHead, buf, + total_len, len); + len += snprintf(buf + len, total_len - len, + "sgeCount: %d\n", mgr_req->sgeCount); + len += snprintf(buf + len, total_len - len, + "sgeOffset: %d\n", mgr_req->sgeOffset); + len += snprintf(buf + len, total_len - len, + "syncFlag: %d\n", mgr_req->syncFlag); + len += snprintf(buf + len, total_len - len, + "timeout: %d\n", mgr_req->timeout); + len += snprintf(buf + len, total_len - len, + "abortFlag: %d\n", mgr_req->abortFlag); + len += snprintf(buf + len, total_len - len, + "pendingFlag: %d\n", mgr_req->pendingFlag); + } else if (mgr_req->reqHead.cmdType == PS3_CMD_SCSI_TASK_MANAGEMENT){ + PS3MgrTaskReqFrame_s *task_req = + (PS3MgrTaskReqFrame_s*)cmd->req_frame; + len = ps3_req_head_dump(&task_req->reqHead, buf, + total_len, len); + len += snprintf(buf + len, total_len - len, + "taskID: %d\n", task_req->taskID); + len += snprintf(buf + len, total_len - len, + "abortedCmdType: %d\n", task_req->abortedCmdType); + } else { + PS3FrontEndReqFrame_s *fe_req = + (PS3FrontEndReqFrame_s*)cmd->req_frame; + len = ps3_req_head_dump(&fe_req->reqHead, buf, + total_len, len); + len += snprintf(buf + len, total_len - len, + "sgeCount: %d\n", fe_req->sgeCount); + } + return len; +} + +static ssize_t ps3_req_frame_dump(struct ps3_cmd *cmd, + char *buf, ssize_t total_len, size_t len) +{ + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type)) { + if (cmd->req_frame->mgrReq.reqHead.reqFrameFormat == PS3_REQFRAME_FORMAT_FRONTEND) { + PS3FrontEndReqFrame_s *fe_req = + (PS3FrontEndReqFrame_s*)cmd->req_frame; + len = ps3_req_head_dump(&fe_req->reqHead, buf, + total_len, len); + len += snprintf(buf + len, total_len - len, + "dataXferLen: %d\n", fe_req->dataXferLen); + len += snprintf(buf + len, total_len - len, + "sgeCount: %d\n", fe_req->sgeCount); + } else { + PS3HwReqFrame_s *hw_req = + (PS3HwReqFrame_s*)cmd->req_frame; + len += snprintf(buf + len, total_len - len, + "traceID: %llu\n", hw_req->reqHead.traceID); + len += snprintf(buf + len, total_len - len, + "vlba: 0x%llx\n", + hw_req->softwareZone.virtDiskLba); + len += snprintf(buf + len, total_len - len, + "numBlocks: 0x%u\n", + hw_req->softwareZone.numBlocks); + len += snprintf(buf + len, total_len - len, + "opcode: 0x%u\n", + hw_req->softwareZone.opcode); + len += snprintf(buf + len, total_len - len, + "sglOffset: 0x%u\n", + hw_req->softwareZone.sglOffset); + len += snprintf(buf + len, total_len - len, + "sglFormat: 0x%u\n", + hw_req->softwareZone.sglFormat); + len += snprintf(buf + len, total_len - len, + "isResendCmd: 0x%u\n", + hw_req->softwareZone.isResendCmd); + len += snprintf(buf + len, total_len - len, + "subOpcode: 0x%u\n", + hw_req->softwareZone.subOpcode); + len += snprintf(buf + len, total_len - len, + "sgeCount: 0x%u\n", + hw_req->softwareZone.sgeCount); + } + } else if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR){ + len = ps3_mgr_req_frame_dump(cmd, buf, total_len, len); + } else { + len += snprintf(buf + len, total_len - len, + "req frame is null\n"); + } + + return len; +} + +static ssize_t ps3_cmd_dump(struct ps3_instance *instance, U16 CFID, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + struct ps3_cmd *cmd = NULL; + + cmd = (struct ps3_cmd*)instance->cmd_context.cmd_buf[CFID]; + if (cmd == NULL) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "----dump ps3_cmd----\n"); + len += snprintf(buf + len, total_len - len, "cmdFrameID: %d\n", + CFID); + len += snprintf(buf + len, total_len - len, "trace_id: %lld\n", + cmd->trace_id); + len += snprintf(buf + len, total_len - len, "no_reply_word: %d\n", + cmd->no_reply_word); + len += snprintf(buf + len, total_len - len, "is_retry_cmd: %d\n", + cmd->io_attr.is_retry_cmd); + len += snprintf(buf + len, total_len - len, "direct_flag: %d\n", + cmd->io_attr.direct_flag); + len += snprintf(buf + len, total_len - len, "dev_type: %s\n", + namePS3DevType((enum PS3DevType)cmd->io_attr.dev_type)); + len += snprintf(buf + len, total_len - len, "rw_flag: %d\n", + cmd->io_attr.rw_flag); + + len += snprintf(buf + len, total_len - len, "------cmd_word------\n"); + len += snprintf(buf + len, total_len - len, "type: %d\n", + cmd->cmd_word.type); + len += snprintf(buf + len, total_len - len, "direct: %d\n", + cmd->cmd_word.direct); + len += snprintf(buf + len, total_len - len, "isrSN: %d\n", + cmd->cmd_word.isrSN); + len += snprintf(buf + len, total_len - len, "phyDiskID: %d\n", + cmd->cmd_word.phyDiskID); + len += snprintf(buf + len, total_len - len, "queID: %d\n", + cmd->cmd_word.qMask); + len += snprintf(buf + len, total_len - len, "cmdFrameID: %d\n", + cmd->cmd_word.cmdFrameID); + len += snprintf(buf + len, total_len - len, "virtDiskID: %d\n", + cmd->cmd_word.virtDiskID); + + len += snprintf(buf + len, total_len - len, "------req_frame------\n"); + if (cmd->cmd_word.cmdFrameID == 0) { + len += snprintf(buf + len, total_len - len, "--cmd is null--\n"); + goto l_out; + } + + len = ps3_req_frame_dump(cmd, buf, total_len, len); + +l_out: + return len; +} + +static void ps3_cli_cmd_dump(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + char *buf = NULL; + U16 host_no = 0; + U16 cmdFrameID = 0; + S32 ret = 0; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_malloc_failed; + } + + if (argc < 5) { + ps3stor_cli_printf("Too few args, must input 5 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + if (strcmp(argv[3], "cmd_frame_id") != 0) { + ps3stor_cli_printf("cmd_frame_id is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[4], 0, &cmdFrameID); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + if (cmdFrameID >= instance->cmd_context.max_cmd_count) { + ps3stor_cli_printf("Invalid cmd_frame_id %d, max id %d!\n", + cmdFrameID, instance->cmd_context.max_cmd_count); + goto l_out; + } + + (void)ps3_cmd_dump(instance, cmdFrameID, buf, PAGE_SIZE); + ps3stor_cli_printf(buf); + +l_out: + kfree(buf); +l_malloc_failed: + return; +} + +static ssize_t ps3_io_statis_to_str(struct ps3_dev_io_statis *disk_io_statis, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + const U32 temp_array_len = 256; + char temp[256] = {0}; + ssize_t temp_len = 0; + + (void)disk_io_statis; + (void)buf; + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "readSendCnt", + (U64)atomic64_read(&disk_io_statis->read_send_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "readSendCnt", + (U64)atomic64_read(&disk_io_statis->read_send_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "readSendOkCnt", + (U64)atomic64_read(&disk_io_statis->read_send_ok_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "readSendOkCnt", + (U64)atomic64_read(&disk_io_statis->read_send_ok_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "readOutStandCnt", + (U64)atomic64_read(&disk_io_statis->read_send_wait_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "readOutStandCnt", + (U64)atomic64_read(&disk_io_statis->read_send_wait_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "readRecvCnt", + (U64)atomic64_read(&disk_io_statis->read_recv_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "readRecvCnt", + (U64)atomic64_read(&disk_io_statis->read_recv_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "readRecvOkCnt", + (U64)atomic64_read(&disk_io_statis->read_recv_ok_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "readRecvOkCnt", + (U64)atomic64_read(&disk_io_statis->read_recv_ok_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "readOkBytes", + (U64)atomic64_read(&disk_io_statis->read_ok_bytes)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "readOkBytes", + (U64)atomic64_read(&disk_io_statis->read_ok_bytes)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "writeSendCnt", + (U64)atomic64_read(&disk_io_statis->write_send_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "writeSendCnt", + (U64)atomic64_read(&disk_io_statis->write_send_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "writeSendOkCnt", + (U64)atomic64_read(&disk_io_statis->write_send_ok_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "writeSendOkCnt", + (U64)atomic64_read(&disk_io_statis->write_send_ok_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "writeOutStandCnt", + (U64)atomic64_read(&disk_io_statis->write_send_wait_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "writeOutStandCnt", + (U64)atomic64_read(&disk_io_statis->write_send_wait_cnt)); + + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "writeRecvCnt", + (U64)atomic64_read(&disk_io_statis->write_recv_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "writeRecvCnt", + (U64)atomic64_read(&disk_io_statis->write_recv_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n", "writeRecvOkCnt", + (U64)atomic64_read(&disk_io_statis->write_recv_ok_cnt)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n", "writeRecvOkCnt", + (U64)atomic64_read(&disk_io_statis->write_recv_ok_cnt)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%llu\n\n", "writeOkBytes", + (U64)atomic64_read(&disk_io_statis->write_ok_bytes)); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%llu\n\n", "writeOkBytes", + (U64)atomic64_read(&disk_io_statis->write_ok_bytes)); + +l_out: + return len; +} + +static ssize_t ps3_io_statis_detail_dump(struct ps3_instance *instance, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + struct scsi_device *sdev = NULL; + struct ps3_scsi_priv_data *scsi_priv = NULL; + struct ps3_dev_io_statis disk_io_statis; + U32 i = 0; + const U32 temp_array_len = 256; + char temp[256] = {0}; + ssize_t temp_len = 0; + U8 dev_type = 0; + + if (!instance || !buf || total_len <= 0) { + ps3stor_cli_printf("invalid parameters"); + return 0; + } + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%s\n", "disk io statistics detail:"); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%s\n", "disk io statistics detail:"); + + list_for_each_entry(sdev, &instance->host->__devices, siblings) { + if (scsi_device_get(sdev)) + continue; + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + scsi_priv = (struct ps3_scsi_priv_data*)sdev->hostdata; + if (scsi_priv == NULL) { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + scsi_device_put(sdev); + continue; + } + + memset(&disk_io_statis, 0, sizeof(struct ps3_dev_io_statis)); + memcpy(&disk_io_statis, &scsi_priv->statis, sizeof(struct ps3_dev_io_statis)); + dev_type = scsi_priv->dev_type; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%d\n", "index", i); + if ((len + temp_len) > total_len) { + scsi_device_put(sdev); + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%d\n", "index", i); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:[%d,%d]\n", "diskId", + sdev->channel, sdev->id); + if ((len + temp_len) > total_len) { + scsi_device_put(sdev); + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:[%d,%d]\n", "diskId", + sdev->channel, sdev->id); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%s\n", "diskType", + (dev_type == PS3_DEV_TYPE_VD ? "VD" : "PD")); + if ((len + temp_len) > total_len) { + scsi_device_put(sdev); + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%s\n", "diskType", + (dev_type == PS3_DEV_TYPE_VD ? "VD" : "PD")); + + if (len >= total_len) { + scsi_device_put(sdev); + break; + } + len += ps3_io_statis_to_str(&disk_io_statis, buf + len, total_len - len); + + scsi_device_put(sdev); + i++; + } + +l_out: + return len; +} + +static void ps3_io_statis_clear_by_target(struct ps3_instance *instance, + U32 channel, U32 target) +{ + struct scsi_device *sdev = NULL; + + if (!instance) { + ps3stor_cli_printf("invalid parameters"); + return ; + } + + sdev = scsi_device_lookup(instance->host, channel, target, 0); + if (sdev){ + if (sdev->channel == channel && sdev->id == target) { + ps3_io_statis_clear(sdev); + } + + scsi_device_put(sdev); + } +} + +static ssize_t ps3_io_statis_summary_dump(struct ps3_instance *instance, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + struct scsi_device *sdev = NULL; + struct ps3_scsi_priv_data *scsi_priv = NULL; + struct ps3_dev_io_statis disk_io_statis; + struct ps3_dev_io_statis disk_io_statis_total; + U32 pd_cnt = 0, vd_cnt = 0; + const U32 temp_array_len = 256; + char temp[256] = {0}; + ssize_t temp_len = 0; + U8 dev_type = 0; + + if (!instance || !buf || total_len <= 0) { + ps3stor_cli_printf("invalid parameters"); + return 0; + } + + ps3_dev_io_statis_init(&disk_io_statis_total); + list_for_each_entry(sdev, &instance->host->__devices, siblings) { + if (scsi_device_get(sdev)) + continue; + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + scsi_priv = (struct ps3_scsi_priv_data*)sdev->hostdata; + if (scsi_priv == NULL) { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + scsi_device_put(sdev); + continue; + } + memset(&disk_io_statis, 0, sizeof(struct ps3_dev_io_statis)); + memcpy(&disk_io_statis, &scsi_priv->statis, sizeof(struct ps3_dev_io_statis)); + + dev_type = scsi_priv->dev_type; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + + atomic64_add(atomic64_read(&disk_io_statis.read_send_cnt), &disk_io_statis_total.read_send_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_send_ok_cnt), &disk_io_statis_total.read_send_ok_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_send_err_cnt), &disk_io_statis_total.read_send_err_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_send_wait_cnt), &disk_io_statis_total.read_send_wait_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_recv_cnt), &disk_io_statis_total.read_recv_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_recv_err_cnt), &disk_io_statis_total.read_recv_err_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_recv_ok_cnt), &disk_io_statis_total.read_recv_ok_cnt); + atomic64_add(atomic64_read(&disk_io_statis.read_ok_bytes), &disk_io_statis_total.read_ok_bytes); + + atomic64_add(atomic64_read(&disk_io_statis.write_send_cnt), &disk_io_statis_total.write_send_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_send_ok_cnt), &disk_io_statis_total.write_send_ok_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_send_err_cnt), &disk_io_statis_total.write_send_err_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_send_wait_cnt), &disk_io_statis_total.write_send_wait_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_recv_cnt), &disk_io_statis_total.write_recv_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_recv_err_cnt), &disk_io_statis_total.write_recv_err_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_recv_ok_cnt), &disk_io_statis_total.write_recv_ok_cnt); + atomic64_add(atomic64_read(&disk_io_statis.write_ok_bytes), &disk_io_statis_total.write_ok_bytes); + + if (dev_type == PS3_DEV_TYPE_VD) { + vd_cnt++; + } else { + pd_cnt++; + } + + scsi_device_put(sdev); + } + + memcpy(&disk_io_statis, &disk_io_statis_total, sizeof(struct ps3_dev_io_statis)); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%s\n", "disk io statistics summary:"); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%s\n", "disk io statistics summary:"); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%d\n", "VD count", vd_cnt); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%d\n", "VD count", vd_cnt); + + memset(temp, 0, temp_array_len); + temp_len = snprintf(temp, temp_array_len, "%-20s:%d\n", "PD count", pd_cnt); + if ((len + temp_len) > total_len) { + goto l_out; + } + len += snprintf(buf + len, total_len - len, "%-20s:%d\n", "PD count", pd_cnt); + + if (len >= total_len) { + goto l_out; + } + len += ps3_io_statis_to_str(&disk_io_statis, buf, total_len - len); + +l_out: + return len; +} + +void ps3_io_statis_dump_cli_cb_test(U8 detail) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + char *buf = NULL; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_malloc_failed; + } + + if (detail) { + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance) { + (void)ps3_io_statis_detail_dump(instance, buf, PAGE_SIZE); + break; + } + } + } else { + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance) { + (void)ps3_io_statis_summary_dump(instance, buf, PAGE_SIZE); + break; + } + } + } + + ps3stor_cli_printf(buf); + LOG_DEBUG("buf = %s\n",buf); + + kfree(buf); + buf = NULL; + +l_malloc_failed: + return; +} + +static void ps3_io_statis_dump_cli_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + char *buf = NULL; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_malloc_failed; + } + + if (argc < 4) { + ps3stor_cli_printf("Too few args, must input 4 args!\n"); + goto l_out; + } + + if (strcmp(argv[0], "show") != 0) { + ps3stor_cli_printf("invalid arg 0 %s!\n", argv[0]); + goto l_out; + } + + if (strcmp(argv[1], "io") != 0) { + ps3stor_cli_printf("invalid arg 1 %s!\n", argv[1]); + goto l_out; + } + + if (strcmp(argv[2], "statis") != 0) { + ps3stor_cli_printf("invalid arg 2 %s!\n", argv[2]); + goto l_out; + } + + if (strcmp(argv[3], "detail") == 0) { + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance) { + (void)ps3_io_statis_detail_dump(instance, buf, PAGE_SIZE); + break; + } + } + } else { + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance) { + (void)ps3_io_statis_summary_dump(instance, buf, PAGE_SIZE); + break; + } + } + } + + ps3stor_cli_printf(buf); + LOG_INFO("buf: %s\n", buf); + +l_out: + kfree(buf); + buf = NULL; + +l_malloc_failed: + return; +} + +static void ps3_io_statis_clear_cli_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + U32 channel = 0, target = 0; + S32 ret = 0; + + if (argc < 5) { + ps3stor_cli_printf("Too few args, must input 5 args!\n"); + goto l_out; + } + + if (strcmp(argv[0], "clear") != 0) { + ps3stor_cli_printf("invalid arg 0 %s!\n", argv[0]); + goto l_out; + } + + if (strcmp(argv[1], "io") != 0) { + ps3stor_cli_printf("invalid arg 1 %s!\n", argv[1]); + goto l_out; + } + + if (strcmp(argv[2], "statis") != 0) { + ps3stor_cli_printf("invalid arg 2 %s!\n", argv[2]); + goto l_out; + } + + ret = kstrtouint(argv[3], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Invalid channel %s!\n", argv[3]); + goto l_out; + } + ret = kstrtouint(argv[4], 0, &target); + if (ret != 0) { + ps3stor_cli_printf("Invalid target %s!\n", argv[4]); + goto l_out; + } + + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance) { + ps3_io_statis_clear_by_target(instance, channel, target); + ps3stor_cli_printf("clear host %d channel %d target %d io statistics\n", + instance->host->host_no, channel, target); + break; + } + } + +l_out: + return; +} +static ssize_t ps3_hardreset_cnt_show(struct ps3_instance *instance, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + + if (!instance || !buf || total_len <= 0) { + ps3stor_cli_printf("invalid parameters"); + goto l_out; + } + + len += snprintf(buf + len, total_len - len, "%s:%u\n", "hard reset cnt", + instance->recovery_context->hardreset_count); + +l_out: + return len; +} + +static ssize_t ps3_hardreset_cnt_clear(struct ps3_instance *instance, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + if (!instance || !buf || total_len <= 0) { + ps3stor_cli_printf("invalid parameters"); + goto l_out; + } + + instance->recovery_context->hardreset_count = 0; + len += snprintf(buf + len, total_len - len, "%s:%u\n", + "hard reset cnt",instance->recovery_context->hardreset_count); +l_out: + return len; +} + +static void ps3_hardreset_cnt_show_cli_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + char *buf = NULL; + U16 host_no = 0; + S32 ret = 0; + + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_malloc_failed; + } + + if (argc < 3) { + ps3stor_cli_printf("Too few args for register dump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for register dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for register dump cmd!\n", + host_no); + goto l_out; + } + + (void)ps3_hardreset_cnt_show(instance, buf, PAGE_SIZE); + ps3stor_cli_printf(buf); + LOG_INFO("buf: %s\n", buf); + +l_out: + kfree(buf); + buf = NULL; + +l_malloc_failed: + return; +} + +static void ps3_hardreset_cnt_clear_cli_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + char *buf = NULL; + U16 host_no = 0; + S32 ret = 0; + buf = (char*)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_malloc_failed; + } + + if (argc < 3) { + ps3stor_cli_printf("Too few args for register dump cli cmd!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no for register dump cmd!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d for register dump cmd!\n", + host_no); + goto l_out; + } + (void)ps3_hardreset_cnt_clear(instance, buf, PAGE_SIZE); + ps3stor_cli_printf(buf); + LOG_INFO("buf: %s\n", buf); + +l_out: + kfree(buf); + buf = NULL; + +l_malloc_failed: + return; + +} + +static void ps3_cli_stop_all_instance(void) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + struct ps3_cmd *cmd = NULL; + struct scsi_cmnd *s_cmd = NULL; + struct ps3_scsi_priv_data *data = NULL; + U32 index = 0; + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance == NULL) { + continue; + } + + ps3_instance_state_transfer_to_dead(instance); + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + + ps3_r1x_conflict_queue_clean_all(instance, + PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT), PS3_TRUE); +#ifdef PS3_SUPPORT_INJECT + ps3_inject_clear(); +#endif + for (index = 0; index < instance->cmd_context.max_scsi_cmd_count; index++) { + cmd = instance->cmd_context.cmd_buf[index]; + if (cmd->scmd != NULL) { + PS3_IO_OUTSTAND_DEC(instance, cmd->scmd); + PS3_VD_OUTSTAND_DEC(instance, cmd->scmd); + PS3_IO_BACK_ERR_INC(instance, cmd->scmd); + PS3_DEV_BUSY_DEC(cmd->scmd); + cmd->scmd->result = ((S32)PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT)); + s_cmd = cmd->scmd; + ps3_scsi_dma_unmap(cmd); + data = (struct ps3_scsi_priv_data *)cmd->scmd->device->hostdata; + if(likely(data != NULL)){ + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + ps3_scsi_cmd_free(cmd); + SCMD_IO_DONE(s_cmd); + } + } + + for (index = instance->cmd_context.max_scsi_cmd_count; + index < instance->cmd_context.max_cmd_count; index++) { + cmd = instance->cmd_context.cmd_buf[index]; + if (cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NO_REPLY_WORD) { + cmd->resp_frame->normalRespFrame.respStatus = PS3_STATUS_DEVICE_NOT_FOUND; + } else if (cmd->cmd_receive_cb != NULL) { + cmd->resp_frame->normalRespFrame.respStatus = PS3_STATUS_DEVICE_NOT_FOUND; + cmd->cmd_receive_cb(cmd, PS3_REPLY_WORD_FLAG_FAIL); + } + } + + cancel_delayed_work_sync(&instance->event_context.delay_work->event_work); + ps3_watchdog_stop(instance); + + instance->ioc_adpter->irq_enable(instance); + ps3_irqpolls_enable(instance); + + ps3stor_cli_printf("host_no:%d instance stopped!\n", instance->host->host_no); + } +} + +static void ps3_cli_force_to_stop(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + ps3_mutex_lock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + + ps3stor_cli_printf("force_to_stop begain.... !\n"); + ps3_cli_stop_all_instance(); + ps3stor_cli_printf("force_to_stop success !\n"); + + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); +} + +static void ps3_debug_mem_dump(struct ps3_instance *ins, U16 entry, U32 len) +{ + U32 i = 0; + const U32 once_dump_len = 1024; + char buf[256] = { 0 }; + + for (; i < ins->debug_context.debug_mem_vaddr[entry].debugMemSize; ++i) { + if (ins->debug_context.debug_mem_vaddr[entry].debugMemAddr == 0 || len == 0) { + break; + } + memset(buf, '\0', sizeof(buf)); + if (len <= once_dump_len) { + (void)snprintf(buf, sizeof(buf),"base addr[0x%llx] len[%u]\n", + ins->debug_context.debug_mem_vaddr[entry].debugMemAddr + + i * once_dump_len, len); + DATA_DUMP(((U8*)(ins->debug_context.debug_mem_vaddr[entry].debugMemAddr + i * once_dump_len)), + len, buf); + break; + } else { + len -= once_dump_len; + (void)snprintf(buf, sizeof(buf),"base addr[0x%llx] len[%u]\n", + ins->debug_context.debug_mem_vaddr[entry].debugMemAddr + + i * once_dump_len, once_dump_len); + DATA_DUMP(((U8*)(ins->debug_context.debug_mem_vaddr[entry].debugMemAddr + i * once_dump_len)), + once_dump_len, buf); + } + } + return; +} + +static void ps3_debug_mem_write(struct ps3_instance *ins, U16 entry, U32 len) +{ + const U8 l_value = 0x55; + const U8 h_value = 0xaa; + U32 i = 0; + + for (i = 0; i < len; i+=2) { + *((U8*)ins->debug_context.debug_mem_vaddr[entry].debugMemAddr + i) = l_value; + *((U8*)ins->debug_context.debug_mem_vaddr[entry].debugMemAddr + i + 1) = h_value; + } + + return; +} + +static void ps3_debug_mem_rw_cli_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + U16 entry = 0; + U16 dir = 0; + U32 len = 0; + S32 ret = 0; + + if (argc < 9) { + ps3stor_cli_printf("Too few args, must input 9 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + + if (strcmp(argv[3], "entry_index") != 0) { + ps3stor_cli_printf("entry_index is needed!\n"); + goto l_out; + } + ret = kstrtou16(argv[4], 0, &entry); + if (ret != 0) { + ps3stor_cli_printf("Can not parse entry!\n"); + goto l_out; + } + + if (instance->debug_context.debug_mem_array_num == 0) { + ps3stor_cli_printf("host_no %d not support debug mem!\n", host_no); + goto l_out; + } + + if (entry >= instance->debug_context.debug_mem_array_num) { + ps3stor_cli_printf("Invalid entry %u !\n", entry); + goto l_out; + } + + if (strcmp(argv[5], "dir") != 0) { + ps3stor_cli_printf("dir is needed!\n"); + goto l_out; + } + ret = kstrtou16(argv[6], 0, &dir); + if (ret != 0) { + ps3stor_cli_printf("Can not parse entry!\n"); + goto l_out; + } + if (!(dir == 0 || dir == 1)) { + ps3stor_cli_printf("Invalid dir %u, need is 0 or 1 !\n", dir); + goto l_out; + } + + if (strcmp(argv[7], "length") != 0) { + ps3stor_cli_printf("length is needed!\n"); + goto l_out; + } + ret = kstrtouint(argv[8], 0, &len); + if (ret != 0) { + ps3stor_cli_printf("Can not parse entry!\n"); + goto l_out; + } + if (len > (instance->debug_context.debug_mem_vaddr[entry].debugMemSize * 1024)) { + ps3stor_cli_printf("len over mem [%u], max[%u]!\n", len, + instance->debug_context.debug_mem_vaddr[entry].debugMemSize * 1024); + goto l_out; + } + + if (dir == 1) { + ps3_debug_mem_write(instance, entry, len); + } else { + ps3_debug_mem_dump(instance, entry, len); + } + +l_out: + return; +} + +static void ps3_debug_mem_para_dump(struct ps3_instance *instance) +{ + struct ps3_debug_context *cxt = &instance->debug_context; + U32 i = 0; + ps3stor_cli_printf("debug mem array num %u\n", cxt->debug_mem_array_num); + if (cxt->debug_mem_array_num == 0) { + goto l_out; + } + + for (; i < cxt->debug_mem_array_num; ++i) { + ps3stor_cli_printf("entry[%u] vaddr[0x%llx] dma[0x%llx] max_size[%u]KB\n", + i, cxt->debug_mem_vaddr[i].debugMemAddr, + cxt->debug_mem_buf[i].debugMemAddr, + cxt->debug_mem_buf[i].debugMemSize); + } +l_out: + return; +} + +static void ps3_debug_mem_para_cli_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + + if (instance->debug_context.debug_mem_array_num == 0) { + ps3stor_cli_printf("host_no %d not support debug mem!\n", host_no); + goto l_out; + } + + ps3_debug_mem_para_dump(instance); + +l_out: + return; +} + +static void ps3_scsi_device_loop_dump(struct ps3_instance *instance) +{ + struct scsi_device *sdev = NULL; + ULong flags = 0; + struct Scsi_Host *shost = instance->host; + + if (instance->host == NULL) { + goto l_out; + } + + spin_lock_irqsave(shost->host_lock, flags); + list_for_each_entry(sdev, &shost->__devices, siblings) { + if (sdev == NULL) { + continue; + } + ps3stor_cli_printf("channel[%u], id[%u], lun[%llu], state[%d]!\n", + sdev->channel, sdev->id, sdev->lun, sdev->sdev_state); + } + spin_unlock_irqrestore(shost->host_lock, flags); + +l_out: + return; +} + +static void ps3_scsi_device_lookup_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + + ps3_scsi_device_loop_dump(instance); + +l_out: + return; +} + +static void ps3_hard_reset_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + ps3stor_cli_printf("hno:%u entry hard reset !\n", host_no); + + LOG_INFO("hno:%u entry hard reset!\n", + PS3_HOST(instance)); + + LOG_WARN("hno:%u cli call recovery request!\n", + PS3_HOST(instance)); + if ((!PS3_IOC_HARD_RECOVERY_SUPPORT(instance)) + || (!ps3_hard_reset_enable_query())) { + LOG_WARN("hno:%u soc feature unsupport Hard reset! need to be offline!\n", + PS3_HOST(instance)); + goto l_out; + } + if (ps3_need_block_hard_reset_request(instance)) { + LOG_WARN("hno:%u can not start hard reset\n", + PS3_HOST(instance)); + goto l_out; + } + + ps3_hard_recovery_request_with_retry(instance); + LOG_WARN("hno:%u cli call recovery request!\n", + PS3_HOST(instance)); + +l_out: + return; +} + +static void ps3_soc_halt_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = 0; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + + if (PS3_IOC_STATE_HALT_SUPPORT(instance)) { + LOG_WARN("hno:%u cli call trans to halt!\n", + PS3_HOST(instance)); + ps3_instance_state_transfer_to_dead(instance); + instance->ioc_adpter->ioc_force_to_halt(instance); + LOG_WARN("hno:%u cli call trans to halt end!\n", + PS3_HOST(instance)); + } else { + ps3stor_cli_printf("host does not support HALT!\n", host_no); + } + +l_out: + return; +} + +static void ps3_cmd_stat_switch_store(U16 host_no, + U16 switch_flag, U16 mask) +{ + struct ps3_instance *instance = ps3_instance_lookup(host_no); + struct ps3_cmd_stat_wrokq_context *ctx = NULL; + Bool is_inc_switch_open = PS3_FALSE; + + if (instance == NULL) { + ps3stor_cli_printf("invalid host_no %u\n", host_no); + goto l_out; + } + + if ((instance->cmd_statistics.cmd_stat_switch & mask) == + (switch_flag & mask)) { + ps3stor_cli_printf("switch_flag no change 0x%x\n", + instance->cmd_statistics.cmd_stat_switch); + goto l_out; + } + + is_inc_switch_open = ps3_stat_inc_switch_is_open(instance); + + instance->cmd_statistics.cmd_stat_switch &= (~mask) ; + instance->cmd_statistics.cmd_stat_switch |= (switch_flag & mask) ; + + ctx = &instance->cmd_statistics.stat_workq; + if ((ctx->stat_queue != NULL) && (!ctx->is_stop) && + ps3_stat_inc_switch_is_open(instance) && !is_inc_switch_open) { + ps3stor_cli_printf("schedule delay work\n"); + queue_delayed_work(ctx->stat_queue, &ctx->stat_work, + msecs_to_jiffies(instance->cmd_statistics.stat_interval)); + } + + ps3stor_cli_printf("stat switch value is 0x%x\n", + instance->cmd_statistics.cmd_stat_switch); +l_out: + return; +} + +static void ps3_cmd_stat_switch_store_cb(int argc, char *argv[]) +{ + U16 host_no = 0; + U16 switch_flag = 0; + U16 mask = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 7) { + ps3stor_cli_printf("Too few args, must input 7 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + if (strcmp(argv[3], "value") != 0) { + ps3stor_cli_printf("value is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[4], 0, &switch_flag); + if (ret != 0) { + ps3stor_cli_printf("Can not parse value!\n"); + goto l_out; + } + + if (strcmp(argv[5], "mask") != 0) { + ps3stor_cli_printf("mask is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[6], 0, &mask); + if (ret != 0) { + ps3stor_cli_printf("Can not parse mask!\n"); + goto l_out; + } + + ps3_cmd_stat_switch_store(host_no, switch_flag, mask); + +l_out: + return; +} + +static inline void ps3_cmd_stat_switch_show(U16 host_no) +{ + struct ps3_instance *instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("invalid host_no %u\n", host_no); + goto l_out; + } + + ps3stor_cli_printf("[bit0:OUTSTAND_SWITCH_OPEN, bit1:INC_SWITCH_OPEN," + "bit2:LOG_SWITCH_OPEN, bit3:DEV_SWITCH_OPEN]\n"); + ps3stor_cli_printf("stat switch value is 0x%x\n", + instance->cmd_statistics.cmd_stat_switch); + +l_out: + return; +} + +static void ps3_cmd_stat_switch_show_cb(int argc, char *argv[]) +{ + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + ps3_cmd_stat_switch_show(host_no); +l_out: + return; +} + +static void ps3_stat_total_dump(struct ps3_instance *instance, + char *buf, S32 total_len) +{ + S32 len = 0; + const U32 temp_array_len = total_len; + S8 *tmp_buf = NULL; + S32 temp_len = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + U16 i = 0; + + len += snprintf(buf + len, total_len - len, + "----host[%u] total cmd statistics show begin----\n", PS3_HOST(instance)); + len += snprintf(buf + len, total_len - len, + "----cmd_outstandin:%u----\n", + ps3_atomic_read(&instance->cmd_statistics.cmd_outstanding)); + len += snprintf(buf + len, total_len - len, + "%-25s %-15s %-15s %-15s %-15s %-20s %-20s %-20s\n", + " ", "start", "back_good", "back_err", "not_back", "avg(us)", "max(us)", "min(us)"); + + tmp_buf = (S8 *)kzalloc(temp_array_len, GFP_KERNEL); + if (tmp_buf == NULL) { + goto l_out; + } + + for (; i < PS3_QOS_PD_PRO; ++i) { + temp_len = snprintf(tmp_buf, temp_array_len, + "%-25s %-15llu %-15llu %-15llu %-15llu " + "%-20llu %-20llu %-20llu\n", + ps3_cmd_stat_item_tostring((enum ps3_cmd_stat_item)i), + ctx->total_stat.stat[i].start, + ctx->total_stat.stat[i].back_good, + ctx->total_stat.stat[i].back_err, + ctx->total_stat.stat[i].not_back, + ctx->total_stat.stat[i].lagency.avg, + ctx->total_stat.stat[i].lagency.max_lagency, + ctx->total_stat.stat[i].lagency.min_lagency); + if ((len + temp_len) > total_len) { + ps3stor_cli_printf("print over!\n"); + goto l_out; + } + + memset(tmp_buf, 0, temp_array_len); + + len += snprintf(buf + len, total_len - len, + "%-25s %-15llu %-15llu %-15llu %-15llu " + "%-20llu %-20llu %-20llu\n", + ps3_cmd_stat_item_tostring((enum ps3_cmd_stat_item)i), + ctx->total_stat.stat[i].start, + ctx->total_stat.stat[i].back_good, + ctx->total_stat.stat[i].back_err, + ctx->total_stat.stat[i].not_back, + ctx->total_stat.stat[i].lagency.avg, + ctx->total_stat.stat[i].lagency.max_lagency, + ctx->total_stat.stat[i].lagency.min_lagency); + } + + temp_len = snprintf(tmp_buf, temp_array_len, + "----host[%u] cmd statistics show end----\n", PS3_HOST(instance)); + if ((len + temp_len) > total_len) { + ps3stor_cli_printf("print over!\n"); + goto l_out; + } + + len += snprintf(buf + len, total_len - len, + "----host[%u] cmd statistics show end----\n", PS3_HOST(instance)); +l_out: + if (tmp_buf != NULL) { + kfree((void*)tmp_buf); + tmp_buf = NULL; + } + return; +} + +static void ps3_stat_total_show_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + S8 *buf = NULL; + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + buf = (S8 *)kzalloc(PAGE_SIZE * 2, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_out; + } + + ps3_stat_total_dump(instance, buf, PAGE_SIZE * 2); + ps3stor_cli_printf(buf); + +l_out: + if (buf != NULL) { + kfree(buf); + buf = NULL; + } + return; +} + +static void ps3_stat_inc_dump(struct ps3_instance *instance, + char *buf, S32 total_len) +{ + S32 len = 0; + const U32 temp_array_len = PAGE_SIZE; + S8 *tmp_buf = NULL; + S32 temp_len = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + U16 i = 0; + + len += snprintf(buf + len, total_len - len, + "----host[%u] inc cmd statistics show begin----\n", PS3_HOST(instance)); + len += snprintf(buf + len, total_len - len, + "%-25s %-15s %-15s %-15s %-15s %-20s %-20s %-20s\n", + " ", "start", "back_good", "back_err", "not_back", "avg(us)", "max(us)", "min(us)"); + + tmp_buf = (S8 *)kzalloc(temp_array_len, GFP_KERNEL); + if (tmp_buf == NULL) { + goto l_out; + } + + for (; i < PS3_QOS_PD_PRO; ++i) { + temp_len = snprintf(tmp_buf, temp_array_len, + "%-25s %-15llu %-15llu %-15llu %-15llu " + "%-20llu %-20llu %-20llu\n", + ps3_cmd_stat_item_tostring((enum ps3_cmd_stat_item)i), + ctx->inc_stat.stat[i].start, + ctx->inc_stat.stat[i].back_good, + ctx->inc_stat.stat[i].back_err, + ctx->inc_stat.stat[i].not_back, + ctx->inc_stat.stat[i].lagency.avg, + ctx->inc_stat.stat[i].lagency.max_lagency, + ctx->inc_stat.stat[i].lagency.min_lagency); + if ((len + temp_len) > total_len) { + ps3stor_cli_printf("print over!\n"); + goto l_out; + } + + memset(tmp_buf, 0, temp_array_len); + + len += snprintf(buf + len, total_len - len, + "%-25s %-15llu %-15llu %-15llu %-15llu " + "%-20llu %-20llu %-20llu\n", + ps3_cmd_stat_item_tostring((enum ps3_cmd_stat_item)i), + ctx->inc_stat.stat[i].start, + ctx->inc_stat.stat[i].back_good, + ctx->inc_stat.stat[i].back_err, + ctx->inc_stat.stat[i].not_back, + ctx->inc_stat.stat[i].lagency.avg, + ctx->inc_stat.stat[i].lagency.max_lagency, + ctx->inc_stat.stat[i].lagency.min_lagency); + } + + temp_len = snprintf(tmp_buf, temp_array_len, + "----host[%u] cmd statistics show end----\n", PS3_HOST(instance)); + if ((len + temp_len) > total_len) { + ps3stor_cli_printf("print over!\n"); + goto l_out; + } + + len += snprintf(buf + len, total_len - len, + "----host[%u] cmd statistics show end----\n", PS3_HOST(instance)); +l_out: + if (tmp_buf != NULL) { + kfree((void*)tmp_buf); + tmp_buf = NULL; + } + return; +} + +static void ps3_stat_inc_show_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + S8 *buf = NULL; + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + buf = (S8 *)kzalloc(PAGE_SIZE, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_out; + } + + ps3_stat_inc_dump(instance, buf, PAGE_SIZE); + ps3stor_cli_printf(buf); + +l_out: + if (buf != NULL) { + kfree(buf); + buf = NULL; + } + return; +} + +static void ps3_stat_buf_clr_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + ps3_stat_all_clear(instance); + ps3stor_cli_printf("cmd stat clear complete\n"); + +l_out: + return; +} + +static void ps3_stat_interval_show_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + ps3stor_cli_printf("cmd stat interval is %u ms\n", + instance->cmd_statistics.stat_interval); + +l_out: + return; +} + +static void ps3_stat_interval_store_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + U32 interval = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 5) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + if (strcmp(argv[3], "interval") != 0) { + ps3stor_cli_printf("value err!\n"); + goto l_out; + } + + ret = kstrtouint(argv[4], 0, &interval); + if (ret != 0) { + ps3stor_cli_printf("Can not parse value!\n"); + goto l_out; + } + + if (interval < 1000) { + ps3stor_cli_printf("interval need > 1000ms!\n"); + goto l_out; + } + + instance->cmd_statistics.stat_interval = interval; + + ps3stor_cli_printf("cmd stat interval is %u ms\n", + instance->cmd_statistics.stat_interval); + +l_out: + return; +} + +static void ps3_reply_fifo_reset_cb(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + ps3_all_reply_fifo_complete(instance); + ps3_all_reply_fifo_init(instance); + ps3stor_cli_printf("all reply fifo complete reply_index to 0\n"); + +l_out: + return; +} + +static void ps3_cli_remove_host_force(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d !\n", host_no); + goto l_out; + } + + ps3_remove(instance->pdev); + + ps3stor_cli_printf("remove instance %d completed\n", host_no); +l_out: + return; +} + +static void ps3_cli_ramfs_test_set(int argc, char *argv[]) +{ + U16 ramfs_enable = 0; + S32 ret = PS3_SUCCESS; + + if (argc < 2) { + ps3stor_cli_printf("Too few args, must input 2 args!\n"); + goto l_out; + } + + ret = kstrtou16(argv[1], 0, &ramfs_enable); + if (ret != 0) { + ps3stor_cli_printf("Can not parse ramfs_enable!\n"); + goto l_out; + } + + ps3_ramfs_test_store((S32)ramfs_enable); + + ps3stor_cli_printf("set ramfs test enable to %d\n", ramfs_enable); +l_out: + return; +} + +static void ps3_cli_err_inject_active(int argc, char *argv[]) +{ + U32 err_inject_type = 0; + U32 count; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + ret = kstrtouint(argv[1], 0, &err_inject_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse err_inject_type!\n"); + goto l_out; + } + + ret = kstrtouint(argv[2], 0, &count); + if (ret != 0) { + ps3stor_cli_printf("Can not parse count!\n"); + goto l_out; + } + + if ((err_inject_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) && + (err_inject_type < PS3_ERR_IJ_MAX_COUNT)) { + INJECT_ACTIVE(err_inject_type, count) + ps3stor_cli_printf("active %u count %u\n", err_inject_type, count); + } +l_out: + return; +} +static void ps3_cli_err_inject_clear(int argc, char *argv[]) +{ + argc = argc; + argv = argv; + INJECT_EXIT() +} + +Bool ps3_get_wait_cli_flag(void) +{ + return ps3_cli_wait_flag; +} + +static void ps3_no_wait_cli_cmd(int argc, char *argv[]) +{ + U16 wait_cli_flag = PS3_FALSE; + S32 ret = PS3_SUCCESS; + + if (argc < 3) { + ps3stor_cli_printf("Too few args, must input 3 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "flag") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &wait_cli_flag); + if (ret != 0) { + ps3stor_cli_printf("Can not parse wait_cli_flag!\n", + argv[3]); + goto l_out; + } + + if (wait_cli_flag) { + ps3_cli_wait_flag = PS3_TRUE; + } else { + ps3_cli_wait_flag = PS3_FALSE; + } + ps3stor_cli_printf("ps3 no wait cli flag %d\n", ps3_cli_wait_flag); + +l_out: + return; +} + +static void ps3_qos_show_pd(struct ps3_instance *instance, U16 disk_id) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct qos_wait_queue *waitq = NULL; + U16 i = 0; + if (disk_id > 0 && + disk_id <= instance->qos_context.max_pd_count) { + ps3stor_cli_printf("qos pd[%u] info\n", disk_id); + qos_pd_mgr = &instance->qos_context.pd_ctx.qos_pd_mgrs[disk_id]; + ps3stor_cli_printf("-----valid[%u] vid[%u] used_quota[%u] quota[%u] total_waited_cmd[%u]\n", + ps3_atomic_read(&qos_pd_mgr->valid), qos_pd_mgr->vd_id, + ps3_atomic_read(&qos_pd_mgr->pd_used_quota), + qos_pd_mgr->pd_quota, qos_pd_mgr->total_wait_cmd_cnt); + if (qos_pd_mgr->total_wait_cmd_cnt > 0) { + for (i = 1; i < qos_pd_mgr->waitq_cnt; i++) { + waitq = &qos_pd_mgr->waitqs[i]; + if (waitq->count > 0) { + ps3stor_cli_printf(" vid[%u] waitq_cnt[%u]\n", + waitq->id, waitq->count); + } + } + } + + if (qos_pd_mgr->dev_type == PS3_DEV_TYPE_NVME_SSD) { + waitq = &qos_pd_mgr->waitqs[0]; + ps3stor_cli_printf(" direct_used_quota[%u] direct_quota[%u] waitq_cnt[%u]\n", + ps3_atomic_read(&qos_pd_mgr->direct_used_quota), + qos_pd_mgr->direct_quota, waitq->count); + } + + } else { + ps3stor_cli_printf("disk_id[%u] is error\n", disk_id); + } +} + +static void ps3_qos_show_vd(struct ps3_instance *instance, U16 disk_id) +{ + U8 i = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_qos_cq_context *qos_cq_ctx = &instance->qos_context.cq_ctx; + struct ps3_qos_softq_mgr *qos_softq_mgr = NULL; + if (disk_id > 0 && disk_id <= instance->qos_context.max_vd_count) { + ps3stor_cli_printf("qos vd[%u] info\n", disk_id); + if (instance->qos_context.vd_ctx.qos_vd_mgrs) { + qos_vd_mgr = &instance->qos_context.vd_ctx.qos_vd_mgrs[disk_id]; + ps3stor_cli_printf("-----valid[%u] quota[%u] quota_waitq[%u] exclusive[%u]\n", + qos_vd_mgr->valid, ps3_atomic_read(&qos_vd_mgr->vd_quota), + qos_vd_mgr->vd_quota_wait_q.count, ps3_atomic_read(&qos_vd_mgr->exclusive_cmd_cnt)); + } + + if (qos_cq_ctx->cmdqs) { + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + qos_softq_mgr = &qos_cq_ctx->cmdqs[i]; + ps3stor_cli_printf("-----cmdq[%u] waitq_cnt[%u]\n", + i, qos_softq_mgr->waitqs[disk_id].count); + } + } + } else { + ps3stor_cli_printf("disk_id[%u] is error\n", disk_id); + } +} + +static void ps3_qos_stat_dump(struct ps3_instance *instance, + char *buf, S32 total_len) +{ + S32 len = 0; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + struct ps3_qos_pd_context *qos_pd_ctx = &instance->qos_context.pd_ctx; + struct ps3_qos_vd_context *qos_vd_ctx = &instance->qos_context.vd_ctx; + struct ps3_qos_cq_context *qos_cq_ctx = &instance->qos_context.cq_ctx; + struct ps3_qos_softq_mgr *qos_softq_mgr = NULL; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct qos_wait_queue *cmd_waitq = NULL; + U16 i = 0; + + len += snprintf(buf + len, total_len - len, + "----host[%u] qos cmd statistics show begin switch[%u] " + "total_qos_cmd[%llu]\n", + PS3_HOST(instance), instance->qos_context.qos_switch, + ps3_atomic64_read(&instance->cmd_statistics.cmd_qos_total)); + + if (qos_tg_ctx->vd_cmd_waitqs) { + len += snprintf(buf + len, total_len - len, + "tag: share[%u] mgr[%u]\n", ps3_atomic_read(&qos_tg_ctx->share_free_cnt), + ps3_atomic_read(&qos_tg_ctx->mgr_free_cnt)); + + if (qos_tg_ctx ->mgr_cmd_wait_q.count > 0) { + len += snprintf(buf + len, total_len - len, + "mgr cmd waitq count[%u]\n", + qos_tg_ctx->mgr_cmd_wait_q.count); + if (len >= total_len) { + goto l_out; + } + } + + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + cmd_waitq = &qos_tg_ctx ->vd_cmd_waitqs[i]; + if (cmd_waitq->count) { + len += snprintf(buf + len, total_len - len, + "vd[%u] cmd waitq_count[%u]\n", i, cmd_waitq->count); + if (len >= total_len) { + goto l_out; + } + } + } + } + + if (qos_cq_ctx->cmdqs) { + qos_softq_mgr = &qos_cq_ctx->mgrq; + len += snprintf(buf + len, total_len - len, + "mgrq: free[%u] waitq_count[%u]\n", ps3_atomic_read(&qos_softq_mgr->free_cnt), + qos_softq_mgr->total_wait_cmd_cnt); + if (len >= total_len) { + goto l_out; + } + + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + qos_softq_mgr = &qos_cq_ctx->cmdqs[i]; + len += snprintf(buf + len, total_len - len, + "cmdq[%u]: free[%u] waitq_count[%u]\n", i, ps3_atomic_read(&qos_softq_mgr->free_cnt), + qos_softq_mgr->total_wait_cmd_cnt); + if (len >= total_len) { + goto l_out; + } + } + } + + if (qos_pd_ctx->qos_pd_mgrs) { + for (i = 1; i <= instance->qos_context.max_pd_count; i++) { + qos_pd_mgr = &qos_pd_ctx->qos_pd_mgrs[i]; + if (qos_pd_mgr->total_wait_cmd_cnt) { + len += snprintf(buf + len, total_len - len, + "pid[%u] vid[%u] valid[%u] used_quota[%u] waitq_count[%u]\n", + qos_pd_mgr->disk_id, qos_pd_mgr->vd_id, ps3_atomic_read(&qos_pd_mgr->valid), + ps3_atomic_read(&qos_pd_mgr->pd_used_quota),qos_pd_mgr->total_wait_cmd_cnt); + if (len >= total_len) { + goto l_out; + } + } + + if (qos_pd_mgr->total_waited_direct_cmd) { + len += snprintf(buf + len, total_len - len, + "pid[%u] valid[%u] direct_used_quota[%u] waitq_count[%u]\n", + qos_pd_mgr->disk_id, qos_pd_mgr->vd_id, ps3_atomic_read(&qos_pd_mgr->direct_used_quota), + qos_pd_mgr->total_waited_direct_cmd); + if (len >= total_len) { + goto l_out; + } + } + } + } + + if (qos_vd_ctx->qos_vd_mgrs) { + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + qos_vd_mgr = &qos_vd_ctx->qos_vd_mgrs[i]; + if (qos_vd_mgr->vd_quota_wait_q.count) { + len += snprintf(buf + len, total_len - len, + "vid[%u] quota[%u] waitq_count[%u]\n", + i, ps3_atomic_read(&qos_vd_mgr->vd_quota),qos_vd_mgr->vd_quota_wait_q.count); + if (len >= total_len) { + goto l_out; + } + } + } + } + + len += snprintf(buf + len, total_len - len, + "----host[%u] qos cmd statistics show end----\n", PS3_HOST(instance)); +l_out: + return; +} + +static void ps3_qos_show_delay(struct ps3_instance *instance) +{ + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + U16 i = 0; + + ps3stor_cli_printf("----host[%u] qos delay show begin----\n", PS3_HOST(instance)); + ps3stor_cli_printf("%-25s %-20s %-20s %-20s\n", + " ", "avg(us)", "max(us)", "min(us)"); + for (i = PS3_QOS_PD_PRO; i < PS3_CMD_STAT_COUNT; i++) { + ps3stor_cli_printf("%-25s %-20llu %-20llu %-20llu\n", + ps3_cmd_stat_item_tostring((enum ps3_cmd_stat_item)i), + ctx->total_stat.stat[i].lagency.avg, + ctx->total_stat.stat[i].lagency.max_lagency, + ctx->total_stat.stat[i].lagency.min_lagency); + } + + ps3stor_cli_printf("----host[%u] qos delay show end----\n", PS3_HOST(instance)); + return; +} + +static void ps3_cli_qos_info(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + U16 disk_id = 0; + S8 *buf = NULL; + S32 ret = 0; + + if (argc < 4) { + ps3stor_cli_printf("Too few args, must input 4 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + + if (!instance->qos_context.inited) { + ps3stor_cli_printf("qos not support host_no %u !\n", host_no); + goto l_out; + } + + if (strcmp(argv[3], "pd") == 0) { + if (argc < 5) { + ps3stor_cli_printf("pd_id is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[4], 0, &disk_id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse disk id!\n"); + goto l_out; + } + ps3_qos_show_pd(instance, disk_id); + goto l_out; + } else if (strcmp(argv[3], "vd") == 0) { + if (argc < 5) { + ps3stor_cli_printf("vd_id is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[4], 0, &disk_id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse disk id!\n"); + goto l_out; + } + ps3_qos_show_vd(instance, disk_id); + goto l_out; + } else if (strcmp(argv[3], "all") == 0) { + buf = (S8 *)kzalloc(PAGE_SIZE * 2, GFP_KERNEL); + if (buf == NULL) { + ps3stor_cli_printf("malloc buf failed!\n"); + goto l_out; + } + + ps3_qos_stat_dump(instance, buf, PAGE_SIZE * 2); + ps3stor_cli_printf(buf); + } else if (strcmp(argv[3], "delay") == 0) { + ps3_qos_show_delay(instance); + } +l_out: + if (buf != NULL) { + kfree(buf); + buf = NULL; + } + + return; +} + +static void ps3_cli_special_log(int argc, char *argv[]) +{ + struct ps3_instance *instance = NULL; + U16 host_no = 0; + U16 print_switch = 0; + S32 ret = 0; + + if (argc < 5) { + ps3stor_cli_printf("Too few args, must input 5 args!\n"); + goto l_out; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_out; + } + + ret = kstrtou16(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no!\n"); + goto l_out; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %u !\n", host_no); + goto l_out; + } + + if (strcmp(argv[3], "set") == 0) { + ret = kstrtou16(argv[4], 0, &print_switch); + if (ret != 0) { + ps3stor_cli_printf("Can not parse log_switch!\n"); + goto l_out; + } + + instance->is_print_special_log = (print_switch > 0 ? 1 : 0); + ps3stor_cli_printf("set print_special_log=%u\n", + instance->is_print_special_log); + } +l_out: + return; +} + +#ifdef PS3_SUPPORT_INJECT +struct inject_cmds_t * ps3_inject_scsi_rw_exist(struct inject_cmds_t *this_pitem) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + Bool is_find = PS3_FALSE; + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->scsi_rw_list)) { + goto l_out; + } + + list_for_each_entry(pitem, &p_inject_list->scsi_rw_list, list) { + if ((this_pitem->item.scsi_cmd.host_no == pitem->item.scsi_cmd.host_no) && + (this_pitem->item.scsi_cmd.channel == pitem->item.scsi_cmd.channel) && + (this_pitem->item.scsi_cmd.id == pitem->item.scsi_cmd.id)) { + if (((this_pitem->item.scsi_cmd.lba >= pitem->item.scsi_cmd.lba) && + (this_pitem->item.scsi_cmd.lba <= pitem->item.scsi_cmd.lba + pitem->item.scsi_cmd.len)) || + ((this_pitem->item.scsi_cmd.lba + this_pitem->item.scsi_cmd.len >= pitem->item.scsi_cmd.lba) && + (this_pitem->item.scsi_cmd.lba + this_pitem->item.scsi_cmd.len <= + pitem->item.scsi_cmd.lba + pitem->item.scsi_cmd.len))) { + ps3stor_cli_printf("inject [%u:%u:%u] lba[0x%llx], len[0x%x], is exist!\n", + pitem->item.scsi_cmd.host_no, pitem->item.scsi_cmd.channel, + pitem->item.scsi_cmd.id, pitem->item.scsi_cmd.lba, + pitem->item.scsi_cmd.len); + is_find = PS3_TRUE; + break; + } + } + } +l_out: + if(!is_find) { + pitem = NULL; + } + ps3_mutex_unlock(&p_inject_list->lock); + return pitem; +} + +struct inject_cmds_t * ps3_inject_scsi_task_exist(struct inject_cmds_t *this_pitem) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + Bool is_find = PS3_FALSE; + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->scsi_task_list)) { + goto l_out; + } + + list_for_each_entry(pitem, &p_inject_list->scsi_task_list, list) { + if ((this_pitem->item.scsi_task_cmd.host_no == pitem->item.scsi_task_cmd.host_no) && + (this_pitem->item.scsi_task_cmd.channel == pitem->item.scsi_task_cmd.channel) && + (this_pitem->item.scsi_task_cmd.id == pitem->item.scsi_task_cmd.id)) { + if (this_pitem->item.scsi_task_cmd.cmd_type == pitem->item.scsi_task_cmd.cmd_type && + this_pitem->item.scsi_task_cmd.cmd_sub_type == pitem->item.scsi_task_cmd.cmd_sub_type) { + is_find = PS3_TRUE; + break; + } + } + } +l_out: + if(!is_find) { + pitem = NULL; + } + ps3_mutex_unlock(&p_inject_list->lock); + return pitem; +} +struct inject_cmds_t * ps3_inject_mgr_exist(struct inject_cmds_t *this_pitem) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + Bool is_find = PS3_FALSE; + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->mgr_list)) { + goto l_out; + } + + list_for_each_entry(pitem, &p_inject_list->mgr_list, list) { + if ((this_pitem->item.mgr_cmd.host_no == pitem->item.mgr_cmd.host_no) && + (this_pitem->item.mgr_cmd.cmd_type == pitem->item.mgr_cmd.cmd_type) && + (this_pitem->item.mgr_cmd.cmd_sub_type == pitem->item.mgr_cmd.cmd_sub_type)) { + is_find = PS3_TRUE; + } + } +l_out: + if(!is_find) { + pitem = NULL; + } + ps3_mutex_unlock(&p_inject_list->lock); + return pitem; +} + +void ps3_show_inject_scsi_rw_item(struct inject_cmds_t *pitem) +{ + struct inject_cmds_t *pitem1 = NULL; + PS3Inject_s *p_inject_list = get_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->scsi_rw_list)) { + ps3stor_cli_printf("rw inject list is empty!\n"); + ps3_mutex_unlock(&p_inject_list->lock); + goto l_out; + } + ps3_mutex_unlock(&p_inject_list->lock); + + if ((pitem1 = ps3_inject_scsi_rw_exist(pitem)) == NULL){ + ps3stor_cli_printf("rw inject type is noexist!\n"); + goto l_out; + } + ps3stor_cli_printf("inject_rw host_no %u channel %u id %u lba 0x%llx len 0x%u type %u, time %u!\n", + pitem1->item.scsi_cmd.host_no, pitem1->item.scsi_cmd.channel, + pitem1->item.scsi_cmd.id, pitem1->item.scsi_cmd.lba, + pitem1->item.scsi_cmd.len, pitem1->item.scsi_cmd.dealType, + pitem1->item.scsi_cmd.inject_count); + +l_out: + return; +} + +void ps3_show_inject_all_scsi_rw(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + + argc = argc; + argv = argv; + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->scsi_rw_list)) { + ps3stor_cli_printf("rw inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry(pitem, &p_inject_list->scsi_rw_list, list) { + ps3stor_cli_printf("inject_rw host_no %u channel %u id %u lba 0x%llx len 0x%u!\n", + pitem->item.scsi_cmd.host_no, pitem->item.scsi_cmd.channel, + pitem->item.scsi_cmd.id, pitem->item.scsi_cmd.lba, + pitem->item.scsi_cmd.len); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return; +} +void ps3_show_inject_scsi_task_item(struct inject_cmds_t *pitem) +{ + struct inject_cmds_t *pitem1; + PS3Inject_s *p_inject_list = get_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->scsi_task_list)) { + ps3stor_cli_printf("task inject list is empty!\n"); + ps3_mutex_unlock(&p_inject_list->lock); + goto l_out; + } + ps3_mutex_unlock(&p_inject_list->lock); + + if ((pitem1 = ps3_inject_scsi_task_exist(pitem)) == NULL){ + ps3stor_cli_printf("task inject type is noexist!\n"); + goto l_out; + } + ps3stor_cli_printf("inject_rw host_no %u channel %u id %u cmdtype" + " 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem1->item.scsi_task_cmd.host_no, pitem1->item.scsi_task_cmd.channel, + pitem1->item.scsi_task_cmd.id, pitem1->item.scsi_task_cmd.cmd_type, + pitem1->item.scsi_task_cmd.cmd_sub_type, pitem1->item.scsi_task_cmd.dealType, + pitem1->item.scsi_task_cmd.inject_count); + +l_out: + return; +} +void ps3_show_inject_mgr_item(struct inject_cmds_t *pitem) +{ + struct inject_cmds_t *pitem1; + PS3Inject_s *p_inject_list = get_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->mgr_list)) { + ps3_mutex_unlock(&p_inject_list->lock); + goto l_out; + } + ps3_mutex_unlock(&p_inject_list->lock); + + if ((pitem1 = ps3_inject_mgr_exist(pitem)) == NULL){ + ps3stor_cli_printf("mgr type is noexist!\n"); + goto l_out; + } + ps3stor_cli_printf("inject_mgr host_no %u cmdtype 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem1->item.mgr_cmd.host_no, pitem1->item.mgr_cmd.cmd_type, + pitem1->item.mgr_cmd.cmd_sub_type, pitem1->item.mgr_cmd.dealType, + pitem1->item.mgr_cmd.inject_count); + +l_out: + return; +} + +void ps3_show_inject_all_scsi_task(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + + argc = argc; + argv = argv; + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->scsi_task_list)) { + ps3stor_cli_printf("task inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry(pitem, &p_inject_list->scsi_task_list, list) { + ps3stor_cli_printf("inject_task host_no %u channel %u id %u" + " cmdtype 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem->item.scsi_task_cmd.host_no, pitem->item.scsi_task_cmd.channel, + pitem->item.scsi_task_cmd.id, pitem->item.scsi_task_cmd.cmd_type, + pitem->item.scsi_task_cmd.cmd_sub_type,pitem->item.scsi_task_cmd.dealType, + pitem->item.scsi_task_cmd.inject_count); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return; +} +void ps3_show_inject_all_mgr(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + + argc = argc; + argv = argv; + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_inject_list->mgr_list)) { + goto l_out; + } + + list_for_each_entry(pitem, &p_inject_list->mgr_list, list) { + ps3stor_cli_printf("inject_task host_no %u cmdtype 0x%u " + "cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem->item.mgr_cmd.host_no, pitem->item.mgr_cmd.cmd_type, + pitem->item.mgr_cmd.cmd_sub_type,pitem->item.mgr_cmd.dealType, + pitem->item.mgr_cmd.inject_count); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return; +} + +void ps3_clear_all_inject_scsi_rw(void) +{ + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + struct inject_cmds_t *pitem_next = NULL; + + ps3_mutex_lock(&p_inject_list->lock); + + if (list_empty(&p_inject_list->scsi_rw_list)) { + goto l_out; + } + + list_for_each_entry_safe(pitem, pitem_next, &p_inject_list->scsi_rw_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return; +} +void ps3_clear_all_inject_scsi_task(void) +{ + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + PS3Inject_s *p_inject_list = get_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + + if (list_empty(&p_inject_list->scsi_task_list)) { + goto l_out; + } + + list_for_each_entry_safe(pitem, pitem_next, &p_inject_list->scsi_task_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return; +} +void ps3_clear_all_inject_mgr(void) +{ + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + PS3Inject_s *p_inject_list = get_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + + if (list_empty(&p_inject_list->mgr_list)) { + goto l_out; + } + + list_for_each_entry_safe(pitem, pitem_next, &p_inject_list->mgr_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return; +} + +void ps3_del_inject_scsi_rw(struct inject_cmds_t *pitem) +{ + struct inject_cmds_t *pitem1; + PS3Inject_s *p_inject_list = get_inject(); + + if ((pitem1 = ps3_inject_scsi_rw_exist(pitem)) == NULL){ + ps3stor_cli_printf("rw inject type is noexist!\n"); + goto l_err; + } + ps3_mutex_lock(&p_inject_list->lock); + ps3stor_cli_printf("del inject_rw host_no %u channel %u id %u lba 0x%llx len 0x%u type %u, time %u!\n", + pitem1->item.scsi_cmd.host_no, pitem1->item.scsi_cmd.channel, + pitem1->item.scsi_cmd.id, pitem1->item.scsi_cmd.lba, + pitem1->item.scsi_cmd.len, pitem1->item.scsi_cmd.dealType, + pitem1->item.scsi_cmd.inject_count); + list_del(&pitem1->list); + ps3_mutex_unlock(&p_inject_list->lock); + kfree(pitem1); + +l_err: + kfree(pitem); + return; +} +void ps3_del_inject_scsi_task(struct inject_cmds_t *pitem) +{ + struct inject_cmds_t *pitem1; + PS3Inject_s *p_inject_list = get_inject(); + + if ((pitem1 = ps3_inject_scsi_task_exist(pitem)) == NULL){ + ps3stor_cli_printf("task inject type is noexist!\n"); + goto l_err; + } + ps3_mutex_lock(&p_inject_list->lock); + ps3stor_cli_printf("del inject_task host_no %u channel %u id %u" + " cmdtype 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem1->item.scsi_task_cmd.host_no, pitem1->item.scsi_task_cmd.channel, + pitem1->item.scsi_task_cmd.id, pitem1->item.scsi_task_cmd.cmd_type, + pitem1->item.scsi_task_cmd.cmd_sub_type, pitem1->item.scsi_task_cmd.dealType, + pitem1->item.scsi_task_cmd.inject_count); + list_del(&pitem1->list); + ps3_mutex_unlock(&p_inject_list->lock); + kfree(pitem1); + +l_err: + kfree(pitem); + return; +} +void ps3_del_inject_mgr(struct inject_cmds_t *pitem) +{ + struct inject_cmds_t *pitem1; + PS3Inject_s *p_inject_list = get_inject(); + + if ((pitem1 = ps3_inject_mgr_exist(pitem)) == NULL){ + ps3stor_cli_printf("mgr inject type is noexist!\n"); + goto l_err; + } + ps3_mutex_lock(&p_inject_list->lock); + ps3stor_cli_printf("del inject_mgr host_no %u cmdtype 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem1->item.mgr_cmd.host_no, pitem1->item.mgr_cmd.cmd_type, + pitem1->item.mgr_cmd.cmd_sub_type,pitem1->item.mgr_cmd.dealType, + pitem1->item.mgr_cmd.inject_count); + list_del(&pitem1->list); + ps3_mutex_unlock(&p_inject_list->lock); + kfree(pitem1); + +l_err: + kfree(pitem); + return; +} + +S32 ps3_add_inject_scsi_rw(struct inject_cmds_t *pitem) +{ + S32 iRet = PS3_SUCCESS; + PS3Inject_s *p_inject_list = get_inject(); + + if (ps3_inject_scsi_rw_exist(pitem) != NULL){ + ps3stor_cli_printf("rw inject type is exist!\n"); + iRet = -PS3_FAILED; + goto l_err; + } + ps3_mutex_lock(&p_inject_list->lock); + ps3stor_cli_printf("inject_rw host_no %u channel %u id %u lba 0x%llx len 0x%u type %u, time %u!\n", + pitem->item.scsi_cmd.host_no, pitem->item.scsi_cmd.channel, + pitem->item.scsi_cmd.id, pitem->item.scsi_cmd.lba, + pitem->item.scsi_cmd.len, pitem->item.scsi_cmd.dealType, + pitem->item.scsi_cmd.inject_count); + list_add_tail(&pitem->list, &p_inject_list->scsi_rw_list); + ps3_mutex_unlock(&p_inject_list->lock); + goto l_out; + +l_err: + kfree(pitem); +l_out: + return iRet; +} +S32 ps3_add_inject_scsi_task(struct inject_cmds_t *pitem) +{ + S32 iRet = PS3_SUCCESS; + PS3Inject_s *p_inject_list = get_inject(); + + if (ps3_inject_scsi_task_exist(pitem) != NULL){ + ps3stor_cli_printf("task inject type is exist!\n"); + iRet = -PS3_FAILED; + goto l_err; + } + ps3_mutex_lock(&p_inject_list->lock); + ps3stor_cli_printf("inject_task host_no %u channel %u id %u " + "cmdtype 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem->item.scsi_task_cmd.host_no, pitem->item.scsi_task_cmd.channel, + pitem->item.scsi_task_cmd.id, pitem->item.scsi_task_cmd.cmd_type, + pitem->item.scsi_task_cmd.cmd_sub_type, pitem->item.scsi_task_cmd.dealType, + pitem->item.scsi_task_cmd.inject_count); + list_add_tail(&pitem->list, &p_inject_list->scsi_task_list); + ps3_mutex_unlock(&p_inject_list->lock); + goto l_out; + +l_err: + kfree(pitem); +l_out: + return iRet; +} +S32 ps3_add_inject_mgr(struct inject_cmds_t *pitem) +{ + S32 iRet = PS3_SUCCESS; + PS3Inject_s *p_inject_list = get_inject(); + + if (ps3_inject_mgr_exist(pitem) != NULL){ + ps3stor_cli_printf("mgr inject type is exist!\n"); + iRet = -PS3_FAILED; + goto l_err; + } + ps3_mutex_lock(&p_inject_list->lock); + ps3stor_cli_printf("inject_task host_no %u cmdtype 0x%u cmdSubtype 0x%u dealType 0x%u times %u!\n", + pitem->item.mgr_cmd.host_no, pitem->item.mgr_cmd.cmd_type, + pitem->item.mgr_cmd.cmd_sub_type, pitem->item.mgr_cmd.dealType, + pitem->item.mgr_cmd.inject_count); + list_add_tail(&pitem->list, &p_inject_list->mgr_list); + ps3_mutex_unlock(&p_inject_list->lock); + goto l_out; + +l_err: + kfree(pitem); +l_out: + return iRet; +} + +static void ps3_inject_scsi_rw(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + U32 host_no; + U32 id; + U32 channel; + U64 lba; + U32 len; + S32 ret; + U32 result; + U32 sense_info; + struct scsi_device *sdev; + U32 times; + U32 dealType; + struct ps3_instance *instance; + + if (argc < 13) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t*)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_cmd.host_no = host_no; + + if (strcmp(argv[3], "dev") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse channel!\n"); + goto l_err; + } + + ret = kstrtouint(argv[5], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse id!\n"); + goto l_err; + } + sdev = ps3_scsi_device_lookup(instance, channel, id, 0); + if (sdev == NULL) { + ps3stor_cli_printf("Invalid sdev [%d:%d:%d] invalid !\n", + host_no, channel, id); + goto l_err; + } + pitem->item.scsi_cmd.channel = channel; + pitem->item.scsi_cmd.id = id; + pitem->item.scsi_cmd.device = sdev; + if (strcmp(argv[6], "lba") != 0) { + ps3stor_cli_printf("lba is needed!\n"); + goto l_err; + } + + ret = kstrtou64(argv[7], 0, &lba); + if (ret != 0) { + ps3stor_cli_printf("Can not parse lba!\n"); + goto l_err; + } + pitem->item.scsi_cmd.lba = lba; + + if (strcmp(argv[8], "len") != 0) { + ps3stor_cli_printf("len is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[9], 0, &len); + if (ret != 0) { + ps3stor_cli_printf("Can not parse len!\n"); + goto l_err; + } + pitem->item.scsi_cmd.len = len; + + ret = kstrtouint(argv[10], 0, &dealType); + if (ret != 0) { + ps3stor_cli_printf("Can not parse dealType!\n"); + goto l_err; + } + if (dealType != PS3_SCSI_CMD_TIMEOUT_FORCE_REPLY + && dealType != PS3_SCSI_CMD_ERROR) { + ps3stor_cli_printf("err type is invalid!\n"); + goto l_err; + } + + pitem->item.scsi_cmd.dealType = dealType; + switch (pitem->item.scsi_cmd.dealType) + { + case PS3_SCSI_CMD_TIMEOUT_FORCE_REPLY: + if (strcmp(argv[11], "times") != 0) { + ps3stor_cli_printf("times is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[12], 0, ×); + if (ret != 0) { + ps3stor_cli_printf("Can not parse times!\n"); + goto l_err; + } + pitem->item.scsi_cmd.inject_count = times; + break; + case PS3_SCSI_CMD_ERROR: + if (strcmp(argv[11], "result") != 0) { + ps3stor_cli_printf("result is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[12], 0, &result); + if (ret != 0) { + ps3stor_cli_printf("Can not parse result!\n"); + goto l_err; + } + pitem->item.scsi_cmd.cmdDeal.errReply.result = result; + + if (strcmp(argv[13], "sense") != 0) { + ps3stor_cli_printf("sense is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[14], 0, &sense_info); + if (ret != 0) { + ps3stor_cli_printf("Can not parse sense!\n"); + goto l_err; + } + pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.resp_code = sense_info & 0xf; + pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.sense_key = sense_info >> 8 & 0xf; + pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.asc = sense_info >> 16 & 0xf; + pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.ascq = sense_info >> 24 & 0xf; + + if (strcmp(argv[15], "times") != 0) { + ps3stor_cli_printf("times is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[16], 0, ×); + if (ret != 0) { + ps3stor_cli_printf("Can not parse times!\n"); + goto l_err; + } + pitem->item.scsi_cmd.inject_count = times; + break; + default: + ps3stor_cli_printf("handle type is invalid!\n"); + goto l_err; + break; + } + ps3_add_inject_scsi_rw(pitem); + goto l_out; + +l_err: + kfree(pitem); +l_out: + return; +} +static void ps3_inject_scsi_task(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + U32 host_no; + U32 id; + U32 channel; + S32 ret; + struct scsi_device *sdev; + U32 times; + U32 dealType; + struct ps3_instance *instance; + + if (argc < 10) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t *)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_task_cmd.host_no = host_no; + + if (strcmp(argv[3], "dev") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse channel!\n"); + goto l_err; + } + + ret = kstrtouint(argv[5], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse id!\n"); + goto l_err; + } + sdev = ps3_scsi_device_lookup(instance, channel, id, 0); + if (sdev == NULL) { + ps3stor_cli_printf("Invalid sdev [%d:%d:%d] invalid !\n", + host_no, channel, id); + goto l_err; + } + pitem->item.scsi_task_cmd.channel = channel; + pitem->item.scsi_task_cmd.id = id; + + if (strcmp(argv[6], "abort") == 0) { + pitem->item.scsi_task_cmd.cmd_type = PS3_CMD_SCSI_TASK_MANAGEMENT; + pitem->item.scsi_task_cmd.cmd_sub_type = PS3_TASK_CMD_SCSI_TASK_ABORT; + } else if (strcmp(argv[6], "reset") == 0) { + pitem->item.scsi_task_cmd.cmd_type = PS3_CMD_SCSI_TASK_MANAGEMENT; + pitem->item.scsi_task_cmd.cmd_sub_type = PS3_TASK_CMD_SCSI_TASK_RESET; + } else { + ps3stor_cli_printf("type is invalid!\n"); + goto l_err; + } + + ret = kstrtouint(argv[7], 0, &dealType); + if (ret != 0) { + ps3stor_cli_printf("Can not parse dealType!\n"); + goto l_err; + } + if (dealType != PS3_SCSI_TASK_CMD_TIMEOUT && dealType != PS3_SCSI_TASK_CMD_ERROE && + dealType != PS3_SCSI_TASK_CMD_NORMAL) { + ps3stor_cli_printf("deal type is invalid!\n"); + goto l_err; + } + pitem->item.scsi_task_cmd.dealType = dealType; + + if (strcmp(argv[8], "times") != 0) { + ps3stor_cli_printf("times is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[9], 0, ×); + if (ret != 0) { + ps3stor_cli_printf("Can not parse times!\n"); + goto l_err; + } + pitem->item.scsi_task_cmd.inject_count = times; + + ps3_add_inject_scsi_task(pitem); + goto l_out; + +l_err: + kfree(pitem); +l_out: + return; +} +static void ps3_inject_mgr(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + U32 host_no; + U8 cmd_type; + U8 cmd_sub_type; + S32 ret; + U32 times; + U32 dealType; + U32 errType; + struct ps3_instance *instance; + + if (argc < 10) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t *)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_task_cmd.host_no = host_no; + + if (strcmp(argv[3], "cmd_type") != 0) { + ps3stor_cli_printf("cmd_type is needed!\n"); + goto l_err; + } + + ret = kstrtou8(argv[4], 0, &cmd_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse cmd_type!\n"); + goto l_err; + } + pitem->item.mgr_cmd.cmd_type = cmd_type; + + if (strcmp(argv[5], "cmd_sub_type") != 0) { + ps3stor_cli_printf("cmd_sub_type is needed!\n"); + goto l_err; + } + + ret = kstrtou8(argv[6], 0, &cmd_sub_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse cmd_sub_type!\n"); + goto l_err; + } + pitem->item.mgr_cmd.cmd_sub_type = cmd_sub_type; + + ret = kstrtouint(argv[7], 0, &dealType); + if (ret != 0) { + ps3stor_cli_printf("Can not parse dealType!\n"); + goto l_err; + } + + if (dealType == PS3_MGR_CMD_TIMEOUT) { + if (strcmp(argv[8], "times") != 0) { + ps3stor_cli_printf("times is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[9], 0, ×); + if (ret != 0) { + ps3stor_cli_printf("Can not parse times!\n"); + goto l_err; + } + } else if (dealType == PS3_MGR_CMD_ERROE) { + ret = kstrtouint(argv[8], 0, &errType); + if (ret != 0) { + ps3stor_cli_printf("Can not parse errType!\n"); + goto l_err; + } + pitem->item.mgr_cmd.errType = errType; + if (strcmp(argv[9], "times") != 0) { + ps3stor_cli_printf("times is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[10], 0, ×); + if (ret != 0) { + ps3stor_cli_printf("Can not parse times!\n"); + goto l_err; + } + } else { + ps3stor_cli_printf("deal type is invalid!\n"); + goto l_err; + } + + pitem->item.mgr_cmd.dealType = dealType; + pitem->item.mgr_cmd.inject_count = times; + + ps3_add_inject_mgr(pitem); + goto l_out; + +l_err: + kfree(pitem); +l_out: + return; +} + +static void ps3_clear_inject_scsi_rw(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + + U32 host_no; + U32 id; + U32 channel; + U64 lba; + U32 len; + S32 ret; + struct scsi_device *sdev; + struct ps3_instance *instance; + + if (argc < 10) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t*)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_cmd.host_no = host_no; + + if (strcmp(argv[3], "dev") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse channel!\n"); + goto l_err; + } + + ret = kstrtouint(argv[5], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse id!\n"); + goto l_err; + } + sdev = ps3_scsi_device_lookup(instance, channel, id, 0); + if (sdev == NULL) { + ps3stor_cli_printf("Invalid sdev [%d:%d:%d] invalid !\n", + host_no, channel, id); + goto l_err; + } + pitem->item.scsi_cmd.channel = channel; + pitem->item.scsi_cmd.id = id; + pitem->item.scsi_cmd.device = sdev; + if (strcmp(argv[6], "lba") != 0) { + ps3stor_cli_printf("lba is needed!\n"); + goto l_err; + } + + ret = kstrtou64(argv[7], 0, &lba); + if (ret != 0) { + ps3stor_cli_printf("Can not parse lba!\n"); + goto l_err; + } + pitem->item.scsi_cmd.lba = lba; + + if (strcmp(argv[8], "len") != 0) { + ps3stor_cli_printf("len is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[9], 0, &len); + if (ret != 0) { + ps3stor_cli_printf("Can not parse len!\n"); + goto l_err; + } + pitem->item.scsi_cmd.len = len; + + ps3_del_inject_scsi_rw(pitem); + return; + +l_err: + kfree(pitem); + return; +} +static void ps3_clear_inject_scsi_task(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + + U32 host_no; + U32 id; + U32 channel; + S32 ret; + struct scsi_device *sdev; + struct ps3_instance *instance; + + if (argc < 7) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t *)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_task_cmd.host_no = host_no; + + if (strcmp(argv[3], "dev") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse channel!\n"); + goto l_err; + } + + ret = kstrtouint(argv[5], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse id!\n"); + goto l_err; + } + sdev = ps3_scsi_device_lookup(instance, channel, id, 0); + if (sdev == NULL) { + ps3stor_cli_printf("Invalid sdev [%d:%d:%d] invalid !\n", + host_no, channel, id); + goto l_err; + } + pitem->item.scsi_task_cmd.channel = channel; + pitem->item.scsi_task_cmd.id = id; + + if (strcmp(argv[6], "abort") == 0) { + pitem->item.scsi_task_cmd.cmd_type = PS3_CMD_SCSI_TASK_MANAGEMENT; + pitem->item.scsi_task_cmd.cmd_sub_type = PS3_TASK_CMD_SCSI_TASK_ABORT; + } else if (strcmp(argv[6], "reset") == 0) { + pitem->item.scsi_task_cmd.cmd_type = PS3_CMD_SCSI_TASK_MANAGEMENT; + pitem->item.scsi_task_cmd.cmd_sub_type = PS3_TASK_CMD_SCSI_TASK_RESET; + } else { + ps3stor_cli_printf("type is invalid!\n"); + goto l_err; + } + ps3_del_inject_scsi_task(pitem); + return; + +l_err: + kfree(pitem); + return; +} + +static void ps3_clear_inject_mgr(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + U32 host_no; + U32 cmd_type; + U32 cmd_sub_type; + S32 ret; + struct ps3_instance *instance; + + if (argc < 7) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t *)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.mgr_cmd.host_no = host_no; + + if (strcmp(argv[3], "cmd_type") != 0){ + ps3stor_cli_printf("cmd_type is invalid!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &cmd_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse cmd_type !\n"); + goto l_err; + } + pitem->item.mgr_cmd.cmd_type = cmd_type; + + if (strcmp(argv[5], "cmd_sub_type") != 0){ + ps3stor_cli_printf("cmd_sub_type is invalid!\n"); + goto l_err; + } + + ret = kstrtouint(argv[6], 0, &cmd_sub_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse cmd_type !\n"); + goto l_err; + } + pitem->item.mgr_cmd.cmd_sub_type = cmd_sub_type; + + ps3_del_inject_mgr(pitem); + return; + +l_err: + kfree(pitem); + return; +} + +static void ps3_clear_all_inject(int argc, char *argv[]) +{ + argc = argc; + argv = argv; + + ps3_clear_all_inject_scsi_rw(); + ps3_clear_all_inject_scsi_task(); + ps3_clear_all_inject_mgr(); +} + +static void ps3_show_inject_scsi_rw(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + + U32 host_no; + U32 id; + U32 channel; + U64 lba; + U32 len; + S32 ret; + struct scsi_device *sdev; + struct ps3_instance *instance; + + if (argc < 10) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t*)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_cmd.host_no = host_no; + + if (strcmp(argv[3], "dev") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse channel!\n"); + goto l_err; + } + + ret = kstrtouint(argv[5], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse id!\n"); + goto l_err; + } + sdev = ps3_scsi_device_lookup(instance, channel, id, 0); + if (sdev == NULL) { + ps3stor_cli_printf("Invalid sdev [%d:%d:%d] invalid !\n", + host_no, channel, id); + goto l_err; + } + pitem->item.scsi_cmd.channel = channel; + pitem->item.scsi_cmd.id = id; + if (strcmp(argv[6], "lba") != 0) { + ps3stor_cli_printf("lba is needed!\n"); + goto l_err; + } + + ret = kstrtou64(argv[7], 0, &lba); + if (ret != 0) { + ps3stor_cli_printf("Can not parse lba!\n"); + goto l_err; + } + pitem->item.scsi_cmd.lba = lba; + + if (strcmp(argv[8], "len") != 0) { + ps3stor_cli_printf("len is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[9], 0, &len); + if (ret != 0) { + ps3stor_cli_printf("Can not parse len!\n"); + goto l_err; + } + pitem->item.scsi_cmd.len = len; + ps3_show_inject_scsi_rw_item(pitem); + return; + +l_err: + kfree(pitem); + return; +} +static void ps3_show_inject_scsi_task(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + + U32 host_no; + U32 id; + U32 channel; + S32 ret; + struct scsi_device *sdev; + struct ps3_instance *instance; + + if (argc < 7) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t *)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_task_cmd.host_no = host_no; + + if (strcmp(argv[3], "dev") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &channel); + if (ret != 0) { + ps3stor_cli_printf("Can not parse channel!\n"); + goto l_err; + } + + ret = kstrtouint(argv[5], 0, &id); + if (ret != 0) { + ps3stor_cli_printf("Can not parse id!\n"); + goto l_err; + } + sdev = ps3_scsi_device_lookup(instance, channel, id, 0); + if (sdev == NULL) { + ps3stor_cli_printf("Invalid sdev [%d:%d:%d] invalid !\n", + host_no, channel, id); + goto l_err; + } + pitem->item.scsi_task_cmd.channel = channel; + pitem->item.scsi_task_cmd.id = id; + + if (strcmp(argv[6], "abort") == 0) { + pitem->item.scsi_task_cmd.cmd_type = PS3_CMD_SCSI_TASK_MANAGEMENT; + pitem->item.scsi_task_cmd.cmd_sub_type = PS3_TASK_CMD_SCSI_TASK_ABORT; + } else if (strcmp(argv[6], "reset") == 0) { + pitem->item.scsi_task_cmd.cmd_type = PS3_CMD_SCSI_TASK_MANAGEMENT; + pitem->item.scsi_task_cmd.cmd_sub_type = PS3_TASK_CMD_SCSI_TASK_RESET; + } else { + ps3stor_cli_printf("type is invalid!\n"); + goto l_err; + } + ps3_show_inject_scsi_task_item(pitem); + return; + +l_err: + kfree(pitem); + return; +} +static void ps3_show_inject_mgr(int argc, char *argv[]) +{ + struct inject_cmds_t *pitem = NULL; + + U32 host_no; + U32 cmd_type; + U32 cmd_sub_type; + S32 ret; + struct ps3_instance *instance; + + if (argc < 7) { + ps3stor_cli_printf("Too few args for enject!\n"); + return; + } + + pitem = (struct inject_cmds_t *)kmalloc(sizeof(struct inject_cmds_t), GFP_KERNEL); + if (pitem == NULL) { + return; + } + + if (strcmp(argv[1], "host_no") != 0) { + ps3stor_cli_printf("host_no is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[2], 0, &host_no); + if (ret != 0) { + ps3stor_cli_printf("Can not parse host_no !\n"); + goto l_err; + } + + instance = ps3_instance_lookup(host_no); + if (instance == NULL) { + ps3stor_cli_printf("Invalid host_no %d invalid !\n", + host_no); + goto l_err; + } + pitem->item.scsi_task_cmd.host_no = host_no; + + if (strcmp(argv[3], "cmd_type") != 0) { + ps3stor_cli_printf("dev is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[4], 0, &cmd_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse cmd_type!\n"); + goto l_err; + } + pitem->item.mgr_cmd.cmd_type = cmd_type; + + if (strcmp(argv[5], "cmd_sub_type") != 0) { + ps3stor_cli_printf("cmd_sub_type is needed!\n"); + goto l_err; + } + + ret = kstrtouint(argv[6], 0, &cmd_sub_type); + if (ret != 0) { + ps3stor_cli_printf("Can not parse cmd_sub_type!\n"); + goto l_err; + } + + ps3_show_inject_mgr_item(pitem); + return; + +l_err: + kfree(pitem); + return; +} +static void ps3_show_all_inject(int argc, char *argv[]) +{ + ps3_show_inject_all_scsi_rw(argc, argv); + ps3_show_inject_all_scsi_task(argc, argv); + ps3_show_inject_all_mgr(argc, argv); + return; +} + +void ps3_scsi_task_cmd_clear_all(void) +{ + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + PS3HitCmd_s * p_hit_inject = get_hit_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_hit_inject->scsi_task_list)) { + LOG_DEBUG("task inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(p_cmd, p_cmd_next, &p_hit_inject->scsi_task_list, list) { + list_del(&p_cmd->list); + kfree(p_cmd); + } + + if(pitem->item.scsi_task_cmd.inject_count == 0) { + ps3_delete_scsi_task_inject(pitem); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return ; +} + +void ps3_mgr_cmd_clear_all(void) +{ + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + struct inject_cmds_t *pitem = NULL; + PS3Inject_s *p_inject_list = get_inject(); + PS3HitCmd_s * p_hit_inject = get_hit_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_hit_inject->mgr_list)) { + LOG_DEBUG("mgr inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(p_cmd, p_cmd_next, &p_hit_inject->mgr_list, list) { + list_del(&p_cmd->list); + kfree(p_cmd); + } + + if(pitem->item.mgr_cmd.inject_count == 0) { + ps3_delete_mgr_inject(pitem); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return ; +} +void ps3_scsi_rw_cmd_clear_all(void) +{ + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + PS3Inject_s *p_inject_list = get_inject(); + PS3HitCmd_s * p_hit_inject = get_hit_inject(); + + ps3_mutex_lock(&p_inject_list->lock); + if (list_empty(&p_hit_inject->scsi_rw_list)) { + LOG_DEBUG("rw inject cmd list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(p_cmd, p_cmd_next, &p_hit_inject->scsi_rw_list, list) { + list_del(&p_cmd->list); + ps3_scsi_dma_unmap(p_cmd->cmd); + ps3_scsi_cmd_free(p_cmd->cmd); + kfree(p_cmd); + } + +l_out: + ps3_mutex_unlock(&p_inject_list->lock); + return ; +} + +static void ps3_clear_hit_cmd(int argc, char *argv[]) +{ + argc = argc; + argv = argv; + + ps3_scsi_rw_cmd_clear_all(); + ps3_scsi_task_cmd_clear_all(); + ps3_mgr_cmd_clear_all(); +} +void ps3_inject_clear(void) +{ + ps3_scsi_rw_cmd_clear_all(); + ps3_scsi_task_cmd_clear_all(); + ps3_mgr_cmd_clear_all(); + + ps3_clear_all_inject_scsi_rw(); + ps3_clear_all_inject_scsi_task(); + ps3_clear_all_inject_mgr(); +} +#endif + +void ps3_cli_debug_init(void) +{ + int ret = 0; + struct ps3_cli_debug_cmd *cmd = NULL; + U32 table_index = 0; + U32 table_size = ARRAY_SIZE(g_ps3_cli_debug_cmd_table); + for (table_index = 0; table_index < table_size; table_index++) { + cmd = &g_ps3_cli_debug_cmd_table[table_index]; + ret = ps3stor_cli_register(cmd->func, cmd->func_name, cmd->help); + if (ret) { + printk("cli register failed:%s:%d\n", cmd->func_name, ret); + } + } + INJECT_INIT() +} diff --git a/drivers/scsi/ps3stor/linux/ps3_cli_debug.h b/drivers/scsi/ps3stor/linux/ps3_cli_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..63b362c25d382ef2a6a864ef0358369396aae3b3 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_cli_debug.h @@ -0,0 +1,18 @@ + +#ifndef _PS3_CLI_DEBUG_H_ +#define _PS3_CLI_DEBUG_H_ +#include "ps3_instance_manager.h" + +ssize_t ps3_ioc_reg_dump(struct ps3_instance *instance, char *buf); + +void ps3_cli_debug_init(void); + +void ps3_io_statis_dump_cli_cb_test(U8 detail); + +Bool ps3_get_wait_cli_flag(void); +#ifdef PS3_SUPPORT_INJECT + +void ps3_inject_clear(void); +#endif +#endif + diff --git a/drivers/scsi/ps3stor/linux/ps3_driver_log.c b/drivers/scsi/ps3stor/linux/ps3_driver_log.c new file mode 100644 index 0000000000000000000000000000000000000000..d15aa32ec9ca5eae57b29a593f10d662a2682500 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_driver_log.c @@ -0,0 +1,1058 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __KERNEL__ +#include +#endif + +#include "ps3_driver_log.h" +#include "ps3_module_para.h" +S32 g_ramfs_test_enable = 0; + +#if defined DRIVER_DEBUG && defined __KERNEL__ + +#define FILE_NAME_SIZE 128 +#define PS3_KLOG_OUT_WAIT (5 * HZ) +#define DRIVER_SWITCH_FILE +#define LOG_PATH_LEN 100 +#define DRV_LOG_FILE_SIZE_MIN_MB 10 +#define DRV_LOG_FILE_SIZE_MAX_MB 200 + +ps3_debug_t g_ps3_debug; +char g_log_path_str[LOG_PATH_LEN] = {0}; +char g_log_path_bin[LOG_PATH_LEN] = {0}; + +static inline int time_for_log(char *buff, int buf_len) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + struct timeval tv; + struct tm td; + + do_gettimeofday(&tv); + time_to_tm(tv.tv_sec, -sys_tz.tz_minuteswest*60, &td); + + return snprintf(buff, buf_len, "[%04ld-%02d-%02d;%02d:%02d:%02d.%ld]", + td.tm_year + 1900, + td.tm_mon + 1, td.tm_mday, td.tm_hour, + td.tm_min, td.tm_sec, tv.tv_usec); +#else + struct timespec64 tv; + struct tm td; + ktime_get_real_ts64(&tv); + time64_to_tm(tv.tv_sec, -sys_tz.tz_minuteswest*60, &td); + return snprintf(buff, buf_len, "[%04ld-%02d-%02d;%02d:%02d:%02d.%ld]", + td.tm_year + 1900, + td.tm_mon + 1, td.tm_mday, td.tm_hour, + td.tm_min, td.tm_sec, tv.tv_nsec*1000); +#endif +} + +static inline int time_for_file_name(char *buff, int buf_len) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + struct timeval tv; + struct tm td; + + do_gettimeofday(&tv); + time_to_tm(tv.tv_sec, -sys_tz.tz_minuteswest*60, &td); +#else + struct timespec64 tv; + struct tm td; + ktime_get_real_ts64(&tv); + time64_to_tm(tv.tv_sec, -sys_tz.tz_minuteswest*60, &td); +#endif + return snprintf(buff, buf_len, "%04ld-%02d-%02d_%02d:%02d:%02d", + td.tm_year + 1900, td.tm_mon + 1, td.tm_mday, + td.tm_hour, td.tm_min, td.tm_sec); +} + +static inline char *ps3_stack_top(void) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + ULong *ptr = (ULong*)(current->thread_info + 1); +#else + ULong *ptr = (ULong*)(task_thread_info(current) + 1 ); +#endif + return (char*)(ptr + 1); +} + +static inline ps3_thread_local_t *ps3_thread_local_get(ps3_thread_key_t * key) +{ + return (ps3_thread_local_t*)(ps3_stack_top() + key->offset); +} + +void ps3_thread_key_create(int size, ps3_thread_key_t *key) +{ + key->offset = g_ps3_debug.key_offset; + g_ps3_debug.key_offset += sizeof(ps3_thread_local_t) + size; +} + +void *ps3_thread_get_specific(ps3_thread_key_t *key) +{ + ps3_thread_local_t *local = ps3_thread_local_get(key); + if (local->magic != DEBUG_TRACE_MAGIC) + { + return NULL; + } + return (void*)local->data; +} + +void ps3_thread_clear_specific(ps3_thread_key_t *key) +{ + ps3_thread_local_t *local = ps3_thread_local_get(key); + local->magic = 0; +} + +int ps3_filter_file_add(char *name) +{ + debug_file_t *file = NULL; + + file = (debug_file_t*)kmalloc(sizeof(debug_file_t), GFP_ATOMIC); + if (!file){ + ps3_print(KERN_ERR,"kmalloc size %lu failed\n", PAGE_SIZE); + return -ENOMEM; + } + strncpy(file->name, name, sizeof(file->name)); + INIT_LIST_HEAD(&file->list); + + list_add_rcu(&file->list, &g_ps3_debug.filter_file); + return 0; +} + +void ps3_filter_file_del(char *filename) +{ + debug_file_t *file = NULL; + + list_for_each_entry_rcu(file, &g_ps3_debug.filter_file, list){ + if(!strcmp(file->name, filename)){ + list_del_rcu(&file->list); + synchronize_rcu(); + kfree(file); + return; + } + } + return; +} + +#ifndef PS3_CFG_RELEASE +static inline int ps3_filter_file_print(const char *filename) +{ + debug_file_t *file; + rcu_read_lock(); + list_for_each_entry_rcu(file, &g_ps3_debug.filter_file, list){ + if(!strcmp(file->name, filename)){ + rcu_read_unlock(); + return 1; + } + } + rcu_read_unlock(); + return 0; +} + +#endif +void ps3_filter_file_clear(void) +{ + debug_file_t *file = NULL; + + do{ + file = list_first_or_null_rcu( + &g_ps3_debug.filter_file, + debug_file_t, + list); + if (file){ + list_del_rcu(&file->list); + synchronize_rcu(); + kfree(file); + } + }while(file); + + return; +} + +int ps3_filter_func_add(char *name) +{ + debug_func_t *func = NULL; + + func = (debug_func_t *)kmalloc(sizeof(debug_func_t), GFP_ATOMIC); + if (!func){ + ps3_print(KERN_ERR,"kmalloc size %lu failed\n", PAGE_SIZE); + return -ENOMEM; + } + strncpy(func->name, name, sizeof(func->name)); + INIT_LIST_HEAD(&func->list); + + list_add_rcu(&func->list, &g_ps3_debug.filter_func); + return 0; +} + +void ps3_filter_func_del(char *name) +{ + debug_func_t *func = NULL; + + list_for_each_entry_rcu(func, &g_ps3_debug.filter_func, list){ + if(!strcmp(func->name, name)){ + list_del_rcu(&func->list); + synchronize_rcu(); + kfree(func); + return; + } + } + return; +} + +void ps3_filter_func_clear(void) +{ + debug_func_t *func = NULL; + + do{ + func = list_first_or_null_rcu( + &g_ps3_debug.filter_func, + debug_func_t, + list); + if (func){ + list_del_rcu(&func->list); + synchronize_rcu(); + kfree(func); + } + }while(func); + + return; +} + +void ps3_level_set(int level) +{ + g_ps3_debug.level = level; +} + +S32 ps3_level_get(void) +{ + return (S32)g_ps3_debug.level; +} + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) + +static void ps3_file_close(struct file **file) +{ + filp_close(*file, NULL); + *file = NULL; +} + +static int ps3_file_open(ps3_log_t *log, struct file **pp_file) +{ + struct file *file; + int flags_new = O_CREAT | O_RDWR | O_APPEND | O_LARGEFILE; + int flags_rewrite = O_CREAT | O_RDWR | O_LARGEFILE | O_TRUNC; + int err = 0; + int len = 0; + char filename[FILE_NAME_SIZE]; + static unsigned long j; +#ifdef DRIVER_SWITCH_FILE + memset(filename, 0, FILE_NAME_SIZE); + len += snprintf(filename, FILE_NAME_SIZE, "%s", log->file_path); + if (log->file_num == 0) { + time_for_file_name(filename + len, FILE_NAME_SIZE - len); + } else { + snprintf(filename + len, FILE_NAME_SIZE - len, "%04d", log->index++); + log->index = log->index % log->file_num; + } + + if(log->file_num == 1 && log->file != NULL) { + ps3_file_close(&log->file); + log->file_pos = 0; + } +#else + memset(filename, 0, FILE_NAME_SIZE); + strncpy(filename, path, FILE_NAME_SIZE); +#endif + if (log->file_num == 0) { + file = filp_open(filename, flags_new, 0666); + } else { + file = filp_open(filename, flags_rewrite, 0666); + if (IS_ERR(file)) { + err = (int)PTR_ERR(file); + if (err == -ENOENT) { + file = filp_open(filename, flags_new, 0666); + } + } + } + if (IS_ERR(file)) { + err = (int)PTR_ERR(file); + if (printk_timed_ratelimit(&j, PS3_LOG_LIMIT_INTERVAL_MSEC)) { + ps3_print(KERN_INFO,"open file:%s failed[errno:%d]\n", filename, err); + } + goto l_out; + } + + if (!ps3_fs_requires_dev(file)) { +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) + if (printk_timed_ratelimit(&j, PS3_LOG_LIMIT_INTERVAL_MSEC)) { + ps3_print(KERN_INFO, "unexpected filesystem, superblock flags: 0x%x\n", + file->f_inode->i_sb->s_type->fs_flags); + } +#endif + ps3_file_close(&file); + err = -EINVAL; + goto l_out; + } + + mapping_set_gfp_mask(file->f_path.dentry->d_inode->i_mapping, GFP_NOFS); + + ps3_print(KERN_INFO,"redirect file %s\n", filename); + + *pp_file = file; + +l_out: + return err; +} + +static void ps3_file_sync(struct file *file) +{ + struct address_space *mapping; + void *journal; + int ret = 0; + int err; + + (void)ret; + (void)err; + + if( !file || !file->f_op || !file->f_op->fsync ){ + goto l_end; + } + + journal = current->journal_info; + current->journal_info = NULL; + + mapping = file->f_mapping; + + ret = filemap_fdatawrite(mapping); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) + mutex_lock(&mapping->host->i_mutex); + err = file->f_op->fsync(file, file->f_path.dentry, 1); + if( !ret ){ + ret = err; + } + mutex_unlock(&mapping->host->i_mutex); + err = filemap_fdatawait(mapping); + if( !ret ){ + ret = err; + } + +#else + err = file->f_op->fsync(file, 0, file->f_mapping->host->i_size, 1); +#endif + + current->journal_info = journal; + +l_end: + return; +} + +static int ps3_file_write(struct file *file, char *buf, int len) +{ + int ret = 0; + + void *journal; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0) + mm_segment_t old_fs; +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) + old_fs = get_fs(); + set_fs(get_ds()); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + old_fs = get_fs(); + set_fs(KERNEL_DS); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + old_fs = force_uaccess_begin(); +#endif + + journal = current->journal_info; + current->journal_info = NULL; + + if (!file){ + return 0; + } + + do{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,9,0) + ret = file->f_op->write(file, buf, len, &file->f_pos); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0) + ret = vfs_write(file, buf, len, &file->f_pos); +#else + ret = kernel_write(file, buf, len, &file->f_pos); +#endif + }while( ret == -EINTR ); + + if (ret >= 0) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) + fsnotify_modify(file); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) + if ( file->f_path.dentry) { + fsnotify_modify(file->f_path.dentry); + } +#endif + } + + current->journal_info = journal; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + set_fs(old_fs); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + force_uaccess_end(old_fs); +#endif + + return ret; +} + +static void ps3_klog_in(ps3_log_t *log, char *buf, const int len) +{ + int begin = 0; + int end = 0; + int free_size; + ULong flags; + static unsigned long j; + + spin_lock_irqsave(&log->lock, flags); + + if (log->head > log->tail) { + if (printk_timed_ratelimit(&j, PS3_LOG_LIMIT_INTERVAL_MSEC)) { + ps3_print(KERN_INFO,"FAILURE: log head exceeds log tail\n"); + PS3_BUG_NO_SYNC(); + } + } + + free_size = log->buf_size - (log->tail - log->head); + + if (free_size <= len){ + log->is_drop = 1; + spin_unlock_irqrestore(&log->lock, flags); + return; + } + + begin = log->tail % log->buf_size; + end = (log->tail + len) % log->buf_size; + + if (begin < end){ + memcpy(log->buf + begin, buf, len); + } + else{ + memcpy(log->buf + begin, buf, log->buf_size - begin); + memcpy(log->buf, buf + log->buf_size - begin, end); + } + + log->tail = log->tail + len; + + spin_unlock_irqrestore(&log->lock, flags); + + return; +} + +static void ps3_klog_out(ps3_log_t *log) +{ + int len = 0; + int rc = 0; + long long tail; + int begin; + int end; + int schedule_count_th = 0; + const int max_loop = 4096; + static unsigned long j; + +#ifdef DRIVER_SWITCH_FILE + struct file *file = NULL; +#endif + + if (log->file == NULL) { + rc = ps3_file_open(log, &log->file); + if (log->file != NULL) { + log->file_pos = 0; + } else { + return; + } + } + + do { + tail = log->tail; + begin = log->head % log->buf_size; + end = tail % log->buf_size; + len = 0; + rc = 0; + + schedule_count_th++; + if ((schedule_count_th >= max_loop)) { + schedule_count_th = 0; + schedule_timeout_interruptible(PS3_KLOG_OUT_WAIT); + } + + if (log->is_drop) { + rc = ps3_file_write( + log->file, + DEBUG_DROP_LOG_STRING, + strlen(DEBUG_DROP_LOG_STRING)); + if (rc < 0) { + break; + } + log->is_drop = 0; + } + + if (begin < end) { + rc = ps3_file_write( + log->file, + log->buf + begin, + end - begin); + if (rc > 0) { + len += rc; + } + } else if(begin > end) { + rc = ps3_file_write( + log->file, + log->buf + begin, + log->buf_size - begin); + if (rc > 0) { + len += rc; + rc = ps3_file_write(log->file, log->buf, end); + if (rc > 0) { + len += rc; + } + } + } + log->head += len; + log->file_pos += len; + + LOG_BUG_ON(log->head > log->tail, "FAILURE: log head exceeds log tail\n"); + }while (log->head != log->tail && rc > 0); + + if (rc < 0) { + if (printk_timed_ratelimit(&j, PS3_LOG_LIMIT_INTERVAL_MSEC)) { + ps3_print(KERN_INFO,"write file %s error %d\n", log->file_path, rc); + } + return ; + } + +#ifdef DRIVER_SWITCH_FILE + if (log->file_pos >= log->file_size) { + rc = ps3_file_open(log, &file); + if (rc >= 0 && log->file != NULL && log->file_num != 1) { + ps3_file_close(&log->file); + log->file = file; + log->file_pos = 0; + } + } +#endif + return ; +} + +static int ps3_klog_flush(void *arg) +{ + int i; + + while (!kthread_should_stop()){ + schedule_timeout_interruptible(PS3_KLOG_OUT_WAIT); + + for (i = 0; i < ARRAY_SIZE(g_ps3_debug.log); i++){ + ps3_klog_out(&g_ps3_debug.log[i]); + } + } + return 0; +} + +static int ps3_klog_init( + ps3_log_t *log, + long long buf_size, + char *file_path, + long long file_size, + U32 file_num) +{ + int rc = 0; + + memset(log, 0, sizeof(*log)); + spin_lock_init(&log->lock); + + log->buf = (char*)vmalloc(buf_size+PAGE_SIZE); + if (!log->buf){ + rc = -ENOMEM; + goto l_end; + } + + log->file = NULL; + log->head = 0; + log->tail = 0; + log->buf_size = buf_size; + + log->file_path = file_path; + log->file_pos = 0; + log->file_size = file_size; + log->file_num = file_num; + log->index = 0; +l_end: + return rc; +} + +static void ps3_klog_exit(ps3_log_t *log) +{ + if (log->buf) { + vfree(log->buf); + } + if (log->file) { + ps3_file_close(&log->file); + } +} + +static inline char *ps3_file_name_locale(char *file) +{ + char *p_slash = strrchr(file, '/'); + return (p_slash == NULL)?file:(p_slash+1); +} + +void ps3_log_string( + debug_level_e level, + const char *file, + int line, + const char *fmt,...) +{ + ps3_ctxt_t *ctxt = NULL; + char *buf = NULL; + int len = 0; + ULong flags = 0; + + va_list args; + + if (level > g_ps3_debug.level){ +#ifndef PS3_CFG_RELEASE + if (!ps3_filter_file_print(file)){ + return; + } +#else + return; +#endif + } + + if (!in_interrupt()){ + local_irq_save(flags); + } + + ctxt = per_cpu_ptr(g_ps3_debug.ctxt, get_cpu()); + put_cpu(); + + buf = ctxt->buff; + + len = snprintf(buf, PAGE_SIZE, "%s", ps3_debug_level_name(level)); + len += time_for_log(buf+len, PAGE_SIZE - len); + len += snprintf(buf+len, PAGE_SIZE - len, "[%d][%d]%s:%4d:", + raw_smp_processor_id(), current->pid, + ps3_file_name_locale((char*)file), line); + + va_start(args, fmt); + len += vsnprintf( + buf + len, + PAGE_SIZE - len, + fmt, + args); + va_end(args); + + + if (!in_interrupt()){ + local_irq_restore(flags); + } + + if (ps3_log_tty_query()) { + if (buf[0] == 'I' || buf[0] == 'W') { + printk_ratelimited(KERN_WARNING"%s", buf + LOG_INFO_PREFIX_LEN); + } else if (buf[0] == 'E') { + printk_ratelimited(KERN_WARNING"%s", buf + LOG_ERROR_PREFIX_LEN); + } + } + ps3_klog_in(&g_ps3_debug.log[DEBUG_TYPE_STRING], buf, len); + + wake_up_process(g_ps3_debug.task); + + return; +} + +void ps3_log_binary( + const char *file, + int line, + char *ptr, + int size, + char *str) +{ +#define LINE_TOTAL 16 + ps3_ctxt_t *ctxt = NULL; + char *buf = NULL; + int len = 0; + int i; + ULong flags = 0; + + if (!in_interrupt()){ + local_irq_save(flags); + } + + ctxt = per_cpu_ptr(g_ps3_debug.ctxt, get_cpu()); + put_cpu(); + + buf = ctxt->buff; + + len += time_for_log(buf+len, PAGE_SIZE - len); + len += snprintf(buf+len, PAGE_SIZE - len, "[%d]%s:%d, size:%d, ", + current->pid, ps3_file_name_locale((char*)file), + line, size); + + len+=snprintf(buf + len, PAGE_SIZE - len, "%s",str); + + for(i = 0; i < size; i++){ + if (i % LINE_TOTAL == 0){ + len += snprintf(buf + len, PAGE_SIZE - len, "%08x ", i); + } + + len += snprintf(buf + len, PAGE_SIZE - len, "%02hhx", ptr[i]); + if ((i % LINE_TOTAL) == (LINE_TOTAL - 1) || i == (size - 1)){ + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + } else if ((i % LINE_TOTAL) == (LINE_TOTAL/2 - 1)){ + len += snprintf(buf + len, PAGE_SIZE - len, " "); + } else{ + len += snprintf(buf + len, PAGE_SIZE - len, " "); + } + } + + if (!in_interrupt()){ + local_irq_restore(flags); + } + + ps3_klog_in(&g_ps3_debug.log[DEBUG_TYPE_BINARY], buf, len); + + wake_up_process(g_ps3_debug.task); +} + +void ps3_log_sync(void) +{ + ps3_file_sync(g_ps3_debug.log[DEBUG_TYPE_STRING].file); + ps3_file_sync(g_ps3_debug.log[DEBUG_TYPE_BINARY].file); +} + +int ps3_debug_init(void) +{ + struct task_struct *task = NULL; + ps3_ctxt_t *ctxt = NULL; + int rc = 0; + int i; + int nid; + U32 file_num = 0; + U32 log_path_len = 0; + U32 input_log_space = ps3_log_space_size_query(); + U32 input_log_file_size = ps3_log_file_size_query(); + unsigned int log_file_size = 0; + char *log_path_p = NULL; + ps3_log_t *log_bin = &g_ps3_debug.log[DEBUG_TYPE_BINARY]; + ps3_log_t *log_str = &g_ps3_debug.log[DEBUG_TYPE_STRING]; + + INIT_LIST_HEAD(&g_ps3_debug.filter_file); + INIT_LIST_HEAD(&g_ps3_debug.filter_func); + + g_ps3_debug.level = ps3_log_level_query(); + g_ps3_debug.ctxt = alloc_percpu(ps3_ctxt_t); + if (!g_ps3_debug.ctxt) { + rc = -ENOMEM; + ps3_print(KERN_ERR,"alloc percpu failed\n"); + goto l_end; + } + + for_each_possible_cpu(i) { + ctxt = per_cpu_ptr(g_ps3_debug.ctxt, i); + memset(ctxt, 0, sizeof(*ctxt)); + } + + for_each_possible_cpu(i) { + ctxt = per_cpu_ptr(g_ps3_debug.ctxt, i); + nid = cpu_to_node(i); + + ctxt->page = alloc_pages_node(nid, GFP_ATOMIC, 0); + if (!ctxt->page) { + rc = -ENOMEM; + ps3_print(KERN_ERR,"kmalloc size %lu failed\n", PAGE_SIZE); + goto l_free_cpu_buff; + } + ctxt->buff = kmap(ctxt->page); + } + + log_path_p = ps3_log_path_query(); + log_path_len = strlen(log_path_p); + if (log_path_p != NULL && log_path_p[0] == '/') { + if (log_path_p[log_path_len - 1] == '/') { + snprintf(g_log_path_str, LOG_PATH_LEN, "%s%s.", log_path_p, LOG_FILE_PREFIX); + snprintf(g_log_path_bin, LOG_PATH_LEN, "%s%s.", log_path_p, BINARY_FILE_PREFIX); + } else { + snprintf(g_log_path_str, LOG_PATH_LEN, "%s/%s.", log_path_p, LOG_FILE_PREFIX); + snprintf(g_log_path_bin, LOG_PATH_LEN, "%s/%s.", log_path_p, BINARY_FILE_PREFIX); + } + } else { + snprintf(g_log_path_str, LOG_PATH_LEN, "%s.", LOG_FILE_PATH); + snprintf(g_log_path_bin, LOG_PATH_LEN, "%s.", BINARY_FILE_PATH); + } + if (input_log_file_size < DRV_LOG_FILE_SIZE_MIN_MB || + input_log_file_size > DRV_LOG_FILE_SIZE_MAX_MB) { + ps3_log_file_size_modify(LOG_FILE_SIZE >> MEGABYTE); + input_log_file_size = LOG_FILE_SIZE >> MEGABYTE; + } + if (input_log_space && input_log_space < input_log_file_size) { + ps3_log_file_size_modify(input_log_space); + input_log_file_size = input_log_space; + } + log_file_size = input_log_file_size << MEGABYTE; + + if (input_log_space) { + file_num = input_log_space / input_log_file_size; + if (file_num == 0) { + ps3_print(KERN_ERR,"filenum shouldnot be 0\n"); + PS3_BUG(); + } + } else { + file_num = 0; + } + + rc = ps3_klog_init( + log_str, + LOG_BUF_SIZE, + g_log_path_str, + log_file_size, + file_num); + if (rc < 0) { + goto l_free_cpu_buff; + } + + rc = ps3_klog_init( + log_bin, + BIN_BUF_SIZE, + g_log_path_bin, + BINARY_FILE_SIZE, + 0); + if (rc < 0) { + goto l_free_string; + } + + task = kthread_create(ps3_klog_flush, NULL, "ps3_klog_flush"); + if (IS_ERR(task)) { + rc = (int)PTR_ERR(task); + ps3_print(KERN_ERR,"Create kernel thread, err: %d\n", rc); + goto l_free_binary; + } + wake_up_process(task); + g_ps3_debug.task = task; + rc = 0; + ps3_print(KERN_INFO,"PS3 debug init logpath[%s] strlogsize[%dM] filenum[%d]\n", + g_log_path_str, (log_file_size >> MEGABYTE), log_str->file_num); +l_end: + return rc; + +l_free_binary: + ps3_klog_exit(&g_ps3_debug.log[DEBUG_TYPE_BINARY]); + +l_free_string: + ps3_klog_exit(&g_ps3_debug.log[DEBUG_TYPE_STRING]); + +l_free_cpu_buff: + for_each_possible_cpu(i) { + ctxt = per_cpu_ptr(g_ps3_debug.ctxt, i); + if (ctxt && ctxt->page) { + kunmap(ctxt->page); + __free_page(ctxt->page); + } + } + free_percpu(g_ps3_debug.ctxt); + goto l_end; +} + +void ps3_debug_exit(void) +{ + int i = 0; + ps3_ctxt_t *ctxt; + + if (g_ps3_debug.task == NULL) { + return; + } + + kthread_stop(g_ps3_debug.task); + + for (i = 0; i < ARRAY_SIZE(g_ps3_debug.log); i++) { + ps3_klog_exit(&g_ps3_debug.log[i]); + } + + if (g_ps3_debug.ctxt) { + for_each_possible_cpu(i) { + ctxt = per_cpu_ptr(g_ps3_debug.ctxt, i); + if (ctxt && ctxt->page) { + kunmap(ctxt->page); + __free_page(ctxt->page); + } + } + + free_percpu(g_ps3_debug.ctxt); + g_ps3_debug.ctxt = NULL; + } +} +#else + +void ps3_log_sync(void) +{ +} + +int ps3_debug_init(void) +{ + g_ps3_debug.level = LEVEL_WARN; + return 0; +}; + +void ps3_debug_exit(void) +{ +} + +#endif + +#if 0 + +struct task_struct *g_ps3_task[8]; +static int ps3_log_test(void *arg) +{ + int i = 0; + int dump[16] = {}; + while(!kthread_should_stop()){ + for(i = 0; i < 1024; i++) { + LOG_WARN("hello world,%d\n",i); + DATA_DUMP(dump, sizeof(dump), "123\n"); + } + schedule_timeout_interruptible(8*HZ); + } + return 0; +} + +static int __init ps3_init(void) +{ + int rc = 0; + int i = 0; + int dump[16] = {}; + rc = ps3_debug_init(); + if (rc < 0){ + return rc; + } + + for (i = 0; i < 8; i++){ + LOG_WARN("hello world,%d\n",i); + DATA_DUMP(dump, sizeof(dump), "123\n"); + } + + for (i = 0; i < 8; i++){ + g_ps3_task[i] = kthread_create(ps3_log_test, NULL, "ps3_log_test"); + wake_up_process(g_ps3_task[i]); + } + return 0; +} + +static void __exit ps3_exit(void) +{ + int i; + for (i = 0; i < 8; i++){ + kthread_stop(g_ps3_task[i]); + } + ps3_debug_exit(); +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("ps3@starsmicrosystem.com"); +MODULE_DESCRIPTION("Stars PS3 Driver"); + +module_init(ps3_init); +module_exit(ps3_exit); + +#endif + +#else + +S32 g_ps3_log_level = LEVEL_INFO; + +void ps3_thread_key_create(int size, ps3_thread_key_t *key) +{ + size = size; + key = key; +} + +void *ps3_thread_get_specific(ps3_thread_key_t *key) +{ + key = key; + return key; +} + +void ps3_thread_clear_specific(ps3_thread_key_t *key) +{ + key = key; +} + +int ps3_filter_file_add(char *name) +{ + name = name; + return 0; +} +void ps3_filter_file_del(char *name) +{ + name = name; +} +void ps3_filter_file_clear(void) +{ +} + +int ps3_filter_func_add(char *name) +{ + name = name; + return 0; +} +void ps3_filter_func_del(char *name) +{ + name = name; +} +void ps3_filter_func_clear(void) +{ +} +void ps3_level_set(int level) +{ + g_ps3_log_level = level; +} + +S32 ps3_level_get(void) +{ + return g_ps3_log_level; +} + +void ps3_log_sync(void) +{ +} + +int ps3_debug_init(void) +{ + g_ps3_log_level = LEVEL_WARN; + return 0; +}; + +void ps3_debug_exit(void) +{ +} + +#endif + diff --git a/drivers/scsi/ps3stor/linux/ps3_driver_log.h b/drivers/scsi/ps3stor/linux/ps3_driver_log.h new file mode 100644 index 0000000000000000000000000000000000000000..c84ae285975081604e72170e37aec010efbfa7e6 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_driver_log.h @@ -0,0 +1,565 @@ +#ifndef _PS3_DRIVER_LOG_H_ +#define _PS3_DRIVER_LOG_H_ + +#include +#include +#include +#include + +#include "ps3_htp_def.h" +#ifdef __cplusplus +extern "C"{ +#endif + +#define PS3_HOST(ins) (ins)->host->host_no +#define DRIVER_DEBUG + +#define LOG_INFO_PREFIX_LEN 32 +#define LOG_ERROR_PREFIX_LEN 33 +#define MEGABYTE 20 + +typedef enum { + LEVEL_ERROR, + LEVEL_WARN, + LEVEL_INFO, + LEVEL_DEBUG, +}debug_level_e; + +static inline const S8 *ps3_debug_level_name(debug_level_e lv) +{ + static const S8 *level[] = { + [LEVEL_ERROR] = "ERROR", + [LEVEL_WARN] = "WARN", + [LEVEL_INFO] = "INFO", + [LEVEL_DEBUG] = "DBG", + }; + + return level[lv]; +} + +S32 ps3_level_get(void); +#define PS3_LOG_LIMIT_INTERVAL_MSEC (24 * 60 * 60 * 1000) +#ifdef __KERNEL__ + +#define PRINT_DEBUG KERN_DEBUG +#define PRINT_INFO KERN_INFO +#define PRINT_WARN KERN_WARNING +#define PRINT_ERR KERN_ERR + +#define ps3_print(level,fmt,...) \ + printk(level"[PS3STOR]%s():%d;" fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__) + +#define ps3_printk(level,fmt,...) do { \ + if (level <= ps3_level_get()) { \ + if (level == LEVEL_DEBUG) { \ + printk(KERN_DEBUG "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + } else if (level == LEVEL_INFO) { \ + printk(KERN_INFO "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + } else if (level == LEVEL_WARN) { \ + printk(KERN_WARNING "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + }else if (level == LEVEL_ERROR) { \ + printk(KERN_ERR "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + } \ + } \ +} while(0) + +#define ps3_printk_ratelimited(level,fmt,...) do { \ + if (level <= ps3_level_get()) { \ + if (level == LEVEL_INFO) { \ + pr_info_ratelimited(KERN_INFO "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + } else if (level == LEVEL_WARN) { \ + printk_ratelimited(KERN_WARNING "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + }else if (level == LEVEL_ERROR) { \ + printk_ratelimited(KERN_ERR "[PS3STOR][%u]%d;" fmt, \ + current->pid, __LINE__, ##__VA_ARGS__); \ + } \ + } \ +} while(0) + +#else + +#define PRINT_DEBUG LEVEL_DEBUG +#define PRINT_INFO LEVEL_INFO +#define PRINT_WARN LEVEL_WARN +#define PRINT_ERR LEVEL_ERROR + +#include +#include +#include +#define __percpu + +static inline U64 get_now_ms() { + struct timeval tv; + U64 timestamp = 0; + gettimeofday(&tv, NULL); + timestamp = tv.tv_sec * 1000 + tv.tv_usec/1000; + return timestamp; +} + +#define filename_printf(x) strrchr((x),'/')?strrchr((x),'/')+1:(x) + +#define ps3_print(lock_chk,level,fmt,...) do { \ + if (level != LEVEL_DEBUG && lock_chk) { \ + EXPECT_EQ(ps3_get_irq_spin_lock_count(), 0); \ + } \ + if (level <= ps3_level_get()) { \ + if (level == LEVEL_DEBUG) { \ + printf("DEBUG:%llu:%s:%s():%d:[%lu];" fmt, get_now_ms(), filename_printf(__FILE__), \ + __FUNCTION__, __LINE__, pthread_self(), ##__VA_ARGS__); \ + } else if (level == LEVEL_INFO) { \ + printf("INFO:%llu:%s:%s():%d:[%lu];" fmt, get_now_ms(), filename_printf(__FILE__), \ + __FUNCTION__, __LINE__, pthread_self(), ##__VA_ARGS__); \ + } else if (level == LEVEL_WARN) { \ + printf("WARN:%llu:%s:%s():%d:[%lu];" fmt, get_now_ms(), filename_printf(__FILE__), \ + __FUNCTION__, __LINE__, pthread_self(), ##__VA_ARGS__); \ + }else if (level == LEVEL_ERROR) { \ + printf("ERROR:%llu:%s:%s():%d:[%lu];" fmt, get_now_ms(), filename_printf(__FILE__), \ + __FUNCTION__, __LINE__, pthread_self(), ##__VA_ARGS__); \ + } \ + } \ +} while(0) + +#endif + +#define LOG_BUG_ON(cond, fmt, ...) do { \ + if((cond)) { \ + LOG_ERROR(fmt, ##__VA_ARGS__); \ + LOG_SYNC(); \ + BUG(); \ + } \ +}while(0) + +#define DEBUG_TRACE_MAGIC 0x456789 +#define LOG_BUF_SIZE (1024LL << 11) +#define BIN_BUF_SIZE (1024LL << 10) + +#define LOG_FILE_SIZE (200LL << 20) +#define LOG_FILE_PATH "/var/log/ps3sas_drv.log" +#define LOG_FILE_PREFIX "ps3sas_drv.log" +#define BINARY_FILE_PREFIX "ps3sas_drv.bin" + +#define BINARY_FILE_SIZE (200LL << 20) +#define BINARY_FILE_PATH "/var/log/ps3sas_drv.bin" + +#define DEBUG_DROP_LOG_STRING "\nwarnning:drop some logs\n\n" + +enum { + DEBUG_TYPE_STRING, + DEBUG_TYPE_BINARY, + DEBUG_TYPE_NR, +}; + +typedef struct { + struct list_head list; + char name[64]; +} debug_func_t; + +typedef struct { + struct list_head list; + char name[64]; +} debug_file_t; + +typedef struct { + struct { + char *buf; + int buf_size; + long long head; + long long tail; + spinlock_t lock; + unsigned char is_drop; + }; + struct { + char *file_path; + struct file *file; + long long file_pos; + long long file_size; + U32 file_num; + U32 index; + }; +} ps3_log_t; + +typedef struct { + S32 magic; + char data[0]; +} ps3_thread_local_t; + +typedef struct { + struct page *page; + void *buff; +} ps3_ctxt_t; + +typedef struct { + S32 offset; +} ps3_thread_key_t; + +typedef struct { + debug_level_e level; + U16 key_offset; + ps3_ctxt_t __percpu *ctxt; + struct list_head filter_func; + struct list_head filter_file; + struct task_struct *task; + ps3_log_t log[DEBUG_TYPE_NR]; +} ps3_debug_t; + +void ps3_thread_key_create(int size, ps3_thread_key_t *key); +void *ps3_thread_get_specific(ps3_thread_key_t *key); +void ps3_thread_clear_specific(ps3_thread_key_t *key); + +int ps3_filter_file_add(char *name); +void ps3_filter_file_del(char *name); +void ps3_filter_file_clear(void); + +int ps3_filter_func_add(char *name); +void ps3_filter_func_del(char *name); +void ps3_filter_func_clear(void); +void ps3_level_set(int level); +S32 ps3_level_get(void); + +int ps3_debug_init(void); +void ps3_debug_exit(void); + +void ps3_log_string(debug_level_e level, const char *file, + int line, const char *fmt, ...); + +void ps3_log_binary(const char *file, int line, char *ptr, + S32 size, char *str); + +void ps3_log_sync(void); + +extern S32 g_ramfs_test_enable; +static inline S32 ps3_ramfs_test_query(void) +{ + return g_ramfs_test_enable; +} + +static inline void ps3_ramfs_test_store(S32 val) +{ + g_ramfs_test_enable = val; +} + +#if defined DRIVER_DEBUG && defined __KERNEL__ + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) + +#define WRITE_LOG(level, fmt, ...) \ + ps3_log_string(level, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#define LOG_DEBUG(fmt, ...) WRITE_LOG(LEVEL_DEBUG, fmt, ##__VA_ARGS__) +#define LOG_INFO(fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG_WARN(fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG_ERROR(fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG2_DEBUG(fmt, ...) WRITE_LOG(LEVEL_DEBUG, fmt, ##__VA_ARGS__); \ + ps3_print(PRINT_DEBUG, fmt, ##__VA_ARGS__) +#define LOG2_INFO(fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__); \ + ps3_print(PRINT_INFO, fmt, ##__VA_ARGS__) +#define LOG2_WARN(fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__); \ + ps3_print(PRINT_WARN, fmt, ##__VA_ARGS__) +#define LOG2_ERROR(fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__); \ + ps3_print(PRINT_ERR, fmt, ##__VA_ARGS__) + +#define LOG_LEVEL(log_lvl, fmt, ...) WRITE_LOG(log_lvl, fmt, ##__VA_ARGS__) + +#define LOG_INFO_LIM(fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG_WARN_LIM(fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG_ERROR_LIM(fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_INFO_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + (void)caller_jiffies; \ + (void)time; \ + WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__); \ +}while(0) +#define LOG_WARN_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + (void)caller_jiffies; \ + (void)time; \ + WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__); \ +}while(0) +#define LOG_ERROR_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + (void)caller_jiffies; \ + (void)time; \ + WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__); \ +}while(0) + +#define LOG2_INFO_LIM(fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG2_WARN_LIM(fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG2_ERROR_LIM(fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_FILE_INFO(fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG_FILE_WARN(fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG_FILE_ERROR(fmt, ...)WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_SPC_ERROR(fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_INFO_IN_IRQ(ins, fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG_WARN_IN_IRQ(ins, fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG_ERROR_IN_IRQ(ins, fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_INFO_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) WRITE_LOG(LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG_WARN_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) WRITE_LOG(LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG_ERROR_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) WRITE_LOG(LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_SYNC() ps3_log_sync() +#define DATA_DUMP(ptr, size, str) \ + ps3_log_binary(__FILE__, __LINE__, (char*)ptr, size, str) +#else + +#define LOG_DEBUG(fmt, ...) ps3_printk(LEVEL_DEBUG, fmt, ##__VA_ARGS__); +#define LOG_INFO(fmt, ...) ps3_printk(LEVEL_INFO, fmt, ##__VA_ARGS__); +#define LOG_WARN(fmt, ...) ps3_printk(LEVEL_WARN, fmt, ##__VA_ARGS__); +#define LOG_ERROR(fmt, ...) ps3_printk(LEVEL_ERROR, fmt, ##__VA_ARGS__); + +#define LOG2_DEBUG(fmt, ...) ps3_print(PRINT_DEBUG, fmt, ##__VA_ARGS__); +#define LOG2_INFO(fmt, ...) ps3_print(PRINT_INFO, fmt, ##__VA_ARGS__); +#define LOG2_WARN(fmt, ...) ps3_print(PRINT_WARN, fmt, ##__VA_ARGS__); +#define LOG2_ERROR(fmt, ...) ps3_print(PRINT_ERR, fmt, ##__VA_ARGS__); + +#define LOG_INFO_LIM(fmt, ...) ps3_printk_ratelimited(LEVEL_INFO, fmt, ##__VA_ARGS__); +#define LOG_WARN_LIM(fmt, ...) ps3_printk_ratelimited(LEVEL_WARN, fmt, ##__VA_ARGS__); +#define LOG_ERROR_LIM(fmt, ...) ps3_printk_ratelimited(LEVEL_ERROR, fmt, ##__VA_ARGS__); + +#define LOG_INFO_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + if (printk_timed_ratelimit(caller_jiffies, time)) { \ + ps3_printk(LEVEL_INFO, fmt, ##__VA_ARGS__); \ + } \ +}while(0) +#define LOG_WARN_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + if (printk_timed_ratelimit(caller_jiffies, time)) { \ + ps3_printk(LEVEL_WARN, fmt, ##__VA_ARGS__); \ + } \ +}while(0) +#define LOG_ERROR_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + if (printk_timed_ratelimit(caller_jiffies, time)) { \ + ps3_printk(LEVEL_ERROR, fmt, ##__VA_ARGS__); \ + } \ +}while(0) + +#define LOG2_INFO_LIM(fmt, ...) LOG_INFO_LIM(fmt, ##__VA_ARGS__) +#define LOG2_WARN_LIM(fmt, ...) LOG_WARN_LIM(fmt, ##__VA_ARGS__) +#define LOG2_ERROR_LIM(fmt, ...) LOG_ERROR_LIM(fmt, ##__VA_ARGS__) + +#define LOG_SPC_ERROR(fmt, ...) LOG_INFO(fmt, ##__VA_ARGS__) + +#define LOG_FILE_INFO(fmt, ...) +#define LOG_FILE_WARN(fmt, ...) +#define LOG_FILE_ERROR(fmt, ...) + +#define LOG_LEVEL(log_lvl, fmt, ...) ps3_printk(log_lvl, fmt, ##__VA_ARGS__) + +#define LOG_INFO_IN_IRQ(ins, fmt, ...) do { \ + if((ins)->is_irq_prk_support) { \ + ps3_printk(LEVEL_INFO, fmt, ##__VA_ARGS__); \ + } \ +}while(0) + +#define LOG_WARN_IN_IRQ(ins, fmt, ...) do { \ + if((ins)->is_irq_prk_support) { \ + ps3_printk(LEVEL_WARN, fmt, ##__VA_ARGS__); \ + } \ +}while(0) + +#define LOG_ERROR_IN_IRQ(ins, fmt, ...) do { \ + if((ins)->is_irq_prk_support) { \ + ps3_printk(LEVEL_ERROR, fmt, ##__VA_ARGS__); \ + } \ +}while(0) + +#define LOG_INFO_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) do { \ + if (need_prk_err) { \ + LOG_INFO_LIM(fmt, ##__VA_ARGS__); \ + } else { \ + LOG_INFO_IN_IRQ((ins), fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#define LOG_WARN_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) do { \ + if (need_prk_err) { \ + LOG_WARN_LIM(fmt, ##__VA_ARGS__); \ + } else { \ + LOG_WARN_IN_IRQ((ins), fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#define LOG_ERROR_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) do { \ + if (need_prk_err) { \ + LOG_ERROR_LIM(fmt, ##__VA_ARGS__); \ + } else { \ + LOG_ERROR_IN_IRQ((ins), fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#define LOG_SYNC() +#define DATA_DUMP(ptr, size, str) +#endif + +static inline Bool ps3_fs_requires_dev(struct file *fp) +{ + if (ps3_ramfs_test_query()) { + return PS3_FALSE; + } + return (fp->f_inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV); +} + +#else + +#define LOG_DEBUG(fmt, ...) ps3_print(PS3_TRUE, PRINT_DEBUG, fmt, ##__VA_ARGS__) +#define LOG_INFO(fmt, ...) ps3_print(PS3_TRUE, PRINT_INFO, fmt, ##__VA_ARGS__) +#define LOG_WARN(fmt, ...) ps3_print(PS3_TRUE, PRINT_WARN, fmt, ##__VA_ARGS__) +#define LOG_ERROR(fmt, ...) ps3_print(PS3_TRUE, PRINT_ERR, fmt, ##__VA_ARGS__) + +#define LOG2_DEBUG(fmt, ...) ps3_print(PS3_TRUE, PRINT_DEBUG, fmt, ##__VA_ARGS__) +#define LOG2_INFO(fmt, ...) ps3_print(PS3_TRUE, PRINT_INFO, fmt, ##__VA_ARGS__) +#define LOG2_WARN(fmt, ...) ps3_print(PS3_TRUE, PRINT_WARN, fmt, ##__VA_ARGS__) +#define LOG2_ERROR(fmt, ...) ps3_print(PS3_TRUE, PRINT_ERR, fmt, ##__VA_ARGS__) + +#define LOG_LEVEL(log_lvl, fmt, ...) ps3_print(PS3_TRUE, log_lvl, fmt, ##__VA_ARGS__) + +#define LOG_INFO_LIM(fmt, ...) ps3_print(PS3_TRUE, LEVEL_INFO, fmt, ##__VA_ARGS__) +#define LOG_WARN_LIM(fmt, ...) ps3_print(PS3_TRUE, LEVEL_WARN, fmt, ##__VA_ARGS__) +#define LOG_ERROR_LIM(fmt, ...) ps3_print(PS3_TRUE, LEVEL_ERROR, fmt, ##__VA_ARGS__) + +#define LOG_INFO_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + (void)caller_jiffies; \ + (void)time; \ + ps3_print(PS3_TRUE, LEVEL_INFO, fmt, ##__VA_ARGS__); \ +}while(0) +#define LOG_WARN_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + (void)caller_jiffies; \ + (void)time; \ + ps3_print(PS3_TRUE, LEVEL_WARN, fmt, ##__VA_ARGS__); \ +}while(0) +#define LOG_ERROR_TIME_LIM(caller_jiffies, time, fmt, ...) do { \ + (void)caller_jiffies; \ + (void)time; \ + ps3_print(PS3_TRUE, LEVEL_ERROR, fmt, ##__VA_ARGS__); \ +}while(0) + +#define LOG2_INFO_LIM(fmt, ...) LOG_INFO_LIM(fmt, ##__VA_ARGS__) +#define LOG2_WARN_LIM(fmt, ...) LOG_WARN_LIM(fmt, ##__VA_ARGS__) +#define LOG2_ERROR_LIM(fmt, ...) LOG_ERROR_LIM(fmt, ##__VA_ARGS__) + +#define LOG_FILE_INFO(fmt, ...) +#define LOG_FILE_WARN(fmt, ...) +#define LOG_FILE_ERROR(fmt, ...) + +#define LOG_SPC_ERROR(fmt, ...) LOG_INFO(fmt, ##__VA_ARGS__) + +#define LOG_INFO_IN_IRQ(ins, fmt, ...) do { \ + (void)ins; \ + ps3_print(PS3_FALSE, LEVEL_INFO, fmt, ##__VA_ARGS__); \ +}while(0) +#define LOG_WARN_IN_IRQ(ins, fmt, ...) do { \ + (void)ins; \ + ps3_print(PS3_FALSE, LEVEL_WARN, fmt, ##__VA_ARGS__); \ +}while(0) +#define LOG_ERROR_IN_IRQ(ins, fmt, ...) do { \ + (void)ins; \ + ps3_print(PS3_FALSE, LEVEL_ERROR, fmt, ##__VA_ARGS__); \ +}while(0) + +#define LOG_INFO_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) do { \ + (void)ins; \ + ps3_print((need_prk_err), LEVEL_INFO, fmt, ##__VA_ARGS__); \ +} while(0) + +#define LOG_WARN_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) do { \ + (void)ins; \ + ps3_print((need_prk_err), LEVEL_WARN, fmt, ##__VA_ARGS__); \ +} while(0) + +#define LOG_ERROR_LIM_WITH_CHECK(ins, need_prk_err, fmt, ...) do { \ + (void)ins; \ + ps3_print((need_prk_err), LEVEL_ERROR, fmt, ##__VA_ARGS__); \ +} while(0) + +#define LOG_SYNC() +#define DATA_DUMP(ptr, size, str) + +static inline Bool ps3_fs_requires_dev(struct file *fp) +{ + (void)fp; + return PS3_TRUE; +} +#endif + +#ifdef PS3_CFG_RELEASE + +#define PS3_BUG() +#define PS3_BUG_NO_SYNC() + +#if defined(PS3_CFG_OCM_DBGBUG) || defined(PS3_CFG_OCM_RELEASE) + +#define PS3_BUG_ON(cond) do { \ + if((cond)) { \ + printk(KERN_ERR "BUG_ON's condition(%s) has been triggered\n", #cond); \ + LOG_ERROR("BUG_ON's condition(%s) has been triggered\n", #cond); \ + } \ +}while(0) + +#define PS3_BUG_ON_NO_SYNC(cond) do { \ + if((cond)) { \ + printk(KERN_ERR "BUG_ON's condition(%s) has been triggered\n", #cond); \ + LOG_ERROR("BUG_ON's condition(%s) has been triggered\n", #cond); \ + } \ +}while(0) + +#else +#define PS3_BUG_ON(cond) do { \ + if((cond)) { \ + printk(KERN_ERR "BUG_ON's condition(%s) has been triggered\n", #cond); \ + } \ + }while(0) + +#define PS3_BUG_ON_NO_SYNC(cond) do { \ + if((cond)) { \ + printk(KERN_ERR "BUG_ON's condition(%s) has been triggered\n", #cond); \ + } \ + }while(0) + +#endif + +#else +#define PS3_BUG_ON(cond) do { \ + if((cond)) { \ + printk(KERN_ERR "BUG_ON's condition(%s) has been triggered\n", #cond); \ + LOG_ERROR("BUG_ON's condition(%s) has been triggered\n", #cond); \ + LOG_SYNC(); \ + } \ + BUG_ON(cond); \ +}while(0) + +#define PS3_BUG(void) do { \ + LOG_SYNC(); \ + BUG(void); \ +}while(0) + +#define PS3_BUG_ON_NO_SYNC(cond) do { \ + if((cond)) { \ + printk(KERN_ERR "BUG_ON's condition(%s) has been triggered\n", #cond); \ + LOG_ERROR("BUG_ON's condition(%s) has been triggered\n", #cond); \ + } \ + BUG_ON(cond); \ +}while(0) + +#define PS3_BUG_NO_SYNC(void) do { \ + BUG(void); \ +}while(0) + +#endif + +#define PS3_WARN_ON(cond) do { \ + WARN_ON(cond); \ +}while(0) + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/scsi/ps3stor/linux/ps3_dump.c b/drivers/scsi/ps3stor/linux/ps3_dump.c new file mode 100644 index 0000000000000000000000000000000000000000..d6cda7b3f8976d9731fd4317ac714ab5a47d233e --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_dump.c @@ -0,0 +1,1024 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ps3_dump.h" +#include "ps3_mgr_cmd.h" +#include "ps3_cmd_channel.h" +#include "ps3_mgr_channel.h" +#include "ps3_cmd_statistics.h" +#include "ps3_ioc_manager.h" +#include "ps3_util.h" +#include "ps3_cli.h" +#include "ps3_module_para.h" +#include "ps3_err_inject.h" + +static inline void ps3_dump_status_set(struct ps3_instance *instance, + U64 value); + +S32 ps3_dump_local_time(struct rtc_time *tm) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + struct timeval time; + U64 local_time; + + do_gettimeofday(&time); + local_time = (U64)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); + rtc_time_to_tm(local_time, tm); +#else + struct timespec64 time; + U64 local_time; + + ktime_get_real_ts64(&time); + local_time = (U64)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); + rtc_time64_to_tm(local_time, tm); +#endif + tm->tm_mon += 1; + tm->tm_year += 1900; + return 0; +} + +S32 ps3_dump_filename_build(struct ps3_instance *instance, + char *filename, U32 len, U8 *prefix) +{ + struct ps3_dump_context *ctxt = &instance->dump_context; + struct rtc_time tm; + char *p_str = filename; + + if (filename == NULL || prefix == NULL) { + return -1; + } + + ps3_dump_local_time(&tm); + p_str += snprintf(p_str, len - (p_str - filename), "%s", ctxt->dump_dir); + p_str += snprintf(p_str, len - (p_str - filename), (const char*)prefix); + p_str += snprintf(p_str, len - (p_str - filename), "host%d-", instance->host->host_no); + p_str += snprintf(p_str, len - (p_str - filename), "%04d%02d%02d-%02d%02d%02d-", + tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + p_str += snprintf(p_str, len - (p_str - filename), "%llu", instance->ioc_fw_version); + + return 0; +} + +S32 ps3_dump_file_open(struct ps3_dump_context *ctxt, U32 dump_type) +{ + struct ps3_dump_file_info *file_info = &ctxt->dump_out_file; + U8 filename[PS3_DUMP_FILE_NAME_LEN] = {0}; + U8 *p_prefix = NULL; + S32 ret = PS3_SUCCESS; + struct file *fp = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0) + mm_segment_t old_fs; +#endif + + if (file_info->fp || file_info->file_status == PS3_DUMP_FILE_OPEN) { + LOG_INFO("dump file open: file already open\n"); + ret = -PS3_FAILED; + goto l_out; + } + + memset(file_info, 0, sizeof(struct ps3_dump_file_info)); + + switch (dump_type){ + case PS3_DUMP_TYPE_FW_LOG: + p_prefix = (U8*)PS3_DUMP_FILE_FWLOG_PREFIX; + break; + case PS3_DUMP_TYPE_BAR_DATA: + p_prefix = (U8*)PS3_DUMP_FILE_BAR_PREFIX; + break; + case PS3_DUMP_TYPE_CRASH: + p_prefix = (U8*)PS3_DUMP_FILE_CORE_PREFIX; + break; + default: + LOG_INFO("dump file create: unknown dump type %d\n", dump_type); + ret = -PS3_FAILED; + goto l_out; + } + + if (ps3_dump_filename_build(ctxt->instance, (char*)filename, + PS3_DUMP_FILE_NAME_LEN, p_prefix) != 0) { + LOG_INFO("dump file create: filename build NOK\n"); + ret = -PS3_FAILED; + goto l_out; + } + + fp = (struct file*)filp_open((char*)filename, O_CREAT |O_RDWR | O_TRUNC | O_LARGEFILE, 0); + if (IS_ERR(fp)) { + LOG_INFO("dump file create: filp_open error filename %s errno %d\n", filename, (int)PTR_ERR(fp)); + ret = -PS3_FAILED; + goto l_out; + } + if (!ps3_fs_requires_dev(fp)) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) + old_fs = get_fs(); + set_fs(get_ds() ); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + old_fs = get_fs(); + set_fs( KERNEL_DS ); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + old_fs = force_uaccess_begin(); +#endif + filp_close(fp, NULL); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + set_fs(old_fs); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + force_uaccess_end(old_fs); +#endif + + ret = -PS3_FAILED; + goto l_out; + } + + memcpy(file_info->filename, filename, PS3_DUMP_FILE_NAME_LEN); + file_info->type = dump_type; + file_info->file_status = PS3_DUMP_FILE_OPEN; + file_info->fp = fp; + +l_out: + return ret; +} + +S32 ps3_dump_file_write(struct ps3_dump_file_info *file_info, U8 *buf, U32 len) +{ + struct file *fp = NULL; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0) + mm_segment_t old_fs; +#endif + S32 ret = 0; + + if (file_info && file_info->fp) { + fp = file_info->fp; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) + old_fs = get_fs(); + set_fs(get_ds() ); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + old_fs = get_fs(); + set_fs( KERNEL_DS ); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + old_fs = force_uaccess_begin(); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,14,0) + ret = kernel_write(fp, (char*)buf, len, &fp->f_pos); +#else + ret = vfs_write(fp, (char*)buf, len, &fp->f_pos); +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + set_fs(old_fs); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + force_uaccess_end(old_fs); +#endif + + if (ret > 0) { + file_info->file_size += len; + } + file_info->file_w_cnt++; + } + + return ret; +} + +S32 ps3_dump_file_close(struct ps3_dump_file_info *file_info) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0) + mm_segment_t old_fs; +#endif + if (file_info && file_info->fp) { + PS3_BUG_ON(IS_ERR(file_info->fp)); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,0,0) + old_fs = get_fs(); + set_fs(get_ds()); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + old_fs = get_fs(); + set_fs( KERNEL_DS ); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + old_fs = force_uaccess_begin(); +#endif + filp_close(file_info->fp, NULL); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + set_fs(old_fs); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 14, 0) +#else + force_uaccess_end(old_fs); +#endif + + file_info->fp = NULL; + file_info->file_status = PS3_DUMP_FILE_CLOSE; + } + return 0; +} + +struct ps3_dump_context * dev_to_dump_context(struct device *cdev) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct ps3_instance *instance = + (struct ps3_instance *) shost->hostdata; + return &instance->dump_context; +} + +static inline Bool ps3_dump_ctrl_get(struct ps3_instance *instance, U64 *dump_ctrl) +{ + Bool ret = PS3_TRUE; + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3DumpCtrl, *dump_ctrl); + INJECT_START(PS3_ERR_IJ_DUMP_CTRL_ERR, dump_ctrl); + if (*dump_ctrl == U64_MAX) { + LOG_INFO("hno:%u read reg ps3DumpCtrl NOK!\n", + PS3_HOST(instance)); + ret = PS3_FALSE; + goto l_out; + } + *dump_ctrl &= 0xff; + +l_out: + return ret; +} + +static inline void ps3_dump_ctrl_set(struct ps3_instance *instance, + U64 value) +{ + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3DumpCtrl, value); +} + +static inline void ps3_dump_abort(struct ps3_instance *instance) +{ + struct ps3_dump_context * ctxt = &instance->dump_context; + U64 dump_ctrl; + Bool ret = PS3_TRUE; + + if (ctxt->dump_state == PS3_DUMP_STATE_ABORTED || + ctxt->dump_state == PS3_DUMP_STATE_INVALID ) { + goto l_ret; + } + + ret = ps3_dump_ctrl_get(instance, &dump_ctrl); + INJECT_START(PS3_ERR_IJ_DUMP_ABORT_GET_CTRL_FAIL, &ret); + if (ret) { + if (dump_ctrl) { + LOG_WARN("dump ctrl is not cleared 0x%llx\n", dump_ctrl); + } + ps3_dump_ctrl_set(instance, PS3_DUMP_CTRL_DUMP_ABORT); + } else { + LOG_INFO("hno:%u read ps3DumpCtrl NOK!\n", + PS3_HOST(instance)); + } + ctxt->dump_state = PS3_DUMP_STATE_ABORTED; +l_ret: + return; +} + +static inline void ps3_dump_end(struct ps3_instance *instance) +{ + U64 dump_ctrl; + Bool ret = PS3_TRUE; + + ret = ps3_dump_ctrl_get(instance, &dump_ctrl); + INJECT_START(PS3_ERR_IJ_DUMP_END_GET_CTRL_FAIL, &ret); + if (ret) { + if (dump_ctrl) { + LOG_WARN("dump ctrl is not cleared 0x%llx\n", dump_ctrl); + } + ps3_dump_ctrl_set(instance, PS3_DUMP_CTRL_DUMP_END); + } else { + LOG_INFO("hno:%u read ps3DumpCtrl NOK!\n", + PS3_HOST(instance)); + } + + return; +} + +static inline S32 ps3_dump_trigger(struct ps3_instance *instance, + S32 dump_type) +{ + U64 dump_ctrl; + U64 ctrl_val = 0; + S32 ret = PS3_SUCCESS; + Bool reg_ret = PS3_TRUE; + + switch (dump_type) { + case PS3_DUMP_TYPE_CRASH: + ctrl_val = PS3_DUMP_CTRL_DUMP_CORE_FILE; + break; + case PS3_DUMP_TYPE_FW_LOG: + ctrl_val = PS3_DUMP_CTRL_DUMP_FW_LOG; + break; + case PS3_DUMP_TYPE_BAR_DATA: + ctrl_val = PS3_DUMP_CTRL_DUMP_BAR_DATA; + break; + default: + ret = -PS3_FAILED; + goto l_ret; + } + + reg_ret = ps3_dump_ctrl_get(instance, &dump_ctrl); + INJECT_START(PS3_ERR_IJ_DUMP_TRIGGER_GET_CTRL_FAIL, ®_ret); + if (reg_ret) { + if (dump_ctrl) { + LOG_WARN("dump ctrl is not cleared 0x%llx\n", dump_ctrl); + ret = -PS3_FAILED; + } else { + ps3_dump_ctrl_set(instance, ctrl_val); + } + } else { + LOG_INFO("hno:%u read ps3DumpCtrl NOK!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } +l_ret: + return ret; +} + +static inline Bool ps3_dump_status_get(struct ps3_instance *instance, + U64 *dump_status) +{ + Bool ret = PS3_TRUE; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3DumpStatus, *dump_status); + INJECT_START(PS3_ERR_IJ_DUMP_STATUS_ERR, dump_status); + if (*dump_status == U64_MAX) { + LOG_INFO("hno:%u read reg ps3DumpStatus NOK!\n", + PS3_HOST(instance)); + *dump_status = 0; + ret = PS3_FALSE; + goto l_out; + } + + *dump_status &= 0xff; + +l_out: + return ret; +} + +static inline void ps3_dump_status_set(struct ps3_instance *instance, + U64 value) +{ + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3DumpStatus, value); +} + +static inline Bool ps3_dump_data_size_get_clear(struct ps3_instance *instance, + U64 *data_size) +{ + Bool ret = PS3_TRUE; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3DumpDataSize, *data_size); + INJECT_START(PS3_ERR_IJ_DUMP_DATA_SIZE_FAIL, data_size); + if (*data_size == U64_MAX) { + LOG_INFO("hno:%u read reg ps3DumpDataSize NOK!\n", + PS3_HOST(instance)); + *data_size = 0; + ret = PS3_FALSE; + } + + PS3_IOC_REG_WRITE_WITH_CHECK(instance, reg_f.Excl_reg, ps3DumpDataSize, 0); + return ret; +} + +static Bool ps3_dump_status_check(U64 status, U8 dump_type) +{ + Bool ret = PS3_TRUE; + + switch(dump_type){ + case PS3_DUMP_TYPE_FW_LOG: + ret = PS3_REG_TEST(status, PS3_DUMP_STATUS_REG_FW_DUMP_MASK); + break; + case PS3_DUMP_TYPE_BAR_DATA: + ret = PS3_REG_TEST(status, PS3_DUMP_STATUS_REG_BAR_DUMP_MASK); + break; + case PS3_DUMP_TYPE_CRASH: + ret = PS3_REG_TEST(status, PS3_DUMP_STATUS_REG_CRASH_DUMP_MASK); + break; + default: + LOG_INFO("invalid type %d\n", dump_type); + ret = PS3_FALSE; + goto l_out; + } + + if (ret == PS3_TRUE) { + ret = PS3_REG_TEST(status, PS3_DUMP_STATUS_REG_DMA_FINISH_MASK); + } + +l_out: + return ret; +} + +static S32 ps3_dump_dma_data_copy(struct ps3_dump_context * ctxt, U64 status) +{ + U64 dma_size = 0; + U64 dump_ctrl; + S32 ret = PS3_SUCCESS; + Bool reg_ret = PS3_TRUE; + + if (!ps3_dump_data_size_get_clear(ctxt->instance, &dma_size)) { + ret = -PS3_FAILED; + goto l_out; + } + + if (dma_size == 0 || dma_size > PS3_DUMP_DMA_BUF_SIZE) { + LOG_ERROR("error: invalid data size %llu\n", dma_size); + ret = -PS3_FAILED; + goto l_out; + } + ctxt->dump_data_size += dma_size; + + ret = ps3_dump_file_write(&ctxt->dump_out_file, ctxt->dump_dma_buf, dma_size); + INJECT_START(PS3_ERR_IJ_DUMP_WRITE_FAIL, &ret); + if (ret < 0 || ret != (S32)dma_size) { + LOG_WARN("error: write data failure ret %d, dma_size %llu\n", ret, dma_size); + ret = -PS3_FAILED; + goto l_out; + } + ctxt->copyed_data_size += ret; + + PS3_REG_CLR(status, PS3_DUMP_STATUS_REG_DMA_FINISH_MASK); + ps3_dump_status_set(ctxt->instance, status); + + reg_ret = ps3_dump_ctrl_get(ctxt->instance, &dump_ctrl); + INJECT_START(PS3_ERR_IJ_DUMP_DATA_COPY_GET_CTRL_FAIL, ®_ret); + if (reg_ret) { + if (dump_ctrl) { + LOG_WARN("dump ctrl is not cleared 0x%llx\n", dump_ctrl); + } + ps3_dump_ctrl_set(ctxt->instance, PS3_DUMP_CTRL_COPY_FINISH); + ret = PS3_SUCCESS; + } else { + LOG_INFO("hno:%u read ps3DumpCtrl NOK!\n", + PS3_HOST(ctxt->instance)); + ret = -PS3_FAILED; + } + +l_out: + return ret; +} + +static inline void ps3_dump_work_done(struct ps3_dump_context * ctxt, S32 cur_state) +{ + ctxt->dump_work_status = PS3_DUMP_WORK_STOP; + ps3_dump_file_close(&ctxt->dump_out_file); + cur_state = ctxt->dump_state; + ctxt->dump_state = PS3_DUMP_STATE_INVALID; + if (cur_state == PS3_DUMP_STATE_COPY_DONE) { + LOG_INFO("end dump in COPY_DONE STATE\n"); + ps3_dump_end(ctxt->instance); + } +} + +static void ps3_dump_work(struct work_struct *work) +{ + static U32 work_wait_times = 0; + struct ps3_dump_context * ctxt = + ps3_container_of(work, struct ps3_dump_context, dump_work.work); + U64 status = 0, delay_ms = 0; + S32 cur_state = 0; + Bool ret = PS3_TRUE; + + ctxt->dump_work_status = PS3_DUMP_WORK_RUNNING; + ret = ps3_dump_status_get(ctxt->instance, &status); + INJECT_START(PS3_ERR_IJ_DUMP_DUMP_STATE_GET_FAIL, &ret); + if (!ret) { + delay_ms = PS3_REG_READ_INTERVAL_MS; + LOG_INFO("ps3_dump_status_get error, delay %llums try again\n", + delay_ms); + queue_delayed_work(ctxt->dump_work_queue, &ctxt->dump_work, + msecs_to_jiffies(delay_ms)); + goto l_out; + } + + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID, ctxt->instance); + + while(delay_ms == 0) { + if (ctxt->is_hard_recovered) { + LOG_WARN("dump in hard recovery, ready to abort\n"); + ctxt->dump_state = PS3_DUMP_STATE_PRE_ABORT; + } + + switch(ctxt->dump_state) { + case PS3_DUMP_STATE_START: + INJECT_START(PS3_ERR_IJ_DUMP_DUMP_STATE_INVALID, &status); + if ((status & PS3_DUMP_STATUS_REG_INVALID_BITS_MASK) == 0 || + (status & PS3_DUMP_STATUS_REG_ABORT_MASK) != 0) { + LOG_INFO("abort dump in START STATE, status: 0x%llx\n", status); + ctxt->dump_state = PS3_DUMP_STATE_PRE_ABORT; + continue; + } + + if ((status & PS3_DUMP_STATUS_REG_MASK) == 0 || + ps3_dump_status_check(status, ctxt->dump_type) == PS3_FALSE) { + delay_ms = WAIT_DUMP_COLLECT; + work_wait_times++; + break; + } + + if (ctxt->dump_out_file.file_status != PS3_DUMP_FILE_OPEN) { + if (ps3_dump_file_open(ctxt, (U32)ctxt->dump_type) != PS3_SUCCESS) { + delay_ms = WAIT_DUMP_COLLECT; + work_wait_times++; + break; + } + } + work_wait_times = 0; + ctxt->dump_state = PS3_DUMP_STATE_COPYING; + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID_2, ctxt->instance); + break; + case PS3_DUMP_STATE_COPYING: + if (status & PS3_DUMP_STATUS_REG_ABORT_MASK) { + LOG_INFO("abort dump in COPYING STATE\n"); + ctxt->dump_state = PS3_DUMP_STATE_PRE_ABORT; + continue; + } + + if ((status & PS3_DUMP_STATUS_REG_MASK) == 0) { + ctxt->dump_state = PS3_DUMP_STATE_COPY_DONE; + ctxt->dump_work_status = PS3_DUMP_WORK_DONE; + break; + } + if (ps3_dump_status_check(status, ctxt->dump_type) == PS3_FALSE) { + delay_ms = WAIT_DUMP_COLLECT; + work_wait_times++; + break; + } + if (ps3_dump_dma_data_copy(ctxt, status) != PS3_SUCCESS) { + LOG_INFO("abort dump in COPYING STATE\n"); + ctxt->dump_state = PS3_DUMP_STATE_PRE_ABORT; + continue; + } + + delay_ms = WAIT_DUMP_DMA_DONE; + work_wait_times = 0; + break; + case PS3_DUMP_STATE_PRE_ABORT: + ps3_dump_abort(ctxt->instance); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) + ps3_dump_work_done(ctxt, cur_state); + work_wait_times = 0; + goto l_out; +#endif + case PS3_DUMP_STATE_ABORTED: + case PS3_DUMP_STATE_COPY_DONE: + ps3_dump_work_done(ctxt, cur_state); + work_wait_times = 0; + goto l_out; + default: + LOG_INFO("warn: dump work state %d\n", ctxt->dump_state); + ctxt->dump_state = PS3_DUMP_STATE_PRE_ABORT; + continue; + } + if (delay_ms) { + if (work_wait_times >= + max((U32)WAIT_DUMP_TIMES_MIN, (U32)ctxt->dump_dma_wait_times)) { + LOG_INFO("error: wait too many times %d for dump %s, abort it\n", + work_wait_times,ps3_dump_type_to_name(ctxt->dump_type)); + ctxt->dump_state = PS3_DUMP_STATE_PRE_ABORT; + work_wait_times = 0; + delay_ms = 0; + continue; + } + + queue_delayed_work(ctxt->dump_work_queue, &ctxt->dump_work, + msecs_to_jiffies(delay_ms)); + break; + } + } + +l_out: + return; +} + +S32 ps3_dump_dma_buf_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dump_context *ctxt = &instance->dump_context; + + ctxt->dump_dma_buf = (U8*) ps3_dma_alloc_coherent( + instance, + PS3_DUMP_DMA_BUF_SIZE, + &ctxt->dump_dma_addr); + INJECT_START(PS3_ERR_IJ_FORCE_ALLOC_DMA_BUF_FAILED, &ctxt->dump_dma_buf) + if (ctxt->dump_dma_buf == NULL) { + LOG_ERROR("host_no[%d], dump dma alloc NOK!\n", PS3_HOST(instance)); + ret = -PS3_FAILED; + } + + return ret; +} + +void ps3_dump_dma_buf_free(struct ps3_instance *instance) +{ + struct ps3_dump_context *ctxt = &instance->dump_context; + + if (ctxt->dump_dma_buf != NULL) { + ps3_dma_free_coherent(instance, + PS3_DUMP_DMA_BUF_SIZE, ctxt->dump_dma_buf, + ctxt->dump_dma_addr); + ctxt->dump_dma_buf = NULL; + } +} + +static void ps3_dump_reset(struct ps3_dump_context *ctxt) +{ + ctxt->dump_data_size = 0; + ctxt->copyed_data_size = 0; + ctxt->dump_type = PS3_DUMP_TYPE_UNKNOWN; + ctxt->dump_state = PS3_DUMP_STATE_INVALID; + memset(&ctxt->dump_out_file, 0, sizeof(ctxt->dump_out_file)); +} + +S32 ps3_dump_type_set(struct ps3_dump_context *ctxt, S32 type, U32 env) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + LOG_INFO("dump type set: type %d\n", type); + + INJECT_START(PS3_ERR_IJ_DUMP_TYPE_ILLEGAL, &type); + if ( (type < PS3_DUMP_TYPE_CRASH)|| (type > PS3_DUMP_TYPE_BAR_DATA)) { + ret = -PS3_FAILED; + goto l_ret; + } + + INJECT_START(PS3_ERR_IJ_DUMP_WORK_QUEUE_NULL, &ctxt->dump_work_queue); + if (ctxt->dump_work_queue == NULL) { + LOG_WARN("dump type set: no work to do, type %d\n", type); + ret = -PS3_FAILED; + goto l_ret; + } + + ps3_mutex_lock(&ctxt->dump_lock); + INJECT_START(PS3_ERR_IJ_DUMP_STATE_ILLEGAL, &ctxt->dump_state); + if (ctxt->dump_state != PS3_DUMP_STATE_INVALID) { + LOG_FILE_ERROR("dump type set: work is busy, current state: %d, type %d\n", ctxt->dump_state, type); + ret = -PS3_FAILED; + goto l_unlock; + } + + ps3_dump_reset(ctxt); + + INJECT_AT_TIMES(PS3_ERR_IJ_WAIT_UNNORMAL, ctxt->instance); + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID, ctxt->instance); + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_NORMAL, ctxt->instance); + INJECT_AT_TIMES(PS3_ERR_IJ_WAIT_OPT, ctxt->instance); + + ctxt->is_hard_recovered = PS3_FALSE; + + INJECT_AT_TIMES(PS3_ERR_IJ_WAIT_UNNORMAL, ctxt->instance); + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID, ctxt->instance); + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_NORMAL, ctxt->instance); + INJECT_AT_TIMES(PS3_ERR_IJ_WAIT_OPT, ctxt->instance); + + cur_state = ps3_atomic_read(&ctxt->instance->state_machine.state); + if (!ps3_state_is_normal(cur_state)) { + LOG_WARN("h_no[%u], instance state is unnormal[%s]\n", + PS3_HOST(ctxt->instance), namePS3InstanceState(cur_state)); + ret = -PS3_FAILED; + goto l_unlock; + } + + ctxt->dump_state = PS3_DUMP_STATE_START; + ctxt->dump_type = type; + ctxt->dump_env = env; + ctxt->dump_type_times++; + + INJECT_AT_TIMES(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID, ctxt->instance); + + ret = ps3_dump_trigger (ctxt->instance, type); + INJECT_START(PS3_ERR_IJ_DUMP_TRIGGER_FAIL, &ret); + if (ret != PS3_SUCCESS) { + ps3_dump_reset(ctxt); + goto l_unlock; + } + + queue_delayed_work(ctxt->dump_work_queue, &ctxt->dump_work, 0); +l_unlock: + ps3_mutex_unlock(&ctxt->dump_lock); +l_ret: + return ret; +} + +S32 ps3_dump_state_set(struct ps3_dump_context *ctxt, S32 state) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state; + + LOG_INFO("dump state set: state %d\n", state); + + if (state != PS3_DUMP_STATE_INVALID) { + ret = -PS3_FAILED; + goto l_ret; + } + + ps3_mutex_lock(&ctxt->dump_lock); + cur_state = ctxt->dump_state; + if (cur_state == PS3_DUMP_STATE_INVALID) { + goto l_unlock; + } + + cancel_delayed_work_sync(&ctxt->dump_work); + ctxt->dump_work_status = PS3_DUMP_WORK_CANCEL; + ctxt->dump_state_times++; + + if (cur_state == PS3_DUMP_STATE_PRE_ABORT || + cur_state == PS3_DUMP_STATE_START || + cur_state == PS3_DUMP_STATE_COPYING) { + ps3_dump_abort(ctxt->instance); + } + + ps3_dump_file_close(&ctxt->dump_out_file); + + ps3_dump_reset(ctxt); + if (cur_state == PS3_DUMP_STATE_COPY_DONE) { + ps3_dump_end(ctxt->instance); + } +l_unlock: + ps3_mutex_unlock(&ctxt->dump_lock); +l_ret: + return ret; +} + +void ps3_dump_detect(struct ps3_instance *instance) +{ + struct ps3_dump_context *p_dump_ctx = &instance->dump_context; + S32 ret = PS3_SUCCESS; + S32 dump_type = 0; + U64 status = 0; + HilReg0Ps3RegisterFPs3DumpStatus_u dump_status = {0}; + U8 is_trigger_log; + + if (!ps3_dump_status_get(instance, &status)) { + goto l_out; + } + dump_status.val = status; + + dump_type = dump_status.reg.hasAutoDump; + INJECT_START(PS3_ERR_IJ_DUMP_TYPE_INVALID, &dump_type); + if (dump_type == 0) { + goto l_out; + } + + ps3_ioc_dump_support_get(instance); + + if (!PS3_IOC_DUMP_SUPPORT(instance)) { + goto l_out; + } + + LOG_DEBUG("hno:%u detect dump log file type[%d], status[%llx]\n", + PS3_HOST(instance), dump_type, status); + + is_trigger_log = ps3_dump_is_trigger_log(instance); + INJECT_START(PS3_ERR_IJ_DETECT_NO_TRIGGER_LOG, &is_trigger_log) + if(!is_trigger_log) { + LOG_DEBUG("cannot dump type set!\n"); + goto l_out; + } + + ret = ps3_dump_type_set(p_dump_ctx, dump_type, PS3_DUMP_ENV_NOTIFY); + LOG_DEBUG("hno:%u type[%d] autodump set trigger ret %d\n", + PS3_HOST(instance), dump_type, ret); + if (ret == PS3_SUCCESS) { + goto l_out; + } + +l_out: + return; +} + +static void ps3_dump_irq_handler_work(struct work_struct *work) +{ + struct ps3_dump_context * ctxt = + ps3_container_of(work, struct ps3_dump_context, dump_irq_handler_work); + + ctxt->dump_irq_handler_work_status = PS3_DUMP_IRQ_HANDLER_WORK_RUNNING; + ps3_dump_detect(ctxt->instance); + ctxt->dump_irq_handler_work_status = PS3_DUMP_IRQ_HANDLER_WORK_DONE; + + return; + +} + +irqreturn_t ps3_dump_irq_handler(S32 virq, void *dev_id) +{ + struct ps3_instance *pInstance = (struct ps3_instance *)dev_id; + struct ps3_dump_context *p_dump_ctx = &pInstance->dump_context; + ULong flags = 0; + + spin_lock_irqsave(&p_dump_ctx->dump_irq_handler_lock, flags); + if (p_dump_ctx->dump_enabled) { + + LOG_DEBUG("hno:%u dump irq recieved, virq: %d, dev_id: 0x%llx\n", + PS3_HOST(pInstance), virq, (U64)dev_id); + + if (!work_busy(&p_dump_ctx->dump_irq_handler_work)) { + queue_work(p_dump_ctx->dump_irq_handler_work_queue, &p_dump_ctx->dump_irq_handler_work); + } + } + + spin_unlock_irqrestore(&p_dump_ctx->dump_irq_handler_lock, flags); + + return IRQ_HANDLED; +} + +static void ps3_dump_dir_init(char *dump_dir) +{ + char *log_path_p; + U32 log_path_len = 0; + + log_path_p = ps3_log_path_query(); + if (log_path_p != NULL) { + log_path_len = strlen(log_path_p); + } + + if (log_path_p != NULL && log_path_p[0] == '/') { + if (log_path_p[log_path_len - 1] == '/') { + snprintf(dump_dir, PS3_DUMP_FILE_DIR_LEN, "%s", log_path_p); + } else { + snprintf(dump_dir, PS3_DUMP_FILE_DIR_LEN, "%s/", log_path_p); + } + } else { + LOG_INFO("provided log dump dir not valid, using default\n"); + snprintf(dump_dir, PS3_DUMP_FILE_DIR_LEN, "%s/", PS3_DUMP_FILE_DIR); + } + + return; +} + +S32 ps3_dump_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dump_context *ctxt = &instance->dump_context; + + if (reset_devices) { + LOG_INFO("resetting device in progress, Do not initialize dump\n"); + goto l_ret; + } + + if (ctxt->dump_dma_buf != NULL) { + LOG_INFO("hno:%u init already\n", PS3_HOST(instance)); + goto l_ret; + } + memset((void*)ctxt, 0, sizeof(struct ps3_dump_context )); + + if (!ps3_ioc_dump_support_get(instance)) { + goto l_ret; + } + + ps3_dump_dir_init((char *)ctxt->dump_dir); + + ctxt->instance = instance; + ctxt->dump_type = PS3_DUMP_TYPE_UNKNOWN; + ctxt->dump_state = PS3_DUMP_STATE_INVALID; + ctxt->dump_dma_wait_times = WAIT_DUMP_TIMES_DEFAULT; + if (ps3_dump_dma_buf_alloc(instance) != PS3_SUCCESS) { + ret = -PS3_FAILED; + goto l_failed; + } + + INIT_DELAYED_WORK(&ctxt->dump_work, ps3_dump_work); + ctxt->dump_work_queue = create_singlethread_workqueue((char*)"ps3_dump_work_queue"); + INJECT_START(PS3_ERR_IJ_DUMP_WORK_FAILED, &ctxt->dump_work_queue); + if (ctxt->dump_work_queue == NULL) { + LOG_ERROR("dump work queue create NOK\n"); + ret = -PS3_FAILED; + goto l_failed; + } + + INIT_WORK(&ctxt->dump_irq_handler_work, ps3_dump_irq_handler_work); + ctxt->dump_irq_handler_work_queue = create_singlethread_workqueue( + (char*)"ps3_dump_irq_handler_work_queue"); + INJECT_START(PS3_ERR_DUMP_ALLOC_FAILED, &ctxt->dump_irq_handler_work_queue); + if (ctxt->dump_irq_handler_work_queue == NULL) { + LOG_ERROR("dump irq handler work queue create NOK\n"); + ret = -PS3_FAILED; + goto l_failed; + } + ps3_mutex_init(&ctxt->dump_lock); + + spin_lock_init(&ctxt->dump_irq_handler_lock); + ctxt->dump_enabled = 1; + goto l_ret; +l_failed: + ps3_dump_exit(instance); +l_ret: + return ret; +} + +void ps3_dump_exit(struct ps3_instance *instance) +{ + struct ps3_dump_context *ctxt = &instance->dump_context; + ULong flags = 0; + + if (ctxt->dump_dma_buf == NULL) { + return; + } + + spin_lock_irqsave(&ctxt->dump_irq_handler_lock, flags); + ctxt->dump_enabled = 0; + spin_unlock_irqrestore(&ctxt->dump_irq_handler_lock, flags); + + if (ctxt->dump_irq_handler_work_queue != NULL) { + if (!cancel_work_sync(&ctxt->dump_irq_handler_work)) { + flush_workqueue(ctxt->dump_irq_handler_work_queue); + } else { + ctxt->dump_irq_handler_work_status = + PS3_DUMP_IRQ_HANDLER_WORK_CANCEL; + } + destroy_workqueue(ctxt->dump_irq_handler_work_queue); + ctxt->dump_irq_handler_work_queue = NULL; + } + + if (ctxt->dump_work_queue != NULL) { + if (!cancel_delayed_work_sync(&ctxt->dump_work)) { + flush_workqueue(ctxt->dump_work_queue); + } else { + ctxt->dump_work_status = PS3_DUMP_WORK_CANCEL; + } + destroy_workqueue(ctxt->dump_work_queue); + ctxt->dump_work_queue = NULL; + } + + ctxt->dump_state = PS3_DUMP_STATE_INVALID; + ps3_dump_file_close(&ctxt->dump_out_file); + + ps3_mutex_destroy(&ctxt->dump_lock); + LOG_INFO("hno:%u dump destory work and stop service\n", + PS3_HOST(instance)); +} + +void ps3_dump_work_stop(struct ps3_instance *instance) +{ + struct ps3_dump_context *ctxt = &instance->dump_context; + ULong flags = 0; + + spin_lock_irqsave(&ctxt->dump_irq_handler_lock, flags); + if (ctxt->dump_enabled == 0) { + spin_unlock_irqrestore(&ctxt->dump_irq_handler_lock, flags); + return; + } + spin_unlock_irqrestore(&ctxt->dump_irq_handler_lock, flags); + + if (ctxt->dump_irq_handler_work_queue != NULL) { + if (!cancel_work_sync(&ctxt->dump_irq_handler_work)) { + flush_workqueue(ctxt->dump_irq_handler_work_queue); + } else { + ctxt->dump_irq_handler_work_status = + PS3_DUMP_IRQ_HANDLER_WORK_CANCEL; + } + } + + if (ctxt->dump_work_queue != NULL) { + ps3_dump_state_set(ctxt, PS3_DUMP_STATE_INVALID); + if (!cancel_delayed_work_sync(&ctxt->dump_work)) { + flush_workqueue(ctxt->dump_work_queue); + } else { + ctxt->dump_work_status = PS3_DUMP_WORK_CANCEL; + } + } +} +void ps3_dump_ctrl_set_int_ready(struct ps3_instance *instance) +{ + if (reset_devices) { + LOG_INFO("resetting device in progress, unable to confiure ps3DumpCtrl\n"); + return; + } + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3DumpCtrl, PS3_DUMP_CTRL_DUMP_INT_READY); +} + +Bool ps3_dump_is_trigger_log(struct ps3_instance *instance) +{ + Bool is_support_halt = PS3_IOC_STATE_HALT_SUPPORT(instance); + U64 dump_ctrl; + Bool is_trigger_log = PS3_FALSE; + S32 cur_state = ps3_atomic_read(&instance->state_machine.state); + Bool is_halt = (is_support_halt && (cur_state == PS3_INSTANCE_STATE_DEAD)); + Bool ret = PS3_TRUE; + + INJECT_START(PS3_ERR_IJ_DUMP_PCIE_ERR, instance); + INJECT_START(PS3_ERR_IJ_DUMP_RECOVERY_ERR, instance); + if (likely(is_halt || + (cur_state == PS3_INSTANCE_STATE_OPERATIONAL && !ps3_pci_err_recovery_get(instance)))) { + is_trigger_log = PS3_TRUE; + } + + if (instance->is_support_dump_ctrl) { + ret = ps3_dump_ctrl_get(instance, &dump_ctrl); + INJECT_START(PS3_ERR_IJ_DUMP_IS_TRIGGER_GET_CTRL_FAIL, &ret); + if (ret) { + if(dump_ctrl != 0) { + is_trigger_log = PS3_FALSE; + } + } else { + LOG_INFO("hno:%u read ps3DumpCtrl NOK!\n", + PS3_HOST(instance)); + is_trigger_log = PS3_FALSE; + } + } + + return is_trigger_log; +} + diff --git a/drivers/scsi/ps3stor/linux/ps3_pcie_err_handle.c b/drivers/scsi/ps3stor/linux/ps3_pcie_err_handle.c new file mode 100644 index 0000000000000000000000000000000000000000..9713d0e72b6273bd6d67734e6ab82acf7befa99a --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_pcie_err_handle.c @@ -0,0 +1,233 @@ + +#include + +#include "ps3_pcie_err_handle.h" +#include "ps3_driver_log.h" +#include "ps3_recovery.h" +#include "ps3_ioc_state.h" +#include "ps3_module_para.h" + +static pci_ers_result_t ps3_pci_err_detected(struct pci_dev *pdev, + pci_channel_state_t state); +static pci_ers_result_t ps3_pci_mmio_enabled(struct pci_dev *pdev); +static pci_ers_result_t ps3_pci_slot_reset(struct pci_dev *pdev); +static void ps3_pci_resume(struct pci_dev *pdev); + +extern S32 ps3_pci_init(struct pci_dev *pdev, struct ps3_instance *instance); +extern S32 ps3_pci_init_complete(struct ps3_instance *instance); +extern void ps3_pci_init_complete_exit(struct ps3_instance *instance); + +static struct pci_error_handlers ps3_err_handlers = { + .error_detected = ps3_pci_err_detected, + .mmio_enabled = ps3_pci_mmio_enabled, + .slot_reset = ps3_pci_slot_reset, + .resume = ps3_pci_resume +}; + +void ps3_pci_err_handler_init(struct pci_driver *drv) +{ + drv->err_handler = &ps3_err_handlers; + return; +} + +int ps3_base_init_resources(struct ps3_instance *instance) +{ + int ret = PS3_SUCCESS; + struct pci_dev *pdev = instance->pdev; + + ret = ps3_pci_init(pdev, instance); + INJECT_START(PS3_ERR_IJ_FORCE_PCIE_ERR_PCI_INIT_FAILED, &ret) + if (ret) { + LOG_ERROR("hno:%u pci init failed, ret: %d\n", PS3_HOST(instance), ret); + goto l_out; + } + + instance->is_pci_reset = PS3_FALSE; + + ret = ps3_pci_init_complete(instance); + INJECT_START(PS3_ERR_IJ_FORCE_PCIE_ERR_PCI_INIT_COMP_FAILED, &ret) + if (ret) { + LOG_ERROR("hno:%u pci init complete failed, ret: %d\n", PS3_HOST(instance), ret); + goto l_out; + } + + pci_save_state(pdev); + +l_out: + + return ret; +} + +void ps3_base_free_resources(struct ps3_instance *instance) +{ + instance->ioc_adpter->irq_disable(instance); + ps3_irqs_sync(instance); + + ps3_irqpolls_enable(instance); + ps3_dump_work_stop(instance); + ps3_pci_init_complete_exit(instance); +} + +static pci_ers_result_t ps3_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + pci_ers_result_t ret = PCI_ERS_RESULT_NEED_RESET; + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + if (instance == NULL) { + LOG_INFO("get instance failed\n"); + dev_info(&pdev->dev, "[PS3]%s():%d; get instance failed\n", __FUNCTION__, __LINE__); + ret = PCI_ERS_RESULT_DISCONNECT; + goto l_out; + } + + LOG_INFO("[%04x:%02x:%02x:%x]:PCIe err detected state:%u\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev), state); + dev_info(&pdev->dev, "[PS3]%s():%d;PCIe err detected state:%u\n", + __FUNCTION__, __LINE__, state); + + switch (state) { + case pci_channel_io_normal: + ret = PCI_ERS_RESULT_CAN_RECOVER; + break; + case pci_channel_io_frozen: + ps3_pci_err_recovery_set(instance, PS3_TRUE); + scsi_block_requests(instance->host); + ps3_watchdog_stop(instance); + if (ps3_recovery_cancel_work_sync(instance) != PS3_SUCCESS) { + LOG_ERROR("hno:%u work sync failed, state: %u\n", PS3_HOST(instance), state); + } + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_CLEAN; + ps3_base_free_resources(instance); + ret = PCI_ERS_RESULT_NEED_RESET; + break; + case pci_channel_io_perm_failure: + ps3_pci_err_recovery_set(instance, PS3_TRUE); + ps3_watchdog_stop(instance); + if (ps3_recovery_cancel_work_sync(instance) != PS3_SUCCESS) { + LOG_ERROR("hno:%u work sync failed, state: %u\n", PS3_HOST(instance), state); + } + ps3_cmd_force_stop(instance); + ps3_pci_err_recovery_set(instance, PS3_FALSE); + ps3_instance_state_transfer_to_dead(instance); + ret = PCI_ERS_RESULT_DISCONNECT; + break; + default: + ret = PCI_ERS_RESULT_RECOVERED; + break; + } + +l_out: + LOG_INFO("[%04x:%02x:%02x:%x]:PCIe err detect state:%u ret:%u\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev), state, ret); + dev_info(&pdev->dev, "[PS3]%s():%d;PCIe err detect state:%u ret:%u\n", + __FUNCTION__, __LINE__, state, ret); + return ret; +} + +static pci_ers_result_t ps3_pci_mmio_enabled(struct pci_dev *pdev) +{ + pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED; + + LOG_INFO("[%04x:%02x:%02x:%x]: PCIe err mmio enabled\n", ps3_get_pci_domain(pdev), ps3_get_pci_bus(pdev), \ + ps3_get_pci_slot(pdev), ps3_get_pci_function(pdev)); + dev_info(&pdev->dev, "[PS3]%s():%d; PCIe err mmio enabled\n", + __FUNCTION__, __LINE__); + + return ret; +} + +static pci_ers_result_t ps3_pci_slot_reset(struct pci_dev *pdev) +{ + int ret; + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + + LOG_INFO("hno:%u PCIe err slot reset begin.\n", PS3_HOST(instance)); + dev_info(&pdev->dev, "[PS3]%s():%d;hno:%u PCIe err slot reset begin.\n", + __FUNCTION__, __LINE__, PS3_HOST(instance)); + + instance->pdev = pdev; + pci_restore_state(pdev); + + ret = ps3_base_init_resources(instance); + if (ret) { + LOG_ERROR("hno:%u base init resources failed, ret: %d\n", PS3_HOST(instance), ret); + dev_info(&pdev->dev, "[PS3]hno:%u init resources failed, ret: %d\n", PS3_HOST(instance), ret); + goto l_out; + } + + LOG_INFO("hno:%u PCIe err slot reset succeed.\n", PS3_HOST(instance)); + dev_info(&pdev->dev, "[PS3]%s():%d;hno:%u PCIe err slot reset succeed.\n", + __FUNCTION__, __LINE__, PS3_HOST(instance)); + ps3_pci_err_recovery_set(instance, PS3_FALSE); + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_INIT; + return PCI_ERS_RESULT_RECOVERED; +l_out: + if (instance) { + ps3_instance_state_transfer_to_dead(instance); + } + ps3_pci_err_recovery_set(instance, PS3_FALSE); + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_INIT; + + return PCI_ERS_RESULT_DISCONNECT; +} + +static void ps3_pci_resume(struct pci_dev *pdev) +{ + S32 ret = PS3_SUCCESS; + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + struct ps3_instance *instance = (struct ps3_instance *)pci_get_drvdata(pdev); + + LOG_INFO("hno:%u PCIe err resume\n", PS3_HOST(instance)); + dev_info(&pdev->dev, "[PS3]%s():%d;hno:%u PCIe err resume\n", + __FUNCTION__, __LINE__, PS3_HOST(instance)); + + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_FORCE_PCIE_ERR_IOC_RUNNING_INIT_FAILED, &fw_cur_state) + if (fw_cur_state == PS3_FW_STATE_RUNNING) { + LOG_INFO("hno:%u not need repeat recovery\n", PS3_HOST(instance)); + dev_info(&pdev->dev, "[PS3]hno:%u not need repeat recovery\n", PS3_HOST(instance)); + goto l_norecovery; + } + INJECT_START(PS3_ERR_IJ_PCI_FORCE_HARD_RECOVERY_REQ_FAILED, instance) + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u hard reset NOK, ret: %d\n", PS3_HOST(instance), ret); + dev_info(&pdev->dev, "[PS3]hno:%u hard reset NOK, ret: %d\n", PS3_HOST(instance), ret); + goto l_failed; + } + ret = ps3_instance_wait_for_operational(instance, PS3_TRUE); + INJECT_START(PS3_ERR_IJ_PCI_FORCE_WAIT_OPERARIONAL_FAILED, &ret) + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u wait for opt NOK.\n", PS3_HOST(instance)); + dev_info(&pdev->dev, "[PS3]hno:%u wait for opt NOK.\n", PS3_HOST(instance)); + goto l_failed; + } + +l_norecovery: +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 3)) \ + || (defined(CONFIG_SUSE_KERNEL) && ((CONFIG_SUSE_VERSION == 15) \ + && (CONFIG_SUSE_PATCHLEVEL >= 2)))) + pci_aer_clear_nonfatal_status(pdev); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + pci_cleanup_aer_uncorrect_error_status(pdev); +#endif + ps3_watchdog_start(instance); + scsi_unblock_requests(instance->host); + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_NORMAL; + return; +l_failed: +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 3)) \ + || (defined(CONFIG_SUSE_KERNEL) && ((CONFIG_SUSE_VERSION == 15) \ + && (CONFIG_SUSE_PATCHLEVEL >= 2)))) + pci_aer_clear_nonfatal_status(pdev); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + pci_cleanup_aer_uncorrect_error_status(pdev); +#endif + if (instance) { + ps3_instance_state_transfer_to_dead(instance); + } + instance->pci_err_handle_state = PS3_DEVICE_ERR_STATE_NORMAL; + return; +} + diff --git a/drivers/scsi/ps3stor/linux/ps3_pcie_err_handle.h b/drivers/scsi/ps3stor/linux/ps3_pcie_err_handle.h new file mode 100644 index 0000000000000000000000000000000000000000..81f1361789adc867339a84f8558c3da9a95b7e18 --- /dev/null +++ b/drivers/scsi/ps3stor/linux/ps3_pcie_err_handle.h @@ -0,0 +1,23 @@ + +#ifndef _PS3_PCIE_ERR_HANDLE_H_ +#define _PS3_PCIE_ERR_HANDLE_H_ + +#include +#include + +#include "ps3_instance_manager.h" +#ifdef __cplusplus +extern "C"{ +#endif + +void ps3_pci_err_handler_init(struct pci_driver *drv); + +int ps3_base_init_resources(struct ps3_instance *instance); + +void ps3_base_free_resources(struct ps3_instance *instance); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/scsi/ps3stor/load.sh b/drivers/scsi/ps3stor/load.sh new file mode 100644 index 0000000000000000000000000000000000000000..d4d59e035cdcfb7bf54dbd3d6bfc85e3250a2054 --- /dev/null +++ b/drivers/scsi/ps3stor/load.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# load.sh : a helper script for loading the drivers +# + +modprobe scsi_transport_sas + +# loading the driver +insmod ps3stor.ko +if [ $? -eq 0 ]; then + echo "The ps3stor.ko module has been loaded successfully." +else + echo "The ps3stor.ko module has been loaded failed." + exit 1 +fi +exit 0 \ No newline at end of file diff --git a/drivers/scsi/ps3stor/ps3_cmd_channel.c b/drivers/scsi/ps3stor/ps3_cmd_channel.c new file mode 100644 index 0000000000000000000000000000000000000000..ce5eb6e1d26e47566be18b3dda291f7e4c2da76e --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_channel.c @@ -0,0 +1,1613 @@ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include +#include "ps3_trace_id_alloc.h" +#endif + +#include "ps3_cmd_channel.h" +#include "ps3_instance_manager.h" +#include "ps3_inner_data.h" +#include "ps3_irq.h" +#include "ps3_cmd_complete.h" +#include "ps3_ioc_manager.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_htp.h" +#include "ps3_util.h" +#include "ps3_ioctl.h" +#include "ps3_cmd_statistics.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_module_para.h" +#include "ps3_scsih.h" +#include "ps3_ioc_state.h" +#include "ps3_mgr_cmd.h" + +static S32 ps3_req_frame_alloc(struct ps3_instance *instance); +static void ps3_req_frame_free(struct ps3_instance *instance); +static S32 ps3_cmd_resp_frame_alloc(struct ps3_instance *instance); +static void ps3_cmd_resp_frame_free(struct ps3_instance *instance); +static S32 ps3_cmd_buf_alloc(struct ps3_instance *instance); +static void ps3_cmd_buf_free(struct ps3_instance *instance); +static S32 ps3_cmd_ext_buf_alloc(struct ps3_instance *instance); +static void ps3_cmd_ext_buf_free(struct ps3_instance *instance); +static S32 ps3_cmd_r1xlock_buff_alloc(struct ps3_instance *instance); +static void ps3_cmd_r1xlock_buff_free(struct ps3_instance *instance); +static S32 ps3_cmd_init(struct ps3_instance *instance); +static void ps3_cmd_content_init(struct ps3_cmd *cmd); +static inline Bool is_mgr_cmd(struct ps3_instance *instance, U32 index); +static inline Bool is_task_cmd(struct ps3_instance *instance, U32 index); +static void cmd_pool_free(ps3_list_head *pool_list, + ps3_spinlock *pool_lock, struct ps3_cmd *cmd); +static struct ps3_cmd *cmd_pool_alloc(ps3_list_head *pool_list, + ps3_spinlock *pool_lock); + +#define PS3_RESP_FRAME_LENGH (PS3_SENSE_BUFFER_SIZE + 32) + +static inline Bool is_mgr_cmd(struct ps3_instance *instance, U32 index) +{ + index -= instance->cmd_context.max_scsi_cmd_count; + return index < instance->max_mgr_cmd_count ? PS3_DRV_TRUE : PS3_DRV_FALSE; +} + +static inline Bool is_task_cmd(struct ps3_instance *instance, U32 index) +{ + index -= (instance->cmd_context.max_scsi_cmd_count + instance->max_mgr_cmd_count); + return index < instance->max_task_cmd_count ? PS3_DRV_TRUE : PS3_DRV_FALSE; +} + +static inline Bool is_r1x_peer_cmd(struct ps3_instance *instance, U32 index) +{ + struct ps3_cmd_context *cmd_ctx = &instance->cmd_context; + return ((cmd_ctx->max_scsi_cmd_count - cmd_ctx->max_r1x_cmd_count) <= index && + index < cmd_ctx->max_scsi_cmd_count) ? + PS3_DRV_TRUE : PS3_DRV_FALSE; +} + +struct ps3_cmd *ps3_r1x_peer_cmd_alloc(struct ps3_instance *instance, U32 index) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + U32 offset = context->max_scsi_cmd_count - context->max_r1x_cmd_count; + if (instance->r1x_mode == PS3_R1X_MODE_PERF) { + cmd = context->cmd_buf[index + offset]; + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_trace_id_alloc(&cmd->trace_id); + init_completion(&cmd->sync_done); + } else { + cmd = cmd_pool_alloc(&context->r1x_scsi_cmd_pool, &context->r1x_scsi_pool_lock); + if (cmd != NULL && cmd->is_aborting == 1) { + cmd->cmd_state.state = PS3_CMD_STATE_INIT; + cmd->trace_id = 0; + INJECT_START(PS3_ERR_IJ_SET_CMD_TID_FLAG, cmd); + cmd_pool_free(&context->r1x_scsi_cmd_pool, &context->r1x_scsi_pool_lock, cmd); + cmd = NULL; + } + INJECT_START(PS3_ERR_IJ_SET_CMD_TID_FLAG, cmd); + } + return cmd; +} + +struct ps3_cmd *ps3_mgr_cmd_alloc(struct ps3_instance *instance) +{ + struct ps3_cmd_context *context = &instance->cmd_context; + return cmd_pool_alloc(&context->mgr_cmd_pool, &context->mgr_pool_lock); +} + +S32 ps3_mgr_cmd_free(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + ULong flags = 0; + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + ret = ps3_mgr_cmd_free_nolock(instance, cmd); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + return ret; +} + +struct ps3_cmd *ps3_task_cmd_alloc(struct ps3_instance *instance) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = NULL; + + context = &instance->cmd_context; + cmd = cmd_pool_alloc(&context->task_cmd_pool, &context->task_pool_lock); + if (cmd == NULL) { + cmd = ps3_mgr_cmd_alloc(instance); + } + return cmd; +} + +S32 ps3_task_cmd_free(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + (void)instance; + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + ret = ps3_mgr_cmd_free_nolock(instance, cmd); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + return ret; +} + +static S32 ps3_req_frame_alloc(struct ps3_instance *instance) +{ + U32 size = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + + size = PS3_DEFAULT_REQ_FRAME_SIZE * context->max_cmd_count; + + context->req_frame_dma_pool = (struct dma_pool *) ps3_dma_pool_create( + "PS3 req frame pool",&instance->pdev->dev, size, + DMA_ALIGN_BYTES_256, 0); + INJECT_START(PS3_ERR_IJ_PS3_REQ_FRAME_BUF_ALLOC, &context->req_frame_dma_pool); + if (!context->req_frame_dma_pool) { + LOG_ERROR("Failed to setup frame pool\n"); + goto l_create_dma_pool_failed; + } + + context->req_frame_buf = (U8*)ps3_dma_pool_alloc(instance, + context->req_frame_dma_pool, + GFP_KERNEL, &context->req_frame_buf_phys); + if (!context->req_frame_buf) { + LOG_ERROR("Failed to alloc frame dma memory\n"); + goto l_free_mem; + } + + return PS3_SUCCESS; + +l_free_mem: + if (context->req_frame_dma_pool) { + ps3_dma_pool_destroy(context->req_frame_dma_pool); + context->req_frame_dma_pool = NULL; + } +l_create_dma_pool_failed: + return -PS3_FAILED; +} + +static void ps3_req_frame_free(struct ps3_instance *instance) +{ + struct ps3_cmd_context *context = &instance->cmd_context; +#ifndef _WINDOWS + if (context->req_frame_buf) { + ps3_dma_pool_free(context->req_frame_dma_pool, + context->req_frame_buf, + context->req_frame_buf_phys); + context->req_frame_buf = NULL; + } + if (context->req_frame_dma_pool) { + ps3_dma_pool_destroy(context->req_frame_dma_pool); + context->req_frame_dma_pool = NULL; + } +#else + if (context->req_frame_buf != NULL) { + ps3_dma_free_coherent(instance, + context->req_frame_buf_size, + context->req_frame_buf, + context->req_frame_buf_phys); + context->req_frame_buf = NULL; + context->req_frame_buf_size = 0; + } +#endif +} + +static S32 ps3_cmd_resp_frame_alloc(struct ps3_instance *instance) +{ + U32 sense_size = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + + sense_size = PS3_RESP_FRAME_LENGH * context->max_cmd_count; + + context->response_frame_dma_pool = (struct dma_pool *)ps3_dma_pool_create("PS3 respSense pool", + &instance->pdev->dev, sense_size, + DMA_ALIGN_BYTES_4K, 0); + + if (!context->response_frame_dma_pool) { + LOG_ERROR("Failed to setup sense pool\n"); + goto l_failed_alloc; + } + context->response_frame_buf = (U8*)ps3_dma_pool_alloc(instance, context->response_frame_dma_pool, + GFP_KERNEL, &context->response_frame_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_RESP_FRAME_BUF_ALLOC, &context->response_frame_buf); + if (!context->response_frame_buf) { + LOG_ERROR("Failed to alloc sense dma memory\n"); + goto l_free_mem; + } + ps3_get_so_addr_ranger(instance, context->response_frame_buf_phys, sense_size); + return PS3_SUCCESS; + +l_free_mem: + if (context->response_frame_dma_pool) { + ps3_dma_pool_destroy(context->response_frame_dma_pool); + context->response_frame_dma_pool = NULL; + } + +l_failed_alloc: + return -PS3_FAILED; +} + +static void ps3_cmd_resp_frame_free(struct ps3_instance *instance) +{ + struct ps3_cmd_context *context = &instance->cmd_context; +#ifndef _WINDOWS + if (context->response_frame_buf) { + ps3_dma_pool_free(context->response_frame_dma_pool, + context->response_frame_buf, context->response_frame_buf_phys); + context->response_frame_buf = NULL; + } + if (context->response_frame_dma_pool) { + ps3_dma_pool_destroy(context->response_frame_dma_pool); + context->response_frame_dma_pool = NULL; + } +#else + if (context->response_frame_buf != NULL) { + ps3_dma_free_coherent(instance, + context->response_frame_buf_size, + context->response_frame_buf, + context->response_frame_buf_phys); + context->response_frame_buf = NULL; + context->response_frame_buf_size = 0; + } +#endif +} + +static void ps3_cmd_mgr_trans_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + + if (context->cmd_buf == NULL) { + return; + } + + for (i = 0; i < instance->max_mgr_cmd_count; i++) { + if (context->cmd_buf) { + cmd = context->cmd_buf[instance->cmd_context.max_scsi_cmd_count + i]; + if (cmd && cmd->transient) { + ps3_kfree(instance, cmd->transient); + cmd->transient = NULL; + } + } + } +} + +static S32 ps3_cmd_mgr_trans_alloc(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd *cmd; + struct ps3_cmd_context *context = &instance->cmd_context; + + for (i = 0; i < instance->max_mgr_cmd_count; i++) { + cmd = context->cmd_buf[instance->cmd_context.max_scsi_cmd_count + i]; + + cmd->transient = (struct ps3_ioctl_transient *) + ps3_kzalloc(instance, sizeof(struct ps3_ioctl_transient)); + INJECT_START(PS3_ERR_IJ_PS3_IOCTL_TRANSIENT_ALLOC, &cmd->transient); + if (cmd->transient == NULL) { + LOG_ERROR("Failed to alloc sge dma memory\n"); + goto l_free; + } + } + return PS3_SUCCESS; +l_free: + ps3_cmd_mgr_trans_free(instance); + return -PS3_FAILED; + +} + +static S32 ps3_cmd_ext_buf_alloc(struct ps3_instance *instance) +{ + U32 i = 0; + U32 sge_frame_size = 0; + struct ps3_cmd *cmd; + struct ps3_cmd_context *context = &instance->cmd_context; + + sge_frame_size = sizeof(struct PS3Sge) * context->ext_sge_frame_count; + context->ext_buf_size = PS3_MAX(sge_frame_size, PS3_CMD_EXT_BUF_DEFAULT_SIZE); +#ifndef _WINDOWS + context->ext_buf_dma_pool = (struct dma_pool *)ps3_dma_pool_create("PS3 ext buf pool", + &instance->pdev->dev, context->ext_buf_size, + PS3_CMD_EXT_BUF_DEFAULT_SIZE, 0); + if (!context->ext_buf_dma_pool) { + LOG_ERROR("Failed to setup sense pool\n"); + goto l_failed_alloc; + } + + for (i = 0; i < context->max_scsi_cmd_count; i++) { + cmd = context->cmd_buf[i]; + cmd->ext_buf = ps3_dma_pool_zalloc(instance, context->ext_buf_dma_pool, + GFP_KERNEL, &cmd->ext_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_EXT_BUF_ALLOC, &cmd->ext_buf); + if (!cmd->ext_buf) { + LOG_ERROR("Failed to alloc scsi ext buf memory\n"); + goto l_free_sge; + } + } + + context->mgr_ext_buf_size = PS3_CMD_EXT_BUF_SIZE_MGR; + context->mgr_ext_buf_dma_pool = (struct dma_pool *)ps3_dma_pool_create("PS3 mgr ext buf pool", + &instance->pdev->dev, context->ext_buf_size, + PS3_CMD_EXT_BUF_SIZE_MGR, 0); + if (!context->mgr_ext_buf_dma_pool) { + LOG_ERROR("Failed to setup sense pool\n"); + goto l_failed_alloc; + } + + for (i = context->max_scsi_cmd_count; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + cmd->ext_buf = ps3_dma_pool_zalloc(instance, context->mgr_ext_buf_dma_pool, + GFP_KERNEL, &cmd->ext_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_MGR_EXT_BUF_ALLOC, &cmd->ext_buf); + if (!cmd->ext_buf) { + LOG_ERROR("Failed to alloc mgr ext buf memory\n"); + goto l_free_sge; + } + } + + return PS3_SUCCESS; +l_free_sge: + ps3_cmd_ext_buf_free(instance); +l_failed_alloc: + return -PS3_FAILED; +#else + for (i = 0; i < context->max_scsi_cmd_count; i++) { + cmd = context->cmd_buf[i]; + cmd->ext_buf = ps3_dma_alloc_coherent(instance, context->ext_buf_size, + &cmd->ext_buf_phys); + if (cmd->ext_buf == NULL) { + LOG_ERROR("Failed to alloc scsi ext buf memory\n"); + goto l_failed; + } + } + + context->mgr_ext_buf_size = PS3_CMD_EXT_BUF_SIZE_MGR; + for (i = context->max_scsi_cmd_count; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + cmd->ext_buf = ps3_dma_alloc_coherent(instance, context->mgr_ext_buf_size, + &cmd->ext_buf_phys); + if (cmd->ext_buf == NULL) { + LOG_ERROR("Failed to alloc mgr ext buf memory\n"); + goto l_failed; + } + } + + return PS3_SUCCESS; + +l_failed: + ps3_cmd_ext_buf_free(instance); + return -PS3_FAILED; + +#endif +} + +static void ps3_cmd_ext_buf_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + + if (context->cmd_buf == NULL) { + return; + } +#ifndef _WINDOWS + for (i = 0; i < context->max_scsi_cmd_count; i++) { + cmd = context->cmd_buf[i]; + if ((cmd != NULL) && (cmd->ext_buf != NULL)) { + ps3_dma_pool_free(context->ext_buf_dma_pool, + cmd->ext_buf, + cmd->ext_buf_phys); + cmd->ext_buf = NULL; + } + } + + if (context->ext_buf_dma_pool) { + ps3_dma_pool_destroy(context->ext_buf_dma_pool); + context->ext_buf_dma_pool = NULL; + } + + for (i = context->max_scsi_cmd_count; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + if ((cmd != NULL) && (cmd->ext_buf != NULL)) { + ps3_dma_pool_free(context->mgr_ext_buf_dma_pool, + cmd->ext_buf, + cmd->ext_buf_phys); + cmd->ext_buf = NULL; + } + } + + if (context->mgr_ext_buf_dma_pool) { + ps3_dma_pool_destroy(context->mgr_ext_buf_dma_pool); + context->mgr_ext_buf_dma_pool = NULL; + } +#else + for (i = 0; i < context->max_scsi_cmd_count; i++) { + cmd = context->cmd_buf[i]; + if ((cmd != NULL) && (cmd->ext_buf != NULL)) { + ps3_dma_free_coherent(instance, context->ext_buf_size, + cmd->ext_buf, + cmd->ext_buf_phys); + cmd->ext_buf = NULL; + } + } + + for (i = context->max_scsi_cmd_count; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + if ((cmd != NULL) && (cmd->ext_buf != NULL)) { + ps3_dma_free_coherent(instance, context->mgr_ext_buf_size, + cmd->ext_buf, + cmd->ext_buf_phys); + cmd->ext_buf = NULL; + } + } +#endif +} + +static S32 ps3_cmd_r1xlock_buff_alloc(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + struct ps3_cmd *cmd = NULL; + U32 node_buff_size = ps3_r1x_get_node_Buff_size(); + + for (i = 0; i < context->max_scsi_cmd_count; i++) { + cmd = context->cmd_buf[i]; + cmd->szblock_cnt = 0; + cmd->node_buff = ps3_kzalloc(instance, node_buff_size); + INJECT_START(PS3_ERR_IJ_PS3_R1XLOCK_BUF_ALLOC, &cmd->node_buff); + if (!cmd->node_buff) { + LOG_ERROR("Failed to alloc r1x write lock range node buf memory\n"); + goto l_free_node; + } + } + + return PS3_SUCCESS; + +l_free_node: + ps3_cmd_r1xlock_buff_free(instance); + return -PS3_FAILED; +} + +static void ps3_cmd_r1xlock_buff_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + struct ps3_cmd* cmd = NULL; + + if (context->cmd_buf == NULL) { + return; + } + + for (i = 0; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + if(cmd != NULL) { + cmd->szblock_cnt = 0; + if(cmd->node_buff != NULL){ + ps3_kfree(instance, cmd->node_buff); + cmd->node_buff = NULL; + } + } + } + + return; +} + +static S32 ps3_cmd_buf_alloc(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + + context->cmd_buf = (struct ps3_cmd**)ps3_kcalloc(instance, context->max_cmd_count, + sizeof(struct ps3_cmd*)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_BUF_ALLOC, &context->cmd_buf); + if (context->cmd_buf == NULL) { + LOG_ERROR("Failed to kcalloc memory for cmd_buf\n"); + goto l_failed; + } + memset(context->cmd_buf, 0, + sizeof(struct ps3_cmd*) * context->max_cmd_count); + for (i = 0; i < context->max_cmd_count; i++) { + context->cmd_buf[i] = (struct ps3_cmd*)ps3_kzalloc(instance, + sizeof(struct ps3_cmd)); + INJECT_START(PS3_ERR_IJ_PS3_PS3_CMD_ALLOC, &context->cmd_buf[i]); + if (context->cmd_buf[i] == NULL) { + LOG_ERROR("Failed to malloc memory for ps3_cmd\n"); + goto l_failed; + } + } + + INIT_LIST_HEAD(&context->mgr_cmd_pool); + INIT_LIST_HEAD(&context->task_cmd_pool); + INIT_LIST_HEAD(&context->r1x_scsi_cmd_pool); + ps3_spin_lock_init(&context->mgr_pool_lock); + ps3_spin_lock_init(&context->task_pool_lock); + ps3_spin_lock_init(&context->r1x_scsi_pool_lock); + return PS3_SUCCESS; + +l_failed: + ps3_cmd_buf_free(instance); + return -PS3_FAILED; +} + +static void ps3_cmd_buf_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + + if (context->cmd_buf == NULL) { + goto l_out; + } + + while(i < context->max_cmd_count && context->cmd_buf[i]) { + ps3_kfree(instance, context->cmd_buf[i]); + context->cmd_buf[i] = NULL; + i++; + } + + ps3_kfree(instance, context->cmd_buf); + context->cmd_buf = NULL; + INIT_LIST_HEAD(&context->mgr_cmd_pool); + INIT_LIST_HEAD(&context->task_cmd_pool); + INIT_LIST_HEAD(&context->r1x_scsi_cmd_pool); +#ifdef _WINDOWS + INIT_LIST_HEAD(&context->scsi_cmd_pool); +#endif +l_out: + return; +} + +static S32 ps3_cmd_init(struct ps3_instance *instance) +{ + U16 i = 0; + S32 ret = PS3_SUCCESS; + U32 offset = 0; + + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + + for (i = 0; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + if (!cmd) { + LOG_ERROR("Failed ps3_cmd_init \n"); + ret = -PS3_FAILED; + goto l_out; + } + + cmd->instance = instance; + offset = i * PS3_RESP_FRAME_LENGH; + cmd->resp_frame = (PS3RespFrame_u *) + (context->response_frame_buf + offset); + cmd->resp_frame_phys = context->response_frame_buf_phys + offset; + cmd->index = i; + cmd->is_aborting = 0; +#ifndef _WINDOWS + cmd->scmd = NULL; +#endif + offset = i * PS3_DEFAULT_REQ_FRAME_SIZE; + cmd->req_frame = (union PS3ReqFrame *) + (context->req_frame_buf + offset); + cmd->req_frame_phys = context->req_frame_buf_phys + offset; + ps3_spin_lock_init(&cmd->cmd_state.lock); + ps3_cmd_content_init(cmd); + if (is_r1x_peer_cmd(instance, i)) { + if (instance->r1x_mode == PS3_R1X_MODE_NORMAL) { + list_add_tail(&cmd->cmd_list, + &context->r1x_scsi_cmd_pool); + } + } else if (is_task_cmd(instance,i)) { + list_add_tail(&cmd->cmd_list, &context->task_cmd_pool); + init_completion(&cmd->sync_done); + } else if (is_mgr_cmd(instance,i)) { + list_add_tail(&cmd->cmd_list, &context->mgr_cmd_pool); + init_completion(&cmd->sync_done); + } +#ifdef _WINDOWS + else { + list_add_tail(&cmd->cmd_list, &context->scsi_cmd_pool); + } +#endif + } + +l_out: + return ret; +} + +static inline void ps3_host_max_sge_count(struct ps3_cmd_context *context) +{ + context->max_host_sge_count = PS3_FRAME_REQ_SGE_NUM_HW; + if (context->sgl_mode_support) { + if (context->ext_sge_frame_count > PS3_FRAME_REQ_EXT_SGE_MIN) { + context->max_host_sge_count += (U16)context->ext_sge_frame_count - PS3_FRAME_REQ_EXT_SGE_MIN; + } + } else if (context->ext_sge_frame_count > 1) { + context->max_host_sge_count = PS3_MAX((U16)(context->ext_sge_frame_count - 1), + context->max_host_sge_count); + } +} + +static inline void ps3_r1x_mode_set(struct ps3_instance *instance) +{ + struct ps3_cmd_context *context = &instance->cmd_context; + if (context->max_r1x_cmd_count >= context->max_scsi_cmd_count / 2) { + instance->r1x_mode = PS3_R1X_MODE_PERF; + } + LOG_INFO("host_no:%u r1x_mode:%u\n", PS3_HOST(instance), instance->r1x_mode); +} + +S32 ps3_cmd_context_init(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + struct ps3_cmd_context *context = &instance->cmd_context; + int cpu = 0; + S64 *scsi_cmd_deliver = NULL; + + if (!ps3_ioc_mgr_max_fw_cmd_get(instance, &context->max_cmd_count)) { + goto l_failed; + } +#ifdef PS3_HARDWARE_SIM + context->max_r1x_cmd_count = 16; +#else + if (!ps3_get_max_r1x_cmds_with_check(instance, + &context->max_r1x_cmd_count)) { + goto l_failed; + } +#endif + LOG_DEBUG("host_no:%u max_r1x_cmd_count:%u\n", + PS3_HOST(instance), context->max_r1x_cmd_count); + context->max_mgr_cmd_count = instance->max_mgr_cmd_total_count; + context->max_scsi_cmd_count = context->max_cmd_count - + instance->max_mgr_cmd_total_count; + + if (context->max_r1x_cmd_count > (context->max_scsi_cmd_count / 2 )) { + context->max_r1x_cmd_count = (context->max_scsi_cmd_count / 2); + } + ps3_r1x_mode_set(instance); + + LOG_DEBUG("host_no:%u max_r1x_cmd_final count:%u\n", + PS3_HOST(instance), context->max_r1x_cmd_count); + + if (!ps3_ioc_mgr_max_chain_size_get(instance, + &context->ext_sge_frame_count)) { + goto l_failed; + } + context->ext_sge_frame_count /= sizeof(struct PS3Sge); + + if (!ps3_ioc_mgr_max_nvme_page_size_get(instance, + &instance->cmd_attr.nvme_page_size)) { + goto l_failed; + } + context->max_prp_count = PS3_FRAME_REQ_PRP_NUM_FE + + (instance->cmd_attr.nvme_page_size / sizeof(U64)); + + ps3_host_max_sge_count(context); + + if (context->max_cmd_count <= instance->max_mgr_cmd_total_count) { + LOG_ERROR("max_cmd_count %d too few\n", + context->max_cmd_count); + goto l_failed; + } + + ret = ps3_cmd_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + ret = ps3_req_frame_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + ret = ps3_cmd_resp_frame_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + ret = ps3_cmd_ext_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + ret = ps3_cmd_r1xlock_buff_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + ret = ps3_cmd_mgr_trans_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + ret = ps3_cmd_init(instance); + if (ret != PS3_SUCCESS) { + goto l_failed; + } + + instance->scsi_cmd_deliver = alloc_percpu(S64); + INJECT_START(PS3_ERR_IJ_PS3_PERCPU_ALLOC, &instance->scsi_cmd_deliver); + if (!instance->scsi_cmd_deliver) { + LOG_ERROR("alloc per_cpu scsi_cmd_deliver failed. hno:%u\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } else { + for_each_possible_cpu(cpu) { + scsi_cmd_deliver = per_cpu_ptr(instance->scsi_cmd_deliver, cpu); + *scsi_cmd_deliver = 0; + } + } + + return ret; + +l_failed: + ps3_cmd_context_exit(instance); + return ret; +} + +void ps3_cmd_context_exit(struct ps3_instance *instance) +{ + ps3_cmd_mgr_trans_free(instance); + ps3_cmd_ext_buf_free(instance); + ps3_cmd_r1xlock_buff_free(instance); + ps3_cmd_resp_frame_free(instance); + ps3_req_frame_free(instance); + ps3_cmd_buf_free(instance); + + if (instance->scsi_cmd_deliver) { + free_percpu(instance->scsi_cmd_deliver); + instance->scsi_cmd_deliver = NULL; + } +} + +static void ps3_cmd_content_init(struct ps3_cmd *cmd) +{ + cmd->cmd_word_value = 0; +#ifndef _WINDOWS + cmd->scmd = NULL; +#else + cmd->srb = NULL; + memset(&cmd->scmd_imp, 0, sizeof(cmd->scmd_imp)); + cmd->scmd = &cmd->scmd_imp; +#endif + cmd->trace_id = 0; + cmd->no_reply_word = 0; + cmd->os_sge_map_count = 0; + INIT_LIST_HEAD(&cmd->cmd_list); + cmd->cmd_receive_cb = NULL; + cmd->cmd_send_cb = NULL; + + cmd->cmd_state.state = PS3_CMD_STATE_INIT; + cmd->cmd_state.reset_flag = 0; + cmd->qos_processing = PS3_FALSE; + cmd->time_out = 0; + cmd->is_interrupt = PS3_DRV_FALSE; + cmd->retry_cnt = 0; + cmd->is_force_polling = 0; + cmd->is_inserted_c_q = 0; + cmd->is_got_r1x = 0; + cmd->is_r1x_aborting = 0; + cmd->r1x_peer_cmd = NULL; + cmd->r1x_reply_flag = 0; + cmd->is_r1x_scsi_complete = PS3_FALSE; + cmd->flighting = PS3_FALSE; + cmd->r1x_read_pd = 0; + + memset(&cmd->io_attr, 0, sizeof(struct ps3_scsi_io_attr)); + memset((void*)&cmd->sync_done, 0, sizeof(cmd->sync_done)); + if (cmd->transient == NULL || cmd->transient->sge_num == 0) { + memset((void*)cmd->req_frame, 0, sizeof(union PS3ReqFrame)); + } + + memset((void*)cmd->resp_frame, 0xff, sizeof(PS3RespFrame_u)); + + memset(cmd->ext_buf, 0, cmd->instance->cmd_context.ext_buf_size); + + INIT_LIST_HEAD(&cmd->qos_list); + memset(&cmd->target_pd, 0, sizeof(struct ps3_qos_member_pd_info) * PS3_QOS_MAX_PD_IN_VD); + cmd->target_pd_count = 0; + cmd->first_over_quota_pd_idx = 0; + cmd->qos_waitq_flag = 0; + memset(&cmd->cmdq_info, 0, sizeof(struct ps3_qos_cmdq_info) * PS3_QOS_MAX_CMDQ_ONE_CMD); + cmd->cmdq_count = 0; +} + +static void ps3_scsi_cmd_content_init(struct ps3_cmd *cmd) +{ + cmd->cmd_word_value = 0; +#ifndef _WINDOWS + cmd->scmd = NULL; +#else + cmd->srb = NULL; + memset(&cmd->scmd_imp, 0, sizeof(cmd->scmd_imp)); + cmd->scmd = &cmd->scmd_imp; +#endif + cmd->trace_id = 0; + cmd->no_reply_word = 0; + cmd->os_sge_map_count = 0; + INIT_LIST_HEAD(&cmd->cmd_list); + cmd->cmd_receive_cb = NULL; + cmd->cmd_send_cb = NULL; + + cmd->cmd_state.state = PS3_CMD_STATE_INIT; + cmd->cmd_state.reset_flag = 0; + cmd->qos_processing = PS3_FALSE; + cmd->time_out = 0; + cmd->is_interrupt = PS3_DRV_FALSE; + cmd->retry_cnt = 0; + cmd->is_force_polling = 0; + cmd->is_inserted_c_q = 0; + cmd->is_got_r1x = 0; + cmd->is_r1x_aborting = 0; + cmd->r1x_peer_cmd = NULL; + cmd->r1x_reply_flag = 0; + cmd->is_r1x_scsi_complete = PS3_FALSE; + cmd->flighting = PS3_FALSE; + cmd->r1x_read_pd = 0; + + if (cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].length != 0) { + memset(cmd->ext_buf, 0, cmd->instance->cmd_context.ext_buf_size); + } + + if (!ps3_scsih_is_rw_type(cmd->io_attr.rw_flag) && + (cmd->transient == NULL || cmd->transient->sge_num == 0)) { + memset((void*)cmd->req_frame, 0, sizeof(union PS3ReqFrame)); + } + + if (cmd->resp_frame->normalRespFrame.respStatus != 0xFF) { + cmd->resp_frame->normalRespFrame.respStatus = 0xFF; + } + + if (cmd->resp_frame->sasRespFrame.status != 0xFF) { + cmd->resp_frame->sasRespFrame.status = 0xFF; + } + + memset((void*)&cmd->sync_done, 0, sizeof(cmd->sync_done)); + memset(&cmd->io_attr, 0, sizeof(struct ps3_scsi_io_attr)); + INIT_LIST_HEAD(&cmd->qos_list); + memset(&cmd->target_pd, 0, sizeof(struct ps3_qos_member_pd_info) * PS3_QOS_MAX_PD_IN_VD); + cmd->target_pd_count = 0; + cmd->first_over_quota_pd_idx = 0; + cmd->qos_waitq_flag = 0; + memset(&cmd->cmdq_info, 0, sizeof(struct ps3_qos_cmdq_info) * PS3_QOS_MAX_CMDQ_ONE_CMD); + cmd->cmdq_count = 0; +} + +#ifndef _WINDOWS +struct ps3_cmd *ps3_scsi_cmd_alloc(struct ps3_instance *instance, U32 tag) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + + if (tag < (U32)instance->cmd_attr.cur_can_que) { + cmd = context->cmd_buf[tag]; + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_trace_id_alloc(&cmd->trace_id); + cmd->flighting = PS3_TRUE; + } + return cmd; +} + +S32 ps3_scsi_cmd_free(struct ps3_cmd *cmd) +{ + S32 ret = -PS3_FAILED; + + if (cmd->index < (U32)cmd->instance->cmd_attr.cur_can_que) { + ps3_scsi_cmd_content_init(cmd); + ret = PS3_SUCCESS; + } + return ret; +} +#else +struct ps3_cmd *ps3_scsi_cmd_alloc(struct ps3_instance *instance) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + ULong flags = 0; + + ps3_spin_lock_irqsave(&context->scsi_pool_lock, &flags); + if (!list_empty(&context->scsi_cmd_pool)) { + cmd = list_entry(list_remove_head(&context->scsi_cmd_pool), struct ps3_cmd, cmd_list); + } + ps3_spin_unlock_irqrestore(&context->scsi_pool_lock, flags); + + if (cmd != NULL) { + cmd->trace_id = ps3_atomic64_inc(&context->trace_id); + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + } + return cmd; +} + +S32 ps3_scsi_cmd_free(struct ps3_cmd *cmd) +{ + S32 ret = -PS3_FAILED; + U32 max_count = 0; + ULong flags = 0; + struct ps3_cmd_context *context = &cmd->instance->cmd_context; + + if (unlikely(cmd == NULL)) { + goto l_out; + } + + max_count = context->max_scsi_cmd_count; + if (cmd->index < max_count) { + ps3_cmd_content_init(cmd); + ret = PS3_SUCCESS; + } + + ps3_spin_lock_irqsave(&context->scsi_pool_lock, &flags); + list_add_tail(&cmd->cmd_list, &context->scsi_cmd_pool); + ps3_spin_unlock_irqrestore(&context->scsi_pool_lock, flags); +l_out: + return ret; +} +#endif + +static void cmd_pool_free(ps3_list_head *pool_list, + ps3_spinlock *pool_lock, struct ps3_cmd *cmd) +{ + ULong flags = 0; + ps3_spin_lock_irqsave(pool_lock, &flags); + list_add_tail(&cmd->cmd_list, pool_list); + ps3_spin_unlock_irqrestore(pool_lock, flags); +} + +static struct ps3_cmd *cmd_pool_alloc(ps3_list_head *pool_list, + ps3_spinlock *pool_lock) +{ + struct ps3_cmd *cmd = NULL; + ULong flags = 0; +#ifdef _WINDOWS + struct ps3_cmd_context *context = NULL; +#endif + ps3_spin_lock_irqsave(pool_lock, &flags); + if (!list_empty(pool_list)) { +#ifdef _WINDOWS + cmd = list_first_entry(pool_list, struct ps3_cmd, cmd_list); +#else + cmd = list_entry(pool_list->next, struct ps3_cmd, cmd_list); +#endif + list_del_init(&cmd->cmd_list); + } + ps3_spin_unlock_irqrestore(pool_lock, flags); + + if(cmd != NULL) { +#ifndef _WINDOWS + ps3_trace_id_alloc(&cmd->trace_id); +#else + context = &cmd->instance->cmd_context; + cmd->trace_id = ps3_atomic64_inc(&context->trace_id); +#endif + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + init_completion(&cmd->sync_done); + } + + return cmd; +} + +Bool ps3_r1x_peer_cmd_free_nolock(struct ps3_cmd *cmd) +{ + Bool ret = PS3_TRUE; + struct ps3_cmd_context *context = NULL; + struct ps3_instance *instance = cmd->instance; + + context = &instance->cmd_context; + if (!is_r1x_peer_cmd(instance, cmd->index)) { + ret = PS3_FALSE; + goto l_out; + } + + if(cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + goto l_out; + } + + ps3_scsi_cmd_content_init(cmd); + if (instance->r1x_mode == PS3_R1X_MODE_NORMAL) { + cmd_pool_free(&context->r1x_scsi_cmd_pool, + &context->r1x_scsi_pool_lock, cmd); + } +l_out: + return ret; +} + +S32 ps3_mgr_cmd_free_nolock(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd_context *context = NULL; + + context = &instance->cmd_context; + if (cmd->index < context->max_scsi_cmd_count) { + ret = -PS3_FAILED; + goto l_out; + } + + if(cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + goto l_out; + } + + ps3_cmd_content_init(cmd); + INJECT_START(PS3_ERR_FORCE_SET_CMD_INDEX_NOT_MGR, &cmd->index); + if (is_task_cmd(instance, cmd->index)) { + cmd_pool_free(&context->task_cmd_pool, + &context->task_pool_lock, cmd); + } else if (is_mgr_cmd(instance, cmd->index)) { + cmd_pool_free(&context->mgr_cmd_pool, + &context->mgr_pool_lock, cmd); + } else { + LOG_INFO_IN_IRQ(instance, "host_no:%u CFID:%u not mgr cmd!\n", + PS3_HOST(instance), cmd->index); + PS3_BUG(); + ret = -PS3_FAILED; + } +l_out: + return ret; +} + +S32 ps3_async_cmd_send(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + mb(); + ret = ps3_cmd_send_pre_check(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cmd == instance->event_context.event_cmd) { + INJECT_START(PS3_ERR_IJ_FORCE_EVENT_CMD_FAIL_DEAD, &cur_state) + } + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + if (instance->is_probe_finish && !instance->is_resume) { + LOG_FILE_ERROR("host_no:%u cannot send async cmd due to %s, return fail\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = -PS3_FAILED; + } else { + LOG_FILE_WARN("host_no:%u cannot send async cmd due to %s, return recovered\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = -PS3_RECOVERED; + } + goto l_out; + } + + instance->ioc_adpter->cmd_send(instance, &cmd->cmd_word); +l_out: + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + return ret; +} +#ifndef _WINDOWS + +static void ps3_r1x_peer_cmd_build(struct ps3_cmd *cmd, + struct ps3_cmd *peer_cmd) +{ + memcpy(peer_cmd->req_frame, cmd->req_frame, + sizeof(union PS3ReqFrame)); + memcpy((void*)&peer_cmd->io_attr, (void*)&cmd->io_attr, + sizeof(struct ps3_scsi_io_attr)); + memcpy(peer_cmd->ext_buf, cmd->ext_buf, cmd->instance->cmd_context.ext_buf_size); + + peer_cmd->scmd = cmd->scmd; + peer_cmd->is_got_r1x = cmd->is_got_r1x; + peer_cmd->szblock_cnt = cmd->szblock_cnt; + peer_cmd->os_sge_map_count = cmd->os_sge_map_count; + peer_cmd->cmd_receive_cb = cmd->cmd_receive_cb; + peer_cmd->io_attr.pd_entry = cmd->io_attr.peer_pd_entry; + peer_cmd->io_attr.disk_id = PS3_PDID(&peer_cmd->io_attr.pd_entry->disk_pos); + peer_cmd->io_attr.plba = cmd->io_attr.plba_back; + + peer_cmd->cmd_word_value = cmd->cmd_word_value; + peer_cmd->cmd_word.phyDiskID = PS3_PDID(&peer_cmd->io_attr.pd_entry->disk_pos); + peer_cmd->cmd_word.cmdFrameID = peer_cmd->index; + + peer_cmd->req_frame->hwReq.reqHead.cmdFrameID = peer_cmd->index; + peer_cmd->req_frame->hwReq.reqHead.devID.diskID = + peer_cmd->io_attr.pd_entry->disk_pos.diskDev.diskID; + peer_cmd->req_frame->hwReq.reqHead.traceID = peer_cmd->trace_id; + + ps3_vd_direct_req_frame_build(peer_cmd); + + cmd->r1x_peer_cmd = peer_cmd; + peer_cmd->r1x_peer_cmd = cmd; + cmd->is_r1x_scsi_complete = PS3_FALSE; + peer_cmd->is_r1x_scsi_complete = PS3_FALSE; + + LOG_DEBUG("host_no:%u r1x direct write cmd:%d, peer cmd:%d build:" + " tid:0x%llx pid:%u plba:0x%llx\n", + PS3_HOST(cmd->instance), cmd->index, peer_cmd->index, + peer_cmd->trace_id, peer_cmd->cmd_word.phyDiskID, + peer_cmd->io_attr.plba); +} + +static struct ps3_cmd* ps3_r1x_scsi_peer_prepare(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + struct ps3_cmd *peer_cmd = NULL; + if (cmd->io_attr.direct_flag != PS3_CMDWORD_DIRECT_ADVICE || + cmd->io_attr.peer_pd_entry == NULL) { + goto _lout; + } + + peer_cmd = ps3_r1x_peer_cmd_alloc(instance, cmd->index); + if (peer_cmd != NULL) { + ps3_r1x_peer_cmd_build(cmd, peer_cmd); + } else { + LOG_DEBUG("host_no:%u cmd:%d can not alloc r1x peer cmd any more\n", + PS3_HOST(instance), cmd->index); + instance->ioc_adpter->io_cmd_rebuild(cmd); + } +_lout: + return peer_cmd; +} + +void ps3_wait_scsi_cmd_done(struct ps3_instance *instance, Bool time_out) +{ + int cpu = 0; + S64 result = 0; + U16 try_cnt = 0; + + if (instance->scsi_cmd_deliver) { + do { + result = 0; + for_each_possible_cpu(cpu) { + result += *per_cpu_ptr(instance->scsi_cmd_deliver, cpu); + } + + if (result > 0) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + if (time_out) { + try_cnt++; + if (try_cnt > PS3_WAIT_SCSI_CMD_DONE_COUNT) { + LOG_WARN("hno:%u wait scsi cmd done NOK\n", + PS3_HOST(instance)); + INJECT_START(PS3_ERR_IJ_WAIT_SCSI_CMD_DONE_FAIL, instance); + break; + } + } + } + } while (result); + } + + LOG_INFO("wait scsi cmd done end. hno:%u try_cnt[%u]\n", + PS3_HOST(instance), try_cnt); +} + +void ps3_scsi_cmd_deliver_get(struct ps3_instance *instance) +{ + S64 *cmd_deliver = NULL; + cmd_deliver = get_cpu_ptr(instance->scsi_cmd_deliver); + (*cmd_deliver)++; + put_cpu_ptr(cmd_deliver); +} + +void ps3_scsi_cmd_deliver_put(struct ps3_instance *instance) +{ + S64 *cmd_deliver = NULL; + cmd_deliver = get_cpu_ptr(instance->scsi_cmd_deliver); + (*cmd_deliver)--; + put_cpu_ptr(cmd_deliver); +} + +void ps3_wait_mgr_cmd_done(struct ps3_instance *instance, Bool time_out) +{ + U16 try_cnt = 0; + + while (ps3_atomic_read(&instance->cmd_statistics.cmd_delivering) != 0) { + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED_2, instance); + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + if (time_out) { + try_cnt++; + if (try_cnt > PS3_WAIT_SCSI_CMD_DONE_COUNT) { + LOG_WARN("hno:%u wait mgr cmd done NOK\n", + PS3_HOST(instance)); + break; + } + } + } + + LOG_INFO("wait mgr cmd done end. hno:%u try_cnt[%u]\n", + PS3_HOST(instance), try_cnt); +} + +S32 ps3_scsi_cmd_send(struct ps3_instance *instance, struct ps3_cmd *cmd, Bool need_prk_err) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *peer_cmd = NULL; + + ret = ps3_cmd_send_pre_check(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + PS3_IJ_SLEEP(10000, PS3_ERR_IJ_SCSI_DELIVER_DELAY); + INJECT_START(PS3_ERR_IJ_WAIT_TASK_MGR_BUSY, instance); + INJECT_START(PS3_ERR_IJ_FORCE_TASK_MGR_BUSY, instance); + if (unlikely(instance->task_manager_host_busy)) { + INJECT_START(PS3_ERR_IJ_SEND_CMD_TASK_MGR_BUSY, instance); + LOG_INFO_LIM_WITH_CHECK(instance, need_prk_err, + "host_no:%u cannot send block cmd due to task_manager_host_busy\n", + PS3_HOST(instance)); + + ret = -PS3_RETRY; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_CMD_SEND_FORCE_INS_UNLOAD, instance) + if (!instance->state_machine.is_load) { + LOG_WARN_LIM_WITH_CHECK(instance, need_prk_err, + "host_no:%u instance state not is_load\n", PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_CMD_SEND_BLOCK, instance); + INJECT_START(PS3_ERR_IJ_CMD_SEND_FORCE_UNORMAL, instance); + + PS3_IJ_SLEEP(10000, PS3_ERR_IJ_SCSI_DELIVER_DELAY_2); + + if (!ps3_is_instance_state_normal(instance, need_prk_err)) { + ret = -PS3_RECOVERED; + goto l_out; + } + + peer_cmd = ps3_r1x_scsi_peer_prepare(instance, cmd); + + PS3_DEV_IO_START_INC(instance, cmd); + PS3_DEV_IO_START_OK_INC(instance, cmd); + PS3_DEV_IO_OUTSTAND_INC(instance, cmd); + PS3_IO_DRV2IOC_START_INC(instance, cmd); + cmd->flighting = PS3_FALSE; + wmb(); + + INJECT_START(PS3_ERR_IJ_CMD_BLOCK_BEFORE_SEND_TO_IOC, instance); + ps3_ioc_scsi_cmd_send(instance, &cmd->cmd_word); + INJECT_START(PS3_ERR_IJ_WAIT_CMD_DONE, instance); + if (peer_cmd != NULL) { + PS3_IO_DRV2IOC_START_INC(instance, peer_cmd); + ps3_ioc_scsi_cmd_send(instance, &peer_cmd->cmd_word); + } +l_out: + + return ret; +} +#endif + +struct ps3_cmd *ps3_cmd_find(struct ps3_instance *instance, U16 cmd_frame_id) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + if (cmd_frame_id >= context->max_cmd_count) { + LOG_ERROR_IN_IRQ(instance, "host_no:%u CFID:%d invalid\n", + PS3_HOST(instance), cmd_frame_id); + goto l_failed; + } + + cmd = context->cmd_buf[cmd_frame_id]; + if (cmd->index != cmd_frame_id) { + LOG_ERROR_IN_IRQ(instance, "host_no:%u CFID:%d incorrect, expect CFID:%d\n", + PS3_HOST(instance), cmd_frame_id, cmd->index); + cmd = NULL; + goto l_failed; + } + +l_failed: + return cmd; +} + +S32 ps3_cmd_dispatch(struct ps3_instance *instance, U16 cmd_frame_id, struct PS3ReplyWord *reply_word) +{ + S32 ret = -PS3_FAILED; + struct ps3_cmd *cmd = NULL; + U16 reply_flags = 0xff; + + if (reply_word->retType == PS3_HARD_RET && + reply_word->retStatus == PS3_REPLY_WORD_FLAG_REPEAT_REPLY) { + LOG_ERROR_IN_IRQ(instance, "hno:%u repeated response CFID:%u reply_word:0x%llx\n", + PS3_HOST(instance), cmd_frame_id, *(U64 *)reply_word); + goto l_out; + } + cmd = ps3_cmd_find(instance, cmd_frame_id); + if (cmd == NULL) { + goto l_out; + } + memcpy(&(cmd->reply_word), reply_word, sizeof(struct PS3ReplyWord)); + reply_flags = reply_word->retStatus; + if (cmd->cmd_receive_cb) { + ret = cmd->cmd_receive_cb(cmd, reply_flags); + } else { + LOG_ERROR_IN_IRQ(instance, "warn ps3 cmd index %d has no cmd_receive_cb\n", + cmd->index); + } +l_out: + return ret; +} + +Bool ps3_is_instance_state_allow_cmd_execute(struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + cur_state = ps3_atomic_read(&instance->state_machine.state); + INJECT_START(PS3_ERR_IJ_INS_STATE_UNNORMAL, &cur_state) + INJECT_START(PS3_ERR_IJ_INS_STATE_DEAD, &cur_state) + INJECT_START(PS3_ERR_IJ_V2_FORCE_INS_STATE_UNNORMAL, instance); + INJECT_START(PS3_ERR_IJ_V2_FORCE_INS_DEAD, instance); + if (cur_state == PS3_INSTANCE_STATE_DEAD && + (PS3_IOC_STATE_HALT_SUPPORT(instance) == PS3_TRUE) && + PS3_HALT_CLI_SUPPORT(instance)){ + goto l_out; + } + + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_SOFT_RECOVERY) { + LOG_FILE_INFO("host_no:%u cannot handle cmd, driver state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = PS3_FALSE; + } + +l_out: + return ret; +} + +S32 ps3_cmd_send_pre_check(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + if (instance->is_probe_finish && !instance->state_machine.is_load) { + LOG_FILE_INFO("host_no:%u instance state state is unloading\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_CMD_SEND_FORCE_PCI_ERR, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_FILE_WARN("host_no:%u cannot send block cmd due to pci err recovery\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } +l_out: + return ret; +} + +S32 ps3_mgr_cmd_send_pre_check(struct ps3_instance *instance, Bool no_check) +{ + S32 ret = PS3_SUCCESS; + INJECT_START(PS3_ERR_IJ_V2_IS_LOAD_FALSE, instance); + if (!no_check && !instance->state_machine.is_load) { + LOG_WARN_LIM("hno[%u] instance state not is_load\n", + PS3_HOST(instance)); + ret = -PS3_IN_UNLOAD; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_UNORMAL, instance); + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + ret = -PS3_RECOVERED; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_V2_PCIE_ERR, instance); + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN_LIM("hno[%u] host in pci err recovery\n", + PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } +l_out: + return ret; +} + +S32 ps3_mgr_cmd_send_check(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state = ps3_atomic_read(&instance->state_machine.state); + + INJECT_START(PS3_ERR_IJ_V2_IS_LOAD_FALSE, instance); + if (!instance->state_machine.is_load) { + if (PS3_MGR_CMD_TYPE(cmd) != PS3_CMD_MANAGEMENT){ + ret = -PS3_IN_UNLOAD; + goto l_failed; + } + } + INJECT_START(PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_UNORMAL, instance); + INJECT_START(PS3_ERR_IJ_V2_FORCE_INS_DEAD1, instance); + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + ret = -PS3_RECOVERED; + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_IOCTL) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_QUIT || + cur_state == PS3_INSTANCE_STATE_DEAD) { + goto l_failed; + } + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_BUSY; + ret = -PS3_RESP_ERR; + } + goto l_failed; + } + INJECT_START(PS3_ERR_IJ_V2_PCIE_ERR, instance); + if (ps3_pci_err_recovery_get(instance)) { + ret = -PS3_IN_PCIE_ERR; + goto l_failed; + } + goto l_out; + +l_failed: + LOG_WARN_LIM("hno:%u, tid:0x%llx CFID:%u type:%d state:%d send check ret:%d\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, PS3_MGR_CMD_TYPE(cmd), cur_state, ret); +l_out: + return ret; +} + +void ps3_dma_addr_bit_pos_update(struct ps3_instance *instance, U8 bit_pos) +{ + U32 i = 0; + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + struct ps3_debug_context *debug_context = &instance->debug_context; + struct ps3_dump_context *dump_context = &instance->dump_context; + struct ps3_dev_context *dev_context = &instance->dev_context; + struct ps3_sas_dev_context *ps3_sas_ctx = &instance->sas_dev_context; + struct ps3_cmd *cmd = NULL; + + irq_context->reply_fifo_desc_buf_phys = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, + irq_context->reply_fifo_desc_buf_phys); + irq_context->reply_fifo_desc_buf_phys = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, + irq_context->reply_fifo_desc_buf_phys); + for (; i < irq_context->valid_msix_vector_count; i++) { + irq_context->reply_fifo_desc_buf[i].ReplyFifoBaseAddr = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, irq_context->reply_fifo_desc_buf[i].ReplyFifoBaseAddr); + irq_context->reply_fifo_desc_buf[i].ReplyFifoBaseAddr = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, + irq_context->reply_fifo_desc_buf[i].ReplyFifoBaseAddr); + irq_context->reply_fifo_phys_base_addr_buf[i] = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, + irq_context->reply_fifo_phys_base_addr_buf[i]); + irq_context->reply_fifo_phys_base_addr_buf[i] = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, + irq_context->reply_fifo_phys_base_addr_buf[i]); + } + cmd_context->init_frame_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, cmd_context->init_frame_buf_phys); + cmd_context->init_frame_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, cmd_context->init_frame_buf_phys); + cmd_context->init_filter_table_phy_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, cmd_context->init_filter_table_phy_addr); + cmd_context->init_filter_table_phy_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, cmd_context->init_filter_table_phy_addr); + if (cmd_context->init_frame_sys_info_buf != NULL) { + cmd_context->init_frame_sys_info_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, cmd_context->init_frame_sys_info_phys); + cmd_context->init_frame_sys_info_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, cmd_context->init_frame_sys_info_phys); + } + instance->ctrl_info_buf_h = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, instance->ctrl_info_buf_h); + instance->ctrl_info_buf_h = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, instance->ctrl_info_buf_h); + cmd_context->req_frame_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, cmd_context->req_frame_buf_phys); + cmd_context->req_frame_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, cmd_context->req_frame_buf_phys); + cmd_context->response_frame_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, cmd_context->response_frame_buf_phys); + cmd_context->response_frame_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, cmd_context->response_frame_buf_phys); + for (i = 0; i < cmd_context->max_cmd_count; i++) { + cmd = cmd_context->cmd_buf[i]; + if (cmd->ext_buf != NULL) { + cmd->ext_buf_phys = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, cmd->ext_buf_phys); + cmd->ext_buf_phys = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, cmd->ext_buf_phys); + } + } + if (debug_context->debug_mem_buf != NULL) { + debug_context->debug_mem_buf_phy = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, debug_context->debug_mem_buf_phy); + debug_context->debug_mem_buf_phy = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, debug_context->debug_mem_buf_phy); + for (i = 0; i < debug_context->debug_mem_array_num; i++) { + debug_context->debug_mem_buf[i].debugMemAddr = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, + debug_context->debug_mem_buf[i].debugMemAddr); + debug_context->debug_mem_buf[i].debugMemAddr = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, + debug_context->debug_mem_buf[i].debugMemAddr); + } + } + if (dump_context->dump_dma_buf != NULL) { + dump_context->dump_dma_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dump_context->dump_dma_addr); + dump_context->dump_dma_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, dump_context->dump_dma_addr); + } + instance->drv_info_buf_phys = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, instance->drv_info_buf_phys); + instance->drv_info_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, instance->drv_info_buf_phys); + instance->host_mem_info_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, instance->host_mem_info_buf_phys); + instance->host_mem_info_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, instance->host_mem_info_buf_phys); + if (dev_context->pd_list_buf != NULL) { + dev_context->pd_list_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dev_context->pd_list_buf_phys); + dev_context->pd_list_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, dev_context->pd_list_buf_phys); + } + if (dev_context->pd_info_buf != NULL) { + dev_context->pd_info_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dev_context->pd_info_buf_phys); + dev_context->pd_info_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, dev_context->pd_info_buf_phys); + } + if (dev_context->vd_list_buf != NULL) { + dev_context->vd_list_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dev_context->vd_list_buf_phys); + dev_context->vd_list_buf_phys = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, dev_context->vd_list_buf_phys); + } + if (dev_context->vd_info_buf_sync != NULL) { + dev_context->vd_info_buf_phys_sync = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dev_context->vd_info_buf_phys_sync); + dev_context->vd_info_buf_phys_sync = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, dev_context->vd_info_buf_phys_sync); + } + if (dev_context->vd_info_buf_async != NULL) { + dev_context->vd_info_buf_phys_async = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dev_context->vd_info_buf_phys_async); + dev_context->vd_info_buf_phys_async = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, dev_context->vd_info_buf_phys_async); + } + if (ps3_sas_ctx->ps3_sas_buff != NULL) { + ps3_sas_ctx->ps3_sas_buff_dma_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, ps3_sas_ctx->ps3_sas_buff_dma_addr); + ps3_sas_ctx->ps3_sas_buff_dma_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, ps3_sas_ctx->ps3_sas_buff_dma_addr); + } + if (ps3_sas_ctx->ps3_sas_phy_buff != NULL) { + ps3_sas_ctx->ps3_sas_phy_buff_dma_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, ps3_sas_ctx->ps3_sas_phy_buff_dma_addr); + ps3_sas_ctx->ps3_sas_phy_buff_dma_addr = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, ps3_sas_ctx->ps3_sas_phy_buff_dma_addr); + } + instance->so_start_addr = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, instance->so_start_addr); + instance->so_start_addr = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, instance->so_start_addr); + instance->so_end_addr = PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, instance->so_end_addr); + instance->so_end_addr = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, instance->so_end_addr); +} + +Bool ps3_bit_pos_update(struct ps3_instance *instance) +{ + U8 old_bit_pos = instance->dma_addr_bit_pos; + U8 bit_pos = 0; + Bool ret = PS3_FALSE; + + if (!ps3_ioc_atu_support_retry_read(instance, &bit_pos)) { + goto l_out; + } + switch(bit_pos) { + case PS3_BIT_POS_DEFAULT: + case PS3_BIT_POS_44: + instance->dma_addr_bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS; + break; + case PS3_BIT_POS_53: + instance->dma_addr_bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS_F1; + break; + case PS3_BIT_POS_54: + instance->dma_addr_bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS_F0; + break; + default: + LOG_WARN("hno:%u bit pos value is unexpect %u\n", + PS3_HOST(instance), bit_pos); + goto l_out; + } + mb(); + if (instance->dma_addr_bit_pos == old_bit_pos) { + ret = PS3_TRUE; + goto l_out; + } + ps3_dma_addr_bit_pos_update(instance, old_bit_pos); + LOG_WARN("hno:%u bit pos %u change to %u\n", + PS3_HOST(instance), old_bit_pos, instance->dma_addr_bit_pos); + ret = PS3_TRUE; +l_out: + return ret; +} + diff --git a/drivers/scsi/ps3stor/ps3_cmd_channel.h b/drivers/scsi/ps3stor/ps3_cmd_channel.h new file mode 100644 index 0000000000000000000000000000000000000000..5d579a29ecb9889153ec0251bafb6946ecae2f2a --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_channel.h @@ -0,0 +1,344 @@ + +#ifndef _PS3_CMD_CHANNEL_H_ +#define _PS3_CMD_CHANNEL_H_ + +#include "ps3_htp.h" +#include "ps3_htp_reqframe.h" + +#ifdef _WINDOWS +#include "ps3_def.h" +#include "ps3_cmd_adp.h" + +#endif +#include "ps3_platform_utils.h" +#include "ps3_inner_data.h" +#include "ps3_driver_log.h" +#include "ps3_htp_ioctl.h" + +#define PS3_DEFAULT_REQ_FRAME_SIZE (256) + +#define PS3_WAIT_SCSI_CMD_DONE_COUNT (1200) + +enum { + DMA_ALIGN_BYTES_4K = 4096, + DMA_ALIGN_BYTES_2K = 2048, + DMA_ALIGN_BYTES_1K = 1024, + DMA_ALIGN_BYTES_512 = 512, + DMA_ALIGN_BYTES_256 = 256, + DMA_ALIGN_BYTES_128 = 128, + DMA_ALIGN_BYTES_64 = 64, + DMA_ALIGN_BYTES_16 = 16, + DMA_ALIGN_BYTES_4 = 4, +}; + +enum { + PS3_CMD_STATE_INIT = 0, + PS3_CMD_STATE_PROCESS = 1, + PS3_CMD_STATE_COMPLETE = 2, + PS3_CMD_STATE_DEAD = 3, +}; +enum { + PS3_CMD_FLAG_SOFTRESET = 1, + PS3_CMD_FLAG_HARDRESET = 2, +}; + +enum { + PS3_R1X_MODE_NORMAL = 0, + PS3_R1X_MODE_PERF = 1, +}; + +#define PS3_CMD_EXT_BUF_DEFAULT_SIZE (4096) +#define PS3_CMD_EXT_BUF_SIZE_MGR (4096) + +#define PS3_MIN_SCSI_CMD_COUNT (4096) + +static inline const S8 *namePS3CmdState(U32 s) +{ + static const S8 *myNames[] = { + [PS3_CMD_STATE_INIT] = "PS3_CMD_STATE_INIT", + [PS3_CMD_STATE_PROCESS] = "PS3_CMD_STATE_PROCESS", + [PS3_CMD_STATE_COMPLETE] = "PS3_CMD_STATE_COMPLETE", + [PS3_CMD_STATE_DEAD] = "PS3_CMD_STATE_DEAD" + }; + + if (s > PS3_CMD_STATE_DEAD) { + return "PS3_CMD_STATE_INVALID"; + } + + return myNames[s]; +} + +struct ps3_cmd_state_t { + U8 state; + U8 reset_flag; + U8 reserived[6]; + ps3_spinlock lock; +}; +typedef union ps3_scsi_cdb_option { + struct { + U8 non_ncq : 1; + U8 reserved0 : 1; + U8 reserved1 : 1; + U8 fua : 1; + U8 dpo : 1; + U8 protect : 3; + }; + U8 option; +} ps3_scsi_cdb_opts_u; + +struct ps3_scsi_io_attr +{ + Bool is_retry_cmd; + U8 direct_flag; + U8 seq_flag; + U8 dev_type; + union + { + struct{ + U8 rw_flag : 7; + U8 is_confilct_check : 1; + }; + U8 rw_type; + }; + U32 num_blocks; + U32 lba_lo; + U32 lba_hi; + const struct ps3_pd_entry *pd_entry; + const struct ps3_pd_entry *peer_pd_entry; + const struct PS3VDEntry *vd_entry; + + U64 plba; + U64 plba_back; + U8 span_idx; + U8 span_pd_idx; + U16 disk_id; + Bool is_use_frontend_prp; + U8 span_pd_idx_p; + U8 span_pd_idx_q; + U8 is_force_normal:1; + U8 reserved:7; + ps3_scsi_cdb_opts_u cdb_opts; + U8 cdb[PS3_FRAME_CDB_BUFLEN]; + U32 sgl_buf_len; + U32 reserved1; +}; + +struct ps3_ioctl_transient { + U16 sge_num; + U8 reserved[6]; + void *transient_buff[PS3_MAX_IOCTL_SGE_NUM]; +}; + +#define PS3_QOS_MAX_PD_IN_VD (17) +struct ps3_qos_member_pd_info { + U16 flat_disk_id; + U16 strip_count; + Bool get_quota; +}; + +#define PS3_QOS_MAX_CMDQ_ONE_CMD 2 +struct ps3_qos_cmdq_info { + U8 que_id; + Bool get_rc; +}; + +struct ps3_cmd { + union PS3ReqFrame *req_frame; + U64 req_frame_phys; + void *ext_buf; + U64 ext_buf_phys; + PS3RespFrame_u *resp_frame; + U64 resp_frame_phys; + struct ps3_instance *instance; + union { + struct PS3CmdWord cmd_word; + struct PS3InitCmdWord init_cmd_word; + U64 cmd_word_value; + }; + + struct scsi_cmnd *scmd; + +#ifndef _WINDOWS + struct list_head cmd_list; +#else + SCSI_REQUEST_BLOCK *srb; + ps3_list_head cmd_list; +#endif + + U64 trace_id; + U16 index; + U8 no_reply_word; + U8 is_force_polling; + U8 is_got_r1x; + U8 is_inserted_c_q; + U8 is_r1x_aborting; + Bool is_r1x_scsi_complete; + U16 r1x_read_pd; + struct ps3_cmd *r1x_peer_cmd; + U8 is_aborting; + U8 r1x_reply_flag; + U8 qos_processing; + U32 os_sge_map_count; + struct ps3_cmd_state_t cmd_state; + U16 time_out; + Bool is_interrupt; + U8 szblock_cnt; + U32 retry_cnt; + void* node_buff; +#ifdef _WINDOWS + KEVENT sync_done; +#else + struct completion sync_done; +#endif + S32 (*cmd_send_cb)(struct ps3_instance *, struct ps3_cmd *, U16 ); + S32 (*cmd_receive_cb)(struct ps3_cmd *, U16); + struct ps3_ioctl_transient *transient; + struct ps3_scsi_io_attr io_attr; +#ifdef _WINDOWS + struct scsi_cmnd scmd_imp; +#endif + struct PS3ReplyWord reply_word; + + struct list_head qos_list; + struct ps3_qos_member_pd_info target_pd[PS3_QOS_MAX_PD_IN_VD]; + struct ps3_qos_cmdq_info cmdq_info[PS3_QOS_MAX_CMDQ_ONE_CMD]; + U16 target_pd_count; + U16 first_over_quota_pd_idx; + U8 qos_waitq_flag; + U8 cmdq_count; + Bool flighting; +}; + +struct ps3_cmd_context { + U32 max_cmd_count; + U32 max_scsi_cmd_count; + U32 max_mgr_cmd_count; + U32 max_prp_count; + struct ps3_cmd **cmd_buf; + + dma_addr_t init_frame_buf_phys; + U8 *init_frame_buf; + dma_addr_t init_filter_table_phy_addr; + U8 *init_filter_table_buff; +#ifndef _WINDOWS + struct dma_pool* req_frame_dma_pool; +#endif + U32 req_frame_buf_size; + dma_addr_t req_frame_buf_phys; + U8 *req_frame_buf; +#ifndef _WINDOWS + struct dma_pool* response_frame_dma_pool; +#endif + U32 response_frame_buf_size; + dma_addr_t response_frame_buf_phys; + U8 *response_frame_buf; +#ifndef _WINDOWS + struct dma_pool* ext_buf_dma_pool; +#endif + U32 ext_buf_size; + U32 ext_sge_frame_count; +#ifndef _WINDOWS + struct dma_pool* mgr_ext_buf_dma_pool; +#endif + U32 mgr_ext_buf_size; + + dma_addr_t init_frame_sys_info_phys; + U8 *init_frame_sys_info_buf; + U8 sgl_mode_support; + U8 reserved0[1]; + U16 max_host_sge_count; + +#ifndef _WINDOWS + struct list_head mgr_cmd_pool; + struct list_head task_cmd_pool; + struct list_head r1x_scsi_cmd_pool; + spinlock_t mgr_pool_lock; + spinlock_t task_pool_lock; + spinlock_t r1x_scsi_pool_lock; +#else + ps3_list_head mgr_cmd_pool; + ps3_list_head task_cmd_pool; + ps3_list_head scsi_cmd_pool; + ps3_spinlock mgr_pool_lock; + ps3_spinlock task_pool_lock; + ps3_spinlock scsi_pool_lock; + + ps3_atomic64 trace_id; +#endif + U16 max_r1x_cmd_count; + U8 reserved1[6]; +}; + +S32 ps3_cmd_context_init(struct ps3_instance *instance); + +void ps3_cmd_context_exit(struct ps3_instance *instance); + +#ifndef _WINDOWS +struct ps3_cmd *ps3_scsi_cmd_alloc(struct ps3_instance *instance, U32 tag); +#else +struct ps3_cmd *ps3_scsi_cmd_alloc(struct ps3_instance *instance); +#endif +S32 ps3_scsi_cmd_free(struct ps3_cmd *cmd); + +struct ps3_cmd *ps3_mgr_cmd_alloc(struct ps3_instance *instance); + +S32 ps3_mgr_cmd_free_nolock(struct ps3_instance *instance, struct ps3_cmd *cmd); +S32 ps3_mgr_cmd_free(struct ps3_instance *instance, struct ps3_cmd *cmd); + +struct ps3_cmd *ps3_task_cmd_alloc(struct ps3_instance *instance); + +S32 ps3_task_cmd_free(struct ps3_instance *instance, struct ps3_cmd *cmd); + +S32 ps3_reply_cmd_dispatcher(struct ps3_instance *instance, U16 cmd_frame_id); + +S32 ps3_async_cmd_send(struct ps3_instance *instance, struct ps3_cmd *cmd); + +#ifndef _WINDOWS +S32 ps3_scsi_cmd_send(struct ps3_instance *instance, struct ps3_cmd *cmd, Bool need_prk_err); +#endif + +struct ps3_cmd *ps3_cmd_find(struct ps3_instance *instance, U16 cmd_frame_id); + +S32 ps3_cmd_dispatch(struct ps3_instance *instance, U16 cmd_frame_id, + struct PS3ReplyWord *reply_word); + +struct ps3_cmd *ps3_r1x_peer_cmd_alloc(struct ps3_instance *instance, U32 index); + +Bool ps3_r1x_peer_cmd_free_nolock(struct ps3_cmd *cmd); + +static inline U16 ps3_cmd_frame_id(struct ps3_cmd *cmd) +{ + return cmd->index; +} + +static inline U64 ps3_cmd_trace_id(struct ps3_cmd *cmd) +{ + return cmd->trace_id; +} + +static inline void ps3_cmd_trace_id_replace(struct ps3_cmd *cmd, U64 trace_id) +{ + cmd->trace_id = trace_id; +} + +Bool ps3_is_instance_state_allow_cmd_execute(struct ps3_instance *instance); + +S32 ps3_cmd_send_pre_check(struct ps3_instance *instance); + +void ps3_wait_scsi_cmd_done(struct ps3_instance *instance, Bool time_out); + +void ps3_scsi_cmd_deliver_get(struct ps3_instance *instance); + +void ps3_scsi_cmd_deliver_put(struct ps3_instance *instance); + +void ps3_dma_addr_bit_pos_update(struct ps3_instance *instance, U8 bit_pos); + +Bool ps3_bit_pos_update(struct ps3_instance *instance); + +void ps3_wait_mgr_cmd_done(struct ps3_instance *instance, Bool time_out); + +S32 ps3_mgr_cmd_send_pre_check(struct ps3_instance *instance, Bool no_check); + +S32 ps3_mgr_cmd_send_check(struct ps3_instance *instance, struct ps3_cmd *cmd); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_cmd_complete.c b/drivers/scsi/ps3stor/ps3_cmd_complete.c new file mode 100644 index 0000000000000000000000000000000000000000..c5a7e03f52b9fb907cc2f5a1819eb1cae019b452 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_complete.c @@ -0,0 +1,355 @@ + +#ifdef _WINDOWS + +#else +#include +#include +#include +#include +#include +#include +#include + +#endif +#include "ps3_cmd_complete.h" +#include "ps3_cmd_channel.h" +#include "ps3_driver_log.h" +#include "ps3_err_def.h" +#include "ps3_ioc_state.h" +#include "ps3_ioc_manager.h" +#include "ps3_scsi_cmd_err.h" + +static inline Bool ps3_reply_word_is_valid(U64 val); +static inline void ps3_reply_word_next(struct ps3_irq *irq, + struct PS3ReplyWord **reply_word); +static S32 ps3_reply_fifo_traverse(struct ps3_irq *irq, + struct ps3_instance *instance, struct PS3ReplyWord* reply_word, + S32 *completed_count); +static inline struct PS3ReplyWord* ps3_reply_word_query( + struct ps3_irq *irq, U16 idx); + +S32 ps3_cmd_complete(struct ps3_irq *irq) +{ + S32 ret = PS3_SUCCESS; + S32 completed_count = 0; + struct PS3ReplyWord *reply_word = NULL; + struct ps3_instance *instance = irq->instance; + S32 cur_state = PS3_INSTANCE_STATE_INIT; +#ifndef _WINDOWS + LOG_DEBUG("hno:%u start isr_os:%d, name:%s isr_sn:%d, " + "irq_enable:%d, irq_poll:%d, last_reply_idx:%d, is_busy:%d\n", + PS3_HOST(irq->instance), irq->irqNo, irq->name, + irq->isrSN, irq->is_enable_irq, irq->is_sched_irq_poll, + irq->last_reply_idx, atomic_read(&irq->is_busy)); +#else + LOG_DEBUG("hno:%u start isr_os:%d, name:%s isr_sn:%d, " + "last_reply_idx:%d, is_busy:%d\n", + PS3_HOST(irq->instance), irq->irqNo, irq->name, + irq->isrSN, irq->last_reply_idx, ps3_atomic_read(&irq->is_busy)); +#endif + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (unlikely (cur_state == PS3_INSTANCE_STATE_QUIT) ) { + LOG_WARN_IN_IRQ(instance, "hno:%u instance state is quit\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + if (!ps3_irq_busy_add(irq)) { + LOG_INFO_IN_IRQ(instance, "hno:%u irq is_busy:%d\n", PS3_HOST(instance), + ps3_atomic_read(&irq->is_busy)); + goto l_out; + } + + reply_word = ps3_reply_word_query(irq, irq->last_reply_idx); + if (!ps3_reply_word_is_valid(*(U64*)reply_word)) { + ps3_irq_busy_dec(irq); + LOG_DEBUG("hno:%u reply_w:0x%llx last_reply_idx:%d\n", + PS3_HOST(instance), *(U64*)reply_word, + irq->last_reply_idx); + goto l_out; + } + + ret = ps3_reply_fifo_traverse(irq, instance, + reply_word, &completed_count); + if (ret == -PS3_IN_IRQ_POLLING) { + ps3_irq_busy_dec(irq); + LOG_DEBUG("hno:%u reply in irq polling:%d\n", + PS3_HOST(instance), ret); + goto l_out; + } + + if (completed_count != 0) { + wmb(); +#ifndef _WINDOWS + ps3_can_queue_depth_update(instance); +#endif + } + + ps3_irq_busy_dec(irq); +#ifndef _WINDOWS + LOG_DEBUG("hno:%u end isr_os:%d, name:%s isr_sn:%d, " + "irq_enable:%d, irq_poll:%d, last_reply_idx:%d, complete_count:%d, is_busy:%d\n", + PS3_HOST(instance), irq->irqNo, irq->name, irq->isrSN, + irq->is_enable_irq, irq->is_sched_irq_poll, irq->last_reply_idx, + completed_count, atomic_read(&irq->is_busy)); +#else + LOG_DEBUG("hno:%u end isr_os:%d, name:%s isr_sn:%d, " + "irq_enable:%d, complete_count:%d, is_busy:%d\n", + PS3_HOST(instance), irq->irqNo, irq->name, irq->isrSN, + irq->last_reply_idx, completed_count, ps3_atomic_read(&irq->is_busy)); +#endif + +l_out: + return completed_count; +} + +static inline struct PS3ReplyWord *ps3_reply_word_query( + struct ps3_irq *irq, U16 idx) +{ + return irq->reply_fifo_virt_base_addr + idx; +} + +static inline Bool ps3_reply_word_is_valid(U64 val) +{ + U64 type = val & U64_MAX; + return (type != U64_MAX); +} + +static inline void ps3_reply_word_next(struct ps3_irq *irq, + struct PS3ReplyWord **reply_word) +{ + if (!irq->last_reply_idx) { + *reply_word = ps3_reply_word_query(irq, irq->last_reply_idx); + } else { + ++(*reply_word); + } + return; +} +#ifndef _WINDOWS +void ps3_trigger_irq_poll(struct ps3_irq *irq) +{ + LOG_DEBUG("host_no:%u trigger irq_poll isrSN:%d\n", + PS3_HOST(irq->instance), irq->isrSN); + + if (irq->is_sched_irq_poll) { + LOG_DEBUG("host_no:%u irq_poll_is_processing is PS3_TRUE\n", + PS3_HOST(irq->instance)); + goto l_out; + } + + irq->is_sched_irq_poll = PS3_TRUE; + irq->is_enable_irq = PS3_TRUE; + ps3_irq_poll_sched(&irq->irqpoll); + +l_out: + return; +} + +void ps3_can_queue_depth_update(struct ps3_instance *instance) +{ + ULong flag = 0; + ULong time_threahold = 5; + S32 old_host_can_que = 0; + + if (instance->fault_context.ioc_busy && + time_after(jiffies, instance->fault_context.last_time + + time_threahold * HZ) && + (atomic_read(&instance->cmd_statistics.io_outstanding) < + (instance->cmd_attr.throttle_que_depth + 1))) { + instance->fault_context.ioc_busy = PS3_FALSE; + + spin_lock_irqsave(instance->host->host_lock, flag); + old_host_can_que = instance->host->can_queue; + instance->host->can_queue = instance->cmd_attr.cur_can_que; + spin_unlock_irqrestore(instance->host->host_lock, flag); + LOG_INFO("hno:%u old_can_queue:%d, cur_can_que:%d, ioc_busy:%d.\n", + PS3_HOST(instance), old_host_can_que, + instance->cmd_attr.cur_can_que, + instance->fault_context.ioc_busy); + } + return ; +} +#endif +static S32 ps3_reply_fifo_traverse(struct ps3_irq *irq, + struct ps3_instance *instance, struct PS3ReplyWord *reply_word, + S32 *completed_count) +{ + S32 ret = PS3_SUCCESS; + U32 reply_threshold_count = 0; + U64 *r_word = NULL; + static U16 reply_word_size = sizeof(struct PS3ReplyWord); + + while (ps3_reply_word_is_valid(*(U64*)reply_word)) { + r_word = (U64 *)reply_word; + LOG_DEBUG("hno:%u CFID:%d reply_word:0x%llx reply_f:%d reply_mode:%d rettype:%d\n", + PS3_HOST(instance), le16_to_cpu(reply_word->cmdFrameID), *r_word, + reply_word->retStatus, reply_word->mode, reply_word->retType); + ret = ps3_cmd_dispatch(instance, + le16_to_cpu(reply_word->cmdFrameID), + reply_word); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_IN_IRQ(instance, "host_no:%u CFID:%d dispatch cmd fail\n", + PS3_HOST(instance), + le16_to_cpu(reply_word->cmdFrameID)); + } + + memset(reply_word, 0xff, reply_word_size); + + ++(irq->last_reply_idx); + if (irq->last_reply_idx >= + instance->irq_context.reply_fifo_depth) { + LOG_DEBUG("last_reply_idx = %d, depth=%d\n", irq->last_reply_idx, + instance->irq_context.reply_fifo_depth); + irq->last_reply_idx = 0; + } + + if (((++(*completed_count)) & (PS3_QOS_NOTIFY_CMD_COUNT - 1)) == 0) { + ps3_qos_waitq_notify(instance); + } + + ++reply_threshold_count; + + ps3_reply_word_next(irq, &reply_word); + if (!ps3_reply_word_is_valid(*(U64*)reply_word)) { + break; + } +#ifndef _WINDOWS +#ifdef CONFIG_IRQ_POLL + if (reply_threshold_count >= irq->irq_poll_sched_threshold) { + reply_threshold_count = 0; + wmb(); + ps3_trigger_irq_poll(irq); + ret = -PS3_IN_IRQ_POLLING; + break; + } +#endif +#endif + } + + if (((*completed_count) & (PS3_QOS_NOTIFY_CMD_COUNT - 1)) > 0) { + ps3_qos_waitq_notify(instance); + } + + return ret; +} + +S32 ps3_resp_status_convert(U32 resp_status) +{ + S32 ret = PS3_SUCCESS; + + switch (resp_status) { + case U8_MAX: + ret = -PS3_TIMEOUT; + break; + case SCSI_STATUS_GOOD: + ret = PS3_SUCCESS; + break; + default: + ret = -PS3_RESP_ERR; + break; + } + + return ret; +} + +S32 ps3_cmd_reply_polling(struct ps3_instance *instance, + struct ps3_cmd *cmd, ULong timeout, Bool ignore) +{ + const U32 seconds_to_msecs_unit = 1000; + const U32 step_size = 20; + const U32 read_fw_satus_period = 5000; + U32 local_resp_status = U8_MAX; + U32 msecs = U32_MAX; + U32 i = 0; + ULong flags = 0; + U32 time_out; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + time_out = max((ULong)cmd->time_out, timeout); + if (time_out != 0) { + msecs = time_out * seconds_to_msecs_unit; + } + + for (i = 0; (i < msecs) && + (cmd->resp_frame->normalRespFrame.respStatus == PS3_SCSI_STATUS_MASK); + i += step_size) { + rmb(); + ps3_msleep(step_size); + if (i % read_fw_satus_period) { + continue; + } + + if (ignore) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_DEAD) { + break; + } + } else { + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + break; + } + } + } + + local_resp_status = le32_to_cpu(cmd->resp_frame->normalRespFrame.respStatus); + LOG_DEBUG("host_no:%u CFID:%d, respStatus:0x%x\n", + PS3_HOST(instance), cmd->index, local_resp_status); + + if (local_resp_status != U8_MAX) { + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + return ps3_resp_status_convert(local_resp_status); +} +S32 ps3_cmd_reply_polling_when_recovery(struct ps3_instance *instance, + struct ps3_cmd *cmd, ULong timeout) +{ + const U32 seconds_to_msecs_unit = 1000; + const U32 step_size = 20; + const U32 read_fw_satus_period = 5000; + U32 local_resp_status = U8_MAX; + U32 msecs = U32_MAX; + U32 i = 0; + ULong flags = 0; + U32 time_out; + + time_out = max((ULong)cmd->time_out, timeout); + if (time_out != 0) { + msecs = time_out * seconds_to_msecs_unit; + } + + for (i = 0; (i < msecs) && + (cmd->resp_frame->normalRespFrame.respStatus == PS3_SCSI_STATUS_MASK); + i += step_size) { + rmb(); + ps3_msleep(step_size); + if (i % read_fw_satus_period) { + continue; + } + } + + local_resp_status = le32_to_cpu(cmd->resp_frame->normalRespFrame.respStatus); + LOG_DEBUG("host_no:%u CFID:%d, respStatus:0x%x\n", + PS3_HOST(instance), cmd->index, local_resp_status); + + if (local_resp_status != U8_MAX) { + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + return ps3_resp_status_convert(local_resp_status); +} + +void ps3_all_reply_fifo_complete(struct ps3_instance *instance) +{ + U32 i = 0; + for (; i < instance->irq_context.valid_msix_vector_count; ++i) { + (void)ps3_cmd_complete(instance->irq_context.irqs + i); + } + + return; +} diff --git a/drivers/scsi/ps3stor/ps3_cmd_complete.h b/drivers/scsi/ps3stor/ps3_cmd_complete.h new file mode 100644 index 0000000000000000000000000000000000000000..b4fe4e1ebdca87d0d9b80db60892fcc97cedcad3 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_complete.h @@ -0,0 +1,22 @@ + +#ifndef _PS3_CMD_COMPLETE_H_ +#define _PS3_CMD_COMPLETE_H_ + +#include "ps3_htp_def.h" +#include "ps3_irq.h" +#include "ps3_instance_manager.h" +#include "ps3_inner_data.h" + +S32 ps3_cmd_complete(struct ps3_irq *irq); + +S32 ps3_cmd_reply_polling(struct ps3_instance *instance, + struct ps3_cmd *cmd, ULong timeout, Bool ignore); + +S32 ps3_cmd_reply_polling_when_recovery(struct ps3_instance *instance, + struct ps3_cmd *cmd, ULong timeout); + +void ps3_all_reply_fifo_complete(struct ps3_instance *instance); + +void ps3_can_queue_depth_update(struct ps3_instance *instance); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_cmd_stat_def.h b/drivers/scsi/ps3stor/ps3_cmd_stat_def.h new file mode 100644 index 0000000000000000000000000000000000000000..ed78e04f57443a503beba5983a0215c1e725c007 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_stat_def.h @@ -0,0 +1,188 @@ + +#ifndef _PS3_CMD_STAT_DEF_H_ +#define _PS3_CMD_STAT_DEF_H_ + +#ifndef _WINDOWS +#include +#include +#else +#include "ps3_worker.h" +#endif +#include "ps3_htp_def.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +struct ps3_instance; + +enum { + PS3_STAT_LOG_COUNT = 0, + PS3_STAT_LOG_MAX_COUNT = 10, + PS3_STAT_START = 0, + PS3_STAT_BACK = 1, + PS3_STAT_WROKQ_NAME_MAX_LEN = 16, + PS3_STAT_WORKQ_INTERVAL_DEFAULT = 5000, +}; + +enum ps3_cmd_stat_item { + PS3_SCSI_DRV_READ, + PS3_SCSI_DRV_WRITE, + PS3_SCSI_DRV_NORW, + PS3_SCSI_DRV_ALL, + PS3_DRV_IOC_READ, + PS3_DRV_IOC_WRITE, + PS3_DRV_IOC_NORW, + PS3_DRV_IOC_ALL, + PS3_DRV_IOC_VD_READ, + PS3_DRV_IOC_VD_WRITE, + PS3_DRV_IOC_VD_NORW, + PS3_DRV_IOC_PD_READ, + PS3_DRV_IOC_PD_WRITE, + PS3_DRV_IOC_PD_NORW, + PS3_DRV_IOC_VD_D_READ, + PS3_DRV_IOC_VD_D_WRITE, + PS3_DRV_IOC_PD_D_READ, + PS3_DRV_IOC_PD_D_WRITE, + PS3_DRV_IOC_MGR, + PS3_SCSI_ABORT, + PS3_SCSI_DEVICE_RESET, + PS3_SCSI_RETRY_CMD, + PS3_QOS_PD_PRO, + PS3_QOS_VD_PRO, + PS3_QOS_TAG_PRO, + PS3_QOS_MGR_PRO, + PS3_QOS_CMD_PRO, + PS3_QOS_PD_QUEUE, + PS3_QOS_VD_QUEUE, + PS3_QOS_TAG_QUEUE, + PS3_QOS_MGR_QUEUE, + PS3_QOS_CMD_QUEUE, + PS3_CMD_STAT_COUNT, +}; + +static inline const S8 *ps3_cmd_stat_item_tostring(enum ps3_cmd_stat_item type) +{ + static const S8 *itme_string[] = { + [PS3_SCSI_DRV_READ] = "scsi_drv_read", + [PS3_SCSI_DRV_WRITE] = "scsi_drv_write", + [PS3_SCSI_DRV_NORW] = "scsi_drv_norw", + [PS3_SCSI_DRV_ALL] = "scsi_drv_all", + [PS3_DRV_IOC_READ] = "scsi_drv_ioc_read", + [PS3_DRV_IOC_WRITE] = "scsi_drv_ioc_write", + [PS3_DRV_IOC_NORW] = "scsi_drv_ioc_norw", + [PS3_DRV_IOC_ALL] = "scsi_drv_ioc_all", + [PS3_DRV_IOC_VD_READ] = "scsi_drv_ioc_vd_read", + [PS3_DRV_IOC_VD_WRITE] = "scsi_drv_ioc_vd_write", + [PS3_DRV_IOC_VD_NORW] = "scsi_drv_ioc_vd_norw", + [PS3_DRV_IOC_PD_READ] = "scsi_drv_ioc_pd_read", + [PS3_DRV_IOC_PD_WRITE] = "scsi_drv_ioc_pd_write", + [PS3_DRV_IOC_PD_NORW] = "scsi_drv_ioc_pd_norw", + [PS3_DRV_IOC_VD_D_READ] = "scsi_drv_ioc_vd_d_read", + [PS3_DRV_IOC_VD_D_WRITE] = "scsi_drv_ioc_vd_d_write", + [PS3_DRV_IOC_PD_D_READ] = "scsi_drv_ioc_pd_d_read", + [PS3_DRV_IOC_PD_D_WRITE] = "scsi_drv_ioc_pd_d_write", + [PS3_DRV_IOC_MGR] = "mgr_drv_ioc_cmd", + [PS3_SCSI_ABORT] = "task_abort", + [PS3_SCSI_DEVICE_RESET] = "task_reset", + [PS3_SCSI_RETRY_CMD] = "scsi_retry_cmd", + [PS3_QOS_PD_PRO] = "qos_pd_pro", + [PS3_QOS_VD_PRO] = "qos_vd_pro", + [PS3_QOS_TAG_PRO] = "qos_tag_pro", + [PS3_QOS_MGR_PRO] = "qos_mgr_pro", + [PS3_QOS_CMD_PRO] = "qos_cmd_pro", + [PS3_QOS_PD_QUEUE] = "qos_pd_queue", + [PS3_QOS_VD_QUEUE] = "qos_vd_queue", + [PS3_QOS_TAG_QUEUE] = "qos_tag_queue", + [PS3_QOS_MGR_QUEUE] = "qos_mgr_queue", + [PS3_QOS_CMD_QUEUE] = "qos_cmd_queue", + [PS3_CMD_STAT_COUNT] = "type_unknown", + }; + + return (type >= PS3_CMD_STAT_COUNT) ? "type_unknown" : itme_string[type]; +} + +struct ps3_lagency_info { + U64 start_time; + U64 back_time; + U64 avg; + U64 max_lagency; + U64 min_lagency; + U64 all; +}; + +struct ps3_cmd_stat_entry { + U64 start; + U64 back_good; + U64 back_err; + U64 not_back; + struct ps3_lagency_info lagency; +}; + +struct ps3_total_cmd_stat { + struct ps3_cmd_stat_entry stat[PS3_CMD_STAT_COUNT]; +}; + +enum ps3_cmd_stat_back_flag { + PS3_STAT_BACK_OK, + PS3_STAT_BACK_FAIL, + PS3_STAT_BACK_NO = 0xFF, +}; + +struct ps3_single_cmd_stat { + struct ps3_cmd_stat_entry stat[PS3_CMD_STAT_COUNT]; +}; + +enum ps3_cmd_stat_switch_flag { + PS3_STAT_ALL_SWITCH_CLOSE = 0x00, + PS3_STAT_OUTSTAND_SWITCH_OPEN = 0x01, + PS3_STAT_INC_SWITCH_OPEN = 0x02, + PS3_STAT_LOG_SWITCH_OPEN = 0x04, + PS3_STAT_DEV_SWITCH_OPEN = 0x08, + PS3_STAT_QOS_SWITCH_OPEN = 0x10, + PS3_STAT_ALL_SWITCH_OPEN = (PS3_STAT_OUTSTAND_SWITCH_OPEN | + PS3_STAT_INC_SWITCH_OPEN | + PS3_STAT_LOG_SWITCH_OPEN | + PS3_STAT_DEV_SWITCH_OPEN | + PS3_STAT_QOS_SWITCH_OPEN), +}; + +struct ps3_cmd_stat_wrokq_context { +#ifndef _WINDOWS + struct delayed_work stat_work; + struct workqueue_struct *stat_queue; + struct ps3_instance *instance; +#else + struct ps3_delay_worker statis_work; +#endif + Bool is_stop; +}; + +struct ps3_cmd_statistics_context { + ps3_atomic32 cmd_outstanding; + ps3_atomic32 io_outstanding; + ps3_atomic32 vd_io_outstanding; + ps3_atomic32 cmd_delivering; + ps3_atomic32 scsi_cmd_delivering; + ps3_atomic64 cmd_word_send_count; + struct ps3_total_cmd_stat total_stat; + struct ps3_total_cmd_stat inc_stat; + struct ps3_single_cmd_stat **cmd_stat_backup_buf; + struct ps3_single_cmd_stat **last_stat_buf; + struct ps3_single_cmd_stat **cmd_stat_buf; + U32 stat_entry_max_count; + U32 stat_interval; + struct ps3_cmd_stat_wrokq_context stat_workq; + U8 cmd_stat_switch; + U8 log_record_count; + ps3_atomic32 cli_cnt; + ps3_atomic32 cmd_qos_processing; + ps3_atomic64 cmd_qos_total; + U8 reserved2[2]; +}; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/ps3_cmd_statistics.c b/drivers/scsi/ps3stor/ps3_cmd_statistics.c new file mode 100644 index 0000000000000000000000000000000000000000..afa3fe855f84359508c9234fc5bac3d82cbc877e --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_statistics.c @@ -0,0 +1,1646 @@ + +#ifndef _WINDOWS +#include +#endif + +#include "ps3_cmd_statistics.h" +#include "ps3_cmd_channel.h" +#include "ps3_driver_log.h" + +static S32 ps3_cmd_stat_buf_alloc(struct ps3_instance *instance); +static void ps3_cmd_stat_buf_free(struct ps3_instance *instance); +static inline void ps3_stat_data_collect(struct ps3_instance *instance); +static void ps3_cmd_stat_content_init(struct ps3_instance *instance); +static inline void ps3_stat_buf_init(struct ps3_instance *instance); +static void ps3_dev_io_recv_bytes_stat_inc(struct ps3_instance *ins, + const struct ps3_cmd *cmd); +static S32 ps3_cmd_stat_backup_buf_alloc(struct ps3_instance *instance); +static S32 ps3_last_stat_buf_alloc(struct ps3_instance *instance); +static void ps3_cmd_stat_backup_buf_free(struct ps3_instance *instance); +static void ps3_last_stat_buf_free(struct ps3_instance *instance); +static inline void ps3_cmd_stat_backup_buf_init(struct ps3_instance *instance); +static inline void ps3_last_stat_init(struct ps3_instance *instance); + +S32 ps3_cmd_statistics_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + ps3_atomic_set(&instance->cmd_statistics.cmd_outstanding, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&instance->cmd_statistics.io_outstanding, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&instance->cmd_statistics.vd_io_outstanding, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&instance->cmd_statistics.cmd_delivering, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&instance->cmd_statistics.scsi_cmd_delivering, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&instance->cmd_statistics.cmd_word_send_count, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&instance->cmd_statistics.cmd_qos_total, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&instance->cmd_statistics.cmd_qos_processing, + PS3_CMD_STAT_INIT_VALUE); + + ret = ps3_cmd_stat_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_free_stat_buf; + } + + ret = ps3_cmd_stat_backup_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_free_stat_buf; + } + + ret = ps3_last_stat_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_free_stat_buf; + } + + ps3_cmd_stat_content_init(instance); + + ret = ps3_stat_workq_start(instance); + if (ret != PS3_SUCCESS) { + goto l_stop_workq; + } + + goto l_out; + +l_stop_workq: + ps3_stat_workq_stop(instance); + +l_free_stat_buf: + ps3_cmd_stat_buf_free(instance); + ps3_cmd_stat_backup_buf_free(instance); + ps3_last_stat_buf_free(instance); +l_out: + return ret; +} + +void ps3_cmd_statistics_exit(struct ps3_instance *instance) +{ + ps3_stat_workq_stop(instance); + ps3_cmd_stat_buf_free(instance); + ps3_cmd_stat_backup_buf_free(instance); + ps3_last_stat_buf_free(instance); +} + +void ps3_cmd_stat_content_clear(struct ps3_instance *instance) +{ + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + memset(&ctx->total_stat, 0, sizeof(struct ps3_total_cmd_stat)); + memset(&ctx->inc_stat, 0, sizeof(struct ps3_total_cmd_stat)); + ps3_stat_buf_init(instance); + ps3_cmd_stat_backup_buf_init(instance); + ps3_last_stat_init(instance); +} + +static void ps3_cmd_stat_content_init(struct ps3_instance *instance) +{ + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + ps3_cmd_stat_content_clear(instance); + ctx->stat_interval = PS3_STAT_WORKQ_INTERVAL_DEFAULT; + ctx->log_record_count = PS3_STAT_LOG_COUNT; +#ifdef PS3_CFG_RELEASE + ctx->cmd_stat_switch = PS3_STAT_OUTSTAND_SWITCH_OPEN; +#else + ctx->cmd_stat_switch = PS3_STAT_OUTSTAND_SWITCH_OPEN | PS3_STAT_INC_SWITCH_OPEN + | PS3_STAT_QOS_SWITCH_OPEN; +#endif +} + +static inline Bool ps3_cmd_is_vd(const struct ps3_cmd *cmd) +{ + return cmd->io_attr.dev_type == PS3_DEV_TYPE_VD; +} + +void ps3_dev_io_statis_init(struct ps3_dev_io_statis *statis) +{ + ps3_atomic64_set(&statis->read_send_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_send_ok_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_send_wait_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_send_err_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_recv_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_recv_ok_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_recv_err_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->read_ok_bytes, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_send_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_send_ok_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_send_wait_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_send_err_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_recv_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_recv_ok_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_recv_err_cnt, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->write_ok_bytes, + PS3_CMD_STAT_INIT_VALUE); + ps3_atomic64_set(&statis->qos_processing_cnt, + PS3_CMD_STAT_INIT_VALUE); +} + +void ps3_io_statis_inc(struct scsi_device *sdev, enum ps3_dev_io_stat_type type) +{ + struct ps3_scsi_priv_data *data = NULL; + data = PS3_SDEV_PRI_DATA(sdev); + + switch(type) { + case PS3_DEV_IO_STAT_TYPE_R_SEND: + ps3_atomic64_inc(&data->statis.read_send_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_R_SEND_OK: + ps3_atomic64_inc(&data->statis.read_send_ok_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_R_SEND_WAIT: + ps3_atomic64_inc(&data->statis.read_send_wait_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_R_SEND_ERR: + ps3_atomic64_inc(&data->statis.read_send_err_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_R_RECV: + ps3_atomic64_inc(&data->statis.read_recv_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_R_RECV_OK: + ps3_atomic64_inc(&data->statis.read_recv_ok_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_R_RECV_ERR: + ps3_atomic64_inc(&data->statis.read_recv_err_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_SEND: + ps3_atomic64_inc(&data->statis.write_send_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_SEND_OK: + ps3_atomic64_inc(&data->statis.write_send_ok_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_SEND_WAIT: + ps3_atomic64_inc(&data->statis.write_send_wait_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_SEND_ERR: + ps3_atomic64_inc(&data->statis.write_send_err_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_RECV: + ps3_atomic64_inc(&data->statis.write_recv_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_RECV_OK: + ps3_atomic64_inc(&data->statis.write_recv_ok_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_RECV_ERR: + ps3_atomic64_inc(&data->statis.write_recv_err_cnt); + break; + default: + LOG_INFO("unknown io statis type %d", type); + break; + } +} + +static inline void ps3_io_statis_add(struct scsi_device *sdev, + enum ps3_dev_io_stat_type type, U64 offset) +{ + struct ps3_scsi_priv_data *data = NULL; + data = PS3_SDEV_PRI_DATA(sdev); + + switch(type) { + case PS3_DEV_IO_STAT_TYPE_R_OK_BYTES: + ps3_atomic64_add(offset, &data->statis.read_ok_bytes); + break; + case PS3_DEV_IO_STAT_TYPE_W_OK_BYTES: + ps3_atomic64_add(offset, &data->statis.write_ok_bytes); + break; + default: + LOG_INFO("unknown io statis type %d", type); + break; + } +} + +void ps3_io_statis_dec(struct scsi_device *sdev, + enum ps3_dev_io_stat_type type) +{ + struct ps3_scsi_priv_data *data = NULL; + data = PS3_SDEV_PRI_DATA(sdev); + + switch(type) { + case PS3_DEV_IO_STAT_TYPE_R_SEND_WAIT: + ps3_atomic64_dec(&data->statis.read_send_wait_cnt); + break; + case PS3_DEV_IO_STAT_TYPE_W_SEND_WAIT: + ps3_atomic64_dec(&data->statis.write_send_wait_cnt); + break; + default: + LOG_INFO("io statis type %d not support to dec", type); + break; + } +} + +void ps3_io_statis_clear(struct scsi_device *sdev) +{ + struct ps3_scsi_priv_data *data = NULL; + struct ps3_instance *instance = + (struct ps3_instance*)sdev->host->hostdata; + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + data = PS3_SDEV_PRI_DATA(sdev); + if (data != NULL) { + ps3_dev_io_statis_init(&data->statis); + } + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); +} + +void ps3_dev_io_start_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + if (instance == NULL || cmd == NULL) { + goto l_out; + } + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_SEND); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_SEND); + } + +l_out: + return; +} + +void ps3_dev_io_start_err_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + if (instance == NULL || cmd == NULL) { + goto l_out; + } + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_SEND_ERR); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_SEND_ERR); + } + +l_out: + return; +} + +void ps3_dev_io_start_ok_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + if (instance == NULL || cmd == NULL) { + goto l_out; + } + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_SEND_OK); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_SEND_OK); + } + +l_out: + return; +} + +void ps3_dev_io_outstand_dec(const struct ps3_cmd *cmd) +{ + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_dec(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_SEND_WAIT); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_dec(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_SEND_WAIT); + } +} + +void ps3_dev_io_qos_inc(struct ps3_scsi_priv_data* priv_data) +{ + ps3_atomic64_inc(&priv_data->statis.qos_processing_cnt); +} + +void ps3_dev_io_qos_dec(struct ps3_scsi_priv_data* priv_data) +{ + ps3_atomic64_dec(&priv_data->statis.qos_processing_cnt); +} + +void ps3_io_outstand_dec(struct ps3_instance *instance, + const struct scsi_cmnd *s_cmd) +{ + if (instance == NULL || s_cmd == NULL) { + goto l_out; + } + + ps3_atomic_dec(&instance->cmd_statistics.io_outstanding); + + if((instance->cmd_attr.vd_io_threshold != 0) && ps3_is_vd_rw_cmd(s_cmd)) { + ps3_atomic_dec(&instance->cmd_statistics.vd_io_outstanding); + } + +l_out: + return; +} + +void ps3_vd_outstand_dec(struct ps3_instance *instance, const struct scsi_cmnd *s_cmd) +{ + struct ps3_scsi_priv_data *data = PS3_SDEV_PRI_DATA(s_cmd->device); + struct PS3VDEntry *vd_entry = NULL; + + if (data->dev_type == PS3_DEV_TYPE_VD) { + vd_entry = ps3_dev_mgr_lookup_vd_info(instance, s_cmd->device->channel,\ + s_cmd->device->id); + if (unlikely(vd_entry != NULL)) { + if (ps3_is_read_cmd(s_cmd)) { + atomic_dec(&data->rd_io_outstand); + } else if (ps3_is_write_cmd(s_cmd)) { + if (!vd_entry->isNvme && !vd_entry->isSsd) { + atomic_dec(&data->wr_io_outstand); + } + } + } + } +} + +void ps3_dev_io_outstand_inc(const struct ps3_cmd *cmd) +{ + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_SEND_WAIT); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)) { + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_SEND_WAIT); + } +} + +void ps3_vd_outstand_inc(struct ps3_instance *instance, const struct scsi_cmnd *s_cmd) +{ + struct ps3_scsi_priv_data *data = PS3_SDEV_PRI_DATA(s_cmd->device); + struct PS3VDEntry *vd_entry = NULL; + + if (data->dev_type == PS3_DEV_TYPE_VD) { + vd_entry = ps3_dev_mgr_lookup_vd_info(instance, s_cmd->device->channel,\ + s_cmd->device->id); + if (unlikely(vd_entry != NULL)) { + if (ps3_is_read_cmd(s_cmd)) { + atomic_inc(&data->rd_io_outstand); + } else if (ps3_is_write_cmd(s_cmd)) { + if (!vd_entry->isNvme && !vd_entry->isSsd) { + atomic_inc(&data->wr_io_outstand); + } + } + } + } +} + +void ps3_io_outstand_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + if (ps3_stat_outstand_switch_is_open(instance)) { + ps3_atomic_inc(&instance->cmd_statistics.io_outstanding); + + if (ps3_is_vd_rw_cmd(cmd->scmd) && + (instance->cmd_attr.vd_io_threshold != 0)) { + ps3_atomic_inc(&instance->cmd_statistics.vd_io_outstanding); + } + } + + return; +} + +void ps3_io_recv_ok_stat_inc(struct ps3_instance *ins, + const struct ps3_cmd *cmd) +{ + if (ins == NULL || cmd == NULL) { + goto l_out; + } + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_RECV_OK); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_RECV_OK); + } + +l_out: + return; +} + +void ps3_dev_io_back_inc(struct ps3_instance *ins, + const struct ps3_cmd *cmd, U8 status) +{ + if (ins == NULL || cmd == NULL) { + goto l_out; + } + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_RECV); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_RECV); + } + + if (status == PS3_REPLY_WORD_FLAG_SUCCESS) { + ps3_io_recv_ok_stat_inc(ins, cmd); + ps3_dev_io_recv_bytes_stat_inc(ins, cmd); + } + +l_out: + return; +} + +static void ps3_dev_io_recv_bytes_stat_inc(struct ps3_instance *ins, + const struct ps3_cmd *cmd) +{ + if (ins == NULL || cmd == NULL || cmd->scmd == NULL) { + goto l_out; + } + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_add(cmd->scmd->device, + PS3_DEV_IO_STAT_TYPE_R_OK_BYTES, + scsi_bufflen(cmd->scmd)); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_add(cmd->scmd->device, + PS3_DEV_IO_STAT_TYPE_W_OK_BYTES, + scsi_bufflen(cmd->scmd)); + } + +l_out: + return; +} + +void ps3_qos_cmd_inc(struct ps3_instance *instance) +{ + ps3_atomic64_inc(&instance->cmd_statistics.cmd_qos_total); +} +static void ps3_cmd_stat_buf_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + if (ctx->cmd_stat_buf == NULL) { + goto l_out; + } + + for (; i < ctx->stat_entry_max_count; ++i) { + if (ctx->cmd_stat_buf[i] == NULL) { + continue; + } + ps3_kfree(instance, ctx->cmd_stat_buf[i]); + ctx->cmd_stat_buf[i] = NULL; + + } + + ps3_kfree(instance, ctx->cmd_stat_buf); + ctx->cmd_stat_buf = NULL; +l_out: + return; +} + +static S32 ps3_cmd_stat_buf_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + ctx->stat_entry_max_count = instance->cmd_context.max_cmd_count; + ctx->cmd_stat_buf = (struct ps3_single_cmd_stat**)ps3_kzalloc(instance, + ctx->stat_entry_max_count * sizeof(struct ps3_single_cmd_stat*)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_STAT_BUF_ALLOC1, &ctx->cmd_stat_buf); + if (ctx->cmd_stat_buf == NULL) { + LOG_ERROR("failed to kcalloc for cmd_stat_buf\n"); + ret = -PS3_FAILED; + goto l_out; + } + + for (; i < ctx->stat_entry_max_count; ++i) { + ctx->cmd_stat_buf[i] = (struct ps3_single_cmd_stat*)ps3_kzalloc(instance, + sizeof(struct ps3_single_cmd_stat)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_STAT_BUF_ALLOC2, &ctx->cmd_stat_buf[i]); + if (ctx->cmd_stat_buf[i] == NULL) { + LOG_ERROR("Failed to alloc mem for ps3_single_cmd_stat\n"); + ret = -PS3_FAILED; + goto l_free_mem; + } + } + + goto l_out; + +l_free_mem: + ps3_cmd_stat_buf_free(instance); +l_out: + return ret; +} + +static void ps3_last_stat_buf_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + if (ctx->last_stat_buf == NULL) { + goto l_out; + } + + for (; i < ctx->stat_entry_max_count; ++i) { + if (ctx->last_stat_buf[i] == NULL) { + continue; + } + ps3_kfree(instance, ctx->last_stat_buf[i]); + ctx->last_stat_buf[i] = NULL; + + } + + ps3_kfree(instance, ctx->last_stat_buf); + ctx->last_stat_buf = NULL; +l_out: + return; +} + +static S32 ps3_last_stat_buf_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + ctx->stat_entry_max_count = instance->cmd_context.max_cmd_count; + ctx->last_stat_buf = (struct ps3_single_cmd_stat**)ps3_kzalloc(instance, + ctx->stat_entry_max_count * sizeof(struct ps3_single_cmd_stat*)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_LAST_STAT_BUF_ALLOC1, &ctx->last_stat_buf); + if (ctx->last_stat_buf == NULL) { + LOG_ERROR("failed to kzalloc for last_stat_buf\n"); + ret = -PS3_FAILED; + goto l_out; + } + + for (; i < ctx->stat_entry_max_count; ++i) { + ctx->last_stat_buf[i] = (struct ps3_single_cmd_stat*)ps3_kzalloc(instance, + sizeof(struct ps3_single_cmd_stat)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_LAST_STAT_BUF_ALLOC2, &ctx->last_stat_buf[i]); + if (ctx->last_stat_buf[i] == NULL) { + LOG_ERROR("Failed to alloc mem for ps3_single_cmd_stat\n"); + ret = -PS3_FAILED; + goto l_free_mem; + } + } + + goto l_out; + +l_free_mem: + ps3_last_stat_buf_free(instance); +l_out: + return ret; +} + +static inline struct ps3_single_cmd_stat* ps3_last_stat_entry_find(U32 index, + struct ps3_instance *instance) +{ + return (index < instance->cmd_statistics.stat_entry_max_count) ? + instance->cmd_statistics.last_stat_buf[index] : NULL; +} + +static inline void ps3_last_stat_init(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + for (; i < ctx->stat_entry_max_count; ++i) { + memset(ctx->last_stat_buf[i], 0, sizeof(struct ps3_single_cmd_stat)); + mb(); + } + + return; +} +static void ps3_cmd_stat_backup_buf_free(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + if (ctx->cmd_stat_backup_buf == NULL) { + goto l_out; + } + + for (; i < ctx->stat_entry_max_count; ++i) { + if (ctx->cmd_stat_backup_buf[i] == NULL) { + continue; + } + ps3_kfree(instance, ctx->cmd_stat_backup_buf[i]); + ctx->cmd_stat_backup_buf[i] = NULL; + + } + + ps3_kfree(instance, ctx->cmd_stat_backup_buf); + ctx->cmd_stat_backup_buf = NULL; +l_out: + return; +} + +static S32 ps3_cmd_stat_backup_buf_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + ctx->stat_entry_max_count = instance->cmd_context.max_cmd_count; + ctx->cmd_stat_backup_buf = (struct ps3_single_cmd_stat**)ps3_kzalloc(instance, + ctx->stat_entry_max_count * sizeof(struct ps3_single_cmd_stat*)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_STAT_BACKUP_BUF_ALLOC1, &ctx->cmd_stat_backup_buf); + if (ctx->cmd_stat_backup_buf == NULL) { + LOG_ERROR("failed to kzalloc for cmd_stat_backup_buf\n"); + ret = -PS3_FAILED; + goto l_out; + } + + for (; i < ctx->stat_entry_max_count; ++i) { + ctx->cmd_stat_backup_buf[i] = (struct ps3_single_cmd_stat*)ps3_kzalloc(instance, + sizeof(struct ps3_single_cmd_stat)); + INJECT_START(PS3_ERR_IJ_PS3_CMD_STAT_BACKUP_BUF_ALLOC2, &ctx->cmd_stat_backup_buf[i]); + if (ctx->cmd_stat_backup_buf[i] == NULL) { + LOG_ERROR("Failed to alloc mem for ps3_single_cmd_stat\n"); + ret = -PS3_FAILED; + goto l_free_mem; + } + } + + goto l_out; + +l_free_mem: + ps3_cmd_stat_backup_buf_free(instance); +l_out: + return ret; +} + +static inline struct ps3_single_cmd_stat* ps3_backup_stat_entry_find(U32 index, + struct ps3_instance *instance) +{ + return (index < instance->cmd_statistics.stat_entry_max_count) ? + instance->cmd_statistics.cmd_stat_backup_buf[index] : NULL; +} + +static inline void ps3_cmd_stat_backup_buf_init(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + for (; i < ctx->stat_entry_max_count; ++i) { + memset(ctx->cmd_stat_backup_buf[i], 0, + sizeof(struct ps3_single_cmd_stat)); + mb(); + } + + return; +} +static inline struct ps3_single_cmd_stat* ps3_stat_entry_find(U32 index, + struct ps3_instance *instance) +{ + return (index < instance->cmd_statistics.stat_entry_max_count) ? + instance->cmd_statistics.cmd_stat_buf[index] : NULL; +} + +static inline void ps3_stat_buf_init(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + for (; i < ctx->stat_entry_max_count; ++i) { + memset(ctx->cmd_stat_buf[i], 0, sizeof(struct ps3_single_cmd_stat)); + mb(); + } + + return; +} + +void ps3_stat_all_clear(struct ps3_instance *instance) +{ + ps3_stat_buf_init(instance); + ps3_cmd_stat_backup_buf_init(instance); + ps3_last_stat_init(instance); + memset(&instance->cmd_statistics.total_stat, 0, sizeof(struct ps3_total_cmd_stat)); + memset(&instance->cmd_statistics.inc_stat, 0, sizeof(struct ps3_total_cmd_stat)); +} + +static inline void ps3_stat_start_inc(U16 type, + struct ps3_single_cmd_stat *cmd_stat) +{ + if (type >= PS3_CMD_STAT_COUNT) { + LOG_ERROR("type:%u overflow\n", type); + goto l_out; + } + + cmd_stat->stat[type].start++; + + cmd_stat->stat[type].lagency.start_time = ps3_tick_count_get(); + +l_out: + return; +} + +static inline void ps3_stat_lagency_update(struct ps3_lagency_info *lagency, + U64 start_time, U64 back_time) +{ + U64 intervals = back_time - start_time; + + lagency->all += intervals; + if (intervals > lagency->max_lagency) { + lagency->max_lagency = intervals; + } + + if (intervals < lagency->min_lagency || lagency->min_lagency == 0) { + lagency->min_lagency = intervals; + } + + return; +} + +static inline void ps3_stat_lagency_merge(struct ps3_lagency_info *target, + const struct ps3_lagency_info *source) +{ + target->all += source->all; + if (source->max_lagency > target->max_lagency) { + target->max_lagency = source->max_lagency; + } + + if ((source->min_lagency < target->min_lagency && + source->min_lagency != 0) || target->min_lagency == 0) { + target->min_lagency = source->min_lagency; + } + + return; +} + +static inline void ps3_stat_lagency_avg_calc(struct ps3_total_cmd_stat *total_stat) +{ + U64 back_count = 0; + U16 i = 0; + + for(; i < PS3_CMD_STAT_COUNT; ++i) { + back_count = total_stat->stat[i].back_good + + total_stat->stat[i].back_err; + if (back_count != 0) { + total_stat->stat[i].lagency.avg = + (total_stat->stat[i].lagency.all / back_count); + } + mb(); + } +} + +static inline void ps3_stat_lagency_inc_cal(struct ps3_lagency_info *inc, + const struct ps3_lagency_info *cur, + const struct ps3_lagency_info *last) +{ + inc->all += cur->all - last->all; + inc->max_lagency = (cur->max_lagency > inc->max_lagency) ? + cur->max_lagency : inc->max_lagency; + inc->min_lagency = ((cur->min_lagency < inc->min_lagency && cur->min_lagency != 0) + || inc->min_lagency == 0) ? cur->min_lagency : inc->min_lagency; + + return; +} + +static inline void ps3_stat_back_inc(U16 type, + struct ps3_single_cmd_stat *single_stat, U8 status) +{ + if (type >= PS3_CMD_STAT_COUNT) { + LOG_ERROR("type:%u err\n", type); + goto l_out; + } + + single_stat->stat[type].lagency.back_time = ps3_tick_count_get(); + + switch (status) { + case PS3_STAT_BACK_OK: + single_stat->stat[type].back_good++; + break; + case PS3_STAT_BACK_FAIL: + single_stat->stat[type].back_err++; + break; + case PS3_STAT_BACK_NO: + single_stat->stat[type].not_back++; + break; + default: + single_stat->stat[type].back_err++; + break; + } + + ps3_stat_lagency_update(&single_stat->stat[type].lagency, + single_stat->stat[type].lagency.start_time, + single_stat->stat[type].lagency.back_time); + if (type == PS3_SCSI_ABORT) { + LOG_WARN("start:%llu back:%llu all:%llu\n", + single_stat->stat[type].lagency.start_time, + single_stat->stat[type].lagency.back_time, + single_stat->stat[type].lagency.all); + } + +l_out: + return; +} + +#ifndef _WINDOWS +static inline void ps3_scmd_start_inc(struct ps3_single_cmd_stat* stat_entry, + const struct scsi_cmnd *s_cmd) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(s_cmd->cmnd)); + if (ps3_scsih_is_rw_type(type)) { + if (ps3_scsih_is_read_cmd(type)) { + ps3_stat_start_inc(PS3_SCSI_DRV_READ, stat_entry); + } else { + ps3_stat_start_inc(PS3_SCSI_DRV_WRITE, stat_entry); + } + } else { + ps3_stat_start_inc(PS3_SCSI_DRV_NORW, stat_entry); + } + + ps3_stat_start_inc(PS3_SCSI_DRV_ALL, stat_entry); + + if (s_cmd->retries != 0) { + ps3_stat_start_inc(PS3_SCSI_RETRY_CMD, stat_entry); + } + + return; +} + +static inline void ps3_scmd_back_inc(struct ps3_single_cmd_stat* stat_entry, + const struct scsi_cmnd *s_cmd, U8 status) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(s_cmd->cmnd)); + + if (ps3_scsih_is_rw_type(type)) { + if (ps3_scsih_is_read_cmd(type)) { + ps3_stat_back_inc(PS3_SCSI_DRV_READ, stat_entry, status); + } else { + ps3_stat_back_inc(PS3_SCSI_DRV_WRITE, stat_entry, status); + } + } else { + ps3_stat_back_inc(PS3_SCSI_DRV_NORW, stat_entry, status); + } + + ps3_stat_back_inc(PS3_SCSI_DRV_ALL, stat_entry, status); + + if (s_cmd->retries != 0) { + ps3_stat_back_inc(PS3_SCSI_RETRY_CMD, stat_entry, status); + } + + return; +} + +void ps3_scmd_inc(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, U8 type, U8 status) +{ + struct ps3_single_cmd_stat* stat_entry = NULL; + + if (s_cmd == NULL) { + LOG_ERROR("scsi cmd is null\n"); + goto l_out; + } + + if (SCMD_GET_REQUEST(s_cmd) == NULL) { + LOG_ERROR("scsi_cmnd->request is null\n"); + goto l_out; + } + + stat_entry = ps3_stat_entry_find(SCMD_GET_REQUEST(s_cmd)->tag, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u CFID:%u stat entry find fail\n", + PS3_HOST(instance), SCMD_GET_REQUEST(s_cmd)->tag); + goto l_out; + } + + if (type == PS3_STAT_START) { + ps3_scmd_start_inc(stat_entry, s_cmd); + } else if (type == PS3_STAT_BACK) { + ps3_scmd_back_inc(stat_entry, s_cmd, status); + } else { + LOG_ERROR("type:%u is err\n", type); + } + +l_out: + return; +} +#else +static inline void ps3_scmd_start_inc(struct ps3_single_cmd_stat* stat_entry, + const struct scsi_cmnd *s_cmd) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(s_cmd->cmnd)); + if (ps3_scsih_is_rw_type(type)) { + if (ps3_scsih_is_read_cmd(type)) { + ps3_stat_start_inc(PS3_SCSI_DRV_READ, stat_entry); + } else { + ps3_stat_start_inc(PS3_SCSI_DRV_WRITE, stat_entry); + } + } else { + ps3_stat_start_inc(PS3_SCSI_DRV_NORW, stat_entry); + } + + ps3_stat_start_inc(PS3_SCSI_DRV_ALL, stat_entry); + + return; +} + +static inline void ps3_scmd_back_inc(struct ps3_single_cmd_stat* stat_entry, + const struct scsi_cmnd *s_cmd, U8 status) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(scsi_cmnd_cdb(s_cmd))); + + if (ps3_scsih_is_rw_type(type)) { + if (ps3_scsih_is_read_cmd(type)) { + ps3_stat_back_inc(PS3_SCSI_DRV_READ, stat_entry, status); + } else { + ps3_stat_back_inc(PS3_SCSI_DRV_WRITE, stat_entry, status); + } + } else { + ps3_stat_back_inc(PS3_SCSI_DRV_NORW, stat_entry, status); + } + + ps3_stat_back_inc(PS3_SCSI_DRV_ALL, stat_entry, status); + + return; +} + +void ps3_scmd_inc(struct ps3_instance *instance, + const struct scsi_cmnd *s_cmd, U32 tag, U8 type, U8 status) +{ + struct ps3_single_cmd_stat* stat_entry = NULL; + + if (s_cmd == NULL) { + LOG_ERROR("scsi cmd is null\n"); + goto l_out; + } + + stat_entry = ps3_stat_entry_find(tag, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u CFID:%u stat entry find fail\n", + PS3_HOST(instance), tag); + goto l_out; + } + + if (type == PS3_STAT_START) { + ps3_scmd_start_inc(stat_entry, s_cmd); + } + else if (type == PS3_STAT_BACK) { + ps3_scmd_back_inc(stat_entry, s_cmd, status); + } else { + LOG_ERROR("type:%u is err\n", type); + } + +l_out: + return; +} +#endif +static inline Bool ps3_is_direct_cmd(U8 type) +{ + return (type == PS3_CMDWORD_DIRECT_OK || + type == PS3_CMDWORD_DIRECT_ADVICE); +} + +static inline void ps3_direct_cmd_start_inc(const struct ps3_cmd *cmd, + struct ps3_single_cmd_stat *stat_entry, Bool vd_flag) +{ + U16 type = PS3_DRV_IOC_READ; + + if (ps3_is_direct_cmd(cmd->io_attr.direct_flag)) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + type = vd_flag ? PS3_DRV_IOC_VD_D_READ : + PS3_DRV_IOC_PD_D_READ; + } else { + type = vd_flag ? PS3_DRV_IOC_VD_D_WRITE : + PS3_DRV_IOC_PD_D_WRITE; + } + ps3_stat_start_inc(type, stat_entry); + } + + return; +} + +static inline void ps3_scmd_drv2ioc_start_vd_inc(const struct ps3_cmd *cmd, + struct ps3_single_cmd_stat *stat_entry) +{ + if (ps3_scsih_is_rw_type(cmd->io_attr.rw_flag)) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_stat_start_inc(PS3_DRV_IOC_VD_READ, stat_entry); + ps3_stat_start_inc(PS3_DRV_IOC_READ, stat_entry); + } else { + ps3_stat_start_inc(PS3_DRV_IOC_VD_WRITE, stat_entry); + ps3_stat_start_inc(PS3_DRV_IOC_WRITE, stat_entry); + } + } else { + ps3_stat_start_inc(PS3_DRV_IOC_NORW, stat_entry); + ps3_stat_start_inc(PS3_DRV_IOC_VD_NORW, stat_entry); + } + + ps3_direct_cmd_start_inc(cmd, stat_entry, PS3_TRUE); +} + +static inline void ps3_scmd_drv2ioc_start_pd_inc(const struct ps3_cmd *cmd, + struct ps3_single_cmd_stat *stat_entry) +{ + if (ps3_scsih_is_rw_type(cmd->io_attr.rw_flag)) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_stat_start_inc(PS3_DRV_IOC_PD_READ, stat_entry); + ps3_stat_start_inc(PS3_DRV_IOC_READ, stat_entry); + } else { + ps3_stat_start_inc(PS3_DRV_IOC_PD_WRITE, stat_entry); + ps3_stat_start_inc(PS3_DRV_IOC_WRITE, stat_entry); + } + } else { + ps3_stat_start_inc(PS3_DRV_IOC_PD_NORW, stat_entry); + ps3_stat_start_inc(PS3_DRV_IOC_NORW, stat_entry); + } + + ps3_direct_cmd_start_inc(cmd, stat_entry, PS3_FALSE); +} + +void ps3_scmd_drv2ioc_start_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + struct ps3_single_cmd_stat *stat_entry = NULL; + + if (cmd == NULL) { + goto l_out; + } + + stat_entry = ps3_stat_entry_find(cmd->index, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u index:%u stat entry find fail\n", + PS3_HOST(instance), cmd->index); + goto l_out; + } + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + ps3_scmd_drv2ioc_start_vd_inc(cmd, stat_entry); + } else { + ps3_scmd_drv2ioc_start_pd_inc(cmd, stat_entry); + } + + ps3_stat_start_inc(PS3_DRV_IOC_ALL, stat_entry); + ps3_atomic_inc(&instance->cmd_statistics.cmd_outstanding); + +l_out: + return; +} + +static inline void ps3_direct_cmd_back_inc(const struct ps3_cmd *cmd, + struct ps3_single_cmd_stat *stat_entry, Bool vd_flag, U8 status) +{ + U16 type = PS3_DRV_IOC_READ; + if (ps3_is_direct_cmd(cmd->io_attr.direct_flag)) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + type = vd_flag ? PS3_DRV_IOC_VD_D_READ : + PS3_DRV_IOC_PD_D_READ; + } else { + type = vd_flag ? PS3_DRV_IOC_VD_D_WRITE : + PS3_DRV_IOC_PD_D_WRITE; + } + ps3_stat_back_inc(type, stat_entry, status); + } + + return; +} + +static inline void ps3_scmd_drv2ioc_back_vd_inc(const struct ps3_cmd *cmd, + struct ps3_single_cmd_stat *stat_entry, U8 status) +{ + if (ps3_scsih_is_rw_type(cmd->io_attr.rw_flag)) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_stat_back_inc(PS3_DRV_IOC_VD_READ, stat_entry, status); + ps3_stat_back_inc(PS3_DRV_IOC_READ, stat_entry, status); + } else { + ps3_stat_back_inc(PS3_DRV_IOC_VD_WRITE, stat_entry, status); + ps3_stat_back_inc(PS3_DRV_IOC_WRITE, stat_entry, status); + } + } else { + ps3_stat_back_inc(PS3_DRV_IOC_NORW, stat_entry, status); + ps3_stat_back_inc(PS3_DRV_IOC_VD_NORW, stat_entry, status); + } + + ps3_direct_cmd_back_inc(cmd, stat_entry, PS3_TRUE, status); + + return; +} + +static inline void ps3_scmd_drv2ioc_back_pd_inc(const struct ps3_cmd *cmd, + struct ps3_single_cmd_stat *stat_entry, U8 status) +{ + if (ps3_scsih_is_rw_type(cmd->io_attr.rw_flag)) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + ps3_stat_back_inc(PS3_DRV_IOC_PD_READ, stat_entry, status); + ps3_stat_back_inc(PS3_DRV_IOC_READ, stat_entry, status); + } else { + ps3_stat_back_inc(PS3_DRV_IOC_PD_WRITE, stat_entry, status); + ps3_stat_back_inc(PS3_DRV_IOC_WRITE, stat_entry, status); + } + } else { + ps3_stat_back_inc(PS3_DRV_IOC_PD_NORW, stat_entry, status); + ps3_stat_back_inc(PS3_DRV_IOC_NORW, stat_entry, status); + } + + ps3_direct_cmd_back_inc(cmd, stat_entry, PS3_FALSE, status); +} + +void ps3_scmd_drv2ioc_back_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd, U8 status) +{ + struct ps3_single_cmd_stat *stat_entry = NULL; + + if (cmd == NULL) { + LOG_ERROR("host_no:%u cmd is null\n", PS3_HOST(instance)); + goto l_out; + } + + stat_entry = ps3_stat_entry_find(cmd->index, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u index:%u stat entry find fail\n", + PS3_HOST(instance), cmd->index); + goto l_out; + } + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + ps3_scmd_drv2ioc_back_vd_inc(cmd, stat_entry, status); + } else { + ps3_scmd_drv2ioc_back_pd_inc(cmd, stat_entry, status); + } + + ps3_stat_back_inc(PS3_DRV_IOC_ALL, stat_entry, status); + ps3_atomic_dec(&instance->cmd_statistics.cmd_outstanding); + +l_out: + return; +} + +static inline void ps3_task_cmd_start_inc(struct ps3_single_cmd_stat *stat_entry, + const struct ps3_cmd *cmd) +{ + switch (cmd->req_frame->mgrReq.reqHead.cmdSubType) { + case PS3_TASK_CMD_SCSI_TASK_ABORT: + ps3_stat_start_inc(PS3_SCSI_ABORT, stat_entry); + break; + + case PS3_TASK_CMD_SCSI_TASK_RESET: + ps3_stat_start_inc(PS3_SCSI_DEVICE_RESET, stat_entry); + break; + + default: + break; + } + + return; +} + +void ps3_mgr_start_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + struct ps3_single_cmd_stat *stat_entry = + ps3_stat_entry_find(cmd->index, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u CFID:%u stat entry find fail\n", + PS3_HOST(instance), cmd->index); + goto l_out; + } + + switch (cmd->req_frame->mgrReq.reqHead.cmdType) { + case PS3_CMD_MANAGEMENT: + case PS3_CMD_SAS_MANAGEMENT: + case PS3_CMD_IOCTL: + goto l_mgr_inc; + case PS3_CMD_SCSI_TASK_MANAGEMENT: + ps3_task_cmd_start_inc(stat_entry, cmd); + goto l_mgr_inc; + default: + goto l_out; + } + +l_mgr_inc: + ps3_stat_start_inc(PS3_DRV_IOC_MGR, stat_entry); +l_out: + return; +} + +static inline void ps3_task_cmd_back_inc(struct ps3_single_cmd_stat *stat_entry, + const struct ps3_cmd *cmd, U8 status) +{ + switch (cmd->req_frame->mgrReq.reqHead.cmdSubType) { + case PS3_TASK_CMD_SCSI_TASK_ABORT: + ps3_stat_back_inc(PS3_SCSI_ABORT, stat_entry, status); + break; + + case PS3_TASK_CMD_SCSI_TASK_RESET: + ps3_stat_back_inc(PS3_SCSI_DEVICE_RESET, stat_entry, status); + break; + + default: + break; + } + + return; +} + +void ps3_mgr_back_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd, U8 status) +{ + struct ps3_single_cmd_stat *stat_entry = + ps3_stat_entry_find(cmd->index, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u index:%u stat entry find fail\n", + PS3_HOST(instance), cmd->index); + goto l_out; + } + + switch (cmd->req_frame->mgrReq.reqHead.cmdType) { + case PS3_CMD_MANAGEMENT: + case PS3_CMD_SAS_MANAGEMENT: + case PS3_CMD_IOCTL: + goto l_mgr_inc; + + case PS3_CMD_SCSI_TASK_MANAGEMENT: + ps3_task_cmd_back_inc(stat_entry, cmd, status); + goto l_mgr_inc; + + default: + goto l_out; + } + +l_mgr_inc: + ps3_stat_back_inc(PS3_DRV_IOC_MGR, stat_entry, status); +l_out: + return; +} + +#ifndef _WINDOWS + +static inline void ps3_stat_workq_service(struct work_struct *work) +{ + struct ps3_cmd_stat_wrokq_context *ctx = ps3_container_of(work, + struct ps3_cmd_stat_wrokq_context, stat_work.work); + struct ps3_instance *instance = NULL; + + if (ctx == NULL) { + LOG_ERROR("ps3_cmd_stat_wrokq_context is null\n"); + goto l_out; + } + + instance = ctx->instance; + if (!ps3_stat_inc_switch_is_open(instance)) { + LOG_INFO("cmd_stat_switch is close\n"); + goto l_out; + } + + if (ctx->is_stop) { + LOG_INFO("cmd_stat_switch workq is stop\n"); + goto l_out; + } + + ps3_stat_data_collect(instance); + + if (ctx->stat_queue != NULL) { + queue_delayed_work(ctx->stat_queue, &ctx->stat_work, + msecs_to_jiffies(instance->cmd_statistics.stat_interval)); + } + +l_out: + return; +} + +S32 ps3_stat_workq_start(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd_stat_wrokq_context *ctx = &instance->cmd_statistics.stat_workq; + char qname[PS3_STAT_WROKQ_NAME_MAX_LEN] = { 0 }; + struct delayed_work *work = &ctx->stat_work; + + if (ctx->stat_queue != NULL) { + LOG_INFO("host_no:%u stat work for is already started!\n", + PS3_HOST(instance)); + goto l_out; + } + + memset(qname, 0, sizeof(qname)); + memset(ctx, 0, sizeof(struct ps3_cmd_stat_wrokq_context)); + INIT_DELAYED_WORK(work, ps3_stat_workq_service); + snprintf(qname, sizeof(qname), "ps3_stat_%u", PS3_HOST(instance)); + + ctx->stat_queue = create_singlethread_workqueue(qname); + if (ctx->stat_queue == NULL) { + LOG_ERROR("host_no:%u cmd stat work queue create failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + ctx->instance = instance; + + if (!ps3_stat_inc_switch_is_open(instance)) { + LOG_INFO("cmd_stat_switch is close\n"); + goto l_out; + } + + ctx->is_stop = PS3_FALSE; + queue_delayed_work(ctx->stat_queue, work, + msecs_to_jiffies(instance->cmd_statistics.stat_interval)); + +l_out: + + return ret; +} + +void ps3_stat_workq_stop(struct ps3_instance *instance) +{ + struct ps3_cmd_stat_wrokq_context *ctx = NULL; + struct workqueue_struct *workq = NULL; + + ctx = &instance->cmd_statistics.stat_workq; + + ctx->is_stop = PS3_TRUE; + + if (ctx->stat_queue == NULL) { + goto l_out; + } + + workq = ctx->stat_queue; + if (!cancel_delayed_work_sync(&ctx->stat_work)) { + flush_workqueue(workq); + } + ctx->stat_queue = NULL; + + destroy_workqueue(workq); + +l_out: + memset(ctx, 0, sizeof(struct ps3_cmd_stat_wrokq_context)); + return; +} +#else + +static inline void ps3_stat_workq_service(void *ins) +{ + struct ps3_instance *instance = (struct ps3_instance*)ins; + struct ps3_cmd_stat_wrokq_context* ctx = &instance->cmd_statistics.stat_workq; + + if (ctx == NULL) { + LOG_ERROR("ps3_cmd_stat_wrokq_context is null\n"); + goto l_out; + } + + if (!ps3_stat_inc_switch_is_open(instance)) { + LOG_INFO("cmd_stat_switch is close\n"); + goto l_out; + } + + if (ctx->is_stop) { + LOG_INFO("cmd_stat_switch workq is stop\n"); + goto l_out; + } + + ps3_stat_data_collect(instance); + + ps3_delay_worker_start(&ctx->statis_work, instance->cmd_statistics.stat_interval); + +l_out: + return; +} + +S32 ps3_stat_workq_start(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd_stat_wrokq_context* ctx = &instance->cmd_statistics.stat_workq; + struct ps3_delay_worker* statis_work = &ctx->statis_work; + + memset(ctx, 0, sizeof(struct ps3_cmd_stat_wrokq_context)); + + if (ps3_delay_worker_init(instance, statis_work, "ps3_statis", ps3_stat_workq_service) != PS3_SUCCESS) { + LOG_ERROR("host_no:%u timer init failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + if (!ps3_stat_inc_switch_is_open(instance)) { + LOG_INFO("cmd_stat_switch is close\n"); + goto l_out; + } + + ctx->is_stop = PS3_FALSE; + if (ps3_delay_worker_start(statis_work, instance->cmd_statistics.stat_interval) != PS3_SUCCESS) { + LOG_ERROR("host_no:%u timer request failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + ctx->is_stop = PS3_TRUE; + goto l_out; + } +l_out: + return ret; +} + +void ps3_stat_workq_stop(struct ps3_instance *instance) +{ + struct ps3_cmd_stat_wrokq_context* ctx = NULL; + ctx = &instance->cmd_statistics.stat_workq; + + ctx->is_stop = PS3_TRUE; + ps3_delay_worker_exit(&ctx->statis_work); + + memset(ctx, 0, sizeof(struct ps3_cmd_stat_wrokq_context)); + return; +} +#endif +static void ps3_backup_stat_entry_build(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + for (; i < ctx->stat_entry_max_count; ++i) { + memcpy(ctx->cmd_stat_backup_buf[i], ctx->cmd_stat_buf[i], + sizeof(struct ps3_single_cmd_stat)); + mb(); + } + + return; +} + +static inline void ps3_last_stat_entry_build(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + + for (; i < ctx->stat_entry_max_count; ++i) { + memcpy(ctx->last_stat_buf[i], ctx->cmd_stat_backup_buf[i], + sizeof(struct ps3_single_cmd_stat)); + mb(); + } + + return; +} +static void ps3_stat_inc_data_collect(struct ps3_instance *instance) +{ + U32 i = 0; + U16 j = 0; + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + struct ps3_single_cmd_stat *backup_stat = NULL; + struct ps3_single_cmd_stat *last_stat = NULL; + U64 inc_back_good = 0; + U64 inc_back_err = 0; + + memset(&ctx->inc_stat, 0, sizeof(ctx->inc_stat)); + for (; i < ctx->stat_entry_max_count; ++i) { + backup_stat = ps3_backup_stat_entry_find(i, instance); + if (backup_stat == NULL) { + LOG_WARN("host_no:%u index:%u get backup_stat err\n", + PS3_HOST(instance), i); + continue; + } + last_stat = ps3_last_stat_entry_find(i, instance); + if (last_stat == NULL) { + LOG_WARN("host_no:%u index:%u get last_stat err\n", + PS3_HOST(instance), i); + continue; + } + + mb(); + + for (j = 0; j < PS3_CMD_STAT_COUNT; ++j) { + ctx->inc_stat.stat[j].start += + backup_stat->stat[j].start - last_stat->stat[j].start; + inc_back_good = backup_stat->stat[j].back_good - + last_stat->stat[j].back_good; + inc_back_err = backup_stat->stat[j].back_err - + last_stat->stat[j].back_err; + if ((inc_back_good + inc_back_err) == 0) { + continue; + } + mb(); + ctx->inc_stat.stat[j].back_good += inc_back_good; + ctx->inc_stat.stat[j].back_err += inc_back_err; + ctx->inc_stat.stat[j].not_back += + backup_stat->stat[j].not_back - + last_stat->stat[j].not_back; + ps3_stat_lagency_inc_cal(&ctx->inc_stat.stat[j].lagency, + &backup_stat->stat[j].lagency, + &last_stat->stat[j].lagency); + } + } + ps3_stat_lagency_avg_calc(&ctx->inc_stat); + + return; +} + +static inline void ps3_stat_total_data_collect(struct ps3_instance *instance) +{ + struct ps3_cmd_statistics_context *ctx = &instance->cmd_statistics; + U64 back_count = 0; + U16 i = 0; + + for (; i < PS3_CMD_STAT_COUNT; ++i) { + ctx->total_stat.stat[i].start += ctx->inc_stat.stat[i].start; + ctx->total_stat.stat[i].back_good += ctx->inc_stat.stat[i].back_good; + ctx->total_stat.stat[i].back_err += ctx->inc_stat.stat[i].back_err; + back_count = ctx->total_stat.stat[i].back_good + ctx->total_stat.stat[i].back_err; + ctx->total_stat.stat[i].not_back = ctx->total_stat.stat[i].start - back_count; + ps3_stat_lagency_merge(&ctx->total_stat.stat[i].lagency, + &ctx->inc_stat.stat[i].lagency); + mb(); + if (back_count != 0) { + ctx->total_stat.stat[i].lagency.avg = + (ctx->total_stat.stat[i].lagency.all / back_count); + } + } + + return; +} + +static inline void ps3_stat_data_log(const struct ps3_cmd_stat_entry *stat, + const struct ps3_cmd_stat_entry *inc_stat, U16 stat_num) +{ + U16 i = 0; + + for (; i < stat_num; ++i) { + if (inc_stat[i].start == 0) { + continue; + } + LOG_INFO("[%s:] start:%llu back_good:%llu back_err:%llu " + "not_back:%llu avg[%lluus] max[%lluus] min[%lluus]\n", + ps3_cmd_stat_item_tostring((enum ps3_cmd_stat_item)i), + stat[i].start, stat[i].back_good, stat[i].back_err, + stat[i].not_back, stat[i].lagency.avg, + stat[i].lagency.max_lagency, stat[i].lagency.min_lagency); + } + + return; +} + +static inline void ps3_stat_total_data_log(struct ps3_instance *instance) +{ + LOG_INFO("host_no:%u total cmd stat show begin\n", PS3_HOST(instance)); + ps3_stat_data_log(instance->cmd_statistics.total_stat.stat, + instance->cmd_statistics.inc_stat.stat, PS3_CMD_STAT_COUNT); + LOG_INFO("host_no:%u total cmd stat show end\n", PS3_HOST(instance)); + + return; +} + +static inline void ps3_stat_inc_data_log(struct ps3_instance *instance) +{ + LOG_INFO("host_no:%u inc cmd stat show begin \n", PS3_HOST(instance)); + ps3_stat_data_log(instance->cmd_statistics.inc_stat.stat, + instance->cmd_statistics.inc_stat.stat, PS3_CMD_STAT_COUNT); + LOG_INFO("host_no:%u inc cmd stat show end \n", PS3_HOST(instance)); + + return; +} + +static inline Bool ps3_stat_is_write_log(struct ps3_instance *instance) +{ + return instance->cmd_statistics.log_record_count == PS3_STAT_LOG_COUNT; +} + +static inline void ps3_stat_log_count_inc(struct ps3_instance *instance) +{ + instance->cmd_statistics.log_record_count++; + if (instance->cmd_statistics.log_record_count == PS3_STAT_LOG_MAX_COUNT) { + instance->cmd_statistics.log_record_count = 0; + } +} + +static inline void ps3_stat_write_log(struct ps3_instance *instance) +{ + if (ps3_stat_log_switch_is_open(instance) && + ps3_stat_inc_switch_is_open(instance)) { + if (ps3_stat_is_write_log(instance)) { + ps3_stat_inc_data_log(instance); + + ps3_stat_total_data_log(instance); + } + ps3_stat_log_count_inc(instance); + } + + return; +} + +static inline void ps3_stat_data_collect(struct ps3_instance *instance) +{ + ps3_backup_stat_entry_build(instance); + + ps3_stat_inc_data_collect(instance); + + ps3_stat_total_data_collect(instance); + + ps3_last_stat_entry_build(instance); + + ps3_stat_write_log(instance); + + return; +} + +void ps3_qos_stat_inc(struct ps3_instance *instance, + struct ps3_cmd *cmd, U16 stat, U16 type) +{ + struct ps3_single_cmd_stat *stat_entry = ps3_stat_entry_find(cmd->index, instance); + if (stat_entry == NULL) { + LOG_ERROR("host_no:%u index:%u stat entry find fail\n", + PS3_HOST(instance), cmd->index); + return; + } + + if (type == PS3_STAT_START) { + ps3_stat_start_inc(stat, stat_entry); + } else if (type == PS3_STAT_BACK) { + ps3_stat_back_inc(stat, stat_entry, PS3_STAT_BACK_OK); + } +} diff --git a/drivers/scsi/ps3stor/ps3_cmd_statistics.h b/drivers/scsi/ps3stor/ps3_cmd_statistics.h new file mode 100644 index 0000000000000000000000000000000000000000..d11d5cdbe39bc3bd6f977101ca0987449f1d5307 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_cmd_statistics.h @@ -0,0 +1,374 @@ + +#ifndef _PS3_CMD_STATICTIS_H_ +#define _PS3_CMD_STATICTIS_H_ +#ifndef _WINDOWS +#include +#include +#include +#endif + +#include "ps3_htp_def.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_instance_manager.h" +#include "ps3_cmd_channel.h" +#include "ps3_platform_utils.h" +#include "ps3_scsih.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +#define PS3_CMD_STAT_INIT_VALUE (0) + +#define PS3_CMD_WORD_INDEX_SHIFT (0x000000FF) + +void ps3_dev_io_statis_init(struct ps3_dev_io_statis *statis); + +void ps3_io_statis_inc(struct scsi_device *sdev, enum ps3_dev_io_stat_type type); + +void ps3_io_statis_dec(struct scsi_device *sdev, + enum ps3_dev_io_stat_type type); + +void ps3_io_statis_clear(struct scsi_device *sdev); + +S32 ps3_cmd_statistics_init(struct ps3_instance *instance); + + +void ps3_cmd_statistics_exit(struct ps3_instance *instance); + +void ps3_dev_io_start_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd); + +void ps3_dev_io_start_err_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd); + +void ps3_dev_io_start_ok_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd); + +void ps3_dev_io_back_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd, U8 status); + +static inline void ps3_dev_scsi_err_stat_inc(struct ps3_cmd *cmd) +{ + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_R_RECV_ERR); + } else if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag)){ + ps3_io_statis_inc(cmd->scmd->device, PS3_DEV_IO_STAT_TYPE_W_RECV_ERR); + } +} + +static inline Bool ps3_is_vd_rw_cmd(const struct scsi_cmnd *s_cmd) +{ + return (PS3_SDEV_PRI_DATA(s_cmd->device)->dev_type == PS3_DEV_TYPE_VD) && + ps3_scsih_cdb_is_rw_cmd(s_cmd->cmnd); + +} + +static inline Bool ps3_is_read_cmd(const struct scsi_cmnd *s_cmd) +{ + return ps3_scsih_cdb_is_read_cmd(s_cmd->cmnd); +} +static inline Bool ps3_is_write_cmd(const struct scsi_cmnd *s_cmd) +{ + return ps3_scsih_cdb_is_write_cmd(s_cmd->cmnd); +} + +void ps3_io_outstand_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd); + +void ps3_io_outstand_dec(struct ps3_instance *instance, + const struct scsi_cmnd *s_cmd); + +void ps3_vd_outstand_dec(struct ps3_instance *instance, const struct scsi_cmnd *s_cmd); + +void ps3_vd_outstand_inc(struct ps3_instance *instance, const struct scsi_cmnd *s_cmd); + +void ps3_dev_io_outstand_dec(const struct ps3_cmd *cmd); + +void ps3_dev_io_qos_inc(struct ps3_scsi_priv_data* priv_data); + +void ps3_dev_io_qos_dec(struct ps3_scsi_priv_data* priv_data); + +void ps3_dev_io_outstand_inc(const struct ps3_cmd *cmd); + +void ps3_qos_cmd_inc(struct ps3_instance *instance); + +void ps3_qos_stat_inc(struct ps3_instance *instance, + struct ps3_cmd *cmd, U16 stat, U16 type); + +static inline U8 ps3_cmd_word_index_get(struct ps3_instance *instance) +{ + U64 cmd_count = (U64)ps3_atomic64_inc_return(&instance->cmd_statistics.cmd_word_send_count); + return (U8)(cmd_count & PS3_CMD_WORD_INDEX_SHIFT); +} + +static inline void ps3_cmd_word_stat_inc(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word) +{ + (void)cmd_word; + (void)ps3_cmd_word_index_get(instance); + return; +} + +#ifndef _WINDOWS +void ps3_scmd_inc(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, U8 type, U8 status); +#else +void ps3_scmd_inc(struct ps3_instance *instance, + const struct scsi_cmnd *s_cmd, U32 tag, U8 type, U8 status); +#endif +void ps3_scmd_drv2ioc_start_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd); + +void ps3_scmd_drv2ioc_back_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd, U8 status); + + +static inline U8 ps3_resp_stauts_to_stat_status(U8 reply_flags) +{ + return (reply_flags == PS3_REPLY_WORD_FLAG_SUCCESS) ? + (U8)PS3_STAT_BACK_OK : (U8)PS3_STAT_BACK_FAIL; +} + +void ps3_mgr_start_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd); + +void ps3_mgr_back_inc(struct ps3_instance *instance, + const struct ps3_cmd *cmd, U8 status); + +void ps3_stat_all_clear(struct ps3_instance *instance); + +static inline Bool ps3_stat_inc_switch_is_open(const struct ps3_instance *instance) +{ + return (instance->cmd_statistics.cmd_stat_switch & PS3_STAT_INC_SWITCH_OPEN); +} + +static inline Bool ps3_stat_log_switch_is_open(const struct ps3_instance *instance) +{ + return (instance->cmd_statistics.cmd_stat_switch & PS3_STAT_LOG_SWITCH_OPEN); +} + +static inline Bool ps3_stat_outstand_switch_is_open(const struct ps3_instance *instance) +{ + return (instance->cmd_statistics.cmd_stat_switch & PS3_STAT_OUTSTAND_SWITCH_OPEN); +} + +static inline Bool ps3_stat_dev_switch_is_open(const struct ps3_instance *instance) +{ + return (instance->cmd_statistics.cmd_stat_switch & PS3_STAT_DEV_SWITCH_OPEN); +} + +#ifndef _WINDOWS +static inline void ps3_sdev_busy_inc(struct scsi_cmnd *scmd) +{ +#if defined DRIVER_SUPPORT_PRIV_BUSY + struct ps3_scsi_priv_data *device_priv_data = (struct ps3_scsi_priv_data*)scmd->device->hostdata; + if (device_priv_data == NULL) { + return; + } + + atomic_inc(&device_priv_data->sdev_priv_busy); +#else +#ifdef PS3_UT + atomic_inc(&scmd->device->device_busy); +#else + (void) scmd; +#endif +#endif + + return; +} + +static inline void ps3_sdev_busy_dec(struct scsi_cmnd *scmd) +{ +#if defined DRIVER_SUPPORT_PRIV_BUSY + struct ps3_scsi_priv_data *device_priv_data = (struct ps3_scsi_priv_data*)scmd->device->hostdata; + if (device_priv_data == NULL) { + return; + } + + atomic_dec(&device_priv_data->sdev_priv_busy); +#else +#ifdef PS3_UT + atomic_dec(&scmd->device->device_busy); +#else + (void) scmd; +#endif +#endif + return; +} + +#define PS3_DEV_BUSY_DEC(cmd) do { \ + ps3_sdev_busy_dec((cmd)); \ +} while (0) + +#define PS3_DEV_BUSY_INC(cmd) do { \ + ps3_sdev_busy_inc((cmd)); \ +} while (0) +#else +#define PS3_DEV_BUSY_DEC(cmd) +#define PS3_DEV_BUSY_INC(cmd) +#endif + +static inline Bool ps3_stat_qos_switch_is_open(const struct ps3_instance *instance) +{ + return (instance->cmd_statistics.cmd_stat_switch & PS3_STAT_QOS_SWITCH_OPEN); +} + +#define PS3_CMD_WORD_STAT_INC(instance, cmd_word) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_cmd_word_stat_inc((instance), (cmd_word)); \ + } \ +} while (0) + +#define PS3_DEV_IO_START_OK_INC(instance, cmd) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_io_start_ok_inc((instance), (cmd)); \ + } \ +} while (0); + +#define PS3_DEV_IO_BACK_INC(instance, cmd, status) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_io_back_inc((instance), (cmd), (status)); \ + } \ +} while (0); + +#define PS3_DEV_IO_START_ERR_INC(instance, cmd) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_io_start_err_inc((instance), (cmd)); \ + } \ +} while (0); + +#define PS3_DEV_IO_START_INC(instance, cmd) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_io_start_inc((instance), (cmd)); \ + } \ +} while (0) +#ifndef _WINDOWS +#define PS3_IO_BACK_INC(instance, s_cmd, status) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_inc((instance), (s_cmd), PS3_STAT_BACK, \ + ps3_resp_stauts_to_stat_status((status))); \ + } \ +} while (0) +#else +#define PS3_IO_BACK_INC(instance, s_cmd, tag, status) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_inc((instance), (s_cmd), (tag), PS3_STAT_BACK, \ + ps3_resp_stauts_to_stat_status((status))); \ + } \ +} while (0) +#endif +#define PS3_IO_OUTSTANDING_INC(instance, cmd) do { \ + ps3_io_outstand_inc(instance, cmd); \ +} while (0) + +#define PS3_DEV_IO_ERR_STAT_INC(instance, cmd) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_scsi_err_stat_inc((cmd)); \ + } \ +} while (0) +#ifndef _WINDOWS +#define PS3_IO_START_INC(instance, s_cmd) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_inc((instance), (s_cmd), PS3_STAT_START, PS3_STAT_BACK_OK); \ + } \ +} while (0) + +#define PS3_IO_BACK_ERR_INC(instance, s_cmd) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_inc((instance), (s_cmd), PS3_STAT_BACK, PS3_STAT_BACK_FAIL); \ + } \ +} while (0) +#else +#define PS3_IO_START_INC(instance, s_cmd, tag) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_inc((instance), (s_cmd), (tag), PS3_STAT_START, PS3_STAT_BACK_OK); \ + } \ +} while (0) + +#define PS3_IO_BACK_ERR_INC(instance, s_cmd, tag) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_inc((instance), (s_cmd), (tag), PS3_STAT_BACK, PS3_STAT_BACK_FAIL); \ + } \ +} while (0) +#endif +#define PS3_IO_DRV2IOC_START_INC(instance, cmd) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_drv2ioc_start_inc((instance), (cmd)); \ + } \ +} while (0) + +#define PS3_IOC_DRV2IOC_BACK_INC(instance, cmd, status) { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_scmd_drv2ioc_back_inc((instance), (cmd), \ + ps3_resp_stauts_to_stat_status((status))); \ + } \ +} while (0) + +#define PS3_MGR_CMD_STAT_INC(instance, cmd) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_mgr_start_inc((instance), (cmd)); \ + } \ +} while (0) + +#define PS3_MGR_CMD_BACK_INC(instance, cmd, status) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_mgr_back_inc((instance), (cmd), \ + ps3_resp_stauts_to_stat_status((status))); \ + } \ +} while (0) + +#define PS3_IO_OUTSTAND_DEC(instance, s_cmd) do { \ + if (ps3_stat_outstand_switch_is_open((instance))) { \ + ps3_io_outstand_dec((instance), (s_cmd)); \ + } \ +} while (0) + +#define PS3_VD_OUTSTAND_DEC(instance, s_cmd) do { \ + ps3_vd_outstand_dec(instance, s_cmd); \ +} while (0) + +#define PS3_VD_OUTSTAND_INC(instance, s_cmd) do { \ + ps3_vd_outstand_inc(instance, s_cmd); \ +} while (0) + +#define PS3_DEV_IO_OUTSTAND_DEC(instance, cmd) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_io_outstand_dec((cmd)); \ + } \ +} while (0) + +#define PS3_DEV_IO_OUTSTAND_INC(instance, cmd) do { \ + if (ps3_stat_dev_switch_is_open((instance))) { \ + ps3_dev_io_outstand_inc((cmd)); \ + } \ +} while (0) + +#define PS3_QOS_CMD_INC(instance) do { \ + if (ps3_stat_qos_switch_is_open((instance))) { \ + ps3_qos_cmd_inc((instance)); \ + } \ +} while (0) + +#define PS3_QOS_STAT_START(instance, cmd, type) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_qos_stat_inc((instance), (cmd), (type), PS3_STAT_START); \ + } \ + } while (0) + +#define PS3_QOS_STAT_END(instance, cmd, type) do { \ + if (ps3_stat_inc_switch_is_open((instance))) { \ + ps3_qos_stat_inc((instance), (cmd), (type), PS3_STAT_BACK); \ + } \ + } while (0) + +S32 ps3_stat_workq_start(struct ps3_instance *instance); + +void ps3_stat_workq_stop(struct ps3_instance *instance); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/drivers/scsi/ps3stor/ps3_debug.c b/drivers/scsi/ps3stor/ps3_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..6284f1c836ee3c17c146e2f134716c1c27e11176 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_debug.c @@ -0,0 +1,1186 @@ +#ifndef _WINDOWS + +#include +#include +#include +#include +#ifdef __KERNEL__ +#include +#else +#include +#endif +#include "ps3_htp_def.h" +#include "ps3_instance_manager.h" +#include "ps3_ioc_manager.h" +#include "ps3_ioc_state.h" + +#include "ps3_debug.h" +#include "ps3_irq.h" +#include "ps3_driver_log.h" +#include "ps3_cli_debug.h" +#include "ps3_module_para.h" +#include "ps3_util.h" + +#endif + +#include "ps3_htp_def.h" +#include "ps3_instance_manager.h" +#include "ps3_event.h" +#include "ps3_dump.h" +#define REG_OFFSET_BY_ADDR(instance, reg) ((U8*)(reg) - ((U8*)(instance)->reg_set)) + +#ifndef _WINDOWS +typedef void (*dma_dump_mappings_cb)(struct device *dev); +#endif + +struct ps3_reg_name { + U64 read_dump_interval_ms; + U64 write_dump_interval_ms; + U32 reg_cnt; + S8 name[32]; +}; + +static struct ps3_reg_name g_ps3_reg_name_table[] = { + {0, 0, 8, "reserved0"}, + {0, 0, 1, "ps3Doorbell"}, + {0, 0, 1, "ps3DoorbellIrqClear"}, + {0, 0, 1, "ps3DoorbellIrqMask"}, + {0, 0, 1, "ps3IrqControl"}, + {0, 0, 20, "reserved1"}, + + {0, 0, 1, "ps3SoftresetKey"}, + {1000, 0, 1, "ps3SoftresetState"}, + {0, 0, 1, "ps3Softreset"}, + {0, 0, 1, "ps3SoftresetIrqClear"}, + {0, 0, 1, "ps3SoftresetIrqMask"}, + {0, 0, 1, "ps3SoftresetKeyShiftRegLow"}, + {0, 0, 1, "ps3SoftresetKeyShiftRegHigh"}, + {0, 0, 1, "ps3SoftresetTimeCnt"}, + {0, 0, 1, "ps3SoftresetTimeOutEn"}, + {0, 0, 23, "reserved2"}, + + {0, 0, 1, "ps3HardresetKey"}, + {1000, 0, 1, "ps3HardresetState"}, + {0, 0, 1, "ps3Hardreset"}, + {0, 0, 1, "ps3HardresetKeyShiftRegLow"}, + {0, 0, 1, "ps3HardresetKeyShiftRegHigh"}, + {0, 0, 1, "ps3HardresetTimeCnt"}, + {0, 0, 1, "ps3HardresetTimeOutEn"}, + {0, 0, 1, "ps3KeyGapCfg"}, + {0, 0, 1, "ps3HardresetIrqClear"}, + {0, 0, 1, "ps3HardresetIrqMask"}, + {0, 0, 22, "reserved3"}, + + {10000, 0, 1, "ps3SocFwState"}, + {0, 0, 1, "ps3MaxFwCmd"}, + {0, 0, 1, "ps3MaxChainSize"}, + {0, 0, 1, "ps3MaxVdInfoSize"}, + {0, 0, 1, "ps3MaxNvmePageSize"}, + {0, 0, 1, "ps3FeatureSupport"}, + {0, 0, 1, "ps3FirmwareVersion"}, + {0, 0, 1, "ps3MaxReplyque"}, + {0, 0, 1, "ps3HardwareVersion"}, + {0, 0, 1, "ps3MgrQueueDepth"}, + {0, 0, 1, "ps3CmdQueueDepth"}, + {0, 0, 1, "ps3TfifoDepth"}, + {0, 0, 1, "ps3MaxSecR1xCmds"}, + {0, 0, 19, "reserved4"}, + + {0, 0, 1, "ps3HilAdvice2directCnt0"}, + {0, 0, 1, "ps3HilAdvice2directCnt1"}, + {0, 0, 1, "ps3HilAdvice2directCnt2"}, + {0, 0, 1, "ps3HilAdvice2directCnt3"}, + {0, 0, 1, "ps3HilAdvice2directCntAll"}, + {0, 0, 3, "reserved5"}, + {0, 0, 1, "ps3IrqStatusRpt"}, + {0, 0, 23, "reserved6"}, + + {0, 0, 1, "ps3DumpCtrl"}, + {0, 0, 1, "ps3DumpCtrlIrqClear"}, + {0, 0, 1, "ps3DumpCtrlIrqMask"}, + {0, 0, 1, "ps3DumpStatus"}, + {0, 0, 1, "ps3DumpDataSize"}, + {0, 0, 27, "reserved7"}, + + {0, 0, 1, "ps3CmdTrigger"}, + {0, 0, 1, "ps3CmdTriggerIrqClear"}, + {0, 0, 1, "ps3CmdTriggerIrqMask"}, + {0, 0, 1, "ps3SoftresetCounter"}, + {0, 0, 1, "ps3RegCmdState"}, + {0, 0, 1, "ps3Debug0"}, + {0, 0, 1, "ps3Debug0IrqClear"}, + {0, 0, 1, "ps3Debug0IrqMask"}, + {0, 0, 1, "ps3Debug1"}, + {0, 0, 1, "ps3Debug1IrqClear"}, + {0, 0, 1, "ps3Debug1IrqMask"}, + {0, 0, 1, "ps3Debug2"}, + {0, 0, 1, "ps3Debug2IrqClear"}, + {0, 0, 1, "ps3Debug2IrqMask"}, + {0, 0, 1, "ps3Debug3"}, + {0, 0, 1, "ps3Debug3IrqClear"}, + {0, 0, 1, "ps3Debug3IrqMask"}, + {0, 0, 1, "ps3Debug4"}, + {0, 0, 1, "ps3Debug4IrqClear"}, + {0, 0, 1, "ps3Debug4IrqMask"}, + {0, 0, 1, "ps3Debug5"}, + {0, 0, 1, "ps3Debug6"}, + {0, 0, 1, "ps3Debug7"}, + {0, 0, 1, "ps3Debug8"}, + {0, 0, 1, "ps3Debug9"}, + {0, 0, 1, "ps3Debug10"}, + {0, 0, 1, "ps3Debug11"}, + {0, 0, 1, "ps3Debug12"}, + {0, 0, 4, "reserved8"}, + + {0, 0, 1, "ps3SessioncmdAddr"}, + {0, 0, 1, "ps3SessioncmdAddrIrqClear"}, + {0, 0, 1, "ps3SessioncmdAddrIrqMask"}, + {0, 0, 7965, "reserved9"}, + {0, 0, 1, "ps3RequestQueue"}, + {0, 0, 1, "fifoErrCnt"}, + {0, 0, 1, "fifoStatus"}, + {0, 0, 1, "fifoLevelConfig"}, + {0, 0, 1, "fifoRst"}, + {0, 0, 1, "fifoIOCnt"}, + {0, 0, 1, "fifoFlowCnt"}, + {0, 0, 1, "fifoIntStatus"}, + {0, 0, 1, "fifoIntSet"}, + {0, 0, 1, "fifoIntClr"}, + {0, 0, 1, "fifoIntMask"}, + {0, 0, 1, "fifoCntClr"}, + {0, 0, 1, "fifoOrderError"}, + {0, 0, 4, "fifoDinShift"}, + {0, 0, 4, "fifoDoutShift"}, + {0, 0, 1, "fifoStatusMaxLevel"}, + {0, 0, 1, "fifoInit"}, + {0, 0, 1, "fifoinitEn"}, + {0, 0, 1, "fifoinitMax"}, + {0, 0, 1, "fifoStatusEccCnt"}, + {0, 0, 1, "fifoStatusEccAddr"}, + {0, 0, 1, "fifoDecoderOverflow"}, + {0, 0, 1, "fifoEccBadProject"}, + {0, 0, 1, "fifoOverFlowWord"}, + {0, 0, 34, "reserved10"}, + + {0, 0, 1, "ps3FucntionLock"}, + {0, 0, 1, "ps3FunctionLockOwner"}, + {0, 0, 30, "reserved11"}, +}; +static inline U64 ps3_util_now_timestamp_ms_get(void) +{ + U64 timenow = 0; +#ifndef _WINDOWS + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + struct timespec now; + now = current_kernel_time(); +#else + struct timespec64 now; + ktime_get_coarse_real_ts64(&now); +#endif + timenow = now.tv_sec * 1000 + now.tv_nsec / 1000000; +#else + LARGE_INTEGER now; + StorPortQuerySystemTime(&now); + + timenow = (U64)(now.QuadPart / 10000); +#endif + return timenow; + +} + +static void ps3_reg_dump_attr_init(struct ps3_instance *instance) +{ + U32 local_index = 0; + U32 count = 0; + U32 table_index = 0; + U32 table_cnt = 0; + U32 table_size = (sizeof(g_ps3_reg_name_table)/sizeof(g_ps3_reg_name_table[0])); + struct ps3_reg_dump_attr *reg_dump = instance->debug_context.reg_dump; + + for (table_index = 0; table_index < table_size; table_index++) { + table_cnt = g_ps3_reg_name_table[table_index].reg_cnt; + + for (local_index = 0; local_index < table_cnt; local_index++) { + if (count >= (PS3_REGISTER_SET_SIZE/sizeof(U64))) { + goto l_out; + } + + reg_dump[count].read_dump_timestamp = 0; + reg_dump[count].write_dump_timestamp = 0; + reg_dump[count].read_dump_interval_ms = + g_ps3_reg_name_table[table_index].read_dump_interval_ms; + reg_dump[count].write_dump_interval_ms = + g_ps3_reg_name_table[table_index].write_dump_interval_ms; + memcpy(reg_dump[count].name, + g_ps3_reg_name_table[table_index].name, 32); + reg_dump[count].lastest_value = 0; + + count++; + } + } +l_out: + return; +} + +void ps3_reg_dump(struct ps3_instance *instance, + void __iomem *reg, U64 value, Bool is_read) +{ + Bool is_dump = PS3_FALSE; + const S8 *dump_type = NULL; + U64 timestamp_ms = ps3_util_now_timestamp_ms_get(); + U64 last_dump_timestamp = 0; + U64 dump_interval = 0; + U32 reg_index = (U32)REG_OFFSET_BY_ADDR(instance, reg)/sizeof(U64); + struct ps3_reg_dump_attr *reg_dump = instance->debug_context.reg_dump; + + if( (reg == NULL) || + ((U8*)reg < (U8*)instance->reg_set) || + (((U8*)reg - (U8*)instance->reg_set) > PS3_REGISTER_SET_SIZE)) { + return; + } + + if (is_read) { + dump_type = "reg read"; + last_dump_timestamp = reg_dump[reg_index].read_dump_timestamp; + dump_interval = reg_dump[reg_index].read_dump_interval_ms; + } else { + dump_type = "reg write"; + last_dump_timestamp = reg_dump[reg_index].write_dump_timestamp; + dump_interval = reg_dump[reg_index].write_dump_interval_ms; + } + + if (timestamp_ms - last_dump_timestamp >= dump_interval) { + is_dump = PS3_TRUE; + } + + if (reg_dump[reg_index].lastest_value != value) { + is_dump = PS3_TRUE; + reg_dump[reg_index].lastest_value = value; + } + + if (!is_dump) { + return; + } + + LOG_DEBUG("hno:%u %s:0x%04x:%s:0x%08llx \n", + PS3_HOST(instance), dump_type, + (U32)(reg_index * sizeof(U64)), + reg_dump[reg_index].name, value); + if (is_read) { + reg_dump[reg_index].read_dump_timestamp = timestamp_ms; + } else { + reg_dump[reg_index].write_dump_timestamp = timestamp_ms; + } +} + +#ifndef _WINDOWS + +static inline Bool ps3_is_alloc_debug_mem(U32 debug_mem_size) +{ + return (debug_mem_size != 0); +} + +static S32 ps3_debug_mem_array_alloc(struct ps3_instance *instance, + U32 debug_mem_size) +{ + S32 ret = PS3_SUCCESS; + U32 array_num = 0; + U32 alloc_size = 0; + struct ps3_debug_context *ctx = &instance->debug_context; + Ps3DebugMemEntry_s *entry = (Ps3DebugMemEntry_s*)ctx->debug_mem_buf; + U8 i = 0; + + for (; i < PS3_DEBUG_MEM_ARRAY_MAX_NUM; ++i) { + if (debug_mem_size == 0) { + break; + } + + array_num++; + if (debug_mem_size <= PS3_MAX_DMA_MEM_SIZE) { + alloc_size = debug_mem_size * 1024; + ctx->debug_mem_vaddr[i].debugMemAddr = + (U64)ps3_dma_alloc_coherent(instance, alloc_size, + &entry[i].debugMemAddr); + INJECT_START(PS3_ERR_IJ_PS3_DEBUG_MEM_ADDR_ALLOC, &ctx->debug_mem_vaddr[i].debugMemAddr); + if (ctx->debug_mem_vaddr[i].debugMemAddr == 0) { + LOG_ERROR("hno:%u alloc debug_mem[%u] end failed\n", + PS3_HOST(instance), i); + ret = -PS3_ENOMEM; + goto l_out; + } + ctx->debug_mem_vaddr[i].debugMemSize = debug_mem_size; + entry[i].debugMemSize = debug_mem_size; + debug_mem_size = 0; + LOG_INFO("hno:%u index[%u] vaddr[0x%llx], dma[0x%llx], size[%u]KB\n", + PS3_HOST(instance), i, ctx->debug_mem_vaddr[i].debugMemAddr, + entry[i].debugMemAddr, entry[i].debugMemSize); + break; + } else { + debug_mem_size -= PS3_MAX_DMA_MEM_SIZE; + alloc_size = PS3_MAX_DMA_MEM_SIZE * 1024; + ctx->debug_mem_vaddr[i].debugMemAddr = + (U64)ps3_dma_alloc_coherent(instance, alloc_size, + &entry[i].debugMemAddr); + INJECT_START(PS3_ERR_IJ_PS3_DEBUG_MEM_ADDR_ALLOC, &ctx->debug_mem_vaddr[i].debugMemAddr); + if (ctx->debug_mem_vaddr[i].debugMemAddr == 0) { + LOG_ERROR("hno:%u alloc debug_mem index[%u] failed\n", + PS3_HOST(instance), i); + ret = -PS3_ENOMEM; + goto l_out; + } + ctx->debug_mem_vaddr[i].debugMemSize = PS3_MAX_DMA_MEM_SIZE; + entry[i].debugMemSize = PS3_MAX_DMA_MEM_SIZE; + } + + LOG_INFO("hno:%u index[%u] m vaddr[0x%llx], dma[0x%llx], size[%u]KB\n", + PS3_HOST(instance), i, ctx->debug_mem_vaddr[i].debugMemAddr, + entry[i].debugMemAddr, entry[i].debugMemSize); + } + ctx->debug_mem_array_num = array_num; + LOG_INFO("hno:%u debug mem array num [%u]\n", PS3_HOST(instance), array_num); + +l_out: + return ret; +} + +S32 ps3_debug_mem_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 debug_mem_size = ps3_debug_mem_size_query(); + U32 buf_size = PS3_DEBUG_MEM_ARRAY_MAX_NUM * sizeof(Ps3DebugMemEntry_s); + + if (!ps3_is_alloc_debug_mem(debug_mem_size)) { + goto l_out; + } + + if (debug_mem_size > PS3_MAX_DEBUG_MEM_SIZE_PARA) { + LOG_WARN("hno:%u debug mem size is greater than the maximum value\n", PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_out; + } + + instance->debug_context.debug_mem_buf = (Ps3DebugMemEntry_s*)ps3_dma_alloc_coherent(instance, + buf_size, &instance->debug_context.debug_mem_buf_phy); + INJECT_START(PS3_ERR_IJ_PS3_DEBUG_MEM_BUF_ALLOC, &instance->debug_context.debug_mem_buf); + if (instance->debug_context.debug_mem_buf == NULL) { + LOG_ERROR("hno:%u alloc debug_mem_buf failed\n", PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_out; + } + memset(instance->debug_context.debug_mem_buf, 0, buf_size); + + ret = ps3_debug_mem_array_alloc(instance, debug_mem_size); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u alloc debug_mem_array failed\n", PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_free; + } + + LOG_INFO("hno:%u alloc debug_mem buf vaddr[0x%p], dma[0x%llx], size[%u]KB\n", + PS3_HOST(instance), instance->debug_context.debug_mem_buf, + instance->debug_context.debug_mem_buf_phy, buf_size); + + goto l_out; + +l_free: + ps3_debug_mem_free(instance); +l_out: + return ret; +} + +S32 ps3_debug_mem_free(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_debug_context *ctx = &instance->debug_context; + Ps3DebugMemEntry_s *entry = ctx->debug_mem_buf; + U32 size = 0; + U8 i = 0; + + if (entry == NULL) { + ret = PS3_SUCCESS; + goto l_out; + } + + for (i = 0; i < PS3_DEBUG_MEM_ARRAY_MAX_NUM; ++i) { + if (ctx->debug_mem_vaddr[i].debugMemAddr == 0) { + continue; + } + size = ctx->debug_mem_vaddr[i].debugMemSize * 1024; + LOG_INFO("dma free size[%u] addr[0x%llx]\n", + size, ctx->debug_mem_vaddr[i].debugMemAddr); + (void)ps3_dma_free_coherent(instance, size, + (void*)ctx->debug_mem_vaddr[i].debugMemAddr, + entry[i].debugMemAddr); + } + memset(ctx->debug_mem_vaddr, 0, sizeof(ctx->debug_mem_vaddr)); + + size = PS3_DEBUG_MEM_ARRAY_MAX_NUM * sizeof(Ps3DebugMemEntry_s); + (void)ps3_dma_free_coherent(instance, size, + ctx->debug_mem_buf, ctx->debug_mem_buf_phy); + ctx->debug_mem_buf = NULL; + ctx->debug_mem_buf_phy = 0; + LOG_INFO("free debug mem end\n"); + +l_out: + return ret; +} + +void ps3_debug_context_init(struct ps3_instance *instance) +{ + memset(&instance->debug_context, 0, sizeof(struct ps3_debug_context)); + instance->debug_context.io_trace_switch = PS3_FALSE; + + ps3_reg_dump_attr_init(instance); +} + +static inline struct ps3_instance *ps3_debug_instance_query(struct device *cdev, + struct device_attribute *attr, const char *buf) +{ + struct Scsi_Host *shost = NULL; + struct ps3_instance *instance = NULL; + + if (cdev == NULL || buf == NULL) { + instance = NULL; + goto l_out; + } + (void)attr; + + shost = class_to_shost(cdev); + if (shost == NULL) { + instance = NULL; + goto l_out; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,19,0) + if (shost->hostdata == NULL) { + instance = NULL; + goto l_out; + } +#endif + instance = (struct ps3_instance *)shost->hostdata; + +l_out: + return instance; +} + +ssize_t ps3_vd_io_outstanding_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + atomic_read(&instance->cmd_statistics.vd_io_outstanding)); + +l_out: + return ret; +} + +ssize_t ps3_io_outstanding_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + atomic_read(&instance->cmd_statistics.io_outstanding)); + +l_out: + return ret; +} + +ssize_t ps3_is_load_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", instance->state_machine.is_load); + +l_out: + return ret; +} +ssize_t ps3_dump_ioc_regs_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = ps3_ioc_reg_dump(instance, buf); + +l_out: + return ret; +} + +ssize_t ps3_max_scsi_cmds_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + instance->cmd_context.max_scsi_cmd_count); + +l_out: + return ret; +} +#endif +static ssize_t ps3_event_map_get(U32 event_type_map, char *buf, + ssize_t left_len) +{ + ssize_t len = 0; + U32 mask_bit = 0X00000001; + U32 idx = 0; + U32 event_type = event_type_map & mask_bit; + U32 line_cnt = 2; + + while (mask_bit != 0) { + if (event_type != 0) { + if (idx && (!(idx % line_cnt))) { + len += snprintf(buf + len, + left_len - len, "\n"); + } + + len += snprintf(buf + len, left_len - len, "\t%s", + ps3_event_print((MgrEvtType_e)event_type)); + } + + mask_bit = mask_bit << 1; + event_type = event_type_map & mask_bit; + idx++; + } + + len += snprintf(buf + len, left_len - len, "\n"); + return len; +} + +ssize_t ps3_event_subscribe_info_get(struct ps3_instance *instance, + char *buf, ssize_t total_len) +{ + ssize_t len = 0; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + struct PS3MgrEvent *event_req_info = NULL; + ULong flags = 0; + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + cmd = instance->event_context.event_cmd; + if (cmd != NULL) { + mgr_req_frame = (PS3MgrReqFrame_s *)cmd->req_frame; + event_req_info = + (struct PS3MgrEvent *)&mgr_req_frame->value.event; + + len += snprintf(buf + len, total_len - len, + "Event subscribe cmd index:\t%d\n", + cmd->index); + + len += snprintf(buf + len, total_len - len, + "Event subscribe level:\t%d\n", + event_req_info->eventLevel); + + len += snprintf(buf + len, total_len - len, + "Event subscribe type:\n"); + len += ps3_event_map_get(event_req_info->eventTypeMap, + buf + len, total_len - len); + + len += snprintf(buf + len, total_len - len, + "Event proc failed type:\n"); + len += ps3_event_map_get(event_req_info->eventTypeMapProcResult, + buf + len, total_len - len); + goto l_out; + } +l_out: + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + return len; +} +#ifndef _WINDOWS +ssize_t ps3_event_subscribe_info_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = ps3_event_subscribe_info_get(instance, buf, PAGE_SIZE); +l_out: + return ret; +} + +static ssize_t ps3_ioc_state_dump(struct ps3_instance *instance, char *buf) +{ + ssize_t len = 0; + ssize_t total_len = PAGE_SIZE; + + len += snprintf(buf + len, total_len - len, "%s\n", + ps3_ioc_state_print(instance->ioc_adpter->ioc_state_get(instance))); + + return len; +} + +ssize_t ps3_ioc_state_show(struct device *cdev, struct device_attribute *attr, + char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = ps3_ioc_state_dump(instance, buf); +l_out: + return ret; +} + +ssize_t ps3_log_level_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int level = 0; + ssize_t ret = count; + (void)attr; + + if (cdev == NULL || buf == NULL) { + goto l_out; + } + + if (kstrtoint(buf, 10, &level)) { + LOG_ERROR("invalid log level, could not set log level\n"); + ret = -EINVAL; + goto l_out; + } + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else + if (level > LEVEL_INFO) { + LOG_INFO("log level limited INFO\n"); + level = LEVEL_INFO; + } +#endif + + LOG_WARN("set log level to %d\n", level); + + ps3_level_set(level); +l_out: + return ret; +} + +ssize_t ps3_log_level_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + S32 level = ps3_level_get(); + (void)attr; + + if (cdev == NULL || buf == NULL) { + goto l_out; + } + ret = snprintf(buf, PAGE_SIZE, "%d\n", level); + + LOG_DEBUG("get log level to %d\n", level); +l_out: + return ret; +} + +ssize_t ps3_io_trace_switch_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + U8 trace_switch = 0; + ssize_t ret = count; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = count; + goto l_out; + } + + if (kstrtou8(buf, 10, &trace_switch)) { + LOG_ERROR("invalid io trace switch, could not set\n"); + ret = count; + goto l_out; + } + + instance->debug_context.io_trace_switch = trace_switch; + + LOG_WARN("set io trace switch is %d\n", + instance->debug_context.io_trace_switch); + +l_out: + return ret; +} + +ssize_t ps3_io_trace_switch_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + instance->debug_context.io_trace_switch); + + LOG_DEBUG("get io trace switch is %d\n", + instance->debug_context.io_trace_switch); +l_out: + return ret; +} + +ssize_t ps3_dump_state_show(struct device *cdev,struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_dump_context *ctxt = NULL; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ctxt = &instance->dump_context; + ret = snprintf(buf, PAGE_SIZE,"%d \n",ctxt->dump_state); +l_out: + return ret; +} + +ssize_t ps3_dump_state_store(struct device *cdev,struct device_attribute *attr, + const char *buf, size_t count) +{ + S32 val = 0; + S32 ret = 0; + struct ps3_dump_context *ctxt = NULL; + (void)attr; + + ctxt = dev_to_dump_context (cdev); + + if (kstrtoint(buf, 0, &val) != 0) { + ret = -EINVAL; + goto l_ret; + } + + if ((val != PS3_DUMP_STATE_INVALID) && (val != PS3_DUMP_STATE_ABORTED)) { + LOG_ERROR("hno:%u dump state should be %d or %d," + "%d is an invalid value\n",PS3_HOST(ctxt->instance), + PS3_DUMP_STATE_INVALID,PS3_DUMP_STATE_ABORTED,val); + ret = -EINVAL; + goto l_ret; + } + + if (ps3_dump_state_set(ctxt, val) != PS3_SUCCESS) { + ret = -EPERM; + goto l_ret; + } + + return count; +l_ret: + return ret; +} + +ssize_t ps3_product_model_show(struct device *cdev,struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, attr, buf); + (void)attr; + + if (instance == NULL) { + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%s\n", instance->product_model); +l_out: + return ret; +} + +ssize_t ps3_dump_dir_show(struct device *cdev,struct device_attribute *attr, char *buf) +{ + struct ps3_dump_context *ctxt; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + ssize_t ret = 0; + + if (instance == NULL) { + goto l_out; + } + + ctxt = &instance->dump_context; + + ret = snprintf(buf,PAGE_SIZE,"%s\n",ctxt->dump_dir); + +l_out: + return ret; +} + +S32 ps3_dump_dir_length( const char *buf, size_t count) +{ + S32 i = 0; + char c; + + while ((size_t)i++ < count) { + c = buf[i]; + + if (isdigit(c)) + continue; + + if (isalpha(c)) + continue; + + switch(c) { + case '-': + case '_': + case '/': + case '~': + continue; + break; + default: + goto l_out; + } + } + +l_out: + return i; +} + +#if 0 +ssize_t ps3_dump_dir_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ +#if 1 + LOG_INFO("set dump log dir is not supported\n"); + return 0; +#else + S32 ret = 0, length = 0; + struct ps3_dump_context *ctxt = NULL; + (void)attr; + + LOG_INFO("dir param %s\n", buf); + + ctxt = dev_to_dump_context (cdev); + + length = ps3_dump_dir_length(buf, count); + length = min(length, (S32)PS3_DUMP_FILE_DIR_LEN); + if (length <= 0 || count > PS3_DUMP_FILE_DIR_LEN) { + ret = -EINVAL; + LOG_ERROR("Invalid param %s\n", buf); + goto l_ret; + } + + ps3_mutex_lock(&ctxt->dump_lock); + memset(ctxt->dump_dir, 0, sizeof(ctxt->dump_dir)); + (void)strncpy((char*)ctxt->dump_dir, buf, length); + ps3_mutex_unlock(&ctxt->dump_lock); + + LOG_INFO("dump dir change to %s\n", ctxt->dump_dir); + + ret = count; + +l_ret: + return ret; +#endif +} +#endif + +ssize_t ps3_dump_type_show(struct device *cdev,struct device_attribute *attr, char *buf) +{ + struct ps3_dump_context *ctxt; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + ssize_t ret = 0; + + if (instance == NULL) { + goto l_out; + } + + ctxt = &instance->dump_context; + + ret = snprintf(buf,PAGE_SIZE,"%d \n",ctxt->dump_type); + +l_out: + return ret; +} + +ssize_t ps3_dump_type_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + S32 val = 0; + S32 ret = 0; + struct ps3_dump_context *ctxt = NULL; + Bool is_trigger_log = PS3_FALSE; + (void)attr; + + ctxt = dev_to_dump_context (cdev); + + if (kstrtoint(buf, 0, &val) != 0) { + ret = -EINVAL; + goto l_ret; + } + + if ((val < PS3_DUMP_TYPE_CRASH) || (val > PS3_DUMP_TYPE_BAR_DATA)) { + LOG_ERROR("host_no[%d],dump state should be %d - %d," + "%d is an invalid value\n", PS3_HOST(ctxt->instance), + PS3_DUMP_TYPE_CRASH, PS3_DUMP_TYPE_BAR_DATA, val); + ret = -EINVAL; + goto l_ret; + } + + ps3_ioc_dump_support_get(ctxt->instance); + is_trigger_log = ps3_dump_is_trigger_log(ctxt->instance); + INJECT_START(PS3_ERR_IJ_STORE_NO_TRIGGER_LOG, &is_trigger_log) + if(!is_trigger_log) { + LOG_INFO("cannot dump type set!\n"); + ret = -EBUSY; + goto l_ret; + } + + if (ps3_dump_type_set(ctxt, val, PS3_DUMP_ENV_CLI) == -PS3_FAILED) { + ret = -EBUSY; + goto l_ret; + } + return count; +l_ret: + return ret; +} + +void ps3_dma_dump_mapping(struct pci_dev *pdev) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) + dma_dump_mappings_cb dma_dump_mappings = NULL; + dma_dump_mappings = (dma_dump_mappings_cb) kallsyms_lookup_name("debug_dma_dump_mappings"); + if (dma_dump_mappings && pdev) { + printk(KERN_INFO "ps3 dma dump mapping begin\n"); + dma_dump_mappings(&pdev->dev); + printk(KERN_INFO "ps3 dma dump mapping end\n"); + } +#endif +#endif + (void)pdev; +} + +ssize_t ps3_soc_dead_reset_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + S32 val = 0; + S32 ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, attr, buf); + + (void)attr; + (void)count; + if (kstrtoint(buf, 0, &val) != 0) { + ret = -EINVAL; + goto l_ret; + } + if (ps3_atomic_read(&instance->state_machine.state) + != PS3_INSTANCE_STATE_DEAD) { + ret = -EPERM; + goto l_ret; + } + if (ps3_need_block_hard_reset_request(instance)) { + LOG_WARN("hno:%u can not start hard reset\n", + PS3_HOST(instance)); + } else { + ps3_hard_recovery_request_with_retry(instance); + } + + return count; +l_ret: + return ret; +} +ssize_t ps3_halt_support_cli_show(struct device *cdev,struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + instance->is_halt_support_cli); + + LOG_DEBUG("get halt_support_cli is %d\n", + instance->is_halt_support_cli); +l_out: + return ret; +} + +ssize_t ps3_halt_support_cli_store(struct device *cdev,struct device_attribute *attr, + const char *buf, size_t count) +{ + U8 halt_support_cli = 0; + Bool is_halt_support_cli; + ssize_t ret = count; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + + goto l_out; + } + + if (kstrtou8(buf, 10, &halt_support_cli)) { + ret = -EINVAL; + LOG_ERROR("invalid io halt_support_cli, could not set\n"); + goto l_out; + } + + is_halt_support_cli = (halt_support_cli == 0)?(0):(1); + instance->is_halt_support_cli = is_halt_support_cli; + + LOG_WARN("set halt_support_cli is %d\n", + instance->is_halt_support_cli); + +l_out: + return ret; +} + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else +ssize_t ps3_irq_prk_support_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int is_prk_in_irq= 0; + ssize_t ret = count; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (cdev == NULL || buf == NULL) { + goto l_out; + } + + if (kstrtoint(buf, 10, &is_prk_in_irq)) { + LOG_ERROR("invalid is_prk_in_irq, could not set is_prk_in_irq\n"); + ret = -EINVAL; + goto l_out; + } + + LOG_WARN("set is_prk_in_irq %d\n", is_prk_in_irq); + + instance->is_irq_prk_support = is_prk_in_irq; +l_out: + return ret; +} + +ssize_t ps3_irq_prk_support_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (cdev == NULL || buf == NULL) { + goto l_out; + } + ret = snprintf(buf, PAGE_SIZE, "%d\n", instance->is_irq_prk_support); + + LOG_DEBUG("get log level to %d\n", instance->is_irq_prk_support); +l_out: + return ret; +} +#endif + +ssize_t ps3_qos_switch_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = 0; + goto l_out; + } + + ret = snprintf(buf, PAGE_SIZE, "%d\n", + instance->qos_context.qos_switch); + +l_out: + return ret; +} + +ssize_t ps3_qos_switch_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count) +{ + U8 qos_switch = 0; + ssize_t ret = count; + struct ps3_instance *instance = ps3_debug_instance_query(cdev, + attr, buf); + + if (instance == NULL) { + ret = count; + goto l_out; + } + + if (kstrtou8(buf, 10, &qos_switch)) { + LOG_ERROR("invalid io trace switch, could not set\n"); + ret = count; + goto l_out; + } + + if (instance->qos_context.qos_switch > 0 && qos_switch == 0) { + instance->qos_context.qos_switch = 0; + ps3_qos_close(instance); + } + + if (instance->qos_context.qos_switch == 0 && qos_switch > 0) { + ps3_qos_open(instance); + instance->qos_context.qos_switch = qos_switch; + } + + LOG_WARN("set qos switch is %d\n", + instance->qos_context.qos_switch); + +l_out: + return ret; +} + +#endif diff --git a/drivers/scsi/ps3stor/ps3_debug.h b/drivers/scsi/ps3stor/ps3_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..fb9609714edc864c67134025e822ebfbc7c422d2 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_debug.h @@ -0,0 +1,151 @@ + +#ifndef _PS3_DEBUG_H_ +#define _PS3_DEBUG_H_ + +#ifndef _WINDOWS +#include +#include +#include + +struct ps3_reg_dump_attr { + U64 read_dump_timestamp; + U64 write_dump_timestamp; + U64 read_dump_interval_ms; + U64 write_dump_interval_ms; + U64 lastest_value; + S8 name[32]; +}; + +struct ps3_debug_context { + U8 io_trace_switch; + U8 reserved[7]; + struct ps3_reg_dump_attr reg_dump[PS3_REGISTER_SET_SIZE/sizeof(U64)]; + Ps3DebugMemEntry_s debug_mem_vaddr[PS3_DEBUG_MEM_ARRAY_MAX_NUM]; + Ps3DebugMemEntry_s *debug_mem_buf; + dma_addr_t debug_mem_buf_phy; + U32 debug_mem_array_num; + U8 reserved1[4]; +}; + +void ps3_debug_context_init(struct ps3_instance *instance); + +void ps3_reg_dump(struct ps3_instance *instance, + void __iomem *reg, U64 value, Bool is_read); + +ssize_t ps3_vd_io_outstanding_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_io_outstanding_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_is_load_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_dump_ioc_regs_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_max_scsi_cmds_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_event_subscribe_info_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_ioc_state_show(struct device *cdev, struct device_attribute *attr, + char *buf); + +ssize_t ps3_log_level_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count); + +ssize_t ps3_log_level_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_io_trace_switch_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count); + +ssize_t ps3_io_trace_switch_show(struct device *cdev, + struct device_attribute *attr, char *buf); +ssize_t ps3_halt_support_cli_show(struct device *cdev,struct device_attribute *attr, char *buf); + +ssize_t ps3_halt_support_cli_store(struct device *cdev,struct device_attribute *attr, + const char *buf, size_t count); + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#else +ssize_t ps3_irq_prk_support_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count); + +ssize_t ps3_irq_prk_support_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +#endif + +ssize_t ps3_product_model_show(struct device *cdev,struct device_attribute *attr, char *buf); + +ssize_t ps3_qos_switch_show(struct device *cdev, + struct device_attribute *attr, char *buf); + +ssize_t ps3_qos_switch_store(struct device *cdev, + struct device_attribute *attr, const char *buf, size_t count); + +#endif +ssize_t ps3_event_subscribe_info_get(struct ps3_instance *instance, char *buf, + ssize_t total_len); + +#ifndef _WINDOWS + +S32 ps3_debug_mem_alloc(struct ps3_instance *ins); + +S32 ps3_debug_mem_free(struct ps3_instance *ins); + +ssize_t ps3_dump_state_show(struct device *cdev,struct device_attribute *attr, char *buf); + +ssize_t ps3_dump_state_store(struct device *cdev,struct device_attribute *attr, + const char *buf, size_t count); + +ssize_t ps3_dump_type_show(struct device *cdev,struct device_attribute *attr, char *buf); + +ssize_t ps3_dump_type_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count); + +#if 0 +ssize_t ps3_dump_dir_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count); +#endif +ssize_t ps3_dump_dir_show(struct device *cdev,struct device_attribute *attr, char *buf); + +void ps3_dma_dump_mapping(struct pci_dev *pdev); + +ssize_t ps3_soc_dead_reset_store(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count); +#else + +struct ps3_reg_dump_attr { + U64 read_dump_timestamp; + U64 write_dump_timestamp; + U64 read_dump_interval_ms; + U64 write_dump_interval_ms; + U64 lastest_value; + S8 name[32]; +}; + +struct ps3_debug_context { + U8 io_trace_switch; + U8 reserved[7]; + struct ps3_reg_dump_attr reg_dump[PS3_REGISTER_SET_SIZE / sizeof(U64)]; + Ps3DebugMemEntry_s debug_mem_vaddr[PS3_DEBUG_MEM_ARRAY_MAX_NUM]; + Ps3DebugMemEntry_s* debug_mem_buf; + dma_addr_t debug_mem_buf_phy; + U32 debug_mem_array_num; + U8 reserved1[4]; +}; + +void ps3_debug_context_init(struct ps3_instance *instance); + +void ps3_reg_dump(struct ps3_instance *instance, + void __iomem* reg, U64 value, Bool is_read); + +#endif + +#endif diff --git a/drivers/scsi/ps3stor/ps3_device_manager.c b/drivers/scsi/ps3stor/ps3_device_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..96f500ef49dec0639023d3847f97c460762384f6 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_device_manager.c @@ -0,0 +1,2196 @@ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#endif + +#include "ps3_meta.h" +#include "ps3_dev_type.h" +#include "ps3_device_manager.h" +#include "ps3_cmd_statistics.h" +#include "ps3_mgr_cmd.h" +#include "ps3_ioc_manager.h" +#include "ps3_util.h" +#include "ps3_device_update.h" +#include "ps3_module_para.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_qos.h" + +static void ps3_nvme_attr_set(const struct ps3_instance *instance, + struct scsi_device *sdev); + +static S32 ps3_dev_channel_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U8 i = 0; + U16 vd_start = 0; + U16 pd_start = 0; + struct PS3ChannelInfo *channel_info = &instance->ctrl_info.channelInfo; + struct ps3_channel *pd_chan = instance->dev_context.channel_pd; + struct ps3_channel *vd_chan = instance->dev_context.channel_vd; + + memset(pd_chan, 0, + sizeof(struct ps3_channel) * PS3_MAX_CHANNEL_NUM); + memset(vd_chan, 0, + sizeof(struct ps3_channel) * PS3_MAX_CHANNEL_NUM); + + instance->dev_context.pd_channel_count = 0; + instance->dev_context.vd_channel_count = 0; + instance->dev_context.max_dev_per_channel = 0; + instance->dev_context.abort_vdpending_cmd = 0; + + for (i = 0; i < channel_info->channelNum; i++) { + LOG_INFO("hno:%u channel[%u] is type %s,max dev num is:%u\n", + PS3_HOST(instance), i, + namePS3ChannelType((enum PS3ChannelType) + channel_info->channels[i].channelType), + channel_info->channels[i].maxDevNum); + + if (channel_info->channels[i].maxDevNum > + instance->dev_context.max_dev_per_channel) { + instance->dev_context.max_dev_per_channel = + channel_info->channels[i].maxDevNum; + } + + if (channel_info->channels[i].channelType == + PS3_CHAN_TYPE_VD) { + vd_chan->channel = i; + vd_chan->max_dev_num = + channel_info->channels[i].maxDevNum; + vd_chan->channel_start_num = vd_start; + vd_start += vd_chan->max_dev_num; + instance->dev_context.max_dev_in_channel[i] = + vd_chan->max_dev_num; + + vd_chan++; + instance->dev_context.vd_channel_count++; + } else if (channel_info->channels[i].channelType == + PS3_CHAN_TYPE_PD) { + pd_chan->channel = i; + pd_chan->max_dev_num = + channel_info->channels[i].maxDevNum; + pd_chan->channel_start_num = pd_start; + pd_start += pd_chan->max_dev_num; + instance->dev_context.max_dev_in_channel[i] = + pd_chan->max_dev_num; + pd_chan++; + instance->dev_context.pd_channel_count++; + } + } + + if (instance->dev_context.max_dev_per_channel == 0) { + LOG_WARN("hno:%u total dev in channel == 0\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + + return ret; +} + +static void ps3_dev_buff_release(struct ps3_instance *instance) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + U8 i = 0; + + LOG_INFO("hno:%u release all device mgr buffer\n", + PS3_HOST(instance)); + + if (p_dev_ctx->pd_pool.devs_buffer != NULL) { + ps3_kfree(instance, p_dev_ctx->pd_pool.devs_buffer); + p_dev_ctx->pd_pool.devs_buffer = NULL; + } + + if (p_dev_ctx->vd_pri_data_table.vd_pri_data_idxs_array != NULL) { + ps3_vfree(instance, p_dev_ctx->vd_pri_data_table.vd_pri_data_idxs_array); + p_dev_ctx->vd_pri_data_table.vd_pri_data_idxs_array = NULL; + } + + if (p_dev_ctx->vd_pool.devs_buffer != NULL) { + ps3_kfree(instance, p_dev_ctx->vd_pool.devs_buffer); + p_dev_ctx->vd_pool.devs_buffer = NULL; + } + + if (p_dev_ctx->pd_table.pd_idxs_array != NULL) { + ps3_kfree(instance, p_dev_ctx->pd_table.pd_idxs_array); + p_dev_ctx->pd_table.pd_idxs_array = NULL; + } + + if (p_dev_ctx->pd_entries_array != NULL) { + ps3_kfree(instance, p_dev_ctx->pd_entries_array); + p_dev_ctx->pd_entries_array = NULL; + } + + for (i = 0; i < PS3_VD_TABLE_NUM; i++) { + if (p_dev_ctx->vd_table[i].vd_idxs_array != NULL) { + ps3_kfree(instance, p_dev_ctx->vd_table[i].vd_idxs_array); + p_dev_ctx->vd_table[i].vd_idxs_array = NULL; + } + + if (p_dev_ctx->vd_entries_array[i] != NULL) { + ps3_kfree(instance, p_dev_ctx->vd_entries_array[i]); + p_dev_ctx->vd_entries_array[i] = NULL; + } + } +} + +static S32 ps3_vd_buff_alloc(struct ps3_instance *instance) +{ + U8 i = 0; + U8 j = 0; + struct ps3_channel *p_chan = NULL; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_dev_pool *vd_pool = &p_dev_ctx->vd_pool; + struct ps3_vd_table *p_vd_table = p_dev_ctx->vd_table; + struct ps3_pri_data_table *p_vd_pri_data_table = &p_dev_ctx->vd_pri_data_table; + + p_dev_ctx->subwork = 0; + p_dev_ctx->total_vd_count = 0; + if (p_dev_ctx->vd_channel_count > 0) { + p_chan = &p_dev_ctx->channel_vd[p_dev_ctx->vd_channel_count-1]; + p_dev_ctx->total_vd_count = p_chan->channel_start_num + + p_chan->max_dev_num; + } + + for (i = 0; i < PS3_VD_TABLE_NUM; i++) { + p_vd_table[i].vd_idxs_array = (U16*)ps3_kzalloc(instance, sizeof(U16) * + p_dev_ctx->total_vd_count); + INJECT_START(PS3_ERR_IJ_PS3_VD_IDX_ARRAY_ALLOC, &p_vd_table[i].vd_idxs_array); + if (p_vd_table[i].vd_idxs_array == NULL) { + LOG_ERROR("hno:%u, Failed to allocate VD table %d buffer\n", + PS3_HOST(instance), i); + goto free_dev_buff; + } + + p_dev_ctx->vd_entries_array[i] = (struct PS3VDEntry*) + ps3_kzalloc(instance, sizeof(struct PS3VDEntry) * + (PS3_MAX_VD_COUNT(instance) + 1)); + INJECT_START(PS3_ERR_IJ_PS3_VD_ENTRIES_ARRAY_ALLOC, &p_dev_ctx->vd_entries_array[i]); + if (p_dev_ctx->vd_entries_array[i] == NULL) { + LOG_ERROR("hno:%u, Failed to allocate VD entry buffer\n", + PS3_HOST(instance)); + goto free_dev_buff; + } + } + + vd_pool->devs_buffer = (union PS3Device*)ps3_kzalloc(instance, + sizeof(union PS3Device) * p_dev_ctx->total_vd_count); + INJECT_START(PS3_ERR_IJ_PS3_VD_DEVS_BUF_ALLOC, &vd_pool->devs_buffer); + if (vd_pool->devs_buffer == NULL) { + LOG_ERROR("hno:%u Failed to allocate VD pool buffer\n", + PS3_HOST(instance)); + goto free_dev_buff; + } + + memset(vd_pool->devs_buffer, 0, sizeof(union PS3Device) * p_dev_ctx->total_vd_count); + + p_vd_pri_data_table->vd_pri_data_idxs_array = + (struct ps3_scsi_priv_data**)ps3_vzalloc(instance, + sizeof(struct ps3_scsi_priv_data*) * p_dev_ctx->total_vd_count); + INJECT_START(PS3_ERR_IJ_PS3_VD_PRI_DATA_IDXS_ARRAY_ALLOC, &p_vd_pri_data_table->vd_pri_data_idxs_array); + if (p_vd_pri_data_table->vd_pri_data_idxs_array == NULL) { + LOG_ERROR("hno:%u, Failed to allocate VD R1X table %d buffer\n", + PS3_HOST(instance), i); + goto free_dev_buff; + } + + memset(p_vd_pri_data_table->vd_pri_data_idxs_array, 0, + sizeof(struct ps3_scsi_priv_data*) * p_dev_ctx->total_vd_count); + + p_chan = p_dev_ctx->channel_vd; + for (i = 0; i < p_dev_ctx->vd_channel_count; i++) { + vd_pool->devs[p_chan->channel] = + &vd_pool->devs_buffer[p_chan->channel_start_num]; + + p_vd_pri_data_table->vd_pri_data_idxs[p_chan->channel] = + &p_vd_pri_data_table->vd_pri_data_idxs_array[p_chan->channel_start_num]; + + for (j = 0; j < PS3_VD_TABLE_NUM; j++) { + p_vd_table[j].vd_idxs[p_chan->channel] = + &p_vd_table[j].vd_idxs_array[p_chan->channel_start_num]; + } + + p_chan++; + } + + return PS3_SUCCESS; +free_dev_buff: + ps3_dev_buff_release(instance); + + return -PS3_ENOMEM; +} + +static S32 ps3_pd_buff_alloc(struct ps3_instance *instance) +{ + U8 i = 0; + struct ps3_channel *p_chan = NULL; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_dev_pool *pd_pool = &p_dev_ctx->pd_pool; + struct ps3_pd_table *pd_table = &p_dev_ctx->pd_table; + + p_dev_ctx->total_pd_count = 0; + if (p_dev_ctx->pd_channel_count > 0) { + p_chan = &p_dev_ctx->channel_pd[p_dev_ctx->pd_channel_count - 1]; + p_dev_ctx->total_pd_count = p_chan->channel_start_num + + p_chan->max_dev_num; + } + + p_dev_ctx->pd_entries_array = (struct ps3_pd_entry*) + ps3_kzalloc(instance, sizeof(struct ps3_pd_entry) * + (PS3_MAX_PD_COUNT(instance) + 1)); + INJECT_START(PS3_ERR_IJ_PS3_PD_ENTRIES_ARRAY_ALLOC, &p_dev_ctx->pd_entries_array); + if (p_dev_ctx->pd_entries_array == NULL) { + LOG_ERROR("hno:%u, Failed to allocate PD entry buffer\n", + PS3_HOST(instance)); + goto free_dev_pool; + } + + pd_table->pd_idxs_array = (U16*)ps3_kzalloc(instance, sizeof(U16) * + p_dev_ctx->total_pd_count); + INJECT_START(PS3_ERR_IJ_PS3_PD_IDX_ARRAY_ALLOC, &pd_table->pd_idxs_array); + if (pd_table->pd_idxs_array == NULL) { + LOG_ERROR("hno:%u, Failed to allocate PD table buffer\n", + PS3_HOST(instance)); + goto free_dev_pool; + } + + pd_pool->devs_buffer = (union PS3Device*)ps3_kzalloc(instance, + sizeof(union PS3Device) * p_dev_ctx->total_pd_count); + INJECT_START(PS3_ERR_IJ_PS3_PD_DEVS_BUF_ALLOC, &pd_pool->devs_buffer); + if (pd_pool->devs_buffer == NULL) { + LOG_ERROR("hno:%u, Failed to allocate PD pool buffer\n", + PS3_HOST(instance)); + goto free_dev_pool; + } + + p_chan = p_dev_ctx->channel_pd; + for (i = 0; i < p_dev_ctx->pd_channel_count; i++) { + pd_pool->devs[p_chan->channel] = + &pd_pool->devs_buffer[p_chan->channel_start_num]; + pd_table->pd_idxs[p_chan->channel] = + &pd_table->pd_idxs_array[p_chan->channel_start_num]; + p_chan++; + } + + return PS3_SUCCESS; +free_dev_pool: + ps3_dev_buff_release(instance); + + return -PS3_ENOMEM; +} + +static S32 ps3_dev_buff_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + LOG_INFO("hno:%u buff alloc pd count %d, vd count %d\n", + PS3_HOST(instance), PS3_MAX_PD_COUNT(instance), PS3_MAX_VD_COUNT(instance)); + + if (PS3_MAX_VD_COUNT(instance) > 0) { + ret = ps3_vd_buff_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + } + + if (PS3_MAX_PD_COUNT(instance) > 0) { + ret = ps3_pd_buff_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + } + +l_out: + return ret; +} + +static inline U16 ps3_pd_dma_alignment_calc(U8 align_shift) +{ + return align_shift ? 1 << align_shift : 0; +} + +static inline U8 ps3_pd_type_localed(const struct PS3PDInfo *pd_info) +{ + U8 dev_type = PS3_DEV_TYPE_UNKNOWN; + + dev_type = ps3_get_converted_dev_type(pd_info->driverType, pd_info->mediumType); + + if (unlikely(dev_type == PS3_DEV_TYPE_UNKNOWN)) { + LOG_ERROR("pd[%u:%u:%u], magic_num[%#x], driver_type[%s], medium_type[%s], dev_type is unknown\n", + PS3_CHANNEL(&pd_info->diskPos), PS3_TARGET(&pd_info->diskPos), + PS3_PDID(&pd_info->diskPos), pd_info->diskPos.diskMagicNum, + getDriverTypeName((DriverType_e)pd_info->driverType), + getMediumTypeName((MediumType_e)pd_info->mediumType)); + PS3_BUG(); + } else { + LOG_INFO("pd[%u:%u:%u], magic_num[%#x], driver_type[%s], medium_type[%s], dev_type[%s]\n", + PS3_CHANNEL(&pd_info->diskPos), PS3_TARGET(&pd_info->diskPos), + PS3_PDID(&pd_info->diskPos), pd_info->diskPos.diskMagicNum, + getDriverTypeName((DriverType_e)pd_info->driverType), + getMediumTypeName((MediumType_e)pd_info->mediumType), + namePS3DevType((enum PS3DevType)dev_type)); + } + return dev_type; +} + +void ps3_vd_info_show(const struct ps3_instance *instance, + const struct PS3VDEntry *vd_entry) +{ + U8 i = 0; + U8 j = 0; + U8 channel = (U8)PS3_CHANNEL(&vd_entry->diskPos); + U16 target_id = PS3_TARGET(&vd_entry->diskPos); + U16 vd_id = PS3_VDID(&vd_entry->diskPos); + + LOG_INFO_IN_IRQ(instance, + "hno:%u disk detail info - vd[%u:%u:%u], magicNum[%#x], " + "dev_type: PS3_DEV_TYPE_VD, isHidden[%s], " + "accessPolicy[%s], diskGrpId[%u], sectorSize[%u], " + "stripeDataSize[%u], physDrvCnt[%u], stripSize[%u], " + "isDirectEnable[%s], raidLevel[%u], spanCount[%u], " + "diskState[%u], startLBA[%llu], extentSize[%llu], " + "isTaskMgmtEnable[%u], taskAbortTimeout[%u], " + "taskResetTimeout[%u], mapBlock[%llu], mapBlockVer[%u], " + "maxIOSize[%u], devQueDepth[%u], capacity[%llu], isNvme[%u], isSsd[%u], virtDiskSeq[%d], " + "bdev_bdi_cap[%d], umapBlkDescCnt[%d], umapNumblk[%d], normalQuota[%u], directQuota[%u], " + "dev_busy_scale[%u]\n" + , PS3_HOST(instance), channel, target_id, vd_id, + vd_entry->diskPos.diskMagicNum, + (vd_entry->isHidden) ? "true" : "false", + ps3_get_vd_access_plolicy_str((VDAccessPolicy_e)vd_entry->accessPolicy), + vd_entry->diskGrpId, + vd_entry->sectorSize, vd_entry->stripeDataSize, + vd_entry->physDrvCnt, vd_entry->stripSize, + (vd_entry->isDirectEnable) ? "true" : "false", + vd_entry->raidLevel, + vd_entry->spanCount, vd_entry->diskState, + vd_entry->startLBA, vd_entry->extentSize, + vd_entry->isTaskMgmtEnable, vd_entry->taskAbortTimeout, + vd_entry->taskResetTimeout, vd_entry->mapBlock, + vd_entry->mapBlockVer, vd_entry->maxIOSize, + vd_entry->devQueDepth, vd_entry->capacity, vd_entry->isNvme, + vd_entry->isSsd, vd_entry->virtDiskSeq, vd_entry->bdev_bdi_cap, + vd_entry->umapBlkDescCnt, vd_entry->umapNumblk, + vd_entry->normalQuota, vd_entry->directQuota, + vd_entry->dev_busy_scale); + + for (i = 0; i < vd_entry->spanCount; i++) { + LOG_INFO_IN_IRQ(instance, + "hno:%u vd[%u:%u:%u]----span[%u]----" + "spanStripeDataSize[%u], spanState[%u], spanPdNum[%u]\n" + , PS3_HOST(instance), channel, target_id, vd_id, i, + vd_entry->span[i].spanStripeDataSize, + vd_entry->span[i].spanState, + vd_entry->span[i].spanPdNum); + + for (j = 0; j < vd_entry->span[i].spanPdNum; j++) { + LOG_INFO_IN_IRQ(instance, + "hno:%u vd[%u:%u:%u]----span[%u]." + "extent[%u]----pd:[%u:%u:%u], state[%u]\n" + , PS3_HOST(instance), channel, target_id, vd_id, i, j, + vd_entry->span[i].extent[j].phyDiskID.ps3Dev.softChan, + vd_entry->span[i].extent[j].phyDiskID.ps3Dev.devID, + vd_entry->span[i].extent[j].phyDiskID.ps3Dev.phyDiskID, + vd_entry->span[i].extent[j].state); + } + } +} + +static void ps3_pd_info_show(const struct ps3_instance *instance, + const struct ps3_pd_entry *pd_entry) +{ + LOG_INFO("hno:%u disk detail info - pd[%u:%u:%u], magicNum[%#x], " + "state[%s], dev_type[%s], config_flag[%s], pd_flags[0x%02x]" + "RWCT[%u], scsi_interface_type[%u], " + "task_abort_timeout[%u], task_reset_timeout[%u], " + "max_io_size[%u], dev_queue_depth[%u], " + "sector_size[%u], encl_id[%u], pd phy_id[%u], " + "dma_addr_alignment[%u], dma_len_alignment[%u]" + "normal_quota[%u] direct_quota[%u] is_direct_disable[%u]\n" + , PS3_HOST(instance), + PS3_CHANNEL(&pd_entry->disk_pos), + PS3_TARGET(&pd_entry->disk_pos), + PS3_PDID(&pd_entry->disk_pos), + pd_entry->disk_pos.diskMagicNum, + getDeviceStateName((DeviceState_e)pd_entry->state), + namePS3DevType((enum PS3DevType)pd_entry->dev_type), + getPdStateName((MicPdState_e)pd_entry->config_flag, instance->is_raid), pd_entry->pd_flags, + pd_entry->RWCT, pd_entry->scsi_interface_type, + pd_entry->task_abort_timeout, pd_entry->task_reset_timeout, + pd_entry->max_io_size, pd_entry->dev_queue_depth, + pd_entry->sector_size, pd_entry->encl_id, + pd_entry->phy_id, pd_entry->dma_addr_alignment, + pd_entry->dma_len_alignment, + pd_entry->normal_quota, pd_entry->direct_quota, pd_entry->is_direct_disable + ); +} + +static inline void ps3_pd_info_localed(const struct ps3_instance *instance, + struct ps3_pd_entry *local_entry, const struct PS3PDInfo *pd_info) +{ + local_entry->disk_pos = pd_info->diskPos; + local_entry->dev_type = ps3_pd_type_localed(pd_info); + local_entry->scsi_interface_type = pd_info->scsiInterfaceType; + local_entry->state = pd_info->diskState; + local_entry->task_abort_timeout = pd_info->taskAbortTimeout; + local_entry->task_reset_timeout = pd_info->taskResetTimeout; + local_entry->config_flag = pd_info->configFlag; + local_entry->pd_flags = pd_info->pdFlags; + local_entry->max_io_size = pd_info->maxIOSize; + local_entry->dev_queue_depth = pd_info->devQueDepth; + local_entry->sector_size = pd_info->sectorSize; + local_entry->is_direct_disable = pd_info->isDirectDisable; + local_entry->encl_id = pd_info->enclId; + local_entry->phy_id = pd_info->phyId; + local_entry->dma_addr_alignment = ps3_pd_dma_alignment_calc(pd_info->dmaAddrAlignShift); + local_entry->dma_len_alignment = ps3_pd_dma_alignment_calc(pd_info->dmaLenAlignShift); + local_entry->normal_quota = pd_info->normalQuota; + local_entry->direct_quota = pd_info->directQuota; + + if (unlikely(local_entry->sector_size == 0)) { + LOG_WARN("pd[%u:%u] sector_size is 0\n", + PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos)); + } + + ps3_pd_info_show(instance, local_entry); +} + +S32 ps3_dev_mgr_pd_info_get(struct ps3_instance *instance, U16 channel, + U16 target_id, U16 pd_id) +{ + S32 ret = PS3_SUCCESS; + struct PS3PDInfo *pd_info = NULL; + struct ps3_dev_context *dev_ctx = &instance->dev_context; + + LOG_DEBUG("hno:%u, get PD info [%u:%u:%u] start\n", + PS3_HOST(instance), channel, target_id, pd_id); + + ret = ps3_pd_info_get(instance, channel, target_id, pd_id); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL6, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, get single PD info [%u:%u:%u] NOK\n", + PS3_HOST(instance), channel, target_id, pd_id); + goto l_out; + } + + pd_info = dev_ctx->pd_info_buf; + INJECT_START(PS3_ERR_IJ_FORCE_MOD_DISKPOS1, &pd_info->diskPos.diskDev.diskID); + if (PS3_PDID_INVALID(&pd_info->diskPos)) { + LOG_WARN("hno:%u, cannot found PD info [%u:%u:%u]\n", + PS3_HOST(instance), channel, target_id, pd_id); + ret = -PS3_FAILED; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_MOD_ALIGN, &pd_info->dmaAddrAlignShift); + if (pd_info->dmaAddrAlignShift > + PS3_DMA_ALIGN_SHIFT_MAX) { + LOG_WARN("hno:%u PD info [%u:%u:%u] invalid dmaAddrAlignShift\n", + PS3_HOST(instance), channel, target_id, PS3_PDID(&pd_info->diskPos)); + ret = -PS3_FAILED; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_MOD_ALIGN1, &pd_info->dmaLenAlignShift); + if (pd_info->dmaLenAlignShift > + PS3_DMA_ALIGN_SHIFT_MAX) { + LOG_WARN("hno:%u PD info [%u:%u:%u] invalid dmalenAlignShift\n", + PS3_HOST(instance), channel, target_id, PS3_PDID(&pd_info->diskPos)); + ret = -PS3_FAILED; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_MOD_CHAN2, &channel); + if (unlikely(PS3_CHANNEL(&pd_info->diskPos) != channel || + PS3_TARGET(&pd_info->diskPos) != target_id)) { + LOG_ERROR("hno:%u PD info get [%u:%u:%u]!=[%u:%u:%u] magic[%#x] unmatched\n", + PS3_HOST(instance), channel, target_id, pd_id, + PS3_CHANNEL(&pd_info->diskPos), + PS3_TARGET(&pd_info->diskPos), + PS3_PDID(&pd_info->diskPos), + pd_info->diskPos.diskMagicNum); + PS3_BUG(); + ret = -PS3_FAILED; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_MOD_DISKID, &PS3_PDID(&pd_info->diskPos)); + if (unlikely(PS3_PDID(&pd_info->diskPos) > PS3_MAX_PD_COUNT(instance))) { + LOG_ERROR("hno:%u init pd info NOK, pd_id[%d] > max[%d]\n", + PS3_HOST(instance), + PS3_PDID(&pd_info->diskPos), PS3_MAX_PD_COUNT(instance)); + + PS3_BUG(); + ret = -PS3_FAILED; + goto l_out; + } + + ps3_pd_info_localed(instance, &dev_ctx->pd_entries_array[ + PS3_PDID(&pd_info->diskPos)], pd_info); + dev_ctx->pd_table.pd_idxs[channel][target_id] = + PS3_PDID(&pd_info->diskPos); +l_out: + return ret; +} + +static void ps3_pd_info_get_all(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U16 i = 0; + U16 j = 0; + U8 chan_id = 0; + + struct ps3_channel *pd_chan = instance->dev_context.channel_pd; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_pd_table *p_table = &p_dev_ctx->pd_table; + struct ps3_dev_pool *p_pd_pool = &p_dev_ctx->pd_pool; + + memset(p_table->pd_idxs_array, PS3_INVALID_VALUE, + p_dev_ctx->total_pd_count * sizeof(U16)); + + for (i = 0; i < p_dev_ctx->pd_channel_count; i++) { + chan_id = pd_chan[i].channel; + for (j = 0; j < pd_chan[i].max_dev_num; j++) { + if (PS3_PDID_INVALID(&p_pd_pool->devs[chan_id][j].pd.diskPos)) { + continue; + } + + ret = ps3_dev_mgr_pd_info_get(instance, chan_id, j, + PS3_PDID(&p_pd_pool->devs[chan_id][j].pd.diskPos)); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, get PD[%u:%u] info NOK\n", + PS3_HOST(instance), chan_id, j); + } + } + } +} + +S32 ps3_dev_mgr_vd_info_subscribe(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + LOG_FILE_INFO("hno:%u ps3_dev_mgr_vd_info_subscribe\n", PS3_HOST(instance)); + + if (PS3_MAX_VD_COUNT(instance) <= 0) { + goto l_out; + } + + ret = ps3_vd_info_async_get(instance); + if (ret != PS3_SUCCESS) { + LOG_FILE_ERROR("hno:%u async get VD info failed\n", + PS3_HOST(instance)); + } +l_out: + return ret; +} + +S32 ps3_dev_mgr_vd_info_unsubscribe(struct ps3_instance *instance) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + cmd = instance->dev_context.vd_pending_cmd; + if (cmd == NULL) { + LOG_WARN("hno:%u vd pending cmd has been cancel\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u who steal free this cmd,CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->dev_context.vd_pending_cmd = NULL; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + if (ps3_atomic_add_unless(&instance->dev_context.is_vdpending_abort, 1, 1) == 0) { + ret = PS3_SUCCESS; + goto l_out; + } + + ret = ps3_mgr_cmd_cancel_send(instance, cmd->index, PS3_CANCEL_VDPENDING_CMD); + INJECT_START(PS3_ERR_IJ_CANCEL_VDPENDING_CMD_FAIL, &ret) + if(ret == -PS3_ENOMEM){ + LOG_INFO("hno:%u alloc failed\n",PS3_HOST(instance)); + ret = PS3_FAILED; + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + goto l_out; + }else if(ret != PS3_SUCCESS){ + LOG_INFO("hno:%u reqFrameId=%d cancel_cmd_frame_id[%u] free!\n", + PS3_HOST(instance), ps3_cmd_frame_id(instance->dev_context.vdpending_abort_cmd), cmd->index); + abort_cmd = instance->dev_context.vdpending_abort_cmd; + instance->dev_context.vdpending_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + ret = PS3_FAILED; + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + goto l_out; + } + + ret = ps3_mgr_cmd_cancel_wait(instance, PS3_CANCEL_VDPENDING_CMD); + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_VD_PENDING_FAILED, &ret) + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u unsubscribe vd pending, cancel cmd NOK\n", + PS3_HOST(instance)); + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + goto l_out; + } + + LOG_INFO("hno:%u vd pending cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->dev_context.vd_pending_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + +l_out: + return ret; +} +S32 ps3_dev_mgr_vd_info_resubscribe(struct ps3_instance *instance) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + ULong flags1 = 0; + Bool is_need_resend = PS3_FALSE; + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + cmd = instance->dev_context.vd_pending_cmd; + if (cmd == NULL) { + LOG_WARN("hno:%u vd pending cmd has been cancel\n", + PS3_HOST(instance)); + is_need_resend = PS3_TRUE; + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + goto l_resend; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u free vdpending cmd,CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->dev_context.vd_pending_cmd = NULL; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + if (ps3_atomic_add_unless(&instance->dev_context.is_vdpending_abort, 1, 1) == 0) { + ret = PS3_SUCCESS; + goto l_out; + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + ret = ps3_mgr_cmd_cancel_send(instance, cmd->index, PS3_CANCEL_VDPENDING_CMD); + if(ret == -PS3_ENOMEM){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u alloc failed\n",PS3_HOST(instance)); + ret = -PS3_FAILED; + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + goto l_out; + }else if(ret != PS3_SUCCESS){ + LOG_FILE_INFO("hno:%u reqFrameId=%d cancel_cmd_frame_id[%u] free!\n", + PS3_HOST(instance), ps3_cmd_frame_id(instance->dev_context.vdpending_abort_cmd), cmd->index); + abort_cmd = instance->dev_context.vdpending_abort_cmd; + instance->dev_context.vdpending_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + ret = -PS3_FAILED; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + goto l_out; + } + instance->dev_context.abort_vdpending_cmd = 1; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + + ret = ps3_mgr_cmd_cancel_wait(instance, PS3_CANCEL_VDPENDING_CMD); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u unsubscribe vd pending, cancel cmd NOK\n", + PS3_HOST(instance)); + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); + goto l_out; + } + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if(instance->dev_context.subwork == 0){ + if(instance->dev_context.abort_vdpending_cmd != 0){ + instance->dev_context.abort_vdpending_cmd = 0; + LOG_FILE_INFO("hno:%u vd pending cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->dev_context.vd_pending_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + is_need_resend = PS3_TRUE; + } + } + ps3_atomic_set(&instance->dev_context.is_vdpending_abort, 0); +l_resend: + if (is_need_resend) { + ret = ps3_dev_mgr_vd_info_subscribe(instance); + if (ret != PS3_SUCCESS) { + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + goto l_out; + } + } + + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + +l_out: + return ret; +} + +void ps3_dev_mgr_vd_info_clear(struct ps3_instance *instance) +{ + ULong flags = 0; + ULong flags1 = 0; + struct ps3_cmd *cmd = NULL; + instance->dev_context.abort_vdpending_cmd = 0; + + cmd = instance->dev_context.vd_pending_cmd; + + if (cmd == NULL) { + LOG_WARN("hno:%u vd pending cmd has been cancel\n", + PS3_HOST(instance)); + goto l_out; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_INFO("hno:%u free this cmd,CFID:%d\n", + PS3_HOST(instance), cmd->index); + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + instance->dev_context.vd_pending_cmd = NULL; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + LOG_INFO("hno:%u vd pending cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->dev_context.vd_pending_cmd = NULL; + instance->dev_context.subwork = 0; + + ps3_mgr_cmd_free(instance, cmd); + +l_out: + return; +} + +#ifndef _WINDOWS +void ps3_change_sdev_max_sector(struct ps3_instance *instance, + struct PS3VDEntry *vd_entry) +{ + struct scsi_device *sdev = NULL; + struct PS3Dev *p_vd = &vd_entry->diskPos.diskDev.ps3Dev; + + sdev = ps3_scsi_device_lookup(instance, p_vd->softChan, + p_vd->devID, 0); + if (sdev != NULL) { + if (vd_entry->sectorSize == PS3_SECTORSIZE_512B) { + blk_queue_max_hw_sectors(sdev->request_queue, vd_entry->maxIOSize); + } else { + blk_queue_max_hw_sectors(sdev->request_queue, + vd_entry->maxIOSize << (ilog2(vd_entry->sectorSize) - PS3_512B_SHIFT)); + } + + LOG_INFO_IN_IRQ(instance, + "hno:%u vd[%u:%u] max sector num change to:%d\n", + PS3_HOST(instance), p_vd->softChan, p_vd->devID, + vd_entry->maxIOSize); + + ps3_scsi_device_put(instance, sdev); + } +} +#endif +S32 ps3_vd_info_get_all(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + U16 i = 0; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + U8 vd_table_idx = (p_dev_ctx->vd_table_idx + 1) & 1; + struct ps3_vd_table *p_vd_table = + &p_dev_ctx->vd_table[vd_table_idx]; + struct PS3VDEntry *p_vd_array = + p_dev_ctx->vd_entries_array[vd_table_idx]; + struct PS3VDEntry *p_vd_entry = + p_dev_ctx->vd_info_buf_sync->vds; + struct PS3Dev *p_dev = NULL; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + if (PS3_MAX_VD_COUNT(instance) == 0) { + LOG_INFO("hno:%u vd max count is %d\n", + PS3_HOST(instance), PS3_MAX_VD_COUNT(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + if (p_dev_ctx->vd_list_buf->count == 0) { + LOG_INFO("hno:%u vd list count is 0\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ret = ps3_vd_info_sync_get(instance, 0, PS3_MAX_VD_COUNT(instance)); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, sync get VD info NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + memset(p_vd_table->vd_idxs_array, 0, + p_dev_ctx->total_vd_count * sizeof(U16)); + + LOG_INFO("hno:%u get vd info count is %d\n", + PS3_HOST(instance),p_dev_ctx->vd_info_buf_sync->count); + + for (i = 0; i < p_dev_ctx->vd_info_buf_sync->count; i++) { + if (PS3_VDID_INVALID(&p_vd_entry[i].diskPos)) { + LOG_WARN("hno:%u, init %d of %d vd info NOK, vdid is 0\n", + PS3_HOST(instance), i, + p_dev_ctx->vd_info_buf_sync->count); + continue; + } + + p_dev = PS3_DEV(&p_vd_entry[i].diskPos); + + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), p_dev->virtDiskID); + if (!ps3_dev_id_valid_check(instance, (U8)p_dev->softChan, + p_dev->devID, PS3_DISK_TYPE_VD)) { + PS3_BUG(); + continue; + } + + if (unlikely(virtDiskIdx > PS3_MAX_VD_COUNT(instance))) { + LOG_ERROR("hno:%u init %d of %d vd info NOK, vir_id[%d] > max[%d]\n", + PS3_HOST(instance),i, + p_dev_ctx->vd_info_buf_sync->count-1, + virtDiskIdx, PS3_MAX_VD_COUNT(instance)); + + PS3_BUG(); + continue; + } + ps3_vd_busy_scale_get(&p_vd_entry[i]); + memcpy(&p_vd_array[virtDiskIdx], &p_vd_entry[i], + sizeof(struct PS3VDEntry)); + p_vd_table->vd_idxs[p_dev->softChan][p_dev->devID] = p_dev->virtDiskID; + + ps3_vd_info_show(instance, &p_vd_array[virtDiskIdx]); +#ifndef _WINDOWS + if (p_vd_entry[i].maxIOSize != 0) { + ps3_change_sdev_max_sector(instance, &p_vd_entry[i]); + } +#endif + } + mb(); + p_dev_ctx->vd_table_idx = vd_table_idx; + mb(); +l_out: + return ret; +} + +S32 ps3_device_mgr_data_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + LOG_DEBUG("hno:%u enter\n", + PS3_HOST(instance)); + + if (PS3_MAX_PD_COUNT(instance) != 0) { + ret = ps3_dev_mgr_pd_list_get(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + ps3_pd_info_get_all(instance); + } + + if (PS3_MAX_VD_COUNT(instance) != 0) { + ret = ps3_dev_mgr_vd_list_get(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + instance->dev_context.vd_table_idx = 0; + ps3_vd_info_get_all(instance); + } +l_out: + LOG_DEBUG("hno:%u out\n", + PS3_HOST(instance)); + + return ret ; +} + +S32 ps3_device_mgr_data_exit(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + LOG_DEBUG("hno:%u \n", PS3_HOST(instance)); + + return ret; +} + +S32 ps3_device_mgr_init(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + + if (PS3_MAX_VD_COUNT(instance) == 0 && + PS3_MAX_PD_COUNT(instance) == 0) { + LOG_ERROR("hno:%u max VD and PD count == 0\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + ret = ps3_dev_channel_init(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + ret = ps3_dev_buff_alloc(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + ps3_mutex_init(&instance->dev_context.dev_priv_lock); + ps3_mutex_init(&instance->dev_context.dev_scan_lock); +#ifdef _WINDOWS + ps3_windows_channel_map_init(instance); + ret = ps3_windows_private_init(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } +#endif + +l_out: + return ret ; +} + +void ps3_device_mgr_exit(struct ps3_instance *instance) +{ +#ifdef _WINDOWS + ps3_windows_private_exit(instance); +#endif + ps3_dev_buff_release(instance); + ps3_mutex_destroy(&instance->dev_context.dev_priv_lock); + ps3_mutex_destroy(&instance->dev_context.dev_scan_lock); +} + +S32 ps3_dev_mgr_pd_list_get(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct PS3DevList *p_pd_list = p_dev_ctx->pd_list_buf; + struct PS3Dev *p_dev = NULL; + + ret = ps3_pd_list_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, dev mgr get pd list NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + memset((U8*)p_dev_ctx->pd_pool.devs_buffer, PS3_INVALID_VALUE, + p_dev_ctx->total_pd_count * sizeof(union PS3Device)); + + LOG_INFO("hno:%u get pd list count is %d\n", + PS3_HOST(instance), p_pd_list->count); + + for (i = 0; i < p_pd_list->count; i++) { + p_dev = PS3_DEV(&p_pd_list->devs[i].pd.diskPos); + + if (PS3_PDID_INVALID(&p_pd_list->devs[i].pd.diskPos)) { + LOG_WARN("hno:%u, get pd list %d dev pdid is 0\n", + PS3_HOST(instance), i); + continue; + } + + if (!ps3_dev_id_valid_check(instance, (U8)p_dev->softChan, + p_dev->devID, PS3_DISK_TYPE_PD)) { + PS3_BUG(); + continue; + } + + LOG_INFO("hno:%u, pd list %d dev[%u:%u:%u], magic[%#x], state[%s]\n", + PS3_HOST(instance), i, p_dev->softChan, p_dev->devID, + p_dev->phyDiskID, + p_pd_list->devs[i].pd.diskPos.diskMagicNum, + getDeviceStateName((DeviceState_e)p_pd_list->devs[i].pd.diskState)); + + p_dev_ctx->pd_pool.devs[p_dev->softChan][p_dev->devID].pd = + p_pd_list->devs[i].pd; + + } +l_out: + return ret; +} + +S32 ps3_dev_mgr_vd_list_get(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct PS3DevList *p_vd_list = p_dev_ctx->vd_list_buf; + struct PS3Dev *p_dev = NULL; + + ret = ps3_vd_list_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, dev mgr get vd list NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + memset((U8*)p_dev_ctx->vd_pool.devs_buffer, PS3_INVALID_VALUE, + p_dev_ctx->total_vd_count * sizeof(union PS3Device)); + + LOG_INFO("hno:%u get vd list count is %d\n", + PS3_HOST(instance), p_vd_list->count); + + for (i = 0; i < p_vd_list->count; i++) { + p_dev = PS3_DEV(&p_vd_list->devs[i].vd.diskPos); + + if (PS3_VDID_INVALID(&p_vd_list->devs[i].vd.diskPos)) { + LOG_WARN("hno:%u, get vd list %d vdid is 0\n", + PS3_HOST(instance), i); + continue; + } + + if (!ps3_dev_id_valid_check(instance, (U8)p_dev->softChan, + p_dev->devID, PS3_DISK_TYPE_VD)) { + PS3_BUG(); + continue; + } + + LOG_INFO("hno:%u, vd list %d dev[%u:%u:%u], magic[%#x]\n", + PS3_HOST(instance), i, p_dev->softChan, p_dev->devID, + p_dev->virtDiskID, + p_vd_list->devs[i].vd.diskPos.diskMagicNum); + + p_dev_ctx->vd_pool.devs[p_dev->softChan][p_dev->devID].vd = + p_vd_list->devs[i].vd; + } +l_out: + return ret; +} + +Bool ps3_dev_id_valid_check(struct ps3_instance *instance, U8 channel, + U16 target_id, U8 dev_type) +{ + U8 ret = PS3_DRV_FALSE; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + + if (dev_type == PS3_DISK_TYPE_VD) { + INJECT_START(PS3_ERR_IJ_FORCE_MOD_CHAN1, &channel); + if (!PS3_IS_VD_CHANNEL(instance, channel)) { + LOG_ERROR_IN_IRQ(instance, + "hno:%u check channel[%u] is not vd channel\n", + PS3_HOST(instance), channel); + goto l_out; + } + + } else if (dev_type == PS3_DISK_TYPE_PD) { + INJECT_START(PS3_ERR_IJ_FORCE_MOD_CHAN3, &channel); + if (!PS3_IS_PD_CHANNEL(instance, channel)) { + LOG_ERROR_IN_IRQ(instance, + "hno:%u check channel[%u] is not pd channel\n", + PS3_HOST(instance), channel); + goto l_out; + } + } else { + LOG_ERROR_IN_IRQ(instance, + "hno:%u dev id[%u:%u] channel err\n", + PS3_HOST(instance), channel, target_id); + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_MOD_TARGET, &target_id); + if (unlikely(target_id >= p_dev_ctx->max_dev_in_channel[channel])) { + LOG_ERROR_IN_IRQ(instance, + "hno:%u check disk[%u:%u] target >= max[%u]\n", + PS3_HOST(instance), channel, target_id, + p_dev_ctx->max_dev_in_channel[channel]); + goto l_out; + } + + ret = PS3_DRV_TRUE; +l_out: + return ret; +} + +U8 ps3_get_vd_raid_level(struct ps3_instance *instance, + U8 channel, U16 target_id) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + U8 vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct ps3_vd_table *p_table = + &p_dev_ctx->vd_table[vd_table_idx]; + struct PS3VDEntry *p_vd_array = + p_dev_ctx->vd_entries_array[vd_table_idx]; + struct PS3VDEntry *p_entry = NULL; + U8 ret = RAID_UNKNOWN; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_VD)) { + goto l_out; + } + + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), p_table->vd_idxs[channel][target_id]); + + p_entry = &p_vd_array[virtDiskIdx]; + if (p_entry == NULL) { + goto l_out; + } + + LOG_DEBUG("hno:%u, vd[%u:%u] raid level is:%d\n", + PS3_HOST(instance), channel, target_id, p_entry->raidLevel); + + ret = p_entry->raidLevel; +l_out: + return ret; +} + +struct ps3_scsi_priv_data *ps3_dev_mgr_lookup_vd_pri_data( + struct ps3_instance *instance, U8 channel, U16 target_id) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_scsi_priv_data *ret = NULL; + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_VD)) { + goto l_out; + } + + ret = p_dev_ctx->vd_pri_data_table.vd_pri_data_idxs[channel] + [target_id]; +l_out: + return ret; +} + +static inline Bool ps3_dev_is_valid(struct PS3DiskDevPos *diskPos, U8 channel, U16 target_id) +{ + if (PS3_DEV_INVALID(*diskPos) || PS3_CHANNEL(diskPos) != channel || PS3_TARGET(diskPos) != target_id) { + return PS3_FALSE; + } + return PS3_TRUE; +} + +struct PS3VDEntry *ps3_dev_mgr_lookup_vd_info( + struct ps3_instance *instance, U8 channel, U16 target_id) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + U8 vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct ps3_vd_table *p_table = + &p_dev_ctx->vd_table[vd_table_idx]; + struct PS3VDEntry *p_vd_array = + p_dev_ctx->vd_entries_array[vd_table_idx]; + struct PS3VDEntry *p_entry = NULL; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + LOG_DEBUG("hno:%u cur_vd_idx[%d]\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx); + + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_VD)) { + goto l_out; + } + + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), p_table->vd_idxs[channel][target_id]); + + p_entry = &p_vd_array[virtDiskIdx]; + + INJECT_START(PS3_ERR_IJ_FORCE_MOD_DISKPOS, &p_entry->diskPos.diskDev.diskID); + if (ps3_dev_is_valid(&p_entry->diskPos, channel, target_id) != PS3_TRUE) { + p_entry = NULL; + goto l_out; + } +l_out: + return p_entry; +} + +struct ps3_pd_entry *ps3_dev_mgr_lookup_pd_info( + struct ps3_instance *instance, U8 channel, U16 target_id) +{ + struct ps3_pd_table *p_table = &instance->dev_context.pd_table; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_pd_entry *p_entry = NULL; + U16 disk_idx = 0; + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_PD)) { + goto l_out; + } + + disk_idx = p_table->pd_idxs[channel][target_id]; + p_entry = &p_dev_ctx->pd_entries_array[disk_idx]; + + INJECT_START(PS3_ERR_IJ_FORCE_MOD_DISKPOS, &p_entry->disk_pos.diskDev.diskID); + if (ps3_dev_is_valid(&p_entry->disk_pos, channel, target_id) != PS3_TRUE) { + p_entry = NULL; + goto l_out; + } +l_out: + return p_entry; +} + +struct PS3VDEntry *ps3_dev_mgr_lookup_vd_info_by_id( + struct ps3_instance *instance, U16 disk_id) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + U8 vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct PS3VDEntry *p_vd_array = + p_dev_ctx->vd_entries_array[vd_table_idx]; + struct PS3VDEntry *p_entry = NULL; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + LOG_DEBUG("hno:%u cur_vd_idx[%d]\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx); + + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), disk_id); + + if (unlikely(virtDiskIdx > PS3_MAX_VD_COUNT(instance))) { + LOG_ERROR_IN_IRQ(instance, "hno:%u , dev mgr lookup vd info disk id > max count:%d>%d\n", + PS3_HOST(instance), disk_id, + PS3_MAX_VD_COUNT(instance)); + + PS3_BUG(); + goto l_out; + } + + p_entry = &p_vd_array[virtDiskIdx]; + + if (PS3_DEV_INVALID(p_entry->diskPos)) { + LOG_INFO_IN_IRQ(instance, "hno:%u idx[%d], virDisk[%d] dev id is invalid\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx, disk_id); + p_entry = NULL; + goto l_out; + } +l_out: + return p_entry; +} + +struct ps3_pd_entry *ps3_dev_mgr_lookup_pd_info_by_id( + struct ps3_instance *instance, U16 disk_id) +{ + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_pd_entry *p_entry = NULL; + + if (unlikely(disk_id > PS3_MAX_PD_COUNT(instance))) { + LOG_ERROR_IN_IRQ(instance, "hno:%u, dev mgr lookup pd info disk id > max count:%d>%d\n", + PS3_HOST(instance), disk_id, + PS3_MAX_PD_COUNT(instance)); + PS3_BUG(); + goto l_out; + } + + p_entry = &p_dev_ctx->pd_entries_array[disk_id]; + + if (PS3_DEV_INVALID(p_entry->disk_pos) || + p_entry->config_flag == MIC_PD_STATE_UNKNOWN) { + LOG_INFO_IN_IRQ(instance, "hno:%u pdid[%d] dev[%x] id is invalid, config_flag[%d]\n", + PS3_HOST(instance), disk_id, + PS3_DISKID(&p_entry->disk_pos), + p_entry->config_flag); + p_entry = NULL; + goto l_out; + } +l_out: + return p_entry; +} + +union PS3Device* ps3_dev_mgr_lookup_vd_list( + struct ps3_instance *instance, U8 channel, U16 target_id) +{ + struct ps3_dev_pool *p_vd_pool = &instance->dev_context.vd_pool; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + union PS3Device *p_vd = NULL; + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_VD)) { + goto l_out; + } + + p_vd = &p_vd_pool->devs[channel][target_id]; + + if (PS3_DEV_INVALID(p_vd->vd.diskPos)) { + LOG_INFO("hno:%u idx[%d], dev[%u:%u] dev id is invalid\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx, channel, + target_id); + p_vd = NULL; + goto l_out; + } +l_out: + return p_vd; +} + +union PS3Device* ps3_dev_mgr_lookup_pd_list( + struct ps3_instance *instance, U8 channel, U16 target_id) +{ + struct ps3_dev_pool *p_pd_pool = &instance->dev_context.pd_pool; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + union PS3Device *p_pd = NULL; + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_PD)) { + goto l_out; + } + + p_pd = &p_pd_pool->devs[channel][target_id]; + + if (PS3_DEV_INVALID(p_pd->pd.diskPos)) { +#if 0 + LOG_INFO("hno:%u idx[%d], dev[%u:%u] dev id is invalid\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx, channel, + target_id); +#endif + p_pd = NULL; + goto l_out; + } + LOG_INFO("hno:%u idx[%d], dev[%u:%u] dev id is valid\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx, channel, + target_id); +l_out: + return p_pd; +} + +S32 ps3_adjust_queue_depth(struct ps3_instance *instance, + U8 dev_type, U32 queue_depth) +{ + S32 dev_queue_depth = PS3_QUEUE_DEPTH_DEFAULT; + + switch (dev_type) { + case PS3_DEV_TYPE_SAS_HDD: + case PS3_DEV_TYPE_SAS_SSD: + dev_queue_depth = PS3_QUEUE_DEPTH_SAS; + break; + case PS3_DEV_TYPE_SATA_HDD: + case PS3_DEV_TYPE_SATA_SSD: + dev_queue_depth = PS3_QUEUE_DEPTH_SATA; + break; + case PS3_DEV_TYPE_NVME_SSD: + dev_queue_depth = PS3_QUEUE_DEPTH_NVME; + break; + default: + dev_queue_depth = PS3_QUEUE_DEPTH_DEFAULT; + break; + } + + if (queue_depth != 0 && (S32)queue_depth <= + instance->cmd_attr.cur_can_que) { + dev_queue_depth = queue_depth; + } + + return dev_queue_depth; +} + +static inline S32 ps3_adjust_device_queue_depth(struct scsi_device *sdev, + struct ps3_instance *instance, S32 q_depth) +{ + S32 queue_depth = q_depth; + struct ps3_pd_entry *p_pd_entry = NULL; + if (PS3_IS_PD_CHANNEL(instance, sdev->channel)) { + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, + sdev->channel, sdev->id); + if (p_pd_entry == NULL) { + LOG_WARN_IN_IRQ(instance, "hno:%u cannot found PD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + goto l_out; + } + if ((p_pd_entry->dev_type == PS3_DEV_TYPE_SATA_HDD) || + (p_pd_entry->dev_type == PS3_DEV_TYPE_SATA_SSD)) { + if (q_depth > PS3_QUEUE_DEPTH_SATA) { + queue_depth = PS3_QUEUE_DEPTH_SATA; + } + } + } + +l_out: +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), queue_depth); +#else + scsi_change_queue_depth(sdev, queue_depth); +#endif + return queue_depth; +} + +#ifndef _WINDOWS +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) +S32 ps3_change_queue_depth(struct scsi_device *sdev, + S32 queue_depth, S32 reason) +{ + S32 ret = -EOPNOTSUPP; + struct ps3_instance *instance = NULL; + instance = (struct ps3_instance*)sdev->host->hostdata; + if (instance == NULL) { + LOG_ERROR_IN_IRQ(instance,"hno:%u have no host\n", + sdev->host->host_no); + goto l_out; + } + + if (queue_depth > sdev->host->can_queue) { + queue_depth = sdev->host->can_queue; + } + if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) { + ret = ps3_adjust_device_queue_depth(sdev, instance, queue_depth); + } else if (reason == SCSI_QDEPTH_QFULL) { + scsi_track_queue_full(sdev, queue_depth); + ret = sdev->queue_depth; + } + LOG_INFO_IN_IRQ(instance,"hno:%u change dev[%u:%u] queue depth to [%d] reason [%d]\n", + PS3_HOST(instance), sdev->channel, sdev->id, ret, reason); +l_out: + return ret; +} + +#else +S32 ps3_change_queue_depth(struct scsi_device *sdev, + S32 queue_depth) +{ + S32 ret = sdev->queue_depth; + struct ps3_instance *instance = NULL; + + instance = (struct ps3_instance*)sdev->host->hostdata; + if (instance == NULL) { + LOG_ERROR("hno:%u have no host\n", + sdev->host->host_no); + goto l_out; + } + + if (queue_depth > sdev->host->can_queue) { + queue_depth = sdev->host->can_queue; + } + + ret = ps3_adjust_device_queue_depth(sdev, instance, queue_depth); + + LOG_INFO("hno:%u change dev[%u:%u] queue depth to [%d]\n", + PS3_HOST(instance), sdev->channel, sdev->id, ret); + +l_out: + return ret; +} + +#endif +static inline void ps3_init_vd_stream(struct ps3_vd_stream_detect *vdsd) +{ + U32 index = 0; + U8 tyepIndex = 0; + for(tyepIndex = PS3_SCSI_CMD_TYPE_READ;tyepIndex < PS3_SCSI_CMD_TYPE_WRITE;tyepIndex++){ + vdsd[tyepIndex-PS3_SCSI_CMD_TYPE_READ].mru_bit_map = MR_STREM_BITMAP; + ps3_spin_lock_init(&vdsd[tyepIndex-PS3_SCSI_CMD_TYPE_READ].ps3_sequence_stream_lock); + + for(index = 0;index < PS3_IO_MAX_STREAMS_TRACKED;index++){ + vdsd[tyepIndex-PS3_SCSI_CMD_TYPE_READ].stream_track[index].next_seq_lba = 0; + vdsd[tyepIndex-PS3_SCSI_CMD_TYPE_READ].stream_track[index].rw_type = tyepIndex; + } + } + return; +} +S32 ps3_scsi_private_init_pd(struct scsi_device *sdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = NULL; + struct ps3_pd_entry *p_pd_entry = NULL; + struct ps3_qos_pd_mgr *p_qos_pd_mgr = NULL; + struct ps3_instance *instance = + (struct ps3_instance*)sdev->host->hostdata; + + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, + sdev->channel, sdev->id); + INJECT_START(PS3_ERR_IJ_FORCE_PD_ENTRY_NULL1, &p_pd_entry); + if (p_pd_entry == NULL) { + LOG_WARN("hno:%u cannot found PD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + ret = -ENXIO; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_PD_STATE_ERROR, &p_pd_entry->state); + if (! ps3_pd_scsi_visible_check(instance, &p_pd_entry->disk_pos, + p_pd_entry->dev_type, p_pd_entry->config_flag, + p_pd_entry->state)) { + ret = -ENXIO; + LOG_WARN("hno:%u pd was blocked: chan[%d] id[%d]\n", + PS3_HOST(instance), sdev->channel, sdev->id); + goto l_out; + } + + LOG_DEBUG("hno:%u found PD[%u:%u:%u] magic[%#x] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id, + PS3_PDID(&p_pd_entry->disk_pos), + p_pd_entry->disk_pos.diskMagicNum); + + p_priv_data = (struct ps3_scsi_priv_data*)ps3_kzalloc(instance, + sizeof(struct ps3_scsi_priv_data)); + INJECT_START(PS3_ERR_IJ_FORCE_PRIV_DATA_NULL2, &p_priv_data); + if (p_priv_data == NULL) { + LOG_ERROR("hno:%u pd[%u:%u:%u] Failed" + " to allocate scsi device private data\n", + PS3_HOST(instance), sdev->channel, sdev->id, + PS3_PDID(&p_pd_entry->disk_pos)); + ret = -ENOMEM; + goto l_out; + } + + p_priv_data->disk_pos = p_pd_entry->disk_pos; + p_priv_data->dev_type = p_pd_entry->dev_type; + p_priv_data->is_taskmgmt_enable = PS3_DRV_TRUE; + p_priv_data->task_abort_timeout = + p_pd_entry->task_abort_timeout; + p_priv_data->task_reset_timeout = + p_pd_entry->task_reset_timeout; + p_priv_data->task_manager_busy = 0; + p_priv_data->encl_id = p_pd_entry->encl_id; + p_priv_data->phy_id = p_pd_entry->phy_id; + ps3_atomic_set(&p_priv_data->rd_io_outstand, PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&p_priv_data->wr_io_outstand, PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&p_priv_data->r1x_read_cmd_swap_total_cnt, PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&p_priv_data->r1x_read_cmd_swap_res_cnt, PS3_CMD_STAT_INIT_VALUE); + p_qos_pd_mgr = ps3_qos_pd_mgr_init(instance, p_pd_entry); + if (p_qos_pd_mgr != NULL && p_qos_pd_mgr->dev_type != p_pd_entry->dev_type) { + ps3_qos_pd_rsc_init(p_qos_pd_mgr, p_pd_entry); + } + p_priv_data->dev_deling = PS3_FALSE; + p_priv_data->swap_flag = PS3_FALSE; + sdev->hostdata = p_priv_data; +l_out: + return ret; +} + +void ps3_vd_busy_scale_get(struct PS3VDEntry *vd_entry) +{ + U16 scale = 0; + U32 strip_size_shift = 0; + + strip_size_shift = ps3_blocksize_to_shift(vd_entry->stripSize); + scale = vd_entry->span[0].spanStripeDataSize >> strip_size_shift;; + if ((vd_entry->raidLevel == RAID1E || + vd_entry->raidLevel == RAID10) && + (vd_entry->span[0].spanPdNum & 1)) { + scale = scale >> 1; + } + + vd_entry->dev_busy_scale = scale; + return; +} + +S32 ps3_scsi_private_init_vd(struct scsi_device *sdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = NULL; + struct PS3VDEntry *p_vd_entry = NULL; + struct ps3_instance *instance = + (struct ps3_instance*)sdev->host->hostdata; + struct ps3_pri_data_table *p_vd_pri_data_table = &instance->dev_context.vd_pri_data_table; + + p_vd_entry = ps3_dev_mgr_lookup_vd_info(instance, + sdev->channel, sdev->id); + INJECT_START(PS3_ERR_IJ_FORCE_VD_ENTRY_NULL1, &p_vd_entry); + if (p_vd_entry == NULL) { + LOG_WARN("hno:%u cannot found VD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + ret = -ENXIO; + goto l_out; + } + LOG_DEBUG("hno:%u found VD[%u:%u:%u] magic[%#x] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id, + PS3_VDID(&p_vd_entry->diskPos), + p_vd_entry->diskPos.diskMagicNum); + + p_priv_data = (struct ps3_scsi_priv_data*)ps3_kzalloc(instance, + sizeof(struct ps3_scsi_priv_data)); + INJECT_START(PS3_ERR_IJ_FORCE_PRIV_DATA_NULL, &p_priv_data); + if (p_priv_data == NULL) { + LOG_ERROR("hno:%u vd[%u:%u:%u] Failed" + " to allocate scsi device private data\n", + PS3_HOST(instance), sdev->channel, sdev->id, + PS3_VDID(&p_vd_entry->diskPos)); + ret = -ENOMEM; + goto l_out; + } + + p_priv_data->disk_pos = p_vd_entry->diskPos; + p_priv_data->dev_type = PS3_DEV_TYPE_VD; + p_priv_data->is_taskmgmt_enable = p_vd_entry->isTaskMgmtEnable; + p_priv_data->task_abort_timeout = p_vd_entry->taskAbortTimeout; + p_priv_data->task_reset_timeout = p_vd_entry->taskResetTimeout; + p_priv_data->task_manager_busy = 0; + ps3_atomic_set(&p_priv_data->rd_io_outstand, PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&p_priv_data->wr_io_outstand, PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&p_priv_data->r1x_read_cmd_swap_total_cnt, PS3_CMD_STAT_INIT_VALUE); + ps3_atomic_set(&p_priv_data->r1x_read_cmd_swap_res_cnt, PS3_CMD_STAT_INIT_VALUE); + p_priv_data->dev_deling = PS3_FALSE; + p_priv_data->swap_flag = PS3_FALSE; + ps3_vd_busy_scale_get(p_vd_entry); + ps3_init_vd_stream(p_priv_data->vd_sd); + p_priv_data->r1x_rb_info = (struct ps3_r1x_read_balance_info *)ps3_kzalloc(instance, + sizeof(struct ps3_r1x_read_balance_info)); + INJECT_START(PS3_ERR_IJ_FORCE_RB_INFO_NULL, &p_priv_data->r1x_rb_info); + if (p_priv_data->r1x_rb_info == NULL) { + LOG_ERROR("hno:%u vd[%u:%u:%u] Failed to allocate r1x_lb_info\n", + PS3_HOST(instance), sdev->channel, sdev->id, + PS3_VDID(&p_vd_entry->diskPos)); + ret = -ENOMEM; + goto l_err; + } + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + sdev->hostdata = p_priv_data; + + ret = ps3_r1x_lock_prepare_for_vd(instance, sdev, + p_vd_entry->raidLevel); + if(unlikely(PS3_SUCCESS != ret)){ + ps3_kfree(instance, p_priv_data->r1x_rb_info); + p_priv_data->r1x_rb_info = NULL; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + LOG_ERROR("hno:%u vd[%u:%u:%u] Failed" + " to allocate raid1x write lock mgr\n", + PS3_HOST(instance), sdev->channel, sdev->id, + PS3_VDID(&p_vd_entry->diskPos)); + ret = -ENOMEM; + goto l_err; + } + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + + p_vd_pri_data_table->vd_pri_data_idxs[PS3_SDEV_CHANNEL(sdev)] + [PS3_SDEV_TARGET(sdev)] = p_priv_data; + + ps3_qos_vd_init(instance, p_vd_entry); + + goto l_out; +l_err: + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + if (p_priv_data != NULL) { + ps3_kfree(instance, p_priv_data); + sdev->hostdata = NULL; + } + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + +l_out: + return ret; +} + +S32 ps3_scsi_slave_alloc(struct scsi_device *sdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = NULL; + struct ps3_instance *instance = NULL; + struct PS3VDEntry *p_vd_entry = NULL; + struct ps3_pd_entry *p_pd_entry = NULL; + U32 dma_addr_alignment = 0; + U32 dma_len_alignment = 0; + U8 dev_type = PS3_DISK_TYPE_UNKNOWN; + struct PS3DiskDevPos* p_diskPos = NULL; + + LOG_DEBUG("enter, [%u:%u:%llu]\n", + sdev->channel, sdev->id, (U64)sdev->lun); + INJECT_START(PS3_ERR_IJ_FORCE_LUN_ERROR, &sdev->lun); + if (sdev->lun != 0) { + ret = -ENXIO; + goto l_out; + } + + instance = (struct ps3_instance*)sdev->host->hostdata; + INJECT_START(PS3_ERR_IJ_FORCE_INSTANCE_NULL, &instance); + if (instance == NULL) { + LOG_ERROR("hno:%u have no host\n", + sdev->host->host_no); + ret = -ENXIO; + goto l_out; + } + + sdev->hostdata = NULL; + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_GET_PRIV_DATA_DELAY, PS3_ERR_IJ_FORCE_WAIT, sdev); + + ret = -ENXIO; + if (PS3_IS_VD_CHANNEL(instance, sdev->channel)) { + dev_type = PS3_DISK_TYPE_VD; + p_vd_entry = ps3_dev_mgr_lookup_vd_info(instance, sdev->channel, + sdev->id); + INJECT_START(PS3_ERR_IJ_FORCE_VD_ENTRY_NULL, &p_vd_entry); + if (p_vd_entry == NULL) { + LOG_ERROR("hno:%u, cannot found VD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + + goto l_out; + } + + p_diskPos = &p_vd_entry->diskPos; + + } else if (PS3_IS_PD_CHANNEL(instance, sdev->channel)) { + dev_type = PS3_DISK_TYPE_PD; + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, sdev->channel, + sdev->id); + INJECT_START(PS3_ERR_IJ_FORCE_PD_ENTRY_NULL, &p_pd_entry); + if (p_pd_entry == NULL) { + LOG_ERROR("hno:%u, cannot found PD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + + goto l_out; + } + + p_diskPos = &p_pd_entry->disk_pos; + } else { + LOG_ERROR("hno:%u dev channel[%u] type NOK\n", + PS3_HOST(instance), sdev->channel); + goto l_out; + } + + if (dev_type == PS3_DISK_TYPE_VD) { + ret = ps3_scsi_private_init_vd(sdev); + } else { + ret = ps3_scsi_private_init_pd(sdev); + } + + if (ret != PS3_SUCCESS) { + goto l_dev_done; + } + + p_priv_data = (struct ps3_scsi_priv_data*)sdev->hostdata; + + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_GET_PRIV_DATA_DELAY, PS3_ERR_IJ_FORCE_WAIT, NULL); + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_GET_PRIV_DATA_DELAY, PS3_ERR_IJ_ADD_DEV_WAIT_OS_PRIV_DATA, NULL); + ret = ps3_scsi_add_device_ack(instance, p_diskPos, + dev_type); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL3, &ret); + if (unlikely(ret != PS3_SUCCESS)) { + ret = -ENXIO; + goto l_dev_ack_failed; + } + + LOG_INFO("[%u:%u:%llu], dev_type[%s]\n", + sdev->channel, sdev->id, (U64)sdev->lun, + namePS3DevType((enum PS3DevType)p_priv_data->dev_type)); + + if (p_priv_data->task_abort_timeout == 0) { + p_priv_data->task_abort_timeout = PS3_DEFAULT_TASK_MGR_TIMEOUT; + } + + if (p_priv_data->task_reset_timeout == 0) { + p_priv_data->task_reset_timeout = PS3_DEFAULT_TASK_MGR_TIMEOUT; + } + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) + + sdev->tagged_supported = 1; + scsi_activate_tcq(sdev, sdev->queue_depth); +#endif + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD) { + dma_addr_alignment = ps3_pd_dma_alignment_calc(p_vd_entry->dmaAddrAlignShift); + dma_len_alignment = ps3_pd_dma_alignment_calc(p_vd_entry->dmaLenAlignShift); + } else { + dma_addr_alignment = p_pd_entry->dma_addr_alignment; + dma_len_alignment = p_pd_entry->dma_len_alignment; + } + + blk_queue_dma_alignment(sdev->request_queue, PS3_SCSI_ALINNMENT_MASK); + if(dma_addr_alignment){ + blk_queue_dma_alignment(sdev->request_queue, dma_addr_alignment - 1); + } + + if(dma_len_alignment){ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + blk_queue_dma_pad(sdev->request_queue, dma_len_alignment - 1); +#else + blk_queue_update_dma_pad(sdev->request_queue, dma_len_alignment - 1); +#endif + + } + + LOG_INFO("slave_alloc,dma_addr_alignment[%d] dma_len_alignment[%d]\n", + dma_addr_alignment, dma_len_alignment); + + goto l_out; +l_dev_ack_failed: + ps3_scsi_slave_destroy(sdev); + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_GET_PRIV_DATA_DELAY, PS3_ERR_IJ_FORCE_WAIT, sdev); +l_dev_done: + ps3_scsi_remove_device_done(instance, p_diskPos, dev_type); +l_out: + LOG_DEBUG("exit, hno:%u\n", sdev->host->host_no); + return ret; +} + +void ps3_scsi_slave_destroy(struct scsi_device *sdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = NULL; + struct ps3_instance *instance = + (struct ps3_instance*)sdev->host->hostdata; + struct ps3_pri_data_table *p_vd_pri_data_table = &instance->dev_context.vd_pri_data_table; + INJECT_START(PS3_ERR_IJ_FORCE_INSTANCE_NULL2, &instance); + if (instance == NULL) { + LOG_ERROR("hno:%u have no host\n",sdev->host->host_no); + goto l_out; + } + + LOG_DEBUG("hno:%u enter, max_chan[%u], max_id[%u], max_lun[%llu]\n", + PS3_HOST(instance), sdev->host->max_channel, + sdev->host->max_id, (U64)sdev->host->max_lun); + + p_priv_data = (struct ps3_scsi_priv_data*)sdev->hostdata; + if (p_priv_data != NULL) { + if (PS3_IS_VD_CHANNEL(instance, sdev->channel)) { + LOG_INFO("hno[%u], vd[%u:%u] r1x conflict destory\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + INJECT_AT_TIMES(PS3_ERR_IJ_GET_PRIV_DATA_DELAY, NULL); + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + ps3_r1x_lock_destory_for_vd(instance, &p_priv_data->lock_mgr); + ps3_qos_vd_reset(instance, PS3_VDID(&p_priv_data->disk_pos)); + p_vd_pri_data_table->vd_pri_data_idxs + [PS3_SDEV_CHANNEL(sdev)] + [PS3_SDEV_TARGET(sdev)] = NULL; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + if (p_priv_data->r1x_rb_info != NULL) { + ps3_kfree(instance, p_priv_data->r1x_rb_info); + p_priv_data->r1x_rb_info = NULL; + } + } else if (PS3_IS_PD_CHANNEL(instance, sdev->channel)) { + ps3_qos_pd_mgr_reset(instance, PS3_PDID(&p_priv_data->disk_pos)); + } + + ret = ps3_scsi_remove_device_done(instance, &p_priv_data->disk_pos, + ps3_disk_type((enum PS3DevType) p_priv_data->dev_type)); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL5, &ret); + if (ret != PS3_SUCCESS) { + LOG_INFO("hno:%u dev[%u:%u:%u] magic[%#x] dev del done error %d\n", + PS3_HOST(instance), + PS3_CHANNEL(&p_priv_data->disk_pos), + PS3_TARGET(&p_priv_data->disk_pos), + PS3_PDID(&p_priv_data->disk_pos), + p_priv_data->disk_pos.diskMagicNum, ret); + } + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + if(sdev->hostdata != NULL) { + ps3_kfree(instance, sdev->hostdata); + } + sdev->hostdata = NULL; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + } + +l_out: + LOG_DEBUG("exit, hno:%u\n", sdev->host->host_no); +} + +static Bool ps3_is_nvme_device(struct ps3_instance *instance, U8 dev_type, + U8 channel, U16 target_id) +{ + Bool ret = PS3_FALSE; + struct PS3VDEntry *vd_entry = NULL; + + if (dev_type == PS3_DEV_TYPE_NVME_SSD) { + ret = PS3_TRUE; + goto l_out; + } + + if (dev_type == PS3_DEV_TYPE_VD) { + vd_entry = ps3_dev_mgr_lookup_vd_info(instance, channel, target_id); + if (vd_entry == NULL) { + LOG_ERROR("hno:%u cannot found VD[%u:%u] device\n", + PS3_HOST(instance), channel, target_id); + ret = PS3_FALSE; + goto l_out; + } + if (vd_entry->isNvme == 1) { + ret = PS3_TRUE; + goto l_out; + } + + goto l_out; + } + +l_out: + return ret; +} + +static void ps3_nvme_attr_set(const struct ps3_instance *instance, + struct scsi_device *sdev) +{ + U32 page_size = instance->cmd_attr.nvme_page_size; + U32 align_mask = (page_size == 0) ? page_size : (page_size- 1); + + LOG_INFO("nvme page size is %u\n", page_size); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,16,0) + queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, sdev->request_queue); +#else + blk_queue_flag_set(QUEUE_FLAG_NOMERGES, sdev->request_queue); +#endif + blk_queue_virt_boundary(sdev->request_queue, align_mask); +} + +static inline void ps3_nvme_pd_attr_set(struct scsi_device *sdev, + const struct ps3_pd_entry *p_pd_entry) +{ + struct ps3_instance *instance = (struct ps3_instance *)sdev->host->hostdata; + U32 sector_count = 0; + + if (p_pd_entry->max_io_size != 0 && p_pd_entry->sector_size != 0) { + sector_count = p_pd_entry->max_io_size >> PS3_512B_SHIFT; + blk_queue_max_hw_sectors(sdev->request_queue, sector_count); + } + + LOG_INFO("nvme attr max_io_size[%u], sector_size[%u], sector_count[%u]\n", + p_pd_entry->max_io_size, p_pd_entry->sector_size, sector_count); + + ps3_nvme_attr_set(instance, sdev); +} + +static inline void ps3_set_queue_depth(struct scsi_device *sdev, U8 dev_type, + U32 queue_depth) +{ + S32 dev_queue_depth = queue_depth; + struct ps3_instance *instance = (struct ps3_instance *)sdev->host->hostdata; + + dev_queue_depth = ps3_adjust_queue_depth(instance, dev_type, queue_depth); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), dev_queue_depth); +#else + scsi_change_queue_depth(sdev, dev_queue_depth); +#endif +} +void ps3_sdev_bdi_stable_writes_set(struct ps3_instance *instance, struct scsi_device *sdev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR >= 8) && (RHEL_MINOR >= 6))) + (void)instance; + blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, + sdev->request_queue); +#else + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) + sdev->request_queue->backing_dev_info.capabilities + |= BDI_CAP_STABLE_WRITES; + LOG_INFO("hno:%u, dev type[%u:%u] capabilities[0x%x]\n", + PS3_HOST(instance), sdev->channel, sdev->id, + sdev->request_queue->backing_dev_info.capabilities); + #else + sdev->request_queue->backing_dev_info->capabilities + |= BDI_CAP_STABLE_WRITES; + LOG_INFO("hno:%u, dev type[%u:%u] capabilities[0x%x]\n", + PS3_HOST(instance), sdev->channel, sdev->id, + sdev->request_queue->backing_dev_info->capabilities); + #endif +#endif +} +S32 ps3_sdev_bdi_stable_writes_get(struct scsi_device *sdev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR >= 8) && (RHEL_MINOR >= 6))) + return blk_queue_stable_writes(sdev->request_queue); +#else + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) + return ((sdev->request_queue->backing_dev_info.capabilities & \ + BDI_CAP_STABLE_WRITES) == BDI_CAP_STABLE_WRITES); + #else + return ((sdev->request_queue->backing_dev_info->capabilities & \ + BDI_CAP_STABLE_WRITES) == BDI_CAP_STABLE_WRITES); + #endif +#endif +} + +void ps3_sdev_bdi_stable_writes_clear(struct ps3_instance *instance, struct scsi_device *sdev) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR >= 8) && (RHEL_MINOR >= 6))) + (void)instance; + blk_queue_flag_clear(QUEUE_FLAG_STABLE_WRITES, + sdev->request_queue); +#else + #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)) + sdev->request_queue->backing_dev_info.capabilities + &= ~BDI_CAP_STABLE_WRITES;; + LOG_INFO("hno:%u, dev type[%u:%u] capabilities[0x%x]\n", + PS3_HOST(instance), sdev->channel, sdev->id, + sdev->request_queue->backing_dev_info.capabilities); + #else + sdev->request_queue->backing_dev_info->capabilities + &= ~BDI_CAP_STABLE_WRITES;; + LOG_INFO("hno:%u, dev type[%u:%u] capabilities[0x%x]\n", + PS3_HOST(instance), sdev->channel, sdev->id, + sdev->request_queue->backing_dev_info->capabilities); + #endif +#endif +} + +S32 ps3_scsi_slave_configure(struct scsi_device *sdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = NULL; + struct ps3_pd_entry *p_pd_entry = NULL; + struct PS3VDEntry *p_vd_entry = NULL; + U32 queue_depth = 0; + U32 dma_addr_alignment = 0; + U32 dma_len_alignment = 0; + U8 io_tmo = PS3_SCSI_CMD_TIMEOUT_DEFAULT; + + struct ps3_instance *instance = + (struct ps3_instance*)sdev->host->hostdata; + INJECT_START(PS3_ERR_IJ_FORCE_INSTANCE_NULL1, &instance); + if (unlikely(instance == NULL)) { + LOG_ERROR("hno:%u slave configure have no host instance\n", + sdev->host->host_no); + PS3_BUG(); + ret = -ENXIO; + goto l_out; + } + + p_priv_data = (struct ps3_scsi_priv_data*)sdev->hostdata; + INJECT_START(PS3_ERR_IJ_FORCE_PRIV_DATA_NULL1, &p_priv_data); + if (unlikely(p_priv_data == NULL)) { + LOG_ERROR("hno:%u, slave configure have no private data, [%u:%u]\n", + PS3_HOST(instance), sdev->channel, sdev->id); + PS3_BUG(); + ret = -ENXIO; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_MOD_DEV_TYPE, &p_priv_data->dev_type); + if (unlikely(p_priv_data->dev_type == PS3_DEV_TYPE_UNKNOWN)) { + LOG_ERROR("hno:%u, dev type[%u:%u] is PS3_DEV_TYPE_UNKNOWN\n", + PS3_HOST(instance), sdev->channel, sdev->id); + ret = -ENXIO; + goto l_out; + } + + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD) { + p_vd_entry = ps3_dev_mgr_lookup_vd_info(instance, sdev->channel, + sdev->id); + INJECT_START(PS3_ERR_IJ_FORCE_VD_ENTRY_NULL2, &p_vd_entry); + if (p_vd_entry == NULL) { + LOG_ERROR("hno:%u, cannot found VD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + ret = -ENXIO; + goto l_out; + } + queue_depth = p_vd_entry->devQueDepth; + dma_addr_alignment = ps3_pd_dma_alignment_calc(p_vd_entry->dmaAddrAlignShift); + dma_len_alignment = ps3_pd_dma_alignment_calc(p_vd_entry->dmaLenAlignShift); + if (p_vd_entry->bdev_bdi_cap & PS3_STABLE_WRITES_MASK) { + ps3_sdev_bdi_stable_writes_set(instance, sdev); + } + } else { + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, sdev->channel, + sdev->id); + INJECT_START(PS3_ERR_IJ_FORCE_PD_ENTRY_NULL2, &p_pd_entry); + if (p_pd_entry == NULL) { + LOG_ERROR("hno:%u, cannot found PD[%u:%u] device info\n", + PS3_HOST(instance), sdev->channel, sdev->id); + ret = -ENXIO; + goto l_out; + } + queue_depth = p_pd_entry->dev_queue_depth; + dma_addr_alignment = p_pd_entry->dma_addr_alignment; + dma_len_alignment = p_pd_entry->dma_len_alignment; + } + + blk_queue_dma_alignment(sdev->request_queue, PS3_SCSI_ALINNMENT_MASK); + if(dma_addr_alignment){ + blk_queue_dma_alignment(sdev->request_queue, dma_addr_alignment - 1); + } + + if(dma_len_alignment){ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + blk_queue_dma_pad(sdev->request_queue, dma_len_alignment - 1); +#else + blk_queue_update_dma_pad(sdev->request_queue, dma_len_alignment - 1); +#endif + } + if (instance->ctrl_info.ioTimeOut != 0) { + io_tmo = instance->ctrl_info.ioTimeOut; + } + if (ps3_scsi_cmd_timeout_query() != 0) { + io_tmo = ps3_scsi_cmd_timeout_query(); + } + + LOG_INFO("slave_configure, dma_addr_alignment[%d], " + "dma_len_alignment[%d], io_timeout[%u], queue_depth[%u]\n", + dma_addr_alignment, dma_len_alignment, io_tmo, queue_depth); + + blk_queue_rq_timeout(sdev->request_queue, io_tmo * HZ); + + ps3_set_queue_depth(sdev, p_priv_data->dev_type, queue_depth); + + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD) { + if (p_vd_entry->maxIOSize != 0) { + if (p_vd_entry->sectorSize == PS3_SECTORSIZE_512B) { + blk_queue_max_hw_sectors(sdev->request_queue, p_vd_entry->maxIOSize); + } else { + blk_queue_max_hw_sectors(sdev->request_queue, + p_vd_entry->maxIOSize << (ilog2(p_vd_entry->sectorSize) - PS3_512B_SHIFT)); + } + } else { + LOG_DEBUG("hno:%u vd[%u:%u] update max sector num is:0\n", + PS3_HOST(instance), sdev->channel, sdev->id); + } + if (ps3_is_nvme_device(instance, p_priv_data->dev_type, + sdev->channel, sdev->id)) { + ps3_nvme_attr_set(instance, sdev); + } else { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)) + blk_queue_dma_pad(sdev->request_queue, dma_len_alignment - 1); +#else + blk_queue_update_dma_pad(sdev->request_queue, dma_len_alignment - 1); +#endif + } + } else if (p_pd_entry != NULL) { + if (p_priv_data->dev_type == PS3_DEV_TYPE_NVME_SSD) { + ps3_nvme_pd_attr_set(sdev, p_pd_entry); + } else if (PS3_IS_HAC_LIMIT_TYPE(p_priv_data->dev_type)) { + if (p_pd_entry->max_io_size != 0 && p_pd_entry->sector_size != 0) { + blk_queue_max_hw_sectors(sdev->request_queue, + p_pd_entry->max_io_size >> PS3_512B_SHIFT); + } + } + } + + if (ps3_sas_is_support_smp(instance) && p_pd_entry != NULL) { + if (ps3_check_pd_is_vd_member(p_pd_entry->config_flag)) { + LOG_DEBUG("hno:%u, PD[%u:%u] is belong to vd device\n", + PS3_HOST(instance), sdev->channel, sdev->id); + sdev->no_uld_attach = 1; + } + + if (p_priv_data->dev_type == PS3_DEV_TYPE_SAS_HDD || + p_priv_data->dev_type == PS3_DEV_TYPE_SAS_SSD || + p_priv_data->dev_type == PS3_DEV_TYPE_SES) { + LOG_DEBUG("hno:%u pd[%u:%u] dev_type[%s] ready read port mode page\n", + PS3_HOST(instance), sdev->channel, sdev->id, + namePS3DevType((enum PS3DevType)p_pd_entry->dev_type)); + sas_read_port_mode_page(sdev); + } + } + +l_out: + return ret; +} +#else +void ps3_nvme_attr_set(const struct ps3_instance *instance, + struct scsi_device *sdev) +{ + (void)instance; + (void)sdev; +} +#endif diff --git a/drivers/scsi/ps3stor/ps3_device_manager.h b/drivers/scsi/ps3stor/ps3_device_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d40e9225a51bb2ada32606d3a2f1970e279473c2 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_device_manager.h @@ -0,0 +1,576 @@ + +#ifndef _PS3_DEVICE_MANAGER_H_ +#define _PS3_DEVICE_MANAGER_H_ + +#include "ps3_platform_utils.h" +#ifdef _WINDOWS +#include "ps3_dev_adp.h" +#else +#include +#include +#include +#include + +#endif + +#include "ps3_meta.h" +#include "ps3_dev_type.h" +#include "ps3_htp.h" +#include "ps3_err_def.h" + +#define PS3_QUEUE_DEPTH_DEFAULT (256) +#define PS3_QUEUE_DEPTH_SATA (32) +#define PS3_QUEUE_DEPTH_SAS (64) +#define PS3_QUEUE_DEPTH_NVME (32) + +#define PS3_INVALID_VALUE (0) +#define PS3_INVALID_DEV_ID (0) +#define PS3_INVALID_LIST_ID (0) +#define PS3_DMA_ALIGN_SHIFT_MAX (15) + +#define PS3_VD_TABLE_NUM (2) +#define PS3_SCSI_4B_ALINNMENT_MASK (4) +#define PS3_SCSI_ALINNMENT_MASK (0x3) +#define PS3_SCSI_32B_ALINNMENT_MASK (0x1f) +#define PS3_SCSI_512B_ALINNMENT_MASK (0x000001FF) +#define PS3_SCSI_4K_ALINNMENT_MASK (0xFFF) +#define PS3_512B_SHIFT (9) +#define PS3_SECTORSIZE_512B (512) + +#define PS3_MAX_VD_COUNT(instance) \ + ((instance)->ctrl_info.maxVdCount) +#define PS3_MAX_PD_COUNT(instance) \ + ((instance)->ctrl_info.maxPdCount) + +#define PS3_CHANNEL(pos) \ + ((U8)((pos)->diskDev.ps3Dev.softChan)) +#define PS3_TARGET(pos) \ + ((U16)((pos)->diskDev.ps3Dev.devID)) +#define PS3_DISKID(pos) \ + ((pos)->diskDev.diskID) +#define PS3_PDID(pos) \ + ((pos)->diskDev.ps3Dev.phyDiskID) +#define PS3_VDID(pos) \ + ((pos)->diskDev.ps3Dev.virtDiskID) +#define PS3_DEV(pos) \ + ((struct PS3Dev*)(&(pos)->diskDev.ps3Dev)) +#define PS3_VDID_OFFSET(instance) \ + ((instance)->ctrl_info.offsetOfVDID) + +#define PS3_DEV_INVALID(pos) \ + ((pos).diskDev.diskID == PS3_INVALID_DEV_ID) +#define PS3_PDID_INVALID(pos) \ + (PS3_PDID(pos) == PS3_INVALID_DEV_ID) +#define PS3_VDID_INVALID(pos) \ + (PS3_VDID(pos) == PS3_INVALID_DEV_ID) +#define PS3_IS_VD_CHANNEL(ins, chan) \ + ((ins->dev_context.vd_table[0].vd_idxs[chan] != NULL) ? \ + PS3_DRV_TRUE : PS3_DRV_FALSE) + +#define PS3_IS_PD_CHANNEL(ins, chan) \ + ((ins->dev_context.pd_table.pd_idxs[chan] != NULL) ? \ + PS3_DRV_TRUE : PS3_DRV_FALSE) + +#define PS3_MAX_PD_NUM_ONE_VD (PS3_MAX_PD_COUNT_IN_SPAN * PS3_MAX_SPAN_IN_VD) + +struct ps3_instance; + +#define MR_STREM_BITMAP (0xfedcba9876543210) +#define PS3_IO_MAX_STREAMS_TRACKED (16) +#define BITS_PER_INDEX_STREAM (4) +#define BITS_PER_INDEX_STREAM_SHIFT (2) +#define STREAM_MASK ((1ULL << BITS_PER_INDEX_STREAM) - 1) +#define ZERO_LAST_STREAM (0x0FFFFFFFFFFFFFFF) + +#define MAX_QUE_DEPTH (16) +#define TEST_IO_BLOCK_SIZE (8) +#define IO_STREAM_DETECT_RANGE (MAX_QUE_DEPTH * TEST_IO_BLOCK_SIZE) +#define PS3_IS_HAC_LIMIT_TYPE(type) \ + ((type) == PS3_DEV_TYPE_SAS_HDD || \ + (type) == PS3_DEV_TYPE_SATA_HDD || \ + (type) == PS3_DEV_TYPE_SATA_SSD || \ + (type) == PS3_DEV_TYPE_SAS_SSD || \ + (type) == PS3_DEV_TYPE_SES) + +struct ps3_stream_detect { + U64 next_seq_lba; + U8 rw_type; + U8 reserved[7]; +}; + + +struct ps3_vd_stream_detect { + ps3_spinlock ps3_sequence_stream_lock; + U64 mru_bit_map; + struct ps3_stream_detect stream_track[PS3_IO_MAX_STREAMS_TRACKED]; +}; +enum PS3DevType { + PS3_DEV_TYPE_UNKNOWN = 0, + PS3_DEV_TYPE_VD = 1, + PS3_DEV_TYPE_SAS_HDD = 2, + PS3_DEV_TYPE_SATA_HDD = 3, + PS3_DEV_TYPE_SATA_SSD = 4, + PS3_DEV_TYPE_SAS_SSD = 5, + PS3_DEV_TYPE_NVME_SSD = 6, + PS3_DEV_TYPE_SES = 7, + PS3_DEV_TYPE_VEP = 8, + PS3_DEV_TYPE_COUNT, +}; + +enum PS3DevTypeV1 { + PS3_DEV_TYPE_SAS_SATA = 0, + PS3_DEV_TYPE_NVME = 1, +}; + +static inline const S8 *namePS3DevType(enum PS3DevType e) +{ + static const S8 *myNames[] = { + [PS3_DEV_TYPE_UNKNOWN] = "DEV_T_UNKNOWN", + [PS3_DEV_TYPE_VD] = "DEV_T_VD", + [PS3_DEV_TYPE_SAS_HDD] = "DEV_T_SAS_HDD", + [PS3_DEV_TYPE_SATA_HDD] = "DEV_T_SATA_HDD", + [PS3_DEV_TYPE_SATA_SSD] = "DEV_T_SATA_SSD", + [PS3_DEV_TYPE_SAS_SSD] = "DEV_T_SAS_SSD", + [PS3_DEV_TYPE_NVME_SSD] = "DEV_T_NVME_SSD", + [PS3_DEV_TYPE_SES] = "DEV_T_SES", + [PS3_DEV_TYPE_VEP] = "DEV_T_VEP" + }; + + return myNames[e]; +} + +enum ps3_dev_io_stat_type { + PS3_DEV_IO_STAT_TYPE_R_SEND = 1, + PS3_DEV_IO_STAT_TYPE_R_SEND_OK, + PS3_DEV_IO_STAT_TYPE_R_SEND_WAIT, + PS3_DEV_IO_STAT_TYPE_R_SEND_ERR, + PS3_DEV_IO_STAT_TYPE_R_RECV, + PS3_DEV_IO_STAT_TYPE_R_RECV_OK, + PS3_DEV_IO_STAT_TYPE_R_RECV_ERR, + PS3_DEV_IO_STAT_TYPE_R_OK_BYTES, + + PS3_DEV_IO_STAT_TYPE_W_SEND, + PS3_DEV_IO_STAT_TYPE_W_SEND_OK, + PS3_DEV_IO_STAT_TYPE_W_SEND_WAIT, + PS3_DEV_IO_STAT_TYPE_W_SEND_ERR, + PS3_DEV_IO_STAT_TYPE_W_RECV, + PS3_DEV_IO_STAT_TYPE_W_RECV_OK, + PS3_DEV_IO_STAT_TYPE_W_RECV_ERR, + PS3_DEV_IO_STAT_TYPE_W_OK_BYTES, + PS3_DEV_IO_STAT_TYPE_MAX, +}; + +struct ps3_dev_io_statis { + ps3_atomic64 read_send_cnt; + ps3_atomic64 read_send_ok_cnt; + ps3_atomic64 read_send_wait_cnt; + ps3_atomic64 read_send_err_cnt; + ps3_atomic64 read_recv_cnt; + ps3_atomic64 read_recv_ok_cnt; + ps3_atomic64 read_recv_err_cnt; + ps3_atomic64 read_ok_bytes; + + ps3_atomic64 write_send_cnt; + ps3_atomic64 write_send_ok_cnt; + ps3_atomic64 write_send_err_cnt; + ps3_atomic64 write_send_wait_cnt; + ps3_atomic64 write_recv_cnt; + ps3_atomic64 write_recv_ok_cnt; + ps3_atomic64 write_recv_err_cnt; + ps3_atomic64 write_ok_bytes; + + ps3_atomic64 qos_processing_cnt; +}; + +static inline U8 ps3_disk_type(enum PS3DevType e) +{ + U8 disk_type = PS3_DISK_TYPE_UNKNOWN; + + switch(e) { + case PS3_DEV_TYPE_VD: + disk_type = PS3_DISK_TYPE_VD; + break; + case PS3_DEV_TYPE_SAS_HDD: + case PS3_DEV_TYPE_SATA_HDD: + case PS3_DEV_TYPE_SATA_SSD: + case PS3_DEV_TYPE_SAS_SSD: + case PS3_DEV_TYPE_NVME_SSD: + case PS3_DEV_TYPE_SES: + case PS3_DEV_TYPE_VEP: + disk_type = PS3_DISK_TYPE_PD; + break; + default: + disk_type = PS3_DISK_TYPE_UNKNOWN; + break; + } + return disk_type; +} + +static inline Bool ps3_is_fake_pd(U8 dev_type) +{ + return (dev_type == PS3_DEV_TYPE_SES || dev_type == PS3_DEV_TYPE_VEP); +} + +struct ps3_r1x_read_balance_info { + ps3_atomic32 scsi_outstanding_cmds[PS3_MAX_PD_NUM_ONE_VD + 1]; + U64 last_accessed_block[PS3_MAX_PD_NUM_ONE_VD + 1]; +}; + +struct ps3_r1x_lock_mgr { + S32 (*try_lock)(struct ps3_r1x_lock_mgr *mgr, void *cmd); + S32 (*resend_try_lock)(struct ps3_r1x_lock_mgr *mgr, void *cmd); + void (*unlock)(struct ps3_r1x_lock_mgr *mgr, void *cmd); + ps3_spinlock mgr_lock; + void *hash_mgr; + ps3_list_head conflict_cmd_list; + struct task_struct *conflict_send_th; + void *hash_mgr_conflict; + S32 force_ret_code; + U32 cmd_count_in_q; + Bool dev_deling; + Bool thread_stop; +#ifdef _WINDOWS + KEVENT thread_sync; +#else + struct completion thread_sync; +#endif + +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) || \ + (defined(KYLIN_MAJOR) && defined(CONFIG_X86) && (KYLIN_MAJOR == 10 && KYLIN_MINOR == 4))) +#define DRIVER_SUPPORT_PRIV_BUSY +#endif + +struct ps3_scsi_priv_data { + struct PS3DiskDevPos disk_pos; + struct ps3_dev_io_statis statis; + struct ps3_vd_stream_detect vd_sd[2]; + struct ps3_r1x_lock_mgr lock_mgr; + struct ps3_r1x_read_balance_info *r1x_rb_info; + U8 is_taskmgmt_enable; + U8 task_manager_busy; + U8 dev_type; + U8 task_abort_timeout; + U8 task_reset_timeout; + U8 encl_id; + U8 phy_id; + U8 reserved; + ps3_atomic32 rd_io_outstand; + ps3_atomic32 wr_io_outstand; + ps3_atomic32 r1x_read_cmd_swap_total_cnt; + ps3_atomic32 r1x_read_cmd_swap_res_cnt; +#if defined DRIVER_SUPPORT_PRIV_BUSY + ps3_atomic32 sdev_priv_busy; +#else + U8 reserved1[4]; +#endif + ULong ata_cmd_busy; + Bool dev_deling; + Bool swap_flag; + U16 qmask_count; + U8 reserved2[6]; +}; + +#ifdef _WINDOWS + +struct scsi_device_real { + struct scsi_device sdev; + struct ps3_scsi_priv_data hostdata; +}; + +#define PS3_SDEV_PRI_DATA(sdev) \ + ((struct ps3_scsi_priv_data*)&(((struct scsi_device_real *)(sdev))->hostdata)) +#define PS3_SDEV_POS(sdev) \ + (&(PS3_SDEV_PRI_DATA(sdev)->disk_pos)) +#define PS3_SDEV_CHANNEL(sdev) \ + (PS3_CHANNEL(PS3_SDEV_POS(sdev))) +#define PS3_SDEV_TARGET(sdev) \ + (PS3_TARGET(PS3_SDEV_POS(sdev))) +#define PS3_SDEV_PDID(sdev) \ + (PS3_PDID(PS3_SDEV_POS(sdev))) +#define PS3_SDEV_MAGIC(sdev) \ + (PS3_SDEV_POS(sdev)->diskMagicNum) +#else +#define PS3_SDEV_CHANNEL(sdev) \ + ((sdev)->channel) +#define PS3_SDEV_TARGET(sdev) \ + ((sdev)->id) + +#define PS3_SDEV_PRI_DATA(sdev) \ + ((struct ps3_scsi_priv_data*)((sdev)->hostdata)) +#endif + +struct ps3_channel { + U8 channel; + U8 reserved0; + U16 max_dev_num; + U16 channel_start_num; + U8 reserved1[2]; +}; + +struct ps3_dev_pool { + union PS3Device *devs_buffer; + union PS3Device *devs[PS3_MAX_CHANNEL_NUM]; +}; + +struct ps3_pd_entry { + struct PS3DiskDevPos disk_pos; + U8 state; + U8 config_flag; + U8 RWCT; + U8 scsi_interface_type; + U8 task_abort_timeout; + U8 task_reset_timeout; + U8 dev_type; + union { + struct { + U8 support_ncq:1; + U8 protect:1; + U8 is_direct_disable:1; + U8 reserved:5; + }; + U8 pd_flags; + }; + U32 max_io_size; + U32 dev_queue_depth; + U8 encl_id; + U8 phy_id; + U16 sector_size; + U16 dma_addr_alignment; + U16 dma_len_alignment; + struct sas_rphy *sas_rphy; + U16 normal_quota; + U16 direct_quota; +}; + +struct ps3_pd_table { + U16 *pd_idxs_array; + U16 *pd_idxs[PS3_MAX_CHANNEL_NUM]; +}; + +struct ps3_vd_table { + U16 *vd_idxs_array; + U16 *vd_idxs[PS3_MAX_CHANNEL_NUM]; +}; + +struct ps3_pri_data_table { + struct ps3_scsi_priv_data **vd_pri_data_idxs_array; + struct ps3_scsi_priv_data **vd_pri_data_idxs[PS3_MAX_CHANNEL_NUM]; +}; + +struct ps3_dev_context { + struct ps3_vd_table vd_table[PS3_VD_TABLE_NUM]; + struct ps3_pd_table pd_table; + struct PS3VDEntry *vd_entries_array[PS3_VD_TABLE_NUM]; + struct ps3_pd_entry *pd_entries_array; + struct ps3_channel channel_pd[PS3_MAX_CHANNEL_NUM]; + struct ps3_channel channel_vd[PS3_MAX_CHANNEL_NUM]; + struct ps3_pri_data_table vd_pri_data_table; + + U16 max_dev_in_channel[PS3_MAX_CHANNEL_NUM]; + volatile U8 subwork; + U8 reserved[3]; + struct ps3_dev_pool vd_pool; + struct ps3_dev_pool pd_pool; + + dma_addr_t pd_list_buf_phys; + struct PS3DevList *pd_list_buf; + dma_addr_t vd_list_buf_phys; + struct PS3DevList *vd_list_buf; + dma_addr_t pd_info_buf_phys; + struct PS3PDInfo *pd_info_buf; + dma_addr_t vd_info_buf_phys_sync; + struct PS3VDInfo *vd_info_buf_sync; + dma_addr_t vd_info_buf_phys_async; + struct PS3VDInfo *vd_info_buf_async; + + struct ps3_cmd *vd_pending_cmd; + struct ps3_cmd *vdpending_abort_cmd; + volatile U32 abort_vdpending_cmd; + ps3_atomic32 is_vdpending_abort; + + U16 total_vd_count; + U16 total_pd_count; + U16 max_dev_per_channel; + U8 vd_table_idx; + U8 pd_channel_count; + U8 vd_channel_count; + ps3_mutex dev_priv_lock; +#ifdef _WINDOWS + U8 channel_map_rang_num; + U8 total_os_channel; + struct ps3_windows_private_table windows_table; + + U8 reserved2[3]; + KEVENT disk_sync; + ps3_spinlock dev_lock; +#else + U8 reserved2[7]; +#endif + ps3_mutex dev_scan_lock; +}; + +S32 ps3_dev_mgr_cli_register(void); + +S32 ps3_device_mgr_init(struct ps3_instance *instance); + +void ps3_device_mgr_exit(struct ps3_instance *instance); + +S32 ps3_device_mgr_data_init(struct ps3_instance *instance); + +S32 ps3_device_mgr_data_exit(struct ps3_instance *instance); + +S32 ps3_dev_mgr_vd_info_subscribe(struct ps3_instance *instance); + +S32 ps3_dev_mgr_vd_info_unsubscribe(struct ps3_instance *instance); +S32 ps3_dev_mgr_vd_info_resubscribe(struct ps3_instance *instance); + +void ps3_dev_mgr_vd_info_clear(struct ps3_instance *instance); + +S32 ps3_dev_mgr_pd_info_get(struct ps3_instance *instance, U16 channel, + U16 target_id, U16 pd_id); + +struct ps3_pd_entry *ps3_dev_mgr_pd_info_find_by_id( + struct ps3_instance *instance, U16 disk_id); + +S32 ps3_dev_mgr_pd_list_get(struct ps3_instance *instance); + +S32 ps3_dev_mgr_vd_list_get(struct ps3_instance *instance); + +S32 ps3_vd_info_get_all(struct ps3_instance *instance); + +static inline U16 get_offset_of_vdid(U16 offsetOfVDID, U16 virtDiskID) +{ + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + + if ( virtDiskID >= offsetOfVDID ) { + virtDiskIdx = virtDiskID - offsetOfVDID; + } + + return virtDiskIdx; +} + +Bool ps3_dev_id_valid_check(struct ps3_instance *instance, U8 channel, + U16 target_id, U8 dev_type); + +U8 ps3_get_vd_raid_level( + struct ps3_instance *instance, U8 channel, U16 target_id); + +struct ps3_scsi_priv_data *ps3_dev_mgr_lookup_vd_pri_data( + struct ps3_instance *instance, U8 channel, U16 target_id); + +struct PS3VDEntry *ps3_dev_mgr_lookup_vd_info( + struct ps3_instance *instance, U8 channel, U16 target_id); + +struct ps3_pd_entry *ps3_dev_mgr_lookup_pd_info( + struct ps3_instance *instance, U8 channel, U16 target_id); + +struct PS3VDEntry *ps3_dev_mgr_lookup_vd_info_by_id( + struct ps3_instance *instance, U16 disk_id); + +struct ps3_pd_entry *ps3_dev_mgr_lookup_pd_info_by_id( + struct ps3_instance *instance, U16 disk_id); + +union PS3Device* ps3_dev_mgr_lookup_vd_list( + struct ps3_instance *instance, U8 channel, U16 target_id); + +union PS3Device* ps3_dev_mgr_lookup_pd_list( + struct ps3_instance *instance, U8 channel, U16 target_id); + +#ifndef _WINDOWS +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) +S32 ps3_change_queue_depth(struct scsi_device *sdev, + S32 queue_depth, S32 reason); +#else +S32 ps3_change_queue_depth(struct scsi_device *sdev, + S32 queue_depth); +#endif + +S32 ps3_scsi_slave_alloc(struct scsi_device *sdev); + +void ps3_scsi_slave_destroy(struct scsi_device *sdev); + +S32 ps3_scsi_slave_configure(struct scsi_device *sdev); +#endif +static inline Bool ps3_check_pd_is_vd_member(U8 config_flag) +{ + return (config_flag != MIC_PD_STATE_JBOD && + config_flag != MIC_PD_STATE_READY && + config_flag != MIC_PD_STATE_UNKNOWN + ); +} + +static inline U8 ps3_get_converted_dev_type(U8 driverType, U8 mediumType) +{ + U8 dev_type = PS3_DEV_TYPE_UNKNOWN; + + switch (driverType) { + case DRIVER_TYPE_SAS: + if (mediumType == DEVICE_TYPE_HDD) { + dev_type = PS3_DEV_TYPE_SAS_HDD; + } else if (mediumType == DEVICE_TYPE_SSD) { + dev_type = PS3_DEV_TYPE_SAS_SSD; + } + break; + case DRIVER_TYPE_SATA: + if (mediumType == DEVICE_TYPE_HDD) { + dev_type = PS3_DEV_TYPE_SATA_HDD; + } else if (mediumType == DEVICE_TYPE_SSD) { + dev_type = PS3_DEV_TYPE_SATA_SSD; + } + break; + case DRIVER_TYPE_SES: + if (mediumType == DEVICE_TYPE_ENCLOSURE) { + dev_type = PS3_DEV_TYPE_SES; + } + break; + case DRIVER_TYPE_VEP: + if (mediumType == DEVICE_TYPE_ENCLOSURE) { + dev_type = PS3_DEV_TYPE_VEP; + } + break; + case DRIVER_TYPE_NVME: + if (mediumType == DEVICE_TYPE_SSD) { + dev_type = PS3_DEV_TYPE_NVME_SSD; + } + break; + default: + break; + } + return dev_type; +}; + +void ps3_change_sdev_max_sector(struct ps3_instance *instance, + struct PS3VDEntry *vd_entry); + +void ps3_vd_info_show(const struct ps3_instance *instance, + const struct PS3VDEntry *vd_entry); +S32 ps3_adjust_queue_depth(struct ps3_instance *instance, + U8 dev_type, U32 queue_depth); + +static inline const char *ps3_get_vd_access_plolicy_str(VDAccessPolicy_e policy) +{ + static const char *vdAccessPolicyName[] = { + [VD_ACCESS_POLICY_READ_WRITE] = "RW", + [VD_ACCESS_POLICY_READ_ONLY] = "RO", + [VD_ACCESS_POLICY_BLOCK] = "BLOCK", + [VD_ACCESS_POLICY_REMOVE_ACCESS] = "REMOVE_ACCESS", + }; + + return (policy < ARRAY_SIZE(vdAccessPolicyName)) ? + vdAccessPolicyName[policy] : "Unknown"; +} + +static inline Bool ps3_is_hdd_pd(U8 dev_type) +{ + return (dev_type == PS3_DEV_TYPE_SAS_HDD || dev_type == PS3_DEV_TYPE_SATA_HDD); +} + +void ps3_vd_busy_scale_get(struct PS3VDEntry *vd_entry); +void ps3_sdev_bdi_stable_writes_set(struct ps3_instance *instance, struct scsi_device *sdev); + +void ps3_sdev_bdi_stable_writes_clear(struct ps3_instance *instance, struct scsi_device *sdev); +S32 ps3_sdev_bdi_stable_writes_get(struct scsi_device *sdev); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_device_manager_sas.c b/drivers/scsi/ps3stor/ps3_device_manager_sas.c new file mode 100644 index 0000000000000000000000000000000000000000..8d39bebf8ad450dd1aa13b4a71b49ffc4a61f5ca --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_device_manager_sas.c @@ -0,0 +1,2026 @@ +#ifndef _WINDOWS + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ps3_device_manager_sas.h" +#include "ps3_sas_transport.h" +#include "ps3_util.h" +#include "ps3_mgr_cmd.h" + +static S32 ps3_sas_expander_event_update(struct ps3_instance *instance, U8 encl_id); + +Bool ps3_sas_is_support_smp(struct ps3_instance *instance) +{ + return instance->sas_dev_context.is_support_smp; +} + +static inline Bool ps3_is_sata_end_device(struct ps3_pd_entry *pd_entry) +{ + return (pd_entry->dev_type == PS3_DEV_TYPE_SATA_HDD || + pd_entry->dev_type == PS3_DEV_TYPE_SATA_SSD); +} + +S32 ps3_sas_rphy_slot_get(struct ps3_instance *instance, U64 sas_addr, U32 *slot_id) +{ + S32 ret = -PS3_FAILED; + struct ps3_sas_node *ps3_sas_node = &instance->sas_dev_context.ps3_hba_sas; + struct ps3_sas_port *ps3_sas_port = NULL; + ULong flags = 0; + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + list_for_each_entry(ps3_sas_port, &ps3_sas_node->sas_port_list, list) { + if (ps3_sas_port->remote_identify.sas_address == + sas_addr) { + *slot_id = ps3_sas_node->phys[ps3_sas_port-> + remote_identify.phy_identifier].slot_id; + ret = PS3_SUCCESS; + INJECT_START(PS3_ERR_IJ_SAS_RPHY_SLOT_GET_FAILED, &ret) + goto l_out; + } + } + + list_for_each_entry(ps3_sas_node, + &instance->sas_dev_context.ps3_sas_node_list, list) { + list_for_each_entry(ps3_sas_port, + &ps3_sas_node->sas_port_list, list) { + if (ps3_sas_port->remote_identify.sas_address == + sas_addr) { + *slot_id = ps3_sas_node->phys[ps3_sas_port-> + remote_identify.phy_identifier].slot_id; + ret = PS3_SUCCESS; + INJECT_START(PS3_ERR_IJ_SAS_EXP_RPHY_SLOT_GET_FAILED, &ret) + goto l_out; + } + } + } +l_out: + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + return ret; +} + +U64 ps3_sas_rphy_parent_sas_addr_get(struct ps3_instance *instance, U64 sas_addr) +{ + struct ps3_sas_node *ps3_sas_node = NULL; + struct ps3_sas_port *ps3_sas_port = NULL; + struct ps3_sas_phy *ps3_sas_phy = NULL; + + U64 encl_id = PS3_SAS_INVALID_SAS_ADDR; + ULong flags = 0; + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + list_for_each_entry(ps3_sas_port, + &instance->sas_dev_context.ps3_hba_sas.sas_port_list, list) { + if (ps3_sas_port->remote_identify.sas_address != + sas_addr) { + continue; + } + + list_for_each_entry(ps3_sas_phy, + &ps3_sas_port->phy_list, port_siblings) { + if (ps3_sas_phy->remote_identify.sas_address == + sas_addr) { + encl_id = ps3_sas_phy->identify.sas_address; + goto l_out; + } + } + } + + list_for_each_entry(ps3_sas_node, + &instance->sas_dev_context.ps3_sas_node_list, list) { + list_for_each_entry(ps3_sas_port, + &ps3_sas_node->sas_port_list, list) { + if (ps3_sas_port->remote_identify.sas_address == + sas_addr) { + encl_id = ps3_sas_node->sas_address; + goto l_out; + } + } + } +l_out: + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + return encl_id; +} + +U8 ps3_sas_encl_id_get(struct ps3_instance *instance, U64 sas_addr) +{ + U8 encl_id = PS3_SAS_INVALID_ID; + struct ps3_sas_node *ps3_sas_node = NULL; + ULong flags = 0; + U8 i = 0; + + for (i = 0; i < PS3_SAS_HBA_MAX_SAS_NUM; i++) { + if (instance->sas_dev_context.ps3_hba_sas_addr[i] == sas_addr) { + return instance->sas_dev_context.ps3_hba_sas.encl_id; + } + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_for_each_entry(ps3_sas_node, + &instance->sas_dev_context.ps3_sas_node_list, list) { + if (ps3_sas_node->sas_address == sas_addr) { + encl_id = ps3_sas_node->encl_id; + goto l_out; + } + } +l_out: + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + return encl_id; +} + +static void ps3_sas_node_phy_init(struct ps3_sas_phy *ps3_phy, + struct ps3_sas_node *sas_node, struct PS3PhyInfo *phy_info) +{ + ps3_phy->phy_id = phy_info->phyId; + ps3_phy->encl_id = sas_node->encl_id; + ps3_phy->slot_id = phy_info->slotId; + + ps3_phy->identify.device_type = sas_node->dev_type; + ps3_phy->identify.sas_address = le64_to_cpu(phy_info->sasAddr); + ps3_phy->identify.initiator_port_protocols = + phy_info->initiatorPortProtocol; + ps3_phy->identify.target_port_protocols = + phy_info->targetPortProtocols; + ps3_phy->identify.phy_identifier = phy_info->phyId; + + if (phy_info->attachedSasAddr != PS3_SAS_INVALID_SAS_ADDR) { + ps3_phy->remote_identify.device_type = phy_info->attachDevType; + ps3_phy->remote_identify.sas_address = le64_to_cpu(phy_info->attachedSasAddr); + ps3_phy->remote_identify.initiator_port_protocols = + phy_info->attachInitiatorPortProtocol; + ps3_phy->remote_identify.target_port_protocols = + phy_info->attachTargetPortProtocols; + ps3_phy->remote_identify.phy_identifier = phy_info->phyId; + } +} + +static S32 ps3_sas_node_phy_add(struct ps3_instance *instance, + struct ps3_sas_phy *ps3_phy, struct ps3_sas_node *sas_node, + struct PS3PhyInfo *phy_info) +{ + S32 ret = PS3_SUCCESS; + struct sas_phy *sas_phy = NULL; + + INIT_LIST_HEAD(&ps3_phy->port_siblings); + sas_phy = sas_phy_alloc(sas_node->dev, phy_info->phyId); + INJECT_START(PS3_ERR_IJ_SAS_ALLOC_PHY_NULL1, &sas_phy); + if (sas_phy == NULL) { + LOG_ERROR("hno:%u alloc node[%d] phys[%d] buffer failed !\n", + PS3_HOST(instance), sas_node->encl_id, + phy_info->phyId); + ret = -PS3_ENOMEM; + goto l_out; + } + + ps3_sas_node_phy_init(ps3_phy, sas_node, phy_info); + sas_phy->identify = ps3_phy->identify; + + sas_phy->negotiated_linkrate = phy_info->negLinkRate; + sas_phy->minimum_linkrate = phy_info->minLinkRate; + sas_phy->maximum_linkrate = phy_info->maxLinkRate; + sas_phy->minimum_linkrate_hw = phy_info->minLinkRateHw; + sas_phy->maximum_linkrate_hw = phy_info->maxLinkRateHw; + + LOG_INFO("hno:%u phy %d in encl[%d], dev_type[%d]," + "sas_addr[%016llx], n_linkrate[%d], slot_id[%d], i_prol[%d], t_prol[%d], " + "remote_dev_type[%d], remote_sas_addr[%016llx], i_prol[%d], t_prol[%d]" + " min_linkr[%u:%u], max_linikr[%u:%u] !\n", + PS3_HOST(instance), sas_phy->identify.phy_identifier, + sas_node->encl_id, sas_phy->identify.device_type, + sas_phy->identify.sas_address, + sas_phy->negotiated_linkrate, phy_info->slotId, + sas_phy->identify.initiator_port_protocols, + sas_phy->identify.target_port_protocols, + ps3_phy->remote_identify.device_type, + ps3_phy->remote_identify.sas_address, + ps3_phy->remote_identify.initiator_port_protocols, + ps3_phy->remote_identify.target_port_protocols, + sas_phy->minimum_linkrate, sas_phy->minimum_linkrate_hw, + sas_phy->maximum_linkrate, sas_phy->maximum_linkrate_hw); + + ret = sas_phy_add(sas_phy); + INJECT_START(PS3_ERR_IJ_SAS_PHY_ADD_FAILED1, &ret); + if (ret != 0) { + LOG_ERROR("hno:%u add node[%d]-phys[%d] failed ret[%d] !\n", + PS3_HOST(instance), sas_node->encl_id, + phy_info->phyId, ret); + sas_phy_free(sas_phy); + goto l_out; + } + + ps3_phy->phy = sas_phy; +l_out: + return ret; +} + +void ps3_sas_node_phy_update(struct ps3_instance *instance, struct ps3_sas_phy *ps3_phy, + struct PS3PhyInfo *phy_info) +{ + instance = instance; + ps3_phy->identify.initiator_port_protocols = + phy_info->initiatorPortProtocol; + ps3_phy->identify.target_port_protocols = + phy_info->targetPortProtocols; +#if 0 + if (phy_info->attachedSasAddr != PS3_SAS_INVALID_SAS_ADDR) { +#endif + ps3_phy->remote_identify.device_type = phy_info->attachDevType; + ps3_phy->remote_identify.sas_address = phy_info->attachedSasAddr; + ps3_phy->remote_identify.initiator_port_protocols = + phy_info->attachInitiatorPortProtocol; + ps3_phy->remote_identify.target_port_protocols = + phy_info->attachTargetPortProtocols; + ps3_phy->remote_identify.phy_identifier = phy_info->phyId; +#if 0 + } +#endif + ps3_phy->phy->identify = ps3_phy->identify; + + ps3_phy->phy->negotiated_linkrate = phy_info->negLinkRate; + ps3_phy->phy->enabled = phy_info->enable; + ps3_phy->phy->minimum_linkrate = phy_info->minLinkRate; + ps3_phy->phy->maximum_linkrate = phy_info->maxLinkRate; + ps3_phy->phy->minimum_linkrate_hw = phy_info->minLinkRateHw; + ps3_phy->phy->maximum_linkrate_hw = phy_info->maxLinkRateHw; + + LOG_INFO_IN_IRQ(instance, "update phy %d, dev_type[%d], enable[%d]" + "sas_addr[%016llx], n_linkrate[%d], slot_id[%d], i_prol[%d], t_prol[%d], " + "remote_dev_type[%d], remote_sas_addr[%016llx], i_prol[%d], t_prol[%d]" + " min_linkr[%u:%u], max_linikr[%u:%u] !\n", + ps3_phy->phy->identify.phy_identifier, + ps3_phy->phy->identify.device_type, + ps3_phy->phy->enabled, + ps3_phy->phy->identify.sas_address, + ps3_phy->phy->negotiated_linkrate, phy_info->slotId, + ps3_phy->phy->identify.initiator_port_protocols, + ps3_phy->phy->identify.target_port_protocols, + ps3_phy->remote_identify.device_type, + ps3_phy->remote_identify.sas_address, + ps3_phy->remote_identify.initiator_port_protocols, + ps3_phy->remote_identify.target_port_protocols, + ps3_phy->phy->minimum_linkrate, + ps3_phy->phy->minimum_linkrate_hw, + ps3_phy->phy->maximum_linkrate, + ps3_phy->phy->maximum_linkrate_hw); +} + +static void ps3_sas_port_phy_update(struct ps3_instance *instance, + struct ps3_sas_node *sas_node) +{ + struct ps3_sas_port *ps3_sas_port = NULL; + struct ps3_sas_port *ps3_sas_port_next = NULL; + U8 i = 0; + ULong flags = 0; + + for (i = 0; i < sas_node->phy_count; i++) { + if (sas_node->phys[i].remote_identify.sas_address == 0 || + sas_node->phys[i].remote_identify.device_type == SAS_END_DEVICE) { + continue; + } + + if (sas_node->phys[i].attach_port != NULL) { + continue; + } + + list_for_each_entry_safe(ps3_sas_port, ps3_sas_port_next, + &sas_node->sas_port_list, list) { + if (sas_node->phys[i].remote_identify.sas_address == + ps3_sas_port->remote_identify.sas_address) { + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_add_tail(&sas_node->phys[i].port_siblings, &ps3_sas_port->phy_list); + sas_node->phys[i].attach_port = ps3_sas_port; + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + ps3_sas_port->phy_count++; + sas_port_add_phy(ps3_sas_port->port, sas_node->phys[i].phy); + } + } + } +} + +static struct ps3_sas_port* ps3_sas_port_find(struct ps3_instance *instance, + struct ps3_sas_node *exp_node, U64 sas_addr) +{ + struct ps3_sas_port *ps3_sas_port = NULL; + ULong flags = 0; + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_for_each_entry(ps3_sas_port, &exp_node->sas_port_list, list) { + if (ps3_sas_port->remote_identify.sas_address == sas_addr) { + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + return ps3_sas_port; + } + } + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + return NULL; +} + +static void ps3_sas_port_phy_add(struct ps3_instance *instance, + struct ps3_sas_port *ps3_sas_port, struct ps3_sas_phy *ps3_phy) +{ + struct ps3_sas_phy *tmp_phy = NULL; + ULong flags = 0; + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_for_each_entry(tmp_phy, &ps3_sas_port->phy_list, port_siblings) { + if (tmp_phy == ps3_phy) { + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + return; + } + } + list_add_tail(&ps3_phy->port_siblings, &ps3_sas_port->phy_list); + ps3_phy->attach_port = ps3_sas_port; + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + ps3_sas_port->phy_count++; + + sas_port_add_phy(ps3_sas_port->port, ps3_phy->phy); +} + +static struct sas_port* ps3_sas_sas_port_create(struct ps3_instance *instance, + struct ps3_sas_node *parent_node, struct list_head *phy_list) +{ + S32 ret = PS3_SUCCESS; + struct sas_port *sas_port = NULL; + struct ps3_sas_phy *ps3_phy = NULL; + + sas_port = sas_port_alloc_num(parent_node->dev); + INJECT_START(PS3_ERR_IJ_SAS_ALLOC_NUM_NULL, &sas_port); + if (sas_port == NULL) { + LOG_ERROR("hno:%u alloc sas_port on node[%d] failed !\n", + PS3_HOST(instance), parent_node->encl_id); + goto l_out; + } + + ret = sas_port_add(sas_port); + INJECT_START(PS3_ERR_IJ_SAS_PORT_ADD_FAILED, &ret); + if (ret != 0) { + LOG_ERROR("hno:%u add sas_port on node[%d] failed !\n", + PS3_HOST(instance), parent_node->encl_id); + goto l_failed; + } + + list_for_each_entry(ps3_phy, phy_list, port_siblings) { + LOG_DEBUG("hno:%u add phy[%d] in sas_port[%016llx] on node[%d] !\n", + PS3_HOST(instance), ps3_phy->phy_id, + ps3_phy->remote_identify.sas_address, + parent_node->encl_id); + sas_port_add_phy(sas_port, ps3_phy->phy); + } + + return sas_port; +l_failed: + sas_port_delete(sas_port); +l_out: + return NULL; +} + +static S32 ps3_sas_end_device_add_past(struct ps3_instance *instance, + struct ps3_sas_port *ps3_sas_port, struct ps3_pd_entry *pd_entry, + struct sas_rphy *sas_rphy) +{ + S32 ret = PS3_SUCCESS; + + if (ps3_sas_port->remote_identify.device_type != SAS_END_DEVICE) { + ret = PS3_SUCCESS; + goto l_out; + } + + sas_rphy->identify = ps3_sas_port->remote_identify; + ret = ps3_scsi_add_device_ack(instance, &pd_entry->disk_pos, + PS3_DISK_TYPE_PD); + INJECT_START(PS3_ERR_IJ_SAS_ADD_ACK_FAILED, &ret); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR("hno:%u rphy sas_addr[%016llx] end-device[%u:%u:%u] " + "magic[%#x] add scsi device ack NOK, ret %d\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address, + PS3_CHANNEL(&pd_entry->disk_pos), PS3_TARGET(&pd_entry->disk_pos), + PS3_PDID(&pd_entry->disk_pos), + pd_entry->disk_pos.diskMagicNum, ret); + ret = -PS3_ACTIVE_ERR; + } else { + LOG_WARN("hno:%u rphy sas_addr[%016llx] end-device[%u:%u:%u] add begin\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address, + PS3_CHANNEL(&pd_entry->disk_pos), PS3_TARGET(&pd_entry->disk_pos), + PS3_PDID(&pd_entry->disk_pos)); + scsi_scan_target(&sas_rphy->dev, PS3_CHANNEL(&pd_entry->disk_pos), + PS3_TARGET(&pd_entry->disk_pos), 0, SCSI_SCAN_INITIAL); + LOG_WARN("hno:%u rphy sas_addr[%016llx] end-device[%u:%u:%u] add end\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address, + PS3_CHANNEL(&pd_entry->disk_pos), PS3_TARGET(&pd_entry->disk_pos), + PS3_PDID(&pd_entry->disk_pos)); + } +l_out: + return ret; +} + +static S32 ps3_sas_port_rphy_create(struct ps3_instance *instance, + struct ps3_sas_port *ps3_sas_port) +{ + S32 ret = -PS3_FAILED; + struct sas_rphy *sas_rphy = NULL; + struct ps3_pd_entry *pd_entry = NULL; + + LOG_DEBUG("hno:%u enter port rphy create, type[%d], pdflatid[%d], sas_addr[%016llx]\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.device_type, + ps3_sas_port->pd_flat_id, + ps3_sas_port->remote_identify.sas_address); + + if (ps3_sas_port->remote_identify.device_type == SAS_END_DEVICE) { + sas_rphy = sas_end_device_alloc(ps3_sas_port->port); + } else { + sas_rphy = sas_expander_alloc(ps3_sas_port->port, + (enum sas_device_type)ps3_sas_port->remote_identify.device_type); + } + INJECT_START(PS3_ERR_IJ_SAS_ALLOC_PHY_NULL, &sas_rphy); + if (unlikely(sas_rphy == NULL)) { + LOG_ERROR("hno:%u alloc SAS rphy for sas_addr[%016llx] failed !\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address); + goto l_out; + } + + sas_rphy->identify = ps3_sas_port->remote_identify; + + if (ps3_sas_port->remote_identify.device_type == SAS_END_DEVICE) { + sas_rphy->identify.target_port_protocols = SAS_PROTOCOL_NONE; + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, + ps3_sas_port->pd_flat_id); + if (unlikely(pd_entry == NULL)) { + LOG_ERROR("hno:%u cannot find pd entry by pd_flat_id[%d] !\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id); + goto l_out; + } + } + + ret = sas_rphy_add(sas_rphy); + INJECT_START(PS3_ERR_IJ_SAS_PHY_ADD_FAILED, &ret); + if (unlikely(ret != 0)) { + LOG_ERROR("hno:%u add SAS rphy for sas_addr[%016llx] failed !\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address); + goto l_out; + } + + ret = ps3_sas_end_device_add_past(instance, ps3_sas_port, pd_entry, sas_rphy); + +l_out: + ps3_sas_port->rphy = sas_rphy; + LOG_DEBUG("hno:%u quit port rphy create, type[%d], pdflatid[%d], sas_addr[%016llx]\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.device_type, + ps3_sas_port->pd_flat_id, ps3_sas_port->remote_identify.sas_address); + return ret; +} + +struct ps3_sas_node* ps3_sas_find_node_by_sas_addr( + struct ps3_instance *instance, U64 sas_addr) +{ + struct ps3_sas_node *ps3_sas_node = NULL; + struct ps3_sas_node *ret_node = NULL; + ULong flags = 0; + U8 i = 0; + + for (i = 0; i < PS3_SAS_HBA_MAX_SAS_NUM; i++) { + if (instance->sas_dev_context.ps3_hba_sas_addr[i] == sas_addr) { + ret_node = &instance->sas_dev_context.ps3_hba_sas; + goto l_out; + } + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_for_each_entry(ps3_sas_node, + &instance->sas_dev_context.ps3_sas_node_list, list) { + if (ps3_sas_node->sas_address == sas_addr) { + ret_node = ps3_sas_node; + break; + } + } + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); +l_out: + return ret_node; +} + +static void ps3_sanity_check_clean(struct ps3_instance *instance, + struct ps3_sas_node *sas_node, U64 sas_address, struct ps3_sas_port *sas_port) +{ + struct ps3_sas_port *ps3_sas_port = NULL; + struct ps3_sas_port *ps3_sas_port_next = NULL; + struct ps3_sas_phy *ps3_sas_phy = NULL; + struct ps3_sas_phy *ps3_sas_phy_next = NULL; + struct ps3_sas_node *exp_node = NULL; + ULong flags = 0; + struct ps3_pd_entry *pd_entry = NULL; + + list_for_each_entry_safe(ps3_sas_port, ps3_sas_port_next, + &sas_node->sas_port_list, list) { + if (ps3_sas_port == sas_port) { + continue; + } + list_for_each_entry_safe(ps3_sas_phy, ps3_sas_phy_next, + &ps3_sas_port->phy_list, port_siblings) { + if (ps3_sas_phy->remote_identify.sas_address != + sas_address) { + continue; + } + + LOG_WARN("hno:%u phy[%d] sas_addr[%016llx] == new device SAS addr\n", + PS3_HOST(instance), ps3_sas_phy->phy_id, + ps3_sas_port->remote_identify.sas_address); + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_del(&ps3_sas_phy->port_siblings); + ps3_sas_phy->attach_port = NULL; + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + ps3_sas_port->phy_count--; + sas_port_delete_phy(ps3_sas_port->port, ps3_sas_phy->phy); + } + + if (ps3_sas_port->phy_count != 0){ + continue; + } + + if (ps3_sas_port->remote_identify.device_type == + SAS_EDGE_EXPANDER_DEVICE || + ps3_sas_port->remote_identify.device_type == + SAS_FANOUT_EXPANDER_DEVICE) { + + exp_node = ps3_sas_find_node_by_sas_addr(instance, + ps3_sas_port->remote_identify.sas_address); + if (exp_node == NULL) { + LOG_ERROR("hno:%u cannot find node sas_addr[%016llx] !\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address); + PS3_BUG(); + continue; + } + + ps3_sas_expander_node_del(instance, exp_node); + + }else if (ps3_sas_port->remote_identify.device_type == + SAS_END_DEVICE) { + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_del(&ps3_sas_port->list); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + LOG_INFO("hno:%u sas_port pdid[%u] delete start, by r SAS addr[0x%llx], change\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, sas_address); + + sas_port_delete(ps3_sas_port->port); + + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, ps3_sas_port->pd_flat_id); + if (pd_entry != NULL) { + pd_entry->sas_rphy = NULL; + } + + LOG_INFO("hno:%u sas_port pdid[%u] delete end, by r SAS addr[0x%llx], change\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, sas_address); + kfree(ps3_sas_port); + } + } + +} + +static S32 ps3_sas_port_create(struct ps3_instance *instance, + struct ps3_sas_node *sas_node, struct ps3_sas_port *ps3_sas_port) +{ + S32 ret = -PS3_FAILED; + ULong flags = 0; + + ps3_sas_port->port = ps3_sas_sas_port_create(instance, sas_node, + &ps3_sas_port->phy_list); + INJECT_START(PS3_ERR_IJ_SAS_PORT_CREATE_FAIL, ps3_sas_port); + if (unlikely(ps3_sas_port->port == NULL)) { + LOG_ERROR("hno:%u cannot add port on parent[%d] !\n", + PS3_HOST(instance), sas_node->encl_id); + + goto l_out; + } + + ret = ps3_sas_port_rphy_create(instance, ps3_sas_port); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR("hno:%u create rphy[%016llx] on parent[%d] NOK!\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address, + sas_node->encl_id); + goto l_failed; + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_add_tail(&ps3_sas_port->list, &sas_node->sas_port_list); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + goto l_out; +l_failed: + if (ps3_sas_port->port != NULL) { + sas_port_delete(ps3_sas_port->port); + ps3_sas_port->port = NULL; + } +l_out: + return ret; +} + +static void ps3_sas_port_del(struct ps3_instance *instance, + struct ps3_sas_port *ps3_sas_port) +{ + struct ps3_sas_phy *ps3_sas_phy = NULL; + struct ps3_sas_phy *ps3_sas_phy_next = NULL; + ULong flags = 0; + struct ps3_pd_entry *pd_entry = NULL; + + (void)instance; + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_del(&ps3_sas_port->list); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + list_for_each_entry_safe(ps3_sas_phy, ps3_sas_phy_next, + &ps3_sas_port->phy_list, port_siblings) { + + sas_port_delete_phy(ps3_sas_port->port, ps3_sas_phy->phy); + + list_del(&ps3_sas_phy->port_siblings); + ps3_sas_phy->attach_port = NULL; + ps3_sas_port->phy_count--; + } + + LOG_INFO("hno:%u sas_port pdid[%u] phy_count[%u] delete start\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, ps3_sas_port->phy_count); + sas_port_delete(ps3_sas_port->port); + + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, ps3_sas_port->pd_flat_id); + if (pd_entry != NULL) { + pd_entry->sas_rphy = NULL; + } + + LOG_WARN("hno:%u sas_port pdid[%u] phy_count[%u] delete end\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, ps3_sas_port->phy_count); + + kfree(ps3_sas_port); + +} + +static S32 ps3_sas_end_device_try_add(struct ps3_instance *instance, + struct ps3_sas_node *sas_node, struct ps3_sas_phy *ps3_phy, + struct ps3_pd_entry *pd_entry) +{ + S32 ret = PS3_SUCCESS; + struct ps3_sas_port *ps3_sas_port = NULL; + + LOG_DEBUG("hno:%u ready add end device[%016llx] on node[%d]\n", + PS3_HOST(instance), ps3_phy->remote_identify.sas_address, + sas_node->encl_id); + + ps3_sas_port = ps3_sas_port_find(instance, sas_node, + ps3_phy->remote_identify.sas_address); + + ps3_sanity_check_clean(instance, sas_node, ps3_phy->remote_identify.sas_address, ps3_sas_port); + + if (ps3_sas_port != NULL) { + LOG_DEBUG("hno:%u find exist port[%016llx] on node[%d]\n", + PS3_HOST(instance), ps3_phy->remote_identify.sas_address, + sas_node->encl_id); + if (ps3_is_sata_end_device(pd_entry) && + ps3_sas_port->pd_flat_id != PS3_PDID(&pd_entry->disk_pos)) { + LOG_INFO("hno:%u sata end device [%u:%u] not exist but in port\n", + PS3_HOST(instance), PS3_CHANNEL(&pd_entry->disk_pos), + PS3_TARGET(&pd_entry->disk_pos)); + ps3_sas_port_del(instance, ps3_sas_port); + ps3_sas_port = NULL; + } else { + ps3_sas_port_phy_add(instance, ps3_sas_port, ps3_phy); + goto l_out; + } + } + + ps3_sas_port = (struct ps3_sas_port *)ps3_kzalloc(instance, sizeof(struct ps3_sas_port)); + INJECT_START(PS3_ERR_IJ_SAS_PORT_ALLOC_NULL, &ps3_sas_port); + if (ps3_sas_port == NULL) { + LOG_ERROR("hno:%u alloc PS3 port on node[%d] failed !\n", + PS3_HOST(instance), sas_node->encl_id); + ret = -PS3_FAILED; + goto l_out; + } + + INIT_LIST_HEAD(&ps3_sas_port->phy_list); + ps3_sas_port->remote_identify = ps3_phy->remote_identify; + list_add_tail(&ps3_phy->port_siblings, &ps3_sas_port->phy_list); + ps3_phy->attach_port = ps3_sas_port; + ps3_sas_port->phy_count++; + ps3_sas_port->pd_flat_id = pd_entry->disk_pos.diskDev.ps3Dev.phyDiskID; + ret = ps3_sas_port_create(instance, sas_node, ps3_sas_port); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u create end device rphy[%016llx] on parent[%d] NOK!\n", + PS3_HOST(instance), ps3_phy->remote_identify.sas_address, sas_node->encl_id); + goto l_failed; + } + pd_entry->sas_rphy = ps3_sas_port->rphy; + + goto l_out; +l_failed: + list_del(&ps3_phy->port_siblings); + ps3_phy->attach_port = NULL; + kfree(ps3_sas_port); + +l_out: + LOG_DEBUG("hno:%u add end device[%016llx] on node[%d] end\n", + PS3_HOST(instance), ps3_phy->remote_identify.sas_address, + sas_node->encl_id); + + return ret; +} + +static S32 ps3_sas_node_all_phys_add(struct ps3_instance *instance, + struct ps3_sas_node *sas_node) +{ + S32 ret = PS3_SUCCESS; + struct PS3SasMgr sas_req_param; + struct PS3PhyInfo *phy_info = instance->sas_dev_context.ps3_sas_phy_buff; + U8 i = 0; + + memset(&sas_req_param, 0, sizeof(sas_req_param)); + sas_req_param.enclID = sas_node->encl_id; + sas_req_param.startPhyID = 0; + sas_req_param.phyCount = sas_node->phy_count; + sas_req_param.sasAddr = sas_node->sas_address; + + memset(phy_info, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_phy_get(instance, &sas_req_param); + INJECT_START(PS3_ERR_IJ_SAS_PHY_GET_ERR1, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u get encl[%d] all phys info NOK\n", + PS3_HOST(instance), sas_req_param.enclID); + goto l_out; + } + + for (i = 0; i < sas_node->phy_count; i++) { + ret = ps3_sas_node_phy_add(instance, &sas_node->phys[i], + sas_node, &phy_info[i]); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add node[%d]-phys[%d] NOK !\n", + PS3_HOST(instance), sas_node->encl_id, i); + goto l_out; + } +#if 0 + 不能再此添加,需要通过scsi那边进行添加,否则无法定序,分配正确的channel + if ((phy_info[i].attachedSasAddr != PS3_SAS_INVALID_SAS_ADDR && + phy_info[i].attachDevType == SAS_END_DEVICE) && + phy_info[i].attachedSasAddr != + sas_node->parent_sas_address) { + ret = ps3_sas_end_device_try_add(instance, sas_node, + &sas_node->phys[i]); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add end device[%016llx] on node[%d]-phys[%d] failed !\n", + PS3_HOST(instance), + phy_info[i].attachedSasAddr, + sas_node->encl_id, i); + goto l_out; + } + } +#endif + } +l_out: + return ret; +} + +static S32 ps3_sas_hba_node_init(struct ps3_instance *instance, + struct PS3ExpanderInfo *exp_info, U64 *hba_sas_addr) +{ + S32 ret = PS3_SUCCESS; + U8 i = 0; + struct ps3_sas_node *hba_node = + &instance->sas_dev_context.ps3_hba_sas; + + LOG_DEBUG("hno:%u enter !\n", PS3_HOST(instance)); + + for (i = 0; i < PS3_SAS_HBA_MAX_SAS_NUM; i++) { + instance->sas_dev_context.ps3_hba_sas_addr[i] = + le64_to_cpu(hba_sas_addr[i]); + LOG_INFO("hno:%u hba SAS addr[%d] is [%016llx] !\n", + PS3_HOST(instance), i, + instance->sas_dev_context.ps3_hba_sas_addr[i]); + } + + hba_node->encl_id = exp_info->enclID; + hba_node->phy_count = exp_info->phyCount; + hba_node->dev_type = exp_info->devType; + + LOG_INFO("hno:%u hba encl_id[%d], phy_count[%d], dev_type[%d] !\n", + PS3_HOST(instance), hba_node->encl_id, hba_node->phy_count, + hba_node->dev_type); + + if (hba_node->phys == NULL) { + hba_node->phys = (struct ps3_sas_phy*)ps3_kcalloc(instance, hba_node->phy_count, + sizeof(struct ps3_sas_phy)); + } + if (hba_node->phys == NULL) { + LOG_ERROR("hno:%u alloc hba phys buffer failed !\n", + PS3_HOST(instance)); + goto l_out; + } + + ret = ps3_sas_node_all_phys_add(instance, hba_node); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u hba add phys NOK !\n", + PS3_HOST(instance)); + goto l_out; + } + +l_out: + LOG_DEBUG("hno:%u quit !\n", PS3_HOST(instance)); + return ret; +} + +static struct ps3_sas_node* ps3_sas_find_node_by_id(struct ps3_instance *instance, + U8 encl_id) +{ + struct ps3_sas_node *ps3_sas_node = NULL; + ULong flags = 0; + + if (instance->sas_dev_context.ps3_hba_sas.encl_id == encl_id) { + return &instance->sas_dev_context.ps3_hba_sas; + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_for_each_entry(ps3_sas_node, + &instance->sas_dev_context.ps3_sas_node_list, list) { + if (ps3_sas_node->encl_id == encl_id) { + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + return ps3_sas_node; + } + } + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + return NULL; +} + +static struct ps3_sas_port* ps3_sas_expander_parent_attach(struct ps3_instance *instance, + struct ps3_sas_node *exp_node) +{ + S32 ret = -PS3_FAILED; + struct ps3_sas_node *parent_node = NULL; + struct ps3_sas_port *ps3_sas_port = NULL; + U8 i = 0; + ULong flags = 0; + Bool is_exist_port = PS3_TRUE; + struct ps3_sas_phy *sas_phy = NULL; + struct ps3_sas_phy *sas_phy_next = NULL; + + parent_node = ps3_sas_find_node_by_id(instance, + exp_node->parent_encl_id); + if (parent_node == NULL) { + LOG_ERROR("hno:%u cannot find parent node[%d] !\n", + PS3_HOST(instance), exp_node->parent_encl_id); + goto l_out; + } + + ps3_sas_port = ps3_sas_port_find(instance, parent_node, exp_node->sas_address); + if (ps3_sas_port == NULL) { + ps3_sas_port = (struct ps3_sas_port*)ps3_kzalloc(instance, sizeof(struct ps3_sas_port)); + INJECT_START(PS3_ERR_IJ_SAS_PORT_ALLOC_NULL1, &ps3_sas_port); + if (ps3_sas_port == NULL) { + LOG_ERROR("hno:%u alloc PS3 port on node[%d] failed !\n", + PS3_HOST(instance), parent_node->encl_id); + goto l_out; + } + INIT_LIST_HEAD(&ps3_sas_port->phy_list); + is_exist_port = PS3_FALSE; + } + + ps3_sanity_check_clean(instance, parent_node, exp_node->sas_address, ps3_sas_port); + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + for (i = 0; i < parent_node->phy_count; i++) { + if ((parent_node->phys[i].remote_identify.sas_address == + exp_node->sas_address) && + (parent_node->phys[i].attach_port == NULL)) { + if (ps3_sas_port->phy_count == 0) { + ps3_sas_port->remote_identify = + parent_node->phys[i].remote_identify; + } + list_add_tail(&parent_node->phys[i].port_siblings, + &ps3_sas_port->phy_list); + parent_node->phys[i].attach_port = ps3_sas_port; + ps3_sas_port->phy_count++; + if (is_exist_port && ps3_sas_port->port != NULL) { + sas_port_add_phy(ps3_sas_port->port, parent_node->phys[i].phy); + } + } + } + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + if (!is_exist_port) { + if (ps3_sas_port->phy_count == 0) { + LOG_ERROR("hno:%u cannot find phy in parent[%d] !\n", + PS3_HOST(instance), parent_node->encl_id); + goto l_failed; + } + + ret = ps3_sas_port_create(instance, parent_node, ps3_sas_port); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u create rphy on parent[%d] for exp[%d] !\n", + PS3_HOST(instance), parent_node->encl_id, exp_node->encl_id); + goto l_failed; + } + + exp_node->dev = &ps3_sas_port->rphy->dev; + } +l_out: + return ps3_sas_port; + +l_failed: + list_for_each_entry_safe(sas_phy, sas_phy_next, + &ps3_sas_port->phy_list, port_siblings) { + sas_phy->attach_port = NULL; + list_del(&sas_phy->port_siblings); + } + kfree(ps3_sas_port); + + return NULL; +} + +static S32 ps3_sas_expander_node_add(struct ps3_instance *instance, + struct PS3ExpanderInfo *exp_info) +{ + S32 ret = PS3_SUCCESS; + struct ps3_sas_node *exp_node = NULL; + struct ps3_sas_port *ps3_sas_port = NULL; + Bool is_exist_expander = PS3_TRUE; + ULong flags = 0; + U8 old_parent_id = PS3_SAS_INVALID_ID; + + LOG_DEBUG("hno:%u enter !\n", PS3_HOST(instance)); + + if ((exp_node = ps3_sas_find_node_by_id(instance, exp_info->enclID)) != NULL && + unlikely(exp_node->parent_sas_address != exp_info->parentSasAddr || + exp_node->parent_encl_id != exp_info->parentId)) { + LOG_WARN("hno:%u SAS node encl_id[%d], change place, " + "parent sas_addr old[0x%016llx]-new[0x%016llx], parent_encl_id old[%d]=new[%d]\n", + PS3_HOST(instance), exp_info->enclID, + exp_node->parent_sas_address, + exp_info->parentSasAddr, exp_node->parent_encl_id, + exp_info->parentId); + old_parent_id = exp_node->parent_encl_id; + ps3_sas_expander_node_del(instance, exp_node); + ps3_sas_expander_event_update(instance, old_parent_id); + exp_node = NULL; + } + + if (exp_node == NULL) { + exp_node = (struct ps3_sas_node*)ps3_kzalloc(instance, sizeof(struct ps3_sas_node)); + INJECT_START(PS3_ERR_IJ_ALLOC_EXP_NODE_NULL, &exp_node); + if (exp_node == NULL) { + LOG_ERROR("hno:%u alloc node[%d] failed !\n", + PS3_HOST(instance), exp_info->enclID); + goto l_out; + } + + exp_node->sas_address = le64_to_cpu(exp_info->sasAddr); + exp_node->encl_id = exp_info->enclID; + exp_node->phy_count = exp_info->phyCount; + exp_node->dev_type = exp_info->devType; + exp_node->parent_encl_id = exp_info->parentId; + exp_node->parent_sas_address = le64_to_cpu(exp_info->parentSasAddr); + + exp_node->phys = (struct ps3_sas_phy*)ps3_kcalloc(instance, exp_node->phy_count, + sizeof(struct ps3_sas_phy)); + INJECT_START(PS3_ERR_IJ_ALLOC_EXP_PHYS_NULL, &exp_node->phys); + if (exp_node->phys == NULL) { + LOG_ERROR("hno:%u alloc exp[%d] phys buffer failed !\n", + PS3_HOST(instance), exp_node->encl_id); + goto l_failed; + } + INIT_LIST_HEAD(&exp_node->sas_port_list); + is_exist_expander = PS3_FALSE; + } + + LOG_INFO("hno:%u ready add exp_node sas_address[0x%016llx]," + " encl_id[%d], phy_count[%d], parent_encl_id[%d]," + " parent_sas_address[0x%016llx] !\n", + PS3_HOST(instance), exp_node->sas_address, exp_node->encl_id, + exp_node->phy_count, exp_node->parent_encl_id, + exp_node->parent_sas_address); + + ps3_sas_port = ps3_sas_expander_parent_attach(instance, exp_node); + if (ps3_sas_port == NULL) { + LOG_ERROR("hno:%u attch exp[%d] on parent NOK !\n", + PS3_HOST(instance), exp_node->encl_id); + ret = -PS3_FAILED; + goto l_failed; + } + if (!is_exist_expander) { + ret = ps3_sas_node_all_phys_add(instance, exp_node); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u expander[%d] add phys NOK !\n", + PS3_HOST(instance), exp_node->encl_id); + goto l_failed; + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_add_tail(&exp_node->list,&instance->sas_dev_context.ps3_sas_node_list); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + LOG_WARN("hno:%u add exp_node sas_address[0x%016llx]," + " encl_id[%d], phy_count[%d], parent_encl_id[%d]," + " parent_sas_address[0x%016llx] end!\n", + PS3_HOST(instance), exp_node->sas_address, exp_node->encl_id, + exp_node->phy_count, exp_node->parent_encl_id, + exp_node->parent_sas_address); + } + goto l_out; + +l_failed: + if (ps3_sas_port != NULL) { + ps3_sas_port_del(instance, ps3_sas_port); + ps3_sas_port = NULL; + } + + if (exp_node->phys != NULL) { + kfree(exp_node->phys); + exp_node->phys = NULL; + } + + if (exp_node != NULL) { + kfree(exp_node); + exp_node = NULL; + } +l_out: + LOG_DEBUG("hno:%u quit !\n", PS3_HOST(instance)); + return ret; +} + +static void ps3_sas_expander_del_list_build(struct ps3_instance *instance, + struct list_head *node_del_list) +{ + struct ps3_sas_node *exp_node = NULL; + struct ps3_sas_node *child_exp_node = NULL; + struct ps3_sas_port *ps3_sas_port = NULL; + ULong flags = 0; + + list_for_each_entry(exp_node, node_del_list, list) { + list_for_each_entry(ps3_sas_port, &exp_node->sas_port_list, list) { + if ((ps3_sas_port->remote_identify.device_type != + SAS_EDGE_EXPANDER_DEVICE) && + (ps3_sas_port->remote_identify.device_type != + SAS_FANOUT_EXPANDER_DEVICE)) { + continue; + } + + child_exp_node = ps3_sas_find_node_by_sas_addr( + instance, + ps3_sas_port->remote_identify.sas_address); + if (child_exp_node != NULL) { + spin_lock_irqsave(&instance->sas_dev_context. + ps3_sas_node_lock, flags); + list_move_tail(&child_exp_node->list, + node_del_list); + spin_unlock_irqrestore(&instance->sas_dev_context. + ps3_sas_node_lock, flags); + } + } + } +} + +static void ps3_sas_node_del(struct ps3_instance *instance, + struct ps3_sas_node *exp_node) +{ + struct ps3_sas_port *ps3_sas_port = NULL; + struct ps3_sas_port *tmp_port = NULL; + + list_for_each_entry_safe(ps3_sas_port, tmp_port, + &exp_node->sas_port_list, list) { + + ps3_sas_port_del(instance, ps3_sas_port); + ps3_sas_port = NULL; + } + + kfree(exp_node->phys); +} + +static S32 ps3_sas_node_port_del(struct ps3_instance *instance, + struct ps3_sas_node *parent_node, U64 sas_addr) +{ + S32 ret = PS3_SUCCESS; + struct ps3_sas_port *ps3_port = NULL; + ps3_port = ps3_sas_port_find(instance, parent_node, sas_addr); + if (ps3_port == NULL) { + LOG_ERROR("hno:%u cannot find port[%016llx] in node[%d] !\n", + PS3_HOST(instance), sas_addr, parent_node->encl_id); + ret = -PS3_FAILED; + goto l_out; + } + + ps3_sas_port_del(instance, ps3_port); + ps3_port = NULL; +l_out: + return ret; +} + +void ps3_sas_expander_node_del(struct ps3_instance *instance, + struct ps3_sas_node *exp_node) +{ + S32 ret = PS3_SUCCESS; + struct ps3_sas_node *parent_node = NULL; + struct ps3_sas_node *del_exp_node = NULL; + struct ps3_sas_node *tmp_exp_node = NULL; + struct list_head node_del_list = {NULL, NULL}; + U64 sas_address = exp_node->sas_address; + ULong flags = 0; + + LOG_INFO("hno:%u enter !, encl_id[%d], parent_id[%d], sas_addr[%016llx]\n", PS3_HOST(instance), + exp_node->encl_id, exp_node->parent_encl_id, exp_node->sas_address); + + parent_node = ps3_sas_find_node_by_id(instance, + exp_node->parent_encl_id); + if (parent_node == NULL) { + LOG_ERROR("hno:%u cannot find parent node[%d] !\n", + PS3_HOST(instance), exp_node->parent_encl_id); + BUG(); + goto l_out; + } + + INIT_LIST_HEAD(&node_del_list); + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_move_tail(&exp_node->list, &node_del_list); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + ps3_sas_expander_del_list_build(instance, &node_del_list); + + list_for_each_entry_safe_reverse(del_exp_node, tmp_exp_node, + &node_del_list, list) { + LOG_DEBUG("hno:%u remove encl_id[%d], sas_addr[%016llx]\n", PS3_HOST(instance), + del_exp_node->encl_id, del_exp_node->sas_address); + ps3_sas_node_del(instance, del_exp_node); + list_del(&del_exp_node->list); + kfree(del_exp_node); + } + + LOG_WARN("hno:%u remove sas_addr[%016llx] from parent[%d]\n", PS3_HOST(instance), + sas_address, parent_node->encl_id); + + ret = ps3_sas_node_port_del(instance, parent_node, + sas_address); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u cannot delete expander[%016llx] from parent[%d] !\n", + PS3_HOST(instance), sas_address, + parent_node->encl_id); + BUG(); + goto l_out; + } +l_out: + LOG_DEBUG("hno:%u quit !\n", PS3_HOST(instance)); +} + +S32 ps3_sas_device_data_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct PS3Expanders *p_expanders = + (struct PS3Expanders *)instance->sas_dev_context.ps3_sas_buff; + struct PS3ExpanderInfo *exp_info = p_expanders->expanders; + U8 i = 0; + + if (!ps3_sas_is_support_smp(instance)) { + goto l_out; + } + + LOG_DEBUG("hno:%u ready get init expander enter\n", + PS3_HOST(instance)); + + + + memset(p_expanders, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_expander_all_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init get expander NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + LOG_INFO("hno:%u get expander list count[%d]\n", + PS3_HOST(instance), p_expanders->count); + + INJECT_START(PS3_ERR_HBA_PHY_COUNT_ZERO, &p_expanders->count); + if (p_expanders->count == 0) { + LOG_ERROR("hno:%u expander init info count = 0\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out;; + } + + ret = ps3_sas_hba_node_init(instance, exp_info, p_expanders->hbaSasAddr); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init hba info NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + for (i = 1; i < p_expanders->count; i++) { + ret = ps3_sas_expander_node_add(instance, &exp_info[i]); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init add expander[%d] info NOK\n", + PS3_HOST(instance), exp_info[i].enclID); + goto l_out; + } + } + + LOG_DEBUG("hno:%u SAS init end\n", + PS3_HOST(instance)); +l_out: + return ret ; +} + +S32 ps3_sas_device_data_exit(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + if (!ps3_sas_is_support_smp(instance)) { + goto l_out; + } + + LOG_INFO("hno:%u ps3_sas_device_data_exit\n", + PS3_HOST(instance)); + + + (void)instance; +l_out: + return ret; +} + +static S32 ps3_sas_expander_dma_buf_alloc(struct ps3_instance *instance) +{ + struct ps3_sas_dev_context *ps3_sas_ctx = &instance->sas_dev_context; + + ps3_sas_ctx->ps3_sas_buff = ps3_dma_alloc_coherent(instance, + PS3_SAS_REQ_BUFF_LEN, + &ps3_sas_ctx->ps3_sas_buff_dma_addr); + INJECT_START(PS3_ERR_IJ_PS3_SAS_BUF_ALLOC, &ps3_sas_ctx->ps3_sas_buff); + if (ps3_sas_ctx->ps3_sas_buff == NULL) { + LOG_ERROR("hno:%u alloc SAS req buffer failed !\n", + PS3_HOST(instance)); + goto l_fail; + } + return PS3_SUCCESS; +l_fail: + return -PS3_ENOMEM; +} + +static void ps3_sas_expander_dma_buf_free(struct ps3_instance *instance) +{ + struct ps3_sas_dev_context *ps3_sas_ctx = &instance->sas_dev_context; + + if (ps3_sas_ctx->ps3_sas_buff != NULL) { + ps3_dma_free_coherent(instance, PS3_SAS_REQ_BUFF_LEN, + ps3_sas_ctx->ps3_sas_buff, + ps3_sas_ctx->ps3_sas_buff_dma_addr); + + ps3_sas_ctx->ps3_sas_buff = NULL; + } +} + +static S32 ps3_sas_phy_dma_buf_alloc(struct ps3_instance *instance) +{ + struct ps3_sas_dev_context *ps3_sas_ctx = &instance->sas_dev_context; + + ps3_sas_ctx->ps3_sas_phy_buff = + (struct PS3PhyInfo *)ps3_dma_alloc_coherent(instance, + PS3_SAS_REQ_BUFF_LEN, + &ps3_sas_ctx->ps3_sas_phy_buff_dma_addr); + INJECT_START(PS3_ERR_IJ_PS3_SAS_PHY_BUF_ALLOC, &ps3_sas_ctx->ps3_sas_phy_buff); + if (ps3_sas_ctx->ps3_sas_phy_buff == NULL) { + LOG_ERROR("hno:%u alloc SAS req buffer failed !\n", + PS3_HOST(instance)); + goto l_fail; + } + return PS3_SUCCESS; +l_fail: + return -PS3_ENOMEM; +} + +static void ps3_sas_phy_dma_buf_free(struct ps3_instance *instance) +{ + struct ps3_sas_dev_context *ps3_sas_ctx = &instance->sas_dev_context; + + if (ps3_sas_ctx->ps3_sas_phy_buff != NULL) { + ps3_dma_free_coherent(instance, PS3_SAS_REQ_BUFF_LEN, + ps3_sas_ctx->ps3_sas_phy_buff, + ps3_sas_ctx->ps3_sas_phy_buff_dma_addr); + + ps3_sas_ctx->ps3_sas_phy_buff = NULL; + } +} + +S32 ps3_sas_device_mgr_init(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + U8 i = 0; + + if (instance->ioc_adpter->sas_transport_get != NULL) { + instance->sas_dev_context.is_support_smp = PS3_TRUE; + } else { + instance->sas_dev_context.is_support_smp = PS3_FALSE; + ret = PS3_SUCCESS; + LOG_INFO("hno:%u the IOC is not support SAS expander !\n", + PS3_HOST(instance)); + goto l_out; + } + + sema_init(&instance->sas_dev_context.ps3_sas_smp_semaphore, 1); + + ret = ps3_sas_expander_dma_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u alloc SAS expander dma buffer failed !\n", + PS3_HOST(instance)); + goto l_out; + } + + ret = ps3_sas_phy_dma_buf_alloc(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u alloc SAS phy dma buffer failed !\n", + PS3_HOST(instance)); + goto l_out; + } + + INIT_LIST_HEAD(&instance->sas_dev_context.ps3_sas_node_list); + spin_lock_init(&instance->sas_dev_context.ps3_sas_node_lock); + + memset(&instance->sas_dev_context.ps3_hba_sas, 0, + sizeof(struct ps3_sas_node)); + + for (i = 0; i < PS3_SAS_HBA_MAX_SAS_NUM; i++) { + instance->sas_dev_context.ps3_hba_sas_addr[i] = + PS3_SAS_INVALID_SAS_ADDR; + } + + INIT_LIST_HEAD(&instance->sas_dev_context.ps3_hba_sas.sas_port_list); + instance->sas_dev_context.ps3_hba_sas.parent_encl_id = + PS3_SAS_INVALID_ID; + instance->sas_dev_context.ps3_hba_sas.parent_sas_address = + PS3_SAS_INVALID_SAS_ADDR; + instance->sas_dev_context.ps3_hba_sas.dev = + &instance->host->shost_gendev; +l_out: + return ret ; +} + +S32 ps3_sas_device_mgr_exit(struct ps3_instance *instance) +{ + if (ps3_sas_is_support_smp(instance)) { + ps3_sas_phy_dma_buf_free(instance); + ps3_sas_expander_dma_buf_free(instance); + } + + return PS3_SUCCESS; +} + + +static void ps3_sas_end_dev_del(struct ps3_instance *instance, + struct ps3_sas_node* parent_node, U8 phy_id) +{ + struct ps3_sas_port *ps3_sas_port = NULL; + struct ps3_sas_port *ps3_sas_port_next = NULL; + struct ps3_sas_phy *ps3_sas_phy = NULL; + struct ps3_sas_phy *ps3_sas_phy_next = NULL; + Bool del_finish = PS3_FALSE; + ULong flags = 0; + struct ps3_pd_entry *pd_entry = NULL; + + (void)instance; + + list_for_each_entry_safe(ps3_sas_port, ps3_sas_port_next, &parent_node->sas_port_list, list) { + list_for_each_entry_safe(ps3_sas_phy, ps3_sas_phy_next, &ps3_sas_port->phy_list, port_siblings) { + if (likely(ps3_sas_phy->phy_id == phy_id)) { + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_del(&ps3_sas_phy->port_siblings); + ps3_sas_phy->attach_port = NULL; + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + sas_port_delete_phy(ps3_sas_port->port, ps3_sas_phy->phy); + + ps3_sas_port->phy_count--; + + LOG_DEBUG("hno:%u sas_port pdid[%u] phy_count[%u] -> " + "encl[%u] phy_id[%u] sas_addr[%016llx] sas_remote_addr[%016llx] sas_phy delete\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, ps3_sas_port->phy_count, + ps3_sas_phy->encl_id, ps3_sas_phy->phy_id, + ps3_sas_phy->identify.sas_address, + ps3_sas_phy->remote_identify.sas_address); + + memset(&ps3_sas_phy->remote_identify, 0, + sizeof(struct sas_identify)); + del_finish = PS3_TRUE; + break; + } + } + + if (del_finish == PS3_TRUE) { + if (ps3_sas_port->phy_count == 0) { + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + list_del(&ps3_sas_port->list); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + + LOG_INFO("hno:%u sas_port pdid[%u] phy_count[%u] delete start\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, ps3_sas_port->phy_count); + + sas_port_delete(ps3_sas_port->port); + + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, ps3_sas_port->pd_flat_id); + if (pd_entry != NULL) { + pd_entry->sas_rphy = NULL; + } + + LOG_INFO("hno:%u sas_port pdid[%u] phy_count[%u] delete end\n", + PS3_HOST(instance), ps3_sas_port->pd_flat_id, ps3_sas_port->phy_count); + kfree(ps3_sas_port); + } + + break; + } + } +} + +static Bool ps3_sas_addr_is_exist( + struct PS3Expanders *p_expanders, U64 sas_addr) +{ + Bool ret = PS3_FALSE; + U8 i = 0; + + if (p_expanders == NULL) { + goto l_out; + } + for (i = 1; i < p_expanders->count; i++) { + if (p_expanders->expanders[i].sasAddr == sas_addr) { + ret = PS3_TRUE; + break; + } + } +l_out: + return ret; +} + +static void ps3_sas_expander_port_clean(struct ps3_instance *instance, + struct ps3_sas_node *sas_node, struct PS3Expanders *p_expanders) +{ + struct ps3_sas_port *ps3_sas_port = NULL; + struct ps3_sas_port *ps3_sas_port_next = NULL; + struct ps3_sas_phy *ps3_sas_phy = NULL; + struct ps3_sas_phy *ps3_sas_phy_next = NULL; + struct ps3_sas_node *exp_node = NULL; + Bool is_exist = PS3_FALSE; + U8 diff_phy_num = 0; + + list_for_each_entry_safe(ps3_sas_port, ps3_sas_port_next, + &sas_node->sas_port_list, list) { + if (ps3_sas_port->remote_identify.device_type != + SAS_EDGE_EXPANDER_DEVICE && + ps3_sas_port->remote_identify.device_type != + SAS_FANOUT_EXPANDER_DEVICE) { + continue; + } + is_exist = ps3_sas_addr_is_exist(p_expanders, ps3_sas_port->remote_identify.sas_address); + diff_phy_num = ps3_sas_port->phy_count; + list_for_each_entry_safe(ps3_sas_phy, ps3_sas_phy_next, + &ps3_sas_port->phy_list, port_siblings) { + + if ((ps3_sas_phy->remote_identify.sas_address == + ps3_sas_port->remote_identify.sas_address) || + (ps3_sas_phy->remote_identify.sas_address == 0 && is_exist)) { + continue; + } + + diff_phy_num--; + LOG_WARN("hno:%u phy[%d]'s remote " + "addr[%016llx] != expander " + "port's rphy addr[0x%016llx]!\n", + PS3_HOST(instance), ps3_sas_phy->phy_id, + ps3_sas_phy->remote_identify.sas_address, + ps3_sas_port->remote_identify.sas_address); + } + if (diff_phy_num != 0) { + continue; + } + + exp_node = ps3_sas_find_node_by_sas_addr(instance, + ps3_sas_port->remote_identify.sas_address); + if (exp_node == NULL) { + LOG_ERROR("hno:%u cannot find node sas_addr[%016llx] !\n", + PS3_HOST(instance), ps3_sas_port->remote_identify.sas_address); + PS3_BUG(); + } else { + LOG_INFO("hno:%u del expander in sas port clean. encl_id[%d], sas_addr[%016llx]\n", + PS3_HOST(instance), exp_node->encl_id, exp_node->sas_address); + ps3_sas_expander_node_del(instance, exp_node); + } + } +} + +S32 ps3_sas_expander_phys_refresh(struct ps3_instance *instance, + struct ps3_sas_node *sas_node) +{ + S32 ret = -PS3_FAILED; + struct PS3SasMgr sas_req_param; + struct PS3PhyInfo *phy_info = instance->sas_dev_context.ps3_sas_phy_buff; + U8 i = 0; + ULong flags = 0; + + memset(&sas_req_param, 0, sizeof(sas_req_param)); + sas_req_param.enclID = sas_node->encl_id; + sas_req_param.sasAddr =cpu_to_le64(sas_node->sas_address); + sas_req_param.startPhyID = 0; + sas_req_param.phyCount = sas_node->phy_count; + + LOG_DEBUG("hno:%u ready get phys[%d] of encl_id[%d] !\n", + PS3_HOST(instance), sas_req_param.phyCount, sas_req_param.enclID); + + memset(phy_info, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_phy_get(instance, &sas_req_param); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init get expander NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + LOG_INFO_IN_IRQ(instance, "hno:%u ready update %d phys of encl_id[%d]!\n", + PS3_HOST(instance), sas_req_param.phyCount, sas_req_param.enclID); + for (i = 0; i < sas_node->phy_count; i++) { + ps3_sas_node_phy_update(instance, &sas_node->phys[i], &phy_info[i]); +#if 0 + 所有的添加都应该通过scsi来触发 + if (phy_info[i].attachedSasAddr != PS3_SAS_INVALID_SAS_ADDR && + phy_info[i].attachDevType == SAS_END_DEVICE) { + ret = ps3_sas_end_device_try_add(instance, sas_node, + &sas_node->phys[i]); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add end device[%016llx] on node[%d]-phys[%d] failed !\n", + PS3_HOST(instance), + phy_info[i].attachedSasAddr, + sas_node->encl_id, i); + goto l_out; + } + } +#endif + } + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + ps3_sas_port_phy_update(instance, sas_node); +l_out: + return ret; +} + +static S32 ps3_sas_device_date_refresh(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct PS3Expanders *p_expanders = (struct PS3Expanders*)instance->sas_dev_context.ps3_sas_buff; + struct PS3ExpanderInfo *exp_info = p_expanders->expanders; + struct ps3_sas_node *exp_node = NULL; + U8 i = 0; + + LOG_DEBUG("hno:%u SAS dev refresh enter\n", + PS3_HOST(instance)); + + memset(p_expanders, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_expander_all_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init get expander NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + LOG_DEBUG("hno:%u ready refresh expander count[%d]\n", + PS3_HOST(instance), p_expanders->count); + if (p_expanders->count == 0) { + LOG_ERROR("hno:%u expander init info count = 0\n", + PS3_HOST(instance)); + BUG(); + } + + LOG_DEBUG("hno:%u ready refresh HBA\n", PS3_HOST(instance)); + + ret = ps3_sas_expander_phys_refresh(instance, + &instance->sas_dev_context.ps3_hba_sas); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u refresh phys on HBA NOK!\n", + PS3_HOST(instance)); + goto l_out; + } + ps3_sas_expander_port_clean(instance, &instance->sas_dev_context.ps3_hba_sas, p_expanders); + + LOG_DEBUG("hno:%u end refresh HBA\n", PS3_HOST(instance)); + + for (i = 1; i < p_expanders->count; i++) { + exp_node = ps3_sas_find_node_by_id(instance, exp_info[i].enclID); + if (exp_node != NULL) { + if (likely(exp_node->parent_sas_address == exp_info[i].parentSasAddr && + exp_node->parent_encl_id == exp_info[i].parentId)) { + LOG_DEBUG("hno:%u ready refresh expander[%d]\n", + PS3_HOST(instance), exp_info[i].enclID); + ret = ps3_sas_expander_phys_refresh(instance, exp_node); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u refresh phys on expander[%d] NOK!\n", + PS3_HOST(instance), exp_info[i].enclID); + goto l_out; + } + ps3_sas_expander_port_clean(instance, exp_node, p_expanders); + LOG_DEBUG("hno:%u end refresh expander[%d]\n", + PS3_HOST(instance), exp_info[i].enclID); + } + } + + LOG_DEBUG("hno:%u ready add expander[%d]\n", + PS3_HOST(instance), exp_info[i].enclID); + ret = ps3_sas_expander_node_add(instance, &exp_info[i]); + LOG_DEBUG("hno:%u end add expander[%d], ret[%d]\n", + PS3_HOST(instance), exp_info[i].enclID, ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init add expander[%d] info NOK\n", + PS3_HOST(instance), exp_info[i].enclID); + goto l_out; + } + } + + LOG_DEBUG("hno:%u SAS refresh end\n", + PS3_HOST(instance)); +l_out: + return ret ; +} + +static S32 ps3_sas_expander_event_update(struct ps3_instance *instance, U8 encl_id) +{ + S32 ret = -PS3_FAILED; + struct ps3_sas_node *sas_node = NULL; + + LOG_DEBUG("hno:%u enter SAS expander update encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + sas_node = ps3_sas_find_node_by_id(instance, encl_id); + if (sas_node == NULL) { + LOG_ERROR("hno:%u cannot find PS3 node[%d] !\n", + PS3_HOST(instance), encl_id); + goto l_out; + } + + ret = ps3_sas_expander_phys_refresh(instance, sas_node); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u refresh phys on node[%d] NOK!\n", + PS3_HOST(instance), encl_id); + goto l_out; + } +l_out: + LOG_DEBUG("hno:%u quit SAS expander update encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + return ret; +} + +static S32 ps3_sas_expander_phy_update(struct ps3_instance *instance, U8 encl_id, U8 phy_id) +{ + S32 ret = -PS3_FAILED; + struct ps3_sas_node *sas_node = NULL; + struct PS3SasMgr sas_req_param; + struct PS3PhyInfo *phy_info = instance->sas_dev_context.ps3_sas_phy_buff; + ULong flags = 0; + + LOG_DEBUG("hno:%u enter SAS expander update encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + sas_node = ps3_sas_find_node_by_id(instance, encl_id); + if (sas_node == NULL) { + LOG_ERROR("hno:%u cannot find PS3 node[%d] !\n", + PS3_HOST(instance), encl_id); + goto l_out; + } + + memset(&sas_req_param, 0, sizeof(sas_req_param)); + sas_req_param.enclID = sas_node->encl_id; + sas_req_param.sasAddr =cpu_to_le64(sas_node->sas_address); + sas_req_param.startPhyID = phy_id; + sas_req_param.phyCount = 1; + + memset(phy_info, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_phy_get(instance, &sas_req_param); + INJECT_START(PS3_ERR_IJ_SAS_PHY_GET_ERR, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u init get expander NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + ps3_sas_node_phy_update(instance, &sas_node->phys[phy_id], phy_info); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); + +l_out: + LOG_DEBUG("hno:%u quit sas expander update encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + return ret; +} + +static S32 ps3_sas_expander_event_add(struct ps3_instance *instance, U8 encl_id) +{ + S32 ret = PS3_SUCCESS; + struct PS3ExpanderInfo *exp_info = + (struct PS3ExpanderInfo *)instance->sas_dev_context.ps3_sas_buff; + struct PS3SasMgr sas_req_param; + + memset(&sas_req_param, 0, sizeof(sas_req_param)); + sas_req_param.enclID = encl_id; + + LOG_WARN("hno:%u enter sas expander add encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + + memset(exp_info, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_expander_get(instance, &sas_req_param); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u get expander[%d] NOK\n", + PS3_HOST(instance), encl_id); + goto l_out; + } + + if (exp_info->phyCount == 0) { + LOG_ERROR("hno:%u phy_count Invalid!\n", PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + INJECT_START(PS3_ERR_EXP_ID_ERR, &encl_id); + if (exp_info->enclID != encl_id) { + LOG_ERROR("hno:%u got expander[%d] is not [%d]\n", + PS3_HOST(instance), exp_info->enclID, encl_id); + PS3_BUG(); + ret = -PS3_FAILED; + goto l_out; + } + + ret = ps3_sas_expander_event_update(instance, exp_info->parentId); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u update parent encl[%d] NOK\n", + PS3_HOST(instance), exp_info->parentId); + goto l_out; + } + + ret = ps3_sas_expander_node_add(instance, exp_info); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add expander[%d] NOK\n", + PS3_HOST(instance), encl_id); + goto l_out; + } +l_out: + LOG_WARN("hno:%u quit sas expander add encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + return ret; +} + +static S32 ps3_sas_expander_event_del(struct ps3_instance *instance, U8 encl_id) +{ + S32 ret = PS3_SUCCESS; + struct ps3_sas_node *exp_node = NULL; + U8 parentId = 0; + + LOG_WARN("hno:%u enter sas expander del encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + + exp_node = ps3_sas_find_node_by_id(instance, encl_id); + if (exp_node == NULL) { + LOG_ERROR("hno:%u cannot find node[%d] !\n", + PS3_HOST(instance), encl_id); + ret = -PS3_FAILED; + goto l_out; + } + + parentId = exp_node->parent_encl_id; + ps3_sas_expander_node_del(instance, exp_node); + + ret = ps3_sas_expander_event_update(instance, parentId); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u update parent encl[%d] NOK\n", + PS3_HOST(instance), parentId); + goto l_out; + } + +l_out: + LOG_WARN("hno:%u quit sas expander del encl_id[%d] !\n", + PS3_HOST(instance), encl_id); + return ret; +} + +S32 ps3_sas_expander_event_refresh(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + ret = ps3_sas_device_date_refresh(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u refresh all SAS NOK\n", + PS3_HOST(instance)); + goto l_out; + } + +l_out: + return ret; +} + +S32 ps3_sas_update_detail_proc(struct ps3_instance *instance, + struct PS3EventDetail *event_detail, U32 event_cnt) +{ + S32 ret = PS3_SUCCESS; + S32 ret_map = PS3_SUCCESS; + U32 i = 0; + + LOG_DEBUG("hno:%u, event detail count[%d]\n", + PS3_HOST(instance), event_cnt); + + for (i = 0; i < event_cnt; i++) { + LOG_INFO("hno:%u, event detail %d eventCode is [%s], encl_Id[%d]\n", + PS3_HOST(instance), i, mgrEvtCodeTrans(event_detail[i].eventCode), + event_detail[i].EnclId); + + switch (event_detail[i].eventCode) { + case PS3_EVT_CODE(MGR_EVT_SAS_EXPANDER_CHANGE): + case PS3_EVT_CODE(MGR_EVT_SAS_EXPANDER_IN): + ret = ps3_sas_expander_event_add(instance, + event_detail[i].EnclId); + break; + case PS3_EVT_CODE(MGR_EVT_SAS_EXPANDER_OUT): + ret = ps3_sas_expander_event_del(instance, + event_detail[i].EnclId); + break; + case PS3_EVT_CODE(MGR_EVT_SAS_EXPANDER_UPDATE): + ret = ps3_sas_expander_event_update(instance, + event_detail[i].EnclId); + break; + default: + break; + } + + if (ret != PS3_SUCCESS) { + ret_map |= event_detail[i].eventType; + } + } + return ret_map; +} + +S32 ps3_sas_add_device(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry) +{ + S32 ret = -PS3_FAILED; + struct ps3_sas_node* parent_node = NULL; + struct sas_identify *remote_id = NULL; + + U32 softChan = PS3_CHANNEL(&pd_entry->disk_pos); + U32 devID = PS3_TARGET(&pd_entry->disk_pos); + U32 phyDiskID = PS3_PDID(&pd_entry->disk_pos); + + LOG_DEBUG("hno:%u enter ps3_sas_add_device pd[%u:%u:%u] on encl[%u], phy[%u]!\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + pd_entry->encl_id, pd_entry->phy_id); + + parent_node = ps3_sas_find_node_by_id(instance, pd_entry->encl_id); + if (parent_node == NULL) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] cannot found node[%d] !\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + pd_entry->encl_id); + goto l_out; + } + if (pd_entry->phy_id >= parent_node->phy_count) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] phyid[%u] exceed node phy_count[%u] !\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + pd_entry->phy_id, parent_node->phy_count); + goto l_out; + } + + ret = ps3_sas_expander_phy_update(instance, pd_entry->encl_id, pd_entry->phy_id); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u update phy in add pd channel[%u:%u:%u] phyid[%u] on node[%u] NOK !\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + pd_entry->phy_id, parent_node->encl_id); + goto l_out; + } + + remote_id = &parent_node->phys[pd_entry->phy_id].remote_identify; + if (remote_id->sas_address == PS3_SAS_INVALID_SAS_ADDR || + remote_id->device_type != SAS_END_DEVICE || + remote_id->sas_address == parent_node->parent_sas_address) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] phyid[%u] " + "invalid SAS addr[%016llx] or dev_type[%d] != SAS_END_DEVICE or " + " SAS addr = parent SAS addr[%016llx]!\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + pd_entry->phy_id, remote_id->sas_address, + remote_id->device_type, + parent_node->parent_sas_address); + goto l_out; + } + + ret = ps3_sas_end_device_try_add(instance, parent_node, + &parent_node->phys[pd_entry->phy_id], pd_entry); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] phyid[%u] on node[%u] NOK !\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + pd_entry->phy_id, parent_node->encl_id); + goto l_out; + } + +l_out: + return ret; +} + +S32 ps3_sas_remove_device(struct ps3_instance *instance, + struct PS3DiskDevPos *diskPos, U8 encl_id, U8 phy_id) +{ + S32 ret = -PS3_FAILED; + struct ps3_sas_node* parent_node = NULL; + struct sas_identify *remote_id = NULL; + U32 softChan = PS3_CHANNEL(diskPos); + U32 devID = PS3_TARGET(diskPos); + U32 phyDiskID = PS3_PDID(diskPos); + + LOG_WARN("hno:%u enter ps3_sas_remove_device pd[%u:%u:%u] on encl[%u], phy[%u]!\n", + PS3_HOST(instance), softChan, + devID, phyDiskID, encl_id, phy_id); + + parent_node = ps3_sas_find_node_by_id(instance, encl_id); + if (parent_node == NULL) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] cannot found node[%u] !\n", + PS3_HOST(instance),softChan, devID, phyDiskID, + encl_id); + goto l_out; + } + + if (phy_id >= parent_node->phy_count) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] phyid[%u] exceed node phy_count[%u] !\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + phy_id, parent_node->phy_count); + goto l_out; + } + + remote_id = &parent_node->phys[phy_id].remote_identify; + if (remote_id->sas_address != PS3_SAS_INVALID_SAS_ADDR && + remote_id->sas_address == parent_node->parent_sas_address) { + LOG_ERROR("hno:%u add end device channel[%u:%u:%u] phyid[%u] " + "SAS addr[%016llx] dev_type[%d] parent SAS addr[%016llx]!\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + phy_id, remote_id->sas_address, + remote_id->device_type, + parent_node->parent_sas_address); + goto l_out; + } + + ps3_sas_end_dev_del(instance, parent_node, phy_id); + + ret = ps3_sas_expander_phy_update(instance, encl_id, phy_id); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u update phy in add pd channel[%u:%u:%u] phyid[%u] on node[%u] NOK !\n", + PS3_HOST(instance), softChan, devID, phyDiskID, phy_id, encl_id); + goto l_out; + } +l_out: + LOG_WARN("hno:%u ps3_sas_remove_device pd[%u:%u:%u] on encl[%u], phy[%u] end, ret[%d]!\n", + PS3_HOST(instance), softChan, devID, phyDiskID, + encl_id, phy_id, ret); + return ret; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) + S32 ps3_sas_user_scan(struct Scsi_Host *host, U32 channel, U32 id, U32 lun) +#else + S32 ps3_sas_user_scan(struct Scsi_Host *host, U32 channel, U32 id, U64 lun) +#endif +{ + struct PS3ChannelInfo *channel_info = NULL; + struct ps3_instance *instance = NULL; + struct ps3_pd_entry *pd_entry = NULL; + U16 max_dev_num = 0; + U8 i = 0; + U16 j = 0; + + if ((lun != 0) && (lun != SCAN_WILD_CARD)) { + goto l_out; + } + + instance = (struct ps3_instance *)shost_priv(host); + channel_info = &instance->ctrl_info.channelInfo; + INJECT_START(PS3_ERR_IJ_PD_ATTR, NULL); + ps3_mutex_lock(&instance->dev_context.dev_scan_lock); + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_PD_ATTR_WAIT_PD_ATTR, PS3_ERR_IJ_PD_ATTR, NULL); + for (i = 0; i < channel_info->channelNum; i++) { + if ((channel_info->channels[i].channelType == PS3_CHAN_TYPE_PD) && + (channel == SCAN_WILD_CARD || channel == i)) { + max_dev_num = channel_info->channels[i].maxDevNum; + for (j = 0; j < max_dev_num; j++) { + pd_entry = ps3_dev_mgr_lookup_pd_info(instance, i, j); + if ((pd_entry != NULL) && (pd_entry->sas_rphy != NULL)) { + if (id == SCAN_WILD_CARD || id == j) { + scsi_scan_target(&pd_entry->sas_rphy->dev, i, j, 0, SCSI_SCAN_MANUAL); + LOG_DEBUG("hno:%u channel:%u target:%u scan\n", PS3_HOST(instance), i, j); + } + } + } + } + } + ps3_mutex_unlock(&instance->dev_context.dev_scan_lock); + +l_out: + return 0; +} + +#endif diff --git a/drivers/scsi/ps3stor/ps3_device_manager_sas.h b/drivers/scsi/ps3stor/ps3_device_manager_sas.h new file mode 100644 index 0000000000000000000000000000000000000000..e083c7402510a740342e83e4ddb65f25d259f0c1 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_device_manager_sas.h @@ -0,0 +1,119 @@ +#ifndef _WINDOWS + +#ifndef _PS3_DEVICE_MANAGER_SAS_H_ +#define _PS3_DEVICE_MANAGER_SAS_H_ +#include + +#include +#include + +#include "ps3_htp_def.h" +#include "ps3_htp_dev.h" +#include "ps3_htp_event.h" +#include "ps3_device_manager.h" + +#define PS3_SAS_HBA_MAX_SAS_NUM 3 + +#define PS3_SAS_MAX_PHY_NUM (128) +#define PS3_SAS_INVALID_ID (0xFF) +#define PS3_SAS_INVALID_SAS_ADDR (0x0) +#define PS3_SAS_REQ_BUFF_LEN (4096) + +struct ps3_instance; + +struct ps3_sas_node { + struct list_head list; + struct device *dev; + struct ps3_sas_phy *phys; + struct list_head sas_port_list; + U64 sas_address; + U64 parent_sas_address; + U8 phy_count; + U8 encl_id; + U8 parent_encl_id; + U8 dev_type; + U8 reserved[4]; +}; + +struct ps3_sas_phy { + struct list_head port_siblings; + struct sas_identify identify; + struct sas_identify remote_identify; + struct sas_phy *phy; + struct ps3_sas_port *attach_port; + U8 phy_id; + U8 encl_id; + U8 slot_id; + U8 reserved[5]; +}; + +struct ps3_sas_port { + struct list_head list; + struct sas_identify remote_identify; + struct sas_rphy *rphy; + struct sas_port *port; + struct list_head phy_list; + U16 pd_flat_id; + U8 phy_count; + U8 reserved[5]; +}; + +struct ps3_sas_dev_context { + struct list_head ps3_sas_node_list; + spinlock_t ps3_sas_node_lock; + struct ps3_sas_node ps3_hba_sas; + U64 ps3_hba_sas_addr[PS3_SAS_HBA_MAX_SAS_NUM]; + struct semaphore ps3_sas_smp_semaphore; + + dma_addr_t ps3_sas_buff_dma_addr; + dma_addr_t ps3_sas_phy_buff_dma_addr; + void *ps3_sas_buff; + struct PS3PhyInfo *ps3_sas_phy_buff; + Bool is_support_smp; + U8 reserved[7]; +}; + +Bool ps3_sas_is_support_smp(struct ps3_instance *instance); + +S32 ps3_sas_device_mgr_init(struct ps3_instance *instance); + +S32 ps3_sas_device_mgr_exit(struct ps3_instance *instance); + +S32 ps3_sas_device_data_init(struct ps3_instance *instance); + +S32 ps3_sas_device_data_exit(struct ps3_instance *instance); + +S32 ps3_sas_rphy_slot_get(struct ps3_instance *instance, U64 sas_addr, U32 *slot_id); + +U64 ps3_sas_rphy_parent_sas_addr_get(struct ps3_instance *instance, U64 sas_addr); + +U8 ps3_sas_encl_id_get(struct ps3_instance *instance, U64 sas_addr); + +S32 ps3_sas_expander_event_refresh(struct ps3_instance *instance); + +S32 ps3_sas_update_detail_proc(struct ps3_instance *instance, + struct PS3EventDetail *event_detail, U32 event_cnt); + +S32 ps3_sas_add_device(struct ps3_instance *instance, + struct ps3_pd_entry *pd_entry); + +S32 ps3_sas_remove_device(struct ps3_instance *instance, + struct PS3DiskDevPos *diskPos, U8 encl_id, U8 phy_id); + +void ps3_sas_expander_node_del(struct ps3_instance *instance, + struct ps3_sas_node *exp_node); + +struct ps3_sas_node* ps3_sas_find_node_by_sas_addr( + struct ps3_instance *instance, U64 sas_addr); + +void ps3_sas_node_phy_update(struct ps3_instance *instance, struct ps3_sas_phy *ps3_phy, + struct PS3PhyInfo *phy_info); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,17,0) + S32 ps3_sas_user_scan(struct Scsi_Host *host, U32 channel, U32 id, U32 lun); +#else + S32 ps3_sas_user_scan(struct Scsi_Host *host, U32 channel, U32 id, U64 lun); +#endif + +#endif +#endif diff --git a/drivers/scsi/ps3stor/ps3_device_update.c b/drivers/scsi/ps3stor/ps3_device_update.c new file mode 100644 index 0000000000000000000000000000000000000000..2fb7ee889c6295139ed97b21c29e82dcbadc5178 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_device_update.c @@ -0,0 +1,1741 @@ + +#include "ps3_device_update.h" + +#ifdef _WINDOWS + +#include "ps3_dev_adp.h" + +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ps3_device_manager_sas.h" +#endif + +#include "ps3_event.h" +#include "ps3_meta.h" +#include "ps3_htp_event.h" +#include "ps3_mgr_cmd.h" +#include "ps3_ioc_manager.h" +#include "ps3_driver_log.h" +#include "ps3_cmd_statistics.h" +#include "ps3_device_update.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_ioc_state.h" + +static S32 ps3_pd_del(struct ps3_instance *instance, + struct PS3DiskDevPos *dev_pos, U8 config_flag); + +static S32 ps3_pd_add(struct ps3_instance *instance, + struct PS3DiskDevPos* dev_pos); + +U32 ps3_scsi_dev_magic(struct ps3_instance *instance, struct scsi_device *sdev) +{ + U32 dev_magic_num = 0; + struct ps3_scsi_priv_data *p_priv_data = NULL; + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + p_priv_data = PS3_SDEV_PRI_DATA(sdev); + if (p_priv_data != NULL) { + if (PS3_IS_VD_CHANNEL(instance, PS3_SDEV_CHANNEL(sdev)) || + ps3_sas_is_support_smp(instance)) { + dev_magic_num = p_priv_data->disk_pos.diskMagicNum; + } else { + dev_magic_num = p_priv_data->disk_pos.checkSum; + } + } + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + + return dev_magic_num; +} + +Bool ps3_pd_scsi_visible_check(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type, U8 config_flag, + U8 pd_state) +{ + Bool visible = PS3_DRV_TRUE; + + if (pd_state == DEVICE_STATE_OUTING) { + LOG_INFO("hno:%u PD[%u:%u:%u], dev_type[%s] state[%s] is outing\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_PDID(disk_pos), + namePS3DevType((enum PS3DevType)dev_type), + getDeviceStateName((DeviceState_e)pd_state)); + visible = PS3_DRV_FALSE; + goto l_out; + } + + if (ps3_is_fake_pd(dev_type)) { + LOG_DEBUG("hno:%u PD[%u:%u:%u], dev_type[%s] device is visible all time\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_PDID(disk_pos), + namePS3DevType((enum PS3DevType)dev_type)); + goto l_out; + } + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0) && LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)) + if (!instance->is_support_jbod && + ps3_check_pd_is_vd_member(config_flag)) { + LOG_DEBUG("hno:%u PD[%u:%u:%u] is vd component, config_flag[%s] \n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_PDID(disk_pos), + getPdStateName((MicPdState_e)config_flag, instance->is_raid)); + visible = PS3_DRV_FALSE; + goto l_out; + } +#endif + + if (instance->is_support_jbod && config_flag != + MIC_PD_STATE_JBOD) { + LOG_DEBUG("hno:%u PD[%u:%u:%u] config_flag is [%s], invisible \n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_PDID(disk_pos), + getPdStateName((MicPdState_e)config_flag, instance->is_raid)); + visible = PS3_DRV_FALSE; + goto l_out; + } + +l_out: + LOG_DEBUG("hno:%u PD[%u:%u:%u] is %s\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_PDID(disk_pos), + visible ? "visible" : "invisible"); + + return visible; +} + +static inline Bool ps3_vd_scsi_visible_check(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, Bool is_hidden, U8 disk_state) +{ + Bool visible = PS3_DRV_TRUE; + + if (is_hidden) { + LOG_INFO("hno:%u vd[%u:%u:%u] is hidden\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_VDID(disk_pos)); + visible = PS3_DRV_FALSE; + } + + if (disk_state == MIC_VD_STATE_OFFLINE) { + LOG_INFO("hno:%u vd[%u:%u:%u] state offline\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_VDID(disk_pos)); + visible = PS3_DRV_FALSE; + } + + return visible; +} + +static Bool ps3_scsi_visible_check(struct ps3_instance *instance, + U8 channel, U16 target_id, U8 disk_type) +{ + struct PS3VDEntry *p_vd_entry = NULL; + struct ps3_pd_entry *p_pd_entry = NULL; + Bool visible = PS3_DRV_FALSE; + + if (disk_type == PS3_DISK_TYPE_PD) { + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, channel, target_id); + if (p_pd_entry) { + visible = ps3_pd_scsi_visible_check(instance, + &p_pd_entry->disk_pos, p_pd_entry->dev_type, + p_pd_entry->config_flag, p_pd_entry->state); + } + } else if (disk_type == PS3_DISK_TYPE_VD){ + p_vd_entry = ps3_dev_mgr_lookup_vd_info(instance, channel, target_id); + if (p_vd_entry) { + visible = ps3_vd_scsi_visible_check(instance, + &p_vd_entry->diskPos, p_vd_entry->isHidden, p_vd_entry->diskState); + } + } + + if (p_pd_entry || p_vd_entry) { + LOG_INFO("hno:%u dev[%u:%u] visible is %s\n", + PS3_HOST(instance), channel, target_id, + visible ? "PS3_TRUE" : "PS3_FALSE"); + } + return visible; +} + +static inline void __ps3_scsi_add_device(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type) +{ + S32 ret = PS3_SUCCESS; + U8 channel = PS3_CHANNEL(disk_pos); + U16 id = PS3_TARGET(disk_pos); + + ret = ps3_scsi_add_device_ack(instance, disk_pos, dev_type); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL2, &ret); + if (ret != PS3_SUCCESS) { + LOG_WARN("hno:%u dev[%u:%u] magic[%#x] add scsi device ack NOK, ret %d\n", + PS3_HOST(instance), channel, id, + disk_pos->diskMagicNum, ret); + } else { + LOG_INFO("hno:%u dev_type[%d] id[%u:%u] add device begin\n", + PS3_HOST(instance), dev_type, channel, id); + + ret = ps3_scsi_add_device(instance, channel, id, 0); + + LOG_INFO("hno:%u dev_type[%d] id[%u:%u] add end, add ret %d\n", + PS3_HOST(instance), dev_type, channel, id, ret); + } +} + +static void _ps3_scsi_add_device(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type) +{ + struct scsi_device *sdev = NULL; + U8 channel = PS3_CHANNEL(disk_pos); + U16 target_id = PS3_TARGET(disk_pos); + U16 disk_id = PS3_VDID(disk_pos); + + LOG_DEBUG("hno:%u dev_type[%s] id[%u:%u] disk_id[%d] add scsi device start\n", + PS3_HOST(instance), namePS3DiskType((enum PS3DiskType)dev_type), + channel, target_id, disk_id); + + sdev = ps3_scsi_device_lookup(instance, channel, target_id, 0); + if (sdev == NULL) { + __ps3_scsi_add_device(instance, disk_pos, dev_type); + } else { + ps3_scsi_device_put(instance, sdev); + LOG_INFO("hno:%u channel[%u] target[%u] device already exists in os\n", + PS3_HOST(instance), channel, target_id); + } + + LOG_DEBUG("hno:%u dev_type[%s] id[%u:%u] disk_id[%d] add scsi device end\n", + PS3_HOST(instance), namePS3DiskType((enum PS3DiskType)dev_type), + channel, target_id, disk_id); +} + +static S32 _ps3_add_disk(struct ps3_instance *instance, + U8 channel, U16 target_id, U8 disk_type) +{ + S32 ret = PS3_SUCCESS; + struct ps3_pd_entry *p_pd_entry = NULL; + struct PS3VDEntry *p_vd_entry = NULL; + struct PS3DiskDevPos *p_diskPos = NULL; + U8 dev_type = PS3_DISK_TYPE_UNKNOWN; + + if (!ps3_scsi_visible_check(instance, channel, target_id, disk_type)) { + goto l_out; + } + + if (disk_type == PS3_DISK_TYPE_PD) { + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, channel, target_id); + if (p_pd_entry) { +#ifndef _WINDOWS + if (ps3_sas_is_support_smp(instance) && + p_pd_entry->dev_type != PS3_DEV_TYPE_NVME_SSD && + p_pd_entry->dev_type != PS3_DEV_TYPE_VEP) { + ps3_sas_add_device(instance, p_pd_entry); + goto l_out; + } else { +#endif + p_diskPos = &p_pd_entry->disk_pos; + dev_type = PS3_DISK_TYPE_PD; +#ifndef _WINDOWS + } +#endif + } + } else if (disk_type == PS3_DISK_TYPE_VD){ + p_vd_entry = ps3_dev_mgr_lookup_vd_info(instance, channel, target_id); + if (p_vd_entry) { + p_diskPos = &p_vd_entry->diskPos; + dev_type = PS3_DISK_TYPE_VD; + } + } + + _ps3_scsi_add_device(instance, p_diskPos, dev_type); +l_out: + return ret; +} +#ifndef _WINDOWS + +static Bool ps3_sd_available_check(struct scsi_device *sdev) +{ + Bool ret = PS3_TRUE; + if (dev_get_drvdata(&sdev->sdev_gendev) == NULL) { + ret = PS3_FALSE; + } + return ret; +} + +void ps3_scsi_scan_host(struct ps3_instance *instance) +{ + struct PS3ChannelInfo *channel_info = &instance->ctrl_info.channelInfo; + U16 timeout = instance->ctrl_info.isotoneTimeOut; + U8 channelType = 0; + U16 maxDevNum = 0; + U8 i = 0; + U16 j = 0; + struct scsi_device *sdev = NULL; + Bool bootdrv_ok = PS3_FALSE; + U16 count = 0; + + LOG_WARN("hno:%u scan device begin, channel number %d\n", + PS3_HOST(instance), channel_info->channelNum); + INJECT_START(PS3_ERR_IJ_ADD_DISK_HOST_RESET, instance) + for (i = 0; i < channel_info->channelNum; i++) { + channelType = channel_info->channels[i].channelType; + maxDevNum = channel_info->channels[i].maxDevNum; + + LOG_INFO("hno:%u channel[%u] is type %s,max dev num is:%d\n", + PS3_HOST(instance), i, + namePS3ChannelType((enum PS3ChannelType)channelType), + maxDevNum); + for (j = 0; j < maxDevNum; j++) { + _ps3_add_disk(instance, i, j, channelType); + if (timeout != 0 && !bootdrv_ok && i == 0 && + ps3_scsi_visible_check(instance, i, j, channelType)) { + for (count = 0; count < timeout; count++) { + sdev = ps3_scsi_device_lookup(instance, i, j, 0); + if (sdev == NULL) { + continue; + } + if (!ps3_sd_available_check(sdev)) { + ps3_scsi_device_put(instance, sdev); + ps3_msleep(PS3_PS3_LOOP_TIME_INTERVAL_1000MS); + continue; + } + ps3_scsi_device_put(instance, sdev); + LOG_WARN("hno:%u bootdrive disk[%u:%u] drive-letter add complete\n", + PS3_HOST(instance), i, j); + break; + } + bootdrv_ok = PS3_TRUE; + } + } + } + + LOG_WARN("hno:%u scan device end, channel number %d\n", + PS3_HOST(instance), channel_info->channelNum); +} +#endif +static inline S32 _ps3_del_disk(struct ps3_instance *instance, + struct scsi_device *sdev) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = NULL; + + U8 dev_type = PS3_DISK_TYPE_UNKNOWN; + U8 channel = PS3_SDEV_CHANNEL(sdev); + U16 target_id = PS3_SDEV_TARGET(sdev); + struct PS3DiskDevPos disk_pos; + U8 encl_id = 0; + U8 phy_id = 0; + + if (PS3_IS_PD_CHANNEL(instance, channel)) { + dev_type = PS3_DISK_TYPE_PD; + } else if (PS3_IS_VD_CHANNEL(instance, channel)) { + dev_type = PS3_DISK_TYPE_VD; + } else { + LOG_ERROR("hno:%u dev id[%u:%u] channel NOK\n", + PS3_HOST(instance), channel, + target_id); + PS3_BUG(); + goto l_out; + } + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + p_priv_data = (struct ps3_scsi_priv_data*)sdev->hostdata; + if (p_priv_data != NULL) { + INJECT_AT_TIMES(PS3_ERR_IJ_FORCE_WAIT, sdev); + + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_DEL_DEV_WAIT_OS_PRIV_DATA, + PS3_ERR_IJ_GET_PRIV_DATA_DELAY, NULL); + + ps3_qos_disk_del(instance, p_priv_data); + if (ps3_sas_is_support_smp(instance) && dev_type == PS3_DISK_TYPE_PD && + p_priv_data->dev_type != PS3_DEV_TYPE_NVME_SSD && + p_priv_data->dev_type != PS3_DEV_TYPE_VEP) { + memset(&disk_pos, 0, sizeof(struct PS3DiskDevPos)); + memcpy(&disk_pos, &p_priv_data->disk_pos, sizeof(struct PS3DiskDevPos)); + encl_id = p_priv_data->encl_id; + phy_id = p_priv_data->phy_id; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + ps3_sas_remove_device(instance, &disk_pos, encl_id, phy_id); + } else { + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD && + p_priv_data->lock_mgr.hash_mgr != NULL) { + p_priv_data->lock_mgr.dev_deling = PS3_TRUE; + ps3_r1x_conflict_queue_clean(p_priv_data, + PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT)); + } + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + LOG_WARN("remove device channel[%u], id[%u] begin\n", channel, target_id); + ps3_scsi_remove_device(instance, sdev); + LOG_WARN("remove device channel[%u], id[%u] end\n", channel, target_id); + } + } else { + + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + LOG_DEBUG("hno:%u del disk, priv data NULL, [%u:%u],\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), PS3_SDEV_TARGET(sdev)); + } +l_out: + return ret; +} + +static S32 ps3_del_disk(struct ps3_instance *instance, + U8 channel, U16 target_id) +{ + struct scsi_device *sdev = NULL; + S32 ret = PS3_SUCCESS; +#if 0 + LOG_INFO("hno:%u dev id[%u:%u] delete scsi device start\n", + PS3_HOST(instance), channel, target_id); +#endif +#ifdef _WINDOWS + sdev = ps3_scsi_device_lookup_win(instance, channel, target_id); + if (sdev == NULL || sdev->add_ack != 1) { + LOG_INFO("hno:%u dev[%p] id[%u:%u] not exist scsi device\n", + PS3_HOST(instance), sdev, channel, target_id); + goto l_out; + } +#else + sdev = ps3_scsi_device_lookup(instance, channel, target_id, 0); + if(sdev == NULL) { +#if 0 + LOG_INFO("hno:%u dev id[%u:%u] not exist scsi device\n", + PS3_HOST(instance), channel, target_id); +#endif + goto l_out; + } +#endif + INJECT_AT_TIMES(PS3_ERR_IJ_FORCE_WAIT, sdev); + ret = _ps3_del_disk(instance, sdev); + ps3_scsi_device_put(instance, sdev); +l_out: +#if 0 + LOG_INFO("hno:%u dev id[%u:%u] " + "delete scsi device end\n", PS3_HOST(instance), + channel, target_id); +#endif + return ret; +} + +static struct PS3VDEntry *ps3_get_single_vd_info(struct ps3_instance *instance, + struct PS3Dev *dev) +{ + S32 ret = -PS3_FAILED; + PS3DiskDev_u vd_id = {0}; + struct PS3VDEntry *p_vd_entry = NULL; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + vd_id.ps3Dev.virtDiskID = dev->virtDiskID; + vd_id.ps3Dev.softChan = dev->softChan; + vd_id.ps3Dev.devID = dev->devID; + + ret = ps3_vd_info_sync_get(instance, vd_id.diskID, 1); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL1, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, sync get VD info NOK\n", + PS3_HOST(instance)); + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_VD_COUNT_ERR, &instance->dev_context.vd_info_buf_sync->count); + if (instance->dev_context.vd_info_buf_sync->count != 1) { + LOG_ERROR("hno:%u, single add VD, has no info\n", + PS3_HOST(instance)); + goto l_out; + } + + p_vd_entry = instance->dev_context.vd_info_buf_sync->vds; + if (PS3_VDID_INVALID(&p_vd_entry->diskPos)) { + LOG_WARN("hno:%u, init single vd info NOK, vdid is 0\n", + PS3_HOST(instance)); + p_vd_entry = NULL; + goto l_out; + } + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), PS3_VDID(&p_vd_entry->diskPos)); + if (unlikely(virtDiskIdx > PS3_MAX_VD_COUNT(instance))) { + LOG_WARN("hno:%u, init single vd info NOK, vir_id[%d] > max[%d]\n", + PS3_HOST(instance), virtDiskIdx, PS3_MAX_VD_COUNT(instance)); + p_vd_entry = NULL; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_MOD_CHAN, dev); + if (PS3_CHANNEL(&p_vd_entry->diskPos) != dev->softChan || + PS3_TARGET(&p_vd_entry->diskPos) != dev->devID) { + LOG_ERROR("hno:%u single add VD[%u:%u:%u] != req VD[%u:%u:%u] magic[%#x] unmatched\n", + PS3_HOST(instance), dev->softChan, dev->devID, + dev->virtDiskID, PS3_CHANNEL(&p_vd_entry->diskPos), + PS3_TARGET(&p_vd_entry->diskPos), + PS3_VDID(&p_vd_entry->diskPos), + p_vd_entry->diskPos.diskMagicNum); + p_vd_entry = NULL; + goto l_out; + } + ps3_vd_busy_scale_get(p_vd_entry); + + LOG_DEBUG("hno:%u VD[%u:%u:%u] got single vd info success\n", + PS3_HOST(instance), dev->softChan, dev->devID, dev->virtDiskID); +l_out: + return p_vd_entry; +} + +static S32 ps3_update_single_vd_info(struct ps3_instance *instance, + struct PS3Dev *dev) +{ + S32 ret = PS3_SUCCESS; + struct PS3VDEntry *p_vd_entry = NULL; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + U8 vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct ps3_vd_table *p_vd_tb = + &p_dev_ctx->vd_table[vd_table_idx]; + struct PS3VDEntry *p_vd_array = + p_dev_ctx->vd_entries_array[vd_table_idx]; + U16 virtDiskIdx = 0; + + p_vd_entry = ps3_get_single_vd_info(instance, dev); + if (p_vd_entry == NULL) { + LOG_ERROR("hno:%u sync get VD info NOK\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(instance), PS3_VDID(&p_vd_entry->diskPos)); + + if (p_vd_entry->isHidden) { + LOG_INFO("hno:%u single add VD[%u:%u] vd info is hidden\n", + PS3_HOST(instance), dev->softChan, dev->devID); + goto l_out; + } + + ps3_qos_vd_init(instance, p_vd_entry); + memcpy(&p_vd_array[virtDiskIdx], + p_vd_entry, sizeof(struct PS3VDEntry)); + p_vd_tb->vd_idxs[dev->softChan][dev->devID] = + PS3_VDID(&p_vd_entry->diskPos); + + ps3_vd_info_show(instance, &p_vd_array[virtDiskIdx]); + + LOG_DEBUG("hno:%u, idx[%d], VD[%u:%u] single add, got vd info\n", + PS3_HOST(instance), p_dev_ctx->vd_table_idx, dev->softChan, + dev->devID); +l_out: + return ret; +} + +static Bool _ps3_add_disk_prepare(struct ps3_instance *instance, + struct PS3DiskDevPos *dev_pos) +{ + Bool is_need_add = PS3_TRUE; + struct scsi_device *sdev = NULL; + U32 sdev_magic = 0; + U32 new_magic = 0; + S32 ret = PS3_SUCCESS; + + sdev = ps3_scsi_device_lookup(instance, PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos), 0); + if (sdev == NULL) { + goto l_out; + } + + sdev_magic = ps3_scsi_dev_magic(instance, sdev); + if (PS3_IS_VD_CHANNEL(instance, PS3_SDEV_CHANNEL(sdev)) || + ps3_sas_is_support_smp(instance)) { + new_magic = dev_pos->diskMagicNum; + } else { + new_magic = dev_pos->checkSum; + } + + if (new_magic == sdev_magic) { + LOG_INFO("hno:%u check magic same [%u:%u] magic[%#x]\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), PS3_SDEV_TARGET(sdev), + sdev_magic); + is_need_add = PS3_FALSE; + } else { + LOG_WARN("hno:%u check dev[%u:%u] magic is diff[%#x != %#x]\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev), + new_magic, sdev_magic); + ret = _ps3_del_disk(instance, sdev); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u del dev[%u:%u] unexpect ret[%d]\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev), ret); + } + } + ps3_scsi_device_put(instance, sdev); +l_out: + return is_need_add; +} + +void ps3_check_vd_member_change(struct ps3_instance *instance, + struct ps3_pd_entry *local_entry) +{ + struct scsi_device *sdev = NULL; + + if (!ps3_sas_is_support_smp(instance)) { + goto l_out; + } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0) && LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)) + (void)sdev; + if (ps3_check_pd_is_vd_member(local_entry->config_flag)) { + LOG_WARN("hno:%u change ready to component, remove device channel[%u], id[%u], begin\n", + PS3_HOST(instance), + PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos)); + ps3_pd_del(instance, &local_entry->disk_pos, local_entry->config_flag); + LOG_WARN("hno:%u change ready to component, remove device channel[%u], id[%u] end\n", + PS3_HOST(instance), + PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos)); + } else { + ps3_mutex_lock(&instance->dev_context.dev_scan_lock); + sdev = ps3_scsi_device_lookup(instance, PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos), 0); + if (sdev) { + ps3_scsi_device_put(instance, sdev); + ps3_mutex_unlock(&instance->dev_context.dev_scan_lock); + } else { + ps3_mutex_unlock(&instance->dev_context.dev_scan_lock); + ps3_linx80_vd_member_change(instance, local_entry); + } + LOG_WARN("hno:%u change component to ready, add device channel[%u], id[%u], begin\n", + PS3_HOST(instance), + PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos)); + ps3_pd_add(instance, &local_entry->disk_pos); + LOG_WARN("hno:%u change component to ready, add device channel[%u], id[%u], end\n", + PS3_HOST(instance), + PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos)); + } +#else + + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_PD_ATTR_WAIT_OS_SCAN, PS3_ERR_IJ_OS_SCAN, NULL); + INJECT_START(PS3_ERR_IJ_OS_SCAN, NULL); + ps3_mutex_lock(&instance->dev_context.dev_scan_lock); + sdev = ps3_scsi_device_lookup(instance, PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos), 0); + if (sdev) { + if (ps3_check_pd_is_vd_member(local_entry->config_flag)) { + if (sdev->no_uld_attach != 1) { + sdev->no_uld_attach = 1; + ps3_qos_vd_member_change(instance, local_entry, sdev, PS3_TRUE); + LOG_WARN("hno:%u pd[%u:%u] change ready to component start\n", + PS3_HOST(instance), sdev->channel, sdev->id); + PS3_WARN_ON(scsi_device_reprobe(sdev)); + LOG_WARN("hno:%u pd[%u:%u] change ready to component end\n", + PS3_HOST(instance), sdev->channel, sdev->id); + } + } else { + if (sdev->no_uld_attach != 0) { + sdev->no_uld_attach = 0; + ps3_qos_vd_member_change(instance, local_entry, sdev, PS3_FALSE); + LOG_WARN("hno:%u pd[%u:%u] change component to ready start\n", + PS3_HOST(instance), sdev->channel, sdev->id); + PS3_WARN_ON(scsi_device_reprobe(sdev)); + LOG_WARN("hno:%u pd[%u:%u] change component to ready end\n", + PS3_HOST(instance), sdev->channel, sdev->id); + } + } + ps3_scsi_device_put(instance, sdev); + } + ps3_mutex_unlock(&instance->dev_context.dev_scan_lock); +#endif +l_out: + return; +} + +static struct PS3DiskDevPos* ps3_get_info_pos( + struct ps3_instance *instance, U8 channel, U16 target_id, U8 disk_type) +{ + struct PS3DiskDevPos *disk_Pos_ret = NULL; + struct ps3_pd_entry *pd_entry = NULL; + struct PS3VDEntry *vd_entry = NULL; + + if (disk_type == PS3_DISK_TYPE_PD) { + pd_entry = ps3_dev_mgr_lookup_pd_info(instance, + channel, target_id); + if (pd_entry != NULL) { + disk_Pos_ret = &pd_entry->disk_pos; + } + } + else if (disk_type == PS3_DISK_TYPE_VD) { + vd_entry = ps3_dev_mgr_lookup_vd_info(instance, + channel, target_id); + if (vd_entry != NULL) { + disk_Pos_ret = &vd_entry->diskPos; + } + } + + return disk_Pos_ret; +} + +static inline S32 ps3_add_disk(struct ps3_instance *instance, + struct PS3DiskDevPos* dev_pos, U8 disk_type) +{ + S32 ret = PS3_SUCCESS; + struct PS3DiskDevPos* dev_pos_newes = NULL; + + if (disk_type == PS3_DISK_TYPE_PD) { + ret = ps3_dev_mgr_pd_info_get(instance, + PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos), PS3_PDID(dev_pos)); + } + else if (disk_type == PS3_DISK_TYPE_VD) { + ret = ps3_update_single_vd_info(instance, &dev_pos->diskDev.ps3Dev); + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u single add dev[%u:%u] get info NOK\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + goto l_out; + } + + dev_pos_newes = ps3_get_info_pos(instance, PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos), disk_type); + if (dev_pos_newes == NULL) { + ret = -PS3_FAILED; + LOG_WARN("hno:%u update pos[%u:%u] invalid\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + goto l_out; + } + + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_ADD_DEV_WAIT_OS_PRIV_DATA, + PS3_ERR_IJ_GET_PRIV_DATA_DELAY, NULL); + if (!_ps3_add_disk_prepare(instance, dev_pos_newes)) { + goto l_out; + } + + INJECT_START_AT_TIME_WAIT_REV_PRE(PS3_ERR_IJ_ADD_DEV_WAIT_OS_PRIV_DATA, + PS3_ERR_IJ_GET_PRIV_DATA_DELAY, NULL); + ret = _ps3_add_disk(instance, PS3_CHANNEL(dev_pos_newes), + PS3_TARGET(dev_pos_newes), disk_type); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u single add dev[%u:%u] NOK\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos_newes), + PS3_TARGET(dev_pos_newes)); + goto l_out; + } +l_out: + return ret; +} + +static S32 ps3_pd_add(struct ps3_instance *instance, + struct PS3DiskDevPos* dev_pos) +{ + S32 ret = -PS3_FAILED; + ps3_mutex_lock(&instance->dev_context.dev_scan_lock); + + if (unlikely(!PS3_IS_PD_CHANNEL(instance, + PS3_CHANNEL(dev_pos)))) { + LOG_ERROR("hno:%u pd[%u:%u] single add, but channel is not pd\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + PS3_BUG(); + goto l_out; + } + + ret = ps3_add_disk(instance, dev_pos, PS3_DISK_TYPE_PD); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add PD NOK\n", + PS3_HOST(instance)); + goto l_out; + } +l_out: + ps3_mutex_unlock(&instance->dev_context.dev_scan_lock); + + return ret; +} + +static Bool ps3_pd_ext_del_done_check(struct ps3_instance *instance, + struct PS3DiskDevPos *dev_pos) +{ + struct scsi_device *sdev = NULL; + Bool is_need_del_done = PS3_FALSE; + S32 ret = PS3_SUCCESS; + +#ifdef _WINDOWS + sdev = ps3_scsi_device_lookup_win(instance, PS3_CHANNEL(dev_pos), PS3_TARGET(dev_pos)); + if (unlikely(sdev == NULL || sdev->add_ack != 1)) { + is_need_del_done = TRUE; + } +#else + struct ps3_pd_entry *pd_entry = NULL; + + sdev = ps3_scsi_device_lookup(instance, PS3_CHANNEL(dev_pos), PS3_TARGET(dev_pos), 0); + if(unlikely(sdev == NULL)) { + if (ps3_sas_is_support_smp(instance)) { + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, + PS3_PDID(dev_pos)); + if (pd_entry != NULL && pd_entry->sas_rphy != NULL) { + ps3_sas_remove_device(instance, &pd_entry->disk_pos, + pd_entry->encl_id, pd_entry->phy_id); + } else { + LOG_ERROR("hno:%u, can not found PD [%u:%u:%u] pd_entry:%p or sas_rphy is NULL\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos), PS3_PDID(dev_pos), pd_entry); + } + } + is_need_del_done = PS3_TRUE; + } +#endif + if (is_need_del_done) { + LOG_WARN("hno:%u dev id[%u:%u] not exist scsi device\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), PS3_TARGET(dev_pos)); + + ret = ps3_scsi_remove_device_done(instance, dev_pos, + PS3_DISK_TYPE_PD); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL7, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u dev[%u:%u:%u] magic[%#x] dev del done NOK %d\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos), PS3_PDID(dev_pos), + dev_pos->diskMagicNum, ret); + } + } else { + ps3_scsi_device_put(instance, sdev); + } + + return is_need_del_done; +} + +static S32 ps3_pd_del(struct ps3_instance *instance, + struct PS3DiskDevPos *dev_pos, U8 config_flag) +{ + S32 ret = -PS3_FAILED; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct ps3_pd_table* p_pd_tb = &p_dev_ctx->pd_table; + U16 disk_idx = 0; + + ps3_mutex_lock(&instance->dev_context.dev_scan_lock); + + if (!ps3_dev_id_valid_check(instance, PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos),PS3_DISK_TYPE_PD)) { + PS3_BUG(); + goto l_out; + } + + if (ps3_pd_ext_del_done_check(instance, dev_pos)) { + ret = PS3_SUCCESS; + goto l_clean_again; + } + + ret = ps3_del_disk(instance, PS3_CHANNEL(dev_pos), PS3_TARGET(dev_pos)); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL8, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u unable to delete scsi device PD[%u:%u] ret %d\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), PS3_TARGET(dev_pos), ret); + goto l_out; + } +l_clean_again: + disk_idx = p_pd_tb->pd_idxs[PS3_CHANNEL(dev_pos)][PS3_TARGET(dev_pos)]; + p_pd_tb->pd_idxs[PS3_CHANNEL(dev_pos)][PS3_TARGET(dev_pos)] = PS3_INVALID_VALUE; + + p_dev_ctx->pd_entries_array[disk_idx].config_flag = config_flag; + +l_out: + ps3_mutex_unlock(&instance->dev_context.dev_scan_lock); + return ret; + +} + +static S32 ps3_vd_add(struct ps3_instance *instance, + struct PS3DiskDevPos* dev_pos) +{ + S32 ret = -PS3_FAILED; + struct PS3Dev* dev = &dev_pos->diskDev.ps3Dev; + + if (unlikely(!PS3_IS_VD_CHANNEL(instance, dev->softChan))) { + LOG_ERROR("hno:%u VD[%u:%u] single add, but channel is not vd\n", + PS3_HOST(instance), dev->softChan, dev->devID); + PS3_BUG(); + goto l_out; + } + + ret = ps3_add_disk(instance, dev_pos, PS3_DISK_TYPE_VD); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u add VD NOK\n", + PS3_HOST(instance)); + goto l_out; + } +l_out: + return ret; +} + +static S32 ps3_vd_del(struct ps3_instance *instance, + U8 channel, U16 target_id) +{ + S32 ret = -PS3_FAILED; + + if (!ps3_dev_id_valid_check(instance, channel, target_id, + PS3_DISK_TYPE_VD)) { + PS3_BUG(); + goto l_out; + } + + ret = ps3_del_disk(instance, channel, target_id); + INJECT_START(PS3_ERR_IJ_FORCE_RET_FAIL4, &ret); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u unable to delete scsi device VD[%u:%u] ret %d\n", + PS3_HOST(instance), channel, target_id, ret); + goto l_out; + } + +l_out: + return ret; +} + +static S32 ps3_vd_hidden_change(struct ps3_instance *instance, + struct PS3Dev* dev) +{ + S32 ret = -PS3_FAILED; + struct PS3VDEntry *p_vd_entry = NULL; + struct PS3DiskDevPos disk_pos; + + p_vd_entry = ps3_get_single_vd_info(instance, dev); + if (unlikely(p_vd_entry == NULL)) { + LOG_ERROR("hno:%u sync get VD info NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + if (!p_vd_entry->isHidden) { + disk_pos = p_vd_entry->diskPos; + ret = ps3_vd_add(instance, &disk_pos); + } else { + ret = ps3_vd_del(instance, (U8)dev->softChan, dev->devID); + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u vd hidden change NOK, dev[%u:%u:%u], ret[%d]\n", + PS3_HOST(instance), dev->softChan, dev->devID, + dev->virtDiskID, ret); + ret = -PS3_FAILED; + } + +l_out: + return ret; +} + +static inline Bool ps3_check_pd_is_same(struct ps3_instance *instance, + struct PS3DiskDevPos* src_dev_pos, struct PS3DiskDevPos* dest_dev_pos) +{ + Bool ret_valid = PS3_FALSE; + + if (likely(dest_dev_pos->diskMagicNum == src_dev_pos->diskMagicNum && + PS3_DISKID(dest_dev_pos) == PS3_DISKID(src_dev_pos))) { + LOG_DEBUG("hno:%u check pd id same [%u:%u:%u] magic[%#x]\n", + PS3_HOST(instance), PS3_CHANNEL(dest_dev_pos), + PS3_TARGET(dest_dev_pos), PS3_PDID(dest_dev_pos), + src_dev_pos->diskMagicNum); + ret_valid = PS3_TRUE; + } else { + LOG_FILE_WARN("hno:%u check mismatch, src dev[%u:%u:%u] magic[%#x], " + "dest dev[%u:%u:%u] magic[%#x]\n", + PS3_HOST(instance), PS3_CHANNEL(src_dev_pos), + PS3_TARGET(src_dev_pos), PS3_PDID(src_dev_pos), + src_dev_pos->diskMagicNum, PS3_CHANNEL(dest_dev_pos), + PS3_TARGET(dest_dev_pos), PS3_PDID(dest_dev_pos), + dest_dev_pos->diskMagicNum); + } + + return ret_valid; +} +static inline void ps3_update_info_by_list_item(struct ps3_pd_entry *local_entry, + union PS3Device *list_item, Bool is_raid) +{ + if (unlikely((local_entry->disk_pos.diskMagicNum != + list_item->pd.diskPos.diskMagicNum) || + (PS3_DISKID(&local_entry->disk_pos) != + PS3_DISKID(&list_item->pd.diskPos)))) { + LOG_ERROR("Device is mismatch, local entry device[%u:%u:%u] " + "and magic[%#x], new device[%u:%u:%u] and magic[%#x]\n", + PS3_CHANNEL(&local_entry->disk_pos), + PS3_TARGET(&local_entry->disk_pos), + PS3_PDID(&local_entry->disk_pos), + local_entry->disk_pos.diskMagicNum, + PS3_CHANNEL(&list_item->pd.diskPos), + PS3_TARGET(&list_item->pd.diskPos), + PS3_PDID(&list_item->pd.diskPos), + list_item->pd.diskPos.diskMagicNum); + return; + } + + local_entry->config_flag = list_item->pd.configFlag; + local_entry->state = list_item->pd.diskState; + LOG_INFO("single pd info update PD[%u:%u] config_flag[%s], state[%s]\n", + PS3_CHANNEL(&list_item->pd.diskPos), PS3_TARGET(&list_item->pd.diskPos), + getPdStateName((MicPdState_e)local_entry->config_flag, is_raid), + getDeviceStateName((DeviceState_e)local_entry->state)); +} + +static S32 ps3_update_single_pd_info(struct ps3_instance *instance, + struct PS3DiskDevPos *dev_pos, union PS3Device *list_item) +{ + S32 ret = PS3_SUCCESS; + U8 channel = dev_pos->diskDev.ps3Dev.softChan; + struct ps3_pd_entry *p_pd_entry = NULL; + INJECT_START(PS3_ERR_IJ_FORCE_MOD_CHAN1, &channel); + if (unlikely(!PS3_IS_PD_CHANNEL(instance, channel))) { + LOG_ERROR("hno:%u , PD[%u:%u] info update, but channel is not pd\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + ret = -PS3_FAILED; + PS3_BUG(); + goto l_out; + } + + p_pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, + PS3_PDID(dev_pos)); + if (p_pd_entry == NULL) { + LOG_FILE_WARN("hno:%u single PD info update[%u:%u], cannot find entry\n", + PS3_HOST(instance), + PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + } + + if (p_pd_entry != NULL && !ps3_check_pd_is_same(instance, + &p_pd_entry->disk_pos, dev_pos) && list_item) { + ps3_update_info_by_list_item(p_pd_entry, list_item, instance->is_raid); + } else { + ret = ps3_dev_mgr_pd_info_get(instance, PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos), PS3_PDID(dev_pos)); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, single add get PD[%u:%u] info NOK\n", + PS3_HOST(instance), PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + goto l_out; + } + + p_pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, + PS3_PDID(dev_pos)); + if (p_pd_entry == NULL) { + LOG_WARN("hno:%u single PD info update[%u:%u], cannot find new entry\n", + PS3_HOST(instance), + PS3_CHANNEL(dev_pos), + PS3_TARGET(dev_pos)); + goto l_out; + } + } + + if (instance->ioc_adpter->check_vd_member_change != NULL) { + instance->ioc_adpter->check_vd_member_change(instance, p_pd_entry); + } + +l_out: + return ret; +} + +static void ps3_dev_update_pre_check(struct PS3EventDetail *event_detail, + U32 event_cnt) +{ + U8 i = 0; + U8 vd_count_idx = 0XFF; + U8 pd_count_idx = 0XFF; + U8 pd_info_idx = 0XFF; + + for (i = 0; i < event_cnt; i++) { + switch (event_detail[i].eventCode) { + case PS3_EVT_CODE(MGR_EVT_MULITPILE_PD_IN): + case PS3_EVT_CODE(MGR_EVT_MULITPILE_PD_OUT): + case PS3_EVT_CODE(MGR_EVT_MULITPILE_JBOD): + case PS3_EVT_CODE(MGR_EVT_MULITPILE_READY): + case PS3_EVT_CODE(MGR_EVT_BACKPLANE_ON): + case PS3_EVT_CODE(MGR_EVT_BACKPLANE_OFF): + case PS3_EVT_CODE(MGR_EVT_MULITPILE_PD_STATE_CHANGE): + pd_count_idx = i; + break; + case PS3_EVT_CODE(MGR_EVT_MULITPILE_VD_IN): + case PS3_EVT_CODE(MGR_EVT_MULITPILE_VD_OUT): + vd_count_idx = i; + break; + default: + break; + } + } + + if (pd_count_idx == 0xFF && vd_count_idx == 0xFF && + pd_info_idx == 0xFF) { + return; + } + + LOG_DEBUG("detail update pd_count_idx[%d], vd_count_idx[%d], pd_info_idx[%d]\n", + pd_count_idx, vd_count_idx, pd_info_idx); + + for (i = 0; i < event_cnt; i++) { + switch (event_detail[i].eventType) { + case PS3_EVT_PD_COUNT: + if (pd_count_idx !=0xFF && pd_count_idx != i) { + LOG_DEBUG("detail update remove %d eventCode[%d]\n", + i, event_detail[i].eventCode); + event_detail[i].eventType = + PS3_EVT_ILLEGAL_TYPE; + event_detail[i].eventCode = + PS3_EVT_CODE(MGR_EVT_PD_COUNT_START); + } + break; + case PS3_EVT_VD_COUNT: + if (vd_count_idx !=0xFF && vd_count_idx != i) { + LOG_DEBUG("detail update remove %d eventCode[%d]\n", + i, event_detail[i].eventCode); + event_detail[i].eventType = + PS3_EVT_ILLEGAL_TYPE; + event_detail[i].eventCode = + PS3_EVT_CODE(MGR_EVT_VD_COUNT_START); + } + break; + case PS3_EVT_PD_ATTR: + if (pd_info_idx !=0xFF && pd_info_idx != i) { + LOG_DEBUG("detail update remove %d eventCode[%d]\n", + i, event_detail[i].eventCode); + event_detail[i].eventType = + PS3_EVT_ILLEGAL_TYPE; + event_detail[i].eventCode = + PS3_EVT_CODE(MGR_EVT_PD_ATTR_START); + } + + break; + default: + break; + } + } +} + +static Bool ps3_get_sdev_pose_by_chl_tid(struct ps3_instance *instance, + const U8 channel, const U16 target_id, struct PS3DiskDevPos *disk_Pos) +{ + struct scsi_device *sdev = NULL; + struct ps3_scsi_priv_data *scsi_priv = NULL; + Bool ret = PS3_TRUE; + + sdev = ps3_scsi_device_lookup(instance, channel, target_id, 0); + if(unlikely(sdev == NULL)) { + ret = PS3_FALSE; + } + if (ret) { + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + scsi_priv = PS3_SDEV_PRI_DATA(sdev); + if (scsi_priv != NULL) { + *disk_Pos = scsi_priv->disk_pos; + } else { + ret = PS3_FALSE; + LOG_DEBUG("hno:%u get sdev pos, priv data NULL, [%u:%u],\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), PS3_SDEV_TARGET(sdev)); + } + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + ps3_scsi_device_put(instance, sdev); + } + + return ret; +} + +static S32 _ps3_add_remove_multi_pd(struct ps3_instance *instance, + U8 channel, U16 target_id) +{ + S32 ret = PS3_SUCCESS; + S32 ret_tmp = PS3_SUCCESS; + union PS3Device* p_dev = NULL; + struct PS3DiskDevPos pd_Pos; + U8 config_flag = MIC_PD_STATE_UNKNOWN; + + p_dev = ps3_dev_mgr_lookup_pd_list(instance, channel, target_id); + if (p_dev == NULL) { + if (ps3_get_sdev_pose_by_chl_tid(instance, channel, + target_id, &pd_Pos)) { + ret_tmp = ps3_pd_del(instance, &pd_Pos, + MIC_PD_STATE_UNKNOWN); + } + + goto l_out; + } + + if (ps3_pd_scsi_visible_check(instance, &p_dev->pd.diskPos, + ps3_get_converted_dev_type(p_dev->pd.driverType, + p_dev->pd.mediumType), p_dev->pd.configFlag, + p_dev->pd.diskState)) { + ret_tmp = ps3_pd_add(instance, &p_dev->pd.diskPos); + } else { + + ret_tmp = ps3_dev_mgr_pd_info_get(instance, + channel, target_id, PS3_PDID(&p_dev->pd.diskPos)); + if (ret_tmp != PS3_SUCCESS) { + LOG_ERROR("hno:%u get pd info NOK, [%u:%u], ret[%d]\n", + PS3_HOST(instance), channel, target_id, ret_tmp); + ret = -PS3_FAILED; + } + config_flag = p_dev->pd.configFlag; + + ret_tmp = ps3_pd_del(instance, &p_dev->pd.diskPos, config_flag); + } +l_out: + + if (ret_tmp != PS3_SUCCESS) { + LOG_ERROR("hno:%u add or del pd NOK, [%u:%u], ret[%d]\n", + PS3_HOST(instance), channel, target_id, ret_tmp); + ret = -PS3_FAILED; + } + + return ret; +} + +static S32 ps3_add_remove_multi_pd(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 ret_tmp = PS3_SUCCESS; + U16 i = 0; + U16 j = 0; + U8 chan_id = 0; + struct ps3_channel *pd_chan = instance->dev_context.channel_pd; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + + LOG_DEBUG("hno:%u, ready to update full pd count\n", + PS3_HOST(instance)); + + ret = ps3_dev_mgr_pd_list_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u get pd list NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + for (i = 0; i < p_dev_ctx->pd_channel_count; i++) { + chan_id = pd_chan[i].channel; + for (j = 0; j < pd_chan[i].max_dev_num; j++) { + ret_tmp = _ps3_add_remove_multi_pd(instance, chan_id, j); + if (ret_tmp != PS3_SUCCESS) { + ret = -PS3_FAILED; + } + } + } + +l_out: + LOG_DEBUG("hno:%u, update full pd count end\n", + PS3_HOST(instance)); + + return ret; +} + +static S32 ps3_add_remove_multi_vd(struct ps3_instance *instance) +{ + S32 ret_tmp = PS3_SUCCESS; + S32 ret = PS3_SUCCESS; + U16 i = 0; + U16 j = 0; + U8 chan_id = 0; + struct ps3_channel *vd_chan = instance->dev_context.channel_vd; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + union PS3Device* p_dev = NULL; + + LOG_DEBUG("hno:%u ready to update full vd count\n", + PS3_HOST(instance)); + + ret = ps3_dev_mgr_vd_list_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u get vd list NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + for (i = 0; i < p_dev_ctx->vd_channel_count; i++) { + chan_id = vd_chan[i].channel; + for (j = 0; j < vd_chan[i].max_dev_num; j++) { + + p_dev = ps3_dev_mgr_lookup_vd_list(instance, chan_id, j); + if (p_dev != NULL && ps3_vd_scsi_visible_check(instance, + &p_dev->vd.diskPos, p_dev->vd.isHidden, p_dev->vd.diskState)) { + ret_tmp = ps3_vd_add(instance, &p_dev->pd.diskPos); + } else { + ret_tmp = ps3_vd_del(instance, chan_id, j); + } + + if (ret_tmp != PS3_SUCCESS) { + LOG_ERROR("hno:%u update vd[%u:%u] count NOK, ret[%d]\n", + PS3_HOST(instance), chan_id, j, ret_tmp); + ret = -PS3_FAILED; + } + } + } +l_out: + LOG_DEBUG("hno:%u update full vd count end\n", + PS3_HOST(instance)); + + return ret; +} + +static S32 ps3_update_multi_pd_info(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 ret_tmp = PS3_SUCCESS; + U16 i = 0; + struct ps3_dev_context *p_dev_ctx = &instance->dev_context; + struct PS3DevList *p_pd_list = p_dev_ctx->pd_list_buf; + struct PS3Dev *p_dev = NULL; + + LOG_DEBUG("hno:%u ready to update full pd info\n", + PS3_HOST(instance)); + + ret = ps3_pd_list_get(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u, dev mgr get pd list NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + LOG_INFO("hno:%u get pd list count is %d\n", + PS3_HOST(instance), p_pd_list->count); + + for (i = 0; i < p_pd_list->count; i++) { + p_dev = PS3_DEV(&p_pd_list->devs[i].pd.diskPos); + + if (PS3_PDID_INVALID(&p_pd_list->devs[i].pd.diskPos)) { + LOG_WARN("hno:%u check pd list %d dev pdid is 0\n", + PS3_HOST(instance), i); + continue; + } + + if (!ps3_dev_id_valid_check(instance, (U8)p_dev->softChan, + p_dev->devID, PS3_DISK_TYPE_PD)) { + PS3_BUG(); + continue; + } + + LOG_INFO("hno:%u ready update pd info by list" + " %d dev[%u:%u:%u], magic[%#x], state[%s]\n", + PS3_HOST(instance), i, p_dev->softChan, p_dev->devID, + p_dev->phyDiskID, + p_pd_list->devs[i].pd.diskPos.diskMagicNum, + getDeviceStateName((DeviceState_e)p_pd_list->devs[i].pd.diskState)); + + ret_tmp = ps3_update_single_pd_info(instance, &p_pd_list->devs[i].pd.diskPos, + &p_pd_list->devs[i]); + if (ret_tmp != PS3_SUCCESS) { + LOG_ERROR("hno:%u NOK, %u:%u, ret[%d]\n", + PS3_HOST(instance), p_dev->softChan, p_dev->devID, ret_tmp); + ret = -PS3_FAILED; + } + } + +l_out: + LOG_DEBUG("hno:%u update full pd info end ret[%d]\n", + PS3_HOST(instance), ret); + + return ret; +} + +static inline S32 ps3_dev_evt_update_pd_count(struct ps3_instance *instance, + U32 eventCode, struct PS3DiskDevPos *dev_pos) +{ + S32 ret = PS3_SUCCESS; + + switch(eventCode) + { + case PS3_EVT_CODE(MGR_EVT_DEVM_DISK_IN): + case PS3_EVT_CODE(MGR_EVT_DEVM_JBOD): + case PS3_EVT_CODE(MGR_EVT_DEVM_DISK_CHANGE): + ret = ps3_pd_add(instance, dev_pos); + break; + case PS3_EVT_CODE(MGR_EVT_DEVM_DISK_OUT): + ret = ps3_pd_del(instance, dev_pos, MIC_PD_STATE_UNKNOWN); + break; + case PS3_EVT_CODE(MGR_EVT_DEVM_READY): + case PS3_EVT_CODE(MGR_EVT_PD_PRE_READY): + ret = ps3_pd_del(instance, dev_pos, MIC_PD_STATE_READY); + break; + default: + ret = ps3_add_remove_multi_pd(instance); + break; + } + + return ret; +} + +static inline S32 ps3_dev_evt_update_vd_count(struct ps3_instance *instance, + U32 eventCode, struct PS3DiskDevPos *dev_pos) +{ + S32 ret = PS3_SUCCESS; + + switch (eventCode) { + case PS3_EVT_CODE(MGR_EVT_VD_CREATED): + case PS3_EVT_CODE(MGR_EVT_VD_OPTIMAL): + case PS3_EVT_CODE(MGR_EVT_VD_PARTIAL_DEGRADE): + case PS3_EVT_CODE(MGR_EVT_VD_DEGRADE): + case PS3_EVT_CODE(MGR_EVT_VD_UNLOCK): + ret = ps3_vd_add(instance, dev_pos); + break; + case PS3_EVT_CODE(MGR_EVT_VD_DELETED): + case PS3_EVT_CODE(MGR_EVT_VD_OFFLINE): + ret = ps3_vd_del(instance, PS3_CHANNEL(dev_pos), PS3_TARGET(dev_pos)); + break; + case PS3_EVT_CODE(MGR_EVT_VD_HIDDEN_CHANGE): + ret = ps3_vd_hidden_change(instance, PS3_DEV(dev_pos)); + break; + default: + ret = ps3_add_remove_multi_vd(instance); + break; + } + + return ret; +} + +static inline S32 ps3_dev_evt_update_pd_attr(struct ps3_instance *instance, + U32 eventCode, struct PS3DiskDevPos *dev_pos) +{ + S32 ret = PS3_SUCCESS; + (void)eventCode; + + ret = ps3_update_single_pd_info(instance, dev_pos, NULL); + + return ret; +} + +S32 ps3_dev_update_detail_proc(struct ps3_instance *instance, + struct PS3EventDetail *event_detail, U32 event_cnt) +{ + S32 ret = PS3_SUCCESS; + S32 ret_map = PS3_SUCCESS; + U32 i = 0; + + LOG_INFO("hno:%u, event detail count[%d]\n", + PS3_HOST(instance), event_cnt); + + ps3_dev_update_pre_check(event_detail, event_cnt); + + for (i = 0; i < event_cnt; i++) { + + LOG_INFO("hno:%u event detail %d event type[%s]," + " eventCode is [%s], dev[%u:%u:%u]\n", + PS3_HOST(instance), i, + nameMgrEvtType(event_detail[i].eventType), + mgrEvtCodeTrans(event_detail[i].eventCode), + PS3_CHANNEL(&event_detail[i].devicePos), + PS3_TARGET(&event_detail[i].devicePos), + PS3_VDID(&event_detail[i].devicePos)); + + switch (event_detail[i].eventType) { + case PS3_EVT_PD_COUNT: + ret = ps3_dev_evt_update_pd_count(instance, + event_detail[i].eventCode, + &event_detail[i].devicePos); + break; + case PS3_EVT_VD_COUNT: + ret = ps3_dev_evt_update_vd_count(instance, + event_detail[i].eventCode, + &event_detail[i].devicePos); + break; + case PS3_EVT_PD_ATTR: + ret = ps3_dev_evt_update_pd_attr(instance, + event_detail[i].eventCode, + &event_detail[i].devicePos); + break; + default: + break; + } + + if (ret != PS3_SUCCESS) { + ret_map |= event_detail[i].eventType; + } + } + + return ret_map; +} + +S32 ps3_dev_update_full_proc(struct ps3_instance *instance, + MgrEvtType_e event_type) +{ + S32 ret = -PS3_FAILED; + + switch (event_type) { + case PS3_EVT_PD_COUNT: + ret = ps3_add_remove_multi_pd(instance); + break; + case PS3_EVT_VD_COUNT: + ret = ps3_add_remove_multi_vd(instance); + break; + case PS3_EVT_PD_ATTR: + ret = ps3_update_multi_pd_info(instance); + break; + default: + break; + } + + return ret; +} + +static S32 ps3_dev_vd_pending_resend(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dev_context *p_dev_ctx = &cmd->instance->dev_context; + memset(p_dev_ctx->vd_info_buf_async, + 0, sizeof(struct PS3VDInfo)); + + ps3_vd_pending_filter_table_build((U8*) + p_dev_ctx->vd_info_buf_async); + + PS3_MGR_CMD_STAT_INC(cmd->instance, cmd); + + ret = ps3_async_cmd_send(cmd->instance, cmd); + if (ret != PS3_SUCCESS) { + LOG_FILE_ERROR("trace_id[0x%llx], hno:%u re send vd pending cmd faild\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + } + + return ret; + +} + +static Bool ps3_dev_vd_pending_data_switch(struct ps3_cmd *cmd) +{ + S32 i = 0; + Bool ret = PS3_FALSE; + struct ps3_dev_context *p_dev_ctx = &cmd->instance->dev_context; + U8 new_vd_table_idx = (p_dev_ctx->vd_table_idx + 1) & 1; + struct ps3_vd_table *p_new_vd_tb = &p_dev_ctx->vd_table[new_vd_table_idx]; + struct PS3VDEntry *p_new_vd_array = p_dev_ctx->vd_entries_array[new_vd_table_idx]; + U8 old_vd_table_idx = p_dev_ctx->vd_table_idx & 1; + struct ps3_vd_table *p_old_vd_tb = &p_dev_ctx->vd_table[old_vd_table_idx]; + struct PS3VDEntry *p_old_vd_array = p_dev_ctx->vd_entries_array[old_vd_table_idx]; + struct PS3VDEntry *p_vd_entry = p_dev_ctx->vd_info_buf_async->vds; + struct PS3VDEntry *vd_entry_old = NULL; + struct PS3Dev *p_dev = NULL; + U16 virtDiskIdx = PS3_INVALID_DEV_ID; + struct scsi_device *sdev = NULL; + + memcpy(p_new_vd_tb->vd_idxs_array, p_old_vd_tb->vd_idxs_array, + p_dev_ctx->total_vd_count * sizeof(U16)); + memcpy(p_new_vd_array, p_old_vd_array, (PS3_MAX_VD_COUNT(cmd->instance) + 1) * + sizeof(struct PS3VDEntry)); + + for (i = 0; i < p_dev_ctx->vd_info_buf_async->count; i++) { + if (PS3_VDID_INVALID(&p_vd_entry[i].diskPos)) { + LOG_WARN_IN_IRQ(cmd->instance, + "hno:%u, init %d of %d vd info NOK, vdid is 0\n", + PS3_HOST(cmd->instance), i, + p_dev_ctx->vd_info_buf_sync->count); + continue; + } + p_dev = PS3_DEV(&p_vd_entry[i].diskPos); + if (!ps3_dev_id_valid_check(cmd->instance, (U8)p_dev->softChan, + p_dev->devID, PS3_DISK_TYPE_VD)) { + LOG_ERROR_IN_IRQ(cmd->instance, + "trace_id[0x%llx], hno:%u vd pending " + "%d err softchan:%d, or dev id > max, %d>%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), + i, p_dev->softChan, p_dev->devID, + p_dev_ctx->max_dev_in_channel[p_dev->softChan]); + PS3_BUG_NO_SYNC(); + continue; + } + virtDiskIdx = get_offset_of_vdid(PS3_VDID_OFFSET(cmd->instance), p_dev->virtDiskID); + if (unlikely(virtDiskIdx > PS3_MAX_VD_COUNT(cmd->instance))) { + LOG_WARN_IN_IRQ(cmd->instance, "hno:%u, init %d of %d vd info NOK, vir_id[%d] > max[%d]\n", + PS3_HOST(cmd->instance), i, + p_dev_ctx->vd_info_buf_sync->count, + virtDiskIdx, PS3_MAX_VD_COUNT(cmd->instance)); + continue; + } + LOG_INFO_IN_IRQ(cmd->instance, + "hno:%u update vd[%u:%u] info\n", + PS3_HOST(cmd->instance), p_dev->softChan, p_dev->devID); + + ps3_qos_vd_init(cmd->instance, &p_vd_entry[i]); + vd_entry_old = ps3_dev_mgr_lookup_vd_info_by_id(cmd->instance, p_dev->virtDiskID); + ps3_qos_vd_attr_change(cmd->instance, vd_entry_old, &p_vd_entry[i]); + p_new_vd_tb->vd_idxs[p_dev->softChan][p_dev->devID] = + p_dev->virtDiskID; + memcpy(&p_new_vd_array[virtDiskIdx], &p_vd_entry[i], + sizeof(struct PS3VDEntry)); + + sdev = ps3_scsi_device_lookup(cmd->instance, p_dev->softChan, p_dev->devID, 0); + if(sdev != NULL) { + ps3_vd_busy_scale_get(&p_new_vd_array[virtDiskIdx]); + if (ps3_sdev_bdi_stable_writes_get(sdev)) { + if (!(p_vd_entry[i].bdev_bdi_cap & PS3_STABLE_WRITES_MASK)) { + ps3_sdev_bdi_stable_writes_clear(cmd->instance, sdev); + } + } else { + if (p_vd_entry[i].bdev_bdi_cap & PS3_STABLE_WRITES_MASK) { + ps3_sdev_bdi_stable_writes_set(cmd->instance, sdev); + } + } + ps3_scsi_device_put(cmd->instance, sdev); + } + + ps3_vd_info_show(cmd->instance, &p_new_vd_array[virtDiskIdx]); +#ifndef _WINDOWS + if (p_vd_entry[i].maxIOSize != 0) { + ps3_change_sdev_max_sector(cmd->instance, &p_vd_entry[i]); + } else { + LOG_DEBUG("hno:%u vd[%u:%u] update max sector num is:0\n", + PS3_HOST(cmd->instance), p_dev->softChan, p_dev->devID); + } +#endif + } + mb(); + if ( p_dev_ctx->vd_table_idx == (PS3_VD_TABLE_NUM -1)) { + p_dev_ctx->vd_table_idx = 0; + } else { + p_dev_ctx->vd_table_idx++; + } + mb(); + + LOG_INFO_IN_IRQ(cmd->instance, + "trace_id[0x%llx], hno:%u vd pending change cur_idx to [%d]\n", + cmd->trace_id, PS3_HOST(cmd->instance), p_dev_ctx->vd_table_idx); + + return ret; +} + +S32 ps3_dev_vd_pending_proc(struct ps3_cmd *cmd, U16 reply_flags) +{ + ULong flags = 0; + ULong flags1 = 0; + S32 ret = PS3_SUCCESS; + struct ps3_dev_context *p_dev_ctx = NULL; + struct ps3_instance *instance = cmd->instance; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + p_dev_ctx = &instance->dev_context; + p_dev_ctx->subwork += 1; + LOG_DEBUG("trace_id[0x%llx], hno:%u got a vd pending response, cur_idx[%d]\n", + cmd->trace_id, PS3_HOST(instance), p_dev_ctx->vd_table_idx); + + PS3_MGR_CMD_BACK_INC(instance, cmd, reply_flags); + if (unlikely(reply_flags == PS3_REPLY_WORD_FLAG_FAIL)) { + LOG_ERROR_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u vd pending cmd return failed\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + if (p_dev_ctx->vd_pending_cmd == NULL) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u vd pending is unsubscribed!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + if (!instance->state_machine.is_load) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u instance is suspend or instance unload!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u instance is not operational!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u vd pending had [%d] vds\n", + cmd->trace_id, PS3_HOST(instance), p_dev_ctx->vd_info_buf_async->count); + + ps3_dev_vd_pending_data_switch(cmd); + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if(instance->dev_context.abort_vdpending_cmd == 0){ + ret = ps3_dev_vd_pending_resend(cmd); + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + if (ret == PS3_SUCCESS) { + goto l_out; + } + }else{ + LOG_FILE_INFO("hno:%u vd pending cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->dev_context.vd_pending_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + ret = ps3_dev_mgr_vd_info_subscribe(instance); + if (ret != PS3_SUCCESS) { + LOG_INFO_IN_IRQ(instance, "hno:%u subscribe failed!\n", + PS3_HOST(instance)); + } + + instance->dev_context.abort_vdpending_cmd = 0; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + goto l_out; + } +l_failed: + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], CFID[%d], hno:%u to dead\n", + cmd->trace_id, cmd->index, PS3_HOST(instance)); + +l_out: + p_dev_ctx->subwork -= 1; + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], CFID[%d], hno:%u end proc a vd pending response, subwork:%d,ret:%d\n", + cmd->trace_id, cmd->index, PS3_HOST(instance), p_dev_ctx->subwork,ret); + return ret; +} + +#ifdef _WINDOWS +BOOL ps3_device_check_and_ack(struct ps3_instance *instance, + U8 channel_type, U8 channel, U16 target_id) +{ + S32 ret_tmp = PS3_SUCCESS; + BOOL ret = FALSE; + struct ps3_pd_entry *p_pd_entry = NULL; + struct PS3VDEntry *p_vd_entry = NULL; + struct PS3DiskDevPos* p_diskPos = NULL; + U8 dev_type = PS3_DISK_TYPE_UNKNOWN; + + if (!ps3_scsi_visible_check(instance, channel, target_id, channel_type)) { + goto l_out; + } + + if (channel_type == PS3_DISK_TYPE_PD) { + p_pd_entry = ps3_dev_mgr_lookup_pd_info(instance, channel, target_id); + if (p_pd_entry) { + + p_diskPos = &p_pd_entry->disk_pos; + dev_type = PS3_DISK_TYPE_PD; + + } + } + else if (channel_type == PS3_DISK_TYPE_VD) { + p_vd_entry = ps3_dev_mgr_lookup_vd_info(instance, channel, target_id); + if (p_vd_entry) { + p_diskPos = &p_vd_entry->diskPos; + dev_type = PS3_DISK_TYPE_VD; + } + } + + if (p_diskPos == NULL) { + goto l_out; + } + + ret_tmp = ps3_scsi_add_device_ack(instance, p_diskPos, dev_type); + if (ret_tmp != PS3_SUCCESS) { + LOG_ERROR("hno:%u dev[%u:%u] magic[%#x] pre scan ack NOK, ret %d\n", + PS3_HOST(instance), channel, target_id, + p_diskPos->diskMagicNum, ret_tmp); + } else { + LOG_INFO("hno:%u dev_type[%d] id[%u:%u] send ack success\n", + PS3_HOST(instance), dev_type, channel, target_id); + + ret = TRUE; + } +l_out: + return ret; +} +#endif diff --git a/drivers/scsi/ps3stor/ps3_device_update.h b/drivers/scsi/ps3stor/ps3_device_update.h new file mode 100644 index 0000000000000000000000000000000000000000..e51e8db3b04d94cca52f0bb8b30e5c56ba99d178 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_device_update.h @@ -0,0 +1,36 @@ + +#ifndef _PS3_DEVICE_UPDATE_H_ +#define _PS3_DEVICE_UPDATE_H_ + +#ifndef _WINDOWS +#include +#endif + +#include "ps3_htp_event.h" +#include "ps3_instance_manager.h" + +Bool ps3_pd_scsi_visible_check(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type, U8 config_flag, + U8 pd_state); + +S32 ps3_dev_update_detail_proc(struct ps3_instance *instance, + struct PS3EventDetail *event_detail, U32 event_cnt); + +S32 ps3_dev_update_full_proc(struct ps3_instance *instance, + MgrEvtType_e event_type); + +S32 ps3_dev_vd_pending_proc(struct ps3_cmd *cmd, U16 reply_flags); + +#ifdef _WINDOWS + +BOOL ps3_device_check_and_ack(struct ps3_instance *instance, + U8 channel_type, U8 channel, U16 target_id); +#endif +U32 ps3_scsi_dev_magic(struct ps3_instance *instance, struct scsi_device *sdev); + +void ps3_scsi_scan_host(struct ps3_instance *instance); + +void ps3_check_vd_member_change(struct ps3_instance *instance, + struct ps3_pd_entry *local_entry); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_drv_readme.sh b/drivers/scsi/ps3stor/ps3_drv_readme.sh new file mode 100644 index 0000000000000000000000000000000000000000..e1a86069dca9c77a834d8cbf01e09dee610b4210 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_drv_readme.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# 检查参数 +num=0 +while getopts :i:o:h opt +do + case "$opt" in + "o") VERSION_FILE=$OPTARG + num=$(($num+1)) + ;; + "i") TOOLCHAIN_ID=$OPTARG + num=$(($num+1)) + ;; + "h") echo "Usage: ps3_drv_readme.sh -o [-i ]" + ;; + *) echo "Unknown option: $opt. Usage: ps3_drv_readme.sh -o [-i ]" + ;; + esac +done + +if [ $num -ne 1 ]&&[ $num -ne 2 ]; then + echo "Invalid command. Usage: ps3_drv_readme.sh -o [-i ]" + exit 1 +fi + +# 将toolchain id 写入版本信息头文件 +if [ "$TOOLCHAIN_ID" == "no" ]; then + TOOLCHAIN_ID='' +fi + +DRV_TOOLCHAIN="#define PS3_DRV_TOOLCHAIN_ID \"${TOOLCHAIN_ID}\"" +sed -i "/PS3_DRV_TOOLCHAIN_ID/c ${DRV_TOOLCHAIN}" $VERSION_FILE + +# 从已生成的版本信息头文件中获取版本信息 +CUR_DIR=$(dirname $0) +README_FILE=${CUR_DIR}/ps3_drv_readme.txt + +VERSION=$(grep PS3_DRV_VERSION ${VERSION_FILE} | cut -d '"' -f 2- |cut -d '"' -f 1) +COMMIT_ID=$(grep PS3_DRV_COMMIT_ID ${VERSION_FILE} | cut -d '"' -f 2- |cut -d '"' -f 1) +BRANCH=$(grep PS3_DRV_BRANCH ${VERSION_FILE} | cut -d '"' -f 2- |cut -d '"' -f 1) +BUILD_TIME=$(grep PS3_DRV_BUILD_TIME ${VERSION_FILE} | cut -d '"' -f 2- |cut -d '"' -f 1) +ARCH=$(grep PS3_DRV_ARCH ${VERSION_FILE} | cut -d '"' -f 2- |cut -d '"' -f 1) +PRODUCT_SUPPORT=$(grep PS3_DRV_PRODUCT_SUPPORT ${VERSION_FILE} | cut -d '"' -f 2- |cut -d '"' -f 1) + +# 将版本信息写入 readme.txt +echo "version : " ${VERSION} > ${README_FILE} #第一行,覆盖写 +echo "commit_id : " ${COMMIT_ID} >> ${README_FILE} #第二行开始,用追加写 +echo "toolchain_id : " ${TOOLCHAIN_ID} >> ${README_FILE} #第二行开始,用追加写 +echo "build_time : " ${BUILD_TIME} >> ${README_FILE} #第二行开始,用追加写 +echo "arch : " ${ARCH} >> ${README_FILE} #第二行开始,用追加写 +echo "product_support : " ${PRODUCT_SUPPORT} >> ${README_FILE} #第二行开始,用追加写 diff --git a/drivers/scsi/ps3stor/ps3_drv_readme.txt b/drivers/scsi/ps3stor/ps3_drv_readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..b69fd18ad7b05ad5e1cabb5624eb7857a94f64d9 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_drv_readme.txt @@ -0,0 +1,5 @@ +version : 2.5.0.16 +commit_id : 1a43aaf bcd87d4 +toolchain_id : +build_time : Oct 31 2024 22:09:48 +product_support : RAID/HBA diff --git a/drivers/scsi/ps3stor/ps3_drv_ver.h b/drivers/scsi/ps3stor/ps3_drv_ver.h new file mode 100644 index 0000000000000000000000000000000000000000..9d893bd4eddfaeda1482ffe5143529dc356af8f7 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_drv_ver.h @@ -0,0 +1,15 @@ +#ifndef _PS3_DRV_VER_H_ +#define _PS3_DRV_VER_H_ + +#define PS3_PRIVATE_VERSION "00.000.00.01" +#define PS3_DRV_VERSION "2.5.0.16" +#define PS3_DRV_COMMIT_ID "1a43aaf bcd87d4" +#define PS3_DRV_BUILD_TIME "Oct 31 2024 22:09:48" +#define PS3_DRV_TOOLCHAIN_ID "" + +#define PS3_DRV_PRODUCT_SUPPORT "RAID/HBA" +#define PS3_DRV_LICENSE "GPL" +#define PS3_DRV_AUTHOR "ps3stor" +#define PS3_DRV_DESCRIPTION "ps3stor driver" + +#endif diff --git a/drivers/scsi/ps3stor/ps3_dump.h b/drivers/scsi/ps3stor/ps3_dump.h new file mode 100644 index 0000000000000000000000000000000000000000..d17d4323fe353571ecb7c5f3f3ef0200878ec7c6 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_dump.h @@ -0,0 +1,185 @@ + +#ifndef _PS3_CRASH_DUMP_H_ +#define _PS3_CRASH_DUMP_H_ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#else +#include "ps3_worker.h" +#endif +#include "ps3_platform_utils.h" +#include "ps3_htp.h" +#include "ps3_htp_def.h" + +#define PS3_DUMP_DATA_MAX_NUM 512 + +#define WAIT_DUMP_COLLECT (1000) +#define WAIT_DUMP_TIMES_DEFAULT (300) +#define WAIT_DUMP_TIMES_MIN (10) +#define WAIT_DUMP_TIMES_MAX (3600) + +#define WAIT_DUMP_DMA_DONE (200) +#ifndef _WINDOWS +#ifdef __KERNEL__ +#define PS3_DUMP_FILE_DIR "/var/log" +#else +#define PS3_DUMP_FILE_DIR "/tmp" +#endif +#else +#define PS3_DUMP_FILE_DIR "c:" +#endif +#define PS3_DUMP_FILE_CORE_PREFIX "core-" +#define PS3_DUMP_FILE_FWLOG_PREFIX "fwlog-" +#define PS3_DUMP_FILE_BAR_PREFIX "bar-" + +#define PS3_DUMP_STATUS_REG_DMA_FINISH_MASK (0x1 << 0) +#define PS3_DUMP_STATUS_REG_CRASH_DUMP_MASK (0x1 << 1) +#define PS3_DUMP_STATUS_REG_FW_DUMP_MASK (0x1 << 2) +#define PS3_DUMP_STATUS_REG_BAR_DUMP_MASK (0x1 << 3) +#define PS3_DUMP_STATUS_REG_CRASH_DUMP_TRIGGER_MASK (0x1 << 4) +#define PS3_DUMP_STATUS_REG_FW_DUMP_TRIGGER_MASK (0x2 << 4) +#define PS3_DUMP_STATUS_REG_BAR_DUMP_TRIGGER_MASK (0x3 << 4) +#define PS3_DUMP_STATUS_REG_ABORT_MASK (0x1 << 6) +#define PS3_DUMP_STATUS_REG_MASK (0x0F) +#define PS3_DUMP_STATUS_REG_INVALID_BITS_MASK (0x7F) + +#define PS3_REG_TEST(val, mask) (((val) & (mask)) ? PS3_TRUE:PS3_FALSE) +#define PS3_REG_SET(val, mask) (((val) |= (mask))) +#define PS3_REG_CLR(val, mask) ((val) &= (~(mask))) + +#define PS3_IOC_DUMP_SUPPORT(ins) \ + (ins->dump_context.is_dump_support) + +enum ps3_dump_work_status { + PS3_DUMP_WORK_UNKNOWN, + PS3_DUMP_WORK_RUNNING, + PS3_DUMP_WORK_STOP, + PS3_DUMP_WORK_DONE, + PS3_DUMP_WORK_CANCEL, +}; + +enum ps3_dump_irq_handler_work_status { + PS3_DUMP_IRQ_HANDLER_WORK_UNKNOWN, + PS3_DUMP_IRQ_HANDLER_WORK_RUNNING, + PS3_DUMP_IRQ_HANDLER_WORK_STOP, + PS3_DUMP_IRQ_HANDLER_WORK_DONE, + PS3_DUMP_IRQ_HANDLER_WORK_CANCEL, +}; + +enum ps3_dump_env { + PS3_DUMP_ENV_UNKNOWN, + PS3_DUMP_ENV_CLI, + PS3_DUMP_ENV_NOTIFY, + PS3_DUMP_ENV_COUNT, +}; + +enum ps3_dump_file_status { + PS3_DUMP_FILE_UNKNOWN, + PS3_DUMP_FILE_OPEN, + PS3_DUMP_FILE_CLOSE, + PS3_DUMP_FILE_MAX, +}; + +#define PS3_DUMP_FILE_DIR_LEN (128) +#define PS3_DUMP_FILE_NAME_LEN (256) + +struct ps3_dump_file_info { + U8 filename[PS3_DUMP_FILE_NAME_LEN]; +#ifdef _WINDOWS + HANDLE fp; +#else + struct file *fp; +#endif + U64 file_size; + U32 file_w_cnt; + U32 file_status; + U32 type; + U8 reserved[4]; +}; + +struct ps3_dump_context { + U8 dump_dir[PS3_DUMP_FILE_DIR_LEN]; + U64 dump_data_size; + S8 dump_type; + S32 dump_state; + U32 dump_env; + U32 dump_work_status; + U32 dump_irq_handler_work_status; + U64 copyed_data_size; + U8 *dump_dma_buf; + dma_addr_t dump_dma_addr; + U32 dump_dma_wait_times; +#ifdef _WINDOWS + struct ps3_delay_worker dump_work; + ps3_mutex dump_mutex; +#else + struct workqueue_struct *dump_work_queue; + struct delayed_work dump_work; + + struct workqueue_struct *dump_irq_handler_work_queue; + struct work_struct dump_irq_handler_work; + spinlock_t dump_irq_handler_lock; + U32 dump_enabled; + +#endif + ps3_mutex dump_lock; + struct ps3_instance *instance; + struct ps3_dump_file_info dump_out_file; + struct ps3_cmd *dump_pending_cmd; + + U32 dump_pending_send_times; + U32 dump_type_times; + U32 dump_state_times; + Bool is_dump_support; + Bool is_hard_recovered; + + U8 reserved[2]; +}; +static inline const S8 *ps3_dump_type_to_name(S32 dump_type) +{ + static const S8 *name[] = { + [PS3_DUMP_TYPE_UNKNOWN] = "NULL", + [PS3_DUMP_TYPE_CRASH] = "dump_crash", + [PS3_DUMP_TYPE_FW_LOG] = "fw_log", + [PS3_DUMP_TYPE_BAR_DATA] = "bar_data" + }; + return name[dump_type]; +} + +extern S32 ps3_dump_init(struct ps3_instance *instance); +extern void ps3_dump_exit(struct ps3_instance *instance); +extern S32 ps3_dump_type_set(struct ps3_dump_context *ctxt, S32 type, U32 env); +extern S32 ps3_dump_state_set(struct ps3_dump_context *ctxt, S32 state); + +#ifndef _WINDOWS +extern struct ps3_dump_context *dev_to_dump_context(struct device *cdev); + +void ps3_dump_work_stop(struct ps3_instance *instance); + +#endif + +S32 ps3_dump_dma_buf_alloc(struct ps3_instance *instance); + +void ps3_dump_dma_buf_free(struct ps3_instance *instance); + +void ps3_dump_detect(struct ps3_instance *instance); + +#ifndef _WINDOWS +irqreturn_t ps3_dump_irq_handler(S32 virq, void *dev_id); + +#endif +void ps3_dump_ctrl_set_int_ready(struct ps3_instance *instance); + +Bool ps3_dump_is_trigger_log(struct ps3_instance *instance); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_err_def.h b/drivers/scsi/ps3stor/ps3_err_def.h new file mode 100644 index 0000000000000000000000000000000000000000..94a11215761736d60d81b0db68855903176b4c49 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_err_def.h @@ -0,0 +1,47 @@ + + +#ifndef _PS3_ERR_DEF_H_ +#define _PS3_ERR_DEF_H_ + +#include "ps3_htp_def.h" + + +enum { + PS3_SUCCESS = 0x00, + PS3_FAILED = 0x01, + PS3_TIMEOUT = 0x02, + PS3_IN_IRQ_POLLING = 0x03, + PS3_DEV_TYPE_UNKOWN = 0x04, + PS3_RETRY = 0x05, + PS3_EBUSY = 0x06, + PS3_EINVAL = 0x07, + PS3_ENOMEM = 0x08, + PS3_ENODEV = 0x09, + PS3_ERESTARTSYS = 0x0a, + PS3_ENOTTY = 0x0b, + PS3_RESP_ERR = 0x0c, + PS3_RESP_INT = 0x0d, + PS3_ACTIVE_ERR = 0x0e, + PS3_CMD_NO_RESP = 0x0f, + PS3_IO_BLOCK = 0x10, + PS3_IO_REQUEUE = 0x11, + PS3_IO_CONFLICT_IN_Q = 0x12, + PS3_IO_CONFLICT = 0x13, + PS3_MGR_REC_FORCE = 0x14, + PS3_RECOVERED = 0x15, + PS3_IN_UNLOAD = 0x16, + PS3_NO_RECOVERED = 0x17, + PS3_IN_QOS_Q = 0x18, + PS3_IN_PCIE_ERR = 0x19, +}; + +#define PS3_DRV_TRUE (1) +#define PS3_DRV_FALSE (0) + +struct ps3_fault_context { + U8 ioc_busy; + U8 reserved[2]; + ULong last_time; +}; + +#endif diff --git a/drivers/scsi/ps3stor/ps3_err_inject.c b/drivers/scsi/ps3stor/ps3_err_inject.c new file mode 100644 index 0000000000000000000000000000000000000000..d2c49c553f8d2fa1b6b0221abee9291768cdd93c --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_err_inject.c @@ -0,0 +1,3063 @@ + +#include + +#include "ps3_ioc_manager.h" +#include "ps3_err_inject.h" +#include "ps3_cmd_channel.h" +#include "ps3_mgr_cmd.h" +#include "ps3_module_para.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_ioc_state.h" +#include "ps3_scsih.h" +#include "ps3_sas_transport.h" + +#include +#include "ps3_inject.h" +#include "ps3_cmd_statistics.h" +#include + +#ifdef PS3_SUPPORT_INJECT + +struct ps3_rec_work_context g_work_que_recovery; +struct ps3_rec_work_context g_work_que_probe; + +static Ps3Injection_t g_ps3_err_scene[PS3_ERR_SCENE_NUM]; +static Bool is_inject_init = PS3_FALSE; +static U64 sgl_addr; + +void ps3_err_inject_sleep(U32 ms, U16 err_type) +{ + if ((err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) && + g_ps3_err_scene[err_type - 1].active) { + ps3_msleep(ms); + } +} + +void ps3_err_inject_sleep_rand(U32 min, U32 max, U16 err_type) +{ + U16 slepp_ms = min; + if ((err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) && + g_ps3_err_scene[err_type - 1].active) { + slepp_ms = min + prandom_u32_max(max - min); + ps3_msleep(slepp_ms); + } +} + +void ps3_err_inject_err_type_valid(U16 err_type) +{ + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + g_ps3_err_scene[err_type - 1].active = PS3_TRUE; + } +} + +void ps3_err_inject_err_type_clean(U16 err_type) +{ + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + g_ps3_err_scene[err_type - 1].active = PS3_FALSE; + } +} + +Bool ps3_err_inject_err_type_get(U16 err_type) +{ + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + return g_ps3_err_scene[err_type - 1].type; + } + + return PS3_FALSE; +} + +void ps3_err_inject_wait_pre(U16 err_type_wait) +{ + while(g_ps3_err_scene[err_type_wait-1].active && + !g_ps3_err_scene[err_type_wait-1].is_hit_pre) { + msleep(5); + } +} + +void ps3_err_inject_wait_post(U16 err_type_wait) +{ + while(g_ps3_err_scene[err_type_wait-1].active && + !g_ps3_err_scene[err_type_wait-1].is_hit_pre) { + msleep(5); + } +} + +void inject_register(U16 err_type, injectCallback callback) +{ + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + g_ps3_err_scene[err_type - 1].callback = callback; + } + + return ; +} + +void inject_active_intf(U16 err_type, U16 count) +{ + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + g_ps3_err_scene[err_type - 1].active = PS3_TRUE; + g_ps3_err_scene[err_type - 1].count = count; + g_ps3_err_scene[err_type - 1].is_hit_pre = PS3_FALSE; + g_ps3_err_scene[err_type - 1].is_hit_post = PS3_FALSE; + } + + return ; +} +void inject_execute_callback(U16 err_type, void * data) +{ + S32 ret = PS3_SUCCESS; + + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + if (g_ps3_err_scene[err_type-1].active == PS3_TRUE && + g_ps3_err_scene[err_type-1].count != 0) { + g_ps3_err_scene[err_type-1].is_hit_pre = PS3_TRUE; + if (g_ps3_err_scene[err_type-1].callback != NULL) { + ret = g_ps3_err_scene[err_type-1].callback(data); + } + g_ps3_err_scene[err_type-1].is_hit_post = PS3_TRUE; + if(g_ps3_err_scene[err_type-1].count > 0 && ret == PS3_SUCCESS){ + g_ps3_err_scene[err_type-1].count--; + } + } + } + + return ; +} + +void inject_execute_callback_at_time(U16 err_type, void * data) +{ + S32 ret = PS3_SUCCESS; + + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + + if (g_ps3_err_scene[err_type-1].active == PS3_TRUE) { + if (g_ps3_err_scene[err_type-1].count > 1) { + g_ps3_err_scene[err_type-1].count--; + } else if (g_ps3_err_scene[err_type-1].count == 1) { + g_ps3_err_scene[err_type-1].is_hit_pre = PS3_TRUE; + if (g_ps3_err_scene[err_type-1].callback != NULL) { + ret = g_ps3_err_scene[err_type-1].callback(data); + } + g_ps3_err_scene[err_type-1].is_hit_post = PS3_TRUE; + if(g_ps3_err_scene[err_type-1].count > 0 && ret == PS3_SUCCESS){ + g_ps3_err_scene[err_type-1].count--; + } + } + } + } + + return; +} + +void inject_execute_callback_relevance_wait_pre(U16 err_type, U16 err_type_wait, void * data) +{ + S32 ret = PS3_SUCCESS; + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + if (g_ps3_err_scene[err_type-1].active == PS3_TRUE && + g_ps3_err_scene[err_type_wait-1].active == PS3_TRUE && + g_ps3_err_scene[err_type-1].count != 0) { + g_ps3_err_scene[err_type-1].is_hit_pre = PS3_TRUE; + while(g_ps3_err_scene[err_type_wait-1].active && + !g_ps3_err_scene[err_type_wait-1].is_hit_pre) { + msleep(5); + } + if (g_ps3_err_scene[err_type-1].callback != NULL) { + ret = g_ps3_err_scene[err_type-1].callback(data); + } + g_ps3_err_scene[err_type-1].is_hit_post = PS3_TRUE; + if(g_ps3_err_scene[err_type-1].count > 0 && ret == PS3_SUCCESS){ + g_ps3_err_scene[err_type-1].count--; + } + } + } + + return ; +} + +void inject_execute_callback_relevance_wait_post(U16 err_type, U16 err_type_wait, void * data) +{ + S32 ret = PS3_SUCCESS; + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + if (g_ps3_err_scene[err_type-1].active == PS3_TRUE && + g_ps3_err_scene[err_type_wait-1].active == PS3_TRUE && + g_ps3_err_scene[err_type-1].count != 0) { + g_ps3_err_scene[err_type-1].is_hit_pre = PS3_TRUE; + while(g_ps3_err_scene[err_type_wait-1].active && + !g_ps3_err_scene[err_type_wait-1].is_hit_post) { + msleep(5); + } + if (g_ps3_err_scene[err_type-1].callback != NULL) { + ret = g_ps3_err_scene[err_type-1].callback(data); + } + g_ps3_err_scene[err_type-1].is_hit_post = PS3_TRUE; + if(g_ps3_err_scene[err_type-1].count > 0 && ret == PS3_SUCCESS){ + g_ps3_err_scene[err_type-1].count--; + } + } + } + + return ; +} + +void inject_execute_callback_at_time_relevance_wait_pre(U16 err_type, + U16 err_type_wait, void * data) +{ + S32 ret = PS3_SUCCESS; + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + + if (g_ps3_err_scene[err_type-1].active == PS3_TRUE) { + if (g_ps3_err_scene[err_type-1].count > 1) { + g_ps3_err_scene[err_type-1].count--; + } else if (g_ps3_err_scene[err_type-1].count == 1) { + g_ps3_err_scene[err_type-1].is_hit_pre = PS3_TRUE; + + while(g_ps3_err_scene[err_type_wait-1].active && + !g_ps3_err_scene[err_type_wait-1].is_hit_pre) { + msleep(5); + } + + if (g_ps3_err_scene[err_type-1].callback != NULL) { + ret = g_ps3_err_scene[err_type-1].callback(data); + } + g_ps3_err_scene[err_type-1].is_hit_post = PS3_TRUE; + if(g_ps3_err_scene[err_type-1].count > 0 && ret == PS3_SUCCESS){ + g_ps3_err_scene[err_type-1].count--; + } + } + } + } + + return; +} + +void inject_execute_callback_at_time_relevance_wait_post(U16 err_type, + U16 err_type_wait, void * data) +{ + S32 ret = PS3_SUCCESS; + if (err_type < PS3_ERR_SCENE_NUM && + err_type >= PS3_ERR_IJ_WATCHDOG_CONCURY) { + + if (g_ps3_err_scene[err_type-1].active == PS3_TRUE) { + if (g_ps3_err_scene[err_type-1].count > 1) { + g_ps3_err_scene[err_type-1].count--; + } else if (g_ps3_err_scene[err_type-1].count == 1) { + g_ps3_err_scene[err_type-1].is_hit_pre = PS3_TRUE; + + while(g_ps3_err_scene[err_type_wait-1].active && + !g_ps3_err_scene[err_type_wait-1].is_hit_post) { + msleep(5); + } + + if (g_ps3_err_scene[err_type-1].callback != NULL) { + ret = g_ps3_err_scene[err_type-1].callback(data); + } + g_ps3_err_scene[err_type-1].is_hit_post = PS3_TRUE; + if(g_ps3_err_scene[err_type-1].count > 0 && ret == PS3_SUCCESS){ + g_ps3_err_scene[err_type-1].count--; + } + } + } + } + + return; +} + +S32 force_ioctl_cmd_dead(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + + if (cmd == NULL) { + goto end; + } + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_IOCTL) { + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + } +end: + return PS3_SUCCESS; +} +S32 force_ioctl_cmd_pending(void * ptr) +{ + *(S32 *)ptr = 1; + return PS3_SUCCESS; +} + +S32 force_ioctl_cmd_sig_interrupt(void * ptr) +{ + *(S32 *)ptr = 1; + return PS3_SUCCESS; +} + +S32 force_ioctl_cmd_interrupt(void * ptr) +{ + *(S32 *)ptr = -PS3_FAILED; + return PS3_SUCCESS; +} +S32 force_ioctl_cmd_no_resp(void * ptr) +{ + *(S32 *)ptr = -PS3_TIMEOUT; + return PS3_SUCCESS; +} +S32 force_mgr_cmd_no_resp(void * ptr) +{ + *(S32 *)ptr = -PS3_TIMEOUT; + return PS3_SUCCESS; +} + +S32 force_return_fail(void * ptr) +{ + *(S32 *)ptr = -PS3_FAILED; + return PS3_SUCCESS; +} +S32 force_ioctl_cmd_abort_no_resp(void * ptr) +{ + *(S32 *)ptr = -PS3_CMD_NO_RESP; + return PS3_SUCCESS; +} + +S32 force_ioctl_cmd_force_done(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + msleep(500); + complete(&cmd->sync_done); + return PS3_SUCCESS; +} + +S32 ioctl_cmd_retry_done(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + cmd->retry_cnt = 3; + return PS3_SUCCESS; +} + +S32 force_ioctl_cmd_recovery_cancel(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + S32 ret; + ret = ps3_hard_recovery_request(cmd->instance); + if (ret == -PS3_FAILED) { + LOG_ERROR("hno:%u hard recovery request failed\n", + PS3_HOST(cmd->instance)); + return -PS3_FAILED; + } + while(ps3_atomic_read(&cmd->instance->state_machine.state) != PS3_INSTANCE_STATE_RECOVERY){ + msleep(50); + } + + return PS3_SUCCESS; +} + +S32 wait_instance_normal(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + while(ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_OPERATIONAL && + ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_PRE_OPERATIONAL){ + msleep(5); + } + return PS3_SUCCESS; +} + +S32 wait_instance_operational(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + while(ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_OPERATIONAL){ + msleep(5); + } + return PS3_SUCCESS; +} +S32 host_reset_wait_decide_normal(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_INFO("inject host_reset_wait_decide_normal enter,recovery_state:%d\n", + instance->recovery_context->recovery_state); + + while(instance->recovery_context->host_reset_state == PS3_HOST_RESET_INIT){ + msleep(5); + } + + msleep(50); + + LOG_INFO("inject host_reset_wait_decide_normal end,host_reset_state:%d\n", + instance->recovery_context->host_reset_state); + return PS3_SUCCESS; +} + +S32 force_instance_unload(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->state_machine.is_load = PS3_FALSE; + return PS3_SUCCESS; +} + +S32 force_instance_state_unnormal(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY); + return PS3_SUCCESS; +} + +S32 force_instance_state_pci_err(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->state_machine.is_pci_err_recovery = PS3_TRUE; + return PS3_SUCCESS; +} + +S32 force_instance_state_normal(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_OPERATIONAL); + return PS3_SUCCESS; +} + +S32 wait_instance_unnormal(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + while(ps3_atomic_read(&instance->state_machine.state) == PS3_INSTANCE_STATE_OPERATIONAL){ + msleep(5); + } + return PS3_SUCCESS; +} + +S32 wait_instance_unnormal_and_set_flag(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + Bool flag = PS3_FALSE; + while(ps3_atomic_read(&instance->state_machine.state) == PS3_INSTANCE_STATE_OPERATIONAL) { + if (!flag) { + instance->reserved[0] = 0x11; + flag = PS3_TRUE; + } + msleep(5); + } + msleep(1000); + return PS3_SUCCESS; +} + +S32 wait_ioc_ready(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 ioc_state = 0; + if (instance->recovery_context->heartbeat_recovery != PS3_HEARTBEAT_HARDRESET_RECOVERY) { + goto l_out; + } + + LOG_INFO("wait_ioc_ready inject\n"); + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + while(ioc_state != PS3_FW_STATE_READY){ + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + msleep(5); + } + +l_out: + return PS3_SUCCESS; +} + +static void force_work_queue_unull_test(struct work_struct* work) +{ + LOG_INFO("force_work_queue_unull_test inject\n"); + + (void) work; + return; +} + +S32 force_work_queue_unull(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct work_struct* recovery_irq_work = &instance->recovery_irq_work; + S8 request_irq_queue_name[PS3_RECOVERY_IRQ_NAME_MAX_LENTH]; + LOG_INFO("force_work_queue_unull inject\n"); + + memset(request_irq_queue_name, 0, PS3_RECOVERY_IRQ_NAME_MAX_LENTH); + INIT_WORK(recovery_irq_work, force_work_queue_unull_test); + + snprintf(request_irq_queue_name, PS3_RECOVERY_IRQ_NAME_MAX_LENTH, + "ps3_irq_recovery_start_service_host%d", instance->host->host_no); + + instance->recovery_irq_queue = + create_singlethread_workqueue(request_irq_queue_name); + + return PS3_SUCCESS; +} + +S32 force_work_queue_failed(void * ptr) +{ + S32 *ret = (S32 *)ptr; + LOG_INFO("force_work_queue_failed\n"); + *ret = -PS3_FAILED; + + return PS3_SUCCESS; +} + +S32 force_fw_state_ff(void * ptr) +{ + U64 *heartbeat_value = (U64 *)ptr; + LOG_INFO("force_fw_state_ff\n"); + *heartbeat_value = U64_MAX; + + return PS3_SUCCESS; +} + +S32 wait_remove_is_load_flag(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_INFO("wait_remove_is_load_flag\n"); + while(instance->state_machine.is_load){ + msleep(5); + } + return PS3_SUCCESS; +} + +S32 wait_reco_dump_valid(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + while(instance->dump_context.is_hard_recovered == 0){ + msleep(5); + + } + return PS3_SUCCESS; +} + +S32 force_ret_fail(void * ptr) +{ + S32 *ret = (S32 *)ptr; + *ret = -PS3_FAILED; + return PS3_SUCCESS; +} + +S32 force_reg_fail(void * ptr) +{ + U64 *ret = (U64 *)ptr; + *ret = U64_MAX; + return PS3_SUCCESS; +} + +S32 force_ready_failed(void * ptr) +{ + U32 *fw_cur_state = (U32 *)ptr; + *fw_cur_state = PS3_FW_STATE_START; + return PS3_SUCCESS; +} + +S32 force_ioc_critical(void * ptr) +{ + U32 *fw_cur_state = (U32 *)ptr; + *fw_cur_state = PS3_FW_STATE_CRITICAL; + return PS3_SUCCESS; +} + +S32 force_change_sgl_addr_to_page_mode_5(void * ptr) +{ + U64 *addr = (U64 *)ptr; + sgl_addr = *addr; + *addr = 0xfffffc5600000; + return PS3_SUCCESS; +} + +S32 force_sgl_addr_restore(void * ptr) +{ + U64 *addr = (U64 *)ptr; + *addr = sgl_addr; + return PS3_SUCCESS; +} + +S32 force_atu_support_failed(void * ptr) +{ + U8 *bit_pos = (U8 *)ptr; + *bit_pos = 0xe0; + return PS3_SUCCESS; +} + +S32 force_reg_zero(void * ptr) +{ + U64 *reg = (U64 *)ptr; + *reg = 0x0; + return PS3_SUCCESS; +} + +S32 force_scan_host_delay(void * ptr) +{ + U32 times = *(U32 *)ptr; + LOG_INFO("inject ps3_scsi_scan_host dalay start:%u\n", times); + while(times) { + msleep(100); + times -= 100; + } + LOG_INFO("inject ps3_scsi_scan_host dalay end:%u\n", times); + return PS3_SUCCESS; +} +S32 force_scan_host_fail(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->is_scan_host_finish = PS3_FALSE; + return PS3_SUCCESS; +} + +S32 force_ignore_task_io(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + U8 type; + S32 ret = PS3_FAILED; + + if (cmd == NULL) { + goto end; + } + type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(cmd->scmd->cmnd)); + if (ps3_scsih_is_rw_type(type)) { + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + init_completion(&cmd->sync_done); + + LOG_INFO("inject force_ignore_task_io CFID %u no resp\n", cmd->index); + ret = PS3_SUCCESS; + } +end: + return ret; +} + +S32 force_ignore_task_abort(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + S32 ret = PS3_FAILED; + + if (cmd == NULL) { + goto end; + } + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_SCSI_TASK_MANAGEMENT && + PS3_MGR_CMD_SUBTYPE(cmd) == PS3_TASK_CMD_SCSI_TASK_ABORT) { + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + init_completion(&cmd->sync_done); + LOG_INFO("inject force_ignore_task_abort CFID %u no resp\n", cmd->index); + ret = PS3_SUCCESS; + } +end: + return ret; +} +S32 force_ignore_task_reset(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + S32 ret = PS3_FAILED; + + if (cmd == NULL) { + goto end; + } + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_SCSI_TASK_MANAGEMENT && + PS3_MGR_CMD_SUBTYPE(cmd) == PS3_TASK_CMD_SCSI_TASK_RESET) { + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + init_completion(&cmd->sync_done); + LOG_INFO("inject force_ignore_task_reset CFID %u no resp\n", cmd->index); + ret = PS3_SUCCESS; + } +end: + return ret; +} +S32 force_event_handle(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance*)ptr; + schedule_delayed_work(&instance->event_context.delay_work->event_work, 0); + return PS3_SUCCESS; +} +S32 force_del_disk(void * ptr) +{ + struct scsi_device *sdev = (struct scsi_device *)ptr; + if (sdev) { + sdev = NULL; + } + return PS3_SUCCESS; +} + +S32 force_priv_data_null(void * ptr) +{ + struct scsi_device *sdev = (struct scsi_device *)ptr; + struct ps3_instance *instance = (struct ps3_instance*)(sdev->host->hostdata); + + if(sdev->hostdata != NULL) { + ps3_kfree(instance, sdev->hostdata); + } + sdev->hostdata = NULL; + return PS3_SUCCESS; +} +S32 force_wait_hard_flag(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 180*HZ; + while (instance->hardreset_event != 1) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + LOG_INFO("event wait hard flag %d\n", + instance->hardreset_event); + return PS3_SUCCESS; +} +S32 force_int_wait_hard_flag(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 10*HZ; + while (instance->hardreset_event != 0) { + ps3_mdelay(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + LOG_INFO("int wait hard flag %d\n", + instance->hardreset_event); + return PS3_SUCCESS; +} + +S32 force_int_wait_hard_subcribe(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 10*HZ; + + while (instance->recovery_context->recovery_state != PS3_HARD_RECOVERY_SHALLOW) { + ps3_mdelay(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + LOG_INFO("int wait hard recovery finish %d\n", + instance->recovery_context->recovery_state); + return PS3_SUCCESS; +} + +S32 force_wait_hard_subcribe(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 180*HZ; + while (instance->recovery_context->recovery_state != PS3_HARD_RECOVERY_SHALLOW) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + while (instance->recovery_context->recovery_state != PS3_HARD_RECOVERY_FINISH) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + LOG_INFO("event wait hard recovery finish %d\n", + instance->recovery_context->recovery_state); + return PS3_SUCCESS; +} + +S32 force_wait_event_int(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 180*HZ; + while (instance->event_context.subwork != 1) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + LOG_INFO("recovery wait event int %d\n", + instance->event_context.subwork); + return PS3_SUCCESS; +} + +S32 force_wait_event_proc(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 180*HZ; + while (instance->event_context.subwork != 1) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + + ps3_msleep(100*HZ); + LOG_INFO("recovery wait event proc %d\n", + instance->event_context.subwork); + return PS3_SUCCESS; +} + +S32 force_wait_event_subscribe(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 wait_time = 180*HZ; + while (instance->event_context.subwork != 1) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + while (instance->event_context.subwork != 0) { + ps3_msleep(1); + wait_time--; + if (wait_time == 0) { + break; + } + } + LOG_INFO("recovery wait event subc %d\n", + instance->event_context.subwork); + return PS3_SUCCESS; +} + +S32 force_hard_ready_failed(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = PS3_FW_STATE_FAULT; + LOG_INFO("force_hard_ready_failed success \n"); + + return PS3_SUCCESS; +} + +S32 wait_recovery_func0_running_1(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserve[0] = 0xcc; + + while (instance->reserve[0] == 0xcc) { + msleep(10); + } + LOG_INFO("wait_recovery_func0_running_1 success \n"); + + return PS3_SUCCESS; +} +S32 wait_recovery_func1_probe(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_INFO("wait_recovery_func1_probe in \n"); + while (instance->peer_instance == NULL) { + msleep(10); + } + LOG_INFO("wait_recovery_func1_probe success \n"); + + return PS3_SUCCESS; +} + +S32 wait_recovery_func1_remove(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserve[0] = 0xb0; + + while (instance->reserve[0] == 0xb0) { + msleep(10); + } + LOG_INFO("wait_recovery_func1_remove success \n"); + + return PS3_SUCCESS; +} +S32 wait_recovery_req_func1_remove(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserve[0] = 0xb1; + + while (instance->reserve[0] == 0xb1) { + msleep(10); + } + LOG_INFO("wait_recovery_func1_remove success \n"); + + return PS3_SUCCESS; +} + +S32 wait_recovery_func0_running_2(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserve[0] = 0; + if(instance->peer_instance) { + instance->peer_instance->reserve[0] = 0; + } + LOG_INFO("wait_recovery_func0_running_2 \n"); + + return PS3_SUCCESS; +} + +S32 force_trigger_log_fail(void * ptr) +{ + U8 * ret = (U8 *)ptr; + *ret = PS3_FALSE; + + return PS3_SUCCESS; +} +S32 force_event_cmd_null(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->event_context.event_cmd = NULL; + + return PS3_SUCCESS; +} + +S32 force_event_cmd_init(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct ps3_cmd *cmd = instance->event_context.event_cmd; + cmd->cmd_state.state = PS3_CMD_STATE_INIT; + + return PS3_SUCCESS; +} +S32 force_cmd_done(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + U8 reply_flags = PS3_SUCCESS; + + ps3_scsih_io_done(cmd, reply_flags); + + return PS3_SUCCESS; +} +S32 force_aborted_cmd_done(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + U16 aborted_cmd_frame_id = 0; + U8 reply_flags = PS3_SUCCESS; + PS3MgrTaskReqFrame_s *mgr_task_req_frame = NULL; + struct ps3_instance *instance = cmd->instance; + + mgr_task_req_frame = &cmd->req_frame->taskReq; + aborted_cmd_frame_id = mgr_task_req_frame->taskID; + cmd = ps3_cmd_find(instance, aborted_cmd_frame_id); + + ps3_scsih_io_done(cmd, reply_flags); + + return PS3_SUCCESS; +} +S32 force_stop_aborted_cmd_done(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_hard_recovery_request(instance); + + ps3_recovery_cancel_work_sync(instance); + + return PS3_SUCCESS; +} + +#ifdef PS3_UT +S32 force_scsi_cmd_done(void * ptr) +{ + struct scsi_cmnd *scmd = (struct scsi_cmnd *)ptr; + U8 reply_flags = PS3_SUCCESS; + U16 cmd_frame_id = 0; + struct ps3_cmd *aborted_cmd; + struct ps3_instance *instance = scsi_host_data(scmd); + + cmd_frame_id = SCMD_GET_REQUEST(scmd)->tag; + aborted_cmd = ps3_cmd_find(instance, cmd_frame_id); + + ps3_scsih_io_done(aborted_cmd, reply_flags); + + return PS3_SUCCESS; +} + +S32 force_set_ioc_in_security(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + writeq_fake(0x1, &instance->reg_set->reg_f.Excl_reg.ps3Debug7); + + return PS3_SUCCESS; +} +S32 force_set_ioc_running(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reg_set != NULL) { + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_RUNNING; + } + state = instance->ioc_adpter->ioc_state_get(instance); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +#else +S32 force_set_ioc_in_security(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3Debug7, 0x1); + + return PS3_SUCCESS; +} +S32 force_set_ioc_running(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3SocFwState, state); + state |= PS3_FW_STATE_RUNNING; + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3SocFwState, state); + + return PS3_SUCCESS; +} +#endif +S32 force_set_ioc_fault(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reg_set != NULL) { + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_FAULT; + } + state = instance->ioc_adpter->ioc_state_get(instance); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} +S32 force_set_ioc_halt(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reg_set != NULL) { + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_HALT; + } + state = instance->ioc_adpter->ioc_state_get(instance); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +S32 force_set_f0_ioc_critical(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reg_set != NULL && instance->peer_instance != NULL && + ps3_get_pci_function(instance->peer_instance->pdev) == PS3_FUNC_ID_0) { + instance->peer_instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_CRITICAL; + } + state = instance->peer_instance->ioc_adpter->ioc_state_get(instance); + while (ps3_atomic_read(&instance->recovery_context->hardreset_ref) == 0) { + msleep(5); + } + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +S32 set_qos_share_cnt(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_atomic_set(&instance->qos_context.tg_ctx.share_free_cnt, 1); + + return PS3_SUCCESS; +} +S32 force_event_cmd_dead(void *ptr) +{ + S32 *cur_state = (S32 *)ptr; + *cur_state = PS3_INSTANCE_STATE_RECOVERY; + + return PS3_SUCCESS; +} + +S32 wait_irq_disable(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + instance->reserved[0] = 0; + while(ps3_irq_is_enable(&instance->irq_context)) { + msleep(1); + } + + return PS3_SUCCESS; +} + +S32 wait_ioctl_detect_irq_disable(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while(instance->reserved[0] != 0xab) { + msleep(1); + } + + return PS3_SUCCESS; +} + +S32 set_send_ioctl_block_flag(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + if (cmd->req_frame->mgrReq.reqHead.cmdType == PS3_CMD_IOCTL) { + instance->reserved[0] = 0xab; + } + + return PS3_SUCCESS; +} + +S32 force_has_scsi_pending_io(void * ptr) +{ + Bool *found = (Bool *)ptr; + *found = PS3_TRUE; + return PS3_SUCCESS; +} +#ifdef PS3_UT +void scsi_cmd_create(struct scsi_cmnd *s_cmd, struct ps3_instance *instance) +{ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)) + unsigned char scsi_cmnd_tmp[] = {0x2a, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x08, 0x00, 0x00}; + struct scsi_device *device; +#if defined DRIVER_SUPPORT_PRIV_BUSY + struct ps3_scsi_priv_data *device_priv_data = (struct ps3_scsi_priv_data*)s_cmd->device->hostdata; +#endif + memset(s_cmd, 0, sizeof(*s_cmd)); + s_cmd->cmnd = (U8 *)kmalloc(32, GFP_KERNEL); + memset(s_cmd->cmnd, 0, sizeof(unsigned char) * 32); + SCMD_GET_REQUEST(s_cmd) = (struct request *)kmalloc(sizeof(struct request), GFP_KERNEL); + instance->host->can_queue = instance->cmd_context.max_scsi_cmd_count; + instance->cmd_attr.nvme_page_size = PAGE_SIZE; + s_cmd->sense_buffer = (unsigned char *)kmalloc(96, GFP_KERNEL); + + memcpy(s_cmd->cmnd, scsi_cmnd_tmp, 10); + device = (struct scsi_device *)kmalloc(sizeof(struct scsi_device), GFP_KERNEL); + s_cmd->device = device; + s_cmd->device->host = instance->host; + SCMD_GET_REQUEST(s_cmd)->tag = 88; + s_cmd->cmd_len = 10; + +#if defined DRIVER_SUPPORT_PRIV_BUSY + atomic_set(&device_priv_data->sdev_priv_busy, 9); +#else + s_cmd->device->device_busy.counter = 9; +#endif + instance->irq_context.high_iops_io_count.counter = 62; +#endif +} +void scsi_cmd_free(struct scsi_cmnd *s_cmd) +{ + kfree(s_cmd->cmnd); + kfree(SCMD_GET_REQUEST(s_cmd)); + kfree(s_cmd->sense_buffer); + kfree(s_cmd->device); +} + +S32 force_host_reset(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + S32 ret_check = 0; + + struct scsi_cmnd pending_scsi_cmd; + scsi_cmd_create(&pending_scsi_cmd, instance); + ret_check = instance->host->hostt->eh_host_reset_handler(&pending_scsi_cmd); + LOG_WARN("host reset [%d]\n", ret_check); + scsi_cmd_free(&pending_scsi_cmd); + return PS3_SUCCESS; +} +#endif +S32 force_return_false(void * ptr) +{ + Bool *found = (Bool *)ptr; + *found = PS3_FALSE; + return PS3_SUCCESS; +} + +S32 force_return_true(void * ptr) +{ + Bool *ret = (Bool *)ptr; + *ret = PS3_TRUE; + return PS3_SUCCESS; +} + +S32 force_scsi_priv_data_null(void * ptr) +{ + S32 ret_check = 0; + struct scsi_cmnd *s_cmd = (struct scsi_cmnd *)ptr; + if (s_cmd->device) { + s_cmd->device->hostdata = NULL; + } + return ret_check; +} +S32 force_scsi_task_cmd_error(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_TM_FAILED; + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + complete(&cmd->sync_done); + LOG_WARN("hno:%u force complete task mgr CFID:%d\n", + PS3_HOST(instance), cmd->index); + return PS3_SUCCESS; +} +S32 force_ioc_not_running(void * ptr) +{ + U32 * ioc_state = (U32 *)ptr; + if(ioc_state) { + *ioc_state = PS3_FW_STATE_RUNNING + 1; + } + + return PS3_SUCCESS; +} +S32 force_ioc_running(void * ptr) +{ + U32 * ioc_state = (U32 *)ptr; + if(ioc_state) { + *ioc_state = PS3_FW_STATE_RUNNING; + } + + return PS3_SUCCESS; +} + +S32 force_task_cmd_alloc_null(void ** ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)*ptr; + struct ps3_instance *instance = NULL; + if(cmd) { + instance = (struct ps3_instance *)cmd->instance; + ps3_mgr_cmd_free(instance, cmd); + *ptr = NULL; + } + return PS3_SUCCESS; +} +S32 force_pcie_err(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->state_machine.is_pci_err_recovery = PS3_TRUE; + return PS3_SUCCESS; +} +S32 force_ptr_null(void ** ptr) +{ + if (*ptr) { + *ptr = NULL; + } + return PS3_SUCCESS; +} +S32 wait_task_mgr_busy(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while (!instance->task_manager_host_busy) { + ps3_msleep(10); + } + return PS3_SUCCESS; +} +S32 wait_pd_clear(void * ptr) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = (struct ps3_qos_pd_mgr *)ptr; + while (!qos_pd_mgr->clearing) { + ps3_msleep(100); + } + return PS3_SUCCESS; +} + +S32 reset_target_pause(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while(instance->reserved[0] != 0xab) { + ps3_msleep(10); + } + return PS3_SUCCESS; +} + +S32 set_send_cmd_task_mgr_busy_flag(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xab; + return PS3_SUCCESS; +} + +S32 wait_qos_vd_send(void * ptr) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = (struct ps3_qos_pd_mgr *)ptr; + while((qos_pd_mgr->vd_id == 0) || + (ps3_atomic_read(&qos_pd_mgr->pd_used_quota) >= + qos_pd_mgr->pd_quota)) { + msleep(1); + } + + return PS3_SUCCESS; +} +S32 force_smp_cmd_error(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_SMP_BACKEND_ERR; + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + complete(&cmd->sync_done); + LOG_WARN("hno:%u force complete task mgr CFID:%d\n", + PS3_HOST(instance), cmd->index); + + return PS3_SUCCESS; +} + +S32 force_pdlist_cmd_retry(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_BUSY; + LOG_WARN("hno:%u force complete task mgr CFID:%d\n", + PS3_HOST(instance), cmd->index); + + return PS3_SUCCESS; +} + +S32 force_get_linkerrors_cmd_error(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_LINK_GET_BACKEND_ERR; + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + complete(&cmd->sync_done); + LOG_WARN("hno:%u force complete task mgr CFID:%d\n", + PS3_HOST(instance), cmd->index); + + return PS3_SUCCESS; +} +S32 force_sas_phy_ctrl_cmd_error(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + struct ps3_instance *instance = cmd->instance; + + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_PHY_CTL_BACKEND_ERR; + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + complete(&cmd->sync_done); + LOG_WARN("hno:%u force complete task mgr CFID:%d\n", + PS3_HOST(instance), cmd->index); + + return PS3_SUCCESS; +} + +S32 force_instance_state_to_unnormal(void *ptr) +{ + S32 * state = (S32 *)ptr; + if(state) { + *state = PS3_INSTANCE_STATE_RECOVERY; + } + + return PS3_SUCCESS; +} +S32 force_instance_state_to_dead(void *ptr) +{ + S32 * state = (S32 *)ptr; + if(state) { + *state = PS3_INSTANCE_STATE_DEAD; + } + + return PS3_SUCCESS; +} + +S32 ps3_sas_encl_id_get_failed(void *ptr) +{ + U8 *encl_id = (U8 *)ptr; + if(encl_id) { + *encl_id = PS3_SAS_INVALID_ID; + } + + return PS3_SUCCESS; +} + +S32 ps3_sas_rphy_parent_sas_addr_get_failed(void *ptr) +{ + u64 *encl_id = (u64 *)ptr; + if(encl_id) { + *encl_id = PS3_SAS_INVALID_SAS_ADDR; + } + + return PS3_SUCCESS; +} + +S32 force_mgr_cmd_alloc_null(void ** ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)*ptr; + struct ps3_instance *instance = NULL; + if(cmd) { + instance = (struct ps3_instance *)cmd->instance; + ps3_mgr_cmd_free(instance, cmd); + *ptr = NULL; + } + + return PS3_SUCCESS; +} + +S32 force_cmd_polling(void ** ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + if(cmd) { + cmd->is_force_polling = 1; + } + + return PS3_SUCCESS; +} + +S32 force_pci_err_recovery(void ** ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + if(instance) { + instance->state_machine.is_pci_err_recovery = PS3_TRUE; + } + + return PS3_SUCCESS; +} + +S32 cli_wait_recovery(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + Bool flag = PS3_FALSE; + while (ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_READY) { + if (!flag) { + instance->reserve[0] = 1; + flag = PS3_TRUE; + } + msleep(10); + } + instance->reserve[1] = 1; + while (ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_OPERATIONAL) { + msleep(10); + } + return PS3_SUCCESS; +} + +S32 recovery_wait_cli(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while (instance->reserve[1] != 1) { + msleep(10); + } + instance->reserve[1] = 0; + return PS3_SUCCESS; +} + +S32 force_blk_rq_bytes_invalid(void * ptr) +{ + struct request *req = (struct request *)ptr; + + if(req) { + req->__data_len = U32_MAX; + } + return PS3_SUCCESS; +} +S32 wait_cmd_done(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xab; + while(instance->reserved[0] == 0xab) { + msleep(10); + } + return PS3_SUCCESS; +} + +S32 wait_cmd_send_block(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while(instance->reserved[0] == 0) { + instance->reserved[1] = 0xcd; + msleep(10); + } + return PS3_SUCCESS; +} + +S32 set_r1x_conflict_process_flag(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xab; + return PS3_SUCCESS; +} + +S32 force_task_mgr_busy(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->task_manager_host_busy = PS3_TRUE; + return PS3_SUCCESS; +} + +S32 block_in_cmd_send(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xab; + while(instance->reserved[0] == 0xab) { + msleep(10); + } + return PS3_SUCCESS; +} + +S32 create_pd_worker_fail(void * ptr) +{ + struct ps3_qos_pd_context *qos_pd_ctx = NULL; + struct workqueue_struct **work_queues = NULL; + qos_pd_ctx = (struct ps3_qos_pd_context *)ptr; + work_queues = qos_pd_ctx->work_queues; + + if (qos_pd_ctx->workq_count > 1 && work_queues[1] != NULL) { + destroy_workqueue(work_queues[1]); + work_queues[1] = NULL; + qos_pd_ctx->work_queues[1] = NULL; + } + + return PS3_SUCCESS; +} + +S32 create_tag_waitq_fail(void *ptr) +{ + struct ps3_qos_tg_context *qos_tg_ctx = (struct ps3_qos_tg_context *)ptr; + if (qos_tg_ctx->vd_cmd_waitqs != NULL) { + ps3_vfree(qos_tg_ctx->instance, qos_tg_ctx->vd_cmd_waitqs); + qos_tg_ctx->vd_cmd_waitqs = NULL; + + } + return PS3_SUCCESS; +} + +S32 create_tag_workq_fail(void *ptr) +{ + struct ps3_qos_tg_context *qos_tg_ctx = (struct ps3_qos_tg_context *)ptr; + if (qos_tg_ctx->work_queue != NULL) { + destroy_workqueue(qos_tg_ctx->work_queue); + qos_tg_ctx->work_queue = NULL; + } + + return PS3_SUCCESS; +} + +S32 create_vd_mgrs_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct ps3_qos_vd_context *qos_vd_ctx = &instance->qos_context.vd_ctx; + if (qos_vd_ctx->qos_vd_mgrs != NULL) { + ps3_vfree(instance, qos_vd_ctx->qos_vd_mgrs); + qos_vd_ctx->qos_vd_mgrs = NULL; + } + return PS3_SUCCESS; +} + +S32 create_vd_workq_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct ps3_qos_vd_context *qos_vd_ctx = &instance->qos_context.vd_ctx; + if (qos_vd_ctx->work_queues != NULL) { + ps3_vfree(instance, qos_vd_ctx->work_queues); + qos_vd_ctx->work_queues = NULL; + } + return PS3_SUCCESS; + +} + +S32 create_vd_worker_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct ps3_qos_vd_context *qos_vd_ctx = &instance->qos_context.vd_ctx; + if (qos_vd_ctx->work_queues[0] != NULL) { + destroy_workqueue(qos_vd_ctx->work_queues[0]); + qos_vd_ctx->work_queues[0] = NULL; + } + return PS3_SUCCESS; +} + +S32 create_pd_mgrs_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct ps3_qos_pd_context *qos_pd_ctx = &instance->qos_context.pd_ctx; + if (qos_pd_ctx->qos_pd_mgrs != NULL) { + ps3_vfree(instance, qos_pd_ctx->qos_pd_mgrs); + qos_pd_ctx->qos_pd_mgrs = NULL; + } + return PS3_SUCCESS; +} + +S32 create_pd_waitq_fail(void *ptr) +{ + struct ps3_qos_pd_context *qos_pd_ctx = (struct ps3_qos_pd_context *)ptr; + struct ps3_qos_pd_mgr *qos_pd_mgr = &qos_pd_ctx->qos_pd_mgrs[2]; + struct ps3_instance *instance = qos_pd_mgr->instance; + if (qos_pd_mgr->waitqs != NULL) { + ps3_vfree(instance, qos_pd_mgr->waitqs); + qos_pd_mgr->waitqs = NULL; + } + return PS3_SUCCESS; +} + +S32 create_pd_workq_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + struct ps3_qos_pd_context *qos_pd_ctx = &instance->qos_context.pd_ctx; + if (qos_pd_ctx->work_queues != NULL) { + ps3_vfree(instance, qos_pd_ctx->work_queues); + qos_pd_ctx->work_queues = NULL; + } + return PS3_SUCCESS; +} + +S32 force_cmd_vd_seq_change(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + cmd->req_frame->hwReq.reqHead.virtDiskSeq = 0xFF; + return PS3_SUCCESS; +} + +S32 force_u64_zero(void *ptr) +{ + *(U64 *)ptr = 0; + return PS3_SUCCESS; +} + +S32 force_fifo_depth_zero(void *ptr) +{ + *(U64 *)ptr = 0; + return PS3_SUCCESS; +} + +S32 create_mgr_waitq_fail(void *ptr) +{ + struct ps3_qos_softq_mgr *softq_mgr = (struct ps3_qos_softq_mgr *)ptr; + if (softq_mgr->waitqs) { + ps3_vfree(softq_mgr->instance, softq_mgr->waitqs); + softq_mgr->waitqs = NULL; + } + + return PS3_SUCCESS; +} + +S32 create_mgr_worker_fail(void *ptr) +{ + struct ps3_qos_softq_mgr *softq_mgr = (struct ps3_qos_softq_mgr *)ptr; + if (softq_mgr->work_queue) { + destroy_workqueue(softq_mgr->work_queue); + softq_mgr->work_queue = NULL; + } + + return PS3_SUCCESS; +} + +S32 create_cmd_waitq_fail(void *ptr) +{ + struct ps3_qos_softq_mgr *softq_mgr = (struct ps3_qos_softq_mgr *)ptr; + if (softq_mgr->waitqs) { + ps3_vfree(softq_mgr->instance, softq_mgr->waitqs); + softq_mgr->waitqs = NULL; + } + return PS3_SUCCESS; +} + +S32 create_cmd_worker_fail(void *ptr) +{ + struct ps3_qos_softq_mgr *softq_mgr = (struct ps3_qos_softq_mgr *)ptr; + if (softq_mgr->id == 1 && softq_mgr->work_queue) { + destroy_workqueue(softq_mgr->work_queue); + softq_mgr->work_queue = NULL; + } + return PS3_SUCCESS; +} + +S32 wait_for_dead_or_pre_operational(void *ptr) +{ + U32 wait_cnt = 180 * 3; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + U32 idx = 0; + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + LOG_INFO("hno:%u wait dead or pre_operational begin\n", PS3_HOST(instance)); + for (idx = 0; idx < wait_cnt; idx++) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if ((cur_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_DEAD) || + (cur_state == PS3_INSTANCE_STATE_QUIT)) { + break; + } + + ps3_msleep(1000); + } + + if (idx >= wait_cnt) { + LOG_WARN("hno:%u wait dead or pre_operational timeout!\n", + PS3_HOST(instance)); + } + + if ((cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL) && + (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) && + (cur_state != PS3_INSTANCE_STATE_DEAD)) { + LOG_WARN("hno:%u wait dead or pre_operational failed!\n", + PS3_HOST(instance)); + return -PS3_FAILED; + + } + + LOG_INFO("hno:%u wait dead or pre_operational success!\n", PS3_HOST(instance)); + return PS3_SUCCESS; +} +S32 force_init_cmd_failed(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reg_set != NULL) { + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_UNDEFINED; + } + state = instance->ioc_adpter->ioc_state_get(instance); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +S32 force_recovery_init_cmd_failed(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reg_set != NULL && instance->reserve[0]) { + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_UNDEFINED; + } + state = instance->ioc_adpter->ioc_state_get(instance); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +S32 force_recovery_operation_cmd_failed(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + + if (instance->reserve[0]) { + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_RECOVERY); + } + state = ps3_atomic_read(&instance->state_machine.state); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +S32 force_init_cmd_running_failed(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U64 state; + if (instance->reg_set != NULL) { + instance->reg_set->reg_f.Excl_reg.ps3SocFwState.reg.ps3SocFwState = + PS3_FW_STATE_FAULT; + } + state = instance->ioc_adpter->ioc_state_get(instance); + + LOG_WARN("ioc state [%llu]\n", state); + return PS3_SUCCESS; +} + +S32 err_abort_block(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while(instance->reserved2[0] == 0) { + instance->reserved2[1] = 0xcd; + msleep(10); + } + return PS3_SUCCESS; +} + +static void ps3_test_recovery_call(struct work_struct* work) +{ + struct ps3_instance *instance = NULL; + + (void)work; + instance = g_work_que_recovery.instance; + + LOG_WARN("ps3_test_reco_call enter\n"); + + ps3_hard_recovery_request(instance); + g_work_que_recovery.state = 1; + LOG_WARN("ps3_test_reco_call quit\n"); +} +void ps3_start_recovery_rand_thread(struct ps3_instance *instance) +{ + char _queue_name[32] = {"test_reco"}; + + INIT_DELAYED_WORK(&g_work_que_recovery._work, ps3_test_recovery_call); + + g_work_que_recovery._queue = create_singlethread_workqueue(_queue_name); + if (g_work_que_recovery._queue == NULL) { + return; + } + + g_work_que_recovery.instance = instance; + g_work_que_recovery.state = 0; + + queue_delayed_work(g_work_que_recovery._queue, &g_work_que_recovery._work, + msecs_to_jiffies(prandom_u32() % 800)); +} + +static void ps3_test_probe_call(struct work_struct* work) +{ + struct ps3_instance *instance = NULL; + U32 idx = 0; + (void)work; + instance = g_work_que_probe.instance; + + LOG_WARN("ps3_test_probe_call enter\n"); + + if (instance->peer_instance == NULL) { + return ; + } + instance->peer_instance->is_probe_finish = false; + g_work_que_probe.state = 1; + while (idx++ < 10000) { + msleep(10); + } + + instance->peer_instance->is_probe_finish = true; + LOG_WARN("ps3_test_probe_call quit\n"); +} +void ps3_start_probe_rand_thread(struct ps3_instance *instance) +{ + char _queue_name[32] = {"test_probe"}; + + INIT_DELAYED_WORK(&g_work_que_probe._work, ps3_test_probe_call); + + g_work_que_probe._queue = create_singlethread_workqueue(_queue_name); + if (g_work_que_probe._queue == NULL) { + return; + } + + g_work_que_probe.instance = instance; + g_work_que_probe.state = 0; + + queue_delayed_work(g_work_que_probe._queue, &g_work_que_probe._work, + msecs_to_jiffies(prandom_u32() % 800)); +} +S32 wait_recovery_req_func1_probe(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_start_probe_rand_thread(instance); + while (g_work_que_probe.state != 1) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + LOG_INFO("wait_recovery_func1_probe success \n"); + + return PS3_SUCCESS; +} +void ps3_wait_probe_rand_finish(void) +{ + LOG_WARN("enter ps3_wait_probe_rand_finish\n"); + while (g_work_que_probe.state != 1) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + if (g_work_que_probe._queue != NULL) { + if (!cancel_delayed_work_sync(&g_work_que_probe._work)) { + flush_workqueue(g_work_que_probe._queue); + } + + destroy_workqueue(g_work_que_probe._queue); + g_work_que_probe._queue = NULL; + } + LOG_WARN("quit ps3_wait_probe_rand_finish\n"); +} + +S32 force_hard_reset_request(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + if (instance->peer_instance != NULL) { + ps3_start_recovery_rand_thread(instance->peer_instance); + while (ps3_atomic_read(&instance->recovery_context->hardreset_ref) == 0) { + msleep(5); + } + } else { + ps3_hard_recovery_request(instance); + } + + return PS3_SUCCESS; +} + +S32 force_hard_reset_request_1(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_WARN("enter force_hard_reset_request_1\n"); + if (instance->reserve[0] == 0) { + ps3_hard_recovery_request(instance); + } else { + ps3_hard_recovery_request(instance->peer_instance); + } + cancel_work_sync(&instance->recovery_context->recovery_work); + LOG_WARN("enter force_hard_reset_request_1 end\n"); + + return PS3_SUCCESS; +} + +S32 force_instance_null(void *ptr) +{ + struct ps3_instance **instance = (struct ps3_instance **)ptr; + LOG_WARN("enter force_instance_null\n"); + *instance = NULL; + LOG_WARN("force_instance_null end\n"); + return PS3_SUCCESS; +} + +S32 force_half_reset(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_WARN("enter force_half_reset\n"); + instance->is_half_hard_reset = PS3_DRV_TRUE; + LOG_WARN("force_half_reset end\n"); + return PS3_SUCCESS; +} + +S32 force_half_reset_false(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_WARN("enter force_half_reset_false\n"); + instance->is_half_hard_reset = PS3_DRV_FALSE; + LOG_WARN("force_half_reset_false end\n"); + return PS3_SUCCESS; +} + +S32 force_web_subscribe_failed(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + LOG_WARN("enter force_half_reset_false\n"); + ps3_atomic_set(&instance->webSubscribe_context.is_subscribe, 1); + ps3_atomic_set(&instance->cmd_statistics.cmd_delivering, 1); + LOG_WARN("force_half_reset_false end\n"); + return PS3_SUCCESS; +} + +S32 force_cmd_delivering_zero(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + LOG_WARN("enter force_cmd_delivering_zero\n"); + ps3_atomic_set(&instance->cmd_statistics.cmd_delivering, 0); + LOG_WARN("force_cmd_delivering_zero end\n"); + return PS3_SUCCESS; +} + +S32 force_async_hard_reset_request(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_start_recovery_rand_thread(instance); + + return PS3_SUCCESS; +} + +S32 change_fw_state_to_halt_in_recover_prepare(void *ptr) +{ + U32 *p_ioc_state = (U32 *)ptr; + *p_ioc_state = PS3_FW_STATE_HALT; + + return PS3_SUCCESS; +} + +S32 wait_scsi_cmd_done_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xab; + while (*instance->scsi_cmd_deliver != 0) { + ps3_msleep(10); + } + return PS3_SUCCESS; +} +void ps3_wait_recovery_rand_finish(void) +{ + LOG_WARN("enter ps3_wait_reco_rand_finish\n"); + while (g_work_que_recovery.state != 1) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + if (g_work_que_recovery._queue != NULL) { + if (!cancel_delayed_work_sync(&g_work_que_recovery._work)) { + flush_workqueue(g_work_que_recovery._queue); + } + while (g_work_que_recovery.instance->recovery_context->recovery_state != \ + PS3_HARD_RECOVERY_FINISH) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + + destroy_workqueue(g_work_que_recovery._queue); + g_work_que_recovery._queue = NULL; + } + LOG_WARN("quit ps3_wait_reco_rand_finish\n"); +} + +S32 force_hard_recovery_request_nosupport_fail(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance = instance; + ps3_hard_reset_enable_modify(0); + return PS3_SUCCESS; +} + +S32 force_seq_cmd(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + cmd->io_attr.seq_flag = SCSI_RW_SEQ_CMD; + return PS3_SUCCESS; +} + +S32 wait_cmd_free(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + while (cmd->r1x_peer_cmd != NULL) { + cmd->instance->reserved2[0] = 0xcd; + ps3_msleep(20); + } + return PS3_SUCCESS; +} + +S32 wait_abort_flag(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + while (cmd->is_aborting != 1) { + ps3_msleep(20); + } + return PS3_SUCCESS; +} + +S32 wait_cmd_alloc1(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + Bool is_first = PS3_TRUE; + while (cmd->trace_id != 0xff) { + if (is_first) { +#ifdef PS3_UT + cmd->scmd->is_in_err += 1; +#endif + is_first = PS3_FALSE; + } + ps3_msleep(20); + } + cmd->trace_id = 0; + return PS3_SUCCESS; +} + +S32 wait_cmd_alloc2(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + while (cmd->scmd == NULL) { + ps3_msleep(20); + } +#ifdef PS3_UT + cmd->scmd->is_in_err += 1; +#endif + return PS3_SUCCESS; +} + +S32 set_abort_count(void *ptr) +{ +#ifdef PS3_UT + struct scsi_cmnd *s_cmnd = (struct scsi_cmnd *)ptr; + s_cmnd->abort_count++; +#endif + return PS3_SUCCESS; +} +S32 wait_cmd_alloc(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + while (cmd->trace_id != 0xff) { + ps3_msleep(20); + } + cmd->trace_id = 0; + return PS3_SUCCESS; +} + +S32 set_cmd_tid_flag(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + cmd->trace_id = 0xff; + return PS3_SUCCESS; +} + +S32 set_cmd_io_rw_flag_unkown(void * ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + cmd->io_attr.rw_flag = PS3_SCSI_CMD_TYPE_UNKOWN; + return PS3_SUCCESS; +} + +S32 set_soft_zone_type_unkown(void * ptr) +{ + U8 *type = (U8 *)ptr; + *type = PS3_DEV_TYPE_UNKNOWN; + return PS3_SUCCESS; +} + +S32 force_rand_cmd(void *ptr) +{ + struct ps3_cmd *cmd = (struct ps3_cmd *)ptr; + cmd->io_attr.seq_flag = SCSI_RW_RANDOM_CMD; + return PS3_SUCCESS; +} + +S32 force_ret_recovery(void * ptr) +{ + S32 *ret = (S32 *)ptr; + if(ret) { + *ret = -PS3_RECOVERED; + } + + return PS3_SUCCESS; +} + +S32 force_return_zero(void * ptr) +{ + *(S32 *)ptr = 0; + return PS3_SUCCESS; +} + +S32 force_return_invalid(void * ptr) +{ + *(S32 *)ptr = 0x80; + return PS3_SUCCESS; +} + +S32 force_ret_failed(void * ptr) +{ + S32 *ret = (S32 *)ptr; + if(ret) { + *ret = -PS3_FAILED; + } + + return PS3_SUCCESS; +} + +S32 force_cmd_not_mgr_cmd(void * ptr) +{ + U16 *index = (U16 *)ptr; + *index = 0; + return PS3_SUCCESS; +} + +S32 force_phy_count_zero(void * ptr) +{ + U8 *phy_count = (U8 *)ptr; + *phy_count = 0; + return PS3_SUCCESS; +} + +S32 force_doorbell_failed(void * ptr) +{ + U32 *fw_cur_state = (U32 *)ptr; + + LOG_INFO("force doorbell failed start\n"); + *fw_cur_state = PS3_FW_STATE_READY; + LOG_INFO("force doorbell failed end\n"); + + return PS3_SUCCESS; +} + +S32 force_vd_count_err(void * ptr) +{ + U16 *count = (U16 *)ptr; + if(count) { + *count = 2; + } + + return PS3_SUCCESS; +} + +S32 force_chan_err(void * ptr) +{ + U8 *chan = (U8 *)ptr; + if(chan) { + *chan = 255; + } + + return PS3_SUCCESS; +} + +S32 force_dev_err(void * ptr) +{ + struct PS3Dev *dev = (struct PS3Dev *)ptr; + if(dev) { + dev->softChan = 15; + } + + return PS3_SUCCESS; +} + +S32 force_target_err(void * ptr) +{ + U16 *target = (U16 *)ptr; + if(target) { + *target = 65535; + } + + return PS3_SUCCESS; +} + +S32 force_diskpos_err(void * ptr) +{ + U32 *disk_id = (U32 *)ptr; + if(disk_id) { + *disk_id = 0; + } + + return PS3_SUCCESS; +} +S32 force_s32_zero(void * ptr) +{ + S32 *ret = (S32 *)ptr; + if(ret) { + *ret = 0; + } + + return PS3_SUCCESS; +} +S32 force_s32_letter_zero(void * ptr) +{ + S32 *ret = (S32 *)ptr; + if(ret) { + *ret = 0; + } + + return PS3_SUCCESS; +} + +S32 force_align_err(void * ptr) +{ + U8 *align = (U8 *)ptr; + if(align) { + *align = 16; + } + + return PS3_SUCCESS; +} + +S32 force_lun_err(void * ptr) +{ + U64 *lun = (U64 *)ptr; + if(lun) { + *lun = 1; + } + + return PS3_SUCCESS; +} + +S32 force_dev_type_err(void * ptr) +{ + U8 *type = (U8 *)ptr; + if(type) { + *type = 0; + } + + return PS3_SUCCESS; +} + +S32 force_pd_state_err(void * ptr) +{ + U8 *align = (U8 *)ptr; + if(align) { + *align = DEVICE_STATE_OUTING; + } + + return PS3_SUCCESS; +} + +S32 force_thread_null(void * ptr) +{ + struct ps3_r1x_lock_mgr *mgr = (struct ps3_r1x_lock_mgr *)ptr; + if (mgr->conflict_send_th != NULL) { + mgr->thread_stop = PS3_TRUE; + complete(&mgr->thread_sync); + kthread_stop(mgr->conflict_send_th); + mgr->conflict_send_th = NULL; + } + return PS3_SUCCESS; +} + +S32 wait_pcie_err(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + LOG_INFO("wait pcie err start\n"); + instance->reserve[0] = 1; + while(!ps3_pci_err_recovery_get(instance)){ + msleep(50); + } + LOG_INFO("wait pcie err end\n"); + + return PS3_SUCCESS; +} + +S32 set_iops_channel(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + if (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_1) { + instance->irq_context.high_iops_msix_vectors = 16; + } + return PS3_SUCCESS; +} +S32 force_pcie_frozen(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reg_set = NULL; + return PS3_SUCCESS; +} + +S32 for_mod_so_addr(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->so_start_addr = PCIE_DMA_HOST_ADDR_BIT_POS_SET(0x5000); + instance->so_end_addr = PCIE_DMA_HOST_ADDR_BIT_POS_SET(0x10000); + return PS3_SUCCESS; +} +S32 force_pci_ioremap_fail(void ** ptr) +{ + iounmap(*ptr); + *ptr = NULL; + + return PS3_SUCCESS; +} +S32 wait_recovery_req_coming(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 count = 0; + LOG_INFO("wait_recovery_req in \n"); + while (1){ + if (ps3_atomic_read(&instance->recovery_context->hardreset_ref) != 0) { + break; + } + if (count == 10000) { + break; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + count++; + } + + LOG_INFO("wait_recovery_req success \n"); + + return PS3_SUCCESS; +} +S32 wait_hard_recovery_req(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + U32 count = 0; + LOG_INFO("wait_recovery_req in \n"); + while (1){ + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + break; + } + if (count == 10000) { + break; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + count++; + } + + LOG_INFO("wait_recovery_req success \n"); + + return PS3_SUCCESS; +} + +S32 force_u8_1(void * ptr) +{ + U8 *ret = (U8 *)ptr; + if(ret) { + *ret = 1; + } + + return PS3_SUCCESS; +} +S32 force_multi_hard_req(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->recovery_context->recovery_state = PS3_HARD_RECOVERY_SHALLOW; + + return PS3_SUCCESS; +} +S32 force_multi_hard_req_pending(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_PENDING) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_CONTINUE; + } + return PS3_SUCCESS; +} +S32 force_recovery_wq_null(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->recovery_context->recovery_wq = NULL; + return PS3_SUCCESS; +} +S32 force_recovery_state_dead(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_DEAD); + return PS3_SUCCESS; +} +S32 force_recovery_support_false(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + + instance->is_hard_recovery_support = false; + return PS3_SUCCESS; +} +S32 force_memory_alloc_failed(void ** ptr) +{ + kfree(*ptr); + + *ptr = NULL; + return PS3_SUCCESS; +} +S32 force_web_subcribe(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_atomic_set(&instance->webSubscribe_context.is_subscribe, 1); + + return PS3_SUCCESS; +} +S32 force_instance_probe_failed(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->state_machine.is_load = PS3_FALSE; + + return PS3_SUCCESS; +} + +S32 force_func_id_invalid(void ** ptr) +{ + (void)ptr; + ps3_avaliable_func_id_modify(PS3_FUNC_ID_1); + + return PS3_SUCCESS; +} + +S32 wait_recovery_request(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + while (instance->recovery_context->recovery_state != PS3_HARD_RECOVERY_DECIDE && + instance->recovery_context->recovery_state != PS3_HARD_RECOVERY_SHALLOW) { + msleep(10); + } + return PS3_SUCCESS; +} + +S32 recovery_wait_conditional(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xab; + while(instance->reserved[0] == 0xab) { + msleep(10); + } + return PS3_SUCCESS; +} + +S32 wait_recovery_request_2(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + ps3_hard_recovery_request(instance); + return PS3_SUCCESS; +} + +S32 wait_f0_watchdog(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_WARN("wait_f0_watchdog in \n"); + if (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_1) { + goto l_out; + } + while (instance->recovery_context->recovery_state < PS3_HARD_RECOVERY_DECIDE) { + ps3_msleep(10); + } +l_out: + LOG_WARN("wait_f0_watchdog out \n"); + return PS3_SUCCESS; +} + +S32 wait_f0_watchdog_2(void *ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + LOG_WARN("wait_f0_watchdog_2 in \n"); + while (instance->ioc_adpter->ioc_heartbeat_detect(instance) == 0) { + ps3_msleep(10); + } + LOG_WARN("wait_f0_watchdog_2 out \n"); + return PS3_SUCCESS; +} + +S32 wait_recovery_end(void * ptr) +{ + struct ps3_instance *instance = (struct ps3_instance *)ptr; + instance->reserved[0] = 0xff; + cancel_work_sync(&instance->recovery_context->recovery_work); + return PS3_SUCCESS; +} + +S32 force_sas_port_create_fail(void * ptr) +{ + struct ps3_sas_port *sas_port = (struct ps3_sas_port *)ptr; + if (sas_port->port != NULL) { + sas_port_delete(sas_port->port); + sas_port->port = NULL; + } + return PS3_SUCCESS; +} + +void active_err_inject(void) +{ + U32 idx = 0; + U32 *arr_base = ps3_err_inject_array_query(); + U32 err_inject_num = ps3_err_inject_num_query(); + LOG_DEBUG("active err_inject_num:%u\n", + err_inject_num); + + for(; idx < err_inject_num;) + { + if ((arr_base[idx] >= PS3_ERR_IJ_WATCHDOG_CONCURY) && + (arr_base[idx] < PS3_ERR_IJ_MAX_COUNT)) { + INJECT_ACTIVE(arr_base[idx], arr_base[idx + 1]) + LOG_DEBUG("active err_inject:%u count:%u \n", + arr_base[idx], arr_base[idx + 1]); + idx += 2; + } + } +} +void inject_init(void) +{ + if(is_inject_init == PS3_TRUE) { + return; + } + is_inject_init = PS3_TRUE; + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_DEAD, force_ioctl_cmd_dead) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_PENDING, force_ioctl_cmd_pending) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_SIG_INTERRUPT, force_ioctl_cmd_sig_interrupt) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_INTERRUPT, force_ioctl_cmd_interrupt) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_NO_RESP, force_ioctl_cmd_no_resp) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_ABORT_FAIL, force_return_fail) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_RECOVERY_CANCEL, force_ioctl_cmd_recovery_cancel) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_ABORT_NO_RESP, force_ioctl_cmd_abort_no_resp) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_FORCE_DONE, force_ioctl_cmd_force_done) + INJECT_REG(PS3_ERR_IJ_WAIT_NORMAL, wait_instance_normal) + INJECT_REG(PS3_ERR_IJ_FIRMWARE_INIT_FAIL, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_SCSI_SCAN_HOST_DELAY, force_scan_host_delay) + INJECT_REG(PS3_ERR_IJ_SCSI_SCAN_HOST_NOT_FINISH, force_scan_host_fail) + INJECT_REG(PS3_ERR_IJ_IGNORE_TASK_IO, force_ignore_task_io) + INJECT_REG(PS3_ERR_IJ_IGNORE_TASK_ABORT, force_ignore_task_abort) + INJECT_REG(PS3_ERR_IJ_IGNORE_TASK_RESET, force_ignore_task_reset) + INJECT_REG(PS3_ERR_IJ_EVENT_HANDLE, force_event_handle) + INJECT_REG(PS3_ERR_IJ_DEL_SCSI_DEV1, force_del_disk) + INJECT_REG(PS3_ERR_IJ_DEL_SCSI_DEV2, force_del_disk) + INJECT_REG(PS3_ERR_IJ_R1X_DEL_SCSI_DEV1, force_del_disk) + INJECT_REG(PS3_ERR_IJ_PRIV_DATA_NULL1, force_priv_data_null) + INJECT_REG(PS3_ERR_IJ_PRIV_DATA_NULL2, force_priv_data_null) + INJECT_REG(PS3_ERR_IJ_PRIV_DATA_NULL3, force_priv_data_null) + INJECT_REG(PS3_ERR_IJ_PRIV_DATA_NULL4, force_priv_data_null) + INJECT_REG(PS3_ERR_IJ_R1X_PRIV_DATA_NULL1, force_priv_data_null) + INJECT_REG(PS3_ERR_IJ_HT_ABNORMAL1, force_return_fail) + INJECT_REG(PS3_ERR_IJ_HT_ABNORMAL2, force_return_fail) + INJECT_REG(PS3_ERR_IJ_EVENT_INT_WAIT_HARD_FLAG, force_int_wait_hard_flag) + INJECT_REG(PS3_ERR_IJ_EVENT_INT_WAIT_HARD_SUBCRIBE, force_int_wait_hard_subcribe) + INJECT_REG(PS3_ERR_IJ_EVENT_PROC_WAIT_HARD_FLAG, force_wait_hard_flag) + INJECT_REG(PS3_ERR_IJ_EVENT_PROC_WAIT_HARD_SUBCRIBE, force_wait_hard_subcribe) + INJECT_REG(PS3_ERR_IJ_EVENT_SUBC_WAIT_HARD_FLAG, force_wait_hard_flag) + INJECT_REG(PS3_ERR_IJ_EVENT_SUBC_WAIT_HARD_SUBCRIBE, force_wait_hard_subcribe) + INJECT_REG(PS3_ERR_IJ_FLAG_WAIT_EVENT_INT, force_wait_event_int) + INJECT_REG(PS3_ERR_IJ_FLAG_WAIT_EVENT_PROC, force_wait_event_proc) + INJECT_REG(PS3_ERR_IJ_FLAG_WAIT_EVENT_SUBCRIBE, force_wait_event_subscribe) + INJECT_REG(PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_INT, force_wait_event_int) + INJECT_REG(PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_PROC, force_wait_event_proc) + INJECT_REG(PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_SUBCRIBE, force_wait_event_subscribe) + INJECT_REG(PS3_ERR_IJ_STORE_NO_TRIGGER_LOG, force_trigger_log_fail) + INJECT_REG(PS3_ERR_IJ_DETECT_NO_TRIGGER_LOG, force_trigger_log_fail) + INJECT_REG(PS3_ERR_IJ_EVENT_CMD_NULL, force_event_cmd_null) + INJECT_REG(PS3_ERR_IJ_SUBC_EVENT_CMD_INIT, force_event_cmd_null) + INJECT_REG(PS3_ERR_IJ_SUBC_EVENT_CMD_INIT,force_event_cmd_init) + INJECT_REG(PS3_ERR_IJ_RESUBC_EVENT_CMD_INIT,force_event_cmd_init) + INJECT_REG(PS3_ERR_IJ_CANCEL_EVENT_CMD_FAIL, force_return_fail) + INJECT_REG(PS3_ERR_IJ_CANCEL_VDPENDING_CMD_FAIL, force_return_fail) + INJECT_REG(PS3_ERR_IJ_FW_STATE_RUNNING, force_return_fail) + INJECT_REG(PS3_ERR_IJ_SET_IOC_IN_SECURITY, force_set_ioc_in_security) + INJECT_REG(PS3_ERR_IJ_WAIT_UNNORMAL, wait_instance_unnormal) + INJECT_REG(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID, wait_reco_dump_valid) + INJECT_REG(PS3_ERR_IJ_DUMP_WAIT_RECO_VALID_2, wait_reco_dump_valid) + INJECT_REG(PS3_ERR_IJ_DUMP_WAIT_NORMAL, wait_instance_normal) + INJECT_REG(PS3_ERR_IJ_WAIT_OPT, wait_instance_operational) + INJECT_REG(PS3_ERR_IJ_WAIT_READY, wait_ioc_ready) + INJECT_REG(PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F1, force_hard_ready_failed) + INJECT_REG(PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F0, force_hard_ready_failed) + INJECT_REG(PS3_ERR_IJ_RECOVERY_WAIT_FUNC0_RUNNING_1, wait_recovery_func0_running_1) + INJECT_REG(PS3_ERR_IJ_RECOVERY_WAIT_FUNC0_RUNNING_2, wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FWSTATE_REMOVE, wait_remove_is_load_flag) + INJECT_REG(PS3_ERR_IJ_IOCTL_CMD_RETRY_DONE, ioctl_cmd_retry_done) + INJECT_REG(PS3_ERR_IJ_QOS_SET_SHARE_COUNT, set_qos_share_cnt) + INJECT_REG(PS3_ERR_IJ_IOCTL_WAIT_UNNORMAL, wait_instance_unnormal_and_set_flag) + INJECT_REG(PS3_ERR_IJ_FORCE_EVENT_CMD_FAIL_DEAD, force_event_cmd_dead) + INJECT_REG(PS3_ERR_IJ_IOCTL_WAIT_IRQ_DISABLE, wait_irq_disable) + INJECT_REG(PS3_ERR_IJ_WAIT_IOCTL_IN_RECOVERY, wait_ioctl_detect_irq_disable) + INJECT_REG(PS3_ERR_IJ_WAIT_IOCTL_IN_DEVICE_RESET, wait_ioctl_detect_irq_disable) + INJECT_REG(PS3_ERR_IJ_SEND_IOCTL_BLOCK_MODE_FLAG, set_send_ioctl_block_flag) + INJECT_REG(PS3_ERR_IJ_FORCE_HAS_SCIS_PENDING_IO, force_has_scsi_pending_io) + INJECT_REG(PS3_ERR_IJ_HOST_RESET_WAIT_DECIDE, host_reset_wait_decide_normal) +#ifdef PS3_UT + INJECT_REG(PS3_ERR_IJ_ABORT_PRE1_FORCE_ABORTED_CMD_DONE, force_scsi_cmd_done) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE2_FORCE_ABORTED_CMD_DONE, force_scsi_cmd_done) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_BULID_FORCE_ABORTED_CMD_DONE, force_scsi_cmd_done) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_BULID1_FORCE_ABORTED_CMD_DONE, force_scsi_cmd_done) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_SEND_FORCE_ABORTED_CMD_DONE, force_scsi_cmd_done) + INJECT_REG(PS3_ERR_IJ_ABORT_CMD_ERROR, force_scsi_task_cmd_error) + INJECT_REG(PS3_ERR_IJ_RESET_CMD_ERROR, force_scsi_task_cmd_error) + INJECT_REG(PS3_ERR_IJ_SCSI_TASK_PRE_CHECK_FAILED, force_pcie_err) + INJECT_REG( PS3_ERR_IJ_FORCE_INSTANCE_UNNORMAL, force_instance_state_unnormal) + INJECT_REG(PS3_ERR_IJ_TASK_CMD_ALLOC_FAILED, force_task_cmd_alloc_null) + INJECT_REG(PS3_ERR_IJ_SMP_CMD_ERROR, force_smp_cmd_error) + INJECT_REG(PS3_ERR_IJ_GET_LINKERRORS_CMD_ERROR, force_get_linkerrors_cmd_error) + INJECT_REG(PS3_ERR_IJ_PHY_CTRL_CMD_ERROR, force_sas_phy_ctrl_cmd_error) + INJECT_REG(PS3_ERR_IJ_PROBE_HOST_RESET, force_host_reset) +#else + INJECT_REG(PS3_ERR_IJ_ABORT_PRE1_FORCE_ABORTED_CMD_DONE, ps3_scsi_rw_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE2_FORCE_ABORTED_CMD_DONE, ps3_scsi_rw_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_BULID_FORCE_ABORTED_CMD_DONE, ps3_scsi_rw_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_BULID1_FORCE_ABORTED_CMD_DONE, ps3_scsi_rw_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_SEND_FORCE_ABORTED_CMD_DONE, ps3_scsi_rw_cmd_filter_handle) + + INJECT_REG(PS3_ERR_IJ_ABORT_CMD_TIMEOUT, ps3_scsi_task_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_RESET_CMD_TIMEOUT, ps3_scsi_task_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_ABORT_CMD_ERROR, ps3_scsi_task_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_RESET_CMD_ERROR, ps3_scsi_task_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_ABORT_CMD_NORMAL, ps3_scsi_task_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_RESET_CMD_NORMAL, ps3_scsi_task_cmd_filter_handle) + + INJECT_REG(PS3_ERR_IJ_SMP_CMD_TIMEOUT, ps3_mgr_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_SMP_CMD_ERROR, ps3_mgr_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_GET_LINKERRORS_CMD_ERROR, ps3_mgr_cmd_filter_handle) + INJECT_REG(PS3_ERR_IJ_PHY_CTRL_CMD_ERROR, ps3_mgr_cmd_filter_handle) +#endif + INJECT_REG(PS3_ERR_IJ_ABORT_PRE_DEAL_FORCE_ABORTED_CMD_DONE, force_aborted_cmd_done) + INJECT_REG(PS3_ERR_IJ_FORCE_STOP_ALL_CMD_DONE, force_stop_aborted_cmd_done) + INJECT_REG(PS3_ERR_IJ_QOS_NOT_AWAKE_PD, force_return_false) + INJECT_REG(PS3_ERR_IJ_UNLOAD_TIMEOUT, force_ioctl_cmd_no_resp) + INJECT_REG(PS3_ERR_IJ_QOS_PD_RESEND_NOT_EXPIRED, force_return_false) + INJECT_REG(PS3_ERR_IJ_IOC_NOT_RUNNING, force_ioc_not_running) + INJECT_REG(PS3_ERR_IJ_IOC_IS_NOT_NORMAL_IN_UNLOAD, force_ioc_not_running) + INJECT_REG(PS3_ERR_IJ_HALF_HARD_RESET, force_return_true) + INJECT_REG(PS3_ERR_IJ_ROMOVE_UNLOAD_FAIL, force_mgr_cmd_alloc_null) + INJECT_REG(PS3_ERR_IJ_WAIT_TASK_MGR_BUSY, wait_task_mgr_busy) + INJECT_REG(PS3_ERR_IJ_RESET_TARGET_PAUSE, reset_target_pause) + INJECT_REG(PS3_ERR_IJ_SEND_CMD_TASK_MGR_BUSY, set_send_cmd_task_mgr_busy_flag) + INJECT_REG(PS3_ERR_IJ_QOS_VD_MEMBER_CLEARING, wait_pd_clear) + INJECT_REG(PS3_ERR_IJ_QOS_WAIT_VD_SEND, wait_qos_vd_send) + INJECT_REG(PS3_ERR_IJ_SAS_REQ_PRE_CHECK, force_instance_state_to_unnormal) + INJECT_REG(PS3_ERR_IJ_SAS_RPHY_SLOT_GET_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_SAS_EXP_RPHY_SLOT_GET_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_SAS_ENCL_ID_GET_FAILED, ps3_sas_encl_id_get_failed) + INJECT_REG(PS3_ERR_IJ_MGR_CMD_ALLOC_FAILED, force_mgr_cmd_alloc_null) + INJECT_REG(PS3_ERR_IJ_CMD_POLLING, force_cmd_polling) + INJECT_REG(PS3_ERR_IJ_PCI_ERR_RECOVERY, force_pci_err_recovery) + INJECT_REG(PS3_ERR_IJ_INS_STATE_UNNORMAL, force_instance_state_to_unnormal) + INJECT_REG(PS3_ERR_IJ_INS_STATE_DEAD, force_instance_state_to_dead) + INJECT_REG(PS3_ERR_IJ_RPHY_PARENT_SAS_ADDR_GET_FAILED, ps3_sas_rphy_parent_sas_addr_get_failed) + INJECT_REG(PS3_ERR_IJ_SAS_NODE_NOT_FOUND, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_REQ_EXT_BUF_INVALLID, force_blk_rq_bytes_invalid) + INJECT_REG(PS3_ERR_IJ_EXT_BUF_TO_RSP_INVALLID,force_ptr_null) + INJECT_REG(PS3_ERR_IJ_WAIT_CMD_DONE, wait_cmd_done) + INJECT_REG(PS3_ERR_IJ_CMD_SEND_BLOCK, wait_cmd_send_block) + INJECT_REG(PS3_ERR_IJ_FORCE_TASK_MGR_BUSY, force_task_mgr_busy) + INJECT_REG(PS3_ERR_IJ_FORCE_INS_UNLOAD, force_instance_unload) + INJECT_REG(PS3_ERR_IJ_FORCE_INSTANCE_UNNORMAL, force_instance_state_unnormal) + INJECT_REG(PS3_ERR_IJ_QOS_PD_INIT_FAIL_1, create_pd_worker_fail) + INJECT_REG(PS3_ERR_IJ_QOS_PD_INIT_FAIL_2, create_pd_mgrs_fail) + INJECT_REG(PS3_ERR_IJ_QOS_PD_INIT_FAIL_3, create_pd_waitq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_PD_INIT_FAIL_4, create_pd_workq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_TAG_INIT_FAIL_1, create_tag_waitq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_TAG_INIT_FAIL_2, create_tag_workq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_VD_INIT_FAIL_1, create_vd_mgrs_fail) + INJECT_REG(PS3_ERR_IJ_QOS_VD_INIT_FAIL_2, create_vd_workq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_VD_INIT_FAIL_3, create_vd_worker_fail) + INJECT_REG(PS3_ERR_IJ_QOS_WAIT_PD_WAITQ_CLEAR, block_in_cmd_send) + INJECT_REG(PS3_ERR_IJ_QOS_WAIT_PD_WAITQ_CLEAR_2, block_in_cmd_send) + INJECT_REG(PS3_ERR_IJ_QOS_WAIT_VD_WAITQ_CLEAR, block_in_cmd_send) + INJECT_REG(PS3_ERR_IJ_QOS_WAIT_TAG_WAITQ_CLEAR, block_in_cmd_send) + INJECT_REG(PS3_ERR_IJ_QOS_NOT_AWAKE_TAG, force_return_false) + INJECT_REG(PS3_ERR_IJ_CMD_SEND_FORCE_INS_UNLOAD, force_instance_unload) + INJECT_REG(PS3_ERR_IJ_CMD_SEND_FORCE_UNORMAL, force_instance_state_unnormal) + INJECT_REG(PS3_ERR_IJ_CMD_SEND_FORCE_PCI_ERR, force_instance_state_pci_err) + INJECT_REG(PS3_ERR_IJ_QOS_FORCE_VD_SEQ_CHANGE, force_cmd_vd_seq_change) + INJECT_REG(PS3_ERR_IJ_QOS_FORCE_MGRQ_ZERO_DEPTH, force_u64_zero) + INJECT_REG(PS3_ERR_IJ_QOS_FORCE_CMDQ_ZERO_DEPTH, force_u64_zero) + INJECT_REG(PS3_ERR_IJ_QOS_MGRQ_INIT_FAIL_1, create_mgr_waitq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_MGRQ_INIT_FAIL_2, create_mgr_worker_fail) + INJECT_REG(PS3_ERR_IJ_QOS_CMDQ_INIT_FAIL_1, create_cmd_waitq_fail) + INJECT_REG(PS3_ERR_IJ_QOS_CMDQ_INIT_FAIL_2, create_cmd_worker_fail) + INJECT_REG(PS3_ERR_IJ_QOS_WAIT_SOFT_WAITQ_CLEAR, block_in_cmd_send) + INJECT_REG(PS3_ERR_IJ_BLOCK_HOST_RESET, block_in_cmd_send) + INJECT_REG(PS3_ERR_IJ_R1X_CONFLICTQ_PROCESS_FINISH, set_r1x_conflict_process_flag) + INJECT_REG(PS3_ERR_IJ_WAIT_TASK_MGR_BUSY, wait_task_mgr_busy) + INJECT_REG(PS3_ERR_IJ_RESET_TARGET_PAUSE, reset_target_pause) + INJECT_REG(PS3_ERR_IJ_WAIT_HARD_RESET, wait_for_dead_or_pre_operational) + INJECT_REG(PS3_ERR_IJ_FORCE_IOC_RUNNING, force_set_ioc_running) + INJECT_REG(PS3_ERR_IJ_FORCE_INIT_FAIL, force_init_cmd_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL, force_init_cmd_running_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL2, force_init_cmd_running_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_LOAD_START_HARD, force_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_HOST_START_HARD, force_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_SCAN_START_HARD, force_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_A_SCAN_START_HARD, force_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_A_SCAN_FINISH_HARD, force_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_F1_PROBE_FORCE_IOC_FAULT, force_set_ioc_fault) + INJECT_REG(PS3_ERR_IJ_RECOVERY_WAIT_FUNC1_PROBE,wait_recovery_func1_probe) + INJECT_REG(PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_PROBE,wait_recovery_req_func1_probe) + INJECT_REG(PS3_ERR_IJ_RECOVERY_WAIT_FUNC1_REMOVE,wait_recovery_func1_remove) + INJECT_REG(PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_REMOVE,wait_recovery_req_func1_remove) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_B_READY, wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_A_READY, wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_B_INIT, wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_A_INIT, wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_RUNNING, wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_CTRL_INFO,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_OPER,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_SCSI_INIT,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_LOAD,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_B_SCAN,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_A_SCAN,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_SCAN_FINISH,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_F1_EVENT,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_IOC_RUNNING_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_INIT_FAIL_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL2_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_LOAD_START_HARD_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_HOST_START_HARD_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_F1_PROBE_FORCE_IOC_FAULT_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_SCAN_START_HARD_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_A_SCAN_START_HARD_RESUME_RECOVERY,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_NOT_RUNNING, force_set_ioc_fault) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_EVENT_FAIL, force_set_ioc_fault) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_VDINFO_FAIL, force_set_ioc_fault) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_WEB_FAIL, force_set_ioc_fault) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_UNLOAD_FAIL, force_set_ioc_fault) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_CANCEL_EVENT_WORK_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_EVENT_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_VDINFO_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_WEB_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_UNLOAD_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_CANCEL_EVENT_WORK_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_EVENT_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_VDINFO_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_WEB_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_UNLOAD_FAIL_RESUME,wait_recovery_func0_running_2) + INJECT_REG(PS3_ERR_IJ_WAIT_SCSI_CMD_DONE_FAIL, wait_scsi_cmd_done_fail) + INJECT_REG(PS3_ERR_IJ_INIT_CMD_PROC_FAIL, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_IOC_STATE_WAIT_TO_RUNNING_FAIL, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_IOC_INIT_PROC_STATE_RUNNING, force_ioc_running) + INJECT_REG(PS3_ERR_IJ_INIT_PROC_FAIL_NOUNLOAD, force_ioc_running) + INJECT_REG(PS3_ERR_IJ_GET_PD_INFO_RETURN_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_FORCE_MEMDUP_USER_RETURN_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_IOCTL_WAIT_NORMAL_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_FORCE_IOCTL_ALLOC_CMD_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_WAIT_CMD_FREE, wait_cmd_free) + INJECT_REG(PS3_ERR_IJ_WAIT_ABORT_FLAG, wait_abort_flag) + INJECT_REG(PS3_ERR_IJ_WAIT_CMD_ALLOC, wait_cmd_alloc) + INJECT_REG(PS3_ERR_IJ_SET_CMD_TID_FLAG, set_cmd_tid_flag) + INJECT_REG(PS3_ERR_IJ_WAIT_CMD_FREE1, wait_cmd_free) + INJECT_REG(PS3_ERR_IJ_WAIT_ABORT_FLAG1, wait_abort_flag) + INJECT_REG(PS3_ERR_IJ_SET_ABORT_COUNT, set_abort_count) + INJECT_REG(PS3_ERR_IJ_WAIT_CMD_ALLOC1, wait_cmd_alloc1) + INJECT_REG(PS3_ERR_IJ_WAIT_CMD_ALLOC2, wait_cmd_alloc2) + INJECT_REG(PS3_ERR_IJ_FORCE_ALLOC_DMA_BUF_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PCIE_ERR_PCI_INIT_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_FORCE_PCIE_ERR_PCI_INIT_COMP_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_PCI_FORCE_HARD_RECOVERY_REQ_FAILED, force_hard_recovery_request_nosupport_fail) + INJECT_REG(PS3_ERR_IJ_PCI_FORCE_WAIT_OPERARIONAL_FAILED, force_ret_fail) + INJECT_REG(PS3_ERR_IJ_FORCE_PCIE_ERR_IOC_RUNNING_INIT_FAILED, force_ioc_not_running) + INJECT_REG(PS3_ERR_IJ_FORCE_STREAM_DETECT_TRUE, force_return_true) + INJECT_REG(PS3_ERR_IJ_FORCE_SEQ_CMD, force_seq_cmd) + INJECT_REG(PS3_ERR_IJ_FORCE_RAND_CMD, force_rand_cmd) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL1, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_VD_COUNT_ERR, force_vd_count_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_CHAN, force_dev_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_CHAN1, force_chan_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_TARGET, force_target_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_DISKPOS, force_diskpos_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL2, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_LUN_ERROR,force_lun_err) + INJECT_REG(PS3_ERR_IJ_FORCE_INSTANCE_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_VD_ENTRY_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_VD_ENTRY_NULL1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PRIV_DATA_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_RB_INFO_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_HASH_MGR_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_MGR_CONFLICT_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_SEND_TH_NULL, force_thread_null) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL3, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_INSTANCE_NULL1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PRIV_DATA_NULL1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_DEV_TYPE, force_dev_type_err) + INJECT_REG(PS3_ERR_IJ_FORCE_VD_ENTRY_NULL2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL4, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_INSTANCE_NULL2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL5, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL6, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_DISKPOS1, force_diskpos_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_ALIGN, force_align_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_ALIGN1, force_align_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_CHAN2, force_target_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_DISKID, force_target_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_CHAN3, force_chan_err) + INJECT_REG(PS3_ERR_IJ_FORCE_MOD_DISKPOS2, force_diskpos_err) + INJECT_REG(PS3_ERR_IJ_FORCE_PD_ENTRY_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PD_ENTRY_NULL1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PD_STATE_ERROR, force_pd_state_err) + INJECT_REG(PS3_ERR_IJ_FORCE_PRIV_DATA_NULL2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PD_ENTRY_NULL2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_0, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_1, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_2, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_3, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_4, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_5, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_6, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_7, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_8, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_9, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_10, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_11, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_12, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_13, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_14, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_15, wait_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL7, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_RET_FAIL8, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_DOORBELL_FAILED, force_doorbell_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_INIT_FAIL, force_recovery_init_cmd_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_OPE_FAIL, force_recovery_operation_cmd_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_DEBUG_INIT_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_TRANSPORT_INIT_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_CHARDEV_INIT_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_PCIDRV_INIT_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_VERFILE_INIT_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_VERFILE2_INIT_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_IO_RW_FLAG_SET_UNKOWN, set_cmd_io_rw_flag_unkown) + INJECT_REG(PS3_ERR_IJ_SOFT_ZONE_TYPE_SET_UNKOWN, set_soft_zone_type_unkown) + INJECT_REG(PS3_ERR_IJ_WATCHDOG_WAIT_RUNNING, wait_ioc_ready) + INJECT_REG(PS3_ERR_IJ_WATCHDOG_IRQ_QUEUE, force_work_queue_unull) + INJECT_REG(PS3_ERR_IJ_WATCHDOG_IRQ_QUEUE_1, force_work_queue_failed) + INJECT_REG(PS3_ERR_IJ_READ_FW_STATE_REG_FF, force_fw_state_ff) + INJECT_REG(PS3_ERR_IJ_SET_HIGH_IOPS_CHANNEL_IN_QOS, set_iops_channel) + INJECT_REG(PS3_ERR_IJ_FORCE_F0_WATCHDOG_START_HARD, force_set_f0_ioc_critical) + INJECT_REG(PS3_ERR_IJ_ADD_DISK_HOST_RESET, force_stop_aborted_cmd_done) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_WAIT_RECOVERY, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_WAIT_RECOVERY_1, force_stop_aborted_cmd_done) + INJECT_REG(PS3_ERR_IJ_PCIE_FROZEN, force_pcie_frozen) + INJECT_REG(PS3_ERR_IJ_PEER_PCIE_FROZEN, force_pcie_frozen) + INJECT_REG(PS3_ERR_IJ_ASYNC_HARDRESET_PROBE, force_async_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_ASYNC_HARDRESET_REMOVE, force_async_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_MOD_SO_ADDR, for_mod_so_addr) + INJECT_REG(PS3_ERR_IJ_SHUTDOWN_HARDRESET, force_hard_reset_request) + INJECT_REG(PS3_ERR_IJ_CANCEL_WEB_CMD_ALLOC_NULL, force_return_fail) + INJECT_REG(PS3_ERR_IJ_GET_REPLYQ_COUNT_INVALID, force_fw_state_ff) + INJECT_REG(PS3_ERR_IJ_GET_MSIX_VEC_COUNT_INVALID, force_s32_zero) + INJECT_REG(PS3_ERR_IJ_GET_MSI_VEC_COUNT_INVALID, force_s32_letter_zero) + INJECT_REG(PS3_ERR_IJ_GET_MAX_CMD_COUNT_INVALID, force_fw_state_ff) + INJECT_REG(PS3_ERR_IJ_ALLOC_LEGACY_VECTOR_FAILED, force_s32_zero) + INJECT_REG(PS3_ERR_IJ_CPU_MSIX_TABLE_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_REPLY_FIFO_DESC_BUF_POOL_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_REPLY_FIFO_DESC_BUF_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_REPLY_FIFO_POOL_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_REPLY_VIRT_BASE_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_IRQS_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_REPLY_REQ_IRQS_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_DUMP_REQ_IRQS_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_IRQ_VECTORS_ALLOC_FAILED, force_s32_zero) + INJECT_REG(PS3_ERR_IJ_SAS_PHY_GET_ERR, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_SAS_PORT_ALLOC_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_ALLOC_NUM_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_PORT_ADD_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_SAS_ALLOC_PHY_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_PHY_ADD_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_SAS_ADD_ACK_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_CHANGE_FW_TO_HALT_IN_PREPARE, change_fw_state_to_halt_in_recover_prepare) + INJECT_REG(PS3_ERR_IJ_ALLOC_EXP_NODE_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_ALLOC_EXP_PHYS_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_PORT_ALLOC_NULL1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_PHY_GET_ERR1, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_SAS_ALLOC_PHY_NULL1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_SAS_PHY_ADD_FAILED1, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_READ_ATU_REG_FAILED, force_reg_fail) + INJECT_REG(PS3_ERR_IJ_IOC_TO_READY_FAILED, force_ready_failed) + INJECT_REG(PS3_ERR_IJ_BIT_POS_ERR, force_atu_support_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_ALLOC_CANCEL_CMD_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_CANCEL_CMD_RET_RECOVERY, force_ret_recovery) + INJECT_REG(PS3_ERR_IJ_FORCE_CANCEL_CMD_PCIE_ERR,force_ret_failed) + INJECT_REG(PS3_ERR_IJ_WAIT_RESUME_WAIT_RECOVERY, force_hard_reset_request_1) + INJECT_REG(PS3_ERR_IJ_FORCE_STREAM_DETECT_FALSE, force_return_false) + INJECT_REG(PS3_ERR_IJ_PS3_INIT_FRAME_SYS_INFO_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PS3_CMD_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_REQ_FRAME_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_RESP_FRAME_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_EXT_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_MGR_EXT_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_R1XLOCK_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_IOCTL_TRANSIENT_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PERCPU_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_DELAY_WORK_POOL_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_STAT_BUF_ALLOC1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_STAT_BUF_ALLOC2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_STAT_BACKUP_BUF_ALLOC1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_STAT_BACKUP_BUF_ALLOC2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_LAST_STAT_BUF_ALLOC1, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_CMD_LAST_STAT_BUF_ALLOC2, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_DEBUG_MEM_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_DEBUG_MEM_ADDR_ALLOC, force_u64_zero) + INJECT_REG(PS3_ERR_IJ_PS3_DRV_INFO_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_HOST_MEM_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PD_LIST_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PD_INFO_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_LIST_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_INFO_BUF_SYNC_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_INFO_BUF_ASYNC_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_IDX_ARRAY_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_ENTRIES_ARRAY_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_DEVS_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_PRI_DATA_IDXS_ARRAY_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PD_ENTRIES_ARRAY_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PD_IDX_ARRAY_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_PD_DEVS_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_SAS_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_SAS_PHY_BUF_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_PS3_VD_PENDING_CMD_ALLOC, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_PCI_EN_MEM_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_PCI_RES_FLAGS_FAILED, force_s32_zero) + INJECT_REG(PS3_ERR_IJ_FORCE_PCI_REQ_REGION_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_PCI_IOREMAP_FAILED, force_pci_ioremap_fail) + INJECT_REG(PS3_ERR_IJ_ADD_INSTANCE_WAIT, wait_recovery_req_coming) + INJECT_REG(PS3_ERR_IJ_REMOVE_INSTANCE_WAIT, wait_recovery_req_coming) + INJECT_REG(PS3_ERR_IJ_ADD_INSTANCE, force_u8_1) + INJECT_REG(PS3_ERR_IJ_REMOVE_INSTANCE, force_u8_1) + INJECT_REG(PS3_ERR_IJ_FORCE_DUL_RECOVERY, force_multi_hard_req) + INJECT_REG(PS3_ERR_IJ_FORCE_START_DUL_RECOVERY, force_multi_hard_req) + INJECT_REG(PS3_ERR_IJ_WAIT_HARDRESET, wait_hard_recovery_req) + INJECT_REG(PS3_ERR_IJ_FORCE_DUL_RECOVERY_PENDING, force_multi_hard_req_pending) + INJECT_REG(PS3_ERR_IJ_FORCE_DESTORY_RECOVERY, force_recovery_wq_null) + INJECT_REG(PS3_ERR_IJ_FORCE_START_DESTORY_RECOVERY, force_recovery_wq_null) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_STATE_DEAD, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PEER_STATE_DEAD, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_NOT_SUPPORT, force_recovery_support_false) + INJECT_REG(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_PEER_DEAD_FAIL, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_REG_FAILED, force_ioc_not_running) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PEER_COMPLETE_FAILED, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, force_mgr_cmd_alloc_null) + INJECT_REG(PS3_ERR_IJ_PD_LIST_WAIT_IRQ_DISABLE, wait_irq_disable) + INJECT_REG(PS3_ERR_IJ_PD_LIST_CMD_NO_RESP, force_mgr_cmd_no_resp) + INJECT_REG(PS3_ERR_IJ_PD_LIST_RESP_RETRY, force_pdlist_cmd_retry) + INJECT_REG(PS3_ERR_IJ_FORCE_ENTRY_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL1, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_ALLOC_FAIL, force_memory_alloc_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_DECIDE_PEER_INSTANCE_FAIL, force_instance_state_to_unnormal) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PCIE_ERR, force_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PEER_PCIE_ERR, force_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_IOC_HALT, force_set_ioc_halt) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PEER_IOC_HALT, force_set_ioc_halt) + INJECT_REG(PS3_ERR_IJ_FORCE_IOC_RUNNING_PCI_ERR, force_pcie_err) + INJECT_REG(PS3_ERR_IJ_FORCE_VDINFO_SUB_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_WEB_SUB_FAIL, force_ret_failed) + INJECT_REG(PS3_ERR_IJ_WAIT_RUNNING_FAIL, force_ioc_not_running) + INJECT_REG(PS3_ERR_IJ_WAIT_RUNNING_FAIL1, force_ioc_not_running) + INJECT_REG(PS3_ERR_IJ_WEB_SUBSCRIBE, force_web_subcribe) + INJECT_REG(PS3_ERR_IJ_FORCE_RECOVERY_FINISH_STATE_NOOPERATIONAL, force_instance_state_to_unnormal) + INJECT_REG(PS3_ERR_IJ_FORCE_HARD_INIT_RUNING_UNNORMAL, force_instance_probe_failed) + INJECT_REG(PS3_ERR_IJ_FORCE_HARD_READY_PCIE_ERRL, force_pcie_err) + INJECT_REG(PS3_ERR_IJ_WAIT_PM_INSTANCE_NULL, force_instance_null) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET, force_half_reset) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET_1, force_half_reset_false) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED, force_web_subscribe_failed) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED_1, force_return_fail) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED_2, force_cmd_delivering_zero) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_VD_PENDING_FAILED, force_return_fail) + INJECT_REG(PS3_ERR_IJ_WAIT_RESUME_EVENT_FAILED, force_return_fail) + INJECT_REG(PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET_2, force_half_reset) + INJECT_REG(PS3_ERR_IJ_WAIT_RESUME_FUNCID_INVALID, force_func_id_invalid) + INJECT_REG(PS3_ERR_IJ_DUMP_WORK_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_FEATURE_SUPPORT_ERR, force_reg_fail) + INJECT_REG(PS3_ERR_IJ_DUMP_STATUS_ERR, force_reg_fail) + INJECT_REG(PS3_ERR_IJ_DUMP_TYPE_INVALID, force_return_zero) + INJECT_REG(PS3_ERR_IJ_DUMP_PCIE_ERR, force_pcie_err) + INJECT_REG(PS3_ERR_IJ_DUMP_RECOVERY_ERR, force_instance_state_unnormal) + INJECT_REG(PS3_ERR_IJ_DUMP_TYPE_ILLEGAL, force_return_zero) + INJECT_REG(PS3_ERR_IJ_DUMP_WORK_QUEUE_NULL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_DUMP_STATE_ILLEGAL, force_return_true) + INJECT_REG(PS3_ERR_IJ_DUMP_TRIGGER_FAIL, force_return_fail) + INJECT_REG(PS3_ERR_IJ_DUMP_DUMP_STATE_GET_FAIL, force_return_false) + INJECT_REG(PS3_ERR_IJ_DUMP_DUMP_STATE_INVALID, force_return_invalid) + INJECT_REG(PS3_ERR_IJ_DUMP_FILE_OPEN_FAIL, force_ptr_null) + INJECT_REG(PS3_ERR_IJ_DUMP_DATA_SIZE_FAIL, force_reg_fail) + INJECT_REG(PS3_ERR_IJ_DUMP_WRITE_FAIL, force_return_fail) + INJECT_REG(PS3_ERR_IJ_DUMP_ABORT_GET_CTRL_FAIL, force_return_false) + INJECT_REG(PS3_ERR_IJ_DUMP_END_GET_CTRL_FAIL, force_return_false) + INJECT_REG(PS3_ERR_IJ_DUMP_TRIGGER_GET_CTRL_FAIL, force_return_false) + INJECT_REG(PS3_ERR_IJ_DUMP_DATA_COPY_GET_CTRL_FAIL, force_return_false) + INJECT_REG(PS3_ERR_IJ_DUMP_IS_TRIGGER_GET_CTRL_FAIL, force_return_false) + INJECT_REG(PS3_ERR_IJ_DUMP_CTRL_ERR, force_reg_fail) + INJECT_REG(PS3_ERR_DUMP_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_RECOVERY_CONTEXT_ALLOC_FAILED, force_ptr_null) + INJECT_REG(PS3_ERR_FORCE_SET_CMD_INDEX_NOT_MGR, force_cmd_not_mgr_cmd) + INJECT_REG(PS3_ERR_EXP_ID_ERR, force_chan_err) + INJECT_REG(PS3_ERR_HBA_PHY_COUNT_ZERO, force_phy_count_zero) + INJECT_REG(PS3_ERR_IJ_CHANGE_FW_TO_HALT_IN_PREPARE, change_fw_state_to_halt_in_recover_prepare) + INJECT_REG(PS3_ERR_IJ_IOC_TO_READY_FAILED1, force_ready_failed) + INJECT_REG(PS3_ERR_IJ_REG_READ_ERR, force_reg_fail) + INJECT_REG(PS3_ERR_IJ_REG_READ_ZERO, force_reg_zero) + INJECT_REG(PS3_ERR_IJ_QOS_FORCE_TFIFO_ZERO_DEPTH, force_fifo_depth_zero) + INJECT_REG(PS3_ERR_IJ_FEATURE_REG_READ_ERR, force_reg_fail) + INJECT_REG(PS3_ERR_IJ_IOC_TO_CRITICAL, force_ioc_critical) + INJECT_REG(PS3_ERR_IJ_GET_PRIV_DATA_DELAY, NULL) + INJECT_REG(PS3_ERR_IJ_DEL_DEV_WAIT_OS_PRIV_DATA, NULL) + INJECT_REG(PS3_ERR_IJ_ADD_DEV_WAIT_OS_PRIV_DATA, NULL) + INJECT_REG(PS3_ERR_IJ_SGL_ADDR_PAGE_MODE_5, force_change_sgl_addr_to_page_mode_5) + INJECT_REG(PS3_ERR_IJ_SGL_ADDR_RESTORE, force_sgl_addr_restore) + INJECT_REG(PS3_ERR_IJ_FORCE_WAIT, NULL) + INJECT_REG(PS3_ERR_IJ_PD_ATTR_WAIT_OS_SCAN, NULL) + INJECT_REG(PS3_ERR_IJ_OS_SCAN, NULL) + INJECT_REG(PS3_ERR_IJ_PD_ATTR_WAIT_PD_ATTR, NULL) + INJECT_REG(PS3_ERR_IJ_PD_ATTR, NULL) + INJECT_REG(PS3_ERR_IJ_CMD_BLOCK_BEFORE_SEND_TO_IOC, wait_cmd_send_block) + INJECT_REG(PS3_ERR_IJ_FORCE_IOCTL_WAIT_RECOVERY, cli_wait_recovery) + INJECT_REG(PS3_ERR_IJ_FORCE_WAIT_CLI_CMD, recovery_wait_cli) + INJECT_REG(PS3_ERR_IJ_WDT_WAIT_REC_REQ, wait_recovery_request) + INJECT_REG(PS3_ERR_IJ_WDT_WAIT_REC_REQ_2, wait_recovery_request_2) + INJECT_REG(PS3_ERR_IJ_RECOVERY_BLOCK_BEFORE_RUNNING, recovery_wait_conditional) + INJECT_REG(PS3_ERR_IJ_CMD_SEND_INSTANCE_RECOVERY, force_instance_state_unnormal) + INJECT_REG(PS3_ERR_IJ_CMD_BLOCK_BEFORE_DELIVER_CNT, wait_cmd_send_block) + INJECT_REG(PS3_ERR_IJ_WDT_WAIT_REC_REQ_3, wait_f0_watchdog) + INJECT_REG(PS3_ERR_IJ_WDT_WAIT_REC_REQ_4, wait_f0_watchdog_2) + INJECT_REG(PS3_ERR_IJ_V2_IS_LOAD_FALSE, force_instance_unload) + INJECT_REG(PS3_ERR_IJ_V2_PCIE_ERR, force_instance_state_pci_err) + INJECT_REG(PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_UNORMAL, wait_instance_unnormal_and_set_flag) + INJECT_REG(PS3_ERR_IJ_V2_WAKE_RECOVERY_WAIT, set_send_cmd_task_mgr_busy_flag) + INJECT_REG(PS3_ERR_IJ_V2_RECOVERY_WAIT_NOTIFY, reset_target_pause) + INJECT_REG(PS3_ERR_IJ_V2_FORCE_INSTANCE_STATE_NORMAL, force_instance_state_normal) + INJECT_REG(PS3_ERR_IJ_V2_FORCE_INS_STATE_UNNORMAL, force_instance_state_unnormal) + INJECT_REG(PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_NORMAL, wait_instance_normal) + INJECT_REG(PS3_ERR_IJ_V2_FORCE_INS_DEAD, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_V2_IS_LOAD_FALSE1, force_instance_unload) + INJECT_REG(PS3_ERR_IJ_V2_FORCE_INS_DEAD1, force_recovery_state_dead) + INJECT_REG(PS3_ERR_IJ_ABORT_BLOCK1, err_abort_block) + INJECT_REG(PS3_ERR_IJ_ABORT_BLOCK2, wait_cmd_send_block) + INJECT_REG(PS3_ERR_IJ_SAS_PORT_CREATE_FAIL, force_sas_port_create_fail) + + LOG_INFO("inject_init success\n"); + ps3_inject_init(); + return; +} +void inject_exit(void) +{ + U32 idx = 0; + for(idx = PS3_ERR_IJ_WATCHDOG_CONCURY ;idx < PS3_ERR_IJ_MAX_COUNT; idx++) + { + memset(&g_ps3_err_scene[idx - 1], 0, sizeof(Ps3Injection_t)); + } + ps3_inject_exit(); + is_inject_init = PS3_FALSE; +} +#endif + diff --git a/drivers/scsi/ps3stor/ps3_err_inject.h b/drivers/scsi/ps3stor/ps3_err_inject.h new file mode 100644 index 0000000000000000000000000000000000000000..5b6dc9141df4cb2e8a1a4aa864c576ecf02c709f --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_err_inject.h @@ -0,0 +1,617 @@ + +#ifndef _PS3_ERR_INJECT_H_ +#define _PS3_ERR_INJECT_H_ + +#include + +#include "ps3_platform_utils.h" +#include "ps3_htp_def.h" + +typedef enum { + PS3_ERR_IJ_WATCHDOG_CONCURY = 1, + PS3_ERR_IJ_STOP_DUMP_CONCURY = 2, + PS3_ERR_IJ_SOFT_TO_HARD = 3, + PS3_ERR_IJ_WATCHDOG_DELAY, + PS3_ERR_IJ_EVENT_DELAY, + PS3_ERR_IJ_VD_PENDING_DELAY, + PS3_ERR_IJ_IOCTL_CMD_DEAD, + PS3_ERR_IJ_IOCTL_CMD_PENDING, + PS3_ERR_IJ_IOCTL_CMD_SIG_INTERRUPT, + PS3_ERR_IJ_IOCTL_CMD_INTERRUPT, + PS3_ERR_IJ_IOCTL_CMD_NO_RESP, + PS3_ERR_IJ_IOCTL_CMD_ABORT_FAIL, + PS3_ERR_IJ_IOCTL_CMD_ABORT_NO_RESP, + PS3_ERR_IJ_IOCTL_CMD_FORCE_DONE, + PS3_ERR_IJ_IOCTL_CMD_RECOVERY_CANCEL, + PS3_ERR_IJ_WAIT_NORMAL, + PS3_ERR_IJ_FIRMWARE_INIT_FAIL, + PS3_ERR_IJ_SCSI_SCAN_HOST_DELAY, + PS3_ERR_IJ_SCSI_SCAN_HOST_NOT_FINISH, + PS3_ERR_IJ_IGNORE_TASK_IO, + PS3_ERR_IJ_IGNORE_TASK_ABORT, + PS3_ERR_IJ_IGNORE_TASK_RESET, + PS3_ERR_IJ_EVENT_HANDLE, + PS3_ERR_IJ_DEL_SCSI_DEV1, + PS3_ERR_IJ_DEL_SCSI_DEV2, + PS3_ERR_IJ_PRIV_DATA_NULL1, + PS3_ERR_IJ_PRIV_DATA_NULL2, + PS3_ERR_IJ_PRIV_DATA_NULL3, + PS3_ERR_IJ_PRIV_DATA_NULL4, + PS3_ERR_IJ_R1X_DEL_SCSI_DEV1, + PS3_ERR_IJ_R1X_PRIV_DATA_NULL1, + PS3_ERR_IJ_HT_ABNORMAL1, + PS3_ERR_IJ_HT_ABNORMAL2, + PS3_ERR_IJ_EVENT_INT_WAIT_HARD_FLAG, + PS3_ERR_IJ_EVENT_INT_WAIT_HARD_SUBCRIBE, + PS3_ERR_IJ_EVENT_PROC_WAIT_HARD_FLAG, + PS3_ERR_IJ_EVENT_PROC_WAIT_HARD_SUBCRIBE, + PS3_ERR_IJ_EVENT_SUBC_WAIT_HARD_FLAG, + PS3_ERR_IJ_EVENT_SUBC_WAIT_HARD_SUBCRIBE, + PS3_ERR_IJ_FLAG_WAIT_EVENT_INT, + PS3_ERR_IJ_FLAG_WAIT_EVENT_PROC, + PS3_ERR_IJ_FLAG_WAIT_EVENT_SUBCRIBE, + PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_INT, + PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_PROC, + PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_SUBCRIBE, + PS3_ERR_IJ_STORE_NO_TRIGGER_LOG, + PS3_ERR_IJ_DETECT_NO_TRIGGER_LOG, + PS3_ERR_IJ_EVENT_CMD_NULL, + PS3_ERR_IJ_SUBC_EVENT_CMD_INIT, + PS3_ERR_IJ_RESUBC_EVENT_CMD_INIT, + PS3_ERR_IJ_CANCEL_EVENT_CMD_FAIL, + PS3_ERR_IJ_CANCEL_VDPENDING_CMD_FAIL, + PS3_ERR_IJ_R1X_ABORT, + PS3_ERR_IJ_TASK_RESET_DELAY, + PS3_ERR_IJ_SCSI_DELIVER_DELAY, + PS3_ERR_IJ_SCSI_DELIVER_DELAY_2, + PS3_ERR_IJ_FW_STATE_RUNNING, + PS3_ERR_IJ_SET_IOC_IN_SECURITY, + PS3_ERR_IJ_WAIT_UNNORMAL, + PS3_ERR_IJ_DUMP_WAIT_RECO_VALID, + PS3_ERR_IJ_DUMP_WAIT_RECO_VALID_2, + PS3_ERR_IJ_DUMP_WAIT_NORMAL, + PS3_ERR_IJ_WAIT_OPT, + PS3_ERR_IJ_WAIT_READY, + PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F1, + PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F0, + PS3_ERR_IJ_FWSTATE_REMOVE, + PS3_ERR_IJ_IOCTL_CMD_RETRY_DONE, + PS3_ERR_IJ_IOCTL_WAIT_UNNORMAL, + PS3_ERR_IJ_QOS_SET_SHARE_COUNT, + PS3_ERR_IJ_FORCE_EVENT_CMD_FAIL_DEAD, + PS3_ERR_IJ_IOCTL_WAIT_IRQ_DISABLE, + PS3_ERR_IJ_WAIT_IOCTL_IN_RECOVERY, + PS3_ERR_IJ_WAIT_IOCTL_IN_DEVICE_RESET, + PS3_ERR_IJ_SEND_IOCTL_BLOCK_MODE_FLAG, + PS3_ERR_IJ_FORCE_HAS_SCIS_PENDING_IO, + PS3_ERR_IJ_HOST_RESET_WAIT_DECIDE, + PS3_ERR_IJ_ABORT_PRE1_FORCE_ABORTED_CMD_DONE, + PS3_ERR_IJ_ABORT_PRE2_FORCE_ABORTED_CMD_DONE, + PS3_ERR_IJ_ABORT_PRE_BULID_FORCE_ABORTED_CMD_DONE, + PS3_ERR_IJ_ABORT_PRE_BULID1_FORCE_ABORTED_CMD_DONE, + PS3_ERR_IJ_ABORT_PRE_SEND_FORCE_ABORTED_CMD_DONE, + PS3_ERR_IJ_ABORT_PRE_DEAL_FORCE_ABORTED_CMD_DONE, + PS3_ERR_IJ_FORCE_STOP_ALL_CMD_DONE, + PS3_ERR_IJ_PROBE_HOST_RESET, + PS3_ERR_IJ_IOC_NOT_RUNNING, + PS3_ERR_IJ_IOC_IS_NOT_NORMAL_IN_UNLOAD, + PS3_ERR_IJ_HALF_HARD_RESET, + PS3_ERR_IJ_ROMOVE_UNLOAD_FAIL, + PS3_ERR_IJ_WAIT_TASK_MGR_BUSY, + PS3_ERR_IJ_RESET_TARGET_PAUSE, + PS3_ERR_IJ_SEND_CMD_TASK_MGR_BUSY, + PS3_ERR_IJ_UNLOAD_TIMEOUT, + PS3_ERR_IJ_ABORT_CMD_TIMEOUT, + PS3_ERR_IJ_RESET_CMD_TIMEOUT, + PS3_ERR_IJ_ABORT_CMD_ERROR, + PS3_ERR_IJ_RESET_CMD_ERROR, + PS3_ERR_IJ_ABORT_CMD_NORMAL, + PS3_ERR_IJ_RESET_CMD_NORMAL, + PS3_ERR_IJ_QOS_NOT_AWAKE_PD, + PS3_ERR_IJ_QOS_PD_RESEND_NOT_EXPIRED, + PS3_ERR_IJ_QOS_VD_MEMBER_CLEARING, + PS3_ERR_IJ_QOS_WAIT_VD_SEND, + PS3_ERR_IJ_SCSI_TASK_PRE_CHECK_FAILED, + PS3_ERR_IJ_TASK_CMD_ALLOC_FAILED, + PS3_ERR_IJ_SAS_REQ_PRE_CHECK, + PS3_ERR_IJ_SAS_RPHY_SLOT_GET_FAILED, + PS3_ERR_IJ_SAS_ENCL_ID_GET_FAILED, + PS3_ERR_IJ_MGR_CMD_ALLOC_FAILED, + PS3_ERR_IJ_CMD_POLLING, + PS3_ERR_IJ_PCI_ERR_RECOVERY, + PS3_ERR_IJ_SMP_CMD_TIMEOUT, + PS3_ERR_IJ_SMP_CMD_ERROR, + PS3_ERR_IJ_GET_LINKERRORS_CMD_ERROR, + PS3_ERR_IJ_PHY_CTRL_CMD_ERROR, + PS3_ERR_IJ_SAS_EXP_RPHY_SLOT_GET_FAILED, + PS3_ERR_IJ_INS_STATE_UNNORMAL, + PS3_ERR_IJ_INS_STATE_DEAD, + PS3_ERR_IJ_RPHY_PARENT_SAS_ADDR_GET_FAILED, + PS3_ERR_IJ_SAS_NODE_NOT_FOUND, + PS3_ERR_IJ_SAS_REQ_EXT_BUF_INVALLID, + PS3_ERR_IJ_EXT_BUF_TO_RSP_INVALLID, + PS3_ERR_IJ_WAIT_CMD_DONE, + PS3_ERR_IJ_CMD_SEND_BLOCK, + PS3_ERR_IJ_FORCE_TASK_MGR_BUSY, + PS3_ERR_IJ_FORCE_INS_UNLOAD, + PS3_ERR_IJ_FORCE_INSTANCE_UNNORMAL, + PS3_ERR_IJ_QOS_PD_INIT_FAIL_1, + PS3_ERR_IJ_QOS_PD_INIT_FAIL_2, + PS3_ERR_IJ_QOS_PD_INIT_FAIL_3, + PS3_ERR_IJ_QOS_PD_INIT_FAIL_4, + PS3_ERR_IJ_QOS_TAG_INIT_FAIL_1, + PS3_ERR_IJ_QOS_TAG_INIT_FAIL_2, + PS3_ERR_IJ_QOS_VD_INIT_FAIL_1, + PS3_ERR_IJ_QOS_VD_INIT_FAIL_2, + PS3_ERR_IJ_QOS_VD_INIT_FAIL_3, + PS3_ERR_IJ_QOS_WAIT_PD_WAITQ_CLEAR, + PS3_ERR_IJ_QOS_WAIT_PD_WAITQ_CLEAR_2, + PS3_ERR_IJ_QOS_WAIT_VD_WAITQ_CLEAR, + PS3_ERR_IJ_QOS_WAIT_TAG_WAITQ_CLEAR, + PS3_ERR_IJ_QOS_NOT_AWAKE_TAG, + PS3_ERR_IJ_CMD_SEND_FORCE_INS_UNLOAD, + PS3_ERR_IJ_CMD_SEND_FORCE_UNORMAL, + PS3_ERR_IJ_CMD_SEND_FORCE_PCI_ERR, + PS3_ERR_IJ_QOS_FORCE_VD_SEQ_CHANGE, + PS3_ERR_IJ_QOS_FORCE_MGRQ_ZERO_DEPTH, + PS3_ERR_IJ_QOS_FORCE_CMDQ_ZERO_DEPTH, + PS3_ERR_IJ_QOS_MGRQ_INIT_FAIL_1, + PS3_ERR_IJ_QOS_MGRQ_INIT_FAIL_2, + PS3_ERR_IJ_QOS_CMDQ_INIT_FAIL_1, + PS3_ERR_IJ_QOS_CMDQ_INIT_FAIL_2, + PS3_ERR_IJ_QOS_WAIT_SOFT_WAITQ_CLEAR, + PS3_ERR_IJ_BLOCK_HOST_RESET, + PS3_ERR_IJ_R1X_CONFLICTQ_PROCESS_FINISH, + PS3_ERR_IJ_RECOVERY_WAIT_FUNC0_RUNNING_1, + PS3_ERR_IJ_RECOVERY_WAIT_FUNC0_RUNNING_2, + PS3_ERR_IJ_WAIT_HARD_RESET, + PS3_ERR_IJ_FORCE_IOC_RUNNING, + PS3_ERR_IJ_FORCE_INIT_FAIL, + PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL, + PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL2, + PS3_ERR_IJ_FORCE_F1_LOAD_START_HARD, + PS3_ERR_IJ_FORCE_F1_LOAD_ENTER_HARD, + PS3_ERR_IJ_FORCE_F1_HOST_START_HARD, + PS3_ERR_IJ_FORCE_F1_SCAN_START_HARD, + PS3_ERR_IJ_FORCE_F1_A_SCAN_START_HARD, + PS3_ERR_IJ_FORCE_F1_A_SCAN_FINISH_HARD, + PS3_ERR_IJ_F1_PROBE_FORCE_IOC_FAULT, + PS3_ERR_IJ_RECOVERY_WAIT_FUNC1_PROBE, + PS3_ERR_IJ_RECOVERY_WAIT_FUNC1_REMOVE, + PS3_ERR_IJ_RECOVERY_F1_B_READY, + PS3_ERR_IJ_RECOVERY_F1_A_READY, + PS3_ERR_IJ_RECOVERY_F1_B_INIT, + PS3_ERR_IJ_RECOVERY_F1_A_INIT, + PS3_ERR_IJ_RECOVERY_F1_RUNNING, + PS3_ERR_IJ_RECOVERY_F1_CTRL_INFO, + PS3_ERR_IJ_RECOVERY_F1_OPER, + PS3_ERR_IJ_RECOVERY_F1_SCSI_INIT, + PS3_ERR_IJ_RECOVERY_F1_LOAD, + PS3_ERR_IJ_RECOVERY_F1_B_SCAN, + PS3_ERR_IJ_RECOVERY_F1_A_SCAN, + PS3_ERR_IJ_RECOVERY_F1_SCAN_FINISH, + PS3_ERR_IJ_RECOVERY_F1_EVENT, + PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_PROBE, + PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_REMOVE, + PS3_ERR_IJ_FORCE_IOC_RUNNING_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_INIT_FAIL_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL2_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_F1_LOAD_START_HARD_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_F1_HOST_START_HARD_RESUME_RECOVERY, + PS3_ERR_IJ_F1_PROBE_FORCE_IOC_FAULT_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_F1_SCAN_START_HARD_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_F1_A_SCAN_START_HARD_RESUME_RECOVERY, + PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_NOT_RUNNING, + PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_EVENT_FAIL, + PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_VDINFO_FAIL, + PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_WEB_FAIL, + PS3_ERR_IJ_FORCE_F1_REMOVE_IOC_UNLOAD_FAIL, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_CANCEL_EVENT_WORK_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_EVENT_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_VDINFO_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_WEB_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_REQ_IOC_UNLOAD_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_CANCEL_EVENT_WORK_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_EVENT_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_VDINFO_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_WEB_FAIL_RESUME, + PS3_ERR_IJ_FORCE_F1_REMOVE_RECOVERY_IOC_UNLOAD_FAIL_RESUME, + PS3_ERR_IJ_WAIT_SCSI_CMD_DONE_FAIL, + PS3_ERR_IJ_INIT_CMD_PROC_FAIL, + PS3_ERR_IJ_IOC_STATE_WAIT_TO_RUNNING_FAIL, + PS3_ERR_IJ_IOC_INIT_PROC_STATE_RUNNING, + PS3_ERR_IJ_INIT_PROC_FAIL_UNLOAD_IOC_RUN, + PS3_ERR_IJ_INIT_PROC_FAIL_NOUNLOAD, + PS3_ERR_IJ_GET_PD_INFO_RETURN_FAILED, + PS3_ERR_IJ_FORCE_MEMDUP_USER_RETURN_FAILED, + PS3_ERR_IJ_FORCE_IOCTL_WAIT_NORMAL_FAILED, + PS3_ERR_IJ_FORCE_IOCTL_ALLOC_CMD_FAILED, + PS3_ERR_IJ_WAIT_CMD_FREE, + PS3_ERR_IJ_WAIT_ABORT_FLAG, + PS3_ERR_IJ_WAIT_CMD_ALLOC, + PS3_ERR_IJ_SET_CMD_TID_FLAG, + PS3_ERR_IJ_WAIT_CMD_FREE1, + PS3_ERR_IJ_WAIT_ABORT_FLAG1, + PS3_ERR_IJ_SET_ABORT_COUNT, + PS3_ERR_IJ_WAIT_CMD_ALLOC1, + PS3_ERR_IJ_WAIT_CMD_ALLOC2, + PS3_ERR_IJ_FORCE_ALLOC_DMA_BUF_FAILED, + PS3_ERR_IJ_FORCE_PCIE_ERR_PCI_INIT_FAILED, + PS3_ERR_IJ_FORCE_PCIE_ERR_PCI_INIT_COMP_FAILED, + PS3_ERR_IJ_FORCE_PCIE_ERR_RES_ONLINE_FAILED, + PS3_ERR_IJ_PCI_FORCE_HARD_RECOVERY_REQ_FAILED, + PS3_ERR_IJ_PCI_FORCE_WAIT_OPERARIONAL_FAILED, + PS3_ERR_IJ_FORCE_PCIE_ERR_IOC_RUNNING_INIT_FAILED, + PS3_ERR_IJ_FORCE_STREAM_DETECT_TRUE, + PS3_ERR_IJ_FORCE_SEQ_CMD, + PS3_ERR_IJ_FORCE_RAND_CMD, + PS3_ERR_IJ_FORCE_RET_FAIL1, + PS3_ERR_IJ_FORCE_VD_COUNT_ERR, + PS3_ERR_IJ_FORCE_MOD_CHAN, + PS3_ERR_IJ_FORCE_MOD_CHAN1, + PS3_ERR_IJ_FORCE_MOD_TARGET, + PS3_ERR_IJ_FORCE_MOD_DISKPOS, + PS3_ERR_IJ_FORCE_RET_FAIL2, + PS3_ERR_IJ_FORCE_LUN_ERROR, + PS3_ERR_IJ_FORCE_INSTANCE_NULL, + PS3_ERR_IJ_FORCE_VD_ENTRY_NULL, + PS3_ERR_IJ_FORCE_VD_ENTRY_NULL1, + PS3_ERR_IJ_FORCE_PRIV_DATA_NULL, + PS3_ERR_IJ_FORCE_RB_INFO_NULL, + PS3_ERR_IJ_FORCE_HASH_MGR_NULL, + PS3_ERR_IJ_FORCE_MGR_CONFLICT_NULL, + PS3_ERR_IJ_FORCE_SEND_TH_NULL, + PS3_ERR_IJ_FORCE_RET_FAIL3, + PS3_ERR_IJ_FORCE_INSTANCE_NULL1, + PS3_ERR_IJ_FORCE_PRIV_DATA_NULL1, + PS3_ERR_IJ_FORCE_MOD_DEV_TYPE, + PS3_ERR_IJ_FORCE_VD_ENTRY_NULL2, + PS3_ERR_IJ_FORCE_RET_FAIL4, + PS3_ERR_IJ_FORCE_INSTANCE_NULL2, + PS3_ERR_IJ_FORCE_RET_FAIL5, + PS3_ERR_IJ_FORCE_RET_FAIL6, + PS3_ERR_IJ_FORCE_MOD_DISKPOS1, + PS3_ERR_IJ_FORCE_MOD_ALIGN, + PS3_ERR_IJ_FORCE_MOD_ALIGN1, + PS3_ERR_IJ_FORCE_MOD_CHAN2, + PS3_ERR_IJ_FORCE_MOD_DISKID, + PS3_ERR_IJ_FORCE_MOD_CHAN3, + PS3_ERR_IJ_FORCE_MOD_DISKPOS2, + PS3_ERR_IJ_FORCE_PD_ENTRY_NULL, + PS3_ERR_IJ_FORCE_PD_ENTRY_NULL1, + PS3_ERR_IJ_FORCE_PD_STATE_ERROR, + PS3_ERR_IJ_FORCE_PRIV_DATA_NULL2, + PS3_ERR_IJ_FORCE_PD_ENTRY_NULL2, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_0, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_1, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_2, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_3, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_4, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_5, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_6, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_7, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_8, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_9, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_10, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_11, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_12, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_13, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_14, + PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_15, + PS3_ERR_IJ_FORCE_RET_FAIL7, + PS3_ERR_IJ_FORCE_RET_FAIL8, + PS3_ERR_IJ_FORCE_RECOVERY_DOORBELL_FAILED, + PS3_ERR_IJ_FORCE_DEBUG_INIT_FAIL, + PS3_ERR_IJ_FORCE_TRANSPORT_INIT_FAIL, + PS3_ERR_IJ_FORCE_CHARDEV_INIT_FAIL, + PS3_ERR_IJ_FORCE_PCIDRV_INIT_FAIL, + PS3_ERR_IJ_FORCE_VERFILE_INIT_FAIL, + PS3_ERR_IJ_FORCE_VERFILE2_INIT_FAIL, + PS3_ERR_IJ_FORCE_RECOVERY_INIT_FAIL, + PS3_ERR_IJ_FORCE_RECOVERY_OPE_FAIL, + PS3_ERR_IJ_IO_RW_FLAG_SET_UNKOWN, + PS3_ERR_IJ_SOFT_ZONE_TYPE_SET_UNKOWN, + PS3_ERR_IJ_WATCHDOG_WAIT_RUNNING, + PS3_ERR_IJ_WATCHDOG_IRQ_QUEUE, + PS3_ERR_IJ_WATCHDOG_IRQ_QUEUE_1, + PS3_ERR_IJ_READ_FW_STATE_REG_FF, + PS3_ERR_IJ_SET_HIGH_IOPS_CHANNEL_IN_QOS, + PS3_ERR_IJ_FORCE_F0_WATCHDOG_START_HARD, + PS3_ERR_IJ_ADD_DISK_HOST_RESET, + PS3_ERR_IJ_PCIE_FROZEN, + PS3_ERR_IJ_PEER_PCIE_FROZEN, + PS3_ERR_IJ_ASYNC_HARDRESET_PROBE, + PS3_ERR_IJ_ASYNC_HARDRESET_REMOVE, + PS3_ERR_IJ_WAIT_SUSPEND_WAIT_RECOVERY, + PS3_ERR_IJ_WAIT_SUSPEND_WAIT_RECOVERY_1, + PS3_ERR_IJ_MOD_SO_ADDR, + PS3_ERR_IJ_SHUTDOWN_HARDRESET, + PS3_ERR_IJ_CANCEL_WEB_CMD_ALLOC_NULL, + PS3_ERR_IJ_GET_REPLYQ_COUNT_INVALID, + PS3_ERR_IJ_GET_MSIX_VEC_COUNT_INVALID, + PS3_ERR_IJ_GET_MSI_VEC_COUNT_INVALID, + PS3_ERR_IJ_GET_MAX_CMD_COUNT_INVALID, + PS3_ERR_IJ_ALLOC_LEGACY_VECTOR_FAILED, + PS3_ERR_IJ_CPU_MSIX_TABLE_ALLOC_FAILED, + PS3_ERR_IJ_REPLY_FIFO_DESC_BUF_POOL_ALLOC_FAILED, + PS3_ERR_IJ_REPLY_FIFO_DESC_BUF_ALLOC_FAILED, + PS3_ERR_IJ_REPLY_FIFO_POOL_ALLOC_FAILED, + PS3_ERR_IJ_REPLY_VIRT_BASE_ALLOC_FAILED, + PS3_ERR_IJ_IRQS_ALLOC_FAILED, + PS3_ERR_IJ_REPLY_REQ_IRQS_FAILED, + PS3_ERR_IJ_DUMP_REQ_IRQS_FAILED, + PS3_ERR_IJ_IRQ_VECTORS_ALLOC_FAILED, + PS3_ERR_IJ_SAS_PHY_GET_ERR, + PS3_ERR_IJ_SAS_PORT_ALLOC_NULL, + PS3_ERR_IJ_SAS_ALLOC_NUM_NULL, + PS3_ERR_IJ_SAS_PORT_ADD_FAILED, + PS3_ERR_IJ_SAS_ALLOC_PHY_NULL, + PS3_ERR_IJ_SAS_PHY_ADD_FAILED, + PS3_ERR_IJ_SAS_ADD_ACK_FAILED, + PS3_ERR_IJ_ALLOC_EXP_NODE_NULL, + PS3_ERR_IJ_ALLOC_EXP_PHYS_NULL, + PS3_ERR_IJ_SAS_PORT_ALLOC_NULL1, + PS3_ERR_IJ_SAS_PHY_GET_ERR1, + PS3_ERR_IJ_SAS_ALLOC_PHY_NULL1, + PS3_ERR_IJ_SAS_PHY_ADD_FAILED1, + PS3_ERR_IJ_READ_ATU_REG_FAILED, + PS3_ERR_IJ_IOC_TO_READY_FAILED, + PS3_ERR_IJ_BIT_POS_ERR, + PS3_ERR_RECOVERY_CONTEXT_ALLOC_FAILED, + PS3_ERR_IJ_FORCE_ALLOC_CANCEL_CMD_FAILED, + PS3_ERR_IJ_FORCE_CANCEL_CMD_RET_RECOVERY, + PS3_ERR_IJ_FORCE_CANCEL_CMD_PCIE_ERR, + PS3_ERR_IJ_WAIT_RESUME_WAIT_RECOVERY, + PS3_ERR_IJ_FORCE_STREAM_DETECT_FALSE, + PS3_ERR_IJ_PS3_INIT_FRAME_SYS_INFO_BUF_ALLOC, + PS3_ERR_IJ_PS3_CMD_BUF_ALLOC, + PS3_ERR_IJ_PS3_PS3_CMD_ALLOC, + PS3_ERR_IJ_PS3_REQ_FRAME_BUF_ALLOC, + PS3_ERR_IJ_PS3_RESP_FRAME_BUF_ALLOC, + PS3_ERR_IJ_PS3_EXT_BUF_ALLOC, + PS3_ERR_IJ_PS3_MGR_EXT_BUF_ALLOC, + PS3_ERR_IJ_PS3_R1XLOCK_BUF_ALLOC, + PS3_ERR_IJ_PS3_IOCTL_TRANSIENT_ALLOC, + PS3_ERR_IJ_PS3_PERCPU_ALLOC, + PS3_ERR_IJ_PS3_DELAY_WORK_POOL_ALLOC, + PS3_ERR_IJ_PS3_CMD_STAT_BUF_ALLOC1, + PS3_ERR_IJ_PS3_CMD_STAT_BUF_ALLOC2, + PS3_ERR_IJ_PS3_CMD_STAT_BACKUP_BUF_ALLOC1, + PS3_ERR_IJ_PS3_CMD_STAT_BACKUP_BUF_ALLOC2, + PS3_ERR_IJ_PS3_CMD_LAST_STAT_BUF_ALLOC1, + PS3_ERR_IJ_PS3_CMD_LAST_STAT_BUF_ALLOC2, + PS3_ERR_IJ_PS3_DEBUG_MEM_BUF_ALLOC, + PS3_ERR_IJ_PS3_DEBUG_MEM_ADDR_ALLOC, + PS3_ERR_IJ_PS3_DRV_INFO_BUF_ALLOC, + PS3_ERR_IJ_PS3_HOST_MEM_BUF_ALLOC, + PS3_ERR_IJ_PS3_PD_LIST_BUF_ALLOC, + PS3_ERR_IJ_PS3_PD_INFO_BUF_ALLOC, + PS3_ERR_IJ_PS3_VD_LIST_BUF_ALLOC, + PS3_ERR_IJ_PS3_VD_INFO_BUF_SYNC_ALLOC, + PS3_ERR_IJ_PS3_VD_INFO_BUF_ASYNC_ALLOC, + PS3_ERR_IJ_PS3_VD_IDX_ARRAY_ALLOC, + PS3_ERR_IJ_PS3_VD_ENTRIES_ARRAY_ALLOC, + PS3_ERR_IJ_PS3_VD_DEVS_BUF_ALLOC, + PS3_ERR_IJ_PS3_VD_PRI_DATA_IDXS_ARRAY_ALLOC, + PS3_ERR_IJ_PS3_PD_ENTRIES_ARRAY_ALLOC, + PS3_ERR_IJ_PS3_PD_IDX_ARRAY_ALLOC, + PS3_ERR_IJ_PS3_PD_DEVS_BUF_ALLOC, + PS3_ERR_IJ_PS3_SAS_BUF_ALLOC, + PS3_ERR_IJ_PS3_SAS_PHY_BUF_ALLOC, + PS3_ERR_IJ_PS3_VD_PENDING_CMD_ALLOC, + PS3_ERR_IJ_FORCE_PCI_EN_MEM_FAILED, + PS3_ERR_IJ_FORCE_PCI_RES_FLAGS_FAILED, + PS3_ERR_IJ_FORCE_PCI_REQ_REGION_FAILED, + PS3_ERR_IJ_FORCE_PCI_IOREMAP_FAILED, + PS3_ERR_IJ_ADD_INSTANCE_WAIT, + PS3_ERR_IJ_REMOVE_INSTANCE_WAIT, + PS3_ERR_IJ_ADD_INSTANCE, + PS3_ERR_IJ_REMOVE_INSTANCE, + PS3_ERR_IJ_FORCE_DUL_RECOVERY, + PS3_ERR_IJ_FORCE_START_DUL_RECOVERY, + PS3_ERR_IJ_FORCE_DUL_RECOVERY_PENDING, + PS3_ERR_IJ_FORCE_DESTORY_RECOVERY, + PS3_ERR_IJ_FORCE_START_DESTORY_RECOVERY, + PS3_ERR_IJ_FORCE_RECOVERY_STATE_DEAD, + PS3_ERR_IJ_FORCE_RECOVERY_PEER_STATE_DEAD, + PS3_ERR_IJ_FORCE_RECOVERY_NOT_SUPPORT, + PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL, + PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_PEER_DEAD_FAIL, + PS3_ERR_IJ_FORCE_RECOVERY_REG_FAILED, + PS3_ERR_IJ_FORCE_RECOVERY_PEER_COMPLETE_FAILED, + PS3_ERR_IJ_WAIT_HARDRESET, + PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, + PS3_ERR_IJ_PD_LIST_WAIT_IRQ_DISABLE, + PS3_ERR_IJ_PD_LIST_CMD_NO_RESP, + PS3_ERR_IJ_PD_LIST_RESP_RETRY, + PS3_ERR_IJ_FORCE_ENTRY_NULL, + PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL1, + PS3_ERR_IJ_FORCE_RECOVERY_ALLOC_FAIL, + PS3_ERR_IJ_FORCE_RECOVERY_DECIDE_PEER_INSTANCE_FAIL, + PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PCIE_ERR, + PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PEER_PCIE_ERR, + PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_IOC_HALT, + PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PEER_IOC_HALT, + PS3_ERR_IJ_FORCE_IOC_RUNNING_PCI_ERR, + PS3_ERR_IJ_FORCE_VDINFO_SUB_FAIL, + PS3_ERR_IJ_FORCE_WEB_SUB_FAIL, + PS3_ERR_IJ_WAIT_RUNNING_FAIL, + PS3_ERR_IJ_WEB_SUBSCRIBE, + PS3_ERR_IJ_FORCE_RECOVERY_FINISH_STATE_NOOPERATIONAL, + PS3_ERR_IJ_FORCE_HARD_INIT_RUNING_UNNORMAL, + PS3_ERR_IJ_FORCE_HARD_READY_PCIE_ERRL, + PS3_ERR_IJ_WAIT_RUNNING_FAIL1, + PS3_ERR_DUMP_ALLOC_FAILED, + PS3_ERR_IJ_DUMP_WORK_FAILED, + PS3_ERR_IJ_FEATURE_SUPPORT_ERR, + PS3_ERR_IJ_DUMP_STATUS_ERR, + PS3_ERR_IJ_DUMP_TYPE_INVALID, + PS3_ERR_IJ_DUMP_PCIE_ERR, + PS3_ERR_IJ_DUMP_RECOVERY_ERR, + PS3_ERR_IJ_DUMP_TYPE_ILLEGAL, + PS3_ERR_IJ_DUMP_WORK_QUEUE_NULL, + PS3_ERR_IJ_DUMP_STATE_ILLEGAL, + PS3_ERR_IJ_DUMP_TRIGGER_FAIL, + PS3_ERR_IJ_DUMP_DUMP_STATE_GET_FAIL, + PS3_ERR_IJ_DUMP_DUMP_STATE_INVALID, + PS3_ERR_IJ_DUMP_FILE_OPEN_FAIL, + PS3_ERR_IJ_DUMP_DATA_SIZE_FAIL, + PS3_ERR_IJ_DUMP_WRITE_FAIL, + PS3_ERR_IJ_DUMP_ABORT_GET_CTRL_FAIL, + PS3_ERR_IJ_DUMP_END_GET_CTRL_FAIL, + PS3_ERR_IJ_DUMP_TRIGGER_GET_CTRL_FAIL, + PS3_ERR_IJ_DUMP_DATA_COPY_GET_CTRL_FAIL, + PS3_ERR_IJ_DUMP_IS_TRIGGER_GET_CTRL_FAIL, + PS3_ERR_IJ_DUMP_CTRL_ERR, + PS3_ERR_IJ_WAIT_PM_INSTANCE_NULL, + PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET, + PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET_1, + PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED, + PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED_1, + PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED_2, + PS3_ERR_IJ_WAIT_SUSPEND_VD_PENDING_FAILED, + PS3_ERR_IJ_WAIT_RESUME_EVENT_FAILED, + PS3_ERR_IJ_WAIT_SUSPEND_HALT_RESET_2, + PS3_ERR_IJ_WAIT_RESUME_FUNCID_INVALID, + PS3_ERR_FORCE_SET_CMD_INDEX_NOT_MGR, + PS3_ERR_EXP_ID_ERR, + PS3_ERR_HBA_PHY_COUNT_ZERO, + PS3_ERR_IJ_IOC_TO_READY_FAILED1, + PS3_ERR_IJ_REG_READ_ZERO, + PS3_ERR_IJ_REG_READ_ERR, + PS3_ERR_IJ_QOS_FORCE_TFIFO_ZERO_DEPTH, + PS3_ERR_IJ_FEATURE_REG_READ_ERR, + PS3_ERR_IJ_IOC_TO_CRITICAL, + PS3_ERR_IJ_CHANGE_FW_TO_HALT_IN_PREPARE, + PS3_ERR_IJ_GET_PRIV_DATA_DELAY, + PS3_ERR_IJ_DEL_DEV_WAIT_OS_PRIV_DATA, + PS3_ERR_IJ_ADD_DEV_WAIT_OS_PRIV_DATA, + PS3_ERR_IJ_FORCE_WAIT, + PS3_ERR_IJ_PD_ATTR_WAIT_OS_SCAN, + PS3_ERR_IJ_OS_SCAN, + PS3_ERR_IJ_PD_ATTR_WAIT_PD_ATTR, + PS3_ERR_IJ_PD_ATTR, + PS3_ERR_IJ_CMD_BLOCK_BEFORE_SEND_TO_IOC, + PS3_ERR_IJ_SGL_ADDR_PAGE_MODE_5, + PS3_ERR_IJ_SGL_ADDR_RESTORE, + PS3_ERR_IJ_FORCE_IOCTL_WAIT_RECOVERY, + PS3_ERR_IJ_FORCE_WAIT_CLI_CMD, + PS3_ERR_IJ_WDT_WAIT_REC_REQ, + PS3_ERR_IJ_WDT_WAIT_REC_REQ_2, + PS3_ERR_IJ_WDT_WAIT_REC_REQ_3, + PS3_ERR_IJ_WDT_WAIT_REC_REQ_4, + PS3_ERR_IJ_RECOVERY_BLOCK_BEFORE_RUNNING, + PS3_ERR_IJ_CMD_SEND_WAIT_RECOVERY_END, + PS3_ERR_IJ_CMD_SEND_INSTANCE_RECOVERY, + PS3_ERR_IJ_CMD_BLOCK_BEFORE_DELIVER_CNT, + PS3_ERR_IJ_V2_IS_LOAD_FALSE, + PS3_ERR_IJ_V2_PCIE_ERR, + PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_UNORMAL, + PS3_ERR_IJ_V2_WAKE_RECOVERY_WAIT, + PS3_ERR_IJ_V2_RECOVERY_WAIT_NOTIFY, + PS3_ERR_IJ_V2_FORCE_INSTANCE_STATE_NORMAL, + PS3_ERR_IJ_V2_FORCE_INS_STATE_UNNORMAL, + PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_NORMAL, + PS3_ERR_IJ_V2_FORCE_INS_DEAD, + PS3_ERR_IJ_V2_IS_LOAD_FALSE1, + PS3_ERR_IJ_V2_FORCE_INS_DEAD1, + PS3_ERR_IJ_ABORT_BLOCK1, + PS3_ERR_IJ_ABORT_BLOCK2, + PS3_ERR_IJ_SAS_PORT_CREATE_FAIL, + PS3_ERR_IJ_MAX_COUNT, +}InjectType_E; +struct ps3_rec_work_context { + struct delayed_work _work; + struct workqueue_struct *_queue; + struct ps3_instance *instance; + U32 state; +}; + +#ifdef PS3_SUPPORT_INJECT + +#define PS3_ERR_SCENE_NUM (1000) + +typedef S32 (*injectCallback)(void* userData, ...); + +typedef struct Ps3Injection +{ + InjectType_E type; + injectCallback callback; + Bool active; + U16 count; + U8 is_hit_pre:1; + U8 is_hit_post:1; + U8 reserved:6; +}Ps3Injection_t; + +void inject_register(U16 err_type, injectCallback callback); +void inject_active_intf(U16 err_type, U16 count); +void inject_execute_callback(U16 err_type, void * data); +void inject_execute_callback_at_time(U16 err_type, void * data); +void inject_execute_callback_relevance_wait_pre(U16 err_type, U16 err_type_wait, void * data); +void inject_execute_callback_relevance_wait_post(U16 err_type, U16 err_type_wait, void * data); +void inject_execute_callback_at_time_relevance_wait_pre(U16 err_type, + U16 err_type_wait, void * data); +void inject_execute_callback_at_time_relevance_wait_post(U16 err_type, + U16 err_type_wait, void * data); + +#define INJECT_REG(type, callback) inject_register(type, (injectCallback)callback); +#define INJECT_ACTIVE(type, count) inject_active_intf(type, count); +#define INJECT_START(type, data) inject_execute_callback(type, data); +#define INJECT_AT_TIMES(type, data) inject_execute_callback_at_time(type, data); +#define INJECT_START_WAIT_REV_PRE(type, type_wait, data) \ + inject_execute_callback_relevance_wait_pre(type, type_wait, data); +#define INJECT_START_WAIT_REV_POST(type, type_wait, data) \ + inject_execute_callback_relevance_wait_post(type, type_wait, data); +#define INJECT_START_AT_TIME_WAIT_REV_PRE(type, type_wait, data) \ + inject_execute_callback_at_time_relevance_wait_pre(type, type_wait, data); +#define INJECT_START_AT_TIME_WAIT_REV_POST(type, type_wait, data) \ + inject_execute_callback_at_time_relevance_wait_post(type, type_wait, data); + + + +#define PS3_IJ_SLEEP(ms, err_t) do {ps3_err_inject_sleep((ms), (err_t));} while(0) +#define PS3_IJ_SLEEP_RAND(min, max, err_t) do {ps3_err_inject_sleep_rand((min), (max), (err_t));} while(0) + +void ps3_err_inject_sleep(U32 ms, U16 err_type); + +void ps3_err_inject_sleep_rand(U32 min, U32 max, U16 err_type); + +void ps3_err_inject_err_type_valid(U16 err_type); + +void ps3_err_inject_err_type_clean(U16 err_type); + +Bool ps3_err_inject_err_type_get(U16 err_type); +void active_err_inject(void); +void ps3_wait_recovery_rand_finish(void); + +void ps3_err_inject_wait_pre(U16 err_type_wait); +void ps3_err_inject_wait_post(U16 err_type_wait); + +#define INJECT_PROBE_ACTIVE() active_err_inject(); +void inject_init(void); +void inject_exit(void); + +#define INJECT_INIT() inject_init(); +#define INJECT_EXIT() inject_exit(); + +#else + +#define PS3_IJ_SLEEP(ms, err_t) +#define PS3_IJ_SLEEP_RAND(min, max, err_t) +#define INJECT_REG(type, callback) +#define INJECT_ACTIVE(type, count) +#define INJECT_START(type, data) +#define INJECT_AT_TIMES(type, data) +#define INJECT_START_WAIT_REV_PRE(type, type_wait, data) +#define INJECT_START_WAIT_REV_POST(type, type_wait, data) +#define INJECT_START_AT_TIME_WAIT_REV_PRE(type, type_wait, data) +#define INJECT_START_AT_TIME_WAIT_REV_POST(type, type_wait, data) + +#define INJECT_INIT() +#define INJECT_EXIT() +#define INJECT_PROBE_ACTIVE() +#endif + +#endif diff --git a/drivers/scsi/ps3stor/ps3_event.c b/drivers/scsi/ps3stor/ps3_event.c new file mode 100644 index 0000000000000000000000000000000000000000..820f94ec5b753f0f99928712819c402a9bc7776f --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_event.c @@ -0,0 +1,1257 @@ +#include "ps3_event.h" +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include +#else + +#endif +#include "ps3_platform_utils.h" +#include "ps3_instance_manager.h" +#include "ps3_inner_data.h" +#include "ps3_htp_event.h" +#include "ps3_mgr_cmd.h" +#include "ps3_htp.h" +#include "ps3_device_update.h" +#include "ps3_util.h" +#include "ps3_cmd_statistics.h" +#include "ps3_err_inject.h" +U16 ps3_event_code_pd_count[] = { + PS3_EVT_CODE(MGR_EVT_DEVM_DISK_IN), + PS3_EVT_CODE(MGR_EVT_DEVM_DISK_OUT), + PS3_EVT_CODE(MGR_EVT_MULITPILE_PD_IN), + PS3_EVT_CODE(MGR_EVT_MULITPILE_PD_OUT), + PS3_EVT_CODE(MGR_EVT_DEVM_JBOD), + PS3_EVT_CODE(MGR_EVT_DEVM_READY), + PS3_EVT_CODE(MGR_EVT_MULITPILE_JBOD), + PS3_EVT_CODE(MGR_EVT_MULITPILE_READY), + PS3_EVT_CODE(MGR_EVT_BACKPLANE_ON), + PS3_EVT_CODE(MGR_EVT_BACKPLANE_OFF), + PS3_EVT_CODE(MGR_EVT_DEVM_DISK_CHANGE), + PS3_EVT_CODE(MGR_EVT_MULITPILE_PD_STATE_CHANGE), + PS3_EVT_CODE(MGR_EVT_PD_PRE_READY) +}; + +U16 ps3_event_code_pd_attr[] = { + PS3_EVT_CODE(MGR_EVT_PD_INFO_CHANGE), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_READY), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_ONLINE), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_FAILED), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_REBUILD), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_REPLACE), + PS3_EVT_CODE(MGR_EVT_PD_R_GLOBAL_SPARE_ADDED), + PS3_EVT_CODE(MGR_EVT_PD_R_GLOBAL_SPARE_DELETED), + PS3_EVT_CODE(MGR_EVT_PD_R_DEDICATED_SPARE_ADDED), + PS3_EVT_CODE(MGR_EVT_PD_R_DEDICATED_SPARE_DELETED), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_UNCONFIGUREDBAD), + PS3_EVT_CODE(MGR_EVT_PD_MARKED_OFFLINE) +}; + +U16 ps3_event_code_vd_attr[] = { + PS3_EVT_CODE(MGR_EVT_VD_SETTINGS_CHANGE), + PS3_EVT_CODE(MGR_EVT_VD_PD_CHANGE), + PS3_EVT_CODE(MGR_EVT_VD_STATE_CHANGE), + PS3_EVT_CODE(MGR_EVT_VD_ALTER_ATTR_BY_MIGRATION), + PS3_EVT_CODE(MGR_EVT_VD_EXPAND_FINISH) +}; + +struct ps3_event_type_desc_map { + MgrEvtType_e event_type; + const char *event_type_desc; +}; + +static struct ps3_event_type_desc_map g_event_type_desc_table[] = { + {PS3_EVT_PD_COUNT, "PS3_EVT_PD_COUNT"}, + {PS3_EVT_VD_COUNT, "PS3_EVT_VD_COUNT"}, + {PS3_EVT_CTRL_INFO, "PS3_EVT_CTRL_INFO"}, + {PS3_EVT_PD_ATTR, "PS3_EVT_PD_ATTR"}, + {PS3_EVT_VD_ATTR, "PS3_EVT_VD_ATTRs"}, + {PS3_EVT_SAS_INFO, "PS3_EVT_SAS_INFO"}, + {PS3_EVT_DG_INFO, "MGR_EVT_DG_DELETED"}, +}; + +static struct fasync_struct *g_async_queue; + +static void ps3_event_print_cmd(struct ps3_cmd *cmd, Bool is_send) +{ + LOG_INFO("trace_id[0x%llx], hno:%u event[%s] print cmd word type[%d]," + "direct[%d], qmask[0x%x], CFID[%d], isr_sn[%d], vid[%d], pid[%d]\n", + cmd->trace_id, PS3_HOST(cmd->instance), (is_send) ? "send" : "recv", + cmd->cmd_word.type, cmd->cmd_word.direct, + cmd->cmd_word.qMask, cmd->cmd_word.cmdFrameID, + cmd->cmd_word.isrSN, cmd->cmd_word.virtDiskID, + cmd->cmd_word.phyDiskID); +} + +void ps3_vd_pending_filter_table_build(U8 *data) +{ + PS3EventFilter_s *event_filter = (PS3EventFilter_s*)data; + memset(event_filter, 0, sizeof(PS3EventFilter_s)); + + event_filter->eventType = PS3_EVT_VD_ATTR_LOCAL; + event_filter->eventCodeCnt = ARRAY_SIZE(ps3_event_code_vd_attr); + + data += sizeof(PS3EventFilter_s); + memcpy(data, ps3_event_code_vd_attr, sizeof(ps3_event_code_vd_attr)); +} + +void ps3_event_filter_table_get_raid(U8 *data) +{ + PS3EventFilter_s event_filter; + memset(&event_filter, 0, sizeof(PS3EventFilter_s)); + + event_filter.eventType = PS3_EVT_PD_COUNT_LOCAL; + event_filter.eventCodeCnt = ARRAY_SIZE(ps3_event_code_pd_count); + memcpy(data, &event_filter, sizeof(PS3EventFilter_s)); + data += sizeof(PS3EventFilter_s); + memcpy(data, ps3_event_code_pd_count, sizeof(ps3_event_code_pd_count)); + data += sizeof(ps3_event_code_pd_count); + + event_filter.eventType = PS3_EVT_VD_COUNT_LOCAL; + event_filter.eventCodeCnt = 0; + memcpy(data, &event_filter, sizeof(PS3EventFilter_s)); + data += sizeof(PS3EventFilter_s); + + event_filter.eventType = PS3_EVT_CTRL_INFO_LOCAL; + event_filter.eventCodeCnt = 0; + memcpy(data, &event_filter, sizeof(PS3EventFilter_s)); + data += sizeof(PS3EventFilter_s); + + event_filter.eventType = PS3_EVT_PD_ATTR_LOCAL; + event_filter.eventCodeCnt = ARRAY_SIZE(ps3_event_code_pd_attr); + memcpy(data, &event_filter, sizeof(PS3EventFilter_s)); + data += sizeof(PS3EventFilter_s); + memcpy(data, ps3_event_code_pd_attr, sizeof(ps3_event_code_pd_attr)); + data += sizeof(ps3_event_code_pd_attr); +} + +void ps3_event_filter_table_get_hba(U8 *data) +{ + PS3EventFilter_s event_filter; + memset(&event_filter, 0, sizeof(PS3EventFilter_s)); + + event_filter.eventType = PS3_EVT_SAS_INFO_LOCAL; + event_filter.eventCodeCnt = 0; + memcpy(data, &event_filter, sizeof(PS3EventFilter_s)); + data += sizeof(PS3EventFilter_s); + + ps3_event_filter_table_get_raid(data); +} + +void ps3_event_filter_table_get_switch(U8 *data) +{ + PS3EventFilter_s event_filter; + memset(&event_filter, 0, sizeof(PS3EventFilter_s)); + + event_filter.eventType = PS3_EVT_PD_COUNT_LOCAL; + event_filter.eventCodeCnt = ARRAY_SIZE(ps3_event_code_pd_count); + memcpy(data, &event_filter, sizeof(PS3EventFilter_s)); + data += sizeof(PS3EventFilter_s); + memcpy(data, ps3_event_code_pd_count, sizeof(ps3_event_code_pd_count)); + data += sizeof(ps3_event_code_pd_count); +} + +static S32 ps3_event_type_proc(struct ps3_instance *instance, + MgrEvtType_e event_type) +{ + S32 ret = PS3_SUCCESS; + + switch (event_type) { + case PS3_EVT_PD_COUNT: + case PS3_EVT_VD_COUNT: + case PS3_EVT_PD_ATTR: + case PS3_EVT_VD_ATTR: + ret = ps3_dev_update_full_proc(instance, event_type); + break; + case PS3_EVT_CTRL_INFO: + ret = ps3_ctrl_info_get(instance); + break; + default: + LOG_INFO("hno:%u Not cared event type %s\n", + PS3_HOST(instance), ps3_event_print(event_type)); + break; + } + + return ret; +} + +#ifndef _WINDOWS +S32 ps3_event_delay_set(struct ps3_instance *instance, U32 delay) +{ + struct ps3_event_context *event_ctx = NULL; + struct ps3_event_delay_work *delay_work = NULL; + + if (instance) { + event_ctx = &instance->event_context; + if (event_ctx->delay_work) { + delay_work = event_ctx->delay_work; + delay_work->event_delay = delay; + return PS3_SUCCESS; + } + } + + return -PS3_FAILED; +} +#endif + +static void ps3_event_resubscribe(struct ps3_instance *instance, + struct ps3_cmd *cmd, U32 event_proc_result_bitmap) +{ + ULong flags = 0; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + struct PS3MgrEvent *event_req_info = NULL; + INJECT_START(PS3_ERR_IJ_INS_STATE_UNNORMAL, &instance->state_machine.is_load) + + if (!instance->state_machine.is_load) { + LOG_WARN_IN_IRQ(instance, + "hno:%u instance is suspend or instance unload!\n", + PS3_HOST(instance)); + return; + } + + mgr_req_frame = (struct PS3MgrReqFrame *)cmd->req_frame; + event_req_info = (struct PS3MgrEvent *)&mgr_req_frame->value.event; + + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u old event proc result bitmap: [0x%x], " + "current event proc result bitmap: [0x%x]\n", + cmd->trace_id, PS3_HOST(instance), + event_req_info->eventTypeMapProcResult, + event_proc_result_bitmap); + + event_req_info->eventTypeMapProcResult = event_proc_result_bitmap; + + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u subcribe event proc result bitmap: [0x%x]\n", + cmd->trace_id, PS3_HOST(instance), + event_req_info->eventTypeMapProcResult); + + if (instance->ioc_adpter->event_filter_table_get != NULL) { + instance->ioc_adpter->event_filter_table_get((U8*)cmd->ext_buf); + } + wmb(); + PS3_MGR_CMD_STAT_INC(instance, cmd); + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + if (ps3_async_cmd_send(cmd->instance, cmd) != PS3_SUCCESS) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx],CFID[%d],hno:%u re send event cmd faild\n", + cmd->trace_id,cmd->index, PS3_HOST(cmd->instance)); + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + return; +} + +static U32 ps3_event_proc_without_details(struct ps3_instance *instance, + struct PS3EventInfo *event_info) +{ + S32 ret = -PS3_FAILED; + U32 event_proc_result_bitmap = 0; + U32 mask_bit = 0X00000001; + U32 event_type = event_info->eventTypeMap & mask_bit; +#ifndef _WINDOWS + if (event_info->eventTypeMap & PS3_EVT_SAS_INFO) { + ret = ps3_sas_expander_event_refresh(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u Event type PS3_EVT_SAS_INFO proc NOK!\n", + PS3_HOST(instance)); + event_proc_result_bitmap |= PS3_EVT_SAS_INFO; + } + + event_info->eventTypeMap ^= PS3_EVT_SAS_INFO; + } +#endif + while (mask_bit != 0) { + if (event_type != 0) { + LOG_INFO("hno:%u Event type %s report without details!\n", + PS3_HOST(instance), ps3_event_print((MgrEvtType_e)event_type)); + + ret = ps3_event_type_proc(instance, + (MgrEvtType_e)event_type); + + } else { + ret = PS3_SUCCESS; + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u Event type %s proc NOK!\n", + PS3_HOST(instance), + ps3_event_print((MgrEvtType_e)event_type)); + event_proc_result_bitmap |= event_type; + } + + mask_bit = mask_bit << 1; + event_type = event_info->eventTypeMap & mask_bit; + } + + return event_proc_result_bitmap; +} + +static void ps3_event_details_pre_proc(struct ps3_instance *instance, + struct PS3EventInfo *event_info, struct ps3_cmd *cmd) +{ + U32 idx = 0; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + struct PS3MgrEvent *event_req_info = NULL; + struct PS3EventDetail *event_detail = NULL; + + mgr_req_frame = (PS3MgrReqFrame_s *)cmd->req_frame; + event_req_info = (struct PS3MgrEvent *)&mgr_req_frame->value.event; + + for(idx = 0;idx < event_info->eventCount;idx++) { + event_detail = &event_info->eventDetail[idx]; + if (event_detail->eventType & + event_req_info->eventTypeMapProcResult) { + LOG_INFO("trace_id[0x%llx], hno:%u Event type %s code %s with " + "timestamp[%d] dev id[0x%x] magic %#x do not process in details!\n", + cmd->trace_id, PS3_HOST(instance), + ps3_event_print(event_detail->eventType), + mgrEvtCodeTrans(event_detail->eventCode), + event_detail->timestamp, + event_detail->devicePos.diskDev.diskID, + event_detail->devicePos.diskMagicNum); + + event_detail->eventType = PS3_EVT_ILLEGAL_TYPE; + continue; + } + + if (event_detail->eventType == + PS3_EVT_CTRL_INFO) { + event_detail->eventType = PS3_EVT_ILLEGAL_TYPE; + continue; + } + + event_info->eventTypeMap &= (~event_detail->eventType); + LOG_INFO("trace_id[0x%llx], hno:%u Event type %s code %s reports " + "in details with timestamp %d dev id 0x%x magic %#x!\n", + cmd->trace_id, PS3_HOST(instance), + ps3_event_print(event_detail->eventType), + mgrEvtCodeTrans(event_detail->eventCode), event_detail->timestamp, + event_detail->devicePos.diskDev.diskID, + event_detail->devicePos.diskMagicNum); + } + + event_info->eventTypeMap |= event_req_info->eventTypeMapProcResult; +} + +static U32 ps3_event_proc_with_details(struct ps3_instance *instance, + struct PS3EventInfo *event_info, struct ps3_cmd *cmd) +{ + U32 event_proc_result_bitmap = 0; + + ps3_event_details_pre_proc(instance, event_info, cmd); +#ifndef _WINDOWS + event_proc_result_bitmap |= ps3_sas_update_detail_proc(instance, + event_info->eventDetail, event_info->eventCount); +#endif + event_proc_result_bitmap = ps3_dev_update_detail_proc(instance, + event_info->eventDetail, event_info->eventCount); + + return event_proc_result_bitmap; +} + +static void ps3_event_delay(struct ps3_instance *instance, + struct ps3_event_delay_work *delay_work) +{ + struct ps3_cmd *cmd = delay_work->cmd; + U32 event_delay = 0; + + event_delay = delay_work->event_delay; + LOG_WARN("trace_id[0x%llx], hno:%u Event handle will delay %d seconds\n", + cmd->trace_id, PS3_HOST(instance), event_delay); + + while (event_delay > 0) { + if (kthread_should_stop() || + delay_work->event_delay == 0){ + LOG_WARN("trace_id[0x%llx], hno:%u Event handle delay cancel\n", + cmd->trace_id, PS3_HOST(instance)); + return; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ); + event_delay--; + } + LOG_WARN("trace_id[0x%llx], hno:%u Event handle delay %d seconds timeout\n", + cmd->trace_id, PS3_HOST(instance), delay_work->event_delay); +} + +void ps3_event_handle(struct ps3_event_delay_work* ps3_delay_work) +{ + struct ps3_cmd *cmd = ps3_delay_work->cmd; + struct ps3_instance *instance = cmd->instance; + struct PS3EventInfo* event_info = instance->event_context.event_info; + U32 event_proc_result_bitmap = PS3_EVT_ILLEGAL_TYPE; + struct ps3_event_delay_work* ps3_new_delay_work = NULL; + ULong flags = 0; + S32 ret; + + INJECT_START(PS3_ERR_IJ_EVENT_CMD_NULL, instance); + if (instance->event_context.event_cmd == NULL) { + LOG_WARN("trace_id[0x%llx], hno:%u Event is unsubscribed\n", + cmd->trace_id, PS3_HOST(instance)); + return; + } + + if (!instance->state_machine.is_load) { + LOG_WARN("trace_id[0x%llx], hno:%u instance is suspend or instance unload!\n", + cmd->trace_id, PS3_HOST(instance)); + return; + } + + LOG_INFO("trace_id[0x%llx], hno:%u event count[%d], bitmap[%08x]\n", + cmd->trace_id, PS3_HOST(instance), event_info->eventCount, + event_info->eventTypeMap); + + INJECT_START(PS3_ERR_IJ_EVENT_PROC_WAIT_HARD_FLAG, instance) + INJECT_START(PS3_ERR_IJ_EVENT_PROC_WAIT_HARD_SUBCRIBE, instance) + +#ifndef _WINDOWS + if (ps3_delay_work->event_delay) { + ps3_event_delay(instance, ps3_delay_work); + } +#endif + INJECT_START(PS3_ERR_IJ_WAIT_NORMAL, instance) + if (event_info->eventCount <= PS3_EVENT_DETAIL_BUF_MAX) { + LOG_INFO("trace_id[0x%llx], hno:%u Event has valid details info!\n", + cmd->trace_id, PS3_HOST(instance)); + event_proc_result_bitmap |= + ps3_event_proc_with_details(instance, event_info, cmd); + } + + if (event_info->eventTypeMap) { + event_proc_result_bitmap |= + ps3_event_proc_without_details(instance, event_info); + } + PS3_IJ_SLEEP(5000, PS3_ERR_IJ_EVENT_DELAY); + + memset(event_info, 0, sizeof(*event_info)); + ps3_event_print_cmd(cmd, PS3_TRUE); + INJECT_START(PS3_ERR_IJ_EVENT_SUBC_WAIT_HARD_FLAG, instance) + INJECT_START(PS3_ERR_IJ_EVENT_SUBC_WAIT_HARD_SUBCRIBE, instance) + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + if (instance->event_context.abort_eventcmd == 0 && + instance->hardreset_event == 0) { + ps3_new_delay_work = + (ps3_delay_work == &instance->event_context.delay_work_pool[PS3_EVENT_WORKER_POOL_SIZE - 1])? + (&instance->event_context.delay_work_pool[0]):(ps3_delay_work + 1); + instance->event_context.delay_work = ps3_new_delay_work; + ps3_event_resubscribe(instance, cmd, event_proc_result_bitmap); + + if (instance->event_context.subwork != 0) { + instance->event_context.subwork -= 1; + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + } else { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Event proc free cmd:%d, abort_eventcmd %d!\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, + instance->event_context.abort_eventcmd); + instance->event_context.event_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + ps3_new_delay_work = + (ps3_delay_work == &instance->event_context.delay_work_pool[PS3_EVENT_WORKER_POOL_SIZE - 1])? + (&instance->event_context.delay_work_pool[0]):(ps3_delay_work + 1); + instance->event_context.delay_work = ps3_new_delay_work; + instance->event_req_info.eventTypeMapProcResult = instance->event_req_info.eventTypeMap; + ret = ps3_event_subscribe(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR_IN_IRQ(instance, "hno:%u event subscribe failed!\n", + PS3_HOST(instance)); + } + + if(instance->hardreset_event != 0) { + instance->hardreset_event = 0; + } + + if(instance->event_context.abort_eventcmd != 0) { + instance->event_context.abort_eventcmd = 0; + } + wmb(); + if (instance->event_context.subwork != 0) { + instance->event_context.subwork -= 1; + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + } + + return; +} +#ifdef _WINDOWS +static void ps3_event_polling(void *ins) +{ + struct ps3_instance *instance = (struct ps3_instance*)ins; + ps3_event_handle(&instance->event_context.delay_work); +} +#else +static void ps3_event_polling(struct work_struct *work) +{ + struct ps3_event_delay_work *delay_work = ps3_container_of(work, + struct ps3_event_delay_work, event_work.work); + + ps3_event_handle(delay_work); +} +#endif +const char *ps3_event_print(MgrEvtType_e event_type) +{ + U32 idx = 0; + const char *ps3_event_type_name = NULL; + + for (idx = 0;idx < ARRAY_SIZE(g_event_type_desc_table);idx++) { + if (g_event_type_desc_table[idx].event_type == event_type) { + ps3_event_type_name + = g_event_type_desc_table[idx].event_type_desc; + break; + } + } + + return ps3_event_type_name; +} + +S32 ps3_event_context_init(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + U32 idx = 0; + struct ps3_event_context *event_ctx = &instance->event_context; + struct ps3_event_delay_work *delay_work = NULL; + struct ps3_event_delay_work *delay_work_pool = NULL; + memset(event_ctx, 0, sizeof(*event_ctx)); +#ifndef _WINDOWS + delay_work_pool = (struct ps3_event_delay_work *)ps3_kzalloc(instance, + sizeof(struct ps3_event_delay_work) * PS3_EVENT_WORKER_POOL_SIZE); + INJECT_START(PS3_ERR_IJ_PS3_DELAY_WORK_POOL_ALLOC, &delay_work_pool); + if (delay_work_pool == NULL) { + LOG_ERROR("hno:%u delay work kzalloc failed!\n", + PS3_HOST(instance)); + goto l_out; + } + event_ctx->delay_work_pool = delay_work_pool; + for(idx = 0; idx < PS3_EVENT_WORKER_POOL_SIZE; idx++){ + delay_work = &delay_work_pool[idx]; + INIT_DELAYED_WORK(&delay_work->event_work, ps3_event_polling); + } + event_ctx->delay_work = &delay_work_pool[0]; + event_ctx->event_cmd = NULL; + event_ctx->event_abort_cmd = NULL; + event_ctx->abort_eventcmd = 0; + event_ctx->flag = PS3_FALSE; +#else + delay_work = &event_ctx->delay_work; + if (ps3_worker_init(instance, &delay_work->event_work, "ps3_event_wk", ps3_event_polling) != PS3_SUCCESS) { + LOG_ERROR("hno:%u worker init failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + +#endif + event_ctx->subwork = 0; + + ret = PS3_SUCCESS; +l_out: + return ret; +} + +void ps3_event_context_exit(struct ps3_instance *instance) +{ + struct ps3_event_context *event_ctx = &instance->event_context; +#ifdef _WINDOWS + struct ps3_event_delay_work* delay_work = NULL; + + delay_work = &event_ctx->delay_work; + ps3_worker_exit(&delay_work->event_work); +#else + if (event_ctx->delay_work_pool != NULL) { + ps3_kfree(instance, event_ctx->delay_work_pool); + event_ctx->delay_work_pool = NULL; + event_ctx->delay_work = NULL; + } +#endif + memset(event_ctx, 0, sizeof(*event_ctx)); +} + +S32 ps3_event_subscribe(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_event_context *event_ctx = &instance->event_context; + struct PS3MgrEvent *event_req_info = &instance->event_req_info; + + if (!instance->is_need_event) { + LOG_WARN_IN_IRQ(instance, "hno:%u IOC no need event!!\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + if (event_ctx->event_cmd != NULL) { + LOG_ERROR_IN_IRQ(instance, "hno:%u Event already subscribe!\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + if (!instance->state_machine.is_load) { + LOG_WARN_IN_IRQ(instance, "hno:%u instance is suspend or instance unload!\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ret = ps3_event_register(instance, event_req_info); + INJECT_START(PS3_ERR_IJ_WAIT_RESUME_EVENT_FAILED, &ret) + if (ret != PS3_SUCCESS) { + LOG_WARN_IN_IRQ(instance, "hno:%u Failed to register event cmd, ret: %d\n", + PS3_HOST(instance), ret); + goto l_out; + } + + LOG_INFO_IN_IRQ(instance, "hno:%u Success to subscribe event, bitmap[%08x]!\n", + PS3_HOST(instance), event_req_info->eventTypeMap); +l_out: + return ret; +} + +S32 ps3_event_unsubscribe(struct ps3_instance *instance) +{ + ULong flags = 0; + ULong flags1 = 0; + S32 ret = -PS3_FAILED; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + struct ps3_event_context *event_ctx = &instance->event_context; + + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if(event_ctx->flag){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + goto l_out; + } + event_ctx->flag = PS3_TRUE; + cmd = event_ctx->event_cmd; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + if (cmd == NULL) { + LOG_WARN("hno:%u Event is not register yet\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + INJECT_START(PS3_ERR_IJ_SUBC_EVENT_CMD_INIT, instance) + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u had been free,CFID:%d\n", + PS3_HOST(instance), cmd->index); + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + event_ctx->event_cmd = NULL; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + ret = PS3_SUCCESS; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + ret = ps3_mgr_cmd_cancel_send(instance, cmd->index, PS3_CANCEL_EVENT_CMD); + INJECT_START(PS3_ERR_IJ_CANCEL_EVENT_CMD_FAIL, &ret) + if(ret == -PS3_ENOMEM){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u alloc failed\n",PS3_HOST(instance)); + ret = PS3_FAILED; + goto l_out; + }else if(ret != PS3_SUCCESS){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u reqFrameId=%d cancel_cmd_frame_id[%u] free!\n", + PS3_HOST(instance), ps3_cmd_frame_id(instance->event_context.event_abort_cmd), cmd->index); + abort_cmd = instance->event_context.event_abort_cmd; + instance->event_context.event_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + ret = PS3_FAILED; + goto l_out; + } + instance->event_context.abort_eventcmd = 1; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + + ret = ps3_mgr_cmd_cancel_wait(instance, PS3_CANCEL_EVENT_CMD); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u event cancel cmd NOK, ret:%d\n", + PS3_HOST(instance), ret); + goto l_out; + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if(instance->event_context.subwork == 0){ + if(instance->event_context.abort_eventcmd != 0){ + instance->event_context.abort_eventcmd = 0; + LOG_FILE_INFO("hno:%u event cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + event_ctx->event_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + } + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); +l_out: + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + event_ctx->flag = PS3_FALSE; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + return ret; +} +S32 ps3_soft_reset_event_resubscribe(struct ps3_instance *instance) +{ + ULong flags = 0; + ULong flags1 = 0; + S32 ret = -PS3_FAILED; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + struct ps3_event_context *event_ctx = &instance->event_context; + Bool is_need_resend = PS3_FALSE; + + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if(event_ctx->flag){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + goto l_out; + } + event_ctx->flag = PS3_TRUE; + cmd = event_ctx->event_cmd; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + if (cmd == NULL) { + LOG_WARN("hno:%u Event is not register yet\n", + PS3_HOST(instance)); + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + is_need_resend = PS3_TRUE; + goto l_resend; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + INJECT_START(PS3_ERR_IJ_RESUBC_EVENT_CMD_INIT, instance) + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u had been free,CFID:%d\n", + PS3_HOST(instance), cmd->index); + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + event_ctx->event_cmd = NULL; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + ret = PS3_SUCCESS; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + ret = ps3_mgr_cmd_cancel_send(instance, cmd->index, PS3_CANCEL_EVENT_CMD); + if (ret == -PS3_ENOMEM){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u alloc failed\n",PS3_HOST(instance)); + ret = PS3_FAILED; + goto l_out; + } else if (ret != PS3_SUCCESS){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u reqFrameId=%d cancel_cmd_frame_id[%u] free!\n", + PS3_HOST(instance), ps3_cmd_frame_id(instance->event_context.event_abort_cmd), cmd->index); + abort_cmd = instance->event_context.event_abort_cmd; + instance->event_context.event_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + ret = PS3_FAILED; + goto l_out; + } + instance->event_context.abort_eventcmd = 1; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + + ret = ps3_mgr_cmd_cancel_wait(instance, PS3_CANCEL_EVENT_CMD); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u event cancel cmd failed, ret:%d\n", + PS3_HOST(instance), ret); + goto l_out; + } + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if(instance->event_context.subwork == 0){ + if(instance->event_context.abort_eventcmd != 0){ + instance->event_context.abort_eventcmd = 0; + LOG_FILE_INFO("hno:%u event cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + event_ctx->event_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + + is_need_resend = PS3_TRUE; + } + } + +l_resend: + if (is_need_resend) { + instance->event_req_info.eventTypeMapProcResult = + instance->event_req_info.eventTypeMap; + ret = ps3_event_subscribe(instance); + if ((ret != PS3_SUCCESS) && (ret != -PS3_IN_UNLOAD)) { + LOG_FILE_ERROR("hno:%u event subscribe failed!\n", + PS3_HOST(instance)); + ret = PS3_FAILED; + } + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + +l_out: + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + event_ctx->flag = PS3_FALSE; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + return ret; +} + +S32 ps3_event_service(struct ps3_cmd *cmd, U16 reply_flags) +{ + ULong flags = 0; + ULong flags1 = 0; + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance = cmd->instance; + struct ps3_event_context *event_ctx = &instance->event_context; +#ifdef _WINDOWS + struct ps3_event_delay_work *delay_work = &event_ctx->delay_work; +#else + struct ps3_event_delay_work *delay_work = event_ctx->delay_work; +#endif + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + PS3_MGR_CMD_BACK_INC(instance, cmd, reply_flags); + ps3_event_print_cmd(cmd, PS3_FALSE); + + if (reply_flags != PS3_REPLY_WORD_FLAG_SUCCESS) { + LOG_ERROR_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Event notify fetal error!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if (event_ctx->event_cmd == NULL) { + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Event is unsubscribed!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + + if (!instance->state_machine.is_load) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u instance is suspend or instance unload!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u instance is not operational!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + delay_work->cmd = cmd; +#ifdef _WINDOWS + if (ps3_worker_start(&delay_work->event_work) != PS3_SUCCESS) { + LOG_ERROR_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Event start worker failed!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + instance->event_context.subwork += 1; +#else + INJECT_START(PS3_ERR_IJ_EVENT_INT_WAIT_HARD_FLAG, instance) + INJECT_START(PS3_ERR_IJ_EVENT_INT_WAIT_HARD_SUBCRIBE, instance) + instance->event_context.subwork += 1; + schedule_delayed_work(&delay_work->event_work, 0); +#endif + goto l_out; + +l_failed: + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx],CFID[%d], hno:%u failed!\n", + cmd->trace_id, cmd->index, PS3_HOST(instance)); +l_out: + LOG_INFO_IN_IRQ(instance, + "instance->event_context.subwork[%u]!\n", + instance->event_context.subwork); + return ret; +} + +S32 ps3_fasync(int fd, struct file *filp, int mode) +{ + return fasync_helper(fd, filp, mode, &g_async_queue); +} + +S32 ps3_webSubscribe_context_init(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + struct ps3_webSubscribe_context *web_context = &instance->webSubscribe_context; + memset(web_context, 0, sizeof(*web_context)); + web_context->webSubscribe_cmd = NULL; + web_context->web_abort_cmd = NULL; + ps3_atomic_set(&web_context->subscribe_count, PS3_WEB_FLAG_INIT_VALUE); + ps3_atomic_set(&web_context->is_subscribe, PS3_WEB_FLAG_INIT_VALUE); + ps3_atomic_set(&web_context->is_abort, PS3_WEB_FLAG_INIT_VALUE); + web_context->abort_webcmd = PS3_WEB_FLAG_INIT_VALUE; + ret = PS3_SUCCESS; + return ret; +} + +void ps3_webSubscribe_context_exit(struct ps3_instance *instance) +{ + struct ps3_webSubscribe_context *web_context = &instance->webSubscribe_context; + memset(web_context, 0, sizeof(*web_context)); +} + +static void ps3_web_resubscribe(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + ULong flags = 0; + PS3_MGR_CMD_STAT_INC(instance, cmd); + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + if (ps3_async_cmd_send(cmd->instance, cmd) != PS3_SUCCESS) { + LOG_ERROR_IN_IRQ(instance, "trace_id[0x%llx],CFID[%d],hno:%u resend web cmd NOK\n", + cmd->trace_id,cmd->index, PS3_HOST(cmd->instance)); + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + return; +} + +S32 ps3_webSubscribe_service(struct ps3_cmd *cmd, U16 reply_flags) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance = cmd->instance; + struct ps3_webSubscribe_context *web_context = &instance->webSubscribe_context; + + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + PS3_MGR_CMD_BACK_INC(instance, cmd, reply_flags); + ps3_event_print_cmd(cmd, PS3_FALSE); + + if (reply_flags == PS3_REPLY_WORD_FLAG_FAIL) { + LOG_ERROR_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Web notify fetal error!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + if (web_context->webSubscribe_cmd == NULL) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Web is unsubscribed!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + if (!instance->state_machine.is_load) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u instance is suspend or instance unload!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u instance is not operational!\n", + cmd->trace_id, PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_failed; + } + + kill_fasync(&g_async_queue, PS3_EVENT_NOTICE_SIG, POLL_IN); + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + if (instance->webSubscribe_context.abort_webcmd == 0) { + ps3_web_resubscribe(instance, cmd); + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + } else { + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx], hno:%u Web proc free cmd:%d, abort_webcmd %d!\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, + instance->webSubscribe_context.abort_webcmd); + + instance->webSubscribe_context.webSubscribe_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + ret = ps3_web_subscribe(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR_IN_IRQ(instance, + "hno:%u web subscribe failed!\n", + PS3_HOST(instance)); + } + instance->webSubscribe_context.abort_webcmd = 0; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + } + goto l_out; + +l_failed: + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_INFO_IN_IRQ(instance, + "trace_id[0x%llx],CFID[%d], hno:%u failed!\n", + cmd->trace_id, cmd->index, PS3_HOST(instance)); +l_out: + return ret; +} + +S32 ps3_web_subscribe(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + if (!instance->is_need_event) { + LOG_WARN_IN_IRQ(instance, "hno:%u ioc no need web server!!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + ret = ps3_web_register(instance); + if (ret != PS3_SUCCESS) { + LOG_WARN_IN_IRQ(instance, "hno:%u Failed to register web cmd, ret: %d\n", + PS3_HOST(instance), ret); + goto l_out; + } + + LOG_INFO_IN_IRQ(instance, "hno:%u Success to subscribe web event\n", + PS3_HOST(instance)); +l_out: + return ret; +} + +S32 ps3_web_unsubscribe(struct ps3_instance *instance) +{ + ULong flags = 0; + S32 ret = -PS3_FAILED; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + struct ps3_webSubscribe_context *web_context = &instance->webSubscribe_context; + + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + cmd = web_context->webSubscribe_cmd; + if (cmd == NULL) { + LOG_WARN("hno:%u web event is not register yet\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u had been free,CFID:%d\n", + PS3_HOST(instance), cmd->index); + web_context->webSubscribe_cmd = NULL; + ret = PS3_SUCCESS; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + if (ps3_atomic_add_unless(&instance->webSubscribe_context.is_abort, 1, 1) == 0) { + ret = PS3_SUCCESS; + goto l_out; + } + + ret = ps3_mgr_cmd_cancel_send(instance, cmd->index, PS3_CANCEL_WEB_CMD); + INJECT_START(PS3_ERR_IJ_CANCEL_WEB_CMD_ALLOC_NULL, &ret) + if(ret == -PS3_ENOMEM){ + LOG_INFO("hno:%u alloc failed\n",PS3_HOST(instance)); + ret = -PS3_FAILED; + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + goto l_out; + } else if(ret != PS3_SUCCESS) { + LOG_INFO("hno:%u reqFrameId=%d cancel_cmd_frame_id[%u] free!\n", + PS3_HOST(instance), ps3_cmd_frame_id(instance->webSubscribe_context.web_abort_cmd), cmd->index); + abort_cmd = instance->webSubscribe_context.web_abort_cmd; + instance->webSubscribe_context.web_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + ret = -PS3_FAILED; + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + goto l_out; + } + ret = ps3_mgr_cmd_cancel_wait(instance, PS3_CANCEL_WEB_CMD); + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_WEB_UNSUB_FAILED_1, &ret) + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u event cancel cmd NOK, ret:%d\n", + PS3_HOST(instance), ret); + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + goto l_out; + } + LOG_INFO("hno:%u web cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + web_context->webSubscribe_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); +l_out: + return ret; +} + +S32 ps3_soft_reset_web_resubscribe(struct ps3_instance *instance) +{ + ULong flags = 0; + ULong flags1 = 0; + S32 ret = -PS3_FAILED; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + struct ps3_webSubscribe_context *web_context = &instance->webSubscribe_context; + Bool is_need_resend = PS3_FALSE; + + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + cmd = web_context->webSubscribe_cmd; + if (cmd == NULL) { + LOG_WARN("hno:%u Web is not register yet\n", + PS3_HOST(instance)); + is_need_resend = PS3_TRUE; + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + goto l_resend; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u had been free,CFID:%d\n", + PS3_HOST(instance), cmd->index); + web_context->webSubscribe_cmd = NULL; + ret = PS3_SUCCESS; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + if (ps3_atomic_add_unless(&instance->webSubscribe_context.is_abort, 1, 1) == 0) { + ret = PS3_SUCCESS; + goto l_out; + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + ret = ps3_mgr_cmd_cancel_send(instance, cmd->index, PS3_CANCEL_WEB_CMD); + if (ret == -PS3_ENOMEM){ + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u alloc failed\n",PS3_HOST(instance)); + ret = -PS3_FAILED; + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + goto l_out; + } else if (ret != PS3_SUCCESS) { + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + LOG_INFO("hno:%u reqFrameId=%d cancel_cmd_frame_id[%u] free!\n", + PS3_HOST(instance), ps3_cmd_frame_id(instance->webSubscribe_context.web_abort_cmd), cmd->index); + abort_cmd = instance->webSubscribe_context.web_abort_cmd; + instance->webSubscribe_context.web_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + ret = -PS3_FAILED; + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + goto l_out; + } + instance->webSubscribe_context.abort_webcmd = 1; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); + + ret = ps3_mgr_cmd_cancel_wait(instance, PS3_CANCEL_WEB_CMD); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u web cancel cmd failed, ret:%d\n", + PS3_HOST(instance), ret); + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + goto l_out; + } + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags1); + if (instance->webSubscribe_context.abort_webcmd != 0){ + instance->webSubscribe_context.abort_webcmd = 0; + LOG_FILE_INFO("hno:%u web cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + web_context->webSubscribe_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + is_need_resend = PS3_TRUE; + } + ps3_atomic_set(&instance->webSubscribe_context.is_abort, 0); + +l_resend: + if (is_need_resend) { + ret = ps3_web_subscribe(instance); + if ((ret != PS3_SUCCESS) && (ret != -PS3_IN_UNLOAD)) { + LOG_FILE_ERROR("hno:%u web subscribe failed!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags1); +l_out: + return ret; +} + +void ps3_web_cmd_clear(struct ps3_instance *instance) +{ + ULong flags = 0; + struct ps3_cmd *cmd = NULL; + instance->webSubscribe_context.abort_webcmd = 0; + + cmd = instance->webSubscribe_context.webSubscribe_cmd; + + if (cmd == NULL) { + LOG_WARN("hno:%u web cmd has been cancel\n", + PS3_HOST(instance)); + goto l_out; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("hno:%u free this cmd,CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->webSubscribe_context.webSubscribe_cmd = NULL; + goto l_out; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + LOG_INFO("hno:%u web cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->webSubscribe_context.webSubscribe_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + +l_out: + return; +} + diff --git a/drivers/scsi/ps3stor/ps3_event.h b/drivers/scsi/ps3stor/ps3_event.h new file mode 100644 index 0000000000000000000000000000000000000000..a3c7ef2069ad9af2701d711aec25b111430db593 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_event.h @@ -0,0 +1,37 @@ + +#ifndef _PS3_EVENT_H_ +#define _PS3_EVENT_H_ + +#include "ps3_instance_manager.h" + +#define PS3_EVENT_WORKER_POOL_SIZE (3) +#define PS3_WEB_FLAG_INIT_VALUE (0) +S32 ps3_event_context_init(struct ps3_instance *instance); +void ps3_event_context_exit(struct ps3_instance *instance); +const char *ps3_event_print(MgrEvtType_e event_type); +S32 ps3_event_subscribe(struct ps3_instance *instance); +S32 ps3_event_unsubscribe(struct ps3_instance *instance); +S32 ps3_soft_reset_event_resubscribe(struct ps3_instance *instance); +void ps3_event_handle(struct ps3_event_delay_work* ps3_delay_work); + +S32 ps3_event_service(struct ps3_cmd *cmd, U16 reply_flags); +S32 ps3_event_delay_set(struct ps3_instance *instance, U32 delay); + +void ps3_event_filter_table_get_raid(U8 *data); + +void ps3_event_filter_table_get_hba(U8 *data); + +void ps3_event_filter_table_get_switch(U8 *data); + +void ps3_vd_pending_filter_table_build(U8 *data); + +S32 ps3_fasync(int fd, struct file *filp, int mode); +S32 ps3_webSubscribe_context_init(struct ps3_instance *instance); +void ps3_webSubscribe_context_exit(struct ps3_instance *instance); +S32 ps3_webSubscribe_service(struct ps3_cmd *cmd, U16 reply_flags); +S32 ps3_web_subscribe(struct ps3_instance *instance); +S32 ps3_web_unsubscribe(struct ps3_instance *instance); +S32 ps3_soft_reset_web_resubscribe(struct ps3_instance *instance); +void ps3_web_cmd_clear(struct ps3_instance *instance); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_inject.c b/drivers/scsi/ps3stor/ps3_inject.c new file mode 100644 index 0000000000000000000000000000000000000000..3da0c6839c547761dd76b0a495999ae50e2be34f --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_inject.c @@ -0,0 +1,749 @@ + +#include +#include "ps3_cli.h" +#include "ps3_err_inject.h" +#include "ps3_cmd_channel.h" +#include "ps3_mgr_cmd.h" +#include "ps3_module_para.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_ioc_manager.h" +#include "ps3_scsih.h" +#include "ps3_inject.h" +#include "ps3_cmd_statistics.h" +#include "ps3_r1x_write_lock.h" + +#ifdef PS3_SUPPORT_INJECT + +static PS3Inject_s g_inject_list; +static PS3HitCmd_s g_hit_cmd_list; + +PS3Inject_s * get_inject(void){ + return &g_inject_list; +} +PS3HitCmd_s * get_hit_inject(void){ + return &g_hit_cmd_list; +} + +void ps3_inject_list_init(void) +{ + INIT_LIST_HEAD(&g_inject_list.scsi_rw_list); + INIT_LIST_HEAD(&g_inject_list.scsi_task_list); + INIT_LIST_HEAD(&g_inject_list.mgr_list); + ps3_mutex_init(&g_inject_list.lock); +} + +void ps3_hit_cmd_list_init(void) +{ + INIT_LIST_HEAD(&g_hit_cmd_list.scsi_rw_list); + INIT_LIST_HEAD(&g_hit_cmd_list.scsi_task_list); + INIT_LIST_HEAD(&g_hit_cmd_list.mgr_list); +} + +void ps3_inject_init(void) +{ + ps3_hit_cmd_list_init(); + ps3_inject_list_init(); +} + +void ps3_inject_list_exit(void) +{ + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + ps3_mutex_lock(&g_inject_list.lock); + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_rw_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_task_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.mgr_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + ps3_mutex_unlock(&g_inject_list.lock); + ps3_mutex_destroy(&g_inject_list.lock); +} + +void ps3_hit_cmd_list_exit(void) +{ + struct inject_hit_cmds_t *pitem = NULL; + struct inject_hit_cmds_t *pitem_next = NULL; + + ps3_mutex_lock(&g_inject_list.lock); + list_for_each_entry_safe(pitem, pitem_next, &g_hit_cmd_list.scsi_rw_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + + list_for_each_entry_safe(pitem, pitem_next, &g_hit_cmd_list.scsi_task_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + + list_for_each_entry_safe(pitem, pitem_next, &g_hit_cmd_list.mgr_list, list) { + list_del(&pitem->list); + kfree(pitem); + } + ps3_mutex_unlock(&g_inject_list.lock); + return; +} + +void ps3_inject_exit(void) +{ + ps3_hit_cmd_list_exit(); + ps3_inject_list_exit(); +} +void ps3_delete_scsi_rw_inject(struct inject_cmds_t *this_pitem) +{ + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + + if (list_empty(&g_inject_list.scsi_rw_list)) { + LOG_DEBUG("rw inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_rw_list, list) { + if(this_pitem == pitem) { + list_del(&pitem->list); + kfree(pitem); + } + } + +l_out: + return; +} +void ps3_delete_scsi_task_inject(struct inject_cmds_t *this_pitem) +{ + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + + if (list_empty(&g_inject_list.scsi_task_list)) { + LOG_DEBUG("task inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_task_list, list) { + if(this_pitem == pitem) { + list_del(&pitem->list); + kfree(pitem); + } + } + +l_out: + return; +} +void ps3_delete_mgr_inject(struct inject_cmds_t *this_pitem) +{ + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + + if (list_empty(&g_inject_list.mgr_list)) { + LOG_DEBUG("mgr inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.mgr_list, list) { + if(this_pitem == pitem) { + list_del(&pitem->list); + kfree(pitem); + } + } + +l_out: + return; +} + +Bool ps3_add_scsi_rw_cmd_filter(struct ps3_instance *instance, struct PS3CmdWord *cmd_word) +{ + struct ps3_cmd *cmd = ps3_cmd_find(instance, cmd_word->cmdFrameID); + struct inject_cmds_t *pitem = NULL; + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_cmds_t *pitem_next = NULL; + U64 lba; + U32 len; + Bool is_find = PS3_FALSE; + + ps3_mutex_lock(&g_inject_list.lock); + if (list_empty(&g_inject_list.scsi_rw_list)) { + goto l_out; + } + + if (cmd == NULL) { + LOG_DEBUG("[inject] tag[%u] cmd null!\n",cmd_word->cmdFrameID); + } + ps3_scsih_lba_parse(cmd->scmd->cmnd, &lba); + ps3_scsih_len_parse(cmd->scmd->cmnd, &len); + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_rw_list, list) { + if ((cmd->instance->host->host_no == pitem->item.scsi_cmd.host_no) && + (cmd->scmd->device->channel == pitem->item.scsi_cmd.channel) && + (cmd->scmd->device->id == pitem->item.scsi_cmd.id)) { + if (((lba >= pitem->item.scsi_cmd.lba) && + (lba <= pitem->item.scsi_cmd.lba + pitem->item.scsi_cmd.len)) || + ((lba + len >= pitem->item.scsi_cmd.lba) && + (lba + len <= pitem->item.scsi_cmd.lba + pitem->item.scsi_cmd.len))) { + LOG_DEBUG("[inject] add rw cmd [%u:%u:%u] lba[0x%llx], len[0x%x], times[%d], tag[%u]!\n", + pitem->item.scsi_cmd.host_no, pitem->item.scsi_cmd.channel, + pitem->item.scsi_cmd.id, lba, + len, pitem->item.scsi_cmd.inject_count, cmd->index); + is_find = PS3_TRUE; + break; + } + } + } + if(!is_find){ + goto l_out; + } + + p_cmd = (struct inject_hit_cmds_t *)kmalloc(sizeof(struct inject_hit_cmds_t), GFP_KERNEL); + if (p_cmd == NULL) { + is_find = PS3_FALSE; + goto l_out ; + } + p_cmd->cmd = cmd; + p_cmd->pitem = pitem; + pitem->item.scsi_cmd.inject_count--; + list_add_tail(&p_cmd->list, &g_hit_cmd_list.scsi_rw_list); +l_out: + ps3_mutex_unlock(&g_inject_list.lock); + return is_find; +} +Bool ps3_add_scsi_task_cmd_filter(struct ps3_instance *instance, struct PS3CmdWord *cmd_word) +{ + struct ps3_cmd *cmd; + struct ps3_cmd *abort_cmd; + U16 abort_cmd_id = 0; + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + struct inject_hit_cmds_t *p_cmd = NULL; + Bool is_find = PS3_FALSE; + struct ps3_scsi_priv_data *scsi_priv_data = NULL; + + ps3_mutex_lock(&g_inject_list.lock); + if (list_empty(&g_inject_list.scsi_task_list)) { + goto l_out; + } + cmd = ps3_cmd_find(instance, cmd_word->cmdFrameID); + if (cmd == NULL) { + return is_find; + } + if (cmd->req_frame->taskReq.reqHead.cmdSubType == PS3_TASK_CMD_SCSI_TASK_ABORT + && cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_SCSI_TASK_MANAGEMENT) { + abort_cmd_id = cmd->req_frame->taskReq.taskID; + abort_cmd= ps3_cmd_find(instance, abort_cmd_id); + LOG_DEBUG("[inject] {%u:%u:%u} CFID[%u], abort CFID[%u]!\n", + abort_cmd->instance->host->host_no, abort_cmd->scmd->device->channel, + abort_cmd->scmd->device->id, cmd->index, abort_cmd_id); + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_task_list, list) { + if ((abort_cmd->instance->host->host_no == pitem->item.scsi_task_cmd.host_no) && + (abort_cmd->scmd->device->channel == pitem->item.scsi_task_cmd.channel) && + (abort_cmd->scmd->device->id == pitem->item.scsi_task_cmd.id)) { + if (cmd->req_frame->taskReq.reqHead.cmdType == pitem->item.scsi_task_cmd.cmd_type && + cmd->req_frame->taskReq.reqHead.cmdSubType == pitem->item.scsi_task_cmd.cmd_sub_type) { + LOG_DEBUG("[inject] add abort [%u:%u:%u] type[0x%x], subType[0x%x], CFID[%u], abort CFID[%u]!\n", + pitem->item.scsi_task_cmd.host_no, pitem->item.scsi_task_cmd.channel, + pitem->item.scsi_task_cmd.id, pitem->item.scsi_task_cmd.cmd_type, + pitem->item.scsi_task_cmd.cmd_sub_type, cmd->index, abort_cmd_id); + is_find = PS3_TRUE; + if (pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_TIMEOUT) { + } else if (pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_ERROE) { + INJECT_ACTIVE(PS3_ERR_IJ_ABORT_CMD_ERROR, pitem->item.scsi_task_cmd.inject_count) + } else if (pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_NORMAL) { + INJECT_ACTIVE(PS3_ERR_IJ_ABORT_CMD_NORMAL, pitem->item.scsi_task_cmd.inject_count) + } else { + LOG_DEBUG("[inject] dealType[%u] is invalid!\n", + pitem->item.scsi_task_cmd.dealType); + } + break; + } + } + } + }else if (cmd->req_frame->taskReq.reqHead.cmdSubType == PS3_TASK_CMD_SCSI_TASK_RESET + && cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_SCSI_TASK_MANAGEMENT) { + LOG_DEBUG("[inject] type %d subType %d CFID[%u]!\n", + cmd->req_frame->taskReq.reqHead.cmdType,cmd->req_frame->taskReq.reqHead.cmdSubType, + cmd->index); + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.scsi_task_list, list) { + scsi_priv_data = PS3_SDEV_PRI_DATA(pitem->item.scsi_task_cmd.device); + if (cmd->req_frame->taskReq.reqHead.cmdType == pitem->item.scsi_task_cmd.cmd_type && + cmd->req_frame->taskReq.reqHead.cmdSubType == pitem->item.scsi_task_cmd.cmd_sub_type && + (cmd->req_frame->taskReq.reqHead.devID.diskID == scsi_priv_data->disk_pos.diskDev.diskID)) { + LOG_DEBUG("[inject] add reset [%u:%u:%u] type[0x%x], subType[0x%x], CFID[%u]!\n", + pitem->item.scsi_task_cmd.host_no, pitem->item.scsi_task_cmd.channel, + pitem->item.scsi_task_cmd.id, pitem->item.scsi_task_cmd.cmd_type, + pitem->item.scsi_task_cmd.cmd_sub_type, cmd->index); + is_find = PS3_TRUE; + if (pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_TIMEOUT) { + } else if (pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_ERROE) { + INJECT_ACTIVE(PS3_ERR_IJ_RESET_CMD_ERROR, pitem->item.scsi_task_cmd.inject_count) + } else if (pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_NORMAL) { + INJECT_ACTIVE(PS3_ERR_IJ_RESET_CMD_NORMAL, pitem->item.scsi_task_cmd.inject_count) + } else { + LOG_DEBUG("[inject] dealType[%u] is invalid!\n", + pitem->item.scsi_task_cmd.dealType); + } + break; + } + } + } + if (!is_find){ + goto l_out; + } + + p_cmd = (struct inject_hit_cmds_t *)kmalloc(sizeof(struct inject_hit_cmds_t), GFP_KERNEL); + if (p_cmd == NULL) { + is_find = PS3_FALSE; + goto l_out ; + } + pitem->item.scsi_task_cmd.inject_count--; + p_cmd->cmd = cmd; + p_cmd->pitem = pitem; + list_add_tail(&p_cmd->list, &g_hit_cmd_list.scsi_task_list); +l_out: + ps3_mutex_unlock(&g_inject_list.lock); + return is_find; +} + +Bool ps3_add_mgr_cmd_filter(struct ps3_instance *instance, struct PS3CmdWord *cmd_word) +{ + struct ps3_cmd *cmd; + struct inject_cmds_t *pitem = NULL; + struct inject_cmds_t *pitem_next = NULL; + struct inject_hit_cmds_t *p_cmd = NULL; + Bool is_find = PS3_FALSE; + + ps3_mutex_lock(&g_inject_list.lock); + if (list_empty(&g_inject_list.mgr_list)) { + goto l_out; + } + cmd = ps3_cmd_find(instance, cmd_word->cmdFrameID); + if (cmd == NULL) { + return is_find; + } + if (cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_SAS_MANAGEMENT + || cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_MANAGEMENT) { + LOG_DEBUG("[inject] hostno[%u], mgr CFID[%u], cmdType[%u], cmdSubType[%u]!\n", + cmd->instance->host->host_no, cmd->index, cmd->req_frame->taskReq.reqHead.cmdType, + cmd->req_frame->taskReq.reqHead.cmdSubType); + + list_for_each_entry_safe(pitem, pitem_next, &g_inject_list.mgr_list, list) { + if ((cmd->instance->host->host_no == pitem->item.mgr_cmd.host_no) && + (cmd->req_frame->taskReq.reqHead.cmdType == pitem->item.mgr_cmd.cmd_type) && + (cmd->req_frame->taskReq.reqHead.cmdSubType == pitem->item.mgr_cmd.cmd_sub_type)) { + LOG_DEBUG("[inject] add mgr type[0x%x], subType[0x%x], CFID[%u]!\n", + pitem->item.mgr_cmd.cmd_type, + pitem->item.mgr_cmd.cmd_sub_type, cmd->index); + if (pitem->item.mgr_cmd.dealType == PS3_MGR_CMD_TIMEOUT) { + } else if (pitem->item.mgr_cmd.dealType == PS3_SCSI_TASK_CMD_ERROE) { + INJECT_ACTIVE(PS3_ERR_IJ_GET_LINKERRORS_CMD_ERROR, pitem->item.mgr_cmd.inject_count) + INJECT_ACTIVE(PS3_ERR_IJ_PHY_CTRL_CMD_ERROR, pitem->item.mgr_cmd.inject_count) + INJECT_ACTIVE(PS3_ERR_IJ_SMP_CMD_ERROR, pitem->item.mgr_cmd.inject_count) + is_find = PS3_TRUE; + } else { + LOG_DEBUG("[inject] dealType[%u] is invalid!\n", + pitem->item.mgr_cmd.dealType); + } + break; + } + } + } + + if (!is_find){ + goto l_out; + } + + p_cmd = (struct inject_hit_cmds_t *)kmalloc(sizeof(struct inject_hit_cmds_t), GFP_KERNEL); + if (p_cmd == NULL) { + is_find = PS3_FALSE; + goto l_out ; + } + pitem->item.mgr_cmd.inject_count--; + p_cmd->cmd = cmd; + p_cmd->pitem = pitem; + list_add_tail(&p_cmd->list, &g_hit_cmd_list.mgr_list); +l_out: + ps3_mutex_unlock(&g_inject_list.lock); + return is_find; +} + +Bool ps3_add_cmd_filter(struct ps3_instance *instance, struct PS3CmdWord *cmd_word) +{ + Bool is_find = PS3_FALSE; + struct ps3_cmd *cmd = ps3_cmd_find(instance, cmd_word->cmdFrameID); + + if(ps3_err_inject_state_query() == 0) { + return is_find; + } + if(cmd == NULL) { + LOG_DEBUG("[inject] CFID[%u] is invalid!\n", + cmd->index); + return is_find; + } + + if ((cmd_word->type == PS3_CMDWORD_TYPE_READ) || + (cmd_word->type == PS3_CMDWORD_TYPE_WRITE)) { + if (cmd->req_frame->taskReq.reqHead.cmdType != PS3_CMD_SCSI_TASK_MANAGEMENT) + { + is_find = ps3_add_scsi_rw_cmd_filter(instance, cmd_word); + } else { + is_find = ps3_add_scsi_task_cmd_filter(instance, cmd_word); + } + } else { + if (cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_SCSI_TASK_MANAGEMENT) { + is_find = ps3_add_scsi_task_cmd_filter(instance, cmd_word); + } else if (cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_MANAGEMENT || + cmd->req_frame->taskReq.reqHead.cmdType == PS3_CMD_SAS_MANAGEMENT) { + is_find = ps3_add_mgr_cmd_filter(instance, cmd_word); + } + } + + if (is_find) { + LOG_DEBUG("[inject] add filter CFID[%u]!\n", + cmd_word->cmdFrameID); + } + + return is_find; +} +void ps3_inject_scsi_rw_force_stop(struct ps3_cmd *cmd) +{ + struct scsi_cmnd *s_cmd; + S32 ret_code = 0 ; + struct ps3_scsi_priv_data *data = NULL; + ret_code = 0; + + if ((cmd->cmd_state.state == PS3_CMD_STATE_INIT) || + (cmd->cmd_state.state == PS3_CMD_STATE_COMPLETE)) { + return; + } + s_cmd = cmd->scmd; + LOG_DEBUG("[inject] hno:%u force stop scsi CFID[%d]\n", + PS3_HOST(cmd->instance), cmd->index); + + PS3_IO_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_VD_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_DEV_IO_OUTSTAND_DEC(cmd->instance, cmd); + PS3_IOC_DRV2IOC_BACK_INC(cmd->instance, cmd, PS3_REPLY_WORD_FLAG_FAIL); + + ps3_qos_cmd_update(cmd->instance, cmd); + +#ifndef _WINDOWS + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + s_cmd->result = ret_code; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) + s_cmd->SCp.ptr = NULL; +#endif + ps3_scsi_dma_unmap(cmd); + if (likely(cmd && cmd->scmd && cmd->scmd->device && cmd->scmd->device->hostdata)) { + data = (struct ps3_scsi_priv_data *)cmd->scmd->device->hostdata; + if (likely(data != NULL) && + data->lock_mgr.hash_mgr != NULL) { + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + } else { + LOG_WARN("hno:%u force stop scsi has Null pointer CFID[%u]\n", + PS3_HOST(cmd->instance), cmd->index); + } + if (cmd->r1x_peer_cmd != NULL) { + LOG_DEBUG("[inject] hno:%u force stop r1x scsi CFID[%d] and CFID[%d]\n", + PS3_HOST(cmd->instance), cmd->index, cmd->r1x_peer_cmd->index); + if (!ps3_r1x_peer_cmd_free_nolock(cmd->r1x_peer_cmd)) { + PS3_IOC_DRV2IOC_BACK_INC(cmd->instance, cmd->r1x_peer_cmd, PS3_REPLY_WORD_FLAG_FAIL); + ps3_scsi_cmd_free(cmd->r1x_peer_cmd); + } + + if (!ps3_r1x_peer_cmd_free_nolock(cmd)) { + ps3_scsi_cmd_free(cmd); + } + } else { + ps3_scsi_cmd_free(cmd); + } + SCMD_IO_DONE(s_cmd); +#else + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd, cmd->index); + scsi_cmnd_hoststatus_set(s_cmd, DID_RESET); + data = scsi_device_private_data(s_cmd); + if(likely(data != NULL) && data->lock_mgr.hash_mgr != NULL){ + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + ps3_scsi_cmd_done(cmd); + +#endif +return; +} +void ps3_task_abort_force_scsi_cmd(struct ps3_cmd *cmd) +{ + struct ps3_cmd *abort_cmd = NULL; + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + ULong cmd_lock_flags = 0; + struct inject_cmds_t *pitem = NULL; + + abort_cmd = ps3_cmd_find(cmd->instance, cmd->req_frame->taskReq.taskID); + if (abort_cmd == NULL) { + goto l_out; + } + list_for_each_entry_safe(p_cmd, p_cmd_next, &g_hit_cmd_list.scsi_rw_list, list) { + if (abort_cmd == p_cmd->cmd) { + LOG_DEBUG("[inject] hno:%u del scsi CFID [%u] from hit_rw_list\n", + PS3_HOST(cmd->instance), abort_cmd->index); + list_del(&p_cmd->list); + pitem = p_cmd->pitem; + kfree(p_cmd); + break; + } + } + + if (pitem->item.scsi_cmd.inject_count == 0) { + LOG_DEBUG("[inject] del inject_rw host_no %u channel %u id %u lba 0x%llx len 0x%u type %u, time %u!\n", + pitem->item.scsi_cmd.host_no, pitem->item.scsi_cmd.channel, + pitem->item.scsi_cmd.id, pitem->item.scsi_cmd.lba, + pitem->item.scsi_cmd.len, pitem->item.scsi_cmd.dealType, + pitem->item.scsi_cmd.inject_count); + ps3_delete_scsi_rw_inject(pitem); + } + + ps3_inject_scsi_rw_force_stop(abort_cmd); + +l_out: + + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &cmd_lock_flags); + cmd->resp_frame->normalRespFrame.respStatus = SCSI_STATUS_GOOD; + complete(&cmd->sync_done); + LOG_DEBUG("[inject] hno:%u force complete task abort CFID:%d\n", + PS3_HOST(cmd->instance), cmd->index); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); +} + +void ps3_task_reset_force_scsi_cmd(struct ps3_cmd *cmd) +{ + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + struct ps3_scsi_priv_data *scsi_priv_data; + ULong cmd_lock_flags = 0; + + list_for_each_entry_safe(p_cmd, p_cmd_next, &g_hit_cmd_list.scsi_rw_list, list) { + scsi_priv_data = scsi_device_private_data(p_cmd->cmd->scmd); + if (scsi_priv_data->disk_pos.diskDev.diskID == cmd->req_frame->taskReq.reqHead.devID.diskID) { + LOG_DEBUG("[inject] hno:%u del scsi CFID [%u] from hit_rw_list\n", + PS3_HOST(cmd->instance), p_cmd->cmd->index); + list_del(&p_cmd->list); + ps3_inject_scsi_rw_force_stop(p_cmd->cmd); + kfree(p_cmd); + } + } + + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &cmd_lock_flags); + cmd->resp_frame->normalRespFrame.respStatus = SCSI_STATUS_GOOD; + complete(&cmd->sync_done); + LOG_DEBUG("[inject] hno:%u force complete task reset CFID:%d\n", + PS3_HOST(cmd->instance), cmd->index); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + +} +#ifndef PS3_UT +S32 ps3_scsi_rw_cmd_filter_handle(struct scsi_cmnd *scmd) +{ + struct ps3_cmd *cmd = NULL; + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + struct ps3_instance *instance = scsi_host_data(scmd); + Bool is_find = PS3_FALSE; + U16 reply_flags; + S32 iRet = PS3_SUCCESS; + struct inject_cmds_t *pitem = NULL; + + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(scmd->cmnd)); + if (!ps3_scsih_is_rw_type(type)) { + goto l_out; + } + ps3_mutex_lock(&g_inject_list.lock); + if (list_empty(&g_hit_cmd_list.scsi_rw_list)) { + LOG_DEBUG("[inject] rw inject list is empty!\n"); + goto l_out; + } + + cmd = ps3_cmd_find(instance, SCMD_GET_REQUEST(scmd)->tag); + + list_for_each_entry_safe(p_cmd, p_cmd_next, &g_hit_cmd_list.scsi_rw_list, list) { + if (cmd == p_cmd->cmd) { + is_find = PS3_TRUE; + break; + } + } + + if (!is_find){ + goto l_out; + } + pitem = p_cmd->pitem; + + if (p_cmd->pitem->item.scsi_cmd.dealType == PS3_SCSI_CMD_TIMEOUT_FORCE_REPLY) { + ps3_inject_scsi_rw_force_stop(cmd); + } else if (p_cmd->pitem->item.scsi_cmd.dealType == PS3_SCSI_CMD_ERROR) { + scmd->result = p_cmd->pitem->item.scsi_cmd.cmdDeal.errReply.result; + scmd->sense_buffer[0] = p_cmd->pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.resp_code; + scmd->sense_buffer[1] = p_cmd->pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.sense_key; + scmd->sense_buffer[2] = p_cmd->pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.asc; + scmd->sense_buffer[3] = p_cmd->pitem->item.scsi_cmd.cmdDeal.errReply.sshdr.ascq; + reply_flags = 1; + if (cmd->cmd_receive_cb) { + LOG_DEBUG("[inject] sense: CFID:%d, rcode:0x%x, key:0x%x, asc:0x%x, ascq:0x%x\n", + cmd->index, scmd->sense_buffer[0], scmd->sense_buffer[1], + scmd->sense_buffer[2], scmd->sense_buffer[3]); + iRet = cmd->cmd_receive_cb(cmd, reply_flags); + } else { + LOG_DEBUG("[inject] ps3 cmd index %d has no cmd_receive_cb\n", + cmd->index); + } + } else { + LOG_DEBUG("[inject] ps3 CFID %d dealType %d invalid\n", + cmd->index,p_cmd->pitem->item.scsi_cmd.dealType); + } + list_del(&p_cmd->list); + kfree(p_cmd); + + if (pitem->item.scsi_cmd.inject_count == 0) { + ps3_delete_scsi_rw_inject(pitem); + } + +l_out: + ps3_mutex_unlock(&g_inject_list.lock); + return iRet; +} +S32 ps3_scsi_task_cmd_filter_handle(struct ps3_cmd *cmd) +{ + struct inject_cmds_t *pitem = NULL; + struct ps3_instance *instance = cmd->instance; + Bool is_find = PS3_FALSE; + ULong cmd_lock_flags = 0; + S32 iRet = PS3_SUCCESS; + + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + + if (cmd->req_frame->taskReq.reqHead.cmdType != PS3_CMD_SCSI_TASK_MANAGEMENT) { + goto l_out; + } + ps3_mutex_lock(&g_inject_list.lock); + if (list_empty(&g_hit_cmd_list.scsi_task_list)) { + LOG_DEBUG("[inject] task inject list is empty!\n"); + goto l_out; + } + + list_for_each_entry_safe(p_cmd, p_cmd_next, &g_hit_cmd_list.scsi_task_list, list) { + if (cmd == p_cmd->cmd) { + list_del(&p_cmd->list); + pitem = p_cmd->pitem; + kfree(p_cmd); + is_find = PS3_TRUE; + break; + } + } + + if (!is_find){ + goto l_out; + } + + if (p_cmd->pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_TIMEOUT) { + LOG_DEBUG("[inject] hno:%u force task mgr CFID:%d timeout\n", + PS3_HOST(instance), cmd->index); + } else if (p_cmd->pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_ERROE) { + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &cmd_lock_flags); + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_TM_FAILED; + complete(&cmd->sync_done); + LOG_DEBUG("[inject] hno:%u force complete task mgr CFID:%d error\n", + PS3_HOST(instance), cmd->index); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + + } else if (p_cmd->pitem->item.scsi_task_cmd.dealType == PS3_SCSI_TASK_CMD_NORMAL){ + if (cmd->req_frame->taskReq.reqHead.cmdSubType == PS3_TASK_CMD_SCSI_TASK_ABORT) { + LOG_DEBUG("[inject] hno:%u force complete task abort CFID:%d normal reply\n", + PS3_HOST(instance), cmd->index); + ps3_task_abort_force_scsi_cmd(cmd); + } else if(cmd->req_frame->taskReq.reqHead.cmdSubType == PS3_TASK_CMD_SCSI_TASK_RESET){ + LOG_DEBUG("[inject] hno:%u force complete task reset CFID:%d normal reply\n", + PS3_HOST(instance), cmd->index); + ps3_task_reset_force_scsi_cmd(cmd); + } else { + LOG_INFO("[inject] ps3 CFID %u type %d subType %d invalid\n", + cmd->index,cmd->req_frame->taskReq.reqHead.cmdType, + cmd->req_frame->taskReq.reqHead.cmdSubType); + } + } + + if(pitem->item.scsi_cmd.inject_count == 0) { + ps3_delete_scsi_task_inject(pitem); + } + +l_out: + ps3_mutex_unlock(&g_inject_list.lock); + return iRet; +} + +S32 ps3_mgr_cmd_filter_handle(struct ps3_cmd *cmd) +{ + struct inject_cmds_t *pitem = NULL; + struct ps3_instance *instance = cmd->instance; + Bool is_find = PS3_FALSE; + ULong cmd_lock_flags = 0; + S32 iRet = PS3_SUCCESS; + struct inject_hit_cmds_t *p_cmd = NULL; + struct inject_hit_cmds_t *p_cmd_next = NULL; + + if (cmd->req_frame->taskReq.reqHead.cmdType != PS3_CMD_MANAGEMENT && + cmd->req_frame->taskReq.reqHead.cmdType != PS3_CMD_SAS_MANAGEMENT) { + goto l_out; + } + ps3_mutex_lock(&g_inject_list.lock); + if (list_empty(&g_hit_cmd_list.mgr_list)) { + LOG_DEBUG("[inject] task inject list is empty!\n"); + goto l_unlock; + } + + list_for_each_entry_safe(p_cmd, p_cmd_next, &g_hit_cmd_list.mgr_list, list) { + if (cmd == p_cmd->cmd) { + list_del(&p_cmd->list); + pitem = p_cmd->pitem; + kfree(p_cmd); + is_find = PS3_TRUE; + break; + } + } + + if (!is_find){ + goto l_unlock; + } + + if (p_cmd->pitem->item.mgr_cmd.dealType == PS3_MGR_CMD_TIMEOUT) { + LOG_DEBUG("[inject] hno:%u force mgr CFID:%d timeout\n", + PS3_HOST(instance), cmd->index); + } else if (p_cmd->pitem->item.mgr_cmd.dealType == PS3_MGR_CMD_ERROE) { + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &cmd_lock_flags); + cmd->resp_frame->normalRespFrame.respStatus = pitem->item.mgr_cmd.errType; + complete(&cmd->sync_done); + LOG_DEBUG("[inject] hno:%u force complete task mgr CFID:%d error\n", + PS3_HOST(instance), cmd->index); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + + } + + if(pitem->item.mgr_cmd.inject_count == 0) { + ps3_delete_mgr_inject(pitem); + } +l_unlock: + ps3_mutex_unlock(&g_inject_list.lock); +l_out: + return iRet; +} + +#endif +#endif diff --git a/drivers/scsi/ps3stor/ps3_inject.h b/drivers/scsi/ps3stor/ps3_inject.h new file mode 100644 index 0000000000000000000000000000000000000000..85f482c1c0779309140266e6972145fffec822ed --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_inject.h @@ -0,0 +1,120 @@ + +#ifndef _PS3_INJECT_H_ +#define _PS3_INJECT_H_ + +typedef struct PS3Inject { + ps3_mutex lock; + struct list_head scsi_rw_list; + struct list_head scsi_task_list; + struct list_head mgr_list; +} PS3Inject_s; + +typedef struct PS3HitCmd { + struct list_head scsi_rw_list; + struct list_head scsi_task_list; + struct list_head mgr_list; +} PS3HitCmd_s; + +typedef struct ps3_scsi_sense{ + U8 resp_code; + U8 sense_key; + U8 asc; + U8 ascq; +} ps3_scsi_sense_s; + + +typedef struct PS3ScsiErrorReply { + S32 result; + ps3_scsi_sense_s sshdr; +} PS3ScsiErrorReply_s; + + +typedef struct PS3ScsiForceReply { + U32 step; +} PS3ScsiForceReply_s; + +union PS3CmdInjectDeal { + PS3ScsiErrorReply_s errReply; + PS3ScsiForceReply_s forceReply; +}; + +struct inject_scsi_cmds_t { + U32 host_no; + U32 id; + U32 channel; + struct scsi_device *device; + U64 lba; + U32 len; + U32 dealType; + union PS3CmdInjectDeal cmdDeal; + U32 inject_count; +}; + +struct inject_scsi_task_cmds_t { + U32 host_no; + U32 id; + U32 channel; + struct scsi_device *device; + U8 cmd_type; + U8 cmd_sub_type; + U32 dealType; + union PS3CmdInjectDeal cmdDeal; + U32 inject_count; +}; + +struct inject_mgr_cmds_t { + U32 host_no; + U8 cmd_type; + U8 cmd_sub_type; + U32 dealType; + U32 errType; + U32 inject_count; +}; + +union PS3CmdInject { + struct inject_scsi_cmds_t scsi_cmd; + struct inject_scsi_task_cmds_t scsi_task_cmd; + struct inject_mgr_cmds_t mgr_cmd; +}; +struct inject_cmds_t { + struct list_head list; + union PS3CmdInject item; +}; + +struct inject_hit_cmds_t { + struct list_head list; + struct ps3_cmd *cmd; + struct inject_cmds_t *pitem; +}; + +enum { + PS3_SCSI_CMD_TIMEOUT_FORCE_REPLY = 1, + PS3_SCSI_CMD_ERROR = 2, + PS3_SCSI_TASK_CMD_NORMAL = 3, + PS3_SCSI_TASK_CMD_TIMEOUT = 4, + PS3_SCSI_TASK_CMD_ERROE = 5, + PS3_MGR_CMD_NORMAL = 6, + PS3_MGR_CMD_TIMEOUT = 7, + PS3_MGR_CMD_ERROE = 8, +} ; +PS3Inject_s * get_inject(void); + +#ifndef PS3_UT +S32 ps3_scsi_rw_cmd_filter_handle(struct scsi_cmnd *scmd); +S32 ps3_scsi_task_cmd_filter_handle(struct ps3_cmd *cmd); +S32 ps3_mgr_cmd_filter_handle(struct ps3_cmd *cmd); +#endif + +Bool ps3_add_cmd_filter(struct ps3_instance *instance, struct PS3CmdWord *cmd_word); + +void ps3_delete_scsi_rw_inject(struct inject_cmds_t *this_pitem); +void ps3_delete_scsi_task_inject(struct inject_cmds_t *this_pitem); +void ps3_delete_mgr_inject(struct inject_cmds_t *this_pitem); + +PS3HitCmd_s * get_hit_inject(void); + +void ps3_inject_init(void); + +void ps3_inject_exit(void); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_inner_data.h b/drivers/scsi/ps3stor/ps3_inner_data.h new file mode 100644 index 0000000000000000000000000000000000000000..ae2917f6f1c0824257254dcfe70f7d83c010f91c --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_inner_data.h @@ -0,0 +1,313 @@ + +#ifndef _PS3_INNER_DATA_H_ +#define _PS3_INNER_DATA_H_ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#else +#include "ps3_worker.h" +#endif + +#include "ps3_htp_event.h" +#include "ps3_htp_dev.h" +#include "ps3_htp_pci.h" +#include "hwapi/include_v200/s1861_regs/s1861_global_baseaddr.h" +#include "hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_request_queue_reg.h" +#include "hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_f_reg.h" +#include "hwapi/include_v200/s1861_regs/s1861_hil_reg0_ps3_register_s_reg.h" + +#include "ps3_device_manager.h" +#include "ps3_register_fifo.h" +#include "ps3_err_def.h" + +#define PS3_DEFAULT_PAGE_SIZE_SHIFT (12) +#define PS3_CMD_SGE_FRAME_BUFFER_SIZE (4096) +#define PS3_DUMP_DMA_BUF_SIZE (0x100000) +#define PS3_DEFAULT_TASK_MGR_TIMEOUT (50) +#define PS3_DEFAULT_MGR_CMD_TIMEOUT (180) +#define PS3_CANCEL_MGR_CMD_TIMEOUT (30) +#define PS3_UNLOAD_MGR_CMD_TIMEOUT (60) +#define PS3_RAID_UNLOAD_MGR_CMD_TIMEOUT (360) +#define PS3_SOFT_RESET_WAIT_TIMEOUT (30) +#define PS3_SLEEP_TOLERATE_TIMEOUT (10) +#define PS3_RESET_WAIT_IO_REPLY_MAX_TIME (5) +#define PS3_REGISTER_SET_SIZE (147456) +#define PS3_MAX_DEBUG_REG_CNT (8) + +#define PS3_HARD_RESET_MAX_RETRY (2) + +#define PS3_MAX_REPLY_QUE_COUNT (128) +#define PS3_RAIDHBA_NUM_ADJUST_VALUE (1) + +#define PS3_DEVICE_IO_BUSY_THRESHOLD (8) + +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 4)) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR == 9) && (RHEL_MINOR >= 1)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0))) +#include +#ifndef PS3_TAGSET_SUPPORT +#define PS3_TAGSET_SUPPORT +#endif +#endif + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR == 9 && RHEL_MINOR >= 2)) || \ + (defined(CONFIG_SUSE_KERNEL) && \ + ((CONFIG_SUSE_VERSION == 15) && (CONFIG_SUSE_PATCHLEVEL >= 5)))) +#define MAP_QUEUES_RET_TYPE void +#define MAP_QUEUES_RET_VAL(x) return +#else +#define MAP_QUEUES_RET_TYPE int +#define MAP_QUEUES_RET_VAL(x) return x +#endif + +#define PS3_BLOCK_NUM_OF_32K (1 << 6) +#define PS3_VD_IO_16_OUTSTANDING (16) +#define PS3_VD_IO_1_OUTSTANDING (1) +enum { + PS3_SCSI_CMD_TIMEOUT_MIN = 10, + PS3_SCSI_CMD_TIMEOUT_DEFAULT = 90, + PS3_SCSI_CMD_TIMEOUT_MAX = 255, +}; + +enum { + PS3_DEVICE_QDEPTH_DEFAULT_VALUE = 16, +}; + + +typedef enum PS3FuncID { + PS3_FUNC_ID_0 = 0, + PS3_FUNC_ID_1 = 1, + PS3_FUNC_UNLIMITED = 2, +}PS3FuncID_e; + +enum { + PS3_SHIFT_BYTE = 8, + PS3_SHIFT_WORD = 16, + PS3_SHIFT_3BYTE = 24, + PS3_SHIFT_DWORD = 32, +}; + +enum { + PS3_SGL_MODE_SGE_COUNT_NO_DATA = 0, + PS3_SGL_MODE_SGE_COUNT_DIRECT = 1, +}; + +struct ps3_event_delay_work { +#ifdef _WINDOWS + struct ps3_worker event_work; +#else + struct delayed_work event_work; +#endif + struct ps3_cmd *cmd; + U32 event_delay; +}; + +struct ps3_event_context { + struct PS3EventInfo *event_info; + struct ps3_cmd *event_cmd; + struct ps3_cmd *event_abort_cmd; + volatile U32 abort_eventcmd; +#ifdef _WINDOWS + struct ps3_event_delay_work delay_work; +#else + struct ps3_event_delay_work* delay_work; + struct ps3_event_delay_work* delay_work_pool; +#endif + U64 event_phy_addr; + volatile U32 subwork; + Bool flag; +}; + +struct ps3_webSubscribe_context { + struct ps3_cmd *webSubscribe_cmd; + struct ps3_cmd *web_abort_cmd; + ps3_atomic32 is_subscribe; + ps3_atomic32 is_abort; + ps3_atomic32 subscribe_count; + volatile U32 abort_webcmd; +}; + +#ifndef _WINDOWS +struct ps3_refire_delay_work { + struct delayed_work refire_cmd_work; + struct ps3_cmd *refire_cmd; +}; +#endif + +struct ps3_cmd_attr_context { + S32 throttle_que_depth; + S32 cur_can_que; + U32 vd_io_threshold; + U32 nvme_page_size; + Bool is_support_direct_cmd; + U8 reserved[7]; +}; + +enum { + PS3_REG_OFFSET_REQUEST_QUE = \ + (HIL_REG0_PS3_REQUEST_QUEUE_PS3_REQUEST_QUEUE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DOORBELL = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DOORBELL_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DOORBELL_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DOORBELL_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_IRQ_CONTROL = \ + (HIL_REG0_PS3_REGISTER_F_PS3_IRQ_CONTROL_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_KEY = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_STATE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_STATE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_KEY_SHIFT_REG_LOW = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_SHIFT_REG_LOW_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_KEY_SHIFT_REG_HIGH = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_KEY_SHIFT_REG_HIGH_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_TIME_CNT = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_TIME_CNT_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_TIME_OUT_CNT = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_TIME_OUT_EN_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_KEY = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_STATE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_STATE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_KEY_SHIFT_REG_LOW = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_SHIFT_REG_LOW_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_KEY_SHIFT_REG_HIGH = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_KEY_SHIFT_REG_HIGH_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_TIME_CNT = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_TIME_CNT_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_TIME_OUT_CNT = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_TIME_OUT_EN_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_KEY_GAP_CFG = \ + (HIL_REG0_PS3_REGISTER_F_PS3_KEY_GAP_CFG_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDRESET_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDRESET_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOC_FW_STATE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOC_FW_STATE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_MAX_FW_CMD = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MAX_FW_CMD_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_MAX_CHAIN_SIZE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MAX_CHAIN_SIZE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_MAX_VD_INFO_SIZE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MAX_VD_INFO_SIZE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_MAX_NVME_PAGE_SIZE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MAX_NVME_PAGE_SIZE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_FEATURE_SUPPORT = \ + (HIL_REG0_PS3_REGISTER_F_PS3_FEATURE_SUPPORT_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_FIRMWARE_VERSION = \ + (HIL_REG0_PS3_REGISTER_F_PS3_FIRMWARE_VERSION_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_REPLY_QUE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MAX_REPLYQUE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HARDWARE_VERSION = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HARDWARE_VERSION_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_MGR_QUEUE_DEPTH = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MGR_QUEUE_DEPTH_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_CMD_QUEUE_DEPTH = \ + (HIL_REG0_PS3_REGISTER_F_PS3_CMD_QUEUE_DEPTH_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_TFIFO_DEPTH = \ + (HIL_REG0_PS3_REGISTER_F_PS3_TFIFO_DEPTH_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_MAX_SEC_R1X_CMDS = \ + (HIL_REG0_PS3_REGISTER_F_PS3_MAX_SEC_R1X_CMDS_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT0 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT0_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT1 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT1_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT2 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT2_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT3 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT3_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_HIL_ADVICE2DIRECT_CNT_ALL = \ + (HIL_REG0_PS3_REGISTER_F_PS3_HIL_ADVICE2DIRECT_CNT_ALL_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_IRQ_STATUS_RPT = \ + (HIL_REG0_PS3_REGISTER_F_PS3_IRQ_STATUS_RPT_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DUMP_CTRL = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DUMP_CTRl_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DUMP_CTRl_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DUMP_CTRL_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DUMP_STATUS = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DUMP_STATUS_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DUMP_DATA_SIZE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DUMP_DATA_SIZE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_CMD_TRIGGER = \ + (HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_CMD_TRIGGER_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_CMD_TRIGGER_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_CMD_TRIGGER_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_REG_CMD_STATE = \ + (HIL_REG0_PS3_REGISTER_F_PS3_REG_CMD_STATE_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_SOFTRESET_COUNTER = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SOFTRESET_COUNTER_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG0 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG0_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG0_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG0_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG1 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG1_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG1_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG1_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG2 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG2_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG2_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG2_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG3 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG3_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG3_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG3_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG4 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG4_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG4_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG4_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG5 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG5_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG6 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG6_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG7 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG7_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG8 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG8_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG9 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG9_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG10 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG10_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG11 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG11_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_OFFSET_DEBUG12 = \ + (HIL_REG0_PS3_REGISTER_F_PS3_DEBUG12_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_SESSION_ADDR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_SESSION_ADDR_IRQ_CLEAR = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_IRQ_CLEAR_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), + PS3_REG_SESSION_ADDR_IRQ_MASK = \ + (HIL_REG0_PS3_REGISTER_F_PS3_SESSIONCMD_ADDR_IRQ_MASK_ADDR - HIL_REG0_PS3_REGISTER_F_BASEADDR), +}; + +#endif diff --git a/drivers/scsi/ps3stor/ps3_instance_manager.c b/drivers/scsi/ps3stor/ps3_instance_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..111320caa2e7871ad24f725d3d4d5f1ff76ef509 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_instance_manager.c @@ -0,0 +1,698 @@ + +#include "ps3_instance_manager.h" +#include "ps3_driver_log.h" +#include "ps3_ioc_manager.h" + +#ifndef _WINDOWS +#include "ps3_debug.h" +#include +#include +#endif +#include "ps3_cli_debug.h" + +#ifdef PS3_HARDWARE_HAPS_V200 +#define PS3_INSTANCE_WAIT_TO_OPERATIONAL_MAX_SECS (180) +#define PS3_INSTANCE_WAIT_TO_NORMAL_MAX_SECS (3600) +#define PS3_INSTANCE_STATE_CHECK_INTERVAL_MS (1000) +#define PS3_INSTANCE_STATE_CHECK_NORMAL_INTERVAL_MS (3000) +#else +#define PS3_INSTANCE_WAIT_TO_OPERATIONAL_MAX_SECS (180) +#define PS3_INSTANCE_WAIT_TO_NORMAL_MAX_SECS (420) +#define PS3_INSTANCE_STATE_CHECK_INTERVAL_MS (1000) +#endif + +struct ps3_host_info g_ps3_host_info; + +#ifndef _WINDOWS +struct ps3_mgmt_info *ps3_mgmt_info_get(void) +{ + static struct ps3_mgmt_info g_mgmt_info; + + return &g_mgmt_info; +} + +struct ps3_instance *ps3_instance_lookup(U16 host_no) +{ + struct ps3_instance *instance = NULL; + struct list_head *pitem = NULL; + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + instance = list_entry(pitem, struct ps3_instance, list_item); + if (instance->host->host_no == host_no) { + return instance; + } + } + + return NULL; +} + +S32 ps3_instance_add(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + struct list_head *pitem = NULL; + struct ps3_instance *peer_instance = NULL; + + if (instance == NULL) { + return ret; + } + + ps3_mutex_lock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + list_for_each(pitem, &ps3_mgmt_info_get()->instance_list_head) { + if (pitem == &instance->list_item) { + pitem = NULL; + goto l_repeat_add; + } + } + + list_for_each_entry(peer_instance, &ps3_mgmt_info_get()->instance_list_head, list_item) { + if (peer_instance != NULL && + ps3_get_pci_domain(peer_instance->pdev) == ps3_get_pci_domain(instance->pdev) && + peer_instance->pdev->bus->number == instance->pdev->bus->number && + PCI_SLOT(peer_instance->pdev->devfn) == PCI_SLOT(instance->pdev->devfn)) { + INJECT_START(PS3_ERR_IJ_ASYNC_HARDRESET_PROBE, peer_instance) + peer_instance->recovery_context->instance_change = 1; + INJECT_START(PS3_ERR_IJ_ADD_INSTANCE_WAIT, peer_instance) + mb(); + ps3_recovery_cancel_work_sync(peer_instance); + instance->peer_instance = peer_instance; + peer_instance->peer_instance = instance; + mb(); + peer_instance->recovery_context->instance_change = 0; + } + } + + list_add(&instance->list_item, &ps3_mgmt_info_get()->instance_list_head); + mutex_init(&instance->state_machine.lock); + ps3_mutex_init(&instance->task_mgr_reset_lock); + ps3_mutex_init(&instance->task_abort_lock); + atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_INIT); + instance->state_machine.is_load = PS3_FALSE; + instance->state_machine.is_pci_err_recovery = PS3_FALSE; + + ret = PS3_SUCCESS; +l_repeat_add: + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + if (pitem == NULL) { + LOG_WARN("hno:%u repeat add instance!\n", + PS3_HOST(instance)); + } + return ret; +} + +S32 ps3_instance_remove(struct ps3_instance *instance) +{ + struct ps3_instance *peer_instance = NULL; + + if (instance == NULL) { + return -PS3_FAILED; + } + + ps3_mutex_lock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + list_del(&instance->list_item); + instance->peer_instance = NULL; + list_for_each_entry(peer_instance, &ps3_mgmt_info_get()->instance_list_head, list_item) { + if (peer_instance != NULL && + ps3_get_pci_domain(peer_instance->pdev) == ps3_get_pci_domain(instance->pdev) && + peer_instance->pdev->bus->number == instance->pdev->bus->number && + PCI_SLOT(peer_instance->pdev->devfn) == PCI_SLOT(instance->pdev->devfn)) { + INJECT_START(PS3_ERR_IJ_ASYNC_HARDRESET_REMOVE, peer_instance) + INJECT_START(PS3_ERR_IJ_REMOVE_INSTANCE_WAIT, peer_instance) + peer_instance->recovery_context->instance_change = 1; + mb(); + ps3_recovery_cancel_work_sync(peer_instance); + peer_instance->peer_instance = NULL; + mb(); + peer_instance->recovery_context->instance_change = 0; + } + } + mutex_destroy(&instance->state_machine.lock); + ps3_mutex_destroy(&instance->task_mgr_reset_lock); + ps3_mutex_destroy(&instance->task_abort_lock); + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + + return PS3_SUCCESS; +} + +void ps3_mgmt_info_init(void) +{ + ps3_mutex_init(&ps3_mgmt_info_get()->ps3_mgmt_lock); + INIT_LIST_HEAD(&ps3_mgmt_info_get()->instance_list_head); + + ps3_cli_debug_init(); + + return; +} + +void ps3_mgmt_exit(void) +{ + ps3_mutex_destroy(&ps3_mgmt_info_get()->ps3_mgmt_lock); +} + +#endif +void ps3_instance_init(struct ps3_instance *instance) +{ + memset(instance, 0, sizeof(struct ps3_instance)); + ps3_mutex_init(&instance->state_machine.lock); + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_INIT); + instance->state_machine.is_load = PS3_FALSE; + instance->state_machine.is_poweroff = PS3_FALSE; + instance->state_machine.is_pci_err_recovery = PS3_FALSE; +} + +S32 ps3_instance_state_transfer(struct ps3_instance *instance, + U32 exp_cur_state, U32 dest_state) +{ + U32 cur_state = 0; + ps3_mutex_lock(&instance->state_machine.lock); +#if 0 + 由于当前硬件不支持拦截dma等通路,只能通过硬复位 + 来防止片内踩主机内存,所以状态需要正常切换 + + if (!instance->state_machine.is_load) { + LOG_ERROR("hno:%u driver is unload or suspend!\n", + PS3_HOST(instance)); + goto l_fail; + } +#endif + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state != exp_cur_state) { + goto l_fail; + } + + switch(cur_state) { + case PS3_INSTANCE_STATE_INIT: + if ((dest_state == PS3_INSTANCE_STATE_READY) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_READY: + if ((dest_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_PCIE_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_PRE_OPERATIONAL: + if ((dest_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_SOFT_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_OPERATIONAL: + if ((dest_state == PS3_INSTANCE_STATE_SOFT_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_SUSPEND) || + (dest_state == PS3_INSTANCE_STATE_QUIT)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_SOFT_RECOVERY: + if ((dest_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) + || (dest_state == PS3_INSTANCE_STATE_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_RECOVERY: + if ((dest_state == PS3_INSTANCE_STATE_READY) + || (dest_state == PS3_INSTANCE_STATE_DEAD)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_SUSPEND: + if (dest_state == PS3_INSTANCE_STATE_READY) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_DEAD: + if (dest_state == PS3_INSTANCE_STATE_QUIT) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_QUIT: + goto l_fail; + case PS3_INSTANCE_STATE_PCIE_RECOVERY: + if (dest_state == PS3_INSTANCE_STATE_RECOVERY) { + goto l_success; + } else { + goto l_fail; + } + default: + goto l_fail; + } + +l_fail: + ps3_mutex_unlock(&instance->state_machine.lock); + LOG_ERROR("hno:%u state transfer NOK!" + "[exp_cur_state:%s][cur_state:%s][dest_state:%s]\n", + PS3_HOST(instance), + namePS3InstanceState(exp_cur_state), + namePS3InstanceState(cur_state), + namePS3InstanceState(dest_state)); + return -PS3_FAILED; +l_success: + ps3_atomic_set(&instance->state_machine.state, dest_state); + ps3_mutex_unlock(&instance->state_machine.lock); + LOG_INFO("hno:%u state transfer from %s to %s!\n", + PS3_HOST(instance), + namePS3InstanceState(cur_state), + namePS3InstanceState(dest_state)); + return PS3_SUCCESS; +} +S32 ps3_instance_no_lock_state_transfer(struct ps3_instance *instance, + U32 dest_state) +{ + U32 cur_state = 0; +#if 0 + 由于当前硬件不支持拦截dma等通路,只能通过硬复位 + 来防止片内踩主机内存,所以状态需要正常切换 + if (!instance->state_machine.is_load) { + LOG_ERROR("hno:%u driver is unload or suspend!\n", + PS3_HOST(instance)); + goto l_fail; + } +#endif + cur_state = ps3_atomic_read(&instance->state_machine.state); + if(cur_state == dest_state){ + goto l_success; + } + switch(cur_state) { + case PS3_INSTANCE_STATE_INIT: + if ((dest_state == PS3_INSTANCE_STATE_READY) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_READY: + if ((dest_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_PRE_OPERATIONAL: + if ((dest_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_SOFT_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_OPERATIONAL: + if ((dest_state == PS3_INSTANCE_STATE_SOFT_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_RECOVERY) || + (dest_state == PS3_INSTANCE_STATE_SUSPEND) || + (dest_state == PS3_INSTANCE_STATE_QUIT)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_SOFT_RECOVERY: + if ((dest_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) + || (dest_state == PS3_INSTANCE_STATE_RECOVERY)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_RECOVERY: + if ((dest_state == PS3_INSTANCE_STATE_READY) + || (dest_state == PS3_INSTANCE_STATE_DEAD)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_SUSPEND: + if (dest_state == PS3_INSTANCE_STATE_READY) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_DEAD: + if (dest_state == PS3_INSTANCE_STATE_QUIT) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_INSTANCE_STATE_QUIT: + goto l_fail; + case PS3_INSTANCE_STATE_PCIE_RECOVERY: + if (dest_state == PS3_INSTANCE_STATE_RECOVERY) { + goto l_success; + } else { + goto l_fail; + } + default: + goto l_fail; + } + +l_fail: + LOG_ERROR("hno:%u state transfer NOK!" + "[cur_state:%s][dest_state:%s]\n", + PS3_HOST(instance), + namePS3InstanceState(cur_state), + namePS3InstanceState(dest_state)); + return -PS3_FAILED; +l_success: + ps3_atomic_set(&instance->state_machine.state, dest_state); + LOG_INFO("hno:%u state transfer from %s to %s!\n", + PS3_HOST(instance), + namePS3InstanceState(cur_state), + namePS3InstanceState(dest_state)); + return PS3_SUCCESS; +} + +void ps3_instance_state_transfer_to_dead_nolock(struct ps3_instance *instance) +{ + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_DEAD); +} + +void ps3_instance_state_transfer_to_dead(struct ps3_instance *instance) +{ + ps3_mutex_lock(&instance->state_machine.lock); + if(ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_DEAD){ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_DEAD); + } + ps3_mutex_unlock(&instance->state_machine.lock); +} + +void ps3_instance_state_transfer_to_pcie_recovery(struct ps3_instance *instance) +{ + ps3_mutex_lock(&instance->state_machine.lock); + if(ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_PCIE_RECOVERY){ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_PCIE_RECOVERY); + } + ps3_mutex_unlock(&instance->state_machine.lock); +} + +void ps3_instance_state_transfer_to_quit(struct ps3_instance *instance) +{ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_QUIT); +} + +void ps3_instance_state_transfer_to_suspend(struct ps3_instance *instance) +{ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_SUSPEND); +} + +void ps3_instance_state_transition_to_recovery(struct ps3_instance *instance) +{ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_RECOVERY); +} + +S32 ps3_instance_wait_for_hard_reset_flag_done(struct ps3_instance *instance) +{ + U32 wait_cnt = PS3_INSTANCE_WAIT_TO_OPERATIONAL_MAX_SECS * 2; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + U32 idx = 0; + S32 ret = PS3_SUCCESS; + for (idx = 0;idx < wait_cnt;idx++) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if ((cur_state == PS3_INSTANCE_STATE_DEAD) || + (cur_state == PS3_INSTANCE_STATE_QUIT)){ + ret = -PS3_FAILED; + goto l_out; + } + ps3_mutex_lock(&instance->state_machine.lock); + if (instance->recovery_context->host_reset_state == PS3_HOST_RESET_HARD_RESET_DONE && + ps3_atomic_read(&instance->state_machine.state) == PS3_INSTANCE_STATE_OPERATIONAL){ + if(atomic_read(&instance->cmd_statistics.io_outstanding) != 0) { + ret = -PS3_RETRY; + } + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ps3_msleep(PS3_INSTANCE_STATE_CHECK_INTERVAL_MS); + } + + if (idx >= wait_cnt) { + LOG_WARN("hno:%u wait pre_operational timeout!\n", + PS3_HOST(instance)); + } + ps3_mutex_lock(&instance->state_machine.lock); + if (instance->recovery_context->host_reset_state != PS3_HOST_RESET_HARD_RESET_DONE) { + LOG_WARN("hno:%u wait host reset hard reset done NOK!\n", + PS3_HOST(instance)); + ret = -PS3_RETRY; + } + ps3_mutex_unlock(&instance->state_machine.lock); +l_out: + LOG_INFO("hno:%u wait hard reset flag %d!\n", PS3_HOST(instance), ret); + return ret; +} + +S32 ps3_instance_wait_for_dead_or_pre_operational(struct ps3_instance *instance) +{ + U32 wait_cnt = PS3_INSTANCE_WAIT_TO_OPERATIONAL_MAX_SECS * 3; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + U32 idx = 0; + + LOG_INFO("hno:%u wait dead or pre_operational begin\n", PS3_HOST(instance)); + for (idx = 0; idx < wait_cnt; idx++) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if ((cur_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_DEAD) || + (cur_state == PS3_INSTANCE_STATE_QUIT)) { + break; + } + + ps3_msleep(PS3_INSTANCE_STATE_CHECK_INTERVAL_MS); + } + + if (idx >= wait_cnt) { + LOG_WARN("hno:%u wait dead or pre_operational timeout!\n", + PS3_HOST(instance)); + } + + if ((cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL) && + (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) && + (cur_state != PS3_INSTANCE_STATE_DEAD)) { + LOG_WARN("hno:%u wait dead or pre_operational NOK!\n", + PS3_HOST(instance)); + return -PS3_FAILED; + + } + + LOG_INFO("hno:%u wait dead or pre_operational success!\n", PS3_HOST(instance)); + return PS3_SUCCESS; +} + +S32 ps3_instance_wait_for_operational(struct ps3_instance *instance, Bool is_hardreset) +{ + U32 wait_cnt = PS3_INSTANCE_WAIT_TO_OPERATIONAL_MAX_SECS * 3; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + U32 idx = 0; + S32 recovery_state = PS3_RESET_LOG_INTERVAL; + + for (idx = 0; idx < wait_cnt; idx++) { + if (!instance->state_machine.is_load) { + LOG_INFO("hno:%u instance state not is_load\n", PS3_HOST(instance)); + break; + } + + ps3_mutex_lock(&instance->state_machine.lock); + cur_state = ps3_atomic_read(&instance->state_machine.state); + recovery_state = instance->recovery_context->recovery_state; + if (((cur_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_DEAD) || + (cur_state == PS3_INSTANCE_STATE_QUIT)) && + (is_hardreset ? (recovery_state == PS3_HARD_RECOVERY_FINISH) : PS3_TRUE)) { + LOG_INFO("hno:%u wait break, cur_state: %s, recovery_state: %d, is_hardreset: %d\n", + PS3_HOST(instance), namePS3InstanceState(cur_state), recovery_state, is_hardreset); + ps3_mutex_unlock(&instance->state_machine.lock); + break; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ps3_msleep(PS3_INSTANCE_STATE_CHECK_INTERVAL_MS); + } + + if (idx >= wait_cnt) { + LOG_WARN("hno:%u wait operational timeout!\n", + PS3_HOST(instance)); + } + + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + LOG_WARN("hno:%u wait operational NOK, cur_state: %s, recovery_state: %d\n", + PS3_HOST(instance), namePS3InstanceState(cur_state), recovery_state); + return -PS3_FAILED; + + } + + LOG_INFO("hno:%u wait operational success!\n", PS3_HOST(instance)); + return PS3_SUCCESS; +} + +S32 ps3_instance_wait_for_normal(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 wait_cnt = PS3_INSTANCE_WAIT_TO_NORMAL_MAX_SECS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + U32 idx = 0; + Bool is_pci_err_recovery = PS3_FALSE; + + for (idx = 0; idx < wait_cnt; idx++) { + INJECT_START(PS3_ERR_IJ_V2_WAKE_RECOVERY_WAIT, instance); + INJECT_START(PS3_ERR_IJ_V2_FORCE_INSTANCE_WAIT_NORMAL, instance); + is_pci_err_recovery = ps3_pci_err_recovery_get(instance); + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_DEAD && + PS3_IOC_STATE_HALT_SUPPORT(instance) && + PS3_HALT_CLI_SUPPORT(instance)) { + goto l_out; + } + + if (ps3_state_is_normal(cur_state) || + cur_state == PS3_INSTANCE_STATE_QUIT || + cur_state == PS3_INSTANCE_STATE_DEAD || + is_pci_err_recovery) { + LOG_DEBUG("hno:%u cur state: %d, pci err recovery: %d\n", + PS3_HOST(instance), cur_state, is_pci_err_recovery); + break; + } + + if (!(idx % PS3_RESET_LOG_INTERVAL)) { + LOG_DEBUG("hno:%u state[%s] waiting for reset to finish\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + } +#ifdef PS3_HARDWARE_HAPS_V200 + ps3_msleep(PS3_INSTANCE_STATE_CHECK_NORMAL_INTERVAL_MS); + + if (ps3_get_wait_cli_flag()) { + LOG_DEBUG("hno:%u not wait cmd\n", PS3_HOST(instance)); + break; + } +#else + ps3_msleep(PS3_INSTANCE_STATE_CHECK_INTERVAL_MS); +#endif + } + + if (!ps3_state_is_normal(cur_state) || is_pci_err_recovery) { + LOG_WARN("hno:%u cannot handle cmd, driver state: %s, pci recovery: %d\n", + PS3_HOST(instance), namePS3InstanceState(cur_state), is_pci_err_recovery); + ret = -PS3_FAILED; + goto l_out; + } + +l_out: + return ret; +} + +S32 ps3_recovery_state_wait_for_normal(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 wait_cnt = PS3_INSTANCE_WAIT_TO_NORMAL_MAX_SECS; + S32 recovery_state = PS3_RESET_LOG_INTERVAL; + U32 idx = 0; + Bool is_pci_err_recovery = PS3_FALSE; + + for (idx = 0; idx < wait_cnt; idx++) { + recovery_state = instance->recovery_context->recovery_state; + is_pci_err_recovery = ps3_pci_err_recovery_get(instance); + + if ( recovery_state == PS3_HARD_RECOVERY_FINISH || + recovery_state == PS3_SOFT_RECOVERY_PROBE_PROCESS || + is_pci_err_recovery) { + LOG_DEBUG("hno:%u recovery state: %d, pci err recovery: %d\n", + PS3_HOST(instance), recovery_state, is_pci_err_recovery); + goto l_out; + } +#ifdef PS3_HARDWARE_HAPS_V200 + ps3_msleep(PS3_INSTANCE_STATE_CHECK_NORMAL_INTERVAL_MS); + + if (ps3_get_wait_cli_flag()) { + LOG_DEBUG("hno:%u not wait cmd\n", PS3_HOST(instance)); + break; + } +#else + ps3_msleep(PS3_INSTANCE_STATE_CHECK_INTERVAL_MS); +#endif + } + + ret = -PS3_FAILED; + LOG_WARN("hno:%u wait recovery time out, recovery_state: %d\n", + PS3_HOST(instance), recovery_state); +l_out: + if (is_pci_err_recovery) { + LOG_WARN("hno:%u cannot handle cmd, pci recovery: %d\n", + PS3_HOST(instance), is_pci_err_recovery); + ret = -PS3_FAILED; + } + return ret; +} + +void ps3_host_info_get(void) +{ +#if defined(CONFIG_X86) || defined(CONFIG_X86_64) + struct cpuinfo_x86 *cpu = NULL; + + memset(&g_ps3_host_info, 0, sizeof(struct ps3_host_info)); + cpu = &cpu_data(0); + g_ps3_host_info.machine = PS3_HOST_MACHINE_X86; + if (strstr(cpu->x86_vendor_id, "Intel")) { + g_ps3_host_info.vendor = PS3_HOST_VENDOR_INTEL; + } else if (strstr(cpu->x86_vendor_id, "Hygon")) { + g_ps3_host_info.vendor = PS3_HOST_VENDOR_HYGON; + } else if (strstr(cpu->x86_vendor_id, "AMD")) { + g_ps3_host_info.vendor = PS3_HOST_VENDOR_AMD; + } + g_ps3_host_info.processor_cnt = num_online_cpus(); +#else + memset(&g_ps3_host_info, 0, sizeof(struct ps3_host_info)); +#endif + + memset(g_ps3_host_info.release, 0, SYS_INFO_LEN + 1); + snprintf(g_ps3_host_info.release, SYS_INFO_LEN, "%s", utsname()->release); + + LOG_DEBUG("host info: machine=%u,vendor=%u,processor_cnt=%u release=%s\n", + g_ps3_host_info.machine, g_ps3_host_info.vendor, + g_ps3_host_info.processor_cnt, g_ps3_host_info.release); +} + +U16 ps3_host_vendor_get(void) +{ + return g_ps3_host_info.vendor; +} + +char* ps3_host_release_get(void) +{ + return g_ps3_host_info.release; +} + +U8 ps3_is_last_func(struct ps3_instance *instance) +{ + return (!ps3_ioc_multi_func_support(instance) || + (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_1)); +} diff --git a/drivers/scsi/ps3stor/ps3_instance_manager.h b/drivers/scsi/ps3stor/ps3_instance_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..868b9e38f634dae4bcd38657bd130f305b608ab7 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_instance_manager.h @@ -0,0 +1,493 @@ + +#ifndef _PS3_INSTANCE_MANAGER_H_ +#define _PS3_INSTANCE_MANAGER_H_ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include +#include "ps3_sas_transport.h" +#include "ps3_device_manager_sas.h" +#else +#include "ps3_pci.h" + +#endif + +#include "ps3_inner_data.h" +#include "ps3_irq.h" +#include "ps3_cmd_channel.h" +#include "ps3_platform_utils.h" +#include "ps3_cmd_channel.h" +#include "ps3_inner_data.h" +#include "ps3_debug.h" +#include "ps3_irq.h" +#include "ps3_recovery.h" +#include "ps3_dump.h" +#include "ps3_cmd_stat_def.h" +#include "ps3_watchdog.h" +#include "ps3_err_inject.h" +#include "ps3_qos.h" + +enum PS3_INSTANCE_STATE_TYPE { + PS3_INSTANCE_STATE_INIT = 0, + PS3_INSTANCE_STATE_READY = 1, + PS3_INSTANCE_STATE_PRE_OPERATIONAL = 2, + PS3_INSTANCE_STATE_OPERATIONAL = 3, + PS3_INSTANCE_STATE_SOFT_RECOVERY = 4, + PS3_INSTANCE_STATE_RECOVERY = 5, + PS3_INSTANCE_STATE_SUSPEND = 6, + PS3_INSTANCE_STATE_DEAD = 7, + PS3_INSTANCE_STATE_QUIT = 8, + PS3_INSTANCE_STATE_PCIE_RECOVERY = 9, + PS3_INSTANCE_STATE_COUNT = 10 +}; +enum PS3_DEVICE_ERR_HANDLE_STATE_TYPE { + PS3_DEVICE_ERR_STATE_NORMAL = 0, + PS3_DEVICE_ERR_STATE_CLEAN = 1, + PS3_DEVICE_ERR_STATE_INIT = 2, +}; + +struct ps3_instance_state_machine { + ps3_mutex lock; + ps3_atomic32 state; + Bool is_load; + Bool is_suspend; + Bool is_poweroff; + Bool is_pci_err_recovery; + Bool can_hostreset; +}; + +static inline const S8 *namePS3InstanceState(S32 s) +{ + static const S8 *myNames[] = { + [PS3_INSTANCE_STATE_INIT] = "PS3_INSTANCE_STATE_INIT", + [PS3_INSTANCE_STATE_READY] = "PS3_INSTANCE_STATE_READY", + [PS3_INSTANCE_STATE_PRE_OPERATIONAL] = "PS3_INSTANCE_STATE_PRE_OPERATIONAL", + [PS3_INSTANCE_STATE_OPERATIONAL] = "PS3_INSTANCE_STATE_OPERATIONAL", + [PS3_INSTANCE_STATE_SOFT_RECOVERY] = "PS3_INSTANCE_STATE_SOFT_RECOVERY", + [PS3_INSTANCE_STATE_RECOVERY] = "PS3_INSTANCE_STATE_RECOVERY", + [PS3_INSTANCE_STATE_SUSPEND] = "PS3_INSTANCE_STATE_SUSPEND", + [PS3_INSTANCE_STATE_DEAD] = "PS3_INSTANCE_STATE_DEAD", + [PS3_INSTANCE_STATE_QUIT] = "PS3_INSTANCE_STATE_QUIT", + [PS3_INSTANCE_STATE_PCIE_RECOVERY] = "PS3_INSTANCE_STATE_PCIE_RECOVERY" + }; + + if (s >= PS3_INSTANCE_STATE_COUNT) { + return "PS3_INSTANCE_STATE_INVALID"; + } + + return myNames[s]; +} + +struct ps3_recovery_function { + S32 (*recovery_handle_cb)(struct ps3_instance *instance, U8 reason); + S32 (*hardreset_handle_pre_cb)(struct ps3_instance *instance); + S32 (*hardreset_handle_wait_ready_cb)(struct ps3_instance *instance); + S32 (*hardreset_handle_init_running_cb)(struct ps3_instance *instance); + S32 (*hardreset_handle_post_cb)(struct ps3_instance *instance); + S32 (*hardreset_handle_finish_cb)(struct ps3_instance *instance); + S32 (*hardreset_handle_offline_cb)(struct ps3_instance *instance); + S32 (*softreset_handle_pre_cb)(struct ps3_instance *instance); + S32 (*softreset_handle_post_cb)(struct ps3_instance *instance); + S32 (*halt_handle_cb)(struct ps3_instance *instance); +}; + +struct ps3_instance { + ps3_list_head list_item; + struct ps3_instance *peer_instance; +#ifndef _WINDOWS + struct pci_dev *pdev; + struct Scsi_Host *host; +#else + ULong bus_number; + struct ps3_pci_context pci_dev_context; +#endif + Ps3Fifo_s __iomem *reg_set; + ps3_atomic32 watchdog_reg_read_fail_count; + + struct ps3_cmd_context cmd_context; + struct ps3_irq_context irq_context; + struct ps3_dev_context dev_context; +#ifndef _WINDOWS + struct ps3_sas_dev_context sas_dev_context; +#endif + struct ps3_event_context event_context; + struct ps3_webSubscribe_context webSubscribe_context; + + struct ps3_fault_context fault_context; + + struct ps3_watchdog_context watchdog_context; + struct ps3_dump_context dump_context; + struct ps3_debug_context debug_context; + struct ps3_cmd_statistics_context cmd_statistics; + struct PS3IocCtrlInfo ctrl_info; + struct PS3IocCtrlInfo *ctrl_info_buf; + +#ifdef _WINDOWS + ps3_atomic32 ioctl_count; +#else + struct semaphore ioctl_sem; +#endif + struct ps3_ioc_adp_template *ioc_adpter; + struct ps3_cmd_attr_context cmd_attr; + struct PS3MgrEvent event_req_info; + + ps3_spinlock req_queue_lock; + + dma_addr_t ctrl_info_buf_h; + dma_addr_t drv_info_buf_phys; + U8 *drv_info_buf; + dma_addr_t host_mem_info_buf_phys; + U8 *host_mem_info_buf; + U32 max_mgr_cmd_total_count; + U32 max_mgr_cmd_count; + U32 max_task_cmd_count; + U32 min_intr_count; + U8 reserve[4]; + U32 reply_fifo_depth_addition; + + ULong reg_bar; + Bool is_support_sync_cache; + Bool is_use_frontend_prp; + U8 dma_mask; + Bool is_support_jbod; + Bool use_clusting; + Bool is_adjust_register_count; + Bool is_scan_host_finish; + Bool is_probe_finish; + Bool is_probe_failed; + Bool is_suspend; + Bool is_resume; + Bool is_hard_reset; + Bool is_pci_reset; + Bool is_ioc_halt_support; + Bool is_shallow_soft_recovery_support; + Bool is_deep_soft_recovery_support; + Bool is_hard_recovery_support; + Bool is_halt_support_cli; + Bool is_half_hard_reset; + Bool is_host_added; + Bool is_need_event; + Bool is_raid1_direct_skip_mapblock_check; + Bool is_single_disk_raid0_direct_skip_strip_check; + Bool is_support_dump_ctrl; + Bool is_support_io_limit; + Bool task_manager_host_busy; + U8 hilMode; + Bool is_irq_prk_support; + Bool is_support_irq; + Bool is_raid; + Bool smp_affinity_enable; + Bool msix_combined; + U8 reserved[2]; + U16 unload_timeout; + U16 wait_ready_timeout; + U16 dev_id; + U8 dma_addr_bit_pos; + U8 pci_err_handle_state; + const char *product_model; + S64 __percpu *scsi_cmd_deliver; + + U64 ioc_fw_version; + ps3_mutex task_mgr_reset_lock; +#ifdef _WINDOWS + STOR_DPC device_reset_dpc; +#endif + Bool page_mode_change; + U64 page_mode_addr_mask; + ps3_atomic32 is_err_scsi_processing; + ps3_atomic32 reg_op_count; + ps3_atomic32 host_reset_processing; + ps3_atomic32 watchdog_ref; + struct ps3_instance_state_machine state_machine; + struct ps3_recovery_context *recovery_context; + struct ps3_recovery_function recovery_function; +#ifndef _WINDOWS + struct work_struct recovery_irq_work; + struct workqueue_struct *recovery_irq_queue; + U8 recovery_irq_enable; + Bool is_print_special_log; + U8 reserved2[2]; + U32 hard_dog_mask; +#endif + volatile U32 hardreset_event; + struct ps3_qos_context qos_context; + ps3_mutex task_abort_lock; + U8 r1x_mode; + U64 start_pfn; + U64 end_pfn; + U64 so_start_addr; + U64 so_end_addr; + S32 device_busy_threshold; +}; + +#ifndef _WINDOWS +struct ps3_mgmt_info { + ps3_mutex ps3_mgmt_lock; + ps3_list_head instance_list_head; +}; + +enum { + PS3_HOST_MACHINE_DEFAULT, + PS3_HOST_MACHINE_X86 = 0, + PS3_HOST_MACHINE_ARM, + PS3_HOST_MACHINE_MIPS, + PS3_HOST_MACHINE_COUNT, +}; + +enum { + PS3_HOST_VENDOR_DEFAULT, + PS3_HOST_VENDOR_INTEL = 0, + PS3_HOST_VENDOR_HYGON, + PS3_HOST_VENDOR_AMD, + PS3_HOST_VENDOR_COUNT, +}; + +#define SYS_INFO_LEN (64) +struct ps3_host_info { + U8 machine; + U8 vendor; + U16 cpu_cnt; + U16 core_cnt; + U16 processor_cnt; + char release[SYS_INFO_LEN + 1]; +}; + +struct ps3_mgmt_info* ps3_mgmt_info_get(void); + +struct ps3_instance *ps3_instance_lookup(U16 host_no); + +S32 ps3_instance_add(struct ps3_instance *instance); + +S32 ps3_instance_remove(struct ps3_instance *instance); + +void ps3_mgmt_info_init(void); + +void ps3_mgmt_exit(void); + +#endif + +void ps3_instance_init(struct ps3_instance *instance); + +S32 ps3_instance_state_transfer(struct ps3_instance *instance, + U32 exp_cur_state, U32 dest_state); +S32 ps3_instance_no_lock_state_transfer(struct ps3_instance *instance, + U32 dest_state); + +void ps3_instance_state_transfer_to_dead_nolock(struct ps3_instance *instance); + +void ps3_instance_state_transfer_to_dead(struct ps3_instance *instance); + +void ps3_instance_state_transfer_to_pcie_recovery(struct ps3_instance *instance); + +void ps3_instance_state_transfer_to_quit(struct ps3_instance *instance); + +void ps3_instance_state_transfer_to_suspend(struct ps3_instance *instance); + +void ps3_instance_state_transition_to_recovery(struct ps3_instance *instance); + +S32 ps3_instance_wait_for_operational(struct ps3_instance *instance, Bool is_hardreset); +S32 ps3_instance_wait_for_hard_reset_flag_done(struct ps3_instance *instance); + +S32 ps3_instance_wait_for_dead_or_pre_operational(struct ps3_instance *instance); + +static inline Bool ps3_is_instance_state_normal(struct ps3_instance *instance, Bool need_prk_err) +{ + S32 cur_state = ps3_atomic_read(&instance->state_machine.state); + INJECT_START(PS3_ERR_IJ_SAS_REQ_PRE_CHECK, &cur_state) + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_SOFT_RECOVERY) { + LOG_WARN_LIM_WITH_CHECK(instance, need_prk_err, "hno:%u instance exception state %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + + return PS3_FALSE; + } + + return PS3_TRUE; +} + +static inline void ps3_pci_err_recovery_set(struct ps3_instance *instance, Bool state) +{ + instance->state_machine.is_pci_err_recovery = state; +} + +static inline Bool ps3_pci_err_recovery_get(struct ps3_instance *instance) +{ + return instance->state_machine.is_pci_err_recovery; +} +static inline Bool ps3_need_block_hard_reset_request(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN_LIM("hno[%u], host in pci recovery during reset request\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto end; + } + ps3_mutex_lock(&instance->state_machine.lock); + if(instance->recovery_context->host_reset_state != PS3_HOST_RESET_INIT) { + ps3_mutex_unlock(&instance->state_machine.lock); + LOG_WARN_LIM("hno[%u], host in host reset during reset request\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto end; + } + ps3_mutex_unlock(&instance->state_machine.lock); +end: + return ((ret == PS3_SUCCESS) ? PS3_FALSE:PS3_TRUE); +} +static inline void ps3_need_wait_hard_reset_request(struct ps3_instance *instance) +{ + do { + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN_LIM("hno[%u], host in pci recovery during reset request\n", + PS3_HOST(instance)); + ps3_msleep(100); + continue; + } + ps3_mutex_lock(&instance->state_machine.lock); + if(instance->recovery_context->host_reset_state != PS3_HOST_RESET_INIT) { + ps3_mutex_unlock(&instance->state_machine.lock); + LOG_WARN_LIM("hno[%u], host in host reset during reset request\n", + PS3_HOST(instance)); + ps3_msleep(100); + continue; + } + ps3_mutex_unlock(&instance->state_machine.lock); + break; + } while (1); +} + +static inline Bool ps3_state_is_normal(S32 cur_state) +{ + return (cur_state != PS3_INSTANCE_STATE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL) ? + PS3_FALSE : PS3_TRUE; +} + +S32 ps3_instance_wait_for_normal(struct ps3_instance *instance); + +S32 ps3_recovery_state_wait_for_normal(struct ps3_instance *instance); + +struct ps3_ioc_adp_template { + S32 (*io_cmd_build)(struct ps3_cmd *cmd); + S32 (*mgr_cmd_build)(struct ps3_instance *instance, + struct ps3_cmd *cmd); + void (*init_cmd_send)(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word); + void (*cmd_send)(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word); + U32 (*ioc_state_get)(struct ps3_instance *instance); + S32 (*ioc_init_state_to_ready)(struct ps3_instance *instance); + S32 (*ioc_init_proc)(struct ps3_instance *instance); + void (*ioc_resource_prepare)(struct ps3_instance *instance); + S32 (*ioc_hard_reset)(struct ps3_instance *instance); + S32 (*ioc_shallow_soft_reset)(struct ps3_instance *instance); + S32 (*ioc_deep_soft_reset)(struct ps3_instance *instance); + S32 (*ioc_force_to_fault)(struct ps3_instance *instance); + S32 (*ioc_force_to_halt)(struct ps3_instance *instance); + S32 (*irq_init)(struct ps3_instance *instance); + void (*irq_enable)(struct ps3_instance *instance); + void (*irq_disable)(struct ps3_instance *instance); +#ifndef _WINDOWS + irqreturn_t (*isr)(int irq_no, void *data); + struct scsi_transport_template *(*sas_transport_get)(void); +#else + U8(*isr)(void *instance, ULong irq_no); +#endif + void (*event_filter_table_get)(U8 *data); + void (*reg_write)(struct ps3_instance *instance, U64 val, void __iomem *reg); + U64 (*reg_read)(struct ps3_instance *instance, void __iomem *reg); + Bool (*is_need_direct_to_normal)(const struct ps3_cmd *cmd); + Bool (*max_replyq_count_get)(struct ps3_instance *instance, + U32 *max_replyq_count); + void (*check_vd_member_change)(struct ps3_instance *instance, + struct ps3_pd_entry *local_entry); + Bool (*scsih_stream_is_detect)(struct ps3_cmd *cmd); + Bool (*scsih_stream_is_direct)(const struct ps3_cmd *cmd); + U32 (*ioc_heartbeat_detect)(struct ps3_instance *instance); + void __iomem * (*reg_set)(struct pci_dev *pdev, ULong reg_bar); + Bool (*ioc_security_check)(struct ps3_instance *instance); + void (*io_cmd_rebuild)(struct ps3_cmd *cmd); + Bool (*rw_cmd_is_need_split)(struct ps3_cmd *cmd); + Bool (*write_direct_enable)(struct ps3_cmd *cmd); + Bool (*ssd_vd_qmask_calculate)(struct ps3_cmd *cmd); +}; +#define PS3_DEVICE_IS_SWITCH(id) ((id == PCI_DEVICE_ID_PS3_SWITCH || \ + id == PCI_DEVICE_ID_PS3_SWITCH_FPGA)) + +#ifndef _WINDOWS +void ps3_ioc_adp_init(struct ps3_instance *instance, const struct pci_device_id *id); + +void ps3_remove(struct pci_dev *pdev); + +#else +void ps3_ioc_adp_init(struct ps3_instance *instance); +#endif + +static inline S32 ps3_get_pci_function(struct pci_dev *pci) +{ + return (PCI_FUNC(pci->devfn)); +} + +static inline S32 ps3_get_pci_slot(struct pci_dev * pci) +{ + return (PCI_SLOT(pci->devfn)); +} + +static inline S32 ps3_get_pci_bus(struct pci_dev * pci) +{ + return (pci->bus->number); +} + +static inline S32 ps3_get_pci_domain(struct pci_dev * pci) +{ + return pci_domain_nr(pci->bus); +} + +static inline bool ps3_is_latest_func(struct ps3_instance *instance) +{ + bool ret = PS3_TRUE; + struct ps3_instance *peer_instance = NULL; + + list_for_each_entry(peer_instance, &ps3_mgmt_info_get()->instance_list_head, list_item) { + if ((peer_instance != NULL) && + (ps3_get_pci_domain(peer_instance->pdev) == ps3_get_pci_domain(instance->pdev)) && + (PCI_BUS_NUM(peer_instance->pdev->devfn) == PCI_BUS_NUM(instance->pdev->devfn)) && + (PCI_SLOT(peer_instance->pdev->devfn) == PCI_SLOT(instance->pdev->devfn)) && + (PCI_FUNC(peer_instance->pdev->devfn) != PCI_FUNC(instance->pdev->devfn))) { + ret = PS3_FALSE; + } + } + + return ret; +} + +static inline void ps3_get_so_addr_ranger(struct ps3_instance *instance, + U64 addr, U32 offset) +{ + U64 so_end_addr = (addr + offset) - 1; + if (instance->so_start_addr == 0 && instance->so_end_addr == 0) { + instance->so_start_addr = addr; + instance->so_end_addr = so_end_addr; + goto l_out; + } + instance->so_start_addr = ((addr < instance->so_start_addr) ? addr : instance->so_start_addr); + instance->so_end_addr = ((so_end_addr > instance->so_end_addr) ? so_end_addr : instance->so_end_addr); +l_out: + return; +} + +void ps3_host_info_get(void); + +U16 ps3_host_vendor_get(void); + +char* ps3_host_release_get(void); + +U8 ps3_is_last_func(struct ps3_instance *instance); +#endif diff --git a/drivers/scsi/ps3stor/ps3_io_trace.c b/drivers/scsi/ps3stor/ps3_io_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..6b41c234508947b9d58724f0f348231a684db9dc --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_io_trace.c @@ -0,0 +1,126 @@ +#ifndef _WINDOWS +#include +#include +#include +#endif +#include "ps3_instance_manager.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_io_trace.h" + +static inline const char *ps3_io_trace_direct_name(ps3_io_trace_dtype type) +{ + static const char *direct_name[] = { + "cmd send", + "cmd recv", + "unknown" + }; + if(type >= PS3_IO_TRACE_DIRECT_COUNT) { + return direct_name[PS3_IO_TRACE_DIRECT_COUNT]; + } + return direct_name[type]; +} +#ifndef _WINDOWS +static inline Bool ps3_is_scsi_read_cmd(struct scsi_cmnd *s_cmnd) +{ + return (s_cmnd != NULL && s_cmnd->sc_data_direction == DMA_FROM_DEVICE && + (s_cmnd->cmnd[0] == READ_6 || s_cmnd->cmnd[0] == READ_10 || + s_cmnd->cmnd[0] == READ_12 || s_cmnd->cmnd[0] == READ_16)); +} + +static inline Bool ps3_is_scsi_write_cmd(struct scsi_cmnd *s_cmnd) +{ + return (s_cmnd != NULL && s_cmnd->sc_data_direction == DMA_TO_DEVICE && + (s_cmnd->cmnd[0] == WRITE_6 || s_cmnd->cmnd[0] == WRITE_10 || + s_cmnd->cmnd[0] == WRITE_12 || s_cmnd->cmnd[0] == WRITE_16)); +} + +static void ps3_scsi_sgl_crc(const struct ps3_cmd *cmd) +{ + U32 sge_count = 0; + U32 i = 0; + U32 crc = 0; + U32 seed = 0x1234; + S8 *pdata = NULL; + U32 buf_len = 0; + S8 buf[PS3_IO_TRACE_BUF_LEN] = { 0 }; + struct scatterlist *os_sgl = NULL; + struct ps3_instance *instance = cmd->instance; + struct scsi_cmnd *s_cmnd = cmd->scmd; + + if (instance->debug_context.io_trace_switch == PS3_FALSE) { + goto l_out; + } + + sge_count = cmd->os_sge_map_count; + scsi_for_each_sg(s_cmnd, os_sgl, sge_count, i) { + pdata = (S8 *)sg_virt(os_sgl); + crc = crc32(seed, pdata, sg_dma_len(os_sgl)); + + memset(buf, '\0', sizeof(buf)); + buf_len = snprintf(buf, PS3_IO_TRACE_BUF_LEN, + "hno:%u channel[%u], target[%u]," + "trace_id[0x%llx], [%u of %u]sge, sge data addr[0x%llx] length[%u], " + "D[%llx:%llx] CRC[0x%x] \n", + PS3_HOST(instance), s_cmnd->device->channel, s_cmnd->device->id, + cmd->trace_id, + i + 1, sge_count, sg_dma_address(os_sgl), + sg_dma_len(os_sgl), *(U64*)pdata, *((U64 *)(pdata + 8)), crc); + if (buf_len >= PS3_IO_TRACE_BUF_LEN) { + LOG_ERROR("buf_len > PS3_IO_TRACE_BUF_LEN\n"); + goto l_out; + } + DATA_DUMP(NULL, 0, buf); + } + +l_out: + return; +} +#endif +void ps3_scsih_io_trace(const struct ps3_cmd *cmd, ps3_io_trace_dtype type) +{ + S32 buf_len = 0; + char buf[PS3_IO_TRACE_BUF_LEN] = { 0 }; + U64 lba = 0; + + if (cmd == NULL || cmd->scmd == NULL) { + LOG_WARN("cmd or scmd is null\n"); + goto l_out; + } + if (scsi_sg_count(cmd->scmd) == 0) { + goto l_out; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) + if (cmd->scmd->cmnd == NULL || cmd->instance->host == NULL) { + LOG_WARN("cdb null\n"); + goto l_out; + } +#else + if (cmd->instance->host == NULL) { + LOG_WARN("cdb null\n"); + goto l_out; + } +#endif + + if ((type == PS3_IO_TRACE_DIRECT_SEND && ps3_is_scsi_write_cmd(cmd->scmd)) || + (type == PS3_IO_TRACE_DIRECT_RECV && ps3_is_scsi_read_cmd(cmd->scmd))){ + ps3_scsi_sgl_crc(cmd); + } + + ps3_scsih_lba_parse(cmd->scmd->cmnd, &lba); + memset(buf, '\0', sizeof(buf)); + buf_len = snprintf(buf, PS3_IO_TRACE_BUF_LEN, + "%s, trace_id[0x%llx], hno:%u lba[0x%llx]\n", + ps3_io_trace_direct_name(type), cmd->trace_id, PS3_HOST(cmd->instance), lba); + if (buf_len >= PS3_IO_TRACE_BUF_LEN) { + LOG_ERROR("buf_len > PS3_IO_TRACE_BUF_LEN\n"); + goto l_out; + } + DATA_DUMP(sg_virt(cmd->scmd->sdb.table.sgl), + min_t(U32, cmd->scmd->sdb.table.sgl[0].length, + PS3_IO_TRACE_PRINT_COUNT), buf); + +l_out: + return; +} + diff --git a/drivers/scsi/ps3stor/ps3_io_trace.h b/drivers/scsi/ps3stor/ps3_io_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..3675dad01f6ed69d86772019e11b153a90f59d75 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_io_trace.h @@ -0,0 +1,24 @@ + +#ifndef _PS3_IO_TRACE_H_ +#define _PS3_IO_TRACE_H_ + +#include "ps3_cmd_channel.h" + +#define PS3_IO_TRACE_PRINT_COUNT (32) +#define PS3_IO_TRACE_BUF_LEN (256) + +typedef enum { + PS3_IO_TRACE_DIRECT_SEND, + PS3_IO_TRACE_DIRECT_RECV, + PS3_IO_TRACE_DIRECT_COUNT, +}ps3_io_trace_dtype; + +void ps3_scsih_io_trace(const struct ps3_cmd *cmd, ps3_io_trace_dtype type); +#define PS3_IO_TRACE(cmd, type) do { \ + if ((cmd)->instance->debug_context.io_trace_switch == PS3_FALSE) { \ + break; \ + } \ + ps3_scsih_io_trace((cmd),(type)); \ +} while(0); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_ioc_adp.c b/drivers/scsi/ps3stor/ps3_ioc_adp.c new file mode 100644 index 0000000000000000000000000000000000000000..da0f02482ffa188a1e7ca803d8f2de7ee943dbdd --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioc_adp.c @@ -0,0 +1,445 @@ +#ifdef _WINDOWS +#include "ps3_def.h" +#endif + +#include "ps3_instance_manager.h" +#include "ps3_ioc_state.h" +#include "ps3_irq.h" +#include "ps3_ioc_manager.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_scsih.h" +#include "ps3_inner_data.h" +#include "ps3_event.h" +#include "ps3_device_update.h" +#include "ps3_pci.h" +#include "ps3_module_para.h" +#include "ps3_scsih.h" + +#define MAX_MGR_CMD_COUNT (8) +#define MAX_TASK_CMD_COUNT (8) +#define MIN_MSIX_INT_COUNT (1) +#define PS3_HARD_DOG_MASK (0xF000000UL) + +#define SWITCH_MAX_MGR_CMD_COUNT (12) +#define SWITCH_MAX_TASK_CMD_COUNT (2) +#define SWITCH_MAX_MGR_CMD_TOTAL_COUNT (14) +#define SWITCH_MIN_MSI_INT_COUNT (1) +#define SWITCH_REPLY_FIFO_DEP_ADDITION (1) +#define PS3_HARD_DOG_MASK_SWITCH (0x1000000UL) + +struct ps3_ioc_adp_temp_entry { + U16 device_id; + struct ps3_ioc_adp_template *adp_template; +}; + +void ps3_ioc_resource_prepare_switch(struct ps3_instance *instance) +{ + struct PS3MgrEvent *event_req_info = &instance->event_req_info; + + memset(event_req_info, 0, sizeof(struct PS3MgrEvent)); + + event_req_info->eventTypeMap = PS3_EVT_PD_COUNT; + event_req_info->eventLevel = PS3_EVENT_LEVEL_INFO; + event_req_info->eventTypeMapProcResult = PS3_EVT_ILLEGAL_TYPE; + + instance->max_mgr_cmd_total_count = SWITCH_MAX_MGR_CMD_TOTAL_COUNT; + instance->max_mgr_cmd_count = SWITCH_MAX_MGR_CMD_COUNT; + instance->max_task_cmd_count = SWITCH_MAX_TASK_CMD_COUNT; + instance->min_intr_count = SWITCH_MIN_MSI_INT_COUNT; + instance->reply_fifo_depth_addition = SWITCH_REPLY_FIFO_DEP_ADDITION; + instance->is_support_jbod = PS3_TRUE; + instance->use_clusting = PS3_TRUE; + instance->is_use_frontend_prp = PS3_FALSE; + instance->is_adjust_register_count = PS3_FALSE; + instance->is_probe_finish = PS3_FALSE; + instance->is_probe_failed = PS3_FALSE; + instance->is_suspend = PS3_FALSE; + instance->is_resume = PS3_FALSE; + instance->is_hard_reset = PS3_FALSE; + instance->is_pci_reset = PS3_FALSE; + instance->ioc_fw_version = 0; + instance->hilMode = HIL_MODEL_SW; + instance->unload_timeout = PS3_DEFAULT_MGR_CMD_TIMEOUT; + instance->wait_ready_timeout = PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_SWITCH; + instance ->is_half_hard_reset = PS3_FALSE; + instance->is_need_event = PS3_FALSE; + instance->is_raid1_direct_skip_mapblock_check = PS3_FALSE; + instance->is_single_disk_raid0_direct_skip_strip_check = PS3_FALSE; + instance->is_support_dump_ctrl = PS3_FALSE; + instance->is_support_io_limit = PS3_FALSE; + instance->is_irq_prk_support = PS3_FALSE; + instance->is_support_irq = PS3_FALSE; + instance->is_raid = PS3_FALSE; + instance->hard_dog_mask = PS3_HARD_DOG_MASK_SWITCH; + instance->task_manager_host_busy = PS3_FALSE; + instance->is_print_special_log = PS3_FALSE; + instance->r1x_mode = PS3_R1X_MODE_NORMAL; + instance->smp_affinity_enable = ps3_smp_affinity_query(); + instance->page_mode_change = + ps3_host_vendor_get() == PS3_HOST_VENDOR_INTEL ? PS3_FALSE : PS3_TRUE; + instance->page_mode_addr_mask = PS3_PAGE_MODE_ABOVE_3_ADDR_MASK; + ps3_mutex_init(&instance->task_mgr_reset_lock); + ps3_mutex_init(&instance->task_abort_lock); +} + +void ps3_ioc_resource_prepare_raid(struct ps3_instance *instance) +{ + struct PS3MgrEvent *event_req_info = &instance->event_req_info; + + memset(event_req_info, 0, sizeof(struct PS3MgrEvent)); + + event_req_info->eventTypeMap = + PS3_EVT_PD_COUNT | + PS3_EVT_VD_COUNT | + PS3_EVT_CTRL_INFO | + PS3_EVT_PD_ATTR; + + event_req_info->eventLevel = PS3_EVENT_LEVEL_INFO; + event_req_info->eventTypeMapProcResult = PS3_EVT_ILLEGAL_TYPE; + + instance->max_mgr_cmd_total_count = MAX_MGR_CMD_TOTAL_COUNT; + instance->max_mgr_cmd_count = MAX_MGR_CMD_COUNT; + instance->max_task_cmd_count = MAX_TASK_CMD_COUNT; + instance->min_intr_count = MIN_MSIX_INT_COUNT; + instance->is_support_jbod = PS3_TRUE; + instance->use_clusting = (ps3_use_clustering_query() == PS3_TRUE); + instance->is_use_frontend_prp = PS3_FALSE; + instance->is_adjust_register_count = PS3_TRUE; + instance->is_probe_finish = PS3_FALSE; + instance->is_probe_failed = PS3_FALSE; + instance->is_suspend = PS3_FALSE; + instance->is_resume = PS3_FALSE; + instance->is_hard_reset = PS3_FALSE; + instance->is_pci_reset = PS3_FALSE; + instance->ioc_fw_version = 0; + instance->hilMode = HIL_MODEL_HW_ENHANCED; + instance->unload_timeout = PS3_RAID_UNLOAD_MGR_CMD_TIMEOUT; +#ifdef PS3_HARDWARE_HAPS_V200 + instance->wait_ready_timeout = PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_RAID_HAPS; +#else + instance->wait_ready_timeout = PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_RAID; +#endif + instance ->is_half_hard_reset = PS3_FALSE; + instance->is_need_event = PS3_TRUE; + instance->is_raid1_direct_skip_mapblock_check = PS3_FALSE; + instance->is_single_disk_raid0_direct_skip_strip_check = PS3_FALSE; + instance->is_support_dump_ctrl = PS3_TRUE; + instance->is_support_io_limit = PS3_TRUE; + instance->is_irq_prk_support = PS3_FALSE; + instance->is_support_irq = PS3_FALSE; + instance->is_raid = PS3_TRUE; + instance->hard_dog_mask = PS3_HARD_DOG_MASK; + instance->is_print_special_log = PS3_FALSE; + instance->r1x_mode = PS3_R1X_MODE_NORMAL; + instance->task_manager_host_busy = PS3_FALSE; + instance->smp_affinity_enable = ps3_smp_affinity_query(); + instance->page_mode_change = + ps3_host_vendor_get() == PS3_HOST_VENDOR_INTEL ? PS3_FALSE : PS3_TRUE; + instance->page_mode_addr_mask = PS3_PAGE_MODE_ABOVE_3_ADDR_MASK; + ps3_mutex_init(&instance->task_mgr_reset_lock); + ps3_mutex_init(&instance->task_abort_lock); + ps3_raid_qos_prepare(instance); +} + +void ps3_ioc_resource_prepare_hba(struct ps3_instance *instance) +{ + struct PS3MgrEvent *event_req_info = &instance->event_req_info; + + memset(event_req_info, 0, sizeof(struct PS3MgrEvent)); + + event_req_info->eventTypeMap = + PS3_EVT_PD_COUNT | + PS3_EVT_VD_COUNT | + PS3_EVT_CTRL_INFO | + PS3_EVT_SAS_INFO | + PS3_EVT_PD_ATTR; + + event_req_info->eventLevel = PS3_EVENT_LEVEL_INFO; + event_req_info->eventTypeMapProcResult = PS3_EVT_ILLEGAL_TYPE; + + instance->max_mgr_cmd_total_count = MAX_MGR_CMD_TOTAL_COUNT; + instance->max_mgr_cmd_count = MAX_MGR_CMD_COUNT; + instance->max_task_cmd_count = MAX_TASK_CMD_COUNT; + instance->min_intr_count = MIN_MSIX_INT_COUNT; + instance->is_support_jbod = PS3_FALSE; + instance->use_clusting = (ps3_use_clustering_query() == PS3_TRUE); + instance->is_use_frontend_prp = PS3_TRUE; + instance->is_adjust_register_count = PS3_TRUE; + instance->is_probe_finish = PS3_FALSE; + instance->is_probe_failed = PS3_FALSE; + instance->is_suspend = PS3_FALSE; + instance->is_resume = PS3_FALSE; + instance->is_scan_host_finish = PS3_FALSE; + instance->is_hard_reset = PS3_FALSE; + instance->is_pci_reset = PS3_FALSE; + instance->is_halt_support_cli = PS3_FALSE; + ps3_atomic_set(&instance->reg_op_count, 0); + instance->ioc_fw_version = 0; + instance->hilMode = HIL_MODEL_HW_ENHANCED; + instance->unload_timeout = PS3_UNLOAD_MGR_CMD_TIMEOUT; + instance->wait_ready_timeout = PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_HBA; + instance ->is_half_hard_reset = PS3_FALSE; + instance->is_need_event = PS3_TRUE; + instance->is_raid1_direct_skip_mapblock_check = PS3_TRUE; + instance->is_single_disk_raid0_direct_skip_strip_check = PS3_TRUE; + instance->is_support_dump_ctrl = PS3_TRUE; + instance->is_support_io_limit = PS3_FALSE; + instance->is_irq_prk_support = PS3_FALSE; + instance->is_support_irq = PS3_FALSE; + instance->is_raid = PS3_FALSE; + instance->hard_dog_mask = PS3_HARD_DOG_MASK; + instance->is_print_special_log = PS3_FALSE; + instance->smp_affinity_enable = ps3_smp_affinity_query(); + ps3_atomic_set(&instance->host_reset_processing, 0); + instance->task_manager_host_busy = PS3_FALSE; + instance->r1x_mode = PS3_R1X_MODE_NORMAL; + instance->page_mode_change = + ps3_host_vendor_get() == PS3_HOST_VENDOR_INTEL ? PS3_FALSE : PS3_TRUE; + instance->page_mode_addr_mask = PS3_PAGE_MODE_ABOVE_3_ADDR_MASK; + ps3_mutex_init(&instance->task_mgr_reset_lock); + ps3_mutex_init(&instance->task_abort_lock); + ps3_hba_qos_prepare(instance); +} + +static Bool ps3_replyq_count_raidhba_get(struct ps3_instance *instance, + U32 *max_replyq_count) +{ + Bool ret = PS3_TRUE; + if (!ps3_max_replyq_count_get(instance, max_replyq_count)) { + LOG_ERROR("hno:%u ps3_max_replyq_count_get NOK!\n", + PS3_HOST(instance)); + ret = PS3_FALSE; + goto l_out; + } + *max_replyq_count += PS3_RAIDHBA_NUM_ADJUST_VALUE; + *max_replyq_count = *max_replyq_count > PS3_MAX_REPLY_QUE_COUNT ? + PS3_MAX_REPLY_QUE_COUNT : *max_replyq_count; +l_out: + return ret; +} + +static Bool ps3_is_need_direct_to_normal_hba(const struct ps3_cmd *cmd) +{ + Bool ret = PS3_TRUE; + + if (ps3_direct_to_normal_query()) { + ret = PS3_TRUE; + goto l_out; + } + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_NVME_SSD) { + ret = PS3_TRUE; + goto l_out; + } + + if (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD) { + ret = PS3_FALSE; + goto l_out; + } + + if (unlikely(cmd->io_attr.vd_entry == NULL)) { + ret = PS3_FALSE; + goto l_out; + } + + if (cmd->io_attr.vd_entry->isNvme) { + ret = PS3_TRUE; + goto l_out; + } + +l_out: + return ret; +} + +static Bool ps3_is_need_direct_to_normal_raid(const struct ps3_cmd *cmd) +{ + (void)cmd; + return PS3_TRUE; +} + +static Bool ps3_is_need_direct_to_normal_switch(const struct ps3_cmd *cmd) +{ + (void)cmd; + return PS3_FALSE; +} + +struct ps3_ioc_adp_template g_ps3_template_switch = { + .io_cmd_build = ps3_scsih_cmd_build, + .mgr_cmd_build = NULL, + .init_cmd_send = ps3_switch_init_cmd_send, + .cmd_send = ps3_switch_normal_cmd_send, + .ioc_state_get = ps3_ioc_state_get, + .ioc_init_state_to_ready = ps3_ioc_init_to_ready, + .ioc_init_proc = ps3_ioc_init_proc, + .ioc_resource_prepare = ps3_ioc_resource_prepare_switch, + .ioc_hard_reset = ps3_ioc_state_hard_reset, + .ioc_shallow_soft_reset = ps3_ioc_state_shallow_soft_reset, + .ioc_deep_soft_reset = ps3_ioc_state_deep_soft_reset, + .ioc_force_to_fault = ps3_ioc_state_force_to_fault, + .ioc_force_to_halt = ps3_ioc_state_force_to_halt, + .irq_init = ps3_irqs_init_switch, + .irq_enable = ps3_irqs_enable, + .irq_disable = ps3_irqs_disable, + .isr = ps3_irqs_service, +#ifndef _WINDOWS + .sas_transport_get = NULL, +#endif + .event_filter_table_get = ps3_event_filter_table_get_switch, + .reg_write = ps3_reg_write_u64, +#ifdef _WINDOWS + .reg_read = ps3_reg_read_u64, +#else + .reg_read = ps3_switch_ioc_reg_read, +#endif + .is_need_direct_to_normal = ps3_is_need_direct_to_normal_switch, + .max_replyq_count_get = ps3_max_replyq_count_get, + .check_vd_member_change = NULL, + .scsih_stream_is_detect = NULL, + .scsih_stream_is_direct = NULL, +#ifdef PS3_HARDWARE_ASIC + .ioc_heartbeat_detect = ps3_ioc_heartbeat_detect, +#else + .ioc_heartbeat_detect = NULL, +#endif + .reg_set = NULL, + .ioc_security_check = NULL, + .io_cmd_rebuild = ps3_scsih_direct_to_normal_req_frame_rebuild, + .rw_cmd_is_need_split = NULL, + .write_direct_enable = NULL, + .ssd_vd_qmask_calculate = NULL, +}; + +struct ps3_ioc_adp_template g_ps3_template_hba = { + .io_cmd_build = ps3_scsih_cmd_build, + .mgr_cmd_build = NULL, + + + .init_cmd_send = ps3_switch_init_cmd_send, + .cmd_send = ps3_ioc_cmd_send, + .ioc_state_get = ps3_ioc_state_get, + .ioc_init_state_to_ready = ps3_ioc_init_to_ready, + .ioc_init_proc = ps3_ioc_init_proc, + .ioc_resource_prepare = ps3_ioc_resource_prepare_hba, + .ioc_hard_reset = ps3_ioc_state_hard_reset, + .ioc_shallow_soft_reset = ps3_ioc_state_shallow_soft_reset, + .ioc_deep_soft_reset = ps3_ioc_state_deep_soft_reset, + .ioc_force_to_fault = ps3_ioc_state_force_to_fault, + .ioc_force_to_halt = ps3_ioc_state_force_to_halt, + .irq_init = ps3_irqs_init, + .irq_enable = ps3_irqs_enable, + .irq_disable = ps3_irqs_disable, + .isr = ps3_irqs_service, +#ifndef _WINDOWS + .sas_transport_get = ps3_sas_transport_get, +#endif + .event_filter_table_get = ps3_event_filter_table_get_hba, + .reg_write = ps3_reg_write_u64, + .reg_read = ps3_reg_read_u64, + .is_need_direct_to_normal = ps3_is_need_direct_to_normal_hba, + .max_replyq_count_get = ps3_replyq_count_raidhba_get, + .check_vd_member_change = ps3_check_vd_member_change, + .scsih_stream_is_detect = ps3_scsih_stream_is_detect, + .scsih_stream_is_direct = ps3_hba_scsih_stream_is_direct, +#ifdef PS3_HARDWARE_ASIC + .ioc_heartbeat_detect = ps3_ioc_heartbeat_detect, +#else + .ioc_heartbeat_detect = NULL, +#endif + .reg_set = ps3_reg_set_ioremap, + .ioc_security_check = NULL, + .io_cmd_rebuild = ps3_scsih_direct_to_normal_req_frame_rebuild, + .rw_cmd_is_need_split = ps3_scsih_rw_cmd_is_need_split_hba, + .write_direct_enable = NULL, + .ssd_vd_qmask_calculate = ps3_ssd_vd_qmask_calculate_hba, +}; + +struct ps3_ioc_adp_template g_ps3_template_raid = { + .io_cmd_build = ps3_scsih_cmd_build, + .mgr_cmd_build = NULL, + + .init_cmd_send = ps3_switch_init_cmd_send, + .cmd_send = ps3_ioc_cmd_send, + .ioc_state_get = ps3_ioc_state_get, + .ioc_init_state_to_ready = ps3_ioc_init_to_ready, + .ioc_init_proc = ps3_ioc_init_proc, + .ioc_resource_prepare = ps3_ioc_resource_prepare_raid, + .ioc_hard_reset = ps3_ioc_state_hard_reset, + .ioc_shallow_soft_reset = ps3_ioc_state_shallow_soft_reset, + .ioc_deep_soft_reset = ps3_ioc_state_deep_soft_reset, + .ioc_force_to_fault = ps3_ioc_state_force_to_fault, + .ioc_force_to_halt = ps3_ioc_state_force_to_halt, + .irq_init = ps3_irqs_init, + .irq_enable = ps3_irqs_enable, + .irq_disable = ps3_irqs_disable, + .isr = ps3_irqs_service, +#ifndef _WINDOWS + .sas_transport_get = NULL, +#endif + .event_filter_table_get = ps3_event_filter_table_get_raid, + .reg_write = ps3_reg_write_u64, + .reg_read = ps3_reg_read_u64, + .is_need_direct_to_normal = ps3_is_need_direct_to_normal_raid, + .max_replyq_count_get = ps3_replyq_count_raidhba_get, + .check_vd_member_change = NULL, + .scsih_stream_is_detect = ps3_scsih_stream_is_detect, + .scsih_stream_is_direct = ps3_raid_scsih_stream_is_direct, +#ifdef PS3_HARDWARE_ASIC + .ioc_heartbeat_detect = ps3_ioc_heartbeat_detect, +#else + .ioc_heartbeat_detect = NULL, +#endif + .reg_set = ps3_reg_set_ioremap, + .ioc_security_check = ps3_ioc_security_state_check, + .io_cmd_rebuild = ps3_scsih_direct_to_normal_req_frame_rebuild, + .rw_cmd_is_need_split = ps3_scsih_rw_cmd_is_need_split_raid, + .write_direct_enable = ps3_write_direct_enable, + .ssd_vd_qmask_calculate = NULL, +}; + +static struct ps3_ioc_adp_temp_entry ps3_ioc_adp_template_map[] = { + {PCI_DEVICE_ID_PS3_RAID, &g_ps3_template_raid}, + {PCI_DEVICE_ID_PS3_HBA, &g_ps3_template_hba}, + {PCI_DEVICE_ID_PS3_SWITCH, &g_ps3_template_switch}, + {PCI_DEVICE_ID_PS3_SWITCH_FPGA, &g_ps3_template_switch}, + {PCI_DEVICE_ID_STARS_IOC_2020_18i, &g_ps3_template_hba}, + {PCI_DEVICE_ID_STARS_ROC_2020_10i, &g_ps3_template_raid}, + {PCI_DEVICE_ID_PS3_RAID_FPGA, &g_ps3_template_raid}, + {PCI_DEVICE_ID_STARS_IOC_2213_16i, &g_ps3_template_hba}, +}; + +#ifndef _WINDOWS +void ps3_ioc_adp_init(struct ps3_instance *instance, const struct pci_device_id *id) +{ + U16 i = 0; + U16 adp_num = sizeof(ps3_ioc_adp_template_map) / sizeof(struct ps3_ioc_adp_temp_entry); + + for (i = 0; i < adp_num; i++) { + if (id->device == ps3_ioc_adp_template_map[i].device_id) { + instance->ioc_adpter = ps3_ioc_adp_template_map[i].adp_template; + } + } + + instance->ioc_adpter->ioc_resource_prepare(instance); +} +#else +void ps3_ioc_adp_init(struct ps3_instance *instance) +{ + U16 i = 0; + U16 adp_num = sizeof(ps3_ioc_adp_template_map) / sizeof(struct ps3_ioc_adp_temp_entry); + + for (i = 0; i < adp_num; i++) { + if (instance->pci_dev_context.device_id == ps3_ioc_adp_template_map[i].device_id) { + instance->ioc_adpter = ps3_ioc_adp_template_map[i].adp_template; + LOG_WARN("hno:%u pci dev type is [%s]\n", + PS3_HOST(instance), + namePciDevType(ps3_ioc_adp_template_map[i].device_id)); +#ifdef _WINDOWS + instance->ioc_adpter->event_filter_table_get = ps3_event_filter_table_get_raid; +#endif + + } + } + + instance->ioc_adpter->ioc_resource_prepare(instance); +} +#endif diff --git a/drivers/scsi/ps3stor/ps3_ioc_manager.c b/drivers/scsi/ps3stor/ps3_ioc_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..2d7c1548cccae492472dd919a100deb6b2b7476b --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioc_manager.c @@ -0,0 +1,1107 @@ +#ifndef _WINDOWS + +#include +#include +#include +#include +#include +#else +#include "ps3_def.h" +#endif + +#include "ps3_cmd_statistics.h" +#include "ps3_ioc_manager.h" +#include "ps3_ioc_state.h" +#include "ps3_util.h" +#include "ps3_pci.h" +#include "ps3_htp_def.h" +#include "ps3_mgr_cmd.h" +#include "ps3_err_inject.h" +#include "ps3_inject.h" +#include "ps3_drv_ver.h" + +#define PS3_INIT_CMD_WAIT_MAX_TIMEOUT (180) +#define PS3_INIT_CMD_WAIT_INTERVAL (20) +#define PS3_INIT_CMD_CHECK_FAULT_INTERVAL (1000) +#if (defined PS3_HARDWARE_FPGA && defined PS3_MODEL_V200) +#define PS3_REG_READ_MAX_TRY_COUNT (60) +#else +#define PS3_REG_READ_MAX_TRY_COUNT (10) +#endif +#define PS3_REG_SWITCH_QEQUEST_QUEUE_OFFSET (0x10000) +#define PS3_IOC_INIT_PROC_FAIL_RETRY_COUNT (2) + +static S32 ps3_ioc_init_cmd_result_poll(struct ps3_instance *instance, + struct PS3InitReqFrame *init_frame_msg) +{ + U32 state = PS3_FW_STATE_UNDEFINED; + U32 wait_count = PS3_INIT_CMD_WAIT_MAX_TIMEOUT * 1000 / + PS3_INIT_CMD_WAIT_INTERVAL; + U32 count = 0; + S32 ret = -PS3_FAILED; + + state = instance->ioc_adpter->ioc_state_get(instance); + + while((count < wait_count) && (state != PS3_FW_STATE_FAULT) + && (state != PS3_FW_STATE_CRITICAL)) { + rmb(); + ps3_msleep(PS3_INIT_CMD_WAIT_INTERVAL); + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_8, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + + if (init_frame_msg->respStatus != U32_MAX) { + break; + } + + if (!(count % PS3_INIT_CMD_CHECK_FAULT_INTERVAL)) { + state = instance->ioc_adpter->ioc_state_get(instance) + & PS3_FW_STATE_MASK; + } + + count++; + } + + if (state == PS3_FW_STATE_FAULT || + state == PS3_FW_STATE_CRITICAL) { + LOG_ERROR("hno:%u init cmd NOK since IOC state fault\n", + PS3_HOST(instance)); + goto l_out; + } + + if (count == wait_count) { + LOG_ERROR("hno:%u init cmd timeout, state=%#x, respStatus=%#x\n", + PS3_HOST(instance), state, init_frame_msg->respStatus); + goto l_out; + } + + if (init_frame_msg->respStatus != 0) { + LOG_ERROR("hno:%u init cmd NOK[%d]\n", + PS3_HOST(instance), init_frame_msg->respStatus); + goto l_out; + } + + ret = PS3_SUCCESS; + LOG_WARN("hno:%u init cmd response successfully\n", + PS3_HOST(instance)); + +l_out: + init_frame_msg->respStatus = U32_MAX; + return ret; +} + +static S32 ps3_ioc_init_cmd_issue(struct ps3_instance *instance, + struct PS3InitReqFrame *init_frame_msg) +{ + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + struct PS3InitCmdWord cmd_word; + + memset(&cmd_word, 0, sizeof(struct PS3InitCmdWord)); + + cmd_word.lowAddr = + cpu_to_le32(lower_32_bits(cmd_context->init_frame_buf_phys)); + cmd_word.highAddr = + cpu_to_le32(upper_32_bits(cmd_context->init_frame_buf_phys)); + cmd_word.type = PS3_CMDWORD_TYPE_INIT; + cmd_word.direct = PS3_CMDWORD_DIRECT_NORMAL; + + instance->ioc_adpter->init_cmd_send(instance, (struct PS3CmdWord *)&cmd_word); + + LOG_INFO("hno:%u init command: cmd.lowAddr[0x%x], cmd.highAddr[0x%x], " + "cmd.type[%u]\n", PS3_HOST(instance), cmd_word.lowAddr, + cmd_word.highAddr, cmd_word.type); + INJECT_START(PS3_ERR_IJ_FORCE_INIT_FAIL, instance) + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_A_INIT, instance) + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_INIT_FAIL, instance) + + return ps3_ioc_init_cmd_result_poll(instance, init_frame_msg); +} + +static S32 ps3_ioc_init_cmd_alloc(struct ps3_instance *instance) +{ + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + S32 ret = PS3_SUCCESS; + + cmd_context->init_frame_buf = + (U8*)ps3_dma_alloc_coherent(instance, + sizeof(struct PS3InitReqFrame), + &cmd_context->init_frame_buf_phys); + + if (!cmd_context->init_frame_buf) { + LOG_ERROR("hno:%u Failed to alloc init cmd dma buffer\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + + cmd_context->init_filter_table_buff = (U8*)ps3_dma_alloc_coherent(instance, + PS3_CMD_EXT_BUF_SIZE_MGR, + &cmd_context->init_filter_table_phy_addr); + + if (!cmd_context->init_filter_table_buff) { + LOG_ERROR("hno:%u Failed to alloc init filter table dma buffer\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + + return ret; +} +#ifndef _WINDOWS + +static S32 ps3_ioc_sys_info_get(struct ps3_instance *instance) +{ + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + struct PS3DrvSysInfo *drv_sys_info = NULL; + const char *sys_info = NULL; + U32 sys_info_len = 0; + S32 ret = -PS3_FAILED; + + cmd_context->init_frame_sys_info_buf = + (U8*)ps3_dma_alloc_coherent(instance, + sizeof(struct PS3DrvSysInfo), + &cmd_context->init_frame_sys_info_phys); + INJECT_START(PS3_ERR_IJ_PS3_INIT_FRAME_SYS_INFO_BUF_ALLOC, &cmd_context->init_frame_sys_info_buf); + if (!cmd_context->init_frame_sys_info_buf) { + LOG_ERROR("hno:%u Failed to alloc sysinfo dma buffer\n", + PS3_HOST(instance)); + goto l_out; + } + + drv_sys_info = + (struct PS3DrvSysInfo *)cmd_context->init_frame_sys_info_buf; + + memset(drv_sys_info->systemID, 0, PS3_DRV_SYSTEM_ID_MAX_LEN); + + sys_info = dmi_get_system_info(DMI_PRODUCT_UUID); + if (!sys_info) { + LOG_INFO("hno:%u Failed to get sysinfo\n", + PS3_HOST(instance)); + drv_sys_info->systemIDLen = 0; + drv_sys_info->version = 0; + ret = PS3_SUCCESS; + goto l_out; + } + + sys_info_len = strlen(sys_info) > PS3_DRV_SYSTEM_ID_MAX_LEN ? + PS3_DRV_SYSTEM_ID_MAX_LEN : strlen(sys_info); + + memcpy(drv_sys_info->systemID, sys_info, sys_info_len); + drv_sys_info->systemIDLen = sys_info_len; + drv_sys_info->version = 0; + ret = PS3_SUCCESS; + +l_out: + return ret; +} + +#endif + +S32 ps3_ioc_init_cmd_context_init(struct ps3_instance *instance) +{ + if (ps3_ioc_init_cmd_alloc(instance) != PS3_SUCCESS) { + goto l_failed; + } +#ifndef _WINDOWS + if (ps3_ioc_sys_info_get(instance) != PS3_SUCCESS) { + goto l_failed; + } +#endif + return PS3_SUCCESS; +l_failed: + ps3_ioc_init_cmd_context_exit(instance); + return -PS3_FAILED; +} + +void ps3_ioc_init_cmd_context_exit(struct ps3_instance *instance) +{ + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + + LOG_INFO("entry\n"); +#ifndef _WINDOWS + if (cmd_context->init_frame_sys_info_buf != NULL) { + LOG_INFO("free init_frame_sys_info_buf = %p\n", cmd_context->init_frame_sys_info_buf); + ps3_dma_free_coherent(instance, + sizeof(struct PS3DrvSysInfo), + cmd_context->init_frame_sys_info_buf, + cmd_context->init_frame_sys_info_phys); + cmd_context->init_frame_sys_info_buf = NULL; + } +#endif + + if (cmd_context->init_filter_table_buff != NULL) { + LOG_INFO("free init_filter_table_buff = %p\n", cmd_context->init_filter_table_buff); + ps3_dma_free_coherent(instance, + PS3_CMD_EXT_BUF_SIZE_MGR, + cmd_context->init_filter_table_buff, + cmd_context->init_filter_table_phy_addr); + + cmd_context->init_filter_table_buff = NULL; + cmd_context->init_filter_table_phy_addr = 0; + } + + if (cmd_context->init_frame_buf != NULL) { + LOG_INFO("free init_frame_buf = %p\n", cmd_context->init_frame_buf); + ps3_dma_free_coherent(instance, + sizeof(struct PS3InitReqFrame), + cmd_context->init_frame_buf, + cmd_context->init_frame_buf_phys); + cmd_context->init_frame_buf = NULL; + } +} + +S32 ps3_drv_info_buf_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + instance->drv_info_buf = + (U8*)ps3_dma_alloc_coherent(instance, + sizeof(struct PS3DrvInfo), + &instance->drv_info_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_DRV_INFO_BUF_ALLOC, &instance->drv_info_buf); + if (instance->drv_info_buf == NULL) { + LOG_ERROR("hno:%u Failed to alloc drv info dma buffer\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + return ret; +} + +void ps3_drv_info_buf_free(struct ps3_instance *instance) +{ + if (instance->drv_info_buf != NULL) { + LOG_INFO("drv_info_buf = %p\n", instance->drv_info_buf); + ps3_dma_free_coherent(instance, sizeof(struct PS3DrvInfo), + instance->drv_info_buf, + instance->drv_info_buf_phys); + instance->drv_info_buf = NULL; + } +} + +S32 ps3_host_mem_info_buf_alloc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + instance->host_mem_info_buf = + (U8*)ps3_dma_alloc_coherent(instance, + (sizeof(struct PS3HostMemInfo) * PS3_HOST_MEM_INFO_NUM), + &instance->host_mem_info_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_HOST_MEM_BUF_ALLOC, &instance->host_mem_info_buf); + if (instance->host_mem_info_buf == NULL) { + LOG_ERROR("hno:%u Failed to alloc host mem info dma buffer\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + return ret; +} + +void ps3_host_mem_info_buf_free(struct ps3_instance *instance) +{ + if (instance->host_mem_info_buf != NULL) { + LOG_INFO("free host_mem_info_buf = %p\n", instance->host_mem_info_buf); + ps3_dma_free_coherent(instance, (sizeof(struct PS3HostMemInfo) * PS3_HOST_MEM_INFO_NUM), + instance->host_mem_info_buf, + instance->host_mem_info_buf_phys); + instance->host_mem_info_buf = NULL; + } +} + +S32 ps3_hard_reset_to_ready(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + if (instance->peer_instance != NULL) { + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_PENDING) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_CONTINUE; + while (instance->recovery_context->parall_hardreset_state != PS3_PARALLEL_HARDRESET_STATE_INIT) { + ps3_msleep(PS3_PARALLEL_HARDRESET_STATE_WAIT_INIT_INTERVAL); + } + } else { + ret = ps3_hard_recovery_request(instance); + if (ret != PS3_SUCCESS){ + LOG_WARN("hno:%u hard recovery request failed\n", + PS3_HOST(instance)); + goto l_out; + } + } + ps3_recovery_cancel_work_sync(instance); + } else { + if (!instance->ioc_adpter->ioc_hard_reset) { + ret = -PS3_FAILED; + goto l_out; + } + + ret = instance->ioc_adpter->ioc_hard_reset(instance); + if (ret == -PS3_FAILED) { + goto l_out; + } + INJECT_START(PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F0, instance); + if ((ret = ps3_ioc_state_ready_wait(instance)) != PS3_SUCCESS) { + goto l_out; + } + } + +l_out: + if (ret == PS3_SUCCESS) { + LOG_WARN("hno:%u ps3 fw state reset to ready successfully\n", + PS3_HOST(instance)); + } else { + LOG_ERROR("hno:%u PS3 fw state reset to ready NOK \n", + PS3_HOST(instance)); + } + + return ret; +} +S32 ps3_ioc_hard_reset_to_ready(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + if (!instance->ioc_adpter->ioc_hard_reset) { + ret = -PS3_FAILED; + goto l_out; + } + + if (instance->recovery_context->heartbeat_recovery != PS3_HEARTBEAT_HARDRESET_RECOVERY) { + ret = instance->ioc_adpter->ioc_hard_reset(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + } + + INJECT_START(PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F0, instance); + if ((ret = ps3_ioc_state_transfer_to_ready(instance)) != PS3_SUCCESS) { + goto l_out; + } + +l_out: + if (ret == PS3_SUCCESS) { + LOG_WARN("hno:%u ps3 fw state reset to ready successfully\n", + PS3_HOST(instance)); + } else { + LOG_ERROR("hno:%u PS3 fw state reset to ready NOK \n", + PS3_HOST(instance)); + } + + return ret; +} + +S32 ps3_ioc_init_to_ready(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + Bool is_unload_valid = PS3_FALSE; + + INJECT_START(PS3_ERR_IJ_FORCE_IOC_RUNNING, instance); + INJECT_START(PS3_ERR_IJ_FORCE_IOC_RUNNING_RESUME_RECOVERY, instance); + ret = ps3_ioc_state_transfer_to_ready(instance); + INJECT_START(PS3_ERR_IJ_FW_STATE_RUNNING, &ret) + if (ret == PS3_SUCCESS) { + goto l_out; + } + + ps3_check_debug0_valid_with_check(instance, &is_unload_valid, + PS3_CMD_TRIGGER_UNLOAD); + LOG_INFO("hno:%u PS3 fw state cannot directly init to ready successfully\n", + PS3_HOST(instance)); + if (ret != -PS3_NO_RECOVERED) { + if(ps3_is_need_hard_reset(instance)) { + ret = ps3_hard_reset_to_ready(instance); + } + } + +l_out: + if (ret == PS3_SUCCESS) { + LOG_INFO("hno:%u PS3 fw state init to ready successfully\n", + PS3_HOST(instance)); + if (is_unload_valid) { + ret = ps3_ioc_notify_unload(instance); + } + }else { + LOG_ERROR("hno:%u PS3 fw state init to ready NOK\n", + PS3_HOST(instance)); + } + + return ret; +} + +static void ps3_drv_info_prepare(struct ps3_instance *instance) +{ + struct PS3DrvInfo *drv_info = NULL; + drv_info = (struct PS3DrvInfo *)instance->drv_info_buf; + memset(drv_info, 0, sizeof(struct PS3DrvInfo)); + + snprintf(drv_info->drvName, PS3_DRV_NAME_MAX_LEN, PS3_DRV_AUTHOR); + snprintf(drv_info->drvVersion, PS3_DRV_VERSION_MAX_LEN, PS3_DRV_VERSION); + drv_info->domain_support = PS3_TRUE; + drv_info->domain = (U32)ps3_get_pci_domain(instance->pdev); + drv_info->bus = ps3_get_pci_bus(instance->pdev); + drv_info->dev = PCI_SLOT(instance->pdev->devfn); + drv_info->func = PCI_FUNC(instance->pdev->devfn); + drv_info->compatVer = PS3_COMPAT_VER_1; + LOG_DEBUG("hno:%u driver information dump:\n" + "\t drvName = %s, drvVersion = %s\n" + "\t domain = %x bus = %llx, dev = %x, func = %x\n", + PS3_HOST(instance), drv_info->drvName, drv_info->drvVersion, + drv_info->domain, drv_info->bus, drv_info->dev, drv_info->func); +} + +static inline bool ps3_pgdat_is_empty(pg_data_t *pgdat) +{ + return !pgdat->node_start_pfn && !pgdat->node_spanned_pages; +} + +struct pglist_data *first_online_pgdat(void) +{ + return NODE_DATA(first_online_node); +} + +struct pglist_data *next_online_pgdat(struct pglist_data *pgdat) +{ + int nid = next_online_node(pgdat->node_id); + if (nid == MAX_NUMNODES) { + return NULL; + } + return NODE_DATA(nid); +} + +static Bool ps3_get_numa_mem_addr(struct ps3_instance *instance) +{ + Bool ret = PS3_FALSE; + S32 node = -1; + struct pglist_data *pgdata = NULL; + node = dev_to_node(&instance->pdev->dev); + if (node < 0) { + goto l_out; + } + pgdata = NODE_DATA(node); + if (pgdata == NULL || ps3_pgdat_is_empty(pgdata)) { + goto l_out; + } + + instance->start_pfn = pgdata->node_start_pfn << PAGE_SHIFT; + instance->end_pfn = ((pgdat_end_pfn(pgdata) << PAGE_SHIFT) - 1); + + LOG_INFO("host_no:%u numa:%d, addr range:[0x%llx - 0x%llx], so addr range:[0x%llx - 0x%llx]\n", + PS3_HOST(instance), node, instance->start_pfn, instance->end_pfn, + instance->so_start_addr, instance->so_end_addr); + ret = PS3_TRUE; +l_out: + return ret; +} + +static void ps3_get_all_numa_mem_addr(struct ps3_instance *instance) +{ + struct pglist_data *pgdata = NULL; + S32 node = -1; + Bool is_in_range = PS3_FALSE; + U64 start_pfn = 0; + U64 end_pfn = 0; + if (ps3_get_numa_mem_addr(instance)) { + goto l_out; + } + for_each_online_pgdat(pgdata) { + if (ps3_pgdat_is_empty(pgdata)) { + continue; + } + start_pfn = pgdata->node_start_pfn << PAGE_SHIFT; + end_pfn = ((pgdat_end_pfn(pgdata) << PAGE_SHIFT) - 1); + INJECT_START(PS3_ERR_IJ_MOD_SO_ADDR, instance); + if (PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(instance->dma_addr_bit_pos, instance->so_start_addr) >= start_pfn && + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(instance->dma_addr_bit_pos, instance->so_end_addr) <= end_pfn) { + node = pgdata->node_id; + is_in_range = PS3_TRUE; + break; + } + } + if (is_in_range) { + instance->start_pfn = start_pfn; + instance->end_pfn = end_pfn; + } else { + instance->start_pfn = 0; + instance->end_pfn = 0; + } + LOG_INFO("host_no:%u numa:%d, addr range:[0x%llx - 0x%llx], so addr range:[0x%llx - 0x%llx]\n", + PS3_HOST(instance), node, instance->start_pfn, instance->end_pfn, + instance->so_start_addr, instance->so_end_addr); +l_out: + return; +} + +static void ps3_host_mem_info_prepare(struct ps3_instance *instance) +{ + struct PS3HostMemInfo *host_mem_info = NULL; + host_mem_info = (struct PS3HostMemInfo *)instance->host_mem_info_buf; + memset(host_mem_info, 0, sizeof(struct PS3HostMemInfo)); + + host_mem_info->startAddr = instance->start_pfn; + host_mem_info->endAddr = instance->end_pfn; + host_mem_info->type = PS3_MEM_TYPE_SO; + LOG_DEBUG("hno:%u host mem info dump:\n" + "\t startAddr = 0x%llx, endAddr = 0x%llx, type = %u\n", + PS3_HOST(instance), host_mem_info->startAddr, host_mem_info->endAddr, + host_mem_info->type); +} + +static void ps3_ioc_init_cmd_prepare(struct ps3_instance *instance) +{ + + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_cmd_attr_context *cmd_attr = &instance->cmd_attr; + struct ps3_dump_context *dump_context = &instance->dump_context; + struct PS3InitReqFrame* init_frame_msg = NULL; + + init_frame_msg = (struct PS3InitReqFrame *)cmd_context->init_frame_buf; + + memset(&init_frame_msg->reqHead, 0, sizeof(PS3ReqFrameHead_s)); + init_frame_msg->reqHead.cmdType = PS3_CMD_INIT_IOC; + init_frame_msg->reqHead.timeout = PS3_INIT_CMD_WAIT_MAX_TIMEOUT; + + init_frame_msg->ver = 0; + init_frame_msg->length = sizeof(struct PS3InitReqFrame); + init_frame_msg->operater = PS3_CMD_OPERATOR_TYPE_HOST; + init_frame_msg->pageSize = (U8)cmd_attr->nvme_page_size; + init_frame_msg->msixVector = (U16)irq_context->valid_msix_vector_count; + init_frame_msg->pciIrqType = (U16)irq_context->pci_irq_type; + init_frame_msg->osType = PS3_LINUX_FRAME; + + init_frame_msg->timeStamp = cpu_to_le64(ps3_1970_now_ms_get()); + init_frame_msg->reqFrameBufBaseAddr = + cpu_to_le64(cmd_context->req_frame_buf_phys); + + init_frame_msg->replyFifoDescBaseAddr = + cpu_to_le64(irq_context->reply_fifo_desc_buf_phys); + + init_frame_msg->respFrameBaseAddr = + cpu_to_le64(cmd_context->response_frame_buf_phys); + + init_frame_msg->reqFrameMaxNum = (U16)cmd_context->max_cmd_count; + init_frame_msg->respFrameMaxNum = (U16)cmd_context->max_cmd_count; + init_frame_msg->bufSizePerRespFrame = PS3_RESP_FRAME_BUFFER_SIZE; + + + if(ps3_hil_mode_query() > HIL_MODEL_SW_ASSIST) + { + init_frame_msg->hilMode = instance->hilMode; + }else{ + init_frame_msg->hilMode = (U8)ps3_hil_mode_query(); + } + +#ifndef _WINDOWS + init_frame_msg->systemInfoBufAddr = + cmd_context->init_frame_sys_info_phys; +#endif + if (!reset_devices) { + init_frame_msg->dumpDmaBufAddr = cpu_to_le64(dump_context->dump_dma_addr); + init_frame_msg->dumpDmaBufLen = cpu_to_le64(PS3_DUMP_DMA_BUF_SIZE); + init_frame_msg->dumpIsrSN = cpu_to_le32(irq_context->dump_isrSN); + } +#ifndef _WINDOWS + init_frame_msg->debugMemArrayNum = + cpu_to_le32(instance->debug_context.debug_mem_array_num); + init_frame_msg->debugMemArrayAddr = + (instance->debug_context.debug_mem_array_num != 0) ? + cpu_to_le64(instance->debug_context.debug_mem_buf_phy) : 0; +#endif + memset(cmd_context->init_filter_table_buff, 0, PS3_CMD_EXT_BUF_SIZE_MGR); + if (instance->ioc_adpter->event_filter_table_get != NULL) { + init_frame_msg->filterTableAddr = cpu_to_le64(cmd_context->init_filter_table_phy_addr); + init_frame_msg->filterTableLen = cpu_to_le32(PS3_CMD_EXT_BUF_SIZE_MGR); + instance->ioc_adpter->event_filter_table_get(cmd_context->init_filter_table_buff); + } + ps3_drv_info_prepare(instance); + init_frame_msg->drvInfoBufAddr = cpu_to_le64(instance->drv_info_buf_phys); + init_frame_msg->drvInfoBufLen = cpu_to_le16(sizeof(struct PS3DrvInfo)); + ps3_get_all_numa_mem_addr(instance); + if (instance->end_pfn != 0) { + ps3_host_mem_info_prepare(instance); + init_frame_msg->hostMemInfoBaseAddr = cpu_to_le64(instance->host_mem_info_buf_phys); + init_frame_msg->hostMemInfoNum = cpu_to_le32(PS3_HOST_MEM_INFO_NUM); + } else { + init_frame_msg->hostMemInfoBaseAddr = 0; + init_frame_msg->hostMemInfoNum = 0; + } + LOG_DEBUG("hno:%u init frame information dump:\n" + "\t initFramePhysicAddr = 0x%llx, initFrameLen = %d, version = %d\n" + "\t pciIrqType = %d, msixVectorCount = %d, reqHead.cmdType = %d\n" + "\t reqFrameBufBase = 0x%llx, reqFrameMaxNum = %d\n" + "\t responseFrameBase = 0x%llx, responseFrameMaxNum = %d, responseFrameSize = %d\n" + "\t replyFifoDescBase = 0x%llx, hostSystemInfoBuf = %llx\n" + "\t filterTableAddr = 0x%llx, filterTableLen = %d\n" + "\t drvInfoBufAddr = 0x%llx, drvInfoBufLen = %d\n" + "\t hostMemInfoBaseAddr = 0x%llx, hostMemInfoNum = %d, function = %d\n", + PS3_HOST(instance), cpu_to_le64(cmd_context->init_frame_buf_phys), + init_frame_msg->length, init_frame_msg->ver, + init_frame_msg->pciIrqType, init_frame_msg->msixVector, init_frame_msg->reqHead.cmdType, + init_frame_msg->reqFrameBufBaseAddr, init_frame_msg->reqFrameMaxNum, + init_frame_msg->respFrameBaseAddr, init_frame_msg->reqFrameMaxNum, init_frame_msg->bufSizePerRespFrame, + init_frame_msg->replyFifoDescBaseAddr, init_frame_msg->systemInfoBufAddr, + init_frame_msg->filterTableAddr, init_frame_msg->filterTableLen, + init_frame_msg->drvInfoBufAddr, init_frame_msg->drvInfoBufLen, + init_frame_msg->hostMemInfoBaseAddr, init_frame_msg->hostMemInfoNum, ps3_get_pci_function(instance->pdev)); + + return; +} + +static S32 ps3_ioc_init_cmd_proc(struct ps3_instance *instance) +{ + struct PS3MgrEvent *event_req_info = &instance->event_req_info; + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + struct PS3InitReqFrame *init_frame_msg = NULL; + + ps3_ioc_init_cmd_prepare(instance); + + init_frame_msg = (struct PS3InitReqFrame *)cmd_context->init_frame_buf; + init_frame_msg->eventTypeMap = event_req_info->eventTypeMap; + + init_frame_msg->respStatus = U32_MAX; + + ps3_all_reply_fifo_init(instance); + LOG_WARN("hno:%u start to send init cmd![init:0x%llx, respstats:0x%llx]\n", PS3_HOST(instance), + cmd_context->init_frame_buf_phys, + (U64)cmd_context->init_frame_buf_phys + offsetof(struct PS3InitReqFrame, respStatus)); + + return ps3_ioc_init_cmd_issue(instance, init_frame_msg); +} +S32 ps3_ioc_init_proc(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 state = PS3_FW_STATE_UNDEFINED; + S32 retry = 0; + + ps3_ioc_can_hardreset_set(instance, PS3_IOC_CANNOT_HARDRESET); + while (retry < PS3_IOC_INIT_PROC_FAIL_RETRY_COUNT) { + ret = ps3_ioc_init_cmd_proc(instance); + INJECT_START(PS3_ERR_IJ_INIT_CMD_PROC_FAIL, &ret) + if (ret != PS3_SUCCESS) { + goto l_clean; + } + INJECT_START(PS3_ERR_IJ_FORCE_INIT_RUNNING_FAIL, instance) + + INJECT_START(PS3_ERR_IJ_RECOVERY_F1_RUNNING, instance) + ret = ps3_ioc_state_transfer_wait_to_running(instance); + INJECT_START(PS3_ERR_IJ_IOC_STATE_WAIT_TO_RUNNING_FAIL, &ret) + if (ret != PS3_SUCCESS) { + if (ret == -PS3_IN_PCIE_ERR) { + goto l_out; + } + goto l_clean; + } + + goto l_out; + l_clean: + state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_IOC_STATE_WAIT_TO_RUNNING_FAIL, &ret) + INJECT_START(PS3_ERR_IJ_IOC_INIT_PROC_STATE_RUNNING, &state) + INJECT_START(PS3_ERR_IJ_INIT_PROC_FAIL_NOUNLOAD, &state) + if(state == PS3_FW_STATE_WAIT || + state == PS3_FW_STATE_RUNNING){ + if (ps3_soc_unload(instance, PS3_TRUE, PS3_UNLOAD_SUB_TYPE_REMOVE, PS3_SUSPEND_TYPE_NONE) == PS3_SUCCESS) { + LOG_INFO("device[%d] unload success,exit init proc.\n", instance->pdev->dev.id); + retry++; + continue; + } + } + ret = ps3_init_fail_hard_reset_with_doorbell(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("device[%d] hard reset NOK,exit init proc.\n", instance->pdev->dev.id); + goto l_out; + } + retry++; + } + if (retry == PS3_IOC_INIT_PROC_FAIL_RETRY_COUNT) { + ret = -PS3_FAILED; + } + LOG_INFO("device[%d] doorbell success,exit init proc [%d].\n", instance->pdev->dev.id, ret); + +l_out: + return ret; +} + +void ps3_ioc_legacy_irqs_enable(struct ps3_instance *instance) +{ + LOG_INFO("hno:%u Enable legacy!\n", PS3_HOST(instance)); +#ifndef _WINDOWS + pci_intx(instance->pdev, 1); +#else + ps3_pci_intx(instance, 1); +#endif + return; +} + +void ps3_ioc_legacy_irqs_disable(struct ps3_instance *instance) +{ + LOG_INFO("hno:%u Disable legacy!\n", PS3_HOST(instance)); +#ifndef _WINDOWS + pci_intx(instance->pdev, 0); +#else + ps3_pci_intx(instance, 0); +#endif + return; +} + +void ps3_ioc_msi_enable(struct ps3_instance *instance) +{ + U32 pos = 0; + U16 control = 0; + + pos = ps3_pci_find_capability(instance, PCI_CAP_ID_MSI); + if (pos == 0) { + LOG_INFO("hno:%u Find PCI_CAP_ID_MSI failed!\n", + PS3_HOST(instance)); + return; + } + + ps3_pci_read_config_word(instance, pos + PCI_MSI_FLAGS, &control); + if (!(control & PCI_MSI_FLAGS_ENABLE)) { + LOG_INFO("hno:%u Enable Msi!\n", PS3_HOST(instance)); + ps3_pci_write_config_word(instance, pos + PCI_MSI_FLAGS, + control | PCI_MSI_FLAGS_ENABLE); + } + + return; +} + +void ps3_ioc_msi_disable(struct ps3_instance *instance) +{ + U32 pos = 0; + U16 control = 0; + + pos = ps3_pci_find_capability(instance, PCI_CAP_ID_MSI); + if (pos == 0) { + LOG_ERROR("hno:%u Find PCI_CAP_ID_MSI failed!\n", + PS3_HOST(instance)); + return; + } + + ps3_pci_read_config_word(instance, pos + PCI_MSI_FLAGS, &control); + if (control & PCI_MSI_FLAGS_ENABLE) { + LOG_INFO("hno:%u Disable Msi!\n", PS3_HOST(instance)); + ps3_pci_write_config_word(instance, pos + PCI_MSI_FLAGS, + control & ~PCI_MSI_FLAGS_ENABLE); + } + + return; + +} + +void ps3_ioc_msix_enable(struct ps3_instance *instance) +{ + U32 pos = 0; + U16 control = 0; + + pos = ps3_pci_find_capability(instance, PCI_CAP_ID_MSIX); + if (pos == 0) { + LOG_ERROR("hno:%u Find PCI_CAP_ID_MSIX failed!\n", + PS3_HOST(instance)); + return; + } + + ps3_pci_read_config_word(instance, pos + PCI_MSIX_FLAGS, &control); + if (!(control & PCI_MSIX_FLAGS_ENABLE)) { + LOG_INFO("hno:%u Enable Msix!\n", PS3_HOST(instance)); + ps3_pci_write_config_word(instance, pos + PCI_MSIX_FLAGS, + control | PCI_MSIX_FLAGS_ENABLE); + } + + return; +} + +void ps3_ioc_msix_disable(struct ps3_instance *instance) +{ + U32 pos = 0; + U16 control = 0; + + pos = ps3_pci_find_capability(instance, PCI_CAP_ID_MSIX); + if (pos == 0) { + LOG_ERROR("hno:%u Find PCI_CAP_ID_MSIX failed!\n", + PS3_HOST(instance)); + return; + } + + ps3_pci_read_config_word(instance, pos + PCI_MSIX_FLAGS, &control); + if (control & PCI_MSIX_FLAGS_ENABLE) { + LOG_INFO("hno:%u disable Msix!\n", PS3_HOST(instance)); + ps3_pci_write_config_word(instance, pos + PCI_MSIX_FLAGS, + control & ~PCI_MSIX_FLAGS_ENABLE); + } + + return; +} + +Bool ps3_ioc_is_legacy_irq_existed(struct ps3_instance *instance) +{ + U16 status = 0; + Bool is_legacy_irq_existed = PS3_FALSE; + + ps3_pci_read_config_word(instance, PCI_COMMAND, &status); + if (status & PCI_COMMAND_INTX_DISABLE) { + LOG_INFO("hno:%u Legacy irq is disabled!\n", + PS3_HOST(instance)); + goto l_out; + } + + ps3_pci_read_config_word(instance, PCI_STATUS, &status); + if (status & PCI_STATUS_INTERRUPT) { + LOG_INFO("hno:%u Legacy irq is existed!\n", + PS3_HOST(instance)); + is_legacy_irq_existed = PS3_TRUE; + } + +l_out: + return is_legacy_irq_existed; +} + +void ps3_ioc_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word) +{ + union PS3DefaultCmdWord *cmd_word_default = NULL; + + PS3_CMD_WORD_STAT_INC(instance, cmd_word); + + cmd_word_default = (union PS3DefaultCmdWord *) cmd_word; +#ifdef PS3_SUPPORT_INJECT + if(ps3_add_cmd_filter(instance, cmd_word)) { + goto l_out; + } +#endif + + PS3_IOC_REG_WRITE(instance, cmd_fifo.request_fifo, ps3RequestQueue, cmd_word_default->words); +#ifdef PS3_SUPPORT_INJECT +l_out: + return; +#endif +} + +void ps3_ioc_scsi_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word) +{ + union PS3DefaultCmdWord *cmd_word_default = NULL; + + PS3_CMD_WORD_STAT_INC(instance, cmd_word); + cmd_word_default = (union PS3DefaultCmdWord *)cmd_word; + + if(instance->is_pci_reset == PS3_FALSE) { + ps3_ioc_reg_write(instance, cmd_word_default->words, + &instance->reg_set->cmd_fifo.request_fifo.ps3RequestQueue); + } else { + LOG_FILE_ERROR("hno:%u register %p,write blocked by pci err\n", + PS3_HOST(instance), + &instance->reg_set->cmd_fifo.request_fifo.ps3RequestQueue); + } +} + +void ps3_switch_normal_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word) +{ + union PS3CmdWordU32 cmd_word_u32; + union PS3DefaultCmdWord cmd_word_default; + struct ps3_cmd *cmd = NULL; + + cmd = ps3_cmd_find(instance, cmd_word->cmdFrameID); + + PS3_CMD_WORD_STAT_INC(instance, cmd_word); + + cmd_word_u32.cmdWord.cmdFrameID = cmd_word->cmdFrameID; + cmd_word_u32.cmdWord.type = cmd_word->type; + cmd_word_u32.cmdWord.isrSN = cmd_word->isrSN; + cmd_word_u32.cmdWord.noReplyWord = cmd->req_frame->frontendReq.reqHead.noReplyWord; + + cmd_word_default.words = 0; + cmd_word_default.u.low = cmd_word_u32.val; + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, reserved0, cmd_word_default.words); +} + +void ps3_switch_init_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word) +{ + union PS3DefaultCmdWord *cmd_word_default = NULL; + PS3_CMD_WORD_STAT_INC(instance, cmd_word); + + cmd_word_default = (union PS3DefaultCmdWord *) cmd_word; + ps3_atomic_inc(&(instance)->reg_op_count); + mb(); + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { + PS3_REG_SESSION_ADDR_WRITE(instance, cmd_word_default->words, + &instance->reg_set->reg_f.Excl_reg.ps3SessioncmdAddr); + } else { + LOG_ERROR("hno:%u register %p,write blocked by hardreset(%d) or pci recovery(%d)\n", + PS3_HOST(instance), &instance->reg_set->reg_f.Excl_reg.ps3SessioncmdAddr, + (instance)->is_hard_reset, instance->is_pci_reset); + } + ps3_atomic_dec(&(instance)->reg_op_count); + + LOG_DEBUG("hno:%u init command: cmd.words = 0x%llx, " + "session_reg_offset = %#lx\n", PS3_HOST(instance), + cmd_word_default->words, + offsetof(HilReg0Ps3RegisterF_s, ps3SessioncmdAddr)); +} +#ifndef _WINDOWS +U64 ps3_switch_ioc_reg_read(struct ps3_instance *instance, void __iomem *reg) +{ + U64 value = 0; + U64 addr = (U64)reg; + value = (((U64)readl((void*)(addr + 0x4UL)) << 32) | (U64)readl(reg)); + + if (&instance->reg_set->cmd_fifo.request_fifo.ps3RequestQueue == reg) { + reg = (void __iomem *)((U64)reg - PS3_REG_SWITCH_QEQUEST_QUEUE_OFFSET); + } + ps3_reg_dump(instance, reg, value, PS3_TRUE); + return value; +} +#endif +inline void ps3_ioc_reg_write(struct ps3_instance *instance, + U64 val, void __iomem *reg) +{ + ps3_reg_dump(instance, reg, val, PS3_FALSE); + if (instance->ioc_adpter->reg_write) { + instance->ioc_adpter->reg_write(instance, val, reg); + } else { + LOG_FILE_ERROR("hno:%u no register write\n", PS3_HOST(instance)); + } +} +void ps3_ioc_hardreset_reg_write(struct ps3_instance *instance, + U64 val, void __iomem *reg, Bool is_warn_prk) +{ + ps3_reg_dump(instance, reg, val, PS3_FALSE); + if (instance->ioc_adpter->reg_write) { + if (is_warn_prk) { + LOG_WARN("hno:%u register write reset,val:0x%llx,reg=%p\n", + PS3_HOST(instance),val,reg); + } + instance->ioc_adpter->reg_write(instance, val, reg); + } else { + LOG_ERROR("hno:%u no register write\n", PS3_HOST(instance)); + } +} + +inline U64 ps3_ioc_reg_read(struct ps3_instance *instance, void __iomem *reg) +{ + U64 value = 0; + if (instance->ioc_adpter->reg_read) { + value = instance->ioc_adpter->reg_read(instance, reg); + } else { + LOG_ERROR("hno:%u no register read\n", PS3_HOST(instance)); + } + + ps3_reg_dump(instance, reg, value, PS3_TRUE); + return value; +} +U64 ps3_ioc_hardreset_reg_read(struct ps3_instance *instance, void __iomem *reg) +{ + U64 value = 0; + if (instance->ioc_adpter->reg_read) { + value = instance->ioc_adpter->reg_read(instance, reg); + } else { + LOG_ERROR("hno:%u no register read\n", PS3_HOST(instance)); + } + + + return value; +} +inline U64 ps3_ioc_reg_read_with_check(struct ps3_instance *instance, + void __iomem *reg) +{ + U8 try_count = 0; + U64 reg_value = ps3_ioc_reg_read(instance, reg); + + while (reg_value == U64_MAX && + try_count != PS3_REG_READ_MAX_TRY_COUNT) { + ps3_msleep(PS3_REG_READ_INTERVAL_MS); + try_count++; + reg_value = ps3_ioc_reg_read(instance, reg); + } + + return reg_value; +} + +static U64 ps3_ioc_reg_safe_read(struct ps3_instance *instance, + void __iomem *reg) +{ + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + U32 count = 0; + U32 retry_cnt = 0; + U64 tmp_value = U64_MAX; + U64 value = U64_MAX; + Bool is_first = PS3_TRUE; + for (; retry_cnt < PS3_REG_READ_SAFE_RETRY_NUM; retry_cnt++) { + tmp_value = ps3_ioc_reg_read_with_check(instance, reg); + INJECT_START(PS3_ERR_IJ_REG_READ_ERR, &tmp_value); + if (tmp_value == U64_MAX) { + value = U64_MAX; + goto l_out; + } + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_IOC_TO_READY_FAILED1, &fw_cur_state); + INJECT_START(PS3_ERR_IJ_IOC_TO_CRITICAL, &fw_cur_state); + if (!ps3_ioc_state_valid_check(fw_cur_state)) { + for (; count < PS3_REG_READ_RETRY_NUM; count++) { + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_IOC_TO_READY_FAILED1, &fw_cur_state); + INJECT_START(PS3_ERR_IJ_IOC_TO_CRITICAL, &fw_cur_state); + if (ps3_ioc_state_valid_check(fw_cur_state)) { + value = ps3_ioc_reg_read_with_check(instance, reg); + goto l_out; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + } + value = U64_MAX; + LOG_WARN_LIM("hno:%u wait ioc to vaild state NOK\n", PS3_HOST(instance)); + goto l_out; + } + if (is_first) { + value = tmp_value; + is_first = PS3_FALSE; + continue; + } + INJECT_START(PS3_ERR_IJ_REG_READ_ZERO, &tmp_value); + if (value != tmp_value) { + LOG_WARN_LIM("hno:%u reg value not equal old-new[%llu, %llu]\n", + PS3_HOST(instance), value, tmp_value); + value = U64_MAX; + goto l_out; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_50MS); + } +l_out: + return value; +} + +U64 ps3_ioc_reg_retry_safe_read(struct ps3_instance *instance, void __iomem *reg) +{ + U32 retry_cnt = PS3_REG_READ_SAFE_RETRY_NUM; + U64 reg_value = 0; + while (retry_cnt--) { + reg_value = ps3_ioc_reg_safe_read(instance, reg); + if (reg_value != U64_MAX) { + break; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + } + return reg_value; +} + +Bool ps3_feature_support_reg_get(struct ps3_instance *instance) +{ + Bool ret = PS3_FALSE; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + INJECT_START(PS3_ERR_IJ_FEATURE_REG_READ_ERR, &value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport NOK!\n", + PS3_HOST(instance)); + goto l_out; + } + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + instance->is_ioc_halt_support = (ps3_feature_support->reg.fwHaltSupport == 1); + instance->is_shallow_soft_recovery_support = (ps3_feature_support->reg.shallowSoftRecoverySupport == 1); + instance->is_deep_soft_recovery_support = (ps3_feature_support->reg.deepSoftRecoverySupport == 1); + instance->is_hard_recovery_support = (ps3_feature_support->reg.hardRecoverySupport == 1); + instance->cmd_context.sgl_mode_support = (ps3_feature_support->reg.sglModeSupport == 1); + ret = PS3_TRUE; +l_out: + return ret; +} + diff --git a/drivers/scsi/ps3stor/ps3_ioc_manager.h b/drivers/scsi/ps3stor/ps3_ioc_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..026537ce793fd85c593210e9db4634aac913dd10 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioc_manager.h @@ -0,0 +1,809 @@ + +#ifndef _PS3_IOC_MANAGER_H_ +#define _PS3_IOC_MANAGER_H_ + +#include "ps3_instance_manager.h" +#include "ps3_inner_data.h" +#include "ps3_module_para.h" +#include "ps3_ioc_state.h" +#ifndef _WINDOWS +#define PS3_REG_SESSION_ADDR_WRITE(instance, val, reg) \ + do { \ + ps3_reg_dump(instance, reg, val, PS3_FALSE); \ + writeq(val, reg); \ + } while(0) +#else +#define PS3_REG_SESSION_ADDR_WRITE(instance, val, reg) \ + do { \ + ps3_reg_dump(instance, reg, val, PS3_FALSE); \ + ps3_ioc_reg_write(instance, val, reg); \ + } while(0) +#endif + +#define PS3_MAX_CMD_COUNT_DURING_RESET_DEVICES (100) +#define PS3_REG_READ_INTERVAL_MS (10) +#if (defined PS3_HARDWARE_FPGA && defined PS3_MODEL_V200) +#define PS3_REG_WRITE_RETRY_NUM (60) +#else +#define PS3_REG_WRITE_RETRY_NUM (10) +#endif +#define PS3_REG_WRITE_INTERVAL_MS (10) +#define PS3_REG_READ_RETRY_NUM (5000) +#define PS3_ATU_SUPPORT_READ_RETRY_NUM (3) +#define PS3_REG_READ_SAFE_RETRY_NUM (3) +#define PS3_HOST_MEM_INFO_NUM (1) +#define PS3_IOC_STATE_HALT_SUPPORT(ins) \ + (ins->is_ioc_halt_support) + +#define PS3_IOC_SHALLOW_SOFT_RECOVERY_SUPPORT(ins) \ + (ins->is_shallow_soft_recovery_support) + +#define PS3_IOC_DEEP_SOFT_RECOVERY_SUPPORT(ins) \ + ((ins->is_deep_soft_recovery_support) && ps3_deep_soft_reset_enable_query()) + +#define PS3_IOC_HARD_RECOVERY_SUPPORT(ins) \ + (PS3_INSTANCE_ABNORMAL_FORCE_HARD_RECOVERY(ins) || \ + ins->is_hard_recovery_support) + +#define PS3_HALT_CLI_SUPPORT(ins) \ + (ins->is_halt_support_cli) + +#define PS3_IOC_REG_READ_WITH_CHECK(instance, reg_type, reg_name, read_value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + read_value = ps3_ioc_reg_read_with_check(instance, &(instance)->reg_set->reg_type.reg_name); \ + } else { \ + LOG_FILE_ERROR("hno:%u register %p,read blocked by hardreset(%d) or pci err(%d)\n", \ + PS3_HOST(instance), &(instance)->reg_set->reg_type.reg_name, \ + (instance)->is_hard_reset, (instance)->is_pci_reset); \ + read_value = U64_MAX; \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0); + +#define PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_type, reg_name, read_value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + read_value = ps3_ioc_reg_retry_safe_read(instance, &(instance)->reg_set->reg_type.reg_name); \ + } else { \ + LOG_FILE_ERROR("hno:%u register %p,read blocked by hardreset(%d) or pci err(%d)\n", \ + PS3_HOST(instance), &(instance)->reg_set->reg_type.reg_name, \ + (instance)->is_hard_reset, (instance)->is_pci_reset); \ + read_value = U64_MAX; \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0); + +#define PS3_IOC_REG_READ_OFFSET(instance, offset, read_value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + read_value = ps3_ioc_reg_read(instance, (U8 *)(instance)->reg_set + (offset)); \ + } else { \ + LOG_FILE_ERROR("hno:%u register %p, read blocked by hardreset(%d) or pci err(%d)\n", \ + PS3_HOST(instance), (U8 *)(instance)->reg_set + (offset), \ + (instance)->is_hard_reset, instance->is_pci_reset); \ + read_value = U64_MAX; \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0); + +#define PS3_IOC_REG_READ_OFFSET_WITCH_CHECK(instance, offset, read_value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + read_value = ps3_ioc_reg_read_with_check(instance, (U8 *)(instance)->reg_set + (offset)); \ + } else { \ + LOG_WARN("hno:%u register %p, read blocked by hardreset(%d) or pci recovery(%d)\n", \ + PS3_HOST(instance), (U8 *)(instance)->reg_set + (offset), \ + (instance)->is_hard_reset, instance->is_pci_reset); \ + read_value = U64_MAX; \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0); + +#define PS3_IOC_REG_WRITE(instance, reg_type, reg_name, value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + ps3_ioc_reg_write(instance, value, &(instance)->reg_set->reg_type.reg_name); \ + } else { \ + LOG_FILE_ERROR("hno:%u register %p,write blocked by hardreset(%d) or pci err(%d)\n", \ + PS3_HOST(instance), &(instance)->reg_set->reg_type.reg_name, \ + (instance)->is_hard_reset, instance->is_pci_reset); \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0) + +#define PS3_IOC_REG_WRITE_OFFSET(instance, offset, value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + ps3_ioc_reg_write(instance, value, (U8 *)(instance)->reg_set + (offset)); \ + } else { \ + LOG_FILE_ERROR("hno:%u register %p,write blocked by hardreset(%d) or pci err(%d)\n", \ + PS3_HOST(instance), (U8 *)(instance)->reg_set + (offset), \ + (instance)->is_hard_reset, instance->is_pci_reset); \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0) + +#define PS3_IOC_REG_WRITE_WITH_CHECK(instance, reg_type, reg_name, value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + ps3_ioc_reg_write_with_check(instance, value, &(instance)->reg_set->reg_type.reg_name); \ + } else { \ + LOG_WARN("hno:%u register %p,write blocked by hardreset(%d) or pci recovery(%d)\n", \ + PS3_HOST(instance), &(instance)->reg_set->reg_type.reg_name, \ + (instance)->is_hard_reset, instance->is_pci_reset); \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0) + +#define PS3_IOC_REG_WRITE_OFFSET_WITH_CHECK(instance, offset, value) do {\ + ps3_atomic_inc(&(instance)->reg_op_count); \ + mb(); \ + if((instance)->is_hard_reset == PS3_FALSE && (instance)->is_pci_reset == PS3_FALSE) { \ + ps3_ioc_reg_write_with_check(instance, value, (U8 *)(instance)->reg_set + (offset)); \ + } else { \ + LOG_WARN("hno:%u register %p,write blocked by hardreset(%d) or pci recovery(%d)\n", \ + PS3_HOST(instance), (U8 *)(instance)->reg_set + (offset), \ + (instance)->is_hard_reset, instance->is_pci_reset); \ + } \ + ps3_atomic_dec(&(instance)->reg_op_count); \ +} while(0) + +S32 ps3_ioc_init_cmd_context_init(struct ps3_instance *instance); +void ps3_ioc_init_cmd_context_exit(struct ps3_instance *instance); +void ps3_ioc_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word); +void ps3_switch_init_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word); +void ps3_switch_normal_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word); +void ps3_ioc_legacy_irqs_enable(struct ps3_instance *instance); +void ps3_ioc_legacy_irqs_disable(struct ps3_instance *instance); +void ps3_ioc_msi_enable(struct ps3_instance *instance); +void ps3_ioc_msi_disable(struct ps3_instance *instance); +void ps3_ioc_msix_enable(struct ps3_instance *instance); +void ps3_ioc_msix_disable(struct ps3_instance *instance); +Bool ps3_ioc_is_legacy_irq_existed(struct ps3_instance *instance); +S32 ps3_drv_info_buf_alloc(struct ps3_instance *instance); + +void ps3_drv_info_buf_free(struct ps3_instance *instance); + +S32 ps3_host_mem_info_buf_alloc(struct ps3_instance *instance); + +void ps3_host_mem_info_buf_free(struct ps3_instance *instance); + +S32 ps3_ioc_init_to_ready(struct ps3_instance *instance); + +S32 ps3_ioc_hard_reset_to_ready(struct ps3_instance *instance); + +S32 ps3_ioc_init_proc(struct ps3_instance *instance); + +void ps3_ioc_reg_write(struct ps3_instance *instance, U64 val, + void __iomem *reg); +void ps3_ioc_hardreset_reg_write(struct ps3_instance *instance, + U64 val, void __iomem *reg, Bool is_warn_prk); +U64 ps3_ioc_hardreset_reg_read(struct ps3_instance *instance, + void __iomem *reg); +U64 ps3_ioc_reg_read(struct ps3_instance *instance, void __iomem *reg); + +U64 ps3_ioc_reg_read_with_check(struct ps3_instance *instance, + void __iomem *reg); + +static inline Bool ps3_ioc_state_valid_check(U32 fw_cur_state) { + return ((fw_cur_state > PS3_FW_STATE_START) && (fw_cur_state != PS3_FW_STATE_MASK)); +} + +U64 ps3_ioc_reg_retry_safe_read(struct ps3_instance *instance, void __iomem *reg); + +static inline void ps3_ioc_reg_write_with_check(struct ps3_instance *instance, + U64 val, void __iomem *reg) +{ + U8 try_count = 0; + + ps3_reg_dump(instance, reg, val, PS3_FALSE); + if (instance->ioc_adpter->reg_write) { + while (try_count != PS3_REG_WRITE_RETRY_NUM) { + instance->ioc_adpter->reg_write(instance, val, reg); + if (instance->ioc_adpter->reg_read(instance, reg) == val) { + break; + } + try_count++; + ps3_msleep(PS3_REG_WRITE_INTERVAL_MS); + } + } else { + LOG_ERROR("hno:%u no register write\n", PS3_HOST(instance)); + } + + if (try_count == PS3_REG_WRITE_RETRY_NUM) { + ps3_instance_state_transfer_to_dead(instance); + } +} + +U64 ps3_switch_ioc_reg_read(struct ps3_instance *instance, void __iomem *reg); + +static inline void +ps3_ioc_mgr_req_queue_lock_init(struct ps3_instance *instance) +{ + ps3_spin_lock_init(&instance->req_queue_lock); +} + +static inline Bool ps3_ioc_mgr_max_fw_cmd_get(struct ps3_instance *instance, + U32 *max_cmd_count) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3MaxFwCmd_u *reg_max_fw_cmd = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3MaxFwCmd, value); + INJECT_START(PS3_ERR_IJ_GET_REPLYQ_COUNT_INVALID, &value) + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3MaxFwCmd NOK!\n", + PS3_HOST(instance)); + *max_cmd_count = 0; + ret = PS3_FALSE; + goto l_out; + } + + reg_max_fw_cmd = (HilReg0Ps3RegisterFPs3MaxFwCmd_u *)&value; + *max_cmd_count = (U32)reg_max_fw_cmd->reg.ps3MaxFwCmd; + + if(instance->is_adjust_register_count) { + *max_cmd_count += 1; + } + if (reset_devices && *max_cmd_count > PS3_MAX_CMD_COUNT_DURING_RESET_DEVICES) { + *max_cmd_count = PS3_MAX_CMD_COUNT_DURING_RESET_DEVICES; + } +l_out: + return ret; + +} + +static inline U32 +ps3_ioc_mgr_max_msix_vectors_get(struct ps3_instance *instance) +{ + U64 reg_max_msix_vectors = PS3_MAX_REPLY_QUE_COUNT; + (void)instance; + return (U32)(reg_max_msix_vectors & PS3_FW_MAX_MSIX_VECTORS_MASK); +} + +static inline Bool ps3_ioc_mgr_max_chain_size_get( + struct ps3_instance *instance, U32 *max_chain_size) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3MaxChainSize_u *max_chain_size_u = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3MaxChainSize, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3MaxChainSize NOK!\n", + PS3_HOST(instance)); + *max_chain_size = 0; + ret = PS3_FALSE; + goto l_out; + } + + max_chain_size_u = (HilReg0Ps3RegisterFPs3MaxChainSize_u *)&value; + *max_chain_size = (U32)max_chain_size_u->reg.ps3MaxChainSize; +l_out: + return ret; +} + +static inline Bool ps3_ioc_mgr_max_vd_info_size_get( + struct ps3_instance *instance, U32 *vd_info_size) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3MaxVdInfoSize_u *vd_info_size_u = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3MaxVdInfoSize, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3MaxVdInfoSize NOK!\n", + PS3_HOST(instance)); + *vd_info_size = 0; + ret = PS3_FALSE; + goto l_out; + } + vd_info_size_u = (HilReg0Ps3RegisterFPs3MaxVdInfoSize_u *)&value; + + *vd_info_size = (U32)vd_info_size_u->reg.ps3MaxVdInfoSize; +l_out: + return ret; +} + +static inline Bool ps3_ioc_mgr_max_nvme_page_size_get( + struct ps3_instance *instance, U32 *max_nvme_page_size) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3MaxNvmePageSize_u *max_nvme_page_size_u = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3MaxNvmePageSize, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3MaxNvmePageSize NOK!\n", + PS3_HOST(instance)); + *max_nvme_page_size = 0; + ret = PS3_FALSE; + goto l_out; + } + + max_nvme_page_size_u = (HilReg0Ps3RegisterFPs3MaxNvmePageSize_u *)&value; + *max_nvme_page_size = (U32)max_nvme_page_size_u->reg.ps3MaxNvmePageSize; +l_out: + return ret; +} + +static inline Bool ps3_ioc_mgr_is_dma64_support(struct ps3_instance *instance, + Bool *is_dma64_support) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport NOK!\n", + PS3_HOST(instance)); + *is_dma64_support = PS3_FALSE; + ret = PS3_FALSE; + goto l_out; + } + + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + *is_dma64_support = (ps3_feature_support->reg.dmaBit64Support != 0); +l_out: + return ret; +} + +static inline Bool ps3_max_replyq_count_get(struct ps3_instance *instance, + U32 *max_replyq_count) +{ + Bool ret = PS3_TRUE; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3MaxReplyque, value); + INJECT_START(PS3_ERR_IJ_GET_REPLYQ_COUNT_INVALID, &value) + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3MaxReplyque NOK!\n", + PS3_HOST(instance)); + *max_replyq_count = 0; + ret = PS3_FALSE; + goto l_out; + } + + *max_replyq_count = value & 0xffff; +l_out: + return ret; +} + +static inline Bool ps3_ioc_fw_version_get(struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3FirmwareVersion_u *pver = NULL; + U64 fw_version_last = instance->ioc_fw_version; + U64 ver = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3FirmwareVersion, ver); + if (ver == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FirmwareVersion NOK!\n", + PS3_HOST(instance)); + instance->ioc_fw_version = fw_version_last; + ret = PS3_FALSE; + goto l_out; + } + + pver = (HilReg0Ps3RegisterFPs3FirmwareVersion_u *)&ver; + instance->ioc_fw_version = (U64)pver->reg.ps3FmVer; +l_out: + return ret; +} + +static inline Bool ps3_ioc_sgl_mode_support(struct ps3_instance *instance, + Bool *is_sgl_mode_support) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport NOK!\n", + PS3_HOST(instance)); + *is_sgl_mode_support = PS3_FALSE; + ret = PS3_FALSE; + goto l_out; + } + + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + *is_sgl_mode_support = (ps3_feature_support->reg.sglModeSupport == 1); +l_out: + return ret; +} + +static inline Bool ps3_ioc_dump_support_get(struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + Bool last_dump_support = instance->dump_context.is_dump_support; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + INJECT_START(PS3_ERR_IJ_FEATURE_SUPPORT_ERR, &value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport NOK!\n", + PS3_HOST(instance)); + instance->dump_context.is_dump_support = last_dump_support; + ret = PS3_FALSE; + goto l_out; + } + + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + instance->dump_context.is_dump_support = + (ps3_feature_support->reg.dumpCrashSupport == 1); +l_out: + return ret; +} + +static inline Bool ps3_ioc_state_halt_support_get(struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + Bool last_halt_support = instance->is_ioc_halt_support; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport NOK!\n", + PS3_HOST(instance)); + instance->is_ioc_halt_support = last_halt_support; + ret = PS3_FALSE; + goto l_out; + } + + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + instance->is_ioc_halt_support = (ps3_feature_support->reg.fwHaltSupport == 1); +l_out: + return ret; +} + +static inline Bool ps3_ioc_recovery_count_get(struct ps3_instance *instance, + U32 *recovery_count) +{ +#if 0 + Bool ret = PS3_TRUE; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3SoftresetCounter, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3Debug4 failed!\n", + PS3_HOST(instance)); + *recovery_count = 0; + ret = PS3_FALSE; + goto l_out; + } + + *recovery_count = (U32)(value & PS3_IOC_RECOVERY_COUNT_MASK); +l_out: + return ret; +#else + (void) instance; + *recovery_count = 0; + return PS3_TRUE; +#endif +} + +static inline U32 ps3_ioc_state_get(struct ps3_instance *instance) +{ + U64 ioc_state = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3SocFwState, ioc_state); + return (U32)(ioc_state & PS3_FW_STATE_MASK); +} + +static inline Bool ps3_ioc_state_get_with_check(struct ps3_instance *instance, + U32 *ioc_state) +{ + Bool ret = PS3_TRUE; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3SocFwState, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3SocFwState NOK!\n", + PS3_HOST(instance)); + *ioc_state = 0; + ret = PS3_FALSE; + goto l_out; + } + + *ioc_state = (U32)value & PS3_FW_STATE_MASK; +l_out: + return ret; +} + +static inline Bool ps3_get_doorbell_done_with_check(struct ps3_instance *instance, + Bool *is_doorbell_done) +{ + Bool ret = PS3_TRUE; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3RegCmdState, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3RegCmdState NOK!\n", + PS3_HOST(instance)); + *is_doorbell_done = PS3_FALSE; + ret = PS3_FALSE; + goto l_out; + } + + *is_doorbell_done = value & PS3_DOORBELL_DONE; + + if (*is_doorbell_done) { + value &= ~PS3_DOORBELL_DONE; + if (instance->peer_instance != NULL && + instance->peer_instance->reg_set != NULL) { + PS3_IOC_REG_WRITE_WITH_CHECK(instance, reg_f.Excl_reg, ps3RegCmdState, value); + PS3_IOC_REG_WRITE_WITH_CHECK(instance->peer_instance, + reg_f.Excl_reg, ps3RegCmdState, value); + } else { + PS3_IOC_REG_WRITE_WITH_CHECK(instance, reg_f.Excl_reg, ps3RegCmdState, value); + } + + } +l_out: + return ret; +} + +static inline Bool ps3_get_max_r1x_cmds_with_check(struct ps3_instance *instance, + U16 *max_r1x_cmds) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3MaxSecR1xCmds_u *ps3_max_sec_r1x_cmds = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3MaxSecR1xCmds, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3Debug6 NOK!\n", + PS3_HOST(instance)); + *max_r1x_cmds = 0; + ret = PS3_FALSE; + goto l_out; + } + + ps3_max_sec_r1x_cmds = (HilReg0Ps3RegisterFPs3MaxSecR1xCmds_u *)&value; + *max_r1x_cmds = ps3_max_sec_r1x_cmds->reg.ps3MaxSecR1xCmds; +l_out: + return ret; +} + +static inline Bool ps3_check_debug0_valid_with_check( + struct ps3_instance *instance, Bool *is_doorbell_valid, U32 check_mask) +{ + Bool ret = PS3_TRUE; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3CmdTrigger, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3CmdTrigger NOK!\n", + PS3_HOST(instance)); + *is_doorbell_valid = PS3_FALSE; + ret = PS3_FALSE; + goto l_out; + } + + *is_doorbell_valid = (value & check_mask); +l_out: + return ret; +} + +static inline Bool ps3_ioc_heartbeat_get(struct ps3_instance *instance, + U64 *heartbeat_value) +{ + Bool ret = PS3_TRUE; + static Bool last_fault_state = PS3_TRUE; + + *heartbeat_value = ps3_ioc_reg_read_with_check(instance, + &instance->reg_set->reg_f.Excl_reg.ps3SocFwState); + INJECT_START(PS3_ERR_IJ_READ_FW_STATE_REG_FF, heartbeat_value) + if (*heartbeat_value == U64_MAX) { + if (last_fault_state) { + LOG_ERROR("hno:%u read reg ps3SocFwState NOK!\n", + PS3_HOST(instance)); + last_fault_state = PS3_FALSE; + } + *heartbeat_value = 0; + ret = PS3_FALSE; + goto l_out; + } else { + last_fault_state = PS3_TRUE; + LOG_DEBUG("hno:%u read reg ps3SocFwState success value[%llu]!\n", + PS3_HOST(instance), *heartbeat_value); + } + +l_out: + return ret; +} + +static inline Bool ps3_ioc_recovery_support_get(struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + Bool last_shallow_soft_recovery_support = + instance->is_shallow_soft_recovery_support; + Bool last_deep_soft_recovery_support = + instance->is_deep_soft_recovery_support; + Bool last_hard_recovery_support = + instance->is_hard_recovery_support; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport NOK!\n", + PS3_HOST(instance)); + instance->is_shallow_soft_recovery_support = + last_shallow_soft_recovery_support; + instance->is_deep_soft_recovery_support = + last_deep_soft_recovery_support; + instance->is_hard_recovery_support = + last_hard_recovery_support; + ret = PS3_FALSE; + goto l_out; + } + + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + instance->is_shallow_soft_recovery_support = + (ps3_feature_support->reg.shallowSoftRecoverySupport == 1); + instance->is_deep_soft_recovery_support = + (ps3_feature_support->reg.deepSoftRecoverySupport == 1); + instance->is_hard_recovery_support = + (ps3_feature_support->reg.hardRecoverySupport == 1); +l_out: + return ret; +} + +static inline Bool ps3_ioc_multi_func_support(struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + U64 value = 0; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3FeatureSupport failed!\n", + PS3_HOST(instance)); + ret = PS3_FALSE; + goto l_out; + } + + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + ret = (ps3_feature_support->reg.multiDevfnSupport == 1); +l_out: + return ret; +} + +static inline Bool ps3_ioc_security_state_check(struct ps3_instance *instance) +{ + U64 value = 0; + Bool ret = PS3_FALSE; + + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3Debug7, value); + if (value == U64_MAX || (value & 0x1)) { + ret = PS3_TRUE; + LOG_ERROR("hno:%u read register NOK or ioc is security [%llu]\n", + PS3_HOST(instance), value); + } + +#ifdef PS3_HARDWARE_SIM + ret = PS3_FALSE; +#endif + + return ret; +} + +static inline Bool ps3_ioc_atu_support_get(struct ps3_instance *instance, U8 *bit_pos) +{ + Bool ret = PS3_TRUE; + HilRegPs3RegisterFPs3AtuSupport_u *ps3_atu_support = NULL; + U64 value = PS3_BIT_POS_DEFAULT; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3Debug8, value); + INJECT_START(PS3_ERR_IJ_READ_ATU_REG_FAILED, &value); + if (value == U64_MAX) { + LOG_ERROR("hno:%u read reg ps3AtuSupport NOK!\n", + PS3_HOST(instance)); + *bit_pos = PS3_BIT_POS_DEFAULT; + ret = PS3_FALSE; + goto l_out; + } + ps3_atu_support = (HilRegPs3RegisterFPs3AtuSupport_u *)&value; + *bit_pos = ps3_atu_support->reg.bitPos; +l_out: + return ret; +} + +static inline Bool ps3_ioc_atu_support_safe_get(struct ps3_instance *instance, U8 *bit_pos) +{ + Bool ret = PS3_FALSE; + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + U32 count = 0; + U32 retry_cnt = 0; + U8 tmp_bit_pos = 0; + Bool is_first = PS3_TRUE; + for (; retry_cnt < PS3_ATU_SUPPORT_READ_RETRY_NUM; retry_cnt++) { + if (!ps3_ioc_atu_support_get(instance, &tmp_bit_pos)) { + goto l_out; + } + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_IOC_TO_READY_FAILED, &fw_cur_state); + if (!ps3_ioc_state_valid_check(fw_cur_state)) { + for (; count < PS3_REG_READ_RETRY_NUM; count++) { + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_IOC_TO_READY_FAILED, &fw_cur_state); + if (ps3_ioc_state_valid_check(fw_cur_state)) { + if (!ps3_ioc_atu_support_get(instance, &tmp_bit_pos)) { + goto l_out; + } + *bit_pos = tmp_bit_pos; + ret = PS3_TRUE; + goto l_out; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + } + goto l_out; + } + if (is_first) { + *bit_pos = tmp_bit_pos; + is_first = PS3_FALSE; + continue; + } + INJECT_START(PS3_ERR_IJ_BIT_POS_ERR, &tmp_bit_pos); + if (*bit_pos != tmp_bit_pos) { + goto l_out; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_50MS); + } + ret = PS3_TRUE; +l_out: + return ret; +} + +static inline Bool ps3_ioc_atu_support_retry_read(struct ps3_instance *instance, U8 *bit_pos) +{ + U32 retry_cnt = PS3_ATU_SUPPORT_READ_RETRY_NUM; + Bool ret = PS3_FALSE; + + while (retry_cnt--) { + if (ps3_ioc_atu_support_safe_get(instance, bit_pos)) { + ret = PS3_TRUE; + break; + } + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + } + return ret; +} + +static inline void ps3_ioc_can_hardreset_set(struct ps3_instance *instance, U8 enable) +{ + U64 can_hardreset = 0; + HilRegPs3RegisterFPs3CanHardReset_u *ps3_can_hardreset = NULL; + + ps3_can_hardreset = (HilRegPs3RegisterFPs3CanHardReset_u*)&can_hardreset; + ps3_can_hardreset->reg.canHardReset = enable; + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3Debug9, ps3_can_hardreset->val); +} + +Bool ps3_feature_support_reg_get(struct ps3_instance *instance); + +void ps3_ioc_scsi_cmd_send(struct ps3_instance *instance, + struct PS3CmdWord *cmd_word); + +struct pglist_data *first_online_pgdat(void); + +struct pglist_data *next_online_pgdat(struct pglist_data *pgdat); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_ioc_state.c b/drivers/scsi/ps3stor/ps3_ioc_state.c new file mode 100644 index 0000000000000000000000000000000000000000..bb5213fd0808b527cee0af0f7f0cb720ad2f8855 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioc_state.c @@ -0,0 +1,851 @@ + +#ifndef _WINDOWS +#include +#include +#include +#endif + +#include "ps3_ioc_state.h" +#include "ps3_driver_log.h" +#include "ps3_ioc_manager.h" +#include "ps3_module_para.h" + +#define PS3_SOFTRESET_MASK (0xFF) +#define PS3_HARDRESET_MASK (0xFF) + +enum ps3_reset_type { + PS3_FW_HARD_RESET = 0, + PS3_FW_SHALLOW_SOFT_RESET = 1, + PS3_FW_DEEP_SOFT_RESET = 2, +}; + +static inline const S8 *namePS3ResetType(S32 s) +{ + static const S8 *myNames[] = { + [PS3_FW_HARD_RESET] = "PS3_FW_HARD_RESET", + [PS3_FW_SHALLOW_SOFT_RESET] = "PS3_FW_SHALLOW_SOFT_RESET", + [PS3_FW_DEEP_SOFT_RESET] = "PS3_FW_DEEP_SOFT_RESET" + }; + + if (s > PS3_FW_DEEP_SOFT_RESET) { + return "PS3_RESET_TYPE_INVALID"; + } + + return myNames[s]; +} + +struct ps3_reset_key_map { + U32 reset_key_offset; + U32 reset_state_offset; + U32 reset_offset; + U32 reset_type; + U32 reset_status_offset; + U32 reset_status_mask; +}; + +struct ps3_state_desc_map { + U32 state; + const char *state_desc; +}; + +static struct ps3_reset_key_map g_reset_key_table[] = { + [PS3_FW_HARD_RESET] = { + offsetof(HilReg0Ps3RegisterF_s, ps3HardresetKey), + offsetof(HilReg0Ps3RegisterF_s, ps3HardresetState), + offsetof(HilReg0Ps3RegisterF_s, ps3Hardreset), + PS3_FW_HARD_RESET_ACT, + offsetof(HilReg0Ps3RegisterF_s, ps3Hardreset), + PS3_HARDRESET_MASK + }, + [PS3_FW_SHALLOW_SOFT_RESET] = { + offsetof(HilReg0Ps3RegisterF_s, ps3SoftresetKey), + offsetof(HilReg0Ps3RegisterF_s, ps3SoftresetState), + offsetof(HilReg0Ps3RegisterF_s, ps3Softreset), + PS3_FW_STATE_ACT_SHALLOW_SOFT_RESET, + offsetof(HilReg0Ps3RegisterF_s, ps3Softreset), + PS3_SOFTRESET_MASK + }, + [PS3_FW_DEEP_SOFT_RESET] = { + offsetof(HilReg0Ps3RegisterF_s, ps3SoftresetKey), + offsetof(HilReg0Ps3RegisterF_s, ps3SoftresetState), + offsetof(HilReg0Ps3RegisterF_s, ps3Softreset), + PS3_FW_STATE_ACT_DEEP_SOFT_RESET, + offsetof(HilReg0Ps3RegisterF_s, ps3Softreset), + PS3_SOFTRESET_MASK + }, +}; + +static struct ps3_state_desc_map g_state_desc[] = { + {PS3_FW_STATE_UNDEFINED, "PS3_FW_STATE_UNDEFINED"}, + {PS3_FW_STATE_START, "PS3_FW_STATE_START"}, + {PS3_FW_STATE_READY, "PS3_FW_STATE_READY"}, + {PS3_FW_STATE_WAIT, "PS3_FW_STATE_WAIT"}, + {PS3_FW_STATE_RUNNING, "PS3_FW_STATE_RUNNING"}, + {PS3_FW_STATE_FLUSHING, "PS3_FW_STATE_FLUSHING"}, + {PS3_FW_STATE_RESET, "PS3_FW_STATE_RESET"}, + {PS3_FW_STATE_FAULT, "PS3_FW_STATE_FAULT"}, + {PS3_FW_STATE_CRITICAL, "PS3_FW_STATE_CRITICAL"}, + {PS3_FW_STATE_HALT, "PS3_FW_STATE_HALT"} +}; + +static void ps3_reset_key_write(struct ps3_instance *instance, + U32 offset) +{ + static U32 reset_key_array[] = { + PS3_FW_DIAG_1ST_KEY, + PS3_FW_DIAG_2ND_KEY, + PS3_FW_DIAG_3RD_KEY, + PS3_FW_DIAG_4TH_KEY, + PS3_FW_DIAG_5TH_KEY, + PS3_FW_DIAG_6TH_KEY, + PS3_FW_DIAG_7TH_KEY, + PS3_FW_DIAG_8TH_KEY, + PS3_FW_DIAG_9TH_KEY + }; + U32 idx = 0; + + for(idx = 0;idx < ARRAY_SIZE(reset_key_array);idx++) { + PS3_IOC_REG_WRITE_OFFSET(instance, offset, (U64)reset_key_array[idx]); + } +} +static void ps3_hardreset_key_write(struct ps3_instance *instance, + U8 *reset_key_vir_addr, U64 *timeval) +{ + static U32 reset_key_array[] = { + PS3_FW_DIAG_1ST_KEY, + PS3_FW_DIAG_2ND_KEY, + PS3_FW_DIAG_3RD_KEY, + PS3_FW_DIAG_4TH_KEY, + PS3_FW_DIAG_5TH_KEY, + PS3_FW_DIAG_6TH_KEY, + PS3_FW_DIAG_7TH_KEY, + PS3_FW_DIAG_8TH_KEY, + PS3_FW_DIAG_9TH_KEY + }; + U32 idx = 0; + timeval[PS3_START_WRITE_KEY_REG] = ps3_1970_now_ms_get(); + for(idx = 0;idx < ARRAY_SIZE(reset_key_array);idx++) { + ps3_ioc_hardreset_reg_write(instance, + (U64)reset_key_array[idx], reset_key_vir_addr, 0); + } + timeval[PS3_END_WRITE_KEY_REG] = ps3_1970_now_ms_get(); +} +static S32 ps3_reset_key_state_check(struct ps3_instance *instance, + U32 offset) +{ + U32 reset_key_state = 0; + U32 read_count = 0; + const U32 retry_max = 50; + S32 ret = PS3_SUCCESS; + U64 value = 0; + + do { + if (read_count >= retry_max) { + LOG_ERROR("hno:%u PS3 reset key state is still " + "disabled after 5 sec \n", PS3_HOST(instance)); + ret = -PS3_FAILED; + break; + } + + if (read_count != 0) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + + PS3_IOC_REG_READ_OFFSET(instance, offset, value); + reset_key_state = (U32)value; + + read_count++; + } while (!(reset_key_state & PS3_FW_DIAG_ENABLE) || + (reset_key_state == U32_MAX)); + + if (ret == PS3_SUCCESS) { + LOG_INFO("hno:%u PS3 reset key state is enabled after %d msecs\n", + PS3_HOST(instance), + (read_count - 1) * PS3_LOOP_TIME_INTERVAL_100MS); + } + + return ret; +} +static S32 ps3_hardreset_key_state_check(struct ps3_instance *instance, + U8 *reset_key_state_vir_addr, U64 *timeval) +{ + U32 reset_key_state = 0; + U32 read_count = 0; + const U32 retry_max = 900; + S32 ret = PS3_SUCCESS; + + timeval[PS3_START_WAIT_KEY_READY_REG] = ps3_1970_now_ms_get(); + do { + if (read_count >= retry_max) { + ret = -PS3_FAILED; + break; + } + + if (read_count != 0) { + ps3_mdelay(PS3_LOOP_TIME_INTERVAL_1MS); + } + + reset_key_state = (U32)ps3_ioc_hardreset_reg_read(instance, + reset_key_state_vir_addr); + + read_count++; + } while (!(reset_key_state & PS3_FW_DIAG_ENABLE) || + ((U32_MAX & reset_key_state) == U32_MAX)); + timeval[PS3_END_WAIT_KEY_READY_REG] = ps3_1970_now_ms_get(); + + return ret; +} + +static S32 ps3_after_reset_request_check( + struct ps3_instance *instance, enum ps3_reset_type reset_type) +{ + U32 fw_state = instance->ioc_adpter->ioc_state_get(instance); + U32 read_count = 0; +#ifdef PS3_HARDWARE_HAPS_V200 + const U32 retry_max = 3600; +#else + const U32 retry_max = 1800; +#endif + S32 ret = -PS3_FAILED; + + while(read_count < retry_max) { + if ( (fw_state == PS3_FW_STATE_START) || + (fw_state == PS3_FW_STATE_READY)) { + ret = PS3_SUCCESS; + break; + } + if ((reset_type == PS3_FW_SHALLOW_SOFT_RESET) || + (reset_type == PS3_FW_DEEP_SOFT_RESET)) { + if (fw_state == PS3_FW_STATE_RUNNING) { + ret = PS3_SUCCESS; + break; + } + } + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + break; + } +#ifdef PS3_HARDWARE_HAPS_V200 + ps3_msleep(PS3_LOOP_TIME_INTERVAL_3000MS); +#else + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); +#endif + fw_state = instance->ioc_adpter->ioc_state_get(instance); + read_count++; + } + + if ( ret != PS3_SUCCESS ) { + LOG_ERROR("hno:%u PS3 IOC state is not valid 180 secs after IOC reset, fw state is %s\n", + PS3_HOST(instance),ps3_ioc_state_print(fw_state)); + } + + LOG_INFO("hno:%u fw state is %s\n", PS3_HOST(instance), + ps3_ioc_state_print(fw_state)); + + return ret; + +} + +static S32 ps3_reset_request_completion_check( + struct ps3_instance *instance, U32 offset, U32 completion_mask) +{ + U32 read_count = 0; + const U32 retry_max = 1000; + S32 ret = PS3_SUCCESS; + U64 value = 0; + U32 completion = 0; + + PS3_IOC_REG_READ_OFFSET(instance, offset, value); + completion = (U32)value; + while (completion & completion_mask || + completion == U32_MAX) { + if (read_count > retry_max) { + LOG_ERROR("hno:%u PS3 reset flag is not " + "clear 100 secs after reset request \n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + break; + } + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_FAILED; + break; + } + + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + PS3_IOC_REG_READ_OFFSET(instance, offset, value); + completion = (U32)value; + read_count++; + } + + if (ret == PS3_SUCCESS) { + LOG_INFO("hno:%u PS3 reset complete %d msecs after reset complete \n", + PS3_HOST(instance), read_count * PS3_LOOP_TIME_INTERVAL_100MS); + } + + return ret; +} + +const char *ps3_ioc_state_print(U32 state) +{ + U32 idx = 0; + U32 fw_state = state & PS3_FW_STATE_MASK; + const char *ps3_state_name = "invalid state"; + + for (idx = 0;idx < ARRAY_SIZE(g_state_desc);idx++) { + if (g_state_desc[idx].state == fw_state) { + ps3_state_name = g_state_desc[idx].state_desc; + break; + } + } + + return ps3_state_name; +} + +static inline void ps3_ioc_state_trigger_transition(struct ps3_instance *instance, U32 action) +{ + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3Doorbell, (U64)action); +} + +static inline void ps3_ioc_debug0_trigger(struct ps3_instance *instance, U32 mask_value) +{ + PS3_IOC_REG_WRITE(instance, reg_f.Excl_reg, ps3CmdTrigger, (U64)mask_value); +} + +S32 ps3_ioc_state_fault_wait(struct ps3_instance *instance) +{ + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + S32 ret = PS3_SUCCESS; + U32 count = 0; + + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + while (count < PS3_FW_STATE_TO_FAULT_TMO_LOOP_COUNT) { + if (fw_cur_state == PS3_FW_STATE_FAULT || + fw_cur_state == PS3_FW_STATE_CRITICAL) { + LOG_INFO("hno:%u within 180s fw transfer to %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state)); + break; + } + + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + count++; + } + + if (fw_cur_state != PS3_FW_STATE_FAULT) { + LOG_ERROR("hno:%u fw state[%s] is not fault\n", + PS3_HOST(instance), ps3_ioc_state_print(fw_cur_state)); + ret = -PS3_FAILED; + } else { + LOG_INFO("hno:%u fw state transition to %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state)); + } + + return ret; +} + +S32 ps3_ioc_state_ready_wait(struct ps3_instance *instance) +{ + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + S32 ret = PS3_SUCCESS; + U32 count = 0; + Bool is_unload_valid = PS3_FALSE; + + ps3_check_debug0_valid_with_check(instance, &is_unload_valid, + PS3_CMD_TRIGGER_UNLOAD); + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + while (count < instance->wait_ready_timeout) { +#if 0 + if ( (fw_cur_state == PS3_FW_STATE_READY) + || (fw_cur_state == PS3_FW_STATE_FAULT) + || (fw_cur_state == PS3_FW_STATE_HALT) ){ + break; + } +#else + INJECT_START(PS3_ERR_IJ_FORCE_HARD_READY_PCIE_ERRL, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + + if (fw_cur_state == PS3_FW_STATE_READY && !is_unload_valid) { + LOG_INFO("hno:%u within 180s fw transfer to %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state)); + break; + } +#endif +#ifdef PS3_HARDWARE_HAPS_V200 + ps3_msleep(PS3_LOOP_TIME_INTERVAL_3000MS); +#else + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); +#endif + ps3_check_debug0_valid_with_check(instance, &is_unload_valid, + PS3_CMD_TRIGGER_UNLOAD); + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + count++; + } + + if (fw_cur_state != PS3_FW_STATE_READY || is_unload_valid) { + LOG_ERROR("hno:%u fw state[%s] is not ready, or unload[%d] not done\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state), is_unload_valid); + ret = -PS3_FAILED; + } else { + LOG_INFO("hno:%u fw state transition to %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state)); + } + +l_out: + return ret; +} + +S32 ps3_ioc_state_transfer_to_ready(struct ps3_instance *instance) +{ + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + S32 ret = PS3_SUCCESS; + + if (!ps3_ioc_state_get_with_check(instance, &fw_cur_state)) { + ret = -PS3_FAILED; + goto l_out; + } + + LOG_INFO("hno:%u fw state is %s(0x%x)\n", + PS3_HOST(instance), ps3_ioc_state_print(fw_cur_state), fw_cur_state); + + switch (fw_cur_state) { + case PS3_FW_STATE_UNDEFINED: + case PS3_FW_STATE_RESET: + case PS3_FW_STATE_START: + case PS3_FW_STATE_FLUSHING: + ret = ps3_ioc_state_ready_wait(instance); + if (ret != PS3_SUCCESS) { + if (ret != -PS3_IN_PCIE_ERR) { + ret = -PS3_NO_RECOVERED; + } + LOG_ERROR("hno:%u fw state to ready NOK \n", + PS3_HOST(instance)); + } + break; + case PS3_FW_STATE_READY: + break; + case PS3_FW_STATE_WAIT: + case PS3_FW_STATE_RUNNING: + LOG_WARN("hno:%u fw state is wait/running\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + break; + case PS3_FW_STATE_FAULT: + case PS3_FW_STATE_CRITICAL: + case PS3_FW_STATE_HALT: + LOG_ERROR("hno:%u fw state is fault/halt, to ready NOK \n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + break; + + default: + ret = ps3_ioc_state_ready_wait(instance); + break; + } +l_out: + return ret; +} + +S32 ps3_ioc_state_transfer_wait_to_running(struct ps3_instance *instance) +{ + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + S32 ret = PS3_SUCCESS; + U32 count = 0; + + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_WAIT_RUNNING_FAIL, &fw_cur_state) + LOG_INFO("hno:%u fw state is %s(0x%x)\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state), fw_cur_state); + + while (count < PS3_FW_STATE_TO_RUNNING_TMO_LOOP_COUNT) { + if ( (fw_cur_state == PS3_FW_STATE_RUNNING) + || (fw_cur_state == PS3_FW_STATE_FAULT) + || (fw_cur_state == PS3_FW_STATE_HALT) + || (fw_cur_state == PS3_FW_STATE_CRITICAL)){ + break; + } + INJECT_START(PS3_ERR_IJ_FORCE_IOC_RUNNING_PCI_ERR, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + ps3_mutex_unlock(&instance->state_machine.lock); + break; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + count++; + } + INJECT_START(PS3_ERR_IJ_WAIT_RUNNING_FAIL1, &fw_cur_state) + if (fw_cur_state != PS3_FW_STATE_RUNNING) { + LOG_ERROR("hno:%u fw state transition NOK, state is %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(fw_cur_state)); + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + } else { + ret = -PS3_FAILED; + } + } + + LOG_INFO("hno:%u fw state transit to %s\n", + PS3_HOST(instance), ps3_ioc_state_print(fw_cur_state)); +l_out: + return ret; +} + +static S32 ps3_ioc_state_reset_request(struct ps3_instance *instance, + enum ps3_reset_type reset_type) +{ + S32 ret = -PS3_FAILED; + U32 ioc_reset_type = 0; + U32 reset_status_mask = 0; + U32 cur_state = 0; + + ioc_reset_type = g_reset_key_table[reset_type].reset_type; + reset_status_mask = g_reset_key_table[reset_type].reset_status_mask; + + cur_state = ps3_atomic_read(&instance->state_machine.state); + + LOG_INFO("hno:%u %s, key_offset: 0x%x, state_offset: 0x%x," + " reset_offset: 0x%x, status_offset: 0x%x, IOC reset_type: 0x%8x" + " status mask: 0x%8x cur_state[%d]\n", + PS3_HOST(instance), namePS3ResetType(reset_type), + g_reset_key_table[reset_type].reset_key_offset, + g_reset_key_table[reset_type].reset_state_offset, + g_reset_key_table[reset_type].reset_offset, + g_reset_key_table[reset_type].reset_status_offset, + g_reset_key_table[reset_type].reset_type, + g_reset_key_table[reset_type].reset_status_mask, + cur_state); + preempt_disable(); + ps3_reset_key_write(instance, g_reset_key_table[reset_type].reset_key_offset); + preempt_enable(); + + ps3_reset_key_state_check(instance, g_reset_key_table[reset_type].reset_state_offset); + + PS3_IOC_REG_WRITE_OFFSET(instance, g_reset_key_table[reset_type].reset_offset, (U64)ioc_reset_type); + + if (ps3_hard_reset_waiting_query()) { + ps3_msleep(ps3_hard_reset_waiting_query()); + } + + if (ps3_reset_request_completion_check(instance, g_reset_key_table[reset_type].reset_status_offset, + reset_status_mask) != PS3_SUCCESS) { + goto l_out; + } + + if (ps3_after_reset_request_check(instance, reset_type) != + PS3_SUCCESS) { + goto l_out; + } + + ret = PS3_SUCCESS; + +l_out: + LOG_INFO("hno:%u PS3 %s complete, ret:%d\n", + PS3_HOST(instance), namePS3ResetType(reset_type), ret); + return ret; +} + +static S32 ps3_ioc_state_hardreset_request(struct ps3_instance *instance, + enum ps3_reset_type reset_type) +{ + S32 ret = -PS3_FAILED; + U8 *reset_key_addr = NULL; + U8 *reset_state_addr = NULL; + U8 *reset_addr = NULL; + U32 ioc_reset_type = 0; + U32 cur_state = 0; + U8 *reg_start = (U8*)instance->reg_set; + U32 read_count = 0; + const U32 retry_max = 180; + ULong flags = 0; + U64 timeval[PS3_RESET_MAX_COUNT] = {0}; + + reset_key_addr = reg_start + + g_reset_key_table[reset_type].reset_key_offset; + reset_state_addr = reg_start + + g_reset_key_table[reset_type].reset_state_offset; + reset_addr = reg_start + + g_reset_key_table[reset_type].reset_offset; + ioc_reset_type = g_reset_key_table[reset_type].reset_type; + + cur_state = ps3_atomic_read(&instance->state_machine.state); + + LOG_INFO("hno:%u %s, key_offset: 0x%x, state_offset: 0x%x," + " reset_offset: 0x%x, status_offset: 0x%x, IOC reset_type: 0x%8x" + " status mask: 0x%8x cur_state[%d]\n", + PS3_HOST(instance), namePS3ResetType(reset_type), + g_reset_key_table[reset_type].reset_key_offset, + g_reset_key_table[reset_type].reset_state_offset, + g_reset_key_table[reset_type].reset_offset, + g_reset_key_table[reset_type].reset_status_offset, + g_reset_key_table[reset_type].reset_type, + g_reset_key_table[reset_type].reset_status_mask, + cur_state); + instance->is_hard_reset = PS3_TRUE; + mb(); + while(ps3_atomic_read(&instance->reg_op_count) != 0){ + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + + if(read_count++ > retry_max){ + LOG_INFO("hno:%u %s, wait reg op over:%d ms,failed\n", + PS3_HOST(instance), namePS3ResetType(reset_type), + read_count*PS3_LOOP_TIME_INTERVAL_100MS); + ret = -PS3_FAILED; + goto l_out; + } + } + INJECT_START(PS3_ERR_IJ_V2_RECOVERY_WAIT_NOTIFY, instance); + ps3_wait_scsi_cmd_done(instance, PS3_TRUE); + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + if (instance->peer_instance != NULL) { + ps3_wait_scsi_cmd_done(instance->peer_instance, PS3_TRUE); + ps3_wait_mgr_cmd_done(instance->peer_instance, PS3_TRUE); + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_4, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_INFO("hno:%u pcie recovery proceess\n", + PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + spin_lock_irqsave(&instance->recovery_context->ps3_hardreset_lock, flags); + ps3_hardreset_key_write(instance, reset_key_addr, timeval); + + ret = ps3_hardreset_key_state_check(instance, reset_state_addr, timeval); + if(ret != PS3_SUCCESS){ + spin_unlock_irqrestore(&instance->recovery_context->ps3_hardreset_lock, flags); + LOG_INFO("hno:%u %s, key check failed, ret:%d\n", + PS3_HOST(instance), namePS3ResetType(reset_type),ret); + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_5, instance) + if (ps3_pci_err_recovery_get(instance)) { + spin_unlock_irqrestore(&instance->recovery_context->ps3_hardreset_lock, flags); + LOG_WARN("hno:%u pcie recovery proceess\n", + PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + + timeval[PS3_START_WRITE_HARDRESET_REG] = ps3_1970_now_ms_get(); + ps3_ioc_hardreset_reg_write(instance, (U64)ioc_reset_type, reset_addr, PS3_TRUE); + timeval[PS3_END_WRITE_HARDRESET_REG] = ps3_1970_now_ms_get(); + spin_unlock_irqrestore(&instance->recovery_context->ps3_hardreset_lock, flags); + LOG_INFO("hno:%u %s, key_offset: key state success," + "then write hardreset ioc_reset_type:%u, reset_addr:%p\n", + PS3_HOST(instance), namePS3ResetType(reset_type), ioc_reset_type, reset_addr); + LOG_INFO("hno:%u time:%lld-%lld-%lld-%lld-%lld-%lld\n", + PS3_HOST(instance), timeval[PS3_START_WRITE_KEY_REG], timeval[PS3_END_WRITE_KEY_REG], + timeval[PS3_START_WAIT_KEY_READY_REG], timeval[PS3_END_WAIT_KEY_READY_REG], + timeval[PS3_START_WRITE_HARDRESET_REG], timeval[PS3_END_WRITE_HARDRESET_REG]); + + instance->recovery_context->hardreset_count++; + if (ps3_hard_reset_waiting_query()) { + ps3_msleep(ps3_hard_reset_waiting_query()); + } + LOG_INFO("hno:%u %s, after sleep:%d ms\n", + PS3_HOST(instance), namePS3ResetType(reset_type),ps3_hard_reset_waiting_query()); + + instance->is_hard_reset = PS3_FALSE; + if ((ret = ps3_after_reset_request_check(instance, reset_type)) != + PS3_SUCCESS) { + goto l_out; + } + + ret = PS3_SUCCESS; + +l_out: + instance->is_hard_reset = PS3_FALSE; + LOG_INFO("hno:%u PS3 %s complete, ret:%d\n", + PS3_HOST(instance), namePS3ResetType(reset_type), ret); + return ret; +} + +S32 ps3_ioc_state_hard_reset(struct ps3_instance *instance) +{ + if (ps3_use_hard_reset_reg_query()) { + return ps3_ioc_state_hardreset_request(instance, PS3_FW_HARD_RESET); + } else { + return ps3_ioc_state_reset_request(instance, PS3_FW_SHALLOW_SOFT_RESET); + } +} + +S32 ps3_ioc_state_shallow_soft_reset(struct ps3_instance *instance) +{ + return ps3_ioc_state_reset_request(instance, PS3_FW_SHALLOW_SOFT_RESET); +} + +S32 ps3_ioc_state_deep_soft_reset(struct ps3_instance *instance) +{ + return ps3_ioc_state_reset_request(instance, PS3_FW_DEEP_SOFT_RESET); +} + +static S32 ps3_trigger_ioc_state_change_by_doorbell(struct ps3_instance *instance, + U32 expect_fw_state, U32 doorbell_trigger, u32 time_out) +{ + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + Bool is_doorbell_done = PS3_TRUE; + S32 ret = PS3_SUCCESS; + U32 count = 0; + + LOG2_WARN("hno:%u expect fw state:%s, doorbell_trigger is %d\n", + PS3_HOST(instance), + ps3_ioc_state_print(expect_fw_state), doorbell_trigger); + + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + if (fw_cur_state == expect_fw_state) { + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_2, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + ps3_ioc_state_trigger_transition(instance, doorbell_trigger); + + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + if (doorbell_trigger == PS3_REG_DOORBELL_STATE_TO_FAULT) { + ps3_get_doorbell_done_with_check(instance, &is_doorbell_done); + } + while (count < time_out) { + if (fw_cur_state == expect_fw_state && is_doorbell_done) { + break; + } + + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + if (fw_cur_state == PS3_FW_STATE_MASK) { + LOG_ERROR("hno:%u break because get fw_cur_state NOK.\n", + PS3_HOST(instance)); + break; + } + + if (doorbell_trigger == PS3_REG_DOORBELL_STATE_TO_FAULT && !is_doorbell_done) { + if (ps3_get_doorbell_done_with_check(instance, &is_doorbell_done) == PS3_FALSE) { + LOG_ERROR("hno:%u break because get doorbell_done NOK.\n", + PS3_HOST(instance)); + break; + } + } + + count++; + } + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_DOORBELL_FAILED, &fw_cur_state) + if (fw_cur_state != expect_fw_state) { + LOG_ERROR("hno:%u fw state transition NOK, is_doorbell_done %d state is %s\n", + PS3_HOST(instance), + is_doorbell_done, + ps3_ioc_state_print(fw_cur_state)); + ret = -PS3_FAILED; + } +l_out: + return ret; +} + +S32 ps3_ioc_notify_unload(struct ps3_instance *instance) +{ + Bool is_unload_valid = PS3_FALSE; + S32 ret = PS3_SUCCESS; + U32 count = 0; + U8 unload_type = PS3_CMD_TRIGGER_UNLOAD; + + LOG_WARN("hno:%u trigger ioc unload reg!!\n", + PS3_HOST(instance)); + + if (instance->state_machine.is_suspend) { + unload_type = PS3_CMD_TRIGGER_UNLOAD_SUSPEND; + } + + ps3_ioc_debug0_trigger(instance, unload_type); + + ps3_check_debug0_valid_with_check(instance, &is_unload_valid, + unload_type); + while (count < PS3_FW_STATE_TO_UNLOAD_TMO_LOOP_COUNT) { + if (!is_unload_valid) { + break; + } + + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + ps3_check_debug0_valid_with_check(instance, &is_unload_valid, + unload_type); + count++; + } + + if (is_unload_valid) { + LOG_ERROR("hno:%u do not wait unload done\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + + return ret; +} + +S32 ps3_ioc_state_force_to_fault(struct ps3_instance *instance) +{ + return ps3_trigger_ioc_state_change_by_doorbell(instance, + PS3_FW_STATE_FAULT, PS3_REG_DOORBELL_STATE_TO_FAULT, + PS3_FW_STATE_TO_FAULT_TMO_LOOP_COUNT); +} + +S32 ps3_ioc_state_force_to_halt(struct ps3_instance *instance) +{ + return ps3_trigger_ioc_state_change_by_doorbell(instance, + PS3_FW_STATE_HALT, PS3_REG_DOORBELL_STATE_TO_HALT, + PS3_FW_STATE_TO_HALT_TMO_LOOP_COUNT); +} + +#ifdef PS3_HARDWARE_ASIC +U32 ps3_ioc_heartbeat_detect(struct ps3_instance *instance) +{ + U32 ret = PS3_FALSE; + U64 heartbeat_value = 0; + + (void) instance; + + if (!ps3_enable_heartbeat_query()) { + return ret; + } + + if (!ps3_ioc_heartbeat_get(instance, &heartbeat_value)) { + LOG_DEBUG("hno:%u probably Linkdown\n", PS3_HOST(instance)); + return ret; + } + + if (heartbeat_value & instance->hard_dog_mask) { + LOG_DEBUG("hno:%u heartbeat detect success\n", PS3_HOST(instance)); + ret = PS3_TRUE; + } + + return ret; +} +#endif diff --git a/drivers/scsi/ps3stor/ps3_ioc_state.h b/drivers/scsi/ps3stor/ps3_ioc_state.h new file mode 100644 index 0000000000000000000000000000000000000000..268d87eb158948860907401472b7b46b9dffacec --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioc_state.h @@ -0,0 +1,81 @@ + +#ifndef _PS3_IOC_STATE_H_ +#define _PS3_IOC_STATE_H_ + +#include "ps3_instance_manager.h" + +enum { + PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_RAID = 18000, + PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_HBA = 18000, + PS3_WAIT_FOR_OUTSTANDING_IO_COMPLETE = 9000, + PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_SWITCH = 15000, + PS3_FW_STATE_TO_READY_TMO_LOOP_COUNT_RAID_HAPS = 3600, + PS3_FW_STATE_TO_RUNNING_TMO_LOOP_COUNT = 9000, + PS3_FW_STATE_TO_FAULT_TMO_LOOP_COUNT = 1500, + PS3_FW_STATE_TO_HALT_TMO_LOOP_COUNT = 9000, + PS3_FW_STATE_TO_UNLOAD_TMO_LOOP_COUNT = 500, + PS3_WAIT_EVENT_CMD_LOOP_COUNT = 100, + PS3_LOOP_TIME_INTERVAL_1MS = 1, + PS3_LOOP_TIME_INTERVAL_20MS = 20, + PS3_LOOP_TIME_INTERVAL_50MS = 50, + PS3_LOOP_TIME_INTERVAL_100MS = 100, + PS3_LOOP_TIME_INTERVAL_3000MS = 3000, + PS3_WRITE_HARD_RESET_WAIT_TIME_500MS = 500, + PS3_RECOVERY_WAIT_PROBE_FINISH_LOOP_COUNT =9000, + PS3_RECOVERY_WAIT_LOOP_TIME_INTERVAL_20MS =20, + PS3_PS3_LOOP_TIME_INTERVAL_1000MS = 1000, + PS3_TRANS_DEAD_IOC_FAILED_MAX_COUNT = 10, +}; +enum ps3_reset_time_type { + PS3_START_WRITE_KEY_REG = 0, + PS3_END_WRITE_KEY_REG = 1, + PS3_START_WAIT_KEY_READY_REG = 2, + PS3_END_WAIT_KEY_READY_REG = 3, + PS3_START_WRITE_HARDRESET_REG = 4, + PS3_END_WRITE_HARDRESET_REG = 5, + PS3_RESET_MAX_COUNT=6, +}; + +#define PS3_HARD_RESET_FORCE_STOP_MAX_TIME_FIXED (PS3_RECOVERY_WAIT_PROBE_FINISH_LOOP_COUNT * \ + PS3_RECOVERY_WAIT_LOOP_TIME_INTERVAL_20MS / HZ + \ + PS3_FW_STATE_TO_FAULT_TMO_LOOP_COUNT * PS3_LOOP_TIME_INTERVAL_20MS / HZ + \ + PS3_LOOP_TIME_INTERVAL_100MS * PS3_LOOP_TIME_INTERVAL_100MS / HZ + \ + PS3_WRITE_HARD_RESET_WAIT_TIME_500MS / HZ + \ + PS3_SLEEP_TOLERATE_TIMEOUT) + +#ifdef PS3_HARDWARE_HAPS_V200 +#define PS3_HARD_RESET_FORCE_STOP_MAX_TIME(ins) (PS3_HARD_RESET_FORCE_STOP_MAX_TIME_FIXED + \ + (ins)->wait_ready_timeout * PS3_LOOP_TIME_INTERVAL_3000MS / HZ) + +#else +#define PS3_HARD_RESET_FORCE_STOP_MAX_TIME(ins) (PS3_HARD_RESET_FORCE_STOP_MAX_TIME_FIXED + \ + (ins)->wait_ready_timeout * PS3_LOOP_TIME_INTERVAL_20MS / HZ) +#endif + +S32 ps3_ioc_state_transfer_to_ready(struct ps3_instance *instance); + +S32 ps3_ioc_state_transfer_wait_to_running(struct ps3_instance *instance); + +S32 ps3_ioc_state_hard_reset(struct ps3_instance *instance); + +S32 ps3_ioc_state_shallow_soft_reset(struct ps3_instance *instance); + +S32 ps3_ioc_state_deep_soft_reset(struct ps3_instance *instance); + +S32 ps3_ioc_state_force_to_fault(struct ps3_instance *instance); + +S32 ps3_ioc_state_force_to_halt(struct ps3_instance *instance); + +S32 ps3_ioc_notify_unload(struct ps3_instance *instance); + +#ifdef PS3_HARDWARE_ASIC +U32 ps3_ioc_heartbeat_detect(struct ps3_instance *instance); +#endif + +S32 ps3_ioc_state_ready_wait(struct ps3_instance *instance); + +S32 ps3_ioc_state_fault_wait(struct ps3_instance *instance); + +const char *ps3_ioc_state_print(U32 state); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_ioctl.c b/drivers/scsi/ps3stor/ps3_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..f77254b0d96508fef106baccc53ab2c6ce713f15 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioctl.c @@ -0,0 +1,785 @@ + +#include "ps3_ioctl.h" + +#ifdef _WINDOWS +#include + +#define PS3_FUNC_FROM_CTL_CODE(ctrlCode) (((ULong)(ctrlCode & 0x3FFC)) >> 2) +#define PS3_ACC_FROM_CTL_CODE(ctrlCode) (((ULong)(ctrlCode & 0xC000)) >> 14) +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#endif + +#include "ps3_cmd_statistics.h" +#include "ps3_htp.h" +#include "ps3_htp_def.h" +#include "ps3_mgr_cmd.h" +#include "ps3_driver_log.h" +#include "ps3_mgr_channel.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_util.h" +#include "ps3_err_inject.h" +#include "ps3_event.h" + +S32 ps3_ioctl_init(struct ps3_instance*instance, S32 cmd_num) +{ +#ifdef _WINDOWS + (void)cmd_num; + ps3_atomic_set(&instance->ioctl_count, 0); +#else + sema_init(&instance->ioctl_sem, cmd_num); +#endif + ps3_atomic_set(&instance->cmd_statistics.cli_cnt, PS3_CMD_STAT_INIT_VALUE); + return PS3_SUCCESS; +} + +static S32 ps3_ioctl_capbility_pre_check(struct ps3_instance *instance, + struct PS3IoctlSyncCmd* ioc) +{ + S32 ret = PS3_SUCCESS; + + if (ioc->sgeCount > PS3_MAX_IOCTL_SGE_NUM || ioc->sgeCount == 0) { + LOG_WARN("hno:%u ioctl req, SGE count [%d] > max limit [%d], or SGE count = 0\n", + PS3_HOST(instance), ioc->sgeCount, PS3_MAX_IOCTL_SGE_NUM); + ret = -PS3_EINVAL; + goto l_out; + } + + (void)instance; +l_out: + return ret; +} + +void ps3_ioctl_buff_bit_pos_update(struct ps3_cmd *cmd) +{ + U8 i = 0; + struct PS3Sge *pSge = (struct PS3Sge*)cmd->req_frame->mgrReq.sgl; + struct ps3_instance *instance = cmd->instance; + U8 bit_pos = 0; + + if (cmd->transient == NULL) { + goto l_out; + } + + if (cmd->transient->sge_num == 0) { + goto l_out; + } + + for (i = 0; i < cmd->transient->sge_num; i++) { + if (cmd->transient->transient_buff[i] != NULL) { + if (pSge->ext == 1) { + pSge = (struct PS3Sge*)cmd->ext_buf; + } + bit_pos = ps3_dma_addr_bit_pos_check((dma_addr_t)le64_to_cpu(pSge->addr)); + if (bit_pos != instance->dma_addr_bit_pos) { + pSge->addr = cpu_to_le64(PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, le64_to_cpu(pSge->addr))); + pSge->addr = cpu_to_le64(PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, + le64_to_cpu(pSge->addr))); + } + } + pSge++; + } +l_out: + return; +} + +void ps3_ioctl_buff_release(struct ps3_cmd *cmd) +{ + U8 i = 0; + struct PS3Sge *pSge = (struct PS3Sge*)cmd->req_frame->mgrReq.sgl; + struct ps3_instance *instance = cmd->instance; + + if (cmd->transient == NULL) { + return; + } + + if (cmd->transient->sge_num == 0) { + return; + } + + for (i = 0; i < cmd->transient->sge_num; i++) { + if (cmd->transient->transient_buff[i] != NULL) { + if (pSge->ext == 1) { + pSge = (struct PS3Sge*)cmd->ext_buf; + } + ps3_dma_free_coherent(instance, + cpu_to_le32(pSge->length), + cmd->transient->transient_buff[i], + (dma_addr_t)cpu_to_le64(pSge->addr)); + + cmd->transient->transient_buff[i] = NULL; + memset(pSge, 0, sizeof(struct PS3Sge)); + } + pSge++; + } + memset((void*)cmd->req_frame, 0, sizeof(union PS3ReqFrame)); + cmd->transient->sge_num = 0; +} + +static S32 ps3_ioctl_sge_fill(struct ps3_instance *instance, U8 *base_addr, + struct PS3Sge *psrc_sge, struct PS3Sge *pdst_sge, void **transient_buff) +{ + S32 ret = PS3_SUCCESS; + dma_addr_t transient_addr = 0; + + *transient_buff = ps3_dma_alloc_coherent(instance, + psrc_sge->length, &transient_addr); + + if (*transient_buff == NULL) { + LOG_ERROR("hno:%u Failed to alloc kernel SGL buffer for IOCTL\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_out; + } + + pdst_sge->length = cpu_to_le32(psrc_sge->length); + pdst_sge->ext = 0; + pdst_sge->lastSge = 0; + pdst_sge->addr = (U64)cpu_to_le64(transient_addr); +#ifdef _WINDOWS + LOG_DEBUG("===base_addr[%p],psrc_sge->addr[%d], psrc_sge->length[%d] \n", + base_addr, psrc_sge->addr, psrc_sge->length); + memcpy(*transient_buff, (void*)(base_addr + psrc_sge->addr), psrc_sge->length); +#else + (void)base_addr; + if (copy_from_user(*transient_buff, (void __user*)psrc_sge->addr, psrc_sge->length)) { + LOG_ERROR("hno:%u, copy from user err\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } +#endif +l_out: + return ret; +} + +static S32 ps3_ioctl_sgl_fill(struct ps3_instance *instance, + struct ps3_cmd *cmd, struct PS3IoctlSyncCmd* ioc) +{ + U8 i = 0; + S32 ret = PS3_SUCCESS; + struct PS3Sge *pdst_sge = NULL; + struct PS3Sge *psrc_sge = (struct PS3Sge*)((U32*)ioc + + ioc->sglOffset); + U8 pre_sge_count = (U8)((ioc->sgeCount > PS3_FRAME_REQ_SGE_NUM_MGR) ? + (PS3_FRAME_REQ_SGE_NUM_MGR - 1) : ioc->sgeCount); + + if (cmd->transient->sge_num != 0) { + LOG_ERROR("trace_id[0x%llx], hno:%u got cmd NOK: %d\n", + cmd->trace_id, PS3_HOST(instance), cmd->index); + PS3_BUG(); + ret = -PS3_FAILED; + goto l_out; + } + cmd->transient->sge_num = ioc->sgeCount; + + cmd->req_frame->mgrReq.sgeOffset = + offsetof(PS3MgrReqFrame_s, sgl) >> PS3_MGR_CMD_SGL_OFFSET_DWORD_SHIFT; + cmd->req_frame->mgrReq.sgeCount = ioc->sgeCount; + + pdst_sge = cmd->req_frame->mgrReq.sgl; + + for (i = 0; i < pre_sge_count; i++) { + LOG_DEBUG("trace_id[0x%llx], hno:%u sge[%u] size : %d\n", + cmd->trace_id, PS3_HOST(instance), i, + psrc_sge->length); + + pdst_sge->length = 0; + + if (psrc_sge->length > 0) { + ret = ps3_ioctl_sge_fill(instance, (U8*)ioc, psrc_sge, pdst_sge, + &cmd->transient->transient_buff[i]); + if (ret != PS3_SUCCESS) { + LOG_ERROR("trace_id[0x%llx], hno:%u sge[%u] " + "fill data error(%d)\n", cmd->trace_id, + PS3_HOST(instance), i, ret); + goto l_out; + } + } + + pdst_sge++; + psrc_sge++; + } + + if (ioc->sgeCount > PS3_FRAME_REQ_SGE_NUM_MGR) { + LOG_FILE_INFO("hno:%u ioctl req num %d is bigger than req frame num %d\n", + PS3_HOST(instance), ioc->sgeCount, PS3_FRAME_REQ_SGE_NUM_MGR); + pdst_sge->addr = (U64)cpu_to_le64(cmd->ext_buf_phys); + pdst_sge->length = 0; + pdst_sge->ext = 1; + + pdst_sge = (struct PS3Sge*)cmd->ext_buf; + cmd->req_frame->mgrReq.sgeCount++; + + for (i = PS3_FRAME_REQ_SGE_NUM_MGR - 1; i < ioc->sgeCount; i++) { + LOG_DEBUG("trace_id[0x%llx], hno:%u sge[%u] size : %d\n", + cmd->trace_id, PS3_HOST(instance), i, + psrc_sge->length); + + pdst_sge->length = 0; + + if (psrc_sge->length > 0) { + ret = ps3_ioctl_sge_fill(instance, (U8*)ioc, psrc_sge, pdst_sge, + &cmd->transient->transient_buff[i]); + if (ret != PS3_SUCCESS) { + LOG_ERROR("trace_id[0x%llx], hno:%u sge[%u] fill data error(%d)\n", + cmd->trace_id, PS3_HOST(instance), i, + ret); + goto l_out; + } + } + + pdst_sge++; + psrc_sge++; + } + } + + pdst_sge--; + pdst_sge->lastSge = 1; +l_out: + return ret; +} + +static S32 ps3_ioctl_complete(struct ps3_instance *instance, + struct ps3_cmd *cmd, + struct PS3IoctlSyncCmd* ioc) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + + struct PS3Sge *psrc_sge = (struct PS3Sge*)((U32*)ioc + + ioc->sglOffset); + + for (i = 0; i < ioc->sgeCount; i++) { + LOG_DEBUG("trace_id[0x%llx], hno:%u CFID [%d], transient_buff[%u] address: %p, data size: %d\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, + i, cmd->transient->transient_buff[i], psrc_sge->length); + + if (psrc_sge->length > 0) { +#ifdef _WINDOWS + memcpy((void*)((U8*)ioc + psrc_sge->addr), cmd->transient->transient_buff[i], psrc_sge->length); +#else + if (copy_to_user((void __user*)psrc_sge->addr, + cmd->transient->transient_buff[i], psrc_sge->length)) { + LOG_ERROR("hno:%u copy to user err\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } +#endif + } + psrc_sge++; + } +#ifndef _WINDOWS + l_out: +#endif + LOG_FILE_INFO("trace_id[0x%llx], ioctl complete hno:%u CFID [%u], ret[%d]\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, ret); + return ret; +} + +static S32 ps3_ioctl_mgr_handle(struct ps3_instance *instance, + struct PS3IoctlSyncCmd* ioc) + +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + S32 send_result = PS3_SUCCESS; + U8 retry_count = 0; + + while (retry_count < PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if ((ret = ps3_mgr_cmd_send_pre_check(instance, PS3_FALSE)) != PS3_SUCCESS) { + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (ret == -PS3_RECOVERED) { + if (++retry_count < PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + INJECT_START(PS3_ERR_IJ_V2_FORCE_INSTANCE_STATE_NORMAL, instance); + ret = ps3_instance_wait_for_normal(instance); + } + } + if (ret != PS3_SUCCESS) { + LOG_WARN_LIM("tid[0x%llx], hno:%u ioctl cmd pre check NOK ret:%d!\n", + ioc->traceId, PS3_HOST(instance), ret); + goto l_no_free_cmd; + } + continue; + } + break; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_FORCE_IOCTL_ALLOC_CMD_FAILED, &cmd) + if (cmd == NULL) { + LOG_WARN("hno:%u ioctl req, not get a cmd packet\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + goto l_no_free_cmd; + } + LOG_DEBUG("trace_id[0x%llx], hno:%u CFID [%u], get mgr cmd succeed\n", + cmd->trace_id, PS3_HOST(instance), cmd->index); + + cmd->time_out = 0; + cmd->is_interrupt = PS3_DRV_TRUE; + + if (ioc->traceId != 0) { + ps3_cmd_trace_id_replace(cmd, ioc->traceId); + LOG_DEBUG("trace_id[0x%llx], hno:%u CFID [%u], change trace id from cli\n", + cmd->trace_id, PS3_HOST(instance), cmd->index); + } + + memset(&cmd->req_frame->mgrReq, 0, sizeof(struct PS3MgrReqFrame)); + + memset(cmd->transient->transient_buff, 0, sizeof(void*) * PS3_MAX_IOCTL_SGE_NUM); + ret = ps3_ioctl_sgl_fill(instance, cmd, ioc); + if (ret != PS3_SUCCESS) { + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_IOCTL_WAIT_RECOVERY, instance); + ps3_ioctl_req_frame_build(cmd); + ps3_mgr_cmd_word_build(cmd); + + INJECT_START(PS3_ERR_IJ_IOCTL_WAIT_IRQ_DISABLE, cmd); + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_NO_RESP, &send_result); + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret == -PS3_CMD_NO_RESP) { + LOG_ERROR("trace_id[0x%llx], hno:%u ioctl request no response!\n", + cmd->trace_id, PS3_HOST(instance)); + goto l_no_free_cmd; + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("trace_id[0x%llx], hno:%u ioctl send request NOK!%d\n", + cmd->trace_id, PS3_HOST(instance), ret); + goto l_out; + } + + ret = ps3_ioctl_complete(instance, cmd, ioc); + + LOG_INFO("trace_id[0x%llx], hno:%u CFID [%u], ioctl cmd_type[%d], sub_type[%d] end\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, + ioc->msg.header.cmdType, ioc->msg.header.cmdSubType); + +l_out: + ps3_ioctl_buff_release(cmd); + ps3_mgr_cmd_free(instance, cmd); +l_no_free_cmd: + return ret; +} + +#ifdef _WINDOWS + +static U8 ps3_ioctl_windows_pre_check(struct ps3_instance *instance, + PPS3_IO_CONTROL ioctl) +{ + U8 ret = PS3_TRUE; + U8 i = 0; + U8 *base_addr = (U8*)&ioctl->ps3Ioctl; + U8 *last_addr = base_addr + ioctl->SrbHeader.Length; + + if (ioctl->ps3Ioctl.data == NULL || ioctl->SrbHeader.Length == 0) { + LOG_WARN("hno:%u ioctl req, data is [%p], or data len is [%llu]\n", + PS3_HOST(instance), ioctl->ps3Ioctl.data, ioctl->SrbHeader.Length); + ret = PS3_FALSE; + goto l_out; + } + + if (ps3_ioctl_capbility_pre_check(instance, &ioctl->ps3Ioctl) != PS3_SUCCESS) { + ret = PS3_FALSE; + goto l_out; + } + + LOG_INFO("hno:%u base_addr[%p], Length[%d], last_addr[%p]\n", + PS3_HOST(instance), base_addr, ioctl->SrbHeader.Length, last_addr); + + for (i = 0; i < ioctl->ps3Ioctl.sgeCount; i++) { + if (base_addr + ioctl->ps3Ioctl.Sgl[i].addr + + ioctl->ps3Ioctl.Sgl[i].length > last_addr) { + + LOG_ERROR("hno:%u ioctl req, sge[%d] len[%d] > total len[%d], sge offset[%p], base addr[%p]\n", + PS3_HOST(instance), i, ioctl->ps3Ioctl.Sgl[i].length, ioctl->SrbHeader.Length, + ioctl->ps3Ioctl.Sgl[i].addr, &ioctl->ps3Ioctl); + ret = PS3_FALSE; + goto l_out; + } + } + + (void)instance; + +l_out: + return ret; +} + +S32 ps3_ioctl_callback_proc(struct ps3_cmd *cmd, U8 reply_flags) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance = cmd->instance; + S32 send_result = -PS3_RESP_ERR; + SCSI_REQUEST_BLOCK *srb = cmd->srb; + PPS3_IO_CONTROL ps3_ioctl = NULL; + + LOG_DEBUG("hno:%u trace_id[0x%llx], got a ioctl response, reply_flags[0x%x]\n", + PS3_HOST(instance), cmd->trace_id, reply_flags); + + PS3_MGR_CMD_BACK_INC(instance, cmd, reply_flags); + + if (unlikely(reply_flags != PS3_REPLY_WORD_FLAG_SUCCESS) && + cmd->retry_cnt < PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + LOG_ERROR("trace_id[0x%llx], hno:%u ioctl cmd return failed\n", + cmd->trace_id, PS3_HOST(instance)); + + ret = ps3_err_mgr_cmd_proc(instance, send_result, cmd); + if (ret == -PS3_CMD_NO_RESP) { + ret = ps3_mgr_cmd_no_resp_proc(instance, cmd); + } + + if (ret != -PS3_RETRY) { + LOG_WARN("hno:%u CFID:%d retry, retries:%d, ret:%d\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt, ret); + goto l_out; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + cmd->retry_cnt++; + if (cmd->retry_cnt >= PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + LOG_ERROR("hno:%u retry time full.\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + LOG_INFO("hno:%u mgr CFID[%d] retry:%u\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt); + + ret = ps3_srb_send(instance, srb); + if (ret != PS3_SUCCESS) { + LOG_ERROR("trace_id[0x%llx], hno:%u ioctl send request failed!%d\n", + cmd->trace_id, PS3_HOST(instance), ret); + goto l_out; + } + + goto l_retry; + } + +l_out: + SrbSetSrbStatus(srb, SRB_STATUS_ERROR); + if((cmd->resp_frame->normalRespFrame.respStatus == PS3_DRV_MGR_RESTART_COMMAND_RSP) && + (reply_flags == PS3_REPLY_WORD_FLAG_FAIL)){ + reply_flags = PS3_REPLY_WORD_FLAG_SUCCESS; + } + if (likely(reply_flags == PS3_REPLY_WORD_FLAG_SUCCESS)) { + ps3_ioctl = (PPS3_IO_CONTROL)SrbGetDataBuffer(srb); + ps3_ioctl_complete(instance, cmd, &ps3_ioctl->ps3Ioctl); + SrbSetSrbStatus(srb, SRB_STATUS_SUCCESS); + } + + ps3_ioctl_buff_release(cmd); + ps3_mgr_cmd_free(instance, cmd); + StorPortNotification(RequestComplete, instance, srb); + ps3_atomic_dec(&instance->ioctl_count); + +l_retry: + LOG_DEBUG("hno:%u trace_id[0x%llx], end proc a ioctl response, ret[%d]\n", + PS3_HOST(instance), cmd->trace_id, ret); + + return ret; +} + +U8 ps3_ioctl_build_io(_In_ struct ps3_instance *instance, _In_ PSCSI_REQUEST_BLOCK Srb) +{ + U8 ret = PS3_FALSE; + PPS3_IO_CONTROL ps3_ioctl = (PPS3_IO_CONTROL)SrbGetDataBuffer(Srb); + + LOG_INFO("ioctl parase: Type[0x%x], Method[0x%x], Function[0x%x], Access[0x%x] \n", + DEVICE_TYPE_FROM_CTL_CODE(ps3_ioctl->SrbHeader.ControlCode), METHOD_FROM_CTL_CODE(ps3_ioctl->SrbHeader.ControlCode), + PS3_FUNC_FROM_CTL_CODE(ps3_ioctl->SrbHeader.ControlCode), PS3_ACC_FROM_CTL_CODE(ps3_ioctl->SrbHeader.ControlCode)); + + if (memcmp(ps3_ioctl->SrbHeader.Signature, PS3_IOCTL_SIG, sizeof(PS3_IOCTL_SIG)) != 0) { + LOG_ERROR("hno:%u ioctl signature error\n", + PS3_HOST(instance)); + SrbSetSrbStatus(Srb, SRB_STATUS_INVALID_REQUEST); + goto l_out; + } + + if (!instance->state_machine.is_load) { + LOG_WARN("trace_id[0x%llx], hno:%u instance state not is_load\n", + ps3_ioctl->ps3Ioctl.traceId, PS3_HOST(instance)); + SrbSetSrbStatus(Srb, SRB_STATUS_NO_HBA); + goto l_out; + } + + if (!ps3_atomic_add_unless(&instance->ioctl_count, 1, PS3_MAX_IOCTL_CMDS)) { + LOG_WARN("hno:%u ioctl concurrency full\n", + PS3_HOST(instance)); + + SrbSetSrbStatus(Srb, SRB_STATUS_BUSY); + goto l_out; + } + + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + SrbSetSrbStatus(Srb, SRB_STATUS_NO_DEVICE); + goto l_out; + } + + ret = ps3_ioctl_windows_pre_check(instance, ps3_ioctl); + if (!ret) { + LOG_WARN("hno:%u ioctl capblity not support\n", + PS3_HOST(instance)); + SrbSetSrbStatus(Srb, SRB_STATUS_INVALID_REQUEST); + ps3_atomic_dec(&instance->ioctl_count); + goto l_out; + } + + if (ps3_ioctl_mgr_handle(instance, &ps3_ioctl->ps3Ioctl, Srb) != PS3_SUCCESS) { + LOG_ERROR("hno:%u ioctl handle err\n", + PS3_HOST(instance)); + SrbSetSrbStatus(Srb, SRB_STATUS_ERROR); + ps3_atomic_dec(&instance->ioctl_count); + goto l_out; + } + + ret = PS3_TRUE; + SrbSetSrbStatus(Srb, SRB_STATUS_SUCCESS); +l_out: + if (!ret) { + StorPortNotification(RequestComplete, instance, Srb); + } + return ret; +} + +U8 ps3_ioctl_start_io(_In_ struct ps3_instance *instance, _In_ PSCSI_REQUEST_BLOCK Srb) +{ + struct ps3_cmd *cmd = ps3_cmd_from_srb_extension_get(Srb); + U8 ret = PS3_FALSE; + S32 ret_tmp = PS3_SUCCESS; + SrbSetSrbStatus(Srb, SRB_STATUS_ERROR); + + ret_tmp = ps3_srb_send(instance, Srb); + if (ret_tmp != PS3_SUCCESS) { + LOG_ERROR("trace_id[0x%llx], hno:%u ioctl send request failed!%d\n", + cmd->trace_id, PS3_HOST(instance), ret_tmp); + goto l_out; + } + + ret = PS3_TRUE; + SrbSetSrbStatus(Srb, SRB_STATUS_SUCCESS); +l_out: + if (!ret) { + ps3_ioctl_buff_release(cmd); + ps3_mgr_cmd_free(instance, cmd); + StorPortNotification(RequestComplete, instance, Srb); + ps3_atomic_dec(&instance->ioctl_count); + } + return ret; +} + +#else + +static S32 ps3_ioctl_mgr_sync(ULong arg) +{ + S32 ret = PS3_SUCCESS; + struct PS3IoctlSyncCmd* ioc = NULL; + struct ps3_instance *instance = NULL; + struct PS3IoctlSyncCmd __user* user_ioc = + (struct PS3IoctlSyncCmd __user*)arg; + + ioc = (struct PS3IoctlSyncCmd*)memdup_user( + (const void __user*)user_ioc, sizeof(*ioc)); + INJECT_START(PS3_ERR_IJ_FORCE_MEMDUP_USER_RETURN_FAILED, &ioc) + if (IS_ERR(ioc)) { + LOG_ERROR("ioctl memdup_user err\n"); + return PTR_ERR(ioc); + } + + LOG_INFO("ioctl ps3_ioctl_sync_cmd: trace_id[0x%llx], hno:%u " + "cmd_type[%d], sgl_offset[%d], sge_count[%d], result[%d]\n", + ioc->traceId, ioc->hostId, ioc->msg.header.cmdType, + ioc->sglOffset, ioc->sgeCount, ioc->resultCode); + + ps3_mutex_lock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + instance = ps3_instance_lookup(ioc->hostId); + if (instance == NULL) { + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + LOG_WARN("can found instance, host no is %d\n", ioc->hostId); + ret = -ENODEV; + goto l_out_free_ioc; + } + + if (!instance->state_machine.is_load) { + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + LOG_WARN("trace_id[0x%llx], hno:%u instance state [%d]\n", + ioc->traceId, PS3_HOST(instance), + instance->state_machine.is_load); + ret = -ENODEV; + goto l_out_free_ioc; + } + + INJECT_START(PS3_ERR_IJ_SCSI_SCAN_HOST_NOT_FINISH, instance) + if (!instance->is_scan_host_finish) { + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + LOG_WARN("trace_id[0x%llx], hno:%u instance scan host not finish\n", + ioc->traceId, PS3_HOST(instance)); + ret = -EAGAIN; + goto l_out_free_ioc; + } + + ps3_atomic_inc(&instance->cmd_statistics.cli_cnt); + ps3_mutex_unlock(&ps3_mgmt_info_get()->ps3_mgmt_lock); + + LOG_FILE_INFO("hno:%u ioctl ready get sem\n", + PS3_HOST(instance)); + if (down_interruptible(&instance->ioctl_sem)) { + LOG_WARN("hno:%u ioctl concurrency full\n", + PS3_HOST(instance)); + ret = -ERESTARTSYS; + goto l_out_dec_cnt; + } + + ret = ps3_instance_wait_for_normal(instance); + INJECT_START(PS3_ERR_IJ_FORCE_IOCTL_WAIT_NORMAL_FAILED, &ret); + if (ret != PS3_SUCCESS) { + LOG_WARN("trace_id[0x%llx], hno:%u instance state not allowed ioctl req\n", + ioc->traceId, PS3_HOST(instance)); + ret = -ENODEV; + goto l_out_up; + } + + LOG_INFO("hno:%u ioctl got sem\n", + PS3_HOST(instance)); + + if (ioc->msg.header.cmdType == PS3_IOCTL_CMD_WEB_SUBSCRIBE) { + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) != 1) { + if (ps3_atomic_add_unless(&instance->webSubscribe_context.subscribe_count, 1, 1) != 0) { + ret = ps3_web_subscribe(instance); + if (ret != PS3_SUCCESS) { + ps3_atomic_set(&instance->webSubscribe_context.subscribe_count, 0); + ret = -EBUSY; + goto l_out_up; + } + ps3_atomic_set(&instance->webSubscribe_context.is_subscribe, 1); + goto l_out_dec_cnt; + } else { + ret = -EAGAIN; + goto l_out_up; + } + } else { + ret = PS3_SUCCESS; + goto l_out_up; + } + } else { + ret = ps3_ioctl_capbility_pre_check(instance, ioc); + if (ret != PS3_SUCCESS) { + LOG_WARN("hno:%u ioctl capblity not support\n", + PS3_HOST(instance)); + ret = -EINVAL; + goto l_out_up; + } + ret = ps3_ioctl_mgr_handle(instance, ioc); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u ioctl handle NOK\n", + PS3_HOST(instance)); + ret = -EBUSY; + } + } + +l_out_up: + up(&instance->ioctl_sem); +l_out_dec_cnt: + ps3_atomic_dec(&instance->cmd_statistics.cli_cnt); +l_out_free_ioc: + kfree(ioc); + return ret; +} + +#if 0 +static S32 ps3_ioctl_mgr_async(struct file *file, ULong arg) +{ + (void)file; + (void)arg; + return PS3_SUCCESS; +} +#endif + +long ps3_ioctl_fops(struct file *file, U32 cmd, ULong arg) +{ + S32 ret = -ENOTTY; + if (file == NULL || arg == 0) { + goto l_out; + } + + switch (cmd) { + case PS3_CMD_IOCTL_SYNC_CMD: + ret = ps3_ioctl_mgr_sync(arg); + break; +#if 0 + case PS3_CMD_IOCTL_ASYNC_CMD: + return ps3_ioctl_mgr_async(file, arg); + break; +#endif + default: + break; + } +l_out: + return ret; +} + +void ps3_clean_mgr_cmd(struct ps3_instance *instance) +{ + struct ps3_cmd_context *context = &instance->cmd_context; + U32 mgr_cmd_idx = 0; + U32 mgr_start_idx = context->max_scsi_cmd_count; + U32 mgr_end_idx = context->max_scsi_cmd_count + + instance->max_mgr_cmd_count; + struct ps3_cmd *cmd = NULL; + + for (mgr_cmd_idx = mgr_start_idx; mgr_cmd_idx < mgr_end_idx; + mgr_cmd_idx++) { + cmd = context->cmd_buf[mgr_cmd_idx]; + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + LOG_WARN("hno:%u mgr cmd[%d] complete force!\n", + PS3_HOST(instance), cmd->index); + + cmd->resp_frame->normalRespFrame.respStatus = PS3_MGR_REC_FORCE; + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + complete(&cmd->sync_done); + } + } +} + +void ps3_ioctl_clean(struct ps3_instance *instance) +{ + if (ps3_atomic_read(&instance->state_machine.state) != + PS3_INSTANCE_STATE_QUIT){ + goto l_out; + } + + while (ps3_atomic_read(&instance->cmd_statistics.cli_cnt) != 0) { + LOG_INFO("hno:%u ioctls not finish\n", + PS3_HOST(instance)); + ps3_clean_mgr_cmd(instance); + ps3_msleep(1000); + } +l_out: + return; +} + +#endif diff --git a/drivers/scsi/ps3stor/ps3_ioctl.h b/drivers/scsi/ps3stor/ps3_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..01ad0c7e9744f6344d3213829e6c67962fb3a6f0 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_ioctl.h @@ -0,0 +1,61 @@ + +#ifndef _PS3_IOCTL_H_ +#define _PS3_IOCTL_H_ + +#ifdef _WINDOWS +#include "ps3_def.h" +#endif +#include "ps3_instance_manager.h" +#include "ps3_cmd_channel.h" +#include "ps3_htp_ioctl.h" + +#define PS3_MAX_IOCTL_CMDS 3 + +#ifdef _WINDOWS +U8 ps3_ioctl_start_io(_In_ struct ps3_instance *instance, _In_ PSCSI_REQUEST_BLOCK Srb); +U8 ps3_ioctl_build_io(_In_ struct ps3_instance *instance, _In_ PSCSI_REQUEST_BLOCK Srb); +#else +long ps3_ioctl_fops(struct file *file, U32 cmd, ULong arg); +#endif + +S32 ps3_ioctl_init(struct ps3_instance *instance, S32 cmd_num); + +void ps3_ioctl_buff_release(struct ps3_cmd *cmd); + +inline static void ps3_ioctl_req_frame_build(struct ps3_cmd *cmd) +{ + PS3MgrReqFrame_s* mgr_req = &cmd->req_frame->mgrReq; + + mgr_req->reqHead.traceID = cmd->trace_id; + mgr_req->reqHead.cmdType = PS3_CMD_IOCTL; + mgr_req->reqHead.cmdSubType = 0; + mgr_req->reqHead.cmdFrameID = cmd->index; + mgr_req->reqHead.timeout = 0; + mgr_req->timeout = 0; + mgr_req->syncFlag = 1; +} + +inline static void ps3_ioctl_cmd_word_build(struct ps3_instance *instance, + struct ps3_cmd *cmd, U16 cmd_frame_id) +{ + struct PS3CmdWord* cmd_word = &cmd->cmd_word; + memset(cmd_word, 0, sizeof(*cmd_word)); + + (void)instance; + + cmd_word->type = PS3_CMDWORD_TYPE_MGR; + cmd_word->direct = PS3_CMDWORD_DIRECT_NORMAL; + cmd_word->cmdFrameID = cmd_frame_id; +#ifndef _WINDOWS + cmd_word->isrSN = ps3_msix_index_get(cmd, 1); +#endif +} + +S32 ps3_ioctl_callback_proc(struct ps3_cmd *cmd, U8 reply_flags); + +void ps3_ioctl_clean(struct ps3_instance *instance); + +void ps3_ioctl_buff_bit_pos_update(struct ps3_cmd *cmd); + +#endif + diff --git a/drivers/scsi/ps3stor/ps3_irq.c b/drivers/scsi/ps3stor/ps3_irq.c new file mode 100644 index 0000000000000000000000000000000000000000..af09a6b6fe9b5572b2267416e1c75e3501b641af --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_irq.c @@ -0,0 +1,1706 @@ +#include "ps3_irq.h" + +#ifndef _WINDOWS +#include +#include +#include +#include +#endif + +#include "ps3_instance_manager.h" +#include "ps3_inner_data.h" +#include "ps3_cmd_complete.h" +#include "ps3_ioc_manager.h" +#include "ps3_util.h" +#include "ps3_dump.h" +#include "ps3_scsih.h" + +#ifndef _WINDOWS + +const U32 PS3_INTERRUPT_STATUS_NO_IRQ = 0x00; +const U32 PS3_INTERRUPT_CMD_DISABLE_ALL_MASK = 0x02; +const U32 PS3_INTERRUPT_CMD_ENABLE_MSIX = 0x01; +const U32 PS3_INTERRUPT_MASK_DISABLE = 0x00000002; +const U32 PS3_INTERRUPT_STATUS_EXIST_IRQ = 0x00000001; +const U32 PS3_INTERRUPT_CLEAR_IRQ= 0x00000001; + +const U32 PS3_SSD_IOPS_MSIX_VECTORS = 8; +const U32 PS3_HDD_IOPS_MSIX_VECTORS = 8; +const U32 PS3_IRQ_POLL_SCHED_THRESHOLD = 1024; +const U32 PS3_HIGH_IOPS_VECTOR_BATCH_COUNT_SHIFT = 5; +const U32 PS3_BALANCE_MODE_MIN_CPU_NUM = 16; +const S32 PS3_SSD_MAX_BUSY_THRESHOLD = 40; +const U32 PS3_IOPS_MSIX_VECTORS = 12; +const S32 PS3_HYGON_BUSY_ADJUST_THRESHOLD = 32; +const U32 PS3_MSIX_COMBINED_MODE_MSIX_VECTORS = 16; + +#define PS3_IRQCTX_HOST(irq_context) \ + ps3_container_of((irq_context), struct ps3_instance, irq_context)->host->host_no + +#define PS3_MGR_CMD_MSIX_INDEX(irq_context) ((irq_context)->high_iops_msix_vectors) +#define IS_HIGN_OPS_IRQ(irq_context, irq) \ + (((irq_context)->high_iops_msix_vectors > (irq)->isrSN)) + +#define PS3_MULTI_DATA_DISK_BUSY_THRESHOLD(var, base) ((var) > (base)) +static void msix_irq_mode_check(struct ps3_irq_context *irq_context, + U32 max_vectors) +{ + U32 online_cpu_num = num_online_cpus(); + U16 speed = 0; + U16 lnksta = 0; + U32 iops_msix_cnt = 0; + + if (!ps3_ioc_multi_func_support(irq_context->instance) || + ps3_get_pci_function(irq_context->instance->pdev) == PS3_FUNC_ID_1) { + iops_msix_cnt = PS3_IOPS_MSIX_VECTORS; + } else { + iops_msix_cnt = 0; + } + + pcie_capability_read_word(irq_context->instance->pdev, PCI_EXP_LNKSTA, &lnksta); + speed = lnksta & PCI_EXP_LNKSTA_CLS; + if ((iops_msix_cnt > 0) && (online_cpu_num >= PS3_BALANCE_MODE_MIN_CPU_NUM) && + (iops_msix_cnt < max_vectors) && (speed >= 0x4)) { + irq_context->high_iops_msix_vectors = iops_msix_cnt; + irq_context->valid_msix_vector_count = + min(irq_context->high_iops_msix_vectors + online_cpu_num, max_vectors); + irq_context->is_support_balance = PS3_TRUE; + irq_context->is_balance_current_perf_mode = PS3_TRUE; + } else { + irq_context->high_iops_msix_vectors = 0; + irq_context->is_support_balance = PS3_FALSE; + irq_context->is_balance_current_perf_mode = PS3_FALSE; + irq_context->valid_msix_vector_count = + min(online_cpu_num, max_vectors); + } + + return; +} + +static inline Bool ps3_is_linx80_os(void) +{ + Bool ret = PS3_FALSE; +#if (!defined(PS3_OS_MANAGED_IRQ_SUPPORT)) + ret = PS3_TRUE; +#endif + + return ret; +} + +static inline Bool ps3_support_irq_affinity(void) +{ + Bool ret = PS3_FALSE; + +#if defined(DRIVER_SUPPORT_KERNEL_IRQ_AFFINITY) + ret = PS3_TRUE; +#endif + + if (!ret) { + if (strstr(ps3_host_release_get(), "an8")) { + ret = PS3_TRUE; + } + } + + return ret; +} + +static U32 __ps3_irq_vectors_alloc(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + int msix_vectors = 0; + U32 irq_flags = PCI_IRQ_MSIX | PCI_IRQ_MSI; + struct ps3_instance *instance = irq_context->instance; + U32 ps3_irq_mode = ps3_pci_irq_mode_query(); + struct irq_affinity *descp = NULL; +#if defined(PS3_OS_MANAGED_IRQ_SUPPORT) + struct irq_affinity desc = { .pre_vectors = irq_context->high_iops_msix_vectors }; + descp = &desc; +#endif + + switch (ps3_irq_mode) { + case PS3_PCI_IRQ_MODE_LEGACY: + irq_flags = PCI_IRQ_LEGACY; + break; + case PS3_PCI_IRQ_MODE_MSI: + irq_flags = PCI_IRQ_MSI; + break; + case PS3_PCI_IRQ_MODE_MSIX: + irq_flags = PCI_IRQ_MSIX; + break; + default: + break; + } + + if (ps3_support_irq_affinity() || ps3_is_linx80_os()) { + if (irq_context->instance->smp_affinity_enable) { + irq_flags |= PCI_IRQ_AFFINITY; + } else { + descp = NULL; + } + } else { + if (irq_context->is_support_balance == PS3_TRUE && + irq_context->is_balance_current_perf_mode == PS3_TRUE) { + descp = NULL; + } else { + if (irq_context->instance->smp_affinity_enable) { + irq_flags |= PCI_IRQ_AFFINITY; + } else { + descp = NULL; + } + } + } + + LOG_INFO("host_no:%u pci_irq_mode:%d specified, msix_vectors:%d max:%d\n", + PS3_IRQCTX_HOST(irq_context), ps3_irq_mode, + irq_context->high_iops_msix_vectors, + irq_context->valid_msix_vector_count); +#if defined(PS3_OS_MANAGED_IRQ_SUPPORT) + msix_vectors = pci_alloc_irq_vectors_affinity(pdev, + max(instance->min_intr_count, irq_context->high_iops_msix_vectors), + irq_context->valid_msix_vector_count, irq_flags, descp); +#else + msix_vectors = pci_alloc_irq_vectors(pdev, + max(instance->min_intr_count, irq_context->high_iops_msix_vectors), + irq_context->valid_msix_vector_count, irq_flags); +#endif + + if (msix_vectors <= 0) { + LOG_WARN("host_no:%u alloc msi irq fail! msix_vectors:%d\n", + PS3_IRQCTX_HOST(irq_context), msix_vectors); + msix_vectors = 0; + } else { + if (pdev->msix_enabled == 1) { + irq_context->pci_irq_type = PS3_PCI_IRQ_MSIX; + LOG_DEBUG("host_no:%u alloc msix count:%d\n", + PS3_IRQCTX_HOST(irq_context), msix_vectors); + } else if (pdev->msi_enabled == 1) { + irq_context->pci_irq_type = PS3_PCI_IRQ_MSI; + LOG_DEBUG("host_no:%u alloc msi count:%d\n", + PS3_IRQCTX_HOST(irq_context), msix_vectors); + } else { + LOG_ERROR("host_no:%u msi/msix all disable, msix_vectors:%d\n", + PS3_IRQCTX_HOST(irq_context), msix_vectors); + } + } + + return (U32)msix_vectors; +} + +static void ps3_iops_vectors_affinity_hint_set(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + U32 msix_vector = 0; + U32 os_vector = 0; + S32 node = -1; + const struct cpumask* mask = NULL; + S32 cpu_id = 0; + + if (!ps3_support_irq_affinity()) { + goto l_out; + } + + if (!irq_context->is_support_balance) { + goto l_out; + } + + if (!irq_context->instance->smp_affinity_enable) { + goto l_out; + } + + node = dev_to_node(&pdev->dev); + if (node >= 0) { + mask = cpumask_of_node(node); + } + + if (mask == NULL) { + mask = cpu_online_mask; + } + + for_each_cpu_and(cpu_id, mask, cpu_online_mask) { + LOG_DEBUG("host_no:%u affinity_hint cpu_id:%d, node:%d \n", + PS3_IRQCTX_HOST(irq_context), cpu_id, node); + } + + for (msix_vector = 0; + msix_vector < irq_context->high_iops_msix_vectors; + msix_vector++) { + os_vector = pci_irq_vector(pdev, msix_vector); + irq_set_affinity_hint(os_vector, mask); + } +l_out: + return; +} + +static U32 ps3_irq_vectors_alloc(struct pci_dev *pdev, + struct ps3_irq_context *irq_context, + U32 max_vectors) +{ + U32 msix_vectors = 0; + S32 nr_entries = 0; + msix_irq_mode_check(irq_context, max_vectors); + + msix_vectors = __ps3_irq_vectors_alloc(pdev, irq_context); + if ((msix_vectors != irq_context->valid_msix_vector_count) && + (irq_context->is_support_balance)) { + pci_free_irq_vectors(pdev); + irq_context->is_support_balance = PS3_FALSE; + irq_context->is_balance_current_perf_mode = PS3_FALSE; + irq_context->high_iops_msix_vectors = 0; + irq_context->valid_msix_vector_count = + min(num_online_cpus(), max_vectors); + msix_vectors = __ps3_irq_vectors_alloc(pdev, irq_context); + LOG_DEBUG("host_no:%u alloc resource for normal perf mode! \n", + PS3_IRQCTX_HOST(irq_context)); + } + INJECT_START(PS3_ERR_IJ_IRQ_VECTORS_ALLOC_FAILED, &msix_vectors) + if (msix_vectors > 0) { + irq_context->valid_msix_vector_count = msix_vectors; + ps3_iops_vectors_affinity_hint_set(pdev, irq_context); + } else { + irq_context->high_iops_msix_vectors = 0; + irq_context->is_support_balance = PS3_FALSE; + irq_context->is_balance_current_perf_mode = PS3_FALSE; + nr_entries = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY); + INJECT_START(PS3_ERR_IJ_ALLOC_LEGACY_VECTOR_FAILED, &nr_entries) + if (nr_entries != 1) { + LOG_ERROR("host_no:%u alloc irq fail! \n", + PS3_IRQCTX_HOST(irq_context)); + irq_context->valid_msix_vector_count = 0; + } else { + irq_context->valid_msix_vector_count = 1; + irq_context->pci_irq_type = PS3_PCI_IRQ_LEGACY; + LOG_DEBUG("host_no:%u alloc legacy irq\n", + PS3_IRQCTX_HOST(irq_context)); + } + } + return irq_context->valid_msix_vector_count; +} + +static inline Bool ps3_irq_set_affinity_hint(struct pci_dev *pdev, + U32 msix_vector, const struct cpumask *mask, Bool smp_affinity_enable) { + U32 os_vector = pci_irq_vector(pdev, msix_vector); + Bool ret = PS3_TRUE; + + if (smp_affinity_enable) { + if (irq_set_affinity_hint(os_vector, mask)) { + ret = PS3_FALSE; + } + } + return ret; +} + +static void __ps3_cpu_msix_table_init(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + const struct cpumask *mask = NULL; + S32 cpu_id = 0; + U32 normal_msix_index = irq_context->high_iops_msix_vectors; + Bool smp_affinify_enable = irq_context->instance->smp_affinity_enable; + + for (; normal_msix_index < irq_context->valid_msix_vector_count; + normal_msix_index++) { + mask = pci_irq_get_affinity(pdev, normal_msix_index); + if (mask == NULL) { + goto l_get_affinity_failed; + } + + for_each_cpu_and(cpu_id, mask, cpu_online_mask) { + if (cpu_id >= irq_context->cpu_msix_table_sz) { + break; + } + irq_context->cpu_msix_table[cpu_id] = normal_msix_index; + LOG_DEBUG("host_no:%u affinity cpu_id:%d, msix_index:%d \n", + PS3_IRQCTX_HOST(irq_context), cpu_id, normal_msix_index); + } + } + + return; + +l_get_affinity_failed: + cpu_id = cpumask_first(cpu_online_mask); + normal_msix_index = irq_context->high_iops_msix_vectors; + for (; normal_msix_index < irq_context->valid_msix_vector_count; + normal_msix_index++) { + mask = get_cpu_mask(cpu_id); + if (!ps3_irq_set_affinity_hint(pdev, normal_msix_index, + mask, smp_affinify_enable)) { + LOG_ERROR("host_no:%u set affinity failed, %d.\n", + PS3_IRQCTX_HOST(irq_context), normal_msix_index); + } else { + irq_context->cpu_msix_table[cpu_id] = normal_msix_index; + LOG_DEBUG("host_no:%u affinity cpu_id:%d, msix_index:%d \n", + PS3_IRQCTX_HOST(irq_context), cpu_id, normal_msix_index); + } + cpu_id = cpumask_next(cpu_id, cpu_online_mask); + } + return; +} + +static S32 ps3_cpu_msix_table_init(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + S32 last_cpu_id = 0; + S32 cpu_id = 0; + for_each_online_cpu(cpu_id) { + last_cpu_id = cpu_id; + } + irq_context->cpu_msix_table_sz = last_cpu_id + 1; + + irq_context->cpu_msix_table = + (U32*)kcalloc(irq_context->cpu_msix_table_sz, sizeof(S32), GFP_KERNEL); + INJECT_START(PS3_ERR_IJ_CPU_MSIX_TABLE_ALLOC_FAILED, &(irq_context->cpu_msix_table)) + if (irq_context->cpu_msix_table == NULL) { + LOG_ERROR("host_no:%u kcalloc fail! \n", + PS3_IRQCTX_HOST(irq_context)); + return -PS3_FAILED; + } + + __ps3_cpu_msix_table_init(pdev, irq_context) ; + + return PS3_SUCCESS; +} + +static S32 ps3_reply_fifo_desc_alloc(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + size_t reply_fifo_desc_buf_size = sizeof(struct PS3ReplyFifoDesc) * + irq_context->valid_msix_vector_count; + irq_context->reply_fifo_desc_buf_pool = (struct dma_pool *) + ps3_dma_pool_create("PS3 reply fifo desc pool", + &pdev->dev, reply_fifo_desc_buf_size, + sizeof(struct PS3ReplyFifoDesc), 0); + INJECT_START(PS3_ERR_IJ_REPLY_FIFO_DESC_BUF_POOL_ALLOC_FAILED, &(irq_context->reply_fifo_desc_buf_pool)) + if (irq_context->reply_fifo_desc_buf_pool == NULL) { + LOG_ERROR("host_no:%u ps3_dma_pool_create fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_desc_buf_pool_failed; + } + + irq_context->reply_fifo_desc_buf = (struct PS3ReplyFifoDesc*) + ps3_dma_pool_zalloc(irq_context->instance, irq_context->reply_fifo_desc_buf_pool, + GFP_KERNEL, + &irq_context->reply_fifo_desc_buf_phys); + INJECT_START(PS3_ERR_IJ_REPLY_FIFO_DESC_BUF_ALLOC_FAILED, &(irq_context->reply_fifo_desc_buf)) + if (irq_context->reply_fifo_desc_buf == NULL) { + LOG_ERROR("host_no:%u ps3_dma_pool_create fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_desc_buf_alloc_failed; + } + + return PS3_SUCCESS; + +l_desc_buf_alloc_failed: + ps3_dma_pool_destroy(irq_context->reply_fifo_desc_buf_pool); + irq_context->reply_fifo_desc_buf_pool = NULL; +l_desc_buf_pool_failed: + return -PS3_FAILED; +} + +static void ps3_reply_fifo_desc_free(struct ps3_irq_context *irq_context) +{ + if (irq_context->reply_fifo_desc_buf != NULL) { + ps3_dma_pool_free( + irq_context->reply_fifo_desc_buf_pool, + irq_context->reply_fifo_desc_buf, + irq_context->reply_fifo_desc_buf_phys); + irq_context->reply_fifo_desc_buf = NULL; + irq_context->reply_fifo_desc_buf_phys = 0; + } + + if (irq_context->reply_fifo_desc_buf_pool != NULL) { + ps3_dma_pool_destroy(irq_context->reply_fifo_desc_buf_pool); + irq_context->reply_fifo_desc_buf_pool = NULL; + } + + return; +} + +static S32 __ps3_reply_fifo_alloc(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + dma_addr_t *phys_base = irq_context->reply_fifo_phys_base_addr_buf; + size_t reply_fifo_size = sizeof(struct PS3ReplyWord) * + irq_context->reply_fifo_depth; + U32 i = 0; + (void)pdev; + + for (; i < irq_context->valid_msix_vector_count; i++) { + virt_base[i] = (struct PS3ReplyWord *) + ps3_dma_pool_alloc(irq_context->instance, irq_context->reply_fifo_pool, + GFP_KERNEL, + &phys_base[i]); + INJECT_START(PS3_ERR_IJ_REPLY_VIRT_BASE_ALLOC_FAILED, &(virt_base[i])) + if (virt_base[i] == NULL) { + LOG_ERROR("host_no:%u ps3_dma_pool_zalloc fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_alloc_failed; + } + memset(virt_base[i], 0xff, reply_fifo_size); + ps3_get_so_addr_ranger(irq_context->instance, phys_base[i], reply_fifo_size); + LOG_DEBUG("host_no:%u reply_fifo index:%u phy addr:0x%llx! \n", + PS3_IRQCTX_HOST(irq_context), i, phys_base[i]); + } + + return PS3_SUCCESS; + +l_alloc_failed: + for (; i > 0; i--) { + ps3_dma_pool_free( + irq_context->reply_fifo_pool, + virt_base[i-1], phys_base[i-1]); + virt_base[i-1] = NULL; + phys_base[i-1] = 0; + } + return -PS3_FAILED; +} + +static S32 ps3_reply_fifo_alloc(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + size_t reply_fifo_size = sizeof(struct PS3ReplyWord) * + irq_context->reply_fifo_depth; + irq_context->reply_fifo_pool = + ps3_dma_pool_create("PS3 reply fifo pool", + &pdev->dev, reply_fifo_size, DMA_ALIGN_BYTES_4K, 0); + INJECT_START(PS3_ERR_IJ_REPLY_FIFO_POOL_ALLOC_FAILED,& (irq_context->reply_fifo_pool)) + if (irq_context->reply_fifo_pool == NULL) { + LOG_ERROR("host_no:%u ps3_dma_pool_create fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_reply_fifo_pool_failed; + } + + if (__ps3_reply_fifo_alloc(pdev, irq_context) != PS3_SUCCESS) { + goto l_reply_fifo_alloc_failed; + } + + return PS3_SUCCESS; + +l_reply_fifo_alloc_failed: + ps3_dma_pool_destroy(irq_context->reply_fifo_pool); + irq_context->reply_fifo_pool = NULL; +l_reply_fifo_pool_failed: + return -PS3_FAILED; +} + +static void ps3_reply_fifo_free(struct ps3_irq_context *irq_context) +{ + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + dma_addr_t *phys_base = irq_context->reply_fifo_phys_base_addr_buf; + U32 i = 0; + + if (irq_context->reply_fifo_pool == NULL) { + goto l_out; + } + + for (; i < irq_context->valid_msix_vector_count; i++) { + + if (virt_base[i] == NULL) { + continue; + } + + ps3_dma_pool_free( + irq_context->reply_fifo_pool, + virt_base[i], phys_base[i]); + virt_base[i] = NULL; + phys_base[i] = 0; + } + + ps3_dma_pool_destroy(irq_context->reply_fifo_pool); + irq_context->reply_fifo_pool = NULL; +l_out: + return; +} + +static S32 ps3_irq_resource_alloc(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + if (ps3_reply_fifo_desc_alloc(pdev, irq_context) != PS3_SUCCESS) { + goto l_desc_alloc_failed; + } + + if (ps3_reply_fifo_alloc(pdev, irq_context) != PS3_SUCCESS) { + goto l_reply_fifo_alloc_failed; + } + + return PS3_SUCCESS; + +l_reply_fifo_alloc_failed: + ps3_reply_fifo_desc_free(irq_context); +l_desc_alloc_failed: + return -PS3_FAILED; +} + +static void ps3_irq_resource_free(struct ps3_irq_context *irq_context) +{ + ps3_reply_fifo_free(irq_context); + ps3_reply_fifo_desc_free(irq_context); + + return; +} + +static void ps3_reply_fifo_desc_set(struct pci_dev *pdev, + struct ps3_irq_context *irq_context) +{ + struct PS3ReplyFifoDesc *desc_buf = irq_context->reply_fifo_desc_buf; + dma_addr_t *phys_base = irq_context->reply_fifo_phys_base_addr_buf; + U32 i = 0; + + for (; i < irq_context->valid_msix_vector_count; i++) { + desc_buf[i].ReplyFifoBaseAddr = cpu_to_le64(phys_base[i]); + desc_buf[i].irqNo = cpu_to_le32(pci_irq_vector(pdev, i)); + desc_buf[i].depthReplyFifo = irq_context->reply_fifo_depth; + + if (irq_context->is_support_balance && + i < irq_context->high_iops_msix_vectors) { + desc_buf[i].isrAccMode = PS3_ISR_ACC_MODE_IOPS_VER0; + } + else { + desc_buf[i].isrAccMode = PS3_ISR_ACC_MODE_LATENCY; + } + } + + return; +} + +static inline void __ps3_irqs_exit(struct ps3_irq *irq, struct ps3_irq_context *irq_context) +{ + irq_set_affinity_hint(irq->irqNo, NULL); + + if (irq->is_irq_poll_disabled == PS3_FALSE) { + ps3_irq_poll_disable(&irq->irqpoll); + irq->is_irq_poll_disabled = PS3_TRUE; + } else { + LOG_INFO("host_no:%u irq poll(%u) already disabled!\n", + PS3_HOST(irq_context->instance), irq->isrSN); + } + + free_irq(irq->irqNo, irq); +} + +S32 ps3_irqs_init(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + struct pci_dev *pdev = instance->pdev; + struct ps3_irq *irqs = NULL; + U32 i = 0; + U32 dump_irq_index; + S32 retval; + irq_context->irqs = (struct ps3_irq*) + ps3_kcalloc(instance, irq_context->valid_msix_vector_count, + sizeof(struct ps3_irq)); + INJECT_START(PS3_ERR_IJ_IRQS_ALLOC_FAILED, &(irq_context->irqs)) + if (irq_context->irqs == NULL) { + LOG_ERROR("host_no:%u kcalloc fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_out; + } + irqs = irq_context->irqs; + + for (i=0; i < irq_context->valid_msix_vector_count; i++) { + irqs[i].irqNo = pci_irq_vector(pdev, i); + irqs[i].isrSN = i; + irqs[i].reply_fifo_virt_base_addr = virt_base[i]; + irqs[i].instance = instance; + irqs[i].irq_poll_sched_threshold = PS3_IRQ_POLL_SCHED_THRESHOLD; + irqs[i].is_irq_poll_disabled = PS3_FALSE; + irqs[i].is_sched_irq_poll = PS3_FALSE; + irqs[i].is_enable_irq = PS3_TRUE; + atomic_set(&irqs[i].is_busy, 0); + irqs[i].last_reply_idx = 0; + snprintf(irqs[i].name, PS3_IRQ_NAME_LENGTH, "ps3_irq_%d_%d", + instance->host->host_no, i); + retval = request_irq(irqs[i].irqNo, instance->ioc_adpter->isr, + IRQF_SHARED, irqs[i].name, &(irqs[i])); + INJECT_START(PS3_ERR_IJ_REPLY_REQ_IRQS_FAILED, &retval) + if (retval) { + LOG_ERROR("host_no:%u request_irq failed! SN:%d\n", + PS3_HOST(instance), i); + + goto l_failed; + } + + ps3_irq_poll_init(&irqs[i].irqpoll, PS3_IRQ_POLL_SCHED_THRESHOLD, + ps3_irqpoll_service); + } + + dump_irq_index = PS3_MGR_CMD_MSIX_INDEX(irq_context); + retval = request_irq(irqs[dump_irq_index].irqNo, ps3_dump_irq_handler, IRQF_SHARED, "ps3_dump_irq", (void *)instance); + INJECT_START(PS3_ERR_IJ_DUMP_REQ_IRQS_FAILED, &retval) + if (retval) { + LOG_ERROR("host_no:%u request dump irq failed! SN:%d\n", + PS3_HOST(instance), dump_irq_index); + goto l_failed; + } + irq_context->dump_isrSN = dump_irq_index; + + instance->ioc_adpter->irq_disable(instance); + + return PS3_SUCCESS; +l_failed: + for (; i > 0; i--) { + __ps3_irqs_exit(&irqs[i-1], irq_context); + } + + if (irq_context->irqs != NULL) { + ps3_kfree(instance, irq_context->irqs); + irq_context->irqs = NULL; + } +l_out: + return -PS3_FAILED; +} + +S32 ps3_irqs_init_switch(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + struct pci_dev *pdev = instance->pdev; + struct ps3_irq *irqs = NULL; + struct ps3_irq_recovery *irqs_recovery = NULL; + U32 i = 0; + U32 dump_irq_index; + U32 watch_irq_index = PS3_SWITCH_IRQ_INDEX; + + irq_context->irqs = (struct ps3_irq*) + ps3_kcalloc(instance, irq_context->valid_msix_vector_count, + sizeof(struct ps3_irq)); + if (irq_context->irqs == NULL) { + LOG_ERROR("host_no:%u kcalloc fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_out; + } + irqs = irq_context->irqs; + + for (i=0; i < irq_context->valid_msix_vector_count; i++) { + irqs[i].irqNo = pci_irq_vector(pdev, i); + irqs[i].isrSN = i; + irqs[i].reply_fifo_virt_base_addr = virt_base[i]; + irqs[i].instance = instance; + irqs[i].irq_poll_sched_threshold = PS3_IRQ_POLL_SCHED_THRESHOLD; + irqs[i].is_irq_poll_disabled = PS3_FALSE; + irqs[i].is_sched_irq_poll = PS3_FALSE; + irqs[i].is_enable_irq = PS3_TRUE; + atomic_set(&irqs[i].is_busy, 0); + irqs[i].last_reply_idx = 0; + snprintf(irqs[i].name, PS3_IRQ_NAME_LENGTH, "ps3_irq_%d_%d", + instance->host->host_no, i); + + if (request_irq(irqs[i].irqNo, instance->ioc_adpter->isr, + IRQF_SHARED, irqs[i].name, &(irqs[i]))) { + LOG_ERROR("host_no:%u request_irq failed! SN:%d\n", + PS3_HOST(instance), i); + + goto l_failed; + } + + ps3_irq_poll_init(&irqs[i].irqpoll, PS3_IRQ_POLL_SCHED_THRESHOLD, + ps3_irqpoll_service); + } + + dump_irq_index = PS3_MGR_CMD_MSIX_INDEX(irq_context); + if (request_irq(irqs[dump_irq_index].irqNo, ps3_dump_irq_handler, IRQF_SHARED, "ps3_dump_irq", (void *)instance)) { + LOG_ERROR("host_no:%u request dump irq failed! SN:%d\n", + PS3_HOST(instance), dump_irq_index); + goto l_failed; + } + irq_context->dump_isrSN = dump_irq_index; + + irq_context->irq_recovery = (struct ps3_irq_recovery*) + ps3_kcalloc(instance, 1, + sizeof(struct ps3_irq_recovery)); + if (irq_context->irq_recovery == NULL) { + LOG_ERROR("host_no:%u kcalloc irq_recovery fail! \n", + PS3_IRQCTX_HOST(irq_context)); + goto l_free_dump; + } + irqs_recovery = irq_context->irq_recovery; + irqs_recovery->irqNo = pci_irq_vector(pdev, 0); + irqs_recovery->isrSN = watch_irq_index; + irqs_recovery->instance = instance; + + if (request_irq(irqs_recovery[watch_irq_index].irqNo, ps3_recovery_irq_handler, + IRQF_SHARED, "ps3_watchdog_irq", (void *)irqs_recovery)) { + LOG_ERROR("host_no:%u request watchdog irq failed! SN:%d\n", + PS3_HOST(instance), watch_irq_index); + goto l_free_dump; + } + instance->ioc_adpter->irq_disable(instance); + + return PS3_SUCCESS; +l_free_dump: + free_irq(irqs[dump_irq_index].irqNo, instance); +l_failed: + for (; i > 0; i--) { + __ps3_irqs_exit(&irqs[i-1], irq_context); + } + + if (irq_context->irqs != NULL) { + ps3_kfree(instance, irq_context->irqs); + irq_context->irqs = NULL; + } + + if (irq_context->irq_recovery != NULL) { + ps3_kfree(instance, irq_context->irq_recovery); + irq_context->irq_recovery = NULL; + } +l_out: + return -PS3_FAILED; +} + +void ps3_irqs_exit(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_irq *irqs = irq_context->irqs; + struct pci_dev *pdev = instance->pdev; + U32 i = 0; + U32 dump_irq_index; + U32 watch_irq_index = PS3_SWITCH_IRQ_INDEX; + struct ps3_irq_recovery * irq_recovery; + + if (irqs == NULL) { + goto l_out; + } + + dump_irq_index = PS3_MGR_CMD_MSIX_INDEX(irq_context); + irq_set_affinity_hint(irqs[dump_irq_index].irqNo, NULL); + free_irq(irqs[dump_irq_index].irqNo, instance); + + if (irq_context->irq_recovery != NULL) { + irq_set_affinity_hint(irq_context->irq_recovery[watch_irq_index].irqNo, NULL); + free_irq(irq_context->irq_recovery[watch_irq_index].irqNo, irq_context->irq_recovery); + irq_recovery = irq_context->irq_recovery; + irq_context->irq_recovery = NULL; + ps3_kfree(instance, irq_recovery); + } + + for (i=0; i < irq_context->valid_msix_vector_count; i++) { + __ps3_irqs_exit(&irqs[i], irq_context); + } + + irq_context->irqs = NULL; + kfree(irqs); + + if (pdev->msix_enabled || pdev->msi_enabled) { + pci_free_irq_vectors(pdev); + } + +l_out: + return; +} + +static Bool ps3_irq_max_vectors_calc(struct ps3_instance *instance, + S32 *max_vectors) +{ + Bool ret = PS3_TRUE; + U32 max_replyq_count = 0; + + if (!instance->ioc_adpter->max_replyq_count_get(instance, &max_replyq_count)) { + LOG_ERROR("host_no:%u get max replyq count NOK\n", PS3_HOST(instance)); + ret = PS3_FALSE; + goto l_out; + } + + if (max_replyq_count > PS3_MSIX_COMBINED_MODE_MSIX_VECTORS) { + instance->msix_combined = PS3_TRUE; + } + + LOG_INFO("reqlyq max_replyq_count:%d\n", max_replyq_count); + + *max_vectors = pci_msix_vec_count(instance->pdev); + INJECT_START(PS3_ERR_IJ_GET_MSIX_VEC_COUNT_INVALID, max_vectors) + if (*max_vectors <= 0) { + *max_vectors = pci_msi_vec_count(instance->pdev); + INJECT_START(PS3_ERR_IJ_GET_MSIX_VEC_COUNT_INVALID, max_vectors) + if (*max_vectors < 0) { + *max_vectors = 0; + goto l_out; + } + } + *max_vectors = min_t(S32, *max_vectors, max_replyq_count); + +l_out: + return ret; +} + +S32 ps3_irq_context_init(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct pci_dev *pdev = instance->pdev; + S32 max_vectors = 0; + if (!ps3_irq_max_vectors_calc(instance, &max_vectors)) { + goto l_irq_vectors_alloc_failed; + } + + if (!ps3_ioc_mgr_max_fw_cmd_get(instance, + &irq_context->reply_fifo_depth)) { + goto l_irq_vectors_alloc_failed; + } + + irq_context->reply_fifo_depth += instance->reply_fifo_depth_addition; + irq_context->instance = instance; + + LOG_INFO("max_vectors:%d replyQ_depth:%d\n", + max_vectors, irq_context->reply_fifo_depth); + + if (max_vectors <= 0) { + LOG_ERROR("host_no:%u IOC max_vectors invliad:%d \n", + PS3_IRQCTX_HOST(irq_context), max_vectors); + goto l_irq_vectors_alloc_failed; + } + + if (!instance->msix_combined) { + instance->smp_affinity_enable = PS3_FALSE; + } + + if (ps3_irq_vectors_alloc(pdev, irq_context, max_vectors) < + instance->min_intr_count) { + LOG_ERROR("host_no:%u alloc irq NOK![cpunum:%d][irq_type:%d][min_intr:%d] \n", + PS3_IRQCTX_HOST(irq_context), num_online_cpus(), + irq_context->pci_irq_type, instance->min_intr_count); + if (irq_context->valid_msix_vector_count > 0) { + pci_free_irq_vectors(pdev); + irq_context->high_iops_msix_vectors = 0; + irq_context->valid_msix_vector_count = 0; + } + goto l_irq_vectors_alloc_failed; + } + + if (ps3_cpu_msix_table_init(pdev, irq_context) != PS3_SUCCESS) { + goto l_cpu_msix_table_init_failed; + } + + if (ps3_irq_resource_alloc(pdev, irq_context) != PS3_SUCCESS) { + goto l_irq_resource_alloc_failed; + } + + ps3_reply_fifo_desc_set(pdev, irq_context); + instance->is_support_irq = PS3_TRUE; + + return PS3_SUCCESS; + +l_irq_resource_alloc_failed: + kfree(irq_context->cpu_msix_table); + irq_context->cpu_msix_table = NULL; +l_cpu_msix_table_init_failed: + pci_free_irq_vectors(pdev); + irq_context->high_iops_msix_vectors = 0; + irq_context->valid_msix_vector_count = 0; +l_irq_vectors_alloc_failed: + memset(irq_context, 0, sizeof(struct ps3_irq_context)); + return -PS3_FAILED; +} + +S32 ps3_irq_context_exit(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct pci_dev *pdev = instance->pdev; + + ps3_irq_resource_free(irq_context); + + if (irq_context->cpu_msix_table != NULL) { + kfree(irq_context->cpu_msix_table); + irq_context->cpu_msix_table = NULL; + } + + if (pdev->msix_enabled || pdev->msi_enabled) { + pci_free_irq_vectors(pdev); + } + + memset(irq_context, 0, sizeof(struct ps3_irq_context)); + return PS3_SUCCESS; +} + +static inline Bool ps3_is_hdd_cmd(struct ps3_cmd *cmd) +{ + Bool is_hdd_io = PS3_FALSE; + const struct PS3VDEntry *vd_entry = NULL; + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + vd_entry = cmd->io_attr.vd_entry; + if (!vd_entry->isNvme && !vd_entry->isSsd) { + is_hdd_io = PS3_TRUE; + } + } else { + if (ps3_is_hdd_pd(cmd->io_attr.pd_entry->dev_type)) { + is_hdd_io = PS3_TRUE; + } + } + + return is_hdd_io; +} + +static inline Bool ps3_sdev_is_high_load(struct ps3_cmd *cmd, U16 scale) +{ + S32 busy_base = cmd->instance->device_busy_threshold; + S32 busy_threshold = busy_base * scale; + S32 device_busy = 0; +#if defined DRIVER_SUPPORT_PRIV_BUSY + struct ps3_scsi_priv_data *device_priv_data = (struct ps3_scsi_priv_data*)cmd->scmd->device->hostdata; + if (device_priv_data == NULL) { + return PS3_FALSE; + } + device_busy = atomic_read(&device_priv_data->sdev_priv_busy); +#else + device_busy = atomic_read(&cmd->scmd->device->device_busy); +#endif + + if (PS3_MULTI_DATA_DISK_BUSY_THRESHOLD(busy_threshold, busy_base) && !ps3_is_hdd_cmd(cmd)) { + if (ps3_host_vendor_get() == PS3_HOST_VENDOR_HYGON && + busy_threshold <= PS3_HYGON_BUSY_ADJUST_THRESHOLD) { + busy_threshold = busy_base; + } else if (busy_threshold > PS3_SSD_MAX_BUSY_THRESHOLD) { + busy_threshold = PS3_SSD_MAX_BUSY_THRESHOLD; + } + } + + if (device_busy > busy_threshold) { + return PS3_TRUE; + } + return PS3_FALSE; +} + +static inline U32 ps3_iops_msix_index_get(struct ps3_irq_context *irq_context) +{ + U32 msix_index = 0; + U32 ioc_count = atomic_add_return(1, &irq_context->high_iops_io_count); + U32 batch_num = ioc_count >> PS3_HIGH_IOPS_VECTOR_BATCH_COUNT_SHIFT; + + msix_index = batch_num % PS3_IOPS_MSIX_VECTORS; + return msix_index; +} + +U32 ps3_msix_index_get(struct ps3_cmd *cmd, U16 scale) +{ + int processor_id = 0; + U32 msix_index = 0; + struct ps3_irq_context *irq_context = &cmd->instance->irq_context; + + if (irq_context->valid_msix_vector_count == 1) { + msix_index = 0; + goto l_out; + } + + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + msix_index = PS3_MGR_CMD_MSIX_INDEX(irq_context); + goto l_out; + } + + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type) && + (irq_context->is_balance_current_perf_mode) && + ps3_sdev_is_high_load(cmd, scale)) { + msix_index = ps3_iops_msix_index_get(irq_context); + } else if (cmd->instance->host->nr_hw_queues > 1) { + msix_index = blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(SCMD_GET_REQUEST(cmd->scmd))) + + irq_context->high_iops_msix_vectors; + } else { + processor_id = raw_smp_processor_id(); + msix_index = irq_context->cpu_msix_table[processor_id]; + + if (msix_index == PS3_MGR_CMD_MSIX_INDEX(irq_context)) { + msix_index++; + } + } + +l_out: + return msix_index; +} +void ps3_perf_update(struct ps3_instance *instance, U8 iocPerfMode) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + Bool support_balance = irq_context->is_support_balance; + Bool *is_balance = &irq_context->is_balance_current_perf_mode; + + if (support_balance) { + if (iocPerfMode == PS3_PERF_MODE_BALANCE) { + *is_balance = PS3_TRUE; + } else { + *is_balance = PS3_FALSE; + } + } else { + *is_balance = PS3_FALSE; + } + + return; +} +void ps3_irqs_enable(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + + LOG_DEBUG("host_no:%u irq enable\n", PS3_HOST(instance)); + + switch (irq_context->pci_irq_type) + { + case PS3_PCI_IRQ_LEGACY: + ps3_ioc_legacy_irqs_enable(instance); + break; + case PS3_PCI_IRQ_MSI: + ps3_ioc_msi_enable(instance); + break; + case PS3_PCI_IRQ_MSIX: + ps3_ioc_msix_enable(instance); + break; + default: + LOG_ERROR("host_no:%u irq type is NOK :%d \n", + PS3_HOST(instance), irq_context->pci_irq_type); + break; + } + irq_context->is_enable_interrupts = PS3_DRV_TRUE; + mb(); + return; +} + +void ps3_irqs_disable(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + + LOG_DEBUG("host_no:%u irq disable\n", PS3_HOST(instance)); + + if(irq_context->is_enable_interrupts == PS3_DRV_FALSE) { + goto l_out; + } + + irq_context->is_enable_interrupts = PS3_DRV_FALSE; + mb(); + switch (irq_context->pci_irq_type) + { + case PS3_PCI_IRQ_LEGACY: + ps3_ioc_legacy_irqs_disable(instance); + break; + case PS3_PCI_IRQ_MSI: + ps3_ioc_msi_disable(instance); + break; + case PS3_PCI_IRQ_MSIX: + ps3_ioc_msix_disable(instance); + break; + default: + LOG_ERROR("host_no:%u irq type is NOK :%d \n", + PS3_HOST(instance), irq_context->pci_irq_type); + break; + } + +l_out: + return; +} + +irqreturn_t ps3_irqs_service(int irq_so, void *priv) +{ + irqreturn_t ret = IRQ_NONE; + int complete_num = 0; + struct ps3_irq *irq = (struct ps3_irq *)priv; + struct ps3_irq_context *irq_context = NULL; + + if (irq == NULL) { + LOG_ERROR_IN_IRQ(irq->instance, "irq is null !\n"); + ret = IRQ_NONE; + goto l_out; + } + irq_context = &irq->instance->irq_context; + + if ((U32)irq_so != irq->irqNo) { + LOG_ERROR_IN_IRQ(irq->instance, + "irq_so:%d != irq->irqNo:%d !\n", + irq_so, irq->irqNo); + ret = IRQ_NONE; + goto l_out; + } + + if (!irq_context->is_enable_interrupts) { + LOG_INFO_IN_IRQ(irq->instance, + "host_no:%u interrupt has disabled !\n", + PS3_HOST(irq->instance)); + ret = IRQ_NONE; + goto l_out; + } + + if (irq->is_sched_irq_poll) { + LOG_WARN_IN_IRQ(irq->instance, + "host_no:%u had enter into irq poll !\n", + PS3_HOST(irq->instance)); + ret = IRQ_HANDLED; + goto l_out; + } + + complete_num = ps3_cmd_complete(irq); + if (complete_num <= 0) { + LOG_DEBUG("host_no:%u there is no completed ps3_cmd !\n", + PS3_HOST(irq->instance)); + ret = IRQ_NONE; + } else { + ret = IRQ_HANDLED; + } + +l_out: + return ret; +} + +S32 ps3_irqpoll_service(struct irq_poll *irqpoll, int budget) +{ + S32 complete_num = 0; + struct ps3_irq *irq = ps3_container_of(irqpoll, struct ps3_irq, irqpoll); + + if (irq->is_enable_irq) { + disable_irq(irq->irqNo); + irq->is_enable_irq = PS3_DRV_FALSE; + } + + complete_num = ps3_cmd_complete(irq); + if (complete_num < budget) { + ps3_irq_poll_complete(irqpoll); + irq->is_sched_irq_poll = PS3_DRV_FALSE; + enable_irq(irq->irqNo); + irq->is_enable_irq = PS3_DRV_TRUE; + } + + return complete_num; +} + +void ps3_irqpolls_enable(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_irq *irqs = irq_context->irqs; + U32 i = 0; + + for (; i < irq_context->valid_msix_vector_count; i++) { + if (irqs[i].is_irq_poll_disabled == PS3_TRUE) { + ps3_irq_poll_enable(&irqs[i].irqpoll); + irqs[i].is_irq_poll_disabled = PS3_FALSE; + } else { + LOG_INFO("host_no:%u irq poll(%d) not disabled!\n", + PS3_HOST(instance), i); + } + } + + return; +} + +void ps3_irqs_sync(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_irq *irqs = irq_context->irqs; + U32 i = 0; + if (irqs == NULL) { + goto l_out; + } + for (; i < irq_context->valid_msix_vector_count; i++) { + synchronize_irq(irqs[i].irqNo); + + if (irqs[i].is_irq_poll_disabled == PS3_FALSE) { + ps3_irq_poll_disable(&irqs[i].irqpoll); + irqs[i].is_irq_poll_disabled = PS3_TRUE; + } else { + LOG_INFO("host_no:%u irq poll(%d) already disabled!\n", + PS3_HOST(instance), i); + } + } +l_out: + return; +} + +#else + +static void ps3_reply_fifo_desc_free(struct ps3_instance *instance); +static void ps3_reply_fifo_free(struct ps3_instance *instance); +static void ps3_irq_resource_free(struct ps3_instance *instance); + +static Bool ps3_irq_max_vectors_calc(struct ps3_instance *instance, + U32 *max_vectors) +{ + Bool ret = PS3_TRUE; + U32 max_replyq_count = 0; + + if (!instance->ioc_adpter->max_replyq_count_get(instance, + &max_replyq_count)) { + ret = PS3_FALSE; + goto l_out; + } + + LOG_INFO("reqlyq max_replyq_count:%u\n", max_replyq_count); + + *max_vectors = instance->pci_dev_context.irq_vec_count; + + *max_vectors = PS3_MIN(*max_vectors, max_replyq_count); + *max_vectors = PS3_MIN(*max_vectors, (U32)num_online_cpus() + 1); +l_out: + return ret; +} + +static S32 ps3_reply_fifo_desc_alloc(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + + irq_context->reply_fifo_desc_buf_size = sizeof(struct PS3ReplyFifoDesc) * + irq_context->valid_msix_vector_count; + + irq_context->reply_fifo_desc_buf = (struct PS3ReplyFifoDesc*) + ps3_dma_alloc_coherent(instance, + irq_context->reply_fifo_desc_buf_size, + &irq_context->reply_fifo_desc_buf_phys); + if (irq_context->reply_fifo_desc_buf == NULL) { + LOG_ERROR("host_no:%u dma alloc fail! \n", + PS3_HOST(instance)); + goto l_failed; + } + + return PS3_SUCCESS; +l_failed: + ps3_reply_fifo_desc_free(instance); + return -PS3_FAILED; +} + +static void ps3_reply_fifo_desc_free(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + if (irq_context->reply_fifo_desc_buf != NULL) { + ps3_dma_free_coherent(instance, + irq_context->reply_fifo_desc_buf_size, + irq_context->reply_fifo_desc_buf, + irq_context->reply_fifo_desc_buf_phys); + + irq_context->reply_fifo_desc_buf = NULL; + irq_context->reply_fifo_desc_buf_phys = 0; + } + + return; +} + +static S32 ps3_reply_fifo_alloc(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + dma_addr_t *phys_base = irq_context->reply_fifo_phys_base_addr_buf; + U32 i = 0; + + irq_context->reply_fifo_size = sizeof(struct PS3ReplyWord) * + irq_context->reply_fifo_depth; + + for (; i < irq_context->valid_msix_vector_count; i++) { + virt_base[i] = (struct PS3ReplyWord*) + ps3_dma_alloc_coherent(instance, + irq_context->reply_fifo_size, + &phys_base[i]); + if (virt_base[i] == NULL) { + LOG_ERROR("host_no:%u ps3_dma_pool_zalloc fail! \n", + PS3_HOST(instance)); + goto l_failed; + } + memset(virt_base[i], 0xff, irq_context->reply_fifo_size); + } + + return PS3_SUCCESS; + +l_failed: + ps3_reply_fifo_free(instance); + return -PS3_FAILED; +} + +static void ps3_reply_fifo_free(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + dma_addr_t *phys_base = irq_context->reply_fifo_phys_base_addr_buf; + U32 i = 0; + + for (; i < irq_context->valid_msix_vector_count; i++) { + + if (virt_base[i] == NULL) { + continue; + } + + ps3_dma_free_coherent(instance, + irq_context->reply_fifo_size, + virt_base[i], + phys_base[i]); + + virt_base[i] = NULL; + phys_base[i] = 0; + } + + return; +} + +static inline S32 ps3_irq_group_affinity_alloc(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + U32 size = sizeof(GROUP_AFFINITY) * irq_context->valid_msix_vector_count; + + irq_context->group_affinity = ps3_kzalloc(instance, size); + if (irq_context->group_affinity == NULL) { + LOG_ERROR("host_no:%u, group_affinity alloc failed\n", PS3_HOST(instance)); + return -PS3_FAILED; + } + return PS3_SUCCESS; +} + +static inline void ps3_irq_group_affinity_free(struct ps3_instance *instance) +{ + if (instance->irq_context.group_affinity != NULL) { + ps3_kfree(instance, instance->irq_context.group_affinity); + instance->irq_context.group_affinity = NULL; + } +} + +static S32 ps3_irq_resource_alloc(struct ps3_instance *instance) +{ + if (ps3_reply_fifo_desc_alloc(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_reply_fifo_alloc(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_irq_group_affinity_alloc(instance) != PS3_SUCCESS) { + goto l_failed; + } + + return PS3_SUCCESS; + +l_failed: + ps3_irq_resource_free(instance); + return -PS3_FAILED; +} + +static void ps3_irq_resource_free(struct ps3_instance *instance) +{ + ps3_irq_group_affinity_free(instance); + ps3_reply_fifo_free(instance); + ps3_reply_fifo_desc_free(instance); + + return; +} + +static void ps3_reply_fifo_desc_set(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyFifoDesc *desc_buf = irq_context->reply_fifo_desc_buf; + dma_addr_t *phys_base = irq_context->reply_fifo_phys_base_addr_buf; + + U32 i = 0; + for (; i < irq_context->valid_msix_vector_count; i++) { + desc_buf[i].ReplyFifoBaseAddr = cpu_to_le64(phys_base[i]); + desc_buf[i].irqNo = i; + desc_buf[i].depthReplyFifo = (U16)irq_context->reply_fifo_depth; + + if (i < irq_context->high_iops_msix_vectors) { + desc_buf[i].isHighIops = PS3_TRUE; + } else { + desc_buf[i].isHighIops = PS3_FALSE; + } + } + + return; +} + +S32 ps3_irq_context_init(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + U32 max_vectors = 0; + if (!ps3_irq_max_vectors_calc(instance, &max_vectors)) { + goto l_failed; + } + + if (!ps3_ioc_mgr_max_fw_cmd_get(instance, + &irq_context->reply_fifo_depth)) { + goto l_failed; + } + + irq_context->reply_fifo_depth += instance->reply_fifo_depth_addition; + irq_context->instance = instance; + + irq_context->high_iops_msix_vectors = 0; + + LOG_INFO("max_vectors:%d replyQ_depth:%d\n", + max_vectors, irq_context->reply_fifo_depth); + + if (max_vectors <= instance->min_intr_count) { + LOG_ERROR("host_no:%u alloc irq failed![cpunum:%d][irq_type:%d][min_intr:%d] \n", + PS3_HOST(instance), num_online_cpus(), + irq_context->pci_irq_type, instance->min_intr_count); + goto l_failed; + } + + irq_context->pci_irq_type = instance->pci_dev_context.pci_irq_type; + irq_context->valid_msix_vector_count = max_vectors; + if (ps3_irq_resource_alloc(instance) != PS3_SUCCESS) { + goto l_failed; + } + + ps3_reply_fifo_desc_set(instance); + + return PS3_SUCCESS; + +l_failed: + ps3_irq_context_exit(instance); + return -PS3_FAILED; +} + +S32 ps3_irq_context_exit(struct ps3_instance *instance) +{ + ps3_irq_resource_free(instance); + + return PS3_SUCCESS; +} + +U8 ps3_irqs_service(void *priv, ULong irq_no) +{ + struct ps3_instance *instance = (struct ps3_instance*)priv; + U32 isrSN = (U32)irq_no; + if (isrSN >= instance->irq_context.valid_msix_vector_count) { + goto l_out; + } + + if (!instance->irq_context.is_enable_interrupts) { + goto l_out; + } + + StorPortIssueDpc(instance, + &instance->irq_context.irqs[isrSN].dpc, + &instance->irq_context.irqs[isrSN].isrSN, + NULL); + +l_out: + return PS3_TRUE; +} + +static void ps3_irq_dpc_routine(PSTOR_DPC dpc, + void *context, + void *isr_no, + void *arg +) +{ + struct ps3_instance *instance = (struct ps3_instance*)context; + U32 isrSN = *((U32*)isr_no); + struct ps3_irq *irqs = &instance->irq_context.irqs[isrSN]; + (void)arg; + (void)dpc; + + LOG_DEBUG("%d\n", isrSN); + irqs->is_dpc_running = PS3_TRUE; + + ps3_cmd_complete(irqs); + + irqs->is_dpc_running = PS3_FALSE; +} + +S32 ps3_irqs_dpc_init(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_irq *irqs = NULL; + U32 i = 0; + + irqs = irq_context->irqs; + if (irq_context->irqs == NULL) { + LOG_ERROR("host_no:%u irqs fail! \n", + PS3_HOST(instance)); + goto l_out; + } + + for (i = 0; i < irq_context->valid_msix_vector_count; i++) { + irqs[i].is_dpc_running = PS3_FALSE; + StorPortInitializeDpc(instance, &irqs[i].dpc, ps3_irq_dpc_routine); + } + instance->ioc_adpter->irq_disable(instance); + return PS3_SUCCESS; + +l_out: + return -PS3_FAILED; +} + +S32 ps3_irqs_init(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + struct ps3_irq *irqs = NULL; + U32 i = 0; + + irq_context->irqs = (struct ps3_irq*) + ps3_kcalloc(instance, irq_context->valid_msix_vector_count, + sizeof(struct ps3_irq)); + if (irq_context->irqs == NULL) { + LOG_ERROR("host_no:%u kcalloc fail! \n", + PS3_HOST(instance)); + goto l_out; + } + irqs = irq_context->irqs; + + for (i = 0; i < irq_context->valid_msix_vector_count; i++) { + memset(&irqs[i], 0, sizeof(irqs[i])); + irqs[i].isrSN = i; + irqs[i].reply_fifo_virt_base_addr = virt_base[i]; + irqs[i].instance = instance; + ps3_atomic_set(&irqs[i].is_busy, 0); + irqs[i].last_reply_idx = 0; + } + + return PS3_SUCCESS; + +l_out: + return -PS3_FAILED; +} + +S32 ps3_irqs_init_switch(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct PS3ReplyWord **virt_base = irq_context->reply_fifo_virt_base_addr_buf; + struct ps3_irq *irqs = NULL; + U32 i = 0; + + irq_context->irqs = (struct ps3_irq*) + ps3_kcalloc(instance, irq_context->valid_msix_vector_count, + sizeof(struct ps3_irq)); + if (irq_context->irqs == NULL) { + LOG_ERROR("host_no:%u kcalloc fail! \n", + PS3_HOST(instance)); + goto l_out; + } + irqs = irq_context->irqs; + + for (i = 0; i < irq_context->valid_msix_vector_count; i++) { + memset(&irqs[i], 0, sizeof(irqs[i])); + irqs[i].isrSN = i; + irqs[i].reply_fifo_virt_base_addr = virt_base[i]; + irqs[i].instance = instance; + ps3_atomic_set(&irqs[i].is_busy, 0); + irqs[i].last_reply_idx = 0; + } + + return PS3_SUCCESS; + +l_out: + return -PS3_FAILED; +} + +static void ps3_irq_dpc_sync(struct ps3_instance *instance, struct ps3_irq *irqs) +{ + ULong status = STOR_STATUS_SUCCESS; + U8 cancel_ret = PS3_TRUE; + + if (irqs == NULL) { + LOG_ERROR("host_no:%u irqs fail! \n", + PS3_HOST(instance)); + goto l_out; + } + + status = StorPortCancelDpc(instance, &irqs->dpc, &cancel_ret); + if (status != STOR_STATUS_SUCCESS) { + LOG_ERROR("host_no:%u, cancel dpc failed,status:0x%x\n", PS3_HOST(instance), status); + } + + if (cancel_ret) { + goto l_out; + } + + while (irqs->is_dpc_running) { + ps3_msleep(10); + } +l_out: + return; +} + +void ps3_irqs_exit(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_irq *irqs = irq_context->irqs; + + if (irqs == NULL) { + goto l_out; + } + instance->ioc_adpter->irq_disable(instance); + + ps3_kfree(instance, irqs); + irq_context->irqs = NULL; + +l_out: + return; +} + +void ps3_irqs_enable(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + + LOG_DEBUG("host_no:%u irq enable\n", PS3_HOST(instance)); + + switch (irq_context->pci_irq_type) + { + case PS3_PCI_IRQ_LEGACY: + ps3_ioc_legacy_irqs_enable(instance); + break; + case PS3_PCI_IRQ_MSI: + ps3_ioc_msi_enable(instance); + break; + case PS3_PCI_IRQ_MSIX: + ps3_ioc_msix_enable(instance); + break; + default: + LOG_ERROR("host_no:%u irq type is failed :%d \n", + PS3_HOST(instance), irq_context->pci_irq_type); + break; + } + irq_context->is_enable_interrupts = PS3_DRV_TRUE; + mb(); + return; +} + +void ps3_irqs_disable(struct ps3_instance *instance) +{ + struct ps3_irq_context *irq_context = &instance->irq_context; + struct ps3_irq *irqs = irq_context->irqs; + U32 i = 0; + LOG_DEBUG("host_no:%u irq disable\n", PS3_HOST(instance)); + + if(irq_context->is_enable_interrupts == PS3_DRV_FALSE) { + goto l_out; + } + switch (irq_context->pci_irq_type) + { + case PS3_PCI_IRQ_LEGACY: + ps3_ioc_legacy_irqs_disable(instance); + break; + case PS3_PCI_IRQ_MSI: + ps3_ioc_msi_disable(instance); + break; + case PS3_PCI_IRQ_MSIX: + ps3_ioc_msix_disable(instance); + break; + default: + LOG_ERROR("host_no:%u irq type is failed :%d \n", + PS3_HOST(instance), irq_context->pci_irq_type); + break; + } + + if (irqs == NULL) { + LOG_ERROR("host_no:%u irqs fail! \n", + PS3_HOST(instance)); + goto l_out; + } + for (i = 0; i < irq_context->valid_msix_vector_count; i++) { + ps3_irq_dpc_sync(instance, &irqs[i]); + } + irq_context->is_enable_interrupts = PS3_DRV_FALSE; + mb(); + +l_out: + return; +} + +#endif + +void ps3_all_reply_fifo_init(struct ps3_instance *instance) +{ + U32 reply_fifo_size = sizeof(struct PS3ReplyWord) * + instance->irq_context.reply_fifo_depth; + struct ps3_irq *irq = NULL; + U32 i = 0; + + LOG_DEBUG("host_no:%u start to reply fifo init!\n", PS3_HOST(instance)); + for (; i < instance->irq_context.valid_msix_vector_count; ++i) { + irq = instance->irq_context.irqs + i; + memset(irq->reply_fifo_virt_base_addr, 0xff, reply_fifo_size); + irq->last_reply_idx = 0; + } + LOG_DEBUG("host_no:%u end to reply fifo init!\n", PS3_HOST(instance)); + + return; +} + diff --git a/drivers/scsi/ps3stor/ps3_irq.h b/drivers/scsi/ps3stor/ps3_irq.h new file mode 100644 index 0000000000000000000000000000000000000000..758a8c00f4391f9bd3e2194608fb59177de11218 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_irq.h @@ -0,0 +1,203 @@ +#ifndef _PS3_IRQ_H_ +#define _PS3_IRQ_H_ + +#ifndef _WINDOWS +#include +#include +#include + +#include +#endif + +#include "ps3_htp_def.h" +#include "ps3_err_def.h" +#include "ps3_cmd_channel.h" +#include "ps3_inner_data.h" + +#define PS3_IRQ_NAME_LENGTH (32) +#define PS3_SWITCH_IRQ_INDEX (0) + +struct ps3_instance; + +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR >= 2)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0))) +#define DRIVER_SUPPORT_KERNEL_IRQ_AFFINITY +#endif + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4,9,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) +#define PS3_OS_MANAGED_IRQ_SUPPORT +#endif + +enum { + PS3_PCI_IRQ_MODE_NONE_SPE = 0, + PS3_PCI_IRQ_MODE_LEGACY = 1, + PS3_PCI_IRQ_MODE_MSI = 2, + PS3_PCI_IRQ_MODE_MSIX = 3, +}; + +struct ps3_irq { + char name[PS3_IRQ_NAME_LENGTH]; + struct PS3ReplyWord *reply_fifo_virt_base_addr; + struct ps3_instance *instance; + + U32 irqNo; + U32 isrSN; + U16 last_reply_idx; + U8 reserved0[6]; +#ifdef _WINDOWS + STOR_DPC dpc; + volatile U8 is_dpc_running; +#else + struct irq_poll irqpoll; + Bool is_irq_poll_disabled; + U32 irq_poll_sched_threshold; + Bool is_sched_irq_poll; + Bool is_enable_irq; + U8 reserved1[2]; +#endif + ps3_atomic32 is_busy; +}; + +struct ps3_irq_recovery { + U32 irqNo; + U32 isrSN; + U8 reserved0[8]; + struct ps3_instance *instance; +}; + +struct ps3_irq_context { + struct ps3_instance *instance; + U32 reply_fifo_depth; + U32 valid_msix_vector_count; + U32 high_iops_msix_vectors; + U32 dump_isrSN; + U32 reply_fifo_desc_buf_size; +#ifndef _WINDOWS + struct dma_pool *reply_fifo_desc_buf_pool; +#endif + U32 reply_fifo_size; + dma_addr_t reply_fifo_desc_buf_phys; + struct PS3ReplyFifoDesc *reply_fifo_desc_buf; +#ifndef _WINDOWS + struct dma_pool *reply_fifo_pool; +#endif + struct PS3ReplyWord *reply_fifo_virt_base_addr_buf[PS3_MAX_REPLY_QUE_COUNT]; + dma_addr_t reply_fifo_phys_base_addr_buf[PS3_MAX_REPLY_QUE_COUNT]; + + struct ps3_irq *irqs; +#ifndef _WINDOWS + U32 *cpu_msix_table; + atomic_t high_iops_io_count; + S32 cpu_msix_table_sz; +#endif + + Bool is_enable_interrupts; + Bool is_support_balance; + Bool is_balance_current_perf_mode; + U8 pci_irq_type; + +#ifdef _WINDOWS + PGROUP_AFFINITY group_affinity; +#endif + struct ps3_irq_recovery * irq_recovery; +}; + +S32 ps3_irq_context_init(struct ps3_instance *instance); + +S32 ps3_irq_context_exit(struct ps3_instance *instance); + +S32 ps3_irqs_dpc_init(struct ps3_instance *instance); + +S32 ps3_irqs_init(struct ps3_instance *instance); + +S32 ps3_irqs_init_switch(struct ps3_instance *instance); + +void ps3_irqs_exit(struct ps3_instance *instance); +#ifndef _WINDOWS +U32 ps3_msix_index_get(struct ps3_cmd *cmd, U16 pd_count); + +void ps3_perf_update(struct ps3_instance *instance, U8 iocPerfMode); +#endif +void ps3_irqs_enable(struct ps3_instance *instance); + +void ps3_irqs_disable(struct ps3_instance *instance); +#ifndef _WINDOWS +void ps3_irqpolls_enable(struct ps3_instance *instance); + +void ps3_irqs_sync(struct ps3_instance *instance); +#endif +#ifndef _WINDOWS +irqreturn_t ps3_irqs_service(int irq_so, void *priv); +#else +U8 ps3_irqs_service(void *priv, ULong irq_no); +#endif + +#ifndef _WINDOWS +int ps3_irqpoll_service(struct irq_poll *irqpoll, int budget); +#endif +static inline Bool ps3_irq_busy_add(struct ps3_irq *irq) +{ + return ps3_atomic_add_unless(&irq->is_busy, 1, 1); +} + +static inline void ps3_irq_busy_dec(struct ps3_irq *irq) +{ + ps3_atomic_dec(&irq->is_busy); +} + +static inline Bool ps3_irq_is_enable(const struct ps3_irq_context *irq_ctx) +{ + return (irq_ctx->is_enable_interrupts == PS3_DRV_TRUE); +} + +void ps3_all_reply_fifo_init(struct ps3_instance *instance); + +#ifndef _WINDOWS +static inline void ps3_irq_poll_sched(struct irq_poll * iop) +{ +#ifdef CONFIG_IRQ_POLL + irq_poll_sched(iop); +#else + (void)iop; +#endif +} + +static inline void ps3_irq_poll_init(struct irq_poll *iop, int weight, irq_poll_fn *func) +{ +#ifdef CONFIG_IRQ_POLL + irq_poll_init(iop, weight, func); +#else + (void)iop; + (void)weight; + (void)func; +#endif +} + +static inline void ps3_irq_poll_complete(struct irq_poll * iop) +{ +#ifdef CONFIG_IRQ_POLL + irq_poll_complete(iop); +#else + (void)iop; +#endif +} + +static inline void ps3_irq_poll_enable(struct irq_poll * iop) +{ +#ifdef CONFIG_IRQ_POLL + irq_poll_enable(iop); +#else + (void)iop; +#endif +} + +static inline void ps3_irq_poll_disable(struct irq_poll * iop) +{ +#ifdef CONFIG_IRQ_POLL + irq_poll_disable(iop); +#else + (void)iop; +#endif +} +#endif +#endif diff --git a/drivers/scsi/ps3stor/ps3_load.c b/drivers/scsi/ps3stor/ps3_load.c new file mode 100644 index 0000000000000000000000000000000000000000..ed7c6308e05e588fb02adbf0fac3a1885079bfec --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_load.c @@ -0,0 +1,283 @@ + +#include "ps3_load.h" +#include "ps3_instance_manager.h" +#include "ps3_ioc_manager.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_mgr_cmd.h" +#include "ps3_cmd_channel.h" +#include "ps3_event.h" +#include "ps3_cmd_statistics.h" +#include "ps3_ioctl.h" + +#ifdef _WINDOWS + +static S32 ps3_init_ioc_prepare(struct ps3_instance *instance); +static void ps3_init_ioc_prepare_exit(struct ps3_instance *instance); +static S32 ps3_init_ioc_complete(struct ps3_instance *instance); +static void ps3_init_ioc_complete_exit(struct ps3_instance *instance); +static S32 ps3_pci_init_complete(struct ps3_instance *instance); +static void ps3_pci_init_complete_exit(struct ps3_instance *instance); + +S32 ps3_firmware_init(struct ps3_instance *instance) +{ + ps3_ioc_adp_init(instance); + + if (instance->ioc_adpter->ioc_init_state_to_ready(instance) != PS3_SUCCESS) { + goto l_failed; + } + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_READY); + + if (ps3_pci_init_complete(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_init_ioc_prepare(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (instance->ioc_adpter->ioc_init_proc(instance) != PS3_SUCCESS) { + goto l_failed; + } + ps3_atomic_set(&instance->state_machine.state, PS3_INSTANCE_STATE_PRE_OPERATIONAL); + + if (ps3_ctrl_info_get(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_init_ioc_complete(instance) != PS3_SUCCESS) { + goto l_failed; + } + + ps3_ioctl_init(instance, PS3_MAX_IOCTL_CMDS); + + return PS3_SUCCESS; + +l_failed: + DbgPrint("fireware init failed\n"); + ps3_firmware_exit(instance); + return -PS3_FAILED; +} + +void ps3_firmware_exit(struct ps3_instance *instance) +{ + ps3_pci_init_complete_exit(instance); + ps3_init_ioc_complete_exit(instance); + ps3_init_ioc_prepare_exit(instance); + + return; +} + +void ps3_remove(struct ps3_instance *instance) +{ + ULong flags = 0; + LOG_INFO("hno:%u ps3_remove\n", PS3_HOST(instance)); + + instance->state_machine.is_load = PS3_FALSE; + instance->ioc_adpter->irq_disable(instance); + + ps3_watchdog_stop(instance); + + ps3_recovery_context_exit(instance); + + ps3_event_unsubscribe(instance); + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + instance->event_context.abort_eventcmd = 0; + instance->dev_context.abort_vdpending_cmd = 0; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + ps3_dev_mgr_vd_info_unsubscribe(instance); + +#ifndef _WINDOWS + ps3_sas_device_data_exit(instance); +#endif + ps3_device_mgr_data_exit(instance); +#ifndef _WINDOWS + if (ps3_sas_is_support_smp(instance)) { + sas_remove_host(instance->host); + } + else { + scsi_remove_host(instance->host); + } +#else + ps3_device_unload_done(instance); +#endif + if (ps3_soc_unload(instance, PS3_FALSE, PS3_UNLOAD_SUB_TYPE_REMOVE, PS3_SUSPEND_TYPE_NONE) != PS3_SUCCESS) { + LOG_ERROR("hno:%u unload failed.\n", PS3_HOST(instance)); + if (ps3_ioc_hard_reset_to_ready(instance) != PS3_SUCCESS) { + LOG_ERROR("hno:%u hard reset failed.\n", PS3_HOST(instance)); + } + } + +#ifndef _WINDOWS + ps3_irqs_sync(instance); + ps3_irqpolls_enable(instance); +#endif + ps3_instance_state_transfer_to_quit(instance); + + ps3_firmware_exit(instance); + ps3_pci_exit(instance); +#ifndef _WINDOWS + pci_set_drvdata(instance->pdev, NULL); + ps3_instance_put(instance); + scsi_host_put(instance->host); + + ps3_dma_dump_mapping(pdev); +#endif + return; +} + +static void ps3_cmd_attr_context_init(struct ps3_instance *instance) +{ + U32 cmd_qdepth = 0; + instance->cmd_attr.cur_can_que = + instance->cmd_context.max_scsi_cmd_count - + instance->cmd_context.max_r1x_cmd_count; + +#ifndef _WINDOWS + + cmd_qdepth = ps3_throttle_qdepth_query(); + if ((cmd_qdepth != 0) && + cmd_qdepth <= instance->cmd_attr.cur_can_que) { + instance->cmd_attr.throttle_que_depth = cmd_qdepth; + } + else { + instance->cmd_attr.throttle_que_depth = + PS3_DEVICE_QDEPTH_DEFAULT_VALUE; + } +#else + instance->cmd_attr.throttle_que_depth = + PS3_DEVICE_QDEPTH_DEFAULT_VALUE; +#endif + + instance->cmd_attr.vd_io_threshold = 0; + instance->cmd_attr.is_support_direct_cmd = PS3_FALSE; +} + +static S32 ps3_init_ioc_prepare(struct ps3_instance *instance) +{ + ps3_ioc_mgr_req_queue_lock_init(instance); + ps3_err_fault_context_init(instance); + + if (!ps3_ioc_fw_version_get(instance)) { + goto l_fail; + } + + if (!ps3_ioc_state_halt_support_get(instance)) { + goto l_fail; + } + + if (!ps3_ioc_recovery_support_get(instance)) { + goto l_fail; + } + + if (ps3_recovery_context_init(instance) != PS3_SUCCESS) { + goto l_fail; + } + + if (ps3_ioc_init_cmd_context_init(instance) != PS3_SUCCESS) { + goto l_fail; + } + + if (ps3_ctrl_info_buf_alloc(instance) != PS3_SUCCESS) { + goto l_fail; + } + + if (ps3_cmd_context_init(instance) != PS3_SUCCESS) { + goto l_fail; + } + + ps3_cmd_attr_context_init(instance); + + if (ps3_event_context_init(instance) != PS3_SUCCESS) { + goto l_fail; + } + + if (ps3_cmd_statistics_init(instance) != PS3_SUCCESS) { + goto l_fail; + } + + if (ps3_dump_init(instance) != PS3_SUCCESS) { + goto l_fail; + } + + return PS3_SUCCESS; +l_fail: + ps3_init_ioc_prepare_exit(instance); + return -PS3_FAILED; +} + +static void ps3_init_ioc_prepare_exit(struct ps3_instance *instance) +{ + ps3_ioc_init_cmd_context_exit(instance); + ps3_err_fault_context_exit(instance); + ps3_ctrl_info_buf_free(instance); + ps3_cmd_statistics_exit(instance); + ps3_event_context_exit(instance); + ps3_recovery_context_exit(instance); + ps3_cmd_context_exit(instance); + ps3_dump_dma_buf_free(instance); + ps3_dump_exit(instance); +#ifndef _WINDOWS + (void)ps3_debug_mem_free(instance); +#endif +} + +static S32 ps3_init_ioc_complete(struct ps3_instance *instance) +{ + if (ps3_mgr_cmd_init(instance) != PS3_SUCCESS) { + goto l_failed; + } + + if (ps3_device_mgr_init(instance) != PS3_SUCCESS) { + goto l_failed; + } +#ifndef _WINDOWS + if (ps3_sas_device_mgr_init(instance) != PS3_SUCCESS) { + goto l_failed; + } +#endif + return PS3_SUCCESS; +l_failed: + ps3_init_ioc_complete_exit(instance); + return -PS3_FAILED; +} + +static void ps3_init_ioc_complete_exit(struct ps3_instance *instance) +{ +#ifndef _WINDOWS + ps3_sas_device_mgr_exit(instance); +#endif + ps3_device_mgr_exit(instance); + ps3_mgr_cmd_exit(instance); + + return; +} + +static S32 ps3_pci_init_complete(struct ps3_instance *instance) +{ + if (ps3_irq_context_init(instance) != PS3_SUCCESS) { + goto l_failed; + } + if (instance->ioc_adpter->irq_init) { + if (instance->ioc_adpter->irq_init(instance) != PS3_SUCCESS) { + goto l_failed; + } + } else { + if (ps3_irqs_init(instance) != PS3_SUCCESS) { + goto l_failed; + } + } + + return PS3_SUCCESS; + +l_failed: + ps3_pci_init_complete_exit(instance); + return -PS3_FAILED; +} + +static void ps3_pci_init_complete_exit(struct ps3_instance *instance) +{ + ps3_irqs_exit(instance); + ps3_irq_context_exit(instance); +} + +#endif diff --git a/drivers/scsi/ps3stor/ps3_load.h b/drivers/scsi/ps3stor/ps3_load.h new file mode 100644 index 0000000000000000000000000000000000000000..fc5ace49222d9dc4f2e26ff24ee42a600220e60d --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_load.h @@ -0,0 +1,19 @@ + +#ifndef _PS3_LOAD_H_ +#define _PS3_LOAD_H_ + +#ifdef _WINDOWS + +#include "ps3_def.h" + +struct ps3_instance; + +S32 ps3_firmware_init(struct ps3_instance *instance); + +void ps3_firmware_exit(struct ps3_instance *instance); + +void ps3_remove(struct ps3_instance *instance); + +#endif +#endif + diff --git a/drivers/scsi/ps3stor/ps3_mgr_channel.c b/drivers/scsi/ps3stor/ps3_mgr_channel.c new file mode 100644 index 0000000000000000000000000000000000000000..bd20a4b1b80010fa26ac80e9dacd7d73698992be --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_mgr_channel.c @@ -0,0 +1,421 @@ + +#ifdef _WINDOWS +#include "ps3_def.h" + +#else + +#define WINDOWS_DELAY + +#include +#include +#include +#include +#include +#include + +#include "ps3_scsih.h" +#include "ps3_scsih_cmd_parse.h" +#endif + +#include "ps3_htp.h" +#include "ps3_mgr_channel.h" +#include "ps3_cmd_complete.h" +#include "ps3_platform_utils.h" +#include "ps3_util.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_mgr_cmd.h" +#include "ps3_cmd_complete.h" +#include "ps3_ioc_manager.h" +#include "ps3_driver_log.h" +#include "ps3_instance_manager.h" +#include "ps3_cmd_statistics.h" +#include "ps3_err_inject.h" + +#ifndef _WINDOWS +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(4,9,0) || LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)) +#include +#else +#include +#endif +#endif + +#define CMD_MAX_RETRY_COUNT (10) + +#define SEND_IOCTL_CMD_CHECK(instance, cmd) ((PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_IOCTL)\ + && (instance)->is_support_irq) + +static inline Bool is_interrupt_signal(struct task_struct *p) +{ + if (sigismember(&p->pending.signal, SIGINT) || + sigismember(&p->pending.signal, SIGKILL) || + sigismember(&p->pending.signal, SIGQUIT)) { + return PS3_TRUE; + } + return PS3_FALSE; +} + +void ps3_wait_cmd_for_completion_interrupt(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + ULong flags = 0; + Bool is_send_cancel = PS3_FALSE; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + S32 retry_count = 0; + + while(1) { + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_FORCE_DONE, cmd) + ret = wait_for_completion_interruptible(&cmd->sync_done); + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_INTERRUPT, &ret) + if (ret == PS3_SUCCESS) { + LOG_DEBUG("host_no:%u wait_for_completion_interrupted success\n", + PS3_HOST(instance)); + if((cmd->resp_frame->normalRespFrame.respStatus == PS3_DRV_MGR_BUSY) && is_send_cancel) { + cmd->resp_frame->normalRespFrame.respStatus = PS3_MGR_REC_FORCE; + } + break; + } + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + + ret = signal_pending(current); + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_PENDING, &ret) + if(!ret) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + continue; + } + ret = is_interrupt_signal(current); + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_SIG_INTERRUPT, &ret) + if (ret) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_QUIT || + cur_state == PS3_INSTANCE_STATE_DEAD) { + LOG_INFO_IN_IRQ(instance, "host_no:%u cur_state:%s\n", + PS3_HOST(instance),namePS3InstanceState(cur_state)); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + break; + } + + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + LOG_INFO_LIM("host_no:%u wait_for_completion_interrupted by SIG INT OR KILL, QUIT\n", + PS3_HOST(instance)); + if(is_send_cancel) { + ps3_msleep(100); + continue; + } + is_send_cancel = PS3_TRUE; +cancel: + ret = ps3_mgr_cmd_cancel(instance, cmd->index); + INJECT_START(PS3_ERR_IJ_FORCE_CANCEL_CMD_RET_RECOVERY, &ret); + INJECT_START(PS3_ERR_IJ_FORCE_CANCEL_CMD_PCIE_ERR, &ret); + if (ret != PS3_SUCCESS) { + if (ret == -PS3_RECOVERED) { + LOG_INFO_LIM("host_no:%u cancel cmd %u send failed, wait\n", + PS3_HOST(instance), cmd->index); + continue; + } else if(ret == -PS3_EBUSY) { + if(retry_count++ < CMD_MAX_RETRY_COUNT) { + ps3_msleep(100); + goto cancel; + } + continue; + } + LOG_INFO("host_no:%u cancel cmd %u failed, QUIT, ret:%d\n", + PS3_HOST(instance), cmd->index, ret); + } else { + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + break; + } else { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + } + + return ; +} + +static S32 ps3_mgr_cmd_send(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + if (!instance->state_machine.is_load) { + if (PS3_MGR_CMD_TYPE(cmd) != PS3_CMD_MANAGEMENT){ + LOG_WARN("host_no:%u instance state is unloading or suspend\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + } + INJECT_START(PS3_ERR_IJ_IOCTL_WAIT_UNNORMAL, instance) + INJECT_START(PS3_ERR_IJ_FORCE_INSTANCE_UNNORMAL, instance) + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + LOG_WARN("host_no:%u cannot send block cmd\n", PS3_HOST(instance)); + ret = -PS3_RECOVERED; + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_IOCTL) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_QUIT || + cur_state == PS3_INSTANCE_STATE_DEAD) { + LOG_WARN("host_no:%u cur_state:%s\n", PS3_HOST(instance),namePS3InstanceState(cur_state)); + goto l_out; + } + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_BUSY; + LOG_WARN("host_no:%u ioctl cannot send block cmd:%u,resp:%d, will retry\n", + PS3_HOST(instance), cmd->index, cmd->resp_frame->normalRespFrame.respStatus); + ret = -PS3_RESP_ERR; + } + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_PCI_ERR_RECOVERY, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("host_no:%u cannot send block cmd due to pci recovery\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + PS3_MGR_CMD_STAT_INC(instance, cmd); + + LOG_FILE_INFO("host_no:%u CFID:%d trace_id:0x%llx ready send\n", + PS3_HOST(instance), cmd->cmd_word.cmdFrameID, cmd->trace_id); + LOG_DEBUG("host_no:%u req cmd info:\n" + "\t reqFrameBufBase = 0x%llx, function = %d\n", + PS3_HOST(instance), + cpu_to_le64(instance->cmd_context.req_frame_buf_phys), + ps3_get_pci_function(instance->pdev)); + + instance->ioc_adpter->cmd_send(instance, &cmd->cmd_word); +l_out: + return ret; +} +static S32 ps3_blocked_unload_cmd_send(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + PS3_MGR_CMD_STAT_INC(instance, cmd); + + instance->ioc_adpter->cmd_send(instance, &cmd->cmd_word); + ret = ps3_block_cmd_wait(instance, cmd, 0); + INJECT_START(PS3_ERR_IJ_UNLOAD_TIMEOUT, &ret) + LOG_INFO("host_no:%u CFID:%d trace_id:0x%llx ret:%d\n", + PS3_HOST(instance), cmd->cmd_word.cmdFrameID, cmd->trace_id, ret); + return ret; +} + +static S32 ps3_blocked_cmd_wake(struct ps3_cmd *cmd) +{ + ULong flags = 0; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_DEAD) { + LOG_WARN_IN_IRQ(cmd->instance, + "host_no:%u CFID:%d trace_id:0x%llx dead free\n", + PS3_HOST(cmd->instance), cmd->index, cmd->trace_id); + + PS3_MGR_CMD_BACK_INC(cmd->instance, cmd, 0); + ps3_mgr_cmd_free_nolock(cmd->instance, cmd); + goto l_out; + } + + if (cmd->cmd_state.state == PS3_CMD_STATE_PROCESS) { + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + + complete(&cmd->sync_done); + INJECT_START(PS3_ERR_IJ_IGNORE_TASK_ABORT, cmd); + + PS3_MGR_CMD_BACK_INC(cmd->instance, cmd, 0); + } else { + LOG_ERROR_IN_IRQ(cmd->instance, + "host_no:%u CFID:%d trace_id:0x%llx repeat reply\n", + PS3_HOST(cmd->instance), cmd->index, cmd->trace_id); + } + +l_out: + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + return PS3_SUCCESS; +} + +static S32 ps3_polled_cmd_send(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + if (!instance->state_machine.is_load) { + if (PS3_MGR_CMD_TYPE(cmd) != PS3_CMD_MANAGEMENT){ + LOG_WARN("host_no:%u instance state is unloading or suspend\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + } + INJECT_START(PS3_ERR_IJ_FORCE_INSTANCE_UNNORMAL, instance); + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + ret = -PS3_RECOVERED; + goto l_out; + } + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("host_no:%u cannot send block cmd due to pci recovery\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + PS3_MGR_CMD_STAT_INC(instance, cmd); + instance->ioc_adpter->cmd_send(instance, &cmd->cmd_word); +l_out: + return ret; +} +static S32 ps3_polled_unload_cmd_send(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = -PS3_FAILED; + + PS3_MGR_CMD_STAT_INC(instance, cmd); + instance->ioc_adpter->cmd_send(instance, &cmd->cmd_word); + + ret = ps3_cmd_reply_polling(instance, cmd, 0, PS3_TRUE); + INJECT_START(PS3_ERR_IJ_UNLOAD_TIMEOUT, &ret) + if (ret != -PS3_TIMEOUT) { + PS3_MGR_CMD_BACK_INC(instance, cmd, (ret == PS3_SUCCESS) ? + PS3_REPLY_WORD_FLAG_SUCCESS : PS3_REPLY_WORD_FLAG_FAIL); + } + return ret; +} + +static S32 ps3_blocked_cmd_cb(struct ps3_cmd *cmd, U16 reply_flags) +{ + if((cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NEED_REPLY_WORD) + && (reply_flags == PS3_REPLY_WORD_FLAG_SUCCESS)) { + cmd->resp_frame->normalRespFrame.respStatus = SCSI_STATUS_GOOD; + } + + return ps3_blocked_cmd_wake(cmd); +} + +S32 ps3_cmd_send_sync(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + if ((cmd->is_force_polling == 0 && ps3_irq_is_enable(&cmd->instance->irq_context)) + || SEND_IOCTL_CMD_CHECK(instance, cmd)){ + INJECT_START(PS3_ERR_IJ_SEND_IOCTL_BLOCK_MODE_FLAG, cmd); + cmd->cmd_receive_cb = ps3_blocked_cmd_cb; + cmd->req_frame->mgrReq.reqHead.noReplyWord = PS3_CMD_WORD_NEED_REPLY_WORD; + return ps3_mgr_cmd_send(instance, cmd); + } else { + cmd->cmd_receive_cb = NULL; + cmd->req_frame->mgrReq.reqHead.noReplyWord = PS3_CMD_WORD_NO_REPLY_WORD; + return ps3_polled_cmd_send(instance, cmd); + } +} + +S32 ps3_cmd_wait_sync(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + if (cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NEED_REPLY_WORD) { + INJECT_START(PS3_ERR_IJ_ABORT_CMD_ERROR ,cmd); + INJECT_START(PS3_ERR_IJ_RESET_CMD_ERROR ,cmd); + INJECT_START(PS3_ERR_IJ_ABORT_CMD_NORMAL ,cmd); + INJECT_START(PS3_ERR_IJ_RESET_CMD_NORMAL ,cmd); + INJECT_START(PS3_ERR_IJ_SMP_CMD_ERROR ,cmd); + INJECT_START(PS3_ERR_IJ_GET_LINKERRORS_CMD_ERROR ,cmd); + INJECT_START(PS3_ERR_IJ_PHY_CTRL_CMD_ERROR ,cmd); + INJECT_START(PS3_ERR_IJ_PD_LIST_RESP_RETRY, cmd); + ret = ps3_block_cmd_wait(instance, cmd, 0); + INJECT_START(PS3_ERR_IJ_PD_LIST_CMD_NO_RESP, &ret); + } else { + INJECT_START(PS3_ERR_IJ_ABORT_CMD_ERROR, cmd); + INJECT_START(PS3_ERR_IJ_RESET_CMD_ERROR, cmd); + INJECT_START(PS3_ERR_IJ_ABORT_CMD_NORMAL, cmd); + INJECT_START(PS3_ERR_IJ_RESET_CMD_NORMAL, cmd); + ret = ps3_cmd_reply_polling(instance, cmd, 0, PS3_FALSE); + if (ret != -PS3_TIMEOUT) { + PS3_MGR_CMD_BACK_INC(instance, cmd, (ret == PS3_SUCCESS) ? + PS3_REPLY_WORD_FLAG_SUCCESS : PS3_REPLY_WORD_FLAG_FAIL); + } + } + LOG_FILE_INFO("host_no:%u CFID:%d trace_id:0x%llx recv ret:%d\n", + PS3_HOST(instance), cmd->cmd_word.cmdFrameID, cmd->trace_id, ret); + return ret; +} + +S32 ps3_unload_cmd_send_sync(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + if (cmd->is_force_polling == 0 && + ps3_irq_is_enable(&cmd->instance->irq_context)) { + cmd->cmd_receive_cb = ps3_blocked_cmd_cb; + cmd->req_frame->mgrReq.reqHead.noReplyWord = PS3_CMD_WORD_NEED_REPLY_WORD; + return ps3_blocked_unload_cmd_send(instance, cmd); + } else { + cmd->cmd_receive_cb = NULL; + cmd->req_frame->mgrReq.reqHead.noReplyWord = PS3_CMD_WORD_NO_REPLY_WORD; + return ps3_polled_unload_cmd_send(instance, cmd); + } +} + +S32 ps3_cmd_no_block_send(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + cmd->cmd_receive_cb = ps3_blocked_cmd_cb; + cmd->req_frame->mgrReq.reqHead.noReplyWord = PS3_CMD_WORD_NEED_REPLY_WORD; + + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + PS3_MGR_CMD_STAT_INC(instance, cmd); + + instance->ioc_adpter->cmd_send(instance, &cmd->cmd_word); +l_out: + return ret; +} + +S32 ps3_block_cmd_wait(struct ps3_instance *instance, struct ps3_cmd *cmd, ULong timeout) +{ + S32 ret = PS3_SUCCESS; + + if (cmd->is_interrupt) { +#ifdef WINDOWS_DELAY + ps3_wait_cmd_for_completion_interrupt(instance, cmd); +#endif + } else { + ret = ps3_wait_cmd_for_completion_timeout(instance, cmd, timeout); + if (ret == -PS3_TIMEOUT) { + LOG_ERROR("host_no:%u CFID:%d trace_id:0x%llx time out\n", + PS3_HOST(instance), + cmd->cmd_word.cmdFrameID, cmd->trace_id); + goto l_out; + } + } + + if (cmd->cmd_state.state != PS3_CMD_STATE_COMPLETE) { + LOG_INFO("host_no:%u CFID:%d trace_id:0x%llx not complete,state:%u\n", + PS3_HOST(instance), + cmd->cmd_word.cmdFrameID, cmd->trace_id, cmd->cmd_state.state); + ret = -PS3_TIMEOUT; + goto l_out; + } + + if (ps3_cmd_resp_status(cmd) != SCSI_STATUS_GOOD) { + ret = -PS3_RESP_ERR; + LOG_INFO("host_no:%u CFID:%d trace_id:0x%llx resp err:0x%x\n", + PS3_HOST(instance), + cmd->cmd_word.cmdFrameID, cmd->trace_id, + ps3_cmd_resp_status(cmd)); + } +l_out: + return ret; +} + +S32 ps3_cmd_send_async(struct ps3_instance *instance, struct ps3_cmd *cmd, + S32 (*cmd_receive_cb)(struct ps3_cmd *, U16)) +{ + cmd->cmd_receive_cb = cmd_receive_cb; + PS3_MGR_CMD_STAT_INC(instance, cmd); + return ps3_async_cmd_send(instance, cmd); +} diff --git a/drivers/scsi/ps3stor/ps3_mgr_channel.h b/drivers/scsi/ps3stor/ps3_mgr_channel.h new file mode 100644 index 0000000000000000000000000000000000000000..2b407a6e11b4f8e2c1ad9e500b2daff5bad9713c --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_mgr_channel.h @@ -0,0 +1,28 @@ + +#ifndef _PS3_MGR_CHANNEL_H_ +#define _PS3_MGR_CHANNEL_H_ + +#include "ps3_cmd_channel.h" + +S32 ps3_cmd_send_sync(struct ps3_instance *instance, struct ps3_cmd *cmd); +S32 ps3_unload_cmd_send_sync(struct ps3_instance *instance, struct ps3_cmd *cmd); +S32 ps3_block_cmd_wait(struct ps3_instance *instance, struct ps3_cmd *cmd, ULong timeout); +S32 ps3_cmd_send_async(struct ps3_instance *instance, struct ps3_cmd *cmd, +S32 (*cmd_receive_cb)(struct ps3_cmd *, U16)); + +S32 ps3_cmd_wait_sync(struct ps3_instance *instance, struct ps3_cmd *cmd); + +S32 ps3_cmd_no_block_send(struct ps3_instance *instance, struct ps3_cmd *cmd); + +#ifndef _WINDOWS +void ps3_wait_cmd_for_completion_interrupt(struct ps3_instance *instance, struct ps3_cmd *cmd); +#endif + +static inline PS3RespFrame_u * ps3_cmd_resp_frame_get(struct ps3_cmd *cmd){ + return cmd->resp_frame; +} +static inline U32 ps3_cmd_resp_status(struct ps3_cmd *cmd){ + return le32_to_cpu(cmd->resp_frame->normalRespFrame.respStatus); +}; + +#endif diff --git a/drivers/scsi/ps3stor/ps3_mgr_cmd.c b/drivers/scsi/ps3stor/ps3_mgr_cmd.c new file mode 100644 index 0000000000000000000000000000000000000000..ea6e64a67312f2a09f8c13d40ce29b510b37e618 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_mgr_cmd.c @@ -0,0 +1,2027 @@ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#endif + +#include "ps3_mgr_cmd.h" +#include "ps3_event.h" +#include "ps3_device_update.h" +#include "ps3_device_manager.h" +#include "ps3_cmd_complete.h" +#include "ps3_mgr_channel.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_scsih.h" +#include "ps3_util.h" +#include "ps3_ioc_manager.h" +#include "ps3_err_inject.h" +#include "ps3_ioc_state.h" +#include "ps3_ioctl.h" + +static S32 ps3_mgr_cmd_sync_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd, U16 time_out); + +S32 ps3_ctrl_info_buf_alloc(struct ps3_instance *instance) +{ + instance->ctrl_info_buf = (struct PS3IocCtrlInfo *) + ps3_dma_alloc_coherent(instance, sizeof(struct PS3IocCtrlInfo), + &instance->ctrl_info_buf_h); + + if (instance->ctrl_info_buf == NULL) { + LOG_ERROR("host_no:%u alloc ctrl info buffer failed !\n", + PS3_HOST(instance)); + goto l_fail; + } + return PS3_SUCCESS; +l_fail: + return -PS3_ENOMEM; +} + +void ps3_ctrl_info_buf_free(struct ps3_instance *instance) +{ + if (instance->ctrl_info_buf != NULL) { + LOG_INFO("ctrl_info_buf = %p\n", instance->ctrl_info_buf); + ps3_dma_free_coherent(instance, sizeof(struct PS3IocCtrlInfo), + instance->ctrl_info_buf, + instance->ctrl_info_buf_h); + instance->ctrl_info_buf = NULL; + } + + memset(&instance->ctrl_info, 0, sizeof(struct PS3IocCtrlInfo)); +} + +static S32 ps3_mgr_pd_list_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dev_context *dev_context = &instance->dev_context; + + dev_context->pd_list_buf = (struct PS3DevList *) + ps3_dma_alloc_coherent(instance, + PS3_MAX_PD_COUNT(instance) * + sizeof(struct PS3PhyDevice) + sizeof(struct PS3DevList), + &dev_context->pd_list_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_PD_LIST_BUF_ALLOC, &dev_context->pd_list_buf); + if (dev_context->pd_list_buf == NULL) { + LOG_ERROR("host_no:%u alloc pd list buffer failed !\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + } + + return ret; +} + +static S32 ps3_mgr_vd_list_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dev_context *dev_context = &instance->dev_context; + + dev_context->vd_list_buf = (struct PS3DevList *) + ps3_dma_alloc_coherent(instance, + PS3_MAX_VD_COUNT(instance) * + sizeof(struct PS3VirtDevice) + sizeof(struct PS3DevList), + &dev_context->vd_list_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_VD_LIST_BUF_ALLOC, &dev_context->vd_list_buf); + if (dev_context->vd_list_buf == NULL) { + LOG_ERROR("host_no:%u alloc vd list buffer failed !\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + } + return ret; +} + +static S32 ps3_mgr_pd_info_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dev_context *dev_context = &instance->dev_context; + + dev_context->pd_info_buf = (struct PS3PDInfo *) + ps3_dma_alloc_coherent(instance, sizeof(struct PS3PDInfo), + &dev_context->pd_info_buf_phys); + INJECT_START(PS3_ERR_IJ_PS3_PD_INFO_BUF_ALLOC, &dev_context->pd_info_buf); + if (dev_context->pd_info_buf == NULL) { + LOG_ERROR("host_no:%u alloc pd info buffer failed !\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + } + return ret; +} + +static inline void ps3_mgr_pd_list_exit(struct ps3_instance *instance) +{ + struct ps3_dev_context *dev_context = &instance->dev_context; + + if (dev_context->pd_list_buf != NULL) { + ps3_dma_free_coherent(instance, + PS3_MAX_PD_COUNT(instance) * + sizeof(struct PS3PhyDevice) + + sizeof(struct PS3DevList), + dev_context->pd_list_buf, + dev_context->pd_list_buf_phys); + dev_context->pd_list_buf = NULL; + } +} + +static inline void ps3_mgr_vd_list_exit(struct ps3_instance *instance) +{ + struct ps3_dev_context *dev_context = &instance->dev_context; + + if (dev_context->vd_list_buf != NULL) { + ps3_dma_free_coherent(instance, + PS3_MAX_VD_COUNT(instance) * + sizeof(struct PS3VirtDevice) + + sizeof(struct PS3DevList), + dev_context->vd_list_buf, + dev_context->vd_list_buf_phys); + dev_context->vd_list_buf = NULL; + } +} + +static inline void ps3_mgr_pd_info_exit(struct ps3_instance *instance) +{ + struct ps3_dev_context *dev_context = &instance->dev_context; + + if (dev_context->pd_info_buf != NULL) { + ps3_dma_free_coherent(instance, sizeof(struct PS3PDInfo), + dev_context->pd_info_buf, + dev_context->pd_info_buf_phys); + dev_context->pd_info_buf = NULL; + } +} + +static inline void ps3_mgr_vd_info_exit(struct ps3_instance *instance) +{ + struct ps3_dev_context *dev_context = &instance->dev_context; + + if (dev_context->vd_info_buf_sync != NULL) { + ps3_dma_free_coherent(instance, PS3_MAX_VD_COUNT(instance) + * sizeof(struct PS3VDEntry) + + sizeof(struct PS3VDInfo), + dev_context->vd_info_buf_sync, + dev_context->vd_info_buf_phys_sync); + dev_context->vd_info_buf_sync = NULL; + } + + if (dev_context->vd_info_buf_async != NULL) { + ps3_dma_free_coherent(instance, PS3_MAX_VD_COUNT(instance) + * sizeof(struct PS3VDEntry) + + sizeof(struct PS3VDInfo), + dev_context->vd_info_buf_async, + dev_context->vd_info_buf_phys_async); + dev_context->vd_info_buf_async = NULL; + } + +} + +static S32 ps3_mgr_vd_info_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_dev_context *dev_context = &instance->dev_context; + + dev_context->vd_table_idx = 0; + dev_context->vd_info_buf_sync = (struct PS3VDInfo *) + ps3_dma_alloc_coherent(instance, + PS3_MAX_VD_COUNT(instance) * sizeof(struct PS3VDEntry) + + sizeof(struct PS3VDInfo), + &dev_context->vd_info_buf_phys_sync); + INJECT_START(PS3_ERR_IJ_PS3_VD_INFO_BUF_SYNC_ALLOC, &dev_context->vd_info_buf_sync); + if (dev_context->vd_info_buf_sync == NULL) { + LOG_ERROR("host_no:%u alloc vd sync info buffer failed !\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_out; + } + + dev_context->vd_info_buf_async = (struct PS3VDInfo *) + ps3_dma_alloc_coherent(instance, + PS3_MAX_VD_COUNT(instance) * sizeof(struct PS3VDEntry) + + sizeof(struct PS3VDInfo), + &dev_context->vd_info_buf_phys_async); + INJECT_START(PS3_ERR_IJ_PS3_VD_INFO_BUF_ASYNC_ALLOC, &dev_context->vd_info_buf_async); + if (dev_context->vd_info_buf_async == NULL) { + LOG_ERROR("host_no:%u alloc vd async info buffer failed !\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_failed; + } + + return ret; + +l_failed: + ps3_mgr_vd_info_exit(instance); +l_out: + return ret; +} + +S32 ps3_mgr_cmd_init(struct ps3_instance *instance) +{ + LOG_INFO("host_no:%u, Soc VD max is:%d\n", PS3_HOST(instance), + PS3_MAX_VD_COUNT(instance)); + LOG_INFO("host_no:%u, Soc PD max is:%d\n", PS3_HOST(instance), + PS3_MAX_PD_COUNT(instance)); + + if (PS3_MAX_PD_COUNT(instance) > 0) { + if (ps3_mgr_pd_list_init(instance) != PS3_SUCCESS) { + goto free_mgr_cmd; + } + + if (ps3_mgr_pd_info_init(instance) != PS3_SUCCESS) { + goto free_mgr_cmd; + } + } + + if (PS3_MAX_VD_COUNT(instance) > 0) { + if (ps3_mgr_vd_list_init(instance) != PS3_SUCCESS) { + goto free_mgr_cmd; + } + + if (ps3_mgr_vd_info_init(instance) != PS3_SUCCESS) { + goto free_mgr_cmd; + } + } + + return PS3_SUCCESS; + +free_mgr_cmd: + ps3_mgr_cmd_exit(instance); + return -PS3_ENOMEM; +} + +void ps3_mgr_cmd_exit(struct ps3_instance *instance) +{ + ps3_mgr_pd_list_exit(instance); + ps3_mgr_vd_list_exit(instance); + ps3_mgr_pd_info_exit(instance); + ps3_mgr_vd_info_exit(instance); + + return ; +} + +void ps3_mgr_cmd_word_build(struct ps3_cmd *cmd) +{ + struct PS3CmdWord *cmd_word = &cmd->cmd_word; + memset(cmd_word, 0, sizeof(*cmd_word)); + + cmd_word->type = PS3_CMDWORD_TYPE_MGR; + cmd_word->direct = PS3_CMDWORD_DIRECT_NORMAL; + cmd_word->cmdFrameID = ps3_cmd_frame_id(cmd); +#ifndef _WINDOWS + cmd_word->isrSN = ps3_msix_index_get(cmd, 1); +#else + cmd_word->isrSN = 0; +#endif +} + +static void ps3_mgr_print_cmd(struct ps3_cmd *cmd, const S8 *cmd_type, Bool is_send) +{ + LOG_DEBUG("host_no:%u t_id:0x%llx mgr:%s:%s cmd word type:%d " + "direct:%d qmask:0x%x CFID:%d isr_sn:%d vid:%d pid:%d function:%d\n", + PS3_HOST(cmd->instance), cmd->trace_id, + (is_send) ? "send" : "recv", cmd_type, + cmd->cmd_word.type, cmd->cmd_word.direct, + cmd->cmd_word.qMask, cmd->cmd_word.cmdFrameID, + cmd->cmd_word.isrSN, cmd->cmd_word.virtDiskID, + cmd->cmd_word.phyDiskID, ps3_get_pci_function(cmd->instance->pdev)); +} + +static inline void ps3_mgr_req_head_init(struct ps3_cmd *cmd, + PS3ReqFrameHead_s *req_header, U8 cmdSubType) +{ + req_header->timeout = PS3_DEFAULT_MGR_CMD_TIMEOUT; + req_header->traceID = ps3_cmd_trace_id(cmd); + req_header->cmdType = PS3_CMD_MANAGEMENT; + req_header->cmdSubType = cmdSubType; + req_header->cmdFrameID = ps3_cmd_frame_id(cmd); + req_header->control = 0; + req_header->reqFrameFormat = PS3_REQFRAME_FORMAT_FRONTEND; + req_header->noReplyWord = PS3_CMD_WORD_NEED_REPLY_WORD; +} + +static inline void ps3_mgr_req_frame_sge_build(PS3MgrReqFrame_s *mgr_req_frame, + dma_addr_t dma_addr, U32 dma_len) +{ + struct PS3Sge *p_sge = mgr_req_frame->sgl; + + mgr_req_frame->sgeOffset = offsetof(PS3MgrReqFrame_s, sgl) >> PS3_MGR_CMD_SGL_OFFSET_DWORD_SHIFT; + mgr_req_frame->sgeCount = 1; + + p_sge->addr = cpu_to_le64(dma_addr); + p_sge->length = cpu_to_le32(dma_len); + p_sge->lastSge = 1; + p_sge->ext = 0; +} + +static S32 ps3_mgr_unload_cmd_send(struct ps3_cmd *cmd, U16 time_out) +{ + S32 ret = PS3_SUCCESS; + enum PS3MgrCmdSubType cmd_type = + (enum PS3MgrCmdSubType)cmd->req_frame->mgrReq.reqHead.cmdSubType; + + ps3_mgr_cmd_word_build(cmd); + cmd->time_out = time_out; + cmd->is_interrupt = PS3_DRV_FALSE; + ps3_mgr_print_cmd(cmd, namePS3MgrCmdSubType(cmd_type), PS3_DRV_TRUE); + ret = ps3_unload_cmd_send_sync(cmd->instance, cmd); + ps3_mgr_print_cmd(cmd, namePS3MgrCmdSubType(cmd_type), PS3_DRV_FALSE); + + if (ret == PS3_SUCCESS) { + LOG_INFO("host_no:%u send %s success\n", PS3_HOST(cmd->instance), + namePS3MgrCmdSubType(cmd_type)); + } else { + LOG_ERROR("host_no:%u send %s %s respStatus:%d\n", PS3_HOST(cmd->instance), + namePS3MgrCmdSubType(cmd_type), + (ret == -PS3_TIMEOUT) ? "timeout" : "failed", + ps3_cmd_resp_status(cmd)); + } + + return ret; +} + +S32 ps3_pd_list_get(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + U32 pd_list_size = PS3_MAX_PD_COUNT(instance) * + sizeof(struct PS3PhyDevice) + sizeof(struct PS3DevList); + + LOG_INFO("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u pd list cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_MGR_CMD_ALLOC_FAILED, &cmd) + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(instance->dev_context.pd_list_buf, 0, pd_list_size); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_GET_PD_LIST); + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->value.dev.devID.diskDev.diskID = 0; + mgr_req_frame->value.dev.num = PS3_MAX_PD_COUNT(instance); + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + instance->dev_context.pd_list_buf_phys, + pd_list_size); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_GET_PD_LIST), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + + LOG_INFO("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_vd_list_get(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + U32 vd_list_size = PS3_MAX_VD_COUNT(instance) * + sizeof(struct PS3VirtDevice) + sizeof(struct PS3DevList); + + LOG_INFO("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u vd list cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(instance->dev_context.vd_list_buf, 0, vd_list_size); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_GET_VD_LIST); + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->value.dev.devID.diskDev.diskID = 0; + mgr_req_frame->value.dev.num = PS3_MAX_VD_COUNT(instance); + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + instance->dev_context.vd_list_buf_phys, + vd_list_size); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_GET_VD_LIST), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + LOG_INFO("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_pd_info_get(struct ps3_instance *instance, U16 channel, U16 target_id, U16 pd_disk_id) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + U32 pd_info_size = sizeof(struct PS3PDInfo); + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u pd info cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(instance->dev_context.pd_info_buf, 0, pd_info_size); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_GET_PD_INFO); + + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + + mgr_req_frame->value.dev.num = 1; + mgr_req_frame->value.dev.devID.diskDev.ps3Dev.softChan = channel; + mgr_req_frame->value.dev.devID.diskDev.ps3Dev.devID = target_id; + mgr_req_frame->value.dev.devID.diskDev.ps3Dev.phyDiskID = pd_disk_id; + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + instance->dev_context.pd_info_buf_phys, + pd_info_size); + + LOG_INFO("host_no:%u ready send, reqFrameId=%d, [%d:%d:%d]!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), channel, target_id, + pd_disk_id); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_GET_PD_INFO), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + LOG_INFO("host_no:%u get pd info [%d:%d:%d] finished!:ret = %d\n", + PS3_HOST(instance), channel, target_id, pd_disk_id, ret); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + + INJECT_START(PS3_ERR_IJ_GET_PD_INFO_RETURN_FAILED, &ret); + + LOG_DEBUG("host_no:%u exit ret[%d]!\n", PS3_HOST(instance), ret); + return ret; +} + +S32 ps3_vd_info_sync_get(struct ps3_instance *instance, U32 disk_id, + U16 vd_num) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + U32 vd_info_size = PS3_MAX_VD_COUNT(instance) * + sizeof(struct PS3VDEntry) + sizeof(struct PS3VDInfo); + struct ps3_dev_context *dev_context = &instance->dev_context; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u vd info sync cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(dev_context->vd_info_buf_sync, 0, vd_info_size); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_GET_VD_INFO); + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->value.dev.devID.diskDev.diskID = disk_id; + mgr_req_frame->value.dev.num = vd_num; + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + dev_context->vd_info_buf_phys_sync, + vd_info_size); + + LOG_INFO("host_no:%u ready send, reqFrameId=%d, disk_id=0x%x, num=%d !\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), disk_id, vd_num); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_GET_VD_INFO), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + LOG_INFO("host_no:%u get vd info, reqFrameId=%d, disk_id=0x%x, num=%d finish!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), disk_id, vd_num); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_vd_info_async_get(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + U32 vd_info_size = PS3_MAX_VD_COUNT(instance) * + sizeof(struct PS3VDEntry) + sizeof(struct PS3VDInfo); + struct ps3_dev_context *dev_context = &instance->dev_context; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + + cmd = dev_context->vd_pending_cmd; + if (cmd == NULL) { + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_PS3_VD_PENDING_CMD_ALLOC, &cmd); + if (cmd == NULL) { + LOG_FILE_ERROR("host_no:%u mgr cmd get failed !\n", + PS3_HOST(instance)); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(dev_context->vd_info_buf_async, + 0, vd_info_size); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_GET_VD_INFO); + mgr_req_frame->reqHead.timeout = 0; + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 0; + mgr_req_frame->pendingFlag = 1; + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + dev_context->vd_info_buf_phys_async, + vd_info_size); + + ps3_vd_pending_filter_table_build((U8*) + dev_context->vd_info_buf_async); + + ps3_mgr_cmd_word_build(cmd); + LOG_FILE_INFO("host_no:%u ready send, reqFrameId=%d, t_id:0x%llx!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cmd->trace_id); + ps3_mgr_print_cmd(cmd, "vd info async", PS3_DRV_TRUE); + dev_context->vd_pending_cmd = cmd; + ret = ps3_cmd_send_async(instance, cmd, ps3_dev_vd_pending_proc); + INJECT_START(PS3_ERR_IJ_FORCE_VDINFO_SUB_FAIL, &ret) + ps3_mgr_print_cmd(cmd, "vd info async", PS3_DRV_FALSE); + if (ret != PS3_SUCCESS) { + LOG_FILE_ERROR("host_no:%u send error, reqFrameId=%d, t_id:0x%llx ret:%d!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), + cmd->trace_id, ret); + dev_context->vd_pending_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + } + } else { + LOG_FILE_INFO("host_no:%u vd info already subscribed\n", PS3_HOST(instance)); + } +l_out: + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +static inline void ps3_ctrl_info_capablity_dump(struct ps3_instance *instance) +{ + LOG_WARN("host_no:%u ctrl info--supportUnevenSpans:%d supportJbodSecure:%d " + "supportNvmePassthru:%d supportDirectCmd:%d " + "supportAcceleration:%d supportSataDirectCmd:%d supportSataNcq:%d ioTimeOut:%u cancelTimeOut:%u isotoneTimeOut:%u\n", + PS3_HOST(instance), + instance->ctrl_info.capabilities.supportUnevenSpans, + instance->ctrl_info.capabilities.supportJbodSecure, + instance->ctrl_info.capabilities.supportNvmePassthru, + instance->ctrl_info.capabilities.supportDirectCmd, + instance->ctrl_info.capabilities.supportAcceleration, + instance->ctrl_info.capabilities.supportSataDirectCmd, + instance->ctrl_info.capabilities.supportSataNcq, + instance->ctrl_info.ioTimeOut, + instance->ctrl_info.cancelTimeOut, + instance->ctrl_info.isotoneTimeOut + ); +} + +static void ps3_ctrl_info_update(struct ps3_instance *instance) +{ + Bool is_need_dump_info = (0 != memcmp(&instance->ctrl_info, + instance->ctrl_info_buf, sizeof(instance->ctrl_info))); + + memcpy(&instance->ctrl_info, instance->ctrl_info_buf, + sizeof(instance->ctrl_info)); + + if (is_need_dump_info) { + ps3_ctrl_info_capablity_dump(instance); + } + + if (instance->ctrl_info.capabilities.supportDirectCmd) { + instance->cmd_attr.is_support_direct_cmd = PS3_DRV_TRUE; + LOG_INFO("host_no:%u change is_support_direct_cmd to :%d !\n", + PS3_HOST(instance), + instance->cmd_attr.is_support_direct_cmd); + } else { + instance->cmd_attr.is_support_direct_cmd = PS3_DRV_FALSE; + LOG_INFO("host_no:%u change is_support_direct_cmd to :%d !\n", + PS3_HOST(instance), + instance->cmd_attr.is_support_direct_cmd); + } + + instance->cmd_attr.vd_io_threshold = + le32_to_cpu(instance->ctrl_info.vdIOThreshold); + + LOG_INFO("host_no:%u change vdIOThreshold to :%d !\n", + PS3_HOST(instance), + instance->cmd_attr.vd_io_threshold); + ps3_perf_update(instance, instance->ctrl_info.iocPerfMode); + if (instance->ctrl_info.vdQueueNum == 0) { + LOG_ERROR("host_no:%u ctrl info update vd Queue Num is 0!\n", + PS3_HOST(instance)); + instance->ctrl_info.vdQueueNum = 1; + } + LOG_DEBUG("host_no:%u offsetOfVDID:%u\n", + PS3_HOST(instance), instance->ctrl_info.offsetOfVDID); + + LOG_INFO("host_no:%u change is_balance_current_perf_mode to :%d !\n", + PS3_HOST(instance), + instance->irq_context.is_balance_current_perf_mode); +} + +S32 ps3_ctrl_info_get(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u ctrl info cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(instance->ctrl_info_buf, 0, sizeof(struct PS3IocCtrlInfo)); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_GET_CTRL_INFO); + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + cmd->is_force_polling = 1; + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + instance->ctrl_info_buf_h, + sizeof(struct PS3IocCtrlInfo)); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_GET_CTRL_INFO), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret != PS3_SUCCESS) { + LOG_WARN("host_no:%u get ctrl info NOK!\n", PS3_HOST(instance)); + goto l_out; + } + ps3_ctrl_info_update(instance); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_soc_unload(struct ps3_instance *instance, Bool is_polling, U8 type, U8 suspend_type) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + + if (!ps3_check_ioc_state_is_normal_in_unload(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + ps3_wait_scsi_cmd_done(instance, PS3_TRUE); + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_ROMOVE_UNLOAD_FAIL, &cmd) + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_UNLOAD); + mgr_req_frame->reqHead.timeout = instance->unload_timeout; + mgr_req_frame->sgeCount = 0; + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->osType = PS3_LINUX_FRAME; + mgr_req_frame->value.unLoadType = type; + mgr_req_frame->suspend_type = suspend_type; + cmd->is_force_polling = is_polling; + + LOG_WARN("host_no:%u ready send unload, reqFrameId=%d suspend_type:%d!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), suspend_type); + ret = ps3_mgr_unload_cmd_send(cmd, instance->unload_timeout); + INJECT_START(PS3_ERR_IJ_WAIT_SUSPEND_WAIT_RECOVERY, &ret) + LOG_WARN("host_no:%u reqFrameId=%d finished ret:%d!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), ret); +l_out: + if (cmd != NULL) { + ps3_mgr_cmd_free(instance, cmd); + } + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +struct ps3_cmd *ps3_dump_notify_cmd_build(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + struct ps3_dump_context *dump_context = &instance->dump_context; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + cmd = ps3_mgr_cmd_alloc(instance); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get failed !\n", + PS3_HOST(instance)); + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(dump_context->dump_dma_buf, 0, PS3_DUMP_DMA_BUF_SIZE); + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_AUTODUMP_NOTIFY); + + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 0; + mgr_req_frame->pendingFlag = 1; + + ps3_mgr_req_frame_sge_build(mgr_req_frame, dump_context->dump_dma_addr, + PS3_DUMP_DMA_BUF_SIZE); + + ps3_mgr_cmd_word_build(cmd); + + LOG_DEBUG("host_no:%u reqFrameId=%d !\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd)); + +l_out: + LOG_DEBUG("host_no:%u exit ! ret %d\n", PS3_HOST(instance), ret); + return cmd; +} + +S32 ps3_scsi_remove_device_done(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u remove done cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_DEV_DEL_DONE); + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->reqHead.devID.ps3Dev = disk_pos->diskDev.ps3Dev; + mgr_req_frame->value.dev.devID.diskDev = disk_pos->diskDev; + mgr_req_frame->value.dev.devID.diskMagicNum = disk_pos->diskMagicNum; + mgr_req_frame->value.dev.devType = dev_type; + + + LOG_INFO("host_no:%u ready send, t_id:0x%llx reqFrameId=%d, dev_type=%d, " + "[%d:%d:%d:%u]!\n", + PS3_HOST(instance), cmd->trace_id, ps3_cmd_frame_id(cmd), dev_type, + PS3_CHANNEL(disk_pos), PS3_TARGET(disk_pos), + PS3_VDID(disk_pos), disk_pos->diskMagicNum); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_DEV_DEL_DONE), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret != PS3_SUCCESS) { + LOG_INFO("host_no:%u send [%u:%u:%u:%u][type:%d] del done failed!:ret = %d\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_VDID(disk_pos), + disk_pos->diskMagicNum, + dev_type, ret); + } + +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + + LOG_INFO("host_no:%u send [%d:%d:%d:%u] finish!:ret = %d\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_VDID(disk_pos), + disk_pos->diskMagicNum, ret); + + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_scsi_add_device_ack(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u add ack cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u mgr cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_DEV_ADD_ACK); + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->reqHead.devID.ps3Dev = disk_pos->diskDev.ps3Dev; + mgr_req_frame->value.dev.devID.diskDev = disk_pos->diskDev; + mgr_req_frame->value.dev.devID.diskMagicNum = disk_pos->diskMagicNum; + mgr_req_frame->value.dev.devType = dev_type; + + LOG_INFO("t_id:0x%llx host_no:%u ready send, CFID:%d dev_type:%d " + "[%u:%u:%u:%u]!\n", + cmd->trace_id, PS3_HOST(instance), ps3_cmd_frame_id(cmd), dev_type, + PS3_CHANNEL(disk_pos), PS3_TARGET(disk_pos), + PS3_VDID(disk_pos), disk_pos->diskMagicNum); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_DEV_ADD_ACK), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret != PS3_SUCCESS) { + LOG_ERROR("host_no:%u send [%u:%u:%u:%u][type:%d] add ack NOK!:ret = %d\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_VDID(disk_pos), + disk_pos->diskMagicNum, + dev_type, ret); + } + +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + + LOG_INFO("host_no:%u send [%u:%u:%u:%u] finish!:ret = %d\n", + PS3_HOST(instance), PS3_CHANNEL(disk_pos), + PS3_TARGET(disk_pos), PS3_VDID(disk_pos), + disk_pos->diskMagicNum, ret); + + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_mgr_cmd_cancel(struct ps3_instance *instance, U16 cancel_cmd_frame_id) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + U16 cancel_time_out = PS3_CANCEL_MGR_CMD_TIMEOUT; + + LOG_DEBUG("host_no:%u enter, be cancel CFID:%d !\n", + PS3_HOST(instance), cancel_cmd_frame_id); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u mgr cancel cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_task_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_FORCE_ALLOC_CANCEL_CMD_FAILED, &cmd) + if (cmd == NULL) { + LOG_FILE_ERROR("host_no:%u task cmd get failed !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + if (instance->ctrl_info.cancelTimeOut > cancel_time_out) { + cancel_time_out = instance->ctrl_info.cancelTimeOut; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_CANCEL); + mgr_req_frame->reqHead.timeout = cancel_time_out; + mgr_req_frame->sgeCount = 0; + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->abortFlag = 0; + mgr_req_frame->value.originalCmdFrameID = cancel_cmd_frame_id; + + LOG_FILE_INFO("host_no:%u ready send, reqFrameId=%d cancel_cmd_frame_id:%u !\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cancel_cmd_frame_id); + + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_RECOVERY_CANCEL, cmd); + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, cancel_time_out); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(PS3_MGR_CMD_CANCEL), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + LOG_FILE_INFO("host_no:%u reqFrameId=%d cancel_cmd_frame_id:%u finished!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cancel_cmd_frame_id); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_task_cmd_free(instance, cmd); + } + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} +S32 ps3_mgr_cmd_cancel_send(struct ps3_instance *instance, + U16 cancel_cmd_frame_id, U8 type) +{ + S32 ret = PS3_SUCCESS; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + enum PS3MgrCmdSubType sub_type; + struct ps3_cmd *cmd = NULL; + LOG_DEBUG("host_no:%u enter, be cancel CFID:%d !\n", + PS3_HOST(instance), cancel_cmd_frame_id); + + cmd = ps3_task_cmd_alloc(instance); + if (cmd == NULL) { + LOG_FILE_ERROR("host_no:%u task cmd get failed !\n", + PS3_HOST(instance)); + ret = -PS3_ENOMEM; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_CANCEL); + mgr_req_frame->sgeCount = 0; + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 1; + mgr_req_frame->abortFlag = 0; + mgr_req_frame->value.originalCmdFrameID = cancel_cmd_frame_id; + + LOG_FILE_INFO("host_no:%u ready send, reqFrameId=%d cancel_cmd_frame_id:%u !\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cancel_cmd_frame_id); + + sub_type = (enum PS3MgrCmdSubType)PS3_MGR_CMD_SUBTYPE(cmd); + + cmd->time_out = PS3_DEFAULT_MGR_CMD_TIMEOUT; + cmd->is_interrupt = PS3_DRV_FALSE; + ps3_mgr_cmd_word_build(cmd); + + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(sub_type), PS3_DRV_TRUE); + if(type == PS3_CANCEL_EVENT_CMD){ + instance->event_context.event_abort_cmd = cmd; + }else if(type == PS3_CANCEL_WEB_CMD){ + instance->webSubscribe_context.web_abort_cmd = cmd; + }else{ + instance->dev_context.vdpending_abort_cmd = cmd; + } + ret = ps3_cmd_no_block_send(instance, cmd); + if (ret != PS3_SUCCESS) { + LOG_FILE_INFO("host_no:%u CFID:%d trace_id:0x%llx send failed\n", + PS3_HOST(instance), + ps3_cmd_frame_id(cmd), cmd->trace_id); + } + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(sub_type), PS3_DRV_FALSE); +l_out: + return ret; +} +S32 ps3_mgr_cmd_cancel_wait(struct ps3_instance *instance, U8 type) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + ULong flags = 0; + S32 send_result; + if (type == PS3_CANCEL_EVENT_CMD){ + cmd = instance->event_context.event_abort_cmd; + if (cmd == NULL){ + LOG_INFO("host_no:%u event abort cmd null!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + }else if(type == PS3_CANCEL_WEB_CMD){ + cmd = instance->webSubscribe_context.web_abort_cmd; + if (cmd == NULL){ + LOG_INFO("host_no:%u web abort cmd null!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + }else{ + cmd = instance->dev_context.vdpending_abort_cmd; + if (cmd == NULL){ + LOG_INFO("host_no:%u vdpending abort cmd null!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + } + send_result = ps3_block_cmd_wait(instance, cmd, 0); + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if(cmd->cmd_state.state != PS3_CMD_STATE_COMPLETE){ + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + ret = -PS3_RECOVERED; + goto l_out; + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + + LOG_INFO("host_no:%u reqFrameId=%d finished!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd)); + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + if(type == PS3_CANCEL_EVENT_CMD){ + abort_cmd = instance->event_context.event_abort_cmd; + instance->event_context.event_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + }else if(type == PS3_CANCEL_WEB_CMD){ + abort_cmd = instance->webSubscribe_context.web_abort_cmd; + instance->webSubscribe_context.web_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + }else{ + abort_cmd = instance->dev_context.vdpending_abort_cmd; + instance->dev_context.vdpending_abort_cmd = NULL; + if (abort_cmd != NULL) { + ps3_task_cmd_free(instance, abort_cmd); + } + } + } +l_out: + return ret; +} + +S32 ps3_event_register(struct ps3_instance *instance, + struct PS3MgrEvent *event) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR_IN_IRQ(instance, "host_no:%u mgr cmd get failed !\n", + PS3_HOST(instance)); + ret = -PS3_EBUSY; + goto l_out; + } + + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(*mgr_req_frame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_SUBSCRIBE_EVENT); + mgr_req_frame->reqHead.timeout = 0; + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 0; + mgr_req_frame->pendingFlag = 1; + + mgr_req_frame->value.event.eventTypeMap = + event->eventTypeMap; + mgr_req_frame->value.event.eventTypeMapProcResult = + event->eventTypeMapProcResult; + mgr_req_frame->value.event.eventLevel = event->eventLevel; + + instance->event_context.event_info = (struct PS3EventInfo*)cmd->ext_buf; + + ps3_mgr_req_frame_sge_build(mgr_req_frame, + cmd->ext_buf_phys, + cmd->instance->cmd_context.ext_buf_size); + + memset(cmd->ext_buf, 0, cmd->instance->cmd_context.ext_buf_size); + if (instance->ioc_adpter->event_filter_table_get != NULL) { + instance->ioc_adpter->event_filter_table_get((U8*)cmd->ext_buf); + } + + ps3_mgr_cmd_word_build(cmd); + LOG_INFO_IN_IRQ(instance, "host_no:%u ready send, reqFrameId=%d !\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd)); + + ps3_mgr_print_cmd(cmd, "event register", PS3_DRV_TRUE); + instance->event_context.event_cmd = cmd; + ret = ps3_cmd_send_async(instance, cmd, ps3_event_service); + if (ret != PS3_SUCCESS) { + instance->event_context.event_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + } + ps3_mgr_print_cmd(cmd, "event register", PS3_DRV_FALSE); +l_out: + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +S32 ps3_web_register(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + PS3MgrReqFrame_s *mgr_req_frame = NULL; + struct ps3_webSubscribe_context *web_context = &instance->webSubscribe_context; + + cmd = web_context->webSubscribe_cmd; + + if (cmd == NULL) { + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_TRUE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u web cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_FAILED; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_WARN_IN_IRQ(instance, + "host_no:%u ioctl req, Failed to get a cmd packet\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_FAILED; + goto l_out; + } + mgr_req_frame = &cmd->req_frame->mgrReq; + memset(mgr_req_frame, 0, sizeof(struct PS3MgrReqFrame)); + + ps3_mgr_req_head_init(cmd, &mgr_req_frame->reqHead, PS3_MGR_CMD_WEBSUBSCRIBE_EVENT); + mgr_req_frame->reqHead.timeout = 0; + mgr_req_frame->timeout = 0; + mgr_req_frame->syncFlag = 0; + mgr_req_frame->pendingFlag = 1; + ps3_mgr_cmd_word_build(cmd); + LOG_INFO_IN_IRQ(instance, "host_no:%u ready send, reqFrameId=%d !\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd)); + ps3_mgr_print_cmd(cmd, "web event register", PS3_DRV_TRUE); + + web_context->webSubscribe_cmd = cmd; + + ret = ps3_cmd_send_async(instance, cmd, ps3_webSubscribe_service); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + INJECT_START(PS3_ERR_IJ_FORCE_WEB_SUB_FAIL, &ret) + if (ret != PS3_SUCCESS) { + web_context->webSubscribe_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + goto l_out; + } + }else { + LOG_INFO_IN_IRQ(instance, "host_no:%u web event already subscribed\n", + PS3_HOST(instance)); + } +l_out: + LOG_DEBUG("host_no:%u exit !\n", PS3_HOST(instance)); + return ret; +} + +static S32 ps3_scsi_task_abort_sync_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd, struct ps3_cmd *abort_cmd, + struct ps3_scsi_priv_data *priv_data) +{ + S32 ret = PS3_SUCCESS; + + cmd->cmd_word_value = abort_cmd->cmd_word_value; + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_INIT) { + ret = -PS3_FAILED; + goto end; + } + cmd->cmd_word.direct = PS3_CMDWORD_DIRECT_NORMAL; + cmd->cmd_word.cmdFrameID = ps3_cmd_frame_id(cmd); + cmd->cmd_word.type = PS3_CMDWORD_TYPE_ABORT; + cmd->time_out = priv_data->task_abort_timeout; + cmd->is_interrupt = PS3_DRV_FALSE; + + INJECT_START(PS3_ERR_IJ_ABORT_PRE_SEND_FORCE_ABORTED_CMD_DONE, abort_cmd->scmd) + ret = ps3_cmd_send_sync(instance, cmd); +end: + return ret; +} + +static inline void ps3_mgr_scsi_req_head_init(struct ps3_cmd *cmd, + PS3ReqFrameHead_s *req_header, U8 cmdSubType, U32 disk_id, + struct ps3_scsi_priv_data *priv_data) +{ + if (cmdSubType == PS3_TASK_CMD_SCSI_TASK_RESET) { + req_header->timeout = priv_data->task_reset_timeout; + } else { + req_header->timeout = priv_data->task_abort_timeout; + } + req_header->traceID = ps3_cmd_trace_id(cmd); + req_header->cmdType = PS3_CMD_SCSI_TASK_MANAGEMENT; + req_header->cmdSubType = cmdSubType; + req_header->cmdFrameID = ps3_cmd_frame_id(cmd); + req_header->control = 0; + req_header->devID.diskID = disk_id; +} + +struct ps3_cmd * ps3_scsi_task_mgr_reset_build(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data) +{ + struct ps3_cmd *cmd = NULL; + PS3MgrTaskReqFrame_s *mgr_task_req_frame = NULL; + U32 disk_id = priv_data->disk_pos.diskDev.diskID; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + + if ((priv_data->dev_type == PS3_DEV_TYPE_UNKNOWN) || + (disk_id == PS3_INVALID_DEV_ID)) { + LOG_ERROR("host_no:%u unknow dev type !\n", + PS3_HOST(instance)); + goto l_out; + } + + cmd = ps3_task_cmd_alloc(instance); + if (cmd == NULL) { + LOG_ERROR("host_no:%u task cmd get NOK !\n", + PS3_HOST(instance)); + goto l_out; + } + + mgr_task_req_frame = &cmd->req_frame->taskReq; + mgr_task_req_frame->taskID = 0; + memset(mgr_task_req_frame, 0, sizeof(*mgr_task_req_frame)); + ps3_mgr_scsi_req_head_init(cmd, &mgr_task_req_frame->reqHead, + PS3_TASK_CMD_SCSI_TASK_RESET, disk_id, priv_data); + + LOG_WARN("host_no:%u ready send reset, CFID:%u t_id:0x%llx [%u:%u:%u]!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cmd->trace_id, + PS3_CHANNEL(&priv_data->disk_pos), + PS3_TARGET(&priv_data->disk_pos), + PS3_VDID(&priv_data->disk_pos)); + + ps3_mgr_cmd_word_build(cmd); + + if (priv_data->dev_type == PS3_DEV_TYPE_VD) { + cmd->cmd_word.virtDiskID = (U8)priv_data->disk_pos.diskDev.ps3Dev.virtDiskID; + } else { + cmd->cmd_word.phyDiskID = priv_data->disk_pos.diskDev.ps3Dev.phyDiskID; + } + + cmd->time_out = priv_data->task_reset_timeout; + cmd->is_interrupt = PS3_FALSE; + +l_out: + return cmd; +} + +#ifndef _WINDOWS +#if 0 +static void ps3_abort_req_frame_dump(struct ps3_cmd *cmd) +{ + PS3_BUG_ON((cmd->req_frame == NULL) || (cmd->scmd == NULL)); + + switch (cmd->cmd_word.type) + { + case PS3_CMDWORD_TYPE_MGR: + if ((cmd->req_frame->word[0] == PS3_CMD_VD_SCSI_IO_NORW) || + (cmd->req_frame->word[0] == PS3_CMD_PD_SCSI_IO_NORW)) { + LOG_DEBUG("t_id:0x%llx host_no:%u aborted_cmd CFID:%u " + "type:%d fe isr_sn:%d cmd_type:%d opcode:0x%x!\n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->cmd_word.cmdFrameID, cmd->cmd_word.type, + cmd->cmd_word.isrSN, + cmd->req_frame->frontendReq.reqHead.cmdType, + cmd->scmd->cmnd[0]); + } else { + LOG_ERROR("host_no:%u abort_cmd no scsi cmd! cmd_type:%d\n", + PS3_HOST(cmd->instance), + (int)cmd->req_frame->word[0]); + } + break; + case PS3_CMDWORD_TYPE_READ: + case PS3_CMDWORD_TYPE_WRITE: + if (cmd->cmd_word.isHardCmd) { + LOG_DEBUG("t_id:0x%llx host_no:%u abort_cmd CFID:%u type:%d " + "hwReq isr_sn:%d opcode:0x%x!\n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->cmd_word.cmdFrameID, cmd->cmd_word.type, + cmd->cmd_word.isrSN, cmd->scmd->cmnd[0]); + } else { + LOG_DEBUG("t_id:0x%llx host_no:%u abort_cmd CFID:%u type:%d " + "fe isr_sn:%d opcode:0x%x cmd_type:%u !\n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->cmd_word.cmdFrameID, cmd->cmd_word.type, + cmd->cmd_word.isrSN, cmd->scmd->cmnd[0], + cmd->req_frame->frontendReq.reqHead.cmdType); + } + break; + default: + LOG_ERROR("host_no:%u abort_cmd no scsi cmd! \n", + PS3_HOST(cmd->instance)); + break; + } + return; +} +#endif +S32 ps3_scsi_task_mgr_abort(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, U16 aborted_cmd_frame_id, struct scsi_cmnd *scmd) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *aborted_cmd = NULL; + PS3MgrTaskReqFrame_s *mgr_task_req_frame = NULL; + U32 disk_id = priv_data->disk_pos.diskDev.diskID; + + LOG_DEBUG("host_no:%u enter !\n", PS3_HOST(instance)); + if ((priv_data->dev_type == PS3_DEV_TYPE_UNKNOWN) || + (disk_id == PS3_INVALID_DEV_ID)) { + LOG_ERROR("host_no:%u unknow dev type !\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_ABORT_PRE_BULID_FORCE_ABORTED_CMD_DONE, scmd) + aborted_cmd = ps3_cmd_find(instance, aborted_cmd_frame_id); + if (aborted_cmd == NULL || aborted_cmd->scmd == NULL) { + LOG_ERROR("host_no:%u there is no aborted cmd CFID:%u\n", + PS3_HOST(instance), aborted_cmd_frame_id); + + ret = PS3_SUCCESS; + goto l_out; + } + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_FALSE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u aborted cmd pre check NOK CFID:%d\n", + PS3_HOST(instance), aborted_cmd_frame_id); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + cmd = ps3_task_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_ERROR("host_no:%u task cmd get NOK !\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_EBUSY; + goto l_out; + } + + LOG_DEBUG("t_id:0x%llx aborted_t_id:0x%llx host_no:%u mgr abort CFID:%d\n", + cmd->trace_id, aborted_cmd->trace_id, PS3_HOST(instance), cmd->index); + + mgr_task_req_frame = &cmd->req_frame->taskReq; + memset(mgr_task_req_frame, 0, sizeof(*mgr_task_req_frame)); + + ps3_mgr_scsi_req_head_init(cmd, &mgr_task_req_frame->reqHead, + PS3_TASK_CMD_SCSI_TASK_ABORT, disk_id, priv_data); + mgr_task_req_frame->taskID = aborted_cmd_frame_id; + mgr_task_req_frame->abortedCmdType = aborted_cmd->cmd_word.direct; + mgr_task_req_frame->reqHead.reqFrameFormat = PS3_REQFRAME_FORMAT_FRONTEND; + + LOG_WARN("host_no:%u ready send abort, CFID:%d t_id:0x%llx aborted cmd info:" + "CFID:%d t_id:0x%llx op:0x%x is_retry_cmd:%d timeout:%d dev[%u:%u:%u:%u], " + "cmdword[0x%08llx]{type:%d direct:%d que:%d isr_sn:%d}!\n ", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cmd->trace_id, + aborted_cmd_frame_id, aborted_cmd->trace_id, + scmd->cmd_len > 0 ? scmd->cmnd[0] : 0xff, + scmd->retries, + SCMD_GET_REQUEST(scmd)->timeout, PS3_CHANNEL(&priv_data->disk_pos), + PS3_TARGET(&priv_data->disk_pos), + PS3_VDID(&priv_data->disk_pos), + priv_data->disk_pos.diskMagicNum, aborted_cmd->cmd_word_value, + aborted_cmd->cmd_word.type, aborted_cmd->cmd_word.direct, + aborted_cmd->cmd_word.qMask, aborted_cmd->cmd_word.isrSN); + + ps3_scsih_print_req(aborted_cmd, LEVEL_INFO); + INJECT_START(PS3_ERR_IJ_ABORT_PRE_BULID1_FORCE_ABORTED_CMD_DONE, scmd) + INJECT_START(PS3_ERR_IJ_SET_ABORT_COUNT, scmd); + + send_result = ps3_scsi_task_abort_sync_proc(instance, cmd, aborted_cmd, priv_data); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + LOG_WARN("host_no:%u abort finish, CFID:%d aborted CFID:%d aborted cmdword[0x%08llx], " + "[%u:%u:%u:%u]!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), aborted_cmd_frame_id, aborted_cmd->cmd_word_value, + PS3_CHANNEL(&priv_data->disk_pos), + PS3_TARGET(&priv_data->disk_pos), + PS3_VDID(&priv_data->disk_pos), + priv_data->disk_pos.diskMagicNum); + +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_task_cmd_free(instance, cmd); + } + LOG_WARN("host_no:%u exit !, ret:%d\n", PS3_HOST(instance), ret); + return ret; +} +#endif + +#ifndef _WINDOWS +static inline void ps3_sas_info_reqframe_build(struct ps3_cmd *cmd, + enum PS3MgrCmdSubType sub_type, dma_addr_t *sge_addr, struct PS3SasMgr *sas_req) +{ + PS3MgrReqFrame_s *mgrReq = &cmd->req_frame->mgrReq; + mgrReq->reqHead.timeout = PS3_DEFAULT_MGR_CMD_TIMEOUT; + mgrReq->reqHead.traceID = cmd->trace_id; + mgrReq->reqHead.cmdType = PS3_CMD_SAS_MANAGEMENT; + mgrReq->reqHead.cmdSubType = sub_type; + mgrReq->reqHead.cmdFrameID = cmd->index; + mgrReq->reqHead.control = 0; + mgrReq->syncFlag = 1; + mgrReq->timeout = 0; + mgrReq->sgeOffset = + offsetof(PS3MgrReqFrame_s, sgl) >> PS3_MGR_CMD_SGL_OFFSET_DWORD_SHIFT; + mgrReq->sgeCount = 1; + mgrReq->sgl[0].length = cpu_to_le32(PS3_SAS_REQ_BUFF_LEN); + mgrReq->sgl[0].addr = cpu_to_le64(*sge_addr); + mgrReq->sgl[0].lastSge = 1; + mgrReq->sgl[0].ext = 0; + + if (sas_req != NULL) { + mgrReq->value.sasMgr.sasAddr = + cpu_to_le64(sas_req->sasAddr); + mgrReq->value.sasMgr.enclID = sas_req->enclID; + mgrReq->value.sasMgr.startPhyID = sas_req->startPhyID; + mgrReq->value.sasMgr.phyCount = sas_req->phyCount; + } +} + +static S32 __ps3_sas_info_get(struct ps3_instance *instance, + enum PS3MgrCmdSubType sub_type, dma_addr_t *sge_addr, struct PS3SasMgr *sas_req) +{ + S32 ret = 0; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_FALSE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u sas info cmd pre check NOK\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_FAILED; + goto l_out; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_EVENT_MGR_CMD_ALLOC_FAILED, &cmd); + if (cmd == NULL) { + LOG_WARN("host_no:%u not get a cmd packet\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -PS3_FAILED; + goto l_out; + } + + ps3_sas_info_reqframe_build(cmd, sub_type, sge_addr, sas_req); + ps3_mgr_cmd_word_build(cmd); + + LOG_INFO("host_no:%u ready send t_id:0x%llx CFID:%u req type:%s\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, + namePS3MgrCmdSubType((enum PS3MgrCmdSubType)sub_type)); + + send_result = ps3_mgr_cmd_sync_proc(instance, cmd, PS3_DEFAULT_MGR_CMD_TIMEOUT); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(sub_type), PS3_DRV_FALSE); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret != PS3_SUCCESS) { + LOG_ERROR("host_no:%u %d respStatus NOK CFID:%d respStatus:%d\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + } + + LOG_INFO("host_no:%u t_id:0x%llx CFID :%u type:%s end, ret:%d\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, + namePS3MgrCmdSubType((enum PS3MgrCmdSubType)sub_type), ret); +l_out: + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_mgr_cmd_free(instance, cmd); + } + + return ret; +} + +S32 ps3_sas_expander_all_get(struct ps3_instance *instance) +{ + LOG_DEBUG("host_no:%u\n", PS3_HOST(instance)); + + return __ps3_sas_info_get(instance, PS3_SAS_GET_EXPANDERS, + &instance->sas_dev_context.ps3_sas_buff_dma_addr, + NULL); +} + +S32 ps3_sas_phy_get(struct ps3_instance *instance, struct PS3SasMgr *sas_req) +{ + LOG_DEBUG("host_no:%u\n", PS3_HOST(instance)); + + if (sas_req->phyCount == 0) { + LOG_WARN("host_no:%u unexpect phyCount:%d !\n", + PS3_HOST(instance), sas_req->phyCount); + return -PS3_FAILED; + } + return __ps3_sas_info_get(instance, PS3_SAS_GET_PHY_INFO, + &instance->sas_dev_context.ps3_sas_phy_buff_dma_addr, + sas_req); +} + +S32 ps3_sas_expander_get(struct ps3_instance *instance, struct PS3SasMgr *sas_req) +{ + LOG_DEBUG("host_no:%u\n", PS3_HOST(instance)); + + return __ps3_sas_info_get(instance, PS3_SAS_GET_EXPANDER_INFO, + &instance->sas_dev_context.ps3_sas_buff_dma_addr, + sas_req); +} +#endif +static S32 ps3_mgr_cmd_sync_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd, U16 time_out) +{ + enum PS3MgrCmdSubType sub_type = (enum PS3MgrCmdSubType)PS3_MGR_CMD_SUBTYPE(cmd); + + cmd->time_out = time_out; + cmd->is_interrupt = PS3_DRV_FALSE; + ps3_mgr_cmd_word_build(cmd); + + ps3_mgr_print_cmd(cmd, + namePS3MgrCmdSubType(sub_type), PS3_DRV_TRUE); + + INJECT_START(PS3_ERR_IJ_PD_LIST_WAIT_IRQ_DISABLE, cmd); + + return ps3_cmd_send_sync(instance, cmd); +} + +static S32 ps3_no_resp_cmd_dead_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT || + cmd->cmd_state.state == PS3_CMD_STATE_COMPLETE) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("host_no:%u CFID:%d finished\n", + PS3_HOST(instance), cmd->index); + ret = -PS3_FAILED; + goto l_out; + } + + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("host_no:%u cmd_dead_proc entry reset due to cmd not resp!\n", PS3_HOST(instance)); + + if (!instance->is_probe_finish || + !instance->state_machine.is_load) { + ps3_need_wait_hard_reset_request(instance); + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret == PS3_SUCCESS) { + ps3_instance_wait_for_dead_or_pre_operational(instance); + } else { + LOG_WARN("host_no:%u hard recovery request NOK\n", + PS3_HOST(instance)); + } + + } else { + ps3_need_wait_hard_reset_request(instance); + ps3_recovery_request_with_retry(instance); + } + + LOG_ERROR("t_id:0x%llx CFID:%d host_no:%u state %u, recovery request\n", + cmd->trace_id, cmd->index, PS3_HOST(instance),cmd->cmd_state.state); + + ret = -PS3_CMD_NO_RESP; +l_out: + return ret; +} + +static S32 ps3_no_resp_cmd_wait_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + Bool is_probe_finish = PS3_FALSE; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT || + cmd->cmd_state.state == PS3_CMD_STATE_COMPLETE) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("host_no:%u CFID:%d finished, retries:%d\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt); + ret = -PS3_FAILED; + goto l_out; + } else { + if (cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NEED_REPLY_WORD) { + init_completion(&cmd->sync_done); + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + LOG_WARN("host_no:%u cmd_wait_proc entry reset due to cmd not resp, CFID:%d t_id:0x%llx !\n", + PS3_HOST(instance), cmd->index, cmd->trace_id); + + is_probe_finish = instance->is_probe_finish; + ps3_need_wait_hard_reset_request(instance); + if (!is_probe_finish) { + ret = ps3_hard_recovery_request_with_retry(instance); + } else { + ret = ps3_recovery_request_with_retry(instance); + } + + if (ret == -PS3_FAILED) { + ret = -PS3_CMD_NO_RESP; + LOG_ERROR("host_no:%u recovery request NOK\n", + PS3_HOST(instance)); + goto l_dead; + } + INJECT_START(PS3_ERR_IJ_WAIT_HARD_RESET, instance) + + if (!is_probe_finish) { + ps3_instance_wait_for_dead_or_pre_operational(instance); + } + + LOG_WARN("host_no:%u CFID:%d wait again, retries:%d\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt); + + if (cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NEED_REPLY_WORD) { + ret = ps3_block_cmd_wait(instance, cmd, 0); + } else { + ret = ps3_cmd_reply_polling_when_recovery(instance, cmd, 0); + } + + ret = ps3_err_mgr_cmd_proc(instance, ret, cmd); + if (ret == -PS3_CMD_NO_RESP) { + LOG_WARN("host_no:%u CFID:%d wait again, retries:%d\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt); + } +l_dead: + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state != PS3_CMD_STATE_INIT && + cmd->cmd_state.state != PS3_CMD_STATE_COMPLETE) { + LOG_FILE_ERROR("host_no:%u CFID:%d is dead\n", + PS3_HOST(instance), cmd->index); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + +l_out: + LOG_INFO("host_no:%u noresp cmd deal ret:%d\n", + PS3_HOST(instance),ret); + return ret; +} +static S32 ps3_no_resp_scsi_task_cmd_wait_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + ULong flags = 0; + S32 ret = PS3_SUCCESS; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT || + cmd->cmd_state.state == PS3_CMD_STATE_COMPLETE) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + LOG_WARN("host_no:%u CFID:%d finished, retries:%d\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt); + ret = -PS3_FAILED; + goto l_out; + } else { + if (cmd->req_frame->frontendReq.reqHead.noReplyWord == PS3_CMD_WORD_NEED_REPLY_WORD) { + init_completion(&cmd->sync_done); + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } + + ps3_need_wait_hard_reset_request(instance); + LOG_WARN("host_no:%u scsi_task_cmd_wait_proc entry reset due to cmd not resp, CFID:%d t_id:0x%llx !\n", + PS3_HOST(instance), cmd->index, cmd->trace_id); + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret == -PS3_FAILED) { + ret = -PS3_CMD_NO_RESP; + LOG_ERROR("host_no:%u hard recovery request NOK\n", + PS3_HOST(instance)); + goto l_dead; + } + + if (cmd->req_frame->frontendReq.reqHead.noReplyWord == PS3_CMD_WORD_NEED_REPLY_WORD) { + ret = ps3_block_cmd_wait(instance, cmd, PS3_HARD_RESET_FORCE_STOP_MAX_TIME(instance)); + } else { + ret = ps3_cmd_reply_polling_when_recovery(instance, cmd, PS3_HARD_RESET_FORCE_STOP_MAX_TIME(instance)); + } + ret = ps3_err_mgr_cmd_proc(instance, ret, cmd); + if (ret == -PS3_CMD_NO_RESP) { + LOG_ERROR("host_no:%u hard recovery request,cmd timeout again\n", + PS3_HOST(instance)); + goto l_dead; + }else{ + goto l_out; + } + +l_dead: + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state != PS3_CMD_STATE_INIT && + cmd->cmd_state.state != PS3_CMD_STATE_COMPLETE) { + LOG_FILE_ERROR("host_no:%u CFID:%d is dead\n", + PS3_HOST(instance), cmd->index); + cmd->cmd_state.state = PS3_CMD_STATE_DEAD; + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + +l_out: + LOG_INFO("host_no:%u noresp cmd deal ret:%d\n", + PS3_HOST(instance),ret); + return ret; +} + +S32 ps3_mgr_cmd_no_resp_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + switch (PS3_MGR_CMD_TYPE(cmd)) + { + case PS3_CMD_MANAGEMENT: + ret = ps3_no_resp_cmd_dead_proc(instance, cmd); + break; + case PS3_CMD_SCSI_TASK_MANAGEMENT: + ret = ps3_no_resp_scsi_task_cmd_wait_proc(instance, cmd); + break; + case PS3_CMD_IOCTL: + ret = ps3_no_resp_cmd_wait_proc(instance, cmd); + break; + case PS3_CMD_SAS_MANAGEMENT: + if ((PS3_MGR_CMD_SUBTYPE(cmd) == PS3_SAS_SMP_REQUEST) || + (PS3_MGR_CMD_SUBTYPE(cmd) == PS3_SAS_GET_LINK_ERR) || + (PS3_MGR_CMD_SUBTYPE(cmd) == PS3_SAS_PHY_CTRL) ) { + ret = ps3_no_resp_cmd_wait_proc(instance, cmd); + } else { + ret = ps3_no_resp_cmd_dead_proc(instance, cmd); + } + break; + default: + LOG_ERROR("host_no:%u UNEXPEXT!!!! no response proc cmd_type:%d, sub_type:%d \n", + PS3_HOST(instance), PS3_MGR_CMD_TYPE(cmd), PS3_MGR_CMD_SUBTYPE(cmd)); + ret = -PS3_FAILED; + break; + } + + return ret; +} + +S32 ps3_mgr_complete_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd, S32 send_result) +{ + S32 ret = PS3_SUCCESS; + ULong flags = 0; + + while(cmd->retry_cnt < PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + if (send_result == PS3_SUCCESS) { + LOG_FILE_INFO("host_no:%u externel mgr CFID:%d respStatus:%d success\n", + PS3_HOST(instance), + cmd->index, + ps3_cmd_resp_status(cmd)); + ret = PS3_SUCCESS; + break; + } + + if(send_result == -PS3_RECOVERED) { + LOG_INFO("host_no:%u mgr CFID:%d respStatus:%d cannot send because recovery process\n", + PS3_HOST(instance), + cmd->index, + ps3_cmd_resp_status(cmd)); + ret = -PS3_RECOVERED; + break; + } + + ret = ps3_err_mgr_cmd_proc(instance, send_result, cmd); + if (ret == -PS3_CMD_NO_RESP) { + ret = ps3_mgr_cmd_no_resp_proc(instance, cmd); + } + + if (ret != -PS3_RETRY) { + if ((PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_MANAGEMENT) && + (PS3_MGR_CMD_SUBTYPE(cmd) == PS3_MGR_CMD_DEV_DEL_DONE)) { + LOG_FILE_INFO("host_no:%u CFID:%d retry, retries:%d, ret:%d\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt, ret); + } else { + LOG_INFO("host_no:%u cmd:%s CFID:%d retry, retries:%d, ret:%d\n", + PS3_HOST(instance), namePS3MgrCmdSubType( + (enum PS3MgrCmdSubType)PS3_MGR_CMD_SUBTYPE(cmd)), + cmd->index, cmd->retry_cnt, ret); + } + break; + } + + cmd->retry_cnt++; + INJECT_START(PS3_ERR_IJ_IOCTL_CMD_RETRY_DONE, cmd) + if (cmd->retry_cnt >= PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + break; + } + LOG_INFO("host_no:%u mgr CFID:%d retry:%u\n", + PS3_HOST(instance), cmd->index, cmd->retry_cnt); + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if ((send_result = ps3_mgr_cmd_send_check(instance, cmd)) != PS3_SUCCESS) { + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + continue; + } + cmd->resp_frame->normalRespFrame.respStatus = 0xff; + init_completion(&cmd->sync_done); + ps3_ioctl_buff_bit_pos_update(cmd); + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + cmd->cmd_state.state = PS3_CMD_STATE_PROCESS; + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + }; + + if (cmd->retry_cnt >= PS3_ERR_MGR_CMD_FAULT_RETRY_MAX) { + ret = -PS3_FAILED; + LOG_ERROR("host_no:%u cmd request NOK.\n", + PS3_HOST(instance)); + } + + return ret; +} + +Bool ps3_check_ioc_state_is_normal_in_unload( + struct ps3_instance *instance) +{ + Bool ret = PS3_TRUE; + U32 ioc_state = PS3_FW_STATE_UNDEFINED; + + if (instance->state_machine.is_load) { + goto l_out; + } + + if (!ps3_ioc_state_get_with_check(instance, &ioc_state)) { + ret = PS3_FALSE; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_IOC_IS_NOT_NORMAL_IN_UNLOAD, &ioc_state) + if ((ioc_state != PS3_FW_STATE_RUNNING)) { + LOG_ERROR("host_no:%d ioc_state:%d is not running.\n", + PS3_HOST(instance), ioc_state); + ret = PS3_FALSE; + goto l_out; + } +l_out: + return ret; + +} diff --git a/drivers/scsi/ps3stor/ps3_mgr_cmd.h b/drivers/scsi/ps3stor/ps3_mgr_cmd.h new file mode 100644 index 0000000000000000000000000000000000000000..aa4e1371818a1ede87ef608626ae6861465fef38 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_mgr_cmd.h @@ -0,0 +1,85 @@ + +#ifndef _PS3_MANAGMENT_CMD_H_ +#define _PS3_MANAGMENT_CMD_H_ + +#include "ps3_instance_manager.h" +#include "ps3_device_manager.h" + +#define PS3_MGR_BASE_DATA_SIZE (64) + +#define PS3_MGR_CMD_SGL_OFFSET_DWORD_SHIFT (2) + +#define PS3_MGR_CMD_TYPE(cmd) ((cmd)->req_frame->mgrReq.reqHead.cmdType) +#define PS3_MGR_CMD_SUBTYPE(cmd) ((cmd)->req_frame->mgrReq.reqHead.cmdSubType) +enum{ + PS3_CANCEL_EVENT_CMD = 1, + PS3_CANCEL_VDPENDING_CMD, + PS3_CANCEL_WEB_CMD, +}; +S32 ps3_ctrl_info_buf_alloc(struct ps3_instance *instance); + +void ps3_ctrl_info_buf_free(struct ps3_instance *instance); + +S32 ps3_mgr_cmd_init(struct ps3_instance *instance); + +void ps3_mgr_cmd_exit(struct ps3_instance *instance); + +S32 ps3_pd_list_get(struct ps3_instance *instance); + +S32 ps3_vd_list_get(struct ps3_instance *instance); + +S32 ps3_pd_info_get(struct ps3_instance *instance, U16 channel, U16 target_id, U16 pd_disk_id); + +S32 ps3_vd_info_sync_get(struct ps3_instance *instance, U32 disk_id, + U16 vd_num); + +S32 ps3_vd_info_async_get(struct ps3_instance *instance); + +S32 ps3_ctrl_info_get(struct ps3_instance *instance); + +S32 ps3_soc_unload(struct ps3_instance *instance, Bool is_polling, U8 type, U8 suspend_type); + +S32 ps3_scsi_remove_device_done(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type); + +S32 ps3_scsi_add_device_ack(struct ps3_instance *instance, + struct PS3DiskDevPos *disk_pos, U8 dev_type); + +S32 ps3_mgr_cmd_cancel(struct ps3_instance *instance, U16 cancel_cmd_frame_id); + +S32 ps3_event_register(struct ps3_instance *instance, + struct PS3MgrEvent *event); +S32 ps3_web_register(struct ps3_instance *instance); + +S32 ps3_scsi_task_mgr_abort(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, U16 aborted_cmd_frame_id, struct scsi_cmnd *scmd); + +void ps3_mgr_cmd_word_build(struct ps3_cmd *cmd); + +S32 ps3_sas_expander_all_get(struct ps3_instance *instance); + +S32 ps3_sas_phy_get(struct ps3_instance *instance, struct PS3SasMgr *sas_req); + +S32 ps3_sas_expander_get(struct ps3_instance *instance, struct PS3SasMgr *sas_req); + +S32 ps3_mgr_complete_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd, S32 send_result); + +struct ps3_cmd *ps3_dump_notify_cmd_build(struct ps3_instance *instance); +struct ps3_cmd * ps3_scsi_task_mgr_reset_build(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data); + +struct ps3_cmd * ps3_scsi_task_mgr_reset_build(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data); + +S32 ps3_mgr_cmd_no_resp_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd); + +Bool ps3_check_ioc_state_is_normal_in_unload( + struct ps3_instance *instance); + +S32 ps3_mgr_cmd_cancel_send(struct ps3_instance *instance, + U16 cancel_cmd_frame_id, U8 type); +S32 ps3_mgr_cmd_cancel_wait(struct ps3_instance *instance, U8 type); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_mgr_cmd_err.c b/drivers/scsi/ps3stor/ps3_mgr_cmd_err.c new file mode 100644 index 0000000000000000000000000000000000000000..8c0c921eeb7f86d5f2a793aa2311246669b0754a --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_mgr_cmd_err.c @@ -0,0 +1,254 @@ +#include "ps3_mgr_cmd_err.h" + +#ifndef _WINDOWS +#include +#include +#include +#include +#include + +#include +#endif + +#include "ps3_htp.h" + +#include "ps3_mgr_channel.h" +#include "ps3_mgr_cmd.h" +#include "ps3_driver_log.h" +#include "ps3_recovery.h" + +enum ps3_fault_action { + PS3_FAULT_STRATEGY_NONE = 0, + PS3_FAULT_STRATEGY_RETRY, +}; + +enum ps3_reset_type { + PS3_RESET_TYPE_SOFT, + PS3_RESET_TYPE_HARD, +}; + +struct ps3_fault_strategy { + U32 resp_status; + enum ps3_fault_action fault_action; +}; + +static struct ps3_fault_strategy ps3_fault_strategy_desc[] = { + {PS3_DRV_MGR_UNRUNING ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_INVAL_CMD ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_NORESOURCE ,PS3_FAULT_STRATEGY_RETRY}, + {PS3_DRV_MGR_INVAL_PARAM ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_DEV_NOEXIST ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_DEV_DATA_ERR ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_EVT_REPEAT ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_EVT_CANCLE_ERR ,PS3_FAULT_STRATEGY_NONE }, + {PS3_DRV_MGR_FLUSH_FAIELD ,PS3_FAULT_STRATEGY_RETRY}, + {PS3_DRV_MGR_BUSY ,PS3_FAULT_STRATEGY_RETRY}, + {PS3_DRV_MGR_TIMEOUT ,PS3_FAULT_STRATEGY_RETRY}, + {PS3_DRV_MGR_SMP_BACKEND_ERR, PS3_FAULT_STRATEGY_NONE}, + {PS3_DRV_MGR_LINK_GET_BACKEND_ERR, PS3_FAULT_STRATEGY_NONE}, + {PS3_DRV_MGR_PHY_CTL_BACKEND_ERR, PS3_FAULT_STRATEGY_NONE}, + {PS3_DRV_MGR_RESTART_COMMAND_RSP, PS3_FAULT_STRATEGY_NONE}, + {PS3_DRV_MGR_TM_FAILED, PS3_FAULT_STRATEGY_NONE}, + {U32_MAX ,PS3_FAULT_STRATEGY_NONE} +}; + +static inline const S8 *ps3_err_action_print(enum ps3_fault_action action) +{ + static const S8 *action_string[] = { + [PS3_FAULT_STRATEGY_NONE] = "PS3_FAULT_STRATEGY_NONE", + [PS3_FAULT_STRATEGY_RETRY] = "PS3_FAULT_STRATEGY_RETRY" + }; + + return action_string[action]; +} + +const S8 *ps3_err_mgr_fault_proc_result_print(S32 result) +{ + const S8 *proc_result_string = NULL; + + switch (result) + { + case PS3_SUCCESS: + proc_result_string = "SUCCESS"; + break; + case -PS3_RETRY: + proc_result_string = "NEED RETRY"; + break; + case -PS3_FAILED: + proc_result_string = "FAILED"; + break; + case -PS3_TIMEOUT: + proc_result_string = "TIMEOUT"; + break; + case -PS3_RESP_ERR: + proc_result_string = "RESPONSE ERROR"; + break; + case -PS3_RESP_INT: + proc_result_string = "RESPONSE INTERRUPTED"; + break; + case -PS3_CMD_NO_RESP: + proc_result_string = "PS3_CMD_NO_RESP"; + break; + default: + proc_result_string = "INVALID RESULT"; + break; + } + + return proc_result_string; +} + +static enum ps3_fault_action ps3_err_fault_strategy_lookup( + struct ps3_instance *instance, U32 resp_status, U32 retry_cnt) +{ + U32 idx = 0; + enum ps3_fault_action fault_action = PS3_FAULT_STRATEGY_RETRY; + + for (idx = 0;idx < ARRAY_SIZE(ps3_fault_strategy_desc);idx++) { + if (ps3_fault_strategy_desc[idx].resp_status == resp_status) { + fault_action + = ps3_fault_strategy_desc[idx].fault_action; + break; + } + } + + if ((fault_action == PS3_FAULT_STRATEGY_RETRY) + && (retry_cnt > 0)) { + fault_action = PS3_FAULT_STRATEGY_NONE; + } + + LOG_INFO("host_no:%u error_no:%d fault_action is %s!\n", PS3_HOST(instance), + resp_status,ps3_err_action_print(fault_action)); + return fault_action; +} + +static S32 ps3_err_fault_strategy_exec(struct ps3_instance *instance, + enum ps3_fault_action fault_action) +{ + S32 proc_result = -PS3_FAILED; + + switch (fault_action) { + case PS3_FAULT_STRATEGY_RETRY: + ps3_msleep(PS3_ERR_MGR_CMD_DELAY_TIME_BEFORE_RERTY); + proc_result = -PS3_RETRY; + default: + break; + } + + LOG_INFO("host_no:%u proc result for mgr cmd fault is %s!\n", + PS3_HOST(instance), ps3_err_mgr_fault_proc_result_print(proc_result)); + return proc_result; +} + +S32 ps3_err_mgr_cmd_failed_check(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + enum ps3_fault_action fault_action = PS3_FAULT_STRATEGY_NONE; + U32 resp_status = cmd->resp_frame->normalRespFrame.respStatus; + + if (!ps3_is_instance_state_allow_cmd_execute(instance)) { + ret = -PS3_FAILED; + goto l_out; + } + + fault_action = ps3_err_fault_strategy_lookup(instance, resp_status, cmd->retry_cnt); + ret = ps3_err_fault_strategy_exec(instance, fault_action); +l_out: + return ret; +} + +void ps3_err_fault_context_init(struct ps3_instance *instance) +{ + struct ps3_fault_context *fault_context = &instance->fault_context; + + memset(fault_context, 0, sizeof(*fault_context)); + ps3_atomic_set(&instance->is_err_scsi_processing, 0); + +} + +void ps3_err_fault_context_exit(struct ps3_instance *instance) +{ + struct ps3_fault_context *fault_context = &instance->fault_context; + + memset(fault_context, 0, sizeof(*fault_context)); +} + +S32 ps3_err_mgr_cmd_proc(struct ps3_instance *instance, + S32 fault_type, struct ps3_cmd *cmd) +{ + S32 proc_result = PS3_SUCCESS; + S32 ret = PS3_SUCCESS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + LOG_INFO("host_no:%u fault_type: %s, retries:%d!\n", + PS3_HOST(instance), + ps3_err_mgr_fault_proc_result_print(fault_type), cmd->retry_cnt); + + switch (fault_type) { + case PS3_SUCCESS: + break; + case -PS3_RESP_ERR: + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_IOCTL) { + LOG_INFO("host_no:%u CFID:%d trace_id:0x%llx cli return err:%u\n", + PS3_HOST(instance), + cmd->cmd_word.cmdFrameID, cmd->trace_id, ps3_cmd_resp_status(cmd)); + if (instance->is_probe_finish) { + if (ps3_cmd_resp_status(cmd) == PS3_DRV_MGR_BUSY) { + LOG_INFO("host_no:%u CFID:%d trace_id:0x%llx cli return busy\n", + PS3_HOST(instance), + cmd->cmd_word.cmdFrameID, cmd->trace_id); + if (ps3_instance_wait_for_normal(instance) == PS3_SUCCESS){ + cmd->req_frame->mgrReq.value.isRetry = PS3_TRUE; + proc_result = -PS3_RETRY; + } else { + proc_result = -PS3_FAILED; + } + } else if(ps3_cmd_resp_status(cmd) == PS3_DRV_MGR_RESTART_COMMAND_RSP){ + LOG_WARN("host_no:%u CFID:%d trace_id:0x%llx cli cx restart return success\n", + PS3_HOST(instance), + cmd->cmd_word.cmdFrameID, cmd->trace_id); + ps3_need_wait_hard_reset_request(instance); + INJECT_START(PS3_ERR_IJ_RECOVERY_WAIT_FUNC0_RUNNING_2, instance) + if (ps3_recovery_state_wait_for_normal(instance) == PS3_SUCCESS){ + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret != PS3_SUCCESS){ + LOG_WARN("host_no:%u hard recovery request NOK\n", + PS3_HOST(instance)); + } + } else { + proc_result = -PS3_FAILED; + } + } else { + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_QUIT || + cur_state == PS3_INSTANCE_STATE_DEAD) { + proc_result = -PS3_ENODEV; + } else { + proc_result = -PS3_FAILED; + } + } + } else { + proc_result = -PS3_FAILED; + } + } else { + proc_result = + ps3_err_mgr_cmd_failed_check(instance, cmd); + } + break; + case -PS3_TIMEOUT: + proc_result = -PS3_CMD_NO_RESP; + break; + default: + proc_result = -PS3_FAILED; + break; + } + + if (proc_result != -PS3_CMD_NO_RESP) { + cmd->cmd_state.reset_flag = 0; + } + + LOG_INFO("host_no:%u proc_result: %s, retries:%d!\n", + PS3_HOST(instance), + ps3_err_mgr_fault_proc_result_print(proc_result), cmd->retry_cnt); + + return proc_result; +} diff --git a/drivers/scsi/ps3stor/ps3_mgr_cmd_err.h b/drivers/scsi/ps3stor/ps3_mgr_cmd_err.h new file mode 100644 index 0000000000000000000000000000000000000000..4805dbbe4a5553d03e8536de891473a04b7da7bf --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_mgr_cmd_err.h @@ -0,0 +1,27 @@ + +#ifndef _PS3_MGR_CMD_ERR_H_ +#define _PS3_MGR_CMD_ERR_H_ + +#ifndef _WINDOWS +#include +#include +#endif + +#include "ps3_htp_def.h" +#include "ps3_instance_manager.h" + +#define PS3_ERR_MGR_CMD_FAULT_RETRY_MAX (3) +#define PS3_ERR_MGR_CMD_DELAY_TIME_BEFORE_RERTY (500) + +void ps3_err_fault_context_init(struct ps3_instance *instance); +void ps3_err_fault_context_exit(struct ps3_instance *instance); + +S32 ps3_err_mgr_cmd_proc(struct ps3_instance *instance, + S32 fault_type, struct ps3_cmd *cmd); + +S32 ps3_err_mgr_cmd_failed_check(struct ps3_instance *instance, + struct ps3_cmd *cmd); + +const S8 *ps3_err_mgr_fault_proc_result_print(S32 result); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_module_para.c b/drivers/scsi/ps3stor/ps3_module_para.c new file mode 100644 index 0000000000000000000000000000000000000000..2a89115a3b2342a8cb21981f644e9cc62d7f07ce --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_module_para.c @@ -0,0 +1,644 @@ + +#ifndef _WINDOWS +#include "linux/moduleparam.h" +#endif +#include "ps3_inner_data.h" +#include "ps3_module_para.h" +#include "ps3_driver_log.h" +#include "ps3_drv_ver.h" +#include "ps3_ioc_state.h" + +#ifndef _WINDOWS +static U32 cli_ver = PS3_IOCTL_VERSION; +module_param(cli_ver, uint, S_IRUGO | S_IRUSR); +MODULE_PARM_DESC(cli_ver, + "The version for communication between driver and CLI"); +#endif + +static U32 g_throttle_que_depth = PS3_DEVICE_QDEPTH_DEFAULT_VALUE; +#ifndef _WINDOWS +module_param(g_throttle_que_depth, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_throttle_que_depth, + "IOC queue depth when throttled due to SCSI cmd timeout. Default: 16"); +#endif +static U32 g_debug_mem_size = 0; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_debug_mem_size, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_debug_mem_size, + "Allocate DMA memory for IOC debugging little than 65535KB. Default: 0KB"); +#endif +#endif + +static U32 g_use_clustering = 1; +#ifndef _WINDOWS +module_param(g_use_clustering, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_use_clustering, + "SCSI mid-layer bio merge feature enable/disable. Default: enable(1)"); +#endif +static U32 g_scsi_cmd_timeout = 0; +#ifndef _WINDOWS +module_param(g_scsi_cmd_timeout, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_scsi_cmd_timeout, + "SCSI cmd timeout (10-255s). Default: 0(No specify default 90s)"); +#endif + +extern U32 g_ps3_r1x_lock_flag; +extern U32 g_ps3_r1x_lock_enable; +#ifndef _WINDOWS + +#if 0 +module_param(g_ps3_r1x_lock_flag, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_ps3_r1x_lock_flag, + "R1X write conflict check func. 0 - hash+bitmap, 1 - " + "hash+rangetree. Default: 0"); +#endif +module_param(g_ps3_r1x_lock_enable, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_ps3_r1x_lock_enable, + "R1x write conflict check feature enable/disable. Default: enable(1)"); +#endif + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +extern U32 g_ps3_qos_hdd_pd_quota; +extern U32 g_ps3_qos_nvme_pd_quota; +#ifndef _WINDOWS +module_param(g_ps3_qos_hdd_pd_quota, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_ps3_qos_hdd_pd_quota, + "Qos pd quota. Default: 40"); +module_param(g_ps3_qos_nvme_pd_quota, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_ps3_qos_nvme_pd_quota, + "Qos nvme pd quota. Default: 127"); +#endif + +extern U32 g_ps3_r1x_rb_diff_cmds; +#ifndef _WINDOWS +module_param(g_ps3_r1x_rb_diff_cmds, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_ps3_r1x_rb_diff_cmds, + "R1x read balancing outstanding threshold. Default: 4"); +#endif + +#endif + +static U32 g_direct_to_normal_enable = 1; +#ifndef _WINDOWS +module_param(g_direct_to_normal_enable, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_direct_to_normal_enable, + "Direct to normal feature enable/disable. Default: enable(1)"); +#endif + +static U32 g_hba_check_time = 10; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_hba_check_time, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_hba_check_time, "HBA device id check time out. Default: 10s"); +#endif +#endif + +static U32 g_task_reset_delay_time = 50; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_task_reset_delay_time, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_task_reset_delay_time, + "Task reset delay time (0-1000ms). Default: 50ms"); +#endif +#endif + +static U32 g_r1x_ring_size = 16; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_r1x_ring_size, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_r1x_ring_size, + "If R1X direct read more than g_r1x_ring_size, read from spare. Default: 16MB"); +#endif +#endif + +static U32 g_direct_check_stream_enable = PS3_TRUE; +#ifndef _WINDOWS +module_param(g_direct_check_stream_enable, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_direct_check_stream_enable, + "Direct detect stream or not feature enable/disable. Default: enable(1)"); +#endif + +static S32 g_device_busy_threshold = PS3_DEVICE_IO_BUSY_THRESHOLD; +#ifndef _WINDOWS +module_param(g_device_busy_threshold, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_device_busy_threshold, + "Device busy threshold value. Default: 8"); +#endif + +#ifndef __cplusplus +static char g_log_path[80] = {0}; +#ifndef _WINDOWS +module_param_string(g_log_path, g_log_path, 80, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_log_path, "The log path of host driver will be saved little than 80 chars. Default: /var/log"); +#endif +#endif + +static U32 g_log_file_size = 200; +#ifdef PS3_CFG_RELEASE +static U32 g_log_level = LEVEL_INFO; +#else +static U32 g_log_level = LEVEL_DEBUG; +#endif + +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +#ifndef _WINDOWS +module_param(g_log_file_size, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_log_file_size, + "Single driver log file size (10-200MB). Default: 200MB"); + +module_param(g_log_level, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_log_level, + "Specify driver log level." +#ifdef PS3_CFG_RELEASE + "0 - error, 1 - warn, 2 - info, 3 - debug. Default: 2"); +#else + "0 - error, 1 - warn, 2 - info, 3 - debug. Default: 3"); +#endif +#endif +#endif + +static U32 g_r1x_time_out = 3000; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) + +module_param(g_r1x_time_out, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_r1x_time_out, + "R1X conflict in queue after time. Default: 3000ms"); +#endif +#endif + +static U32 g_r1x_conflict_queue_enable = PS3_TRUE; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_r1x_conflict_queue_enable, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_r1x_conflict_queue_enable, + "R1X conflict queue function feature enable/disable. Default: enable(1)"); +#endif +#endif + +#ifndef _WINDOWS +#ifdef PS3_SUPPORT_INJECT +#define PS3_MAX_ERR_INJECT (16) +static U32 g_err_inject[PS3_MAX_ERR_INJECT]; +static U32 num_inject; +static U32 g_enable_inject = 0; +module_param_array(g_err_inject, uint, &num_inject, 0); +MODULE_PARM_DESC(g_err_inject, + "Err inject array. Default: 0"); +module_param(g_enable_inject, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_enable_inject, + "Err inject feature enable/disable. Default: disable(0)"); + +U32 ps3_err_inject_num_query(void) +{ + return num_inject; +} +U32* ps3_err_inject_array_query(void) +{ + return &g_err_inject[0]; +} +U32 ps3_err_inject_state_query(void) +{ + return g_enable_inject; +} + +#endif +#endif +static U32 g_log_space_size = 0; + +static U32 g_log_tty = 0; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_log_tty, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_log_tty, + "Allow driver log output to tty console feature enable/disable. Default: disable(0)"); +#endif +#endif + +#if defined PS3_HARDWARE_ASIC +static U32 g_hard_reset_enable = 1; +static U32 g_deep_soft_reset_enable = 0; +#elif (((defined PS3_HARDWARE_FPGA || defined PS3_HARDWARE_ASIC) \ + && defined PS3_MODEL_V200)\ + || defined(PS3_HARDWARE_HAPS_V200)) +static U32 g_hard_reset_enable = 1; +static U32 g_deep_soft_reset_enable = 0; +#else +static U32 g_hard_reset_enable = 0; +static U32 g_deep_soft_reset_enable = 0; +#endif +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_hard_reset_enable, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_hard_reset_enable, + "Hard reset feature enable/disable. Default: enable(1)"); +module_param(g_deep_soft_reset_enable, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_deep_soft_reset_enable, + "Deep soft reset feature enable/disable. Default: disable(0)"); +#endif +#endif + +static U32 g_aer_handle_support = 1; +#ifndef _WINDOWS +module_param(g_aer_handle_support, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_aer_handle_support, + "Driver aer handle support feature enable/disable. Default: enable(1)"); +#endif + +#ifndef __cplusplus +static char g_version_verbose[512] = {0}; +#ifndef _WINDOWS +module_param_string(g_version_verbose, g_version_verbose, 511, S_IRUGO); +MODULE_PARM_DESC(g_version_verbose, "Display detailed version information about ps3stor driver"); +#endif +#endif + +static U32 g_hard_reset_waiting = 0; +static U32 g_use_hard_reset_reg = 1; +static U32 g_use_hard_reset_max_retry = PS3_HARD_RESET_MAX_RETRY; + +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_hard_reset_waiting, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_hard_reset_waiting, + "Allow to access PCIe Config/BAR after xxx ms. Default: 0"); +module_param(g_use_hard_reset_reg, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_use_hard_reset_reg, + "Write hard reset reg triggered feature enable/disable. Default: enable(1)"); +module_param(g_use_hard_reset_max_retry, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_use_hard_reset_max_retry, + "Hard reset retry max count. Default: 2"); +#endif +#endif + +#if ((defined PS3_HARDWARE_FPGA && defined PS3_MODEL_V200) \ + || defined(PS3_HARDWARE_HAPS_V200) || defined(PS3_HARDWARE_ASIC)) +static U32 g_enable_heartbeat = 1; +module_param(g_enable_heartbeat, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_enable_heartbeat, + "Heartbeat query feature enable/disable. Default: enable(1)"); +#else +static U32 g_enable_heartbeat = 0; +module_param(g_enable_heartbeat, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_enable_heartbeat, + "Heartbeat query feature enable/disable. Default: disable(0)"); +#endif + +static U32 g_hil_mode = 0xFFFF; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_hil_mode, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_hil_mode, + "Set HIL operational mode." + "0 - SW mode, 1 - HW mode, 2 - Enhanced HW mode, 3 - SW assist mode. Default: 65535(0xFFFF)"); +#endif +#endif + +static U32 g_avaliable_func_id = 0xFF; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_avaliable_func_id, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_avaliable_func_id, + "Set function id." + "0 - Func0, 1 - Func1, 2 - Unlimited. Default: 255(0xFF)"); +#endif +#endif + +static U32 g_pci_irq_mode = PS3_PCI_IRQ_MODE_NONE_SPE; +#ifndef _WINDOWS +#if defined(PS3_SUPPORT_DEBUG) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_DBGBUG)) || \ + (defined(PS3_CFG_RELEASE) && defined(PS3_CFG_OCM_RELEASE)) +module_param(g_pci_irq_mode, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(g_pci_irq_mode, + "Specify pci irq mode." + "0 - none specify, 1 - legacy, 2 - msi, 3 - msix. Default: 0"); +#endif +#endif + +#if defined(PS3_TAGSET_SUPPORT) + +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 8) && (RHEL_MINOR > 5)) || \ + (defined(RHEL_MAJOR) && (RHEL_MAJOR == 9) && (RHEL_MINOR >= 1)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0))) +S32 g_ps3_tagset_enable = 1; +module_param(g_ps3_tagset_enable, int, 0444); +MODULE_PARM_DESC(g_ps3_tagset_enable, "Shared host tagset enable/disable. Default: enable(1)"); +#else +S32 g_ps3_tagset_enable = 0; +module_param(g_ps3_tagset_enable, int, 0444); +MODULE_PARM_DESC(g_ps3_tagset_enable, "Shared host tagset enable/disable. Default: disable(0)"); +#endif + +#endif + +static U32 g_smp_affinity_enable = 1; +module_param(g_smp_affinity_enable, int, 0444); +MODULE_PARM_DESC(g_smp_affinity_enable, "SMP affinity feature enable/disable. Default: enable(1)"); + +void ps3_version_verbose_fill(void) +{ +#ifndef __cplusplus + S32 len = 0; + S32 total_len = sizeof(g_version_verbose) - 1; + + memset(g_version_verbose, 0, sizeof(g_version_verbose)); + len += snprintf(g_version_verbose + len, total_len - len, "%-20s:%s\n", + "version", PS3_DRV_VERSION); + + len += snprintf(g_version_verbose + len, total_len - len, "%-20s:%s\n", + "commit_id", PS3_DRV_COMMIT_ID); + + len += snprintf(g_version_verbose + len, total_len - len, "%-20s:%s\n", + "toolchain_id", PS3_DRV_TOOLCHAIN_ID); + + len += snprintf(g_version_verbose + len, total_len - len, "%-20s:%s\n", + "build_time", PS3_DRV_BUILD_TIME); + + len += snprintf(g_version_verbose + len, total_len - len, "%-20s:%s\n", + "product_support", PS3_DRV_PRODUCT_SUPPORT); +#endif +} + +U32 ps3_throttle_qdepth_query(void) +{ + return g_throttle_que_depth; +} + +void ps3_debug_mem_size_modify(U32 size) +{ + g_debug_mem_size = size; +} + +U32 ps3_debug_mem_size_query(void) +{ + return g_debug_mem_size; +} + +U16 ps3_use_clustering_query(void) +{ + return (U16)g_use_clustering; +} + +void ps3_scsi_cmd_timeout_modify(U32 val) +{ + g_scsi_cmd_timeout = val; +} + +void ps3_scsi_cmd_timeout_adjust(void) +{ + + if (g_scsi_cmd_timeout != 0 && ( + g_scsi_cmd_timeout < PS3_SCSI_CMD_TIMEOUT_MIN || + g_scsi_cmd_timeout > PS3_SCSI_CMD_TIMEOUT_MAX)) { + g_scsi_cmd_timeout = PS3_SCSI_CMD_TIMEOUT_DEFAULT; + } +} + +U32 ps3_scsi_cmd_timeout_query(void) +{ + return g_scsi_cmd_timeout; +} + +U32 ps3_r1x_lock_flag_quiry(void) +{ + return g_ps3_r1x_lock_flag; +} + +void ps3_r1x_lock_flag_modify(U32 val) +{ + g_ps3_r1x_lock_flag = val; +} + +U32 ps3_direct_to_normal_query(void) +{ + return g_direct_to_normal_enable; +} + +void ps3_direct_to_normal_modify(U32 val) +{ + g_direct_to_normal_enable = val; +} + +U32 ps3_hba_check_time_query(void) +{ + return g_hba_check_time; +} + +U32 ps3_task_reset_delay_time_query(void) +{ + return g_task_reset_delay_time; +} + +U64 ps3_r1x_ring_size_query(void) +{ + U64 ring_size_byte = (U64)g_r1x_ring_size; + ring_size_byte = MB_TO_BYTE(ring_size_byte); + return ring_size_byte; +} + +void ps3_r1x_ring_size_modify(U32 size) +{ + g_r1x_ring_size = size; +} + +U32 ps3_direct_check_stream_query(void) +{ + return g_direct_check_stream_enable; +} + +void ps3_direct_check_stream_modify(U32 val) +{ + g_direct_check_stream_enable = val; +} + +S32 ps3_device_busy_threshold_query(void) +{ + return g_device_busy_threshold; +} + +void ps3_device_busy_threshold_modify(S32 busy) +{ + g_device_busy_threshold = busy; +} + +void ps3_log_level_modify(U32 level) +{ + ps3_level_set(level); +} + +char* ps3_log_path_query(void) +{ +#ifndef __cplusplus + return g_log_path; +#else + return NULL; +#endif +} + +U32 ps3_log_space_size_query(void) +{ + return g_log_space_size; +} + +U32 ps3_log_file_size_query(void) +{ + return g_log_file_size; +} + +U32 ps3_log_level_query(void) +{ + return g_log_level; +} + +void ps3_log_file_size_modify(U32 size) +{ + g_log_file_size = size; +} + +U32 ps3_log_tty_query(void) +{ + return g_log_tty; +} + +void ps3_log_tty_modify(U32 enable) +{ + g_log_tty = enable; +} + +void ps3_hard_reset_enable_modify(U32 val) +{ + g_hard_reset_enable = val; +} + +U32 ps3_hard_reset_enable_query(void) +{ + return g_hard_reset_enable; +} +U32 ps3_deep_soft_reset_enable_query(void) +{ + return g_deep_soft_reset_enable; +} +void ps3_deep_soft_reset_enable_modify(U32 val) +{ + g_deep_soft_reset_enable = val; +} + +U32 ps3_aer_handle_support_query(void) +{ + return g_aer_handle_support; +} + +void ps3_aer_handle_support_set(U32 aer_handle_support) +{ + g_aer_handle_support = aer_handle_support; +} + +U32 ps3_hard_reset_waiting_query(void) +{ + return g_hard_reset_waiting; +} + +U32 ps3_use_hard_reset_reg_query(void) +{ + return g_use_hard_reset_reg; +} +U32 ps3_use_hard_reset_max_retry(void) +{ + return g_use_hard_reset_max_retry; +} + +U32 ps3_enable_heartbeat_query(void) +{ + return g_enable_heartbeat; +} + +U32 ps3_enable_heartbeat_set(U32 val) +{ + return g_enable_heartbeat = val; +} + +U32 ps3_hil_mode_query(void) +{ + return g_hil_mode; +} + +void ps3_hil_mode_modify(U32 val) +{ + g_hil_mode = val; + return; +} + +U32 ps3_avaliable_func_id_query(void) +{ + return g_avaliable_func_id; +} + +void ps3_avaliable_func_id_modify(U32 val) +{ + g_avaliable_func_id = val; + return; +} + +U32 ps3_r1x_tmo_query(void) +{ + if (unlikely(g_r1x_time_out > 360000)) { + g_r1x_time_out = 360000; + } + return g_r1x_time_out * HZ / 1000; +} + +U32 ps3_r1x_conflict_queue_support_query(void) +{ + return g_r1x_conflict_queue_enable; +} + +U32 ps3_pci_irq_mode_query(void) +{ + return g_pci_irq_mode; +} + +U32 ps3_cli_ver_query(void) +{ + return cli_ver; +} +#if defined(PS3_TAGSET_SUPPORT) + +Bool ps3_tagset_enable_query(void) +{ + return (g_ps3_tagset_enable == 1) ? PS3_TRUE: PS3_FALSE; +} +#endif + +Bool ps3_smp_affinity_query(void) +{ + return (g_smp_affinity_enable == 1) ? PS3_TRUE: PS3_FALSE; +} + diff --git a/drivers/scsi/ps3stor/ps3_module_para.h b/drivers/scsi/ps3stor/ps3_module_para.h new file mode 100644 index 0000000000000000000000000000000000000000..3428fbce9e1197948ee1c0c854d3017b6ec2e5d3 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_module_para.h @@ -0,0 +1,121 @@ + +#ifndef _PS3_MODULE_PARA_H_ +#define _PS3_MODULE_PARA_H_ + +#include "ps3_types.h" + +#define MB_TO_BYTE(MB) ((MB) << 20) +#define PS3_MAX_FUNC_ID (2) + +U32 ps3_throttle_qdepth_query(void); + +void ps3_debug_mem_size_modify(U32 size); + +U32 ps3_debug_mem_size_query(void); + +U32 ps3_sata_direct_query(void); + +void ps3_sata_direct_modify(U32 val); + +U16 ps3_use_clustering_query(void); + +void ps3_scsi_cmd_timeout_modify(U32 val); + +U32 ps3_scsi_cmd_timeout_query(void); + +void ps3_scsi_cmd_timeout_adjust(void); + +U32 ps3_r1x_lock_flag_quiry(void); + +void ps3_r1x_lock_flag_modify(U32 val); + +U32 ps3_direct_to_normal_query(void); + +void ps3_direct_to_normal_modify(U32 val); + +U32 ps3_hba_check_time_query(void); + +U32 ps3_task_reset_delay_time_query(void); + +U64 ps3_r1x_ring_size_query(void); + +void ps3_r1x_ring_size_modify(U32 size); + +U32 ps3_direct_check_stream_query(void); + +S32 ps3_device_busy_threshold_query(void); + +void ps3_device_busy_threshold_modify(S32 busy); + +void ps3_log_level_modify(U32 level); + +char* ps3_log_path_query(void); + +U32 ps3_log_space_size_query(void); + +U32 ps3_log_file_size_query(void); + +void ps3_log_file_size_modify(U32 size); + +U32 ps3_log_level_query(void); + +U32 ps3_log_tty_query(void); + +void ps3_log_tty_modify(U32 enable); + +void ps3_hard_reset_enable_modify(U32 val); +void ps3_deep_soft_reset_enable_modify(U32 val); + +U32 ps3_hard_reset_enable_query(void); +U32 ps3_deep_soft_reset_enable_query(void); + +U32 ps3_log_level_query(void); + +U32 ps3_aer_handle_support_query(void); + +void ps3_aer_handle_support_set(U32 aer_handle_support); + +void ps3_version_verbose_fill(void); + +U32 ps3_hard_reset_waiting_query(void); + +U32 ps3_use_hard_reset_reg_query(void); +U32 ps3_use_hard_reset_max_retry(void); + +U32 ps3_enable_heartbeat_query(void); + +U32 ps3_enable_heartbeat_set(U32 val); + +U32 ps3_hil_mode_query(void); + +void ps3_hil_mode_modify(U32 val); + +U32 ps3_avaliable_func_id_query(void); + +void ps3_avaliable_func_id_modify(U32 val); + +void ps3_direct_check_stream_modify(U32 val); + +U32 ps3_r1x_tmo_query(void); + +U32 ps3_r1x_conflict_queue_support_query(void); + +U32 ps3_pci_irq_mode_query(void); + +#if defined(PS3_TAGSET_SUPPORT) + +Bool ps3_tagset_enable_query(void); +#endif + +Bool ps3_smp_affinity_query(void); + +#ifndef _WINDOWS +#ifdef PS3_SUPPORT_INJECT +U32 ps3_err_inject_num_query(void); +U32* ps3_err_inject_array_query(void); +U32 ps3_err_inject_state_query(void); + +#endif +#endif + +#endif diff --git a/drivers/scsi/ps3stor/ps3_nvme_resp_to_scsi.c b/drivers/scsi/ps3stor/ps3_nvme_resp_to_scsi.c new file mode 100644 index 0000000000000000000000000000000000000000..e799e954a1b7e0c7c913dc5db6f9ea3505e0df4f --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_nvme_resp_to_scsi.c @@ -0,0 +1,389 @@ + +#include + +#include "ps3_nvme_spec.h" +#include "ps3_nvme_resp_to_scsi.h" +#include "ps3_instance_manager.h" +#include "ps3_htp_def.h" +#include "ps3_htp.h" + +enum { + SENSE_KEY_NO_SENSE = 0x00, + SENSE_KEY_RECOVERED_ERROR = 0x01, + SENSE_KEY_NOT_READY = 0x02, + SENSE_KEY_MEDIUM_ERROR = 0x03, + SENSE_KEY_HARDWARE_ERROR = 0x04, + SENSE_KEY_ILLEGAL_REQUEST = 0x05, + SENSE_KEY_UNIT_ATTENTION = 0x06, + SENSE_KEY_DATA_PROTECT = 0x07, + SENSE_KEY_BLANK_CHECK = 0x08, + SENSE_KEY_VENDOR_SPECIFIC = 0x09, + SENSE_KEY_COPY_ABORTED = 0x0a, + SENSE_KEY_ABORTED_COMMAND = 0x0b, + SENSE_KEY_VOLUME_OVERFLOW = 0x0d, + SENSE_KEY_MISCOMPARE = 0x0e, +} ; + +enum { + SCSI_ASC_NO_ADDITIONAL_SENSE = 0x00, + SCSI_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03, + SCSI_ASC_LOGICAL_UNIT_NOT_READY = 0x04, + SCSI_ASC_WARNING = 0x0b, + SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAILED = 0x10, + SCSI_ASC_LOGICAL_BLOCK_APPTAG_CHECK_FAILED = 0x10, + SCSI_ASC_LOGICAL_BLOCK_REFTAG_CHECK_FAILED = 0x10, + SCSI_ASC_UNRECOVERED_READ_ERROR = 0x11, + SCSI_ASC_MISCOMPARE_DURING_VERIFY_OPERATION = 0x1d, + SCSI_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20, + SCSI_ASC_ACCESS_DENIED = 0x20, + SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE = 0x21, + SCSI_ASC_INVALID_FIELD_IN_CDB = 0x24, + SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED = 0x25, + SCSI_ASC_WRITE_PROTECTED = 0x27, + SCSI_ASC_FORMAT_COMMAND_FAILED = 0x31, + SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED = 0x39, + SCSI_ASC_INTERNAL_TARGET_FAILURE = 0x44, + SCSI_ASC_DATA_PHASE_ERROR = 0x4b, +} ; + +typedef enum ScsiAscq { + SCSI_ASCQ_CAUSE_NOT_REPORTABLE = 0x00, + SCSI_ASCQ_BECOMING_READY = 0x01, + SCSI_ASCQ_FORMAT_COMMAND_FAILED = 0x01, + SCSI_ASCQ_LOGICAL_BLOCK_GUARD_CHECK_FAILED = 0x01, + SCSI_ASCQ_LOGICAL_BLOCK_APPTAG_CHECK_FAILED = 0x02, + SCSI_ASCQ_NO_ACCESS_RIGHTS = 0x02, + SCSI_ASCQ_LOGICAL_BLOCK_REFTAG_CHECK_FAILED = 0x03, + SCSI_ASCQ_SANITIZE_COMMAND_FAILED = 0x03, + SCSI_ASCQ_LOGICAL_UNIT_NOT_READY_FORMAT_IN_PROGRESS = 0x04, + SCSI_ASCQ_DATA_OFFSET_ERROR = 0x05, + SCSI_ASCQ_POWER_LOSS_EXPECTED = 0x08, + SCSI_ASCQ_INVALID_LU_IDENTIFIER = 0x09, + SCSI_ASCQ_SDBP_INCOMING_BUFFER_OVERFLOW = 0x0C, + SCSI_ASCQ_WARNING_MICROCODE_DIGITAL_SIGNATURE_VALIDATION_FAILURE = 0x13, + SCSI_ASCQ_ERASE_OPEARTION_IN_PROGRESS = 0x18, + SCSI_ASCQ_LOGICAL_UNIT_NOT_READY_SANITIZE_IN_PROGRESS = 0x1b, +} ScsiAscq_e; + +#define PS3_MEDIUM_ERROR_LEN (4) +static void ps3_nvme_generic_error_to_scsi_status(U8 nvmeSc, ps3_nvme_scsi_status *cpl) +{ + switch (nvmeSc) { + case NVME_SC_SUCCESS: + cpl->status = SCSI_STATUS_GOOD; + cpl->senseKey = SENSE_KEY_NO_SENSE; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_INVALID_OPCODE: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_INVALID_COMMAND_OPERATION_CODE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_INVALID_FIELD: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_INVALID_FIELD_IN_CDB; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_DATA_TRANSFER_ERROR: + case NVME_SC_CAPACITY_EXCEEDED: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_MEDIUM_ERROR; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_ABORTED_POWER_LOSS: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_WARNING; + cpl->ascq = SCSI_ASCQ_POWER_LOSS_EXPECTED; + break; + case NVME_SC_INTERNAL_DEVICE_ERROR: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_HARDWARE_ERROR; + cpl->asc = SCSI_ASC_INTERNAL_TARGET_FAILURE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_ABORTED_BY_REQUEST: + case NVME_SC_ABORTED_SQ_DELETION: + case NVME_SC_ABORTED_FAILED_FUSED: + case NVME_SC_ABORTED_MISSING_FUSED: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_INVALID_NAMESPACE_OR_FORMAT: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_ACCESS_DENIED; + cpl->ascq = SCSI_ASCQ_INVALID_LU_IDENTIFIER; + break; + case NVME_SC_LBA_OUT_OF_RANGE: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_NAMESPACE_NOT_READY: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_NOT_READY; + cpl->asc = SCSI_ASC_LOGICAL_UNIT_NOT_READY; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_RESERVATION_CONFLICT: + cpl->status = SCSI_STATUS_RESERVATION_CONFLICT; + cpl->senseKey = SENSE_KEY_NO_SENSE; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_COMMAND_ID_CONFLICT: + case NVME_SC_COMMAND_SEQUENCE_ERROR: + case NVME_SC_INVALID_SGL_SEG_DESCRIPTOR: + case NVME_SC_INVALID_NUM_SGL_DESCIRPTORS: + case NVME_SC_DATA_SGL_LENGTH_INVALID: + case NVME_SC_METADATA_SGL_LENGTH_INVALID: + case NVME_SC_SGL_DESCRIPTOR_TYPE_INVALID: + case NVME_SC_INVALID_CONTROLLER_MEM_BUF: + case NVME_SC_INVALID_PRP_OFFSET: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_DATA_PHASE_ERROR; + cpl->ascq = SCSI_ASCQ_DATA_OFFSET_ERROR; + break; + case NVME_SC_ATOMIC_WRITE_UNIT_EXCEEDED: + case NVME_SC_INVALID_SGL_OFFSET: + case NVME_SC_HOSTID_INCONSISTENT_FORMAT: + case NVME_SC_KEEP_ALIVE_EXPIRED: + case NVME_SC_KEEP_ALIVE_INVALID: + case NVME_SC_FORMAT_IN_PROGRESS: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_NOT_READY; + cpl->asc = SCSI_ASC_LOGICAL_UNIT_NOT_READY; + cpl->ascq = SCSI_ASCQ_LOGICAL_UNIT_NOT_READY_FORMAT_IN_PROGRESS; + break; + case NVME_SC_SANITIZE_FAILED: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_MEDIUM_ERROR; + cpl->asc = SCSI_ASC_FORMAT_COMMAND_FAILED; + cpl->ascq = SCSI_ASCQ_SANITIZE_COMMAND_FAILED; + break; + case NVME_SC_SANITIZE_IN_PROGRESS: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_NOT_READY; + cpl->asc = SCSI_ASC_LOGICAL_UNIT_NOT_READY; + cpl->ascq = SCSI_ASCQ_LOGICAL_UNIT_NOT_READY_SANITIZE_IN_PROGRESS; + break; + case NVME_SC_NAMESPACE_IS_WRITE_PROTECTED: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_DATA_PROTECT; + cpl->asc = SCSI_ASC_WRITE_PROTECTED; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_SC_COMMAND_INTERRUPTED: + case NVME_SC_TRANSIENT_TRANSPORT_ERROR: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + default: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + } +} + +static void ps3_nvme_spec_error_to_scsi_status(U8 nvmeSc, ps3_nvme_scsi_status *cpl) +{ + switch (nvmeSc) { + case NVME_CSC_COMPLETION_QUEUE_INVALID: + case NVME_CSC_ABORT_COMMAND_LIMIT_EXCEEDED: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_CSC_INVALID_FORMAT: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_FORMAT_COMMAND_FAILED; + cpl->ascq = SCSI_ASCQ_FORMAT_COMMAND_FAILED; + break; + case NVME_CSC_CONFLICTING_ATTRIBUTES: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_INVALID_FIELD_IN_CDB; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_CSC_ATTEMPTED_WRITE_TO_RO_RANGE: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_DATA_PROTECT; + cpl->asc = SCSI_ASC_WRITE_PROTECTED; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_CSC_INVALID_QUEUE_IDENTIFIER: + case NVME_CSC_MAXIMUM_QUEUE_SIZE_EXCEEDED: + case NVME_CSC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED: + case NVME_CSC_FIRMWARE_REQ_NVM_RESET: + case NVME_CSC_INVALID_PROTECTION_INFO: + case NVME_CSC_FIRMWARE_REQ_MAX_TIME_VIOLATION: + case NVME_CSC_FIRMWARE_ACTIVATION_PROHIBITED: + case NVME_CSC_BOOT_PARTITION_WRITE_PROHIBITED: + case NVME_CSC_INVALID_FIRMWARE_SLOT: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_CSC_INVALID_FIRMWARE_IMAGE: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_WARNING; + cpl->ascq = SCSI_ASCQ_WARNING_MICROCODE_DIGITAL_SIGNATURE_VALIDATION_FAILURE; + break; + case NVME_CSC_INVALID_INTERRUPT_VECTOR: + case NVME_CSC_INVALID_LOG_PAGE: + case NVME_CSC_FIRMWARE_REQ_CONVENTIONAL_RESET: + case NVME_CSC_INVALID_QUEUE_DELETION: + case NVME_CSC_FEATURE_ID_NOT_SAVEABLE: + case NVME_CSC_FEATURE_NOT_CHANGEABLE: + case NVME_CSC_FEATURE_NOT_NAMESPACE_SPECIFIC: + case NVME_CSC_FIRMWARE_REQ_RESET: + case NVME_CSC_OVERLAPPING_RANGE: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_INVALID_FIELD_IN_CDB; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_CSC_NAMESPACE_INSUFFICIENT_CAPACITY: + case NVME_CSC_NAMESPACE_ID_UNAVAILABLE: + case NVME_CSC_NAMESPACE_ALREADY_ATTACHED: + case NVME_CSC_NAMESPACE_IS_PRIVATE: + case NVME_CSC_NAMESPACE_NOT_ATTACHED: + case NVME_CSC_THINPROVISIONING_NOT_SUPPORTED: + case NVME_CSC_CONTROLLER_LIST_INVALID: + + default: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + } +} + +static void ps3_nvme_media_error_to_scsi_status(U8 nvmeSc, ps3_nvme_scsi_status *cpl) +{ + switch (nvmeSc) { + case NVME_MSC_WRITE_FAULTS: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_MEDIUM_ERROR; + cpl->asc = SCSI_ASC_PERIPHERAL_DEVICE_WRITE_FAULT; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_MSC_UNRECOVERED_READ_ERROR: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_MEDIUM_ERROR; + cpl->asc = SCSI_ASC_UNRECOVERED_READ_ERROR; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_MSC_GUARD_CHECK_ERROR: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_LOGICAL_BLOCK_GUARD_CHECK_FAILED; + cpl->ascq = SCSI_ASCQ_LOGICAL_BLOCK_GUARD_CHECK_FAILED; + break; + case NVME_MSC_APPLICATION_TAG_CHECK_ERROR: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_LOGICAL_BLOCK_APPTAG_CHECK_FAILED; + cpl->ascq = SCSI_ASCQ_LOGICAL_BLOCK_APPTAG_CHECK_FAILED; + break; + case NVME_MSC_REFERENCE_TAG_CHECK_ERROR: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ABORTED_COMMAND; + cpl->asc = SCSI_ASC_LOGICAL_BLOCK_REFTAG_CHECK_FAILED; + cpl->ascq = SCSI_ASCQ_LOGICAL_BLOCK_REFTAG_CHECK_FAILED; + break; + case NVME_MSC_COMPARE_FAILURE: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_MISCOMPARE; + cpl->asc = SCSI_ASC_MISCOMPARE_DURING_VERIFY_OPERATION; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + case NVME_MSC_ACCESS_DENIED: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_DATA_PROTECT; + cpl->asc = SCSI_ASC_ACCESS_DENIED; + cpl->ascq = SCSI_ASCQ_NO_ACCESS_RIGHTS; + break; + case NVME_MSC_DEALLOCATED_OR_UNWRITTEN_BLOCK: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_MEDIUM_ERROR; + cpl->asc = SCSI_ASC_UNRECOVERED_READ_ERROR; + cpl->ascq = SCSI_ASCQ_SDBP_INCOMING_BUFFER_OVERFLOW; + break; + default: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + } +} + +void ps3_nvme_error_to_scsi_status(PS3NvmeCmdStatus_s status, ps3_nvme_scsi_status *cpl) +{ + U8 sct = status.sct; + U8 sc = status.sc; + + switch (sct) { + case NVME_SCT_GENERIC: + ps3_nvme_generic_error_to_scsi_status(sc, cpl); + break; + case NVME_SCT_COMMAND_SPECIFIC: + ps3_nvme_spec_error_to_scsi_status(sc, cpl); + break; + case NVME_SCT_MEDIA_ERROR: + ps3_nvme_media_error_to_scsi_status(sc, cpl); + break; + case NVME_SCT_VENDOR_SPECIFIC: + default: + cpl->status = SCSI_STATUS_CHECK_CONDITION; + cpl->senseKey = SENSE_KEY_ILLEGAL_REQUEST; + cpl->asc = SCSI_ASC_NO_ADDITIONAL_SENSE; + cpl->ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; + break; + } +} + +void ps3_nvme_resp_to_scsi_status(struct ps3_cmd *cmd) +{ + PS3NvmeCmdStatus_s status; + ps3_nvme_scsi_status cpl; + + status.cmdStatus = cmd->reply_word.retStatus; + LOG_FILE_ERROR("trace_id:0x%llx host_no:%d tag:%d nvme status:" + "sc:%d sct:%d crd:%d more:%d dnr:%d p:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->index, status.sc, status.sct, status.crd, + status.m, status.dnr, status.p); + + memset(&cpl, 0, sizeof(ps3_nvme_scsi_status)); + ps3_nvme_error_to_scsi_status(status, &cpl); + + memset(cmd->resp_frame->sasRespFrame.data, 0, PS3_SENSE_BUFFER_SIZE); + scsi_build_sense_buffer(0, cmd->resp_frame->sasRespFrame.data, + cpl.senseKey, cpl.asc, cpl.ascq); + if (cmd->reply_word.mode == PS3_REPLY_WORD_MODE_DIRECT_OK && + cpl.senseKey == SENSE_KEY_MEDIUM_ERROR) { + memset(&cmd->resp_frame->sasRespFrame.data[3], 0xff, PS3_MEDIUM_ERROR_LEN); + } + cmd->resp_frame->sasRespFrame.status = cpl.status; + +} diff --git a/drivers/scsi/ps3stor/ps3_nvme_resp_to_scsi.h b/drivers/scsi/ps3stor/ps3_nvme_resp_to_scsi.h new file mode 100644 index 0000000000000000000000000000000000000000..35206918ee8a073920e584afb5b31dabfefe8491 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_nvme_resp_to_scsi.h @@ -0,0 +1,13 @@ + +#include "ps3_cmd_channel.h" + +typedef struct ps3_nvme_scsi_status { + U8 status; + U8 senseKey; + U8 asc; + U8 ascq; +} ps3_nvme_scsi_status; + +void ps3_nvme_error_to_scsi_status(PS3NvmeCmdStatus_s status, ps3_nvme_scsi_status *cpl); + +void ps3_nvme_resp_to_scsi_status(struct ps3_cmd *cmd); \ No newline at end of file diff --git a/drivers/scsi/ps3stor/ps3_pci.c b/drivers/scsi/ps3stor/ps3_pci.c new file mode 100644 index 0000000000000000000000000000000000000000..689527f62f8c378be79d1035ffc8c85c3e633d15 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_pci.c @@ -0,0 +1,461 @@ + +#include "ps3_instance_manager.h" +#include "ps3_pci.h" + +#define PS3_VALID_MEMORY_BAR_INDEX 2 +#ifdef _WINDOWS +#define PS3_CHECK_BAR_64BIT(bar) ((bar)&0x4) +#define PS3_CHECK_BAR_MEMORYSPACE(bar) (!((bar)&0x1)) +#define PS3_BAR_BASE_ADDR_MARSK (0xFFFFFFF0) +#define PS3_GET_BAR_BASE_ADDR(addr) (U64)((addr) & PS3_BAR_BASE_ADDR_MARSK) + +static S32 ps3_pci_map_reg(struct ps3_instance *instance, PPORT_CONFIGURATION_INFORMATION config); +static S32 ps3_pci_info_get(struct ps3_instance *instance, PPORT_CONFIGURATION_INFORMATION config); +static void ps3_pci_unmap_reg(struct ps3_instance *instance); +static void ps3_pci_irq_type_get(struct ps3_instance *instance, PPCI_COMMON_CONFIG pci_config); +static U16 ps3_pci_msix_vec_count(struct ps3_instance *instance, PPCI_COMMON_CONFIG pci_config); +static U16 ps3_pci_msi_vec_count(struct ps3_instance *instance, PPCI_COMMON_CONFIG pci_config); + +S32 ps3_pci_init(struct ps3_instance *instance, void *config) +{ + S32 ret = PS3_SUCCESS; + PPORT_CONFIGURATION_INFORMATION config_info = (PPORT_CONFIGURATION_INFORMATION)config; + + ret = ps3_pci_info_get(instance, config_info); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + ret = ps3_pci_map_reg(instance, config_info); + if (ret != PS3_SUCCESS) { + goto l_out; + } + +l_out: + return ret; +} + +void ps3_pci_exit(struct ps3_instance *instance) +{ + ps3_pci_unmap_reg(instance); +} + +static S32 ps3_pci_info_get( + struct ps3_instance *instance, + PPORT_CONFIGURATION_INFORMATION config +) +{ + PCI_COMMON_CONFIG pci_config = { 0 }; + ULong len = 0; + ULong base_addr = 0; +#ifdef PS3_HARDWARE_ASIC + U32 check_count = ps3_hba_check_time_query() * 10; +#endif + + if (config->AdapterInterfaceType != PCIBus) { + LOG_ERROR("there is not pcibus, type:%d\n", config->AdapterInterfaceType); + return -PS3_FAILED; + } + + len = StorPortGetBusData(instance, + PCIConfiguration, + config->SystemIoBusNumber, + (ULong)config->SlotNumber, + (void*)&pci_config, + sizeof(pci_config)); + + if (len == 0 || len == 2) { + LOG_ERROR("get bus data failed,cfg length:%d\n", len); + return -PS3_FAILED; + } + +#ifdef PS3_HARDWARE_ASIC + while(pci_config.DeviceID == PCI_DEVICE_ID_PS3_RAID_FPGA && + check_count > 0) { + + check_count--; + ps3_msleep(100); + + len = StorPortGetBusData(instance, + PCIConfiguration, + config->SystemIoBusNumber, + (ULong)config->SlotNumber, + (void*)&pci_config, + sizeof(pci_config)); + + if (len == 0 || len == 2) { + LOG_ERROR("get bus data failed,cfg length:%d\n", len); + return -PS3_FAILED; + } + + LOG_INFO("get real device id is[0x%x] \n", pci_config.DeviceID); + }; +#endif + + instance->pci_dev_context.slot_number = (U64)config->SlotNumber; + instance->pci_dev_context.device_id = pci_config.DeviceID; + instance->pci_dev_context.vendor_id = pci_config.VendorID; + instance->pci_dev_context.sub_vendor_id = pci_config.u.type0.SubVendorID; + instance->pci_dev_context.sub_device_id = pci_config.u.type0.SubSystemID; + + base_addr = pci_config.u.type0.BaseAddresses[PS3_VALID_MEMORY_BAR_INDEX]; + if (!PS3_CHECK_BAR_MEMORYSPACE(base_addr)) { + LOG_ERROR("Bar%d is not memory space\n", PS3_VALID_MEMORY_BAR_INDEX); + return -PS3_FAILED; + } + + if (PS3_CHECK_BAR_64BIT(base_addr)) { + instance->pci_dev_context.bar_base_addr = + PS3_GET_BAR_BASE_ADDR(base_addr); + base_addr = pci_config.u.type0.BaseAddresses[PS3_VALID_MEMORY_BAR_INDEX + 1]; + instance->pci_dev_context.bar_base_addr |= ((U64)base_addr) << 32; + } + else { + instance->pci_dev_context.bar_base_addr = + PS3_GET_BAR_BASE_ADDR(base_addr); + } + + ps3_pci_irq_type_get(instance, &pci_config); + + if (instance->pci_dev_context.pci_irq_type == PS3_PCI_IRQ_MSIX) { + instance->pci_dev_context.irq_vec_count = ps3_pci_msix_vec_count(instance, &pci_config); + } + else if (instance->pci_dev_context.pci_irq_type == PS3_PCI_IRQ_MSI) { + instance->pci_dev_context.irq_vec_count = ps3_pci_msi_vec_count(instance, &pci_config); + } + else { + instance->pci_dev_context.irq_vec_count = 1; + } + + LOG_INFO("vid:%x, devid:%x, sub_vid:%x, sub_devid:%x, bar_base:0x%llx, irq_type:%d, vec_count:%d\n", + instance->pci_dev_context.vendor_id, + instance->pci_dev_context.device_id, + instance->pci_dev_context.sub_vendor_id, + instance->pci_dev_context.sub_device_id, + instance->pci_dev_context.bar_base_addr, + instance->pci_dev_context.pci_irq_type, + instance->pci_dev_context.irq_vec_count); + + return PS3_SUCCESS; +}; + +static S32 ps3_pci_map_reg(struct ps3_instance *instance, PPORT_CONFIGURATION_INFORMATION config) +{ + S32 ret = -PS3_FAILED; + ULong i = 0; + + if (config->NumberOfAccessRanges <= 0) { + LOG_ERROR("valid access range is 0\n"); + goto l_out; + } + + if (config->AdapterInterfaceType != PCIBus) { + LOG_ERROR("adapter interface type is not PCIBus\n"); + goto l_out; + } + + for (i = 0; i < config->NumberOfAccessRanges; i++) { + + LOG_DEBUG("Bar%llu:0x%llx, memory:%d, len:0x%x, ex:0x%llx\n", i, + (*(config->AccessRanges))[i].RangeStart.QuadPart, (*(config->AccessRanges))[i].RangeInMemory, + (*(config->AccessRanges))[i].RangeLength, + instance->pci_dev_context.bar_base_addr); + if ((U64)(*(config->AccessRanges))[i].RangeStart.QuadPart != instance->pci_dev_context.bar_base_addr) { + continue; + } + + if (!(*(config->AccessRanges))[i].RangeInMemory) { + LOG_INFO("access range number continue:%d, is not memery\n", i); + continue; + } + + instance->reg_set = (Ps3Fifo_s*)StorPortGetDeviceBase(instance, + config->AdapterInterfaceType, + config->SystemIoBusNumber, + (*(config->AccessRanges))[i].RangeStart, + (*(config->AccessRanges))[i].RangeLength, + 0); + + if (instance->reg_set != NULL) { + ret = PS3_SUCCESS; + } + + break; + } + +l_out: + LOG_INFO("map reg:%d,reg:%p\n", ret, instance->reg_set); + return ret; +} + +static void ps3_pci_unmap_reg(struct ps3_instance *instance) +{ + if (instance->reg_set != NULL) { + StorPortFreeDeviceBase(instance, instance->reg_set); + instance->reg_set = NULL; + } +} + +static S32 __ps3_pci_find_capability(PPCI_COMMON_CONFIG pci_config, S32 cap_id) +{ + S32 pos = 0; + U8 *config_base_addr = (U8*)pci_config; + U8 cap_offset = 0; + PPCI_CAPABILITIES_HEADER cap_header = NULL; + + if (PCI_CONFIGURATION_TYPE(pci_config)) { + LOG_ERROR("there is not agent device\n"); + goto l_out; + } + + if ((pci_config->Status & PCI_STATUS_CAPABILITIES_LIST) == 0) { + LOG_ERROR("capability pointer invalid\n"); + goto l_out; + } + + cap_offset = pci_config->u.type0.CapabilitiesPtr; + while (cap_offset != 0) { + cap_header = (PPCI_CAPABILITIES_HEADER)(config_base_addr + cap_offset); + if (cap_header->CapabilityID == 0) { + cap_offset = cap_header->Next; + continue; + } + + if (cap_header->CapabilityID == (U8)cap_id) { + pos = cap_offset; + break; + + } + cap_offset = cap_header->Next; + }; + +l_out: + return pos; +} + +static void ps3_pci_irq_type_get(struct ps3_instance *instance, PPCI_COMMON_CONFIG pci_config) +{ + U8 *config_base_addr = (U8*)pci_config; + U16 data_u16 = 0; + S32 pos = 0; + + instance->pci_dev_context.pci_irq_type = PS3_PCI_IRQ_LEGACY; + pos = __ps3_pci_find_capability(pci_config, PCI_CAP_ID_MSIX); + if ( pos != 0) { + data_u16 = *( (U16*)(config_base_addr + pos + PCI_MSIX_FLAGS) ); + + for (size_t i = 0; i < 4; i++) + { + U8 tmp = *((U8*)(config_base_addr + pos + i)); + LOG_DEBUG("%d:%d:%x\n", pos, i, tmp); + } + + if ((data_u16 & PCI_MSIX_FLAGS_ENABLE) == PCI_MSIX_FLAGS_ENABLE) { + instance->pci_dev_context.pci_irq_type = PS3_PCI_IRQ_MSIX; + goto l_out; + } + } + + pos = __ps3_pci_find_capability(pci_config, PCI_CAP_ID_MSI); + if (pos != 0) { + data_u16 = *((U16*)(config_base_addr + pos + PCI_MSI_FLAGS)); + if ( (data_u16 & PCI_MSI_FLAGS_ENABLE) == PCI_MSI_FLAGS_ENABLE) { + instance->pci_dev_context.pci_irq_type = PS3_PCI_IRQ_MSI; + goto l_out; + } + } + +l_out: + return; +} + +void ps3_pci_intx(struct ps3_instance *instance, U8 enable) +{ + U16 pci_command = 0; + U16 pci_command_new = 0; + if (ps3_pci_read_config_word(instance, PCI_COMMAND, &pci_command) != PS3_SUCCESS) { + goto l_out; + } + + if (enable) { + pci_command_new = pci_command & ~PCI_COMMAND_INTX_DISABLE; + } + else { + pci_command_new = pci_command | PCI_COMMAND_INTX_DISABLE; + } + + if (pci_command_new != pci_command) { + ps3_pci_write_config_word(instance, PCI_COMMAND, pci_command_new); + } + +l_out: + return; +} + +static U16 ps3_pci_msix_vec_count(struct ps3_instance *instance, PPCI_COMMON_CONFIG pci_config) +{ + U8 *config_base_addr = (U8*)pci_config; + S32 pos = 0; + U16 msix_vec_count = 0; + U16 data_u16 = 0; + + (void)instance; + pos = __ps3_pci_find_capability(pci_config, PCI_CAP_ID_MSIX); + if (pos != 0) { + data_u16 = *((U16*)(config_base_addr + pos + PCI_MSIX_FLAGS)); + } + + msix_vec_count = ((data_u16 & PCI_MSIX_FLAGS_QSIZE) + 1); + + return msix_vec_count; +} + +static U16 ps3_pci_msi_vec_count(struct ps3_instance *instance, PPCI_COMMON_CONFIG pci_config) +{ + U8 *config_base_addr = (U8*)pci_config; + S32 pos = 0; + U16 msi_vec_count = 0; + U16 data_u16 = 0; + + (void)instance; + pos = __ps3_pci_find_capability(pci_config, PCI_CAP_ID_MSI); + if (pos != 0) { + data_u16 = *((U16*)(config_base_addr + pos + PCI_MSI_FLAGS)); + } + + msi_vec_count = 1 << ((data_u16 & PCI_MSI_FLAGS_QMASK) >> 1); + + return data_u16; +} + +#endif + +S32 ps3_pci_find_capability(struct ps3_instance *instance, S32 cap_id) +{ + S32 pos = 0; +#ifdef _WINDOWS + PCI_COMMON_CONFIG pci_config = { 0 }; + U32 len = 0; + + len = (U32)StorPortGetBusData(instance, + PCIConfiguration, + (ULong)instance->bus_number, + (ULong)instance->pci_dev_context.slot_number, + (void*)&pci_config, + (ULong)sizeof(pci_config)); + + if (len == 0 || len == 2) { + LOG_ERROR("get bus data failed,cfg length:%d\n", len); + goto l_out; + } + + pos = __ps3_pci_find_capability(&pci_config, cap_id); + +l_out: +#else + pos = pci_find_capability(instance->pdev, cap_id); +#endif + return pos; +} + +S32 ps3_pci_read_config_word(struct ps3_instance *instance, U32 offset, U16 *val) +{ + S32 ret = -PS3_FAILED; +#ifdef _WINDOWS + PCI_COMMON_CONFIG pci_config = { 0 }; + U32 len = 0; + U8 *config_base_addr = (U8*)&pci_config; + + len = (U32)StorPortGetBusData(instance, + PCIConfiguration, + (ULong)instance->bus_number, + (ULong)instance->pci_dev_context.slot_number, + (void*)&pci_config, + (ULong)sizeof(pci_config)); + + if (len == 0 || len == 2) { + LOG_ERROR("get bus data failed,cfg length:%d\n", len); + goto l_out; + } + + *val = *( (U16*)(config_base_addr + offset) ); + ret = PS3_SUCCESS; + +l_out: +#else + ret = pci_read_config_word(instance->pdev, offset, val); +#endif + LOG_INFO("read config word :%d\n", ret); + return ret; +} + +S32 ps3_pci_write_config_word(struct ps3_instance *instance, U32 offset, U16 val) +{ + S32 ret = -PS3_FAILED; +#ifdef _WINDOWS + U32 len = 0; + len = (U32)StorPortSetBusDataByOffset(instance, + PCIConfiguration, + (ULong)instance->bus_number, + (ULong)instance->pci_dev_context.slot_number, + (void*)&val, + (ULong)offset, + (ULong)sizeof(U16) + ); + + if (len == sizeof(U16)) { + ret = PS3_SUCCESS; + } +#else + ret = pci_write_config_word(instance->pdev, offset, + val); +#endif + LOG_INFO("write config word :%d\n", ret); + return ret; +} + +void ps3_reg_write_u64(struct ps3_instance *instance, U64 val, void *reg) +{ + (void)instance; +#ifndef _WINDOWS +#if defined(writeq) && defined(CONFIG_64BIT) + writeq(val, reg); +#else + ULong flags; + ps3_spin_lock_irqsave(&instance->req_queue_lock, &flags); + writel((U32)(val & 0xffffffff), reg); + writel((U32)(val >> 32), reg + 0x4UL); + ps3_spin_unlock_irqrestore(&instance->req_queue_lock, flags); +#endif +#else + StorPortWriteRegisterUlong64(instance, reg, val); +#endif + +} + +U64 ps3_reg_read_u64(struct ps3_instance *instance, void *reg) +{ + U64 value = 0; + (void)instance; +#ifndef _WINDOWS +#if defined(readq) && defined(CONFIG_64BIT) + value = readq(reg); +#else + value = (((U64)readl(reg + 0x4UL) << 32) | + (U64)readl(reg)); +#endif +#else + + value = StorPortReadRegisterUlong64(instance, reg); + +#endif + return value; +} + +void __iomem *ps3_reg_set_ioremap(struct pci_dev *pdev, ULong reg_bar) +{ + resource_size_t base_addr = 0; + + base_addr = pci_resource_start(pdev, reg_bar); + return ioremap(base_addr,PS3_REGISTER_SET_SIZE); +} \ No newline at end of file diff --git a/drivers/scsi/ps3stor/ps3_pci.h b/drivers/scsi/ps3stor/ps3_pci.h new file mode 100644 index 0000000000000000000000000000000000000000..c00d0d5ea7fe0a153eeaf1979dd13c754230e42c --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_pci.h @@ -0,0 +1,68 @@ + +#ifndef _PS3_PCI_H_ +#define _PS3_PCI_H_ + +#ifdef _WINDOWS +#include "ps3_def.h" + +#define PCI_CAP_ID_MSIX PCI_CAPABILITY_ID_MSIX +#define PCI_CAP_ID_MSI PCI_CAPABILITY_ID_MSI + +#define PCI_MSIX_FLAGS_ENABLE 0x8000 +#define PCI_MSIX_FLAGS 2 +#define PCI_MSI_FLAGS 2 +#define PCI_MSI_FLAGS_ENABLE 0x0001 +#define PCI_COMMAND_INTX_DISABLE 0x400 +#define PCI_COMMAND 0x04 +#define PCI_STATUS 0x06 +#define PCI_STATUS_INTERRUPT 0x08 +#define PCI_MSIX_FLAGS_QSIZE 0x07FF +#define PCI_MSI_FLAGS_QMASK 0x000e + +#else +#include "ps3_types.h" +#endif + +#ifndef _WINDOWS +#if defined PS3_HARDWARE_ASIC +#include "ps3_ioc_manager.h" +#endif +#endif + +struct ps3_instance; + +#ifdef _WINDOWS +struct ps3_pci_context { + U64 slot_number; + U16 vendor_id; + U16 device_id; + U16 sub_vendor_id; + U16 sub_device_id; + + U64 bar_base_addr; + U16 irq_vec_count; + U16 valid_irq_count; + U8 pci_irq_type; +}; + +S32 ps3_pci_init(struct ps3_instance *instance, void *config); + +void ps3_pci_exit(struct ps3_instance *instance); + +void ps3_pci_intx(struct ps3_instance *instance, U8 enable); + +#endif + +S32 ps3_pci_find_capability(struct ps3_instance *instance, S32 cap_id); + +S32 ps3_pci_read_config_word(struct ps3_instance *instance, U32 offset, U16 *val); + +S32 ps3_pci_write_config_word(struct ps3_instance *instance, U32 offset, U16 val); + +void ps3_reg_write_u64(struct ps3_instance *instance, U64 val, void *reg); + +U64 ps3_reg_read_u64(struct ps3_instance *instance, void *reg); + +void __iomem *ps3_reg_set_ioremap(struct pci_dev *pdev, ULong reg_bar); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_platform_utils.c b/drivers/scsi/ps3stor/ps3_platform_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..9bf53834108df72ec171c8b348e4a177762f829d --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_platform_utils.c @@ -0,0 +1,396 @@ + + +#include "ps3_platform_utils.h" +#include "ps3_instance_manager.h" +#include "ps3_mgr_channel.h" +#include "ps3_driver_log.h" +#ifndef _WINDOWS +#include +#endif +#ifdef _WINDOWS +S32 ps3_dma_free( + struct ps3_instance *instance, + size_t length, + void *buffer +) +{ + S32 ret = PS3_SUCCESS; + ULong status; + + if (buffer == NULL || length == 0) { + ret = -PS3_FAILED; + goto l_out; + } + + status = StorPortFreeContiguousMemorySpecifyCache(instance, + buffer, + length, + MmCached); + + if (status != STOR_STATUS_SUCCESS) { + ret = -PS3_FAILED; + } +l_out: + return ret; +} + +S32 ps3_dma_alloc( + struct ps3_instance *instance, + size_t length, + void **buffer, + U64 *phy_addr +) +{ + S32 ret = PS3_SUCCESS; + ULong len; + ULong status; + PHYSICAL_ADDRESS minPhysicalAddress; + PHYSICAL_ADDRESS maxPhysicalAddress; + PHYSICAL_ADDRESS boundaryPhysicalAddress; + STOR_PHYSICAL_ADDRESS PhysicalAddress; + + minPhysicalAddress.QuadPart = 0; + maxPhysicalAddress.QuadPart = 0xFFFFFFFFFFFF; + boundaryPhysicalAddress.QuadPart = 0; + + status = StorPortAllocateContiguousMemorySpecifyCacheNode(instance, + length, + minPhysicalAddress, + maxPhysicalAddress, + boundaryPhysicalAddress, + MmCached, + MM_ANY_NODE_OK, + buffer); + + if (status != STOR_STATUS_SUCCESS) { + LOG_ERROR("alloc dma buffer failed, length:%d, status:0x%x\n", length, status); + ret = -PS3_FAILED; + goto l_out; + } + + PhysicalAddress = StorPortGetPhysicalAddress(instance, NULL, *buffer, &len); + *phy_addr = (U64)PhysicalAddress.QuadPart; + if (PhysicalAddress.QuadPart == 0) { + LOG_ERROR("dma buffer remap fail\n"); + ps3_dma_free(instance, length, *buffer); + *buffer = NULL; + ret = -PS3_FAILED; + } + +l_out: + return ret; +} + +#endif + +void *ps3_kcalloc(struct ps3_instance *instance, U32 blocks, U32 block_size) +{ + void *ret = NULL; +#ifndef _WINDOWS + (void)instance; + ret = kcalloc(blocks, block_size, GFP_KERNEL); +#else + ULong status = StorPortAllocatePool(instance, + blocks * block_size, 'd3sp', &ret); + + if (status != STOR_STATUS_SUCCESS) { + LOG_ERROR("host_no:%d, memory alloc failed, status0x%x\n", PS3_HOST(instance), status); + ret = NULL; + } else { + memset(ret, 0, blocks * block_size); + } + +#endif + + if (ret == NULL) { + LOG_ERROR("host_no:%u, memory:%u %u alloc failed\n", PS3_HOST(instance), blocks, block_size); + } + + return ret; +} + +void ps3_kfree(struct ps3_instance *instance, void *buffer) +{ +#ifndef _WINDOWS + (void)instance; + if(buffer != NULL){ + kfree(buffer); + } +#else + ULong status = StorPortFreePool(instance, buffer); + if (status != STOR_STATUS_SUCCESS) { + LOG_ERROR("host_no:%u, memory free failed, status0x%x\n", PS3_HOST(instance), status); + } + +#endif + + return; +} + +void *ps3_kzalloc(struct ps3_instance *instance, U32 size) { + return ps3_kcalloc(instance, 1, size); +} + +void ps3_vfree(struct ps3_instance *instance, void *buffer) +{ +#ifndef _WINDOWS + (void)instance; + vfree(buffer); +#else + ULong status = StorPortFreePool(instance, buffer); + if (status != STOR_STATUS_SUCCESS) { + LOG_ERROR("host_no:%u, memory free failed, status0x%x\n", PS3_HOST(instance), status); + } + +#endif + + return; +} + +void *ps3_vzalloc(struct ps3_instance *instance, U32 size) +{ + void *ret = NULL; +#ifndef _WINDOWS + (void)instance; + ret = vzalloc(size); +#else + ULong status = StorPortAllocatePool(instance, + size, 'd3sp', &ret); + + if (status != STOR_STATUS_SUCCESS) { + LOG_ERROR("host_no:%d, memory alloc failed, status0x%x\n", PS3_HOST(instance), status); + ret = NULL; + } else { + memset(ret, 0, size); + } + +#endif + + if (ret == NULL) { + LOG_ERROR("host_no:%u, memory:%u alloc failed\n", PS3_HOST(instance), size); + } + + return ret; +} + +S32 ps3_wait_for_completion_timeout(void *sync_done, ULong time_out) +{ + S32 ret = PS3_SUCCESS; +#ifdef _WINDOWS + NTSTATUS wait_ret = STATUS_SUCCESS; + LARGE_INTEGER win_timeout = { 0 }; + if (time_out > 0) { + win_timeout.QuadPart = (S64)(time_out * (-10000000LL)); + wait_ret = KeWaitForSingleObject(sync_done, Executive, + KernelMode, FALSE, &win_timeout); + } + else { + wait_ret = KeWaitForSingleObject(sync_done, Executive, + KernelMode, FALSE, NULL); + } + + if (wait_ret == STATUS_TIMEOUT) { + ret = -PS3_TIMEOUT; + } +#else + U16 timeout = 0; + if (time_out > 0) { + timeout = wait_for_completion_timeout((struct completion *)sync_done, time_out * HZ); + if (timeout == 0) { + ret = -PS3_TIMEOUT; + } + } else { + wait_for_completion((struct completion *)sync_done); + } +#endif + return ret; +} + +S32 ps3_wait_cmd_for_completion_timeout(struct ps3_instance *instance, struct ps3_cmd *cmd, ULong timeout) { + S32 ret = PS3_SUCCESS; + ULong time_out; +#ifdef _WINDOWS + (void)instance; + time_out = max((ULong)cmd->time_out, timeout); + ret = ps3_wait_for_completion_timeout(&cmd->sync_done, time_out); +#else + if (cmd->time_out == 0 && cmd->is_interrupt) { + ps3_wait_cmd_for_completion_interrupt(instance, cmd); + } else { + time_out = max((ULong)cmd->time_out, timeout); + ret = ps3_wait_for_completion_timeout(&cmd->sync_done, time_out); + } +#endif + return ret; +} + +S32 ps3_scsi_device_get(struct ps3_instance *instance, struct scsi_device *sdev) +{ +#ifdef _WINDOWS + return ps3_scsi_device_get_win(instance, sdev); +#else + (void)instance; + return scsi_device_get(sdev); +#endif +} + +void ps3_scsi_device_put(struct ps3_instance *instance, struct scsi_device *sdev) +{ +#ifdef _WINDOWS + ps3_scsi_device_put_win(instance, sdev); +#else + (void)instance; + scsi_device_put(sdev); +#endif +} + +#ifndef _WINDOWS + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) +struct scsi_device *__ps3_scsi_device_lookup_check(struct Scsi_Host *shost, + U32 channel, U32 id, U32 lun) +{ + struct scsi_device *sdev = NULL; + + list_for_each_entry(sdev, &shost->__devices, siblings) { + if (sdev->sdev_state == SDEV_DEL) + continue; + if (sdev->channel == channel && sdev->id == id && + sdev->lun == lun) + return sdev; + } + + return NULL; +} + +struct scsi_device *ps3_scsi_device_lookup_check(struct Scsi_Host *shost, + U32 channel, U32 id, U32 lun) +{ + struct scsi_device *sdev = NULL; + unsigned long flags = 0; + + spin_lock_irqsave(shost->host_lock, flags); + sdev = __ps3_scsi_device_lookup_check(shost, channel, id, lun); + if (sdev && scsi_device_get(sdev)) + sdev = NULL; + spin_unlock_irqrestore(shost->host_lock, flags); + + return sdev; +} + +#endif + +#endif + +struct scsi_device *ps3_scsi_device_lookup(struct ps3_instance *instance, U8 channel, U16 target_id, U8 lun) +{ +#ifdef _WINDOWS + (void)lun; + struct scsi_device *sdev = ps3_scsi_device_lookup_win(instance, channel, (U8)target_id); + if (sdev != NULL && sdev->unit_start == 1) { + return sdev; + } + return NULL; +#else +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0) + return ps3_scsi_device_lookup_check(instance->host, channel, target_id, lun); +#else + return scsi_device_lookup(instance->host, channel, target_id, lun); +#endif +#endif +} + +void ps3_scsi_remove_device(struct ps3_instance *instance, struct scsi_device *sdev) +{ +#ifdef _WINDOWS + ps3_scsi_remove_device_win(instance, sdev); +#else + (void)instance; + scsi_remove_device(sdev); +#endif +} + +S32 ps3_scsi_add_device(struct ps3_instance *instance, U8 channel, U16 target_id, U8 lun) +{ +#ifdef _WINDOWS + (void)lun; + return ps3_scsi_add_device_win(instance, channel, (U8)target_id); +#else + return scsi_add_device(instance->host, channel, target_id, lun); +#endif +} + +U64 ps3_now_ms_get(void) +{ +#ifdef _WINDOWS + LARGE_INTEGER timestamp; + KeQuerySystemTime(×tamp); + return timestamp.QuadPart / 10000; +#else + return ktime_to_ms(ktime_get_real()); +#endif +} + +U64 ps3_1970_now_ms_get(void) +{ +#ifdef _WINDOWS + U64 timestamp; + LARGE_INTEGER timestamp1970; + TIME_FIELDS timefiled; + + timefiled.Year = 1970; + timefiled.Month = 1; + timefiled.Day = 1; + timefiled.Hour = 0; + timefiled.Minute = 0; + timefiled.Second = 0; + timefiled.Milliseconds = 0; + + RtlTimeFieldsToTime(&timefiled, ×tamp1970); + timestamp = ps3_now_ms_get(); + return timestamp - (timestamp1970.QuadPart / 10000); +#else + return ps3_now_ms_get(); +#endif +} +#ifdef _WINDOWS +S32 ps3_now_format_get(char *buff, S32 buf_len) +{ +#ifdef _WINDOWS + LARGE_INTEGER timestamp; + KeQuerySystemTime(×tamp); + LARGE_INTEGER localtime; + TIME_FIELDS timefiled; + + ExSystemTimeToLocalTime(×tamp, &localtime); + RtlTimeToTimeFields(&localtime, &timefiled); + + return snprintf(buff, buf_len, "%04ld-%02d-%02d_%02d:%02d:%02d.%03d", + timefiled.Year, timefiled.Month, timefiled.Day, + timefiled.Hour, timefiled.Minute, timefiled.Second, + timefiled.Milliseconds); +#else + struct timeval tv; + struct tm td; + + do_gettimeofday(&tv); + time_to_tm(tv.tv_sec, -sys_tz.tz_minuteswest * 60, &td); + + return snprintf(buff, buf_len, "%04ld-%02d-%02d_%02d:%02d:%02d", + td.tm_year + 1900, td.tm_mon + 1, td.tm_mday, + td.tm_hour, td.tm_min, td.tm_sec); +#endif +} +#endif +U64 ps3_tick_count_get(void) +{ +#ifdef _WINDOWS + LARGE_INTEGER tick_count; + LARGE_INTEGER tick_frequency; + + tick_count = KeQueryPerformanceCounter(&tick_frequency); + return (U64)(tick_count.QuadPart * 1000000 / tick_frequency.QuadPart); +#else + return (U64)ktime_to_us(ktime_get_real()); +#endif +} diff --git a/drivers/scsi/ps3stor/ps3_platform_utils.h b/drivers/scsi/ps3stor/ps3_platform_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..2efd0de9b7e0896bd62f4f3004b8fda0ba46d7f0 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_platform_utils.h @@ -0,0 +1,533 @@ + +#ifndef _PS3_PLATFORM_UTILS_H_ +#define _PS3_PLATFORM_UTILS_H_ + +#ifdef _WINDOWS +#include "ps3_def.h" +#else +#include +#include +#include +#include + +#endif + +#include "ps3_err_def.h" + +struct ps3_instance; +struct scsi_device; +struct ps3_cmd; + +#define scsi_cmnd_cdb(scmnd) ((scmnd)->cmnd) +#define scsi_device_private_data(scmnd) (PS3_SDEV_PRI_DATA((scmnd)->device)) +#ifdef _WINDOWS +#define scsi_host_data(scmnd) (struct ps3_instance*)((scmnd)->instance) +#else +#define scsi_host_data(scmnd) (struct ps3_instance*)((scmnd)->device->host->hostdata) +#endif + +#ifdef _WINDOWS +#define ps3_container_of(ptr, type, member) \ + ((type*)((char*)ptr - offsetof(type,member))) +#else +#define ps3_container_of container_of +#endif +#define MAX_MDELAY (1) + +#ifdef _WINDOWS +typedef struct { + FAST_MUTEX mutex; +}ps3_mutex, *pps3_mutex; +#else + +typedef struct mutex ps3_mutex; + +#endif + +static inline void ps3_mutex_init(ps3_mutex *mutex_lock) +{ +#ifdef _WINDOWS + ExInitializeFastMutex(&mutex_lock->mutex); +#else + mutex_init(mutex_lock); +#endif +} + +static inline void ps3_mutex_destroy(ps3_mutex *mutex_lock) +{ +#ifdef _WINDOWS + (void)mutex_lock; +#else + mutex_destroy(mutex_lock); +#endif + return; +} + +static inline S32 ps3_mutex_lock(ps3_mutex *mtx_lock) +{ + +#ifdef _WINDOWS + if (KeGetCurrentIrql() <= APC_LEVEL) { + ExAcquireFastMutex(&mtx_lock->mutex); + + return PS3_SUCCESS; + } + return -PS3_FAILED; +#else + mutex_lock(mtx_lock); + return PS3_SUCCESS; +#endif +} +static inline S32 ps3_mutex_trylock(ps3_mutex *mutex_lock) +{ + S32 ret = PS3_SUCCESS; +#ifdef _WINDOWS + if (KeGetCurrentIrql() > APC_LEVEL) { + ret = -PS3_FAILED; + goto l_out; + } + + if (!ExTryToAcquireFastMutex(&mutex_lock->mutex)) { + ret = -PS3_FAILED; + goto l_out; + } +l_out: +#else + ret = mutex_trylock(mutex_lock); +#endif + return ret; +} + +static inline S32 ps3_mutex_unlock(ps3_mutex *mutex_lock) +{ +#ifdef _WINDOWS + if (KeGetCurrentIrql() <= APC_LEVEL) { + ExReleaseFastMutex(&mutex_lock->mutex); + + return PS3_SUCCESS; + } + + return -PS3_FAILED; +#else + mutex_unlock(mutex_lock); + return PS3_SUCCESS; + +#endif +} + +#ifdef _WINDOWS +typedef struct { + volatile S32 value; +}ps3_atomic32, *pps3_atomic32; + +typedef struct { + volatile S64 value; +}ps3_atomic64, *pps3_atomic64; +#else +typedef atomic_t ps3_atomic32; +typedef atomic64_t ps3_atomic64; +#endif + +static inline S32 ps3_atomic_read(ps3_atomic32 *value) { +#ifdef _WINDOWS + return value->value; +#else + return atomic_read(value); +#endif +} + +static inline S32 ps3_atomic_dec(ps3_atomic32 *value) { +#ifdef _WINDOWS + return (S32)InterlockedDecrement((LONG*)(&value->value)); +#else + atomic_dec(value); + return PS3_SUCCESS; +#endif +} + +static inline S32 ps3_atomic_add(S32 i, ps3_atomic32 *value) { +#ifdef _WINDOWS + return (S32)_InlineInterlockedAdd((LONG*)&value->value, (LONG)i); +#else + atomic_add(i, value); + return PS3_SUCCESS; +#endif +} + +static inline S32 ps3_atomic_sub(S32 i, ps3_atomic32 *value) { +#ifdef _WINDOWS + return (S32)_InlineInterlockedAdd((LONG*)&value->value, (LONG)-i); +#else + atomic_sub(i, value); + return PS3_SUCCESS; +#endif +} + +static inline S32 ps3_atomic_cmpxchg(ps3_atomic32 *value, S32 old, S32 cur) +{ +#ifdef _WINDOWS + return (S32)InterlockedCompareExchange((LONG*)&value->value, (LONG)cur, (LONG)old); +#else + return atomic_cmpxchg(value, cur, old); +#endif +} + +static inline Bool ps3_atomic_add_unless(ps3_atomic32 *value, S32 a, S32 u) { +#ifdef _WINDOWS + + S32 c = 0; + S32 old = 0; + c = value->value; + while (c != u && + (old = ps3_atomic_cmpxchg(value, c, c + a)) != c) { + c = old; + } + + return c != u; +#else + return atomic_add_unless(value, a, u); +#endif +} + +static inline S32 ps3_atomic_inc(ps3_atomic32 *value) { +#ifdef _WINDOWS + return (S32)InterlockedIncrement((LONG*)(&value->value)); +#else + atomic_inc(value); + return PS3_SUCCESS; +#endif +} + +static inline S32 ps3_atomic_inc_return(ps3_atomic32 *value) { +#ifdef _WINDOWS + return (S32)InterlockedIncrement((LONG*)(&value->value)); +#else + return atomic_inc_return(value); +#endif +} + +static inline S32 ps3_atomic_dec_return(ps3_atomic32 *value) { +#ifdef _WINDOWS + return (S32)InterlockedDecrement((LONG*)(&value->value)); +#else + return atomic_dec_return(value); +#endif +} + +static inline S64 ps3_atomic64_inc(ps3_atomic64 *value) { +#ifdef _WINDOWS + return (S64)InterlockedIncrement64((LONG64*)(&value->value)); +#else + atomic64_inc(value); + return PS3_SUCCESS; +#endif +} + +static inline S64 ps3_atomic64_inc_return(ps3_atomic64 *value) { +#ifdef _WINDOWS + return (S64)InterlockedIncrement64((LONG64*)(&value->value)); +#else + return atomic64_inc_return(value); +#endif +} + +static inline S64 ps3_atomic64_read(ps3_atomic64 *value) { +#ifdef _WINDOWS + return value->value; +#else + return atomic64_read(value); +#endif +} + +static inline void ps3_atomic64_set(ps3_atomic64 *value, S64 i) { +#ifdef _WINDOWS + value->value = i; +#else + atomic64_set(value, i); +#endif +} + +static inline void ps3_atomic_set(ps3_atomic32 *value, S32 i) { +#ifdef _WINDOWS + value->value = i; +#else + atomic_set(value, i); +#endif +} + +static inline S64 ps3_atomic64_add(S64 i, ps3_atomic64 *value) { +#ifdef _WINDOWS + return (S64)_InlineInterlockedAdd64((LONG64*)&value->value, (LONG64)i); +#else + atomic64_add(i, value); + return PS3_SUCCESS; +#endif +} + +static inline S64 ps3_atomic64_dec(ps3_atomic64 *value) { +#ifdef _WINDOWS + return (S64)InterlockedDecrement64((LONG64*)&value->value); +#else + atomic64_dec(value); + return PS3_SUCCESS; +#endif +} + +#ifdef _WINDOWS +typedef struct { + KSPIN_LOCK lock; +}ps3_spinlock, *pps3_spinlock; +#else +typedef spinlock_t ps3_spinlock; +#endif + +static inline void ps3_spin_lock_init(ps3_spinlock *lock) +{ +#ifdef _WINDOWS + KeInitializeSpinLock(&lock->lock); +#else + spin_lock_init(lock); +#endif +} + +static inline void ps3_spin_lock(ps3_spinlock *lock, ULong*flag) +{ +#ifdef _WINDOWS + KeAcquireSpinLock(&lock->lock, (PKIRQL)flag); +#else + (void)flag; + spin_lock(lock); +#endif +} + +static inline void ps3_spin_lock_irqsave(ps3_spinlock *lock, ULong *flag) +{ +#ifdef _WINDOWS + KeAcquireSpinLock(&lock->lock, (PKIRQL)flag); +#else + spin_lock_irqsave(lock, *flag); +#endif +} + +static inline void ps3_spin_unlock(ps3_spinlock *lock, ULong flag) +{ +#ifdef _WINDOWS + KeReleaseSpinLock(&lock->lock, (KIRQL)flag); +#else + (void)flag; + spin_unlock(lock); +#endif +} + +static inline void ps3_spin_unlock_irqrestore(ps3_spinlock *lock, ULong flag) +{ +#ifdef _WINDOWS + KeReleaseSpinLock(&lock->lock, (KIRQL)flag); +#else + spin_unlock_irqrestore(lock, flag); +#endif +} + +S32 ps3_wait_for_completion_timeout(void *sync_done, ULong Timeout); +S32 ps3_wait_cmd_for_completion_timeout(struct ps3_instance *instance, + struct ps3_cmd *cmd, ULong timeout); + +#ifdef _WINDOWS +typedef LIST_ENTRY ps3_list_head; +#else +typedef struct list_head ps3_list_head; +#endif + +#ifdef _WINDOWS + +#define complete(x) KeSetEvent(x, IO_NO_INCREMENT, FALSE); +#define init_completion(x) KeInitializeEvent(x, SynchronizationEvent, FALSE); + +static inline int list_empty(const ps3_list_head* head) +{ + return head->Blink == head; +} + +#define list_entry(ptr, type, member) \ + CONTAINING_RECORD(ptr, type, member) + +#define list_for_each(pos, head) \ + for (pos = (head)->Blink; pos != (head); pos = pos->Blink) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->Blink, type, member) + +#define list_next_entry(pos, type, member) \ + list_entry((pos)->member.Blink, type, member) + +#define list_for_each_entry(pos, type, head, member) \ + for (pos = list_first_entry(head, type, member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, type, member)) + +#define list_for_each_entry_safe(pos, type, tmp, head, member) \ + for (pos = list_first_entry(head, type, member), \ + tmp = list_next_entry(pos, type, member); \ + &pos->member != (head); \ + pos = tmp, tmp = list_next_entry(tmp, type, member)) + +static inline void INIT_LIST_HEAD(ps3_list_head* list) +{ + InitializeListHead((PLIST_ENTRY)list); +} + +static inline void list_del(ps3_list_head* entry) +{ + RemoveEntryList((PLIST_ENTRY)entry); +} + +static inline void list_del_init(ps3_list_head* entry) +{ + list_del(entry); + INIT_LIST_HEAD(entry); +} + +static inline void list_add_tail(ps3_list_head* entry, ps3_list_head* head) +{ + InsertTailList((PLIST_ENTRY)head, (PLIST_ENTRY)entry); +} + +static inline ps3_list_head* list_remove_head(ps3_list_head* head) +{ + return (ps3_list_head*)RemoveHeadList((PLIST_ENTRY)head); +} + +inline S32 kstrtou16(const S8 *s, U32 base, U16 *res) +{ + ULong tmp = 0; + int ret = RtlCharToInteger(s, base, &tmp); + if (ret != STATUS_SUCCESS) { + goto l_out; + } + + if (tmp != (U64)(U16)tmp) { + ret = -34; + goto l_out; + } + + *res = (U16)tmp; +l_out: + return ret; +} + +inline S32 kstrtoint(const S8 *s, U32 base, S32* res) +{ + ULong tmp = 0; + int ret = RtlCharToInteger(s, base, &tmp); + if (ret != STATUS_SUCCESS) { + + } + + if (tmp != (U64)(int)tmp) { + ret = -34; + goto l_out; + } + + *res = (int)tmp; +l_out: + return ret; +} + +inline S32 kstrtouint(const S8 *s, U32 base, U32* res) +{ + ULong tmp = 0; + int ret = RtlCharToInteger(s, base, &tmp); + if (ret != STATUS_SUCCESS) { + goto l_out; + } + + if (tmp != (U64)(U32)tmp) { + ret = -34; + goto l_out; + } + + *res = (unsigned int)tmp; +l_out: + return ret; +} + +inline S32 kstrtou64(const S8 *s, U64 base, U64* res) +{ + ULong tmp = 0; + int ret = RtlCharToInteger(s, base, &tmp); + if (ret != STATUS_SUCCESS) { + goto l_out; + } + + if (tmp != (U64)tmp) { + ret = -34; + goto l_out; + } + + *res = (ULong)tmp; +l_out: + return ret; +} + +S32 ps3_dma_free( + struct ps3_instance *instance, + size_t length, + void *buffer +); + +S32 ps3_dma_alloc( + struct ps3_instance *instance, + size_t length, + void **buffer, + U64 *phy_addr +); + +#endif + +static inline void ps3_msleep(U32 ms) +{ +#ifdef _WINDOWS + StorPortStallExecution((ULong)ms*1000); +#else + msleep(ms); +#endif +} + +static inline void ps3_mdelay(U32 ms) +{ +#ifndef _WINDOWS + U32 count = (ms/MAX_MDELAY); + U32 remain = (ms%MAX_MDELAY); + do { + udelay(1000*MAX_MDELAY); + count--; + } while(count); + + if(remain != 0){ + udelay(remain * 1000); + } +#else + StorPortStallExecution((ULong)ms*1000); +#endif +} +void *ps3_kcalloc(struct ps3_instance *instance, U32 blocks, U32 block_size); +void ps3_kfree(struct ps3_instance *instance, void *buffer); +void *ps3_kzalloc(struct ps3_instance *instance, U32 size); + +void ps3_vfree(struct ps3_instance *instance, void *buffer); +void *ps3_vzalloc(struct ps3_instance *instance, U32 size); + +int ps3_scsi_device_get(struct ps3_instance *instance, struct scsi_device *sdev); +void ps3_scsi_device_put(struct ps3_instance *instance, struct scsi_device *sdev); +struct scsi_device *ps3_scsi_device_lookup(struct ps3_instance *instance, U8 channel, U16 target_id, U8 lun); +void ps3_scsi_remove_device(struct ps3_instance *instance, struct scsi_device *sdev); +S32 ps3_scsi_add_device(struct ps3_instance *instance, U8 channel, U16 target_id, U8 lun); + +U64 ps3_now_ms_get(void); +#ifdef _WINDOWS +S32 ps3_now_format_get(char *buff, S32 buf_len); +#endif +U64 ps3_1970_now_ms_get(void); +U64 ps3_tick_count_get(void); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_qos.c b/drivers/scsi/ps3stor/ps3_qos.c new file mode 100644 index 0000000000000000000000000000000000000000..eba1220f815990665a6644db94c6cf122083ec91 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_qos.c @@ -0,0 +1,4043 @@ +#include +#include +#include +#include +#include +#include +#include "ps3_ioc_manager.h" +#include "ps3_util.h" +#include "ps3_types.h" +#include "ps3_instance_manager.h" +#include "ps3_htp_def.h" +#include "ps3_scsih.h" +#include "ps3_mgr_cmd.h" +#include "ps3_driver_log.h" +#include "ps3_htp_dev.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_cmd_statistics.h" +#include "ps3_scsih_raid_engine.h" +#include "ps3_ioc_state.h" + +#define PS3_QOS_PD_IS_VD_MEMBER(qos_pd_mgr) ((qos_pd_mgr)->vd_id > 0) + +#define PS3_QOS_JBOD_PD_WAITQ_ID(qos_pd_mgr) ((qos_pd_mgr)->waitq_cnt - 1) + +#define PS3_QOS_VD_HDD_DELAY_THD_MS 500 + +#define PS3_QOS_VD_SDD_DELAY_THD_MS 1 + +static inline Bool ps3_tfifo_depth_get(struct ps3_instance *instance, + U64 *depth) +{ + Bool ret = PS3_TRUE; + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3TfifoDepth, *depth); + if (*depth == U64_MAX) { + LOG_INFO("host_no:%u read reg ps3TfifoDepth failed!\n", + PS3_HOST(instance)); + *depth = 0; + ret = PS3_FALSE; + goto l_out; + } + + *depth &= 0xffff; + +l_out: + return ret; +} + +static inline Bool ps3_cmdq_depth_get(struct ps3_instance *instance, + U64 *depth) +{ + Bool ret = PS3_TRUE; + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3CmdQueueDepth, *depth); + + if (*depth == U64_MAX) { + LOG_INFO("host_no:%u read reg ps3CmdQueueDepth failed!\n", + PS3_HOST(instance)); + *depth = 0; + ret = PS3_FALSE; + goto l_out; + } + + *depth &= 0xffff; + +l_out: + return ret; +} + +static inline Bool ps3_mgrq_depth_get(struct ps3_instance *instance, + U64 *depth) +{ + Bool ret = PS3_TRUE; + PS3_IOC_REG_READ_SAFE_WITH_RETRY(instance, reg_f.Excl_reg, ps3MgrQueueDepth, *depth); + + if (*depth == U64_MAX) { + LOG_INFO("host_no:%u read reg ps3MgrQueueDepth failed!\n", + PS3_HOST(instance)); + *depth = 0; + ret = PS3_FALSE; + goto l_out; + } + + *depth &= 0xffff; + +l_out: + return ret; +} + +static inline struct ps3_qos_pd_mgr *ps3_qos_pd_mgr_get(struct ps3_instance *instance, U16 disk_id) +{ + return &instance->qos_context.pd_ctx.qos_pd_mgrs[disk_id]; +} + +static inline bool ps3_is_nvme_direct_cmd(struct ps3_qos_pd_mgr *qos_pd_mgr, struct ps3_cmd *cmd) +{ + return (qos_pd_mgr->dev_type == PS3_DEV_TYPE_NVME_SSD && + cmd->io_attr.direct_flag == PS3_CMDWORD_DIRECT_OK); +} + +static void ps3_qos_update_pd_quota(struct ps3_cmd *cmd) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + U16 i = 0; + U16 disk_id = 0; + S32 pd_used_quota = 0; + ps3_atomic32 *pd_rsc = NULL; + + for (i = 0; i < cmd->target_pd_count; i++) { + if (cmd->target_pd[i].get_quota) { + disk_id = cmd->target_pd[i].flat_disk_id; + qos_pd_mgr = ps3_qos_pd_mgr_get(cmd->instance, disk_id); + if (ps3_is_nvme_direct_cmd(qos_pd_mgr, cmd)) { + pd_rsc = &qos_pd_mgr->direct_used_quota; + } else { + pd_rsc = &qos_pd_mgr->pd_used_quota; + } + pd_used_quota = ps3_atomic_dec_return(pd_rsc); + LOG_DEBUG("update pd quota. host_no:%u t_id:0x%llx CFID:%u direct:%u pid:%u used_quota:%d\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, cmd->cmd_word.direct, + disk_id, pd_used_quota); + break; + } + } +} + +static inline struct ps3_qos_vd_mgr *ps3_qos_vd_mgr_get(struct ps3_cmd *cmd) +{ + U16 disk_id = 0; + U16 flat_disk_id = 0; + struct ps3_instance *instance = cmd->instance; + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + disk_id = PS3_VDID(&cmd->io_attr.vd_entry->diskPos); + flat_disk_id = get_offset_of_vdid(PS3_VDID_OFFSET(instance), disk_id); + return &instance->qos_context.vd_ctx.qos_vd_mgrs[flat_disk_id]; + } else { + return &instance->qos_context.vd_ctx.qos_vd_mgrs[instance->qos_context.max_vd_count]; + } +} + +static inline struct ps3_qos_vd_mgr *ps3_qos_vd_mgr_get_by_id(struct ps3_instance *instance, + U16 disk_id) +{ + struct ps3_qos_vd_context *qos_vd_ctx = NULL; + U16 flat_disk_id = 0; + + qos_vd_ctx = &instance->qos_context.vd_ctx; + flat_disk_id = get_offset_of_vdid(PS3_VDID_OFFSET(instance), disk_id); + return &qos_vd_ctx->qos_vd_mgrs[flat_disk_id]; +} + +static void ps3_qos_update_vd_quota(struct ps3_cmd *cmd) +{ + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + + if (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD) { + qos_vd_mgr = ps3_qos_vd_mgr_get(cmd); + ps3_atomic_inc(&qos_vd_mgr->vd_quota); + } +} + +Bool ps3_qos_enable(struct ps3_instance *instance) +{ + return instance->qos_context.qos_switch; +} + +static void ps3_qos_cmd_resend_fail(struct ps3_cmd *cmd, S32 ret) +{ + struct ps3_scsi_priv_data *pri_data = NULL; + struct ps3_instance *instance = cmd->instance; + struct scsi_cmnd *s_cmd = cmd->scmd; + + if (ret == -PS3_RECOVERED || ret == -PS3_RETRY) { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_RESET); + } else { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + } + + if (cmd->is_got_r1x == 1) { + pri_data = (struct ps3_scsi_priv_data *)s_cmd->device->hostdata; + ps3_r1x_write_unlock(&pri_data->lock_mgr, cmd); + } + + LOG_INFO_IN_IRQ(instance, "t_id:0x%llx hno:%u tag:%d cmd send err ret:%d\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, ret); + ps3_scsi_dma_unmap(cmd); + s_cmd = cmd->scmd; + PS3_DEV_IO_START_ERR_INC(instance, cmd); + PS3_IO_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd); + PS3_VD_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + ps3_scsi_cmd_free(cmd); + SCMD_IO_DONE(s_cmd); +} + +struct qos_wait_queue *ps3_qos_cmd_waitq_get(struct ps3_qos_tg_context *qos_tg_ctx, struct ps3_cmd *cmd) +{ + struct qos_wait_queue *wait_q = NULL; + U16 disk_id = 0; + struct ps3_qos_context *qos_ctx = NULL; + + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + wait_q = &qos_tg_ctx->mgr_cmd_wait_q; + } else { + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + disk_id = get_offset_of_vdid(PS3_VDID_OFFSET(cmd->instance), + PS3_VDID(&cmd->io_attr.vd_entry->diskPos)); + wait_q = &qos_tg_ctx->vd_cmd_waitqs[disk_id]; + } else { + qos_ctx = &cmd->instance->qos_context; + wait_q = &qos_tg_ctx->vd_cmd_waitqs[qos_ctx->max_vd_count]; + } + } + + return wait_q; +} + +static void ps3_hba_qos_cmd_update(struct ps3_cmd *cmd) +{ + struct ps3_qos_tg_context *qos_tg_ctx = &cmd->instance->qos_context.tg_ctx; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + if (ps3_atomic_dec_return(&qos_tg_ctx->mgr_share_used) >= 0) { + ps3_atomic_inc(&qos_tg_ctx->share_free_cnt); + } else { + ps3_atomic_inc(&qos_tg_ctx->mgr_share_used); + ps3_atomic_inc(&qos_tg_ctx->mgr_free_cnt); + } + } else { + ps3_qos_update_pd_quota(cmd); + if (cmd->cmd_word.direct != PS3_CMDWORD_DIRECT_OK) { + qos_vd_mgr = ps3_qos_vd_mgr_get(cmd); + if (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD) { + ps3_atomic_inc(&qos_vd_mgr->vd_quota); + } + + if (ps3_atomic_dec_return(&qos_vd_mgr->share_cmd_used) >= 0) { + ps3_atomic_inc(&qos_tg_ctx->share_free_cnt); + } else { + ps3_atomic_inc(&qos_vd_mgr->share_cmd_used); + ps3_atomic_inc(&qos_vd_mgr->exclusive_cmd_cnt); + } + } + } + LOG_DEBUG("qos cmd update. host_no:%u dev_t:%u share:%u\n", + PS3_HOST(cmd->instance), cmd->io_attr.dev_type, + ps3_atomic_read(&qos_tg_ctx->share_free_cnt)); +} + +static inline Bool ps3_qos_share_cmdword_dec(struct ps3_qos_tg_context *qos_tg_ctx) +{ + Bool can_get = PS3_FALSE; + if (ps3_atomic_dec_return(&qos_tg_ctx->share_free_cnt) >= 0) { + can_get = PS3_TRUE; + } else { + ps3_atomic_inc(&qos_tg_ctx->share_free_cnt); + can_get = PS3_FALSE; + } + + return can_get; +} + +static Bool ps3_qos_share_cmdword_get(struct ps3_qos_tg_context *qos_tg_ctx, + struct ps3_cmd *cmd, struct qos_wait_queue *wait_q) +{ + Bool can_get = PS3_FALSE; + ULong flag = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + + can_get = ps3_qos_share_cmdword_dec(qos_tg_ctx); + if (!can_get) { + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + list_add_tail(&cmd->qos_list, &wait_q->wait_list); + wait_q->count++; + qos_tg_ctx->total_wait_cmd_cnt++; + cmd->qos_waitq_flag = PS3_QOS_CMD_IN_FRAME; + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); + LOG_DEBUG("insert qos tag waitq.host_no:%u:t_id:0x%llx CFID:%u diskid:%u waitq:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + cmd->io_attr.disk_id, wait_q->count); + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_TAG_QUEUE); + } else { + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + ps3_atomic_inc(&qos_tg_ctx->mgr_share_used); + } else { + qos_vd_mgr = ps3_qos_vd_mgr_get(cmd); + ps3_atomic_inc(&qos_vd_mgr->share_cmd_used); + } + } + + return can_get; +} + +static bool ps3_qos_mgr_cmdword_get(struct ps3_cmd *cmd) +{ + bool can_get = PS3_FALSE; + struct ps3_instance *instance = cmd->instance; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + + if (ps3_atomic_dec_return(&qos_tg_ctx->mgr_free_cnt) >= 0) { + can_get = PS3_TRUE; + } else { + ps3_atomic_inc(&qos_tg_ctx->mgr_free_cnt); + can_get = PS3_FALSE; + } + + return can_get; +} + +Bool ps3_qos_vd_cmdword_get(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + + qos_vd_mgr = ps3_qos_vd_mgr_get(cmd); + if (ps3_atomic_dec_return(&qos_vd_mgr->exclusive_cmd_cnt) >= 0) { + can_get = PS3_TRUE; + } else { + ps3_atomic_inc(&qos_vd_mgr->exclusive_cmd_cnt); + can_get = PS3_FALSE; + } + + return can_get; +} + +Bool ps3_qos_exclusive_cmdword_get(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + can_get = ps3_qos_mgr_cmdword_get(cmd); + } else { + can_get = ps3_qos_vd_cmdword_get(cmd); + } + + return can_get; +} + +Bool ps3_qos_tg_decision(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + struct ps3_instance *instance = cmd->instance; + ULong flag = 0; + struct qos_wait_queue *cmd_wait_q = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + + PS3_QOS_STAT_START(instance, cmd, PS3_QOS_TAG_PRO); + cmd_wait_q = ps3_qos_cmd_waitq_get(qos_tg_ctx, cmd); + if (cmd_wait_q->count == 0) { + can_get = ps3_qos_exclusive_cmdword_get(cmd); + if (can_get){ + goto out; + } + } + + if (likely(qos_tg_ctx->total_wait_cmd_cnt == 0)) { + can_get = ps3_qos_share_cmdword_get(qos_tg_ctx, cmd, cmd_wait_q); + } else { + INJECT_START(PS3_ERR_IJ_QOS_WAIT_TAG_WAITQ_CLEAR, cmd->instance) + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + if (qos_tg_ctx->total_wait_cmd_cnt > 0){ + list_add_tail(&cmd->qos_list, &cmd_wait_q->wait_list); + cmd_wait_q->count++; + qos_tg_ctx->total_wait_cmd_cnt++; + cmd->qos_waitq_flag = PS3_QOS_CMD_IN_FRAME; + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); + can_get = PS3_FALSE; + LOG_DEBUG("insert qos tag waitq.host_no:%u:t_id:0x%llx CFID:%u diskid:%u waitq:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, + cmd->io_attr.disk_id, cmd_wait_q->count); + PS3_QOS_STAT_START(instance, cmd, PS3_QOS_TAG_QUEUE); + } else { + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); + can_get = ps3_qos_share_cmdword_get(qos_tg_ctx, cmd, cmd_wait_q); + } + } +out: + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_TAG_PRO); + return can_get; +} + +static inline bool ps3_qos_pd_quota_add(struct qos_wait_queue *waitq) +{ + Bool can_get = PS3_TRUE; + + if (ps3_atomic_inc_return(waitq->used_rsc) > *waitq->free_rsc) { + ps3_atomic_dec(waitq->used_rsc); + can_get = PS3_FALSE; + } + + return can_get; +} + +static void ps3_qos_pd_in_q(struct ps3_cmd *cmd, struct qos_wait_queue *waitq, + U16 pd_idx) { + ULong flag = 0; + ps3_spin_lock_irqsave(waitq->rsc_lock, &flag); + list_add_tail(&cmd->qos_list, &waitq->wait_list); + waitq->count++; + (*waitq->total_waited_cnt)++; + cmd->qos_waitq_flag = PS3_QOS_CMD_IN_PD; + cmd->first_over_quota_pd_idx = pd_idx; + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_PD_QUEUE); +} + +static struct qos_wait_queue* ps3_qos_pd_waitq_get(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct ps3_cmd *cmd) +{ + U16 que_id = 0; + struct ps3_instance *instance = NULL; + + instance = cmd->instance; + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + que_id = get_offset_of_vdid(PS3_VDID_OFFSET(instance), + PS3_VDID(&cmd->io_attr.vd_entry->diskPos)); + } else { + if (ps3_is_nvme_direct_cmd(qos_pd_mgr, cmd)) { + que_id = 0; + } else { + que_id = instance->qos_context.max_vd_count; + } + } + + return &qos_pd_mgr->waitqs[que_id]; +} + +static Bool ps3_qos_pd_quota_get(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct ps3_cmd *cmd, U16 pd_idx, struct qos_wait_queue *waitq) +{ + Bool can_get = PS3_FALSE; + + can_get = ps3_qos_pd_quota_add(waitq); + if (!can_get) { + ps3_qos_pd_in_q(cmd, waitq, pd_idx); + LOG_DEBUG("insert qos pd quota waitq.host_no:%u:t_id:0x%llx CFID:%u waitq[%u,%u] did[%u,%u]\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + waitq->id, waitq->count, qos_pd_mgr->disk_id, pd_idx); + } else { + cmd->target_pd[pd_idx].get_quota = PS3_TRUE; + } + + return can_get; +} + +static bool ps3_qos_pd_quota_req(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct ps3_cmd *cmd, U16 pd_idx) +{ + bool can_get = PS3_FALSE; + ULong flag = 0; + struct qos_wait_queue *waitq = NULL; + + waitq = ps3_qos_pd_waitq_get(qos_pd_mgr, cmd); + if (likely((*waitq->total_waited_cnt) == 0)) { + can_get = ps3_qos_pd_quota_get(qos_pd_mgr, cmd, pd_idx, waitq); + } else { + INJECT_START(PS3_ERR_IJ_QOS_WAIT_PD_WAITQ_CLEAR, cmd->instance) + ps3_spin_lock_irqsave(waitq->rsc_lock, &flag); + if ((*waitq->total_waited_cnt) > 0) { + list_add_tail(&cmd->qos_list, &waitq->wait_list); + waitq->count++; + (*waitq->total_waited_cnt)++; + cmd->qos_waitq_flag = PS3_QOS_CMD_IN_PD; + cmd->first_over_quota_pd_idx = pd_idx; + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); + can_get = PS3_FALSE; + LOG_DEBUG("insert qos pd quota waitq.host_no:%u:t_id:0x%llx CFID:%u waitq[%u,%u] did[%u,%u]\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + waitq->id, waitq->count, qos_pd_mgr->disk_id, pd_idx); + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_PD_QUEUE); + } else { + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); + can_get = ps3_qos_pd_quota_get(qos_pd_mgr, cmd, pd_idx, waitq); + } + } + + return can_get; +} + +static bool ps3_qos_pd_quota_check(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct ps3_cmd *cmd) +{ + bool can_get = PS3_FALSE; + ULong flag = 0; + struct qos_wait_queue *waitq = NULL; + + waitq = ps3_qos_pd_waitq_get(qos_pd_mgr, cmd); + if (likely((*waitq->total_waited_cnt) == 0)) { + can_get = ps3_qos_pd_quota_add(waitq); + } else { + INJECT_START(PS3_ERR_IJ_QOS_WAIT_PD_WAITQ_CLEAR_2, cmd->instance) + ps3_spin_lock_irqsave(waitq->rsc_lock, &flag); + if ((*waitq->total_waited_cnt) > 0) { + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); + can_get = PS3_FALSE; + } else { + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); + can_get = ps3_qos_pd_quota_add(waitq); + } + } + + return can_get; +} + +static inline bool ps3_qos_vd_quota_dec(struct ps3_qos_vd_mgr *qos_vd_mgr) +{ + Bool can_get = PS3_FALSE; + if (ps3_atomic_dec_return(&qos_vd_mgr->vd_quota) >= 0) { + can_get = PS3_TRUE; + } else { + ps3_atomic_inc(&qos_vd_mgr->vd_quota); + can_get = PS3_FALSE; + } + + return can_get; +} + +static void ps3_qos_insert_vd_quota_waitq(struct ps3_qos_vd_mgr *qos_vd_mgr, struct ps3_cmd *cmd) +{ + ULong flag = 0; + struct qos_wait_queue *wait_q = NULL; + + wait_q = &qos_vd_mgr->vd_quota_wait_q; + ps3_spin_lock_irqsave(wait_q->rsc_lock, &flag); + list_add_tail(&cmd->qos_list, &wait_q->wait_list); + wait_q->count++; + cmd->qos_waitq_flag = PS3_QOS_CMD_IN_VD; + ps3_spin_unlock_irqrestore(wait_q->rsc_lock, flag); + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_VD_QUEUE); + LOG_DEBUG("insert qos vd quota waitq.host_no:%u:tid:0x%llx CFID:%u diskid:%u waitq:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + cmd->io_attr.disk_id, wait_q->count); +} + +static bool ps3_qos_vd_quota_get_waitq(struct ps3_qos_vd_mgr *qos_vd_mgr, struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + can_get = ps3_qos_vd_quota_dec(qos_vd_mgr); + if (!can_get) { + ps3_qos_insert_vd_quota_waitq(qos_vd_mgr, cmd); + } + + return can_get; +} + +static bool ps3_qos_vd_quota_check(struct ps3_cmd *cmd) +{ + bool can_get = PS3_FALSE; + ULong flag = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct qos_wait_queue *wait_q = NULL; + + qos_vd_mgr = ps3_qos_vd_mgr_get(cmd); + wait_q = &qos_vd_mgr->vd_quota_wait_q; + if (likely(wait_q->count == 0)){ + can_get = ps3_qos_vd_quota_get_waitq(qos_vd_mgr, cmd); + } else { + INJECT_START(PS3_ERR_IJ_QOS_WAIT_VD_WAITQ_CLEAR, cmd->instance) + ps3_spin_lock_irqsave(wait_q->rsc_lock, &flag); + if (wait_q->count > 0) { + list_add_tail(&cmd->qos_list, &wait_q->wait_list); + wait_q->count++; + cmd->qos_waitq_flag = PS3_QOS_CMD_IN_VD; + ps3_spin_unlock_irqrestore(wait_q->rsc_lock, flag); + can_get = PS3_FALSE; + LOG_DEBUG("insert qos vd quota waitq.host_no:%u:tid:0x%llx CFID:%u " + "diskid:%u waitq:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + cmd->io_attr.disk_id, wait_q->count); + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_VD_QUEUE); + } else { + ps3_spin_unlock_irqrestore(wait_q->rsc_lock, flag); + can_get = ps3_qos_vd_quota_get_waitq(qos_vd_mgr, cmd); + } + } + + return can_get; +} + +static inline Bool ps3_qos_pd_notify_judge(struct ps3_qos_pd_mgr *qos_pd_mgr) +{ + Bool can_notify = PS3_FALSE; + + can_notify = qos_pd_mgr->total_wait_cmd_cnt && + (ps3_atomic_read(&qos_pd_mgr->pd_used_quota) < qos_pd_mgr->pd_quota); + if (PS3_QOS_PD_IS_VD_MEMBER(qos_pd_mgr) || can_notify) { + goto _out; + } else { + can_notify = qos_pd_mgr->total_waited_direct_cmd && + (ps3_atomic_read(&qos_pd_mgr->direct_used_quota) < qos_pd_mgr->direct_quota); + } +_out: + INJECT_START(PS3_ERR_IJ_QOS_NOT_AWAKE_PD, &can_notify) + return can_notify; +} + +static Bool ps3_qos_single_pd_notify(struct ps3_qos_pd_context *qos_pd_ctx, + struct ps3_qos_pd_mgr *qos_pd_mgr) +{ + struct workqueue_struct *workq = NULL; + Bool notified = PS3_FALSE; + + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1) { + if (ps3_qos_pd_notify_judge(qos_pd_mgr)) { + workq = qos_pd_ctx->work_queues[qos_pd_mgr->workq_id]; + queue_work(workq, &qos_pd_mgr->resend_work); + notified = PS3_TRUE; + } + } + + return notified; +} + +static void ps3_qos_pd_notify(struct ps3_instance *instance) +{ + U16 id = 0; + struct ps3_qos_pd_context *qos_pd_ctx = NULL; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + qos_pd_ctx = &instance->qos_context.pd_ctx; + for (id = 1; id <= instance->qos_context.max_pd_count; id++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, id); + ps3_qos_single_pd_notify(qos_pd_ctx, qos_pd_mgr); + } +} + +static Bool ps3_qos_single_vd_notify(struct ps3_qos_vd_context *qos_vd_ctx, + struct ps3_qos_vd_mgr *qos_vd_mgr) +{ + struct workqueue_struct *workq = NULL; + Bool notify = PS3_FALSE; + + if (qos_vd_mgr->valid) { + if (qos_vd_mgr->vd_quota_wait_q.count > 0 && + ps3_atomic_read(&qos_vd_mgr->vd_quota) > 0) { + workq = qos_vd_ctx->work_queues[qos_vd_mgr->workq_id]; + queue_work(workq, &qos_vd_mgr->resend_work); + notify = PS3_TRUE; + } + } + + return notify; +} + +static U8 ps3_qos_vd_notify(struct ps3_instance *instance) +{ + U8 notify = PS3_FALSE; + U16 id = 0; + struct ps3_qos_vd_context *qos_vd_ctx = NULL; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + + qos_vd_ctx = &instance->qos_context.vd_ctx; + for (id = 1; id <= instance->qos_context.max_vd_count; id++) { + qos_vd_mgr = &qos_vd_ctx->qos_vd_mgrs[id]; + if (ps3_qos_single_vd_notify(qos_vd_ctx, qos_vd_mgr)) { + notify = PS3_TRUE; + } + } + + return notify; +} + +static Bool ps3_qos_tag_rsc_available(struct ps3_instance *instance) +{ + Bool rsc_avail = PS3_FALSE; + U16 i = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + if (ps3_atomic_read(&qos_tg_ctx->share_free_cnt) > 0) { + rsc_avail = PS3_TRUE; + goto _lout; + } + + if (qos_tg_ctx->mgr_cmd_wait_q.count > 0 && + ps3_atomic_read(&qos_tg_ctx->mgr_free_cnt) > 0) { + rsc_avail = PS3_TRUE; + goto _lout; + } + + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + qos_vd_mgr = &instance->qos_context.vd_ctx.qos_vd_mgrs[i]; + if (ps3_atomic_read(&qos_vd_mgr->exclusive_cmd_cnt) > 0 && + qos_tg_ctx->vd_cmd_waitqs[i].count > 0) { + rsc_avail = PS3_TRUE; + break; + } + } + +_lout: + INJECT_START(PS3_ERR_IJ_QOS_NOT_AWAKE_TAG, &rsc_avail); + return rsc_avail; +} + +static Bool ps3_qos_tg_notify(struct ps3_instance *instance) +{ + Bool notified = PS3_FALSE; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + + if (qos_tg_ctx->total_wait_cmd_cnt > 0 && + ps3_qos_tag_rsc_available(instance)) { + queue_work(qos_tg_ctx->work_queue, &qos_tg_ctx->resend_work); + notified = PS3_TRUE; + } + + return notified; +} + +Bool ps3_qos_all_pd_rc_get(struct ps3_cmd *cmd) +{ + cmd->target_pd[cmd->first_over_quota_pd_idx].get_quota = PS3_TRUE; + PS3_QOS_STAT_END(cmd->instance, cmd, PS3_QOS_PD_QUEUE); + LOG_DEBUG("resend cmd judge:host_no:%u t_id:0x%llx cmd:%u cmd_t:%u dev_t:%u ret[%u,%u]\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, cmd->cmd_word.type, cmd->io_attr.dev_type, + cmd->first_over_quota_pd_idx, 1); + return PS3_TRUE; +} + +static void ps3_vd_quota_waitq_clean( struct ps3_qos_vd_mgr *qos_vd_mgr, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + ULong flag = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + + ps3_spin_lock_irqsave(qos_vd_mgr->vd_quota_wait_q.rsc_lock, &flag); + if (qos_vd_mgr->vd_quota_wait_q.count > 0) { + list_for_each_entry_safe(cmd, cmd_next, &qos_vd_mgr->vd_quota_wait_q.wait_list, qos_list) { + if (priv_data == NULL || + priv_data == scsi_device_private_data(cmd->scmd)) { + list_del(&cmd->qos_list); + qos_vd_mgr->vd_quota_wait_q.count--; + LOG_DEBUG("qos clean vd quota waitq. hno:%u t_id:0x%llx cmd:%d vd_id:%u\n", + PS3_HOST(qos_vd_mgr->instance), cmd->trace_id, cmd->index, qos_vd_mgr->id); + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + } + } + ps3_spin_unlock_irqrestore(qos_vd_mgr->vd_quota_wait_q.rsc_lock, flag); + LOG_FILE_INFO("clean qos device vd quota waitq host_no:%u diskid:%u\n", + PS3_HOST(qos_vd_mgr->instance), qos_vd_mgr->id); +} + +static void ps3_qos_vd_quota_waitq_resend(struct ps3_qos_vd_mgr *qos_vd_mgr) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + ULong flag = 0; + S32 ret = PS3_SUCCESS; + Bool waitq_cleared = PS3_FALSE; + struct ps3_instance *instance = qos_vd_mgr->instance; + + ps3_spin_lock_irqsave(qos_vd_mgr->vd_quota_wait_q.rsc_lock, &flag); + if (qos_vd_mgr->vd_quota_wait_q.count > 0 + && ps3_atomic_read(&qos_vd_mgr->vd_quota) > 0) { + list_for_each_entry_safe(cmd, cmd_next, &qos_vd_mgr->vd_quota_wait_q.wait_list, qos_list) { + if (ps3_atomic_dec_return(&qos_vd_mgr->vd_quota) < 0) { + ps3_atomic_inc(&qos_vd_mgr->vd_quota); + break; + } + list_del(&cmd->qos_list); + qos_vd_mgr->vd_quota_wait_q.count--; + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_VD_QUEUE); + if (ps3_qos_tg_decision(cmd)) { + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_cmd_update(instance, cmd); + ps3_qos_cmd_resend_fail(cmd, ret); + } else { + cmd->qos_waitq_flag = 0; + LOG_DEBUG("qos vd quota waitq resend:host_no:%u vid:%u t_id:0x%llx CFID:%u type:%u\n", + PS3_HOST(instance), qos_vd_mgr->id, cmd->trace_id, cmd->index, cmd->cmd_word.type); + } + } + } + + if (qos_vd_mgr->vd_quota_wait_q.count == 0) { + waitq_cleared = PS3_TRUE; + } + } + ps3_spin_unlock_irqrestore(qos_vd_mgr->vd_quota_wait_q.rsc_lock, flag); + if (waitq_cleared) { + LOG_DEBUG("qos vd quota waitq cleared.host_no:%u vd:%u\n", + PS3_HOST(instance), qos_vd_mgr->id); + } + + qos_vd_mgr->last_sched_jiffies = jiffies; + ps3_qos_pd_notify(instance); +} + +static void ps3_qos_vd_resend_work(struct work_struct *work) +{ + struct ps3_qos_vd_mgr *qos_vd_mgr = + ps3_container_of(work, struct ps3_qos_vd_mgr, resend_work); + ps3_qos_vd_quota_waitq_resend(qos_vd_mgr); +} + +static void ps3_qos_waitq_clean(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct qos_wait_queue *waitq, S32 resp_status) +{ + ULong flag = 0; + struct ps3_cmd *cmd = NULL; + ps3_spin_lock_irqsave(waitq->rsc_lock, &flag); + while (waitq->count > 0) { + cmd = list_first_entry(&waitq->wait_list, struct ps3_cmd, qos_list); + LOG_DEBUG("qos clean pd waitq. hno:%u t_id:0x%llx CFID:%d pid:%u que_id:%u\n", + PS3_HOST(qos_pd_mgr->instance), cmd->trace_id, cmd->index, + qos_pd_mgr->disk_id, waitq->id); + list_del(&cmd->qos_list); + waitq->count--; + (*waitq->total_waited_cnt)--; + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); +} + +void ps3_pd_quota_waitq_clear_all(struct ps3_qos_pd_mgr *qos_pd_mgr, + S32 resp_status) +{ + U16 i = 0; + struct qos_wait_queue *waitq = NULL; + + for (i = 0; i < qos_pd_mgr->waitq_cnt; i++) { + waitq = &qos_pd_mgr->waitqs[i]; + ps3_qos_waitq_clean(qos_pd_mgr, waitq, resp_status); + } + + LOG_DEBUG("clear all qos pd quota waitq host_no:%u did:%u vid:%u\n", + PS3_HOST(qos_pd_mgr->instance), qos_pd_mgr->disk_id, qos_pd_mgr->vd_id); +} + +void ps3_pd_quota_waitq_clean(struct ps3_qos_pd_mgr *qos_pd_mgr, + U16 que_id, S32 resp_status) +{ + struct qos_wait_queue *waitq = NULL; + if (que_id == 0) { + ps3_pd_quota_waitq_clear_all(qos_pd_mgr, resp_status); + } else { + waitq = &qos_pd_mgr->waitqs[que_id]; + ps3_qos_waitq_clean(qos_pd_mgr, waitq, resp_status); + } + + LOG_DEBUG("clean qos pd quota waitq host_no:%u did:%u vid:%u\n", + PS3_HOST(qos_pd_mgr->instance), qos_pd_mgr->disk_id, qos_pd_mgr->vd_id); +} + +static Bool ps3_hba_qos_pd_resend_check(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + + if (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD) { + if (!ps3_qos_vd_quota_check(cmd)) { + goto _out; + } + } + can_get = ps3_qos_tg_decision(cmd); +_out: + return can_get; +} + +static Bool ps3_qos_pd_resend_check(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + + if (cmd->io_attr.direct_flag == PS3_CMDWORD_DIRECT_OK) { + cmd->target_pd[cmd->first_over_quota_pd_idx].get_quota = PS3_TRUE; + PS3_QOS_STAT_END(cmd->instance, cmd, PS3_QOS_PD_QUEUE); + can_get = PS3_TRUE; + } else { + if (!ps3_qos_all_pd_rc_get(cmd)) { + goto _out; + } + can_get = instance->qos_context.opts.qos_pd_resend_check(cmd); + } +_out: + return can_get; +} + +static Bool ps3_qos_vd_seq_check(struct ps3_cmd *cmd) +{ + struct PS3VDEntry *vd_entry = NULL; + U16 vd_id = 0; + Bool seq_changed = PS3_FALSE; + + INJECT_START(PS3_ERR_IJ_QOS_FORCE_VD_SEQ_CHANGE, cmd); + if (cmd->cmd_word.direct == PS3_CMDWORD_DIRECT_ADVICE) { + vd_id = PS3_VDID(&cmd->io_attr.vd_entry->diskPos); + vd_entry = ps3_dev_mgr_lookup_vd_info_by_id(cmd->instance, vd_id); + if (!vd_entry || vd_entry->virtDiskSeq != + cmd->req_frame->hwReq.reqHead.virtDiskSeq) { + seq_changed = PS3_TRUE; + LOG_DEBUG("qos pd waitq vd seq check:host_no:%u" + "t_id:0x%llx CFID:%u seq[%u %u]\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + cmd->req_frame->hwReq.reqHead.virtDiskSeq, + (!vd_entry) ? 0 : vd_entry->virtDiskSeq); + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, + SCSI_STATUS_TASK_ABORTED, PS3_FALSE); + } + } + + return seq_changed; +} + +static U32 ps3_qos_pd_resend_cmd(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct qos_wait_queue *waitq, S32 count) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_instance *instance = qos_pd_mgr->instance; + U32 can_send = 0; + U32 que_cnt = 0; + S32 avail_rsc = 0; + S32 used_rsc = ps3_atomic_read(waitq->used_rsc); + + if (used_rsc < *waitq->free_rsc) { + avail_rsc = *waitq->free_rsc - used_rsc; + } + can_send = PS3_MIN(avail_rsc, count); + que_cnt = waitq->count; + while(can_send > 0 && waitq->count > 0) { + cmd = list_first_entry(&waitq->wait_list, struct ps3_cmd, qos_list); + list_del(&cmd->qos_list); + waitq->count--; + (*waitq->total_waited_cnt)--; + if (ps3_qos_vd_seq_check(cmd)) { + continue; + } + can_send--; + ps3_atomic_inc(waitq->used_rsc); + if (ps3_qos_pd_resend_check(instance, cmd)) { + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_cmd_update(instance, cmd); + ps3_qos_cmd_resend_fail(cmd, ret); + } else { + cmd->qos_waitq_flag = 0; + LOG_DEBUG("qos pd quota waitq resend:host_no:%u qid:%u pid:%u" + "t_id:0x%llx CFID:%u resend[%u %u]\n", + PS3_HOST(instance), waitq->id, qos_pd_mgr->disk_id, + cmd->trace_id, cmd->index, waitq->has_resend, waitq->can_resend); + } + } + } + + return (que_cnt - waitq->count); +} + +static void ps3_qos_pd_waitq_resend(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct qos_wait_queue *waitq ) +{ + ULong flag = 0; + Bool waitq_cleared = PS3_FALSE; + if (waitq->count > 0) { + ps3_spin_lock_irqsave(waitq->rsc_lock, &flag); + if (ps3_atomic_read(waitq->used_rsc) < *waitq->free_rsc) { + ps3_qos_pd_resend_cmd(qos_pd_mgr, waitq, waitq->count); + } + + if (*waitq->total_waited_cnt == 0) { + waitq_cleared = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(waitq->rsc_lock, flag); + + if (waitq_cleared) { + LOG_DEBUG("qos pd quota waitq is cleard. host_no:%u did:%u qid:%u\n", + PS3_HOST(qos_pd_mgr->instance), qos_pd_mgr->disk_id, waitq->id); + } + } +} + +static void ps3_qos_pd_jbod_resend(struct ps3_qos_pd_mgr *qos_pd_mgr) +{ + struct ps3_instance *instance = qos_pd_mgr->instance; + struct qos_wait_queue *waitq = NULL; + U16 que_id = 0; + + if (qos_pd_mgr->dev_type == PS3_DEV_TYPE_NVME_SSD) { + waitq = &qos_pd_mgr->waitqs[0]; + ps3_qos_pd_waitq_resend(qos_pd_mgr, waitq); + } + + que_id = instance->qos_context.max_vd_count; + waitq = &qos_pd_mgr->waitqs[que_id]; + ps3_qos_pd_waitq_resend(qos_pd_mgr, waitq); +} + +void ps3_qos_pd_waitq_ratio_update(struct ps3_qos_pd_mgr *qos_pd_mgr) +{ + U16 min_waitq_cnt = 0; + U16 i = 0; + struct qos_wait_queue *waitq = NULL; + ULong min_cmd_jiffies = 0; + struct ps3_cmd *cmd = NULL; + U16 poll_que_id = 1; + + if (qos_pd_mgr->poll_que_id != qos_pd_mgr->poll_start_que_id) { + return; + } + + waitq = &qos_pd_mgr->waitqs[qos_pd_mgr->poll_que_id]; + if (waitq->has_resend > 0) { + return; + } + + for (i = 1; i < qos_pd_mgr->waitq_cnt - 1; i++) { + waitq = &qos_pd_mgr->waitqs[i]; + if (waitq->count > 0) { + cmd = list_first_entry(&waitq->wait_list, struct ps3_cmd, qos_list); + if (min_waitq_cnt == 0) { + min_waitq_cnt = waitq->count; + min_cmd_jiffies = cmd->scmd->jiffies_at_alloc; + } else { + if (min_waitq_cnt > waitq->count) { + min_waitq_cnt = waitq->count; + } + + if (min_cmd_jiffies > cmd->scmd->jiffies_at_alloc) { + min_cmd_jiffies = cmd->scmd->jiffies_at_alloc; + poll_que_id = i; + } + } + } + } + + for (i = 1; i < qos_pd_mgr->waitq_cnt - 1; i++) { + waitq = &qos_pd_mgr->waitqs[i]; + if (waitq->count > 0) { + waitq->can_resend = waitq->count/min_waitq_cnt > 0 ? + waitq->count/min_waitq_cnt : 1; + waitq->has_resend = 0; + } + } + + qos_pd_mgr->poll_que_id = poll_que_id; + qos_pd_mgr->poll_start_que_id = poll_que_id; + + LOG_DEBUG("qos pd ratio update:host_no:%u pid:%u first:%u\n", + PS3_HOST(qos_pd_mgr->instance), qos_pd_mgr->disk_id, poll_que_id); +} + +static void ps3_qos_pd_vd_member_resend(struct ps3_qos_pd_mgr *qos_pd_mgr) +{ + ULong flag = 0; + struct ps3_instance *instance = qos_pd_mgr->instance; + struct qos_wait_queue *waitq = NULL; + ULong timeout_jiffies = 0; + Bool waitq_cleared = PS3_FALSE; + Bool vd_expired = PS3_FALSE; + U32 pd_wait_count = 0; + + ps3_spin_lock_irqsave(&qos_pd_mgr->rc_lock, &flag); + pd_wait_count = qos_pd_mgr->waitqs[instance->qos_context.max_vd_count].count; + while ((ps3_atomic_read(&qos_pd_mgr->pd_used_quota) < + qos_pd_mgr->pd_quota) && qos_pd_mgr->total_wait_cmd_cnt > pd_wait_count) { + ps3_qos_pd_waitq_ratio_update(qos_pd_mgr); + waitq = &qos_pd_mgr->waitqs[qos_pd_mgr->poll_que_id]; + if (waitq->count == 0) { + goto _next_waitq; + } + + if (waitq->has_resend > 0) { + if (qos_pd_mgr->dev_type == PS3_DEV_TYPE_SAS_HDD || + qos_pd_mgr->dev_type == PS3_DEV_TYPE_SATA_HDD) { + timeout_jiffies = waitq->last_sched_jiffies + + msecs_to_jiffies(PS3_QOS_VD_HDD_DELAY_THD_MS); + } else { + timeout_jiffies = waitq->last_sched_jiffies + + msecs_to_jiffies(PS3_QOS_VD_SDD_DELAY_THD_MS); + } + + vd_expired = time_after(jiffies, timeout_jiffies); + INJECT_START(PS3_ERR_IJ_QOS_PD_RESEND_NOT_EXPIRED, &vd_expired) + if (vd_expired) { + LOG_DEBUG("go to next vd waitq for delay:host_no:%u qid:%u pid:%u", + PS3_HOST(instance), waitq->id, qos_pd_mgr->disk_id); + goto _next_waitq; + } + } + + waitq->last_sched_jiffies = jiffies; + waitq->has_resend += ps3_qos_pd_resend_cmd(qos_pd_mgr, waitq, waitq->can_resend - waitq->has_resend); + if (waitq->has_resend >= waitq->can_resend) { + goto _next_waitq; + } + continue; +_next_waitq: + waitq->has_resend = 0; + if (++qos_pd_mgr->poll_que_id == instance->qos_context.max_vd_count) { + qos_pd_mgr->poll_que_id = 1; + } + } + + if (qos_pd_mgr->total_wait_cmd_cnt == 0) { + waitq_cleared = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(&qos_pd_mgr->rc_lock, flag); + + if (waitq_cleared) { + LOG_DEBUG("qos pd quota waitq is cleard. host_no:%u diskid:%u\n", + PS3_HOST(instance), qos_pd_mgr->disk_id); + } +} + +static void ps3_qos_pd_resend_work(struct work_struct *work) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = + ps3_container_of(work, struct ps3_qos_pd_mgr, resend_work); + + ps3_qos_pd_jbod_resend(qos_pd_mgr); + INJECT_START(PS3_ERR_IJ_QOS_WAIT_VD_SEND, qos_pd_mgr) + ps3_qos_pd_vd_member_resend(qos_pd_mgr); + qos_pd_mgr->last_sched_jiffies = jiffies; + + return; +} + +static void ps3_poll_vd_cmd_waitq(struct ps3_qos_tg_context *qos_tg_ctx) +{ + struct qos_wait_queue *waitq = NULL; + U32 free_cnt = 0; + U8 vd_id = 0; + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + U32 sent_count = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_instance *instance = qos_tg_ctx->instance; + U32 mgrq_cnt = qos_tg_ctx->mgr_cmd_wait_q.count; + + INJECT_START(PS3_ERR_IJ_QOS_SET_SHARE_COUNT, instance) + free_cnt = ps3_atomic_read(&qos_tg_ctx->share_free_cnt); + vd_id = qos_tg_ctx->poll_vd_id; + while (free_cnt > sent_count && qos_tg_ctx->total_wait_cmd_cnt > mgrq_cnt) { + waitq = &qos_tg_ctx->vd_cmd_waitqs[vd_id]; + if (waitq->count > 0) { + qos_vd_mgr = &instance->qos_context.vd_ctx.qos_vd_mgrs[vd_id]; + cmd = list_first_entry(&waitq->wait_list, struct ps3_cmd, qos_list); + list_del(&cmd->qos_list); + cmd->qos_waitq_flag = 0; + waitq->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_TAG_QUEUE); + if (ps3_qos_vd_seq_check(cmd)) { + continue; + } + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_update_vd_quota(cmd); + ps3_qos_update_pd_quota(cmd); + ps3_qos_cmd_resend_fail(cmd, ret); + } else { + ps3_atomic_inc(&qos_vd_mgr->share_cmd_used); + ++sent_count; + LOG_DEBUG("qos cmd waitq resend:host_no:%u t_id:0x%llx CFID:%u type:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, cmd->cmd_word.type); + } + } + + if (++vd_id > instance->qos_context.max_vd_count) { + vd_id = 1; + } + } + ps3_atomic_sub(sent_count, &qos_tg_ctx->share_free_cnt); + LOG_DEBUG("resend vd cmd waitq. host_no:%u poll_vd_id:%u sent:%u\n", + PS3_HOST(instance), vd_id, sent_count); + + qos_tg_ctx->poll_vd_id = vd_id; +} + +static void ps3_mgr_cmd_waitq_resend(struct ps3_qos_tg_context *qos_tg_ctx) +{ + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct qos_wait_queue *wait_q = NULL; + struct ps3_instance *instance = qos_tg_ctx->instance; + S32 ret = PS3_SUCCESS; + U32 free_cnt = ps3_atomic_read(&qos_tg_ctx->share_free_cnt); + U32 sent_count = 0; + + wait_q = &qos_tg_ctx->mgr_cmd_wait_q; + if (wait_q->count > 0 && free_cnt > 0) { + list_for_each_entry_safe(cmd, cmd_next, &wait_q->wait_list, qos_list) { + list_del(&cmd->qos_list); + cmd->qos_waitq_flag = 0; + wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_TAG_QUEUE); + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_cmd_resend_fail(cmd, ret); + } else { + LOG_DEBUG("qos cmd waitq resend:host_no:%u t_id:0x%llx CFID:%u type:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, cmd->cmd_word.type); + ps3_atomic_inc(&qos_tg_ctx->mgr_share_used); + if(++sent_count == free_cnt) { + break; + } + } + } + + ps3_atomic_sub(sent_count, &qos_tg_ctx->share_free_cnt); + } +} + +static void ps3_qos_tg_share_resend(struct ps3_qos_tg_context *qos_tg_ctx) +{ + ps3_mgr_cmd_waitq_resend(qos_tg_ctx); + ps3_poll_vd_cmd_waitq(qos_tg_ctx); +} + +static void ps3_qos_tg_exclusive_resend(struct ps3_qos_tg_context *qos_tg_ctx) +{ + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct qos_wait_queue *waitq = NULL; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + S32 ret = PS3_SUCCESS; + U8 id = 0; + struct ps3_instance *instance = qos_tg_ctx->instance; + + waitq = &qos_tg_ctx->mgr_cmd_wait_q; + if (waitq->count > 0 && + ps3_atomic_read(&qos_tg_ctx->mgr_free_cnt) > 0) { + list_for_each_entry_safe(cmd, cmd_next, &waitq->wait_list, qos_list) { + if (ps3_atomic_dec_return(&qos_tg_ctx->mgr_free_cnt) < 0) { + ps3_atomic_inc(&qos_tg_ctx->mgr_free_cnt); + break; + } + list_del(&cmd->qos_list); + cmd->qos_waitq_flag = 0; + waitq->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_TAG_QUEUE); + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_cmd_resend_fail(cmd, ret); + ps3_atomic_inc(&qos_tg_ctx->mgr_free_cnt); + } else { + LOG_DEBUG("qos cmd waitq resend:host_no:%u t_id:0x%llx CFID:%u type:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, cmd->cmd_word.type); + } + } + } + + for (id = 1; id <= instance->qos_context.max_vd_count; id++) { + waitq = &qos_tg_ctx->vd_cmd_waitqs[id]; + qos_vd_mgr = &instance->qos_context.vd_ctx.qos_vd_mgrs[id]; + if (waitq->count > 0 && + ps3_atomic_read(&qos_vd_mgr->exclusive_cmd_cnt) > 0) { + list_for_each_entry_safe(cmd, cmd_next, &waitq->wait_list, qos_list) { + if (ps3_atomic_dec_return(&qos_vd_mgr->exclusive_cmd_cnt) < 0) { + ps3_atomic_inc(&qos_vd_mgr->exclusive_cmd_cnt); + break; + } + list_del(&cmd->qos_list); + cmd->qos_waitq_flag = 0; + waitq->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_TAG_QUEUE); + if (ps3_qos_vd_seq_check(cmd)) { + ps3_atomic_inc(&qos_vd_mgr->exclusive_cmd_cnt); + continue; + } + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_update_vd_quota(cmd); + ps3_qos_update_pd_quota(cmd); + ps3_qos_cmd_resend_fail(cmd, ret); + ps3_atomic_inc(&qos_vd_mgr->exclusive_cmd_cnt); + } else { + LOG_DEBUG("qos cmd waitq resend:host_no:%u t_id:0x%llx CFID:%u type:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, cmd->cmd_word.type); + } + } + } + } +} + +static void ps3_qos_tg_waitq_resend(struct ps3_qos_tg_context *qos_tg_ctx) +{ + ULong flag = 0; + Bool waitq_cleard = PS3_FALSE; + struct ps3_instance *instance = qos_tg_ctx->instance; + + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + ps3_qos_tg_share_resend(qos_tg_ctx); + ps3_qos_tg_exclusive_resend(qos_tg_ctx); + + if (qos_tg_ctx->total_wait_cmd_cnt == 0) { + waitq_cleard = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); + if (waitq_cleard) { + LOG_DEBUG("hno:%u resend all tag waited cmds\n", + PS3_HOST(instance)); + } + + if (!ps3_qos_vd_notify(instance)) { + ps3_qos_pd_notify(instance); + } + qos_tg_ctx->last_sched_jiffies = jiffies; +} + +static void ps3_qos_tg_resend_work(struct work_struct *work) +{ + struct ps3_qos_tg_context *qos_tg_ctx = + ps3_container_of(work, struct ps3_qos_tg_context, resend_work); + ps3_qos_tg_waitq_resend(qos_tg_ctx); +} + +U32 g_ps3_qos_cmdq_depth = PS3_QOS_CMDQ_DEPTH; +U32 g_ps3_qos_mgrq_depth = PS3_QOS_MGRQ_DEPTH; +U32 g_ps3_qos_hdd_pd_quota = PS3_QOS_DEFAULT_PD_QUOTA; +U32 g_ps3_qos_ssd_pd_quota = PS3_QOS_DEFAULT_PD_QUOTA; +U32 g_ps3_qos_sas_pd_quota = PS3_QOS_SAS_PD_QUOTA; +U32 g_ps3_qos_nvme_pd_quota = PS3_QOS_NVME_DIRECT_QUOTA; +U32 g_ps3_qos_nvme_member_quota = PS3_QOS_NVME_MEMBER_QUOTA; +U32 g_ps3_qos_hba_nvme_normal_quota = PS3_QOS_HBA_NVME_NORMAL_QUOTA; +U32 g_ps3_qos_raid_nvme_normal_quota = PS3_QOS_RAID_NVME_NORMAL_QUOTA; +U32 g_ps3_qos_vd_quota = PS3_QOS_FUNC1_JBOD_VD_QUOTA; +U32 g_ps3_qos_max_cmds = PS3_QOS_HBA_MAX_CMD; +U32 g_ps3_qos_jbod_exclusive = PS3_QOS_JBOD_EXCLUSIVE_CMD_COUNT; +U32 g_ps3_qos_vd_exclusive = PS3_QOS_VD_EXCLUSIVE_CMD_COUNT; +U32 g_ps3_qos_mgr_exclusive = QOS_MGR_EXCLUSIVE_CMD_COUNT; + +#define PS3_QOS_MAX_WORKQ_NAME_LENGTH 32 +static S32 ps3_qos_pd_context_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U16 i = 0; + U16 j = 0; + U16 k = 0; + struct ps3_qos_pd_context *qos_pd_ctx = NULL; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + char workq_name[PS3_QOS_MAX_WORKQ_NAME_LENGTH] = {0}; + U16 max_pd_count = 0; + struct qos_wait_queue *waitq = NULL; + U32 cpu_num = 0; + + qos_pd_ctx = &instance->qos_context.pd_ctx; + if (ps3_is_last_func(instance)) { + cpu_num = num_online_cpus(); + if (instance->irq_context.is_balance_current_perf_mode) { + INJECT_START(PS3_ERR_IJ_SET_HIGH_IOPS_CHANNEL_IN_QOS, instance); + if (cpu_num > instance->irq_context.high_iops_msix_vectors + + PS3_QOS_FUNC1_PD_WORKQ_COUNT) { + qos_pd_ctx->workq_count = + cpu_num - instance->irq_context.high_iops_msix_vectors; + } else { + qos_pd_ctx->workq_count = PS3_QOS_FUNC1_PD_WORKQ_COUNT; + } + } else { + qos_pd_ctx->workq_count = PS3_QOS_FUNC1_PD_WORKQ_COUNT; + } + } else { + qos_pd_ctx->workq_count = PS3_QOS_FUNC0_PD_WORKQ_COUNT; + } + + max_pd_count = instance->qos_context.max_pd_count; + qos_pd_ctx->qos_pd_mgrs = (struct ps3_qos_pd_mgr *)ps3_vzalloc(instance, + (max_pd_count + 1) * sizeof(struct ps3_qos_pd_mgr)); + INJECT_START(PS3_ERR_IJ_QOS_PD_INIT_FAIL_2, instance) + if (qos_pd_ctx->qos_pd_mgrs == NULL ) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for qos_pd_mgrs\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _out; + } + memset(qos_pd_ctx->qos_pd_mgrs, 0, sizeof(struct ps3_qos_pd_mgr) * (max_pd_count + 1)); + for (i = 1; i <= max_pd_count; i++) { + qos_pd_mgr = &qos_pd_ctx->qos_pd_mgrs[i]; + INIT_WORK(&qos_pd_mgr->resend_work, ps3_qos_pd_resend_work); + ps3_spin_lock_init(&qos_pd_mgr->rc_lock); + ps3_spin_lock_init(&qos_pd_mgr->direct_rsc_lock); + ps3_spin_lock_init(&qos_pd_mgr->adjust_quota_lock); + + qos_pd_mgr->workq_id = 0; + qos_pd_mgr->clearing = PS3_FALSE; + qos_pd_mgr->poll_cmd_cnt = 1; + qos_pd_mgr->poll_que_id = 1; + qos_pd_mgr->poll_start_que_id = 1; + ps3_atomic_set(&qos_pd_mgr->processing_cnt, 0); + qos_pd_mgr->pd_init_quota = 0; + qos_pd_mgr->instance = instance; + qos_pd_mgr->total_wait_cmd_cnt = 0; + qos_pd_mgr->total_waited_direct_cmd = 0; + qos_pd_mgr->waitq_cnt = instance->qos_context.max_vd_count + 1; + qos_pd_mgr->waitqs = (struct qos_wait_queue *)ps3_vzalloc(instance, + qos_pd_mgr->waitq_cnt * sizeof(struct qos_wait_queue)); + INJECT_START(PS3_ERR_IJ_QOS_PD_INIT_FAIL_3, qos_pd_ctx) + if (qos_pd_mgr->waitqs == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for pd waitqs\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _release_pd_waitq; + } + + for (j = 0; j < qos_pd_mgr->waitq_cnt; j++) { + waitq = &qos_pd_mgr->waitqs[j]; + waitq->count = 0; + waitq->id = j; + waitq->can_resend = 0; + waitq->has_resend = 0; + INIT_LIST_HEAD(&waitq->wait_list); + if (j == 0) { + waitq->free_rsc = &qos_pd_mgr->direct_quota; + waitq->used_rsc = &qos_pd_mgr->direct_used_quota; + waitq->rsc_lock = &qos_pd_mgr->direct_rsc_lock; + waitq->total_waited_cnt = &qos_pd_mgr->total_waited_direct_cmd; + } else { + waitq->free_rsc = &qos_pd_mgr->pd_quota; + waitq->used_rsc = &qos_pd_mgr->pd_used_quota; + waitq->rsc_lock = &qos_pd_mgr->rc_lock; + waitq->total_waited_cnt = &qos_pd_mgr->total_wait_cmd_cnt; + } + } + } + + qos_pd_ctx->work_queues = (struct workqueue_struct **)ps3_vzalloc(instance, + (qos_pd_ctx->workq_count) * sizeof(struct workqueue_struct *)); + INJECT_START(PS3_ERR_IJ_QOS_PD_INIT_FAIL_4, instance) + if (qos_pd_ctx->work_queues == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for work_queues\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _release_pd_mgr; + } + memset(qos_pd_ctx->work_queues, 0, (qos_pd_ctx->workq_count) * sizeof(struct workqueue_struct *)); + for (j = 0; j < qos_pd_ctx->workq_count; j++) { + snprintf(workq_name, PS3_QOS_MAX_WORKQ_NAME_LENGTH, "pd_wq_f%u_%u", + ps3_get_pci_function(instance->pdev), j); + qos_pd_ctx->work_queues[j] = create_singlethread_workqueue(workq_name); + INJECT_START(PS3_ERR_IJ_QOS_PD_INIT_FAIL_1, qos_pd_ctx) + if (qos_pd_ctx->work_queues[j] == NULL) { + LOG_ERROR("qos pd workq:%u create failed\n", j); + ret = -PS3_FAILED; + goto _destroy_created_workqueue; + } + } + + LOG_INFO("hno:%u: qos pd context init success\n", PS3_HOST(instance)); + goto _out; +_destroy_created_workqueue: + for (k = 0; k < j; k++) { + destroy_workqueue(qos_pd_ctx->work_queues[k]); + qos_pd_ctx->work_queues[k] = NULL; + } + ps3_vfree(instance, qos_pd_ctx->work_queues); + qos_pd_ctx->work_queues = NULL; +_release_pd_waitq: + for (k = 1; k < i; k++) { + qos_pd_mgr = &qos_pd_ctx->qos_pd_mgrs[k]; + if (qos_pd_mgr->waitqs) { + ps3_vfree(instance, qos_pd_mgr->waitqs); + qos_pd_mgr->waitqs = NULL; + } + } +_release_pd_mgr: + ps3_vfree(instance, qos_pd_ctx->qos_pd_mgrs); + qos_pd_ctx->qos_pd_mgrs = NULL; +_out: + return ret; +} + +static void ps3_qos_pd_context_exit(struct ps3_instance *instance) +{ + U16 i = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_qos_pd_context *qos_pd_ctx = NULL; + struct workqueue_struct *wq = NULL; + + qos_pd_ctx = &instance->qos_context.pd_ctx; + if (qos_pd_ctx->qos_pd_mgrs != NULL) { + for (i = 1; i <= instance->qos_context.max_pd_count; i++) { + qos_pd_mgr = &qos_pd_ctx->qos_pd_mgrs[i]; + cancel_work_sync(&qos_pd_mgr->resend_work); + ps3_vfree(instance, qos_pd_mgr->waitqs); + qos_pd_mgr->waitqs = NULL; + } + ps3_vfree(instance, qos_pd_ctx->qos_pd_mgrs); + qos_pd_ctx->qos_pd_mgrs = NULL; + } + + if (qos_pd_ctx->work_queues != NULL) { + for (i = 0; i < qos_pd_ctx->workq_count; i++) { + wq = qos_pd_ctx->work_queues[i]; + flush_workqueue(wq); + destroy_workqueue(wq); + qos_pd_ctx->work_queues[i] = NULL; + } + ps3_vfree(instance, qos_pd_ctx->work_queues); + qos_pd_ctx->work_queues = NULL; + } +} + +static S32 ps3_qos_vd_context_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U16 i = 0; + U16 j = 0; + struct ps3_qos_vd_context *qos_vd_ctx = NULL; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + char workq_name[PS3_QOS_MAX_WORKQ_NAME_LENGTH] = {0}; + U16 max_vd_count = 0; + U16 jbod_vd_quota = 0; + + qos_vd_ctx = &instance->qos_context.vd_ctx; + if (ps3_is_last_func(instance)) { + qos_vd_ctx->vd_exclusive_cnt = g_ps3_qos_vd_exclusive; + qos_vd_ctx->jbod_exclusive_cnt = g_ps3_qos_jbod_exclusive; + } else { + qos_vd_ctx->vd_exclusive_cnt = 0; + qos_vd_ctx->jbod_exclusive_cnt = 0; + } + + jbod_vd_quota = instance->qos_context.tg_ctx.share + qos_vd_ctx->jbod_exclusive_cnt; + + max_vd_count = instance->qos_context.max_vd_count; + qos_vd_ctx->qos_vd_mgrs = (struct ps3_qos_vd_mgr *)ps3_vzalloc(instance, + (max_vd_count + 1) * sizeof(struct ps3_qos_vd_mgr)); + INJECT_START(PS3_ERR_IJ_QOS_VD_INIT_FAIL_1, instance) + if (qos_vd_ctx->qos_vd_mgrs == NULL ) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for qos_vd_mgrs\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _out; + } + memset(qos_vd_ctx->qos_vd_mgrs, 0, sizeof(struct ps3_qos_vd_mgr) * (max_vd_count + 1)); + for (i = 1; i <= max_vd_count; i++) { + qos_vd_mgr = &qos_vd_ctx->qos_vd_mgrs[i]; + qos_vd_mgr->instance = instance; + ps3_spin_lock_init(&qos_vd_mgr->rsc_lock); + INIT_LIST_HEAD(&qos_vd_mgr->vd_quota_wait_q.wait_list); + qos_vd_mgr->vd_quota_wait_q.rsc_lock = &qos_vd_mgr->rsc_lock; + qos_vd_mgr->vd_quota_wait_q.count = 0; + INIT_WORK(&qos_vd_mgr->resend_work, ps3_qos_vd_resend_work); + qos_vd_mgr->workq_id = 0; + qos_vd_mgr->id = i; + if (i == max_vd_count) { + ps3_atomic_set(&qos_vd_mgr->vd_quota, jbod_vd_quota); + ps3_atomic_set(&qos_vd_mgr->exclusive_cmd_cnt, qos_vd_ctx->jbod_exclusive_cnt); + qos_vd_mgr->valid = PS3_TRUE; + } else { + ps3_atomic_set(&qos_vd_mgr->exclusive_cmd_cnt, qos_vd_ctx->vd_exclusive_cnt); + } + ps3_atomic_set(&qos_vd_mgr->share_cmd_used, 0); + } + + qos_vd_ctx->workq_count = 1; + qos_vd_ctx->work_queues = (struct workqueue_struct **)ps3_vzalloc(instance, + (qos_vd_ctx->workq_count) * sizeof(struct workqueue_struct *)); + INJECT_START(PS3_ERR_IJ_QOS_VD_INIT_FAIL_2, instance) + if (qos_vd_ctx->work_queues == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for work_queues\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _release_vd_mgr; + } + memset(qos_vd_ctx->work_queues, 0, (qos_vd_ctx->workq_count) * sizeof(struct workqueue_struct *)); + for (i = 0; i < qos_vd_ctx->workq_count; i++) { + snprintf(workq_name, PS3_QOS_MAX_WORKQ_NAME_LENGTH, "qos_vd_wq_f%u_%u", + ps3_get_pci_function(instance->pdev), i); + qos_vd_ctx->work_queues[i] = create_singlethread_workqueue(workq_name); + INJECT_START(PS3_ERR_IJ_QOS_VD_INIT_FAIL_3, instance) + if (qos_vd_ctx->work_queues[i] == NULL) { + LOG_ERROR("qos vd workq:%u create failed\n", i); + ret = -PS3_FAILED; + goto _destroy_created_workqueue; + } + } + + LOG_INFO("hno:%u: qos vd context init success\n", PS3_HOST(instance)); + + goto _out; +_destroy_created_workqueue: + for (j = 0; j < i; j++) { + destroy_workqueue(qos_vd_ctx->work_queues[j]); + qos_vd_ctx->work_queues[j] = NULL; + } + ps3_vfree(instance, qos_vd_ctx->work_queues); + qos_vd_ctx->work_queues = NULL; +_release_vd_mgr: + ps3_vfree(instance, qos_vd_ctx->qos_vd_mgrs); + qos_vd_ctx->qos_vd_mgrs = NULL; +_out: + return ret; +} + +static void ps3_qos_vd_context_exit(struct ps3_instance *instance) +{ + U16 i = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_qos_vd_context *qos_vd_ctx = NULL; + struct workqueue_struct *wq = NULL; + + qos_vd_ctx = &instance->qos_context.vd_ctx; + if (qos_vd_ctx->qos_vd_mgrs != NULL) { + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + qos_vd_mgr = &qos_vd_ctx->qos_vd_mgrs[i]; + cancel_work_sync(&qos_vd_mgr->resend_work); + } + ps3_vfree(instance, qos_vd_ctx->qos_vd_mgrs); + qos_vd_ctx->qos_vd_mgrs = NULL; + } + + if (qos_vd_ctx->work_queues != NULL) { + for (i = 0; i < qos_vd_ctx->workq_count; i++) { + wq = qos_vd_ctx->work_queues[i]; + flush_workqueue(wq); + destroy_workqueue(wq); + } + ps3_vfree(instance, qos_vd_ctx->work_queues); + qos_vd_ctx->work_queues = NULL; + } +} + +static S32 ps3_qos_tg_context_init(struct ps3_instance *instance) +{ + struct ps3_qos_tg_context *qos_tg_ctx = NULL; + S32 ret = PS3_SUCCESS; + U64 tfifo_depth = 0; + U16 i = 0; + struct qos_wait_queue *wait_q = NULL; + char workq_name[PS3_QOS_MAX_WORKQ_NAME_LENGTH] = {0}; + U32 tag_exclusive = 0; + + ps3_tfifo_depth_get(instance, &tfifo_depth); + INJECT_START(PS3_ERR_IJ_QOS_FORCE_TFIFO_ZERO_DEPTH, &tfifo_depth) + if (tfifo_depth == 0) { + ret = -PS3_FAILED; + LOG_ERROR("hno:%u:tfifo_depth is invalid func:%u\n", + PS3_HOST(instance), + ps3_get_pci_function(instance->pdev)); + goto out; + } + qos_tg_ctx = &instance->qos_context.tg_ctx; + qos_tg_ctx->instance = instance; + + qos_tg_ctx->high_pri_exclusive_cnt = QOS_HIGH_PRI_EXCLUSIVE_CMD_COUNT; + qos_tg_ctx->mgr_exclusive_cnt = g_ps3_qos_mgr_exclusive; + if (!ps3_ioc_multi_func_support(instance)) { + tag_exclusive = qos_tg_ctx->mgr_exclusive_cnt + qos_tg_ctx->high_pri_exclusive_cnt + + g_ps3_qos_jbod_exclusive + instance->ctrl_info.maxVdCount * g_ps3_qos_vd_exclusive; + } else { + qos_tg_ctx->high_pri_exclusive_cnt = qos_tg_ctx->high_pri_exclusive_cnt >> 1; + qos_tg_ctx->mgr_exclusive_cnt = qos_tg_ctx->mgr_exclusive_cnt >> 1; + tag_exclusive = qos_tg_ctx->high_pri_exclusive_cnt + qos_tg_ctx->mgr_exclusive_cnt; + if (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_1) { + tag_exclusive += (g_ps3_qos_jbod_exclusive + instance->ctrl_info.maxVdCount * g_ps3_qos_vd_exclusive); + } + } + + if (tfifo_depth > tag_exclusive) { + qos_tg_ctx->share = tfifo_depth - tag_exclusive; + } else { + qos_tg_ctx->share = tag_exclusive; + } + + ps3_atomic_set(&qos_tg_ctx->mgr_free_cnt, qos_tg_ctx->mgr_exclusive_cnt); + ps3_atomic_set(&qos_tg_ctx->share_free_cnt, qos_tg_ctx->share); + ps3_atomic_set(&qos_tg_ctx->mgr_share_used, 0); + ps3_spin_lock_init(&qos_tg_ctx->lock); + qos_tg_ctx->poll_vd_id = 1; + + wait_q = &qos_tg_ctx->mgr_cmd_wait_q; + INIT_LIST_HEAD(&wait_q->wait_list); + qos_tg_ctx->vd_cmd_waitqs = (struct qos_wait_queue *)ps3_vzalloc(instance, + (instance->qos_context.max_vd_count + 1) * sizeof(struct qos_wait_queue)); + INJECT_START(PS3_ERR_IJ_QOS_TAG_INIT_FAIL_1, qos_tg_ctx) + if (qos_tg_ctx->vd_cmd_waitqs == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for qos_context\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto out; + } + memset(qos_tg_ctx->vd_cmd_waitqs, 0, (instance->qos_context.max_vd_count + 1) * sizeof(struct qos_wait_queue)); + for (i = 1; i < instance->qos_context.max_vd_count + 1; i++) { + wait_q = &qos_tg_ctx->vd_cmd_waitqs[i]; + INIT_LIST_HEAD(&wait_q->wait_list); + } + + INIT_WORK(&qos_tg_ctx->resend_work, ps3_qos_tg_resend_work); + snprintf(workq_name, PS3_QOS_MAX_WORKQ_NAME_LENGTH, "qos_tag_wq_f%u", ps3_get_pci_function(instance->pdev)); + qos_tg_ctx->work_queue = create_singlethread_workqueue(workq_name); + INJECT_START(PS3_ERR_IJ_QOS_TAG_INIT_FAIL_2, qos_tg_ctx) + if (qos_tg_ctx->work_queue == NULL) { + LOG_ERROR("qos tag workq:%u create failed\n", i); + ret = -PS3_FAILED; + goto release_vd_cmd_waitqs; + } + + LOG_INFO("hno:%u func:%u: qos tg context init success tfifo:%llu\n", + PS3_HOST(instance), ps3_get_pci_function(instance->pdev), tfifo_depth); + goto out; +release_vd_cmd_waitqs: + ps3_vfree(instance, qos_tg_ctx->vd_cmd_waitqs); + qos_tg_ctx->vd_cmd_waitqs = NULL; +out: + return ret; +} + +static void ps3_qos_tg_context_exit(struct ps3_instance *instance) +{ + struct ps3_qos_tg_context *qos_tg_ctx = NULL; + + qos_tg_ctx = &instance->qos_context.tg_ctx; + if (qos_tg_ctx->work_queue != NULL) { + cancel_work_sync(&qos_tg_ctx->resend_work); + flush_workqueue(qos_tg_ctx->work_queue); + destroy_workqueue(qos_tg_ctx->work_queue); + qos_tg_ctx->work_queue = NULL; + } + + if (qos_tg_ctx->vd_cmd_waitqs != NULL) { + ps3_vfree(instance, qos_tg_ctx->vd_cmd_waitqs); + qos_tg_ctx->vd_cmd_waitqs = NULL; + } +} + +S32 ps3_hba_qos_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + ret = ps3_qos_tg_context_init(instance); + if (ret != PS3_SUCCESS) { + goto _out; + } + + ret = ps3_qos_vd_context_init(instance); + if (ret != PS3_SUCCESS) { + goto _tg_ctx_exit; + } + + ret = ps3_qos_pd_context_init(instance); + if (ret != PS3_SUCCESS) { + goto _vd_ctx_exit; + } + + goto _out; +_vd_ctx_exit: + ps3_qos_vd_context_exit(instance); +_tg_ctx_exit: + ps3_qos_tg_context_exit(instance); +_out: + return ret; +} + +void ps3_hba_qos_exit(struct ps3_instance *instance) +{ + ps3_qos_tg_context_exit(instance); + ps3_qos_vd_context_exit(instance); + ps3_qos_pd_context_exit(instance); + + LOG_INFO("hba qos exit. host_no:%u\n", PS3_HOST(instance)); +} + +static Bool ps3_qos_vd_member_insert(struct ps3_cmd *cmd) +{ + U8 i = 0; + U16 disk_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct qos_wait_queue *waitq = NULL; + Bool in_queue = PS3_FALSE; + + for (i = 0; i < cmd->target_pd_count; i++) { + disk_id = cmd->target_pd[i].flat_disk_id; + qos_pd_mgr = ps3_qos_pd_mgr_get(cmd->instance, disk_id); + ps3_atomic_inc(&qos_pd_mgr->processing_cnt); + INJECT_START(PS3_ERR_IJ_QOS_VD_MEMBER_CLEARING, qos_pd_mgr); + if (unlikely(qos_pd_mgr->clearing)) { + LOG_DEBUG("qos vd member is clearing .host_no:%u:t_id:0x%llx CFID:%u did[%u %u]\n", + PS3_HOST(qos_pd_mgr->instance), cmd->trace_id, cmd->index, + qos_pd_mgr->disk_id, qos_pd_mgr->vd_id); + ps3_atomic_dec(&qos_pd_mgr->processing_cnt); + } else { + in_queue = PS3_TRUE; + break; + } + } + + if (in_queue) { + waitq = ps3_qos_pd_waitq_get(qos_pd_mgr, cmd); + ps3_qos_pd_in_q(cmd, waitq, i); + ps3_atomic_dec(&qos_pd_mgr->processing_cnt); + LOG_DEBUG("insert qos pd quota waitq.host_no:%u:t_id:0x%llx" + " CFID:%u waitq[%u,%u] did[%u %u]\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, + waitq->id, waitq->count, qos_pd_mgr->disk_id, i); + } + + return in_queue; +} + +static Bool ps3_qos_pd_quota_decision(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + U16 disk_id = 0; + U16 i = 0; + struct scsi_device *sdev = NULL; + S32 pd_quota = 0; + + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_PD_PRO); + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + ps3_qos_cmd_member_pd_calc(cmd); + for (i = 0; i < cmd->target_pd_count; i++) { + disk_id = cmd->target_pd[i].flat_disk_id; + qos_pd_mgr = ps3_qos_pd_mgr_get(cmd->instance, disk_id); + if (ps3_qos_pd_quota_check(qos_pd_mgr, cmd)) { + cmd->target_pd[i].get_quota = PS3_TRUE; + can_get = PS3_TRUE; + break; + } + } + + if (cmd->target_pd_count == 0) { + can_get = PS3_TRUE; + } + + if (!can_get) { + if (!ps3_qos_vd_member_insert(cmd)) { + can_get = PS3_TRUE; + } + } + } else { + disk_id = cmd->io_attr.disk_id; + qos_pd_mgr = ps3_qos_pd_mgr_get(cmd->instance, disk_id); + if (ps3_is_nvme_direct_cmd(qos_pd_mgr, cmd)) { + pd_quota = qos_pd_mgr->direct_quota; + } else { + pd_quota = qos_pd_mgr->pd_quota; + } + sdev = cmd->scmd->device; + if (pd_quota >= sdev->queue_depth) { + can_get = PS3_TRUE; + } else { + ps3_qos_cmd_member_pd_calc(cmd); + can_get = ps3_qos_pd_quota_req(qos_pd_mgr, cmd, 0); + } + } + PS3_QOS_STAT_END(cmd->instance, cmd, PS3_QOS_PD_PRO); + return can_get; +} + +static Bool ps3_qos_vd_quota_decision(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_TRUE; + + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_VD_PRO); + if (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD){ + can_get = ps3_qos_vd_quota_check(cmd); + } + PS3_QOS_STAT_END(cmd->instance, cmd, PS3_QOS_VD_PRO); + + return can_get; +} + +static inline Bool ps3_qos_dev_valid(struct ps3_cmd *cmd) +{ + Bool valid = PS3_TRUE; + struct ps3_scsi_priv_data* priv_data = NULL; + + priv_data = scsi_device_private_data(cmd->scmd); + if (priv_data->dev_deling) { + LOG_INFO_LIM("qos dev is deling. host_no:%u chanel:%u id:%u\n", + PS3_HOST(cmd->instance), + PS3_SDEV_CHANNEL(cmd->scmd->device), + PS3_SDEV_TARGET(cmd->scmd->device)); + valid = PS3_FALSE; + } + + return valid; +} + +static S32 ps3_qos_pre_check(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + INJECT_START(PS3_ERR_IJ_FORCE_TASK_MGR_BUSY, instance) + if (instance->task_manager_host_busy) { + LOG_INFO_LIM("hno:%u task_manager_host_busy\n", + PS3_HOST(instance)); + ret = -PS3_RETRY; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_INS_UNLOAD, instance) + if (instance->is_probe_finish && !instance->state_machine.is_load) { + LOG_INFO_LIM("hno:%u instance state not is_load\n", PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + if (!ps3_qos_dev_valid(cmd)){ + ret = -PS3_FAILED; + } + + INJECT_START(PS3_ERR_IJ_FORCE_INSTANCE_UNNORMAL, instance) + if (!ps3_is_instance_state_normal(instance, PS3_TRUE)) { + LOG_INFO_LIM("hno:%u instance state is not normal\n", PS3_HOST(instance)); + ret = -PS3_RECOVERED; + goto l_out; + } +l_out: + return ret; +} + +Bool ps3_hba_qos_decision(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type)) { + can_get = ps3_qos_pd_quota_decision(cmd); + if (!can_get || + cmd->io_attr.direct_flag == PS3_CMDWORD_DIRECT_OK) { + goto _out; + } + + can_get = ps3_qos_vd_quota_decision(cmd); + if (!can_get) { + goto _out; + } + } + + can_get = ps3_qos_tg_decision(cmd); +_out: + return can_get; +} + +void ps3_hba_qos_waitq_notify(struct ps3_instance *instance) +{ + if (!ps3_qos_tg_notify(instance)) { + if (!ps3_qos_vd_notify(instance)) { + ps3_qos_pd_notify(instance); + } + } +} + +static Bool ps3_pd_quota_waiq_abort(struct ps3_cmd *cmd) +{ + ULong lock_flag_pd = 0; + U16 disk_id = 0; + Bool found = PS3_FALSE; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct qos_wait_queue *waitq = NULL; + U16 index = 0; + + for (index = cmd->first_over_quota_pd_idx; + index < cmd->target_pd_count; index++) { + disk_id = cmd->target_pd[index].flat_disk_id; + qos_pd_mgr = ps3_qos_pd_mgr_get(cmd->instance, disk_id); + waitq = ps3_qos_pd_waitq_get(qos_pd_mgr, cmd); + ps3_spin_lock_irqsave(waitq->rsc_lock, &lock_flag_pd); + if (cmd->qos_waitq_flag == PS3_QOS_CMD_IN_PD && + index == cmd->first_over_quota_pd_idx) { + list_del(&cmd->qos_list); + waitq->count--; + (*waitq->total_waited_cnt)--; + ps3_spin_unlock_irqrestore(waitq->rsc_lock, lock_flag_pd); + found = PS3_TRUE; + break; + } + ps3_spin_unlock_irqrestore(waitq->rsc_lock, lock_flag_pd); + LOG_INFO("abort pd waitq. t_id:0x%llx did[%u,%u] qid:%u found:%u\n", + cmd->trace_id, index, disk_id, waitq->id, found); + } + + return found; +} + +static bool ps3_vd_quota_waiq_abort(struct ps3_cmd *aborted_cmd) +{ + ULong flag = 0; + Bool found = PS3_FALSE; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + + qos_vd_mgr = ps3_qos_vd_mgr_get(aborted_cmd); + ps3_spin_lock_irqsave(qos_vd_mgr->vd_quota_wait_q.rsc_lock, &flag); + if (aborted_cmd->qos_waitq_flag == PS3_QOS_CMD_IN_VD) { + list_del(&aborted_cmd->qos_list); + qos_vd_mgr->vd_quota_wait_q.count--; + found = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(qos_vd_mgr->vd_quota_wait_q.rsc_lock, flag); + + return found; +} + +bool ps3_cmd_waitq_abort(struct ps3_cmd *aborted_cmd) +{ + ULong lock_flag_mgr = 0; + struct ps3_instance *instance = NULL; + Bool found = PS3_FALSE; + struct qos_wait_queue *cmd_wait_q = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = NULL; + + instance = aborted_cmd->instance; + qos_tg_ctx = &instance->qos_context.tg_ctx; + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &lock_flag_mgr); + if (aborted_cmd->qos_waitq_flag == PS3_QOS_CMD_IN_FRAME) { + cmd_wait_q = ps3_qos_cmd_waitq_get(qos_tg_ctx, aborted_cmd); + list_del(&aborted_cmd->qos_list); + cmd_wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + found = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, lock_flag_mgr); + + return found; +} + +static Bool ps3_hba_qos_waitq_abort(struct ps3_cmd *cmd) +{ + Bool found = PS3_FALSE; + if (cmd->qos_waitq_flag == 0) { + goto out; + } + + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type)) { + if (cmd->qos_waitq_flag == PS3_QOS_CMD_IN_PD) { + found = ps3_pd_quota_waiq_abort(cmd); + if (found) { + goto out; + } + } + + if (cmd->qos_waitq_flag == PS3_QOS_CMD_IN_VD) { + found = ps3_vd_quota_waiq_abort(cmd); + if (found) { + ps3_qos_update_pd_quota(cmd); + goto out; + } + } + } + + if (cmd->qos_waitq_flag == PS3_QOS_CMD_IN_FRAME) { + found = ps3_cmd_waitq_abort(cmd); + if (found) { + ps3_qos_update_vd_quota(cmd); + ps3_qos_update_pd_quota(cmd); + } + } +out: + return found; +} + +static void ps3_vd_cmd_waitq_clean(struct ps3_instance *instance, U16 disk_id, int result) +{ + ULong flag = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + struct qos_wait_queue *wait_q = &qos_tg_ctx->vd_cmd_waitqs[disk_id]; + + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + if (wait_q->count > 0) { + list_for_each_entry_safe(cmd, cmd_next, &wait_q->wait_list, qos_list) { + LOG_DEBUG("qos clean vd cmd waitq. hno:%u t_id:0x%llx cmd:%d vd_id:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, disk_id); + list_del(&cmd->qos_list); + wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + ps3_qos_update_vd_quota(cmd); + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, result, PS3_FALSE); + } + } + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); +} + +static void ps3_jbod_cmd_waitq_clean(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, int result) +{ + ULong flag = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + struct qos_wait_queue *wait_q = &qos_tg_ctx->vd_cmd_waitqs + [instance->qos_context.max_vd_count]; + U16 disk_id = priv_data->disk_pos.diskDev.ps3Dev.virtDiskID; + + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + if (wait_q->count > 0) { + list_for_each_entry_safe(cmd, cmd_next, &wait_q->wait_list, qos_list) { + if (scsi_device_private_data(cmd->scmd) == priv_data) { + LOG_DEBUG("qos clean jbod cmd waitq. hno:%u t_id:0x%llx cmd:%d dev_t:%u diskid:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, + priv_data->dev_type, disk_id); + list_del(&cmd->qos_list); + wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + ps3_qos_update_vd_quota(cmd); + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, result, PS3_FALSE); + } + } + } + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); +} + +static void ps3_mgr_cmd_waitq_clean(struct ps3_instance *instance, struct ps3_scsi_priv_data *priv_data, int result) +{ + ULong flag = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + struct qos_wait_queue *wait_q = &qos_tg_ctx->mgr_cmd_wait_q; + U16 disk_id = priv_data->disk_pos.diskDev.ps3Dev.virtDiskID; + + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + if (wait_q->count > 0) { + list_for_each_entry_safe(cmd, cmd_next, &wait_q->wait_list, qos_list) { + if (cmd->scmd && scsi_device_private_data(cmd->scmd) == priv_data) { + LOG_DEBUG("qos clean mgr cmd waitq. hno:%u t_id:0x%llx cmd:%d dev_t:%u diskid:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, + priv_data->dev_type, disk_id); + list_del(&cmd->qos_list); + wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, result, PS3_FALSE); + } + } + } + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); +} + +static void ps3_hba_qos_vd_clean(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + U16 vd_id = 0; + U16 pd_id = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + vd_id = get_offset_of_vdid(PS3_VDID_OFFSET(instance), PS3_VDID(&priv_data->disk_pos)); + qos_vd_mgr = ps3_qos_vd_mgr_get_by_id(instance, PS3_VDID(&priv_data->disk_pos)); + for (pd_id = 1; pd_id <= instance->qos_context.max_pd_count; pd_id++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1 && + qos_pd_mgr->vd_id == vd_id) { + ps3_pd_quota_waitq_clean(qos_pd_mgr, vd_id, resp_status); + cancel_work_sync(&qos_pd_mgr->resend_work); + } + } + + ps3_vd_quota_waitq_clean(qos_vd_mgr, NULL, resp_status); + cancel_work_sync(&qos_vd_mgr->resend_work); + + ps3_vd_cmd_waitq_clean(instance, vd_id, resp_status); + ps3_mgr_cmd_waitq_clean(instance, priv_data, resp_status); + + LOG_FILE_INFO("qos clean vd. host_no:%u type:%u disk_id:%u\n", + PS3_HOST(instance), priv_data->dev_type, vd_id); +} + +#define PS3_QOS_JBOD_VD_MGR(instance) \ + (&instance->qos_context.vd_ctx.qos_vd_mgrs[instance->qos_context.max_vd_count]) + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0) && LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)) +void ps3_linx80_vd_member_change(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry) +{ + U16 pd_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + if (!PS3_QOS_INITED(instance)) { + goto _out; + } + + pd_id = PS3_PDID(&pd_entry->disk_pos); + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + if (ps3_atomic_read(&qos_pd_mgr->valid) != PS3_TRUE) { + goto _out; + } + ps3_pd_quota_waitq_clean(qos_pd_mgr, 0, PS3_STATUS_VD_MEMBER_OFFLINE); + cancel_work_sync(&qos_pd_mgr->resend_work); + LOG_INFO("linx80 update pd qos rsc. host_no:%u pd_id:%u dev_type:%u\n", + PS3_HOST(instance), pd_id, pd_entry->dev_type); + +_out: + return; +} +#endif +static void ps3_hba_qos_pd_clean(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + U16 disk_id = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + disk_id = PS3_PDID(&priv_data->disk_pos); + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, disk_id); + ps3_pd_quota_waitq_clean(qos_pd_mgr, 0, resp_status); + cancel_work_sync(&qos_pd_mgr->resend_work); + + qos_vd_mgr = PS3_QOS_JBOD_VD_MGR(instance); + ps3_vd_quota_waitq_clean(qos_vd_mgr, priv_data, resp_status); + ps3_jbod_cmd_waitq_clean(instance, priv_data, resp_status); + ps3_mgr_cmd_waitq_clean(instance, priv_data, resp_status); + + LOG_FILE_INFO("qos clean pd. host_no:%u diskid:%u\n", + PS3_HOST(instance), disk_id); +} + +static void ps3_qos_wait_io_end(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd *cmd = NULL; + LOG_DEBUG("host_no:%u wait cmd in qos flighting start\n", + PS3_HOST(instance)); + for (i = 0; i < instance->cmd_context.max_scsi_cmd_count; i++) { + cmd = instance->cmd_context.cmd_buf[i]; + while (cmd->qos_processing) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + } + } + LOG_DEBUG("host_no:%u wait cmd in qos flighting end\n", + PS3_HOST(instance)); +} + +void ps3_qos_device_clean(struct ps3_instance *instance, struct ps3_scsi_priv_data *priv_data, + S32 resp_status) +{ + if (!PS3_QOS_INITED(instance)) { + return; + } + + ps3_qos_wait_io_end(instance); + if (priv_data->dev_type == PS3_DEV_TYPE_VD) { + instance->qos_context.opts.qos_vd_clean(instance, priv_data, resp_status); + } else { + instance->qos_context.opts.qos_pd_clean(instance, priv_data, resp_status); + } +} + +static inline void ps3_qos_dev_end(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data) +{ + U32 i = 0; + struct ps3_cmd *cmd = NULL; + struct scsi_cmnd *scmd = NULL; + struct scsi_device *sdev = NULL; + U32 softChan = PS3_CHANNEL(&priv_data->disk_pos); + U32 devID = PS3_TARGET(&priv_data->disk_pos); + + LOG_DEBUG("host_no:%u dev wait cmd in qos flighting start\n", + PS3_HOST(instance)); + for (i = 0; i < instance->cmd_context.max_scsi_cmd_count; i++) { + cmd = instance->cmd_context.cmd_buf[i]; + if (likely(!cmd->qos_processing)) { + continue; + } + + scmd = cmd->scmd; + if (scmd == NULL) { + continue; + } + + sdev = scmd->device; + if (sdev == NULL) { + continue; + } + + if (PS3_SDEV_CHANNEL(sdev) == softChan && + PS3_SDEV_TARGET(sdev) == devID) { + LOG_DEBUG("cmd is flighting. host_no:%u CFID:%u\n", + PS3_HOST(instance), cmd->index); + while (cmd->qos_processing) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + } + } + } + LOG_DEBUG("host_no:%u dev wait cmd in qos flighting end\n", + PS3_HOST(instance)); +} + +void ps3_qos_disk_del(struct ps3_instance *instance, struct ps3_scsi_priv_data *priv_data) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + U16 disk_id = 0; + S32 resp_status = PS3_STATUS_DEVICE_NOT_FOUND; + + if (!PS3_QOS_INITED(instance)) { + return; + } + + priv_data->dev_deling = PS3_TRUE; + wmb(); + disk_id = PS3_PDID(&priv_data->disk_pos); + LOG_FILE_INFO("qos disk del. host_no:%u dev_t:%u diskid:%u\n", + PS3_HOST(instance), priv_data->dev_type, disk_id); + if (priv_data->dev_type == PS3_DEV_TYPE_VD) { + ps3_qos_dev_end(instance, priv_data); + instance->qos_context.opts.qos_vd_clean(instance, priv_data, resp_status); + } else { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, disk_id); + ps3_qos_dev_end(instance, priv_data); + if (PS3_QOS_PD_IS_VD_MEMBER(qos_pd_mgr)) { + resp_status = PS3_STATUS_VD_MEMBER_OFFLINE; + qos_pd_mgr->clearing = PS3_TRUE; + wmb(); + LOG_INFO("host_no:%u wait cmd in qos vd member flighting count:%d did:%u\n", + PS3_HOST(instance), + ps3_atomic_read(&qos_pd_mgr->processing_cnt), disk_id); + while (ps3_atomic_read(&qos_pd_mgr->processing_cnt) > 0) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + } + instance->qos_context.opts.qos_pd_clean(instance, priv_data, resp_status); + } +} + +void ps3_qos_vd_member_del(struct ps3_instance *instance, struct PS3DiskDevPos *dev_pos) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + U16 disk_id = 0; + + disk_id = PS3_PDID(dev_pos); + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, disk_id); + LOG_INFO("qos disk del. host_no:%u did:%u vid:%u\n", + PS3_HOST(instance), disk_id, qos_pd_mgr->vd_id); + + if (PS3_QOS_PD_IS_VD_MEMBER(qos_pd_mgr)) { + ps3_pd_quota_waitq_clean(qos_pd_mgr, 0, PS3_STATUS_VD_MEMBER_OFFLINE); + } +} + +void ps3_hba_qos_waitq_clear_all(struct ps3_instance *instance, S32 resp_status) +{ + ULong flag = 0; + U16 i = 0; + struct ps3_qos_tg_context *qos_tg_ctx = &instance->qos_context.tg_ctx; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct qos_wait_queue *wait_q = NULL; + struct ps3_cmd *cmd = NULL; + + for (i = 1; i <= instance->qos_context.max_pd_count; i++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, i); + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1) { + ps3_pd_quota_waitq_clear_all(qos_pd_mgr, resp_status); + cancel_work_sync(&qos_pd_mgr->resend_work); + } + } + + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + qos_vd_mgr = &instance->qos_context.vd_ctx.qos_vd_mgrs[i]; + if (qos_vd_mgr->valid) { + ps3_vd_quota_waitq_clean(qos_vd_mgr, NULL, resp_status); + cancel_work_sync(&qos_vd_mgr->resend_work); + } + } + + ps3_spin_lock_irqsave(&qos_tg_ctx->lock, &flag); + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + wait_q = &qos_tg_ctx->vd_cmd_waitqs[i]; + while (wait_q->count > 0) { + cmd = list_first_entry(&wait_q->wait_list, struct ps3_cmd, qos_list); + LOG_DEBUG("qos clear tg vd waitq. hno:%u qid:%u t_id:0x%llx cmd:%d\n", + PS3_HOST(instance), i, cmd->trace_id, cmd->index); + list_del(&cmd->qos_list); + wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + ps3_qos_update_vd_quota(cmd); + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + } + + wait_q = &qos_tg_ctx->mgr_cmd_wait_q; + while (wait_q->count > 0) { + cmd = list_first_entry(&wait_q->wait_list, struct ps3_cmd, qos_list); + LOG_DEBUG("qos clear tg mgr waitq. hno:%u t_id:0x%llx cmd:%d\n", + PS3_HOST(instance), cmd->trace_id, cmd->index); + list_del(&cmd->qos_list); + wait_q->count--; + qos_tg_ctx->total_wait_cmd_cnt--; + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + ps3_spin_unlock_irqrestore(&qos_tg_ctx->lock, flag); + cancel_work_sync(&qos_tg_ctx->resend_work); + + LOG_INFO("host_no:%u:clear all qos waitq\n", PS3_HOST(instance)); +} + +static inline U16 ps3_qos_pd_workq_id_get(struct ps3_qos_pd_context *qos_pd_ctx) +{ + return ps3_atomic_inc_return(&qos_pd_ctx->workq_id_cnt) % qos_pd_ctx->workq_count; +} + +void ps3_qos_pd_rsc_init(struct ps3_qos_pd_mgr *qos_pd_mgr, struct ps3_pd_entry *pd_entry) +{ + struct ps3_qos_pd_context *pd_ctx = NULL; + struct PS3QosInfo *qos_cfg_info = NULL; + + qos_cfg_info = &qos_pd_mgr->instance->ctrl_info.qosInfo; + qos_pd_mgr->pd_quota = pd_entry->normal_quota; + qos_pd_mgr->direct_quota = pd_entry->direct_quota; + qos_pd_mgr->dev_type = pd_entry->dev_type; + switch (pd_entry->dev_type) { + case PS3_DEV_TYPE_SAS_HDD: + if (qos_pd_mgr->pd_quota == 0) { + qos_pd_mgr->pd_quota = qos_cfg_info->sasHddQuota > 0 ? + qos_cfg_info->sasHddQuota : g_ps3_qos_sas_pd_quota; + } + qos_pd_mgr->pd_init_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->pd_quota - (qos_pd_mgr->pd_quota / 10); + break; + case PS3_DEV_TYPE_SAS_SSD: + if (qos_pd_mgr->pd_quota == 0) { + qos_pd_mgr->pd_quota = qos_cfg_info->sasSsdQuota > 0 ? + qos_cfg_info->sasSsdQuota : g_ps3_qos_sas_pd_quota; + } + qos_pd_mgr->pd_init_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->pd_quota - (qos_pd_mgr->pd_quota / 10); + break; + case PS3_DEV_TYPE_SATA_HDD: + if (qos_pd_mgr->pd_quota == 0) { + qos_pd_mgr->pd_quota = qos_cfg_info->sataHddQuota > 0 ? + qos_cfg_info->sataHddQuota : g_ps3_qos_hdd_pd_quota; + } + qos_pd_mgr->pd_init_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->pd_quota - (qos_pd_mgr->pd_quota / 10); + break; + case PS3_DEV_TYPE_SATA_SSD: + if (qos_pd_mgr->pd_quota == 0) { + qos_pd_mgr->pd_quota = qos_cfg_info->sataSsdQuota > 0 ? + qos_cfg_info->sataSsdQuota : g_ps3_qos_ssd_pd_quota; + } + qos_pd_mgr->pd_init_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->pd_quota - (qos_pd_mgr->pd_quota / 10); + break; + case PS3_DEV_TYPE_NVME_SSD: + pd_ctx = &qos_pd_mgr->instance->qos_context.pd_ctx; + if (qos_pd_mgr->pd_quota == 0) { + qos_pd_mgr->pd_quota = qos_cfg_info->nvmeNormalQuota > 0 ? + qos_cfg_info->nvmeNormalQuota : pd_ctx->nvme_normal_quota; + } + if (qos_pd_mgr->direct_quota == 0) { + qos_pd_mgr->direct_quota = qos_cfg_info->nvmeDirectQuota > 0 ? + qos_cfg_info->nvmeDirectQuota : g_ps3_qos_nvme_pd_quota; + } + qos_pd_mgr->pd_init_quota = qos_pd_mgr->direct_quota; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->direct_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->direct_quota - (qos_pd_mgr->direct_quota / 10); + break; + } + + LOG_DEBUG("qos pd rsc init. hno:%u type:%u normal_quota:%u direct_quota:%u\n", + PS3_HOST(qos_pd_mgr->instance), pd_entry->dev_type, + pd_entry->normal_quota, pd_entry->direct_quota); +} + +void ps3_qos_adjust_pd_rsc(struct scsi_device *sdev, + struct ps3_instance *instance, S32 reason) +{ + S32 *quota = NULL; + ULong flag = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + if (!PS3_QOS_INITED(instance) || + (PS3_SDEV_PRI_DATA(sdev) == NULL) || + (PS3_SDEV_PRI_DATA(sdev)->dev_type == PS3_DEV_TYPE_VD)) { + goto l_out; + } + + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, PS3_PDID(&PS3_SDEV_PRI_DATA(sdev)->disk_pos)); + + switch (PS3_SDEV_PRI_DATA(sdev)->dev_type) { + case PS3_DEV_TYPE_SAS_HDD: + case PS3_DEV_TYPE_SAS_SSD: + case PS3_DEV_TYPE_SATA_HDD: + case PS3_DEV_TYPE_SATA_SSD: + quota = &qos_pd_mgr->pd_quota; + break; + case PS3_DEV_TYPE_NVME_SSD: + quota = &qos_pd_mgr->direct_quota; + break; + default: + goto l_out; + } + if ((*quota > sdev->queue_depth && reason == PS3_QOS_QUOTA_ADJUST_QFULL) || + ((*quota == qos_pd_mgr->adjust_max_quota || + time_after(sdev->last_queue_full_time + sdev->queue_ramp_up_period, jiffies) || + time_after(sdev->last_queue_ramp_up + sdev->queue_ramp_up_period, jiffies)) + && reason == PS3_QOS_QUOTA_ADJUST_UP)) { + goto l_out; + } + if (reason == PS3_QOS_QUOTA_ADJUST_UP) { + ps3_spin_lock_irqsave(&qos_pd_mgr->adjust_quota_lock, &flag); + if (*quota < qos_pd_mgr->adjust_max_quota) { + (*quota)++; + } + } else if (reason == PS3_QOS_QUOTA_ADJUST_QFULL) { + ps3_spin_lock_irqsave(&qos_pd_mgr->adjust_quota_lock, &flag); + if (*quota > qos_pd_mgr->adjust_min_quota) { + (*quota)--; + } + } else if (reason == PS3_QOS_QUOTA_ADJUST_DEFULAT) { + ps3_spin_lock_irqsave(&qos_pd_mgr->adjust_quota_lock, &flag); + *quota = qos_pd_mgr->adjust_max_quota; + } else { + goto l_out; + } + ps3_spin_unlock_irqrestore(&qos_pd_mgr->adjust_quota_lock, flag); + LOG_INFO_IN_IRQ(instance,"hno:%u dev[%u:%u] qos quota change to [%d] reason [%d]\n", + PS3_HOST(instance), sdev->channel, sdev->id, *quota, reason); +l_out: + return; +} + + struct ps3_qos_pd_mgr* ps3_qos_pd_mgr_init(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry) +{ + U16 pd_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + if (!PS3_QOS_INITED(instance)) { + goto _out; + } + + pd_id = PS3_PDID(&pd_entry->disk_pos); + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + + if ((ps3_atomic_add_unless(&qos_pd_mgr->valid, 1, 1) != 0) || +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0) && LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)) + ((ps3_sas_is_support_smp(instance)) && (!ps3_check_pd_is_vd_member(pd_entry->config_flag))) || + (pd_entry->config_flag == MIC_PD_STATE_JBOD)) { +#else + (pd_entry->config_flag == MIC_PD_STATE_JBOD)) { +#endif + if (pd_entry->config_flag == MIC_PD_STATE_JBOD) { + ps3_qos_vd_member_del(instance, &pd_entry->disk_pos); + } + + ps3_qos_pd_rsc_init(qos_pd_mgr, pd_entry); + qos_pd_mgr->disk_id = pd_id; + qos_pd_mgr->vd_id = 0; + qos_pd_mgr->workq_id = ps3_qos_pd_workq_id_get(&instance->qos_context.pd_ctx); + qos_pd_mgr->clearing = PS3_FALSE; + LOG_INFO_IN_IRQ(instance, "host_no:%u pd_id:%u dev_type:%u device qos init\n", + PS3_HOST(instance), pd_id, qos_pd_mgr->dev_type); + } +_out: + return qos_pd_mgr; +} + +void ps3_qos_pd_mgr_reset(struct ps3_instance *instance, U16 pd_id) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + if (!PS3_QOS_INITED(instance)) { + return; + } + + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + qos_pd_mgr->clearing = PS3_FALSE; +} + +void ps3_qos_vd_attr_change(struct ps3_instance *instance, + struct PS3VDEntry *vd_entry_old, struct PS3VDEntry *vd_entry) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + U16 change_type = PS3_QOS_VD_TYPE_CHANGE_INVALID; + U16 i = 0; + U16 j = 0; + U16 pd_id = 0; + + if (!PS3_QOS_INITED(instance) || vd_entry->isNvme) { + goto l_out; + } + + if (!vd_entry->isSsd) { + change_type = PS3_QOS_VD_TYPE_CHANGE_TO_HDD; + } else { + change_type = PS3_QOS_VD_TYPE_CHANGE_TO_SSD; + } + + for (i = 0; i < vd_entry->spanCount; i++) { + for (j = 0; j < vd_entry->span[i].spanPdNum; j++) { + pd_id = vd_entry->span[i].extent[j].phyDiskID.ps3Dev.phyDiskID; + if (pd_id <= PS3_MAX_PD_COUNT(instance)) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + switch (change_type) { + case PS3_QOS_VD_TYPE_CHANGE_TO_SSD: + qos_pd_mgr->pd_quota = qos_pd_mgr->adjust_max_quota; + break; + case PS3_QOS_VD_TYPE_CHANGE_TO_HDD: + if (vd_entry_old != NULL) { + qos_pd_mgr->pd_quota = instance->cmd_context.max_scsi_cmd_count; + } else { + qos_pd_mgr->pd_quota = qos_pd_mgr->adjust_max_quota; + } + break; + default: + break; + } + } + } + } + + LOG_INFO_IN_IRQ(instance, "host_no:%u qos vd[%u:%u:%u] attr change:%u complete\n", + PS3_HOST(instance), PS3_CHANNEL(&vd_entry->diskPos), + PS3_TARGET(&vd_entry->diskPos), PS3_VDID(&vd_entry->diskPos), change_type); +l_out: + return; +} + +void ps3_qos_vd_member_change(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry, + struct scsi_device *sdev, Bool is_vd_member) +{ + U16 pd_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_scsi_priv_data *priv_data = NULL; + if (!PS3_QOS_INITED(instance)) { + goto _out; + } + + pd_id = PS3_PDID(&pd_entry->disk_pos); + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + priv_data = PS3_SDEV_PRI_DATA(sdev); + if (priv_data != NULL) { + if (is_vd_member) { + ps3_hba_qos_pd_clean(instance, priv_data, PS3_STATUS_DEVICE_NOT_FOUND); + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + } else { + ps3_hba_qos_pd_clean(instance, priv_data, PS3_STATUS_VD_MEMBER_OFFLINE); + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + ps3_qos_pd_rsc_init(qos_pd_mgr, pd_entry); + qos_pd_mgr->vd_id = 0; + } + } else { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + } + LOG_INFO("update pd qos rsc. host_no:%u pd_id:%u dev_type:%u is_vd_member:%u\n", + PS3_HOST(instance), pd_id, pd_entry->dev_type, is_vd_member); + +_out: + return; +} + +void ps3_hba_qos_vd_init(struct ps3_instance *instance, struct PS3VDEntry *vd_entry) +{ + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + U16 vd_id = 0; + + vd_id = PS3_VDID(&vd_entry->diskPos); + qos_vd_mgr = ps3_qos_vd_mgr_get_by_id(instance, vd_id); + ps3_atomic_set(&qos_vd_mgr->vd_quota, g_ps3_qos_hdd_pd_quota * vd_entry->physDrvCnt); + qos_vd_mgr->vd_entry = vd_entry; + qos_vd_mgr->valid = PS3_TRUE; +} + +static void ps3_qos_r1x_member_init(struct ps3_qos_pd_mgr *qos_pd_mgr, + struct ps3_pd_entry *pd_entry, U16 judge_type) +{ + switch (judge_type) { + case PS3_IS_SSD_ODD_R1X_VD: + if (qos_pd_mgr->dev_type == PS3_DEV_TYPE_NVME_SSD) { + qos_pd_mgr->direct_quota = qos_pd_mgr->pd_init_quota >> 1; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->direct_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->direct_quota - (qos_pd_mgr->direct_quota / 10); + } else { + qos_pd_mgr->pd_quota = qos_pd_mgr->pd_init_quota >> 1; + qos_pd_mgr->adjust_max_quota = qos_pd_mgr->pd_quota; + qos_pd_mgr->adjust_min_quota = qos_pd_mgr->pd_quota - (qos_pd_mgr->pd_quota / 10); + } + break; + case PS3_IS_SSD_EVEN_R1X_VD: + case PS3_IS_VALID_R1X_VD: + if (qos_pd_mgr->vd_id > 0) { + ps3_qos_pd_rsc_init(qos_pd_mgr, pd_entry); + } + break; + case PS3_IS_HDD_R1X_VD: + default: + break; + } +} + +void ps3_qos_vd_init(struct ps3_instance *instance, struct PS3VDEntry *vd_entry) +{ + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + U16 vd_id = 0; + U16 pd_id = 0; + struct ps3_pd_entry *pd_entry = NULL; + U16 i, j = 0; + U16 judge_type = PS3_IS_VALID_R1X_VD; + + if(!PS3_QOS_INITED(instance)) { + return; + } + + vd_id = get_offset_of_vdid(PS3_VDID_OFFSET(instance), + PS3_VDID(&vd_entry->diskPos)); + judge_type = ps3_odd_r1x_judge(vd_entry); + for (i = 0; i < vd_entry->spanCount; i++) { + for (j = 0; j < vd_entry->span[i].spanPdNum; j++) { + pd_id = vd_entry->span[i].extent[j].phyDiskID.ps3Dev.phyDiskID; + if (pd_id <= PS3_MAX_PD_COUNT(instance)) { + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, pd_id); + if (pd_entry) { + qos_pd_mgr = ps3_qos_pd_mgr_init(instance, pd_entry); + if (unlikely(qos_pd_mgr->dev_type != pd_entry->dev_type)) { + ps3_qos_pd_rsc_init(qos_pd_mgr, pd_entry); + if (!vd_entry->isSsd) { + qos_pd_mgr->pd_quota = instance->cmd_context.max_scsi_cmd_count; + } + } + + ps3_qos_r1x_member_init(qos_pd_mgr, pd_entry, judge_type); + if (qos_pd_mgr->dev_type == PS3_DEV_TYPE_NVME_SSD) { + if (qos_pd_mgr->pd_quota > qos_pd_mgr->direct_quota) { + qos_pd_mgr->pd_quota = qos_pd_mgr->direct_quota; + } + } + qos_pd_mgr->vd_id = vd_id; + } + } + } + } + + if (instance->qos_context.opts.qos_vd_init) { + instance->qos_context.opts.qos_vd_init(instance, vd_entry); + } + + LOG_INFO_IN_IRQ(instance, "host_no:%u disk_pos[%u:%u:%u] device qos init\n", + PS3_HOST(instance), PS3_CHANNEL(&vd_entry->diskPos), + PS3_TARGET(&vd_entry->diskPos), vd_id); +} + +void ps3_hba_qos_vd_reset(struct ps3_instance *instance, U16 disk_id) +{ + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + qos_vd_mgr = ps3_qos_vd_mgr_get_by_id(instance, disk_id); + qos_vd_mgr->valid = PS3_FALSE; +} + +void ps3_qos_vd_reset(struct ps3_instance *instance, U16 disk_id) +{ + if (!PS3_QOS_INITED(instance)) { + return; + } + + if (instance->qos_context.opts.qos_vd_reset) { + instance->qos_context.opts.qos_vd_reset(instance, disk_id); + } +} + +static void ps3_qos_pd_notify_timeout(struct ps3_instance *instance) +{ + struct ps3_qos_pd_context *qos_pd_ctx = NULL; + U16 i = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + ULong timeout_jiffies = 0; + + qos_pd_ctx = &instance->qos_context.pd_ctx; + for (i = 1; i <= instance->qos_context.max_pd_count; i++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, i); + timeout_jiffies = qos_pd_mgr->last_sched_jiffies + PS3_QOS_WAITQ_TIMEOUT * HZ; + if (time_after(jiffies, timeout_jiffies)) { + if (ps3_qos_single_pd_notify(qos_pd_ctx, qos_pd_mgr)) { + LOG_INFO("awake qos pd quota waitq by poll. host_no:%u vid:%u pid:%u\n", + PS3_HOST(instance), qos_pd_mgr->vd_id, qos_pd_mgr->disk_id); + } + } + + } +} + +static Bool ps3_qos_vd_notify_timeout(struct ps3_instance *instance) +{ + struct ps3_qos_vd_context *qos_vd_ctx = NULL; + U16 i = 0; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + ULong timeout_jiffies = 0; + Bool notified = PS3_FALSE; + + for (i = 1; i <= instance->qos_context.max_vd_count; i++) { + qos_vd_ctx = &instance->qos_context.vd_ctx; + qos_vd_mgr = &qos_vd_ctx->qos_vd_mgrs[i]; + timeout_jiffies = qos_vd_mgr->last_sched_jiffies + PS3_QOS_WAITQ_TIMEOUT * HZ; + if (time_after(jiffies, timeout_jiffies)) { + if (ps3_qos_single_vd_notify(qos_vd_ctx, qos_vd_mgr)) { + notified = PS3_TRUE; + LOG_INFO("awake qos vd quota waitq by poll. host_no:%u vid:%u\n", + PS3_HOST(instance), qos_vd_mgr->id); + } + + } + + } + + return notified; +} + +static Bool ps3_qos_tg_notify_timeout(struct ps3_instance *instance) +{ + struct ps3_qos_tg_context *qos_tg_ctx = NULL; + Bool notified = PS3_FALSE; + ULong timeout_jiffies = 0; + + qos_tg_ctx = &instance->qos_context.tg_ctx; + timeout_jiffies = qos_tg_ctx->last_sched_jiffies + PS3_QOS_WAITQ_TIMEOUT * HZ; + if (qos_tg_ctx->total_wait_cmd_cnt && + ps3_qos_tag_rsc_available(instance) && + time_after(jiffies, timeout_jiffies)) { + queue_work(qos_tg_ctx->work_queue, &qos_tg_ctx->resend_work); + notified = PS3_TRUE; + LOG_INFO("awake qos cmd waitq by poll. host_no:%u\n", + PS3_HOST(instance)); + } + + return notified; +} + +void ps3_hba_qos_waitq_poll(struct ps3_instance *instance) +{ + if (!ps3_qos_tg_notify_timeout(instance)) { + if (!ps3_qos_vd_notify_timeout(instance)) { + ps3_qos_pd_notify_timeout(instance); + } + } +} + +void ps3_qos_waitq_poll(struct ps3_instance *instance) +{ + if (!PS3_QOS_INITED(instance)) { + return; + } + + if (++instance->qos_context.poll_count == PS3_QOS_POLL_INTERVAL) { + instance->qos_context.poll_count = 0; + instance->qos_context.opts.qos_waitq_poll(instance); + } +} + +static void ps3_hba_qos_reset(struct ps3_instance *instance) +{ + struct ps3_qos_context *qos_ctx = &instance->qos_context; + struct ps3_qos_vd_mgr *qos_vd_mgr = NULL; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_qos_tg_context *qos_tg_ctx = NULL; + U16 i = 0; + struct ps3_pd_entry *pd_entry = NULL; + + qos_tg_ctx = &instance->qos_context.tg_ctx; + ps3_atomic_set(&qos_tg_ctx->mgr_free_cnt, qos_tg_ctx->mgr_exclusive_cnt); + ps3_atomic_set(&qos_tg_ctx->mgr_share_used, 0); + ps3_atomic_set(&qos_tg_ctx->share_free_cnt, qos_tg_ctx->share); + + for (i = 1; i <= qos_ctx->max_vd_count; i++) { + qos_vd_mgr = &instance->qos_context.vd_ctx.qos_vd_mgrs[i]; + if (i == qos_ctx->max_vd_count) { + ps3_atomic_set(&qos_vd_mgr->vd_quota, g_ps3_qos_vd_quota); + ps3_atomic_set(&qos_vd_mgr->exclusive_cmd_cnt, g_ps3_qos_jbod_exclusive); + } else { + ps3_atomic_set(&qos_vd_mgr->exclusive_cmd_cnt, g_ps3_qos_vd_exclusive); + } + ps3_atomic_set(&qos_vd_mgr->share_cmd_used, 0); + } + + qos_ctx->pd_ctx.nvme_normal_quota = g_ps3_qos_hba_nvme_normal_quota; + for (i = 1; i <= qos_ctx->max_pd_count; i++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, i); + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1) { + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, i); + if (pd_entry != NULL) { + ps3_qos_pd_rsc_init(qos_pd_mgr, pd_entry); + } + } + } +} + +void ps3_qos_close(struct ps3_instance *instance) +{ + if (!PS3_QOS_INITED(instance)) { + return; + } + + ps3_qos_wait_io_end(instance); + instance->qos_context.opts.qos_waitq_clear(instance, + PS3_SCSI_RESULT_HOST_STATUS(DID_SOFT_ERROR)); + LOG_INFO("qos close. host_no:%u\n", PS3_HOST(instance)); +} + +void ps3_qos_open(struct ps3_instance *instance) +{ + if (!PS3_QOS_INITED(instance)) { + return; + } + + instance->qos_context.opts.qos_reset(instance); +} + +static U8 ps3_qos_waitq_flag_get(struct ps3_qos_softq_mgr *softq_mgr) +{ + U8 waitq_flag = 0; + switch (softq_mgr->id) { + case PS3_QOS_MGRQ: + waitq_flag = PS3_QOS_CMD_IN_MGR; + break; + case PS3_QOS_CMDQ_0: + waitq_flag = PS3_QOS_CMD_IN_CMDQ0; + break; + case PS3_QOS_CMDQ_1: + waitq_flag = PS3_QOS_CMD_IN_CMDQ1; + break; + case PS3_QOS_CMDQ_2: + waitq_flag = PS3_QOS_CMD_IN_CMDQ2; + break; + case PS3_QOS_CMDQ_3: + waitq_flag = PS3_QOS_CMD_IN_CMDQ3; + break; + default: + LOG_ERROR_IN_IRQ(softq_mgr->instance, "invalid softq id. host_no:%u id:%u\n", + PS3_HOST(softq_mgr->instance), softq_mgr->id); + } + + return waitq_flag; +} + +static Bool ps3_qos_cq_rc_get(struct ps3_cmd *cmd, + struct ps3_qos_softq_mgr *softq_mgr, struct qos_wait_queue *wait_q) +{ + Bool can_get = PS3_FALSE; + ULong flag = 0; + if (ps3_atomic_dec_return(&softq_mgr->free_cnt) >= 0) { + can_get = PS3_TRUE; + } else { + ps3_atomic_inc(&softq_mgr->free_cnt); + } + + if (!can_get) { + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + list_add_tail(&cmd->qos_list, &wait_q->wait_list); + wait_q->count++; + softq_mgr->total_wait_cmd_cnt++; + cmd->qos_waitq_flag = ps3_qos_waitq_flag_get(softq_mgr); + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + LOG_DEBUG("insert qos cq waitq.host_no:%u:t_id:0x%llx " + "CFID:%u que_id:%u diskid:%u waitq:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, softq_mgr->id, + cmd->io_attr.disk_id, wait_q->count); + } + + return can_get; +} + +static struct qos_wait_queue* ps3_qos_cq_waitq_get(struct ps3_cmd *cmd, + struct ps3_qos_softq_mgr *softq_mgr) +{ + U16 waitq_id = 0; + struct qos_wait_queue *waitq = NULL; + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type)) { + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + waitq_id = get_offset_of_vdid(PS3_VDID_OFFSET(cmd->instance), + PS3_VDID(&cmd->io_attr.vd_entry->diskPos)); + } else { + waitq_id = cmd->instance->qos_context.max_vd_count; + } + waitq = &softq_mgr->waitqs[waitq_id]; + } else { + waitq = &softq_mgr->waitqs[0]; + } + + return waitq; +} + +static Bool ps3_qos_cq_rc_check(struct ps3_cmd *cmd, + struct ps3_qos_softq_mgr *softq_mgr) +{ + Bool can_get = PS3_FALSE; + ULong flag = 0; + struct qos_wait_queue *waitq = NULL; + + waitq = ps3_qos_cq_waitq_get(cmd, softq_mgr); + if (likely(softq_mgr->total_wait_cmd_cnt == 0)) { + can_get = ps3_qos_cq_rc_get(cmd, softq_mgr, waitq); + } else { + INJECT_START(PS3_ERR_IJ_QOS_WAIT_SOFT_WAITQ_CLEAR, cmd->instance) + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + if (softq_mgr->total_wait_cmd_cnt > 0) { + list_add_tail(&cmd->qos_list, &waitq->wait_list); + waitq->count++; + softq_mgr->total_wait_cmd_cnt++; + cmd->qos_waitq_flag = ps3_qos_waitq_flag_get(softq_mgr); + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + can_get = PS3_FALSE; + LOG_DEBUG("insert qos cq waitq.host_no:%u:t_id:0x%llx CFID:%u " + "que_id:%u diskid:%u waitq:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, softq_mgr->id, + cmd->io_attr.disk_id, waitq->count); + } else { + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + can_get = ps3_qos_cq_rc_get(cmd, softq_mgr, waitq); + } + } + + return can_get; +} + +static inline struct ps3_qos_softq_mgr *ps3_qos_cmdq_mgr_get(struct ps3_instance *instance, U16 index) +{ + return &instance->qos_context.cq_ctx.cmdqs[index]; +} + +static void ps3_qos_update_target_cmdq(struct ps3_cmd *cmd) +{ + U8 que_id = 0; + U8 qmask = 0; + + cmd->cmdq_count = 0; + qmask = cmd->cmd_word.qMask; + while (que_id < cmd->instance->ctrl_info.vdQueueNum) { + if (qmask & (1 << que_id)) { + cmd->cmdq_info[cmd->cmdq_count].que_id = que_id; + if (++cmd->cmdq_count == PS3_QOS_MAX_CMDQ_ONE_CMD) { + break; + } + } + que_id++; + } +} + +static Bool ps3_qos_cq_decision(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_TRUE; + struct ps3_instance *instance = cmd->instance; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + U16 cmdq_index = 0; + U8 i = 0; + + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_MGR_PRO); + softq_mgr = &instance->qos_context.cq_ctx.mgrq; + can_get = ps3_qos_cq_rc_check(cmd, softq_mgr); + PS3_QOS_STAT_END(cmd->instance, cmd, PS3_QOS_MGR_PRO); + if (!can_get) { + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_MGR_QUEUE); + } + } else { + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_CMD_PRO); + ps3_qos_update_target_cmdq(cmd); + for (i = 0; i < cmd->cmdq_count; i++) { + cmdq_index = cmd->cmdq_info[i].que_id; + softq_mgr = ps3_qos_cmdq_mgr_get(instance, cmdq_index); + can_get = ps3_qos_cq_rc_check(cmd, softq_mgr); + if (can_get) { + cmd->cmdq_info[i].get_rc = PS3_TRUE; + } else { + can_get = PS3_FALSE; + break; + } + } + PS3_QOS_STAT_END(cmd->instance, cmd, PS3_QOS_CMD_PRO); + if (!can_get) { + PS3_QOS_STAT_START(cmd->instance, cmd, PS3_QOS_CMD_QUEUE); + } + } + + return can_get; +} + +Bool ps3_raid_qos_decision(struct ps3_cmd *cmd) +{ + Bool can_get = PS3_FALSE; + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type)) { + can_get = ps3_qos_pd_quota_decision(cmd); + if (!can_get || + cmd->io_attr.direct_flag == PS3_CMDWORD_DIRECT_OK) { + goto _out; + } + } + can_get = ps3_qos_cq_decision(cmd); +_out: + return can_get; +} + +static void ps3_qos_update_cmdq_rc(struct ps3_cmd *cmd) +{ + U8 i = 0; + U8 index = 0; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + S32 cmdq_free = 0; + + for (i = 0; i < cmd->cmdq_count; i++) { + index = cmd->cmdq_info[i].que_id; + softq_mgr = ps3_qos_cmdq_mgr_get(cmd->instance, index); + cmdq_free = ps3_atomic_inc_return(&softq_mgr->free_cnt); + LOG_DEBUG("update cmdq rc. host_no:%u t_id:0x%llx CFID:%u rc[%u,%d] dev_t:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, softq_mgr->id, cmdq_free, + cmd->io_attr.dev_type); + } +} + +static void ps3_qos_update_mgrq_rc(struct ps3_cmd *cmd) +{ + struct ps3_qos_cq_context *qos_cq_ctx = &cmd->instance->qos_context.cq_ctx; + S32 free_cnt = 0; + + free_cnt = ps3_atomic_inc_return(&qos_cq_ctx->mgrq.free_cnt); + LOG_DEBUG("update mgrq rc. host_no:%u t_id:0x%llx CFID:%u rc:%d\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, free_cnt); +} + +static void ps3_raid_qos_cmd_update(struct ps3_cmd *cmd) +{ + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_MGR) { + ps3_qos_update_mgrq_rc(cmd); + } else { + ps3_qos_update_pd_quota(cmd); + ps3_qos_update_cmdq_rc(cmd); + } +} + +void ps3_qos_mgrq_resend(struct ps3_qos_softq_mgr *softq_mgr) +{ + S32 ret = PS3_SUCCESS; + ULong flag = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_instance *instance = softq_mgr->instance; + struct qos_wait_queue *waitq = &softq_mgr->waitqs[0]; + Bool waitq_cleared = PS3_FALSE; + + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + while (waitq->count > 0) { + cmd = list_first_entry(&waitq->wait_list, struct ps3_cmd, qos_list); + if (ps3_atomic_dec_return(&softq_mgr->free_cnt) < 0) { + ps3_atomic_inc(&softq_mgr->free_cnt); + break; + } + list_del(&cmd->qos_list); + waitq->count--; + softq_mgr->total_wait_cmd_cnt--; + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_MGR_QUEUE); + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_raid_qos_cmd_update(cmd); + ps3_qos_cmd_resend_fail(cmd, ret); + } else { + cmd->qos_waitq_flag = 0; + LOG_DEBUG("raid qos mgr waitq resend:host_no:%u t_id:0x%llx CFID:%u type:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, cmd->cmd_word.type); + } + } + + if (softq_mgr->total_wait_cmd_cnt == 0) { + waitq_cleared = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + + if (waitq_cleared) { + LOG_DEBUG("hno:%u resend all mgrq waited cmds\n", + PS3_HOST(instance)); + } + softq_mgr->last_sched_jiffies = jiffies; +} + +static void ps3_qos_mgrq_resend_work(struct work_struct *work) +{ + struct ps3_qos_softq_mgr *softq_mgr = + ps3_container_of(work, struct ps3_qos_softq_mgr, resend_work); + ps3_qos_mgrq_resend(softq_mgr); + return; +} + +static S32 ps3_qos_mgrq_init(struct ps3_instance *instance, struct ps3_qos_softq_mgr *softq_mgr) +{ + S32 ret = PS3_SUCCESS; + U32 mgrq_depth = 0; + U32 high_mgr_cmd = 0; + char workq_name[PS3_QOS_MAX_WORKQ_NAME_LENGTH] = {0}; + + if (!ps3_ioc_multi_func_support(instance)) { + high_mgr_cmd = PS3_QOS_HIGH_PRI_MGR_CMD_COUNT; + } else { + high_mgr_cmd = PS3_QOS_HIGH_PRI_MGR_CMD_COUNT >> 1; + } + + mgrq_depth = instance->qos_context.cq_ctx.mgrq_depth; + if (mgrq_depth <= high_mgr_cmd) { + ret = -PS3_FAILED; + LOG_ERROR("hno:%u:mgrq_depth is too small func:%u depth:%u\n", + PS3_HOST(softq_mgr->instance), ps3_get_pci_function(instance->pdev), + mgrq_depth); + goto _out; + } + + softq_mgr->id = PS3_QOS_MGRQ; + softq_mgr->instance = instance; + ps3_spin_lock_init(&softq_mgr->rc_lock); + ps3_atomic_set(&softq_mgr->free_cnt, mgrq_depth - high_mgr_cmd); + softq_mgr->waitq_cnt = 1; + softq_mgr->waitqs = (struct qos_wait_queue *)ps3_vzalloc(instance, sizeof(struct qos_wait_queue)); + INJECT_START(PS3_ERR_IJ_QOS_MGRQ_INIT_FAIL_1, softq_mgr) + if (softq_mgr->waitqs == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for waitqs\n", + PS3_HOST(softq_mgr->instance)); + ret = -PS3_FAILED; + goto _out; + } + INIT_LIST_HEAD(&softq_mgr->waitqs[0].wait_list); + softq_mgr->waitqs[0].count = 0; + INIT_WORK(&softq_mgr->resend_work, ps3_qos_mgrq_resend_work); + softq_mgr->total_wait_cmd_cnt = 0; + softq_mgr->last_sched_jiffies = 0; + snprintf(workq_name, PS3_QOS_MAX_WORKQ_NAME_LENGTH, "mgrq_wq_f%u", + ps3_get_pci_function(instance->pdev)); + softq_mgr->work_queue = create_singlethread_workqueue(workq_name); + INJECT_START(PS3_ERR_IJ_QOS_MGRQ_INIT_FAIL_2, softq_mgr) + if (softq_mgr->work_queue == NULL) { + LOG_ERROR("qos mgr workq create failed\n"); + ret = -PS3_FAILED; + goto _release_waitq; + } + + LOG_INFO("hno:%u:mgrq init success func:%u depth:%u\n", + PS3_HOST(softq_mgr->instance), ps3_get_pci_function(instance->pdev), + mgrq_depth); + goto _out; +_release_waitq: + ps3_vfree(instance, softq_mgr->waitqs); + softq_mgr->waitqs = NULL; +_out: + return ret; +} + +static Bool ps3_qos_softq_notify(struct ps3_qos_softq_mgr *softq_mgr) +{ + Bool notified = PS3_FALSE; + if (softq_mgr->total_wait_cmd_cnt > 0 && + ps3_atomic_read(&softq_mgr->free_cnt) > 0) { + queue_work(softq_mgr->work_queue, &softq_mgr->resend_work); + notified = PS3_TRUE; + } + + return notified; +} + +static Bool ps3_qos_cq_notify(struct ps3_instance *instance) +{ + U8 i = 0; + Bool notified = PS3_FALSE; + struct ps3_qos_cq_context *qos_cq_ctx = &instance->qos_context.cq_ctx; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + + softq_mgr = &qos_cq_ctx->mgrq; + ps3_qos_softq_notify(softq_mgr); + + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + softq_mgr = ps3_qos_cmdq_mgr_get(instance, i); + if (ps3_qos_softq_notify(softq_mgr)) { + notified = PS3_TRUE; + } + } + + return notified; +} + +void ps3_raid_qos_waitq_notify(struct ps3_instance *instance) +{ + if (!ps3_qos_cq_notify(instance)) { + ps3_qos_pd_notify(instance); + } +} + +static Bool ps3_qos_cmdq_resend_judge(struct ps3_qos_softq_mgr *softq_mgr, struct ps3_cmd *cmd) +{ + Bool can_get = PS3_TRUE; + struct ps3_instance *instance = NULL; + struct ps3_qos_softq_mgr *next_softq_mgr = NULL; + + instance = cmd->instance; + if (cmd->cmdq_count == 1) { + cmd->cmdq_info[0].get_rc = PS3_TRUE; + } else { + if (cmd->cmdq_info[0].que_id == softq_mgr->id) { + cmd->cmdq_info[0].get_rc = PS3_TRUE; + next_softq_mgr = ps3_qos_cmdq_mgr_get(instance, cmd->cmdq_info[1].que_id); + can_get = ps3_qos_cq_rc_check(cmd, next_softq_mgr); + if (can_get) { + cmd->cmdq_info[1].get_rc = PS3_TRUE; + } + } else { + cmd->cmdq_info[1].get_rc = PS3_TRUE; + } + } + + if (can_get) { + PS3_QOS_STAT_END(instance, cmd, PS3_QOS_CMD_QUEUE); + } + + LOG_DEBUG("raid resend cmdq judge:host_no:%u t_id:0x%llx CFID:%u cmdq_id:%u ret:%u\n", + PS3_HOST(cmd->instance), cmd->trace_id, cmd->index, softq_mgr->id, can_get); + return can_get; +} + +static void ps3_qos_resend_multi_cmd(struct ps3_qos_softq_mgr *softq_mgr, + struct qos_wait_queue *waitq, S32 count) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_instance *instance = softq_mgr->instance; + U32 can_send = 0; + + can_send = PS3_MIN(ps3_atomic_read(&softq_mgr->free_cnt), count); + while(waitq->count > 0 && can_send > 0) { + cmd = list_first_entry(&waitq->wait_list, struct ps3_cmd, qos_list); + list_del(&cmd->qos_list); + softq_mgr->total_wait_cmd_cnt--; + waitq->count--; + + if (ps3_qos_vd_seq_check(cmd)) { + continue; + } + can_send--; + ps3_atomic_dec(&softq_mgr->free_cnt); + if (ps3_qos_cmdq_resend_judge(softq_mgr, cmd)) { + ret = ps3_scsi_cmd_send(instance, cmd, PS3_FALSE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_raid_qos_cmd_update(cmd); + ps3_qos_cmd_resend_fail(cmd, ret); + } else { + cmd->qos_waitq_flag = 0; + LOG_DEBUG("raid qos cmdq waitq resend:host_no:%u t_id:0x%llx CFID:%u qid:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, waitq->id); + } + } + } +} + +static void ps3_qos_cmdq_resend(struct ps3_qos_softq_mgr *softq_mgr) +{ + ULong flag = 0; + struct ps3_instance *instance = softq_mgr->instance; + struct qos_wait_queue *waitq = NULL; + U16 cur_que_id = softq_mgr->poll_que_id; + + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + while (ps3_atomic_read(&softq_mgr->free_cnt) > 0 + && softq_mgr->total_wait_cmd_cnt > 0) { + waitq = &softq_mgr->waitqs[cur_que_id]; + if (waitq->count > 0) { + ps3_qos_resend_multi_cmd(softq_mgr, waitq, softq_mgr->poll_cmd_cnt); + } + if (++cur_que_id > instance->qos_context.max_vd_count) { + cur_que_id = 1; + } + } + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + softq_mgr->poll_que_id = cur_que_id; + softq_mgr->last_sched_jiffies = jiffies; + ps3_qos_pd_notify(instance); +} + +static void ps3_qos_cmdq_resend_work(struct work_struct *work) +{ + struct ps3_qos_softq_mgr *softq_mgr = + ps3_container_of(work, struct ps3_qos_softq_mgr, resend_work); + ps3_qos_cmdq_resend(softq_mgr); + return; +} + +static S32 ps3_qos_cmdq_init(struct ps3_instance *instance, struct ps3_qos_softq_mgr *softq_mgr) +{ + S32 ret = PS3_SUCCESS; + U16 i = 0; + struct qos_wait_queue *waitq = NULL; + char workq_name[PS3_QOS_MAX_WORKQ_NAME_LENGTH] = {0}; + U32 cmdq_depth = 0; + + cmdq_depth = instance->qos_context.cq_ctx.cmdq_depth; + softq_mgr->instance = instance; + ps3_spin_lock_init(&softq_mgr->rc_lock); + ps3_atomic_set(&softq_mgr->free_cnt, cmdq_depth); + softq_mgr->waitq_cnt = instance->qos_context.max_vd_count + 1; + softq_mgr->waitqs = (struct qos_wait_queue *)ps3_vzalloc(instance, + softq_mgr->waitq_cnt * sizeof(struct qos_wait_queue)); + INJECT_START(PS3_ERR_IJ_QOS_CMDQ_INIT_FAIL_1, softq_mgr) + if (softq_mgr->waitqs == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for waitqs\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _out; + } + memset(softq_mgr->waitqs, 0, (instance->qos_context.max_vd_count + 1) * sizeof(struct qos_wait_queue)); + for (i = 1; i < softq_mgr->waitq_cnt; i++) { + waitq = &softq_mgr->waitqs[i]; + waitq->id = i; + INIT_LIST_HEAD(&waitq->wait_list); + waitq->count = 0; + } + + softq_mgr->poll_cmd_cnt = PS3_QOS_POLL_CMD_COUNT; + softq_mgr->poll_que_id = 1; + INIT_WORK(&softq_mgr->resend_work, ps3_qos_cmdq_resend_work); + softq_mgr->total_wait_cmd_cnt = 0; + softq_mgr->last_sched_jiffies = 0; + snprintf(workq_name, PS3_QOS_MAX_WORKQ_NAME_LENGTH, "cmdq_wq_f%u_%u", + ps3_get_pci_function(instance->pdev), softq_mgr->id); + softq_mgr->work_queue = create_singlethread_workqueue(workq_name); + INJECT_START(PS3_ERR_IJ_QOS_CMDQ_INIT_FAIL_2, softq_mgr) + if (softq_mgr->work_queue == NULL) { + LOG_ERROR("qos mgr workq create failed\n"); + ret = -PS3_FAILED; + goto _release_waitq; + } + + LOG_INFO("hno:%u:cmdq init success func:%u depth:%u id:%u\n", + PS3_HOST(softq_mgr->instance), ps3_get_pci_function(instance->pdev), + cmdq_depth, softq_mgr->id); + goto _out; +_release_waitq: + ps3_vfree(instance, softq_mgr->waitqs); + softq_mgr->waitqs = NULL; +_out: + return ret; +} + +static void ps3_qos_softq_exit(struct ps3_instance *instance, struct ps3_qos_softq_mgr *softq_mgr) +{ + cancel_work_sync(&softq_mgr->resend_work); + flush_workqueue(softq_mgr->work_queue); + destroy_workqueue(softq_mgr->work_queue); + ps3_vfree(instance, softq_mgr->waitqs); + softq_mgr->waitqs = NULL; +} + +static S32 ps3_qos_cq_context_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U16 i = 0; + U16 j = 0; + struct ps3_qos_cq_context *qos_cq_ctx = NULL; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + U64 mgrq_depth = 0; + U64 cmdq_depth = 0; + + qos_cq_ctx = &instance->qos_context.cq_ctx; + ps3_mgrq_depth_get(instance, &mgrq_depth); + INJECT_START(PS3_ERR_IJ_QOS_FORCE_MGRQ_ZERO_DEPTH, &mgrq_depth) + if (mgrq_depth == 0) { + ret = -PS3_FAILED; + LOG_ERROR("hno:%u:mgrq_depth is invalid func:%u\n", + PS3_HOST(instance),ps3_get_pci_function(instance->pdev)); + goto _out; + } + qos_cq_ctx->mgrq_depth = mgrq_depth; + + ps3_cmdq_depth_get(instance, &cmdq_depth); + INJECT_START(PS3_ERR_IJ_QOS_FORCE_CMDQ_ZERO_DEPTH, &cmdq_depth) + if (cmdq_depth == 0) { + ret = -PS3_FAILED; + LOG_ERROR("hno:%u:cmdq_depth is invalid func:%u\n", + PS3_HOST(instance), + ps3_get_pci_function(instance->pdev)); + goto _out; + } + qos_cq_ctx->cmdq_depth = cmdq_depth; + + if (ps3_qos_mgrq_init(instance, &qos_cq_ctx->mgrq) != PS3_SUCCESS) { + ret = -PS3_FAILED; + goto _out; + } + + qos_cq_ctx->cmdq_cnt = instance->ctrl_info.vdQueueNum; + qos_cq_ctx->cmdqs = (struct ps3_qos_softq_mgr *)ps3_vzalloc(instance, + qos_cq_ctx->cmdq_cnt * sizeof(struct ps3_qos_softq_mgr)); + if (qos_cq_ctx->cmdqs == NULL) { + LOG_ERROR("hno:%u:Failed to kcalloc memory for cmdqs\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto _mgrq_exit; + } + + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + softq_mgr = &qos_cq_ctx->cmdqs[i]; + softq_mgr->id = i; + if (ps3_qos_cmdq_init(instance, softq_mgr) != PS3_SUCCESS) { + ret = -PS3_FAILED; + goto _cmdq_exit; + } + } + + LOG_INFO("hno:%u: qos cq context init success cmdq_cnt:%u\n", + PS3_HOST(instance), qos_cq_ctx->cmdq_cnt); + goto _out; +_cmdq_exit: + for (j = 0; j < i; j++) { + softq_mgr = &qos_cq_ctx->cmdqs[j]; + ps3_qos_softq_exit(instance, softq_mgr); + } + ps3_vfree(instance, qos_cq_ctx->cmdqs); + qos_cq_ctx->cmdqs = NULL; +_mgrq_exit: + ps3_qos_softq_exit(instance, &qos_cq_ctx->mgrq); +_out: + return ret; +} + +static void ps3_qos_cq_context_exit(struct ps3_instance *instance) +{ + struct ps3_qos_cq_context *qos_cq_ctx = NULL; + U16 i = 0; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + + qos_cq_ctx = &instance->qos_context.cq_ctx; + if (qos_cq_ctx->cmdqs != NULL) { + ps3_qos_softq_exit(instance, &qos_cq_ctx->mgrq); + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + softq_mgr = &qos_cq_ctx->cmdqs[i]; + ps3_qos_softq_exit(instance, softq_mgr); + } + ps3_vfree(instance, qos_cq_ctx->cmdqs); + qos_cq_ctx->cmdqs = NULL; + } + + LOG_INFO("hno:%u: qos cq context exit success\n", PS3_HOST(instance)); +} + +S32 ps3_raid_qos_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + ret = ps3_qos_cq_context_init(instance); + if (ret != PS3_SUCCESS) { + goto _out; + } + + ret = ps3_qos_pd_context_init(instance); + if (ret != PS3_SUCCESS) { + goto _cq_ctx_exit; + } + + goto _out; +_cq_ctx_exit: + ps3_qos_cq_context_exit(instance); +_out: + return ret; +} + +static Bool ps3_qos_softq_abort(struct ps3_qos_softq_mgr *softq_mgr, + struct ps3_cmd *cmd, U8 waitq_flag) +{ + ULong lock_flag = 0; + Bool found = PS3_FALSE; + struct qos_wait_queue *waitq = NULL; + + waitq = ps3_qos_cq_waitq_get(cmd, softq_mgr); + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &lock_flag); + if (cmd->qos_waitq_flag == waitq_flag) { + list_del(&cmd->qos_list); + waitq->count--; + softq_mgr->total_wait_cmd_cnt--; + found = PS3_TRUE; + } + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, lock_flag); + + return found; +} + +static void ps3_qos_peer_cmdq_rc_update(struct ps3_cmd *cmd) +{ + U8 i = 0; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + for (i = 0; i < cmd->cmdq_count; i++) { + if (cmd->cmdq_info[i].get_rc) { + softq_mgr = ps3_qos_cmdq_mgr_get(cmd->instance, cmd->cmdq_info[i].que_id); + ps3_atomic_inc(&softq_mgr->free_cnt); + } + } +} + +static Bool ps3_qos_cmdq_abort(struct ps3_cmd *cmd) +{ + U8 i = 0; + U8 waitq_flag = 0; + Bool found = PS3_FALSE; + struct ps3_qos_softq_mgr *qos_softq_mgr = NULL; + + for (i = 0; i < cmd->cmdq_count; i++) { + qos_softq_mgr = ps3_qos_cmdq_mgr_get(cmd->instance, cmd->cmdq_info[i].que_id); + waitq_flag = ps3_qos_waitq_flag_get(qos_softq_mgr); + if (cmd->qos_waitq_flag == waitq_flag) { + found = ps3_qos_softq_abort(qos_softq_mgr, cmd, waitq_flag); + if (found) { + break; + } + } + } + + return found; +} + +Bool ps3_raid_qos_waitq_abort(struct ps3_cmd *cmd) +{ + Bool found = PS3_FALSE; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + + if (cmd->qos_waitq_flag == 0) { + goto _out; + } + + if (PS3_CMD_TYPE_IS_RW(cmd->cmd_word.type)) { + if (cmd->qos_waitq_flag == PS3_QOS_CMD_IN_PD) { + found = ps3_pd_quota_waiq_abort(cmd); + if (found) { + goto _out; + } + } + + found = ps3_qos_cmdq_abort(cmd); + if (found) { + ps3_qos_update_pd_quota(cmd); + ps3_qos_peer_cmdq_rc_update(cmd); + } + } else { + if (cmd->qos_waitq_flag == PS3_QOS_CMD_IN_MGR) { + softq_mgr = &cmd->instance->qos_context.cq_ctx.mgrq; + found = ps3_qos_softq_abort(softq_mgr, cmd, PS3_QOS_CMD_IN_MGR); + } + } + +_out: + return found; +} + +static void ps3_qos_mgrq_clean(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + struct ps3_qos_softq_mgr *softq_mgr = NULL; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct qos_wait_queue *waitq = NULL; + ULong flag = 0; + + softq_mgr = &instance->qos_context.cq_ctx.mgrq; + waitq = &softq_mgr->waitqs[0]; + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + if (waitq->count > 0) { + list_for_each_entry_safe(cmd, cmd_next, &waitq->wait_list, qos_list) { + if (priv_data == NULL || + priv_data == scsi_device_private_data(cmd->scmd)) { + LOG_DEBUG("qos clean mgrq. hno:%u t_id:0x%llx CFID:%d\n", + PS3_HOST(instance), cmd->trace_id, cmd->index); + list_del(&cmd->qos_list); + waitq->count--; + softq_mgr->total_wait_cmd_cnt--; + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + } + } + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + if (priv_data == NULL) { + cancel_work_sync(&softq_mgr->resend_work); + } +} + +static void ps3_qos_cmdq_clean(struct ps3_instance *instance, U16 disk_id, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + U8 i = 0; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct qos_wait_queue *waitq = NULL; + ULong flag = 0; + struct ps3_qos_cq_context *qos_cq_ctx = &instance->qos_context.cq_ctx; + + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + softq_mgr = ps3_qos_cmdq_mgr_get(instance, i); + waitq = &softq_mgr->waitqs[disk_id]; + if (waitq->count > 0) { + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + list_for_each_entry_safe(cmd, cmd_next, &waitq->wait_list, qos_list) { + if (priv_data == NULL || + priv_data == scsi_device_private_data(cmd->scmd)) { + LOG_DEBUG("qos clean cmdq. hno:%u t_id:0x%llx CFID:%d cmdq:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, softq_mgr->id); + list_del(&cmd->qos_list); + waitq->count--; + softq_mgr->total_wait_cmd_cnt--; + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + } + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + } + } +} + +static void ps3_qos_cmdq_clear(struct ps3_instance *instance, S32 resp_status) +{ + U16 i = 0; + U16 j = 0; + struct ps3_qos_softq_mgr *softq_mgr = NULL; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct qos_wait_queue *waitq = NULL; + ULong flag = 0; + struct ps3_qos_cq_context *qos_cq_ctx = &instance->qos_context.cq_ctx; + + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + softq_mgr = ps3_qos_cmdq_mgr_get(instance, i); + for (j = 1; j <= instance->qos_context.max_vd_count; j++) { + waitq = &softq_mgr->waitqs[j]; + if (waitq->count > 0) { + ps3_spin_lock_irqsave(&softq_mgr->rc_lock, &flag); + list_for_each_entry_safe(cmd, cmd_next, &waitq->wait_list, qos_list) { + LOG_DEBUG("qos clean cmdq. hno:%u t_id:0x%llx CFID:%d cmdq:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, softq_mgr->id); + list_del(&cmd->qos_list); + waitq->count--; + softq_mgr->total_wait_cmd_cnt--; + ps3_qos_update_pd_quota(cmd); + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, resp_status, PS3_FALSE); + } + ps3_spin_unlock_irqrestore(&softq_mgr->rc_lock, flag); + } + } + cancel_work_sync(&softq_mgr->resend_work); + } +} + +static void ps3_raid_qos_pd_clean(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + U16 pd_id = 0; + U16 vd_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + pd_id = PS3_PDID(&priv_data->disk_pos); + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + ps3_pd_quota_waitq_clean(qos_pd_mgr, 0, resp_status); + + if (!PS3_QOS_PD_IS_VD_MEMBER(qos_pd_mgr)) { + vd_id = instance->qos_context.max_vd_count; + ps3_qos_cmdq_clean(instance, vd_id, priv_data, resp_status); + ps3_qos_mgrq_clean(instance, priv_data, resp_status); + } + + LOG_INFO("qos clean vd. host_no:%u did:%u vid:%u\n", + PS3_HOST(instance), pd_id, vd_id); +} + +static void ps3_raid_qos_vd_clean(struct ps3_instance *instance, + struct ps3_scsi_priv_data *priv_data, S32 resp_status) +{ + U16 vd_id = 0; + U16 pd_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + vd_id = get_offset_of_vdid(PS3_VDID_OFFSET(instance), PS3_VDID(&priv_data->disk_pos)); + for (pd_id = 1; pd_id <= instance->qos_context.max_pd_count; pd_id++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, pd_id); + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1 && PS3_QOS_PD_IS_VD_MEMBER(qos_pd_mgr)) { + ps3_pd_quota_waitq_clean(qos_pd_mgr, vd_id, resp_status); + } + } + + ps3_qos_cmdq_clean(instance, vd_id, NULL, resp_status); + ps3_qos_mgrq_clean(instance, priv_data, resp_status); + + LOG_FILE_INFO("qos clean vd. host_no:%u type:%u disk_id:%u\n", + PS3_HOST(instance), priv_data->dev_type, vd_id); +} + +void ps3_raid_qos_waitq_clear_all(struct ps3_instance *instance, S32 resp_status) +{ + U16 i = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + + for (i = 1; i <= instance->qos_context.max_pd_count; i++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, i); + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1) { + ps3_pd_quota_waitq_clear_all(qos_pd_mgr, resp_status); + cancel_work_sync(&qos_pd_mgr->resend_work); + } + } + + ps3_qos_cmdq_clear(instance, resp_status); + + ps3_qos_mgrq_clean(instance, NULL, resp_status); + + LOG_INFO("host_no:%u:clear all qos waitq\n", + PS3_HOST(instance)); +} + +static Bool ps3_qos_softq_notify_timeout(struct ps3_qos_softq_mgr *qos_softq_mgr) +{ + Bool notified = PS3_FALSE; + ULong timeout_jiffies = 0; + + timeout_jiffies = qos_softq_mgr->last_sched_jiffies + PS3_QOS_WAITQ_TIMEOUT * HZ; + if (qos_softq_mgr->total_wait_cmd_cnt && + ps3_atomic_read(&qos_softq_mgr->free_cnt) > 0 && + time_after(jiffies, timeout_jiffies)) { + queue_work(qos_softq_mgr->work_queue, &qos_softq_mgr->resend_work); + notified = PS3_TRUE; + LOG_INFO("awake qos softq by poll. host_no:%u q_id:%u\n", + PS3_HOST(qos_softq_mgr->instance), qos_softq_mgr->id); + } + + return notified; +} + +static Bool ps3_qos_cq_notify_timeout(struct ps3_instance *instance) +{ + struct ps3_qos_cq_context *qos_cq_ctx = NULL; + struct ps3_qos_softq_mgr *qos_softq_mgr = NULL; + Bool notified = PS3_FALSE; + U8 i = 0; + + qos_cq_ctx = &instance->qos_context.cq_ctx; + ps3_qos_softq_notify_timeout(&qos_cq_ctx->mgrq); + + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + qos_softq_mgr = &qos_cq_ctx->cmdqs[i]; + if (ps3_qos_softq_notify_timeout(qos_softq_mgr)) { + notified = PS3_TRUE; + } + } + + return notified; +} + +void ps3_raid_qos_waitq_poll(struct ps3_instance *instance) +{ + if (!ps3_qos_cq_notify_timeout(instance)) { + ps3_qos_pd_notify_timeout(instance); + } +} + +static void ps3_raid_qos_reset(struct ps3_instance *instance) +{ + struct ps3_qos_context *qos_ctx = &instance->qos_context; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_qos_cq_context *qos_cq_ctx = NULL; + struct ps3_qos_softq_mgr *qos_softq_mgr = NULL; + U16 i = 0; + struct ps3_pd_entry *pd_entry = NULL; + + qos_cq_ctx = &instance->qos_context.cq_ctx; + qos_softq_mgr = &qos_cq_ctx->mgrq; + ps3_atomic_set(&qos_softq_mgr->free_cnt, + qos_ctx->cq_ctx.mgrq_depth - (PS3_QOS_HIGH_PRI_MGR_CMD_COUNT >> 1)); + for (i = 0; i < qos_cq_ctx->cmdq_cnt; i++) { + qos_softq_mgr = &qos_cq_ctx->cmdqs[i]; + ps3_atomic_set(&qos_softq_mgr->free_cnt, qos_ctx->cq_ctx.cmdq_depth); + } + + qos_ctx->pd_ctx.nvme_normal_quota = g_ps3_qos_raid_nvme_normal_quota; + for (i = 1; i <= qos_ctx->max_pd_count; i++) { + qos_pd_mgr = ps3_qos_pd_mgr_get(instance, i); + if (ps3_atomic_read(&qos_pd_mgr->valid) == 1) { + pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(instance, i); + if (pd_entry != NULL) { + ps3_qos_pd_rsc_init(qos_pd_mgr, pd_entry); + } + } + } +} + +static Bool ps3_raid_qos_pd_resend_check(struct ps3_cmd *cmd) +{ + return ps3_qos_cq_decision(cmd); +} + +void ps3_raid_qos_exit(struct ps3_instance *instance) +{ + ps3_qos_cq_context_exit(instance); + ps3_qos_pd_context_exit(instance); + + LOG_INFO("raid qos exit. hno:%u\n", PS3_HOST(instance)); +} + +void ps3_hba_qos_prepare(struct ps3_instance *instance) +{ + instance->qos_context.opts.qos_init = ps3_hba_qos_init; + instance->qos_context.opts.qos_exit = ps3_hba_qos_exit; + instance->qos_context.opts.qos_decision = ps3_hba_qos_decision; + instance->qos_context.opts.qos_cmd_update = ps3_hba_qos_cmd_update; + instance->qos_context.opts.qos_waitq_notify = ps3_hba_qos_waitq_notify; + instance->qos_context.opts.qos_pd_resend_check = ps3_hba_qos_pd_resend_check; + instance->qos_context.opts.qos_waitq_abort = ps3_hba_qos_waitq_abort; + instance->qos_context.opts.qos_vd_clean = ps3_hba_qos_vd_clean; + instance->qos_context.opts.qos_pd_clean = ps3_hba_qos_pd_clean; + instance->qos_context.opts.qos_waitq_poll = ps3_hba_qos_waitq_poll; + instance->qos_context.opts.qos_waitq_clear = ps3_hba_qos_waitq_clear_all; + instance->qos_context.opts.qos_reset = ps3_hba_qos_reset; + instance->qos_context.opts.qos_vd_init = ps3_hba_qos_vd_init; + instance->qos_context.opts.qos_vd_reset = ps3_hba_qos_vd_reset; + instance->qos_context.qos_switch = 1; + instance->qos_context.pd_ctx.nvme_normal_quota = g_ps3_qos_hba_nvme_normal_quota; +} + +void ps3_raid_qos_prepare(struct ps3_instance *instance) +{ + instance->qos_context.opts.qos_init = ps3_raid_qos_init; + instance->qos_context.opts.qos_exit = ps3_raid_qos_exit; + instance->qos_context.opts.qos_decision = ps3_raid_qos_decision; + instance->qos_context.opts.qos_cmd_update = ps3_raid_qos_cmd_update; + instance->qos_context.opts.qos_waitq_notify = ps3_raid_qos_waitq_notify; + instance->qos_context.opts.qos_pd_resend_check = ps3_raid_qos_pd_resend_check; + instance->qos_context.opts.qos_waitq_abort = ps3_raid_qos_waitq_abort; + instance->qos_context.opts.qos_vd_clean = ps3_raid_qos_vd_clean; + instance->qos_context.opts.qos_pd_clean = ps3_raid_qos_pd_clean; + instance->qos_context.opts.qos_waitq_poll = ps3_raid_qos_waitq_poll; + instance->qos_context.opts.qos_waitq_clear = ps3_raid_qos_waitq_clear_all; + instance->qos_context.opts.qos_reset = ps3_raid_qos_reset; + instance->qos_context.opts.qos_vd_init = NULL; + instance->qos_context.opts.qos_vd_reset = NULL; + instance->qos_context.qos_switch = 1; + instance->qos_context.pd_ctx.nvme_normal_quota = g_ps3_qos_raid_nvme_normal_quota; +} + +S32 ps3_qos_decision(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + Bool can_get = PS3_TRUE; + struct ps3_instance *instance = NULL; + + cmd->qos_processing = PS3_TRUE; + wmb(); + instance = cmd->instance; + if (!ps3_qos_enable(cmd->instance) || !PS3_QOS_INITED(instance)) { + goto _exit; + } + + ret = ps3_qos_pre_check(instance, cmd); + if (ret != PS3_SUCCESS) { + goto _exit; + } + + can_get = instance->qos_context.opts.qos_decision(cmd); + if (!can_get) { + ret = -PS3_IN_QOS_Q; + PS3_QOS_CMD_INC(instance); + } +_exit: + cmd->qos_processing = PS3_FALSE; + return ret; +} + +void ps3_qos_cmd_update(struct ps3_instance *instance, struct ps3_cmd *cmd) +{ + if (!ps3_qos_enable(instance) || !PS3_QOS_INITED(instance)) { + return; + } + + instance->qos_context.opts.qos_cmd_update(cmd); +} + +void ps3_qos_waitq_notify(struct ps3_instance *instance) +{ + + if (!ps3_qos_enable(instance) || !PS3_QOS_INITED(instance)) { + return; + } + instance->qos_context.opts.qos_waitq_notify(instance); +} + +Bool ps3_qos_waitq_abort(struct ps3_cmd *cmd) +{ + Bool found = PS3_FALSE; + if (!PS3_QOS_INITED(cmd->instance)) { + goto out; + } + + found = cmd->instance->qos_context.opts.qos_waitq_abort(cmd); + LOG_INFO("task abort cmd in qos waitq t_id:0x%llx CFID:%u flag:%u ret:%u\n", + cmd->trace_id, cmd->index, cmd->qos_waitq_flag, found); + if (found) { + ps3_scsih_drv_io_reply_scsi(cmd->scmd, cmd, SCSI_STATUS_TASK_ABORTED, PS3_FALSE); + } +out: + return found; +} + +void ps3_qos_hard_reset(struct ps3_instance *instance) +{ + S32 resp_status = 0; + if (ps3_pci_err_recovery_get(instance)) { + resp_status = PS3_STATUS_PCI_RECOVERY; + } else { + resp_status = PS3_STATUS_HOST_RESET; + } + + ps3_qos_waitq_clear_all(instance, resp_status); +} + +void ps3_qos_waitq_clear_all(struct ps3_instance *instance, S32 resp_status) +{ + if (!PS3_QOS_INITED(instance)) { + return; + } + + ps3_qos_wait_io_end(instance); + instance->qos_context.opts.qos_waitq_clear(instance, resp_status); +} + +S32 ps3_qos_init(struct ps3_instance *instance) +{ + struct ps3_qos_context *qos_ctx = &instance->qos_context; + S32 ret = PS3_SUCCESS; + + qos_ctx->max_vd_count = instance->ctrl_info.maxVdCount + 1; + qos_ctx->max_pd_count = instance->ctrl_info.maxPdCount; + qos_ctx->inited = 0; + + LOG_INFO("hno:%u ps3 qos info:tfifo:%u sas_pd_quota[%u %u] sata_pd_quota[%u %u] nvme_quota[%u %u %u]\n", + PS3_HOST(instance), instance->ctrl_info.qosInfo.tfifoDepth, + instance->ctrl_info.qosInfo.sasHddQuota, + instance->ctrl_info.qosInfo.sasSsdQuota, + instance->ctrl_info.qosInfo.sataHddQuota, + instance->ctrl_info.qosInfo.sataSsdQuota, + instance->ctrl_info.qosInfo.nvmeVdQuota, + instance->ctrl_info.qosInfo.nvmeDirectQuota, + instance->ctrl_info.qosInfo.nvmeNormalQuota); + + if (qos_ctx->opts.qos_init) { + if (qos_ctx->opts.qos_init(instance) == PS3_SUCCESS) { + qos_ctx->inited = 1; + LOG_INFO("hno:%u:ps3 qos init success, vd_count:%u pd_count:%u\n", + PS3_HOST(instance), qos_ctx->max_vd_count, qos_ctx->max_pd_count); + } else { + ret = -PS3_FAILED; + } + } + + return ret; +} + +void ps3_qos_exit(struct ps3_instance *instance) +{ + if (instance->qos_context.opts.qos_exit) { + instance->qos_context.opts.qos_exit(instance); + instance->qos_context.inited = 0; + } +} diff --git a/drivers/scsi/ps3stor/ps3_qos.h b/drivers/scsi/ps3stor/ps3_qos.h new file mode 100644 index 0000000000000000000000000000000000000000..bd1db94a62330d6040978acdeec9686731d4b4c6 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_qos.h @@ -0,0 +1,290 @@ + +#ifndef _PS3_QOS_H_ +#define _PS3_QOS_H_ + +#include "ps3_platform_utils.h" +#include "ps3_htp.h" +#include "ps3_cmd_channel.h" + +#define QOS_HIGH_PRI_EXCLUSIVE_CMD_COUNT 32 +#define QOS_MGR_EXCLUSIVE_CMD_COUNT 64 +#define PS3_QOS_DEFAULT_PD_QUOTA 40 +#define PS3_QOS_SAS_PD_QUOTA 125 +#define PS3_QOS_NVME_MEMBER_QUOTA 127 +#define PS3_QOS_NVME_DIRECT_QUOTA 127 +#define PS3_QOS_HBA_NVME_NORMAL_QUOTA 126 +#define PS3_QOS_RAID_NVME_NORMAL_QUOTA 252 +#define PS3_QOS_FUNC1_JBOD_VD_QUOTA 768 +#define PS3_QOS_VD_EXCLUSIVE_CMD_COUNT 40 +#define PS3_QOS_JBOD_EXCLUSIVE_CMD_COUNT 128 +#define PS3_QOS_POLL_INTERVAL 2 +#define PS3_QOS_WAITQ_TIMEOUT 5 +#define PS3_QOS_HBA_MAX_CMD 944 +#define PS3_QOS_CS_FUNC0_SHARE_CMD 80 +#define PS3_QOS_CS_FUNC0_JBOD_VD_QUOTA 80 +#define PS3_QOS_NOTIFY_CMD_COUNT 32 +#define PS3_QOS_FUNC0_PD_WORKQ_COUNT 1 +#define PS3_QOS_FUNC1_PD_WORKQ_COUNT 4 +#define PS3_QOS_POLL_CMD_COUNT 16 + +#define PS3_CMD_NEED_QOS(cmd) \ + ((cmd)->cmd_word.direct == PS3_CMDWORD_DIRECT_NORMAL || \ + (cmd)->cmd_word.direct == PS3_CMDWORD_DIRECT_ADVICE) + +#define PS3_QOS_INITED(instance) ((instance)->qos_context.inited) + +enum ps3_qos_fifo_type { + PS3_QOS_CMDQ_0, + PS3_QOS_CMDQ_1, + PS3_QOS_CMDQ_2, + PS3_QOS_CMDQ_3, + PS3_QOS_MGRQ, + PS3_QOS_TFIFO, + PS3_QOS_FIFO_TYPE_MAX +}; + +enum ps3_qos_cmd_flag { + PS3_QOS_CMD_INIT = 0, + PS3_QOS_CMD_IN_PD, + PS3_QOS_CMD_IN_VD, + PS3_QOS_CMD_IN_FRAME, + PS3_QOS_CMD_IN_MGR, + PS3_QOS_CMD_IN_CMDQ0, + PS3_QOS_CMD_IN_CMDQ1, + PS3_QOS_CMD_IN_CMDQ2, + PS3_QOS_CMD_IN_CMDQ3 +}; + +enum ps3_qos_quota_adjust_flag { + PS3_QOS_QUOTA_ADJUST_DEFULAT = 0, + PS3_QOS_QUOTA_ADJUST_QFULL, + PS3_QOS_QUOTA_ADJUST_UP, + PS3_QOS_QUOTA_ADJUST_INVALID +}; + +enum ps3_qos_vd_change_type { + PS3_QOS_VD_TYPE_CHANGE_TO_HDD, + PS3_QOS_VD_TYPE_CHANGE_TO_SSD, + PS3_QOS_VD_TYPE_CHANGE_INVALID +}; + +struct qos_wait_queue { + ps3_list_head wait_list; + U32 count; + U16 id; + ps3_spinlock *rsc_lock; + S32 *free_rsc; + ps3_atomic32 *used_rsc; + U32 *total_waited_cnt; + U16 can_resend; + U16 has_resend; + ULong last_sched_jiffies; +}; + +struct ps3_qos_vd_mgr { + Bool valid; + U16 id; + U8 workq_id; + ps3_atomic32 vd_quota; + ps3_spinlock rsc_lock; + struct qos_wait_queue vd_quota_wait_q; + ps3_atomic32 exclusive_cmd_cnt; + ps3_atomic32 share_cmd_used; + struct PS3VDEntry *vd_entry; + struct ps3_instance *instance; + struct work_struct resend_work; + U64 last_sched_jiffies; +}; + +struct ps3_qos_pd_mgr { + ps3_atomic32 valid; + U8 workq_id; + U8 dev_type; + Bool clearing; + U16 disk_id; + U16 vd_id; + S32 pd_quota; + ps3_atomic32 pd_used_quota; + struct ps3_instance *instance; + struct work_struct resend_work; + U64 last_sched_jiffies; + struct qos_wait_queue *waitqs; + U16 waitq_cnt; + U32 total_wait_cmd_cnt; + ps3_spinlock rc_lock; + U16 poll_que_id; + U16 poll_start_que_id; + U16 poll_cmd_cnt; + ps3_spinlock direct_rsc_lock; + S32 direct_quota; + ps3_atomic32 direct_used_quota; + U32 total_waited_direct_cmd; + ps3_atomic32 processing_cnt; + ps3_spinlock adjust_quota_lock; + S32 adjust_max_quota; + S32 adjust_min_quota; + S32 pd_init_quota; +}; + +struct ps3_qos_pd_context { + struct ps3_qos_pd_mgr *qos_pd_mgrs; + struct workqueue_struct **work_queues; + U16 sas_sata_hdd_quota; + U16 sas_sata_ssd_quota; + U16 nvme_normal_quota; + U16 nvme_direct_quota; + ps3_atomic32 workq_id_cnt; + U8 workq_count; +}; + +struct ps3_qos_vd_context { + struct ps3_qos_vd_mgr *qos_vd_mgrs; + struct workqueue_struct **work_queues; + U16 jbod_exclusive_cnt; + U16 vd_exclusive_cnt; + U8 workq_count; + Bool inited; +}; + +struct ps3_qos_tg_context { + U32 share; + U32 mgr_exclusive_cnt; + U16 high_pri_exclusive_cnt; + ps3_atomic32 mgr_free_cnt; + ps3_atomic32 mgr_share_used; + ps3_atomic32 share_free_cnt; + struct qos_wait_queue mgr_cmd_wait_q; + struct qos_wait_queue *vd_cmd_waitqs; + U32 total_wait_cmd_cnt; + U8 poll_vd_id; + ps3_spinlock lock; + struct ps3_instance *instance; + struct workqueue_struct *work_queue; + struct work_struct resend_work; + U64 last_sched_jiffies; +}; + +struct ps3_qos_ops { + S32 (*qos_init)(struct ps3_instance *instance); + void (*qos_exit)(struct ps3_instance *instance); + void (*qos_vd_init)(struct ps3_instance *instance, struct PS3VDEntry *vd_entry); + void (*qos_vd_reset)(struct ps3_instance *instance, U16 disk_id); + Bool (*qos_decision)(struct ps3_cmd *cmd); + void (*qos_cmd_update)(struct ps3_cmd *cmd); + void (*qos_waitq_notify)(struct ps3_instance *instance); + Bool (*qos_pd_resend_check)(struct ps3_cmd *cmd); + Bool (*qos_waitq_abort)(struct ps3_cmd *cmd); + void (*qos_vd_clean)(struct ps3_instance *instance, struct ps3_scsi_priv_data *pri_data, S32 ret_code); + void (*qos_pd_clean)(struct ps3_instance *instance, struct ps3_scsi_priv_data *priv_data, S32 ret_code); + void (*qos_waitq_clear)(struct ps3_instance *instance, S32 ret_code); + void (*qos_waitq_poll)(struct ps3_instance *instance); + void (*qos_reset)(struct ps3_instance *instance); +}; + +Bool inline ps3_qos_enable(struct ps3_instance *instance); + +S32 ps3_hba_qos_init(struct ps3_instance *instance); + +void ps3_hba_qos_exit(struct ps3_instance *instance); + +void ps3_qos_vd_init(struct ps3_instance *instance, struct PS3VDEntry *vd_entry); + +void ps3_qos_vd_reset(struct ps3_instance *instance, U16 disk_id); + +struct ps3_qos_pd_mgr* ps3_qos_pd_mgr_init(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry); + +void ps3_qos_pd_mgr_reset(struct ps3_instance *instance, U16 pd_id); + +void ps3_qos_vd_member_change(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry, + struct scsi_device *sdev, Bool is_vd_member); + +S32 ps3_qos_decision(struct ps3_cmd *cmd); + +void ps3_qos_cmd_update(struct ps3_instance *instance, struct ps3_cmd *cmd); + +void ps3_qos_waitq_notify(struct ps3_instance *instance); + +Bool ps3_qos_waitq_abort(struct ps3_cmd *aborted_cmd); + +void ps3_qos_device_clean(struct ps3_instance *instance, struct ps3_scsi_priv_data *pri_data, + S32 ret_code); + +void ps3_qos_disk_del(struct ps3_instance *instance, struct ps3_scsi_priv_data *priv_data); + +void ps3_qos_vd_member_del(struct ps3_instance *instance, struct PS3DiskDevPos *dev_pos); + +void ps3_qos_hard_reset(struct ps3_instance *instance); + +void ps3_qos_waitq_clear_all(struct ps3_instance *instance, S32 resp_status); + +void ps3_qos_waitq_poll(struct ps3_instance *instance); + +void ps3_qos_close(struct ps3_instance *instance); + +void ps3_qos_open(struct ps3_instance *instance); + +void ps3_hba_qos_prepare(struct ps3_instance *instance); + +void ps3_raid_qos_prepare(struct ps3_instance *instance); + +#define PS3_QOS_CMDQ_COUNT 4 +#define PS3_QOS_CMDQ_DEPTH 4096 +#define PS3_QOS_MGRQ_DEPTH 1024 +#define PS3_QOS_HIGH_PRI_MGR_CMD_COUNT 32 +struct ps3_qos_softq_mgr { + U16 id; + struct ps3_instance *instance; + ps3_spinlock rc_lock; + ps3_atomic32 free_cnt; + struct qos_wait_queue *waitqs; + U16 waitq_cnt; + U32 total_wait_cmd_cnt; + struct workqueue_struct *work_queue; + struct work_struct resend_work; + U64 last_sched_jiffies; + U16 poll_cmd_cnt; + U16 poll_que_id; +}; + +struct ps3_qos_cq_context { + struct ps3_qos_softq_mgr mgrq; + struct ps3_qos_softq_mgr *cmdqs; + U8 cmdq_cnt; + U32 mgrq_depth; + U32 cmdq_depth; +}; + +struct ps3_qos_context { + struct ps3_qos_ops opts; + struct ps3_qos_pd_context pd_ctx; + struct ps3_qos_vd_context vd_ctx; + struct ps3_qos_tg_context tg_ctx; + struct ps3_qos_cq_context cq_ctx; + U16 max_vd_count; + U16 max_pd_count; + U8 poll_count; + U8 qos_switch; + U8 inited; +}; + +S32 ps3_raid_qos_init(struct ps3_instance *instance); + +void ps3_raid_qos_exit(struct ps3_instance *instance); + +S32 ps3_qos_init(struct ps3_instance *instance); + +void ps3_qos_exit(struct ps3_instance *instance); + +void ps3_qos_adjust_pd_rsc(struct scsi_device *sdev, + struct ps3_instance *instance, S32 reason); + +void ps3_qos_vd_attr_change(struct ps3_instance *instance, + struct PS3VDEntry *vd_entry_old, struct PS3VDEntry *vd_entry); + +void ps3_qos_pd_rsc_init(struct ps3_qos_pd_mgr *qos_pd_mgr, struct ps3_pd_entry *pd_entry); + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,9,0) && LINUX_VERSION_CODE < KERNEL_VERSION(4,10,0)) +void ps3_linx80_vd_member_change(struct ps3_instance *instance, struct ps3_pd_entry *pd_entry); +#endif + +#endif diff --git a/drivers/scsi/ps3stor/ps3_r1x_write_lock.c b/drivers/scsi/ps3stor/ps3_r1x_write_lock.c new file mode 100644 index 0000000000000000000000000000000000000000..3dba5820cb36f6804aa402978c265ff4bb917f51 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_r1x_write_lock.c @@ -0,0 +1,1391 @@ +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include + +#endif +#include "ps3_err_def.h" +#include "ps3_driver_log.h" +#include "ps3_rb_tree.h" +#include "ps3_inner_data.h" +#include "ps3_meta.h" +#include "ps3_cmd_channel.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_instance_manager.h" +#include "ps3_platform_utils.h" +#include "ps3_driver_log.h" +#include "ps3_cmd_statistics.h" +#include "ps3_scsih.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_module_para.h" + +enum{ + PS3_CONFLICT_QUEUE_EMPTY = 0, + PS3_CONFLICT_QUEUE_CONFLICT = 1, + PS3_CONFLICT_QUEUE_NO_CONFLICT = 2, +}; + +#define PS3_R1X_RESEND_COUNT (32) + +#define LOCK_BLOCK_SIZE_SHIFT 3 +#define HASH_TABLE_SIZE_SHIFT 12 +#define HASH_TABLE_SIZE (1 << HASH_TABLE_SIZE_SHIFT) +#define HASH_TABLE_SIZE_MASK (HASH_TABLE_SIZE - 1) +#define SZBLOCK_SIZE_SHIFT 10 +#define SZBLOCK_SIZE ((U32)(1 << SZBLOCK_SIZE_SHIFT)) +#define SZBLOCK_SIZE_MASK (SZBLOCK_SIZE - 1) +#define VD_QUE_DEPTH 512 +#define CMD_SIZE_MAX 4096 + +#define PS3_R1X_BIT_CNT ((SZBLOCK_SIZE >> LOCK_BLOCK_SIZE_SHIFT) * HASH_TABLE_SIZE) +#define PS3_R1X_BIT_MAP_SIZE (PS3_R1X_BIT_CNT >> 3) + +#define SECTOR_SIZE_4K 4096 +#define SECTOR_512_4K_SHIFT 3 +#define SZ_BLOCK_SPLIT_MAX ((4096 >> SZBLOCK_SIZE_SHIFT) + 2) + +#define RW_R1X_HASHIDX(lba) (((lba) >> SZBLOCK_SIZE_SHIFT) & HASH_TABLE_SIZE_MASK) +#define RW_R1X_HASHIDX_HASH(mgr, lba) ps3_private_r1x_hash((mgr), ((lba) >> SZBLOCK_SIZE_SHIFT)) + +#define PS3_LBA(lba_hi, lba_lo) ((((U64)(lba_hi)) << PS3_SHIFT_DWORD) | (lba_lo)) + +#define PS3_SZ_BLOCK_CNT (2560) + +enum{ + PS3_R1X_IO_CONFLICT = 1, + PS3_R1X_HASH_CONFILICT = 2, + PS3_R1X_BIT_NOT_ENOUGH = 3, +}; + +#define PS3_R1X_LOCK_TRACE(fmt, ...) LOG_DEBUG(fmt "\n", ##__VA_ARGS__); +#define PS3_R1X_LOCK_INFO(fmt, ...) LOG_INFO(fmt "\n", ##__VA_ARGS__); +#define PS3_R1X_LOCK_WARN(fmt, ...) LOG_WARN(fmt "\n", ##__VA_ARGS__); +#define PS3_R1X_LOCK_ERROR(fmt, ...) LOG_ERROR(fmt "\n", ##__VA_ARGS__); + +#define PS3_R1X_TIMEOUT(cmd, tmo) (time_after(jiffies, \ + (cmd)->scmd->jiffies_at_alloc + (tmo))) + +U32 g_ps3_r1x_lock_flag = PS3_R1X_HASHRANGE_LOCK; +U32 g_ps3_r1x_lock_enable = 1; + +static S32 ps3_r1x_hash_bit_lock_of_conflict_queue( + struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd); + +#if PS3_DESC("-----------------------hash bit互斥方案------------------------") +#define LOCK_BLOCK_SIZE (1 << LOCK_BLOCK_SIZE_SHIFT) +#define LOCK_BLOCK_SIZE_MASK (LOCK_BLOCK_SIZE - 1) +#define RW_BIT_TO_BYTE(bit) ((bit) >> 3) +#define RW_BYTE_TO_BIT(byte) ((bit) << 3) +#define RW_BIT_BYTE_MASK 7 +#define RW_R1X_SZBLOCKIDX(lba) (lba >> SZBLOCK_SIZE_SHIFT) +#define RW_SZBLOCK_IDX_INVALUD 0xFFFFFFFFFFFF +#define RW_BITMAP_IDX_INVALUD 0xFFFF +#define RW_R1X_GET_BITMAP(bit_buff,idx) (bit_buff[idx]) +#define RW_BIT_64_MASK 63 +#define RW_BYTE_TO_U64(n) (n >> 3) + +struct ps3_r1x_hash_bit_item{ + U64 sz_block_idx : 48; + U64 bitmap_idx : 16; +}; + +struct ps3_r1x_bit_block_mgr +{ + U8* bit_buff; + U8 bit_block_size; + U8 resv[7]; +}; + +struct ps3_r1x_hash_bit_mgr{ + struct ps3_r1x_hash_bit_item hash_item[HASH_TABLE_SIZE]; + struct ps3_r1x_bit_block_mgr bitmap_mgr; +}; + +static U16 ps3_private_r1x_hash(struct ps3_r1x_lock_mgr *mgr, ULong hashval) +{ + ULong tmp; + tmp = (hashval * (ULong)mgr) ^ (GOLDEN_RATIO_PRIME + hashval) / + L1_CACHE_BYTES; + tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> HASH_TABLE_SIZE_SHIFT); + return tmp & HASH_TABLE_SIZE_MASK; +} + +static inline void ps3_r1x_conflict_queue_del(struct ps3_r1x_lock_mgr *mgr, + struct ps3_cmd *cmd) +{ + ULong flag = 0; + + if (cmd->is_inserted_c_q == 1) { + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + list_del(&cmd->cmd_list); + cmd->is_inserted_c_q = 0; + mgr->cmd_count_in_q--; + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + } +} + +void ps3_r1x_conflict_queue_clean(struct ps3_scsi_priv_data *pri_data, + S32 ret_code) +{ + ULong flag = 0; + + if(unlikely(pri_data == NULL) || pri_data->lock_mgr.hash_mgr == NULL) { + return; + } + + ps3_spin_lock_irqsave(&pri_data->lock_mgr.mgr_lock, &flag); + if (pri_data->lock_mgr.force_ret_code == SCSI_STATUS_GOOD) { + pri_data->lock_mgr.force_ret_code = ret_code; + complete(&pri_data->lock_mgr.thread_sync); + } + ps3_spin_unlock_irqrestore(&pri_data->lock_mgr.mgr_lock, flag); + + LOG_FILE_INFO("dev[%u:%u], wait r1x conflict queue clean begin\n", + PS3_CHANNEL(&pri_data->disk_pos), + PS3_TARGET(&pri_data->disk_pos)); + wmb(); + while (pri_data->lock_mgr.force_ret_code != SCSI_STATUS_GOOD) { + ps3_msleep(100); + rmb(); + } + LOG_FILE_INFO("dev[%u:%u], wait r1x conflict queue clean end\n", + PS3_CHANNEL(&pri_data->disk_pos), + PS3_TARGET(&pri_data->disk_pos)); +} + +void ps3_r1x_conflict_queue_target_reset(struct ps3_instance *instance, + U16 target_id) +{ + struct PS3ChannelInfo *channel_info = &instance->ctrl_info.channelInfo; + U8 i = 0; + struct ps3_scsi_priv_data *pri_data = NULL; + + for (i = 0; i < channel_info->channelNum; i++) { + if (channel_info->channels[i].channelType != PS3_DISK_TYPE_VD || + channel_info->channels[i].maxDevNum <= target_id) { + continue; + } + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + + pri_data = ps3_dev_mgr_lookup_vd_pri_data(instance, i, target_id); + ps3_r1x_conflict_queue_clean(pri_data, SCSI_STATUS_TASK_ABORTED); + + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + } +} + +void ps3_r1x_conflict_queue_clean_all(struct ps3_instance *instance, + S32 ret_code, Bool is_remove) +{ + struct PS3ChannelInfo *channel_info = &instance->ctrl_info.channelInfo; + U16 maxDevNum = 0; + U8 i = 0; + U16 j = 0; + struct ps3_scsi_priv_data *pri_data = NULL; + + for (i = 0; i < channel_info->channelNum; i++) { + if (channel_info->channels[i].channelType != PS3_DISK_TYPE_VD) { + continue; + } + maxDevNum = channel_info->channels[i].maxDevNum; + + for (j = 0; j < maxDevNum; j++) { + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + + pri_data = ps3_dev_mgr_lookup_vd_pri_data(instance, i, j); + if(unlikely(pri_data == NULL) || pri_data->lock_mgr.hash_mgr == NULL) { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + continue; + } + pri_data->lock_mgr.dev_deling = is_remove; + ps3_r1x_conflict_queue_clean(pri_data, ret_code); + + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + } + } +} + +Bool ps3_r1x_conflict_queue_abort(struct ps3_cmd *cmd, struct scsi_cmnd *scmd) +{ + Bool ret = PS3_TRUE; + struct ps3_scsi_priv_data *data = NULL; + + if (cmd->is_inserted_c_q == 0) { + ret = PS3_FALSE; + goto l_out; + } + + LOG_INFO("task abort cmd:%d is in conflict queue !\n", + cmd->index); + + data = (struct ps3_scsi_priv_data *)scmd->device->hostdata; + if(unlikely(data == NULL)){ + ret = PS3_FALSE; + goto l_out; + } + + cmd->is_r1x_aborting = 1; + complete(&data->lock_mgr.thread_sync); + + while (cmd->is_inserted_c_q == 1) { + ps3_msleep(100); + rmb(); + } + + if (cmd->is_r1x_aborting == 0) { + ret = PS3_TRUE; + while (cmd->cmd_state.state != PS3_CMD_STATE_INIT) { + ps3_msleep(10); + rmb(); + } + } else { + ret = PS3_FALSE; + } + LOG_INFO("task abort cmd:%d in conflict queue aborting ret:%d\n", + cmd->index, ret); + +l_out: + return ret; +} + +static void ps3_conflict_queue_clean_bitmap(struct ps3_r1x_hash_bit_mgr* mgr) +{ + U32 i = 0; + + LOG_FILE_INFO("ready clean conflict queue bitmap\n"); + + for (i = 0; i < HASH_TABLE_SIZE; i++) { + mgr->hash_item[i].sz_block_idx = RW_SZBLOCK_IDX_INVALUD; + } + + memset(mgr->bitmap_mgr.bit_buff, 0, PS3_R1X_BIT_MAP_SIZE); +} + +static void ps3_conflict_queue_return_all(struct ps3_r1x_lock_mgr *mgr) +{ + ULong flag = 0; + ps3_list_head conflict_cmd_list_tmp; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct scsi_cmnd *s_cmd = NULL; + S32 ret_result = SCSI_STATUS_GOOD; + + INIT_LIST_HEAD(&conflict_cmd_list_tmp); + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + + ret_result = mgr->force_ret_code; + + if (!list_empty(&mgr->conflict_cmd_list)) { + list_for_each_entry_safe(cmd, cmd_next, + &mgr->conflict_cmd_list, cmd_list) { + list_move_tail(&cmd->cmd_list, &conflict_cmd_list_tmp); + } + } + + ps3_conflict_queue_clean_bitmap((struct ps3_r1x_hash_bit_mgr*) + mgr->hash_mgr_conflict); + + mgr->cmd_count_in_q = 0; + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + list_for_each_entry_safe(cmd, cmd_next, + &conflict_cmd_list_tmp, cmd_list) { + + LOG_DEBUG("conflict queue cmd:%d t_id:0x%llx return:0x%x\n", + cmd->index, cmd->trace_id, ret_result); + + ps3_scsi_dma_unmap(cmd); + s_cmd = cmd->scmd; + PS3_IO_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + ps3_scsi_cmd_free(cmd); + s_cmd->result = ret_result; + SCMD_IO_DONE(s_cmd); + } + + if (ret_result != SCSI_STATUS_GOOD) { + mgr->force_ret_code = SCSI_STATUS_GOOD; + } +} + +static S32 ps3_conflict_queue_resend(struct ps3_instance *instance, + struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *pri_data = NULL; + struct scsi_cmnd *s_cmd = cmd->scmd; + static unsigned long j; + + ret = instance->ioc_adpter->io_cmd_build(cmd); + if (ret == -PS3_IO_CONFLICT_IN_Q) { + LOG_DEBUG("t_id:0x%llx hno:%u tag:%d cmd build err ret:%d\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, ret); + goto l_out; + } + + ps3_r1x_conflict_queue_del(mgr, cmd); + + if (ret == -PS3_IN_QOS_Q) { + ret = PS3_SUCCESS; + LOG_DEBUG("insert qos waitq. hno:%u t_id:0x%llx tag:%u\n", + PS3_HOST(instance), cmd->trace_id, cmd->index); + goto l_out; + } + + if (ret != PS3_SUCCESS) { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "t_id:0x%llx hno:%u tag:%d cmd build NOK ret:%d\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, ret); + goto l_cmd_release; + } + + ret = ps3_scsi_cmd_send(instance, cmd, PS3_TRUE); + if (unlikely(ret != PS3_SUCCESS)) { + if (ret == -PS3_RECOVERED || ret == -PS3_RETRY) { + ps3_errcode_to_scsi_status(instance, s_cmd, + SCSI_STATUS_BUSY, NULL, 0, cmd); + } else { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + } + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "t_id:0x%llx hno:%u tag:%d cmd send NOK ret:%d\n", + cmd->trace_id, PS3_HOST(instance), cmd->index, ret); + PS3_DEV_IO_START_ERR_INC(instance, cmd); + goto l_cmd_release; + } + + goto l_out; + +l_cmd_release: + if (cmd->is_got_r1x == 1) { + pri_data = (struct ps3_scsi_priv_data *)s_cmd->device->hostdata; + ps3_r1x_write_unlock(&pri_data->lock_mgr, cmd); + } +l_out: + return ret; +} + +static S32 ps3_conflict_queue_send_wk(void *data) +{ + struct scsi_device *sdev = (struct scsi_device *)data; + struct ps3_r1x_lock_mgr *mgr =&PS3_SDEV_PRI_DATA(sdev)->lock_mgr; + struct ps3_instance *instance = + (struct ps3_instance*)sdev->host->hostdata; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *cmd_next = NULL; + struct scsi_cmnd *s_cmd = NULL; + ULong flag = 0; + S32 ret = PS3_SUCCESS; + U32 cur_total_count = 0; + U32 cmd_count = 0; + U8 try_count = 0; + + LOG_INFO("hno:%u vd[%u:%u] conflict queue thread enter\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + + while (true) { + wait_for_completion_interruptible(&mgr->thread_sync); + if (mgr->thread_stop || kthread_should_stop()) { + LOG_INFO("hno:%u r1x conflict thread, ready stop\n", + PS3_HOST(instance)); + goto l_out; + } + + if (mgr->force_ret_code != SCSI_STATUS_GOOD) { + LOG_INFO("hno:%u r1x conflict thread, return all cmd with:0x%x\n", + PS3_HOST(instance), mgr->force_ret_code); + ps3_conflict_queue_return_all(mgr); + LOG_INFO("hno:%u r1x conflict thread, return all cmd with:0x%x end\n", + PS3_HOST(instance), mgr->force_ret_code); + continue; + } + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + cur_total_count = mgr->cmd_count_in_q; + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + cmd_count = 0; + try_count = 0; + + list_for_each_entry_safe(cmd, cmd_next, + &mgr->conflict_cmd_list, cmd_list) { + + if (cmd->is_r1x_aborting == 1) { + ps3_scsi_dma_unmap(cmd); + s_cmd = cmd->scmd; + cmd->is_r1x_aborting = 0; + wmb(); + ps3_r1x_conflict_queue_del(mgr, cmd); + PS3_IO_OUTSTAND_DEC(instance, s_cmd); + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + s_cmd->result = SCSI_STATUS_TASK_ABORTED; + SCMD_IO_DONE(s_cmd); + PS3_IJ_SLEEP(2000, PS3_ERR_IJ_R1X_ABORT); + ps3_scsi_cmd_free(cmd); + LOG_INFO("hno:%u cmd:%d out r1x conflict queue by abort\n", + PS3_HOST(instance), cmd->index); + continue; + } + + LOG_DEBUG("hno:%u cmd:%d t_id:0x%llx ready resend\n", + PS3_HOST(instance), cmd->index, cmd->trace_id); + ret = ps3_conflict_queue_resend(instance, mgr, cmd); + if (ret == PS3_SUCCESS) { + LOG_DEBUG("hno:%u cmd:%d t_id[%llx] out r1x conflict queue by send success\n", + PS3_HOST(instance), cmd->index, cmd->trace_id); + } else if(ret == -PS3_IO_CONFLICT_IN_Q) { + } else { + LOG_INFO("hno:%u cmd:%d tid:0x%llx out r1x conflict queue by send failed\n", + PS3_HOST(instance), cmd->index, cmd->trace_id); + ps3_scsi_dma_unmap(cmd); + s_cmd = cmd->scmd; + PS3_IO_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + ps3_scsi_cmd_free(cmd); + SCMD_IO_DONE(s_cmd); + } + LOG_DEBUG("hno:%u cmd:%d t_id:0x%llx resend ret:%d\n", + PS3_HOST(instance), cmd->index, cmd->trace_id, ret); + if (++cmd_count == cur_total_count) { + break; + } + + if (++try_count == PS3_R1X_RESEND_COUNT) { + cond_resched(); + try_count = 0; + } + } + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + if (list_empty(&mgr->conflict_cmd_list)) { + if (mgr->cmd_count_in_q != 0) { + LOG_INFO_LIM("cmd count in q not zero\n"); + PS3_BUG(); + } + ps3_conflict_queue_clean_bitmap( + (struct ps3_r1x_hash_bit_mgr*) + mgr->hash_mgr_conflict); + } + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + INJECT_START(PS3_ERR_IJ_R1X_CONFLICTQ_PROCESS_FINISH, instance); + } + +l_out: + LOG_FILE_INFO("hno:%u vd[%u:%u] conflict queue thread exit\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + + return 0; +} + +static inline void ps3_r1x_bitmap_set(struct ps3_r1x_hash_bit_mgr* pHashbitMgr, + U16 bitmap_idx, U32 bit_start, U32 bit_cnt) +{ + U32 i = 0; + ULong* addr = (ULong*)(void*)&RW_R1X_GET_BITMAP(pHashbitMgr->bitmap_mgr.bit_buff, bitmap_idx); + for(; i < bit_cnt; ++i){ + setBitNonAtomic(bit_start+i, addr); + } +} + +static inline void ps3_r1x_bitmap_clean(struct ps3_r1x_hash_bit_mgr* pHashbitMgr, + U16 bitmap_idx, U32 bit_start, U32 bit_cnt) +{ + U32 i = 0; + ULong* addr = (ULong*)(void*)&RW_R1X_GET_BITMAP(pHashbitMgr->bitmap_mgr.bit_buff, bitmap_idx); + for(; i < bit_cnt; ++i){ + clearBitNonAtomic(bit_start+i, addr); + } +} + +static inline S32 ps3_r1x_bitmap_check(struct ps3_r1x_hash_bit_mgr* pHashbitMgr, + U16 bitmap_idx, U32 bit_start, U32 bit_cnt) +{ + U32 i = 0; + ULong* addr = (ULong*)(void*)&RW_R1X_GET_BITMAP(pHashbitMgr->bitmap_mgr.bit_buff, bitmap_idx); + for(; i < bit_cnt; ++i){ + if(unlikely(testBitNonAtomic(bit_start+i, addr))){ + return -PS3_R1X_IO_CONFLICT; + } + } + return PS3_SUCCESS; +} + +static inline U32 calc_block_num(U64 lba, U32 len, U32 block_shift, U32 block_mask) +{ + U64 start_align = lba; + U32 block_num = 0; + U32 remain_len = 0; + + if (lba & block_mask) { + block_num += 1; + start_align = ((lba >> block_shift) + 1) << block_shift; + } + + if(start_align < lba + len){ + remain_len = len - ((U32)(start_align - lba)); + block_num += remain_len >> block_shift; + if(remain_len & block_mask){ + block_num += 1; + } + } + + return block_num; +} + +struct ps3_write_r1x_hash_tmp{ + struct ps3_r1x_hash_bit_item* hash_item; + U32 bit_start; + U32 bit_cnt; + Bool is_new; + U8 resv[7]; +}; + +S32 ps3_r1x_hash_bit_check(struct ps3_r1x_hash_bit_mgr* hash_mgr, + U64 lba, U32 len, + struct ps3_write_r1x_hash_tmp* hash_tmp, U16 hash_idx) +{ + U64 sz_block_idx = 0; + U32 offset = 0; + struct ps3_r1x_hash_bit_item* hash_item = NULL; + S32 ret = PS3_SUCCESS; + U32 bit_start = 0; + U32 bit_cnt = 0; + + hash_item = &hash_mgr->hash_item[hash_idx]; + sz_block_idx = RW_R1X_SZBLOCKIDX(lba); + offset = (U32)(lba & SZBLOCK_SIZE_MASK); + bit_start = offset >> LOCK_BLOCK_SIZE_SHIFT; + bit_cnt = calc_block_num(lba, len, LOCK_BLOCK_SIZE_SHIFT, LOCK_BLOCK_SIZE_MASK); + hash_tmp->hash_item = hash_item; + hash_tmp->is_new = PS3_FALSE; + hash_tmp->bit_start = bit_start; + hash_tmp->bit_cnt = bit_cnt; + + PS3_R1X_LOCK_TRACE("lba=%llu, len=%u, hash_idx=%u, hash item=%p, bit check.", + lba, len, hash_idx, hash_item); + if(hash_item->sz_block_idx == RW_SZBLOCK_IDX_INVALUD) { + hash_item->sz_block_idx = sz_block_idx; + hash_tmp->is_new = PS3_TRUE; + PS3_R1X_LOCK_TRACE("lba=%llu, len=%u, hash_idx=%u, bit_idx=%u, hash item=%p, new hash item.", + lba, len, hash_idx, (U16)hash_item->bitmap_idx, hash_item); + } else { + if(hash_item->sz_block_idx == sz_block_idx) { + ret = ps3_r1x_bitmap_check(hash_mgr,(U16)hash_item->bitmap_idx, bit_start, bit_cnt); + } else { + PS3_R1X_LOCK_TRACE("hash item=%p, oldSzBlock=%llu, newSzBlock=%llu, hash conflict.", + hash_item, (U64)hash_item->sz_block_idx, sz_block_idx); + ret = -PS3_R1X_HASH_CONFILICT; + } + } + + return ret; +} + +static Bool ps3_r1x_hash_bit_check_conflict_queue( + struct ps3_r1x_lock_mgr *mgr, U64 lba, U32 len, U32 left) +{ + Bool is_conflict = PS3_TRUE; + S32 ret = PS3_SUCCESS; + U32 i = 0; + U8 item_cnt = 0; + + struct ps3_write_r1x_hash_tmp* hash_tmp = NULL; + struct ps3_write_r1x_hash_tmp tmp_array[SZ_BLOCK_SPLIT_MAX]; + struct ps3_r1x_hash_bit_mgr* hash_mgr = + (struct ps3_r1x_hash_bit_mgr*)mgr->hash_mgr_conflict; + + LOG_DEBUG("lba=%llu, len=%u, left=%u, " + "check if conflict with conflict queue.\n", + lba, len, left); + + do{ + len = PS3_MIN(len, left); + ret = ps3_r1x_hash_bit_check(hash_mgr, lba, len, + &tmp_array[item_cnt], RW_R1X_HASHIDX(lba)); + item_cnt += 1; + if(PS3_SUCCESS != ret) { + is_conflict = PS3_TRUE; + goto exit_fail; + } + left -= len; + lba += len; + len = SZBLOCK_SIZE; + }while(left > 0); + + is_conflict = PS3_FALSE; + +exit_fail: + + for (i = 0; i < item_cnt; ++i) { + hash_tmp = &tmp_array[i]; + if (hash_tmp->is_new) { + hash_tmp->hash_item->sz_block_idx = + RW_SZBLOCK_IDX_INVALUD; + } + } + + return is_conflict; +} + +void ps3_r1x_conflict_queue_hash_bit_lock( + struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + U32 i = 0; + U8 item_cnt = 0; + U32 shift = 0; + U64 lba = 0; + U32 len = 0; + U32 left = 0; + + struct ps3_r1x_hash_bit_mgr* hash_mgr_conflict = + (struct ps3_r1x_hash_bit_mgr*)mgr->hash_mgr_conflict; + struct ps3_write_r1x_hash_tmp* hash_tmp = NULL; + struct ps3_write_r1x_hash_tmp tmp_array[SZ_BLOCK_SPLIT_MAX]; + + shift = cmd->io_attr.vd_entry->sectorSize != SECTOR_SIZE_4K ? + 0 : SECTOR_512_4K_SHIFT; + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo) << shift; + left = cmd->io_attr.num_blocks << shift; + len = SZBLOCK_SIZE - (lba & SZBLOCK_SIZE_MASK); + + do{ + len = PS3_MIN(len, left); + + hash_tmp = &tmp_array[item_cnt]; + hash_tmp->hash_item = &hash_mgr_conflict->hash_item[ + RW_R1X_HASHIDX(lba)]; + hash_tmp->hash_item->sz_block_idx = RW_R1X_SZBLOCKIDX(lba); + hash_tmp->is_new = PS3_TRUE; + hash_tmp->bit_start = ((U32)(lba & SZBLOCK_SIZE_MASK)) >> + LOCK_BLOCK_SIZE_SHIFT; + hash_tmp->bit_cnt = calc_block_num(lba, len, + LOCK_BLOCK_SIZE_SHIFT, LOCK_BLOCK_SIZE_MASK); + + item_cnt += 1; + left -= len; + lba += len; + len = SZBLOCK_SIZE; + } while(left > 0); + + for(i = 0; i < item_cnt; ++i){ + hash_tmp = &tmp_array[i]; + ps3_r1x_bitmap_set(hash_mgr_conflict, + (U16)hash_tmp->hash_item->bitmap_idx, + hash_tmp->bit_start, hash_tmp->bit_cnt); + } + + return; +} + +S32 ps3_r1x_hash_bit_lock(struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + U8 item_cnt = 0; + U8 item_cnt_conflict = 0; + U32 shift = 0; + U64 lba = 0; + U32 len = 0; + U32 left = 0; + struct ps3_r1x_hash_bit_mgr* hash_mgr = + (struct ps3_r1x_hash_bit_mgr*)mgr->hash_mgr; + struct ps3_r1x_hash_bit_mgr* hash_mgr_conflict = + (struct ps3_r1x_hash_bit_mgr*)mgr->hash_mgr_conflict; + struct ps3_write_r1x_hash_tmp* hash_tmp = NULL; + struct ps3_write_r1x_hash_tmp tmp_array[SZ_BLOCK_SPLIT_MAX]; + struct ps3_write_r1x_hash_tmp tmp_array_conflict[SZ_BLOCK_SPLIT_MAX]; + ULong flag = 0; + Bool is_conflict_q_empty = PS3_FALSE; + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, cmd=%p, try lock.\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, + cmd->io_attr.num_blocks, cmd); + + shift = cmd->io_attr.vd_entry->sectorSize != SECTOR_SIZE_4K ? + 0 : SECTOR_512_4K_SHIFT; + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo) << shift; + len = cmd->io_attr.num_blocks << shift; + left = len; + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + + if (mgr->dev_deling) { + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + ret = PS3_IO_CONFLICT; + goto l_out; + } + + is_conflict_q_empty = list_empty(&mgr->conflict_cmd_list); + + + len = SZBLOCK_SIZE - (lba & SZBLOCK_SIZE_MASK); + if (is_conflict_q_empty) { + do{ + PS3_BUG_ON(item_cnt >= SZ_BLOCK_SPLIT_MAX); + len = PS3_MIN(len, left); + ret = ps3_r1x_hash_bit_check(hash_mgr, lba, len, + &tmp_array[item_cnt], + RW_R1X_HASHIDX(lba)); + item_cnt += 1; + if(PS3_SUCCESS != ret) { + goto exit_fail; + } + left -= len; + lba += len; + len = SZBLOCK_SIZE; + } while(left > 0); + } else { + do{ + PS3_BUG_ON(item_cnt >= SZ_BLOCK_SPLIT_MAX); + len = PS3_MIN(len, left); + ret = ps3_r1x_hash_bit_check(hash_mgr, lba, len, + &tmp_array[item_cnt], + RW_R1X_HASHIDX(lba)); + item_cnt += 1; + if(PS3_SUCCESS != ret) { + goto exit_fail; + } + ret = ps3_r1x_hash_bit_check(hash_mgr_conflict, lba, len, + &tmp_array_conflict[item_cnt_conflict], + RW_R1X_HASHIDX(lba)); + item_cnt_conflict += 1; + if(PS3_SUCCESS != ret) { + goto exit_fail; + } + left -= len; + lba += len; + len = SZBLOCK_SIZE; + } while(left > 0); + + for(i = 0; i < item_cnt_conflict; ++i){ + hash_tmp = &tmp_array_conflict[i]; + if(PS3_TRUE == hash_tmp->is_new){ + hash_tmp->hash_item->sz_block_idx = + RW_SZBLOCK_IDX_INVALUD; + } + } + } + + for(i = 0; i < item_cnt; ++i){ + hash_tmp = &tmp_array[i]; + ps3_r1x_bitmap_set(hash_mgr, + (U16)hash_tmp->hash_item->bitmap_idx, + hash_tmp->bit_start, hash_tmp->bit_cnt); + } + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + cmd->szblock_cnt = item_cnt; + cmd->is_got_r1x = 1; + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, lock success.\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, + cmd->io_attr.num_blocks); + + ret = PS3_SUCCESS; + goto l_out; +exit_fail: + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, lock faild, ret=%d" + "(%d: io conflict, %d: hash conflict, %d: bitmap not enough).\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, + cmd->io_attr.num_blocks, ret, -PS3_R1X_IO_CONFLICT, + -PS3_R1X_HASH_CONFILICT,-PS3_R1X_BIT_NOT_ENOUGH); + + cmd->szblock_cnt = 0; + for(i = 0; i < item_cnt; ++i){ + hash_tmp = &tmp_array[i]; + if(PS3_TRUE == hash_tmp->is_new){ + hash_tmp->hash_item->sz_block_idx = + RW_SZBLOCK_IDX_INVALUD; + } + } + + for(i = 0; i < item_cnt_conflict; ++i){ + hash_tmp = &tmp_array_conflict[i]; + if(PS3_TRUE == hash_tmp->is_new){ + hash_tmp->hash_item->sz_block_idx = + RW_SZBLOCK_IDX_INVALUD; + } + } + + if (ps3_r1x_conflict_queue_support_query()) { + if (PS3_R1X_TIMEOUT(cmd, ps3_r1x_tmo_query())) { + list_add_tail(&cmd->cmd_list, &mgr->conflict_cmd_list); + + ps3_r1x_conflict_queue_hash_bit_lock(mgr, cmd); + cmd->is_inserted_c_q = 1; + mgr->cmd_count_in_q++; + + ret = -PS3_IO_CONFLICT_IN_Q; + } else { + if (is_conflict_q_empty) { + ret = -PS3_IO_REQUEUE; + } else { + ret = -PS3_IO_CONFLICT; + } + } + } else { + ret = -PS3_IO_CONFLICT; + } + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, lock faild, fanal ret=%d" + "(%d: conflict requeue, %d: conflict in queue, %d: conflict busy).\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, + cmd->io_attr.num_blocks, ret, -PS3_IO_REQUEUE, + -PS3_IO_CONFLICT_IN_Q, -PS3_IO_CONFLICT); +l_out: + + return ret; +} + +static S32 ps3_r1x_hash_bit_lock_of_conflict_queue(struct ps3_r1x_lock_mgr *mgr, + struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U32 i = 0; + U8 item_cnt = 0; + U32 shift = 0; + U64 lba = 0; + U32 len = 0; + U32 left = 0; + struct ps3_r1x_hash_bit_mgr* hash_mgr = (struct ps3_r1x_hash_bit_mgr*)mgr->hash_mgr; + struct ps3_write_r1x_hash_tmp* hash_tmp = NULL; + struct ps3_write_r1x_hash_tmp tmp_array[SZ_BLOCK_SPLIT_MAX]; + ULong flag = 0; + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, cmd=%p, try lock.\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks, cmd); + + shift = cmd->io_attr.vd_entry->sectorSize != SECTOR_SIZE_4K ? 0 : SECTOR_512_4K_SHIFT;; + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo) << shift;; + len = cmd->io_attr.num_blocks << shift; + left = len; + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + + len = SZBLOCK_SIZE - (lba & SZBLOCK_SIZE_MASK); + do{ + PS3_BUG_ON(item_cnt >= SZ_BLOCK_SPLIT_MAX); + len = PS3_MIN(len, left); + ret = ps3_r1x_hash_bit_check(hash_mgr, lba, len, + &tmp_array[item_cnt], RW_R1X_HASHIDX(lba)); + item_cnt += 1; + if(PS3_SUCCESS != ret) { + goto exit_fail; + } + left -= len; + lba += len; + len = SZBLOCK_SIZE; + }while(left > 0); + + for(i = 0; i < item_cnt; ++i){ + hash_tmp = &tmp_array[i]; + ps3_r1x_bitmap_set(hash_mgr, + (U16)hash_tmp->hash_item->bitmap_idx, hash_tmp->bit_start, + hash_tmp->bit_cnt); + } + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + cmd->szblock_cnt = item_cnt; + cmd->is_got_r1x = 1; + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, lock success.\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, + cmd->io_attr.num_blocks); + + return PS3_SUCCESS; + +exit_fail: + + for(i = 0; i < item_cnt; ++i){ + hash_tmp = &tmp_array[i]; + if(PS3_TRUE == hash_tmp->is_new){ + hash_tmp->hash_item->sz_block_idx = + RW_SZBLOCK_IDX_INVALUD; + } + } + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + cmd->szblock_cnt = 0; + ret = -PS3_IO_CONFLICT_IN_Q; + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, relock faild, ret=%d" + "(%d: io conflict, %d: hash conflict, %d: bitmap not enough).\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks,ret, + -PS3_R1X_IO_CONFLICT,-PS3_R1X_HASH_CONFILICT,-PS3_R1X_BIT_NOT_ENOUGH); + return ret; +} + +void ps3_r1x_hash_bit_unlock(struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + struct ps3_r1x_hash_bit_item* hash_item = NULL; + U32 bit_start = 0; + U32 bit_cnt = 0; + U64* bit_map = NULL; + U32 i = 0; + BOOL is_clean = PS3_TRUE; + U32 shift = 0; + U64 lba = 0; + U32 len = 0; + U32 left = 0; + U64 conflict_check_lba = 0; + U32 conflict_check_len = 0; + U32 conflict_check_left = 0; + struct ps3_r1x_hash_bit_mgr* hash_mgr = (struct ps3_r1x_hash_bit_mgr*)mgr->hash_mgr; + struct ps3_r1x_bit_block_mgr* bit_map_mgr = &hash_mgr->bitmap_mgr; + ULong flag = 0; + U8 ret_check = PS3_CONFLICT_QUEUE_EMPTY; + + PS3_R1X_LOCK_TRACE("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, cmd=%p, unlock.", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks, cmd); + + shift = cmd->io_attr.vd_entry->sectorSize != SECTOR_SIZE_4K ? 0 : SECTOR_512_4K_SHIFT; + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo) << shift; + left = cmd->io_attr.num_blocks << shift; + len = SZBLOCK_SIZE - (lba & SZBLOCK_SIZE_MASK); + + conflict_check_lba = lba; + conflict_check_len = len; + conflict_check_left = left; + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + do{ + hash_item = &hash_mgr->hash_item[RW_R1X_HASHIDX(lba)]; + len = PS3_MIN(len, left); + bit_start = (lba & SZBLOCK_SIZE_MASK) >> LOCK_BLOCK_SIZE_SHIFT; + bit_cnt = calc_block_num(lba, len, LOCK_BLOCK_SIZE_SHIFT, LOCK_BLOCK_SIZE_MASK); + ps3_r1x_bitmap_clean(hash_mgr, (U16)hash_item->bitmap_idx, bit_start, bit_cnt); + + is_clean = PS3_TRUE; + bit_map = (U64*)(void*)&RW_R1X_GET_BITMAP(bit_map_mgr->bit_buff, hash_item->bitmap_idx); + for(i = 0; i < bit_map_mgr->bit_block_size; ++i){ + if(bit_map[i] != 0){ + is_clean = PS3_FALSE; + } + } + + if(PS3_TRUE == is_clean){ + PS3_R1X_LOCK_TRACE("t_id:0x%llx lba=%llu, len=%u, szBlockIdx=%llu, bitIdx=%lu," + "szblock_cnt=%u, cmd=%p, release hash item.", + cmd->trace_id, lba, len, (U64)hash_item->sz_block_idx, + (unsigned long int)hash_item->bitmap_idx, + cmd->szblock_cnt, cmd); + hash_item->sz_block_idx = RW_SZBLOCK_IDX_INVALUD; + } + + left -= len; + lba += len; + len = SZBLOCK_SIZE; + }while(left > 0); + + if (!list_empty(&mgr->conflict_cmd_list)) { + if (ps3_r1x_hash_bit_check_conflict_queue(mgr, + conflict_check_lba, conflict_check_len, + conflict_check_left)) { + ret_check = PS3_CONFLICT_QUEUE_CONFLICT; + } else { + ret_check = PS3_CONFLICT_QUEUE_NO_CONFLICT; + } + } + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + if (ret_check != PS3_CONFLICT_QUEUE_EMPTY) { + LOG_FILE_INFO("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u," + " conflict queue check ret:%d.\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, + cmd->io_attr.num_blocks, ret_check); + + if (ret_check == PS3_CONFLICT_QUEUE_CONFLICT) { + complete(&mgr->thread_sync); + } + } + + return; +} + +static void* ps3_r1x_lock_hash_bit_init(struct ps3_instance *instance) +{ + U32 bit_map_size = 0; + U16 sz_block_bit_cnt = 0; + U16 bitmap_block_size = 0; + U16 bitmap_block_cnt = 0; + U32 total_size = 0; + struct ps3_r1x_hash_bit_mgr* mgr = NULL; + U8* buff = NULL; + U32 i = 0; + (void)instance; + (void)bitmap_block_cnt; + + if (SZBLOCK_SIZE & LOCK_BLOCK_SIZE_MASK) { + LOG_FILE_ERROR("hno: %u, SZBLOCK_SIZE check NOK\n", PS3_HOST(instance)); + goto exit; + } + bit_map_size = PS3_R1X_BIT_MAP_SIZE; + sz_block_bit_cnt = SZBLOCK_SIZE >> LOCK_BLOCK_SIZE_SHIFT; + if (sz_block_bit_cnt & RW_BIT_64_MASK) { + LOG_FILE_ERROR("hno: %u, sz_block_bit_cnt check NOK\n", PS3_HOST(instance)); + goto exit; + } + total_size = sizeof(struct ps3_r1x_hash_bit_mgr) + bit_map_size; + buff = (U8*)(void*)ps3_vzalloc(instance, total_size); + if(NULL == buff) { + PS3_R1X_LOCK_ERROR("r1x vd alloc write lock mgr faild. totoalSize=%u", total_size); + goto exit; + } + + bitmap_block_size = RW_BIT_TO_BYTE(sz_block_bit_cnt); + mgr = (struct ps3_r1x_hash_bit_mgr*)(void*)buff; + for (i = 0; i < HASH_TABLE_SIZE; ++i) { + mgr->hash_item[i].sz_block_idx = RW_SZBLOCK_IDX_INVALUD; + if (RW_BITMAP_IDX_INVALUD < (i * bitmap_block_size)) { + LOG_ERROR("hno: %u, bitmap_block_size check NOK\n", PS3_HOST(instance)); + PS3_BUG(); + ps3_vfree(instance, buff); + mgr = NULL; + goto exit; + } + mgr->hash_item[i].bitmap_idx = i*bitmap_block_size; + } + mgr->bitmap_mgr.bit_block_size = (U8)RW_BYTE_TO_U64(bitmap_block_size); + buff += sizeof(struct ps3_r1x_hash_bit_mgr); + mgr->bitmap_mgr.bit_buff = (U8*)(void*)buff; + buff += bit_map_size; + + LOG_FILE_INFO("r1x vd init write lock mgr success,totoalSize=%u, hashTableSize=%u, " + "bitmapSize=%u(bytes), bitmap_block_cnt=%u, bitmap_block_size=%u.\n", + total_size, HASH_TABLE_SIZE, + bit_map_size, bitmap_block_cnt, bitmap_block_size); + +exit: + return mgr; +} +#endif + +#if PS3_DESC("-----------------------hash range互斥方案------------------------") +struct ps3_renge_extent +{ + U64 start; + U64 end; +}; + +struct ps3_range_tree_node +{ + Ps3RbNode_s rbNode; + struct ps3_renge_extent extent; +}; + +struct ps3_range_tree_root +{ + Ps3RbRoot_s rbRoot; +}; + +struct ps3_r1x_hash_range_mgr +{ + struct ps3_range_tree_root hash_item[HASH_TABLE_SIZE]; +}; + +#define RANGETEE_EXTENT(rbNodePtr) ((ps3_container_of(rbNodePtr, struct ps3_range_tree_node, rbNode))->extent) + +S32 ps3_range_check_and_insert(struct ps3_range_tree_root *range_root, struct ps3_range_tree_node* range_node) +{ + S32 ret = PS3_SUCCESS; + Ps3RbNode_s *node = &range_node->rbNode; + Ps3RbNode_s *parent = NULL; + Ps3RbNode_s **pp_linker = NULL; + struct ps3_renge_extent* ext = &range_node->extent; + PS3_R1X_LOCK_TRACE("root=%p, rbNode=%p, lba=%llu, endLba=%llu, check.", range_root->rbRoot.pRoot, + node, ext->start, ext->end); + + pp_linker = &range_root->rbRoot.pRoot; + while (*pp_linker != NULL){ + parent = *pp_linker; + if (ext->start > RANGETEE_EXTENT(parent).end) { + pp_linker = &parent->pRight; + } else if (ext->end < RANGETEE_EXTENT(parent).start) { + pp_linker = &parent->pLeft; + } else { + ret = -PS3_R1X_IO_CONFLICT; + PS3_R1X_LOCK_TRACE("root=%p, rbNode=%p, lba=%llu, endLba=%llu, confilct.", range_root->rbRoot.pRoot, + node, ext->start, ext->end); + goto exit; + } + } + + node->pParentColor = ((uintptr_t)(void*)parent); + node->pLeft = NULL; + node->pRight = NULL; + (*pp_linker) = node; + ps3RbtColorAfterAdd(&range_root->rbRoot, node); + PS3_R1X_LOCK_TRACE("root=%p, rbNode=%p, lba=%llu, endLba=%llu, add.", range_root->rbRoot.pRoot, + node, ext->start, ext->end); + +exit: + return ret; +} + +static inline void ps3_range_del_node(struct ps3_range_tree_root *range_root, struct ps3_range_tree_node* del_node) +{ + PS3_R1X_LOCK_TRACE("root=%p, rbNode=%p, lba=%llu, endLba=%llu, del.", range_root->rbRoot.pRoot, + &del_node->rbNode, del_node->extent.start, del_node->extent.end); + if(unlikely(PS3_SUCCESS != ps3RbtDelNode(&range_root->rbRoot, &del_node->rbNode))){ + LOG_FILE_ERROR("startLba=%llu, endLba=%llu, del range node failed.\n", + del_node->extent.start, del_node->extent.end); + PS3_BUG(); + } +} + +S32 ps3_r1x_hash_range_lock(struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U64 hash_idx = 0; + U8 node_num = 0; + U32 shift = 0; + U64 lba = 0; + U32 len = 0; + U32 left = 0; + struct ps3_r1x_hash_range_mgr* hash_range_mgr = (struct ps3_r1x_hash_range_mgr*)mgr->hash_mgr; + struct ps3_range_tree_node* range_node = (struct ps3_range_tree_node*)cmd->node_buff; + struct ps3_range_tree_node* del_node = NULL; + ULong flag = 0; + + PS3_R1X_LOCK_TRACE("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, try lock.", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks); + + shift = cmd->io_attr.vd_entry->sectorSize != SECTOR_SIZE_4K ? 0 : SECTOR_512_4K_SHIFT;; + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo) << shift;; + len = cmd->io_attr.num_blocks << shift; + left = len; + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + + len = SZBLOCK_SIZE - (lba & SZBLOCK_SIZE_MASK); + do{ + range_node = &((struct ps3_range_tree_node*)cmd->node_buff)[node_num]; + len = PS3_MIN(len, left); + range_node->extent.start = lba; + range_node->extent.end = lba + len - 1; + ps3RbNodeInit(&range_node->rbNode); + hash_idx = RW_R1X_HASHIDX_HASH(mgr, lba); + + ret = ps3_range_check_and_insert(&hash_range_mgr->hash_item[hash_idx], range_node); + if(unlikely(PS3_SUCCESS != ret)){ + goto exit_fail; + } + + left -= len; + lba += len; + len = SZBLOCK_SIZE; + node_num++; + }while(left > 0); + + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + cmd->szblock_cnt = node_num; + cmd->is_got_r1x = 1; + + PS3_R1X_LOCK_TRACE("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, lock success.", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks); + return ret; + +exit_fail: + cmd->szblock_cnt = 0; + del_node = (struct ps3_range_tree_node*)cmd->node_buff; + for(; del_node != range_node; del_node++){ + hash_idx = RW_R1X_HASHIDX_HASH(mgr, del_node->extent.start); + ps3_range_del_node(&hash_range_mgr->hash_item[hash_idx], del_node); + } + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + LOG_DEBUG("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, io conflict, lock faild.\n", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks); + ret = -PS3_IO_REQUEUE; + return ret; +} + +void ps3_r1x_hash_range_unlock(struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + U32 i = 0; + U64 hash_idx = 0; + struct ps3_range_tree_node* range_node = NULL; + struct ps3_r1x_hash_range_mgr* hash_range_mgr = (struct ps3_r1x_hash_range_mgr*)mgr->hash_mgr; + ULong flag = 0; + + PS3_R1X_LOCK_TRACE("t_id:0x%llx lba_high=%u, lba_low=%u, len=%u, unlock.", + cmd->trace_id, cmd->io_attr.lba_hi, cmd->io_attr.lba_lo, cmd->io_attr.num_blocks); + + ps3_spin_lock_irqsave(&mgr->mgr_lock, &flag); + + for(i = 0; i < cmd->szblock_cnt; ++i){ + range_node = &((struct ps3_range_tree_node*)cmd->node_buff)[i]; + hash_idx = RW_R1X_HASHIDX_HASH(mgr, range_node->extent.start); + ps3_range_del_node(&hash_range_mgr->hash_item[hash_idx], range_node); + } + ps3_spin_unlock_irqrestore(&mgr->mgr_lock, flag); + + return; +} + +static void* ps3_r1x_hash_range_init(struct ps3_instance *instance) +{ + U32 total_size = 0; + U32 i = 0; + struct ps3_r1x_hash_range_mgr* mgr = NULL; + + total_size = sizeof(struct ps3_r1x_hash_range_mgr); + mgr = (struct ps3_r1x_hash_range_mgr*)(void*)ps3_vzalloc(instance, total_size); + if(NULL == mgr) { + PS3_R1X_LOCK_ERROR("r1x vd write lock alloc hash range mgr faild. totoalSize=%u", total_size); + goto exit; + } + + for(i = 0; i < HASH_TABLE_SIZE; ++i){ + mgr->hash_item[i].rbRoot.pRoot = NULL; + } + + LOG_FILE_INFO("r1x vd write lock init hash range mgr success." + "totoalSize=%u, hashTableSize=%u\n", + total_size, HASH_TABLE_SIZE); +exit: + return mgr; +} + +#endif + +#if PS3_DESC("-----------------------对外接口------------------------") + +U32 ps3_r1x_get_node_Buff_size(void) +{ + return sizeof(struct ps3_range_tree_node) * SZ_BLOCK_SPLIT_MAX; +} + +typedef S32 (*PS3_R1X_LOCK_FUNC)(struct ps3_r1x_lock_mgr*, void*); +typedef void (*PS3_R1X_UNLOCK_FUNC)(struct ps3_r1x_lock_mgr*, void*); + +S32 ps3_r1x_lock_prepare_for_vd(struct ps3_instance *instance, + struct scsi_device *sdev, U8 raid_level) +{ + S32 ret = PS3_SUCCESS; + struct ps3_r1x_lock_mgr *mgr =&PS3_SDEV_PRI_DATA(sdev)->lock_mgr; + + mgr->hash_mgr = NULL; + mgr->try_lock = NULL; + mgr->unlock = NULL; + + if(RAID1 != raid_level && RAID1E != raid_level && RAID10 != raid_level){ + goto exit; + } + + ps3_spin_lock_init(&mgr->mgr_lock); + + if (PS3_R1X_HASHBIT_LOCK == g_ps3_r1x_lock_flag) { + mgr->hash_mgr = ps3_r1x_lock_hash_bit_init(instance); + mgr->try_lock = (PS3_R1X_LOCK_FUNC)(void*)ps3_r1x_hash_bit_lock; + mgr->resend_try_lock = (PS3_R1X_LOCK_FUNC)(void*)ps3_r1x_hash_bit_lock_of_conflict_queue; + mgr->unlock = (PS3_R1X_UNLOCK_FUNC)(void*)ps3_r1x_hash_bit_unlock; + } else if(PS3_R1X_HASHRANGE_LOCK == g_ps3_r1x_lock_flag) { + LOG_DEBUG("hno:%u vd[%u:%u] use rb tree r1x\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + mgr->hash_mgr = ps3_r1x_hash_range_init(instance); + mgr->try_lock = (PS3_R1X_LOCK_FUNC)(void*)ps3_r1x_hash_range_lock; + mgr->resend_try_lock = (PS3_R1X_LOCK_FUNC)(void*)ps3_r1x_hash_range_lock; + mgr->unlock = (PS3_R1X_UNLOCK_FUNC)(void*)ps3_r1x_hash_range_unlock; + } + INJECT_START(PS3_ERR_IJ_FORCE_HASH_MGR_NULL, &mgr->hash_mgr); + if (unlikely(NULL == mgr->hash_mgr)) { + LOG_ERROR("hno:%u vd[%u:%u] r1x hash mgr init failed\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + goto l_err; + } + + mgr->hash_mgr_conflict = ps3_r1x_lock_hash_bit_init(instance); + INJECT_START(PS3_ERR_IJ_FORCE_MGR_CONFLICT_NULL, &mgr->hash_mgr_conflict); + if (unlikely(NULL == mgr->hash_mgr_conflict)) { + LOG_ERROR("hno:%u vd[%u:%u] r1x hash mgr conflict init failed\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + goto l_err; + } + + mgr->thread_stop = PS3_FALSE; + mgr->dev_deling = PS3_FALSE; + mgr->force_ret_code = SCSI_STATUS_GOOD; + + INIT_LIST_HEAD(&mgr->conflict_cmd_list); + mgr->cmd_count_in_q = 0; + init_completion(&mgr->thread_sync); + + mgr->conflict_send_th = kthread_run(ps3_conflict_queue_send_wk, sdev, "r1x_send"); + INJECT_START(PS3_ERR_IJ_FORCE_SEND_TH_NULL, mgr); + if (IS_ERR(mgr->conflict_send_th)) { + LOG_ERROR("hno:%u vd[%u:%u] r1x conflict send thread creat failed\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(sdev), + PS3_SDEV_TARGET(sdev)); + goto l_err; + } + + goto exit; +l_err: + ps3_r1x_lock_destory_for_vd(instance, mgr); + ret = -PS3_FAILED; +exit: + return ret; +} + +static S32 ps3_kthread_stop(struct ps3_instance *instance, + struct ps3_r1x_lock_mgr *mgr) +{ + S32 ret = PS3_SUCCESS; + + (void)instance; + mgr->thread_stop = PS3_TRUE; + complete(&mgr->thread_sync); + + LOG_FILE_INFO("hno:%u r1x conflict destory, begin stop\n", + PS3_HOST(instance)); + ret = kthread_stop(mgr->conflict_send_th); + LOG_FILE_INFO("hno:%u r1x conflict destory, stoped\n", + PS3_HOST(instance)); + + return ret; +} + +void ps3_r1x_lock_destory_for_vd(struct ps3_instance *instance, + struct ps3_r1x_lock_mgr *mgr) +{ + if (mgr->conflict_send_th != NULL) { + ps3_kthread_stop(instance, mgr); + } + + if(mgr->hash_mgr_conflict != NULL){ + ps3_vfree(instance, mgr->hash_mgr_conflict); + } + + if(mgr->hash_mgr != NULL){ + ps3_vfree(instance, mgr->hash_mgr); + } + mgr->hash_mgr = NULL; + mgr->try_lock = NULL; + mgr->unlock = NULL; + LOG_FILE_INFO("r1x vd deinit write lock mgr success."); + + return; +} + +#endif diff --git a/drivers/scsi/ps3stor/ps3_r1x_write_lock.h b/drivers/scsi/ps3stor/ps3_r1x_write_lock.h new file mode 100644 index 0000000000000000000000000000000000000000..e60d514de42f20772a8539292c0047547fcbdcaa --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_r1x_write_lock.h @@ -0,0 +1,65 @@ + +#ifndef __PS3_R1X_WRITE_LOCK_H__ +#define __PS3_R1X_WRITE_LOCK_H__ + +#include "ps3_types.h" +#include "ps3_cmd_channel.h" + +enum { + PS3_R1X_HASHBIT_LOCK = 0, + PS3_R1X_HASHRANGE_LOCK = 1, +}; + +extern U32 g_ps3_r1x_lock_flag; +extern U32 g_ps3_r1x_lock_enable; + +U32 ps3_r1x_get_node_Buff_size(void); + +static inline S32 ps3_r1x_write_lock(struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + if (mgr->hash_mgr == NULL) { + return PS3_SUCCESS; + } + + if (0 == g_ps3_r1x_lock_enable) { + return PS3_SUCCESS; + } + + if (!cmd->io_attr.is_confilct_check) { + return PS3_SUCCESS; + } + + if (cmd->is_inserted_c_q == 0) { + return mgr->try_lock(mgr, cmd); + } else { + return mgr->resend_try_lock(mgr, cmd); + } +} + +static inline void ps3_r1x_write_unlock(struct ps3_r1x_lock_mgr *mgr, struct ps3_cmd *cmd) +{ + if(cmd->szblock_cnt == 0){ + return; + } + mgr->unlock(mgr, cmd); + cmd->szblock_cnt = 0; +} + +S32 ps3_r1x_lock_prepare_for_vd(struct ps3_instance *instance, + struct scsi_device *sdev, U8 raid_level); + +void ps3_r1x_lock_destory_for_vd(struct ps3_instance *instance, + struct ps3_r1x_lock_mgr *mgr); + +void ps3_r1x_conflict_queue_clean(struct ps3_scsi_priv_data *pri_data, + S32 ret_code); + +Bool ps3_r1x_conflict_queue_abort(struct ps3_cmd *cmd, struct scsi_cmnd *scmd); + +void ps3_r1x_conflict_queue_target_reset(struct ps3_instance *instance, + U16 target_id); + +void ps3_r1x_conflict_queue_clean_all(struct ps3_instance *instance, + S32 ret_code, Bool is_remove); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_rb_tree.c b/drivers/scsi/ps3stor/ps3_rb_tree.c new file mode 100644 index 0000000000000000000000000000000000000000..1a515e1e1b4187a4a294e54e2690cee9dee8a7cc --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_rb_tree.c @@ -0,0 +1,731 @@ + +#include "ps3_rb_tree.h" + +static void rbtNodeSetParent(Ps3RbNode_s *pNode, + Ps3RbNode_s *pParent) +{ + pNode->pParentColor = + ((pNode->pParentColor & 3ULL) | ((uintptr_t)(void*)pParent)); +} + +static void rbtNodeSetColor(Ps3RbNode_s *pNode, U32 color) +{ + pNode->pParentColor = ((pNode->pParentColor & ~1ULL) | color); +} + +static void rbtRotateLeft(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode) +{ + Ps3RbNode_s *pRight = pNode->pRight; + Ps3RbNode_s *pParent = RBT_PARENT(pNode); + + pNode->pRight = pRight->pLeft; + if (NULL != pNode->pRight) + { + rbtNodeSetParent(pRight->pLeft, pNode); + } + + pRight->pLeft = pNode; + rbtNodeSetParent(pRight, pParent); + + if (NULL != pParent) + { + if (pNode == pParent->pLeft) + { + pParent->pLeft = pRight; + } + else + { + pParent->pRight = pRight; + } + } + else + { + pRoot->pRoot = pRight; + } + + rbtNodeSetParent(pNode, pRight); +} + +static void rbtRotateRight(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode) +{ + Ps3RbNode_s *pLeft = pNode->pLeft; + Ps3RbNode_s *pParent = RBT_PARENT(pNode); + + pNode->pLeft = pLeft->pRight; + if (NULL != pNode->pLeft) + { + rbtNodeSetParent(pLeft->pRight, pNode); + } + + pLeft->pRight = pNode; + rbtNodeSetParent(pLeft, pParent); + + if (NULL != pParent) + { + if (pNode == pParent->pRight) + { + pParent->pRight = pLeft; + } + else + { + pParent->pLeft = pLeft; + } + } + else + { + pRoot->pRoot = pLeft; + } + + rbtNodeSetParent(pNode, pLeft); +} + +static void rbtColorAfterDel(Ps3RbRoot_s *pRoot, + Ps3RbNode_s *pNode, Ps3RbNode_s *pParent) +{ + Ps3RbNode_s *pOther = NULL; + Ps3RbNode_s *pOLeft = NULL; + Ps3RbNode_s *pORight = NULL; + + while (((NULL == pNode) || RBT_IS_BLACK(pNode)) && + (pNode != pRoot->pRoot)) + { + if (pParent->pLeft == pNode) + { + pOther = pParent->pRight; + + if (RBT_IS_RED(pOther)) + { + RBT_SET_BLACK(pOther); + RBT_SET_RED(pParent); + rbtRotateLeft(pRoot, pParent); + pOther = pParent->pRight; + } + + if (((NULL == pOther->pLeft) || RBT_IS_BLACK(pOther->pLeft)) && + ((NULL == pOther->pRight) || RBT_IS_BLACK(pOther->pRight))) + { + RBT_SET_RED(pOther); + pNode = pParent; + pParent = RBT_PARENT(pNode); + + continue ; + } + + if ((NULL == pOther->pRight) || RBT_IS_BLACK(pOther->pRight)) + { + pOLeft = pOther->pLeft; + if (NULL != pOLeft) + { + RBT_SET_BLACK(pOLeft); + } + + RBT_SET_RED(pOther); + rbtRotateRight(pRoot, pOther); + pOther = pParent->pRight; + } + + rbtNodeSetColor(pOther, RBT_COLOR(pParent)); + RBT_SET_BLACK(pParent); + + if (NULL != pOther->pRight) + { + RBT_SET_BLACK(pOther->pRight); + } + + rbtRotateLeft(pRoot, pParent); + pNode = pRoot->pRoot; + + break; + } + + pOther = pParent->pLeft; + + if (RBT_IS_RED(pOther)) + { + RBT_SET_BLACK(pOther); + RBT_SET_RED(pParent); + + rbtRotateRight(pRoot, pParent); + pOther = pParent->pLeft; + } + + if (((NULL == pOther->pLeft) || RBT_IS_BLACK(pOther->pLeft)) && + ((NULL == pOther->pRight) || RBT_IS_BLACK(pOther->pRight))) + { + RBT_SET_RED(pOther); + pNode = pParent; + pParent = RBT_PARENT(pNode); + + continue ; + } + + if ((NULL == pOther->pLeft) || RBT_IS_BLACK(pOther->pLeft)) + { + pORight = pOther->pRight; + if (NULL != pORight) + { + RBT_SET_BLACK(pORight); + } + + RBT_SET_RED(pOther); + rbtRotateLeft(pRoot, pOther); + pOther = pParent->pLeft; + } + + rbtNodeSetColor(pOther, RBT_COLOR(pParent)); + RBT_SET_BLACK(pParent); + + if (NULL != pOther->pLeft) + { + RBT_SET_BLACK(pOther->pLeft); + } + + rbtRotateRight(pRoot, pParent); + pNode = pRoot->pRoot; + + break; + } + + if (NULL != pNode) + { + RBT_SET_BLACK(pNode); + } +} + +void rbtDelNodeDo(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode) +{ + Ps3RbNode_s *pParent = NULL; + Ps3RbNode_s *pChild = NULL; + Ps3RbNode_s *pOld = NULL; + U32 color = 0; + + if (NULL == pNode->pLeft) + { + pChild = pNode->pRight; + } + else if (NULL == pNode->pRight) + { + pChild = pNode->pLeft; + } + else + { + pOld = pNode; + + pNode = pNode->pRight; + while (NULL != pNode->pLeft) + { + pNode = pNode->pLeft; + } + + pChild = pNode->pRight; + pParent = RBT_PARENT(pNode); + color = RBT_COLOR(pNode); + + if (NULL != pChild) + { + rbtNodeSetParent(pChild, pParent); + } + + if (pParent == pOld) + { + pParent->pRight = pChild; + pParent = pNode; + } + else + { + pParent->pLeft = pChild; + } + + pNode->pParentColor = pOld->pParentColor; + pNode->pRight = pOld->pRight; + pNode->pLeft = pOld->pLeft; + + if (NULL != RBT_PARENT(pOld)) + { + if (RBT_PARENT(pOld)->pLeft == pOld) + { + RBT_PARENT(pOld)->pLeft = pNode; + } + else + { + RBT_PARENT(pOld)->pRight = pNode; + } + } + else + { + pRoot->pRoot = pNode; + } + + rbtNodeSetParent(pOld->pLeft, pNode); + if (NULL != pOld->pRight) + { + rbtNodeSetParent(pOld->pRight, pNode); + } + + goto l_color; + } + + pParent = RBT_PARENT(pNode); + color = RBT_COLOR(pNode); + + if (NULL != pChild) + { + rbtNodeSetParent(pChild, pParent); + } + + if (NULL != pParent) + { + if (pParent->pLeft == pNode) + { + pParent->pLeft = pChild; + } + else + { + pParent->pRight = pChild; + } + } + else + { + pRoot->pRoot = pChild; + } + +l_color: + if (color == RBT_BLACK) + { + rbtColorAfterDel(pRoot, pChild, pParent); + } +} + +static Ps3RbNode_s* rbtFindNodeDo(Ps3RbRoot_s *pRoot, void *pKey, + Ps3RbTreeOps_s *pOps, Bool intent_addnode, Ps3RbNode_s **ppParent, + Ps3RbNode_s ***pppLinker) +{ + Ps3RbNode_s *pNode = NULL; + Ps3RbNode_s *pParent = NULL; + Ps3RbNode_s **ppLinker = NULL; + void *pKeyCur = NULL; + Ps3Cmp_e cmprc = PS3_EQ; + + BUG_ON(NULL == pOps->cmpkey); + BUG_ON((NULL == pOps->getkey) && + (!testBitNonAtomic(RBTBF_KEYOFFSET_ENABLE, (volatile ULong *)&pOps->flags))); + + ppLinker = &pRoot->pRoot; + while (NULL != (*ppLinker)) + { + pParent = (*ppLinker); + + pKeyCur = ps3RbNodeGetKey(pParent, pOps); + cmprc = pOps->cmpkey(pKey, pKeyCur); + if (PS3_LT == cmprc) + { + ppLinker = &pParent->pLeft; + } + else if (PS3_GT == cmprc) + { + ppLinker = &pParent->pRight; + } + else if ((PS3_TRUE == intent_addnode) && + testBitNonAtomic(RBTBF_CONFLICT_ENABLE, (volatile ULong *)&pOps->flags)) + { + ppLinker = &pParent->pLeft; + } + else + { + pNode = pParent; + break ; + } + } + + if (NULL != pppLinker) + { + (*pppLinker) = ppLinker; + } + + if (NULL != ppParent) + { + if (NULL != pNode) + { + (*ppParent) = RBT_PARENT(pNode); + } + else + { + (*ppParent) = pParent; + } + } + + return pNode; +} + +void ps3RbtColorAfterAdd(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode) +{ + Ps3RbNode_s *pGparent = NULL; + Ps3RbNode_s *pParent = NULL; + Ps3RbNode_s *pUncle = NULL; + Ps3RbNode_s *pTmp = NULL; + + while (1) + { + pParent = RBT_PARENT(pNode); + if ((NULL == pParent) || RBT_IS_BLACK(pParent)) + { + break ; + } + + pGparent = RBT_PARENT(pParent); + if (pParent == pGparent->pLeft) + { + pUncle = pGparent->pRight; + if ((NULL != pUncle) && RBT_IS_RED(pUncle)) + { + RBT_SET_BLACK(pUncle); + RBT_SET_BLACK(pParent); + RBT_SET_RED(pGparent); + + pNode = pGparent; + continue ; + } + + if (pParent->pRight == pNode) + { + rbtRotateLeft(pRoot, pParent); + + pTmp = pParent; + pParent = pNode; + pNode = pTmp; + } + + RBT_SET_BLACK(pParent); + RBT_SET_RED(pGparent); + rbtRotateRight(pRoot, pGparent); + } + else + { + pUncle = pGparent->pLeft; + if ((NULL != pUncle) && RBT_IS_RED(pUncle)) + { + RBT_SET_BLACK(pUncle); + RBT_SET_BLACK(pParent); + RBT_SET_RED(pGparent); + + pNode = pGparent; + continue ; + } + + if (pParent->pLeft == pNode) + { + rbtRotateRight(pRoot, pParent); + + pTmp = pParent; + pParent = pNode; + pNode = pTmp; + } + + RBT_SET_BLACK(pParent); + RBT_SET_RED(pGparent); + rbtRotateLeft(pRoot, pGparent); + } + } + + RBT_SET_BLACK(pRoot->pRoot); +} + +Ps3RbNode_s* ps3RbtHeadNode(Ps3RbRoot_s *pRoot) +{ + Ps3RbNode_s *pNode = NULL; + + pNode = pRoot->pRoot; + if (NULL == pNode) + { + goto end; + } + + while (NULL != pNode->pLeft) + { + pNode = pNode->pLeft; + } + +end: + return pNode; +} + +Ps3RbNode_s* ps3RbtTailNode(Ps3RbRoot_s *pRoot) +{ + Ps3RbNode_s *pNode = NULL; + + pNode = pRoot->pRoot; + if (NULL == pNode) + { + goto end; + } + + while (NULL != pNode->pRight) + { + pNode = pNode->pRight; + } + +end: + return pNode; +} + +Ps3RbNode_s* ps3RbtPrevNode(Ps3RbNode_s *pNode) +{ + Ps3RbNode_s *pParent = NULL; + + if (NULL == pNode) + { + goto end; + } + + if (NULL != pNode->pLeft) + { + pNode = pNode->pLeft; + while (NULL != pNode->pRight) + { + pNode = pNode->pRight; + } + + return pNode; + } + + while (1) + { + pParent = RBT_PARENT(pNode); + if ((NULL == pParent) || (pNode != pParent->pLeft)) + { + goto end; + } + + pNode = pParent; + } + +end: + return pParent; +} + +Ps3RbNode_s* ps3RbtNextNode(Ps3RbNode_s *pNode) +{ + Ps3RbNode_s *pParent = NULL; + + if (NULL == pNode) + { + goto end; + } + + if (NULL != pNode->pRight) + { + pNode = pNode->pRight; + while (NULL != pNode->pLeft) + { + pNode = pNode->pLeft; + } + + return pNode; + } + + while (1) + { + pParent = RBT_PARENT(pNode); + if ((NULL == pParent) || (pNode != pParent->pRight)) + { + goto end; + } + + pNode = pParent; + } + +end: + return pParent; +} + +void ps3RbtReplaceNode(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNew, + Ps3RbNode_s *pVictim) +{ + Ps3RbNode_s *pParent = RBT_PARENT(pVictim); + + if (NULL != pParent) + { + if (pVictim == pParent->pLeft) + { + pParent->pLeft = pNew; + } + else + { + pParent->pRight = pNew; + } + } + else + { + pRoot->pRoot = pNew; + } + + if (NULL != pVictim->pLeft) + { + rbtNodeSetParent(pVictim->pLeft, pNew); + } + + if (NULL != pVictim->pRight) + { + rbtNodeSetParent(pVictim->pRight, pNew); + } + + (*pNew) = (*pVictim); +} + +S32 ps3RbtDelNode(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode) +{ + S32 rc = 0; + + if (RBT_NODE_IS_EMPTY(pNode)) + { + rc = -PS3_FAILED; + goto end; + } + + rbtDelNodeDo(pRoot, pNode); + ps3RbNodeInit(pNode); + +end: + return rc; +} + +S32 ps3RbtAddNode(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode, + Ps3RbTreeOps_s *pOps) +{ + Ps3RbNode_s *pParent = NULL; + Ps3RbNode_s **ppLinker = NULL; + void *pKey = NULL; + S32 rc = 0; + + BUG_ON((NULL == pOps->getkey) && + (!testBitNonAtomic(RBTBF_KEYOFFSET_ENABLE, (volatile ULong *)&pOps->flags))); + + if (!RBT_NODE_IS_EMPTY(pNode)) + { + rc = -PS3_FAILED; + goto end; + } + + pKey = ps3RbNodeGetKey(pNode, pOps); + if (NULL != rbtFindNodeDo(pRoot, pKey, pOps, PS3_TRUE, &pParent, + &ppLinker)) + { + rc = -PS3_FAILED; + goto end; + } + + ps3RbNodeLink(pNode, pParent, ppLinker); + ps3RbtColorAfterAdd(pRoot, pNode); + +end: + return rc; +} + +Ps3RbNode_s* ps3RbtFindNode(Ps3RbRoot_s *pRoot, void *pKey, + Ps3RbTreeOps_s *pOps) +{ + Ps3RbNode_s *pNode = NULL; + + if (NULL == pKey) + { + pNode = ps3RbtHeadNode(pRoot); + goto end; + } + + pNode = rbtFindNodeDo(pRoot, pKey, pOps, PS3_FALSE, NULL, NULL); + +end: + return pNode; +} + +Ps3RbNode_s* ps3RbtFindNextNode(Ps3RbRoot_s *pRoot, void *pKey, + Ps3RbTreeOps_s *pOps) +{ + Ps3RbNode_s *pNode = NULL; + Ps3RbNode_s *pParent = NULL; + Ps3RbNode_s **ppLinker = NULL; + void *pKeyCur = NULL; + + if (NULL == pKey) + { + pNode = ps3RbtHeadNode(pRoot); + goto end; + } + + pNode = rbtFindNodeDo(pRoot, pKey, pOps, PS3_FALSE, &pParent, + &ppLinker); + if (NULL != pNode) + { + pNode = ps3RbtNextNode(pNode); + + if (!testBitNonAtomic(RBTBF_CONFLICT_ENABLE, (volatile ULong *)&pOps->flags)) + { + goto end; + } + + while (NULL != pNode) + { + pKeyCur = ps3RbNodeGetKey(pNode, pOps); + if (PS3_EQ != pOps->cmpkey(pKey, pKeyCur)) + { + break; + } + + pNode = ps3RbtNextNode(pNode); + } + + goto end; + } + + if (NULL == pParent) + { + goto end; + } + + if (ppLinker == &pParent->pLeft) + { + pNode = pParent; + goto end; + } + + pNode = ps3RbtNextNode(pParent); + +end: + return pNode; +} + +void ps3RbtClean(Ps3RbRoot_s *pRoot) +{ + Ps3RbNode_s *pNode = NULL; + + pNode = ps3RbtHeadNode(pRoot); + while (NULL != pNode) + { + (void)ps3RbtDelNode(pRoot, pNode); + + pNode = ps3RbtHeadNode(pRoot); + } +} + +S32 ps3RbtTraverse(Ps3RbRoot_s *pRoot, ps3RbtreeVisitFunc visit, + void *p_ctxt) +{ + Ps3RbNode_s *pNode = NULL; + Ps3RbNode_s *pNext = NULL; + S32 rc = 0; + + BUG_ON(NULL == visit); + + RBT_FOR_EACH_SAFE(pNode, pNext, pRoot) + { + rc = visit(pNode, p_ctxt); + if (rc < 0) + { + goto end; + } + } + +end: + return rc; +} + diff --git a/drivers/scsi/ps3stor/ps3_rb_tree.h b/drivers/scsi/ps3stor/ps3_rb_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..44697aad58509ced8d80798f2d2b5671d22d2a8a --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_rb_tree.h @@ -0,0 +1,341 @@ + +#ifndef __PS3_RBTREE_H__ +#define __PS3_RBTREE_H__ + +#ifndef _WINDOWS +#include +#include +#endif + +#include "ps3_driver_log.h" +#include "ps3_define.h" +#include "ps3_err_def.h" + +static inline void setBitNonAtomic(U32 nr, volatile ULong *addr) +{ + ULong mask = BIT_MASK(nr); + ULong *p = ((ULong *)addr) + BIT_WORD(nr); + + *p |= mask; +} + +static inline void clearBitNonAtomic(U32 nr, volatile ULong *addr) +{ + ULong mask = BIT_MASK(nr); + ULong *p = ((ULong *)addr) + BIT_WORD(nr); + + *p &= ~mask; +} + +static inline S32 testBitNonAtomic(U32 nr, const volatile ULong *addr) +{ + return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); +} + + +typedef struct Ps3RbNode +{ + __attribute__((__aligned__(8))) + U64 pParentColor; + + struct + { + struct Ps3RbNode *pLeft; + struct Ps3RbNode *pRight; + }; +} Ps3RbNode_s; + +typedef struct Ps3RbRoot +{ + Ps3RbNode_s *pRoot; +} Ps3RbRoot_s; + +#define PS3_RBROOT_INITNIL {NULL} + +typedef enum Ps3Cmp +{ + PS3_EQ = 0, + PS3_GT = 1, + PS3_LT = 2, + PS3_CMPNR = 3, +} Ps3Cmp_e; + +typedef Ps3Cmp_e (*ps3CmpKeyFunc)(void *pKey1, void *pKey2); + +typedef void* (*ps3RbtreeGetKeyFunc)(Ps3RbNode_s *pNode, void *pCtxt); + +typedef S32 (*ps3RbtreeVisitFunc)(Ps3RbNode_s *pNode, void *pCtxt); + +typedef enum Ps3RbtreebFlag +{ + RBTBF_KEYOFFSET_ENABLE = 0, + RBTBF_CONFLICT_ENABLE, +} Ps3RbtreebFlag_e; + +typedef struct Ps3RbTreeOps +{ + ps3CmpKeyFunc cmpkey; + + union + { + ps3RbtreeGetKeyFunc getkey; + U64 keyoffset; + }; + + U32 flags; + void *pCtxt; +} Ps3RbTreeOps_s; + +typedef struct Ps3RbTree +{ + Ps3RbRoot_s root; + U32 nodenr; + Ps3RbTreeOps_s ops; +} Ps3RbTree_s; + +static inline void ps3RbNodeInit(Ps3RbNode_s *pNode) +{ + pNode->pParentColor = ((uintptr_t)(void*)pNode); +} + +static inline void ps3RbNodeLink(Ps3RbNode_s *pNode, + Ps3RbNode_s *pParent, Ps3RbNode_s **ppLinker) +{ + pNode->pParentColor = ((uintptr_t)(void*)pParent); + pNode->pLeft = NULL; + pNode->pRight = NULL; + + (*ppLinker) = pNode; +} + +static inline void* ps3RbNodeGetKey(Ps3RbNode_s *pNode, + Ps3RbTreeOps_s *pOps) +{ + if (testBitNonAtomic(RBTBF_KEYOFFSET_ENABLE, (volatile ULong *)&pOps->flags)) + { + return (void *)((U8 *)pNode + pOps->keyoffset); + } + + return pOps->getkey(pNode, pOps->pCtxt); +} + +static inline void ps3RbRootInit(Ps3RbRoot_s *pRoot) +{ + pRoot->pRoot = NULL; +} + +static inline void ps3RbRootFini(Ps3RbRoot_s *pRoot) +{ + BUG_ON(pRoot->pRoot != NULL); +} + +void ps3RbtColorAfterAdd(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode); + +Ps3RbNode_s* ps3RbtHeadNode(Ps3RbRoot_s *pRoot); + +Ps3RbNode_s* ps3RbtTailNode(Ps3RbRoot_s *pRoot); + +Ps3RbNode_s* ps3RbtPrevNode(Ps3RbNode_s *pNode); + +Ps3RbNode_s* ps3RbtNextNode(Ps3RbNode_s *pNode); + +void ps3RbtReplaceNode(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNew, + Ps3RbNode_s *pVictim); + +S32 ps3RbtDelNode(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode); + +S32 ps3RbtAddNode(Ps3RbRoot_s *pRoot, Ps3RbNode_s *pNode, + Ps3RbTreeOps_s *pOps); + +Ps3RbNode_s* ps3RbtFindNode(Ps3RbRoot_s *pRoot, void *pKey, + Ps3RbTreeOps_s *pOps); + +Ps3RbNode_s* ps3RbtFindNextNode(Ps3RbRoot_s *pRoot, void *pKey, + Ps3RbTreeOps_s *pOps); + +void ps3RbtClean(Ps3RbRoot_s *pRoot); + +S32 ps3RbtTraverse(Ps3RbRoot_s *pRoot, ps3RbtreeVisitFunc visit, + void *pCtxt); + +static inline Bool ps3RbtIsEmpty(Ps3RbRoot_s *pRoot) +{ + return (Bool)(pRoot->pRoot == NULL); +} + +static inline S32 ps3RbTreeInit(Ps3RbTree_s *pTree, + Ps3RbTreeOps_s *pOps) +{ + S32 rc = 0; + + ps3RbRootInit(&pTree->root); + pTree->nodenr = 0; + + memset(&pTree->ops, 0, sizeof(Ps3RbTreeOps_s)); + if (NULL != pOps) + { + pTree->ops = (*pOps); + } + + return rc; +} + +static inline S32 ps3RbTreeInitGetKey(Ps3RbTree_s *pTree, + ps3CmpKeyFunc cmpkey, ps3RbtreeGetKeyFunc getkey, void *pCtxt) +{ + Ps3RbTreeOps_s ops; + + memset(&ops, 0, sizeof(Ps3RbTreeOps_s)); + ops.cmpkey = cmpkey; + ops.getkey = getkey; + ops.pCtxt = pCtxt; + + return ps3RbTreeInit(pTree, &ops); +} + +static inline S32 ps3RbTreeInitKeyOffset(Ps3RbTree_s *pTree, + ps3CmpKeyFunc cmpkey, U64 keyoffset, void *pCtxt) +{ + Ps3RbTreeOps_s ops; + + memset(&ops, 0, sizeof(Ps3RbTreeOps_s)); + ops.cmpkey = cmpkey; + ops.keyoffset = keyoffset; + ops.pCtxt = pCtxt; + setBitNonAtomic(RBTBF_KEYOFFSET_ENABLE, (volatile ULong *)&ops.flags); + + return ps3RbTreeInit(pTree, &ops); +} + +static inline void ps3RbTreeFini(Ps3RbTree_s *pTree) +{ + BUG_ON(pTree->nodenr != 0); + ps3RbRootFini(&pTree->root); +} + +static inline Ps3RbNode_s* ps3RbTreeHeadNode(Ps3RbTree_s *pTree) +{ + return ps3RbtHeadNode(&pTree->root); +} + +static inline Ps3RbNode_s* ps3RbTreeTailNode(Ps3RbTree_s *pTree) +{ + return ps3RbtTailNode(&pTree->root); +} + +static inline Ps3RbNode_s* ps3RbTreePrevNode(Ps3RbNode_s *pNode) +{ + return ps3RbtPrevNode(pNode); +} + +static inline Ps3RbNode_s* ps3RbTreeNextNode(Ps3RbNode_s *pNode) +{ + return ps3RbtNextNode(pNode); +} + +static inline void ps3RbTreeReplaceNode(Ps3RbTree_s *pTree, + Ps3RbNode_s *pNew, Ps3RbNode_s *pVictim) +{ + ps3RbtReplaceNode(&pTree->root, pNew, pVictim); +} + +static inline S32 ps3RbTreeDelNode(Ps3RbTree_s *pTree, + Ps3RbNode_s *pNode) +{ + S32 rc = 0; + + rc = ps3RbtDelNode(&pTree->root, pNode); + if (rc >= 0) + { + pTree->nodenr--; + } + + return rc; +} + +static inline S32 ps3RbTreeAddNode(Ps3RbTree_s *pTree, + Ps3RbNode_s *pNode) +{ + S32 rc = 0; + + rc = ps3RbtAddNode(&pTree->root, pNode, &pTree->ops); + if (rc >= 0) + { + pTree->nodenr++; + } + + return rc; +} + +static inline Ps3RbNode_s* ps3RbTreeFindNode(Ps3RbTree_s *pTree, + void *pKey) +{ + return ps3RbtFindNode(&pTree->root, pKey, &pTree->ops); +} + +static inline Ps3RbNode_s* ps3RbTreeFindNextNode(Ps3RbTree_s *pTree, + void *pKey) +{ + return ps3RbtFindNextNode(&pTree->root, pKey, &pTree->ops); +} + +static inline void ps3RbTreeClean(Ps3RbTree_s *pTree) +{ + ps3RbtClean(&pTree->root); + pTree->nodenr = 0; +} + +static inline S32 ps3RbTreeTraverse(Ps3RbTree_s *pTree, + ps3RbtreeVisitFunc visit, void *pCtxt) +{ + return ps3RbtTraverse(&pTree->root, visit, pCtxt); +} + +static inline Bool ps3RbTreeIsEmpty(Ps3RbTree_s *pTree) +{ + return (Bool)(pTree->root.pRoot == NULL); +} + +static inline U32 ps3RbTreeNodeNr(Ps3RbTree_s *pTree) +{ + return pTree->nodenr; +} + +#define RBT_RED (0) +#define RBT_BLACK (1) + +#define RBT_PARENT(_n) ((Ps3RbNode_s*)(uintptr_t)((_n)->pParentColor & ~3ULL)) +#define RBT_COLOR(_n) ((_n)->pParentColor & 1ULL) + +#define RBT_IS_RED(_n) (!RBT_COLOR(_n)) +#define RBT_IS_BLACK(_n) RBT_COLOR(_n) +#define RBT_SET_RED(_n) \ + do { (_n)->pParentColor &= ~1ULL; } while (0) +#define RBT_SET_BLACK(_n) \ + do { (_n)->pParentColor |= 1ULL; } while (0) + +#define RBT_ROOT_IS_EMPTY(_r) ((_r)->pRoot == NULL) +#define RBT_TREE_IS_EMPTY(_t) RBT_ROOT_IS_EMPTY(&(_t)->root) +#define RBT_NODE_IS_EMPTY(_n) (RBT_PARENT(_n) == (_n)) +#define RBT_NODE_CLEAR(_n) do { ps3RbNodeInit(_n); } while (0) + +#define RBT_FOR_EACH(_p_node, _p_root) \ + for (_p_node = ps3RbtHeadNode(_p_root); \ + _p_node != NULL; \ + _p_node = ps3RbtNextNode(_p_node)) + +#define RBT_FOR_EACH_SAFE(_p_node, _p_next, _p_root) \ + for (_p_node = ps3RbtHeadNode(_p_root), \ + _p_next = ps3RbtNextNode(_p_node); \ + _p_node != NULL; \ + _p_node = _p_next, \ + _p_next = ps3RbtNextNode(_p_node)) + +#define RBTREE_FOR_EACH(_p_node, _p_tree) \ + RBT_FOR_EACH((_p_node), &(_p_tree)->root) + +#define RBTREE_FOR_EACH_SAFE(_p_node, _p_next, _p_tree) \ + RBT_FOR_EACH_SAFE((_p_node), (_p_next), &(_p_tree)->root) + +#endif + diff --git a/drivers/scsi/ps3stor/ps3_recovery.c b/drivers/scsi/ps3stor/ps3_recovery.c new file mode 100644 index 0000000000000000000000000000000000000000..ab5bc3bbabac6ba1c838142233e107a2b21b087e --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_recovery.c @@ -0,0 +1,3576 @@ + +#include "ps3_recovery.h" + +#ifndef _WINDOWS + +#include +#endif +#include "ps3_recovery.h" +#include "ps3_ioc_state.h" +#include "ps3_event.h" +#include "ps3_mgr_channel.h" +#include "ps3_cmd_complete.h" +#include "ps3_device_update.h" +#include "ps3_ioc_manager.h" +#include "ps3_mgr_cmd.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_scsih.h" +#include "ps3_cmd_statistics.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_ioc_state.h" +#include "ps3_module_para.h" +#include "ps3_err_inject.h" +#include "ps3_ioctl.h" +#include "ps3_dump.h" +#include "ps3_cli_debug.h" +S32 ps3_recovery_cancel_work_sync(struct ps3_instance *instance); +#ifndef _WINDOWS +static void ps3_recovery_work(struct work_struct* work); +#else +static void ps3_recovery_work(void *work); +#endif +static S32 ps3_hard_recovery_handle(struct ps3_instance *instance); +static S32 ps3_soft_recovery_handle(struct ps3_instance *instance); +static S32 ps3_recovery_ready_to_force_cmd_stop(struct ps3_instance *instance); +static S32 ps3_recovery_ready_to_running(struct ps3_instance *instance); +static void ps3_can_queue_reset(struct ps3_instance *instance, U32 cur_max_fw_cmds); +static void ps3_cmd_reset_flag_set(struct ps3_instance *instance, U8 reset_flag); +static S32 ps3_soft_recovery_fail_to_hard_recovery(struct ps3_instance *instance); + +enum { + PS3_RECOVERY_INTER_ERR_SUCCESS = 0, + PS3_RECOVERY_INTER_ERR_INTERRUPT = 1, + PS3_RECOVERY_INTER_ERR_FAILED = 2, + PS3_RECOVERY_INTER_ERR_NEED_RECOVERY = 3, + PS3_RECOVERY_INTER_ERR_PCIE_ERR = 4, + PS3_RECOVERY_INTER_ERR_SUSPEND_RESUME = 5, +}; + +static inline void ps3_wait_watchdog_dect_recovery( + struct ps3_instance *instance) +{ + U16 wait_step = 100; + U16 cur_cnt = 0; + Bool printed = PS3_TRUE; + + while(!instance->watchdog_context.is_halt && + instance->watchdog_context.watchdog_queue != NULL) { + ps3_msleep(wait_step); + if (printed && ((++cur_cnt) * wait_step > PS3_RECOVERY_WHILE_PRINT_REACH_TIME)) { + printed = PS3_FALSE; + LOG_WARN("host:%u wait watchdog recovery.\n", PS3_HOST(instance)); + } + } +} + +struct ps3_recovery_context *ps3_recovery_context_alloc(void) +{ + struct ps3_recovery_context *context; + + context = (struct ps3_recovery_context *)kzalloc(sizeof(struct ps3_recovery_context), GFP_KERNEL); + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_ALLOC_FAIL, &context) + if (!context) + return NULL; + + return context; +} +void ps3_recovery_context_free(struct ps3_recovery_context *context) +{ + if (context != NULL) { + kfree(context); + } + return; +} + +void ps3_recovery_context_delete(struct ps3_recovery_context *context) +{ + if (context != NULL) { + if (context->recovery_wq) { + destroy_workqueue(context->recovery_wq); + context->recovery_wq = NULL; + } + kfree(context); + context = NULL; + } + return; +} + +#ifndef _WINDOWS +static void ps3_recovery_irq_service(struct work_struct* work) +{ + struct ps3_instance *instance = + ps3_container_of(work, struct ps3_instance, + recovery_irq_work); + S32 ret = PS3_SUCCESS; + U32 count = 0; + LOG_INFO("hno:%u recovery irq triggered\n", + PS3_HOST(instance)); + + if ((instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_DECIDE || + instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_RECOVERY) + &&(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE)) { + goto l_out; + } + + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + if (instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_NULL) { + instance->recovery_context->heartbeat_recovery = + PS3_HEARTBEAT_HARDRESET_DECIDE; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + while ((ret = ps3_hard_recovery_request(instance)) == -PS3_RETRY) { + if (count++ == ps3_use_hard_reset_max_retry()) { + ret = -PS3_FAILED; + break; + } + ps3_mdelay(10); + } + if (ret == PS3_SUCCESS) { + LOG_INFO("hno[%u], recovery success!\n", + PS3_HOST(instance)); + }else{ + LOG_ERROR("hno[%u], recovery request NOK, %s!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state))); + } +l_out: + return; +} + +S32 ps3_recovery_irq_start(struct ps3_instance *instance) +{ + S8 request_irq_queue_name[PS3_RECOVERY_IRQ_NAME_MAX_LENTH]; + struct work_struct* recovery_irq_work = &instance->recovery_irq_work; + + INJECT_START(PS3_ERR_IJ_WATCHDOG_IRQ_QUEUE, instance) + if (instance->recovery_irq_queue != NULL) { + LOG_DEBUG("hno:%u watchdog for is already started!\n", + PS3_HOST(instance)); + goto l_out; + } + + memset(request_irq_queue_name, 0, PS3_RECOVERY_IRQ_NAME_MAX_LENTH); + INIT_WORK(recovery_irq_work, ps3_recovery_irq_service); + + snprintf(request_irq_queue_name, PS3_RECOVERY_IRQ_NAME_MAX_LENTH, + "ps3_irq_recovery_start_service_host%d", instance->host->host_no); + + instance->recovery_irq_queue = + create_singlethread_workqueue(request_irq_queue_name); + if (instance->recovery_irq_queue == NULL) { + LOG_ERROR("hno:%u watchdog work queue create failed\n", + PS3_HOST(instance)); + return -PS3_FAILED; + } + instance->recovery_irq_enable = PS3_TRUE; +l_out: + return PS3_SUCCESS; +} + +irqreturn_t ps3_recovery_irq_handler(S32 virq, void *dev_id) +{ + struct ps3_irq_recovery *irq = (struct ps3_irq_recovery *)dev_id; + struct ps3_instance *instance = irq->instance; + + if (instance->ioc_adpter->ioc_heartbeat_detect == NULL) { + goto l_out; + } + + if (instance->ioc_adpter->ioc_heartbeat_detect(instance) == PS3_TRUE + && !ps3_pci_err_recovery_get(instance) + && instance->recovery_irq_enable) { + + + LOG_DEBUG("hno:%u recovery irq recieved, virq: %d, dev_id: 0x%llx\n", + PS3_HOST(instance), virq, (U64)dev_id); + if (!work_busy(&instance->recovery_irq_work)) { + queue_work(instance->recovery_irq_queue, &instance->recovery_irq_work); + } + } +l_out: + return IRQ_HANDLED; +} + +void ps3_recovery_irq_queue_destory(struct ps3_instance *instance) +{ + if (instance->recovery_irq_queue) { + flush_workqueue(instance->recovery_irq_queue); + destroy_workqueue(instance->recovery_irq_queue); + instance->recovery_irq_queue = NULL; + } + return; +} + +void ps3_recovery_work_queue_destory(struct ps3_instance *instance) +{ + struct ps3_recovery_context *context = instance->recovery_context; + struct workqueue_struct* wq = context->recovery_wq; + + if (!ps3_is_latest_func(instance)) { + LOG_DEBUG("hno:%u not latest func\n", + PS3_HOST(instance)); + goto l_out; + } + + context->recovery_wq = NULL; + if (wq == NULL) { + return; + } + + flush_workqueue(wq); + destroy_workqueue(wq); +l_out: + return; +} +#endif +void ps3_recovery_function_init(struct ps3_instance *instance) +{ + instance->recovery_function.halt_handle_cb = NULL; + instance->recovery_function.hardreset_handle_init_running_cb = ps3_hardreset_handle_init_running; + instance->recovery_function.hardreset_handle_post_cb = ps3_hardreset_handle_post; + instance->recovery_function.hardreset_handle_pre_cb = ps3_hardreset_handle_pre; + instance->recovery_function.hardreset_handle_wait_ready_cb = ps3_hardreset_handle_wait_ready; + instance->recovery_function.hardreset_handle_finish_cb = ps3_hardreset_handle_finish; + instance->recovery_function.hardreset_handle_offline_cb = ps3_hardreset_handle_offline; + instance->recovery_function.recovery_handle_cb = NULL; + instance->recovery_function.softreset_handle_post_cb = ps3_softreset_handle_post; + instance->recovery_function.softreset_handle_pre_cb = ps3_softreset_handle_pre; + + return; +} + +S32 ps3_recovery_context_init(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_recovery_context *context = NULL; + + ps3_recovery_function_init(instance); + + if (instance->peer_instance != NULL) { + instance->recovery_context = instance->peer_instance->recovery_context; + goto l_recovery_irq_init; + } + + context = ps3_recovery_context_alloc(); + INJECT_START(PS3_ERR_RECOVERY_CONTEXT_ALLOC_FAILED, &context); + if (context == NULL) { + LOG_ERROR("hno:%u, alloc recovery context failed !\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + LOG_DEBUG("recovery context add!\n"); + snprintf(context->recovery_wq_name, 20, "ps3_rec_th_%d", + instance->host->host_no); + context->recovery_wq = + create_singlethread_workqueue(context->recovery_wq_name); + if (context->recovery_wq == NULL) { + LOG_ERROR("hno:%u create recovery_wq NOK !\n", PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + INIT_WORK(&context->recovery_work, ps3_recovery_work); + + ps3_mutex_init(&context->ps3_watchdog_recovery_mutex); + ps3_mutex_init(&context->free_cmd_lock); + ps3_spin_lock_init(&context->recovery_lock); + ps3_spin_lock_init(&context->ps3_hardreset_lock); + context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + ps3_atomic_set(&context->hardreset_ref, 0); + context->recovery_state = PS3_SOFT_RECOVERY_PROBE_PROCESS; + instance->recovery_context = context; + instance->recovery_context->hardreset_count = 0; + context->host_reset_state = PS3_HOST_RESET_INIT; + context->instance_change = 0; + +l_recovery_irq_init: + if (ps3_recovery_irq_start(instance) != PS3_SUCCESS) { + LOG_ERROR("hno:%u recovery irq NOK\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_recovery_start_failed; + } + + return ret; +l_recovery_start_failed: + ps3_recovery_irq_queue_destory(instance); + ps3_mutex_destroy(&context->ps3_watchdog_recovery_mutex); + ps3_mutex_destroy(&context->free_cmd_lock); + instance->recovery_context = NULL; +l_out: + ps3_recovery_context_delete(context); + return ret; +} + +void ps3_recovery_clean(struct ps3_instance *instance) +{ + struct ps3_recovery_context *context = instance->recovery_context; + if(context == NULL) { + goto l_out; + } + + if (!ps3_is_latest_func(instance)) { + instance->recovery_context = NULL; + goto l_out; + } + + ps3_mutex_destroy(&context->ps3_watchdog_recovery_mutex); + ps3_mutex_destroy(&context->free_cmd_lock); + ps3_recovery_context_free(instance->recovery_context); + instance->recovery_context = NULL; +l_out: + return ; +} + +void ps3_recovery_destory(struct ps3_instance *instance) +{ +#ifndef _WINDOWS + ps3_recovery_cancel_work_sync(instance); + ps3_recovery_work_queue_destory(instance); +#else + struct ps3_recovery_context *context = instance->recovery_context; + ps3_worker_exit(&context->recovery_work); +#endif + return ; +} + +void ps3_recovery_context_exit(struct ps3_instance *instance) +{ + ps3_recovery_irq_queue_destory(instance); + + if (instance->peer_instance == NULL && + instance->recovery_context != NULL) { + ps3_recovery_destory(instance); + ps3_recovery_clean(instance); + } + + return ; +} +S32 ps3_recovery_state_transfer(struct ps3_instance *instance, + U32 dest_state) +{ + U32 recovery_origin_state; + + ps3_mutex_lock(&instance->state_machine.lock); + recovery_origin_state = instance->recovery_context->recovery_state; + if (recovery_origin_state == dest_state) { + goto l_fail; + } + + switch(recovery_origin_state) { + case PS3_SOFT_RECOVERY_PROBE_PROCESS: + if (dest_state == PS3_SOFT_RECOVERY_SHALLOW || + dest_state == PS3_SOFT_RECOVERY_DEEP || + dest_state == PS3_SOFT_RECOVERY_IOC_RECOVERY || + dest_state == PS3_HARD_RECOVERY_DECIDE) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_SOFT_RECOVERY_SHALLOW: + case PS3_SOFT_RECOVERY_DEEP: + case PS3_SOFT_RECOVERY_IOC_RECOVERY: + if ((dest_state == PS3_HARD_RECOVERY_DECIDE) || + (dest_state == PS3_HARD_RECOVERY_SHALLOW)|| + (dest_state == PS3_SOFT_RECOVERY_FINISH)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_SOFT_RECOVERY_FINISH: + if ((dest_state == PS3_HARD_RECOVERY_DECIDE) || + (dest_state == PS3_SOFT_RECOVERY_SHALLOW) || + (dest_state == PS3_SOFT_RECOVERY_DEEP) || + (dest_state == PS3_SOFT_RECOVERY_IOC_RECOVERY) || + (dest_state == PS3_HARD_RECOVERY_SHALLOW)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_HARD_RECOVERY_DECIDE: + if (dest_state == PS3_HARD_RECOVERY_SHALLOW || + dest_state == PS3_HARD_RECOVERY_FINISH) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_HARD_RECOVERY_FINISH: + if ((dest_state == PS3_HARD_RECOVERY_DECIDE) || + (dest_state == PS3_SOFT_RECOVERY_SHALLOW) || + (dest_state == PS3_SOFT_RECOVERY_DEEP) || + (dest_state == PS3_SOFT_RECOVERY_IOC_RECOVERY) || + (dest_state == PS3_HARD_RECOVERY_SHALLOW)) { + goto l_success; + } else { + goto l_fail; + } + break; + case PS3_HARD_RECOVERY_SHALLOW: + if (dest_state == PS3_HARD_RECOVERY_FINISH) { + goto l_success; + } else { + goto l_fail; + } + break; + default: + goto l_fail; + } + +l_fail: + ps3_mutex_unlock(&instance->state_machine.lock); + LOG_ERROR("hno:%u recovery state transfer NOK!" + "[cur_state:%d][dest_state:%d]\n", + PS3_HOST(instance), + recovery_origin_state,dest_state); + return -PS3_FAILED; +l_success: + instance->recovery_context->recovery_state = dest_state; + ps3_mutex_unlock(&instance->state_machine.lock); + LOG_FILE_INFO("hno:%u recovery state transfer from %d to %d!\n", + PS3_HOST(instance), + recovery_origin_state,dest_state); + + return PS3_SUCCESS; +} + +#ifndef _WINDOWS + +static S32 ps3_recovery_work_start(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_recovery_context *context = instance->recovery_context; + INJECT_START(PS3_ERR_IJ_FORCE_START_DESTORY_RECOVERY, instance) + + if (unlikely(context->recovery_wq == NULL)) { + ret = -PS3_FAILED; + goto l_out; + } + context->work_instance = instance; + + queue_work(context->recovery_wq, &context->recovery_work); + +l_out: + return ret; +} + static inline void ps3_wait_hard_reset_finish(struct ps3_instance *instance) +{ + while(ps3_atomic_read(&instance->recovery_context->hardreset_ref) != 0){ + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + do{ + ps3_msleep(100); + + if (likely(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE)) { + continue; + } else { + cancel_work_sync(&instance->recovery_context->recovery_work); + break; + } + }while(1); + } else { + cancel_work_sync(&instance->recovery_context->recovery_work); + } +} +S32 ps3_recovery_cancel_work_sync(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_recovery_context *context = instance->recovery_context; + if (unlikely(context->recovery_wq == NULL)) { + ret = -PS3_FAILED; + goto l_out; + } + + ps3_wait_hard_reset_finish(instance); + +l_out: + return ret; +} + +static S32 ps3_recovery_start(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + ps3_mutex_lock(&instance->state_machine.lock); + INJECT_START(PS3_ERR_IJ_FORCE_START_DUL_RECOVERY, instance) + if(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW){ + LOG_ERROR("hno:%u hard recovery work proc,exit!\n", + PS3_HOST(instance)); + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + INJECT_START(PS3_ERR_IJ_FORCE_DESTORY_RECOVERY, instance) + if (unlikely(instance->recovery_context->recovery_wq == NULL)) { + ret = -PS3_FAILED; + LOG_ERROR("hno:%u recovery work sync NOK!\n", + PS3_HOST(instance)); + goto l_out; + } + + cancel_work_sync(&instance->recovery_context->recovery_work); + + ps3_mutex_lock(&instance->state_machine.lock); + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_STATE_DEAD, instance) + if(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + if(ps3_instance_no_lock_state_transfer(instance, PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to PS3_INSTANCE_STATE_RECOVERY NOK!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + } + ps3_mutex_unlock(&instance->state_machine.lock); + + if (instance->peer_instance != NULL) { + ps3_mutex_lock(&instance->peer_instance->state_machine.lock); + if(instance->peer_instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PEER_STATE_DEAD, instance->peer_instance) + if(ps3_instance_no_lock_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to PS3_INSTANCE_STATE_RECOVERY NOK!\n", + PS3_HOST(instance->peer_instance)); + ret = -PS3_FAILED; + ps3_mutex_unlock(&instance->peer_instance->state_machine.lock); + goto l_out; + } + } + ps3_mutex_unlock(&instance->peer_instance->state_machine.lock); + } + + ret = ps3_recovery_work_start(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u recovery work start NOK!\n", + PS3_HOST(instance)); + goto l_out; + } +l_out: + return ret; +} +#else +static S32 ps3_recovery_start(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_recovery_context* context = instance->recovery_context; + if (ps3_worker_start(&context->recovery_work) != PS3_SUCCESS) { + LOG_ERROR("trace_id[0x%llx], hno:%u recovery start worker failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } +l_out: + return ret; +} +#endif + +static Bool ps3_recovery_is_state_halt(struct ps3_instance *instance) +{ + Bool ret = PS3_FALSE; + struct ps3_instance_state_machine *state_machine + = &instance->state_machine; + U32 cur_state = 0; + U32 ioc_state = instance->ioc_adpter->ioc_state_get(instance); + + cur_state = ps3_atomic_read(&state_machine->state); + if (cur_state == PS3_INSTANCE_STATE_DEAD) { + LOG2_INFO_LIM("hno:%u ioc_state:%s, " + "drv_state:PS3_INSTANCE_STATE_DEAD, stop recovery!\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state)); + ret = PS3_TRUE; + goto l_out; + } + + if (ioc_state == PS3_FW_STATE_HALT && + instance->recovery_context->heartbeat_recovery != PS3_HEARTBEAT_HARDRESET_DECIDE) { + ps3_atomic_set(&state_machine->state, PS3_INSTANCE_STATE_DEAD); + LOG2_INFO_LIM("hno:%u ioc_state:PS3_FW_STATE_HALT, stop recovery!\n", + PS3_HOST(instance)); + while(1) { + ps3_msleep(10); + } + ret = PS3_TRUE; + goto l_out; + } + + if (PS3_IOC_STATE_HALT_SUPPORT(instance) && + instance->recovery_context->heartbeat_recovery != PS3_HEARTBEAT_HARDRESET_DECIDE) { + instance->ioc_adpter->ioc_force_to_halt(instance); + ps3_atomic_set(&state_machine->state, PS3_INSTANCE_STATE_DEAD); + LOG_WARN("hno:%u IOC support HALT, enter HALT!\n", + PS3_HOST(instance)); + while(1) { + ps3_msleep(10); + } + ret = PS3_TRUE; + } +l_out: + + return ret; +} + +static inline S32 ps3_hard_recovery_request_decide( + struct ps3_instance *instance, U32 cur_state, U32 peer_cur_state) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + LOG_INFO("hno:%u instance state during hard recovery!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + goto l_out; + } + + if ((cur_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_SOFT_RECOVERY) || + (cur_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) || + (cur_state == PS3_INSTANCE_STATE_DEAD) || + (cur_state == PS3_INSTANCE_STATE_PCIE_RECOVERY) || + (cur_state == PS3_INSTANCE_STATE_INIT)) { + if (instance->is_need_event) { + if(instance->event_context.event_abort_cmd != NULL){ + complete(&instance->event_context.event_abort_cmd->sync_done); + } else if (instance->dev_context.vdpending_abort_cmd != NULL){ + complete(&instance->dev_context.vdpending_abort_cmd->sync_done); + } else if (instance->webSubscribe_context.web_abort_cmd != NULL){ + complete(&instance->webSubscribe_context.web_abort_cmd->sync_done); + } + } + + if (instance->peer_instance == NULL) { + instance->recovery_context->recovery_state = PS3_HARD_RECOVERY_DECIDE; + LOG_INFO("hno:%u instance state to recovery!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } + } else { + LOG_INFO("hno:%u instance state during hard recovery!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + goto l_out; + } + + if (instance->peer_instance != NULL) { + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_DECIDE_PEER_INSTANCE_FAIL,\ + &peer_cur_state) + if ((peer_cur_state == PS3_INSTANCE_STATE_OPERATIONAL) || + (peer_cur_state == PS3_INSTANCE_STATE_SOFT_RECOVERY) || + (peer_cur_state == PS3_INSTANCE_STATE_PRE_OPERATIONAL) || + (peer_cur_state == PS3_INSTANCE_STATE_DEAD) || + (peer_cur_state == PS3_INSTANCE_STATE_PCIE_RECOVERY) || + (peer_cur_state == PS3_INSTANCE_STATE_INIT)) { + if (instance->peer_instance->is_need_event) { + if(instance->peer_instance->event_context.event_abort_cmd != NULL){ + complete(&instance->peer_instance->event_context.event_abort_cmd->sync_done); + } else if (instance->peer_instance->dev_context.vdpending_abort_cmd != NULL){ + complete(&instance->peer_instance->dev_context.vdpending_abort_cmd->sync_done); + } else if (instance->webSubscribe_context.web_abort_cmd != NULL){ + complete(&instance->webSubscribe_context.web_abort_cmd->sync_done); + } + } + + instance->peer_instance->recovery_context->recovery_state = PS3_HARD_RECOVERY_DECIDE; + + LOG_INFO("hno:%u instance state to recovery!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } else { + LOG_INFO("hno:%u instance state during hard recovery!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + } + } +l_out: + return ret; +} + +static S32 ps3_hard_recovery_request_prepare(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + U32 ioc_state = 0; + struct ps3_instance_state_machine *state_machine + = &instance->state_machine; + U32 cur_state = 0; + struct ps3_instance_state_machine *state_machine_peer = NULL; + U32 peer_cur_state = PS3_INSTANCE_STATE_OPERATIONAL; + INJECT_START(PS3_ERR_IJ_PCIE_FROZEN, instance) + if (instance->reg_set == NULL) { + return ret; + } + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + ps3_mutex_lock(&state_machine->lock); + cur_state = ps3_atomic_read(&state_machine->state); + + LOG_INFO("hno:%u hard recovery request:%s, %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state), namePS3InstanceState(cur_state)); + + if (instance->peer_instance != NULL) { + state_machine_peer = &instance->peer_instance->state_machine; + INJECT_START(PS3_ERR_IJ_PEER_PCIE_FROZEN, instance->peer_instance) + if (instance->peer_instance->reg_set == NULL) { + goto l_clean; + } + ioc_state = instance->peer_instance->ioc_adpter->ioc_state_get(instance->peer_instance); + ps3_mutex_lock(&state_machine_peer->lock); + peer_cur_state = ps3_atomic_read(&state_machine_peer->state); + + LOG_INFO("hno:%u hard recovery request:%s, %s\n", + PS3_HOST(instance->peer_instance), + ps3_ioc_state_print(ioc_state), namePS3InstanceState(peer_cur_state)); + } + + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + if (instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_DECIDE) { + ret = ps3_hard_recovery_request_decide(instance, cur_state, peer_cur_state); + if (ret == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + LOG_INFO("hno:%u heartbeat hard recovery start\n", + PS3_HOST(instance)); + instance->recovery_context->heartbeat_recovery = PS3_HEARTBEAT_HARDRESET_RECOVERY; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + goto l_out; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + + ret = ps3_hard_recovery_request_decide(instance, cur_state, peer_cur_state); + +l_out: + if (instance->peer_instance != NULL) { + ps3_mutex_unlock(&state_machine_peer->lock); + } +l_clean: + ps3_mutex_unlock(&state_machine->lock); + return ret; +} + +S32 ps3_hard_recovery_request(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance_recovery = NULL; + + LOG_WARN("hno:%u ps3 hard recovery request start, IOC outstanding: %d!!\n", PS3_HOST(instance), + ps3_atomic_read(&instance->cmd_statistics.cmd_outstanding)); + ps3_atomic_inc(&instance->recovery_context->hardreset_ref); + mb(); + + INJECT_START(PS3_ERR_IJ_ADD_INSTANCE, &instance->recovery_context->instance_change) + if (instance->recovery_context->instance_change) { + LOG_INFO("hno:%u peer instance is change\n", PS3_HOST(instance)); + ret = -PS3_RETRY; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_PROBE, instance) + INJECT_START(PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_REMOVE, instance) + while (instance->peer_instance != NULL && + PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance->peer_instance)) { + + INJECT_START(PS3_ERR_IJ_FORCE_DUL_RECOVERY, instance) + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || \ + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_REMOVE_INSTANCE, &instance->recovery_context->instance_change) + if (instance->recovery_context->instance_change) { + LOG_INFO("hno:%u peer instance is change\n", PS3_HOST(instance)); + ret = -PS3_RETRY; + goto l_out; + } + + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_INIT) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_PENDING; + } + INJECT_START(PS3_ERR_IJ_FORCE_DUL_RECOVERY_PENDING, instance) + ps3_atomic_dec(&instance->recovery_context->hardreset_ref); + ps3_msleep(10); + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_CONTINUE) { + ps3_atomic_inc(&instance->recovery_context->hardreset_ref); + mb(); + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + break; + } + ps3_atomic_inc(&instance->recovery_context->hardreset_ref); + mb(); + } + + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_PENDING) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + } + LOG_INFO("hno:%u peer_instance[%p], hard recovery request Function[%d]\n", + PS3_HOST(instance), instance->peer_instance, ps3_get_pci_function(instance->pdev)); + if (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_0 || + (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_1 && instance->peer_instance == NULL)) { + instance_recovery = instance; + } else { + instance_recovery = instance->peer_instance; + } + + if (ps3_recovery_is_state_halt(instance_recovery)) { + LOG_WARN("hno:%u driver_state:DEAD or HALT now !!!\n", + PS3_HOST(instance_recovery)); + ret = -PS3_FAILED; + goto l_out; + } + + if ((!PS3_IOC_HARD_RECOVERY_SUPPORT(instance_recovery)) || \ + (!ps3_hard_reset_enable_query())) { + LOG_ERROR("hno:%u soc feature unsupport Hard reset[%d] or unable[%d]!!\n", + PS3_HOST(instance_recovery), + PS3_IOC_HARD_RECOVERY_SUPPORT(instance_recovery), + ps3_hard_reset_enable_query()); + ret = -PS3_FAILED; + goto l_out; + } + + ret = ps3_hard_recovery_request_prepare(instance_recovery); + if (ret == PS3_RECOVERY_INTER_ERR_SUCCESS) { + ret = PS3_SUCCESS; + } else if(ret == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + ret = ps3_recovery_start(instance_recovery); + } else { + ret = -PS3_FAILED; + } + INJECT_START(PS3_ERR_IJ_WATCHDOG_IRQ_QUEUE_1, &ret) +l_out: + LOG_INFO("hno:%u hard recovery request end, ret:%d!\n", + PS3_HOST(instance), ret); + + ps3_atomic_dec(&instance->recovery_context->hardreset_ref); + return ret; +} + +static inline S32 ps3_ioc_soft_recovery_request_decide( + struct ps3_instance *instance, U32 ioc_state) +{ + U32 ioc_recovery_count = 0; + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + struct ps3_instance_state_machine *state_machine + = &instance->state_machine; + S32 recovery_state = 0; + + recovery_state = instance->recovery_context->recovery_state; + if(recovery_state == PS3_HARD_RECOVERY_SHALLOW|| + recovery_state == PS3_HARD_RECOVERY_DECIDE){ + LOG_INFO("hno:%u instance state %s,recovery_state %d,hard reset doing, IOC soft return!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&state_machine->state)), + recovery_state); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + }else if(recovery_state == PS3_SOFT_RECOVERY_SHALLOW || + recovery_state == PS3_SOFT_RECOVERY_DEEP || + recovery_state == PS3_SOFT_RECOVERY_IOC_RECOVERY){ + LOG_INFO("hno:%u instance state %s,recovery_state %d,repeat request!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&state_machine->state)), + recovery_state); + goto l_out; + } + if (!ps3_ioc_recovery_count_get(instance, &ioc_recovery_count)) { + LOG_INFO("hno:%u entry IOC soft recovery request decide!,ioc_state:%s," + " save_recovery_count:%d, ioc_recovery_count:%d\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state), + instance->recovery_context->ioc_recovery_count, ioc_recovery_count); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + LOG_INFO("hno:%u entry IOC soft recovery request decide!,ioc_state:%s," + " save_recovery_count:%d, ioc_recovery_count:%d\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state), + instance->recovery_context->ioc_recovery_count, ioc_recovery_count); + + if (instance->recovery_context->ioc_recovery_count == ioc_recovery_count) { + goto l_out; + } + + if(ps3_instance_no_lock_state_transfer(instance, PS3_INSTANCE_STATE_SOFT_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to ready failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + if (instance->peer_instance != NULL) { + if(ps3_instance_no_lock_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_SOFT_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to ready failed!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + } + instance->recovery_context->recovery_state + = PS3_SOFT_RECOVERY_IOC_RECOVERY; + + ret = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; +l_out: + return ret; +} + +static inline S32 ps3_soft_recovery_request_decide( + struct ps3_instance *instance, U32 ioc_state) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + struct ps3_instance_state_machine *state_machine + = &instance->state_machine; + S32 recovery_state = instance->recovery_context->recovery_state; + if( recovery_state == PS3_HARD_RECOVERY_SHALLOW || + recovery_state == PS3_HARD_RECOVERY_DECIDE){ + LOG_INFO("hno:%u instance state %s,recovery_state %d,repeat request!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&state_machine->state)), + recovery_state); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + }else if(recovery_state == PS3_SOFT_RECOVERY_SHALLOW || + recovery_state == PS3_SOFT_RECOVERY_DEEP || + recovery_state == PS3_SOFT_RECOVERY_IOC_RECOVERY){ + LOG_INFO("hno:%u instance state %s,recovery_state %d,repeat request!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&state_machine->state)), + recovery_state); + goto l_out; + } + + if (ioc_state == PS3_FW_STATE_RUNNING) { + if(ps3_instance_no_lock_state_transfer(instance, PS3_INSTANCE_STATE_SOFT_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to ready failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + if (instance->peer_instance != NULL) { + if(ps3_instance_no_lock_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_SOFT_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to ready failed!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + } + instance->recovery_context->recovery_state + = PS3_SOFT_RECOVERY_SHALLOW; + + LOG_INFO("hno:%u instance state to soft recovery shallow!\n", + PS3_HOST(instance)); + + ret = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } +l_out: + return ret; +} + +static S32 ps3_recovery_request_prepare(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + U32 ioc_state = 0; + struct ps3_instance_state_machine *state_machine + = &instance->state_machine; + U32 cur_state = 0; + struct ps3_instance_state_machine *state_machine_peer = NULL; + U32 peer_cur_state = PS3_INSTANCE_STATE_OPERATIONAL; + + ps3_mutex_lock(&state_machine->lock); + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + cur_state = ps3_atomic_read(&state_machine->state); + + INJECT_START(PS3_ERR_IJ_CHANGE_FW_TO_HALT_IN_PREPARE, &ioc_state); + LOG_INFO("hno:%u recovery request:%s, %s\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state), namePS3InstanceState(cur_state)); + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PCIE_ERR, instance) + if (ps3_pci_err_recovery_get(instance) || + (instance->peer_instance != NULL && ps3_pci_err_recovery_get(instance->peer_instance))) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + goto l_out; + } + + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + if (instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_DECIDE) { + ret = ps3_hard_recovery_request_decide(instance, cur_state, peer_cur_state); + if (ret == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + LOG_INFO("hno:%u heartbeat recovery start\n", + PS3_HOST(instance)); + instance->recovery_context->heartbeat_recovery = PS3_HEARTBEAT_HARDRESET_RECOVERY; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + goto l_out; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_IOC_HALT, instance) + if (ioc_state == PS3_FW_STATE_HALT) { + ps3_instance_state_transfer_to_dead_nolock(instance); + if (instance->peer_instance != NULL) { + ps3_instance_state_transfer_to_dead_nolock(instance->peer_instance); + } + LOG_ERROR("hno:%u IOC state has halt, instance state to dead!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + if (cur_state == PS3_INSTANCE_STATE_DEAD || + cur_state == PS3_INSTANCE_STATE_QUIT || + cur_state == PS3_INSTANCE_STATE_SUSPEND) { + LOG_ERROR("hno:%u instance state is %s, and ioc_state is %s!\n", + PS3_HOST(instance), namePS3InstanceState(cur_state), + ps3_ioc_state_print(ioc_state)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + if (instance->peer_instance != NULL) { + state_machine_peer = &instance->peer_instance->state_machine; + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PEER_PCIE_ERR, instance) + if (ps3_pci_err_recovery_get(instance->peer_instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + goto l_out; + } + ps3_mutex_lock(&state_machine_peer->lock); + ioc_state = instance->peer_instance->ioc_adpter->ioc_state_get(instance); + peer_cur_state = ps3_atomic_read(&state_machine->state); + LOG_INFO("hno:%u recovery request:%s, %s\n", + PS3_HOST(instance->peer_instance), + ps3_ioc_state_print(ioc_state), namePS3InstanceState(peer_cur_state)); + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PREPARE_PEER_IOC_HALT, instance) + if (ioc_state == PS3_FW_STATE_HALT) { + ps3_instance_state_transfer_to_dead_nolock(instance->peer_instance); + ps3_instance_state_transfer_to_dead_nolock(instance); + LOG_ERROR("hno:%u ioc state has halt, instance state to dead!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out_peer; + } + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_STATE_DEAD, instance) + if (peer_cur_state == PS3_INSTANCE_STATE_DEAD || + peer_cur_state == PS3_INSTANCE_STATE_QUIT || + peer_cur_state == PS3_INSTANCE_STATE_SUSPEND) { + LOG_ERROR("hno:%u instance state is %s, and ioc_state is %s!\n", + PS3_HOST(instance->peer_instance), namePS3InstanceState(peer_cur_state), + ps3_ioc_state_print(ioc_state)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out_peer; + } + } + + if (ioc_state == PS3_FW_STATE_FAULT || + ioc_state == PS3_FW_STATE_CRITICAL) { + LOG_ERROR("hno:%u instance state is %s, and ioc_state is %s!\n", + PS3_HOST(instance), namePS3InstanceState(peer_cur_state), + ps3_ioc_state_print(ioc_state)); + ret = ps3_hard_recovery_request_decide(instance, cur_state, peer_cur_state); + goto l_out_peer; + } + + if(cur_state != PS3_INSTANCE_STATE_OPERATIONAL || + peer_cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + LOG_INFO("hno:%u instance state is %s:%s! no need repeat recovery requeset\n", + PS3_HOST(instance), namePS3InstanceState(cur_state), namePS3InstanceState(cur_state)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + goto l_out_peer; + } + + ret = ps3_ioc_soft_recovery_request_decide(instance, ioc_state); + if (ret == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY || + ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + goto l_out_peer; + }else if (ret == PS3_RECOVERY_INTER_ERR_FAILED) { + goto l_hardreset; + } + + ret = ps3_soft_recovery_request_decide(instance, ioc_state); + if (ret == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY || + ret == PS3_RECOVERY_INTER_ERR_SUCCESS || + ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + goto l_out_peer; + }else if (ret == PS3_RECOVERY_INTER_ERR_FAILED) { + goto l_hardreset; + } + + LOG_ERROR("hno:%u UNEXPECT!!! hard recovery!,ioc_state:%s, %s:%s\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state), namePS3InstanceState(cur_state), namePS3InstanceState(peer_cur_state)); + +l_hardreset: + ret = ps3_hard_recovery_request_decide(instance, cur_state, peer_cur_state); +l_out_peer: + if (instance->peer_instance != NULL) { + ps3_mutex_unlock(&state_machine_peer->lock); + } +l_out: + ps3_mutex_unlock(&state_machine->lock); + return ret; +} + +S32 ps3_recovery_request(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance_recovery = NULL; + + LOG_WARN("hno:%u ps3 recovery request start, IOC outstanding: %d!!\n", PS3_HOST(instance), + ps3_atomic_read(&instance->cmd_statistics.cmd_outstanding)); + ps3_atomic_inc(&instance->recovery_context->hardreset_ref); + mb(); + INJECT_START(PS3_ERR_IJ_ADD_INSTANCE, &instance->recovery_context->instance_change) + if (instance->recovery_context->instance_change) { + LOG_INFO("hno:%u peer instance is change\n", PS3_HOST(instance)); + ret = -PS3_RETRY; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_PROBE, instance) + INJECT_START(PS3_ERR_IJ_RECOVERY_REQ_WAIT_FUNC1_REMOVE, instance) + while (instance->peer_instance != NULL && + PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance->peer_instance)) { + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || \ + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + goto l_out; + } + + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_INIT) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_PENDING; + } + INJECT_START(PS3_ERR_IJ_REMOVE_INSTANCE, &instance->recovery_context->instance_change) + if (instance->recovery_context->instance_change) { + LOG_INFO("hno:%u peer instance is change\n", PS3_HOST(instance)); + ret = -PS3_RETRY; + goto l_out; + } + + ps3_atomic_dec(&instance->recovery_context->hardreset_ref); + ps3_msleep(10); + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_CONTINUE) { + ps3_atomic_inc(&instance->recovery_context->hardreset_ref); + mb(); + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + break; + } + ps3_atomic_inc(&instance->recovery_context->hardreset_ref); + mb(); + } + INJECT_START(PS3_ERR_IJ_FORCE_DUL_RECOVERY_PENDING, instance) + if (instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_PENDING) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_INIT; + } + LOG_INFO("hno:%u peer_instance[%p], hard recovery request Function[%d]\n", + PS3_HOST(instance), instance->peer_instance, ps3_get_pci_function(instance->pdev)); + INJECT_START(PS3_ERR_IJ_WDT_WAIT_REC_REQ_3, instance) + if (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_0 || + (ps3_get_pci_function(instance->pdev) == PS3_FUNC_ID_1 && instance->peer_instance == NULL)) { + instance_recovery = instance; + } else { + instance_recovery = instance->peer_instance; + } + + if (ps3_pci_err_recovery_get(instance_recovery)) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance_recovery)); + ret = PS3_SUCCESS; + goto l_out; + } + + if (ps3_recovery_is_state_halt(instance_recovery)) { + LOG_INFO_LIM("hno:%u driver_state:DEAD or HALT now !!!\n", + PS3_HOST(instance_recovery)); + ret = -PS3_FAILED; + goto l_out; + } + + if (instance_recovery->peer_instance != NULL) { + if (ps3_pci_err_recovery_get(instance_recovery->peer_instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance_recovery->peer_instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + if (instance_recovery->peer_instance->reg_set == NULL || + ps3_recovery_is_state_halt(instance_recovery->peer_instance)) { + LOG_WARN("hno:%u driver_state:DEAD or HALT now !!!\n", + PS3_HOST(instance_recovery->peer_instance)); + ret = -PS3_FAILED; + goto l_out; + } + } + + ret = ps3_recovery_request_prepare(instance_recovery); + if (ret == PS3_RECOVERY_INTER_ERR_SUCCESS || + ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + ret = PS3_SUCCESS; + } else if(ret == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + ret = ps3_recovery_start(instance_recovery); + } else { + ret = -PS3_FAILED; + } + +l_out: + LOG_INFO("hno:%u recovery request end, ret:%d!\n", + PS3_HOST(instance), ret); + ps3_atomic_dec(&instance->recovery_context->hardreset_ref); + return ret; +} + +static Bool ps3_recovery_reg(struct ps3_instance *instance) +{ + Bool ret = PS3_FALSE; + HilReg0Ps3RegisterFPs3FeatureSupport_u *ps3_feature_support = NULL; + HilReg0Ps3RegisterFPs3FirmwareVersion_u *pver = NULL; + U32 cur_max_fw_cmds = 0; + U32 fw_cur_state = PS3_FW_STATE_UNDEFINED; + U64 value = 0; + U64 ver = 0; + + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3FeatureSupport, value); + if (value == U64_MAX) { + goto l_out; + } + ps3_feature_support = (HilReg0Ps3RegisterFPs3FeatureSupport_u *)&value; + PS3_IOC_REG_READ_WITH_CHECK(instance, reg_f.Excl_reg, ps3FirmwareVersion, ver); + if (ver == U64_MAX) { + goto l_out; + } + pver = (HilReg0Ps3RegisterFPs3FirmwareVersion_u *)&ver; + if (!ps3_ioc_mgr_max_fw_cmd_get(instance, &cur_max_fw_cmds)) { + goto l_out; + } + fw_cur_state = instance->ioc_adpter->ioc_state_get(instance); + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_REG_FAILED, &fw_cur_state) + if (fw_cur_state != PS3_FW_STATE_RUNNING) { + goto l_out; + } + instance->is_ioc_halt_support = (ps3_feature_support->reg.fwHaltSupport == 1); + instance->dump_context.is_dump_support = (ps3_feature_support->reg.dumpCrashSupport == 1); + instance->is_shallow_soft_recovery_support = (ps3_feature_support->reg.shallowSoftRecoverySupport == 1); + instance->is_deep_soft_recovery_support = (ps3_feature_support->reg.deepSoftRecoverySupport == 1); + instance->is_hard_recovery_support = (ps3_feature_support->reg.hardRecoverySupport == 1); + instance->ioc_fw_version = (U64)pver->reg.ps3FmVer; + ps3_can_queue_reset(instance, cur_max_fw_cmds); + ret = PS3_TRUE; +l_out: + return ret; +} + +static S32 ps3_recovery_finish(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + if (!ps3_recovery_reg(instance)) { + LOG_WARN("hno:%u recovery reg NOK\n",PS3_HOST(instance)); + } + return ret; +} + +static S32 ps3_recovery_complete(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_13, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + ret = -PS3_IN_PCIE_ERR; + goto l_out; + } + + if (PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance)) { + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_14, instance) + if (ps3_recovery_finish(instance) != PS3_SUCCESS) { + ps3_instance_state_transfer_to_dead(instance); + LOG_ERROR("hno:%u recovery finish process failed, to DEAD\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + +l_out: + return ret; +} +static void ps3_hard_recovery(struct ps3_instance *instance) +{ + struct ps3_recovery_context *context = instance->recovery_context; + if (ps3_hard_recovery_handle(instance) != PS3_SUCCESS) { + context->recovery_result = -PS3_FAILED; + LOG_ERROR("hno:%u hard recovery failed!\n", + PS3_HOST(instance)); + }else{ + context->recovery_result = PS3_SUCCESS; + LOG_WARN("hno:%u hard recovery success!\n", + PS3_HOST(instance)); + } + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + instance->recovery_context->heartbeat_recovery = PS3_HEARTBEAT_NULL; + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + + return; +} + +#ifndef _WINDOWS +static void ps3_recovery_work(struct work_struct* work) +{ + struct ps3_recovery_context *context = + ps3_container_of(work, struct ps3_recovery_context, recovery_work); + struct ps3_instance *instance = context->work_instance; +#else +static void ps3_recovery_work(void *ins) +{ + struct ps3_instance *instance = (struct ps3_instance*)ins; + struct ps3_recovery_context *context = instance->recovery_context; +#endif + U32 cur_state = ps3_atomic_read(&instance->state_machine.state); + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + LOG_INFO("hno:%u recovery work start, %s recovery state[%d]\n", + PS3_HOST(instance), namePS3InstanceState(cur_state), context->recovery_state); + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance)); + + if(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE){ + ps3_recovery_state_transfer(instance, PS3_HARD_RECOVERY_FINISH); + }else{ + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_FINISH); + } + + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + instance->recovery_context->heartbeat_recovery = + PS3_HEARTBEAT_NULL; + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + goto l_out; + } + + context->recovery_result = PS3_SUCCESS; + if (cur_state == PS3_INSTANCE_STATE_SOFT_RECOVERY) { + ps3_mutex_lock(&instance->state_machine.lock); + if (context->recovery_state == PS3_SOFT_RECOVERY_IOC_RECOVERY){ + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_soft_reset; + } + + if (context->recovery_state == PS3_SOFT_RECOVERY_SHALLOW) { + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_soft_reset; + } + + if (context->recovery_state == PS3_SOFT_RECOVERY_DEEP) { + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_soft_reset; + } + + LOG_ERROR("hno:%u nothing to do %s,recovery_state %d!\n", + PS3_HOST(instance),namePS3InstanceState(cur_state),context->recovery_state); + ps3_mutex_unlock(&instance->state_machine.lock); + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_SOFT_RECOVERY, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + if (instance->peer_instance == NULL || + instance->peer_instance->recovery_context == NULL) { + context->recovery_result = -PS3_FAILED; + LOG_ERROR("hno:%u hard recovery NOK,recovery_state %d!\n", + PS3_HOST(instance),context->recovery_state); + ps3_recovery_state_transfer(instance, PS3_HARD_RECOVERY_FINISH); + goto l_out; + } + } + + if (instance->peer_instance != NULL && + ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_SOFT_RECOVERY, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + context->recovery_result = -PS3_FAILED; + LOG_ERROR("hno:%u hard recovery NOK,recovery_state %d!\n", + PS3_HOST(instance->peer_instance),context->recovery_state); + ps3_recovery_state_transfer(instance->peer_instance, PS3_HARD_RECOVERY_FINISH); + goto l_out; + } + } else if (cur_state == PS3_INSTANCE_STATE_RECOVERY) { + goto l_hard_reset; + } else { + LOG_ERROR("hno:%u nothing to do %s,recovery_state %d, cur_state:%s!\n", + PS3_HOST(instance),namePS3InstanceState(cur_state),context->recovery_state, + namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state))); + if(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE){ + ps3_recovery_state_transfer(instance, PS3_HARD_RECOVERY_FINISH); + }else{ + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_FINISH); + } + goto l_out; + } + +l_soft_reset: + ret = ps3_soft_recovery_handle(instance); + if (ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + context->recovery_result = PS3_SUCCESS; + LOG_INFO("hno:%u soft recovery interrupt!\n", + PS3_HOST(instance)); + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_FINISH); + } else if(ret == PS3_RECOVERY_INTER_ERR_SUCCESS){ + context->recovery_result = PS3_SUCCESS; + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_FINISH); + LOG_WARN("hno:%u soft recovery success!\n", + PS3_HOST(instance)); + } else { + LOG_INFO("hno:%u soft recovery to hard recovery!\n", + PS3_HOST(instance)); + if(ps3_soft_recovery_fail_to_hard_recovery(instance) != PS3_SUCCESS){ + context->recovery_result = -PS3_FAILED; + LOG_ERROR("hno:%u soft to hard recovery failed!\n", + PS3_HOST(instance)); + }else{ + context->recovery_result = PS3_SUCCESS; + LOG_INFO("hno:%u soft to hard recovery success!\n", + PS3_HOST(instance)); + } + } + goto l_out; + +l_hard_reset: + ps3_hard_recovery(instance); + +l_out: + if (ps3_pci_err_recovery_get(instance)) { + LOG_INFO("hno:%u recovery is interrupted by pci err recovery.\n", + PS3_HOST(instance)); + ps3_instance_state_transfer_to_pcie_recovery(instance); + if (instance->peer_instance != NULL) { + ps3_instance_state_transfer_to_pcie_recovery(instance->peer_instance); + } + } + return; +} + +static S32 ps3_soft_recovery_cmd_reply_check(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + U32 i = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + U32 no_reply_count = 0; + + for (i = context->max_scsi_cmd_count; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + if (cmd->cmd_state.reset_flag != PS3_CMD_FLAG_SOFTRESET) { + continue; + } + + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + continue; + } + + if (cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NO_REPLY_WORD && + ps3_cmd_resp_status(cmd) != U32_MAX) { + continue; + } + if (cmd == instance->event_context.event_cmd || + cmd == instance->dev_context.vd_pending_cmd || + cmd == instance->webSubscribe_context.webSubscribe_cmd) { + continue; + } + + no_reply_count++; + LOG_DEBUG("hno:%u no reply cmd,CFID[%d], %s,max_scsi_cmd_count %u, max_cmd_count %u\n", + PS3_HOST(instance), i, namePS3CmdState(cmd->cmd_state.state), + context->max_scsi_cmd_count, context->max_cmd_count); + } + + if (no_reply_count > 0) { + ret = PS3_RECOVERY_INTER_ERR_FAILED; + } +l_out: + return ret; +} + +static S32 ps3_soft_recovery_cmd_reply_polling_check( + struct ps3_instance *instance, U32 wait_seconds) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_FAILED; + const U32 interval_check_ms = 20; + U32 msecs = U32_MAX; + U32 i = 0; + + if (wait_seconds != 0) { +#ifndef _WINDOWS + msecs = wait_seconds * HZ; +#else + msecs = wait_seconds * 1000; +#endif + } + + for (i = 0; (i < msecs); i += interval_check_ms) { + if (!ps3_is_instance_state_normal(instance, PS3_TRUE)) { + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + break; + } + ps3_mutex_lock(&instance->state_machine.lock); + + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + break; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u host in pci err recovery\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + break; + } + + ret = ps3_soft_recovery_cmd_reply_check(instance); + if (ret == PS3_RECOVERY_INTER_ERR_SUCCESS || + ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + LOG_WARN("hno:%u no mgr cmd pending\n", + PS3_HOST(instance)); + break; + } + + ps3_msleep(interval_check_ms); + } + + return ret; +} + +static S32 ps3_soft_recovery_to_pre_operational(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ps3_cmd_reset_flag_set(instance, PS3_CMD_FLAG_SOFTRESET); + + ret = ps3_ioc_state_transfer_wait_to_running(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u soft recovery to running failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + ret = ps3_soft_recovery_cmd_reply_polling_check(instance, PS3_SOFT_RESET_WAIT_TIMEOUT); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_ERROR("hno:%u pending mgr cmd no reply all!\n", + PS3_HOST(instance)); + goto l_out; + } + + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + LOG_INFO("hno:%u soft recovery to pre-operational success!\n", + PS3_HOST(instance)); +l_out: + return ret; +} + +static S32 ps3_hard_recovery_pre_operational_to_operational(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + if (!ps3_ioc_recovery_count_get(instance, + &instance->recovery_context->ioc_recovery_count)) { + LOG_ERROR("hno:%u get recovery count NOK\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + LOG_INFO("hno:%u pre-operational to operational success!\n", + PS3_HOST(instance)); +l_out: + return ret; +} + +static S32 ps3_soft_recovery_pre_operational_to_operational(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + if (!ps3_ioc_recovery_count_get(instance, + &instance->recovery_context->ioc_recovery_count)) { + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + LOG_INFO("hno:%u pre-operational to operational success!,reset count:%d\n", + PS3_HOST(instance), instance->recovery_context->ioc_recovery_count); +l_out: + return ret; +} +static S32 ps3_cmd_resubscribe(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + ret = ps3_soft_reset_event_resubscribe(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u event unsubscribe failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ret = ps3_dev_mgr_vd_info_resubscribe(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u vd pending unsubscribe failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u soft reset proc is interrupt!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ret = ps3_soft_reset_web_resubscribe(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u web unsubscribe failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + } + + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; +l_out: + return ret; +} +static S32 ps3_soft_recovery_complete(struct ps3_instance *instance) +{ + S32 ret = ps3_soft_recovery_to_pre_operational(instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_WARN("hno:%u ioc soft reset failed!\n", + PS3_HOST(instance)); + goto l_out; + } + + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_SOFT_RECOVERY, + PS3_INSTANCE_STATE_PRE_OPERATIONAL) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to pre operational failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + + if (instance->peer_instance != NULL && \ + instance->peer_instance->recovery_function.softreset_handle_pre_cb != NULL) { + ret = instance->peer_instance->recovery_function.softreset_handle_pre_cb(instance->peer_instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_WARN("hno:%u softreset handle pre cb failed\n", + PS3_HOST(instance->peer_instance)); + goto l_out; + } + + if (ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_SOFT_RECOVERY, + PS3_INSTANCE_STATE_PRE_OPERATIONAL) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to pre operational failed!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + } + + ret = ps3_soft_recovery_pre_operational_to_operational(instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_WARN("hno:%u ioc soft reset failed!\n", + PS3_HOST(instance)); + goto l_out; + } + + if (instance->peer_instance != NULL && \ + instance->peer_instance->recovery_function.softreset_handle_post_cb != NULL) { + ret = instance->peer_instance->recovery_function.softreset_handle_post_cb(instance->peer_instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_WARN("hno:%u softreset handle post cb failed\n", + PS3_HOST(instance->peer_instance)); + goto l_out; + } + } + +l_out: + return ret; +} + +static S32 ps3_soft_recovery_fail_to_hard_recovery(struct ps3_instance *instance) +{ + S32 ret = -PS3_FAILED; + U32 cur_state = ps3_atomic_read(&instance->state_machine.state); + S32 ret_peer = PS3_SUCCESS; + U32 peer_cur_state = PS3_INSTANCE_STATE_OPERATIONAL; + + PS3_IJ_SLEEP(10000, PS3_ERR_IJ_SOFT_TO_HARD); + ps3_mutex_lock(&instance->state_machine.lock); + + if (instance->peer_instance != NULL) { + ps3_mutex_lock(&instance->peer_instance->state_machine.lock); + peer_cur_state = ps3_atomic_read(&instance->peer_instance->state_machine.state); + } + + ret = ps3_hard_recovery_request_decide(instance, cur_state, peer_cur_state); + if (instance->peer_instance != NULL) { + ps3_mutex_unlock(&instance->peer_instance->state_machine.lock); + } + ps3_mutex_unlock(&instance->state_machine.lock); + if (ret != PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + LOG_WARN("hno:%u decide no need to hard recovery\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ret = ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_SOFT_RECOVERY, + PS3_INSTANCE_STATE_RECOVERY); + if (ret != PS3_SUCCESS) { + ret = ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY); + } + if (ret != PS3_SUCCESS) { + ret = ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY); + } + + if (instance->peer_instance != NULL) { + ret_peer = ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_SOFT_RECOVERY, + PS3_INSTANCE_STATE_RECOVERY); + if (ret_peer != PS3_SUCCESS) { + ret_peer = ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY); + } + if (ret_peer != PS3_SUCCESS) { + ret_peer = ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY); + } + } + + if (ret == PS3_SUCCESS && ret_peer == PS3_SUCCESS) { + ps3_need_wait_hard_reset_request(instance); + ret = ps3_hard_recovery_handle(instance); + } else { + LOG_ERROR("hno:%u transfer to recovery failed!, cur_state:%s\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state))); + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_FINISH); + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u hard reset failed!\n", + PS3_HOST(instance)); + } else { + LOG_INFO("hno:%u hard reset success and finished!\n", + PS3_HOST(instance)); + } +l_out: + return ret; +} + +static S32 ps3_ioc_soft_recovery(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + ret = ps3_soft_recovery_complete(instance); + if (ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + LOG_WARN("hno:%u IOC soft reset proc is interrupt!\n", + PS3_HOST(instance)); + goto l_out; + } else if (ret == PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u IOC soft reset success!\n", + PS3_HOST(instance)); + goto l_reset_sucess; + } else { + LOG_ERROR("hno:%u IOC self soft reset failed! need to hard reset\n", + PS3_HOST(instance)); + goto l_out; + } + +l_reset_sucess: + ret = ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_OPERATIONAL); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to operational failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + ret = ps3_cmd_resubscribe(instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_ERROR("hno:%u cmd unsubscribe failed!\n", + PS3_HOST(instance)); + goto l_out; + } + ret = ps3_recovery_complete(instance); + if(ret != PS3_SUCCESS){ + LOG_INFO("hno:%u IOC soft reset opeational but complete failed! cur_state:%s,ret %d\n", + PS3_HOST(instance), namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state)),ret); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + if (instance->peer_instance != NULL) { + ret = ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_OPERATIONAL); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to operational failed!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + LOG_INFO("hno:%u soft reset success and finished!\n", + PS3_HOST(instance->peer_instance)); + ret = ps3_cmd_resubscribe(instance->peer_instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_ERROR("hno:%u cmd unsubscribe failed!\n", + PS3_HOST(instance->peer_instance)); + goto l_out; + } + ret = ps3_recovery_complete(instance->peer_instance); + if(ret != PS3_SUCCESS){ + LOG_INFO("hno:%u soft reset opeational but complete failed! cur_state:%s,ret %d\n", + PS3_HOST(instance->peer_instance), + namePS3InstanceState(ps3_atomic_read(&instance->peer_instance->state_machine.state)),ret); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + } + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_FINISH); + + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + LOG_INFO("hno:%u soft reset success and finished!\n", + PS3_HOST(instance)); +l_out: + return ret; +} + +static S32 ps3_host_shallow_soft_recovery(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + if (PS3_FALSE == PS3_IOC_SHALLOW_SOFT_RECOVERY_SUPPORT(instance)) { + LOG_ERROR("hno:%u soc feature unsupport soft reset Shallow!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + + if (instance->peer_instance != NULL) { + if (PS3_FALSE == PS3_IOC_SHALLOW_SOFT_RECOVERY_SUPPORT(instance->peer_instance)) { + LOG_ERROR("hno:%u soc feature unsupport soft reset Shallow!\n", + PS3_HOST(instance->peer_instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + } + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u shallow soft reset proc is interrupt!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + if (instance->ioc_adpter->ioc_shallow_soft_reset != NULL) { + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_SHALLOW); + ret = instance->ioc_adpter->ioc_shallow_soft_reset(instance); + } else { + LOG_ERROR("hno:%u driver unsupport soft reset shallow!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + + if (ret == PS3_SUCCESS) { + LOG_INFO("hno:%u shallow soft reset entry complete prcoess!\n", + PS3_HOST(instance)); + err_code = ps3_soft_recovery_complete(instance); + } else { + LOG_ERROR("hno:%u shallow soft reset fail!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } + + LOG_INFO("hno:%u shallow soft reset finished!:ret:%d, err_code:%d\n", + PS3_HOST(instance), ret, err_code); + +l_out: + return err_code; +} + +static S32 ps3_host_deep_soft_recovery(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + if (PS3_FALSE == PS3_IOC_DEEP_SOFT_RECOVERY_SUPPORT(instance)) { + LOG_ERROR("hno:%u soc feature unsupport soft reset Deep!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + + if (instance->peer_instance != NULL) { + if (PS3_FALSE == PS3_IOC_DEEP_SOFT_RECOVERY_SUPPORT(instance->peer_instance)) { + LOG_ERROR("hno:%u soc feature unsupport soft reset Deep!\n", + PS3_HOST(instance->peer_instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + } + + ps3_mutex_lock(&instance->state_machine.lock); + if(PS3_IS_INTERRUPT_SOFT_RECOVERY(instance)){ + LOG_WARN("hno:%u deep soft reset proc is interrupt!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + ps3_mutex_unlock(&instance->state_machine.lock); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_SOFT_RECOVERY); + + if (ps3_atomic_read(&instance->state_machine.state) != + PS3_INSTANCE_STATE_SOFT_RECOVERY) { + LOG_ERROR("hno:%u soft reovery has been interrupt!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + if (instance->peer_instance != NULL) { + ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_SOFT_RECOVERY); + + if (ps3_atomic_read(&instance->peer_instance->state_machine.state) != + PS3_INSTANCE_STATE_SOFT_RECOVERY) { + LOG_ERROR("hno:%u soft reovery has been interrupt!\n", + PS3_HOST(instance->peer_instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + } + + if (instance->ioc_adpter->ioc_deep_soft_reset != NULL) { + ps3_recovery_state_transfer(instance, PS3_SOFT_RECOVERY_DEEP); + ret = instance->ioc_adpter->ioc_deep_soft_reset(instance); + } else { + LOG_ERROR("hno:%u driver unsupport soft reset deep!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + + if (ret == PS3_SUCCESS) { + LOG_INFO("hno:%u deep soft reset entry complete prcoess!\n", + PS3_HOST(instance)); + err_code = ps3_soft_recovery_complete(instance); + } else { + LOG_ERROR("hno:%u deep soft reset fail!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } + + LOG_INFO("hno:%u deep soft reset finished!:ret:%d, err_code:%d\n", + PS3_HOST(instance), ret, err_code); + +l_out: + return err_code; +} +static inline S32 ps3_wait_event_vdpending_cmd_complete(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 count = 0; + + const U32 retry_max = PS3_WAIT_EVENT_CMD_LOOP_COUNT; + + while(instance->event_context.abort_eventcmd != 0 || + instance->dev_context.abort_vdpending_cmd != 0 || + instance->webSubscribe_context.abort_webcmd != 0){ + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + + if(count++ > retry_max){ + LOG_INFO("hno:%u wait event proc over:%d ms,failed\n", + PS3_HOST(instance), + retry_max*PS3_LOOP_TIME_INTERVAL_100MS); + ret = -PS3_FAILED; + break; + } + } + return ret; +} +static S32 ps3_soft_recovery_handle(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + struct ps3_recovery_context *context = instance->recovery_context; + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci error recovery resetting\n", + PS3_HOST(instance)); + goto l_out; + } + + if(ps3_wait_event_vdpending_cmd_complete(instance) != PS3_SUCCESS){ + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + if (instance->peer_instance != NULL) { + if (ps3_pci_err_recovery_get(instance->peer_instance)) { + LOG_WARN("hno:%u pci error recovery resetting\n", + PS3_HOST(instance->peer_instance)); + goto l_out; + } + + if(ps3_wait_event_vdpending_cmd_complete(instance->peer_instance) != PS3_SUCCESS){ + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + } + ps3_mutex_lock(&instance->state_machine.lock); + if (context->recovery_state == PS3_SOFT_RECOVERY_IOC_RECOVERY) { + ps3_mutex_unlock(&instance->state_machine.lock); + ret = ps3_ioc_soft_recovery(instance); + goto l_out; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ret = ps3_host_shallow_soft_recovery(instance); + if (ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + LOG_WARN("hno:%u shallow soft reset proc is interrupt!\n", + PS3_HOST(instance)); + goto l_out; + } else if (ret == PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_WARN("hno:%u shallow soft reset success!\n", + PS3_HOST(instance)); + goto l_reset_sucess; + } else { + LOG_WARN("hno:%u shallow soft reset fail, need to deep recovery!\n", + PS3_HOST(instance)); + } + + ret = ps3_host_deep_soft_recovery(instance); + if (ret == PS3_RECOVERY_INTER_ERR_INTERRUPT) { + LOG_WARN("hno:%u deep soft reset proc is interrupt!\n", + PS3_HOST(instance)); + goto l_out; + } else if (ret == PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u deep soft reset success!\n", + PS3_HOST(instance)); + goto l_reset_sucess; + } else { + LOG_INFO("hno:%u deep soft reset fail, need to hard recovery!\n", + PS3_HOST(instance)); + goto l_out; + } + +l_reset_sucess: + ret = ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_OPERATIONAL); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to operational failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + LOG_INFO("hno:%u soft reset success and finished!\n", + PS3_HOST(instance)); + ret = ps3_cmd_resubscribe(instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_ERROR("hno:%u cmd unsubscribe failed!\n", + PS3_HOST(instance)); + goto l_out; + } + ret = ps3_recovery_complete(instance); + if(ret != PS3_SUCCESS){ + LOG_INFO("hno:%u soft reset opeational but complete failed! cur_state:%s,ret %d\n", + PS3_HOST(instance), namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state)),ret); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + if (instance->peer_instance != NULL) { + ret = ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_OPERATIONAL); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to operational failed!\n", + PS3_HOST(instance->peer_instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + LOG_INFO("hno:%u soft reset success and finished!\n", + PS3_HOST(instance->peer_instance)); + ret = ps3_cmd_resubscribe(instance->peer_instance); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_ERROR("hno:%u cmd unsubscribe failed!\n", + PS3_HOST(instance->peer_instance)); + goto l_out; + } + ret = ps3_recovery_complete(instance->peer_instance); + if(ret != PS3_SUCCESS){ + LOG_INFO("hno:%u soft reset opeational but complete failed! cur_state:%s,ret %d\n", + PS3_HOST(instance->peer_instance), + namePS3InstanceState(ps3_atomic_read(&instance->peer_instance->state_machine.state)),ret); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + } + + LOG_INFO("hno:%u soft reset success and finished!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + return ret; + +l_out: + return ret; +} + +static S32 ps3_hard_recovery_to_ready(struct ps3_instance *instance) +{ + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + U32 ioc_state = 0; + S32 ret = PS3_SUCCESS; + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_3, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + goto l_out; + } + + if ((ret = ps3_ioc_hard_reset_to_ready(instance)) != PS3_SUCCESS) { + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + LOG_ERROR("hno:%u hard reset to ready NOK,%s!\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state)); + if (ret == -PS3_IN_PCIE_ERR) { + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + } else { + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } + goto l_out; + } + + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_RECOVERY, + PS3_INSTANCE_STATE_READY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to ready NOK!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + } +l_out: + return err_code; +} + +static S32 ps3_hard_recovery_to_pre_operational(struct ps3_instance *instance) +{ + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + S32 ret = PS3_SUCCESS; + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_7, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + goto l_out; + } + + if (PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance)) { + goto l_out; + } + + if ((ret = ps3_recovery_ready_to_running(instance)) != PS3_SUCCESS) { + LOG_ERROR("hno:%u hard reset to running NOK!\n", + PS3_HOST(instance)); + + if (ret == -PS3_IN_PCIE_ERR) { + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL, instance) + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_READY, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to recovery NOK!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + + instance->ioc_adpter->irq_enable(instance); +#ifndef _WINDOWS + ps3_irqpolls_enable(instance); +#endif + if (instance->is_need_event && ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ps3_web_cmd_clear(instance); + } + if (instance->is_need_event) { + ps3_dev_mgr_vd_info_clear(instance); + } + INJECT_START(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL, instance) + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_READY, + PS3_INSTANCE_STATE_PRE_OPERATIONAL) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to pre-operational NOK!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + ps3_dump_ctrl_set_int_ready(instance); + +l_out: + return err_code; +} + +static S32 ps3_hard_recovery_to_operational(struct ps3_instance *instance) +{ + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + S32 ret; + ULong flags = 0; + struct ps3_cmd *cmd = NULL; + Bool need_subscribe = PS3_FALSE; + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_10, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + goto l_out; + } + + if (PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance)) { + goto l_out; + } + + if (ps3_hard_recovery_pre_operational_to_operational(instance) != PS3_SUCCESS) { + LOG_ERROR("hno:%u pre operational NOK!\n", + PS3_HOST(instance)); + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to recovery NOK!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_OPE_FAIL, instance) + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_OPERATIONAL) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to operational NOK!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_INT, instance) + INJECT_START(PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_PROC, instance) + INJECT_START(PS3_ERR_IJ_HARD_SUBC_WAIT_EVENT_SUBCRIBE, instance) + + if (!instance->is_need_event) { + LOG_INFO("hno:%u not need event\n", + PS3_HOST(instance)); + goto l_out; + } + + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + cmd = instance->event_context.event_cmd; + if (cmd == NULL) { + LOG_WARN_IN_IRQ(instance, "hno:%u Event is not register yet\n", + PS3_HOST(instance)); + need_subscribe = PS3_TRUE; + goto l_subscribe; + } + if (instance->event_context.subwork == 0) { + if (instance->hardreset_event != 0) { + instance->hardreset_event = 0; + LOG_INFO_IN_IRQ(instance, "hno:%u event cmd free, CFID:%d\n", + PS3_HOST(instance), cmd->index); + instance->event_context.event_cmd = NULL; + ps3_mgr_cmd_free(instance, cmd); + need_subscribe = PS3_TRUE; + } + } + +l_subscribe: + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_11, instance) + if(need_subscribe == PS3_TRUE) { + instance->event_req_info.eventTypeMapProcResult = instance->event_req_info.eventTypeMap; + ret = ps3_event_subscribe(instance); + if (ret != PS3_SUCCESS && ret != -PS3_IN_UNLOAD) { + err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + LOG_WARN("hno:%u IOC event subscribe NOK ret[%d]\n", + PS3_HOST(instance), ret); + goto l_out; + } + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + + ret = ps3_dev_mgr_vd_info_subscribe(instance); + if (ret != PS3_SUCCESS && ret != -PS3_IN_UNLOAD) { + err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + LOG_WARN("hno:%u vd info subscribe NOK ret[%d]\n", + PS3_HOST(instance), ret); + goto l_out; + } + + if (ps3_atomic_read(&instance->webSubscribe_context.is_subscribe) == 1) { + ret = ps3_web_subscribe(instance); + if (ret != PS3_SUCCESS && ret != -PS3_IN_UNLOAD) { + err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + LOG_WARN("hno:%u web subscribe NOK ret[%d]\n", + PS3_HOST(instance), ret); + goto l_out; + } + } +l_out: + return err_code; +} + +static inline void ps3_hard_reset_unnormal_handle(struct ps3_instance *instance) +{ + ps3_recovery_ready_to_force_cmd_stop(instance); + + ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_READY, + PS3_INSTANCE_STATE_RECOVERY); + instance ->is_half_hard_reset = PS3_TRUE; + if (!instance->state_machine.is_load || + instance->state_machine.is_suspend) { + ps3_ioc_notify_unload(instance); + } +} + +static inline S32 ps3_hard_reset_error_code_decide(struct ps3_instance *instance) +{ + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + if (PS3_IS_INSTANCE_SUSPEND_OR_RESUME(instance)) { + err_code = PS3_RECOVERY_INTER_ERR_SUSPEND_RESUME; + goto l_out; + } + + if (PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance) && \ + instance->peer_instance == NULL) { + err_code = PS3_RECOVERY_INTER_ERR_FAILED; + } + +l_out: + return err_code; +} + +static inline S32 ps3_hard_reset_multi_unnormal_handle(struct ps3_instance *instance) +{ + + if (PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance)) { + LOG_WARN("host_no[%u], reset while probe or in shutdown/remove," + " finish[%d], flag[%d], is_load[%d]\n", + PS3_HOST(instance), instance->is_probe_finish, + instance->is_probe_failed, + instance->state_machine.is_load); + if (((PS3_IS_INSTANCE_PROBE(instance) || PS3_IS_INSTANCE_RESUME(instance)) && \ + instance->state_machine.is_load) || \ + PS3_IS_INSTANCE_REMOVE(instance)) { + ps3_hard_reset_unnormal_handle(instance); + ps3_instance_state_transfer_to_dead(instance); + } else if (PS3_IS_INSTANCE_SUSPEND(instance)) { + ps3_hard_reset_unnormal_handle(instance); + } + } + if (instance->peer_instance != NULL && PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance->peer_instance)) { + LOG_WARN("host_no[%u], reset while probe or in shutdown/remove," + " finish[%d], flag[%d], is_load[%d]\n", + PS3_HOST(instance->peer_instance), instance->peer_instance->is_probe_finish, + instance->peer_instance->is_probe_failed, + instance->peer_instance->state_machine.is_load); + if (((PS3_IS_INSTANCE_PROBE(instance->peer_instance) || PS3_IS_INSTANCE_RESUME(instance->peer_instance)) && \ + instance->peer_instance->state_machine.is_load) || \ + PS3_IS_INSTANCE_REMOVE(instance->peer_instance)) { + ps3_hard_reset_unnormal_handle(instance->peer_instance); + ps3_instance_state_transfer_to_dead(instance->peer_instance); + } else if (PS3_IS_INSTANCE_SUSPEND(instance->peer_instance)) { + ps3_hard_reset_unnormal_handle(instance->peer_instance); + } + } + return ps3_hard_reset_error_code_decide(instance); +} + +static void ps3_recovery_wait_reg_access_done(struct ps3_instance *instance) +{ + U16 cur_cnt = 0; + Bool printed = PS3_TRUE; + + LOG_DEBUG("hno:%u recovery wait reg access done start\n", + PS3_HOST(instance)); + ps3_wait_scsi_cmd_done(instance, PS3_TRUE); + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + while (ps3_atomic_read(&instance->reg_op_count) != 0) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_20MS); + if (printed && ((++cur_cnt) * PS3_LOOP_TIME_INTERVAL_20MS > PS3_RECOVERY_WHILE_PRINT_REACH_TIME)) { + printed = PS3_FALSE; + LOG_WARN("host:%u wait reg access done.\n", PS3_HOST(instance)); + } + } + LOG_DEBUG("hno:%u recovery wait reg access done end\n", + PS3_HOST(instance)); +} + +void ps3_hard_recovery_state_finish(struct ps3_instance *instance) { + ps3_mutex_lock(&instance->state_machine.lock); + if (instance->recovery_context->host_reset_state == PS3_HOST_RESET_START) { + instance->recovery_context->host_reset_state = PS3_HOST_RESET_HARD_RESET_DONE; + } + ps3_mutex_unlock(&instance->state_machine.lock); + ps3_recovery_state_transfer(instance, PS3_HARD_RECOVERY_FINISH); + INJECT_START(PS3_ERR_IJ_WDT_WAIT_REC_REQ, instance) +} + +static S32 ps3_hard_recovery_handle(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 retries = 0; + U32 cur_state = 0; + U32 ioc_state = 0; + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + U32 wait_count = 0; + ULong flags = 0; + U16 cur_cnt = 0; + Bool printed = PS3_TRUE; + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_0, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance)); + goto l_out; + } + + if (((!PS3_IOC_HARD_RECOVERY_SUPPORT(instance)) + || (!ps3_hard_reset_enable_query())) + && (instance->recovery_context->heartbeat_recovery != PS3_HEARTBEAT_HARDRESET_RECOVERY)) { + LOG_ERROR("hno:%u soc feature unsupport Hard reset! need to be offline!\n", + PS3_HOST(instance)); + goto l_offline; + } + + INJECT_START(PS3_ERR_IJ_FLAG_WAIT_EVENT_INT, instance) + INJECT_START(PS3_ERR_IJ_FLAG_WAIT_EVENT_PROC, instance) + INJECT_START(PS3_ERR_IJ_FLAG_WAIT_EVENT_SUBCRIBE, instance) + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + if (instance->event_context.abort_eventcmd != 0) { + instance->event_context.abort_eventcmd = 0; + } + + if (instance->hardreset_event == 0) { + instance->hardreset_event = 1; + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + INJECT_START(PS3_ERR_IJ_HOST_RESET_WAIT_DECIDE, instance) + ps3_recovery_state_transfer(instance, PS3_HARD_RECOVERY_SHALLOW); + INJECT_START(PS3_ERR_IJ_RECOVERY_WAIT_FUNC1_PROBE, instance) + INJECT_START(PS3_ERR_IJ_RECOVERY_WAIT_FUNC1_REMOVE, instance) + if (instance->is_scan_host_finish + && !instance->is_probe_finish) { + LOG_INFO("hno:%u recovery wait until probe finish/failed\n", + PS3_HOST(instance)); + while (wait_count < PS3_RECOVERY_WAIT_PROBE_FINISH_LOOP_COUNT) { + if (instance->is_probe_finish || instance->is_probe_failed) { + break; + } + + wait_count++; + ps3_msleep(PS3_RECOVERY_WAIT_LOOP_TIME_INTERVAL_20MS); + } + + LOG_INFO("hno:%u probe finish(%d)/failed(%d), continue recovery\n", + PS3_HOST(instance), instance->is_probe_finish, instance->is_probe_failed); + } + + ps3_wait_watchdog_dect_recovery(instance); + + if (instance->peer_instance != NULL && \ + instance->peer_instance->recovery_function.hardreset_handle_pre_cb != NULL) { + ret = instance->peer_instance->recovery_function.hardreset_handle_pre_cb(instance->peer_instance); + if (ret != PS3_SUCCESS) { + LOG_WARN("hno:%u hardreset handle pre cb NOK\n", + PS3_HOST(instance)); + if (ret == -PS3_IN_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + } + + while(ps3_use_hard_reset_max_retry() > retries) { + LOG_DEBUG("hno:%u request IOC state to fault! retries:%d\n", + PS3_HOST(instance), retries); + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + if (instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_RECOVERY && + retries != 0) { + instance->recovery_context->heartbeat_recovery = PS3_HEARTBEAT_HARDRESET_RETRY; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + + instance->dump_context.is_hard_recovered = PS3_TRUE; + if (instance->recovery_context->heartbeat_recovery != PS3_HEARTBEAT_HARDRESET_RECOVERY) { + ret = instance->ioc_adpter->ioc_force_to_fault(instance); + if (ret != PS3_SUCCESS) { + LOG_WARN("hno:%u hardreset handle force to fault NOK\n", + PS3_HOST(instance)); + if (ret == -PS3_IN_PCIE_ERR) { + goto l_out; + } + } + } else { + ps3_recovery_wait_reg_access_done(instance); + if (instance->peer_instance != NULL) { + ps3_recovery_wait_reg_access_done(instance->peer_instance); + } + } + + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + LOG_DEBUG("hno:%u IOC state is %s! retries:%d\n", + PS3_HOST(instance), ps3_ioc_state_print(ioc_state), retries); + + while(ps3_atomic_read(&instance->is_err_scsi_processing) > 0) { + ps3_msleep(10); + if (printed && ((++cur_cnt) * 10 > PS3_RECOVERY_WHILE_PRINT_REACH_TIME)) { + printed = PS3_FALSE; + LOG_WARN("host:%u wait err scsi process\n", PS3_HOST(instance)); + } + } + instance->ioc_adpter->irq_disable(instance); + INJECT_START(PS3_ERR_IJ_WAIT_IOCTL_IN_RECOVERY, instance) +#ifndef _WINDOWS + ps3_irqs_sync(instance); +#endif + + INJECT_START(PS3_ERR_IJ_WAIT_READY, instance); + INJECT_START(PS3_ERR_IJ_WDT_WAIT_REC_REQ_4, instance); + err_code = ps3_hard_recovery_to_ready(instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u IOC state to ready failed! retries:%d\n", + PS3_HOST(instance), retries); + if (err_code == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + retries++; + continue; + } else if (err_code == PS3_RECOVERY_INTER_ERR_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + LOG_INFO("hno:%u IOC state to ready success! retries:%d\n", + PS3_HOST(instance), retries); + + if (instance->peer_instance != NULL && \ + instance->peer_instance->recovery_function.hardreset_handle_wait_ready_cb != NULL) { + err_code = instance->peer_instance->recovery_function.hardreset_handle_wait_ready_cb( \ + instance->peer_instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u ioc state to ready failed! retries:%d\n", + PS3_HOST(instance), retries); + if (err_code == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + retries++; + continue; + } else if (err_code == PS3_RECOVERY_INTER_ERR_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + LOG_INFO("hno:%u ioc state to ready success! retries:%d\n", + PS3_HOST(instance), retries); + } + + INJECT_START(PS3_ERR_IJ_FWSTATE_REMOVE, instance) + err_code = ps3_hard_reset_multi_unnormal_handle(instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("driver loading or unloading err_code:%d\n", + err_code); + if (err_code == PS3_RECOVERY_INTER_ERR_SUSPEND_RESUME) { + goto l_out; + } else { + goto l_offline; + } + } + INJECT_START(PS3_ERR_IJ_FORCE_WAIT_CLI_CMD, instance); + INJECT_START(PS3_ERR_IJ_WATCHDOG_WAIT_RUNNING, instance); + err_code = ps3_hard_recovery_to_pre_operational(instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u IOC state to pre-operatioal failed! retries:%d\n", + PS3_HOST(instance), retries); + INJECT_START(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_DEAD_FAIL1, instance->peer_instance) + if (err_code == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + if(instance->peer_instance != NULL) { + if (ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_READY, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_WARN("hno:%u transfer to recovery NOK!\n", + PS3_HOST(instance->peer_instance)); + goto l_offline; + } + } + retries++; + continue; + } else if (err_code == PS3_RECOVERY_INTER_ERR_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + LOG_INFO("hno:%u IOC state to pre-operatioal success! retries:%d\n", + PS3_HOST(instance), retries); + + INJECT_START(PS3_ERR_IJ_RECOVERY_WAIT_FUNC0_RUNNING_1, instance) + if (instance->peer_instance != NULL && !PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance->peer_instance) && \ + instance->peer_instance->recovery_function.hardreset_handle_init_running_cb != NULL) { + if(ps3_atomic_read(&instance->peer_instance->state_machine.state) != PS3_INSTANCE_STATE_DEAD){ + err_code = instance->peer_instance->recovery_function.hardreset_handle_init_running_cb( \ + instance->peer_instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u IOC state to pre-operatioal failed! retries:%d\n", + PS3_HOST(instance), retries); + if (err_code == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + INJECT_START(PS3_ERR_IJ_FORCE_TO_PREOPERTIONAL_PEER_DEAD_FAIL, instance->peer_instance) + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_PRE_OPERATIONAL, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_WARN("hno:%u transfer to recovery NOK!\n", + PS3_HOST(instance->peer_instance)); + goto l_offline; + } + retries++; + continue; + } else if (err_code == PS3_RECOVERY_INTER_ERR_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + LOG_INFO("hno:%u IOC state to pre-operatioal success! retries:%d\n", + PS3_HOST(instance), retries); + } + } + INJECT_START(PS3_ERR_IJ_WDT_WAIT_REC_REQ_2, instance) + + err_code = ps3_hard_recovery_to_operational(instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u IOC state to operatioal failed! retries:%d\n", + PS3_HOST(instance), retries); + if (err_code == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + retries++; + continue; + } else if (err_code == PS3_RECOVERY_INTER_ERR_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + LOG_INFO("hno:%u IOC state to operatioal success! retries:%d\n", + PS3_HOST(instance), retries); + + if (instance->peer_instance != NULL && \ + instance->peer_instance->recovery_function.hardreset_handle_post_cb != NULL) { + if (!PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance->peer_instance)) { + if(ps3_atomic_read(&instance->peer_instance->state_machine.state) != PS3_INSTANCE_STATE_DEAD){ + err_code = instance->peer_instance->recovery_function.hardreset_handle_post_cb( \ + instance->peer_instance); + if (err_code != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_INFO("hno:%u IOC state to operatioal failed! retries:%d\n", + PS3_HOST(instance), retries); + if (err_code == PS3_RECOVERY_INTER_ERR_NEED_RECOVERY) { + retries++; + continue; + } else if (err_code == PS3_RECOVERY_INTER_ERR_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + LOG_INFO("hno:%u IOC state to operatioal success! retries:%d\n", + PS3_HOST(instance), retries); + } + } + } + break; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if ((cur_state != PS3_INSTANCE_STATE_OPERATIONAL || + ps3_use_hard_reset_max_retry() == retries) && !PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance)) { + LOG_ERROR("hno:%u hard reset failed! cur_state:%s\n", + PS3_HOST(instance), + namePS3InstanceState(cur_state)); + goto l_offline; + } + + ret = ps3_recovery_complete(instance); + if(ret != PS3_SUCCESS){ + LOG_WARN("hno:%u hard reset opeational but complete failed! cur_state:%s,ret %d\n", + PS3_HOST(instance), namePS3InstanceState(cur_state),ret); + if (ret == -PS3_IN_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + + if (instance->peer_instance == NULL || \ + instance->peer_instance->recovery_function.hardreset_handle_finish_cb == NULL) { + ps3_hard_recovery_state_finish(instance); + LOG_INFO("hno:%u hard reset finish! cur_state:%s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + } else { + if(!PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance->peer_instance)) { + if(ps3_atomic_read(&instance->peer_instance->state_machine.state) != PS3_INSTANCE_STATE_DEAD){ + ret = instance->peer_instance->recovery_function.hardreset_handle_finish_cb( \ + instance->peer_instance); + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PEER_COMPLETE_FAILED, &ret) + } + if (ret != PS3_SUCCESS) { + LOG_WARN("hno:%u hardreset handle running cb NOK\n", + PS3_HOST(instance->peer_instance)); + if (ret == -PS3_IN_PCIE_ERR) { + goto l_out; + } else { + goto l_offline; + } + } + } else { + ps3_hard_recovery_state_finish(instance); + } + } + ps3_ioc_can_hardreset_set(instance, PS3_IOC_CAN_HARDRESET); + if (instance->peer_instance != NULL) { + ps3_ioc_can_hardreset_set(instance->peer_instance, PS3_IOC_CAN_HARDRESET); + } + return ret; +l_offline: + ps3_instance_state_transfer_to_dead(instance); + if (instance->peer_instance != NULL && \ + instance->peer_instance->recovery_function.hardreset_handle_offline_cb != NULL) { + instance->peer_instance->recovery_function.hardreset_handle_offline_cb( \ + instance->peer_instance); + } +l_out: + ps3_hard_recovery_state_finish(instance); + if (ps3_pci_err_recovery_get(instance)) { + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + instance->recovery_context->heartbeat_recovery = + PS3_HEARTBEAT_NULL; + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + } + LOG_WARN("hno:%u hard reset finish! cur_state:%s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = -PS3_FAILED; + return ret; +} + +static S32 ps3_recovery_ready_to_force_cmd_stop(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U16 cur_cnt = 0; + Bool printed = PS3_TRUE; + + ps3_cmd_reset_flag_set(instance, PS3_CMD_FLAG_HARDRESET); + + while(ps3_atomic_read(&instance->is_err_scsi_processing) > 0) { + ps3_msleep(10); + if (printed && ((++cur_cnt) * 10 > PS3_RECOVERY_WHILE_PRINT_REACH_TIME)) { + printed = PS3_FALSE; + LOG_WARN("host:%u cmd stop wait err scsi process\n", PS3_HOST(instance)); + } + } + + ps3_all_reply_fifo_complete(instance); + + ps3_cmd_force_stop(instance); + + LOG2_DEBUG("hno:%u force cmd stop end\n", + PS3_HOST(instance)); + return ret; +} + +static S32 ps3_recovery_ready_to_running(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U16 cur_cnt = 0; + Bool printed = PS3_TRUE; + + ps3_cmd_reset_flag_set(instance, PS3_CMD_FLAG_HARDRESET); + + while(ps3_atomic_read(&instance->is_err_scsi_processing) > 0) { + ps3_msleep(10); + if (printed && ((++cur_cnt) * 10 > PS3_RECOVERY_WHILE_PRINT_REACH_TIME)) { + printed = PS3_FALSE; + LOG_WARN("host:%u to running wait err scsi process\n", PS3_HOST(instance)); + } + } + + ps3_all_reply_fifo_complete(instance); + + INJECT_START(PS3_ERR_IJ_RECOVERY_BLOCK_BEFORE_RUNNING, instance); + + ps3_cmd_force_stop(instance); + if (!ps3_bit_pos_update(instance)) { + LOG_ERROR("hno:%u update bit pos NOK\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + if ((ret = instance->ioc_adpter->ioc_init_proc(instance)) != PS3_SUCCESS) { + LOG_ERROR("hno:%u init IOC frame NOK\n", + PS3_HOST(instance)); + goto l_out; + } + +l_out: + LOG_DEBUG("hno:%u ready to running :%d\n", + PS3_HOST(instance), ret); + return ret; +} + +static void ps3_can_queue_reset(struct ps3_instance *instance, U32 cur_max_fw_cmds) +{ + ULong flag = 0; + LOG_INFO("hno:%u IOC cur max fw cmd is %d!\n", + PS3_HOST(instance), cur_max_fw_cmds); + + if (cur_max_fw_cmds <= instance->cmd_context.max_cmd_count) { + instance->cmd_attr.cur_can_que = cur_max_fw_cmds - + instance->cmd_context.max_mgr_cmd_count - + instance->cmd_context.max_r1x_cmd_count; + spin_lock_irqsave(instance->host->host_lock, flag); + instance->host->can_queue = instance->cmd_attr.cur_can_que; + LOG_INFO_IN_IRQ(instance, + "hno:%u IOC cur max fw cmd %d is less than %d, can queue is updated to %d!\n", + PS3_HOST(instance), cur_max_fw_cmds, + instance->cmd_context.max_cmd_count, + instance->host->can_queue); + spin_unlock_irqrestore(instance->host->host_lock, flag); + } +} + +static void ps3_cmd_reset_flag_set(struct ps3_instance *instance, U8 reset_flag) +{ + U32 i = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + ULong flags = 0; + + if (context->cmd_buf == NULL) { + return; + } + + for (i = 0; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &flags); + if (cmd->cmd_state.state != PS3_CMD_STATE_INIT) { + cmd->cmd_state.reset_flag = reset_flag; + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, flags); + } +} + +static Bool ps3_is_scsi_task_cmd(struct ps3_cmd *cmd) +{ + U8 cmd_type = cmd->req_frame->word[0]; + + if (cmd_type == PS3_CMD_SCSI_TASK_MANAGEMENT) { + return PS3_TRUE; + } else { + return PS3_FALSE; + } +} + +void ps3_scsi_cmd_force_stop(struct ps3_instance *instance) +{ + S32 i = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *peer_cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + struct scsi_cmnd *s_cmd = NULL; + struct ps3_scsi_priv_data *data = NULL; + U16 count = 0; +#ifndef _WINDOWS + S32 ret_code = 0 ; + + if (ps3_pci_err_recovery_get(instance)) { + ret_code = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + } else { + ret_code = ps3_get_requeue_or_reset(); + } +#endif + ps3_mutex_lock(&instance->recovery_context->free_cmd_lock); + for (i = 0; i < instance->cmd_attr.cur_can_que; i++) { + cmd = context->cmd_buf[i]; + if ((cmd->cmd_state.state == PS3_CMD_STATE_INIT) || + (cmd->cmd_state.state == PS3_CMD_STATE_COMPLETE)) { + continue; + } + + LOG_INFO("hno:%u force stop scsi CFID[%d] [%u]\n", + PS3_HOST(instance), i, cmd->cmd_state.state); + + s_cmd = cmd->scmd; + count++; + + PS3_IO_OUTSTAND_DEC(instance, s_cmd); + PS3_VD_OUTSTAND_DEC(instance, s_cmd); + PS3_DEV_IO_OUTSTAND_DEC(instance, cmd); + PS3_IOC_DRV2IOC_BACK_INC(cmd->instance, cmd, PS3_REPLY_WORD_FLAG_FAIL); + ps3_qos_cmd_update(instance, cmd); + +#ifndef _WINDOWS + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + + s_cmd->result = ret_code; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) + s_cmd->SCp.ptr = NULL; +#endif + ps3_scsi_dma_unmap(cmd); + if (likely(cmd && cmd->scmd && cmd->scmd->device && cmd->scmd->device->hostdata)) { + data = (struct ps3_scsi_priv_data *)cmd->scmd->device->hostdata; + if (likely(data != NULL) && + data->lock_mgr.hash_mgr != NULL) { + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + } else { + LOG_WARN("hno:%u force stop scsi has Null pointer CFID[%u]\n", + PS3_HOST(instance), i); + } + peer_cmd = cmd->r1x_peer_cmd; + ps3_scsi_cmd_free(cmd); + if (peer_cmd != NULL) { + LOG_DEBUG("hno:%u force stop r1x scsi CFID[%d] and CFID[%d]\n", + PS3_HOST(instance), i, peer_cmd->index); + PS3_IOC_DRV2IOC_BACK_INC(peer_cmd->instance, peer_cmd, PS3_REPLY_WORD_FLAG_FAIL); + ps3_r1x_peer_cmd_free_nolock(peer_cmd); + } + SCMD_IO_DONE(s_cmd); +#else + PS3_IO_BACK_ERR_INC(cmd->instance, s_cmd, cmd->index); + scsi_cmnd_hoststatus_set(s_cmd, DID_RESET); + data = scsi_device_private_data(s_cmd); + if(likely(data != NULL) && data->lock_mgr.hash_mgr != NULL){ + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + ps3_scsi_cmd_done(cmd); + +#endif + } + ps3_mutex_unlock(&instance->recovery_context->free_cmd_lock); + LOG_WARN("hno:%u force stop scsi cmd count[%u] during hard recovery\n", + PS3_HOST(instance), count); + + return; +} + +void ps3_mgr_cmd_force_stop(struct ps3_instance *instance) +{ + U32 i = 0; + struct ps3_cmd *cmd = NULL; + struct ps3_cmd *abort_cmd = NULL; + struct ps3_cmd_context *context = &instance->cmd_context; + ULong cmd_lock_flags = 0; + + for (i = context->max_scsi_cmd_count; i < context->max_cmd_count; i++) { + cmd = context->cmd_buf[i]; + ps3_spin_lock_irqsave(&cmd->cmd_state.lock, &cmd_lock_flags); + if ((cmd->cmd_state.state == PS3_CMD_STATE_INIT) || + (cmd->cmd_state.state == PS3_CMD_STATE_COMPLETE)) { + LOG_FILE_WARN("hno:%u init or complete CFID:%d\n", PS3_HOST(instance), i); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + continue; + } + + if (cmd->cmd_state.state == PS3_CMD_STATE_DEAD) { + LOG_FILE_WARN("hno:%u force free CFID:%d\n", PS3_HOST(instance), i); + PS3_MGR_CMD_BACK_INC(instance, cmd, PS3_REPLY_WORD_FLAG_FAIL); + + if (PS3_MGR_CMD_TYPE(cmd) == PS3_CMD_IOCTL){ + LOG_FILE_WARN("hno:%u force free CFID:%d ioctl buff\n", PS3_HOST(instance), i); + ps3_ioctl_buff_release(cmd); + } + if (cmd == instance->event_context.event_cmd) { + instance->event_context.event_cmd = NULL; + } + ps3_mgr_cmd_free_nolock(instance, cmd); + + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + continue; + } + + if (cmd->req_frame->mgrReq.reqHead.noReplyWord == PS3_CMD_WORD_NO_REPLY_WORD) { + LOG_FILE_WARN("hno:%u force complete no reply word CFID:%d\n", + PS3_HOST(instance), i); + if (ps3_is_scsi_task_cmd(cmd)) { + cmd->resp_frame->normalRespFrame.respStatus = SCSI_STATUS_GOOD; + } else { + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_BUSY; + } + PS3_MGR_CMD_BACK_INC(instance, cmd, PS3_REPLY_WORD_FLAG_FAIL); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + continue; + } + + if (ps3_is_scsi_task_cmd(cmd)) { + cmd->resp_frame->normalRespFrame.respStatus = SCSI_STATUS_GOOD; + PS3_MGR_CMD_BACK_INC(instance, cmd, PS3_REPLY_WORD_FLAG_FAIL); + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + complete(&cmd->sync_done); + LOG_FILE_WARN("hno:%u force complete task mgr CFID:%d\n", + PS3_HOST(instance), i); + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + continue; + } + + if (cmd->req_frame->mgrReq.syncFlag == 1) { + PS3_MGR_CMD_BACK_INC(instance, cmd, PS3_REPLY_WORD_FLAG_FAIL); + cmd->resp_frame->normalRespFrame.respStatus = PS3_DRV_MGR_BUSY; + cmd->cmd_state.state = PS3_CMD_STATE_COMPLETE; + LOG_FILE_WARN("hno:%u force complete sync mgr CFID:%d\n", + PS3_HOST(instance), i); + complete(&cmd->sync_done); + } else { + if (instance->is_need_event) { + if (cmd == instance->event_context.event_cmd || + cmd == instance->dev_context.vd_pending_cmd || + cmd == instance->webSubscribe_context.webSubscribe_cmd) { + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + LOG_INFO("trace_id[0x%llx], hno:%u Event cmd:%d ignore!\n", + cmd->trace_id, PS3_HOST(instance), cmd->index); + continue; + } + } + } + ps3_spin_unlock_irqrestore(&cmd->cmd_state.lock, cmd_lock_flags); + } + if (instance->is_need_event) { + if(instance->event_context.event_abort_cmd != NULL){ + abort_cmd = instance->event_context.event_abort_cmd; + instance->event_context.event_abort_cmd = NULL; + } + if(abort_cmd != NULL){ + ps3_task_cmd_free(instance, abort_cmd); + } + + if(instance->dev_context.vdpending_abort_cmd != NULL){ + abort_cmd = instance->dev_context.vdpending_abort_cmd; + instance->dev_context.vdpending_abort_cmd = NULL; + } + if(abort_cmd != NULL){ + ps3_task_cmd_free(instance, abort_cmd); + } + + if(instance->webSubscribe_context.web_abort_cmd != NULL){ + abort_cmd = instance->webSubscribe_context.web_abort_cmd; + instance->webSubscribe_context.web_abort_cmd = NULL; + } + if(abort_cmd != NULL){ + ps3_task_cmd_free(instance, abort_cmd); + } + } +} + +void ps3_cmd_force_stop(struct ps3_instance *instance) +{ + S32 ret_code = 0; + struct ps3_cmd_context *context = &instance->cmd_context; + if (context->cmd_buf == NULL) { + return; + } + + if (ps3_pci_err_recovery_get(instance)) { + ret_code = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + } else { + ret_code = ps3_get_requeue_or_reset(); + } + + ps3_r1x_conflict_queue_clean_all(instance, ret_code, PS3_FALSE); + + ps3_qos_hard_reset(instance); +#ifdef PS3_SUPPORT_INJECT + ps3_inject_clear(); +#endif + ps3_scsi_cmd_force_stop(instance); + ps3_mgr_cmd_force_stop(instance); +} + +Bool ps3_is_need_hard_reset(struct ps3_instance *instance) +{ + Bool need_hardreset = PS3_FALSE; + Bool is_support_halt = PS3_FALSE; + U32 hard_reset_enable = 0; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + if (!ps3_feature_support_reg_get(instance)) { + goto l_out; + } + + is_support_halt = PS3_IOC_STATE_HALT_SUPPORT(instance); + + LOG_INFO("hno:%u instance state not support hardreset!\n", + PS3_HOST(instance)); + if(is_support_halt && (cur_state != PS3_INSTANCE_STATE_DEAD)){ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_DEAD); + instance->ioc_adpter->ioc_force_to_halt(instance); + LOG_INFO("hno:%u instance state while support halt!\n", + PS3_HOST(instance)); + while (1) { + ps3_msleep(10); + } + } + + if(PS3_INSTANCE_ABNORMAL_FORCE_HARD_RECOVERY(instance)) { + need_hardreset = PS3_TRUE; + goto l_out; + } + + hard_reset_enable = ps3_hard_reset_enable_query(); + cur_state = ps3_atomic_read(&instance->state_machine.state); + + LOG_WARN("hno[%u], ready to hard reset,instance state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + if((!PS3_IOC_HARD_RECOVERY_SUPPORT(instance)) + || (!hard_reset_enable)){ + LOG_INFO("hno:%u instance state not support hardreset!\n", + PS3_HOST(instance)); + ps3_instance_state_transfer_to_dead(instance); + } else { + need_hardreset = PS3_TRUE; + } + +l_out: + return need_hardreset; +} + +S32 ps3_hard_reset_to_ready_with_doorbell(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + if (instance->peer_instance != NULL && + instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_PENDING) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_CONTINUE; + while (instance->recovery_context->parall_hardreset_state != PS3_PARALLEL_HARDRESET_STATE_INIT) { + ps3_msleep(PS3_PARALLEL_HARDRESET_STATE_WAIT_INIT_INTERVAL); + } + } else { + ret = ps3_hard_recovery_request(instance); + if (ret != PS3_SUCCESS){ + LOG_WARN("hno:%u hard recovery request NOK\n", + PS3_HOST(instance)); + goto l_out; + } + } + ps3_recovery_cancel_work_sync(instance); + +l_out: + return ret; +} +S32 ps3_init_fail_hard_reset_with_doorbell(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + LOG_WARN("hno[%u], ready to hard reset\n", PS3_HOST(instance)); + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW){ + goto l_out; + } + + if (instance->peer_instance != NULL && + instance->recovery_context->parall_hardreset_state == PS3_PARALLEL_HARDRESET_STATE_PENDING) { + instance->recovery_context->parall_hardreset_state = PS3_PARALLEL_HARDRESET_STATE_CONTINUE; + while (instance->recovery_context->parall_hardreset_state != PS3_PARALLEL_HARDRESET_STATE_INIT) { + ps3_msleep(PS3_PARALLEL_HARDRESET_STATE_WAIT_INIT_INTERVAL); + } + } else { + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret != PS3_SUCCESS){ + LOG_WARN("hno:%u hard recovery request NOK\n", + PS3_HOST(instance)); + goto l_out; + } + } + ps3_recovery_cancel_work_sync(instance); + + if (instance->ioc_adpter->ioc_state_get(instance) != PS3_FW_STATE_READY) { + ret = -PS3_FAILED; + } + + LOG_WARN("device[%d] hard reset success,exit init proc %d.\n", instance->pdev->dev.id, ret); + return ret; +l_out: + if (ps3_recovery_is_state_halt(instance)) { + LOG_WARN("hno:%u driver_state:DEAD or HALT now !!!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_end; + } + + if ((!PS3_IOC_HARD_RECOVERY_SUPPORT(instance)) + || (!ps3_hard_reset_enable_query())) { + LOG_ERROR("hno:%u soc feature unsupport Hard reset! need to be offline!\n", + PS3_HOST(instance)); + + ret = -PS3_FAILED; + ps3_msleep(PS3_DEFAULT_MGR_CMD_TIMEOUT * 1000); + goto l_end; + } + + ret = instance->ioc_adpter->ioc_force_to_fault(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("device[%d] doorbell fault NOK.\n", instance->pdev->dev.id); + } + + if (!instance->ioc_adpter->ioc_hard_reset) { + ret = -PS3_FAILED; + LOG_ERROR("device[%d] ioc_hard_reset is null.\n", instance->pdev->dev.id); + goto l_end; + } + ret = instance->ioc_adpter->ioc_hard_reset(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("device[%d] hard reset NOK,exit init proc.\n", instance->pdev->dev.id); + goto l_end; + } + LOG_WARN("device[%d] hard reset success,exit init proc.\n", instance->pdev->dev.id); + ret = -PS3_FAILED; +l_end: + return ret; +} + +S32 ps3_hardreset_handle_pre(struct ps3_instance *instance) +{ + U32 wait_count = 0; + ULong flags = 0; + + LOG_DEBUG("hno:%u functoin[%d], hardreset handle pre start\n", + PS3_HOST(instance), ps3_get_pci_function(instance->pdev)); + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_1, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", + PS3_HOST(instance)); + return -PS3_IN_PCIE_ERR; + } + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_NOT_SUPPORT, instance) + if(!PS3_IS_INSTANCE_PROBE_INIT(instance)) { + + if ((!PS3_IOC_HARD_RECOVERY_SUPPORT(instance)) + || (!ps3_hard_reset_enable_query())) { + LOG_ERROR("hno:%u soc feature unsupport Hard reset! need to be offline!\n", + PS3_HOST(instance)); + return -PS3_FAILED; + } + } + ps3_spin_lock_irqsave(&instance->recovery_context->recovery_lock, &flags); + if (instance->event_context.abort_eventcmd != 0) { + instance->event_context.abort_eventcmd = 0; + } + + if (instance->hardreset_event == 0) { + instance->hardreset_event = 1; + } + ps3_spin_unlock_irqrestore(&instance->recovery_context->recovery_lock, flags); + + if (PS3_IS_INSTANCE_PROBE(instance) && instance->is_scan_host_finish + && !instance->is_probe_finish) { + LOG_INFO("hno:%u recovery wait until probe finish/failed\n", + PS3_HOST(instance)); + while (wait_count < PS3_RECOVERY_WAIT_PROBE_FINISH_LOOP_COUNT) { + if (instance->is_probe_finish || instance->is_probe_failed) { + break; + } + + wait_count++; + ps3_msleep(PS3_RECOVERY_WAIT_LOOP_TIME_INTERVAL_20MS); + } + + LOG_INFO("hno:%u probe finish(%d)/failed(%d), continue recovery\n", + PS3_HOST(instance), instance->is_probe_finish, instance->is_probe_failed); + } + + ps3_wait_watchdog_dect_recovery(instance); + + LOG_DEBUG("hno:%u functoin[%d], hardreset handle pre end\n", + PS3_HOST(instance), ps3_get_pci_function(instance->pdev)); + + return PS3_SUCCESS; +} + +S32 ps3_hardreset_handle_wait_ready(struct ps3_instance *instance) +{ + S32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + U32 ioc_state = 0; + S32 ret = PS3_SUCCESS; + U16 cur_cnt = 0; + Bool printed = PS3_TRUE; + + LOG_DEBUG("hno:%u function[%d], hardreset handle wait ready start.\n", + PS3_HOST(instance), ps3_get_pci_function(instance->pdev)); + + instance->dump_context.is_hard_recovered = PS3_TRUE; + ioc_state = instance->ioc_adpter->ioc_state_get(instance); + LOG_DEBUG("hno:%u ioc state is %s! function:%d\n", + PS3_HOST(instance), ps3_ioc_state_print(ioc_state), ps3_get_pci_function(instance->pdev)); + + while(ps3_atomic_read(&instance->is_err_scsi_processing) > 0) { + ps3_msleep(10); + if (printed && ((++cur_cnt) * 10 > PS3_RECOVERY_WHILE_PRINT_REACH_TIME)) { + printed = PS3_FALSE; + LOG_WARN("host:%u wait ready wait err scsi process\n", PS3_HOST(instance)); + } + } + instance->ioc_adpter->irq_disable(instance); +#ifndef _WINDOWS + ps3_irqs_sync(instance); +#endif + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_6, instance) + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno:%u pci recovery resetting\n", PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_HARD_WAIT_READY_FAILED_F1, instance); + if ((ret = ps3_ioc_state_transfer_to_ready(instance)) != PS3_SUCCESS) { + LOG_ERROR("hno:%u hard reset to ready NOK,%s!\n", + PS3_HOST(instance), + ps3_ioc_state_print(ioc_state)); + if (ret == -PS3_IN_PCIE_ERR) { + err_code = PS3_RECOVERY_INTER_ERR_PCIE_ERR; + } else { + if (ps3_instance_state_transfer(instance->peer_instance, PS3_INSTANCE_STATE_READY, + PS3_INSTANCE_STATE_RECOVERY) != PS3_SUCCESS) { + LOG_WARN("hno:%u transfer to recovery NOK!\n", + PS3_HOST(instance->peer_instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + goto l_out; + } + err_code = PS3_RECOVERY_INTER_ERR_NEED_RECOVERY; + } + goto l_out; + } + if (instance->state_machine.is_load || \ + instance->state_machine.is_suspend) { + if (ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_RECOVERY,\ + PS3_INSTANCE_STATE_READY) != PS3_SUCCESS) { + LOG_ERROR("hno:%u transfer to ready NOK!\n", + PS3_HOST(instance)); + err_code = PS3_RECOVERY_INTER_ERR_INTERRUPT; + } + } + +l_out: + LOG_DEBUG("hno:%u function[%d], hardreset handle wait ready end.\n", + PS3_HOST(instance), ps3_get_pci_function(instance->pdev)); + + return err_code; +} + +S32 ps3_hardreset_handle_init_running(struct ps3_instance *instance) +{ + U32 err_code = PS3_RECOVERY_INTER_ERR_SUCCESS; + + if (!instance->is_probe_finish || instance->is_probe_failed || + !instance->state_machine.is_load) { + ps3_recovery_ready_to_force_cmd_stop(instance); + LOG_ERROR("hno:%u reset while probe or in shutdown/remove," + " finish[%d], failed[%d], is_load[%d]\n", + PS3_HOST(instance), instance->is_probe_finish, + instance->is_probe_failed, + instance->state_machine.is_load); + ps3_instance_state_transfer(instance, PS3_INSTANCE_STATE_READY, + PS3_INSTANCE_STATE_RECOVERY); + instance ->is_half_hard_reset = PS3_TRUE; + if (!instance->state_machine.is_load) { + ps3_ioc_notify_unload(instance); + } + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_9, instance) + err_code = ps3_hard_recovery_to_pre_operational(instance); +l_out: + return err_code; +} + +S32 ps3_hardreset_handle_post(struct ps3_instance *instance) +{ + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_12, instance) + return ps3_hard_recovery_to_operational(instance); +} + +S32 ps3_hardreset_handle_finish(struct ps3_instance *instance) +{ + U32 cur_state = 0; + S32 ret = PS3_SUCCESS; + + cur_state = ps3_atomic_read(&instance->state_machine.state); + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_FINISH_STATE_NOOPERATIONAL, &cur_state) + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL) { + ps3_instance_state_transfer_to_dead(instance); + LOG_ERROR("hno:%u hard reset NOK! cur_state:%s\n", + PS3_HOST(instance), + namePS3InstanceState(cur_state)); + return -PS3_FAILED; + } + + INJECT_START(PS3_ERR_IJ_FORCE_RECOVERY_PRE_PCIE_ERR_15, instance) + ret = ps3_recovery_complete(instance); + if(ret != PS3_SUCCESS){ + LOG_WARN("hno:%u hard reset opeational but complete failed! cur_state:%s,ret %d\n", + PS3_HOST(instance), namePS3InstanceState(cur_state),ret); + return ret; + } + + ps3_hard_recovery_state_finish(instance); + LOG_INFO("hno:%u hard reset finish! cur_state:%s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + + return PS3_SUCCESS; +} + +S32 ps3_hardreset_handle_offline(struct ps3_instance *instance) +{ + U32 cur_state = 0; + ps3_instance_state_transfer_to_dead(instance); + cur_state = ps3_atomic_read(&instance->state_machine.state); + LOG_ERROR("hno:%u hard reset finish! cur_state:%s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + return PS3_SUCCESS; +} + +S32 ps3_softreset_handle_pre(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + ps3_cmd_reset_flag_set(instance, PS3_CMD_FLAG_SOFTRESET); + + ret = ps3_ioc_state_transfer_wait_to_running(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u soft recovery to running failed!\n", + PS3_HOST(instance)); + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + ret = ps3_soft_recovery_cmd_reply_polling_check(instance, PS3_SOFT_RESET_WAIT_TIMEOUT); + if (ret != PS3_RECOVERY_INTER_ERR_SUCCESS) { + LOG_ERROR("hno:%u pending mgr cmd no reply all!\n", + PS3_HOST(instance)); + goto l_out; + } + + ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + LOG_INFO("hno:%u soft recovery to pre-operational success!\n", + PS3_HOST(instance)); +l_out: + return ret; +} + +S32 ps3_softreset_handle_post(struct ps3_instance *instance) +{ + S32 ret = PS3_RECOVERY_INTER_ERR_SUCCESS; + + if (!ps3_ioc_recovery_count_get(instance, + &instance->recovery_context->ioc_recovery_count)) { + ret = PS3_RECOVERY_INTER_ERR_FAILED; + goto l_out; + } + + LOG_INFO("hno:%u pre-operational to operational success!,reset count:%d\n", + PS3_HOST(instance), instance->recovery_context->ioc_recovery_count); +l_out: + return ret; +} + +S32 ps3_hard_recovery_request_with_retry(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 count = 0; + + while ((ret = ps3_hard_recovery_request(instance)) == -PS3_RETRY) { + if (count++ == ps3_use_hard_reset_max_retry()) { + ret = -PS3_FAILED; + break; + } + ps3_mdelay(10); + } + + return ret; +} +S32 ps3_recovery_request_with_retry(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + U32 count = 0; + + while ((ret = ps3_recovery_request(instance)) == -PS3_RETRY) { + if (count++ == ps3_use_hard_reset_max_retry()) { + ret = -PS3_FAILED; + break; + } + ps3_mdelay(10); + } + + return ret; +} diff --git a/drivers/scsi/ps3stor/ps3_recovery.h b/drivers/scsi/ps3stor/ps3_recovery.h new file mode 100644 index 0000000000000000000000000000000000000000..d7e569f5e2a2a1ddb5fb8472c19a1cf60374580b --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_recovery.h @@ -0,0 +1,158 @@ + +#ifndef _PS3_RECOVERY_H_ +#define _PS3_RECOVERY_H_ + +#ifndef _WINDOWS +#include +#include +#include +#include +#else +#include "ps3_worker.h" +#endif + +#include "ps3_platform_utils.h" +#include "ps3_inner_data.h" +#include "ps3_driver_log.h" +enum { + PS3_SOFT_RECOVERY_PROBE_PROCESS = 0, + PS3_SOFT_RECOVERY_SHALLOW = 1, + PS3_SOFT_RECOVERY_DEEP = 2, + PS3_SOFT_RECOVERY_IOC_RECOVERY = 3, + PS3_SOFT_RECOVERY_FINISH = 4, + PS3_HARD_RECOVERY_DECIDE = 5, + PS3_HARD_RECOVERY_SHALLOW = 6, + PS3_HARD_RECOVERY_FINISH = 7, + PS3_RESET_LOG_INTERVAL = 8, +}; + +enum { + PS3_HOST_RESET_INIT = 0, + PS3_HOST_RESET_START = 1, + PS3_HOST_RESET_HARD_RESET_DONE = 2, +}; +enum { + PS3_PARALLEL_HARDRESET_STATE_INIT = 0, + PS3_PARALLEL_HARDRESET_STATE_PENDING, + PS3_PARALLEL_HARDRESET_STATE_CONTINUE, +}; +#define PS3_PARALLEL_HARDRESET_STATE_WAIT_INIT_INTERVAL (5) +#define PS3_RECOVERY_CONTEXT_MAX_NUM (8) +#define PS3_RECOVERY_IRQ_NAME_MAX_LENTH (48) +#define PS3_RECOVERY_WHILE_PRINT_REACH_TIME (10 * 1000) + +enum { + PS3_HEARTBEAT_NULL = 0, + PS3_HEARTBEAT_HARDRESET_DECIDE = 1, + PS3_HEARTBEAT_HARDRESET_RECOVERY = 2, + PS3_HEARTBEAT_HARDRESET_RETRY = 3, +}; + +enum { + PS3_IOC_CANNOT_HARDRESET = 0, + PS3_IOC_CAN_HARDRESET = 1, +}; + +struct ps3_recovery_context +{ + ps3_mutex free_cmd_lock; + ps3_spinlock recovery_lock; + ps3_spinlock ps3_hardreset_lock; + U32 ioc_recovery_count; + U8 recovery_state; + U8 reserved1; + U8 host_reset_state; + U8 heartbeat_recovery; +#ifndef _WINDOWS + struct workqueue_struct *recovery_wq; + S8 recovery_wq_name[20]; + struct work_struct recovery_work; +#else + struct ps3_worker recovery_work; +#endif + struct ps3_instance *instance[2]; + struct ps3_instance *work_instance; + S32 recovery_result; + U32 hardreset_count; + U8 parall_hardreset_state; + U8 instance_change; + U8 reserved[6]; + ps3_atomic32 hardreset_ref; + ps3_mutex ps3_watchdog_recovery_mutex; +}; +#define PS3_IS_INTERRUPT_SOFT_RECOVERY(instance) \ + (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) + +#define PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance) (PS3_IS_INSTANCE_PROBE(instance) || \ + PS3_IS_INSTANCE_REMOVE(instance) || PS3_IS_INSTANCE_SUSPEND_OR_RESUME(instance)) + +#define PS3_IS_INSTANCE_PROBE(instance) (!(instance)->state_machine.is_suspend && !((instance)->is_probe_finish || \ + (instance)->is_probe_failed)) + +#define PS3_IS_INSTANCE_REMOVE(instance) (!(instance)->state_machine.is_suspend && ((instance)->is_probe_finish || \ + (instance)->is_probe_failed) && !(instance)->state_machine.is_load) + +#define PS3_INSTANCE_ABNORMAL_FORCE_HARD_RECOVERY(instance) (PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance) || \ + ((instance)->peer_instance != NULL && PS3_IS_INSTANCE_NOT_LOAD_NORMAL((instance)->peer_instance))) + +#define PS3_IS_INSTANCE_PROBE_INIT(instance) (!((instance)->is_probe_finish || (instance)->is_probe_failed) && \ + !(instance)->state_machine.is_load) + +#define PS3_IS_INSTANCE_SUSPEND_OR_RESUME(instance) (PS3_IS_INSTANCE_SUSPEND(instance) || \ + PS3_IS_INSTANCE_RESUME(instance)) + +#define PS3_IS_INSTANCE_SUSPEND(instance) ((instance)->state_machine.is_suspend && \ + (instance)->is_suspend) + +#define PS3_IS_INSTANCE_RESUME(instance) ((instance)->state_machine.is_suspend && \ + (instance)->is_resume) + +S32 ps3_recovery_context_init(struct ps3_instance *instance); + +void ps3_recovery_function_init(struct ps3_instance *instance); + +void ps3_recovery_context_exit(struct ps3_instance *instance); + +void ps3_recovery_clean(struct ps3_instance *instance); + +void ps3_recovery_destory(struct ps3_instance *instance); + +S32 ps3_recovery_request(struct ps3_instance *instance); + +S32 ps3_hard_recovery_request(struct ps3_instance *instance); + +void ps3_scsi_cmd_force_stop(struct ps3_instance *instance); +void ps3_mgr_cmd_force_stop(struct ps3_instance *instance); + +S32 ps3_recovery_cancel_work_sync(struct ps3_instance *instance); + +#ifndef _WINDOWS +S32 ps3_hard_reset_to_ready_with_doorbell(struct ps3_instance *instance); +S32 ps3_init_fail_hard_reset_with_doorbell(struct ps3_instance *instance); +Bool ps3_is_need_hard_reset(struct ps3_instance *instance); + +void ps3_recovery_work_queue_destory(struct ps3_instance *instance); +#endif + +S32 ps3_hardreset_handle_pre(struct ps3_instance *instance); + +S32 ps3_hardreset_handle_wait_ready(struct ps3_instance *instance); + +S32 ps3_hardreset_handle_init_running(struct ps3_instance *instance); + +S32 ps3_hardreset_handle_post(struct ps3_instance *instance); + +S32 ps3_hardreset_handle_finish(struct ps3_instance *instance); + +S32 ps3_hardreset_handle_offline(struct ps3_instance *instance); + +S32 ps3_softreset_handle_pre(struct ps3_instance *instance); + +S32 ps3_softreset_handle_post(struct ps3_instance *instance); +S32 ps3_hard_recovery_request_with_retry(struct ps3_instance *instance); +S32 ps3_recovery_request_with_retry(struct ps3_instance *instance); +irqreturn_t ps3_recovery_irq_handler(S32 virq, void *dev_id); +S32 ps3_recovery_irq_start(struct ps3_instance *instance); + +void ps3_cmd_force_stop(struct ps3_instance *instance); +#endif diff --git a/drivers/scsi/ps3stor/ps3_sas_transport.c b/drivers/scsi/ps3stor/ps3_sas_transport.c new file mode 100644 index 0000000000000000000000000000000000000000..52420a317f03fca28aa687fa1b4c1294808e6f80 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_sas_transport.c @@ -0,0 +1,899 @@ +#ifndef _WINDOWS +#include + +#include "ps3_sas_transport.h" +#include "ps3_mgr_channel.h" +#include "ps3_irq.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_mgr_cmd.h" +#include "ps3_driver_log.h" +#include "ps3_device_manager_sas.h" + +static struct scsi_transport_template *ps3_sas_transport_template = NULL; +extern struct ps3_sas_node* ps3_sas_find_node_by_sas_addr( + struct ps3_instance *instance, U64 sas_addr); +struct scsi_transport_template *ps3_sas_transport_get(void) +{ + return ps3_sas_transport_template; +} + +static inline struct ps3_instance *phy_to_ps3_instance(struct sas_phy *phy) +{ + struct Scsi_Host *s_host = dev_to_shost(phy->dev.parent); + return (struct ps3_instance *)s_host->hostdata; +} + +static inline struct ps3_instance *rphy_to_ps3_instance(struct sas_rphy *rphy) +{ + struct Scsi_Host *s_host = dev_to_shost(rphy->dev.parent); + return (struct ps3_instance *)s_host->hostdata; +} + +static inline S32 ps3_sas_request_pre_check(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + if (!instance->state_machine.is_load) { + LOG_WARN("hno:%u instance state not is_load\n", PS3_HOST(instance)); + ret = -EFAULT; + goto l_out; + } + + if (!ps3_is_instance_state_normal(instance, PS3_TRUE)) { + ret = -EFAULT; + goto l_out; + } + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN("hno[%u] host in pci recovery\n", + PS3_HOST(instance)); + ret = -EFAULT; + goto l_out; + } + +l_out: + return ret; +} + +static inline S32 ps3_sas_smp_pre_check(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + ret = ps3_sas_request_pre_check(instance); + if (ret != PS3_SUCCESS) { + goto l_out; + } + + LOG_INFO("hno:%u ready get semaphore\n", PS3_HOST(instance)); + if (down_interruptible(&instance->sas_dev_context.ps3_sas_smp_semaphore)) { + LOG_WARN("hno:%u smp concurrency full\n", + PS3_HOST(instance)); + ret = -EFAULT; + } + LOG_INFO("hno:%u got semaphore\n", PS3_HOST(instance)); + +l_out: + return ret; +} + +static inline void ps3_sas_linkerror_reqframe_build(struct ps3_cmd *cmd, + struct sas_phy *phy, U8 encl_id) +{ + PS3MgrReqFrame_s *mgrReq = &cmd->req_frame->mgrReq; + mgrReq->reqHead.timeout = cmd->time_out; + mgrReq->reqHead.traceID = cmd->trace_id; + mgrReq->reqHead.cmdType = PS3_CMD_SAS_MANAGEMENT; + mgrReq->reqHead.cmdSubType = PS3_SAS_GET_LINK_ERR; + mgrReq->reqHead.cmdFrameID = cmd->index; + mgrReq->reqHead.control = 0; + mgrReq->syncFlag = 1; + mgrReq->timeout = 0; + mgrReq->sgeOffset = + offsetof(PS3MgrReqFrame_s, sgl) >> PS3_MGR_CMD_SGL_OFFSET_DWORD_SHIFT; + mgrReq->sgeCount = 1; + mgrReq->sgl[0].length = cpu_to_le32(sizeof(struct PS3LinkErrInfo)); + mgrReq->sgl[0].addr = cpu_to_le64(cmd->ext_buf_phys); + mgrReq->sgl[0].lastSge = 1; + mgrReq->sgl[0].ext = 0; + + mgrReq->value.sasMgr.sasAddr = cpu_to_le64(phy->identify.sas_address); + mgrReq->value.sasMgr.enclID = encl_id; + mgrReq->value.sasMgr.phyCount = 1; + mgrReq->value.sasMgr.startPhyID = phy->identify.phy_identifier; +} + +S32 ps3_sas_linkerrors_get(struct sas_phy *phy) +{ + S32 ret = 0; + S32 send_result = PS3_SUCCESS; + U8 encl_id = PS3_SAS_INVALID_ID; + struct ps3_cmd *cmd = NULL; + struct PS3LinkErrInfo *erroInfo = NULL; + struct ps3_instance *instance = phy_to_ps3_instance(phy); + + ret = ps3_sas_smp_pre_check(instance); + if (ret != PS3_SUCCESS) { + ret = -ENXIO; + goto l_out; + } + + encl_id = ps3_sas_encl_id_get(instance, phy->identify.sas_address); + INJECT_START(PS3_ERR_IJ_SAS_ENCL_ID_GET_FAILED, &encl_id) + if (encl_id == PS3_SAS_INVALID_ID) { + LOG_ERROR("hno:%u cannot foud PS3 node by sas_addr[%016llx]\n", + PS3_HOST(instance), phy->identify.sas_address); + ret = -EINVAL; + goto l_no_free_cmd; + } + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + INJECT_START(PS3_ERR_IJ_V2_IS_LOAD_FALSE1, instance); + if (ps3_sas_request_pre_check(instance) != PS3_SUCCESS) { + LOG_WARN_LIM("sas_addr[%016llx], hno:%u smp linkerror pre check NOK\n", + phy->identify.sas_address, PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -ENXIO; + goto l_no_free_cmd; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_MGR_CMD_ALLOC_FAILED, &cmd) + if (cmd == NULL) { + LOG_WARN("hno:%u not get a cmd packet\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -ENOMEM; + goto l_no_free_cmd; + } + + cmd->time_out = PS3_SAS_TIMEOUT_SEC; + cmd->is_interrupt = PS3_DRV_FALSE; + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], sas_addr[%016llx] get mgr cmd succeed\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, phy->identify.sas_address); + + ps3_sas_linkerror_reqframe_build(cmd, phy, encl_id); + ps3_mgr_cmd_word_build(cmd); + INJECT_START(PS3_ERR_IJ_CMD_POLLING, &cmd) + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret == -PS3_CMD_NO_RESP) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -ETIMEDOUT; + goto l_no_free_cmd; + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -EFAULT; + } else { + erroInfo = (struct PS3LinkErrInfo *)cmd->ext_buf; + phy->invalid_dword_count = le32_to_cpu(erroInfo->invalidDwordCount); + phy->running_disparity_error_count = + le32_to_cpu(erroInfo->runningDisparityErrCount); + phy->loss_of_dword_sync_count = + le32_to_cpu(erroInfo->lossOfDwordSyncCount); + phy->phy_reset_problem_count = + le32_to_cpu(erroInfo->phyResetProblemCount); + ret = 0; + } + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], end, ret[%d]\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, ret); + + ps3_mgr_cmd_free(instance, cmd); +l_no_free_cmd: + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); +l_out: + return ret; +} + +S32 ps3_sas_enclosure_identifier_get(struct sas_rphy *rphy, u64 *identifier) +{ + S32 ret = 0; + struct ps3_instance *instance = rphy_to_ps3_instance(rphy); + *identifier = 0; + + LOG_DEBUG("hno:%u ----1---ready get encl identifier sas_addr[%016llx]\n", + PS3_HOST(instance), rphy->identify.sas_address); + + ret = ps3_sas_smp_pre_check(instance); + if (ret != PS3_SUCCESS) { + ret = -ENXIO; + goto l_out; + } + + LOG_DEBUG("hno:%u ready get encl identifier sas_addr[%016llx]\n", + PS3_HOST(instance), rphy->identify.sas_address); + + *identifier = ps3_sas_rphy_parent_sas_addr_get(instance, rphy->identify.sas_address); + INJECT_START(PS3_ERR_IJ_RPHY_PARENT_SAS_ADDR_GET_FAILED,identifier) + if (*identifier == PS3_SAS_INVALID_SAS_ADDR) { + ret = -ENXIO; + *identifier = 0; + } + + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); +l_out: + LOG_DEBUG("hno:%u end get encl identifier sas_addr[%016llx], identifier[%llu]\n", + PS3_HOST(instance), rphy->identify.sas_address, *identifier); + return ret; +} + +S32 ps3_sas_bay_identifier_get(struct sas_rphy *rphy) +{ + U32 solt_id = 0; + struct ps3_instance *instance = rphy_to_ps3_instance(rphy); + + LOG_DEBUG("hno:%u ----1---ready get bay identifier sas_addr[%016llx]\n", + PS3_HOST(instance), rphy->identify.sas_address); + + if (ps3_sas_smp_pre_check(instance) != PS3_SUCCESS) { + solt_id = -ENXIO; + goto l_out; + } + + LOG_DEBUG("hno:%u ready get bay identifier sas_addr[%016llx]\n", + PS3_HOST(instance), rphy->identify.sas_address); + + if (ps3_sas_rphy_slot_get(instance, rphy->identify.sas_address, &solt_id) + != PS3_SUCCESS) { + solt_id = -ENXIO; + } + + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); +l_out: + LOG_DEBUG("hno:%u end get bay identifier sas_addr[%016llx], slot_id[%d]\n", + PS3_HOST(instance), rphy->identify.sas_address, solt_id); + return solt_id; +} + +static inline void ps3_sas_ctrl_reqframe_build(struct ps3_cmd *cmd, + struct sas_phy *phy, + enum PhyCtrl ctrl_code) +{ + PS3MgrReqFrame_s *mgrReq = &cmd->req_frame->mgrReq; + mgrReq->reqHead.timeout = cmd->time_out; + mgrReq->reqHead.traceID = cmd->trace_id; + mgrReq->reqHead.cmdType = PS3_CMD_SAS_MANAGEMENT; + mgrReq->reqHead.cmdSubType = PS3_SAS_PHY_CTRL; + mgrReq->reqHead.cmdFrameID = cmd->index; + mgrReq->reqHead.control = 0; + mgrReq->syncFlag = 1; + mgrReq->timeout = 0; + mgrReq->sgeCount = 0; + + mgrReq->value.phySet.sasAddr = + cpu_to_le64(phy->identify.sas_address); + mgrReq->value.phySet.phyCtrl = ctrl_code; + mgrReq->value.phySet.phyID = phy->identify.phy_identifier; + mgrReq->value.phySet.maxLinkRate = phy->maximum_linkrate; + mgrReq->value.phySet.minLinkRate = phy->minimum_linkrate; +} + +static inline S32 __ps3_sas_phy_ctrl(struct sas_phy *phy, + enum PhyCtrl ctrl_code) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_instance *instance = phy_to_ps3_instance(phy); + + ret = ps3_sas_smp_pre_check(instance); + if (ret != PS3_SUCCESS) { + ret = -ENXIO; + goto l_out; + } + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + INJECT_START(PS3_ERR_IJ_V2_IS_LOAD_FALSE1, instance); + if (ps3_sas_request_pre_check(instance) != PS3_SUCCESS) { + LOG_WARN_LIM("sas_addr[%016llx], hno:%u smp phyctrl pre check NOK\n", + phy->identify.sas_address, PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -ENXIO; + goto l_no_free_cmd; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_MGR_CMD_ALLOC_FAILED, &cmd) + if (cmd == NULL) { + LOG_WARN("hno:%u not get a cmd packet\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -ENOMEM; + goto l_no_free_cmd; + } + cmd->time_out = PS3_SAS_TIMEOUT_SEC; + cmd->is_interrupt = PS3_DRV_FALSE; + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], sas_addr[%016llx] ctrl_code[%s] get mgr cmd succeed\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, + phy->identify.sas_address, namePhyCtrl((enum PhyCtrl)ctrl_code)); + + ps3_sas_ctrl_reqframe_build(cmd, phy, ctrl_code); + ps3_mgr_cmd_word_build(cmd); + INJECT_START(PS3_ERR_IJ_CMD_POLLING, &cmd) + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret == -PS3_CMD_NO_RESP) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -ETIMEDOUT; + goto l_no_free_cmd; + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -EFAULT; + } + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], end, ret[%d]\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, ret); + ps3_mgr_cmd_free(instance, cmd); +l_no_free_cmd: + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); +l_out: + return ret; +} + +S32 ps3_sas_phy_reset(struct sas_phy *phy, int hard_reset) +{ + enum PhyCtrl ctrl_code = + hard_reset ? PS3_SAS_CTRL_RESET_HARD : PS3_SAS_CTRL_RESET; + struct sas_phy tmp_phy = *phy; + tmp_phy.maximum_linkrate = 0; + tmp_phy.minimum_linkrate = 0; + + LOG_INFO("enter phy reset, phy sas_addr[%016llx], is_hard[%d]\n", + phy->identify.sas_address, hard_reset); + return __ps3_sas_phy_ctrl(&tmp_phy, ctrl_code); +} + +S32 ps3_sas_phy_enable(struct sas_phy *phy, int enable) +{ + enum PhyCtrl ctrl_code = + enable ? PS3_SAS_CTRL_RESET : PS3_SAS_CTRL_DISABLE; + struct sas_phy tmp_phy = *phy; + tmp_phy.maximum_linkrate = 0; + tmp_phy.minimum_linkrate = 0; + + LOG_INFO("enter phy enable, phy sas_addr[%016llx], is_enable[%d]\n", + phy->identify.sas_address, enable); + return __ps3_sas_phy_ctrl(&tmp_phy, ctrl_code); +} + +S32 ps3_sas_update_phy_info(struct sas_phy *phy) +{ + S32 ret = -PS3_FAILED; + struct PS3SasMgr sas_req_param; + + struct ps3_instance *instance = phy_to_ps3_instance(phy); + struct PS3PhyInfo *phy_info = instance->sas_dev_context.ps3_sas_phy_buff; + ULong flags = 0; + + struct ps3_sas_node* sas_node = ps3_sas_find_node_by_sas_addr( + instance, phy->identify.sas_address); + + memset(&sas_req_param, 0, sizeof(sas_req_param)); + sas_req_param.enclID = sas_node->encl_id; + sas_req_param.sasAddr =cpu_to_le64(sas_node->sas_address); + sas_req_param.startPhyID = phy->identify.phy_identifier; + sas_req_param.phyCount = 1; + + LOG_DEBUG("hno:%u ready get phys[%d] of encl_id[%d] !\n", + PS3_HOST(instance), phy->identify.phy_identifier, sas_req_param.enclID); + + memset(phy_info, 0, PS3_SAS_REQ_BUFF_LEN); + ret = ps3_sas_phy_get(instance, &sas_req_param); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u get phy info NOK\n", + PS3_HOST(instance)); + goto l_out; + } + + spin_lock_irqsave(&instance->sas_dev_context.ps3_sas_node_lock, flags); + LOG_INFO_IN_IRQ(instance, "hno:%u ready update phy %d of encl_id[%d]!\n", + PS3_HOST(instance), phy->identify.phy_identifier, sas_req_param.enclID); + + ps3_sas_node_phy_update(instance, &sas_node->phys[phy->identify.phy_identifier], &phy_info[0]); + spin_unlock_irqrestore(&instance->sas_dev_context.ps3_sas_node_lock, flags); +l_out: + return ret; +} + +S32 ps3_sas_linkrates_set(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + S32 ret = PS3_SUCCESS; + U8 tmp_min = 0; + U8 tmp_max = 0; + LOG_INFO("enter link rate set, phy sas_addr[%016llx]," + "minimum_linkrate[%d], maximum_linkrate[%d]\n", + phy->identify.sas_address, rates->minimum_linkrate, + rates->maximum_linkrate); + + if (!rates->minimum_linkrate) { + rates->minimum_linkrate = phy->minimum_linkrate; + } else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) { + rates->minimum_linkrate = phy->minimum_linkrate_hw; + } + + if (!rates->maximum_linkrate) { + rates->maximum_linkrate = phy->maximum_linkrate; + } else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) { + rates->maximum_linkrate = phy->maximum_linkrate_hw; + } + + if (rates->maximum_linkrate < phy->minimum_linkrate || + rates->minimum_linkrate> phy->maximum_linkrate) { + LOG_ERROR("linkrate set param NOK, %d phy sas_addr[%016llx]," + "rate minimum_linkrate[%d] > cur maximum_linkrate[%d] or" + "rate maximum_linkrate[%d] < cur minimum_linkrate[%d]\n", + phy->identify.phy_identifier, phy->identify.sas_address, + rates->minimum_linkrate, phy->maximum_linkrate, + rates->maximum_linkrate, phy->minimum_linkrate); + ret = -EINVAL; + goto l_out; + } + + tmp_min = phy->minimum_linkrate; + tmp_max = phy->maximum_linkrate; + + phy->minimum_linkrate = rates->minimum_linkrate; + phy->maximum_linkrate = rates->maximum_linkrate; + + ret = __ps3_sas_phy_ctrl(phy, PS3_SAS_CTRL_RESET); + if (ret != PS3_SUCCESS) { + LOG_ERROR("linkrate NOK, phy sas_addr[%016llx]," + "minimum_linkrate[%d], maximum_linkrate[%d]\n", + phy->identify.sas_address, rates->minimum_linkrate, + rates->maximum_linkrate); + + phy->minimum_linkrate = tmp_min; + phy->maximum_linkrate = tmp_max; + goto l_out; + } + + ps3_sas_update_phy_info(phy); +l_out: + return ret; +} + +static inline void ps3_sas_smp_reqframe_build(struct ps3_cmd *cmd, + U64 sas_addr, U32 req_data_len) +{ + PS3MgrReqFrame_s *mgrReq = &cmd->req_frame->mgrReq; + mgrReq->reqHead.timeout = cmd->time_out; + mgrReq->reqHead.traceID = cmd->trace_id; + mgrReq->reqHead.cmdType = PS3_CMD_SAS_MANAGEMENT; + mgrReq->reqHead.cmdSubType = PS3_SAS_SMP_REQUEST; + mgrReq->reqHead.cmdFrameID = cmd->index; + mgrReq->reqHead.control = 0; + mgrReq->syncFlag = 1; + mgrReq->timeout = 0; + + mgrReq->sgeOffset = + offsetof(PS3MgrReqFrame_s, sgl) >> PS3_MGR_CMD_SGL_OFFSET_DWORD_SHIFT; + mgrReq->sgeCount = 1; + mgrReq->sgl[0].length = + cpu_to_le32(cmd->instance->cmd_context.ext_buf_size); + mgrReq->sgl[0].addr = cpu_to_le64(cmd->ext_buf_phys); + mgrReq->sgl[0].lastSge = 1; + mgrReq->sgl[0].ext = 0; + + mgrReq->value.sasMgr.sasAddr = cpu_to_le64(sas_addr); + mgrReq->value.sasMgr.reqLen = cpu_to_le16(req_data_len - PS3_SMP_CRC_LEN); +} + +static inline void show_smp(U8 *data, U16 len) +{ + U16 i = 0; + S8 tmp_buf[256] = {0}; + S8 *p_tmp = tmp_buf; + LOG_DEBUG("smp frame data start\n"); + while (len != 0) { + memset(tmp_buf, 0, sizeof(S8) * 256); + for (i = 0; i < 32 && len != 0; i++, len--) { + snprintf(p_tmp, 4, " %02x", *data++); + p_tmp += 3; + } + LOG_DEBUG("smp frame data is ==[%s]==\n", tmp_buf); + p_tmp = tmp_buf; + } + + LOG_DEBUG("smp frame data end\n"); +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,14,0) + +static inline U32 ps3_sas_req_to_ext_buf(struct ps3_instance *instance, + struct request *req, void *ext_buf) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + struct bio_vec bvec; + struct bvec_iter iter; +#else + struct bio_vec *bvec = NULL; + U32 i = 0; +#endif + + U32 req_len = 0; + + INJECT_START(PS3_ERR_IJ_SAS_REQ_EXT_BUF_INVALLID, req) + if (unlikely(blk_rq_bytes(req) > instance->cmd_context.ext_buf_size)) { + LOG_ERROR("hno:%u request is too big!(req_len:%d > ext_buf_len:%d\n", + PS3_HOST(instance), blk_rq_bytes(req), + instance->cmd_context.ext_buf_size); + goto l_out; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + bio_for_each_segment(bvec, req->bio, iter) { + memcpy((U8*)ext_buf + req_len, + page_address(bvec.bv_page) + bvec.bv_offset, + bvec.bv_len); + req_len += bvec.bv_len; + } +#else + bio_for_each_segment(bvec, req->bio, i) { + memcpy((U8*)ext_buf + req_len, + page_address(bvec->bv_page) + bvec->bv_offset, + bvec->bv_len); + req_len += bvec->bv_len; + } +#endif + +l_out: + return req_len; +} + +static inline S32 ps3_sas_ext_buf_to_rsp(struct ps3_instance *instance, + struct request *req, void *ext_buf) +{ + S32 ret = PS3_SUCCESS; + struct request *rsp = req->next_rq; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + struct bio_vec bvec; + struct bvec_iter iter; +#else + struct bio_vec *bvec = NULL; + U32 i = 0; +#endif + U32 offset = 0; + U16 rsq_data_len = 0; + U16 smp_len = 0; + + INJECT_START(PS3_ERR_IJ_EXT_BUF_TO_RSP_INVALLID, &rsp) + if (rsp == NULL) { + ret = -PS3_FAILED; + LOG_ERROR("hno:%u rsp == NULL\n", PS3_HOST(instance)); + goto l_out; + } + + rsq_data_len = min(blk_rq_bytes(rsp), instance->cmd_context.ext_buf_size); + + smp_len = ((U8*)ext_buf)[3] * 4 + 4; + rsp->resid_len -= smp_len; + LOG_DEBUG("hno:%u smp frame len[%d], rsq_data_len[%d]\n", + PS3_HOST(instance), smp_len, rsq_data_len); + + rsq_data_len = min(smp_len, rsq_data_len); + + show_smp((U8*)ext_buf, rsq_data_len); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0)) + bio_for_each_segment(bvec, rsp->bio, iter) { + if (rsq_data_len <= bvec.bv_len) { + memcpy(page_address(bvec.bv_page) + bvec.bv_offset, + (U8*)ext_buf + offset, rsq_data_len); + break; + } else { + memcpy(page_address(bvec.bv_page) + bvec.bv_offset, + (U8*)ext_buf + offset, bvec.bv_len); + rsq_data_len -= bvec.bv_len; + } + offset += bvec.bv_len; + } +#else + bio_for_each_segment(bvec, rsp->bio, i) { + if (rsq_data_len <= bvec->bv_len) { + memcpy(page_address(bvec->bv_page) + bvec->bv_offset, + (U8*)ext_buf + offset, rsq_data_len); + break; + } else { + memcpy(page_address(bvec->bv_page) + bvec->bv_offset, + (U8*)ext_buf + offset, bvec->bv_len); + rsq_data_len -= bvec->bv_len; + } + offset += bvec->bv_len; + } +#endif +l_out: + return ret; +} +S32 ps3_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, + struct request *req) +{ + S32 ret = -PS3_FAILED; + S32 send_result = PS3_SUCCESS; + struct ps3_instance *instance = (struct ps3_instance *)shost->hostdata; + struct ps3_cmd *cmd = NULL; + U32 req_data_len = 0; + U64 sas_addr = 0; + struct ps3_sas_node *ps3_sas_node = NULL; + + ret = ps3_sas_smp_pre_check(instance); + if (ret != PS3_SUCCESS) { + ret = -EFAULT; + goto l_out; + } + + sas_addr = (rphy) ? (rphy->identify.sas_address) : (instance->sas_dev_context.ps3_hba_sas.sas_address); + ps3_sas_node = ps3_sas_find_node_by_sas_addr(instance, sas_addr); + INJECT_START(PS3_ERR_IJ_SAS_NODE_NOT_FOUND, &ps3_sas_node) + if (ps3_sas_node == NULL) { + LOG_ERROR("hno:%u cannot find node[%llx] !\n", + PS3_HOST(instance), sas_addr); + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); + ret = -EFAULT; + goto l_out; + } + + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + INJECT_START(PS3_ERR_IJ_V2_IS_LOAD_FALSE1, instance); + if (ps3_sas_request_pre_check(instance) != PS3_SUCCESS) { + LOG_WARN_LIM("sas_addr[%016llx], hno:%u smp pre check NOK\n", + sas_addr, PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -EFAULT; + goto l_no_free_cmd; + } + cmd = ps3_mgr_cmd_alloc(instance); + INJECT_START(PS3_ERR_IJ_MGR_CMD_ALLOC_FAILED, &cmd) + if (cmd == NULL) { + LOG_WARN("hno:%u not get a cmd packet\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -ENOMEM; + goto l_no_free_cmd; + } + cmd->time_out = PS3_SAS_TIMEOUT_SEC; + cmd->is_interrupt = PS3_DRV_FALSE; + + req_data_len = ps3_sas_req_to_ext_buf(instance, req, cmd->ext_buf); + if (req_data_len == 0) { + ret = -ENOMEM; + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + goto l_out_failed; + } + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], sas_addr[%016llx], len[%u] send smp req\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, sas_addr, req_data_len); + + ps3_sas_smp_reqframe_build(cmd, sas_addr, req_data_len); + ps3_mgr_cmd_word_build(cmd); + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret == -PS3_CMD_NO_RESP) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -ETIMEDOUT; + goto l_no_free_cmd; + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -ENXIO; + if (ret == -PS3_TIMEOUT) { + ret = -ETIMEDOUT; + } + goto l_out_failed; + } + + ret = ps3_sas_ext_buf_to_rsp(instance, req, cmd->ext_buf); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u %d smp response NOK CFID[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID); + ret = -EINVAL; + goto l_out_failed; + } + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], end, ret[%d]\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, ret); +l_out_failed: + ps3_mgr_cmd_free(instance, cmd); +l_no_free_cmd: + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); +l_out: + return ret; +} +#else + +static inline U32 ps3_sas_req_to_ext_buf(struct ps3_instance *instance, + struct bsg_buffer *req_buf, void *ext_buf) +{ + U32 req_len = 0; + + if (unlikely(req_buf->payload_len > instance->cmd_context.ext_buf_size)) { + LOG_ERROR("hno:%u request is too big!(req_len:%d > ext_buf_len:%d\n", + PS3_HOST(instance), req_buf->payload_len, + instance->cmd_context.ext_buf_size); + goto l_out; + } + + req_len = sg_copy_to_buffer(req_buf->sg_list, req_buf->sg_cnt, ext_buf, + req_buf->payload_len); +l_out: + return req_len; +} + +static inline U32 ps3_sas_ext_buf_to_rsp(struct ps3_instance *instance, + struct bsg_buffer *rsp_buf, void *ext_buf) +{ + U16 rsq_data_len = 0; + U16 smp_len = 0; + + rsq_data_len = min(rsp_buf->payload_len, instance->cmd_context.ext_buf_size); + + smp_len = ((U8*)ext_buf)[3] * 4 + 4; + LOG_DEBUG("hno:%u smp frame len[%d], rsq_data_len[%d]\n", + PS3_HOST(instance), smp_len, rsq_data_len); + + rsq_data_len = min(smp_len, rsq_data_len); + + show_smp((U8*)ext_buf, rsq_data_len); + + sg_copy_from_buffer(rsp_buf->sg_list, rsp_buf->sg_cnt, ext_buf, + rsp_buf->payload_len); + return rsq_data_len; +} + +void ps3_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, + struct sas_rphy *rphy) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_instance *instance = (struct ps3_instance *)shost->hostdata; + struct ps3_cmd *cmd = NULL; + U32 req_data_len = 0; + U32 resp_len = 0; + U64 sas_addr = 0; + struct ps3_sas_node *ps3_sas_node = NULL; + + ret = ps3_sas_smp_pre_check(instance); + if (ret != PS3_SUCCESS) { + ret = -EFAULT; + goto l_out; + } + + sas_addr = (rphy) ? (rphy->identify.sas_address) : (instance->sas_dev_context.ps3_hba_sas.sas_address); + ps3_sas_node = ps3_sas_find_node_by_sas_addr(instance, sas_addr); + if (ps3_sas_node == NULL) { + LOG_ERROR("hno:%u cannot find node[%llx] !\n", + PS3_HOST(instance), sas_addr); + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); + ret = -EFAULT; + goto l_out; + } + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + if (ps3_sas_request_pre_check(instance) != PS3_SUCCESS) { + LOG_WARN_LIM("sas_addr[%016llx], hno:%u smp pre check NOK\n", + sas_addr, PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -EFAULT; + goto l_no_free_cmd; + } + cmd = ps3_mgr_cmd_alloc(instance); + if (cmd == NULL) { + LOG_WARN("hno:%u Failed to get a cmd packet\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = -ENOMEM; + goto l_no_free_cmd; + } + cmd->time_out = PS3_SAS_TIMEOUT_SEC; + cmd->is_interrupt = PS3_DRV_FALSE; + + req_data_len = ps3_sas_req_to_ext_buf(instance, &job->request_payload, cmd->ext_buf); + if (req_data_len == 0) { + ret = -ENOMEM; + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + goto l_out_failed; + } + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], sas_addr[%016llx], len[%u] send smp req\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, sas_addr, req_data_len); + + ps3_sas_smp_reqframe_build(cmd, sas_addr, req_data_len); + ps3_mgr_cmd_word_build(cmd); + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + if (ret == -PS3_CMD_NO_RESP) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -ETIMEDOUT; + goto l_no_free_cmd; + } + + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u %d respStatus NOK CFID[%d] respStatus[%d]\n", + PS3_HOST(cmd->instance), ret, + cmd->cmd_word.cmdFrameID, + ps3_cmd_resp_status(cmd)); + ret = -ENXIO; + goto l_out_failed; + } + + resp_len = ps3_sas_ext_buf_to_rsp(instance, &job->reply_payload, cmd->ext_buf); + + LOG_DEBUG("hno:%u trace_id[0x%llx] CFID [%u], end, ret[%d]\n", + PS3_HOST(instance), cmd->trace_id, cmd->index, ret); +l_out_failed: + ps3_mgr_cmd_free(instance, cmd); +l_no_free_cmd: + up(&instance->sas_dev_context.ps3_sas_smp_semaphore); +l_out: + bsg_job_done(job, ret, resp_len); +} +#endif + +S32 ps3_sas_attach_transport() +{ + S32 ret = PS3_SUCCESS; + static struct sas_function_template ps3_sas_transport_functions = { + .get_linkerrors = ps3_sas_linkerrors_get, + .get_enclosure_identifier = ps3_sas_enclosure_identifier_get, + .get_bay_identifier = ps3_sas_bay_identifier_get, + .phy_reset = ps3_sas_phy_reset, + .phy_enable = ps3_sas_phy_enable, + .set_phy_speed = ps3_sas_linkrates_set, + .smp_handler = ps3_sas_smp_handler, + }; + + ps3_sas_transport_template = + sas_attach_transport(&ps3_sas_transport_functions); + if (!ps3_sas_transport_template) { + ret = -PS3_FAILED; + } + return ret; +} + +void ps3_sas_release_transport() +{ + if(ps3_sas_transport_template != NULL) { + sas_release_transport(ps3_sas_transport_template); + ps3_sas_transport_template = NULL; + } +} +#endif + diff --git a/drivers/scsi/ps3stor/ps3_sas_transport.h b/drivers/scsi/ps3stor/ps3_sas_transport.h new file mode 100644 index 0000000000000000000000000000000000000000..5b305d43933f0f3deb6bc1c21cf665a4be527dec --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_sas_transport.h @@ -0,0 +1,42 @@ +#ifndef _WINDOWS + +#ifndef _PS3_SAS_TRANSPORT_H_ +#define _PS3_SAS_TRANSPORT_H_ + +#include "ps3_instance_manager.h" +#include +#include + +#include "ps3_htp.h" + +#define PS3_SAS_TIMEOUT_SEC (40) +#define PS3_SMP_CRC_LEN (4) + +struct scsi_transport_template *ps3_sas_transport_get(void); + +S32 ps3_sas_attach_transport(void); + +void ps3_sas_release_transport(void); + +S32 ps3_sas_linkerrors_get(struct sas_phy *phy); + +S32 ps3_sas_enclosure_identifier_get(struct sas_rphy *rphy, u64 *identifier); + +S32 ps3_sas_bay_identifier_get(struct sas_rphy *rphy); + +S32 ps3_sas_phy_reset(struct sas_phy *phy, int hard_reset); + +S32 ps3_sas_phy_enable(struct sas_phy *phy, int enable); + +S32 ps3_sas_linkrates_set(struct sas_phy *phy, struct sas_phy_linkrates *rates); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,14,0) +S32 ps3_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, + struct request *req); +#else +void ps3_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, + struct sas_rphy *rphy); +#endif + +#endif +#endif diff --git a/drivers/scsi/ps3stor/ps3_scsi_cmd_err.c b/drivers/scsi/ps3stor/ps3_scsi_cmd_err.c new file mode 100644 index 0000000000000000000000000000000000000000..02517c79d73576ed927749b667308637c0ad96e1 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsi_cmd_err.c @@ -0,0 +1,1387 @@ + +#ifndef _WINDOWS +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#endif + +#include "ps3_htp_def.h" +#include "ps3_util.h" +#include "ps3_instance_manager.h" +#include "ps3_ioc_state.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_mgr_cmd.h" +#include "ps3_scsih.h" +#include "ps3_cmd_complete.h" +#include "ps3_driver_log.h" +#include "ps3_cmd_statistics.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_module_para.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_nvme_spec.h" +#include "ps3_nvme_resp_to_scsi.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_ioc_manager.h" +#include "ps3_mgr_channel.h" + +static void ps3_scsi_sense_print(struct ps3_instance *instance, + const U8 *sense_buffer, U8 len, S32 CFID); + +static void ps3_internal_errcode_to_scsi(struct scsi_cmnd *s_cmd, S32 err_code, + U32 xfer_cnt, Bool is_sata_jbod_mgr_cmd) +{ + S32 host_status = DID_OK; + S32 status = SCSI_STATUS_GOOD; + + switch (err_code) { + case PS3_STATUS_VD_OFFLINE: + case PS3_STATUS_DEVICE_NOT_FOUND: + host_status = DID_BAD_TARGET; + break; + case PS3_STATUS_INTERNAL_ERR: + host_status = DID_ERROR; + break; + + case PS3_STATUS_IO_ABORTED: + case PS3_STATUS_INTERNAL_SOFT_ERR: +#ifndef _WINDOWS + host_status = DID_SOFT_ERROR; +#else + host_status = DID_ERROR; +#endif + break; + case PS3_STATUS_ACCESS_BLOCK: + host_status = DID_OK; +#ifndef _WINDOWS +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,14,0)) + s_cmd->result |= PS3_SCSI_RESULT_DRIVER_STATUS(DRIVER_SENSE); +#endif + status = SAM_STAT_CHECK_CONDITION; + scsi_build_sense_buffer(0, s_cmd->sense_buffer, + ILLEGAL_REQUEST, 0x20, 0x02); + scsi_set_resid(s_cmd, scsi_bufflen(s_cmd)); + break; + case PS3_STATUS_REQ_ILLEGAL: + host_status = DID_OK; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,14,0)) + s_cmd->result |= PS3_SCSI_RESULT_DRIVER_STATUS(DRIVER_SENSE); +#endif + status = SAM_STAT_CHECK_CONDITION; + scsi_build_sense_buffer(0, s_cmd->sense_buffer, + ILLEGAL_REQUEST, 0x20, 0x00); + scsi_set_resid(s_cmd, scsi_bufflen(s_cmd)); +#else + scsi_build_sense_buffer(s_cmd, 0, ILLEGAL_REQUEST, 0x20, 0x02); +#endif + break; + case PS3_STATUS_HOST_NOT_FOUND: + case PS3_STATUS_PCI_RECOVERY: + host_status = DID_NO_CONNECT; + break; + case PS3_STATUS_VD_MEMBER_OFFLINE: + host_status = DID_IMM_RETRY; + break; + case PS3_STATUS_HOST_RESET: + #if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 7) && (RHEL_MINOR == 3)) || \ + ((LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4,4,14)))) + host_status = DID_REQUEUE; + #else + host_status = DID_RESET; + #endif + break; + case PS3_STATUS_UNDERRUN: + if ((scsi_bufflen(s_cmd) < xfer_cnt) + && (!is_sata_jbod_mgr_cmd)) { + host_status = DID_SOFT_ERROR; + scsi_set_resid(s_cmd, 0); + } else if (scsi_bufflen(s_cmd) == xfer_cnt) { + host_status = DID_OK; + } else { + if (scsi_bufflen(s_cmd) > xfer_cnt) { + scsi_set_resid(s_cmd, scsi_bufflen(s_cmd) - xfer_cnt); + } else { + scsi_set_resid(s_cmd, 0); + } + if (xfer_cnt < s_cmd->underflow) { + host_status = DID_SOFT_ERROR; + } else if (!xfer_cnt && s_cmd->cmnd[0] == REPORT_LUNS) { + host_status = DID_OK; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,14,0)) + s_cmd->result |= PS3_SCSI_RESULT_DRIVER_STATUS(DRIVER_SENSE); +#endif + status = SAM_STAT_CHECK_CONDITION; + scsi_build_sense_buffer(0, s_cmd->sense_buffer, ILLEGAL_REQUEST, 0x20, 0x0); + } else { + host_status = DID_OK; + } + } + break; + case PS3_STATUS_OVERRUN: + scsi_set_resid(s_cmd, 0); + host_status = DID_SOFT_ERROR; + break; + + default: + host_status = DID_ERROR; + break; + } +#ifndef _WINDOWS + s_cmd->result |= PS3_SCSI_RESULT_HOST_STATUS(host_status) | status; +#else + scsi_cmnd_scsistatus_set(s_cmd, status); + scsi_cmnd_hoststatus_set(s_cmd, host_status); +#endif +} + +static void ps3_standard_errcode_to_scsi(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, S32 err_code, + PS3RespFrame_u *resp_frame) +{ + S32 host_status = DID_OK; + S32 status = SCSI_STATUS_GOOD; + + switch (err_code) { + case SCSI_STATUS_GOOD: + case SCSI_STATUS_CONDITION_MET: + case SCSI_STATUS_BUSY: + case SCSI_STATUS_TASK_SET_FULL: + case SCSI_STATUS_ACA_ACTIVE: + case SCSI_STATUS_TASK_ABORTED: + status = err_code; + break; + case SCSI_STATUS_RESERVATION_CONFLICT: +#if ((defined(RHEL_MAJOR) && \ + ((RHEL_MAJOR < 9) || (RHEL_MAJOR == 9 && RHEL_MINOR < 3))) || \ + (!defined(RHEL_MAJOR) && LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 38))) + host_status = DID_NEXUS_FAILURE; +#endif + status = err_code; + break; + case SCSI_STATUS_CHECK_CONDITION: + host_status = DID_OK; + status = err_code; + if (resp_frame != NULL) { + memcpy(s_cmd->sense_buffer, resp_frame->normalRespFrame.sense, + SCSI_SENSE_BUFFERSIZE); + ps3_scsi_sense_print(instance, + s_cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, SCMD_GET_REQUEST(s_cmd)->tag); + } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,14,0)) + s_cmd->result |= PS3_SCSI_RESULT_DRIVER_STATUS(DRIVER_SENSE); +#endif + break; + default: + host_status = DID_ERROR; + break; + } + + s_cmd->result |= PS3_SCSI_RESULT_HOST_STATUS(host_status) | status; +} + +void ps3_errcode_to_scsi_status(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, U32 err_code, + PS3RespFrame_u *resp_frame, U32 xfer_cnt, struct ps3_cmd *cmd) +{ + Bool is_sata_jbod_mgr_cmd = 0; + if (cmd != NULL) { + is_sata_jbod_mgr_cmd = ps3_scsih_is_sata_jbod_mgr_cmd(cmd); + } + + s_cmd->result = SCSI_STATUS_GOOD; + + if (err_code < PS3_STATUS_DEVICE_NOT_FOUND) { + ps3_standard_errcode_to_scsi(instance, + s_cmd, err_code, resp_frame); + } else { + ps3_internal_errcode_to_scsi(s_cmd, err_code, xfer_cnt, is_sata_jbod_mgr_cmd); + } +} + +static inline void ps3_err_scsi_errcode_mapping(struct ps3_cmd *cmd, U16 mode, + Bool is_sas_direct) +{ + U8 opcode = 0; + U16 sub_opcode = 0; + U32 resp_status = 0; + PS3RespFrame_u *resp_frame = cmd->resp_frame; + U32 xfer_cnt = 0; + Ps3SasDirectRespFrameIU_s *frame = NULL; + + ps3_scsih_cdb_opcode_get(cmd->scmd->cmnd, &opcode, &sub_opcode); + LOG_FILE_INFO("tid:0x%llx hno:%u op:0x%x sub_op:0x%x " + "tag:%u\n", cmd->trace_id, PS3_HOST(cmd->instance), + opcode, sub_opcode, cmd->index); + + if (ps3_err_is_resp_from_direct_cmd(mode) + && (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD)) { + resp_status = resp_frame->sasRespFrame.status & PS3_SCSI_STATUS_MASK; + } else { + resp_status = resp_frame->normalRespFrame.respStatus & PS3_SCSI_STATUS_MASK; + } + xfer_cnt = ps3_scsih_xfer_cnt_get(cmd); + ps3_errcode_to_scsi_status(cmd->instance, cmd->scmd, resp_status, resp_frame, xfer_cnt, cmd); + + if (is_sas_direct) { + frame = &resp_frame->sasRespFrame; + LOG_INFO_IN_IRQ(cmd->instance, + "tid:0x%llx hno:%u [%u:%u:%u], op:0x%x sub_op:0x%x " + "tag:%u data_pres:%u resp_status:0x%x scmd status:0x%x " + "scmd cmd_flags:0x%llx, retries:%d, allowd:%d," + "xfer_cnt:%u scsi_buflen:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->scmd->device->channel, + cmd->scmd->device->id, cmd->io_attr.disk_id, opcode, sub_opcode, + cmd->index, frame->dataPres, frame->status, cmd->scmd->result, + (U64)SCMD_GET_REQUEST(cmd->scmd)->cmd_flags, + cmd->scmd->retries, cmd->scmd->allowed, + xfer_cnt, scsi_bufflen(cmd->scmd)); + } else { + LOG_INFO_IN_IRQ(cmd->instance, + "tid:0x%llx hno:%u [%u:%u:%u], op:0x%x sub_op:0x%x " + "tag:%u resp_status:0x%x scmd status:0x%x" + "scmd cmd_flags:0x%llx, retries:%d, allowd:%d, " + "xfer_cnt:%u scsi_buflen:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->scmd->device->channel, + cmd->scmd->device->id, cmd->io_attr.disk_id, opcode, sub_opcode, + cmd->index, resp_frame->normalRespFrame.respStatus, cmd->scmd->result, + (U64)SCMD_GET_REQUEST(cmd->scmd)->cmd_flags, cmd->scmd->retries, + cmd->scmd->allowed, xfer_cnt, scsi_bufflen(cmd->scmd)); + } +} + +static Bool ps3_err_retry_sys_state_check(struct ps3_instance *instance) +{ + Bool ret = PS3_DRV_TRUE; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + if (!instance->state_machine.is_load) { + LOG_WARN_IN_IRQ(instance, + "hno:%u instance state not is_load\n", PS3_HOST(instance)); + ret = PS3_DRV_FALSE; + goto l_out; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_DEAD || + cur_state == PS3_INSTANCE_STATE_QUIT) { + LOG_WARN_IN_IRQ(instance, + "hno:%u instance state is dead/quit\n", PS3_HOST(instance)); + ret = PS3_DRV_FALSE; + goto l_out; + } + +l_out: + return ret; +} + +static S32 ps3_is_state_abnormal(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + + static unsigned long j; + + if (!ps3_is_instance_state_normal(instance, PS3_TRUE)){ + ret = -PS3_FAILED; + goto l_out; + } + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u host in pci recovery\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } +l_out: + return ret; +} + +static Bool ps3_err_code_is_need_change(const struct ps3_cmd *cmd) +{ + U32 err_code = 0; + PS3RespFrame_u *resp_frame = cmd->resp_frame; + U16 mode = cmd->reply_word.mode; + Bool ret = PS3_TRUE; + PS3NvmeCmdStatus_s status; + ps3_nvme_scsi_status cpl; + + if (ps3_err_is_resp_from_direct_cmd(mode)) { + if (cmd->reply_word.diskType == PS3_DEV_TYPE_SAS_SATA) { + err_code = resp_frame->sasRespFrame.status & PS3_SCSI_STATUS_MASK; + } else { + status.cmdStatus = cmd->reply_word.retStatus; + memset(&cpl, 0, sizeof(ps3_nvme_scsi_status)); + ps3_nvme_error_to_scsi_status(status, &cpl); + err_code = cpl.status; + } + } + + switch (err_code) { + case SCSI_STATUS_BUSY: + case SCSI_STATUS_TASK_SET_FULL: + case SCSI_STATUS_CONDITION_MET: + case SCSI_STATUS_ACA_ACTIVE: + case PS3_STATUS_OVERRUN: + case PS3_STATUS_UNDERRUN: + ret = PS3_FALSE; + break; + default: + ret = PS3_TRUE; + } + + LOG_DEBUG("tid:0x%llx hno:%u tag:%u status:0x%x %s change\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, err_code, + ret == PS3_TRUE?"need":"no need"); + + return ret; +} + +static inline Bool ps3_is_need_direct_to_normal(const struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + return ((instance->ioc_adpter->is_need_direct_to_normal != NULL) + && (instance->ioc_adpter->is_need_direct_to_normal(cmd)) + && (cmd->scmd->allowed != 0)); +} + +void ps3_scsih_drv_io_reply_scsi(struct scsi_cmnd *s_cmd, struct ps3_cmd *cmd, U8 resp_status, Bool cmd_lock); + +S32 ps3_err_scsi_io_processing(struct ps3_instance *instance, + U32 id, U32 channel) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd_context *cmd_context = &instance->cmd_context; + struct ps3_cmd *cmd = NULL; + U16 idx = 0; + struct scsi_cmnd *s_cmd = NULL; + static unsigned long j; + ps3_msleep(ps3_task_reset_delay_time_query()); + + ps3_atomic_inc(&instance->is_err_scsi_processing); + rmb(); + + ret = ps3_is_state_abnormal(instance); + if (ret != PS3_SUCCESS) { + LOG_INFO("hno:%u ps3_err_scsi_io_processing [%d:%d] fail, abnormal\n", + PS3_HOST(instance), channel, id); + ret = -PS3_FAILED; + ps3_atomic_dec(&instance->is_err_scsi_processing); + goto l_out; + } + + instance->ioc_adpter->irq_disable(instance); + INJECT_START(PS3_ERR_IJ_WAIT_IOCTL_IN_DEVICE_RESET, instance); +#ifndef _WINDOWS + ps3_irqs_sync(instance); +#endif + + ps3_all_reply_fifo_complete(instance); + + for (idx = 0 ; idx < cmd_context->max_scsi_cmd_count; idx++) { + cmd = ps3_cmd_find(instance, idx); + if(cmd == NULL) { + ret = -PS3_FAILED; + break; + } + if (cmd->cmd_state.state == PS3_CMD_STATE_INIT) { + continue; + } + s_cmd = cmd->scmd; + if (s_cmd == NULL) { + continue; + } + if (s_cmd->device == NULL) { + continue; + } + if (PS3_SDEV_TARGET(s_cmd->device) == id && + PS3_SDEV_CHANNEL(s_cmd->device) == channel) { +#ifndef _WINDOWS + scsi_print_command(s_cmd); +#endif + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u SCSI commands pending to target" + " tid:0x%llx [%u:%u]: frame_id:%d\n", + PS3_HOST(instance), cmd->trace_id, channel, id, cmd->index); + ret = -PS3_FAILED; + break; + } + } + + instance->ioc_adpter->irq_enable(instance); +#ifndef _WINDOWS + ps3_irqpolls_enable(instance); +#endif + + ps3_atomic_dec(&instance->is_err_scsi_processing); +l_out: + return ret; +} + +static void ps3_err_sas_errcode_mapping_with_sense(struct ps3_cmd *cmd, + PS3RespFrame_u *frame) +{ + U32 sense_data_len = 0; + struct scsi_cmnd *scmd = cmd->scmd; + struct ps3_instance *instance = cmd->instance; +#ifndef _WINDOWS + S32 host_status = DID_OK; + Ps3SasDirectRespFrameIU_s frame_sas = frame->sasRespFrame; + if (scmd == NULL || scmd->sense_buffer == NULL) { + LOG_WARN_IN_IRQ(instance, "scmd is null\n"); + goto l_out; + } + scmd->result = 0; + + if (frame == NULL) { + LOG_ERROR_IN_IRQ(instance, "direct frame is null, retry\n"); + scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_SOFT_ERROR); + goto l_out; + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5,14,0)) + scmd->result |= PS3_SCSI_RESULT_DRIVER_STATUS(DRIVER_SENSE); +#endif + scmd->result |= PS3_SCSI_RESULT_HOST_STATUS(host_status) | frame_sas.status; + + memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + sense_data_len = min_t(U32, SCSI_SENSE_BUFFERSIZE, sizeof(frame_sas.data)); + if (sense_data_len == 0) { + LOG_ERROR_IN_IRQ(instance, "sense_data_len len is zero\n"); + goto l_out; + } + memcpy(scmd->sense_buffer, frame_sas.data, sense_data_len); + ps3_scsi_sense_print(instance, scmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, SCMD_GET_REQUEST(scmd)->tag); +#else + if (frame == NULL) { + LOG_ERROR_IN_IRQ(instance, "direct frame is null, retry\n"); + scsi_cmnd_scsistatus_set(scmd, SCSI_STATUS_BUSY); + goto l_out; + } + sense_data_len = min(SCSI_SENSE_BUFFERSIZE, sizeof(frame_sas.data)); + if (sense_data_len == 0) { + LOG_ERROR_IN_IRQ(instance, "sense_data_len len is zero\n"); + goto l_out; + } + + ps3_sense_info_set(scmd, frame_sas.data, (U16)sense_data_len); +#endif +l_out: + return; +} + +static void ps3_err_sas_errcode_mapping(struct ps3_instance *instance, struct ps3_cmd *cmd, U16 mode) +{ + struct scsi_cmnd *scmd = cmd->scmd; + U32 channel = 0; + U32 id = 0; + U16 disk_id = 0; + PS3RespFrame_u *frame = cmd->resp_frame; + static unsigned long j; +#ifndef _WINDOWS + channel = scmd->device->channel; + id = scmd->device->id; + disk_id = cmd->io_attr.disk_id; +#endif + if (ps3_err_is_resp_from_direct_cmd(mode)){ + Ps3SasDirectRespFrameIU_s frame_sas = frame->sasRespFrame; + + switch (frame_sas.dataPres) { + case PS3_SAS_PRES_NO_DATA: + case PS3_SAS_PRES_REPSNSE_DATA: + ps3_err_scsi_errcode_mapping(cmd, mode, PS3_TRUE); + break; + case PS3_SAS_PRES_SENSE_DATA: + LOG_INFO_IN_IRQ(instance, + "tid:0x%llx hno:%u [%u:%u:%u], CFID:%u data_pres:%u status:%u\n", + cmd->trace_id, PS3_HOST(instance), channel, + id, disk_id, cmd->index, + frame->sasRespFrame.dataPres, frame->sasRespFrame.status); + ps3_err_sas_errcode_mapping_with_sense(cmd, frame); + break; + default: +#ifndef _WINDOWS + scmd->result |= PS3_SCSI_RESULT_HOST_STATUS(DID_ERROR); + LOG_INFO_IN_IRQ(instance, + "tid:0x%llx hno:%d tag:%u scmd result:%x \n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->index, cmd->scmd->result); +#else + scsi_cmnd_hoststatus_set(scmd, DID_ERROR); + LOG_INFO_IN_IRQ(instance, + "tid:0x%llx hno:%d tag:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index); +#endif + break; + } + + } else { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, \ + "tid:0x%llx hno:%u [chl:%u, id:%u, devid:%u], CFID:%u respStatus:%u\n", + cmd->trace_id, PS3_HOST(instance), channel, id, disk_id, + cmd->index, frame->normalRespFrame.respStatus); + ps3_err_scsi_errcode_mapping(cmd, mode, PS3_FALSE); + } + return; +} + +static void ps3_err_nvme_errcode_mapping(struct ps3_instance *instance, + struct ps3_cmd *cmd, U16 mode) +{ + ps3_nvme_resp_to_scsi_status(cmd); + ps3_err_scsi_errcode_mapping(cmd, mode, PS3_FALSE); + (void)instance; + + LOG_INFO_IN_IRQ(instance, + "tid:0x%llx hno:%d tag:%d scmd result:%x \n", + cmd->trace_id, PS3_HOST(instance), + cmd->index, cmd->scmd->result); +} + +static void ps3_err_protocol_errcode_mapping(struct ps3_instance *instance, + struct ps3_cmd *cmd, struct PS3ReplyWord *reply_word) +{ + if (reply_word->diskType == PS3_DEV_TYPE_SAS_SATA){ + ps3_err_sas_errcode_mapping(instance, cmd, reply_word->mode); + } else { + ps3_err_nvme_errcode_mapping(instance, cmd, reply_word->mode); + } + + return; +} + +Bool ps3_err_is_resp_from_direct_cmd(U16 mode) +{ + return ((mode == PS3_REPLY_WORD_MODE_DIRECT_OK) + || (mode == PS3_REPLY_WORD_MODE_DIRECT_ADVICE_TO_DIRECT)); +} + +S32 ps3_err_scsi_cmd_fault_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd) +{ + U16 mode = cmd->reply_word.mode; + S32 ret = PS3_SUCCESS; + + LOG_FILE_INFO("tid:0x%llx hno:%u scsi cmd fault proc CFID:%u " + "reply_word info: mode:%d retStatus[%02x], rettype:%d disktype:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, mode, + cmd->reply_word.retStatus, cmd->reply_word.retType, cmd->reply_word.diskType); + + if(cmd->reply_word.retType == 0) { + if ((cmd->io_attr.dev_type != PS3_DEV_TYPE_VD) + && ps3_err_is_resp_from_direct_cmd(mode)) { + if (ps3_err_retry_sys_state_check(instance)) { + LOG_FILE_INFO("hno:%u Direct cmd needs retry!" + " [scmd cmd_flags:0x%llx, retries:%d, allowd:%d]\n", + PS3_HOST(instance), (U64)SCMD_GET_REQUEST(cmd->scmd)->cmd_flags, + cmd->scmd->retries, cmd->scmd->allowed); + + if ((ps3_is_need_direct_to_normal(instance, cmd)) + && (ps3_err_code_is_need_change(cmd))) { + cmd->scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_SOFT_ERROR); + } else { + ps3_err_protocol_errcode_mapping(instance, cmd, &(cmd->reply_word)); + } + } else { + cmd->scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + } + } else { + ps3_err_scsi_errcode_mapping(cmd, mode, PS3_FALSE); + } + }else { + if (ps3_err_retry_sys_state_check(instance)) { + LOG_FILE_INFO("hno:%u Hil hardware err,need retry!" + " [scmd cmd_flags:0x%llx, retries:%d, allowd:%d]\n", + PS3_HOST(instance), SCMD_GET_REQUEST(cmd->scmd)->cmd_flags, + cmd->scmd->retries, cmd->scmd->allowed); + if (cmd->reply_word.retStatus == PS3_NVME_RESP_STATUS_SQ_FULL && + cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + cmd->scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_OK) | SCSI_STATUS_TASK_SET_FULL; + cmd->scmd->retries = ((cmd->scmd->retries == 0) ? 1 : cmd->scmd->retries); + } else { + cmd->scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_SOFT_ERROR); + } + } else { + cmd->scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + } + } + if (cmd->scmd->result == SCSI_STATUS_TASK_SET_FULL) { + ps3_qos_adjust_pd_rsc(cmd->scmd->device, instance, PS3_QOS_QUOTA_ADJUST_QFULL); + } + return ret; +} + +void ps3_scsih_drv_io_reply_scsi(struct scsi_cmnd *s_cmd, struct ps3_cmd *cmd, U8 resp_status, Bool cmd_lock) +{ + struct ps3_instance *instance = cmd->instance; + struct ps3_scsi_priv_data *data = NULL; + + if (cmd_lock) { + ps3_mutex_lock(&instance->recovery_context->free_cmd_lock); + LOG_INFO("hno:%u tid:0x%llx CFID:%u drv reply scsi independently!\n", + PS3_HOST(instance), cmd->trace_id, cmd->index); + } + if (likely(cmd->scmd == NULL)) { + LOG_DEBUG("scmd is has reply scsi\n"); + goto l_out; + } + + PS3_IO_OUTSTAND_DEC(instance, s_cmd); + PS3_VD_OUTSTAND_DEC(instance, s_cmd); + + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + + ps3_errcode_to_scsi_status(cmd->instance, s_cmd, resp_status, NULL, 0, cmd); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) + s_cmd->SCp.ptr = NULL; +#endif + ps3_scsi_dma_unmap(cmd); + data = (struct ps3_scsi_priv_data *)s_cmd->device->hostdata; + if(likely(data != NULL)){ + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + + if (cmd->r1x_peer_cmd != NULL) { + LOG_DEBUG("host_no:%u task repaly r1x scsi write CFID:%d and CFID:%d\n", + PS3_HOST(instance), cmd->index, cmd->r1x_peer_cmd->index); + if (!ps3_r1x_peer_cmd_free_nolock(cmd->r1x_peer_cmd)) { + ps3_scsi_cmd_free(cmd->r1x_peer_cmd); + } + + if (!ps3_r1x_peer_cmd_free_nolock(cmd)) { + ps3_scsi_cmd_free(cmd); + } + } else { + ps3_scsi_cmd_free(cmd); + } + SCMD_IO_DONE(s_cmd); + +l_out: + if (cmd_lock) { + ps3_mutex_unlock(&instance->recovery_context->free_cmd_lock); + } + return ; +} + +S32 ps3_err_scsi_task_mgr_abort(struct scsi_cmnd *scmd) +{ +#ifdef _WINDOWS + (void)scmd; +#else + S32 ret = SUCCESS; + + struct ps3_cmd *aborted_cmd = NULL; + struct ps3_cmd *aborted_peer_cmd = NULL; + U16 cmd_frame_id = 0; + struct ps3_instance *instance = scsi_host_data(scmd); + struct ps3_scsi_priv_data *scsi_priv_data = scsi_device_private_data(scmd); + U32 cmd_flighting_wait_cnt = 0; + + LOG_WARN("hno:%u enter, ready aborted CFID:%u op:0x%x " + "chl:%u id:%u\n", PS3_HOST(instance), SCMD_GET_REQUEST(scmd)->tag, + scmd->cmnd[0], ps3_scsi_channel_query(scmd), + ps3_scsi_target_query(scmd)); + + INJECT_START(PS3_ERR_IJ_SCSI_TASK_PRE_CHECK_FAILED, instance) + if (ps3_mgr_cmd_send_pre_check(instance, PS3_FALSE) != PS3_SUCCESS) { + LOG_WARN("hno:%u pre check NOK!\n", + PS3_HOST(instance)); + ret = FAILED; + goto l_out; + } + + if (!scsi_priv_data->is_taskmgmt_enable) { + LOG_ERROR("hno:%u task mgmt is disable!\n", + PS3_HOST(instance)); + ret = FAILED; + goto l_out; + } + cmd_frame_id = SCMD_GET_REQUEST(scmd)->tag; + INJECT_START(PS3_ERR_IJ_ABORT_PRE1_FORCE_ABORTED_CMD_DONE, scmd) + aborted_cmd = ps3_cmd_find(instance, cmd_frame_id); + if (aborted_cmd == NULL || aborted_cmd->scmd == NULL) { + LOG_INFO("host_no:%u there is no aborted cmd CFID:%u\n", + PS3_HOST(instance), cmd_frame_id); + + ret = SUCCESS; + goto l_out; + } + INJECT_START(PS3_ERR_IJ_ABORT_PRE2_FORCE_ABORTED_CMD_DONE, scmd) + + LOG_FILE_WARN("tid:0x%llx hno:%u task aborted CFID:%u ready \n", + aborted_cmd->trace_id, PS3_HOST(instance), cmd_frame_id); + + scsi_priv_data->task_manager_busy = 1; + + while(aborted_cmd->flighting && + cmd_flighting_wait_cnt < PS3_ABORT_WAIT_CMD_FLIGHT_END) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + cmd_flighting_wait_cnt++; + } + + if (aborted_cmd->flighting) { + ret = FAILED; + LOG_WARN("task abort wait cmd filghting end NOK. hno:%u tid:0x%llx CFID:%u\n", + PS3_HOST(instance), aborted_cmd->trace_id, aborted_cmd->index); + goto l_busy_clean_out; + } + + LOG_DEBUG("hno:%u task abort wait flighting cmd end\n", + PS3_HOST(instance)); + + if (ps3_r1x_conflict_queue_abort(aborted_cmd, scmd)) { + ret = SUCCESS; + goto l_busy_clean_out; + } + + if (ps3_qos_waitq_abort(aborted_cmd)) { + ret = SUCCESS; + goto l_busy_clean_out; + } + + aborted_peer_cmd = aborted_cmd->r1x_peer_cmd; + if (aborted_peer_cmd != NULL) { + INJECT_START(PS3_ERR_IJ_WAIT_CMD_ALLOC1, aborted_peer_cmd); + ps3_mutex_lock(&instance->task_abort_lock); + aborted_peer_cmd->is_aborting = 1; + wmb(); + INJECT_START(PS3_ERR_IJ_WAIT_CMD_FREE, aborted_cmd); + if (aborted_cmd->r1x_peer_cmd == NULL) { + INJECT_START(PS3_ERR_IJ_WAIT_CMD_ALLOC, aborted_peer_cmd); + INJECT_START(PS3_ERR_IJ_WAIT_CMD_ALLOC2, aborted_peer_cmd); + INJECT_START(PS3_ERR_IJ_WAIT_CMD_FREE, aborted_peer_cmd); + aborted_peer_cmd->is_aborting = 0; + INJECT_START(PS3_ERR_IJ_WAIT_CMD_ALLOC2, aborted_peer_cmd); + ps3_mutex_unlock(&instance->task_abort_lock); + goto l_busy_clean_out; + } + ps3_mutex_unlock(&instance->task_abort_lock); + INJECT_START(PS3_ERR_IJ_WAIT_CMD_FREE1, aborted_cmd); + INJECT_START(PS3_ERR_IJ_ABORT_BLOCK1, instance); + if (!aborted_peer_cmd->is_r1x_scsi_complete) { + ret = ps3_scsi_task_mgr_abort(instance, scsi_priv_data, + aborted_peer_cmd->index, scmd); + ret = (ret == PS3_SUCCESS) ? SUCCESS : FAILED; + aborted_peer_cmd->is_aborting = 0; + INJECT_START(PS3_ERR_IJ_ABORT_BLOCK2, instance); + if (ret == SUCCESS) { + LOG_INFO("hno:%u task abort peer cmd:%d success !\n", + PS3_HOST(instance), aborted_peer_cmd->index); + aborted_peer_cmd = ps3_cmd_find(instance, + aborted_peer_cmd->index); + if (unlikely(aborted_peer_cmd == NULL)) { + ret = FAILED; + goto l_busy_clean_out; + } + } else { + goto l_busy_clean_out; + } + } else { + aborted_peer_cmd->is_aborting = 0; + } + } + + ret = ps3_scsi_task_mgr_abort(instance, scsi_priv_data, + cmd_frame_id, scmd); + ret = (ret == PS3_SUCCESS) ? SUCCESS : FAILED; + + if(ret == SUCCESS) { + LOG_INFO("hno:%u task abort cmd success !\n", PS3_HOST(instance)); + aborted_cmd = ps3_cmd_find(instance, cmd_frame_id); + if (aborted_cmd == NULL) { + ret = FAILED; + } else { + if (unlikely(aborted_cmd->scmd)) { + LOG_WARN("task abort success but scmd is not freed. hno:%u tid:0x%llx CFID:%u\n", + PS3_HOST(instance), aborted_cmd->trace_id, cmd_frame_id); + ret = FAILED; + } + ps3_can_queue_depth_update(instance); + } + } +l_busy_clean_out: + scsi_priv_data->task_manager_busy = 0; + wmb(); +l_out: + LOG_WARN("hno:%u quit ret:%#x\n",PS3_HOST(instance), ret); + return ret; +#endif + return -PS3_FAILED; +} + +void ps3_set_task_manager_busy(struct ps3_instance *instance, U32 channel, U32 id, U32 state) +{ + struct ps3_scsi_priv_data *scsi_priv_data = NULL; + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + + scsi_priv_data = ps3_dev_mgr_lookup_vd_pri_data(instance, channel, id); + if (scsi_priv_data == NULL) { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + LOG_ERROR("hno:%u device has been deleted.channel:%u, id:%u!\n", + PS3_HOST(instance), channel, id); + goto l_out; + } + scsi_priv_data->task_manager_busy = state; + + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + +l_out: + return; +} + +S32 ps3_err_scsi_task_mgr_reset(struct scsi_cmnd *scmd) +{ + S32 ret = PS3_SUCCESS; + S32 send_result = PS3_SUCCESS; + struct ps3_instance *instance = scsi_host_data(scmd); + struct ps3_scsi_priv_data *scsi_priv_data = NULL; + struct ps3_scsi_priv_data pending_priv_data; + struct ps3_cmd * cmd = NULL; + + LOG_INFO("hno:%u enter device reset channel:%u id:%u\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(scmd->device), + PS3_SDEV_TARGET(scmd->device)); + + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + INJECT_START(PS3_ERR_IJ_PRIV_DATA_NULL1, scmd->device) + scsi_priv_data = scsi_device_private_data(scmd); + if(scsi_priv_data == NULL) { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + LOG_ERROR("hno:%u device has been deleted!\n", + PS3_HOST(instance)); +#ifndef _WINDOWS + scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + ret = SUCCESS; +#else + scsi_cmnd_hoststatus_set(scmd, DID_ERROR); +#endif + goto l_out; + } + + LOG_WARN("hno:%u enter ready reset[%u:%u:%u:%#x], CFID:%d\n", + PS3_HOST(instance), scsi_priv_data->disk_pos.diskDev.ps3Dev.softChan, + scsi_priv_data->disk_pos.diskDev.ps3Dev.devID, + scsi_priv_data->disk_pos.diskDev.ps3Dev.phyDiskID, + scsi_priv_data->disk_pos.diskMagicNum, SCMD_GET_REQUEST(scmd)->tag); + + if (ps3_mgr_cmd_send_pre_check(instance, PS3_FALSE) != PS3_SUCCESS) { + LOG_WARN("hno:%u pre check NOK!\n", + PS3_HOST(instance)); +#ifndef _WINDOWS + ret = FAILED; +#else + ret = -PS3_FAILED; +#endif + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + goto l_out; + } + + if (!scsi_priv_data->is_taskmgmt_enable) { + LOG_ERROR("hno:%u task mgmt is disable!\n", + PS3_HOST(instance)); +#ifndef _WINDOWS + ret = FAILED; +#else + ret = -PS3_FAILED; +#endif + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + goto l_out; + } + + LOG_INFO("hno:%u task ready reset[%u:%u:%u] \n",PS3_HOST(instance), + scsi_priv_data->disk_pos.diskDev.ps3Dev.softChan, + scsi_priv_data->disk_pos.diskDev.ps3Dev.devID, + scsi_priv_data->disk_pos.diskDev.ps3Dev.phyDiskID); + scsi_priv_data->task_manager_busy = 1; + + ps3_wait_scsi_cmd_done(instance, PS3_TRUE); + LOG_WARN("hno[%u], task reset wait scsi delivering cmd count[%d] !\n", PS3_HOST(instance), + ps3_atomic_read(&instance->cmd_statistics.cmd_delivering)); + ps3_wait_mgr_cmd_done(instance, PS3_TRUE); + LOG_WARN("hno:%u task reset wait delivering cmd end !\n", PS3_HOST(instance)); + + ps3_r1x_conflict_queue_clean(scsi_priv_data, SCSI_STATUS_TASK_ABORTED); + memcpy(&pending_priv_data, scsi_priv_data, sizeof(struct ps3_scsi_priv_data)); + + ps3_qos_device_clean(instance, scsi_priv_data, SCSI_STATUS_TASK_ABORTED); + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + + ps3_atomic_inc(&instance->cmd_statistics.cmd_delivering); + INJECT_START(PS3_ERR_IJ_V2_IS_LOAD_FALSE1, instance); + if (ps3_mgr_cmd_send_pre_check(instance, PS3_FALSE) != PS3_SUCCESS) { + LOG_WARN_LIM("hno:%u mgr reset cmd pre check NOK CFID:%d\n", + PS3_HOST(instance), SCMD_GET_REQUEST(scmd)->tag); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = FAILED; + goto l_err; + } + cmd = ps3_scsi_task_mgr_reset_build(instance, &pending_priv_data); + if (cmd == NULL) { + LOG_ERROR("hno:%u task reset cmd NOK!\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + ret = FAILED; + goto l_err; + } + + send_result = ps3_cmd_send_sync(instance, cmd); + ps3_atomic_dec(&instance->cmd_statistics.cmd_delivering); + if (send_result == PS3_SUCCESS) { + send_result = ps3_cmd_wait_sync(instance, cmd); + } + ret = ps3_mgr_complete_proc(instance, cmd, send_result); + LOG_INFO("host_no:%u reset finish CFID:%u t_id:0x%llx!\n", + PS3_HOST(instance), ps3_cmd_frame_id(cmd), cmd->trace_id); + + if ((ret != -PS3_CMD_NO_RESP) && (cmd != NULL)) { + ps3_task_cmd_free(instance, cmd); + } + + ret = (ret == PS3_SUCCESS) ? SUCCESS : FAILED; + if (ret == SUCCESS) { + LOG_INFO("hno:%u target reset success !\n", PS3_HOST(instance)); + ret = ps3_err_scsi_io_processing(instance, scmd->device->id, + scmd->device->channel); + INJECT_START(PS3_ERR_IJ_HT_ABNORMAL1, &ret) + ret = (ret == PS3_SUCCESS) ? SUCCESS : FAILED; + ps3_can_queue_depth_update(instance); + } +l_err: + ps3_mutex_lock(&instance->dev_context.dev_priv_lock); + INJECT_START(PS3_ERR_IJ_PRIV_DATA_NULL2, scmd->device) + scsi_priv_data = scsi_device_private_data(scmd); + if (scsi_priv_data == NULL) { + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); + LOG_ERROR("hno:%u device has been deleted!\n", + PS3_HOST(instance)); + goto l_out; + } + scsi_priv_data->task_manager_busy = 0; + ps3_mutex_unlock(&instance->dev_context.dev_priv_lock); +l_out: + LOG_WARN("hno:%u quit ret:%#x\n",PS3_HOST(instance), ret); + return ret; +} + +S32 ps3_device_reset_handler(struct scsi_cmnd *scmd) +{ + S32 ret = PS3_SUCCESS; + struct ps3_instance *instance = scsi_host_data(scmd); + + LOG_INFO("hno:%u ready device[%u:%u] reset!\n", + PS3_HOST(instance), PS3_SDEV_CHANNEL(scmd->device), + PS3_SDEV_TARGET(scmd->device)); + + ps3_mutex_lock(&instance->task_mgr_reset_lock); + instance->task_manager_host_busy = PS3_TRUE; + ret = ps3_err_scsi_task_mgr_reset(scmd); + instance->task_manager_host_busy = PS3_FALSE; + ps3_mutex_unlock(&instance->task_mgr_reset_lock); + + return ret; +} + +static S32 ps3_hard_reset_pre_check(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + Bool is_support_halt = PS3_IOC_STATE_HALT_SUPPORT(instance); + U32 hard_reset_enable = ps3_hard_reset_enable_query(); + + cur_state = ps3_atomic_read(&instance->state_machine.state); + + LOG_WARN("hno:%u ready to host reset,instance state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + + if(is_support_halt && (cur_state != PS3_INSTANCE_STATE_DEAD)){ + ps3_atomic_set(&instance->state_machine.state, + PS3_INSTANCE_STATE_DEAD); + instance->ioc_adpter->ioc_force_to_halt(instance); + LOG_INFO("host_no:%u instance state while support halt!\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + } + + if ((cur_state = ps3_atomic_read(&instance->state_machine.state)) == + PS3_INSTANCE_STATE_DEAD && (!hard_reset_enable || is_support_halt + || (!PS3_IOC_HARD_RECOVERY_SUPPORT(instance)))) { + LOG_INFO("hno:%u host reset, instance state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = -PS3_FAILED; + } + + LOG_INFO("hno:%u host reset, instance state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + + return ret; +} +static S32 ps3_host_reset_pre_check(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + S32 cur_state = ps3_atomic_read(&instance->state_machine.state); + + LOG_WARN("hno:%u ready to host reset,instance state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + if (PS3_DEVICE_IS_SWITCH(instance->dev_id) && + !instance->is_scan_host_finish) { + LOG_INFO("host_no:%u instance deviceId:%u is probe, exit failed!\n", + PS3_HOST(instance), instance->dev_id); + ret = -PS3_FAILED; + goto l_out; + } + + if (cur_state == PS3_INSTANCE_STATE_QUIT || cur_state == PS3_INSTANCE_STATE_DEAD || + !instance->state_machine.can_hostreset) { + LOG_ERROR("hno:%u cannot perform host reset due to %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = -PS3_FAILED; + } else { + LOG_INFO("hno:%u host reset, instance state: %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + } +l_out: + return ret; +} +S32 ps3_wait_for_outstanding_complete(struct ps3_instance *instance) +{ + U32 i = 0; + U32 ioc_state = PS3_FW_STATE_UNDEFINED; + S32 ret = -PS3_FAILED; + U32 waittime_for_io_completion = PS3_WAIT_FOR_OUTSTANDING_IO_COMPLETE; + U32 interval = 1000; + U32 count = 0; + + for (i = 0; i < waittime_for_io_completion * 10 / interval; i++) { + if (!ps3_ioc_state_get_with_check(instance, &ioc_state)) { + LOG_ERROR_LIM("host_no:%u get ioc state NOK\n", + PS3_HOST(instance)); + if (count++ < 3) { + continue; + } + goto l_out; + } + if (ioc_state == PS3_FW_STATE_FAULT || + ioc_state == PS3_FW_STATE_CRITICAL) { + LOG_WARN("host_no:%u ioc_state:0x%x\n", + PS3_HOST(instance), ioc_state); + goto l_out; + } + + if(atomic_read(&instance->cmd_statistics.io_outstanding) == 0) { + LOG_WARN("host_no:%u io_outstanding is zero\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + goto l_out; + } + + ps3_msleep(interval); + } + +l_out: + return ret; +} + +S32 ps3_reset_host(struct ps3_instance *instance) +{ + S32 ret = SUCCESS; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + LOG_INFO("hno:%u Host reset is requested, IOC outstanding: %d!!\n", + PS3_HOST(instance), + ps3_atomic_read(&instance->cmd_statistics.io_outstanding)); + ps3_atomic_inc(&instance->host_reset_processing); + if (ps3_host_reset_pre_check(instance) != PS3_SUCCESS) { + ret = FAILED; + goto l_out; + } + do { + if (unlikely(ps3_pci_err_recovery_get(instance))) { + LOG_WARN_LIM("hno:%u host in pci recovery during reset request\n", + PS3_HOST(instance)); + } else { + ps3_mutex_lock(&instance->state_machine.lock); + if (instance->recovery_context->host_reset_state == PS3_HOST_RESET_INIT) { + instance->recovery_context->host_reset_state = PS3_HOST_RESET_START; + ps3_mutex_unlock(&instance->state_machine.lock); + break; + } + ps3_mutex_unlock(&instance->state_machine.lock); + } + ps3_msleep(100); + } while(1); + + + ps3_mutex_lock(&instance->state_machine.lock); + if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + do{ + ps3_mutex_unlock(&instance->state_machine.lock); + ps3_msleep(100); + + ps3_mutex_lock(&instance->state_machine.lock); + if (likely(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE)) { + continue; + } else { + ps3_mutex_unlock(&instance->state_machine.lock); + cancel_work_sync(&instance->recovery_context->recovery_work); + goto wait_hard_reset; + } + }while(1); + } else if (instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW){ + ps3_mutex_unlock(&instance->state_machine.lock); + cancel_work_sync(&instance->recovery_context->recovery_work); + } else { + ps3_mutex_unlock(&instance->state_machine.lock); + } + ps3_mutex_lock(&instance->state_machine.lock); + if (unlikely(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE)) { + instance->recovery_context->recovery_state = PS3_HARD_RECOVERY_FINISH; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + if(ps3_wait_for_outstanding_complete(instance) == PS3_SUCCESS) { + ret = SUCCESS; + goto l_out; + } + + if (ps3_host_reset_pre_check(instance) != PS3_SUCCESS) { + ret = FAILED; + goto l_out; + } + + if ((ret = ps3_hard_reset_pre_check(instance) ) != PS3_SUCCESS) { + LOG_ERROR("hno:%u hard reset pre check NOK, %s!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state))); + ret = FAILED; + goto l_wait; + } + + ps3_mutex_lock(&instance->state_machine.lock); + if (instance->recovery_context->host_reset_state == PS3_HOST_RESET_HARD_RESET_DONE) { + instance->recovery_context->host_reset_state = PS3_HOST_RESET_START; + } + ps3_mutex_unlock(&instance->state_machine.lock); + + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret != PS3_SUCCESS) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + LOG_ERROR("hno:%u recovery request NOK, %s!\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = FAILED; + goto l_wait; + } + +wait_hard_reset: + ret = ps3_instance_wait_for_hard_reset_flag_done(instance); + if (ret == PS3_SUCCESS) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + LOG_INFO("hno:%u recovery success, %s!\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = SUCCESS; + goto l_wait; + } else if(ret == -PS3_RETRY){ + ps3_mutex_lock(&instance->state_machine.lock); + if (unlikely(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE)) { + instance->recovery_context->recovery_state = PS3_HARD_RECOVERY_FINISH; + } + ps3_mutex_unlock(&instance->state_machine.lock); + ret = ps3_hard_recovery_request_with_retry(instance); + if (ret != PS3_SUCCESS) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + LOG_ERROR("hno:%u recovery request NOK, %s!\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + ret = FAILED; + goto l_wait; + } + ret = ps3_instance_wait_for_hard_reset_flag_done(instance); + if (ret != PS3_SUCCESS) { + cur_state = ps3_atomic_read(&instance->state_machine.state); + LOG_ERROR("hno:%u recovery NOK, %s,host_reset_state:%d!\n", + PS3_HOST(instance),namePS3InstanceState(cur_state), + instance->recovery_context->host_reset_state); + ret = FAILED; + } else { + ret = SUCCESS; + } + }else { + ret = FAILED; + goto l_out; + } + +l_wait: + while(atomic_read(&instance->cmd_statistics.io_outstanding) != 0) { + ps3_msleep(3000); + } +l_out: + if (!instance->state_machine.is_load && + !instance->is_suspend) { + instance->state_machine.can_hostreset = PS3_FALSE; + } + INJECT_START(PS3_ERR_IJ_BLOCK_HOST_RESET, instance) + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_DEAD && + instance->state_machine.can_hostreset) { + ps3_r1x_conflict_queue_clean_all(instance, + PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT), PS3_TRUE); + ps3_qos_waitq_clear_all(instance, PS3_STATUS_HOST_NOT_FOUND); + } + ps3_mutex_lock(&instance->state_machine.lock); + instance->recovery_context->host_reset_state = PS3_HOST_RESET_INIT; + ps3_mutex_unlock(&instance->state_machine.lock); + ps3_atomic_dec(&instance->host_reset_processing); + LOG_WARN("hno:%u host reset hard recovery %d!\n", + PS3_HOST(instance), ret); + return ret; +} + +S32 ps3_err_reset_target(struct scsi_cmnd *scmd) +{ +#ifndef _WINDOWS + LOG_WARN("hno:%u enter target reset channel:%u id:%u\n", + PS3_HOST(scsi_host_data(scmd)), + PS3_SDEV_CHANNEL(scmd->device), PS3_SDEV_TARGET(scmd->device)); + + return ps3_device_reset_handler(scmd); +#else + (void)scmd; + return PS3_SUCCESS; +#endif +} + +S32 ps3_err_reset_host(struct scsi_cmnd *scmd) +{ + S32 ret = 0; +#ifndef _WINDOWS + struct ps3_instance *instance = + (struct ps3_instance*)scmd->device->host->hostdata; +#else + struct ps3_instance *instance = scsi_host_data(scmd); +#endif + + ret = ps3_reset_host(instance); + return ret; +} + +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 9) && (RHEL_MINOR >= 3)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0))) +enum scsi_timeout_action ps3_err_reset_timer(struct scsi_cmnd *scmd) +#else +enum blk_eh_timer_return ps3_err_reset_timer(struct scsi_cmnd *scmd) +#endif +{ + struct ps3_instance *instance = NULL; + ULong flags = 0; + + instance = (struct ps3_instance *)scmd->device->host->hostdata; + if (time_after(jiffies, scmd->jiffies_at_alloc + + (SCMD_GET_REQUEST(scmd)->timeout * 2))) { + LOG_FILE_WARN("reset timer not handled [%u:%u:%u:%llu], tag:%d op:0x%x " + "timeout:%u alloc_time:%lu cur_time:%lu\n", + PS3_HOST(instance), scmd->device->channel, + scmd->device->id, (U64)scmd->device->lun, SCMD_GET_REQUEST(scmd)->tag, + scmd->cmd_len > 0 ? scmd->cmnd[0] : 0xff, + SCMD_GET_REQUEST(scmd)->timeout, scmd->jiffies_at_alloc, jiffies); +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,16,0) + return BLK_EH_NOT_HANDLED; +#elif ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 9) && (RHEL_MINOR >= 3)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0))) + return SCSI_EH_NOT_HANDLED; +#else + return BLK_EH_DONE; +#endif + } + + if (instance->is_support_io_limit && + !instance->fault_context.ioc_busy) { + + spin_lock_irqsave(instance->host->host_lock, flags); + instance->host->can_queue = + instance->cmd_attr.throttle_que_depth; + instance->fault_context.last_time = jiffies; + instance->fault_context.ioc_busy = PS3_DRV_TRUE; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + } + + LOG_FILE_WARN("reset timer [%u:%u:%u:%llu], tag:%d op:0x%x " + "timeout:%u alloc_time:%lu cur_time:%lu\n", + PS3_HOST(instance), scmd->device->channel, + scmd->device->id, (U64)scmd->device->lun, SCMD_GET_REQUEST(scmd)->tag, + scmd->cmd_len > 0 ? scmd->cmnd[0] : 0xff, + SCMD_GET_REQUEST(scmd)->timeout, scmd->jiffies_at_alloc, jiffies); + +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 9) && (RHEL_MINOR >= 3)) || \ +(LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0))) + return SCSI_EH_RESET_TIMER; +#else + return BLK_EH_RESET_TIMER; +#endif +} +static void ps3_scsi_sense_print(struct ps3_instance *instance, + const U8 *sense_buffer, U8 len, S32 CFID) +{ + ps3_scsi_sense_hdr_s sshdr; + memset(&sshdr, 0, sizeof(sshdr)); + + (void)instance; + if (sense_buffer == NULL || len == 0) { + goto l_out; + } + + sshdr.resp_code = (sense_buffer[0] & PS3_SENSE_RESP_CODE_MASK); + if ((sshdr.resp_code & PS3_SENSE_RESP_CODE_VALID_MASK) != + PS3_SENSE_RESP_CODE_VALID_MASK) { + LOG_WARN_IN_IRQ(instance, + "CFID:%d sense rcode invalid:0x%x\n", CFID, + sshdr.resp_code); + goto l_out; + } + + if (sshdr.resp_code >= PS3_SENSE_RESP_CODE_DESC_FORMAT) { + if (len > 1) + sshdr.sense_key = (sense_buffer[1] & PS3_SENSE_KEY_MASK); + if (len > 2) + sshdr.asc = sense_buffer[2]; + if (len > 3) + sshdr.ascq = sense_buffer[3]; + if (len > 7) + sshdr.additional_len = sense_buffer[7]; + } else { + if (len > 2) + sshdr.sense_key = (sense_buffer[2] & PS3_SENSE_KEY_MASK); + if (len > 7) { + len = (len < (sense_buffer[7] + 8)) ? len : + (sense_buffer[7] + 8); + if (len > 12) + sshdr.asc = sense_buffer[12]; + if (len > 13) + sshdr.ascq = sense_buffer[13]; + } + } + + LOG_WARN_IN_IRQ(instance, + "sense: CFID:%d, rcode:0x%x, key:0x%x, asc:0x%x, ascq:0x%x\n", + CFID, sshdr.resp_code, sshdr.sense_key, sshdr.asc, sshdr.ascq); +l_out: + return; +} +void ps3_check_and_wait_host_reset(struct ps3_instance *instance) +{ + while(ps3_atomic_read(&instance->host_reset_processing) != 0){ + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + +return; +} diff --git a/drivers/scsi/ps3stor/ps3_scsi_cmd_err.h b/drivers/scsi/ps3stor/ps3_scsi_cmd_err.h new file mode 100644 index 0000000000000000000000000000000000000000..918bc3e123c20668db65febd02924b11d630959e --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsi_cmd_err.h @@ -0,0 +1,92 @@ + +#ifndef _PS3_SCSI_CMD_ERR_H_ +#define _PS3_SCSI_CMD_ERR_H_ + +#ifndef _WINDOWS +#include +#else +#include "ps3_cmd_adp.h" +#endif + +#include "ps3_htp_def.h" +#include "ps3_instance_manager.h" + +#define PS3_SCSI_HOST_SHIFT (16) +#define PS3_SCSI_DRIVER_SHIFT (24) + +#define PS3_SAS_DATA_PRES_SHIFT (8) +#define PS3_SAS_DATA_PRES_MASK (0x3) +#define PS3_SAS_SENSE_LEN_OFFSET (16) +#define PS3_SAS_RESPDATA_LEN_OFFSET (20) +#define PS3_SAS_SENSE_RESPDATA_LEN_BYTE (4) +#define PS3_SAS_SCSI_STATUS_OFFSET (11) +#define PS3_SAS_RESP_CODE_BYTE (3) + +#define PS3_SCSI_STATUS_MASK (0xFF) + +#define PS3_SCSI_RESULT_HOST_STATUS(STATUS) ((STATUS) << PS3_SCSI_HOST_SHIFT) +#define PS3_SCSI_RESULT_DRIVER_STATUS(STATUS) ((STATUS) << PS3_SCSI_DRIVER_SHIFT) + +#define PS3_SENSE_RESP_CODE_VALID_MASK (0x70) +#define PS3_SENSE_RESP_CODE_DESC_FORMAT (0x72) +#define PS3_SENSE_RESP_CODE_MASK (0x7F) +#define PS3_SENSE_KEY_MASK (0xF) +#define PS3_ABORT_WAIT_CMD_FLIGHT_END 50 +#define PS3_NVME_RESP_STATUS_SQ_FULL (0x102) + +enum ps3_sas_resp_code { + PS3_SAS_RESP_CODE_TASK_MGR_COMPLETE = 0x0, + PS3_SAS_RESP_CODE_INVALID_FRAME = 0x2, + PS3_SAS_RESP_CODE_TASK_MGR_NOT_SUPPORT = 0x4, + PS3_SAS_RESP_CODE_TASK_MGR_FAILED = 0x5, + PS3_SAS_RESP_CODE_TASK_MGR_SUCCESS = 0x8, + PS3_SAS_RESP_CODE_INCORRECT_LUN = 0x9, + PS3_SAS_RESP_CODE_OVERLAPPED_INIT_PORT = 0xa, +}; + +enum ps3_sas_data_pres { + PS3_SAS_PRES_NO_DATA = 0x0, + PS3_SAS_PRES_REPSNSE_DATA = 0x1, + PS3_SAS_PRES_SENSE_DATA = 0x2, + PS3_SAS_PRES_RESERVED = 0x3, +}; + +typedef struct ps3_scsi_sense_hdr { + U8 resp_code; + U8 sense_key; + U8 asc; + U8 ascq; + U8 byte4; + U8 byte5; + U8 byte6; + U8 additional_len; +} ps3_scsi_sense_hdr_s; + +S32 ps3_err_scsi_cmd_fault_proc(struct ps3_instance *instance, + struct ps3_cmd *cmd); +S32 ps3_err_scsi_task_mgr_reset(struct scsi_cmnd *scmd); +S32 ps3_err_scsi_task_mgr_abort(struct scsi_cmnd *scmd); +S32 ps3_device_reset_handler(struct scsi_cmnd *scmd); +S32 ps3_err_reset_target(struct scsi_cmnd *scmd); +S32 ps3_err_reset_host(struct scsi_cmnd *scmd); +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 9) && (RHEL_MINOR >= 3)) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0))) +enum scsi_timeout_action ps3_err_reset_timer(struct scsi_cmnd *scmd); +#else +enum blk_eh_timer_return ps3_err_reset_timer(struct scsi_cmnd *scmd); +#endif +Bool ps3_err_is_resp_from_direct_cmd(U16 mode); + +void ps3_errcode_to_scsi_status(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, U32 err_code, + PS3RespFrame_u *resp_frame, U32 xfer_cnt, struct ps3_cmd *cmd); + +S32 ps3_err_scsi_io_processing(struct ps3_instance *instance, + U32 id, U32 channel); + +S32 ps3_reset_host(struct ps3_instance *instance); + +void ps3_scsih_drv_io_reply_scsi(struct scsi_cmnd *s_cmd, struct ps3_cmd *cmd, U8 resp_status, Bool cmd_lock); +void ps3_check_and_wait_host_reset(struct ps3_instance *instance); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_scsih.c b/drivers/scsi/ps3stor/ps3_scsih.c new file mode 100644 index 0000000000000000000000000000000000000000..041cb5a357596ab117dfd239ba43766d2aa99d64 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsih.c @@ -0,0 +1,3457 @@ +#include "ps3_scsih.h" + +#ifndef _WINDOWS +#include +#include +#include +#include +#include "ps3_module_para.h" +#include +#include + +#endif + +#include "ps3_htp.h" +#include "ps3_meta.h" +#include "ps3_err_def.h" +#include "ps3_instance_manager.h" +#include "ps3_cmd_channel.h" +#include "ps3_scsi_cmd_err.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_util.h" +#include "ps3_cmd_statistics.h" +#include "ps3_scsih_raid_engine.h" +#include "ps3_module_para.h" +#include "ps3_device_manager.h" +#include "ps3_r1x_write_lock.h" +#include "ps3_io_trace.h" +#include "ps3_htp_sas.h" + +static S32 ps3_scsih_vd_req_frame_build(struct ps3_cmd *cmd); +static S32 ps3_scsih_sas_hw_req_frame_build(struct ps3_cmd *cmd, + U16 disk_id, U64 data_addr, U32 sge_count); +static S32 ps3_scsih_sas_req_frame_build(struct ps3_cmd *cmd); +static S32 ps3_scsih_sata_req_frame_build(struct ps3_cmd *cmd); +static S32 ps3_scsih_nvme_req_frame_build(struct ps3_cmd *cmd); +static inline U16 ps3_scsih_is_use_hard_cmd(const struct ps3_cmd *cmd); +static S32 ps3_vd_access_policy_check(struct ps3_instance *instance, + U8 channel, U16 id, struct scsi_cmnd *s_cmd); +static U16 ps3_scsih_frontend_data_buf_build(struct ps3_cmd *cmd, + PS3FrontEndReqFrame_s *req); +static void ps3_scsih_req_frame_head_build(struct ps3_cmd *cmd, + U8 req_frame_format); +static inline void ps3_scsih_print_req_head(struct ps3_cmd *cmd, U8 log_level); +static U32 ps3_scsih_datelen_calc(const struct ps3_cmd *cmd); + +#ifdef _WINDOWS +static void ps3_scsi_need_remap_check(struct ps3_cmd *cmd); +static S32 ps3_scsi_remap_sgl(struct ps3_cmd *cmd); +#endif + +#define PS3_CMD_WORD_QUE_CALC(vd_id, lba, map_block, que_num) \ + (((vd_id) + ((lba) / (map_block))) & que_num) + +#define PS3_SCSIH_NOT_SAME_MAPBLOCK(lba, map_block, num_blocks) \ + (((map_block) - ((lba) % (map_block))) < (num_blocks)) +#define PS3_LBA(lba_hi, lba_lo) \ + ((((U64)(lba_hi)) << PS3_SHIFT_DWORD) | (lba_lo)) + +#ifndef _WINDOWS +#define sg_dma_address_u64(sg) sg_dma_address(sg) +#endif + +#define UNMAP_PARAM_LEN (8) +#define UNMAP_DESCRIPTOR_LEN (16) +#define UNMAP_CDB_VALID_LEN (10) + +static struct disk_type_to_proc_func_table g_req_frame_func_table[] = { + {PS3_DEV_TYPE_VD, ps3_scsih_vd_req_frame_build}, + {PS3_DEV_TYPE_SAS_HDD, ps3_scsih_sas_req_frame_build}, + {PS3_DEV_TYPE_SATA_HDD, ps3_scsih_sata_req_frame_build}, + {PS3_DEV_TYPE_SATA_SSD, ps3_scsih_sata_req_frame_build}, + {PS3_DEV_TYPE_SAS_SSD, ps3_scsih_sas_req_frame_build}, + {PS3_DEV_TYPE_NVME_SSD, ps3_scsih_nvme_req_frame_build}, + {PS3_DEV_TYPE_SES, ps3_scsih_sas_req_frame_build}, + {PS3_DEV_TYPE_VEP, ps3_scsih_sas_req_frame_build} + +}; +#ifndef _WINDOWS + +Bool ps3_scsih_stream_is_detect(struct ps3_cmd *cmd) +{ + struct ps3_scsi_priv_data *data = + (struct ps3_scsi_priv_data *)cmd->scmd->device->hostdata; + + struct ps3_vd_stream_detect *current_ld_sd; + u64 *track_stream; + u8 stream_num; + u64 shifted_values, unshifted_values; + u64 index_value_mask, shifted_values_mask; + u32 index; + struct ps3_stream_detect *current_sd; + u64 lba = 0; + u32 len = 0; + Bool is_stream = PS3_FALSE; + U32 typeIndex; + u32 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(cmd->scmd->cmnd)); + ULong flag = 0; + S64 value = 0; + + if (PS3_IF_QUIT_STREAM_DIRECT_DETECT()) { + goto l_out; + } + + + if((type != PS3_SCSI_CMD_TYPE_READ) && (type != PS3_SCSI_CMD_TYPE_WRITE)){ + goto l_out; + } + + typeIndex = type - PS3_SCSI_CMD_TYPE_READ; + current_ld_sd = &(data->vd_sd[typeIndex]); + ps3_spin_lock_irqsave(¤t_ld_sd->ps3_sequence_stream_lock, &flag); + track_stream = ¤t_ld_sd->mru_bit_map; + + ps3_scsih_lba_parse(cmd->scmd->cmnd, &lba); + ps3_scsih_len_parse(cmd->scmd->cmnd, &len); + for (index = 0; index < PS3_IO_MAX_STREAMS_TRACKED; ++index) { + stream_num = (*track_stream >> + (index << BITS_PER_INDEX_STREAM_SHIFT)) & + STREAM_MASK; + current_sd = ¤t_ld_sd->stream_track[stream_num]; + value = current_sd->next_seq_lba - IO_STREAM_DETECT_RANGE; + + if ((((value >= 0) && + (lba >= current_sd->next_seq_lba - IO_STREAM_DETECT_RANGE) && + (lba <= (current_sd->next_seq_lba + IO_STREAM_DETECT_RANGE * 2))) || + ((current_sd->next_seq_lba) && + (lba >= current_sd->next_seq_lba) && + (lba <= (current_sd->next_seq_lba + 32))))&& + (type == current_sd->rw_type)){ + is_stream = PS3_TRUE; + cmd->io_attr.seq_flag = SCSI_RW_SEQ_CMD; + cmd->req_frame->frontendReq.reqHead.isStream1 = PS3_TRUE; + current_sd->next_seq_lba = + lba + len; + + shifted_values_mask = + (1ULL << (index << BITS_PER_INDEX_STREAM_SHIFT)) - 1; + shifted_values = ((*track_stream & shifted_values_mask) + << BITS_PER_INDEX_STREAM); + index_value_mask = + STREAM_MASK << (index << BITS_PER_INDEX_STREAM_SHIFT); + unshifted_values = + *track_stream & ~(shifted_values_mask | + index_value_mask); + *track_stream = + unshifted_values | shifted_values | stream_num; + goto end; + } + } + stream_num = (*track_stream >> ((PS3_IO_MAX_STREAMS_TRACKED - 1) << + BITS_PER_INDEX_STREAM_SHIFT)) & STREAM_MASK; + current_sd = ¤t_ld_sd->stream_track[stream_num]; + current_sd->rw_type = type; + current_sd->next_seq_lba = lba + len; + *track_stream = (((*track_stream & ZERO_LAST_STREAM) << 4) | stream_num); + cmd->io_attr.seq_flag = SCSI_RW_RANDOM_CMD; + +end: + ps3_spin_unlock_irqrestore(¤t_ld_sd->ps3_sequence_stream_lock, flag); +l_out: + INJECT_START(PS3_ERR_IJ_FORCE_SEQ_CMD, cmd); + INJECT_START(PS3_ERR_IJ_FORCE_STREAM_DETECT_TRUE, &is_stream); + + INJECT_START(PS3_ERR_IJ_FORCE_RAND_CMD, cmd); + INJECT_START(PS3_ERR_IJ_FORCE_STREAM_DETECT_FALSE, &is_stream); + return is_stream; +} +Bool ps3_raid_scsih_stream_is_direct(const struct ps3_cmd *cmd) +{ + struct ps3_scsi_priv_data *p_priv_data = scsi_device_private_data(cmd->scmd); + Bool is_direct = PS3_TRUE; + + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD) { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (cmd->io_attr.vd_entry->isNvme || !(cmd->io_attr.vd_entry->isSsd && + (ps3_atomic_read(&p_priv_data->rd_io_outstand) > PS3_VD_IO_16_OUTSTANDING) && + (cmd->io_attr.num_blocks > PS3_BLOCK_NUM_OF_32K))) { + is_direct = PS3_FALSE; + } + } + } + + return is_direct; +} +Bool ps3_hba_scsih_stream_is_direct(const struct ps3_cmd *cmd) +{ + Bool is_direct = PS3_TRUE; + struct ps3_scsi_priv_data *p_priv_data = scsi_device_private_data(cmd->scmd); + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD && + cmd->io_attr.vd_entry->isNvme && + ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (ps3_atomic_read(&p_priv_data->rd_io_outstand) > PS3_VD_IO_16_OUTSTANDING && + cmd->io_attr.num_blocks > PS3_BLOCK_NUM_OF_32K) { + is_direct = PS3_FALSE; + } + } + + return is_direct; +} + +static Bool ps3_scsih_sys_state_check(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, S32 *scsi_result) +{ + Bool ret = PS3_TRUE; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + + *scsi_result = PS3_SUCCESS; + if (!instance->state_machine.is_load) { + LOG_INFO_LIM("hno:%u instance state not is_load\n", PS3_HOST(instance)); + goto l_scsi_done; + } + + PS3_IO_START_INC(instance, s_cmd); + cur_state = atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_DEAD || + cur_state == PS3_INSTANCE_STATE_QUIT) { + PS3_IO_BACK_ERR_INC(instance, s_cmd); + LOG_INFO_LIM("hno:%u instance state is dead/quit\n", PS3_HOST(instance)); + goto l_scsi_done; + } + + if (instance->recovery_context->host_reset_state != PS3_HOST_RESET_INIT) { + *scsi_result = SCSI_MLQUEUE_HOST_BUSY; + ret = PS3_FALSE; + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + LOG_WARN_LIM("hno:%u host_Reset_state:%d\n", PS3_HOST(instance),instance->recovery_context->host_reset_state); + goto l_out; + } + + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_SOFT_RECOVERY) { + *scsi_result = SCSI_MLQUEUE_HOST_BUSY; + ret = PS3_FALSE; + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + LOG_INFO_LIM("hno:%u cannot request scsi cmd tag:%d due to %s\n", + PS3_HOST(instance), SCMD_GET_REQUEST(s_cmd)->tag, + namePS3InstanceState(cur_state)); + goto l_out; + } + + goto l_out; + +l_scsi_done: + PS3_DEV_BUSY_DEC(s_cmd); + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + SCMD_IO_DONE(s_cmd); + *scsi_result = PS3_SUCCESS; + ret = PS3_FALSE; + +l_out: + return ret; +} + +static inline Bool ps3_scsih_is_illegel_vd_io(const struct scsi_cmnd *s_cmd, + struct ps3_instance *instance) +{ + return(!ps3_dev_id_valid_check(instance, s_cmd->device->channel, + s_cmd->device->id, PS3_DISK_TYPE_VD) || s_cmd->device->lun); +} + +static Bool ps3_scsih_device_attr_check(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, S32 *scsi_result) +{ + Bool ret = PS3_TRUE; + struct ps3_scsi_priv_data *data = NULL; + static unsigned long j; + *scsi_result = PS3_SUCCESS; + if (unlikely(instance->task_manager_host_busy)) { + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + *scsi_result = SCSI_MLQUEUE_DEVICE_BUSY; + ret = PS3_FALSE; + LOG_INFO_LIM("hno:%u task_manager_host_busy\n", PS3_HOST(instance)); + goto l_out; + } + + data = (struct ps3_scsi_priv_data*)s_cmd->device->hostdata; + if (unlikely(data == NULL)) { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u device_priv_data is null s_cmd result:%d\n", + PS3_HOST(instance), s_cmd->result); + goto l_scsi_done; + } + + if (unlikely(data->task_manager_busy)) { + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + *scsi_result = SCSI_MLQUEUE_DEVICE_BUSY; + ret = PS3_FALSE; + LOG_INFO_LIM("hno:%u task_manager_busy\n", PS3_HOST(instance)); + goto l_out; + } + + if (data->dev_type == PS3_DEV_TYPE_VD) { + if (unlikely(ps3_scsih_is_illegel_vd_io(s_cmd, instance))) { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_BAD_TARGET); + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u dev_type:%s id:%u " + "max_vd_count:%u vd id NOK\n", PS3_HOST(instance), + namePS3DevType((enum PS3DevType)data->dev_type), + s_cmd->device->id, instance->ctrl_info.maxVdCount); + goto l_scsi_done; + } + + if (unlikely(ps3_vd_access_policy_check(instance, s_cmd->device->channel, + s_cmd->device->id, s_cmd) != PS3_SUCCESS)) { + goto l_scsi_done; + } + } + +#if 0 + if ((s_cmd->cmnd[0] == SYNCHRONIZE_CACHE) && is_vd_io && + !instance->is_support_sync_cache) { + s_cmd->result = DID_OK << PS3_SHIFT_WORD; + LOG_ERROR("hno:%u SYNCHRONIZE_CACHE cmd, return\n", + PS3_HOST(instance)); + goto l_out; + } +#endif + + goto l_out; + +l_scsi_done: + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + *scsi_result = PS3_SUCCESS; + ret = PS3_FALSE; + SCMD_IO_DONE(s_cmd); +l_out: + return ret; +} + +static inline U8 ps3_scsih_dev_type_get(const struct scsi_cmnd *s_cmd) +{ + struct ps3_scsi_priv_data *data = + (struct ps3_scsi_priv_data*)s_cmd->device->hostdata; + return data->dev_type; +} + +static inline Bool ps3_scsih_is_vd_scsi_rw_cmd(const struct scsi_cmnd *s_cmd) +{ + return (ps3_scsih_dev_type_get(s_cmd) == PS3_DEV_TYPE_VD) ? + ps3_scsih_cdb_is_rw_cmd(s_cmd->cmnd) : PS3_DRV_FALSE; +} + +static Bool ps3_scsih_qos_check(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, S32 *scsi_result) +{ + Bool ret = PS3_DRV_TRUE; + S32 vd_io_threshold = instance->cmd_attr.vd_io_threshold; + S32 io_outstand = 0; + S32 vd_io_outstand = 0; + + if (unlikely(!ps3_stat_outstand_switch_is_open(instance))) { + goto l_out; + } + + io_outstand = atomic_inc_return(&instance->cmd_statistics.io_outstanding); + if (unlikely(io_outstand > instance->host->can_queue)) { + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + *scsi_result = SCSI_MLQUEUE_HOST_BUSY; + ret = PS3_FALSE; + + LOG_INFO_LIM("hno:%u ioc io exceed can_queue:%d io_outstanding:%d\n", + PS3_HOST(instance), instance->host->can_queue, io_outstand); + goto l_dec_io_outstand; + } + + if (unlikely(vd_io_threshold && ps3_scsih_is_vd_scsi_rw_cmd(s_cmd))) { + vd_io_outstand = atomic_inc_return(&instance->cmd_statistics.vd_io_outstanding); + if (unlikely(vd_io_outstand > vd_io_threshold)) { + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + *scsi_result = SCSI_MLQUEUE_DEVICE_BUSY; + ret = PS3_FALSE; + LOG_INFO_LIM("hno:%u vd io exceed vd_io_threshold:%d vd_outstanding:%d\n", + PS3_HOST(instance), vd_io_threshold, vd_io_outstand); + goto l_dec_vd_io_outstand; + } + } + + PS3_VD_OUTSTAND_INC(instance, s_cmd); + + goto l_out; + +l_dec_vd_io_outstand: + atomic_dec(&instance->cmd_statistics.vd_io_outstanding); +l_dec_io_outstand: + atomic_dec(&instance->cmd_statistics.io_outstanding); +l_out: + return ret; +} + +static Bool ps3_scsih_que_cmd_check(struct ps3_instance *instance, + struct scsi_cmnd *s_cmd, S32 *scsi_result) +{ + Bool ret = PS3_TRUE; + + s_cmd->result = DID_OK; + ret = ps3_scsih_sys_state_check(instance, s_cmd, scsi_result); + if (unlikely(!ret)) { + goto l_out; + } + + ret = ps3_scsih_device_attr_check(instance, s_cmd, scsi_result); + if (unlikely(!ret)) { + goto l_out; + } + + ret = ps3_scsih_qos_check(instance, s_cmd, scsi_result); + +l_out: + return ret; +} + +#else +Bool ps3_scsih_sys_state_check(struct ps3_instance *instance, S32 *host_status) +{ + Bool ret = PS3_DRV_TRUE; + S32 cur_state = PS3_INSTANCE_STATE_INIT; + static unsigned long j; + if (!instance->state_machine.is_load) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u instance state not is_load\n", PS3_HOST(instance)); + *host_status = DID_ERROR; + goto l_out; + } + + cur_state = ps3_atomic_read(&instance->state_machine.state); + if (cur_state == PS3_INSTANCE_STATE_DEAD || + cur_state == PS3_INSTANCE_STATE_QUIT) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u instance state is dead/quit\n", PS3_HOST(instance)); + *host_status = DID_BAD_TARGET; + goto l_out; + } + + if (cur_state != PS3_INSTANCE_STATE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_PRE_OPERATIONAL && + cur_state != PS3_INSTANCE_STATE_SOFT_RECOVERY) { + ret = PS3_DRV_FALSE; + *host_status = DID_BUS_BUSY; + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u cannot request scsi cmd due to %s\n", + PS3_HOST(instance), namePS3InstanceState(cur_state)); + goto l_out; + } + +l_out: + return ret; +} + +Bool ps3_scsih_stream_is_detect(struct ps3_cmd *cmd) +{ + (void)cmd; + return PS3_FALSE; +} +#endif + +#if 0 +static Bool ps3_synchronize_cache_filter(struct scsi_cmnd *s_cmd) +{ + (void)s_cmd; + return PS3_DRV_FALSE; +} +#endif + +#ifndef _WINDOWS +S32 ps3_scsih_queue_command(struct Scsi_Host *s_host, + struct scsi_cmnd *s_cmd) +{ + S32 ret = PS3_SUCCESS; + struct ps3_cmd *cmd = NULL; + struct ps3_instance *instance = NULL; + struct ps3_scsi_priv_data *data = (struct ps3_scsi_priv_data *)s_cmd->device->hostdata; + static unsigned long j; + instance = (struct ps3_instance *)s_host->hostdata; + if (unlikely(instance == NULL)) { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + PS3_BUG_ON(instance == NULL); + goto l_scsi_done; + } + + LOG_DEBUG("hno:%u tag:%d op:0x%x cmd_len:%d chl:%u " + "id:%u timeout:%u\n", s_host->host_no, SCMD_GET_REQUEST(s_cmd)->tag, + s_cmd->cmnd[0], s_cmd->cmd_len, s_cmd->device->channel, + s_cmd->device->id, SCMD_GET_REQUEST(s_cmd)->timeout); + + PS3_DEV_BUSY_INC(s_cmd); + if (unlikely(!ps3_scsih_que_cmd_check(instance, s_cmd, &ret))) { + goto l_out; + } + + INJECT_START(PS3_ERR_IJ_CMD_BLOCK_BEFORE_DELIVER_CNT, instance); + if (unlikely(s_cmd->cmd_len > PS3_FRAME_CDB_BUFLEN)) { + LOG_ERROR("hno:%u cmd len %u check NOK\n", PS3_HOST(instance), s_cmd->cmd_len); + PS3_BUG(); + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_ERROR); + goto l_scsi_done; + } + + ps3_scsi_cmd_deliver_get(instance); + INJECT_START(PS3_ERR_IJ_CMD_SEND_INSTANCE_RECOVERY, instance); + if (unlikely(!ps3_is_instance_state_normal(instance, PS3_TRUE))) { + ret = SCSI_MLQUEUE_HOST_BUSY; + goto l_cmd_stat_dec; + } + + cmd = ps3_scsi_cmd_alloc(instance, SCMD_GET_REQUEST(s_cmd)->tag); + if (unlikely(cmd == NULL)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u tag:%d ps3_cmd_get NOK ret:%d\n", + PS3_HOST(instance), SCMD_GET_REQUEST(s_cmd)->tag, ret); + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_IO_OUTSTAND_DEC(instance, s_cmd); + PS3_VD_OUTSTAND_DEC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + ret = SCSI_MLQUEUE_HOST_BUSY; + ps3_scsi_cmd_deliver_put(instance); + goto l_scsi_done; + } + + INJECT_START(PS3_ERR_IJ_CMD_BLOCK_BEFORE_SEND_TO_IOC, instance); + if (cmd->scmd != NULL) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u CFID:%u cmd is exist\n", + PS3_HOST(instance), SCMD_GET_REQUEST(s_cmd)->tag); + PS3_BUG(); + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + goto l_cmd_stat_dec; + } + + cmd->scmd = s_cmd; + + ret = instance->ioc_adpter->io_cmd_build(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + switch (ret) { + case -PS3_IO_CONFLICT: + ps3_errcode_to_scsi_status(instance, s_cmd, SCSI_STATUS_BUSY, NULL, 0, cmd); + ret = SCSI_MLQUEUE_DEVICE_BUSY; + goto l_cmd_release; + break; + case -PS3_IO_REQUEUE: + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_REQUEUE); + break; + case -PS3_IO_CONFLICT_IN_Q: + LOG_DEBUG("tid:0x%llx hno:%u tag:%d conflict in queue, " + "timeout:%u alloc_time:%lu cur_time:%lu\n", + cmd->trace_id, PS3_HOST(instance), + SCMD_GET_REQUEST(s_cmd)->tag, + SCMD_GET_REQUEST(s_cmd)->timeout, + s_cmd->jiffies_at_alloc, jiffies); + ret = PS3_SUCCESS; + cmd->flighting = PS3_FALSE; + wmb(); + ps3_scsi_cmd_deliver_put(instance); + goto l_out; + break; + case -PS3_IN_QOS_Q: + ret = PS3_SUCCESS; + cmd->flighting = PS3_FALSE; + wmb(); + ps3_scsi_cmd_deliver_put(instance); + goto l_out; + case -PS3_RETRY: + ret = SCSI_MLQUEUE_DEVICE_BUSY; + goto l_cmd_release; + case -PS3_RECOVERED: + case SCSI_MLQUEUE_HOST_BUSY: + ret = SCSI_MLQUEUE_HOST_BUSY; + goto l_cmd_release; + default: + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + break; + } + LOG_DEBUG("tid:0x%llx hno:%u tag:%d cmd build err ret:%d\n", + cmd->trace_id, PS3_HOST(instance), SCMD_GET_REQUEST(s_cmd)->tag, ret); + ret = PS3_SUCCESS; + goto l_cmd_release; + } + + INJECT_START(PS3_ERR_IJ_CMD_SEND_WAIT_RECOVERY_END, instance); + ret = ps3_scsi_cmd_send(instance, cmd, PS3_TRUE); + if (unlikely(ret != PS3_SUCCESS)) { + ps3_qos_cmd_update(instance, cmd); + if (ret == -PS3_RECOVERED) { + ret = SCSI_MLQUEUE_HOST_BUSY; + } else if (ret == -PS3_RETRY) { + ret = SCSI_MLQUEUE_DEVICE_BUSY; + } else { + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_NO_CONNECT); + ret = PS3_SUCCESS; + } + LOG_ERROR_LIM("tid:0x%llx hno:%u tag:%d cmd send NOK ret:%d\n", + cmd->trace_id, PS3_HOST(instance), SCMD_GET_REQUEST(s_cmd)->tag, ret); + PS3_DEV_IO_START_ERR_INC(instance, cmd); + goto l_cmd_release; + } + + ps3_scsi_cmd_deliver_put(instance); + goto l_out; + +l_cmd_release: + ps3_scsi_dma_unmap(cmd); + if (cmd->is_got_r1x == 1) { + data = (struct ps3_scsi_priv_data *)s_cmd->device->hostdata; + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + } + + ps3_scsi_cmd_free(cmd); +l_cmd_stat_dec: + PS3_IO_BACK_ERR_INC(instance, s_cmd); + PS3_IO_OUTSTAND_DEC(instance, s_cmd); + PS3_VD_OUTSTAND_DEC(instance, s_cmd); + PS3_DEV_BUSY_DEC(s_cmd); + ps3_scsi_cmd_deliver_put(instance); +l_scsi_done: + if (ret != SCSI_MLQUEUE_HOST_BUSY && ret != SCSI_MLQUEUE_DEVICE_BUSY) { + SCMD_IO_DONE(s_cmd); + } +l_out: + return ret; +} + +#endif +static inline Bool ps3_is_need_build_hw_req_frame(const struct ps3_cmd *cmd) +{ + return ps3_scsih_is_use_hard_cmd(cmd) == PS3_CMDWORD_FORMAT_HARDWARE; +} + +Bool ps3_is_r1x_write_cmd(const struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + + switch(cmd->io_attr.vd_entry->raidLevel) { + case RAID1: + case RAID10: + case RAID1E: + if (cmd->io_attr.rw_flag == PS3_SCSI_CMD_TYPE_WRITE) { + ret = PS3_TRUE; + } + break; + default: + ret = PS3_FALSE; + break; + } + + return ret; +} + +static Bool direct_cmd_is_raidlevel_support(struct ps3_cmd *cmd) +{ + Bool ret = PS3_DRV_TRUE; + + switch(cmd->io_attr.vd_entry->raidLevel) { + case RAID0: + case RAID00: + break; + case RAID1: + case RAID10: + case RAID1E: + if (cmd->instance->cmd_context.max_r1x_cmd_count > 0) { + if (cmd->io_attr.rw_flag == PS3_SCSI_CMD_TYPE_READ || + cmd->io_attr.rw_flag == PS3_SCSI_CMD_TYPE_WRITE) { + ret = PS3_TRUE; + } else { + ret = PS3_FALSE; + } + } else if (cmd->io_attr.rw_flag != PS3_SCSI_CMD_TYPE_READ) { + ret = PS3_FALSE; + } + break; + case RAID5: + case RAID6: + case RAID50: + case RAID60: + if (cmd->io_attr.rw_flag != PS3_SCSI_CMD_TYPE_READ) { + ret = PS3_FALSE; + } + break; + default: + ret = PS3_FALSE; + break; + } + + return ret; +} + +static Bool direct_cmd_is_plba_sector_aligned(struct ps3_cmd *cmd, + const struct ps3_pd_entry *pd) +{ + const struct PS3VDEntry *vd = cmd->io_attr.vd_entry; + Bool ret = PS3_DRV_FALSE; + + if (unlikely(pd->sector_size == 0)) { + LOG_FILE_ERROR("pd chl:%u id:%u sector_size is 0\n", + PS3_CHANNEL(&pd->disk_pos), + PS3_TARGET(&pd->disk_pos)); + goto l_out; + } +#ifndef _WINDOWS + if ((cmd->io_attr.plba << ilog2(vd->sectorSize)) % pd->sector_size) { +#else + if ((cmd->io_attr.plba * vd->sectorSize) % pd->sector_size) { +#endif + LOG_DEBUG("pd chl:%u id:%u plba:0x%llx pd sector_size:%u\n", + PS3_CHANNEL(&pd->disk_pos), PS3_TARGET(&pd->disk_pos), + cmd->io_attr.plba, pd->sector_size); + goto l_out; + } +#ifndef _WINDOWS + if ((cmd->io_attr.num_blocks << ilog2(vd->sectorSize)) % pd->sector_size) { +#else + if ((cmd->io_attr.num_blocks * vd->sectorSize) % pd->sector_size) { +#endif + LOG_DEBUG("num_blocks:%u pd sector_size:%u vd sector_size:%u\n", + cmd->io_attr.num_blocks, pd->sector_size, vd->sectorSize); + goto l_out; + } + ret = PS3_DRV_TRUE; +l_out: + return ret; +} +Bool ps3_scsih_sata_direct_is_support(struct ps3_cmd *cmd, + const struct ps3_pd_entry *pd_entry) +{ + Bool ret = PS3_FALSE; + + if (cmd == NULL || cmd->instance == NULL || + pd_entry == NULL) { + LOG_ERROR_LIM("sata direct support judge parameter NOK\n"); + goto l_out; + } + + if (cmd->instance->ctrl_info.capabilities.supportSataNcq == 0) { + LOG_DEBUG("IOC SATA NCQ not support\n"); + goto l_out; + } + + if (pd_entry->support_ncq == 0) { + LOG_DEBUG("SATA ncq not support\n"); + goto l_out; + } + ret = PS3_TRUE; + +l_out: + return ret; +} + +static inline Bool ps3_scsih_datelen_buflen_is_match(const struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + U32 data_len = 0; + + data_len = ps3_scsih_datelen_calc(cmd); + + if(data_len != scsi_bufflen(cmd->scmd)) { + LOG_INFO("data_len:%u not equal to bufflen:%u\n", + data_len, scsi_bufflen(cmd->scmd)); + goto l_out; + } + ret = PS3_TRUE; + +l_out: + return ret; +} + +static U32 ps3_scsih_datelen_calc(const struct ps3_cmd *cmd) +{ + U16 sector_size = 0; + U32 num_blocks = 0; + U32 date_len = 0; + static unsigned long j; + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + if (cmd->io_attr.vd_entry == NULL) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "host parameter NOK\n"); + goto l_out; + } + sector_size = cmd->io_attr.vd_entry->sectorSize; + + } else { + sector_size = cmd->io_attr.pd_entry->sector_size; + } + if (sector_size == 0) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "host parameter NOK\n"); + goto l_out; + } + num_blocks = cmd->io_attr.num_blocks; + date_len = num_blocks << ilog2(sector_size); + +l_out: + return date_len; +} + +Bool ps3_scsih_sata_direct_is_need(struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + + if (cmd->scmd->cmd_len == 32) { + LOG_DEBUG("read32 or write32 no need direct\n"); + goto l_out; + } + + if(ps3_scsih_datelen_buflen_is_match(cmd) != PS3_TRUE) { + goto l_out; + } + + if (ps3_scsih_cdb_opts_parse(cmd) == PS3_SUCCESS) { + if (likely(cmd->io_attr.cdb_opts.protect == 0 && + cmd->io_attr.cdb_opts.fua == 0)) { + ret = PS3_TRUE; + } else { + LOG_DEBUG("SATA cdb_opts is 0x%x\n", cmd->io_attr.cdb_opts.option); + } + } else { + LOG_DEBUG("SATA options parse failure\n"); + } +l_out: + return ret; +} + +static inline Bool ps3_scsih_sas_direct_is_need(const struct ps3_cmd *cmd) +{ + (void)cmd; + return PS3_TRUE; +} + +static inline Bool ps3_scsih_nvme_direct_is_need(struct ps3_cmd *cmd) +{ + if (ps3_scsih_cdb_opts_parse(cmd) == PS3_SUCCESS) { + if (likely(cmd->io_attr.cdb_opts.protect != 0)) { + LOG_DEBUG("NVMe protect is 0x%x\n", cmd->io_attr.cdb_opts.protect); + return PS3_FALSE; + } + } else { + LOG_DEBUG("NVMe options parse failure\n"); + return PS3_FALSE; + } + + return (ps3_scsih_datelen_buflen_is_match(cmd) == PS3_TRUE); +} + +static Bool ps3_scsih_direct_cmd_is_supported_logic(struct ps3_cmd *cmd, + const struct ps3_pd_entry *pd_entry) +{ + Bool ret = PS3_FALSE; + if (pd_entry == NULL) { + PS3_BUG(); + goto l_out; + } + + switch (pd_entry->dev_type) + { + case PS3_DEV_TYPE_SATA_SSD: + case PS3_DEV_TYPE_SATA_HDD: + ret = ps3_scsih_sata_direct_is_need(cmd); + break; + case PS3_DEV_TYPE_SAS_SSD: + case PS3_DEV_TYPE_SAS_HDD: + ret = ps3_scsih_sas_direct_is_need(cmd); + break; + case PS3_DEV_TYPE_NVME_SSD: + ret = ps3_scsih_nvme_direct_is_need(cmd); + break; + default: + ret = PS3_FALSE; + break; + } +l_out: + return ret; +} + +static Bool direct_cmd_is_supported_device(struct ps3_cmd *cmd, + const struct ps3_pd_entry *pd_entry) +{ + Bool ret = PS3_FALSE; + if (pd_entry == NULL) { + LOG_ERROR("tid:0x%llx hno:%u CFID:%d pd entry is NULL\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index); + PS3_BUG(); + return ret; + } + if (pd_entry->is_direct_disable) { + LOG_DEBUG("Direct is disable\n"); + return ret; + } + switch (pd_entry->dev_type) + { + case PS3_DEV_TYPE_SATA_SSD: + case PS3_DEV_TYPE_SATA_HDD: + ret = ps3_scsih_sata_direct_is_support(cmd, pd_entry); + break; + case PS3_DEV_TYPE_SAS_SSD: + case PS3_DEV_TYPE_SAS_HDD: + ret = PS3_TRUE; + break; + case PS3_DEV_TYPE_NVME_SSD: + ret = ps3_scsih_is_protocal_rw(cmd->scmd->cmnd); + break; + default: + ret = PS3_FALSE; + break; + } + + return ret; +} + +static inline S32 ps3_scsih_is_valid_vlba(struct ps3_cmd *cmd) +{ + return ((U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo) + + cmd->io_attr.num_blocks) > cmd->io_attr.vd_entry->capacity) ? + -PS3_FAILED : PS3_SUCCESS; +} + +static inline Bool ps3_scsih_is_direct_to_normal(const struct ps3_instance *instance, + const struct ps3_cmd *cmd) +{ + return (instance->ioc_adpter->is_need_direct_to_normal != NULL && + instance->ioc_adpter->is_need_direct_to_normal(cmd)); +} + +static inline Bool ps3_scsih_is_sas_jbod_cmd(const struct ps3_cmd *cmd) +{ + return cmd->io_attr.dev_type == PS3_DEV_TYPE_SAS_HDD || + cmd->io_attr.dev_type == PS3_DEV_TYPE_SAS_SSD; +} + +static inline Bool ps3_scsih_is_sata_jbod_cmd(const struct ps3_cmd *cmd) +{ + return cmd->io_attr.dev_type == PS3_DEV_TYPE_SATA_HDD || + cmd->io_attr.dev_type == PS3_DEV_TYPE_SATA_SSD; +} + +Bool ps3_scsih_is_sata_jbod_mgr_cmd(const struct ps3_cmd *cmd) +{ + return (ps3_scsih_is_sata_jbod_cmd(cmd)) + && (!ps3_scsih_cdb_is_rw_cmd(cmd->scmd->cmnd)); +} + +U32 ps3_scsih_xfer_cnt_get(const struct ps3_cmd *cmd) +{ + U32 xfer_cnt = 0; + + PS3RespFrame_u *resp_frame = cmd->resp_frame; + U16 mode = cmd->reply_word.mode; + + if (ps3_err_is_resp_from_direct_cmd(mode) + && (cmd->io_attr.dev_type != PS3_DEV_TYPE_VD)) { + xfer_cnt = resp_frame->sasRespFrame.xfer_cnt; + } else { + xfer_cnt = resp_frame->normalRespFrame.respDetail.xfer_cnt; + } + return xfer_cnt; +} +static inline Bool ps3_scsih_hdd_vd_direct_check(const struct ps3_cmd *cmd) +{ + Bool is_direct = PS3_TRUE; + struct ps3_scsi_priv_data *p_priv_data = scsi_device_private_data(cmd->scmd); + + if (p_priv_data->dev_type == PS3_DEV_TYPE_VD) { + if (!cmd->io_attr.vd_entry->isNvme && !cmd->io_attr.vd_entry->isSsd) { + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) && + (ps3_atomic_read(&p_priv_data->wr_io_outstand) != PS3_VD_IO_1_OUTSTANDING)) { + is_direct = PS3_FALSE; + } else if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + is_direct = PS3_FALSE; + } + } + } + return is_direct; +} + +static void ps3_scsih_build_direct_cmd(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U64 lba = 0; + + struct ps3_cmd_attr_context *cmd_attr = &cmd->instance->cmd_attr; + + if (!cmd_attr->is_support_direct_cmd) { + goto l_out; + } + + if (cmd->io_attr.is_force_normal) { + goto l_out; + } + + if (!ps3_scsih_is_rw_type(cmd->io_attr.rw_flag)) { + goto l_out; + } + + if ((!ps3_scsih_is_protocal_rw(cmd->scmd->cmnd)) && + ps3_scsih_is_sas_jbod_cmd(cmd)) { + goto l_out; + } + + if (unlikely(cmd->io_attr.num_blocks == 0)) { + LOG_DEBUG("tid:0x%llx hno:%u num blocks is zero\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + if (unlikely(cmd->io_attr.is_retry_cmd && + ps3_scsih_is_direct_to_normal(cmd->instance, cmd))) { + LOG_FILE_WARN("tid:0x%llx hno:%u is_retry_cmd \n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + if (cmd->instance->ioc_adpter->scsih_stream_is_detect != NULL && + cmd->instance->ioc_adpter->scsih_stream_is_detect(cmd)) { + + LOG_DEBUG("hno[%u], cmd index[%u], tid[0x%llx], detected it is sequential io\n", + PS3_HOST(cmd->instance), cmd->index, cmd->trace_id); + if (cmd->instance->ioc_adpter->scsih_stream_is_direct != NULL && \ + !cmd->instance->ioc_adpter->scsih_stream_is_direct(cmd)) { + goto l_out; + } + } + if (unlikely(!cmd->io_attr.vd_entry->isDirectEnable)) { + LOG_DEBUG("tid:0x%llx hno:%u direct disable\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + if (cmd->instance->ioc_adpter->write_direct_enable != NULL && + !cmd->instance->ioc_adpter->write_direct_enable(cmd)) { + LOG_DEBUG("tid:0x%llx hno:%u write direct disable\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + if (unlikely(ps3_scsih_is_valid_vlba(cmd) != PS3_SUCCESS)) { + LOG_ERROR_LIM("hno:%u tid:%#llx lba:0x%llx " + "num_blks:0x%x vd capacity:%llu cmd out of range\n", + PS3_HOST(cmd->instance), cmd->trace_id, + U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo), + cmd->io_attr.num_blocks, cmd->io_attr.vd_entry->capacity); + goto l_out; + } + + if (!direct_cmd_is_raidlevel_support(cmd)) { + goto l_out; + } + + if (!ps3_scsih_is_protocal_rw(cmd->scmd->cmnd)) { + goto l_out; + } + + if ((cmd->io_attr.vd_entry->raidLevel == RAID1)) { + if (cmd->io_attr.vd_entry->mapBlock == 0) { + PS3_BUG(); + goto l_out; + } + if (cmd->instance->is_raid1_direct_skip_mapblock_check) { + LOG_DEBUG("hba raid1, skip MapBlock check\n"); + } else { + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + if (PS3_SCSIH_NOT_SAME_MAPBLOCK(lba, cmd->io_attr.vd_entry->mapBlock, + cmd->io_attr.num_blocks)) { + LOG_DEBUG("hno:%u map_block:%llu lba:0x%llx num_blks:0x%x not same map block\n", + PS3_HOST(cmd->instance), cmd->io_attr.vd_entry->mapBlock, + lba, cmd->io_attr.num_blocks); + goto l_out; + } + } + + } else { + if ((cmd->instance->is_single_disk_raid0_direct_skip_strip_check) && + (cmd->io_attr.vd_entry->raidLevel == RAID0) && + (cmd->io_attr.vd_entry->physDrvCnt == 1)) { + LOG_DEBUG("hba raid0 with single disk, skip strip check\n"); + } else { + if ( !ps3_scsih_is_same_strip(cmd->io_attr.vd_entry, + cmd->io_attr.lba_lo, cmd->io_attr.num_blocks) ) { + LOG_DEBUG("not same strip lba:0x%x num_blks:0x%x\n", + cmd->io_attr.lba_lo, cmd->io_attr.num_blocks); + goto l_out; + } + } + } + + ret = ps3_scsih_vd_rw_io_to_pd_calc(cmd); + if (ret != PS3_SUCCESS) { + LOG_DEBUG("cmd index:%u vlba to plba fail\n", cmd->index); + goto l_out; + } + + if (!direct_cmd_is_supported_device(cmd, cmd->io_attr.pd_entry)) { + LOG_DEBUG("tid:0x%llx hno:%u not support to direct for this cmd\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + if (ps3_scsih_direct_cmd_is_supported_logic(cmd, cmd->io_attr.pd_entry) != PS3_TRUE) { + LOG_DEBUG("tid:0x%llx hno:%u not need to direct for this cmd\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + if (!direct_cmd_is_plba_sector_aligned(cmd, + cmd->io_attr.pd_entry)) { + goto l_out; + } + + if (ps3_is_r1x_write_cmd(cmd)) { + if (!direct_cmd_is_supported_device(cmd, + cmd->io_attr.peer_pd_entry)) { + LOG_DEBUG("tid:0x%llx hno:%u peer_pd[%u:%u:%u] not " + "support to direct for this cmd\n", + cmd->trace_id, + PS3_HOST(cmd->instance), + PS3_CHANNEL(&cmd->io_attr.peer_pd_entry->disk_pos), + PS3_TARGET(&cmd->io_attr.peer_pd_entry->disk_pos), + PS3_PDID(&cmd->io_attr.peer_pd_entry->disk_pos)); + goto l_out; + } + + if (ps3_scsih_direct_cmd_is_supported_logic(cmd, + cmd->io_attr.peer_pd_entry) != PS3_TRUE) { + goto l_out; + } + + if (!direct_cmd_is_plba_sector_aligned(cmd, + cmd->io_attr.peer_pd_entry)) { + goto l_out; + } + } + if (!ps3_scsih_hdd_vd_direct_check(cmd)) { + goto l_out; + } + cmd->io_attr.direct_flag = (U8)PS3_CMDWORD_DIRECT_ADVICE; + } else { + if (!direct_cmd_is_supported_device(cmd, cmd->io_attr.pd_entry)) { + goto l_out; + } + + if (ps3_scsih_direct_cmd_is_supported_logic(cmd, cmd->io_attr.pd_entry) != PS3_TRUE) { + LOG_DEBUG("tid:0x%llx hno:%u not need to direct for this cmd\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + cmd->io_attr.direct_flag = (U8)PS3_CMDWORD_DIRECT_OK; + cmd->io_attr.plba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + } + +l_out: + return ; +} + +static inline Bool ps3_scsih_is_invalid_dev(U8 type) +{ + return (type <= PS3_DEV_TYPE_UNKNOWN || type >= PS3_DEV_TYPE_COUNT); +} + +static inline void ps3_scsih_use_frontend_prp_check(struct ps3_cmd *cmd) +{ + if (!cmd->instance->is_use_frontend_prp) { + goto l_out; + } + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + if (!cmd->io_attr.vd_entry->isNvme) { + goto l_out; + } + } else { + if (cmd->io_attr.pd_entry->dev_type != PS3_DEV_TYPE_NVME_SSD) { + goto l_out; + } + } + + cmd->io_attr.is_use_frontend_prp = ps3_scsih_is_protocal_rw(cmd->scmd->cmnd); + +l_out: + return ; +} + +static Bool ps3_unmap_check_block_valid(struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + U8 umap_xbuf[32] = {0}; + U32 *p_umap_unmblk = &cmd->io_attr.num_blocks; + U16 payload_len = 0; + U16 desc_len = 0; + + if (cmd->scmd->cmnd[0] != UNMAP) { + ret = PS3_TRUE; + goto l_out; + } + + payload_len = ps3_get_unaligned_be16(&cmd->scmd->cmnd[7]); + if (unlikely(payload_len != scsi_bufflen(cmd->scmd))) { + LOG_DEBUG("hno:%u. unmap: buf len:%u != cdb:%u\n", + PS3_HOST(cmd->instance), scsi_bufflen(cmd->scmd), + payload_len); + goto l_out; + } + + if (unlikely(scsi_bufflen(cmd->scmd) > (UNMAP_PARAM_LEN + UNMAP_DESCRIPTOR_LEN))) { + LOG_DEBUG("hno:%u. unmap: buf len:%u > %u\n", + PS3_HOST(cmd->instance), scsi_bufflen(cmd->scmd), + (UNMAP_PARAM_LEN + UNMAP_DESCRIPTOR_LEN)); + goto l_out; + } + + scsi_sg_copy_to_buffer(cmd->scmd, umap_xbuf, scsi_bufflen(cmd->scmd)); + + if (ps3_get_unaligned_be16(&umap_xbuf[0]) != (payload_len - 2)) { + LOG_DEBUG("hno:%u. unmap data len: :%u > payload:%u\n", + PS3_HOST(cmd->instance), ps3_get_unaligned_be16(&umap_xbuf[0]), + payload_len - 2); + goto l_out; + } + + desc_len = ps3_get_unaligned_be16(&umap_xbuf[2]); + if ((desc_len >> 4) > cmd->io_attr.vd_entry->umapBlkDescCnt) { + LOG_DEBUG("hno:%u. unmap: desc len:%u > desc cnt:%u*16\n", + PS3_HOST(cmd->instance), desc_len, + cmd->io_attr.vd_entry->umapBlkDescCnt); + goto l_out; + } + + ps3_scsih_unmap_desc_parse(&umap_xbuf[UNMAP_PARAM_LEN], p_umap_unmblk, + &cmd->io_attr.lba_lo, &cmd->io_attr.lba_hi); + if (*p_umap_unmblk > cmd->io_attr.vd_entry->umapNumblk) { + LOG_DEBUG("hno:%u. unmap: numblk:%u > limit %u\n", + PS3_HOST(cmd->instance), *p_umap_unmblk, + cmd->io_attr.vd_entry->umapNumblk); + goto l_out; + } + + ret = PS3_TRUE; +l_out: + return ret; +} + +static inline void ps3_req_frame_head_init(PS3ReqFrameHead_s *req_head) +{ + req_head->cmdType = 0; + req_head->cmdSubType = 0; + req_head->cmdFrameID = 0; + req_head->control= 0; + req_head->devID.diskID = 0; + req_head->timeout = 0; + req_head->virtDiskSeq = 0; + req_head->reserved1[0] = 0; + req_head->reserved1[1] = 0; + req_head->reserved1[2] = 0; + req_head->reserved1[3] = 0; + req_head->traceID = 0; +} + +static inline U32 ps3_hw_vd_max_io_size_get(U8 enum_size) +{ + U32 max_size = PS3_HW_VD_MAX_IO_SIZE_1M; + + switch (enum_size) { + case PS3_ENUM_HW_VD_MAX_IO_SIZE_1M: + default: + break; + } + return max_size; +} + +static S32 ps3_scsih_cmd_build_prepare(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + S32 dma_map_ret = 0; + Bool is_need_split = PS3_FALSE; + struct ps3_scsi_priv_data *data = scsi_device_private_data(cmd->scmd); + U32 hw_vd_max_num_blk = 0; + U32 hw_vd_max_io_size = 0; + + cmd->io_attr.dev_type = data->dev_type; + if (cmd->is_inserted_c_q == 0) { + dma_map_ret = ps3_scsi_dma_map(cmd); + if (unlikely(dma_map_ret < 0)) { + LOG_WARN_LIM("hno:%u. cfid[%u] dma_map NOK:%d\n", + PS3_HOST(cmd->instance), cmd->index, dma_map_ret); + ret = -PS3_ENOMEM; + goto l_out; + } + } + + if (unlikely(ps3_scsih_is_invalid_dev(cmd->io_attr.dev_type))) { + LOG_ERROR_LIM("hno:%u get dev type NOK :%d dev_type:%s\n", + PS3_HOST(cmd->instance), cmd->index, + namePS3DevType((enum PS3DevType)cmd->io_attr.dev_type)); + ret = -PS3_DEV_TYPE_UNKOWN; + goto l_out; + } + + ps3_req_frame_head_init(&cmd->req_frame->hwReq.reqHead); + + cmd->io_attr.disk_id = data->disk_pos.diskDev.ps3Dev.phyDiskID; +#ifndef _WINDOWS + cmd->io_attr.is_retry_cmd = (cmd->scmd->retries != 0); +#endif + cmd->io_attr.direct_flag = (U8)PS3_CMDWORD_DIRECT_NORMAL; + cmd->io_attr.rw_type = ps3_scsih_cdb_rw_type_get(scsi_cmnd_cdb(cmd->scmd)); + + if (ps3_scsih_is_rw_type(cmd->io_attr.rw_flag)) { + ps3_scsih_cdb_parse(scsi_cmnd_cdb(cmd->scmd), &cmd->io_attr.num_blocks, + &cmd->io_attr.lba_lo, &cmd->io_attr.lba_hi, &is_need_split); + } + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + cmd->io_attr.vd_entry = ps3_dev_mgr_lookup_vd_info_by_id(cmd->instance, + cmd->io_attr.disk_id); + if (unlikely(cmd->io_attr.vd_entry == NULL)) { + ret = -PS3_ENODEV; + goto l_out; + } + + if (unlikely(cmd->io_attr.num_blocks > cmd->io_attr.vd_entry->maxIOSize)) { + LOG_DEBUG("hno:%u. numblk:%u > maxio:%u\n", + PS3_HOST(cmd->instance), cmd->io_attr.num_blocks, + cmd->io_attr.vd_entry->maxIOSize); + cmd->io_attr.is_force_normal = PS3_TRUE; + } + + hw_vd_max_io_size = ps3_hw_vd_max_io_size_get(cmd->instance->ctrl_info.hwVdMaxIOSize); + hw_vd_max_num_blk = hw_vd_max_io_size >> ps3_blocksize_to_shift(cmd->io_attr.vd_entry->sectorSize); + if (unlikely(cmd->io_attr.num_blocks > hw_vd_max_num_blk && + cmd->io_attr.num_blocks > cmd->io_attr.vd_entry->maxIOSize)) { + LOG_DEBUG("hno:%u. numblk:%u > max size, hw max numblk:%u maxIOSize:%u\n", + PS3_HOST(cmd->instance), cmd->io_attr.num_blocks, + hw_vd_max_num_blk, cmd->io_attr.vd_entry->maxIOSize); + goto l_skip_r1x_write_lock; + } + + if (!ps3_unmap_check_block_valid(cmd)) { + cmd->io_attr.is_force_normal = PS3_TRUE; + goto l_skip_r1x_write_lock; + } + + ret = ps3_r1x_write_lock(&data->lock_mgr, cmd); + if(unlikely(ret != PS3_SUCCESS)){ + goto l_out; + } + } else { + cmd->io_attr.pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(cmd->instance, + cmd->io_attr.disk_id); + if (unlikely(cmd->io_attr.pd_entry == NULL)) { + ret = -PS3_ENODEV; + goto l_out; + } + } + +l_skip_r1x_write_lock: + + ps3_scsih_use_frontend_prp_check(cmd); + + ps3_scsih_build_direct_cmd(cmd); + + cmd->cmd_receive_cb = ps3_scsih_io_done; + +l_out: + return ret; +} + +static S32 ps3_scsih_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = -PS3_FAILED; + U32 table_size = ARRAY_SIZE(g_req_frame_func_table); + U32 i = 0; +#ifdef _WINDOWS + ps3_scsi_need_remap_check(cmd); + if (cmd->scmd->is_remap_databuff) { + if (ps3_scsi_remap_sgl(cmd) != PS3_SUCCESS) { + LOG_ERROR("remap sgl error\n"); + return ret; + } + } +#endif + + for (; i < table_size; ++i) { + if (cmd->io_attr.dev_type == g_req_frame_func_table[i].type) { + ret = g_req_frame_func_table[i].func(cmd); + break; + } + } + + return ret; +} + +static void ps3_scsih_vd_cmd_word_devid_build(struct ps3_cmd *cmd, + const struct PS3VDEntry *vd_info) +{ + cmd->cmd_word.virtDiskID = (U8)PS3_VDID(&vd_info->diskPos); + + switch (cmd->io_attr.direct_flag) { + case PS3_CMDWORD_DIRECT_OK: + case PS3_CMDWORD_DIRECT_ADVICE: + cmd->cmd_word.phyDiskID = + PS3_PDID(&cmd->io_attr.pd_entry->disk_pos); + break; + case PS3_CMDWORD_DIRECT_RESERVE: + case PS3_CMDWORD_DIRECT_NORMAL: + default: + cmd->cmd_word.phyDiskID = 0; + break; + } + + return; +} + +static Bool ps3_is_no_calc_mapblocks(const struct PS3VDEntry *vd_info, + const struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + (void)vd_info; + + if (ps3_scsih_is_sync_cache(scsi_cmnd_cdb(cmd->scmd))) { + LOG_DEBUG("hno:%u is SYNCHRONIZE_CACHE\n", + PS3_HOST(cmd->instance)); + ret = PS3_FALSE; + goto l_out; + } + + if (ps3_scsih_is_rw_type(cmd->io_attr.rw_flag) == PS3_FALSE) { + LOG_DEBUG("hno:%u not rw cmd\n", + PS3_HOST(cmd->instance)); + ret = PS3_TRUE; + goto l_out; + } + +l_out: + return ret; +} + +static S32 ps3_scsih_vd_cmd_word_cpu_set(struct ps3_cmd *cmd, + const struct PS3VDEntry *vd_info) +{ + S32 ret = PS3_SUCCESS; + U32 num_blocks = cmd->io_attr.num_blocks; + U32 lba_lo = cmd->io_attr.lba_lo; + U32 lba_hi = cmd->io_attr.lba_hi; + U64 lba = 0; + U8 que_offset = 0; + PS3ReqFrameHead_s *req_head= &cmd->req_frame->frontendReq.reqHead; + + cmd->cmd_word.qMask = 0; + req_head->mapBlockVer = PS3_CMDWORD_VER_INVALID; + + lba = ((U64)lba_hi << PS3_SHIFT_DWORD) | lba_lo; + + LOG_DEBUG("tid:0x%llx hno:%u CFID:%d lba:0x%llx map_block[%lld], num_blks:0x%x\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, lba, + vd_info->mapBlock, num_blocks); + + if (ps3_is_no_calc_mapblocks(vd_info, cmd)) { + LOG_DEBUG("tid:0x%llx hno:%u CFID:%u lba:0x%llx map_block[%lld], num_blks:0x%x\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, lba, + vd_info->mapBlock, num_blocks); + goto l_out; + } + + req_head->mapBlockVer = cmd->io_attr.vd_entry->mapBlockVer; + + if (vd_info->mapBlock == 0) { + PS3_BUG(); + ret = -PS3_FAILED; + goto l_out; + } + + if (vd_info->isSsd && cmd->instance->ioc_adpter->ssd_vd_qmask_calculate != NULL) { + if (cmd->instance->ioc_adpter->ssd_vd_qmask_calculate(cmd)) { + goto l_hba_ssd_vd; + } + } + + que_offset = PS3_CMD_WORD_QUE_CALC(vd_info->diskPos.diskDev.ps3Dev.virtDiskID, lba, + vd_info->mapBlock, (cmd->instance->ctrl_info.vdQueueNum - 1)); + cmd->cmd_word.qMask = 1 << que_offset; + + if ((PS3_SCSIH_NOT_SAME_MAPBLOCK(lba, vd_info->mapBlock, num_blocks)) + && (cmd->instance->ioc_adpter->rw_cmd_is_need_split != NULL) + && (cmd->instance->ioc_adpter->rw_cmd_is_need_split(cmd))) { + + if (que_offset == (cmd->instance->ctrl_info.vdQueueNum - 1)) { + cmd->cmd_word.qMask |= 0x1; + } else { + cmd->cmd_word.qMask |= 1 << (que_offset + 1); + } + req_head->mapBlockVer = PS3_CMDWORD_VER_INVALID; + LOG_DEBUG("hno:%u map_block:%llu not same map block qMask 0x:%x\n", + PS3_HOST(cmd->instance), vd_info->mapBlock, cmd->cmd_word.qMask); + } +l_hba_ssd_vd: + + LOG_DEBUG("tid:0x%llx hno:%u CFID:%d que:%d ver:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, + cmd->cmd_word.qMask, req_head->mapBlockVer); + +l_out: + return ret; + +} + +static S32 ps3_scsih_cmd_word_type_set(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + INJECT_START(PS3_ERR_IJ_IO_RW_FLAG_SET_UNKOWN, cmd); + + switch (cmd->io_attr.rw_flag) { + case PS3_SCSI_CMD_TYPE_READ: + cmd->cmd_word.type = PS3_CMDWORD_TYPE_READ; + break; + case PS3_SCSI_CMD_TYPE_WRITE: + case PS3_SCSI_CMD_TYPE_UNMAP: + case PS3_SCSI_CMD_TYPE_RW: + cmd->cmd_word.type = PS3_CMDWORD_TYPE_WRITE; + break; + case PS3_SCSI_CMD_TYPE_NORW: + cmd->cmd_word.type = PS3_CMDWORD_TYPE_MGR; + break; + default: + cmd->cmd_word.type = PS3_CMDWORD_TYPE_MGR; + ret = -PS3_FAILED; + LOG_ERROR_LIM("hno:%u cmd word set type NOK CFID:%d ret:%d rw_flag:%d\n", + PS3_HOST(cmd->instance), cmd->index, ret, cmd->io_attr.rw_flag); + break; + } + + return ret; +} + +static inline U16 ps3_scsih_is_use_hard_cmd(const struct ps3_cmd *cmd) +{ + return ((cmd->cmd_word.direct == PS3_CMDWORD_DIRECT_OK) || + (cmd->cmd_word.direct == PS3_CMDWORD_DIRECT_ADVICE)) ? + PS3_CMDWORD_FORMAT_HARDWARE : PS3_CMDWORD_FORMAT_FRONTEND; +} + +static S32 ps3_scsih_vd_cmd_word_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + const struct PS3VDEntry *vd_info = cmd->io_attr.vd_entry; + + memset(&cmd->cmd_word, 0, sizeof(cmd->cmd_word)); + ret = ps3_scsih_cmd_word_type_set(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_LIM("tid:0x%llx hno:%u set cmd word fail " + "cmd:%d chl:%u id:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, + PS3_SDEV_CHANNEL(cmd->scmd->device), + PS3_SDEV_TARGET(cmd->scmd->device)); + ret = -PS3_FAILED; + goto l_out; + } + + ret = ps3_scsih_vd_cmd_word_cpu_set(cmd, vd_info); + +#if 0 + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_LIM("tid:0x%llx hno:%u vd cmd word cpu set NOK, " + "cmd:%u chl:%u id:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, + PS3_SDEV_CHANNEL(cmd->scmd->device), + PS3_SDEV_TARGET(cmd->scmd->device)); + ret = -PS3_FAILED; + goto l_out; + } +#endif + + cmd->cmd_word.direct = cmd->io_attr.direct_flag; +#ifndef _WINDOWS + cmd->cmd_word.isrSN = ps3_msix_index_get(cmd, vd_info->dev_busy_scale); +#else + cmd->cmd_word.isrSN = 0; +#endif + + ps3_scsih_vd_cmd_word_devid_build(cmd, vd_info); + cmd->cmd_word.cmdFrameID = cmd->index; + +l_out: + return ret; +} + +static S32 ps3_scsih_pd_cmd_word_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *priv_data = NULL; + + cmd->cmd_word.direct = cmd->io_attr.direct_flag; + ret = ps3_scsih_cmd_word_type_set(cmd); + if (ret != PS3_SUCCESS) { + goto l_out; + } + +#ifndef _WINDOWS + cmd->cmd_word.isrSN = ps3_msix_index_get(cmd, 1); +#else + cmd->cmd_word.isrSN = 0; +#endif + + cmd->cmd_word.cmdFrameID = cmd->index; + priv_data = scsi_device_private_data(cmd->scmd); + cmd->cmd_word.phyDiskID = priv_data->disk_pos.diskDev.ps3Dev.phyDiskID; + cmd->cmd_word.virtDiskID = PS3_INVALID_DEV_ID; + + if ((cmd->cmd_word.type == PS3_CMDWORD_TYPE_READ) + || (cmd->cmd_word.type == PS3_CMDWORD_TYPE_WRITE)){ + cmd->cmd_word.qMask = 0x1; + } + +l_out: + return ret; +} + +static S32 ps3_scsih_cmd_word_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + ret = ps3_scsih_vd_cmd_word_build(cmd); + } else { + ret = ps3_scsih_pd_cmd_word_build(cmd); + } + + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_LIM("tid:0x%llx hno:%u CFID:%d cmd word build NOK!\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index); + } + + return ret; +} + +static inline const char *ps3_scsih_print_rw_type(U8 rw_flag) +{ + static const char *rw_type_table[] = { + [PS3_SCSI_CMD_TYPE_UNKOWN] = "SCMD_T_UNKOWN", + [PS3_SCSI_CMD_TYPE_READ] ="SCMD_T_R", + [PS3_SCSI_CMD_TYPE_WRITE] ="SCMD_T_W", + [PS3_SCSI_CMD_TYPE_RW] ="SCMD_T_RW", + [PS3_SCSI_CMD_TYPE_UNMAP] ="SCMD_T_UNMAP", + [PS3_SCSI_CMD_TYPE_NORW] ="SCMD_T_NORW", + [PS3_SCSI_CMD_TYPE_COUNT] ="SCMD_T_CNT" + }; + + if (rw_flag >= PS3_SCSI_CMD_TYPE_COUNT) { + return rw_type_table[PS3_SCSI_CMD_TYPE_UNKOWN]; + } + + return rw_type_table[rw_flag]; +} + +static void ps3_scsih_print_cdb(const U8 *cdb) +{ + LOG_DEBUG("CDB: %02x %02x %02x %02x %02x %02x %02x %02x" + " %02x %02x %02x %02x %02x %02x %02x %02x" + " %02x %02x %02x %02x %02x %02x %02x %02x" + " %02x %02x %02x %02x %02x %02x %02x %02x\n", + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], + cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], + cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], + cdb[15], cdb[16], cdb[17], cdb[18], cdb[19], + cdb[20], cdb[21], cdb[22], cdb[23], cdb[24], + cdb[25], cdb[26], cdb[27], cdb[28], cdb[29], + cdb[30], cdb[31]); +} + +static inline void ps3_scsih_print_req_head(struct ps3_cmd *cmd, U8 log_level) +{ + if (cmd->req_frame->frontendReq.reqHead.reqFrameFormat == PS3_REQFRAME_FORMAT_FRONTEND){ + PS3ReqFrameHead_s reqHead = cmd->req_frame->frontendReq.reqHead; + LOG_LEVEL(log_level, "tid:0x%llx hno:%u fe head cmd_t:%d" + " stype:%d CFID:%d ctrl:0x%x dev id:0x%x noReplyWord:%d" + "dataFormat:%d reqFrameFormat:%d mapBlockVer:%d isWrite:%d" + "virtDiskSeq:%d\n", + reqHead.traceID, PS3_HOST(cmd->instance), reqHead.cmdType, + reqHead.cmdSubType, reqHead.cmdFrameID, reqHead.control, + reqHead.devID.diskID, reqHead.noReplyWord, reqHead.dataFormat, + reqHead.reqFrameFormat, reqHead.mapBlockVer, reqHead.isWrite, + reqHead.virtDiskSeq); + } else { + PS3ReqFrameHead_s reqHead = cmd->req_frame->hwReq.reqHead; + LOG_LEVEL(log_level, "tid:0x%llx hno:%u fe head cmd_t:%d" + " stype:%d CFID:%d ctrl:0x%x dev id:0x%x noReplyWord:%d" + "dataFormat:%d reqFrameFormat:%d mapBlockVer:%d isWrite:%d" + "virtDiskSeq:%d\n", + reqHead.traceID, PS3_HOST(cmd->instance), reqHead.cmdType, + reqHead.cmdSubType, reqHead.cmdFrameID, reqHead.control, + reqHead.devID.diskID, reqHead.noReplyWord, reqHead.dataFormat, + reqHead.reqFrameFormat, reqHead.mapBlockVer, reqHead.isWrite, + reqHead.virtDiskSeq); + } +} + +static void ps3_scsih_print_hw_req(struct ps3_cmd *cmd, U8 log_level) +{ + IODT_V1_s *req = NULL; + struct ps3_pd_entry * pd_entry = (struct ps3_pd_entry *)cmd->io_attr.pd_entry; + if (pd_entry == NULL) { + return; + } + ps3_scsih_print_req_head(cmd, log_level); + switch (pd_entry->dev_type) { + case PS3_DEV_TYPE_SAS_HDD: + case PS3_DEV_TYPE_SAS_SSD: + req = &cmd->req_frame->hwReq.sasReqFrame; + LOG_LEVEL(log_level, "hno:%u cmdProto:%d cmdType:%d " + "cmdLen:%d dataAddr:0x%llx sgeMode:%d " + "direct:%d function:%d phyDiskID:%d " + "reqFrameID:%d CmdWordType:%d cmdDir:%d " + "dataBufLenDWAlign:0x%x iuSrc:%d sataCtl:%d\n", + PS3_HOST(cmd->instance), req->protocolType, req->frameType, + le32_to_cpu(req->cmdLen), le64_to_cpu(req->dataBaseAddr), + req->dmaCfg.sgMode, req->commonWord.direct, req->commonWord.function, + le16_to_cpu(req->commonWord.phyDiskID), + le16_to_cpu(req->commonWord.reqFrameID), + req->commonWord.type, req->cmdDir, le32_to_cpu(req->dataBufLenDWAlign), + req->iuSrc, req->sasCtl); + ps3_scsih_print_cdb(req->B.cdb); + break; + case PS3_DEV_TYPE_SATA_HDD: + case PS3_DEV_TYPE_SATA_SSD: + req = &cmd->req_frame->hwReq.sasReqFrame; + LOG_LEVEL(log_level, "hno:%u cmdProto:%d cmdType:%d " + "dataAddr:0x%llx sgeMode:%d " + "direct:%d function:%d phyDiskID:%d " + "reqFrameID:%d CmdWordType:%d cmdDir:%d " + "dataBufLenDWAlign:0x%x lba:0x%llx " + "opCode:0x%llx iuSrc:%d sataCtl:%d\n", + PS3_HOST(cmd->instance), req->protocolType, req->frameType, + le64_to_cpu(req->dataBaseAddr), req->dmaCfg.sgMode, + req->commonWord.direct, req->commonWord.function, + le16_to_cpu(req->commonWord.phyDiskID), + le16_to_cpu(req->commonWord.reqFrameID), req->commonWord.type, + req->cmdDir, le32_to_cpu(req->dataBufLenDWAlign), + le64_to_cpu(req->C.lba), (U64)req->C.opCode, req->iuSrc, req->sataCtl); + break; + case PS3_DEV_TYPE_NVME_SSD: + break; + default : + LOG_LEVEL(log_level, "hno:%u dev_type:%d\n", + PS3_HOST(cmd->instance), pd_entry->dev_type); + break; + } +} + +static void ps3_scsih_print_frontend_req(struct ps3_cmd *cmd, U8 log_level) +{ + ps3_scsih_print_req_head(cmd, log_level); + LOG_LEVEL(log_level, "cmd sge_cnt:%d sge_of:%d data_len:%d isStream:%d" + " num_blks:0x%x\n", + cmd->req_frame->frontendReq.sgeCount, + cmd->req_frame->frontendReq.sgeOffset, + cmd->req_frame->frontendReq.dataXferLen, + cmd->req_frame->frontendReq.vdAccAttr.isStream, + cmd->io_attr.num_blocks); + ps3_scsih_print_cdb(cmd->req_frame->frontendReq.cdb); +} + +void ps3_scsih_print_req(struct ps3_cmd *cmd, U8 log_level) +{ + if (cmd->req_frame->frontendReq.reqHead.reqFrameFormat == PS3_REQFRAME_FORMAT_FRONTEND) { + ps3_scsih_print_frontend_req(cmd, log_level); + } else { + ps3_scsih_print_hw_req(cmd, log_level); + } +} + +static void ps3_scsih_print_io_cmd(struct ps3_cmd *cmd) +{ + if(cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + if (cmd->io_attr.pd_entry != NULL) { + LOG_DEBUG("tid:0x%llx hno:%u cmd CFID:%d, dev_t:%s [%d:%d:%d]\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, + namePS3DevType((enum PS3DevType)cmd->io_attr.pd_entry->dev_type), + cmd->io_attr.pd_entry->disk_pos.diskDev.ps3Dev.softChan, + cmd->io_attr.pd_entry->disk_pos.diskDev.ps3Dev.devID, + cmd->io_attr.pd_entry->disk_pos.diskDev.ps3Dev.phyDiskID); + } + } + + LOG_DEBUG("tid:0x%llx hno:%u print CMD: CFID:%u" + " dev_t:%s outstand:%u is_retry_cmd:%d " + "direct_f:%d rw_f:%s CMD_WORD: type:%d direct:%d" + " qmask:0x%x CFID:%d isr_sn:%d vid:%d pid:%d" + " lba:0x%llx opcode:0x%x\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, + namePS3DevType((enum PS3DevType)cmd->io_attr.dev_type), + ps3_atomic_read(&cmd->instance->cmd_statistics.io_outstanding), + cmd->io_attr.is_retry_cmd, cmd->io_attr.direct_flag, + ps3_scsih_print_rw_type(cmd->io_attr.rw_flag), + + cmd->cmd_word.type, cmd->cmd_word.direct, + cmd->cmd_word.qMask, cmd->cmd_word.cmdFrameID, + cmd->cmd_word.isrSN, cmd->cmd_word.virtDiskID, + cmd->cmd_word.phyDiskID, + ((((U64)(cmd->io_attr.lba_hi)) << 32) + (cmd->io_attr.lba_lo)), + cmd->scmd->cmnd[0]); + + ps3_scsih_print_req(cmd, LEVEL_DEBUG); +} + +S32 ps3_scsih_cmd_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + static unsigned long j; + ret = ps3_scsih_cmd_build_prepare(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_DEBUG("tid:0x%llx hno:%u cmd_word build prepare fail CFID:%d ret:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, ret); + ret = ((-PS3_IO_CONFLICT == ret || -PS3_IO_REQUEUE == ret || + -PS3_IO_CONFLICT_IN_Q == ret) ? + ret : SCSI_MLQUEUE_HOST_BUSY); + goto l_out; + } + + ret = ps3_scsih_cmd_word_build(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u cmd_word build NOK CFID:%d ret:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, ret); + ret = SCSI_MLQUEUE_HOST_BUSY; + goto l_out; + } + + ret = ps3_scsih_req_frame_build(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u req_frame NOK CFID:%d ret:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, ret); + ret = SCSI_MLQUEUE_HOST_BUSY; + goto l_out; + } + + ps3_scsih_print_io_cmd(cmd); + PS3_IO_TRACE(cmd, PS3_IO_TRACE_DIRECT_SEND); + + ret = ps3_qos_decision(cmd); +l_out: + return ret; +} + +static inline union PS3DiskDev ps3_scsih_dev_id_get(const struct scsi_cmnd *s_cmd) +{ + struct ps3_scsi_priv_data *data = scsi_device_private_data(s_cmd); + return data->disk_pos.diskDev; +} + +static inline Bool ps3_scsih_is_vd_accelerate(struct ps3_cmd *cmd) +{ + return ps3_scsih_vd_acc_att_build(cmd); +} + +static inline void ps3_sas_cdb_build(struct ps3_cmd *cmd) +{ + U32 blocks = 0; + + memset(cmd->io_attr.cdb, 0, PS3_FRAME_CDB_BUFLEN); + memcpy(cmd->io_attr.cdb, cmd->scmd->cmnd, cmd->scmd->cmd_len); +#ifndef _WINDOWS + blocks = cmd->io_attr.num_blocks << ilog2(cmd->io_attr.vd_entry->sectorSize); +#else + blocks = cmd->io_attr.num_blocks * cmd->io_attr.vd_entry->sectorSize; +#endif + blocks = blocks >> ps3_blocksize_to_shift(cmd->io_attr.pd_entry->sector_size); + + ps3_scsih_cdb_rebuild(cmd->io_attr.cdb, cmd->scmd->cmd_len, blocks, + (U32)cmd->io_attr.plba, (U32)(cmd->io_attr.plba >> PS3_SHIFT_DWORD)); +} +S32 ps3_vd_direct_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + switch(cmd->io_attr.pd_entry->dev_type) { + case PS3_DEV_TYPE_SAS_SSD: + case PS3_DEV_TYPE_SAS_HDD: + ps3_sas_cdb_build(cmd); + ret = ps3_scsih_sas_req_frame_build(cmd); + break; + case PS3_DEV_TYPE_SATA_SSD: + case PS3_DEV_TYPE_SATA_HDD: + ret = ps3_scsih_sata_req_frame_build(cmd); + break; + case PS3_DEV_TYPE_NVME_SSD: + ret = ps3_scsih_nvme_req_frame_build(cmd); + break; + default: + PS3_BUG(); + ret = -PS3_FAILED; + break; + } + return ret; +} + +static inline U32 ps3_scsih_data_direction_build(const struct ps3_cmd *cmd) +{ + U32 ret; + static unsigned long j; + if((cmd->scmd->sc_data_direction == DMA_BIDIRECTIONAL) + || (cmd->scmd->sc_data_direction == DMA_TO_DEVICE)){ + ret = PS3_DATA_DIRECTION_WRITE; + } else if((cmd->scmd->sc_data_direction == DMA_FROM_DEVICE) + || (cmd->scmd->sc_data_direction == DMA_NONE)){ + ret = PS3_DATA_DIRECTION_READ; + } else { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u tid:0x%llx date direction:%d check NOK", + PS3_HOST(cmd->instance),cmd->trace_id, cmd->scmd->sc_data_direction); + ret = PS3_DATA_DIRECTION_WRITE; + } + return ret; +} + +static S32 ps3_scsih_vd_frontend_req_build(struct ps3_cmd *cmd, + PS3FrontEndReqFrame_s *req, U16 sge_count) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_priv_data *p_priv_data = scsi_device_private_data(cmd->scmd); + ps3_scsih_req_frame_head_build(cmd, PS3_REQFRAME_FORMAT_FRONTEND); + + memcpy(req->cdb, cmd->scmd->cmnd, cmd->scmd->cmd_len); + req->dataXferLen = cmd->io_attr.sgl_buf_len; + req->sgeCount = sge_count; + req->sgeOffset = offsetof(PS3FrontEndReqFrame_s, sgl) >> 2; + if(cmd->io_attr.seq_flag == SCSI_RW_UNUSED_CMD && + cmd->instance->ioc_adpter->scsih_stream_is_detect != NULL) { + cmd->instance->ioc_adpter->scsih_stream_is_detect(cmd); + } + req->vdAccAttr.isStream = ((cmd->io_attr.seq_flag == SCSI_RW_SEQ_CMD)?(1):(0)); + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + req->vdAccAttr.ioOutStandingCnt = (U16)ps3_atomic_read(&p_priv_data->rd_io_outstand); + } + if (ps3_scsih_is_vd_accelerate(cmd)) { + LOG_DEBUG("tid:0x%llx hno:%u cmd_type:%d CFID:%d " + "ret:%d vlba->plba:0x%llx\n", + cmd->trace_id, PS3_HOST(cmd->instance), + req->reqHead.cmdType, cmd->index, ret, cmd->io_attr.plba); + } + + return ret; +} + +static inline void ps3_align_16bytes_check(U64 addr) +{ + if (unlikely(addr & PS3_SCSI_ALINNMENT_MASK)) { + LOG_ERROR_LIM("addr:0x%llx not align\n", addr); + } +} + +static inline void ps3_align_4bytes_check(U64 addr) +{ + if (unlikely(addr & PS3_SCSI_ALINNMENT_MASK)) { + LOG_ERROR_LIM("addr:0x%llx not align\n", addr); + } +} + +static inline Bool ps3_is_invalid_ossgl_count(U16 valid_os_sge_count, + U16 max_drv_sge_count) +{ + return (max_drv_sge_count < valid_os_sge_count + 1); +} + +static inline void ps3_last_sge_build(struct PS3Sge *sgl_ptr, + const ps3_scatter_gather_element *os_sgl) +{ + sgl_ptr->length = cpu_to_le32(sg_dma_len(os_sgl)); + sgl_ptr->addr = cpu_to_le64(sg_dma_address_u64(os_sgl)); + sgl_ptr->lastSge = 1; + sgl_ptr->ext = 0; + + return ; +} + +static inline Bool ps3_is_last_sge(S32 sgl_idx, U16 os_sge_count) +{ + return ((sgl_idx + 1) == os_sge_count); +} + +static inline Bool ps3_is_list_sge(S32 sgl_idx, U16 frame_sge_count) +{ + return ((sgl_idx + 1) == frame_sge_count); +} + +static inline void ps3_list_sge_build(struct PS3Sge *sgl_ptr, + const struct ps3_cmd *cmd, U16 ext_sge_size) +{ + sgl_ptr->length = ext_sge_size; + sgl_ptr->addr = cpu_to_le64(cmd->ext_buf_phys); + sgl_ptr->lastSge = 0; + sgl_ptr->ext = 1; + + return; +} + +static U32 ps3_scsih_data_buf_len(struct ps3_cmd *cmd, U32 os_sge_count) +{ + struct scsi_cmnd *scp = cmd->scmd; + ps3_scatter_gather_element *os_sgl = NULL; + U32 index = 0; + + cmd->io_attr.sgl_buf_len = 0; + scsi_for_each_sg(scp, os_sgl, os_sge_count, index) { + cmd->io_attr.sgl_buf_len += sg_dma_len(os_sgl); + mb(); + } + + if (scsi_bufflen(scp) != cmd->io_attr.sgl_buf_len) { + LOG_INFO("data_buf:%u buf_len:%u mismatch\n", + scsi_bufflen(scp), cmd->io_attr.sgl_buf_len); + } + + return cmd->io_attr.sgl_buf_len; +} + +static inline U16 ps3_drv_max_sge_count(const struct ps3_cmd *cmd, + U16 frame_sge_count) +{ + U16 count = 0; + + if (cmd->instance->cmd_context.sgl_mode_support) { + count = ((U16)cmd->instance->cmd_context.ext_sge_frame_count + + frame_sge_count); + } else { + count = PS3_MAX((U16)cmd->instance->cmd_context.ext_sge_frame_count + 1, + frame_sge_count); + } + + return count; +} + +static inline U16 ps3_scsih_frame_ext_sge_pos(const struct ps3_cmd *cmd, + U16 frame_sge_count, U16 os_sge_count) +{ + U16 pos = 0; + + if (cmd->instance->cmd_context.sgl_mode_support) { + pos = frame_sge_count; + } else { + pos = (os_sge_count <= frame_sge_count) ? 0 : 1; + } + + return pos; +} + +static inline U16 ps3_scsih_ext_sge_size_calc(U16 ext_sge_pos, + U16 frame_sge_count, U16 os_sge_count) +{ + U16 cnt = 0; + + if (ext_sge_pos == 0) { + cnt = 0; + } else if (ext_sge_pos == 1) { + cnt = os_sge_count; + } else { + cnt = os_sge_count - frame_sge_count + 1; + } + return cnt * sizeof(struct PS3Sge); +} + +static U16 ps3_scsih_sgl_build(struct ps3_cmd *cmd, struct PS3Sge *sge, + U8 frame_sge_count) +{ + S32 index = 0; + U16 max_drv_sge_count = 0; + U16 os_sge_count = cmd->os_sge_map_count; + struct scsi_cmnd *scp = cmd->scmd; + ps3_scatter_gather_element *os_sgl = NULL; + struct PS3Sge *sge_ptr = sge; + U16 ret_sge_count = 0; + U16 ext_sge_pos = 0; + U16 ext_sge_size = 0; + static unsigned long j; + cmd->io_attr.sgl_buf_len = 0; + max_drv_sge_count = ps3_drv_max_sge_count(cmd, frame_sge_count); + + if (unlikely(ps3_is_invalid_ossgl_count(os_sge_count, + max_drv_sge_count))) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u CFID:%u io is " + "too huge max_drv_sge_count:%d os_sge_count:%u\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, + max_drv_sge_count , os_sge_count); + goto l_out; + } + + memset(&cmd->req_frame->hwReq.sgl, 0, sizeof(cmd->req_frame->hwReq.sgl)); + ext_sge_pos = ps3_scsih_frame_ext_sge_pos(cmd, frame_sge_count, os_sge_count); + ext_sge_size = ps3_scsih_ext_sge_size_calc(ext_sge_pos, frame_sge_count, + os_sge_count); + + ret_sge_count = os_sge_count; + scsi_for_each_sg(scp, os_sgl, os_sge_count, index) { + if (ps3_is_last_sge(index, os_sge_count)) { + ps3_last_sge_build(sge_ptr, os_sgl); + cmd->io_attr.sgl_buf_len += sge_ptr->length; + ps3_align_4bytes_check(sge_ptr->addr); + LOG_DEBUG("sgl addr:0x%llx len:%d\n", sge_ptr->addr, + sge_ptr->length); + break; + } + + if (ps3_is_list_sge(index, ext_sge_pos)) { + ps3_list_sge_build(sge_ptr, cmd, ext_sge_size); + sge_ptr = (struct PS3Sge*)cmd->ext_buf; + ret_sge_count += 1; + } + + sge_ptr->length = cpu_to_le32(sg_dma_len(os_sgl)); + sge_ptr->addr = cpu_to_le64(sg_dma_address_u64(os_sgl)); + sge_ptr->lastSge = 0; + sge_ptr->ext = 0; + cmd->io_attr.sgl_buf_len += sge_ptr->length; + ps3_align_4bytes_check(sge_ptr->addr); + + sge_ptr++; + } +l_out: + return ret_sge_count; +} + +static S32 ps3_vd_normal_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + PS3FrontEndReqFrame_s *req = &cmd->req_frame->frontendReq; + U16 sge_count = 0; + static unsigned long j; + memset(&req->reserved, 0 , sizeof(req->reserved)); + req->vdAccAttr.isAccActive = 0; + req->vdAccAttr.reserved1 = 0; + memset(&req->vdAccAttr.reserved2, 0, sizeof(req->vdAccAttr.reserved2)); + + sge_count = ps3_scsih_frontend_data_buf_build(cmd, req); + if (sge_count == 0 && cmd->os_sge_map_count != 0) { + cmd->io_attr.is_use_frontend_prp = PS3_FALSE; + sge_count = ps3_scsih_frontend_data_buf_build(cmd, req); + if (sge_count == 0 && cmd->os_sge_map_count != 0) { + ret = -PS3_FAILED; + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u tid:0x%llx drv_sge_count:%u " + "os_sge_count:%u\n", PS3_HOST(cmd->instance), + cmd->trace_id, sge_count, cmd->os_sge_map_count); + goto l_out; + } + } + + ret = ps3_scsih_vd_frontend_req_build(cmd, req, sge_count); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u CFID:%d ret:%d frondend build NOK\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, ret); + } + +l_out: + return ret; +} + +static inline S32 ps3_vd_adv_to_normal_req_frame_rebuild(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + static unsigned long j; + cmd->io_attr.direct_flag = PS3_CMDWORD_DIRECT_NORMAL; + cmd->io_attr.is_use_frontend_prp = PS3_FALSE; + memset((void *) &cmd->cmd_word, 0, sizeof(struct PS3CmdWord)); + memset((void *)cmd->req_frame, 0, sizeof(union PS3ReqFrame)); + memset(cmd->ext_buf, 0, cmd->instance->cmd_context.ext_buf_size); + ret = ps3_scsih_vd_cmd_word_build(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u cmd_word build NOK CFID:%d ret:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, ret); + ret = -PS3_FAILED; + goto l_out; + } + ret = ps3_vd_normal_req_frame_build(cmd); + + ps3_scsih_print_io_cmd(cmd); +l_out: + return ret; +} + +static S32 ps3_scsih_vd_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + static unsigned long j; + if ((cmd->io_attr.direct_flag == PS3_CMDWORD_DIRECT_OK) || + (cmd->io_attr.direct_flag == PS3_CMDWORD_DIRECT_ADVICE)) { + ret = ps3_vd_direct_req_frame_build(cmd); + + if ((ret != PS3_SUCCESS) && + (cmd->io_attr.pd_entry->dev_type == PS3_DEV_TYPE_NVME_SSD) ) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u advice direct NVMe vd NOK, to normal" + "is_use_frontend_prp:%d\n", cmd->trace_id, + PS3_HOST(cmd->instance), cmd->io_attr.is_use_frontend_prp); + ret = ps3_vd_adv_to_normal_req_frame_rebuild(cmd); + } + } else { + ret = ps3_vd_normal_req_frame_build(cmd); + } + return ret; +} + +static S32 ps3_software_zone_build(struct ps3_cmd *cmd, + U64 virtDiskLba, U8 type, U16 sge_count) +{ + PS3SoftwareZone_s *zone = NULL; + U32 num_blocks = cmd->io_attr.num_blocks; + S32 ret = PS3_SUCCESS; + static unsigned long j; + INJECT_START(PS3_ERR_IJ_SOFT_ZONE_TYPE_SET_UNKOWN, &type); + if(unlikely((type < PS3_DEV_TYPE_SAS_HDD) || + (type >= PS3_DEV_TYPE_COUNT))) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u type:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), type); + ret = -PS3_FAILED; + goto l_ret; + } + + zone = &cmd->req_frame->hwReq.softwareZone; + ps3_scsih_cdb_opcode_get(cmd->scmd->cmnd, &zone->opcode, &zone->subOpcode); + + zone->virtDiskLba = cpu_to_le64(virtDiskLba); + zone->numBlocks = cpu_to_le32(num_blocks); + zone->sgeCount = sge_count; + + if( type == PS3_DEV_TYPE_NVME_SSD) { + zone->sglOffset = offsetof(struct PS3NvmeCmdDw0_9, dPtr) >> 2; + zone->sglFormat = 1; + } else { + zone->sglOffset = offsetof(struct PS3HwReqFrame, sgl) >> 2; + zone->sglFormat = 0; + } + zone->isResendCmd = 0; + +l_ret: + return ret; +} + +static Bool ps3_prp_build_check(struct ps3_cmd *cmd, U32 data_len) +{ + struct scsi_cmnd *scmd = cmd->scmd; + Bool prp_convert_support = PS3_TRUE; + S32 index = 0; + U16 total_sge_count = cmd->os_sge_map_count; + U32 nvme_page_size = cmd->instance->cmd_attr.nvme_page_size; + ps3_scatter_gather_element *sge_ptr = scsi_sglist(scmd); + U64 sge_addr = 0; + U32 first_prp_len = 0; + U32 nvme_page_size_mask = nvme_page_size - 1; + static unsigned long j; + (void)data_len; + LOG_DEBUG("hno:%u CFID:%u sge_count:%u\n", + PS3_HOST(cmd->instance), cmd->index, total_sge_count); + + scsi_for_each_sg(scmd, sge_ptr, total_sge_count, index) { + sge_addr = sg_dma_address(sge_ptr); +#if 0 + LOG_DEBUG("hno:%u CFID:%u index:%u sge_addr:0x%llx len:%u\n", + PS3_HOST(cmd->instance), cmd->index, index, sge_addr, + sg_dma_len(sge_ptr)); +#endif + if (index == 0) { + first_prp_len = nvme_page_size - (sge_addr & nvme_page_size_mask); + if (first_prp_len >= sg_dma_len(sge_ptr)) { + prp_convert_support = PS3_TRUE; + break; + } + + if (total_sge_count <= 1) { + prp_convert_support = PS3_TRUE; + break; + } else if (ps3_utility_mod64(sge_addr + sg_dma_len(sge_ptr), + nvme_page_size)) { + prp_convert_support = PS3_FALSE; + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u CFID:%u index:%u " + "sge_addr:0x%llx len:%u\n", + PS3_HOST(cmd->instance), cmd->index, + index, sge_addr, sg_dma_len(sge_ptr)); + break; + } + } else { + if ((total_sge_count > 1) && (index == (total_sge_count - 1))) { + if (ps3_utility_mod64(sge_addr, nvme_page_size)) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u CFID:%u index:%u " + "sge_addr:0x%llx len:%u\n", + PS3_HOST(cmd->instance), cmd->index, + index, sge_addr, sg_dma_len(sge_ptr)); + prp_convert_support = PS3_FALSE; + break; + } + } + + if ((total_sge_count > 1) && (index != (total_sge_count - 1))) { + if (ps3_utility_mod64(sg_dma_len(sge_ptr), nvme_page_size) || + ps3_utility_mod64(sge_addr, nvme_page_size)) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "middle hno:%u CFID:%u index:%u " + "sge_addr:0x%llx len:%u\n", + PS3_HOST(cmd->instance), cmd->index, + index, sge_addr, sg_dma_len(sge_ptr)); + prp_convert_support = PS3_FALSE; + break; + } + } + } + } + + return prp_convert_support; +} + +static U16 ps3_scsih_prp_build(struct ps3_cmd *cmd, U64 *prp_ptr, + U8 frame_prp_count, U32 data_len, Bool is_need_clean_sgl) +{ + struct scsi_cmnd *scp = cmd->scmd; + ps3_scatter_gather_element *sge_scmd = scsi_sglist(scp); + U32 page_size = cmd->instance->cmd_attr.nvme_page_size; + U32 nvme_page_size_mask = page_size - 1; + U32 sge_len = sg_dma_len(sge_scmd); + U64 sge_addr = sg_dma_address_u64(sge_scmd); + U32 first_prp_len = 0; + U16 prp_entry_count = 0; + static unsigned long j; + if (is_need_clean_sgl) { + memset(&cmd->req_frame->hwReq.sgl, 0, sizeof(cmd->req_frame->hwReq.sgl)); + } + *prp_ptr = sge_addr; + prp_entry_count++; + first_prp_len = page_size - (sge_addr & nvme_page_size_mask); + + LOG_DEBUG("hno:%u CFID:%u sge0_addr:0x%llx data_len:%u sge_len:%u" + "first_max_prp_len:%u\n", PS3_HOST(cmd->instance), + cmd->index, sge_addr, data_len, sge_len, first_prp_len); + + data_len = (data_len > first_prp_len)? (data_len - first_prp_len) : 0; + if (data_len <= 0) { + goto l_out; + } + + if (sge_len > first_prp_len) { + sge_addr += first_prp_len; + sge_len = (sge_len > first_prp_len) ? (sge_len - first_prp_len) : 0 ; + } else { + sge_scmd = sg_next(sge_scmd); + sge_len = sg_dma_len(sge_scmd); + sge_addr = sg_dma_address_u64(sge_scmd); + } + + prp_ptr++; + frame_prp_count--; + + for (;;) { + if (prp_entry_count > cmd->instance->cmd_context.max_prp_count) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u CFID:%u prp_entry_count:%u " + "max_prp_count:%u\n", cmd->trace_id, PS3_HOST(cmd->instance), + cmd->index, prp_entry_count, cmd->instance->cmd_context.max_prp_count); + prp_entry_count = 0; + goto l_out; + } + + if (frame_prp_count == 1) { + if (data_len > page_size) { + *prp_ptr = cmd->ext_buf_phys; + prp_ptr = (U64*)cmd->ext_buf; + prp_entry_count++; + } + frame_prp_count--; + } + + *prp_ptr = sge_addr; + prp_entry_count++; + + sge_len = (sge_len > page_size) ? (sge_len - page_size) : 0; + data_len = (data_len > page_size) ? (data_len - page_size) : 0; + if (frame_prp_count > 0) { + frame_prp_count--; + } + + if (data_len <= 0) { + LOG_DEBUG("end hno:%u CFID:%u data_len:%u prp_entry:0x%llx " + "sge_addr:0x%llx sge_len:%u prp_entry_count:%u\n", + PS3_HOST(cmd->instance), cmd->index, data_len, *prp_ptr, + sge_addr, sge_len, prp_entry_count); + break; + } + + if (unlikely(cmd->instance->is_print_special_log)) { + LOG_DEBUG("end hno:%u CFID:%u data_len:%u prp_entry:0x%llx " + "sge_addr:0x%llx sge_len:%u\n", PS3_HOST(cmd->instance), + cmd->index, data_len, *prp_ptr, sge_addr, sge_len); + } + + prp_ptr++; + + if (sge_len > 0) { + sge_addr += page_size; + continue; + } + sge_scmd = sg_next(sge_scmd); + sge_addr = sg_dma_address_u64(sge_scmd); + sge_len = sg_dma_len(sge_scmd); + } + +l_out: + return prp_entry_count; +} + +static void ps3_scsih_frontend_prp_build(struct ps3_cmd *cmd, U64 *prp_ptr, + U32 data_len, U16 prp_count) +{ + struct scsi_cmnd *scp = cmd->scmd; + ps3_scatter_gather_element *sge_scmd = scsi_sglist(scp); + struct PS3Sge *sge_ptr = (struct PS3Sge *)prp_ptr; + U32 page_size = cmd->instance->cmd_attr.nvme_page_size; + U32 nvme_page_size_mask = page_size - 1; + U32 first_prp_len = 0; + U32 sge_len = sg_dma_len(sge_scmd); + U64 sge_addr = sg_dma_address_u64(sge_scmd); + + first_prp_len = page_size - (sg_dma_address_u64(sge_scmd) & nvme_page_size_mask); + data_len = (data_len > first_prp_len)? (data_len - first_prp_len) : 0; + + sge_ptr->length = first_prp_len; + sge_ptr->addr = sge_addr; + sge_ptr->lastSge = 0; + sge_ptr->ext = 0; + ps3_align_16bytes_check(sge_ptr->addr); + + LOG_DEBUG("hno:%u CFID:%u sge0_addr:0x%llx sge_len:%u\n", + PS3_HOST(cmd->instance), cmd->index, sge_ptr->addr, sge_ptr->length); + + if(data_len <= 0){ + goto l_out; + } + + if (sge_len > first_prp_len) { + sge_addr += first_prp_len; + sge_len = (sge_len > first_prp_len) ? (sge_len - first_prp_len) : 0 ; + } else { + sge_scmd = sg_next(sge_scmd); + sge_len = sg_dma_len(sge_scmd); + sge_addr = sg_dma_address_u64(sge_scmd); + } + + sge_ptr++; + + if (data_len <= page_size) { + sge_ptr->length = data_len; + sge_ptr->addr = sge_addr; + sge_ptr->lastSge = 1; + sge_ptr->ext = 0; + ps3_align_16bytes_check(sge_ptr->addr); + goto l_out; + } else { + sge_ptr->length = (prp_count - PS3_FRAME_REQ_PRP_NUM_FE) * sizeof(U64); + sge_ptr->addr = cmd->ext_buf_phys; + sge_ptr->lastSge = 0; + sge_ptr->ext = 1; + sge_ptr = (struct PS3Sge *)prp_ptr; + sge_ptr = sge_ptr + PS3_FRAME_REQ_SGE_NUM_FE - 1; + sge_ptr->length = (prp_count - PS3_FRAME_REQ_PRP_NUM_FE) * sizeof(U64); + sge_ptr->addr = cmd->ext_buf_phys; + sge_ptr->lastSge = 0; + sge_ptr->ext = 1; + } + LOG_DEBUG("hno:%u CFID:%u sge1_addr:0x%llx sge_len:%u sge_ext:%d\n", + PS3_HOST(cmd->instance), cmd->index, sge_ptr->addr, sge_ptr->length, sge_ptr->ext); +l_out: + return ; +} + +static inline S32 ps3_scsih_prp_len_check(struct ps3_cmd *cmd, U32 data_len) +{ + S32 ret = PS3_SUCCESS; + U32 max_prp_count = cmd->instance->cmd_context.max_prp_count; + U64 max_nvme_data_size = (U64)(max_prp_count - (U32)PS3_FRAME_REQ_PRP_NUM_FE - 1) * + cmd->instance->cmd_attr.nvme_page_size; + static unsigned long j; + if (unlikely(max_nvme_data_size < data_len)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u io is too huge " + "[max_nvme_data_size:%llu][data_len:%d]\n", + cmd->trace_id, PS3_HOST(cmd->instance), + max_nvme_data_size , data_len); + ret = -PS3_FAILED; + } + + return ret; +} +#if 0 +static U16 ps3_scsih_nvme_normal_cmd_split(struct ps3_cmd *cmd, + PS3FrontEndReqFrame_s *req, U32 data_len) +{ + U16 prp_count = 0; + + (void)cmd; + (void)req; + (void)data_len; + + return prp_count; +} +#endif +static U16 ps3_scsih_frontend_data_buf_build(struct ps3_cmd *cmd, + PS3FrontEndReqFrame_s *req) +{ + U16 sge_count = 0; + U32 data_len = 0; + static unsigned long j; + if (cmd->io_attr.is_use_frontend_prp) { + if (cmd->os_sge_map_count == 0) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u CFID:%u os_sge_map_count==0\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index); + sge_count = 0; + goto l_out; + } + data_len = ps3_scsih_data_buf_len(cmd, cmd->os_sge_map_count); + if (ps3_scsih_prp_len_check(cmd, data_len) != PS3_SUCCESS) { + sge_count = 0; + goto l_out; + } + + if (ps3_prp_build_check(cmd, data_len)) { + sge_count = ps3_scsih_prp_build(cmd, &req->prp.prp1, + PS3_FRAME_REQ_PRP_NUM_FE, data_len, PS3_TRUE); + + ps3_scsih_frontend_prp_build(cmd, &req->prp.prp1, + data_len, sge_count); + } else { +#if 0 + LOG_WARN("tid:0x%llx hno:%u CFID:%u need split cmd\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index); + + sge_count = ps3_scsih_nvme_normal_cmd_split(cmd, req, data_len); +#else + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u CFID:%u nvme prp change to sgl\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index); + sge_count = 0; +#endif + } + } else { + sge_count = ps3_scsih_sgl_build(cmd, req->sgl, PS3_FRAME_REQ_SGE_NUM_FE); + } + +l_out: + return sge_count; +} + +static S32 ps3_scsih_pd_frontend_req_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + PS3FrontEndReqFrame_s *req = &cmd->req_frame->frontendReq; + static unsigned long j; + ps3_scsih_req_frame_head_build(cmd, PS3_REQFRAME_FORMAT_FRONTEND); + + memset(&req->reserved, 0, sizeof(req->reserved)); + req->vdAccAttr.isAccActive = 0; + req->vdAccAttr.reserved1 = 0; + memset(&req->vdAccAttr.reserved2, 0, sizeof(req->vdAccAttr.reserved2)); + + req->sgeCount = ps3_scsih_frontend_data_buf_build(cmd, req); + if (req->sgeCount == 0 && cmd->os_sge_map_count != 0) { + cmd->io_attr.is_use_frontend_prp = PS3_FALSE; + cmd->req_frame->hwReq.reqHead.dataFormat = PS3_SGL; + req->sgeCount = ps3_scsih_frontend_data_buf_build(cmd, req); + if (req->sgeCount == 0 && cmd->os_sge_map_count != 0) { + ret = -PS3_FAILED; + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u tid:0x%llx drv_sge_count:%u " + "os_sge_count:%u\n", PS3_HOST(cmd->instance), + cmd->trace_id, req->sgeCount, cmd->os_sge_map_count); + goto l_out; + } + } + + memcpy(req->cdb, cmd->scmd->cmnd, cmd->scmd->cmd_len); + + req->sgeOffset = offsetof(PS3FrontEndReqFrame_s, sgl) >> 2; + req->dataXferLen = cmd->io_attr.sgl_buf_len; + +l_out: + return ret; +} + +static U16 ps3_scsi_cmd_timeout_get(struct ps3_cmd *cmd) +{ + U32 time_s = SCMD_GET_REQUEST(cmd->scmd)->timeout / HZ; + U16 timeout = 0; + if (time_s > 0xfffe) { + timeout = 0; + return timeout; + } + timeout = time_s; + return timeout; +} + +static void ps3_scsih_req_frame_head_build(struct ps3_cmd *cmd, U8 req_frame_format) +{ + PS3ReqFrameHead_s *req_head= &cmd->req_frame->hwReq.reqHead; + static unsigned long j; + req_head->reqFrameFormat = req_frame_format; + req_head->cmdSubType = 0; + req_head->cmdFrameID = cmd->index; + req_head->noReplyWord = PS3_CMD_WORD_NEED_REPLY_WORD; + req_head->dataFormat = cmd->io_attr.is_use_frontend_prp || req_frame_format == PS3_REQFRAME_FORMAT_NVME ? \ + PS3_PRP : PS3_SGL; + req_head->isWrite = ps3_scsih_data_direction_build(cmd); + req_head->timeout = ps3_scsi_cmd_timeout_get(cmd); + req_head->traceID = cmd->trace_id; + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + req_head->devID = cmd->io_attr.vd_entry->diskPos.diskDev; + if (unlikely(req_head->devID.diskID == 0)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u chl:%u id:%u dev id:0x%x NOK\n", + cmd->trace_id, PS3_HOST(cmd->instance), PS3_SDEV_CHANNEL(cmd->scmd->device), + PS3_SDEV_TARGET(cmd->scmd->device), req_head->devID.diskID); + } + + req_head->cmdType = ps3_scsih_is_rw_type(cmd->io_attr.rw_flag) ? + PS3_CMD_VD_SCSI_IO_RW : PS3_CMD_VD_SCSI_IO_NORW; + req_head->virtDiskSeq = cmd->io_attr.vd_entry->virtDiskSeq; + + }else { + req_head->devID.diskID = PS3_DISKID(&cmd->io_attr.pd_entry->disk_pos); + req_head->mapBlockVer = PS3_CMDWORD_VER_INVALID; + req_head->cmdType = ps3_scsih_is_rw_type(cmd->io_attr.rw_flag) ? + PS3_CMD_PD_SCSI_IO_RW : PS3_CMD_PD_SCSI_IO_NORW; + } + return; +} + +static inline U64 ps3_scsih_direct_sgl_base_addr(const struct ps3_cmd *cmd, + U16 sge_count) +{ + U64 data_base = 0; + + if (sge_count == PS3_SGL_MODE_SGE_COUNT_DIRECT) { + data_base = cmd->req_frame->hwReq.sgl[0].addr; + } else if ((sge_count > PS3_FRAME_REQ_SGE_NUM_HW) && + (!cmd->instance->cmd_context.sgl_mode_support)) { + data_base = cmd->ext_buf_phys; + ps3_align_16bytes_check(data_base); + } else { + data_base = cmd->req_frame_phys + offsetof(PS3HwReqFrame_s, sgl); + ps3_align_16bytes_check(data_base); + } + + return data_base; +} + +static inline void ps3_scsih_sata_iodt_data_build(struct ps3_cmd *cmd, + U32 sge_count, U64 data_addr) +{ + IODT_V1_s *iodt = &cmd->req_frame->hwReq.sasReqFrame; + struct ps3_scsi_io_attr *cmd_io_attr = &cmd->io_attr; + U16 sector_size = cmd_io_attr->pd_entry->sector_size; +#ifndef _WINDOWS + U32 data_buf_len = cmd_io_attr->num_blocks << ilog2(sector_size); +#else + U32 data_buf_len = cmd_io_attr->num_blocks * sector_size; +#endif + switch(sge_count) { + case PS3_SGL_MODE_SGE_COUNT_NO_DATA: + iodt->dataBufLenDWAlign = 0; + iodt->dataBaseAddr = 0; + iodt->dmaCfg.sgMode = IODT_SGEMODE_DIRECT; + break; + case PS3_SGL_MODE_SGE_COUNT_DIRECT: + iodt->dataBaseAddr = cpu_to_le64(data_addr); + iodt->dataBufLenDWAlign = cpu_to_le32(ENCODE_CCS_XFERLEN(data_buf_len)); + iodt->dmaCfg.sgMode = IODT_SGEMODE_DIRECT; + break; + default: + iodt->dataBaseAddr = cpu_to_le64(data_addr); + iodt->dataBufLenDWAlign = cpu_to_le32(ENCODE_CCS_XFERLEN(data_buf_len)); + iodt->dmaCfg.sgMode = IODT_SGEMODE_SGL; + break; + } + return; +} + +static S32 ps3_scsih_sata_hw_req_frame_build(struct ps3_cmd *cmd, U16 sge_count, U64 data_addr) +{ + S32 ret = PS3_SUCCESS; + struct ps3_scsi_io_attr *cmd_io_attr = &cmd->io_attr; + IODT_V1_s *iodt = &cmd->req_frame->hwReq.sasReqFrame; + PS3ReqFrameHead_s *req_head = &cmd->req_frame->hwReq.reqHead; + U8 req_frame_format = PS3_REQFRAME_FORMAT_SATA; + + memset(iodt, 0, sizeof(IODT_V1_s)); + + ps3_scsih_req_frame_head_build(cmd, req_frame_format); + + iodt->protocolType = PROTOCOL_DIRT; + iodt->frameType = FRAMETYPE_DIRECT; + iodt->iuSrc = IU_SRC_TUPLE; + + if (cmd->cmd_word.type == PS3_CMDWORD_TYPE_READ) { + iodt->commonWord.type = PS3_CMDWORD_TYPE_READ; + iodt->C.opCode = PS3_ATA_OPC_READ_FPDMA; + } else { + iodt->commonWord.type = PS3_CMDWORD_TYPE_WRITE; + iodt->C.opCode = PS3_ATA_OPC_WRITE_FPDMA; + } + + iodt->cmdDir = ps3_scsih_data_direction_build(cmd); + iodt->sataCtl = 0; + iodt->sasCtl = 1; + iodt->commonWord.direct = DIRECT_FLAG_DIRECT; + iodt->commonWord.reqFrameID = req_head->cmdFrameID; + iodt->commonWord.function = ps3_get_pci_function(cmd->instance->pdev); + iodt->commonWord.phyDiskID = cmd->cmd_word.phyDiskID; + + iodt->C.lba = cmd_io_attr->plba; + + ps3_scsih_sata_iodt_data_build(cmd, sge_count, data_addr); + + return ret; +} + +static S32 ps3_scsih_sata_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U64 lba = 0; + U64 data_addr = 0; + U16 sge_count = 0; + + if (ps3_is_need_build_hw_req_frame(cmd)) { + sge_count = ps3_scsih_sgl_build(cmd, cmd->req_frame->hwReq.sgl, + PS3_FRAME_REQ_SGE_NUM_HW); + data_addr = ps3_scsih_direct_sgl_base_addr(cmd, sge_count); + ret = ps3_scsih_sata_hw_req_frame_build(cmd, sge_count, data_addr); + if (likely(ret == PS3_SUCCESS)) { + cmd->req_frame->hwReq.reqHead.traceID = cmd->trace_id; + lba = PS3_LBA(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + ret = ps3_software_zone_build(cmd, lba, + cmd->io_attr.pd_entry->dev_type, sge_count); + } + } else { + ret = ps3_scsih_pd_frontend_req_build(cmd); + } + + return ret; +} + +static inline void ps3_scsih_sas_iodt_data_build(struct ps3_cmd *cmd, + U64 data_addr, U32 sge_count) +{ + IODT_V1_s *iodt = &cmd->req_frame->hwReq.sasReqFrame; + switch(sge_count) { + case PS3_SGL_MODE_SGE_COUNT_NO_DATA: + iodt->dataBufLenDWAlign = 0; + iodt->dataBaseAddr = 0; + iodt->dmaCfg.sgMode = IODT_SGEMODE_DIRECT; + break; + + case PS3_SGL_MODE_SGE_COUNT_DIRECT: + iodt->dataBufLenDWAlign = cpu_to_le32(ENCODE_CCS_XFERLEN(cmd->io_attr.sgl_buf_len)); + iodt->dataBaseAddr = cpu_to_le64(data_addr); + iodt->dmaCfg.sgMode = IODT_SGEMODE_DIRECT; + break; + + default: + iodt->dataBufLenDWAlign = cpu_to_le32(ENCODE_CCS_XFERLEN(cmd->io_attr.sgl_buf_len)); + iodt->dataBaseAddr = cpu_to_le64(data_addr); + iodt->dmaCfg.sgMode = IODT_SGEMODE_SGL; + break; + } + return; +} + +static S32 ps3_scsih_sas_hw_req_frame_build(struct ps3_cmd *cmd, U16 disk_id, + U64 data_addr, U32 sge_count) +{ + IODT_V1_s *iodt = &cmd->req_frame->hwReq.sasReqFrame; + U8 *cdb = cmd->scmd->cmnd; + S32 ret = PS3_SUCCESS; + PS3ReqFrameHead_s *req_head = &cmd->req_frame->hwReq.reqHead; + U8 req_frame_format = PS3_REQFRAME_FORMAT_SAS; + + if(cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + cdb = cmd->io_attr.cdb; + } + memset(iodt, 0, sizeof(IODT_V1_s)); + + ps3_scsih_req_frame_head_build(cmd, req_frame_format); + + iodt->protocolType = PROTOCOL_DIRT; + iodt->frameType = FRAMETYPE_DIRECT; + iodt->iuSrc = IU_SRC_IODT; + + if(cmd->scmd->cmd_len != CMD_LEN_THR) { + iodt->cmdLen = CMD_LEN_S; + } else { + iodt->cmdLen = CMD_LEN_L; + } + + memcpy(iodt->B.cdb, cdb, CMD_LEN_THR); + + iodt->cmdDir = ps3_scsih_data_direction_build(cmd); + + iodt->sasCtl = 0; + + if(cmd->cmd_word.type == PS3_CMDWORD_TYPE_READ) { + iodt->commonWord.type = PS3_CMDWORD_TYPE_READ; + } else { + iodt->commonWord.type = PS3_CMDWORD_TYPE_WRITE; + } + + iodt->commonWord.direct = DIRECT_FLAG_DIRECT; + iodt->commonWord.function = ps3_get_pci_function(cmd->instance->pdev); + iodt->commonWord.phyDiskID = disk_id; + iodt->commonWord.reqFrameID = req_head->cmdFrameID; + ps3_scsih_sas_iodt_data_build(cmd, data_addr, sge_count); + + return ret; +} + +static S32 ps3_scsih_sas_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U16 sge_count = 0; + U64 data_addr = 0; + U64 lba = 0; + + if (ps3_is_need_build_hw_req_frame(cmd)) { + sge_count = ps3_scsih_sgl_build(cmd, + cmd->req_frame->hwReq.sgl, PS3_FRAME_REQ_SGE_NUM_HW); + data_addr = ps3_scsih_direct_sgl_base_addr(cmd, sge_count); + ret = ps3_scsih_sas_hw_req_frame_build(cmd, + PS3_PDID(&cmd->io_attr.pd_entry->disk_pos), + data_addr, sge_count); + if (likely(ret == PS3_SUCCESS)) { + lba = (U64)cmd->io_attr.lba_hi << PS3_SHIFT_DWORD | cmd->io_attr.lba_lo; + ret = ps3_software_zone_build(cmd, lba, + cmd->io_attr.pd_entry->dev_type, sge_count); + } + } else { + ret = ps3_scsih_pd_frontend_req_build(cmd); + } + return ret; +} + +static void ps3_hw_nvme_req_frame_build(struct ps3_cmd *cmd, + PS3HwReqFrame_s *hw_reqframe) +{ + PS3NvmeRWCmd_s *rwReqFrame = &hw_reqframe->nvmeReqFrame.rwReqFrame; + rwReqFrame->numLba = cpu_to_le32(cmd->io_attr.num_blocks - 1); + rwReqFrame->numLba |= (U32)((U32)cmd->io_attr.cdb_opts.fua << 30); + + rwReqFrame->sLbaHi = cpu_to_le32((U32)(cmd->io_attr.plba >> PS3_SHIFT_DWORD)); + rwReqFrame->sLbaLo = cpu_to_le32((U32)(cmd->io_attr.plba)); + + rwReqFrame->cDW0_9.cID = cpu_to_le16(cmd->index); + rwReqFrame->cDW0_9.psdt = 0; + rwReqFrame->cDW0_9.nsID = 1; + if (cmd->io_attr.rw_flag == PS3_SCSI_CMD_TYPE_READ) { + rwReqFrame->cDW0_9.opcode = 0x02; + } else if(cmd->io_attr.rw_flag == PS3_SCSI_CMD_TYPE_WRITE) { + rwReqFrame->cDW0_9.opcode = 0x01; + } else { + } + + LOG_DEBUG("hno:%u cid:%d, op:%d, nsid:%d, prp1:0x%llx, " + "prp2:0x%llx, numLb:%d, LbaHi:0x%x, LbaLo:0x%x, dw13:0x%x, " + "dw13:0x%x, dw13:0x%x\n", + PS3_HOST(cmd->instance), rwReqFrame->cDW0_9.cID, + rwReqFrame->cDW0_9.opcode, rwReqFrame->cDW0_9.nsID, + rwReqFrame->cDW0_9.dPtr.prp.prp1, + rwReqFrame->cDW0_9.dPtr.prp.prp2, + rwReqFrame->numLba, rwReqFrame->sLbaHi, rwReqFrame->sLbaLo, + rwReqFrame->cDW13, rwReqFrame->cDW14, rwReqFrame->cDW15); + + return ; +} + +static void ps3_hw_nvme_ext_fill(struct ps3_cmd *cmd, U16 prp_count) +{ + if (prp_count > PS3_FRAME_REQ_PRP_NUM_HW) { + cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].length = + (prp_count - PS3_FRAME_REQ_PRP_NUM_HW) * sizeof(U64); + cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].addr = + cmd->ext_buf_phys; + cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].lastSge = 0; + cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].ext = 1; + } else { + if (cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].ext != 0) { + cmd->req_frame->hwReq.sgl[PS3_FRAME_REQ_SGE_NUM_HW - 1].ext = 0; + } + } +} + +static S32 ps3_scsih_nvme_hw_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + U64 * prp_ptr = NULL; + PS3HwReqFrame_s *hw_reqframe = NULL; + U8 pd_dev_type = PS3_DEV_TYPE_COUNT; + U64 lba = 0; + U16 prp_count = 0; + U32 data_len = ps3_scsih_data_buf_len(cmd, cmd->os_sge_map_count); + static unsigned long j; + hw_reqframe = &cmd->req_frame->hwReq; + memset(&hw_reqframe->nvmeReqFrame, 0, sizeof(PS3NvmeReqFrame_u)); + prp_ptr = &hw_reqframe->nvmeReqFrame.rwReqFrame.cDW0_9.dPtr.prp.prp1; + + ps3_scsih_req_frame_head_build(cmd, PS3_REQFRAME_FORMAT_NVME); + if (cmd->io_attr.pd_entry != NULL) { + pd_dev_type = cmd->io_attr.pd_entry->dev_type; + } + + if (ps3_prp_build_check(cmd, data_len)) { + prp_count = ps3_scsih_prp_build(cmd, prp_ptr, PS3_FRAME_REQ_PRP_NUM_HW, data_len, PS3_FALSE); + ps3_hw_nvme_ext_fill(cmd, prp_count); + ps3_hw_nvme_req_frame_build(cmd, hw_reqframe); + cmd->req_frame->hwReq.reqHead.traceID = cmd->trace_id; + lba = (U64)cmd->io_attr.lba_hi << PS3_SHIFT_DWORD | cmd->io_attr.lba_lo; + ret = ps3_software_zone_build(cmd, lba, pd_dev_type, prp_count); + } else { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u this io don't support prp!\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + ret = -PS3_FAILED; + } + return ret; +} + +static S32 ps3_scsih_nvme_req_frame_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + static unsigned long j; + if (ps3_is_need_build_hw_req_frame(cmd)) { + ret = ps3_scsih_nvme_hw_req_frame_build(cmd); + if (ret != PS3_SUCCESS) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u direct NVMe NOK, to normal" + "is_use_frontend_prp:%d\n", cmd->trace_id, + PS3_HOST(cmd->instance), cmd->io_attr.is_use_frontend_prp); + cmd->io_attr.direct_flag = PS3_CMDWORD_DIRECT_NORMAL; + cmd->io_attr.is_use_frontend_prp = PS3_FALSE; + memset((void *) &cmd->cmd_word, 0, sizeof(struct PS3CmdWord)); + memset((void *)cmd->req_frame, 0, sizeof(union PS3ReqFrame)); + memset(cmd->ext_buf, 0, cmd->instance->cmd_context.ext_buf_size); + ret = ps3_scsih_pd_cmd_word_build(cmd); + if (unlikely(ret != PS3_SUCCESS)) { + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "tid:0x%llx hno:%u cmd_word build NOK CFID:%d ret:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, ret); + ret = -PS3_FAILED; + goto l_out; + } + ret = ps3_scsih_pd_frontend_req_build(cmd); + } + } else { + ret = ps3_scsih_pd_frontend_req_build(cmd); + } + +l_out: + return ret; +} + +static inline void ps3_scsih_cmd_back_stat(struct ps3_cmd *cmd, U8 reply_flags) +{ + PS3_IOC_DRV2IOC_BACK_INC(cmd->instance, cmd, reply_flags); + PS3_DEV_IO_OUTSTAND_DEC(cmd->instance, cmd); + PS3_DEV_IO_BACK_INC(cmd->instance, cmd, reply_flags); +#ifdef _WINDOWS + PS3_IO_BACK_INC(cmd->instance, cmd->scmd, cmd->index, reply_flags); +#else + PS3_IO_BACK_INC(cmd->instance, cmd->scmd, reply_flags); + PS3_DEV_BUSY_DEC(cmd->scmd); +#endif +} + +static inline void ps3_scsih_overrun_underrun_verify(struct ps3_cmd *cmd) +{ + if ((ps3_scsih_is_sas_jbod_cmd(cmd)) + || (ps3_scsih_is_sata_jbod_cmd(cmd) + && ps3_scsih_cdb_is_rw_cmd(cmd->scmd->cmnd))) { + if (cmd->io_attr.sgl_buf_len > scsi_bufflen(cmd->scmd)) { + scsi_set_resid(cmd->scmd, 0); + cmd->scmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_SOFT_ERROR); + LOG_DEBUG("cmd overrun, CFID:%u op:0x%x data_len:%u scsi_buf_len:%u\n", + cmd->index, cmd->scmd->cmnd[0], cmd->io_attr.sgl_buf_len, scsi_bufflen(cmd->scmd)); + } + } + + return; +} + +static inline void ps3_r1x_read_dec(struct ps3_cmd *cmd, struct ps3_r1x_read_balance_info *rb_info) +{ + if (rb_info != NULL && cmd->r1x_read_pd > 0) { + if (cmd->r1x_read_pd > PS3_MAX_PD_NUM_ONE_VD) { + PS3_BUG(); + return; + } + ps3_atomic_dec(&rb_info->scsi_outstanding_cmds[cmd->r1x_read_pd]); + } +} + +S32 ps3_scsih_io_done(struct ps3_cmd *cmd, U16 reply_flags) +{ + S32 ret = PS3_SUCCESS; + struct scsi_cmnd *s_cmd = cmd->scmd; + struct ps3_scsi_priv_data *data = NULL; + struct ps3_cmd *err_cmd = cmd; + struct ps3_cmd *peer_cmd = NULL; + + if (unlikely(s_cmd == NULL)) { + LOG_ERROR_IN_IRQ(cmd->instance, + "hno:%u CFID:%d scmd is null\n", + PS3_HOST(cmd->instance), cmd->index); + goto l_out; + } + + if (cmd->r1x_peer_cmd != NULL) { + LOG_DEBUG("hno:%u CFID:%d one of the r1x write scmd is return, rflag:%d\n", + PS3_HOST(cmd->instance), cmd->index, reply_flags); + cmd->r1x_reply_flag = reply_flags; + cmd->is_r1x_scsi_complete = PS3_TRUE; + if (!cmd->r1x_peer_cmd->is_r1x_scsi_complete) { + PS3_IOC_DRV2IOC_BACK_INC(cmd->instance, cmd->r1x_peer_cmd, reply_flags); + LOG_DEBUG("hno:%u CFID:%d r1x write peer cmd:%d is not return\n", + PS3_HOST(cmd->instance), cmd->index, + cmd->r1x_peer_cmd->index); + goto l_out; + } + + if (cmd->r1x_peer_cmd->r1x_reply_flag != PS3_REPLY_WORD_FLAG_SUCCESS) { + err_cmd = cmd->r1x_peer_cmd; + reply_flags = cmd->r1x_peer_cmd->r1x_reply_flag; + } + + if (cmd->index >= (U32)cmd->instance->cmd_attr.cur_can_que) { + cmd = cmd->r1x_peer_cmd; + } + } + + data = scsi_device_private_data(s_cmd); + LOG_DEBUG("tid:0x%llx hno:%u scsi cmd reply cb CFID:%u rep_f:%u" + " op:0x%x chl:%u id:%u data_len:%u scsi_buflen:%u dev_type:%s\n", + cmd->trace_id, PS3_HOST(cmd->instance), cmd->index, reply_flags, + s_cmd->cmnd[0], PS3_SDEV_CHANNEL(cmd->scmd->device), + PS3_SDEV_TARGET(cmd->scmd->device), cmd->io_attr.sgl_buf_len, + scsi_bufflen(cmd->scmd), + namePS3DevType((enum PS3DevType)cmd->io_attr.dev_type)); + + ps3_scsih_cmd_back_stat(cmd, reply_flags); + PS3_IO_TRACE(cmd, PS3_IO_TRACE_DIRECT_RECV); + + if (unlikely(reply_flags != PS3_REPLY_WORD_FLAG_SUCCESS)) { + PS3_DEV_IO_ERR_STAT_INC(cmd->instance, cmd); + ret = ps3_err_scsi_cmd_fault_proc(cmd->instance, err_cmd); + } else { + ps3_scsih_overrun_underrun_verify(cmd); + if (cmd->scmd->result == DID_OK) { + ps3_qos_adjust_pd_rsc(s_cmd->device, cmd->instance, PS3_QOS_QUOTA_ADJUST_UP); + } + } + + ps3_r1x_read_dec(cmd, data->r1x_rb_info); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)) + s_cmd->SCp.ptr = NULL; +#endif + ps3_scsi_dma_unmap(cmd); + + ps3_qos_cmd_update(cmd->instance, cmd); + + ps3_r1x_write_unlock(&data->lock_mgr, cmd); + peer_cmd = cmd->r1x_peer_cmd; + INJECT_START(PS3_ERR_IJ_WAIT_ABORT_FLAG, peer_cmd); + PS3_IO_OUTSTAND_DEC(cmd->instance, s_cmd); + PS3_VD_OUTSTAND_DEC(cmd->instance, s_cmd); + ps3_scsi_cmd_free(cmd); + if (peer_cmd != NULL) { + LOG_DEBUG("host_no:%u r1x scsi write done CFID:%d and CFID:%d\n", + PS3_HOST(peer_cmd->instance), peer_cmd->r1x_peer_cmd->index, + peer_cmd->index); + ps3_r1x_peer_cmd_free_nolock(peer_cmd); + } + SCMD_IO_DONE(s_cmd); + +l_out: + return ret; +} + +void ps3_scsih_direct_to_normal_req_frame_rebuild( + struct ps3_cmd *cmd) +{ + ps3_vd_adv_to_normal_req_frame_rebuild(cmd); +} + +#ifdef _WINDOWS +static Bool ps3_scsi_sge_remap_check(struct ps3_cmd *cmd, + ps3_scatter_gather_element *os_sgl, S32 index) +{ + Bool ret = PS3_FALSE; + struct scsi_cmnd *scp = cmd->scmd; + U16 os_sge_count = (U16)scp->scatterlist->NumberOfElements; + + if (index != 0 && index != os_sge_count-1) { + goto l_check; + } + + if ( cmd->io_attr.dev_type == PS3_DEV_TYPE_VD ) { + if (cmd->io_attr.vd_entry->isNvme) { + goto l_nvme_check; + } + } else if (cmd->io_attr.dev_type == PS3_DEV_TYPE_NVME_SSD) { + goto l_nvme_check; + } else { + } + + goto l_check; +l_nvme_check: + if (index == 0) { + if (os_sgl->PhysicalAddress.QuadPart & PS3_SCSI_ALINNMENT_MASK) { + ret = PS3_TRUE; + } + } else { + if (os_sgl->PhysicalAddress.QuadPart & + scp->dma_addr_alignment_mask) { + ret = PS3_TRUE; + } + } + + goto l_out; +l_check: + if ((os_sgl->PhysicalAddress.QuadPart & scp->dma_addr_alignment_mask) + || (os_sgl->Length & scp->dma_len_alignment_mask)) { + ret = PS3_TRUE; + } +l_out: + return ret; +} + +static void ps3_scsi_dma_algin_calc(struct ps3_cmd *cmd) +{ + U32 dma_addr_alignment = 0; + U32 dma_len_alignment = 0; + struct scsi_cmnd *scp = cmd->scmd; + + if ((cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) && + (ps3_scsih_is_use_hard_cmd(cmd) != PS3_CMDWORD_FORMAT_HARDWARE)) { + dma_addr_alignment = cmd->io_attr.vd_entry->dmaAddrAlignShift; + dma_len_alignment = cmd->io_attr.vd_entry->dmaLenAlignShift; + dma_addr_alignment = dma_addr_alignment ? 1 << dma_addr_alignment : 0; + dma_len_alignment = dma_len_alignment ? 1 << dma_len_alignment : 0; + } else { + dma_addr_alignment = cmd->io_attr.pd_entry->dma_addr_alignment; + dma_len_alignment = cmd->io_attr.pd_entry->dma_len_alignment; + } + + scp->dma_addr_alignment_mask = PS3_SCSI_ALINNMENT_MASK; + scp->dma_len_alignment_mask = 0; + if (dma_addr_alignment) { + scp->dma_addr_alignment_mask = dma_addr_alignment - 1; + } + + if(dma_len_alignment){ + scp->dma_len_alignment_mask = dma_len_alignment - 1; + } + + if (( (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) && + (cmd->io_attr.vd_entry->isNvme)) || + (cmd->io_attr.dev_type == PS3_DEV_TYPE_NVME_SSD) ) { + scp->dma_addr_alignment_mask = PS3_SCSI_4K_ALINNMENT_MASK; + scp->dma_len_alignment_mask = PS3_SCSI_4K_ALINNMENT_MASK; + } + + LOG_DEBUG("tid:0x%llx hno:%u align[addr:%d,len:%d][addr_mask:%x,len_mask:%x]\n", + cmd->trace_id, PS3_HOST(cmd->instance), + dma_addr_alignment, + dma_len_alignment, + scp->dma_addr_alignment_mask, + scp->dma_len_alignment_mask); +} + +static void ps3_scsi_need_remap_check(struct ps3_cmd *cmd) +{ + S32 index = 0; + U16 os_sge_count = 0; + struct scsi_cmnd *scp = cmd->scmd; + ps3_scatter_gather_element *os_sgl = NULL; + scp->is_remap_databuff = PS3_FALSE; + + if (scp->scatterlist == NULL) { + goto l_out; + } + + if (!ps3_scsih_cdb_is_rw_cmd(scp->cmnd) && + (cmd->io_attr.dev_type == PS3_DEV_TYPE_NVME_SSD)) { + goto l_out; + } + + ps3_scsi_dma_algin_calc(cmd); + + os_sge_count = (U16)scp->scatterlist->NumberOfElements; + scsi_for_each_sg(scp, os_sgl, os_sge_count, index) { + if (os_sgl == NULL) { + break; + } + + if (ps3_scsi_sge_remap_check(cmd, os_sgl, index)) { + scp->is_remap_databuff = PS3_TRUE; + break; + } + } +l_out: + if(scp->is_remap_databuff) { + LOG_DEBUG("tid:0x%llx hno:%u unalign[addr_mask:%x,len_mask:%x] " + "sgl addr:0x%llx len:%d or SAS sge num:%d > %d, index:%d\n", + cmd->trace_id, PS3_HOST(cmd->instance), + scp->dma_addr_alignment_mask, + scp->dma_len_alignment_mask, + os_sgl->PhysicalAddress.QuadPart, + os_sgl->Length, + scp->scatterlist->NumberOfElements, + PS3_FRAME_REQ_SGE_NUM_HW, + index); + } + return; +} + +static S32 ps3_scsi_remap_sgl(struct ps3_cmd *cmd) +{ + S32 ret = -PS3_FAILED; + struct scsi_cmnd *scp = cmd->scmd; + void *srb_data_buff = SrbGetDataBuffer(cmd->srb); + + if (srb_data_buff == NULL) { + goto l_out; + } + + scp->remap_databuff_length = scp->data_transfer_length; + if (scp->data_transfer_length & scp->dma_len_alignment_mask) { + scp->remap_databuff_length = + (scp->data_transfer_length + scp->dma_len_alignment_mask + 1) & + (~(U64)scp->dma_len_alignment_mask); + } + + scp->remap_databuff = ps3_dma_alloc_coherent(cmd->instance, + scp->remap_databuff_length, + &scp->remap_databuff_phy); + if (scp->remap_databuff == NULL) { + goto l_out; + } + + cmd->os_sge_map_count = 1; + memset(&scp->remap_sgl, 0, sizeof(scp->remap_sgl)); + scp->scatterlist = (STOR_SCATTER_GATHER_LIST*)&scp->remap_sgl; + scp->scatterlist->NumberOfElements = 1; + scp->scatterlist->List[0].Length = scp->remap_databuff_length; + scp->scatterlist->List[0].PhysicalAddress.QuadPart = (LONGLONG)scp->remap_databuff_phy; + RtlMoveMemory(scp->remap_databuff, + srb_data_buff, + scp->data_transfer_length); + LOG_DEBUG("remap io,%p, data_len:%d, remap_len:%d, addr:0x%llx\n", + srb_data_buff, + scp->data_transfer_length, + scp->remap_databuff_length, + scp->remap_databuff_phy); + + ret = PS3_SUCCESS; +l_out: + return ret; +} + +static S32 ps3_scsi_unremap_sgl(struct ps3_cmd *cmd) +{ + S32 ret = -PS3_FAILED; + struct scsi_cmnd *scp = cmd->scmd; + void *srb_data_buff = SrbGetDataBuffer(cmd->srb); + + if (srb_data_buff == NULL) { + goto l_out; + } + + if (scp->remap_databuff != NULL) { + RtlMoveMemory(srb_data_buff, + scp->remap_databuff, + scp->data_transfer_length); + + LOG_DEBUG("unremap io,%p, len:%d \n", + srb_data_buff, + scp->data_transfer_length); + + ps3_dma_free_coherent(cmd->instance, + scp->remap_databuff_length, + scp->remap_databuff, + scp->remap_databuff_phy ); + scp->remap_databuff = NULL; + scp->is_remap_databuff = PS3_FALSE; + cmd->os_sge_map_count = 0; + ret = PS3_SUCCESS; + } + +l_out: + return ret; +} +#endif + +S32 ps3_scsi_dma_map(struct ps3_cmd *cmd) +{ + S32 index = 0; + S32 os_sge_count = 0; + struct scsi_cmnd *scp = cmd->scmd; + ps3_scatter_gather_element *os_sgl = NULL; + + os_sge_count = scsi_dma_map(scp); + if (unlikely(os_sge_count <= 0)) { + cmd->os_sge_map_count = 0; + goto l_out; + } + + scsi_for_each_sg(scp, os_sgl, os_sge_count, index) { + if (os_sgl == NULL) { + break; + } + INJECT_START(PS3_ERR_IJ_SGL_ADDR_PAGE_MODE_5, &(sg_dma_address_u64(os_sgl))); + if (index == 0 && cmd->instance->page_mode_change + && (sg_dma_address_u64(os_sgl) & cmd->instance->page_mode_addr_mask)) { + cmd->instance->page_mode_addr_mask = PS3_PAGE_MODE_ABOVE_4_ADDR_MASK; + if (sg_dma_address_u64(os_sgl) & PS3_PAGE_MODE_ABOVE_4_ADDR_MASK) { + cmd->instance->page_mode_change = PS3_FALSE; + } + dev_info(&cmd->instance->pdev->dev, + "page mode change, addr:0x%llx\n", + sg_dma_address_u64(os_sgl)); + } + INJECT_START(PS3_ERR_IJ_SGL_ADDR_RESTORE, &(sg_dma_address_u64(os_sgl))); + sg_dma_address(os_sgl) = + PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(cmd->instance->dma_addr_bit_pos, sg_dma_address_u64(os_sgl)); + } + + cmd->os_sge_map_count = os_sge_count; +l_out: + return os_sge_count; +} + +void ps3_scsi_dma_unmap(struct ps3_cmd *cmd) +{ + S32 index = 0; + U16 os_sge_count = 0; + struct scsi_cmnd *scp = NULL; + ps3_scatter_gather_element *os_sgl = NULL; + + if (cmd == NULL) { + goto l_out; + } + + os_sge_count = cmd->os_sge_map_count; + scp = cmd->scmd; + if (os_sge_count == 0) { + goto l_out; + } + scsi_for_each_sg(scp, os_sgl, os_sge_count, index) { + if (os_sgl == NULL) { + break; + } + sg_dma_address(os_sgl) = + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(cmd->instance->dma_addr_bit_pos, sg_dma_address_u64(os_sgl)); + } + if (scp->sdb.table.sgl) { + scsi_dma_unmap(scp); + } + cmd->os_sge_map_count = 0; + +l_out: + return; +} + +#if 0 +struct disk_type_to_proc_func_table* ps3_req_func_entry_query(U8 dev_type) +{ + struct disk_type_to_proc_func_table *entry = NULL; + U32 table_size = ARRAY_SIZE(g_req_frame_func_table); + U32 i = 0; + + for (; i < table_size; ++i) { + if (dev_type == g_req_frame_func_table[i].type) { + entry = &g_req_frame_func_table[i]; + goto l_out; + } + } +l_out: + return entry; +} +#endif + +static S32 ps3_vd_access_policy_check(struct ps3_instance *instance, + U8 channel, U16 id, struct scsi_cmnd *s_cmd) +{ + S32 ret = PS3_SUCCESS; + U8 opcode = 0; + U16 sub_opcode = 0; + struct PS3VDEntry *entry = ps3_dev_mgr_lookup_vd_info(instance, channel, id); + static unsigned long j; + if (unlikely(entry == NULL)) { +#ifndef _WINDOWS + s_cmd->result = PS3_SCSI_RESULT_HOST_STATUS(DID_BAD_TARGET); +#else + scsi_cmnd_hoststatus_set(s_cmd, DID_BAD_TARGET); +#endif + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "hno:%u chl:%u id:%u\n", + PS3_HOST(instance), channel, id); + ret = -PS3_ENODEV; + goto l_out; + } + + if (unlikely((entry->accessPolicy == VD_ACCESS_POLICY_BLOCK) && + ps3_scsih_cdb_is_rw_cmd(s_cmd->cmnd))) { + ps3_errcode_to_scsi_status(instance, s_cmd, PS3_STATUS_ACCESS_BLOCK, NULL, 0, NULL); + ps3_scsih_cdb_opcode_get(s_cmd->cmnd, &opcode, &sub_opcode); + + LOG_DEBUG("hno:%u chl:%u id:%u vd_access_policy:%u" + "op:0x%x sub_op:0x%x block io\n", + PS3_HOST(instance), channel, id, entry->accessPolicy, + opcode, sub_opcode); + ret = -PS3_IO_BLOCK; + goto l_out; + } else if (unlikely((entry->accessPolicy == VD_ACCESS_POLICY_READ_ONLY) && + ps3_scsih_cdb_is_write_cmd(s_cmd->cmnd))) { + ps3_errcode_to_scsi_status(instance, s_cmd, PS3_STATUS_ACCESS_BLOCK, NULL, 0, NULL); + ps3_scsih_cdb_opcode_get(s_cmd->cmnd, &opcode, &sub_opcode); + + LOG_DEBUG("hno:%u chl:%u id:%u vd_access_policy:%u" + "op:0x%x sub_op:0x%x block write io\n", + PS3_HOST(instance), channel, id, entry->accessPolicy, + opcode, sub_opcode); + ret = -PS3_IO_BLOCK; + goto l_out; + } +l_out: + return ret; +} + +S32 ps3_get_requeue_or_reset(void) +{ +#if ((defined(RHEL_MAJOR) && (RHEL_MAJOR == 7) && (RHEL_MINOR == 3)) || \ +((LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) && \ +(LINUX_VERSION_CODE < KERNEL_VERSION(4,4,14)))) + return PS3_SCSI_RESULT_HOST_STATUS(DID_REQUEUE); +#else + return PS3_SCSI_RESULT_HOST_STATUS(DID_RESET); +#endif +} + +Bool ps3_write_direct_enable(struct ps3_cmd *cmd) +{ + Bool result = PS3_TRUE; + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) && + !cmd->io_attr.vd_entry->isWriteDirectEnable) { + result = PS3_FALSE; + } + + return result; +} + +Bool ps3_ssd_vd_qmask_calculate_hba(struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + struct ps3_scsi_priv_data *device_priv_data = NULL; + + device_priv_data = PS3_SDEV_PRI_DATA(cmd->scmd->device); + if (device_priv_data != NULL) { + cmd->cmd_word.qMask = 1 << + (device_priv_data->qmask_count & (cmd->instance->ctrl_info.vdQueueNum - 1)); + device_priv_data->qmask_count++; + ret = PS3_TRUE;; + } + + return ret; +} + diff --git a/drivers/scsi/ps3stor/ps3_scsih.h b/drivers/scsi/ps3stor/ps3_scsih.h new file mode 100644 index 0000000000000000000000000000000000000000..e451f019a5d146aaa27b211b508cc10a9ca7614f --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsih.h @@ -0,0 +1,153 @@ + +#ifndef _PS3_SCSIH_H_ +#define _PS3_SCSIH_H_ + +#ifndef _WINDOWS +#include +#include +#else +#include "ps3_cmd_adp.h" +#endif + +#include "ps3_htp_def.h" +#include "ps3_inner_data.h" + +#define PS3_HW_VD_MAX_IO_SIZE_1M (1ULL << 20) +#define PS3_PAGE_MODE_ABOVE_3_ADDR_MASK 0xFFFFFF8000000000ULL +#define PS3_PAGE_MODE_ABOVE_4_ADDR_MASK 0xFFFF000000000000ULL + +#define PS3_IS_R0J1(raidlevel) \ + ((raidlevel) == RAID0 || (raidlevel) == RAID1 || \ + (raidlevel) == RAID10 || (raidlevel) == RAID1E || \ + (raidlevel) == RAID00) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,15,0)) +#define SCMD_GET_REQUEST(scmd) scsi_cmd_to_rq(scmd) +#else +#define SCMD_GET_REQUEST(scmd) scmd->request +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)) +#define SCMD_IO_DONE(scmd) scsi_done(scmd) +#else +#define SCMD_IO_DONE(scmd) scmd->scsi_done(scmd) +#endif + +#if 0 +#define PS3_IF_QUIT_STREAM_DIRECT_DETECT(raidlevel) \ + ((ps3_direct_check_stream_query() == PS3_FALSE) && PS3_IS_R0J1(raidlevel)) +#endif + +#define PS3_IF_QUIT_STREAM_DIRECT_DETECT() \ + (ps3_direct_check_stream_query() == PS3_FALSE) + +typedef S32 (*dev_type_to_proc_func)(struct ps3_cmd*); +struct disk_type_to_proc_func_table { + U8 type; + dev_type_to_proc_func func; +}; +#define CMND_LEN16 (16) +#define FRAME_CMD_MASK_SHIFT (0x1) +#define FRAME_CMD_MASK_BITS (0x07) + +enum PS3_FRAME_CMD_TYPE { + SCSI_FRAME_CMD = 0, + SAS_FRAME_CMD = 1, + SATA_FRAME_CMD = 2, + NVME_FRAME_CMD = 3, + UNKNOWN_FRAME_CMD, +}; +enum PS3_RW_CMD_TYPE { + SCSI_RW_UNUSED_CMD = 0, + SCSI_RW_SEQ_CMD = 1, + SCSI_RW_RANDOM_CMD = 2, +}; + +struct scsi_cmd_parse_table { + U8 cmd_type; + U8 rw_attr; +}; + +static inline void ps3_put_unaligned_be64(U8 *p, U32 val_hi, U32 val_lo) +{ + p[0] = (U8) (val_hi >> PS3_SHIFT_3BYTE) & 0xff; + p[1] = (U8) (val_hi >> PS3_SHIFT_WORD) & 0xff; + p[2] = (U8) (val_hi >> PS3_SHIFT_BYTE) & 0xff; + p[3] = (U8) val_hi & 0xff; + + p[4] = (U8) (val_lo >> PS3_SHIFT_3BYTE) & 0xff; + p[5] = (U8) (val_lo >> PS3_SHIFT_WORD) & 0xff; + p[6] = (U8) (val_lo >> PS3_SHIFT_BYTE) & 0xff; + p[7] = (U8) val_lo & 0xff; +} + +static inline void ps3_put_unaligned_be32(U8 *p, U32 val) +{ + p[0] = (U8) (val >> PS3_SHIFT_3BYTE) & 0xff; + p[1] = (U8) (val >> PS3_SHIFT_WORD) & 0xff; + p[2] = (U8) (val >> PS3_SHIFT_BYTE) & 0xff; + p[3] = (U8) val & 0xff; +} + +static inline void ps3_put_unaligned_be16(U8 *p, U16 val) +{ + p[0] = (U8) (val >> PS3_SHIFT_BYTE) & 0xff; + p[1] = (U8) val & 0xff; +} + +static inline U16 ps3_get_unaligned_be16(U8 *p) +{ + return (U16)((p[0] << PS3_SHIFT_BYTE) | p[1]); +} + +#ifndef _WINDOWS + +typedef struct scatterlist ps3_scatter_gather_element; + +S32 ps3_scsih_queue_command(struct Scsi_Host *s_host, + struct scsi_cmnd *s_cmd); +#else +Bool ps3_scsih_sys_state_check(struct ps3_instance *instance, S32 *host_status); +#endif + +S32 ps3_scsih_cmd_build(struct ps3_cmd *cmd); + +void ps3_scsih_direct_to_normal_req_frame_rebuild( + struct ps3_cmd *cmd); + +S32 ps3_scsih_io_done(struct ps3_cmd *cmd, U16 reply_flags); + +void ps3_scsi_dma_unmap(struct ps3_cmd *cmd); + +S32 ps3_scsi_dma_map(struct ps3_cmd *cmd); + +#if 0 +struct disk_type_to_proc_func_table* ps3_req_func_entry_query(U8 dev_type); +#endif + +Bool ps3_scsih_sata_direct_is_support(struct ps3_cmd *cmd, + const struct ps3_pd_entry *pd_entry); + +Bool ps3_scsih_stream_is_detect(struct ps3_cmd * cmd); +Bool ps3_raid_scsih_stream_is_direct(const struct ps3_cmd * cmd); +Bool ps3_hba_scsih_stream_is_direct(const struct ps3_cmd * cmd); + +void ps3_scsih_print_req(struct ps3_cmd *cmd, U8 log_level); + +S32 ps3_get_requeue_or_reset(void); + +Bool ps3_scsih_sata_direct_is_need(struct ps3_cmd *cmd); + +Bool ps3_scsih_is_sata_jbod_mgr_cmd(const struct ps3_cmd *cmd); + +U32 ps3_scsih_xfer_cnt_get(const struct ps3_cmd *cmd); + +Bool ps3_is_r1x_write_cmd(const struct ps3_cmd *cmd); + +S32 ps3_vd_direct_req_frame_build(struct ps3_cmd *cmd); + +Bool ps3_write_direct_enable(struct ps3_cmd *cmd); + +Bool ps3_ssd_vd_qmask_calculate_hba(struct ps3_cmd *cmd); + +#endif diff --git a/drivers/scsi/ps3stor/ps3_scsih_cmd_parse.c b/drivers/scsi/ps3stor/ps3_scsih_cmd_parse.c new file mode 100644 index 0000000000000000000000000000000000000000..71d3887b2bbcc2753769c353ffdb5ade78c58761 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsih_cmd_parse.c @@ -0,0 +1,804 @@ + +#ifndef _WINDOWS +#include +#include "ps3_scsih.h" +#include "ps3_module_para.h" +#endif + +#include "ps3_scsih_cmd_parse.h" +#include "ps3_err_def.h" +#include "ps3_inner_data.h" +#include "ps3_instance_manager.h" +#include "ps3_driver_log.h" + +#define PS3_WRITE_VERIFY_16 (0x8e) +#define PS3_WRITE_VERIFY_32 (0x0C) +#define ORWRITE_16 (0x8B) +#define ORWRITE_32 (0x0E) +#define PRE_FETCH_16 (0x90) +#define READ_BUFFER_16 (0X9B) +#define REPORT_REFERRALS (0x9E) +#define SANITIZE (0x48) +#define WRITE_ATOMIC_16 (0x9C) +#define WRITE_ATOMIC_32 (0x0F) +#define WRITE_SCATTERED_16 (0x12) +#define WRITE_SCATTERED_32 (0x0011) +#define WRITE_STREAM_16 (0x9A) +#define WRITE_STREAM_32 (0x10) +#define WRITE_LONG_16 (0x11) + +Bool ps3_scsih_is_rw_type(U8 type) +{ + Bool is_rw_type = PS3_FALSE; + + switch (type) { + case PS3_SCSI_CMD_TYPE_READ: + case PS3_SCSI_CMD_TYPE_WRITE: + case PS3_SCSI_CMD_TYPE_UNMAP: + case PS3_SCSI_CMD_TYPE_RW: + is_rw_type = PS3_TRUE; + break; + default: + is_rw_type = PS3_FALSE; + break; + } + + return is_rw_type; +} + +Bool ps3_scsih_rw_cmd_is_need_split_hba(struct ps3_cmd *cmd) +{ + Bool ret = PS3_FALSE; + (void)cmd; + + return ret; +} + +Bool ps3_scsih_rw_cmd_is_need_split_raid(struct ps3_cmd *cmd) +{ + Bool is_need_split = PS3_FALSE; + U32 num_blocks = 0; + U32 lba_lo = 0; + U32 lba_hi = 0; + + + ps3_scsih_cdb_parse(cmd->scmd->cmnd, &num_blocks, &lba_lo, &lba_hi, &is_need_split); + + return is_need_split; +} + +static U8 ps3_scsih_service_action32_rw_type_get(const U8 *cdb) +{ + enum ps3_scsi_cmd_type rw_type = PS3_SCSI_CMD_TYPE_UNKOWN; + + U16 cmd_type = PS3_SERVICE_ACTION32(cdb); + switch (cmd_type) { + case READ_32: + rw_type = PS3_SCSI_CMD_TYPE_READ; + break; + + case WRITE_32: + case PS3_WRITE_VERIFY_32: + case ORWRITE_32: + case WRITE_ATOMIC_32: + rw_type = (enum ps3_scsi_cmd_type)((U8)PS3_SCSI_CMD_TYPE_WRITE | PS3_SCSI_CONFLICT_CHECK); + break; + case VERIFY_32: + case WRITE_SAME_32: + case WRITE_STREAM_32: + case WRITE_SCATTERED_32: + rw_type = PS3_SCSI_CMD_TYPE_WRITE; + break; + + default: + rw_type = PS3_SCSI_CMD_TYPE_NORW; + break; + } + + return (U8)rw_type; +} + +static inline U8 ps3_service_action16_rw_type_get(const U8 *cdb) +{ + enum ps3_scsi_cmd_type rw_type = PS3_SCSI_CMD_TYPE_UNKOWN; + + U8 cmd_type = cdb[1] & 0x1f; + switch (cmd_type) { + case WRITE_LONG_16: + case WRITE_SCATTERED_16: + rw_type = PS3_SCSI_CMD_TYPE_WRITE; + break; + default: + rw_type = PS3_SCSI_CMD_TYPE_NORW; + break; + } + + return (U8)rw_type; +} + +static inline void ps3_scsih_cdb_options_get(const U8 *cdb, + ps3_scsi_cdb_opts_u *cdb_opts) +{ + ps3_scsi_cdb_opts_u *pRead = (ps3_scsi_cdb_opts_u *)(cdb); + + cdb_opts->fua = pRead->fua; + cdb_opts->protect = pRead->protect; + cdb_opts->dpo = pRead->dpo; +} + +S32 ps3_scsih_cdb_opts_parse(struct ps3_cmd *cmd) +{ + ps3_scsi_cdb_opts_u *cdb_opts = &cmd->io_attr.cdb_opts; +#ifndef _WINDOWS + const U8 *cdb = cmd->scmd->cmnd; +#else + const U8 *cdb = scsi_cmnd_cdb(cmd->scmd); +#endif + + U16 sub_cmd_type = 0; + S32 ret = PS3_SUCCESS; + + switch (cdb[0]) { + case READ_10: + case READ_12: + case READ_16: + case WRITE_10: + case WRITE_12: + case WRITE_16: + ps3_scsih_cdb_options_get(&cdb[1], cdb_opts); + break; + case VARIABLE_LENGTH_CMD: + sub_cmd_type = PS3_SERVICE_ACTION32(cdb); + switch (sub_cmd_type) { + case READ_32: + case WRITE_32: + ps3_scsih_cdb_options_get(&cdb[10], cdb_opts); + break; + default: + ret = -PS3_FAILED; + break; + } + break; + case WRITE_6: + cdb_opts->option = 0; + break; + case READ_6: + cdb_opts->option = 0; + break; + default: + ret = -PS3_FAILED; + break; + } + + return ret; +} + +Bool ps3_scsih_is_protocal_rw(const U8 *cdb) +{ + Bool ret = PS3_DRV_FALSE; + U16 sub_cmd_type = 0; + + switch (cdb[0]) { + case READ_6: + case READ_10: + case READ_12: + case READ_16: + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + ret = PS3_DRV_TRUE; + break; + case VARIABLE_LENGTH_CMD: + sub_cmd_type = PS3_SERVICE_ACTION32(cdb); + switch (sub_cmd_type) { + case READ_32: + case WRITE_32: + ret = PS3_DRV_TRUE; + break; + default: + break; + } + break; + default: + break; + } + + return ret; +} + +U8 ps3_scsih_cdb_rw_type_get(const U8 *cdb) +{ + U8 rw_type = (U8)PS3_SCSI_CMD_TYPE_UNKOWN; + + switch (cdb[0]) { + case READ_6: + case READ_10: + case READ_12: + case READ_16: + case PRE_FETCH: + case PRE_FETCH_16: + rw_type = (U8)PS3_SCSI_CMD_TYPE_READ; + break; + + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case ORWRITE_16: + case WRITE_ATOMIC_16: + case PS3_WRITE_VERIFY_16: + rw_type = (U8)PS3_SCSI_CMD_TYPE_WRITE | PS3_SCSI_CONFLICT_CHECK; + break; + case VERIFY: + case WRITE_SAME: + case VERIFY_12: + case VERIFY_16: + case WRITE_SAME_16: + case SYNCHRONIZE_CACHE: + case SYNCHRONIZE_CACHE_16: + case WRITE_STREAM_16: + case WRITE_LONG: + rw_type = (U8)PS3_SCSI_CMD_TYPE_WRITE; + break; + + case VARIABLE_LENGTH_CMD: + rw_type = ps3_scsih_service_action32_rw_type_get(cdb); + break; + case UNMAP: + rw_type = (U8)PS3_SCSI_CMD_TYPE_UNMAP | PS3_SCSI_CONFLICT_CHECK; + break; + + case COMPARE_AND_WRITE: + rw_type = (U8)PS3_SCSI_CMD_TYPE_RW | PS3_SCSI_CONFLICT_CHECK; + break; + + case SERVICE_ACTION_OUT_16: + rw_type = ps3_service_action16_rw_type_get(cdb); + break; + + default: + rw_type = (U8)PS3_SCSI_CMD_TYPE_NORW; + break; + } + + return rw_type; +} + +static inline void ps3_scsih_cdb_rw6_rebuild(U8 *cdb, U32 num_blocks, + U32 lba_lo) +{ + cdb[1] &= ~(0x1f); + cdb[1] |= (U8) (lba_lo >> PS3_SHIFT_WORD) & 0x1f; + cdb[2] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[3] = (U8) lba_lo & 0xff; + + cdb[4] = (256 == num_blocks ) ? 0 : ((U8) num_blocks & 0xff); +} + +static inline void ps3_scsih_cdb_rw10_rebuild(U8 *cdb, U32 num_blocks, + U32 lba_lo) +{ + cdb[2] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = (U8) lba_lo & 0xff; + + cdb[7] = (U8) (num_blocks >> PS3_SHIFT_BYTE) & 0xff; + cdb[8] = (U8) num_blocks & 0xff; +} + +static inline void ps3_scsih_cdb_rw12_rebuild(U8 *cdb, U32 num_blocks, + U32 lba_lo) +{ + cdb[2] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = (U8) lba_lo & 0xff; + + cdb[6] = (U8) (num_blocks >> PS3_SHIFT_3BYTE) & 0xff; + cdb[7] = (U8) (num_blocks >> PS3_SHIFT_WORD) & 0xff; + cdb[8] = (U8) (num_blocks >> PS3_SHIFT_BYTE) & 0xff; + cdb[9] = (U8) num_blocks & 0xff; +} + +static inline void ps3_scsih_cdb_rw16_rebuild(U8 *cdb, U32 num_blocks, + U32 lba_lo, U32 lba_hi) +{ + cdb[2] = (U8) (lba_hi >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (U8) (lba_hi >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (U8) (lba_hi >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = (U8) lba_hi & 0xff; + + cdb[6] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[7] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[8] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[9] = (U8) lba_lo & 0xff; + + cdb[10] = (U8) (num_blocks >> PS3_SHIFT_3BYTE) & 0xff; + cdb[11] = (U8) (num_blocks >> PS3_SHIFT_WORD) & 0xff; + cdb[12] = (U8) (num_blocks >> PS3_SHIFT_BYTE) & 0xff; + cdb[13] = (U8) num_blocks & 0xff; +} + +static inline void ps3_scsih_cdb_rw32_rebuild(U8 *cdb, U32 num_blocks, + U32 lba_lo, U32 lba_hi) +{ + U16 cmd_type = PS3_SERVICE_ACTION32(cdb); + LOG_DEBUG("[ps3]VARIABLE_LENGTH_CMD :0x%x!\n", cmd_type); + + switch (cmd_type) { + case READ_32: + case VERIFY_32: + case WRITE_32: + case PS3_WRITE_VERIFY_32: + case WRITE_SAME_32: + case ORWRITE_32: + case WRITE_ATOMIC_32: + case WRITE_STREAM_32: + cdb[12] = (U8) (lba_hi >> PS3_SHIFT_3BYTE) & 0xff; + cdb[13] = (U8) (lba_hi >> PS3_SHIFT_WORD) & 0xff; + cdb[14] = (U8) (lba_hi >> PS3_SHIFT_BYTE) & 0xff; + cdb[15] = (U8) lba_hi & 0xff; + + cdb[16] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[17] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[18] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[19] = (U8) lba_lo & 0xff; + + cdb[20] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[21] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[22] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[23] = (U8) lba_lo & 0xff; + + cdb[28] = (U8) (num_blocks >> PS3_SHIFT_3BYTE) & 0xff; + cdb[29] = (U8) (num_blocks >> PS3_SHIFT_WORD) & 0xff; + cdb[30] = (U8) (num_blocks >> PS3_SHIFT_BYTE) & 0xff; + cdb[31] = (U8) num_blocks & 0xff; + break; + default : + break; + } +} +static inline void ps3_scsih_cdb_write_long10_rebuild(U8 *cdb,U32 lba_lo) +{ + cdb[2] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = (U8) lba_lo & 0xff; +} + +static inline void ps3_cdb_comp_and_write_rebuild(U8 *cdb, + U32 num_blocks, U32 lba_lo, U32 lba_hi) +{ + cdb[2] = (U8) (lba_hi >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (U8) (lba_hi >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (U8) (lba_hi >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = (U8) lba_hi & 0xff; + + cdb[6] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[7] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[8] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[9] = (U8) lba_lo & 0xff; + + cdb[13] = (U8) num_blocks & 0xff; +} + +static inline void ps3_scsih_service_16_rebuild(U8 *cdb, + U32 lba_lo, U32 lba_hi) +{ + U8 cmd_type = cdb[1] & 0x1f; + LOG_DEBUG("[ps3] CMD :0x%x!\n", cmd_type); + + if (WRITE_LONG_16 == cmd_type) { + cdb[2] = (U8) (lba_hi >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (U8) (lba_hi >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (U8) (lba_hi >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = (U8) lba_hi & 0xff; + + cdb[6] = (U8) (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[7] = (U8) (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[8] = (U8) (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[9] = (U8) lba_lo & 0xff; + } +} + +static inline void ps3_scsih_atomic_stream_16_rebuild(U8 *cdb, + U32 num_blocks, U32 lba_lo, U32 lba_hi) +{ + cdb[2] = (lba_hi >> PS3_SHIFT_3BYTE) & 0xff; + cdb[3] = (lba_hi >> PS3_SHIFT_WORD) & 0xff; + cdb[4] = (lba_hi >> PS3_SHIFT_BYTE) & 0xff; + cdb[5] = lba_hi & 0xff; + + cdb[6] = (lba_lo >> PS3_SHIFT_3BYTE) & 0xff; + cdb[7] = (lba_lo >> PS3_SHIFT_WORD) & 0xff; + cdb[8] = (lba_lo >> PS3_SHIFT_BYTE) & 0xff; + cdb[9] = lba_lo & 0xff; + + cdb[12] = (num_blocks >> PS3_SHIFT_BYTE) & 0xff; + cdb[13] = num_blocks & 0xff; +} + +static inline void ps3_scsih_cdb_rw6_parse(const U8 *cdb, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi) +{ + const U32 default_num_blocks = 256; + (void)lba_hi; + *lba_lo = (U32)(((cdb[1] & 0x1f) << PS3_SHIFT_WORD) | + (cdb[2] << PS3_SHIFT_BYTE) | cdb[3]); + *num_blocks = ((U32)cdb[4] == 0) ? default_num_blocks : (U32)cdb[4]; + return; +} + +static inline void ps3_scsih_cdb_rw10_parse(const U8 *cdb, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi) +{ + (void)lba_hi; + *lba_lo = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks = ((U32)cdb[8] | ((U32)cdb[7] << PS3_SHIFT_BYTE)); + + return; +} + +static inline void ps3_scsih_cdb_rw12_parse(const U8 *cdb, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi) +{ + (void)lba_hi; + *lba_lo = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks = ((U32)cdb[6] << PS3_SHIFT_3BYTE) | + ((U32)cdb[7] << PS3_SHIFT_WORD) | + ((U32)cdb[8] << PS3_SHIFT_BYTE) | (U32)cdb[9]; + return; +} + +static inline void ps3_scsih_cdb_rw16_parse(const U8 *cdb, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi) +{ + *lba_lo = ((U32)cdb[6] << PS3_SHIFT_3BYTE) | + ((U32)cdb[7] << PS3_SHIFT_WORD) | + ((U32) cdb[8] << PS3_SHIFT_BYTE) | (U32)cdb[9]; + *lba_hi = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks = ((U32)cdb[10] << PS3_SHIFT_3BYTE) | + ((U32)cdb[11] << PS3_SHIFT_WORD) | + ((U32)cdb[12] << PS3_SHIFT_BYTE) | (U32)cdb[13]; + return; +} + +static inline void ps3_scsih_cdb_rw32_parse(const U8 *cdb, + U32 *num_blocks, U32 *lba_lo, U32 *lba_hi, Bool *is_need_split) +{ + U16 cmd_type = PS3_SERVICE_ACTION32(cdb); + LOG_DEBUG("[ps3]VARIABLE_LENGTH_CMD :0x%x!\n", cmd_type); + *is_need_split = PS3_FALSE; + + switch (cmd_type) { + case READ_32: + case WRITE_32: + case PS3_WRITE_VERIFY_32: + *is_need_split = PS3_TRUE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) + fallthrough; +#endif + case VERIFY_32: + case WRITE_SAME_32: + case ORWRITE_32: + case WRITE_ATOMIC_32: + case WRITE_STREAM_32: + *lba_lo = ((U32)cdb[16] << PS3_SHIFT_3BYTE) | + ((U32)cdb[17] << PS3_SHIFT_WORD) | + ((U32) cdb[18] << PS3_SHIFT_BYTE) | (U32)cdb[19]; + *lba_hi = ((U32)cdb[12] << PS3_SHIFT_3BYTE) | + ((U32)cdb[13] << PS3_SHIFT_WORD) | + ((U32)cdb[14] << PS3_SHIFT_BYTE) | (U32)cdb[15]; + *num_blocks = ((U32)cdb[28] << PS3_SHIFT_3BYTE) | + ((U32)cdb[29] << PS3_SHIFT_WORD) | + ((U32)cdb[30] << PS3_SHIFT_BYTE) | (U32)cdb[31]; + break; + + case WRITE_SCATTERED_32: + *lba_lo = 0; + *num_blocks = 0; + break; + + default: + break; + } + + return; +} + +static inline void ps3_cdb_write_long10_parse(const U8 *cdb, + U32 *num_blocks, U32 *lba_lo, U32 *lba_hi) +{ + (void)lba_hi; + *lba_lo = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks =1; +} + +static inline void ps3_cdb_comp_and_write_parse(const U8 *cdb, + U32 *num_blocks, U32 *lba_lo, U32 *lba_hi) +{ + *lba_lo = ((U32)cdb[6] << PS3_SHIFT_3BYTE) | + ((U32)cdb[7] << PS3_SHIFT_WORD) | + ((U32) cdb[8] << PS3_SHIFT_BYTE) | (U32)cdb[9]; + *lba_hi = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks = (U32)cdb[13]; +} + +static inline void ps3_scsih_service_16_parse(const U8 *cdb, + U32 *num_blocks, U32 *lba_lo, U32 *lba_hi) +{ + U8 cmd_type = cdb[1] & 0x1f; + LOG_DEBUG("[ps3] CMD :0x%x!\n", cmd_type); + + switch (cmd_type) { + case WRITE_LONG_16: + *lba_lo = ((U32)cdb[6] << PS3_SHIFT_3BYTE) | + ((U32)cdb[7] << PS3_SHIFT_WORD) | + ((U32) cdb[8] << PS3_SHIFT_BYTE) | (U32)cdb[9]; + *lba_hi = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks = 1; + break; + + case WRITE_SCATTERED_16: + *lba_lo = 0; + *num_blocks = 0; + break; + + default: + break; + } + + return; +} + +void ps3_scsih_cdb_parse(const U8 *cdb, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi, Bool *is_need_split) +{ + *num_blocks = 0; + *lba_lo = 0; + *lba_hi = 0; + *is_need_split = PS3_FALSE; + + switch (cdb[0]) { + case READ_6: + case WRITE_6: + ps3_scsih_cdb_rw6_parse(cdb, num_blocks, lba_lo, lba_hi); + *is_need_split = PS3_TRUE; + break; + + case READ_10: + case WRITE_10: + case WRITE_VERIFY: + *is_need_split = PS3_TRUE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) + fallthrough; +#endif + case VERIFY: + case WRITE_SAME: + case PRE_FETCH: + case SYNCHRONIZE_CACHE: + ps3_scsih_cdb_rw10_parse(cdb, num_blocks, lba_lo, lba_hi); + break; + + case READ_12: + case WRITE_12: + case WRITE_VERIFY_12: + *is_need_split = PS3_TRUE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) + fallthrough; +#endif + case VERIFY_12: + ps3_scsih_cdb_rw12_parse(cdb, num_blocks, lba_lo, lba_hi); + break; + + case READ_16: + case WRITE_16: + case PS3_WRITE_VERIFY_16: + *is_need_split = PS3_TRUE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,0) + fallthrough; +#endif + case VERIFY_16: + case WRITE_SAME_16: + case ORWRITE_16: + case PRE_FETCH_16: + case SYNCHRONIZE_CACHE_16: + ps3_scsih_cdb_rw16_parse(cdb, num_blocks, lba_lo, lba_hi); + break; + + case FORMAT_UNIT: + case UNMAP: + case SANITIZE: + break; + + case VARIABLE_LENGTH_CMD: + ps3_scsih_cdb_rw32_parse(cdb, num_blocks, lba_lo, lba_hi, is_need_split); + break; + + case COMPARE_AND_WRITE: + ps3_cdb_comp_and_write_parse(cdb, num_blocks, lba_lo, lba_hi); + break; + + case WRITE_ATOMIC_16: + case WRITE_STREAM_16: + *lba_lo = ((U32)cdb[6] << PS3_SHIFT_3BYTE) | + ((U32)cdb[7] << PS3_SHIFT_WORD) | + ((U32) cdb[8] << PS3_SHIFT_BYTE) | (U32)cdb[9]; + *lba_hi = ((U32)cdb[2] << PS3_SHIFT_3BYTE) | + ((U32)cdb[3] << PS3_SHIFT_WORD) | + ((U32)cdb[4] << PS3_SHIFT_BYTE) | (U32)cdb[5]; + *num_blocks = ((U32)cdb[12] << PS3_SHIFT_BYTE) | (U32)cdb[13]; + break; + + case WRITE_LONG: + ps3_cdb_write_long10_parse(cdb, num_blocks, lba_lo, lba_hi); + break; + + case SERVICE_ACTION_OUT_16: + ps3_scsih_service_16_parse(cdb, num_blocks, lba_lo, lba_hi); + break; + + default: + break; + } + + return; +} +static inline void ps3_convert_to_cdb16(U8 *cdb, U16 cdb_len, U32 num_blocks, U32 lba_lo, U32 lba_hi) +{ + U8 opcode = 0; + U8 flagvals = 0; + U8 groupnum = 0; + U8 control = 0; + + switch (cdb_len) { + case 6: + opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16; + control = cdb[5]; + break; + case 10: + opcode = + cdb[0] == READ_10 ? READ_16 : WRITE_16; + flagvals = cdb[1]; + groupnum = cdb[6]; + control = cdb[9]; + break; + case 12: + opcode = + cdb[0] == READ_12 ? READ_16 : WRITE_16; + flagvals = cdb[1]; + groupnum = cdb[10]; + control = cdb[11]; + break; + default: + break; + } + + cdb[0] = opcode; + cdb[1] = flagvals; + cdb[14] = groupnum; + cdb[15] = control; + + cdb[9] = (U8)(lba_lo & 0xff); + cdb[8] = (U8)((lba_lo >> PS3_SHIFT_BYTE) & 0xff); + cdb[7] = (U8)((lba_lo >> PS3_SHIFT_WORD) & 0xff); + cdb[6] = (U8)((lba_lo >> PS3_SHIFT_3BYTE) & 0xff); + cdb[5] = (U8)(lba_hi & 0xff); + cdb[4] = (U8)((lba_hi >> PS3_SHIFT_BYTE) & 0xff); + cdb[3] = (U8)((lba_hi >> PS3_SHIFT_WORD) & 0xff); + cdb[2] = (U8)((lba_hi >> PS3_SHIFT_3BYTE) & 0xff); + + cdb[13] = (U8)(num_blocks & 0xff); + cdb[12] = (U8)((num_blocks >> PS3_SHIFT_BYTE) & 0xff); + cdb[11] = (U8)((num_blocks >> PS3_SHIFT_WORD) & 0xff); + cdb[10] = (U8)((num_blocks >> PS3_SHIFT_3BYTE) & 0xff); +} + +void ps3_scsih_cdb_rebuild(U8 *cdb, U16 cdb_len, U32 num_blocks, + U32 lba_lo, U32 lba_hi) +{ + if (unlikely((cdb_len < 16) && (((U64)lba_hi << PS3_SHIFT_DWORD | lba_lo) > 0xffffffff))) { + ps3_convert_to_cdb16(cdb, cdb_len, num_blocks, lba_lo, lba_hi); + goto l_out; + } + + switch (cdb[0]) { + case READ_6: + case WRITE_6: + ps3_scsih_cdb_rw6_rebuild( cdb, num_blocks, lba_lo); + break; + + case READ_10: + case WRITE_10: + case VERIFY: + case WRITE_VERIFY: + case WRITE_SAME: + case PRE_FETCH: + case SYNCHRONIZE_CACHE: + ps3_scsih_cdb_rw10_rebuild( cdb, num_blocks, lba_lo); + break; + + case READ_12: + case WRITE_12: + case VERIFY_12: + case WRITE_VERIFY_12: + ps3_scsih_cdb_rw12_rebuild( cdb, num_blocks, lba_lo); + break; + + case READ_16: + case WRITE_16: + case VERIFY_16: + case PS3_WRITE_VERIFY_16: + case WRITE_SAME_16: + case ORWRITE_16: + case PRE_FETCH_16: + case SYNCHRONIZE_CACHE_16: + ps3_scsih_cdb_rw16_rebuild( cdb, num_blocks, lba_lo, lba_hi); + break; + + case VARIABLE_LENGTH_CMD: + ps3_scsih_cdb_rw32_rebuild(cdb, num_blocks, lba_lo, lba_hi); + break; + + case COMPARE_AND_WRITE: + ps3_cdb_comp_and_write_rebuild(cdb, num_blocks, lba_lo, lba_hi); + break; + + case WRITE_ATOMIC_16: + case WRITE_STREAM_16: + ps3_scsih_atomic_stream_16_rebuild(cdb, num_blocks, lba_lo, lba_hi); + break; + + case WRITE_LONG: + ps3_scsih_cdb_write_long10_rebuild(cdb, lba_lo); + break; + + case SERVICE_ACTION_OUT_16: + ps3_scsih_service_16_rebuild(cdb, lba_lo, lba_hi); + break; + + default: + break; + } +l_out: + return; +} + +void ps3_scsih_lba_parse(const U8 *cdb, U64 *lba) +{ + U32 num_blocks = 0; + U32 lba_lo = 0; + U32 lba_hi = 0; + Bool is_need_split = PS3_FALSE; + + ps3_scsih_cdb_parse(cdb, &num_blocks, &lba_lo, &lba_hi, &is_need_split); + *lba = ((U64)lba_hi << PS3_SHIFT_DWORD) | lba_lo; +} + +void ps3_scsih_len_parse(const U8 *cdb, U32 *len) +{ + U32 num_blocks = 0; + U32 lba_lo = 0; + U32 lba_hi = 0; + Bool is_need_split = PS3_FALSE; + + ps3_scsih_cdb_parse(cdb, &num_blocks, &lba_lo, &lba_hi, &is_need_split); + *len = num_blocks; +} + diff --git a/drivers/scsi/ps3stor/ps3_scsih_cmd_parse.h b/drivers/scsi/ps3stor/ps3_scsih_cmd_parse.h new file mode 100644 index 0000000000000000000000000000000000000000..5add446d624ab8829d921e9f3b46c3c686be8235 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsih_cmd_parse.h @@ -0,0 +1,183 @@ +#ifndef _PS3_SCSIH_CMD_PARSE_H_ +#define _PS3_SCSIH_CMD_PARSE_H_ + +#include "ps3_err_def.h" + +#include "ps3_inner_data.h" +#include "ps3_driver_log.h" + +#ifndef _WINDOWS +#include +#else + +#define VARIABLE_LENGTH_CMD 0x7f +#define SYNCHRONIZE_CACHE_16 0x91 +#define SYNCHRONIZE_CACHE 0x35 + +#define FORMAT_UNIT 0x04 +#define REASSIGN_BLOCKS 0x07 +#define READ_6 0x08 +#define WRITE_6 0x0a +#define READ_10 0x28 +#define WRITE_10 0x2a +#define WRITE_VERIFY 0x2e +#define VERIFY 0x2f +#define PRE_FETCH 0x34 +#define SYNCHRONIZE_CACHE 0x35 +#define WRITE_LONG 0x3f +#define WRITE_SAME 0x41 +#define UNMAP 0x42 +#define VARIABLE_LENGTH_CMD 0x7f +#define READ_12 0xa8 +#define WRITE_12 0xaa +#define WRITE_VERIFY_12 0xae +#define VERIFY_12 0xaf +#define EXTENDED_COPY 0x83 +#define READ_16 0x88 +#define COMPARE_AND_WRITE 0x89 +#define WRITE_16 0x8a +#define WRITE_ATTRIBUTE 0x8d +#define PS3_WRITE_VERIFY_16 0x8e +#define VERIFY_16 0x8f +#define SYNCHRONIZE_CACHE_16 0x91 +#define WRITE_SAME_16 0x93 +#define SERVICE_ACTION_IN_16 0x9e +#define SERVICE_ACTION_OUT_16 0x9f +#define READ_32 0x09 +#define VERIFY_32 0x0a +#define WRITE_32 0x0b +#define PS3_WRITE_VERIFY_32 0x0c +#define WRITE_SAME_32 0x0d + +#endif + +#define PS3_SCSI_CONFLICT_CHECK 0x80 +#define PS3_SCSI_CONFLICT_CHECK_TEST(type) ((type) & PS3_SCSI_CONFLICT_CHECK) +#define PS3_SCSI_CMD_TYPE(type) ((type) & 0x7F) + +enum ps3_scsi_cmd_type { + PS3_SCSI_CMD_TYPE_UNKOWN, + PS3_SCSI_CMD_TYPE_READ, + PS3_SCSI_CMD_TYPE_WRITE, + PS3_SCSI_CMD_TYPE_RW, + PS3_SCSI_CMD_TYPE_UNMAP, + PS3_SCSI_CMD_TYPE_NORW, + PS3_SCSI_CMD_TYPE_COUNT +}; + +enum { + PS3_ATA_OPC_READ_FPDMA = 0x60, + PS3_ATA_OPC_WRITE_FPDMA =0x61, + PS3_SATA_DEV_REG_DEFAULT = 0x40, + PS3_NCQ_FUA_OFFSET_IN_DEVICE_REG = 7, +}; + +#define PS3_SERVICE_ACTION32(cdb) (*(cdb + 9) | (*(cdb + 8) << PS3_SHIFT_BYTE)) +#define PS3_SERVICE_ACTION16_TO_OPCODE(cdb) (*(cdb + 1) & 0x1f) + +static inline void ps3_scsih_cdb_opcode_get(const U8 *cdb, + U8 *opcode, U16 *sub_opcode) +{ + *opcode = cdb[0]; + switch(cdb[0]) { + case VARIABLE_LENGTH_CMD: + *sub_opcode = PS3_SERVICE_ACTION32(cdb); + break; + case SERVICE_ACTION_IN_16: + case SERVICE_ACTION_OUT_16: + *sub_opcode = (U16)PS3_SERVICE_ACTION16_TO_OPCODE(cdb); + break; + default: + *sub_opcode = 0; + break; + } +} + +#ifndef U32_HIGH_LOW_TO_U64 +#define U32_HIGH_LOW_TO_U64(u64_high, u64_low) \ + (((U64)(u64_high) << 32) | (u64_low)) +#endif + +Bool ps3_scsih_is_rw_type(U8 type); + +U8 ps3_scsih_cdb_rw_type_get(const U8 *cdb); + +void ps3_scsih_cdb_parse(const U8 *cdb, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi, Bool *is_need_split); + +static inline Bool ps3_scsih_cdb_is_rw_cmd(const U8 *cdb) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(cdb)); + return ps3_scsih_is_rw_type(type); +} + +static inline Bool ps3_scsih_is_read_cmd(U8 type) +{ + return (type == PS3_SCSI_CMD_TYPE_READ); +} + +static inline Bool ps3_scsih_is_write_cmd(U8 type) +{ + Bool ret = PS3_FALSE; + + switch (type) + { + case PS3_SCSI_CMD_TYPE_WRITE: + case PS3_SCSI_CMD_TYPE_UNMAP: + case PS3_SCSI_CMD_TYPE_RW: + ret = PS3_TRUE; + goto l_out; + default: + ret = PS3_FALSE; + goto l_out; + } +l_out: + return ret; +} +static inline Bool ps3_scsih_is_sync_cache(const U8 *cdb) +{ + return cdb[0] == SYNCHRONIZE_CACHE || cdb[0] == SYNCHRONIZE_CACHE_16; +} + +void ps3_scsih_lba_parse(const U8 *cdb, U64 *lba); + +void ps3_scsih_len_parse(const U8 *cdb, U32 *len); + +S32 ps3_scsih_cdb_opts_parse(struct ps3_cmd *cmd); + +void ps3_scsih_cdb_rebuild(U8 *cdb, U16 cdb_len, U32 num_blocks, U32 lba_lo, U32 lba_hi); + +static inline Bool ps3_scsih_cdb_is_read_cmd(const U8 *cdb) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(cdb)); + return ps3_scsih_is_read_cmd(type); +} + +static inline Bool ps3_scsih_cdb_is_write_cmd(const U8 *cdb) +{ + U8 type = PS3_SCSI_CMD_TYPE(ps3_scsih_cdb_rw_type_get(cdb)); + return ps3_scsih_is_write_cmd(type); +} + +Bool ps3_scsih_is_protocal_rw(const U8 *cdb); + +Bool ps3_scsih_rw_cmd_is_need_split_hba(struct ps3_cmd *cmd); + +Bool ps3_scsih_rw_cmd_is_need_split_raid(struct ps3_cmd *cmd); + +static inline void ps3_scsih_unmap_desc_parse(const U8 *desc, U32 *num_blocks, + U32 *lba_lo, U32 *lba_hi) +{ + *lba_lo = ((U32)desc[4] << PS3_SHIFT_3BYTE) | + ((U32)desc[5] << PS3_SHIFT_WORD) | + ((U32) desc[6] << PS3_SHIFT_BYTE) | (U32)desc[7]; + *lba_hi = ((U32)desc[0] << PS3_SHIFT_3BYTE) | + ((U32)desc[1] << PS3_SHIFT_WORD) | + ((U32)desc[2] << PS3_SHIFT_BYTE) | (U32)desc[3]; + *num_blocks = ((U32)desc[8] << PS3_SHIFT_3BYTE) | + ((U32)desc[9] << PS3_SHIFT_WORD) | + ((U32)desc[10] << PS3_SHIFT_BYTE) | (U32)desc[11]; + return; +} + +#endif diff --git a/drivers/scsi/ps3stor/ps3_scsih_raid_engine.c b/drivers/scsi/ps3stor/ps3_scsih_raid_engine.c new file mode 100644 index 0000000000000000000000000000000000000000..9e63e076825b2e75d65f7426c94559d3215f1053 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsih_raid_engine.c @@ -0,0 +1,1405 @@ + +#ifndef _WINDOWS +#include +#include +#else +#include "ps3_def.h" +#endif + +#include "ps3_scsih_raid_engine.h" +#include "ps3_instance_manager.h" +#include "ps3_meta.h" +#include "ps3_scsih_cmd_parse.h" +#include "ps3_driver_log.h" +#include "ps3_util.h" +#include "ps3_module_para.h" +#include "ps3_scsih.h" + +#define LBA_TO_STRIPE_INDEX(u64_lba, u32_stripe_data_size, u64_stripe_idx) \ + (u64_stripe_idx) = (u64_lba) / (u32_stripe_data_size) + +#define LBA_TO_STRIPE_OFFSET(u64_lba, u32_stripe_data_size, u32_stripe_offset) \ + (u32_stripe_offset) = (u64_lba) % (u32_stripe_data_size) + +#define SPANNO_DISKIDX_TO_PHYDISKID(vd_entry, span_idx, span_disk_idx) \ + (vd_entry)->span[(span_idx)].extent[(span_disk_idx)].phyDiskID.ps3Dev.phyDiskID + +#define VD_SPAN_PD_NUM(vd_entry, span_idx) \ + (vd_entry)->span[(span_idx)].spanPdNum + +#define STRIP_SIZE_MASK(strip_size) ((strip_size) - 1) + +#define RAID660_GET_PQ_SPINDLENO(stripe_idx, phy_disk_count, q_disk_idx) \ +do { \ + if (ps3_is_power_of_2(phy_disk_count)){ \ + (q_disk_idx) = (stripe_idx) & ((phy_disk_count) - 1); \ + } else { \ + (q_disk_idx) = (stripe_idx) % (phy_disk_count); \ + } \ + (q_disk_idx) = (phy_disk_count) - (q_disk_idx) - 1; \ +} while (0); + +#define PS3_R1X_HDD_MAX_SWAP_CNT_1 (64) +#define PS3_R1X_HDD_MAX_SWAP_CNT_2 (32) +#define PS3_R1X_SSD_MAX_SWAP_CNT_1 (32) +#define PS3_R1X_SSD_MAX_SWAP_CNT_2 (16) +#define PS3_R1X_SWAP_VD_MEMBER_CNT (8) +#define PS3_R1X_RB_DIFF_CMDS_DEFAULT (4) +#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) +#define PS3_R1X_RB_INFO_INDEX(span, span_disk_idx) \ + ((span) * PS3_MAX_PD_COUNT_IN_SPAN + (span_disk_idx) + 1) +U32 g_ps3_r1x_rb_diff_cmds = PS3_R1X_RB_DIFF_CMDS_DEFAULT; + +static inline Bool ps3_is_power_of_2(U32 n) +{ + return (Bool)(n != 0 && ((n & (n - 1)) == 0)); +} + +static inline Bool ps3_vd_entry_valid_check(const struct PS3VDEntry *vd_entry) +{ + Bool ret = PS3_DRV_TRUE; + + if (unlikely(vd_entry == NULL)) { + ret = PS3_DRV_FALSE; + goto l_out; + } + + if (unlikely(!ps3_is_power_of_2(vd_entry->stripSize))) { + ret = PS3_DRV_FALSE; + goto l_out; + } + + if (unlikely(!vd_entry->stripeDataSize)) { + ret = PS3_DRV_FALSE; + goto l_out; + } +l_out: + return ret; +} + +Bool ps3_scsih_is_same_strip(const struct PS3VDEntry *vd_entry, U32 vlba_lo, U32 lba_length) +{ + if (unlikely(!ps3_vd_entry_valid_check(vd_entry))) { + return PS3_DRV_FALSE; + } + + if ( (vd_entry->stripSize - (vlba_lo & STRIP_SIZE_MASK(vd_entry->stripSize)) ) + >= lba_length ) { + return PS3_DRV_TRUE; + } else { + return PS3_DRV_FALSE; + } +} + +static void ps3_r0_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + + cmd->io_attr.span_idx = 0; + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; +} + +static void ps3_r1x_rand_read_target_pd_calc(struct ps3_cmd *cmd, U32 span_idx, + U32 span_pd_idx, U32 span_pd_back_idx) +{ + struct ps3_r1x_read_balance_info *rb_info = NULL; + struct ps3_scsi_priv_data *priv_data = NULL; + U64 vlba = 0; + U32 outstanding0 = 0; + U32 outstanding1 = 0; + U64 diff0 = 0; + U64 diff1 = 0; + U32 pd0 = 0; + U32 pd1 = 0; + U32 target_pd = 0; + + if (!cmd->r1x_read_pd) { + priv_data = scsi_device_private_data(cmd->scmd); + rb_info = priv_data->r1x_rb_info; + vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + pd0 = PS3_R1X_RB_INFO_INDEX(span_idx, span_pd_idx); + pd1 = PS3_R1X_RB_INFO_INDEX(span_idx, span_pd_back_idx); + outstanding0 = ps3_atomic_read(&rb_info->scsi_outstanding_cmds[pd0]); + outstanding1 = ps3_atomic_read(&rb_info->scsi_outstanding_cmds[pd1]); + + if (outstanding0 > outstanding1 + g_ps3_r1x_rb_diff_cmds) { + target_pd = pd1; + } else if (outstanding1 > outstanding0 + g_ps3_r1x_rb_diff_cmds) { + target_pd = pd0; + } else { + diff0 = ABS_DIFF(vlba, rb_info->last_accessed_block[pd0]); + diff1 = ABS_DIFF(vlba, rb_info->last_accessed_block[pd1]); + target_pd = (diff0 <= diff1 ? pd0 : pd1); + } + + if (target_pd == pd0) { + cmd->io_attr.span_pd_idx = (U8)span_pd_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_pd_back_idx; + } else { + cmd->io_attr.span_pd_idx = (U8)span_pd_back_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_pd_idx; + } + + cmd->r1x_read_pd = target_pd; + rb_info->last_accessed_block[target_pd] = vlba + cmd->io_attr.num_blocks; + ps3_atomic_inc(&rb_info->scsi_outstanding_cmds[target_pd]); + } +} + +static void ps3_r1x_seq_read_target_pd_calc(struct ps3_cmd *cmd, U32 span_idx, + U32 span_pd_idx, U32 span_pd_back_idx) +{ + struct ps3_r1x_read_balance_info *rb_info = NULL; + struct ps3_scsi_priv_data *priv_data = NULL; + U64 vlba = 0; + U32 outstanding0 = 0; + U32 outstanding1 = 0; + U64 diff0 = 0; + U64 diff1 = 0; + U32 pd0 = 0; + U32 pd1 = 0; + U32 target_pd = 0; + + if (!cmd->r1x_read_pd) { + priv_data = scsi_device_private_data(cmd->scmd); + rb_info = priv_data->r1x_rb_info; + vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + pd0 = PS3_R1X_RB_INFO_INDEX(span_idx, span_pd_idx); + pd1 = PS3_R1X_RB_INFO_INDEX(span_idx, span_pd_back_idx); + outstanding0 = ps3_atomic_read(&rb_info->scsi_outstanding_cmds[pd0]); + outstanding1 = ps3_atomic_read(&rb_info->scsi_outstanding_cmds[pd1]); + + if (outstanding0 == 0 && outstanding1 != 0) { + target_pd = pd0; + } else if (outstanding0 != 0 && outstanding1 == 0) { + target_pd = pd1; + } else { + diff0 = ABS_DIFF(vlba, rb_info->last_accessed_block[pd0]); + diff1 = ABS_DIFF(vlba, rb_info->last_accessed_block[pd1]); + target_pd = (diff0 <= diff1 ? pd0 : pd1); + } + + if (target_pd == pd0) { + cmd->io_attr.span_pd_idx = (U8)span_pd_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_pd_back_idx; + } else { + cmd->io_attr.span_pd_idx = (U8)span_pd_back_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_pd_idx; + } + + cmd->r1x_read_pd = target_pd; + rb_info->last_accessed_block[target_pd] = vlba + cmd->io_attr.num_blocks; + ps3_atomic_inc(&rb_info->scsi_outstanding_cmds[target_pd]); + } +} + +static void ps3_r1_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + cmd->io_attr.plba = vd_entry->startLBA + vlba; + cmd->io_attr.span_idx = 0; + cmd->io_attr.plba_back = cmd->io_attr.plba; + + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (cmd->io_attr.seq_flag == SCSI_RW_RANDOM_CMD) { + ps3_r1x_rand_read_target_pd_calc(cmd, 0, 0, 1); + } else { + ps3_r1x_seq_read_target_pd_calc(cmd, 0, 0, 1); + } + } else { + cmd->io_attr.span_pd_idx = 0; + cmd->io_attr.span_pd_idx_p = 1; + } + + LOG_DEBUG("hno:%u chl:%u id:%u rw=%u, span_pd_idx=%u, span_pd_idx_p=%u\n", + PS3_HOST(cmd->instance), cmd->scmd->device->channel, cmd->scmd->device->id, + cmd->io_attr.rw_flag, cmd->io_attr.span_pd_idx, cmd->io_attr.span_pd_idx_p); +} + +static void ps3_r5_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_parity_disk_idx = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + if (ps3_is_power_of_2(vd_entry->physDrvCnt)) { + span_parity_disk_idx = stripe_idx & (vd_entry->physDrvCnt - 1); + } else { + span_parity_disk_idx = stripe_idx % vd_entry->physDrvCnt; + } + span_parity_disk_idx = vd_entry->physDrvCnt - span_parity_disk_idx - 1; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_parity_disk_idx + span_data_disk_idx + 1; + if ( span_data_disk_idx >= vd_entry->physDrvCnt) { + span_data_disk_idx -= vd_entry->physDrvCnt; + } + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + + cmd->io_attr.span_idx = 0; + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_parity_disk_idx; + LOG_DEBUG("vlba:0x%llx plba:0x%llx startLBA:0x%llx stripe_idx:%llu" + "strip_size_shift:%u stripe_offset:%u span_pd_indx:%u\n", + vlba, cmd->io_attr.plba, vd_entry->startLBA, stripe_idx, + strip_size_shift, stripe_offset, cmd->io_attr.span_pd_idx); +} + +static void ps3_r6_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_q_disk_idx = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + RAID660_GET_PQ_SPINDLENO(stripe_idx, vd_entry->physDrvCnt, span_q_disk_idx); + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_data_disk_idx + span_q_disk_idx + 1; + if ( span_data_disk_idx >= vd_entry->physDrvCnt) { + span_data_disk_idx -= vd_entry->physDrvCnt; + } + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + + cmd->io_attr.span_idx = 0; + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; + cmd->io_attr.span_pd_idx_q = (U8)span_q_disk_idx; + if(0 != span_q_disk_idx){ + cmd->io_attr.span_pd_idx_p = span_q_disk_idx - 1; + } else{ + cmd->io_attr.span_pd_idx_p = vd_entry->physDrvCnt - 1; + } +} + +static void ps3_r10_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_data_disk_back_idx = 0; + U32 span_idx = 0; + U8 span_pd_num = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + while(stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_data_disk_idx << 1; + span_pd_num = VD_SPAN_PD_NUM(vd_entry, span_idx); + if ( span_data_disk_idx > span_pd_num ) { + span_data_disk_idx -= span_pd_num; + span_data_disk_back_idx = + ((span_data_disk_idx+1) == span_pd_num)? + 0 :(span_data_disk_idx+1); + stripe_idx = (stripe_idx << 1) + 1; + } else { + if (span_pd_num & 1) { + stripe_idx = stripe_idx << 1; + span_data_disk_back_idx = + ((span_data_disk_idx+1) == span_pd_num)? + 0 :(span_data_disk_idx+1); + } else { + span_data_disk_back_idx = span_data_disk_idx + 1; + } + } + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + cmd->io_attr.plba_back = cmd->io_attr.plba; + if (span_data_disk_back_idx == 0) { + cmd->io_attr.plba_back += vd_entry->stripSize; + } + cmd->io_attr.span_idx = (U8)span_idx; + + if (!(span_pd_num & 1) && ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (cmd->io_attr.seq_flag == SCSI_RW_RANDOM_CMD) { + ps3_r1x_rand_read_target_pd_calc(cmd, span_idx, + span_data_disk_idx, span_data_disk_back_idx); + } else { + ps3_r1x_seq_read_target_pd_calc(cmd, span_idx, + span_data_disk_idx, span_data_disk_back_idx); + } + } else { + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_data_disk_back_idx; + } + + LOG_DEBUG("hno:%u tid:0x%llx chl:%u id:%u " + "odd physDrvCnt:%d rw=%u span_pd_idx=%u-plba:0x%llx span_pd_idx_p=%u-bplba:0x%llx stripe_offset=0x%x\n", + PS3_HOST(cmd->instance), cmd->trace_id, + cmd->scmd->device->channel, cmd->scmd->device->id, + vd_entry->physDrvCnt & 1, + cmd->io_attr.rw_flag, cmd->io_attr.span_pd_idx, + cmd->io_attr.plba, cmd->io_attr.span_pd_idx_p, + cmd->io_attr.plba_back, stripe_offset); +} + +static void ps3_r1e_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_data_disk_back_idx = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_data_disk_idx << 1; + if ( span_data_disk_idx > vd_entry->physDrvCnt ) { + span_data_disk_idx -= vd_entry->physDrvCnt; + span_data_disk_back_idx = + ((span_data_disk_idx+1) == vd_entry->physDrvCnt)? + 0 :(span_data_disk_idx+1) ; + stripe_idx = (stripe_idx << 1) + 1; + } else { + if (vd_entry->physDrvCnt & 1) { + stripe_idx = stripe_idx << 1; + span_data_disk_back_idx = + ((span_data_disk_idx+1) == vd_entry->physDrvCnt)? + 0 :(span_data_disk_idx+1) ; + } else { + span_data_disk_back_idx = span_data_disk_idx + 1; + } + } + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + cmd->io_attr.plba_back = cmd->io_attr.plba; + if (span_data_disk_back_idx == 0) { + cmd->io_attr.plba_back += vd_entry->stripSize; + } + cmd->io_attr.span_idx = 0; + + if (!(vd_entry->physDrvCnt & 1) && ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (cmd->io_attr.seq_flag == SCSI_RW_RANDOM_CMD) { + ps3_r1x_rand_read_target_pd_calc(cmd, 0, span_data_disk_idx, span_data_disk_back_idx); + } else { + ps3_r1x_seq_read_target_pd_calc(cmd, 0, span_data_disk_idx, span_data_disk_back_idx); + } + } else { + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_data_disk_back_idx; + } + + LOG_DEBUG("hno:%u chl:%u id:%u " + "odd physDrvCnt:%d rw=%u, span_pd_idx=%u, span_pd_idx_p=%u\n", + PS3_HOST(cmd->instance), cmd->scmd->device->channel, cmd->scmd->device->id, + vd_entry->physDrvCnt & 1, cmd->io_attr.rw_flag, + cmd->io_attr.span_pd_idx, cmd->io_attr.span_pd_idx_p); +} + +static void ps3_r00_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_idx = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + while (stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + cmd->io_attr.span_idx = (U8)span_idx; + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; +} + +static void ps3_r50_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_parity_disk_idx = 0; + U32 span_idx = 0; + U8 span_pd_num = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + while (stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + + span_pd_num = VD_SPAN_PD_NUM(vd_entry, span_idx); + if (ps3_is_power_of_2(span_pd_num)) { + span_parity_disk_idx = stripe_idx & (span_pd_num - 1); + } else { + span_parity_disk_idx = stripe_idx % span_pd_num; + } + span_parity_disk_idx = span_pd_num - span_parity_disk_idx - 1; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_parity_disk_idx + span_data_disk_idx + 1; + if ( span_data_disk_idx >= span_pd_num) { + span_data_disk_idx -= span_pd_num; + } + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + cmd->io_attr.span_idx = (U8)span_idx; + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; + cmd->io_attr.span_pd_idx_p = (U8)span_parity_disk_idx; +} + +static void ps3_r60_convert_vlba_to_pd_attr(struct ps3_cmd *cmd) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_q_disk_idx = 0; + U32 span_idx = 0; + U8 span_pd_num = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + while (stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + + span_pd_num = VD_SPAN_PD_NUM(vd_entry, span_idx); + RAID660_GET_PQ_SPINDLENO(stripe_idx, span_pd_num, span_q_disk_idx); + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_data_disk_idx + span_q_disk_idx + 1; + if ( span_data_disk_idx >= span_pd_num) { + span_data_disk_idx -= span_pd_num; + } + + cmd->io_attr.plba = vd_entry->startLBA + + (stripe_idx << strip_size_shift) + + (stripe_offset & STRIP_SIZE_MASK(vd_entry->stripSize)); + cmd->io_attr.span_idx = (U8)span_idx; + cmd->io_attr.span_pd_idx = (U8)span_data_disk_idx; + cmd->io_attr.span_pd_idx_q = (U8)span_q_disk_idx; + if(0 != span_q_disk_idx){ + cmd->io_attr.span_pd_idx_p = span_q_disk_idx - 1; + } else{ + cmd->io_attr.span_pd_idx_p = span_pd_num - 1; + } +} + +static S32 ps3_convert_to_pd_info(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + const struct PS3Extent *extent = &(vd_entry->span[cmd->io_attr.span_idx]. + extent[cmd->io_attr.span_pd_idx]); + + if (extent->state != MIC_PD_STATE_ONLINE) { + LOG_DEBUG("cmd :%u direct check pd:%u state:%s != ONLINE\n", + cmd->index, extent->phyDiskID.ps3Dev.phyDiskID, + getPdStateName((MicPdState_e)extent->state, cmd->instance->is_raid)); + ret = -PS3_ENODEV; + goto l_out; + } + + cmd->io_attr.pd_entry = ps3_dev_mgr_lookup_pd_info_by_id(cmd->instance, + extent->phyDiskID.ps3Dev.phyDiskID); + if (unlikely(cmd->io_attr.pd_entry == NULL)) { + LOG_FILE_ERROR("host_no:%u trace_id:0x%llx idspan_id:%d " + "span_pd_idx:%d pd[%u:%u:%u], pd_entry == NULL\n", + PS3_HOST(cmd->instance), + cmd->trace_id, + cmd->io_attr.span_idx, + cmd->io_attr.span_pd_idx, + extent->phyDiskID.ps3Dev.softChan, + extent->phyDiskID.ps3Dev.devID, + extent->phyDiskID.ps3Dev.phyDiskID); + ret = -PS3_ENODEV; + goto l_out; + } + + if (!ps3_is_r1x_write_cmd(cmd)) { + goto l_out; + } + + extent = &(vd_entry->span[cmd->io_attr.span_idx]. + extent[cmd->io_attr.span_pd_idx_p]); + + if (extent->state != MIC_PD_STATE_ONLINE) { + LOG_DEBUG("cmd :%u direct check pd:%u state:%s != ONLINE\n", + cmd->index, extent->phyDiskID.ps3Dev.phyDiskID, + getPdStateName((MicPdState_e)extent->state, cmd->instance->is_raid)); + ret = -PS3_ENODEV; + goto l_out; + } + + cmd->io_attr.peer_pd_entry = ps3_dev_mgr_lookup_pd_info_by_id( + cmd->instance, extent->phyDiskID.ps3Dev.phyDiskID); + if (unlikely(cmd->io_attr.peer_pd_entry == NULL)) { + LOG_ERROR_LIM("host_no:%u trace_id:0x%llx idspan_id:%d " + "span_pd_idx:%d peer_pd[%u:%u:%u], pd_entry == NULL\n", + PS3_HOST(cmd->instance), + cmd->trace_id, + cmd->io_attr.span_idx, + cmd->io_attr.span_pd_idx, + extent->phyDiskID.ps3Dev.softChan, + extent->phyDiskID.ps3Dev.devID, + extent->phyDiskID.ps3Dev.phyDiskID); + ret = -PS3_ENODEV; + goto l_out; + } + +l_out: + return ret; +} + +S32 ps3_scsih_vlba_to_pd_calc(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + if ( unlikely(!ps3_vd_entry_valid_check(cmd->io_attr.vd_entry)) ) { + ret = -PS3_FAILED; + LOG_ERROR_LIM("trace_id:0x%llx host_no:%u vd entry is invalid\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + switch(cmd->io_attr.vd_entry->raidLevel) { + case RAID0: + ps3_r0_convert_vlba_to_pd_attr(cmd); + break; + case RAID1: + ps3_r1_convert_vlba_to_pd_attr(cmd); + break; + case RAID5: + ps3_r5_convert_vlba_to_pd_attr(cmd); + break; + case RAID6: + ps3_r6_convert_vlba_to_pd_attr(cmd); + break; + case RAID10: + ps3_r10_convert_vlba_to_pd_attr(cmd); + break; + case RAID1E: + ps3_r1e_convert_vlba_to_pd_attr(cmd); + break; + case RAID00: + ps3_r00_convert_vlba_to_pd_attr(cmd); + break; + case RAID50: + ps3_r50_convert_vlba_to_pd_attr(cmd); + break; + case RAID60: + ps3_r60_convert_vlba_to_pd_attr(cmd); + break; + default: + ret = -PS3_FAILED; + LOG_ERROR_LIM("trace_id:0x%llx host_no:%u vd level:%d is illegal\n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->io_attr.vd_entry->raidLevel); + goto l_out; + } + +l_out: + return ret; +} + +Bool ps3_scsih_vd_acc_att_build(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + PS3VDAccAttr_s *acc_attr = &cmd->req_frame->frontendReq.vdAccAttr; + static unsigned long j; + ret = ps3_scsih_vlba_to_pd_calc(cmd); + if (ret != PS3_SUCCESS) { + LOG_WARN_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "trace_id:0x%llx host_no:%u vlba calc NOK\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + acc_attr->isAccActive = 0; + goto l_out; + } + + acc_attr->isAccActive = 1; + acc_attr->firstPdStartLba = cmd->io_attr.plba; + acc_attr->firstSpanNo = cmd->io_attr.span_idx; + acc_attr->fisrtSeqInSpan = cmd->io_attr.span_pd_idx; + acc_attr->secondSeqInSapn = cmd->io_attr.span_pd_idx_p; + acc_attr->thirdSeqInSapn = cmd->io_attr.span_pd_idx_q; +l_out: + return (acc_attr->isAccActive == 1); +} + +S32 ps3_scsih_vd_rw_io_to_pd_calc(struct ps3_cmd *cmd) +{ + S32 ret = PS3_SUCCESS; + + ret = ps3_scsih_vlba_to_pd_calc(cmd); + if (ret != PS3_SUCCESS) { + LOG_WARN_LIM("trace_id:0x%llx host_no:%u vlba calc NOK\n", + cmd->trace_id, PS3_HOST(cmd->instance)); + goto l_out; + } + + ret = ps3_convert_to_pd_info(cmd); + +l_out: + return ret; +} + +static void ps3_update_cmd_target_pd(struct ps3_cmd *cmd, U16 disk_id) +{ + U16 i = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_instance *instance = cmd->instance; + if (unlikely(cmd->target_pd_count >= PS3_QOS_MAX_PD_IN_VD)) { + LOG_INFO("host_no:%u CFID:%u did:%u target pd count %u check NOK\n", + PS3_HOST(instance), cmd->index, disk_id, cmd->target_pd_count); + goto l_out; + } + if (disk_id > instance->ctrl_info.maxPdCount ) { + LOG_DEBUG("disk_id is error.host_no:%u CFID:%u did:%u\n", + PS3_HOST(instance), cmd->index, disk_id); + goto l_out; + } + + qos_pd_mgr = &instance->qos_context.pd_ctx.qos_pd_mgrs[disk_id]; + if (ps3_atomic_read(&qos_pd_mgr->valid) != 1) { + LOG_DEBUG("qos pd is invalid. host_no:%u CFID:%u did:%u\n", + PS3_HOST(instance), cmd->index, disk_id); + goto l_out; + } + + for (i = 0; i < cmd->target_pd_count; i++) { + if (cmd->target_pd[i].flat_disk_id == disk_id) { + cmd->target_pd[i].strip_count++; + goto l_out; + } + } + + cmd->target_pd[cmd->target_pd_count].flat_disk_id = disk_id; + cmd->target_pd[cmd->target_pd_count].strip_count = 1; + cmd->target_pd_count++; +l_out: + return; +} + +static void ps3_r0_vlba_to_pd(struct ps3_cmd *cmd, U64 lba) +{ + U32 stripe_offset = 0; + U32 strip_size_shift = 0; + U8 span_idx = 0; + U32 span_disk_idx = 0; + U16 disk_id= 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + LBA_TO_STRIPE_OFFSET(lba, vd_entry->stripeDataSize, stripe_offset); + span_disk_idx = stripe_offset >> strip_size_shift; + if (vd_entry->span[span_idx].extent[span_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } +} + +static void ps3_r0_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + Bool first_strip = PS3_TRUE; + + while (left_len > 0) { + ps3_r0_vlba_to_pd(cmd, vlba); + if (first_strip) { + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + first_strip = PS3_FALSE; + } else { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + } + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r1_target_pd_get(struct ps3_cmd *cmd) +{ + U8 span_idx = 0; + U16 span_disk_idx = 0; + U16 disk_id= 0; + const struct PS3Extent *extent = NULL; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + Bool primary_valid = PS3_FALSE; + + ps3_scsih_vlba_to_pd_calc(cmd); + span_disk_idx = cmd->io_attr.span_pd_idx; + extent = &vd_entry->span[span_idx].extent[span_disk_idx]; + if (extent->state == MIC_PD_STATE_ONLINE) { + disk_id = extent->phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + primary_valid = PS3_TRUE; + } + + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) || !primary_valid) { + span_disk_idx = cmd->io_attr.span_pd_idx_p; + extent = &vd_entry->span[span_idx].extent[span_disk_idx]; + if (extent->state == MIC_PD_STATE_ONLINE) { + disk_id = extent->phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } + } +} + +static void ps3_r00_vlba_to_pd(struct ps3_cmd *cmd, U64 lba) +{ + U32 stripe_offset = 0; + U32 strip_size_shift = 0; + U8 span_idx = 0; + U32 span_disk_idx = 0; + U16 disk_id= 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + LBA_TO_STRIPE_OFFSET(lba, vd_entry->stripeDataSize, stripe_offset); + while (stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + span_disk_idx = stripe_offset >> strip_size_shift; + if (vd_entry->span[span_idx].extent[span_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } +} + +static void ps3_r00_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + Bool first_strip = PS3_TRUE; + + while (left_len > 0) { + ps3_r00_vlba_to_pd(cmd, vlba); + if (first_strip) { + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + first_strip = PS3_FALSE; + } else { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + } + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r5_vlba_to_pd(struct ps3_cmd *cmd, U64 vlba) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_parity_disk_idx = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U16 disk_id = 0; + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + if (ps3_is_power_of_2(vd_entry->physDrvCnt)) { + span_parity_disk_idx = stripe_idx & (vd_entry->physDrvCnt - 1); + } else { + span_parity_disk_idx = stripe_idx % vd_entry->physDrvCnt; + } + span_parity_disk_idx = vd_entry->physDrvCnt - span_parity_disk_idx - 1; + + strip_size_shift = ps3_blocksize_to_shift(vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_parity_disk_idx + span_data_disk_idx + 1; + if (span_data_disk_idx >= vd_entry->physDrvCnt) { + span_data_disk_idx -= vd_entry->physDrvCnt; + } + + if (vd_entry->span[0].extent[span_data_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[0].extent[span_data_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } +} + +static void ps3_r5_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + Bool first_strip = PS3_TRUE; + + while (left_len > 0) { + ps3_r5_vlba_to_pd(cmd, vlba); + if (first_strip) { + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + first_strip = PS3_FALSE; + } else { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + } + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r6_vlba_to_pd(struct ps3_cmd *cmd, U64 vlba) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_q_disk_idx = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U16 disk_id = 0; + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + if (ps3_is_power_of_2(vd_entry->physDrvCnt)){ + span_q_disk_idx = stripe_idx & (vd_entry->physDrvCnt - 1); + } else { + span_q_disk_idx = stripe_idx % vd_entry->physDrvCnt; + } + span_q_disk_idx = (vd_entry->physDrvCnt) - span_q_disk_idx - 1; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_data_disk_idx + span_q_disk_idx + 1; + if ( span_data_disk_idx >= vd_entry->physDrvCnt) { + span_data_disk_idx -= vd_entry->physDrvCnt; + } + + if (vd_entry->span[0].extent[span_data_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[0].extent[span_data_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } +} + +static void ps3_r6_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + + ps3_r6_vlba_to_pd(cmd, vlba); + + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + left_len -= strip_len; + vlba += strip_len; + while (left_len > 0) { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + ps3_r6_vlba_to_pd(cmd, vlba); + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r50_vlba_to_pd(struct ps3_cmd *cmd, U64 vlba) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_parity_disk_idx = 0; + U32 span_idx = 0; + U8 span_pd_num = 0; + U16 disk_id = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + while (stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + + span_pd_num = VD_SPAN_PD_NUM(vd_entry, span_idx); + if (ps3_is_power_of_2(span_pd_num)) { + span_parity_disk_idx = stripe_idx & (span_pd_num - 1); + } else { + span_parity_disk_idx = stripe_idx % span_pd_num; + } + span_parity_disk_idx = span_pd_num - span_parity_disk_idx - 1; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_parity_disk_idx + span_data_disk_idx + 1; + if ( span_data_disk_idx >= span_pd_num) { + span_data_disk_idx -= span_pd_num; + } + + if (vd_entry->span[span_idx].extent[span_data_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_data_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } +} + +static void ps3_r50_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + + ps3_r50_vlba_to_pd(cmd, vlba); + + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + left_len -= strip_len; + vlba += strip_len; + while (left_len > 0) { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + ps3_r50_vlba_to_pd(cmd, vlba); + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r60_vlba_to_pd(struct ps3_cmd *cmd, U64 vlba) +{ + U32 stripe_offset = 0; + U64 stripe_idx = 0; + U32 strip_size_shift = 0; + U32 span_data_disk_idx = 0; + U32 span_q_disk_idx = 0; + U32 span_idx = 0; + U8 span_pd_num = 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U16 disk_id = 0; + + LBA_TO_STRIPE_INDEX(vlba, vd_entry->stripeDataSize, stripe_idx); + LBA_TO_STRIPE_OFFSET(vlba, vd_entry->stripeDataSize, stripe_offset); + + while (stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + + span_pd_num = VD_SPAN_PD_NUM(vd_entry, span_idx); + RAID660_GET_PQ_SPINDLENO(stripe_idx, span_pd_num, span_q_disk_idx); + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + span_data_disk_idx = stripe_offset >> strip_size_shift; + span_data_disk_idx = span_data_disk_idx + span_q_disk_idx + 1; + if ( span_data_disk_idx >= span_pd_num) { + span_data_disk_idx -= span_pd_num; + } + + if (vd_entry->span[span_idx].extent[span_data_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_data_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } +} + +static void ps3_r60_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + + ps3_r60_vlba_to_pd(cmd, vlba); + + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + left_len -= strip_len; + vlba += strip_len; + while (left_len > 0) { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + ps3_r60_vlba_to_pd(cmd, vlba); + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r10_vlba_to_pd(struct ps3_cmd *cmd, U64 lba) +{ + U32 stripe_offset = 0; + U32 strip_size_shift = 0; + U8 span_idx = 0; + U32 span_disk_idx = 0; + U32 span_disk_back_idx = 0; + U16 span_pd_num = 0; + U16 disk_id= 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + Bool primary_valid = PS3_FALSE; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + LBA_TO_STRIPE_OFFSET(lba, vd_entry->stripeDataSize, stripe_offset); + while(stripe_offset >= vd_entry->span[span_idx].spanStripeDataSize) { + stripe_offset -= vd_entry->span[span_idx].spanStripeDataSize; + span_idx++; + } + span_disk_idx = stripe_offset >> strip_size_shift; + span_disk_idx = span_disk_idx << 1; + span_pd_num = VD_SPAN_PD_NUM(vd_entry, span_idx); + if (span_pd_num & 1) { + if (span_disk_idx > span_pd_num ) { + span_disk_idx -= span_pd_num; + } + + if (span_disk_idx + 1 == span_pd_num) { + span_disk_back_idx = 0; + } else { + span_disk_back_idx = span_disk_idx + 1; + } + } else { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (cmd->io_attr.span_pd_idx & 1) { + span_disk_back_idx = span_disk_idx; + span_disk_idx++; + } + + } else { + span_disk_back_idx = span_disk_idx + 1; + } + } + + if (vd_entry->span[span_idx].extent[span_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + primary_valid = PS3_TRUE; + } + + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) || !primary_valid) { + if (vd_entry->span[span_idx].extent[span_disk_back_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_disk_back_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } + } +} + +static void ps3_r10_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + const struct PS3Extent *extent = NULL; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + U16 flat_pd_id = 0; + Bool primary_valid = PS3_FALSE; + U8 span_idx = 0; + U8 span_disk_idx = 0; + + ps3_scsih_vlba_to_pd_calc(cmd); + span_idx = cmd->io_attr.span_idx; + span_disk_idx = cmd->io_attr.span_pd_idx; + extent = &vd_entry->span[span_idx].extent[span_disk_idx]; + if (extent->state == MIC_PD_STATE_ONLINE) { + flat_pd_id = extent->phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, flat_pd_id); + primary_valid = PS3_TRUE; + } + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) || !primary_valid) { + span_disk_idx = cmd->io_attr.span_pd_idx_p; + extent = &vd_entry->span[span_idx].extent[span_disk_idx]; + if (extent->state == MIC_PD_STATE_ONLINE) { + flat_pd_id = extent->phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, flat_pd_id); + } + } + + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + left_len -= strip_len; + vlba += strip_len; + while (left_len > 0) { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + ps3_r10_vlba_to_pd(cmd, vlba); + left_len -= strip_len; + vlba += strip_len; + } +} + +static void ps3_r1e_vlba_to_pd(struct ps3_cmd *cmd, U64 lba) +{ + U32 stripe_offset = 0; + U32 strip_size_shift = 0; + U8 span_idx = 0; + U32 span_disk_idx = 0; + U32 span_disk_back_idx = 0; + U16 disk_id= 0; + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + Bool primary_valid = PS3_FALSE; + + strip_size_shift = ps3_blocksize_to_shift (vd_entry->stripSize); + LBA_TO_STRIPE_OFFSET(lba, vd_entry->stripeDataSize, stripe_offset); + span_disk_idx = stripe_offset >> strip_size_shift; + span_disk_idx = span_disk_idx << 1; + if (vd_entry->physDrvCnt & 1) { + if (span_disk_idx > vd_entry->physDrvCnt) { + span_disk_idx -= vd_entry->physDrvCnt; + } + if (span_disk_idx + 1 == vd_entry->physDrvCnt) { + span_disk_back_idx = 0; + } else { + span_disk_back_idx = span_disk_idx + 1; + } + } else { + if (ps3_scsih_is_read_cmd(cmd->io_attr.rw_flag)) { + if (cmd->io_attr.span_pd_idx & 1) { + span_disk_back_idx = span_disk_idx; + span_disk_idx++; + } + + } else { + span_disk_back_idx = span_disk_idx + 1; + } + } + + if (vd_entry->span[span_idx].extent[span_disk_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_disk_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + primary_valid = PS3_TRUE; + } + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) || !primary_valid) { + if (vd_entry->span[span_idx].extent[span_disk_back_idx].state == MIC_PD_STATE_ONLINE) { + disk_id = vd_entry->span[span_idx].extent[span_disk_back_idx].phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, disk_id); + } + } +} + +static void ps3_r1e_target_pd_get(struct ps3_cmd *cmd) +{ + U64 vlba = U32_HIGH_LOW_TO_U64(cmd->io_attr.lba_hi, cmd->io_attr.lba_lo); + const struct PS3VDEntry *vd_entry = cmd->io_attr.vd_entry; + const struct PS3Extent *extent = NULL; + U32 left_len = cmd->io_attr.num_blocks; + U32 strip_len = 0; + U16 flat_pd_id = 0; + Bool primary_valid = PS3_FALSE; + U8 span_idx = 0; + U8 span_disk_idx = 0; + + ps3_scsih_vlba_to_pd_calc(cmd); + span_idx = cmd->io_attr.span_idx; + span_disk_idx = cmd->io_attr.span_pd_idx; + extent = &vd_entry->span[span_idx].extent[span_disk_idx]; + if (extent->state == MIC_PD_STATE_ONLINE) { + flat_pd_id = extent->phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, flat_pd_id); + primary_valid = PS3_TRUE; + } + if (ps3_scsih_is_write_cmd(cmd->io_attr.rw_flag) || !primary_valid) { + span_disk_idx = cmd->io_attr.span_pd_idx_p; + extent = &vd_entry->span[span_idx].extent[span_disk_idx]; + if (extent->state == MIC_PD_STATE_ONLINE) { + flat_pd_id = extent->phyDiskID.ps3Dev.phyDiskID; + ps3_update_cmd_target_pd(cmd, flat_pd_id); + } + } + + strip_len = vd_entry->stripSize - (vlba & STRIP_SIZE_MASK(vd_entry->stripSize)); + strip_len = PS3_MIN(strip_len, left_len); + left_len -= strip_len; + vlba += strip_len; + while (left_len > 0) { + strip_len = PS3_MIN(left_len, vd_entry->stripSize); + ps3_r1e_vlba_to_pd(cmd, vlba); + left_len -= strip_len; + vlba += strip_len; + } +} + +static inline void ps3_swap_in_array(struct ps3_qos_member_pd_info *arr, U16 i, U16 j) +{ + struct ps3_qos_member_pd_info tmp; + tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; +} + +static void ps3_qos_target_pd_adjust(struct ps3_cmd *cmd) +{ + U16 i = 0; + U16 j = 0; + + for (i = 0; i < cmd->target_pd_count; i++) { + for (j = i + 1; j < cmd->target_pd_count; j++) { + if (cmd->target_pd[i].flat_disk_id > + cmd->target_pd[j].flat_disk_id) { + ps3_swap_in_array(cmd->target_pd, i, j); + } + } + } +} + +void ps3_qos_cmd_member_pd_calc(struct ps3_cmd *cmd) +{ + const struct PS3VDEntry *vd_entry = NULL; + U16 disk_id = 0; + struct ps3_qos_pd_mgr *qos_pd_mgr = NULL; + struct ps3_qos_pd_mgr *qos_peer_pd_mgr = NULL; + static unsigned long j; + if (cmd->io_attr.dev_type == PS3_DEV_TYPE_VD) { + vd_entry = cmd->io_attr.vd_entry; + + if (cmd->cmd_word.direct == PS3_CMDWORD_DIRECT_ADVICE) { + disk_id = PS3_PDID(&cmd->io_attr.pd_entry->disk_pos); + if (ps3_is_r1x_write_cmd(cmd)) { + qos_pd_mgr = &cmd->instance->qos_context.pd_ctx.qos_pd_mgrs[disk_id]; + disk_id = PS3_PDID(&cmd->io_attr.peer_pd_entry->disk_pos); + qos_peer_pd_mgr = &cmd->instance->qos_context.pd_ctx.qos_pd_mgrs[disk_id]; + disk_id = (qos_pd_mgr->pd_quota <= qos_peer_pd_mgr->pd_quota) ? + qos_pd_mgr->disk_id : qos_peer_pd_mgr->disk_id; + } + ps3_update_cmd_target_pd(cmd, disk_id); + } else { + if (!vd_entry->isNvme && !vd_entry->isSsd) { + goto _out; + } + switch(vd_entry->raidLevel) { + case RAID0: + ps3_r0_target_pd_get(cmd); + break; + case RAID1: + ps3_r1_target_pd_get(cmd); + break; + case RAID10: + ps3_r10_target_pd_get(cmd); + break; + case RAID1E: + ps3_r1e_target_pd_get(cmd); + break; + case RAID00: + ps3_r00_target_pd_get(cmd); + break; + case RAID5: + ps3_r5_target_pd_get(cmd); + break; + case RAID6: + ps3_r6_target_pd_get(cmd); + break; + case RAID50: + ps3_r50_target_pd_get(cmd); + break; + case RAID60: + ps3_r60_target_pd_get(cmd); + break; + default: + LOG_ERROR_TIME_LIM(&j, PS3_LOG_LIMIT_INTERVAL_MSEC, "trace_id:0x%llx host_no:%u vd level:%d is illegal\n", + cmd->trace_id, PS3_HOST(cmd->instance), + cmd->io_attr.vd_entry->raidLevel); + } + + ps3_qos_target_pd_adjust(cmd); + } + } else { + ps3_update_cmd_target_pd(cmd, cmd->io_attr.disk_id); + } +_out: + LOG_DEBUG("qos target pd calc. host_no:%u cmd[%u,%u] pd_cnt:%u dev_t:%u diskid:%u\n", + PS3_HOST(cmd->instance), cmd->index, cmd->cmd_word.type, cmd->target_pd_count, + cmd->io_attr.dev_type, cmd->io_attr.disk_id); +} + +U16 ps3_odd_r1x_judge(struct PS3VDEntry *vd_entry) +{ + U16 ret = PS3_IS_SSD_EVEN_R1X_VD; + U8 span_idx = 0; + if (!vd_entry->isSsd) { + ret = PS3_IS_HDD_R1X_VD; + goto l_out; + } + switch (vd_entry->raidLevel) { + case RAID10: + for (; span_idx < vd_entry->spanCount; span_idx++) { + if (VD_SPAN_PD_NUM(vd_entry, span_idx) & 1) { + ret = PS3_IS_SSD_ODD_R1X_VD; + goto l_out; + } + } + break; + case RAID1E: + if (VD_SPAN_PD_NUM(vd_entry, 0) & 1) { + ret = PS3_IS_SSD_ODD_R1X_VD; + goto l_out; + } + break; + default: + ret = PS3_IS_VALID_R1X_VD; + break; + } +l_out: + return ret; +} + diff --git a/drivers/scsi/ps3stor/ps3_scsih_raid_engine.h b/drivers/scsi/ps3stor/ps3_scsih_raid_engine.h new file mode 100644 index 0000000000000000000000000000000000000000..b231a461c21c15a1b9031c0ab2a41410d76f9643 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_scsih_raid_engine.h @@ -0,0 +1,28 @@ + +#ifndef _PS3_SCSIH_RAID_ENGINE_H_ +#define _PS3_SCSIH_RAID_ENGINE_H_ + +#include "ps3_htp.h" +#include "ps3_err_def.h" +#include "ps3_cmd_channel.h" + +enum ps3_odd_r1x_vd_judge_type { + PS3_IS_HDD_R1X_VD, + PS3_IS_SSD_ODD_R1X_VD, + PS3_IS_SSD_EVEN_R1X_VD, + PS3_IS_VALID_R1X_VD +}; + +Bool ps3_scsih_is_same_strip(const struct PS3VDEntry *vd_entry, U32 vlba_lo, U32 lba_length); + +S32 ps3_scsih_vd_rw_io_to_pd_calc(struct ps3_cmd *cmd); + +Bool ps3_scsih_vd_acc_att_build(struct ps3_cmd *cmd); + +S32 ps3_scsih_vlba_to_pd_calc(struct ps3_cmd *cmd); + +void ps3_qos_cmd_member_pd_calc(struct ps3_cmd *cmd); + +U16 ps3_odd_r1x_judge(struct PS3VDEntry *vd_entry); + +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/ps3_trace_id_alloc.c b/drivers/scsi/ps3stor/ps3_trace_id_alloc.c new file mode 100644 index 0000000000000000000000000000000000000000..f4710fc29cca5cdfd6c60263ff89823041884a47 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_trace_id_alloc.c @@ -0,0 +1,74 @@ +#ifndef _WINDOWS + +#include +#include +#include + +#include "ps3_trace_id.h" +#include "ps3_err_def.h" +#include "ps3_trace_id_alloc.h" + +static DEFINE_PER_CPU(ps3_trace_id_u, ps3_trace_id); + +static U8 g_ps3_trace_id_swith = ps3_trace_id_switch_open; + +void ps3_trace_id_alloc(U64 *trace_id) +{ + ps3_trace_id_u *id = NULL; + U64 trace_id_count = 0; + + if (g_ps3_trace_id_swith != ps3_trace_id_switch_open) { + *trace_id = 0; + goto l_out; + } + + preempt_disable(); + id = this_cpu_ptr(&ps3_trace_id); + + trace_id_count = id->ps3_trace_id.count; + ++trace_id_count; + id->ps3_trace_id.count = (trace_id_count & TRACE_ID_CHIP_OUT_COUNT_MASK); + + *trace_id = id->trace_id; + preempt_enable(); + +l_out: + return ; +} + +void ps3_trace_id_init(void) +{ + S32 cpu = 0; + ps3_trace_id_u *id = NULL; + + for_each_possible_cpu(cpu) { + id = &per_cpu(ps3_trace_id, cpu); + id->ps3_trace_id.flag = ps3_trace_id_flag_host_driver; + id->ps3_trace_id.cpu_id = (cpu & TRACE_ID_CHIP_OUT_CPUID_MASK); + id->ps3_trace_id.count = 0; + } + + return; +} + +S32 ps3_trace_id_switch_store(U8 value) +{ + S32 ret = PS3_SUCCESS; + + if (value != ps3_trace_id_switch_close && + value != ps3_trace_id_switch_open) { + ret = PS3_FAILED; + goto l_out; + } + + g_ps3_trace_id_swith = value; + +l_out: + return ret; +} + +U8 ps3_trace_id_switch_show(void) +{ + return g_ps3_trace_id_swith; +} +#endif diff --git a/drivers/scsi/ps3stor/ps3_trace_id_alloc.h b/drivers/scsi/ps3stor/ps3_trace_id_alloc.h new file mode 100644 index 0000000000000000000000000000000000000000..7b77221208112637734862b70296d2d83515cd62 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_trace_id_alloc.h @@ -0,0 +1,33 @@ + +#ifndef _PS3_TRACE_ID_ALLOC_H_ +#define _PS3_TRACE_ID_ALLOC_H_ + +#include "ps3_htp_def.h" + +enum { + ps3_trace_id_flag_host_driver = 0, +}; + +enum { + ps3_trace_id_switch_open, + ps3_trace_id_switch_close, +}; + +typedef union { + U64 trace_id; + struct { + U64 count : 52; + U64 cpu_id : 11; + U64 flag : 1; + } ps3_trace_id; +} ps3_trace_id_u; + +void ps3_trace_id_alloc(U64 *trace_id); + +void ps3_trace_id_init(void); + +S32 ps3_trace_id_switch_store(U8 value); + +U8 ps3_trace_id_switch_show(void); + +#endif \ No newline at end of file diff --git a/drivers/scsi/ps3stor/ps3_util.h b/drivers/scsi/ps3stor/ps3_util.h new file mode 100644 index 0000000000000000000000000000000000000000..3965fa08b98134b87ed8d18cd81bce3f70087f3b --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_util.h @@ -0,0 +1,408 @@ + +#ifndef _PS3_UTIL_H_ +#define _PS3_UTIL_H_ + +#ifndef _WINDOWS +#include +#include "ps3_instance_manager.h" + +#endif +#include "htp_v200/ps3_htp_def.h" +#include "ps3_driver_log.h" +#include "ps3_platform_utils.h" + +#define PS3_DRV_MAX(x, y) ((x) > (y) ? (x) : (y)) + +#define PCIE_DMA_HOST_ADDR_BIT53_MASK_CHECK(addr) \ + (((1ULL) << (PCIE_DMA_HOST_ADDR_BIT_POS_F1)) & (addr)) + +#define PCIE_DMA_HOST_ADDR_BIT54_MASK_CHECK(addr) \ + (((1ULL) << (PCIE_DMA_HOST_ADDR_BIT_POS_F0)) & (addr)) + +enum { + PS3_BLOCK_SIZE_16 = 16, + PS3_BLOCK_SIZE_32 = 32, + PS3_BLOCK_SIZE_64 = 64, + PS3_BLOCK_SIZE_128 = 128, + PS3_BLOCK_SIZE_256 = 256, + PS3_BLOCK_SIZE_512 = 512, + PS3_BLOCK_SIZE_1024 = 1024, + PS3_BLOCK_SIZE_2048 = 2048, + PS3_BLOCK_SIZE_4096 = 4096, + PS3_BLOCK_SIZE_8192 = 8192, +}; + +#define PS3_BLOCK_SIZE_16K (16uLL << 10) +#define PS3_BLOCK_SIZE_32K (32uLL << 10) +#define PS3_BLOCK_SIZE_64K (64uLL << 10) +#define PS3_BLOCK_SIZE_128K (128uLL << 10) +#define PS3_BLOCK_SIZE_256K (256uLL << 10) +#define PS3_BLOCK_SIZE_512K (512uLL << 10) +#define PS3_BLOCK_SIZE_1M (1uLL << 20) +#define PS3_BLOCK_SIZE_2M (2uLL << 20) +#define PS3_BLOCK_SIZE_4M (4uLL << 20) +#define PS3_BLOCK_SIZE_8M (8uLL << 20) +#define PS3_BLOCK_SIZE_16M (16uLL << 20) +#define PS3_BLOCK_SIZE_32M (32uLL << 20) +#define PS3_BLOCK_SIZE_64M (64uLL << 20) +#define PS3_BLOCK_SIZE_128M (128uLL << 20) +#define PS3_BLOCK_SIZE_256M (256uLL << 20) +#define PS3_BLOCK_SIZE_512M (512uLL << 20) +#define PS3_BLOCK_SIZE_1G (1uLL << 30) +#define PS3_BLOCK_SIZE_2G (2uLL << 30) +#define PS3_BLOCK_SIZE_4G (4uLL << 30) +#define PS3_BLOCK_SIZE_8G (8uLL << 30) +#define PS3_BLOCK_SIZE_16G (16uLL << 30) +#define PS3_BLOCK_SIZE_32G (32uLL << 30) +#define PS3_BLOCK_SIZE_64G (64uLL << 30) +#define PS3_BLOCK_SIZE_128G (128uLL << 30) +#define PS3_BLOCK_SIZE_256G (256uLL << 30) +#define PS3_BLOCK_SIZE_512G (512uLL << 30) +#define PS3_BLOCK_SIZE_1T (1uLL << 40) +#define PS3_BLOCK_SIZE_2T (2uLL << 40) +#define PS3_BLOCK_SIZE_4T (4uLL << 40) +#define PS3_BLOCK_SIZE_8T (8uLL << 40) +#define PS3_BLOCK_SIZE_16T (16uLL << 40) +#define PS3_BLOCK_SIZE_32T (32uLL << 40) + +enum { + PS3_BLOCK_SIZE_SHIFT_4 = 4, + PS3_BLOCK_SIZE_SHIFT_5 = 5, + PS3_BLOCK_SIZE_SHIFT_6 = 6, + PS3_BLOCK_SIZE_SHIFT_7 = 7, + PS3_BLOCK_SIZE_SHIFT_8 = 8, + PS3_BLOCK_SIZE_SHIFT_9 = 9, + PS3_BLOCK_SIZE_SHIFT_10 = 10, + PS3_BLOCK_SIZE_SHIFT_11 = 11, + PS3_BLOCK_SIZE_SHIFT_12 = 12, + PS3_BLOCK_SIZE_SHIFT_13 = 13, + PS3_BLOCK_SIZE_SHIFT_16K = 14, + PS3_BLOCK_SIZE_SHIFT_32K = 15, + PS3_BLOCK_SIZE_SHIFT_64K, + PS3_BLOCK_SIZE_SHIFT_128K, + PS3_BLOCK_SIZE_SHIFT_256K, + PS3_BLOCK_SIZE_SHIFT_512K, + PS3_BLOCK_SIZE_SHIFT_1M = 20, + PS3_BLOCK_SIZE_SHIFT_2M, + PS3_BLOCK_SIZE_SHIFT_4M, + PS3_BLOCK_SIZE_SHIFT_8M, + PS3_BLOCK_SIZE_SHIFT_16M, + PS3_BLOCK_SIZE_SHIFT_32M = 25, + PS3_BLOCK_SIZE_SHIFT_64M, + PS3_BLOCK_SIZE_SHIFT_128M, + PS3_BLOCK_SIZE_SHIFT_256M, + PS3_BLOCK_SIZE_SHIFT_512M, + PS3_BLOCK_SIZE_SHIFT_1G = 30, + PS3_BLOCK_SIZE_SHIFT_2G, + PS3_BLOCK_SIZE_SHIFT_4G, + PS3_BLOCK_SIZE_SHIFT_8G, + PS3_BLOCK_SIZE_SHIFT_16G, + PS3_BLOCK_SIZE_SHIFT_32G = 35, + PS3_BLOCK_SIZE_SHIFT_64G, + PS3_BLOCK_SIZE_SHIFT_128G, + PS3_BLOCK_SIZE_SHIFT_256G, + PS3_BLOCK_SIZE_SHIFT_512G, + PS3_BLOCK_SIZE_SHIFT_1T = 40, + PS3_BLOCK_SIZE_SHIFT_2T, + PS3_BLOCK_SIZE_SHIFT_4T, + PS3_BLOCK_SIZE_SHIFT_8T, + PS3_BLOCK_SIZE_SHIFT_16T, + PS3_BLOCK_SIZE_SHIFT_32T = 45, +}; + +static inline U32 ps3_blocksize_to_shift(U32 block_size) +{ + U32 shift = 0; + + switch (block_size) { + case PS3_BLOCK_SIZE_16: + shift = PS3_BLOCK_SIZE_SHIFT_4; + break; + case PS3_BLOCK_SIZE_32: + shift = PS3_BLOCK_SIZE_SHIFT_5; + break; + case PS3_BLOCK_SIZE_64: + shift = PS3_BLOCK_SIZE_SHIFT_6; + break; + case PS3_BLOCK_SIZE_128: + shift = PS3_BLOCK_SIZE_SHIFT_7; + break; + case PS3_BLOCK_SIZE_256: + shift = PS3_BLOCK_SIZE_SHIFT_8; + break; + case PS3_BLOCK_SIZE_512: + shift = PS3_BLOCK_SIZE_SHIFT_9; + break; + case PS3_BLOCK_SIZE_1024: + shift = PS3_BLOCK_SIZE_SHIFT_10; + break; + case PS3_BLOCK_SIZE_2048: + shift = PS3_BLOCK_SIZE_SHIFT_11; + break; + case PS3_BLOCK_SIZE_4096: + shift = PS3_BLOCK_SIZE_SHIFT_12; + break; + case PS3_BLOCK_SIZE_8192: + shift = PS3_BLOCK_SIZE_SHIFT_13; + break; + default: + PS3_BUG(); + break; + } + + return shift; +} + +static inline U32 ps3_ringsize_to_shift(U64 ring_size) +{ + U32 shift = 0; + + switch (ring_size) { + case PS3_BLOCK_SIZE_512: + shift = PS3_BLOCK_SIZE_SHIFT_9; + break; + case PS3_BLOCK_SIZE_1024: + shift = PS3_BLOCK_SIZE_SHIFT_10; + break; + case PS3_BLOCK_SIZE_2048: + shift = PS3_BLOCK_SIZE_SHIFT_11; + break; + case PS3_BLOCK_SIZE_4096: + shift = PS3_BLOCK_SIZE_SHIFT_12; + break; + case PS3_BLOCK_SIZE_8192: + shift = PS3_BLOCK_SIZE_SHIFT_13; + break; + case PS3_BLOCK_SIZE_16K: + shift = PS3_BLOCK_SIZE_SHIFT_16K; + break; + case PS3_BLOCK_SIZE_32K: + shift = PS3_BLOCK_SIZE_SHIFT_32K; + break; + case PS3_BLOCK_SIZE_64K: + shift = PS3_BLOCK_SIZE_SHIFT_64K; + break; + case PS3_BLOCK_SIZE_128K: + shift = PS3_BLOCK_SIZE_SHIFT_128K; + break; + case PS3_BLOCK_SIZE_256K: + shift = PS3_BLOCK_SIZE_SHIFT_256K; + break; + case PS3_BLOCK_SIZE_512K: + shift = PS3_BLOCK_SIZE_SHIFT_512K; + break; + case PS3_BLOCK_SIZE_1M: + shift = PS3_BLOCK_SIZE_SHIFT_1M; + break; + case PS3_BLOCK_SIZE_2M: + shift = PS3_BLOCK_SIZE_SHIFT_2M; + break; + case PS3_BLOCK_SIZE_4M: + shift = PS3_BLOCK_SIZE_SHIFT_4M; + break; + case PS3_BLOCK_SIZE_8M: + shift = PS3_BLOCK_SIZE_SHIFT_8M; + break; + case PS3_BLOCK_SIZE_16M: + shift = PS3_BLOCK_SIZE_SHIFT_16M; + break; + case PS3_BLOCK_SIZE_32M: + shift = PS3_BLOCK_SIZE_SHIFT_32M; + break; + case PS3_BLOCK_SIZE_64M: + shift = PS3_BLOCK_SIZE_SHIFT_64M; + break; + case PS3_BLOCK_SIZE_128M: + shift = PS3_BLOCK_SIZE_SHIFT_128M; + break; + case PS3_BLOCK_SIZE_256M: + shift = PS3_BLOCK_SIZE_SHIFT_256M; + break; + case PS3_BLOCK_SIZE_512M: + shift = PS3_BLOCK_SIZE_SHIFT_512M; + break; + case PS3_BLOCK_SIZE_1G: + shift = PS3_BLOCK_SIZE_SHIFT_1G; + break; + case PS3_BLOCK_SIZE_2G: + shift = PS3_BLOCK_SIZE_SHIFT_2G; + break; + case PS3_BLOCK_SIZE_4G: + shift = PS3_BLOCK_SIZE_SHIFT_4G; + break; + case PS3_BLOCK_SIZE_8G: + shift = PS3_BLOCK_SIZE_SHIFT_8G; + break; + case PS3_BLOCK_SIZE_16G: + shift = PS3_BLOCK_SIZE_SHIFT_16G; + break; + case PS3_BLOCK_SIZE_32G: + shift = PS3_BLOCK_SIZE_SHIFT_32G; + break; + case PS3_BLOCK_SIZE_64G: + shift = PS3_BLOCK_SIZE_SHIFT_64G; + break; + case PS3_BLOCK_SIZE_128G: + shift = PS3_BLOCK_SIZE_SHIFT_128G; + break; + case PS3_BLOCK_SIZE_256G: + shift = PS3_BLOCK_SIZE_SHIFT_256G; + break; + case PS3_BLOCK_SIZE_512G: + shift = PS3_BLOCK_SIZE_SHIFT_512G; + break; + case PS3_BLOCK_SIZE_1T: + shift = PS3_BLOCK_SIZE_SHIFT_1T; + break; + case PS3_BLOCK_SIZE_2T: + shift = PS3_BLOCK_SIZE_SHIFT_2T; + break; + case PS3_BLOCK_SIZE_4T: + shift = PS3_BLOCK_SIZE_SHIFT_4T; + break; + case PS3_BLOCK_SIZE_8T: + shift = PS3_BLOCK_SIZE_SHIFT_8T; + break; + case PS3_BLOCK_SIZE_16T: + shift = PS3_BLOCK_SIZE_SHIFT_16T; + break; + case PS3_BLOCK_SIZE_32T: + shift = PS3_BLOCK_SIZE_SHIFT_32T; + break; + default: + shift = PS3_BLOCK_SIZE_SHIFT_1T; + break; + } + return shift; +} + +static U8 ps3_dma_addr_bit_pos_check(dma_addr_t handle) +{ + U8 bit_pos = 0; + if (PCIE_DMA_HOST_ADDR_BIT54_MASK_CHECK(handle)) { + bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS_F0; + } else if (PCIE_DMA_HOST_ADDR_BIT53_MASK_CHECK(handle)) { + bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS_F1; + } else { + bit_pos = PCIE_DMA_HOST_ADDR_BIT_POS; + } + return bit_pos; +} + +static inline struct dma_pool *ps3_dma_pool_create(const char *name, + struct device *dev, size_t size, size_t align, size_t boundary) +{ + struct dma_pool *pool = NULL; + pool = dma_pool_create(name, dev, size, align, boundary); + LOG_INFO("create dma pool:name '%s', size %lu, align %lu, boundary %lu, pool %p\n", + name, size, align, boundary, pool); + return pool; +} + +static inline void *ps3_dma_pool_alloc(struct ps3_instance *instance, + struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle) +{ + void *ret = dma_pool_alloc(pool, mem_flags, handle); + if(ret != NULL) { + *handle = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, *handle); + } + return ret; +} + +static inline void *ps3_dma_pool_zalloc(struct ps3_instance *instance, + struct dma_pool *pool, gfp_t mem_flags, + dma_addr_t *handle) +{ + void *ret = dma_pool_zalloc(pool, mem_flags, handle); + *handle = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, *handle); + return ret; +} + +static inline void ps3_dma_pool_destroy(struct dma_pool *pool) +{ + dma_pool_destroy(pool); + LOG_INFO("pool destroy %p \n",pool); + return; +} + +static inline void ps3_dma_pool_free(struct dma_pool *pool, + void *vaddr, dma_addr_t dma) +{ + U8 bit_pos = 0; + bit_pos = ps3_dma_addr_bit_pos_check(dma); + dma_pool_free(pool, vaddr, PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dma)); + return; +} + +static inline U32 ps3_scsi_channel_query(struct scsi_cmnd *scmd) +{ + U32 ret = U32_MAX; + + if (scmd == NULL) { + goto l_out; + } + + if (scmd->device == NULL) { + goto l_out; + } + + ret = scmd->device->channel; +l_out: + return ret; +} + +static inline U32 ps3_scsi_target_query(struct scsi_cmnd *scmd) +{ + U32 ret = U32_MAX; + + if (scmd == NULL) { + goto l_out; + } + + if (scmd->device == NULL) { + goto l_out; + } + + ret = scmd->device->id; +l_out: + return ret; +} + +static inline void *ps3_dma_alloc_coherent(struct ps3_instance *instance, size_t size, + U64 *handle) +{ + void *buffer = NULL; + buffer = dma_alloc_coherent(&instance->pdev->dev, size, handle, GFP_KERNEL); + *handle = PCIE_DMA_HOST_ADDR_BIT_POS_SET_NEW(instance->dma_addr_bit_pos, *handle); + return buffer; +} + +static inline void ps3_dma_free_coherent(struct ps3_instance *instance, size_t size, + void *vaddr, U64 dma_handle) +{ + U8 bit_pos = 0; + bit_pos = ps3_dma_addr_bit_pos_check(dma_handle); + dma_free_coherent(&instance->pdev->dev, size, vaddr, + PCIE_DMA_HOST_ADDR_BIT_POS_CLEAR_NEW(bit_pos, dma_handle)); + return; +} + +static inline U32 ps3_utility_mod64(U64 dividend, U32 divisor) +{ + U64 d = dividend; + U32 remainder = 0; + + if (!divisor) { + LOG_ERROR("DIVISOR is zero, in div fn\n"); + return (U32)-1; + } + +#ifndef _WINDOWS + remainder = do_div(d, divisor); +#else + remainder = d % divisor; +#endif + return remainder; +} +#endif + diff --git a/drivers/scsi/ps3stor/ps3_watchdog.c b/drivers/scsi/ps3stor/ps3_watchdog.c new file mode 100644 index 0000000000000000000000000000000000000000..4e25829b24de9d6fb417f77adb15a6d4b3716c14 --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_watchdog.c @@ -0,0 +1,352 @@ +#ifndef _WINDOWS +#include +#include +#include +#include +#include + +#include +#endif + +#include "ps3_instance_manager.h" +#include "ps3_ioc_state.h" +#include "ps3_mgr_cmd_err.h" +#include "ps3_watchdog.h" +#include "ps3_driver_log.h" +#include "ps3_dump.h" +#include "ps3_module_para.h" +#include "ps3_ioc_manager.h" +#include "ps3_err_inject.h" + +#define PS3_WATCHDOG_NAME_MAX_LENGTH (48) + +static S32 ps3_watchdog_fault_detect_and_recovery(struct ps3_instance *instance) +{ + U32 ioc_recovery_count = 0; + U32 ioc_state = PS3_FW_STATE_UNDEFINED; + S32 ret = PS3_SUCCESS; + U32 heartbeat_triggered = 0; + + if (ps3_pci_err_recovery_get(instance)) { + LOG_WARN_LIM("hno:%u pci recovery resetting\n", + PS3_HOST(instance)); + goto l_out; + } + + if (!ps3_ioc_recovery_count_get(instance, &ioc_recovery_count)) { + ps3_atomic_inc(&instance->watchdog_reg_read_fail_count); + LOG_ERROR_LIM("hno:%u get recovery count NOK, cnt: %d\n", + PS3_HOST(instance), ps3_atomic_read(&instance->watchdog_reg_read_fail_count)); + goto l_out; + } + + if (!ps3_ioc_state_get_with_check(instance, &ioc_state)) { + ps3_atomic_inc(&instance->watchdog_reg_read_fail_count); + LOG_ERROR_LIM("hno:%u get ioc state NOK, cnt: %u\n", + PS3_HOST(instance), ps3_atomic_read(&instance->watchdog_reg_read_fail_count)); + goto l_out; + } + + ps3_atomic_set(&instance->watchdog_reg_read_fail_count, 0); + + if (instance->ioc_adpter->ioc_heartbeat_detect) { + if ((instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_DECIDE || + instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_RECOVERY || + instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_HARDRESET_RETRY) + &&(instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE)) { + goto l_out; + } + + heartbeat_triggered = instance->ioc_adpter->ioc_heartbeat_detect(instance); + if (heartbeat_triggered == PS3_TRUE + && !ps3_pci_err_recovery_get(instance)) { + LOG_INFO("hno:%u heartbeat recovery triggered\n", + PS3_HOST(instance)); + ps3_mutex_lock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + if (instance->recovery_context->heartbeat_recovery == PS3_HEARTBEAT_NULL) { + instance->recovery_context->heartbeat_recovery = + PS3_HEARTBEAT_HARDRESET_DECIDE; + } + ps3_mutex_unlock(&instance->recovery_context->ps3_watchdog_recovery_mutex); + goto l_recovery; + } + } + + if (ioc_state == PS3_FW_STATE_FAULT || + ioc_state == PS3_FW_STATE_CRITICAL) { + goto l_recovery; + } + + if ((ioc_state == PS3_FW_STATE_RUNNING) && + (instance->recovery_context->ioc_recovery_count == + ioc_recovery_count)) { + goto l_out; + } + + if (ioc_state == PS3_FW_STATE_RESET) { + goto l_out; + } + + if (ioc_recovery_count == PS3_IOC_RECOVERY_COUNT_MASK) { + goto l_out; + } + + if (ioc_state == PS3_FW_STATE_UNDEFINED) { + goto l_out; + } + + if (ioc_state == PS3_FW_STATE_MASK) { + goto l_out; + } + +l_recovery: + LOG_INFO("hno:%u watchdog recovery request, ioc_state[0x%x]," + " ioc_reco_cnt[%u], local_reco_cnt[%u]\n", + PS3_HOST(instance), ioc_state, ioc_recovery_count, + instance->recovery_context->ioc_recovery_count); + + PS3_IJ_SLEEP(200000, PS3_ERR_IJ_WATCHDOG_DELAY); + + if (ps3_atomic_read(&instance->state_machine.state) != PS3_INSTANCE_STATE_DEAD) { + if (ps3_need_block_hard_reset_request(instance) || PS3_IS_INSTANCE_NOT_LOAD_NORMAL(instance) || \ + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_SHALLOW || \ + instance->recovery_context->recovery_state == PS3_HARD_RECOVERY_DECIDE) { + LOG_WARN_LIM("hno:%u can not start reset request recovery_state:%d\n", + PS3_HOST(instance), instance->recovery_context->recovery_state); + } else { + LOG_WARN("hno:%u ps3 watchdog recovery start, heartbeat_triggered:%u ioc_state:0x%x\n", + PS3_HOST(instance), heartbeat_triggered, ioc_state); + if(ps3_recovery_request(instance) == PS3_SUCCESS){ + LOG_INFO("hno[%u], recovery success!\n", + PS3_HOST(instance)); + ret = PS3_SUCCESS; + }else{ + LOG_ERROR("hno[%u], recovery request NOK, %s!\n", + PS3_HOST(instance), + namePS3InstanceState(ps3_atomic_read(&instance->state_machine.state))); + return -PS3_FAILED; + } + } + } + +l_out: + if (ps3_atomic_read(&instance->watchdog_reg_read_fail_count) >= PS3_TRANS_DEAD_IOC_FAILED_MAX_COUNT) { +#ifdef PS3_HARDWARE_SIM + LOG_WARN("hno:%u reg read failed 5 times consecutively, simu platform ignore\n", + PS3_HOST(instance)); +#else + ps3_instance_state_transfer_to_dead(instance); + instance->watchdog_context.is_stop = PS3_TRUE; + LOG_ERROR("hno:%u reg read failed 5 times consecutively, transfer to dead\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; +#endif + } + + return ret; +} + +#ifndef _WINDOWS + +static void ps3_watchdog_service(struct work_struct* work) +{ + struct ps3_watchdog_context* watchdog_ctx = + ps3_container_of(work, struct ps3_watchdog_context, + watchdog_work.work); + struct ps3_instance *instance = watchdog_ctx->instance; + struct delayed_work* delayed_work = &watchdog_ctx->watchdog_work; + S32 ret = PS3_SUCCESS; + + if (instance->recovery_context->recovery_state == + PS3_HARD_RECOVERY_SHALLOW || + instance->recovery_context->recovery_state == + PS3_HARD_RECOVERY_DECIDE) { + watchdog_ctx->is_halt = PS3_TRUE; + goto l_next; + } + + watchdog_ctx->is_halt = PS3_FALSE; + if (instance->is_probe_finish && instance->state_machine.is_load) { + ret = ps3_watchdog_fault_detect_and_recovery(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u watchdog fault detect and recovery \ + NOK watchdog service exit\n", + PS3_HOST(instance)); + } + } +l_next: + + if (watchdog_ctx->is_stop) { + LOG_INFO("hno:%u watchdog has stop\n", + PS3_HOST(instance)); + return; + } + + ps3_qos_waitq_poll(instance); + + if (watchdog_ctx->watchdog_queue != NULL) { + queue_delayed_work(watchdog_ctx->watchdog_queue, delayed_work, + msecs_to_jiffies(PS3_WATCHDOG_INTERVAL)); + } +} + +S32 ps3_watchdog_start(struct ps3_instance *instance) +{ + struct ps3_watchdog_context* watchdog_ctx = &instance->watchdog_context; + char watchdog_queue_name[PS3_WATCHDOG_NAME_MAX_LENGTH]; + struct delayed_work* delayed_work = &watchdog_ctx->watchdog_work; + ps3_atomic_inc(&instance->watchdog_ref); + mb(); + + if (PS3_FALSE == watchdog_ctx->is_stop) { + LOG_DEBUG("hno:%u watchdog running\n", PS3_HOST(instance)); + ps3_atomic_dec(&instance->watchdog_ref); + return PS3_SUCCESS; + } + + if (watchdog_ctx->watchdog_queue != NULL) { + LOG_DEBUG("hno:%u watchdog for is already started!\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->watchdog_ref); + goto l_out; + } + + memset(watchdog_queue_name, 0, PS3_WATCHDOG_NAME_MAX_LENGTH); + memset(watchdog_ctx, 0, sizeof(struct ps3_watchdog_context)); + INIT_DELAYED_WORK(delayed_work, ps3_watchdog_service); + + snprintf(watchdog_queue_name, PS3_WATCHDOG_NAME_MAX_LENGTH, + "ps3_watchdog_service_host%d", instance->host->host_no); + + watchdog_ctx->watchdog_queue = + create_singlethread_workqueue(watchdog_queue_name); + if (watchdog_ctx->watchdog_queue == NULL) { + LOG_ERROR("hno:%u watchdog work queue create failed\n", + PS3_HOST(instance)); + ps3_atomic_dec(&instance->watchdog_ref); + return -PS3_FAILED; + } + + watchdog_ctx->instance = instance; + watchdog_ctx->is_stop = PS3_FALSE; + queue_delayed_work(watchdog_ctx->watchdog_queue, delayed_work, + msecs_to_jiffies(PS3_WATCHDOG_INTERVAL)); + ps3_atomic_dec(&instance->watchdog_ref); + +l_out: + return PS3_SUCCESS; +} + +void ps3_watchdog_stop(struct ps3_instance *instance) +{ + struct ps3_watchdog_context* watchdog_ctx = &instance->watchdog_context; + struct workqueue_struct* watchdog_queue; + struct delayed_work* delayed_work = &watchdog_ctx->watchdog_work; + + if (PS3_TRUE == watchdog_ctx->is_stop) { + return; + } + + watchdog_ctx->is_stop = PS3_TRUE; + mb(); + while(ps3_atomic_read(&instance->watchdog_ref) != 0) { + ps3_msleep(PS3_LOOP_TIME_INTERVAL_100MS); + } + + if (watchdog_ctx->watchdog_queue != NULL) { + watchdog_queue = watchdog_ctx->watchdog_queue; + if (!cancel_delayed_work_sync(delayed_work)) { + flush_workqueue(watchdog_queue); + } + + destroy_workqueue(watchdog_queue); + watchdog_ctx->watchdog_queue = NULL; + LOG_INFO("hno:%u watchdog destory work and stop\n", + PS3_HOST(instance)); + } +} +#else + +static void ps3_watchdog_service(void *ins) +{ + struct ps3_instance *instance = (struct ps3_instance*)ins; + struct ps3_watchdog_context* watchdog_ctx = &instance->watchdog_context; + struct ps3_delay_worker* watchdog_work = &watchdog_ctx->watchdog_work; + S32 ret = PS3_SUCCESS; + + if(ps3_atomic_read(&instance->state_machine.state) != + PS3_INSTANCE_STATE_OPERATIONAL && + (instance->recovery_context->recovery_state == + PS3_HARD_RECOVERY_SHALLOW || + instance->recovery_context->recovery_state == + PS3_HARD_RECOVERY_DECIDE)) { + watchdog_ctx->is_halt = PS3_TRUE; + goto l_next; + } + + watchdog_ctx->is_halt = PS3_FALSE; + + if (instance->is_probe_finish) { + ret = ps3_watchdog_fault_detect_and_recovery(instance); + if (ret != PS3_SUCCESS) { + LOG_ERROR("hno:%u watchdog fault detect and recovery \ + failed watchdog service exit\n", + PS3_HOST(instance)); + } + } +l_next: + + if (watchdog_ctx->is_stop) { + LOG_DEBUG("hno:%u watchdog has stop\n", + PS3_HOST(instance)); + return; + } + + ps3_dump_detect(instance); + + ps3_delay_worker_start(watchdog_work, PS3_WATCHDOG_INTERVAL); +} + +S32 ps3_watchdog_start(struct ps3_instance *instance) +{ + S32 ret = PS3_SUCCESS; + struct ps3_watchdog_context* watchdog_ctx = &instance->watchdog_context; + struct ps3_delay_worker* watchdog_work = &watchdog_ctx->watchdog_work; + + memset(watchdog_ctx, 0, sizeof(struct ps3_watchdog_context)); + + if (ps3_delay_worker_init(instance, watchdog_work, "ps3_watchdog_service", ps3_watchdog_service) != PS3_SUCCESS) { + LOG_ERROR("hno:%u timer init failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + goto l_out; + } + + watchdog_ctx->is_stop = PS3_FALSE; + if (ps3_delay_worker_start(watchdog_work, PS3_WATCHDOG_INTERVAL) != PS3_SUCCESS) { + LOG_ERROR("hno:%u timer request failed\n", + PS3_HOST(instance)); + ret = -PS3_FAILED; + watchdog_ctx->is_stop = PS3_TRUE; + goto l_out; + } + +l_out: + return PS3_SUCCESS; +} + +void ps3_watchdog_stop(struct ps3_instance *instance) +{ + struct ps3_watchdog_context* watchdog_ctx = &instance->watchdog_context; + struct ps3_delay_worker* watchdog_work = &watchdog_ctx->watchdog_work; + + watchdog_ctx->is_stop = PS3_TRUE; + ps3_delay_worker_exit(watchdog_work); + + memset(watchdog_ctx, 0, sizeof(struct ps3_watchdog_context)); + LOG_WARN("hno:%u watchdog destory work and stop\n", + PS3_HOST(instance)); +} +#endif + diff --git a/drivers/scsi/ps3stor/ps3_watchdog.h b/drivers/scsi/ps3stor/ps3_watchdog.h new file mode 100644 index 0000000000000000000000000000000000000000..156fb28428d740f2808c603f4dfc6504627ed7ab --- /dev/null +++ b/drivers/scsi/ps3stor/ps3_watchdog.h @@ -0,0 +1,32 @@ + +#ifndef _PS3_WATCHDOG_H_ +#define _PS3_WATCHDOG_H_ + +#ifndef _WINDOWS +#include +#include +#include +#else +#include "ps3_worker.h" +#endif + +#include "ps3_htp_def.h" +#include "ps3_instance_manager.h" +#define PS3_WATCHDOG_INTERVAL (1000) + +struct ps3_watchdog_context { +#ifndef _WINDOWS + struct delayed_work watchdog_work; + struct workqueue_struct *watchdog_queue; + struct ps3_instance *instance; +#else + struct ps3_delay_worker watchdog_work; +#endif + Bool is_stop; + Bool is_halt; +}; + +S32 ps3_watchdog_start(struct ps3_instance *instance); +void ps3_watchdog_stop(struct ps3_instance *instance); + +#endif diff --git a/drivers/scsi/ps3stor/ramfs_install.sh b/drivers/scsi/ps3stor/ramfs_install.sh new file mode 100644 index 0000000000000000000000000000000000000000..2b988b244932c7a19907a9e5e86ccf44ebf17a83 --- /dev/null +++ b/drivers/scsi/ps3stor/ramfs_install.sh @@ -0,0 +1,75 @@ +#!/bin/sh +#note 实现卡下系统安装脚本 +#warn 该脚本仅在系统安装使用进行使用 + +#验证rpm安装是否正常,若是失败,退出 +function check_return(){ + if [ $? -ne 0 ]; then + exit 1; + fi +} + +function dirCheck(){ + driverDir=$1 + imageDir=$2 + serviceDir="/mnt/sysimage/usr/lib/systemd/system" + serviceLnDir="/mnt/sysimage/etc/systemd/system" + + while ((1)) + do + isImageDir="null" + sleep 1 + if [ -d ${imageDir} ];then + sleep 10; + if [ -d ${imageDir} ];then + isImageDir=`ls -dn $imageDir | grep "drw" | awk '{print $1}'` + check_return + fi + fi + if [ ${isImageDir} != "null" ]&&[ ! -f ${imageDir}/ps3stor.ko ];then + echo "The image dir has been built!" + cp ${driverDir}/ps3stor.ko ${imageDir}/ + check_return + echo "mv ps3stor.ko finisded" + fi + done +} + +#step1 基础变量赋值 +echo "The rpm script is running!" +kernel=`uname -r` +driverSourDir=`pwd` +driverDesDir="/usr/lib/modules/${kernel}/kernel/drivers/scsi" +imageDir="/mnt/sysimage/usr/lib/modules/${kernel}/kernel/drivers/scsi" + +#step2 安装基本驱动程序 +if [ ! -e ${driverSourDir}/ps3stor.ko ]; then + echo "The ps3stor.ko needs to be in the current dirctory!" + exit 1; +fi + +isload=`lsmod | grep -wm1 ps3stor | cut -d " " -f 1` +if [ ! ${isload} ]; then + cp -rf ${driverSourDir}/ps3stor.ko ${driverDesDir}/ps3stor.ko + check_return + modprobe scsi_transport_sas + check_return + echo "Finish scsi_transport_sas.ko install!" + insmod ${driverDesDir}/ps3stor.ko + check_return + echo "Finsih ps3stor.ko install!" +else + if [ ${kernel} == "4.19.90-2305.1.0.0199.56.uel20.x86_64" ]; then + imageDir="/mnt/sysimage/usr/lib/modules/5.10.0-46.uel20.x86_64/kernel/drivers/scsi" + fi + if [ ${kernel} == "4.19.90-2403.3.0.0270.84.uel20.x86_64" ]; then + imageDir="/mnt/sysimage/usr/lib/modules/5.10.0-74.uel20.x86_64/kernel/drivers/scsi" + fi + if [ ${kernel} == "5.10.134-16.2.an8.x86_64" ]; then + imageDir="/mnt/sysimage/usr/lib/modules/4.19.91-27.8.an8.x86_64/kernel/drivers/scsi" + fi + echo "No need to insmod ps3stor.ko" +fi + +#step3 判断安装目录是否存在,存在的话进行文件拷贝 +dirCheck ${driverSourDir} ${imageDir} & diff --git a/drivers/scsi/ps3stor/readme.txt b/drivers/scsi/ps3stor/readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..cdf31b2d5c63baf1e9664670a885a5a9c70661f3 --- /dev/null +++ b/drivers/scsi/ps3stor/readme.txt @@ -0,0 +1,7 @@ +Compile dependencies pkgs:kernel-devel kernel-headers + +1. compiling + compile.sh: a script compiling the driver source. + +2、cleaning + clean.sh : a script for cleaning the driver source tree. diff --git a/drivers/scsi/ps3stor/uload.sh b/drivers/scsi/ps3stor/uload.sh new file mode 100644 index 0000000000000000000000000000000000000000..5cd69e2b51768c0a3f9bd111e3f631318a006695 --- /dev/null +++ b/drivers/scsi/ps3stor/uload.sh @@ -0,0 +1,217 @@ +#!/bin/bash +# +# uload.sh: a helper script for unloading the drivers +# +driverDesDir="/lib/modules/$(uname -r)/kernel/drivers/scsi/" +rpm_initrd="/boot/initramfs-$(uname -r).img" +dpkg_initrd="/boot/initrd.img-$(uname -r)" +install_mode="" +unload_module="" +pkg_mode="" +print_usage() { + echo "Usage: $0 [-rpm|deb|-auto|-ko] [-help]" + echo "" + echo "Options:" + echo " -rpm|-r: uninstall the driver in rpm" + echo " -deb|-d: uninstall the driver in deb" + echo " -auto|-a: uninstall the driver in auto" + echo " -ko|-k: uninstall the driver in ko" + echo " -help|-h: print usage message" + echo "" + echo "Performs selective uninstallation of drivers based on the input provided. " + echo "Please ensure to back up the driver and system boot files in advance. " + exit 1 +} + +while [[ $# -gt 0 ]]; do + case "$1" in + -rpm|-r) + if [ "$unload_module" != "" ]; then + print_usage + exit 1 + else + unload_module="rpm" + shift + fi + ;; + -deb|-d) + if [ "$unload_module" != "" ]; then + print_usage + exit 1 + else + unload_module="deb" + shift + fi + ;; + -auto|-a) + if [ "$unload_module" != "" ]; then + print_usage + exit 1 + else + unload_module="auto" + shift + fi + ;; + -ko|-k) + if [ "$unload_module" != "" ]; then + print_usage + exit 1 + else + unload_module="ko" + shift + fi + ;; + -help|-h) + print_usage + exit 0 + shift + ;; + *) + echo "Invalid argument: $1" + print_usage + exit 1 + ;; + esac +done + +find_rpm_or_deb() { + install_mode=$1 + ramfs_file=$2 + + if [ -f "$rpm_initrd" ]; then + ramfs_file=$rpm_initrd + if rpm -qa |grep ps3stor &> /dev/null ; then + install_mode="pkg_rpm" + elif lsinitrd "$ramfs_file" | grep -q "ps3stor" ; then + install_mode="auto_rpm" + elif lsmod | grep -q ps3stor; then + install_mode="ko" + else + install_mode="no" + fi + + elif [ -f "$dpkg_initrd" ]; then + ramfs_file=$dpkg_initrd + dpkg_status=$(dpkg -l | grep ps3stor | awk '{ print $1 }') + if [ "$dpkg_status" == "ii" ]; then + install_mode="pkg_deb" + elif lsinitramfs -l "$ramfs_file" | grep -q "ps3stor" ; then + install_mode="auto_deb" + elif lsmod | grep -q ps3stor; then + install_mode="ko" + else + install_mode="no" + fi + else + install_mode="no" + fi +} +unload_ko(){ + reference_count=$(lsmod | grep "^ps3stor\s" | awk '{ print $3 }') + + if [ "$reference_count" -ne 0 ]; then + echo "The driver is in use, please wait until it is no longer in use or seek technical support." + exit 1 + else + rmmod ps3stor.ko + if [ $? -eq 0 ]; then + echo "The ps3stor.ko module has been unloaded successfully." + else + echo "The ps3stor.ko module has been unloaded failed." + exit 1 + fi + fi +} + +unload_auto(){ + if [ -f ${driverDesDir}/ps3stor.ko ]||[ -f ${driverDesDir}/ps3stor.ko.xz ]; then + rm -f ${driverDesDir}/ps3stor.ko ${driverDesDir}/ps3stor.ko.xz + if [ $? -ne 0 ]; then + echo "ps3stor file delete failed, please check permissions." + exit 1 + fi + fi + echo "ps3stor.ko is being uninstall, please wait." + depmod -a + + if [ "$install_mode" == "auto_rpm" ]; then + dracut -v -f + elif [ "$install_mode" == "auto_deb" ]; then + mkinitramfs -o $ramfs_file + fi + sleep 1s + + if [ "$install_mode" == "auto_rpm" ] ; then + if lsinitrd "$ramfs_file" | grep -q "ps3stor" ; then + echo "The ps3stor.ko uninstall failed. Please use the backup file to restore the system environment." + else + echo "The ps3stor.ko has been uninstalled." + echo "Please execute ./compile -auto or install the RPM/DEB driver package promptly." + echo "Keep system security and prevent unexpected power loss before the new driver is successfully installed." + fi + elif [ "$install_mode" == "auto_deb" ] ; then + if lsinitramfs -l "$ramfs_file" | grep -q "ps3stor"; then + echo "The ps3stor.ko uninstall failed. Please use the backup file to restore the system environment." + else + echo "The ps3stor.ko has been uninstalled." + echo "Please execute ./compile -auto or install the RPM/DEB driver package promptly." + echo "Keep system security and prevent unexpected power loss before the new driver is successfully installed." + fi + fi +} + +if [ -z $unload_module ]; then + print_usage +fi + +find_rpm_or_deb $install_mode $ramfs_file +case "$unload_module" in + rpm) + if [ "$install_mode" == "pkg_rpm" ]; then + rpm -ev ps3stor + if [ $? -ne 0 ]; then + echo "The ps3stor.ko unload failed." + exit 1 + fi + echo "The RPM packages has been remove." + echo "Please execute ./compile -auto or install the RPM/DEB driver package promptly." + echo "Keep system security and prevent unexpected power loss before the new driver is successfully installed." + else + echo "The ps3stor.ko module not found in RPM packages." + exit 1 + fi + ;; + deb) + if [ "$install_mode" == "pkg_deb" ]; then + dpkg --purge ps3stor + if [ $? -ne 0 ]; then + echo "The ps3stor.ko unload failed." + exit 1 + fi + echo "The DEB packages has been remove." + echo "Please execute ./compile -auto or install the RPM/DEB driver package promptly." + echo "Keep system security and prevent unexpected power loss before the new driver is successfully installed." + else + echo "The ps3stor.ko module not found in DEB packages." + exit 1 + fi + ;; + auto) + if [ "$install_mode" == "auto_rpm" ]||[ "$install_mode" == "auto_deb" ]; then + unload_auto + else + echo "The ps3stor.ko moudule is not loaded in auto mode." + exit 1 + fi + ;; + ko) + if [ "$install_mode" == "ko" ]; then + unload_ko + else + echo "The ps3stor.ko moudule is not loaded in install mode." + exit 1 + fi + ;; +esac + +exit 0