Contiki 2.6

scsi_decoder.c

Go to the documentation of this file.
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
00002 /*! \file scsi_decoder.c *******************************************************
00003  *
00004  * \brief
00005  *      This file is the scsi decoder
00006  *
00007  * \addtogroup usbstick
00008  *
00009  * \author
00010  *      Atmel Corporation: http://www.atmel.com \n
00011  *      Support email: avr@atmel.com
00012  ******************************************************************************/
00013 /* 
00014    Copyright (c) 2004  ATMEL Corporation
00015    All rights reserved.
00016 
00017    Redistribution and use in source and binary forms, with or without
00018    modification, are permitted provided that the following conditions are met:
00019 
00020    * Redistributions of source code must retain the above copyright
00021      notice, this list of conditions and the following disclaimer.
00022    * Redistributions in binary form must reproduce the above copyright
00023      notice, this list of conditions and the following disclaimer in
00024      the documentation and/or other materials provided with the
00025      distribution.
00026    * Neither the name of the copyright holders nor the names of
00027      contributors may be used to endorse or promote products derived
00028      from this software without specific prior written permission.
00029 
00030   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00031   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00032   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00033   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00034   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00035   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00036   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00037   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00038   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00039   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00040   POSSIBILITY OF SUCH DAMAGE.
00041 */
00042 
00043 /**
00044  \addtogroup usbstorage
00045  @{
00046 */
00047 
00048 //_____  I N C L U D E S ___________________________________________________
00049 
00050 #include "config.h"
00051 #include "storage/scsi_decoder.h"
00052 #include "conf_usb.h"
00053 #include "usb_drv.h"                   
00054 #include "storage/ctrl_status.h"
00055 #include "storage/ctrl_access.h"
00056 
00057 
00058 //_____ M A C R O S ________________________________________________________
00059 
00060 
00061 //_____ D E F I N I T I O N S ______________________________________________
00062 
00063 
00064 U8  g_scsi_command[16];
00065 U8  g_scsi_status;
00066 U32 g_scsi_data_remaining;
00067 
00068 FLASH U8    g_sbc_vendor_id[8]   = SBC_VENDOR_ID;
00069 FLASH U8    g_sbc_product_id[16] = SBC_PRODUCT_ID;
00070 FLASH U8    g_sbc_revision_id[4] = SBC_REVISION_ID;
00071 
00072 extern  U8  usb_LUN;
00073 
00074  s_scsi_sense  g_scsi_sense;
00075 
00076 
00077 FLASH struct sbc_st_std_inquiry_data sbc_std_inquiry_data =
00078 {
00079    /* Byte 0 : 0x00 */
00080    0x00,        /* DeviceType: Direct-access device */
00081    0,           /* PeripheralQualifier : Currently connected */
00082 
00083    /* Byte 1 : 0x80 */
00084    0,           /* Reserved1 */
00085    1,           /* RMB : Medium is removable (this bit must be at 1, else the medium isn't see on Windows) */
00086 
00087  //  /* Byte 2 : 0x02 */
00088  //  0x02,        /* Version: Device compliant to ANSI X3.131:1994 */
00089 
00090    /* Byte 2 : 0x00 */
00091    0x00,        /* Version: Device not compliant to any standard */
00092 
00093    /* Byte 3 : 0x02 */
00094    2,           /* Response data format */
00095    0,           /* NormACA */
00096    0,           /* Obsolete0 */
00097    0,           /* AERC */
00098 
00099    /* Byte 4 : 0x1F */
00100    /* Byte 5 : 0x00 */
00101    /* Byte 6 : 0x00 */
00102                 /* Reserved4[3] */
00103    {
00104       0x1F,     /* Additional Length (n-4) */
00105       0,        /* SCCS : SCC supported */
00106       0
00107    },
00108 
00109    /* Byte 7 : 0x00 */
00110    0,          /* SoftReset */
00111    0,          /* CommandQueue */
00112    0,          /* Reserved5 */
00113    0,          /* LinkedCommands */
00114    0,          /* Synchronous */
00115    0,          /* Wide16Bit */
00116    0,          /* Wide32Bit */
00117    0,          /* RelativeAddressing */
00118 };
00119 
00120 
00121 static  void  send_informational_exceptions_page (void);
00122 static  void  send_read_write_error_recovery_page (U8);
00123 static  void sbc_header_mode_sense( Bool b_sense_10 , U8 u8_data_length );
00124 
00125 
00126 //_____ D E C L A R A T I O N S ____________________________________________
00127 /**
00128  * @brief SCSI decoder function
00129  *
00130  * This function read the SCSI command and launches the appropriate function
00131  *
00132  * @warning Code:.. bytes (function FLASH length)
00133  *
00134  * @return  FALSE: result KO,
00135  *          TRUE:  result OK
00136  *
00137  */
00138 Bool scsi_decode_command(void)
00139 {
00140 Bool status;
00141 
00142    if (g_scsi_command[0] == SBC_CMD_WRITE_10)
00143    {
00144       Scsi_start_write_action();
00145       status = sbc_write_10();
00146           Scsi_stop_write_action();
00147       return status;
00148    }
00149    if (g_scsi_command[0] == SBC_CMD_READ_10 )
00150    {
00151       Scsi_start_read_action();
00152       status = sbc_read_10();
00153       Scsi_stop_read_action();
00154       return status;
00155    }
00156 
00157    switch (g_scsi_command[0])                /* check other command received */
00158    {
00159       case SBC_CMD_REQUEST_SENSE:             /* 0x03 - Mandatory */
00160            return sbc_request_sense();
00161            break;
00162 
00163       case SBC_CMD_INQUIRY:                   /* 0x12 - Mandatory */
00164            return sbc_inquiry();
00165            break;
00166 
00167       case SBC_CMD_TEST_UNIT_READY:           /* 0x00 - Mandatory */
00168            return sbc_test_unit_ready();
00169            break;
00170 
00171       case SBC_CMD_READ_CAPACITY:             /* 0x25 - Mandatory */
00172            return sbc_read_capacity();
00173            break;
00174 
00175       case SBC_CMD_MODE_SENSE_6:              /* 0x1A - Optional */
00176            return sbc_mode_sense( FALSE );
00177            break;
00178 
00179       case SBC_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:/* 0x1E */
00180            return sbc_prevent_allow_medium_removal();
00181            break;
00182 
00183       case SBC_CMD_VERIFY_10:                 /* 0x2F - Optional */
00184            sbc_lun_status_is_good();
00185            break;
00186       case SBC_CMD_MODE_SENSE_10:             /* 0x5A - Optional */
00187            return sbc_mode_sense( TRUE );
00188            break;
00189 
00190       case SBC_CMD_FORMAT_UNIT:               /* 0x04 - Mandatory */
00191 
00192       case SBC_CMD_MODE_SELECT_6:             /* 0x15 - Optional */
00193 
00194 
00195 
00196 
00197       case SBC_CMD_START_STOP_UNIT:           /* 0x1B - Optional */
00198       case SBC_CMD_SEND_DIAGNOSTIC:           /* 0x1D -  */
00199       case SBC_CMD_READ_LONG:                 /* 0x23 - Optional */
00200       case SBC_CMD_SYNCHRONIZE_CACHE:         /* 0x35 - Optional */
00201       case SBC_CMD_WRITE_BUFFER:              /* 0x3B - Optional */
00202       case SBC_CMD_RESERVE_10:                /* 0x56 - Mandatory */
00203       case SBC_CMD_RELEASE_10:                /* 0x57 - Mandatory - see chapter 7.16 - SPC 2 */
00204       default:
00205            { /* Command not supported */
00206               Sbc_send_failed();
00207               Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_COMMAND_OPERATION_CODE, 0x00);
00208               return FALSE;
00209               break;
00210            }
00211    }
00212    return TRUE;
00213 }
00214 
00215 
00216 /**
00217  * @brief This function manages the SCSI REQUEST SENSE command (0x03)
00218  *
00219  * The SCSI Sense contains the status of the last command
00220  * This status is composed of 3 Bytes :
00221  * - sense key  (g_scsi_sense.key)
00222  * - additional sense code  (g_scsi_sense.asc)
00223  * - additional sense code qualifier  (g_scsi_sense.ascq)
00224  *
00225  * @warning Code:.. bytes (function code length)
00226  *
00227  * @return  FALSE: result KO,
00228  *          TRUE:  result OK
00229  *
00230  */
00231 Bool sbc_request_sense (void)
00232 {
00233   U8  allocation_length, i;
00234   U8  request_sens_output[18];   /* the maximum size of request is 17 */
00235 
00236   allocation_length = g_scsi_command[4];  /* Allocation length */
00237 
00238   /* Initialize the request sense data */
00239   request_sens_output[0] = SBC_RESPONSE_CODE_SENSE; /* 70h */
00240   request_sens_output[1] = 0x00;                    /* Obsolete */
00241   request_sens_output[2] = g_scsi_sense.key;
00242 
00243   request_sens_output[3] = 0x00;   /* For direct access media, Information field */
00244   request_sens_output[4] = 0x00;   /* give the unsigned logical block */
00245   request_sens_output[5] = 0x00;   /* address associated with the sense key */
00246   request_sens_output[6] = 0x00;
00247 
00248   request_sens_output[7] = SBC_ADDITIONAL_SENSE_LENGTH; /* !! UFI device shall not adjust the Additional sense length to reflect truncation */
00249   request_sens_output[8] = SBC_COMMAND_SPECIFIC_INFORMATION_3;
00250   request_sens_output[9] = SBC_COMMAND_SPECIFIC_INFORMATION_2;
00251   request_sens_output[10] = SBC_COMMAND_SPECIFIC_INFORMATION_1;
00252   request_sens_output[11] = SBC_COMMAND_SPECIFIC_INFORMATION_0;
00253 
00254   request_sens_output[12] = g_scsi_sense.asc;
00255   request_sens_output[13] = g_scsi_sense.ascq;
00256 
00257   request_sens_output[14] = SBC_FIELD_REPLACEABLE_UNIT_CODE;
00258   request_sens_output[15] = SBC_SENSE_KEY_SPECIFIC_2;
00259   request_sens_output[16] = SBC_SENSE_KEY_SPECIFIC_1;
00260   request_sens_output[17] = SBC_SENSE_KEY_SPECIFIC_0;
00261 
00262   /* Send the request data */
00263   for( i=0 ; i<allocation_length ; i++ )
00264   {
00265     Usb_write_byte( request_sens_output[i] );
00266   }
00267   Sbc_valid_write_usb( allocation_length );
00268 
00269   sbc_lun_status_is_good();
00270 
00271   return TRUE;
00272 }
00273 
00274 /**
00275  * @brief This function manages the SCSI INQUIRY command (0x12)
00276  *
00277  * The SCSI Inquiry field contains information regarding parameters
00278  * of the target. For example:
00279  * - vendor identification
00280  * - product identification
00281  * - peripheral qualifier
00282  * - peripheral device type
00283  * - etc
00284  *
00285  * @warning Code:.. bytes (function code length)
00286  *
00287  * @return  FALSE: result KO,
00288  *          TRUE:  result OK
00289  *
00290  */
00291 Bool sbc_inquiry (void)
00292 {
00293    U8 allocation_length, i;
00294 
00295 #ifdef AVRGCC
00296    PGM_VOID_P ptr;
00297 #else
00298    U8 FLASH *ptr;
00299 #endif
00300 
00301    if( (0 == (g_scsi_command[1] & 0x03) )    // CMDT and EPVD bits are 0
00302    &&  (0 ==  g_scsi_command[2]         ) )  // PAGE or OPERATION CODE fields = 0x00?
00303    {
00304       //** send standard inquiry data
00305 
00306       // Check the size of inquiry data
00307       allocation_length = g_scsi_command[4];
00308       if (allocation_length > SBC_MAX_INQUIRY_DATA)
00309       {
00310          allocation_length = SBC_MAX_INQUIRY_DATA;
00311       }
00312 
00313       // send first inquiry data (0 to 8)
00314       ptr = (FLASH U8*) &sbc_std_inquiry_data;
00315 
00316       for ( i=0 ; ((i != 36) && (allocation_length > i)); i++)
00317       {
00318          if( 8 == i )
00319          {  // send vendor id (8 to 16)
00320               ptr = (FLASH U8 *) &g_sbc_vendor_id;
00321          }
00322          if( 16 == i )
00323          {  // send product id (16 to 32)
00324             ptr = (FLASH U8 *) &g_sbc_product_id;
00325          }
00326          if( 32 == i )
00327          {  // send revision id (32 to 36)
00328             ptr = (FLASH U8 *) &g_sbc_revision_id;
00329          }
00330 #ifndef AVRGCC
00331          Usb_write_byte((U8)(*ptr++));     // send tab
00332 #else    // AVRGCC does not support point to PGM space
00333 #warning with avrgcc assumes devices descriptors are stored in the lower 64Kbytes of on-chip flash memory
00334          Usb_write_byte(pgm_read_byte_near((unsigned int)ptr++));
00335 #endif
00336 
00337       }
00338 
00339       //  send data (36 to SBC_MAX_INQUIRY_DATA), and can be tranmitted by Bulk
00340       //  Description of next bytes (this bytes is always egal to 0) :
00341       //  VendorSpecific    : 20 Bytes
00342       //  Next byte         : 1 byte
00343       //       - InfoUnitSupport   : 1 bit
00344       //       - QuickArbitSupport : 1 bit
00345       //       - Clocking          : 2 bits
00346       //       - Reserved6         : 4 bits
00347       //  Reserved7         : 1 byte
00348       //  VersionDescriptor : 8 bytes
00349       //  Reserved8         : 22 bytes
00350       //  ...
00351       while( allocation_length > i )
00352       {
00353          if (64 == i)
00354          {  // for each 64 bytes, send USB packet
00355             Sbc_valid_write_usb(64);
00356             allocation_length -= 64;
00357             i = 0;
00358          }
00359          Usb_write_byte(0);       // write value of last bytes of inquiry data
00360          i++;
00361       }
00362       // send last USB packet
00363       Sbc_valid_write_usb(allocation_length);
00364       sbc_lun_status_is_good();
00365       return TRUE;
00366    }
00367    else
00368    {  // (CMDT=EVPD <> 0) or (PAGE CODE <> 0x00)
00369       Sbc_send_failed();
00370       Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_FIELD_IN_CDB, 0x00);
00371       return FALSE;
00372    }
00373 }
00374 
00375 
00376 Bool sbc_test_unit_ready(void)
00377 {
00378    switch ( mem_test_unit_ready(usb_LUN) )
00379    {
00380    case CTRL_GOOD :
00381       sbc_lun_status_is_good();
00382       break;
00383 
00384    case CTRL_NO_PRESENT :
00385       sbc_lun_status_is_not_present();
00386       break;
00387 
00388    case CTRL_BUSY :
00389       sbc_lun_status_is_busy_or_change();
00390       break;
00391 
00392    case CTRL_FAIL :
00393    default :
00394       sbc_lun_status_is_fail();
00395       break;
00396    }
00397    return TRUE;
00398 }
00399 
00400 
00401 Bool sbc_read_capacity (void)
00402 {
00403    _MEM_TYPE_SLOW_ U32 mem_size_nb_sector;
00404 
00405    switch ( mem_read_capacity( usb_LUN, &mem_size_nb_sector ) )
00406    {
00407    case CTRL_GOOD :
00408       Usb_write_byte(MSB0(mem_size_nb_sector));  // return nb block
00409       Usb_write_byte(MSB1(mem_size_nb_sector));
00410       Usb_write_byte(MSB2(mem_size_nb_sector));
00411       Usb_write_byte(MSB3(mem_size_nb_sector));
00412       Usb_write_byte( 0               );        // return block size (= 512B)
00413       Usb_write_byte( 0               );
00414       Usb_write_byte( (U8)(512 >> 8)  );
00415       Usb_write_byte( (U8)(512 & 0xFF));
00416 
00417       Sbc_valid_write_usb(SBC_READ_CAPACITY_LENGTH);
00418       sbc_lun_status_is_good();
00419       return TRUE;
00420       break;
00421 
00422    case CTRL_NO_PRESENT :
00423       sbc_lun_status_is_not_present();
00424       break;
00425 
00426    case CTRL_BUSY :
00427       sbc_lun_status_is_busy_or_change();
00428       break;
00429 
00430    case CTRL_FAIL :
00431    default :
00432       sbc_lun_status_is_fail();
00433       break;
00434    }
00435    return FALSE;
00436 }
00437 
00438 
00439 Bool sbc_read_10 (void)
00440 {
00441    U32   mass_addr;                    // rd or wr block address
00442    U16   mass_size;                    // rd or write nb of blocks
00443 
00444    MSB0(mass_addr) = g_scsi_command[2];  // read address
00445    MSB1(mass_addr) = g_scsi_command[3];
00446    MSB2(mass_addr) = g_scsi_command[4];
00447    MSB3(mass_addr) = g_scsi_command[5];
00448 
00449    MSB(mass_size) = g_scsi_command[7];  // read size
00450    LSB(mass_size) = g_scsi_command[8];
00451 
00452    if (mass_size != 0)
00453    {
00454       switch ( memory_2_usb( usb_LUN , mass_addr, mass_size ) )
00455       {
00456       case CTRL_GOOD :
00457          sbc_lun_status_is_good();
00458          g_scsi_data_remaining = g_scsi_data_remaining - (512 * (Uint32)mass_size);
00459          return TRUE;
00460          break;
00461 
00462       case CTRL_NO_PRESENT :
00463          sbc_lun_status_is_not_present();
00464          return FALSE;
00465          break;
00466 
00467       case CTRL_BUSY :
00468          sbc_lun_status_is_busy_or_change();
00469          return FALSE;
00470          break;
00471 
00472       case CTRL_FAIL :
00473       default :
00474          sbc_lun_status_is_fail();
00475          return FALSE;
00476          break;
00477       }
00478    }
00479    else
00480    {  // No data to transfer
00481       sbc_lun_status_is_good();
00482    }
00483    return TRUE;
00484 }
00485 
00486 
00487 Bool sbc_write_10 (void)
00488 {
00489    U32   mass_addr;                    // rd or wr block address
00490    U16   mass_size;                    // rd or write nb of blocks
00491 
00492    MSB0(mass_addr) = g_scsi_command[2];  // read address
00493    MSB1(mass_addr) = g_scsi_command[3];
00494    MSB2(mass_addr) = g_scsi_command[4];
00495    MSB3(mass_addr) = g_scsi_command[5];
00496 
00497    MSB(mass_size) = g_scsi_command[7];  // read size
00498    LSB(mass_size) = g_scsi_command[8];
00499 
00500    if (mass_size != 0)
00501    {
00502       if( TRUE == mem_wr_protect( usb_LUN ) )
00503       {
00504          sbc_lun_status_is_protected();
00505          return FALSE;
00506 #warning For Win98 data must be read to avoid blocking
00507       }
00508       else
00509       {
00510          switch (usb_2_memory( usb_LUN , mass_addr, mass_size ))
00511          {
00512          case CTRL_GOOD :
00513             sbc_lun_status_is_good();
00514             g_scsi_data_remaining = g_scsi_data_remaining - (512 * (Uint32)mass_size);
00515             return TRUE;
00516             break;
00517 
00518          case CTRL_NO_PRESENT :
00519             sbc_lun_status_is_not_present();
00520             return FALSE;
00521             break;
00522 
00523          case CTRL_BUSY :
00524             sbc_lun_status_is_busy_or_change();
00525             return FALSE;
00526             break;
00527 
00528          case CTRL_FAIL :
00529          default :
00530             sbc_lun_status_is_fail();
00531             return FALSE;
00532             break;
00533          }
00534       }
00535    }
00536    else
00537    {  // No data to transfer
00538       sbc_lun_status_is_good();
00539    }
00540    return TRUE;
00541 }
00542 
00543 
00544 /**
00545  * @brief This function manages the SCSI MODE SENSE command (0x1A for sense 6 and 0x5A for sense 10)
00546  *
00547  * The SCSI mode sense function returns parameters to an application client.
00548  * It is a complementary command to the SCSI MODE SELECT command.
00549  *
00550  * @warning Code:.. bytes (function code length)
00551  *
00552  * @param b_sense_10 ( TRUE = sense 10, TRUE = sense 6)
00553  *
00554  * @return  FALSE: result KO,
00555  *          TRUE:  result OK
00556  *
00557  */
00558 Bool sbc_mode_sense( Bool b_sense_10 )
00559 {
00560    U8 allocation_length;
00561 
00562    if( b_sense_10 )
00563       allocation_length = g_scsi_command[8];
00564    else
00565       allocation_length = g_scsi_command[4];
00566 
00567    // switch for page code
00568    switch ( g_scsi_command[2] & SBC_MSK_PAGE_CODE )
00569    {
00570       case SBC_PAGE_CODE_INFORMATIONAL_EXCEPTIONS:       /* Page Code: Informational exceptions control page */
00571          sbc_header_mode_sense( b_sense_10 , SBC_MODE_DATA_LENGTH_INFORMATIONAL_EXCEPTIONS );
00572          send_informational_exceptions_page();
00573          Sbc_valid_write_usb(SBC_MODE_DATA_LENGTH_INFORMATIONAL_EXCEPTIONS + 1);
00574          break;
00575 
00576       case SBC_PAGE_CODE_READ_WRITE_ERROR_RECOVERY:
00577          sbc_header_mode_sense( b_sense_10 , SBC_MODE_DATA_LENGTH_READ_WRITE_ERROR_RECOVERY );
00578          send_read_write_error_recovery_page(allocation_length);
00579          Sbc_valid_write_usb(SBC_MODE_DATA_LENGTH_READ_WRITE_ERROR_RECOVERY + 1);
00580          break;
00581 
00582       case SBC_PAGE_CODE_ALL:
00583          sbc_header_mode_sense( b_sense_10 , SBC_MODE_DATA_LENGTH_CODE_ALL );
00584          if( b_sense_10 )
00585          {
00586             if (allocation_length == 8)
00587             {
00588                Sbc_valid_write_usb(8);
00589                break;
00590             }
00591          }
00592          else
00593          {
00594             if (allocation_length == 4)
00595             {
00596                Sbc_valid_write_usb(4);
00597                break;
00598             }
00599          }
00600          // send page by ascending order code
00601          send_read_write_error_recovery_page(allocation_length);  // 12 bytes
00602          if (allocation_length > 12)
00603          {
00604             send_informational_exceptions_page();                 // 12 bytes
00605             Sbc_valid_write_usb(SBC_MODE_DATA_LENGTH_CODE_ALL + 1);
00606          }
00607          else
00608          {
00609             Sbc_valid_write_usb(allocation_length);
00610          }
00611          break;
00612 
00613       default:
00614            Sbc_send_failed();
00615            Sbc_build_sense(SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_FIELD_IN_CDB, 0x00);
00616            return FALSE;
00617            break;
00618    }
00619    sbc_lun_status_is_good();
00620    return TRUE;
00621 }
00622 
00623 
00624 /**
00625  * @brief This function send the header of the SCSI MODE SENSE command
00626  *
00627  * @param b_sense_10 TRUE = sense 10, FALSE = sense 6
00628  * @param u8_data_length data length in byte
00629  *
00630  */
00631 void sbc_header_mode_sense( Bool b_sense_10 , U8 u8_data_length )
00632 {
00633    // Send Data length
00634    if( b_sense_10 )
00635    {
00636       Usb_write_byte(0);
00637    }
00638    Usb_write_byte( u8_data_length );
00639 
00640    // Send device type
00641    Usb_write_byte(SBC_MEDIUM_TYPE);
00642 
00643    // Write protect status
00644    if (mem_wr_protect( usb_LUN ))
00645    {
00646       Usb_write_byte(SBC_DEV_SPEC_PARAM_WR_PROTECT);  // Device is write protected
00647    }
00648    else
00649    {
00650       Usb_write_byte(SBC_DEV_SPEC_PARAM_WR_ENABLE);   // Device is write enabled
00651    }
00652 
00653    if( b_sense_10 )
00654    {  // Reserved
00655       Usb_write_byte(0);
00656       Usb_write_byte(0);
00657    }
00658 
00659    // Send Block descriptor length
00660    if( b_sense_10 )
00661    {
00662       Usb_write_byte(0);
00663    }
00664    Usb_write_byte(SBC_BLOCK_DESCRIPTOR_LENGTH);
00665 }
00666 
00667 
00668 /**
00669  * @brief This function writes informational exceptions page parameters
00670  *
00671  * @warning Code:.. bytes (function code length)
00672  *
00673  * @return  FALSE: result KO,
00674  *          TRUE:  result OK
00675  *
00676  */
00677 void send_informational_exceptions_page (void)
00678 {
00679    Usb_write_byte(SBC_PAGE_CODE_INFORMATIONAL_EXCEPTIONS);     /* Page Code: Informational exceptions control page */
00680                                                                /* See chapter 8.3.8 on SPC-2 specification */
00681    Usb_write_byte(SBC_PAGE_LENGTH_INFORMATIONAL_EXCEPTIONS);   /* Page Length */
00682    Usb_write_byte(0x00);                                       /* ..., Test bit = 0, ... */
00683    Usb_write_byte(SBC_MRIE);                                   /* MRIE = 0x05 */
00684    Usb_write_byte(0x00);                                       /* Interval Timer (MSB) */
00685    Usb_write_byte(0x00);
00686    Usb_write_byte(0x00);
00687    Usb_write_byte(0x00);                                       /* Interval Timer (LSB) */
00688    Usb_write_byte(0x00);                                       /* Report Count (MSB) */
00689    Usb_write_byte(0x00);
00690    Usb_write_byte(0x00);
00691    Usb_write_byte(0x01);                                       /* Report Count (LSB) */
00692 }
00693 
00694 
00695 /**
00696  * @brief This function writes error recovery page
00697  *
00698  * @warning Code:.. bytes (function code length)
00699  *
00700  * @param length The length of 
00701  *
00702  * @return  FALSE: result KO,
00703  *          TRUE:  result OK
00704  *
00705  */
00706 void send_read_write_error_recovery_page (U8 length)
00707 {
00708    Usb_write_byte(SBC_PAGE_CODE_READ_WRITE_ERROR_RECOVERY);
00709 
00710    Usb_write_byte(SBC_PAGE_LENGTH_READ_WRITE_ERROR_RECOVERY);   /* Page Length */
00711    Usb_write_byte(0x80);
00712    Usb_write_byte(SBC_READ_RETRY_COUNT);
00713    Usb_write_byte(SBC_CORRECTION_SPAN);
00714    Usb_write_byte(SBC_HEAD_OFFSET_COUNT);
00715    Usb_write_byte(SBC_DATA_STROBE_OFFSET);
00716    Usb_write_byte(0x00);   /* Reserved */
00717 
00718    if (length > 12)
00719    {
00720       Usb_write_byte(SBC_WRITE_RETRY_COUNT);
00721       Usb_write_byte(0x00);
00722       Usb_write_byte(SBC_RECOVERY_LIMIT_MSB);
00723       Usb_write_byte(SBC_RECOVERY_LIMIT_LSB);
00724    }
00725 }
00726 
00727 /**
00728  * @brief This function manages the SCSI PREVENT ALLOW MEDIUM REMOVAL
00729  *        command (0x1E)
00730  *
00731  * The SCSI prevent allow medium removal command requests that the target
00732  * enable or disable the removal of the medium in the logical unit.
00733  *
00734  * @warning Code:.. bytes (function code length)
00735  *
00736  * @return  FALSE: result KO,
00737  *          TRUE:  result OK
00738  *
00739  */
00740 Bool sbc_prevent_allow_medium_removal(void)
00741 {
00742    sbc_lun_status_is_good();
00743    return TRUE;
00744 }
00745 
00746 
00747 //! This fonction send the UFI status GOOD
00748 //!
00749 void sbc_lun_status_is_good(void)
00750 {
00751    Sbc_send_good();
00752    Sbc_build_sense(SBC_SENSE_KEY_NO_SENSE, SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION, 0x00);
00753 }
00754 
00755 //! This fonction send the UFI status "lun not present"
00756 //!
00757 void sbc_lun_status_is_not_present(void)
00758 {
00759    Sbc_send_failed();
00760    Sbc_build_sense(SBC_SENSE_KEY_NOT_READY, SBC_ASC_MEDIUM_NOT_PRESENT, 0x00);
00761 }
00762 
00763 //! This fonction send the UFI status busy and change
00764 //!
00765 void sbc_lun_status_is_busy_or_change(void)
00766 {
00767    Sbc_send_failed();
00768    Sbc_build_sense(SBC_SENSE_KEY_UNIT_ATTENTION, SBC_ASC_NOT_READY_TO_READY_CHANGE, 0x00 );
00769 }
00770 
00771 //! This fonction send the UFI status FAIL
00772 //!
00773 void sbc_lun_status_is_fail(void)
00774 {
00775    Sbc_send_failed();
00776    Sbc_build_sense(SBC_SENSE_KEY_HARDWARE_ERROR, SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION, 0x00);
00777 }
00778 
00779 //! This fonction send the UFI status FAIL because write protection
00780 //!
00781 void sbc_lun_status_is_protected(void)
00782 {
00783    Sbc_send_failed();
00784    Sbc_build_sense(SBC_SENSE_KEY_DATA_PROTECT, SBC_ASC_WRITE_PROTECTED, 0x00);
00785 }
00786 
00787 /** @} */