Another USB Mass Storage question

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
ylli122
Posts: 9
Joined: Sun Apr 12, 2020 1:34 pm

Another USB Mass Storage question

Post by ylli122 »

Hey all,
Hope youre all doing well in these troubling times!

Just a quick question.
Ive been reading the spec sheets for EHCI and Bulk-Only Transport and I think I get it. One thing that is confusing me slightly is the following:
Per function endpoint, there exists a value "wMaxPacketSize" which identifies the maximum size of the data packet sendable to that endpoint. Its meaning confuses me slightly. Consider the following:

Say I wanted to send 512 bytes of data to the OUT endpoint with wMaxPacketSize of 08h (for arguments sake). Lets say the Controller is idle for arguments sake, with a pointer to the QH associated to the OUT endpoint of the function on the LUN we are looking at written to ASYNCLISTADDR. (The following is the structure of the Asynch list QH0 = Control EP-> QH1 = OUT EP->QH2 = IN EP-> QH0)

I would, create a qTD (lets call it TD0) associated to QH1, pointing to, in the "Buffer 0 + Current offset" field, a CBW with the value 200h in its "Transfer Length" field. TD0 would have the value 01Fh in the "Total bytes to transfer" field. I would then create another qTD (TD1), linked to TD0 via TD0's "Next qTD pointer" field, with a pointer in the "Buffer 0 + Current offset" field of TD1, the head of the raw 200h of data to be transferred. TD1 would have 200h in the "Total bytes to transfer" field and a null ptr in the "Next qTD pointer" field to indicate that it is the last ptr in the linked list.

Now this is where my confusion arises.
If I now initialise the HC and let it process this QH, would it correctly send the data, with the HC correctly sending 8 byte packets at a time for me OR, do I need to create 40h = (200h/8) data transfer Transfer Descriptors and two Transfer Descriptors for the CBW to account for the value of wMaxPacketSize (of course this value is also mirrored in the "Maximum Packet Length" field of the QH1)? Or is my understanding totally incorrect and I should go and beat myself over the head with the Spec some more? :lol:

Thanks for your help in advance!
PS I assume the former but this has been bugging me for a while.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: Another USB Mass Storage question

Post by BenLunt »

Hi,

Your explanation is a little confusing to me, so I will try to explain the process.

First, EHCI has nothing to do with BBB (Bulk Bulk Bulk) transport. BBB transport is the same whether it is UHCI, OHCI, EHCI, or xHCI.
However, I do see why you chose to use EHCI as the example, because, yes you show each TD pointing to the next.

Second, just a few notes. A BBB device, called a Mass Storage Device (see note below), will most likely have a bulk endpoint max packet size the size of the largest allowed size for the speed of the device. For example, if the device is a full-speed device, it most likely will have a max packet size of 64 for the two bulk endpoints. If it is a super-speed device, it might have a max packet size of 512.

However, as you state, let's assume for arguments sake, the bulk endpoint has a max packet size of 64.

Therefore, if I want to read a 512-byte sector from the device, I must use ten (10) TD's.

CBW TD OUT as 31 bytes.
TD0 IN 64 bytes
TD1 IN 64 bytes
TD2 IN 64 bytes
TD3 IN 64 bytes
TD4 IN 64 bytes
TD5 IN 64 bytes
TD6 IN 64 bytes
TD7 IN 64 bytes
CSW TD IN as 13 bytes.

You can create the TD stack however you wish. The TDs do not have to be in a single Queue Head. You may have multiple QHs. Again, the TDs and QHs are EHCI specific, not BBB specific.

An 8-byte max packet size is illegal with BBB devices. The two wrapper transfers must be single transfers so the max packet size must be at at least 31 bytes. (If memory serves. I would have to look at my notes to verify this for sure.)

Please note that even if one of the data transfers between the two wrapper packets stalls or errors, you must still read the CSW wrapper packet. Except for unrecoverable errors, the device will still expect you to read the CSW packet. This gets to be dificult if not done correctly because you have to know the toggle bit status of the last successful transfer to know what the toggle bit will be for the CSW transfer.

Note on Mass Storage Devices (MSDs). MSD can have different forms of transfer protocols. The common protocol is the BBB protocol shown here. A new(ish) protocol is the UAS protocol. UAS stands for USB Attached SCSI. This protocol allows for much faster transfers and requires at least high-speed (EHCI) but is really designed for super-speed (xHCI) and streams.

The MSD will tell you which protocol it uses. My point here is, please don't confuse protocols by joining them. The physical transport of data (UHCI, OHCI, EHCI, xHCI) is one driver (layer). The MSD protocol is another layer. The BBB or UAS is another layer. Therefore, you should have at least three separate layers/drivers for BBB devices.

1) USB Controller Driver
2) MSD driver
3a) BBB protocol
3b) UAS protocol

Also, MSD actually has other protocols as well, including CB and CBI for floppies, Control Bulk [Interrupt].

