USBHost_t36 USB Mass Storage Driver Experiments

The newer drive does not work either (I also just tried reformat on windows 10 Fat system... to see if that would change it). Again does not get to the CD... But instead of endless messages it just hangs...

One thing I noticed, that Win10 exFAT formatting did dot work here. used the SDFormatter (the official one) and it worked.
Reason (I believe) is that Win10 does not add a boot-record anymore, formats only a single volume (first record starts with 'exFAT')
 
@WMXZ Will try. Note I tried SDFormatter, including allowing resize... and it still does not read... But it now acts more like the other disk in that it does not repeat.... Just stops...
 
@WMXZ, @Kutre, @mjs513

One thing that I see in sd_msc.cpp, in the "MSC_disk_read(BYTE *buff, DWORD sector, UINT count)" and "MSC_disk_write(const BYTE *buff, DWORD sector, UINT count)" functions is
"WaitDriveReady()". I probably did not comment that out in the library I sent. Comment them out in sd_msc.cpp and see if the library stabalises. It did on my side. Not as many hangs as
before. Only when I try copy a 4.3MB file from one file to another file on the same USB drive and that seems to be due to buffer size which is using multi sector reads and writes.
 
Thanks @wwatson,

Will try it.

As I mentioned in the T4 thread, with my two thumb drives the call to mscInit is hanging, in the call to msDeviceInquiry, which has called msDoCommand,
msDoCommand has the flags of CMDDIRDATAIN so it queues the command to the datapipeOut pipe and the return buffer to the datapipeIn pipe and we make it through the two loops waiting for msOutCompleted and msInCompleted.. It then go to call msGetCSW, which queues a prefilled in buffer on the datapipeIN pipe and waits for a callback (which waits for msInCompleted which is never cleared (Callback is not called....

The last stuff in my debug output:
Code:
## mscInit before DeviceInquiry
## msDeviceInquiry before do command 36
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)
msDoCommand after msOutCompleted loop
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msDoCommand after msInCompleted loop
msGetCSW before QDT
msGetCSW after QDT

Questions I have include:

The msGetCSW is setting up transfer from the datapipeIn, and it is also prefilling the buffer it sets up to some values. Who is it that triggers something to actually be returned on this pipe?
I understand when I setup to send an INQUIRY command (setup on output pipe), that the device will respond with a Inquiry response, which will come back on the input pipe.

But does it also automatically respond with a second packet of the status block?

Do you have a link to some PDF or the like that you have been using to understand the SCSI stuff?
Maybe something like: https://www.usb.org/sites/default/files/usbmassbulk_10.pdf ?

Thanks and again good stuff!
 
Just setup TD 1.47B2 and ran uSDFS_test.ino on the T3.6 at 180MHZ and 240MHZ. Tested good on Kingston 16G flash drive and a Seagate 250GB hard drive with "WaitDriveReady()" enabled. But when I disabled "WaitDriveReady()" at 240MHZ it fails on writing to a file. On my other T3.6 system it still works at 240MHZ. There are lots of other USB drivers involved on that system. I am going to port this latest version of uSDFS over to that system and see if it reacts the same way.
Need to be able to better detect errors. "msController::checkCSW(msCommandStatusWrapper_t *CSW)" is where it is done".
 
Thanks @wwatson - Lots of information in there about the different commands and structures!

The Document I linked to in #29 from the USB Spec documents did not have any of those details, but does have some interesting stuff about CBW and CSW usages and about the handshaking between host and device and things like if a device does not like something it may stall the pipes...

For the fun of it I may try some other type of disk to see if they get beyond the INQUIRY command.
 
@PaulStoffregen - Wondering how best to do something using usbhost_t36 library. I have done some stuff in the library, but am unsure about some of the low level stuff and how best to do it...

Example: The USB document for USB Bulk storage talking about Data transfer conditions (Section 5.3) has a simple Flow chart that shows what you should do to output the next CBW.

First step after Enter: Attemt to read CSW from Bulk-In-endpoint And then a conditional box (STALL Bulk-In -OR- Bulk Error) ...


Question is how do we properly do this with our Pipes/Transfers - Currently the code simply queues up a buffer to the input pipe and waits for a response to happen (Callback function sets a completed variable)
Code:
uint8_t msController::msGetCSW() {
	uint8_t CSWResult = 0;
	msCommandStatusWrapper_t StatusBlockWrapper = (msCommandStatusWrapper_t)
	{
		.Signature = CSWSIGNATURE,
		.Tag = 0,
		.DataResidue = 0, // TODO: Proccess this if received.
		.Status = 0
	};
	println("msGetCSW before QDT");
	if (!queue_Data_Transfer(datapipeIn, &StatusBlockWrapper, sizeof(StatusBlockWrapper), this)) {
		println("msController::msGetCSW QDT failed");
	}
	println("msGetCSW after QDT");
	uint16_t timeout_loop_count=32767;
	while(!msInCompleted /*&& --timeout_loop_count*/);
	msInCompleted = false;
	CSWResult = checkCSW(&StatusBlockWrapper);
	return CSWResult;
}
This is a modified version of @wwatson's code in that I print out a few more things, check to see if the queue failed ...

The current code hangs on my machine with a couple of different USB Sticks after the INQUIRY call... I played around with timeout loop, which is shown semi-commented out...
This allowed it to continue, but then we still have the transfer structure pending on the pipe so things out of sync...

Again not sure of how to handle this. I don't know of any normal way to for example cancel a transfer? Or put in timeout? ...

Suggestions?

Kurt

P.S. - I understand you might be busy with a few other things ;)
 
