Skip to content

Instantly share code, notes, and snippets.

@griznog
Created January 16, 2025 12:21
Show Gist options
  • Save griznog/09f13c59b1a0dbeddd011bd8a08291f8 to your computer and use it in GitHub Desktop.
Save griznog/09f13c59b1a0dbeddd011bd8a08291f8 to your computer and use it in GitHub Desktop.
Script to check and optionally set LBA size to 4k on Western Digital drives.
#!/bin/bash
# Author: griznog
# Purpose: Set any 512b sector drives to 4k sectors.
#
# Notes:
# * Targets all drives using multipath.
# Exit on error convenience function.
function die(){
echo $*
exit 1
}
# Check current LBA:
function lba_is_4k () {
local device=/dev/$1
local retval=0
[[ -e ${device} ]] || die "${device} not found."
LBA=$(smartctl -a ${device} | awk '/Logical block size:/ {print $4}')
if [[ ${LBA} -eq 4096 ]]; then
retval=0
elif [[ ${LBA} -eq 512 ]]; then
retval=1
else
die "smartctl -a ${device} | awk '/Logical block size:/ {print \$4}' failed to find LBA size."
fi
return ${retval}
}
function lba_set_4k () {
local device=/dev/$1
local retval=0
# Abort script if ${device} not found. Seems harsh, but probably indicates
# the controller has lost it's mind and device names *may* be changing while
# this script is running.
[[ -e ${device} ]] || die "${device} not found."
# Change the disk format.
echo "Setting ${device} to 4k sector LBA."
sg_format ${device} --format --ffmt=1 --size=4096 --count=-1 --wait --quick
retval=$?
if [[ ${retval} -ne 0 ]]; then
die "ERROR: Setting ${device} to 4k sectors failed."
else
echo "Sleeping 5s after setting LBA to prevent bus resets."
sleep 5s
fi
return ${retval}
}
# Check for command line argument.
expected=$1
if [[ -z "${expected}" ]] || [[ "${expected}" -lt 0 ]] || [[ ${expected} -gt 1024 ]]; then
die "Need 1 argument for number of drives to expect."
fi
# Collect a list of drives, use the first reported path.
# Collect devices from each enclosure.
devices=( $(sas_devices -v | awk '/35000/ {print $1 "," $4 "," $5 "," $10}') )
# Verify drive count matches expected.
[[ ${#devices[*]} -eq ${expected} ]] || die "Expected ${expected} devices, found ${#devices[*]}"
# Check the drives and display the serial number of 512b sector devices.
# We do this by serial because checking these in bulk may trigger drive/controller resets
# which will cause multipath falures and result in the device name changing. YMMV.
if ! [[ ${PLEASE_DESTROY_MY_DRIVES} == "YES" ]]; then
echo "# Checking LBA format only."
echo "# Set PLEASE_DESTROY_MY_DRIVES=YES to immediately convert to 4k sectors."
echo "# You can also pipe the output of this script to BASH."
echo "$ Please also verify that for your drives "--ffmt=1" is the right thing to do."
echo "# You can also see Western Digital to get the HUGO utility and use it to set LBA size."
fi
# Let's probe some drives. No alien abduction needed.
for device in ${devices[*]}; do
record=( ${device//,/ } )
bay=${record[0]}
wwn=${record[1]}
dev1=${record[2]}
dev2=${record[3]}
sn=${record[4]}
if ! lba_is_4k ${dev1}; then
if [[ ${PLEASE_DESTROY_MY_DRIVES} == "YES" ]]; then
lba_set_4k ${dev1}
else
# Show serial number of discovered 512b sector device in case we need to track down a failure later.
echo "# Drive: ${sn}"
echo "sg_format /dev/${dev1} --format --ffmt=1 --size=4096 --count=-1 --wait --quick && sleep 5s"
echo
fi
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment