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