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