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