@Kurte

That is where I am at with this as well. How to detect a stalled pipe and other errors or conditions that constitute performing a reset recovery.

This is the code that checks for a valid CSW:
Code:
//---------------------------------------------------------------------------
// Check for valid CSW
uint8_t msController::checkCSW(msCommandStatusWrapper_t *CSW) {

	if(CSW->Signature != CSWSIGNATURE) return MSCSWSIGERROR; // Signature error
	if(CSW->Tag != CBWTag) return MSCSWTAGERROR; // Tag mismatch error
	if(CSW->Status != 0) return CSW->Status; // Actual status from last transaction 

	return MSCOMMANDPASS; // Command transaction success (0)
}

The tag mismatch error is the most common error I get. When I hex dump the CSW the signature is there but the tag and status are always zero. Sometimes I get a status byte=1 which is an invalid CBW sent. I have never been able to detect a phase error which is status byte=2.

Section 6 in the usbmassbulk_10.pdf manual gives lots of information on how to handle error conditions.
 
@wwatson - Understand...

I did a little more hacking and maybe some of the issue is handling conditions and errors.

That is I hacked up your function:
Code:
void msController::new_dataIn(const Transfer_t *transfer)
{
	uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
	println("msController dataIn (static): ", len, DEC);
	print_hexbytes((uint8_t*)transfer->buffer, (len < 32)? len : 32 );
	if (len >= 4) {
		uint32_t l = *(uint32_t*)transfer->buffer;
		if (l == CBWSIGNATURE) println("** CBWSIGNATURE");
		else if (l == CSWSIGNATURE) println("** CSWSIGNATURE");
		else println("** ????");
	}


	msInCompleted = true; // Last in transaction is completed.
}
So I can see what data is coming back from the different commands and the like:
Code:
Test uSDFS
2:/
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20005000
periodictable = 20005000
## mscInit Called
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 00 02 09 00 01 40 E3 05 08 06 98 32 00 01 00 01 
    VendorID = 05E3, ProductID = 0608, Version = 3298
    Class/Subclass/Protocol = 9(Hub) / 0 / 1(Single-TT)
    Number of Configurations = 1
enumeration:
enumeration:
Product: USB2.0 Hub
enumeration:
Config data length = 25
enumeration:
Configuration Descriptor:
  09 02 19 00 01 01 00 E0 32 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 01 09 00 00 00 
    Interface = 0
    Number of endpoints = 1
    Class/Subclass/Protocol = 9(Hub) / 0 / 0
  07 05 81 03 01 00 0C 
    Endpoint = 1 IN
    Type = Interrupt
    Max Size = 1
    Polling Interval = 12
enumeration:
USBHub memory usage = 960
USBHub claim_device this=20004660
found possible interface, altsetting=0
number of interfaces found = 1
USBHub control callback
09 29 04 E0 00 32 64 00 FF 00 00 00 00 00 00 00 
Hub ports = 4
USBHub control callback
USBHub control callback
USBHub control callback
USBHub control callback
power turned on to all ports
device addr = 1
new_Pipe
allocate_interrupt_pipe_bandwidth
  ep interval = 12
  interval = 256
 best_bandwidth = 2, at offset = 0
pipe cap1 = F0012101
HUB Callback (member)
status = 4
getstatus, port = 2
USBHub control callback
01 01 01 00 
New Port Status
  status=10101  port=2
  state=0
  Device is present: 
  Has Power
USBHub control callback
Port Status Cleared, port=2
timer event (19999 us): Debounce Timer, this = 20004660, timer = 20004978
ports in use bitmask = 4
getstatus, port = 2
USBHub control callback
01 01 00 00 
New Port Status
  status=101  port=2
  state=2
  Device is present: 
  Has Power
timer event (19999 us): Debounce Timer, this = 20004660, timer = 20004978
ports in use bitmask = 4
getstatus, port = 2
USBHub control callback
01 01 00 00 
New Port Status
  status=101  port=2
  state=3
  Device is present: 
  Has Power
timer event (19999 us): Debounce Timer, this = 20004660, timer = 20004978
ports in use bitmask = 4
getstatus, port = 2
USBHub control callback
01 01 00 00 
New Port Status
  status=101  port=2
  state=4
  Device is present: 
  Has Power
