]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Scsi/ScsiDiskDxe/ScsiDisk.c
Remove IfrLibConstruct, because it do nothing.
[mirror_edk2.git] / MdeModulePkg / Bus / Scsi / ScsiDiskDxe / ScsiDisk.c
CommitLineData
6ad55b15 1/*++\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 ScsiDisk.c\r
15\r
16Abstract:\r
17\r
18--*/\r
ed7748fe 19\r
6ad55b15 20#include <PiDxe.h>\r
21\r
ed7748fe 22\r
6ad55b15 23#include <Protocol/ScsiIo.h>\r
24#include <Protocol/ComponentName.h>\r
25#include <Protocol/BlockIo.h>\r
26#include <Protocol/DriverBinding.h>\r
f36d6e66 27#include <Protocol/ScsiPassThruExt.h>\r
ed7748fe 28\r
6ad55b15 29#include <Library/DebugLib.h>\r
30#include <Library/UefiDriverEntryPoint.h>\r
31#include <Library/UefiLib.h>\r
32#include <Library/BaseMemoryLib.h>\r
33#include <Library/ScsiLib.h>\r
34#include <Library/UefiBootServicesTableLib.h>\r
35\r
36#include "ScsiDisk.h"\r
37\r
38EFI_DRIVER_BINDING_PROTOCOL gScsiDiskDriverBinding = {\r
39 ScsiDiskDriverBindingSupported,\r
40 ScsiDiskDriverBindingStart,\r
41 ScsiDiskDriverBindingStop,\r
42 0xa,\r
43 NULL,\r
44 NULL\r
45};\r
46\r
47/**\r
48 The user Entry Point for module ScsiDisk. The user code starts with this function.\r
49\r
50 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
51 @param[in] SystemTable A pointer to the EFI System Table.\r
52 \r
53 @retval EFI_SUCCESS The entry point is executed successfully.\r
54 @retval other Some error occurs when executing this entry point.\r
55\r
56**/\r
57EFI_STATUS\r
58EFIAPI\r
59InitializeScsiDisk(\r
60 IN EFI_HANDLE ImageHandle,\r
61 IN EFI_SYSTEM_TABLE *SystemTable\r
62 )\r
63{\r
64 EFI_STATUS Status;\r
65\r
66 //\r
67 // Install driver model protocol(s).\r
68 //\r
70da5bc2 69 Status = EfiLibInstallDriverBindingComponentName2 (\r
6ad55b15 70 ImageHandle,\r
71 SystemTable,\r
72 &gScsiDiskDriverBinding,\r
73 ImageHandle,\r
74 &gScsiDiskComponentName,\r
70da5bc2 75 &gScsiDiskComponentName2\r
6ad55b15 76 );\r
77 ASSERT_EFI_ERROR (Status);\r
78\r
79\r
80 return Status;\r
81}\r
82\r
83EFI_STATUS\r
84EFIAPI\r
85ScsiDiskDriverBindingSupported (\r
86 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
87 IN EFI_HANDLE Controller,\r
88 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
89 )\r
90/*++\r
f36d6e66 91\r
92Routine Description:\r
93\r
94 Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
95 that has ScsiIoProtocol installed will be supported.\r
96\r
97Arguments:\r
98\r
99 This - Protocol instance pointer.\r
100 Controller - Handle of device to test\r
101 RemainingDevicePath - Not used\r
102\r
103Returns:\r
104\r
105 EFI_SUCCESS - This driver supports this device.\r
106 EFI_UNSUPPORTED - This driver does not support this device.\r
6ad55b15 107 \r
6ad55b15 108 \r
109--*/\r
6ad55b15 110{\r
111 EFI_STATUS Status;\r
112 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
113 UINT8 DeviceType;\r
114\r
115 Status = gBS->OpenProtocol (\r
116 Controller,\r
117 &gEfiScsiIoProtocolGuid,\r
118 (VOID **) &ScsiIo,\r
119 This->DriverBindingHandle,\r
120 Controller,\r
121 EFI_OPEN_PROTOCOL_BY_DRIVER\r
122 );\r
123 if (EFI_ERROR (Status)) {\r
124 return Status;\r
125 }\r
126\r
127 Status = ScsiIo->GetDeviceType (ScsiIo, &DeviceType);\r
128 if (!EFI_ERROR (Status)) {\r
129 if ((DeviceType == EFI_SCSI_TYPE_DISK) || (DeviceType == EFI_SCSI_TYPE_CDROM)) {\r
130 Status = EFI_SUCCESS;\r
131 } else {\r
132 Status = EFI_UNSUPPORTED;\r
133 }\r
134 }\r
135\r
136 gBS->CloseProtocol (\r
f36d6e66 137 Controller,\r
138 &gEfiScsiIoProtocolGuid,\r
139 This->DriverBindingHandle,\r
140 Controller\r
141 );\r
6ad55b15 142 return Status;\r
143}\r
144\r
145EFI_STATUS\r
146EFIAPI\r
147ScsiDiskDriverBindingStart (\r
148 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
149 IN EFI_HANDLE Controller,\r
150 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
151 )\r
152/*++\r
f36d6e66 153\r
154Routine Description:\r
155\r
156 Start SCSI Disk Driver, and attach BlockIoProtocol to it.\r
6ad55b15 157 \r
f36d6e66 158Arguments:\r
159\r
160 This - Protocol instance pointer.\r
161 Controller - Handle of device to test\r
162 RemainingDevicePath - Not used\r
163\r
164Returns:\r
165\r
166 EFI_SUCCESS - This driver supports this device.\r
167 EFI_UNSUPPORTED - This driver does not support this device.\r
6ad55b15 168 \r
6ad55b15 169 \r
170--*/\r
6ad55b15 171{\r
172 EFI_STATUS Status;\r
173 EFI_SCSI_IO_PROTOCOL *ScsiIo;\r
174 SCSI_DISK_DEV *ScsiDiskDevice;\r
175 BOOLEAN Temp;\r
176 UINT8 Index;\r
177 UINT8 MaxRetry;\r
178 BOOLEAN NeedRetry;\r
179\r
180 Status = gBS->AllocatePool (\r
181 EfiBootServicesData,\r
182 sizeof (SCSI_DISK_DEV),\r
183 (VOID **) &ScsiDiskDevice\r
184 );\r
185 if (EFI_ERROR (Status)) {\r
186 return Status;\r
187 }\r
188\r
189 ZeroMem (ScsiDiskDevice, sizeof (SCSI_DISK_DEV));\r
190\r
191 Status = gBS->OpenProtocol (\r
192 Controller,\r
193 &gEfiScsiIoProtocolGuid,\r
194 (VOID **) &ScsiIo,\r
195 This->DriverBindingHandle,\r
196 Controller,\r
197 EFI_OPEN_PROTOCOL_BY_DRIVER\r
198 );\r
199 if (EFI_ERROR (Status)) {\r
200 gBS->FreePool (ScsiDiskDevice);\r
201 return Status;\r
202 }\r
203\r
204 ScsiDiskDevice->Signature = SCSI_DISK_DEV_SIGNATURE;\r
205 ScsiDiskDevice->ScsiIo = ScsiIo;\r
206 ScsiDiskDevice->BlkIo.Media = &ScsiDiskDevice->BlkIoMedia;\r
207 ScsiDiskDevice->BlkIo.Reset = ScsiDiskReset;\r
208 ScsiDiskDevice->BlkIo.ReadBlocks = ScsiDiskReadBlocks;\r
209 ScsiDiskDevice->BlkIo.WriteBlocks = ScsiDiskWriteBlocks;\r
210 ScsiDiskDevice->BlkIo.FlushBlocks = ScsiDiskFlushBlocks;\r
211 ScsiDiskDevice->Handle = Controller;\r
212\r
213 ScsiIo->GetDeviceType (ScsiIo, &(ScsiDiskDevice->DeviceType));\r
214 switch (ScsiDiskDevice->DeviceType) {\r
215 case EFI_SCSI_TYPE_DISK:\r
216 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
217 break;\r
218\r
219 case EFI_SCSI_TYPE_CDROM:\r
220 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
221 break;\r
222 }\r
223 //\r
224 // The Sense Data Array's initial size is 6\r
225 //\r
226 ScsiDiskDevice->SenseDataNumber = 6;\r
227 Status = gBS->AllocatePool (\r
228 EfiBootServicesData,\r
229 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber,\r
230 (VOID **) &(ScsiDiskDevice->SenseData)\r
231 );\r
232 if (EFI_ERROR (Status)) {\r
233 gBS->CloseProtocol (\r
234 Controller,\r
235 &gEfiScsiIoProtocolGuid,\r
236 This->DriverBindingHandle,\r
237 Controller\r
238 );\r
239 gBS->FreePool (ScsiDiskDevice);\r
240 return Status;\r
241 }\r
242\r
243 ZeroMem (\r
244 ScsiDiskDevice->SenseData,\r
245 sizeof (EFI_SCSI_SENSE_DATA) * ScsiDiskDevice->SenseDataNumber\r
246 );\r
247\r
248 //\r
249 // Retrive device information\r
250 //\r
251 MaxRetry = 2;\r
252 for (Index = 0; Index < MaxRetry; Index++) {\r
253 Status = ScsiDiskInquiryDevice (ScsiDiskDevice, &NeedRetry);\r
254 if (!EFI_ERROR (Status)) {\r
255 break;\r
256 }\r
257\r
258 if (!NeedRetry) {\r
259 gBS->FreePool (ScsiDiskDevice->SenseData);\r
260 gBS->CloseProtocol (\r
f36d6e66 261 Controller,\r
262 &gEfiScsiIoProtocolGuid,\r
263 This->DriverBindingHandle,\r
264 Controller\r
265 );\r
6ad55b15 266 gBS->FreePool (ScsiDiskDevice);\r
267 return EFI_DEVICE_ERROR;\r
268 }\r
269 }\r
270 //\r
271 // The second parameter "TRUE" means must\r
272 // retrieve media capacity\r
273 //\r
274 Status = ScsiDiskDetectMedia (ScsiDiskDevice, TRUE, &Temp);\r
275 if (!EFI_ERROR (Status)) {\r
276 Status = gBS->InstallMultipleProtocolInterfaces (\r
277 &Controller,\r
278 &gEfiBlockIoProtocolGuid,\r
279 &ScsiDiskDevice->BlkIo,\r
280 NULL\r
281 );\r
282 }\r
283\r
284 if (EFI_ERROR (Status)) {\r
285 gBS->FreePool (ScsiDiskDevice->SenseData);\r
286 gBS->CloseProtocol (\r
f36d6e66 287 Controller,\r
288 &gEfiScsiIoProtocolGuid,\r
289 This->DriverBindingHandle,\r
290 Controller\r
291 );\r
6ad55b15 292 gBS->FreePool (ScsiDiskDevice);\r
293 return Status;\r
294 }\r
295\r
296 ScsiDiskDevice->ControllerNameTable = NULL;\r
70da5bc2 297 AddUnicodeString2 (\r
6ad55b15 298 "eng",\r
299 gScsiDiskComponentName.SupportedLanguages,\r
300 &ScsiDiskDevice->ControllerNameTable,\r
70da5bc2 301 L"SCSI Disk Device",\r
302 TRUE\r
6ad55b15 303 );\r
70da5bc2 304 AddUnicodeString2 (\r
305 "en",\r
306 gScsiDiskComponentName2.SupportedLanguages,\r
307 &ScsiDiskDevice->ControllerNameTable,\r
308 L"SCSI Disk Device",\r
309 FALSE\r
310 );\r
311\r
6ad55b15 312\r
313 return EFI_SUCCESS;\r
314\r
315}\r
316\r
317EFI_STATUS\r
318EFIAPI\r
319ScsiDiskDriverBindingStop (\r
320 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
321 IN EFI_HANDLE Controller,\r
322 IN UINTN NumberOfChildren,\r
323 IN EFI_HANDLE *ChildHandleBuffer\r
324 )\r
325/*++\r
f36d6e66 326\r
327Routine Description:\r
328\r
329 Stop this driver on ControllerHandle. Support stoping any child handles\r
330 created by this driver.\r
331\r
332Arguments:\r
333\r
334 This - Protocol instance pointer.\r
335 Controller - Handle of device to stop driver on\r
336 NumberOfChildren - Number of Children in the ChildHandleBuffer\r
337 ChildHandleBuffer - List of handles for the children we need to stop.\r
338\r
339Returns:\r
340\r
341 EFI_SUCCESS\r
342 EFI_DEVICE_ERROR\r
343 others\r
6ad55b15 344 \r
345--*/\r
6ad55b15 346{\r
347 EFI_BLOCK_IO_PROTOCOL *BlkIo;\r
348 SCSI_DISK_DEV *ScsiDiskDevice;\r
349 EFI_STATUS Status;\r
350\r
351 Status = gBS->OpenProtocol (\r
352 Controller,\r
353 &gEfiBlockIoProtocolGuid,\r
354 (VOID **) &BlkIo,\r
355 This->DriverBindingHandle,\r
356 Controller,\r
357 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
358 );\r
359 if (EFI_ERROR (Status)) {\r
360 return Status;\r
361 }\r
362\r
363 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (BlkIo);\r
364 Status = gBS->UninstallProtocolInterface (\r
365 Controller,\r
366 &gEfiBlockIoProtocolGuid,\r
367 &ScsiDiskDevice->BlkIo\r
368 );\r
369 if (!EFI_ERROR (Status)) {\r
370 gBS->CloseProtocol (\r
f36d6e66 371 Controller,\r
372 &gEfiScsiIoProtocolGuid,\r
373 This->DriverBindingHandle,\r
374 Controller\r
375 );\r
6ad55b15 376\r
377 ReleaseScsiDiskDeviceResources (ScsiDiskDevice);\r
378\r
379 return EFI_SUCCESS;\r
380 }\r
381 //\r
382 // errors met\r
383 //\r
384 return Status;\r
385}\r
386\r
6ad55b15 387\r
388EFI_STATUS\r
389EFIAPI\r
390ScsiDiskReset (\r
391 IN EFI_BLOCK_IO_PROTOCOL *This,\r
392 IN BOOLEAN ExtendedVerification\r
393 )\r
394/*++\r
395\r
396Routine Description:\r
397\r
f36d6e66 398 Reset SCSI Disk \r
6ad55b15 399\r
400Arguments:\r
401\r
f36d6e66 402 This - The pointer of EFI_BLOCK_IO_PROTOCOL\r
403 ExtendedVerification - The flag about if extend verificate\r
6ad55b15 404\r
405Returns:\r
406\r
f36d6e66 407 EFI_STATUS\r
6ad55b15 408\r
409--*/\r
410{\r
f36d6e66 411 EFI_TPL OldTpl;\r
6ad55b15 412 SCSI_DISK_DEV *ScsiDiskDevice;\r
413 EFI_STATUS Status;\r
6ad55b15 414\r
415 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
416\r
417 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
418\r
419 Status = ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
420\r
421 if (!ExtendedVerification) {\r
422 goto Done;\r
423 }\r
424\r
425 Status = ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
426\r
427Done:\r
428 gBS->RestoreTPL (OldTpl);\r
429 return Status;\r
430}\r
431\r
432EFI_STATUS\r
433EFIAPI\r
434ScsiDiskReadBlocks (\r
435 IN EFI_BLOCK_IO_PROTOCOL *This,\r
436 IN UINT32 MediaId,\r
437 IN EFI_LBA LBA,\r
438 IN UINTN BufferSize,\r
439 OUT VOID *Buffer\r
440 )\r
441/*++\r
442\r
443Routine Description:\r
444\r
f36d6e66 445 The function is to Read Block from SCSI Disk\r
6ad55b15 446\r
447Arguments:\r
448\r
f36d6e66 449 This - The pointer of EFI_BLOCK_IO_PROTOCOL\r
450 MediaId - The Id of Media detected\r
451 LBA - The logic block address\r
452 BufferSize - The size of Buffer\r
453 Buffer - The buffer to fill the read out data\r
6ad55b15 454\r
455Returns:\r
456\r
f36d6e66 457 EFI_INVALID_PARAMETER - Invalid parameter passed in.\r
458 EFI_SUCCESS - Successfully to read out block.\r
459 EFI_DEVICE_ERROR - Fail to detect media.\r
460 EFI_NO_MEDIA - Media is not present.\r
461 EFI_MEDIA_CHANGED - Media has changed.\r
462 EFI_BAD_BUFFER_SIZE - The buffer size is not multiple of BlockSize.\r
6ad55b15 463\r
464--*/\r
465{\r
466 SCSI_DISK_DEV *ScsiDiskDevice;\r
467 EFI_BLOCK_IO_MEDIA *Media;\r
468 EFI_STATUS Status;\r
469 UINTN BlockSize;\r
470 UINTN NumberOfBlocks;\r
471 BOOLEAN MediaChange;\r
472 EFI_TPL OldTpl;\r
473\r
474 MediaChange = FALSE;\r
475 if (!Buffer) {\r
476 return EFI_INVALID_PARAMETER;\r
477 }\r
478\r
479 if (BufferSize == 0) {\r
480 return EFI_SUCCESS;\r
481 }\r
482\r
483 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
484\r
485 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
486\r
487 if (!IsDeviceFixed (ScsiDiskDevice)) {\r
488\r
489 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
490 if (EFI_ERROR (Status)) {\r
491 Status = EFI_DEVICE_ERROR;\r
492 goto Done;\r
493 }\r
494\r
495 if (MediaChange) {\r
496 gBS->ReinstallProtocolInterface (\r
497 ScsiDiskDevice->Handle,\r
498 &gEfiBlockIoProtocolGuid,\r
499 &ScsiDiskDevice->BlkIo,\r
500 &ScsiDiskDevice->BlkIo\r
501 );\r
502 }\r
503 }\r
504 //\r
505 // Get the intrinsic block size\r
506 //\r
507 Media = ScsiDiskDevice->BlkIo.Media;\r
508 BlockSize = Media->BlockSize;\r
509\r
510 NumberOfBlocks = BufferSize / BlockSize;\r
511\r
512 if (!(Media->MediaPresent)) {\r
513 Status = EFI_NO_MEDIA;\r
514 goto Done;\r
515 }\r
516\r
517 if (MediaId != Media->MediaId) {\r
518 Status = EFI_MEDIA_CHANGED;\r
519 goto Done;\r
520 }\r
521\r
522 if (BufferSize % BlockSize != 0) {\r
523 Status = EFI_BAD_BUFFER_SIZE;\r
524 goto Done;\r
525 }\r
526\r
527 if (LBA > Media->LastBlock) {\r
528 Status = EFI_INVALID_PARAMETER;\r
529 goto Done;\r
530 }\r
531\r
532 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
533 Status = EFI_INVALID_PARAMETER;\r
534 goto Done;\r
535 }\r
536\r
537 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
538 Status = EFI_INVALID_PARAMETER;\r
539 goto Done;\r
540 }\r
f36d6e66 541\r
6ad55b15 542 //\r
f36d6e66 543 // If all the parameters are valid, then perform read sectors command\r
6ad55b15 544 // to transfer data from device to host.\r
545 //\r
546 Status = ScsiDiskReadSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks);\r
547\r
548Done:\r
549 gBS->RestoreTPL (OldTpl);\r
550 return Status;\r
551}\r
552\r
553EFI_STATUS\r
554EFIAPI\r
555ScsiDiskWriteBlocks (\r
556 IN EFI_BLOCK_IO_PROTOCOL *This,\r
557 IN UINT32 MediaId,\r
558 IN EFI_LBA LBA,\r
559 IN UINTN BufferSize,\r
560 IN VOID *Buffer\r
561 )\r
562/*++\r
563\r
564Routine Description:\r
565\r
f36d6e66 566 The function is to Write Block to SCSI Disk\r
6ad55b15 567\r
568Arguments:\r
569\r
f36d6e66 570 This - The pointer of EFI_BLOCK_IO_PROTOCOL\r
571 MediaId - The Id of Media detected\r
572 LBA - The logic block address\r
573 BufferSize - The size of Buffer\r
574 Buffer - The buffer to fill the read out data\r
6ad55b15 575\r
576Returns:\r
577\r
f36d6e66 578 EFI_INVALID_PARAMETER - Invalid parameter passed in.\r
579 EFI_SUCCESS - Successfully to read out block.\r
580 EFI_DEVICE_ERROR - Fail to detect media.\r
581 EFI_NO_MEDIA - Media is not present.\r
582 EFI_MEDIA_CHANGED - Media has changed.\r
583 EFI_BAD_BUFFER_SIZE - The buffer size is not multiple of BlockSize.\r
6ad55b15 584\r
585--*/\r
586{\r
587 SCSI_DISK_DEV *ScsiDiskDevice;\r
588 EFI_BLOCK_IO_MEDIA *Media;\r
589 EFI_STATUS Status;\r
590 UINTN BlockSize;\r
591 UINTN NumberOfBlocks;\r
592 BOOLEAN MediaChange;\r
593 EFI_TPL OldTpl;\r
594\r
595 MediaChange = FALSE;\r
596 if (!Buffer) {\r
597 return EFI_INVALID_PARAMETER;\r
598 }\r
599\r
600 if (BufferSize == 0) {\r
601 return EFI_SUCCESS;\r
602 }\r
603\r
604 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
605\r
606 ScsiDiskDevice = SCSI_DISK_DEV_FROM_THIS (This);\r
607\r
608 if (!IsDeviceFixed (ScsiDiskDevice)) {\r
609\r
610 Status = ScsiDiskDetectMedia (ScsiDiskDevice, FALSE, &MediaChange);\r
611 if (EFI_ERROR (Status)) {\r
612 Status = EFI_DEVICE_ERROR;\r
613 goto Done;\r
614 }\r
615\r
616 if (MediaChange) {\r
617 gBS->ReinstallProtocolInterface (\r
618 ScsiDiskDevice->Handle,\r
619 &gEfiBlockIoProtocolGuid,\r
620 &ScsiDiskDevice->BlkIo,\r
621 &ScsiDiskDevice->BlkIo\r
622 );\r
623 }\r
624 }\r
625 //\r
626 // Get the intrinsic block size\r
627 //\r
628 Media = ScsiDiskDevice->BlkIo.Media;\r
629 BlockSize = Media->BlockSize;\r
630\r
631 NumberOfBlocks = BufferSize / BlockSize;\r
632\r
633 if (!(Media->MediaPresent)) {\r
634 Status = EFI_NO_MEDIA;\r
635 goto Done;\r
636 }\r
637\r
638 if (MediaId != Media->MediaId) {\r
639 Status = EFI_MEDIA_CHANGED;\r
640 goto Done;\r
641 }\r
642\r
643 if (BufferSize % BlockSize != 0) {\r
644 Status = EFI_BAD_BUFFER_SIZE;\r
645 goto Done;\r
646 }\r
647\r
648 if (LBA > Media->LastBlock) {\r
649 Status = EFI_INVALID_PARAMETER;\r
650 goto Done;\r
651 }\r
652\r
653 if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {\r
654 Status = EFI_INVALID_PARAMETER;\r
655 goto Done;\r
656 }\r
657\r
658 if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {\r
659 Status = EFI_INVALID_PARAMETER;\r
660 goto Done;\r
661 }\r
662 //\r
663 // if all the parameters are valid, then perform read sectors command\r
664 // to transfer data from device to host.\r
665 //\r
666 Status = ScsiDiskWriteSectors (ScsiDiskDevice, Buffer, LBA, NumberOfBlocks);\r
667\r
668Done:\r
669 gBS->RestoreTPL (OldTpl);\r
6ad55b15 670 return Status;\r
671}\r
672\r
673EFI_STATUS\r
674EFIAPI\r
675ScsiDiskFlushBlocks (\r
676 IN EFI_BLOCK_IO_PROTOCOL *This\r
677 )\r
678/*++\r
679\r
680Routine Description:\r
681\r
f36d6e66 682 Flush Block to Disk\r
6ad55b15 683\r
684Arguments:\r
685\r
f36d6e66 686 This - The pointer of EFI_BLOCK_IO_PROTOCOL\r
6ad55b15 687\r
688Returns:\r
689\r
f36d6e66 690 EFI_SUCCESS \r
6ad55b15 691\r
692--*/\r
693{\r
694 //\r
695 // return directly\r
696 //\r
697 return EFI_SUCCESS;\r
698}\r
699\r
700EFI_STATUS\r
701ScsiDiskDetectMedia (\r
702 SCSI_DISK_DEV *ScsiDiskDevice,\r
703 BOOLEAN MustReadCapacity,\r
704 BOOLEAN *MediaChange\r
705 )\r
706/*++\r
707\r
708Routine Description:\r
709\r
f36d6e66 710 Dectect Device and read out capacity ,if error occurs, parse the sense key.\r
6ad55b15 711\r
712Arguments:\r
713\r
f36d6e66 714 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
715 MustReadCapacity - The flag about reading device capacity\r
716 MediaChange - The pointer of flag indicates if media has changed \r
6ad55b15 717\r
718Returns:\r
719\r
f36d6e66 720 EFI_DEVICE_ERROR - Indicates that error occurs\r
721 EFI_SUCCESS - Successfully to detect media\r
6ad55b15 722\r
723--*/\r
724{\r
725 EFI_STATUS Status;\r
726 EFI_STATUS ReadCapacityStatus;\r
727 EFI_SCSI_SENSE_DATA *SenseData;\r
728 UINTN NumberOfSenseKeys;\r
729 BOOLEAN NeedRetry;\r
730 BOOLEAN NeedReadCapacity;\r
731 UINT8 Index;\r
732 UINT8 MaxRetry;\r
733 EFI_BLOCK_IO_MEDIA OldMedia;\r
734 UINTN Action;\r
735\r
736 Status = EFI_SUCCESS;\r
737 ReadCapacityStatus = EFI_SUCCESS;\r
738 SenseData = NULL;\r
739 NumberOfSenseKeys = 0;\r
740 NeedReadCapacity = FALSE;\r
741 CopyMem (&OldMedia, ScsiDiskDevice->BlkIo.Media, sizeof (OldMedia));\r
6ad55b15 742 *MediaChange = FALSE;\r
6ad55b15 743 MaxRetry = 3;\r
f36d6e66 744\r
6ad55b15 745 for (Index = 0; Index < MaxRetry; Index++) {\r
746 Status = ScsiDiskTestUnitReady (\r
747 ScsiDiskDevice,\r
748 &NeedRetry,\r
749 &SenseData,\r
750 &NumberOfSenseKeys\r
751 );\r
752 if (!EFI_ERROR (Status)) {\r
753 break;\r
754 }\r
755\r
756 if (!NeedRetry) {\r
757 return Status;\r
758 }\r
759 }\r
760\r
761 if ((Index == MaxRetry) && EFI_ERROR (Status)) {\r
762 return EFI_DEVICE_ERROR;\r
763 }\r
764\r
765 Status = DetectMediaParsingSenseKeys (\r
766 ScsiDiskDevice,\r
767 SenseData,\r
768 NumberOfSenseKeys,\r
769 &Action\r
770 );\r
771 if (EFI_ERROR (Status)) {\r
772 return Status;\r
773 }\r
774 //\r
775 // ACTION_NO_ACTION: need not read capacity\r
776 // other action code: need read capacity\r
777 //\r
778 if (Action == ACTION_NO_ACTION) {\r
779 NeedReadCapacity = FALSE;\r
780 } else {\r
781 NeedReadCapacity = TRUE;\r
782 }\r
f36d6e66 783\r
6ad55b15 784 //\r
785 // either NeedReadCapacity is TRUE, or MustReadCapacity is TRUE,\r
786 // retrieve capacity via Read Capacity command\r
787 //\r
788 if (NeedReadCapacity || MustReadCapacity) {\r
6ad55b15 789 //\r
790 // retrieve media information\r
791 //\r
792 MaxRetry = 3;\r
793 for (Index = 0; Index < MaxRetry; Index++) {\r
794\r
795 ReadCapacityStatus = ScsiDiskReadCapacity (\r
796 ScsiDiskDevice,\r
797 &NeedRetry,\r
798 &SenseData,\r
799 &NumberOfSenseKeys\r
800 );\r
801 if (EFI_ERROR (ReadCapacityStatus) && !NeedRetry) {\r
802 return EFI_DEVICE_ERROR;\r
803 }\r
804 //\r
805 // analyze sense key to action\r
806 //\r
807 Status = DetectMediaParsingSenseKeys (\r
808 ScsiDiskDevice,\r
809 SenseData,\r
810 NumberOfSenseKeys,\r
811 &Action\r
812 );\r
813 //\r
814 // if Status is error, it may indicate crisis error,\r
815 // so return without retry.\r
816 //\r
817 if (EFI_ERROR (Status)) {\r
818 return Status;\r
819 }\r
820\r
821 switch (Action) {\r
822 case ACTION_NO_ACTION:\r
823 //\r
824 // no retry\r
825 //\r
826 Index = MaxRetry;\r
827 break;\r
828\r
829 case ACTION_RETRY_COMMAND_LATER:\r
830 //\r
831 // retry the ReadCapacity later and continuously, until the condition\r
832 // no longer emerges.\r
833 // stall time is 100000us, or say 0.1 second.\r
834 //\r
835 gBS->Stall (100000);\r
836 Index = 0;\r
837 break;\r
838\r
839 default:\r
840 //\r
841 // other cases, just retry the command\r
842 //\r
843 break;\r
844 }\r
845 }\r
846\r
847 if ((Index == MaxRetry) && EFI_ERROR (ReadCapacityStatus)) {\r
848 return EFI_DEVICE_ERROR;\r
849 }\r
850 }\r
851\r
852 if (ScsiDiskDevice->BlkIo.Media->MediaId != OldMedia.MediaId) {\r
853 //\r
854 // Media change information got from the device\r
855 //\r
856 *MediaChange = TRUE;\r
857 }\r
858\r
859 if (ScsiDiskDevice->BlkIo.Media->ReadOnly != OldMedia.ReadOnly) {\r
860 *MediaChange = TRUE;\r
861 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
862 }\r
863\r
864 if (ScsiDiskDevice->BlkIo.Media->BlockSize != OldMedia.BlockSize) {\r
865 *MediaChange = TRUE;\r
866 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
867 }\r
868\r
869 if (ScsiDiskDevice->BlkIo.Media->LastBlock != OldMedia.LastBlock) {\r
870 *MediaChange = TRUE;\r
871 ScsiDiskDevice->BlkIo.Media->MediaId += 1;\r
872 }\r
873\r
874 if (ScsiDiskDevice->BlkIo.Media->MediaPresent != OldMedia.MediaPresent) {\r
875 if (ScsiDiskDevice->BlkIo.Media->MediaPresent) {\r
876 //\r
877 // when change from no media to media present, reset the MediaId to 1.\r
878 //\r
879 ScsiDiskDevice->BlkIo.Media->MediaId = 1;\r
880 } else {\r
881 //\r
882 // when no media, reset the MediaId to zero.\r
883 //\r
884 ScsiDiskDevice->BlkIo.Media->MediaId = 0;\r
885 }\r
886\r
887 *MediaChange = TRUE;\r
888 }\r
889\r
890 return EFI_SUCCESS;\r
891}\r
892\r
893EFI_STATUS\r
894ScsiDiskInquiryDevice (\r
895 SCSI_DISK_DEV *ScsiDiskDevice,\r
896 BOOLEAN *NeedRetry\r
897 )\r
898/*++\r
899\r
900Routine Description:\r
901\r
f36d6e66 902 Send out Inquiry command to Device\r
6ad55b15 903\r
904Arguments:\r
905\r
f36d6e66 906 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
907 NeedRetry - Indicates if needs try again when error happens\r
6ad55b15 908\r
909Returns:\r
910\r
f36d6e66 911 EFI_DEVICE_ERROR - Indicates that error occurs\r
912 EFI_SUCCESS - Successfully to detect media\r
6ad55b15 913\r
914--*/\r
915{\r
916 UINT32 InquiryDataLength;\r
917 UINT8 SenseDataLength;\r
918 UINT8 HostAdapterStatus;\r
919 UINT8 TargetStatus;\r
920 EFI_SCSI_SENSE_DATA *SenseDataArray;\r
921 UINTN NumberOfSenseKeys;\r
922 EFI_STATUS Status;\r
923 UINT8 MaxRetry;\r
924 UINT8 Index;\r
925\r
926 InquiryDataLength = sizeof (EFI_SCSI_INQUIRY_DATA);\r
927 SenseDataLength = 0;\r
928\r
d35be2a4 929 Status = ScsiInquiryCommand (\r
6ad55b15 930 ScsiDiskDevice->ScsiIo,\r
931 EfiScsiStallSeconds (1),\r
932 NULL,\r
933 &SenseDataLength,\r
934 &HostAdapterStatus,\r
935 &TargetStatus,\r
936 (VOID *) &(ScsiDiskDevice->InquiryData),\r
937 &InquiryDataLength,\r
938 FALSE\r
939 );\r
6ad55b15 940 //\r
941 // no need to check HostAdapterStatus and TargetStatus\r
942 //\r
f36d6e66 943 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
944 ParseInquiryData (ScsiDiskDevice);\r
945 return EFI_SUCCESS;\r
946 \r
947 } else if (Status == EFI_NOT_READY) {\r
948 *NeedRetry = TRUE;\r
949 return EFI_DEVICE_ERROR;\r
950 \r
951 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
952 *NeedRetry = FALSE;\r
953 return EFI_DEVICE_ERROR;\r
954 }\r
955 //\r
956 // go ahead to check HostAdapterStatus and TargetStatus\r
957 // (EFI_TIMEOUT, EFI_DEVICE_ERROR)\r
958 //\r
959 \r
960 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
961 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
962 *NeedRetry = TRUE;\r
963 return EFI_DEVICE_ERROR;\r
964 } else if (Status == EFI_DEVICE_ERROR) {\r
965 //\r
966 // reset the scsi channel\r
967 //\r
6ad55b15 968 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
969 *NeedRetry = FALSE;\r
970 return EFI_DEVICE_ERROR;\r
971 }\r
972\r
973 Status = CheckTargetStatus (TargetStatus);\r
974 if (Status == EFI_NOT_READY) {\r
975 //\r
976 // reset the scsi device\r
977 //\r
978 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
979 *NeedRetry = TRUE;\r
980 return EFI_DEVICE_ERROR;\r
f36d6e66 981\r
6ad55b15 982 } else if (Status == EFI_DEVICE_ERROR) {\r
983 *NeedRetry = FALSE;\r
984 return EFI_DEVICE_ERROR;\r
985 }\r
986 \r
987 //\r
f36d6e66 988 // if goes here, meant SubmitInquiryCommand() failed.\r
6ad55b15 989 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
f36d6e66 990 // better retry SubmitInquiryCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 991 //\r
992 MaxRetry = 3;\r
993 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 994 Status = ScsiDiskRequestSenseKeys (\r
995 ScsiDiskDevice,\r
996 NeedRetry,\r
997 &SenseDataArray,\r
998 &NumberOfSenseKeys,\r
999 TRUE\r
1000 );\r
1001 if (!EFI_ERROR (Status)) {\r
1002 *NeedRetry = TRUE;\r
1003 return EFI_DEVICE_ERROR;\r
1004 }\r
1005\r
1006 if (!*NeedRetry) {\r
1007 return EFI_DEVICE_ERROR;\r
1008 }\r
1009 }\r
1010 //\r
1011 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1012 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1013 //\r
1014 *NeedRetry = FALSE;\r
1015 return EFI_DEVICE_ERROR;\r
1016}\r
1017\r
1018EFI_STATUS\r
1019ScsiDiskTestUnitReady (\r
1020 SCSI_DISK_DEV *ScsiDiskDevice,\r
1021 BOOLEAN *NeedRetry,\r
1022 EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1023 UINTN *NumberOfSenseKeys\r
1024 )\r
f36d6e66 1025 /*++\r
1026\r
1027Routine Description:\r
1028\r
1029 When Test Unit Ready command succeeds, retrieve Sense Keys via Request Sense;\r
6ad55b15 1030 When Test Unit Ready command encounters any error caused by host adapter or\r
1031 target, return error without retrieving Sense Keys.\r
f36d6e66 1032 \r
1033Arguments:\r
1034\r
1035 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
1036 NeedRetry - The pointer of flag indicates try again\r
1037 SenseDataArray - The pointer of an array of sense data\r
1038 NumberOfSenseKeys - The pointer of the number of sense data array\r
1039 \r
1040Returns:\r
1041\r
1042 EFI_DEVICE_ERROR - Indicates that error occurs\r
1043 EFI_SUCCESS - Successfully to test unit\r
1044\r
1045--*/\r
6ad55b15 1046{\r
1047 EFI_STATUS Status;\r
1048 UINT8 SenseDataLength;\r
1049 UINT8 HostAdapterStatus;\r
1050 UINT8 TargetStatus;\r
1051 UINT8 Index;\r
1052 UINT8 MaxRetry;\r
1053\r
1054 SenseDataLength = 0;\r
1055 *NumberOfSenseKeys = 0;\r
1056\r
1057 //\r
1058 // Parameter 3 and 4: do not require sense data, retrieve it when needed.\r
1059 //\r
d35be2a4 1060 Status = ScsiTestUnitReadyCommand (\r
6ad55b15 1061 ScsiDiskDevice->ScsiIo,\r
1062 EfiScsiStallSeconds (1),\r
1063 NULL,\r
1064 &SenseDataLength,\r
1065 &HostAdapterStatus,\r
1066 &TargetStatus\r
1067 );\r
f36d6e66 1068 //\r
1069 // no need to check HostAdapterStatus and TargetStatus\r
1070 //\r
6ad55b15 1071 if (Status == EFI_NOT_READY) {\r
6ad55b15 1072 *NeedRetry = TRUE;\r
1073 return EFI_DEVICE_ERROR;\r
f36d6e66 1074\r
6ad55b15 1075 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
6ad55b15 1076 *NeedRetry = FALSE;\r
1077 return EFI_DEVICE_ERROR;\r
1078 }\r
1079 //\r
f36d6e66 1080 // go ahead to check HostAdapterStatus and TargetStatus(in case of EFI_DEVICE_ERROR)\r
6ad55b15 1081 //\r
f36d6e66 1082\r
6ad55b15 1083 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
1084 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1085 *NeedRetry = TRUE;\r
1086 return EFI_DEVICE_ERROR;\r
f36d6e66 1087\r
6ad55b15 1088 } else if (Status == EFI_DEVICE_ERROR) {\r
1089 //\r
1090 // reset the scsi channel\r
1091 //\r
1092 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
1093 *NeedRetry = FALSE;\r
1094 return EFI_DEVICE_ERROR;\r
1095 }\r
1096\r
1097 Status = CheckTargetStatus (TargetStatus);\r
1098 if (Status == EFI_NOT_READY) {\r
1099 //\r
1100 // reset the scsi device\r
1101 //\r
1102 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1103 *NeedRetry = TRUE;\r
1104 return EFI_DEVICE_ERROR;\r
f36d6e66 1105\r
6ad55b15 1106 } else if (Status == EFI_DEVICE_ERROR) {\r
1107 *NeedRetry = FALSE;\r
1108 return EFI_DEVICE_ERROR;\r
1109 }\r
1110\r
1111 MaxRetry = 3;\r
1112 for (Index = 0; Index < MaxRetry; Index++) {\r
6ad55b15 1113 Status = ScsiDiskRequestSenseKeys (\r
1114 ScsiDiskDevice,\r
1115 NeedRetry,\r
1116 SenseDataArray,\r
1117 NumberOfSenseKeys,\r
1118 FALSE\r
1119 );\r
1120 if (!EFI_ERROR (Status)) {\r
1121 return EFI_SUCCESS;\r
1122 }\r
1123\r
1124 if (!*NeedRetry) {\r
1125 return EFI_DEVICE_ERROR;\r
1126 }\r
1127 }\r
1128 //\r
1129 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1130 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1131 //\r
1132 *NeedRetry = FALSE;\r
1133 return EFI_DEVICE_ERROR;\r
1134}\r
1135\r
1136EFI_STATUS\r
1137DetectMediaParsingSenseKeys (\r
1138 SCSI_DISK_DEV *ScsiDiskDevice,\r
1139 EFI_SCSI_SENSE_DATA *SenseData,\r
1140 UINTN NumberOfSenseKeys,\r
1141 UINTN *Action\r
1142 )\r
1143/*++\r
1144\r
1145Routine Description:\r
1146\r
f36d6e66 1147 Parsing Sense Keys which got from request sense command.\r
1148 \r
6ad55b15 1149Arguments:\r
1150\r
f36d6e66 1151 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
1152 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
1153 NumberOfSenseKeys - The number of sense key \r
1154 Action - The pointer of action which indicates what is need to do next\r
6ad55b15 1155\r
1156Returns:\r
1157\r
f36d6e66 1158 EFI_DEVICE_ERROR - Indicates that error occurs\r
1159 EFI_SUCCESS - Successfully to complete the parsing\r
6ad55b15 1160\r
1161--*/\r
1162{\r
1163 BOOLEAN RetryLater;\r
1164\r
1165 //\r
1166 // Default is to read capacity, unless..\r
1167 //\r
1168 *Action = ACTION_READ_CAPACITY;\r
1169\r
1170 if (NumberOfSenseKeys == 0) {\r
1171 *Action = ACTION_NO_ACTION;\r
1172 return EFI_SUCCESS;\r
1173 }\r
1174\r
1175 if (!ScsiDiskHaveSenseKey (SenseData, NumberOfSenseKeys)) {\r
1176 //\r
1177 // No Sense Key returned from last submitted command\r
1178 //\r
1179 *Action = ACTION_NO_ACTION;\r
1180 return EFI_SUCCESS;\r
1181 }\r
1182\r
1183 if (ScsiDiskIsNoMedia (SenseData, NumberOfSenseKeys)) {\r
1184 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
1185 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1186 *Action = ACTION_NO_ACTION;\r
1187 return EFI_SUCCESS;\r
1188 }\r
1189\r
1190 if (ScsiDiskIsMediaChange (SenseData, NumberOfSenseKeys)) {\r
1191 ScsiDiskDevice->BlkIo.Media->MediaId++;\r
1192 return EFI_SUCCESS;\r
1193 }\r
1194\r
1195 if (ScsiDiskIsMediaError (SenseData, NumberOfSenseKeys)) {\r
1196 ScsiDiskDevice->BlkIo.Media->MediaPresent = FALSE;\r
1197 ScsiDiskDevice->BlkIo.Media->LastBlock = 0;\r
1198 return EFI_DEVICE_ERROR;\r
1199 }\r
1200\r
1201 if (ScsiDiskIsHardwareError (SenseData, NumberOfSenseKeys)) {\r
1202 return EFI_DEVICE_ERROR;\r
1203 }\r
1204\r
1205 if (!ScsiDiskIsDriveReady (SenseData, NumberOfSenseKeys, &RetryLater)) {\r
1206 if (RetryLater) {\r
1207 *Action = ACTION_RETRY_COMMAND_LATER;\r
1208 return EFI_SUCCESS;\r
1209 }\r
1210\r
1211 return EFI_DEVICE_ERROR;\r
1212 }\r
1213\r
1214 return EFI_SUCCESS;\r
1215}\r
1216\r
1217EFI_STATUS\r
1218ScsiDiskReadCapacity (\r
1219 SCSI_DISK_DEV *ScsiDiskDevice,\r
1220 BOOLEAN *NeedRetry,\r
1221 EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1222 UINTN *NumberOfSenseKeys\r
1223 )\r
1224/*++\r
1225\r
1226Routine Description:\r
1227\r
f36d6e66 1228 Send read capacity command to device and get the device parameter\r
6ad55b15 1229\r
1230Arguments:\r
1231\r
f36d6e66 1232 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
1233 NeedRetry - The pointer of flag indicates if need a retry\r
1234 SenseDataArray - The pointer of an array of sense data\r
1235 NumberOfSenseKeys - The number of sense key\r
6ad55b15 1236\r
1237Returns:\r
1238\r
f36d6e66 1239 EFI_DEVICE_ERROR - Indicates that error occurs\r
1240 EFI_SUCCESS - Successfully to read capacity\r
6ad55b15 1241\r
1242--*/\r
1243{\r
1244 EFI_SCSI_DISK_CAPACITY_DATA CapacityData;\r
1245 UINT32 DataLength;\r
1246 UINT8 HostAdapterStatus;\r
1247 UINT8 TargetStatus;\r
1248 EFI_STATUS CommandStatus;\r
1249 EFI_STATUS Status;\r
1250 UINT8 Index;\r
1251 UINT8 MaxRetry;\r
1252 UINT8 SenseDataLength;\r
1253\r
1254 SenseDataLength = 0;\r
1255 ZeroMem (&CapacityData, sizeof (EFI_SCSI_DISK_CAPACITY_DATA));\r
1256 DataLength = sizeof (EFI_SCSI_DISK_CAPACITY_DATA);\r
1257\r
1258 *NumberOfSenseKeys = 0;\r
1259 *NeedRetry = FALSE;\r
1260 //\r
1261 // submit Read Capacity Command. in this call,not request sense data\r
1262 //\r
d35be2a4 1263 CommandStatus = ScsiReadCapacityCommand (\r
6ad55b15 1264 ScsiDiskDevice->ScsiIo,\r
1265 EfiScsiStallSeconds (1),\r
1266 NULL,\r
1267 &SenseDataLength,\r
1268 &HostAdapterStatus,\r
1269 &TargetStatus,\r
1270 (VOID *) &CapacityData,\r
1271 &DataLength,\r
1272 FALSE\r
1273 );\r
f36d6e66 1274 //\r
6ad55b15 1275 // no need to check HostAdapterStatus and TargetStatus\r
1276 //\r
f36d6e66 1277 if (CommandStatus == EFI_SUCCESS) {\r
1278 GetMediaInfo (ScsiDiskDevice, &CapacityData);\r
1279 return EFI_SUCCESS;\r
1280 \r
1281 } else if (CommandStatus == EFI_NOT_READY) {\r
1282 *NeedRetry = TRUE;\r
1283 return EFI_DEVICE_ERROR;\r
1284 \r
1285 } else if ((CommandStatus == EFI_INVALID_PARAMETER) || (CommandStatus == EFI_UNSUPPORTED)) {\r
1286 *NeedRetry = FALSE;\r
1287 return EFI_DEVICE_ERROR;\r
1288 }\r
1289 //\r
1290 // go ahead to check HostAdapterStatus and TargetStatus\r
1291 // (EFI_TIMEOUT, EFI_DEVICE_ERROR, EFI_WARN_BUFFER_TOO_SMALL)\r
1292 //\r
1293 \r
1294 Status = CheckHostAdapterStatus (HostAdapterStatus);\r
1295 if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1296 *NeedRetry = TRUE;\r
1297 return EFI_DEVICE_ERROR;\r
1298 \r
1299 } else if (Status == EFI_DEVICE_ERROR) {\r
6ad55b15 1300 //\r
1301 // reset the scsi channel\r
1302 //\r
1303 ScsiDiskDevice->ScsiIo->ResetBus (ScsiDiskDevice->ScsiIo);\r
1304 *NeedRetry = FALSE;\r
1305 return EFI_DEVICE_ERROR;\r
1306 }\r
1307\r
1308 Status = CheckTargetStatus (TargetStatus);\r
1309 if (Status == EFI_NOT_READY) {\r
1310 //\r
1311 // reset the scsi device\r
1312 //\r
1313 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1314 *NeedRetry = TRUE;\r
1315 return EFI_DEVICE_ERROR;\r
f36d6e66 1316\r
6ad55b15 1317 } else if (Status == EFI_DEVICE_ERROR) {\r
1318 *NeedRetry = FALSE;\r
1319 return EFI_DEVICE_ERROR;\r
1320 }\r
1321 \r
1322 //\r
f36d6e66 1323 // if goes here, meant SubmitReadCapacityCommand() failed.\r
6ad55b15 1324 // if ScsiDiskRequestSenseKeys() succeeds at last,\r
f36d6e66 1325 // better retry SubmitReadCapacityCommand(). (by setting *NeedRetry = TRUE)\r
6ad55b15 1326 //\r
1327 MaxRetry = 3;\r
1328 for (Index = 0; Index < MaxRetry; Index++) {\r
1329\r
1330 Status = ScsiDiskRequestSenseKeys (\r
1331 ScsiDiskDevice,\r
1332 NeedRetry,\r
1333 SenseDataArray,\r
1334 NumberOfSenseKeys,\r
1335 TRUE\r
1336 );\r
1337 if (!EFI_ERROR (Status)) {\r
1338 *NeedRetry = TRUE;\r
1339 return EFI_DEVICE_ERROR;\r
1340 }\r
1341\r
1342 if (!*NeedRetry) {\r
1343 return EFI_DEVICE_ERROR;\r
1344 }\r
1345 }\r
1346 //\r
1347 // ScsiDiskRequestSenseKeys() failed after several rounds of retry.\r
1348 // set *NeedRetry = FALSE to avoid the outside caller try again.\r
1349 //\r
1350 *NeedRetry = FALSE;\r
1351 return EFI_DEVICE_ERROR;\r
1352}\r
1353\r
1354EFI_STATUS\r
1355CheckHostAdapterStatus (\r
1356 UINT8 HostAdapterStatus\r
1357 )\r
1358/*++\r
1359\r
1360Routine Description:\r
1361\r
f36d6e66 1362 Check the HostAdapter status\r
1363 \r
6ad55b15 1364Arguments:\r
1365\r
f36d6e66 1366 HostAdapterStatus - Host Adapter status\r
6ad55b15 1367\r
1368Returns:\r
1369\r
f36d6e66 1370 EFI_SUCCESS \r
1371 EFI_TIMEOUT \r
1372 EFI_NOT_READY \r
1373 EFI_DEVICE_ERROR \r
6ad55b15 1374\r
1375--*/\r
1376{\r
1377 switch (HostAdapterStatus) {\r
f36d6e66 1378 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OK:\r
6ad55b15 1379 return EFI_SUCCESS;\r
1380\r
f36d6e66 1381 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_SELECTION_TIMEOUT:\r
1382 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT:\r
1383 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_TIMEOUT_COMMAND:\r
6ad55b15 1384 return EFI_TIMEOUT;\r
1385\r
f36d6e66 1386 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_MESSAGE_REJECT:\r
1387 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PARITY_ERROR:\r
1388 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_REQUEST_SENSE_FAILED:\r
1389 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_DATA_OVERRUN_UNDERRUN:\r
1390 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_RESET:\r
6ad55b15 1391 return EFI_NOT_READY;\r
1392\r
f36d6e66 1393 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_BUS_FREE:\r
1394 case EFI_EXT_SCSI_STATUS_HOST_ADAPTER_PHASE_ERROR:\r
6ad55b15 1395 return EFI_DEVICE_ERROR;\r
1396\r
1397 default:\r
1398 return EFI_SUCCESS;\r
1399 }\r
1400}\r
1401\r
1402EFI_STATUS\r
1403CheckTargetStatus (\r
1404 UINT8 TargetStatus\r
1405 )\r
1406/*++\r
1407\r
1408Routine Description:\r
1409\r
f36d6e66 1410 Check the target status\r
1411 \r
6ad55b15 1412Arguments:\r
1413\r
f36d6e66 1414 TargetStatus - Target status\r
6ad55b15 1415\r
1416Returns:\r
1417\r
f36d6e66 1418 EFI_NOT_READY \r
1419 EFI_DEVICE_ERROR \r
1420 EFI_SUCCESS\r
6ad55b15 1421\r
1422--*/\r
1423{\r
1424 switch (TargetStatus) {\r
f36d6e66 1425 case EFI_EXT_SCSI_STATUS_TARGET_GOOD:\r
1426 case EFI_EXT_SCSI_STATUS_TARGET_CHECK_CONDITION:\r
1427 case EFI_EXT_SCSI_STATUS_TARGET_CONDITION_MET:\r
6ad55b15 1428 return EFI_SUCCESS;\r
1429\r
f36d6e66 1430 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE:\r
1431 case EFI_EXT_SCSI_STATUS_TARGET_INTERMEDIATE_CONDITION_MET:\r
1432 case EFI_EXT_SCSI_STATUS_TARGET_BUSY:\r
1433 case EFI_EXT_SCSI_STATUS_TARGET_TASK_SET_FULL:\r
6ad55b15 1434 return EFI_NOT_READY;\r
1435\r
f36d6e66 1436 case EFI_EXT_SCSI_STATUS_TARGET_RESERVATION_CONFLICT:\r
6ad55b15 1437 return EFI_DEVICE_ERROR;\r
1438 break;\r
1439\r
1440 default:\r
1441 return EFI_SUCCESS;\r
1442 }\r
1443}\r
1444\r
1445EFI_STATUS\r
1446ScsiDiskRequestSenseKeys (\r
1447 SCSI_DISK_DEV *ScsiDiskDevice,\r
1448 BOOLEAN *NeedRetry,\r
1449 EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1450 UINTN *NumberOfSenseKeys,\r
1451 BOOLEAN AskResetIfError\r
1452 )\r
f36d6e66 1453/*++\r
1454\r
1455Routine Description:\r
1456\r
6ad55b15 1457 Retrieve all sense keys from the device.\r
1458 When encountering error during the process,\r
1459 if retrieve sense keys before error encounterred,\r
1460 return the sense keys with return status set to EFI_SUCCESS,\r
1461 and NeedRetry set to FALSE; otherwize, return the proper return\r
1462 status.\r
f36d6e66 1463\r
1464Arguments:\r
1465\r
1466 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
1467 NeedRetry - The pointer of flag indicates if need a retry\r
1468 SenseDataArray - The pointer of an array of sense data\r
1469 NumberOfSenseKeys - The number of sense key\r
1470 AskResetIfError - The flag indicates if need reset when error occurs\r
1471 \r
1472Returns:\r
1473\r
1474 EFI_DEVICE_ERROR - Indicates that error occurs\r
1475 EFI_SUCCESS - Successfully to request sense key\r
1476\r
1477--*/\r
6ad55b15 1478{\r
1479 EFI_SCSI_SENSE_DATA *PtrSenseData;\r
1480 UINT8 SenseDataLength;\r
1481 BOOLEAN SenseReq;\r
1482 EFI_STATUS Status;\r
1483 EFI_STATUS FallStatus;\r
1484 UINT8 HostAdapterStatus;\r
1485 UINT8 TargetStatus;\r
1486\r
1487 FallStatus = EFI_SUCCESS;\r
1488 SenseDataLength = sizeof (EFI_SCSI_SENSE_DATA);\r
1489\r
1490 ZeroMem (\r
1491 ScsiDiskDevice->SenseData,\r
1492 sizeof (EFI_SCSI_SENSE_DATA) * (ScsiDiskDevice->SenseDataNumber)\r
1493 );\r
1494\r
1495 *NumberOfSenseKeys = 0;\r
1496 *SenseDataArray = ScsiDiskDevice->SenseData;\r
1497 PtrSenseData = ScsiDiskDevice->SenseData;\r
1498\r
1499 for (SenseReq = TRUE; SenseReq;) {\r
d35be2a4 1500 Status = ScsiRequestSenseCommand (\r
6ad55b15 1501 ScsiDiskDevice->ScsiIo,\r
1502 EfiScsiStallSeconds (2),\r
1503 PtrSenseData,\r
1504 &SenseDataLength,\r
1505 &HostAdapterStatus,\r
1506 &TargetStatus\r
1507 );\r
f36d6e66 1508 if ((Status == EFI_SUCCESS) || (Status == EFI_WARN_BUFFER_TOO_SMALL)) {\r
1509 FallStatus = EFI_SUCCESS;\r
1510 \r
1511 } else if ((Status == EFI_TIMEOUT) || (Status == EFI_NOT_READY)) {\r
1512 *NeedRetry = TRUE;\r
1513 FallStatus = EFI_DEVICE_ERROR;\r
1514 \r
1515 } else if ((Status == EFI_INVALID_PARAMETER) || (Status == EFI_UNSUPPORTED)) {\r
1516 *NeedRetry = FALSE;\r
1517 FallStatus = EFI_DEVICE_ERROR;\r
1518 \r
1519 } else if (Status == EFI_DEVICE_ERROR) {\r
1520 if (AskResetIfError) {\r
1521 ScsiDiskDevice->ScsiIo->ResetDevice (ScsiDiskDevice->ScsiIo);\r
1522 }\r
1523 \r
1524 FallStatus = EFI_DEVICE_ERROR;\r
6ad55b15 1525 }\r
1526\r
1527 if (EFI_ERROR (FallStatus)) {\r
1528 if (*NumberOfSenseKeys != 0) {\r
1529 *NeedRetry = FALSE;\r
1530 return EFI_SUCCESS;\r
1531 } else {\r
1532 return EFI_DEVICE_ERROR;\r
1533 }\r
1534 }\r
1535\r
1536 (*NumberOfSenseKeys) += 1;\r
1537\r
1538 //\r
1539 // no more sense key or number of sense keys exceeds predefined,\r
1540 // skip the loop.\r
1541 //\r
1542 if ((PtrSenseData->Sense_Key == EFI_SCSI_SK_NO_SENSE) || \r
1543 (*NumberOfSenseKeys == ScsiDiskDevice->SenseDataNumber)) {\r
1544 SenseReq = FALSE;\r
1545 }\r
6ad55b15 1546 PtrSenseData += 1;\r
6ad55b15 1547 }\r
6ad55b15 1548 return EFI_SUCCESS;\r
1549}\r
1550\r
1551VOID\r
1552GetMediaInfo (\r
1553 SCSI_DISK_DEV *ScsiDiskDevice,\r
1554 EFI_SCSI_DISK_CAPACITY_DATA *Capacity\r
1555 )\r
1556/*++\r
1557\r
1558Routine Description:\r
1559\r
f36d6e66 1560 Get information from media read capacity command\r
6ad55b15 1561\r
1562Arguments:\r
1563\r
f36d6e66 1564 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
1565 Capacity - The pointer of EFI_SCSI_DISK_CAPACITY_DATA\r
6ad55b15 1566\r
1567Returns:\r
1568\r
f36d6e66 1569 NONE\r
6ad55b15 1570\r
1571--*/\r
1572{\r
1573 ScsiDiskDevice->BlkIo.Media->LastBlock = (Capacity->LastLba3 << 24) |\r
1574 (Capacity->LastLba2 << 16) |\r
1575 (Capacity->LastLba1 << 8) |\r
1576 Capacity->LastLba0;\r
1577\r
1578 ScsiDiskDevice->BlkIo.Media->MediaPresent = TRUE;\r
1579 ScsiDiskDevice->BlkIo.Media->BlockSize = (Capacity->BlockSize3 << 24) |\r
1580 (Capacity->BlockSize2 << 16) | \r
1581 (Capacity->BlockSize1 << 8) |\r
1582 Capacity->BlockSize0;\r
1583 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_DISK) {\r
1584 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x200;\r
1585 }\r
1586\r
1587 if (ScsiDiskDevice->DeviceType == EFI_SCSI_TYPE_CDROM) {\r
1588 ScsiDiskDevice->BlkIo.Media->BlockSize = 0x800;\r
1589 }\r
1590}\r
1591\r
1592VOID\r
1593ParseInquiryData (\r
1594 SCSI_DISK_DEV *ScsiDiskDevice\r
1595 )\r
1596/*++\r
1597\r
1598Routine Description:\r
1599\r
f36d6e66 1600 Parse Inquiry data\r
6ad55b15 1601\r
1602Arguments:\r
1603\r
f36d6e66 1604 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
6ad55b15 1605\r
1606Returns:\r
1607\r
f36d6e66 1608 NONE\r
6ad55b15 1609\r
1610--*/\r
1611{\r
1612 ScsiDiskDevice->FixedDevice = (BOOLEAN) (ScsiDiskDevice->InquiryData.RMB ? 0 : 1);\r
1613 ScsiDiskDevice->BlkIoMedia.RemovableMedia = (BOOLEAN) (!ScsiDiskDevice->FixedDevice);\r
1614}\r
1615\r
1616EFI_STATUS\r
f36d6e66 1617EFIAPI\r
6ad55b15 1618ScsiDiskReadSectors (\r
1619 SCSI_DISK_DEV *ScsiDiskDevice,\r
1620 VOID *Buffer,\r
1621 EFI_LBA Lba,\r
1622 UINTN NumberOfBlocks\r
1623 )\r
1624/*++\r
1625\r
1626Routine Description:\r
1627\r
f36d6e66 1628 Read sector from SCSI Disk\r
6ad55b15 1629\r
1630Arguments:\r
1631\r
f36d6e66 1632 ScsiDiskDevice - The poiniter of SCSI_DISK_DEV\r
1633 Buffer - The buffer to fill in the read out data\r
1634 Lba - Logic block address\r
1635 NumberOfBlocks - The number of blocks to read\r
6ad55b15 1636\r
1637Returns:\r
1638\r
f36d6e66 1639 EFI_DEVICE_ERROR\r
1640 EFI_SUCCESS\r
6ad55b15 1641\r
1642--*/\r
1643{\r
1644 UINTN BlocksRemaining;\r
1645 UINT32 Lba32;\r
1646 UINT8 *PtrBuffer;\r
1647 UINT32 BlockSize;\r
1648 UINT32 ByteCount;\r
1649 UINT32 MaxBlock;\r
1650 UINT32 SectorCount;\r
1651 UINT64 Timeout;\r
1652 EFI_STATUS Status;\r
1653 UINT8 Index;\r
1654 UINT8 MaxRetry;\r
1655 BOOLEAN NeedRetry;\r
1656 EFI_SCSI_SENSE_DATA *SenseData;\r
1657 UINTN NumberOfSenseKeys;\r
1658\r
1659 SenseData = NULL;\r
1660 NumberOfSenseKeys = 0;\r
1661\r
1662 Status = EFI_SUCCESS;\r
1663\r
1664 BlocksRemaining = NumberOfBlocks;\r
1665 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
1666 //\r
1667 // limit the data bytes that can be transferred by one Read(10) Command\r
1668 //\r
1669 MaxBlock = 65536;\r
1670\r
1671 PtrBuffer = Buffer;\r
1672 Lba32 = (UINT32) Lba;\r
1673\r
1674 while (BlocksRemaining > 0) {\r
1675\r
1676 if (BlocksRemaining <= MaxBlock) {\r
1677\r
1678 SectorCount = (UINT16) BlocksRemaining;\r
1679 } else {\r
1680\r
1681 SectorCount = MaxBlock;\r
1682 }\r
1683\r
1684 ByteCount = SectorCount * BlockSize;\r
1685 Timeout = EfiScsiStallSeconds (2);\r
1686\r
1687 MaxRetry = 2;\r
1688 for (Index = 0; Index < MaxRetry; Index++) {\r
1689\r
1690 Status = ScsiDiskRead10 (\r
1691 ScsiDiskDevice,\r
1692 &NeedRetry,\r
1693 &SenseData,\r
1694 &NumberOfSenseKeys,\r
1695 Timeout,\r
1696 PtrBuffer,\r
1697 &ByteCount,\r
1698 Lba32,\r
1699 SectorCount\r
1700 );\r
1701 if (!EFI_ERROR (Status)) {\r
1702 break;\r
1703 }\r
1704\r
1705 if (!NeedRetry) {\r
1706 return EFI_DEVICE_ERROR;\r
1707 }\r
1708\r
1709 }\r
1710\r
1711 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
1712 return EFI_DEVICE_ERROR;\r
1713 }\r
1714\r
1715 //\r
1716 // actual transferred sectors\r
1717 //\r
1718 SectorCount = ByteCount / BlockSize;\r
1719\r
1720 Lba32 += SectorCount;\r
1721 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
1722 BlocksRemaining -= SectorCount;\r
1723 }\r
1724\r
1725 return EFI_SUCCESS;\r
1726}\r
1727\r
1728EFI_STATUS\r
1729ScsiDiskWriteSectors (\r
1730 SCSI_DISK_DEV *ScsiDiskDevice,\r
1731 VOID *Buffer,\r
1732 EFI_LBA Lba,\r
1733 UINTN NumberOfBlocks\r
1734 )\r
1735/*++\r
1736\r
1737Routine Description:\r
1738\r
f36d6e66 1739 Write SCSI Disk sectors\r
6ad55b15 1740\r
1741Arguments:\r
1742\r
f36d6e66 1743 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
1744 Buffer - The data buffer to write sector\r
1745 Lba - Logic block address\r
1746 NumberOfBlocks - The number of blocks to write\r
6ad55b15 1747\r
1748Returns:\r
1749\r
f36d6e66 1750 EFI_DEVICE_ERROR \r
1751 EFI_SUCCESS\r
6ad55b15 1752\r
1753--*/\r
1754{\r
1755 UINTN BlocksRemaining;\r
1756 UINT32 Lba32;\r
1757 UINT8 *PtrBuffer;\r
1758 UINT32 BlockSize;\r
1759 UINT32 ByteCount;\r
1760 UINT32 MaxBlock;\r
1761 UINT32 SectorCount;\r
1762 UINT64 Timeout;\r
1763 EFI_STATUS Status;\r
1764 UINT8 Index;\r
1765 UINT8 MaxRetry;\r
1766 BOOLEAN NeedRetry;\r
1767 EFI_SCSI_SENSE_DATA *SenseData;\r
1768 UINTN NumberOfSenseKeys;\r
1769\r
1770 SenseData = NULL;\r
1771 NumberOfSenseKeys = 0;\r
1772\r
1773 Status = EFI_SUCCESS;\r
1774\r
1775 BlocksRemaining = NumberOfBlocks;\r
1776 BlockSize = ScsiDiskDevice->BlkIo.Media->BlockSize;\r
1777 //\r
1778 // limit the data bytes that can be transferred by one Write(10) Command\r
1779 //\r
1780 MaxBlock = 65536;\r
1781\r
1782 PtrBuffer = Buffer;\r
1783 Lba32 = (UINT32) Lba;\r
1784\r
1785 while (BlocksRemaining > 0) {\r
1786\r
1787 if (BlocksRemaining <= MaxBlock) {\r
1788\r
1789 SectorCount = (UINT16) BlocksRemaining;\r
1790 } else {\r
1791\r
1792 SectorCount = MaxBlock;\r
1793 }\r
1794\r
1795 ByteCount = SectorCount * BlockSize;\r
1796 Timeout = EfiScsiStallSeconds (2);\r
1797 MaxRetry = 2;\r
1798 for (Index = 0; Index < MaxRetry; Index++) {\r
1799 Status = ScsiDiskWrite10 (\r
1800 ScsiDiskDevice,\r
1801 &NeedRetry,\r
1802 &SenseData,\r
1803 &NumberOfSenseKeys,\r
1804 Timeout,\r
1805 PtrBuffer,\r
1806 &ByteCount,\r
1807 Lba32,\r
1808 SectorCount\r
1809 );\r
1810 if (!EFI_ERROR (Status)) {\r
1811 break;\r
1812 }\r
1813\r
1814 if (!NeedRetry) {\r
1815 return EFI_DEVICE_ERROR;\r
1816 }\r
1817 }\r
1818\r
1819 if ((Index == MaxRetry) && (Status != EFI_SUCCESS)) {\r
1820 return EFI_DEVICE_ERROR;\r
1821 }\r
1822 //\r
1823 // actual transferred sectors\r
1824 //\r
1825 SectorCount = ByteCount / BlockSize;\r
1826\r
1827 Lba32 += SectorCount;\r
1828 PtrBuffer = PtrBuffer + SectorCount * BlockSize;\r
1829 BlocksRemaining -= SectorCount;\r
1830 }\r
1831\r
1832 return EFI_SUCCESS;\r
1833}\r
1834\r
1835EFI_STATUS\r
1836ScsiDiskRead10 (\r
1837 SCSI_DISK_DEV *ScsiDiskDevice,\r
1838 BOOLEAN *NeedRetry,\r
1839 EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1840 UINTN *NumberOfSenseKeys,\r
1841 UINT64 Timeout,\r
1842 UINT8 *DataBuffer,\r
1843 UINT32 *DataLength,\r
1844 UINT32 StartLba,\r
1845 UINT32 SectorSize\r
1846 )\r
1847/*++\r
1848\r
1849Routine Description:\r
1850\r
f36d6e66 1851 Sumbmit Read command \r
6ad55b15 1852\r
1853Arguments:\r
1854\r
f36d6e66 1855 ScsiDiskDevice - The pointer of ScsiDiskDevice\r
1856 NeedRetry - The pointer of flag indicates if needs retry if error happens\r
1857 SenseDataArray - The pointer of an array of sense data\r
1858 NumberOfSenseKeys - The number of sense key\r
1859 Timeout - The time to complete the command\r
1860 DataBuffer - The buffer to fill with the read out data\r
1861 DataLength - The length of buffer\r
1862 StartLba - The start logic block address\r
1863 SectorSize - The size of sector\r
6ad55b15 1864\r
1865Returns:\r
1866\r
f36d6e66 1867 EFI_STATUS\r
1868 \r
6ad55b15 1869--*/\r
1870{\r
1871 UINT8 SenseDataLength;\r
1872 EFI_STATUS Status;\r
1873 UINT8 HostAdapterStatus;\r
1874 UINT8 TargetStatus;\r
1875\r
1876 *NeedRetry = FALSE;\r
1877 *NumberOfSenseKeys = 0;\r
1878 SenseDataLength = 0;\r
d35be2a4 1879 Status = ScsiRead10Command (\r
6ad55b15 1880 ScsiDiskDevice->ScsiIo,\r
1881 Timeout,\r
1882 NULL,\r
1883 &SenseDataLength,\r
1884 &HostAdapterStatus,\r
1885 &TargetStatus,\r
1886 DataBuffer,\r
1887 DataLength,\r
1888 StartLba,\r
1889 SectorSize\r
1890 );\r
1891 return Status;\r
1892}\r
1893\r
1894EFI_STATUS\r
1895ScsiDiskWrite10 (\r
1896 SCSI_DISK_DEV *ScsiDiskDevice,\r
1897 BOOLEAN *NeedRetry,\r
1898 EFI_SCSI_SENSE_DATA **SenseDataArray,\r
1899 UINTN *NumberOfSenseKeys,\r
1900 UINT64 Timeout,\r
1901 UINT8 *DataBuffer,\r
1902 UINT32 *DataLength,\r
1903 UINT32 StartLba,\r
1904 UINT32 SectorSize\r
1905 )\r
1906/*++\r
1907\r
1908Routine Description:\r
1909\r
f36d6e66 1910 Submit Write Command\r
6ad55b15 1911\r
1912Arguments:\r
1913\r
f36d6e66 1914 ScsiDiskDevice - The pointer of ScsiDiskDevice\r
1915 NeedRetry - The pointer of flag indicates if needs retry if error happens\r
1916 SenseDataArray - The pointer of an array of sense data\r
1917 NumberOfSenseKeys - The number of sense key\r
1918 Timeout - The time to complete the command\r
1919 DataBuffer - The buffer to fill with the read out data\r
1920 DataLength - The length of buffer\r
1921 StartLba - The start logic block address\r
1922 SectorSize - The size of sector\r
6ad55b15 1923\r
1924Returns:\r
1925\r
f36d6e66 1926 EFI_STATUS\r
6ad55b15 1927\r
1928--*/\r
1929{\r
1930 EFI_STATUS Status;\r
1931 UINT8 SenseDataLength;\r
1932 UINT8 HostAdapterStatus;\r
1933 UINT8 TargetStatus;\r
1934\r
1935 *NeedRetry = FALSE;\r
1936 *NumberOfSenseKeys = 0;\r
1937 SenseDataLength = 0;\r
d35be2a4 1938 Status = ScsiWrite10Command (\r
6ad55b15 1939 ScsiDiskDevice->ScsiIo,\r
1940 Timeout,\r
1941 NULL,\r
1942 &SenseDataLength,\r
1943 &HostAdapterStatus,\r
1944 &TargetStatus,\r
1945 DataBuffer,\r
1946 DataLength,\r
1947 StartLba,\r
1948 SectorSize\r
1949 );\r
1950 return Status;\r
1951}\r
1952\r
1953BOOLEAN\r
1954ScsiDiskIsNoMedia (\r
1955 IN EFI_SCSI_SENSE_DATA *SenseData,\r
1956 IN UINTN SenseCounts\r
1957 )\r
1958/*++\r
1959\r
1960Routine Description:\r
1961\r
f36d6e66 1962 Check sense key to find if media presents\r
6ad55b15 1963\r
1964Arguments:\r
1965\r
f36d6e66 1966 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
1967 SenseCounts - The number of sense key\r
6ad55b15 1968\r
1969Returns:\r
1970\r
f36d6e66 1971 BOOLEAN\r
6ad55b15 1972\r
1973--*/\r
1974{\r
1975 EFI_SCSI_SENSE_DATA *SensePtr;\r
1976 UINTN Index;\r
1977 BOOLEAN IsNoMedia;\r
1978\r
1979 IsNoMedia = FALSE;\r
1980 SensePtr = SenseData;\r
1981\r
1982 for (Index = 0; Index < SenseCounts; Index++) {\r
6ad55b15 1983 //\r
1984 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2),\r
1985 // Additional Sense Code is ASC_NO_MEDIA (0x3A)\r
1986 //\r
1987 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NOT_READY) &&\r
1988 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_NO_MEDIA)) {\r
1989 IsNoMedia = TRUE;\r
1990 }\r
6ad55b15 1991 SensePtr++;\r
1992 }\r
1993\r
1994 return IsNoMedia;\r
1995}\r
1996\r
1997BOOLEAN\r
1998ScsiDiskIsMediaError (\r
1999 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2000 IN UINTN SenseCounts\r
2001 )\r
2002/*++\r
2003\r
2004Routine Description:\r
2005\r
f36d6e66 2006 Parse sense key\r
6ad55b15 2007\r
2008Arguments:\r
2009\r
f36d6e66 2010 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2011 SenseCounts - The number of sense key\r
6ad55b15 2012\r
2013Returns:\r
2014\r
f36d6e66 2015 BOOLEAN\r
6ad55b15 2016\r
2017--*/\r
2018{\r
2019 EFI_SCSI_SENSE_DATA *SensePtr;\r
2020 UINTN Index;\r
2021 BOOLEAN IsError;\r
2022\r
2023 IsError = FALSE;\r
2024 SensePtr = SenseData;\r
2025\r
2026 for (Index = 0; Index < SenseCounts; Index++) {\r
2027\r
2028 switch (SensePtr->Sense_Key) {\r
2029\r
2030 case EFI_SCSI_SK_MEDIUM_ERROR:\r
2031 //\r
2032 // Sense Key is EFI_SCSI_SK_MEDIUM_ERROR (0x3)\r
2033 //\r
2034 switch (SensePtr->Addnl_Sense_Code) {\r
2035\r
2036 //\r
2037 // fall through\r
2038 //\r
2039 case EFI_SCSI_ASC_MEDIA_ERR1:\r
2040\r
2041 //\r
2042 // fall through\r
2043 //\r
2044 case EFI_SCSI_ASC_MEDIA_ERR2:\r
2045\r
2046 //\r
2047 // fall through\r
2048 //\r
2049 case EFI_SCSI_ASC_MEDIA_ERR3:\r
2050 case EFI_SCSI_ASC_MEDIA_ERR4:\r
2051 IsError = TRUE;\r
2052 break;\r
2053\r
2054 default:\r
2055 break;\r
2056 }\r
2057\r
2058 break;\r
2059\r
2060 case EFI_SCSI_SK_NOT_READY:\r
2061 //\r
2062 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
2063 //\r
2064 switch (SensePtr->Addnl_Sense_Code) {\r
2065 //\r
2066 // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)\r
2067 //\r
2068 case EFI_SCSI_ASC_MEDIA_UPSIDE_DOWN:\r
2069 IsError = TRUE;\r
2070 break;\r
2071\r
2072 default:\r
2073 break;\r
2074 }\r
2075 break;\r
2076\r
2077 default:\r
2078 break;\r
2079 }\r
2080\r
2081 SensePtr++;\r
2082 }\r
2083\r
2084 return IsError;\r
2085}\r
2086\r
2087BOOLEAN\r
2088ScsiDiskIsHardwareError (\r
2089 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2090 IN UINTN SenseCounts\r
2091 )\r
2092/*++\r
2093\r
2094Routine Description:\r
2095\r
f36d6e66 2096 Check sense key to find if hardware error happens\r
6ad55b15 2097\r
2098Arguments:\r
2099\r
f36d6e66 2100 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2101 SenseCounts - The number of sense key\r
6ad55b15 2102\r
2103Returns:\r
2104\r
f36d6e66 2105 BOOLEAN\r
6ad55b15 2106\r
2107--*/\r
2108{\r
2109 EFI_SCSI_SENSE_DATA *SensePtr;\r
2110 UINTN Index;\r
2111 BOOLEAN IsError;\r
2112\r
2113 IsError = FALSE;\r
2114 SensePtr = SenseData;\r
2115\r
2116 for (Index = 0; Index < SenseCounts; Index++) {\r
2117 \r
2118 //\r
2119 // Sense Key is EFI_SCSI_SK_HARDWARE_ERROR (0x4)\r
2120 //\r
2121 if (SensePtr->Sense_Key == EFI_SCSI_SK_HARDWARE_ERROR) {\r
2122 IsError = TRUE;\r
2123 }\r
2124\r
2125 SensePtr++;\r
2126 }\r
2127\r
2128 return IsError;\r
2129}\r
2130\r
2131BOOLEAN\r
2132ScsiDiskIsMediaChange (\r
2133 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2134 IN UINTN SenseCounts\r
2135 )\r
2136/*++\r
2137\r
2138Routine Description:\r
2139\r
f36d6e66 2140 Check sense key to find if media has changed\r
6ad55b15 2141\r
2142Arguments:\r
2143\r
f36d6e66 2144 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2145 SenseCounts - The number of sense key\r
6ad55b15 2146\r
2147Returns:\r
2148\r
f36d6e66 2149 BOOLEAN\r
6ad55b15 2150\r
2151--*/\r
2152{\r
2153 EFI_SCSI_SENSE_DATA *SensePtr;\r
2154 UINTN Index;\r
2155 BOOLEAN IsMediaChanged;\r
2156\r
2157 IsMediaChanged = FALSE;\r
2158 SensePtr = SenseData;\r
2159\r
2160 for (Index = 0; Index < SenseCounts; Index++) {\r
2161 //\r
2162 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6),\r
2163 // Additional sense code is EFI_SCSI_ASC_MEDIA_CHANGE (0x28)\r
2164 //\r
2165 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
2166 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_MEDIA_CHANGE)) {\r
2167 IsMediaChanged = TRUE;\r
2168 }\r
2169\r
2170 SensePtr++;\r
2171 }\r
2172\r
2173 return IsMediaChanged;\r
2174}\r
2175\r
2176BOOLEAN\r
2177ScsiDiskIsResetBefore (\r
2178 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2179 IN UINTN SenseCounts\r
2180 )\r
2181/*++\r
2182\r
2183Routine Description:\r
2184\r
f36d6e66 2185 Check sense key to find if reset happens\r
6ad55b15 2186\r
2187Arguments:\r
2188\r
f36d6e66 2189 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2190 SenseCounts - The number of sense key\r
6ad55b15 2191\r
2192Returns:\r
2193\r
f36d6e66 2194 BOOLEAN\r
6ad55b15 2195\r
2196--*/\r
2197{\r
2198 EFI_SCSI_SENSE_DATA *SensePtr;\r
2199 UINTN Index;\r
2200 BOOLEAN IsResetBefore;\r
2201\r
2202 IsResetBefore = FALSE;\r
2203 SensePtr = SenseData;\r
2204\r
2205 for (Index = 0; Index < SenseCounts; Index++) {\r
2206 \r
2207 //\r
2208 // Sense Key is EFI_SCSI_SK_UNIT_ATTENTION (0x6)\r
2209 // Additional Sense Code is EFI_SCSI_ASC_RESET (0x29)\r
2210 //\r
2211 if ((SensePtr->Sense_Key == EFI_SCSI_SK_UNIT_ATTENTION) &&\r
2212 (SensePtr->Addnl_Sense_Code == EFI_SCSI_ASC_RESET)) {\r
2213 IsResetBefore = TRUE;\r
2214 }\r
2215\r
2216 SensePtr++;\r
2217 }\r
2218\r
2219 return IsResetBefore;\r
2220}\r
2221\r
2222BOOLEAN\r
2223ScsiDiskIsDriveReady (\r
2224 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2225 IN UINTN SenseCounts,\r
2226 OUT BOOLEAN *RetryLater\r
2227 )\r
2228/*++\r
2229\r
2230Routine Description:\r
2231\r
f36d6e66 2232 Check sense key to find if the drive is ready\r
6ad55b15 2233\r
2234Arguments:\r
2235\r
f36d6e66 2236 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2237 SenseCounts - The number of sense key\r
2238 RetryLater - The flag means if need a retry \r
6ad55b15 2239\r
2240Returns:\r
2241\r
f36d6e66 2242 BOOLEAN\r
6ad55b15 2243\r
2244--*/\r
2245{\r
2246 EFI_SCSI_SENSE_DATA *SensePtr;\r
2247 UINTN Index;\r
2248 BOOLEAN IsReady;\r
2249\r
2250 IsReady = TRUE;\r
2251 *RetryLater = FALSE;\r
2252 SensePtr = SenseData;\r
2253\r
2254 for (Index = 0; Index < SenseCounts; Index++) {\r
2255\r
2256 switch (SensePtr->Sense_Key) {\r
2257\r
2258 case EFI_SCSI_SK_NOT_READY:\r
2259 //\r
2260 // Sense Key is EFI_SCSI_SK_NOT_READY (0x2)\r
2261 //\r
2262 switch (SensePtr->Addnl_Sense_Code) {\r
2263 case EFI_SCSI_ASC_NOT_READY:\r
2264 //\r
2265 // Additional Sense Code is EFI_SCSI_ASC_NOT_READY (0x4)\r
2266 //\r
2267 switch (SensePtr->Addnl_Sense_Code_Qualifier) {\r
2268 case EFI_SCSI_ASCQ_IN_PROGRESS:\r
2269 //\r
2270 // Additional Sense Code Qualifier is\r
2271 // EFI_SCSI_ASCQ_IN_PROGRESS (0x1)\r
2272 //\r
2273 IsReady = FALSE;\r
2274 *RetryLater = TRUE;\r
2275 break;\r
2276\r
2277 default:\r
2278 IsReady = FALSE;\r
2279 *RetryLater = FALSE;\r
2280 break;\r
2281 }\r
2282 break;\r
2283\r
2284 default:\r
2285 break;\r
2286 }\r
2287 break;\r
2288\r
2289 default:\r
2290 break;\r
2291 }\r
2292\r
2293 SensePtr++;\r
2294 }\r
2295\r
2296 return IsReady;\r
2297}\r
2298\r
2299BOOLEAN\r
2300ScsiDiskHaveSenseKey (\r
2301 IN EFI_SCSI_SENSE_DATA *SenseData,\r
2302 IN UINTN SenseCounts\r
2303 )\r
2304/*++\r
2305\r
2306Routine Description:\r
2307\r
f36d6e66 2308 Check sense key to find if it has sense key\r
6ad55b15 2309\r
2310Arguments:\r
2311\r
f36d6e66 2312 SenseData - The pointer of EFI_SCSI_SENSE_DATA\r
2313 SenseCounts - The number of sense key\r
6ad55b15 2314\r
2315Returns:\r
2316\r
f36d6e66 2317 BOOLEAN\r
6ad55b15 2318\r
2319--*/\r
2320{\r
2321 EFI_SCSI_SENSE_DATA *SensePtr;\r
2322 UINTN Index;\r
2323 BOOLEAN HaveSenseKey;\r
2324\r
2325 if (SenseCounts == 0) {\r
2326 HaveSenseKey = FALSE;\r
2327 } else {\r
2328 HaveSenseKey = TRUE;\r
2329 }\r
2330\r
2331 SensePtr = SenseData;\r
2332\r
2333 for (Index = 0; Index < SenseCounts; Index++) {\r
2334 \r
2335 //\r
2336 // Sense Key is SK_NO_SENSE (0x0)\r
2337 //\r
2338 if ((SensePtr->Sense_Key == EFI_SCSI_SK_NO_SENSE) &&\r
2339 (Index == 0)) {\r
2340 HaveSenseKey = FALSE;\r
2341 }\r
2342\r
2343 SensePtr++;\r
2344 }\r
2345\r
2346 return HaveSenseKey;\r
2347}\r
2348\r
2349VOID\r
2350ReleaseScsiDiskDeviceResources (\r
2351 IN SCSI_DISK_DEV *ScsiDiskDevice\r
2352 )\r
2353/*++\r
2354\r
2355Routine Description:\r
2356\r
f36d6e66 2357 Release resource about disk device\r
6ad55b15 2358\r
2359Arguments:\r
2360\r
f36d6e66 2361 ScsiDiskDevice - The pointer of SCSI_DISK_DEV\r
6ad55b15 2362\r
2363Returns:\r
2364\r
f36d6e66 2365 NONE\r
6ad55b15 2366\r
2367--*/\r
2368{\r
2369 if (ScsiDiskDevice == NULL) {\r
2370 return ;\r
2371 }\r
2372\r
2373 if (ScsiDiskDevice->SenseData != NULL) {\r
2374 gBS->FreePool (ScsiDiskDevice->SenseData);\r
2375 ScsiDiskDevice->SenseData = NULL;\r
2376 }\r
2377\r
2378 if (ScsiDiskDevice->ControllerNameTable != NULL) {\r
2379 FreeUnicodeStringTable (ScsiDiskDevice->ControllerNameTable);\r
2380 ScsiDiskDevice->ControllerNameTable = NULL;\r
2381 }\r
2382\r
2383 gBS->FreePool (ScsiDiskDevice);\r
2384\r
2385 ScsiDiskDevice = NULL;\r
2386}\r