Example #1
0
/**
 * @brief This method performs all of the translation required for a
 *        SCSI VERIFY 16 byte CDB.
 *        This includes:
 *        - logical block address translation
 *        - transfer length (sector count) translation
 *        - translation items common to all VERIFY CDB sizes.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation was successful.
 *         For more information on return values please reference
 *         sati_move_set_sector_count(), sati_verify_translate_command()
 */
SATI_STATUS sati_verify_16_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   SATI_STATUS   status;
   U8          * cdb          = sati_cb_get_cdb_address(scsi_io);
   U32           sector_count = (sati_get_cdb_byte(cdb, 10) << 24) |
                                (sati_get_cdb_byte(cdb, 11) << 16) |
                                (sati_get_cdb_byte(cdb, 12) << 8)  |
                                (sati_get_cdb_byte(cdb, 13));

   if(sati_device_state_stopped(sequence, scsi_io))
   {
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }
   else
   {
      sequence->type = SATI_SEQUENCE_VERIFY_16;

      // Fill in the Logical Block Address field.
      status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
      if (status != SATI_SUCCESS)
         return status;

      // Fill in the Sector Count fields.
      status = sati_move_set_sector_count(sequence,scsi_io,ata_io,sector_count,0);
      if (status != SATI_SUCCESS)
         return status;

      return sati_verify_translate_command(sequence, scsi_io, ata_io);
   }
}
Example #2
0
/**
 * @brief This method will translate the SCSI read 12 command into a
 *        corresponding ATA read command.  Depending upon the capabilities
 *        supported by the target different ATA commands can be selected.
 *        It ensures that all translation required for this command is
 *        performed successfully.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @see sati_read_32_bit_lba_translate_command() for return values.
 */
SATI_STATUS sati_read_12_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8  * cdb          = sati_cb_get_cdb_address(scsi_io);
   U32   sector_count = (sati_get_cdb_byte(cdb, 6) << 24) |
                        (sati_get_cdb_byte(cdb, 7) << 16) |
                        (sati_get_cdb_byte(cdb, 8) << 8)  |
                        (sati_get_cdb_byte(cdb, 9));

   if(sati_device_state_stopped(sequence, scsi_io))
   {
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }
   else
   {
      sequence->type = SATI_SEQUENCE_READ_12;

      return sati_read_32_bit_lba_translate_command(
                sequence, scsi_io, ata_io, sector_count, 11
             );
   }
}
Example #3
0
/**
 * @brief This method builds the mode parameter header for a 10-byte SCSI
 *        mode sense data response.  The parameter header is 4 bytes in
 *        size.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @param[in] identify This parameter specifies the ATA remote device's
 *            received IDENTIFY DEVICE data.
 * @param[in] mode_data_length This parameter specifies the amount of data
 *            to be returned as part of this mode sense request.
 *
 * @return This method returns the number of bytes written into the
 *         mode sense data buffer.
 */
static
U32 sati_mode_sense_10_build_header(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   ATA_IDENTIFY_DEVICE_DATA_T * identify,
   U16                          mode_data_length
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   // Fill in the length of the mode parameter data returned (do not include
   // the size of the mode data length field in the total).  Adjust the
   // mode data length to not include the mode data length fields itself
   // (i.e. subtract 2).
   mode_data_length -= 2;
   sati_set_data_byte(sequence, scsi_io, 0, (U8)(mode_data_length >> 8) & 0xFF);
   sati_set_data_byte(sequence, scsi_io, 1, (U8)(mode_data_length & 0xFF));

   // Medium Type is 0 for SBC devices
   sati_set_data_byte(sequence, scsi_io, 2, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC);

   // Write Protect (WP), Rsvd, DPOFUA, Rsvd
   if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE)
      sati_set_data_byte(sequence,scsi_io,3,SCSI_MODE_SENSE_HEADER_FUA_ENABLE);
   else
      sati_set_data_byte(sequence, scsi_io, 3, 0);

   // Set the reserved bytes to 0.  The LONGLBA field in byte 4 is overridden
   // later in this method if LLBAA is enabled.
   sati_set_data_byte(sequence, scsi_io, 4, 0);
   sati_set_data_byte(sequence, scsi_io, 5, 0);

   // The MSB for the block descriptor length is never used since the
   // largest block descriptor in this translator is 16-bytes in size.
   sati_set_data_byte(sequence, scsi_io, 6, 0);

   // Set the LSB block descriptor length if block descriptors are utilized.
   if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE)
      sati_set_data_byte(sequence, scsi_io, 7, 0);
   else
   {
      // If Long Logical Block Address are allowed, then the block descriptor
      // is larger (16 bytes total).
      if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE)
      {
         sati_set_data_byte(sequence, scsi_io, 4, 1);
         sati_set_data_byte(
            sequence, scsi_io, 7, SCSI_MODE_SENSE_LLBA_BLOCK_DESCRIPTOR_LENGTH
         );
      }
      else
      {
         sati_set_data_byte(
            sequence, scsi_io, 7, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH
         );
      }
   }

   return SCSI_MODE_SENSE_10_HEADER_LENGTH;
}
Example #4
0
/**
 * @brief This method perform the data translation common to all SCSI MODE
 *        SENSE 10 byte commands.  This includes building the mode page
 *        header and block descriptor (if requested).
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @param[in] identify This parameter specifies the remote device's IDENTIFY
 *            DEVICE data to be used during translation.
 * @param[in] transfer_length This parameter specifies the size of the
 *            mode page (including header & block descriptor).
 *
 * @return This method returns the number of bytes written into the user's
 *         mode page data buffer.
 */
static
U32 sati_mode_sense_10_translate_data(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   ATA_IDENTIFY_DEVICE_DATA_T * identify,
   void                       * scsi_io,
   U16                          transfer_length
)
{
   U8  * cdb = sati_cb_get_cdb_address(scsi_io);
   U32   offset;

   offset = sati_mode_sense_10_build_header(
               sequence, scsi_io, identify, transfer_length
            );

   // Determine if the caller disabled block descriptors (DBD).  If not,
   // then generate a block descriptor.
   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
   {
      // If the user requested the Long LBA format descriptor, then build
      // it
      if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_LLBAA_ENABLE)
         offset += sati_mode_sense_10_build_llba_block_descriptor(
                      sequence, scsi_io, identify, offset
                   );
      else
         offset += sati_mode_sense_build_std_block_descriptor(
                      sequence, scsi_io, identify, offset
                   );
   }

   return offset;
}
Example #5
0
/**
 * @brief This method will translate the SCSI mode sense 6 byte command
 *        into corresponding ATA commands.  If the command is well-formed,
 *        then the translation will result in an ATA IDENTIFY DEVICE
 *        command.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
 *         sense data has been created as a result of something specified
 *         in the CDB.
 */
