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