]> git.proxmox.com Git - mirror_edk2.git/blob - OptionRomPkg/AtapiPassThruDxe/AtapiPassThru.c
MdeModulePkg/UefiBootManagerLib: fix crash on uninitialized ExitData
[mirror_edk2.git] / OptionRomPkg / AtapiPassThruDxe / AtapiPassThru.c
1 /** @file
2 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
3 SPDX-License-Identifier: BSD-2-Clause-Patent
4
5 **/
6
7 #include "AtapiPassThru.h"
8
9
10 SCSI_COMMAND_SET gEndTable = { 0xff, (DATA_DIRECTION) 0xff };
11
12 ///
13 /// This table contains all the supported ATAPI commands.
14 ///
15 SCSI_COMMAND_SET gSupportedATAPICommands[] = {
16 { OP_INQUIRY, DataIn },
17 { OP_LOAD_UNLOAD_CD, NoData },
18 { OP_MECHANISM_STATUS, DataIn },
19 { OP_MODE_SELECT_10, DataOut },
20 { OP_MODE_SENSE_10, DataIn },
21 { OP_PAUSE_RESUME, NoData },
22 { OP_PLAY_AUDIO_10, DataIn },
23 { OP_PLAY_AUDIO_MSF, DataIn },
24 { OP_PLAY_CD, DataIn },
25 { OP_PLAY_CD_MSF, DataIn },
26 { OP_PREVENT_ALLOW_MEDIUM_REMOVAL,NoData },
27 { OP_READ_10, DataIn },
28 { OP_READ_12, DataIn },
29 { OP_READ_CAPACITY, DataIn },
30 { OP_READ_CD, DataIn },
31 { OP_READ_CD_MSF, DataIn },
32 { OP_READ_HEADER, DataIn },
33 { OP_READ_SUB_CHANNEL, DataIn },
34 { OP_READ_TOC, DataIn },
35 { OP_REQUEST_SENSE, DataIn },
36 { OP_SCAN, NoData },
37 { OP_SEEK_10, NoData },
38 { OP_SET_CD_SPEED, DataOut },
39 { OP_STOPPLAY_SCAN, NoData },
40 { OP_START_STOP_UNIT, NoData },
41 { OP_TEST_UNIT_READY, NoData },
42 { OP_FORMAT_UNIT, DataOut },
43 { OP_READ_FORMAT_CAPACITIES, DataIn },
44 { OP_VERIFY, DataOut },
45 { OP_WRITE_10, DataOut },
46 { OP_WRITE_12, DataOut },
47 { OP_WRITE_AND_VERIFY, DataOut },
48 { 0xff, (DATA_DIRECTION) 0xff }
49 };
50
51 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_MODE gScsiPassThruMode = {
52 L"ATAPI Controller",
53 L"ATAPI Channel",
54 4,
55 EFI_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
56 0
57 };
58
59 GLOBAL_REMOVE_IF_UNREFERENCED EFI_SCSI_PASS_THRU_PROTOCOL gScsiPassThruProtocolTemplate = {
60 &gScsiPassThruMode,
61 AtapiScsiPassThruFunction,
62 AtapiScsiPassThruGetNextDevice,
63 AtapiScsiPassThruBuildDevicePath,
64 AtapiScsiPassThruGetTargetLun,
65 AtapiScsiPassThruResetChannel,
66 AtapiScsiPassThruResetTarget
67 };
68
69 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_MODE gExtScsiPassThruMode = {
70 4,
71 EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL,
72 0
73 };
74
75 GLOBAL_REMOVE_IF_UNREFERENCED EFI_EXT_SCSI_PASS_THRU_PROTOCOL gExtScsiPassThruProtocolTemplate = {
76 &gExtScsiPassThruMode,
77 AtapiExtScsiPassThruFunction,
78 AtapiExtScsiPassThruGetNextTargetLun,
79 AtapiExtScsiPassThruBuildDevicePath,
80 AtapiExtScsiPassThruGetTargetLun,
81 AtapiExtScsiPassThruResetChannel,
82 AtapiExtScsiPassThruResetTarget,
83 AtapiExtScsiPassThruGetNextTarget
84 };
85
86 EFI_DRIVER_BINDING_PROTOCOL gAtapiScsiPassThruDriverBinding = {
87 AtapiScsiPassThruDriverBindingSupported,
88 AtapiScsiPassThruDriverBindingStart,
89 AtapiScsiPassThruDriverBindingStop,
90 0x10,
91 NULL,
92 NULL
93 };
94
95 EFI_STATUS
96 EFIAPI
97 AtapiScsiPassThruDriverBindingSupported (
98 IN EFI_DRIVER_BINDING_PROTOCOL *This,
99 IN EFI_HANDLE Controller,
100 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
101 )
102 /*++
103
104 Routine Description:
105 Test to see if this driver supports ControllerHandle. Any ControllerHandle
106 that has gEfiPciIoProtocolGuid installed and is IDE Controller it will be supported.
107
108 Arguments:
109
110 This - Protocol instance pointer.
111 Controller - Handle of device to test
112 RemainingDevicePath - Not used
113
114 Returns:
115 EFI_STATUS
116
117 --*/
118 {
119 EFI_STATUS Status;
120 EFI_PCI_IO_PROTOCOL *PciIo;
121 PCI_TYPE00 Pci;
122
123
124 //
125 // Open the IO Abstraction(s) needed to perform the supported test
126 //
127 Status = gBS->OpenProtocol (
128 Controller,
129 &gEfiPciIoProtocolGuid,
130 (VOID **) &PciIo,
131 This->DriverBindingHandle,
132 Controller,
133 EFI_OPEN_PROTOCOL_BY_DRIVER
134 );
135 if (EFI_ERROR (Status)) {
136 return Status;
137 }
138 //
139 // Use the PCI I/O Protocol to see if Controller is a IDE Controller that
140 // can be managed by this driver. Read the PCI Configuration Header
141 // for this device.
142 //
143 Status = PciIo->Pci.Read (
144 PciIo,
145 EfiPciIoWidthUint32,
146 0,
147 sizeof (Pci) / sizeof (UINT32),
148 &Pci
149 );
150 if (EFI_ERROR (Status)) {
151 gBS->CloseProtocol (
152 Controller,
153 &gEfiPciIoProtocolGuid,
154 This->DriverBindingHandle,
155 Controller
156 );
157 return EFI_UNSUPPORTED;
158 }
159
160 if (Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE || Pci.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE) {
161
162 Status = EFI_UNSUPPORTED;
163 }
164
165 gBS->CloseProtocol (
166 Controller,
167 &gEfiPciIoProtocolGuid,
168 This->DriverBindingHandle,
169 Controller
170 );
171
172 return Status;
173 }
174
175 EFI_STATUS
176 EFIAPI
177 AtapiScsiPassThruDriverBindingStart (
178 IN EFI_DRIVER_BINDING_PROTOCOL *This,
179 IN EFI_HANDLE Controller,
180 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
181 )
182 /*++
183
184 Routine Description:
185 Create handles for IDE channels specified by RemainingDevicePath.
186 Install SCSI Pass Thru Protocol onto each created handle.
187
188 Arguments:
189
190 This - Protocol instance pointer.
191 Controller - Handle of device to test
192 RemainingDevicePath - Not used
193
194 Returns:
195 EFI_STATUS
196
197 --*/
198 {
199 EFI_STATUS Status;
200 EFI_PCI_IO_PROTOCOL *PciIo;
201 UINT64 Supports;
202 UINT64 OriginalPciAttributes;
203 BOOLEAN PciAttributesSaved;
204
205 PciIo = NULL;
206 Status = gBS->OpenProtocol (
207 Controller,
208 &gEfiPciIoProtocolGuid,
209 (VOID **) &PciIo,
210 This->DriverBindingHandle,
211 Controller,
212 EFI_OPEN_PROTOCOL_BY_DRIVER
213 );
214 if (EFI_ERROR (Status)) {
215 return Status;
216 }
217
218 PciAttributesSaved = FALSE;
219 //
220 // Save original PCI attributes
221 //
222 Status = PciIo->Attributes (
223 PciIo,
224 EfiPciIoAttributeOperationGet,
225 0,
226 &OriginalPciAttributes
227 );
228
229 if (EFI_ERROR (Status)) {
230 goto Done;
231 }
232 PciAttributesSaved = TRUE;
233
234 Status = PciIo->Attributes (
235 PciIo,
236 EfiPciIoAttributeOperationSupported,
237 0,
238 &Supports
239 );
240 if (!EFI_ERROR (Status)) {
241 Supports &= (EFI_PCI_DEVICE_ENABLE |
242 EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO |
243 EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO);
244 Status = PciIo->Attributes (
245 PciIo,
246 EfiPciIoAttributeOperationEnable,
247 Supports,
248 NULL
249 );
250 }
251 if (EFI_ERROR (Status)) {
252 goto Done;
253 }
254
255 //
256 // Create SCSI Pass Thru instance for the IDE channel.
257 //
258 Status = RegisterAtapiScsiPassThru (This, Controller, PciIo, OriginalPciAttributes);
259
260 Done:
261 if (EFI_ERROR (Status)) {
262 if (PciAttributesSaved == TRUE) {
263 //
264 // Restore original PCI attributes
265 //
266 PciIo->Attributes (
267 PciIo,
268 EfiPciIoAttributeOperationSet,
269 OriginalPciAttributes,
270 NULL
271 );
272 }
273
274 gBS->CloseProtocol (
275 Controller,
276 &gEfiPciIoProtocolGuid,
277 This->DriverBindingHandle,
278 Controller
279 );
280 }
281
282 return Status;
283 }
284
285 EFI_STATUS
286 EFIAPI
287 AtapiScsiPassThruDriverBindingStop (
288 IN EFI_DRIVER_BINDING_PROTOCOL *This,
289 IN EFI_HANDLE Controller,
290 IN UINTN NumberOfChildren,
291 IN EFI_HANDLE *ChildHandleBuffer
292 )
293 /*++
294
295 Routine Description:
296
297 Stop this driver on ControllerHandle. Support stopping any child handles
298 created by this driver.
299
300 Arguments:
301
302 This - Protocol instance pointer.
303 Controller - Handle of device to stop driver on
304 NumberOfChildren - Number of Children in the ChildHandleBuffer
305 ChildHandleBuffer - List of handles for the children we need to stop.
306
307 Returns:
308
309 EFI_STATUS
310
311 --*/
312 {
313 EFI_STATUS Status;
314 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
315 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
316 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
317
318 if (FeaturePcdGet (PcdSupportScsiPassThru)) {
319 Status = gBS->OpenProtocol (
320 Controller,
321 &gEfiScsiPassThruProtocolGuid,
322 (VOID **) &ScsiPassThru,
323 This->DriverBindingHandle,
324 Controller,
325 EFI_OPEN_PROTOCOL_GET_PROTOCOL
326 );
327 if (EFI_ERROR (Status)) {
328 return Status;
329 }
330 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (ScsiPassThru);
331 if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
332 Status = gBS->UninstallMultipleProtocolInterfaces (
333 Controller,
334 &gEfiScsiPassThruProtocolGuid,
335 &AtapiScsiPrivate->ScsiPassThru,
336 &gEfiExtScsiPassThruProtocolGuid,
337 &AtapiScsiPrivate->ExtScsiPassThru,
338 NULL
339 );
340 } else {
341 Status = gBS->UninstallMultipleProtocolInterfaces (
342 Controller,
343 &gEfiScsiPassThruProtocolGuid,
344 &AtapiScsiPrivate->ScsiPassThru,
345 NULL
346 );
347 }
348 } else {
349 Status = gBS->OpenProtocol (
350 Controller,
351 &gEfiExtScsiPassThruProtocolGuid,
352 (VOID **) &ExtScsiPassThru,
353 This->DriverBindingHandle,
354 Controller,
355 EFI_OPEN_PROTOCOL_GET_PROTOCOL
356 );
357 if (EFI_ERROR (Status)) {
358 return Status;
359 }
360 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (ExtScsiPassThru);
361 Status = gBS->UninstallMultipleProtocolInterfaces (
362 Controller,
363 &gEfiExtScsiPassThruProtocolGuid,
364 &AtapiScsiPrivate->ExtScsiPassThru,
365 NULL
366 );
367 }
368 if (EFI_ERROR (Status)) {
369 return Status;
370 }
371
372 //
373 // Restore original PCI attributes
374 //
375 AtapiScsiPrivate->PciIo->Attributes (
376 AtapiScsiPrivate->PciIo,
377 EfiPciIoAttributeOperationSet,
378 AtapiScsiPrivate->OriginalPciAttributes,
379 NULL
380 );
381
382 gBS->CloseProtocol (
383 Controller,
384 &gEfiPciIoProtocolGuid,
385 This->DriverBindingHandle,
386 Controller
387 );
388
389 gBS->FreePool (AtapiScsiPrivate);
390
391 return EFI_SUCCESS;
392 }
393
394 EFI_STATUS
395 RegisterAtapiScsiPassThru (
396 IN EFI_DRIVER_BINDING_PROTOCOL *This,
397 IN EFI_HANDLE Controller,
398 IN EFI_PCI_IO_PROTOCOL *PciIo,
399 IN UINT64 OriginalPciAttributes
400 )
401 /*++
402
403 Routine Description:
404 Attaches SCSI Pass Thru Protocol for specified IDE channel.
405
406 Arguments:
407 This - Protocol instance pointer.
408 Controller - Parent device handle to the IDE channel.
409 PciIo - PCI I/O protocol attached on the "Controller".
410
411 Returns:
412 Always return EFI_SUCCESS unless installing SCSI Pass Thru Protocol failed.
413
414 --*/
415 {
416 EFI_STATUS Status;
417 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
418 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[ATAPI_MAX_CHANNEL];
419
420 AtapiScsiPrivate = AllocateZeroPool (sizeof (ATAPI_SCSI_PASS_THRU_DEV));
421 if (AtapiScsiPrivate == NULL) {
422 return EFI_OUT_OF_RESOURCES;
423 }
424
425 AtapiScsiPrivate->Signature = ATAPI_SCSI_PASS_THRU_DEV_SIGNATURE;
426 AtapiScsiPrivate->Handle = Controller;
427
428 //
429 // will reset the IoPort inside each API function.
430 //
431 AtapiScsiPrivate->IoPort = NULL;
432 AtapiScsiPrivate->PciIo = PciIo;
433 AtapiScsiPrivate->OriginalPciAttributes = OriginalPciAttributes;
434
435 //
436 // Obtain IDE IO port registers' base addresses
437 //
438 Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
439 if (EFI_ERROR (Status)) {
440 return Status;
441 }
442
443 InitAtapiIoPortRegisters(AtapiScsiPrivate, IdeRegsBaseAddr);
444
445 //
446 // Initialize the LatestTargetId to MAX_TARGET_ID.
447 //
448 AtapiScsiPrivate->LatestTargetId = MAX_TARGET_ID;
449 AtapiScsiPrivate->LatestLun = 0;
450
451 Status = InstallScsiPassThruProtocols (&Controller, AtapiScsiPrivate);
452
453 return Status;
454 }
455
456 EFI_STATUS
457 EFIAPI
458 AtapiScsiPassThruFunction (
459 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
460 IN UINT32 Target,
461 IN UINT64 Lun,
462 IN OUT EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
463 IN EFI_EVENT Event OPTIONAL
464 )
465 /*++
466
467 Routine Description:
468
469 Implements EFI_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
470
471 Arguments:
472
473 This: The EFI_SCSI_PASS_THRU_PROTOCOL instance.
474 Target: The Target ID of the ATAPI device to send the SCSI
475 Request Packet. To ATAPI devices attached on an IDE
476 Channel, Target ID 0 indicates Master device;Target
477 ID 1 indicates Slave device.
478 Lun: The LUN of the ATAPI device to send the SCSI Request
479 Packet. To the ATAPI device, Lun is always 0.
480 Packet: The SCSI Request Packet to send to the ATAPI device
481 specified by Target and Lun.
482 Event: If non-blocking I/O is not supported then Event is ignored,
483 and blocking I/O is performed.
484 If Event is NULL, then blocking I/O is performed.
485 If Event is not NULL and non blocking I/O is supported,
486 then non-blocking I/O is performed, and Event will be signaled
487 when the SCSI Request Packet completes.
488
489 Returns:
490
491 EFI_STATUS
492
493 --*/
494 {
495 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
496 EFI_STATUS Status;
497
498 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
499
500 //
501 // Target is not allowed beyond MAX_TARGET_ID
502 //
503 if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
504 return EFI_INVALID_PARAMETER;
505 }
506
507 //
508 // check the data fields in Packet parameter.
509 //
510 Status = CheckSCSIRequestPacket (Packet);
511 if (EFI_ERROR (Status)) {
512 return Status;
513 }
514
515 //
516 // If Request Packet targets at the IDE channel itself,
517 // do nothing.
518 //
519 if (Target == This->Mode->AdapterId) {
520 Packet->TransferLength = 0;
521 return EFI_SUCCESS;
522 }
523
524 //
525 // According to Target ID, reset the Atapi I/O Register mapping
526 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
527 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
528 //
529 if ((Target / 2) == 0) {
530 Target = Target % 2;
531 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
532 } else {
533 Target = Target % 2;
534 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
535 }
536
537 //
538 // the ATAPI SCSI interface does not support non-blocking I/O
539 // ignore the Event parameter
540 //
541 // Performs blocking I/O.
542 //
543 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, Packet);
544 return Status;
545 }
546
547 EFI_STATUS
548 EFIAPI
549 AtapiScsiPassThruGetNextDevice (
550 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
551 IN OUT UINT32 *Target,
552 IN OUT UINT64 *Lun
553 )
554 /*++
555
556 Routine Description:
557
558 Used to retrieve the list of legal Target IDs for SCSI devices
559 on a SCSI channel.
560
561 Arguments:
562
563 This - Protocol instance pointer.
564 Target - On input, a pointer to the Target ID of a SCSI
565 device present on the SCSI channel. On output,
566 a pointer to the Target ID of the next SCSI device
567 present on a SCSI channel. An input value of
568 0xFFFFFFFF retrieves the Target ID of the first
569 SCSI device present on a SCSI channel.
570 Lun - On input, a pointer to the LUN of a SCSI device
571 present on the SCSI channel. On output, a pointer
572 to the LUN of the next SCSI device present on
573 a SCSI channel.
574 Returns:
575
576 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
577 on the SCSI channel was returned in Target and Lun.
578 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
579 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
580 returned on a previous call to GetNextDevice().
581 --*/
582 {
583 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
584
585 //
586 // Retrieve Device Private Data Structure.
587 //
588 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
589
590 //
591 // Check whether Target is valid.
592 //
593 if (Target == NULL || Lun == NULL) {
594 return EFI_INVALID_PARAMETER;
595 }
596
597 if ((*Target != 0xFFFFFFFF) &&
598 ((*Target != AtapiScsiPrivate->LatestTargetId) ||
599 (*Lun != AtapiScsiPrivate->LatestLun))) {
600 return EFI_INVALID_PARAMETER;
601 }
602
603 if (*Target == MAX_TARGET_ID) {
604 return EFI_NOT_FOUND;
605 }
606
607 if (*Target == 0xFFFFFFFF) {
608 *Target = 0;
609 } else {
610 *Target = AtapiScsiPrivate->LatestTargetId + 1;
611 }
612
613 *Lun = 0;
614
615 //
616 // Update the LatestTargetId.
617 //
618 AtapiScsiPrivate->LatestTargetId = *Target;
619 AtapiScsiPrivate->LatestLun = *Lun;
620
621 return EFI_SUCCESS;
622
623 }
624
625 EFI_STATUS
626 EFIAPI
627 AtapiScsiPassThruBuildDevicePath (
628 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
629 IN UINT32 Target,
630 IN UINT64 Lun,
631 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
632 )
633 /*++
634
635 Routine Description:
636
637 Used to allocate and build a device path node for a SCSI device
638 on a SCSI channel. Would not build device path for a SCSI Host Controller.
639
640 Arguments:
641
642 This - Protocol instance pointer.
643 Target - The Target ID of the SCSI device for which
644 a device path node is to be allocated and built.
645 Lun - The LUN of the SCSI device for which a device
646 path node is to be allocated and built.
647 DevicePath - A pointer to a single device path node that
648 describes the SCSI device specified by
649 Target and Lun. This function is responsible
650 for allocating the buffer DevicePath with the boot
651 service AllocatePool(). It is the caller's
652 responsibility to free DevicePath when the caller
653 is finished with DevicePath.
654 Returns:
655 EFI_SUCCESS - The device path node that describes the SCSI device
656 specified by Target and Lun was allocated and
657 returned in DevicePath.
658 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
659 not exist on the SCSI channel.
660 EFI_INVALID_PARAMETER - DevicePath is NULL.
661 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
662 DevicePath.
663 --*/
664 {
665 EFI_DEV_PATH *Node;
666
667
668 //
669 // Validate parameters passed in.
670 //
671
672 if (DevicePath == NULL) {
673 return EFI_INVALID_PARAMETER;
674 }
675
676 //
677 // can not build device path for the SCSI Host Controller.
678 //
679 if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
680 return EFI_NOT_FOUND;
681 }
682
683 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
684 if (Node == NULL) {
685 return EFI_OUT_OF_RESOURCES;
686 }
687
688 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
689 Node->DevPath.SubType = MSG_ATAPI_DP;
690 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
691
692 Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);
693 Node->Atapi.SlaveMaster = (UINT8) (Target % 2);
694 Node->Atapi.Lun = (UINT16) Lun;
695
696 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
697
698 return EFI_SUCCESS;
699 }
700
701 EFI_STATUS
702 EFIAPI
703 AtapiScsiPassThruGetTargetLun (
704 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
705 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
706 OUT UINT32 *Target,
707 OUT UINT64 *Lun
708 )
709 /*++
710
711 Routine Description:
712
713 Used to translate a device path node to a Target ID and LUN.
714
715 Arguments:
716
717 This - Protocol instance pointer.
718 DevicePath - A pointer to the device path node that
719 describes a SCSI device on the SCSI channel.
720 Target - A pointer to the Target ID of a SCSI device
721 on the SCSI channel.
722 Lun - A pointer to the LUN of a SCSI device on
723 the SCSI channel.
724 Returns:
725
726 EFI_SUCCESS - DevicePath was successfully translated to a
727 Target ID and LUN, and they were returned
728 in Target and Lun.
729 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
730 EFI_UNSUPPORTED - This driver does not support the device path
731 node type in DevicePath.
732 EFI_NOT_FOUND - A valid translation from DevicePath to a
733 Target ID and LUN does not exist.
734 --*/
735 {
736 EFI_DEV_PATH *Node;
737
738 //
739 // Validate parameters passed in.
740 //
741 if (DevicePath == NULL || Target == NULL || Lun == NULL) {
742 return EFI_INVALID_PARAMETER;
743 }
744
745 //
746 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
747 //
748 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
749 (DevicePath->SubType != MSG_ATAPI_DP) ||
750 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
751 return EFI_UNSUPPORTED;
752 }
753
754 Node = (EFI_DEV_PATH *) DevicePath;
755
756 *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;
757 *Lun = Node->Atapi.Lun;
758
759 if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {
760 return EFI_NOT_FOUND;
761 }
762
763 return EFI_SUCCESS;
764 }
765
766 EFI_STATUS
767 EFIAPI
768 AtapiScsiPassThruResetChannel (
769 IN EFI_SCSI_PASS_THRU_PROTOCOL *This
770 )
771 /*++
772
773 Routine Description:
774
775 Resets a SCSI channel.This operation resets all the
776 SCSI devices connected to the SCSI channel.
777
778 Arguments:
779
780 This - Protocol instance pointer.
781
782 Returns:
783
784 EFI_SUCCESS - The SCSI channel was reset.
785 EFI_UNSUPPORTED - The SCSI channel does not support
786 a channel reset operation.
787 EFI_DEVICE_ERROR - A device error occurred while
788 attempting to reset the SCSI channel.
789 EFI_TIMEOUT - A timeout occurred while attempting
790 to reset the SCSI channel.
791 --*/
792 {
793 UINT8 DeviceControlValue;
794 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
795 UINT8 Index;
796 BOOLEAN ResetFlag;
797
798 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
799 ResetFlag = FALSE;
800
801 //
802 // Reset both Primary channel and Secondary channel.
803 // so, the IoPort pointer must point to the right I/O Register group
804 //
805 for (Index = 0; Index < 2; Index++) {
806 //
807 // Reset
808 //
809 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
810
811 DeviceControlValue = 0;
812 //
813 // set SRST bit to initiate soft reset
814 //
815 DeviceControlValue |= SRST;
816 //
817 // disable Interrupt
818 //
819 DeviceControlValue |= BIT1;
820 WritePortB (
821 AtapiScsiPrivate->PciIo,
822 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
823 DeviceControlValue
824 );
825
826 //
827 // Wait 10us
828 //
829 gBS->Stall (10);
830
831 //
832 // Clear SRST bit
833 // 0xfb:1111,1011
834 //
835 DeviceControlValue &= 0xfb;
836
837 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
838
839 //
840 // slave device needs at most 31s to clear BSY
841 //
842 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
843 ResetFlag = TRUE;
844 }
845 }
846
847 if (ResetFlag) {
848 return EFI_SUCCESS;
849 }
850
851 return EFI_TIMEOUT;
852 }
853
854 EFI_STATUS
855 EFIAPI
856 AtapiScsiPassThruResetTarget (
857 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,
858 IN UINT32 Target,
859 IN UINT64 Lun
860 )
861 /*++
862
863 Routine Description:
864
865 Resets a SCSI device that is connected to a SCSI channel.
866
867 Arguments:
868
869 This - Protocol instance pointer.
870 Target - The Target ID of the SCSI device to reset.
871 Lun - The LUN of the SCSI device to reset.
872
873 Returns:
874
875 EFI_SUCCESS - The SCSI device specified by Target and
876 Lun was reset.
877 EFI_UNSUPPORTED - The SCSI channel does not support a target
878 reset operation.
879 EFI_INVALID_PARAMETER - Target or Lun are invalid.
880 EFI_DEVICE_ERROR - A device error occurred while attempting
881 to reset the SCSI device specified by Target
882 and Lun.
883 EFI_TIMEOUT - A timeout occurred while attempting to reset
884 the SCSI device specified by Target and Lun.
885 --*/
886 {
887 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
888 UINT8 Command;
889 UINT8 DeviceSelect;
890
891 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);
892
893 if ((Target > MAX_TARGET_ID) || (Lun != 0)) {
894 return EFI_INVALID_PARAMETER;
895 }
896 //
897 // Directly return EFI_SUCCESS if want to reset the host controller
898 //
899 if (Target == This->Mode->AdapterId) {
900 return EFI_SUCCESS;
901 }
902
903 //
904 // According to Target ID, reset the Atapi I/O Register mapping
905 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
906 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
907 //
908 if ((Target / 2) == 0) {
909 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
910 } else {
911 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
912 }
913
914 //
915 // for ATAPI device, no need to wait DRDY ready after device selecting.
916 //
917 // bit7 and bit5 are both set to 1 for backward compatibility
918 //
919 DeviceSelect = (UINT8) (((BIT7 | BIT5) | (Target << 4)));
920 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
921
922 Command = ATAPI_SOFT_RESET_CMD;
923 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
924
925 //
926 // BSY clear is the only status return to the host by the device
927 // when reset is complete.
928 // slave device needs at most 31s to clear BSY
929 //
930 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
931 return EFI_TIMEOUT;
932 }
933
934 //
935 // stall 5 seconds to make the device status stable
936 //
937 gBS->Stall (5000000);
938
939 return EFI_SUCCESS;
940 }
941
942 EFI_STATUS
943 EFIAPI
944 AtapiExtScsiPassThruFunction (
945 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
946 IN UINT8 *Target,
947 IN UINT64 Lun,
948 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
949 IN EFI_EVENT Event OPTIONAL
950 )
951 /*++
952
953 Routine Description:
954
955 Implements EFI_EXT_SCSI_PASS_THRU_PROTOCOL.PassThru() function.
956
957 Arguments:
958
959 This: The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
960 Target: The Target ID of the ATAPI device to send the SCSI
961 Request Packet. To ATAPI devices attached on an IDE
962 Channel, Target ID 0 indicates Master device;Target
963 ID 1 indicates Slave device.
964 Lun: The LUN of the ATAPI device to send the SCSI Request
965 Packet. To the ATAPI device, Lun is always 0.
966 Packet: The SCSI Request Packet to send to the ATAPI device
967 specified by Target and Lun.
968 Event: If non-blocking I/O is not supported then Event is ignored,
969 and blocking I/O is performed.
970 If Event is NULL, then blocking I/O is performed.
971 If Event is not NULL and non blocking I/O is supported,
972 then non-blocking I/O is performed, and Event will be signaled
973 when the SCSI Request Packet completes.
974
975 Returns:
976
977 EFI_STATUS
978
979 --*/
980 {
981 EFI_STATUS Status;
982 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
983 UINT8 TargetId;
984
985 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
986
987 //
988 // For ATAPI device, UINT8 is enough to represent the SCSI ID on channel.
989 //
990 TargetId = Target[0];
991
992 //
993 // Target is not allowed beyond MAX_TARGET_ID
994 //
995 if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {
996 return EFI_INVALID_PARAMETER;
997 }
998
999 //
1000 // check the data fields in Packet parameter.
1001 //
1002 Status = CheckExtSCSIRequestPacket (Packet);
1003 if (EFI_ERROR (Status)) {
1004 return Status;
1005 }
1006
1007 //
1008 // If Request Packet targets at the IDE channel itself,
1009 // do nothing.
1010 //
1011 if (TargetId == (UINT8)This->Mode->AdapterId) {
1012 Packet->InTransferLength = Packet->OutTransferLength = 0;
1013 return EFI_SUCCESS;
1014 }
1015
1016 //
1017 // According to Target ID, reset the Atapi I/O Register mapping
1018 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1019 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1020 //
1021 if ((TargetId / 2) == 0) {
1022 TargetId = (UINT8) (TargetId % 2);
1023 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
1024 } else {
1025 TargetId = (UINT8) (TargetId % 2);
1026 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
1027 }
1028
1029 //
1030 // the ATAPI SCSI interface does not support non-blocking I/O
1031 // ignore the Event parameter
1032 //
1033 // Performs blocking I/O.
1034 //
1035 Status = SubmitExtBlockingIoCommand (AtapiScsiPrivate, TargetId, Packet);
1036 return Status;
1037 }
1038
1039 EFI_STATUS
1040 EFIAPI
1041 AtapiExtScsiPassThruGetNextTargetLun (
1042 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1043 IN OUT UINT8 **Target,
1044 IN OUT UINT64 *Lun
1045 )
1046 /*++
1047
1048 Routine Description:
1049
1050 Used to retrieve the list of legal Target IDs for SCSI devices
1051 on a SCSI channel.
1052
1053 Arguments:
1054
1055 This - Protocol instance pointer.
1056 Target - On input, a pointer to the Target ID of a SCSI
1057 device present on the SCSI channel. On output,
1058 a pointer to the Target ID of the next SCSI device
1059 present on a SCSI channel. An input value of
1060 0xFFFFFFFF retrieves the Target ID of the first
1061 SCSI device present on a SCSI channel.
1062 Lun - On input, a pointer to the LUN of a SCSI device
1063 present on the SCSI channel. On output, a pointer
1064 to the LUN of the next SCSI device present on
1065 a SCSI channel.
1066 Returns:
1067
1068 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1069 on the SCSI channel was returned in Target and Lun.
1070 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1071 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1072 returned on a previous call to GetNextDevice().
1073 --*/
1074 {
1075 UINT8 ByteIndex;
1076 UINT8 TargetId;
1077 UINT8 ScsiId[TARGET_MAX_BYTES];
1078 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1079
1080 //
1081 // Retrieve Device Private Data Structure.
1082 //
1083 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1084
1085 //
1086 // Check whether Target is valid.
1087 //
1088 if (*Target == NULL || Lun == NULL) {
1089 return EFI_INVALID_PARAMETER;
1090 }
1091
1092 SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
1093
1094 TargetId = (*Target)[0];
1095
1096 //
1097 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1098 //
1099 if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {
1100 for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {
1101 if ((*Target)[ByteIndex] != 0) {
1102 return EFI_INVALID_PARAMETER;
1103 }
1104 }
1105 }
1106
1107 if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&
1108 ((TargetId != AtapiScsiPrivate->LatestTargetId) ||
1109 (*Lun != AtapiScsiPrivate->LatestLun))) {
1110 return EFI_INVALID_PARAMETER;
1111 }
1112
1113 if (TargetId == MAX_TARGET_ID) {
1114 return EFI_NOT_FOUND;
1115 }
1116
1117 if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0) {
1118 SetMem (*Target, TARGET_MAX_BYTES,0);
1119 } else {
1120 (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);
1121 }
1122
1123 *Lun = 0;
1124
1125 //
1126 // Update the LatestTargetId.
1127 //
1128 AtapiScsiPrivate->LatestTargetId = (*Target)[0];
1129 AtapiScsiPrivate->LatestLun = *Lun;
1130
1131 return EFI_SUCCESS;
1132
1133 }
1134
1135 EFI_STATUS
1136 EFIAPI
1137 AtapiExtScsiPassThruBuildDevicePath (
1138 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1139 IN UINT8 *Target,
1140 IN UINT64 Lun,
1141 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
1142 )
1143 /*++
1144
1145 Routine Description:
1146
1147 Used to allocate and build a device path node for a SCSI device
1148 on a SCSI channel. Would not build device path for a SCSI Host Controller.
1149
1150 Arguments:
1151
1152 This - Protocol instance pointer.
1153 Target - The Target ID of the SCSI device for which
1154 a device path node is to be allocated and built.
1155 Lun - The LUN of the SCSI device for which a device
1156 path node is to be allocated and built.
1157 DevicePath - A pointer to a single device path node that
1158 describes the SCSI device specified by
1159 Target and Lun. This function is responsible
1160 for allocating the buffer DevicePath with the boot
1161 service AllocatePool(). It is the caller's
1162 responsibility to free DevicePath when the caller
1163 is finished with DevicePath.
1164 Returns:
1165 EFI_SUCCESS - The device path node that describes the SCSI device
1166 specified by Target and Lun was allocated and
1167 returned in DevicePath.
1168 EFI_NOT_FOUND - The SCSI devices specified by Target and Lun does
1169 not exist on the SCSI channel.
1170 EFI_INVALID_PARAMETER - DevicePath is NULL.
1171 EFI_OUT_OF_RESOURCES - There are not enough resources to allocate
1172 DevicePath.
1173 --*/
1174 {
1175 EFI_DEV_PATH *Node;
1176 UINT8 TargetId;
1177
1178 TargetId = Target[0];
1179
1180 //
1181 // Validate parameters passed in.
1182 //
1183
1184 if (DevicePath == NULL) {
1185 return EFI_INVALID_PARAMETER;
1186 }
1187
1188 //
1189 // can not build device path for the SCSI Host Controller.
1190 //
1191 if ((TargetId > (MAX_TARGET_ID - 1)) || (Lun != 0)) {
1192 return EFI_NOT_FOUND;
1193 }
1194
1195 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));
1196 if (Node == NULL) {
1197 return EFI_OUT_OF_RESOURCES;
1198 }
1199
1200 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
1201 Node->DevPath.SubType = MSG_ATAPI_DP;
1202 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));
1203
1204 Node->Atapi.PrimarySecondary = (UINT8) (TargetId / 2);
1205 Node->Atapi.SlaveMaster = (UINT8) (TargetId % 2);
1206 Node->Atapi.Lun = (UINT16) Lun;
1207
1208 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
1209
1210 return EFI_SUCCESS;
1211 }
1212
1213 EFI_STATUS
1214 EFIAPI
1215 AtapiExtScsiPassThruGetTargetLun (
1216 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1217 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1218 OUT UINT8 **Target,
1219 OUT UINT64 *Lun
1220 )
1221 /*++
1222
1223 Routine Description:
1224
1225 Used to translate a device path node to a Target ID and LUN.
1226
1227 Arguments:
1228
1229 This - Protocol instance pointer.
1230 DevicePath - A pointer to the device path node that
1231 describes a SCSI device on the SCSI channel.
1232 Target - A pointer to the Target ID of a SCSI device
1233 on the SCSI channel.
1234 Lun - A pointer to the LUN of a SCSI device on
1235 the SCSI channel.
1236 Returns:
1237
1238 EFI_SUCCESS - DevicePath was successfully translated to a
1239 Target ID and LUN, and they were returned
1240 in Target and Lun.
1241 EFI_INVALID_PARAMETER - DevicePath/Target/Lun is NULL.
1242 EFI_UNSUPPORTED - This driver does not support the device path
1243 node type in DevicePath.
1244 EFI_NOT_FOUND - A valid translation from DevicePath to a
1245 Target ID and LUN does not exist.
1246 --*/
1247 {
1248 EFI_DEV_PATH *Node;
1249
1250 //
1251 // Validate parameters passed in.
1252 //
1253 if (DevicePath == NULL || Target == NULL || Lun == NULL) {
1254 return EFI_INVALID_PARAMETER;
1255 }
1256
1257 //
1258 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH
1259 //
1260 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
1261 (DevicePath->SubType != MSG_ATAPI_DP) ||
1262 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {
1263 return EFI_UNSUPPORTED;
1264 }
1265
1266 ZeroMem (*Target, TARGET_MAX_BYTES);
1267
1268 Node = (EFI_DEV_PATH *) DevicePath;
1269
1270 (*Target)[0] = (UINT8) (Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster);
1271 *Lun = Node->Atapi.Lun;
1272
1273 if ((*Target)[0] > (MAX_TARGET_ID - 1) || *Lun != 0) {
1274 return EFI_NOT_FOUND;
1275 }
1276
1277 return EFI_SUCCESS;
1278 }
1279
1280 EFI_STATUS
1281 EFIAPI
1282 AtapiExtScsiPassThruResetChannel (
1283 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
1284 )
1285 /*++
1286
1287 Routine Description:
1288
1289 Resets a SCSI channel.This operation resets all the
1290 SCSI devices connected to the SCSI channel.
1291
1292 Arguments:
1293
1294 This - Protocol instance pointer.
1295
1296 Returns:
1297
1298 EFI_SUCCESS - The SCSI channel was reset.
1299 EFI_UNSUPPORTED - The SCSI channel does not support
1300 a channel reset operation.
1301 EFI_DEVICE_ERROR - A device error occurred while
1302 attempting to reset the SCSI channel.
1303 EFI_TIMEOUT - A timeout occurred while attempting
1304 to reset the SCSI channel.
1305 --*/
1306 {
1307 UINT8 DeviceControlValue;
1308 UINT8 Index;
1309 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1310 BOOLEAN ResetFlag;
1311
1312 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1313 ResetFlag = FALSE;
1314 //
1315 // Reset both Primary channel and Secondary channel.
1316 // so, the IoPort pointer must point to the right I/O Register group
1317 // And if there is a channel reset successfully, return EFI_SUCCESS.
1318 //
1319 for (Index = 0; Index < 2; Index++) {
1320 //
1321 // Reset
1322 //
1323 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[Index];
1324
1325 DeviceControlValue = 0;
1326 //
1327 // set SRST bit to initiate soft reset
1328 //
1329 DeviceControlValue |= SRST;
1330 //
1331 // disable Interrupt
1332 //
1333 DeviceControlValue |= BIT1;
1334 WritePortB (
1335 AtapiScsiPrivate->PciIo,
1336 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
1337 DeviceControlValue
1338 );
1339
1340 //
1341 // Wait 10us
1342 //
1343 gBS->Stall (10);
1344
1345 //
1346 // Clear SRST bit
1347 // 0xfb:1111,1011
1348 //
1349 DeviceControlValue &= 0xfb;
1350
1351 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);
1352
1353 //
1354 // slave device needs at most 31s to clear BSY
1355 //
1356 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000) != EFI_TIMEOUT) {
1357 ResetFlag = TRUE;
1358 }
1359 }
1360
1361 if (ResetFlag) {
1362 return EFI_SUCCESS;
1363 }
1364
1365 return EFI_TIMEOUT;
1366 }
1367
1368 EFI_STATUS
1369 EFIAPI
1370 AtapiExtScsiPassThruResetTarget (
1371 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1372 IN UINT8 *Target,
1373 IN UINT64 Lun
1374 )
1375 /*++
1376
1377 Routine Description:
1378
1379 Resets a SCSI device that is connected to a SCSI channel.
1380
1381 Arguments:
1382
1383 This - Protocol instance pointer.
1384 Target - The Target ID of the SCSI device to reset.
1385 Lun - The LUN of the SCSI device to reset.
1386
1387 Returns:
1388
1389 EFI_SUCCESS - The SCSI device specified by Target and
1390 Lun was reset.
1391 EFI_UNSUPPORTED - The SCSI channel does not support a target
1392 reset operation.
1393 EFI_INVALID_PARAMETER - Target or Lun are invalid.
1394 EFI_DEVICE_ERROR - A device error occurred while attempting
1395 to reset the SCSI device specified by Target
1396 and Lun.
1397 EFI_TIMEOUT - A timeout occurred while attempting to reset
1398 the SCSI device specified by Target and Lun.
1399 --*/
1400 {
1401 UINT8 Command;
1402 UINT8 DeviceSelect;
1403 UINT8 TargetId;
1404 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1405
1406 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1407 TargetId = Target[0];
1408
1409 if ((TargetId > MAX_TARGET_ID) || (Lun != 0)) {
1410 return EFI_INVALID_PARAMETER;
1411 }
1412 //
1413 // Directly return EFI_SUCCESS if want to reset the host controller
1414 //
1415 if (TargetId == This->Mode->AdapterId) {
1416 return EFI_SUCCESS;
1417 }
1418
1419 //
1420 // According to Target ID, reset the Atapi I/O Register mapping
1421 // (Target Id in [0,1] area, using AtapiIoPortRegisters[0],
1422 // Target Id in [2,3] area, using AtapiIoPortRegisters[1]
1423 //
1424 if ((TargetId / 2) == 0) {
1425 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[0];
1426 } else {
1427 AtapiScsiPrivate->IoPort = &AtapiScsiPrivate->AtapiIoPortRegisters[1];
1428 }
1429
1430 //
1431 // for ATAPI device, no need to wait DRDY ready after device selecting.
1432 //
1433 // bit7 and bit5 are both set to 1 for backward compatibility
1434 //
1435 DeviceSelect = (UINT8) ((BIT7 | BIT5) | (TargetId << 4));
1436 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);
1437
1438 Command = ATAPI_SOFT_RESET_CMD;
1439 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);
1440
1441 //
1442 // BSY clear is the only status return to the host by the device
1443 // when reset is complete.
1444 // slave device needs at most 31s to clear BSY
1445 //
1446 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000000))) {
1447 return EFI_TIMEOUT;
1448 }
1449
1450 //
1451 // stall 5 seconds to make the device status stable
1452 //
1453 gBS->Stall (5000000);
1454
1455 return EFI_SUCCESS;
1456 }
1457
1458
1459 EFI_STATUS
1460 EFIAPI
1461 AtapiExtScsiPassThruGetNextTarget (
1462 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
1463 IN OUT UINT8 **Target
1464 )
1465 /*++
1466
1467 Routine Description:
1468 Used to retrieve the list of legal Target IDs for SCSI devices
1469 on a SCSI channel.
1470
1471 Arguments:
1472 This - Protocol instance pointer.
1473 Target - On input, a pointer to the Target ID of a SCSI
1474 device present on the SCSI channel. On output,
1475 a pointer to the Target ID of the next SCSI device
1476 present on a SCSI channel. An input value of
1477 0xFFFFFFFF retrieves the Target ID of the first
1478 SCSI device present on a SCSI channel.
1479 Lun - On input, a pointer to the LUN of a SCSI device
1480 present on the SCSI channel. On output, a pointer
1481 to the LUN of the next SCSI device present on
1482 a SCSI channel.
1483
1484 Returns:
1485 EFI_SUCCESS - The Target ID and Lun of the next SCSI device
1486 on the SCSI channel was returned in Target and Lun.
1487 EFI_NOT_FOUND - There are no more SCSI devices on this SCSI channel.
1488 EFI_INVALID_PARAMETER - Target is not 0xFFFFFFFF,and Target and Lun were not
1489 returned on a previous call to GetNextDevice().
1490 --*/
1491 {
1492 UINT8 TargetId;
1493 UINT8 ScsiId[TARGET_MAX_BYTES];
1494 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;
1495 UINT8 ByteIndex;
1496
1497 //
1498 // Retrieve Device Private Data Structure.
1499 //
1500 AtapiScsiPrivate = ATAPI_EXT_SCSI_PASS_THRU_DEV_FROM_THIS (This);
1501
1502 //
1503 // Check whether Target is valid.
1504 //
1505 if (*Target == NULL ) {
1506 return EFI_INVALID_PARAMETER;
1507 }
1508
1509 TargetId = (*Target)[0];
1510 SetMem (ScsiId, TARGET_MAX_BYTES, 0xFF);
1511
1512 //
1513 // For ATAPI device, we use UINT8 to represent the SCSI ID on channel.
1514 //
1515 if (CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) {
1516 for (ByteIndex = 1; ByteIndex < TARGET_MAX_BYTES; ByteIndex++) {
1517 if ((*Target)[ByteIndex] != 0) {
1518 return EFI_INVALID_PARAMETER;
1519 }
1520 }
1521 }
1522
1523 if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) != 0) &&(TargetId != AtapiScsiPrivate->LatestTargetId)) {
1524 return EFI_INVALID_PARAMETER;
1525 }
1526
1527 if (TargetId == MAX_TARGET_ID) {
1528 return EFI_NOT_FOUND;
1529 }
1530
1531 if ((CompareMem(*Target, ScsiId, TARGET_MAX_BYTES) == 0)) {
1532 SetMem (*Target, TARGET_MAX_BYTES, 0);
1533 } else {
1534 (*Target)[0] = (UINT8) (AtapiScsiPrivate->LatestTargetId + 1);
1535 }
1536
1537 //
1538 // Update the LatestTargetId.
1539 //
1540 AtapiScsiPrivate->LatestTargetId = (*Target)[0];
1541 AtapiScsiPrivate->LatestLun = 0;
1542
1543 return EFI_SUCCESS;
1544 }
1545
1546 EFI_STATUS
1547 GetIdeRegistersBaseAddr (
1548 IN EFI_PCI_IO_PROTOCOL *PciIo,
1549 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
1550 )
1551 /*++
1552
1553 Routine Description:
1554 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
1555 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
1556 the PCI IDE controller's Configuration Space.
1557
1558 Arguments:
1559 PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
1560 IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
1561 receive IDE IO port registers' base addresses
1562
1563 Returns:
1564
1565 EFI_STATUS
1566
1567 --*/
1568 {
1569 EFI_STATUS Status;
1570 PCI_TYPE00 PciData;
1571
1572 Status = PciIo->Pci.Read (
1573 PciIo,
1574 EfiPciIoWidthUint8,
1575 0,
1576 sizeof (PciData),
1577 &PciData
1578 );
1579
1580 if (EFI_ERROR (Status)) {
1581 return Status;
1582 }
1583
1584 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
1585 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;
1586 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;
1587 } else {
1588 //
1589 // The BARs should be of IO type
1590 //
1591 if ((PciData.Device.Bar[0] & BIT0) == 0 ||
1592 (PciData.Device.Bar[1] & BIT0) == 0) {
1593 return EFI_UNSUPPORTED;
1594 }
1595
1596 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =
1597 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
1598 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =
1599 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
1600 }
1601
1602 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
1603 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;
1604 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;
1605 } else {
1606 //
1607 // The BARs should be of IO type
1608 //
1609 if ((PciData.Device.Bar[2] & BIT0) == 0 ||
1610 (PciData.Device.Bar[3] & BIT0) == 0) {
1611 return EFI_UNSUPPORTED;
1612 }
1613
1614 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =
1615 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
1616 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =
1617 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
1618 }
1619
1620 return EFI_SUCCESS;
1621 }
1622
1623 VOID
1624 InitAtapiIoPortRegisters (
1625 IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1626 IN IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
1627 )
1628 /*++
1629
1630 Routine Description:
1631
1632 Initialize each Channel's Base Address of CommandBlock and ControlBlock.
1633
1634 Arguments:
1635
1636 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1637 IdeRegsBaseAddr - The pointer of IDE_REGISTERS_BASE_ADDR
1638
1639 Returns:
1640
1641 None
1642
1643 --*/
1644 {
1645
1646 UINT8 IdeChannel;
1647 UINT16 CommandBlockBaseAddr;
1648 UINT16 ControlBlockBaseAddr;
1649 IDE_BASE_REGISTERS *RegisterPointer;
1650
1651
1652 for (IdeChannel = 0; IdeChannel < ATAPI_MAX_CHANNEL; IdeChannel++) {
1653
1654 RegisterPointer = &AtapiScsiPrivate->AtapiIoPortRegisters[IdeChannel];
1655
1656 //
1657 // Initialize IDE IO port addresses, including Command Block registers
1658 // and Control Block registers
1659 //
1660 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
1661 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
1662
1663 RegisterPointer->Data = CommandBlockBaseAddr;
1664 (*(UINT16 *) &RegisterPointer->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
1665 RegisterPointer->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
1666 RegisterPointer->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
1667 RegisterPointer->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
1668 RegisterPointer->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
1669 RegisterPointer->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
1670 (*(UINT16 *) &RegisterPointer->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
1671
1672 (*(UINT16 *) &RegisterPointer->Alt) = ControlBlockBaseAddr;
1673 RegisterPointer->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
1674 }
1675
1676 }
1677
1678
1679 EFI_STATUS
1680 CheckSCSIRequestPacket (
1681 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1682 )
1683 /*++
1684
1685 Routine Description:
1686
1687 Checks the parameters in the SCSI Request Packet to make sure
1688 they are valid for a SCSI Pass Thru request.
1689
1690 Arguments:
1691
1692 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1693
1694 Returns:
1695
1696 EFI_STATUS
1697
1698 --*/
1699 {
1700 if (Packet == NULL) {
1701 return EFI_INVALID_PARAMETER;
1702 }
1703
1704 if (!ValidCdbLength (Packet->CdbLength)) {
1705 return EFI_INVALID_PARAMETER;
1706 }
1707
1708 if (Packet->Cdb == NULL) {
1709 return EFI_INVALID_PARAMETER;
1710 }
1711
1712 //
1713 // Checks whether the request command is supported.
1714 //
1715 if (!IsCommandValid (Packet)) {
1716 return EFI_UNSUPPORTED;
1717 }
1718
1719 return EFI_SUCCESS;
1720 }
1721
1722 BOOLEAN
1723 IsCommandValid (
1724 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1725 )
1726 /*++
1727
1728 Routine Description:
1729
1730 Checks the requested SCSI command:
1731 Is it supported by this driver?
1732 Is the Data transfer direction reasonable?
1733
1734 Arguments:
1735
1736 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1737
1738 Returns:
1739
1740 EFI_STATUS
1741
1742 --*/
1743 {
1744 UINT8 Index;
1745 UINT8 *OpCode;
1746 UINT8 ArrayLen;
1747
1748 OpCode = (UINT8 *) (Packet->Cdb);
1749 ArrayLen = (UINT8) (ARRAY_SIZE (gSupportedATAPICommands));
1750
1751 for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {
1752
1753 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
1754 //
1755 // Check whether the requested Command is supported by this driver
1756 //
1757 if (Packet->DataDirection == DataIn) {
1758 //
1759 // Check whether the requested data direction conforms to
1760 // what it should be.
1761 //
1762 if (gSupportedATAPICommands[Index].Direction == DataOut) {
1763 return FALSE;
1764 }
1765 }
1766
1767 if (Packet->DataDirection == DataOut) {
1768 //
1769 // Check whether the requested data direction conforms to
1770 // what it should be.
1771 //
1772 if (gSupportedATAPICommands[Index].Direction == DataIn) {
1773 return FALSE;
1774 }
1775 }
1776
1777 return TRUE;
1778 }
1779 }
1780
1781 return FALSE;
1782 }
1783
1784 EFI_STATUS
1785 SubmitBlockingIoCommand (
1786 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1787 UINT32 Target,
1788 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1789 )
1790 /*++
1791
1792 Routine Description:
1793
1794 Performs blocking I/O request.
1795
1796 Arguments:
1797
1798 AtapiScsiPrivate: Private data structure for the specified channel.
1799 Target: The Target ID of the ATAPI device to send the SCSI
1800 Request Packet. To ATAPI devices attached on an IDE
1801 Channel, Target ID 0 indicates Master device;Target
1802 ID 1 indicates Slave device.
1803 Packet: The SCSI Request Packet to send to the ATAPI device
1804 specified by Target.
1805
1806 Returns: EFI_STATUS
1807
1808 --*/
1809 {
1810 UINT8 PacketCommand[12];
1811 UINT64 TimeoutInMicroSeconds;
1812 EFI_STATUS PacketCommandStatus;
1813
1814 //
1815 // Fill ATAPI Command Packet according to CDB
1816 //
1817 ZeroMem (&PacketCommand, 12);
1818 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
1819
1820 //
1821 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
1822 //
1823 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
1824
1825 //
1826 // Submit ATAPI Command Packet
1827 //
1828 PacketCommandStatus = AtapiPacketCommand (
1829 AtapiScsiPrivate,
1830 Target,
1831 PacketCommand,
1832 Packet->DataBuffer,
1833 &(Packet->TransferLength),
1834 (DATA_DIRECTION) Packet->DataDirection,
1835 TimeoutInMicroSeconds
1836 );
1837 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
1838 Packet->SenseDataLength = 0;
1839 return PacketCommandStatus;
1840 }
1841
1842 //
1843 // Return SenseData if PacketCommandStatus matches
1844 // the following return codes.
1845 //
1846 if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
1847 (PacketCommandStatus == EFI_DEVICE_ERROR) ||
1848 (PacketCommandStatus == EFI_TIMEOUT)) {
1849
1850 //
1851 // avoid submit request sense command continuously.
1852 //
1853 if (PacketCommand[0] == OP_REQUEST_SENSE) {
1854 Packet->SenseDataLength = 0;
1855 return PacketCommandStatus;
1856 }
1857
1858 RequestSenseCommand (
1859 AtapiScsiPrivate,
1860 Target,
1861 Packet->Timeout,
1862 Packet->SenseData,
1863 &Packet->SenseDataLength
1864 );
1865 }
1866
1867 return PacketCommandStatus;
1868 }
1869
1870 EFI_STATUS
1871 RequestSenseCommand (
1872 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
1873 UINT32 Target,
1874 UINT64 Timeout,
1875 VOID *SenseData,
1876 UINT8 *SenseDataLength
1877 )
1878 /*++
1879
1880 Routine Description:
1881
1882 Submit request sense command
1883
1884 Arguments:
1885
1886 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
1887 Target - The target ID
1888 Timeout - The time to complete the command
1889 SenseData - The buffer to fill in sense data
1890 SenseDataLength - The length of buffer
1891
1892 Returns:
1893
1894 EFI_STATUS
1895
1896 --*/
1897 {
1898 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;
1899 UINT8 Cdb[12];
1900 EFI_STATUS Status;
1901
1902 ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));
1903 ZeroMem (Cdb, 12);
1904
1905 Cdb[0] = OP_REQUEST_SENSE;
1906 Cdb[4] = (UINT8) (*SenseDataLength);
1907
1908 Packet.Timeout = Timeout;
1909 Packet.DataBuffer = SenseData;
1910 Packet.SenseData = NULL;
1911 Packet.Cdb = Cdb;
1912 Packet.TransferLength = *SenseDataLength;
1913 Packet.CdbLength = 12;
1914 Packet.DataDirection = DataIn;
1915
1916 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);
1917 *SenseDataLength = (UINT8) (Packet.TransferLength);
1918 return Status;
1919 }
1920
1921 EFI_STATUS
1922 CheckExtSCSIRequestPacket (
1923 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1924 )
1925 /*++
1926
1927 Routine Description:
1928
1929 Checks the parameters in the SCSI Request Packet to make sure
1930 they are valid for a SCSI Pass Thru request.
1931
1932 Arguments:
1933
1934 Packet - The pointer of EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1935
1936 Returns:
1937
1938 EFI_STATUS
1939
1940 --*/
1941 {
1942 if (Packet == NULL) {
1943 return EFI_INVALID_PARAMETER;
1944 }
1945
1946 if (!ValidCdbLength (Packet->CdbLength)) {
1947 return EFI_INVALID_PARAMETER;
1948 }
1949
1950 if (Packet->Cdb == NULL) {
1951 return EFI_INVALID_PARAMETER;
1952 }
1953
1954 //
1955 // Checks whether the request command is supported.
1956 //
1957 if (!IsExtCommandValid (Packet)) {
1958 return EFI_UNSUPPORTED;
1959 }
1960
1961 return EFI_SUCCESS;
1962 }
1963
1964
1965 BOOLEAN
1966 IsExtCommandValid (
1967 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
1968 )
1969 /*++
1970
1971 Routine Description:
1972
1973 Checks the requested SCSI command:
1974 Is it supported by this driver?
1975 Is the Data transfer direction reasonable?
1976
1977 Arguments:
1978
1979 Packet - The pointer of EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET
1980
1981 Returns:
1982
1983 EFI_STATUS
1984
1985 --*/
1986 {
1987 UINT8 Index;
1988 UINT8 *OpCode;
1989 UINT8 ArrayLen;
1990
1991 OpCode = (UINT8 *) (Packet->Cdb);
1992 ArrayLen = (UINT8) (ARRAY_SIZE (gSupportedATAPICommands));
1993
1994 for (Index = 0; (Index < ArrayLen) && (CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)) != 0); Index++) {
1995
1996 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {
1997 //
1998 // Check whether the requested Command is supported by this driver
1999 //
2000 if (Packet->DataDirection == DataIn) {
2001 //
2002 // Check whether the requested data direction conforms to
2003 // what it should be.
2004 //
2005 if (gSupportedATAPICommands[Index].Direction == DataOut) {
2006 return FALSE;
2007 }
2008 }
2009
2010 if (Packet->DataDirection == DataOut) {
2011 //
2012 // Check whether the requested data direction conforms to
2013 // what it should be.
2014 //
2015 if (gSupportedATAPICommands[Index].Direction == DataIn) {
2016 return FALSE;
2017 }
2018 }
2019
2020 return TRUE;
2021 }
2022 }
2023
2024 return FALSE;
2025 }
2026
2027 EFI_STATUS
2028 SubmitExtBlockingIoCommand (
2029 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2030 UINT8 Target,
2031 EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet
2032 )
2033 /*++
2034
2035 Routine Description:
2036
2037 Performs blocking I/O request.
2038
2039 Arguments:
2040
2041 AtapiScsiPrivate: Private data structure for the specified channel.
2042 Target: The Target ID of the ATAPI device to send the SCSI
2043 Request Packet. To ATAPI devices attached on an IDE
2044 Channel, Target ID 0 indicates Master device;Target
2045 ID 1 indicates Slave device.
2046 Packet: The SCSI Request Packet to send to the ATAPI device
2047 specified by Target.
2048
2049 Returns: EFI_STATUS
2050
2051 --*/
2052 {
2053 UINT8 PacketCommand[12];
2054 UINT64 TimeoutInMicroSeconds;
2055 EFI_STATUS PacketCommandStatus;
2056
2057 //
2058 // Fill ATAPI Command Packet according to CDB
2059 //
2060 ZeroMem (&PacketCommand, 12);
2061 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);
2062
2063 //
2064 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.
2065 //
2066 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);
2067
2068 //
2069 // Submit ATAPI Command Packet
2070 //
2071 if (Packet->DataDirection == DataIn) {
2072 PacketCommandStatus = AtapiPacketCommand (
2073 AtapiScsiPrivate,
2074 Target,
2075 PacketCommand,
2076 Packet->InDataBuffer,
2077 &(Packet->InTransferLength),
2078 DataIn,
2079 TimeoutInMicroSeconds
2080 );
2081 } else {
2082
2083 PacketCommandStatus = AtapiPacketCommand (
2084 AtapiScsiPrivate,
2085 Target,
2086 PacketCommand,
2087 Packet->OutDataBuffer,
2088 &(Packet->OutTransferLength),
2089 DataOut,
2090 TimeoutInMicroSeconds
2091 );
2092 }
2093
2094 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {
2095 Packet->SenseDataLength = 0;
2096 return PacketCommandStatus;
2097 }
2098
2099 //
2100 // Return SenseData if PacketCommandStatus matches
2101 // the following return codes.
2102 //
2103 if ((PacketCommandStatus == EFI_BAD_BUFFER_SIZE) ||
2104 (PacketCommandStatus == EFI_DEVICE_ERROR) ||
2105 (PacketCommandStatus == EFI_TIMEOUT)) {
2106
2107 //
2108 // avoid submit request sense command continuously.
2109 //
2110 if (PacketCommand[0] == OP_REQUEST_SENSE) {
2111 Packet->SenseDataLength = 0;
2112 return PacketCommandStatus;
2113 }
2114
2115 RequestSenseCommand (
2116 AtapiScsiPrivate,
2117 Target,
2118 Packet->Timeout,
2119 Packet->SenseData,
2120 &Packet->SenseDataLength
2121 );
2122 }
2123
2124 return PacketCommandStatus;
2125 }
2126
2127
2128 EFI_STATUS
2129 AtapiPacketCommand (
2130 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2131 UINT32 Target,
2132 UINT8 *PacketCommand,
2133 VOID *Buffer,
2134 UINT32 *ByteCount,
2135 DATA_DIRECTION Direction,
2136 UINT64 TimeoutInMicroSeconds
2137 )
2138 /*++
2139
2140 Routine Description:
2141
2142 Submits ATAPI command packet to the specified ATAPI device.
2143
2144 Arguments:
2145
2146 AtapiScsiPrivate: Private data structure for the specified channel.
2147 Target: The Target ID of the ATAPI device to send the SCSI
2148 Request Packet. To ATAPI devices attached on an IDE
2149 Channel, Target ID 0 indicates Master device;Target
2150 ID 1 indicates Slave device.
2151 PacketCommand: Points to the ATAPI command packet.
2152 Buffer: Points to the transferred data.
2153 ByteCount: When input,indicates the buffer size; when output,
2154 indicates the actually transferred data size.
2155 Direction: Indicates the data transfer direction.
2156 TimeoutInMicroSeconds:
2157 The timeout, in micro second units, to use for the
2158 execution of this ATAPI command.
2159 A TimeoutInMicroSeconds value of 0 means that
2160 this function will wait indefinitely for the ATAPI
2161 command to execute.
2162 If TimeoutInMicroSeconds is greater than zero, then
2163 this function will return EFI_TIMEOUT if the time
2164 required to execute the ATAPI command is greater
2165 than TimeoutInMicroSeconds.
2166
2167 Returns:
2168
2169 EFI_STATUS
2170
2171 --*/
2172 {
2173
2174 UINT16 *CommandIndex;
2175 UINT8 Count;
2176 EFI_STATUS Status;
2177
2178 //
2179 // Set all the command parameters by fill related registers.
2180 // Before write to all the following registers, BSY must be 0.
2181 //
2182 Status = StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
2183 if (EFI_ERROR (Status)) {
2184 return EFI_DEVICE_ERROR;
2185 }
2186
2187
2188 //
2189 // Select device via Device/Head Register.
2190 // "Target = 0" indicates device 0; "Target = 1" indicates device 1
2191 //
2192 WritePortB (
2193 AtapiScsiPrivate->PciIo,
2194 AtapiScsiPrivate->IoPort->Head,
2195 (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
2196 );
2197
2198 //
2199 // Set all the command parameters by fill related registers.
2200 // Before write to all the following registers, BSY DRQ must be 0.
2201 //
2202 Status = StatusDRQClear(AtapiScsiPrivate, TimeoutInMicroSeconds);
2203
2204 if (EFI_ERROR (Status)) {
2205 if (Status == EFI_ABORTED) {
2206 Status = EFI_DEVICE_ERROR;
2207 }
2208 *ByteCount = 0;
2209 return Status;
2210 }
2211
2212 //
2213 // No OVL; No DMA (by setting feature register)
2214 //
2215 WritePortB (
2216 AtapiScsiPrivate->PciIo,
2217 AtapiScsiPrivate->IoPort->Reg1.Feature,
2218 0x00
2219 );
2220
2221 //
2222 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
2223 // determine how much data should be transfered.
2224 //
2225 WritePortB (
2226 AtapiScsiPrivate->PciIo,
2227 AtapiScsiPrivate->IoPort->CylinderLsb,
2228 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
2229 );
2230 WritePortB (
2231 AtapiScsiPrivate->PciIo,
2232 AtapiScsiPrivate->IoPort->CylinderMsb,
2233 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
2234 );
2235
2236 //
2237 // DEFAULT_CTL:0x0a (0000,1010)
2238 // Disable interrupt
2239 //
2240 WritePortB (
2241 AtapiScsiPrivate->PciIo,
2242 AtapiScsiPrivate->IoPort->Alt.DeviceControl,
2243 DEFAULT_CTL
2244 );
2245
2246 //
2247 // Send Packet command to inform device
2248 // that the following data bytes are command packet.
2249 //
2250 WritePortB (
2251 AtapiScsiPrivate->PciIo,
2252 AtapiScsiPrivate->IoPort->Reg.Command,
2253 PACKET_CMD
2254 );
2255
2256 //
2257 // Before data transfer, BSY should be 0 and DRQ should be 1.
2258 // if they are not in specified time frame,
2259 // retrieve Sense Key from Error Register before return.
2260 //
2261 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
2262 if (EFI_ERROR (Status)) {
2263 if (Status == EFI_ABORTED) {
2264 Status = EFI_DEVICE_ERROR;
2265 }
2266
2267 *ByteCount = 0;
2268 return Status;
2269 }
2270
2271 //
2272 // Send out command packet
2273 //
2274 CommandIndex = (UINT16 *) PacketCommand;
2275 for (Count = 0; Count < 6; Count++, CommandIndex++) {
2276 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);
2277 }
2278
2279 //
2280 // call AtapiPassThruPioReadWriteData() function to get
2281 // requested transfer data form device.
2282 //
2283 return AtapiPassThruPioReadWriteData (
2284 AtapiScsiPrivate,
2285 Buffer,
2286 ByteCount,
2287 Direction,
2288 TimeoutInMicroSeconds
2289 );
2290 }
2291
2292 EFI_STATUS
2293 AtapiPassThruPioReadWriteData (
2294 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2295 UINT16 *Buffer,
2296 UINT32 *ByteCount,
2297 DATA_DIRECTION Direction,
2298 UINT64 TimeoutInMicroSeconds
2299 )
2300 /*++
2301
2302 Routine Description:
2303
2304 Performs data transfer between ATAPI device and host after the
2305 ATAPI command packet is sent.
2306
2307 Arguments:
2308
2309 AtapiScsiPrivate: Private data structure for the specified channel.
2310 Buffer: Points to the transferred data.
2311 ByteCount: When input,indicates the buffer size; when output,
2312 indicates the actually transferred data size.
2313 Direction: Indicates the data transfer direction.
2314 TimeoutInMicroSeconds:
2315 The timeout, in micro second units, to use for the
2316 execution of this ATAPI command.
2317 A TimeoutInMicroSeconds value of 0 means that
2318 this function will wait indefinitely for the ATAPI
2319 command to execute.
2320 If TimeoutInMicroSeconds is greater than zero, then
2321 this function will return EFI_TIMEOUT if the time
2322 required to execute the ATAPI command is greater
2323 than TimeoutInMicroSeconds.
2324 Returns:
2325
2326 EFI_STATUS
2327
2328 --*/
2329 {
2330 UINT32 Index;
2331 UINT32 RequiredWordCount;
2332 UINT32 ActualWordCount;
2333 UINT32 WordCount;
2334 EFI_STATUS Status;
2335 UINT16 *ptrBuffer;
2336
2337 Status = EFI_SUCCESS;
2338
2339 //
2340 // Non Data transfer request is also supported.
2341 //
2342 if (*ByteCount == 0 || Buffer == NULL) {
2343 *ByteCount = 0;
2344 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {
2345 return EFI_DEVICE_ERROR;
2346 }
2347 }
2348
2349 ptrBuffer = Buffer;
2350 RequiredWordCount = *ByteCount / 2;
2351
2352 //
2353 // ActuralWordCount means the word count of data really transfered.
2354 //
2355 ActualWordCount = 0;
2356
2357 while (ActualWordCount < RequiredWordCount) {
2358 //
2359 // before each data transfer stream, the host should poll DRQ bit ready,
2360 // which indicates device's ready for data transfer .
2361 //
2362 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);
2363 if (EFI_ERROR (Status)) {
2364 *ByteCount = ActualWordCount * 2;
2365
2366 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
2367
2368 if (ActualWordCount == 0) {
2369 return EFI_DEVICE_ERROR;
2370 }
2371 //
2372 // ActualWordCount > 0
2373 //
2374 if (ActualWordCount < RequiredWordCount) {
2375 return EFI_BAD_BUFFER_SIZE;
2376 }
2377 }
2378 //
2379 // get current data transfer size from Cylinder Registers.
2380 //
2381 WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;
2382 WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);
2383 WordCount = WordCount & 0xffff;
2384 WordCount /= 2;
2385
2386 //
2387 // perform a series data In/Out.
2388 //
2389 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {
2390
2391 if (Direction == DataIn) {
2392
2393 *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);
2394 } else {
2395
2396 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);
2397 }
2398
2399 ptrBuffer++;
2400
2401 }
2402 }
2403 //
2404 // After data transfer is completed, normally, DRQ bit should clear.
2405 //
2406 StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);
2407
2408 //
2409 // read status register to check whether error happens.
2410 //
2411 Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);
2412
2413 *ByteCount = ActualWordCount * 2;
2414
2415 return Status;
2416 }
2417
2418
2419 UINT8
2420 ReadPortB (
2421 IN EFI_PCI_IO_PROTOCOL *PciIo,
2422 IN UINT16 Port
2423 )
2424 /*++
2425
2426 Routine Description:
2427
2428 Read one byte from a specified I/O port.
2429
2430 Arguments:
2431
2432 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2433 Port - IO port
2434
2435 Returns:
2436
2437 A byte read out
2438
2439 --*/
2440 {
2441 UINT8 Data;
2442
2443 Data = 0;
2444 PciIo->Io.Read (
2445 PciIo,
2446 EfiPciIoWidthUint8,
2447 EFI_PCI_IO_PASS_THROUGH_BAR,
2448 (UINT64) Port,
2449 1,
2450 &Data
2451 );
2452 return Data;
2453 }
2454
2455
2456 UINT16
2457 ReadPortW (
2458 IN EFI_PCI_IO_PROTOCOL *PciIo,
2459 IN UINT16 Port
2460 )
2461 /*++
2462
2463 Routine Description:
2464
2465 Read one word from a specified I/O port.
2466
2467 Arguments:
2468
2469 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2470 Port - IO port
2471
2472 Returns:
2473
2474 A word read out
2475 --*/
2476 {
2477 UINT16 Data;
2478
2479 Data = 0;
2480 PciIo->Io.Read (
2481 PciIo,
2482 EfiPciIoWidthUint16,
2483 EFI_PCI_IO_PASS_THROUGH_BAR,
2484 (UINT64) Port,
2485 1,
2486 &Data
2487 );
2488 return Data;
2489 }
2490
2491
2492 VOID
2493 WritePortB (
2494 IN EFI_PCI_IO_PROTOCOL *PciIo,
2495 IN UINT16 Port,
2496 IN UINT8 Data
2497 )
2498 /*++
2499
2500 Routine Description:
2501
2502 Write one byte to a specified I/O port.
2503
2504 Arguments:
2505
2506 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2507 Port - IO port
2508 Data - The data to write
2509
2510 Returns:
2511
2512 NONE
2513
2514 --*/
2515 {
2516 PciIo->Io.Write (
2517 PciIo,
2518 EfiPciIoWidthUint8,
2519 EFI_PCI_IO_PASS_THROUGH_BAR,
2520 (UINT64) Port,
2521 1,
2522 &Data
2523 );
2524 }
2525
2526
2527 VOID
2528 WritePortW (
2529 IN EFI_PCI_IO_PROTOCOL *PciIo,
2530 IN UINT16 Port,
2531 IN UINT16 Data
2532 )
2533 /*++
2534
2535 Routine Description:
2536
2537 Write one word to a specified I/O port.
2538
2539 Arguments:
2540
2541 PciIo - The pointer of EFI_PCI_IO_PROTOCOL
2542 Port - IO port
2543 Data - The data to write
2544
2545 Returns:
2546
2547 NONE
2548
2549 --*/
2550 {
2551 PciIo->Io.Write (
2552 PciIo,
2553 EfiPciIoWidthUint16,
2554 EFI_PCI_IO_PASS_THROUGH_BAR,
2555 (UINT64) Port,
2556 1,
2557 &Data
2558 );
2559 }
2560
2561 EFI_STATUS
2562 StatusDRQClear (
2563 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2564 UINT64 TimeoutInMicroSeconds
2565 )
2566 /*++
2567
2568 Routine Description:
2569
2570 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)
2571 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2572 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2573 elapsed.
2574
2575 Arguments:
2576
2577 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2578 TimeoutInMicroSeconds - The time to wait for
2579
2580 Returns:
2581
2582 EFI_STATUS
2583
2584 --*/
2585 {
2586 UINT64 Delay;
2587 UINT8 StatusRegister;
2588 UINT8 ErrRegister;
2589
2590 if (TimeoutInMicroSeconds == 0) {
2591 Delay = 2;
2592 } else {
2593 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2594 }
2595
2596 do {
2597
2598 StatusRegister = ReadPortB (
2599 AtapiScsiPrivate->PciIo,
2600 AtapiScsiPrivate->IoPort->Reg.Status
2601 );
2602
2603 //
2604 // wait for BSY == 0 and DRQ == 0
2605 //
2606 if ((StatusRegister & (DRQ | BSY)) == 0) {
2607 break;
2608 }
2609 //
2610 // check whether the command is aborted by the device
2611 //
2612 if ((StatusRegister & (BSY | ERR)) == ERR) {
2613
2614 ErrRegister = ReadPortB (
2615 AtapiScsiPrivate->PciIo,
2616 AtapiScsiPrivate->IoPort->Reg1.Error
2617 );
2618 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2619
2620 return EFI_ABORTED;
2621 }
2622 }
2623 //
2624 // Stall for 30 us
2625 //
2626 gBS->Stall (30);
2627
2628 //
2629 // Loop infinitely if not meeting expected condition
2630 //
2631 if (TimeoutInMicroSeconds == 0) {
2632 Delay = 2;
2633 }
2634
2635 Delay--;
2636 } while (Delay);
2637
2638 if (Delay == 0) {
2639 return EFI_TIMEOUT;
2640 }
2641
2642 return EFI_SUCCESS;
2643 }
2644
2645 EFI_STATUS
2646 AltStatusDRQClear (
2647 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2648 UINT64 TimeoutInMicroSeconds
2649 )
2650 /*++
2651
2652 Routine Description:
2653
2654 Check whether DRQ is clear in the Alternate Status Register.
2655 (BSY must also be cleared).If TimeoutInMicroSeconds is zero, this routine should
2656 wait infinitely for DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2657 elapsed.
2658
2659 Arguments:
2660
2661 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2662 TimeoutInMicroSeconds - The time to wait for
2663
2664 Returns:
2665
2666 EFI_STATUS
2667
2668 --*/
2669 {
2670 UINT64 Delay;
2671 UINT8 AltStatusRegister;
2672 UINT8 ErrRegister;
2673
2674 if (TimeoutInMicroSeconds == 0) {
2675 Delay = 2;
2676 } else {
2677 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2678 }
2679
2680 do {
2681
2682 AltStatusRegister = ReadPortB (
2683 AtapiScsiPrivate->PciIo,
2684 AtapiScsiPrivate->IoPort->Alt.AltStatus
2685 );
2686
2687 //
2688 // wait for BSY == 0 and DRQ == 0
2689 //
2690 if ((AltStatusRegister & (DRQ | BSY)) == 0) {
2691 break;
2692 }
2693
2694 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
2695
2696 ErrRegister = ReadPortB (
2697 AtapiScsiPrivate->PciIo,
2698 AtapiScsiPrivate->IoPort->Reg1.Error
2699 );
2700 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2701
2702 return EFI_ABORTED;
2703 }
2704 }
2705 //
2706 // Stall for 30 us
2707 //
2708 gBS->Stall (30);
2709
2710 //
2711 // Loop infinitely if not meeting expected condition
2712 //
2713 if (TimeoutInMicroSeconds == 0) {
2714 Delay = 2;
2715 }
2716
2717 Delay--;
2718 } while (Delay);
2719
2720 if (Delay == 0) {
2721 return EFI_TIMEOUT;
2722 }
2723
2724 return EFI_SUCCESS;
2725 }
2726
2727 EFI_STATUS
2728 StatusDRQReady (
2729 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2730 UINT64 TimeoutInMicroSeconds
2731 )
2732 /*++
2733
2734 Routine Description:
2735
2736 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)
2737 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2738 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2739 elapsed.
2740
2741 Arguments:
2742
2743 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2744 TimeoutInMicroSeconds - The time to wait for
2745
2746 Returns:
2747
2748 EFI_STATUS
2749
2750 --*/
2751 {
2752 UINT64 Delay;
2753 UINT8 StatusRegister;
2754 UINT8 ErrRegister;
2755
2756 if (TimeoutInMicroSeconds == 0) {
2757 Delay = 2;
2758 } else {
2759 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2760 }
2761
2762 do {
2763 //
2764 // read Status Register will clear interrupt
2765 //
2766 StatusRegister = ReadPortB (
2767 AtapiScsiPrivate->PciIo,
2768 AtapiScsiPrivate->IoPort->Reg.Status
2769 );
2770
2771 //
2772 // BSY==0,DRQ==1
2773 //
2774 if ((StatusRegister & (BSY | DRQ)) == DRQ) {
2775 break;
2776 }
2777
2778 if ((StatusRegister & (BSY | ERR)) == ERR) {
2779
2780 ErrRegister = ReadPortB (
2781 AtapiScsiPrivate->PciIo,
2782 AtapiScsiPrivate->IoPort->Reg1.Error
2783 );
2784 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2785 return EFI_ABORTED;
2786 }
2787 }
2788
2789 //
2790 // Stall for 30 us
2791 //
2792 gBS->Stall (30);
2793
2794 //
2795 // Loop infinitely if not meeting expected condition
2796 //
2797 if (TimeoutInMicroSeconds == 0) {
2798 Delay = 2;
2799 }
2800
2801 Delay--;
2802 } while (Delay);
2803
2804 if (Delay == 0) {
2805 return EFI_TIMEOUT;
2806 }
2807
2808 return EFI_SUCCESS;
2809 }
2810
2811 EFI_STATUS
2812 AltStatusDRQReady (
2813 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2814 UINT64 TimeoutInMicroSeconds
2815 )
2816 /*++
2817
2818 Routine Description:
2819
2820 Check whether DRQ is ready in the Alternate Status Register.
2821 (BSY must also be cleared)
2822 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2823 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is
2824 elapsed.
2825
2826 Arguments:
2827
2828 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2829 TimeoutInMicroSeconds - The time to wait for
2830
2831 Returns:
2832
2833 EFI_STATUS
2834
2835 --*/
2836 {
2837 UINT64 Delay;
2838 UINT8 AltStatusRegister;
2839 UINT8 ErrRegister;
2840
2841 if (TimeoutInMicroSeconds == 0) {
2842 Delay = 2;
2843 } else {
2844 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2845 }
2846
2847 do {
2848 //
2849 // read Status Register will clear interrupt
2850 //
2851 AltStatusRegister = ReadPortB (
2852 AtapiScsiPrivate->PciIo,
2853 AtapiScsiPrivate->IoPort->Alt.AltStatus
2854 );
2855 //
2856 // BSY==0,DRQ==1
2857 //
2858 if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {
2859 break;
2860 }
2861
2862 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
2863
2864 ErrRegister = ReadPortB (
2865 AtapiScsiPrivate->PciIo,
2866 AtapiScsiPrivate->IoPort->Reg1.Error
2867 );
2868 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
2869 return EFI_ABORTED;
2870 }
2871 }
2872
2873 //
2874 // Stall for 30 us
2875 //
2876 gBS->Stall (30);
2877
2878 //
2879 // Loop infinitely if not meeting expected condition
2880 //
2881 if (TimeoutInMicroSeconds == 0) {
2882 Delay = 2;
2883 }
2884
2885 Delay--;
2886 } while (Delay);
2887
2888 if (Delay == 0) {
2889 return EFI_TIMEOUT;
2890 }
2891
2892 return EFI_SUCCESS;
2893 }
2894
2895 EFI_STATUS
2896 StatusWaitForBSYClear (
2897 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2898 UINT64 TimeoutInMicroSeconds
2899 )
2900 /*++
2901
2902 Routine Description:
2903
2904 Check whether BSY is clear in the Status Register.
2905 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2906 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2907 elapsed.
2908
2909 Arguments:
2910
2911 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2912 TimeoutInMicroSeconds - The time to wait for
2913
2914 Returns:
2915
2916 EFI_STATUS
2917
2918 --*/
2919 {
2920 UINT64 Delay;
2921 UINT8 StatusRegister;
2922
2923 if (TimeoutInMicroSeconds == 0) {
2924 Delay = 2;
2925 } else {
2926 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2927 }
2928
2929 do {
2930
2931 StatusRegister = ReadPortB (
2932 AtapiScsiPrivate->PciIo,
2933 AtapiScsiPrivate->IoPort->Reg.Status
2934 );
2935 if ((StatusRegister & BSY) == 0x00) {
2936 break;
2937 }
2938
2939 //
2940 // Stall for 30 us
2941 //
2942 gBS->Stall (30);
2943
2944 //
2945 // Loop infinitely if not meeting expected condition
2946 //
2947 if (TimeoutInMicroSeconds == 0) {
2948 Delay = 2;
2949 }
2950
2951 Delay--;
2952 } while (Delay);
2953
2954 if (Delay == 0) {
2955 return EFI_TIMEOUT;
2956 }
2957
2958 return EFI_SUCCESS;
2959 }
2960
2961 EFI_STATUS
2962 AltStatusWaitForBSYClear (
2963 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
2964 UINT64 TimeoutInMicroSeconds
2965 )
2966 /*++
2967
2968 Routine Description:
2969
2970 Check whether BSY is clear in the Alternate Status Register.
2971 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
2972 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is
2973 elapsed.
2974
2975 Arguments:
2976
2977 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
2978 TimeoutInMicroSeconds - The time to wait for
2979
2980 Returns:
2981
2982 EFI_STATUS
2983
2984 --*/
2985 {
2986 UINT64 Delay;
2987 UINT8 AltStatusRegister;
2988
2989 if (TimeoutInMicroSeconds == 0) {
2990 Delay = 2;
2991 } else {
2992 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
2993 }
2994
2995 do {
2996
2997 AltStatusRegister = ReadPortB (
2998 AtapiScsiPrivate->PciIo,
2999 AtapiScsiPrivate->IoPort->Alt.AltStatus
3000 );
3001 if ((AltStatusRegister & BSY) == 0x00) {
3002 break;
3003 }
3004
3005 //
3006 // Stall for 30 us
3007 //
3008 gBS->Stall (30);
3009 //
3010 // Loop infinitely if not meeting expected condition
3011 //
3012 if (TimeoutInMicroSeconds == 0) {
3013 Delay = 2;
3014 }
3015
3016 Delay--;
3017 } while (Delay);
3018
3019 if (Delay == 0) {
3020 return EFI_TIMEOUT;
3021 }
3022
3023 return EFI_SUCCESS;
3024 }
3025
3026 EFI_STATUS
3027 StatusDRDYReady (
3028 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
3029 UINT64 TimeoutInMicroSeconds
3030 )
3031 /*++
3032
3033 Routine Description:
3034
3035 Check whether DRDY is ready in the Status Register.
3036 (BSY must also be cleared)
3037 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3038 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3039 elapsed.
3040
3041 Arguments:
3042
3043 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3044 TimeoutInMicroSeconds - The time to wait for
3045
3046 Returns:
3047
3048 EFI_STATUS
3049
3050 --*/
3051 {
3052 UINT64 Delay;
3053 UINT8 StatusRegister;
3054 UINT8 ErrRegister;
3055
3056 if (TimeoutInMicroSeconds == 0) {
3057 Delay = 2;
3058 } else {
3059 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
3060 }
3061
3062 do {
3063 StatusRegister = ReadPortB (
3064 AtapiScsiPrivate->PciIo,
3065 AtapiScsiPrivate->IoPort->Reg.Status
3066 );
3067 //
3068 // BSY == 0 , DRDY == 1
3069 //
3070 if ((StatusRegister & (DRDY | BSY)) == DRDY) {
3071 break;
3072 }
3073
3074 if ((StatusRegister & (BSY | ERR)) == ERR) {
3075
3076 ErrRegister = ReadPortB (
3077 AtapiScsiPrivate->PciIo,
3078 AtapiScsiPrivate->IoPort->Reg1.Error
3079 );
3080 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
3081 return EFI_ABORTED;
3082 }
3083 }
3084
3085 //
3086 // Stall for 30 us
3087 //
3088 gBS->Stall (30);
3089 //
3090 // Loop infinitely if not meeting expected condition
3091 //
3092 if (TimeoutInMicroSeconds == 0) {
3093 Delay = 2;
3094 }
3095
3096 Delay--;
3097 } while (Delay);
3098
3099 if (Delay == 0) {
3100 return EFI_TIMEOUT;
3101 }
3102
3103 return EFI_SUCCESS;
3104 }
3105
3106 EFI_STATUS
3107 AltStatusDRDYReady (
3108 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,
3109 UINT64 TimeoutInMicroSeconds
3110 )
3111 /*++
3112
3113 Routine Description:
3114
3115 Check whether DRDY is ready in the Alternate Status Register.
3116 (BSY must also be cleared)
3117 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for
3118 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is
3119 elapsed.
3120
3121 Arguments:
3122
3123 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3124 TimeoutInMicroSeconds - The time to wait for
3125
3126 Returns:
3127
3128 EFI_STATUS
3129
3130 --*/
3131 {
3132 UINT64 Delay;
3133 UINT8 AltStatusRegister;
3134 UINT8 ErrRegister;
3135
3136 if (TimeoutInMicroSeconds == 0) {
3137 Delay = 2;
3138 } else {
3139 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;
3140 }
3141
3142 do {
3143 AltStatusRegister = ReadPortB (
3144 AtapiScsiPrivate->PciIo,
3145 AtapiScsiPrivate->IoPort->Alt.AltStatus
3146 );
3147 //
3148 // BSY == 0 , DRDY == 1
3149 //
3150 if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {
3151 break;
3152 }
3153
3154 if ((AltStatusRegister & (BSY | ERR)) == ERR) {
3155
3156 ErrRegister = ReadPortB (
3157 AtapiScsiPrivate->PciIo,
3158 AtapiScsiPrivate->IoPort->Reg1.Error
3159 );
3160 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {
3161 return EFI_ABORTED;
3162 }
3163 }
3164
3165 //
3166 // Stall for 30 us
3167 //
3168 gBS->Stall (30);
3169 //
3170 // Loop infinitely if not meeting expected condition
3171 //
3172 if (TimeoutInMicroSeconds == 0) {
3173 Delay = 2;
3174 }
3175
3176 Delay--;
3177 } while (Delay);
3178
3179 if (Delay == 0) {
3180 return EFI_TIMEOUT;
3181 }
3182
3183 return EFI_SUCCESS;
3184 }
3185
3186 EFI_STATUS
3187 AtapiPassThruCheckErrorStatus (
3188 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
3189 )
3190 /*++
3191
3192 Routine Description:
3193
3194 Check Error Register for Error Information.
3195
3196 Arguments:
3197
3198 AtapiScsiPrivate - The pointer of ATAPI_SCSI_PASS_THRU_DEV
3199
3200 Returns:
3201
3202 EFI_STATUS
3203
3204 --*/
3205 {
3206 UINT8 StatusRegister;
3207 UINT8 ErrorRegister;
3208
3209 StatusRegister = ReadPortB (
3210 AtapiScsiPrivate->PciIo,
3211 AtapiScsiPrivate->IoPort->Reg.Status
3212 );
3213
3214 DEBUG_CODE_BEGIN ();
3215
3216 if (StatusRegister & DWF) {
3217 DEBUG (
3218 (EFI_D_BLKIO,
3219 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",
3220 StatusRegister)
3221 );
3222 }
3223
3224 if (StatusRegister & CORR) {
3225 DEBUG (
3226 (EFI_D_BLKIO,
3227 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",
3228 StatusRegister)
3229 );
3230 }
3231
3232 if (StatusRegister & ERR) {
3233 ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);
3234
3235
3236 if (ErrorRegister & BBK_ERR) {
3237 DEBUG (
3238 (EFI_D_BLKIO,
3239 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
3240 ErrorRegister)
3241 );
3242 }
3243
3244 if (ErrorRegister & UNC_ERR) {
3245 DEBUG (
3246 (EFI_D_BLKIO,
3247 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
3248 ErrorRegister)
3249 );
3250 }
3251
3252 if (ErrorRegister & MC_ERR) {
3253 DEBUG (
3254 (EFI_D_BLKIO,
3255 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",
3256 ErrorRegister)
3257 );
3258 }
3259
3260 if (ErrorRegister & ABRT_ERR) {
3261 DEBUG (
3262 (EFI_D_BLKIO,
3263 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",
3264 ErrorRegister)
3265 );
3266 }
3267
3268 if (ErrorRegister & TK0NF_ERR) {
3269 DEBUG (
3270 (EFI_D_BLKIO,
3271 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
3272 ErrorRegister)
3273 );
3274 }
3275
3276 if (ErrorRegister & AMNF_ERR) {
3277 DEBUG (
3278 (EFI_D_BLKIO,
3279 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
3280 ErrorRegister)
3281 );
3282 }
3283 }
3284
3285 DEBUG_CODE_END ();
3286
3287 if ((StatusRegister & (ERR | DWF | CORR)) == 0) {
3288 return EFI_SUCCESS;
3289 }
3290
3291
3292 return EFI_DEVICE_ERROR;
3293 }
3294
3295
3296 /**
3297 Installs Scsi Pass Thru and/or Ext Scsi Pass Thru
3298 protocols based on feature flags.
3299
3300 @param Controller The controller handle to
3301 install these protocols on.
3302 @param AtapiScsiPrivate A pointer to the protocol private
3303 data structure.
3304
3305 @retval EFI_SUCCESS The installation succeeds.
3306 @retval other The installation fails.
3307
3308 **/
3309 EFI_STATUS
3310 InstallScsiPassThruProtocols (
3311 IN EFI_HANDLE *ControllerHandle,
3312 IN ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate
3313 )
3314 {
3315 EFI_STATUS Status;
3316 EFI_SCSI_PASS_THRU_PROTOCOL *ScsiPassThru;
3317 EFI_EXT_SCSI_PASS_THRU_PROTOCOL *ExtScsiPassThru;
3318
3319 ScsiPassThru = &AtapiScsiPrivate->ScsiPassThru;
3320 ExtScsiPassThru = &AtapiScsiPrivate->ExtScsiPassThru;
3321
3322 if (FeaturePcdGet (PcdSupportScsiPassThru)) {
3323 ScsiPassThru = CopyMem (ScsiPassThru, &gScsiPassThruProtocolTemplate, sizeof (*ScsiPassThru));
3324 if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
3325 ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));
3326 Status = gBS->InstallMultipleProtocolInterfaces (
3327 ControllerHandle,
3328 &gEfiScsiPassThruProtocolGuid,
3329 ScsiPassThru,
3330 &gEfiExtScsiPassThruProtocolGuid,
3331 ExtScsiPassThru,
3332 NULL
3333 );
3334 } else {
3335 Status = gBS->InstallMultipleProtocolInterfaces (
3336 ControllerHandle,
3337 &gEfiScsiPassThruProtocolGuid,
3338 ScsiPassThru,
3339 NULL
3340 );
3341 }
3342 } else {
3343 if (FeaturePcdGet (PcdSupportExtScsiPassThru)) {
3344 ExtScsiPassThru = CopyMem (ExtScsiPassThru, &gExtScsiPassThruProtocolTemplate, sizeof (*ExtScsiPassThru));
3345 Status = gBS->InstallMultipleProtocolInterfaces (
3346 ControllerHandle,
3347 &gEfiExtScsiPassThruProtocolGuid,
3348 ExtScsiPassThru,
3349 NULL
3350 );
3351 } else {
3352 //
3353 // This driver must support either ScsiPassThru or
3354 // ExtScsiPassThru protocols
3355 //
3356 ASSERT (FALSE);
3357 Status = EFI_UNSUPPORTED;
3358 }
3359 }
3360
3361 return Status;
3362 }
3363
3364 /**
3365 The user Entry Point for module AtapiPassThru. The user code starts with this function.
3366
3367 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3368 @param[in] SystemTable A pointer to the EFI System Table.
3369
3370 @retval EFI_SUCCESS The entry point is executed successfully.
3371 @retval other Some error occurs when executing this entry point.
3372
3373 **/
3374 EFI_STATUS
3375 EFIAPI
3376 InitializeAtapiPassThru(
3377 IN EFI_HANDLE ImageHandle,
3378 IN EFI_SYSTEM_TABLE *SystemTable
3379 )
3380 {
3381 EFI_STATUS Status;
3382
3383 //
3384 // Install driver model protocol(s).
3385 //
3386 Status = EfiLibInstallDriverBindingComponentName2 (
3387 ImageHandle,
3388 SystemTable,
3389 &gAtapiScsiPassThruDriverBinding,
3390 ImageHandle,
3391 &gAtapiScsiPassThruComponentName,
3392 &gAtapiScsiPassThruComponentName2
3393 );
3394 ASSERT_EFI_ERROR (Status);
3395
3396 //
3397 // Install EFI Driver Supported EFI Version Protocol required for
3398 // EFI drivers that are on PCI and other plug in cards.
3399 //
3400 gAtapiScsiPassThruDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
3401 Status = gBS->InstallMultipleProtocolInterfaces (
3402 &ImageHandle,
3403 &gEfiDriverSupportedEfiVersionProtocolGuid,
3404 &gAtapiScsiPassThruDriverSupportedEfiVersion,
3405 NULL
3406 );
3407 ASSERT_EFI_ERROR (Status);
3408
3409 return Status;
3410 }