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