VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c@ 76553

Last change on this file since 76553 was 48674, checked in by vboxsync, 11 years ago

EFI: Export newly imported tinaocore UEFI sources to OSE.

  • Property svn:eol-style set to native
File size: 88.5 KB
Line 
1/** @file
2 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
3 This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11**/
12
13#include "AtapiPassThru.h"
14
15
16SCSI_COMMAND_SET gEndTable = { 0xff, (DATA_DIRECTION) 0xff };
17
18///
19/// This table contains all the supported ATAPI commands.
20///
21SCSI_COMMAND_SET gSupportedATAPICommands[] = {
22 { OP_INQUIRY, DataIn },
23 { OP_LOAD_UNLOAD_CD, NoData },
24 { OP_MECHANISM_STATUS, DataIn },
25 { OP_MODE_SELECT_10, DataOut },
26 { OP_MODE_SENSE_10, DataIn },
27 { OP_PAUSE_RESUME, NoData },
28 { OP_PLAY_AUDIO_10, DataIn },
29 { OP_PLAY_AUDIO_MSF, DataIn },
30 { OP_PLAY_CD, DataIn },
31 { OP_PLAY_CD_MSF, DataIn },
32 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData },
33 { OP_READ_10, DataIn },
34 { OP_READ_12, DataIn },
35 { OP_READ_CAPACITY, DataIn },
36 { OP_READ_CD, DataIn },
37 { OP_READ_CD_MSF, DataIn },
38 { OP_READ_HEADER, DataIn },
39 { OP_READ_SUB_CHANNEL, DataIn },
40 { OP_READ_TOC, DataIn },
41 { OP_REQUEST_SENSE, DataIn },
42 { OP_SCAN, NoData },
43 { OP_SEEK_10, NoData },
44 { OP_SET_CD_SPEED, DataOut },
45 { OP_STOPPLAY_SCAN, NoData },
46 { OP_START_STOP_UNIT, NoData },
47 { OP_TEST_UNIT_READY, NoData },
48 { OP_FORMAT_UNIT, DataOut },
49 { OP_READ_FORMAT_CAPACITIES, DataIn },
50 { OP_VERIFY, DataOut },
51 { OP_WRITE_10, DataOut },
52 { OP_WRITE_12, DataOut },
53 { OP_WRITE_AND_VERIFY, DataOut },
54 { 0xff, (DATA_DIRECTION) 0xff }
55};
56
57GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {
58 L"ATAPI Controller",
59 L"ATAPI Channel",
60 4,
61 EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
62 0
63};
64
65GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {
66 &gScsiPassThruMode,
67 AtapiScsiPassThruFunction,
68 AtapiScsiPassThruGetNextDevice,
69 AtapiScsiPassThruBuildDevicePath,
70 AtapiScsiPassThruGetTargetLun,
71 AtapiScsiPassThruResetChannel,
72 AtapiScsiPassThruResetTarget
73};
74
75GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {
76 4,
77 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
78 0
79};
80
81GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {
82 &gExtScsiPassThruMode,
83 AtapiExtScsiPassThruFunction,
84 AtapiExtScsiPassThruGetNextTargetLun,
85 AtapiExtScsiPassThruBuildDevicePath,
86 AtapiExtScsiPassThruGetTargetLun,
87 AtapiExtScsiPassThruResetChannel,
88 AtapiExtScsiPassThruResetTarget,
89 AtapiExtScsiPassThruGetNextTarget
90};
91
92EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {
93 AtapiScsiPassThruDriverBindingSupported,
94 AtapiScsiPassThruDriverBindingStart,
95 AtapiScsiPassThruDriverBindingStop,
96 0x10,
97 NULL,
98 NULL
99};
100
101EFI_STATUS
102EFIAPI
103AtapiScsiPassThruDriverBindingSupported (
104 IN EFI_DRIVER_BINDING_PROTOCOL *This,
105 IN EFI_HANDLE Controller,
106 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
107 )
108/*++
109
110Routine Description:
111 Test to see if this driver supports ControllerHandle. Any ControllerHandle
112 that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.
113
114Arguments:
115
116 This - Protocol instance pointer.
117 Controller - Handle of device to test
118 RemainingDevicePath - Not used
119
120Returns:
121 EFI_STATUS
122
123--*/
124{
125 EFI_STATUS Status;
126 EFI_PCI_IO_PROTOCOL *PciIo;
127 PCI_TYPE00 Pci;
128
129
130 //
131 // Open the IO Abstraction(s) needed to perform the supported test
132 //
133 Status = gBS->OpenProtocol (
134 Controller,
135 &gEfiPciIoProtocolGuid,
136 (VOID **) &PciIo,
137 This->DriverBindingHandle,
138 Controller,
139 EFI_OPEN_PROTOCOL_BY_DRIVER
140 );
141 if (EFI_ERROR (Status)) {
142 return Status;
143 }
144 //
145 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
146 // can be managed by this driver. Read the PCI Configuration Header
147 // for this device.
148 //
149 Status = PciIo->Pci.Read (
150 PciIo,
151 EfiPciIoWidthUint32,
152 0,
153 sizeof (Pci) / sizeof (UINT32),
154 &Pci
155 );
156 if (EFI_ERROR (Status)) {
157 gBS->CloseProtocol (
158 Controller,
159 &gEfiPciIoProtocolGuid,
160 This->DriverBindingHandle,
161 Controller
162 );
163 return EFI_UNSUPPORTED;
164 }
165
166 if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE) {
167
168 Status = EFI_UNSUPPORTED;
169 }
170
171 gBS->CloseProtocol (
172 Controller,
173 &gEfiPciIoProtocolGuid,
174 This->DriverBindingHandle,
175 Controller
176 );
177
178 return Status;
179}
180
181EFI_STATUS
182EFIAPI
183AtapiScsiPassThruDriverBindingStart (
184 IN EFI_DRIVER_BINDING_PROTOCOL *This,
185 IN EFI_HANDLE Controller,
186 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
187 )
188/*++
189
190Routine Description:
191 Create handles for IDE channels specified by RemainingDevicePath.
192 Install SCSI Pass Thru Protocol onto each created handle.
193
194Arguments:
195
196 This - Protocol instance pointer.
197 Controller - Handle of device to test
198 RemainingDevicePath - Not used
199
200Returns:
201 EFI_STATUS
202
203--*/
204{
205 EFI_STATUS Status;
206 EFI_PCI_IO_PROTOCOL *PciIo;
207 UINT64 Supports;
208 UINT64 OriginalPciAttributes;
209 BOOLEAN PciAttributesSaved;
210
211 PciIo = NULL;
212 Status = gBS->OpenProtocol (
213 Controller,
214 &gEfiPciIoProtocolGuid,
215 (VOID **) &PciIo,
216 This->DriverBindingHandle,
217 Controller,
218 EFI_OPEN_PROTOCOL_BY_DRIVER
219 );
220 if (EFI_ERROR (Status)) {
221 return Status;
222 }
223
224 PciAttributesSaved = FALSE;
225 //
226 // Save original PCI attributes
227 //
228 Status = PciIo->Attributes (
229 PciIo,
230 EfiPciIoAttributeOperationGet,
231 0,
232 &OriginalPciAttributes
233 );
234
235 if (EFI_ERROR (Status)) {
236 goto Done;
237 }
238 PciAttributesSaved = TRUE;
239
240 Status = PciIo->Attributes (
241 PciIo,
242 EfiPciIoAttributeOperationSupported,
243 0,
244 &Supports
245 );
246 if (!EFI_ERROR (Status)) {
247 Supports &= (EFI_PCI_DEVICE_ENABLE |
248 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |
249 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);
250 Status = PciIo->Attributes (
251 PciIo,
252 EfiPciIoAttributeOperationEnable,
253 Supports,
254 NULL
255 );
256 }
257 if (EFI_ERROR (Status)) {
258 goto Done;
259 }
260
261 //
262 // Create SCSI Pass Thru instance for the IDE channel.
263 //
264 Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);
265
266Done:
267 if (EFI_ERROR (Status)) {
268 if (PciAttributesSaved == TRUE) {
269 //
270 // Restore original PCI attributes
271 //
272 PciIo->Attributes (
273 PciIo,
274 EfiPciIoAttributeOperationSet,
275 OriginalPciAttributes,
276 NULL
277 );
278 }
279
280 gBS->CloseProtocol (
281 Controller,
282 &gEfiPciIoProtocolGuid,
283 This->DriverBindingHandle,
284 Controller
285 );
286 }
287
288 return Status;
289}
290
291EFI_STATUS
292EFIAPI
293AtapiScsiPassThruDriverBindingStop (
294 IN EFI_DRIVER_BINDING_PROTOCOL *This,
295 IN EFI_HANDLE Controller,
296 IN UINTN NumberOfChildren,
297 IN EFI_HANDLE *ChildHandleBuffer
298 )
299/*++
300
301Routine Description:
302
303 Stop this driver on ControllerHandle. Support stoping any child handles
304 created by this driver.
305
306Arguments:
307
308 This - Protocol instance pointer.
309 Controller - Handle of device to stop driver on
310 NumberOfChildren - Number of Children in the ChildHandleBuffer
311 ChildHandleBuffer - List of handles for the children we need to stop.
312
313Returns:
314
315 EFI_STATUS
316
317--*/
318{
319 EFI_STATUS Status;
320 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
321 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
322 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
323
324 if (FeaturePcdGet (PcdSupportScsiPassThru)) {
325 Status = gBS->OpenProtocol (
326 Controller,
327 &gEfiScsiPassThruProtocolGuid,
328 (VOID **) &ScsiPassThru,
329 This->DriverBindingHandle,
330 Controller,
331 EFI_OPEN_PROTOCOL_GET_PROTOCOL
332 );
333 if (EFI_ERROR (Status)) {
334 return Status;
335 }
336 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);
337 if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
338 Status = gBS->UninstallMultipleProtocolInterfaces (
339 Controller,
340 &gEfiScsiPassThruProtocolGuid,
341 &AtapiScsiPrivate->ScsiPassThru,
342 &gEfiExtScsiPassThruProtocolGuid,
343 &AtapiScsiPrivate->ExtScsiPassThru,
344 NULL
345 );
346 } else {
347 Status = gBS->UninstallMultipleProtocolInterfaces (
348 Controller,
349 &gEfiScsiPassThruProtocolGuid,
350 &AtapiScsiPrivate->ScsiPassThru,
351 NULL
352 );
353 }
354 } else {
355 Status = gBS->OpenProtocol (
356 Controller,
357 &gEfiExtScsiPassThruProtocolGuid,
358 (VOID **) &ExtScsiPassThru,
359 This->DriverBindingHandle,
360 Controller,
361 EFI_OPEN_PROTOCOL_GET_PROTOCOL
362 );
363 if (EFI_ERROR (Status)) {
364 return Status;
365 }
366 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);
367 Status = gBS->UninstallMultipleProtocolInterfaces (
368 Controller,
369 &gEfiExtScsiPassThruProtocolGuid,
370 &AtapiScsiPrivate->ExtScsiPassThru,
371 NULL
372 );
373 }
374 if (EFI_ERROR (Status)) {
375 return Status;
376 }
377
378 //
379 // Restore original PCI attributes
380 //
381 AtapiScsiPrivate->PciIo->Attributes (
382 AtapiScsiPrivate->PciIo,
383 EfiPciIoAttributeOperationSet,
384 AtapiScsiPrivate->OriginalPciAttributes,
385 NULL
386 );
387
388 gBS->CloseProtocol (
389 Controller,
390 &gEfiPciIoProtocolGuid,
391 This->DriverBindingHandle,
392 Controller
393 );
394
395 gBS->FreePool (AtapiScsiPrivate);
396
397 return EFI_SUCCESS;
398}
399
400EFI_STATUS
401RegisterAtapiScsiPassThru (
402 IN EFI_DRIVER_BINDING_PROTOCOL *This,
403 IN EFI_HANDLE Controller,
404 IN EFI_PCI_IO_PROTOCOL *PciIo,
405 IN UINT64 OriginalPciAttributes
406 )
407/*++
408
409Routine Description:
410 Attaches SCSI Pass Thru Protocol for specified IDE channel.
411
412Arguments:
413 This - Protocol instance pointer.
414 Controller - Parent device handle to the IDE channel.
415 PciIo - PCI I/O protocol attached on the "Controller".
416
417Returns:
418 Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
419
420--*/
421{
422 EFI_STATUS Status;
423 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
424 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];
425
426 AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));
427 if (AtapiScsiPrivate == NULL) {
428 return EFI_OUT_OF_RESOURCES;
429 }
430
431 AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;
432 AtapiScsiPrivate->Handle = Controller;
433
434 //
435 // will reset the IoPort inside each API function.
436 //
437 AtapiScsiPrivate->IoPort = NULL;
438 AtapiScsiPrivate->PciIo = PciIo;
439 AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;
440
441 //
442 // Obtain IDE IO port registers' base addresses
443 //
444 Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448
449 InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);
450
451 //
452 // Initialize the LatestTargetId to MAX_TARGET_ID.
453 //
454 AtapiScsiPrivate->LatestTargetId = MAX_TARGET_ID;
455 AtapiScsiPrivate->LatestLun = 0;
456
457 Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);
458
459 return Status;
460}
461
462EFI_STATUS
463EFIAPI
464AtapiScsiPassThruFunction (
465 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
466 IN UINT32 Target,
467 IN UINT64 Lun,
468 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
469 IN EFI_EVENT Event OPTIONAL
470 )
471/*++
472
473Routine Description:
474
475 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
476
477Arguments:
478
479 This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.
480 Target: The Target ID of the ATAPI device to send the SCSI
481 Request Packet. To ATAPI devices attached on an IDE
482 Channel, Target ID 0 indicates Master device;Target
483 ID 1 indicates Slave device.
484 Lun: The LUN of the ATAPI device to send the SCSI Request
485 Packet. To the ATAPI device, Lun is always 0.
486 Packet: The SCSI Request Packet to send to the ATAPI device
487 specified by Target and Lun.
488 Event: If non-blocking I/O is not supported then Event is ignored,
489 and blocking I/O is performed.
490 If Event is NULL, then blocking I/O is performed.
491 If Event is not NULL and non blocking I/O is supported,
492 then non-blocking I/O is performed, and Event will be signaled
493 when the SCSI Request Packet completes.
494
495Returns:
496
497 EFI_STATUS
498
499--*/
500{
501 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
502 EFI_STATUS Status;
503
504 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
505
506 //
507 // Target is not allowed beyond MAX_TARGET_ID
508 //
509 if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
510 return EFI_INVALID_PARAMETER;
511 }
512
513 //
514 // check the data fields in Packet parameter.
515 //
516 Status = CheckSCSIRequestPacket (Packet);
517 if (EFI_ERROR (Status)) {
518 return Status;
519 }
520
521 //
522 // If Request Packet targets at the IDE channel itself,
523 // do nothing.
524 //
525 if (Target == This->Mode->AdapterId) {
526 Packet->TransferLength = 0;
527 return EFI_SUCCESS;
528 }
529
530 //
531 // According to Target ID, reset the Atapi I/O Register mapping
532 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
533 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
534 //
535 if ((Target / 2) == 0) {
536 Target = Target % 2;
537 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
538 } else {
539 Target = Target % 2;
540 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
541 }
542
543 //
544 // the ATAPI SCSI interface does not support non-blocking I/O
545 // ignore the Event parameter
546 //
547 // Performs blocking I/O.
548 //
549 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);
550 return Status;
551}
552
553EFI_STATUS
554EFIAPI
555AtapiScsiPassThruGetNextDevice (
556 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
557 IN OUT UINT32 *Target,
558 IN OUT UINT64 *Lun
559 )
560/*++
561
562Routine Description:
563
564 Used to retrieve the list of legal Target IDs for SCSI devices
565 on a SCSI channel.
566
567Arguments:
568
569 This - Protocol instance pointer.
570 Target - On input, a pointer to the Target ID of a SCSI
571 device present on the SCSI channel. On output,
572 a pointer to the Target ID of the next SCSI device
573 present on a SCSI channel. An input value of
574 0xFFFFFFFF retrieves the Target ID of the first
575 SCSI device present on a SCSI channel.
576 Lun - On input, a pointer to the LUN of a SCSI device
577 present on the SCSI channel. On output, a pointer
578 to the LUN of the next SCSI device present on
579 a SCSI channel.
580Returns:
581
582 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
583 on the SCSI channel was returned in Target and Lun.
584 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
585 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
586 returned on a previous call to GetNextDevice().
587--*/
588{
589 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
590
591 //
592 // Retrieve Device Private Data Structure.
593 //
594 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
595
596 //
597 // Check whether Target is valid.
598 //
599 if (Target == NULL || Lun == NULL) {
600 return EFI_INVALID_PARAMETER;
601 }
602
603 if ((*Target != 0xFFFFFFFF) &&
604 ((*Target != AtapiScsiPrivate->LatestTargetId) ||
605 (*Lun != AtapiScsiPrivate->LatestLun))) {
606 return EFI_INVALID_PARAMETER;
607 }
608
609 if (*Target == MAX_TARGET_ID) {
610 return EFI_NOT_FOUND;
611 }
612
613 if (*Target == 0xFFFFFFFF) {
614 *Target = 0;
615 } else {
616 *Target = AtapiScsiPrivate->LatestTargetId + 1;
617 }
618
619 *Lun = 0;
620
621 //
622 // Update the LatestTargetId.
623 //
624 AtapiScsiPrivate->LatestTargetId = *Target;
625 AtapiScsiPrivate->LatestLun = *Lun;
626
627 return EFI_SUCCESS;
628
629}
630
631EFI_STATUS
632EFIAPI
633AtapiScsiPassThruBuildDevicePath (
634 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
635 IN UINT32 Target,
636 IN UINT64 Lun,
637 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
638 )
639/*++
640
641Routine Description:
642
643 Used to allocate and build a device path node for a SCSI device
644 on a SCSI channel. Would not build device path for a SCSI Host Controller.
645
646Arguments:
647
648 This - Protocol instance pointer.
649 Target - The Target ID of the SCSI device for which
650 a device path node is to be allocated and built.
651 Lun - The LUN of the SCSI device for which a device
652 path node is to be allocated and built.
653 DevicePath - A pointer to a single device path node that
654 describes the SCSI device specified by
655 Target and Lun. This function is responsible
656 for allocating the buffer DevicePath with the boot
657 service AllocatePool(). It is the caller's
658 responsibility to free DevicePath when the caller
659 is finished with DevicePath.
660 Returns:
661 EFI_SUCCESS - The device path node that describes the SCSI device
662 specified by Target and Lun was allocated and
663 returned in DevicePath.
664 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
665 not exist on the SCSI channel.
666 EFI_INVALID_PARAMETER - DevicePath is NULL.
667 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
668 DevicePath.
669--*/
670{
671 EFI_DEV_PATH *Node;
672
673
674 //
675 // Validate parameters passed in.
676 //
677
678 if (DevicePath == NULL) {
679 return EFI_INVALID_PARAMETER;
680 }
681
682 //
683 // can not build device path for the SCSI Host Controller.
684 //
685 if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
686 return EFI_NOT_FOUND;
687 }
688
689 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
690 if (Node == NULL) {
691 return EFI_OUT_OF_RESOURCES;
692 }
693
694 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
695 Node->DevPath.SubType = MSG_ATAPI_DP;
696 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
697
698 Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);
699 Node->Atapi.SlaveMaster = (UINT8) (Target % 2);
700 Node->Atapi.Lun = (UINT16) Lun;
701
702 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
703
704 return EFI_SUCCESS;
705}
706
707EFI_STATUS
708EFIAPI
709AtapiScsiPassThruGetTargetLun (
710 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
711 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
712 OUT UINT32 *Target,
713 OUT UINT64 *Lun
714 )
715/*++
716
717Routine Description:
718
719 Used to translate a device path node to a Target ID and LUN.
720
721Arguments:
722
723 This - Protocol instance pointer.
724 DevicePath - A pointer to the device path node that
725 describes a SCSI device on the SCSI channel.
726 Target - A pointer to the Target ID of a SCSI device
727 on the SCSI channel.
728 Lun - A pointer to the LUN of a SCSI device on
729 the SCSI channel.
730Returns:
731
732 EFI_SUCCESS - DevicePath was successfully translated to a
733 Target ID and LUN, and they were returned
734 in Target and Lun.
735 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
736 EFI_UNSUPPORTED - This driver does not support the device path
737 node type in DevicePath.
738 EFI_NOT_FOUND - A valid translation from DevicePath to a
739 Target ID and LUN does not exist.
740--*/
741{
742 EFI_DEV_PATH *Node;
743
744 //
745 // Validate parameters passed in.
746 //
747 if (DevicePath == NULL || Target == NULL || Lun == NULL) {
748 return EFI_INVALID_PARAMETER;
749 }
750
751 //
752 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
753 //
754 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
755 (DevicePath->SubType != MSG_ATAPI_DP) ||
756 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
757 return EFI_UNSUPPORTED;
758 }
759
760 Node = (EFI_DEV_PATH *) DevicePath;
761
762 *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;
763 *Lun = Node->Atapi.Lun;
764
765 if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {
766 return EFI_NOT_FOUND;
767 }
768
769 return EFI_SUCCESS;
770}
771
772EFI_STATUS
773EFIAPI
774AtapiScsiPassThruResetChannel (
775 IN EFI_SCSI_PASS_THRU_PROTOCOL *This
776 )
777/*++
778
779Routine Description:
780
781 Resets a SCSI channel.This operation resets all the
782 SCSI devices connected to the SCSI channel.
783
784Arguments:
785
786 This - Protocol instance pointer.
787
788Returns:
789
790 EFI_SUCCESS - The SCSI channel was reset.
791 EFI_UNSUPPORTED - The SCSI channel does not support
792 a channel reset operation.
793 EFI_DEVICE_ERROR - A device error occurred while
794 attempting to reset the SCSI channel.
795 EFI_TIMEOUT - A timeout occurred while attempting
796 to reset the SCSI channel.
797--*/
798{
799 UINT8 DeviceControlValue;
800 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
801 UINT8 Index;
802 BOOLEAN ResetFlag;
803
804 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
805 ResetFlag = FALSE;
806
807 //
808 // Reset both Primary channel and Secondary channel.
809 // so, the IoPort pointer must point to the right I/O Register group
810 //
811 for (Index = 0; Index < 2; Index++) {
812 //
813 // Reset
814 //
815 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
816
817 DeviceControlValue = 0;
818 //
819 // set SRST bit to initiate soft reset
820 //
821 DeviceControlValue |= SRST;
822 //
823 // disable Interrupt
824 //
825 DeviceControlValue |= BIT1;
826 WritePortB (
827 AtapiScsiPrivate->PciIo,
828 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
829 DeviceControlValue
830 );
831
832 //
833 // Wait 10us
834 //
835 gBS->Stall (10);
836
837 //
838 // Clear SRST bit
839 // 0xfb:1111,1011
840 //
841 DeviceControlValue &= 0xfb;
842
843 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
844
845 //
846 // slave device needs at most 31s to clear BSY
847 //
848 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
849 ResetFlag = TRUE;
850 }
851 }
852
853 if (ResetFlag) {
854 return EFI_SUCCESS;
855 }
856
857 return EFI_TIMEOUT;
858}
859
860EFI_STATUS
861EFIAPI
862AtapiScsiPassThruResetTarget (
863 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
864 IN UINT32 Target,
865 IN UINT64 Lun
866 )
867/*++
868
869Routine Description:
870
871 Resets a SCSI device that is connected to a SCSI channel.
872
873Arguments:
874
875 This - Protocol instance pointer.
876 Target - The Target ID of the SCSI device to reset.
877 Lun - The LUN of the SCSI device to reset.
878
879Returns:
880
881 EFI_SUCCESS - The SCSI device specified by Target and
882 Lun was reset.
883 EFI_UNSUPPORTED - The SCSI channel does not support a target
884 reset operation.
885 EFI_INVALID_PARAMETER - Target or Lun are invalid.
886 EFI_DEVICE_ERROR - A device error occurred while attempting
887 to reset the SCSI device specified by Target
888 and Lun.
889 EFI_TIMEOUT - A timeout occurred while attempting to reset
890 the SCSI device specified by Target and Lun.
891--*/
892{
893 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
894 UINT8 Command;
895 UINT8 DeviceSelect;
896
897 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
898
899 if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
900 return EFI_INVALID_PARAMETER;
901 }
902 //
903 // Directly return EFI_SUCCESS if want to reset the host controller
904 //
905 if (Target == This->Mode->AdapterId) {
906 return EFI_SUCCESS;
907 }
908
909 //
910 // According to Target ID, reset the Atapi I/O Register mapping
911 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
912 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
913 //
914 if ((Target / 2) == 0) {
915 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
916 } else {
917 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
918 }
919
920 //
921 // for ATAPI device, no need to wait DRDY ready after device selecting.
922 //
923 // bit7 and bit5 are both set to 1 for backward compatibility
924 //
925 DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Target << 4)));
926 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
927
928 Command = ATAPI_SOFT_RESET_CMD;
929 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
930
931 //
932 // BSY clear is the only status return to the host by the device
933 // when reset is complete.
934 // slave device needs at most 31s to clear BSY
935 //
936 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
937 return EFI_TIMEOUT;
938 }
939
940 //
941 // stall 5 seconds to make the device status stable
942 //
943 gBS->Stall (5000000);
944
945 return EFI_SUCCESS;
946}
947
948EFI_STATUS
949EFIAPI
950AtapiExtScsiPassThruFunction (
951 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
952 IN UINT8 *Target,
953 IN UINT64 Lun,
954 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
955 IN EFI_EVENT Event OPTIONAL
956 )
957/*++
958
959Routine Description:
960
961 Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
962
963Arguments:
964
965 This: The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
966 Target: The Target ID of the ATAPI device to send the SCSI
967 Request Packet. To ATAPI devices attached on an IDE
968 Channel, Target ID 0 indicates Master device;Target
969 ID 1 indicates Slave device.
970 Lun: The LUN of the ATAPI device to send the SCSI Request
971 Packet. To the ATAPI device, Lun is always 0.
972 Packet: The SCSI Request Packet to send to the ATAPI device
973 specified by Target and Lun.
974 Event: If non-blocking I/O is not supported then Event is ignored,
975 and blocking I/O is performed.
976 If Event is NULL, then blocking I/O is performed.
977 If Event is not NULL and non blocking I/O is supported,
978 then non-blocking I/O is performed, and Event will be signaled
979 when the SCSI Request Packet completes.
980
981Returns:
982
983 EFI_STATUS
984
985--*/
986{
987 EFI_STATUS Status;
988 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
989 UINT8 TargetId;
990
991 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
992
993 //
994 // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.
995 //
996 TargetId = Target[0];
997
998 //
999 // Target is not allowed beyond MAX_TARGET_ID
1000 //
1001 if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {
1002 return EFI_INVALID_PARAMETER;
1003 }
1004
1005 //
1006 // check the data fields in Packet parameter.
1007 //
1008 Status = CheckExtSCSIRequestPacket (Packet);
1009 if (EFI_ERROR (Status)) {
1010 return Status;
1011 }
1012
1013 //
1014 // If Request Packet targets at the IDE channel itself,
1015 // do nothing.
1016 //
1017 if (TargetId == (UINT8)This->Mode->AdapterId) {
1018 Packet->InTransferLength = Packet->OutTransferLength = 0;
1019 return EFI_SUCCESS;
1020 }
1021
1022 //
1023 // According to Target ID, reset the Atapi I/O Register mapping
1024 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1025 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1026 //
1027 if ((TargetId / 2) == 0) {
1028 TargetId = (UINT8) (TargetId % 2);
1029 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
1030 } else {
1031 TargetId = (UINT8) (TargetId % 2);
1032 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
1033 }
1034
1035 //
1036 // the ATAPI SCSI interface does not support non-blocking I/O
1037 // ignore the Event parameter
1038 //
1039 // Performs blocking I/O.
1040 //
1041 Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);
1042 return Status;
1043}
1044
1045EFI_STATUS
1046EFIAPI
1047AtapiExtScsiPassThruGetNextTargetLun (
1048 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1049 IN OUT UINT8 **Target,
1050 IN OUT UINT64 *Lun
1051 )
1052/*++
1053
1054Routine Description:
1055
1056 Used to retrieve the list of legal Target IDs for SCSI devices
1057 on a SCSI channel.
1058
1059Arguments:
1060
1061 This - Protocol instance pointer.
1062 Target - On input, a pointer to the Target ID of a SCSI
1063 device present on the SCSI channel. On output,
1064 a pointer to the Target ID of the next SCSI device
1065 present on a SCSI channel. An input value of
1066 0xFFFFFFFF retrieves the Target ID of the first
1067 SCSI device present on a SCSI channel.
1068 Lun - On input, a pointer to the LUN of a SCSI device
1069 present on the SCSI channel. On output, a pointer
1070 to the LUN of the next SCSI device present on
1071 a SCSI channel.
1072Returns:
1073
1074 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1075 on the SCSI channel was returned in Target and Lun.
1076 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1077 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1078 returned on a previous call to GetNextDevice().
1079--*/
1080{
1081 UINT8 ByteIndex;
1082 UINT8 TargetId;
1083 UINT8 ScsiId[TARGET_MAX_BYTES];
1084 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1085
1086 //
1087 // Retrieve Device Private Data Structure.
1088 //
1089 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1090
1091 //
1092 // Check whether Target is valid.
1093 //
1094 if (*Target == NULL || Lun == NULL) {
1095 return EFI_INVALID_PARAMETER;
1096 }
1097
1098 SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
1099
1100 TargetId = (*Target)[0];
1101
1102 //
1103 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1104 //
1105 if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {
1106 for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {
1107 if ((*Target)[ByteIndex] != 0) {
1108 return EFI_INVALID_PARAMETER;
1109 }
1110 }
1111 }
1112
1113 if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&
1114 ((TargetId != AtapiScsiPrivate->LatestTargetId) ||
1115 (*Lun != AtapiScsiPrivate->LatestLun))) {
1116 return EFI_INVALID_PARAMETER;
1117 }
1118
1119 if (TargetId == MAX_TARGET_ID) {
1120 return EFI_NOT_FOUND;
1121 }
1122
1123 if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {
1124 SetMem (*Target, TARGET_MAX_BYTES,0);
1125 } else {
1126 (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);
1127 }
1128
1129 *Lun = 0;
1130
1131 //
1132 // Update the LatestTargetId.
1133 //
1134 AtapiScsiPrivate->LatestTargetId = (*Target)[0];
1135 AtapiScsiPrivate->LatestLun = *Lun;
1136
1137 return EFI_SUCCESS;
1138
1139}
1140
1141EFI_STATUS
1142EFIAPI
1143AtapiExtScsiPassThruBuildDevicePath (
1144 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1145 IN UINT8 *Target,
1146 IN UINT64 Lun,
1147 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
1148 )
1149/*++
1150
1151Routine Description:
1152
1153 Used to allocate and build a device path node for a SCSI device
1154 on a SCSI channel. Would not build device path for a SCSI Host Controller.
1155
1156Arguments:
1157
1158 This - Protocol instance pointer.
1159 Target - The Target ID of the SCSI device for which
1160 a device path node is to be allocated and built.
1161 Lun - The LUN of the SCSI device for which a device
1162 path node is to be allocated and built.
1163 DevicePath - A pointer to a single device path node that
1164 describes the SCSI device specified by
1165 Target and Lun. This function is responsible
1166 for allocating the buffer DevicePath with the boot
1167 service AllocatePool(). It is the caller's
1168 responsibility to free DevicePath when the caller
1169 is finished with DevicePath.
1170 Returns:
1171 EFI_SUCCESS - The device path node that describes the SCSI device
1172 specified by Target and Lun was allocated and
1173 returned in DevicePath.
1174 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
1175 not exist on the SCSI channel.
1176 EFI_INVALID_PARAMETER - DevicePath is NULL.
1177 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
1178 DevicePath.
1179--*/
1180{
1181 EFI_DEV_PATH *Node;
1182 UINT8 TargetId;
1183
1184 TargetId = Target[0];
1185
1186 //
1187 // Validate parameters passed in.
1188 //
1189
1190 if (DevicePath == NULL) {
1191 return EFI_INVALID_PARAMETER;
1192 }
1193
1194 //
1195 // can not build device path for the SCSI Host Controller.
1196 //
1197 if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
1198 return EFI_NOT_FOUND;
1199 }
1200
1201 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
1202 if (Node == NULL) {
1203 return EFI_OUT_OF_RESOURCES;
1204 }
1205
1206 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
1207 Node->DevPath.SubType = MSG_ATAPI_DP;
1208 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
1209
1210 Node->Atapi.PrimarySecondary = (UINT8) (TargetId / 2);
1211 Node->Atapi.SlaveMaster = (UINT8) (TargetId % 2);
1212 Node->Atapi.Lun = (UINT16) Lun;
1213
1214 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
1215
1216 return EFI_SUCCESS;
1217}
1218
1219EFI_STATUS
1220EFIAPI
1221AtapiExtScsiPassThruGetTargetLun (
1222 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1223 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1224 OUT UINT8 **Target,
1225 OUT UINT64 *Lun
1226 )
1227/*++
1228
1229Routine Description:
1230
1231 Used to translate a device path node to a Target ID and LUN.
1232
1233Arguments:
1234
1235 This - Protocol instance pointer.
1236 DevicePath - A pointer to the device path node that
1237 describes a SCSI device on the SCSI channel.
1238 Target - A pointer to the Target ID of a SCSI device
1239 on the SCSI channel.
1240 Lun - A pointer to the LUN of a SCSI device on
1241 the SCSI channel.
1242Returns:
1243
1244 EFI_SUCCESS - DevicePath was successfully translated to a
1245 Target ID and LUN, and they were returned
1246 in Target and Lun.
1247 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
1248 EFI_UNSUPPORTED - This driver does not support the device path
1249 node type in DevicePath.
1250 EFI_NOT_FOUND - A valid translation from DevicePath to a
1251 Target ID and LUN does not exist.
1252--*/
1253{
1254 EFI_DEV_PATH *Node;
1255
1256 //
1257 // Validate parameters passed in.
1258 //
1259 if (DevicePath == NULL || Target == NULL || Lun == NULL) {
1260 return EFI_INVALID_PARAMETER;
1261 }
1262
1263 //
1264 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
1265 //
1266 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
1267 (DevicePath->SubType != MSG_ATAPI_DP) ||
1268 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
1269 return EFI_UNSUPPORTED;
1270 }
1271
1272 ZeroMem (*Target, TARGET_MAX_BYTES);
1273
1274 Node = (EFI_DEV_PATH *) DevicePath;
1275
1276 (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);
1277 *Lun = Node->Atapi.Lun;
1278
1279 if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {
1280 return EFI_NOT_FOUND;
1281 }
1282
1283 return EFI_SUCCESS;
1284}
1285
1286EFI_STATUS
1287EFIAPI
1288AtapiExtScsiPassThruResetChannel (
1289 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
1290 )
1291/*++
1292
1293Routine Description:
1294
1295 Resets a SCSI channel.This operation resets all the
1296 SCSI devices connected to the SCSI channel.
1297
1298Arguments:
1299
1300 This - Protocol instance pointer.
1301
1302Returns:
1303
1304 EFI_SUCCESS - The SCSI channel was reset.
1305 EFI_UNSUPPORTED - The SCSI channel does not support
1306 a channel reset operation.
1307 EFI_DEVICE_ERROR - A device error occurred while
1308 attempting to reset the SCSI channel.
1309 EFI_TIMEOUT - A timeout occurred while attempting
1310 to reset the SCSI channel.
1311--*/
1312{
1313 UINT8 DeviceControlValue;
1314 UINT8 Index;
1315 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1316 BOOLEAN ResetFlag;
1317
1318 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1319 ResetFlag = FALSE;
1320 //
1321 // Reset both Primary channel and Secondary channel.
1322 // so, the IoPort pointer must point to the right I/O Register group
1323 // And if there is a channel reset successfully, return EFI_SUCCESS.
1324 //
1325 for (Index = 0; Index < 2; Index++) {
1326 //
1327 // Reset
1328 //
1329 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
1330
1331 DeviceControlValue = 0;
1332 //
1333 // set SRST bit to initiate soft reset
1334 //
1335 DeviceControlValue |= SRST;
1336 //
1337 // disable Interrupt
1338 //
1339 DeviceControlValue |= BIT1;
1340 WritePortB (
1341 AtapiScsiPrivate->PciIo,
1342 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
1343 DeviceControlValue
1344 );
1345
1346 //
1347 // Wait 10us
1348 //
1349 gBS->Stall (10);
1350
1351 //
1352 // Clear SRST bit
1353 // 0xfb:1111,1011
1354 //
1355 DeviceControlValue &= 0xfb;
1356
1357 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
1358
1359 //
1360 // slave device needs at most 31s to clear BSY
1361 //
1362 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
1363 ResetFlag = TRUE;
1364 }
1365 }
1366
1367 if (ResetFlag) {
1368 return EFI_SUCCESS;
1369 }
1370
1371 return EFI_TIMEOUT;
1372}
1373
1374EFI_STATUS
1375EFIAPI
1376AtapiExtScsiPassThruResetTarget (
1377 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1378 IN UINT8 *Target,
1379 IN UINT64 Lun
1380 )
1381/*++
1382
1383Routine Description:
1384
1385 Resets a SCSI device that is connected to a SCSI channel.
1386
1387Arguments:
1388
1389 This - Protocol instance pointer.
1390 Target - The Target ID of the SCSI device to reset.
1391 Lun - The LUN of the SCSI device to reset.
1392
1393Returns:
1394
1395 EFI_SUCCESS - The SCSI device specified by Target and
1396 Lun was reset.
1397 EFI_UNSUPPORTED - The SCSI channel does not support a target
1398 reset operation.
1399 EFI_INVALID_PARAMETER - Target or Lun are invalid.
1400 EFI_DEVICE_ERROR - A device error occurred while attempting
1401 to reset the SCSI device specified by Target
1402 and Lun.
1403 EFI_TIMEOUT - A timeout occurred while attempting to reset
1404 the SCSI device specified by Target and Lun.
1405--*/
1406{
1407 UINT8 Command;
1408 UINT8 DeviceSelect;
1409 UINT8 TargetId;
1410 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1411
1412 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1413 TargetId = Target[0];
1414
1415 if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {
1416 return EFI_INVALID_PARAMETER;
1417 }
1418 //
1419 // Directly return EFI_SUCCESS if want to reset the host controller
1420 //
1421 if (TargetId == This->Mode->AdapterId) {
1422 return EFI_SUCCESS;
1423 }
1424
1425 //
1426 // According to Target ID, reset the Atapi I/O Register mapping
1427 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1428 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1429 //
1430 if ((TargetId / 2) == 0) {
1431 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
1432 } else {
1433 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
1434 }
1435
1436 //
1437 // for ATAPI device, no need to wait DRDY ready after device selecting.
1438 //
1439 // bit7 and bit5 are both set to 1 for backward compatibility
1440 //
1441 DeviceSelect = (UINT8) ((BIT7 | BIT5) | (TargetId << 4));
1442 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
1443
1444 Command = ATAPI_SOFT_RESET_CMD;
1445 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
1446
1447 //
1448 // BSY clear is the only status return to the host by the device
1449 // when reset is complete.
1450 // slave device needs at most 31s to clear BSY
1451 //
1452 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
1453 return EFI_TIMEOUT;
1454 }
1455
1456 //
1457 // stall 5 seconds to make the device status stable
1458 //
1459 gBS->Stall (5000000);
1460
1461 return EFI_SUCCESS;
1462}
1463
1464
1465EFI_STATUS
1466EFIAPI
1467AtapiExtScsiPassThruGetNextTarget (
1468 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1469 IN OUT UINT8 **Target
1470 )
1471/*++
1472
1473Routine Description:
1474 Used to retrieve the list of legal Target IDs for SCSI devices
1475 on a SCSI channel.
1476
1477Arguments:
1478 This - Protocol instance pointer.
1479 Target - On input, a pointer to the Target ID of a SCSI
1480 device present on the SCSI channel. On output,
1481 a pointer to the Target ID of the next SCSI device
1482 present on a SCSI channel. An input value of
1483 0xFFFFFFFF retrieves the Target ID of the first
1484 SCSI device present on a SCSI channel.
1485 Lun - On input, a pointer to the LUN of a SCSI device
1486 present on the SCSI channel. On output, a pointer
1487 to the LUN of the next SCSI device present on
1488 a SCSI channel.
1489
1490Returns:
1491 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1492 on the SCSI channel was returned in Target and Lun.
1493 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1494 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1495 returned on a previous call to GetNextDevice().
1496--*/
1497{
1498 UINT8 TargetId;
1499 UINT8 ScsiId[TARGET_MAX_BYTES];
1500 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1501 UINT8 ByteIndex;
1502
1503 //
1504 // Retrieve Device Private Data Structure.
1505 //
1506 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1507
1508 //
1509 // Check whether Target is valid.
1510 //
1511 if (*Target == NULL ) {
1512 return EFI_INVALID_PARAMETER;
1513 }
1514
1515 TargetId = (*Target)[0];
1516 SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
1517
1518 //
1519 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1520 //
1521 if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {
1522 for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {
1523 if ((*Target)[ByteIndex] != 0) {
1524 return EFI_INVALID_PARAMETER;
1525 }
1526 }
1527 }
1528
1529 if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {
1530 return EFI_INVALID_PARAMETER;
1531 }
1532
1533 if (TargetId == MAX_TARGET_ID) {
1534 return EFI_NOT_FOUND;
1535 }
1536
1537 if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {
1538 SetMem (*Target, TARGET_MAX_BYTES, 0);
1539 } else {
1540 (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);
1541 }
1542
1543 //
1544 // Update the LatestTargetId.
1545 //
1546 AtapiScsiPrivate->LatestTargetId = (*Target)[0];
1547 AtapiScsiPrivate->LatestLun = 0;
1548
1549 return EFI_SUCCESS;
1550}
1551
1552EFI_STATUS
1553GetIdeRegistersBaseAddr (
1554 IN EFI_PCI_IO_PROTOCOL *PciIo,
1555 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
1556 )
1557/*++
1558
1559Routine Description:
1560 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
1561 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
1562 the PCI IDE controller's Configuration Space.
1563
1564Arguments:
1565 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
1566 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
1567 receive IDE IO port registers' base addresses
1568
1569Returns:
1570
1571 EFI_STATUS
1572
1573--*/
1574{
1575 EFI_STATUS Status;
1576 PCI_TYPE00 PciData;
1577
1578 Status = PciIo->Pci.Read (
1579 PciIo,
1580 EfiPciIoWidthUint8,
1581 0,
1582 sizeof (PciData),
1583 &PciData
1584 );
1585
1586 if (EFI_ERROR (Status)) {
1587 return Status;
1588 }
1589
1590 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
1591 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;
1592 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;
1593 } else {
1594 //
1595 // The BARs should be of IO type
1596 //
1597 if ((PciData.Device.Bar[0] & BIT0) == 0 ||
1598 (PciData.Device.Bar[1] & BIT0) == 0) {
1599 return EFI_UNSUPPORTED;
1600 }
1601
1602 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =
1603 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
1604 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =
1605 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
1606 }
1607
1608 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
1609 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;
1610 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;
1611 } else {
1612 //
1613 // The BARs should be of IO type
1614 //
1615 if ((PciData.Device.Bar[2] & BIT0) == 0 ||
1616 (PciData.Device.Bar[3] & BIT0) == 0) {
1617 return EFI_UNSUPPORTED;
1618 }
1619
1620 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =
1621 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
1622 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =
1623 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
1624 }
1625
1626 return EFI_SUCCESS;
1627}
1628
1629VOID
1630InitAtapiIoPortRegisters (
1631 IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1632 IN IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
1633 )
1634/*++
1635
1636Routine Description:
1637
1638 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
1639
1640Arguments:
1641
1642 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1643 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
1644
1645Returns:
1646
1647 None
1648
1649--*/
1650{
1651
1652 UINT8 IdeChannel;
1653 UINT16 CommandBlockBaseAddr;
1654 UINT16 ControlBlockBaseAddr;
1655 IDE_BASE_REGISTERS *RegisterPointer;
1656
1657
1658 for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {
1659
1660 RegisterPointer = &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];
1661
1662 //
1663 // Initialize IDE IO port addresses, including Command Block registers
1664 // and Control Block registers
1665 //
1666 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
1667 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
1668
1669 RegisterPointer->Data = CommandBlockBaseAddr;
1670 (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
1671 RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
1672 RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
1673 RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
1674 RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
1675 RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
1676 (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
1677
1678 (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;
1679 RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
1680 }
1681
1682}
1683
1684
1685EFI_STATUS
1686CheckSCSIRequestPacket (
1687 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1688 )
1689/*++
1690
1691Routine Description:
1692
1693 Checks the parameters in the SCSI Request Packet to make sure
1694 they are valid for a SCSI Pass Thru request.
1695
1696Arguments:
1697
1698 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1699
1700Returns:
1701
1702 EFI_STATUS
1703
1704--*/
1705{
1706 if (Packet == NULL) {
1707 return EFI_INVALID_PARAMETER;
1708 }
1709
1710 if (!ValidCdbLength (Packet->CdbLength)) {
1711 return EFI_INVALID_PARAMETER;
1712 }
1713
1714 if (Packet->Cdb == NULL) {
1715 return EFI_INVALID_PARAMETER;
1716 }
1717
1718 //
1719 // Checks whether the request command is supported.
1720 //
1721 if (!IsCommandValid (Packet)) {
1722 return EFI_UNSUPPORTED;
1723 }
1724
1725 return EFI_SUCCESS;
1726}
1727
1728BOOLEAN
1729IsCommandValid (
1730 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1731 )
1732/*++
1733
1734Routine Description:
1735
1736 Checks the requested SCSI command:
1737 Is it supported by this driver?
1738 Is the Data transfer direction reasonable?
1739
1740Arguments:
1741
1742 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1743
1744Returns:
1745
1746 EFI_STATUS
1747
1748--*/
1749{
1750 UINT8 Index;
1751 UINT8 *OpCode;
1752 UINT8 ArrayLen;
1753
1754 OpCode = (UINT8 *) (Packet->Cdb);
1755 ArrayLen = (UINT8) (sizeof (gSupportedATAPICommands) / sizeof (gSupportedATAPICommands[0]));
1756
1757 for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {
1758
1759 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
1760 //
1761 // Check whether the requested Command is supported by this driver
1762 //
1763 if (Packet->DataDirection == DataIn) {
1764 //
1765 // Check whether the requested data direction conforms to
1766 // what it should be.
1767 //
1768 if (gSupportedATAPICommands[Index].Direction == DataOut) {
1769 return FALSE;
1770 }
1771 }
1772
1773 if (Packet->DataDirection == DataOut) {
1774 //
1775 // Check whether the requested data direction conforms to
1776 // what it should be.
1777 //
1778 if (gSupportedATAPICommands[Index].Direction == DataIn) {
1779 return FALSE;
1780 }
1781 }
1782
1783 return TRUE;
1784 }
1785 }
1786
1787 return FALSE;
1788}
1789
1790EFI_STATUS
1791SubmitBlockingIoCommand (
1792 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1793 UINT32 Target,
1794 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1795 )
1796/*++
1797
1798Routine Description:
1799
1800 Performs blocking I/O request.
1801
1802Arguments:
1803
1804 AtapiScsiPrivate: Private data structure for the specified channel.
1805 Target: The Target ID of the ATAPI device to send the SCSI
1806 Request Packet. To ATAPI devices attached on an IDE
1807 Channel, Target ID 0 indicates Master device;Target
1808 ID 1 indicates Slave device.
1809 Packet: The SCSI Request Packet to send to the ATAPI device
1810 specified by Target.
1811
1812 Returns: EFI_STATUS
1813
1814--*/
1815{
1816 UINT8 PacketCommand[12];
1817 UINT64 TimeoutInMicroSeconds;
1818 EFI_STATUS PacketCommandStatus;
1819
1820 //
1821 // Fill ATAPI Command Packet according to CDB
1822 //
1823 ZeroMem (&PacketCommand, 12);
1824 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
1825
1826 //
1827 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1828 //
1829 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
1830
1831 //
1832 // Submit ATAPI Command Packet
1833 //
1834 PacketCommandStatus = AtapiPacketCommand (
1835 AtapiScsiPrivate,
1836 Target,
1837 PacketCommand,
1838 Packet->DataBuffer,
1839 &(Packet->TransferLength),
1840 (DATA_DIRECTION) Packet->DataDirection,
1841 TimeoutInMicroSeconds
1842 );
1843 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
1844 Packet->SenseDataLength = 0;
1845 return PacketCommandStatus;
1846 }
1847
1848 //
1849 // Return SenseData if PacketCommandStatus matches
1850 // the following return codes.
1851 //
1852 if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
1853 (PacketCommandStatus == EFI_DEVICE_ERROR) ||
1854 (PacketCommandStatus == EFI_TIMEOUT)) {
1855
1856 //
1857 // avoid submit request sense command continuously.
1858 //
1859 if (PacketCommand[0] == OP_REQUEST_SENSE) {
1860 Packet->SenseDataLength = 0;
1861 return PacketCommandStatus;
1862 }
1863
1864 RequestSenseCommand (
1865 AtapiScsiPrivate,
1866 Target,
1867 Packet->Timeout,
1868 Packet->SenseData,
1869 &Packet->SenseDataLength
1870 );
1871 }
1872
1873 return PacketCommandStatus;
1874}
1875
1876EFI_STATUS
1877RequestSenseCommand (
1878 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1879 UINT32 Target,
1880 UINT64 Timeout,
1881 VOID *SenseData,
1882 UINT8 *SenseDataLength
1883 )
1884/*++
1885
1886Routine Description:
1887
1888 Sumbit request sense command
1889
1890Arguments:
1891
1892 AtapiScsiPrivate - The pionter of ATAPI_SCSI_PASS_THRU_DEV
1893 Target - The target ID
1894 Timeout - The time to complete the command
1895 SenseData - The buffer to fill in sense data
1896 SenseDataLength - The length of buffer
1897
1898Returns:
1899
1900 EFI_STATUS
1901
1902--*/
1903{
1904 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
1905 UINT8 Cdb[12];
1906 EFI_STATUS Status;
1907
1908 ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1909 ZeroMem (Cdb, 12);
1910
1911 Cdb[0] = OP_REQUEST_SENSE;
1912 Cdb[4] = (UINT8) (*SenseDataLength);
1913
1914 Packet.Timeout = Timeout;
1915 Packet.DataBuffer = SenseData;
1916 Packet.SenseData = NULL;
1917 Packet.Cdb = Cdb;
1918 Packet.TransferLength = *SenseDataLength;
1919 Packet.CdbLength = 12;
1920 Packet.DataDirection = DataIn;
1921
1922 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);
1923 *SenseDataLength = (UINT8) (Packet.TransferLength);
1924 return Status;
1925}
1926
1927EFI_STATUS
1928CheckExtSCSIRequestPacket (
1929 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1930 )
1931/*++
1932
1933Routine Description:
1934
1935 Checks the parameters in the SCSI Request Packet to make sure
1936 they are valid for a SCSI Pass Thru request.
1937
1938Arguments:
1939
1940 Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1941
1942Returns:
1943
1944 EFI_STATUS
1945
1946--*/
1947{
1948 if (Packet == NULL) {
1949 return EFI_INVALID_PARAMETER;
1950 }
1951
1952 if (!ValidCdbLength (Packet->CdbLength)) {
1953 return EFI_INVALID_PARAMETER;
1954 }
1955
1956 if (Packet->Cdb == NULL) {
1957 return EFI_INVALID_PARAMETER;
1958 }
1959
1960 //
1961 // Checks whether the request command is supported.
1962 //
1963 if (!IsExtCommandValid (Packet)) {
1964 return EFI_UNSUPPORTED;
1965 }
1966
1967 return EFI_SUCCESS;
1968}
1969
1970
1971BOOLEAN
1972IsExtCommandValid (
1973 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1974 )
1975/*++
1976
1977Routine Description:
1978
1979 Checks the requested SCSI command:
1980 Is it supported by this driver?
1981 Is the Data transfer direction reasonable?
1982
1983Arguments:
1984
1985 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1986
1987Returns:
1988
1989 EFI_STATUS
1990
1991--*/
1992{
1993 UINT8 Index;
1994 UINT8 *OpCode;
1995 UINT8 ArrayLen;
1996
1997 OpCode = (UINT8 *) (Packet->Cdb);
1998 ArrayLen = (UINT8) (sizeof (gSupportedATAPICommands) / sizeof (gSupportedATAPICommands[0]));
1999
2000 for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {
2001
2002 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
2003 //
2004 // Check whether the requested Command is supported by this driver
2005 //
2006 if (Packet->DataDirection == DataIn) {
2007 //
2008 // Check whether the requested data direction conforms to
2009 // what it should be.
2010 //
2011 if (gSupportedATAPICommands[Index].Direction == DataOut) {
2012 return FALSE;
2013 }
2014 }
2015
2016 if (Packet->DataDirection == DataOut) {
2017 //
2018 // Check whether the requested data direction conforms to
2019 // what it should be.
2020 //
2021 if (gSupportedATAPICommands[Index].Direction == DataIn) {
2022 return FALSE;
2023 }
2024 }
2025
2026 return TRUE;
2027 }
2028 }
2029
2030 return FALSE;
2031}
2032
2033EFI_STATUS
2034SubmitExtBlockingIoCommand (
2035 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2036 UINT8 Target,
2037 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
2038 )
2039/*++
2040
2041Routine Description:
2042
2043 Performs blocking I/O request.
2044
2045Arguments:
2046
2047 AtapiScsiPrivate: Private data structure for the specified channel.
2048 Target: The Target ID of the ATAPI device to send the SCSI
2049 Request Packet. To ATAPI devices attached on an IDE
2050 Channel, Target ID 0 indicates Master device;Target
2051 ID 1 indicates Slave device.
2052 Packet: The SCSI Request Packet to send to the ATAPI device
2053 specified by Target.
2054
2055 Returns: EFI_STATUS
2056
2057--*/
2058{
2059 UINT8 PacketCommand[12];
2060 UINT64 TimeoutInMicroSeconds;
2061 EFI_STATUS PacketCommandStatus;
2062
2063 //
2064 // Fill ATAPI Command Packet according to CDB
2065 //
2066 ZeroMem (&PacketCommand, 12);
2067 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
2068
2069 //
2070 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
2071 //
2072 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
2073
2074 //
2075 // Submit ATAPI Command Packet
2076 //
2077 if (Packet->DataDirection == DataIn) {
2078 PacketCommandStatus = AtapiPacketCommand (
2079 AtapiScsiPrivate,
2080 Target,
2081 PacketCommand,
2082 Packet->InDataBuffer,
2083 &(Packet->InTransferLength),
2084 DataIn,
2085 TimeoutInMicroSeconds
2086 );
2087 } else {
2088
2089 PacketCommandStatus = AtapiPacketCommand (
2090 AtapiScsiPrivate,
2091 Target,
2092 PacketCommand,
2093 Packet->OutDataBuffer,
2094 &(Packet->OutTransferLength),
2095 DataOut,
2096 TimeoutInMicroSeconds
2097 );
2098 }
2099
2100 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
2101 Packet->SenseDataLength = 0;
2102 return PacketCommandStatus;
2103 }
2104
2105 //
2106 // Return SenseData if PacketCommandStatus matches
2107 // the following return codes.
2108 //
2109 if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
2110 (PacketCommandStatus == EFI_DEVICE_ERROR) ||
2111 (PacketCommandStatus == EFI_TIMEOUT)) {
2112
2113 //
2114 // avoid submit request sense command continuously.
2115 //
2116 if (PacketCommand[0] == OP_REQUEST_SENSE) {
2117 Packet->SenseDataLength = 0;
2118 return PacketCommandStatus;
2119 }
2120
2121 RequestSenseCommand (
2122 AtapiScsiPrivate,
2123 Target,
2124 Packet->Timeout,
2125 Packet->SenseData,
2126 &Packet->SenseDataLength
2127 );
2128 }
2129
2130 return PacketCommandStatus;
2131}
2132
2133
2134EFI_STATUS
2135AtapiPacketCommand (
2136 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2137 UINT32 Target,
2138 UINT8 *PacketCommand,
2139 VOID *Buffer,
2140 UINT32 *ByteCount,
2141 DATA_DIRECTION Direction,
2142 UINT64 TimeoutInMicroSeconds
2143 )
2144/*++
2145
2146Routine Description:
2147
2148 Submits ATAPI command packet to the specified ATAPI device.
2149
2150Arguments:
2151
2152 AtapiScsiPrivate: Private data structure for the specified channel.
2153 Target: The Target ID of the ATAPI device to send the SCSI
2154 Request Packet. To ATAPI devices attached on an IDE
2155 Channel, Target ID 0 indicates Master device;Target
2156 ID 1 indicates Slave device.
2157 PacketCommand: Points to the ATAPI command packet.
2158 Buffer: Points to the transferred data.
2159 ByteCount: When input,indicates the buffer size; when output,
2160 indicates the actually transferred data size.
2161 Direction: Indicates the data transfer direction.
2162 TimeoutInMicroSeconds:
2163 The timeout, in micro second units, to use for the
2164 execution of this ATAPI command.
2165 A TimeoutInMicroSeconds value of 0 means that
2166 this function will wait indefinitely for the ATAPI
2167 command to execute.
2168 If TimeoutInMicroSeconds is greater than zero, then
2169 this function will return EFI_TIMEOUT if the time
2170 required to execute the ATAPI command is greater
2171 than TimeoutInMicroSeconds.
2172
2173Returns:
2174
2175 EFI_STATUS
2176
2177--*/
2178{
2179
2180 UINT16 *CommandIndex;
2181 UINT8 Count;
2182 EFI_STATUS Status;
2183
2184 //
2185 // Set all the command parameters by fill related registers.
2186 // Before write to all the following registers, BSY must be 0.
2187 //
2188 Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
2189 if (EFI_ERROR (Status)) {
2190 return EFI_DEVICE_ERROR;
2191 }
2192
2193
2194 //
2195 // Select device via Device/Head Register.
2196 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
2197 //
2198 WritePortB (
2199 AtapiScsiPrivate->PciIo,
2200 AtapiScsiPrivate->IoPort->Head,
2201 (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
2202 );
2203
2204 //
2205 // Set all the command parameters by fill related registers.
2206 // Before write to all the following registers, BSY DRQ must be 0.
2207 //
2208 Status = StatusDRQClear(AtapiScsiPrivate, TimeoutInMicroSeconds);
2209
2210 if (EFI_ERROR (Status)) {
2211 if (Status == EFI_ABORTED) {
2212 Status = EFI_DEVICE_ERROR;
2213 }
2214 *ByteCount = 0;
2215 return Status;
2216 }
2217
2218 //
2219 // No OVL; No DMA (by setting feature register)
2220 //
2221 WritePortB (
2222 AtapiScsiPrivate->PciIo,
2223 AtapiScsiPrivate->IoPort->Reg1.Feature,
2224 0x00
2225 );
2226
2227 //
2228 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
2229 // determine how much data should be transfered.
2230 //
2231 WritePortB (
2232 AtapiScsiPrivate->PciIo,
2233 AtapiScsiPrivate->IoPort->CylinderLsb,
2234 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
2235 );
2236 WritePortB (
2237 AtapiScsiPrivate->PciIo,
2238 AtapiScsiPrivate->IoPort->CylinderMsb,
2239 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
2240 );
2241
2242 //
2243 // DEFAULT_CTL:0x0a (0000,1010)
2244 // Disable interrupt
2245 //
2246 WritePortB (
2247 AtapiScsiPrivate->PciIo,
2248 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
2249 DEFAULT_CTL
2250 );
2251
2252 //
2253 // Send Packet command to inform device
2254 // that the following data bytes are command packet.
2255 //
2256 WritePortB (
2257 AtapiScsiPrivate->PciIo,
2258 AtapiScsiPrivate->IoPort->Reg.Command,
2259 PACKET_CMD
2260 );
2261
2262 //
2263 // Before data transfer, BSY should be 0 and DRQ should be 1.
2264 // if they are not in specified time frame,
2265 // retrieve Sense Key from Error Register before return.
2266 //
2267 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
2268 if (EFI_ERROR (Status)) {
2269 if (Status == EFI_ABORTED) {
2270 Status = EFI_DEVICE_ERROR;
2271 }
2272
2273 *ByteCount = 0;
2274 return Status;
2275 }
2276
2277 //
2278 // Send out command packet
2279 //
2280 CommandIndex = (UINT16 *) PacketCommand;
2281 for (Count = 0; Count < 6; Count++, CommandIndex++) {
2282 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);
2283 }
2284
2285 //
2286 // call AtapiPassThruPioReadWriteData() function to get
2287 // requested transfer data form device.
2288 //
2289 return AtapiPassThruPioReadWriteData (
2290 AtapiScsiPrivate,
2291 Buffer,
2292 ByteCount,
2293 Direction,
2294 TimeoutInMicroSeconds
2295 );
2296}
2297
2298EFI_STATUS
2299AtapiPassThruPioReadWriteData (
2300 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2301 UINT16 *Buffer,
2302 UINT32 *ByteCount,
2303 DATA_DIRECTION Direction,
2304 UINT64 TimeoutInMicroSeconds
2305 )
2306/*++
2307
2308Routine Description:
2309
2310 Performs data transfer between ATAPI device and host after the
2311 ATAPI command packet is sent.
2312
2313Arguments:
2314
2315 AtapiScsiPrivate: Private data structure for the specified channel.
2316 Buffer: Points to the transferred data.
2317 ByteCount: When input,indicates the buffer size; when output,
2318 indicates the actually transferred data size.
2319 Direction: Indicates the data transfer direction.
2320 TimeoutInMicroSeconds:
2321 The timeout, in micro second units, to use for the
2322 execution of this ATAPI command.
2323 A TimeoutInMicroSeconds value of 0 means that
2324 this function will wait indefinitely for the ATAPI
2325 command to execute.
2326 If TimeoutInMicroSeconds is greater than zero, then
2327 this function will return EFI_TIMEOUT if the time
2328 required to execute the ATAPI command is greater
2329 than TimeoutInMicroSeconds.
2330 Returns:
2331
2332 EFI_STATUS
2333
2334--*/
2335{
2336 UINT32 Index;
2337 UINT32 RequiredWordCount;
2338 UINT32 ActualWordCount;
2339 UINT32 WordCount;
2340 EFI_STATUS Status;
2341 UINT16 *ptrBuffer;
2342
2343 Status = EFI_SUCCESS;
2344
2345 //
2346 // Non Data transfer request is also supported.
2347 //
2348 if (*ByteCount == 0 || Buffer == NULL) {
2349 *ByteCount = 0;
2350 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {
2351 return EFI_DEVICE_ERROR;
2352 }
2353 }
2354
2355 ptrBuffer = Buffer;
2356 RequiredWordCount = *ByteCount / 2;
2357
2358 //
2359 // ActuralWordCount means the word count of data really transfered.
2360 //
2361 ActualWordCount = 0;
2362
2363 while (ActualWordCount < RequiredWordCount) {
2364 //
2365 // before each data transfer stream, the host should poll DRQ bit ready,
2366 // which indicates device's ready for data transfer .
2367 //
2368 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
2369 if (EFI_ERROR (Status)) {
2370 *ByteCount = ActualWordCount * 2;
2371
2372 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
2373
2374 if (ActualWordCount == 0) {
2375 return EFI_DEVICE_ERROR;
2376 }
2377 //
2378 // ActualWordCount > 0
2379 //
2380 if (ActualWordCount < RequiredWordCount) {
2381 return EFI_BAD_BUFFER_SIZE;
2382 }
2383 }
2384 //
2385 // get current data transfer size from Cylinder Registers.
2386 //
2387 WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;
2388 WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);
2389 WordCount = WordCount & 0xffff;
2390 WordCount /= 2;
2391
2392 //
2393 // perform a series data In/Out.
2394 //
2395 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
2396
2397 if (Direction == DataIn) {
2398
2399 *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);
2400 } else {
2401
2402 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);
2403 }
2404
2405 ptrBuffer++;
2406
2407 }
2408 }
2409 //
2410 // After data transfer is completed, normally, DRQ bit should clear.
2411 //
2412 StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
2413
2414 //
2415 // read status register to check whether error happens.
2416 //
2417 Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
2418
2419 *ByteCount = ActualWordCount * 2;
2420
2421 return Status;
2422}
2423
2424
2425UINT8
2426ReadPortB (
2427 IN EFI_PCI_IO_PROTOCOL *PciIo,
2428 IN UINT16 Port
2429 )
2430/*++
2431
2432Routine Description:
2433
2434 Read one byte from a specified I/O port.
2435
2436Arguments:
2437
2438 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2439 Port - IO port
2440
2441Returns:
2442
2443 A byte read out
2444
2445--*/
2446{
2447 UINT8 Data;
2448
2449 Data = 0;
2450 PciIo->Io.Read (
2451 PciIo,
2452 EfiPciIoWidthUint8,
2453 EFI_PCI_IO_PASS_THROUGH_BAR,
2454 (UINT64) Port,
2455 1,
2456 &Data
2457 );
2458 return Data;
2459}
2460
2461
2462UINT16
2463ReadPortW (
2464 IN EFI_PCI_IO_PROTOCOL *PciIo,
2465 IN UINT16 Port
2466 )
2467/*++
2468
2469Routine Description:
2470
2471 Read one word from a specified I/O port.
2472
2473Arguments:
2474
2475 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2476 Port - IO port
2477
2478Returns:
2479
2480 A word read out
2481--*/
2482{
2483 UINT16 Data;
2484
2485 Data = 0;
2486 PciIo->Io.Read (
2487 PciIo,
2488 EfiPciIoWidthUint16,
2489 EFI_PCI_IO_PASS_THROUGH_BAR,
2490 (UINT64) Port,
2491 1,
2492 &Data
2493 );
2494 return Data;
2495}
2496
2497
2498VOID
2499WritePortB (
2500 IN EFI_PCI_IO_PROTOCOL *PciIo,
2501 IN UINT16 Port,
2502 IN UINT8 Data
2503 )
2504/*++
2505
2506Routine Description:
2507
2508 Write one byte to a specified I/O port.
2509
2510Arguments:
2511
2512 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2513 Port - IO port
2514 Data - The data to write
2515
2516Returns:
2517
2518 NONE
2519
2520--*/
2521{
2522 PciIo->Io.Write (
2523 PciIo,
2524 EfiPciIoWidthUint8,
2525 EFI_PCI_IO_PASS_THROUGH_BAR,
2526 (UINT64) Port,
2527 1,
2528 &Data
2529 );
2530}
2531
2532
2533VOID
2534WritePortW (
2535 IN EFI_PCI_IO_PROTOCOL *PciIo,
2536 IN UINT16 Port,
2537 IN UINT16 Data
2538 )
2539/*++
2540
2541Routine Description:
2542
2543 Write one word to a specified I/O port.
2544
2545Arguments:
2546
2547 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2548 Port - IO port
2549 Data - The data to write
2550
2551Returns:
2552
2553 NONE
2554
2555--*/
2556{
2557 PciIo->Io.Write (
2558 PciIo,
2559 EfiPciIoWidthUint16,
2560 EFI_PCI_IO_PASS_THROUGH_BAR,
2561 (UINT64) Port,
2562 1,
2563 &Data
2564 );
2565}
2566
2567EFI_STATUS
2568StatusDRQClear (
2569 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2570 UINT64 TimeoutInMicroSeconds
2571 )
2572/*++
2573
2574Routine Description:
2575
2576 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
2577 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2578 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2579 elapsed.
2580
2581Arguments:
2582
2583 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2584 TimeoutInMicroSeconds - The time to wait for
2585
2586Returns:
2587
2588 EFI_STATUS
2589
2590--*/
2591{
2592 UINT64 Delay;
2593 UINT8 StatusRegister;
2594 UINT8 ErrRegister;
2595
2596 if (TimeoutInMicroSeconds == 0) {
2597 Delay = 2;
2598 } else {
2599 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2600 }
2601
2602 do {
2603
2604 StatusRegister = ReadPortB (
2605 AtapiScsiPrivate->PciIo,
2606 AtapiScsiPrivate->IoPort->Reg.Status
2607 );
2608
2609 //
2610 // wait for BSY == 0 and DRQ == 0
2611 //
2612 if ((StatusRegister & (DRQ | BSY)) == 0) {
2613 break;
2614 }
2615 //
2616 // check whether the command is aborted by the device
2617 //
2618 if ((StatusRegister & (BSY | ERR)) == ERR) {
2619
2620 ErrRegister = ReadPortB (
2621 AtapiScsiPrivate->PciIo,
2622 AtapiScsiPrivate->IoPort->Reg1.Error
2623 );
2624 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2625
2626 return EFI_ABORTED;
2627 }
2628 }
2629 //
2630 // Stall for 30 us
2631 //
2632 gBS->Stall (30);
2633
2634 //
2635 // Loop infinitely if not meeting expected condition
2636 //
2637 if (TimeoutInMicroSeconds == 0) {
2638 Delay = 2;
2639 }
2640
2641 Delay--;
2642 } while (Delay);
2643
2644 if (Delay == 0) {
2645 return EFI_TIMEOUT;
2646 }
2647
2648 return EFI_SUCCESS;
2649}
2650
2651EFI_STATUS
2652AltStatusDRQClear (
2653 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2654 UINT64 TimeoutInMicroSeconds
2655 )
2656/*++
2657
2658Routine Description:
2659
2660 Check whether DRQ is clear in the Alternate Status Register.
2661 (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should
2662 wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2663 elapsed.
2664
2665Arguments:
2666
2667 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2668 TimeoutInMicroSeconds - The time to wait for
2669
2670Returns:
2671
2672 EFI_STATUS
2673
2674--*/
2675{
2676 UINT64 Delay;
2677 UINT8 AltStatusRegister;
2678 UINT8 ErrRegister;
2679
2680 if (TimeoutInMicroSeconds == 0) {
2681 Delay = 2;
2682 } else {
2683 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2684 }
2685
2686 do {
2687
2688 AltStatusRegister = ReadPortB (
2689 AtapiScsiPrivate->PciIo,
2690 AtapiScsiPrivate->IoPort->Alt.AltStatus
2691 );
2692
2693 //
2694 // wait for BSY == 0 and DRQ == 0
2695 //
2696 if ((AltStatusRegister & (DRQ | BSY)) == 0) {
2697 break;
2698 }
2699
2700 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
2701
2702 ErrRegister = ReadPortB (
2703 AtapiScsiPrivate->PciIo,
2704 AtapiScsiPrivate->IoPort->Reg1.Error
2705 );
2706 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2707
2708 return EFI_ABORTED;
2709 }
2710 }
2711 //
2712 // Stall for 30 us
2713 //
2714 gBS->Stall (30);
2715
2716 //
2717 // Loop infinitely if not meeting expected condition
2718 //
2719 if (TimeoutInMicroSeconds == 0) {
2720 Delay = 2;
2721 }
2722
2723 Delay--;
2724 } while (Delay);
2725
2726 if (Delay == 0) {
2727 return EFI_TIMEOUT;
2728 }
2729
2730 return EFI_SUCCESS;
2731}
2732
2733EFI_STATUS
2734StatusDRQReady (
2735 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2736 UINT64 TimeoutInMicroSeconds
2737 )
2738/*++
2739
2740Routine Description:
2741
2742 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
2743 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2744 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2745 elapsed.
2746
2747Arguments:
2748
2749 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2750 TimeoutInMicroSeconds - The time to wait for
2751
2752Returns:
2753
2754 EFI_STATUS
2755
2756--*/
2757{
2758 UINT64 Delay;
2759 UINT8 StatusRegister;
2760 UINT8 ErrRegister;
2761
2762 if (TimeoutInMicroSeconds == 0) {
2763 Delay = 2;
2764 } else {
2765 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2766 }
2767
2768 do {
2769 //
2770 // read Status Register will clear interrupt
2771 //
2772 StatusRegister = ReadPortB (
2773 AtapiScsiPrivate->PciIo,
2774 AtapiScsiPrivate->IoPort->Reg.Status
2775 );
2776
2777 //
2778 // BSY==0,DRQ==1
2779 //
2780 if ((StatusRegister & (BSY | DRQ)) == DRQ) {
2781 break;
2782 }
2783
2784 if ((StatusRegister & (BSY | ERR)) == ERR) {
2785
2786 ErrRegister = ReadPortB (
2787 AtapiScsiPrivate->PciIo,
2788 AtapiScsiPrivate->IoPort->Reg1.Error
2789 );
2790 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2791 return EFI_ABORTED;
2792 }
2793 }
2794
2795 //
2796 // Stall for 30 us
2797 //
2798 gBS->Stall (30);
2799
2800 //
2801 // Loop infinitely if not meeting expected condition
2802 //
2803 if (TimeoutInMicroSeconds == 0) {
2804 Delay = 2;
2805 }
2806
2807 Delay--;
2808 } while (Delay);
2809
2810 if (Delay == 0) {
2811 return EFI_TIMEOUT;
2812 }
2813
2814 return EFI_SUCCESS;
2815}
2816
2817EFI_STATUS
2818AltStatusDRQReady (
2819 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2820 UINT64 TimeoutInMicroSeconds
2821 )
2822/*++
2823
2824Routine Description:
2825
2826 Check whether DRQ is ready in the Alternate Status Register.
2827 (BSY must also be cleared)
2828 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2829 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2830 elapsed.
2831
2832Arguments:
2833
2834 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2835 TimeoutInMicroSeconds - The time to wait for
2836
2837Returns:
2838
2839 EFI_STATUS
2840
2841--*/
2842{
2843 UINT64 Delay;
2844 UINT8 AltStatusRegister;
2845 UINT8 ErrRegister;
2846
2847 if (TimeoutInMicroSeconds == 0) {
2848 Delay = 2;
2849 } else {
2850 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2851 }
2852
2853 do {
2854 //
2855 // read Status Register will clear interrupt
2856 //
2857 AltStatusRegister = ReadPortB (
2858 AtapiScsiPrivate->PciIo,
2859 AtapiScsiPrivate->IoPort->Alt.AltStatus
2860 );
2861 //
2862 // BSY==0,DRQ==1
2863 //
2864 if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {
2865 break;
2866 }
2867
2868 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
2869
2870 ErrRegister = ReadPortB (
2871 AtapiScsiPrivate->PciIo,
2872 AtapiScsiPrivate->IoPort->Reg1.Error
2873 );
2874 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2875 return EFI_ABORTED;
2876 }
2877 }
2878
2879 //
2880 // Stall for 30 us
2881 //
2882 gBS->Stall (30);
2883
2884 //
2885 // Loop infinitely if not meeting expected condition
2886 //
2887 if (TimeoutInMicroSeconds == 0) {
2888 Delay = 2;
2889 }
2890
2891 Delay--;
2892 } while (Delay);
2893
2894 if (Delay == 0) {
2895 return EFI_TIMEOUT;
2896 }
2897
2898 return EFI_SUCCESS;
2899}
2900
2901EFI_STATUS
2902StatusWaitForBSYClear (
2903 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2904 UINT64 TimeoutInMicroSeconds
2905 )
2906/*++
2907
2908Routine Description:
2909
2910 Check whether BSY is clear in the Status Register.
2911 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2912 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2913 elapsed.
2914
2915Arguments:
2916
2917 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2918 TimeoutInMicroSeconds - The time to wait for
2919
2920Returns:
2921
2922 EFI_STATUS
2923
2924--*/
2925{
2926 UINT64 Delay;
2927 UINT8 StatusRegister;
2928
2929 if (TimeoutInMicroSeconds == 0) {
2930 Delay = 2;
2931 } else {
2932 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2933 }
2934
2935 do {
2936
2937 StatusRegister = ReadPortB (
2938 AtapiScsiPrivate->PciIo,
2939 AtapiScsiPrivate->IoPort->Reg.Status
2940 );
2941 if ((StatusRegister & BSY) == 0x00) {
2942 break;
2943 }
2944
2945 //
2946 // Stall for 30 us
2947 //
2948 gBS->Stall (30);
2949
2950 //
2951 // Loop infinitely if not meeting expected condition
2952 //
2953 if (TimeoutInMicroSeconds == 0) {
2954 Delay = 2;
2955 }
2956
2957 Delay--;
2958 } while (Delay);
2959
2960 if (Delay == 0) {
2961 return EFI_TIMEOUT;
2962 }
2963
2964 return EFI_SUCCESS;
2965}
2966
2967EFI_STATUS
2968AltStatusWaitForBSYClear (
2969 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2970 UINT64 TimeoutInMicroSeconds
2971 )
2972/*++
2973
2974Routine Description:
2975
2976 Check whether BSY is clear in the Alternate Status Register.
2977 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2978 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2979 elapsed.
2980
2981Arguments:
2982
2983 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2984 TimeoutInMicroSeconds - The time to wait for
2985
2986Returns:
2987
2988 EFI_STATUS
2989
2990--*/
2991{
2992 UINT64 Delay;
2993 UINT8 AltStatusRegister;
2994
2995 if (TimeoutInMicroSeconds == 0) {
2996 Delay = 2;
2997 } else {
2998 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2999 }
3000
3001 do {
3002
3003 AltStatusRegister = ReadPortB (
3004 AtapiScsiPrivate->PciIo,
3005 AtapiScsiPrivate->IoPort->Alt.AltStatus
3006 );
3007 if ((AltStatusRegister & BSY) == 0x00) {
3008 break;
3009 }
3010
3011 //
3012 // Stall for 30 us
3013 //
3014 gBS->Stall (30);
3015 //
3016 // Loop infinitely if not meeting expected condition
3017 //
3018 if (TimeoutInMicroSeconds == 0) {
3019 Delay = 2;
3020 }
3021
3022 Delay--;
3023 } while (Delay);
3024
3025 if (Delay == 0) {
3026 return EFI_TIMEOUT;
3027 }
3028
3029 return EFI_SUCCESS;
3030}
3031
3032EFI_STATUS
3033StatusDRDYReady (
3034 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
3035 UINT64 TimeoutInMicroSeconds
3036 )
3037/*++
3038
3039Routine Description:
3040
3041 Check whether DRDY is ready in the Status Register.
3042 (BSY must also be cleared)
3043 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3044 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3045 elapsed.
3046
3047Arguments:
3048
3049 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3050 TimeoutInMicroSeconds - The time to wait for
3051
3052Returns:
3053
3054 EFI_STATUS
3055
3056--*/
3057{
3058 UINT64 Delay;
3059 UINT8 StatusRegister;
3060 UINT8 ErrRegister;
3061
3062 if (TimeoutInMicroSeconds == 0) {
3063 Delay = 2;
3064 } else {
3065 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
3066 }
3067
3068 do {
3069 StatusRegister = ReadPortB (
3070 AtapiScsiPrivate->PciIo,
3071 AtapiScsiPrivate->IoPort->Reg.Status
3072 );
3073 //
3074 // BSY == 0 , DRDY == 1
3075 //
3076 if ((StatusRegister & (DRDY | BSY)) == DRDY) {
3077 break;
3078 }
3079
3080 if ((StatusRegister & (BSY | ERR)) == ERR) {
3081
3082 ErrRegister = ReadPortB (
3083 AtapiScsiPrivate->PciIo,
3084 AtapiScsiPrivate->IoPort->Reg1.Error
3085 );
3086 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
3087 return EFI_ABORTED;
3088 }
3089 }
3090
3091 //
3092 // Stall for 30 us
3093 //
3094 gBS->Stall (30);
3095 //
3096 // Loop infinitely if not meeting expected condition
3097 //
3098 if (TimeoutInMicroSeconds == 0) {
3099 Delay = 2;
3100 }
3101
3102 Delay--;
3103 } while (Delay);
3104
3105 if (Delay == 0) {
3106 return EFI_TIMEOUT;
3107 }
3108
3109 return EFI_SUCCESS;
3110}
3111
3112EFI_STATUS
3113AltStatusDRDYReady (
3114 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
3115 UINT64 TimeoutInMicroSeconds
3116 )
3117/*++
3118
3119Routine Description:
3120
3121 Check whether DRDY is ready in the Alternate Status Register.
3122 (BSY must also be cleared)
3123 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3124 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3125 elapsed.
3126
3127Arguments:
3128
3129 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3130 TimeoutInMicroSeconds - The time to wait for
3131
3132Returns:
3133
3134 EFI_STATUS
3135
3136--*/
3137{
3138 UINT64 Delay;
3139 UINT8 AltStatusRegister;
3140 UINT8 ErrRegister;
3141
3142 if (TimeoutInMicroSeconds == 0) {
3143 Delay = 2;
3144 } else {
3145 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
3146 }
3147
3148 do {
3149 AltStatusRegister = ReadPortB (
3150 AtapiScsiPrivate->PciIo,
3151 AtapiScsiPrivate->IoPort->Alt.AltStatus
3152 );
3153 //
3154 // BSY == 0 , DRDY == 1
3155 //
3156 if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {
3157 break;
3158 }
3159
3160 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
3161
3162 ErrRegister = ReadPortB (
3163 AtapiScsiPrivate->PciIo,
3164 AtapiScsiPrivate->IoPort->Reg1.Error
3165 );
3166 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
3167 return EFI_ABORTED;
3168 }
3169 }
3170
3171 //
3172 // Stall for 30 us
3173 //
3174 gBS->Stall (30);
3175 //
3176 // Loop infinitely if not meeting expected condition
3177 //
3178 if (TimeoutInMicroSeconds == 0) {
3179 Delay = 2;
3180 }
3181
3182 Delay--;
3183 } while (Delay);
3184
3185 if (Delay == 0) {
3186 return EFI_TIMEOUT;
3187 }
3188
3189 return EFI_SUCCESS;
3190}
3191
3192EFI_STATUS
3193AtapiPassThruCheckErrorStatus (
3194 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
3195 )
3196/*++
3197
3198Routine Description:
3199
3200 Check Error Register for Error Information.
3201
3202Arguments:
3203
3204 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3205
3206Returns:
3207
3208 EFI_STATUS
3209
3210--*/
3211{
3212 UINT8 StatusRegister;
3213 UINT8 ErrorRegister;
3214
3215 StatusRegister = ReadPortB (
3216 AtapiScsiPrivate->PciIo,
3217 AtapiScsiPrivate->IoPort->Reg.Status
3218 );
3219
3220 DEBUG_CODE_BEGIN ();
3221
3222 if (StatusRegister & DWF) {
3223 DEBUG (
3224 (EFI_D_BLKIO,
3225 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
3226 StatusRegister)
3227 );
3228 }
3229
3230 if (StatusRegister & CORR) {
3231 DEBUG (
3232 (EFI_D_BLKIO,
3233 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
3234 StatusRegister)
3235 );
3236 }
3237
3238 if (StatusRegister & ERR) {
3239 ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);
3240
3241
3242 if (ErrorRegister & BBK_ERR) {
3243 DEBUG (
3244 (EFI_D_BLKIO,
3245 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
3246 ErrorRegister)
3247 );
3248 }
3249
3250 if (ErrorRegister & UNC_ERR) {
3251 DEBUG (
3252 (EFI_D_BLKIO,
3253 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
3254 ErrorRegister)
3255 );
3256 }
3257
3258 if (ErrorRegister & MC_ERR) {
3259 DEBUG (
3260 (EFI_D_BLKIO,
3261 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
3262 ErrorRegister)
3263 );
3264 }
3265
3266 if (ErrorRegister & ABRT_ERR) {
3267 DEBUG (
3268 (EFI_D_BLKIO,
3269 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
3270 ErrorRegister)
3271 );
3272 }
3273
3274 if (ErrorRegister & TK0NF_ERR) {
3275 DEBUG (
3276 (EFI_D_BLKIO,
3277 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
3278 ErrorRegister)
3279 );
3280 }
3281
3282 if (ErrorRegister & AMNF_ERR) {
3283 DEBUG (
3284 (EFI_D_BLKIO,
3285 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
3286 ErrorRegister)
3287 );
3288 }
3289 }
3290
3291 DEBUG_CODE_END ();
3292
3293 if ((StatusRegister & (ERR | DWF | CORR)) == 0) {
3294 return EFI_SUCCESS;
3295 }
3296
3297
3298 return EFI_DEVICE_ERROR;
3299}
3300
3301
3302/**
3303 Installs Scsi Pass Thru and/or Ext Scsi Pass Thru
3304 protocols based on feature flags.
3305
3306 @param Controller The controller handle to
3307 install these protocols on.
3308 @param AtapiScsiPrivate A pointer to the protocol private
3309 data structure.
3310
3311 @retval EFI_SUCCESS The installation succeeds.
3312 @retval other The installation fails.
3313
3314**/
3315EFI_STATUS
3316InstallScsiPassThruProtocols (
3317 IN EFI_HANDLE *ControllerHandle,
3318 IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
3319 )
3320{
3321 EFI_STATUS Status;
3322 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
3323 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
3324
3325 ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;
3326 ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;
3327
3328 if (FeaturePcdGet (PcdSupportScsiPassThru)) {
3329 ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));
3330 if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
3331 ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));
3332 Status = gBS->InstallMultipleProtocolInterfaces (
3333 ControllerHandle,
3334 &gEfiScsiPassThruProtocolGuid,
3335 ScsiPassThru,
3336 &gEfiExtScsiPassThruProtocolGuid,
3337 ExtScsiPassThru,
3338 NULL
3339 );
3340 } else {
3341 Status = gBS->InstallMultipleProtocolInterfaces (
3342 ControllerHandle,
3343 &gEfiScsiPassThruProtocolGuid,
3344 ScsiPassThru,
3345 NULL
3346 );
3347 }
3348 } else {
3349 if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
3350 ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));
3351 Status = gBS->InstallMultipleProtocolInterfaces (
3352 ControllerHandle,
3353 &gEfiExtScsiPassThruProtocolGuid,
3354 ExtScsiPassThru,
3355 NULL
3356 );
3357 } else {
3358 //
3359 // This driver must support either ScsiPassThru or
3360 // ExtScsiPassThru protocols
3361 //
3362 ASSERT (FALSE);
3363 Status = EFI_UNSUPPORTED;
3364 }
3365 }
3366
3367 return Status;
3368}
3369
3370/**
3371 The user Entry Point for module AtapiPassThru. The user code starts with this function.
3372
3373 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3374 @param[in] SystemTable A pointer to the EFI System Table.
3375
3376 @retval EFI_SUCCESS The entry point is executed successfully.
3377 @retval other Some error occurs when executing this entry point.
3378
3379**/
3380EFI_STATUS
3381EFIAPI
3382InitializeAtapiPassThru(
3383 IN EFI_HANDLE ImageHandle,
3384 IN EFI_SYSTEM_TABLE *SystemTable
3385 )
3386{
3387 EFI_STATUS Status;
3388
3389 //
3390 // Install driver model protocol(s).
3391 //
3392 Status = EfiLibInstallDriverBindingComponentName2 (
3393 ImageHandle,
3394 SystemTable,
3395 &gAtapiScsiPassThruDriverBinding,
3396 ImageHandle,
3397 &gAtapiScsiPassThruComponentName,
3398 &gAtapiScsiPassThruComponentName2
3399 );
3400 ASSERT_EFI_ERROR (Status);
3401
3402 //
3403 // Install EFI Driver Supported EFI Version Protocol required for
3404 // EFI drivers that are on PCI and other plug in cards.
3405 //
3406 gAtapiScsiPassThruDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
3407 Status = gBS->InstallMultipleProtocolInterfaces (
3408 &ImageHandle,
3409 &gEfiDriverSupportedEfiVersionProtocolGuid,
3410 &gAtapiScsiPassThruDriverSupportedEfiVersion,
3411 NULL
3412 );
3413 ASSERT_EFI_ERROR (Status);
3414
3415 return Status;
3416}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette