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