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