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