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