Save original PCI attributes in start() function and restore it in Stop() for those...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / AtapiPassThruDxe / AtapiPassThru.c
1 /** @file
2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11 **/
12
13 #include "AtapiPassThru.h"
14
15
16 static SCSI_COMMAND_SET gEndTable = { 0xff, (DATA_DIRECTION) 0xff };
17
18 ///
19 /// This table contains all the supported ATAPI commands.
20 ///
21 static SCSI_COMMAND_SET gSupportedATAPICommands[] = {
22 { OP_INQUIRY, DataIn },
23 { OP_LOAD_UNLOAD_CD, NoData },
24 { OP_MECHANISM_STATUS, DataIn },
25 { OP_MODE_SELECT_10, DataOut },
26 { OP_MODE_SENSE_10, DataIn },
27 { OP_PAUSE_RESUME, NoData },
28 { OP_PLAY_AUDIO_10, DataIn },
29 { OP_PLAY_AUDIO_MSF, DataIn },
30 { OP_PLAY_CD, DataIn },
31 { OP_PLAY_CD_MSF, DataIn },
32 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData },
33 { OP_READ_10, DataIn },
34 { OP_READ_12, DataIn },
35 { OP_READ_CAPACITY, DataIn },
36 { OP_READ_CD, DataIn },
37 { OP_READ_CD_MSF, DataIn },
38 { OP_READ_HEADER, DataIn },
39 { OP_READ_SUB_CHANNEL, DataIn },
40 { OP_READ_TOC, DataIn },
41 { OP_REQUEST_SENSE, DataIn },
42 { OP_SCAN, NoData },
43 { OP_SEEK_10, NoData },
44 { OP_SET_CD_SPEED, DataOut },
45 { OP_STOPPLAY_SCAN, NoData },
46 { OP_START_STOP_UNIT, NoData },
47 { OP_TEST_UNIT_READY, NoData },
48 { OP_FORMAT_UNIT, DataOut },
49 { OP_READ_FORMAT_CAPACITIES, DataIn },
50 { OP_VERIFY, DataOut },
51 { OP_WRITE_10, DataOut },
52 { OP_WRITE_12, DataOut },
53 { OP_WRITE_AND_VERIFY, DataOut },
54 { 0xff, (DATA_DIRECTION) 0xff }
55 };
56
57 static CHAR16 *gControllerNameString = (CHAR16 *) L"ATAPI Controller";
58 static CHAR16 *gAtapiChannelString = (CHAR16 *) L"ATAPI Channel";
59
60 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {
61 AtapiScsiPassThruDriverBindingSupported,
62 AtapiScsiPassThruDriverBindingStart,
63 AtapiScsiPassThruDriverBindingStop,
64 0xa,
65 NULL,
66 NULL
67 };
68
69 /**
70 Supported.
71
72 (Standard DriverBinding Protocol Supported() function)
73
74 @return EFI_STATUS
75
76 @todo This - add argument and description to function comment
77 @todo Controller - add argument and description to function comment
78 @todo RemainingDevicePath - add argument and description to function comment
79 @todo EFI_UNSUPPORTED - add return value to function comment
80 **/
81 EFI_STATUS
82 EFIAPI
83 AtapiScsiPassThruDriverBindingSupported (
84 IN EFI_DRIVER_BINDING_PROTOCOL *This,
85 IN EFI_HANDLE Controller,
86 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
87 )
88 {
89 EFI_STATUS Status;
90 EFI_PCI_IO_PROTOCOL *PciIo;
91 PCI_TYPE00 Pci;
92
93
94 //
95 // Open the IO Abstraction(s) needed to perform the supported test
96 //
97 Status = gBS->OpenProtocol (
98 Controller,
99 &gEfiPciIoProtocolGuid,
100 (VOID **) &PciIo,
101 This->DriverBindingHandle,
102 Controller,
103 EFI_OPEN_PROTOCOL_BY_DRIVER
104 );
105 if (EFI_ERROR (Status)) {
106 return Status;
107 }
108 //
109 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
110 // can be managed by this driver. Read the PCI Configuration Header
111 // for this device.
112 //
113 Status = PciIo->Pci.Read (
114 PciIo,
115 EfiPciIoWidthUint32,
116 0,
117 sizeof (Pci) / sizeof (UINT32),
118 &Pci
119 );
120 if (EFI_ERROR (Status)) {
121 gBS->CloseProtocol (
122 Controller,
123 &gEfiPciIoProtocolGuid,
124 This->DriverBindingHandle,
125 Controller
126 );
127 return EFI_UNSUPPORTED;
128 }
129
130 if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_IDE) {
131
132 Status = EFI_UNSUPPORTED;
133 }
134
135 gBS->CloseProtocol (
136 Controller,
137 &gEfiPciIoProtocolGuid,
138 This->DriverBindingHandle,
139 Controller
140 );
141
142 return Status;
143 }
144
145 /**
146 Create handles for IDE channels specified by RemainingDevicePath.
147 Install SCSI Pass Thru Protocol onto each created handle.
148
149 (Standard DriverBinding Protocol Start() function)
150
151 @return EFI_STATUS
152
153 @todo This - add argument and description to function comment
154 @todo Controller - add argument and description to function comment
155 @todo RemainingDevicePath - add argument and description to function comment
156 **/
157 EFI_STATUS
158 EFIAPI
159 AtapiScsiPassThruDriverBindingStart (
160 IN EFI_DRIVER_BINDING_PROTOCOL *This,
161 IN EFI_HANDLE Controller,
162 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
163 )
164 {
165 EFI_STATUS Status;
166 EFI_PCI_IO_PROTOCOL *PciIo;
167 UINT64 Supports;
168 UINT64 OriginalPciAttributes;
169
170 PciIo = NULL;
171 Status = gBS->OpenProtocol (
172 Controller,
173 &gEfiPciIoProtocolGuid,
174 (VOID **) &PciIo,
175 This->DriverBindingHandle,
176 Controller,
177 EFI_OPEN_PROTOCOL_BY_DRIVER
178 );
179 if (EFI_ERROR (Status)) {
180 return Status;
181 }
182
183 //
184 // Save original PCI attributes
185 //
186 Status = PciIo->Attributes (
187 PciIo,
188 EfiPciIoAttributeOperationGet,
189 0,
190 &OriginalPciAttributes
191 );
192
193 if (EFI_ERROR (Status)) {
194 return Status;
195 }
196
197 Status = PciIo->Attributes (
198 PciIo,
199 EfiPciIoAttributeOperationSupported,
200 0,
201 &Supports
202 );
203 if (!EFI_ERROR (Status)) {
204 Supports &= (EFI_PCI_DEVICE_ENABLE |
205 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |
206 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);
207 Status = PciIo->Attributes (
208 PciIo,
209 EfiPciIoAttributeOperationEnable,
210 Supports,
211 NULL
212 );
213 }
214 if (EFI_ERROR (Status)) {
215 goto Done;
216 }
217
218 //
219 // Create SCSI Pass Thru instance for the IDE channel.
220 //
221 Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);
222
223 Done:
224 if (EFI_ERROR (Status)) {
225 //
226 // Restore original PCI attributes
227 //
228 PciIo->Attributes (
229 PciIo,
230 EfiPciIoAttributeOperationSet,
231 OriginalPciAttributes,
232 NULL
233 );
234
235 gBS->CloseProtocol (
236 Controller,
237 &gEfiPciIoProtocolGuid,
238 This->DriverBindingHandle,
239 Controller
240 );
241 }
242
243 return Status;
244 }
245
246 /**
247 Stop.
248
249 (Standard DriverBinding Protocol Stop() function)
250
251 @return EFI_STATUS
252
253 @todo This - add argument and description to function comment
254 @todo Controller - add argument and description to function comment
255 @todo NumberOfChildren - add argument and description to function comment
256 @todo ChildHandleBuffer - add argument and description to function comment
257 @todo EFI_SUCCESS - add return value to function comment
258 **/
259 EFI_STATUS
260 EFIAPI
261 AtapiScsiPassThruDriverBindingStop (
262 IN EFI_DRIVER_BINDING_PROTOCOL *This,
263 IN EFI_HANDLE Controller,
264 IN UINTN NumberOfChildren,
265 IN EFI_HANDLE *ChildHandleBuffer
266 )
267 {
268 EFI_STATUS Status;
269 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
270 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
271
272 Status = gBS->OpenProtocol (
273 Controller,
274 &gEfiScsiPassThruProtocolGuid,
275 (VOID **) &ScsiPassThru,
276 This->DriverBindingHandle,
277 Controller,
278 EFI_OPEN_PROTOCOL_GET_PROTOCOL
279 );
280 if (EFI_ERROR (Status)) {
281 return Status;
282 }
283
284 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);
285
286 Status = gBS->UninstallProtocolInterface (
287 Controller,
288 &gEfiScsiPassThruProtocolGuid,
289 &AtapiScsiPrivate->ScsiPassThru
290 );
291 if (EFI_ERROR (Status)) {
292 return Status;
293 }
294
295 //
296 // Restore original PCI attributes
297 //
298 AtapiScsiPrivate->PciIo->Attributes (
299 AtapiScsiPrivate->PciIo,
300 EfiPciIoAttributeOperationSet,
301 AtapiScsiPrivate->OriginalPciAttributes,
302 NULL
303 );
304
305 gBS->CloseProtocol (
306 Controller,
307 &gEfiPciIoProtocolGuid,
308 This->DriverBindingHandle,
309 Controller
310 );
311
312 gBS->FreePool (AtapiScsiPrivate);
313
314 return EFI_SUCCESS;
315 }
316
317 /**
318 Attaches SCSI Pass Thru Protocol for specified IDE channel.
319
320 @param Controller: Parent device handle to the IDE channel.
321 @param PciIo: PCI I/O protocol attached on the "Controller".
322 @param OriginalPciAttributes Original PCI attributes
323
324
325 @return EFI_SUCCESS Always returned unless installing SCSI Pass Thru Protocol failed.
326
327 @todo This - add argument and description to function comment
328 @todo Controller - add argument and description to function comment
329 @todo PciIo - add argument and description to function comment
330 @todo EFI_OUT_OF_RESOURCES - add return value to function comment
331 **/
332 EFI_STATUS
333 RegisterAtapiScsiPassThru (
334 IN EFI_DRIVER_BINDING_PROTOCOL *This,
335 IN EFI_HANDLE Controller,
336 IN EFI_PCI_IO_PROTOCOL *PciIo,
337 IN UINT64 OriginalPciAttributes
338 )
339 {
340 EFI_STATUS Status;
341 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
342 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];
343
344 AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));
345 if (AtapiScsiPrivate == NULL) {
346 return EFI_OUT_OF_RESOURCES;
347 }
348
349 CopyMem (AtapiScsiPrivate->ChannelName, gAtapiChannelString, sizeof (gAtapiChannelString));
350
351 AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;
352 AtapiScsiPrivate->Handle = Controller;
353
354 //
355 // will reset the IoPort inside each API function.
356 //
357 AtapiScsiPrivate->IoPort = NULL;
358 AtapiScsiPrivate->PciIo = PciIo;
359 AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;
360
361 //
362 // Obtain IDE IO port registers' base addresses
363 //
364 Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
365 if (EFI_ERROR (Status)) {
366 return Status;
367 }
368
369 InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);
370
371 // initialize SCSI Pass Thru Protocol interface
372 //
373 AtapiScsiPrivate->ScsiPassThru.Mode = &AtapiScsiPrivate->ScsiPassThruMode;
374 AtapiScsiPrivate->ScsiPassThru.PassThru = AtapiScsiPassThruFunction;
375 AtapiScsiPrivate->ScsiPassThru.GetNextDevice = AtapiScsiPassThruGetNextDevice;
376 AtapiScsiPrivate->ScsiPassThru.BuildDevicePath = AtapiScsiPassThruBuildDevicePath;
377 AtapiScsiPrivate->ScsiPassThru.GetTargetLun = AtapiScsiPassThruGetTargetLun;
378 AtapiScsiPrivate->ScsiPassThru.ResetChannel = AtapiScsiPassThruResetChannel;
379 AtapiScsiPrivate->ScsiPassThru.ResetTarget = AtapiScsiPassThruResetTarget;
380
381 //
382 // Set Mode
383 //
384 CopyMem (AtapiScsiPrivate->ControllerName, gControllerNameString, sizeof (gControllerNameString));
385
386 AtapiScsiPrivate->ScsiPassThruMode.ControllerName = AtapiScsiPrivate->ControllerName;
387 AtapiScsiPrivate->ScsiPassThruMode.ChannelName = AtapiScsiPrivate->ChannelName;
388 AtapiScsiPrivate->ScsiPassThruMode.AdapterId = 4;
389 //
390 // non-RAID SCSI controllers should set both physical and logical attributes
391 //
392 AtapiScsiPrivate->ScsiPassThruMode.Attributes = EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL |
393 EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
394 AtapiScsiPrivate->ScsiPassThruMode.IoAlign = 0;
395
396 //
397 // Initialize the LatestTargetId.
398 //
399 AtapiScsiPrivate->LatestTargetId = 4;
400 AtapiScsiPrivate->LatestLun = 0;
401
402 Status = gBS->InstallProtocolInterface (
403 &Controller,
404 &gEfiScsiPassThruProtocolGuid,
405 EFI_NATIVE_INTERFACE,
406 &AtapiScsiPrivate->ScsiPassThru
407 );
408 return Status;
409 }
410
411 /**
412 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
413
414 @param This The EFI_SCSI_PASS_THRU_PROTOCOL instance.
415 @param Target The Target ID of the ATAPI device to send the SCSI
416 Request Packet. To ATAPI devices attached on an IDE
417 Channel, Target ID 0 indicates Master device;Target
418 ID 1 indicates Slave device.
419 @param Lun The LUN of the ATAPI device to send the SCSI Request
420 Packet. To the ATAPI device, Lun is always 0.
421 @param Packet The SCSI Request Packet to send to the ATAPI device
422 specified by Target and Lun.
423 @param Event If non-blocking I/O is not supported then Event is ignored,
424 and blocking I/O is performed.<br>
425 If Event is NULL, then blocking I/O is performed.<br>
426 If Event is not NULL and non blocking I/O is supported,
427 then non-blocking I/O is performed, and Event will be signaled
428 when the SCSI Request Packet completes.
429
430 @todo This - add argument and description to function comment
431 @todo EFI_INVALID_PARAMETER - add return value to function comment
432 @todo EFI_SUCCESS - add return value to function comment
433 **/
434 EFI_STATUS
435 EFIAPI
436 AtapiScsiPassThruFunction (
437 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
438 IN UINT32 Target,
439 IN UINT64 Lun,
440 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
441 IN EFI_EVENT Event OPTIONAL
442 )
443 {
444 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
445 EFI_STATUS Status;
446
447 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
448
449 //
450 // Target is not allowed beyond MAX_TARGET_ID
451 //
452 if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
453 return EFI_INVALID_PARAMETER;
454 }
455
456 //
457 // check the data fields in Packet parameter.
458 //
459 Status = CheckSCSIRequestPacket (Packet);
460 if (EFI_ERROR (Status)) {
461 return Status;
462 }
463
464 //
465 // If Request Packet targets at the IDE channel itself,
466 // do nothing.
467 //
468 if (Target == This->Mode->AdapterId) {
469 Packet->TransferLength = 0;
470 return EFI_SUCCESS;
471 }
472
473 //
474 // According to Target ID, reset the Atapi I/O Register mapping
475 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
476 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
477 //
478 if ((Target / 2) == 0) {
479 Target = Target % 2;
480 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
481 } else {
482 Target = Target % 2;
483 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
484 }
485
486 //
487 // the ATAPI SCSI interface does not support non-blocking I/O
488 // ignore the Event parameter
489 //
490 // Performs blocking I/O.
491 //
492 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);
493 return Status;
494 }
495
496 /**
497 Used to retrieve the list of legal Target IDs for SCSI devices
498 on a SCSI channel.
499
500 @param This Protocol instance pointer.
501 @param Target On input, a pointer to the Target ID of a SCSI
502 device present on the SCSI channel. On output,
503 a pointer to the Target ID of the next SCSI device
504 present on a SCSI channel. An input value of
505 0xFFFFFFFF retrieves the Target ID of the first
506 SCSI device present on a SCSI channel.
507 @param Lun On input, a pointer to the LUN of a SCSI device
508 present on the SCSI channel. On output, a pointer
509 to the LUN of the next SCSI device present on
510 a SCSI channel.
511
512 @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device
513 on the SCSI channel was returned in Target and Lun.
514 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
515 @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were not
516 returned on a previous call to GetNextDevice().
517
518 **/
519 EFI_STATUS
520 EFIAPI
521 AtapiScsiPassThruGetNextDevice (
522 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
523 IN OUT UINT32 *Target,
524 IN OUT UINT64 *Lun
525 )
526 {
527 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
528
529 //
530 // Retrieve Device Private Data Structure.
531 //
532 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
533
534 //
535 // Check whether Target is valid.
536 //
537 if (Target == NULL || Lun == NULL) {
538 return EFI_INVALID_PARAMETER;
539 }
540
541 if ((*Target != 0xFFFFFFFF) &&
542 ((*Target != AtapiScsiPrivate->LatestTargetId) ||
543 (*Lun != AtapiScsiPrivate->LatestLun))) {
544 return EFI_INVALID_PARAMETER;
545 }
546
547 if (*Target == MAX_TARGET_ID) {
548 return EFI_NOT_FOUND;
549 }
550
551 if (*Target == 0xFFFFFFFF) {
552 *Target = 0;
553 } else {
554 *Target = AtapiScsiPrivate->LatestTargetId + 1;
555 }
556
557 *Lun = 0;
558
559 //
560 // Update the LatestTargetId.
561 //
562 AtapiScsiPrivate->LatestTargetId = *Target;
563 AtapiScsiPrivate->LatestLun = *Lun;
564
565 return EFI_SUCCESS;
566
567 }
568
569 /**
570 Used to allocate and build a device path node for a SCSI device
571 on a SCSI channel. Would not build device path for a SCSI Host Controller.
572
573 @param This Protocol instance pointer.
574 @param Target The Target ID of the SCSI device for which
575 a device path node is to be allocated and built.
576 @param Lun The LUN of the SCSI device for which a device
577 path node is to be allocated and built.
578 @param DevicePath A pointer to a single device path node that
579 describes the SCSI device specified by
580 Target and Lun. This function is responsible
581 for allocating the buffer DevicePath with the boot
582 service AllocatePool(). It is the caller's
583 responsibility to free DevicePath when the caller
584 is finished with DevicePath.
585
586 @retval EFI_SUCCESS The device path node that describes the SCSI device
587 specified by Target and Lun was allocated and
588 returned in DevicePath.
589 @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does
590 not exist on the SCSI channel.
591 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
592 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
593 DevicePath.
594
595 **/
596 EFI_STATUS
597 EFIAPI
598 AtapiScsiPassThruBuildDevicePath (
599 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
600 IN UINT32 Target,
601 IN UINT64 Lun,
602 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
603 )
604 {
605 EFI_DEV_PATH *Node;
606
607
608 //
609 // Validate parameters passed in.
610 //
611
612 if (DevicePath == NULL) {
613 return EFI_INVALID_PARAMETER;
614 }
615
616 //
617 // can not build device path for the SCSI Host Controller.
618 //
619 if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
620 return EFI_NOT_FOUND;
621 }
622
623 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
624 if (Node == NULL) {
625 return EFI_OUT_OF_RESOURCES;
626 }
627
628 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
629 Node->DevPath.SubType = MSG_ATAPI_DP;
630 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
631
632 Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);
633 Node->Atapi.SlaveMaster = (UINT8) (Target % 2);
634 Node->Atapi.Lun = (UINT16) Lun;
635
636 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
637
638 return EFI_SUCCESS;
639 }
640
641 /**
642 Used to translate a device path node to a Target ID and LUN.
643
644 @param This Protocol instance pointer.
645 @param DevicePath A pointer to the device path node that
646 describes a SCSI device on the SCSI channel.
647 @param Target A pointer to the Target ID of a SCSI device
648 on the SCSI channel.
649 @param Lun A pointer to the LUN of a SCSI device on
650 the SCSI channel.
651
652 @retval EFI_SUCCESS DevicePath was successfully translated to a
653 Target ID and LUN, and they were returned
654 in Target and Lun.
655 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
656 @retval EFI_INVALID_PARAMETER Target is NULL.
657 @retval EFI_INVALID_PARAMETER Lun is NULL.
658 @retval EFI_UNSUPPORTED This driver does not support the device path
659 node type in DevicePath.
660 @retval EFI_NOT_FOUND A valid translation from DevicePath to a
661 Target ID and LUN does not exist.
662
663 **/
664 EFI_STATUS
665 EFIAPI
666 AtapiScsiPassThruGetTargetLun (
667 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
668 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
669 OUT UINT32 *Target,
670 OUT UINT64 *Lun
671 )
672 {
673 EFI_DEV_PATH *Node;
674
675 //
676 // Validate parameters passed in.
677 //
678 if (DevicePath == NULL || Target == NULL || Lun == NULL) {
679 return EFI_INVALID_PARAMETER;
680 }
681
682 //
683 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
684 //
685 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
686 (DevicePath->SubType != MSG_ATAPI_DP) ||
687 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
688 return EFI_UNSUPPORTED;
689 }
690
691 Node = (EFI_DEV_PATH *) DevicePath;
692
693 *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;
694 *Lun = Node->Atapi.Lun;
695
696 if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {
697 return EFI_NOT_FOUND;
698 }
699
700 return EFI_SUCCESS;
701 }
702
703 /**
704 Resets a SCSI channel.This operation resets all the
705 SCSI devices connected to the SCSI channel.
706
707 @param This Protocol instance pointer.
708
709 @retval EFI_SUCCESS The SCSI channel was reset.
710 @retval EFI_UNSUPPORTED The SCSI channel does not support
711 a channel reset operation.
712 @retval EFI_DEVICE_ERROR A device error occurred while
713 attempting to reset the SCSI channel.
714 @retval EFI_TIMEOUT A timeout occurred while attempting
715 to reset the SCSI channel.
716
717 **/
718 EFI_STATUS
719 EFIAPI
720 AtapiScsiPassThruResetChannel (
721 IN EFI_SCSI_PASS_THRU_PROTOCOL *This
722 )
723 {
724 UINT8 DeviceControlValue;
725 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
726 UINT8 Index;
727 BOOLEAN ResetFlag;
728
729 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
730 ResetFlag = FALSE;
731
732 //
733 // Reset both Primary channel and Secondary channel.
734 // so, the IoPort pointer must point to the right I/O Register group
735 //
736 for (Index = 0; Index < 2; Index++) {
737 //
738 // Reset
739 //
740 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
741
742 DeviceControlValue = 0;
743 //
744 // set SRST bit to initiate soft reset
745 //
746 DeviceControlValue |= SRST;
747 //
748 // disable Interrupt
749 //
750 DeviceControlValue |= bit (1);
751 WritePortB (
752 AtapiScsiPrivate->PciIo,
753 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
754 DeviceControlValue
755 );
756
757 //
758 // Wait 10us
759 //
760 gBS->Stall (10);
761
762 //
763 // Clear SRST bit
764 // 0xfb:1111,1011
765 //
766 DeviceControlValue &= 0xfb;
767
768 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
769
770 //
771 // slave device needs at most 31s to clear BSY
772 //
773 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
774 ResetFlag = TRUE;
775 }
776 }
777
778 if (ResetFlag) {
779 return EFI_SUCCESS;
780 }
781
782 return EFI_TIMEOUT;
783 }
784
785 /**
786 Resets a SCSI device that is connected to a SCSI channel.
787
788 @param This Protocol instance pointer.
789 @param Target The Target ID of the SCSI device to reset.
790 @param Lun The LUN of the SCSI device to reset.
791
792 @retval EFI_SUCCESS The SCSI device specified by Target and
793 Lun was reset.
794 @retval EFI_UNSUPPORTED The SCSI channel does not support a target
795 reset operation.
796 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
797 @retval EFI_DEVICE_ERROR A device error occurred while attempting
798 to reset the SCSI device specified by Target
799 and Lun.
800 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
801 the SCSI device specified by Target and Lun.
802
803 **/
804 EFI_STATUS
805 EFIAPI
806 AtapiScsiPassThruResetTarget (
807 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
808 IN UINT32 Target,
809 IN UINT64 Lun
810 )
811 {
812 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
813 UINT8 Command;
814 UINT8 DeviceSelect;
815
816 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
817
818 if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
819 return EFI_INVALID_PARAMETER;
820 }
821 //
822 // Directly return EFI_SUCCESS if want to reset the host controller
823 //
824 if (Target == This->Mode->AdapterId) {
825 return EFI_SUCCESS;
826 }
827
828 //
829 // According to Target ID, reset the Atapi I/O Register mapping
830 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
831 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
832 //
833 if ((Target / 2) == 0) {
834 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
835 } else {
836 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
837 }
838
839 //
840 // for ATAPI device, no need to wait DRDY ready after device selecting.
841 //
842 // bit7 and bit5 are both set to 1 for backward compatibility
843 //
844 DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (Target << 4)));
845 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
846
847 Command = ATAPI_SOFT_RESET_CMD;
848 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
849
850 //
851 // BSY clear is the only status return to the host by the device
852 // when reset is complete.
853 // slave device needs at most 31s to clear BSY
854 //
855 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
856 return EFI_TIMEOUT;
857 }
858
859 //
860 // stall 5 seconds to make the device status stable
861 //
862 gBS->Stall (5000000);
863
864 return EFI_SUCCESS;
865 }
866
867 EFI_STATUS
868 GetIdeRegistersBaseAddr (
869 IN EFI_PCI_IO_PROTOCOL *PciIo,
870 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
871 )
872 /*++
873
874 Routine Description:
875 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
876 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
877 the PCI IDE controller's Configuration Space.
878
879 Arguments:
880 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
881 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
882 receive IDE IO port registers' base addresses
883
884 Returns:
885
886 EFI_STATUS
887
888 --*/
889 {
890 EFI_STATUS Status;
891 PCI_TYPE00 PciData;
892
893 Status = PciIo->Pci.Read (
894 PciIo,
895 EfiPciIoWidthUint8,
896 0,
897 sizeof (PciData),
898 &PciData
899 );
900
901 if (EFI_ERROR (Status)) {
902 return Status;
903 }
904
905 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
906 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;
907 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;
908 } else {
909 //
910 // The BARs should be of IO type
911 //
912 if ((PciData.Device.Bar[0] & BIT0) == 0 ||
913 (PciData.Device.Bar[1] & BIT0) == 0) {
914 return EFI_UNSUPPORTED;
915 }
916
917 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =
918 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
919 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =
920 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
921 }
922
923 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
924 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;
925 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;
926 } else {
927 //
928 // The BARs should be of IO type
929 //
930 if ((PciData.Device.Bar[2] & BIT0) == 0 ||
931 (PciData.Device.Bar[3] & BIT0) == 0) {
932 return EFI_UNSUPPORTED;
933 }
934
935 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =
936 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
937 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =
938 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
939 }
940
941 return EFI_SUCCESS;
942 }
943
944 VOID
945 InitAtapiIoPortRegisters (
946 IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
947 IN IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
948 )
949 /*++
950
951 Routine Description:
952
953 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
954
955 Arguments:
956
957 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
958 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
959
960 Returns:
961
962 None
963
964 --*/
965 {
966
967 UINT8 IdeChannel;
968 UINT16 CommandBlockBaseAddr;
969 UINT16 ControlBlockBaseAddr;
970 IDE_BASE_REGISTERS *RegisterPointer;
971
972
973 for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {
974
975 RegisterPointer = &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];
976
977 //
978 // Initialize IDE IO port addresses, including Command Block registers
979 // and Control Block registers
980 //
981 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
982 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
983
984 RegisterPointer->Data = CommandBlockBaseAddr;
985 (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
986 RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
987 RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
988 RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
989 RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
990 RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
991 (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
992
993 (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;
994 RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
995 }
996
997 }
998
999
1000 EFI_STATUS
1001 CheckSCSIRequestPacket (
1002 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1003 )
1004 /*++
1005
1006 Routine Description:
1007
1008 Checks the parameters in the SCSI Request Packet to make sure
1009 they are valid for a SCSI Pass Thru request.
1010
1011 Arguments:
1012
1013 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1014
1015 Returns:
1016
1017 EFI_STATUS
1018
1019 --*/
1020 {
1021 if (Packet == NULL) {
1022 return EFI_INVALID_PARAMETER;
1023 }
1024
1025 if (!ValidCdbLength (Packet->CdbLength)) {
1026 return EFI_INVALID_PARAMETER;
1027 }
1028
1029 if (Packet->Cdb == NULL) {
1030 return EFI_INVALID_PARAMETER;
1031 }
1032
1033 //
1034 // Checks whether the request command is supported.
1035 //
1036 if (!IsCommandValid (Packet)) {
1037 return EFI_UNSUPPORTED;
1038 }
1039
1040 return EFI_SUCCESS;
1041 }
1042
1043 /**
1044 Checks the requested SCSI command:
1045 Is it supported by this driver?
1046 Is the Data transfer direction reasonable?
1047
1048 @todo function comment is missing 'Routine Description:'
1049 @todo function comment is missing 'Arguments:'
1050 @todo function comment is missing 'Returns:'
1051 @todo Packet - add argument and description to function comment
1052 **/
1053 BOOLEAN
1054 IsCommandValid (
1055 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1056 )
1057 {
1058 UINT8 Index;
1059 UINT8 *OpCode;
1060
1061 OpCode = (UINT8 *) (Packet->Cdb);
1062
1063 for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {
1064
1065 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
1066 //
1067 // Check whether the requested Command is supported by this driver
1068 //
1069 if (Packet->DataDirection == DataIn) {
1070 //
1071 // Check whether the requested data direction conforms to
1072 // what it should be.
1073 //
1074 if (gSupportedATAPICommands[Index].Direction == DataOut) {
1075 return FALSE;
1076 }
1077 }
1078
1079 if (Packet->DataDirection == DataOut) {
1080 //
1081 // Check whether the requested data direction conforms to
1082 // what it should be.
1083 //
1084 if (gSupportedATAPICommands[Index].Direction == DataIn) {
1085 return FALSE;
1086 }
1087 }
1088
1089 return TRUE;
1090 }
1091 }
1092
1093 return FALSE;
1094 }
1095
1096 /**
1097 Performs blocking I/O request.
1098
1099 @param AtapiScsiPrivate Private data structure for the specified channel.
1100 @param Target The Target ID of the ATAPI device to send the SCSI
1101 Request Packet. To ATAPI devices attached on an IDE
1102 Channel, Target ID 0 indicates Master device;Target
1103 ID 1 indicates Slave device.
1104 @param Packet The SCSI Request Packet to send to the ATAPI device
1105 specified by Target.
1106
1107 @todo AtapiScsiPrivate - add argument and description to function comment
1108 **/
1109 EFI_STATUS
1110 SubmitBlockingIoCommand (
1111 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1112 UINT32 Target,
1113 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1114 )
1115 {
1116 UINT8 PacketCommand[12];
1117 UINT64 TimeoutInMicroSeconds;
1118 EFI_STATUS PacketCommandStatus;
1119
1120 //
1121 // Fill ATAPI Command Packet according to CDB
1122 //
1123 ZeroMem (&PacketCommand, 12);
1124 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
1125
1126 //
1127 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1128 //
1129 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
1130
1131 //
1132 // Submit ATAPI Command Packet
1133 //
1134 PacketCommandStatus = AtapiPacketCommand (
1135 AtapiScsiPrivate,
1136 Target,
1137 PacketCommand,
1138 Packet->DataBuffer,
1139 &(Packet->TransferLength),
1140 (DATA_DIRECTION) Packet->DataDirection,
1141 TimeoutInMicroSeconds
1142 );
1143 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
1144 Packet->SenseDataLength = 0;
1145 return PacketCommandStatus;
1146 }
1147
1148 //
1149 // Check if SenseData meets the alignment requirement.
1150 //
1151 if ((AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 0) \
1152 && (AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 1)) {
1153 if (((UINTN)Packet->SenseData % AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign) != 0) {
1154 return EFI_INVALID_PARAMETER;
1155 }
1156 }
1157
1158
1159 //
1160 // Return SenseData if PacketCommandStatus matches
1161 // the following return codes.
1162 //
1163 if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
1164 (PacketCommandStatus == EFI_DEVICE_ERROR) ||
1165 (PacketCommandStatus == EFI_TIMEOUT)) {
1166
1167 //
1168 // avoid submit request sense command continuously.
1169 //
1170 if (PacketCommand[0] == OP_REQUEST_SENSE) {
1171 Packet->SenseDataLength = 0;
1172 return PacketCommandStatus;
1173 }
1174
1175 RequestSenseCommand (
1176 AtapiScsiPrivate,
1177 Target,
1178 Packet->Timeout,
1179 Packet->SenseData,
1180 &Packet->SenseDataLength
1181 );
1182 }
1183
1184 return PacketCommandStatus;
1185 }
1186
1187 /**
1188 RequestSenseCommand
1189
1190 @param AtapiScsiPrivate
1191 @param Target
1192 @param Timeout
1193 @param SenseData
1194 @param SenseDataLength
1195
1196 @todo Add function description
1197 @todo AtapiScsiPrivate TODO: add argument description
1198 @todo Target TODO: add argument description
1199 @todo Timeout TODO: add argument description
1200 @todo SenseData TODO: add argument description
1201 @todo SenseDataLength TODO: add argument description
1202 @todo add return values
1203 **/
1204 EFI_STATUS
1205 RequestSenseCommand (
1206 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1207 UINT32 Target,
1208 UINT64 Timeout,
1209 VOID *SenseData,
1210 UINT8 *SenseDataLength
1211 )
1212 {
1213 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
1214 UINT8 Cdb[12];
1215 EFI_STATUS Status;
1216
1217 ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1218 ZeroMem (Cdb, 12);
1219
1220 Cdb[0] = OP_REQUEST_SENSE;
1221 Cdb[4] = (UINT8) (*SenseDataLength);
1222
1223 Packet.Timeout = Timeout;
1224 Packet.DataBuffer = SenseData;
1225 Packet.SenseData = NULL;
1226 Packet.Cdb = Cdb;
1227 Packet.TransferLength = *SenseDataLength;
1228 Packet.CdbLength = 12;
1229 Packet.DataDirection = DataIn;
1230
1231 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);
1232 *SenseDataLength = (UINT8) (Packet.TransferLength);
1233 return Status;
1234 }
1235
1236 /**
1237 Submits ATAPI command packet to the specified ATAPI device.
1238
1239 @param AtapiScsiPrivate: Private data structure for the specified channel.
1240 @param Target: The Target ID of the ATAPI device to send the SCSI
1241 Request Packet. To ATAPI devices attached on an IDE
1242 Channel, Target ID 0 indicates Master device;Target
1243 ID 1 indicates Slave device.
1244 @param PacketCommand: Points to the ATAPI command packet.
1245 @param Buffer: Points to the transferred data.
1246 @param ByteCount: When input,indicates the buffer size; when output,
1247 indicates the actually transferred data size.
1248 @param Direction: Indicates the data transfer direction.
1249 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1250 to use for the execution of this ATAPI command.
1251 A TimeoutInMicroSeconds value of 0 means that
1252 this function will wait indefinitely for the ATAPI
1253 command to execute.
1254 <P>
1255 If TimeoutInMicroSeconds is greater than zero, then
1256 this function will return EFI_TIMEOUT if the time
1257 required to execute the ATAPI command is greater
1258 than TimeoutInMicroSeconds.
1259 </P>
1260
1261 @todo AtapiScsiPrivate - add argument and description to function comment
1262 @todo PacketCommand - add argument and description to function comment
1263 @todo Buffer - add argument and description to function comment
1264 @todo ByteCount - add argument and description to function comment
1265 @todo Direction - add argument and description to function comment
1266 **/
1267 EFI_STATUS
1268 AtapiPacketCommand (
1269 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1270 UINT32 Target,
1271 UINT8 *PacketCommand,
1272 VOID *Buffer,
1273 UINT32 *ByteCount,
1274 DATA_DIRECTION Direction,
1275 UINT64 TimeoutInMicroSeconds
1276 )
1277 {
1278
1279 UINT16 *CommandIndex;
1280 UINT8 Count;
1281 EFI_STATUS Status;
1282
1283 //
1284 // Check if the buffer meets the alignment requirement.
1285 //
1286 if ((AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 0) \
1287 && (AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign != 1)) {
1288 if (((UINTN)Buffer % AtapiScsiPrivate->ScsiPassThru.Mode->IoAlign) != 0) {
1289 return EFI_INVALID_PARAMETER;
1290 }
1291 }
1292
1293 //
1294 // Set all the command parameters by fill related registers.
1295 // Before write to all the following registers, BSY must be 0.
1296 //
1297 Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
1298 if (EFI_ERROR (Status)) {
1299 return EFI_DEVICE_ERROR;
1300 }
1301
1302
1303 //
1304 // Select device via Device/Head Register.
1305 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1306 //
1307 WritePortB (
1308 AtapiScsiPrivate->PciIo,
1309 AtapiScsiPrivate->IoPort->Head,
1310 (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
1311 );
1312
1313 //
1314 // Set all the command parameters by fill related registers.
1315 // Before write to all the following registers, BSY DRQ must be 0.
1316 //
1317 Status = StatusDRQClear(AtapiScsiPrivate, TimeoutInMicroSeconds);
1318
1319 if (EFI_ERROR (Status)) {
1320 if (Status == EFI_ABORTED) {
1321 Status = EFI_DEVICE_ERROR;
1322 }
1323 *ByteCount = 0;
1324 return Status;
1325 }
1326
1327 //
1328 // No OVL; No DMA (by setting feature register)
1329 //
1330 WritePortB (
1331 AtapiScsiPrivate->PciIo,
1332 AtapiScsiPrivate->IoPort->Reg1.Feature,
1333 0x00
1334 );
1335
1336 //
1337 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1338 // determine how much data should be transfered.
1339 //
1340 WritePortB (
1341 AtapiScsiPrivate->PciIo,
1342 AtapiScsiPrivate->IoPort->CylinderLsb,
1343 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
1344 );
1345 WritePortB (
1346 AtapiScsiPrivate->PciIo,
1347 AtapiScsiPrivate->IoPort->CylinderMsb,
1348 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
1349 );
1350
1351 //
1352 // DEFAULT_CTL:0x0a (0000,1010)
1353 // Disable interrupt
1354 //
1355 WritePortB (
1356 AtapiScsiPrivate->PciIo,
1357 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
1358 DEFAULT_CTL
1359 );
1360
1361 //
1362 // Send Packet command to inform device
1363 // that the following data bytes are command packet.
1364 //
1365 WritePortB (
1366 AtapiScsiPrivate->PciIo,
1367 AtapiScsiPrivate->IoPort->Reg.Command,
1368 PACKET_CMD
1369 );
1370
1371 //
1372 // Before data transfer, BSY should be 0 and DRQ should be 1.
1373 // if they are not in specified time frame,
1374 // retrieve Sense Key from Error Register before return.
1375 //
1376 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
1377 if (EFI_ERROR (Status)) {
1378 if (Status == EFI_ABORTED) {
1379 Status = EFI_DEVICE_ERROR;
1380 }
1381
1382 *ByteCount = 0;
1383 return Status;
1384 }
1385
1386 //
1387 // Send out command packet
1388 //
1389 CommandIndex = (UINT16 *) PacketCommand;
1390 for (Count = 0; Count < 6; Count++, CommandIndex++) {
1391 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);
1392 }
1393
1394 //
1395 // call AtapiPassThruPioReadWriteData() function to get
1396 // requested transfer data form device.
1397 //
1398 return AtapiPassThruPioReadWriteData (
1399 AtapiScsiPrivate,
1400 Buffer,
1401 ByteCount,
1402 Direction,
1403 TimeoutInMicroSeconds
1404 );
1405 }
1406
1407 /**
1408 Performs data transfer between ATAPI device and host after the
1409 ATAPI command packet is sent.
1410
1411 @param AtapiScsiPrivate: Private data structure for the specified channel.
1412 @param Buffer: Points to the transferred data.
1413 @param ByteCount: When input,indicates the buffer size; when output,
1414 indicates the actually transferred data size.
1415 @param Direction: Indicates the data transfer direction.
1416 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1417 to use for the execution of this ATAPI command.
1418 A TimeoutInMicroSeconds value of 0 means that
1419 this function will wait indefinitely for the ATAPI
1420 command to execute.
1421 <P>
1422 If TimeoutInMicroSeconds is greater than zero, then
1423 this function will return EFI_TIMEOUT if the time
1424 required to execute the ATAPI command is greater
1425 than TimeoutInMicroSeconds.
1426 </P>
1427
1428 @todo AtapiScsiPrivate - add argument and description to function comment
1429 @todo Buffer - add argument and description to function comment
1430 @todo ByteCount - add argument and description to function comment
1431 @todo Direction - add argument and description to function comment
1432 @todo EFI_DEVICE_ERROR - add return value to function comment
1433 @todo EFI_DEVICE_ERROR - add return value to function comment
1434 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1435 **/
1436 EFI_STATUS
1437 AtapiPassThruPioReadWriteData (
1438 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1439 UINT16 *Buffer,
1440 UINT32 *ByteCount,
1441 DATA_DIRECTION Direction,
1442 UINT64 TimeoutInMicroSeconds
1443 )
1444 {
1445 UINT32 Index;
1446 UINT32 RequiredWordCount;
1447 UINT32 ActualWordCount;
1448
1449 UINT32 WordCount;
1450 EFI_STATUS Status;
1451 UINT16 *ptrBuffer;
1452
1453 Status = EFI_SUCCESS;
1454
1455 //
1456 // Non Data transfer request is also supported.
1457 //
1458 if (*ByteCount == 0 || Buffer == NULL) {
1459 *ByteCount = 0;
1460 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {
1461 return EFI_DEVICE_ERROR;
1462 }
1463 }
1464
1465 ptrBuffer = Buffer;
1466 RequiredWordCount = *ByteCount / 2;
1467
1468 //
1469 // ActuralWordCount means the word count of data really transfered.
1470 //
1471 ActualWordCount = 0;
1472
1473 while (ActualWordCount < RequiredWordCount) {
1474 //
1475 // before each data transfer stream, the host should poll DRQ bit ready,
1476 // which indicates device's ready for data transfer .
1477 //
1478 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
1479 if (EFI_ERROR (Status)) {
1480 *ByteCount = ActualWordCount * 2;
1481
1482 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
1483
1484 if (ActualWordCount == 0) {
1485 return EFI_DEVICE_ERROR;
1486 }
1487 //
1488 // ActualWordCount > 0
1489 //
1490 if (ActualWordCount < RequiredWordCount) {
1491 return EFI_BAD_BUFFER_SIZE;
1492 }
1493 }
1494 //
1495 // get current data transfer size from Cylinder Registers.
1496 //
1497 WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;
1498 WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);
1499 WordCount = WordCount & 0xffff;
1500 WordCount /= 2;
1501
1502 //
1503 // perform a series data In/Out.
1504 //
1505 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
1506
1507 if (Direction == DataIn) {
1508
1509 *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);
1510 } else {
1511
1512 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);
1513 }
1514
1515 ptrBuffer++;
1516
1517 }
1518 }
1519 //
1520 // After data transfer is completed, normally, DRQ bit should clear.
1521 //
1522 StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
1523
1524 //
1525 // read status register to check whether error happens.
1526 //
1527 Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
1528
1529 *ByteCount = ActualWordCount * 2;
1530
1531 return Status;
1532 }
1533
1534
1535 /**
1536 Read one byte from a specified I/O port.
1537
1538 @todo function comment is missing 'Routine Description:'
1539 @todo function comment is missing 'Arguments:'
1540 @todo function comment is missing 'Returns:'
1541 @todo PciIo - add argument and description to function comment
1542 @todo Port - add argument and description to function comment
1543 **/
1544 UINT8
1545 ReadPortB (
1546 IN EFI_PCI_IO_PROTOCOL *PciIo,
1547 IN UINT16 Port
1548 )
1549 {
1550 UINT8 Data;
1551
1552 Data = 0;
1553 PciIo->Io.Read (
1554 PciIo,
1555 EfiPciIoWidthUint8,
1556 EFI_PCI_IO_PASS_THROUGH_BAR,
1557 (UINT64) Port,
1558 1,
1559 &Data
1560 );
1561 return Data;
1562 }
1563
1564
1565 /**
1566 Read one word from a specified I/O port.
1567
1568 @todo function comment is missing 'Routine Description:'
1569 @todo function comment is missing 'Arguments:'
1570 @todo function comment is missing 'Returns:'
1571 @todo PciIo - add argument and description to function comment
1572 @todo Port - add argument and description to function comment
1573 **/
1574 UINT16
1575 ReadPortW (
1576 IN EFI_PCI_IO_PROTOCOL *PciIo,
1577 IN UINT16 Port
1578 )
1579 {
1580 UINT16 Data;
1581
1582 Data = 0;
1583 PciIo->Io.Read (
1584 PciIo,
1585 EfiPciIoWidthUint16,
1586 EFI_PCI_IO_PASS_THROUGH_BAR,
1587 (UINT64) Port,
1588 1,
1589 &Data
1590 );
1591 return Data;
1592 }
1593
1594
1595 /**
1596 Write one byte to a specified I/O port.
1597
1598 @todo function comment is missing 'Routine Description:'
1599 @todo function comment is missing 'Arguments:'
1600 @todo function comment is missing 'Returns:'
1601 @todo PciIo - add argument and description to function comment
1602 @todo Port - add argument and description to function comment
1603 @todo Data - add argument and description to function comment
1604 **/
1605 VOID
1606 WritePortB (
1607 IN EFI_PCI_IO_PROTOCOL *PciIo,
1608 IN UINT16 Port,
1609 IN UINT8 Data
1610 )
1611 {
1612
1613 PciIo->Io.Write (
1614 PciIo,
1615 EfiPciIoWidthUint8,
1616 EFI_PCI_IO_PASS_THROUGH_BAR,
1617 (UINT64) Port,
1618 1,
1619 &Data
1620 );
1621
1622 }
1623
1624
1625 /**
1626 Write one word to a specified I/O port.
1627
1628 @todo function comment is missing 'Routine Description:'
1629 @todo function comment is missing 'Arguments:'
1630 @todo function comment is missing 'Returns:'
1631 @todo PciIo - add argument and description to function comment
1632 @todo Port - add argument and description to function comment
1633 @todo Data - add argument and description to function comment
1634 **/
1635 VOID
1636 WritePortW (
1637 IN EFI_PCI_IO_PROTOCOL *PciIo,
1638 IN UINT16 Port,
1639 IN UINT16 Data
1640 )
1641 {
1642
1643 PciIo->Io.Write (
1644 PciIo,
1645 EfiPciIoWidthUint16,
1646 EFI_PCI_IO_PASS_THROUGH_BAR,
1647 (UINT64) Port,
1648 1,
1649 &Data
1650 );
1651 }
1652
1653 /**
1654 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1655 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1656 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1657 elapsed.
1658
1659 @todo function comment is missing 'Routine Description:'
1660 @todo function comment is missing 'Arguments:'
1661 @todo function comment is missing 'Returns:'
1662 @todo AtapiScsiPrivate - add argument and description to function comment
1663 @todo TimeoutInMicroSeconds - add argument and description to function comment
1664 @todo EFI_ABORTED - add return value to function comment
1665 @todo EFI_TIMEOUT - add return value to function comment
1666 @todo EFI_SUCCESS - add return value to function comment
1667 **/
1668 EFI_STATUS
1669 StatusDRQClear (
1670 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1671 UINT64 TimeoutInMicroSeconds
1672 )
1673 {
1674 UINT64 Delay;
1675 UINT8 StatusRegister;
1676 UINT8 ErrRegister;
1677
1678 if (TimeoutInMicroSeconds == 0) {
1679 Delay = 2;
1680 } else {
1681 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1682 }
1683
1684 do {
1685
1686 StatusRegister = ReadPortB (
1687 AtapiScsiPrivate->PciIo,
1688 AtapiScsiPrivate->IoPort->Reg.Status
1689 );
1690
1691 //
1692 // wait for BSY == 0 and DRQ == 0
1693 //
1694 if ((StatusRegister & (DRQ | BSY)) == 0) {
1695 break;
1696 }
1697 //
1698 // check whether the command is aborted by the device
1699 //
1700 if ((StatusRegister & (BSY | ERR)) == ERR) {
1701
1702 ErrRegister = ReadPortB (
1703 AtapiScsiPrivate->PciIo,
1704 AtapiScsiPrivate->IoPort->Reg1.Error
1705 );
1706 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1707
1708 return EFI_ABORTED;
1709 }
1710 }
1711 //
1712 // Stall for 30 us
1713 //
1714 gBS->Stall (30);
1715
1716 //
1717 // Loop infinitely if not meeting expected condition
1718 //
1719 if (TimeoutInMicroSeconds == 0) {
1720 Delay = 2;
1721 }
1722
1723 Delay--;
1724 } while (Delay);
1725
1726 if (Delay == 0) {
1727 return EFI_TIMEOUT;
1728 }
1729
1730 return EFI_SUCCESS;
1731 }
1732
1733 /**
1734 Check whether DRQ is clear in the Alternate Status Register.
1735 (BSY must also be cleared).
1736 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1737 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1738 elapsed.
1739
1740 @todo function comment is missing 'Routine Description:'
1741 @todo function comment is missing 'Arguments:'
1742 @todo function comment is missing 'Returns:'
1743 @todo AtapiScsiPrivate - add argument and description to function comment
1744 @todo TimeoutInMicroSeconds - add argument and description to function comment
1745 @todo EFI_ABORTED - add return value to function comment
1746 @todo EFI_TIMEOUT - add return value to function comment
1747 @todo EFI_SUCCESS - add return value to function comment
1748 **/
1749 EFI_STATUS
1750 AltStatusDRQClear (
1751 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1752 UINT64 TimeoutInMicroSeconds
1753 )
1754 {
1755 UINT64 Delay;
1756 UINT8 AltStatusRegister;
1757 UINT8 ErrRegister;
1758
1759 if (TimeoutInMicroSeconds == 0) {
1760 Delay = 2;
1761 } else {
1762 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1763 }
1764
1765 do {
1766
1767 AltStatusRegister = ReadPortB (
1768 AtapiScsiPrivate->PciIo,
1769 AtapiScsiPrivate->IoPort->Alt.AltStatus
1770 );
1771
1772 //
1773 // wait for BSY == 0 and DRQ == 0
1774 //
1775 if ((AltStatusRegister & (DRQ | BSY)) == 0) {
1776 break;
1777 }
1778
1779 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
1780
1781 ErrRegister = ReadPortB (
1782 AtapiScsiPrivate->PciIo,
1783 AtapiScsiPrivate->IoPort->Reg1.Error
1784 );
1785 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1786
1787 return EFI_ABORTED;
1788 }
1789 }
1790 //
1791 // Stall for 30 us
1792 //
1793 gBS->Stall (30);
1794
1795 //
1796 // Loop infinitely if not meeting expected condition
1797 //
1798 if (TimeoutInMicroSeconds == 0) {
1799 Delay = 2;
1800 }
1801
1802 Delay--;
1803 } while (Delay);
1804
1805 if (Delay == 0) {
1806 return EFI_TIMEOUT;
1807 }
1808
1809 return EFI_SUCCESS;
1810 }
1811
1812 /**
1813 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1814 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1815 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1816 elapsed.
1817
1818 @todo function comment is missing 'Routine Description:'
1819 @todo function comment is missing 'Arguments:'
1820 @todo function comment is missing 'Returns:'
1821 @todo AtapiScsiPrivate - add argument and description to function comment
1822 @todo TimeoutInMicroSeconds - add argument and description to function comment
1823 @todo EFI_ABORTED - add return value to function comment
1824 @todo EFI_TIMEOUT - add return value to function comment
1825 @todo EFI_SUCCESS - add return value to function comment
1826 **/
1827 EFI_STATUS
1828 StatusDRQReady (
1829 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1830 UINT64 TimeoutInMicroSeconds
1831 )
1832 {
1833 UINT64 Delay;
1834 UINT8 StatusRegister;
1835 UINT8 ErrRegister;
1836
1837 if (TimeoutInMicroSeconds == 0) {
1838 Delay = 2;
1839 } else {
1840 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1841 }
1842
1843 do {
1844 //
1845 // read Status Register will clear interrupt
1846 //
1847 StatusRegister = ReadPortB (
1848 AtapiScsiPrivate->PciIo,
1849 AtapiScsiPrivate->IoPort->Reg.Status
1850 );
1851
1852 //
1853 // BSY==0,DRQ==1
1854 //
1855 if ((StatusRegister & (BSY | DRQ)) == DRQ) {
1856 break;
1857 }
1858
1859 if ((StatusRegister & (BSY | ERR)) == ERR) {
1860
1861 ErrRegister = ReadPortB (
1862 AtapiScsiPrivate->PciIo,
1863 AtapiScsiPrivate->IoPort->Reg1.Error
1864 );
1865 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1866 return EFI_ABORTED;
1867 }
1868 }
1869
1870 //
1871 // Stall for 30 us
1872 //
1873 gBS->Stall (30);
1874
1875 //
1876 // Loop infinitely if not meeting expected condition
1877 //
1878 if (TimeoutInMicroSeconds == 0) {
1879 Delay = 2;
1880 }
1881
1882 Delay--;
1883 } while (Delay);
1884
1885 if (Delay == 0) {
1886 return EFI_TIMEOUT;
1887 }
1888
1889 return EFI_SUCCESS;
1890 }
1891
1892 /**
1893 Check whether DRQ is ready in the Alternate Status Register.
1894 (BSY must also be cleared)
1895 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1896 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1897 elapsed.
1898
1899 @todo function comment is missing 'Routine Description:'
1900 @todo function comment is missing 'Arguments:'
1901 @todo function comment is missing 'Returns:'
1902 @todo AtapiScsiPrivate - add argument and description to function comment
1903 @todo TimeoutInMicroSeconds - add argument and description to function comment
1904 @todo EFI_ABORTED - add return value to function comment
1905 @todo EFI_TIMEOUT - add return value to function comment
1906 @todo EFI_SUCCESS - add return value to function comment
1907 **/
1908 EFI_STATUS
1909 AltStatusDRQReady (
1910 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1911 UINT64 TimeoutInMicroSeconds
1912 )
1913 {
1914 UINT64 Delay;
1915 UINT8 AltStatusRegister;
1916 UINT8 ErrRegister;
1917
1918 if (TimeoutInMicroSeconds == 0) {
1919 Delay = 2;
1920 } else {
1921 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1922 }
1923
1924 do {
1925 //
1926 // read Status Register will clear interrupt
1927 //
1928 AltStatusRegister = ReadPortB (
1929 AtapiScsiPrivate->PciIo,
1930 AtapiScsiPrivate->IoPort->Alt.AltStatus
1931 );
1932 //
1933 // BSY==0,DRQ==1
1934 //
1935 if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {
1936 break;
1937 }
1938
1939 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
1940
1941 ErrRegister = ReadPortB (
1942 AtapiScsiPrivate->PciIo,
1943 AtapiScsiPrivate->IoPort->Reg1.Error
1944 );
1945 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1946 return EFI_ABORTED;
1947 }
1948 }
1949
1950 //
1951 // Stall for 30 us
1952 //
1953 gBS->Stall (30);
1954
1955 //
1956 // Loop infinitely if not meeting expected condition
1957 //
1958 if (TimeoutInMicroSeconds == 0) {
1959 Delay = 2;
1960 }
1961
1962 Delay--;
1963 } while (Delay);
1964
1965 if (Delay == 0) {
1966 return EFI_TIMEOUT;
1967 }
1968
1969 return EFI_SUCCESS;
1970 }
1971
1972 /**
1973 Check whether BSY is clear in the Status Register.
1974 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1975 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1976 elapsed.
1977
1978 @todo function comment is missing 'Routine Description:'
1979 @todo function comment is missing 'Arguments:'
1980 @todo function comment is missing 'Returns:'
1981 @todo AtapiScsiPrivate - add argument and description to function comment
1982 @todo TimeoutInMicroSeconds - add argument and description to function comment
1983 @todo EFI_TIMEOUT - add return value to function comment
1984 @todo EFI_SUCCESS - add return value to function comment
1985 **/
1986 EFI_STATUS
1987 StatusWaitForBSYClear (
1988 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1989 UINT64 TimeoutInMicroSeconds
1990 )
1991 {
1992 UINT64 Delay;
1993 UINT8 StatusRegister;
1994
1995 if (TimeoutInMicroSeconds == 0) {
1996 Delay = 2;
1997 } else {
1998 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1999 }
2000
2001 do {
2002
2003 StatusRegister = ReadPortB (
2004 AtapiScsiPrivate->PciIo,
2005 AtapiScsiPrivate->IoPort->Reg.Status
2006 );
2007 if ((StatusRegister & BSY) == 0x00) {
2008 break;
2009 }
2010
2011 //
2012 // Stall for 30 us
2013 //
2014 gBS->Stall (30);
2015
2016 //
2017 // Loop infinitely if not meeting expected condition
2018 //
2019 if (TimeoutInMicroSeconds == 0) {
2020 Delay = 2;
2021 }
2022
2023 Delay--;
2024 } while (Delay);
2025
2026 if (Delay == 0) {
2027 return EFI_TIMEOUT;
2028 }
2029
2030 return EFI_SUCCESS;
2031 }
2032
2033 /**
2034 Check whether BSY is clear in the Alternate Status Register.
2035 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2036 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2037 elapsed.
2038
2039 @todo function comment is missing 'Routine Description:'
2040 @todo function comment is missing 'Arguments:'
2041 @todo function comment is missing 'Returns:'
2042 @todo AtapiScsiPrivate - add argument and description to function comment
2043 @todo TimeoutInMicroSeconds - add argument and description to function comment
2044 @todo EFI_TIMEOUT - add return value to function comment
2045 @todo EFI_SUCCESS - add return value to function comment
2046 **/
2047 EFI_STATUS
2048 AltStatusWaitForBSYClear (
2049 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2050 UINT64 TimeoutInMicroSeconds
2051 )
2052 {
2053 UINT64 Delay;
2054 UINT8 AltStatusRegister;
2055
2056 if (TimeoutInMicroSeconds == 0) {
2057 Delay = 2;
2058 } else {
2059 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2060 }
2061
2062 do {
2063
2064 AltStatusRegister = ReadPortB (
2065 AtapiScsiPrivate->PciIo,
2066 AtapiScsiPrivate->IoPort->Alt.AltStatus
2067 );
2068 if ((AltStatusRegister & BSY) == 0x00) {
2069 break;
2070 }
2071
2072 //
2073 // Stall for 30 us
2074 //
2075 gBS->Stall (30);
2076 //
2077 // Loop infinitely if not meeting expected condition
2078 //
2079 if (TimeoutInMicroSeconds == 0) {
2080 Delay = 2;
2081 }
2082
2083 Delay--;
2084 } while (Delay);
2085
2086 if (Delay == 0) {
2087 return EFI_TIMEOUT;
2088 }
2089
2090 return EFI_SUCCESS;
2091 }
2092
2093 /**
2094 Check whether DRDY is ready in the Status Register.
2095 (BSY must also be cleared)
2096 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2097 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2098 elapsed.
2099
2100 @todo function comment is missing 'Routine Description:'
2101 @todo function comment is missing 'Arguments:'
2102 @todo function comment is missing 'Returns:'
2103 @todo AtapiScsiPrivate - add argument and description to function comment
2104 @todo TimeoutInMicroSeconds - add argument and description to function comment
2105 @todo EFI_ABORTED - add return value to function comment
2106 @todo EFI_TIMEOUT - add return value to function comment
2107 @todo EFI_SUCCESS - add return value to function comment
2108 **/
2109 EFI_STATUS
2110 StatusDRDYReady (
2111 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2112 UINT64 TimeoutInMicroSeconds
2113 )
2114 {
2115 UINT64 Delay;
2116 UINT8 StatusRegister;
2117 UINT8 ErrRegister;
2118
2119 if (TimeoutInMicroSeconds == 0) {
2120 Delay = 2;
2121 } else {
2122 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2123 }
2124
2125 do {
2126 StatusRegister = ReadPortB (
2127 AtapiScsiPrivate->PciIo,
2128 AtapiScsiPrivate->IoPort->Reg.Status
2129 );
2130 //
2131 // BSY == 0 , DRDY == 1
2132 //
2133 if ((StatusRegister & (DRDY | BSY)) == DRDY) {
2134 break;
2135 }
2136
2137 if ((StatusRegister & (BSY | ERR)) == ERR) {
2138
2139 ErrRegister = ReadPortB (
2140 AtapiScsiPrivate->PciIo,
2141 AtapiScsiPrivate->IoPort->Reg1.Error
2142 );
2143 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2144 return EFI_ABORTED;
2145 }
2146 }
2147
2148 //
2149 // Stall for 30 us
2150 //
2151 gBS->Stall (30);
2152 //
2153 // Loop infinitely if not meeting expected condition
2154 //
2155 if (TimeoutInMicroSeconds == 0) {
2156 Delay = 2;
2157 }
2158
2159 Delay--;
2160 } while (Delay);
2161
2162 if (Delay == 0) {
2163 return EFI_TIMEOUT;
2164 }
2165
2166 return EFI_SUCCESS;
2167 }
2168
2169 /**
2170 Check whether DRDY is ready in the Alternate Status Register.
2171 (BSY must also be cleared)
2172 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2173 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2174 elapsed.
2175
2176 @todo function comment is missing 'Routine Description:'
2177 @todo function comment is missing 'Arguments:'
2178 @todo function comment is missing 'Returns:'
2179 @todo AtapiScsiPrivate - add argument and description to function comment
2180 @todo TimeoutInMicroSeconds - add argument and description to function comment
2181 @todo EFI_ABORTED - add return value to function comment
2182 @todo EFI_TIMEOUT - add return value to function comment
2183 @todo EFI_SUCCESS - add return value to function comment
2184 **/
2185 EFI_STATUS
2186 AltStatusDRDYReady (
2187 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2188 UINT64 TimeoutInMicroSeconds
2189 )
2190 {
2191 UINT64 Delay;
2192 UINT8 AltStatusRegister;
2193 UINT8 ErrRegister;
2194
2195 if (TimeoutInMicroSeconds == 0) {
2196 Delay = 2;
2197 } else {
2198 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2199 }
2200
2201 do {
2202 AltStatusRegister = ReadPortB (
2203 AtapiScsiPrivate->PciIo,
2204 AtapiScsiPrivate->IoPort->Alt.AltStatus
2205 );
2206 //
2207 // BSY == 0 , DRDY == 1
2208 //
2209 if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {
2210 break;
2211 }
2212
2213 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
2214
2215 ErrRegister = ReadPortB (
2216 AtapiScsiPrivate->PciIo,
2217 AtapiScsiPrivate->IoPort->Reg1.Error
2218 );
2219 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2220 return EFI_ABORTED;
2221 }
2222 }
2223
2224 //
2225 // Stall for 30 us
2226 //
2227 gBS->Stall (30);
2228 //
2229 // Loop infinitely if not meeting expected condition
2230 //
2231 if (TimeoutInMicroSeconds == 0) {
2232 Delay = 2;
2233 }
2234
2235 Delay--;
2236 } while (Delay);
2237
2238 if (Delay == 0) {
2239 return EFI_TIMEOUT;
2240 }
2241
2242 return EFI_SUCCESS;
2243 }
2244
2245 /**
2246 Check Error Register for Error Information.
2247
2248 @todo function comment is missing 'Routine Description:'
2249 @todo function comment is missing 'Arguments:'
2250 @todo function comment is missing 'Returns:'
2251 @todo AtapiScsiPrivate - add argument and description to function comment
2252 @todo EFI_SUCCESS - add return value to function comment
2253 @todo EFI_DEVICE_ERROR - add return value to function comment
2254 **/
2255 EFI_STATUS
2256 AtapiPassThruCheckErrorStatus (
2257 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
2258 )
2259 {
2260 UINT8 StatusRegister;
2261 UINT8 ErrorRegister;
2262
2263 StatusRegister = ReadPortB (
2264 AtapiScsiPrivate->PciIo,
2265 AtapiScsiPrivate->IoPort->Reg.Status
2266 );
2267
2268 DEBUG_CODE_BEGIN ();
2269
2270 if (StatusRegister & DWF) {
2271 DEBUG (
2272 (EFI_D_BLKIO,
2273 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2274 StatusRegister)
2275 );
2276 }
2277
2278 if (StatusRegister & CORR) {
2279 DEBUG (
2280 (EFI_D_BLKIO,
2281 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2282 StatusRegister)
2283 );
2284 }
2285
2286 if (StatusRegister & ERR) {
2287 ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);
2288
2289
2290 if (ErrorRegister & BBK_ERR) {
2291 DEBUG (
2292 (EFI_D_BLKIO,
2293 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2294 ErrorRegister)
2295 );
2296 }
2297
2298 if (ErrorRegister & UNC_ERR) {
2299 DEBUG (
2300 (EFI_D_BLKIO,
2301 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2302 ErrorRegister)
2303 );
2304 }
2305
2306 if (ErrorRegister & MC_ERR) {
2307 DEBUG (
2308 (EFI_D_BLKIO,
2309 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2310 ErrorRegister)
2311 );
2312 }
2313
2314 if (ErrorRegister & ABRT_ERR) {
2315 DEBUG (
2316 (EFI_D_BLKIO,
2317 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2318 ErrorRegister)
2319 );
2320 }
2321
2322 if (ErrorRegister & TK0NF_ERR) {
2323 DEBUG (
2324 (EFI_D_BLKIO,
2325 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2326 ErrorRegister)
2327 );
2328 }
2329
2330 if (ErrorRegister & AMNF_ERR) {
2331 DEBUG (
2332 (EFI_D_BLKIO,
2333 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2334 ErrorRegister)
2335 );
2336 }
2337 }
2338
2339 DEBUG_CODE_END ();
2340
2341 if ((StatusRegister & (ERR | DWF | CORR)) == 0) {
2342 return EFI_SUCCESS;
2343 }
2344
2345
2346 return EFI_DEVICE_ERROR;
2347 }
2348
2349 /**
2350 The user Entry Point for module AtapiPassThru. The user code starts with this function.
2351
2352 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2353 @param[in] SystemTable A pointer to the EFI System Table.
2354
2355 @retval EFI_SUCCESS The entry point is executed successfully.
2356 @retval other Some error occurs when executing this entry point.
2357
2358 **/
2359 EFI_STATUS
2360 EFIAPI
2361 InitializeAtapiPassThru(
2362 IN EFI_HANDLE ImageHandle,
2363 IN EFI_SYSTEM_TABLE *SystemTable
2364 )
2365 {
2366 EFI_STATUS Status;
2367
2368 //
2369 // Install driver model protocol(s).
2370 //
2371 Status = EfiLibInstallDriverBindingComponentName2 (
2372 ImageHandle,
2373 SystemTable,
2374 &gAtapiScsiPassThruDriverBinding,
2375 ImageHandle,
2376 &gAtapiScsiPassThruComponentName,
2377 &gAtapiScsiPassThruComponentName2
2378 );
2379 ASSERT_EFI_ERROR (Status);
2380
2381 return Status;
2382 }