timer event (19999 us): Debounce Timer, this = 20004660, timer = 20004978
ports in use bitmask = 4
getstatus, port = 2
USBHub control callback
01 01 00 00 
New Port Status
  status=101  port=2
  state=5
  Device is present: 
  Has Power
timer event (19999 us): Debounce Timer, this = 20004660, timer = 20004978
ports in use bitmask = 4
getstatus, port = 2
USBHub control callback
01 01 00 00 
New Port Status
  status=101  port=2
  state=6
  Device is present: 
  Has Power
sending reset
send_setreset
USBHub control callback
unhandled setup, message = 40323
timer event (19999 us): Debounce Timer, this = 20004660, timer = 20004978
ports in use bitmask = 0
HUB Callback (member)
status = 4
getstatus, port = 2
USBHub control callback
03 05 10 00 
New Port Status
  status=100503  port=2
  state=7
  Device is present: 
  Enabled, speed = 480 Mbit/sec
  Has Power
USBHub control callback
unhandled setup, message = 140123
timer event (24999 us): Hello, I'm resettimer, this = 20004660, timer = 20004994
port_doing_reset = 2
PORT_RECOVERY
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 00 02 00 00 00 40 0C 09 00 10 00 11 01 02 00 01 
    VendorID = 090C, ProductID = 1000, Version = 1100
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: SMI Corporation
enumeration:
Product: USB DISK
enumeration:
Config data length = 32
enumeration:
Configuration Descriptor:
  09 02 20 00 01 01 00 80 FA 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 02 08 06 50 00 
    Interface = 0
    Number of endpoints = 2
    Class/Subclass/Protocol = 8(Mass Storage) / 6(SCSI) / 80(Bulk Only)
  07 05 81 02 00 02 FF 
    Endpoint = 1 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 255
  07 05 02 02 00 02 FF 
    Endpoint = 2 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 255
enumeration:
msController claim this=20004A40
Descriptor 4 = INTERFACE
msController claim this=20004A40
09 04 00 00 02 08 06 50 00 07 05 81 02 00 02 FF 07 05 02 02 00 02 FF 
endpointType = 2
numendpoint=2
endpointIn=81
endpointOut=2
packet size in (msController) = 512
packet size out (msController) = 512
polling intervalIn = 255
polling intervalOut = 255
new_Pipe
new_Pipe
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
## mscInit after available
## mscInit after reset
control CallbackIn (msController)
00 00 00 00 00 00 00 00 
## mscInit after msgGetMaxLun
control CallbackIn (msController)
00 00 00 00 00 00 00 00 
## mscInit before startstopunit
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)
msGetCSW before QDT
msGetCSW after QDT
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 02 00 00 00 00 00 00 00 00 
** CSWSIGNATURE
## mscInit before media ready
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)
msGetCSW before QDT
msGetCSW after QDT
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 03 00 00 00 00 00 00 00 00 
** CSWSIGNATURE
## mscInit before DeviceInquiry
## msDeviceInquiry before do command 36
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)
msDoCommand after msOutCompleted loop
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 04 00 00 00 00 00 00 00 00 
** CSWSIGNATURE
msDoCommand after msInCompleted loop
msGetCSW before QDT
msGetCSW after QDT

Notice the ending, that the data returned from the INQUIRY command was a CSW message not a data message. So you already received the status... But thought it was result of inqury.

Kurt
 
@Kurte

I think I see what you are getting at. For each CBW sent there needs to be a corresponding CSW read in and checked. My code is only getting the CSW at the end of "msDoCommand()" which is probably causing things to get out of sync.

Thanks, When I get back from work today I am going to redo the msDoCommand()" and "msGetCSW()" functions.

You are really good at this.
 
Hi @wwatson,

Thanks,

Not sure yet what is the correct way of programming this yet - Still just starting to trace my way through...

But so far it looks like for each command you output you are receiving a CSWSignature message back... Not sure about your data that probably should be returned for the INQUIRY command?

Actually I think there is an issue with the INQUIRY command:

