Home | History | Annotate | Download | only in UsbBotPei
      1 /** @file
      2 Pei USB ATATPI command implementations.
      3 
      4 Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions
      8 of the BSD License which accompanies this distribution.  The
      9 full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "UsbBotPeim.h"
     18 #include "BotPeim.h"
     19 
     20 #define MAXSENSEKEY 5
     21 
     22 /**
     23   Sends out ATAPI Inquiry Packet Command to the specified device. This command will
     24   return INQUIRY data of the device.
     25 
     26   @param PeiServices    The pointer of EFI_PEI_SERVICES.
     27   @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.
     28 
     29   @retval EFI_SUCCESS       Inquiry command completes successfully.
     30   @retval EFI_DEVICE_ERROR  Inquiry command failed.
     31 
     32 **/
     33 EFI_STATUS
     34 PeiUsbInquiry (
     35   IN  EFI_PEI_SERVICES  **PeiServices,
     36   IN  PEI_BOT_DEVICE    *PeiBotDevice
     37   )
     38 {
     39   ATAPI_PACKET_COMMAND  Packet;
     40   EFI_STATUS            Status;
     41   ATAPI_INQUIRY_DATA          Idata;
     42 
     43   //
     44   // fill command packet
     45   //
     46   ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
     47   ZeroMem (&Idata, sizeof (ATAPI_INQUIRY_DATA));
     48 
     49   Packet.Inquiry.opcode             = ATA_CMD_INQUIRY;
     50   Packet.Inquiry.page_code          = 0;
     51   Packet.Inquiry.allocation_length  = 36;
     52 
     53   //
     54   // Send scsi INQUIRY command packet.
     55   // According to SCSI Primary Commands-2 spec, host only needs to
     56   // retrieve the first 36 bytes for standard INQUIRY data.
     57   //
     58   Status = PeiAtapiCommand (
     59             PeiServices,
     60             PeiBotDevice,
     61             &Packet,
     62             (UINT8) sizeof (ATAPI_PACKET_COMMAND),
     63             &Idata,
     64             36,
     65             EfiUsbDataIn,
     66             2000
     67             );
     68 
     69   if (EFI_ERROR (Status)) {
     70     return EFI_DEVICE_ERROR;
     71   }
     72 
     73   if ((Idata.peripheral_type & 0x1f) == 0x05) {
     74     PeiBotDevice->DeviceType      = USBCDROM;
     75     PeiBotDevice->Media.BlockSize = 0x800;
     76     PeiBotDevice->Media2.ReadOnly       = TRUE;
     77     PeiBotDevice->Media2.RemovableMedia = TRUE;
     78     PeiBotDevice->Media2.BlockSize      = 0x800;
     79   } else {
     80     PeiBotDevice->DeviceType      = USBFLOPPY;
     81     PeiBotDevice->Media.BlockSize = 0x200;
     82     PeiBotDevice->Media2.ReadOnly       = FALSE;
     83     PeiBotDevice->Media2.RemovableMedia = TRUE;
     84     PeiBotDevice->Media2.BlockSize      = 0x200;
     85   }
     86 
     87   return EFI_SUCCESS;
     88 }
     89 
     90 /**
     91   Sends out ATAPI Test Unit Ready Packet Command to the specified device
     92   to find out whether device is accessible.
     93 
     94   @param PeiServices    The pointer of EFI_PEI_SERVICES.
     95   @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.
     96 
     97   @retval EFI_SUCCESS        TestUnit command executed successfully.
     98   @retval EFI_DEVICE_ERROR   Device cannot be executed TestUnit command successfully.
     99 
    100 **/
    101 EFI_STATUS
    102 PeiUsbTestUnitReady (
    103   IN  EFI_PEI_SERVICES  **PeiServices,
    104   IN  PEI_BOT_DEVICE    *PeiBotDevice
    105   )
    106 {
    107   ATAPI_PACKET_COMMAND  Packet;
    108   EFI_STATUS            Status;
    109 
    110   //
    111   // fill command packet
    112   //
    113   ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
    114   Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
    115 
    116   //
    117   // send command packet
    118   //
    119   Status = PeiAtapiCommand (
    120             PeiServices,
    121             PeiBotDevice,
    122             &Packet,
    123             (UINT8) sizeof (ATAPI_PACKET_COMMAND),
    124             NULL,
    125             0,
    126             EfiUsbNoData,
    127             2000
    128             );
    129 
    130   if (EFI_ERROR (Status)) {
    131     return EFI_DEVICE_ERROR;
    132   }
    133 
    134   return EFI_SUCCESS;
    135 }
    136 
    137 /**
    138   Sends out ATAPI Request Sense Packet Command to the specified device.
    139 
    140   @param PeiServices    The pointer of EFI_PEI_SERVICES.
    141   @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.
    142   @param SenseCounts    Length of sense buffer.
    143   @param SenseKeyBuffer Pointer to sense buffer.
    144 
    145   @retval EFI_SUCCESS           Command executed successfully.
    146   @retval EFI_DEVICE_ERROR      Some device errors happen.
    147 
    148 **/
    149 EFI_STATUS
    150 PeiUsbRequestSense (
    151   IN  EFI_PEI_SERVICES  **PeiServices,
    152   IN  PEI_BOT_DEVICE    *PeiBotDevice,
    153   OUT UINTN             *SenseCounts,
    154   IN  UINT8             *SenseKeyBuffer
    155   )
    156 {
    157   EFI_STATUS                  Status;
    158   ATAPI_PACKET_COMMAND        Packet;
    159   UINT8                       *Ptr;
    160   BOOLEAN                     SenseReq;
    161   ATAPI_REQUEST_SENSE_DATA    *Sense;
    162 
    163   *SenseCounts = 0;
    164 
    165   //
    166   // fill command packet for Request Sense Packet Command
    167   //
    168   ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
    169   Packet.RequestSence.opcode            = ATA_CMD_REQUEST_SENSE;
    170   Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);
    171 
    172   Ptr = SenseKeyBuffer;
    173 
    174   SenseReq = TRUE;
    175 
    176   //
    177   //  request sense data from device continuously
    178   //  until no sense data exists in the device.
    179   //
    180   while (SenseReq) {
    181     Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
    182 
    183     //
    184     // send out Request Sense Packet Command and get one Sense
    185     // data form device.
    186     //
    187     Status = PeiAtapiCommand (
    188               PeiServices,
    189               PeiBotDevice,
    190               &Packet,
    191               (UINT8) sizeof (ATAPI_PACKET_COMMAND),
    192               (VOID *) Ptr,
    193               sizeof (ATAPI_REQUEST_SENSE_DATA),
    194               EfiUsbDataIn,
    195               2000
    196               );
    197 
    198     //
    199     // failed to get Sense data
    200     //
    201     if (EFI_ERROR (Status)) {
    202       if (*SenseCounts == 0) {
    203         return EFI_DEVICE_ERROR;
    204       } else {
    205         return EFI_SUCCESS;
    206       }
    207     }
    208 
    209     if (Sense->sense_key != ATA_SK_NO_SENSE) {
    210 
    211       Ptr += sizeof (ATAPI_REQUEST_SENSE_DATA);
    212       //
    213       // Ptr is byte based pointer
    214       //
    215       (*SenseCounts)++;
    216 
    217       if (*SenseCounts == MAXSENSEKEY) {
    218         break;
    219       }
    220 
    221     } else {
    222       //
    223       // when no sense key, skip out the loop
    224       //
    225       SenseReq = FALSE;
    226     }
    227   }
    228 
    229   return EFI_SUCCESS;
    230 }
    231 
    232 /**
    233   Sends out ATAPI Read Capacity Packet Command to the specified device.
    234   This command will return the information regarding the capacity of the
    235   media in the device.
    236 
    237   @param PeiServices    The pointer of EFI_PEI_SERVICES.
    238   @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.
    239 
    240   @retval EFI_SUCCESS           Command executed successfully.
    241   @retval EFI_DEVICE_ERROR      Some device errors happen.
    242 
    243 **/
    244 EFI_STATUS
    245 PeiUsbReadCapacity (
    246   IN  EFI_PEI_SERVICES  **PeiServices,
    247   IN  PEI_BOT_DEVICE    *PeiBotDevice
    248   )
    249 {
    250   EFI_STATUS                  Status;
    251   ATAPI_PACKET_COMMAND        Packet;
    252   ATAPI_READ_CAPACITY_DATA    Data;
    253   UINT32                      LastBlock;
    254 
    255   ZeroMem (&Data, sizeof (ATAPI_READ_CAPACITY_DATA));
    256   ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
    257 
    258   Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
    259 
    260   //
    261   // send command packet
    262   //
    263   Status = PeiAtapiCommand (
    264             PeiServices,
    265             PeiBotDevice,
    266             &Packet,
    267             (UINT8) sizeof (ATAPI_PACKET_COMMAND),
    268             (VOID *) &Data,
    269             sizeof (ATAPI_READ_CAPACITY_DATA),
    270             EfiUsbDataIn,
    271             2000
    272             );
    273 
    274   if (EFI_ERROR (Status)) {
    275     return EFI_DEVICE_ERROR;
    276   }
    277   LastBlock = (Data.LastLba3 << 24) | (Data.LastLba2 << 16) | (Data.LastLba1 << 8) | Data.LastLba0;
    278 
    279   if (LastBlock == 0xFFFFFFFF) {
    280     DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
    281   }
    282 
    283   PeiBotDevice->Media.LastBlock    = LastBlock;
    284   PeiBotDevice->Media.MediaPresent = TRUE;
    285 
    286   PeiBotDevice->Media2.LastBlock    = LastBlock;
    287   PeiBotDevice->Media2.MediaPresent = TRUE;
    288 
    289   return EFI_SUCCESS;
    290 }
    291 
    292 /**
    293   Sends out ATAPI Read Format Capacity Data Command to the specified device.
    294   This command will return the information regarding the capacity of the
    295   media in the device.
    296 
    297   @param PeiServices    The pointer of EFI_PEI_SERVICES.
    298   @param PeiBotDevice   The pointer to PEI_BOT_DEVICE instance.
    299 
    300   @retval EFI_SUCCESS           Command executed successfully.
    301   @retval EFI_DEVICE_ERROR      Some device errors happen.
    302 
    303 **/
    304 EFI_STATUS
    305 PeiUsbReadFormattedCapacity (
    306   IN  EFI_PEI_SERVICES  **PeiServices,
    307   IN  PEI_BOT_DEVICE    *PeiBotDevice
    308   )
    309 {
    310   EFI_STATUS                      Status;
    311   ATAPI_PACKET_COMMAND            Packet;
    312   ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
    313   UINT32                          LastBlock;
    314 
    315   ZeroMem (&FormatData, sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA));
    316   ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
    317 
    318   Packet.ReadFormatCapacity.opcode                = ATA_CMD_READ_FORMAT_CAPACITY;
    319   Packet.ReadFormatCapacity.allocation_length_lo  = 12;
    320 
    321   //
    322   // send command packet
    323   //
    324   Status = PeiAtapiCommand (
    325             PeiServices,
    326             PeiBotDevice,
    327             &Packet,
    328             (UINT8) sizeof (ATAPI_PACKET_COMMAND),
    329             (VOID *) &FormatData,
    330             sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
    331             EfiUsbDataIn,
    332             2000
    333             );
    334 
    335   if (EFI_ERROR (Status)) {
    336     return EFI_DEVICE_ERROR;
    337   }
    338 
    339   if (FormatData.DesCode == 3) {
    340     //
    341     // Media is not present
    342     //
    343     PeiBotDevice->Media.MediaPresent  = FALSE;
    344     PeiBotDevice->Media.LastBlock     = 0;
    345     PeiBotDevice->Media2.MediaPresent  = FALSE;
    346     PeiBotDevice->Media2.LastBlock     = 0;
    347 
    348   } else {
    349     LastBlock = (FormatData.LastLba3 << 24) | (FormatData.LastLba2 << 16) | (FormatData.LastLba1 << 8) | FormatData.LastLba0;
    350     if (LastBlock == 0xFFFFFFFF) {
    351       DEBUG ((EFI_D_INFO, "The usb device LBA count is larger than 0xFFFFFFFF!\n"));
    352     }
    353 
    354     PeiBotDevice->Media.LastBlock = LastBlock;
    355 
    356     PeiBotDevice->Media.LastBlock--;
    357 
    358     PeiBotDevice->Media.MediaPresent = TRUE;
    359 
    360     PeiBotDevice->Media2.MediaPresent = TRUE;
    361     PeiBotDevice->Media2.LastBlock    = PeiBotDevice->Media.LastBlock;
    362   }
    363 
    364   return EFI_SUCCESS;
    365 }
    366 
    367 /**
    368   Execute Read(10) ATAPI command on a specific SCSI target.
    369 
    370   Executes the ATAPI Read(10) command on the ATAPI target specified by PeiBotDevice.
    371 
    372   @param PeiServices       The pointer of EFI_PEI_SERVICES.
    373   @param PeiBotDevice      The pointer to PEI_BOT_DEVICE instance.
    374   @param Buffer            The pointer to data buffer.
    375   @param Lba               The start logic block address of reading.
    376   @param NumberOfBlocks    The block number of reading.
    377 
    378   @retval EFI_SUCCESS           Command executed successfully.
    379   @retval EFI_DEVICE_ERROR      Some device errors happen.
    380 
    381 **/
    382 EFI_STATUS
    383 PeiUsbRead10 (
    384   IN  EFI_PEI_SERVICES  **PeiServices,
    385   IN  PEI_BOT_DEVICE    *PeiBotDevice,
    386   IN  VOID              *Buffer,
    387   IN  EFI_PEI_LBA       Lba,
    388   IN  UINTN             NumberOfBlocks
    389   )
    390 {
    391   ATAPI_PACKET_COMMAND  Packet;
    392   ATAPI_READ10_CMD      *Read10Packet;
    393   UINT16                MaxBlock;
    394   UINT16                BlocksRemaining;
    395   UINT16                SectorCount;
    396   UINT32                Lba32;
    397   UINT32                BlockSize;
    398   UINT32                ByteCount;
    399   VOID                  *PtrBuffer;
    400   EFI_STATUS            Status;
    401   UINT16                TimeOut;
    402 
    403   //
    404   // prepare command packet for the Inquiry Packet Command.
    405   //
    406   ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
    407   Read10Packet    = &Packet.Read10;
    408   Lba32           = (UINT32) Lba;
    409   PtrBuffer       = Buffer;
    410 
    411   BlockSize       = (UINT32) PeiBotDevice->Media.BlockSize;
    412 
    413   MaxBlock        = (UINT16) (65535 / BlockSize);
    414   BlocksRemaining = (UINT16) NumberOfBlocks;
    415 
    416   Status          = EFI_SUCCESS;
    417   while (BlocksRemaining > 0) {
    418 
    419     if (BlocksRemaining <= MaxBlock) {
    420 
    421       SectorCount = BlocksRemaining;
    422 
    423     } else {
    424 
    425       SectorCount = MaxBlock;
    426     }
    427     //
    428     // fill the Packet data structure
    429     //
    430     Read10Packet->opcode = ATA_CMD_READ_10;
    431 
    432     //
    433     // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
    434     // Lba0 is MSB, Lba3 is LSB
    435     //
    436     Read10Packet->Lba3  = (UINT8) (Lba32 & 0xff);
    437     Read10Packet->Lba2  = (UINT8) (Lba32 >> 8);
    438     Read10Packet->Lba1  = (UINT8) (Lba32 >> 16);
    439     Read10Packet->Lba0  = (UINT8) (Lba32 >> 24);
    440 
    441     //
    442     // TranLen0 ~ TranLen1 specify the transfer length in block unit.
    443     // TranLen0 is MSB, TranLen is LSB
    444     //
    445     Read10Packet->TranLen1  = (UINT8) (SectorCount & 0xff);
    446     Read10Packet->TranLen0  = (UINT8) (SectorCount >> 8);
    447 
    448     ByteCount               = SectorCount * BlockSize;
    449 
    450     TimeOut                 = (UINT16) (SectorCount * 2000);
    451 
    452     //
    453     // send command packet
    454     //
    455     Status = PeiAtapiCommand (
    456               PeiServices,
    457               PeiBotDevice,
    458               &Packet,
    459               (UINT8) sizeof (ATAPI_PACKET_COMMAND),
    460               (VOID *) PtrBuffer,
    461               ByteCount,
    462               EfiUsbDataIn,
    463               TimeOut
    464               );
    465 
    466     if (Status != EFI_SUCCESS) {
    467       return Status;
    468     }
    469 
    470     Lba32 += SectorCount;
    471     PtrBuffer       = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
    472     BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount);
    473   }
    474 
    475   return Status;
    476 }
    477 
    478 /**
    479   Check if there is media according to sense data.
    480 
    481   @param  SenseData   Pointer to sense data.
    482   @param  SenseCounts Count of sense data.
    483 
    484   @retval TRUE    No media
    485   @retval FALSE   Media exists
    486 
    487 **/
    488 BOOLEAN
    489 IsNoMedia (
    490   IN  ATAPI_REQUEST_SENSE_DATA *SenseData,
    491   IN  UINTN                    SenseCounts
    492   )
    493 {
    494   ATAPI_REQUEST_SENSE_DATA  *SensePtr;
    495   UINTN                     Index;
    496   BOOLEAN                   NoMedia;
    497 
    498   NoMedia   = FALSE;
    499   SensePtr  = SenseData;
    500 
    501   for (Index = 0; Index < SenseCounts; Index++) {
    502 
    503     switch (SensePtr->sense_key) {
    504 
    505     case ATA_SK_NOT_READY:
    506       switch (SensePtr->addnl_sense_code) {
    507       //
    508       // if no media, fill IdeDev parameter with specific info.
    509       //
    510       case ATA_ASC_NO_MEDIA:
    511         NoMedia = TRUE;
    512         break;
    513 
    514       default:
    515         break;
    516       }
    517       break;
    518 
    519     default:
    520       break;
    521     }
    522 
    523     SensePtr++;
    524   }
    525 
    526   return NoMedia;
    527 }
    528 
    529 /**
    530   Check if there is media error according to sense data.
    531 
    532   @param  SenseData   Pointer to sense data.
    533   @param  SenseCounts Count of sense data.
    534 
    535   @retval TRUE    Media error
    536   @retval FALSE   No media error
    537 
    538 **/
    539 BOOLEAN
    540 IsMediaError (
    541   IN  ATAPI_REQUEST_SENSE_DATA    *SenseData,
    542   IN  UINTN                       SenseCounts
    543   )
    544 {
    545   ATAPI_REQUEST_SENSE_DATA  *SensePtr;
    546   UINTN                     Index;
    547   BOOLEAN                   Error;
    548 
    549   SensePtr  = SenseData;
    550   Error     = FALSE;
    551 
    552   for (Index = 0; Index < SenseCounts; Index++) {
    553 
    554     switch (SensePtr->sense_key) {
    555     //
    556     // Medium error case
    557     //
    558     case ATA_SK_MEDIUM_ERROR:
    559       switch (SensePtr->addnl_sense_code) {
    560       case ATA_ASC_MEDIA_ERR1:
    561         //
    562         // fall through
    563         //
    564       case ATA_ASC_MEDIA_ERR2:
    565         //
    566         // fall through
    567         //
    568       case ATA_ASC_MEDIA_ERR3:
    569         //
    570         // fall through
    571         //
    572       case ATA_ASC_MEDIA_ERR4:
    573         Error = TRUE;
    574         break;
    575 
    576       default:
    577         break;
    578       }
    579 
    580       break;
    581 
    582     //
    583     // Medium upside-down case
    584     //
    585     case ATA_SK_NOT_READY:
    586       switch (SensePtr->addnl_sense_code) {
    587       case ATA_ASC_MEDIA_UPSIDE_DOWN:
    588         Error = TRUE;
    589         break;
    590 
    591       default:
    592         break;
    593       }
    594       break;
    595 
    596     default:
    597       break;
    598     }
    599 
    600     SensePtr++;
    601   }
    602 
    603   return Error;
    604 }
    605 
    606 /**
    607   Check if media is changed according to sense data.
    608 
    609   @param  SenseData   Pointer to sense data.
    610   @param  SenseCounts Count of sense data.
    611 
    612   @retval TRUE    There is media change event.
    613   @retval FALSE   media is NOT changed.
    614 
    615 **/
    616 BOOLEAN
    617 IsMediaChange (
    618   IN  ATAPI_REQUEST_SENSE_DATA *SenseData,
    619   IN  UINTN                    SenseCounts
    620   )
    621 {
    622   ATAPI_REQUEST_SENSE_DATA  *SensePtr;
    623   UINTN                     Index;
    624   BOOLEAN                   MediaChange;
    625 
    626   MediaChange = FALSE;
    627 
    628   SensePtr    = SenseData;
    629 
    630   for (Index = 0; Index < SenseCounts; Index++) {
    631     //
    632     // catch media change sense key and addition sense data
    633     //
    634     switch (SensePtr->sense_key) {
    635     case ATA_SK_UNIT_ATTENTION:
    636       switch (SensePtr->addnl_sense_code) {
    637       case ATA_ASC_MEDIA_CHANGE:
    638         MediaChange = TRUE;
    639         break;
    640 
    641       default:
    642         break;
    643       }
    644       break;
    645 
    646     default:
    647       break;
    648     }
    649 
    650     SensePtr++;
    651   }
    652 
    653   return MediaChange;
    654 }
    655