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