SATI_STATUS sati_mode_sense_10_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   sequence->command_specific_data.scratch = 0;

   // Set the data length based on the allocation length field in the CDB.
   sequence->allocation_length = (sati_get_cdb_byte(cdb, 7) << 8) |
                                 (sati_get_cdb_byte(cdb, 8));

   return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 10);
}
Example #6
0
/**
* @brief This function will check the multiple_count field in the SCSI CDB
*        and if multiple_count is nonzero the function will check the
*        ATA command code. Only Read and Write Multiple commands are allowed
*        when multiple_count is a nonzero value.
*
* @param[in]     cdb The SCSI cdb for the ATA pass-through command
*
* @return BOOL
  @retval TRUE - multiple_count is nonzero with a unsupported command
  @retval FALSE - multiple_count is zero or the command supports a nonzero value
*/
static
BOOL sati_passthrough_multiple_count_error(
   U8 *     cdb
)
{
   U8 ata_command_code;

   if(PASSTHROUGH_CDB_MULTIPLE_COUNT(cdb) > 0)
   {
      if(sati_get_cdb_byte(cdb, 0 ) == SCSI_ATA_PASSTHRU_12)
      {
         ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 9);
      }
      else
      {
         ata_command_code = PASSTHROUGH_CDB_COMMAND(cdb, 14);
      }

      switch(ata_command_code)
      {  //MULTICOUNT bit is supported
         case ATA_READ_MULTIPLE:
         case ATA_READ_MULTIPLE_EXT:
         case ATA_WRITE_MULTIPLE:
         case ATA_WRITE_MULTIPLE_EXT:
         case ATA_WRITE_MULTIPLE_FUA_EXT:
            return FALSE;
         break;

         default:
            return TRUE;
      }
   }
   //MULTICOUNT bit is not set
   return FALSE;
}
Example #7
0
/**
 * @brief This method builds the mode parameter header for a 6-byte SCSI
 *        mode sense data response.  The parameter header is 4 bytes in
 *        size.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @param[in] identify This parameter specifies the ATA remote device's
 *            received IDENTIFY DEVICE data.
 * @param[in] mode_data_length This parameter specifies the amount of data
 *            to be returned as part of this mode sense request.
 *
 * @return This method returns the number of bytes written into the
 *         data buffer.
 */
static
U32 sati_mode_sense_6_build_header(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   ATA_IDENTIFY_DEVICE_DATA_T * identify,
   U8                           mode_data_length
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   // Fill in the length of the mode parameter data returned (do not include
   // the size of the mode data length field in the total).
   sati_set_data_byte(sequence, scsi_io, 0, (U8)mode_data_length-1);

   // Medium Type is 0 for SBC devices
   sati_set_data_byte(sequence, scsi_io, 1, SCSI_MODE_HEADER_MEDIUM_TYPE_SBC);

   // Write Protect (WP), Rsvd, DPOFUA, Rsvd
   if (sequence->device->capabilities & SATI_DEVICE_CAP_DMA_FUA_ENABLE)
      sati_set_data_byte(sequence,scsi_io,2,SCSI_MODE_SENSE_HEADER_FUA_ENABLE);
   else
      sati_set_data_byte(sequence, scsi_io, 2, 0);

   // Set the block descriptor length if block descriptors are utilized.
   if (sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE)
      sati_set_data_byte(sequence, scsi_io, 3, 0);
   else
      sati_set_data_byte(
         sequence, scsi_io, 3, SCSI_MODE_SENSE_STD_BLOCK_DESCRIPTOR_LENGTH
      );

   return SCSI_MODE_SENSE_6_HEADER_LENGTH;
}
Example #8
0
/**
 * @brief This method performs the SCSI SYNCHRONIZE_CACHE 10 and 16 command translation
 *        functionality common to all SYNCHRONIZE_CACHE command sizes.
 *        This includes:
 *        - setting the command register
 *        - setting the device head register
 *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the method was successfully completed.
 * @retval SATI_SUCCESS This is returned in all other cases.
 */
SATI_STATUS sati_synchronize_cache_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
   U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);

   sequence->type           = SATI_SEQUENCE_SYNCHRONIZE_CACHE;
   sequence->protocol       = SAT_PROTOCOL_NON_DATA;
   sequence->data_direction = SATI_DATA_DIRECTION_NONE;

   if (sati_get_cdb_byte(cdb, 1) & SCSI_SYNCHRONIZE_CACHE_IMMED_ENABLED)
   {
      //currently we ignore immed bit.
      ;
   }

   // Ensure the device supports the 48 bit feature set.
   if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
      sati_set_ata_command(register_fis, ATA_FLUSH_CACHE_EXT);
   else
      sati_set_ata_command(register_fis, ATA_FLUSH_CACHE);

   return SATI_SUCCESS;
}
Example #9
0
/**
 * @brief This method will translate the read capacity 10 SCSI command into
 *        an ATA IDENTIFY DEVICE command.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if the
 *         LBA field is not 0, the PMI bit is not 0.
 */
SATI_STATUS sati_read_capacity_10_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   /**
    * SAT dictates:
    * - the LBA field must be 0
    * - the PMI bit must be 0
    */
   if (
         (
            (sati_get_cdb_byte(cdb, 2) != 0)
         || (sati_get_cdb_byte(cdb, 3) != 0)
         || (sati_get_cdb_byte(cdb, 4) != 0)
         || (sati_get_cdb_byte(cdb, 5) != 0)
         )
         || ((sati_get_cdb_byte(cdb, 8) & SCSI_READ_CAPACITY_PMI_BIT_ENABLE)
              == 1)
      )
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   // The CDB is properly formed.
   sequence->allocation_length = SCSI_READ_CAPACITY_10_DATA_LENGTH;
   sequence->type              = SATI_SEQUENCE_READ_CAPACITY_10;

   sati_ata_identify_device_construct(ata_io, sequence);
   return SATI_SUCCESS;
}
Example #10
0
/**
 * @brief This method will translate the REPORT LUN SCSI command.  This
 *        command is immediately completed, since there is no applicable
 *        ATA/ATAPI command.  The data payload is written and SATI_COMPLETE
 *        is always returned.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return This method always indicates the translation is complete.
 * @retval SATI_COMPLETE This value is always returned.
 */
