Created
January 16, 2025 12:21
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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