Backstory

About a year ago I bought an external SATA drive for backups. My normal usage consisted of:

Power on and connect the drive mount /media/backup Run my backup script umount /media/backup Power off and unplug the drive

This seemed to work pretty well–at the very least, I wasn’t losing data–except the drive made a strange sound when I powered it off. It wasn’t a normal drive spin down sound; it was louder and shorter. So, I googled for authoritative instructions on using external drives with Linux. While most sources suggest doing exactly what I did, it’s not ideal.

It turns out that most cheap external USB/SATA/firewire enclosures don’t properly issue a stop command to the drive when you flick the power switch. Instead, the power switch simply cuts power to the drive, which forces the drive to do an emergency head retract. If you think that sounds bad, you’re right. Emergency retracts aren’t going to brick your drive immediately, but if they occur regularly they’re putting a lot of unnecessary wear and tear on the drive. In fact, some drives monitor how often this happens with S.M.A.R.T. attribute 192. (Check Wikipedia’s S.M.A.R.T. page for a comprehensive list of attributes)

Solution

The solution is to spin down the drive via software before turning it off and unplugging it. The best way to do this is with a utility called scsiadd. This program can add and remove drives to Linux’s SCSI subsystem. Additionally, with fairly modern kernels, removing a device will issue a stop command, which is exactly what we’re looking for. Run:

$ sudo scsiadd -p

which should print something like:

Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: ATA Model: SAMSUNG HD300LJ Rev: ZT10 Type: Direct-Access ANSI SCSI revision: 05 Host: scsi4 Channel: 00 Id: 00 Lun: 00 Vendor: LITE-ON Model: DVDRW LH-20A1L Rev: BL05 Type: CD-ROM ANSI SCSI revision: 05 Host: scsi5 Channel: 00 Id: 00 Lun: 00 Vendor: ATA Model: WDC WD10EACS-00Z Rev: 01.0 Type: Direct-Access ANSI SCSI revision: 05

Identify the drive you want to remove and then issue:

$ sudo scsiadd -r host channel id lun

substituting the corresponding values from the scsiadd -p output. For example, if I wanted to remove “WDC WD10EACS-00Z”, I would run:

$ sudo scsiadd -r 5 0 0 0

If everything works, scsiadd should print:

Attached devices: Host: scsi0 Channel: 00 Id: 00 Lun: 00 Vendor: ATA Model: SAMSUNG HD300LJ Rev: ZT10 Type: Direct-Access ANSI SCSI revision: 05 Host: scsi4 Channel: 00 Id: 00 Lun: 00 Vendor: LITE-ON Model: DVDRW LH-20A1L Rev: BL05 Type: CD-ROM ANSI SCSI revision: 05

You can double-check the end of dmesg. You should see:

[608188.235216] sd 5:0:0:0: [sdb] Synchronizing SCSI cache [608188.235362] sd 5:0:0:0: [sdb] Stopping disk [608188.794296] ata6.00: disabled

At this point, the drive is removed from Linux’s SCSI subsystem and it should not be spinning. It’s safe to unplug and turn off.

Using scsiadd directly can be inconvenient because it requires looking up the host, channel, id, and lun of the drive. I wrote a short script that will take a normal Linux device file like /dev/sdb, figure out the correct arguments to scsiadd, and run scsiadd -r. I use this script in my larger backup script.

#!/bin/sh if [ $# -ne 1 ]; then echo "Usage: $0 " exit 1 fi if ! which lsscsi >/dev/null 2>&1; then echo "Error: lsscsi not installed"; exit 1 fi if ! which scsiadd >/dev/null 2>&1; then echo "Error: scsiadd not installed" exit 1 fi device=`lsscsi | grep $1` if [ -z "$device" ]; then echo "Error: could not find device: $1" exit 1 fi hcil=`echo $device | awk \ '{split(substr($0, 2, 7),a,":"); print a[1], a[2], a[3], a[4]}'` scsiadd -r $hcil

It does require the lsscsi command to be present on the system.