Fix USB disconnect issue when no SD card is installed
[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
170     {
171         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
172         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
173         hmsc->bot_state = USBD_BOT_NO_DATA;
174     }
175
176     return -1;
177   }
178 }
179
180
181 /**
182 * @brief  SCSI_TestUnitReady
183 *         Process SCSI Test Unit Ready Command
184 * @param  lun: Logical unit number
185 * @param  params: Command parameters
186 * @retval status
187 */
188 static int8_t SCSI_TestUnitReady(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
189 {
190         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
191         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
192     
193   /* case 9 : Hi > D0 */
194   if (hmsc->cbw.dDataLength != 0)
195   {
196     SCSI_SenseCode(pdev,
197                    hmsc->cbw.bLUN, 
198                    ILLEGAL_REQUEST, 
199                    INVALID_CDB);
200     return -1;
201   }  
202   
203   if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
204   {
205     SCSI_SenseCode(pdev,
206                    lun,
207                    NOT_READY, 
208                    MEDIUM_NOT_PRESENT);
209     
210     hmsc->bot_state = USBD_BOT_NO_DATA;
211     return -1;
212   } 
213   hmsc->bot_data_length = 0;
214   return 0;
215 }
216
217 /**
218 * @brief  SCSI_Inquiry
219 *         Process Inquiry command
220 * @param  lun: Logical unit number
221 * @param  params: Command parameters
222 * @retval status
223 */
224 static int8_t  SCSI_Inquiry(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
225 {
226   uint8_t* pPage;
227   uint16_t len;
228
229         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
230         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
231   
232   if (params[1] & 0x01)/*Evpd is set*/
233   {
234     pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
235     len = LENGTH_INQUIRY_PAGE00;
236     if (params[4] <= len)
237     {
238       len = params[4];
239     }
240         memcpy(hmsc->bot_data, pPage, len);
241   }
242   else
243   {
244         len = ((USBD_StorageTypeDef *)pdev->pUserData)->Inquiry(lun, hmsc->bot_data, params[4]);
245     
246     if (params[4] <= len)
247     {
248       len = params[4];
249     }
250   }
251   hmsc->bot_data_length = len;
252
253   return 0;
254 }
255
256 /**
257 * @brief  SCSI_ReadCapacity10
258 *         Process Read Capacity 10 command
259 * @param  lun: Logical unit number
260 * @param  params: Command parameters
261 * @retval status
262 */
263 static int8_t SCSI_ReadCapacity10(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
264 {
265         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
266         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
267   
268   if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &hmsc->scsi_blk_nbr, &hmsc->scsi_blk_size) != 0)
269   {
270     SCSI_SenseCode(pdev,
271                    lun,
272                    NOT_READY, 
273                    MEDIUM_NOT_PRESENT);
274     hmsc->bot_state = USBD_BOT_NO_DATA;
275     return -1;
276   } 
277   else
278   {
279     
280     hmsc->bot_data[0] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 24);
281     hmsc->bot_data[1] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >> 16);
282     hmsc->bot_data[2] = (uint8_t)((hmsc->scsi_blk_nbr - 1) >>  8);
283     hmsc->bot_data[3] = (uint8_t)(hmsc->scsi_blk_nbr - 1);
284     
285     hmsc->bot_data[4] = (uint8_t)(hmsc->scsi_blk_size >>  24);
286     hmsc->bot_data[5] = (uint8_t)(hmsc->scsi_blk_size >>  16);
287     hmsc->bot_data[6] = (uint8_t)(hmsc->scsi_blk_size >>  8);
288     hmsc->bot_data[7] = (uint8_t)(hmsc->scsi_blk_size);
289     
290     hmsc->bot_data_length = 8;
291     return 0;
292   }
293 }
294 /**
295 * @brief  SCSI_ReadFormatCapacity
296 *         Process Read Format Capacity command
297 * @param  lun: Logical unit number
298 * @param  params: Command parameters
299 * @retval status
300 */
301 static int8_t SCSI_ReadFormatCapacity(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
302 {
303         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
304         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
305   
306   uint16_t blk_size;
307   uint32_t blk_nbr;
308   uint16_t i;
309   
310   for(i=0 ; i < 12 ; i++) 
311   {
312     hmsc->bot_data[i] = 0;
313   }
314   
315   if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
316   {
317     // Capacity List Header
318     // [0] Reserved
319     // [1] Reserved
320     // [2] Reserved
321     
322     hmsc->bot_data[3] = 0x08; // Capacity List Length (8 bytes, 1 descriptor)
323
324     // Number of blocks. MAXIMUM
325     // 0x400000 is 2TB worth of 512 blocks.
326     hmsc->bot_data[4] = 0x00;
327     hmsc->bot_data[5] = 0x3F;
328     hmsc->bot_data[6] = 0xFF;
329     hmsc->bot_data[7] = 0xFF;
330     
331     hmsc->bot_data[8] = 0x03; // Descriptor code - No media.
332     hmsc->bot_data[9] = 0x00;
333     hmsc->bot_data[10] = 0x02; // 0x200 512 bytes
334     hmsc->bot_data[11] = 0x00;
335   } 
336   else
337   {
338     hmsc->bot_data[3] = 0x08;
339     hmsc->bot_data[4] = (uint8_t)((blk_nbr - 1) >> 24);
340     hmsc->bot_data[5] = (uint8_t)((blk_nbr - 1) >> 16);
341     hmsc->bot_data[6] = (uint8_t)((blk_nbr - 1) >>  8);
342     hmsc->bot_data[7] = (uint8_t)(blk_nbr - 1);
343     
344     hmsc->bot_data[8] = 0x02; // Descriptor code - Formatted media
345     hmsc->bot_data[9] = (uint8_t)(blk_size >>  16);
346     hmsc->bot_data[10] = (uint8_t)(blk_size >>  8);
347     hmsc->bot_data[11] = (uint8_t)(blk_size);
348   }
349     
350     hmsc->bot_data_length = 12;
351     return 0;
352 }
353
354 /**
355 * @brief  SCSI_ModeSense6
356 *         Process Mode Sense6 command
357 * @param  lun: Logical unit number
358 * @param  params: Command parameters
359 * @retval status
360 */
361 static int8_t SCSI_ModeSense6 (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
362 {
363         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
364         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
365
366   uint16_t len = 8 ;
367   hmsc->bot_data_length = len;
368   
369   while (len) 
370   {
371     len--;
372     hmsc->bot_data[len] = MSC_Mode_Sense6_data[len];
373   }
374   return 0;
375 }
376
377 /**
378 * @brief  SCSI_ModeSense10
379 *         Process Mode Sense10 command
380 * @param  lun: Logical unit number
381 * @param  params: Command parameters
382 * @retval status
383 */
384 static int8_t SCSI_ModeSense10 (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
385 {
386   uint16_t len = 8;
387         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
388         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
389   
390   hmsc->bot_data_length = len;
391
392   while (len) 
393   {
394     len--;
395     hmsc->bot_data[len] = MSC_Mode_Sense10_data[len];
396   }
397   return 0;
398 }
399
400 /**
401 * @brief  SCSI_RequestSense
402 *         Process Request Sense command
403 * @param  lun: Logical unit number
404 * @param  params: Command parameters
405 * @retval status
406 */
407
408 static int8_t SCSI_RequestSense (USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
409 {
410   uint8_t i;
411         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
412         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
413   
414   for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) 
415   {
416     hmsc->bot_data[i] = 0;
417   }
418   
419   hmsc->bot_data[0]     = 0x70;         
420   hmsc->bot_data[7]     = REQUEST_SENSE_DATA_LEN - 6;   
421   
422   if((hmsc->scsi_sense_head != hmsc->scsi_sense_tail)) {
423     
424     hmsc->bot_data[2]     = hmsc->scsi_sense[hmsc->scsi_sense_head].Skey;               
425     hmsc->bot_data[12]    = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASCQ;   
426     hmsc->bot_data[13]    = hmsc->scsi_sense[hmsc->scsi_sense_head].w.b.ASC;    
427     hmsc->scsi_sense_head++;
428     
429     if (hmsc->scsi_sense_head == SENSE_LIST_DEEPTH)
430     {
431       hmsc->scsi_sense_head = 0;
432     }
433   }
434   hmsc->bot_data_length = REQUEST_SENSE_DATA_LEN;  
435   
436   if (params[4] <= REQUEST_SENSE_DATA_LEN)
437   {
438     hmsc->bot_data_length = params[4];
439   }
440   return 0;
441 }
442
443 /**
444 * @brief  SCSI_SenseCode
445 *         Load the last error code in the error list
446 * @param  lun: Logical unit number
447 * @param  sKey: Sense Key
448 * @param  ASC: Additional Sense Key
449 * @retval none
450
451 */
452 void SCSI_SenseCode(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t sKey, uint8_t ASC)
453 {
454         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
455         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
456   
457   hmsc->scsi_sense[hmsc->scsi_sense_tail].Skey  = sKey;
458   hmsc->scsi_sense[hmsc->scsi_sense_tail].w.ASC = ASC << 8;
459   hmsc->scsi_sense_tail++;
460   if (hmsc->scsi_sense_tail == SENSE_LIST_DEEPTH)
461   {
462     hmsc->scsi_sense_tail = 0;
463   }
464 }
465 /**
466 * @brief  SCSI_StartStopUnit
467 *         Process Start Stop Unit command
468 * @param  lun: Logical unit number
469 * @param  params: Command parameters
470 * @retval status
471 */
472 static int8_t SCSI_StartStopUnit(USBD_HandleTypeDef  *pdev, uint8_t lun, uint8_t *params)
473 {
474         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
475         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
476
477   hmsc->bot_data_length = 0;
478   return 0;
479 }
480
481 /**
482 * @brief  SCSI_Read10
483 *         Process Read10 command
484 * @param  lun: Logical unit number
485 * @param  params: Command parameters
486 * @retval status
487 */
488 static int8_t SCSI_Read10(USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params)
489 {
490         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
491         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
492   
493   if(hmsc->bot_state == USBD_BOT_IDLE)  /* Idle */
494   {
495     
496     /* case 10 : Ho <> Di */
497     
498     if ((hmsc->cbw.bmFlags & 0x80) != 0x80)
499     {
500       SCSI_SenseCode(pdev,
501                      hmsc->cbw.bLUN, 
502                      ILLEGAL_REQUEST, 
503                      INVALID_CDB);
504       return -1;
505     }    
506     
507     if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
508     {
509       SCSI_SenseCode(pdev,
510                      lun,
511                      NOT_READY, 
512                      MEDIUM_NOT_PRESENT);
513       return -1;
514     } 
515     
516     hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
517       ((uint32_t)params[3] << 16) | \
518         ((uint32_t)params[4] <<  8) | \
519           (uint32_t)params[5];
520     
521     hmsc->scsi_blk_len =  ((uint32_t)params[7] <<  8) | \
522       (uint32_t)params[8];  
523     
524     
525     
526     if( SCSI_CheckAddressRange(pdev, lun, hmsc->scsi_blk_addr, hmsc->scsi_blk_len) < 0)
527     {
528       return -1; /* error */
529     }
530     
531     hmsc->bot_state = USBD_BOT_DATA_IN;
532     
533     /* cases 4,5 : Hi <> Dn */
534     if (hmsc->cbw.dDataLength != (hmsc->scsi_blk_len * hmsc->scsi_blk_size))
535     {
536       SCSI_SenseCode(pdev,
537                      hmsc->cbw.bLUN, 
538                      ILLEGAL_REQUEST, 
539                      INVALID_CDB);
540       return -1;
541     }
542   }
543   hmsc->bot_data_length = S2S_MSC_MEDIA_PACKET;  
544   
545   return SCSI_ProcessRead(pdev, lun);
546 }
547
548 /**
549 * @brief  SCSI_Write10
550 *         Process Write10 command
551 * @param  lun: Logical unit number
552 * @param  params: Command parameters
553 * @retval status
554 */
555
556 static int8_t SCSI_Write10 (USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params)
557 {
558   USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
559   USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
560   uint32_t len;
561   
562   if (hmsc->bot_state == USBD_BOT_IDLE) /* Idle */
563   {
564     /* case 8 : Hi <> Do */
565     
566     if ((hmsc->cbw.bmFlags & 0x80) == 0x80)
567     {
568       SCSI_SenseCode(pdev,
569                      hmsc->cbw.bLUN, 
570                      ILLEGAL_REQUEST, 
571                      INVALID_CDB);
572       return -1;
573     }
574     
575     /* Check whether Media is ready */
576     if(((USBD_StorageTypeDef *)pdev->pUserData)->IsReady(lun) !=0 )
577     {
578       SCSI_SenseCode(pdev,
579                      lun,
580                      NOT_READY, 
581                      MEDIUM_NOT_PRESENT);
582       return -1;
583     } 
584     
585     /* Check If media is write-protected */
586     if(((USBD_StorageTypeDef *)pdev->pUserData)->IsWriteProtected(lun) !=0 )
587     {
588       SCSI_SenseCode(pdev,
589                      lun,
590                      NOT_READY, 
591                      WRITE_PROTECTED);
592       return -1;
593     } 
594     
595     
596     hmsc->scsi_blk_addr = ((uint32_t)params[2] << 24) | \
597       ((uint32_t)params[3] << 16) | \
598         ((uint32_t)params[4] <<  8) | \
599           (uint32_t)params[5];
600     hmsc->scsi_blk_len = ((uint32_t)params[7] <<  8) | \
601       (uint32_t)params[8];  
602     
603     /* check if LBA address is in the right range */
604     if(SCSI_CheckAddressRange(pdev,
605                               lun,
606                               hmsc->scsi_blk_addr,
607                               hmsc->scsi_blk_len) < 0)
608     {
609       return -1; /* error */      
610     }
611
612     len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
613     
614     /* cases 3,11,13 : Hn,Ho <> D0 */
615     if (hmsc->cbw.dDataLength != len)
616     {
617       SCSI_SenseCode(pdev,
618                      hmsc->cbw.bLUN, 
619                      ILLEGAL_REQUEST, 
620                      INVALID_CDB);
621       return -1;
622     }
623
624     len = MIN(len, S2S_MSC_MEDIA_PACKET);
625     
626     /* Prepare EP to receive first data packet */
627     hmsc->bot_state = USBD_BOT_DATA_OUT;  
628     USBD_LL_PrepareReceive (pdev,
629                       MSC_EPOUT_ADDR,
630                       hmsc->bot_data, 
631                       len);  
632   }
633   else /* Write Process ongoing */
634   {
635     return SCSI_ProcessWrite(pdev, lun);
636   }
637   return 0;
638 }
639
640
641 /**
642 * @brief  SCSI_Verify10
643 *         Process Verify10 command
644 * @param  lun: Logical unit number
645 * @param  params: Command parameters
646 * @retval status
647 */
648
649 static int8_t SCSI_Verify10(USBD_HandleTypeDef  *pdev, uint8_t lun , uint8_t *params)
650 {
651         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
652         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
653   
654   if ((params[1]& 0x02) == 0x02) 
655   {
656     SCSI_SenseCode (pdev,
657                     lun, 
658                     ILLEGAL_REQUEST, 
659                     INVALID_FIELED_IN_COMMAND);
660     return -1; /* Error, Verify Mode Not supported*/
661   }
662   
663   if(SCSI_CheckAddressRange(pdev,
664                             lun, 
665                             hmsc->scsi_blk_addr, 
666                             hmsc->scsi_blk_len) < 0)
667   {
668     return -1; /* error */      
669   }
670   hmsc->bot_data_length = 0;
671   return 0;
672 }
673
674 /**
675 * @brief  SCSI_CheckAddressRange
676 *         Check address range
677 * @param  lun: Logical unit number
678 * @param  blk_offset: first block address
679 * @param  blk_nbr: number of block to be processed
680 * @retval status
681 */
682 static int8_t SCSI_CheckAddressRange (USBD_HandleTypeDef  *pdev, uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
683 {
684         USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
685         USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
686
687         // michael@codesrc.com: Re-check block limits in cause we have different values
688         // for different LUN's.
689     uint32_t blkNbr;
690         uint16_t blkSize;
691         if(((USBD_StorageTypeDef *)pdev->pUserData)->GetCapacity(lun, &blkNbr, &blkSize) != 0)
692         {
693     SCSI_SenseCode(pdev,
694                    lun,
695                    NOT_READY, 
696                    MEDIUM_NOT_PRESENT);
697     return -1;
698   } 
699         // global variables. wooo
700         hmsc->scsi_blk_size = blkSize;
701         hmsc->scsi_blk_nbr = blkNbr;
702
703   if ((blk_offset + blk_nbr) > blkNbr )
704   {
705     SCSI_SenseCode(pdev,
706                    lun, 
707                    ILLEGAL_REQUEST, 
708                    ADDRESS_OUT_OF_RANGE);
709     return -1;
710   }
711   return 0;
712 }
713
714 /**
715 * @brief  SCSI_ProcessRead
716 *         Handle Read Process
717 * @param  lun: Logical unit number
718 * @retval status
719 */
720 static int8_t SCSI_ProcessRead (USBD_HandleTypeDef  *pdev, uint8_t lun)
721 {
722   USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
723   USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
724
725   uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
726
727   len = MIN(len, S2S_MSC_MEDIA_PACKET);
728
729   if( ((USBD_StorageTypeDef *)pdev->pUserData)->Read(lun ,
730                               hmsc->bot_data, 
731                               hmsc->scsi_blk_addr, 
732                               len / hmsc->scsi_blk_size) < 0)
733   {
734     
735     SCSI_SenseCode(pdev,
736                    lun, 
737                    HARDWARE_ERROR, 
738                    UNRECOVERED_READ_ERROR);
739     return -1; 
740   }
741   
742   
743   USBD_LL_Transmit (pdev, 
744              MSC_EPIN_ADDR,
745              hmsc->bot_data,
746              len);
747   
748   hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
749   hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
750   
751   /* case 6 : Hi = Di */
752   hmsc->csw.dDataResidue -= len;
753   
754   if (hmsc->scsi_blk_len == 0)
755   {
756     hmsc->bot_state = USBD_BOT_LAST_DATA_IN;
757   }
758   return 0;
759 }
760
761 /**
762 * @brief  SCSI_ProcessWrite
763 *         Handle Write Process
764 * @param  lun: Logical unit number
765 * @retval status
766 */
767
768 static int8_t SCSI_ProcessWrite (USBD_HandleTypeDef  *pdev, uint8_t lun)
769 {
770   USBD_CompositeClassData *classData = (USBD_CompositeClassData*) pdev->pClassData;
771   USBD_MSC_BOT_HandleTypeDef *hmsc = &(classData->msc);
772
773   uint32_t len = hmsc->scsi_blk_len * hmsc->scsi_blk_size;
774
775   len = MIN(len, S2S_MSC_MEDIA_PACKET);
776   
777   if(((USBD_StorageTypeDef *)pdev->pUserData)->Write(lun ,
778                               hmsc->bot_data, 
779                               hmsc->scsi_blk_addr, 
780                               len / hmsc->scsi_blk_size) < 0)
781   {
782     SCSI_SenseCode(pdev,
783                    lun, 
784                    HARDWARE_ERROR, 
785                    WRITE_FAULT);     
786     return -1; 
787   }
788   
789   
790   hmsc->scsi_blk_addr += (len / hmsc->scsi_blk_size);
791   hmsc->scsi_blk_len -= (len / hmsc->scsi_blk_size);
792   
793   /* case 12 : Ho = Do */
794   hmsc->csw.dDataResidue -= len;
795   
796   if (hmsc->scsi_blk_len == 0)
797   {
798     MSC_BOT_SendCSW (pdev, USBD_CSW_CMD_PASSED);
799   }
800   else
801   {
802     len = MIN((hmsc->scsi_blk_len * hmsc->scsi_blk_size), S2S_MSC_MEDIA_PACKET);
803     /* Prepare EP to Receive next packet */
804     USBD_LL_PrepareReceive (pdev, MSC_EPOUT_ADDR, hmsc->bot_data, len);
805   }
806   
807   return 0;
808 }
809 /**
810   * @}
811   */ 
812
813
814 /**
815   * @}
816   */ 
817
818
819 /**
820   * @}
821   */ 
822
823 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/