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