SATI_STATUS sati_report_luns_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   // Set the data length based on the allocation length field in the CDB.
   sequence->allocation_length = (sati_get_cdb_byte(cdb, 6) << 24) |
                                 (sati_get_cdb_byte(cdb, 7) << 16) |
                                 (sati_get_cdb_byte(cdb, 8) << 8)  |
                                 (sati_get_cdb_byte(cdb, 9));

   // The first 4 bytes indicate the length of the LUN list.  Each
   // LUN entry is 8 bytes.  There is only ever LUN 0 for ATA/ATAPI
   // devices.  The value reported is: n-7, where n is the last byte
   // offset (i.e. 15) in the REPORT LUN data.
   sati_set_data_byte(sequence, scsi_io, 0, 0);
   sati_set_data_byte(sequence, scsi_io, 1, 0);
   sati_set_data_byte(sequence, scsi_io, 2, 0);
   sati_set_data_byte(sequence, scsi_io, 3, 8);

   // Bytes 4-7 are reserved.
   sati_set_data_byte(sequence, scsi_io, 4, 0);
   sati_set_data_byte(sequence, scsi_io, 5, 0);
   sati_set_data_byte(sequence, scsi_io, 6, 0);
   sati_set_data_byte(sequence, scsi_io, 7, 0);

   // Add in our single LUN of zero.
   sati_set_data_byte(sequence, scsi_io, 8, 0);
   sati_set_data_byte(sequence, scsi_io, 9, 0);
   sati_set_data_byte(sequence, scsi_io, 10, 0);
   sati_set_data_byte(sequence, scsi_io, 11, 0);
   sati_set_data_byte(sequence, scsi_io, 12, 0);
   sati_set_data_byte(sequence, scsi_io, 13, 0);
   sati_set_data_byte(sequence, scsi_io, 14, 0);
   sati_set_data_byte(sequence, scsi_io, 15, 0);

   return SATI_COMPLETE;
}
Example #11
0
/**
 * @brief This method will translate the SCSI read 16 command into a
 *        corresponding ATA read command.  Depending upon the capabilities
 *        supported by the target different ATA commands can be selected.
 *        It ensures that all translation required for this command is
 *        performed successfully.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @see sati_read_large_translate_command(), sati_move_translate_64_bit_lba()
 *      for additional return values.
 */
SATI_STATUS sati_read_16_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   SATI_STATUS   status;
   U8            device_head  = 0;
   U8          * cdb          = sati_cb_get_cdb_address(scsi_io);
   U32           sector_count = (sati_get_cdb_byte(cdb, 10) << 24) |
                                (sati_get_cdb_byte(cdb, 11) << 16) |
                                (sati_get_cdb_byte(cdb, 12) << 8)  |
                                (sati_get_cdb_byte(cdb, 13));

   if(sati_device_state_stopped(sequence, scsi_io))
   {
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }
   else
   {
      sequence->type = SATI_SEQUENCE_READ_16;

      // Translate the sector count, write command register, and check various
      // other parts of the CDB.
      status = sati_read_large_translate_command(
                  sequence, scsi_io, ata_io, sector_count, &device_head
               );

      // Attempt to translate the 64-bit LBA field from the SCSI request
      // into the 48-bits of LBA in the ATA register FIS.
      if (status == SATI_SUCCESS)
      {
         sati_move_translate_command(sequence, scsi_io, ata_io, device_head);
         status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);
      }

      return status;
   }
}
Example #12
0
/**
 * @brief This method will translate the SCSI mode sense 6 byte command
 *        into corresponding ATA commands.  If the command is well-formed,
 *        then the translation will result in an ATA IDENTIFY DEVICE
 *        command.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
 *         sense data has been created as a result of something specified
 *         in the CDB.
 */
SATI_STATUS sati_mode_sense_6_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   // Set the data length based on the allocation length field in the CDB.
   sequence->allocation_length = sati_get_cdb_byte(cdb, 4);

   return sati_mode_sense_translate_command(sequence, scsi_io, ata_io, 6);
}
Example #13
0
/**
 * @brief This method will call Mode Select 6 Translation command
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SCI_COMPLETE This is returned if the command translation was
 *         successful and no ATA commands need to be set.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
 *         sense data has been created as a result of something specified
 *         in the parameter data fields.
 */
SATI_STATUS sati_mode_select_6_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   SATI_STATUS status=SATI_FAILURE;
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   //PF bit needs to be 1 byte1 bit ???1????
   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SELECT_PF_MASK) == !SCSI_MODE_SELECT_PF_BIT)
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
      return status;
   }

   status=sati_mode_select_translate_command(
             sequence,
             scsi_io,
             ata_io,
             6
          );

   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
      );
   }
   return status;

}
Example #14
0
/**
 * @brief This method performs the SCSI VERIFY command translation
 *        functionality common to all VERIFY command sizes.
 *        This includes:
 *        - setting the command register
 *        - setting the device head register
 *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the method was successfully completed.
 * @retval SATI_SUCCESS This is returned in all other cases.
 */
static
SATI_STATUS sati_verify_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb          = sati_cb_get_cdb_address(scsi_io);
   U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);

   /**
    * The translator doesn't support performing the byte check operation.
    * As a result, error the request if the BYTCHK bit is set.
    */
   if ((sati_get_cdb_byte(cdb, 1) & SCSI_VERIFY_BYTCHK_ENABLED))
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   sequence->protocol       = SAT_PROTOCOL_NON_DATA;
   sequence->data_direction = SATI_DATA_DIRECTION_NONE;

   sati_set_ata_device_head(register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE);

   // Ensure the device supports the 48 bit feature set.
   if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
      sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS_EXT);
   else
      sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS);

   return SATI_SUCCESS;
}
Example #15
0
/**
 * @brief This method perform the data translation common to all SCSI MODE
 *        SENSE 6 byte commands.  This includes building the mode page
 *        header and block descriptor (if requested).
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @param[in] identify This parameter specifies the remote device's IDENTIFY
 *            DEVICE data to be used during translation.
 * @param[in] transfer_length This parameter specifies the size of the
 *            mode page (including header & block descriptor).
 *
 * @return This method returns the number of bytes written into the user's
 *         mode page data buffer.
 */
