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