ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;\r
ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;\r
ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;\r
+ ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia;\r
+ ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx;\r
+ ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;\r
+ ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;\r
+ ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;\r
ScsiDiskDevice->Handle = Controller;\r
+ InitializeListHead (&ScsiDiskDevice->BlkIo2Queue);\r
\r
ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));\r
switch (ScsiDiskDevice->DeviceType) {\r
Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);\r
if (!EFI_ERROR (Status)) {\r
//\r
- // Determine if Block IO should be produced on this controller handle\r
+ // Determine if Block IO & Block IO2 should be produced on this controller\r
+ // handle\r
//\r
if (DetermineInstallBlockIo(Controller)) {\r
InitializeInstallDiskInfo(ScsiDiskDevice, Controller);\r
&Controller,\r
&gEfiBlockIoProtocolGuid,\r
&ScsiDiskDevice->BlkIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo2,\r
&gEfiDiskInfoProtocolGuid,\r
&ScsiDiskDevice->DiskInfo,\r
NULL\r
return Status;\r
}\r
\r
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);\r
+\r
+ //\r
+ // Wait for the BlockIo2 requests queue to become empty\r
+ //\r
+ while (!IsListEmpty (&ScsiDiskDevice->BlkIo2Queue));\r
+\r
Status = gBS->UninstallMultipleProtocolInterfaces (\r
Controller,\r
&gEfiBlockIoProtocolGuid,\r
&ScsiDiskDevice->BlkIo,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo2,\r
&gEfiDiskInfoProtocolGuid,\r
&ScsiDiskDevice->DiskInfo,\r
NULL\r
\r
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
\r
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);\r
\r
Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
\r
\r
MediaChange = FALSE;\r
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);\r
\r
if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
\r
&ScsiDiskDevice->BlkIo,\r
&ScsiDiskDevice->BlkIo\r
);\r
+ gBS->ReinstallProtocolInterface (\r
+ ScsiDiskDevice->Handle,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo2,\r
+ &ScsiDiskDevice->BlkIo2\r
+ );\r
Status = EFI_MEDIA_CHANGED;\r
goto Done;\r
}\r
\r
MediaChange = FALSE;\r
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
- ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);\r
\r
if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
\r
&ScsiDiskDevice->BlkIo,\r
&ScsiDiskDevice->BlkIo\r
);\r
+ gBS->ReinstallProtocolInterface (\r
+ ScsiDiskDevice->Handle,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo2,\r
+ &ScsiDiskDevice->BlkIo2\r
+ );\r
Status = EFI_MEDIA_CHANGED;\r
goto Done;\r
}\r
}\r
\r
\r
+/**\r
+ Reset SCSI Disk.\r
+\r
+ @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.\r
+ @param ExtendedVerification The flag about if extend verificate.\r
+\r
+ @retval EFI_SUCCESS The device was reset.\r
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
+ not be reset.\r
+ @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskResetEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN BOOLEAN ExtendedVerification\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+ EFI_STATUS Status;\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
+\r
+ Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ if (!ExtendedVerification) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+Done:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The function is to Read Block from SCSI Disk.\r
+\r
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
+ @param MediaId The Id of Media detected.\r
+ @param Lba The logic block address.\r
+ @param Token A pointer to the token associated with the transaction.\r
+ @param BufferSize The size of Buffer.\r
+ @param Buffer The buffer to fill the read out data.\r
+\r
+ @retval EFI_SUCCESS The read request was queued if Token-> Event is\r
+ not NULL. The data was read correctly from the\r
+ device if theToken-> Event is NULL.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the read operation.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
+ valid, or the buffer is not on proper\r
+ alignment.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskReadBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ EFI_STATUS Status;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ BOOLEAN MediaChange;\r
+ EFI_TPL OldTpl;\r
+\r
+ MediaChange = FALSE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
+\r
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
+\r
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ if (MediaChange) {\r
+ gBS->ReinstallProtocolInterface (\r
+ ScsiDiskDevice->Handle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo,\r
+ &ScsiDiskDevice->BlkIo\r
+ );\r
+ gBS->ReinstallProtocolInterface (\r
+ ScsiDiskDevice->Handle,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo2,\r
+ &ScsiDiskDevice->BlkIo2\r
+ );\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto Done;\r
+ }\r
+ }\r
+ //\r
+ // Get the intrinsic block size\r
+ //\r
+ Media = ScsiDiskDevice->BlkIo2.Media;\r
+ BlockSize = Media->BlockSize;\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (!(Media->MediaPresent)) {\r
+ Status = EFI_NO_MEDIA;\r
+ goto Done;\r
+ }\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto Done;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ if (Lba > Media->LastBlock) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // If all the parameters are valid, then perform read sectors command\r
+ // to transfer data from device to host.\r
+ //\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ Status = ScsiDiskAsyncReadSectors (\r
+ ScsiDiskDevice,\r
+ Buffer,\r
+ Lba,\r
+ NumberOfBlocks,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskReadSectors (\r
+ ScsiDiskDevice,\r
+ Buffer,\r
+ Lba,\r
+ NumberOfBlocks\r
+ );\r
+ }\r
+\r
+Done:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The function is to Write Block to SCSI Disk.\r
+\r
+ @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
+ @param MediaId The Id of Media detected.\r
+ @param Lba The logic block address.\r
+ @param Token A pointer to the token associated with the transaction.\r
+ @param BufferSize The size of Buffer.\r
+ @param Buffer The buffer to fill the read out data.\r
+\r
+ @retval EFI_SUCCESS The data were written correctly to the device.\r
+ @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
+ to perform the write operation.\r
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
+ the intrinsic block size of the device.\r
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not\r
+ valid, or the buffer is not on proper\r
+ alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskWriteBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN UINT32 MediaId,\r
+ IN EFI_LBA Lba,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ )\r
+{\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+ EFI_BLOCK_IO_MEDIA *Media;\r
+ EFI_STATUS Status;\r
+ UINTN BlockSize;\r
+ UINTN NumberOfBlocks;\r
+ BOOLEAN MediaChange;\r
+ EFI_TPL OldTpl;\r
+\r
+ MediaChange = FALSE;\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+ ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
+\r
+ if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
+\r
+ Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
+ if (EFI_ERROR (Status)) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Done;\r
+ }\r
+\r
+ if (MediaChange) {\r
+ gBS->ReinstallProtocolInterface (\r
+ ScsiDiskDevice->Handle,\r
+ &gEfiBlockIoProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo,\r
+ &ScsiDiskDevice->BlkIo\r
+ );\r
+ gBS->ReinstallProtocolInterface (\r
+ ScsiDiskDevice->Handle,\r
+ &gEfiBlockIo2ProtocolGuid,\r
+ &ScsiDiskDevice->BlkIo2,\r
+ &ScsiDiskDevice->BlkIo2\r
+ );\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto Done;\r
+ }\r
+ }\r
+ //\r
+ // Get the intrinsic block size\r
+ //\r
+ Media = ScsiDiskDevice->BlkIo2.Media;\r
+ BlockSize = Media->BlockSize;\r
+\r
+ NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+ if (!(Media->MediaPresent)) {\r
+ Status = EFI_NO_MEDIA;\r
+ goto Done;\r
+ }\r
+\r
+ if (MediaId != Media->MediaId) {\r
+ Status = EFI_MEDIA_CHANGED;\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize == 0) {\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if (BufferSize % BlockSize != 0) {\r
+ Status = EFI_BAD_BUFFER_SIZE;\r
+ goto Done;\r
+ }\r
+\r
+ if (Lba > Media->LastBlock) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // if all the parameters are valid, then perform write sectors command\r
+ // to transfer data from device to host.\r
+ //\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ Status = ScsiDiskAsyncWriteSectors (\r
+ ScsiDiskDevice,\r
+ Buffer,\r
+ Lba,\r
+ NumberOfBlocks,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskWriteSectors (\r
+ ScsiDiskDevice,\r
+ Buffer,\r
+ Lba,\r
+ NumberOfBlocks\r
+ );\r
+ }\r
+\r
+Done:\r
+ gBS->RestoreTPL (OldTpl);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Flush the Block Device.\r
+\r
+ @param This Indicates a pointer to the calling context.\r
+ @param Token A pointer to the token associated with the transaction.\r
+\r
+ @retval EFI_SUCCESS All outstanding data was written to the device.\r
+ @retval EFI_DEVICE_ERROR The device reported an error while writing back the\r
+ data.\r
+ @retval EFI_NO_MEDIA There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ScsiDiskFlushBlocksEx (\r
+ IN EFI_BLOCK_IO2_PROTOCOL *This,\r
+ IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ //\r
+ // Signal event and return directly.\r
+ //\r
+ if ((Token != NULL) && (Token->Event != NULL)) {\r
+ Token->TransactionStatus = EFI_SUCCESS;\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
/**\r
Detect Device and read out capacity ,if error occurs, parse the sense key.\r
\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Asynchronously read sector from SCSI Disk.\r
+\r
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
+ @param Buffer The buffer to fill in the read out data.\r
+ @param Lba Logic block address.\r
+ @param NumberOfBlocks The number of blocks to read.\r
+ @param Token A pointer to the token associated with the\r
+ non-blocking read request.\r
+\r
+ @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.\r
+ @retval EFI_DEVICE_ERROR Indicates a device error.\r
+ @retval EFI_SUCCESS Operation is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskAsyncReadSectors (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ OUT VOID *Buffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ UINTN BlocksRemaining;\r
+ UINT8 *PtrBuffer;\r
+ UINT32 BlockSize;\r
+ UINT32 ByteCount;\r
+ UINT32 MaxBlock;\r
+ UINT32 SectorCount;\r
+ UINT64 Timeout;\r
+ SCSI_BLKIO2_REQUEST *BlkIo2Req;\r
+ EFI_STATUS Status;\r
+\r
+ if ((Token == NULL) || (Token->Event == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));\r
+ if (BlkIo2Req == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ BlkIo2Req->Token = Token;\r
+ InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);\r
+ InitializeListHead (&BlkIo2Req->ScsiRWQueue);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ BlocksRemaining = NumberOfBlocks;\r
+ BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+\r
+ //\r
+ // Limit the data bytes that can be transferred by one Read(10) or Read(16)\r
+ // Command\r
+ //\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ MaxBlock = 0xFFFF;\r
+ } else {\r
+ MaxBlock = 0xFFFFFFFF;\r
+ }\r
+\r
+ PtrBuffer = Buffer;\r
+\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining <= MaxBlock) {\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ } else {\r
+ SectorCount = (UINT32) BlocksRemaining;\r
+ }\r
+ } else {\r
+ SectorCount = MaxBlock;\r
+ }\r
+\r
+ ByteCount = SectorCount * BlockSize;\r
+ //\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ //\r
+ // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,\r
+ // we have to use the lowest transfer rate to calculate the possible\r
+ // maximum timeout value for each operation.\r
+ // From the above table, we could know 2.1Mbytes per second is lowest one.\r
+ // The timout value is rounded up to nearest integar and here an additional\r
+ // 30s is added to follow ATA spec in which it mentioned that the device\r
+ // may take up to 30s to respond commands in the Standby/Idle mode.\r
+ //\r
+ Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);\r
+\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskAsyncRead10 (\r
+ ScsiDiskDevice,\r
+ Timeout,\r
+ PtrBuffer,\r
+ ByteCount,\r
+ (UINT32) Lba,\r
+ SectorCount,\r
+ BlkIo2Req,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskAsyncRead16 (\r
+ ScsiDiskDevice,\r
+ Timeout,\r
+ PtrBuffer,\r
+ ByteCount,\r
+ Lba,\r
+ SectorCount,\r
+ BlkIo2Req,\r
+ Token\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI\r
+ // command fails. Otherwise, it will be freed in the callback function\r
+ // ScsiDiskNotify().\r
+ //\r
+ if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+ RemoveEntryList (&BlkIo2Req->Link);\r
+ FreePool (BlkIo2Req);\r
+ }\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Sectors submitted for transfer\r
+ //\r
+ SectorCount = ByteCount / BlockSize;\r
+\r
+ Lba += SectorCount;\r
+ PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Asynchronously write sector to SCSI Disk.\r
+\r
+ @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
+ @param Buffer The buffer of data to be written into SCSI Disk.\r
+ @param Lba Logic block address.\r
+ @param NumberOfBlocks The number of blocks to read.\r
+ @param Token A pointer to the token associated with the\r
+ non-blocking read request.\r
+\r
+ @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL\r
+ @retval EFI_DEVICE_ERROR Indicates a device error.\r
+ @retval EFI_SUCCESS Operation is successful.\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskAsyncWriteSectors (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN VOID *Buffer,\r
+ IN EFI_LBA Lba,\r
+ IN UINTN NumberOfBlocks,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ UINTN BlocksRemaining;\r
+ UINT8 *PtrBuffer;\r
+ UINT32 BlockSize;\r
+ UINT32 ByteCount;\r
+ UINT32 MaxBlock;\r
+ UINT32 SectorCount;\r
+ UINT64 Timeout;\r
+ SCSI_BLKIO2_REQUEST *BlkIo2Req;\r
+ EFI_STATUS Status;\r
+\r
+ if ((Token == NULL) || (Token->Event == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));\r
+ if (BlkIo2Req == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ BlkIo2Req->Token = Token;\r
+ InsertTailList (&ScsiDiskDevice->BlkIo2Queue, &BlkIo2Req->Link);\r
+ InitializeListHead (&BlkIo2Req->ScsiRWQueue);\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ BlocksRemaining = NumberOfBlocks;\r
+ BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+\r
+ //\r
+ // Limit the data bytes that can be transferred by one Read(10) or Read(16)\r
+ // Command\r
+ //\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ MaxBlock = 0xFFFF;\r
+ } else {\r
+ MaxBlock = 0xFFFFFFFF;\r
+ }\r
+\r
+ PtrBuffer = Buffer;\r
+\r
+ while (BlocksRemaining > 0) {\r
+\r
+ if (BlocksRemaining <= MaxBlock) {\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ SectorCount = (UINT16) BlocksRemaining;\r
+ } else {\r
+ SectorCount = (UINT32) BlocksRemaining;\r
+ }\r
+ } else {\r
+ SectorCount = MaxBlock;\r
+ }\r
+\r
+ ByteCount = SectorCount * BlockSize;\r
+ //\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |\r
+ // |------------------------|-----------------|------------------|-----------------|\r
+ //\r
+ // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,\r
+ // we have to use the lowest transfer rate to calculate the possible\r
+ // maximum timeout value for each operation.\r
+ // From the above table, we could know 2.1Mbytes per second is lowest one.\r
+ // The timout value is rounded up to nearest integar and here an additional\r
+ // 30s is added to follow ATA spec in which it mentioned that the device\r
+ // may take up to 30s to respond commands in the Standby/Idle mode.\r
+ //\r
+ Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);\r
+\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskAsyncWrite10 (\r
+ ScsiDiskDevice,\r
+ Timeout,\r
+ PtrBuffer,\r
+ ByteCount,\r
+ (UINT32) Lba,\r
+ SectorCount,\r
+ BlkIo2Req,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskAsyncWrite16 (\r
+ ScsiDiskDevice,\r
+ Timeout,\r
+ PtrBuffer,\r
+ ByteCount,\r
+ Lba,\r
+ SectorCount,\r
+ BlkIo2Req,\r
+ Token\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Free the SCSI_BLKIO2_REQUEST structure only when the first SCSI\r
+ // command fails. Otherwise, it will be freed in the callback function\r
+ // ScsiDiskNotify().\r
+ //\r
+ if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
+ RemoveEntryList (&BlkIo2Req->Link);\r
+ FreePool (BlkIo2Req);\r
+ }\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ //\r
+ // Sectors submitted for transfer\r
+ //\r
+ SectorCount = ByteCount / BlockSize;\r
+\r
+ Lba += SectorCount;\r
+ PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
+ BlocksRemaining -= SectorCount;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
\r
/**\r
Submit Read(10) command.\r
}\r
\r
\r
+/**\r
+ Internal helper notify function in which determine whether retry of a SCSI\r
+ Read/Write command is needed and signal the event passed from Block I/O(2) if\r
+ the SCSI I/O operation completes.\r
+\r
+ @param Event The instance of EFI_EVENT.\r
+ @param Context The parameter passed in.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ScsiDiskNotify (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_ASYNC_RW_REQUEST *Request;\r
+ SCSI_DISK_DEV *ScsiDiskDevice;\r
+ EFI_BLOCK_IO2_TOKEN *Token;\r
+ UINTN Action;\r
+ UINT32 OldDataLength;\r
+ UINT32 OldSectorCount;\r
+ UINT8 MaxRetry;\r
+\r
+ gBS->CloseEvent (Event);\r
+\r
+ Request = (SCSI_ASYNC_RW_REQUEST *) Context;\r
+ ScsiDiskDevice = Request->ScsiDiskDevice;\r
+ Token = Request->BlkIo2Req->Token;\r
+ OldDataLength = Request->DataLength;\r
+ OldSectorCount = Request->SectorCount;\r
+ MaxRetry = 2;\r
+\r
+ //\r
+ // If previous sub-tasks already fails, no need to process this sub-task.\r
+ //\r
+ if (Token->TransactionStatus != EFI_SUCCESS) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // Check HostAdapterStatus and TargetStatus\r
+ // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
+ //\r
+ Status = CheckHostAdapterStatus (Request->HostAdapterStatus);\r
+ if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
+ if (++Request->TimesRetry > MaxRetry) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ } else {\r
+ goto Retry;\r
+ }\r
+ } else if (Status == EFI_DEVICE_ERROR) {\r
+ //\r
+ // reset the scsi channel\r
+ //\r
+ ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ Status = CheckTargetStatus (Request->TargetStatus);\r
+ if (Status == EFI_NOT_READY) {\r
+ //\r
+ // reset the scsi device\r
+ //\r
+ ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
+ if (++Request->TimesRetry > MaxRetry) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ } else {\r
+ goto Retry;\r
+ }\r
+ } else if (Status == EFI_DEVICE_ERROR) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {\r
+ DEBUG ((EFI_D_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));\r
+\r
+ Status = DetectMediaParsingSenseKeys (\r
+ ScsiDiskDevice,\r
+ Request->SenseData,\r
+ Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),\r
+ &Action\r
+ );\r
+ if (Action == ACTION_RETRY_COMMAND_LATER) {\r
+ if (++Request->TimesRetry > MaxRetry) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ } else {\r
+ goto Retry;\r
+ }\r
+ } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
+ if (Request->SectorCount <= 1) {\r
+ //\r
+ // Jump out if the operation still fails with one sector transfer\r
+ // length.\r
+ //\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+ //\r
+ // Try again with two half length request if the sense data shows we need\r
+ // to retry.\r
+ //\r
+ Request->SectorCount >>= 1;\r
+ Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
+ Request->TimesRetry = 0;\r
+\r
+ goto Retry;\r
+ } else {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // This sub-task succeeds, no need to retry.\r
+ //\r
+ goto Exit;\r
+\r
+Retry:\r
+ if (Request->InBuffer != NULL) {\r
+ //\r
+ // SCSI read command\r
+ //\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskAsyncRead10 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->InBuffer,\r
+ Request->DataLength,\r
+ (UINT32) Request->StartLba,\r
+ Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskAsyncRead16 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->InBuffer,\r
+ Request->DataLength,\r
+ Request->StartLba,\r
+ Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ } else if (OldSectorCount != Request->SectorCount) {\r
+ //\r
+ // Original sub-task will be split into two new sub-tasks with smaller\r
+ // DataLength\r
+ //\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskAsyncRead10 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
+ OldDataLength - Request->DataLength,\r
+ (UINT32) Request->StartLba + Request->SectorCount,\r
+ OldSectorCount - Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskAsyncRead16 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
+ OldDataLength - Request->DataLength,\r
+ Request->StartLba + Request->SectorCount,\r
+ OldSectorCount - Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // SCSI write command\r
+ //\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskAsyncWrite10 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->OutBuffer,\r
+ Request->DataLength,\r
+ (UINT32) Request->StartLba,\r
+ Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskAsyncWrite16 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->OutBuffer,\r
+ Request->DataLength,\r
+ Request->StartLba,\r
+ Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ } else if (OldSectorCount != Request->SectorCount) {\r
+ //\r
+ // Original sub-task will be split into two new sub-tasks with smaller\r
+ // DataLength\r
+ //\r
+ if (!ScsiDiskDevice->Cdb16Byte) {\r
+ Status = ScsiDiskAsyncWrite10 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
+ OldDataLength - Request->DataLength,\r
+ (UINT32) Request->StartLba + Request->SectorCount,\r
+ OldSectorCount - Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ } else {\r
+ Status = ScsiDiskAsyncWrite16 (\r
+ ScsiDiskDevice,\r
+ Request->Timeout,\r
+ Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
+ OldDataLength - Request->DataLength,\r
+ Request->StartLba + Request->SectorCount,\r
+ OldSectorCount - Request->SectorCount,\r
+ Request->BlkIo2Req,\r
+ Token\r
+ );\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ Token->TransactionStatus = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+ }\r
+ }\r
+\r
+Exit:\r
+ RemoveEntryList (&Request->Link);\r
+ if (IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) {\r
+ //\r
+ // The last SCSI R/W command of a BlockIo2 request completes\r
+ //\r
+ RemoveEntryList (&Request->BlkIo2Req->Link);\r
+ FreePool (Request->BlkIo2Req); // Should be freed only once\r
+ gBS->SignalEvent (Token->Event);\r
+ }\r
+\r
+ FreePool (Request->SenseData);\r
+ FreePool (Request);\r
+}\r
+\r
+\r
+/**\r
+ Submit Async Read(10) command.\r
+\r
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
+ @param Timeout The time to complete the command.\r
+ @param DataBuffer The buffer to fill with the read out data.\r
+ @param DataLength The length of buffer.\r
+ @param StartLba The start logic block address.\r
+ @param SectorCount The number of blocks to read.\r
+ @param BlkIo2Req The upstream BlockIo2 request.\r
+ @param Token The pointer to the token associated with the\r
+ non-blocking read request.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+ @return others Status returned by calling\r
+ ScsiRead10CommandEx().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskAsyncRead10 (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN UINT64 Timeout,\r
+ OUT UINT8 *DataBuffer,\r
+ IN UINT32 DataLength,\r
+ IN UINT32 StartLba,\r
+ IN UINT32 SectorCount,\r
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_ASYNC_RW_REQUEST *Request;\r
+ EFI_EVENT AsyncIoEvent;\r
+\r
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
+ if (Request == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+\r
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
+ if (Request->SenseData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Request->ScsiDiskDevice = ScsiDiskDevice;\r
+ Request->Timeout = Timeout;\r
+ Request->InBuffer = DataBuffer;\r
+ Request->DataLength = DataLength;\r
+ Request->StartLba = StartLba;\r
+ Request->SectorCount = SectorCount;\r
+ Request->BlkIo2Req = BlkIo2Req;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiDiskNotify,\r
+ Request,\r
+ &AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiRead10CommandEx (\r
+ ScsiDiskDevice->ScsiIo,\r
+ Request->Timeout,\r
+ Request->SenseData,\r
+ &Request->SenseDataLength,\r
+ &Request->HostAdapterStatus,\r
+ &Request->TargetStatus,\r
+ Request->InBuffer,\r
+ &Request->DataLength,\r
+ (UINT32) Request->StartLba,\r
+ Request->SectorCount,\r
+ AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ if (Request != NULL) {\r
+ if (Request->SenseData != NULL) {\r
+ FreePool (Request->SenseData);\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+ FreePool (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submit Async Write(10) command.\r
+\r
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
+ @param Timeout The time to complete the command.\r
+ @param DataBuffer The buffer contains the data to write.\r
+ @param DataLength The length of buffer.\r
+ @param StartLba The start logic block address.\r
+ @param SectorCount The number of blocks to write.\r
+ @param BlkIo2Req The upstream BlockIo2 request.\r
+ @param Token The pointer to the token associated with the\r
+ non-blocking read request.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+ @return others Status returned by calling\r
+ ScsiWrite10CommandEx().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskAsyncWrite10 (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 *DataBuffer,\r
+ IN UINT32 DataLength,\r
+ IN UINT32 StartLba,\r
+ IN UINT32 SectorCount,\r
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_ASYNC_RW_REQUEST *Request;\r
+ EFI_EVENT AsyncIoEvent;\r
+\r
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
+ if (Request == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+\r
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
+ if (Request->SenseData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Request->ScsiDiskDevice = ScsiDiskDevice;\r
+ Request->Timeout = Timeout;\r
+ Request->OutBuffer = DataBuffer;\r
+ Request->DataLength = DataLength;\r
+ Request->StartLba = StartLba;\r
+ Request->SectorCount = SectorCount;\r
+ Request->BlkIo2Req = BlkIo2Req;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiDiskNotify,\r
+ Request,\r
+ &AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiWrite10CommandEx (\r
+ ScsiDiskDevice->ScsiIo,\r
+ Request->Timeout,\r
+ Request->SenseData,\r
+ &Request->SenseDataLength,\r
+ &Request->HostAdapterStatus,\r
+ &Request->TargetStatus,\r
+ Request->OutBuffer,\r
+ &Request->DataLength,\r
+ (UINT32) Request->StartLba,\r
+ Request->SectorCount,\r
+ AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ if (Request != NULL) {\r
+ if (Request->SenseData != NULL) {\r
+ FreePool (Request->SenseData);\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+ FreePool (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submit Async Read(16) command.\r
+\r
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
+ @param Timeout The time to complete the command.\r
+ @param DataBuffer The buffer to fill with the read out data.\r
+ @param DataLength The length of buffer.\r
+ @param StartLba The start logic block address.\r
+ @param SectorCount The number of blocks to read.\r
+ @param BlkIo2Req The upstream BlockIo2 request.\r
+ @param Token The pointer to the token associated with the\r
+ non-blocking read request.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+ @return others Status returned by calling\r
+ ScsiRead16CommandEx().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskAsyncRead16 (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN UINT64 Timeout,\r
+ OUT UINT8 *DataBuffer,\r
+ IN UINT32 DataLength,\r
+ IN UINT64 StartLba,\r
+ IN UINT32 SectorCount,\r
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_ASYNC_RW_REQUEST *Request;\r
+ EFI_EVENT AsyncIoEvent;\r
+\r
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
+ if (Request == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+\r
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
+ if (Request->SenseData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Request->ScsiDiskDevice = ScsiDiskDevice;\r
+ Request->Timeout = Timeout;\r
+ Request->InBuffer = DataBuffer;\r
+ Request->DataLength = DataLength;\r
+ Request->StartLba = StartLba;\r
+ Request->SectorCount = SectorCount;\r
+ Request->BlkIo2Req = BlkIo2Req;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiDiskNotify,\r
+ Request,\r
+ &AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiRead16CommandEx (\r
+ ScsiDiskDevice->ScsiIo,\r
+ Request->Timeout,\r
+ Request->SenseData,\r
+ &Request->SenseDataLength,\r
+ &Request->HostAdapterStatus,\r
+ &Request->TargetStatus,\r
+ Request->InBuffer,\r
+ &Request->DataLength,\r
+ Request->StartLba,\r
+ Request->SectorCount,\r
+ AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ if (Request != NULL) {\r
+ if (Request->SenseData != NULL) {\r
+ FreePool (Request->SenseData);\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+ FreePool (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Submit Async Write(16) command.\r
+\r
+ @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
+ @param Timeout The time to complete the command.\r
+ @param DataBuffer The buffer contains the data to write.\r
+ @param DataLength The length of buffer.\r
+ @param StartLba The start logic block address.\r
+ @param SectorCount The number of blocks to write.\r
+ @param BlkIo2Req The upstream BlockIo2 request.\r
+ @param Token The pointer to the token associated with the\r
+ non-blocking read request.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
+ lack of resources.\r
+ @return others Status returned by calling\r
+ ScsiWrite16CommandEx().\r
+\r
+**/\r
+EFI_STATUS\r
+ScsiDiskAsyncWrite16 (\r
+ IN SCSI_DISK_DEV *ScsiDiskDevice,\r
+ IN UINT64 Timeout,\r
+ IN UINT8 *DataBuffer,\r
+ IN UINT32 DataLength,\r
+ IN UINT64 StartLba,\r
+ IN UINT32 SectorCount,\r
+ IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
+ IN EFI_BLOCK_IO2_TOKEN *Token\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ SCSI_ASYNC_RW_REQUEST *Request;\r
+ EFI_EVENT AsyncIoEvent;\r
+\r
+ Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
+ if (Request == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
+\r
+ Request->SenseDataLength = (UINT8) (6 * sizeof (EFI_SCSI_SENSE_DATA));\r
+ Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
+ if (Request->SenseData == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Request->ScsiDiskDevice = ScsiDiskDevice;\r
+ Request->Timeout = Timeout;\r
+ Request->OutBuffer = DataBuffer;\r
+ Request->DataLength = DataLength;\r
+ Request->StartLba = StartLba;\r
+ Request->SectorCount = SectorCount;\r
+ Request->BlkIo2Req = BlkIo2Req;\r
+\r
+ //\r
+ // Create Event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ScsiDiskNotify,\r
+ Request,\r
+ &AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ Status = ScsiWrite16CommandEx (\r
+ ScsiDiskDevice->ScsiIo,\r
+ Request->Timeout,\r
+ Request->SenseData,\r
+ &Request->SenseDataLength,\r
+ &Request->HostAdapterStatus,\r
+ &Request->TargetStatus,\r
+ Request->OutBuffer,\r
+ &Request->DataLength,\r
+ Request->StartLba,\r
+ Request->SectorCount,\r
+ AsyncIoEvent\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ goto ErrorExit;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+ if (Request != NULL) {\r
+ if (Request->SenseData != NULL) {\r
+ FreePool (Request->SenseData);\r
+ }\r
+\r
+ RemoveEntryList (&Request->Link);\r
+ FreePool (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
/**\r
Check sense key to find if media presents.\r
\r
}\r
\r
/**\r
- Determine if Block Io should be produced.\r
+ Determine if Block Io & Block Io2 should be produced.\r
\r
\r
@param ChildHandle Child Handle to retrieve Parent information.\r
\r
- @retval TRUE Should produce Block Io.\r
- @retval FALSE Should not produce Block Io.\r
+ @retval TRUE Should produce Block Io & Block Io2.\r
+ @retval FALSE Should not produce Block Io & Block Io2.\r
\r
**/ \r
BOOLEAN\r