How to create a pure NVMe solid state Synology1

How to create a pure NVMe solid state Synology

Target: Pure NVMe solid-state Synology

In the known Synology systems, M.2 NVMe can only be used as a storage pool, and does not support first-time installation of the system as a storage pool. If you want to use an M.2 storage pool, you must have a special model. At present, the last point is very easy to understand. The available solutions are:

  • Manually create an M2 storage pool, link:Github
  • After manually modifying the attributes of the M2 disk, the storage management page is created
  • Patchlibhwcontrol.soAfter that, the storage management page is created

So currently, the missing link of pure NVMe solid-state Synology is:When installing the system, install directly to the M.2 NVMe solid state, this article will briefly explain how to achieve this.

process exploration

Additional environment preparations for Virtual Synology are as follows:

  • Create a virtual NVMe SSD disk (qemu-img create -f raw nvme0.raw 64G)
  • Virtual machine adds NVMe parameters (-drive file=nvme0.raw,if=none,format=raw,id=nvme0 -device nvme,drive=nvme0,serial=nvme0)

The test environment of this article adds two virtual disks

1. Installation page

According to the above operation, when only adding a virtual NVMe SSD disk, the installation page will display a disk not found prompt as shown below. Let’s take a look at the network request on the right side of the screenshot, check all asynchronous requests, and find that the penultimate one contains hard disk-related information, so we will check from here.

sa6400-nvme-install-no-disk.png

2. Enter ramdisk

Check get_state.cgiOutput

get_state.cgiis the cgi program of nginx agent. This file is actually a shell script in ramdisk. Let’s take a look at the output first. Line 4 directly says that there is no disk:

  1. {
  2. "success": true,
  3. "data": {
  4. "has_disk": false,
  5. "dsinfo": {
  6. "product": "Synology NAS",
  7. "model": "SA6400",
  8. "internet_ok": "false",
  9. "internet_install_ok": false,
  10. "internet_migrate_ok": true,
  11. "internet_reinstall_ok": true,
  12. "internet_install_version": "",
  13. "internet_migrate_version": "DSM 7.1.1-42962",
  14. "internet_reinstall_version": "DSM 7.1.1-42962",
  15. "ip_addr": "192.168.3.172",
  16. "mac_addr": "",
  17. "serial": "0000XXXBN4YYY",
  18. "build_num": 42962,
  19. "build_ver": "7.1.1-42962",
  20. "is_installing": false,
  21. "clean_all_partition_disks": "",
  22. "buildin_storage": false,
  23. "disk_size_enough": true,
  24. "disk_count": 0,
  25. "support_dual_head": "",
  26. "unique_rd": "epyc7002",
  27. "update_hcl_status": "success",
  28. "incompatible_disks": null,
  29. "syno_incompatible_disks": "",
  30. "missing_system_disks": "",
  31. "root_on_isolated_disk": "",
  32. "disabled_port_disks": "",
  33. "ssd_cache_status": "",
  34. "sas_frimware_upgrade_fail": false,
  35. "unidentified": false,
  36. "status": "",
  37. "hostname": "SynologyNAS"
  38. }
  39. }
  40. }

Check here againget_state.cgi about "has_disk": falseRelevant codes for:

  1. partition="$(/usr/syno/bin/synodiskport -installable_disk_list)"
  2. SupportBuildinStorage="$(/bin/get_key_value /etc.defaults/synoinfo.conf support_buildin_storage)"
  3. if [ "xyes" != "x${SupportBuildinStorage}" ]; then
  4. buildin_storage='false'
  5. if [ ! -z"$partition" ];then
  6. has_disk='true'
  7. else
  8. has_disk='false'
  9. fi
  10. disk_count=`echo $partition | wc -w`
  11. else
  12. buildin_storage='true'
  13. has_disk='true'
  14. disk_name=$(basename ${buildin_storage_node})
  15. disk_size=$(cat/sys/block/${disk_name}/size)
  16. if [ "0" -eq"${disk_size}" ]; then
  17. has_disk='false'
  18. elif [ "${min_buildin_storage_size}" -gt"${disk_size}" ]; then
  19. disk_size_enough='false'
  20. fi
  21. fi

