Using "eject -s /dev/sdx" appears to send more then only the SCSI eject command over USB/MSC connection

I am writing embedded STM32 processor code and using the’s USB drivers. There is no other software running on the STM32 processor. It is a bit unusual, but we have managed to configure the STM32 processor to switch from a USB/CDC to a USB/MSC device on command. The problem is to find a way to switch back from USB/MSC to USB/CDC.

To solve this, I believe I can connect the STM32 based device using a USB cable to a Ubuntu computer and send an SCSI Eject command. However this does not always work. I find I have to send the SCSI Eject command at least twice. And, on occasion, as many as 5 times before my STM32 code sees 1 Eject event. Why?

To verify the STM32 code works, I then connected the STM32 based device to a Windows 10 machine. Using the Eject feature found in the Windows File Explorer, I was able to see every Eject event the Windows 10 machine sent to the STM32 based device. So, it would appear the STM32 code and USB drivers work (with Windows 10).

Going deeper…

I ran the STM32 processor debugger while the STM32 based device was connected to the Ubuntu computer. While debugging the’s USB driver, I observed that all USB/MSC SCSI Eject commands are seen. However, the driver over writes the eject flag with other USB/MSC states such as LOCK and UNLOCK before my code sees the EJECT state. Here is that segment of code that can be found a

if ((params[4] & 0x3U) == 0x1U) /* START=1 */
hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
else if ((params[4] & 0x3U) == 0x2U) /* START=0 and LOEJ Load Eject=1 */
hmsc->scsi_medium_state = SCSI_MEDIUM_EJECTED;
else if ((params[4] & 0x3U) == 0x3U) /* START=1 and LOEJ Load Eject=1 */
hmsc->scsi_medium_state = SCSI_MEDIUM_UNLOCKED;
/* .. */

Is it that Ubuntu sends more then just the SCSI eject commands when the:

eject -s /dev/sdx

…command is used? Is there any way to only send the SCSI Eject command over the USB/MSC connection from Ubuntu?

Asked By: st2000


eject sends ‘ALLOW MEDIUM REMOVAL’ and then ‘START STOP’ SCSI commands to eject the device.

I’ve looked over the eject’s source code.
What happens during ‘eject -s’ is the invocation of eject_scsi function, during which the following happens:

  1. Struct sg_io_hdr_t, which is used to send the SCSI commands, is
  2. SCSI command ‘ALLOW_MEDIUM_REMOVAL‘ (allowRmBlk) is issued.
  3. If allowRmBlk succeeded, SCSI command ‘START_STOP‘ (startStop1Blk)
    is issued.
  4. If succeeded, SCSI command ‘START_STOP‘ (startStop2Blk) is issued again with different options.

allowRmBlk, startStop1Blk and startStop2Blk are what is used in the actual source code, but I have also shown the actual commands used with them in the code (as they’re defined) – the difference between startStop1Blk and startStop2Blk are:

unsigned char startStop1Blk[6] = {START_STOP, 0, 0, 0, 1, 0};
unsigned char startStop2Blk[6] = {START_STOP, 0, 0, 0, 2, 0};

I am not sure what do you mean by "send only the SCSI EJECT command", but assuming you mean the SCSI command that is responsible for ejection, then eject does issue only them.

According to the Seagate’s SCSI command reference, START STOP UNIT is the proper command to handle ejection. Excerpt below:

SCSI command reference excerpt

Answered By: kishkovert