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