want to gethas_disk='true'The places where you can start are: Lines 7 and 14. The SA6400 storage under test is not built-in, so if you choose line 7 here, you need line 6.partitionis not empty, butpartitionis execution/usr/syno/bin/synodiskport -installable_disk_listGot it.

Check synodiskport -installable_disk_list

Execute directly heresynodiskport -installable_disk_listI found that nothing was returned, so I tried to write a shell script to traverse it./sys/blockGetSATA and NVMe disk:

  1. #!/bin/sh
  2. if [ "$1" == "-installable_disk_list" ]; then
  3. disks=$(ls/sys/block|grep'(nvme*|sata*)' |xargs)
  4. echo" "$disks
  5. else
  6. /path/to/old/synodiskport"$@"
  7. fi

After refreshing the page, you can find that the hard disk has been recognized. After trying to install the pat file last time, it was found that the browser requestedget_install_progress.cgiAn error was reported:

  1. {
  2. "success": false,
  3. "data": {},
  4. "errinfo": {
  5. "sec": "error",
  6. "key": "error_mkfs",
  7. "line": 35
  8. }
  9. }

Take a look at the relevant logs:

  1. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1167SYSTEM_NOT_INSTALLED: Raidbut md0notexist
  2. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1235SYSTEM_NOT_INSTALLED: Not SynoParitition and Not Recoverable
  3. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1142(FillUpgradeVolumeInfo):gszUpgradeVolDev= /dev/md0
  4. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1143(FillUpgradeVolumeInfo):gszUpgradeVolMnt= /tmpData
  5. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1245gblSupportRaid: 1,gSysStatus: 3,gblCreateDataVol: 0,gblSystemRecoverable: 0
  6. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1699 CreateDataVol=[0]
  7. messages:Apr 12 twenty two27install.cgi:ninstaller.c:158umount partition/tmpData
  8. messages:Apr 12 twenty two27install.cgi:ninstaller.c:162 Failto execute[/bin/umount-f/tmpData> /dev/null 2>&1]
  9. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1710installer cmd=[/usr/syno/sbin/installer.sh-r>> /tmp/installer_sh.log2>&1]
  10. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1715szCmd=[/usr/syno/sbin/installer.sh-r>> /tmp/installer_sh.log2>&1],retv=[1]
  11. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1739retv=[1]
  12. messages:Apr 12 twenty two27install.cgi:ninstaller.c:1740(ErrFHOSTDoFdiskFormat)retv=[1]

Continue reading/tmp/installer_sh.log:

  1. Check newdisk...
  2. umount:can't unmount /volume1: Invalid argument
  3. raidtooldestroy0
  4. Not found /dev/md0
  5. raidtooldestroy1
  6. Not found /dev/md1
  7. [CREATE] Raidtool initsys
  8. [CREATE][failed] Raidtool initsys

/usr/syno/sbin/installer.shAn error was reported during execution. After viewing the file, the error was reported during execution./sbin/raidtool initsyscaused.

Let’s see again/usr/syno/bin/synodiskport and /sbin/raidtoolThese two commands:

  1. ls-alh/usr/syno/bin//sbin/raidtool|grep'(synodisk|raidtool
  2. )'
  3. lrwxrwxrwx1root root19 Apr 12 twenty two:48 /sbin/raidtool-> /usr/syno/bin/scemd
  4. -wx------ 1root root180 Apr 12 twenty two:17synodiskport

All are soft linked toscemd,and scemdAnyone who has studied Synology Boot knows that this is a tool similar to busybox, which performs different operations based on the currently executed command.
Then we need to reverse itscemdLet’s take a look at the specific disk search logic of this binary file.

3. Reverse analysis

