summaryrefslogtreecommitdiff
path: root/digital/zigbit/bitcloud/stack/Components/HAL/drivers/USBClasses/MSD/src/scsiProtocol.c
blob: 68c3cfb6cf06e0eb798e51987cd3324228dfbc12 (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
/****************************************************************************//**
  \files scsiProtocol.h

  \brief Implementation of communication device protocol command.

  \author
    Atmel Corporation: http://www.atmel.com \n
    Support email: avr@atmel.com

  Copyright (c) 2008-2011, Atmel Corporation. All rights reserved.
  Licensed under Atmel's Limited License Agreement (BitCloudTM).

  \internal
  History:
    30/08/11 N. Fomin - Created
*******************************************************************************/
/******************************************************************************
                   Includes section
******************************************************************************/
#include <scsiProtocol.h>

/******************************************************************************
                   Define(s) section
******************************************************************************/
// scsi commands
#define INQUIRY                      0x12
#define READ_CAPACITY_10             0x25
#define READ_10                      0x28
#define REQUEST_SENSE                0x03
#define TEST_UNIT_READY              0x00
#define WRITE_10                     0x2A
#define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
#define MODE_SENSE_6                 0x1A
#define READ_FORMAT_CAPACITIES       0x23
#define VERIFY_10                    0x2F

// capacity definitions
#define BLOCK_SIZE        512

//inquiry definitions
#define INQUIRY_PERIPHERAL        0x00
#define INQUIRY_REMOVABLE         0x80
#define INQUIRY_VERSION           0x04
#define INQUIRY_RESPONSE_FORMAT   0x02
#define INQUIRY_ADDITIONAL_LENGTH 0x20
#define INQUIRY_FLAGS             0x00
#define INQUIRY_VENDOR_ID         "Atmel   "
#define INQUIRY_PRODUCT_ID        "Mass Storage    "
#define INQUIRY_PRODUCT_REVISION  "0001"

// request sense definitions
#define REQUEST_SENSE_CODE                            0xF0
#define REQUEST_SENSE_OBSOLETE                        0x00
#define REQUEST_SENSE_NORMAL_FLAGS                    0x00
#define REQUEST_SENSE_ERROR_FLAGS                     0x05
#define REQUEST_SENSE_INFO                            0x00
#define REQUEST_SENSE_ADDITIONAL_SENSE_LENGTH         0x0A
#define REQUEST_SENSE_CMD_SPECIFIC_INFO               0x00
#define REQUEST_SENSE_NORMAL_ADDITIONAL_SENSE_CODE    0x00
#define REQUEST_SENSE_ERROR_ADDITIONAL_SENSE_CODE     0x20
#define REQUEST_SENSE_ADDITIONAL_SENSE_CODE_QUALIFIER 0x00
#define REQUEST_SENSE_FIELD_REPLACABLE_UNIT_CODE      0x00
#define REQUEST_SENSE_SENSE_KEY_SPECIFIC_VALID        0x80
#define REQUEST_SENSE_SENSE_KEY_SPECIFIC              0x00

// mode sense definitions
#define MODE_SENSE_LENGTH            0x03
#define MODE_SENSE_MEDIA_TYPE        0x00
#define MODE_SENSE_DEVICE_SPECIFIC   0x00
#define MODE_SENSE_BLOCK_DESC_LENGTH 0x00

// format capacities definitions
#define FORMAT_CAPACITIES_RESERVED  0x00
#define FORMAT_CAPACITIES_LENGTH    0x08
#define FORMAT_CAPACITIES_DESC_TYPE 0x01

/******************************************************************************
                   Types section
******************************************************************************/
BEGIN_PACK
typedef struct PACK
{
  uint32_t lastLogicalBlock;
  uint32_t logicalBlockLength;
} ScsiReadCapacityResponse_t;

typedef struct PACK
{
  uint8_t peripheral;
  uint8_t removable;
  uint8_t version;
  uint8_t responseDataFormat;
  uint8_t additionalLength;
  uint8_t flags[3];
  uint8_t vendorId[8];
  uint8_t productId[16];
  uint8_t productRevision[4];
} ScsiInquiryResponse_t;

typedef struct PACK
{
  uint8_t  responseCodeAndValid;
  uint8_t  obsolete;
  uint8_t  flags;
  uint32_t information;
  uint8_t  addSenseLen;
  uint32_t cmdSpecificInfo;
  uint8_t  additionalSenseCode;
  uint8_t  additionalSenseCodeQualifier;
  uint8_t  fieldReplacableUnitCode;
  uint8_t  senseKeySpecific[3];
} ScsiRequestSenseResponse_t;

typedef struct PACK
{
  uint8_t modeDataLength;
  uint8_t mediumType;
  uint8_t deviceSpecific;
  uint8_t blockDescriptorLength;
} ScsiModeSense6Response_t;

typedef struct PACK
{
  uint8_t reserved[3];
  uint8_t length;
  uint32_t blocksNumber;
  uint8_t descType;
  uint8_t blockLengthUp;
  uint16_t blockLengthDown;
} ScsiReadFormatCapacities_t;

typedef struct PACK
{
  uint8_t flags;
  uint32_t logicalBlockAddress;
  uint8_t groupNumber;
  uint16_t transferLength;
  uint8_t control;
} ScsiReadWriteCommand_t;

typedef struct PACK
{
  uint8_t index;
  union
  {
    ScsiReadWriteCommand_t rwCommand;
  };
} ScsiCommand_t;
END_PACK

/******************************************************************************
                   Global variables section
******************************************************************************/
static bool defaultRequestSenseResponse;
static uint32_t lastLogicalBlockNum;

/******************************************************************************
                   Constants section
******************************************************************************/
const ScsiInquiryResponse_t inquiryResponse = {
  INQUIRY_PERIPHERAL,
  INQUIRY_REMOVABLE,
  INQUIRY_VERSION,
  INQUIRY_RESPONSE_FORMAT,
  INQUIRY_ADDITIONAL_LENGTH,
  {INQUIRY_FLAGS, INQUIRY_FLAGS, INQUIRY_FLAGS},
  INQUIRY_VENDOR_ID,
  INQUIRY_PRODUCT_ID,
  INQUIRY_PRODUCT_REVISION
};

const ScsiRequestSenseResponse_t normalRequestSenseResponse = {
  REQUEST_SENSE_CODE,
  REQUEST_SENSE_OBSOLETE,
  REQUEST_SENSE_NORMAL_FLAGS,
  SWAP32(REQUEST_SENSE_INFO),
  REQUEST_SENSE_ADDITIONAL_SENSE_LENGTH,
  SWAP32(REQUEST_SENSE_CMD_SPECIFIC_INFO),
  REQUEST_SENSE_NORMAL_ADDITIONAL_SENSE_CODE,
  REQUEST_SENSE_ADDITIONAL_SENSE_CODE_QUALIFIER,
  REQUEST_SENSE_FIELD_REPLACABLE_UNIT_CODE,
  {REQUEST_SENSE_SENSE_KEY_SPECIFIC_VALID, REQUEST_SENSE_SENSE_KEY_SPECIFIC, REQUEST_SENSE_SENSE_KEY_SPECIFIC} 
};

const ScsiRequestSenseResponse_t errorRequestSenseResponse = {
  REQUEST_SENSE_CODE,
  REQUEST_SENSE_OBSOLETE,
  REQUEST_SENSE_ERROR_FLAGS,
  SWAP32(REQUEST_SENSE_INFO),
  REQUEST_SENSE_ADDITIONAL_SENSE_LENGTH,
  SWAP32(REQUEST_SENSE_CMD_SPECIFIC_INFO),
  REQUEST_SENSE_ERROR_ADDITIONAL_SENSE_CODE,
  REQUEST_SENSE_ADDITIONAL_SENSE_CODE_QUALIFIER,
  REQUEST_SENSE_FIELD_REPLACABLE_UNIT_CODE,
  {REQUEST_SENSE_SENSE_KEY_SPECIFIC_VALID, REQUEST_SENSE_SENSE_KEY_SPECIFIC, REQUEST_SENSE_SENSE_KEY_SPECIFIC} 
};

const ScsiModeSense6Response_t modeSense6Response = {
  MODE_SENSE_LENGTH,
  MODE_SENSE_MEDIA_TYPE,
  MODE_SENSE_DEVICE_SPECIFIC,
  MODE_SENSE_BLOCK_DESC_LENGTH
};

/******************************************************************************
                   Implementations section
******************************************************************************/

/**************************************************************************//**
\brief Checks if received scsi command is supported.
\param[in]
  data - pointer to received command with parameters.
\return
  false - command is not supported;
  true - command is supported.
******************************************************************************/
bool scsiIsValidCommand(uint8_t *data)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  
  command->rwCommand.transferLength = SWAP16(command->rwCommand.transferLength);
  command->rwCommand.logicalBlockAddress = SWAP32(command->rwCommand.logicalBlockAddress);

  switch (command->index)
  {
    case INQUIRY:
    case READ_CAPACITY_10:
    case TEST_UNIT_READY:
    case PREVENT_ALLOW_MEDIUM_REMOVAL:
    case READ_10:
    case WRITE_10:
    case MODE_SENSE_6:
    case READ_FORMAT_CAPACITIES:
    case VERIFY_10:
      defaultRequestSenseResponse = true;
      break;
    case REQUEST_SENSE:
      return true;
    default:
      defaultRequestSenseResponse = false;
      break;
  }

  return defaultRequestSenseResponse;
}