That is I think you are asking it to not return any data... Page 92 of your SCSI document...
You are passing in allocation length=0 and I think that is saying don't return anything... So I changed:
Code:
uint8_t msController::msDeviceInquiry(msInquiryResponse_t * const Inquiry)
{
	msCommandBlockWrapper_t CommandBlockWrapper = (msCommandBlockWrapper_t)
	{
		.Signature          = CBWSIGNATURE,
		.Tag                = ++CBWTag,
		.TransferLength     = sizeof(msInquiryResponse_t),
		.Flags              = CMDDIRDATAIN,
		.LUN                = 0,
		.CommandLength      = 6,
		.CommandData        = {CMDINQUIRY,0x00,0x00,0x00,sizeof(msInquiryResponse_t),0x00}
	};
	Serial.printf("## msDeviceInquiry before do command %u\n", sizeof(msInquiryResponse_t) );
	uint8_t retval =  msDoCommand(&CommandBlockWrapper, Inquiry);
	Serial.printf("## msDeviceInquiry after do command %u\n", retval );
	return retval;
}
In yours you had .CommandData as all 0's after CMDINQUIRY... I put it to the size of structure you specified.
Code:
msController dataOut (static)31
55 53 42 43 0D 00 00 00 00 02 00 00 80 00 0A 28 00 00 00 40 00 00 00 01 00 00 00 00 00 00 00 
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 512
53 44 46 4F 52 4D 41 54 45 44 20 08 00 00 00 00 00 00 00 00 00 00 23 5B AA 4E 00 00 00 00 00 00 
** ????
msDoCommand after msOutCompleted loop
msDoCommand after msInCompleted loop
msGetCSW before QDT
msGetCSW after QDT
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 0D 00 00 00 00 00 00 00 00 
** CSWSIGNATURE
And now when the inquiry is called, it now returns a data structure of unknown data...

Then we get back the status response the code continues...
 
@all - With the one change I mentioned above:
.CommandData = {CMDINQUIRY,0x00,0x00,0x00,sizeof(msInquiryResponse_t),0x00}

One of my Thumbdrives worked...

Then I removed the debug stuff (it still worked...) Then tried with Cruzer 1GB and it hung.. Doing lots of command transfers...
Code:
sController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)31
55 53 42 43 7C 00 00 00 00 00 00 00 80 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 7C 00 00 00 00 00 00 00 01 
** CSWSIGNATURE
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)31
55 53 42 43 7D 00 00 00 00 00 00 00 80 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 7D 00 00 00 00 00 00 00 01 
** CSWSIGNATURE
So I am pretty sure it is hung calling in:
Code:
uint8_t msController::WaitMediaReady() {
	uint8_t msResult = 0;
	do {
		msResult = msTestReady();
	} while(msResult);
// TODO: Process a Timeout
	return msResult;
}
Which if I am looking correct: msTestReady will be sending command data: .CommandData = {CMDTESTUNITREADY, 0x00, 0x00, 0x00, 0x00, 0x00}
Where #define CMDTESTUNITREADY 0x00

But if I look in the SCSI command PDF it shows opcode=0

Is write(6) 3.59WRITE (6) command page 248 ... Says obsolete... It is returning error code=1 (fail)...
 
@all - With the one change I mentioned above:
.CommandData = {CMDINQUIRY,0x00,0x00,0x00,sizeof(msInquiryResponse_t),0x00}

One of my Thumbdrives worked...

Then I removed the debug stuff (it still worked...) Then tried with Cruzer 1GB and it hung.. Doing lots of command transfers...
...

Sounds like good progress in the right spot … to make more ...
 
Sounds like good progress in the right spot … to make more ...

@all
Wow Kurt you made a lot of progress on this - trying to keep up while isolating the FD issue which I think we have it narrowed to the clock or FD timing issue. Had scope on 3 different boards today watching the transfers - yes it does transfer but noting reading the data properly. Think @tonton81 going to have to check FD timings
 
@Kurte

Nice detective work.

I saw the ommision you were talking about and changed it on my end as well. I also found the same ommision in msGetMaxLUNS() which has not been implemented yet. The Seagate manual
(page 179) says "The allocation length should be at least 16". I added a define in the MassStorage.h file #define MAXLUNS 16".

This is the modified msReportLUNs() function:
Code:
//---------------------------------------------------------------------------
// Report LUNs
uint8_t msController::msReportLUNs(uint8_t *Buffer)
{
	msCommandBlockWrapper_t CommandBlockWrapper = (msCommandBlockWrapper_t)
	{
		.Signature          = CBWSIGNATURE,
		.Tag                = ++CBWTag,
		.TransferLength     = MAXLUNS,
		.Flags              = CMDDIRDATAIN,
		.LUN                = 0,
		.CommandLength      = 8,
		.CommandData        = {CMDREPORTLUNS, 0x00, 0x00, 0x00, 0x00, 0x00, MAXLUNS, 0x00}
	};
	return msDoCommand(&CommandBlockWrapper, Buffer);
}

I also modified msDoCommand() to this:
Code:
//---------------------------------------------------------------------------
// Send SCSI Command
uint8_t msController::msDoCommand(msCommandBlockWrapper_t *CBW,	void *buffer)
{
	uint8_t CSWResult = 0;

	if(CBWTag == 0xFFFFFFFF)
		CBWTag = 1;
	if((CBW->Flags == CMDDIRDATAIN)) { // Data from device
		queue_Data_Transfer(datapipeOut, CBW, sizeof(msCommandBlockWrapper_t), this);
		while(!msOutCompleted);  // Wait for out transaction to complete.
		msOutCompleted = false;
		queue_Data_Transfer(datapipeIn, buffer, CBW->TransferLength, this);
		while(!msInCompleted);  // Wait for in transaction to complete.
		msInCompleted = false;
		if((CSWResult = msGetCSW()) != 0)
			return CSWResult;
	} else { // Data to device
		queue_Data_Transfer(datapipeOut, CBW, sizeof(msCommandBlockWrapper_t), this);
		while(!msOutCompleted);  // Wait for out transaction to complete.
		msOutCompleted = false;
		queue_Data_Transfer(datapipeOut, buffer, CBW->TransferLength, this);
		while(!msOutCompleted);  // Wait for second out transaction to complete.
		msOutCompleted = false;
		if((CSWResult = msGetCSW()) != 0)
			return CSWResult;
	}
	return CSWResult;  // Return CSW status
}