We need to reversescemdThe logic of searching for installable disks is used here. bpftrace is used to capture a lot of output, and comments are added to the code bit by bit. The bpftrace script used is:

  1. uretprobe:"/usr/syno/bin/synodiskport":0xABCCC {
  2. printf("is_suppornmve return: %dn",retval);
  3. }
  4. uretprobe:"/usr/syno/bin/synodiskport":0x5AA09 {
  5. printf("is_support_local_only_dev return: %dn",retval);
  6. }
  7. uretprobe:"/usr/syno/bin/synodiskport":0x6FFF0 {
  8. printf("enumerate_disks return: %dn",retval);
  9. }
  10. uretprobe:"/usr/syno/bin/synodiskport":0x5A7BF {
  11. printf("support_dual_head return: %dn",retval);
  12. }
  13. uprobe:"/usr/syno/bin/synodiskport":0x591CF {
  14. printf("list_insert, string: %sn",str(arg1));
  15. }
  16. uprobe:"/usr/syno/bin/synodiskport":0x6FC50 {
  17. printf("enumerate_disks_with_type, type: %dn",arg0);
  18. }
  19. uretprobe:"/usr/syno/bin/synodiskport":0x6FC50 {
  20. printf("enumerate_disks_with_type, return: %dn",retval);
  21. }
  22. uprobe:"/usr/syno/bin/synodiskport":0x6F580 {
  23. printf("SynoDiskPathGlobAndPortCheck, disk type: %dn", *(uint64*)arg1);
  24. }
  25. uretprobe:"/usr/syno/bin/synodiskport":0x6F580 {
  26. printf("SynoDiskPathGlobAndPortCheck, return: %dn",retval);
  27. }
  28. uprobe:"/usr/syno/bin/synodiskport":0x75390 {
  29. printf("disk_maybe_blocked, disk name: %sn",str(arg0));
  30. }
  31. uretprobe:"/usr/syno/bin/synodiskport":0x75390 {
  32. printf("disk_maybe_blocked, return: %dn",retval);
  33. }
  34. uretprobe:"/usr/syno/bin/synodiskport":0x70A70 {
  35. printf("get_disk_type_by_name, return: %dn",retval);
  36. }
  37. uprobe:"/usr/syno/bin/synodiskport":0xF370 {
  38. printf("strstr, string: %s, sub str: %sn",str(arg0),str(arg1));
  39. }
  40. uretprobe:"/usr/syno/bin/synodiskport":0xF370 {
  41. printf("strstr, return: %sn",str(retval));
  42. }
  43. uprobe:"/usr/syno/bin/synodiskport":0x94FD0 {
  44. printf("nvme_dev_port_check, name: %sn",str(arg0));
  45. }
  46. uretprobe:"/usr/syno/bin/synodiskport":0x94FD0 {
  47. printf("nvme_dev_port_check, return: %dn",retval);
  48. }
  49. uprobe:"/usr/syno/bin/synodiskport":0x98900 {
  50. printf("sata_dev_port_check, name: %sn",str(arg0));
  51. }
  52. uretprobe:"/usr/syno/bin/synodiskport":0x98900 {
  53. printf("sata_dev_port_check, return: %dn",retval);
  54. }

I won’t describe the specific debugging process. I spent a lot of time reading the pseudocode.

