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>
61 #define VERSION "0.0.1"
64 // ------------------------------------------------------- File Static Data
74 // ATAPI_MINIPORT_EXTENSION
77 // Extension to be placed in each port device object
80 // Allocated from NON-PAGED POOL
81 // Available at any IRQL
84 typedef struct _ATAPI_MINIPORT_EXTENSION
86 IDE_DRIVE_IDENTIFY DeviceParams
[2];
88 ULONG TransferSize
[2];
90 ULONG CommandPortBase
;
91 ULONG ControlPortBase
;
92 ULONG BusMasterRegisterBase
;
94 PSCSI_REQUEST_BLOCK CurrentSrb
;
97 ULONG DataTransferLength
;
99 BOOLEAN
FASTCALL (*Handler
)(IN
struct _ATAPI_MINIPORT_EXTENSION
* DevExt
);
105 SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress
;
107 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
110 #define DEVICE_PRESENT 0x00000001
111 #define DEVICE_ATAPI 0x00000002
112 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
113 #define DEVICE_DWORD_IO 0x00000008
114 #define DEVICE_48BIT_ADDRESS 0x00000010
115 #define DEVICE_MEDIA_STATUS 0x00000020
116 #define DEVICE_DMA_CMD 0x00000040
117 #define DEVICE_NO_FLUSH 0x00000080
120 typedef struct _UNIT_EXTENSION
123 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
125 PCI_SLOT_NUMBER LastSlotNumber
;
127 #ifdef ENABLE_NATIVE_PCI
128 typedef struct _PCI_NATIVE_CONTROLLER
133 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
135 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
139 0x4D68, // PDC20268, Ultra100TX2
143 0x4D30, // PDC20267, Ultra100
149 // ----------------------------------------------- Discardable Declarations
153 // make the initialization routines discardable, so that they
156 #pragma alloc_text(init, DriverEntry)
158 // make the PASSIVE_LEVEL routines pageable, so that they don't
159 // waste nonpaged memory
161 #endif /* ALLOC_PRAGMA */
163 // ---------------------------------------------------- Forward Declarations
167 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
168 PSCSI_REQUEST_BLOCK Srb
,
173 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
175 PVOID BusInformation
,
176 PCHAR ArgumentString
,
177 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
181 AtapiFindIsaBusController(PVOID DeviceExtension
,
183 PVOID BusInformation
,
184 PCHAR ArgumentString
,
185 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
189 AtapiFindNativePciController(PVOID DeviceExtension
,
191 PVOID BusInformation
,
192 PCHAR ArgumentString
,
193 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
196 static BOOLEAN STDCALL
197 AtapiInitialize(IN PVOID DeviceExtension
);
199 static BOOLEAN STDCALL
200 AtapiResetBus(IN PVOID DeviceExtension
,
203 static BOOLEAN STDCALL
204 AtapiStartIo(IN PVOID DeviceExtension
,
205 IN PSCSI_REQUEST_BLOCK Srb
);
208 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
210 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
));
212 static BOOLEAN STDCALL
213 AtapiInterrupt(IN PVOID DeviceExtension
);
215 static BOOLEAN FASTCALL
216 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
);
218 static BOOLEAN FASTCALL
219 AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
221 static BOOLEAN FASTCALL
222 AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
225 static BOOLEAN FASTCALL
226 AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
228 static BOOLEAN FASTCALL
229 AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
232 static BOOLEAN FASTCALL
233 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
236 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
237 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
240 AtapiIdentifyDevice(IN ULONG CommandPort
,
241 IN ULONG ControlPort
,
244 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
247 AtapiPolledRead(IN ULONG CommandPort
,
248 IN ULONG ControlPort
,
252 IN UCHAR CylinderLow
,
253 IN UCHAR CylinderHigh
,
259 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
260 IN PSCSI_REQUEST_BLOCK Srb
);
263 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
264 IN PSCSI_REQUEST_BLOCK Srb
);
267 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
268 IN PSCSI_REQUEST_BLOCK Srb
);
271 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
272 IN PSCSI_REQUEST_BLOCK Srb
);
275 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
276 IN PSCSI_REQUEST_BLOCK Srb
);
279 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
280 PSCSI_REQUEST_BLOCK Srb
);
283 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
284 PSCSI_REQUEST_BLOCK Srb
);
287 AtapiErrorToScsi(PVOID DeviceExtension
,
288 PSCSI_REQUEST_BLOCK Srb
);
291 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
);
293 // ---------------------------------------------------------------- Inlines
296 IDESwapBytePairs(UCHAR
*Buf
,
302 for (i
= 0; i
< Cnt
; i
+= 2)
311 // ------------------------------------------------------- Public Interface
316 // This function initializes the driver, locates and claims
317 // hardware resources, and creates various NT objects needed
318 // to process I/O requests.
324 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
326 // IN PUNICODE_STRING RegistryPath Name of registry driver service
333 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
334 IN PUNICODE_STRING RegistryPath
)
336 HW_INITIALIZATION_DATA InitData
;
339 DPRINT("ATAPI Driver %s\n", VERSION
);
340 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
342 /* Initialize data structure */
343 RtlZeroMemory(&InitData
,
344 sizeof(HW_INITIALIZATION_DATA
));
345 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
346 InitData
.HwInitialize
= AtapiInitialize
;
347 InitData
.HwResetBus
= AtapiResetBus
;
348 InitData
.HwStartIo
= AtapiStartIo
;
349 InitData
.HwInterrupt
= AtapiInterrupt
;
351 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
352 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
354 InitData
.MapBuffers
= TRUE
;
356 /* Search the PCI bus for compatibility mode ide controllers */
358 InitData
.NeedPhysicalAddresses
= TRUE
;
360 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
361 InitData
.NumberOfAccessRanges
= 3;
362 InitData
.AdapterInterfaceType
= PCIBus
;
364 InitData
.VendorId
= NULL
;
365 InitData
.VendorIdLength
= 0;
366 InitData
.DeviceId
= NULL
;
367 InitData
.DeviceIdLength
= 0;
369 Status
= ScsiPortInitialize(DriverObject
,
373 // if (newStatus < statusToReturn)
374 // statusToReturn = newStatus;
377 /* Search the PCI bus for all ide controllers */
378 #ifdef ENABLE_NATIVE_PCI
379 InitData
.NeedPhysicalAddresses
= TRUE
;
381 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
382 InitData
.NumberOfAccessRanges
= 3;
383 InitData
.AdapterInterfaceType
= PCIBus
;
385 InitData
.VendorId
= 0;
386 InitData
.VendorIdLength
= 0;
387 InitData
.DeviceId
= 0;
388 InitData
.DeviceIdLength
= 0;
390 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
392 Status
= ScsiPortInitialize(DriverObject
,
396 // if (newStatus < statusToReturn)
397 // statusToReturn = newStatus;
400 /* Search the ISA bus for ide controllers */
402 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
403 InitData
.NumberOfAccessRanges
= 2;
404 InitData
.AdapterInterfaceType
= Isa
;
406 InitData
.VendorId
= NULL
;
407 InitData
.VendorIdLength
= 0;
408 InitData
.DeviceId
= NULL
;
409 InitData
.DeviceIdLength
= 0;
411 Status
= ScsiPortInitialize(DriverObject
,
415 // if (newStatus < statusToReturn)
416 // statusToReturn = newStatus;
419 DPRINT("Returning from DriverEntry\n");
426 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
427 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
428 INTERFACE_TYPE InterfaceType
,
429 ULONG CommandPortBase
,
430 ULONG ControlPortBase
,
431 ULONG BusMasterPortBase
,
432 ULONG InterruptVector
)
434 SCSI_PHYSICAL_ADDRESS IoAddress
;
439 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
440 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
442 ConfigInfo
->SystemIoBusNumber
,
450 DevExt
->Handler
= NULL
;
451 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
452 (*ConfigInfo
->AccessRanges
)[0].RangeStart
= IoAddress
;
453 (*ConfigInfo
->AccessRanges
)[0].RangeLength
= 8;
454 (*ConfigInfo
->AccessRanges
)[0].RangeInMemory
= FALSE
;
458 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
459 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
461 ConfigInfo
->SystemIoBusNumber
,
467 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
468 (PVOID
)DevExt
->CommandPortBase
);
471 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
472 (*ConfigInfo
->AccessRanges
)[1].RangeStart
= IoAddress
;
473 (*ConfigInfo
->AccessRanges
)[1].RangeLength
= 1;
474 (*ConfigInfo
->AccessRanges
)[1].RangeInMemory
= FALSE
;
476 if (BusMasterPortBase
)
478 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
479 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
481 ConfigInfo
->SystemIoBusNumber
,
487 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
488 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
491 DevExt
->BusMasterRegisterBase
= (ULONG
)IoBase
;
492 (*ConfigInfo
->AccessRanges
)[2].RangeStart
= IoAddress
;
493 (*ConfigInfo
->AccessRanges
)[2].RangeLength
= 8;
494 (*ConfigInfo
->AccessRanges
)[2].RangeInMemory
= FALSE
;
496 // ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
497 // ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
498 ConfigInfo
->DmaWidth
= Width32Bits
;
499 // ConfigInfo->DmaSpeed = Compatible;
500 ConfigInfo
->ScatterGather
= TRUE
;
501 ConfigInfo
->Master
= TRUE
;
502 ConfigInfo
->NumberOfPhysicalBreaks
= 0x10000 / PAGE_SIZE
+ 1;
503 ConfigInfo
->Dma32BitAddresses
= TRUE
;
504 ConfigInfo
->NeedPhysicalAddresses
= TRUE
;
505 ConfigInfo
->MapBuffers
= TRUE
;
507 DevExt
->PRDMaxCount
= PAGE_SIZE
/ sizeof(PRD
);
508 DevExt
->PRDTable
= ScsiPortGetUncachedExtension(DevExt
, ConfigInfo
, sizeof(PRD
) * DevExt
->PRDMaxCount
);
509 if (DevExt
->PRDTable
!= NULL
)
511 DevExt
->PRDTablePhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, NULL
, DevExt
->PRDTable
, &Length
);
513 if (DevExt
->PRDTable
== NULL
||
514 DevExt
->PRDTablePhysicalAddress
.QuadPart
== 0LL ||
515 Length
< sizeof(PRD
) * DevExt
->PRDMaxCount
)
517 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
518 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
519 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->BusMasterRegisterBase
);
524 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
525 ConfigInfo
->BusInterruptVector
= InterruptVector
;
526 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
528 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
530 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
532 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
534 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
542 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
544 PVOID BusInformation
,
545 PCHAR ArgumentString
,
546 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
549 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
550 PCI_SLOT_NUMBER SlotNumber
;
551 PCI_COMMON_CONFIG PciConfig
;
553 ULONG StartDeviceNumber
;
555 ULONG StartFunctionNumber
;
556 ULONG FunctionNumber
;
557 BOOLEAN ChannelFound
;
559 ULONG BusMasterBasePort
= 0;
561 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
562 ConfigInfo
->SystemIoBusNumber
,
563 ConfigInfo
->SlotNumber
);
567 /* both channels were claimed: exit */
568 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
569 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
570 return(SP_RETURN_NOT_FOUND
);
572 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
573 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
574 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
575 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
577 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
578 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
580 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
581 ChannelFound
= FALSE
;
584 DataSize
= ScsiPortGetBusData(DeviceExtension
,
586 ConfigInfo
->SystemIoBusNumber
,
587 SlotNumber
.u
.AsULONG
,
589 PCI_COMMON_HDR_LENGTH
);
590 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
592 if (FunctionNumber
== 0)
602 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
603 if (PciConfig
.BaseClass
== 0x01 &&
604 PciConfig
.SubClass
== 0x01) // &&
605 // (PciConfig.ProgIf & 0x05) == 0)
607 /* both channels are in compatibility mode */
608 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
609 ConfigInfo
->SystemIoBusNumber
,
610 SlotNumber
.u
.bits
.DeviceNumber
,
611 SlotNumber
.u
.bits
.FunctionNumber
,
614 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
616 DPRINT("Found IDE controller in compatibility mode!\n");
618 ConfigInfo
->NumberOfBuses
= 1;
619 ConfigInfo
->MaximumNumberOfTargets
= 2;
620 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
622 if (PciConfig
.ProgIf
& 0x80)
624 DPRINT("Found IDE Bus Master controller!\n");
625 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
627 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
628 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
631 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
633 /* Both channels unclaimed: Claim primary channel */
634 DPRINT("Primary channel!\n");
635 ChannelFound
= AtapiClaimHwResources(DevExt
,
644 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
646 /* Primary channel already claimed: claim secondary channel */
647 DPRINT("Secondary channel!\n");
649 ChannelFound
= AtapiClaimHwResources(DevExt
,
654 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
658 /* Find attached devices */
661 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
662 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
663 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
664 return(SP_RETURN_FOUND
);
667 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
672 StartFunctionNumber
= 0;
674 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
676 return(SP_RETURN_NOT_FOUND
);
683 AtapiFindIsaBusController(PVOID DeviceExtension
,
685 PVOID BusInformation
,
686 PCHAR ArgumentString
,
687 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
690 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
691 BOOLEAN ChannelFound
= FALSE
;
692 BOOLEAN DeviceFound
= FALSE
;
694 DPRINT("AtapiFindIsaBusController() called!\n");
698 ConfigInfo
->NumberOfBuses
= 1;
699 ConfigInfo
->MaximumNumberOfTargets
= 2;
700 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
702 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
704 /* Both channels unclaimed: Claim primary channel */
705 DPRINT("Primary channel!\n");
707 ChannelFound
= AtapiClaimHwResources(DevExt
,
716 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
718 /* Primary channel already claimed: claim secondary channel */
719 DPRINT("Secondary channel!\n");
721 ChannelFound
= AtapiClaimHwResources(DevExt
,
732 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
734 return(SP_RETURN_NOT_FOUND
);
737 /* Find attached devices */
740 DeviceFound
= AtapiFindDevices(DevExt
,
742 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
743 return(SP_RETURN_FOUND
);
746 return SP_RETURN_NOT_FOUND
;
751 #ifdef ENABLE_NATIVE_PCI
753 AtapiFindNativePciController(PVOID DeviceExtension
,
755 PVOID BusInformation
,
756 PCHAR ArgumentString
,
757 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
760 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
761 PCI_COMMON_CONFIG PciConfig
;
762 PCI_SLOT_NUMBER SlotNumber
;
765 ULONG StartDeviceNumber
;
766 ULONG FunctionNumber
;
767 ULONG StartFunctionNumber
;
768 ULONG BusMasterBasePort
;
770 BOOLEAN ChannelFound
;
772 DPRINT("AtapiFindNativePciController() called!\n");
774 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
775 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
776 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
777 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
779 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
780 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
782 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
783 DataSize
= ScsiPortGetBusData(DeviceExtension
,
785 ConfigInfo
->SystemIoBusNumber
,
786 SlotNumber
.u
.AsULONG
,
788 PCI_COMMON_HDR_LENGTH
);
789 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
793 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
795 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
796 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
801 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
803 /* We have found a known native pci ide controller */
804 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
806 DPRINT("Found IDE Bus Master controller!\n");
807 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
808 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
812 BusMasterBasePort
= 0;
815 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
816 ConfigInfo
->NumberOfBuses
= 1;
817 ConfigInfo
->MaximumNumberOfTargets
= 2;
818 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
821 We must not store and use the last tested slot number. If there is a recall
822 to the some device and we will claim the primary channel again than the call
823 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
824 claim the secondary channel.
826 ChannelFound
= FALSE
;
827 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
829 /* try to claim primary channel */
830 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
831 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
833 /* primary channel is enabled */
834 ChannelFound
= AtapiClaimHwResources(DevExt
,
837 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
838 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
840 PciConfig
.u
.type0
.InterruptLine
);
843 AtapiFindDevices(DevExt
, ConfigInfo
);
845 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
846 return SP_RETURN_FOUND
;
852 /* try to claim secondary channel */
853 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
854 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
856 /* secondary channel is enabled */
857 ChannelFound
= AtapiClaimHwResources(DevExt
,
860 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
861 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
862 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
863 PciConfig
.u
.type0
.InterruptLine
);
866 AtapiFindDevices(DevExt
, ConfigInfo
);
868 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
869 return SP_RETURN_FOUND
;
875 StartFunctionNumber
= 0;
878 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
879 DPRINT("AtapiFindNativePciController() done!\n");
881 return(SP_RETURN_NOT_FOUND
);
886 static BOOLEAN STDCALL
887 AtapiInitialize(IN PVOID DeviceExtension
)
893 static BOOLEAN STDCALL
894 AtapiResetBus(IN PVOID DeviceExtension
,
901 static BOOLEAN STDCALL
902 AtapiStartIo(IN PVOID DeviceExtension
,
903 IN PSCSI_REQUEST_BLOCK Srb
)
905 PATAPI_MINIPORT_EXTENSION DevExt
;
908 DPRINT("AtapiStartIo() called\n");
910 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
912 switch (Srb
->Function
)
914 case SRB_FUNCTION_EXECUTE_SCSI
:
915 DevExt
->CurrentSrb
= Srb
;
916 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
918 Result
= AtapiSendAtapiCommand(DevExt
,
923 Result
= AtapiSendIdeCommand(DevExt
,
928 case SRB_FUNCTION_ABORT_COMMAND
:
929 if (DevExt
->CurrentSrb
!= NULL
)
931 Result
= SRB_STATUS_ABORT_FAILED
;
935 Result
= SRB_STATUS_SUCCESS
;
940 Result
= SRB_STATUS_INVALID_REQUEST
;
944 Srb
->SrbStatus
= Result
;
947 if (Result
!= SRB_STATUS_PENDING
)
949 DevExt
->CurrentSrb
= NULL
;
951 ScsiPortNotification(RequestComplete
,
954 ScsiPortNotification(NextRequest
,
960 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
963 DPRINT("AtapiStartIo() done\n");
968 static BOOLEAN STDCALL
969 AtapiInterrupt(IN PVOID DeviceExtension
)
971 PATAPI_MINIPORT_EXTENSION DevExt
;
973 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
975 if (DevExt
->Handler
== NULL
)
977 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
978 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) != IDE_SR_DRDY
)
980 static ULONG Count
= 0;
982 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
983 DevExt
->CommandPortBase
, Status
, Count
);
990 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
991 if (!(Status
& 0x04))
999 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1000 if (Status
& IDE_SR_BUSY
)
1005 return DevExt
->Handler(DevExt
);
1008 // ---------------------------------------------------- Discardable statics
1012 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension
, ULONG UnitNumber
)
1014 BOOLEAN Result
= FALSE
;
1019 if (DeviceExtension
->PRDTable
)
1021 if (DeviceExtension
->DeviceParams
[UnitNumber
].Capabilities
& IDE_DRID_DMA_SUPPORTED
)
1023 if ((DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0004) &&
1024 (DeviceExtension
->DeviceParams
[UnitNumber
].UltraDmaModes
& 0x7F00))
1028 else if (DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0002)
1030 if ((DeviceExtension
->DeviceParams
[UnitNumber
].MultiDmaModes
& 0x0404) == 0x0404)
1036 * should we support single mode dma ?
1038 else if ((DeviceExtension
->DeviceParams
[UnitNumber
].DmaModes
& 0x0404) == 0x0404)
1044 Status
= IDEReadDMAStatus(DeviceExtension
->BusMasterRegisterBase
);
1047 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
| (UnitNumber
? 0x40 : 0x20));
1051 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
& (UnitNumber
? ~0x40 : ~0x20));
1060 /**********************************************************************
1065 * Searches for devices on the given port.
1072 * Port device specific information.
1075 * Port configuration information.
1078 * TRUE: At least one device is attached to the port.
1079 * FALSE: No device is attached to the port.
1083 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1084 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1086 BOOLEAN DeviceFound
= FALSE
;
1087 ULONG CommandPortBase
;
1088 ULONG ControlPortBase
;
1094 DPRINT("AtapiFindDevices() called\n");
1096 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
);
1097 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1099 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[1].RangeStart
);
1100 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1102 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1105 IDEWriteDriveHead(CommandPortBase
,
1106 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1107 ScsiPortStallExecution(500);
1109 /* Disable interrupts */
1110 IDEWriteDriveControl(ControlPortBase
,
1112 ScsiPortStallExecution(500);
1114 /* Check if a device is attached to the interface */
1115 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1116 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1118 High
= IDEReadCylinderHigh(CommandPortBase
);
1119 Low
= IDEReadCylinderLow(CommandPortBase
);
1121 IDEWriteCylinderHigh(CommandPortBase
, 0);
1122 IDEWriteCylinderLow(CommandPortBase
, 0);
1124 if (Low
!= 0x55 || High
!= 0xaa)
1126 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1130 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_RESET
, NULL
);
1132 for (Retries
= 0; Retries
< 20000; Retries
++)
1134 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1138 ScsiPortStallExecution(150);
1140 if (Retries
>= 20000)
1142 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1143 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1147 High
= IDEReadCylinderHigh(CommandPortBase
);
1148 Low
= IDEReadCylinderLow(CommandPortBase
);
1150 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1155 if (High
== 0xEB && Low
== 0x14)
1157 if (AtapiIdentifyDevice(CommandPortBase
,
1161 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1163 DPRINT(" ATAPI drive found!\n");
1164 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1165 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1166 DeviceExtension
->TransferSize
[UnitNumber
] =
1167 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1169 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1171 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1178 DPRINT(" No ATAPI drive found!\n");
1183 if (AtapiIdentifyDevice(CommandPortBase
,
1187 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1189 DPRINT(" IDE drive found!\n");
1190 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1191 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1192 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1193 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1194 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1195 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1197 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1198 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1200 if (DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x0400 &&
1201 DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x0400)
1203 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_48BIT_ADDRESS
;
1205 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1207 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1210 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1212 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1219 DPRINT(" No IDE drive found!\n");
1224 /* Reset pending interrupts */
1225 IDEReadStatus(CommandPortBase
);
1226 /* Reenable interrupts */
1227 IDEWriteDriveControl(ControlPortBase
, 0);
1228 ScsiPortStallExecution(500);
1229 /* Return with drive 0 selected */
1230 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1231 ScsiPortStallExecution(500);
1233 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1235 return(DeviceFound
);
1240 * AtapiIdentifyDevice
1243 * Get the identification block from the drive
1250 * Address of the command port
1252 * Address of the control port
1254 * The drive index (0,1)
1256 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1258 * Address to write drive ident block
1261 * TRUE: The drive identification block was retrieved successfully
1262 * FALSE: an error ocurred
1266 AtapiIdentifyDevice(IN ULONG CommandPort
,
1267 IN ULONG ControlPort
,
1270 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1275 /* Get the Drive Identify block from drive or die */
1276 if (AtapiPolledRead(CommandPort
,
1283 (DriveNum
? IDE_DH_DRV1
: 0),
1284 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1285 (PUCHAR
)DrvParms
) == FALSE
)
1287 DPRINT("AtapiPolledRead() failed\n");
1291 /* Report on drive parameters if debug mode */
1292 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1293 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1294 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1295 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1296 DrvParms
->ConfigBits
,
1297 DrvParms
->LogicalCyls
,
1298 DrvParms
->LogicalHeads
,
1299 DrvParms
->SectorsPerTrack
,
1300 DrvParms
->InterSectorGap
,
1301 DrvParms
->InterSectorGapSize
);
1302 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1303 DrvParms
->BytesInPLO
,
1304 DrvParms
->VendorUniqueCnt
,
1305 DrvParms
->SerialNumber
);
1306 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1307 DrvParms
->ControllerType
,
1308 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1309 DrvParms
->ECCByteCnt
,
1310 DrvParms
->FirmwareRev
);
1311 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1312 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1313 (DrvParms
->RWMultImplemented
),
1314 (DrvParms
->RWMultCurrent
) & 0xff,
1315 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1316 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1317 DrvParms
->MinPIOTransTime
,
1318 DrvParms
->MinDMATransTime
);
1319 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1320 DrvParms
->TMCylinders
,
1322 DrvParms
->TMSectorsPerTrk
,
1323 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1324 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1325 DrvParms
->TMSectorCountHi
,
1326 DrvParms
->TMSectorCountLo
,
1327 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1328 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms
->SupportedFeatures83
, DrvParms
->EnabledFeatures86
);
1329 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG
)DrvParms
->Max48BitAddress
);
1330 if (DrvParms
->TMFieldsValid
& 0x0004)
1332 if ((DrvParms
->UltraDmaModes
>> 8) && (DrvParms
->UltraDmaModes
& 0xff))
1335 while (!(DrvParms
->UltraDmaModes
& (0x0100 << mode
)))
1339 DPRINT("Ultra DMA mode %d is selected\n", mode
);
1341 else if ((DrvParms
->MultiDmaModes
>> 8) & (DrvParms
->MultiDmaModes
& 0x07))
1344 while(!(DrvParms
->MultiDmaModes
& (0x01 << mode
)))
1348 DPRINT("Multi DMA mode %d is selected\n", mode
);
1352 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1354 /* LBA ATA drives always have a sector size of 512 */
1355 DrvParms
->BytesPerSector
= 512;
1359 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1360 if (DrvParms
->BytesPerSector
== 0)
1362 DrvParms
->BytesPerSector
= 512;
1366 for (i
= 15; i
>= 0; i
--)
1368 if (DrvParms
->BytesPerSector
& (1 << i
))
1370 DrvParms
->BytesPerSector
= 1 << i
;
1376 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1385 // Read a sector of data from the drive in a polled fashion.
1391 // IN ULONG CommandPort Address of command port for drive
1392 // IN ULONG ControlPort Address of control port for drive
1393 // IN UCHAR PreComp Value to write to precomp register
1394 // IN UCHAR SectorCnt Value to write to sectorCnt register
1395 // IN UCHAR SectorNum Value to write to sectorNum register
1396 // IN UCHAR CylinderLow Value to write to CylinderLow register
1397 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1398 // IN UCHAR DrvHead Value to write to Drive/Head register
1399 // IN UCHAR Command Value to write to Command register
1400 // OUT PUCHAR Buffer Buffer for output data
1403 // BOOLEAN: TRUE success, FALSE error
1407 AtapiPolledRead(IN ULONG CommandPort
,
1408 IN ULONG ControlPort
,
1412 IN UCHAR CylinderLow
,
1413 IN UCHAR CylinderHigh
,
1418 ULONG SectorCount
= 0;
1420 BOOLEAN Junk
= FALSE
;
1423 /* Wait for BUSY to clear */
1424 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1426 Status
= IDEReadStatus(CommandPort
);
1427 if (!(Status
& IDE_SR_BUSY
))
1431 ScsiPortStallExecution(10);
1433 DPRINT("status=%02x\n", Status
);
1434 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1435 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1437 DPRINT("Drive is BUSY for too long\n");
1441 /* Write Drive/Head to select drive */
1442 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1443 ScsiPortStallExecution(500);
1445 /* Disable interrupts */
1446 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1447 ScsiPortStallExecution(500);
1450 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1451 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1453 Status
= IDEReadStatus(CommandPort
);
1454 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1458 ScsiPortStallExecution(10);
1460 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1466 /* Issue command to drive */
1467 if (DrvHead
& IDE_DH_LBA
)
1469 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1470 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1471 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1477 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1478 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1487 /* Setup command parameters */
1488 IDEWritePrecomp(CommandPort
, PreComp
);
1489 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1490 IDEWriteSectorNum(CommandPort
, SectorNum
);
1491 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1492 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1493 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1495 /* Issue the command */
1496 IDEWriteCommand(CommandPort
, Command
);
1497 ScsiPortStallExecution(50);
1499 /* wait for DRQ or error */
1500 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1502 Status
= IDEReadStatus(CommandPort
);
1503 if (!(Status
& IDE_SR_BUSY
))
1505 if (Status
& IDE_SR_ERR
)
1507 IDEWriteDriveControl(ControlPort
, 0);
1508 ScsiPortStallExecution(50);
1509 IDEReadStatus(CommandPort
);
1514 if (Status
& IDE_SR_DRQ
)
1520 IDEWriteDriveControl(ControlPort
, 0);
1521 ScsiPortStallExecution(50);
1522 IDEReadStatus(CommandPort
);
1527 ScsiPortStallExecution(10);
1531 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1533 IDEWriteDriveControl(ControlPort
, 0);
1534 ScsiPortStallExecution(50);
1535 IDEReadStatus(CommandPort
);
1542 /* Read data into buffer */
1545 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1546 Buffer
+= IDE_SECTOR_BUF_SZ
;
1550 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1551 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1555 /* Check for error or more sectors to read */
1556 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1558 Status
= IDEReadStatus(CommandPort
);
1559 if (!(Status
& IDE_SR_BUSY
))
1561 if (Status
& IDE_SR_ERR
)
1563 IDEWriteDriveControl(ControlPort
, 0);
1564 ScsiPortStallExecution(50);
1565 IDEReadStatus(CommandPort
);
1569 if (Status
& IDE_SR_DRQ
)
1571 if (SectorCount
>= SectorCnt
)
1573 DPRINT("Buffer size exceeded!\n");
1580 if (SectorCount
> SectorCnt
)
1582 DPRINT("Read %lu sectors of junk!\n",
1583 SectorCount
- SectorCnt
);
1585 IDEWriteDriveControl(ControlPort
, 0);
1586 ScsiPortStallExecution(50);
1587 IDEReadStatus(CommandPort
);
1597 // ------------------------------------------- Nondiscardable statics
1600 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1601 IN PSCSI_REQUEST_BLOCK Srb
)
1603 UCHAR ByteCountHigh
;
1609 DPRINT("AtapiSendAtapiCommand() called!\n");
1611 if (Srb
->PathId
!= 0)
1613 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1614 return(SRB_STATUS_INVALID_PATH_ID
);
1617 if (Srb
->TargetId
> 1)
1619 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1620 return(SRB_STATUS_INVALID_TARGET_ID
);
1625 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1626 return(SRB_STATUS_INVALID_LUN
);
1629 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1631 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1632 return(SRB_STATUS_NO_DEVICE
);
1635 if (Srb
->Cdb
[0] == SCSIOP_MODE_SENSE
)
1637 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1638 return (SRB_STATUS_INVALID_REQUEST
);
1641 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1644 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1645 return(AtapiInquiry(DeviceExtension
,
1648 /* Set pointer to data buffer. */
1649 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1650 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1651 DeviceExtension
->CurrentSrb
= Srb
;
1653 DPRINT("BufferAddress %x, BufferLength %d\n", Srb
->DataBuffer
, Srb
->DataTransferLength
);
1655 /* Wait for BUSY to clear */
1656 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1658 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1659 if (!(Status
& IDE_SR_BUSY
))
1663 ScsiPortStallExecution(10);
1665 DPRINT("status=%02x\n", Status
);
1666 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1667 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1669 DPRINT("Drive is BUSY for too long\n");
1670 return(SRB_STATUS_BUSY
);
1673 /* Select the desired drive */
1674 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1675 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1677 /* Wait a little while */
1678 ScsiPortStallExecution(50);
1681 /* Wait for BUSY to clear and DRDY to assert */
1682 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1684 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1685 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1689 ScsiPortStallExecution(10);
1691 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1692 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1694 DPRINT("Drive is BUSY for too long after drive select\n");
1695 return(SRB_STATUS_BUSY
);
1700 if ((DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
) &&
1701 (Srb
->Cdb
[0] == SCSIOP_READ
|| Srb
->Cdb
[0] == SCSIOP_WRITE
))
1703 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
1707 DeviceExtension
->UseDma
= FALSE
;
1711 if (DeviceExtension
->DataTransferLength
< 0x10000)
1713 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1714 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1718 ByteCountLow
= 0xFF;
1719 ByteCountHigh
= 0xFF;
1722 /* Set feature register */
1724 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, DeviceExtension
->UseDma
? 1 : 0);
1726 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1729 /* Set command packet length */
1730 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1731 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1733 /* Issue command to drive */
1735 if (DeviceExtension
->UseDma
)
1737 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiDmaPacketInterrupt
);
1742 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiPacketInterrupt
);
1745 /* Wait for DRQ to assert */
1746 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1748 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1749 if ((Status
& IDE_SR_DRQ
))
1753 ScsiPortStallExecution(10);
1756 /* Convert special SCSI SRBs to ATAPI format */
1757 switch (Srb
->Cdb
[0])
1759 case SCSIOP_FORMAT_UNIT
:
1760 case SCSIOP_MODE_SELECT
:
1761 AtapiScsiSrbToAtapi (Srb
);
1765 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
1766 DPRINT("CdbSize: %lu\n", CdbSize
);
1768 /* Write command packet */
1769 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1774 if (DeviceExtension
->UseDma
)
1778 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
1779 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
1782 DPRINT("AtapiSendAtapiCommand() done\n");
1784 return(SRB_STATUS_PENDING
);
1789 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1790 IN PSCSI_REQUEST_BLOCK Srb
)
1792 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1794 DPRINT("AtapiSendIdeCommand() called!\n");
1796 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1801 if (Srb
->PathId
!= 0)
1803 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1804 return(SRB_STATUS_INVALID_PATH_ID
);
1807 if (Srb
->TargetId
> 1)
1809 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1810 return(SRB_STATUS_INVALID_TARGET_ID
);
1815 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1816 return(SRB_STATUS_INVALID_LUN
);
1819 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1821 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1822 return(SRB_STATUS_NO_DEVICE
);
1825 switch (Srb
->Cdb
[0])
1827 case SCSIOP_INQUIRY
:
1828 SrbStatus
= AtapiInquiry(DeviceExtension
,
1832 case SCSIOP_READ_CAPACITY
:
1833 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1839 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1843 case SCSIOP_SYNCHRONIZE_CACHE
:
1844 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1848 case SCSIOP_TEST_UNIT_READY
:
1849 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1853 case SCSIOP_MODE_SENSE
:
1856 case SCSIOP_START_STOP_UNIT
:
1857 case SCSIOP_REQUEST_SENSE
:
1861 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1863 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1867 DPRINT("AtapiSendIdeCommand() done!\n");
1874 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1875 PSCSI_REQUEST_BLOCK Srb
)
1877 PIDE_DRIVE_IDENTIFY DeviceParams
;
1878 PINQUIRYDATA InquiryData
;
1881 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1882 DeviceExtension
, Srb
->TargetId
);
1884 InquiryData
= Srb
->DataBuffer
;
1885 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1888 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1890 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1893 /* set device class */
1894 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1896 /* get it from the ATAPI configuration word */
1897 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1898 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1900 /* Don't flush CD/DVD drives */
1901 if (InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)
1903 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] |= DEVICE_NO_FLUSH
;
1909 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1912 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1913 if (DeviceParams
->ConfigBits
& 0x80)
1915 DPRINT("Removable media!\n");
1916 InquiryData
->RemovableMedia
= 1;
1919 for (i
= 0; i
< 20; i
+= 2)
1921 InquiryData
->VendorId
[i
] =
1922 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1923 InquiryData
->VendorId
[i
+1] =
1924 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1927 for (i
= 0; i
< 4; i
++)
1929 InquiryData
->ProductId
[12+i
] = ' ';
1932 for (i
= 0; i
< 4; i
+= 2)
1934 InquiryData
->ProductRevisionLevel
[i
] =
1935 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1936 InquiryData
->ProductRevisionLevel
[i
+1] =
1937 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1940 InquiryData
->AdditionalLength
= 31;
1942 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1944 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1945 return(SRB_STATUS_SUCCESS
);
1950 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1951 PSCSI_REQUEST_BLOCK Srb
)
1953 PREAD_CAPACITY_DATA CapacityData
;
1954 PIDE_DRIVE_IDENTIFY DeviceParams
;
1955 LARGE_INTEGER LastSector
;
1957 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1958 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1959 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1961 /* Set sector (block) size to 512 bytes (big-endian). */
1962 CapacityData
->BytesPerBlock
= 0x20000;
1964 /* Calculate last sector (big-endian). */
1965 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1967 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
1969 ((PUSHORT
)&LastSector
)[0] = DeviceParams
->Max48BitAddress
[0];
1970 ((PUSHORT
)&LastSector
)[1] = DeviceParams
->Max48BitAddress
[1];
1971 ((PUSHORT
)&LastSector
)[2] = DeviceParams
->Max48BitAddress
[2];
1972 ((PUSHORT
)&LastSector
)[3] = DeviceParams
->Max48BitAddress
[3];
1973 LastSector
.QuadPart
-= 1;
1978 LastSector
.u
.HighPart
= 0;
1979 LastSector
.u
.LowPart
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1980 DeviceParams
->TMSectorCountLo
)-1;
1985 LastSector
.u
.HighPart
= 0;
1986 LastSector
.u
.LowPart
= (ULONG
)(DeviceParams
->LogicalCyls
*
1987 DeviceParams
->LogicalHeads
*
1988 DeviceParams
->SectorsPerTrack
)-1;
1990 if (LastSector
.u
.HighPart
)
1992 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector
.QuadPart
);
1996 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1997 (((PUCHAR
)&LastSector
)[1] << 16) |
1998 (((PUCHAR
)&LastSector
)[2] << 8) |
1999 ((PUCHAR
)&LastSector
)[3];
2001 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2004 CapacityData
->LogicalBlockAddress
);
2006 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2007 return(SRB_STATUS_SUCCESS
);
2012 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2013 PSCSI_REQUEST_BLOCK Srb
)
2015 PIDE_DRIVE_IDENTIFY DeviceParams
;
2016 ULONG StartingSector
;
2018 UCHAR CylinderHigh
[2];
2019 UCHAR CylinderLow
[2];
2021 UCHAR SectorNumber
[2];
2025 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION DevExt
);
2027 DPRINT("AtapiReadWrite() called!\n");
2028 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2031 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2033 /* Get starting sector number from CDB. */
2034 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2035 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2036 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2037 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2039 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2040 DeviceParams
->BytesPerSector
;
2042 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2044 Srb
->DataTransferLength
,
2047 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2049 SectorNumber
[0] = StartingSector
& 0xff;
2050 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2051 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2052 SectorNumber
[1] = (StartingSector
>> 24) & 0xff;
2054 CylinderHigh
[1] = 0;
2055 DrvHead
= (Srb
->TargetId
? IDE_DH_DRV1
: 0) | IDE_DH_LBA
;
2057 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2058 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2059 DeviceExtension
->CommandPortBase
,
2060 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2061 (SectorNumber
[1] << 24) +
2062 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + DectorNumberLow
[0],
2067 else if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2069 SectorNumber
[0] = StartingSector
& 0xff;
2070 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2071 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2072 SectorNumber
[1] = 0;
2074 CylinderHigh
[1] = 0;
2075 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2076 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2079 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2080 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2081 DeviceExtension
->CommandPortBase
,
2082 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2083 ((DrvHead
& 0x0f) << 24) +
2084 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + SectorNumber
[0],
2090 SectorNumber
[0] = (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2091 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2092 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2093 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2094 StartingSector
/= DeviceParams
->LogicalHeads
;
2095 CylinderLow
[0] = StartingSector
& 0xff;
2096 CylinderHigh
[0] = StartingSector
>> 8;
2097 SectorNumber
[1] = 0;
2099 CylinderHigh
[1] = 0;
2101 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2102 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2103 DeviceExtension
->CommandPortBase
,
2104 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2113 /* Set pointer to data buffer. */
2114 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2115 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2117 DeviceExtension
->CurrentSrb
= Srb
;
2119 /* wait for BUSY to clear */
2120 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2122 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2123 if (!(Status
& IDE_SR_BUSY
))
2127 ScsiPortStallExecution(10);
2129 DPRINT("status=%02x\n", Status
);
2130 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2131 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2133 DPRINT ("Drive is BUSY for too long\n");
2134 return(SRB_STATUS_BUSY
);
2137 /* Select the desired drive */
2138 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2139 IDE_DH_FIXED
| DrvHead
);
2141 ScsiPortStallExecution(10);
2143 /* wait for BUSY to clear and DRDY to assert */
2144 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2146 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2147 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2151 ScsiPortStallExecution(10);
2153 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2154 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2156 DPRINT("Drive is BUSY for too long after drive select\n");
2157 return(SRB_STATUS_BUSY
);
2161 /* Setup command parameters */
2162 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2164 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2165 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
>> 8);
2166 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[1]);
2167 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[1]);
2168 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[1]);
2171 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2172 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
& 0xff);
2173 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[0]);
2174 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[0]);
2175 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[0]);
2177 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2180 if (DeviceExtension
->PRDTable
&&
2181 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
)
2183 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2185 if (DeviceExtension
->UseDma
)
2187 Handler
= AtapiDmaInterrupt
;
2188 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2190 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA_EXT
: IDE_CMD_WRITE_DMA_EXT
;
2194 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA
: IDE_CMD_WRITE_DMA
;
2200 Handler
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? AtapiReadInterrupt
: AtapiWriteInterrupt
;
2201 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
)
2203 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2205 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE_EXT
: IDE_CMD_WRITE_MULTIPLE_EXT
;
2209 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE
: IDE_CMD_WRITE_MULTIPLE
;
2214 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2216 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_EXT
: IDE_CMD_WRITE_EXT
;
2220 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ
: IDE_CMD_WRITE
;
2225 AtapiExecuteCommand(DeviceExtension
, Command
, Handler
);
2228 if (DeviceExtension
->UseDma
)
2232 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2233 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2238 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2240 /* Write data block */
2241 PUCHAR TargetAddress
;
2244 /* Wait for controller ready */
2245 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2247 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2248 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2252 ScsiPortStallExecution(10);
2254 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2256 DPRINT1("Drive is BUSY for too long after sending write command\n");
2257 return(SRB_STATUS_BUSY
);
2260 /* Update DeviceExtension data */
2261 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2262 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2264 TransferSize
= DeviceExtension
->DataTransferLength
;
2267 TargetAddress
= DeviceExtension
->DataBuffer
;
2268 DeviceExtension
->DataBuffer
+= TransferSize
;
2269 DeviceExtension
->DataTransferLength
-= TransferSize
;
2271 /* Write data block */
2272 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2274 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2280 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2287 DPRINT("AtapiReadWrite() done!\n");
2289 /* Wait for interrupt. */
2290 return(SRB_STATUS_PENDING
);
2295 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2296 PSCSI_REQUEST_BLOCK Srb
)
2301 DPRINT("AtapiFlushCache() called!\n");
2302 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2305 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_NO_FLUSH
)
2308 * NOTE: Don't flush the cache for CD/DVD drives. Although
2309 * the ATAPI-6 standard allows that, it has been experimentally
2310 * proved that it can damage some broken LG drives. Afterall
2311 * it doesn't make sense to flush cache on devices we don't
2314 return SRB_STATUS_INVALID_REQUEST
;
2317 if (!(DeviceExtension
->DeviceParams
[Srb
->TargetId
].SupportedFeatures83
& 0x1000))
2319 /* The device states it doesn't support the command */
2320 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2321 return SRB_STATUS_INVALID_REQUEST
;
2324 /* Wait for BUSY to clear */
2325 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2327 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2328 if (!(Status
& IDE_SR_BUSY
))
2332 ScsiPortStallExecution(10);
2334 DPRINT("Status=%02x\n", Status
);
2335 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2336 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2338 DPRINT1("Drive is BUSY for too long\n");
2339 return(SRB_STATUS_BUSY
);
2342 /* Select the desired drive */
2343 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2344 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2345 ScsiPortStallExecution(10);
2347 /* Issue command to drive */
2348 AtapiExecuteCommand(DeviceExtension
,
2349 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
? IDE_CMD_FLUSH_CACHE_EXT
: IDE_CMD_FLUSH_CACHE
,
2350 AtapiNoDataInterrupt
);
2353 DPRINT("AtapiFlushCache() done!\n");
2355 /* Wait for interrupt. */
2356 return(SRB_STATUS_PENDING
);
2361 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2362 PSCSI_REQUEST_BLOCK Srb
)
2368 DPRINT1("AtapiTestUnitReady() called!\n");
2370 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2373 /* Return success if media status is not supported */
2374 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2376 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2377 return(SRB_STATUS_SUCCESS
);
2380 /* Wait for BUSY to clear */
2381 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2383 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2384 if (!(Status
& IDE_SR_BUSY
))
2388 ScsiPortStallExecution(10);
2390 DPRINT1("Status=%02x\n", Status
);
2391 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2392 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2394 DPRINT1("Drive is BUSY for too long\n");
2395 return(SRB_STATUS_BUSY
);
2398 /* Select the desired drive */
2399 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2400 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2401 ScsiPortStallExecution(10);
2403 /* Issue command to drive */
2404 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2406 /* Wait for controller ready */
2407 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2409 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2410 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2414 ScsiPortStallExecution(10);
2416 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2418 DPRINT1("Drive is BUSY for too long after sending write command\n");
2419 DeviceExtension
->Handler
= NULL
;
2420 return(SRB_STATUS_BUSY
);
2423 if (Status
& IDE_SR_ERR
)
2425 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2426 if (Error
== IDE_ER_UNC
)
2429 /* Handle write protection 'error' */
2430 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2431 DeviceExtension
->Handler
= NULL
;
2432 return(SRB_STATUS_SUCCESS
);
2437 /* Indicate expecting an interrupt. */
2438 return(SRB_STATUS_PENDING
);
2442 DeviceExtension
->Handler
= NULL
;
2444 DPRINT1("AtapiTestUnitReady() done!\n");
2446 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2447 return(SRB_STATUS_SUCCESS
);
2452 AtapiErrorToScsi(PVOID DeviceExtension
,
2453 PSCSI_REQUEST_BLOCK Srb
)
2455 PATAPI_MINIPORT_EXTENSION DevExt
;
2456 ULONG CommandPortBase
;
2457 ULONG ControlPortBase
;
2462 DPRINT("AtapiErrorToScsi() called\n");
2464 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2466 CommandPortBase
= DevExt
->CommandPortBase
;
2467 ControlPortBase
= DevExt
->ControlPortBase
;
2469 ErrorReg
= IDEReadError(CommandPortBase
);
2471 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2473 switch (ErrorReg
>> 4)
2475 case SCSI_SENSE_NO_SENSE
:
2476 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2477 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2478 SrbStatus
= SRB_STATUS_ERROR
;
2481 case SCSI_SENSE_RECOVERED_ERROR
:
2482 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2484 SrbStatus
= SRB_STATUS_SUCCESS
;
2487 case SCSI_SENSE_NOT_READY
:
2488 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2489 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2490 SrbStatus
= SRB_STATUS_ERROR
;
2493 case SCSI_SENSE_MEDIUM_ERROR
:
2494 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2495 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2496 SrbStatus
= SRB_STATUS_ERROR
;
2499 case SCSI_SENSE_HARDWARE_ERROR
:
2500 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2501 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2502 SrbStatus
= SRB_STATUS_ERROR
;
2505 case SCSI_SENSE_ILLEGAL_REQUEST
:
2506 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2507 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2508 SrbStatus
= SRB_STATUS_ERROR
;
2511 case SCSI_SENSE_UNIT_ATTENTION
:
2512 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2513 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2514 SrbStatus
= SRB_STATUS_ERROR
;
2517 case SCSI_SENSE_DATA_PROTECT
:
2518 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2519 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2520 SrbStatus
= SRB_STATUS_ERROR
;
2523 case SCSI_SENSE_BLANK_CHECK
:
2524 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2525 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2526 SrbStatus
= SRB_STATUS_ERROR
;
2529 case SCSI_SENSE_ABORTED_COMMAND
:
2530 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2531 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2532 SrbStatus
= SRB_STATUS_ERROR
;
2536 DPRINT("ATAPI error: Invalid sense key\n");
2538 SrbStatus
= SRB_STATUS_ERROR
;
2544 DPRINT1("IDE error: %02x\n", ErrorReg
);
2547 SrbStatus
= SRB_STATUS_ERROR
;
2550 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2553 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2554 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2555 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2556 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2557 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2559 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2570 Srb
->ScsiStatus
= ScsiStatus
;
2572 DPRINT("AtapiErrorToScsi() done\n");
2579 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2581 DPRINT("AtapiConvertScsiToAtapi() called\n");
2583 Srb
->CdbLength
= 12;
2585 switch (Srb
->Cdb
[0])
2587 case SCSIOP_FORMAT_UNIT
:
2588 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2591 case SCSIOP_MODE_SELECT
:
2593 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2596 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2597 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2599 RtlZeroMemory (Srb
->Cdb
,
2601 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2602 AtapiModeSelect
->PFBit
= 1;
2603 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2604 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2610 static VOID FASTCALL
2611 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2614 PSCSI_REQUEST_BLOCK Srb
;
2615 Srb
= DevExt
->CurrentSrb
;
2617 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2619 Srb
->SrbStatus
= SrbStatus
;
2620 if (SrbStatus
== SRB_STATUS_ERROR
)
2622 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2624 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2626 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2629 DevExt
->Handler
= NULL
;
2630 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2631 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2635 static BOOLEAN FASTCALL
2636 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2645 DPRINT("AtapiPacketDmaInterrupt\n");
2647 DevExt
->UseDma
= FALSE
;
2650 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2651 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2652 /* get DMA status */
2653 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2654 /* clear the INTR & ERROR bits */
2655 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2657 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2658 DPRINT("DriveStatus: %x\n", Status
);
2660 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2662 if (Status
& IDE_SR_ERR
)
2664 Error
= IDEReadError(DevExt
->CommandPortBase
);
2665 SensKey
= Error
>> 4;
2666 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2668 SrbStatus
= SRB_STATUS_ERROR
;
2672 if ((DmaStatus
& 0x07) != 0x04)
2674 DPRINT("DmaStatus: %02x\n", DmaStatus
);
2675 SrbStatus
= SRB_STATUS_ERROR
;
2679 SrbStatus
= STATUS_SUCCESS
;
2682 AtapiCompleteRequest(DevExt
, SrbStatus
);
2683 DPRINT("AtapiDmaPacketInterrupt() done\n");
2688 static BOOLEAN FASTCALL
2689 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2691 PSCSI_REQUEST_BLOCK Srb
;
2697 PBYTE TargetAddress
;
2703 DPRINT("AtapiPacketInterrupt()\n");
2705 Srb
= DevExt
->CurrentSrb
;
2707 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2708 DPRINT("DriveStatus: %x\n", Status
);
2710 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2712 if (Status
& IDE_SR_ERR
)
2714 Error
= IDEReadError(DevExt
->CommandPortBase
);
2715 SensKey
= Error
>> 4;
2716 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2719 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2720 DPRINT("AtapiPacketInterrupt() done\n");
2724 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
2725 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
2726 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
2728 if (!(Status
& IDE_SR_DRQ
))
2730 if (DevExt
->DataTransferLength
> 0)
2732 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2733 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
2734 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
2738 SrbStatus
= SRB_STATUS_SUCCESS
;
2740 AtapiCompleteRequest(DevExt
, SrbStatus
);
2741 DPRINT("AtapiPacketInterrupt() done\n");
2745 TargetAddress
= DevExt
->DataBuffer
;
2747 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2749 DPRINT("read data\n");
2750 if (DevExt
->DataTransferLength
<= TransferSize
)
2752 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
2753 TransferSize
= DevExt
->DataTransferLength
;
2755 DevExt
->DataTransferLength
= 0;
2760 DevExt
->DataTransferLength
-= TransferSize
;
2761 IsLastBlock
= FALSE
;
2764 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
2766 DevExt
->DataBuffer
+= TransferSize
;
2768 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2773 /* Read remaining junk from device */
2774 while (JunkSize
> 0)
2776 IDEReadWord(DevExt
->CommandPortBase
);
2780 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
2782 ScsiPortStallExecution(10);
2785 /* Check for data overrun */
2786 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
2788 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2789 IDEReadWord(DevExt
->CommandPortBase
);
2793 SrbStatus
= SRB_STATUS_SUCCESS
;
2795 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2797 DPRINT("write data\n");
2798 if (DevExt
->DataTransferLength
< TransferSize
)
2800 TransferSize
= DevExt
->DataTransferLength
;
2803 TargetAddress
= DevExt
->DataBuffer
;
2805 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
2807 DevExt
->DataBuffer
+= TransferSize
;
2808 DevExt
->DataTransferLength
-= TransferSize
;
2810 /* Write the sector */
2811 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2812 SrbStatus
= SRB_STATUS_SUCCESS
;
2813 IsLastBlock
= FALSE
;
2817 DPRINT("Unspecified transfer direction!\n");
2818 SrbStatus
= SRB_STATUS_SUCCESS
;
2823 AtapiCompleteRequest(DevExt
, SrbStatus
);
2825 DPRINT("AtapiPacketInterrupt() done\n");
2829 static BOOLEAN FASTCALL
2830 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2834 DPRINT("AtapiNoDataInterrupt()\n");
2836 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2837 AtapiCompleteRequest(DevExt
,
2838 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
2840 DPRINT("AtapiNoDatanterrupt() done!\n");
2845 static BOOLEAN FASTCALL
2846 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2852 DPRINT("AtapiDmaInterrupt()\n");
2854 DevExt
->UseDma
= FALSE
;
2856 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2857 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2858 /* get DMA status */
2859 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2860 /* clear the INTR & ERROR bits */
2861 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2863 /* read the drive status */
2864 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2865 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
2866 (DmaStatus
& 0x07) == 4)
2868 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2869 DPRINT("AtapiDmaInterrupt() done\n");
2872 DPRINT1("Status %x\n", Status
);
2873 DPRINT1("%x\n", DmaStatus
);
2874 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2875 DPRINT1("AtapiDmaReadInterrupt() done\n");
2880 static BOOLEAN FASTCALL
2881 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2883 PSCSI_REQUEST_BLOCK Srb
;
2885 BOOLEAN IsLastBlock
;
2886 PUCHAR TargetAddress
;
2889 DPRINT("AtapiReadInterrupt() called!\n");
2891 Srb
= DevExt
->CurrentSrb
;
2893 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2894 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
2896 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
2898 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2899 DPRINT("AtapiReadInterrupt() done!\n");
2902 DPRINT("AtapiReadInterrupt() done!\n");
2906 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
2908 /* Update controller/device state variables */
2909 TargetAddress
= DevExt
->DataBuffer
;
2910 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2912 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2913 DPRINT("TransferSize: %lu\n", TransferSize
);
2915 if (DevExt
->DataTransferLength
<= TransferSize
)
2917 TransferSize
= DevExt
->DataTransferLength
;
2918 DevExt
->DataTransferLength
= 0;
2923 DevExt
->DataTransferLength
-= TransferSize
;
2924 IsLastBlock
= FALSE
;
2926 DevExt
->DataBuffer
+= TransferSize
;
2927 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
2929 /* Copy the block of data */
2930 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2932 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2936 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2941 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2944 DPRINT("AtapiReadInterrupt() done!\n");
2949 static BOOLEAN FASTCALL
2950 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
2952 PSCSI_REQUEST_BLOCK Srb
;
2954 BOOLEAN IsLastBlock
;
2955 PUCHAR TargetAddress
;
2958 DPRINT("AtapiWriteInterrupt() called!\n");
2960 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2961 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
2963 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
2965 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2966 DPRINT("AtapiWriteInterrupt() done!\n");
2969 DPRINT("AtapiWriteInterrupt() done!\n");
2974 Srb
= DevExt
->CurrentSrb
;
2975 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2976 if (DevExt
->DataTransferLength
< TransferSize
)
2978 TransferSize
= DevExt
->DataTransferLength
;
2980 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
2982 IsLastBlock
= FALSE
;
2983 TargetAddress
= DevExt
->DataBuffer
;
2984 DevExt
->DataBuffer
+= TransferSize
;
2985 DevExt
->DataTransferLength
-= TransferSize
;
2987 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2988 DPRINT("TransferSize: %lu\n", TransferSize
);
2989 /* Write the sector */
2990 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2992 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2996 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2999 else if (DeviceStatus
& IDE_SR_DRQ
)
3001 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3004 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
3006 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
3015 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3017 DPRINT("AtapiWriteInterrupt() done!\n");
3023 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
3025 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
3027 if (DevExt
->Handler
!= NULL
)
3029 DPRINT1("DevExt->Handler is already set!!\n");
3031 DevExt
->Handler
= Handler
;
3032 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
3033 ScsiPortStallExecution(1);
3038 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
3039 PSCSI_REQUEST_BLOCK Srb
,
3044 PPRD PRDEntry
= DevExt
->PRDTable
;
3045 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
3050 DPRINT("AtapiInitDma()\n");
3052 StartAddress
= Srb
->DataBuffer
;
3053 EndAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ Srb
->DataTransferLength
);
3054 DevExt
->PRDCount
= 0;
3056 while (StartAddress
< EndAddress
)
3058 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
3059 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
3066 /* calculate the length up to the next 64k boundary */
3067 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
3068 if (tmpLength
> Length
)
3073 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3077 if (tmpLength
== 0x10000)
3079 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3081 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3082 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3083 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3084 PRDEntry
->Length
= tmpLength
;
3087 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3091 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3092 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3093 Length
-= tmpLength
;
3094 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3096 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3097 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3098 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3099 PRDEntry
->Length
= tmpLength
;
3101 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3102 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3103 Length
-= tmpLength
;
3106 /* set the end marker in the last PRD */
3108 PRDEntry
->Length
|= 0x80000000;
3109 /* set the PDR table */
3110 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3111 /* write the DMA command */
3112 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3113 /* reset the status and interrupt bit */
3114 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3115 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);