So far, I am not getting the occasional lockups I was with the original version.
I also was able to do copies of large files to the same drive at 240MHZ with buffer sizes up to 8192 bytes without the lockups.
I tested with several hard drives and two different Kingston flash drives.
Maybe you can test the modified version and see if it changes anything with your devices.

One question. Are you testing with T3.6 and T4 or just T4?

This is the sketch I used to check the Inquiry function:
Code:
#include "uSDFS.h"
#include "MassStorage.h"
/*
* for APL see http://elm-chan.org/fsw/ff/00index_e.html
*/
#define TEST_DRV 2
//
#if TEST_DRV == 0
  const char *Dev = "0:/";  // SPI
#elif TEST_DRV == 1
  const char *Dev = "1:/";  //SDHC
#elif TEST_DRV == 2
  const char *Dev = "2:/";  //USB
#endif

FRESULT rc;       /* Result code */
FATFS fatfs;      /* File system object */
FIL fil;          /* File object */
DIR dir;          /* Directory object */
FILINFO fno;      /* File information object */

msInquiryResponse_t *diskInquiry;
msSCSICapacity_t *diskCapacity;

void die(const char *text, FRESULT rc)
{ Serial.printf("%s: Failed with rc=%u.\r\n", text,rc);  while(1) asm("wfi"); }

void setup() {
  // put your setup code here, to run once:
  while(!Serial);
  Serial.println("Test Drive Inquiry with uSDFS");
  Serial.print("Waiting For Device: ");
  Serial.println(Dev);
  if((rc = f_mount (&fatfs, Dev, 1))) die("Mount",rc);      /* Mount/Unmount a logical drive */

  //-----------------------------------------------------------
  Serial.printf("\nChange drive\n");
  if((rc = f_chdrive(Dev))) die("chdrive",rc);

  // Show stats for Mass Storage Device
  Serial.printf("\nDo Device Inquiry\n");
  if(TEST_DRV == 2) {
    diskInquiry = getDriveInquiry();
    Serial.printf("Removable Device: ");
    if(diskInquiry->Removable == 1)
      Serial.printf("YES\n");
    else
      Serial.printf("NO\n");
      Serial.printf("        VendorID: %8.8s\n",diskInquiry->VendorID);
      Serial.printf("       ProductID: %16.16s\n",diskInquiry->ProductID);
      Serial.printf("      RevisionID: %4.4s\n",diskInquiry->RevisionID);
      Serial.printf("\nGet Device Capacity Specs\n");
      diskCapacity = getDriveCapacity();
      Serial.printf("    Sector Count: %ld\n",diskCapacity->Blocks);
      Serial.printf("     Sector size: %ld\n",diskCapacity->BlockSize);
      Serial.printf("   Disk Capacity: %ld * %ld Bytes\n",diskCapacity->Blocks, diskCapacity->BlockSize);
  }
  Serial.printf("\nDevice Inquiry Test Finished.\n");
}

void loop() {
	delay(1000);
}
 
@wwatson and @KurtE

I just incorporated both yours and Kurt's changes in the lib for two of my thumb drives worked like a charm (Cruzer 2gb and sansdisk 32gb) for the third, a microcenter 1gb thumb drive it failed with the following results, going to try a ssd drive in a bit will let you know how that goes:
Code:
Test Drive Inquiry with uSDFS
Waiting For Device: 2:/
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20004000
periodictable = 20004000
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 00 02 00 00 00 40 07 13 63 01 00 01 01 02 03 01 
    VendorID = 1307, ProductID = 0163, Version = 0100
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: USB 2.0
enumeration:
Product: Flash Disk
enumeration:
Serial Number: 0ee644744fd53c
enumeration:
Config data length = 39
enumeration:
Configuration Descriptor:
  09 02 27 00 01 01 00 80 28 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 03 08 06 50 00 
    Interface = 0
    Number of endpoints = 3
    Class/Subclass/Protocol = 8(Mass Storage) / 6(SCSI) / 80(Bulk Only)
  07 05 01 02 00 02 01 
    Endpoint = 1 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 82 02 00 02 01 
    Endpoint = 2 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 83 03 40 00 08 
    Endpoint = 3 IN
    Type = Interrupt
    Max Size = 64
    Polling Interval = 8