Here is the key pseudocode in IDA:

  1. __int64 __fastcallSYNODiskPathGlobAndPortCheck(
  2. __int64 glob_list,
  3. _DWORD*disk_type,
  4. intcheck_type,
  5. _QWORD*disk_list)
  6. {
  7. boolshould_check_type; // r14
  8. intindex; //ebp
  9. char **gl_pathv; //r15
  10. const char *v7; //rax
  11. const char *v8; // r13
  12. intv9; //eax
  13. __int64 v10; // r13
  14. char *v11; //rax
  15. __int64 disk_name; //r15
  16. inttmp_disk_type; //eax
  17. unsigned intv14; //ebx
  18. glob64_tpglob; // [rsp+10h] [rbp-88h] BYREF
  19. unsigned__int64 v18; // [rsp+58h] [rbp-40h]
  20. v18=__readfsqword(0x28u);
  21. memset(&pglob, 0, sizeof(pglob));
  22. if (check_type<= 0 &&disk_type
  23. || ((unsigned__int8)check_type& (disk_type== 0LL)) != 0
  24. || !disk_list
  25. || !*disk_list
  26. || !glob_list)
  27. {
  28. v14= -1;
  29. __syslog_chk(3LL, 1LL, "%s:%d Bad parameter", "external/external_disk_port_enum.c", 42LL);
  30. gl_pathv=pglob.gl_pathv;
  31. gotoLABEL_29;
  32. }
  33. should_check_type=disk_type!= 0LL &&check_type> 0;
  34. if ( *(int *)(glob_list+ 4) <= 0 )
  35. return 0;
  36. index= 0;
  37. while ( 1 )
  38. {
  39. v7= (const char *)list_get(glob_list,index);
  40. memset(&pglob, 0, sizeof(pglob));
  41. v8=v7;
  42. //Return value 0 means matched
  43. v9=glob64(v7, 8, 0LL, &pglob);
  44. if (v9)
  45. break;
  46. gl_pathv=pglob.gl_pathv;
  47. if (pglob.gl_pathc)
  48. {
  49. v10= 0LL;
  50. while ( 2 )
  51. {
  52. v11=strrchr(gl_pathv[v10], '/'); // find the last /
  53. if ( !v11)
  54. gotoLABEL_21;
  55. disk_name= (__int64)(v11+ 1);
  56. tmp_disk_type=get_disk_type_by_name(v11+ 1);
  57. if (should_check_type)
  58. {
  59. if (tmp_disk_type== *disk_type)
  60. gotoLABEL_19;
  61. }
  62. else if (tmp_disk_type!= 10 )
  63. {
  64. LABEL_19:
  65. list_insert((__int64)disk_list,disk_name);
  66. }
  67. gl_pathv=pglob.gl_pathv;
  68. LABEL_21:
  69. if (pglob.gl_pathc<= ++v10)
  70. break;
  71. continue;
  72. }
  73. }
  74. LABEL_12:
  75. if (gl_pathv)
  76. globfree64(&pglob);
  77. if ( *(_DWORD*)(glob_list+ 4) <= ++index)
  78. {
  79. gl_pathv=pglob.gl_pathv;
  80. v14= 0;
  81. gotoLABEL_29;
  82. }
  83. }
  84. if (v9== 2 )
  85. {
  86. __syslog_chk(3LL, 1LL, "%s:%d read error :%s", "external/external_disk_port_enum.c", 58LL,v8);
  87. gotoLABEL_27;
  88. }
  89. if (v9!= 1 )
  90. {
  91. gl_pathv=pglob.gl_pathv;
  92. if (v9!= 3 )
  93. gotoLABEL_28;
  94. gotoLABEL_12;
  95. }
  96. __syslog_chk(
  97. 3LL,
  98. 1LL,
  99. "%s:%d out of memory to alloc glob function when looking for:%s",
  100. "external/external_disk_port_enum.c",
  101. 60LL,
  102. v8);
  103. LABEL_27:
  104. gl_pathv=pglob.gl_pathv;
  105. LABEL_28:
  106. v14= -1;
  107. LABEL_29:
  108. if (gl_pathv)
  109. globfree64(&pglob);
  110. returnv14;
  111. }

exist SYNODiskPathGlobAndPortCheckThe logic is to find the disk according to the disk type, and then check it in reverse. If the type matches, add it to the list (line 58). The default SATA disk type is 1. To remove this type of check, in order to find the installation disk, we will reverse this. After rebuilding the boot and starting, the disk can be found normally on the installation page, and the installation is successful, entering the restart process.

4. After installing the system, still enter ramdisk

The installation was successful, but I found that it still entered ramdisk mode after restarting. After checking the log, I found the following error:

  1. SystemvolumeisassembledwithSSDCacheonly,please remove SSDCache and thenreboot

This error is/linuxrc.syno.implThe check done in means that the system disk cannot beSSD Cache, specific code:

  1. SupportSSDCache=`/bin/get_key_value /etc.defaults/synoinfo.conf support_ssd_cache`
  2. if [ "$SupportDualhead" != "yes" ] && [ "${SupportSSDCache}" = "yes" ] && [ -d"/sys/block/md0" ]; then
  3. WithInternal=0
  4. has_md0disk=0
  5. # check if any disk is INTERNAL, otherwise return fail
  6. forpathin /sys/block/md0/md/dev-*; do
  7. [ -e"$path" ] || continue
  8. disk="$(basename "$path"| cut -c 5-)"
  9. [ -z"$disk" ] && continue
  10. has_md0disk=1
  11. PortType=`/usr/syno/bin/synodiskport -portcheck "${disk}"`
  12. if [ "${PortType}" = "SAS" ] || [ "${PortType}" = "SATA" ] || [ "${PortType}" = "SYS" ]; then
  13. WithInternal=1
  14. fi
  15. done
  16. # has raid0 and not composed by internal disk
  17. if [ "$has_md0disk" = 1 ] && [${WithInternal} -eq0 ]; then
  18. echo"System volume is assembled with SSD Cache only, please remove SSD Cache and then reboot" >> /var/log/messages
  19. Exit 8 "System volume is assembled with SSD Cache only"
  20. fi
  21. fi

