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