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