That’s easy, just replace it directly when compiling and booting:sed -i 's/WithInternal=0/WithInternal=1/' ${RAMDISK_PATH}/linuxrc.syno.impl

5. Enter the system normally

After recompiling and booting, I finally entered the system normally, but there was a new problem: the NVMe disk could not be found in the storage manager, so I continued to explore. After trying to add a sata disk, the operation is normal. There may still be a problem when viewing the disk (because there is no sata disk). After checking the log, the corresponding error is found:

  1. 2023-04-12T2225+08:00 TestSA6400scemd[17874]:disk/disk_info_enum.c:297cann
  2. 't find enumlist_det, try to diskInfoEnum failed
  3. 2023-04-12T2225+08:00 TestSA6400 scemd[17874]: disk/shared_disk_info_enum.c::
  4. 84 Failed to allocate list in SharedDiskInfoEnum, errno=0x900.

SharedDiskInfoEnumIt should be a specific function name, but it must have been stripped away. Search for string keywords.

In the system installed by Synologyscemdthan in ramdiskscemdThe binary is much smaller and is dynamically linked. After searching around, I found that the relevant functions are inlibhwcontrol.so.1in , referencescemdAfter the modification in , it was found that the number of disks had doubled. If we continue to analyze, it should be that disk type 1 returned 3 NVMe disks, and disk type 7 also returned the same disk, so here we choose to skip the check that disk type 1 was not found, which corresponds to line 23 of the pseudocode below.v1 < 0.

Pseudocode in IDA:

  1. __int64 __fastcallSLIBDiskInfoEnumToCache(__int64 a1)
  2. {
  3. intv1; //r12d
  4. intv2; // r13d
  5. intv3; // r14d
  6. intv4; //r15d
  7. intv5; //eax
  8. intv6; //ebp
  9. FILE*v7; //rbx
  10. _QWORD*v8; //rbp
  11. unsigned intv9; //ebx
  12. intv11; // [rsp+Ch] [rbp-4Ch]
  13. void *ptr[9]; // [rsp+10h] [rbp-48h] BYREF
  14. ptr[1] = (void *)__readfsqword(0x28u);
  15. ptr[0] = 0LL;
  16. v1=enumerate_disks_by_type((__int64)ptr, 1LL,a1);
  17. v2=enumerate_disks_by_type((__int64)ptr, 3LL,a1);
  18. v3=enumerate_disks_by_type((__int64)ptr, 7LL,a1);
  19. v4=enumerate_disks_by_type((__int64)ptr, 11LL,a1);
  20. v11=enumerate_disks_by_type((__int64)ptr, 4LL,a1);
  21. v5=enumerate_disks_by_type((__int64)ptr, 2LL,a1);
  22. if (v1< 0 ||v2< 0 ||v3< 0 ||v4< 0 ||v11< 0 || (v6=v5,v5< 0) )
  23. {
  24. v9= -1;
  25. }
  26. else
  27. {
  28. v7=fopen64("/tmp/enumlist_det.tmp", "wb");
  29. if (v7)
  30. {
  31. v8=ptr[0];
  32. if (ptr[0] )
  33. {
  34. do
  35. {
  36. if ( !*v8)
  37. break;
  38. sub_40AE0(v7);
  39. v8= (_QWORD*)v8[1];
  40. }
  41. while (v8);
  42. }
  43. fclose(v7);
  44. v9=rename("/tmp/enumlist_det.tmp", "/tmp/enumlist_det");
  45. if (v9)
  46. {
  47. v9= 0;
  48. __syslog_chk(
  49. 4LL,
  50. 1LL,
  51. "%s:%d Failed to rename %s into %s.",
  52. "disk/disk_info_enum.c",
  53. 456LL,
  54. "/tmp/enumlist_det.tmp",
  55. "/tmp/enumlist_det");
  56. }
  57. }
  58. else
  59. {
  60. v9=v6+v11+v4+v3+v1+v2;
  61. __syslog_chk(3LL, 1LL, "%s:%d fail to save enumlist, device is busy....n", "disk/disk_info_enum.c", 441LL);
  62. }
  63. }
  64. DiskInfoEnumFree(ptr[0]);
  65. returnv9;
  66. }

