Yottamaster Y-Focus 4 Bay External Hard Drive Enclosure

I was looking for an external enclosure to hold a couple of disks to use in a ZFS pool, so I bought the Yottamaster Y-Focus 4 Bay External Hard Drive Enclosure. Here are my experiences with it.

There are three variants of this hardware.

The "NO RAID USB3.0" (FS4Ue)

a USB 5Gbps port in front of a JMS578 USB-to-SATA bridge controller + a JMB575 port multiplier;

I would avoid this one because I frown on port multipliers
The "RAID USB 3.0" (FS4RU3)

a USB 5 Gbps port in front of a JMS587 + a JMB394 RAID port multiplier;

I would avoid this one because I frown on cheap RAID controllers
The "Daisy Chain TYPE-C(No Raid)" (FS4C3)

a USB 10 Gbps port in front of a VL822 USB hub controller + one VL715 USB to SATA bridge controller per drive;

this is the one I bought!

Hardware

Photo of the enclosure

It's decent, feels reasonably solid.

There's an LED that lights up blue for each populated bay. This is very dim, and hard to see unless you're up close & looking directly at the enclosure.

The fan is quiet & keeps the drives cool.

Photo of a drive sled

The sleds are also reasonably solid. Drives are screwed in, and screws & a screwdriver are provided. You could put a small sticker on the non-vented part of the front of the sled if you wanted to have an externally-visible identifier. Sleds can be bought separately & are common across many different Yottamaster enclosures.

Block diagram

block-diagram.png

Performance & Reliability

Before putting it into service I did some benchmarking with two disks, and I found I could read and write at the disks' maximum speeds simultaneously.

It's now been in service for many months, using two of the bays for a mirror vdev within a ZFS pool and it's worked perfectly.

Obviously it uses a USB type C connector, so one has to be careful to avoid accidental disconnections!

USB topology

It shows up as a USB hub (2-1):

$ lsusb.py
usb2              1d6b:0003 09 1IF  [USB 3.10, 10000 Mbps,   0mA] (xhci-hcd 0000:00:14.0) hub
  2-1               2109:0822 09 1IF  [USB 3.20, 10000 Mbps,   0mA] (VIA Labs, Inc. USB3.1 Hub 000000001) hub
    2-1.1             174c:55aa 00 1IF  [USB 3.00,  5000 Mbps,   0mA] (ULT-Best Best USB Device 0419111457B0)
    2-1.3             2109:0822 09 1IF  [USB 3.20, 10000 Mbps,   0mA] (VIA Labs, Inc. USB3.1 Hub 000000001) hub
      2-1.3.2           2109:0715 00 1IF  [USB 3.10, 10000 Mbps,   8mA] (VLI Manufacture String VLI Product String 000000123AE8)
      2-1.3.4           2109:0715 00 1IF  [USB 3.10, 10000 Mbps,   8mA] (VLI Manufacture String VLI Product String 000000123AE8)

The hub has two downstream ports.

Port 1 is the "HUB" connector on the rear.

Port 3 is a second, internal USB hub.

Storage topology

It's UASP.

The USB/SATA controller munges the disk's ATA model number string into the SCSI vendor and product strings, truncating it in the process. The ATA firmware version string gets munged into the SCSI revision string, also truncated.

$ lsscsi
[...]
[10:0:0:0]   disk    WDC WD16 1KFGX-68CMAN     83.0  /dev/sdg 
[11:0:0:0]   disk    WDC WD16 1KFGX-68CMAN     83.0  /dev/sdi 

We can match up the kernel device names to USB bus/port topology/interface if we enable the output of transport information:

$ lsscsi -t 
[10:0:0:0]   disk    usb:2-1.3.2:1.0                 /dev/sdg 
[11:0:0:0]   disk    usb:2-1.3.4:1.0                 /dev/sdi 

But we don't want to use unstable device names, we need stable identifiers. Let's see what symlinks have been formed for each device:

$ parallel -r --tag 'udevadm info {} | grep ^S: | sort' ::: /dev/sd{g,i}
/dev/sdg        S: disk/by-diskseq/7
/dev/sdg        S: disk/by-id/scsi-35000cca012345678
/dev/sdg        S: disk/by-id/scsi-SWDC_WD16_1KFGX-68CMAN_000000123AE8
/dev/sdg        S: disk/by-id/usb-WDC_WD16_1KFGX-68CMAN_000000123AE8-0:0
/dev/sdg        S: disk/by-path/pci-0000:00:14.0-usb-0:1.3.2:1.0-scsi-0:0:0:0
/dev/sdi        S: disk/by-diskseq/9
/dev/sdi        S: disk/by-id/scsi-35000cca9abcdef01
/dev/sdi        S: disk/by-id/scsi-SWDC_WD16_1KFGX-68CMAN_000000123AE8
/dev/sdi        S: disk/by-id/usb-WDC_WD16_1KFGX-68CMAN_000000123AE8-0:0
/dev/sdi        S: disk/by-path/pci-0000:00:14.0-usb-0:1.3.4:1.0-scsi-0:0:0:0

Uh oh... the usual by-id/usb-$env{ID_USB_SERIAL} and by-id/scsi-S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL} symlinks have the same value for both disks!

Fortunately there are other options.

The SCSI identifier can be displayed by lsscsi:

$ lsscsi --wwn -i
[10:0:0:0]   disk    WDC WD16 1KFGX-68CMAN     83.0  0x5000cca012345678                  /dev/sdg   35000cca012345678
[11:0:0:0]   disk    WDC WD16 1KFGX-68CMAN     83.0  0x5000cca9abcdef01                  /dev/sdi   35000cca9abcdef01

It seems the first digit, 0x3, indicates that the identifier is "NAA based" (i.e., based off a WWN in NAA format). Then the WWN follows, so the next digit, 0x5 indicates the WWN is in NAA format. The next six digits are the vendor OUI; 00:0c:ca is "HGST A Western Digital Company". The final nine digits are the vendor-assigned identifier, unique to each disk.

So we can use the by-path/* symlinks to persistently reference a disk by its position in the storage toplogy; or the by-id/scsi-3* symlinks to reference a disk by its internal persistent identifer, respectively.

SATA Passthrough

hdparm works fine.

smartctl also works.
It recognizes the VL715 USB to SATA bridge controller and automatically acts as if -d sat was on the command line.

Disk sleep timer

The only niggle I have with this enclosure is that it does want to spin disks down if they're not accessed for a few minutes. Yottamaster provide a Windows utility that reprograms the enclosure's EEPROM to disable the sleep timer, but I am not using Windows.

There's a hacky but simple and reliable workaround; assuming a filesystem is mounted at /srv/data then keep-awake@srv-data.service will write some data to the disk every few minutes, preventing it from going to sleep:

$ systemctl cat keep-awake@srv-data.service
# /etc/systemd/system/keep-awake@.service
[Unit]
Description=Keep disks backing /%I awake
ConditionPathIsMountPoint=/%I
RequiresMountsFor=/%I

[Service]
Type=exec
ExecStart=/bin/bash -c 'set -eEuo pipefail; while true; do if mountpoint -q /%I; then dd if=/dev/zero bs=16 count=1 of=/%I/.keep-awake oflag=sync status=none; fi; sleep $((300 + ((RANDOM-16383) >> 8))); done'

[Install]
WantedBy=multi-user.target

Conclusion

Overall, I'm pleasantly surprised.


CategoryTechnote

robots.org.uk: YFocus4BayEnclosure (last edited 2025-10-29 20:58:15 by sam)

© Sam Morris <sam@robots.org.uk>.
Content may be distributed and modified providing this notice is preserved.