/**************************************************************************//**
\brief Checks if any response or data transfer needed for received
       scsi command.
\param[in]
  command - received command.
\return
  false - response is not needed;
  true - response is needed.
******************************************************************************/
bool scsiIsDataInOutPhaseNeeded(uint8_t *data)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  
  if ((TEST_UNIT_READY == command->index) || (PREVENT_ALLOW_MEDIUM_REMOVAL == command->index)
      || (VERIFY_10 == command->index))
    return false;
  if ((READ_10 == command->index) || (WRITE_10 == command->index))
    if (0 == command->rwCommand.transferLength)
      return false;
  return true;
}

/**************************************************************************//**
\brief Checks if command is read or write command.
\param[in]
  command - received command.
\return
  false - command is not read/write command;
  true - command is read/write command.
******************************************************************************/
bool scsiIsReadWriteCommand(uint8_t *data)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  
  return ((READ_10 == command->index) || (WRITE_10 == command->index));
}

/**************************************************************************//**
\brief Checks if command is read command.
\param[in]
  command - received command.
\return
  false - command is not read command;
  true - command is read command.
******************************************************************************/
bool scsiIsReadCommand(uint8_t *data)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  
  return (READ_10 == command->index);
}

/**************************************************************************//**
\brief Blocks for read/write command.
\param[in]
  data - pointer to received command with parameters.
\return
  number of blocks to read or write from memory.
******************************************************************************/
uint16_t scsiBlocksAmount(uint8_t *data)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  
  if ((READ_10 == command->index) || (WRITE_10 == command->index))
    return command->rwCommand.transferLength;

  return 0;
}