Update againlibhwcontrol.so.1And after restarting, the storage management disk displays normally.

6. Create storage pool page without RAID type

sa6400-nvme-install-no-raid-type.png

Go back to storage management again, choose to create a storage pool, and find that the RAID type is empty. You can already see the specific disk. I guess it is probably a problem with the front-end logic. After some searching, I found the following piece of code in storage_panel.js:

  1. isCacheTray() {
  2. return "cache" === this.portType
  3. }
  4. raidTypeStore() {
  5. if (SYNO.SDS.StorageUtils.isSingleBay() && (!this.isNeedSelectSource|| "internal" === this.selectDiskSource))
  6. return [{
  7. label: this.T("volume", "volume_type_basic"),
  8. value: "basic"
  9. }];
  10. lete= []
  11. ,t= 0
  12. ,s= {}
  13. ,i= (e,t,s)=>{
  14. this.raidTypeSupportTable[s].support&&e&&t.push({
  15. label: this.raidTypeSupportTable[s].label,
  16. value:s
  17. })
  18. }
  19. ;
  20. for (lete ofthis.disks) {
  21. if ("disabled" ===e.portType||e.isCacheTray())
  22. continue;
  23. lett,i=e.container;
  24. if ("number" != typeofs[i.order]) {
  25. if ("ebox" ===i.type) {
  26. if (SYNO.SDS.StorageUtils.supportSas&& this.env.AHAInfo)
  27. t= this.env.AHAInfo.enclosures[i.order- 1].max_disk;
  28. else if (t=SYNO.SDS.StorageUtils.GetEboxBayNumber(i.str),
  29. 0 ===t)
  30. continue
  31. } else
  32. t= +this.D("maxdisks", "1");
  33. s[i.order] =t
  34. }
  35. }
  36. for (let[e,i]ofObject.entries(s))
  37. SYNO.SDS.StorageUtils.isSupportRaidCross() ?t+=i:t= Math.max(t,i);
  38. returnSYNO.SDS.StorageUtils.supportRaidGroup|| !SYNO.SDS.StorageUtils.isSupportSHR() || "pool_type_multi_volume" !== this.poolType|| this.S("ha_running") || (i(1 <=t,e, "shr"),
  39. i(4 <=t,e, "shr_2")),
  40. i(2 <=t,e, "raid_1"),
  41. i(3 <=t,e, "raid_5"),
  42. i(4 <=t,e, "raid_6"),
  43. i(4 <=t,e, "raid_10"),
  44. i(1 <=t,e, "basic"),
  45. i(1 <=t,e, "raid_linear"),
  46. i(2 <=t,e, "raid_0"),
  47. i(SYNO.SDS.StorageUtils.supportDiffRaid&& 3 <=t,e, "raid_f1"),
  48. e
  49. }

Here are 22 linesif ("disabled" === e.portType || e.isCacheTray())All SSD Cache disks will be skipped. Since we do not have SATA disks, if we skip them all, there will naturally be no disk to judge the RAID type, so we will skip it here.e.isCacheTray()inspection.

Force refresh the browser cache and finally feel free to create NVMe storage pools.

Screenshot of results:

sa6400-nvme-install-raid-type.png

sa6400-nvme-install-storage-manager.png

Summary of related modifications

ramdisk related modifications

  1. Replace under ramdiskscemd,jump over disk typeCheck, corresponding function search keyword:external_disk_port_enum
  2. Modify /linuxrc.syno.impl:sed -i 's/WithInternal=0/WithInternal=1/' ${RAMDISK_PATH}/linuxrc.syno.impl

Relevant modifications after installing the system

  1. Replace libhwcontrol.so.1 under the system and skip the check to find the SATA disk. The corresponding function is:SLIBDiskInfoEnumToCache
  2. Modify storage_panel.js:e.portType||e.isCacheTray()->e.portTypeto load the correct disk RAID type

Newsletter Updates

Enter your email address below and subscribe to our newsletter