static
U32 sati_mode_sense_6_translate_data(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   ATA_IDENTIFY_DEVICE_DATA_T * identify,
   void                       * scsi_io,
   U8                           transfer_length
)
{
   U8  * cdb = sati_cb_get_cdb_address(scsi_io);
   U32   offset;

   offset = sati_mode_sense_6_build_header(
               sequence, scsi_io, identify, transfer_length
            );

   // Determine if the caller disabled block descriptors (DBD).  If not,
   // then generate a block descriptor.
   if ((sati_get_cdb_byte(cdb, 1) & SCSI_MODE_SENSE_DBD_ENABLE) == 0)
      offset += sati_mode_sense_build_std_block_descriptor(
                   sequence, scsi_io, identify, offset
                );

   return offset;
}
Example #16
0
/**
* @brief This method will translate the SCSI Read Buffer command
*        into a corresponding ATA Read Buffer command.
*        For more information on the parameters passed to this method,
*        please reference sati_translate_command().
*
* @return Indicates if the command translation succeeded.
* @retval SATI_SUCCESS indicates that the translation was supported and occurred
*         without error.
* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
*         there is a translation failure.
* @retval SATI_COMPLETE indicates that the translation was supported, occurred without
*         error, and no additional translation is necessary.
*/
SATI_STATUS sati_read_buffer_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
   SATI_STATUS status = SATI_FAILURE;
   U32 allocation_length;
   U32 buffer_offset;

   allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) |
                        (sati_get_cdb_byte(cdb, 7) << 8)  |
                        (sati_get_cdb_byte(cdb, 8)));

   buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) |
                    (sati_get_cdb_byte(cdb, 4) << 8)  |
                    (sati_get_cdb_byte(cdb, 5)));

   sequence->allocation_length = allocation_length;

   switch(sati_get_cdb_byte(cdb, 1))
   {
      case SATI_READ_BUFFER_MODE_DATA:
         if((allocation_length == 512) && (buffer_offset == 0) &&
            (sati_get_cdb_byte(cdb, 2) == 0))
         {
            sati_ata_read_buffer_construct(ata_io, sequence);
            sequence->type = SATI_SEQUENCE_READ_BUFFER;
            sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
            status = SATI_SUCCESS;
         }
         else
         {
            sati_scsi_sense_data_construct(
               sequence,
               scsi_io,
               SCSI_STATUS_CHECK_CONDITION,
               SCSI_SENSE_ILLEGAL_REQUEST,
               SCSI_ASC_INVALID_FIELD_IN_CDB,
               SCSI_ASCQ_INVALID_FIELD_IN_CDB
            );
            sequence->state = SATI_SEQUENCE_STATE_FINAL;
            status = SATI_FAILURE_CHECK_RESPONSE_DATA;
         }
      break;

      case SATI_READ_BUFFER_MODE_DESCRIPTOR:

         //allocation legnth must be at least four to return translated data
         if(allocation_length < 4)
         {
            sati_scsi_sense_data_construct(
               sequence,
               scsi_io,
               SCSI_STATUS_CHECK_CONDITION,
               SCSI_SENSE_ILLEGAL_REQUEST,
               SCSI_ASC_INVALID_FIELD_IN_CDB,
               SCSI_ASCQ_INVALID_FIELD_IN_CDB
            );
            sequence->state = SATI_SEQUENCE_STATE_FINAL;
            status = SATI_FAILURE_CHECK_RESPONSE_DATA;
         }
         else
         {
            //figure out if we support other buffer id's
            sati_set_data_byte(sequence, scsi_io, 0, 0x09); //offset boundary
            sati_set_data_byte(sequence, scsi_io, 1, 0x00);
            sati_set_data_byte(sequence, scsi_io, 2, 0x02); //buffer capacity 0x200
            sati_set_data_byte(sequence, scsi_io, 3, 0x00);
            sequence->state = SATI_SEQUENCE_STATE_FINAL;
            status = SATI_COMPLETE;
         }
      break;

      default:
         //Unspecified sat2v7, returning invalid cdb
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_CHECK_CONDITION,
            SCSI_SENSE_ILLEGAL_REQUEST,
            SCSI_ASC_INVALID_FIELD_IN_CDB,
            SCSI_ASCQ_INVALID_FIELD_IN_CDB
         );
         sequence->state = SATI_SEQUENCE_STATE_FINAL;
         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
   }
   return status;
}
Example #17
0
SATI_STATUS sati_atapi_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   SATI_DEVICE_T              * sati_device,
   void                       * scsi_io,
   void                       * atapi_io
)
{
   SATI_STATUS   status;
   U8          * cdb = sati_cb_get_cdb_address(scsi_io);

   SATA_FIS_REG_H2D_T * register_fis =
      (SATA_FIS_REG_H2D_T *)sati_cb_get_h2d_register_fis_address(atapi_io);

   U8 io_direction = SATI_DATA_DIRECTION_IN;

   //No sense response has been set for the translation sequence yet
   sequence->is_sense_response_set = FALSE;
   // Default to no translation response required
   sequence->is_translate_response_required = FALSE;

   sequence->number_data_bytes_set = 0;
   sequence->device  = sati_device;
   sequence->command_specific_data.scratch = 0;

   sati_cb_get_data_direction(scsi_io, &io_direction);

   //set sat protocol.
   if (io_direction == SATI_DATA_DIRECTION_NONE)
      sequence->protocol = SAT_PROTOCOL_PACKET_NON_DATA;
   else if (io_direction == SATI_DATA_DIRECTION_IN)
      sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_IN;
   else if (io_direction == SATI_DATA_DIRECTION_OUT)
      sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_OUT;

   // We don't send Report Luns command out.
   if  (sati_get_cdb_byte(cdb, 0) == SCSI_REPORT_LUNS)
   {
      status = sati_report_luns_translate_command(
                  sequence, scsi_io, atapi_io
               );
   }
   else if (sati_cb_get_lun(scsi_io) != 0)
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED,
         0
      );
      status = SATI_FAILURE_CHECK_RESPONSE_DATA;
   }
   else
   {
      if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
      {  //Request Sense command is required.
         U8 request_sense_cdb[SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH] =
            {0x3, 0x0, 0x0, 0x0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};

         //set the sequence->protocol to DATA_IN anyway;
         sequence->protocol = SAT_PROTOCOL_PACKET_DMA_DATA_IN;

         //set the cdb for Request Sense using command_specific_data field.
         memcpy(sequence->command_specific_data.sati_atapi_data.request_sense_cdb,
                request_sense_cdb,
                SATI_ATAPI_REQUEST_SENSE_CDB_LENGTH
               );
      }

      //build Packet Fis for any other command translation.
      register_fis->command = ATA_PACKET;
      register_fis->features |= ATA_PACKET_FEATURE_DMA;

      register_fis->fis_type = SATA_FIS_TYPE_REGH2D;
      register_fis->command_flag = 1;

      status = SATI_SUCCESS;
   }

   return status;
}
Example #18
0
/**
 * @brief This method will translate the SCSI Passthrough command
 *        into the corresponding ATA command.
 *
 * @return Indicate if the command translation succeeded.
 * @retval SATI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SATI_FAILURE This is returned if the command translation was
 *         unsuccessful
 */