enumeration:
msController claim this=20002EE0
Descriptor 4 = INTERFACE
msController claim this=20002EE0
09 04 00 00 03 08 06 50 00 07 05 01 02 00 02 01 07 05 82 02 00 02 01 07 05 83 03 40 00 08 
endpointType = 2
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
 
@all

Hooked up a 120GB SSD and got the following results (buf: didn't work), drive is formatted to exFat:
Code:
Test Drive Inquiry with uSDFS
Waiting For Device: 2:/
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20004000
periodictable = 20004000
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 10 02 00 00 00 40 2D 15 78 05 09 05 01 02 03 01 
    VendorID = 152D, ProductID = 0578, Version = 0509
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: JMicron
enumeration:
Product: External USB 3.0
enumeration:
Serial Number: 0123456789CB
enumeration:
Config data length = 85
enumeration:
Configuration Descriptor:
  09 02 55 00 01 01 00 80 FA 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 02 08 06 50 00 
    Interface = 0
    Number of endpoints = 2
    Class/Subclass/Protocol = 8(Mass Storage) / 6(SCSI) / 80(Bulk Only)
  07 05 81 02 00 02 00 
    Endpoint = 1 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  07 05 02 02 00 02 00 
    Endpoint = 2 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  09 04 00 01 04 08 06 62 00 
    Interface = 0
    Number of endpoints = 4
    Class/Subclass/Protocol = 8(Mass Storage) / 6(SCSI) / 98(UAS)
  07 05 01 02 00 02 00 
    Endpoint = 1 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  04 24 01 00 
  07 05 82 02 00 02 00 
    Endpoint = 2 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  04 24 02 00 
  07 05 83 02 00 02 00 
    Endpoint = 3 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  04 24 03 00 
  07 05 04 02 00 02 00 
    Endpoint = 4 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 0
  04 24 04 00 
enumeration:
msController claim this=20002EE0
Descriptor 4 = INTERFACE
msController claim this=20002EE0
09 04 00 00 02 08 06 50 00 07 05 81 02 00 02 00 07 05 02 02 00 02 00 09 04 00 01 04 08 06 62 00 07 05 01 02 00 02 00 04 24 01 00 07 05 82 02 00 02 00 04 24 02 00 07 05 83 02 00 02 00 04 24 03 00 07 05 04 02 00 02 00 04 24 04 00 
endpointType = 2
numendpoint=2
endpointIn=81
endpointOut=2
packet size in (msController) = 512
packet size out (msController) = 512
polling intervalIn = 0
polling intervalOut = 0
new_Pipe
new_Pipe
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Descriptor 4 = INTERFACE
Descriptor 5 = ENDPOINT
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 36 =  ???
Descriptor 5 = ENDPOINT
Descriptor 36 =  ???
control CallbackIn (msController)
00 00 00 00 00 00 00 00 
control CallbackIn (msController)
00 00 00 00 00 00 00 00 
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackOut (static)
transfer->qtd.token = 0
msController dataOut (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static)
[COLOR="#FF0000"]Mount: Failed with rc=13.[/COLOR]
 
@all
Using the same SSD but with a startech sata/ide converter I pretty much get the same results as in previous post:
Code:
Test Drive Inquiry with uSDFS
Waiting For Device: 2:/
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20004000
periodictable = 20004000
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 10 02 00 00 00 40 75 1F 11 06 06 00 04 05 06 01 
    VendorID = 1F75, ProductID = 0611, Version = 0006
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer:  

doesn't want to copy rest
 
@mjs513 and @wwatson and others...

Wonder if your 1GB is hanging the same way as my 1GB...

Note: I have additional debug stuff turned on:
Code:
void msController::new_dataOut(const Transfer_t *transfer)
{
	uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
	println("msController dataOut (static)", len, DEC);
	print_hexbytes((uint8_t*)transfer->buffer, (len < 32)? len : 32 );
	msOutCompleted = true; // Last out transaction is completed.
}

void msController::new_dataIn(const Transfer_t *transfer)
{
	uint32_t len = transfer->length - ((transfer->qtd.token >> 16) & 0x7FFF);
	println("msController dataIn (static): ", len, DEC);
	print_hexbytes((uint8_t*)transfer->buffer, (len < 32)? len : 32 );
	if (len >= 4) {
		uint32_t l = *(uint32_t*)transfer->buffer;
		if (l == CBWSIGNATURE) println("** CBWSIGNATURE");
		else if (l == CSWSIGNATURE) println("** CSWSIGNATURE");
		else println("** ????");
	}


	msInCompleted = true; // Last in transaction is completed.
}
With this you can see all of the input and output stuff going on. And in my case it was hanging in the loop for media available (WaitMeidaReady)

Yesterday I was playing iwth the WaitMediaReady to maybe call msRequestSense if the mediaAvailable call fails... To maybe see what the failure codes are...
Comments embeded ()
Code:
(Here we ask for the media ready)
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)31
55 53 42 43 35 00 00 00 00 00 00 00 80 00 06 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 


