]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
Refine code to make code run more safely.
[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
cd5ebaa0
HT
4Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
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
6ad55b15 35/**\r
9beb888e 36 The user Entry Point for module ScsiDisk.\r
37\r
38 The user code starts with this function.\r
6ad55b15 39\r
9beb888e 40 @param ImageHandle The firmware allocated handle for the EFI image. \r
41 @param SystemTable A pointer to the EFI System Table.\r
6ad55b15 42 \r
43 @retval EFI_SUCCESS The entry point is executed successfully.\r
44 @retval other Some error occurs when executing this entry point.\r
45\r
46**/\r
47EFI_STATUS\r
48EFIAPI\r
49InitializeScsiDisk(\r
50 IN EFI_HANDLE ImageHandle,\r
51 IN EFI_SYSTEM_TABLE *SystemTable\r
52 )\r
53{\r
54 EFI_STATUS Status;\r
55\r
56 //\r
57 // Install driver model protocol(s).\r
58 //\r
70da5bc2 59 Status = EfiLibInstallDriverBindingComponentName2 (\r
6ad55b15 60 ImageHandle,\r
61 SystemTable,\r
62 &gScsiDiskDriverBinding,\r
63 ImageHandle,\r
64 &gScsiDiskComponentName,\r
70da5bc2 65 &gScsiDiskComponentName2\r
6ad55b15 66 );\r
67 ASSERT_EFI_ERROR (Status);\r
68\r
69\r
70 return Status;\r
71}\r
72\r
9beb888e 73/**\r
74 Test to see if this driver supports ControllerHandle.\r
75\r
76 This service is called by the EFI boot service ConnectController(). In order\r
77 to make drivers as small as possible, there are a few calling restrictions for\r
78 this service. ConnectController() must follow these calling restrictions.\r
79 If any other agent wishes to call Supported() it must also follow these\r
80 calling restrictions.\r
81\r
82 @param This Protocol instance pointer.\r
83 @param ControllerHandle Handle of device to test\r
84 @param RemainingDevicePath Optional parameter use to pick a specific child\r
85 device to start.\r
86\r
87 @retval EFI_SUCCESS This driver supports this device\r
88 @retval EFI_ALREADY_STARTED This driver is already running on this device\r
89 @retval other This driver does not support this device\r
90\r
91**/\r
6ad55b15 92EFI_STATUS\r
93EFIAPI\r
94ScsiDiskDriverBindingSupported (\r
95 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
96 IN EFI_HANDLE Controller,\r
9beb888e 97 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
6ad55b15 98 )\r
6ad55b15 99{\r
100 EFI_STATUS Status;\r
101 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
102 UINT8 DeviceType;\r
103\r
104 Status = gBS->OpenProtocol (\r
105 Controller,\r
106 &gEfiScsiIoProtocolGuid,\r
107 (VOID **) &ScsiIo,\r
108 This->DriverBindingHandle,\r
109 Controller,\r
110 EFI_OPEN_PROTOCOL_BY_DRIVER\r
111 );\r
112 if (EFI_ERROR (Status)) {\r
113 return Status;\r
114 }\r
115\r
116 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);\r
117 if (!EFI_ERROR (Status)) {\r
118 if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {\r
119 Status = EFI_SUCCESS;\r
120 } else {\r
121 Status = EFI_UNSUPPORTED;\r
122 }\r
123 }\r
124\r
125 gBS->CloseProtocol (\r
f36d6e66 126 Controller,\r
127 &gEfiScsiIoProtocolGuid,\r
128 This->DriverBindingHandle,\r
129 Controller\r
130 );\r
6ad55b15 131 return Status;\r
132}\r
133\r
9beb888e 134\r
135/**\r
136 Start this driver on ControllerHandle.\r
137\r
138 This service is called by the EFI boot service ConnectController(). In order\r
139 to make drivers as small as possible, there are a few calling restrictions for\r
140 this service. ConnectController() must follow these calling restrictions. If\r
141 any other agent wishes to call Start() it must also follow these calling\r
142 restrictions.\r
143\r
144 @param This Protocol instance pointer.\r
145 @param ControllerHandle Handle of device to bind driver to\r
146 @param RemainingDevicePath Optional parameter use to pick a specific child\r
147 device to start.\r
148\r
149 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
150 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
151 @retval other This driver does not support this device\r
152\r
153**/\r
6ad55b15 154EFI_STATUS\r
155EFIAPI\r
156ScsiDiskDriverBindingStart (\r
157 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
158 IN EFI_HANDLE Controller,\r
9beb888e 159 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
6ad55b15 160 )\r
6ad55b15 161{\r
162 EFI_STATUS Status;\r
163 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
164 SCSI_DISK_DEV *ScsiDiskDevice;\r
165 BOOLEAN Temp;\r
166 UINT8 Index;\r
167 UINT8 MaxRetry;\r
168 BOOLEAN NeedRetry;\r
169\r
9b38ff34 170 ScsiDiskDevice = (SCSI_DISK_DEV *) AllocateZeroPool (sizeof (SCSI_DISK_DEV));\r
171 if (ScsiDiskDevice == NULL) {\r
172 return EFI_OUT_OF_RESOURCES;\r
6ad55b15 173 }\r
174\r
6ad55b15 175 Status = gBS->OpenProtocol (\r
176 Controller,\r
177 &gEfiScsiIoProtocolGuid,\r
178 (VOID **) &ScsiIo,\r
179 This->DriverBindingHandle,\r
180 Controller,\r
181 EFI_OPEN_PROTOCOL_BY_DRIVER\r
182 );\r
183 if (EFI_ERROR (Status)) {\r
9b38ff34 184 FreePool (ScsiDiskDevice);\r
6ad55b15 185 return Status;\r
186 }\r
187\r
188 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;\r
189 ScsiDiskDevice->ScsiIo = ScsiIo;\r
190 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;\r
191 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;\r
192 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;\r
193 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;\r
194 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;\r
195 ScsiDiskDevice->Handle = Controller;\r
196\r
197 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));\r
198 switch (ScsiDiskDevice->DeviceType) {\r
199 case EFI_SCSI_TYPE_DISK:\r
200 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
201 break;\r
202\r
203 case EFI_SCSI_TYPE_CDROM:\r
204 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
205 break;\r
206 }\r
207 //\r
208 // The Sense Data Array's initial size is 6\r
209 //\r
210 ScsiDiskDevice->SenseDataNumber = 6;\r
9b38ff34 211 ScsiDiskDevice->SenseData = (EFI_SCSI_SENSE_DATA *) AllocateZeroPool (\r
212 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber\r
213 );\r
214 if (ScsiDiskDevice->SenseData == NULL) {\r
6ad55b15 215 gBS->CloseProtocol (\r
216 Controller,\r
217 &gEfiScsiIoProtocolGuid,\r
218 This->DriverBindingHandle,\r
219 Controller\r
220 );\r
9b38ff34 221 FreePool (ScsiDiskDevice);\r
222 return EFI_OUT_OF_RESOURCES;\r
6ad55b15 223 }\r
224\r
6ad55b15 225 //\r
dfe687ca 226 // Retrieve device information\r
6ad55b15 227 //\r
228 MaxRetry = 2;\r
229 for (Index = 0; Index < MaxRetry; Index++) {\r
230 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);\r
231 if (!EFI_ERROR (Status)) {\r
232 break;\r
233 }\r
234\r
235 if (!NeedRetry) {\r
9b38ff34 236 FreePool (ScsiDiskDevice->SenseData);\r
6ad55b15 237 gBS->CloseProtocol (\r
f36d6e66 238 Controller,\r
239 &gEfiScsiIoProtocolGuid,\r
240 This->DriverBindingHandle,\r
241 Controller\r
242 );\r
9b38ff34 243 FreePool (ScsiDiskDevice);\r
6ad55b15 244 return EFI_DEVICE_ERROR;\r
245 }\r
246 }\r
247 //\r
248 // The second parameter "TRUE" means must\r
249 // retrieve media capacity\r
250 //\r
251 Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);\r
252 if (!EFI_ERROR (Status)) {\r
d14faa52 253 //\r
254 // Determine if Block IO should be produced on this controller handle\r
255 //\r
256 if (DetermineInstallBlockIo(Controller)) {\r
d716651f 257 InitializeInstallDiskInfo(ScsiDiskDevice, Controller);\r
d14faa52 258 Status = gBS->InstallMultipleProtocolInterfaces (\r
259 &Controller,\r
260 &gEfiBlockIoProtocolGuid,\r
261 &ScsiDiskDevice->BlkIo,\r
d716651f 262 &gEfiDiskInfoProtocolGuid,\r
263 &ScsiDiskDevice->DiskInfo,\r
d14faa52 264 NULL\r
265 );\r
266 if (!EFI_ERROR(Status)) {\r
267 ScsiDiskDevice->ControllerNameTable = NULL;\r
268 AddUnicodeString2 (\r
269 "eng",\r
270 gScsiDiskComponentName.SupportedLanguages,\r
271 &ScsiDiskDevice->ControllerNameTable,\r
272 L"SCSI Disk Device",\r
273 TRUE\r
274 );\r
275 AddUnicodeString2 (\r
276 "en",\r
277 gScsiDiskComponentName2.SupportedLanguages,\r
278 &ScsiDiskDevice->ControllerNameTable,\r
279 L"SCSI Disk Device",\r
280 FALSE\r
281 );\r
282 return EFI_SUCCESS;\r
283 }\r
284 } \r
6ad55b15 285 }\r
286\r
d14faa52 287 gBS->FreePool (ScsiDiskDevice->SenseData);\r
288 gBS->FreePool (ScsiDiskDevice);\r
289 gBS->CloseProtocol (\r
290 Controller,\r
291 &gEfiScsiIoProtocolGuid,\r
292 This->DriverBindingHandle,\r
293 Controller\r
294 );\r
295 return Status;\r
296 \r
6ad55b15 297}\r
298\r
9beb888e 299\r
300/**\r
301 Stop this driver on ControllerHandle.\r
302\r
303 This service is called by the EFI boot service DisconnectController().\r
304 In order to make drivers as small as possible, there are a few calling\r
305 restrictions for this service. DisconnectController() must follow these\r
306 calling restrictions. If any other agent wishes to call Stop() it must\r
307 also follow these calling restrictions.\r
308 \r
309 @param This Protocol instance pointer.\r
310 @param ControllerHandle Handle of device to stop driver on\r
311 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
312 children is zero stop the entire bus driver.\r
313 @param ChildHandleBuffer List of Child Handles to Stop.\r
314\r
315 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
316 @retval other This driver was not removed from this device\r
317\r
318**/\r
6ad55b15 319EFI_STATUS\r
320EFIAPI\r
321ScsiDiskDriverBindingStop (\r
322 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
323 IN EFI_HANDLE Controller,\r
324 IN UINTN NumberOfChildren,\r
9beb888e 325 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
6ad55b15 326 )\r
6ad55b15 327{\r
328 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
329 SCSI_DISK_DEV *ScsiDiskDevice;\r
330 EFI_STATUS Status;\r
331\r
332 Status = gBS->OpenProtocol (\r
333 Controller,\r
334 &gEfiBlockIoProtocolGuid,\r
335 (VOID **) &BlkIo,\r
336 This->DriverBindingHandle,\r
337 Controller,\r
338 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
339 );\r
340 if (EFI_ERROR (Status)) {\r
341 return Status;\r
342 }\r
343\r
344 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);\r
d716651f 345 Status = gBS->UninstallMultipleProtocolInterfaces (\r
6ad55b15 346 Controller,\r
347 &gEfiBlockIoProtocolGuid,\r
d716651f 348 &ScsiDiskDevice->BlkIo,\r
349 &gEfiDiskInfoProtocolGuid,\r
350 &ScsiDiskDevice->DiskInfo,\r
351 NULL\r
6ad55b15 352 );\r
353 if (!EFI_ERROR (Status)) {\r
354 gBS->CloseProtocol (\r
f36d6e66 355 Controller,\r
356 &gEfiScsiIoProtocolGuid,\r
357 This->DriverBindingHandle,\r
358 Controller\r
359 );\r
6ad55b15 360\r
361 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);\r
362\r
363 return EFI_SUCCESS;\r
364 }\r
365 //\r
366 // errors met\r
367 //\r
368 return Status;\r
369}\r
370\r
9beb888e 371/**\r
372 Reset SCSI Disk.\r
373\r
6ad55b15 374\r
9beb888e 375 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
376 @param ExtendedVerification The flag about if extend verificate\r
377\r
378 @retval EFI_SUCCESS The device was reset.\r
379 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
380 not be reset.\r
d716651f 381 @return EFI_STATUS is returned from EFI_SCSI_IO_PROTOCOL.ResetDevice().\r
9beb888e 382\r
383**/\r
6ad55b15 384EFI_STATUS\r
385EFIAPI\r
386ScsiDiskReset (\r
387 IN EFI_BLOCK_IO_PROTOCOL *This,\r
388 IN BOOLEAN ExtendedVerification\r
389 )\r
6ad55b15 390{\r
f36d6e66 391 EFI_TPL OldTpl;\r
6ad55b15 392 SCSI_DISK_DEV *ScsiDiskDevice;\r
393 EFI_STATUS Status;\r
6ad55b15 394\r
395 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
396\r
397 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
398\r
399 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
400\r
c6e797ae 401 if (EFI_ERROR (Status)) {\r
402 Status = EFI_DEVICE_ERROR;\r
403 goto Done;\r
404 }\r
405\r
6ad55b15 406 if (!ExtendedVerification) {\r
407 goto Done;\r
408 }\r
409\r
410 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
411\r
c6e797ae 412 if (EFI_ERROR (Status)) {\r
413 Status = EFI_DEVICE_ERROR;\r
414 goto Done;\r
415 }\r
416\r
6ad55b15 417Done:\r
418 gBS->RestoreTPL (OldTpl);\r
419 return Status;\r
420}\r
421\r
9beb888e 422/**\r
423 The function is to Read Block from SCSI Disk.\r
424\r
425 @param This The pointer of EFI_BLOCK_IO_PROTOCOL.\r
426 @param MediaId The Id of Media detected\r
427 @param Lba The logic block address\r
428 @param BufferSize The size of Buffer\r
429 @param Buffer The buffer to fill the read out data\r
430\r
431 @retval EFI_SUCCESS Successfully to read out block.\r
432 @retval EFI_DEVICE_ERROR Fail to detect media.\r
433 @retval EFI_NO_MEDIA Media is not present.\r
434 @retval EFI_MEDIA_CHANGED Media has changed.\r
435 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
436 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
437\r
438**/\r
6ad55b15 439EFI_STATUS\r
440EFIAPI\r
441ScsiDiskReadBlocks (\r
442 IN EFI_BLOCK_IO_PROTOCOL *This,\r
443 IN UINT32 MediaId,\r
9beb888e 444 IN EFI_LBA Lba,\r
6ad55b15 445 IN UINTN BufferSize,\r
446 OUT VOID *Buffer\r
447 )\r
6ad55b15 448{\r
449 SCSI_DISK_DEV *ScsiDiskDevice;\r
450 EFI_BLOCK_IO_MEDIA *Media;\r
451 EFI_STATUS Status;\r
452 UINTN BlockSize;\r
453 UINTN NumberOfBlocks;\r
454 BOOLEAN MediaChange;\r
455 EFI_TPL OldTpl;\r
456\r
457 MediaChange = FALSE;\r
9beb888e 458 if (Buffer == NULL) {\r
6ad55b15 459 return EFI_INVALID_PARAMETER;\r
460 }\r
461\r
462 if (BufferSize == 0) {\r
463 return EFI_SUCCESS;\r
464 }\r
465\r
466 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
467\r
468 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
469\r
9beb888e 470 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
6ad55b15 471\r
472 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
473 if (EFI_ERROR (Status)) {\r
474 Status = EFI_DEVICE_ERROR;\r
475 goto Done;\r
476 }\r
477\r
478 if (MediaChange) {\r
479 gBS->ReinstallProtocolInterface (\r
480 ScsiDiskDevice->Handle,\r
481 &gEfiBlockIoProtocolGuid,\r
482 &ScsiDiskDevice->BlkIo,\r
483 &ScsiDiskDevice->BlkIo\r
484 );\r
485 }\r
486 }\r
487 //\r
488 // Get the intrinsic block size\r
489 //\r
490 Media = ScsiDiskDevice->BlkIo.Media;\r
491 BlockSize = Media->BlockSize;\r
492\r
493 NumberOfBlocks = BufferSize / BlockSize;\r
494\r
495 if (!(Media->MediaPresent)) {\r
496 Status = EFI_NO_MEDIA;\r
497 goto Done;\r
498 }\r
499\r
500 if (MediaId != Media->MediaId) {\r
501 Status = EFI_MEDIA_CHANGED;\r
502 goto Done;\r
503 }\r
504\r
505 if (BufferSize % BlockSize != 0) {\r
506 Status = EFI_BAD_BUFFER_SIZE;\r
507 goto Done;\r
508 }\r
509\r
9beb888e 510 if (Lba > Media->LastBlock) {\r
6ad55b15 511 Status = EFI_INVALID_PARAMETER;\r
512 goto Done;\r
513 }\r
514\r
9beb888e 515 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
6ad55b15 516 Status = EFI_INVALID_PARAMETER;\r
517 goto Done;\r
518 }\r
519\r
520 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
521 Status = EFI_INVALID_PARAMETER;\r
522 goto Done;\r
523 }\r
f36d6e66 524\r
6ad55b15 525 //\r
f36d6e66 526 // If all the parameters are valid, then perform read sectors command\r
6ad55b15 527 // to transfer data from device to host.\r
528 //\r
9beb888e 529 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
6ad55b15 530\r
531Done:\r
532 gBS->RestoreTPL (OldTpl);\r
533 return Status;\r
534}\r
535\r
9beb888e 536/**\r
537 The function is to Write Block to SCSI Disk.\r
538\r
539 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
540 @param MediaId The Id of Media detected\r
541 @param Lba The logic block address\r
542 @param BufferSize The size of Buffer\r
543 @param Buffer The buffer to fill the read out data\r
544\r
545 @retval EFI_SUCCESS Successfully to read out block.\r
546 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
547 @retval EFI_DEVICE_ERROR Fail to detect media.\r
548 @retval EFI_NO_MEDIA Media is not present.\r
549 @retval EFI_MEDIA_CHNAGED Media has changed.\r
550 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
551 @retval EFI_INVALID_PARAMETER Invalid parameter passed in.\r
552\r
553**/\r
6ad55b15 554EFI_STATUS\r
555EFIAPI\r
556ScsiDiskWriteBlocks (\r
557 IN EFI_BLOCK_IO_PROTOCOL *This,\r
558 IN UINT32 MediaId,\r
9beb888e 559 IN EFI_LBA Lba,\r
6ad55b15 560 IN UINTN BufferSize,\r
561 IN VOID *Buffer\r
562 )\r
6ad55b15 563{\r
564 SCSI_DISK_DEV *ScsiDiskDevice;\r
565 EFI_BLOCK_IO_MEDIA *Media;\r
566 EFI_STATUS Status;\r
567 UINTN BlockSize;\r
568 UINTN NumberOfBlocks;\r
569 BOOLEAN MediaChange;\r
570 EFI_TPL OldTpl;\r
571\r
572 MediaChange = FALSE;\r
9beb888e 573 if (Buffer == NULL) {\r
6ad55b15 574 return EFI_INVALID_PARAMETER;\r
575 }\r
576\r
577 if (BufferSize == 0) {\r
578 return EFI_SUCCESS;\r
579 }\r
580\r
581 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
582\r
583 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
584\r
9beb888e 585 if (!IS_DEVICE_FIXED(ScsiDiskDevice)) {\r
6ad55b15 586\r
587 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
588 if (EFI_ERROR (Status)) {\r
589 Status = EFI_DEVICE_ERROR;\r
590 goto Done;\r
591 }\r
592\r
593 if (MediaChange) {\r
594 gBS->ReinstallProtocolInterface (\r
595 ScsiDiskDevice->Handle,\r
596 &gEfiBlockIoProtocolGuid,\r
597 &ScsiDiskDevice->BlkIo,\r
598 &ScsiDiskDevice->BlkIo\r
599 );\r
600 }\r
601 }\r
602 //\r
603 // Get the intrinsic block size\r
604 //\r
605 Media = ScsiDiskDevice->BlkIo.Media;\r
606 BlockSize = Media->BlockSize;\r
607\r
608 NumberOfBlocks = BufferSize / BlockSize;\r
609\r
610 if (!(Media->MediaPresent)) {\r
611 Status = EFI_NO_MEDIA;\r
612 goto Done;\r
613 }\r
614\r
615 if (MediaId != Media->MediaId) {\r
616 Status = EFI_MEDIA_CHANGED;\r
617 goto Done;\r
618 }\r
619\r
620 if (BufferSize % BlockSize != 0) {\r
621 Status = EFI_BAD_BUFFER_SIZE;\r
622 goto Done;\r
623 }\r
624\r
9beb888e 625 if (Lba > Media->LastBlock) {\r
6ad55b15 626 Status = EFI_INVALID_PARAMETER;\r
627 goto Done;\r
628 }\r
629\r
9beb888e 630 if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {\r
6ad55b15 631 Status = EFI_INVALID_PARAMETER;\r
632 goto Done;\r
633 }\r
634\r
635 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
636 Status = EFI_INVALID_PARAMETER;\r
637 goto Done;\r
638 }\r
639 //\r
640 // if all the parameters are valid, then perform read sectors command\r
641 // to transfer data from device to host.\r
642 //\r
9beb888e 643 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, Lba, NumberOfBlocks);\r
6ad55b15 644\r
645Done:\r
646 gBS->RestoreTPL (OldTpl);\r
6ad55b15 647 return Status;\r
648}\r
649\r
9beb888e 650/**\r
651 Flush Block to Disk.\r
652\r
653 EFI_SUCCESS is returned directly.\r
654\r
655 @param This The pointer of EFI_BLOCK_IO_PROTOCOL\r
656\r
657 @retval EFI_SUCCESS All outstanding data was written to the device\r
658\r
659**/\r
6ad55b15 660EFI_STATUS\r
661EFIAPI\r
662ScsiDiskFlushBlocks (\r
663 IN EFI_BLOCK_IO_PROTOCOL *This\r
664 )\r
6ad55b15 665{\r
666 //\r
667 // return directly\r
668 //\r
669 return EFI_SUCCESS;\r
670}\r
671\r
6ad55b15 672\r
9beb888e 673/**\r
d716651f 674 Detect Device and read out capacity ,if error occurs, parse the sense key.\r
6ad55b15 675\r
9beb888e 676 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
677 @param MustReadCapacity The flag about reading device capacity\r
678 @param MediaChange The pointer of flag indicates if media has changed \r
6ad55b15 679\r
9beb888e 680 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
681 @retval EFI_SUCCESS Successfully to detect media\r
6ad55b15 682\r
9beb888e 683**/\r
684EFI_STATUS\r
685ScsiDiskDetectMedia (\r
686 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
687 IN BOOLEAN MustReadCapacity,\r
688 OUT BOOLEAN *MediaChange\r
689 )\r
6ad55b15 690{\r
691 EFI_STATUS Status;\r
692 EFI_STATUS ReadCapacityStatus;\r
693 EFI_SCSI_SENSE_DATA *SenseData;\r
694 UINTN NumberOfSenseKeys;\r
695 BOOLEAN NeedRetry;\r
696 BOOLEAN NeedReadCapacity;\r
697 UINT8 Index;\r
698 UINT8 MaxRetry;\r
699 EFI_BLOCK_IO_MEDIA OldMedia;\r
700 UINTN Action;\r
701\r
702 Status = EFI_SUCCESS;\r
703 ReadCapacityStatus = EFI_SUCCESS;\r
704 SenseData = NULL;\r
705 NumberOfSenseKeys = 0;\r
706 NeedReadCapacity = FALSE;\r
707 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
6ad55b15 708 *MediaChange = FALSE;\r
6ad55b15 709 MaxRetry = 3;\r
f36d6e66 710\r
6ad55b15 711 for (Index = 0; Index < MaxRetry; Index++) {\r
712 Status = ScsiDiskTestUnitReady (\r
713 ScsiDiskDevice,\r
714 &NeedRetry,\r
715 &SenseData,\r
716 &NumberOfSenseKeys\r
717 );\r
718 if (!EFI_ERROR (Status)) {\r
719 break;\r
720 }\r
721\r
722 if (!NeedRetry) {\r
723 return Status;\r
724 }\r
725 }\r
726\r
727 if ((Index == MaxRetry) && EFI_ERROR (Status)) {\r
728 return EFI_DEVICE_ERROR;\r
729 }\r
730\r
731 Status = DetectMediaParsingSenseKeys (\r
732 ScsiDiskDevice,\r
733 SenseData,\r
734 NumberOfSenseKeys,\r
735 &Action\r
736 );\r
737 if (EFI_ERROR (Status)) {\r
738 return Status;\r
739 }\r
740 //\r
741 // ACTION_NO_ACTION: need not read capacity\r
742 // other action code: need read capacity\r
743 //\r
744 if (Action == ACTION_NO_ACTION) {\r
745 NeedReadCapacity = FALSE;\r
746 } else {\r
747 NeedReadCapacity = TRUE;\r
748 }\r
f36d6e66 749\r
6ad55b15 750 //\r
751 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,\r
752 // retrieve capacity via Read Capacity command\r
753 //\r
754 if (NeedReadCapacity || MustReadCapacity) {\r
6ad55b15 755 //\r
756 // retrieve media information\r
757 //\r
758 MaxRetry = 3;\r
759 for (Index = 0; Index < MaxRetry; Index++) {\r
760\r
761 ReadCapacityStatus = ScsiDiskReadCapacity (\r
762 ScsiDiskDevice,\r
763 &NeedRetry,\r
764 &SenseData,\r
765 &NumberOfSenseKeys\r
766 );\r
767 if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {\r
768 return EFI_DEVICE_ERROR;\r
769 }\r
770 //\r
771 // analyze sense key to action\r
772 //\r
773 Status = DetectMediaParsingSenseKeys (\r
774 ScsiDiskDevice,\r
775 SenseData,\r
776 NumberOfSenseKeys,\r
777 &Action\r
778 );\r
779 //\r
780 // if Status is error, it may indicate crisis error,\r
781 // so return without retry.\r
782 //\r
783 if (EFI_ERROR (Status)) {\r
784 return Status;\r
785 }\r
786\r
787 switch (Action) {\r
788 case ACTION_NO_ACTION:\r
789 //\r
790 // no retry\r
791 //\r
792 Index = MaxRetry;\r
793 break;\r
794\r
795 case ACTION_RETRY_COMMAND_LATER:\r
796 //\r
797 // retry the ReadCapacity later and continuously, until the condition\r
798 // no longer emerges.\r
799 // stall time is 100000us, or say 0.1 second.\r
800 //\r
801 gBS->Stall (100000);\r
802 Index = 0;\r
803 break;\r
804\r
805 default:\r
806 //\r
807 // other cases, just retry the command\r
808 //\r
809 break;\r
810 }\r
811 }\r
812\r
813 if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {\r
814 return EFI_DEVICE_ERROR;\r
815 }\r
816 }\r
817\r
818 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {\r
819 //\r
820 // Media change information got from the device\r
821 //\r
822 *MediaChange = TRUE;\r
823 }\r
824\r
825 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {\r
826 *MediaChange = TRUE;\r
827 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
828 }\r
829\r
830 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {\r
831 *MediaChange = TRUE;\r
832 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
833 }\r
834\r
835 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {\r
836 *MediaChange = TRUE;\r
837 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
838 }\r
839\r
840 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {\r
841 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {\r
842 //\r
843 // when change from no media to media present, reset the MediaId to 1.\r
844 //\r
845 ScsiDiskDevice->BlkIo.Media->MediaId = 1;\r
846 } else {\r
847 //\r
848 // when no media, reset the MediaId to zero.\r
849 //\r
850 ScsiDiskDevice->BlkIo.Media->MediaId = 0;\r
851 }\r
852\r
853 *MediaChange = TRUE;\r
854 }\r
855\r
856 return EFI_SUCCESS;\r
857}\r
858\r
6ad55b15 859\r
9beb888e 860/**\r
861 Send out Inquiry command to Device.\r
6ad55b15 862\r
9beb888e 863 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
864 @param NeedRetry Indicates if needs try again when error happens\r
6ad55b15 865\r
9beb888e 866 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
867 @retval EFI_SUCCESS Successfully to detect media\r
6ad55b15 868\r
9beb888e 869**/\r
870EFI_STATUS\r
871ScsiDiskInquiryDevice (\r
872 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
873 OUT BOOLEAN *NeedRetry\r
874 )\r
6ad55b15 875{\r
876 UINT32 InquiryDataLength;\r
877 UINT8 SenseDataLength;\r
878 UINT8 HostAdapterStatus;\r
879 UINT8 TargetStatus;\r
880 EFI_SCSI_SENSE_DATA *SenseDataArray;\r
881 UINTN NumberOfSenseKeys;\r
882 EFI_STATUS Status;\r
883 UINT8 MaxRetry;\r
884 UINT8 Index;\r
885\r
886 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
887 SenseDataLength = 0;\r
888\r
d35be2a4 889 Status = ScsiInquiryCommand (\r
6ad55b15 890 ScsiDiskDevice->ScsiIo,\r
e72a3b3e 891 EFI_TIMER_PERIOD_SECONDS (1),\r
6ad55b15 892 NULL,\r
893 &SenseDataLength,\r
894 &HostAdapterStatus,\r
895 &TargetStatus,\r
896 (VOID *) &(ScsiDiskDevice->InquiryData),\r
897 &InquiryDataLength,\r
898 FALSE\r
899 );\r
6ad55b15 900 //\r
901 // no need to check HostAdapterStatus and TargetStatus\r
902 //\r
f36d6e66 903 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
904 ParseInquiryData (ScsiDiskDevice);\r
905 return EFI_SUCCESS;\r
906 \r
907 } else if (Status == EFI_NOT_READY) {\r
908 *NeedRetry = TRUE;\r
909 return EFI_DEVICE_ERROR;\r
910 \r
911 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
912 *NeedRetry = FALSE;\r
913 return EFI_DEVICE_ERROR;\r
914 }\r
915 //\r
916 // go ahead to check HostAdapterStatus and TargetStatus\r
917 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
918 //\r
919 \r
920 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
921 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
922 *NeedRetry = TRUE;\r
923 return EFI_DEVICE_ERROR;\r
924 } else if (Status == EFI_DEVICE_ERROR) {\r
925 //\r
926 // reset the scsi channel\r
927 //\r
6ad55b15 928 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
929 *NeedRetry = FALSE;\r
930 return EFI_DEVICE_ERROR;\r
931 }\r
932\r
933 Status = CheckTargetStatus (TargetStatus);\r
934 if (Status == EFI_NOT_READY) {\r
935 //\r
936 // reset the scsi device\r
937 //\r
938 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
939 *NeedRetry = TRUE;\r
940 return EFI_DEVICE_ERROR;\r
f36d6e66 941\r
6ad55b15 942 } else if (Status == EFI_DEVICE_ERROR) {\r
943 *NeedRetry = FALSE;\r
944 return EFI_DEVICE_ERROR;\r
945 }\r
946 \r
947 //\r
b96cd313 948 // if goes here, meant ScsiInquiryCommand() failed.\r
6ad55b15 949 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
b96cd313 950 // better retry ScsiInquiryCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 951 //\r
952 MaxRetry = 3;\r
953 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 954 Status = ScsiDiskRequestSenseKeys (\r
955 ScsiDiskDevice,\r
956 NeedRetry,\r
957 &SenseDataArray,\r
958 &NumberOfSenseKeys,\r
959 TRUE\r
960 );\r
961 if (!EFI_ERROR (Status)) {\r
962 *NeedRetry = TRUE;\r
963 return EFI_DEVICE_ERROR;\r
964 }\r
965\r
966 if (!*NeedRetry) {\r
967 return EFI_DEVICE_ERROR;\r
968 }\r
969 }\r
970 //\r
971 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
972 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
973 //\r
974 *NeedRetry = FALSE;\r
975 return EFI_DEVICE_ERROR;\r
976}\r
977\r
9beb888e 978/**\r
d716651f 979 To test device.\r
f36d6e66 980\r
981 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;\r
6ad55b15 982 When Test Unit Ready command encounters any error caused by host adapter or\r
983 target, return error without retrieving Sense Keys.\r
f36d6e66 984\r
9beb888e 985 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
986 @param NeedRetry The pointer of flag indicates try again\r
987 @param SenseDataArray The pointer of an array of sense data\r
988 @param NumberOfSenseKeys The pointer of the number of sense data array\r
f36d6e66 989\r
9beb888e 990 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
991 @retval EFI_SUCCESS Successfully to test unit\r
f36d6e66 992\r
9beb888e 993**/\r
994EFI_STATUS\r
995ScsiDiskTestUnitReady (\r
996 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
997 OUT BOOLEAN *NeedRetry,\r
998 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
999 OUT UINTN *NumberOfSenseKeys\r
1000 )\r
6ad55b15 1001{\r
1002 EFI_STATUS Status;\r
1003 UINT8 SenseDataLength;\r
1004 UINT8 HostAdapterStatus;\r
1005 UINT8 TargetStatus;\r
1006 UINT8 Index;\r
1007 UINT8 MaxRetry;\r
1008\r
1009 SenseDataLength = 0;\r
1010 *NumberOfSenseKeys = 0;\r
1011\r
1012 //\r
1013 // Parameter 3 and 4: do not require sense data, retrieve it when needed.\r
1014 //\r
d35be2a4 1015 Status = ScsiTestUnitReadyCommand (\r
6ad55b15 1016 ScsiDiskDevice->ScsiIo,\r
e72a3b3e 1017 EFI_TIMER_PERIOD_SECONDS (1),\r
6ad55b15 1018 NULL,\r
1019 &SenseDataLength,\r
1020 &HostAdapterStatus,\r
1021 &TargetStatus\r
1022 );\r
f36d6e66 1023 //\r
1024 // no need to check HostAdapterStatus and TargetStatus\r
1025 //\r
6ad55b15 1026 if (Status == EFI_NOT_READY) {\r
6ad55b15 1027 *NeedRetry = TRUE;\r
1028 return EFI_DEVICE_ERROR;\r
f36d6e66 1029\r
6ad55b15 1030 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
6ad55b15 1031 *NeedRetry = FALSE;\r
1032 return EFI_DEVICE_ERROR;\r
1033 }\r
1034 //\r
f36d6e66 1035 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)\r
6ad55b15 1036 //\r
f36d6e66 1037\r
6ad55b15 1038 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
1039 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1040 *NeedRetry = TRUE;\r
1041 return EFI_DEVICE_ERROR;\r
f36d6e66 1042\r
6ad55b15 1043 } else if (Status == EFI_DEVICE_ERROR) {\r
1044 //\r
1045 // reset the scsi channel\r
1046 //\r
1047 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
1048 *NeedRetry = FALSE;\r
1049 return EFI_DEVICE_ERROR;\r
1050 }\r
1051\r
1052 Status = CheckTargetStatus (TargetStatus);\r
1053 if (Status == EFI_NOT_READY) {\r
1054 //\r
1055 // reset the scsi device\r
1056 //\r
1057 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1058 *NeedRetry = TRUE;\r
1059 return EFI_DEVICE_ERROR;\r
f36d6e66 1060\r
6ad55b15 1061 } else if (Status == EFI_DEVICE_ERROR) {\r
1062 *NeedRetry = FALSE;\r
1063 return EFI_DEVICE_ERROR;\r
1064 }\r
1065\r
1066 MaxRetry = 3;\r
1067 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 1068 Status = ScsiDiskRequestSenseKeys (\r
1069 ScsiDiskDevice,\r
1070 NeedRetry,\r
1071 SenseDataArray,\r
1072 NumberOfSenseKeys,\r
1073 FALSE\r
1074 );\r
1075 if (!EFI_ERROR (Status)) {\r
1076 return EFI_SUCCESS;\r
1077 }\r
1078\r
1079 if (!*NeedRetry) {\r
1080 return EFI_DEVICE_ERROR;\r
1081 }\r
1082 }\r
1083 //\r
1084 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1085 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1086 //\r
1087 *NeedRetry = FALSE;\r
1088 return EFI_DEVICE_ERROR;\r
1089}\r
1090\r
9beb888e 1091/**\r
f36d6e66 1092 Parsing Sense Keys which got from request sense command.\r
6ad55b15 1093\r
9beb888e 1094 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1095 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
1096 @param NumberOfSenseKeys The number of sense key \r
1097 @param Action The pointer of action which indicates what is need to do next\r
6ad55b15 1098\r
9beb888e 1099 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
1100 @retval EFI_SUCCESS Successfully to complete the parsing\r
6ad55b15 1101\r
9beb888e 1102**/\r
1103EFI_STATUS\r
1104DetectMediaParsingSenseKeys (\r
1105 OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1106 IN EFI_SCSI_SENSE_DATA *SenseData,\r
1107 IN UINTN NumberOfSenseKeys,\r
1108 OUT UINTN *Action\r
1109 )\r
6ad55b15 1110{\r
1111 BOOLEAN RetryLater;\r
1112\r
1113 //\r
1114 // Default is to read capacity, unless..\r
1115 //\r
1116 *Action = ACTION_READ_CAPACITY;\r
1117\r
1118 if (NumberOfSenseKeys == 0) {\r
1119 *Action = ACTION_NO_ACTION;\r
1120 return EFI_SUCCESS;\r
1121 }\r
1122\r
1123 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {\r
1124 //\r
1125 // No Sense Key returned from last submitted command\r
1126 //\r
1127 *Action = ACTION_NO_ACTION;\r
1128 return EFI_SUCCESS;\r
1129 }\r
1130\r
1131 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {\r
1132 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
1133 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1134 *Action = ACTION_NO_ACTION;\r
1135 return EFI_SUCCESS;\r
1136 }\r
1137\r
1138 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {\r
1139 ScsiDiskDevice->BlkIo.Media->MediaId++;\r
1140 return EFI_SUCCESS;\r
1141 }\r
1142\r
1143 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
1144 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
1145 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1146 return EFI_DEVICE_ERROR;\r
1147 }\r
1148\r
1149 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {\r
1150 return EFI_DEVICE_ERROR;\r
1151 }\r
1152\r
1153 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {\r
1154 if (RetryLater) {\r
1155 *Action = ACTION_RETRY_COMMAND_LATER;\r
1156 return EFI_SUCCESS;\r
1157 }\r
1158\r
1159 return EFI_DEVICE_ERROR;\r
1160 }\r
1161\r
1162 return EFI_SUCCESS;\r
1163}\r
1164\r
6ad55b15 1165\r
9beb888e 1166/**\r
1167 Send read capacity command to device and get the device parameter.\r
6ad55b15 1168\r
9beb888e 1169 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1170 @param NeedRetry The pointer of flag indicates if need a retry\r
1171 @param SenseDataArray The pointer of an array of sense data\r
1172 @param NumberOfSenseKeys The number of sense key\r
6ad55b15 1173\r
9beb888e 1174 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
1175 @retval EFI_SUCCESS Successfully to read capacity\r
6ad55b15 1176\r
9beb888e 1177**/\r
1178EFI_STATUS\r
1179ScsiDiskReadCapacity (\r
1180 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1181 OUT BOOLEAN *NeedRetry,\r
1182 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1183 OUT UINTN *NumberOfSenseKeys\r
1184 )\r
6ad55b15 1185{\r
b96cd313 1186 UINT8 HostAdapterStatus;\r
1187 UINT8 TargetStatus;\r
1188 EFI_STATUS CommandStatus;\r
1189 EFI_STATUS Status;\r
1190 UINT8 Index;\r
1191 UINT8 MaxRetry;\r
1192 UINT8 SenseDataLength;\r
b96cd313 1193 UINT32 DataLength10;\r
1194 UINT32 DataLength16;\r
1195 EFI_SCSI_DISK_CAPACITY_DATA CapacityData10;\r
1196 EFI_SCSI_DISK_CAPACITY_DATA16 CapacityData16;\r
1197\r
1198\r
1199 SenseDataLength = 0;\r
1200 DataLength10 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
1201 DataLength16 = sizeof (EFI_SCSI_DISK_CAPACITY_DATA16);\r
1202 ZeroMem (&CapacityData10, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
1203 ZeroMem (&CapacityData16, sizeof (EFI_SCSI_DISK_CAPACITY_DATA16));\r
6ad55b15 1204\r
1205 *NumberOfSenseKeys = 0;\r
1206 *NeedRetry = FALSE;\r
b96cd313 1207\r
f95bc048 1208 //\r
1209 // submit Read Capacity(10) Command. If it returns capacity of FFFFFFFFh, \r
1210 // 16 byte command should be used to access large hard disk >2TB\r
1211 //\r
1212 CommandStatus = ScsiReadCapacityCommand (\r
1213 ScsiDiskDevice->ScsiIo,\r
1214 EFI_TIMER_PERIOD_SECONDS(1),\r
1215 NULL,\r
1216 &SenseDataLength,\r
1217 &HostAdapterStatus,\r
1218 &TargetStatus,\r
1219 (VOID *) &CapacityData10,\r
1220 &DataLength10,\r
1221 FALSE\r
1222 );\r
1223\r
1224 ScsiDiskDevice->Cdb16Byte = FALSE;\r
1225 if ((!EFI_ERROR (CommandStatus)) && (CapacityData10.LastLba3 == 0xff) && (CapacityData10.LastLba2 == 0xff) &&\r
1226 (CapacityData10.LastLba1 == 0xff) && (CapacityData10.LastLba0 == 0xff)) {\r
1227 //\r
1228 // use Read Capacity (16), Read (16) and Write (16) next when hard disk size > 2TB\r
1229 //\r
1230 ScsiDiskDevice->Cdb16Byte = TRUE;\r
b96cd313 1231 //\r
f95bc048 1232 // submit Read Capacity(16) Command to get parameter LogicalBlocksPerPhysicalBlock\r
1233 // and LowestAlignedLba\r
b96cd313 1234 //\r
f95bc048 1235 CommandStatus = ScsiReadCapacity16Command (\r
b96cd313 1236 ScsiDiskDevice->ScsiIo,\r
f95bc048 1237 EFI_TIMER_PERIOD_SECONDS (1),\r
b96cd313 1238 NULL,\r
1239 &SenseDataLength,\r
1240 &HostAdapterStatus,\r
1241 &TargetStatus,\r
f95bc048 1242 (VOID *) &CapacityData16,\r
1243 &DataLength16,\r
b96cd313 1244 FALSE\r
1245 );\r
f95bc048 1246 }\r
1247\r
b96cd313 1248 //\r
6ad55b15 1249 // no need to check HostAdapterStatus and TargetStatus\r
1250 //\r
f36d6e66 1251 if (CommandStatus == EFI_SUCCESS) {\r
b96cd313 1252 GetMediaInfo (ScsiDiskDevice, &CapacityData10,&CapacityData16);\r
f36d6e66 1253 return EFI_SUCCESS;\r
1254 \r
1255 } else if (CommandStatus == EFI_NOT_READY) {\r
1256 *NeedRetry = TRUE;\r
1257 return EFI_DEVICE_ERROR;\r
1258 \r
1259 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {\r
1260 *NeedRetry = FALSE;\r
1261 return EFI_DEVICE_ERROR;\r
1262 }\r
1263 //\r
1264 // go ahead to check HostAdapterStatus and TargetStatus\r
1265 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
1266 //\r
1267 \r
1268 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
1269 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1270 *NeedRetry = TRUE;\r
1271 return EFI_DEVICE_ERROR;\r
1272 \r
1273 } else if (Status == EFI_DEVICE_ERROR) {\r
6ad55b15 1274 //\r
1275 // reset the scsi channel\r
1276 //\r
1277 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
1278 *NeedRetry = FALSE;\r
1279 return EFI_DEVICE_ERROR;\r
1280 }\r
1281\r
1282 Status = CheckTargetStatus (TargetStatus);\r
1283 if (Status == EFI_NOT_READY) {\r
1284 //\r
1285 // reset the scsi device\r
1286 //\r
1287 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1288 *NeedRetry = TRUE;\r
1289 return EFI_DEVICE_ERROR;\r
f36d6e66 1290\r
6ad55b15 1291 } else if (Status == EFI_DEVICE_ERROR) {\r
1292 *NeedRetry = FALSE;\r
1293 return EFI_DEVICE_ERROR;\r
1294 }\r
1295 \r
1296 //\r
b96cd313 1297 // if goes here, meant ScsiReadCapacityCommand() failed.\r
6ad55b15 1298 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
b96cd313 1299 // better retry ScsiReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 1300 //\r
1301 MaxRetry = 3;\r
1302 for (Index = 0; Index < MaxRetry; Index++) {\r
1303\r
1304 Status = ScsiDiskRequestSenseKeys (\r
1305 ScsiDiskDevice,\r
1306 NeedRetry,\r
1307 SenseDataArray,\r
1308 NumberOfSenseKeys,\r
1309 TRUE\r
1310 );\r
1311 if (!EFI_ERROR (Status)) {\r
1312 *NeedRetry = TRUE;\r
1313 return EFI_DEVICE_ERROR;\r
1314 }\r
1315\r
1316 if (!*NeedRetry) {\r
1317 return EFI_DEVICE_ERROR;\r
1318 }\r
1319 }\r
1320 //\r
1321 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1322 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1323 //\r
1324 *NeedRetry = FALSE;\r
1325 return EFI_DEVICE_ERROR;\r
1326}\r
1327\r
9beb888e 1328/**\r
1329 Check the HostAdapter status and re-interpret it in EFI_STATUS.\r
6ad55b15 1330\r
9beb888e 1331 @param HostAdapterStatus Host Adapter status\r
6ad55b15 1332\r
9beb888e 1333 @retval EFI_SUCCESS Host adapter is OK.\r
1334 @retval EFI_TIMEOUT Timeout.\r
1335 @retval EFI_NOT_READY Adapter NOT ready.\r
1336 @retval EFI_DEVICE_ERROR Adapter device error.\r
6ad55b15 1337\r
9beb888e 1338**/\r
1339EFI_STATUS\r
1340CheckHostAdapterStatus (\r
1341 IN UINT8 HostAdapterStatus\r
1342 )\r
6ad55b15 1343{\r
1344 switch (HostAdapterStatus) {\r
f36d6e66 1345 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:\r
6ad55b15 1346 return EFI_SUCCESS;\r
1347\r
f36d6e66 1348 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:\r
1349 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:\r
1350 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:\r
6ad55b15 1351 return EFI_TIMEOUT;\r
1352\r
f36d6e66 1353 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:\r
1354 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:\r
1355 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:\r
1356 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:\r
1357 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:\r
6ad55b15 1358 return EFI_NOT_READY;\r
1359\r
f36d6e66 1360 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:\r
1361 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:\r
6ad55b15 1362 return EFI_DEVICE_ERROR;\r
1363\r
1364 default:\r
1365 return EFI_SUCCESS;\r
1366 }\r
1367}\r
1368\r
6ad55b15 1369\r
9beb888e 1370/**\r
1371 Check the target status and re-interpret it in EFI_STATUS.\r
6ad55b15 1372\r
9beb888e 1373 @param TargetStatus Target status\r
6ad55b15 1374\r
9beb888e 1375 @retval EFI_NOT_READY Device is NOT ready.\r
1376 @retval EFI_DEVICE_ERROR \r
1377 @retval EFI_SUCCESS\r
6ad55b15 1378\r
9beb888e 1379**/\r
1380EFI_STATUS\r
1381CheckTargetStatus (\r
1382 IN UINT8 TargetStatus\r
1383 )\r
6ad55b15 1384{\r
1385 switch (TargetStatus) {\r
f36d6e66 1386 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:\r
1387 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:\r
1388 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:\r
6ad55b15 1389 return EFI_SUCCESS;\r
1390\r
f36d6e66 1391 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:\r
1392 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:\r
1393 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:\r
1394 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:\r
6ad55b15 1395 return EFI_NOT_READY;\r
1396\r
f36d6e66 1397 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:\r
6ad55b15 1398 return EFI_DEVICE_ERROR;\r
1399 break;\r
1400\r
1401 default:\r
1402 return EFI_SUCCESS;\r
1403 }\r
1404}\r
1405\r
f36d6e66 1406\r
9beb888e 1407/**\r
6ad55b15 1408 Retrieve all sense keys from the device.\r
f36d6e66 1409\r
9beb888e 1410 When encountering error during the process, if retrieve sense keys before\r
d716651f 1411 error encountered, it returns the sense keys with return status set to EFI_SUCCESS,\r
9beb888e 1412 and NeedRetry set to FALSE; otherwize, return the proper return status.\r
1413\r
1414 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1415 @param NeedRetry The pointer of flag indicates if need a retry\r
1416 @param SenseDataArray The pointer of an array of sense data\r
1417 @param NumberOfSenseKeys The number of sense key\r
1418 @param AskResetIfError The flag indicates if need reset when error occurs\r
1419\r
1420 @retval EFI_DEVICE_ERROR Indicates that error occurs\r
1421 @retval EFI_SUCCESS Successfully to request sense key\r
f36d6e66 1422\r
9beb888e 1423**/\r
1424EFI_STATUS\r
1425ScsiDiskRequestSenseKeys (\r
1426 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1427 OUT BOOLEAN *NeedRetry,\r
1428 OUT EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1429 OUT UINTN *NumberOfSenseKeys,\r
1430 IN BOOLEAN AskResetIfError\r
1431 )\r
6ad55b15 1432{\r
1433 EFI_SCSI_SENSE_DATA *PtrSenseData;\r
1434 UINT8 SenseDataLength;\r
1435 BOOLEAN SenseReq;\r
1436 EFI_STATUS Status;\r
1437 EFI_STATUS FallStatus;\r
1438 UINT8 HostAdapterStatus;\r
1439 UINT8 TargetStatus;\r
1440\r
1441 FallStatus = EFI_SUCCESS;\r
c9325700 1442 SenseDataLength = (UINT8) sizeof (EFI_SCSI_SENSE_DATA);\r
6ad55b15 1443\r
1444 ZeroMem (\r
1445 ScsiDiskDevice->SenseData,\r
1446 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)\r
1447 );\r
1448\r
1449 *NumberOfSenseKeys = 0;\r
1450 *SenseDataArray = ScsiDiskDevice->SenseData;\r
1451 PtrSenseData = ScsiDiskDevice->SenseData;\r
1452\r
1453 for (SenseReq = TRUE; SenseReq;) {\r
d35be2a4 1454 Status = ScsiRequestSenseCommand (\r
6ad55b15 1455 ScsiDiskDevice->ScsiIo,\r
e72a3b3e 1456 EFI_TIMER_PERIOD_SECONDS (2),\r
6ad55b15 1457 PtrSenseData,\r
1458 &SenseDataLength,\r
1459 &HostAdapterStatus,\r
1460 &TargetStatus\r
1461 );\r
f36d6e66 1462 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
1463 FallStatus = EFI_SUCCESS;\r
1464 \r
1465 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1466 *NeedRetry = TRUE;\r
1467 FallStatus = EFI_DEVICE_ERROR;\r
1468 \r
1469 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
1470 *NeedRetry = FALSE;\r
1471 FallStatus = EFI_DEVICE_ERROR;\r
1472 \r
1473 } else if (Status == EFI_DEVICE_ERROR) {\r
1474 if (AskResetIfError) {\r
1475 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1476 }\r
1477 \r
1478 FallStatus = EFI_DEVICE_ERROR;\r
6ad55b15 1479 }\r
1480\r
1481 if (EFI_ERROR (FallStatus)) {\r
1482 if (*NumberOfSenseKeys != 0) {\r
1483 *NeedRetry = FALSE;\r
1484 return EFI_SUCCESS;\r
1485 } else {\r
1486 return EFI_DEVICE_ERROR;\r
1487 }\r
1488 }\r
1489\r
1490 (*NumberOfSenseKeys) += 1;\r
1491\r
1492 //\r
1493 // no more sense key or number of sense keys exceeds predefined,\r
1494 // skip the loop.\r
1495 //\r
1496 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) || \r
1497 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {\r
1498 SenseReq = FALSE;\r
1499 }\r
6ad55b15 1500 PtrSenseData += 1;\r
6ad55b15 1501 }\r
6ad55b15 1502 return EFI_SUCCESS;\r
1503}\r
1504\r
6ad55b15 1505\r
9beb888e 1506/**\r
1507 Get information from media read capacity command.\r
6ad55b15 1508\r
9beb888e 1509 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
aa75dfec 1510 @param Capacity10 The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
1511 @param Capacity16 The pointer of EFI_SCSI_DISK_CAPACITY_DATA16\r
6ad55b15 1512\r
9beb888e 1513**/\r
1514VOID\r
1515GetMediaInfo (\r
aa75dfec 1516 IN OUT SCSI_DISK_DEV *ScsiDiskDevice,\r
1517 IN EFI_SCSI_DISK_CAPACITY_DATA *Capacity10,\r
1518 IN EFI_SCSI_DISK_CAPACITY_DATA16 *Capacity16\r
9beb888e 1519 )\r
6ad55b15 1520{\r
b96cd313 1521 UINT8 *Ptr;\r
1522\r
b96cd313 1523 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = 0;\r
1524 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;\r
1525 \r
1526\r
f95bc048 1527 if (!ScsiDiskDevice->Cdb16Byte) {\r
b96cd313 1528 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity10->LastLba3 << 24) |\r
1529 (Capacity10->LastLba2 << 16) |\r
1530 (Capacity10->LastLba1 << 8) |\r
1531 Capacity10->LastLba0;\r
1532 \r
1533 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity10->BlockSize3 << 24) |\r
1534 (Capacity10->BlockSize2 << 16) | \r
1535 (Capacity10->BlockSize1 << 8) |\r
1536 Capacity10->BlockSize0;\r
1537 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION; \r
1538 } else {\r
1539\r
1540 Ptr = (UINT8*)&ScsiDiskDevice->BlkIo.Media->LastBlock;\r
1541 *Ptr++ = Capacity16->LastLba0;\r
1542 *Ptr++ = Capacity16->LastLba1;\r
1543 *Ptr++ = Capacity16->LastLba2;\r
1544 *Ptr++ = Capacity16->LastLba3;\r
1545 *Ptr++ = Capacity16->LastLba4;\r
1546 *Ptr++ = Capacity16->LastLba5;\r
1547 *Ptr++ = Capacity16->LastLba6;\r
1548 *Ptr = Capacity16->LastLba7;\r
1549 \r
1550 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity16->BlockSize3 << 24) |\r
1551 (Capacity16->BlockSize2 << 16) | \r
1552 (Capacity16->BlockSize1 << 8) |\r
1553 Capacity16->BlockSize0;\r
1554\r
1555 ScsiDiskDevice->BlkIo.Media->LowestAlignedLba = (Capacity16->LowestAlignLogic2 << 8)|(Capacity16->LowestAlignLogic1);\r
1556 ScsiDiskDevice->BlkIo.Media->LogicalBlocksPerPhysicalBlock = Capacity16->LogicPerPhysical;\r
1557 ScsiDiskDevice->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2; \r
1558 }\r
1559\r
6ad55b15 1560\r
1561 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
b96cd313 1562 \r
6ad55b15 1563 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
1564 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
1565 }\r
1566\r
1567 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {\r
1568 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
1569 }\r
1570}\r
1571\r
9beb888e 1572/**\r
1573 Parse Inquiry data.\r
1574\r
1575 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
1576\r
1577**/\r
6ad55b15 1578VOID\r
1579ParseInquiryData (\r
9beb888e 1580 IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
6ad55b15 1581 )\r
6ad55b15 1582{\r
fbfa4a1d 1583 ScsiDiskDevice->FixedDevice = (BOOLEAN) ((ScsiDiskDevice->InquiryData.Rmb == 1) ? 0 : 1);\r
6ad55b15 1584 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);\r
1585}\r
1586\r
9beb888e 1587/**\r
1588 Read sector from SCSI Disk.\r
6ad55b15 1589\r
d716651f 1590 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
9beb888e 1591 @param Buffer The buffer to fill in the read out data\r
1592 @param Lba Logic block address\r
1593 @param NumberOfBlocks The number of blocks to read\r
6ad55b15 1594\r
9beb888e 1595 @retval EFI_DEVICE_ERROR Indicates a device error.\r
1596 @retval EFI_SUCCESS Operation is successful.\r
6ad55b15 1597\r
9beb888e 1598**/\r
1599EFI_STATUS\r
1600ScsiDiskReadSectors (\r
1601 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1602 OUT VOID *Buffer,\r
1603 IN EFI_LBA Lba,\r
1604 IN UINTN NumberOfBlocks\r
1605 )\r
6ad55b15 1606{\r
1607 UINTN BlocksRemaining;\r
6ad55b15 1608 UINT8 *PtrBuffer;\r
1609 UINT32 BlockSize;\r
1610 UINT32 ByteCount;\r
1611 UINT32 MaxBlock;\r
1612 UINT32 SectorCount;\r
1613 UINT64 Timeout;\r
1614 EFI_STATUS Status;\r
1615 UINT8 Index;\r
1616 UINT8 MaxRetry;\r
1617 BOOLEAN NeedRetry;\r
1618 EFI_SCSI_SENSE_DATA *SenseData;\r
1619 UINTN NumberOfSenseKeys;\r
1620\r
1621 SenseData = NULL;\r
1622 NumberOfSenseKeys = 0;\r
1623\r
1624 Status = EFI_SUCCESS;\r
1625\r
1626 BlocksRemaining = NumberOfBlocks;\r
1627 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
a108933e 1628 \r
6ad55b15 1629 //\r
a108933e 1630 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
6ad55b15 1631 //\r
f95bc048 1632 if (!ScsiDiskDevice->Cdb16Byte) {\r
5bf5fb30 1633 MaxBlock = 0xFFFF;\r
a108933e 1634 } else {\r
5bf5fb30 1635 MaxBlock = 0xFFFFFFFF;\r
a108933e 1636 }\r
6ad55b15 1637\r
1638 PtrBuffer = Buffer;\r
6ad55b15 1639\r
1640 while (BlocksRemaining > 0) {\r
1641\r
1642 if (BlocksRemaining <= MaxBlock) {\r
f95bc048 1643 if (!ScsiDiskDevice->Cdb16Byte) {\r
a108933e 1644 SectorCount = (UINT16) BlocksRemaining;\r
1645 } else {\r
1646 SectorCount = (UINT32) BlocksRemaining;\r
1647 }\r
6ad55b15 1648 } else {\r
6ad55b15 1649 SectorCount = MaxBlock;\r
1650 }\r
1651\r
1652 ByteCount = SectorCount * BlockSize;\r
e72a3b3e 1653 Timeout = EFI_TIMER_PERIOD_SECONDS (2);\r
6ad55b15 1654\r
1655 MaxRetry = 2;\r
1656 for (Index = 0; Index < MaxRetry; Index++) {\r
f95bc048 1657 if (!ScsiDiskDevice->Cdb16Byte) {\r
1658 Status = ScsiDiskRead10 (\r
a108933e 1659 ScsiDiskDevice,\r
1660 &NeedRetry,\r
1661 &SenseData,\r
1662 &NumberOfSenseKeys,\r
1663 Timeout,\r
1664 PtrBuffer,\r
1665 &ByteCount,\r
f95bc048 1666 (UINT32) Lba,\r
a108933e 1667 SectorCount\r
1668 );\r
1669 } else {\r
f95bc048 1670 Status = ScsiDiskRead16 (\r
a108933e 1671 ScsiDiskDevice,\r
1672 &NeedRetry,\r
1673 &SenseData,\r
1674 &NumberOfSenseKeys,\r
1675 Timeout,\r
1676 PtrBuffer,\r
1677 &ByteCount,\r
f95bc048 1678 Lba,\r
a108933e 1679 SectorCount\r
1680 );\r
1681 }\r
6ad55b15 1682 if (!EFI_ERROR (Status)) {\r
1683 break;\r
1684 }\r
1685\r
1686 if (!NeedRetry) {\r
1687 return EFI_DEVICE_ERROR;\r
1688 }\r
1689\r
1690 }\r
1691\r
1692 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
1693 return EFI_DEVICE_ERROR;\r
1694 }\r
1695\r
1696 //\r
1697 // actual transferred sectors\r
1698 //\r
1699 SectorCount = ByteCount / BlockSize;\r
1700\r
a108933e 1701 Lba += SectorCount;\r
6ad55b15 1702 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
1703 BlocksRemaining -= SectorCount;\r
1704 }\r
1705\r
1706 return EFI_SUCCESS;\r
1707}\r
1708\r
9beb888e 1709/**\r
1710 Write sector to SCSI Disk.\r
6ad55b15 1711\r
d716651f 1712 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
9beb888e 1713 @param Buffer The buffer of data to be written into SCSI Disk\r
1714 @param Lba Logic block address\r
1715 @param NumberOfBlocks The number of blocks to read\r
6ad55b15 1716\r
9beb888e 1717 @retval EFI_DEVICE_ERROR Indicates a device error.\r
1718 @retval EFI_SUCCESS Operation is successful.\r
6ad55b15 1719\r
9beb888e 1720**/\r
1721EFI_STATUS\r
1722ScsiDiskWriteSectors (\r
1723 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1724 IN VOID *Buffer,\r
1725 IN EFI_LBA Lba,\r
1726 IN UINTN NumberOfBlocks\r
1727 )\r
6ad55b15 1728{\r
1729 UINTN BlocksRemaining;\r
6ad55b15 1730 UINT8 *PtrBuffer;\r
1731 UINT32 BlockSize;\r
1732 UINT32 ByteCount;\r
1733 UINT32 MaxBlock;\r
1734 UINT32 SectorCount;\r
1735 UINT64 Timeout;\r
1736 EFI_STATUS Status;\r
1737 UINT8 Index;\r
1738 UINT8 MaxRetry;\r
1739 BOOLEAN NeedRetry;\r
1740 EFI_SCSI_SENSE_DATA *SenseData;\r
1741 UINTN NumberOfSenseKeys;\r
1742\r
1743 SenseData = NULL;\r
1744 NumberOfSenseKeys = 0;\r
1745\r
1746 Status = EFI_SUCCESS;\r
1747\r
1748 BlocksRemaining = NumberOfBlocks;\r
1749 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
a108933e 1750\r
6ad55b15 1751 //\r
a108933e 1752 // limit the data bytes that can be transferred by one Read(10) or Read(16) Command\r
6ad55b15 1753 //\r
f95bc048 1754 if (!ScsiDiskDevice->Cdb16Byte) {\r
5bf5fb30 1755 MaxBlock = 0xFFFF;\r
a108933e 1756 } else {\r
5bf5fb30 1757 MaxBlock = 0xFFFFFFFF;\r
a108933e 1758 }\r
6ad55b15 1759\r
1760 PtrBuffer = Buffer;\r
6ad55b15 1761\r
1762 while (BlocksRemaining > 0) {\r
1763\r
1764 if (BlocksRemaining <= MaxBlock) {\r
f95bc048 1765 if (!ScsiDiskDevice->Cdb16Byte) {\r
a108933e 1766 SectorCount = (UINT16) BlocksRemaining;\r
1767 } else {\r
1768 SectorCount = (UINT32) BlocksRemaining;\r
1769 }\r
6ad55b15 1770 } else {\r
6ad55b15 1771 SectorCount = MaxBlock;\r
1772 }\r
1773\r
1774 ByteCount = SectorCount * BlockSize;\r
e72a3b3e 1775 Timeout = EFI_TIMER_PERIOD_SECONDS (2);\r
6ad55b15 1776 MaxRetry = 2;\r
1777 for (Index = 0; Index < MaxRetry; Index++) {\r
f95bc048 1778 if (!ScsiDiskDevice->Cdb16Byte) {\r
1779 Status = ScsiDiskWrite10 (\r
a108933e 1780 ScsiDiskDevice,\r
1781 &NeedRetry,\r
1782 &SenseData,\r
1783 &NumberOfSenseKeys,\r
1784 Timeout,\r
1785 PtrBuffer,\r
1786 &ByteCount,\r
f95bc048 1787 (UINT32) Lba,\r
a108933e 1788 SectorCount\r
f95bc048 1789 );\r
a108933e 1790 } else {\r
f95bc048 1791 Status = ScsiDiskWrite16 (\r
a108933e 1792 ScsiDiskDevice,\r
1793 &NeedRetry,\r
1794 &SenseData,\r
1795 &NumberOfSenseKeys,\r
1796 Timeout,\r
1797 PtrBuffer,\r
1798 &ByteCount,\r
f95bc048 1799 Lba,\r
a108933e 1800 SectorCount\r
f95bc048 1801 ); \r
a108933e 1802 }\r
6ad55b15 1803 if (!EFI_ERROR (Status)) {\r
1804 break;\r
1805 }\r
1806\r
1807 if (!NeedRetry) {\r
1808 return EFI_DEVICE_ERROR;\r
1809 }\r
1810 }\r
1811\r
1812 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
1813 return EFI_DEVICE_ERROR;\r
1814 }\r
1815 //\r
1816 // actual transferred sectors\r
1817 //\r
1818 SectorCount = ByteCount / BlockSize;\r
1819\r
a108933e 1820 Lba += SectorCount;\r
6ad55b15 1821 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
1822 BlocksRemaining -= SectorCount;\r
1823 }\r
1824\r
1825 return EFI_SUCCESS;\r
1826}\r
1827\r
9beb888e 1828\r
1829/**\r
a108933e 1830 Submit Read(10) command.\r
9beb888e 1831\r
1832 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
1833 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
1834 @param SenseDataArray NOT used yet in this function\r
1835 @param NumberOfSenseKeys The number of sense key\r
1836 @param Timeout The time to complete the command\r
1837 @param DataBuffer The buffer to fill with the read out data\r
1838 @param DataLength The length of buffer\r
1839 @param StartLba The start logic block address\r
1840 @param SectorSize The size of sector\r
1841\r
1842 @return EFI_STATUS is returned by calling ScsiRead10Command().\r
1843**/\r
6ad55b15 1844EFI_STATUS\r
1845ScsiDiskRead10 (\r
9beb888e 1846 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1847 OUT BOOLEAN *NeedRetry,\r
1848 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
1849 OUT UINTN *NumberOfSenseKeys,\r
1850 IN UINT64 Timeout,\r
1851 OUT UINT8 *DataBuffer,\r
1852 IN OUT UINT32 *DataLength,\r
1853 IN UINT32 StartLba,\r
1854 IN UINT32 SectorSize\r
6ad55b15 1855 )\r
6ad55b15 1856{\r
1857 UINT8 SenseDataLength;\r
1858 EFI_STATUS Status;\r
1859 UINT8 HostAdapterStatus;\r
1860 UINT8 TargetStatus;\r
1861\r
1862 *NeedRetry = FALSE;\r
1863 *NumberOfSenseKeys = 0;\r
1864 SenseDataLength = 0;\r
d35be2a4 1865 Status = ScsiRead10Command (\r
6ad55b15 1866 ScsiDiskDevice->ScsiIo,\r
1867 Timeout,\r
1868 NULL,\r
1869 &SenseDataLength,\r
1870 &HostAdapterStatus,\r
1871 &TargetStatus,\r
1872 DataBuffer,\r
1873 DataLength,\r
1874 StartLba,\r
1875 SectorSize\r
1876 );\r
1877 return Status;\r
1878}\r
1879\r
6ad55b15 1880\r
9beb888e 1881/**\r
a108933e 1882 Submit Write(10) Command.\r
6ad55b15 1883\r
9beb888e 1884 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
1885 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
1886 @param SenseDataArray NOT used yet in this function\r
1887 @param NumberOfSenseKeys The number of sense key\r
1888 @param Timeout The time to complete the command\r
1889 @param DataBuffer The buffer to fill with the read out data\r
1890 @param DataLength The length of buffer\r
1891 @param StartLba The start logic block address\r
1892 @param SectorSize The size of sector\r
6ad55b15 1893\r
9beb888e 1894 @return EFI_STATUS is returned by calling ScsiWrite10Command().\r
6ad55b15 1895\r
9beb888e 1896**/\r
1897EFI_STATUS\r
1898ScsiDiskWrite10 (\r
1899 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1900 OUT BOOLEAN *NeedRetry,\r
1901 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
1902 OUT UINTN *NumberOfSenseKeys,\r
1903 IN UINT64 Timeout,\r
1904 IN UINT8 *DataBuffer,\r
1905 IN OUT UINT32 *DataLength,\r
1906 IN UINT32 StartLba,\r
1907 IN UINT32 SectorSize\r
1908 )\r
6ad55b15 1909{\r
1910 EFI_STATUS Status;\r
1911 UINT8 SenseDataLength;\r
1912 UINT8 HostAdapterStatus;\r
1913 UINT8 TargetStatus;\r
1914\r
1915 *NeedRetry = FALSE;\r
1916 *NumberOfSenseKeys = 0;\r
1917 SenseDataLength = 0;\r
d35be2a4 1918 Status = ScsiWrite10Command (\r
6ad55b15 1919 ScsiDiskDevice->ScsiIo,\r
1920 Timeout,\r
1921 NULL,\r
1922 &SenseDataLength,\r
1923 &HostAdapterStatus,\r
1924 &TargetStatus,\r
1925 DataBuffer,\r
1926 DataLength,\r
1927 StartLba,\r
1928 SectorSize\r
1929 );\r
1930 return Status;\r
1931}\r
1932\r
9beb888e 1933\r
a108933e 1934/**\r
1935 Submit Read(16) command.\r
1936\r
1937 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
1938 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
1939 @param SenseDataArray NOT used yet in this function\r
1940 @param NumberOfSenseKeys The number of sense key\r
1941 @param Timeout The time to complete the command\r
1942 @param DataBuffer The buffer to fill with the read out data\r
1943 @param DataLength The length of buffer\r
1944 @param StartLba The start logic block address\r
1945 @param SectorSize The size of sector\r
1946\r
1947 @return EFI_STATUS is returned by calling ScsiRead10Command().\r
1948**/\r
1949EFI_STATUS\r
1950ScsiDiskRead16 (\r
1951 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
1952 OUT BOOLEAN *NeedRetry,\r
1953 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
1954 OUT UINTN *NumberOfSenseKeys,\r
1955 IN UINT64 Timeout,\r
1956 OUT UINT8 *DataBuffer,\r
1957 IN OUT UINT32 *DataLength,\r
1958 IN UINT64 StartLba,\r
1959 IN UINT32 SectorSize\r
1960 )\r
1961{\r
1962 UINT8 SenseDataLength;\r
1963 EFI_STATUS Status;\r
1964 UINT8 HostAdapterStatus;\r
1965 UINT8 TargetStatus;\r
1966\r
1967 *NeedRetry = FALSE;\r
1968 *NumberOfSenseKeys = 0;\r
1969 SenseDataLength = 0;\r
1970 Status = ScsiRead16Command (\r
1971 ScsiDiskDevice->ScsiIo,\r
1972 Timeout,\r
1973 NULL,\r
1974 &SenseDataLength,\r
1975 &HostAdapterStatus,\r
1976 &TargetStatus,\r
1977 DataBuffer,\r
1978 DataLength,\r
1979 StartLba,\r
1980 SectorSize\r
1981 );\r
1982 return Status;\r
1983}\r
1984\r
1985\r
1986/**\r
1987 Submit Write(16) Command.\r
1988\r
1989 @param ScsiDiskDevice The pointer of ScsiDiskDevice\r
1990 @param NeedRetry The pointer of flag indicates if needs retry if error happens\r
1991 @param SenseDataArray NOT used yet in this function\r
1992 @param NumberOfSenseKeys The number of sense key\r
1993 @param Timeout The time to complete the command\r
1994 @param DataBuffer The buffer to fill with the read out data\r
1995 @param DataLength The length of buffer\r
1996 @param StartLba The start logic block address\r
1997 @param SectorSize The size of sector\r
1998\r
1999 @return EFI_STATUS is returned by calling ScsiWrite10Command().\r
2000\r
2001**/\r
2002EFI_STATUS\r
2003ScsiDiskWrite16 (\r
2004 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
2005 OUT BOOLEAN *NeedRetry,\r
2006 OUT EFI_SCSI_SENSE_DATA **SenseDataArray, OPTIONAL\r
2007 OUT UINTN *NumberOfSenseKeys,\r
2008 IN UINT64 Timeout,\r
2009 IN UINT8 *DataBuffer,\r
2010 IN OUT UINT32 *DataLength,\r
2011 IN UINT64 StartLba,\r
2012 IN UINT32 SectorSize\r
2013 )\r
2014{\r
2015 EFI_STATUS Status;\r
2016 UINT8 SenseDataLength;\r
2017 UINT8 HostAdapterStatus;\r
2018 UINT8 TargetStatus;\r
2019\r
2020 *NeedRetry = FALSE;\r
2021 *NumberOfSenseKeys = 0;\r
2022 SenseDataLength = 0;\r
2023 Status = ScsiWrite16Command (\r
2024 ScsiDiskDevice->ScsiIo,\r
2025 Timeout,\r
2026 NULL,\r
2027 &SenseDataLength,\r
2028 &HostAdapterStatus,\r
2029 &TargetStatus,\r
2030 DataBuffer,\r
2031 DataLength,\r
2032 StartLba,\r
2033 SectorSize\r
2034 );\r
2035 return Status;\r
2036}\r
2037\r
2038\r
9beb888e 2039/**\r
2040 Check sense key to find if media presents.\r
2041\r
2042 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2043 @param SenseCounts The number of sense key\r
2044\r
2045 @retval TRUE NOT any media\r
2046 @retval FALSE Media presents\r
2047**/\r
6ad55b15 2048BOOLEAN\r
2049ScsiDiskIsNoMedia (\r
2050 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2051 IN UINTN SenseCounts\r
2052 )\r
6ad55b15 2053{\r
2054 EFI_SCSI_SENSE_DATA *SensePtr;\r
2055 UINTN Index;\r
2056 BOOLEAN IsNoMedia;\r
2057\r
2058 IsNoMedia = FALSE;\r
2059 SensePtr = SenseData;\r
2060\r
2061 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 2062 //\r
2063 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),\r
2064 // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
2065 //\r
2066 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
2067 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {\r
2068 IsNoMedia = TRUE;\r
2069 }\r
6ad55b15 2070 SensePtr++;\r
2071 }\r
2072\r
2073 return IsNoMedia;\r
2074}\r
2075\r
9beb888e 2076\r
2077/**\r
2078 Parse sense key.\r
2079\r
2080 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2081 @param SenseCounts The number of sense key\r
2082\r
2083 @retval TRUE Error\r
2084 @retval FALSE NOT error\r
2085\r
2086**/\r
6ad55b15 2087BOOLEAN\r
2088ScsiDiskIsMediaError (\r
2089 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2090 IN UINTN SenseCounts\r
2091 )\r
6ad55b15 2092{\r
2093 EFI_SCSI_SENSE_DATA *SensePtr;\r
2094 UINTN Index;\r
2095 BOOLEAN IsError;\r
2096\r
2097 IsError = FALSE;\r
2098 SensePtr = SenseData;\r
2099\r
2100 for (Index = 0; Index < SenseCounts; Index++) {\r
2101\r
2102 switch (SensePtr->Sense_Key) {\r
2103\r
2104 case EFI_SCSI_SK_MEDIUM_ERROR:\r
2105 //\r
2106 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)\r
2107 //\r
2108 switch (SensePtr->Addnl_Sense_Code) {\r
2109\r
2110 //\r
2111 // fall through\r
2112 //\r
2113 case EFI_SCSI_ASC_MEDIA_ERR1:\r
2114\r
2115 //\r
2116 // fall through\r
2117 //\r
2118 case EFI_SCSI_ASC_MEDIA_ERR2:\r
2119\r
2120 //\r
2121 // fall through\r
2122 //\r
2123 case EFI_SCSI_ASC_MEDIA_ERR3:\r
2124 case EFI_SCSI_ASC_MEDIA_ERR4:\r
2125 IsError = TRUE;\r
2126 break;\r
2127\r
2128 default:\r
2129 break;\r
2130 }\r
2131\r
2132 break;\r
2133\r
2134 case EFI_SCSI_SK_NOT_READY:\r
2135 //\r
2136 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
2137 //\r
2138 switch (SensePtr->Addnl_Sense_Code) {\r
2139 //\r
2140 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)\r
2141 //\r
2142 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:\r
2143 IsError = TRUE;\r
2144 break;\r
2145\r
2146 default:\r
2147 break;\r
2148 }\r
2149 break;\r
2150\r
2151 default:\r
2152 break;\r
2153 }\r
2154\r
2155 SensePtr++;\r
2156 }\r
2157\r
2158 return IsError;\r
2159}\r
2160\r
9beb888e 2161\r
2162/**\r
2163 Check sense key to find if hardware error happens.\r
2164\r
2165 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2166 @param SenseCounts The number of sense key\r
2167\r
2168 @retval TRUE Hardware error exits.\r
2169 @retval FALSE NO error.\r
2170\r
2171**/\r
6ad55b15 2172BOOLEAN\r
2173ScsiDiskIsHardwareError (\r
2174 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2175 IN UINTN SenseCounts\r
2176 )\r
6ad55b15 2177{\r
2178 EFI_SCSI_SENSE_DATA *SensePtr;\r
2179 UINTN Index;\r
2180 BOOLEAN IsError;\r
2181\r
2182 IsError = FALSE;\r
2183 SensePtr = SenseData;\r
2184\r
2185 for (Index = 0; Index < SenseCounts; Index++) {\r
2186 \r
2187 //\r
2188 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)\r
2189 //\r
2190 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {\r
2191 IsError = TRUE;\r
2192 }\r
2193\r
2194 SensePtr++;\r
2195 }\r
2196\r
2197 return IsError;\r
2198}\r
2199\r
9beb888e 2200\r
2201/**\r
2202 Check sense key to find if media has changed.\r
2203\r
2204 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2205 @param SenseCounts The number of sense key\r
2206\r
2207 @retval TRUE Media is changed.\r
d716651f 2208 @retval FALSE Media is NOT changed.\r
9beb888e 2209**/\r
6ad55b15 2210BOOLEAN\r
2211ScsiDiskIsMediaChange (\r
2212 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2213 IN UINTN SenseCounts\r
2214 )\r
6ad55b15 2215{\r
2216 EFI_SCSI_SENSE_DATA *SensePtr;\r
2217 UINTN Index;\r
2218 BOOLEAN IsMediaChanged;\r
2219\r
2220 IsMediaChanged = FALSE;\r
2221 SensePtr = SenseData;\r
2222\r
2223 for (Index = 0; Index < SenseCounts; Index++) {\r
2224 //\r
2225 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),\r
2226 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)\r
2227 //\r
2228 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
2229 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {\r
2230 IsMediaChanged = TRUE;\r
2231 }\r
2232\r
2233 SensePtr++;\r
2234 }\r
2235\r
2236 return IsMediaChanged;\r
2237}\r
2238\r
9beb888e 2239/**\r
2240 Check sense key to find if reset happens.\r
2241\r
2242 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2243 @param SenseCounts The number of sense key\r
2244\r
2245 @retval TRUE It is reset before.\r
2246 @retval FALSE It is NOT reset before.\r
2247\r
2248**/\r
6ad55b15 2249BOOLEAN\r
2250ScsiDiskIsResetBefore (\r
2251 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2252 IN UINTN SenseCounts\r
2253 )\r
6ad55b15 2254{\r
2255 EFI_SCSI_SENSE_DATA *SensePtr;\r
2256 UINTN Index;\r
2257 BOOLEAN IsResetBefore;\r
2258\r
2259 IsResetBefore = FALSE;\r
2260 SensePtr = SenseData;\r
2261\r
2262 for (Index = 0; Index < SenseCounts; Index++) {\r
2263 \r
2264 //\r
2265 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)\r
2266 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)\r
2267 //\r
2268 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
2269 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {\r
2270 IsResetBefore = TRUE;\r
2271 }\r
2272\r
2273 SensePtr++;\r
2274 }\r
2275\r
2276 return IsResetBefore;\r
2277}\r
2278\r
9beb888e 2279/**\r
2280 Check sense key to find if the drive is ready.\r
2281\r
2282 @param SenseData The pointer of EFI_SCSI_SENSE_DATA\r
2283 @param SenseCounts The number of sense key\r
2284 @param RetryLater The flag means if need a retry \r
2285\r
2286 @retval TRUE Drive is ready.\r
2287 @retval FALSE Drive is NOT ready.\r
2288\r
2289**/\r
6ad55b15 2290BOOLEAN\r
2291ScsiDiskIsDriveReady (\r
2292 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2293 IN UINTN SenseCounts,\r
2294 OUT BOOLEAN *RetryLater\r
2295 )\r
6ad55b15 2296{\r
2297 EFI_SCSI_SENSE_DATA *SensePtr;\r
2298 UINTN Index;\r
2299 BOOLEAN IsReady;\r
2300\r
2301 IsReady = TRUE;\r
2302 *RetryLater = FALSE;\r
2303 SensePtr = SenseData;\r
2304\r
2305 for (Index = 0; Index < SenseCounts; Index++) {\r
2306\r
2307 switch (SensePtr->Sense_Key) {\r
2308\r
2309 case EFI_SCSI_SK_NOT_READY:\r
2310 //\r
2311 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
2312 //\r
2313 switch (SensePtr->Addnl_Sense_Code) {\r
2314 case EFI_SCSI_ASC_NOT_READY:\r
2315 //\r
2316 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)\r
2317 //\r
2318 switch (SensePtr->Addnl_Sense_Code_Qualifier) {\r
2319 case EFI_SCSI_ASCQ_IN_PROGRESS:\r
2320 //\r
2321 // Additional Sense Code Qualifier is\r
2322 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)\r
2323 //\r
2324 IsReady = FALSE;\r
2325 *RetryLater = TRUE;\r
2326 break;\r
2327\r
2328 default:\r
2329 IsReady = FALSE;\r
2330 *RetryLater = FALSE;\r
2331 break;\r
2332 }\r
2333 break;\r
2334\r
2335 default:\r
2336 break;\r
2337 }\r
2338 break;\r
2339\r
2340 default:\r
2341 break;\r
2342 }\r
2343\r
2344 SensePtr++;\r
2345 }\r
2346\r
2347 return IsReady;\r
2348}\r
2349\r
9beb888e 2350/**\r
2351 Check sense key to find if it has sense key.\r
2352\r
2353 @param SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2354 @param SenseCounts - The number of sense key\r
2355\r
2356 @retval TRUE It has sense key.\r
2357 @retval FALSE It has NOT any sense key.\r
2358\r
2359**/\r
6ad55b15 2360BOOLEAN\r
2361ScsiDiskHaveSenseKey (\r
2362 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2363 IN UINTN SenseCounts\r
2364 )\r
6ad55b15 2365{\r
2366 EFI_SCSI_SENSE_DATA *SensePtr;\r
2367 UINTN Index;\r
2368 BOOLEAN HaveSenseKey;\r
2369\r
2370 if (SenseCounts == 0) {\r
2371 HaveSenseKey = FALSE;\r
2372 } else {\r
2373 HaveSenseKey = TRUE;\r
2374 }\r
2375\r
2376 SensePtr = SenseData;\r
2377\r
2378 for (Index = 0; Index < SenseCounts; Index++) {\r
2379 \r
2380 //\r
2381 // Sense Key is SK_NO_SENSE (0x0)\r
2382 //\r
2383 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&\r
2384 (Index == 0)) {\r
2385 HaveSenseKey = FALSE;\r
2386 }\r
2387\r
2388 SensePtr++;\r
2389 }\r
2390\r
2391 return HaveSenseKey;\r
2392}\r
2393\r
9beb888e 2394/**\r
2395 Release resource about disk device.\r
2396\r
2397 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2398\r
2399**/\r
6ad55b15 2400VOID\r
2401ReleaseScsiDiskDeviceResources (\r
2402 IN SCSI_DISK_DEV *ScsiDiskDevice\r
2403 )\r
6ad55b15 2404{\r
2405 if (ScsiDiskDevice == NULL) {\r
2406 return ;\r
2407 }\r
2408\r
2409 if (ScsiDiskDevice->SenseData != NULL) {\r
9b38ff34 2410 FreePool (ScsiDiskDevice->SenseData);\r
6ad55b15 2411 ScsiDiskDevice->SenseData = NULL;\r
2412 }\r
2413\r
2414 if (ScsiDiskDevice->ControllerNameTable != NULL) {\r
2415 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);\r
2416 ScsiDiskDevice->ControllerNameTable = NULL;\r
2417 }\r
2418\r
9b38ff34 2419 FreePool (ScsiDiskDevice);\r
6ad55b15 2420\r
2421 ScsiDiskDevice = NULL;\r
2422}\r
d14faa52 2423\r
2424/**\r
2425 Determine if Block Io should be produced.\r
2426 \r
2427\r
d716651f 2428 @param ChildHandle Child Handle to retrieve Parent information.\r
d14faa52 2429 \r
2430 @retval TRUE Should produce Block Io.\r
2431 @retval FALSE Should not produce Block Io.\r
2432\r
2433**/ \r
2434BOOLEAN\r
2435DetermineInstallBlockIo (\r
2436 IN EFI_HANDLE ChildHandle\r
2437 ) \r
2438{\r
2439 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;\r
2440 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;\r
2441\r
2442 //\r
2443 // Firstly, check if ExtScsiPassThru Protocol parent handle exists. If existence,\r
2444 // check its attribute, logic or physical.\r
2445 //\r
2446 ExtScsiPassThru = (EFI_EXT_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiExtScsiPassThruProtocolGuid, ChildHandle);\r
2447 if (ExtScsiPassThru != NULL) {\r
2448 if ((ExtScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
2449 return TRUE;\r
2450 }\r
2451 }\r
2452\r
2453 //\r
2454 // Secondly, check if ScsiPassThru Protocol parent handle exists. If existence,\r
2455 // check its attribute, logic or physical.\r
2456 //\r
2457 ScsiPassThru = (EFI_SCSI_PASS_THRU_PROTOCOL *)GetParentProtocol (&gEfiScsiPassThruProtocolGuid, ChildHandle);\r
2458 if (ScsiPassThru != NULL) {\r
2459 if ((ScsiPassThru->Mode->Attributes & EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL) != 0) {\r
2460 return TRUE;\r
2461 }\r
2462 }\r
2463 \r
2464 return FALSE;\r
2465}\r
2466\r
2467/**\r
2468 Search protocol database and check to see if the protocol\r
2469 specified by ProtocolGuid is present on a ControllerHandle and opened by\r
2470 ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
2471 If the ControllerHandle is found, then the protocol specified by ProtocolGuid\r
2472 will be opened on it. \r
2473 \r
2474\r
2475 @param ProtocolGuid ProtocolGuid pointer.\r
2476 @param ChildHandle Child Handle to retrieve Parent information.\r
2477 \r
2478**/ \r
2479VOID *\r
2480EFIAPI\r
2481GetParentProtocol (\r
2482 IN EFI_GUID *ProtocolGuid,\r
2483 IN EFI_HANDLE ChildHandle\r
2484 ) \r
2485{\r
2486 UINTN Index;\r
2487 UINTN HandleCount;\r
2488 VOID *Interface; \r
2489 EFI_STATUS Status;\r
2490 EFI_HANDLE *HandleBuffer;\r
2491\r
2492 //\r
2493 // Retrieve the list of all handles from the handle database\r
2494 //\r
2495 Status = gBS->LocateHandleBuffer (\r
2496 ByProtocol,\r
2497 ProtocolGuid,\r
2498 NULL,\r
2499 &HandleCount,\r
2500 &HandleBuffer\r
2501 );\r
2502\r
2503 if (EFI_ERROR (Status)) {\r
2504 return NULL;\r
2505 }\r
2506\r
2507 //\r
2508 // Iterate to find who is parent handle that is opened with ProtocolGuid by ChildHandle \r
2509 //\r
2510 for (Index = 0; Index < HandleCount; Index++) {\r
2511 Status = EfiTestChildHandle (HandleBuffer[Index], ChildHandle, ProtocolGuid);\r
2512 if (!EFI_ERROR (Status)) {\r
2513 Status = gBS->HandleProtocol (HandleBuffer[Index], ProtocolGuid, (VOID **)&Interface);\r
2514 if (!EFI_ERROR (Status)) {\r
2515 gBS->FreePool (HandleBuffer);\r
2516 return Interface;\r
2517 }\r
2518 }\r
2519 }\r
2520\r
2521 gBS->FreePool (HandleBuffer);\r
2522 return NULL;\r
2523} \r
2524\r
d716651f 2525/**\r
2526 Provides inquiry information for the controller type.\r
2527 \r
2528 This function is used by the IDE bus driver to get inquiry data. Data format\r
2529 of Identify data is defined by the Interface GUID.\r
2530\r
4140a663 2531 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
2532 @param[in, out] InquiryData Pointer to a buffer for the inquiry data.\r
2533 @param[in, out] InquiryDataSize Pointer to the value for the inquiry data size.\r
d716651f 2534\r
2535 @retval EFI_SUCCESS The command was accepted without any errors.\r
2536 @retval EFI_NOT_FOUND Device does not support this data class \r
2537 @retval EFI_DEVICE_ERROR Error reading InquiryData from device \r
2538 @retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough \r
2539\r
2540**/\r
2541EFI_STATUS\r
2542EFIAPI\r
2543ScsiDiskInfoInquiry (\r
2544 IN EFI_DISK_INFO_PROTOCOL *This,\r
2545 IN OUT VOID *InquiryData,\r
2546 IN OUT UINT32 *InquiryDataSize\r
2547 )\r
2548{\r
2549 EFI_STATUS Status;\r
2550 SCSI_DISK_DEV *ScsiDiskDevice;\r
2551\r
2552 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
2553\r
2554 Status = EFI_BUFFER_TOO_SMALL;\r
2555 if (*InquiryDataSize >= sizeof (ScsiDiskDevice->InquiryData)) {\r
2556 Status = EFI_SUCCESS;\r
2557 CopyMem (InquiryData, &ScsiDiskDevice->InquiryData, sizeof (ScsiDiskDevice->InquiryData));\r
2558 }\r
2559 *InquiryDataSize = sizeof (ScsiDiskDevice->InquiryData);\r
2560 return Status;\r
2561}\r
2562\r
2563\r
2564/**\r
2565 Provides identify information for the controller type.\r
2566\r
2567 This function is used by the IDE bus driver to get identify data. Data format\r
2568 of Identify data is defined by the Interface GUID.\r
2569\r
4140a663 2570 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL \r
d716651f 2571 instance.\r
4140a663 2572 @param[in, out] IdentifyData Pointer to a buffer for the identify data.\r
2573 @param[in, out] IdentifyDataSize Pointer to the value for the identify data\r
d716651f 2574 size.\r
2575\r
2576 @retval EFI_SUCCESS The command was accepted without any errors.\r
2577 @retval EFI_NOT_FOUND Device does not support this data class \r
2578 @retval EFI_DEVICE_ERROR Error reading IdentifyData from device \r
2579 @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough \r
2580\r
2581**/\r
2582EFI_STATUS\r
2583EFIAPI\r
2584ScsiDiskInfoIdentify (\r
2585 IN EFI_DISK_INFO_PROTOCOL *This,\r
2586 IN OUT VOID *IdentifyData,\r
2587 IN OUT UINT32 *IdentifyDataSize\r
2588 )\r
2589{\r
2590 EFI_STATUS Status;\r
2591 SCSI_DISK_DEV *ScsiDiskDevice;\r
2592\r
2593 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
2594 //\r
2595 // Physical SCSI bus does not support this data class. \r
2596 //\r
2597 return EFI_NOT_FOUND;\r
2598 }\r
2599\r
2600 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
2601\r
2602 Status = EFI_BUFFER_TOO_SMALL;\r
2603 if (*IdentifyDataSize >= sizeof (ScsiDiskDevice->IdentifyData)) {\r
2604 Status = EFI_SUCCESS;\r
2605 CopyMem (IdentifyData, &ScsiDiskDevice->IdentifyData, sizeof (ScsiDiskDevice->IdentifyData));\r
2606 }\r
2607 *IdentifyDataSize = sizeof (ScsiDiskDevice->IdentifyData);\r
2608 return Status;\r
2609}\r
2610\r
2611/**\r
2612 Provides sense data information for the controller type.\r
2613 \r
2614 This function is used by the IDE bus driver to get sense data. \r
2615 Data format of Sense data is defined by the Interface GUID.\r
2616\r
4140a663 2617 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance.\r
2618 @param[in, out] SenseData Pointer to the SenseData.\r
2619 @param[in, out] SenseDataSize Size of SenseData in bytes.\r
2620 @param[out] SenseDataNumber Pointer to the value for the sense data size.\r
d716651f 2621\r
2622 @retval EFI_SUCCESS The command was accepted without any errors.\r
2623 @retval EFI_NOT_FOUND Device does not support this data class.\r
2624 @retval EFI_DEVICE_ERROR Error reading SenseData from device.\r
2625 @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough.\r
2626\r
2627**/\r
2628EFI_STATUS\r
2629EFIAPI\r
2630ScsiDiskInfoSenseData (\r
2631 IN EFI_DISK_INFO_PROTOCOL *This,\r
2632 IN OUT VOID *SenseData,\r
2633 IN OUT UINT32 *SenseDataSize,\r
2634 OUT UINT8 *SenseDataNumber\r
2635 )\r
2636{\r
2637 return EFI_NOT_FOUND;\r
2638}\r
2639\r
2640\r
2641/**\r
2642 This function is used by the IDE bus driver to get controller information.\r
2643\r
2644 @param[in] This Pointer to the EFI_DISK_INFO_PROTOCOL instance. \r
2645 @param[out] IdeChannel Pointer to the Ide Channel number. Primary or secondary.\r
2646 @param[out] IdeDevice Pointer to the Ide Device number. Master or slave.\r
2647\r
2648 @retval EFI_SUCCESS IdeChannel and IdeDevice are valid.\r
2649 @retval EFI_UNSUPPORTED This is not an IDE device.\r
2650\r
2651**/\r
2652EFI_STATUS\r
2653EFIAPI\r
2654ScsiDiskInfoWhichIde (\r
2655 IN EFI_DISK_INFO_PROTOCOL *This,\r
2656 OUT UINT32 *IdeChannel,\r
2657 OUT UINT32 *IdeDevice\r
2658 )\r
2659{\r
2660 SCSI_DISK_DEV *ScsiDiskDevice;\r
2661\r
2662 if (CompareGuid (&This->Interface, &gEfiDiskInfoScsiInterfaceGuid)) {\r
2663 //\r
2664 // This is not an IDE physical device.\r
2665 //\r
2666 return EFI_UNSUPPORTED;\r
2667 }\r
2668\r
2669 ScsiDiskDevice = SCSI_DISK_DEV_FROM_DISKINFO (This);\r
2670 *IdeChannel = ScsiDiskDevice->Channel;\r
2671 *IdeDevice = ScsiDiskDevice->Device;\r
2672\r
2673 return EFI_SUCCESS;\r
2674}\r
2675\r
2676\r
2677/**\r
2678 Issues ATA IDENTIFY DEVICE command to identify ATAPI device.\r
2679\r
2680 This function tries to fill 512-byte ATAPI_IDENTIFY_DATA for ATAPI device to\r
2681 implement Identify() interface for DiskInfo protocol. The ATA command is sent\r
2682 via SCSI Request Packet.\r
2683\r
2684 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV\r
2685 \r
2686 @retval EFI_SUCCESS The ATAPI device identify data were retrieved successfully.\r
2687 @retval others Some error occurred during the identification that ATAPI device.\r
2688\r
2689**/ \r
2690EFI_STATUS\r
2691AtapiIdentifyDevice (\r
2692 IN OUT SCSI_DISK_DEV *ScsiDiskDevice\r
2693 )\r
2694{\r
2695 EFI_SCSI_IO_SCSI_REQUEST_PACKET CommandPacket;\r
2696 UINT8 Cdb[6];\r
2697\r
2698 //\r
2699 // Initialize SCSI REQUEST_PACKET and 6-byte Cdb\r
2700 //\r
2701 ZeroMem (&CommandPacket, sizeof (CommandPacket));\r
2702 ZeroMem (Cdb, sizeof (Cdb));\r
2703\r
2704 Cdb[0] = ATA_CMD_IDENTIFY_DEVICE;\r
2705 CommandPacket.Timeout = EFI_TIMER_PERIOD_SECONDS (1);\r
2706 CommandPacket.Cdb = Cdb;\r
c9325700 2707 CommandPacket.CdbLength = (UINT8) sizeof (Cdb);\r
d716651f 2708 CommandPacket.InDataBuffer = &ScsiDiskDevice->IdentifyData;\r
2709 CommandPacket.InTransferLength = sizeof (ScsiDiskDevice->IdentifyData);\r
2710\r
2711 return ScsiDiskDevice->ScsiIo->ExecuteScsiCommand (ScsiDiskDevice->ScsiIo, &CommandPacket, NULL);\r
2712}\r
2713\r
2714\r
2715/**\r
2716 Initialize the installation of DiskInfo protocol.\r
2717\r
2718 This function prepares for the installation of DiskInfo protocol on the child handle.\r
2719 By default, it installs DiskInfo protocol with SCSI interface GUID. If it further\r
2720 detects that the physical device is an ATAPI/AHCI device, it then updates interface GUID\r
2721 to be IDE/AHCI interface GUID.\r
2722\r
2723 @param ScsiDiskDevice The pointer of SCSI_DISK_DEV.\r
2724 @param ChildHandle Child handle to install DiskInfo protocol.\r
2725 \r
2726**/ \r
2727VOID\r
2728InitializeInstallDiskInfo (\r
2729 IN SCSI_DISK_DEV *ScsiDiskDevice,\r
2730 IN EFI_HANDLE ChildHandle\r
2731 )\r
2732{\r
2733 EFI_STATUS Status;\r
2734 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
2735 EFI_DEVICE_PATH_PROTOCOL *ChildDevicePathNode;\r
2736 ATAPI_DEVICE_PATH *AtapiDevicePath;\r
2737 SATA_DEVICE_PATH *SataDevicePath;\r
2738 UINTN IdentifyRetry;\r
2739\r
2740 Status = gBS->HandleProtocol (ChildHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePathNode);\r
2741 //\r
2742 // Device Path protocol must be installed on the device handle. \r
2743 //\r
2744 ASSERT_EFI_ERROR (Status);\r
2745 //\r
2746 // Copy the DiskInfo protocol template.\r
2747 //\r
2748 CopyMem (&ScsiDiskDevice->DiskInfo, &gScsiDiskInfoProtocolTemplate, sizeof (gScsiDiskInfoProtocolTemplate));\r
2749\r
2750 while (!IsDevicePathEnd (DevicePathNode)) {\r
2751 ChildDevicePathNode = NextDevicePathNode (DevicePathNode);\r
2752 if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&\r
2753 (DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&\r
2754 (DevicePathType (ChildDevicePathNode) == MESSAGING_DEVICE_PATH) &&\r
2755 ((DevicePathSubType (ChildDevicePathNode) == MSG_ATAPI_DP) ||\r
2756 (DevicePathSubType (ChildDevicePathNode) == MSG_SATA_DP))) {\r
2757\r
2758 IdentifyRetry = 3;\r
2759 do {\r
2760 //\r
2761 // Issue ATA Identify Device Command via SCSI command, which is required to publish DiskInfo protocol\r
2762 // with IDE/AHCI interface GUID.\r
2763 //\r
2764 Status = AtapiIdentifyDevice (ScsiDiskDevice);\r
2765 if (!EFI_ERROR (Status)) {\r
2766 if (DevicePathSubType(ChildDevicePathNode) == MSG_ATAPI_DP) {\r
2767 //\r
2768 // We find the valid ATAPI device path\r
2769 //\r
2770 AtapiDevicePath = (ATAPI_DEVICE_PATH *) ChildDevicePathNode;\r
2771 ScsiDiskDevice->Channel = AtapiDevicePath->PrimarySecondary;\r
2772 ScsiDiskDevice->Device = AtapiDevicePath->SlaveMaster;\r
2773 //\r
2774 // Update the DiskInfo.Interface to IDE interface GUID for the physical ATAPI device. \r
2775 //\r
2776 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid);\r
2777 } else {\r
2778 //\r
2779 // We find the valid SATA device path\r
2780 //\r
2781 SataDevicePath = (SATA_DEVICE_PATH *) ChildDevicePathNode;\r
2782 ScsiDiskDevice->Channel = SataDevicePath->HBAPortNumber;\r
2783 ScsiDiskDevice->Device = SataDevicePath->PortMultiplierPortNumber;\r
2784 //\r
2785 // Update the DiskInfo.Interface to AHCI interface GUID for the physical AHCI device. \r
2786 //\r
2787 CopyGuid (&ScsiDiskDevice->DiskInfo.Interface, &gEfiDiskInfoAhciInterfaceGuid);\r
2788 }\r
2789 return;\r
2790 }\r
2791 } while (--IdentifyRetry > 0);\r
2792 }\r
2793 DevicePathNode = ChildDevicePathNode;\r
2794 }\r
2795\r
2796 return;\r
2797}\r