]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c
e48cf73235f54fdf53a9ba0ffae1b6cb331c6aa0
[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, 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, 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 0x10,
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 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
599 EFI_DEV_PATH *Node;
600
601 //
602 // Retrieve Device Private Data Structure.
603 //
604 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
605
606 //
607 // Validate parameters passed in.
608 //
609
610 if (DevicePath == NULL) {
611 return EFI_INVALID_PARAMETER;
612 }
613
614 //
615 // can not build device path for the SCSI Host Controller.
616 //
617 if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
618 return EFI_NOT_FOUND;
619 }
620
621 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
622 if (Node == NULL) {
623 return EFI_OUT_OF_RESOURCES;
624 }
625
626 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
627 Node->DevPath.SubType = MSG_ATAPI_DP;
628 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
629
630 Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);
631 Node->Atapi.SlaveMaster = (UINT8) (Target % 2);
632 Node->Atapi.Lun = (UINT16) Lun;
633
634 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
635
636 return EFI_SUCCESS;
637 }
638
639 /**
640 Used to translate a device path node to a Target ID and LUN.
641
642 @param This Protocol instance pointer.
643 @param DevicePath A pointer to the device path node that
644 describes a SCSI device on the SCSI channel.
645 @param Target A pointer to the Target ID of a SCSI device
646 on the SCSI channel.
647 @param Lun A pointer to the LUN of a SCSI device on
648 the SCSI channel.
649
650 @retval EFI_SUCCESS DevicePath was successfully translated to a
651 Target ID and LUN, and they were returned
652 in Target and Lun.
653 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
654 @retval EFI_INVALID_PARAMETER Target is NULL.
655 @retval EFI_INVALID_PARAMETER Lun is NULL.
656 @retval EFI_UNSUPPORTED This driver does not support the device path
657 node type in DevicePath.
658 @retval EFI_NOT_FOUND A valid translation from DevicePath to a
659 Target ID and LUN does not exist.
660
661 **/
662 EFI_STATUS
663 EFIAPI
664 AtapiScsiPassThruGetTargetLun (
665 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
666 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
667 OUT UINT32 *Target,
668 OUT UINT64 *Lun
669 )
670 {
671 EFI_DEV_PATH *Node;
672
673 //
674 // Validate parameters passed in.
675 //
676 if (DevicePath == NULL || Target == NULL || Lun == NULL) {
677 return EFI_INVALID_PARAMETER;
678 }
679
680 //
681 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
682 //
683 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
684 (DevicePath->SubType != MSG_ATAPI_DP) ||
685 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
686 return EFI_UNSUPPORTED;
687 }
688
689 Node = (EFI_DEV_PATH *) DevicePath;
690
691 *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;
692 *Lun = Node->Atapi.Lun;
693
694 if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {
695 return EFI_NOT_FOUND;
696 }
697
698 return EFI_SUCCESS;
699 }
700
701 /**
702 Resets a SCSI channel.This operation resets all the
703 SCSI devices connected to the SCSI channel.
704
705 @param This Protocol instance pointer.
706
707 @retval EFI_SUCCESS The SCSI channel was reset.
708 @retval EFI_UNSUPPORTED The SCSI channel does not support
709 a channel reset operation.
710 @retval EFI_DEVICE_ERROR A device error occurred while
711 attempting to reset the SCSI channel.
712 @retval EFI_TIMEOUT A timeout occurred while attempting
713 to reset the SCSI channel.
714
715 **/
716 EFI_STATUS
717 EFIAPI
718 AtapiScsiPassThruResetChannel (
719 IN EFI_SCSI_PASS_THRU_PROTOCOL *This
720 )
721 {
722 UINT8 DeviceControlValue;
723 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
724 UINT8 Index;
725
726 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
727
728 //
729 // Reset both Primary channel and Secondary channel.
730 // so, the IoPort pointer must point to the right I/O Register group
731 //
732 for (Index = 0; Index < 2; Index++) {
733 //
734 // Reset
735 //
736 AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[Index];
737
738 DeviceControlValue = 0;
739 //
740 // set SRST bit to initiate soft reset
741 //
742 DeviceControlValue |= SRST;
743 //
744 // disable Interrupt
745 //
746 DeviceControlValue |= bit (1);
747 WritePortB (
748 AtapiScsiPrivate->PciIo,
749 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
750 DeviceControlValue
751 );
752
753 //
754 // Wait 10us
755 //
756 gBS->Stall (10);
757
758 //
759 // Clear SRST bit
760 // 0xfb:1111,1011
761 //
762 DeviceControlValue &= 0xfb;
763
764 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
765
766 //
767 // slave device needs at most 31s to clear BSY
768 //
769 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000) == EFI_TIMEOUT) {
770 return EFI_DEVICE_ERROR;
771 }
772 }
773
774 return EFI_SUCCESS;
775 }
776
777 /**
778 Resets a SCSI device that is connected to a SCSI channel.
779
780 @param This Protocol instance pointer.
781 @param Target The Target ID of the SCSI device to reset.
782 @param Lun The LUN of the SCSI device to reset.
783
784 @retval EFI_SUCCESS The SCSI device specified by Target and
785 Lun was reset.
786 @retval EFI_UNSUPPORTED The SCSI channel does not support a target
787 reset operation.
788 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.
789 @retval EFI_DEVICE_ERROR A device error occurred while attempting
790 to reset the SCSI device specified by Target
791 and Lun.
792 @retval EFI_TIMEOUT A timeout occurred while attempting to reset
793 the SCSI device specified by Target and Lun.
794
795 **/
796 EFI_STATUS
797 EFIAPI
798 AtapiScsiPassThruResetTarget (
799 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
800 IN UINT32 Target,
801 IN UINT64 Lun
802 )
803 {
804 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
805 UINT8 Command;
806 UINT8 DeviceSelect;
807
808 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
809
810 if (Target > MAX_TARGET_ID) {
811 return EFI_INVALID_PARAMETER;
812 }
813 //
814 // Directly return EFI_SUCCESS if want to reset the host controller
815 //
816 if (Target == This->Mode->AdapterId) {
817 return EFI_SUCCESS;
818 }
819
820 //
821 // According to Target ID, reset the Atapi I/O Register mapping
822 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],
823 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]
824 //
825 if ((Target / 2) == 0) {
826 AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0];
827 } else {
828 AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[1];
829 }
830
831 //
832 // for ATAPI device, no need to wait DRDY ready after device selecting.
833 //
834 // bit7 and bit5 are both set to 1 for backward compatibility
835 //
836 DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (Target << 4)));
837 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
838
839 Command = ATAPI_SOFT_RESET_CMD;
840 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
841
842 //
843 // BSY clear is the only status return to the host by the device
844 // when reset is complete.
845 // slave device needs at most 31s to clear BSY
846 //
847 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000))) {
848 return EFI_DEVICE_ERROR;
849 }
850
851 //
852 // stall 5 seconds to make the device status stable
853 //
854 gBS->Stall (5000000);
855
856 return EFI_SUCCESS;
857 }
858
859
860 /**
861 Checks the parameters in the SCSI Request Packet to make sure
862 they are valid for a SCSI Pass Thru request.
863
864 @todo function comment is missing 'Routine Description:'
865 @todo function comment is missing 'Arguments:'
866 @todo function comment is missing 'Returns:'
867 @todo Packet - add argument and description to function comment
868 @todo EFI_INVALID_PARAMETER - add return value to function comment
869 @todo EFI_INVALID_PARAMETER - add return value to function comment
870 @todo EFI_INVALID_PARAMETER - add return value to function comment
871 @todo EFI_UNSUPPORTED - add return value to function comment
872 @todo EFI_SUCCESS - add return value to function comment
873 **/
874 EFI_STATUS
875 CheckSCSIRequestPacket (
876 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
877 )
878 {
879 if (Packet == NULL) {
880 return EFI_INVALID_PARAMETER;
881 }
882
883 if (!ValidCdbLength (Packet->CdbLength)) {
884 return EFI_INVALID_PARAMETER;
885 }
886
887 if (Packet->Cdb == NULL) {
888 return EFI_INVALID_PARAMETER;
889 }
890
891 //
892 // Checks whether the request command is supported.
893 //
894 if (!IsCommandValid (Packet)) {
895 return EFI_UNSUPPORTED;
896 }
897
898 return EFI_SUCCESS;
899 }
900
901 /**
902 Checks the requested SCSI command:
903 Is it supported by this driver?
904 Is the Data transfer direction reasonable?
905
906 @todo function comment is missing 'Routine Description:'
907 @todo function comment is missing 'Arguments:'
908 @todo function comment is missing 'Returns:'
909 @todo Packet - add argument and description to function comment
910 **/
911 BOOLEAN
912 IsCommandValid (
913 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
914 )
915 {
916 UINT8 Index;
917 UINT8 *OpCode;
918
919 OpCode = (UINT8 *) (Packet->Cdb);
920
921 for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {
922
923 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
924 //
925 // Check whether the requested Command is supported by this driver
926 //
927 if (Packet->DataDirection == DataIn) {
928 //
929 // Check whether the requested data direction conforms to
930 // what it should be.
931 //
932 if (gSupportedATAPICommands[Index].Direction == DataOut) {
933 return FALSE;
934 }
935 }
936
937 if (Packet->DataDirection == DataOut) {
938 //
939 // Check whether the requested data direction conforms to
940 // what it should be.
941 //
942 if (gSupportedATAPICommands[Index].Direction == DataIn) {
943 return FALSE;
944 }
945 }
946
947 return TRUE;
948 }
949 }
950
951 return FALSE;
952 }
953
954 /**
955 Performs blocking I/O request.
956
957 @param AtapiScsiPrivate Private data structure for the specified channel.
958 @param Target The Target ID of the ATAPI device to send the SCSI
959 Request Packet. To ATAPI devices attached on an IDE
960 Channel, Target ID 0 indicates Master device;Target
961 ID 1 indicates Slave device.
962 @param Packet The SCSI Request Packet to send to the ATAPI device
963 specified by Target.
964
965 @todo AtapiScsiPrivate - add argument and description to function comment
966 **/
967 EFI_STATUS
968 SubmitBlockingIoCommand (
969 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
970 UINT32 Target,
971 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
972 )
973 {
974 UINT8 PacketCommand[12];
975 UINT64 TimeoutInMicroSeconds;
976 EFI_STATUS PacketCommandStatus;
977
978 //
979 // Fill ATAPI Command Packet according to CDB
980 //
981 ZeroMem (&PacketCommand, 12);
982 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
983
984 //
985 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
986 //
987 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
988
989 //
990 // Submit ATAPI Command Packet
991 //
992 PacketCommandStatus = AtapiPacketCommand (
993 AtapiScsiPrivate,
994 Target,
995 PacketCommand,
996 Packet->DataBuffer,
997 &(Packet->TransferLength),
998 Packet->DataDirection,
999 TimeoutInMicroSeconds
1000 );
1001 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
1002 Packet->SenseDataLength = 0;
1003 return PacketCommandStatus;
1004 }
1005 //
1006 // Return SenseData if PacketCommandStatus matches
1007 // the following return codes.
1008 //
1009 if ((PacketCommandStatus == EFI_WARN_BUFFER_TOO_SMALL) ||
1010 (PacketCommandStatus == EFI_DEVICE_ERROR) ||
1011 (PacketCommandStatus == EFI_TIMEOUT)) {
1012
1013 //
1014 // avoid submit request sense command continuously.
1015 //
1016 if (PacketCommand[0] == OP_REQUEST_SENSE) {
1017 Packet->SenseDataLength = 0;
1018 return PacketCommandStatus;
1019 }
1020
1021 RequestSenseCommand (
1022 AtapiScsiPrivate,
1023 Target,
1024 Packet->Timeout,
1025 Packet->SenseData,
1026 &Packet->SenseDataLength
1027 );
1028 }
1029
1030 return PacketCommandStatus;
1031 }
1032
1033 /**
1034 RequestSenseCommand
1035
1036 @param AtapiScsiPrivate
1037 @param Target
1038 @param Timeout
1039 @param SenseData
1040 @param SenseDataLength
1041
1042 @todo Add function description
1043 @todo AtapiScsiPrivate TODO: add argument description
1044 @todo Target TODO: add argument description
1045 @todo Timeout TODO: add argument description
1046 @todo SenseData TODO: add argument description
1047 @todo SenseDataLength TODO: add argument description
1048 @todo add return values
1049 **/
1050 EFI_STATUS
1051 RequestSenseCommand (
1052 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1053 UINT32 Target,
1054 UINT64 Timeout,
1055 VOID *SenseData,
1056 UINT8 *SenseDataLength
1057 )
1058 {
1059 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
1060 UINT8 Cdb[12];
1061 EFI_STATUS Status;
1062
1063 ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1064 ZeroMem (Cdb, 12);
1065
1066 Cdb[0] = OP_REQUEST_SENSE;
1067 Cdb[4] = (UINT8) (*SenseDataLength);
1068
1069 Packet.Timeout = Timeout;
1070 Packet.DataBuffer = SenseData;
1071 Packet.SenseData = NULL;
1072 Packet.Cdb = Cdb;
1073 Packet.TransferLength = *SenseDataLength;
1074 Packet.CdbLength = 12;
1075 Packet.DataDirection = DataIn;
1076
1077 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);
1078 *SenseDataLength = (UINT8) (Packet.TransferLength);
1079 return Status;
1080 }
1081
1082 /**
1083 Submits ATAPI command packet to the specified ATAPI device.
1084
1085 @param AtapiScsiPrivate: Private data structure for the specified channel.
1086 @param Target: The Target ID of the ATAPI device to send the SCSI
1087 Request Packet. To ATAPI devices attached on an IDE
1088 Channel, Target ID 0 indicates Master device;Target
1089 ID 1 indicates Slave device.
1090 @param PacketCommand: Points to the ATAPI command packet.
1091 @param Buffer: Points to the transferred data.
1092 @param ByteCount: When input,indicates the buffer size; when output,
1093 indicates the actually transferred data size.
1094 @param Direction: Indicates the data transfer direction.
1095 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1096 to use for the execution of this ATAPI command.
1097 A TimeoutInMicroSeconds value of 0 means that
1098 this function will wait indefinitely for the ATAPI
1099 command to execute.
1100 <P>
1101 If TimeoutInMicroSeconds is greater than zero, then
1102 this function will return EFI_TIMEOUT if the time
1103 required to execute the ATAPI command is greater
1104 than TimeoutInMicroSeconds.
1105 </P>
1106
1107 @todo AtapiScsiPrivate - add argument and description to function comment
1108 @todo PacketCommand - add argument and description to function comment
1109 @todo Buffer - add argument and description to function comment
1110 @todo ByteCount - add argument and description to function comment
1111 @todo Direction - add argument and description to function comment
1112 **/
1113 EFI_STATUS
1114 AtapiPacketCommand (
1115 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1116 UINT32 Target,
1117 UINT8 *PacketCommand,
1118 VOID *Buffer,
1119 UINT32 *ByteCount,
1120 DATA_DIRECTION Direction,
1121 UINT64 TimeoutInMicroSeconds
1122 )
1123 {
1124
1125 UINT16 *CommandIndex;
1126 UINT8 Count;
1127 EFI_STATUS Status;
1128
1129 //
1130 // Set all the command parameters by fill related registers.
1131 // Before write to all the following registers, BSY and DRQ must be 0.
1132 //
1133 Status = StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
1134 if (EFI_ERROR (Status)) {
1135 if (Status == EFI_ABORTED) {
1136 Status = EFI_DEVICE_ERROR;
1137 }
1138
1139 *ByteCount = 0;
1140 return Status;
1141 }
1142 //
1143 // Select device via Device/Head Register.
1144 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
1145 //
1146 WritePortB (
1147 AtapiScsiPrivate->PciIo,
1148 AtapiScsiPrivate->IoPort->Head,
1149 (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
1150 );
1151
1152 //
1153 // No OVL; No DMA (by setting feature register)
1154 //
1155 WritePortB (
1156 AtapiScsiPrivate->PciIo,
1157 AtapiScsiPrivate->IoPort->Reg1.Feature,
1158 0x00
1159 );
1160
1161 //
1162 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
1163 // determine how much data should be transfered.
1164 //
1165 WritePortB (
1166 AtapiScsiPrivate->PciIo,
1167 AtapiScsiPrivate->IoPort->CylinderLsb,
1168 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
1169 );
1170 WritePortB (
1171 AtapiScsiPrivate->PciIo,
1172 AtapiScsiPrivate->IoPort->CylinderMsb,
1173 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
1174 );
1175
1176 //
1177 // DEFAULT_CTL:0x0a (0000,1010)
1178 // Disable interrupt
1179 //
1180 WritePortB (
1181 AtapiScsiPrivate->PciIo,
1182 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
1183 DEFAULT_CTL
1184 );
1185
1186 //
1187 // Send Packet command to inform device
1188 // that the following data bytes are command packet.
1189 //
1190 WritePortB (
1191 AtapiScsiPrivate->PciIo,
1192 AtapiScsiPrivate->IoPort->Reg.Command,
1193 PACKET_CMD
1194 );
1195
1196 //
1197 // Before data transfer, BSY should be 0 and DRQ should be 1.
1198 // if they are not in specified time frame,
1199 // retrieve Sense Key from Error Register before return.
1200 //
1201 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
1202 if (EFI_ERROR (Status)) {
1203 if (Status == EFI_ABORTED) {
1204 Status = EFI_DEVICE_ERROR;
1205 }
1206
1207 *ByteCount = 0;
1208 return Status;
1209 }
1210
1211 //
1212 // Send out command packet
1213 //
1214 CommandIndex = (UINT16 *) PacketCommand;
1215 for (Count = 0; Count < 6; Count++, CommandIndex++) {
1216 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);
1217 }
1218
1219 //
1220 // call AtapiPassThruPioReadWriteData() function to get
1221 // requested transfer data form device.
1222 //
1223 return AtapiPassThruPioReadWriteData (
1224 AtapiScsiPrivate,
1225 Buffer,
1226 ByteCount,
1227 Direction,
1228 TimeoutInMicroSeconds
1229 );
1230 }
1231
1232 /**
1233 Performs data transfer between ATAPI device and host after the
1234 ATAPI command packet is sent.
1235
1236 @param AtapiScsiPrivate: Private data structure for the specified channel.
1237 @param Buffer: Points to the transferred data.
1238 @param ByteCount: When input,indicates the buffer size; when output,
1239 indicates the actually transferred data size.
1240 @param Direction: Indicates the data transfer direction.
1241 @param TimeoutInMicroSeconds: The timeout, in micro second units,
1242 to use for the execution of this ATAPI command.
1243 A TimeoutInMicroSeconds value of 0 means that
1244 this function will wait indefinitely for the ATAPI
1245 command to execute.
1246 <P>
1247 If TimeoutInMicroSeconds is greater than zero, then
1248 this function will return EFI_TIMEOUT if the time
1249 required to execute the ATAPI command is greater
1250 than TimeoutInMicroSeconds.
1251 </P>
1252
1253 @todo AtapiScsiPrivate - add argument and description to function comment
1254 @todo Buffer - add argument and description to function comment
1255 @todo ByteCount - add argument and description to function comment
1256 @todo Direction - add argument and description to function comment
1257 @todo EFI_DEVICE_ERROR - add return value to function comment
1258 @todo EFI_DEVICE_ERROR - add return value to function comment
1259 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment
1260 **/
1261 EFI_STATUS
1262 AtapiPassThruPioReadWriteData (
1263 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1264 UINT16 *Buffer,
1265 UINT32 *ByteCount,
1266 DATA_DIRECTION Direction,
1267 UINT64 TimeoutInMicroSeconds
1268 )
1269 {
1270 UINT32 Index;
1271 UINT32 RequiredWordCount;
1272 UINT32 ActualWordCount;
1273
1274 UINT32 WordCount;
1275 EFI_STATUS Status;
1276 UINT16 *ptrBuffer;
1277
1278 Status = EFI_SUCCESS;
1279
1280 //
1281 // Non Data transfer request is also supported.
1282 //
1283 if (*ByteCount == 0 || Buffer == NULL) {
1284 *ByteCount = 0;
1285 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {
1286 return EFI_DEVICE_ERROR;
1287 }
1288 }
1289
1290 ptrBuffer = Buffer;
1291 RequiredWordCount = *ByteCount / 2;
1292
1293 //
1294 // ActuralWordCount means the word count of data really transfered.
1295 //
1296 ActualWordCount = 0;
1297
1298 while (ActualWordCount < RequiredWordCount) {
1299 //
1300 // before each data transfer stream, the host should poll DRQ bit ready,
1301 // which indicates device's ready for data transfer .
1302 //
1303 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
1304 if (EFI_ERROR (Status)) {
1305 *ByteCount = ActualWordCount * 2;
1306
1307 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
1308
1309 if (ActualWordCount == 0) {
1310 return EFI_DEVICE_ERROR;
1311 }
1312 //
1313 // ActualWordCount > 0
1314 //
1315 if (ActualWordCount < RequiredWordCount) {
1316 return EFI_WARN_BUFFER_TOO_SMALL;
1317 }
1318 }
1319 //
1320 // get current data transfer size from Cylinder Registers.
1321 //
1322 WordCount =
1323 (
1324 (ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8) |
1325 ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb)
1326 ) & 0xffff;
1327 WordCount /= 2;
1328
1329 //
1330 // perform a series data In/Out.
1331 //
1332 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
1333
1334 if (Direction == DataIn) {
1335
1336 *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);
1337 } else {
1338
1339 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);
1340 }
1341
1342 ptrBuffer++;
1343
1344 }
1345 }
1346 //
1347 // After data transfer is completed, normally, DRQ bit should clear.
1348 //
1349 StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
1350
1351 //
1352 // read status register to check whether error happens.
1353 //
1354 Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
1355
1356 *ByteCount = ActualWordCount * 2;
1357
1358 return Status;
1359 }
1360
1361
1362 /**
1363 Read one byte from a specified I/O port.
1364
1365 @todo function comment is missing 'Routine Description:'
1366 @todo function comment is missing 'Arguments:'
1367 @todo function comment is missing 'Returns:'
1368 @todo PciIo - add argument and description to function comment
1369 @todo Port - add argument and description to function comment
1370 **/
1371 UINT8
1372 ReadPortB (
1373 IN EFI_PCI_IO_PROTOCOL *PciIo,
1374 IN UINT16 Port
1375 )
1376 {
1377 UINT8 Data;
1378
1379 Data = 0;
1380 PciIo->Io.Read (
1381 PciIo,
1382 EfiPciIoWidthUint8,
1383 EFI_PCI_IO_PASS_THROUGH_BAR,
1384 (UINT64) Port,
1385 1,
1386 &Data
1387 );
1388 return Data;
1389 }
1390
1391
1392 /**
1393 Read one word from a specified I/O port.
1394
1395 @todo function comment is missing 'Routine Description:'
1396 @todo function comment is missing 'Arguments:'
1397 @todo function comment is missing 'Returns:'
1398 @todo PciIo - add argument and description to function comment
1399 @todo Port - add argument and description to function comment
1400 **/
1401 UINT16
1402 ReadPortW (
1403 IN EFI_PCI_IO_PROTOCOL *PciIo,
1404 IN UINT16 Port
1405 )
1406 {
1407 UINT16 Data;
1408
1409 Data = 0;
1410 PciIo->Io.Read (
1411 PciIo,
1412 EfiPciIoWidthUint16,
1413 EFI_PCI_IO_PASS_THROUGH_BAR,
1414 (UINT64) Port,
1415 1,
1416 &Data
1417 );
1418 return Data;
1419 }
1420
1421
1422 /**
1423 Write one byte to a specified I/O port.
1424
1425 @todo function comment is missing 'Routine Description:'
1426 @todo function comment is missing 'Arguments:'
1427 @todo function comment is missing 'Returns:'
1428 @todo PciIo - add argument and description to function comment
1429 @todo Port - add argument and description to function comment
1430 @todo Data - add argument and description to function comment
1431 **/
1432 VOID
1433 WritePortB (
1434 IN EFI_PCI_IO_PROTOCOL *PciIo,
1435 IN UINT16 Port,
1436 IN UINT8 Data
1437 )
1438 {
1439
1440 PciIo->Io.Write (
1441 PciIo,
1442 EfiPciIoWidthUint8,
1443 EFI_PCI_IO_PASS_THROUGH_BAR,
1444 (UINT64) Port,
1445 1,
1446 &Data
1447 );
1448
1449 }
1450
1451
1452 /**
1453 Write one word to a specified I/O port.
1454
1455 @todo function comment is missing 'Routine Description:'
1456 @todo function comment is missing 'Arguments:'
1457 @todo function comment is missing 'Returns:'
1458 @todo PciIo - add argument and description to function comment
1459 @todo Port - add argument and description to function comment
1460 @todo Data - add argument and description to function comment
1461 **/
1462 VOID
1463 WritePortW (
1464 IN EFI_PCI_IO_PROTOCOL *PciIo,
1465 IN UINT16 Port,
1466 IN UINT16 Data
1467 )
1468 {
1469
1470 PciIo->Io.Write (
1471 PciIo,
1472 EfiPciIoWidthUint16,
1473 EFI_PCI_IO_PASS_THROUGH_BAR,
1474 (UINT64) Port,
1475 1,
1476 &Data
1477 );
1478 }
1479
1480 /**
1481 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
1482 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1483 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1484 elapsed.
1485
1486 @todo function comment is missing 'Routine Description:'
1487 @todo function comment is missing 'Arguments:'
1488 @todo function comment is missing 'Returns:'
1489 @todo AtapiScsiPrivate - add argument and description to function comment
1490 @todo TimeoutInMicroSeconds - add argument and description to function comment
1491 @todo EFI_ABORTED - add return value to function comment
1492 @todo EFI_TIMEOUT - add return value to function comment
1493 @todo EFI_SUCCESS - add return value to function comment
1494 **/
1495 EFI_STATUS
1496 StatusDRQClear (
1497 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1498 UINT64 TimeoutInMicroSeconds
1499 )
1500 {
1501 UINT64 Delay;
1502 UINT8 StatusRegister;
1503 UINT8 ErrRegister;
1504
1505 if (TimeoutInMicroSeconds == 0) {
1506 Delay = 2;
1507 } else {
1508 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1509 }
1510
1511 do {
1512
1513 StatusRegister = ReadPortB (
1514 AtapiScsiPrivate->PciIo,
1515 AtapiScsiPrivate->IoPort->Reg.Status
1516 );
1517
1518 //
1519 // wait for BSY == 0 and DRQ == 0
1520 //
1521 if ((StatusRegister & (DRQ | BSY)) == 0) {
1522 break;
1523 }
1524 //
1525 // check whether the command is aborted by the device
1526 //
1527 if ((StatusRegister & (BSY | ERR)) == ERR) {
1528
1529 ErrRegister = ReadPortB (
1530 AtapiScsiPrivate->PciIo,
1531 AtapiScsiPrivate->IoPort->Reg1.Error
1532 );
1533 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1534
1535 return EFI_ABORTED;
1536 }
1537 }
1538 //
1539 // Stall for 30 us
1540 //
1541 gBS->Stall (30);
1542
1543 //
1544 // Loop infinitely if not meeting expected condition
1545 //
1546 if (TimeoutInMicroSeconds == 0) {
1547 Delay = 2;
1548 }
1549
1550 Delay--;
1551 } while (Delay);
1552
1553 if (Delay == 0) {
1554 return EFI_TIMEOUT;
1555 }
1556
1557 return EFI_SUCCESS;
1558 }
1559
1560 /**
1561 Check whether DRQ is clear in the Alternate Status Register.
1562 (BSY must also be cleared).
1563 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1564 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1565 elapsed.
1566
1567 @todo function comment is missing 'Routine Description:'
1568 @todo function comment is missing 'Arguments:'
1569 @todo function comment is missing 'Returns:'
1570 @todo AtapiScsiPrivate - add argument and description to function comment
1571 @todo TimeoutInMicroSeconds - add argument and description to function comment
1572 @todo EFI_ABORTED - add return value to function comment
1573 @todo EFI_TIMEOUT - add return value to function comment
1574 @todo EFI_SUCCESS - add return value to function comment
1575 **/
1576 EFI_STATUS
1577 AltStatusDRQClear (
1578 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1579 UINT64 TimeoutInMicroSeconds
1580 )
1581 {
1582 UINT64 Delay;
1583 UINT8 AltStatusRegister;
1584 UINT8 ErrRegister;
1585
1586 if (TimeoutInMicroSeconds == 0) {
1587 Delay = 2;
1588 } else {
1589 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1590 }
1591
1592 do {
1593
1594 AltStatusRegister = ReadPortB (
1595 AtapiScsiPrivate->PciIo,
1596 AtapiScsiPrivate->IoPort->Alt.AltStatus
1597 );
1598
1599 //
1600 // wait for BSY == 0 and DRQ == 0
1601 //
1602 if ((AltStatusRegister & (DRQ | BSY)) == 0) {
1603 break;
1604 }
1605
1606 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
1607
1608 ErrRegister = ReadPortB (
1609 AtapiScsiPrivate->PciIo,
1610 AtapiScsiPrivate->IoPort->Reg1.Error
1611 );
1612 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1613
1614 return EFI_ABORTED;
1615 }
1616 }
1617 //
1618 // Stall for 30 us
1619 //
1620 gBS->Stall (30);
1621
1622 //
1623 // Loop infinitely if not meeting expected condition
1624 //
1625 if (TimeoutInMicroSeconds == 0) {
1626 Delay = 2;
1627 }
1628
1629 Delay--;
1630 } while (Delay);
1631
1632 if (Delay == 0) {
1633 return EFI_TIMEOUT;
1634 }
1635
1636 return EFI_SUCCESS;
1637 }
1638
1639 /**
1640 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
1641 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1642 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1643 elapsed.
1644
1645 @todo function comment is missing 'Routine Description:'
1646 @todo function comment is missing 'Arguments:'
1647 @todo function comment is missing 'Returns:'
1648 @todo AtapiScsiPrivate - add argument and description to function comment
1649 @todo TimeoutInMicroSeconds - add argument and description to function comment
1650 @todo EFI_ABORTED - add return value to function comment
1651 @todo EFI_TIMEOUT - add return value to function comment
1652 @todo EFI_SUCCESS - add return value to function comment
1653 **/
1654 EFI_STATUS
1655 StatusDRQReady (
1656 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1657 UINT64 TimeoutInMicroSeconds
1658 )
1659 {
1660 UINT64 Delay;
1661 UINT8 StatusRegister;
1662 UINT8 ErrRegister;
1663
1664 if (TimeoutInMicroSeconds == 0) {
1665 Delay = 2;
1666 } else {
1667 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1668 }
1669
1670 do {
1671 //
1672 // read Status Register will clear interrupt
1673 //
1674 StatusRegister = ReadPortB (
1675 AtapiScsiPrivate->PciIo,
1676 AtapiScsiPrivate->IoPort->Reg.Status
1677 );
1678
1679 //
1680 // BSY==0,DRQ==1
1681 //
1682 if ((StatusRegister & (BSY | DRQ)) == DRQ) {
1683 break;
1684 }
1685
1686 if ((StatusRegister & (BSY | ERR)) == ERR) {
1687
1688 ErrRegister = ReadPortB (
1689 AtapiScsiPrivate->PciIo,
1690 AtapiScsiPrivate->IoPort->Reg1.Error
1691 );
1692 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1693 return EFI_ABORTED;
1694 }
1695 }
1696
1697 //
1698 // Stall for 30 us
1699 //
1700 gBS->Stall (30);
1701
1702 //
1703 // Loop infinitely if not meeting expected condition
1704 //
1705 if (TimeoutInMicroSeconds == 0) {
1706 Delay = 2;
1707 }
1708
1709 Delay--;
1710 } while (Delay);
1711
1712 if (Delay == 0) {
1713 return EFI_TIMEOUT;
1714 }
1715
1716 return EFI_SUCCESS;
1717 }
1718
1719 /**
1720 Check whether DRQ is ready in the Alternate Status Register.
1721 (BSY must also be cleared)
1722 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1723 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1724 elapsed.
1725
1726 @todo function comment is missing 'Routine Description:'
1727 @todo function comment is missing 'Arguments:'
1728 @todo function comment is missing 'Returns:'
1729 @todo AtapiScsiPrivate - add argument and description to function comment
1730 @todo TimeoutInMicroSeconds - add argument and description to function comment
1731 @todo EFI_ABORTED - add return value to function comment
1732 @todo EFI_TIMEOUT - add return value to function comment
1733 @todo EFI_SUCCESS - add return value to function comment
1734 **/
1735 EFI_STATUS
1736 AltStatusDRQReady (
1737 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1738 UINT64 TimeoutInMicroSeconds
1739 )
1740 {
1741 UINT64 Delay;
1742 UINT8 AltStatusRegister;
1743 UINT8 ErrRegister;
1744
1745 if (TimeoutInMicroSeconds == 0) {
1746 Delay = 2;
1747 } else {
1748 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1749 }
1750
1751 do {
1752 //
1753 // read Status Register will clear interrupt
1754 //
1755 AltStatusRegister = ReadPortB (
1756 AtapiScsiPrivate->PciIo,
1757 AtapiScsiPrivate->IoPort->Alt.AltStatus
1758 );
1759 //
1760 // BSY==0,DRQ==1
1761 //
1762 if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {
1763 break;
1764 }
1765
1766 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
1767
1768 ErrRegister = ReadPortB (
1769 AtapiScsiPrivate->PciIo,
1770 AtapiScsiPrivate->IoPort->Reg1.Error
1771 );
1772 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1773 return EFI_ABORTED;
1774 }
1775 }
1776
1777 //
1778 // Stall for 30 us
1779 //
1780 gBS->Stall (30);
1781
1782 //
1783 // Loop infinitely if not meeting expected condition
1784 //
1785 if (TimeoutInMicroSeconds == 0) {
1786 Delay = 2;
1787 }
1788
1789 Delay--;
1790 } while (Delay);
1791
1792 if (Delay == 0) {
1793 return EFI_TIMEOUT;
1794 }
1795
1796 return EFI_SUCCESS;
1797 }
1798
1799 /**
1800 Check whether BSY is clear in the Status Register.
1801 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1802 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1803 elapsed.
1804
1805 @todo function comment is missing 'Routine Description:'
1806 @todo function comment is missing 'Arguments:'
1807 @todo function comment is missing 'Returns:'
1808 @todo AtapiScsiPrivate - add argument and description to function comment
1809 @todo TimeoutInMicroSeconds - add argument and description to function comment
1810 @todo EFI_TIMEOUT - add return value to function comment
1811 @todo EFI_SUCCESS - add return value to function comment
1812 **/
1813 EFI_STATUS
1814 StatusWaitForBSYClear (
1815 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1816 UINT64 TimeoutInMicroSeconds
1817 )
1818 {
1819 UINT64 Delay;
1820 UINT8 StatusRegister;
1821
1822 if (TimeoutInMicroSeconds == 0) {
1823 Delay = 2;
1824 } else {
1825 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1826 }
1827
1828 do {
1829
1830 StatusRegister = ReadPortB (
1831 AtapiScsiPrivate->PciIo,
1832 AtapiScsiPrivate->IoPort->Reg.Status
1833 );
1834 if ((StatusRegister & BSY) == 0x00) {
1835 break;
1836 }
1837
1838 //
1839 // Stall for 30 us
1840 //
1841 gBS->Stall (30);
1842
1843 //
1844 // Loop infinitely if not meeting expected condition
1845 //
1846 if (TimeoutInMicroSeconds == 0) {
1847 Delay = 2;
1848 }
1849
1850 Delay--;
1851 } while (Delay);
1852
1853 if (Delay == 0) {
1854 return EFI_TIMEOUT;
1855 }
1856
1857 return EFI_SUCCESS;
1858 }
1859
1860 /**
1861 Check whether BSY is clear in the Alternate Status Register.
1862 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1863 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
1864 elapsed.
1865
1866 @todo function comment is missing 'Routine Description:'
1867 @todo function comment is missing 'Arguments:'
1868 @todo function comment is missing 'Returns:'
1869 @todo AtapiScsiPrivate - add argument and description to function comment
1870 @todo TimeoutInMicroSeconds - add argument and description to function comment
1871 @todo EFI_TIMEOUT - add return value to function comment
1872 @todo EFI_SUCCESS - add return value to function comment
1873 **/
1874 EFI_STATUS
1875 AltStatusWaitForBSYClear (
1876 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1877 UINT64 TimeoutInMicroSeconds
1878 )
1879 {
1880 UINT64 Delay;
1881 UINT8 AltStatusRegister;
1882
1883 if (TimeoutInMicroSeconds == 0) {
1884 Delay = 2;
1885 } else {
1886 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1887 }
1888
1889 do {
1890
1891 AltStatusRegister = ReadPortB (
1892 AtapiScsiPrivate->PciIo,
1893 AtapiScsiPrivate->IoPort->Alt.AltStatus
1894 );
1895 if ((AltStatusRegister & BSY) == 0x00) {
1896 break;
1897 }
1898
1899 //
1900 // Stall for 30 us
1901 //
1902 gBS->Stall (30);
1903 //
1904 // Loop infinitely if not meeting expected condition
1905 //
1906 if (TimeoutInMicroSeconds == 0) {
1907 Delay = 2;
1908 }
1909
1910 Delay--;
1911 } while (Delay);
1912
1913 if (Delay == 0) {
1914 return EFI_TIMEOUT;
1915 }
1916
1917 return EFI_SUCCESS;
1918 }
1919
1920 /**
1921 Check whether DRDY is ready in the Status Register.
1922 (BSY must also be cleared)
1923 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
1924 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
1925 elapsed.
1926
1927 @todo function comment is missing 'Routine Description:'
1928 @todo function comment is missing 'Arguments:'
1929 @todo function comment is missing 'Returns:'
1930 @todo AtapiScsiPrivate - add argument and description to function comment
1931 @todo TimeoutInMicroSeconds - add argument and description to function comment
1932 @todo EFI_ABORTED - add return value to function comment
1933 @todo EFI_TIMEOUT - add return value to function comment
1934 @todo EFI_SUCCESS - add return value to function comment
1935 **/
1936 EFI_STATUS
1937 StatusDRDYReady (
1938 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1939 UINT64 TimeoutInMicroSeconds
1940 )
1941 {
1942 UINT64 Delay;
1943 UINT8 StatusRegister;
1944 UINT8 ErrRegister;
1945
1946 if (TimeoutInMicroSeconds == 0) {
1947 Delay = 2;
1948 } else {
1949 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
1950 }
1951
1952 do {
1953 StatusRegister = ReadPortB (
1954 AtapiScsiPrivate->PciIo,
1955 AtapiScsiPrivate->IoPort->Reg.Status
1956 );
1957 //
1958 // BSY == 0 , DRDY == 1
1959 //
1960 if ((StatusRegister & (DRDY | BSY)) == DRDY) {
1961 break;
1962 }
1963
1964 if ((StatusRegister & (BSY | ERR)) == ERR) {
1965
1966 ErrRegister = ReadPortB (
1967 AtapiScsiPrivate->PciIo,
1968 AtapiScsiPrivate->IoPort->Reg1.Error
1969 );
1970 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
1971 return EFI_ABORTED;
1972 }
1973 }
1974
1975 //
1976 // Stall for 30 us
1977 //
1978 gBS->Stall (30);
1979 //
1980 // Loop infinitely if not meeting expected condition
1981 //
1982 if (TimeoutInMicroSeconds == 0) {
1983 Delay = 2;
1984 }
1985
1986 Delay--;
1987 } while (Delay);
1988
1989 if (Delay == 0) {
1990 return EFI_TIMEOUT;
1991 }
1992
1993 return EFI_SUCCESS;
1994 }
1995
1996 /**
1997 Check whether DRDY is ready in the Alternate Status Register.
1998 (BSY must also be cleared)
1999 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2000 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2001 elapsed.
2002
2003 @todo function comment is missing 'Routine Description:'
2004 @todo function comment is missing 'Arguments:'
2005 @todo function comment is missing 'Returns:'
2006 @todo AtapiScsiPrivate - add argument and description to function comment
2007 @todo TimeoutInMicroSeconds - add argument and description to function comment
2008 @todo EFI_ABORTED - add return value to function comment
2009 @todo EFI_TIMEOUT - add return value to function comment
2010 @todo EFI_SUCCESS - add return value to function comment
2011 **/
2012 EFI_STATUS
2013 AltStatusDRDYReady (
2014 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2015 UINT64 TimeoutInMicroSeconds
2016 )
2017 {
2018 UINT64 Delay;
2019 UINT8 AltStatusRegister;
2020 UINT8 ErrRegister;
2021
2022 if (TimeoutInMicroSeconds == 0) {
2023 Delay = 2;
2024 } else {
2025 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2026 }
2027
2028 do {
2029 AltStatusRegister = ReadPortB (
2030 AtapiScsiPrivate->PciIo,
2031 AtapiScsiPrivate->IoPort->Alt.AltStatus
2032 );
2033 //
2034 // BSY == 0 , DRDY == 1
2035 //
2036 if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {
2037 break;
2038 }
2039
2040 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
2041
2042 ErrRegister = ReadPortB (
2043 AtapiScsiPrivate->PciIo,
2044 AtapiScsiPrivate->IoPort->Reg1.Error
2045 );
2046 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2047 return EFI_ABORTED;
2048 }
2049 }
2050
2051 //
2052 // Stall for 30 us
2053 //
2054 gBS->Stall (30);
2055 //
2056 // Loop infinitely if not meeting expected condition
2057 //
2058 if (TimeoutInMicroSeconds == 0) {
2059 Delay = 2;
2060 }
2061
2062 Delay--;
2063 } while (Delay);
2064
2065 if (Delay == 0) {
2066 return EFI_TIMEOUT;
2067 }
2068
2069 return EFI_SUCCESS;
2070 }
2071
2072 /**
2073 Check Error Register for Error Information.
2074
2075 @todo function comment is missing 'Routine Description:'
2076 @todo function comment is missing 'Arguments:'
2077 @todo function comment is missing 'Returns:'
2078 @todo AtapiScsiPrivate - add argument and description to function comment
2079 @todo EFI_SUCCESS - add return value to function comment
2080 @todo EFI_DEVICE_ERROR - add return value to function comment
2081 **/
2082 EFI_STATUS
2083 AtapiPassThruCheckErrorStatus (
2084 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
2085 )
2086 {
2087 UINT8 StatusRegister;
2088 UINT8 ErrorRegister;
2089
2090 StatusRegister = ReadPortB (
2091 AtapiScsiPrivate->PciIo,
2092 AtapiScsiPrivate->IoPort->Reg.Status
2093 );
2094
2095 DEBUG_CODE_BEGIN ();
2096
2097 if (StatusRegister & DWF) {
2098 DEBUG (
2099 (EFI_D_BLKIO,
2100 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
2101 StatusRegister)
2102 );
2103 }
2104
2105 if (StatusRegister & CORR) {
2106 DEBUG (
2107 (EFI_D_BLKIO,
2108 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
2109 StatusRegister)
2110 );
2111 }
2112
2113 if (StatusRegister & ERR) {
2114 ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);
2115
2116
2117 if (ErrorRegister & BBK_ERR) {
2118 DEBUG (
2119 (EFI_D_BLKIO,
2120 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
2121 ErrorRegister)
2122 );
2123 }
2124
2125 if (ErrorRegister & UNC_ERR) {
2126 DEBUG (
2127 (EFI_D_BLKIO,
2128 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
2129 ErrorRegister)
2130 );
2131 }
2132
2133 if (ErrorRegister & MC_ERR) {
2134 DEBUG (
2135 (EFI_D_BLKIO,
2136 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
2137 ErrorRegister)
2138 );
2139 }
2140
2141 if (ErrorRegister & ABRT_ERR) {
2142 DEBUG (
2143 (EFI_D_BLKIO,
2144 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
2145 ErrorRegister)
2146 );
2147 }
2148
2149 if (ErrorRegister & TK0NF_ERR) {
2150 DEBUG (
2151 (EFI_D_BLKIO,
2152 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
2153 ErrorRegister)
2154 );
2155 }
2156
2157 if (ErrorRegister & AMNF_ERR) {
2158 DEBUG (
2159 (EFI_D_BLKIO,
2160 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
2161 ErrorRegister)
2162 );
2163 }
2164 }
2165
2166 DEBUG_CODE_END ();
2167
2168 if ((StatusRegister & (ERR | DWF | CORR)) == 0) {
2169 return EFI_SUCCESS;
2170 }
2171
2172
2173 return EFI_DEVICE_ERROR;
2174 }