Hi all, I am using the stm32usb_mem keil example for USB mass storage implementation. It is working well as mass storage device. I found that when i right click the device to use the eject option. I got an error message "An error was encountered trying to eject Device(G:)". The device cannot be removed. Anyone can solve this problem.
Thanks Aru
It seems that problem is that that example uses too small memory and when windows wants to eject it wants to write to disk but it is too small end there are problems. Try Memory_FlashFS\SD_File\ example.
Hi wild, Thanks for your reply. I checked the USB protocol while the eject process. I found that using debug message,the PC requests following commands SCSI_MEDIA_REMOVAL and SCSI_START AND STOP UNIT,SCSI_MODE_SELECT 10,but these commands are not implemented in the USB protocol. Can i know how to implement these commands that will be supported by USB protocol. Thanks
Hi Wild, Thanks for your reply......... I checked the USB protocol as your suggestion and found that the PC does not requests the SCSI_WRITE10 command during eject process. Can i know the location of Memory_FlashFS\SD_File\ example. Thanks
It is in folder where you installed MDK something like C:\Keil\ARM\Boards\"Vendor"\"Board"\RL\USB\Device\Memory_flashFS\SD_File\ (for example for NXP MCB2300 board C:\Keil\ARM\Boards\Keil\MCB2300\RL\USB\Device\Memory_FlashFS\SD_File\)
Unfortunately not all boards have this example.
Sorry, I now saw you are talking about STM32 it should be in folder C:\Keil\ARM\Boards\Keil\MCBSTM32\RL\USB\Device\Memory_FlashFS\SD_File\
> I found that using debug message,the PC requests following commands SCSI_MEDIA_REMOVAL and SCSI_START AND STOP UNIT,SCSI_MODE_SELECT 10,but these commands are not implemented in the USB protocol. > Can i know how to implement these commands that will be supported by USB protocol.
Does your drive have auto-eject capability?
OS puts PREVENT ALLOW MEDIUM REMOVAL(PREVENT:01b - prohibit removal), to know the auto-eject capability of the drive on mount.
a) Auto eject drive If the device succeeds on this command, OS assumes auto-eject capability of the reader. On drag-to-trash eject, OS writes the write cache to the media. And then, it puts this command sequence, to eject the media by command.
- PREVENT ALLOW MEDIUM REMOVAL(PREVENT:00b - allow removal) - START STOP UNIT(IMMED:0, POWER CONDITION:0h(START_VALID), LOEJ:1, START:0) - unload medium
[58.672,342] FS: Data Transfer (Bulk-OUT) Addr:04 Endp:1 - CBW: PREVENT ALLOW MEDIUM REMOVAL 55 53 42 43 91 00 00 00 00 00 00 00 00 00 06 1E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [58.672,520] FS: Data Transfer (Bulk-IN) Addr:04 Endp:1 - CSW - Status:Passed 55 53 42 53 91 00 00 00 00 00 00 00 00 [58.672,681] FS: Data Transfer (Bulk-OUT) Addr:04 Endp:1 - CBW: START STOP UNIT 55 53 42 43 92 00 00 00 00 00 00 00 00 00 06 1B 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 [58.672,832] FS: Data Transfer (Bulk-IN) Addr:04 Endp:1 - CSW - Status:Passed 55 53 42 53 92 00 00 00 00 00 00 00 00
After START STOP UNIT, the device should fail TEST UNIT READY and other commands, because of no media.
b) Manual eject Manual eject reader should fail PREVENT ALLOW MEDIUM REMOVAL(PREVENT:01b) at the mount of a media. The Sense Data for this fail is, - Sense Key: ILLEGAL REQUEST (0x05) - ASC/ASCQ : INVALID COMMAND OPERATION CODE (0x20/0x00)
0x70, // response code 0x00, // obsolete 0x05, // sense key - ILLEGAL REQUEST 0x00, // information 0x00, 0x00, 0x00, 0x0A, // additional sense length - 10 bytes 0x00, // command-specific info 0x00, 0x00, 0x00, 0x20, // additional sense code - INVALID COMMAND OPERATION CODE 0x00, // additional sense code qualifier 0x00, // field replacement unit code 0x00, // sense key specific 0x00, 0x00
On eject, OS writes the write cache to the media. And then, it polls completion of manual eject using TEST UNIT READY
Tsuneo
Hi chinzei, Thanks for your explanation. I understand your words. This is my debug output. When the OS ejects the drive.... SCSI_MEDIA_REMOVAL MSC_SetCSW SCSI_MODE_SELECT6 fail MSC_SetCSW SCSI_START_STOP_UNIT MSC_SetCSW SCSI_MEDIA_REMOVAL MSC_SetCSW SCSI_MODE_SELECT6 fail MSC_SetCSW MSC_RequestSense MSC_SetCSW MSC_TestUnitReady MSC_SetCSW
CSW Status is Passed in these commands SCSI_MEDIA_REMOVAL and SCSI_START_STOP_UNIT,but failed in SCSI_MODE_SELECT6,because it is not implemented in this Keil example protocol.
Can you find my mistake in this implementation
this is my source code:
void MSC_RequestSense (void) {
if (!DataInFormat()) return;
BulkBuf[ 0] = 0x70; /* Response Code */ BulkBuf[ 1] = 0x00; BulkBuf[ 2] = 0x02; /* Sense Key */ BulkBuf[ 3] = 0x00; BulkBuf[ 4] = 0x00; BulkBuf[ 5] = 0x00; BulkBuf[ 6] = 0x00; BulkBuf[ 7] = 0x0A; /* Additional Length */ BulkBuf[ 8] = 0x00; BulkBuf[ 9] = 0x00; BulkBuf[10] = 0x00; BulkBuf[11] = 0x00; BulkBuf[12] = 0x30; /* ASC */ BulkBuf[13] = 0x01; /* ASCQ */ BulkBuf[14] = 0x00; BulkBuf[15] = 0x00; BulkBuf[16] = 0x00; BulkBuf[17] = 0x00;
BulkLen = 18; DataInTransfer(); }
void MSC_ModeSense6 (void) {
BulkBuf[ 0] = 0x03; BulkBuf[ 1] = 0x00; BulkBuf[ 2] = 0x00; BulkBuf[ 3] = 0x00;
BulkLen = 4; DataInTransfer(); }
/* * MSC SCSI Mode Sense (10-Byte) Callback * Parameters: None (global variables) * Return Value: None */
void MSC_ModeSense10 (void) {
BulkBuf[ 0] = 0x00; BulkBuf[ 1] = 0x06; BulkBuf[ 2] = 0x00; BulkBuf[ 3] = 0x00; BulkBuf[ 4] = 0x00; BulkBuf[ 5] = 0x00; BulkBuf[ 6] = 0x00; BulkBuf[ 7] = 0x00;
BulkLen = 8; DataInTransfer(); }
void MSC_GetCBW (void) { DWORD n;
for (n = 0; n < BulkLen; n++) { *((BYTE *)&CBW + n) = BulkBuf[n]; } if ((BulkLen == sizeof(CBW)) && (CBW.dSignature == MSC_CBW_Signature)) { /* Valid CBW */
CSW.dTag = CBW.dTag;
CSW.dDataResidue = CBW.dDataLength;
if ((CBW.bLUN != 0) || (CBW.bCBLength < 1) || CBW.bCBLength > 16) {
fail: CSW.bStatus = CSW_CMD_FAILED;
MSC_SetCSW();
} else {
switch (CBW.CB[0]) {
case SCSI_TEST_UNIT_READY:
MSC_TestUnitReady();
break;
case SCSI_REQUEST_SENSE:
MSC_RequestSense();
break; case SCSI_FORMAT_UNIT:
goto fail;
case SCSI_INQUIRY:
MSC_Inquiry();
case SCSI_START_STOP_UNIT:
CSW.bStatus = CSW_CMD_PASSED;
// goto fail;
case SCSI_MEDIA_REMOVAL:
case SCSI_MODE_SELECT6:
case SCSI_MODE_SENSE6:
MSC_ModeSense6();
break; case SCSI_MODE_SELECT10:
case SCSI_MODE_SENSE10:
MSC_ModeSense10();
break; case SCSI_READ_FORMAT_CAPACITIES:
MSC_ReadFormatCapacity();
break; case SCSI_READ_CAPACITY:
MSC_ReadCapacity();
break; case SCSI_READ10:
if (MSC_RWSetup()) {
if ((CBW.bmFlags & 0x80) != 0) {
BulkStage = MSC_BS_DATA_IN;
MSC_MemoryRead();
USB_SetStallEP(MSC_EP_OUT);
CSW.bStatus = CSW_PHASE_ERROR;
}
case SCSI_WRITE10:
if ((CBW.bmFlags & 0x80) == 0) {
BulkStage = MSC_BS_DATA_OUT;
USB_SetStallEP(MSC_EP_IN);
case SCSI_VERIFY10:
MemOK = TRUE;
default:
/* Invalid CBW */
BulkStage = MSC_BS_ERROR;
Hi Wild, Thanks for your reply Thanks
Are you working on this Keil example? "STM32 USB Mass Storage Device Example" http://www.keil.com/download/docs/362.asp
In your code, SCSI_MEDIA_REMOVAL (PREVENT ALLOW MEDIUM REMOVAL) is always accepted, as follows.
void MSC_GetCBW (void) { ... case SCSI_MEDIA_REMOVAL: CSW.bStatus = CSW_CMD_PASSED; MSC_SetCSW(); // goto fail;
Does your drive have auto-eject capability? If it doesn't, fail this command, as the original code does. MSC device doesn't need to accept every SCSI command sent by host. It should fail on unsupported SCSI commands.
Rather, a problem of the original example is, it always returns the same SenseData of NO SENSE (Key:0x00), NO ADDITIONAL SENSE INFORMATION (ASC/ASCQ=0x00/0x00). After fail of SCSI command, it should return typical SenseData, such as,
Sense Key, ASC/ASCQ NOT_READY (0x02), MEDIUM_NOT_PRESENT (0x3A/0x00) ILLEGAL REQUEST (0x05), INVALID COMMAND OPERATION CODE (0x20/0x00) UNIT_ATTENTION (0x06), NOT_READY_TO_READY_CHANGE, MEDIUM_MAY_HAVE_CHANGED (0x28/0x00) etc.
Hi chinzei, Thanks for your reply.... Yes,i am using this stm32usb_mem example. I need my drive should have auto eject capability. What are the commands and its value need to implement to work this example. Thanks a lot.......
> I need my drive should have auto eject capability.
Er.., does your drive have auto eject mechanism, such as CD/DVD tray which ejects a medium automatically? Or, do you want, by right-click eject, the drive disappears from "My Computer" window?
I observed the behavior of a couple of USB sticks on this issue (right-click, eject) on Windows. Typical responses are,
PREVENT ALLOW MEDIUM REMOVAL(PREVENT:01b - prohibit removal): fails - ILLEGAL REQUEST, INVALID COMMAND OPERATION CODE
PREVENT ALLOW MEDIUM REMOVAL(PREVENT:00b - allow removal): success
START STOP UNIT(IMMED:0, POWER CONDITION:0h(START_VALID), LOEJ:1, START:0) : success
After START STOP UNIT, the sticks fails all commands, including TEST UNIT READY, with NOT_READY, MEDIUM_NOT_PRESENT sense data.
None of USB sticks disappear from "My Computer" by right-click eject
Hi chinzei,
Thanks for your reply...
>>Er.., does your drive have auto eject mechanism, such as CD/DVD tray which ejects a medium >>automatically? >>Or, do you want, by right-click eject, the drive disappears from "My Computer" window?
I need device removal by right-click eject, the drive should disappears from "My Computer" window.
How to implement the following commands in this example?
After successfull execution of these commands...>>None of USB sticks disappear from "My Computer" by right-click eject
Did the device remove from My computer? Thanks
> I need device removal by right-click eject, the drive should disappears from "My Computer" window.
Umm... Though it isn't usual, there is no way other than soft-disconnect of the device.
USB sticks emulate SD card readers. In the view point of USB, USB stick isn't a removable disk, because its medium (memory) isn't removable. But in practice, USB sticks have been implemented as removable. I believe it's because of safety, to cancel write cache. OS writes to removable disks immediately without any write cache. When a disk is accidentally plugged off, write cache increases possibility of file system inconsistency.
After a removable drive ejects its medium, the drive itself still connects to the host PC. After CD, DVD or SD are ejected, you'll see the drive / card reader remain on "My Computer". Just like these drives, USB sticks also keep its emulated "drive" after eject. Just plug-off makes these "drives" disappear. That is, you have to plug off the stick to make it disappear.
Firmware emulates plug-off using soft-disconnect. Call USB_Connect( FALSE ), after the device finishes SCSI_START_STOP_UNIT command.
Hi chinzei, Thanks for your reply... I ejected the media as your suggestion.. The device is removed from PC and its file contents are not available..but I got an error during ejection... "An error was encountered trying to eject Device(G:)" I found from the debug message after execution of these commands:SCSI_MEDIA_REMOVAL SCSI_START_STOP_UNIT,OS sends these commands for another time. But the media is not available,it think the MEDIA is not responding and produce the error... Thanks
Hi Chinzei, Thank for your discussion... Now the device successfully removed from "My Computer" Thanks