Merge branch 'tmaster' into future
[fw/stlink] / example / stm32f4 / STM32_USB_Device_Library / Class / msc / src / usbd_msc_scsi.c
1 /**
2   ******************************************************************************
3   * @file    usbd_msc_scsi.c
4   * @author  MCD Application Team
5   * @version V1.0.0
6   * @date    22-July-2011
7   * @brief   This file provides all the USBD SCSI layer functions.
8   ******************************************************************************
9   * @attention
10   *
11   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
12   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
13   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
14   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
15   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
16   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
17   *
18   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
19   ******************************************************************************
20   */ 
21
22 /* Includes ------------------------------------------------------------------*/
23 #include "usbd_msc_bot.h"
24 #include "usbd_msc_scsi.h"
25 #include "usbd_msc_mem.h"
26 #include "usbd_msc_data.h"
27
28
29
30 /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
31   * @{
32   */
33
34
35 /** @defgroup MSC_SCSI 
36   * @brief Mass storage SCSI layer module
37   * @{
38   */ 
39
40 /** @defgroup MSC_SCSI_Private_TypesDefinitions
41   * @{
42   */ 
43 /**
44   * @}
45   */ 
46
47
48 /** @defgroup MSC_SCSI_Private_Defines
49   * @{
50   */ 
51
52 /**
53   * @}
54   */ 
55
56
57 /** @defgroup MSC_SCSI_Private_Macros
58   * @{
59   */ 
60 /**
61   * @}
62   */ 
63
64
65 /** @defgroup MSC_SCSI_Private_Variables
66   * @{
67   */ 
68
69 SCSI_Sense_TypeDef     SCSI_Sense [SENSE_LIST_DEEPTH];
70 uint8_t   SCSI_Sense_Head;
71 uint8_t   SCSI_Sense_Tail;
72
73 uint32_t  SCSI_blk_size;
74 uint32_t  SCSI_blk_nbr;
75
76 uint32_t  SCSI_blk_addr;
77 uint32_t  SCSI_blk_len;
78
79 USB_OTG_CORE_HANDLE  *cdev;
80 /**
81   * @}
82   */ 
83
84
85 /** @defgroup MSC_SCSI_Private_FunctionPrototypes
86   * @{
87   */ 
88 static int8_t SCSI_TestUnitReady(uint8_t lun, uint8_t *params);
89 static int8_t SCSI_Inquiry(uint8_t lun, uint8_t *params);
90 static int8_t SCSI_ReadFormatCapacity(uint8_t lun, uint8_t *params);
91 static int8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t *params);
92 static int8_t SCSI_RequestSense (uint8_t lun, uint8_t *params);
93 static int8_t SCSI_StartStopUnit(uint8_t lun, uint8_t *params);
94 static int8_t SCSI_ModeSense6 (uint8_t lun, uint8_t *params);
95 static int8_t SCSI_ModeSense10 (uint8_t lun, uint8_t *params);
96 static int8_t SCSI_Write10(uint8_t lun , uint8_t *params);
97 static int8_t SCSI_Read10(uint8_t lun , uint8_t *params);
98 static int8_t SCSI_Verify10(uint8_t lun, uint8_t *params);
99 static int8_t SCSI_CheckAddressRange (uint8_t lun , 
100                                       uint32_t blk_offset , 
101                                       uint16_t blk_nbr);
102 static int8_t SCSI_ProcessRead (uint8_t lun);
103
104 static int8_t SCSI_ProcessWrite (uint8_t lun);
105 /**
106   * @}
107   */ 
108
109
110 /** @defgroup MSC_SCSI_Private_Functions
111   * @{
112   */ 
113
114
115 /**
116 * @brief  SCSI_ProcessCmd
117 *         Process SCSI commands
118 * @param  pdev: device instance
119 * @param  lun: Logical unit number
120 * @param  params: Command parameters
121 * @retval status
122 */
123 int8_t SCSI_ProcessCmd(USB_OTG_CORE_HANDLE  *pdev,
124                            uint8_t lun, 
125                            uint8_t *params)
126 {
127   cdev = pdev;
128   
129   switch (params[0])
130   {
131   case SCSI_TEST_UNIT_READY:
132     return SCSI_TestUnitReady(lun, params);
133     
134   case SCSI_REQUEST_SENSE:
135     return SCSI_RequestSense (lun, params);
136   case SCSI_INQUIRY:
137     return SCSI_Inquiry(lun, params);
138     
139   case SCSI_START_STOP_UNIT:
140     return SCSI_StartStopUnit(lun, params);
141     
142   case SCSI_ALLOW_MEDIUM_REMOVAL:
143     return SCSI_StartStopUnit(lun, params);
144     
145   case SCSI_MODE_SENSE6:
146     return SCSI_ModeSense6 (lun, params);
147     
148   case SCSI_MODE_SENSE10:
149     return SCSI_ModeSense10 (lun, params);
150     
151   case SCSI_READ_FORMAT_CAPACITIES:
152     return SCSI_ReadFormatCapacity(lun, params);
153     
154   case SCSI_READ_CAPACITY10:
155     return SCSI_ReadCapacity10(lun, params);
156     
157   case SCSI_READ10:
158     return SCSI_Read10(lun, params); 
159     
160   case SCSI_WRITE10:
161     return SCSI_Write10(lun, params);
162     
163   case SCSI_VERIFY10:
164     return SCSI_Verify10(lun, params);
165     
166   default:
167     SCSI_SenseCode(lun,
168                    ILLEGAL_REQUEST, 
169                    INVALID_CDB);    
170     return -1;
171   }
172 }
173
174
175 /**
176 * @brief  SCSI_TestUnitReady
177 *         Process SCSI Test Unit Ready Command
178 * @param  lun: Logical unit number
179 * @param  params: Command parameters
180 * @retval status
181 */
182 static int8_t SCSI_TestUnitReady(uint8_t lun, uint8_t *params)
183 {
184   
185   /* case 9 : Hi > D0 */
186   if (MSC_BOT_cbw.dDataLength != 0)
187   {
188     SCSI_SenseCode(MSC_BOT_cbw.bLUN, 
189                    ILLEGAL_REQUEST, 
190                    INVALID_CDB);
191     return -1;
192   }  
193   
194   if(USBD_STORAGE_fops->IsReady(lun) !=0 )
195   {
196     SCSI_SenseCode(lun,
197                    NOT_READY, 
198                    MEDIUM_NOT_PRESENT);
199     return -1;
200   } 
201   MSC_BOT_DataLen = 0;
202   return 0;
203 }
204
205 /**
206 * @brief  SCSI_Inquiry
207 *         Process Inquiry command
208 * @param  lun: Logical unit number
209 * @param  params: Command parameters
210 * @retval status
211 */
212 static int8_t  SCSI_Inquiry(uint8_t lun, uint8_t *params)
213 {
214   uint8_t* pPage;
215   uint16_t len;
216   
217   if (params[1] & 0x01)/*Evpd is set*/
218   {
219     pPage = (uint8_t *)MSC_Page00_Inquiry_Data;
220     len = LENGTH_INQUIRY_PAGE00;
221   }
222   else
223   {
224     
225     pPage = (uint8_t *)&USBD_STORAGE_fops->pInquiry[lun * USBD_STD_INQUIRY_LENGTH];
226     len = pPage[4] + 5;
227     
228     if (params[4] <= len)
229     {
230       len = params[4];
231     }
232   }
233   MSC_BOT_DataLen = len;
234   
235   while (len) 
236   {
237     len--;
238     MSC_BOT_Data[len] = pPage[len];
239   }
240   return 0;
241 }
242
243 /**
244 * @brief  SCSI_ReadCapacity10
245 *         Process Read Capacity 10 command
246 * @param  lun: Logical unit number
247 * @param  params: Command parameters
248 * @retval status
249 */
250 static int8_t SCSI_ReadCapacity10(uint8_t lun, uint8_t *params)
251 {
252   
253   if(USBD_STORAGE_fops->GetCapacity(lun, &SCSI_blk_nbr, &SCSI_blk_size) != 0)
254   {
255     SCSI_SenseCode(lun,
256                    NOT_READY, 
257                    MEDIUM_NOT_PRESENT);
258     return -1;
259   } 
260   else
261   {
262     
263     MSC_BOT_Data[0] = (uint8_t)(SCSI_blk_nbr - 1 >> 24);
264     MSC_BOT_Data[1] = (uint8_t)(SCSI_blk_nbr - 1 >> 16);
265     MSC_BOT_Data[2] = (uint8_t)(SCSI_blk_nbr - 1 >>  8);
266     MSC_BOT_Data[3] = (uint8_t)(SCSI_blk_nbr - 1);
267     
268     MSC_BOT_Data[4] = (uint8_t)(SCSI_blk_size >>  24);
269     MSC_BOT_Data[5] = (uint8_t)(SCSI_blk_size >>  16);
270     MSC_BOT_Data[6] = (uint8_t)(SCSI_blk_size >>  8);
271     MSC_BOT_Data[7] = (uint8_t)(SCSI_blk_size);
272     
273     MSC_BOT_DataLen = 8;
274     return 0;
275   }
276 }
277 /**
278 * @brief  SCSI_ReadFormatCapacity
279 *         Process Read Format Capacity command
280 * @param  lun: Logical unit number
281 * @param  params: Command parameters
282 * @retval status
283 */
284 static int8_t SCSI_ReadFormatCapacity(uint8_t lun, uint8_t *params)
285 {
286   
287   uint32_t blk_size;
288   uint32_t blk_nbr;
289   uint16_t i;
290   
291   for(i=0 ; i < 12 ; i++) 
292   {
293     MSC_BOT_Data[i] = 0;
294   }
295   
296   if(USBD_STORAGE_fops->GetCapacity(lun, &blk_nbr, &blk_size) != 0)
297   {
298     SCSI_SenseCode(lun,
299                    NOT_READY, 
300                    MEDIUM_NOT_PRESENT);
301     return -1;
302   } 
303   else
304   {
305     MSC_BOT_Data[3] = 0x08;
306     MSC_BOT_Data[4] = (uint8_t)(blk_nbr - 1 >> 24);
307     MSC_BOT_Data[5] = (uint8_t)(blk_nbr - 1 >> 16);
308     MSC_BOT_Data[6] = (uint8_t)(blk_nbr - 1 >>  8);
309     MSC_BOT_Data[7] = (uint8_t)(blk_nbr - 1);
310     
311     MSC_BOT_Data[8] = 0x02;
312     MSC_BOT_Data[9] = (uint8_t)(blk_size >>  16);
313     MSC_BOT_Data[10] = (uint8_t)(blk_size >>  8);
314     MSC_BOT_Data[11] = (uint8_t)(blk_size);
315     
316     MSC_BOT_DataLen = 12;
317     return 0;
318   }
319 }
320 /**
321 * @brief  SCSI_ModeSense6
322 *         Process Mode Sense6 command
323 * @param  lun: Logical unit number
324 * @param  params: Command parameters
325 * @retval status
326 */
327 static int8_t SCSI_ModeSense6 (uint8_t lun, uint8_t *params)
328 {
329   
330   uint16_t len = 8 ;
331   MSC_BOT_DataLen = len;
332   
333   while (len) 
334   {
335     len--;
336     MSC_BOT_Data[len] = MSC_Mode_Sense6_data[len];
337   }
338   return 0;
339 }
340
341 /**
342 * @brief  SCSI_ModeSense10
343 *         Process Mode Sense10 command
344 * @param  lun: Logical unit number
345 * @param  params: Command parameters
346 * @retval status
347 */
348 static int8_t SCSI_ModeSense10 (uint8_t lun, uint8_t *params)
349 {
350  uint16_t len = 8;
351
352  MSC_BOT_DataLen = len;
353
354  while (len) 
355   {
356     len--;
357     MSC_BOT_Data[len] = MSC_Mode_Sense10_data[len];
358   }
359   return 0;
360 }
361
362 /**
363 * @brief  SCSI_RequestSense
364 *         Process Request Sense command
365 * @param  lun: Logical unit number
366 * @param  params: Command parameters
367 * @retval status
368 */
369
370 static int8_t SCSI_RequestSense (uint8_t lun, uint8_t *params)
371 {
372   uint8_t i;
373   
374   for(i=0 ; i < REQUEST_SENSE_DATA_LEN ; i++) 
375   {
376     MSC_BOT_Data[i] = 0;
377   }
378   
379   MSC_BOT_Data[0]       = 0x70;         
380   MSC_BOT_Data[7]       = REQUEST_SENSE_DATA_LEN - 6;   
381   
382   if((SCSI_Sense_Head != SCSI_Sense_Tail)) {
383     
384     MSC_BOT_Data[2]     = SCSI_Sense[SCSI_Sense_Head].Skey;             
385     MSC_BOT_Data[12]    = SCSI_Sense[SCSI_Sense_Head].w.b.ASCQ; 
386     MSC_BOT_Data[13]    = SCSI_Sense[SCSI_Sense_Head].w.b.ASC;  
387     SCSI_Sense_Head++;
388     
389     if (SCSI_Sense_Head == SENSE_LIST_DEEPTH)
390     {
391       SCSI_Sense_Head = 0;
392     }
393   }
394   MSC_BOT_DataLen = REQUEST_SENSE_DATA_LEN;  
395   
396   if (params[4] <= REQUEST_SENSE_DATA_LEN)
397   {
398     MSC_BOT_DataLen = params[4];
399   }
400   return 0;
401 }
402
403 /**
404 * @brief  SCSI_SenseCode
405 *         Load the last error code in the error list
406 * @param  lun: Logical unit number
407 * @param  sKey: Sense Key
408 * @param  ASC: Additional Sense Key
409 * @retval none
410
411 */
412 void SCSI_SenseCode(uint8_t lun, uint8_t sKey, uint8_t ASC)
413 {
414   SCSI_Sense[SCSI_Sense_Tail].Skey  = sKey;
415   SCSI_Sense[SCSI_Sense_Tail].w.ASC = ASC << 8;
416   SCSI_Sense_Tail++;
417   if (SCSI_Sense_Tail == SENSE_LIST_DEEPTH)
418   {
419     SCSI_Sense_Tail = 0;
420   }
421 }
422 /**
423 * @brief  SCSI_StartStopUnit
424 *         Process Start Stop Unit command
425 * @param  lun: Logical unit number
426 * @param  params: Command parameters
427 * @retval status
428 */
429 static int8_t SCSI_StartStopUnit(uint8_t lun, uint8_t *params)
430 {
431   MSC_BOT_DataLen = 0;
432   return 0;
433 }
434
435 /**
436 * @brief  SCSI_Read10
437 *         Process Read10 command
438 * @param  lun: Logical unit number
439 * @param  params: Command parameters
440 * @retval status
441 */
442 static int8_t SCSI_Read10(uint8_t lun , uint8_t *params)
443 {
444   if(MSC_BOT_State == BOT_IDLE)  /* Idle */
445   {
446     
447     /* case 10 : Ho <> Di */
448     
449     if ((MSC_BOT_cbw.bmFlags & 0x80) != 0x80)
450     {
451       SCSI_SenseCode(MSC_BOT_cbw.bLUN, 
452                      ILLEGAL_REQUEST, 
453                      INVALID_CDB);
454       return -1;
455     }    
456     
457     if(USBD_STORAGE_fops->IsReady(lun) !=0 )
458     {
459       SCSI_SenseCode(lun,
460                      NOT_READY, 
461                      MEDIUM_NOT_PRESENT);
462       return -1;
463     } 
464     
465     SCSI_blk_addr = (params[2] << 24) | \
466       (params[3] << 16) | \
467         (params[4] <<  8) | \
468           params[5];
469     
470     SCSI_blk_len =  (params[7] <<  8) | \
471       params[8];  
472     
473     
474     
475     if( SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0)
476     {
477       return -1; /* error */
478     }
479     
480     MSC_BOT_State = BOT_DATA_IN;
481     SCSI_blk_addr *= SCSI_blk_size;
482     SCSI_blk_len  *= SCSI_blk_size;
483     
484     /* cases 4,5 : Hi <> Dn */
485     if (MSC_BOT_cbw.dDataLength != SCSI_blk_len)
486     {
487       SCSI_SenseCode(MSC_BOT_cbw.bLUN, 
488                      ILLEGAL_REQUEST, 
489                      INVALID_CDB);
490       return -1;
491     }
492   }
493   MSC_BOT_DataLen = MSC_MEDIA_PACKET;  
494   
495   return SCSI_ProcessRead(lun);
496 }
497
498 /**
499 * @brief  SCSI_Write10
500 *         Process Write10 command
501 * @param  lun: Logical unit number
502 * @param  params: Command parameters
503 * @retval status
504 */
505
506 static int8_t SCSI_Write10 (uint8_t lun , uint8_t *params)
507 {
508   if (MSC_BOT_State == BOT_IDLE) /* Idle */
509   {
510     
511     /* case 8 : Hi <> Do */
512     
513     if ((MSC_BOT_cbw.bmFlags & 0x80) == 0x80)
514     {
515       SCSI_SenseCode(MSC_BOT_cbw.bLUN, 
516                      ILLEGAL_REQUEST, 
517                      INVALID_CDB);
518       return -1;
519     }
520     
521     /* Check whether Media is ready */
522     if(USBD_STORAGE_fops->IsReady(lun) !=0 )
523     {
524       SCSI_SenseCode(lun,
525                      NOT_READY, 
526                      MEDIUM_NOT_PRESENT);
527       return -1;
528     } 
529     
530     /* Check If media is write-protected */
531     if(USBD_STORAGE_fops->IsWriteProtected(lun) !=0 )
532     {
533       SCSI_SenseCode(lun,
534                      NOT_READY, 
535                      WRITE_PROTECTED);
536       return -1;
537     } 
538     
539     
540     SCSI_blk_addr = (params[2] << 24) | \
541       (params[3] << 16) | \
542         (params[4] <<  8) | \
543           params[5];
544     SCSI_blk_len = (params[7] <<  8) | \
545       params[8];  
546     
547     /* check if LBA address is in the right range */
548     if(SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0)
549     {
550       return -1; /* error */      
551     }
552     
553     SCSI_blk_addr *= SCSI_blk_size;
554     SCSI_blk_len  *= SCSI_blk_size;
555     
556     /* cases 3,11,13 : Hn,Ho <> D0 */
557     if (MSC_BOT_cbw.dDataLength != SCSI_blk_len)
558     {
559       SCSI_SenseCode(MSC_BOT_cbw.bLUN, 
560                      ILLEGAL_REQUEST, 
561                      INVALID_CDB);
562       return -1;
563     }
564     
565     /* Prepare EP to receive first data packet */
566     MSC_BOT_State = BOT_DATA_OUT;  
567     DCD_EP_PrepareRx (cdev,
568                       MSC_OUT_EP,
569                       MSC_BOT_Data, 
570                       MIN (SCSI_blk_len, MSC_MEDIA_PACKET));  
571   }
572   else /* Write Process ongoing */
573   {
574     return SCSI_ProcessWrite(lun);
575   }
576   return 0;
577 }
578
579
580 /**
581 * @brief  SCSI_Verify10
582 *         Process Verify10 command
583 * @param  lun: Logical unit number
584 * @param  params: Command parameters
585 * @retval status
586 */
587
588 static int8_t SCSI_Verify10(uint8_t lun , uint8_t *params){
589   if ((params[1]& 0x02) == 0x02) 
590   {
591     SCSI_SenseCode (lun, ILLEGAL_REQUEST, INVALID_FIELED_IN_COMMAND);
592     return -1; /* Error, Verify Mode Not supported*/
593   }
594   
595   if(SCSI_CheckAddressRange(lun, SCSI_blk_addr, SCSI_blk_len) < 0)
596   {
597     return -1; /* error */      
598   }
599   MSC_BOT_DataLen = 0;
600   return 0;
601 }
602
603 /**
604 * @brief  SCSI_CheckAddressRange
605 *         Check address range
606 * @param  lun: Logical unit number
607 * @param  blk_offset: first block address
608 * @param  blk_nbr: number of block to be processed
609 * @retval status
610 */
611 static int8_t SCSI_CheckAddressRange (uint8_t lun , uint32_t blk_offset , uint16_t blk_nbr)
612 {
613   
614   if ((blk_offset + blk_nbr) > SCSI_blk_nbr )
615   {
616     SCSI_SenseCode(lun, ILLEGAL_REQUEST, ADDRESS_OUT_OF_RANGE);
617     return -1;
618   }
619   return 0;
620 }
621
622 /**
623 * @brief  SCSI_ProcessRead
624 *         Handle Read Process
625 * @param  lun: Logical unit number
626 * @retval status
627 */
628 static int8_t SCSI_ProcessRead (uint8_t lun)
629 {
630   uint32_t len;
631   
632   len = MIN(SCSI_blk_len , MSC_MEDIA_PACKET); 
633   
634   if( USBD_STORAGE_fops->Read(lun ,
635                               MSC_BOT_Data, 
636                               SCSI_blk_addr / SCSI_blk_size, 
637                               len / SCSI_blk_size) < 0)
638   {
639     
640     SCSI_SenseCode(lun, HARDWARE_ERROR, UNRECOVERED_READ_ERROR);
641     return -1; 
642   }
643   
644   
645   DCD_EP_Tx (cdev, 
646              MSC_IN_EP,
647              MSC_BOT_Data,
648              len);
649   
650   
651   SCSI_blk_addr   += len; 
652   SCSI_blk_len    -= len;  
653   
654   /* case 6 : Hi = Di */
655   MSC_BOT_csw.dDataResidue -= len;
656   
657   if (SCSI_blk_len == 0)
658   {
659     MSC_BOT_State = BOT_LAST_DATA_IN;
660   }
661   return 0;
662 }
663
664 /**
665 * @brief  SCSI_ProcessWrite
666 *         Handle Write Process
667 * @param  lun: Logical unit number
668 * @retval status
669 */
670
671 static int8_t SCSI_ProcessWrite (uint8_t lun)
672 {
673   uint32_t len;
674   
675   len = MIN(SCSI_blk_len , MSC_MEDIA_PACKET); 
676   
677   if(USBD_STORAGE_fops->Write(lun ,
678                               MSC_BOT_Data, 
679                               SCSI_blk_addr / SCSI_blk_size, 
680                               len / SCSI_blk_size) < 0)
681   {
682     SCSI_SenseCode(lun, HARDWARE_ERROR, WRITE_FAULT);     
683     return -1; 
684   }
685   
686   
687   SCSI_blk_addr  += len; 
688   SCSI_blk_len   -= len; 
689   
690   /* case 12 : Ho = Do */
691   MSC_BOT_csw.dDataResidue -= len;
692   
693   if (SCSI_blk_len == 0)
694   {
695     MSC_BOT_SendCSW (cdev, CSW_CMD_PASSED);
696   }
697   else
698   {
699     /* Prapare EP to Receive next packet */
700     DCD_EP_PrepareRx (cdev,
701                       MSC_OUT_EP,
702                       MSC_BOT_Data, 
703                       MIN (SCSI_blk_len, MSC_MEDIA_PACKET)); 
704   }
705   
706   return 0;
707 }
708 /**
709   * @}
710   */ 
711
712
713 /**
714   * @}
715   */ 
716
717
718 /**
719   * @}
720   */ 
721
722 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/