• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 SCSI_COMMAND_SET     gEndTable = { 0xff, (DATA_DIRECTION) 0xff };
17 
18 ///
19 /// This table contains all the supported ATAPI commands.
20 ///
21 SCSI_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 
57 GLOBAL_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 
65 GLOBAL_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 
75 GLOBAL_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 
81 GLOBAL_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 
92 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {
93   AtapiScsiPassThruDriverBindingSupported,
94   AtapiScsiPassThruDriverBindingStart,
95   AtapiScsiPassThruDriverBindingStop,
96   0x10,
97   NULL,
98   NULL
99 };
100 
101 EFI_STATUS
102 EFIAPI
AtapiScsiPassThruDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)103 AtapiScsiPassThruDriverBindingSupported (
104   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
105   IN EFI_HANDLE                   Controller,
106   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
107   )
108 /*++
109 
110 Routine 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 
114 Arguments:
115 
116   This                - Protocol instance pointer.
117   Controller          - Handle of device to test
118   RemainingDevicePath - Not used
119 
120 Returns:
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 
181 EFI_STATUS
182 EFIAPI
AtapiScsiPassThruDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)183 AtapiScsiPassThruDriverBindingStart (
184   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
185   IN EFI_HANDLE                   Controller,
186   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
187   )
188 /*++
189 
190 Routine Description:
191   Create handles for IDE channels specified by RemainingDevicePath.
192   Install SCSI Pass Thru Protocol onto each created handle.
193 
194 Arguments:
195 
196   This                - Protocol instance pointer.
197   Controller          - Handle of device to test
198   RemainingDevicePath - Not used
199 
200 Returns:
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 
266 Done:
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 
291 EFI_STATUS
292 EFIAPI
AtapiScsiPassThruDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)293 AtapiScsiPassThruDriverBindingStop (
294   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
295   IN  EFI_HANDLE                      Controller,
296   IN  UINTN                           NumberOfChildren,
297   IN  EFI_HANDLE                      *ChildHandleBuffer
298   )
299 /*++
300 
301 Routine Description:
302 
303   Stop this driver on ControllerHandle. Support stopping any child handles
304   created by this driver.
305 
306 Arguments:
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 
313 Returns:
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 
400 EFI_STATUS
RegisterAtapiScsiPassThru(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT64 OriginalPciAttributes)401 RegisterAtapiScsiPassThru (
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 
409 Routine Description:
410   Attaches SCSI Pass Thru Protocol for specified IDE channel.
411 
412 Arguments:
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 
417 Returns:
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 
462 EFI_STATUS
463 EFIAPI
AtapiScsiPassThruFunction(IN EFI_SCSI_PASS_THRU_PROTOCOL * This,IN UINT32 Target,IN UINT64 Lun,IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet,IN EFI_EVENT Event OPTIONAL)464 AtapiScsiPassThruFunction (
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 
473 Routine Description:
474 
475   Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
476 
477 Arguments:
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 
495 Returns:
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 
553 EFI_STATUS
554 EFIAPI
AtapiScsiPassThruGetNextDevice(IN EFI_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT32 * Target,IN OUT UINT64 * Lun)555 AtapiScsiPassThruGetNextDevice (
556   IN  EFI_SCSI_PASS_THRU_PROTOCOL    *This,
557   IN OUT UINT32                      *Target,
558   IN OUT UINT64                      *Lun
559   )
560 /*++
561 
562 Routine Description:
563 
564   Used to retrieve the list of legal Target IDs for SCSI devices
565   on a SCSI channel.
566 
567 Arguments:
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.
580 Returns:
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 
631 EFI_STATUS
632 EFIAPI
AtapiScsiPassThruBuildDevicePath(IN EFI_SCSI_PASS_THRU_PROTOCOL * This,IN UINT32 Target,IN UINT64 Lun,IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)633 AtapiScsiPassThruBuildDevicePath (
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 
641 Routine 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 
646 Arguments:
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 
707 EFI_STATUS
708 EFIAPI
AtapiScsiPassThruGetTargetLun(IN EFI_SCSI_PASS_THRU_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT32 * Target,OUT UINT64 * Lun)709 AtapiScsiPassThruGetTargetLun (
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 
717 Routine Description:
718 
719   Used to translate a device path node to a Target ID and LUN.
720 
721 Arguments:
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.
730 Returns:
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 
772 EFI_STATUS
773 EFIAPI
AtapiScsiPassThruResetChannel(IN EFI_SCSI_PASS_THRU_PROTOCOL * This)774 AtapiScsiPassThruResetChannel (
775   IN  EFI_SCSI_PASS_THRU_PROTOCOL   *This
776   )
777 /*++
778 
779 Routine Description:
780 
781   Resets a SCSI channel.This operation resets all the
782   SCSI devices connected to the SCSI channel.
783 
784 Arguments:
785 
786   This                  - Protocol instance pointer.
787 
788 Returns:
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 
860 EFI_STATUS
861 EFIAPI
AtapiScsiPassThruResetTarget(IN EFI_SCSI_PASS_THRU_PROTOCOL * This,IN UINT32 Target,IN UINT64 Lun)862 AtapiScsiPassThruResetTarget (
863   IN EFI_SCSI_PASS_THRU_PROTOCOL    *This,
864   IN UINT32                         Target,
865   IN UINT64                         Lun
866   )
867 /*++
868 
869 Routine Description:
870 
871   Resets a SCSI device that is connected to a SCSI channel.
872 
873 Arguments:
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 
879 Returns:
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 
948 EFI_STATUS
949 EFIAPI
AtapiExtScsiPassThruFunction(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun,IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet,IN EFI_EVENT Event OPTIONAL)950 AtapiExtScsiPassThruFunction (
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 
959 Routine Description:
960 
961   Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
962 
963 Arguments:
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 
981 Returns:
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 
1045 EFI_STATUS
1046 EFIAPI
AtapiExtScsiPassThruGetNextTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT8 ** Target,IN OUT UINT64 * Lun)1047 AtapiExtScsiPassThruGetNextTargetLun (
1048   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
1049   IN OUT UINT8                           **Target,
1050   IN OUT UINT64                          *Lun
1051   )
1052 /*++
1053 
1054 Routine Description:
1055 
1056   Used to retrieve the list of legal Target IDs for SCSI devices
1057   on a SCSI channel.
1058 
1059 Arguments:
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.
1072 Returns:
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 
1141 EFI_STATUS
1142 EFIAPI
AtapiExtScsiPassThruBuildDevicePath(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun,IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath)1143 AtapiExtScsiPassThruBuildDevicePath (
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 
1151 Routine 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 
1156 Arguments:
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 
1219 EFI_STATUS
1220 EFIAPI
AtapiExtScsiPassThruGetTargetLun(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,OUT UINT8 ** Target,OUT UINT64 * Lun)1221 AtapiExtScsiPassThruGetTargetLun (
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 
1229 Routine Description:
1230 
1231   Used to translate a device path node to a Target ID and LUN.
1232 
1233 Arguments:
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.
1242 Returns:
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 
1286 EFI_STATUS
1287 EFIAPI
AtapiExtScsiPassThruResetChannel(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This)1288 AtapiExtScsiPassThruResetChannel (
1289   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL   *This
1290   )
1291 /*++
1292 
1293 Routine Description:
1294 
1295   Resets a SCSI channel.This operation resets all the
1296   SCSI devices connected to the SCSI channel.
1297 
1298 Arguments:
1299 
1300   This                  - Protocol instance pointer.
1301 
1302 Returns:
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 
1374 EFI_STATUS
1375 EFIAPI
AtapiExtScsiPassThruResetTarget(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN UINT8 * Target,IN UINT64 Lun)1376 AtapiExtScsiPassThruResetTarget (
1377   IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
1378   IN UINT8                              *Target,
1379   IN UINT64                             Lun
1380   )
1381 /*++
1382 
1383 Routine Description:
1384 
1385   Resets a SCSI device that is connected to a SCSI channel.
1386 
1387 Arguments:
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 
1393 Returns:
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 
1465 EFI_STATUS
1466 EFIAPI
AtapiExtScsiPassThruGetNextTarget(IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL * This,IN OUT UINT8 ** Target)1467 AtapiExtScsiPassThruGetNextTarget (
1468   IN  EFI_EXT_SCSI_PASS_THRU_PROTOCOL    *This,
1469   IN OUT UINT8                           **Target
1470   )
1471 /*++
1472 
1473 Routine Description:
1474   Used to retrieve the list of legal Target IDs for SCSI devices
1475   on a SCSI channel.
1476 
1477 Arguments:
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 
1490 Returns:
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 
1552 EFI_STATUS
GetIdeRegistersBaseAddr(IN EFI_PCI_IO_PROTOCOL * PciIo,OUT IDE_REGISTERS_BASE_ADDR * IdeRegsBaseAddr)1553 GetIdeRegistersBaseAddr (
1554   IN  EFI_PCI_IO_PROTOCOL         *PciIo,
1555   OUT IDE_REGISTERS_BASE_ADDR     *IdeRegsBaseAddr
1556   )
1557 /*++
1558 
1559 Routine 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 
1564 Arguments:
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 
1569 Returns:
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 
1629 VOID
InitAtapiIoPortRegisters(IN ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,IN IDE_REGISTERS_BASE_ADDR * IdeRegsBaseAddr)1630 InitAtapiIoPortRegisters (
1631   IN  ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
1632   IN  IDE_REGISTERS_BASE_ADDR      *IdeRegsBaseAddr
1633   )
1634 /*++
1635 
1636 Routine Description:
1637 
1638   Initialize each Channel's Base Address of CommandBlock and ControlBlock.
1639 
1640 Arguments:
1641 
1642   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1643   IdeRegsBaseAddr             - The pointer of IDE_REGISTERS_BASE_ADDR
1644 
1645 Returns:
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 
1685 EFI_STATUS
CheckSCSIRequestPacket(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)1686 CheckSCSIRequestPacket (
1687   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet
1688   )
1689 /*++
1690 
1691 Routine 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 
1696 Arguments:
1697 
1698   Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1699 
1700 Returns:
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 
1728 BOOLEAN
IsCommandValid(EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)1729 IsCommandValid (
1730   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet
1731   )
1732 /*++
1733 
1734 Routine Description:
1735 
1736   Checks the requested SCSI command:
1737   Is it supported by this driver?
1738   Is the Data transfer direction reasonable?
1739 
1740 Arguments:
1741 
1742   Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1743 
1744 Returns:
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) (ARRAY_SIZE (gSupportedATAPICommands));
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 
1790 EFI_STATUS
SubmitBlockingIoCommand(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT32 Target,EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)1791 SubmitBlockingIoCommand (
1792   ATAPI_SCSI_PASS_THRU_DEV                  *AtapiScsiPrivate,
1793   UINT32                                    Target,
1794   EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
1795   )
1796 /*++
1797 
1798 Routine Description:
1799 
1800   Performs blocking I/O request.
1801 
1802 Arguments:
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 
1876 EFI_STATUS
RequestSenseCommand(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT32 Target,UINT64 Timeout,VOID * SenseData,UINT8 * SenseDataLength)1877 RequestSenseCommand (
1878   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
1879   UINT32                      Target,
1880   UINT64                      Timeout,
1881   VOID                        *SenseData,
1882   UINT8                       *SenseDataLength
1883   )
1884 /*++
1885 
1886 Routine Description:
1887 
1888   Submit request sense command
1889 
1890 Arguments:
1891 
1892   AtapiScsiPrivate  - The pointer 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 
1898 Returns:
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 
1927 EFI_STATUS
CheckExtSCSIRequestPacket(EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)1928 CheckExtSCSIRequestPacket (
1929   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET      *Packet
1930   )
1931 /*++
1932 
1933 Routine 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 
1938 Arguments:
1939 
1940   Packet       - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1941 
1942 Returns:
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 
1971 BOOLEAN
IsExtCommandValid(EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)1972 IsExtCommandValid (
1973   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET   *Packet
1974   )
1975 /*++
1976 
1977 Routine Description:
1978 
1979   Checks the requested SCSI command:
1980   Is it supported by this driver?
1981   Is the Data transfer direction reasonable?
1982 
1983 Arguments:
1984 
1985   Packet         -  The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1986 
1987 Returns:
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) (ARRAY_SIZE (gSupportedATAPICommands));
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 
2033 EFI_STATUS
SubmitExtBlockingIoCommand(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT8 Target,EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET * Packet)2034 SubmitExtBlockingIoCommand (
2035   ATAPI_SCSI_PASS_THRU_DEV                      *AtapiScsiPrivate,
2036   UINT8                                         Target,
2037   EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET    *Packet
2038   )
2039 /*++
2040 
2041 Routine Description:
2042 
2043   Performs blocking I/O request.
2044 
2045 Arguments:
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 
2134 EFI_STATUS
AtapiPacketCommand(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT32 Target,UINT8 * PacketCommand,VOID * Buffer,UINT32 * ByteCount,DATA_DIRECTION Direction,UINT64 TimeoutInMicroSeconds)2135 AtapiPacketCommand (
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 
2146 Routine Description:
2147 
2148   Submits ATAPI command packet to the specified ATAPI device.
2149 
2150 Arguments:
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 
2173 Returns:
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 
2298 EFI_STATUS
AtapiPassThruPioReadWriteData(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT16 * Buffer,UINT32 * ByteCount,DATA_DIRECTION Direction,UINT64 TimeoutInMicroSeconds)2299 AtapiPassThruPioReadWriteData (
2300   ATAPI_SCSI_PASS_THRU_DEV  *AtapiScsiPrivate,
2301   UINT16                    *Buffer,
2302   UINT32                    *ByteCount,
2303   DATA_DIRECTION            Direction,
2304   UINT64                    TimeoutInMicroSeconds
2305   )
2306 /*++
2307 
2308 Routine Description:
2309 
2310   Performs data transfer between ATAPI device and host after the
2311   ATAPI command packet is sent.
2312 
2313 Arguments:
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 
2425 UINT8
ReadPortB(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT16 Port)2426 ReadPortB (
2427   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
2428   IN  UINT16                Port
2429   )
2430 /*++
2431 
2432 Routine Description:
2433 
2434   Read one byte from a specified I/O port.
2435 
2436 Arguments:
2437 
2438   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
2439   Port       - IO port
2440 
2441 Returns:
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 
2462 UINT16
ReadPortW(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT16 Port)2463 ReadPortW (
2464   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
2465   IN  UINT16                Port
2466   )
2467 /*++
2468 
2469 Routine Description:
2470 
2471   Read one word from a specified I/O port.
2472 
2473 Arguments:
2474 
2475   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
2476   Port       - IO port
2477 
2478 Returns:
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 
2498 VOID
WritePortB(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT16 Port,IN UINT8 Data)2499 WritePortB (
2500   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
2501   IN  UINT16                Port,
2502   IN  UINT8                 Data
2503   )
2504 /*++
2505 
2506 Routine Description:
2507 
2508   Write one byte to a specified I/O port.
2509 
2510 Arguments:
2511 
2512   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
2513   Port       - IO port
2514   Data       - The data to write
2515 
2516 Returns:
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 
2533 VOID
WritePortW(IN EFI_PCI_IO_PROTOCOL * PciIo,IN UINT16 Port,IN UINT16 Data)2534 WritePortW (
2535   IN  EFI_PCI_IO_PROTOCOL   *PciIo,
2536   IN  UINT16                Port,
2537   IN  UINT16                Data
2538   )
2539 /*++
2540 
2541 Routine Description:
2542 
2543   Write one word to a specified I/O port.
2544 
2545 Arguments:
2546 
2547   PciIo      - The pointer of EFI_PCI_IO_PROTOCOL
2548   Port       - IO port
2549   Data       - The data to write
2550 
2551 Returns:
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 
2567 EFI_STATUS
StatusDRQClear(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)2568 StatusDRQClear (
2569   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
2570   UINT64                          TimeoutInMicroSeconds
2571   )
2572 /*++
2573 
2574 Routine 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 
2581 Arguments:
2582 
2583   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2584   TimeoutInMicroSeconds       - The time to wait for
2585 
2586 Returns:
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 
2651 EFI_STATUS
AltStatusDRQClear(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)2652 AltStatusDRQClear (
2653   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
2654   UINT64                          TimeoutInMicroSeconds
2655   )
2656 /*++
2657 
2658 Routine 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 
2665 Arguments:
2666 
2667   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2668   TimeoutInMicroSeconds       - The time to wait for
2669 
2670 Returns:
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 
2733 EFI_STATUS
StatusDRQReady(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)2734 StatusDRQReady (
2735   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
2736   UINT64                          TimeoutInMicroSeconds
2737   )
2738 /*++
2739 
2740 Routine 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 
2747 Arguments:
2748 
2749   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2750   TimeoutInMicroSeconds       - The time to wait for
2751 
2752 Returns:
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 
2817 EFI_STATUS
AltStatusDRQReady(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)2818 AltStatusDRQReady (
2819   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate,
2820   UINT64                          TimeoutInMicroSeconds
2821   )
2822 /*++
2823 
2824 Routine 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 
2832 Arguments:
2833 
2834   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2835   TimeoutInMicroSeconds       - The time to wait for
2836 
2837 Returns:
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 
2901 EFI_STATUS
StatusWaitForBSYClear(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)2902 StatusWaitForBSYClear (
2903   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
2904   UINT64                      TimeoutInMicroSeconds
2905   )
2906 /*++
2907 
2908 Routine 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 
2915 Arguments:
2916 
2917   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2918   TimeoutInMicroSeconds       - The time to wait for
2919 
2920 Returns:
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 
2967 EFI_STATUS
AltStatusWaitForBSYClear(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)2968 AltStatusWaitForBSYClear (
2969   ATAPI_SCSI_PASS_THRU_DEV    *AtapiScsiPrivate,
2970   UINT64                      TimeoutInMicroSeconds
2971   )
2972 /*++
2973 
2974 Routine 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 
2981 Arguments:
2982 
2983   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2984   TimeoutInMicroSeconds       - The time to wait for
2985 
2986 Returns:
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 
3032 EFI_STATUS
StatusDRDYReady(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)3033 StatusDRDYReady (
3034   ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
3035   UINT64                       TimeoutInMicroSeconds
3036   )
3037 /*++
3038 
3039 Routine 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 
3047 Arguments:
3048 
3049   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3050   TimeoutInMicroSeconds       - The time to wait for
3051 
3052 Returns:
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 
3112 EFI_STATUS
AltStatusDRDYReady(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate,UINT64 TimeoutInMicroSeconds)3113 AltStatusDRDYReady (
3114   ATAPI_SCSI_PASS_THRU_DEV     *AtapiScsiPrivate,
3115   UINT64                       TimeoutInMicroSeconds
3116   )
3117 /*++
3118 
3119 Routine 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 
3127 Arguments:
3128 
3129   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3130   TimeoutInMicroSeconds       - The time to wait for
3131 
3132 Returns:
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 
3192 EFI_STATUS
AtapiPassThruCheckErrorStatus(ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate)3193 AtapiPassThruCheckErrorStatus (
3194   ATAPI_SCSI_PASS_THRU_DEV        *AtapiScsiPrivate
3195   )
3196 /*++
3197 
3198 Routine Description:
3199 
3200   Check Error Register for Error Information.
3201 
3202 Arguments:
3203 
3204   AtapiScsiPrivate            - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3205 
3206 Returns:
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 **/
3315 EFI_STATUS
InstallScsiPassThruProtocols(IN EFI_HANDLE * ControllerHandle,IN ATAPI_SCSI_PASS_THRU_DEV * AtapiScsiPrivate)3316 InstallScsiPassThruProtocols (
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 **/
3380 EFI_STATUS
3381 EFIAPI
InitializeAtapiPassThru(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)3382 InitializeAtapiPassThru(
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 }
3417