SATI_STATUS sati_passthrough_16_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   SATI_STATUS   status;
   U8          * cdb;
   U8          * register_fis;

   status = SATI_FAILURE;

   sequence->type = SATI_SEQUENCE_ATA_PASSTHROUGH_16;
   sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;

   cdb = sati_cb_get_cdb_address(scsi_io);
   sequence->protocol = PASSTHROUGH_CDB_PROTOCOL(cdb);
   register_fis = sati_cb_get_h2d_register_fis_address(ata_io);

   /*
    * CAM will send passthrough commands with protocol set to multiword
    * DMA even though no multiword DMA mode is selected on the device.
    * This is because some controllers (LSI) will only accept
    * ATA_PASSTHROUGH commands with DMA mode - not UDMA_IN/OUT.
    *
    * Since isci does not support multiword DMA, fix this up here.
    */
   if (sequence->protocol == PASSTHROUGH_DMA)
   {
      if (PASSTHROUGH_CDB_T_DIR(cdb) == 0x1)
      {
         sequence->protocol = PASSTHROUGH_UDMA_DATA_IN;
      }
      else
      {
         sequence->protocol = PASSTHROUGH_UDMA_DATA_OUT;
      }
   }

   if (sati_passthrough_check_direction(sequence, cdb) != SATI_COMPLETE
       || sati_passthrough_multiple_count_error(cdb)
      )
   {
      // Fail due to mismatch
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   if (PASSTHROUGH_CDB_EXTEND(cdb) == 1)
   {
      sati_set_ata_features_exp(register_fis, sati_get_cdb_byte(cdb, 3));
      sati_set_ata_sector_count_exp(register_fis, sati_get_cdb_byte(cdb, 5));
      sati_set_ata_lba_low_exp(register_fis, sati_get_cdb_byte(cdb, 7));
      sati_set_ata_lba_mid_exp(register_fis, sati_get_cdb_byte(cdb, 9));
      sati_set_ata_lba_high_exp(register_fis, sati_get_cdb_byte(cdb, 11));
   }

   if (PASSTHROUGH_CDB_CK_COND(cdb) ||
       PASSTHROUGH_CDB_PROTOCOL(cdb) == PASSTHROUGH_RETURN_RESPONSE)
   {
      sequence->is_translate_response_required = TRUE;
   }

   sati_set_ata_features(register_fis, sati_get_cdb_byte(cdb, 4));
   sati_set_ata_sector_count(register_fis, sati_get_cdb_byte(cdb, 6));
   sati_set_ata_lba_low(register_fis, sati_get_cdb_byte(cdb, 8));
   sati_set_ata_lba_mid(register_fis, sati_get_cdb_byte(cdb, 10));
   sati_set_ata_lba_high(register_fis, sati_get_cdb_byte(cdb, 12));
   sati_set_ata_device_head(register_fis, sati_get_cdb_byte(cdb, 13));
   sati_set_ata_command(register_fis, sati_get_cdb_byte(cdb, 14));

   sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;

   return SATI_SUCCESS;
}
Example #19
0
/**
 * @brief This method will translate the inquiry SCSI command into
 *        an ATA IDENTIFY DEVICE command.  It will handle several different
 *        VPD pages and the standard inquiry page.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
 *         the page isn't supported, or the page code
 *         field is not zero when the EVPD bit is 0.
 */
SATI_STATUS sati_inquiry_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   /**
    * SPC dictates:
    * - that the page code field must be 0, if VPD enable is 0.
    */
   if (  ((sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE) == 0)
      && (sati_get_cdb_byte(cdb, 2) != 0) )
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   // Set the data length based on the allocation length field in the CDB.
   sequence->allocation_length = (sati_get_cdb_byte(cdb, 3) << 8) |
                                 (sati_get_cdb_byte(cdb, 4));

   // Check to see if there was a request for the vital product data or just
   // the standard inquiry.
   if (sati_get_cdb_byte(cdb, 1) & SCSI_INQUIRY_EVPD_ENABLE)
   {
      // Parse the page code to determine which translator to invoke.
      switch (sati_get_cdb_byte(cdb, 2))
      {
         case SCSI_INQUIRY_SUPPORTED_PAGES_PAGE:
            sequence->type  = SATI_SEQUENCE_INQUIRY_SUPPORTED_PAGES;
            sati_inquiry_supported_pages_translate_data(sequence, scsi_io);
            return SATI_COMPLETE;
         break;

         case SCSI_INQUIRY_UNIT_SERIAL_NUM_PAGE:
            sequence->type = SATI_SEQUENCE_INQUIRY_SERIAL_NUMBER;
         break;

         case SCSI_INQUIRY_DEVICE_ID_PAGE:
            sequence->type = SATI_SEQUENCE_INQUIRY_DEVICE_ID;
         break;

         case SCSI_INQUIRY_ATA_INFORMATION_PAGE:

            if(sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
            {
               sati_ata_execute_device_diagnostic_construct(
                  ata_io,
                  sequence
               );
               sequence->type = SATI_SEQUENCE_INQUIRY_EXECUTE_DEVICE_DIAG;
            }
            else
            {
               sequence->type = SATI_SEQUENCE_INQUIRY_ATA_INFORMATION;
            }
         break;

         case SCSI_INQUIRY_BLOCK_DEVICE_PAGE:
            sequence->type = SATI_SEQUENCE_INQUIRY_BLOCK_DEVICE;
         break;

         default:
            sati_scsi_sense_data_construct(
               sequence,
               scsi_io,
               SCSI_STATUS_CHECK_CONDITION,
               SCSI_SENSE_ILLEGAL_REQUEST,
               SCSI_ASC_INVALID_FIELD_IN_CDB,
               SCSI_ASCQ_INVALID_FIELD_IN_CDB
            );
            return SATI_FAILURE_CHECK_RESPONSE_DATA;
         break;
      }
   }
   else
   {
      sequence->type = SATI_SEQUENCE_INQUIRY_STANDARD;
   }

   sati_ata_identify_device_construct(ata_io, sequence);

   return SATI_SUCCESS;
}
Example #20
0
/**
* @brief This method will translate the SCSI Write Buffer command
*        into a corresponding ATA Write Buffer and Download Microcode commands.
*        For more information on the parameters passed to this method,
*        please reference sati_translate_command().
*
* @return Indicates if the command translation succeeded.
* @retval SATI_SUCCESS indicates that the translation was supported and occurred
*         without error.
* @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
*         there is a translation failure.
*/
SATI_STATUS sati_write_buffer_translate_command(
    SATI_TRANSLATOR_SEQUENCE_T * sequence,
    void                       * scsi_io,
    void                       * ata_io
)
{
    U8 * cdb = sati_cb_get_cdb_address(scsi_io);
    SATI_STATUS status = SATI_FAILURE;
    U32 allocation_length;
    U32 allocation_blocks;
    U32 buffer_offset;

    allocation_length = ((sati_get_cdb_byte(cdb, 6) << 16) |
                         (sati_get_cdb_byte(cdb, 7) << 8)  |
                         (sati_get_cdb_byte(cdb, 8)));

    buffer_offset = ((sati_get_cdb_byte(cdb, 3) << 16) |
                     (sati_get_cdb_byte(cdb, 4) << 8)  |
                     (sati_get_cdb_byte(cdb, 5)));

    sequence->allocation_length = allocation_length;
    allocation_blocks = allocation_length / DOWNLOAD_MICROCODE_BLOCK_SIZE;

    switch(sati_get_cdb_byte(cdb, 1))
    {
    case WRITE_BUFFER_WRITE_DATA:
        if((allocation_length == DOWNLOAD_MICROCODE_BLOCK_SIZE) &&
                (buffer_offset == 0) &&
                (sati_get_cdb_byte(cdb, 2) == 0))
        {
            sati_ata_write_buffer_construct(ata_io, sequence);
            sequence->type = SATI_SEQUENCE_WRITE_BUFFER;
            sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
            status = SATI_SUCCESS;
        }
        else
        {
            sati_scsi_sense_data_construct(
                sequence,
                scsi_io,
                SCSI_STATUS_CHECK_CONDITION,
                SCSI_SENSE_ILLEGAL_REQUEST,
                SCSI_ASC_INVALID_FIELD_IN_CDB,
                SCSI_ASCQ_INVALID_FIELD_IN_CDB
            );

            sequence->state = SATI_SEQUENCE_STATE_FINAL;
            status = SATI_FAILURE_CHECK_RESPONSE_DATA;
        }
        break;

    case WRITE_BUFFER_DOWNLOAD_SAVE:

        sati_ata_download_microcode_construct(
            ata_io,
            sequence,
            ATA_MICROCODE_DOWNLOAD_SAVE,
            allocation_length,
            buffer_offset
        );

        sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE;
        sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
        status = SATI_SUCCESS;
        break;

    case WRITE_BUFFER_OFFSET_DOWNLOAD_SAVE:
        if(((allocation_length & 0x000001FF) == 0) && //Bits 08:00 need to be zero per SAT2v7
                ((buffer_offset & 0x000001FF) == 0)     &&
                (allocation_blocks <= sequence->device->max_blocks_per_microcode_command) &&
                ((allocation_blocks >= sequence->device->min_blocks_per_microcode_command) ||
                 (allocation_length == 0)))
        {
            sati_ata_download_microcode_construct(
                ata_io,
                sequence,
                ATA_MICROCODE_OFFSET_DOWNLOAD,
                allocation_length,
                buffer_offset
            );

            sequence->type = SATI_SEQUENCE_WRITE_BUFFER_MICROCODE;
            sequence->state = SATI_SEQUENCE_STATE_AWAIT_RESPONSE;
            status = SATI_SUCCESS;
        }
        else
        {
            sati_scsi_sense_data_construct(
                sequence,
                scsi_io,
                SCSI_STATUS_CHECK_CONDITION,
                SCSI_SENSE_ILLEGAL_REQUEST,
                SCSI_ASC_INVALID_FIELD_IN_CDB,
                SCSI_ASCQ_INVALID_FIELD_IN_CDB
            );

            sequence->state = SATI_SEQUENCE_STATE_FINAL;
            status = SATI_FAILURE_CHECK_RESPONSE_DATA;
        }
        break;

    default: //unsupported Write Buffer Mode
        sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_CHECK_CONDITION,
            SCSI_SENSE_ILLEGAL_REQUEST,
            SCSI_ASC_INVALID_FIELD_IN_CDB,
            SCSI_ASCQ_INVALID_FIELD_IN_CDB
        );

        sequence->state = SATI_SEQUENCE_STATE_FINAL;
        status = SATI_FAILURE_CHECK_RESPONSE_DATA;
        break;
    }
    return status;
}
Example #21
0
/**
 * @brief This method will translate the SCSI Mode Select 6 byte or 10 byte command
 *        into corresponding ATA commands.  Depending upon the capabilities
 *        supported by the target different ATA commands can be selected.
 *        Additionally, in some cases more than a single ATA command may
 *        be required.
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SCI_COMPLETE This is returned if the command translation was
 *         successful and no ATA commands need to be set.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
 *         sense data has been created as a result of something specified
 *         in the parameter data fields.
 */
static
SATI_STATUS sati_mode_select_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T   * sequence,
   void                         * scsi_io,
   void                         * ata_io,
   U32                          cdb_size
)
{
   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
   U32 mode_page_offset;
   U32 block_descriptor_length;
   U32 index;
   U16 data_transfer_length;
   U8 current_mode_parameters[8]={0,0,0,0,0,0,0,0};
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   // cdb_size must be 6 or 10
   if(FALSE == (cdb_size == 6 || cdb_size == 10))
   {
      return status;
   }

   if(sequence->state == SATI_SEQUENCE_STATE_INITIAL)
   {
      sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
      sequence->state = SATI_SEQUENCE_STATE_TRANSLATE_DATA;
   }

   //First, initializes mode_sel_processing_state
   if ( sequence->command_specific_data.process_state.ata_command_sent_for_cmp == 0 )
   {
      if (cdb_size == 6)
      {
         //CDB byte 4 is the parameter length
         data_transfer_length = sati_get_cdb_byte(cdb, 4);
      }
      else
      {
         //CDB byte 7 and 8 for Mode Select 10
         data_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) + sati_get_cdb_byte(cdb, 8);
      }

      sequence->allocation_length = data_transfer_length;

      //Get 8 bytes for headers (4 bytes for Mode Select 6 and 8 bytes for Mode Select 10)
      for( index = 0; index < 8; index++ )
      {
         sati_get_data_byte(sequence, scsi_io, index, &current_mode_parameters[index]);
      }

      //medium type should be 0
      if ( sati_mode_select_get_medium_type(current_mode_parameters, cdb_size) != 0 )
      {
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_CHECK_CONDITION,
            SCSI_SENSE_ILLEGAL_REQUEST,
            SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
            SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
         );
         return status;
      }

      block_descriptor_length = sati_mode_select_get_mode_block_descriptor_length(
                                   current_mode_parameters,
                                   cdb_size
                                );

      mode_page_offset = sati_mode_select_get_mode_page_offset(
                            block_descriptor_length,
                            cdb_size
                         );

      if(mode_page_offset > data_transfer_length)
      {
         sequence->state = SATI_SEQUENCE_STATE_FINAL;
         status = SATI_FAILURE_CHECK_RESPONSE_DATA;
      }
      else
      {
         sati_mode_select_initialize_mode_sel_processing_state(
            sequence,
            scsi_io,
            ata_io,
            data_transfer_length,
            mode_page_offset
         );

      }
    }

   // move to next mode page
   if(sequence->command_specific_data.process_state.current_mode_page_processed)
   {
      sequence->command_specific_data.process_state.ata_command_sent_for_cmp = 0;
      sequence->command_specific_data.process_state.current_mode_page_processed = FALSE;
   }

   status = sati_mode_select_process_mode_page(sequence, scsi_io, ata_io);

   if(sequence->command_specific_data.process_state.current_mode_page_processed != FALSE)
   {
      // Done this page
      sequence->state = SATI_SEQUENCE_STATE_FINAL;
   }
   else
   {
      sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
   }

   if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
   {
      sequence->state = SATI_SEQUENCE_STATE_FINAL;
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_PARM_LIST,
         SCSI_ASCQ_INVALID_FIELD_IN_PARM_LIST
      );
   }

   return status;
}
Example #22
0
/**
 * @brief This method will translate the write long 10 & 16 SCSI commands into
 *        ATA write uncorrectable commands. For more information on the
 *        parameters passed to this method, please reference
 *        sati_translate_command().
 *
 * @return Indicate if the command translation succeeded.
 * @retval SCI_SUCCESS This is returned if the command translation was
 *         successful.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA is returned if there was
 *         a problem with the translation of write long.
 *
 */
SATI_STATUS sati_write_long_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);
   SATI_STATUS status = SATI_FAILURE;
   U16 byte_transfer_length;
   U8 device_head  = 0;

   if((sequence->device->capabilities &
       SATI_DEVICE_CAP_WRITE_UNCORRECTABLE_ENABLE) == 0)
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_COMMAND_OPERATION_CODE,
         SCSI_ASCQ_INVALID_COMMAND_OPERATION_CODE
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   //Write Long 10
   if(sati_get_cdb_byte(cdb, 0) == SCSI_WRITE_LONG_10)
   {
      byte_transfer_length = (sati_get_cdb_byte(cdb, 7) << 8) |
                             (sati_get_cdb_byte(cdb, 8));

      sati_move_translate_32_bit_lba(sequence, scsi_io, ata_io);
   }
   else //Write Long 16
   {
      byte_transfer_length = (sati_get_cdb_byte(cdb, 12) << 8) |
                             (sati_get_cdb_byte(cdb, 13));

      status = sati_move_translate_64_bit_lba(sequence, scsi_io, ata_io);

      if( status == SATI_FAILURE_CHECK_RESPONSE_DATA)
      {
         return status;
      }
   }


   sati_move_translate_command(sequence, scsi_io, ata_io, device_head);

   if( byte_transfer_length != 0 )
   {
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   switch(SATI_WRITE_LONG_GET_COR_WR_PB_BITS(cdb))
   {
      case WR_UNCOR_BIT :

         if( (sequence->device->capabilities &
              SATI_DEVICE_CAP_MULTIPLE_SECTORS_PER_PHYSCIAL_SECTOR) != 0 )
         {
            sati_scsi_sense_data_construct(
               sequence,
               scsi_io,
               SCSI_STATUS_CHECK_CONDITION,
               SCSI_SENSE_ILLEGAL_REQUEST,
               SCSI_ASC_INVALID_FIELD_IN_CDB,
               SCSI_ASCQ_INVALID_FIELD_IN_CDB
            );
            return SATI_FAILURE_CHECK_RESPONSE_DATA;
         }
         else
         {
            sati_ata_write_uncorrectable_construct(
               ata_io,
               sequence,
               ATA_WRITE_UNCORRECTABLE_PSUEDO
            );
            sequence->type = SATI_SEQUENCE_WRITE_LONG;
            status = SATI_SUCCESS;
         }
         break;

      case WR_UNCOR_PBLOCK_BIT :

         sati_ata_write_uncorrectable_construct(
            ata_io,
            sequence,
            ATA_WRITE_UNCORRECTABLE_PSUEDO
         );
         sequence->type = SATI_SEQUENCE_WRITE_LONG;
         status = SATI_SUCCESS;
         break;

      case COR_DIS_WR_UNCORR_BIT :

         sati_ata_write_uncorrectable_construct(
            ata_io,
            sequence,
            ATA_WRITE_UNCORRECTABLE_FLAGGED
         );
         sequence->type = SATI_SEQUENCE_WRITE_LONG;
         status = SATI_SUCCESS;
         break;

      default :

         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_CHECK_CONDITION,
            SCSI_SENSE_ILLEGAL_REQUEST,
            SCSI_ASC_INVALID_FIELD_IN_CDB,
            SCSI_ASCQ_INVALID_FIELD_IN_CDB
         );
         return SATI_FAILURE_CHECK_RESPONSE_DATA;
         break;
   }
   return status;
}
/**
 * @brief This method will translate the SCSI request sense command
 *        into corresponding ATA commands.  Depending on supported and enabled
 *        capabilities like SMART, different ATA commands can be selected.
 *        For more information on the parameters passed to this method,
 *        please reference sati_translate_command().
 *
 * @return Indicates if the command translation succeeded.
 * @retval SATI_SUCCESS indicates that the translation was supported and occurred
 *         without error.
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
 *         the SATII is processing a format unit commmand.
 * @retval SATI_COMPLETE indicates that the translation was supported, occurred without
 *         error, and no additional translation is necessary.
 */
SATI_STATUS sati_request_sense_translate_command(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   U8 * cdb = sati_cb_get_cdb_address(scsi_io);

   //check if SATI is processing format unit command
   switch(sequence->device->state)
   {
      case SATI_DEVICE_STATE_FORMAT_UNIT_IN_PROGRESS:
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_GOOD,
            SCSI_SENSE_NOT_READY,
            SCSI_ASC_LUN_FORMAT_IN_PROGRESS,
            SCSI_ASCQ_LUN_FORMAT_IN_PROGRESS
         );
         return SATI_COMPLETE;
      break;

      case SATI_DEVICE_STATE_UNIT_ATTENTION_CONDITION:
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_GOOD,
            SCSI_SENSE_UNIT_ATTENTION,
            sequence->device->unit_attention_asc,
            sequence->device->unit_attention_ascq
         );
         return SATI_COMPLETE;
      break;
      //sending sense data status Idle, this is set by start_stop_unit
      case SATI_DEVICE_STATE_IDLE:
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_GOOD,
            SCSI_SENSE_NO_SENSE,
            SCSI_ASC_POWER_STATE_CHANGE,
            SCSI_ASCQ_IDLE_CONDITION_ACTIVATE_BY_COMMAND
         );
         return SATI_COMPLETE;
      break;
      //sending sense data status Standby, this is set by start_stop_unit
      case SATI_DEVICE_STATE_STANDBY:
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_GOOD,
            SCSI_SENSE_NO_SENSE,
            SCSI_ASC_POWER_STATE_CHANGE,
            SCSI_ASCQ_STANDBY_CONDITION_ACTIVATE_BY_COMMAND
         );
         return SATI_COMPLETE;
      break;

      case SATI_DEVICE_STATE_STOPPED:
         sati_scsi_sense_data_construct(
            sequence,
            scsi_io,
            SCSI_STATUS_GOOD,
            SCSI_SENSE_NO_SENSE,
            SCSI_ASC_NO_ADDITIONAL_SENSE,
            SCSI_ASCQ_NO_ADDITIONAL_SENSE
         );
         return SATI_COMPLETE;
      break;

      default:
      break;
   }

   sequence->allocation_length = sati_get_cdb_byte(cdb, 4);

   //Check if the device has SMART support & SMART enabled
   if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_SUPPORT)
   {
       if(sequence->device->capabilities & SATI_DEVICE_CAP_SMART_ENABLE)
       {
            sati_ata_smart_return_status_construct(
                           ata_io,
                           sequence,
                           ATA_SMART_SUB_CMD_RETURN_STATUS
            );

            sequence->type = SATI_SEQUENCE_REQUEST_SENSE_SMART_RETURN_STATUS;
            return SATI_SUCCESS;
        }
   }
   sati_ata_check_power_mode_construct(ata_io, sequence);
   sequence->type = SATI_SEQUENCE_REQUEST_SENSE_CHECK_POWER_MODE;
   return SATI_SUCCESS;
}
Example #24
0
/**
 * @brief This method will be called before starting the first unmap translation
 *
 * @return Indicate if the translation was successful.
 * @retval SATI_SUCCESS This is returned if the command translation was
 *         successful and no further processing.
 * @retval SATI_COMPLETE - The initial processing was completed successfully
 * @retval SATI_FAILURE_CHECK_RESPONSE_DATA - Failed the initial processing
 */
SATI_STATUS sati_unmap_initial_processing(
   SATI_TRANSLATOR_SEQUENCE_T * sequence,
   void                       * scsi_io,
   void                       * ata_io
)
{
   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
   U8 * cdb;
   U16 unmap_length;
   U32 descriptor_length;
   U32 index;
   U32 max_dsm_blocks;
   U8  unmap_param_list[8];

   unmap_process_state = &sequence->command_specific_data.unmap_process_state;

   // Set up the sequence type for unmap translation
   sequence->type = SATI_SEQUENCE_UNMAP;

   // Make sure the device is TRIM capable
   if ((sequence->device->capabilities & SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
       != SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
   {
      // Can't send TRIM request to device that does not support it
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   // get the amount of data being sent from the cdb
   cdb = sati_cb_get_cdb_address(scsi_io);
   unmap_length = (sati_get_cdb_byte(cdb, 7) << 8) | sati_get_cdb_byte(cdb, 8);

   // If nothing has been requested return success now.
   if (unmap_length == 0)
   {
       // SAT: This is not an error
       return SATI_SUCCESS;
   }
   if (unmap_length < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST)
   {
      // Not enough length specified in the CDB
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   sequence->allocation_length = unmap_length;

   // Get the unmap parameter header
   for(index = 0; index < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST; index++)
   {
      sati_get_data_byte(sequence, scsi_io, index,   &unmap_param_list[index]);
   }
   descriptor_length = (unmap_param_list[2] << 8) | unmap_param_list[3];

   // Check length again
   if (descriptor_length == 0)
   {
       // SAT: This is not an error
       return SATI_SUCCESS;
   }

   if ((U32)(unmap_length - SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST) < descriptor_length)
   {
      // Not enough length specified in the CDB
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_CHECK_CONDITION,
         SCSI_SENSE_ILLEGAL_REQUEST,
         SCSI_ASC_INVALID_FIELD_IN_CDB,
         SCSI_ASCQ_INVALID_FIELD_IN_CDB
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   // Save the maximum unmap block descriptors in this request
   unmap_process_state->max_unmap_block_descriptors =
       descriptor_length/SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;

   // Determine the maximum size of the write buffer that will be required
   // for the translation in terms of number of blocks
   max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);

   // Save the maximum number of DSM descriptors we can send during the translation
   unmap_process_state->max_lba_range_entries =
       (max_dsm_blocks*sequence->device->logical_block_size)/sizeof(TRIM_PAIR);

   // Get the write buffer for the translation
   sati_cb_allocate_dma_buffer(
      scsi_io,
      max_dsm_blocks*sequence->device->logical_block_size,
      &(unmap_process_state->virtual_unmap_buffer),
      &(unmap_process_state->physical_unmap_buffer_low),
      &(unmap_process_state->physical_unmap_buffer_high));

   // Makes sure we have a buffer
   if (unmap_process_state->virtual_unmap_buffer == NULL)
   {
      // Resource failure
      sati_scsi_sense_data_construct(
         sequence,
         scsi_io,
         SCSI_STATUS_BUSY,
         SCSI_SENSE_NO_SENSE,
         SCSI_ASC_NO_ADDITIONAL_SENSE,
         SCSI_ASCQ_NO_ADDITIONAL_SENSE
      );
      return SATI_FAILURE_CHECK_RESPONSE_DATA;
   }

   // Get the first SGL entry.  This code will only use one 4K page so will
   // only utilize the first sge.
   sati_cb_sgl_next_sge(scsi_io,
                        ata_io,
                        NULL,
                        &(unmap_process_state->unmap_buffer_sgl_pair));

   // Load the first descriptor to start the translation loop
   unmap_process_state->current_unmap_block_descriptor_index =
      SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST;
   sati_unmap_load_next_descriptor(sequence,scsi_io);

   // Next state will be incomplete since translation
   // will require a callback and possibly more requests.
   sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;

   return SATI_COMPLETE;
}