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