]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
MdeModulePkg/scsi :Coverity scan flags multiple issues in edk2-stable202205
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
CommitLineData
3b2dbece 1/** @file\r
2 SCSI disk driver that layers on every SCSI IO protocol in the system.\r
6ad55b15 3\r
ac81789c 4Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
52199bf5 5Copyright (c) 1985 - 2022, American Megatrends International LLC.<BR>\r
eae9e51d
S
6<<<<<<< HEAD\r
7=======\r
8\r
9>>>>>>> ace365b4e0 (MdeModulePkg/scsi :Coverity scan flags multiple issues in edk2-stable202205)\r
9d510e61 10SPDX-License-Identifier: BSD-2-Clause-Patent\r
6ad55b15 11\r
3b2dbece 12**/\r
ed7748fe 13\r
6ad55b15 14#include "ScsiDisk.h"\r
15\r
1436aea4 16EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {\r
6ad55b15 17 ScsiDiskDriverBindingSupported,\r
18 ScsiDiskDriverBindingStart,\r
19 ScsiDiskDriverBindingStop,\r
20 0xa,\r
21 NULL,\r
22 NULL\r
23};\r
24\r
1436aea4 25EFI_DISK_INFO_PROTOCOL gScsiDiskInfoProtocolTemplate = {\r
d716651f 26 EFI_DISK_INFO_SCSI_INTERFACE_GUID,\r
27 ScsiDiskInfoInquiry,\r
28 ScsiDiskInfoIdentify,\r
29 ScsiDiskInfoSenseData,\r
30 ScsiDiskInfoWhichIde\r
31};\r
9b38ff34 32\r
957fe093
SZ
33/**\r
34 Allocates an aligned buffer for SCSI disk.\r
35\r
36 This function allocates an aligned buffer for the SCSI disk to perform\r
37 SCSI IO operations. The alignment requirement is from SCSI IO interface.\r
38\r
39 @param ScsiDiskDevice The SCSI disk involved for the operation.\r
40 @param BufferSize The request buffer size.\r
41\r
42 @return A pointer to the aligned buffer or NULL if the allocation fails.\r
43\r
44**/\r
45VOID *\r
46AllocateAlignedBuffer (\r
1436aea4
MK
47 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
48 IN UINTN BufferSize\r
957fe093
SZ
49 )\r
50{\r
51 return AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), ScsiDiskDevice->ScsiIo->IoAlign);\r
52}\r
53\r
54/**\r
55 Frees an aligned buffer for SCSI disk.\r
56\r
57 This function frees an aligned buffer for the SCSI disk to perform\r
58 SCSI IO operations.\r
59\r
60 @param Buffer The aligned buffer to be freed.\r
61 @param BufferSize The request buffer size.\r
62\r
63**/\r
64VOID\r
65FreeAlignedBuffer (\r
1436aea4
MK
66 IN VOID *Buffer,\r
67 IN UINTN BufferSize\r
957fe093
SZ
68 )\r
69{\r
70 if (Buffer != NULL) {\r
71 FreeAlignedPages (Buffer, EFI_SIZE_TO_PAGES (BufferSize));\r
72 }\r
73}\r
74\r
52199bf5
CG
75/**\r
76 Remove trailing spaces from the string.\r
77\r
78 @param String The ASCII string to remove the trailing spaces.\r
79\r
80 @retval the new length of the string.\r
81**/\r
82UINTN\r
83RemoveTrailingSpaces (\r
84 IN OUT CHAR8 *String\r
85 )\r
86{\r
87 UINTN Length;\r
88\r
89 Length = AsciiStrLen (String);\r
90 if (Length == 0) {\r
91 return 0;\r
92 }\r
93\r
94 while ((Length > 0) && (String[Length-1] == ' ')) {\r
95 Length--;\r
96 }\r
97\r
98 String[Length] = '\0';\r
99 return Length;\r
100}\r
101\r
6ad55b15 102/**\r
9beb888e 103 The user Entry Point for module ScsiDisk.\r
104\r
105 The user code starts with this function.\r
6ad55b15 106\r
d1102dba 107 @param ImageHandle The firmware allocated handle for the EFI image.\r
9beb888e 108 @param SystemTable A pointer to the EFI System Table.\r
d1102dba 109\r
6ad55b15 110 @retval EFI_SUCCESS The entry point is executed successfully.\r
111 @retval other Some error occurs when executing this entry point.\r
112\r
113**/\r
114EFI_STATUS\r
115EFIAPI\r
1436aea4
MK
116InitializeScsiDisk (\r
117 IN EFI_HANDLE ImageHandle,\r
118 IN EFI_SYSTEM_TABLE *SystemTable\r
6ad55b15 119 )\r
120{\r
1436aea4 121 EFI_STATUS Status;\r
6ad55b15 122\r
123 //\r
124 // Install driver model protocol(s).\r
125 //\r
70da5bc2 126 Status = EfiLibInstallDriverBindingComponentName2 (\r
6ad55b15 127 ImageHandle,\r
128 SystemTable,\r
129 &gScsiDiskDriverBinding,\r
130 ImageHandle,\r
131 &gScsiDiskComponentName,\r
70da5bc2 132 &gScsiDiskComponentName2\r
6ad55b15 133 );\r
134 ASSERT_EFI_ERROR (Status);\r
135\r
6ad55b15 136 return Status;\r
137}\r
138\r
9beb888e 139/**\r
140 Test to see if this driver supports ControllerHandle.\r
141\r
142 This service is called by the EFI boot service ConnectController(). In order\r
143 to make drivers as small as possible, there are a few calling restrictions for\r
144 this service. ConnectController() must follow these calling restrictions.\r
145 If any other agent wishes to call Supported() it must also follow these\r
146 calling restrictions.\r
147\r
148 @param This Protocol instance pointer.\r
149 @param ControllerHandle Handle of device to test\r
150 @param RemainingDevicePath Optional parameter use to pick a specific child\r
151 device to start.\r
152\r
153 @retval EFI_SUCCESS This driver supports this device\r
154 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
155 @retval other This driver does not support this device\r
156\r
157**/\r
6ad55b15 158EFI_STATUS\r
159EFIAPI\r
160ScsiDiskDriverBindingSupported (\r
161 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
162 IN EFI_HANDLE Controller,\r
9beb888e 163 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
6ad55b15 164 )\r
6ad55b15 165{\r
166 EFI_STATUS Status;\r
167 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
168 UINT8 DeviceType;\r
169\r
170 Status = gBS->OpenProtocol (\r
171 Controller,\r
172 &gEfiScsiIoProtocolGuid,\r
1436aea4 173 (VOID **)&ScsiIo,\r
6ad55b15 174 This->DriverBindingHandle,\r
175 Controller,\r
176 EFI_OPEN_PROTOCOL_BY_DRIVER\r
177 );\r
178 if (EFI_ERROR (Status)) {\r
179 return Status;\r
180 }\r
181\r
182 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);\r
183 if (!EFI_ERROR (Status)) {\r
ac81789c
CZ
184 if ((DeviceType == EFI_SCSI_TYPE_DISK) ||\r
185 (DeviceType == EFI_SCSI_TYPE_CDROM) ||\r
1436aea4
MK
186 (DeviceType == EFI_SCSI_TYPE_WLUN))\r
187 {\r
6ad55b15 188 Status = EFI_SUCCESS;\r
189 } else {\r
190 Status = EFI_UNSUPPORTED;\r
191 }\r
192 }\r
193\r
194 gBS->CloseProtocol (\r
f36d6e66 195 Controller,\r
196 &gEfiScsiIoProtocolGuid,\r
197 This->DriverBindingHandle,\r
198 Controller\r
199 );\r
6ad55b15 200 return Status;\r
201}\r
202\r
9beb888e 203/**\r
204 Start this driver on ControllerHandle.\r
205\r
206 This service is called by the EFI boot service ConnectController(). In order\r
207 to make drivers as small as possible, there are a few calling restrictions for\r
208 this service. ConnectController() must follow these calling restrictions. If\r
209 any other agent wishes to call Start() it must also follow these calling\r
210 restrictions.\r
211\r
212 @param This Protocol instance pointer.\r
213 @param ControllerHandle Handle of device to bind driver to\r
214 @param RemainingDevicePath Optional parameter use to pick a specific child\r
215 device to start.\r
216\r
217 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
218 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
219 @retval other This driver does not support this device\r
220\r
221**/\r
6ad55b15 222EFI_STATUS\r
223EFIAPI\r
224ScsiDiskDriverBindingStart (\r
225 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
226 IN EFI_HANDLE Controller,\r
9beb888e 227 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
6ad55b15 228 )\r
6ad55b15 229{\r
230 EFI_STATUS Status;\r
231 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
232 SCSI_DISK_DEV *ScsiDiskDevice;\r
233 BOOLEAN Temp;\r
234 UINT8 Index;\r
235 UINT8 MaxRetry;\r
236 BOOLEAN NeedRetry;\r
cbd2a4b3 237 BOOLEAN MustReadCapacity;\r
52199bf5
CG
238 CHAR8 VendorStr[VENDOR_IDENTIFICATION_LENGTH + 1];\r
239 CHAR8 ProductStr[PRODUCT_IDENTIFICATION_LENGTH + 1];\r
240 CHAR16 DeviceStr[VENDOR_IDENTIFICATION_LENGTH + PRODUCT_IDENTIFICATION_LENGTH + 2];\r
cbd2a4b3 241\r
242 MustReadCapacity = TRUE;\r
6ad55b15 243\r
1436aea4 244 ScsiDiskDevice = (SCSI_DISK_DEV *)AllocateZeroPool (sizeof (SCSI_DISK_DEV));\r
9b38ff34 245 if (ScsiDiskDevice == NULL) {\r
246 return EFI_OUT_OF_RESOURCES;\r
6ad55b15 247 }\r
248\r
6ad55b15 249 Status = gBS->OpenProtocol (\r
250 Controller,\r
251 &gEfiScsiIoProtocolGuid,\r
1436aea4 252 (VOID **)&ScsiIo,\r
6ad55b15 253 This->DriverBindingHandle,\r
254 Controller,\r
255 EFI_OPEN_PROTOCOL_BY_DRIVER\r
256 );\r
257 if (EFI_ERROR (Status)) {\r
9b38ff34 258 FreePool (ScsiDiskDevice);\r
6ad55b15 259 return Status;\r
260 }\r
261\r
b6e5da19
HW
262 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;\r
263 ScsiDiskDevice->ScsiIo = ScsiIo;\r
264 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION3;\r
265 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;\r
266 ScsiDiskDevice->BlkIo.Media->IoAlign = ScsiIo->IoAlign;\r
267 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;\r
268 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;\r
269 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;\r
270 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;\r
271 ScsiDiskDevice->BlkIo2.Media = &ScsiDiskDevice->BlkIoMedia;\r
272 ScsiDiskDevice->BlkIo2.Reset = ScsiDiskResetEx;\r
273 ScsiDiskDevice->BlkIo2.ReadBlocksEx = ScsiDiskReadBlocksEx;\r
274 ScsiDiskDevice->BlkIo2.WriteBlocksEx = ScsiDiskWriteBlocksEx;\r
275 ScsiDiskDevice->BlkIo2.FlushBlocksEx = ScsiDiskFlushBlocksEx;\r
ac81789c
CZ
276 ScsiDiskDevice->StorageSecurity.ReceiveData = ScsiDiskReceiveData;\r
277 ScsiDiskDevice->StorageSecurity.SendData = ScsiDiskSendData;\r
b6e5da19
HW
278 ScsiDiskDevice->EraseBlock.Revision = EFI_ERASE_BLOCK_PROTOCOL_REVISION;\r
279 ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;\r
280 ScsiDiskDevice->EraseBlock.EraseBlocks = ScsiDiskEraseBlocks;\r
281 ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt = 1;\r
282 ScsiDiskDevice->BlockLimitsVpdSupported = FALSE;\r
283 ScsiDiskDevice->Handle = Controller;\r
284 InitializeListHead (&ScsiDiskDevice->AsyncTaskQueue);\r
6ad55b15 285\r
286 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));\r
287 switch (ScsiDiskDevice->DeviceType) {\r
1436aea4
MK
288 case EFI_SCSI_TYPE_DISK:\r
289 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
290 MustReadCapacity = TRUE;\r
291 break;\r
6ad55b15 292\r
1436aea4
MK
293 case EFI_SCSI_TYPE_CDROM:\r
294 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
295 ScsiDiskDevice->BlkIo.Media->ReadOnly = TRUE;\r
296 MustReadCapacity = FALSE;\r
297 break;\r
ac81789c 298\r
1436aea4
MK
299 case EFI_SCSI_TYPE_WLUN:\r
300 MustReadCapacity = FALSE;\r
301 break;\r
6ad55b15 302 }\r
1436aea4 303\r
6ad55b15 304 //\r
305 // The Sense Data Array's initial size is 6\r
306 //\r
307 ScsiDiskDevice->SenseDataNumber = 6;\r
1436aea4
MK
308 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *)AllocateZeroPool (\r
309 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber\r
310 );\r
9b38ff34 311 if (ScsiDiskDevice->SenseData == NULL) {\r
6ad55b15 312 gBS->CloseProtocol (\r
1436aea4
MK
313 Controller,\r
314 &gEfiScsiIoProtocolGuid,\r
315 This->DriverBindingHandle,\r
316 Controller\r
317 );\r
9b38ff34 318 FreePool (ScsiDiskDevice);\r
319 return EFI_OUT_OF_RESOURCES;\r
6ad55b15 320 }\r
321\r
6ad55b15 322 //\r
dfe687ca 323 // Retrieve device information\r
6ad55b15 324 //\r
325 MaxRetry = 2;\r
326 for (Index = 0; Index < MaxRetry; Index++) {\r
327 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);\r
328 if (!EFI_ERROR (Status)) {\r
329 break;\r
330 }\r
331\r
332 if (!NeedRetry) {\r
9b38ff34 333 FreePool (ScsiDiskDevice->SenseData);\r
6ad55b15 334 gBS->CloseProtocol (\r
f36d6e66 335 Controller,\r
336 &gEfiScsiIoProtocolGuid,\r
337 This->DriverBindingHandle,\r
338 Controller\r
339 );\r
9b38ff34 340 FreePool (ScsiDiskDevice);\r
6ad55b15 341 return EFI_DEVICE_ERROR;\r
342 }\r
343 }\r
1436aea4 344\r
6ad55b15 345 //\r
346 // The second parameter "TRUE" means must\r
347 // retrieve media capacity\r
348 //\r
cbd2a4b3 349 Status = ScsiDiskDetectMedia (ScsiDiskDevice, MustReadCapacity, &Temp);\r
6ad55b15 350 if (!EFI_ERROR (Status)) {\r
d14faa52 351 //\r
d670bf53
HW
352 // Determine if Block IO & Block IO2 should be produced on this controller\r
353 // handle\r
d14faa52 354 //\r
ac81789c
CZ
355 if (DetermineInstallBlockIo (Controller)) {\r
356 InitializeInstallDiskInfo (ScsiDiskDevice, Controller);\r
d14faa52 357 Status = gBS->InstallMultipleProtocolInterfaces (\r
358 &Controller,\r
359 &gEfiBlockIoProtocolGuid,\r
360 &ScsiDiskDevice->BlkIo,\r
d670bf53
HW
361 &gEfiBlockIo2ProtocolGuid,\r
362 &ScsiDiskDevice->BlkIo2,\r
d716651f 363 &gEfiDiskInfoProtocolGuid,\r
364 &ScsiDiskDevice->DiskInfo,\r
d14faa52 365 NULL\r
366 );\r
ac81789c
CZ
367 if (!EFI_ERROR (Status)) {\r
368 if (DetermineInstallEraseBlock (ScsiDiskDevice, Controller)) {\r
b6e5da19
HW
369 Status = gBS->InstallProtocolInterface (\r
370 &Controller,\r
371 &gEfiEraseBlockProtocolGuid,\r
372 EFI_NATIVE_INTERFACE,\r
373 &ScsiDiskDevice->EraseBlock\r
374 );\r
ac81789c
CZ
375 if (EFI_ERROR (Status)) {\r
376 DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Erase Block Protocol! Status = %r\n", Status));\r
377 }\r
378 }\r
1436aea4 379\r
ac81789c
CZ
380 if (DetermineInstallStorageSecurity (ScsiDiskDevice, Controller)) {\r
381 Status = gBS->InstallProtocolInterface (\r
382 &Controller,\r
383 &gEfiStorageSecurityCommandProtocolGuid,\r
384 EFI_NATIVE_INTERFACE,\r
385 &ScsiDiskDevice->StorageSecurity\r
386 );\r
387 if (EFI_ERROR (Status)) {\r
388 DEBUG ((DEBUG_ERROR, "ScsiDisk: Failed to install the Storage Security Command Protocol! Status = %r\n", Status));\r
b6e5da19
HW
389 }\r
390 }\r
1436aea4 391\r
52199bf5
CG
392 CopyMem (\r
393 VendorStr,\r
394 &ScsiDiskDevice->InquiryData.Reserved_5_95[VENDOR_IDENTIFICATION_OFFSET],\r
395 VENDOR_IDENTIFICATION_LENGTH\r
396 );\r
397 VendorStr[VENDOR_IDENTIFICATION_LENGTH] = 0;\r
398 RemoveTrailingSpaces (VendorStr);\r
399\r
400 CopyMem (\r
401 ProductStr,\r
402 &ScsiDiskDevice->InquiryData.Reserved_5_95[PRODUCT_IDENTIFICATION_OFFSET],\r
403 PRODUCT_IDENTIFICATION_LENGTH\r
404 );\r
405 ProductStr[PRODUCT_IDENTIFICATION_LENGTH] = 0;\r
406 RemoveTrailingSpaces (ProductStr);\r
407\r
408 UnicodeSPrint (DeviceStr, sizeof (DeviceStr), L"%a %a", VendorStr, ProductStr);\r
409\r
d14faa52 410 ScsiDiskDevice->ControllerNameTable = NULL;\r
411 AddUnicodeString2 (\r
412 "eng",\r
413 gScsiDiskComponentName.SupportedLanguages,\r
414 &ScsiDiskDevice->ControllerNameTable,\r
52199bf5 415 DeviceStr,\r
d14faa52 416 TRUE\r
417 );\r
418 AddUnicodeString2 (\r
419 "en",\r
420 gScsiDiskComponentName2.SupportedLanguages,\r
421 &ScsiDiskDevice->ControllerNameTable,\r
52199bf5 422 DeviceStr,\r
d14faa52 423 FALSE\r
424 );\r
425 return EFI_SUCCESS;\r
426 }\r
d1102dba 427 }\r
6ad55b15 428 }\r
429\r
d14faa52 430 gBS->FreePool (ScsiDiskDevice->SenseData);\r
431 gBS->FreePool (ScsiDiskDevice);\r
432 gBS->CloseProtocol (\r
433 Controller,\r
434 &gEfiScsiIoProtocolGuid,\r
435 This->DriverBindingHandle,\r
436 Controller\r
437 );\r
438 return Status;\r
6ad55b15 439}\r
440\r
9beb888e 441/**\r
442 Stop this driver on ControllerHandle.\r
443\r
444 This service is called by the EFI boot service DisconnectController().\r
445 In order to make drivers as small as possible, there are a few calling\r
446 restrictions for this service. DisconnectController() must follow these\r
447 calling restrictions. If any other agent wishes to call Stop() it must\r
448 also follow these calling restrictions.\r
d1102dba 449\r
9beb888e 450 @param This Protocol instance pointer.\r
451 @param ControllerHandle Handle of device to stop driver on\r
452 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
453 children is zero stop the entire bus driver.\r
454 @param ChildHandleBuffer List of Child Handles to Stop.\r
455\r
456 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
457 @retval other This driver was not removed from this device\r
458\r
459**/\r
6ad55b15 460EFI_STATUS\r
461EFIAPI\r
462ScsiDiskDriverBindingStop (\r
1436aea4
MK
463 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
464 IN EFI_HANDLE Controller,\r
465 IN UINTN NumberOfChildren,\r
466 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
6ad55b15 467 )\r
6ad55b15 468{\r
1436aea4
MK
469 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
470 EFI_ERASE_BLOCK_PROTOCOL *EraseBlock;\r
471 SCSI_DISK_DEV *ScsiDiskDevice;\r
472 EFI_STATUS Status;\r
6ad55b15 473\r
474 Status = gBS->OpenProtocol (\r
475 Controller,\r
476 &gEfiBlockIoProtocolGuid,\r
1436aea4 477 (VOID **)&BlkIo,\r
6ad55b15 478 This->DriverBindingHandle,\r
479 Controller,\r
480 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
481 );\r
482 if (EFI_ERROR (Status)) {\r
483 return Status;\r
484 }\r
485\r
d670bf53
HW
486 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (BlkIo);\r
487\r
488 //\r
489 // Wait for the BlockIo2 requests queue to become empty\r
490 //\r
1436aea4
MK
491 while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue)) {\r
492 }\r
b6e5da19
HW
493\r
494 //\r
495 // If Erase Block Protocol is installed, then uninstall this protocol.\r
496 //\r
497 Status = gBS->OpenProtocol (\r
498 Controller,\r
499 &gEfiEraseBlockProtocolGuid,\r
1436aea4 500 (VOID **)&EraseBlock,\r
b6e5da19
HW
501 This->DriverBindingHandle,\r
502 Controller,\r
503 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
504 );\r
505\r
506 if (!EFI_ERROR (Status)) {\r
507 Status = gBS->UninstallProtocolInterface (\r
508 Controller,\r
509 &gEfiEraseBlockProtocolGuid,\r
510 &ScsiDiskDevice->EraseBlock\r
511 );\r
512 if (EFI_ERROR (Status)) {\r
513 return Status;\r
514 }\r
515 }\r
d670bf53 516\r
d716651f 517 Status = gBS->UninstallMultipleProtocolInterfaces (\r
6ad55b15 518 Controller,\r
519 &gEfiBlockIoProtocolGuid,\r
d716651f 520 &ScsiDiskDevice->BlkIo,\r
d670bf53
HW
521 &gEfiBlockIo2ProtocolGuid,\r
522 &ScsiDiskDevice->BlkIo2,\r
d716651f 523 &gEfiDiskInfoProtocolGuid,\r
524 &ScsiDiskDevice->DiskInfo,\r
525 NULL\r
6ad55b15 526 );\r
527 if (!EFI_ERROR (Status)) {\r
528 gBS->CloseProtocol (\r
f36d6e66 529 Controller,\r
530 &gEfiScsiIoProtocolGuid,\r
531 This->DriverBindingHandle,\r
532 Controller\r
533 );\r
6ad55b15 534\r
535 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);\r
536\r
537 return EFI_SUCCESS;\r
538 }\r
1436aea4 539\r
6ad55b15 540 //\r
541 // errors met\r
542 //\r
543 return Status;\r
544}\r
545\r
9beb888e 546/**\r
547 Reset SCSI Disk.\r
548\r
6ad55b15 549\r
9beb888e 550 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
551 @param ExtendedVerification The flag about if extend verificate\r
552\r
553 @retval EFI_SUCCESS The device was reset.\r
554 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
555 not be reset.\r
d716651f 556 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
9beb888e 557\r
558**/\r
6ad55b15 559EFI_STATUS\r
560EFIAPI\r
561ScsiDiskReset (\r
1436aea4
MK
562 IN EFI_BLOCK_IO_PROTOCOL *This,\r
563 IN BOOLEAN ExtendedVerification\r
6ad55b15 564 )\r
6ad55b15 565{\r
1436aea4
MK
566 EFI_TPL OldTpl;\r
567 SCSI_DISK_DEV *ScsiDiskDevice;\r
568 EFI_STATUS Status;\r
6ad55b15 569\r
570 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
571\r
1436aea4 572 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);\r
6ad55b15 573\r
1436aea4 574 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
6ad55b15 575\r
c6e797ae 576 if (EFI_ERROR (Status)) {\r
ef952129
HW
577 if (Status == EFI_UNSUPPORTED) {\r
578 Status = EFI_SUCCESS;\r
579 } else {\r
580 Status = EFI_DEVICE_ERROR;\r
581 goto Done;\r
582 }\r
c6e797ae 583 }\r
584\r
6ad55b15 585 if (!ExtendedVerification) {\r
586 goto Done;\r
587 }\r
588\r
589 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
590\r
c6e797ae 591 if (EFI_ERROR (Status)) {\r
592 Status = EFI_DEVICE_ERROR;\r
593 goto Done;\r
594 }\r
595\r
6ad55b15 596Done:\r
597 gBS->RestoreTPL (OldTpl);\r
598 return Status;\r
599}\r
600\r
9beb888e 601/**\r
602 The function is to Read Block from SCSI Disk.\r
603\r
604 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
605 @param MediaId The Id of Media detected\r
606 @param Lba The logic block address\r
607 @param BufferSize The size of Buffer\r
608 @param Buffer The buffer to fill the read out data\r
609\r
610 @retval EFI_SUCCESS Successfully to read out block.\r
611 @retval EFI_DEVICE_ERROR Fail to detect media.\r
612 @retval EFI_NO_MEDIA Media is not present.\r
613 @retval EFI_MEDIA_CHANGED Media has changed.\r
614 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
615 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
616\r
617**/\r
6ad55b15 618EFI_STATUS\r
619EFIAPI\r
620ScsiDiskReadBlocks (\r
1436aea4
MK
621 IN EFI_BLOCK_IO_PROTOCOL *This,\r
622 IN UINT32 MediaId,\r
623 IN EFI_LBA Lba,\r
624 IN UINTN BufferSize,\r
625 OUT VOID *Buffer\r
6ad55b15 626 )\r
6ad55b15 627{\r
628 SCSI_DISK_DEV *ScsiDiskDevice;\r
629 EFI_BLOCK_IO_MEDIA *Media;\r
630 EFI_STATUS Status;\r
631 UINTN BlockSize;\r
632 UINTN NumberOfBlocks;\r
633 BOOLEAN MediaChange;\r
634 EFI_TPL OldTpl;\r
635\r
fcf5e49d
RN
636 MediaChange = FALSE;\r
637 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
d670bf53 638 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);\r
3c12f346 639 Media = ScsiDiskDevice->BlkIo.Media;\r
6ad55b15 640\r
1436aea4 641 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
6ad55b15 642 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
643 if (EFI_ERROR (Status)) {\r
644 Status = EFI_DEVICE_ERROR;\r
645 goto Done;\r
646 }\r
647\r
648 if (MediaChange) {\r
649 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
650 ScsiDiskDevice->Handle,\r
651 &gEfiBlockIoProtocolGuid,\r
652 &ScsiDiskDevice->BlkIo,\r
653 &ScsiDiskDevice->BlkIo\r
654 );\r
d670bf53
HW
655 gBS->ReinstallProtocolInterface (\r
656 ScsiDiskDevice->Handle,\r
657 &gEfiBlockIo2ProtocolGuid,\r
658 &ScsiDiskDevice->BlkIo2,\r
659 &ScsiDiskDevice->BlkIo2\r
660 );\r
ac81789c 661 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
b6e5da19
HW
662 gBS->ReinstallProtocolInterface (\r
663 ScsiDiskDevice->Handle,\r
664 &gEfiEraseBlockProtocolGuid,\r
665 &ScsiDiskDevice->EraseBlock,\r
666 &ScsiDiskDevice->EraseBlock\r
667 );\r
668 }\r
1436aea4 669\r
ac81789c
CZ
670 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
671 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
672 ScsiDiskDevice->Handle,\r
673 &gEfiStorageSecurityCommandProtocolGuid,\r
674 &ScsiDiskDevice->StorageSecurity,\r
675 &ScsiDiskDevice->StorageSecurity\r
676 );\r
ac81789c 677 }\r
1436aea4 678\r
3c12f346
RN
679 if (Media->MediaPresent) {\r
680 Status = EFI_MEDIA_CHANGED;\r
681 } else {\r
682 Status = EFI_NO_MEDIA;\r
683 }\r
1436aea4 684\r
9c922525 685 goto Done;\r
6ad55b15 686 }\r
687 }\r
1436aea4 688\r
6ad55b15 689 //\r
690 // Get the intrinsic block size\r
691 //\r
1436aea4 692 BlockSize = Media->BlockSize;\r
6ad55b15 693\r
ac81789c
CZ
694 if (BlockSize == 0) {\r
695 Status = EFI_DEVICE_ERROR;\r
696 goto Done;\r
697 }\r
698\r
1436aea4 699 NumberOfBlocks = BufferSize / BlockSize;\r
6ad55b15 700\r
701 if (!(Media->MediaPresent)) {\r
702 Status = EFI_NO_MEDIA;\r
703 goto Done;\r
704 }\r
705\r
706 if (MediaId != Media->MediaId) {\r
707 Status = EFI_MEDIA_CHANGED;\r
708 goto Done;\r
709 }\r
710\r
fcf5e49d
RN
711 if (Buffer == NULL) {\r
712 Status = EFI_INVALID_PARAMETER;\r
713 goto Done;\r
714 }\r
715\r
716 if (BufferSize == 0) {\r
717 Status = EFI_SUCCESS;\r
718 goto Done;\r
719 }\r
720\r
6ad55b15 721 if (BufferSize % BlockSize != 0) {\r
722 Status = EFI_BAD_BUFFER_SIZE;\r
723 goto Done;\r
724 }\r
725\r
9beb888e 726 if (Lba > Media->LastBlock) {\r
6ad55b15 727 Status = EFI_INVALID_PARAMETER;\r
728 goto Done;\r
729 }\r
730\r
9beb888e 731 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
6ad55b15 732 Status = EFI_INVALID_PARAMETER;\r
733 goto Done;\r
734 }\r
735\r
1436aea4 736 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {\r
6ad55b15 737 Status = EFI_INVALID_PARAMETER;\r
738 goto Done;\r
739 }\r
f36d6e66 740\r
6ad55b15 741 //\r
f36d6e66 742 // If all the parameters are valid, then perform read sectors command\r
6ad55b15 743 // to transfer data from device to host.\r
744 //\r
9beb888e 745 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
6ad55b15 746\r
747Done:\r
748 gBS->RestoreTPL (OldTpl);\r
749 return Status;\r
750}\r
751\r
9beb888e 752/**\r
753 The function is to Write Block to SCSI Disk.\r
754\r
755 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
756 @param MediaId The Id of Media detected\r
757 @param Lba The logic block address\r
758 @param BufferSize The size of Buffer\r
759 @param Buffer The buffer to fill the read out data\r
760\r
761 @retval EFI_SUCCESS Successfully to read out block.\r
762 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
763 @retval EFI_DEVICE_ERROR Fail to detect media.\r
764 @retval EFI_NO_MEDIA Media is not present.\r
cc530cd1 765 @retval EFI_MEDIA_CHANGED Media has changed.\r
9beb888e 766 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
767 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
768\r
769**/\r
6ad55b15 770EFI_STATUS\r
771EFIAPI\r
772ScsiDiskWriteBlocks (\r
1436aea4
MK
773 IN EFI_BLOCK_IO_PROTOCOL *This,\r
774 IN UINT32 MediaId,\r
775 IN EFI_LBA Lba,\r
776 IN UINTN BufferSize,\r
777 IN VOID *Buffer\r
6ad55b15 778 )\r
6ad55b15 779{\r
780 SCSI_DISK_DEV *ScsiDiskDevice;\r
781 EFI_BLOCK_IO_MEDIA *Media;\r
782 EFI_STATUS Status;\r
783 UINTN BlockSize;\r
784 UINTN NumberOfBlocks;\r
785 BOOLEAN MediaChange;\r
786 EFI_TPL OldTpl;\r
787\r
fcf5e49d
RN
788 MediaChange = FALSE;\r
789 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
d670bf53 790 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO (This);\r
3c12f346 791 Media = ScsiDiskDevice->BlkIo.Media;\r
6ad55b15 792\r
1436aea4 793 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
6ad55b15 794 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
795 if (EFI_ERROR (Status)) {\r
796 Status = EFI_DEVICE_ERROR;\r
797 goto Done;\r
798 }\r
799\r
800 if (MediaChange) {\r
801 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
802 ScsiDiskDevice->Handle,\r
803 &gEfiBlockIoProtocolGuid,\r
804 &ScsiDiskDevice->BlkIo,\r
805 &ScsiDiskDevice->BlkIo\r
806 );\r
d670bf53
HW
807 gBS->ReinstallProtocolInterface (\r
808 ScsiDiskDevice->Handle,\r
809 &gEfiBlockIo2ProtocolGuid,\r
810 &ScsiDiskDevice->BlkIo2,\r
811 &ScsiDiskDevice->BlkIo2\r
812 );\r
ac81789c 813 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
b6e5da19
HW
814 gBS->ReinstallProtocolInterface (\r
815 ScsiDiskDevice->Handle,\r
816 &gEfiEraseBlockProtocolGuid,\r
817 &ScsiDiskDevice->EraseBlock,\r
818 &ScsiDiskDevice->EraseBlock\r
819 );\r
820 }\r
1436aea4 821\r
ac81789c
CZ
822 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
823 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
824 ScsiDiskDevice->Handle,\r
825 &gEfiStorageSecurityCommandProtocolGuid,\r
826 &ScsiDiskDevice->StorageSecurity,\r
827 &ScsiDiskDevice->StorageSecurity\r
828 );\r
ac81789c 829 }\r
1436aea4 830\r
3c12f346
RN
831 if (Media->MediaPresent) {\r
832 Status = EFI_MEDIA_CHANGED;\r
833 } else {\r
834 Status = EFI_NO_MEDIA;\r
835 }\r
1436aea4 836\r
9c922525 837 goto Done;\r
6ad55b15 838 }\r
839 }\r
1436aea4 840\r
6ad55b15 841 //\r
842 // Get the intrinsic block size\r
843 //\r
1436aea4 844 BlockSize = Media->BlockSize;\r
6ad55b15 845\r
ac81789c
CZ
846 if (BlockSize == 0) {\r
847 Status = EFI_DEVICE_ERROR;\r
848 goto Done;\r
849 }\r
850\r
1436aea4 851 NumberOfBlocks = BufferSize / BlockSize;\r
6ad55b15 852\r
853 if (!(Media->MediaPresent)) {\r
854 Status = EFI_NO_MEDIA;\r
855 goto Done;\r
856 }\r
857\r
858 if (MediaId != Media->MediaId) {\r
859 Status = EFI_MEDIA_CHANGED;\r
860 goto Done;\r
861 }\r
862\r
40b0f96f
HW
863 if (Media->ReadOnly) {\r
864 Status = EFI_WRITE_PROTECTED;\r
865 goto Done;\r
866 }\r
867\r
fcf5e49d
RN
868 if (BufferSize == 0) {\r
869 Status = EFI_SUCCESS;\r
870 goto Done;\r
871 }\r
872\r
873 if (Buffer == NULL) {\r
874 Status = EFI_INVALID_PARAMETER;\r
875 goto Done;\r
876 }\r
877\r
6ad55b15 878 if (BufferSize % BlockSize != 0) {\r
879 Status = EFI_BAD_BUFFER_SIZE;\r
880 goto Done;\r
881 }\r
882\r
9beb888e 883 if (Lba > Media->LastBlock) {\r
6ad55b15 884 Status = EFI_INVALID_PARAMETER;\r
885 goto Done;\r
886 }\r
887\r
9beb888e 888 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
6ad55b15 889 Status = EFI_INVALID_PARAMETER;\r
890 goto Done;\r
891 }\r
892\r
1436aea4 893 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {\r
6ad55b15 894 Status = EFI_INVALID_PARAMETER;\r
895 goto Done;\r
896 }\r
1436aea4 897\r
6ad55b15 898 //\r
899 // if all the parameters are valid, then perform read sectors command\r
900 // to transfer data from device to host.\r
901 //\r
9beb888e 902 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
6ad55b15 903\r
904Done:\r
905 gBS->RestoreTPL (OldTpl);\r
6ad55b15 906 return Status;\r
907}\r
908\r
9beb888e 909/**\r
910 Flush Block to Disk.\r
911\r
912 EFI_SUCCESS is returned directly.\r
913\r
914 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
915\r
916 @retval EFI_SUCCESS All outstanding data was written to the device\r
917\r
918**/\r
6ad55b15 919EFI_STATUS\r
920EFIAPI\r
921ScsiDiskFlushBlocks (\r
1436aea4 922 IN EFI_BLOCK_IO_PROTOCOL *This\r
6ad55b15 923 )\r
6ad55b15 924{\r
925 //\r
926 // return directly\r
927 //\r
928 return EFI_SUCCESS;\r
929}\r
930\r
d670bf53
HW
931/**\r
932 Reset SCSI Disk.\r
933\r
934 @param This The pointer of EFI_BLOCK_IO2_PROTOCOL.\r
935 @param ExtendedVerification The flag about if extend verificate.\r
936\r
937 @retval EFI_SUCCESS The device was reset.\r
938 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
939 not be reset.\r
940 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
941\r
942**/\r
943EFI_STATUS\r
944EFIAPI\r
945ScsiDiskResetEx (\r
946 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
947 IN BOOLEAN ExtendedVerification\r
948 )\r
949{\r
1436aea4
MK
950 EFI_TPL OldTpl;\r
951 SCSI_DISK_DEV *ScsiDiskDevice;\r
952 EFI_STATUS Status;\r
d670bf53
HW
953\r
954 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
955\r
1436aea4 956 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
d670bf53 957\r
1436aea4 958 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
d670bf53
HW
959\r
960 if (EFI_ERROR (Status)) {\r
ef952129
HW
961 if (Status == EFI_UNSUPPORTED) {\r
962 Status = EFI_SUCCESS;\r
963 } else {\r
964 Status = EFI_DEVICE_ERROR;\r
965 goto Done;\r
966 }\r
d670bf53
HW
967 }\r
968\r
969 if (!ExtendedVerification) {\r
970 goto Done;\r
971 }\r
972\r
973 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
974\r
975 if (EFI_ERROR (Status)) {\r
976 Status = EFI_DEVICE_ERROR;\r
977 goto Done;\r
978 }\r
979\r
980Done:\r
981 gBS->RestoreTPL (OldTpl);\r
982 return Status;\r
983}\r
984\r
985/**\r
986 The function is to Read Block from SCSI Disk.\r
987\r
988 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
989 @param MediaId The Id of Media detected.\r
990 @param Lba The logic block address.\r
991 @param Token A pointer to the token associated with the transaction.\r
992 @param BufferSize The size of Buffer.\r
993 @param Buffer The buffer to fill the read out data.\r
994\r
995 @retval EFI_SUCCESS The read request was queued if Token-> Event is\r
996 not NULL. The data was read correctly from the\r
997 device if theToken-> Event is NULL.\r
998 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
999 to perform the read operation.\r
1000 @retval EFI_NO_MEDIA There is no media in the device.\r
1001 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1002 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
1003 the intrinsic block size of the device.\r
1004 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not\r
1005 valid, or the buffer is not on proper\r
1006 alignment.\r
1007 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
1008 lack of resources.\r
1009\r
1010**/\r
1011EFI_STATUS\r
1012EFIAPI\r
1013ScsiDiskReadBlocksEx (\r
1436aea4
MK
1014 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1015 IN UINT32 MediaId,\r
1016 IN EFI_LBA Lba,\r
1017 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
1018 IN UINTN BufferSize,\r
1019 OUT VOID *Buffer\r
d670bf53
HW
1020 )\r
1021{\r
1022 SCSI_DISK_DEV *ScsiDiskDevice;\r
1023 EFI_BLOCK_IO_MEDIA *Media;\r
1024 EFI_STATUS Status;\r
1025 UINTN BlockSize;\r
1026 UINTN NumberOfBlocks;\r
1027 BOOLEAN MediaChange;\r
1028 EFI_TPL OldTpl;\r
1029\r
1030 MediaChange = FALSE;\r
1031 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1032 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
3c12f346 1033 Media = ScsiDiskDevice->BlkIo.Media;\r
d670bf53 1034\r
1436aea4 1035 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
d670bf53
HW
1036 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
1037 if (EFI_ERROR (Status)) {\r
1038 Status = EFI_DEVICE_ERROR;\r
1039 goto Done;\r
1040 }\r
1041\r
1042 if (MediaChange) {\r
1043 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1044 ScsiDiskDevice->Handle,\r
1045 &gEfiBlockIoProtocolGuid,\r
1046 &ScsiDiskDevice->BlkIo,\r
1047 &ScsiDiskDevice->BlkIo\r
1048 );\r
d670bf53
HW
1049 gBS->ReinstallProtocolInterface (\r
1050 ScsiDiskDevice->Handle,\r
1051 &gEfiBlockIo2ProtocolGuid,\r
1052 &ScsiDiskDevice->BlkIo2,\r
1053 &ScsiDiskDevice->BlkIo2\r
1054 );\r
ac81789c 1055 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
b6e5da19
HW
1056 gBS->ReinstallProtocolInterface (\r
1057 ScsiDiskDevice->Handle,\r
1058 &gEfiEraseBlockProtocolGuid,\r
1059 &ScsiDiskDevice->EraseBlock,\r
1060 &ScsiDiskDevice->EraseBlock\r
1061 );\r
1062 }\r
1436aea4 1063\r
ac81789c
CZ
1064 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
1065 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1066 ScsiDiskDevice->Handle,\r
1067 &gEfiStorageSecurityCommandProtocolGuid,\r
1068 &ScsiDiskDevice->StorageSecurity,\r
1069 &ScsiDiskDevice->StorageSecurity\r
1070 );\r
ac81789c 1071 }\r
1436aea4 1072\r
3c12f346
RN
1073 if (Media->MediaPresent) {\r
1074 Status = EFI_MEDIA_CHANGED;\r
1075 } else {\r
1076 Status = EFI_NO_MEDIA;\r
1077 }\r
1436aea4 1078\r
d670bf53
HW
1079 goto Done;\r
1080 }\r
1081 }\r
1436aea4 1082\r
d670bf53
HW
1083 //\r
1084 // Get the intrinsic block size\r
1085 //\r
1436aea4 1086 BlockSize = Media->BlockSize;\r
d670bf53 1087\r
ac81789c
CZ
1088 if (BlockSize == 0) {\r
1089 Status = EFI_DEVICE_ERROR;\r
1090 goto Done;\r
1091 }\r
1092\r
1436aea4 1093 NumberOfBlocks = BufferSize / BlockSize;\r
d670bf53
HW
1094\r
1095 if (!(Media->MediaPresent)) {\r
1096 Status = EFI_NO_MEDIA;\r
1097 goto Done;\r
1098 }\r
1099\r
1100 if (MediaId != Media->MediaId) {\r
1101 Status = EFI_MEDIA_CHANGED;\r
1102 goto Done;\r
1103 }\r
1104\r
1105 if (Buffer == NULL) {\r
1106 Status = EFI_INVALID_PARAMETER;\r
1107 goto Done;\r
1108 }\r
1109\r
1110 if (BufferSize == 0) {\r
1111 if ((Token != NULL) && (Token->Event != NULL)) {\r
1112 Token->TransactionStatus = EFI_SUCCESS;\r
1113 gBS->SignalEvent (Token->Event);\r
1114 }\r
1115\r
1116 Status = EFI_SUCCESS;\r
1117 goto Done;\r
1118 }\r
1119\r
1120 if (BufferSize % BlockSize != 0) {\r
1121 Status = EFI_BAD_BUFFER_SIZE;\r
1122 goto Done;\r
1123 }\r
1124\r
1125 if (Lba > Media->LastBlock) {\r
1126 Status = EFI_INVALID_PARAMETER;\r
1127 goto Done;\r
1128 }\r
1129\r
1130 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
1131 Status = EFI_INVALID_PARAMETER;\r
1132 goto Done;\r
1133 }\r
1134\r
1436aea4 1135 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {\r
d670bf53
HW
1136 Status = EFI_INVALID_PARAMETER;\r
1137 goto Done;\r
1138 }\r
1139\r
1140 //\r
1141 // If all the parameters are valid, then perform read sectors command\r
1142 // to transfer data from device to host.\r
1143 //\r
1144 if ((Token != NULL) && (Token->Event != NULL)) {\r
1145 Token->TransactionStatus = EFI_SUCCESS;\r
1436aea4
MK
1146 Status = ScsiDiskAsyncReadSectors (\r
1147 ScsiDiskDevice,\r
1148 Buffer,\r
1149 Lba,\r
1150 NumberOfBlocks,\r
1151 Token\r
1152 );\r
d670bf53
HW
1153 } else {\r
1154 Status = ScsiDiskReadSectors (\r
1155 ScsiDiskDevice,\r
1156 Buffer,\r
1157 Lba,\r
1158 NumberOfBlocks\r
1159 );\r
1160 }\r
1161\r
1162Done:\r
1163 gBS->RestoreTPL (OldTpl);\r
1164 return Status;\r
1165}\r
1166\r
1167/**\r
1168 The function is to Write Block to SCSI Disk.\r
1169\r
1170 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
1171 @param MediaId The Id of Media detected.\r
1172 @param Lba The logic block address.\r
1173 @param Token A pointer to the token associated with the transaction.\r
1174 @param BufferSize The size of Buffer.\r
1175 @param Buffer The buffer to fill the read out data.\r
1176\r
1177 @retval EFI_SUCCESS The data were written correctly to the device.\r
1178 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1179 @retval EFI_NO_MEDIA There is no media in the device.\r
1180 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1181 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
1182 to perform the write operation.\r
1183 @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of\r
1184 the intrinsic block size of the device.\r
1185 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not\r
1186 valid, or the buffer is not on proper\r
1187 alignment.\r
1188\r
1189**/\r
1190EFI_STATUS\r
1191EFIAPI\r
1192ScsiDiskWriteBlocksEx (\r
1436aea4
MK
1193 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1194 IN UINT32 MediaId,\r
1195 IN EFI_LBA Lba,\r
1196 IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r
1197 IN UINTN BufferSize,\r
1198 IN VOID *Buffer\r
d670bf53
HW
1199 )\r
1200{\r
1201 SCSI_DISK_DEV *ScsiDiskDevice;\r
1202 EFI_BLOCK_IO_MEDIA *Media;\r
1203 EFI_STATUS Status;\r
1204 UINTN BlockSize;\r
1205 UINTN NumberOfBlocks;\r
1206 BOOLEAN MediaChange;\r
1207 EFI_TPL OldTpl;\r
1208\r
1209 MediaChange = FALSE;\r
1210 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1211 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
3c12f346 1212 Media = ScsiDiskDevice->BlkIo.Media;\r
d670bf53 1213\r
1436aea4 1214 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
d670bf53
HW
1215 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
1216 if (EFI_ERROR (Status)) {\r
1217 Status = EFI_DEVICE_ERROR;\r
1218 goto Done;\r
1219 }\r
1220\r
1221 if (MediaChange) {\r
1222 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1223 ScsiDiskDevice->Handle,\r
1224 &gEfiBlockIoProtocolGuid,\r
1225 &ScsiDiskDevice->BlkIo,\r
1226 &ScsiDiskDevice->BlkIo\r
1227 );\r
d670bf53
HW
1228 gBS->ReinstallProtocolInterface (\r
1229 ScsiDiskDevice->Handle,\r
1230 &gEfiBlockIo2ProtocolGuid,\r
1231 &ScsiDiskDevice->BlkIo2,\r
1232 &ScsiDiskDevice->BlkIo2\r
1233 );\r
ac81789c 1234 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
b6e5da19
HW
1235 gBS->ReinstallProtocolInterface (\r
1236 ScsiDiskDevice->Handle,\r
1237 &gEfiEraseBlockProtocolGuid,\r
1238 &ScsiDiskDevice->EraseBlock,\r
1239 &ScsiDiskDevice->EraseBlock\r
1240 );\r
1241 }\r
1436aea4 1242\r
ac81789c
CZ
1243 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
1244 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1245 ScsiDiskDevice->Handle,\r
1246 &gEfiStorageSecurityCommandProtocolGuid,\r
1247 &ScsiDiskDevice->StorageSecurity,\r
1248 &ScsiDiskDevice->StorageSecurity\r
1249 );\r
ac81789c 1250 }\r
1436aea4 1251\r
3c12f346
RN
1252 if (Media->MediaPresent) {\r
1253 Status = EFI_MEDIA_CHANGED;\r
1254 } else {\r
1255 Status = EFI_NO_MEDIA;\r
1256 }\r
1436aea4 1257\r
d670bf53
HW
1258 goto Done;\r
1259 }\r
1260 }\r
1436aea4 1261\r
d670bf53
HW
1262 //\r
1263 // Get the intrinsic block size\r
1264 //\r
1436aea4 1265 BlockSize = Media->BlockSize;\r
d670bf53 1266\r
ac81789c
CZ
1267 if (BlockSize == 0) {\r
1268 Status = EFI_DEVICE_ERROR;\r
1269 goto Done;\r
1270 }\r
1271\r
1436aea4 1272 NumberOfBlocks = BufferSize / BlockSize;\r
d670bf53
HW
1273\r
1274 if (!(Media->MediaPresent)) {\r
1275 Status = EFI_NO_MEDIA;\r
1276 goto Done;\r
1277 }\r
1278\r
1279 if (MediaId != Media->MediaId) {\r
1280 Status = EFI_MEDIA_CHANGED;\r
1281 goto Done;\r
1282 }\r
1283\r
40b0f96f
HW
1284 if (Media->ReadOnly) {\r
1285 Status = EFI_WRITE_PROTECTED;\r
1286 goto Done;\r
1287 }\r
1288\r
d670bf53
HW
1289 if (BufferSize == 0) {\r
1290 if ((Token != NULL) && (Token->Event != NULL)) {\r
1291 Token->TransactionStatus = EFI_SUCCESS;\r
1292 gBS->SignalEvent (Token->Event);\r
1293 }\r
1294\r
1295 Status = EFI_SUCCESS;\r
1296 goto Done;\r
1297 }\r
1298\r
1299 if (Buffer == NULL) {\r
1300 Status = EFI_INVALID_PARAMETER;\r
1301 goto Done;\r
1302 }\r
1303\r
1304 if (BufferSize % BlockSize != 0) {\r
1305 Status = EFI_BAD_BUFFER_SIZE;\r
1306 goto Done;\r
1307 }\r
1308\r
1309 if (Lba > Media->LastBlock) {\r
1310 Status = EFI_INVALID_PARAMETER;\r
1311 goto Done;\r
1312 }\r
1313\r
1314 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
1315 Status = EFI_INVALID_PARAMETER;\r
1316 goto Done;\r
1317 }\r
1318\r
1436aea4 1319 if ((Media->IoAlign > 1) && (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) {\r
d670bf53
HW
1320 Status = EFI_INVALID_PARAMETER;\r
1321 goto Done;\r
1322 }\r
1323\r
1324 //\r
1325 // if all the parameters are valid, then perform write sectors command\r
1326 // to transfer data from device to host.\r
1327 //\r
1328 if ((Token != NULL) && (Token->Event != NULL)) {\r
1329 Token->TransactionStatus = EFI_SUCCESS;\r
1436aea4
MK
1330 Status = ScsiDiskAsyncWriteSectors (\r
1331 ScsiDiskDevice,\r
1332 Buffer,\r
1333 Lba,\r
1334 NumberOfBlocks,\r
1335 Token\r
1336 );\r
d670bf53
HW
1337 } else {\r
1338 Status = ScsiDiskWriteSectors (\r
1339 ScsiDiskDevice,\r
1340 Buffer,\r
1341 Lba,\r
1342 NumberOfBlocks\r
1343 );\r
1344 }\r
1345\r
1346Done:\r
1347 gBS->RestoreTPL (OldTpl);\r
1348 return Status;\r
1349}\r
1350\r
1351/**\r
1352 Flush the Block Device.\r
1353\r
1354 @param This Indicates a pointer to the calling context.\r
1355 @param Token A pointer to the token associated with the transaction.\r
1356\r
7013e088
HW
1357 @retval EFI_SUCCESS All outstanding data was written to the device.\r
1358 @retval EFI_DEVICE_ERROR The device reported an error while attempting to\r
1359 write data.\r
1360 @retval EFI_WRITE_PROTECTED The device cannot be written to.\r
1361 @retval EFI_NO_MEDIA There is no media in the device.\r
1362 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
d670bf53
HW
1363\r
1364**/\r
1365EFI_STATUS\r
1366EFIAPI\r
1367ScsiDiskFlushBlocksEx (\r
1368 IN EFI_BLOCK_IO2_PROTOCOL *This,\r
1369 IN OUT EFI_BLOCK_IO2_TOKEN *Token\r
1370 )\r
1371{\r
7013e088
HW
1372 SCSI_DISK_DEV *ScsiDiskDevice;\r
1373 EFI_BLOCK_IO_MEDIA *Media;\r
1374 EFI_STATUS Status;\r
1375 BOOLEAN MediaChange;\r
1376 EFI_TPL OldTpl;\r
1377\r
1378 MediaChange = FALSE;\r
1379 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1380 ScsiDiskDevice = SCSI_DISK_DEV_FROM_BLKIO2 (This);\r
3c12f346 1381 Media = ScsiDiskDevice->BlkIo.Media;\r
7013e088 1382\r
1436aea4 1383 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
7013e088
HW
1384 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
1385 if (EFI_ERROR (Status)) {\r
1386 Status = EFI_DEVICE_ERROR;\r
1387 goto Done;\r
1388 }\r
1389\r
1390 if (MediaChange) {\r
1391 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1392 ScsiDiskDevice->Handle,\r
1393 &gEfiBlockIoProtocolGuid,\r
1394 &ScsiDiskDevice->BlkIo,\r
1395 &ScsiDiskDevice->BlkIo\r
1396 );\r
7013e088
HW
1397 gBS->ReinstallProtocolInterface (\r
1398 ScsiDiskDevice->Handle,\r
1399 &gEfiBlockIo2ProtocolGuid,\r
1400 &ScsiDiskDevice->BlkIo2,\r
1401 &ScsiDiskDevice->BlkIo2\r
1402 );\r
ac81789c 1403 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
b6e5da19
HW
1404 gBS->ReinstallProtocolInterface (\r
1405 ScsiDiskDevice->Handle,\r
1406 &gEfiEraseBlockProtocolGuid,\r
1407 &ScsiDiskDevice->EraseBlock,\r
1408 &ScsiDiskDevice->EraseBlock\r
1409 );\r
1410 }\r
1436aea4 1411\r
ac81789c
CZ
1412 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
1413 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1414 ScsiDiskDevice->Handle,\r
1415 &gEfiStorageSecurityCommandProtocolGuid,\r
1416 &ScsiDiskDevice->StorageSecurity,\r
1417 &ScsiDiskDevice->StorageSecurity\r
1418 );\r
ac81789c 1419 }\r
1436aea4 1420\r
3c12f346
RN
1421 if (Media->MediaPresent) {\r
1422 Status = EFI_MEDIA_CHANGED;\r
1423 } else {\r
1424 Status = EFI_NO_MEDIA;\r
1425 }\r
1436aea4 1426\r
7013e088
HW
1427 goto Done;\r
1428 }\r
1429 }\r
1430\r
7013e088
HW
1431 if (!(Media->MediaPresent)) {\r
1432 Status = EFI_NO_MEDIA;\r
1433 goto Done;\r
1434 }\r
1435\r
1436 if (Media->ReadOnly) {\r
1437 Status = EFI_WRITE_PROTECTED;\r
1438 goto Done;\r
1439 }\r
1440\r
d670bf53 1441 //\r
7013e088
HW
1442 // Wait for the BlockIo2 requests queue to become empty\r
1443 //\r
1436aea4
MK
1444 while (!IsListEmpty (&ScsiDiskDevice->AsyncTaskQueue)) {\r
1445 }\r
7013e088
HW
1446\r
1447 Status = EFI_SUCCESS;\r
1448\r
1449 //\r
1450 // Signal caller event\r
d670bf53
HW
1451 //\r
1452 if ((Token != NULL) && (Token->Event != NULL)) {\r
1453 Token->TransactionStatus = EFI_SUCCESS;\r
1454 gBS->SignalEvent (Token->Event);\r
1455 }\r
1456\r
7013e088
HW
1457Done:\r
1458 gBS->RestoreTPL (OldTpl);\r
1459 return Status;\r
d670bf53
HW
1460}\r
1461\r
b6e5da19
HW
1462/**\r
1463 Internal helper notify function which process the result of an asynchronous\r
1464 SCSI UNMAP Command and signal the event passed from EraseBlocks.\r
1465\r
1466 @param Event The instance of EFI_EVENT.\r
1467 @param Context The parameter passed in.\r
1468\r
1469**/\r
1470VOID\r
1471EFIAPI\r
1472ScsiDiskAsyncUnmapNotify (\r
1473 IN EFI_EVENT Event,\r
1474 IN VOID *Context\r
1475 )\r
1476{\r
1477 SCSI_ERASEBLK_REQUEST *EraseBlkReq;\r
1478 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
1479 EFI_ERASE_BLOCK_TOKEN *Token;\r
1480 EFI_STATUS Status;\r
1481\r
1482 gBS->CloseEvent (Event);\r
1483\r
1436aea4 1484 EraseBlkReq = (SCSI_ERASEBLK_REQUEST *)Context;\r
b6e5da19
HW
1485 CommandPacket = &EraseBlkReq->CommandPacket;\r
1486 Token = EraseBlkReq->Token;\r
1487 Token->TransactionStatus = EFI_SUCCESS;\r
1488\r
1489 Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);\r
1436aea4 1490 if (EFI_ERROR (Status)) {\r
b6e5da19 1491 DEBUG ((\r
87000d77 1492 DEBUG_ERROR,\r
b6e5da19
HW
1493 "ScsiDiskAsyncUnmapNotify: Host adapter indicating error status 0x%x.\n",\r
1494 CommandPacket->HostAdapterStatus\r
1495 ));\r
1496\r
1497 Token->TransactionStatus = Status;\r
1498 goto Done;\r
1499 }\r
1500\r
1501 Status = CheckTargetStatus (CommandPacket->TargetStatus);\r
1436aea4 1502 if (EFI_ERROR (Status)) {\r
b6e5da19 1503 DEBUG ((\r
87000d77 1504 DEBUG_ERROR,\r
b6e5da19
HW
1505 "ScsiDiskAsyncUnmapNotify: Target indicating error status 0x%x.\n",\r
1506 CommandPacket->HostAdapterStatus\r
1507 ));\r
1508\r
1509 Token->TransactionStatus = Status;\r
1510 goto Done;\r
1511 }\r
1512\r
1513Done:\r
1514 RemoveEntryList (&EraseBlkReq->Link);\r
1515 FreePool (CommandPacket->OutDataBuffer);\r
1516 FreePool (EraseBlkReq->CommandPacket.Cdb);\r
1517 FreePool (EraseBlkReq);\r
1518\r
1519 gBS->SignalEvent (Token->Event);\r
1520}\r
1521\r
1522/**\r
1523 Require the device server to cause one or more LBAs to be unmapped.\r
1524\r
1525 @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
1526 @param Lba The start block number.\r
1527 @param Blocks Total block number to be unmapped.\r
1528 @param Token The pointer to the token associated with the\r
1529 non-blocking erase block request.\r
1530\r
1531 @retval EFI_SUCCESS Target blocks have been successfully unmapped.\r
1532 @retval EFI_DEVICE_ERROR Fail to unmap the target blocks.\r
1533\r
1534**/\r
1535EFI_STATUS\r
1536ScsiDiskUnmap (\r
1436aea4
MK
1537 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1538 IN UINT64 Lba,\r
1539 IN UINTN Blocks,\r
1540 IN EFI_ERASE_BLOCK_TOKEN *Token OPTIONAL\r
b6e5da19
HW
1541 )\r
1542{\r
1543 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
1544 SCSI_ERASEBLK_REQUEST *EraseBlkReq;\r
1545 EFI_SCSI_IO_SCSI_REQUEST_PACKET *CommandPacket;\r
1546 EFI_SCSI_DISK_UNMAP_BLOCK_DESP *BlkDespPtr;\r
1547 EFI_STATUS Status;\r
1548 EFI_STATUS ReturnStatus;\r
1549 UINT8 *Cdb;\r
1550 UINT32 MaxLbaCnt;\r
1551 UINT32 MaxBlkDespCnt;\r
1552 UINT32 BlkDespCnt;\r
1553 UINT16 UnmapParamListLen;\r
1554 VOID *UnmapParamList;\r
1555 EFI_EVENT AsyncUnmapEvent;\r
1556 EFI_TPL OldTpl;\r
1557\r
1558 ScsiIo = ScsiDiskDevice->ScsiIo;\r
1559 MaxLbaCnt = ScsiDiskDevice->UnmapInfo.MaxLbaCnt;\r
1560 MaxBlkDespCnt = ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt;\r
1561 EraseBlkReq = NULL;\r
1562 UnmapParamList = NULL;\r
1563 AsyncUnmapEvent = NULL;\r
1564 ReturnStatus = EFI_SUCCESS;\r
1565\r
1436aea4 1566 if (Blocks / (UINTN)MaxLbaCnt > MaxBlkDespCnt) {\r
b6e5da19
HW
1567 ReturnStatus = EFI_DEVICE_ERROR;\r
1568 goto Done;\r
1569 }\r
1570\r
1571 EraseBlkReq = AllocateZeroPool (sizeof (SCSI_ERASEBLK_REQUEST));\r
1572 if (EraseBlkReq == NULL) {\r
1573 ReturnStatus = EFI_DEVICE_ERROR;\r
1574 goto Done;\r
1575 }\r
1576\r
1577 EraseBlkReq->CommandPacket.Cdb = AllocateZeroPool (0xA);\r
1578 if (EraseBlkReq->CommandPacket.Cdb == NULL) {\r
1579 ReturnStatus = EFI_DEVICE_ERROR;\r
1580 goto Done;\r
1581 }\r
1582\r
1436aea4
MK
1583 BlkDespCnt = (UINT32)((Blocks - 1) / MaxLbaCnt + 1);\r
1584 UnmapParamListLen = (UINT16)(sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER)\r
1585 + BlkDespCnt * sizeof (EFI_SCSI_DISK_UNMAP_BLOCK_DESP));\r
1586 UnmapParamList = AllocateZeroPool (UnmapParamListLen);\r
b6e5da19
HW
1587 if (UnmapParamList == NULL) {\r
1588 ReturnStatus = EFI_DEVICE_ERROR;\r
1589 goto Done;\r
1590 }\r
1591\r
1592 *((UINT16 *)UnmapParamList) = SwapBytes16 (UnmapParamListLen - 2);\r
1593 *((UINT16 *)UnmapParamList + 1) = SwapBytes16 (UnmapParamListLen - sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));\r
1594\r
1595 BlkDespPtr = (EFI_SCSI_DISK_UNMAP_BLOCK_DESP *)((UINT8 *)UnmapParamList + sizeof (EFI_SCSI_DISK_UNMAP_PARAM_LIST_HEADER));\r
1596 while (Blocks > 0) {\r
1597 if (Blocks > MaxLbaCnt) {\r
1598 *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);\r
1599 *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 (MaxLbaCnt);\r
1436aea4
MK
1600 Blocks -= MaxLbaCnt;\r
1601 Lba += MaxLbaCnt;\r
b6e5da19
HW
1602 } else {\r
1603 *(UINT64 *)(&BlkDespPtr->Lba) = SwapBytes64 (Lba);\r
1436aea4
MK
1604 *(UINT32 *)(&BlkDespPtr->BlockNum) = SwapBytes32 ((UINT32)Blocks);\r
1605 Blocks = 0;\r
b6e5da19
HW
1606 }\r
1607\r
1608 BlkDespPtr++;\r
1609 }\r
1610\r
1611 CommandPacket = &EraseBlkReq->CommandPacket;\r
1612 CommandPacket->Timeout = SCSI_DISK_TIMEOUT;\r
1613 CommandPacket->OutDataBuffer = UnmapParamList;\r
1614 CommandPacket->OutTransferLength = UnmapParamListLen;\r
1615 CommandPacket->CdbLength = 0xA;\r
1616 CommandPacket->DataDirection = EFI_SCSI_DATA_OUT;\r
1617 //\r
1618 // Fill Cdb for UNMAP Command\r
1619 //\r
1620 Cdb = CommandPacket->Cdb;\r
1621 Cdb[0] = EFI_SCSI_OP_UNMAP;\r
1622 WriteUnaligned16 ((UINT16 *)&Cdb[7], SwapBytes16 (UnmapParamListLen));\r
1623\r
1624 if ((Token != NULL) && (Token->Event != NULL)) {\r
1625 //\r
1626 // Non-blocking UNMAP request\r
1627 //\r
1628 Status = gBS->CreateEvent (\r
1629 EVT_NOTIFY_SIGNAL,\r
1630 TPL_NOTIFY,\r
1631 ScsiDiskAsyncUnmapNotify,\r
1632 EraseBlkReq,\r
1633 &AsyncUnmapEvent\r
1634 );\r
1436aea4 1635 if (EFI_ERROR (Status)) {\r
b6e5da19
HW
1636 ReturnStatus = EFI_DEVICE_ERROR;\r
1637 goto Done;\r
1638 }\r
1639\r
1640 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1641 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &EraseBlkReq->Link);\r
1642 gBS->RestoreTPL (OldTpl);\r
1643\r
1644 EraseBlkReq->Token = Token;\r
1645\r
1646 Status = ScsiIo->ExecuteScsiCommand (\r
1647 ScsiIo,\r
1648 CommandPacket,\r
1649 AsyncUnmapEvent\r
1650 );\r
1436aea4 1651 if (EFI_ERROR (Status)) {\r
b6e5da19
HW
1652 ReturnStatus = EFI_DEVICE_ERROR;\r
1653\r
1654 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1655 RemoveEntryList (&EraseBlkReq->Link);\r
1656 gBS->RestoreTPL (OldTpl);\r
1657\r
1658 goto Done;\r
1659 } else {\r
1660 //\r
1661 // Directly return if the non-blocking UNMAP request is queued.\r
1662 //\r
1663 return EFI_SUCCESS;\r
1664 }\r
1665 } else {\r
1666 //\r
1667 // Blocking UNMAP request\r
1668 //\r
1669 Status = ScsiIo->ExecuteScsiCommand (\r
1670 ScsiIo,\r
1671 CommandPacket,\r
1672 NULL\r
1673 );\r
1436aea4 1674 if (EFI_ERROR (Status)) {\r
b6e5da19
HW
1675 ReturnStatus = EFI_DEVICE_ERROR;\r
1676 goto Done;\r
1677 }\r
1678 }\r
1679\r
1680 //\r
1681 // Only blocking UNMAP request will reach here.\r
1682 //\r
1683 Status = CheckHostAdapterStatus (CommandPacket->HostAdapterStatus);\r
1436aea4 1684 if (EFI_ERROR (Status)) {\r
b6e5da19 1685 DEBUG ((\r
87000d77 1686 DEBUG_ERROR,\r
b6e5da19
HW
1687 "ScsiDiskUnmap: Host adapter indicating error status 0x%x.\n",\r
1688 CommandPacket->HostAdapterStatus\r
1689 ));\r
1690\r
1691 ReturnStatus = EFI_DEVICE_ERROR;\r
1692 goto Done;\r
1693 }\r
1694\r
1695 Status = CheckTargetStatus (CommandPacket->TargetStatus);\r
1436aea4 1696 if (EFI_ERROR (Status)) {\r
b6e5da19 1697 DEBUG ((\r
87000d77 1698 DEBUG_ERROR,\r
b6e5da19
HW
1699 "ScsiDiskUnmap: Target indicating error status 0x%x.\n",\r
1700 CommandPacket->HostAdapterStatus\r
1701 ));\r
1702\r
1703 ReturnStatus = EFI_DEVICE_ERROR;\r
1704 goto Done;\r
1705 }\r
1706\r
1707Done:\r
1708 if (EraseBlkReq != NULL) {\r
1709 if (EraseBlkReq->CommandPacket.Cdb != NULL) {\r
1710 FreePool (EraseBlkReq->CommandPacket.Cdb);\r
1711 }\r
1436aea4 1712\r
b6e5da19
HW
1713 FreePool (EraseBlkReq);\r
1714 }\r
1715\r
1716 if (UnmapParamList != NULL) {\r
1717 FreePool (UnmapParamList);\r
1718 }\r
1719\r
1720 if (AsyncUnmapEvent != NULL) {\r
1721 gBS->CloseEvent (AsyncUnmapEvent);\r
1722 }\r
1723\r
1724 return ReturnStatus;\r
1725}\r
1726\r
1727/**\r
1728 Erase a specified number of device blocks.\r
1729\r
1730 @param[in] This Indicates a pointer to the calling context.\r
1731 @param[in] MediaId The media ID that the erase request is for.\r
1732 @param[in] Lba The starting logical block address to be\r
1733 erased. The caller is responsible for erasing\r
1734 only legitimate locations.\r
1735 @param[in, out] Token A pointer to the token associated with the\r
1736 transaction.\r
1737 @param[in] Size The size in bytes to be erased. This must be\r
1738 a multiple of the physical block size of the\r
1739 device.\r
1740\r
1741 @retval EFI_SUCCESS The erase request was queued if Event is not\r
1742 NULL. The data was erased correctly to the\r
1743 device if the Event is NULL.to the device.\r
1744 @retval EFI_WRITE_PROTECTED The device cannot be erased due to write\r
1745 protection.\r
1746 @retval EFI_DEVICE_ERROR The device reported an error while attempting\r
1747 to perform the erase operation.\r
1748 @retval EFI_INVALID_PARAMETER The erase request contains LBAs that are not\r
1749 valid.\r
1750 @retval EFI_NO_MEDIA There is no media in the device.\r
1751 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1752\r
1753**/\r
1754EFI_STATUS\r
1755EFIAPI\r
1756ScsiDiskEraseBlocks (\r
1436aea4
MK
1757 IN EFI_ERASE_BLOCK_PROTOCOL *This,\r
1758 IN UINT32 MediaId,\r
1759 IN EFI_LBA Lba,\r
1760 IN OUT EFI_ERASE_BLOCK_TOKEN *Token,\r
1761 IN UINTN Size\r
b6e5da19
HW
1762 )\r
1763{\r
1764 SCSI_DISK_DEV *ScsiDiskDevice;\r
1765 EFI_BLOCK_IO_MEDIA *Media;\r
1766 EFI_STATUS Status;\r
1767 UINTN BlockSize;\r
1768 UINTN NumberOfBlocks;\r
1769 BOOLEAN MediaChange;\r
1770 EFI_TPL OldTpl;\r
1771\r
1772 MediaChange = FALSE;\r
1773 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1774 ScsiDiskDevice = SCSI_DISK_DEV_FROM_ERASEBLK (This);\r
1775\r
1436aea4 1776 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
b6e5da19
HW
1777 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
1778 if (EFI_ERROR (Status)) {\r
1779 Status = EFI_DEVICE_ERROR;\r
1780 goto Done;\r
1781 }\r
1782\r
1783 if (MediaChange) {\r
1784 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1785 ScsiDiskDevice->Handle,\r
1786 &gEfiBlockIoProtocolGuid,\r
1787 &ScsiDiskDevice->BlkIo,\r
1788 &ScsiDiskDevice->BlkIo\r
1789 );\r
b6e5da19
HW
1790 gBS->ReinstallProtocolInterface (\r
1791 ScsiDiskDevice->Handle,\r
1792 &gEfiBlockIo2ProtocolGuid,\r
1793 &ScsiDiskDevice->BlkIo2,\r
1794 &ScsiDiskDevice->BlkIo2\r
1795 );\r
ac81789c 1796 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
b6e5da19
HW
1797 gBS->ReinstallProtocolInterface (\r
1798 ScsiDiskDevice->Handle,\r
1799 &gEfiEraseBlockProtocolGuid,\r
1800 &ScsiDiskDevice->EraseBlock,\r
1801 &ScsiDiskDevice->EraseBlock\r
1802 );\r
1803 }\r
1436aea4 1804\r
ac81789c
CZ
1805 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
1806 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1807 ScsiDiskDevice->Handle,\r
1808 &gEfiStorageSecurityCommandProtocolGuid,\r
1809 &ScsiDiskDevice->StorageSecurity,\r
1810 &ScsiDiskDevice->StorageSecurity\r
1811 );\r
ac81789c 1812 }\r
1436aea4 1813\r
b6e5da19
HW
1814 Status = EFI_MEDIA_CHANGED;\r
1815 goto Done;\r
1816 }\r
1817 }\r
1436aea4 1818\r
b6e5da19
HW
1819 //\r
1820 // Get the intrinsic block size\r
1821 //\r
1822 Media = ScsiDiskDevice->BlkIo.Media;\r
1823\r
1824 if (!(Media->MediaPresent)) {\r
1825 Status = EFI_NO_MEDIA;\r
1826 goto Done;\r
1827 }\r
1828\r
1829 if (MediaId != Media->MediaId) {\r
1830 Status = EFI_MEDIA_CHANGED;\r
1831 goto Done;\r
1832 }\r
1833\r
1834 if (Media->ReadOnly) {\r
1835 Status = EFI_WRITE_PROTECTED;\r
1836 goto Done;\r
1837 }\r
1838\r
1839 if (Size == 0) {\r
1840 if ((Token != NULL) && (Token->Event != NULL)) {\r
1841 Token->TransactionStatus = EFI_SUCCESS;\r
1842 gBS->SignalEvent (Token->Event);\r
1843 }\r
1436aea4 1844\r
b6e5da19
HW
1845 Status = EFI_SUCCESS;\r
1846 goto Done;\r
1847 }\r
1848\r
1849 BlockSize = Media->BlockSize;\r
1850 if ((Size % BlockSize) != 0) {\r
1851 Status = EFI_INVALID_PARAMETER;\r
1852 goto Done;\r
1853 }\r
1854\r
1855 NumberOfBlocks = Size / BlockSize;\r
1856 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
1857 Status = EFI_INVALID_PARAMETER;\r
1858 goto Done;\r
1859 }\r
1860\r
1861 if ((Token != NULL) && (Token->Event != NULL)) {\r
1862 Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, Token);\r
1863 } else {\r
1864 Status = ScsiDiskUnmap (ScsiDiskDevice, Lba, NumberOfBlocks, NULL);\r
1865 }\r
1866\r
1867Done:\r
1868 gBS->RestoreTPL (OldTpl);\r
1869 return Status;\r
1870}\r
1871\r
ac81789c
CZ
1872/**\r
1873 Send a security protocol command to a device that receives data and/or the result\r
1874 of one or more commands sent by SendData.\r
1875\r
1876 The ReceiveData function sends a security protocol command to the given MediaId.\r
1877 The security protocol command sent is defined by SecurityProtocolId and contains\r
1878 the security protocol specific data SecurityProtocolSpecificData. The function\r
1879 returns the data from the security protocol command in PayloadBuffer.\r
1880\r
1881 For devices supporting the SCSI command set, the security protocol command is sent\r
1882 using the SECURITY PROTOCOL IN command defined in SPC-4.\r
1883\r
1884 If PayloadBufferSize is too small to store the available data from the security\r
1885 protocol command, the function shall copy PayloadBufferSize bytes into the\r
1886 PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
1887\r
1888 If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
1889 the function shall return EFI_INVALID_PARAMETER.\r
1890\r
1891 If the given MediaId does not support security protocol commands, the function shall\r
1892 return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
1893 EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
1894 the function returns EFI_MEDIA_CHANGED.\r
1895\r
1896 If the security protocol fails to complete within the Timeout period, the function\r
1897 shall return EFI_TIMEOUT.\r
1898\r
1899 If the security protocol command completes without an error, the function shall\r
1900 return EFI_SUCCESS. If the security protocol command completes with an error, the\r
1901 function shall return EFI_DEVICE_ERROR.\r
1902\r
1903 @param This Indicates a pointer to the calling context.\r
1904 @param MediaId ID of the medium to receive data from.\r
1905 @param Timeout The timeout, in 100ns units, to use for the execution\r
1906 of the security protocol command. A Timeout value of 0\r
1907 means that this function will wait indefinitely for the\r
1908 security protocol command to execute. If Timeout is greater\r
1909 than zero, then this function will return EFI_TIMEOUT if the\r
1910 time required to execute the receive data command is greater than Timeout.\r
1911 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
1912 the security protocol command to be sent.\r
1913 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
1914 of the security protocol command to be sent.\r
1915 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
1916 @param PayloadBuffer A pointer to a destination buffer to store the security\r
1917 protocol command specific payload data for the security\r
1918 protocol command. The caller is responsible for having\r
1919 either implicit or explicit ownership of the buffer.\r
1920 @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the\r
1921 data written to the payload data buffer.\r
1922\r
1923 @retval EFI_SUCCESS The security protocol command completed successfully.\r
1924 @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available\r
1925 data from the device. The PayloadBuffer contains the truncated data.\r
1926 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
1927 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
1928 @retval EFI_NO_MEDIA There is no media in the device.\r
1929 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
1930 @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and\r
1931 PayloadBufferSize is non-zero.\r
1932 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
1933 protocol command to execute.\r
1934\r
1935**/\r
1936EFI_STATUS\r
1937EFIAPI\r
1938ScsiDiskReceiveData (\r
1436aea4
MK
1939 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
1940 IN UINT32 MediaId OPTIONAL,\r
1941 IN UINT64 Timeout,\r
1942 IN UINT8 SecurityProtocolId,\r
1943 IN UINT16 SecurityProtocolSpecificData,\r
1944 IN UINTN PayloadBufferSize,\r
1945 OUT VOID *PayloadBuffer,\r
1946 OUT UINTN *PayloadTransferSize\r
ac81789c
CZ
1947 )\r
1948{\r
1949 SCSI_DISK_DEV *ScsiDiskDevice;\r
1950 EFI_BLOCK_IO_MEDIA *Media;\r
1951 EFI_STATUS Status;\r
1952 BOOLEAN MediaChange;\r
1953 EFI_TPL OldTpl;\r
1954 UINT8 SenseDataLength;\r
1955 UINT8 HostAdapterStatus;\r
1956 UINT8 TargetStatus;\r
1957 VOID *AlignedBuffer;\r
1958 BOOLEAN AlignedBufferAllocated;\r
1959\r
1436aea4
MK
1960 AlignedBuffer = NULL;\r
1961 MediaChange = FALSE;\r
1962 AlignedBufferAllocated = FALSE;\r
1963 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1964 ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);\r
1965 Media = ScsiDiskDevice->BlkIo.Media;\r
ac81789c 1966\r
1436aea4 1967 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
ac81789c
CZ
1968\r
1969 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
1970 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
1971 if (EFI_ERROR (Status)) {\r
1972 Status = EFI_DEVICE_ERROR;\r
1973 goto Done;\r
1974 }\r
1975\r
1976 if (MediaChange) {\r
1977 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
1978 ScsiDiskDevice->Handle,\r
1979 &gEfiBlockIoProtocolGuid,\r
1980 &ScsiDiskDevice->BlkIo,\r
1981 &ScsiDiskDevice->BlkIo\r
1982 );\r
ac81789c
CZ
1983 gBS->ReinstallProtocolInterface (\r
1984 ScsiDiskDevice->Handle,\r
1985 &gEfiBlockIo2ProtocolGuid,\r
1986 &ScsiDiskDevice->BlkIo2,\r
1987 &ScsiDiskDevice->BlkIo2\r
1988 );\r
1989 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
1990 gBS->ReinstallProtocolInterface (\r
1991 ScsiDiskDevice->Handle,\r
1992 &gEfiEraseBlockProtocolGuid,\r
1993 &ScsiDiskDevice->EraseBlock,\r
1994 &ScsiDiskDevice->EraseBlock\r
1995 );\r
1996 }\r
1436aea4 1997\r
ac81789c
CZ
1998 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
1999 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
2000 ScsiDiskDevice->Handle,\r
2001 &gEfiStorageSecurityCommandProtocolGuid,\r
2002 &ScsiDiskDevice->StorageSecurity,\r
2003 &ScsiDiskDevice->StorageSecurity\r
2004 );\r
ac81789c 2005 }\r
1436aea4 2006\r
ac81789c
CZ
2007 if (Media->MediaPresent) {\r
2008 Status = EFI_MEDIA_CHANGED;\r
2009 } else {\r
2010 Status = EFI_NO_MEDIA;\r
2011 }\r
1436aea4 2012\r
ac81789c
CZ
2013 goto Done;\r
2014 }\r
2015 }\r
2016\r
2017 //\r
2018 // Validate Media\r
2019 //\r
2020 if (!(Media->MediaPresent)) {\r
2021 Status = EFI_NO_MEDIA;\r
2022 goto Done;\r
2023 }\r
2024\r
2025 if ((MediaId != 0) && (MediaId != Media->MediaId)) {\r
2026 Status = EFI_MEDIA_CHANGED;\r
2027 goto Done;\r
2028 }\r
2029\r
2030 if (PayloadBufferSize != 0) {\r
2031 if ((PayloadBuffer == NULL) || (PayloadTransferSize == NULL)) {\r
2032 Status = EFI_INVALID_PARAMETER;\r
2033 goto Done;\r
2034 }\r
2035\r
2036 if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {\r
2037 AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);\r
2038 if (AlignedBuffer == NULL) {\r
2039 Status = EFI_OUT_OF_RESOURCES;\r
2040 goto Done;\r
2041 }\r
1436aea4 2042\r
ac81789c
CZ
2043 ZeroMem (AlignedBuffer, PayloadBufferSize);\r
2044 AlignedBufferAllocated = TRUE;\r
2045 } else {\r
2046 AlignedBuffer = PayloadBuffer;\r
2047 }\r
2048 }\r
2049\r
2050 Status = ScsiSecurityProtocolInCommand (\r
1436aea4
MK
2051 ScsiDiskDevice->ScsiIo,\r
2052 Timeout,\r
2053 ScsiDiskDevice->SenseData,\r
2054 &SenseDataLength,\r
2055 &HostAdapterStatus,\r
2056 &TargetStatus,\r
2057 SecurityProtocolId,\r
2058 SecurityProtocolSpecificData,\r
2059 FALSE,\r
2060 PayloadBufferSize,\r
2061 AlignedBuffer,\r
2062 PayloadTransferSize\r
2063 );\r
ac81789c
CZ
2064 if (EFI_ERROR (Status)) {\r
2065 goto Done;\r
2066 }\r
2067\r
2068 if (AlignedBufferAllocated) {\r
2069 CopyMem (PayloadBuffer, AlignedBuffer, PayloadBufferSize);\r
2070 }\r
2071\r
2072 if (PayloadBufferSize < *PayloadTransferSize) {\r
2073 Status = EFI_WARN_BUFFER_TOO_SMALL;\r
2074 goto Done;\r
2075 }\r
2076\r
2077 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
2078 if (EFI_ERROR (Status)) {\r
2079 goto Done;\r
2080 }\r
2081\r
2082 Status = CheckTargetStatus (TargetStatus);\r
2083 if (EFI_ERROR (Status)) {\r
2084 goto Done;\r
2085 }\r
2086\r
2087Done:\r
2088 if (AlignedBufferAllocated) {\r
2089 ZeroMem (AlignedBuffer, PayloadBufferSize);\r
2090 FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);\r
2091 }\r
1436aea4 2092\r
ac81789c
CZ
2093 gBS->RestoreTPL (OldTpl);\r
2094 return Status;\r
2095}\r
2096\r
2097/**\r
2098 Send a security protocol command to a device.\r
2099\r
2100 The SendData function sends a security protocol command containing the payload\r
2101 PayloadBuffer to the given MediaId. The security protocol command sent is\r
2102 defined by SecurityProtocolId and contains the security protocol specific data\r
2103 SecurityProtocolSpecificData. If the underlying protocol command requires a\r
2104 specific padding for the command payload, the SendData function shall add padding\r
2105 bytes to the command payload to satisfy the padding requirements.\r
2106\r
2107 For devices supporting the SCSI command set, the security protocol command is sent\r
2108 using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
2109\r
2110 If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
2111 return EFI_INVALID_PARAMETER.\r
2112\r
2113 If the given MediaId does not support security protocol commands, the function\r
2114 shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
2115 returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
2116 device, the function returns EFI_MEDIA_CHANGED.\r
2117\r
2118 If the security protocol fails to complete within the Timeout period, the function\r
2119 shall return EFI_TIMEOUT.\r
2120\r
2121 If the security protocol command completes without an error, the function shall return\r
2122 EFI_SUCCESS. If the security protocol command completes with an error, the function\r
2123 shall return EFI_DEVICE_ERROR.\r
2124\r
2125 @param This Indicates a pointer to the calling context.\r
2126 @param MediaId ID of the medium to receive data from.\r
2127 @param Timeout The timeout, in 100ns units, to use for the execution\r
2128 of the security protocol command. A Timeout value of 0\r
2129 means that this function will wait indefinitely for the\r
2130 security protocol command to execute. If Timeout is greater\r
2131 than zero, then this function will return EFI_TIMEOUT if the\r
2132 time required to execute the receive data command is greater than Timeout.\r
2133 @param SecurityProtocolId The value of the "Security Protocol" parameter of\r
2134 the security protocol command to be sent.\r
2135 @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
2136 of the security protocol command to be sent.\r
2137 @param PayloadBufferSize Size in bytes of the payload data buffer.\r
2138 @param PayloadBuffer A pointer to a destination buffer to store the security\r
2139 protocol command specific payload data for the security\r
2140 protocol command.\r
2141\r
2142 @retval EFI_SUCCESS The security protocol command completed successfully.\r
2143 @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.\r
2144 @retval EFI_DEVICE_ERROR The security protocol command completed with an error.\r
2145 @retval EFI_NO_MEDIA There is no media in the device.\r
2146 @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r
2147 @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
2148 @retval EFI_TIMEOUT A timeout occurred while waiting for the security\r
2149 protocol command to execute.\r
2150\r
2151**/\r
2152EFI_STATUS\r
2153EFIAPI\r
2154ScsiDiskSendData (\r
1436aea4
MK
2155 IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,\r
2156 IN UINT32 MediaId OPTIONAL,\r
2157 IN UINT64 Timeout,\r
2158 IN UINT8 SecurityProtocolId,\r
2159 IN UINT16 SecurityProtocolSpecificData,\r
2160 IN UINTN PayloadBufferSize,\r
2161 OUT VOID *PayloadBuffer\r
ac81789c
CZ
2162 )\r
2163{\r
2164 SCSI_DISK_DEV *ScsiDiskDevice;\r
2165 EFI_BLOCK_IO_MEDIA *Media;\r
2166 EFI_STATUS Status;\r
2167 BOOLEAN MediaChange;\r
2168 EFI_TPL OldTpl;\r
2169 UINT8 SenseDataLength;\r
2170 UINT8 HostAdapterStatus;\r
2171 UINT8 TargetStatus;\r
2172 VOID *AlignedBuffer;\r
2173 BOOLEAN AlignedBufferAllocated;\r
2174\r
1436aea4
MK
2175 AlignedBuffer = NULL;\r
2176 MediaChange = FALSE;\r
2177 AlignedBufferAllocated = FALSE;\r
2178 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
2179 ScsiDiskDevice = SCSI_DISK_DEV_FROM_STORSEC (This);\r
2180 Media = ScsiDiskDevice->BlkIo.Media;\r
ac81789c 2181\r
1436aea4 2182 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
ac81789c
CZ
2183\r
2184 if (!IS_DEVICE_FIXED (ScsiDiskDevice)) {\r
2185 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
2186 if (EFI_ERROR (Status)) {\r
2187 Status = EFI_DEVICE_ERROR;\r
2188 goto Done;\r
2189 }\r
2190\r
2191 if (MediaChange) {\r
2192 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
2193 ScsiDiskDevice->Handle,\r
2194 &gEfiBlockIoProtocolGuid,\r
2195 &ScsiDiskDevice->BlkIo,\r
2196 &ScsiDiskDevice->BlkIo\r
2197 );\r
ac81789c
CZ
2198 gBS->ReinstallProtocolInterface (\r
2199 ScsiDiskDevice->Handle,\r
2200 &gEfiBlockIo2ProtocolGuid,\r
2201 &ScsiDiskDevice->BlkIo2,\r
2202 &ScsiDiskDevice->BlkIo2\r
2203 );\r
2204 if (DetermineInstallEraseBlock (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
2205 gBS->ReinstallProtocolInterface (\r
2206 ScsiDiskDevice->Handle,\r
2207 &gEfiEraseBlockProtocolGuid,\r
2208 &ScsiDiskDevice->EraseBlock,\r
2209 &ScsiDiskDevice->EraseBlock\r
2210 );\r
2211 }\r
1436aea4 2212\r
ac81789c
CZ
2213 if (DetermineInstallStorageSecurity (ScsiDiskDevice, ScsiDiskDevice->Handle)) {\r
2214 gBS->ReinstallProtocolInterface (\r
1436aea4
MK
2215 ScsiDiskDevice->Handle,\r
2216 &gEfiStorageSecurityCommandProtocolGuid,\r
2217 &ScsiDiskDevice->StorageSecurity,\r
2218 &ScsiDiskDevice->StorageSecurity\r
2219 );\r
ac81789c 2220 }\r
1436aea4 2221\r
ac81789c
CZ
2222 if (Media->MediaPresent) {\r
2223 Status = EFI_MEDIA_CHANGED;\r
2224 } else {\r
2225 Status = EFI_NO_MEDIA;\r
2226 }\r
1436aea4 2227\r
ac81789c
CZ
2228 goto Done;\r
2229 }\r
2230 }\r
2231\r
2232 //\r
2233 // Validate Media\r
2234 //\r
2235 if (!(Media->MediaPresent)) {\r
2236 Status = EFI_NO_MEDIA;\r
2237 goto Done;\r
2238 }\r
2239\r
2240 if ((MediaId != 0) && (MediaId != Media->MediaId)) {\r
2241 Status = EFI_MEDIA_CHANGED;\r
2242 goto Done;\r
2243 }\r
2244\r
2245 if (Media->ReadOnly) {\r
2246 Status = EFI_WRITE_PROTECTED;\r
2247 goto Done;\r
2248 }\r
2249\r
2250 if (PayloadBufferSize != 0) {\r
2251 if (PayloadBuffer == NULL) {\r
2252 Status = EFI_INVALID_PARAMETER;\r
2253 goto Done;\r
2254 }\r
2255\r
2256 if ((ScsiDiskDevice->ScsiIo->IoAlign > 1) && !IS_ALIGNED (PayloadBuffer, ScsiDiskDevice->ScsiIo->IoAlign)) {\r
2257 AlignedBuffer = AllocateAlignedBuffer (ScsiDiskDevice, PayloadBufferSize);\r
2258 if (AlignedBuffer == NULL) {\r
2259 Status = EFI_OUT_OF_RESOURCES;\r
2260 goto Done;\r
2261 }\r
1436aea4 2262\r
ac81789c
CZ
2263 CopyMem (AlignedBuffer, PayloadBuffer, PayloadBufferSize);\r
2264 AlignedBufferAllocated = TRUE;\r
2265 } else {\r
2266 AlignedBuffer = PayloadBuffer;\r
2267 }\r
2268 }\r
2269\r
2270 Status = ScsiSecurityProtocolOutCommand (\r
1436aea4
MK
2271 ScsiDiskDevice->ScsiIo,\r
2272 Timeout,\r
2273 ScsiDiskDevice->SenseData,\r
2274 &SenseDataLength,\r
2275 &HostAdapterStatus,\r
2276 &TargetStatus,\r
2277 SecurityProtocolId,\r
2278 SecurityProtocolSpecificData,\r
2279 FALSE,\r
2280 PayloadBufferSize,\r
2281 AlignedBuffer\r
2282 );\r
ac81789c
CZ
2283 if (EFI_ERROR (Status)) {\r
2284 goto Done;\r
2285 }\r
2286\r
2287 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
2288 if (EFI_ERROR (Status)) {\r
2289 goto Done;\r
2290 }\r
2291\r
2292 Status = CheckTargetStatus (TargetStatus);\r
2293 if (EFI_ERROR (Status)) {\r
2294 goto Done;\r
2295 }\r
2296\r
2297Done:\r
2298 if (AlignedBufferAllocated) {\r
2299 ZeroMem (AlignedBuffer, PayloadBufferSize);\r
2300 FreeAlignedBuffer (AlignedBuffer, PayloadBufferSize);\r
2301 }\r
1436aea4 2302\r
ac81789c
CZ
2303 gBS->RestoreTPL (OldTpl);\r
2304 return Status;\r
2305}\r
2306\r
9beb888e 2307/**\r
d716651f 2308 Detect Device and read out capacity ,if error occurs, parse the sense key.\r
6ad55b15 2309\r
9beb888e 2310 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2311 @param MustReadCapacity The flag about reading device capacity\r
d1102dba 2312 @param MediaChange The pointer of flag indicates if media has changed\r
6ad55b15 2313\r
9beb888e 2314 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
2315 @retval EFI_SUCCESS Successfully to detect media\r
6ad55b15 2316\r
9beb888e 2317**/\r
2318EFI_STATUS\r
2319ScsiDiskDetectMedia (\r
1436aea4
MK
2320 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
2321 IN BOOLEAN MustReadCapacity,\r
2322 OUT BOOLEAN *MediaChange\r
9beb888e 2323 )\r
6ad55b15 2324{\r
1436aea4
MK
2325 EFI_STATUS Status;\r
2326 EFI_SCSI_SENSE_DATA *SenseData;\r
2327 UINTN NumberOfSenseKeys;\r
2328 BOOLEAN NeedRetry;\r
2329 BOOLEAN NeedReadCapacity;\r
2330 UINT8 Retry;\r
2331 UINT8 MaxRetry;\r
2332 EFI_BLOCK_IO_MEDIA OldMedia;\r
2333 UINTN Action;\r
2334 EFI_EVENT TimeoutEvt;\r
2335\r
2336 Status = EFI_SUCCESS;\r
2337 SenseData = NULL;\r
2338 NumberOfSenseKeys = 0;\r
2339 Retry = 0;\r
2340 MaxRetry = 3;\r
2341 Action = ACTION_NO_ACTION;\r
2342 NeedReadCapacity = FALSE;\r
2343 *MediaChange = FALSE;\r
2344 TimeoutEvt = NULL;\r
f36d6e66 2345\r
ae5dc795 2346 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
2347\r
2348 Status = gBS->CreateEvent (\r
2349 EVT_TIMER,\r
2350 TPL_CALLBACK,\r
2351 NULL,\r
2352 NULL,\r
2353 &TimeoutEvt\r
2354 );\r
2355 if (EFI_ERROR (Status)) {\r
2356 return Status;\r
2357 }\r
2358\r
1436aea4 2359 Status = gBS->SetTimer (TimeoutEvt, TimerRelative, EFI_TIMER_PERIOD_SECONDS (120));\r
ae5dc795 2360 if (EFI_ERROR (Status)) {\r
2361 goto EXIT;\r
2362 }\r
2363\r
2364 //\r
2365 // Sending Test_Unit cmd to poll device status.\r
2366 // If the sense data shows the drive is not ready or reset before, we need poll the device status again.\r
2367 // We limit the upper boundary to 120 seconds.\r
2368 //\r
2369 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvt))) {\r
6ad55b15 2370 Status = ScsiDiskTestUnitReady (\r
1436aea4
MK
2371 ScsiDiskDevice,\r
2372 &NeedRetry,\r
2373 &SenseData,\r
2374 &NumberOfSenseKeys\r
2375 );\r
6ad55b15 2376 if (!EFI_ERROR (Status)) {\r
cbd2a4b3 2377 Status = DetectMediaParsingSenseKeys (\r
2378 ScsiDiskDevice,\r
2379 SenseData,\r
2380 NumberOfSenseKeys,\r
2381 &Action\r
2382 );\r
2383 if (EFI_ERROR (Status)) {\r
ae5dc795 2384 goto EXIT;\r
cbd2a4b3 2385 } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
2386 continue;\r
2387 } else {\r
2388 break;\r
2389 }\r
ae5dc795 2390 } else {\r
2391 Retry++;\r
2392 if (!NeedRetry || (Retry >= MaxRetry)) {\r
2393 goto EXIT;\r
2394 }\r
6ad55b15 2395 }\r
2396 }\r
2397\r
ae5dc795 2398 if (EFI_ERROR (Status)) {\r
2399 goto EXIT;\r
6ad55b15 2400 }\r
2401\r
6ad55b15 2402 //\r
2403 // ACTION_NO_ACTION: need not read capacity\r
2404 // other action code: need read capacity\r
2405 //\r
cbd2a4b3 2406 if (Action == ACTION_READ_CAPACITY) {\r
6ad55b15 2407 NeedReadCapacity = TRUE;\r
2408 }\r
f36d6e66 2409\r
ac81789c
CZ
2410 //\r
2411 // READ_CAPACITY command is not supported by any of the UFS WLUNs.\r
2412 //\r
2413 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {\r
1436aea4
MK
2414 NeedReadCapacity = FALSE;\r
2415 MustReadCapacity = FALSE;\r
ac81789c
CZ
2416 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
2417 }\r
2418\r
6ad55b15 2419 //\r
2420 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,\r
2421 // retrieve capacity via Read Capacity command\r
2422 //\r
2423 if (NeedReadCapacity || MustReadCapacity) {\r
6ad55b15 2424 //\r
2425 // retrieve media information\r
2426 //\r
ae5dc795 2427 for (Retry = 0; Retry < MaxRetry; Retry++) {\r
2428 Status = ScsiDiskReadCapacity (\r
2429 ScsiDiskDevice,\r
2430 &NeedRetry,\r
2431 &SenseData,\r
2432 &NumberOfSenseKeys\r
2433 );\r
2434 if (!EFI_ERROR (Status)) {\r
6ad55b15 2435 //\r
ae5dc795 2436 // analyze sense key to action\r
6ad55b15 2437 //\r
ae5dc795 2438 Status = DetectMediaParsingSenseKeys (\r
2439 ScsiDiskDevice,\r
2440 SenseData,\r
2441 NumberOfSenseKeys,\r
2442 &Action\r
2443 );\r
2444 if (EFI_ERROR (Status)) {\r
2445 //\r
2446 // if Status is error, it may indicate crisis error,\r
2447 // so return without retry.\r
2448 //\r
2449 goto EXIT;\r
2450 } else if (Action == ACTION_RETRY_COMMAND_LATER) {\r
2451 Retry = 0;\r
2452 continue;\r
2453 } else {\r
2454 break;\r
2455 }\r
d1102dba 2456 } else {\r
ae5dc795 2457 Retry++;\r
2458 if (!NeedRetry || (Retry >= MaxRetry)) {\r
2459 goto EXIT;\r
2460 }\r
6ad55b15 2461 }\r
2462 }\r
2463\r
ae5dc795 2464 if (EFI_ERROR (Status)) {\r
2465 goto EXIT;\r
6ad55b15 2466 }\r
2467 }\r
2468\r
2469 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {\r
2470 //\r
2471 // Media change information got from the device\r
2472 //\r
2473 *MediaChange = TRUE;\r
2474 }\r
2475\r
2476 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {\r
1436aea4 2477 *MediaChange = TRUE;\r
6ad55b15 2478 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
2479 }\r
2480\r
2481 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {\r
1436aea4 2482 *MediaChange = TRUE;\r
6ad55b15 2483 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
2484 }\r
2485\r
2486 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {\r
1436aea4 2487 *MediaChange = TRUE;\r
6ad55b15 2488 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
2489 }\r
2490\r
2491 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {\r
2492 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {\r
2493 //\r
2494 // when change from no media to media present, reset the MediaId to 1.\r
2495 //\r
2496 ScsiDiskDevice->BlkIo.Media->MediaId = 1;\r
2497 } else {\r
2498 //\r
2499 // when no media, reset the MediaId to zero.\r
2500 //\r
2501 ScsiDiskDevice->BlkIo.Media->MediaId = 0;\r
2502 }\r
2503\r
2504 *MediaChange = TRUE;\r
2505 }\r
2506\r
ae5dc795 2507EXIT:\r
2508 if (TimeoutEvt != NULL) {\r
2509 gBS->CloseEvent (TimeoutEvt);\r
2510 }\r
1436aea4 2511\r
ae5dc795 2512 return Status;\r
6ad55b15 2513}\r
2514\r
9beb888e 2515/**\r
2516 Send out Inquiry command to Device.\r
6ad55b15 2517\r
9beb888e 2518 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2519 @param NeedRetry Indicates if needs try again when error happens\r
6ad55b15 2520\r
9beb888e 2521 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
2522 @retval EFI_SUCCESS Successfully to detect media\r
6ad55b15 2523\r
9beb888e 2524**/\r
2525EFI_STATUS\r
2526ScsiDiskInquiryDevice (\r
1436aea4
MK
2527 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
2528 OUT BOOLEAN *NeedRetry\r
9beb888e 2529 )\r
6ad55b15 2530{\r
1436aea4
MK
2531 UINT32 InquiryDataLength;\r
2532 UINT8 SenseDataLength;\r
2533 UINT8 HostAdapterStatus;\r
2534 UINT8 TargetStatus;\r
2535 EFI_SCSI_SENSE_DATA *SenseDataArray;\r
2536 UINTN NumberOfSenseKeys;\r
2537 EFI_STATUS Status;\r
2538 UINT8 MaxRetry;\r
2539 UINT8 Index;\r
2540 EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE *SupportedVpdPages;\r
2541 EFI_SCSI_BLOCK_LIMITS_VPD_PAGE *BlockLimits;\r
2542 UINTN PageLength;\r
6ad55b15 2543\r
2544 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
2545 SenseDataLength = 0;\r
2546\r
d35be2a4 2547 Status = ScsiInquiryCommand (\r
1436aea4
MK
2548 ScsiDiskDevice->ScsiIo,\r
2549 SCSI_DISK_TIMEOUT,\r
2550 NULL,\r
2551 &SenseDataLength,\r
2552 &HostAdapterStatus,\r
2553 &TargetStatus,\r
2554 (VOID *)&(ScsiDiskDevice->InquiryData),\r
2555 &InquiryDataLength,\r
2556 FALSE\r
2557 );\r
2558 //\r
2559 // no need to check HostAdapterStatus and TargetStatus\r
2560 //\r
f36d6e66 2561 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
0e87144e
RN
2562 ParseInquiryData (ScsiDiskDevice);\r
2563\r
2564 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
2565 //\r
2566 // Check whether the device supports Block Limits VPD page (0xB0)\r
2567 //\r
957fe093
SZ
2568 SupportedVpdPages = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));\r
2569 if (SupportedVpdPages == NULL) {\r
2570 *NeedRetry = FALSE;\r
2571 return EFI_DEVICE_ERROR;\r
2572 }\r
1436aea4 2573\r
957fe093
SZ
2574 ZeroMem (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));\r
2575 InquiryDataLength = sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE);\r
0e87144e 2576 SenseDataLength = 0;\r
1436aea4
MK
2577 Status = ScsiInquiryCommandEx (\r
2578 ScsiDiskDevice->ScsiIo,\r
2579 SCSI_DISK_TIMEOUT,\r
2580 NULL,\r
2581 &SenseDataLength,\r
2582 &HostAdapterStatus,\r
2583 &TargetStatus,\r
2584 (VOID *)SupportedVpdPages,\r
2585 &InquiryDataLength,\r
2586 TRUE,\r
2587 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD\r
2588 );\r
0e87144e 2589 if (!EFI_ERROR (Status)) {\r
957fe093 2590 PageLength = (SupportedVpdPages->PageLength2 << 8)\r
1436aea4 2591 | SupportedVpdPages->PageLength1;\r
ce1647fc
LE
2592\r
2593 //\r
2594 // Sanity checks for coping with broken devices\r
2595 //\r
2596 if (PageLength > sizeof SupportedVpdPages->SupportedVpdPageList) {\r
1436aea4
MK
2597 DEBUG ((\r
2598 DEBUG_WARN,\r
ce1647fc 2599 "%a: invalid PageLength (%u) in Supported VPD Pages page\n",\r
1436aea4
MK
2600 __FUNCTION__,\r
2601 (UINT32)PageLength\r
2602 ));\r
ce1647fc
LE
2603 PageLength = 0;\r
2604 }\r
2605\r
2606 if ((PageLength > 0) &&\r
2607 (SupportedVpdPages->SupportedVpdPageList[0] !=\r
1436aea4
MK
2608 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD))\r
2609 {\r
2610 DEBUG ((\r
2611 DEBUG_WARN,\r
ce1647fc 2612 "%a: Supported VPD Pages page doesn't start with code 0x%02x\n",\r
1436aea4
MK
2613 __FUNCTION__,\r
2614 EFI_SCSI_PAGE_CODE_SUPPORTED_VPD\r
2615 ));\r
ce1647fc
LE
2616 PageLength = 0;\r
2617 }\r
2618\r
2619 //\r
2620 // Locate the code for the Block Limits VPD page\r
2621 //\r
0e87144e 2622 for (Index = 0; Index < PageLength; Index++) {\r
ce1647fc
LE
2623 //\r
2624 // Sanity check\r
2625 //\r
2626 if ((Index > 0) &&\r
2627 (SupportedVpdPages->SupportedVpdPageList[Index] <=\r
1436aea4
MK
2628 SupportedVpdPages->SupportedVpdPageList[Index - 1]))\r
2629 {\r
2630 DEBUG ((\r
2631 DEBUG_WARN,\r
ce1647fc 2632 "%a: non-ascending code in Supported VPD Pages page @ %u\n",\r
1436aea4
MK
2633 __FUNCTION__,\r
2634 Index\r
2635 ));\r
2636 Index = 0;\r
ce1647fc
LE
2637 PageLength = 0;\r
2638 break;\r
2639 }\r
2640\r
957fe093 2641 if (SupportedVpdPages->SupportedVpdPageList[Index] == EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD) {\r
0e87144e
RN
2642 break;\r
2643 }\r
2644 }\r
2645\r
2646 //\r
2647 // Query the Block Limits VPD page\r
2648 //\r
2649 if (Index < PageLength) {\r
957fe093
SZ
2650 BlockLimits = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));\r
2651 if (BlockLimits == NULL) {\r
2652 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));\r
2653 *NeedRetry = FALSE;\r
2654 return EFI_DEVICE_ERROR;\r
2655 }\r
1436aea4 2656\r
957fe093
SZ
2657 ZeroMem (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));\r
2658 InquiryDataLength = sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE);\r
0e87144e 2659 SenseDataLength = 0;\r
1436aea4
MK
2660 Status = ScsiInquiryCommandEx (\r
2661 ScsiDiskDevice->ScsiIo,\r
2662 SCSI_DISK_TIMEOUT,\r
2663 NULL,\r
2664 &SenseDataLength,\r
2665 &HostAdapterStatus,\r
2666 &TargetStatus,\r
2667 (VOID *)BlockLimits,\r
2668 &InquiryDataLength,\r
2669 TRUE,\r
2670 EFI_SCSI_PAGE_CODE_BLOCK_LIMITS_VPD\r
2671 );\r
0e87144e 2672 if (!EFI_ERROR (Status)) {\r
d1102dba 2673 ScsiDiskDevice->BlkIo.Media->OptimalTransferLengthGranularity =\r
957fe093 2674 (BlockLimits->OptimalTransferLengthGranularity2 << 8) |\r
1436aea4 2675 BlockLimits->OptimalTransferLengthGranularity1;\r
b6e5da19
HW
2676\r
2677 ScsiDiskDevice->UnmapInfo.MaxLbaCnt =\r
2678 (BlockLimits->MaximumUnmapLbaCount4 << 24) |\r
2679 (BlockLimits->MaximumUnmapLbaCount3 << 16) |\r
2680 (BlockLimits->MaximumUnmapLbaCount2 << 8) |\r
2681 BlockLimits->MaximumUnmapLbaCount1;\r
2682 ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt =\r
2683 (BlockLimits->MaximumUnmapBlockDescriptorCount4 << 24) |\r
2684 (BlockLimits->MaximumUnmapBlockDescriptorCount3 << 16) |\r
2685 (BlockLimits->MaximumUnmapBlockDescriptorCount2 << 8) |\r
2686 BlockLimits->MaximumUnmapBlockDescriptorCount1;\r
2687 ScsiDiskDevice->EraseBlock.EraseLengthGranularity =\r
2688 (BlockLimits->OptimalUnmapGranularity4 << 24) |\r
2689 (BlockLimits->OptimalUnmapGranularity3 << 16) |\r
2690 (BlockLimits->OptimalUnmapGranularity2 << 8) |\r
2691 BlockLimits->OptimalUnmapGranularity1;\r
2692 if (BlockLimits->UnmapGranularityAlignmentValid != 0) {\r
2693 ScsiDiskDevice->UnmapInfo.GranularityAlignment =\r
2694 (BlockLimits->UnmapGranularityAlignment4 << 24) |\r
2695 (BlockLimits->UnmapGranularityAlignment3 << 16) |\r
2696 (BlockLimits->UnmapGranularityAlignment2 << 8) |\r
2697 BlockLimits->UnmapGranularityAlignment1;\r
2698 }\r
2699\r
2700 if (ScsiDiskDevice->EraseBlock.EraseLengthGranularity == 0) {\r
2701 //\r
2702 // A value of 0 indicates that the optimal unmap granularity is\r
2703 // not reported.\r
2704 //\r
2705 ScsiDiskDevice->EraseBlock.EraseLengthGranularity = 1;\r
2706 }\r
2707\r
2708 ScsiDiskDevice->BlockLimitsVpdSupported = TRUE;\r
0e87144e 2709 }\r
957fe093
SZ
2710\r
2711 FreeAlignedBuffer (BlockLimits, sizeof (EFI_SCSI_BLOCK_LIMITS_VPD_PAGE));\r
0e87144e
RN
2712 }\r
2713 }\r
957fe093
SZ
2714\r
2715 FreeAlignedBuffer (SupportedVpdPages, sizeof (EFI_SCSI_SUPPORTED_VPD_PAGES_VPD_PAGE));\r
0e87144e
RN
2716 }\r
2717 }\r
2718\r
2719 if (!EFI_ERROR (Status)) {\r
2720 return EFI_SUCCESS;\r
0e87144e
RN
2721 } else if (Status == EFI_NOT_READY) {\r
2722 *NeedRetry = TRUE;\r
2723 return EFI_DEVICE_ERROR;\r
0e87144e
RN
2724 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
2725 *NeedRetry = FALSE;\r
2726 return EFI_DEVICE_ERROR;\r
2727 }\r
1436aea4 2728\r
0e87144e
RN
2729 //\r
2730 // go ahead to check HostAdapterStatus and TargetStatus\r
2731 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
2732 //\r
2733\r
2734 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
2735 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
2736 *NeedRetry = TRUE;\r
2737 return EFI_DEVICE_ERROR;\r
2738 } else if (Status == EFI_DEVICE_ERROR) {\r
1436aea4
MK
2739 //\r
2740 // reset the scsi channel\r
2741 //\r
6ad55b15 2742 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
2743 *NeedRetry = FALSE;\r
2744 return EFI_DEVICE_ERROR;\r
2745 }\r
2746\r
2747 Status = CheckTargetStatus (TargetStatus);\r
2748 if (Status == EFI_NOT_READY) {\r
2749 //\r
2750 // reset the scsi device\r
2751 //\r
2752 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
2753 *NeedRetry = TRUE;\r
2754 return EFI_DEVICE_ERROR;\r
2755 } else if (Status == EFI_DEVICE_ERROR) {\r
2756 *NeedRetry = FALSE;\r
2757 return EFI_DEVICE_ERROR;\r
2758 }\r
d1102dba 2759\r
6ad55b15 2760 //\r
b96cd313 2761 // if goes here, meant ScsiInquiryCommand() failed.\r
6ad55b15 2762 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
b96cd313 2763 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 2764 //\r
2765 MaxRetry = 3;\r
2766 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 2767 Status = ScsiDiskRequestSenseKeys (\r
1436aea4
MK
2768 ScsiDiskDevice,\r
2769 NeedRetry,\r
2770 &SenseDataArray,\r
2771 &NumberOfSenseKeys,\r
2772 TRUE\r
2773 );\r
6ad55b15 2774 if (!EFI_ERROR (Status)) {\r
2775 *NeedRetry = TRUE;\r
2776 return EFI_DEVICE_ERROR;\r
2777 }\r
2778\r
2779 if (!*NeedRetry) {\r
2780 return EFI_DEVICE_ERROR;\r
2781 }\r
2782 }\r
1436aea4 2783\r
6ad55b15 2784 //\r
2785 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
2786 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
2787 //\r
2788 *NeedRetry = FALSE;\r
2789 return EFI_DEVICE_ERROR;\r
2790}\r
2791\r
9beb888e 2792/**\r
d716651f 2793 To test device.\r
f36d6e66 2794\r
2795 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;\r
6ad55b15 2796 When Test Unit Ready command encounters any error caused by host adapter or\r
2797 target, return error without retrieving Sense Keys.\r
f36d6e66 2798\r
9beb888e 2799 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2800 @param NeedRetry The pointer of flag indicates try again\r
2801 @param SenseDataArray The pointer of an array of sense data\r
2802 @param NumberOfSenseKeys The pointer of the number of sense data array\r
f36d6e66 2803\r
9beb888e 2804 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
2805 @retval EFI_SUCCESS Successfully to test unit\r
f36d6e66 2806\r
9beb888e 2807**/\r
2808EFI_STATUS\r
2809ScsiDiskTestUnitReady (\r
1436aea4
MK
2810 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
2811 OUT BOOLEAN *NeedRetry,\r
2812 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
2813 OUT UINTN *NumberOfSenseKeys\r
9beb888e 2814 )\r
6ad55b15 2815{\r
2816 EFI_STATUS Status;\r
2817 UINT8 SenseDataLength;\r
2818 UINT8 HostAdapterStatus;\r
2819 UINT8 TargetStatus;\r
2820 UINT8 Index;\r
2821 UINT8 MaxRetry;\r
2822\r
1436aea4
MK
2823 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
2824 *NumberOfSenseKeys = 0;\r
6ad55b15 2825\r
2826 //\r
2827 // Parameter 3 and 4: do not require sense data, retrieve it when needed.\r
2828 //\r
d35be2a4 2829 Status = ScsiTestUnitReadyCommand (\r
1436aea4
MK
2830 ScsiDiskDevice->ScsiIo,\r
2831 SCSI_DISK_TIMEOUT,\r
2832 ScsiDiskDevice->SenseData,\r
2833 &SenseDataLength,\r
2834 &HostAdapterStatus,\r
2835 &TargetStatus\r
2836 );\r
f36d6e66 2837 //\r
2838 // no need to check HostAdapterStatus and TargetStatus\r
2839 //\r
6ad55b15 2840 if (Status == EFI_NOT_READY) {\r
6ad55b15 2841 *NeedRetry = TRUE;\r
2842 return EFI_DEVICE_ERROR;\r
2843 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
6ad55b15 2844 *NeedRetry = FALSE;\r
2845 return EFI_DEVICE_ERROR;\r
2846 }\r
1436aea4 2847\r
6ad55b15 2848 //\r
f36d6e66 2849 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)\r
6ad55b15 2850 //\r
f36d6e66 2851\r
6ad55b15 2852 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
2853 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
2854 *NeedRetry = TRUE;\r
2855 return EFI_DEVICE_ERROR;\r
2856 } else if (Status == EFI_DEVICE_ERROR) {\r
2857 //\r
2858 // reset the scsi channel\r
2859 //\r
2860 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
2861 *NeedRetry = FALSE;\r
2862 return EFI_DEVICE_ERROR;\r
2863 }\r
2864\r
2865 Status = CheckTargetStatus (TargetStatus);\r
2866 if (Status == EFI_NOT_READY) {\r
2867 //\r
2868 // reset the scsi device\r
2869 //\r
2870 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
2871 *NeedRetry = TRUE;\r
2872 return EFI_DEVICE_ERROR;\r
2873 } else if (Status == EFI_DEVICE_ERROR) {\r
2874 *NeedRetry = FALSE;\r
2875 return EFI_DEVICE_ERROR;\r
2876 }\r
2877\r
2bf87d82
FT
2878 if (SenseDataLength != 0) {\r
2879 *NumberOfSenseKeys = SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA);\r
2880 *SenseDataArray = ScsiDiskDevice->SenseData;\r
2881 return EFI_SUCCESS;\r
2882 }\r
2883\r
6ad55b15 2884 MaxRetry = 3;\r
2885 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 2886 Status = ScsiDiskRequestSenseKeys (\r
1436aea4
MK
2887 ScsiDiskDevice,\r
2888 NeedRetry,\r
2889 SenseDataArray,\r
2890 NumberOfSenseKeys,\r
2891 FALSE\r
2892 );\r
6ad55b15 2893 if (!EFI_ERROR (Status)) {\r
2894 return EFI_SUCCESS;\r
2895 }\r
2896\r
2897 if (!*NeedRetry) {\r
2898 return EFI_DEVICE_ERROR;\r
2899 }\r
2900 }\r
1436aea4 2901\r
6ad55b15 2902 //\r
2903 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
2904 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
2905 //\r
2906 *NeedRetry = FALSE;\r
2907 return EFI_DEVICE_ERROR;\r
2908}\r
2909\r
9beb888e 2910/**\r
f36d6e66 2911 Parsing Sense Keys which got from request sense command.\r
6ad55b15 2912\r
9beb888e 2913 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2914 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
d1102dba 2915 @param NumberOfSenseKeys The number of sense key\r
9beb888e 2916 @param Action The pointer of action which indicates what is need to do next\r
6ad55b15 2917\r
9beb888e 2918 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
2919 @retval EFI_SUCCESS Successfully to complete the parsing\r
6ad55b15 2920\r
9beb888e 2921**/\r
2922EFI_STATUS\r
2923DetectMediaParsingSenseKeys (\r
1436aea4
MK
2924 OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
2925 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2926 IN UINTN NumberOfSenseKeys,\r
2927 OUT UINTN *Action\r
9beb888e 2928 )\r
6ad55b15 2929{\r
1436aea4 2930 BOOLEAN RetryLater;\r
6ad55b15 2931\r
2932 //\r
2933 // Default is to read capacity, unless..\r
2934 //\r
2935 *Action = ACTION_READ_CAPACITY;\r
2936\r
2937 if (NumberOfSenseKeys == 0) {\r
ae5dc795 2938 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {\r
2939 *Action = ACTION_NO_ACTION;\r
2940 }\r
1436aea4 2941\r
6ad55b15 2942 return EFI_SUCCESS;\r
2943 }\r
2944\r
2945 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {\r
2946 //\r
2947 // No Sense Key returned from last submitted command\r
2948 //\r
ae5dc795 2949 if (ScsiDiskDevice->BlkIo.Media->MediaPresent == TRUE) {\r
2950 *Action = ACTION_NO_ACTION;\r
2951 }\r
1436aea4 2952\r
6ad55b15 2953 return EFI_SUCCESS;\r
2954 }\r
2955\r
2956 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {\r
2957 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
2958 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1436aea4 2959 *Action = ACTION_NO_ACTION;\r
87000d77 2960 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsNoMedia\n"));\r
6ad55b15 2961 return EFI_SUCCESS;\r
2962 }\r
2963\r
2964 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {\r
2965 ScsiDiskDevice->BlkIo.Media->MediaId++;\r
87000d77 2966 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaChange!\n"));\r
6ad55b15 2967 return EFI_SUCCESS;\r
2968 }\r
2969\r
cbd2a4b3 2970 if (ScsiDiskIsResetBefore (SenseData, NumberOfSenseKeys)) {\r
2971 *Action = ACTION_RETRY_COMMAND_LATER;\r
87000d77 2972 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsResetBefore!\n"));\r
cbd2a4b3 2973 return EFI_SUCCESS;\r
2974 }\r
2975\r
6ad55b15 2976 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
87000d77 2977 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsMediaError\n"));\r
73a9e822 2978 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;\r
6ad55b15 2979 return EFI_DEVICE_ERROR;\r
2980 }\r
2981\r
2982 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {\r
87000d77 2983 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskIsHardwareError\n"));\r
73a9e822 2984 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;\r
6ad55b15 2985 return EFI_DEVICE_ERROR;\r
2986 }\r
2987\r
2988 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {\r
2989 if (RetryLater) {\r
2990 *Action = ACTION_RETRY_COMMAND_LATER;\r
87000d77 2991 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: ScsiDiskDriveNotReady!\n"));\r
6ad55b15 2992 return EFI_SUCCESS;\r
2993 }\r
1436aea4 2994\r
ae5dc795 2995 *Action = ACTION_NO_ACTION;\r
6ad55b15 2996 return EFI_DEVICE_ERROR;\r
2997 }\r
2998\r
73a9e822 2999 *Action = ACTION_RETRY_WITH_BACKOFF_ALGO;\r
87000d77 3000 DEBUG ((DEBUG_VERBOSE, "ScsiDisk: Sense Key = 0x%x ASC = 0x%x!\n", SenseData->Sense_Key, SenseData->Addnl_Sense_Code));\r
6ad55b15 3001 return EFI_SUCCESS;\r
3002}\r
3003\r
9beb888e 3004/**\r
3005 Send read capacity command to device and get the device parameter.\r
6ad55b15 3006\r
9beb888e 3007 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
3008 @param NeedRetry The pointer of flag indicates if need a retry\r
3009 @param SenseDataArray The pointer of an array of sense data\r
3010 @param NumberOfSenseKeys The number of sense key\r
6ad55b15 3011\r
9beb888e 3012 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
8536cc4b 3013 @retval EFI_SUCCESS Successfully to read capacity or sense data is received.\r
6ad55b15 3014\r
9beb888e 3015**/\r
3016EFI_STATUS\r
3017ScsiDiskReadCapacity (\r
1436aea4
MK
3018 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
3019 OUT BOOLEAN *NeedRetry,\r
3020 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
3021 OUT UINTN *NumberOfSenseKeys\r
9beb888e 3022 )\r
6ad55b15 3023{\r
1436aea4
MK
3024 UINT8 HostAdapterStatus;\r
3025 UINT8 TargetStatus;\r
3026 EFI_STATUS CommandStatus;\r
3027 EFI_STATUS Status;\r
3028 UINT8 Index;\r
3029 UINT8 MaxRetry;\r
3030 UINT8 SenseDataLength;\r
3031 UINT32 DataLength10;\r
3032 UINT32 DataLength16;\r
3033 EFI_SCSI_DISK_CAPACITY_DATA *CapacityData10;\r
3034 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;\r
b96cd313 3035\r
957fe093
SZ
3036 CapacityData10 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
3037 if (CapacityData10 == NULL) {\r
3038 *NeedRetry = FALSE;\r
3039 return EFI_DEVICE_ERROR;\r
3040 }\r
1436aea4 3041\r
957fe093
SZ
3042 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
3043 if (CapacityData16 == NULL) {\r
3044 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
3045 *NeedRetry = FALSE;\r
3046 return EFI_DEVICE_ERROR;\r
3047 }\r
b96cd313 3048\r
1436aea4
MK
3049 SenseDataLength = 0;\r
3050 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
3051 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
957fe093
SZ
3052 ZeroMem (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
3053 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
6ad55b15 3054\r
1436aea4
MK
3055 *NumberOfSenseKeys = 0;\r
3056 *NeedRetry = FALSE;\r
b96cd313 3057\r
f95bc048 3058 //\r
d1102dba 3059 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh,\r
f95bc048 3060 // 16 byte command should be used to access large hard disk >2TB\r
3061 //\r
3062 CommandStatus = ScsiReadCapacityCommand (\r
3063 ScsiDiskDevice->ScsiIo,\r
3cc033c5 3064 SCSI_DISK_TIMEOUT,\r
f95bc048 3065 NULL,\r
3066 &SenseDataLength,\r
3067 &HostAdapterStatus,\r
3068 &TargetStatus,\r
1436aea4 3069 (VOID *)CapacityData10,\r
f95bc048 3070 &DataLength10,\r
3071 FALSE\r
3072 );\r
3073\r
3074 ScsiDiskDevice->Cdb16Byte = FALSE;\r
957fe093 3075 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10->LastLba3 == 0xff) && (CapacityData10->LastLba2 == 0xff) &&\r
1436aea4
MK
3076 (CapacityData10->LastLba1 == 0xff) && (CapacityData10->LastLba0 == 0xff))\r
3077 {\r
f95bc048 3078 //\r
3079 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB\r
3080 //\r
3081 ScsiDiskDevice->Cdb16Byte = TRUE;\r
b96cd313 3082 //\r
f95bc048 3083 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
3084 // and LowestAlignedLba\r
b96cd313 3085 //\r
f95bc048 3086 CommandStatus = ScsiReadCapacity16Command (\r
b96cd313 3087 ScsiDiskDevice->ScsiIo,\r
3cc033c5 3088 SCSI_DISK_TIMEOUT,\r
b96cd313 3089 NULL,\r
3090 &SenseDataLength,\r
3091 &HostAdapterStatus,\r
3092 &TargetStatus,\r
1436aea4 3093 (VOID *)CapacityData16,\r
f95bc048 3094 &DataLength16,\r
b96cd313 3095 FALSE\r
3096 );\r
f95bc048 3097 }\r
3098\r
1436aea4
MK
3099 //\r
3100 // no need to check HostAdapterStatus and TargetStatus\r
3101 //\r
3102 if (CommandStatus == EFI_SUCCESS) {\r
3103 GetMediaInfo (ScsiDiskDevice, CapacityData10, CapacityData16);\r
3104 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
3105 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
3106 return EFI_SUCCESS;\r
3107 }\r
3108\r
3109 FreeAlignedBuffer (CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
3110 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
3111\r
3112 if (CommandStatus == EFI_NOT_READY) {\r
3113 *NeedRetry = TRUE;\r
3114 return EFI_DEVICE_ERROR;\r
3115 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {\r
3116 *NeedRetry = FALSE;\r
3117 return EFI_DEVICE_ERROR;\r
3118 }\r
3119\r
3120 //\r
3121 // go ahead to check HostAdapterStatus and TargetStatus\r
3122 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
3123 //\r
3124\r
3125 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
3126 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
3127 *NeedRetry = TRUE;\r
3128 return EFI_DEVICE_ERROR;\r
3129 } else if (Status == EFI_DEVICE_ERROR) {\r
6ad55b15 3130 //\r
3131 // reset the scsi channel\r
3132 //\r
3133 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
3134 *NeedRetry = FALSE;\r
3135 return EFI_DEVICE_ERROR;\r
3136 }\r
3137\r
3138 Status = CheckTargetStatus (TargetStatus);\r
3139 if (Status == EFI_NOT_READY) {\r
3140 //\r
3141 // reset the scsi device\r
3142 //\r
3143 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
3144 *NeedRetry = TRUE;\r
3145 return EFI_DEVICE_ERROR;\r
3146 } else if (Status == EFI_DEVICE_ERROR) {\r
3147 *NeedRetry = FALSE;\r
3148 return EFI_DEVICE_ERROR;\r
3149 }\r
d1102dba 3150\r
6ad55b15 3151 //\r
b96cd313 3152 // if goes here, meant ScsiReadCapacityCommand() failed.\r
6ad55b15 3153 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
b96cd313 3154 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 3155 //\r
3156 MaxRetry = 3;\r
3157 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 3158 Status = ScsiDiskRequestSenseKeys (\r
1436aea4
MK
3159 ScsiDiskDevice,\r
3160 NeedRetry,\r
3161 SenseDataArray,\r
3162 NumberOfSenseKeys,\r
3163 TRUE\r
3164 );\r
6ad55b15 3165 if (!EFI_ERROR (Status)) {\r
8536cc4b 3166 return EFI_SUCCESS;\r
6ad55b15 3167 }\r
3168\r
3169 if (!*NeedRetry) {\r
3170 return EFI_DEVICE_ERROR;\r
3171 }\r
3172 }\r
1436aea4 3173\r
6ad55b15 3174 //\r
3175 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
3176 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
3177 //\r
3178 *NeedRetry = FALSE;\r
3179 return EFI_DEVICE_ERROR;\r
3180}\r
3181\r
9beb888e 3182/**\r
3183 Check the HostAdapter status and re-interpret it in EFI_STATUS.\r
6ad55b15 3184\r
9beb888e 3185 @param HostAdapterStatus Host Adapter status\r
6ad55b15 3186\r
9beb888e 3187 @retval EFI_SUCCESS Host adapter is OK.\r
3188 @retval EFI_TIMEOUT Timeout.\r
3189 @retval EFI_NOT_READY Adapter NOT ready.\r
3190 @retval EFI_DEVICE_ERROR Adapter device error.\r
6ad55b15 3191\r
9beb888e 3192**/\r
3193EFI_STATUS\r
3194CheckHostAdapterStatus (\r
1436aea4 3195 IN UINT8 HostAdapterStatus\r
9beb888e 3196 )\r
6ad55b15 3197{\r
3198 switch (HostAdapterStatus) {\r
1436aea4
MK
3199 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:\r
3200 return EFI_SUCCESS;\r
6ad55b15 3201\r
1436aea4
MK
3202 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:\r
3203 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:\r
3204 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:\r
3205 return EFI_TIMEOUT;\r
6ad55b15 3206\r
1436aea4
MK
3207 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:\r
3208 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:\r
3209 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:\r
3210 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:\r
3211 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:\r
3212 return EFI_NOT_READY;\r
6ad55b15 3213\r
1436aea4
MK
3214 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:\r
3215 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:\r
3216 return EFI_DEVICE_ERROR;\r
6ad55b15 3217\r
1436aea4
MK
3218 default:\r
3219 return EFI_SUCCESS;\r
6ad55b15 3220 }\r
3221}\r
3222\r
9beb888e 3223/**\r
3224 Check the target status and re-interpret it in EFI_STATUS.\r
6ad55b15 3225\r
9beb888e 3226 @param TargetStatus Target status\r
6ad55b15 3227\r
9beb888e 3228 @retval EFI_NOT_READY Device is NOT ready.\r
d1102dba 3229 @retval EFI_DEVICE_ERROR\r
9beb888e 3230 @retval EFI_SUCCESS\r
6ad55b15 3231\r
9beb888e 3232**/\r
3233EFI_STATUS\r
3234CheckTargetStatus (\r
1436aea4 3235 IN UINT8 TargetStatus\r
9beb888e 3236 )\r
6ad55b15 3237{\r
3238 switch (TargetStatus) {\r
1436aea4
MK
3239 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:\r
3240 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:\r
3241 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:\r
3242 return EFI_SUCCESS;\r
6ad55b15 3243\r
1436aea4
MK
3244 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:\r
3245 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:\r
3246 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:\r
3247 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:\r
3248 return EFI_NOT_READY;\r
6ad55b15 3249\r
1436aea4
MK
3250 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:\r
3251 return EFI_DEVICE_ERROR;\r
6ad55b15 3252\r
1436aea4
MK
3253 default:\r
3254 return EFI_SUCCESS;\r
6ad55b15 3255 }\r
3256}\r
3257\r
9beb888e 3258/**\r
6ad55b15 3259 Retrieve all sense keys from the device.\r
f36d6e66 3260\r
9beb888e 3261 When encountering error during the process, if retrieve sense keys before\r
d716651f 3262 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,\r
cc530cd1 3263 and NeedRetry set to FALSE; otherwise, return the proper return status.\r
9beb888e 3264\r
3265 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
3266 @param NeedRetry The pointer of flag indicates if need a retry\r
3267 @param SenseDataArray The pointer of an array of sense data\r
3268 @param NumberOfSenseKeys The number of sense key\r
3269 @param AskResetIfError The flag indicates if need reset when error occurs\r
3270\r
3271 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
3272 @retval EFI_SUCCESS Successfully to request sense key\r
f36d6e66 3273\r
9beb888e 3274**/\r
3275EFI_STATUS\r
3276ScsiDiskRequestSenseKeys (\r
1436aea4
MK
3277 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
3278 OUT BOOLEAN *NeedRetry,\r
3279 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
3280 OUT UINTN *NumberOfSenseKeys,\r
3281 IN BOOLEAN AskResetIfError\r
9beb888e 3282 )\r
6ad55b15 3283{\r
1436aea4
MK
3284 EFI_SCSI_SENSE_DATA *PtrSenseData;\r
3285 UINT8 SenseDataLength;\r
3286 BOOLEAN SenseReq;\r
3287 EFI_STATUS Status;\r
3288 EFI_STATUS FallStatus;\r
3289 UINT8 HostAdapterStatus;\r
3290 UINT8 TargetStatus;\r
6ad55b15 3291\r
3292 FallStatus = EFI_SUCCESS;\r
1436aea4 3293 SenseDataLength = (UINT8)sizeof (EFI_SCSI_SENSE_DATA);\r
6ad55b15 3294\r
3295 ZeroMem (\r
3296 ScsiDiskDevice->SenseData,\r
3297 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)\r
3298 );\r
3299\r
1436aea4
MK
3300 *NumberOfSenseKeys = 0;\r
3301 *SenseDataArray = ScsiDiskDevice->SenseData;\r
3302 Status = EFI_SUCCESS;\r
3303 PtrSenseData = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_SENSE_DATA));\r
73a9e822
TF
3304 if (PtrSenseData == NULL) {\r
3305 return EFI_DEVICE_ERROR;\r
3306 }\r
6ad55b15 3307\r
3308 for (SenseReq = TRUE; SenseReq;) {\r
73a9e822 3309 ZeroMem (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
d35be2a4 3310 Status = ScsiRequestSenseCommand (\r
1436aea4
MK
3311 ScsiDiskDevice->ScsiIo,\r
3312 SCSI_DISK_TIMEOUT,\r
3313 PtrSenseData,\r
3314 &SenseDataLength,\r
3315 &HostAdapterStatus,\r
3316 &TargetStatus\r
3317 );\r
3318 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
3319 FallStatus = EFI_SUCCESS;\r
3320 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
3321 *NeedRetry = TRUE;\r
3322 FallStatus = EFI_DEVICE_ERROR;\r
3323 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
3324 *NeedRetry = FALSE;\r
3325 FallStatus = EFI_DEVICE_ERROR;\r
3326 } else if (Status == EFI_DEVICE_ERROR) {\r
3327 if (AskResetIfError) {\r
3328 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
3329 }\r
d1102dba 3330\r
1436aea4 3331 FallStatus = EFI_DEVICE_ERROR;\r
6ad55b15 3332 }\r
3333\r
3334 if (EFI_ERROR (FallStatus)) {\r
3335 if (*NumberOfSenseKeys != 0) {\r
3336 *NeedRetry = FALSE;\r
1436aea4 3337 Status = EFI_SUCCESS;\r
73a9e822 3338 goto EXIT;\r
6ad55b15 3339 } else {\r
73a9e822
TF
3340 Status = EFI_DEVICE_ERROR;\r
3341 goto EXIT;\r
6ad55b15 3342 }\r
3343 }\r
3344\r
73a9e822 3345 CopyMem (ScsiDiskDevice->SenseData + *NumberOfSenseKeys, PtrSenseData, SenseDataLength);\r
6ad55b15 3346 (*NumberOfSenseKeys) += 1;\r
3347\r
3348 //\r
3349 // no more sense key or number of sense keys exceeds predefined,\r
3350 // skip the loop.\r
3351 //\r
d1102dba 3352 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) ||\r
1436aea4
MK
3353 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber))\r
3354 {\r
6ad55b15 3355 SenseReq = FALSE;\r
3356 }\r
6ad55b15 3357 }\r
73a9e822
TF
3358\r
3359EXIT:\r
3360 FreeAlignedBuffer (PtrSenseData, sizeof (EFI_SCSI_SENSE_DATA));\r
3361 return Status;\r
6ad55b15 3362}\r
3363\r
9beb888e 3364/**\r
3365 Get information from media read capacity command.\r
6ad55b15 3366\r
9beb888e 3367 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
aa75dfec 3368 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
3369 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16\r
6ad55b15 3370\r
9beb888e 3371**/\r
3372VOID\r
3373GetMediaInfo (\r
aa75dfec 3374 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
3375 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,\r
3376 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16\r
9beb888e 3377 )\r
6ad55b15 3378{\r
1436aea4 3379 UINT8 *Ptr;\r
b96cd313 3380\r
f95bc048 3381 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4
MK
3382 ScsiDiskDevice->BlkIo.Media->LastBlock = ((UINT32)Capacity10->LastLba3 << 24) |\r
3383 (Capacity10->LastLba2 << 16) |\r
3384 (Capacity10->LastLba1 << 8) |\r
3385 Capacity10->LastLba0;\r
d1102dba 3386\r
b96cd313 3387 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |\r
d1102dba 3388 (Capacity10->BlockSize2 << 16) |\r
b96cd313 3389 (Capacity10->BlockSize1 << 8) |\r
1436aea4
MK
3390 Capacity10->BlockSize0;\r
3391 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;\r
3392 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 0;\r
b6e5da19 3393 if (!ScsiDiskDevice->BlockLimitsVpdSupported) {\r
1436aea4 3394 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;\r
b6e5da19 3395 }\r
b96cd313 3396 } else {\r
1436aea4 3397 Ptr = (UINT8 *)&ScsiDiskDevice->BlkIo.Media->LastBlock;\r
b96cd313 3398 *Ptr++ = Capacity16->LastLba0;\r
3399 *Ptr++ = Capacity16->LastLba1;\r
3400 *Ptr++ = Capacity16->LastLba2;\r
3401 *Ptr++ = Capacity16->LastLba3;\r
3402 *Ptr++ = Capacity16->LastLba4;\r
3403 *Ptr++ = Capacity16->LastLba5;\r
3404 *Ptr++ = Capacity16->LastLba6;\r
3405 *Ptr = Capacity16->LastLba7;\r
0e87144e 3406\r
b96cd313 3407 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |\r
d1102dba 3408 (Capacity16->BlockSize2 << 16) |\r
b96cd313 3409 (Capacity16->BlockSize1 << 8) |\r
1436aea4 3410 Capacity16->BlockSize0;\r
b96cd313 3411\r
0e87144e 3412 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8) |\r
1436aea4
MK
3413 Capacity16->LowestAlignLogic1;\r
3414 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = (1 << Capacity16->LogicPerPhysical);\r
b6e5da19 3415 if (!ScsiDiskDevice->BlockLimitsVpdSupported) {\r
1436aea4
MK
3416 if (ScsiDiskDevice->BlkIo.Media->LastBlock > (UINT32)-1) {\r
3417 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)-1;\r
b6e5da19 3418 } else {\r
1436aea4 3419 ScsiDiskDevice->UnmapInfo.MaxLbaCnt = (UINT32)ScsiDiskDevice->BlkIo.Media->LastBlock;\r
b6e5da19
HW
3420 }\r
3421 }\r
b96cd313 3422 }\r
3423\r
6ad55b15 3424 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
6ad55b15 3425}\r
3426\r
9beb888e 3427/**\r
3428 Parse Inquiry data.\r
3429\r
3430 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
3431\r
3432**/\r
6ad55b15 3433VOID\r
3434ParseInquiryData (\r
1436aea4 3435 IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
6ad55b15 3436 )\r
6ad55b15 3437{\r
1436aea4
MK
3438 ScsiDiskDevice->FixedDevice = (BOOLEAN)((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);\r
3439 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN)(!ScsiDiskDevice->FixedDevice);\r
6ad55b15 3440}\r
3441\r
9beb888e 3442/**\r
3443 Read sector from SCSI Disk.\r
6ad55b15 3444\r
d716651f 3445 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
9beb888e 3446 @param Buffer The buffer to fill in the read out data\r
3447 @param Lba Logic block address\r
3448 @param NumberOfBlocks The number of blocks to read\r
6ad55b15 3449\r
9beb888e 3450 @retval EFI_DEVICE_ERROR Indicates a device error.\r
3451 @retval EFI_SUCCESS Operation is successful.\r
6ad55b15 3452\r
9beb888e 3453**/\r
3454EFI_STATUS\r
3455ScsiDiskReadSectors (\r
1436aea4
MK
3456 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
3457 OUT VOID *Buffer,\r
3458 IN EFI_LBA Lba,\r
3459 IN UINTN NumberOfBlocks\r
9beb888e 3460 )\r
6ad55b15 3461{\r
1436aea4
MK
3462 UINTN BlocksRemaining;\r
3463 UINT8 *PtrBuffer;\r
3464 UINT32 BlockSize;\r
3465 UINT32 ByteCount;\r
3466 UINT32 MaxBlock;\r
3467 UINT32 SectorCount;\r
3468 UINT32 NextSectorCount;\r
3469 UINT64 Timeout;\r
3470 EFI_STATUS Status;\r
3471 UINT8 Index;\r
3472 UINT8 MaxRetry;\r
3473 BOOLEAN NeedRetry;\r
6ad55b15 3474\r
1436aea4 3475 Status = EFI_SUCCESS;\r
6ad55b15 3476\r
1436aea4
MK
3477 BlocksRemaining = NumberOfBlocks;\r
3478 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
d1102dba 3479\r
6ad55b15 3480 //\r
a108933e 3481 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
6ad55b15 3482 //\r
f95bc048 3483 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 3484 MaxBlock = 0xFFFF;\r
a108933e 3485 } else {\r
1436aea4 3486 MaxBlock = 0xFFFFFFFF;\r
a108933e 3487 }\r
6ad55b15 3488\r
3489 PtrBuffer = Buffer;\r
6ad55b15 3490\r
3491 while (BlocksRemaining > 0) {\r
6ad55b15 3492 if (BlocksRemaining <= MaxBlock) {\r
f95bc048 3493 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 3494 SectorCount = (UINT16)BlocksRemaining;\r
a108933e 3495 } else {\r
1436aea4 3496 SectorCount = (UINT32)BlocksRemaining;\r
a108933e 3497 }\r
6ad55b15 3498 } else {\r
6ad55b15 3499 SectorCount = MaxBlock;\r
3500 }\r
3501\r
3502 ByteCount = SectorCount * BlockSize;\r
9690325d 3503 //\r
3504 // |------------------------|-----------------|------------------|-----------------|\r
3505 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |\r
3506 // |------------------------|-----------------|------------------|-----------------|\r
3507 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |\r
3508 // |------------------------|-----------------|------------------|-----------------|\r
3509 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |\r
3510 // |------------------------|-----------------|------------------|-----------------|\r
3511 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |\r
3512 // |------------------------|-----------------|------------------|-----------------|\r
3513 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |\r
3514 // |------------------------|-----------------|------------------|-----------------|\r
3515 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |\r
3516 // |------------------------|-----------------|------------------|-----------------|\r
3517 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |\r
3518 // |------------------------|-----------------|------------------|-----------------|\r
3519 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |\r
3520 // |------------------------|-----------------|------------------|-----------------|\r
3521 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |\r
3522 // |------------------------|-----------------|------------------|-----------------|\r
3523 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |\r
3524 // |------------------------|-----------------|------------------|-----------------|\r
3525 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |\r
3526 // |------------------------|-----------------|------------------|-----------------|\r
3527 //\r
3528 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use\r
3529 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.\r
3530 // From the above table, we could know 2.1Mbytes per second is lowest one.\r
cc530cd1 3531 // The timeout value is rounded up to nearest integer and here an additional 30s is added\r
3cc033c5
FT
3532 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond\r
3533 // commands in the Standby/Idle mode.\r
9690325d 3534 //\r
1436aea4 3535 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);\r
6ad55b15 3536\r
1436aea4 3537 MaxRetry = 2;\r
6ad55b15 3538 for (Index = 0; Index < MaxRetry; Index++) {\r
f95bc048 3539 if (!ScsiDiskDevice->Cdb16Byte) {\r
3540 Status = ScsiDiskRead10 (\r
1436aea4
MK
3541 ScsiDiskDevice,\r
3542 &NeedRetry,\r
3543 Timeout,\r
3544 PtrBuffer,\r
3545 &ByteCount,\r
3546 (UINT32)Lba,\r
3547 SectorCount\r
3548 );\r
a108933e 3549 } else {\r
f95bc048 3550 Status = ScsiDiskRead16 (\r
1436aea4
MK
3551 ScsiDiskDevice,\r
3552 &NeedRetry,\r
3553 Timeout,\r
3554 PtrBuffer,\r
3555 &ByteCount,\r
3556 Lba,\r
3557 SectorCount\r
3558 );\r
a108933e 3559 }\r
1436aea4 3560\r
6ad55b15 3561 if (!EFI_ERROR (Status)) {\r
3562 break;\r
3563 }\r
3564\r
3565 if (!NeedRetry) {\r
3566 return EFI_DEVICE_ERROR;\r
3567 }\r
3568\r
5abc2a70
LE
3569 //\r
3570 // We need to retry. However, if ScsiDiskRead10() or ScsiDiskRead16() has\r
3571 // lowered ByteCount on output, we must make sure that we lower\r
3572 // SectorCount accordingly. SectorCount will be encoded in the CDB, and\r
3573 // it is invalid to request more sectors in the CDB than the entire\r
3574 // transfer (ie. ByteCount) can carry.\r
3575 //\r
cc530cd1 3576 // In addition, ByteCount is only expected to go down, or stay unchanged.\r
5abc2a70
LE
3577 // Therefore we don't need to update Timeout: the original timeout should\r
3578 // accommodate shorter transfers too.\r
3579 //\r
3580 NextSectorCount = ByteCount / BlockSize;\r
3581 if (NextSectorCount < SectorCount) {\r
3582 SectorCount = NextSectorCount;\r
3583 //\r
3584 // Account for any rounding down.\r
3585 //\r
3586 ByteCount = SectorCount * BlockSize;\r
3587 }\r
6ad55b15 3588 }\r
3589\r
3590 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
3591 return EFI_DEVICE_ERROR;\r
3592 }\r
3593\r
3594 //\r
3595 // actual transferred sectors\r
3596 //\r
3597 SectorCount = ByteCount / BlockSize;\r
3598\r
1436aea4
MK
3599 Lba += SectorCount;\r
3600 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
6ad55b15 3601 BlocksRemaining -= SectorCount;\r
3602 }\r
3603\r
3604 return EFI_SUCCESS;\r
3605}\r
3606\r
9beb888e 3607/**\r
3608 Write sector to SCSI Disk.\r
6ad55b15 3609\r
d716651f 3610 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
9beb888e 3611 @param Buffer The buffer of data to be written into SCSI Disk\r
3612 @param Lba Logic block address\r
3613 @param NumberOfBlocks The number of blocks to read\r
6ad55b15 3614\r
9beb888e 3615 @retval EFI_DEVICE_ERROR Indicates a device error.\r
3616 @retval EFI_SUCCESS Operation is successful.\r
6ad55b15 3617\r
9beb888e 3618**/\r
3619EFI_STATUS\r
3620ScsiDiskWriteSectors (\r
1436aea4
MK
3621 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
3622 IN VOID *Buffer,\r
3623 IN EFI_LBA Lba,\r
3624 IN UINTN NumberOfBlocks\r
9beb888e 3625 )\r
6ad55b15 3626{\r
1436aea4
MK
3627 UINTN BlocksRemaining;\r
3628 UINT8 *PtrBuffer;\r
3629 UINT32 BlockSize;\r
3630 UINT32 ByteCount;\r
3631 UINT32 MaxBlock;\r
3632 UINT32 SectorCount;\r
3633 UINT32 NextSectorCount;\r
3634 UINT64 Timeout;\r
3635 EFI_STATUS Status;\r
3636 UINT8 Index;\r
3637 UINT8 MaxRetry;\r
3638 BOOLEAN NeedRetry;\r
6ad55b15 3639\r
1436aea4 3640 Status = EFI_SUCCESS;\r
6ad55b15 3641\r
1436aea4
MK
3642 BlocksRemaining = NumberOfBlocks;\r
3643 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
a108933e 3644\r
6ad55b15 3645 //\r
a108933e 3646 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
6ad55b15 3647 //\r
f95bc048 3648 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 3649 MaxBlock = 0xFFFF;\r
a108933e 3650 } else {\r
1436aea4 3651 MaxBlock = 0xFFFFFFFF;\r
a108933e 3652 }\r
6ad55b15 3653\r
3654 PtrBuffer = Buffer;\r
6ad55b15 3655\r
3656 while (BlocksRemaining > 0) {\r
6ad55b15 3657 if (BlocksRemaining <= MaxBlock) {\r
f95bc048 3658 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 3659 SectorCount = (UINT16)BlocksRemaining;\r
a108933e 3660 } else {\r
1436aea4 3661 SectorCount = (UINT32)BlocksRemaining;\r
a108933e 3662 }\r
6ad55b15 3663 } else {\r
6ad55b15 3664 SectorCount = MaxBlock;\r
3665 }\r
3666\r
3667 ByteCount = SectorCount * BlockSize;\r
9690325d 3668 //\r
3669 // |------------------------|-----------------|------------------|-----------------|\r
3670 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |\r
3671 // |------------------------|-----------------|------------------|-----------------|\r
3672 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |\r
3673 // |------------------------|-----------------|------------------|-----------------|\r
3674 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |\r
3675 // |------------------------|-----------------|------------------|-----------------|\r
3676 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |\r
3677 // |------------------------|-----------------|------------------|-----------------|\r
3678 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |\r
3679 // |------------------------|-----------------|------------------|-----------------|\r
3680 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |\r
3681 // |------------------------|-----------------|------------------|-----------------|\r
3682 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |\r
3683 // |------------------------|-----------------|------------------|-----------------|\r
3684 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |\r
3685 // |------------------------|-----------------|------------------|-----------------|\r
3686 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |\r
3687 // |------------------------|-----------------|------------------|-----------------|\r
3688 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |\r
3689 // |------------------------|-----------------|------------------|-----------------|\r
3690 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |\r
3691 // |------------------------|-----------------|------------------|-----------------|\r
3692 //\r
3693 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices, we have to use\r
3694 // the lowest transfer rate to calculate the possible maximum timeout value for each operation.\r
3695 // From the above table, we could know 2.1Mbytes per second is lowest one.\r
cc530cd1 3696 // The timeout value is rounded up to nearest integer and here an additional 30s is added\r
3cc033c5
FT
3697 // to follow ATA spec in which it mentioned that the device may take up to 30s to respond\r
3698 // commands in the Standby/Idle mode.\r
9690325d 3699 //\r
1436aea4
MK
3700 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);\r
3701 MaxRetry = 2;\r
6ad55b15 3702 for (Index = 0; Index < MaxRetry; Index++) {\r
f95bc048 3703 if (!ScsiDiskDevice->Cdb16Byte) {\r
3704 Status = ScsiDiskWrite10 (\r
1436aea4
MK
3705 ScsiDiskDevice,\r
3706 &NeedRetry,\r
3707 Timeout,\r
3708 PtrBuffer,\r
3709 &ByteCount,\r
3710 (UINT32)Lba,\r
3711 SectorCount\r
3712 );\r
a108933e 3713 } else {\r
f95bc048 3714 Status = ScsiDiskWrite16 (\r
1436aea4
MK
3715 ScsiDiskDevice,\r
3716 &NeedRetry,\r
3717 Timeout,\r
3718 PtrBuffer,\r
3719 &ByteCount,\r
3720 Lba,\r
3721 SectorCount\r
3722 );\r
3723 }\r
3724\r
6ad55b15 3725 if (!EFI_ERROR (Status)) {\r
3726 break;\r
3727 }\r
3728\r
3729 if (!NeedRetry) {\r
3730 return EFI_DEVICE_ERROR;\r
3731 }\r
5abc2a70
LE
3732\r
3733 //\r
3734 // We need to retry. However, if ScsiDiskWrite10() or ScsiDiskWrite16()\r
3735 // has lowered ByteCount on output, we must make sure that we lower\r
3736 // SectorCount accordingly. SectorCount will be encoded in the CDB, and\r
3737 // it is invalid to request more sectors in the CDB than the entire\r
3738 // transfer (ie. ByteCount) can carry.\r
3739 //\r
cc530cd1 3740 // In addition, ByteCount is only expected to go down, or stay unchanged.\r
5abc2a70
LE
3741 // Therefore we don't need to update Timeout: the original timeout should\r
3742 // accommodate shorter transfers too.\r
3743 //\r
3744 NextSectorCount = ByteCount / BlockSize;\r
3745 if (NextSectorCount < SectorCount) {\r
3746 SectorCount = NextSectorCount;\r
3747 //\r
3748 // Account for any rounding down.\r
3749 //\r
3750 ByteCount = SectorCount * BlockSize;\r
3751 }\r
6ad55b15 3752 }\r
3753\r
3754 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
3755 return EFI_DEVICE_ERROR;\r
3756 }\r
1436aea4 3757\r
6ad55b15 3758 //\r
3759 // actual transferred sectors\r
3760 //\r
3761 SectorCount = ByteCount / BlockSize;\r
3762\r
1436aea4
MK
3763 Lba += SectorCount;\r
3764 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
6ad55b15 3765 BlocksRemaining -= SectorCount;\r
3766 }\r
3767\r
3768 return EFI_SUCCESS;\r
3769}\r
3770\r
d670bf53
HW
3771/**\r
3772 Asynchronously read sector from SCSI Disk.\r
3773\r
3774 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
3775 @param Buffer The buffer to fill in the read out data.\r
3776 @param Lba Logic block address.\r
3777 @param NumberOfBlocks The number of blocks to read.\r
3778 @param Token A pointer to the token associated with the\r
3779 non-blocking read request.\r
3780\r
3781 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL.\r
3782 @retval EFI_DEVICE_ERROR Indicates a device error.\r
3783 @retval EFI_SUCCESS Operation is successful.\r
3784\r
3785**/\r
3786EFI_STATUS\r
3787ScsiDiskAsyncReadSectors (\r
1436aea4
MK
3788 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
3789 OUT VOID *Buffer,\r
3790 IN EFI_LBA Lba,\r
3791 IN UINTN NumberOfBlocks,\r
3792 IN EFI_BLOCK_IO2_TOKEN *Token\r
d670bf53
HW
3793 )\r
3794{\r
1436aea4
MK
3795 UINTN BlocksRemaining;\r
3796 UINT8 *PtrBuffer;\r
3797 UINT32 BlockSize;\r
3798 UINT32 ByteCount;\r
3799 UINT32 MaxBlock;\r
3800 UINT32 SectorCount;\r
3801 UINT64 Timeout;\r
3802 SCSI_BLKIO2_REQUEST *BlkIo2Req;\r
3803 EFI_STATUS Status;\r
3804 EFI_TPL OldTpl;\r
d670bf53
HW
3805\r
3806 if ((Token == NULL) || (Token->Event == NULL)) {\r
3807 return EFI_INVALID_PARAMETER;\r
3808 }\r
3809\r
3810 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));\r
3811 if (BlkIo2Req == NULL) {\r
3812 return EFI_OUT_OF_RESOURCES;\r
3813 }\r
3814\r
1436aea4 3815 BlkIo2Req->Token = Token;\r
a717086c
HW
3816\r
3817 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
b6e5da19 3818 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);\r
a717086c
HW
3819 gBS->RestoreTPL (OldTpl);\r
3820\r
d670bf53
HW
3821 InitializeListHead (&BlkIo2Req->ScsiRWQueue);\r
3822\r
1436aea4 3823 Status = EFI_SUCCESS;\r
d670bf53 3824\r
1436aea4
MK
3825 BlocksRemaining = NumberOfBlocks;\r
3826 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
d670bf53
HW
3827\r
3828 //\r
3829 // Limit the data bytes that can be transferred by one Read(10) or Read(16)\r
3830 // Command\r
3831 //\r
3832 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 3833 MaxBlock = 0xFFFF;\r
d670bf53 3834 } else {\r
1436aea4 3835 MaxBlock = 0xFFFFFFFF;\r
d670bf53
HW
3836 }\r
3837\r
3838 PtrBuffer = Buffer;\r
3839\r
3840 while (BlocksRemaining > 0) {\r
d670bf53
HW
3841 if (BlocksRemaining <= MaxBlock) {\r
3842 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 3843 SectorCount = (UINT16)BlocksRemaining;\r
d670bf53 3844 } else {\r
1436aea4 3845 SectorCount = (UINT32)BlocksRemaining;\r
d670bf53
HW
3846 }\r
3847 } else {\r
3848 SectorCount = MaxBlock;\r
3849 }\r
3850\r
3851 ByteCount = SectorCount * BlockSize;\r
3852 //\r
3853 // |------------------------|-----------------|------------------|-----------------|\r
3854 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |\r
3855 // |------------------------|-----------------|------------------|-----------------|\r
3856 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |\r
3857 // |------------------------|-----------------|------------------|-----------------|\r
3858 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |\r
3859 // |------------------------|-----------------|------------------|-----------------|\r
3860 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |\r
3861 // |------------------------|-----------------|------------------|-----------------|\r
3862 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |\r
3863 // |------------------------|-----------------|------------------|-----------------|\r
3864 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |\r
3865 // |------------------------|-----------------|------------------|-----------------|\r
3866 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |\r
3867 // |------------------------|-----------------|------------------|-----------------|\r
3868 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |\r
3869 // |------------------------|-----------------|------------------|-----------------|\r
3870 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |\r
3871 // |------------------------|-----------------|------------------|-----------------|\r
3872 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |\r
3873 // |------------------------|-----------------|------------------|-----------------|\r
3874 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |\r
3875 // |------------------------|-----------------|------------------|-----------------|\r
3876 //\r
3877 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,\r
3878 // we have to use the lowest transfer rate to calculate the possible\r
3879 // maximum timeout value for each operation.\r
3880 // From the above table, we could know 2.1Mbytes per second is lowest one.\r
cc530cd1 3881 // The timeout value is rounded up to nearest integer and here an additional\r
d670bf53
HW
3882 // 30s is added to follow ATA spec in which it mentioned that the device\r
3883 // may take up to 30s to respond commands in the Standby/Idle mode.\r
3884 //\r
1436aea4 3885 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);\r
d670bf53
HW
3886\r
3887 if (!ScsiDiskDevice->Cdb16Byte) {\r
3888 Status = ScsiDiskAsyncRead10 (\r
3889 ScsiDiskDevice,\r
3890 Timeout,\r
032800ec 3891 0,\r
d670bf53
HW
3892 PtrBuffer,\r
3893 ByteCount,\r
1436aea4 3894 (UINT32)Lba,\r
d670bf53
HW
3895 SectorCount,\r
3896 BlkIo2Req,\r
3897 Token\r
3898 );\r
3899 } else {\r
3900 Status = ScsiDiskAsyncRead16 (\r
3901 ScsiDiskDevice,\r
3902 Timeout,\r
032800ec 3903 0,\r
d670bf53
HW
3904 PtrBuffer,\r
3905 ByteCount,\r
3906 Lba,\r
3907 SectorCount,\r
3908 BlkIo2Req,\r
3909 Token\r
3910 );\r
3911 }\r
1436aea4 3912\r
d670bf53
HW
3913 if (EFI_ERROR (Status)) {\r
3914 //\r
d7617bad
HW
3915 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data\r
3916 // length of a SCSI I/O command is too large.\r
3917 // In this case, we retry sending the SCSI command with a data length\r
3918 // half of its previous value.\r
d670bf53 3919 //\r
d7617bad
HW
3920 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
3921 if ((MaxBlock > 1) && (SectorCount > 1)) {\r
3922 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;\r
3923 continue;\r
3924 }\r
3925 }\r
3926\r
a717086c 3927 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 3928 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
d7617bad
HW
3929 //\r
3930 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other\r
3931 // SCSI sub-task running. Otherwise, it will be freed in the callback\r
3932 // function ScsiDiskNotify().\r
3933 //\r
d670bf53
HW
3934 RemoveEntryList (&BlkIo2Req->Link);\r
3935 FreePool (BlkIo2Req);\r
a717086c
HW
3936 BlkIo2Req = NULL;\r
3937 gBS->RestoreTPL (OldTpl);\r
d7617bad
HW
3938\r
3939 //\r
3940 // It is safe to return error status to the caller, since there is no\r
3941 // previous SCSI sub-task executing.\r
3942 //\r
a717086c
HW
3943 Status = EFI_DEVICE_ERROR;\r
3944 goto Done;\r
d7617bad 3945 } else {\r
a717086c
HW
3946 gBS->RestoreTPL (OldTpl);\r
3947\r
d7617bad
HW
3948 //\r
3949 // There are previous SCSI commands still running, EFI_SUCCESS should\r
3950 // be returned to make sure that the caller does not free resources\r
3951 // still using by these SCSI commands.\r
3952 //\r
a717086c
HW
3953 Status = EFI_SUCCESS;\r
3954 goto Done;\r
d670bf53 3955 }\r
d670bf53
HW
3956 }\r
3957\r
3958 //\r
3959 // Sectors submitted for transfer\r
3960 //\r
3961 SectorCount = ByteCount / BlockSize;\r
3962\r
1436aea4
MK
3963 Lba += SectorCount;\r
3964 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
d670bf53
HW
3965 BlocksRemaining -= SectorCount;\r
3966 }\r
3967\r
a717086c
HW
3968 Status = EFI_SUCCESS;\r
3969\r
3970Done:\r
3971 if (BlkIo2Req != NULL) {\r
3972 BlkIo2Req->LastScsiRW = TRUE;\r
3973\r
3974 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
3975 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
3976 RemoveEntryList (&BlkIo2Req->Link);\r
3977 FreePool (BlkIo2Req);\r
3978 BlkIo2Req = NULL;\r
3979\r
3980 gBS->SignalEvent (Token->Event);\r
3981 }\r
1436aea4 3982\r
a717086c
HW
3983 gBS->RestoreTPL (OldTpl);\r
3984 }\r
3985\r
3986 return Status;\r
d670bf53
HW
3987}\r
3988\r
3989/**\r
3990 Asynchronously write sector to SCSI Disk.\r
3991\r
3992 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
3993 @param Buffer The buffer of data to be written into SCSI Disk.\r
3994 @param Lba Logic block address.\r
3995 @param NumberOfBlocks The number of blocks to read.\r
3996 @param Token A pointer to the token associated with the\r
3997 non-blocking read request.\r
3998\r
3999 @retval EFI_INVALID_PARAMETER Token is NULL or Token->Event is NULL\r
4000 @retval EFI_DEVICE_ERROR Indicates a device error.\r
4001 @retval EFI_SUCCESS Operation is successful.\r
4002\r
4003**/\r
4004EFI_STATUS\r
4005ScsiDiskAsyncWriteSectors (\r
1436aea4
MK
4006 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
4007 IN VOID *Buffer,\r
4008 IN EFI_LBA Lba,\r
4009 IN UINTN NumberOfBlocks,\r
4010 IN EFI_BLOCK_IO2_TOKEN *Token\r
d670bf53
HW
4011 )\r
4012{\r
1436aea4
MK
4013 UINTN BlocksRemaining;\r
4014 UINT8 *PtrBuffer;\r
4015 UINT32 BlockSize;\r
4016 UINT32 ByteCount;\r
4017 UINT32 MaxBlock;\r
4018 UINT32 SectorCount;\r
4019 UINT64 Timeout;\r
4020 SCSI_BLKIO2_REQUEST *BlkIo2Req;\r
4021 EFI_STATUS Status;\r
4022 EFI_TPL OldTpl;\r
d670bf53
HW
4023\r
4024 if ((Token == NULL) || (Token->Event == NULL)) {\r
4025 return EFI_INVALID_PARAMETER;\r
4026 }\r
4027\r
4028 BlkIo2Req = AllocateZeroPool (sizeof (SCSI_BLKIO2_REQUEST));\r
4029 if (BlkIo2Req == NULL) {\r
4030 return EFI_OUT_OF_RESOURCES;\r
4031 }\r
4032\r
1436aea4 4033 BlkIo2Req->Token = Token;\r
a717086c
HW
4034\r
4035 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
b6e5da19 4036 InsertTailList (&ScsiDiskDevice->AsyncTaskQueue, &BlkIo2Req->Link);\r
a717086c
HW
4037 gBS->RestoreTPL (OldTpl);\r
4038\r
d670bf53
HW
4039 InitializeListHead (&BlkIo2Req->ScsiRWQueue);\r
4040\r
1436aea4 4041 Status = EFI_SUCCESS;\r
d670bf53 4042\r
1436aea4
MK
4043 BlocksRemaining = NumberOfBlocks;\r
4044 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
d670bf53
HW
4045\r
4046 //\r
4047 // Limit the data bytes that can be transferred by one Read(10) or Read(16)\r
4048 // Command\r
4049 //\r
4050 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 4051 MaxBlock = 0xFFFF;\r
d670bf53 4052 } else {\r
1436aea4 4053 MaxBlock = 0xFFFFFFFF;\r
d670bf53
HW
4054 }\r
4055\r
4056 PtrBuffer = Buffer;\r
4057\r
4058 while (BlocksRemaining > 0) {\r
d670bf53
HW
4059 if (BlocksRemaining <= MaxBlock) {\r
4060 if (!ScsiDiskDevice->Cdb16Byte) {\r
1436aea4 4061 SectorCount = (UINT16)BlocksRemaining;\r
d670bf53 4062 } else {\r
1436aea4 4063 SectorCount = (UINT32)BlocksRemaining;\r
d670bf53
HW
4064 }\r
4065 } else {\r
4066 SectorCount = MaxBlock;\r
4067 }\r
4068\r
4069 ByteCount = SectorCount * BlockSize;\r
4070 //\r
4071 // |------------------------|-----------------|------------------|-----------------|\r
4072 // | ATA Transfer Mode | Transfer Rate | SCSI Interface | Transfer Rate |\r
4073 // |------------------------|-----------------|------------------|-----------------|\r
4074 // | PIO Mode 0 | 3.3Mbytes/sec | SCSI-1 | 5Mbytes/sec |\r
4075 // |------------------------|-----------------|------------------|-----------------|\r
4076 // | PIO Mode 1 | 5.2Mbytes/sec | Fast SCSI | 10Mbytes/sec |\r
4077 // |------------------------|-----------------|------------------|-----------------|\r
4078 // | PIO Mode 2 | 8.3Mbytes/sec | Fast-Wide SCSI | 20Mbytes/sec |\r
4079 // |------------------------|-----------------|------------------|-----------------|\r
4080 // | PIO Mode 3 | 11.1Mbytes/sec | Ultra SCSI | 20Mbytes/sec |\r
4081 // |------------------------|-----------------|------------------|-----------------|\r
4082 // | PIO Mode 4 | 16.6Mbytes/sec | Ultra Wide SCSI | 40Mbytes/sec |\r
4083 // |------------------------|-----------------|------------------|-----------------|\r
4084 // | Single-word DMA Mode 0 | 2.1Mbytes/sec | Ultra2 SCSI | 40Mbytes/sec |\r
4085 // |------------------------|-----------------|------------------|-----------------|\r
4086 // | Single-word DMA Mode 1 | 4.2Mbytes/sec | Ultra2 Wide SCSI | 80Mbytes/sec |\r
4087 // |------------------------|-----------------|------------------|-----------------|\r
4088 // | Single-word DMA Mode 2 | 8.4Mbytes/sec | Ultra3 SCSI | 160Mbytes/sec |\r
4089 // |------------------------|-----------------|------------------|-----------------|\r
4090 // | Multi-word DMA Mode 0 | 4.2Mbytes/sec | Ultra-320 SCSI | 320Mbytes/sec |\r
4091 // |------------------------|-----------------|------------------|-----------------|\r
4092 // | Multi-word DMA Mode 1 | 13.3Mbytes/sec | Ultra-640 SCSI | 640Mbytes/sec |\r
4093 // |------------------------|-----------------|------------------|-----------------|\r
4094 //\r
4095 // As ScsiDisk and ScsiBus driver are used to manage SCSI or ATAPI devices,\r
4096 // we have to use the lowest transfer rate to calculate the possible\r
4097 // maximum timeout value for each operation.\r
4098 // From the above table, we could know 2.1Mbytes per second is lowest one.\r
cc530cd1 4099 // The timeout value is rounded up to nearest integer and here an additional\r
d670bf53
HW
4100 // 30s is added to follow ATA spec in which it mentioned that the device\r
4101 // may take up to 30s to respond commands in the Standby/Idle mode.\r
4102 //\r
1436aea4 4103 Timeout = EFI_TIMER_PERIOD_SECONDS (ByteCount / 2100000 + 31);\r
d670bf53
HW
4104\r
4105 if (!ScsiDiskDevice->Cdb16Byte) {\r
4106 Status = ScsiDiskAsyncWrite10 (\r
4107 ScsiDiskDevice,\r
4108 Timeout,\r
032800ec 4109 0,\r
d670bf53
HW
4110 PtrBuffer,\r
4111 ByteCount,\r
1436aea4 4112 (UINT32)Lba,\r
d670bf53
HW
4113 SectorCount,\r
4114 BlkIo2Req,\r
4115 Token\r
4116 );\r
4117 } else {\r
4118 Status = ScsiDiskAsyncWrite16 (\r
4119 ScsiDiskDevice,\r
4120 Timeout,\r
032800ec 4121 0,\r
d670bf53
HW
4122 PtrBuffer,\r
4123 ByteCount,\r
4124 Lba,\r
4125 SectorCount,\r
4126 BlkIo2Req,\r
4127 Token\r
4128 );\r
4129 }\r
1436aea4 4130\r
d670bf53
HW
4131 if (EFI_ERROR (Status)) {\r
4132 //\r
d7617bad
HW
4133 // Some devices will return EFI_DEVICE_ERROR or EFI_TIMEOUT when the data\r
4134 // length of a SCSI I/O command is too large.\r
4135 // In this case, we retry sending the SCSI command with a data length\r
4136 // half of its previous value.\r
d670bf53 4137 //\r
d7617bad
HW
4138 if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {\r
4139 if ((MaxBlock > 1) && (SectorCount > 1)) {\r
4140 MaxBlock = MIN (MaxBlock, SectorCount) >> 1;\r
4141 continue;\r
4142 }\r
4143 }\r
4144\r
a717086c 4145 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 4146 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
d7617bad
HW
4147 //\r
4148 // Free the SCSI_BLKIO2_REQUEST structure only when there is no other\r
4149 // SCSI sub-task running. Otherwise, it will be freed in the callback\r
4150 // function ScsiDiskNotify().\r
4151 //\r
d670bf53
HW
4152 RemoveEntryList (&BlkIo2Req->Link);\r
4153 FreePool (BlkIo2Req);\r
a717086c
HW
4154 BlkIo2Req = NULL;\r
4155 gBS->RestoreTPL (OldTpl);\r
d7617bad
HW
4156\r
4157 //\r
4158 // It is safe to return error status to the caller, since there is no\r
4159 // previous SCSI sub-task executing.\r
4160 //\r
a717086c
HW
4161 Status = EFI_DEVICE_ERROR;\r
4162 goto Done;\r
d7617bad 4163 } else {\r
a717086c
HW
4164 gBS->RestoreTPL (OldTpl);\r
4165\r
d7617bad
HW
4166 //\r
4167 // There are previous SCSI commands still running, EFI_SUCCESS should\r
4168 // be returned to make sure that the caller does not free resources\r
4169 // still using by these SCSI commands.\r
4170 //\r
a717086c
HW
4171 Status = EFI_SUCCESS;\r
4172 goto Done;\r
d670bf53 4173 }\r
d670bf53
HW
4174 }\r
4175\r
4176 //\r
4177 // Sectors submitted for transfer\r
4178 //\r
4179 SectorCount = ByteCount / BlockSize;\r
4180\r
1436aea4
MK
4181 Lba += SectorCount;\r
4182 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
d670bf53
HW
4183 BlocksRemaining -= SectorCount;\r
4184 }\r
4185\r
a717086c
HW
4186 Status = EFI_SUCCESS;\r
4187\r
4188Done:\r
4189 if (BlkIo2Req != NULL) {\r
4190 BlkIo2Req->LastScsiRW = TRUE;\r
4191\r
4192 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
4193 if (IsListEmpty (&BlkIo2Req->ScsiRWQueue)) {\r
4194 RemoveEntryList (&BlkIo2Req->Link);\r
4195 FreePool (BlkIo2Req);\r
4196 BlkIo2Req = NULL;\r
4197\r
4198 gBS->SignalEvent (Token->Event);\r
4199 }\r
1436aea4 4200\r
a717086c
HW
4201 gBS->RestoreTPL (OldTpl);\r
4202 }\r
4203\r
4204 return Status;\r
d670bf53
HW
4205}\r
4206\r
9beb888e 4207/**\r
a108933e 4208 Submit Read(10) command.\r
9beb888e 4209\r
4210 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
4211 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
9beb888e 4212 @param Timeout The time to complete the command\r
4213 @param DataBuffer The buffer to fill with the read out data\r
4214 @param DataLength The length of buffer\r
4215 @param StartLba The start logic block address\r
73a9e822 4216 @param SectorCount The number of blocks to read\r
9beb888e 4217\r
4218 @return EFI_STATUS is returned by calling ScsiRead10Command().\r
4219**/\r
6ad55b15 4220EFI_STATUS\r
4221ScsiDiskRead10 (\r
1436aea4
MK
4222 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
4223 OUT BOOLEAN *NeedRetry,\r
4224 IN UINT64 Timeout,\r
4225 OUT UINT8 *DataBuffer,\r
4226 IN OUT UINT32 *DataLength,\r
4227 IN UINT32 StartLba,\r
4228 IN UINT32 SectorCount\r
6ad55b15 4229 )\r
6ad55b15 4230{\r
4231 UINT8 SenseDataLength;\r
4232 EFI_STATUS Status;\r
52f8e370 4233 EFI_STATUS ReturnStatus;\r
6ad55b15 4234 UINT8 HostAdapterStatus;\r
4235 UINT8 TargetStatus;\r
52f8e370 4236 UINTN Action;\r
6ad55b15 4237\r
73a9e822 4238 //\r
cc530cd1 4239 // Implement a backoff algorithm to resolve some compatibility issues that\r
73a9e822
TF
4240 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
4241 // big data in a single operation.\r
cc530cd1 4242 // This algorithm will at first try to execute original request. If the request fails\r
73a9e822
TF
4243 // with media error sense data or else, it will reduce the transfer length to half and\r
4244 // try again till the operation succeeds or fails with one sector transfer length.\r
4245 //\r
4246BackOff:\r
1436aea4
MK
4247 *NeedRetry = FALSE;\r
4248 Action = ACTION_NO_ACTION;\r
4249 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
4250 ReturnStatus = ScsiRead10Command (\r
4251 ScsiDiskDevice->ScsiIo,\r
4252 Timeout,\r
4253 ScsiDiskDevice->SenseData,\r
4254 &SenseDataLength,\r
4255 &HostAdapterStatus,\r
4256 &TargetStatus,\r
4257 DataBuffer,\r
4258 DataLength,\r
4259 StartLba,\r
4260 SectorCount\r
4261 );\r
52f8e370 4262\r
1436aea4 4263 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {\r
52f8e370
TF
4264 *NeedRetry = TRUE;\r
4265 return EFI_DEVICE_ERROR;\r
4266 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {\r
4267 *NeedRetry = FALSE;\r
4268 return ReturnStatus;\r
4269 }\r
4270\r
4271 //\r
4272 // go ahead to check HostAdapterStatus and TargetStatus\r
4273 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
4274 //\r
4275 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
4276 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
4277 *NeedRetry = TRUE;\r
4278 return EFI_DEVICE_ERROR;\r
4279 } else if (Status == EFI_DEVICE_ERROR) {\r
4280 //\r
4281 // reset the scsi channel\r
4282 //\r
4283 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
4284 *NeedRetry = FALSE;\r
4285 return EFI_DEVICE_ERROR;\r
4286 }\r
4287\r
4288 Status = CheckTargetStatus (TargetStatus);\r
4289 if (Status == EFI_NOT_READY) {\r
4290 //\r
4291 // reset the scsi device\r
4292 //\r
4293 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
4294 *NeedRetry = TRUE;\r
4295 return EFI_DEVICE_ERROR;\r
4296 } else if (Status == EFI_DEVICE_ERROR) {\r
4297 *NeedRetry = FALSE;\r
4298 return EFI_DEVICE_ERROR;\r
4299 }\r
4300\r
73a9e822 4301 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
87000d77 4302 DEBUG ((DEBUG_ERROR, "ScsiDiskRead10: Check Condition happened!\n"));\r
eae9e51d 4303 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
73a9e822 4304 if (Action == ACTION_RETRY_COMMAND_LATER) {\r
52f8e370
TF
4305 *NeedRetry = TRUE;\r
4306 return EFI_DEVICE_ERROR;\r
73a9e822
TF
4307 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
4308 if (SectorCount <= 1) {\r
4309 //\r
4310 // Jump out if the operation still fails with one sector transfer length.\r
4311 //\r
4312 *NeedRetry = FALSE;\r
4313 return EFI_DEVICE_ERROR;\r
4314 }\r
1436aea4 4315\r
73a9e822
TF
4316 //\r
4317 // Try again with half length if the sense data shows we need to retry.\r
4318 //\r
4319 SectorCount >>= 1;\r
1436aea4 4320 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
73a9e822 4321 goto BackOff;\r
52f8e370
TF
4322 } else {\r
4323 *NeedRetry = FALSE;\r
4324 return EFI_DEVICE_ERROR;\r
4325 }\r
4326 }\r
4327\r
4328 return ReturnStatus;\r
6ad55b15 4329}\r
4330\r
9beb888e 4331/**\r
a108933e 4332 Submit Write(10) Command.\r
6ad55b15 4333\r
9beb888e 4334 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
4335 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
9beb888e 4336 @param Timeout The time to complete the command\r
4337 @param DataBuffer The buffer to fill with the read out data\r
4338 @param DataLength The length of buffer\r
4339 @param StartLba The start logic block address\r
73a9e822 4340 @param SectorCount The number of blocks to write\r
6ad55b15 4341\r
9beb888e 4342 @return EFI_STATUS is returned by calling ScsiWrite10Command().\r
6ad55b15 4343\r
9beb888e 4344**/\r
4345EFI_STATUS\r
4346ScsiDiskWrite10 (\r
1436aea4
MK
4347 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
4348 OUT BOOLEAN *NeedRetry,\r
4349 IN UINT64 Timeout,\r
4350 IN UINT8 *DataBuffer,\r
4351 IN OUT UINT32 *DataLength,\r
4352 IN UINT32 StartLba,\r
4353 IN UINT32 SectorCount\r
9beb888e 4354 )\r
6ad55b15 4355{\r
4356 EFI_STATUS Status;\r
52f8e370 4357 EFI_STATUS ReturnStatus;\r
6ad55b15 4358 UINT8 SenseDataLength;\r
4359 UINT8 HostAdapterStatus;\r
4360 UINT8 TargetStatus;\r
52f8e370 4361 UINTN Action;\r
6ad55b15 4362\r
73a9e822 4363 //\r
cc530cd1 4364 // Implement a backoff algorithm to resolve some compatibility issues that\r
73a9e822
TF
4365 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
4366 // big data in a single operation.\r
cc530cd1 4367 // This algorithm will at first try to execute original request. If the request fails\r
73a9e822
TF
4368 // with media error sense data or else, it will reduce the transfer length to half and\r
4369 // try again till the operation succeeds or fails with one sector transfer length.\r
4370 //\r
4371BackOff:\r
1436aea4
MK
4372 *NeedRetry = FALSE;\r
4373 Action = ACTION_NO_ACTION;\r
4374 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
4375 ReturnStatus = ScsiWrite10Command (\r
4376 ScsiDiskDevice->ScsiIo,\r
4377 Timeout,\r
4378 ScsiDiskDevice->SenseData,\r
4379 &SenseDataLength,\r
4380 &HostAdapterStatus,\r
4381 &TargetStatus,\r
4382 DataBuffer,\r
4383 DataLength,\r
4384 StartLba,\r
4385 SectorCount\r
4386 );\r
4387 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {\r
52f8e370
TF
4388 *NeedRetry = TRUE;\r
4389 return EFI_DEVICE_ERROR;\r
4390 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {\r
4391 *NeedRetry = FALSE;\r
4392 return ReturnStatus;\r
4393 }\r
4394\r
4395 //\r
4396 // go ahead to check HostAdapterStatus and TargetStatus\r
4397 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
4398 //\r
4399 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
4400 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
4401 *NeedRetry = TRUE;\r
4402 return EFI_DEVICE_ERROR;\r
4403 } else if (Status == EFI_DEVICE_ERROR) {\r
4404 //\r
4405 // reset the scsi channel\r
4406 //\r
4407 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
4408 *NeedRetry = FALSE;\r
4409 return EFI_DEVICE_ERROR;\r
4410 }\r
4411\r
4412 Status = CheckTargetStatus (TargetStatus);\r
4413 if (Status == EFI_NOT_READY) {\r
4414 //\r
4415 // reset the scsi device\r
4416 //\r
4417 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
4418 *NeedRetry = TRUE;\r
4419 return EFI_DEVICE_ERROR;\r
4420 } else if (Status == EFI_DEVICE_ERROR) {\r
4421 *NeedRetry = FALSE;\r
4422 return EFI_DEVICE_ERROR;\r
4423 }\r
4424\r
73a9e822 4425 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
87000d77 4426 DEBUG ((DEBUG_ERROR, "ScsiDiskWrite10: Check Condition happened!\n"));\r
eae9e51d 4427 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
73a9e822 4428 if (Action == ACTION_RETRY_COMMAND_LATER) {\r
52f8e370
TF
4429 *NeedRetry = TRUE;\r
4430 return EFI_DEVICE_ERROR;\r
73a9e822
TF
4431 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
4432 if (SectorCount <= 1) {\r
4433 //\r
4434 // Jump out if the operation still fails with one sector transfer length.\r
4435 //\r
4436 *NeedRetry = FALSE;\r
4437 return EFI_DEVICE_ERROR;\r
4438 }\r
1436aea4 4439\r
73a9e822
TF
4440 //\r
4441 // Try again with half length if the sense data shows we need to retry.\r
4442 //\r
4443 SectorCount >>= 1;\r
1436aea4 4444 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
73a9e822 4445 goto BackOff;\r
52f8e370
TF
4446 } else {\r
4447 *NeedRetry = FALSE;\r
4448 return EFI_DEVICE_ERROR;\r
4449 }\r
4450 }\r
4451\r
4452 return ReturnStatus;\r
6ad55b15 4453}\r
4454\r
a108933e 4455/**\r
4456 Submit Read(16) command.\r
4457\r
4458 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
4459 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
a108933e 4460 @param Timeout The time to complete the command\r
4461 @param DataBuffer The buffer to fill with the read out data\r
4462 @param DataLength The length of buffer\r
4463 @param StartLba The start logic block address\r
73a9e822 4464 @param SectorCount The number of blocks to read\r
a108933e 4465\r
73a9e822 4466 @return EFI_STATUS is returned by calling ScsiRead16Command().\r
a108933e 4467**/\r
4468EFI_STATUS\r
4469ScsiDiskRead16 (\r
1436aea4
MK
4470 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
4471 OUT BOOLEAN *NeedRetry,\r
4472 IN UINT64 Timeout,\r
4473 OUT UINT8 *DataBuffer,\r
4474 IN OUT UINT32 *DataLength,\r
4475 IN UINT64 StartLba,\r
4476 IN UINT32 SectorCount\r
a108933e 4477 )\r
4478{\r
4479 UINT8 SenseDataLength;\r
4480 EFI_STATUS Status;\r
52f8e370 4481 EFI_STATUS ReturnStatus;\r
a108933e 4482 UINT8 HostAdapterStatus;\r
4483 UINT8 TargetStatus;\r
52f8e370 4484 UINTN Action;\r
a108933e 4485\r
73a9e822 4486 //\r
cc530cd1 4487 // Implement a backoff algorithm to resolve some compatibility issues that\r
73a9e822
TF
4488 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
4489 // big data in a single operation.\r
cc530cd1 4490 // This algorithm will at first try to execute original request. If the request fails\r
73a9e822
TF
4491 // with media error sense data or else, it will reduce the transfer length to half and\r
4492 // try again till the operation succeeds or fails with one sector transfer length.\r
4493 //\r
4494BackOff:\r
1436aea4
MK
4495 *NeedRetry = FALSE;\r
4496 Action = ACTION_NO_ACTION;\r
4497 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
4498 ReturnStatus = ScsiRead16Command (\r
4499 ScsiDiskDevice->ScsiIo,\r
4500 Timeout,\r
4501 ScsiDiskDevice->SenseData,\r
4502 &SenseDataLength,\r
4503 &HostAdapterStatus,\r
4504 &TargetStatus,\r
4505 DataBuffer,\r
4506 DataLength,\r
4507 StartLba,\r
4508 SectorCount\r
4509 );\r
4510 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {\r
52f8e370
TF
4511 *NeedRetry = TRUE;\r
4512 return EFI_DEVICE_ERROR;\r
4513 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {\r
4514 *NeedRetry = FALSE;\r
4515 return ReturnStatus;\r
4516 }\r
4517\r
4518 //\r
4519 // go ahead to check HostAdapterStatus and TargetStatus\r
4520 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
4521 //\r
4522 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
4523 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
4524 *NeedRetry = TRUE;\r
4525 return EFI_DEVICE_ERROR;\r
4526 } else if (Status == EFI_DEVICE_ERROR) {\r
4527 //\r
4528 // reset the scsi channel\r
4529 //\r
4530 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
4531 *NeedRetry = FALSE;\r
4532 return EFI_DEVICE_ERROR;\r
4533 }\r
4534\r
4535 Status = CheckTargetStatus (TargetStatus);\r
4536 if (Status == EFI_NOT_READY) {\r
4537 //\r
4538 // reset the scsi device\r
4539 //\r
4540 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
4541 *NeedRetry = TRUE;\r
4542 return EFI_DEVICE_ERROR;\r
4543 } else if (Status == EFI_DEVICE_ERROR) {\r
4544 *NeedRetry = FALSE;\r
4545 return EFI_DEVICE_ERROR;\r
4546 }\r
4547\r
73a9e822 4548 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
87000d77 4549 DEBUG ((DEBUG_ERROR, "ScsiDiskRead16: Check Condition happened!\n"));\r
eae9e51d 4550 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
73a9e822 4551 if (Action == ACTION_RETRY_COMMAND_LATER) {\r
52f8e370
TF
4552 *NeedRetry = TRUE;\r
4553 return EFI_DEVICE_ERROR;\r
73a9e822
TF
4554 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
4555 if (SectorCount <= 1) {\r
4556 //\r
4557 // Jump out if the operation still fails with one sector transfer length.\r
4558 //\r
4559 *NeedRetry = FALSE;\r
4560 return EFI_DEVICE_ERROR;\r
4561 }\r
1436aea4 4562\r
73a9e822
TF
4563 //\r
4564 // Try again with half length if the sense data shows we need to retry.\r
4565 //\r
4566 SectorCount >>= 1;\r
1436aea4 4567 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
73a9e822 4568 goto BackOff;\r
52f8e370
TF
4569 } else {\r
4570 *NeedRetry = FALSE;\r
4571 return EFI_DEVICE_ERROR;\r
4572 }\r
4573 }\r
4574\r
4575 return ReturnStatus;\r
a108933e 4576}\r
4577\r
a108933e 4578/**\r
4579 Submit Write(16) Command.\r
4580\r
4581 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
4582 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
a108933e 4583 @param Timeout The time to complete the command\r
4584 @param DataBuffer The buffer to fill with the read out data\r
4585 @param DataLength The length of buffer\r
4586 @param StartLba The start logic block address\r
73a9e822 4587 @param SectorCount The number of blocks to write\r
a108933e 4588\r
73a9e822 4589 @return EFI_STATUS is returned by calling ScsiWrite16Command().\r
a108933e 4590\r
4591**/\r
4592EFI_STATUS\r
4593ScsiDiskWrite16 (\r
1436aea4
MK
4594 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
4595 OUT BOOLEAN *NeedRetry,\r
4596 IN UINT64 Timeout,\r
4597 IN UINT8 *DataBuffer,\r
4598 IN OUT UINT32 *DataLength,\r
4599 IN UINT64 StartLba,\r
4600 IN UINT32 SectorCount\r
a108933e 4601 )\r
4602{\r
4603 EFI_STATUS Status;\r
52f8e370 4604 EFI_STATUS ReturnStatus;\r
a108933e 4605 UINT8 SenseDataLength;\r
4606 UINT8 HostAdapterStatus;\r
4607 UINT8 TargetStatus;\r
52f8e370 4608 UINTN Action;\r
a108933e 4609\r
73a9e822 4610 //\r
cc530cd1 4611 // Implement a backoff algorithm to resolve some compatibility issues that\r
73a9e822
TF
4612 // some SCSI targets or ATAPI devices couldn't correctly response reading/writing\r
4613 // big data in a single operation.\r
cc530cd1 4614 // This algorithm will at first try to execute original request. If the request fails\r
73a9e822
TF
4615 // with media error sense data or else, it will reduce the transfer length to half and\r
4616 // try again till the operation succeeds or fails with one sector transfer length.\r
4617 //\r
4618BackOff:\r
1436aea4
MK
4619 *NeedRetry = FALSE;\r
4620 Action = ACTION_NO_ACTION;\r
4621 SenseDataLength = (UINT8)(ScsiDiskDevice->SenseDataNumber * sizeof (EFI_SCSI_SENSE_DATA));\r
4622 ReturnStatus = ScsiWrite16Command (\r
4623 ScsiDiskDevice->ScsiIo,\r
4624 Timeout,\r
4625 ScsiDiskDevice->SenseData,\r
4626 &SenseDataLength,\r
4627 &HostAdapterStatus,\r
4628 &TargetStatus,\r
4629 DataBuffer,\r
4630 DataLength,\r
4631 StartLba,\r
4632 SectorCount\r
4633 );\r
4634 if ((ReturnStatus == EFI_NOT_READY) || (ReturnStatus == EFI_BAD_BUFFER_SIZE)) {\r
52f8e370
TF
4635 *NeedRetry = TRUE;\r
4636 return EFI_DEVICE_ERROR;\r
4637 } else if ((ReturnStatus == EFI_INVALID_PARAMETER) || (ReturnStatus == EFI_UNSUPPORTED)) {\r
4638 *NeedRetry = FALSE;\r
4639 return ReturnStatus;\r
4640 }\r
4641\r
4642 //\r
4643 // go ahead to check HostAdapterStatus and TargetStatus\r
4644 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
4645 //\r
4646 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
4647 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
4648 *NeedRetry = TRUE;\r
4649 return EFI_DEVICE_ERROR;\r
4650 } else if (Status == EFI_DEVICE_ERROR) {\r
4651 //\r
4652 // reset the scsi channel\r
4653 //\r
4654 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
4655 *NeedRetry = FALSE;\r
4656 return EFI_DEVICE_ERROR;\r
4657 }\r
4658\r
4659 Status = CheckTargetStatus (TargetStatus);\r
4660 if (Status == EFI_NOT_READY) {\r
4661 //\r
4662 // reset the scsi device\r
4663 //\r
4664 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
4665 *NeedRetry = TRUE;\r
4666 return EFI_DEVICE_ERROR;\r
4667 } else if (Status == EFI_DEVICE_ERROR) {\r
4668 *NeedRetry = FALSE;\r
4669 return EFI_DEVICE_ERROR;\r
4670 }\r
4671\r
73a9e822 4672 if ((TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) || (EFI_ERROR (ReturnStatus))) {\r
87000d77 4673 DEBUG ((DEBUG_ERROR, "ScsiDiskWrite16: Check Condition happened!\n"));\r
eae9e51d 4674 DetectMediaParsingSenseKeys (ScsiDiskDevice, ScsiDiskDevice->SenseData, SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA), &Action);\r
73a9e822 4675 if (Action == ACTION_RETRY_COMMAND_LATER) {\r
52f8e370
TF
4676 *NeedRetry = TRUE;\r
4677 return EFI_DEVICE_ERROR;\r
73a9e822
TF
4678 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
4679 if (SectorCount <= 1) {\r
4680 //\r
4681 // Jump out if the operation still fails with one sector transfer length.\r
4682 //\r
4683 *NeedRetry = FALSE;\r
4684 return EFI_DEVICE_ERROR;\r
4685 }\r
1436aea4 4686\r
73a9e822
TF
4687 //\r
4688 // Try again with half length if the sense data shows we need to retry.\r
4689 //\r
4690 SectorCount >>= 1;\r
1436aea4 4691 *DataLength = SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
73a9e822 4692 goto BackOff;\r
52f8e370
TF
4693 } else {\r
4694 *NeedRetry = FALSE;\r
4695 return EFI_DEVICE_ERROR;\r
4696 }\r
4697 }\r
4698\r
4699 return ReturnStatus;\r
a108933e 4700}\r
4701\r
d670bf53
HW
4702/**\r
4703 Internal helper notify function in which determine whether retry of a SCSI\r
4704 Read/Write command is needed and signal the event passed from Block I/O(2) if\r
4705 the SCSI I/O operation completes.\r
4706\r
4707 @param Event The instance of EFI_EVENT.\r
4708 @param Context The parameter passed in.\r
4709\r
4710**/\r
4711VOID\r
4712EFIAPI\r
4713ScsiDiskNotify (\r
4714 IN EFI_EVENT Event,\r
4715 IN VOID *Context\r
4716 )\r
4717{\r
1436aea4
MK
4718 EFI_STATUS Status;\r
4719 SCSI_ASYNC_RW_REQUEST *Request;\r
4720 SCSI_DISK_DEV *ScsiDiskDevice;\r
4721 EFI_BLOCK_IO2_TOKEN *Token;\r
4722 UINTN Action;\r
4723 UINT32 OldDataLength;\r
4724 UINT32 OldSectorCount;\r
4725 UINT8 MaxRetry;\r
d670bf53
HW
4726\r
4727 gBS->CloseEvent (Event);\r
4728\r
1436aea4
MK
4729 Request = (SCSI_ASYNC_RW_REQUEST *)Context;\r
4730 ScsiDiskDevice = Request->ScsiDiskDevice;\r
4731 Token = Request->BlkIo2Req->Token;\r
4732 OldDataLength = Request->DataLength;\r
4733 OldSectorCount = Request->SectorCount;\r
4734 MaxRetry = 2;\r
d670bf53
HW
4735\r
4736 //\r
4737 // If previous sub-tasks already fails, no need to process this sub-task.\r
4738 //\r
4739 if (Token->TransactionStatus != EFI_SUCCESS) {\r
4740 goto Exit;\r
4741 }\r
4742\r
4743 //\r
4744 // Check HostAdapterStatus and TargetStatus\r
4745 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
4746 //\r
4747 Status = CheckHostAdapterStatus (Request->HostAdapterStatus);\r
4748 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
4749 if (++Request->TimesRetry > MaxRetry) {\r
4750 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4751 goto Exit;\r
4752 } else {\r
4753 goto Retry;\r
4754 }\r
4755 } else if (Status == EFI_DEVICE_ERROR) {\r
4756 //\r
4757 // reset the scsi channel\r
4758 //\r
4759 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
4760 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4761 goto Exit;\r
4762 }\r
4763\r
4764 Status = CheckTargetStatus (Request->TargetStatus);\r
4765 if (Status == EFI_NOT_READY) {\r
4766 //\r
4767 // reset the scsi device\r
4768 //\r
4769 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
4770 if (++Request->TimesRetry > MaxRetry) {\r
4771 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4772 goto Exit;\r
4773 } else {\r
4774 goto Retry;\r
4775 }\r
4776 } else if (Status == EFI_DEVICE_ERROR) {\r
4777 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4778 goto Exit;\r
4779 }\r
4780\r
4781 if (Request->TargetStatus == EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION) {\r
87000d77 4782 DEBUG ((DEBUG_ERROR, "ScsiDiskNotify: Check Condition happened!\n"));\r
d670bf53 4783\r
eae9e51d
S
4784 DetectMediaParsingSenseKeys (\r
4785 ScsiDiskDevice,\r
4786 Request->SenseData,\r
4787 Request->SenseDataLength / sizeof (EFI_SCSI_SENSE_DATA),\r
4788 &Action\r
4789 );\r
d670bf53
HW
4790 if (Action == ACTION_RETRY_COMMAND_LATER) {\r
4791 if (++Request->TimesRetry > MaxRetry) {\r
4792 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4793 goto Exit;\r
4794 } else {\r
4795 goto Retry;\r
4796 }\r
4797 } else if (Action == ACTION_RETRY_WITH_BACKOFF_ALGO) {\r
4798 if (Request->SectorCount <= 1) {\r
4799 //\r
4800 // Jump out if the operation still fails with one sector transfer\r
4801 // length.\r
4802 //\r
4803 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4804 goto Exit;\r
4805 }\r
1436aea4 4806\r
d670bf53
HW
4807 //\r
4808 // Try again with two half length request if the sense data shows we need\r
4809 // to retry.\r
4810 //\r
4811 Request->SectorCount >>= 1;\r
1436aea4
MK
4812 Request->DataLength = Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize;\r
4813 Request->TimesRetry = 0;\r
d670bf53
HW
4814\r
4815 goto Retry;\r
4816 } else {\r
4817 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4818 goto Exit;\r
4819 }\r
4820 }\r
4821\r
4822 //\r
4823 // This sub-task succeeds, no need to retry.\r
4824 //\r
4825 goto Exit;\r
4826\r
4827Retry:\r
4828 if (Request->InBuffer != NULL) {\r
4829 //\r
4830 // SCSI read command\r
4831 //\r
4832 if (!ScsiDiskDevice->Cdb16Byte) {\r
4833 Status = ScsiDiskAsyncRead10 (\r
4834 ScsiDiskDevice,\r
4835 Request->Timeout,\r
032800ec 4836 Request->TimesRetry,\r
d670bf53
HW
4837 Request->InBuffer,\r
4838 Request->DataLength,\r
1436aea4 4839 (UINT32)Request->StartLba,\r
d670bf53
HW
4840 Request->SectorCount,\r
4841 Request->BlkIo2Req,\r
4842 Token\r
4843 );\r
4844 } else {\r
4845 Status = ScsiDiskAsyncRead16 (\r
4846 ScsiDiskDevice,\r
4847 Request->Timeout,\r
032800ec 4848 Request->TimesRetry,\r
d670bf53
HW
4849 Request->InBuffer,\r
4850 Request->DataLength,\r
4851 Request->StartLba,\r
4852 Request->SectorCount,\r
4853 Request->BlkIo2Req,\r
4854 Token\r
4855 );\r
4856 }\r
4857\r
4858 if (EFI_ERROR (Status)) {\r
4859 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4860 goto Exit;\r
4861 } else if (OldSectorCount != Request->SectorCount) {\r
4862 //\r
4863 // Original sub-task will be split into two new sub-tasks with smaller\r
4864 // DataLength\r
4865 //\r
4866 if (!ScsiDiskDevice->Cdb16Byte) {\r
4867 Status = ScsiDiskAsyncRead10 (\r
4868 ScsiDiskDevice,\r
4869 Request->Timeout,\r
032800ec 4870 0,\r
d670bf53
HW
4871 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
4872 OldDataLength - Request->DataLength,\r
1436aea4 4873 (UINT32)Request->StartLba + Request->SectorCount,\r
d670bf53
HW
4874 OldSectorCount - Request->SectorCount,\r
4875 Request->BlkIo2Req,\r
4876 Token\r
4877 );\r
4878 } else {\r
4879 Status = ScsiDiskAsyncRead16 (\r
4880 ScsiDiskDevice,\r
4881 Request->Timeout,\r
032800ec 4882 0,\r
d670bf53
HW
4883 Request->InBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
4884 OldDataLength - Request->DataLength,\r
4885 Request->StartLba + Request->SectorCount,\r
4886 OldSectorCount - Request->SectorCount,\r
4887 Request->BlkIo2Req,\r
4888 Token\r
4889 );\r
4890 }\r
1436aea4 4891\r
d670bf53
HW
4892 if (EFI_ERROR (Status)) {\r
4893 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4894 goto Exit;\r
4895 }\r
4896 }\r
4897 } else {\r
4898 //\r
4899 // SCSI write command\r
4900 //\r
4901 if (!ScsiDiskDevice->Cdb16Byte) {\r
4902 Status = ScsiDiskAsyncWrite10 (\r
4903 ScsiDiskDevice,\r
4904 Request->Timeout,\r
032800ec 4905 Request->TimesRetry,\r
d670bf53
HW
4906 Request->OutBuffer,\r
4907 Request->DataLength,\r
1436aea4 4908 (UINT32)Request->StartLba,\r
d670bf53
HW
4909 Request->SectorCount,\r
4910 Request->BlkIo2Req,\r
4911 Token\r
4912 );\r
4913 } else {\r
4914 Status = ScsiDiskAsyncWrite16 (\r
4915 ScsiDiskDevice,\r
4916 Request->Timeout,\r
032800ec 4917 Request->TimesRetry,\r
d670bf53
HW
4918 Request->OutBuffer,\r
4919 Request->DataLength,\r
4920 Request->StartLba,\r
4921 Request->SectorCount,\r
4922 Request->BlkIo2Req,\r
4923 Token\r
4924 );\r
4925 }\r
4926\r
4927 if (EFI_ERROR (Status)) {\r
4928 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4929 goto Exit;\r
4930 } else if (OldSectorCount != Request->SectorCount) {\r
4931 //\r
4932 // Original sub-task will be split into two new sub-tasks with smaller\r
4933 // DataLength\r
4934 //\r
4935 if (!ScsiDiskDevice->Cdb16Byte) {\r
4936 Status = ScsiDiskAsyncWrite10 (\r
4937 ScsiDiskDevice,\r
4938 Request->Timeout,\r
032800ec 4939 0,\r
d670bf53
HW
4940 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
4941 OldDataLength - Request->DataLength,\r
1436aea4 4942 (UINT32)Request->StartLba + Request->SectorCount,\r
d670bf53
HW
4943 OldSectorCount - Request->SectorCount,\r
4944 Request->BlkIo2Req,\r
4945 Token\r
4946 );\r
4947 } else {\r
4948 Status = ScsiDiskAsyncWrite16 (\r
4949 ScsiDiskDevice,\r
4950 Request->Timeout,\r
032800ec 4951 0,\r
d670bf53
HW
4952 Request->OutBuffer + Request->SectorCount * ScsiDiskDevice->BlkIo.Media->BlockSize,\r
4953 OldDataLength - Request->DataLength,\r
4954 Request->StartLba + Request->SectorCount,\r
4955 OldSectorCount - Request->SectorCount,\r
4956 Request->BlkIo2Req,\r
4957 Token\r
4958 );\r
4959 }\r
1436aea4 4960\r
d670bf53
HW
4961 if (EFI_ERROR (Status)) {\r
4962 Token->TransactionStatus = EFI_DEVICE_ERROR;\r
4963 goto Exit;\r
4964 }\r
4965 }\r
4966 }\r
4967\r
4968Exit:\r
4969 RemoveEntryList (&Request->Link);\r
a717086c 4970 if ((IsListEmpty (&Request->BlkIo2Req->ScsiRWQueue)) &&\r
1436aea4
MK
4971 (Request->BlkIo2Req->LastScsiRW))\r
4972 {\r
d670bf53
HW
4973 //\r
4974 // The last SCSI R/W command of a BlockIo2 request completes\r
4975 //\r
4976 RemoveEntryList (&Request->BlkIo2Req->Link);\r
4977 FreePool (Request->BlkIo2Req); // Should be freed only once\r
4978 gBS->SignalEvent (Token->Event);\r
4979 }\r
4980\r
4981 FreePool (Request->SenseData);\r
4982 FreePool (Request);\r
4983}\r
4984\r
d670bf53
HW
4985/**\r
4986 Submit Async Read(10) command.\r
4987\r
4988 @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
4989 @param Timeout The time to complete the command.\r
032800ec 4990 @param TimesRetry The number of times the command has been retried.\r
d670bf53
HW
4991 @param DataBuffer The buffer to fill with the read out data.\r
4992 @param DataLength The length of buffer.\r
4993 @param StartLba The start logic block address.\r
4994 @param SectorCount The number of blocks to read.\r
4995 @param BlkIo2Req The upstream BlockIo2 request.\r
4996 @param Token The pointer to the token associated with the\r
4997 non-blocking read request.\r
4998\r
4999 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
5000 lack of resources.\r
5001 @return others Status returned by calling\r
5002 ScsiRead10CommandEx().\r
5003\r
5004**/\r
5005EFI_STATUS\r
5006ScsiDiskAsyncRead10 (\r
1436aea4
MK
5007 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
5008 IN UINT64 Timeout,\r
5009 IN UINT8 TimesRetry,\r
5010 OUT UINT8 *DataBuffer,\r
5011 IN UINT32 DataLength,\r
5012 IN UINT32 StartLba,\r
5013 IN UINT32 SectorCount,\r
5014 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
5015 IN EFI_BLOCK_IO2_TOKEN *Token\r
d670bf53
HW
5016 )\r
5017{\r
1436aea4
MK
5018 EFI_STATUS Status;\r
5019 SCSI_ASYNC_RW_REQUEST *Request;\r
5020 EFI_EVENT AsyncIoEvent;\r
5021 EFI_TPL OldTpl;\r
d670bf53 5022\r
1f09197d
HW
5023 AsyncIoEvent = NULL;\r
5024\r
d670bf53
HW
5025 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
5026 if (Request == NULL) {\r
5027 return EFI_OUT_OF_RESOURCES;\r
5028 }\r
a717086c
HW
5029\r
5030 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5031 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
a717086c 5032 gBS->RestoreTPL (OldTpl);\r
d670bf53 5033\r
1436aea4 5034 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));\r
d670bf53
HW
5035 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
5036 if (Request->SenseData == NULL) {\r
5037 Status = EFI_OUT_OF_RESOURCES;\r
5038 goto ErrorExit;\r
5039 }\r
5040\r
1436aea4
MK
5041 Request->ScsiDiskDevice = ScsiDiskDevice;\r
5042 Request->Timeout = Timeout;\r
5043 Request->TimesRetry = TimesRetry;\r
5044 Request->InBuffer = DataBuffer;\r
5045 Request->DataLength = DataLength;\r
5046 Request->StartLba = StartLba;\r
5047 Request->SectorCount = SectorCount;\r
5048 Request->BlkIo2Req = BlkIo2Req;\r
d670bf53
HW
5049\r
5050 //\r
5051 // Create Event\r
5052 //\r
5053 Status = gBS->CreateEvent (\r
5054 EVT_NOTIFY_SIGNAL,\r
a717086c 5055 TPL_NOTIFY,\r
d670bf53
HW
5056 ScsiDiskNotify,\r
5057 Request,\r
5058 &AsyncIoEvent\r
5059 );\r
1436aea4 5060 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5061 goto ErrorExit;\r
5062 }\r
5063\r
5064 Status = ScsiRead10CommandEx (\r
5065 ScsiDiskDevice->ScsiIo,\r
5066 Request->Timeout,\r
5067 Request->SenseData,\r
5068 &Request->SenseDataLength,\r
5069 &Request->HostAdapterStatus,\r
5070 &Request->TargetStatus,\r
5071 Request->InBuffer,\r
5072 &Request->DataLength,\r
1436aea4 5073 (UINT32)Request->StartLba,\r
d670bf53
HW
5074 Request->SectorCount,\r
5075 AsyncIoEvent\r
5076 );\r
1436aea4 5077 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5078 goto ErrorExit;\r
5079 }\r
5080\r
5081 return EFI_SUCCESS;\r
5082\r
5083ErrorExit:\r
1f09197d
HW
5084 if (AsyncIoEvent != NULL) {\r
5085 gBS->CloseEvent (AsyncIoEvent);\r
5086 }\r
5087\r
d670bf53
HW
5088 if (Request != NULL) {\r
5089 if (Request->SenseData != NULL) {\r
5090 FreePool (Request->SenseData);\r
5091 }\r
5092\r
a717086c 5093 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5094 RemoveEntryList (&Request->Link);\r
a717086c
HW
5095 gBS->RestoreTPL (OldTpl);\r
5096\r
d670bf53
HW
5097 FreePool (Request);\r
5098 }\r
5099\r
5100 return Status;\r
5101}\r
5102\r
d670bf53
HW
5103/**\r
5104 Submit Async Write(10) command.\r
5105\r
5106 @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
5107 @param Timeout The time to complete the command.\r
032800ec 5108 @param TimesRetry The number of times the command has been retried.\r
d670bf53
HW
5109 @param DataBuffer The buffer contains the data to write.\r
5110 @param DataLength The length of buffer.\r
5111 @param StartLba The start logic block address.\r
5112 @param SectorCount The number of blocks to write.\r
5113 @param BlkIo2Req The upstream BlockIo2 request.\r
5114 @param Token The pointer to the token associated with the\r
5115 non-blocking read request.\r
5116\r
5117 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
5118 lack of resources.\r
5119 @return others Status returned by calling\r
5120 ScsiWrite10CommandEx().\r
5121\r
5122**/\r
5123EFI_STATUS\r
5124ScsiDiskAsyncWrite10 (\r
1436aea4
MK
5125 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
5126 IN UINT64 Timeout,\r
5127 IN UINT8 TimesRetry,\r
5128 IN UINT8 *DataBuffer,\r
5129 IN UINT32 DataLength,\r
5130 IN UINT32 StartLba,\r
5131 IN UINT32 SectorCount,\r
5132 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
5133 IN EFI_BLOCK_IO2_TOKEN *Token\r
d670bf53
HW
5134 )\r
5135{\r
1436aea4
MK
5136 EFI_STATUS Status;\r
5137 SCSI_ASYNC_RW_REQUEST *Request;\r
5138 EFI_EVENT AsyncIoEvent;\r
5139 EFI_TPL OldTpl;\r
d670bf53 5140\r
1f09197d
HW
5141 AsyncIoEvent = NULL;\r
5142\r
d670bf53
HW
5143 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
5144 if (Request == NULL) {\r
5145 return EFI_OUT_OF_RESOURCES;\r
5146 }\r
a717086c
HW
5147\r
5148 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5149 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
a717086c 5150 gBS->RestoreTPL (OldTpl);\r
d670bf53 5151\r
1436aea4 5152 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));\r
d670bf53
HW
5153 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
5154 if (Request->SenseData == NULL) {\r
5155 Status = EFI_OUT_OF_RESOURCES;\r
5156 goto ErrorExit;\r
5157 }\r
5158\r
1436aea4
MK
5159 Request->ScsiDiskDevice = ScsiDiskDevice;\r
5160 Request->Timeout = Timeout;\r
5161 Request->TimesRetry = TimesRetry;\r
5162 Request->OutBuffer = DataBuffer;\r
5163 Request->DataLength = DataLength;\r
5164 Request->StartLba = StartLba;\r
5165 Request->SectorCount = SectorCount;\r
5166 Request->BlkIo2Req = BlkIo2Req;\r
d670bf53
HW
5167\r
5168 //\r
5169 // Create Event\r
5170 //\r
5171 Status = gBS->CreateEvent (\r
5172 EVT_NOTIFY_SIGNAL,\r
a717086c 5173 TPL_NOTIFY,\r
d670bf53
HW
5174 ScsiDiskNotify,\r
5175 Request,\r
5176 &AsyncIoEvent\r
5177 );\r
1436aea4 5178 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5179 goto ErrorExit;\r
5180 }\r
5181\r
5182 Status = ScsiWrite10CommandEx (\r
5183 ScsiDiskDevice->ScsiIo,\r
5184 Request->Timeout,\r
5185 Request->SenseData,\r
5186 &Request->SenseDataLength,\r
5187 &Request->HostAdapterStatus,\r
5188 &Request->TargetStatus,\r
5189 Request->OutBuffer,\r
5190 &Request->DataLength,\r
1436aea4 5191 (UINT32)Request->StartLba,\r
d670bf53
HW
5192 Request->SectorCount,\r
5193 AsyncIoEvent\r
5194 );\r
1436aea4 5195 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5196 goto ErrorExit;\r
5197 }\r
5198\r
5199 return EFI_SUCCESS;\r
5200\r
5201ErrorExit:\r
1f09197d
HW
5202 if (AsyncIoEvent != NULL) {\r
5203 gBS->CloseEvent (AsyncIoEvent);\r
5204 }\r
5205\r
d670bf53
HW
5206 if (Request != NULL) {\r
5207 if (Request->SenseData != NULL) {\r
5208 FreePool (Request->SenseData);\r
5209 }\r
5210\r
a717086c 5211 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5212 RemoveEntryList (&Request->Link);\r
a717086c
HW
5213 gBS->RestoreTPL (OldTpl);\r
5214\r
d670bf53
HW
5215 FreePool (Request);\r
5216 }\r
5217\r
5218 return Status;\r
5219}\r
5220\r
d670bf53
HW
5221/**\r
5222 Submit Async Read(16) command.\r
5223\r
5224 @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
5225 @param Timeout The time to complete the command.\r
032800ec 5226 @param TimesRetry The number of times the command has been retried.\r
d670bf53
HW
5227 @param DataBuffer The buffer to fill with the read out data.\r
5228 @param DataLength The length of buffer.\r
5229 @param StartLba The start logic block address.\r
5230 @param SectorCount The number of blocks to read.\r
5231 @param BlkIo2Req The upstream BlockIo2 request.\r
5232 @param Token The pointer to the token associated with the\r
5233 non-blocking read request.\r
5234\r
5235 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
5236 lack of resources.\r
5237 @return others Status returned by calling\r
5238 ScsiRead16CommandEx().\r
5239\r
5240**/\r
5241EFI_STATUS\r
5242ScsiDiskAsyncRead16 (\r
1436aea4
MK
5243 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
5244 IN UINT64 Timeout,\r
5245 IN UINT8 TimesRetry,\r
5246 OUT UINT8 *DataBuffer,\r
5247 IN UINT32 DataLength,\r
5248 IN UINT64 StartLba,\r
5249 IN UINT32 SectorCount,\r
5250 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
5251 IN EFI_BLOCK_IO2_TOKEN *Token\r
d670bf53
HW
5252 )\r
5253{\r
1436aea4
MK
5254 EFI_STATUS Status;\r
5255 SCSI_ASYNC_RW_REQUEST *Request;\r
5256 EFI_EVENT AsyncIoEvent;\r
5257 EFI_TPL OldTpl;\r
d670bf53 5258\r
1f09197d
HW
5259 AsyncIoEvent = NULL;\r
5260\r
d670bf53
HW
5261 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
5262 if (Request == NULL) {\r
5263 return EFI_OUT_OF_RESOURCES;\r
5264 }\r
a717086c
HW
5265\r
5266 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5267 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
a717086c 5268 gBS->RestoreTPL (OldTpl);\r
d670bf53 5269\r
1436aea4 5270 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));\r
d670bf53
HW
5271 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
5272 if (Request->SenseData == NULL) {\r
5273 Status = EFI_OUT_OF_RESOURCES;\r
5274 goto ErrorExit;\r
5275 }\r
5276\r
1436aea4
MK
5277 Request->ScsiDiskDevice = ScsiDiskDevice;\r
5278 Request->Timeout = Timeout;\r
5279 Request->TimesRetry = TimesRetry;\r
5280 Request->InBuffer = DataBuffer;\r
5281 Request->DataLength = DataLength;\r
5282 Request->StartLba = StartLba;\r
5283 Request->SectorCount = SectorCount;\r
5284 Request->BlkIo2Req = BlkIo2Req;\r
d670bf53
HW
5285\r
5286 //\r
5287 // Create Event\r
5288 //\r
5289 Status = gBS->CreateEvent (\r
5290 EVT_NOTIFY_SIGNAL,\r
a717086c 5291 TPL_NOTIFY,\r
d670bf53
HW
5292 ScsiDiskNotify,\r
5293 Request,\r
5294 &AsyncIoEvent\r
5295 );\r
1436aea4 5296 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5297 goto ErrorExit;\r
5298 }\r
5299\r
5300 Status = ScsiRead16CommandEx (\r
5301 ScsiDiskDevice->ScsiIo,\r
5302 Request->Timeout,\r
5303 Request->SenseData,\r
5304 &Request->SenseDataLength,\r
5305 &Request->HostAdapterStatus,\r
5306 &Request->TargetStatus,\r
5307 Request->InBuffer,\r
5308 &Request->DataLength,\r
5309 Request->StartLba,\r
5310 Request->SectorCount,\r
5311 AsyncIoEvent\r
5312 );\r
1436aea4 5313 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5314 goto ErrorExit;\r
5315 }\r
5316\r
5317 return EFI_SUCCESS;\r
5318\r
5319ErrorExit:\r
1f09197d
HW
5320 if (AsyncIoEvent != NULL) {\r
5321 gBS->CloseEvent (AsyncIoEvent);\r
5322 }\r
5323\r
d670bf53
HW
5324 if (Request != NULL) {\r
5325 if (Request->SenseData != NULL) {\r
5326 FreePool (Request->SenseData);\r
5327 }\r
5328\r
a717086c 5329 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5330 RemoveEntryList (&Request->Link);\r
a717086c
HW
5331 gBS->RestoreTPL (OldTpl);\r
5332\r
d670bf53
HW
5333 FreePool (Request);\r
5334 }\r
5335\r
5336 return Status;\r
5337}\r
5338\r
d670bf53
HW
5339/**\r
5340 Submit Async Write(16) command.\r
5341\r
5342 @param ScsiDiskDevice The pointer of ScsiDiskDevice.\r
5343 @param Timeout The time to complete the command.\r
032800ec 5344 @param TimesRetry The number of times the command has been retried.\r
d670bf53
HW
5345 @param DataBuffer The buffer contains the data to write.\r
5346 @param DataLength The length of buffer.\r
5347 @param StartLba The start logic block address.\r
5348 @param SectorCount The number of blocks to write.\r
5349 @param BlkIo2Req The upstream BlockIo2 request.\r
5350 @param Token The pointer to the token associated with the\r
5351 non-blocking read request.\r
5352\r
5353 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
5354 lack of resources.\r
5355 @return others Status returned by calling\r
5356 ScsiWrite16CommandEx().\r
5357\r
5358**/\r
5359EFI_STATUS\r
5360ScsiDiskAsyncWrite16 (\r
1436aea4
MK
5361 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
5362 IN UINT64 Timeout,\r
5363 IN UINT8 TimesRetry,\r
5364 IN UINT8 *DataBuffer,\r
5365 IN UINT32 DataLength,\r
5366 IN UINT64 StartLba,\r
5367 IN UINT32 SectorCount,\r
5368 IN OUT SCSI_BLKIO2_REQUEST *BlkIo2Req,\r
5369 IN EFI_BLOCK_IO2_TOKEN *Token\r
d670bf53
HW
5370 )\r
5371{\r
1436aea4
MK
5372 EFI_STATUS Status;\r
5373 SCSI_ASYNC_RW_REQUEST *Request;\r
5374 EFI_EVENT AsyncIoEvent;\r
5375 EFI_TPL OldTpl;\r
d670bf53 5376\r
1f09197d
HW
5377 AsyncIoEvent = NULL;\r
5378\r
d670bf53
HW
5379 Request = AllocateZeroPool (sizeof (SCSI_ASYNC_RW_REQUEST));\r
5380 if (Request == NULL) {\r
5381 return EFI_OUT_OF_RESOURCES;\r
5382 }\r
a717086c
HW
5383\r
5384 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5385 InsertTailList (&BlkIo2Req->ScsiRWQueue, &Request->Link);\r
a717086c 5386 gBS->RestoreTPL (OldTpl);\r
d670bf53 5387\r
1436aea4 5388 Request->SenseDataLength = (UINT8)(6 * sizeof (EFI_SCSI_SENSE_DATA));\r
d670bf53
HW
5389 Request->SenseData = AllocateZeroPool (Request->SenseDataLength);\r
5390 if (Request->SenseData == NULL) {\r
5391 Status = EFI_OUT_OF_RESOURCES;\r
5392 goto ErrorExit;\r
5393 }\r
5394\r
1436aea4
MK
5395 Request->ScsiDiskDevice = ScsiDiskDevice;\r
5396 Request->Timeout = Timeout;\r
5397 Request->TimesRetry = TimesRetry;\r
5398 Request->OutBuffer = DataBuffer;\r
5399 Request->DataLength = DataLength;\r
5400 Request->StartLba = StartLba;\r
5401 Request->SectorCount = SectorCount;\r
5402 Request->BlkIo2Req = BlkIo2Req;\r
d670bf53
HW
5403\r
5404 //\r
5405 // Create Event\r
5406 //\r
5407 Status = gBS->CreateEvent (\r
5408 EVT_NOTIFY_SIGNAL,\r
a717086c 5409 TPL_NOTIFY,\r
d670bf53
HW
5410 ScsiDiskNotify,\r
5411 Request,\r
5412 &AsyncIoEvent\r
5413 );\r
1436aea4 5414 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5415 goto ErrorExit;\r
5416 }\r
5417\r
5418 Status = ScsiWrite16CommandEx (\r
5419 ScsiDiskDevice->ScsiIo,\r
5420 Request->Timeout,\r
5421 Request->SenseData,\r
5422 &Request->SenseDataLength,\r
5423 &Request->HostAdapterStatus,\r
5424 &Request->TargetStatus,\r
5425 Request->OutBuffer,\r
5426 &Request->DataLength,\r
5427 Request->StartLba,\r
5428 Request->SectorCount,\r
5429 AsyncIoEvent\r
5430 );\r
1436aea4 5431 if (EFI_ERROR (Status)) {\r
d670bf53
HW
5432 goto ErrorExit;\r
5433 }\r
5434\r
5435 return EFI_SUCCESS;\r
5436\r
5437ErrorExit:\r
1f09197d
HW
5438 if (AsyncIoEvent != NULL) {\r
5439 gBS->CloseEvent (AsyncIoEvent);\r
5440 }\r
5441\r
d670bf53
HW
5442 if (Request != NULL) {\r
5443 if (Request->SenseData != NULL) {\r
5444 FreePool (Request->SenseData);\r
5445 }\r
5446\r
a717086c 5447 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
d670bf53 5448 RemoveEntryList (&Request->Link);\r
a717086c
HW
5449 gBS->RestoreTPL (OldTpl);\r
5450\r
d670bf53
HW
5451 FreePool (Request);\r
5452 }\r
5453\r
5454 return Status;\r
5455}\r
5456\r
9beb888e 5457/**\r
5458 Check sense key to find if media presents.\r
5459\r
5460 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
5461 @param SenseCounts The number of sense key\r
5462\r
5463 @retval TRUE NOT any media\r
5464 @retval FALSE Media presents\r
5465**/\r
6ad55b15 5466BOOLEAN\r
5467ScsiDiskIsNoMedia (\r
1436aea4
MK
5468 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5469 IN UINTN SenseCounts\r
6ad55b15 5470 )\r
6ad55b15 5471{\r
1436aea4
MK
5472 EFI_SCSI_SENSE_DATA *SensePtr;\r
5473 UINTN Index;\r
5474 BOOLEAN IsNoMedia;\r
6ad55b15 5475\r
5476 IsNoMedia = FALSE;\r
5477 SensePtr = SenseData;\r
5478\r
5479 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 5480 //\r
5481 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),\r
5482 // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
5483 //\r
5484 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
1436aea4
MK
5485 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA))\r
5486 {\r
6ad55b15 5487 IsNoMedia = TRUE;\r
5488 }\r
1436aea4 5489\r
6ad55b15 5490 SensePtr++;\r
5491 }\r
5492\r
5493 return IsNoMedia;\r
5494}\r
5495\r
9beb888e 5496/**\r
5497 Parse sense key.\r
5498\r
5499 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
5500 @param SenseCounts The number of sense key\r
5501\r
5502 @retval TRUE Error\r
5503 @retval FALSE NOT error\r
5504\r
5505**/\r
6ad55b15 5506BOOLEAN\r
5507ScsiDiskIsMediaError (\r
1436aea4
MK
5508 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5509 IN UINTN SenseCounts\r
6ad55b15 5510 )\r
6ad55b15 5511{\r
1436aea4
MK
5512 EFI_SCSI_SENSE_DATA *SensePtr;\r
5513 UINTN Index;\r
5514 BOOLEAN IsError;\r
6ad55b15 5515\r
1436aea4
MK
5516 IsError = FALSE;\r
5517 SensePtr = SenseData;\r
6ad55b15 5518\r
5519 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 5520 switch (SensePtr->Sense_Key) {\r
1436aea4
MK
5521 case EFI_SCSI_SK_MEDIUM_ERROR:\r
5522 //\r
5523 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)\r
5524 //\r
5525 switch (SensePtr->Addnl_Sense_Code) {\r
5526 //\r
5527 // fall through\r
5528 //\r
5529 case EFI_SCSI_ASC_MEDIA_ERR1:\r
6ad55b15 5530\r
1436aea4
MK
5531 //\r
5532 // fall through\r
5533 //\r
5534 case EFI_SCSI_ASC_MEDIA_ERR2:\r
6ad55b15 5535\r
1436aea4
MK
5536 //\r
5537 // fall through\r
5538 //\r
5539 case EFI_SCSI_ASC_MEDIA_ERR3:\r
5540 case EFI_SCSI_ASC_MEDIA_ERR4:\r
5541 IsError = TRUE;\r
5542 break;\r
6ad55b15 5543\r
1436aea4
MK
5544 default:\r
5545 break;\r
5546 }\r
6ad55b15 5547\r
6ad55b15 5548 break;\r
5549\r
1436aea4
MK
5550 case EFI_SCSI_SK_NOT_READY:\r
5551 //\r
5552 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
5553 //\r
5554 switch (SensePtr->Addnl_Sense_Code) {\r
5555 //\r
5556 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)\r
5557 //\r
5558 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:\r
5559 IsError = TRUE;\r
5560 break;\r
6ad55b15 5561\r
1436aea4
MK
5562 default:\r
5563 break;\r
5564 }\r
6ad55b15 5565\r
6ad55b15 5566 break;\r
5567\r
5568 default:\r
5569 break;\r
6ad55b15 5570 }\r
5571\r
5572 SensePtr++;\r
5573 }\r
5574\r
5575 return IsError;\r
5576}\r
5577\r
9beb888e 5578/**\r
5579 Check sense key to find if hardware error happens.\r
5580\r
5581 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
5582 @param SenseCounts The number of sense key\r
5583\r
5584 @retval TRUE Hardware error exits.\r
5585 @retval FALSE NO error.\r
5586\r
5587**/\r
6ad55b15 5588BOOLEAN\r
5589ScsiDiskIsHardwareError (\r
1436aea4
MK
5590 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5591 IN UINTN SenseCounts\r
6ad55b15 5592 )\r
6ad55b15 5593{\r
1436aea4
MK
5594 EFI_SCSI_SENSE_DATA *SensePtr;\r
5595 UINTN Index;\r
5596 BOOLEAN IsError;\r
6ad55b15 5597\r
1436aea4
MK
5598 IsError = FALSE;\r
5599 SensePtr = SenseData;\r
6ad55b15 5600\r
5601 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 5602 //\r
5603 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)\r
5604 //\r
5605 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {\r
5606 IsError = TRUE;\r
5607 }\r
5608\r
5609 SensePtr++;\r
5610 }\r
5611\r
5612 return IsError;\r
5613}\r
5614\r
9beb888e 5615/**\r
5616 Check sense key to find if media has changed.\r
5617\r
5618 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
5619 @param SenseCounts The number of sense key\r
5620\r
5621 @retval TRUE Media is changed.\r
d716651f 5622 @retval FALSE Media is NOT changed.\r
9beb888e 5623**/\r
6ad55b15 5624BOOLEAN\r
5625ScsiDiskIsMediaChange (\r
1436aea4
MK
5626 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5627 IN UINTN SenseCounts\r
6ad55b15 5628 )\r
6ad55b15 5629{\r
1436aea4
MK
5630 EFI_SCSI_SENSE_DATA *SensePtr;\r
5631 UINTN Index;\r
5632 BOOLEAN IsMediaChanged;\r
6ad55b15 5633\r
1436aea4
MK
5634 IsMediaChanged = FALSE;\r
5635 SensePtr = SenseData;\r
6ad55b15 5636\r
5637 for (Index = 0; Index < SenseCounts; Index++) {\r
5638 //\r
5639 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),\r
5640 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)\r
5641 //\r
5642 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
1436aea4
MK
5643 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE))\r
5644 {\r
6ad55b15 5645 IsMediaChanged = TRUE;\r
5646 }\r
5647\r
5648 SensePtr++;\r
5649 }\r
5650\r
5651 return IsMediaChanged;\r
5652}\r
5653\r
9beb888e 5654/**\r
5655 Check sense key to find if reset happens.\r
5656\r
5657 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
5658 @param SenseCounts The number of sense key\r
5659\r
5660 @retval TRUE It is reset before.\r
5661 @retval FALSE It is NOT reset before.\r
5662\r
5663**/\r
6ad55b15 5664BOOLEAN\r
5665ScsiDiskIsResetBefore (\r
1436aea4
MK
5666 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5667 IN UINTN SenseCounts\r
6ad55b15 5668 )\r
6ad55b15 5669{\r
1436aea4
MK
5670 EFI_SCSI_SENSE_DATA *SensePtr;\r
5671 UINTN Index;\r
5672 BOOLEAN IsResetBefore;\r
6ad55b15 5673\r
5674 IsResetBefore = FALSE;\r
5675 SensePtr = SenseData;\r
5676\r
5677 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 5678 //\r
5679 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)\r
5680 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)\r
5681 //\r
5682 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
1436aea4
MK
5683 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET))\r
5684 {\r
6ad55b15 5685 IsResetBefore = TRUE;\r
5686 }\r
5687\r
5688 SensePtr++;\r
5689 }\r
5690\r
5691 return IsResetBefore;\r
5692}\r
5693\r
9beb888e 5694/**\r
5695 Check sense key to find if the drive is ready.\r
5696\r
5697 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
5698 @param SenseCounts The number of sense key\r
d1102dba 5699 @param RetryLater The flag means if need a retry\r
9beb888e 5700\r
5701 @retval TRUE Drive is ready.\r
5702 @retval FALSE Drive is NOT ready.\r
5703\r
5704**/\r
6ad55b15 5705BOOLEAN\r
5706ScsiDiskIsDriveReady (\r
1436aea4
MK
5707 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5708 IN UINTN SenseCounts,\r
5709 OUT BOOLEAN *RetryLater\r
6ad55b15 5710 )\r
6ad55b15 5711{\r
1436aea4
MK
5712 EFI_SCSI_SENSE_DATA *SensePtr;\r
5713 UINTN Index;\r
5714 BOOLEAN IsReady;\r
6ad55b15 5715\r
5716 IsReady = TRUE;\r
5717 *RetryLater = FALSE;\r
5718 SensePtr = SenseData;\r
5719\r
5720 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 5721 switch (SensePtr->Sense_Key) {\r
1436aea4 5722 case EFI_SCSI_SK_NOT_READY:\r
6ad55b15 5723 //\r
1436aea4 5724 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
6ad55b15 5725 //\r
1436aea4
MK
5726 switch (SensePtr->Addnl_Sense_Code) {\r
5727 case EFI_SCSI_ASC_NOT_READY:\r
5728 //\r
5729 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)\r
5730 //\r
5731 switch (SensePtr->Addnl_Sense_Code_Qualifier) {\r
5732 case EFI_SCSI_ASCQ_IN_PROGRESS:\r
5733 //\r
5734 // Additional Sense Code Qualifier is\r
5735 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)\r
5736 //\r
5737 IsReady = FALSE;\r
5738 *RetryLater = TRUE;\r
5739 break;\r
5740\r
5741 default:\r
5742 IsReady = FALSE;\r
5743 *RetryLater = FALSE;\r
5744 break;\r
5745 }\r
6ad55b15 5746\r
1436aea4
MK
5747 break;\r
5748\r
5749 default:\r
5750 break;\r
6ad55b15 5751 }\r
1436aea4 5752\r
6ad55b15 5753 break;\r
5754\r
5755 default:\r
5756 break;\r
6ad55b15 5757 }\r
5758\r
5759 SensePtr++;\r
5760 }\r
5761\r
5762 return IsReady;\r
5763}\r
5764\r
9beb888e 5765/**\r
5766 Check sense key to find if it has sense key.\r
5767\r
5768 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
5769 @param SenseCounts - The number of sense key\r
5770\r
5771 @retval TRUE It has sense key.\r
5772 @retval FALSE It has NOT any sense key.\r
5773\r
5774**/\r
6ad55b15 5775BOOLEAN\r
5776ScsiDiskHaveSenseKey (\r
1436aea4
MK
5777 IN EFI_SCSI_SENSE_DATA *SenseData,\r
5778 IN UINTN SenseCounts\r
6ad55b15 5779 )\r
6ad55b15 5780{\r
1436aea4
MK
5781 EFI_SCSI_SENSE_DATA *SensePtr;\r
5782 UINTN Index;\r
5783 BOOLEAN HaveSenseKey;\r
6ad55b15 5784\r
5785 if (SenseCounts == 0) {\r
5786 HaveSenseKey = FALSE;\r
5787 } else {\r
5788 HaveSenseKey = TRUE;\r
5789 }\r
5790\r
5791 SensePtr = SenseData;\r
5792\r
5793 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 5794 //\r
5795 // Sense Key is SK_NO_SENSE (0x0)\r
5796 //\r
5797 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&\r
1436aea4
MK
5798 (Index == 0))\r
5799 {\r
6ad55b15 5800 HaveSenseKey = FALSE;\r
5801 }\r
5802\r
5803 SensePtr++;\r
5804 }\r
5805\r
5806 return HaveSenseKey;\r
5807}\r
5808\r
9beb888e 5809/**\r
5810 Release resource about disk device.\r
5811\r
5812 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
5813\r
5814**/\r
6ad55b15 5815VOID\r
5816ReleaseScsiDiskDeviceResources (\r
1436aea4 5817 IN SCSI_DISK_DEV *ScsiDiskDevice\r
6ad55b15 5818 )\r
6ad55b15 5819{\r
5820 if (ScsiDiskDevice == NULL) {\r
1436aea4 5821 return;\r
6ad55b15 5822 }\r
5823\r
5824 if (ScsiDiskDevice->SenseData != NULL) {\r
9b38ff34 5825 FreePool (ScsiDiskDevice->SenseData);\r
6ad55b15 5826 ScsiDiskDevice->SenseData = NULL;\r
5827 }\r
5828\r
5829 if (ScsiDiskDevice->ControllerNameTable != NULL) {\r
5830 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);\r
5831 ScsiDiskDevice->ControllerNameTable = NULL;\r
5832 }\r
5833\r
9b38ff34 5834 FreePool (ScsiDiskDevice);\r
6ad55b15 5835\r
5836 ScsiDiskDevice = NULL;\r
5837}\r
d14faa52 5838\r
5839/**\r
d670bf53 5840 Determine if Block Io & Block Io2 should be produced.\r
d1102dba 5841\r
d14faa52 5842\r
d716651f 5843 @param ChildHandle Child Handle to retrieve Parent information.\r
d1102dba 5844\r
d670bf53
HW
5845 @retval TRUE Should produce Block Io & Block Io2.\r
5846 @retval FALSE Should not produce Block Io & Block Io2.\r
d14faa52 5847\r
d1102dba 5848**/\r
d14faa52 5849BOOLEAN\r
5850DetermineInstallBlockIo (\r
1436aea4 5851 IN EFI_HANDLE ChildHandle\r
d1102dba 5852 )\r
d14faa52 5853{\r
1436aea4
MK
5854 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
5855 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
d14faa52 5856\r
5857 //\r
5858 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,\r
5859 // check its attribute, logic or physical.\r
5860 //\r
5861 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);\r
5862 if (ExtScsiPassThru != NULL) {\r
5863 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
5864 return TRUE;\r
5865 }\r
5866 }\r
5867\r
5868 //\r
5869 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,\r
5870 // check its attribute, logic or physical.\r
5871 //\r
5872 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);\r
5873 if (ScsiPassThru != NULL) {\r
5874 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
5875 return TRUE;\r
5876 }\r
5877 }\r
d1102dba 5878\r
d14faa52 5879 return FALSE;\r
5880}\r
5881\r
5882/**\r
5883 Search protocol database and check to see if the protocol\r
5884 specified by ProtocolGuid is present on a ControllerHandle and opened by\r
5885 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
5886 If the ControllerHandle is found, then the protocol specified by ProtocolGuid\r
d1102dba
LG
5887 will be opened on it.\r
5888\r
d14faa52 5889\r
5890 @param ProtocolGuid ProtocolGuid pointer.\r
5891 @param ChildHandle Child Handle to retrieve Parent information.\r
d1102dba
LG
5892\r
5893**/\r
d14faa52 5894VOID *\r
5895EFIAPI\r
5896GetParentProtocol (\r
1436aea4
MK
5897 IN EFI_GUID *ProtocolGuid,\r
5898 IN EFI_HANDLE ChildHandle\r
d1102dba 5899 )\r
d14faa52 5900{\r
1436aea4
MK
5901 UINTN Index;\r
5902 UINTN HandleCount;\r
5903 VOID *Interface;\r
5904 EFI_STATUS Status;\r
5905 EFI_HANDLE *HandleBuffer;\r
d14faa52 5906\r
5907 //\r
5908 // Retrieve the list of all handles from the handle database\r
5909 //\r
5910 Status = gBS->LocateHandleBuffer (\r
5911 ByProtocol,\r
5912 ProtocolGuid,\r
5913 NULL,\r
5914 &HandleCount,\r
5915 &HandleBuffer\r
5916 );\r
5917\r
5918 if (EFI_ERROR (Status)) {\r
5919 return NULL;\r
5920 }\r
5921\r
5922 //\r
d1102dba 5923 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle\r
d14faa52 5924 //\r
5925 for (Index = 0; Index < HandleCount; Index++) {\r
5926 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);\r
5927 if (!EFI_ERROR (Status)) {\r
5928 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);\r
5929 if (!EFI_ERROR (Status)) {\r
5930 gBS->FreePool (HandleBuffer);\r
5931 return Interface;\r
5932 }\r
5933 }\r
5934 }\r
5935\r
5936 gBS->FreePool (HandleBuffer);\r
5937 return NULL;\r
d1102dba 5938}\r
d14faa52 5939\r
b6e5da19
HW
5940/**\r
5941 Determine if EFI Erase Block Protocol should be produced.\r
5942\r
5943 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
5944 @param ChildHandle Handle of device.\r
5945\r
5946 @retval TRUE Should produce EFI Erase Block Protocol.\r
5947 @retval FALSE Should not produce EFI Erase Block Protocol.\r
5948\r
5949**/\r
5950BOOLEAN\r
5951DetermineInstallEraseBlock (\r
1436aea4
MK
5952 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
5953 IN EFI_HANDLE ChildHandle\r
b6e5da19
HW
5954 )\r
5955{\r
1436aea4
MK
5956 UINT8 HostAdapterStatus;\r
5957 UINT8 TargetStatus;\r
5958 EFI_STATUS CommandStatus;\r
5959 EFI_STATUS Status;\r
5960 BOOLEAN UfsDevice;\r
5961 BOOLEAN RetVal;\r
5962 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
5963 UINT8 SenseDataLength;\r
5964 UINT32 DataLength16;\r
5965 EFI_SCSI_DISK_CAPACITY_DATA16 *CapacityData16;\r
b6e5da19
HW
5966\r
5967 UfsDevice = FALSE;\r
5968 RetVal = TRUE;\r
5969 CapacityData16 = NULL;\r
5970\r
ac81789c
CZ
5971 //\r
5972 // UNMAP command is not supported by any of the UFS WLUNs.\r
5973 //\r
5974 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_WLUN) {\r
5975 RetVal = FALSE;\r
5976 goto Done;\r
5977 }\r
5978\r
b6e5da19
HW
5979 Status = gBS->HandleProtocol (\r
5980 ChildHandle,\r
5981 &gEfiDevicePathProtocolGuid,\r
1436aea4 5982 (VOID **)&DevicePathNode\r
b6e5da19
HW
5983 );\r
5984 //\r
5985 // Device Path protocol must be installed on the device handle.\r
5986 //\r
5987 ASSERT_EFI_ERROR (Status);\r
5988\r
5989 while (!IsDevicePathEndType (DevicePathNode)) {\r
5990 //\r
5991 // For now, only support Erase Block Protocol on UFS devices.\r
5992 //\r
5993 if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&\r
1436aea4
MK
5994 (DevicePathNode->SubType == MSG_UFS_DP))\r
5995 {\r
b6e5da19
HW
5996 UfsDevice = TRUE;\r
5997 break;\r
5998 }\r
5999\r
6000 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
6001 }\r
1436aea4 6002\r
b6e5da19
HW
6003 if (!UfsDevice) {\r
6004 RetVal = FALSE;\r
6005 goto Done;\r
6006 }\r
6007\r
6008 //\r
6009 // Check whether the erase functionality is enabled on the UFS device.\r
6010 //\r
6011 CapacityData16 = AllocateAlignedBuffer (ScsiDiskDevice, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
6012 if (CapacityData16 == NULL) {\r
6013 RetVal = FALSE;\r
6014 goto Done;\r
6015 }\r
6016\r
6017 SenseDataLength = 0;\r
6018 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
6019 ZeroMem (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
6020\r
6021 CommandStatus = ScsiReadCapacity16Command (\r
6022 ScsiDiskDevice->ScsiIo,\r
6023 SCSI_DISK_TIMEOUT,\r
6024 NULL,\r
6025 &SenseDataLength,\r
6026 &HostAdapterStatus,\r
6027 &TargetStatus,\r
1436aea4 6028 (VOID *)CapacityData16,\r
b6e5da19
HW
6029 &DataLength16,\r
6030 FALSE\r
6031 );\r
6032\r
6033 if (CommandStatus == EFI_SUCCESS) {\r
6034 //\r
6035 // Universal Flash Storage (UFS) Version 2.0\r
6036 // Section 11.3.9.2\r
6037 // Bits TPE and TPRZ should both be set to enable the erase feature on UFS.\r
6038 //\r
6039 if (((CapacityData16->LowestAlignLogic2 & BIT7) == 0) ||\r
1436aea4
MK
6040 ((CapacityData16->LowestAlignLogic2 & BIT6) == 0))\r
6041 {\r
b6e5da19 6042 DEBUG ((\r
87000d77 6043 DEBUG_VERBOSE,\r
b6e5da19
HW
6044 "ScsiDisk EraseBlock: Either TPE or TPRZ is not set: 0x%x.\n",\r
6045 CapacityData16->LowestAlignLogic2\r
6046 ));\r
6047\r
6048 RetVal = FALSE;\r
6049 goto Done;\r
6050 }\r
6051 } else {\r
6052 DEBUG ((\r
87000d77 6053 DEBUG_VERBOSE,\r
b6e5da19
HW
6054 "ScsiDisk EraseBlock: ReadCapacity16 failed with status %r.\n",\r
6055 CommandStatus\r
6056 ));\r
6057\r
6058 RetVal = FALSE;\r
6059 goto Done;\r
6060 }\r
6061\r
6062 //\r
6063 // Check whether the UFS device server implements the UNMAP command.\r
6064 //\r
6065 if ((ScsiDiskDevice->UnmapInfo.MaxLbaCnt == 0) ||\r
1436aea4
MK
6066 (ScsiDiskDevice->UnmapInfo.MaxBlkDespCnt == 0))\r
6067 {\r
b6e5da19 6068 DEBUG ((\r
87000d77 6069 DEBUG_VERBOSE,\r
b6e5da19
HW
6070 "ScsiDisk EraseBlock: The device server does not implement the UNMAP command.\n"\r
6071 ));\r
6072\r
6073 RetVal = FALSE;\r
6074 goto Done;\r
6075 }\r
6076\r
6077Done:\r
6078 if (CapacityData16 != NULL) {\r
6079 FreeAlignedBuffer (CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
6080 }\r
6081\r
6082 return RetVal;\r
6083}\r
6084\r
ac81789c
CZ
6085/**\r
6086 Determine if EFI Storage Security Command Protocol should be produced.\r
6087\r
6088 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
6089 @param ChildHandle Handle of device.\r
6090\r
6091 @retval TRUE Should produce EFI Storage Security Command Protocol.\r
6092 @retval FALSE Should not produce EFI Storage Security Command Protocol.\r
6093\r
6094**/\r
6095BOOLEAN\r
6096DetermineInstallStorageSecurity (\r
1436aea4
MK
6097 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
6098 IN EFI_HANDLE ChildHandle\r
ac81789c
CZ
6099 )\r
6100{\r
1436aea4
MK
6101 EFI_STATUS Status;\r
6102 UFS_DEVICE_PATH *UfsDevice;\r
6103 BOOLEAN RetVal;\r
6104 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
ac81789c 6105\r
1436aea4
MK
6106 UfsDevice = NULL;\r
6107 RetVal = TRUE;\r
ac81789c
CZ
6108\r
6109 Status = gBS->HandleProtocol (\r
6110 ChildHandle,\r
6111 &gEfiDevicePathProtocolGuid,\r
1436aea4 6112 (VOID **)&DevicePathNode\r
ac81789c
CZ
6113 );\r
6114 //\r
6115 // Device Path protocol must be installed on the device handle.\r
6116 //\r
6117 ASSERT_EFI_ERROR (Status);\r
6118\r
6119 while (!IsDevicePathEndType (DevicePathNode)) {\r
6120 //\r
6121 // For now, only support Storage Security Command Protocol on UFS devices.\r
6122 //\r
6123 if ((DevicePathNode->Type == MESSAGING_DEVICE_PATH) &&\r
1436aea4
MK
6124 (DevicePathNode->SubType == MSG_UFS_DP))\r
6125 {\r
6126 UfsDevice = (UFS_DEVICE_PATH *)DevicePathNode;\r
ac81789c
CZ
6127 break;\r
6128 }\r
6129\r
6130 DevicePathNode = NextDevicePathNode (DevicePathNode);\r
6131 }\r
1436aea4 6132\r
ac81789c
CZ
6133 if (UfsDevice == NULL) {\r
6134 RetVal = FALSE;\r
6135 goto Done;\r
6136 }\r
6137\r
6138 if (UfsDevice->Lun != UFS_WLUN_RPMB) {\r
6139 RetVal = FALSE;\r
6140 }\r
6141\r
6142Done:\r
6143 return RetVal;\r
6144}\r
6145\r
d716651f 6146/**\r
6147 Provides inquiry information for the controller type.\r
d1102dba 6148\r
d716651f 6149 This function is used by the IDE bus driver to get inquiry data. Data format\r
6150 of Identify data is defined by the Interface GUID.\r
6151\r
4140a663 6152 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
6153 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.\r
6154 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.\r
d716651f 6155\r
6156 @retval EFI_SUCCESS The command was accepted without any errors.\r
d1102dba
LG
6157 @retval EFI_NOT_FOUND Device does not support this data class\r
6158 @retval EFI_DEVICE_ERROR Error reading InquiryData from device\r
6159 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough\r
d716651f 6160\r
6161**/\r
6162EFI_STATUS\r
6163EFIAPI\r
6164ScsiDiskInfoInquiry (\r
1436aea4
MK
6165 IN EFI_DISK_INFO_PROTOCOL *This,\r
6166 IN OUT VOID *InquiryData,\r
6167 IN OUT UINT32 *InquiryDataSize\r
d716651f 6168 )\r
6169{\r
1436aea4
MK
6170 EFI_STATUS Status;\r
6171 SCSI_DISK_DEV *ScsiDiskDevice;\r
d716651f 6172\r
1436aea4 6173 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
d716651f 6174\r
6175 Status = EFI_BUFFER_TOO_SMALL;\r
6176 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {\r
6177 Status = EFI_SUCCESS;\r
6178 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));\r
6179 }\r
1436aea4 6180\r
d716651f 6181 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);\r
6182 return Status;\r
6183}\r
6184\r
d716651f 6185/**\r
6186 Provides identify information for the controller type.\r
6187\r
6188 This function is used by the IDE bus driver to get identify data. Data format\r
6189 of Identify data is defined by the Interface GUID.\r
6190\r
d1102dba 6191 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL\r
d716651f 6192 instance.\r
4140a663 6193 @param[in, out] IdentifyData Pointer to a buffer for the identify data.\r
6194 @param[in, out] IdentifyDataSize Pointer to the value for the identify data\r
d716651f 6195 size.\r
6196\r
6197 @retval EFI_SUCCESS The command was accepted without any errors.\r
d1102dba
LG
6198 @retval EFI_NOT_FOUND Device does not support this data class\r
6199 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device\r
6200 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough\r
d716651f 6201\r
6202**/\r
6203EFI_STATUS\r
6204EFIAPI\r
6205ScsiDiskInfoIdentify (\r
1436aea4
MK
6206 IN EFI_DISK_INFO_PROTOCOL *This,\r
6207 IN OUT VOID *IdentifyData,\r
6208 IN OUT UINT32 *IdentifyDataSize\r
d716651f 6209 )\r
6210{\r
1436aea4
MK
6211 EFI_STATUS Status;\r
6212 SCSI_DISK_DEV *ScsiDiskDevice;\r
d716651f 6213\r
2bf87d82 6214 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {\r
d716651f 6215 //\r
d1102dba 6216 // Physical SCSI bus does not support this data class.\r
d716651f 6217 //\r
6218 return EFI_NOT_FOUND;\r
6219 }\r
6220\r
1436aea4 6221 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
d716651f 6222\r
6223 Status = EFI_BUFFER_TOO_SMALL;\r
6224 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {\r
6225 Status = EFI_SUCCESS;\r
6226 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));\r
6227 }\r
1436aea4 6228\r
d716651f 6229 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);\r
6230 return Status;\r
6231}\r
6232\r
6233/**\r
6234 Provides sense data information for the controller type.\r
d1102dba
LG
6235\r
6236 This function is used by the IDE bus driver to get sense data.\r
d716651f 6237 Data format of Sense data is defined by the Interface GUID.\r
6238\r
4140a663 6239 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
6240 @param[in, out] SenseData Pointer to the SenseData.\r
6241 @param[in, out] SenseDataSize Size of SenseData in bytes.\r
6242 @param[out] SenseDataNumber Pointer to the value for the sense data size.\r
d716651f 6243\r
6244 @retval EFI_SUCCESS The command was accepted without any errors.\r
6245 @retval EFI_NOT_FOUND Device does not support this data class.\r
6246 @retval EFI_DEVICE_ERROR Error reading SenseData from device.\r
6247 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.\r
6248\r
6249**/\r
6250EFI_STATUS\r
6251EFIAPI\r
6252ScsiDiskInfoSenseData (\r
1436aea4
MK
6253 IN EFI_DISK_INFO_PROTOCOL *This,\r
6254 IN OUT VOID *SenseData,\r
6255 IN OUT UINT32 *SenseDataSize,\r
6256 OUT UINT8 *SenseDataNumber\r
d716651f 6257 )\r
6258{\r
6259 return EFI_NOT_FOUND;\r
6260}\r
6261\r
d716651f 6262/**\r
6263 This function is used by the IDE bus driver to get controller information.\r
6264\r
d1102dba 6265 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
d716651f 6266 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.\r
6267 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.\r
6268\r
6269 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.\r
6270 @retval EFI_UNSUPPORTED This is not an IDE device.\r
6271\r
6272**/\r
6273EFI_STATUS\r
6274EFIAPI\r
6275ScsiDiskInfoWhichIde (\r
1436aea4
MK
6276 IN EFI_DISK_INFO_PROTOCOL *This,\r
6277 OUT UINT32 *IdeChannel,\r
6278 OUT UINT32 *IdeDevice\r
d716651f 6279 )\r
6280{\r
1436aea4 6281 SCSI_DISK_DEV *ScsiDiskDevice;\r
d716651f 6282\r
2bf87d82 6283 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid) || CompareGuid (&This->Interface, &gEfiDiskInfoUfsInterfaceGuid)) {\r
d716651f 6284 //\r
6285 // This is not an IDE physical device.\r
6286 //\r
6287 return EFI_UNSUPPORTED;\r
6288 }\r
6289\r
1436aea4
MK
6290 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
6291 *IdeChannel = ScsiDiskDevice->Channel;\r
6292 *IdeDevice = ScsiDiskDevice->Device;\r
d716651f 6293\r
6294 return EFI_SUCCESS;\r
6295}\r
6296\r
d716651f 6297/**\r
6298 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.\r
6299\r
6300 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to\r
6301 implement Identify() interface for DiskInfo protocol. The ATA command is sent\r
6302 via SCSI Request Packet.\r
6303\r
6304 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
d1102dba 6305\r
d716651f 6306 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.\r
6307 @retval others Some error occurred during the identification that ATAPI device.\r
6308\r
d1102dba 6309**/\r
d716651f 6310EFI_STATUS\r
6311AtapiIdentifyDevice (\r
1436aea4 6312 IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
d716651f 6313 )\r
6314{\r
1436aea4
MK
6315 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
6316 UINT8 Cdb[6];\r
d716651f 6317\r
6318 //\r
6319 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb\r
6320 //\r
6321 ZeroMem (&CommandPacket, sizeof (CommandPacket));\r
6322 ZeroMem (Cdb, sizeof (Cdb));\r
6323\r
1436aea4
MK
6324 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;\r
6325 CommandPacket.Timeout = SCSI_DISK_TIMEOUT;\r
6326 CommandPacket.Cdb = Cdb;\r
6327 CommandPacket.CdbLength = (UINT8)sizeof (Cdb);\r
6328 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;\r
d716651f 6329 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);\r
6330\r
6331 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);\r
6332}\r
6333\r
d716651f 6334/**\r
6335 Initialize the installation of DiskInfo protocol.\r
6336\r
6337 This function prepares for the installation of DiskInfo protocol on the child handle.\r
6338 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further\r
6339 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID\r
6340 to be IDE/AHCI interface GUID.\r
6341\r
6342 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
6343 @param ChildHandle Child handle to install DiskInfo protocol.\r
d1102dba
LG
6344\r
6345**/\r
d716651f 6346VOID\r
6347InitializeInstallDiskInfo (\r
1436aea4
MK
6348 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
6349 IN EFI_HANDLE ChildHandle\r
d716651f 6350 )\r
6351{\r
6352 EFI_STATUS Status;\r
6353 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
6354 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;\r
6355 ATAPI_DEVICE_PATH *AtapiDevicePath;\r
6356 SATA_DEVICE_PATH *SataDevicePath;\r
6357 UINTN IdentifyRetry;\r
6358\r
1436aea4 6359 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathNode);\r
d716651f 6360 //\r
d1102dba 6361 // Device Path protocol must be installed on the device handle.\r
d716651f 6362 //\r
6363 ASSERT_EFI_ERROR (Status);\r
6364 //\r
6365 // Copy the DiskInfo protocol template.\r
6366 //\r
6367 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));\r
6368\r
6369 while (!IsDevicePathEnd (DevicePathNode)) {\r
6370 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);\r
6371 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&\r
6372 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&\r
6373 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&\r
1436aea4
MK
6374 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||\r
6375 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP)))\r
6376 {\r
d716651f 6377 IdentifyRetry = 3;\r
6378 do {\r
6379 //\r
6380 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol\r
6381 // with IDE/AHCI interface GUID.\r
6382 //\r
6383 Status = AtapiIdentifyDevice (ScsiDiskDevice);\r
6384 if (!EFI_ERROR (Status)) {\r
1436aea4 6385 if (DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) {\r
d716651f 6386 //\r
6387 // We find the valid ATAPI device path\r
6388 //\r
1436aea4 6389 AtapiDevicePath = (ATAPI_DEVICE_PATH *)ChildDevicePathNode;\r
d716651f 6390 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;\r
1436aea4 6391 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;\r
d716651f 6392 //\r
d1102dba 6393 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device.\r
d716651f 6394 //\r
6395 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);\r
6396 } else {\r
6397 //\r
6398 // We find the valid SATA device path\r
6399 //\r
1436aea4 6400 SataDevicePath = (SATA_DEVICE_PATH *)ChildDevicePathNode;\r
d716651f 6401 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;\r
1436aea4 6402 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;\r
d716651f 6403 //\r
d1102dba 6404 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device.\r
d716651f 6405 //\r
6406 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);\r
6407 }\r
1436aea4 6408\r
d716651f 6409 return;\r
6410 }\r
6411 } while (--IdentifyRetry > 0);\r
2bf87d82 6412 } else if ((DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&\r
1436aea4
MK
6413 (DevicePathSubType (ChildDevicePathNode) == MSG_UFS_DP))\r
6414 {\r
2bf87d82
FT
6415 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoUfsInterfaceGuid);\r
6416 break;\r
d716651f 6417 }\r
1436aea4 6418\r
d716651f 6419 DevicePathNode = ChildDevicePathNode;\r
6420 }\r
6421\r
6422 return;\r
6423}\r