summaryrefslogtreecommitdiff
path: root/usb/device/massstorage/massstorage.dir
blob: bc793c542a3483de409e3c6804cad4c719fe1285 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
/* ----------------------------------------------------------------------------
 *         ATMEL Microcontroller Software Support 
 * ----------------------------------------------------------------------------
 * Copyright (c) 2008, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

//------------------------------------------------------------------------------
/// \dir
///
/// !!!Purpose
///
/// This directory provides definitions, structs and functions for a USB Mass
/// Storage %device (MSD) - USB Mass Storage demo.
///
/// !!!Contents
///
/// There are four things for the implement of the USB MSD driver:
/// - Implement the MSD driver structs and functions for the %device,
///   to initialize, to handle MSD-specific requests and dispach
///   standard requests in USBD callbacks, to read/write through assigned USB
///   %endpoints,
/// - Create the MSD device's descriptors that should be passed to
///   the USBDDriver instance on initialization, so that the host can 
///   recognize the %device as a USB Mass Storage %device.
/// - Implement state machine for MSD command/data/status handling.
/// - Implement storage media interface for MSD disk accessing.
///
/// For more information about what a particular group contains, please refer to
/// "USB MSD Driver".
//------------------------------------------------------------------------------

/**
 \page "USB MSD Driver"
 This page describes how to use the USB framework to produce a USB MSD driver,
 which appears as a USB Disk on host.

 !!!References
 - "AT91 USB device framework"
 - "USB Device Enumeration"
 - <a href="http://www.usb.org/developers/docs/usb_20_040908.zip">
   Universal Serial Bus Revision 2.0 specification
   </a> (.zip file format, size 9.80 MB)
 - <a href="http://www.usb.org/developers/devclass_docs/usb_msc_overview_1.2.pdf">
   Mass Storage Overview 1.2</a>
 - <a href="http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf">
   Mass Storage Bulk Only 1.0</a>
 - <a href="http://www.t10.org/scsi-3.htm">SCSI Standards</a>
    - SCSI Block Commands - 3 (SBC-3)
    - SCSI Primary Commands - 4 (SPC-4)

 !!!Mass Storage Class Basic
 This section gives generic details on the MSD class.

 See "USB MSD Basic".

 !!!Mass Storage SCSI Disk

 This section describes how to implement a USB disk by using the MSD class with
 the SCSI transparent command set and the AT91 USB Framework. For more
 information about the framework, please refer to the "AT91 USB device
 framework" application note; details about the USB and the Mass Storage class
 can be found in the USB specification 2.0 and the MSC Bulk-Only Transport
 specification 1.0 documents, respectively.

 The software example provided with this document uses the ram disk of the chip
 as its storage medium, but has been designed in a modular way to allow easy
 modification for any medium, e.g. internal flash, DataFlash, SD card, external
 Flash chip.

 !!Architecture
 The MSD driver is based on framework, See "USB Device Framework Architecture".

 The internal architecture of the Application layer is extended for the
 following factors:
 - The Command/Data/Status flow described in "USB MSD Basic" requires the use
   of a #state machine# for non-blocking operation.
 - The example software has been designed to be easily extended with support
   for other media.
 - The example software has been designed to support multiple LUNs on one or
   more media.

 \image MSDAppArch.png "Application Layer Architecture"

 !!Descriptors
 There are no class-specific descriptors for a device using the MSD class with
 the Bulk-only transport protocol. This section thus only details the values
 which must be set in the standard descriptors.

 !Device Descriptor
\code
static const USBDeviceDescriptor deviceDescriptor = {

    sizeof(USBDeviceDescriptor), // bLength: Size of descriptor (18 bytes)
    USBGenericDescriptor_DEVICE, // bDescriptorType: Device descriptor
    USBDeviceDescriptor_USB2_00, // bcdUSB: USB 2.00
    MSDeviceDescriptor_CLASS,    // bDeviceClass: 0
    MSDeviceDescriptor_SUBCLASS, // bDeviceSubClass: 0
    MSDeviceDescriptor_PROTOCOL, // bDeviceProtocol: 0
    BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0), // bMaxPacketSize0: Max Size EP0
    MSDDriverDescriptors_VENDORID, // idVendor: Vendor ID ATMEL (0x03eb)
    MSDDriverDescriptors_PRODUCTID,// idProduct: Product ID (0x6202)
    MSDDriverDescriptors_RELEASE,  // bcdDevice: 0x0001, Version 0.01
    1, // iManufacturer: Manufacturer string (manufacturerDescriptor) index.
    2, // iProduct: Product string (productDescriptor) index.
    3, // iSerialNumber: Serial number string (serialNumberDescriptor) index.
    1  // bNumConfigurations: Device has one possible configuration.
};
\endcode
 Note that the Vendor ID is a special value attributed by the USB-IF
 organization. The product ID can be chosen freely by the vendor.

 !Configuration Descriptor
 The descriptors are defined as:
\code
const MSDConfigurationDescriptors configurationDescriptorsFS;
\endcode

 Configuration descriptor
\code
// Standard configuration descriptor.
{
    sizeof(USBConfigurationDescriptor), // bLength: 9 bytes
    USBGenericDescriptor_CONFIGURATION, // bDescriptorType: Configuration
    sizeof(MSDConfigurationDescriptors),// wTotalLength: Length of all
    1, // bNumInterface: Configuration has one interface.
    1, // bConfigurationValue: This is configuration #1.
    0, // iConfiguration: No string descriptor for configuration.
    BOARD_USB_BMATTRIBUTES, // bmAttributes: Power and remote wakeup
    USBConfigurationDescriptor_POWER(100) // 100mA max power
},
\endcode

 !Interface Descriptor
 The interface descriptor must indicate several features:
 - #Mass Storage Device# class code (08h) in the }bInterfaceClass} field
 - #Data Transport Protocol# code in the }bInterfaceSubclass} field
 - #Bulk-Only Transport# protocol code (50h) in the }bInterfaceProtocol} field
 This example uses the SCSI transparent command set (code 06h). This is the
 most appropriate setting for a Flash %device, given that the RBC command set
 is not supported by Microsoft Windows.
\code
// Mass Storage interface descriptor.
{
    sizeof(USBInterfaceDescriptor), // bLength: Size of descriptor(9 bytes)
    USBGenericDescriptor_INTERFACE, // bDescriptorType: Interface descriptor
    0, // bInterfaceNumber: This is interface #0.
    0, // bAlternateSetting: This is alternate setting #0.
    2, // bNumEndpoints: Interface uses two endpoints.
    MSInterfaceDescriptor_CLASS, // bInterfaceClass: Mass Storage Device Class
    MSInterfaceDescriptor_SCSI, // bInterfaceSubClass: SCSI transparent command
    MSInterfaceDescriptor_BULKONLY,// bInterfaceProtocol: Bulk-Only transport
    0 // iInterface: No string descriptor for interface.
},
\endcode

 !Endpoint Descriptors
 No special requirements on these apart from being Bulk-IN and Bulk-OUT.
\code
// Bulk-OUT endpoint descriptor
{
    sizeof(USBEndpointDescriptor), // bLength: 7 bytes
    USBGenericDescriptor_ENDPOINT, // bDescriptorType: Endpoint descriptor
    USBEndpointDescriptor_ADDRESS(
        USBEndpointDescriptor_OUT,
        MSDDriverDescriptors_BULKOUT), // bEndpointAddress: OUT 0x01
    USBEndpointDescriptor_BULK, // bmAttributes: Bulk endpoint
    MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKOUT),
        USBEndpointDescriptor_MAXBULKSIZE_FS), // wMaxPacketSize: 64 bytes
    0 // bInterval: Must be 0 for full-speed Bulk endpoints.
},
// Bulk-IN endpoint descriptor
{
    sizeof(USBEndpointDescriptor), // bLength: 7 bytes
    USBGenericDescriptor_ENDPOINT, // bDescriptorType: Endpoint descriptor
    USBEndpointDescriptor_ADDRESS(
        USBEndpointDescriptor_IN,
        MSDDriverDescriptors_BULKIN), // bEndpointAddress: IN 0x82
    USBEndpointDescriptor_BULK, // bmAttributes: Bulk endpoint
    MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(MSDDriverDescriptors_BULKIN),
        USBEndpointDescriptor_MAXBULKSIZE_FS), // wMaxPacketSize: 64
    0 // bInterval: Must be 0 for full-speed Bulk endpoints.
}
\endcode

 !String descriptors
 Several descriptors can be commented with a String descriptor. The latter are
 completely optional and do not influence the detection of the device by the
 operating system. Whether or not to include them is entirely up to the
 programmer.

 There is one exception to this rule when using the MSD class. According to the
 specification, there must be a Serial Number string. It must contains at least
 12 characters, and these characters must only be either letters (a-z, A-Z) or
 numbers (0-9). This cause no problem for the driver in practice, but this is a
 strict requirement for certification. Also remember that string descriptors
 use the Unicode format.

 See manufacturerDescriptor, productDescriptor, serialNumberDescriptor.

 !!Class-specific Requests
 There are two Mass Storage-specific requests:
 - GetMaxLUN
 - Bulk-Only Mass Storage Reset

 Standard requests can be forwarded to the USBDDriver_RequestHandler, with one
 exception: #CLEAR_FEATURE#. This is necessary for Reset Recovery sequence.

 !ClearFeature
 As previously stated, the CLEAR_FEATURE request must be handled in a
 particular way, depending on whether or not the device is waiting for a Reset
 Recovery sequence. If it is, then CLEAR_FEATURE requests to unhalt a Bulk
 endpoint must be discarded.

 In the example software, this behavior is indicated by a boolean field in the
 driver structure, named waitResetRecovery. The handler only has to check this
 field value to decide whether to forward the request to the standard handler
 or to discard it.
\code
// Handle requests
switch (USBGenericRequest_GetRequest(request)) {
//---------------------
case USBGenericRequest_CLEARFEATURE:
//---------------------

    switch (USBFeatureRequest_GetFeatureSelector(request)) {

    //---------------------
    case USBFeatureRequest_ENDPOINTHALT:
    //---------------------

        // Do not clear the endpoint halt status if the device is waiting
        // for a reset recovery sequence
        if (!msdDriver.waitResetRecovery) {

            // Forward the request to the standard handler
            USBDDriver_RequestHandler(&usbdDriver, request);
        }

        USBD_Write(0, 0, 0, 0, 0);
        break;

    //------
    default:
    //------
        // Forward the request to the standard handler
        USBDDriver_RequestHandler(&usbdDriver, request);
    }
    break;
}
\endcode

 !GetMaxLUN
 Usually, the first request issued by the host right after the enumeration
 phase will be a GET_MAX_LUN request. It enables it to discover how many
 different logical units the device has; each of these LUNs can then be queried
 in turn by the host when needed.

 After the request is received by the device, it should return one byte of data
 indicating the maximum Logical Unit Number (LUN). It is equal to the number of
 LUNs used by the device minus one. For example, a device with three LUNs shall
 return a GET_MAX_LUN value of two.

 Sending this byte is done by calling the USBD_Write method on Control endpoint
 0. Note that the data must be held in a permanent buffer (since the transfer
 is asynchronous); in the software provided with this application note, a
 dedicated field is used in the driver structure (MSDDriver) to store this
 value.

 In addition due to the }Mass Storage Bulk-Only Transport} specification the
 }wValue} should be 0, }wLength} should be 1, }wIndex} should be the interface
 number also 0. A request which does not comply to these requirements must be
 STALLed.
\code
//-------------------
case MSD_GET_MAX_LUN:
//-------------------
    // Check request parameters
    if ((request->wValue == 0)
        && (request->wIndex == 0)
        && (request->wLength == 1)) {
        USBD_Write(0, &(msdDriver.maxLun), 1, 0, 0);
    }
    else {
        USBD_Stall(0);
    }
    break;
\endcode

 !Bulk-Only Mass Storage Reset
 The host issues #RESET# requests to return the MSD driver of the device to its
 initial state, i.e., ready to receive a new command. However, this request
 does not impact the USB controller state; in particular, endpoints must not be
 reset. This means the data toggle bit must not be altered, and Halted endpoint
 must not be returned to a normal state. After processing the reset, the device
 must return a Zero-Length Packet (ZLP) to acknowledge the SETUP transfer.

 Like GET_MAX_LUN, this request must be issued with specific parameters -
 wValue, wIndex and wLength should be zero. A request which does not have valid
 values in its field must be acknowledged with a STALL handshake from the
 %device.

 The handler for this request must return the state machine to its initial state.
\code
//-----------------------
case MSD_BULK_ONLY_RESET:
//-----------------------
    // Check parameters
    if ((request->wValue == 0)
        && (request->wIndex == 0)
        && (request->wLength == 0)) {

        // Reset the MSD driver
        MSDDriver_Reset();
        USBD_Write(0, 0, 0, 0, 0);
    }
    else {
        USBD_Stall(0);
    }
    break;
\endcode

 !!State Machine
 ...

 !Rationale
 A state machine is necessary for #non-blocking# operation of the driver. As
 previously stated, there are three steps when processing a command:
 - Reception of the CBW
 - Processing of the command (with data transfers if required)
 - Emission of the CSW

 Without a state machine, the program execution would be stopped at each step
 to wait for transfers completion or command processing. For example, reception
 of a CBW does not always happen immediately (the host does not have to issue
 commands regularly) and can block the system for a long time.

 Developing an asynchronous design based on a state machine is made easier when
 using Atmel "AT91 USB device framework", as most methods are asynchronous. For
 example, a write operation (using the USBD_Write function) returns
 immediately; a callback function can then be invoked when the transfer
 actually completes.

 !States
 Apart from the three states corresponding to the command processing flow (CBW,
 command processing and CSW), two more can be identified. The
 reception/emission of CBW/CSW will be broken down into two different states:
 the first state is used to issue the read/write operation, while the second
 one waits for the transfer to finish. This can be done by monitoring a
 "transfer complete" flag which is set using a callback function.

 In addition, some commands can be quite complicated to process: they may
 require several consecutive data transfers mixed with media access. Each
 command thus has its own second-tier state machine. During execution of a
 command, the main state machine remains in the "processing" state, and
 proceeds to the next one (CSW emission) only when the command is complete.

 Here is the states list:
 - MSDDriver_STATE_READ_CBW: Start of CBW reception
   (initial state after reset)
 - MSDDriver_STATE_WAIT_CBW: Waiting for CBW reception
 - MSDDriver_STATE_PROCESS_CBW: Command processing
 - MSDDriver_STATE_SEND_CSW: Start of CSW emission
 - MSDDriver_STATE_WAIT_CSW: Waiting for CSW emission

 A single function, named MSDDriver_StateMachine, is provided by the driver. It
 must be called regularly during the program execution. The following
 subsections describe the actions that must be performed during each state.

 \image MSDDriverStates.png "MSD Driver State Machine"

 #MSDDriver_STATE_READ_CBW#

 As said previously, this state is used to start the reception of a new Command
 Block Wrapper. This is done using the USB_Read method of the USB framework.
 The result code of the function is checked for any error; the
 USB_STATUS_SUCCESS code indicates that the transfer has been successfully
 started.
\code
//----------------------
case MSDDriver_STATE_READ_CBW:
//----------------------
    // Start the CBW read operation
    transfer->semaphore = 0;
    status = USBD_Read(MSDDriverDescriptors_BULKOUT,
                       cbw,
                       MSD_CBW_SIZE,
                       (TransferCallback) MSDDriver_Callback,
                       (void *) transfer);

    // Check operation result code
    if (status == USBD_STATUS_SUCCESS) {

        // If the command was successful, wait for transfer
        msdDriver.state = MSDDriver_STATE_WAIT_CBW;
    }
    break;
\endcode
 A callback function to invoke when the transfer is complete is provided to the
 USBD_Read method, to update a MSDTransfer structure. This structure
 indicates the transfer completion, the returned result code and the number of
 transferred and remaining bytes.
\code
typedef struct {
    unsigned int  transferred; //!< Number of bytes transferred
    unsigned int  remaining;   //!< Number of bytes not transferred
    unsigned char semaphore;   //!< Semaphore to indicate transfer completion
    unsigned char status;      //!< Operation result code
} MSDTransfer;
\endcode
 The callback function is trivial and thus not listed here.

 #MSDDriver_STATE_WAIT_CBW#

 The first step here is to monitor the }semaphore} field of the MSDTransfer
 structure (see above); this will enable detection of the transfer end. Please
 note that this field must be declared as volatile in C, or accesses to it
 might get optimized by the compiler; this can result in endless loops.

 If the transfer is complete, then the result code must be checked to see if
 there was an error. If the operation is successful, the state machine can
 proceed to command processing. Otherwise, it returns to the READ_CBW state.
\code
//----------------------
case MSDDriver_STATE_WAIT_CBW:
//----------------------
    // Check transfer semaphore
    if (transfer->semaphore > 0) {

        // Take semaphore and terminate transfer
        transfer->semaphore--;

        // Check if transfer was successful
        if (transfer->status == USBD_STATUS_SUCCESS) {

            // Process received command
            msdDriver.state = MSDDriver_STATE_PROCESS_CBW;
        }
        else if (transfer->status == USBD_STATUS_RESET) {

            msdDriver.state = MSDDriver_STATE_READ_CBW;
        }
        else {

            msdDriver.state = MSDDriver_STATE_READ_CBW;
        }
    }
    break;
\endcode

 #MSDDriver_STATE_PROCESS_CBW#

 Once the CBW has been received, its validity must be checked. A CBW is not
 valid if:
 - it has not been received right after a CSW was sent or a reset occured or
 - it is not exactly 31 bytes long or
 - its signature field is not equal to 43425355h

 The state machine prevents the first case from happening, so only the two
 other cases have to be verified.

 The number of bytes transferred during a USBD_Read operation is passed as an
 argument to the callback function, if one has been specified. As stated
 previously, such a function is used to fill a MSDTransfer structure.
 Therefore, it is trivial to check that the CBW is indeed 31 bytes by verifying
 that the number of bytes transferred is 31, and that there are no remaining
 bytes. The following table illustrates the three cases which may happen:
||Number of bytes transferred||Number of bytes remaining||Meaning
|transferred<31|remaining==0|CBW is too short
|transferred==31|remaining>0|CBW is too long
|transferred==31|remaining==0|CBW length is correct

 Checking the signature is simply done by comparing the dCBWSignature field
 with the expected value (43425355h).

 If the CBW is not valid, then the device must immediately halt both Bulk
 endpoints, to STALL further traffic from the host. In addition, it should stay
 in this state until a Reset Recovery is performed by the host. This is done by
 setting the waitResetRecovery flag in the MSDDriver structure. Finally, the
 CSW status is set to report an error, and the state machine is returned to
 MSDDriver_STATE_READ_CBW.

 Otherwise, if the CBW is correct, then the command can be processed. Remember
 the CBW tag must be copied regardless of the validity of the CBW.

 Note that these steps are only necessary for a new command (remember commands
 are asynchronous and are carried out in several calls, so a check can be
 performed to avoid useless processing. A value of zero for the internal
 command state indicates a new command.
\code
//-------------------------
case MSDDriver_STATE_PROCESS_CBW:
//-------------------------
    // Check if this is a new command
    if (commandState->state == 0) {

        // Copy the CBW tag
        csw->dCSWTag = cbw->dCBWTag;

        // Check that the CBW is 31 bytes long
        if ((transfer->transferred != MSD_CBW_SIZE) ||
            (transfer->remaining != 0)) {

            // Wait for a reset recovery
            msdDriver.waitResetRecovery = 1;

            // Halt the Bulk-IN and Bulk-OUT pipes
            USBD_Halt(MSDDriverDescriptors_BULKOUT);
            USBD_Halt(MSDDriverDescriptors_BULKIN);

            csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
            msdDriver.state = MSDDriver_STATE_READ_CBW;

        }
        // Check the CBW Signature
        else if (cbw->dCBWSignature != MSD_CBW_SIGNATURE) {

            // Wait for a reset recovery
            msdDriver.waitResetRecovery = 1;

            // Halt the Bulk-IN and Bulk-OUT pipes
            USBD_Halt(MSDDriverDescriptors_BULKOUT);
            USBD_Halt(MSDDriverDescriptors_BULKIN);

            csw->bCSWStatus = MSD_CSW_COMMAND_FAILED;
            msdDriver.state = MSDDriver_STATE_READ_CBW;
        }
        else {

            // Pre-process command
            MSDDriver_PreProcessCommand();
        }
    }

    // Process command
    if (csw->bCSWStatus == MSDDriver_STATUS_SUCCESS) {

        if (MSDDriver_ProcessCommand()) {

            // Post-process command if it is finished
            MSDDriver_PostProcessCommand();
            msdDriver.state = MSDDriver_STATE_SEND_CSW;
        }
    }

    break;
\endcode

 #MSDDriver_STATE_SEND_CSW#

 This state is similar to MSDDriver_STATE_READ_CBW, except that a write
 operation is performed instead of a read and the CSW is sent, not the CBW. The
 same callback function is used to fill the transfer structure, which is
 checked in the next state:
\code
//----------------------
case MSDDriver_STATE_SEND_CSW:
//----------------------
    // Set signature
    csw->dCSWSignature = MSD_CSW_SIGNATURE;

    // Start the CSW write operation
    status = USBD_Write(MSDDriverDescriptors_BULKIN,
                        csw,
                        MSD_CSW_SIZE,
                        (TransferCallback) MSDDriver_Callback,
                        (void *) transfer);

    // Check operation result code
    if (status == USBD_STATUS_SUCCESS) {

        // Wait for end of transfer
        msdDriver.state = MSDDriver_STATE_WAIT_CSW;
    }
    break;
\endcode

 #MSDDriver_STATE_WAIT_CSW#

 Again, this state is very similar to MSDDriver_STATE_WAIT_CBW. The only
 difference is that the state machine is set to MSDDriver_STATE_READ_CBW
 regardless of the operation result code:
\code
//----------------------
case MSDDriver_STATE_WAIT_CSW:
//----------------------
    // Check transfer semaphore
    if (transfer->semaphore > 0) {

        // Take semaphore and terminate transfer
        transfer->semaphore--;

        // Read new CBW
        msdDriver.state = MSDDriver_STATE_READ_CBW;
    }
    break;
\endcode

 !!Media

 USB MSD Media access is three-level abstraction.

 \image MSDMediaArch.png "Media Architecture"

 The bottom level is the specific driver for each media type (See memories).

 In the middle, a structure Media is used to hide which specific driver a media
 instance is using. This enables transparent use of any media driver once it
 has been initialized (See _Media).

 Finally, a LUN abstraction is made over the media structure to allow multiple
 partitions over one media. This also makes it possible to place the LUN at any
 address and use any block size. When performing a write or read operation on a
 LUN, it forwards the operation to the underlying media while translating it to
 the correct address and length.

 !Media Drivers
 A media driver must provide several functions for:
 - Reading data from the media
 - Writing data on the media
 - Handling interrupts on the media
 The last function may be empty if the media does not require interrupts for
 asynchronous operation, or if synchronous operation produces an acceptable
 delay.

 In addition, it should also define a function for initializing a Media
 structure with the correct values, as well as perform the necessary step for
 the media to be useable.

 For the drivers see:
 - MEDSdram.h: }Internal Flash Driver}
 - MEDFlash.h: }SDRAM disk driver}

 !!SCSI Commands

 The example software described in this application note uses SCSI commands
 with the MSD class, since this is the most appropriate setting for a Flash
 device. This section details how SCSI commands are processed.

 !Documents

 There are several documents covering SCSI commands. In this application note,
 the reference document used is SCSI Block Commands - 3 (SBC-3). However, it
 makes many references to another SCSI document, SCSI Primary Commands - 4
 (SPC-4). Both are needed for full details on required commands.

 !Endianness

 SCSI commands use the big-endian format for storing word- and double word-
 sized data. This means the Most Significant Bit (MSB) is stored at the
 lowest address, and the Least Significant Bit (LSB) at the highest one.

 On ARM Thumb microcontrollers, the endianness of the core is selectable.
 However, the little-endian mode is most often used. Therefore, SCSI command
 data must be converted before being usable. This is done by declaring
 word- and dword-sized fields as byte arrays, and then using a macro for
 loading or storing data. Several of them are available in the provided
 software:
 - Load
    - WORDB: Converts a big-endian word value to little-endian
    - DWORDB: Converts a big-endian double-word value to little-endian
 - Store
    - STORE_WORDB: Stores a little-endian word value in big-endian format
    - STORE_DWORDB: Stores a little-endian double-word value in big-endian format

 !Sense Data

 When an error happens during the execution of a command, it is recorded by the
 device. The host may then issue a Request Sense command to retrieve
 #Sense Data#, i.e., information about previous errors.

 While the sense data structure has many fields, only three are really
 important. The first one is the Sense Key. It indicates the result of the last
 command performed: success, media not ready, hardware error, etc. Two other
 fields can then be specified to give a more accurate description of the
 problem. They are named }Additional Sense Code} and }Additional Sense Code
 Qualifier}.

 In the example application, each LUN has its own sense data. It is updated
 during command execution if there is any error.

 !Commands

 The SBC-3 specification gives a list of mandatory and optional commands that
 are relevant for a block device (like a Flash drive). In practice, only a
 subset of the mandatory commands is effectively used by operating systems;
 conversely, several commands which are supposed to be optional are required.
 The software provided with this application note implements the following list
 of commands:
 - SBC-3
    - Prevent/Allow Medium Removal
    - Read (10)
    - Read Capacity (10)
    - Verify (10)
    - Write (10)
 - SPC-4
    - Inquiry
    - Mode Sense (6)
    - Request Sense
    - Test Unit Ready
 The commands are actually processed in SBC_ProcessCommand.

 }Internal State Machine}

 As previously stated, most commands have an internal state machine to prevent
 blocking the whole system during a data transfer (on the USB or when accessing
 a media). A result code is used to indicate that the corresponding function
 must be called again for the command to complete (MSDDriver_STATUS_SUCCESS).

 A command state structure is used by the driver to record several parameters
 during command processing:
\code
typedef struct {

    MSDTransfer transfer;       //!< Current transfer status
    MSCbw      cbw;             //!< Received CBW
    MSCsw      csw;             //!< CSW to send
    unsigned char  state;       //!< Current command state
    unsigned char  postprocess; //!< Actions to perform when command is complete
    unsigned int   length;      //!< Remaining length of command

} MSDCommandState;
\endcode

 Note that the }state} field must be initialized when the command is first
 called. A value of 0 means that no command is currently being executed.

 For the commands descriptions and implementation, please reffer to the SCSI
 spec. and source code.

 Functions to handle SCSI commands:
 - SBC_Inquiry
 - SBC_Read10
 - SBC_ReadCapacity10
 - SBC_RequestSense
 - SBC_TestUnitReady
 - SBC_Write10
 - SBC_ModeSense6

 !Command Processing

 }Flow}

 Command processing is actually divided into three phases in the example
 software:
 - Pre-processing: MSDDriver_PreProcessCommand
 - Processing: MSDDriver_ProcessCommand
 - Post-processing: MSDDriver_PostProcessCommand

 }The Thirteen Cases}

 There are basically three actions that should be performed depending on the
 case:
 - STALL the Bulk-IN endpoint
 - STALL the Bulk-OUT endpoint
 - Report a Phase Error in the CSW

 The table below lists all cases along with the actions which must be taken
 after the command, including the correct length/direction of the transfer. The
 following notation is used to characterize host and %device expectations:

 Data %Transfer Characterization
||Notation||Meaning||Notation||Meaning
|Hn|Host expects no data transfer|Dn|Device expects no data transfer
|Hi|Host expects to #receive# data|Di|Device expects to #send# data
|Ho|Host expects to #send# data|Do|Device expects to #receive# data
|Lh|Length of data expected by the host|Ld|Length of data expected by the %device

|Hx=Dx|Host and %device agree on transfer length and direction (x is either n, i or o)
|Hx>Dx|Host and %device agree on transfer direction, host expects a larger transfer than %device
|Hx<Dx|Host and %device agree on transfer direction, %device expects a larger transfer than host
|Hx<>Dx|Host and %device disagree on transfer direction

 The Thirteen Cases
||\#||Case||Length||Residue||Direction||STALL IN?||STALL OUT?||Phase Error?
|1|Hn = Dn|0|0|Irrelevant| | | 
|2|Hn < Di|0|Ld - Lh|Irrelevant| | |X
|3|Hn < Do|0|Ld - Lh|Irrelevant| | |X
|4|Hi > Dn|0|Lh|Irrelevant|X| | 
|5|Hi > Di|Ld|Lh - Ld|In|X| | 
|6|Hi = Di|Ld|0|In| | | 
|7|Hi < Di|Lh|Ld - Lh|In| | |X
|8|Hi <> Do|0|0|Irrelevant|X| |X
|9|Ho > Dn|0|Lh|Irrelevant| |X| 
|10|Ho <> Di|0|0|Irrelevant| |X|X
|11|Ho > Do|Ld|Lh - Ld|Out| |X| 
|12|Ho = Do|Ld|0|Out| | | 
|13|Ho < Do|Lh|Lh - Ld|Out| | |X

 !!Main Application
 After the MSD driver and the media have been initialized using the
 corresponding functions, the only requirement for the main application is to
 regularly call the state machine function. This is necessary for processing
 received commands in a fully asynchronous way.

 The application is otherwise free of doing any other task; for example, it
 could implement a filesystem and a serial port interface to be accessed with a
 standard terminal. An MP3 player could also continue playing a song while its
 memory is accessed like an external hard disk.

 \image MSDDriverClasses.png "Driver Class Diagram"

*/
/**
 \page "USB MSD Basic"

 This page gives generic details on the MSD class.

 !!!Purpose

 The MSD class defines how devices such as a hard disk, a USB floppy disk drive
 or a disk-on-key shall operate on the USB. These devices are referred to as
 mass storage devices, since they usually offer a high storage capacity. When
 plugged to a PC, a %device complying to the MSD specification is accessed like
 any other disk on the system.

 In practice, the specification only defines a way to wrap existing data
 transfer protocols, such as SCSI or the Reduced Block Commands (RBC) set. A
 list of the supported protocols and their uses will be given in the following
 section.

 !!!Data Transfer Protocols

 The }Mass Storagae Class Specification Overview 1.2} supports the following
 set of %devices:

 Protocols for MSD %devices
||Subclass Code||Command Block Spec.||Used by
|01h|Reduced Block Commands(RBC)|Flash %devices
|02h|SFF-8020i, MMC-2|CD & DVD %devices
|03h|QIC-157|Tape %devices
|04h|UFI|Floppy disk drives
|05h|SFF-8070i|Floppy disk drives
|06h|SCSI transparent command set|Any

 The SCSI transparent command set comprises all SCSI-related specifications,
 such as SCSI Primary Commands (SPC), SCSI Block Commands (SBC), and so on. A
 command will be issued by the host to determine exactly with which standard
 the %device is compliant.

 The protocol used by the %device is specified in its Interface descriptor, in
 the }bInterfaceSubclass} field.

 !!!Transfer Protocols

 There are actually two different transport protocols for the MSD class:
 - Control/Bulk/Interface (CBI) transport
 - Bulk-Only Transport (BOT)

 These two methods are described in two separate stand-alone documents. CBI can
 be considered obsolete and is being completely replaced by BOT. It was
 originally targeted at full-speed floppy disk drives. Therefore, the rest of
 this document will talk about Bulk-Only Transport exclusively.

 Transport Protocol Codes
||bInterfaceProtocol||Protocol Implementation
|00h|Control/Bulk/Interrupt protocol (with command completion interrupt)
|01h|Control/Bulk/Interrupt protocol (without command completion interrupt)
|50h|Bulk-only transport

 !!!Architecture
 ...

 !!Interfaces & Endpoints

 An MSD %device only needs one single interface. The bInterfaceClass field of
 the interface descriptor should be set to MSD class code (0x08), the
 corresponding data transfer protocol code in the }bInterfaceSubclass} field
 and transport protocol code in the }bInterfaceProtocol} field can be found in
 the tables on above.

 Exactly three %endpoints (when using the Bulk-Only Transport protocol) are
 necessary for MSD %devices.

 The first one is the Control endpoint 0, and is used for class-specific
 requests and for clearing Halt conditions on the other two %endpoints.
 Endpoints are halted in response to errors and host bad behavior during data
 transfers, and the CLEAR_FEATURE request is consequently used to return them
 to a functional state.

 The other two %endpoints, which are of type Bulk, are used for transferring
 commands and data over the bus. There must be one Bulk-IN and one Bulk-OUT
 endpoint.

 \image MSDDriverArch.png "Mass Storage Device Driver Architecture"

 !!Class-Specific Descriptors
 No class-specific descriptors for an MSD %device using the Bulk-only transfport
 protocol.

 !!Class-Specific Requests
 Two class specific requests should be handled.

 !GetMaxLUN
 A %device can feature one or more Logical Unit (LU). Each of these units will
 be treated as a separate disk when plugged to a computer. A %device can have up
 to 15 logical units.

 The GET_MAX_LUN request is issued by the host to determine the maximum Logical
 Unit Number (LUN) supported by the %device. This is not equivalent to the
 number of LU on the %device; since units are numbered starting from 0, a %device
 with 5 LUs should report a value of 4, which will be the index of the fifth
 unit.

 Optionally, a %device with only one LUN may STALL this request instead of
 returning a value of zero.

 !Bulk-Only Mass Storage Reset
 This request is used to reset the state of the %device and prepare it to
 receive commands and data. Note that the data toggle bits must not be altered
 by a RESET command; same for the Halt state of %endpoints, i.e., halted
 %endpoints must not be reset to a normal state.

 !!Command/Data/Status
 Each MSD transaction is divided into three steps:
 - Command stage
 - Data stage (optional)
 - Status stage

 During the command stage, a Command Block Wrapper (CBW) is transmitted by the
 host to the %device. The CBW describes several parameters of the transaction
 (direction, length, LUN) and carries a variable-length command block. The
 command block contains data in the format defined by the transfer protocol
 used by the %device.

 Command Block Wrapper Data Format
||Offset||Field Name||Length||Comment
|0|dCBWSignature|4 bytes|Signature to identify CBW, must be 43425355h
|4|dCBWTag|4 bytes|Tag sent by the host, echoed in the CSW
|8|dCBWTransferLength|4 bytes|Length of transfer during the data stage
|12|bmCBWFlags|1 byte|Bits 0-6: Reserved/obsolete\n
                      Bit 7: Transfer direction (0 = OUT, 1 = IN)
|13|bCBWLUN|1 byte|Bits 0-3: LUN to which the command is sent\n
                   Bits 4-7: Reserved
|14|bCBWCBLength|1 byte|Bits 0-5: Length of command block in bytes\n
                        Bits 6-7: Reserved
|15|CBWCB|0-16 bytes|Command block to be executed by the %device

 After the %device has received and interpreted the command, an optional data
 stage may take place if the command requires it. During this step, data is
 transferred either to or from the %device depending on the command, in several
 IN/OUT transfers.

 Once the data stage is complete, the host issues a final IN request on the
 Bulk-IN endpoint of the %device to request the Command Status Wrapper (CSW).
 The CSW is used to report correct or incorrect execution of the command, as
 well as indicating the length of remaining data that has not been transferred.

 Command Status Wrapper
||Offset||Field Name||Length||Comment
|0|dCSWSignature|4 bytes|Signature to identify CSW, must be 53425355h
|4|dCSWTag|4 bytes|Copy of previous CBW tag
|8|dCSWDataResidue|4 bytes|Difference between expected and real transfer length
|12|bCSWStatus|1 byte|Indicates the success or failure of the command

 These steps are all performed on the two Bulk %endpoints, and do not involve
 Control endpoint 0 at all.

 !!Reset Recovery
 When severe errors occur during command or data transfers (as defined in the
 }Mass Storage Bulk-only Transport 1.0} document), the %device must halt both
 Bulk %endpoints and wait for a #Reset Recovery# procedure. The Reset Recovery
 sequence goes as follows:
 - The host issues a Bulk-Only Mass Storage Reset request
 - The host issues two #CLEAR_FEATURE# requests to unhalt each endpoint

 A %device waiting for a Reset Recovery must not carry out CLEAR_FEATURE
 requests trying to unhalt either Bulk endpoint until after a Reset request has
 been received. This enables the host to distinguish between severe and minor
 errors.

 The only major error defined by the Bulk-Only Transport standard is when a CBW
 is not valid. This means one or more of the following:
 - The CBW is not received after a CSW has been sent or a reset.
 - The CBW is not exactly 31 bytes in length.
 - The dCBWSignature field of the CBW is not equal to 43425355h.

 !!!Host Drivers
 Almost all operating systems now provide a generic driver for the MSD class.
 However, the set of supported data transfer protocols may vary. For example,
 Microsoft Windows does not currently support the Reduced Block Command set.

*/
personal git repositories of Harald Welte. Your mileage may vary