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