1 /* Copyright (C) 2011 Circuits At Home, LTD. All rights reserved.
3 This software may be distributed and modified under the terms of the GNU
4 General Public License version 2 (GPL2) as published by the Free Software
5 Foundation and appearing in the file GPL2.TXT included in the packaging of
6 this file. Please note that GPL2 Section 2[b] requires that all works based
7 on this software must also be made publicly available under the terms of
14 Web : http://www.circuitsathome.com
15 e-mail : support@circuitsathome.com
18 #if !defined(__MASSTORAGE_H__)
19 #define __MASSTORAGE_H__
21 // Cruft removal, makes driver smaller, faster.
22 #ifndef MS_WANT_PARSER
23 #define MS_WANT_PARSER 0
28 #define bmREQ_MASSOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
29 #define bmREQ_MASSIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE
31 // Mass Storage Subclass Constants
32 #define MASS_SUBCLASS_SCSI_NOT_REPORTED 0x00 // De facto use
33 #define MASS_SUBCLASS_RBC 0x01
34 #define MASS_SUBCLASS_ATAPI 0x02 // MMC-5 (ATAPI)
35 #define MASS_SUBCLASS_OBSOLETE1 0x03 // Was QIC-157
36 #define MASS_SUBCLASS_UFI 0x04 // Specifies how to interface Floppy Disk Drives to USB
37 #define MASS_SUBCLASS_OBSOLETE2 0x05 // Was SFF-8070i
38 #define MASS_SUBCLASS_SCSI 0x06 // SCSI Transparent Command Set
39 #define MASS_SUBCLASS_LSDFS 0x07 // Specifies how host has to negotiate access before trying SCSI
40 #define MASS_SUBCLASS_IEEE1667 0x08
42 // Mass Storage Class Protocols
43 #define MASS_PROTO_CBI 0x00 // CBI (with command completion interrupt)
44 #define MASS_PROTO_CBI_NO_INT 0x01 // CBI (without command completion interrupt)
45 #define MASS_PROTO_OBSOLETE 0x02
46 #define MASS_PROTO_BBB 0x50 // Bulk Only Transport
47 #define MASS_PROTO_UAS 0x62
50 #define MASS_REQ_ADSC 0x00
51 #define MASS_REQ_GET 0xFC
52 #define MASS_REQ_PUT 0xFD
53 #define MASS_REQ_GET_MAX_LUN 0xFE
54 #define MASS_REQ_BOMSR 0xFF // Bulk-Only Mass Storage Reset
56 #define MASS_CBW_SIGNATURE 0x43425355
57 #define MASS_CSW_SIGNATURE 0x53425355
59 #define MASS_CMD_DIR_OUT 0 // (0 << 7)
60 #define MASS_CMD_DIR_IN 0x80 //(1 << 7)
63 * Reference documents from T10 (http://www.t10.org)
64 * SCSI Primary Commands - 3 (SPC-3)
65 * SCSI Block Commands - 2 (SBC-2)
66 * Multi-Media Commands - 5 (MMC-5)
69 /* Group 1 commands (CDB's here are should all be 6-bytes) */
70 #define SCSI_CMD_TEST_UNIT_READY 0x00
71 #define SCSI_CMD_REQUEST_SENSE 0x03
72 #define SCSI_CMD_FORMAT_UNIT 0x04
73 #define SCSI_CMD_READ_6 0x08
74 #define SCSI_CMD_WRITE_6 0x0A
75 #define SCSI_CMD_INQUIRY 0x12
76 #define SCSI_CMD_MODE_SELECT_6 0x15
77 #define SCSI_CMD_MODE_SENSE_6 0x1A
78 #define SCSI_CMD_START_STOP_UNIT 0x1B
79 #define SCSI_CMD_PREVENT_REMOVAL 0x1E
80 /* Group 2 Commands (CDB's here are 10-bytes) */
81 #define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
82 #define SCSI_CMD_READ_CAPACITY_10 0x25
83 #define SCSI_CMD_READ_10 0x28
84 #define SCSI_CMD_WRITE_10 0x2A
85 #define SCSI_CMD_SEEK_10 0x2B
86 #define SCSI_CMD_ERASE_10 0x2C
87 #define SCSI_CMD_WRITE_AND_VERIFY_10 0x2E
88 #define SCSI_CMD_VERIFY_10 0x2F
89 #define SCSI_CMD_SYNCHRONIZE_CACHE 0x35
90 #define SCSI_CMD_WRITE_BUFFER 0x3B
91 #define SCSI_CMD_READ_BUFFER 0x3C
92 #define SCSI_CMD_READ_SUBCHANNEL 0x42
93 #define SCSI_CMD_READ_TOC 0x43
94 #define SCSI_CMD_READ_HEADER 0x44
95 #define SCSI_CMD_PLAY_AUDIO_10 0x45
96 #define SCSI_CMD_GET_CONFIGURATION 0x46
97 #define SCSI_CMD_PLAY_AUDIO_MSF 0x47
98 #define SCSI_CMD_PLAY_AUDIO_TI 0x48
99 #define SCSI_CMD_PLAY_TRACK_REL_10 0x49
100 #define SCSI_CMD_GET_EVENT_STATUS 0x4A
101 #define SCSI_CMD_PAUSE_RESUME 0x4B
102 #define SCSI_CMD_READ_DISC_INFORMATION 0x51
103 #define SCSI_CMD_READ_TRACK_INFORMATION 0x52
104 #define SCSI_CMD_RESERVE_TRACK 0x53
105 #define SCSI_CMD_SEND_OPC_INFORMATION 0x54
106 #define SCSI_CMD_MODE_SELECT_10 0x55
107 #define SCSI_CMD_REPAIR_TRACK 0x58
108 #define SCSI_CMD_MODE_SENSE_10 0x5A
109 #define SCSI_CMD_CLOSE_TRACK_SESSION 0x5B
110 #define SCSI_CMD_READ_BUFFER_CAPACITY 0x5C
111 #define SCSI_CMD_SEND_CUE_SHEET 0x5D
112 /* Group 5 Commands (CDB's here are 12-bytes) */
113 #define SCSI_CMD_REPORT_LUNS 0xA0
114 #define SCSI_CMD_BLANK 0xA1
115 #define SCSI_CMD_SECURITY_PROTOCOL_IN 0xA2
116 #define SCSI_CMD_SEND_KEY 0xA3
117 #define SCSI_CMD_REPORT_KEY 0xA4
118 #define SCSI_CMD_PLAY_AUDIO_12 0xA5
119 #define SCSI_CMD_LOAD_UNLOAD 0xA6
120 #define SCSI_CMD_SET_READ_AHEAD 0xA7
121 #define SCSI_CMD_READ_12 0xA8
122 #define SCSI_CMD_PLAY_TRACK_REL_12 0xA9
123 #define SCSI_CMD_WRITE_12 0xAA
124 #define SCSI_CMD_READ_MEDIA_SERIAL_12 0xAB
125 #define SCSI_CMD_GET_PERFORMANCE 0xAC
126 #define SCSI_CMD_READ_DVD_STRUCTURE 0xAD
127 #define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xB5
128 #define SCSI_CMD_SET_STREAMING 0xB6
129 #define SCSI_CMD_READ_MSF 0xB9
130 #define SCSI_CMD_SET_SPEED 0xBB
131 #define SCSI_CMD_MECHANISM_STATUS 0xBD
132 #define SCSI_CMD_READ_CD 0xBE
133 #define SCSI_CMD_SEND_DISC_STRUCTURE 0xBF
134 /* Vendor-unique Commands, included for completeness */
135 #define SCSI_CMD_CD_PLAYBACK_STATUS 0xC4 /* SONY unique */
136 #define SCSI_CMD_PLAYBACK_CONTROL 0xC9 /* SONY unique */
137 #define SCSI_CMD_READ_CDDA 0xD8 /* Vendor unique */
138 #define SCSI_CMD_READ_CDXA 0xDB /* Vendor unique */
139 #define SCSI_CMD_READ_ALL_SUBCODES 0xDF /* Vendor unique */
141 /* SCSI error codes */
142 #define SCSI_S_NOT_READY 0x02
143 #define SCSI_S_MEDIUM_ERROR 0x03
144 #define SCSI_S_ILLEGAL_REQUEST 0x05
145 #define SCSI_S_UNIT_ATTENTION 0x06
146 #define SCSI_ASC_LBA_OUT_OF_RANGE 0x21
147 #define SCSI_ASC_MEDIA_CHANGED 0x28
148 #define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3A
150 /* USB error codes */
151 #define MASS_ERR_SUCCESS 0x00
152 #define MASS_ERR_PHASE_ERROR 0x02
153 #define MASS_ERR_UNIT_NOT_READY 0x03
154 #define MASS_ERR_UNIT_BUSY 0x04
155 #define MASS_ERR_STALL 0x05
156 #define MASS_ERR_CMD_NOT_SUPPORTED 0x06
157 #define MASS_ERR_INVALID_CSW 0x07
158 #define MASS_ERR_NO_MEDIA 0x08
159 #define MASS_ERR_BAD_LBA 0x09
160 #define MASS_ERR_MEDIA_CHANGED 0x0A
161 #define MASS_ERR_DEVICE_DISCONNECTED 0x11
162 #define MASS_ERR_UNABLE_TO_RECOVER 0x12 // Reset recovery error
163 #define MASS_ERR_INVALID_LUN 0x13
164 #define MASS_ERR_WRITE_STALL 0x14
165 #define MASS_ERR_READ_NAKS 0x15
166 #define MASS_ERR_WRITE_NAKS 0x16
167 #define MASS_ERR_WRITE_PROTECTED 0x17
168 #define MASS_ERR_NOT_IMPLEMENTED 0xFD
169 #define MASS_ERR_GENERAL_SCSI_ERROR 0xFE
170 #define MASS_ERR_GENERAL_USB_ERROR 0xFF
171 #define MASS_ERR_USER 0xA0 // For subclasses to define their own error codes
173 #define MASS_TRANS_FLG_CALLBACK 0x01 // Callback is involved
174 #define MASS_TRANS_FLG_NO_STALL_CHECK 0x02 // STALL condition is not checked
175 #define MASS_TRANS_FLG_NO_PHASE_CHECK 0x04 // PHASE_ERROR is not checked
177 #define MASS_MAX_ENDPOINTS 3
181 //uint32_t dwBlockAddress;
182 //uint32_t dwBlockLength;
183 } __attribute__((packed
));
192 } __attribute__((packed
));
194 typedef BASICCDB BASICCDB_t
;
204 uint8_t AllocationLength
;
209 CDB6(uint8_t _Opcode
, uint8_t _LUN
, uint32_t LBA
, uint8_t _AllocationLength
, uint8_t _Control
) :
210 Opcode(_Opcode
), LBAMSB(BGRAB2(LBA
) & 0x1f), LUN(_LUN
), LBAHB(BGRAB1(LBA
)), LBALB(BGRAB0(LBA
)),
211 AllocationLength(_AllocationLength
), Control(_Control
) {
214 CDB6(uint8_t _Opcode
, uint8_t _LUN
, uint8_t _AllocationLength
, uint8_t _Control
) :
215 Opcode(_Opcode
), LBAMSB(0), LUN(_LUN
), LBAHB(0), LBALB(0),
216 AllocationLength(_AllocationLength
), Control(_Control
) {
218 } __attribute__((packed
));
225 unsigned Service_Action
: 5;
241 CDB10(uint8_t _Opcode
, uint8_t _LUN
) :
242 Opcode(_Opcode
), Service_Action(0), LUN(_LUN
),
243 LBA_L_M_MB(0), LBA_L_M_LB(0), LBA_L_L_MB(0), LBA_L_L_LB(0),
244 Misc2(0), ALC_MB(0), ALC_LB(0), Control(0) {
247 CDB10(uint8_t _Opcode
, uint8_t _LUN
, uint16_t xflen
, uint32_t _LBA
) :
248 Opcode(_Opcode
), Service_Action(0), LUN(_LUN
),
249 LBA_L_M_MB(BGRAB3(_LBA
)), LBA_L_M_LB(BGRAB2(_LBA
)), LBA_L_L_MB(BGRAB1(_LBA
)), LBA_L_L_LB(BGRAB0(_LBA
)),
250 Misc2(0), ALC_MB(BGRAB1(xflen
)), ALC_LB(BGRAB0(xflen
)), Control(0) {
252 } __attribute__((packed
));
254 typedef CDB10 CDB10_t
;
259 unsigned Service_Action
: 5;
270 } __attribute__((packed
));
272 typedef CDB12 CDB12_t
;
274 struct CDB_LBA32_16
{
277 unsigned Service_Action
: 5;
297 } __attribute__((packed
));
299 struct CDB_LBA64_16
{
320 } __attribute__((packed
));
322 struct InquiryResponse
{
323 uint8_t DeviceType
: 5;
324 uint8_t PeripheralQualifier
: 3;
326 unsigned Reserved
: 7;
327 unsigned Removable
: 1;
331 unsigned ResponseDataFormat
: 4;
333 unsigned NormACA
: 1;
337 uint8_t AdditionalLength
;
338 //uint8_t Reserved3[2];
340 unsigned PROTECT
: 1;
342 unsigned ThreePC
: 1;
353 unsigned ENCSERV
: 1;
356 unsigned SoftReset
: 1;
358 unsigned Reserved4
: 1;
361 unsigned WideBus16Bit
: 1;
362 unsigned WideBus32Bit
: 1;
363 unsigned RelAddr
: 1;
366 uint8_t ProductID
[16];
367 uint8_t RevisionID
[4];
368 } __attribute__((packed
));
370 struct CommandBlockWrapperBase
{
371 uint32_t dCBWSignature
;
373 uint32_t dCBWDataTransferLength
;
377 CommandBlockWrapperBase() {
380 CommandBlockWrapperBase(uint32_t tag
, uint32_t xflen
, uint8_t flgs
) :
381 dCBWSignature(MASS_CBW_SIGNATURE
), dCBWTag(tag
), dCBWDataTransferLength(xflen
), bmCBWFlags(flgs
) {
383 } __attribute__((packed
));
385 struct CommandBlockWrapper
: public CommandBlockWrapperBase
{
388 uint8_t bmCBWLUN
: 4;
389 uint8_t bmReserved1
: 4;
393 uint8_t bmCBWCBLength
: 4;
394 uint8_t bmReserved2
: 4;
402 CommandBlockWrapper() :
403 CommandBlockWrapperBase(0, 0, 0), bmReserved1(0), bmReserved2(0) {
404 for(int i
= 0; i
< 16; i
++) CBWCB
[i
] = 0;
407 // Generic Wrap, CDB zeroed.
409 CommandBlockWrapper(uint32_t tag
, uint32_t xflen
, uint8_t flgs
, uint8_t lu
, uint8_t cmdlen
, uint8_t cmd
) :
410 CommandBlockWrapperBase(tag
, xflen
, flgs
),
411 bmCBWLUN(lu
), bmReserved1(0), bmCBWCBLength(cmdlen
), bmReserved2(0) {
412 for(int i
= 0; i
< 16; i
++) CBWCB
[i
] = 0;
413 // Type punning can cause optimization problems and bugs.
414 // Using reinterpret_cast to a dreinterpretifferent object is the proper way to do this.
415 //(((BASICCDB_t *) CBWCB)->LUN) = cmd;
416 BASICCDB_t
*x
= reinterpret_cast<BASICCDB_t
*>(CBWCB
);
422 CommandBlockWrapper(uint32_t tag
, uint32_t xflen
, CDB6_t
*cdb
, uint8_t dir
) :
423 CommandBlockWrapperBase(tag
, xflen
, dir
),
424 bmCBWLUN(cdb
->LUN
), bmReserved1(0), bmCBWCBLength(6), bmReserved2(0) {
425 memcpy(&CBWCB
, cdb
, 6);
427 // Wrap for CDB of 10
429 CommandBlockWrapper(uint32_t tag
, uint32_t xflen
, CDB10_t
*cdb
, uint8_t dir
) :
430 CommandBlockWrapperBase(tag
, xflen
, dir
),
431 bmCBWLUN(cdb
->LUN
), bmReserved1(0), bmCBWCBLength(10), bmReserved2(0) {
432 memcpy(&CBWCB
, cdb
, 10);
434 } __attribute__((packed
));
436 struct CommandStatusWrapper
{
437 uint32_t dCSWSignature
;
439 uint32_t dCSWDataResidue
;
441 } __attribute__((packed
));
443 struct RequestSenseResponce
{
444 uint8_t bResponseCode
;
445 uint8_t bSegmentNumber
;
447 uint8_t bmSenseKey
: 4;
448 uint8_t bmReserved
: 1;
451 uint8_t bmFileMark
: 1;
453 uint8_t Information
[4];
454 uint8_t bAdditionalLength
;
455 uint8_t CmdSpecificInformation
[4];
456 uint8_t bAdditionalSenseCode
;
457 uint8_t bAdditionalSenseQualifier
;
458 uint8_t bFieldReplaceableUnitCode
;
459 uint8_t SenseKeySpecific
[3];
460 } __attribute__((packed
));
462 class BulkOnly
: public USBDeviceConfig
, public UsbConfigXtracter
{
464 static const uint8_t epDataInIndex
; // DataIn endpoint index
465 static const uint8_t epDataOutIndex
; // DataOUT endpoint index
466 static const uint8_t epInterruptInIndex
; // InterruptIN endpoint index
470 uint8_t bConfNum
; // configuration number
471 uint8_t bIface
; // interface value
472 uint8_t bNumEP
; // total number of EP in the configuration
473 uint32_t qNextPollTime
; // next poll time
474 bool bPollEnable
; // poll enable flag
476 EpInfo epInfo
[MASS_MAX_ENDPOINTS
];
478 uint32_t dCBWTag
; // Tag
479 //uint32_t dCBWDataTransferLength; // Data Transfer Length
480 uint8_t bLastUsbError
; // Last USB error
481 uint8_t bMaxLUN
; // Max LUN
482 uint8_t bTheLUN
; // Active LUN
483 uint32_t CurrentCapacity
[MASS_MAX_SUPPORTED_LUN
]; // Total sectors
484 uint16_t CurrentSectorSize
[MASS_MAX_SUPPORTED_LUN
]; // Sector size, clipped to 16 bits
485 bool LUNOk
[MASS_MAX_SUPPORTED_LUN
]; // use this to check for media changes.
486 bool WriteOk
[MASS_MAX_SUPPORTED_LUN
];
487 void PrintEndpointDescriptor(const USB_ENDPOINT_DESCRIPTOR
* ep_ptr
);
490 // Additional Initialization Method for Subclasses
492 virtual uint8_t OnInit() {
498 uint8_t GetLastUsbError() {
499 return bLastUsbError
;
502 uint8_t GetbMaxLUN() {
503 return bMaxLUN
; // Max LUN
506 uint8_t GetbTheLUN() {
507 return bTheLUN
; // Active LUN
510 bool WriteProtected(uint8_t lun
);
511 uint8_t MediaCTL(uint8_t lun
, uint8_t ctl
);
512 uint8_t Read(uint8_t lun
, uint32_t addr
, uint16_t bsize
, uint8_t blocks
, uint8_t *buf
);
513 uint8_t Read(uint8_t lun
, uint32_t addr
, uint16_t bsize
, uint8_t blocks
, USBReadParser
*prs
);
514 uint8_t Write(uint8_t lun
, uint32_t addr
, uint16_t bsize
, uint8_t blocks
, const uint8_t *buf
);
515 uint8_t LockMedia(uint8_t lun
, uint8_t lock
);
517 bool LUNIsGood(uint8_t lun
);
518 uint32_t GetCapacity(uint8_t lun
);
519 uint16_t GetSectorSize(uint8_t lun
);
521 // USBDeviceConfig implementation
522 uint8_t Init(uint8_t parent
, uint8_t port
, bool lowspeed
);
523 uint8_t ConfigureDevice(uint8_t parent
, uint8_t port
, bool lowspeed
);
528 virtual uint8_t GetAddress() {
532 // UsbConfigXtracter implementation
533 void EndpointXtract(uint8_t conf
, uint8_t iface
, uint8_t alt
, uint8_t proto
, const USB_ENDPOINT_DESCRIPTOR
*ep
);
535 virtual bool DEVCLASSOK(uint8_t klass
) {
536 return (klass
== USB_CLASS_MASS_STORAGE
);
539 uint8_t SCSITransaction6(CDB6_t
*cdb
, uint16_t buf_size
, void *buf
, uint8_t dir
);
540 uint8_t SCSITransaction10(CDB10_t
*cdb
, uint16_t buf_size
, void *buf
, uint8_t dir
);
543 uint8_t Inquiry(uint8_t lun
, uint16_t size
, uint8_t *buf
);
544 uint8_t TestUnitReady(uint8_t lun
);
545 uint8_t RequestSense(uint8_t lun
, uint16_t size
, uint8_t *buf
);
546 uint8_t ModeSense6(uint8_t lun
, uint8_t pc
, uint8_t page
, uint8_t subpage
, uint8_t len
, uint8_t *buf
);
547 uint8_t GetMaxLUN(uint8_t *max_lun
);
548 uint8_t SetCurLUN(uint8_t lun
);
550 uint8_t ResetRecovery();
551 uint8_t ReadCapacity10(uint8_t lun
, uint8_t *buf
);
554 bool CheckLUN(uint8_t lun
);
555 uint8_t Page3F(uint8_t lun
);
556 bool IsValidCBW(uint8_t size
, uint8_t *pcbw
);
557 bool IsMeaningfulCBW(uint8_t size
, uint8_t *pcbw
);
559 bool IsValidCSW(CommandStatusWrapper
*pcsw
, CommandBlockWrapperBase
*pcbw
);
561 uint8_t ClearEpHalt(uint8_t index
);
563 uint8_t Transaction(CommandBlockWrapper
*cbw
, uint16_t bsize
, void *buf
, uint8_t flags
);
565 uint8_t Transaction(CommandBlockWrapper
*cbw
, uint16_t bsize
, void *buf
);
566 uint8_t HandleUsbError(uint8_t error
, uint8_t index
);
567 uint8_t HandleSCSIError(uint8_t status
);
571 #endif // __MASSTORAGE_H__