/**************************************************************************//**
\brief Response for scsi command.
\param[in]
  command - received command.
\param[out]
  buffer - buffer with scsi command response.
\return
  length of response
******************************************************************************/
uint8_t scsiGetCommandResponse(uint8_t *data, uint8_t *buffer)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  ScsiReadCapacityResponse_t readCapacityResponse = {
    .lastLogicalBlock = SWAP32(lastLogicalBlockNum),
    .logicalBlockLength = SWAP32(BLOCK_SIZE)
  };
  ScsiReadFormatCapacities_t readFormatCapacitiesResponse = {
    .reserved = {FORMAT_CAPACITIES_RESERVED, FORMAT_CAPACITIES_RESERVED, FORMAT_CAPACITIES_RESERVED},
    .length = FORMAT_CAPACITIES_LENGTH,
    .blocksNumber = SWAP32(lastLogicalBlockNum + 1),
    .descType = FORMAT_CAPACITIES_DESC_TYPE,
    .blockLengthUp = 0,
    .blockLengthDown = SWAP16(BLOCK_SIZE)
  };

  if (INQUIRY == command->index)
  {
    memcpy(buffer, (uint8_t *)&inquiryResponse, sizeof(ScsiInquiryResponse_t));
    return sizeof(ScsiInquiryResponse_t);
  }
  if (READ_CAPACITY_10 == command->index)
  {
    memcpy(buffer, (uint8_t *)&readCapacityResponse, sizeof(ScsiReadCapacityResponse_t));
    return sizeof(ScsiReadCapacityResponse_t);
  }
  if (REQUEST_SENSE == command->index)
  {
    if (defaultRequestSenseResponse)
      memcpy(buffer, (uint8_t *)&normalRequestSenseResponse, sizeof(ScsiRequestSenseResponse_t));
    else
      memcpy(buffer, (uint8_t *)&errorRequestSenseResponse, sizeof(ScsiRequestSenseResponse_t));
    return sizeof(ScsiRequestSenseResponse_t);
  }
  if (MODE_SENSE_6 == command->index)
  {
    memcpy(buffer, (uint8_t *)&modeSense6Response, sizeof(ScsiModeSense6Response_t));
    return sizeof(ScsiModeSense6Response_t);
  } 
  if (READ_FORMAT_CAPACITIES == command->index)
  {
    memcpy(buffer, (uint8_t *)&readFormatCapacitiesResponse, sizeof(ScsiReadFormatCapacities_t));
    return sizeof(ScsiReadFormatCapacities_t);
  }
  return 0;
}

/**************************************************************************//**
\brief Sets number of last available memory block for scsi response.
\param[in]
  lastBlock - received command.
\param[out]
  buffer - number of last available memory block
******************************************************************************/
void scsiSetCapacity(uint32_t lastBlock)
{
  lastLogicalBlockNum = lastBlock;
}

/**************************************************************************//**
\brief Block address for read/write command.
\param[in]
  data - pointer to received command with parameters.
\return
  block address for read or write from memory.
******************************************************************************/
uint32_t scsiGetBlockAddress(uint8_t *data)
{
  ScsiCommand_t *command = (ScsiCommand_t *)data;
  
  return command->rwCommand.logicalBlockAddress;
}

//eof scsiProtocol.c