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