Add SD keep-alive to ensure it responds immediately
[SCSI2SD-V6.git] / src / firmware / usb_device / usbd_msc_scsi.c
1 /**
2   ******************************************************************************
3   * @file    usbd_msc_scsi.c
4   * @author  MCD Application Team
5   * @version V2.4.1
6   * @date    19-June-2015
7   * @brief   This file provides all the USBD SCSI layer functions.
8   ******************************************************************************
9   * @attention
10   *
11   * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
12   *
13   * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
14   * You may not use this file except in compliance with the License.
15   * You may obtain a copy of the License at:
16   *
17   *        http://www.st.com/software_license_agreement_liberty_v2
18   *
19   * Unless required by applicable law or agreed to in writing, software 
20   * distributed under the License is distributed on an "AS IS" BASIS, 
21   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22   * See the License for the specific language governing permissions and
23   * limitations under the License.
24   *
25   ******************************************************************************
26   */ 
27
28 /* Includes ------------------------------------------------------------------*/
29 #include "usbd_composite.h"
30 #include "usbd_msc_bot.h"
31 #include "usbd_msc_scsi.h"
32 #include "usbd_msc.h"
33 #include "usbd_msc_data.h"
34
35
36
37 /** @addtogroup STM32_USB_DEVICE_LIBRARY
38   * @{
39   */
40
41
42 /** @defgroup MSC_SCSI 
43   * @brief Mass storage SCSI layer module
44   * @{
45   */ 
46
47 /** @defgroup MSC_SCSI_Private_TypesDefinitions
48   * @{
49   */ 
50 /**
51   * @}
52   */ 
53
54
55 /** @defgroup MSC_SCSI_Private_Defines
56   * @{
57   */ 
58
59 /**
60   * @}
61   */ 
62
63
64 /** @defgroup MSC_SCSI_Private_Macros
65   * @{
66   */ 
67 /**
68   * @}
69   */ 
70
71
72 /** @defgroup MSC_SCSI_Private_Variables
73   * @{
74   */ 
75
76 /**
77   * @}
78   */ 
79
80
81 /** @defgroup MSC_SCSI_Private_FunctionPrototypes
82   * @{
83   */ 
84 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
85 static int8_t SCSI_Inquiry(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
86 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
87 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
88 static int8_t SCSI_RequestSense (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
89 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
90 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
91 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
92 static int8_t SCSI_Write10(USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params);
93 static int8_t SCSI_Read10(USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params);
94 static int8_t SCSI_Verify10(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params);
95 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef  *pdev, 
96                                       uint8_t lun , 
97                                       uint32_t blk_offset , 
98                                       uint16_t blk_nbr);
99 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef  *pdev,
100                                 uint8_t lun);
101
102 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef  *pdev,
103                                  uint8_t lun);
104 /**
105   * @}
106   */ 
107
108
109 /** @defgroup MSC_SCSI_Private_Functions
110   * @{
111   */ 
112
113
114 /**
115 * @brief  SCSI_ProcessCmd
116 *         Process SCSI commands
117 * @param  pdev: device instance
118 * @param  lun: Logical unit number
119 * @param  params: Command parameters
120 * @retval status
121 */
122 int8_t SCSI_ProcessCmd(USBD_HandleTypeDef  *pdev,
123                            uint8_t lun, 
124                            uint8_t *params)
125 {
126   
127   switch (params[0])
128   {
129   case SCSI_TEST_UNIT_READY:
130     return SCSI_TestUnitReady(pdev, lun, params);
131     
132   case SCSI_REQUEST_SENSE:
133     return SCSI_RequestSense (pdev, lun, params);
134   case SCSI_INQUIRY:
135     return SCSI_Inquiry(pdev, lun, params);
136     
137   case SCSI_START_STOP_UNIT:
138     return SCSI_StartStopUnit(pdev, lun, params);
139     
140   case SCSI_ALLOW_MEDIUM_REMOVAL:
141     return SCSI_StartStopUnit(pdev, lun, params);
142     
143   case SCSI_MODE_SENSE6:
144     return SCSI_ModeSense6 (pdev, lun, params);
145     
146   case SCSI_MODE_SENSE10:
147     return SCSI_ModeSense10 (pdev, lun, params);
148     
149   case SCSI_READ_FORMAT_CAPACITIES:
150     return SCSI_ReadFormatCapacity(pdev, lun, params);
151     
152   case SCSI_READ_CAPACITY10:
153     return SCSI_ReadCapacity10(pdev, lun, params);
154     
155   case SCSI_READ10:
156     return SCSI_Read10(pdev, lun, params); 
157     
158   case SCSI_WRITE10:
159     return SCSI_Write10(pdev, lun, params);
160     
161   case SCSI_VERIFY10:
162     return SCSI_Verify10(pdev, lun, params);
163     
164   default:
165     SCSI_SenseCode(pdev, 
166                    lun,
167                    ILLEGAL_REQUEST, 
168                    INVALID_CDB);    
169     return -1;
170   }
171 }
172
173
174 /**
175 * @brief  SCSI_TestUnitReady
176 *         Process SCSI Test Unit Ready Command
177 * @param  lun: Logical unit number
178 * @param  params: Command parameters
179 * @retval status
180 */
181 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
182 {
183         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
184         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
185     
186   /* case 9 : Hi > D0 */
187   if (hmsc->cbw.dDataLength != 0)
188   {
189     SCSI_SenseCode(pdev,
190                    hmsc->cbw.bLUN, 
191                    ILLEGAL_REQUEST, 
192                    INVALID_CDB);
193     return -1;
194   }  
195   
196   if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
197   {
198     SCSI_SenseCode(pdev,
199                    lun,
200                    NOT_READY, 
201                    MEDIUM_NOT_PRESENT);
202     
203     hmsc->bot_state = USBD_BOT_NO_DATA;
204     return -1;
205   } 
206   hmsc->bot_data_length = 0;
207   return 0;
208 }
209
210 /**
211 * @brief  SCSI_Inquiry
212 *         Process Inquiry command
213 * @param  lun: Logical unit number
214 * @param  params: Command parameters
215 * @retval status
216 */
217 static int8_t  SCSI_Inquiry(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
218 {
219   uint8_t* pPage;
220   uint16_t len;
221
222         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
223         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
224   
225   if (params[1] & 0x01)/*Evpd is set*/
226   {
227     pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
228     len = LENGTH_INQUIRY_PAGE00;
229     if (params[4] <= len)
230     {
231       len = params[4];
232     }
233         memcpy(hmsc->bot_data, pPage, len);
234   }
235   else
236   {
237         len = ((USBD_StorageTypeDef *)pdev->pUserData)->Inquiry(lun, hmsc->bot_data, params[4]);
238     
239     if (params[4] <= len)
240     {
241       len = params[4];
242     }
243   }
244   hmsc->bot_data_length = len;
245
246   return 0;
247 }
248
249 /**
250 * @brief  SCSI_ReadCapacity10
251 *         Process Read Capacity 10 command
252 * @param  lun: Logical unit number
253 * @param  params: Command parameters
254 * @retval status
255 */
256 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
257 {
258         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
259         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
260   
261   if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
262   {
263     SCSI_SenseCode(pdev,
264                    lun,
265                    NOT_READY, 
266                    MEDIUM_NOT_PRESENT);
267     return -1;
268   } 
269   else
270   {
271     
272     hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
273     hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
274     hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >>  8);
275     hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
276     
277     hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >>  24);
278     hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >>  16);
279     hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >>  8);
280     hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
281     
282     hmsc->bot_data_length = 8;
283     return 0;
284   }
285 }
286 /**
287 * @brief  SCSI_ReadFormatCapacity
288 *         Process Read Format Capacity command
289 * @param  lun: Logical unit number
290 * @param  params: Command parameters
291 * @retval status
292 */
293 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
294 {
295         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
296         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
297   
298   uint16_t blk_size;
299   uint32_t blk_nbr;
300   uint16_t i;
301   
302   for(i=0 ; i < 12 ; i++) 
303   {
304     hmsc->bot_data[i] = 0;
305   }
306   
307   if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
308   {
309     // Capacity List Header
310     // [0] Reserved
311     // [1] Reserved
312     // [2] Reserved
313     
314     hmsc->bot_data[3] = 0x08; // Capacity List Length (8 bytes, 1 descriptor)
315
316     // Number of blocks. MAXIMUM
317     // 0x400000 is 2TB worth of 512 blocks.
318     hmsc->bot_data[4] = 0x00;
319     hmsc->bot_data[5] = 0x3F;
320     hmsc->bot_data[6] = 0xFF;
321     hmsc->bot_data[7] = 0xFF;
322     
323     hmsc->bot_data[8] = 0x03; // Descriptor code - No media.
324     hmsc->bot_data[9] = 0x00;
325     hmsc->bot_data[10] = 0x02; // 0x200 512 bytes
326     hmsc->bot_data[11] = 0x00;
327   } 
328   else
329   {
330     hmsc->bot_data[3] = 0x08;
331     hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
332     hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
333     hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >>  8);
334     hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
335     
336     hmsc->bot_data[8] = 0x02; // Descriptor code - Formatted media
337     hmsc->bot_data[9] = (uint8_t)(blk_size >>  16);
338     hmsc->bot_data[10] = (uint8_t)(blk_size >>  8);
339     hmsc->bot_data[11] = (uint8_t)(blk_size);
340   }
341     
342     hmsc->bot_data_length = 12;
343     return 0;
344 }
345
346 /**
347 * @brief  SCSI_ModeSense6
348 *         Process Mode Sense6 command
349 * @param  lun: Logical unit number
350 * @param  params: Command parameters
351 * @retval status
352 */
353 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
354 {
355         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
356         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
357
358   uint16_t len = 8 ;
359   hmsc->bot_data_length = len;
360   
361   while (len) 
362   {
363     len--;
364     hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
365   }
366   return 0;
367 }
368
369 /**
370 * @brief  SCSI_ModeSense10
371 *         Process Mode Sense10 command
372 * @param  lun: Logical unit number
373 * @param  params: Command parameters
374 * @retval status
375 */
376 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
377 {
378   uint16_t len = 8;
379         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
380         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
381   
382   hmsc->bot_data_length = len;
383
384   while (len) 
385   {
386     len--;
387     hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
388   }
389   return 0;
390 }
391
392 /**
393 * @brief  SCSI_RequestSense
394 *         Process Request Sense command
395 * @param  lun: Logical unit number
396 * @param  params: Command parameters
397 * @retval status
398 */
399
400 static int8_t SCSI_RequestSense (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
401 {
402   uint8_t i;
403         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
404         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
405   
406   for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) 
407   {
408     hmsc->bot_data[i] = 0;
409   }
410   
411   hmsc->bot_data[0]     = 0x70;         
412   hmsc->bot_data[7]     = REQUEST_SENSE_DATA_LEN - 6;   
413   
414   if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
415     
416     hmsc->bot_data[2]     = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;               
417     hmsc->bot_data[12]    = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;   
418     hmsc->bot_data[13]    = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;    
419     hmsc->scsi_sense_head++;
420     
421     if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
422     {
423       hmsc->scsi_sense_head = 0;
424     }
425   }
426   hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;  
427   
428   if (params[4] <= REQUEST_SENSE_DATA_LEN)
429   {
430     hmsc->bot_data_length = params[4];
431   }
432   return 0;
433 }
434
435 /**
436 * @brief  SCSI_SenseCode
437 *         Load the last error code in the error list
438 * @param  lun: Logical unit number
439 * @param  sKey: Sense Key
440 * @param  ASC: Additional Sense Key
441 * @retval none
442
443 */
444 void SCSI_SenseCode(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
445 {
446         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
447         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
448   
449   hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey  = sKey;
450   hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
451   hmsc->scsi_sense_tail++;
452   if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
453   {
454     hmsc->scsi_sense_tail = 0;
455   }
456 }
457 /**
458 * @brief  SCSI_StartStopUnit
459 *         Process Start Stop Unit command
460 * @param  lun: Logical unit number
461 * @param  params: Command parameters
462 * @retval status
463 */
464 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
465 {
466         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
467         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
468
469   hmsc->bot_data_length = 0;
470   return 0;
471 }
472
473 /**
474 * @brief  SCSI_Read10
475 *         Process Read10 command
476 * @param  lun: Logical unit number
477 * @param  params: Command parameters
478 * @retval status
479 */
480 static int8_t SCSI_Read10(USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params)
481 {
482         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
483         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
484   
485   if(hmsc->bot_state == USBD_BOT_IDLE)  /* Idle */
486   {
487     
488     /* case 10 : Ho <> Di */
489     
490     if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
491     {
492       SCSI_SenseCode(pdev,
493                      hmsc->cbw.bLUN, 
494                      ILLEGAL_REQUEST, 
495                      INVALID_CDB);
496       return -1;
497     }    
498     
499     if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
500     {
501       SCSI_SenseCode(pdev,
502                      lun,
503                      NOT_READY, 
504                      MEDIUM_NOT_PRESENT);
505       return -1;
506     } 
507     
508     hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
509       ((uint32_t)params[3] << 16) | \
510         ((uint32_t)params[4] <<  8) | \
511           (uint32_t)params[5];
512     
513     hmsc->scsi_blk_len =  ((uint32_t)params[7] <<  8) | \
514       (uint32_t)params[8];  
515     
516     
517     
518     if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
519     {
520       return -1; /* error */
521     }
522     
523     hmsc->bot_state = USBD_BOT_DATA_IN;
524     
525     /* cases 4,5 : Hi <> Dn */
526     if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
527     {
528       SCSI_SenseCode(pdev,
529                      hmsc->cbw.bLUN, 
530                      ILLEGAL_REQUEST, 
531                      INVALID_CDB);
532       return -1;
533     }
534   }
535   hmsc->bot_data_length = S2S_MSC_MEDIA_PACKET;  
536   
537   return SCSI_ProcessRead(pdev, lun);
538 }
539
540 /**
541 * @brief  SCSI_Write10
542 *         Process Write10 command
543 * @param  lun: Logical unit number
544 * @param  params: Command parameters
545 * @retval status
546 */
547
548 static int8_t SCSI_Write10 (USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params)
549 {
550   USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
551   USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
552   uint32_t len;
553   
554   if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
555   {
556     /* case 8 : Hi <> Do */
557     
558     if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
559     {
560       SCSI_SenseCode(pdev,
561                      hmsc->cbw.bLUN, 
562                      ILLEGAL_REQUEST, 
563                      INVALID_CDB);
564       return -1;
565     }
566     
567     /* Check whether Media is ready */
568     if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
569     {
570       SCSI_SenseCode(pdev,
571                      lun,
572                      NOT_READY, 
573                      MEDIUM_NOT_PRESENT);
574       return -1;
575     } 
576     
577     /* Check If media is write-protected */
578     if(((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) !=0 )
579     {
580       SCSI_SenseCode(pdev,
581                      lun,
582                      NOT_READY, 
583                      WRITE_PROTECTED);
584       return -1;
585     } 
586     
587     
588     hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
589       ((uint32_t)params[3] << 16) | \
590         ((uint32_t)params[4] <<  8) | \
591           (uint32_t)params[5];
592     hmsc->scsi_blk_len = ((uint32_t)params[7] <<  8) | \
593       (uint32_t)params[8];  
594     
595     /* check if LBA address is in the right range */
596     if(SCSI_CheckAddressRange(pdev,
597                               lun,
598                               hmsc->scsi_blk_addr,
599                               hmsc->scsi_blk_len) < 0)
600     {
601       return -1; /* error */      
602     }
603
604     len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
605     
606     /* cases 3,11,13 : Hn,Ho <> D0 */
607     if (hmsc->cbw.dDataLength != len)
608     {
609       SCSI_SenseCode(pdev,
610                      hmsc->cbw.bLUN, 
611                      ILLEGAL_REQUEST, 
612                      INVALID_CDB);
613       return -1;
614     }
615
616     len = MIN(len, S2S_MSC_MEDIA_PACKET);
617     
618     /* Prepare EP to receive first data packet */
619     hmsc->bot_state = USBD_BOT_DATA_OUT;  
620     USBD_LL_PrepareReceive (pdev,
621                       MSC_EPOUT_ADDR,
622                       hmsc->bot_data, 
623                       len);  
624   }
625   else /* Write Process ongoing */
626   {
627     return SCSI_ProcessWrite(pdev, lun);
628   }
629   return 0;
630 }
631
632
633 /**
634 * @brief  SCSI_Verify10
635 *         Process Verify10 command
636 * @param  lun: Logical unit number
637 * @param  params: Command parameters
638 * @retval status
639 */
640
641 static int8_t SCSI_Verify10(USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params)
642 {
643         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
644         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
645   
646   if ((params[1]& 0x02) == 0x02) 
647   {
648     SCSI_SenseCode (pdev,
649                     lun, 
650                     ILLEGAL_REQUEST, 
651                     INVALID_FIELED_IN_COMMAND);
652     return -1; /* Error, Verify Mode Not supported*/
653   }
654   
655   if(SCSI_CheckAddressRange(pdev,
656                             lun, 
657                             hmsc->scsi_blk_addr, 
658                             hmsc->scsi_blk_len) < 0)
659   {
660     return -1; /* error */      
661   }
662   hmsc->bot_data_length = 0;
663   return 0;
664 }
665
666 /**
667 * @brief  SCSI_CheckAddressRange
668 *         Check address range
669 * @param  lun: Logical unit number
670 * @param  blk_offset: first block address
671 * @param  blk_nbr: number of block to be processed
672 * @retval status
673 */
674 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef  *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
675 {
676         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
677         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
678
679         // michael@codesrc.com: Re-check block limits in cause we have different values
680         // for different LUN's.
681     uint32_t blkNbr;
682         uint16_t blkSize;
683         if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blkNbr, &blkSize) != 0)
684         {
685     SCSI_SenseCode(pdev,
686                    lun,
687                    NOT_READY, 
688                    MEDIUM_NOT_PRESENT);
689     return -1;
690   } 
691         // global variables. wooo
692         hmsc->scsi_blk_size = blkSize;
693         hmsc->scsi_blk_nbr = blkNbr;
694
695   if ((blk_offset + blk_nbr) > blkNbr )
696   {
697     SCSI_SenseCode(pdev,
698                    lun, 
699                    ILLEGAL_REQUEST, 
700                    ADDRESS_OUT_OF_RANGE);
701     return -1;
702   }
703   return 0;
704 }
705
706 /**
707 * @brief  SCSI_ProcessRead
708 *         Handle Read Process
709 * @param  lun: Logical unit number
710 * @retval status
711 */
712 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef  *pdev, uint8_t lun)
713 {
714   USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
715   USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
716
717   uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
718
719   len = MIN(len, S2S_MSC_MEDIA_PACKET);
720
721   // TODO there is a dcache issue here.
722   // work out how, and when, to flush cashes between sdio dma and usb dma
723   memset (hmsc->bot_data, 0xAA, len);
724   if( ((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun ,
725                               hmsc->bot_data, 
726                               hmsc->scsi_blk_addr, 
727                               len / hmsc->scsi_blk_size) < 0)
728   {
729     
730     SCSI_SenseCode(pdev,
731                    lun, 
732                    HARDWARE_ERROR, 
733                    UNRECOVERED_READ_ERROR);
734     return -1; 
735   }
736   
737   
738   USBD_LL_Transmit (pdev, 
739              MSC_EPIN_ADDR,
740              hmsc->bot_data,
741              len);
742   
743   hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
744   hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
745   
746   /* case 6 : Hi = Di */
747   hmsc->csw.dDataResidue -= len;
748   
749   if (hmsc->scsi_blk_len == 0)
750   {
751     hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
752   }
753   return 0;
754 }
755
756 /**
757 * @brief  SCSI_ProcessWrite
758 *         Handle Write Process
759 * @param  lun: Logical unit number
760 * @retval status
761 */
762
763 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef  *pdev, uint8_t lun)
764 {
765   USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
766   USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
767
768   uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
769
770   len = MIN(len, S2S_MSC_MEDIA_PACKET);
771   
772   if(((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun ,
773                               hmsc->bot_data, 
774                               hmsc->scsi_blk_addr, 
775                               len / hmsc->scsi_blk_size) < 0)
776   {
777     SCSI_SenseCode(pdev,
778                    lun, 
779                    HARDWARE_ERROR, 
780                    WRITE_FAULT);     
781     return -1; 
782   }
783   
784   
785   hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
786   hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
787   
788   /* case 12 : Ho = Do */
789   hmsc->csw.dDataResidue -= len;
790   
791   if (hmsc->scsi_blk_len == 0)
792   {
793     MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
794   }
795   else
796   {
797     len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), S2S_MSC_MEDIA_PACKET);
798     /* Prepare EP to Receive next packet */
799     USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
800   }
801   
802   return 0;
803 }
804 /**
805   * @}
806   */ 
807
808
809 /**
810   * @}
811   */ 
812
813
814 /**
815   * @}
816   */ 
817
818 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/