]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/AtapiPassThru/Dxe/AtapiPassThru.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[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
1cc8ee78 48static SCSI_COMMAND_SET gEndTable = { 0xff, (DATA_DIRECTION) 0xff };\r
878ddf1f 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
1cc8ee78 86 { 0xff, (DATA_DIRECTION) 0xff } \r
878ddf1f 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
61fb1657 96 0xa,\r
878ddf1f 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
878ddf1f 598 EFI_DEV_PATH *Node;\r
599\r
878ddf1f 600 //\r
601 // Validate parameters passed in.\r
602 //\r
603 \r
604 if (DevicePath == NULL) {\r
605 return EFI_INVALID_PARAMETER;\r
606 }\r
607 \r
608 //\r
609 // can not build device path for the SCSI Host Controller.\r
610 //\r
611 if ((Target > (MAX_TARGET_ID - 1)) || (Lun != 0)) {\r
612 return EFI_NOT_FOUND;\r
613 }\r
614\r
615 Node = AllocateZeroPool (sizeof (EFI_DEV_PATH));\r
616 if (Node == NULL) {\r
617 return EFI_OUT_OF_RESOURCES;\r
618 }\r
619\r
620 Node->DevPath.Type = MESSAGING_DEVICE_PATH;\r
621 Node->DevPath.SubType = MSG_ATAPI_DP;\r
622 SetDevicePathNodeLength (&Node->DevPath, sizeof (ATAPI_DEVICE_PATH));\r
623\r
624 Node->Atapi.PrimarySecondary = (UINT8) (Target / 2);\r
625 Node->Atapi.SlaveMaster = (UINT8) (Target % 2);\r
626 Node->Atapi.Lun = (UINT16) Lun;\r
627\r
628 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;\r
629\r
630 return EFI_SUCCESS;\r
631}\r
632\r
ed72955c 633/**\r
634 Used to translate a device path node to a Target ID and LUN.\r
635\r
636 @param This Protocol instance pointer.\r
637 @param DevicePath A pointer to the device path node that\r
638 describes a SCSI device on the SCSI channel.\r
639 @param Target A pointer to the Target ID of a SCSI device\r
640 on the SCSI channel.\r
641 @param Lun A pointer to the LUN of a SCSI device on\r
642 the SCSI channel.\r
643\r
644 @retval EFI_SUCCESS DevicePath was successfully translated to a\r
645 Target ID and LUN, and they were returned\r
646 in Target and Lun.\r
647 @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
648 @retval EFI_INVALID_PARAMETER Target is NULL.\r
649 @retval EFI_INVALID_PARAMETER Lun is NULL.\r
650 @retval EFI_UNSUPPORTED This driver does not support the device path\r
651 node type in DevicePath.\r
652 @retval EFI_NOT_FOUND A valid translation from DevicePath to a\r
653 Target ID and LUN does not exist.\r
654\r
655**/\r
878ddf1f 656EFI_STATUS\r
657EFIAPI\r
658AtapiScsiPassThruGetTargetLun (\r
659 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
660 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
661 OUT UINT32 *Target,\r
662 OUT UINT64 *Lun\r
663 )\r
878ddf1f 664{\r
665 EFI_DEV_PATH *Node;\r
666\r
667 //\r
668 // Validate parameters passed in.\r
669 //\r
670 if (DevicePath == NULL || Target == NULL || Lun == NULL) {\r
671 return EFI_INVALID_PARAMETER;\r
672 }\r
673 \r
674 //\r
675 // Check whether the DevicePath belongs to SCSI_DEVICE_PATH\r
676 //\r
677 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
678 (DevicePath->SubType != MSG_ATAPI_DP) ||\r
679 (DevicePathNodeLength(DevicePath) != sizeof(ATAPI_DEVICE_PATH))) {\r
680 return EFI_UNSUPPORTED;\r
681 }\r
682\r
683 Node = (EFI_DEV_PATH *) DevicePath;\r
684\r
685 *Target = Node->Atapi.PrimarySecondary * 2 + Node->Atapi.SlaveMaster;\r
686 *Lun = Node->Atapi.Lun;\r
687\r
688 if (*Target > (MAX_TARGET_ID - 1) || *Lun != 0) {\r
689 return EFI_NOT_FOUND;\r
690 }\r
691\r
692 return EFI_SUCCESS;\r
693}\r
694\r
ed72955c 695/**\r
696 Resets a SCSI channel.This operation resets all the \r
697 SCSI devices connected to the SCSI channel.\r
698\r
699 @param This Protocol instance pointer.\r
700\r
701 @retval EFI_SUCCESS The SCSI channel was reset.\r
702 @retval EFI_UNSUPPORTED The SCSI channel does not support\r
703 a channel reset operation.\r
704 @retval EFI_DEVICE_ERROR A device error occurred while\r
705 attempting to reset the SCSI channel.\r
706 @retval EFI_TIMEOUT A timeout occurred while attempting\r
707 to reset the SCSI channel.\r
708\r
709**/\r
878ddf1f 710EFI_STATUS\r
711EFIAPI\r
712AtapiScsiPassThruResetChannel (\r
713 IN EFI_SCSI_PASS_THRU_PROTOCOL *This\r
714 )\r
878ddf1f 715{\r
716 UINT8 DeviceControlValue;\r
717 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
718 UINT8 Index;\r
719\r
720 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
721\r
722 //\r
723 // Reset both Primary channel and Secondary channel.\r
724 // so, the IoPort pointer must point to the right I/O Register group\r
725 //\r
726 for (Index = 0; Index < 2; Index++) {\r
727 //\r
728 // Reset\r
729 //\r
730 AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[Index];\r
731\r
732 DeviceControlValue = 0;\r
733 //\r
734 // set SRST bit to initiate soft reset\r
735 //\r
736 DeviceControlValue |= SRST;\r
737 //\r
738 // disable Interrupt\r
739 //\r
740 DeviceControlValue |= bit (1);\r
741 WritePortB (\r
742 AtapiScsiPrivate->PciIo,\r
743 AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
744 DeviceControlValue\r
745 );\r
746\r
747 //\r
748 // Wait 10us\r
749 //\r
750 gBS->Stall (10);\r
751\r
752 //\r
753 // Clear SRST bit\r
754 // 0xfb:1111,1011\r
755 //\r
756 DeviceControlValue &= 0xfb;\r
757 \r
758 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Alt.DeviceControl, DeviceControlValue);\r
759\r
760 //\r
761 // slave device needs at most 31s to clear BSY\r
762 //\r
763 if (StatusWaitForBSYClear (AtapiScsiPrivate, 31000) == EFI_TIMEOUT) {\r
764 return EFI_DEVICE_ERROR;\r
765 }\r
766 }\r
767\r
768 return EFI_SUCCESS;\r
769}\r
770\r
ed72955c 771/**\r
772 Resets a SCSI device that is connected to a SCSI channel.\r
773\r
774 @param This Protocol instance pointer.\r
775 @param Target The Target ID of the SCSI device to reset.\r
776 @param Lun The LUN of the SCSI device to reset.\r
777\r
778 @retval EFI_SUCCESS The SCSI device specified by Target and\r
779 Lun was reset.\r
780 @retval EFI_UNSUPPORTED The SCSI channel does not support a target\r
781 reset operation.\r
782 @retval EFI_INVALID_PARAMETER Target or Lun are invalid.\r
783 @retval EFI_DEVICE_ERROR A device error occurred while attempting\r
784 to reset the SCSI device specified by Target\r
785 and Lun.\r
786 @retval EFI_TIMEOUT A timeout occurred while attempting to reset\r
787 the SCSI device specified by Target and Lun.\r
788\r
789**/\r
878ddf1f 790EFI_STATUS\r
791EFIAPI\r
792AtapiScsiPassThruResetTarget (\r
793 IN EFI_SCSI_PASS_THRU_PROTOCOL *This,\r
794 IN UINT32 Target,\r
795 IN UINT64 Lun\r
796 )\r
878ddf1f 797{\r
798 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate;\r
799 UINT8 Command;\r
800 UINT8 DeviceSelect;\r
801\r
802 AtapiScsiPrivate = ATAPI_SCSI_PASS_THRU_DEV_FROM_THIS (This);\r
803\r
804 if (Target > MAX_TARGET_ID) {\r
805 return EFI_INVALID_PARAMETER;\r
806 }\r
807 //\r
808 // Directly return EFI_SUCCESS if want to reset the host controller\r
809 //\r
810 if (Target == This->Mode->AdapterId) {\r
811 return EFI_SUCCESS;\r
812 }\r
813 \r
814 //\r
815 // According to Target ID, reset the Atapi I/O Register mapping\r
816 // (Target Id in [0,1] area, using gAtapiIoPortRegisters[0],\r
817 // Target Id in [2,3] area, using gAtapiIoPortRegisters[1]\r
818 //\r
819 if ((Target / 2) == 0) {\r
820 AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[0];\r
821 } else {\r
822 AtapiScsiPrivate->IoPort = &gAtapiIoPortRegisters[1];\r
823 }\r
824 \r
825 //\r
826 // for ATAPI device, no need to wait DRDY ready after device selecting.\r
827 //\r
828 // bit7 and bit5 are both set to 1 for backward compatibility\r
829 //\r
830 DeviceSelect = (UINT8) (((bit (7) | bit (5)) | (Target << 4)));\r
831 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Head, DeviceSelect);\r
832\r
833 Command = ATAPI_SOFT_RESET_CMD;\r
834 WritePortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg.Command, Command);\r
835\r
836 //\r
837 // BSY clear is the only status return to the host by the device\r
838 // when reset is complete.\r
839 // slave device needs at most 31s to clear BSY\r
840 //\r
841 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, 31000))) {\r
842 return EFI_DEVICE_ERROR;\r
843 }\r
844 \r
845 //\r
846 // stall 5 seconds to make the device status stable\r
847 //\r
848 gBS->Stall (5000000);\r
849\r
850 return EFI_SUCCESS;\r
851}\r
852\r
853 \r
ed72955c 854/**\r
855 Checks the parameters in the SCSI Request Packet to make sure\r
856 they are valid for a SCSI Pass Thru request.\r
857\r
858 @todo function comment is missing 'Routine Description:'\r
859 @todo function comment is missing 'Arguments:'\r
860 @todo function comment is missing 'Returns:'\r
861 @todo Packet - add argument and description to function comment\r
862 @todo EFI_INVALID_PARAMETER - add return value to function comment\r
863 @todo EFI_INVALID_PARAMETER - add return value to function comment\r
864 @todo EFI_INVALID_PARAMETER - add return value to function comment\r
865 @todo EFI_UNSUPPORTED - add return value to function comment\r
866 @todo EFI_SUCCESS - add return value to function comment\r
867**/\r
878ddf1f 868EFI_STATUS\r
869CheckSCSIRequestPacket (\r
870 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
871 )\r
878ddf1f 872{\r
873 if (Packet == NULL) {\r
874 return EFI_INVALID_PARAMETER;\r
875 }\r
876\r
877 if (!ValidCdbLength (Packet->CdbLength)) {\r
878 return EFI_INVALID_PARAMETER;\r
879 }\r
880\r
881 if (Packet->Cdb == NULL) {\r
882 return EFI_INVALID_PARAMETER;\r
883 }\r
884 \r
885 //\r
886 // Checks whether the request command is supported.\r
887 //\r
888 if (!IsCommandValid (Packet)) {\r
889 return EFI_UNSUPPORTED;\r
890 }\r
891\r
892 return EFI_SUCCESS;\r
893}\r
894\r
ed72955c 895/**\r
896 Checks the requested SCSI command: \r
897 Is it supported by this driver?\r
898 Is the Data transfer direction reasonable?\r
899\r
900 @todo function comment is missing 'Routine Description:'\r
901 @todo function comment is missing 'Arguments:'\r
902 @todo function comment is missing 'Returns:'\r
903 @todo Packet - add argument and description to function comment\r
904**/\r
878ddf1f 905BOOLEAN\r
906IsCommandValid (\r
907 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
908 )\r
878ddf1f 909{\r
910 UINT8 Index;\r
911 UINT8 *OpCode;\r
912\r
913 OpCode = (UINT8 *) (Packet->Cdb);\r
914\r
915 for (Index = 0; CompareMem (&gSupportedATAPICommands[Index], &gEndTable, sizeof (SCSI_COMMAND_SET)); Index++) {\r
916\r
917 if (*OpCode == gSupportedATAPICommands[Index].OpCode) {\r
918 //\r
919 // Check whether the requested Command is supported by this driver\r
920 //\r
921 if (Packet->DataDirection == DataIn) {\r
922 //\r
923 // Check whether the requested data direction conforms to\r
924 // what it should be.\r
925 //\r
926 if (gSupportedATAPICommands[Index].Direction == DataOut) {\r
927 return FALSE;\r
928 }\r
929 }\r
930\r
931 if (Packet->DataDirection == DataOut) {\r
932 //\r
933 // Check whether the requested data direction conforms to\r
934 // what it should be.\r
935 //\r
936 if (gSupportedATAPICommands[Index].Direction == DataIn) {\r
937 return FALSE;\r
938 }\r
939 }\r
940\r
941 return TRUE;\r
942 }\r
943 }\r
944\r
945 return FALSE;\r
946}\r
947\r
ed72955c 948/**\r
949 Performs blocking I/O request.\r
950\r
951 @param AtapiScsiPrivate Private data structure for the specified channel.\r
952 @param Target The Target ID of the ATAPI device to send the SCSI\r
953 Request Packet. To ATAPI devices attached on an IDE\r
954 Channel, Target ID 0 indicates Master device;Target\r
955 ID 1 indicates Slave device.\r
956 @param Packet The SCSI Request Packet to send to the ATAPI device\r
957 specified by Target.\r
958\r
959 @todo AtapiScsiPrivate - add argument and description to function comment\r
960**/\r
878ddf1f 961EFI_STATUS\r
962SubmitBlockingIoCommand (\r
963 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
964 UINT32 Target,\r
965 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet\r
966 )\r
878ddf1f 967{\r
968 UINT8 PacketCommand[12];\r
969 UINT64 TimeoutInMicroSeconds;\r
970 EFI_STATUS PacketCommandStatus;\r
971\r
972 //\r
973 // Fill ATAPI Command Packet according to CDB\r
974 //\r
975 ZeroMem (&PacketCommand, 12);\r
976 CopyMem (&PacketCommand, Packet->Cdb, Packet->CdbLength);\r
977\r
978 //\r
979 // Timeout is 100ns unit, convert it to 1000ns (1us) unit.\r
980 //\r
981 TimeoutInMicroSeconds = DivU64x32 (Packet->Timeout, (UINT32) 10);\r
982\r
983 //\r
984 // Submit ATAPI Command Packet\r
985 //\r
986 PacketCommandStatus = AtapiPacketCommand (\r
987 AtapiScsiPrivate,\r
988 Target,\r
989 PacketCommand,\r
990 Packet->DataBuffer,\r
991 &(Packet->TransferLength),\r
1cc8ee78 992 (DATA_DIRECTION) Packet->DataDirection,\r
878ddf1f 993 TimeoutInMicroSeconds\r
994 );\r
995 if (!EFI_ERROR (PacketCommandStatus) || (Packet->SenseData == NULL)) {\r
996 Packet->SenseDataLength = 0;\r
997 return PacketCommandStatus;\r
998 }\r
999 //\r
1000 // Return SenseData if PacketCommandStatus matches\r
1001 // the following return codes.\r
1002 //\r
1003 if ((PacketCommandStatus == EFI_WARN_BUFFER_TOO_SMALL) ||\r
1004 (PacketCommandStatus == EFI_DEVICE_ERROR) ||\r
1005 (PacketCommandStatus == EFI_TIMEOUT)) {\r
1006 \r
1007 //\r
1008 // avoid submit request sense command continuously.\r
1009 //\r
1010 if (PacketCommand[0] == OP_REQUEST_SENSE) {\r
1011 Packet->SenseDataLength = 0;\r
1012 return PacketCommandStatus;\r
1013 }\r
1014\r
1015 RequestSenseCommand (\r
1016 AtapiScsiPrivate,\r
1017 Target,\r
1018 Packet->Timeout,\r
1019 Packet->SenseData,\r
1020 &Packet->SenseDataLength\r
1021 );\r
1022 }\r
1023\r
1024 return PacketCommandStatus;\r
1025}\r
1026\r
ed72955c 1027/**\r
1028 RequestSenseCommand\r
1029\r
1030 @param AtapiScsiPrivate\r
1031 @param Target\r
1032 @param Timeout\r
1033 @param SenseData\r
1034 @param SenseDataLength\r
1035\r
1036 @todo Add function description\r
1037 @todo AtapiScsiPrivate TODO: add argument description\r
1038 @todo Target TODO: add argument description\r
1039 @todo Timeout TODO: add argument description\r
1040 @todo SenseData TODO: add argument description\r
1041 @todo SenseDataLength TODO: add argument description\r
1042 @todo add return values\r
1043**/\r
878ddf1f 1044EFI_STATUS\r
1045RequestSenseCommand (\r
1046 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1047 UINT32 Target,\r
1048 UINT64 Timeout,\r
1049 VOID *SenseData,\r
1050 UINT8 *SenseDataLength\r
1051 )\r
878ddf1f 1052{\r
1053 EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET Packet;\r
1054 UINT8 Cdb[12];\r
1055 EFI_STATUS Status;\r
1056\r
1057 ZeroMem (&Packet, sizeof (EFI_SCSI_PASS_THRU_SCSI_REQUEST_PACKET));\r
1058 ZeroMem (Cdb, 12);\r
1059\r
1060 Cdb[0] = OP_REQUEST_SENSE;\r
1061 Cdb[4] = (UINT8) (*SenseDataLength);\r
1062\r
1063 Packet.Timeout = Timeout;\r
1064 Packet.DataBuffer = SenseData;\r
1065 Packet.SenseData = NULL;\r
1066 Packet.Cdb = Cdb;\r
1067 Packet.TransferLength = *SenseDataLength;\r
1068 Packet.CdbLength = 12;\r
1069 Packet.DataDirection = DataIn;\r
1070\r
1071 Status = SubmitBlockingIoCommand (AtapiScsiPrivate, Target, &Packet);\r
1072 *SenseDataLength = (UINT8) (Packet.TransferLength);\r
1073 return Status;\r
1074}\r
1075\r
ed72955c 1076/**\r
1077 Submits ATAPI command packet to the specified ATAPI device.\r
1078\r
1079 @param AtapiScsiPrivate: Private data structure for the specified channel.\r
1080 @param Target: The Target ID of the ATAPI device to send the SCSI\r
1081 Request Packet. To ATAPI devices attached on an IDE\r
1082 Channel, Target ID 0 indicates Master device;Target\r
1083 ID 1 indicates Slave device.\r
1084 @param PacketCommand: Points to the ATAPI command packet.\r
1085 @param Buffer: Points to the transferred data.\r
1086 @param ByteCount: When input,indicates the buffer size; when output,\r
1087 indicates the actually transferred data size.\r
1088 @param Direction: Indicates the data transfer direction.\r
1089 @param TimeoutInMicroSeconds: The timeout, in micro second units,\r
1090 to use for the execution of this ATAPI command.\r
1091 A TimeoutInMicroSeconds value of 0 means that\r
1092 this function will wait indefinitely for the ATAPI\r
1093 command to execute.\r
1094 <P>\r
1095 If TimeoutInMicroSeconds is greater than zero, then\r
1096 this function will return EFI_TIMEOUT if the time\r
1097 required to execute the ATAPI command is greater\r
1098 than TimeoutInMicroSeconds.\r
1099 </P>\r
1100\r
1101 @todo AtapiScsiPrivate - add argument and description to function comment\r
1102 @todo PacketCommand - add argument and description to function comment\r
1103 @todo Buffer - add argument and description to function comment\r
1104 @todo ByteCount - add argument and description to function comment\r
1105 @todo Direction - add argument and description to function comment\r
1106**/\r
878ddf1f 1107EFI_STATUS\r
1108AtapiPacketCommand (\r
1109 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1110 UINT32 Target,\r
1111 UINT8 *PacketCommand,\r
1112 VOID *Buffer,\r
1113 UINT32 *ByteCount,\r
1114 DATA_DIRECTION Direction,\r
1115 UINT64 TimeoutInMicroSeconds\r
1116 )\r
878ddf1f 1117{\r
1118\r
1119 UINT16 *CommandIndex;\r
1120 UINT8 Count;\r
1121 EFI_STATUS Status;\r
1122\r
1123 //\r
1124 // Set all the command parameters by fill related registers.\r
1125 // Before write to all the following registers, BSY and DRQ must be 0.\r
1126 //\r
1127 Status = StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
1128 if (EFI_ERROR (Status)) {\r
1129 if (Status == EFI_ABORTED) {\r
1130 Status = EFI_DEVICE_ERROR;\r
1131 }\r
1132\r
1133 *ByteCount = 0;\r
1134 return Status;\r
1135 }\r
1136 //\r
1137 // Select device via Device/Head Register.\r
1138 // "Target = 0" indicates device 0; "Target = 1" indicates device 1\r
1139 //\r
1140 WritePortB (\r
1141 AtapiScsiPrivate->PciIo,\r
1142 AtapiScsiPrivate->IoPort->Head,\r
1143 (UINT8) ((Target << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)\r
1144 );\r
1145\r
1146 //\r
1147 // No OVL; No DMA (by setting feature register)\r
1148 //\r
1149 WritePortB (\r
1150 AtapiScsiPrivate->PciIo,\r
1151 AtapiScsiPrivate->IoPort->Reg1.Feature,\r
1152 0x00\r
1153 );\r
1154\r
1155 //\r
1156 // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device\r
1157 // determine how much data should be transfered.\r
1158 //\r
1159 WritePortB (\r
1160 AtapiScsiPrivate->PciIo,\r
1161 AtapiScsiPrivate->IoPort->CylinderLsb,\r
1162 (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)\r
1163 );\r
1164 WritePortB (\r
1165 AtapiScsiPrivate->PciIo,\r
1166 AtapiScsiPrivate->IoPort->CylinderMsb,\r
1167 (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)\r
1168 );\r
1169\r
1170 //\r
1171 // DEFAULT_CTL:0x0a (0000,1010)\r
1172 // Disable interrupt\r
1173 //\r
1174 WritePortB (\r
1175 AtapiScsiPrivate->PciIo,\r
1176 AtapiScsiPrivate->IoPort->Alt.DeviceControl,\r
1177 DEFAULT_CTL\r
1178 );\r
1179\r
1180 //\r
1181 // Send Packet command to inform device\r
1182 // that the following data bytes are command packet.\r
1183 //\r
1184 WritePortB (\r
1185 AtapiScsiPrivate->PciIo,\r
1186 AtapiScsiPrivate->IoPort->Reg.Command,\r
1187 PACKET_CMD\r
1188 );\r
1189\r
1190 //\r
1191 // Before data transfer, BSY should be 0 and DRQ should be 1.\r
1192 // if they are not in specified time frame,\r
1193 // retrieve Sense Key from Error Register before return.\r
1194 //\r
1195 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
1196 if (EFI_ERROR (Status)) {\r
1197 if (Status == EFI_ABORTED) {\r
1198 Status = EFI_DEVICE_ERROR;\r
1199 }\r
1200\r
1201 *ByteCount = 0;\r
1202 return Status;\r
1203 }\r
1204\r
1205 //\r
1206 // Send out command packet\r
1207 //\r
1208 CommandIndex = (UINT16 *) PacketCommand;\r
1209 for (Count = 0; Count < 6; Count++, CommandIndex++) {\r
1210 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *CommandIndex);\r
1211 }\r
1212\r
1213 //\r
1214 // call AtapiPassThruPioReadWriteData() function to get\r
1215 // requested transfer data form device.\r
1216 //\r
1217 return AtapiPassThruPioReadWriteData (\r
1218 AtapiScsiPrivate,\r
1219 Buffer,\r
1220 ByteCount,\r
1221 Direction,\r
1222 TimeoutInMicroSeconds\r
1223 );\r
1224}\r
1225\r
ed72955c 1226/**\r
1227 Performs data transfer between ATAPI device and host after the\r
1228 ATAPI command packet is sent.\r
1229\r
1230 @param AtapiScsiPrivate: Private data structure for the specified channel.\r
1231 @param Buffer: Points to the transferred data.\r
1232 @param ByteCount: When input,indicates the buffer size; when output,\r
1233 indicates the actually transferred data size.\r
1234 @param Direction: Indicates the data transfer direction.\r
1235 @param TimeoutInMicroSeconds: The timeout, in micro second units,\r
1236 to use for the execution of this ATAPI command.\r
1237 A TimeoutInMicroSeconds value of 0 means that\r
1238 this function will wait indefinitely for the ATAPI\r
1239 command to execute.\r
1240 <P>\r
1241 If TimeoutInMicroSeconds is greater than zero, then\r
1242 this function will return EFI_TIMEOUT if the time\r
1243 required to execute the ATAPI command is greater\r
1244 than TimeoutInMicroSeconds.\r
1245 </P>\r
1246\r
1247 @todo AtapiScsiPrivate - add argument and description to function comment\r
1248 @todo Buffer - add argument and description to function comment\r
1249 @todo ByteCount - add argument and description to function comment\r
1250 @todo Direction - add argument and description to function comment\r
1251 @todo EFI_DEVICE_ERROR - add return value to function comment\r
1252 @todo EFI_DEVICE_ERROR - add return value to function comment\r
1253 @todo EFI_WARN_BUFFER_TOO_SMALL - add return value to function comment\r
1254**/\r
878ddf1f 1255EFI_STATUS\r
1256AtapiPassThruPioReadWriteData (\r
1257 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1258 UINT16 *Buffer,\r
1259 UINT32 *ByteCount,\r
1260 DATA_DIRECTION Direction,\r
1261 UINT64 TimeoutInMicroSeconds\r
1262 )\r
878ddf1f 1263{\r
1264 UINT32 Index;\r
1265 UINT32 RequiredWordCount;\r
1266 UINT32 ActualWordCount;\r
1267\r
1268 UINT32 WordCount;\r
1269 EFI_STATUS Status;\r
1270 UINT16 *ptrBuffer;\r
1271\r
1272 Status = EFI_SUCCESS;\r
1273\r
1274 //\r
1275 // Non Data transfer request is also supported.\r
1276 //\r
1277 if (*ByteCount == 0 || Buffer == NULL) {\r
1278 *ByteCount = 0;\r
1279 if (EFI_ERROR (StatusWaitForBSYClear (AtapiScsiPrivate, TimeoutInMicroSeconds))) {\r
1280 return EFI_DEVICE_ERROR;\r
1281 }\r
1282 }\r
1283\r
1284 ptrBuffer = Buffer;\r
1285 RequiredWordCount = *ByteCount / 2;\r
1286\r
1287 //\r
1288 // ActuralWordCount means the word count of data really transfered.\r
1289 //\r
1290 ActualWordCount = 0;\r
1291\r
1292 while (ActualWordCount < RequiredWordCount) {\r
1293 //\r
1294 // before each data transfer stream, the host should poll DRQ bit ready,\r
1295 // which indicates device's ready for data transfer .\r
1296 //\r
1297 Status = StatusDRQReady (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
1298 if (EFI_ERROR (Status)) {\r
1299 *ByteCount = ActualWordCount * 2;\r
1300\r
1301 AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);\r
1302\r
1303 if (ActualWordCount == 0) {\r
1304 return EFI_DEVICE_ERROR;\r
1305 }\r
1306 //\r
1307 // ActualWordCount > 0\r
1308 //\r
1309 if (ActualWordCount < RequiredWordCount) {\r
1310 return EFI_WARN_BUFFER_TOO_SMALL;\r
1311 }\r
1312 }\r
1313 //\r
1314 // get current data transfer size from Cylinder Registers.\r
1315 //\r
1cc8ee78 1316 WordCount = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderMsb) << 8;\r
1317 WordCount = WordCount | ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->CylinderLsb);\r
1318 WordCount = WordCount & 0xffff;\r
878ddf1f 1319 WordCount /= 2;\r
1320\r
1321 //\r
1322 // perform a series data In/Out.\r
1323 //\r
1324 for (Index = 0; (Index < WordCount) && (ActualWordCount < RequiredWordCount); Index++, ActualWordCount++) {\r
1325\r
1326 if (Direction == DataIn) {\r
1327\r
1328 *ptrBuffer = ReadPortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data);\r
1329 } else {\r
1330\r
1331 WritePortW (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Data, *ptrBuffer);\r
1332 }\r
1333\r
1334 ptrBuffer++;\r
1335\r
1336 }\r
1337 }\r
1338 //\r
1339 // After data transfer is completed, normally, DRQ bit should clear.\r
1340 //\r
1341 StatusDRQClear (AtapiScsiPrivate, TimeoutInMicroSeconds);\r
1342\r
1343 //\r
1344 // read status register to check whether error happens.\r
1345 //\r
1346 Status = AtapiPassThruCheckErrorStatus (AtapiScsiPrivate);\r
1347\r
1348 *ByteCount = ActualWordCount * 2;\r
1349\r
1350 return Status;\r
1351}\r
1352\r
1353\r
ed72955c 1354/**\r
1355 Read one byte from a specified I/O port.\r
1356\r
1357 @todo function comment is missing 'Routine Description:'\r
1358 @todo function comment is missing 'Arguments:'\r
1359 @todo function comment is missing 'Returns:'\r
1360 @todo PciIo - add argument and description to function comment\r
1361 @todo Port - add argument and description to function comment\r
1362**/\r
878ddf1f 1363UINT8\r
1364ReadPortB (\r
1365 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1366 IN UINT16 Port\r
1367 )\r
878ddf1f 1368{\r
1369 UINT8 Data;\r
1370\r
1371 Data = 0;\r
1372 PciIo->Io.Read (\r
1373 PciIo,\r
1374 EfiPciIoWidthUint8,\r
1375 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1376 (UINT64) Port,\r
1377 1,\r
1378 &Data\r
1379 );\r
1380 return Data;\r
1381}\r
1382\r
1383\r
ed72955c 1384/**\r
1385 Read one word from a specified I/O port.\r
1386\r
1387 @todo function comment is missing 'Routine Description:'\r
1388 @todo function comment is missing 'Arguments:'\r
1389 @todo function comment is missing 'Returns:'\r
1390 @todo PciIo - add argument and description to function comment\r
1391 @todo Port - add argument and description to function comment\r
1392**/\r
878ddf1f 1393UINT16\r
1394ReadPortW (\r
1395 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1396 IN UINT16 Port\r
1397 )\r
878ddf1f 1398{\r
1399 UINT16 Data;\r
1400\r
1401 Data = 0;\r
1402 PciIo->Io.Read (\r
1403 PciIo,\r
1404 EfiPciIoWidthUint16,\r
1405 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1406 (UINT64) Port,\r
1407 1,\r
1408 &Data\r
1409 );\r
1410 return Data;\r
1411}\r
1412\r
1413\r
ed72955c 1414/**\r
1415 Write one byte to a specified I/O port.\r
1416\r
1417 @todo function comment is missing 'Routine Description:'\r
1418 @todo function comment is missing 'Arguments:'\r
1419 @todo function comment is missing 'Returns:'\r
1420 @todo PciIo - add argument and description to function comment\r
1421 @todo Port - add argument and description to function comment\r
1422 @todo Data - add argument and description to function comment\r
1423**/\r
878ddf1f 1424VOID\r
1425WritePortB (\r
1426 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1427 IN UINT16 Port,\r
1428 IN UINT8 Data\r
1429 )\r
878ddf1f 1430{\r
1431\r
1432 PciIo->Io.Write (\r
1433 PciIo,\r
1434 EfiPciIoWidthUint8,\r
1435 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1436 (UINT64) Port,\r
1437 1,\r
1438 &Data\r
1439 );\r
1440\r
1441}\r
1442\r
1443\r
ed72955c 1444/**\r
1445 Write one word to a specified I/O port.\r
1446\r
1447 @todo function comment is missing 'Routine Description:'\r
1448 @todo function comment is missing 'Arguments:'\r
1449 @todo function comment is missing 'Returns:'\r
1450 @todo PciIo - add argument and description to function comment\r
1451 @todo Port - add argument and description to function comment\r
1452 @todo Data - add argument and description to function comment\r
1453**/\r
878ddf1f 1454VOID\r
1455WritePortW (\r
1456 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1457 IN UINT16 Port,\r
1458 IN UINT16 Data\r
1459 )\r
878ddf1f 1460{\r
1461\r
1462 PciIo->Io.Write (\r
1463 PciIo,\r
1464 EfiPciIoWidthUint16,\r
1465 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1466 (UINT64) Port,\r
1467 1,\r
1468 &Data\r
1469 );\r
1470}\r
1471\r
ed72955c 1472/**\r
1473 Check whether DRQ is clear in the Status Register. (BSY must also be cleared)\r
1474 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1475 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1476 elapsed.\r
1477\r
1478 @todo function comment is missing 'Routine Description:'\r
1479 @todo function comment is missing 'Arguments:'\r
1480 @todo function comment is missing 'Returns:'\r
1481 @todo AtapiScsiPrivate - add argument and description to function comment\r
1482 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1483 @todo EFI_ABORTED - add return value to function comment\r
1484 @todo EFI_TIMEOUT - add return value to function comment\r
1485 @todo EFI_SUCCESS - add return value to function comment\r
1486**/\r
878ddf1f 1487EFI_STATUS\r
1488StatusDRQClear (\r
1489 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1490 UINT64 TimeoutInMicroSeconds\r
1491 )\r
878ddf1f 1492{\r
1493 UINT64 Delay;\r
1494 UINT8 StatusRegister;\r
1495 UINT8 ErrRegister;\r
1496\r
1497 if (TimeoutInMicroSeconds == 0) {\r
1498 Delay = 2;\r
1499 } else {\r
1500 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1501 }\r
1502\r
1503 do {\r
1504\r
1505 StatusRegister = ReadPortB (\r
1506 AtapiScsiPrivate->PciIo,\r
1507 AtapiScsiPrivate->IoPort->Reg.Status\r
1508 );\r
1509\r
1510 //\r
1511 // wait for BSY == 0 and DRQ == 0\r
1512 //\r
1513 if ((StatusRegister & (DRQ | BSY)) == 0) {\r
1514 break;\r
1515 }\r
1516 //\r
1517 // check whether the command is aborted by the device\r
1518 //\r
1519 if ((StatusRegister & (BSY | ERR)) == ERR) {\r
1520\r
1521 ErrRegister = ReadPortB (\r
1522 AtapiScsiPrivate->PciIo,\r
1523 AtapiScsiPrivate->IoPort->Reg1.Error\r
1524 );\r
1525 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
1526\r
1527 return EFI_ABORTED;\r
1528 }\r
1529 }\r
1530 //\r
1531 // Stall for 30 us\r
1532 //\r
1533 gBS->Stall (30);\r
1534\r
1535 //\r
1536 // Loop infinitely if not meeting expected condition\r
1537 //\r
1538 if (TimeoutInMicroSeconds == 0) {\r
1539 Delay = 2;\r
1540 }\r
1541\r
1542 Delay--;\r
1543 } while (Delay);\r
1544\r
1545 if (Delay == 0) {\r
1546 return EFI_TIMEOUT;\r
1547 }\r
1548\r
1549 return EFI_SUCCESS;\r
1550}\r
1551\r
ed72955c 1552/**\r
878ddf1f 1553 Check whether DRQ is clear in the Alternate Status Register. \r
1554 (BSY must also be cleared).\r
1555 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1556 DRQ clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1557 elapsed.\r
ed72955c 1558\r
1559 @todo function comment is missing 'Routine Description:'\r
1560 @todo function comment is missing 'Arguments:'\r
1561 @todo function comment is missing 'Returns:'\r
1562 @todo AtapiScsiPrivate - add argument and description to function comment\r
1563 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1564 @todo EFI_ABORTED - add return value to function comment\r
1565 @todo EFI_TIMEOUT - add return value to function comment\r
1566 @todo EFI_SUCCESS - add return value to function comment\r
1567**/\r
1568EFI_STATUS\r
1569AltStatusDRQClear (\r
1570 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1571 UINT64 TimeoutInMicroSeconds\r
1572 )\r
878ddf1f 1573{\r
1574 UINT64 Delay;\r
1575 UINT8 AltStatusRegister;\r
1576 UINT8 ErrRegister;\r
1577\r
1578 if (TimeoutInMicroSeconds == 0) {\r
1579 Delay = 2;\r
1580 } else {\r
1581 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1582 }\r
1583\r
1584 do {\r
1585\r
1586 AltStatusRegister = ReadPortB (\r
1587 AtapiScsiPrivate->PciIo,\r
1588 AtapiScsiPrivate->IoPort->Alt.AltStatus\r
1589 );\r
1590\r
1591 //\r
1592 // wait for BSY == 0 and DRQ == 0\r
1593 //\r
1594 if ((AltStatusRegister & (DRQ | BSY)) == 0) {\r
1595 break;\r
1596 }\r
1597\r
1598 if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
1599\r
1600 ErrRegister = ReadPortB (\r
1601 AtapiScsiPrivate->PciIo,\r
1602 AtapiScsiPrivate->IoPort->Reg1.Error\r
1603 );\r
1604 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
1605\r
1606 return EFI_ABORTED;\r
1607 }\r
1608 }\r
1609 //\r
1610 // Stall for 30 us\r
1611 //\r
1612 gBS->Stall (30);\r
1613\r
1614 //\r
1615 // Loop infinitely if not meeting expected condition\r
1616 //\r
1617 if (TimeoutInMicroSeconds == 0) {\r
1618 Delay = 2;\r
1619 }\r
1620\r
1621 Delay--;\r
1622 } while (Delay);\r
1623\r
1624 if (Delay == 0) {\r
1625 return EFI_TIMEOUT;\r
1626 }\r
1627\r
1628 return EFI_SUCCESS;\r
1629}\r
1630\r
ed72955c 1631/**\r
1632 Check whether DRQ is ready in the Status Register. (BSY must also be cleared)\r
1633 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1634 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1635 elapsed.\r
1636\r
1637 @todo function comment is missing 'Routine Description:'\r
1638 @todo function comment is missing 'Arguments:'\r
1639 @todo function comment is missing 'Returns:'\r
1640 @todo AtapiScsiPrivate - add argument and description to function comment\r
1641 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1642 @todo EFI_ABORTED - add return value to function comment\r
1643 @todo EFI_TIMEOUT - add return value to function comment\r
1644 @todo EFI_SUCCESS - add return value to function comment\r
1645**/\r
878ddf1f 1646EFI_STATUS\r
1647StatusDRQReady (\r
1648 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1649 UINT64 TimeoutInMicroSeconds\r
1650 )\r
878ddf1f 1651{\r
1652 UINT64 Delay;\r
1653 UINT8 StatusRegister;\r
1654 UINT8 ErrRegister;\r
1655\r
1656 if (TimeoutInMicroSeconds == 0) {\r
1657 Delay = 2;\r
1658 } else {\r
1659 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1660 }\r
1661\r
1662 do {\r
1663 //\r
1664 // read Status Register will clear interrupt\r
1665 //\r
1666 StatusRegister = ReadPortB (\r
1667 AtapiScsiPrivate->PciIo,\r
1668 AtapiScsiPrivate->IoPort->Reg.Status\r
1669 );\r
1670\r
1671 //\r
1672 // BSY==0,DRQ==1\r
1673 //\r
1674 if ((StatusRegister & (BSY | DRQ)) == DRQ) {\r
1675 break;\r
1676 }\r
1677\r
1678 if ((StatusRegister & (BSY | ERR)) == ERR) {\r
1679\r
1680 ErrRegister = ReadPortB (\r
1681 AtapiScsiPrivate->PciIo,\r
1682 AtapiScsiPrivate->IoPort->Reg1.Error\r
1683 );\r
1684 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
1685 return EFI_ABORTED;\r
1686 }\r
1687 }\r
1688\r
1689 //\r
1690 // Stall for 30 us\r
1691 //\r
1692 gBS->Stall (30);\r
1693\r
1694 //\r
1695 // Loop infinitely if not meeting expected condition\r
1696 //\r
1697 if (TimeoutInMicroSeconds == 0) {\r
1698 Delay = 2;\r
1699 }\r
1700\r
1701 Delay--;\r
1702 } while (Delay);\r
1703\r
1704 if (Delay == 0) {\r
1705 return EFI_TIMEOUT;\r
1706 }\r
1707\r
1708 return EFI_SUCCESS;\r
1709}\r
1710\r
ed72955c 1711/**\r
878ddf1f 1712 Check whether DRQ is ready in the Alternate Status Register. \r
1713 (BSY must also be cleared)\r
1714 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1715 DRQ ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1716 elapsed.\r
ed72955c 1717\r
1718 @todo function comment is missing 'Routine Description:'\r
1719 @todo function comment is missing 'Arguments:'\r
1720 @todo function comment is missing 'Returns:'\r
1721 @todo AtapiScsiPrivate - add argument and description to function comment\r
1722 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1723 @todo EFI_ABORTED - add return value to function comment\r
1724 @todo EFI_TIMEOUT - add return value to function comment\r
1725 @todo EFI_SUCCESS - add return value to function comment\r
1726**/\r
1727EFI_STATUS\r
1728AltStatusDRQReady (\r
1729 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1730 UINT64 TimeoutInMicroSeconds\r
1731 )\r
878ddf1f 1732{\r
1733 UINT64 Delay;\r
1734 UINT8 AltStatusRegister;\r
1735 UINT8 ErrRegister;\r
1736\r
1737 if (TimeoutInMicroSeconds == 0) {\r
1738 Delay = 2;\r
1739 } else {\r
1740 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1741 }\r
1742\r
1743 do {\r
1744 //\r
1745 // read Status Register will clear interrupt\r
1746 //\r
1747 AltStatusRegister = ReadPortB (\r
1748 AtapiScsiPrivate->PciIo,\r
1749 AtapiScsiPrivate->IoPort->Alt.AltStatus\r
1750 );\r
1751 //\r
1752 // BSY==0,DRQ==1\r
1753 //\r
1754 if ((AltStatusRegister & (BSY | DRQ)) == DRQ) {\r
1755 break;\r
1756 }\r
1757\r
1758 if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
1759\r
1760 ErrRegister = ReadPortB (\r
1761 AtapiScsiPrivate->PciIo,\r
1762 AtapiScsiPrivate->IoPort->Reg1.Error\r
1763 );\r
1764 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
1765 return EFI_ABORTED;\r
1766 }\r
1767 }\r
1768\r
1769 //\r
1770 // Stall for 30 us\r
1771 //\r
1772 gBS->Stall (30);\r
1773\r
1774 //\r
1775 // Loop infinitely if not meeting expected condition\r
1776 //\r
1777 if (TimeoutInMicroSeconds == 0) {\r
1778 Delay = 2;\r
1779 }\r
1780\r
1781 Delay--;\r
1782 } while (Delay);\r
1783\r
1784 if (Delay == 0) {\r
1785 return EFI_TIMEOUT;\r
1786 }\r
1787\r
1788 return EFI_SUCCESS;\r
1789}\r
1790\r
ed72955c 1791/**\r
1792 Check whether BSY is clear in the Status Register.\r
1793 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1794 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1795 elapsed.\r
1796\r
1797 @todo function comment is missing 'Routine Description:'\r
1798 @todo function comment is missing 'Arguments:'\r
1799 @todo function comment is missing 'Returns:'\r
1800 @todo AtapiScsiPrivate - add argument and description to function comment\r
1801 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1802 @todo EFI_TIMEOUT - add return value to function comment\r
1803 @todo EFI_SUCCESS - add return value to function comment\r
1804**/\r
878ddf1f 1805EFI_STATUS\r
1806StatusWaitForBSYClear (\r
1807 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1808 UINT64 TimeoutInMicroSeconds\r
1809 )\r
878ddf1f 1810{\r
1811 UINT64 Delay;\r
1812 UINT8 StatusRegister;\r
1813\r
1814 if (TimeoutInMicroSeconds == 0) {\r
1815 Delay = 2;\r
1816 } else {\r
1817 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1818 }\r
1819\r
1820 do {\r
1821\r
1822 StatusRegister = ReadPortB (\r
1823 AtapiScsiPrivate->PciIo,\r
1824 AtapiScsiPrivate->IoPort->Reg.Status\r
1825 );\r
1826 if ((StatusRegister & BSY) == 0x00) {\r
1827 break;\r
1828 }\r
1829\r
1830 //\r
1831 // Stall for 30 us\r
1832 //\r
1833 gBS->Stall (30);\r
1834\r
1835 //\r
1836 // Loop infinitely if not meeting expected condition\r
1837 //\r
1838 if (TimeoutInMicroSeconds == 0) {\r
1839 Delay = 2;\r
1840 }\r
1841\r
1842 Delay--;\r
1843 } while (Delay);\r
1844\r
1845 if (Delay == 0) {\r
1846 return EFI_TIMEOUT;\r
1847 }\r
1848\r
1849 return EFI_SUCCESS;\r
1850}\r
1851\r
ed72955c 1852/**\r
1853 Check whether BSY is clear in the Alternate Status Register.\r
1854 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1855 BSY clear. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1856 elapsed.\r
1857\r
1858 @todo function comment is missing 'Routine Description:'\r
1859 @todo function comment is missing 'Arguments:'\r
1860 @todo function comment is missing 'Returns:'\r
1861 @todo AtapiScsiPrivate - add argument and description to function comment\r
1862 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1863 @todo EFI_TIMEOUT - add return value to function comment\r
1864 @todo EFI_SUCCESS - add return value to function comment\r
1865**/\r
878ddf1f 1866EFI_STATUS\r
1867AltStatusWaitForBSYClear (\r
1868 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1869 UINT64 TimeoutInMicroSeconds\r
1870 )\r
878ddf1f 1871{\r
1872 UINT64 Delay;\r
1873 UINT8 AltStatusRegister;\r
1874\r
1875 if (TimeoutInMicroSeconds == 0) {\r
1876 Delay = 2;\r
1877 } else {\r
1878 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1879 }\r
1880\r
1881 do {\r
1882\r
1883 AltStatusRegister = ReadPortB (\r
1884 AtapiScsiPrivate->PciIo,\r
1885 AtapiScsiPrivate->IoPort->Alt.AltStatus\r
1886 );\r
1887 if ((AltStatusRegister & BSY) == 0x00) {\r
1888 break;\r
1889 }\r
1890\r
1891 //\r
1892 // Stall for 30 us\r
1893 //\r
1894 gBS->Stall (30);\r
1895 //\r
1896 // Loop infinitely if not meeting expected condition\r
1897 //\r
1898 if (TimeoutInMicroSeconds == 0) {\r
1899 Delay = 2;\r
1900 }\r
1901\r
1902 Delay--;\r
1903 } while (Delay);\r
1904\r
1905 if (Delay == 0) {\r
1906 return EFI_TIMEOUT;\r
1907 }\r
1908\r
1909 return EFI_SUCCESS;\r
1910}\r
1911\r
ed72955c 1912/**\r
878ddf1f 1913 Check whether DRDY is ready in the Status Register. \r
1914 (BSY must also be cleared)\r
1915 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1916 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1917 elapsed.\r
ed72955c 1918\r
1919 @todo function comment is missing 'Routine Description:'\r
1920 @todo function comment is missing 'Arguments:'\r
1921 @todo function comment is missing 'Returns:'\r
1922 @todo AtapiScsiPrivate - add argument and description to function comment\r
1923 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
1924 @todo EFI_ABORTED - add return value to function comment\r
1925 @todo EFI_TIMEOUT - add return value to function comment\r
1926 @todo EFI_SUCCESS - add return value to function comment\r
1927**/\r
1928EFI_STATUS\r
1929StatusDRDYReady (\r
1930 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
1931 UINT64 TimeoutInMicroSeconds\r
1932 )\r
878ddf1f 1933{\r
1934 UINT64 Delay;\r
1935 UINT8 StatusRegister;\r
1936 UINT8 ErrRegister;\r
1937\r
1938 if (TimeoutInMicroSeconds == 0) {\r
1939 Delay = 2;\r
1940 } else {\r
1941 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
1942 }\r
1943\r
1944 do {\r
1945 StatusRegister = ReadPortB (\r
1946 AtapiScsiPrivate->PciIo,\r
1947 AtapiScsiPrivate->IoPort->Reg.Status\r
1948 );\r
1949 //\r
1950 // BSY == 0 , DRDY == 1\r
1951 //\r
1952 if ((StatusRegister & (DRDY | BSY)) == DRDY) {\r
1953 break;\r
1954 }\r
1955\r
1956 if ((StatusRegister & (BSY | ERR)) == ERR) {\r
1957\r
1958 ErrRegister = ReadPortB (\r
1959 AtapiScsiPrivate->PciIo,\r
1960 AtapiScsiPrivate->IoPort->Reg1.Error\r
1961 );\r
1962 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
1963 return EFI_ABORTED;\r
1964 }\r
1965 }\r
1966 \r
1967 //\r
1968 // Stall for 30 us\r
1969 //\r
1970 gBS->Stall (30);\r
1971 //\r
1972 // Loop infinitely if not meeting expected condition\r
1973 //\r
1974 if (TimeoutInMicroSeconds == 0) {\r
1975 Delay = 2;\r
1976 }\r
1977\r
1978 Delay--;\r
1979 } while (Delay);\r
1980\r
1981 if (Delay == 0) {\r
1982 return EFI_TIMEOUT;\r
1983 }\r
1984\r
1985 return EFI_SUCCESS;\r
1986}\r
1987\r
ed72955c 1988/**\r
878ddf1f 1989 Check whether DRDY is ready in the Alternate Status Register. \r
1990 (BSY must also be cleared)\r
1991 If TimeoutInMicroSeconds is zero, this routine should wait infinitely for\r
1992 DRDY ready. Otherwise, it will return EFI_TIMEOUT when specified time is \r
1993 elapsed.\r
ed72955c 1994\r
1995 @todo function comment is missing 'Routine Description:'\r
1996 @todo function comment is missing 'Arguments:'\r
1997 @todo function comment is missing 'Returns:'\r
1998 @todo AtapiScsiPrivate - add argument and description to function comment\r
1999 @todo TimeoutInMicroSeconds - add argument and description to function comment\r
2000 @todo EFI_ABORTED - add return value to function comment\r
2001 @todo EFI_TIMEOUT - add return value to function comment\r
2002 @todo EFI_SUCCESS - add return value to function comment\r
2003**/\r
2004EFI_STATUS\r
2005AltStatusDRDYReady (\r
2006 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate,\r
2007 UINT64 TimeoutInMicroSeconds\r
2008 )\r
878ddf1f 2009{\r
2010 UINT64 Delay;\r
2011 UINT8 AltStatusRegister;\r
2012 UINT8 ErrRegister;\r
2013\r
2014 if (TimeoutInMicroSeconds == 0) {\r
2015 Delay = 2;\r
2016 } else {\r
2017 Delay = DivU64x32 (TimeoutInMicroSeconds, (UINT32) 30) + 1;\r
2018 }\r
2019\r
2020 do {\r
2021 AltStatusRegister = ReadPortB (\r
2022 AtapiScsiPrivate->PciIo,\r
2023 AtapiScsiPrivate->IoPort->Alt.AltStatus\r
2024 );\r
2025 //\r
2026 // BSY == 0 , DRDY == 1\r
2027 //\r
2028 if ((AltStatusRegister & (DRDY | BSY)) == DRDY) {\r
2029 break;\r
2030 }\r
2031\r
2032 if ((AltStatusRegister & (BSY | ERR)) == ERR) {\r
2033\r
2034 ErrRegister = ReadPortB (\r
2035 AtapiScsiPrivate->PciIo,\r
2036 AtapiScsiPrivate->IoPort->Reg1.Error\r
2037 );\r
2038 if ((ErrRegister & ABRT_ERR) == ABRT_ERR) {\r
2039 return EFI_ABORTED;\r
2040 }\r
2041 }\r
2042\r
2043 //\r
2044 // Stall for 30 us\r
2045 //\r
2046 gBS->Stall (30);\r
2047 //\r
2048 // Loop infinitely if not meeting expected condition\r
2049 //\r
2050 if (TimeoutInMicroSeconds == 0) {\r
2051 Delay = 2;\r
2052 }\r
2053\r
2054 Delay--;\r
2055 } while (Delay);\r
2056\r
2057 if (Delay == 0) {\r
2058 return EFI_TIMEOUT;\r
2059 }\r
2060\r
2061 return EFI_SUCCESS;\r
2062}\r
2063\r
ed72955c 2064/**\r
2065 Check Error Register for Error Information. \r
2066\r
2067 @todo function comment is missing 'Routine Description:'\r
2068 @todo function comment is missing 'Arguments:'\r
2069 @todo function comment is missing 'Returns:'\r
2070 @todo AtapiScsiPrivate - add argument and description to function comment\r
2071 @todo EFI_SUCCESS - add return value to function comment\r
2072 @todo EFI_DEVICE_ERROR - add return value to function comment\r
2073**/\r
878ddf1f 2074EFI_STATUS\r
2075AtapiPassThruCheckErrorStatus (\r
2076 ATAPI_SCSI_PASS_THRU_DEV *AtapiScsiPrivate\r
2077 )\r
878ddf1f 2078{\r
2079 UINT8 StatusRegister;\r
878ddf1f 2080 UINT8 ErrorRegister;\r
2081\r
878ddf1f 2082 StatusRegister = ReadPortB (\r
2083 AtapiScsiPrivate->PciIo,\r
2084 AtapiScsiPrivate->IoPort->Reg.Status\r
2085 );\r
2ce31132 2086 \r
2087 DEBUG_CODE_BEGIN ();\r
878ddf1f 2088\r
2089 if (StatusRegister & DWF) {\r
2ce31132 2090 DEBUG (\r
2091 (EFI_D_BLKIO,\r
2092 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Write Fault\n",\r
2093 StatusRegister)\r
2094 );\r
2095 }\r
878ddf1f 2096\r
2ce31132 2097 if (StatusRegister & CORR) {\r
2098 DEBUG (\r
2099 (EFI_D_BLKIO,\r
2100 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Corrected Data\n",\r
2101 StatusRegister)\r
2102 );\r
2103 }\r
878ddf1f 2104\r
2ce31132 2105 if (StatusRegister & ERR) {\r
2106 ErrorRegister = ReadPortB (AtapiScsiPrivate->PciIo, AtapiScsiPrivate->IoPort->Reg1.Error);\r
2107 \r
878ddf1f 2108\r
2ce31132 2109 if (ErrorRegister & BBK_ERR) {\r
2110 DEBUG (\r
2111 (EFI_D_BLKIO,\r
2112 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Bad Block Detected\n",\r
2113 ErrorRegister)\r
2114 );\r
2115 }\r
878ddf1f 2116\r
2ce31132 2117 if (ErrorRegister & UNC_ERR) {\r
2118 DEBUG (\r
2119 (EFI_D_BLKIO,\r
2120 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",\r
2121 ErrorRegister)\r
2122 );\r
2123 }\r
878ddf1f 2124\r
2ce31132 2125 if (ErrorRegister & MC_ERR) {\r
2126 DEBUG (\r
2127 (EFI_D_BLKIO,\r
2128 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Media Change\n",\r
2129 ErrorRegister)\r
2130 );\r
2131 }\r
878ddf1f 2132\r
2ce31132 2133 if (ErrorRegister & ABRT_ERR) {\r
2134 DEBUG (\r
2135 (EFI_D_BLKIO,\r
2136 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Abort\n",\r
2137 ErrorRegister)\r
2138 );\r
2139 }\r
878ddf1f 2140\r
2ce31132 2141 if (ErrorRegister & TK0NF_ERR) {\r
2142 DEBUG (\r
2143 (EFI_D_BLKIO,\r
2144 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",\r
2145 ErrorRegister)\r
2146 );\r
2147 }\r
878ddf1f 2148\r
2ce31132 2149 if (ErrorRegister & AMNF_ERR) {\r
2150 DEBUG (\r
2151 (EFI_D_BLKIO,\r
2152 "AtapiPassThruCheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",\r
2153 ErrorRegister)\r
2154 );\r
2155 }\r
2156 }\r
878ddf1f 2157\r
2ce31132 2158 DEBUG_CODE_END ();\r
878ddf1f 2159\r
2160 if ((StatusRegister & (ERR | DWF | CORR)) == 0) {\r
878ddf1f 2161 return EFI_SUCCESS;\r
2162 }\r
2163\r
2ce31132 2164 \r
878ddf1f 2165 return EFI_DEVICE_ERROR;\r
778cedfb 2166}\r