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