3 * Copyright (C) 2001, 2002, 2003, 2004, 2005 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: drivers/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
33 * This driver is derived from Rex Jolliff's ide driver. Lots of his
34 * routines are still in here although they belong into the higher level
35 * drivers. They will be moved away as soon as possible.
40 * - implement sending of atapi commands
41 * - handle removable atapi non-cdrom drives
45 #define ENABLE_NATIVE_PCI
49 // -------------------------------------------------------------------------
51 #include <ddk/ntddk.h>
54 #include <ddk/ntddscsi.h>
55 #include <ddk/ntdddisk.h>
56 #include <ddk/ntddstor.h>
63 #define VERSION "0.0.1"
66 // ------------------------------------------------------- File Static Data
76 // ATAPI_MINIPORT_EXTENSION
79 // Extension to be placed in each port device object
82 // Allocated from NON-PAGED POOL
83 // Available at any IRQL
86 typedef struct _ATAPI_MINIPORT_EXTENSION
88 IDE_DRIVE_IDENTIFY DeviceParams
[2];
90 ULONG TransferSize
[2];
92 ULONG CommandPortBase
;
93 ULONG ControlPortBase
;
94 ULONG BusMasterRegisterBase
;
96 PSCSI_REQUEST_BLOCK CurrentSrb
;
99 ULONG DataTransferLength
;
101 BOOLEAN
FASTCALL (*Handler
)(IN
struct _ATAPI_MINIPORT_EXTENSION
* DevExt
);
107 SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress
;
109 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
112 #define DEVICE_PRESENT 0x00000001
113 #define DEVICE_ATAPI 0x00000002
114 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
115 #define DEVICE_DWORD_IO 0x00000008
116 #define DEVICE_48BIT_ADDRESS 0x00000010
117 #define DEVICE_MEDIA_STATUS 0x00000020
118 #define DEVICE_DMA_CMD 0x00000040
119 #define DEVICE_NO_FLUSH 0x00000080
122 typedef struct _UNIT_EXTENSION
125 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
127 PCI_SLOT_NUMBER LastSlotNumber
;
129 #ifdef ENABLE_NATIVE_PCI
130 typedef struct _PCI_NATIVE_CONTROLLER
135 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
137 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
141 0x4D68, // PDC20268, Ultra100TX2
145 0x4D30, // PDC20267, Ultra100
151 // ----------------------------------------------- Discardable Declarations
155 // make the initialization routines discardable, so that they
158 #pragma alloc_text(init, DriverEntry)
160 // make the PASSIVE_LEVEL routines pageable, so that they don't
161 // waste nonpaged memory
163 #endif /* ALLOC_PRAGMA */
165 // ---------------------------------------------------- Forward Declarations
169 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
170 PSCSI_REQUEST_BLOCK Srb
,
175 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
177 PVOID BusInformation
,
178 PCHAR ArgumentString
,
179 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
183 AtapiFindIsaBusController(PVOID DeviceExtension
,
185 PVOID BusInformation
,
186 PCHAR ArgumentString
,
187 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
191 AtapiFindNativePciController(PVOID DeviceExtension
,
193 PVOID BusInformation
,
194 PCHAR ArgumentString
,
195 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
198 static BOOLEAN STDCALL
199 AtapiInitialize(IN PVOID DeviceExtension
);
201 static BOOLEAN STDCALL
202 AtapiResetBus(IN PVOID DeviceExtension
,
205 static BOOLEAN STDCALL
206 AtapiStartIo(IN PVOID DeviceExtension
,
207 IN PSCSI_REQUEST_BLOCK Srb
);
210 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
212 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
));
214 static BOOLEAN STDCALL
215 AtapiInterrupt(IN PVOID DeviceExtension
);
217 static BOOLEAN FASTCALL
218 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
);
220 static BOOLEAN FASTCALL
221 AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
223 static BOOLEAN FASTCALL
224 AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
227 static BOOLEAN FASTCALL
228 AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
230 static BOOLEAN FASTCALL
231 AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
234 static BOOLEAN FASTCALL
235 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
238 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
239 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
242 AtapiIdentifyDevice(IN ULONG CommandPort
,
243 IN ULONG ControlPort
,
246 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
249 AtapiPolledRead(IN ULONG CommandPort
,
250 IN ULONG ControlPort
,
254 IN UCHAR CylinderLow
,
255 IN UCHAR CylinderHigh
,
261 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
262 IN PSCSI_REQUEST_BLOCK Srb
);
265 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
266 IN PSCSI_REQUEST_BLOCK Srb
);
269 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
270 IN PSCSI_REQUEST_BLOCK Srb
);
273 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
274 IN PSCSI_REQUEST_BLOCK Srb
);
277 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
278 IN PSCSI_REQUEST_BLOCK Srb
);
281 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
282 PSCSI_REQUEST_BLOCK Srb
);
285 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
286 PSCSI_REQUEST_BLOCK Srb
);
289 AtapiErrorToScsi(PVOID DeviceExtension
,
290 PSCSI_REQUEST_BLOCK Srb
);
293 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
);
295 // ---------------------------------------------------------------- Inlines
298 IDESwapBytePairs(UCHAR
*Buf
,
304 for (i
= 0; i
< Cnt
; i
+= 2)
313 // ------------------------------------------------------- Public Interface
318 // This function initializes the driver, locates and claims
319 // hardware resources, and creates various NT objects needed
320 // to process I/O requests.
326 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
328 // IN PUNICODE_STRING RegistryPath Name of registry driver service
335 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
336 IN PUNICODE_STRING RegistryPath
)
338 HW_INITIALIZATION_DATA InitData
;
341 DPRINT("ATAPI Driver %s\n", VERSION
);
342 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
344 /* Initialize data structure */
345 RtlZeroMemory(&InitData
,
346 sizeof(HW_INITIALIZATION_DATA
));
347 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
348 InitData
.HwInitialize
= AtapiInitialize
;
349 InitData
.HwResetBus
= AtapiResetBus
;
350 InitData
.HwStartIo
= AtapiStartIo
;
351 InitData
.HwInterrupt
= AtapiInterrupt
;
353 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
354 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
356 InitData
.MapBuffers
= TRUE
;
358 /* Search the PCI bus for compatibility mode ide controllers */
360 InitData
.NeedPhysicalAddresses
= TRUE
;
362 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
363 InitData
.NumberOfAccessRanges
= 3;
364 InitData
.AdapterInterfaceType
= PCIBus
;
366 InitData
.VendorId
= NULL
;
367 InitData
.VendorIdLength
= 0;
368 InitData
.DeviceId
= NULL
;
369 InitData
.DeviceIdLength
= 0;
371 Status
= ScsiPortInitialize(DriverObject
,
375 // if (newStatus < statusToReturn)
376 // statusToReturn = newStatus;
379 /* Search the PCI bus for all ide controllers */
380 #ifdef ENABLE_NATIVE_PCI
381 InitData
.NeedPhysicalAddresses
= TRUE
;
383 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
384 InitData
.NumberOfAccessRanges
= 3;
385 InitData
.AdapterInterfaceType
= PCIBus
;
387 InitData
.VendorId
= 0;
388 InitData
.VendorIdLength
= 0;
389 InitData
.DeviceId
= 0;
390 InitData
.DeviceIdLength
= 0;
392 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
394 Status
= ScsiPortInitialize(DriverObject
,
398 // if (newStatus < statusToReturn)
399 // statusToReturn = newStatus;
402 /* Search the ISA bus for ide controllers */
404 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
405 InitData
.NumberOfAccessRanges
= 2;
406 InitData
.AdapterInterfaceType
= Isa
;
408 InitData
.VendorId
= NULL
;
409 InitData
.VendorIdLength
= 0;
410 InitData
.DeviceId
= NULL
;
411 InitData
.DeviceIdLength
= 0;
413 Status
= ScsiPortInitialize(DriverObject
,
417 // if (newStatus < statusToReturn)
418 // statusToReturn = newStatus;
421 DPRINT("Returning from DriverEntry\n");
428 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
429 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
430 INTERFACE_TYPE InterfaceType
,
431 ULONG CommandPortBase
,
432 ULONG ControlPortBase
,
433 ULONG BusMasterPortBase
,
434 ULONG InterruptVector
)
436 SCSI_PHYSICAL_ADDRESS IoAddress
;
441 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
442 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
444 ConfigInfo
->SystemIoBusNumber
,
452 DevExt
->Handler
= NULL
;
453 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
454 (*ConfigInfo
->AccessRanges
)[0].RangeStart
= IoAddress
;
455 (*ConfigInfo
->AccessRanges
)[0].RangeLength
= 8;
456 (*ConfigInfo
->AccessRanges
)[0].RangeInMemory
= FALSE
;
460 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
461 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
463 ConfigInfo
->SystemIoBusNumber
,
469 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
470 (PVOID
)DevExt
->CommandPortBase
);
473 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
474 (*ConfigInfo
->AccessRanges
)[1].RangeStart
= IoAddress
;
475 (*ConfigInfo
->AccessRanges
)[1].RangeLength
= 1;
476 (*ConfigInfo
->AccessRanges
)[1].RangeInMemory
= FALSE
;
478 if (BusMasterPortBase
)
480 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
481 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
483 ConfigInfo
->SystemIoBusNumber
,
489 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
490 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
493 DevExt
->BusMasterRegisterBase
= (ULONG
)IoBase
;
494 (*ConfigInfo
->AccessRanges
)[2].RangeStart
= IoAddress
;
495 (*ConfigInfo
->AccessRanges
)[2].RangeLength
= 8;
496 (*ConfigInfo
->AccessRanges
)[2].RangeInMemory
= FALSE
;
498 // ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
499 // ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
500 ConfigInfo
->DmaWidth
= Width32Bits
;
501 // ConfigInfo->DmaSpeed = Compatible;
502 ConfigInfo
->ScatterGather
= TRUE
;
503 ConfigInfo
->Master
= TRUE
;
504 ConfigInfo
->NumberOfPhysicalBreaks
= 0x10000 / PAGE_SIZE
+ 1;
505 ConfigInfo
->Dma32BitAddresses
= TRUE
;
506 ConfigInfo
->NeedPhysicalAddresses
= TRUE
;
507 ConfigInfo
->MapBuffers
= TRUE
;
509 DevExt
->PRDMaxCount
= PAGE_SIZE
/ sizeof(PRD
);
510 DevExt
->PRDTable
= ScsiPortGetUncachedExtension(DevExt
, ConfigInfo
, sizeof(PRD
) * DevExt
->PRDMaxCount
);
511 if (DevExt
->PRDTable
!= NULL
)
513 DevExt
->PRDTablePhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, NULL
, DevExt
->PRDTable
, &Length
);
515 if (DevExt
->PRDTable
== NULL
||
516 DevExt
->PRDTablePhysicalAddress
.QuadPart
== 0LL ||
517 Length
< sizeof(PRD
) * DevExt
->PRDMaxCount
)
519 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
520 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
521 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->BusMasterRegisterBase
);
526 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
527 ConfigInfo
->BusInterruptVector
= InterruptVector
;
528 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
530 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
532 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
534 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
536 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
544 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
546 PVOID BusInformation
,
547 PCHAR ArgumentString
,
548 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
551 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
552 PCI_SLOT_NUMBER SlotNumber
;
553 PCI_COMMON_CONFIG PciConfig
;
555 ULONG StartDeviceNumber
;
557 ULONG StartFunctionNumber
;
558 ULONG FunctionNumber
;
559 BOOLEAN ChannelFound
;
561 ULONG BusMasterBasePort
= 0;
563 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
564 ConfigInfo
->SystemIoBusNumber
,
565 ConfigInfo
->SlotNumber
);
569 /* both channels were claimed: exit */
570 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
571 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
572 return(SP_RETURN_NOT_FOUND
);
574 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
575 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
576 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
577 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
579 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
580 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
582 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
583 ChannelFound
= FALSE
;
586 DataSize
= ScsiPortGetBusData(DeviceExtension
,
588 ConfigInfo
->SystemIoBusNumber
,
589 SlotNumber
.u
.AsULONG
,
591 PCI_COMMON_HDR_LENGTH
);
592 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
594 if (FunctionNumber
== 0)
604 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
605 if (PciConfig
.BaseClass
== 0x01 &&
606 PciConfig
.SubClass
== 0x01) // &&
607 // (PciConfig.ProgIf & 0x05) == 0)
609 /* both channels are in compatibility mode */
610 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
611 ConfigInfo
->SystemIoBusNumber
,
612 SlotNumber
.u
.bits
.DeviceNumber
,
613 SlotNumber
.u
.bits
.FunctionNumber
,
616 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
618 DPRINT("Found IDE controller in compatibility mode!\n");
620 ConfigInfo
->NumberOfBuses
= 1;
621 ConfigInfo
->MaximumNumberOfTargets
= 2;
622 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
624 if (PciConfig
.ProgIf
& 0x80)
626 DPRINT("Found IDE Bus Master controller!\n");
627 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
629 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
630 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
633 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
635 /* Both channels unclaimed: Claim primary channel */
636 DPRINT("Primary channel!\n");
637 ChannelFound
= AtapiClaimHwResources(DevExt
,
646 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
648 /* Primary channel already claimed: claim secondary channel */
649 DPRINT("Secondary channel!\n");
651 ChannelFound
= AtapiClaimHwResources(DevExt
,
656 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
660 /* Find attached devices */
663 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
664 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
665 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
666 return(SP_RETURN_FOUND
);
669 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
674 StartFunctionNumber
= 0;
676 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
678 return(SP_RETURN_NOT_FOUND
);
685 AtapiFindIsaBusController(PVOID DeviceExtension
,
687 PVOID BusInformation
,
688 PCHAR ArgumentString
,
689 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
692 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
693 BOOLEAN ChannelFound
= FALSE
;
694 BOOLEAN DeviceFound
= FALSE
;
696 DPRINT("AtapiFindIsaBusController() called!\n");
700 ConfigInfo
->NumberOfBuses
= 1;
701 ConfigInfo
->MaximumNumberOfTargets
= 2;
702 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
704 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
706 /* Both channels unclaimed: Claim primary channel */
707 DPRINT("Primary channel!\n");
709 ChannelFound
= AtapiClaimHwResources(DevExt
,
718 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
720 /* Primary channel already claimed: claim secondary channel */
721 DPRINT("Secondary channel!\n");
723 ChannelFound
= AtapiClaimHwResources(DevExt
,
734 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
736 return(SP_RETURN_NOT_FOUND
);
739 /* Find attached devices */
742 DeviceFound
= AtapiFindDevices(DevExt
,
744 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
745 return(SP_RETURN_FOUND
);
748 return SP_RETURN_NOT_FOUND
;
753 #ifdef ENABLE_NATIVE_PCI
755 AtapiFindNativePciController(PVOID DeviceExtension
,
757 PVOID BusInformation
,
758 PCHAR ArgumentString
,
759 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
762 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
763 PCI_COMMON_CONFIG PciConfig
;
764 PCI_SLOT_NUMBER SlotNumber
;
767 ULONG StartDeviceNumber
;
768 ULONG FunctionNumber
;
769 ULONG StartFunctionNumber
;
770 ULONG BusMasterBasePort
;
772 BOOLEAN ChannelFound
;
774 DPRINT("AtapiFindNativePciController() called!\n");
776 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
777 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
778 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
779 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
781 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
782 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
784 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
785 DataSize
= ScsiPortGetBusData(DeviceExtension
,
787 ConfigInfo
->SystemIoBusNumber
,
788 SlotNumber
.u
.AsULONG
,
790 PCI_COMMON_HDR_LENGTH
);
791 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
795 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
797 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
798 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
803 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
805 /* We have found a known native pci ide controller */
806 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
808 DPRINT("Found IDE Bus Master controller!\n");
809 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
810 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
814 BusMasterBasePort
= 0;
817 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
818 ConfigInfo
->NumberOfBuses
= 1;
819 ConfigInfo
->MaximumNumberOfTargets
= 2;
820 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
823 We must not store and use the last tested slot number. If there is a recall
824 to the some device and we will claim the primary channel again than the call
825 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
826 claim the secondary channel.
828 ChannelFound
= FALSE
;
829 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
831 /* try to claim primary channel */
832 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
833 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
835 /* primary channel is enabled */
836 ChannelFound
= AtapiClaimHwResources(DevExt
,
839 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
840 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
842 PciConfig
.u
.type0
.InterruptLine
);
845 AtapiFindDevices(DevExt
, ConfigInfo
);
847 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
848 return SP_RETURN_FOUND
;
854 /* try to claim secondary channel */
855 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
856 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
858 /* secondary channel is enabled */
859 ChannelFound
= AtapiClaimHwResources(DevExt
,
862 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
863 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
864 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
865 PciConfig
.u
.type0
.InterruptLine
);
868 AtapiFindDevices(DevExt
, ConfigInfo
);
870 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
871 return SP_RETURN_FOUND
;
877 StartFunctionNumber
= 0;
880 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
881 DPRINT("AtapiFindNativePciController() done!\n");
883 return(SP_RETURN_NOT_FOUND
);
888 static BOOLEAN STDCALL
889 AtapiInitialize(IN PVOID DeviceExtension
)
895 static BOOLEAN STDCALL
896 AtapiResetBus(IN PVOID DeviceExtension
,
903 static BOOLEAN STDCALL
904 AtapiStartIo(IN PVOID DeviceExtension
,
905 IN PSCSI_REQUEST_BLOCK Srb
)
907 PATAPI_MINIPORT_EXTENSION DevExt
;
910 DPRINT("AtapiStartIo() called\n");
912 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
914 switch (Srb
->Function
)
916 case SRB_FUNCTION_EXECUTE_SCSI
:
917 DevExt
->CurrentSrb
= Srb
;
918 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
920 Result
= AtapiSendAtapiCommand(DevExt
,
925 Result
= AtapiSendIdeCommand(DevExt
,
930 case SRB_FUNCTION_ABORT_COMMAND
:
931 if (DevExt
->CurrentSrb
!= NULL
)
933 Result
= SRB_STATUS_ABORT_FAILED
;
937 Result
= SRB_STATUS_SUCCESS
;
941 case SRB_FUNCTION_IO_CONTROL
:
943 PSRB_IO_CONTROL SrbIoControl
= (PSRB_IO_CONTROL
)Srb
->DataBuffer
;
944 if (!_strnicmp((char*)SrbIoControl
->Signature
, "ScsiDisk", 8))
946 switch (SrbIoControl
->ControlCode
)
949 Result
= SRB_STATUS_INVALID_REQUEST
;
952 case IOCTL_SCSI_MINIPORT_IDENTIFY
:
954 PSENDCMDOUTPARAMS OutParams
= (PSENDCMDOUTPARAMS
)((ULONG_PTR
)Srb
->DataBuffer
+ sizeof(SRB_IO_CONTROL
));
955 SENDCMDINPARAMS InParams
= *(PSENDCMDINPARAMS
)OutParams
;
958 RtlZeroMemory(OutParams
, Srb
->DataTransferLength
- sizeof(SRB_IO_CONTROL
));
960 if (InParams
.irDriveRegs
.bCommandReg
!= IDE_CMD_IDENT_ATA_DRV
)
962 DPRINT1("bCommandReg: %x\n", InParams
.irDriveRegs
.bCommandReg
);
963 OutParams
->DriverStatus
.bIDEError
= 1;
964 Result
= SRB_STATUS_INVALID_REQUEST
;
968 if (InParams
.bDriveNumber
> 1 ||
969 (DevExt
->DeviceFlags
[InParams
.bDriveNumber
] & (DEVICE_PRESENT
|DEVICE_ATAPI
)) != DEVICE_PRESENT
)
971 OutParams
->DriverStatus
.bIDEError
= 1;
972 Result
= SRB_STATUS_NO_DEVICE
;
976 if (Srb
->DataTransferLength
> sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
) - 1)
978 OutParams
->cBufferSize
= min(IDENTIFY_BUFFER_SIZE
, Srb
->DataTransferLength
- (sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
) - 1));
979 RtlCopyMemory(OutParams
->bBuffer
, &DevExt
->DeviceParams
[InParams
.bDriveNumber
], OutParams
->cBufferSize
);
982 Result
= SRB_STATUS_SUCCESS
;
989 Result
= SRB_STATUS_INVALID_REQUEST
;
996 Result
= SRB_STATUS_INVALID_REQUEST
;
1000 Srb
->SrbStatus
= Result
;
1003 if (Result
!= SRB_STATUS_PENDING
)
1005 DevExt
->CurrentSrb
= NULL
;
1007 ScsiPortNotification(RequestComplete
,
1010 ScsiPortNotification(NextRequest
,
1016 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
1019 DPRINT("AtapiStartIo() done\n");
1024 static BOOLEAN STDCALL
1025 AtapiInterrupt(IN PVOID DeviceExtension
)
1027 PATAPI_MINIPORT_EXTENSION DevExt
;
1029 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
1031 if (DevExt
->Handler
== NULL
)
1033 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1034 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) != IDE_SR_DRDY
)
1036 static ULONG Count
= 0;
1038 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
1039 DevExt
->CommandPortBase
, Status
, Count
);
1046 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
1047 if (!(Status
& 0x04))
1055 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1056 if (Status
& IDE_SR_BUSY
)
1061 return DevExt
->Handler(DevExt
);
1064 // ---------------------------------------------------- Discardable statics
1068 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension
, ULONG UnitNumber
)
1070 BOOLEAN Result
= FALSE
;
1075 if (DeviceExtension
->PRDTable
)
1077 if (DeviceExtension
->DeviceParams
[UnitNumber
].Capabilities
& IDE_DRID_DMA_SUPPORTED
)
1079 if ((DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0004) &&
1080 (DeviceExtension
->DeviceParams
[UnitNumber
].UltraDmaModes
& 0x7F00))
1084 else if (DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0002)
1086 if ((DeviceExtension
->DeviceParams
[UnitNumber
].MultiDmaModes
& 0x0404) == 0x0404)
1092 * should we support single mode dma ?
1094 else if ((DeviceExtension
->DeviceParams
[UnitNumber
].DmaModes
& 0x0404) == 0x0404)
1100 Status
= IDEReadDMAStatus(DeviceExtension
->BusMasterRegisterBase
);
1103 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
| (UnitNumber
? 0x40 : 0x20));
1107 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
& (UnitNumber
? ~0x40 : ~0x20));
1116 /**********************************************************************
1121 * Searches for devices on the given port.
1128 * Port device specific information.
1131 * Port configuration information.
1134 * TRUE: At least one device is attached to the port.
1135 * FALSE: No device is attached to the port.
1139 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1140 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1142 BOOLEAN DeviceFound
= FALSE
;
1143 ULONG CommandPortBase
;
1144 ULONG ControlPortBase
;
1150 DPRINT("AtapiFindDevices() called\n");
1152 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
);
1153 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1155 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[1].RangeStart
);
1156 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1158 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1161 IDEWriteDriveHead(CommandPortBase
,
1162 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1163 ScsiPortStallExecution(500);
1165 /* Disable interrupts */
1166 IDEWriteDriveControl(ControlPortBase
,
1168 ScsiPortStallExecution(500);
1170 /* Check if a device is attached to the interface */
1171 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1172 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1174 High
= IDEReadCylinderHigh(CommandPortBase
);
1175 Low
= IDEReadCylinderLow(CommandPortBase
);
1177 IDEWriteCylinderHigh(CommandPortBase
, 0);
1178 IDEWriteCylinderLow(CommandPortBase
, 0);
1180 if (Low
!= 0x55 || High
!= 0xaa)
1182 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1186 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_RESET
, NULL
);
1188 for (Retries
= 0; Retries
< 20000; Retries
++)
1190 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1194 ScsiPortStallExecution(150);
1196 if (Retries
>= 20000)
1198 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1199 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1203 High
= IDEReadCylinderHigh(CommandPortBase
);
1204 Low
= IDEReadCylinderLow(CommandPortBase
);
1206 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1211 if (High
== 0xEB && Low
== 0x14)
1213 if (AtapiIdentifyDevice(CommandPortBase
,
1217 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1219 DPRINT(" ATAPI drive found!\n");
1220 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1221 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1222 DeviceExtension
->TransferSize
[UnitNumber
] =
1223 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1225 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1227 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1230 if (!(DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x1000) ||
1231 !(DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x1000))
1233 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1236 /* Don't flush CD/DVD drives */
1237 if (((DeviceExtension
->DeviceParams
[UnitNumber
].ConfigBits
>> 8) & 0x1F) == READ_ONLY_DIRECT_ACCESS_DEVICE
)
1239 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1245 DPRINT(" No ATAPI drive found!\n");
1250 if (AtapiIdentifyDevice(CommandPortBase
,
1254 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1256 DPRINT(" IDE drive found!\n");
1257 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1258 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1259 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1260 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1261 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1262 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1264 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1265 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1267 if (DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x0400 &&
1268 DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x0400)
1270 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_48BIT_ADDRESS
;
1272 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1274 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1277 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1279 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1282 if (DeviceExtension
->DeviceFlags
[UnitNumber
] & DEVICE_48BIT_ADDRESS
)
1284 if (!(DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x2000) ||
1285 !(DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x2000))
1287 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1292 if (!(DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x1000) ||
1293 !(DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x1000))
1295 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1302 DPRINT(" No IDE drive found!\n");
1307 /* Reset pending interrupts */
1308 IDEReadStatus(CommandPortBase
);
1309 /* Reenable interrupts */
1310 IDEWriteDriveControl(ControlPortBase
, 0);
1311 ScsiPortStallExecution(500);
1312 /* Return with drive 0 selected */
1313 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1314 ScsiPortStallExecution(500);
1316 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1318 return(DeviceFound
);
1323 * AtapiIdentifyDevice
1326 * Get the identification block from the drive
1333 * Address of the command port
1335 * Address of the control port
1337 * The drive index (0,1)
1339 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1341 * Address to write drive ident block
1344 * TRUE: The drive identification block was retrieved successfully
1345 * FALSE: an error ocurred
1349 AtapiIdentifyDevice(IN ULONG CommandPort
,
1350 IN ULONG ControlPort
,
1353 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1357 char SerialNumber
[20];
1358 char FirmwareRev
[8];
1359 char ModelNumber
[40];
1361 /* Get the Drive Identify block from drive or die */
1362 if (AtapiPolledRead(CommandPort
,
1369 (DriveNum
? IDE_DH_DRV1
: 0),
1370 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1371 (PUCHAR
)DrvParms
) == FALSE
)
1373 DPRINT("AtapiPolledRead() failed\n");
1377 /* Report on drive parameters if debug mode */
1378 memcpy(SerialNumber
, DrvParms
->SerialNumber
, 20);
1379 memcpy(FirmwareRev
, DrvParms
->FirmwareRev
, 8);
1380 memcpy(ModelNumber
, DrvParms
->ModelNumber
, 40);
1381 IDESwapBytePairs((PUCHAR
)SerialNumber
, 20);
1382 IDESwapBytePairs((PUCHAR
)FirmwareRev
, 8);
1383 IDESwapBytePairs((PUCHAR
)ModelNumber
, 40);
1384 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1385 DrvParms
->ConfigBits
,
1386 DrvParms
->LogicalCyls
,
1387 DrvParms
->LogicalHeads
,
1388 DrvParms
->SectorsPerTrack
,
1389 DrvParms
->InterSectorGap
,
1390 DrvParms
->InterSectorGapSize
);
1391 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1392 DrvParms
->BytesInPLO
,
1393 DrvParms
->VendorUniqueCnt
,
1395 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1396 DrvParms
->ControllerType
,
1397 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1398 DrvParms
->ECCByteCnt
,
1400 DPRINT("Model:[%.40s]\n", ModelNumber
);
1401 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1402 (DrvParms
->RWMultImplemented
),
1403 (DrvParms
->RWMultCurrent
) & 0xff,
1404 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1405 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1406 DrvParms
->MinPIOTransTime
,
1407 DrvParms
->MinDMATransTime
);
1408 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1409 DrvParms
->TMCylinders
,
1411 DrvParms
->TMSectorsPerTrk
,
1412 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1413 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1414 DrvParms
->TMSectorCountHi
,
1415 DrvParms
->TMSectorCountLo
,
1416 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1417 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms
->SupportedFeatures83
, DrvParms
->EnabledFeatures86
);
1418 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG
)DrvParms
->Max48BitAddress
);
1419 if (DrvParms
->TMFieldsValid
& 0x0004)
1421 if ((DrvParms
->UltraDmaModes
>> 8) && (DrvParms
->UltraDmaModes
& 0xff))
1424 while (!(DrvParms
->UltraDmaModes
& (0x0100 << mode
)))
1428 DPRINT("Ultra DMA mode %d is selected\n", mode
);
1430 else if ((DrvParms
->MultiDmaModes
>> 8) & (DrvParms
->MultiDmaModes
& 0x07))
1433 while(!(DrvParms
->MultiDmaModes
& (0x01 << mode
)))
1437 DPRINT("Multi DMA mode %d is selected\n", mode
);
1441 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1443 /* LBA ATA drives always have a sector size of 512 */
1444 DrvParms
->BytesPerSector
= 512;
1448 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1449 if (DrvParms
->BytesPerSector
== 0)
1451 DrvParms
->BytesPerSector
= 512;
1455 for (i
= 15; i
>= 0; i
--)
1457 if (DrvParms
->BytesPerSector
& (1 << i
))
1459 DrvParms
->BytesPerSector
= 1 << i
;
1465 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1474 // Read a sector of data from the drive in a polled fashion.
1480 // IN ULONG CommandPort Address of command port for drive
1481 // IN ULONG ControlPort Address of control port for drive
1482 // IN UCHAR PreComp Value to write to precomp register
1483 // IN UCHAR SectorCnt Value to write to sectorCnt register
1484 // IN UCHAR SectorNum Value to write to sectorNum register
1485 // IN UCHAR CylinderLow Value to write to CylinderLow register
1486 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1487 // IN UCHAR DrvHead Value to write to Drive/Head register
1488 // IN UCHAR Command Value to write to Command register
1489 // OUT PUCHAR Buffer Buffer for output data
1492 // BOOLEAN: TRUE success, FALSE error
1496 AtapiPolledRead(IN ULONG CommandPort
,
1497 IN ULONG ControlPort
,
1501 IN UCHAR CylinderLow
,
1502 IN UCHAR CylinderHigh
,
1507 ULONG SectorCount
= 0;
1509 BOOLEAN Junk
= FALSE
;
1512 /* Wait for BUSY to clear */
1513 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1515 Status
= IDEReadStatus(CommandPort
);
1516 if (!(Status
& IDE_SR_BUSY
))
1520 ScsiPortStallExecution(10);
1522 DPRINT("status=%02x\n", Status
);
1523 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1524 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1526 DPRINT("Drive is BUSY for too long\n");
1530 /* Write Drive/Head to select drive */
1531 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1532 ScsiPortStallExecution(500);
1534 /* Disable interrupts */
1535 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1536 ScsiPortStallExecution(500);
1539 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1540 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1542 Status
= IDEReadStatus(CommandPort
);
1543 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1547 ScsiPortStallExecution(10);
1549 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1555 /* Issue command to drive */
1556 if (DrvHead
& IDE_DH_LBA
)
1558 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1559 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1560 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1566 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1567 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1576 /* Setup command parameters */
1577 IDEWritePrecomp(CommandPort
, PreComp
);
1578 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1579 IDEWriteSectorNum(CommandPort
, SectorNum
);
1580 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1581 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1582 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1584 /* Issue the command */
1585 IDEWriteCommand(CommandPort
, Command
);
1586 ScsiPortStallExecution(50);
1588 /* wait for DRQ or error */
1589 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1591 Status
= IDEReadStatus(CommandPort
);
1592 if (!(Status
& IDE_SR_BUSY
))
1594 if (Status
& IDE_SR_ERR
)
1596 IDEWriteDriveControl(ControlPort
, 0);
1597 ScsiPortStallExecution(50);
1598 IDEReadStatus(CommandPort
);
1603 if (Status
& IDE_SR_DRQ
)
1609 IDEWriteDriveControl(ControlPort
, 0);
1610 ScsiPortStallExecution(50);
1611 IDEReadStatus(CommandPort
);
1616 ScsiPortStallExecution(10);
1620 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1622 IDEWriteDriveControl(ControlPort
, 0);
1623 ScsiPortStallExecution(50);
1624 IDEReadStatus(CommandPort
);
1631 /* Read data into buffer */
1634 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1635 Buffer
+= IDE_SECTOR_BUF_SZ
;
1639 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1640 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1644 /* Check for error or more sectors to read */
1645 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1647 Status
= IDEReadStatus(CommandPort
);
1648 if (!(Status
& IDE_SR_BUSY
))
1650 if (Status
& IDE_SR_ERR
)
1652 IDEWriteDriveControl(ControlPort
, 0);
1653 ScsiPortStallExecution(50);
1654 IDEReadStatus(CommandPort
);
1658 if (Status
& IDE_SR_DRQ
)
1660 if (SectorCount
>= SectorCnt
)
1662 DPRINT("Buffer size exceeded!\n");
1669 if (SectorCount
> SectorCnt
)
1671 DPRINT("Read %lu sectors of junk!\n",
1672 SectorCount
- SectorCnt
);
1674 IDEWriteDriveControl(ControlPort
, 0);
1675 ScsiPortStallExecution(50);
1676 IDEReadStatus(CommandPort
);
1686 // ------------------------------------------- Nondiscardable statics
1689 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1690 IN PSCSI_REQUEST_BLOCK Srb
)
1692 UCHAR ByteCountHigh
;
1698 DPRINT("AtapiSendAtapiCommand() called!\n");
1700 if (Srb
->PathId
!= 0)
1702 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1703 return(SRB_STATUS_INVALID_PATH_ID
);
1706 if (Srb
->TargetId
> 1)
1708 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1709 return(SRB_STATUS_INVALID_TARGET_ID
);
1714 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1715 return(SRB_STATUS_INVALID_LUN
);
1718 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1720 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1721 return(SRB_STATUS_NO_DEVICE
);
1724 if (Srb
->Cdb
[0] == SCSIOP_MODE_SENSE
)
1726 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1727 return (SRB_STATUS_INVALID_REQUEST
);
1730 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1733 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1734 return(AtapiInquiry(DeviceExtension
,
1737 /* Set pointer to data buffer. */
1738 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1739 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1740 DeviceExtension
->CurrentSrb
= Srb
;
1742 DPRINT("BufferAddress %x, BufferLength %d\n", Srb
->DataBuffer
, Srb
->DataTransferLength
);
1744 /* Wait for BUSY to clear */
1745 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1747 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1748 if (!(Status
& IDE_SR_BUSY
))
1752 ScsiPortStallExecution(10);
1754 DPRINT("status=%02x\n", Status
);
1755 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1756 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1758 DPRINT("Drive is BUSY for too long\n");
1759 return(SRB_STATUS_BUSY
);
1762 /* Select the desired drive */
1763 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1764 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1766 /* Wait a little while */
1767 ScsiPortStallExecution(50);
1770 /* Wait for BUSY to clear and DRDY to assert */
1771 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1773 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1774 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1778 ScsiPortStallExecution(10);
1780 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1781 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1783 DPRINT("Drive is BUSY for too long after drive select\n");
1784 return(SRB_STATUS_BUSY
);
1789 if ((DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
) &&
1790 (Srb
->Cdb
[0] == SCSIOP_READ
|| Srb
->Cdb
[0] == SCSIOP_WRITE
))
1792 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
1796 DeviceExtension
->UseDma
= FALSE
;
1800 if (DeviceExtension
->DataTransferLength
< 0x10000)
1802 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1803 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1807 ByteCountLow
= 0xFF;
1808 ByteCountHigh
= 0xFF;
1811 /* Set feature register */
1813 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, DeviceExtension
->UseDma
? 1 : 0);
1815 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1818 /* Set command packet length */
1819 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1820 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1822 /* Issue command to drive */
1824 if (DeviceExtension
->UseDma
)
1826 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiDmaPacketInterrupt
);
1831 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiPacketInterrupt
);
1834 /* Wait for DRQ to assert */
1835 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1837 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1838 if ((Status
& IDE_SR_DRQ
))
1842 ScsiPortStallExecution(10);
1845 /* Convert special SCSI SRBs to ATAPI format */
1846 switch (Srb
->Cdb
[0])
1848 case SCSIOP_FORMAT_UNIT
:
1849 case SCSIOP_MODE_SELECT
:
1850 AtapiScsiSrbToAtapi (Srb
);
1854 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
1855 DPRINT("CdbSize: %lu\n", CdbSize
);
1857 /* Write command packet */
1858 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1863 if (DeviceExtension
->UseDma
)
1867 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
1868 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
1871 DPRINT("AtapiSendAtapiCommand() done\n");
1873 return(SRB_STATUS_PENDING
);
1878 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1879 IN PSCSI_REQUEST_BLOCK Srb
)
1881 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1883 DPRINT("AtapiSendIdeCommand() called!\n");
1885 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1890 if (Srb
->PathId
!= 0)
1892 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1893 return(SRB_STATUS_INVALID_PATH_ID
);
1896 if (Srb
->TargetId
> 1)
1898 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1899 return(SRB_STATUS_INVALID_TARGET_ID
);
1904 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1905 return(SRB_STATUS_INVALID_LUN
);
1908 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1910 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1911 return(SRB_STATUS_NO_DEVICE
);
1914 switch (Srb
->Cdb
[0])
1916 case SCSIOP_INQUIRY
:
1917 SrbStatus
= AtapiInquiry(DeviceExtension
,
1921 case SCSIOP_READ_CAPACITY
:
1922 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1928 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1932 case SCSIOP_SYNCHRONIZE_CACHE
:
1933 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1937 case SCSIOP_TEST_UNIT_READY
:
1938 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1942 case SCSIOP_MODE_SENSE
:
1945 case SCSIOP_START_STOP_UNIT
:
1946 case SCSIOP_REQUEST_SENSE
:
1950 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1952 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1956 DPRINT("AtapiSendIdeCommand() done!\n");
1963 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1964 PSCSI_REQUEST_BLOCK Srb
)
1966 PIDE_DRIVE_IDENTIFY DeviceParams
;
1967 PINQUIRYDATA InquiryData
;
1969 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1970 DeviceExtension
, Srb
->TargetId
);
1972 InquiryData
= Srb
->DataBuffer
;
1973 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1976 memset(Srb
->DataBuffer
, 0, Srb
->DataTransferLength
);
1978 /* set device class */
1979 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1981 /* get it from the ATAPI configuration word */
1982 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1983 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1988 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1991 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1992 if (DeviceParams
->ConfigBits
& 0x80)
1994 DPRINT("Removable media!\n");
1995 InquiryData
->RemovableMedia
= 1;
1998 memcpy(InquiryData
->VendorId
, DeviceParams
->ModelNumber
, 20);
1999 IDESwapBytePairs(InquiryData
->VendorId
, 20);
2001 memcpy(&InquiryData
->ProductId
[12], " ", 4);
2003 memcpy(InquiryData
->ProductRevisionLevel
, DeviceParams
->FirmwareRev
, 4);
2004 IDESwapBytePairs(InquiryData
->ProductRevisionLevel
, 4);
2006 InquiryData
->AdditionalLength
= 31;
2008 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
2010 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2011 return(SRB_STATUS_SUCCESS
);
2016 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2017 PSCSI_REQUEST_BLOCK Srb
)
2019 PREAD_CAPACITY_DATA CapacityData
;
2020 PIDE_DRIVE_IDENTIFY DeviceParams
;
2021 LARGE_INTEGER LastSector
;
2023 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
2024 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
2025 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2027 /* Set sector (block) size to 512 bytes (big-endian). */
2028 CapacityData
->BytesPerBlock
= 0x20000;
2030 /* Calculate last sector (big-endian). */
2031 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2033 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2035 ((PUSHORT
)&LastSector
)[0] = DeviceParams
->Max48BitAddress
[0];
2036 ((PUSHORT
)&LastSector
)[1] = DeviceParams
->Max48BitAddress
[1];
2037 ((PUSHORT
)&LastSector
)[2] = DeviceParams
->Max48BitAddress
[2];
2038 ((PUSHORT
)&LastSector
)[3] = DeviceParams
->Max48BitAddress
[3];
2039 LastSector
.QuadPart
-= 1;
2044 LastSector
.u
.HighPart
= 0;
2045 LastSector
.u
.LowPart
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
2046 DeviceParams
->TMSectorCountLo
)-1;
2051 LastSector
.u
.HighPart
= 0;
2052 LastSector
.u
.LowPart
= (ULONG
)(DeviceParams
->LogicalCyls
*
2053 DeviceParams
->LogicalHeads
*
2054 DeviceParams
->SectorsPerTrack
)-1;
2056 if (LastSector
.u
.HighPart
)
2058 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector
.QuadPart
);
2062 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
2063 (((PUCHAR
)&LastSector
)[1] << 16) |
2064 (((PUCHAR
)&LastSector
)[2] << 8) |
2065 ((PUCHAR
)&LastSector
)[3];
2067 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2070 CapacityData
->LogicalBlockAddress
);
2072 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2073 return(SRB_STATUS_SUCCESS
);
2078 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2079 PSCSI_REQUEST_BLOCK Srb
)
2081 PIDE_DRIVE_IDENTIFY DeviceParams
;
2082 ULONG StartingSector
;
2084 UCHAR CylinderHigh
[2];
2085 UCHAR CylinderLow
[2];
2087 UCHAR SectorNumber
[2];
2091 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION DevExt
);
2093 DPRINT("AtapiReadWrite() called!\n");
2094 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2097 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2099 /* Get starting sector number from CDB. */
2100 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2101 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2102 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2103 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2105 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2106 DeviceParams
->BytesPerSector
;
2108 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2110 Srb
->DataTransferLength
,
2113 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2115 SectorNumber
[0] = StartingSector
& 0xff;
2116 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2117 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2118 SectorNumber
[1] = (StartingSector
>> 24) & 0xff;
2120 CylinderHigh
[1] = 0;
2121 DrvHead
= (Srb
->TargetId
? IDE_DH_DRV1
: 0) | IDE_DH_LBA
;
2123 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2124 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2125 DeviceExtension
->CommandPortBase
,
2126 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2127 (SectorNumber
[1] << 24) +
2128 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + DectorNumberLow
[0],
2133 else if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2135 SectorNumber
[0] = StartingSector
& 0xff;
2136 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2137 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2138 SectorNumber
[1] = 0;
2140 CylinderHigh
[1] = 0;
2141 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2142 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2145 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2146 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2147 DeviceExtension
->CommandPortBase
,
2148 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2149 ((DrvHead
& 0x0f) << 24) +
2150 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + SectorNumber
[0],
2156 SectorNumber
[0] = (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2157 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2158 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2159 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2160 StartingSector
/= DeviceParams
->LogicalHeads
;
2161 CylinderLow
[0] = StartingSector
& 0xff;
2162 CylinderHigh
[0] = StartingSector
>> 8;
2163 SectorNumber
[1] = 0;
2165 CylinderHigh
[1] = 0;
2167 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2168 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2169 DeviceExtension
->CommandPortBase
,
2170 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2179 /* Set pointer to data buffer. */
2180 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2181 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2183 DeviceExtension
->CurrentSrb
= Srb
;
2185 /* wait for BUSY to clear */
2186 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2188 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2189 if (!(Status
& IDE_SR_BUSY
))
2193 ScsiPortStallExecution(10);
2195 DPRINT("status=%02x\n", Status
);
2196 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2197 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2199 DPRINT ("Drive is BUSY for too long\n");
2200 return(SRB_STATUS_BUSY
);
2203 /* Select the desired drive */
2204 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2205 IDE_DH_FIXED
| DrvHead
);
2207 ScsiPortStallExecution(10);
2209 /* wait for BUSY to clear and DRDY to assert */
2210 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2212 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2213 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2217 ScsiPortStallExecution(10);
2219 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2220 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2222 DPRINT("Drive is BUSY for too long after drive select\n");
2223 return(SRB_STATUS_BUSY
);
2227 /* Setup command parameters */
2228 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2230 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2231 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
>> 8);
2232 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[1]);
2233 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[1]);
2234 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[1]);
2237 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2238 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
& 0xff);
2239 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[0]);
2240 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[0]);
2241 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[0]);
2243 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2246 if (DeviceExtension
->PRDTable
&&
2247 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
)
2249 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2251 if (DeviceExtension
->UseDma
)
2253 Handler
= AtapiDmaInterrupt
;
2254 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2256 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA_EXT
: IDE_CMD_WRITE_DMA_EXT
;
2260 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA
: IDE_CMD_WRITE_DMA
;
2266 Handler
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? AtapiReadInterrupt
: AtapiWriteInterrupt
;
2267 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
)
2269 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2271 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE_EXT
: IDE_CMD_WRITE_MULTIPLE_EXT
;
2275 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE
: IDE_CMD_WRITE_MULTIPLE
;
2280 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2282 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_EXT
: IDE_CMD_WRITE_EXT
;
2286 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ
: IDE_CMD_WRITE
;
2291 AtapiExecuteCommand(DeviceExtension
, Command
, Handler
);
2294 if (DeviceExtension
->UseDma
)
2298 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2299 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2304 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2306 /* Write data block */
2307 PUCHAR TargetAddress
;
2310 /* Wait for controller ready */
2311 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2313 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2314 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2318 ScsiPortStallExecution(10);
2320 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2322 DPRINT1("Drive is BUSY for too long after sending write command\n");
2323 return(SRB_STATUS_BUSY
);
2326 /* Update DeviceExtension data */
2327 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2328 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2330 TransferSize
= DeviceExtension
->DataTransferLength
;
2333 TargetAddress
= DeviceExtension
->DataBuffer
;
2334 DeviceExtension
->DataBuffer
+= TransferSize
;
2335 DeviceExtension
->DataTransferLength
-= TransferSize
;
2337 /* Write data block */
2338 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2340 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2346 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2353 DPRINT("AtapiReadWrite() done!\n");
2355 /* Wait for interrupt. */
2356 return(SRB_STATUS_PENDING
);
2361 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2362 PSCSI_REQUEST_BLOCK Srb
)
2367 DPRINT("AtapiFlushCache() called!\n");
2368 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2371 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_NO_FLUSH
)
2374 * NOTE: Don't flush the cache for CD/DVD drives. Although
2375 * the ATAPI-6 standard allows that, it has been experimentally
2376 * proved that it can damage some broken LG drives. Afterall
2377 * it doesn't make sense to flush cache on devices we don't
2381 /* The device states it doesn't support the command or it is disabled */
2382 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2383 return SRB_STATUS_INVALID_REQUEST
;
2386 /* Wait for BUSY to clear */
2387 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2389 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2390 if (!(Status
& IDE_SR_BUSY
))
2394 ScsiPortStallExecution(10);
2396 DPRINT("Status=%02x\n", Status
);
2397 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2398 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2400 DPRINT1("Drive is BUSY for too long\n");
2401 return(SRB_STATUS_BUSY
);
2404 /* Select the desired drive */
2405 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2406 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2407 ScsiPortStallExecution(10);
2409 /* Issue command to drive */
2410 AtapiExecuteCommand(DeviceExtension
,
2411 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
? IDE_CMD_FLUSH_CACHE_EXT
: IDE_CMD_FLUSH_CACHE
,
2412 AtapiNoDataInterrupt
);
2415 DPRINT("AtapiFlushCache() done!\n");
2417 /* Wait for interrupt. */
2418 return(SRB_STATUS_PENDING
);
2423 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2424 PSCSI_REQUEST_BLOCK Srb
)
2430 DPRINT1("AtapiTestUnitReady() called!\n");
2432 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2435 /* Return success if media status is not supported */
2436 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2438 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2439 return(SRB_STATUS_SUCCESS
);
2442 /* Wait for BUSY to clear */
2443 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2445 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2446 if (!(Status
& IDE_SR_BUSY
))
2450 ScsiPortStallExecution(10);
2452 DPRINT1("Status=%02x\n", Status
);
2453 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2454 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2456 DPRINT1("Drive is BUSY for too long\n");
2457 return(SRB_STATUS_BUSY
);
2460 /* Select the desired drive */
2461 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2462 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2463 ScsiPortStallExecution(10);
2465 /* Issue command to drive */
2466 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2468 /* Wait for controller ready */
2469 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2471 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2472 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2476 ScsiPortStallExecution(10);
2478 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2480 DPRINT1("Drive is BUSY for too long after sending write command\n");
2481 DeviceExtension
->Handler
= NULL
;
2482 return(SRB_STATUS_BUSY
);
2485 if (Status
& IDE_SR_ERR
)
2487 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2488 if (Error
== IDE_ER_UNC
)
2491 /* Handle write protection 'error' */
2492 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2493 DeviceExtension
->Handler
= NULL
;
2494 return(SRB_STATUS_SUCCESS
);
2499 /* Indicate expecting an interrupt. */
2500 return(SRB_STATUS_PENDING
);
2504 DeviceExtension
->Handler
= NULL
;
2506 DPRINT1("AtapiTestUnitReady() done!\n");
2508 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2509 return(SRB_STATUS_SUCCESS
);
2514 AtapiErrorToScsi(PVOID DeviceExtension
,
2515 PSCSI_REQUEST_BLOCK Srb
)
2517 PATAPI_MINIPORT_EXTENSION DevExt
;
2518 ULONG CommandPortBase
;
2519 ULONG ControlPortBase
;
2524 DPRINT("AtapiErrorToScsi() called\n");
2526 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2528 CommandPortBase
= DevExt
->CommandPortBase
;
2529 ControlPortBase
= DevExt
->ControlPortBase
;
2531 ErrorReg
= IDEReadError(CommandPortBase
);
2533 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2535 switch (ErrorReg
>> 4)
2537 case SCSI_SENSE_NO_SENSE
:
2538 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2539 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2540 SrbStatus
= SRB_STATUS_ERROR
;
2543 case SCSI_SENSE_RECOVERED_ERROR
:
2544 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2546 SrbStatus
= SRB_STATUS_SUCCESS
;
2549 case SCSI_SENSE_NOT_READY
:
2550 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2551 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2552 SrbStatus
= SRB_STATUS_ERROR
;
2555 case SCSI_SENSE_MEDIUM_ERROR
:
2556 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2557 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2558 SrbStatus
= SRB_STATUS_ERROR
;
2561 case SCSI_SENSE_HARDWARE_ERROR
:
2562 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2563 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2564 SrbStatus
= SRB_STATUS_ERROR
;
2567 case SCSI_SENSE_ILLEGAL_REQUEST
:
2568 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2569 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2570 SrbStatus
= SRB_STATUS_ERROR
;
2573 case SCSI_SENSE_UNIT_ATTENTION
:
2574 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2575 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2576 SrbStatus
= SRB_STATUS_ERROR
;
2579 case SCSI_SENSE_DATA_PROTECT
:
2580 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2581 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2582 SrbStatus
= SRB_STATUS_ERROR
;
2585 case SCSI_SENSE_BLANK_CHECK
:
2586 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2587 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2588 SrbStatus
= SRB_STATUS_ERROR
;
2591 case SCSI_SENSE_ABORTED_COMMAND
:
2592 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2593 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2594 SrbStatus
= SRB_STATUS_ERROR
;
2598 DPRINT("ATAPI error: Invalid sense key\n");
2600 SrbStatus
= SRB_STATUS_ERROR
;
2606 DPRINT1("IDE error: %02x\n", ErrorReg
);
2609 SrbStatus
= SRB_STATUS_ERROR
;
2612 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2615 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2616 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2617 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2618 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2619 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2621 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2632 Srb
->ScsiStatus
= ScsiStatus
;
2634 DPRINT("AtapiErrorToScsi() done\n");
2641 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2643 DPRINT("AtapiConvertScsiToAtapi() called\n");
2645 Srb
->CdbLength
= 12;
2647 switch (Srb
->Cdb
[0])
2649 case SCSIOP_FORMAT_UNIT
:
2650 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2653 case SCSIOP_MODE_SELECT
:
2655 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2658 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2659 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2661 RtlZeroMemory (Srb
->Cdb
,
2663 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2664 AtapiModeSelect
->PFBit
= 1;
2665 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2666 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2672 static VOID FASTCALL
2673 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2676 PSCSI_REQUEST_BLOCK Srb
;
2677 Srb
= DevExt
->CurrentSrb
;
2679 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2681 Srb
->SrbStatus
= SrbStatus
;
2682 if (SrbStatus
== SRB_STATUS_ERROR
)
2684 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2686 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2688 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2691 DevExt
->Handler
= NULL
;
2692 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2693 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2697 static BOOLEAN FASTCALL
2698 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2707 DPRINT("AtapiPacketDmaInterrupt\n");
2709 DevExt
->UseDma
= FALSE
;
2712 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2713 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2714 /* get DMA status */
2715 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2716 /* clear the INTR & ERROR bits */
2717 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2719 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2720 DPRINT("DriveStatus: %x\n", Status
);
2722 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2724 if (Status
& IDE_SR_ERR
)
2726 Error
= IDEReadError(DevExt
->CommandPortBase
);
2727 SensKey
= Error
>> 4;
2728 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2730 SrbStatus
= SRB_STATUS_ERROR
;
2734 if ((DmaStatus
& 0x07) != 0x04)
2736 DPRINT("DmaStatus: %02x\n", DmaStatus
);
2737 SrbStatus
= SRB_STATUS_ERROR
;
2741 SrbStatus
= STATUS_SUCCESS
;
2744 AtapiCompleteRequest(DevExt
, SrbStatus
);
2745 DPRINT("AtapiDmaPacketInterrupt() done\n");
2750 static BOOLEAN FASTCALL
2751 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2753 PSCSI_REQUEST_BLOCK Srb
;
2759 PBYTE TargetAddress
;
2765 DPRINT("AtapiPacketInterrupt()\n");
2767 Srb
= DevExt
->CurrentSrb
;
2769 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2770 DPRINT("DriveStatus: %x\n", Status
);
2772 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2774 if (Status
& IDE_SR_ERR
)
2776 Error
= IDEReadError(DevExt
->CommandPortBase
);
2777 SensKey
= Error
>> 4;
2778 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2781 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2782 DPRINT("AtapiPacketInterrupt() done\n");
2786 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
2787 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
2788 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
2790 if (!(Status
& IDE_SR_DRQ
))
2792 if (DevExt
->DataTransferLength
> 0)
2794 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2795 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
2796 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
2800 SrbStatus
= SRB_STATUS_SUCCESS
;
2802 AtapiCompleteRequest(DevExt
, SrbStatus
);
2803 DPRINT("AtapiPacketInterrupt() done\n");
2807 TargetAddress
= DevExt
->DataBuffer
;
2809 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2811 DPRINT("read data\n");
2812 if (DevExt
->DataTransferLength
<= TransferSize
)
2814 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
2815 TransferSize
= DevExt
->DataTransferLength
;
2817 DevExt
->DataTransferLength
= 0;
2822 DevExt
->DataTransferLength
-= TransferSize
;
2823 IsLastBlock
= FALSE
;
2826 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
2828 DevExt
->DataBuffer
+= TransferSize
;
2830 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2835 /* Read remaining junk from device */
2836 while (JunkSize
> 0)
2838 IDEReadWord(DevExt
->CommandPortBase
);
2842 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
2844 ScsiPortStallExecution(10);
2847 /* Check for data overrun */
2848 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
2850 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2851 IDEReadWord(DevExt
->CommandPortBase
);
2855 SrbStatus
= SRB_STATUS_SUCCESS
;
2857 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2859 DPRINT("write data\n");
2860 if (DevExt
->DataTransferLength
< TransferSize
)
2862 TransferSize
= DevExt
->DataTransferLength
;
2865 TargetAddress
= DevExt
->DataBuffer
;
2867 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
2869 DevExt
->DataBuffer
+= TransferSize
;
2870 DevExt
->DataTransferLength
-= TransferSize
;
2872 /* Write the sector */
2873 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2874 SrbStatus
= SRB_STATUS_SUCCESS
;
2875 IsLastBlock
= FALSE
;
2879 DPRINT("Unspecified transfer direction!\n");
2880 SrbStatus
= SRB_STATUS_SUCCESS
;
2885 AtapiCompleteRequest(DevExt
, SrbStatus
);
2887 DPRINT("AtapiPacketInterrupt() done\n");
2891 static BOOLEAN FASTCALL
2892 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2896 DPRINT("AtapiNoDataInterrupt()\n");
2898 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2899 AtapiCompleteRequest(DevExt
,
2900 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
2902 DPRINT("AtapiNoDatanterrupt() done!\n");
2907 static BOOLEAN FASTCALL
2908 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2914 DPRINT("AtapiDmaInterrupt()\n");
2916 DevExt
->UseDma
= FALSE
;
2918 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2919 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2920 /* get DMA status */
2921 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2922 /* clear the INTR & ERROR bits */
2923 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2925 /* read the drive status */
2926 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2927 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
2928 (DmaStatus
& 0x07) == 4)
2930 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2931 DPRINT("AtapiDmaInterrupt() done\n");
2934 DPRINT1("Status %x\n", Status
);
2935 DPRINT1("%x\n", DmaStatus
);
2936 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2937 DPRINT1("AtapiDmaReadInterrupt() done\n");
2942 static BOOLEAN FASTCALL
2943 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2945 PSCSI_REQUEST_BLOCK Srb
;
2947 BOOLEAN IsLastBlock
;
2948 PUCHAR TargetAddress
;
2951 DPRINT("AtapiReadInterrupt() called!\n");
2953 Srb
= DevExt
->CurrentSrb
;
2955 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2956 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
2958 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
2960 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2961 DPRINT("AtapiReadInterrupt() done!\n");
2964 DPRINT("AtapiReadInterrupt() done!\n");
2968 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
2970 /* Update controller/device state variables */
2971 TargetAddress
= DevExt
->DataBuffer
;
2972 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2974 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2975 DPRINT("TransferSize: %lu\n", TransferSize
);
2977 if (DevExt
->DataTransferLength
<= TransferSize
)
2979 TransferSize
= DevExt
->DataTransferLength
;
2980 DevExt
->DataTransferLength
= 0;
2985 DevExt
->DataTransferLength
-= TransferSize
;
2986 IsLastBlock
= FALSE
;
2988 DevExt
->DataBuffer
+= TransferSize
;
2989 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
2991 /* Copy the block of data */
2992 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2994 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2998 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3003 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3006 DPRINT("AtapiReadInterrupt() done!\n");
3011 static BOOLEAN FASTCALL
3012 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
3014 PSCSI_REQUEST_BLOCK Srb
;
3016 BOOLEAN IsLastBlock
;
3017 PUCHAR TargetAddress
;
3020 DPRINT("AtapiWriteInterrupt() called!\n");
3022 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
3023 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
3025 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
3027 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
3028 DPRINT("AtapiWriteInterrupt() done!\n");
3031 DPRINT("AtapiWriteInterrupt() done!\n");
3036 Srb
= DevExt
->CurrentSrb
;
3037 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
3038 if (DevExt
->DataTransferLength
< TransferSize
)
3040 TransferSize
= DevExt
->DataTransferLength
;
3042 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
3044 IsLastBlock
= FALSE
;
3045 TargetAddress
= DevExt
->DataBuffer
;
3046 DevExt
->DataBuffer
+= TransferSize
;
3047 DevExt
->DataTransferLength
-= TransferSize
;
3049 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
3050 DPRINT("TransferSize: %lu\n", TransferSize
);
3051 /* Write the sector */
3052 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
3054 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3058 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3061 else if (DeviceStatus
& IDE_SR_DRQ
)
3063 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3066 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
3068 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
3077 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3079 DPRINT("AtapiWriteInterrupt() done!\n");
3085 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
3087 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
3089 if (DevExt
->Handler
!= NULL
)
3091 DPRINT1("DevExt->Handler is already set!!\n");
3093 DevExt
->Handler
= Handler
;
3094 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
3095 ScsiPortStallExecution(1);
3100 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
3101 PSCSI_REQUEST_BLOCK Srb
,
3106 PPRD PRDEntry
= DevExt
->PRDTable
;
3107 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
3112 DPRINT("AtapiInitDma()\n");
3114 StartAddress
= Srb
->DataBuffer
;
3115 EndAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ Srb
->DataTransferLength
);
3116 DevExt
->PRDCount
= 0;
3118 while (StartAddress
< EndAddress
)
3120 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
3121 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
3128 /* calculate the length up to the next 64k boundary */
3129 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
3130 if (tmpLength
> Length
)
3135 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3139 if (tmpLength
== 0x10000)
3141 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3143 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3144 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3145 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3146 PRDEntry
->Length
= tmpLength
;
3149 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3153 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3154 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3155 Length
-= tmpLength
;
3156 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3158 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3159 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3160 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3161 PRDEntry
->Length
= tmpLength
;
3163 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3164 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3165 Length
-= tmpLength
;
3168 /* set the end marker in the last PRD */
3170 PRDEntry
->Length
|= 0x80000000;
3171 /* set the PDR table */
3172 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3173 /* write the DMA command */
3174 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3175 /* reset the status and interrupt bit */
3176 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3177 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);