(Response - ends with 01 - fail)
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 35 00 00 00 00 00 00 00 01 
** CSWSIGNATURE

(Now ask for request sense)
msController CallbackOut (static)
transfer->qtd.token = 1
msController dataOut (static)31
55 53 42 43 36 00 00 00 12 00 00 00 80 00 06 03 00 00 00 12 00 00 00 00 00 00 00 00 00 00 00 
msController CallbackIn (static)
transfer->qtd.token = 0

(response of sense)
msController dataIn (static): 18
70 00 02 00 00 00 00 0A 00 00 00 00 3A 00 00 00 00 00 
** ????
msDoCommand after msOutCompleted loop
msDoCommand after msInCompleted loop
msController CallbackIn (static)
transfer->qtd.token = 0
msController dataIn (static): 13
55 53 42 53 36 00 00 00 00 00 00 00 00 
** CSWSIGNATURE
(I had the waitMedia also dump out the response)...
WaitMediaReady RSP:70 00 02 00 00 00 00 0A 00 00 00 00 3A 00 

.... Repeats for ever or until I unplug

Now to look up what the response codes are...
 
@KurtE
Not even getting that far - hanging before that on endpoints (BTW - Hot swapping works)
Code:
Test Drive Inquiry with uSDFS
Waiting For Device: 2:/
USB2 PLL running
 reset waited 6
USBHS_ASYNCLISTADDR = 0
USBHS_PERIODICLISTBASE = 20004000
periodictable = 20004000
port change: 10001803
    connect
  begin reset
port change: 18001205
  port enabled
  end recovery
new_Device: 480 Mbit/sec
new_Pipe
enumeration:
enumeration:
enumeration:
Device Descriptor:
  12 01 00 02 00 00 00 40 07 13 63 01 00 01 01 02 03 01 
    VendorID = 1307, ProductID = 0163, Version = 0100
    Class/Subclass/Protocol = 0 / 0 / 0
    Number of Configurations = 1
enumeration:
enumeration:
Manufacturer: USB 2.0
enumeration:
Product: Flash Disk
enumeration:
Serial Number: 0ee644744fd53c
enumeration:
Config data length = 39
enumeration:
Configuration Descriptor:
  09 02 27 00 01 01 00 80 28 
    NumInterfaces = 1
    ConfigurationValue = 1
  09 04 00 00 03 08 06 50 00 
    Interface = 0
    Number of endpoints = 3
    Class/Subclass/Protocol = 8(Mass Storage) / 6(SCSI) / 80(Bulk Only)
  07 05 01 02 00 02 01 
    Endpoint = 1 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 82 02 00 02 01 
    Endpoint = 2 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 83 03 40 00 08 
    Endpoint = 3 IN
    Type = Interrupt
    Max Size = 64
    Polling Interval = 8
enumeration:
msController claim this=20002F00
Descriptor 4 = INTERFACE
msController claim this=20002F00
09 04 00 00 03 08 06 50 00 07 05 01 02 00 02 01 07 05 82 02 00 02 01 07 05 83 03 40 00 08 
endpointType = 2
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT

DIES AT THIS POINT
Either that or I am editing the wrong file? (masstoragedriver.cpp)
 
Actually sort of interesting. In particular this one shows 3 end points (The others show 2)
Code:
  07 05 01 02 00 02 01 
    Endpoint = 1 OUT
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 82 02 00 02 01 
    Endpoint = 2 IN
    Type = Bulk
    Max Size = 512
    Polling Interval = 1
  07 05 83 03 40 00 08 
    Endpoint = 3 IN
    Type = Interrupt
    Max Size = 64
    Polling Interval = 8
If you look at: bool msController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)

It is assuming that first end point is In and the second endpoint is out, which in this case is reversed, so then the code:
Code:
if ((endpointIn & 0xF0) != 0x80) return false; // must be IN direction
	if ((endpointOut & 0xF0) != 0x00) return false; // must be OUT direction
Will fail and it won't claim the device...

The code probably needs to walk the number of end points, and find the IN and the OUT. (The 80 bit).
The Joystick claim code I believe has the stuff to walk through the endpoints to find the ones it want's ...
 
@KurtE

I noticed that it was showing 3 endpoints which was kind of strange, like you said.
The Joystick claim code I believe has the stuff to walk through the endpoints to find the ones it want's ...
hope its portable enough to transfer.
 
@KurtE

I noticed that it was showing 3 endpoints which was kind of strange, like you said. hope its portable enough to transfer.

Should be easy enough: Just setup index to first endpoint in buffer set index or like for IN/OUT endpoints in code to something like 0xff , increment by the size (7), and then check the end point, if it is a Bulk OUTPUT, remember it's index (OUT), and if it is input bulk remember it's index... If we ran through all of the end points and either of them is still 0xff then error...

