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