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