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