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