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