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