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