Hope this helps,
Ben
- http://www.fysnet.net/the_universal_serial_bus.htm
ylli122
Posts: 9
Joined: Sun Apr 12, 2020 1:34 pm

Re: Another USB Mass Storage question

Post by ylli122 »

BenLunt wrote:Hi,

Your explanation is a little confusing to me, so I will try to explain the process.

First, EHCI has nothing to do with BBB (Bulk Bulk Bulk) transport. BBB transport is the same whether it is UHCI, OHCI, EHCI, or xHCI.
However, I do see why you chose to use EHCI as the example, because, yes you show each TD pointing to the next.

Second, just a few notes. A BBB device, called a Mass Storage Device (see note below), will most likely have a bulk endpoint max packet size the size of the largest allowed size for the speed of the device. For example, if the device is a full-speed device, it most likely will have a max packet size of 64 for the two bulk endpoints. If it is a super-speed device, it might have a max packet size of 512.

However, as you state, let's assume for arguments sake, the bulk endpoint has a max packet size of 64.

Therefore, if I want to read a 512-byte sector from the device, I must use ten (10) TD's.

CBW TD OUT as 31 bytes.
TD0 IN 64 bytes
TD1 IN 64 bytes
TD2 IN 64 bytes
TD3 IN 64 bytes
TD4 IN 64 bytes
TD5 IN 64 bytes
TD6 IN 64 bytes
TD7 IN 64 bytes
CSW TD IN as 13 bytes.

You can create the TD stack however you wish. The TDs do not have to be in a single Queue Head. You may have multiple QHs. Again, the TDs and QHs are EHCI specific, not BBB specific.

An 8-byte max packet size is illegal with BBB devices. The two wrapper transfers must be single transfers so the max packet size must be at at least 31 bytes. (If memory serves. I would have to look at my notes to verify this for sure.)

Please note that even if one of the data transfers between the two wrapper packets stalls or errors, you must still read the CSW wrapper packet. Except for unrecoverable errors, the device will still expect you to read the CSW packet. This gets to be dificult if not done correctly because you have to know the toggle bit status of the last successful transfer to know what the toggle bit will be for the CSW transfer.

Note on Mass Storage Devices (MSDs). MSD can have different forms of transfer protocols. The common protocol is the BBB protocol shown here. A new(ish) protocol is the UAS protocol. UAS stands for USB Attached SCSI. This protocol allows for much faster transfers and requires at least high-speed (EHCI) but is really designed for super-speed (xHCI) and streams.

The MSD will tell you which protocol it uses. My point here is, please don't confuse protocols by joining them. The physical transport of data (UHCI, OHCI, EHCI, xHCI) is one driver (layer). The MSD protocol is another layer. The BBB or UAS is another layer. Therefore, you should have at least three separate layers/drivers for BBB devices.

1) USB Controller Driver
2) MSD driver
3a) BBB protocol
3b) UAS protocol

Also, MSD actually has other protocols as well, including CB and CBI for floppies, Control Bulk [Interrupt].

Hope this helps,
Ben
- http://www.fysnet.net/the_universal_serial_bus.htm
Dude, youre awesome, thank you so much, this is JUST what was lacking in my "understanding" of whats going on.
I knew the protocols were different layers in some sense but the sheer number of "overlapping" fields of similar function (at least to my eyes) really confused my understanding of how to build the EHCI data structures.

Just to be extra sure, say I wanted to transfer 512 bytes TO the device, the transfer descriptors would do the same thing only TD0-TD7 should be sent to the OUT endpoint rather than IN?

Anyway, thanks again buddy, I really appreciate the helpful response!
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: Another USB Mass Storage question

Post by BenLunt »

ylli122 wrote:Just to be extra sure, say I wanted to transfer 512 bytes TO the device, the transfer descriptors would do the same thing only TD0-TD7 should be sent to the OUT endpoint rather than IN?
That is correct, granted you change the command block in the CBW as well.

At the moment it won't be a concern, but you might want to make note. If you ever have a multi-threading/tasking system and two tasks read from the same device at the same time, you will need to keep track of which CBW goes with which CSW via the tag fields. While the CBW and data transfers must be in sequence, obviously, the CSW packet can be out of sequence.

An easy way to keep this straight is to simply only allow one complete transaction at a time. It makes the driver simple, but considerably slows down multiple transfers.

Another way to do transfers, and considered a more proper way, is to use URBs (USB Request Blocks). All transfers are placed in a queue, not to confuse it with an EHCI queue, but a queue of transfers. Then you have a thread monitoring these URBs. When a packet is found on the wire, so to speak, this thread sends it to the proper queue handler. As for the BBB protocol, the queue handler would match the tag fields and complete the URB, marking it for removal. However, don't worry about this at this time in your project. It sometimes just exaggerates the learning environment and can actually make it worse.

Good luck and happy coding.
Ben
Post Reply