Then change code that used fixed index for fields of it to use saved index plus offset...
Things like: uint32_t sizeIn = descriptors[13] | (descriptors[14] << 8);

would look more like: uint32_t sizeIn = descriptors[in_endpoint_offset+4] | (descriptors[in_endpoint_offset+5] << 8);
Depending on what you save as the index...

EDIT: Should I take a crack at it?
 
@mjs513 and @wwatson - follow on to previous post... Maybe something like:
Code:
bool msController::claim(Device_t *dev, int type, const uint8_t *descriptors, uint32_t len)
{
	println("msController claim this=", (uint32_t)this, HEX);
	// only claim at interface level

	if (type != 1) return false;
	if (len < 9+7+7) return false; // Interface descriptor + 2 endpoint decriptors 

	print_hexbytes(descriptors, len);

	uint32_t numendpoint = descriptors[4];
	if (numendpoint < 1) return false; 
	if (descriptors[5] != 8) return false; // bInterfaceClass, 8 = MASS Storage class
	if (descriptors[6] != 6) return false; // bInterfaceSubClass, 6 = SCSI transparent command set (SCSI Standards)
	if (descriptors[7] != 80) return false; // bInterfaceProtocol, 80 = BULK-ONLY TRANSPORT
#if 1
	uint8_t desc_index = 9;
	uint8_t in_index = 0xff, out_index = 0xff;

	println("numendpoint=", numendpoint, HEX);
	while (numendpoint--) {
		if ((descriptors[desc_index] != 7) || (descriptors[desc_index+1] != 5)) return false; // not an end point
		if (descriptors[desc_index+3] == 2) {  // Bulk end point
			if (descriptors[desc_index+2] & 0x80)
				in_index = desc_index;
			else
				out_index = desc_index;
		}
		desc_index += 7;	// point to next one...
	}
	if ((in_index == 0xff) || (out_index == 0xff)) return false;	// did not find end point
	endpointIn = descriptors[in_index+2]; // bulk-in descriptor 1 81h
	endpointOut = descriptors[out_index+2]; // bulk-out descriptor 2 02h

	println("endpointIn=", endpointIn, HEX);
	println("endpointOut=", endpointOut, HEX);

	uint32_t sizeIn = descriptors[in_index+4] | (descriptors[in_index+5] << 8);
	println("packet size in (msController) = ", sizeIn);

	uint32_t sizeOut = descriptors[out_index+4] | (descriptors[out_index+5] << 8);
	println("packet size out (msController) = ", sizeOut);
	packetSizeIn = sizeIn;	
	packetSizeOut = sizeOut;	

	uint32_t intervalIn = descriptors[in_index+6];
	uint32_t intervalOut = descriptors[out_index+6];

	println("polling intervalIn = ", intervalIn);
	println("polling intervalOut = ", intervalOut);
	datapipeIn = new_Pipe(dev, 2, endpointIn, 1, packetSizeIn, intervalIn);
	datapipeOut = new_Pipe(dev, 2, endpointOut, 0, packetSizeOut, intervalOut);
#else	

	if (descriptors[10] != 5 || descriptors[17] != 5) return false; // Must have bulk-in and bulk-out endpoints

	uint8_t endpointType = (descriptors[12] | descriptors[19]) & 0x03; 
	println("endpointType = ",endpointType);
	endpointIn = descriptors[11]; // bulk-in descriptor 1 81h
	endpointOut = descriptors[18]; // bulk-out descriptor 2 02h

	if ((endpointIn & 0xF0) != 0x80) return false; // must be IN direction
	if ((endpointOut & 0xF0) != 0x00) return false; // must be OUT direction
	println("numendpoint=", numendpoint, HEX);
	println("endpointIn=", endpointIn, HEX);
	println("endpointOut=", endpointOut, HEX);

	uint32_t sizeIn = descriptors[13] | (descriptors[14] << 8);
	println("packet size in (msController) = ", sizeIn);

	uint32_t sizeOut = descriptors[20] | (descriptors[21] << 8);
	println("packet size out (msController) = ", sizeOut);
	packetSizeIn = sizeIn;	
	packetSizeOut = sizeOut;	

	uint32_t intervalIn = descriptors[15];
	uint32_t intervalOut = descriptors[22];

	println("polling intervalIn = ", intervalIn);
	println("polling intervalOut = ", intervalOut);
	datapipeIn = new_Pipe(dev, 2, endpointIn, 1, packetSizeIn, intervalIn);
	datapipeOut = new_Pipe(dev, 2, endpointOut, 0, packetSizeOut, intervalOut);
#endif
	datapipeIn->callback_function = callbackIn;
	datapipeOut->callback_function = callbackOut;

	msOutCompleted = false;
	msInCompleted = false;
	deviceAvailable = true;
	return true;
}
I may not be printing out everything here as before, but most of it...
 
Back
Top