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