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
;
950 Srb
->SrbStatus
= (UCHAR
)Result
;
952 ScsiPortNotification(RequestComplete
,
955 ScsiPortNotification(NextRequest
,
961 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
964 DPRINT("AtapiStartIo() done\n");
969 static BOOLEAN STDCALL
970 AtapiInterrupt(IN PVOID DeviceExtension
)
972 PATAPI_MINIPORT_EXTENSION DevExt
;
974 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
976 if (DevExt
->Handler
== NULL
)
978 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
979 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) != IDE_SR_DRDY
)
981 static ULONG Count
= 0;
983 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
984 DevExt
->CommandPortBase
, Status
, Count
);
991 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
992 if (!(Status
& 0x04))
1000 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1001 if (Status
& IDE_SR_BUSY
)
1006 return DevExt
->Handler(DevExt
);
1009 // ---------------------------------------------------- Discardable statics
1013 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension
, ULONG UnitNumber
)
1015 BOOLEAN Result
= FALSE
;
1020 if (DeviceExtension
->PRDTable
)
1022 if (DeviceExtension
->DeviceParams
[UnitNumber
].Capabilities
& IDE_DRID_DMA_SUPPORTED
)
1024 if ((DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0004) &&
1025 (DeviceExtension
->DeviceParams
[UnitNumber
].UltraDmaModes
& 0x7F00))
1029 else if (DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0002)
1031 if ((DeviceExtension
->DeviceParams
[UnitNumber
].MultiDmaModes
& 0x0404) == 0x0404)
1037 * should we support single mode dma ?
1039 else if ((DeviceExtension
->DeviceParams
[UnitNumber
].DmaModes
& 0x0404) == 0x0404)
1045 Status
= IDEReadDMAStatus(DeviceExtension
->BusMasterRegisterBase
);
1048 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
| (UnitNumber
? 0x40 : 0x20));
1052 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
& (UnitNumber
? ~0x40 : ~0x20));
1061 /**********************************************************************
1066 * Searches for devices on the given port.
1073 * Port device specific information.
1076 * Port configuration information.
1079 * TRUE: At least one device is attached to the port.
1080 * FALSE: No device is attached to the port.
1084 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1085 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1087 BOOLEAN DeviceFound
= FALSE
;
1088 ULONG CommandPortBase
;
1089 ULONG ControlPortBase
;
1095 DPRINT("AtapiFindDevices() called\n");
1097 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
);
1098 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1100 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[1].RangeStart
);
1101 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1103 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1106 IDEWriteDriveHead(CommandPortBase
,
1107 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1108 ScsiPortStallExecution(500);
1110 /* Disable interrupts */
1111 IDEWriteDriveControl(ControlPortBase
,
1113 ScsiPortStallExecution(500);
1115 /* Check if a device is attached to the interface */
1116 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1117 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1119 High
= IDEReadCylinderHigh(CommandPortBase
);
1120 Low
= IDEReadCylinderLow(CommandPortBase
);
1122 IDEWriteCylinderHigh(CommandPortBase
, 0);
1123 IDEWriteCylinderLow(CommandPortBase
, 0);
1125 if (Low
!= 0x55 || High
!= 0xaa)
1127 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1131 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_RESET
, NULL
);
1133 for (Retries
= 0; Retries
< 20000; Retries
++)
1135 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1139 ScsiPortStallExecution(150);
1141 if (Retries
>= 20000)
1143 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1144 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1148 High
= IDEReadCylinderHigh(CommandPortBase
);
1149 Low
= IDEReadCylinderLow(CommandPortBase
);
1151 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1156 if (High
== 0xEB && Low
== 0x14)
1158 if (AtapiIdentifyDevice(CommandPortBase
,
1162 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1164 DPRINT(" ATAPI drive found!\n");
1165 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1166 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1167 DeviceExtension
->TransferSize
[UnitNumber
] =
1168 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1170 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1172 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1179 DPRINT(" No ATAPI drive found!\n");
1184 if (AtapiIdentifyDevice(CommandPortBase
,
1188 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1190 DPRINT(" IDE drive found!\n");
1191 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1192 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1193 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1194 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1195 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1196 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1198 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1199 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1201 if (DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x0400 &&
1202 DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x0400)
1204 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_48BIT_ADDRESS
;
1206 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1208 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1211 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1213 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1220 DPRINT(" No IDE drive found!\n");
1225 /* Reset pending interrupts */
1226 IDEReadStatus(CommandPortBase
);
1227 /* Reenable interrupts */
1228 IDEWriteDriveControl(ControlPortBase
, 0);
1229 ScsiPortStallExecution(500);
1230 /* Return with drive 0 selected */
1231 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1232 ScsiPortStallExecution(500);
1234 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1236 return(DeviceFound
);
1241 * AtapiIdentifyDevice
1244 * Get the identification block from the drive
1251 * Address of the command port
1253 * Address of the control port
1255 * The drive index (0,1)
1257 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1259 * Address to write drive ident block
1262 * TRUE: The drive identification block was retrieved successfully
1263 * FALSE: an error ocurred
1267 AtapiIdentifyDevice(IN ULONG CommandPort
,
1268 IN ULONG ControlPort
,
1271 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1276 /* Get the Drive Identify block from drive or die */
1277 if (AtapiPolledRead(CommandPort
,
1284 (DriveNum
? IDE_DH_DRV1
: 0),
1285 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1286 (PUCHAR
)DrvParms
) == FALSE
)
1288 DPRINT("AtapiPolledRead() failed\n");
1292 /* Report on drive parameters if debug mode */
1293 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1294 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1295 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1296 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1297 DrvParms
->ConfigBits
,
1298 DrvParms
->LogicalCyls
,
1299 DrvParms
->LogicalHeads
,
1300 DrvParms
->SectorsPerTrack
,
1301 DrvParms
->InterSectorGap
,
1302 DrvParms
->InterSectorGapSize
);
1303 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1304 DrvParms
->BytesInPLO
,
1305 DrvParms
->VendorUniqueCnt
,
1306 DrvParms
->SerialNumber
);
1307 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1308 DrvParms
->ControllerType
,
1309 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1310 DrvParms
->ECCByteCnt
,
1311 DrvParms
->FirmwareRev
);
1312 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1313 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1314 (DrvParms
->RWMultImplemented
),
1315 (DrvParms
->RWMultCurrent
) & 0xff,
1316 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1317 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1318 DrvParms
->MinPIOTransTime
,
1319 DrvParms
->MinDMATransTime
);
1320 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1321 DrvParms
->TMCylinders
,
1323 DrvParms
->TMSectorsPerTrk
,
1324 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1325 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1326 DrvParms
->TMSectorCountHi
,
1327 DrvParms
->TMSectorCountLo
,
1328 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1329 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms
->SupportedFeatures83
, DrvParms
->EnabledFeatures86
);
1330 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG
)DrvParms
->Max48BitAddress
);
1331 if (DrvParms
->TMFieldsValid
& 0x0004)
1333 if ((DrvParms
->UltraDmaModes
>> 8) && (DrvParms
->UltraDmaModes
& 0xff))
1336 while (!(DrvParms
->UltraDmaModes
& (0x0100 << mode
)))
1340 DPRINT("Ultra DMA mode %d is selected\n", mode
);
1342 else if ((DrvParms
->MultiDmaModes
>> 8) & (DrvParms
->MultiDmaModes
& 0x07))
1345 while(!(DrvParms
->MultiDmaModes
& (0x01 << mode
)))
1349 DPRINT("Multi DMA mode %d is selected\n", mode
);
1353 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1355 /* LBA ATA drives always have a sector size of 512 */
1356 DrvParms
->BytesPerSector
= 512;
1360 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1361 if (DrvParms
->BytesPerSector
== 0)
1363 DrvParms
->BytesPerSector
= 512;
1367 for (i
= 15; i
>= 0; i
--)
1369 if (DrvParms
->BytesPerSector
& (1 << i
))
1371 DrvParms
->BytesPerSector
= 1 << i
;
1377 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1386 // Read a sector of data from the drive in a polled fashion.
1392 // IN ULONG CommandPort Address of command port for drive
1393 // IN ULONG ControlPort Address of control port for drive
1394 // IN UCHAR PreComp Value to write to precomp register
1395 // IN UCHAR SectorCnt Value to write to sectorCnt register
1396 // IN UCHAR SectorNum Value to write to sectorNum register
1397 // IN UCHAR CylinderLow Value to write to CylinderLow register
1398 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1399 // IN UCHAR DrvHead Value to write to Drive/Head register
1400 // IN UCHAR Command Value to write to Command register
1401 // OUT PUCHAR Buffer Buffer for output data
1404 // BOOLEAN: TRUE success, FALSE error
1408 AtapiPolledRead(IN ULONG CommandPort
,
1409 IN ULONG ControlPort
,
1413 IN UCHAR CylinderLow
,
1414 IN UCHAR CylinderHigh
,
1419 ULONG SectorCount
= 0;
1421 BOOLEAN Junk
= FALSE
;
1424 /* Wait for BUSY to clear */
1425 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1427 Status
= IDEReadStatus(CommandPort
);
1428 if (!(Status
& IDE_SR_BUSY
))
1432 ScsiPortStallExecution(10);
1434 DPRINT("status=%02x\n", Status
);
1435 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1436 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1438 DPRINT("Drive is BUSY for too long\n");
1442 /* Write Drive/Head to select drive */
1443 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1444 ScsiPortStallExecution(500);
1446 /* Disable interrupts */
1447 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1448 ScsiPortStallExecution(500);
1451 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1452 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1454 Status
= IDEReadStatus(CommandPort
);
1455 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1459 ScsiPortStallExecution(10);
1461 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1467 /* Issue command to drive */
1468 if (DrvHead
& IDE_DH_LBA
)
1470 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1471 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1472 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1478 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1479 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1488 /* Setup command parameters */
1489 IDEWritePrecomp(CommandPort
, PreComp
);
1490 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1491 IDEWriteSectorNum(CommandPort
, SectorNum
);
1492 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1493 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1494 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1496 /* Issue the command */
1497 IDEWriteCommand(CommandPort
, Command
);
1498 ScsiPortStallExecution(50);
1500 /* wait for DRQ or error */
1501 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1503 Status
= IDEReadStatus(CommandPort
);
1504 if (!(Status
& IDE_SR_BUSY
))
1506 if (Status
& IDE_SR_ERR
)
1508 IDEWriteDriveControl(ControlPort
, 0);
1509 ScsiPortStallExecution(50);
1510 IDEReadStatus(CommandPort
);
1515 if (Status
& IDE_SR_DRQ
)
1521 IDEWriteDriveControl(ControlPort
, 0);
1522 ScsiPortStallExecution(50);
1523 IDEReadStatus(CommandPort
);
1528 ScsiPortStallExecution(10);
1532 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1534 IDEWriteDriveControl(ControlPort
, 0);
1535 ScsiPortStallExecution(50);
1536 IDEReadStatus(CommandPort
);
1543 /* Read data into buffer */
1546 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1547 Buffer
+= IDE_SECTOR_BUF_SZ
;
1551 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1552 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1556 /* Check for error or more sectors to read */
1557 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1559 Status
= IDEReadStatus(CommandPort
);
1560 if (!(Status
& IDE_SR_BUSY
))
1562 if (Status
& IDE_SR_ERR
)
1564 IDEWriteDriveControl(ControlPort
, 0);
1565 ScsiPortStallExecution(50);
1566 IDEReadStatus(CommandPort
);
1570 if (Status
& IDE_SR_DRQ
)
1572 if (SectorCount
>= SectorCnt
)
1574 DPRINT("Buffer size exceeded!\n");
1581 if (SectorCount
> SectorCnt
)
1583 DPRINT("Read %lu sectors of junk!\n",
1584 SectorCount
- SectorCnt
);
1586 IDEWriteDriveControl(ControlPort
, 0);
1587 ScsiPortStallExecution(50);
1588 IDEReadStatus(CommandPort
);
1598 // ------------------------------------------- Nondiscardable statics
1601 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1602 IN PSCSI_REQUEST_BLOCK Srb
)
1604 UCHAR ByteCountHigh
;
1610 DPRINT("AtapiSendAtapiCommand() called!\n");
1612 if (Srb
->PathId
!= 0)
1614 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1615 return(SRB_STATUS_INVALID_PATH_ID
);
1618 if (Srb
->TargetId
> 1)
1620 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1621 return(SRB_STATUS_INVALID_TARGET_ID
);
1626 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1627 return(SRB_STATUS_INVALID_LUN
);
1630 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1632 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1633 return(SRB_STATUS_NO_DEVICE
);
1636 if (Srb
->Cdb
[0] == SCSIOP_MODE_SENSE
)
1638 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1639 return (SRB_STATUS_INVALID_REQUEST
);
1642 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1645 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1646 return(AtapiInquiry(DeviceExtension
,
1649 /* Set pointer to data buffer. */
1650 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1651 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1652 DeviceExtension
->CurrentSrb
= Srb
;
1654 DPRINT("BufferAddress %x, BufferLength %d\n", Srb
->DataBuffer
, Srb
->DataTransferLength
);
1656 /* Wait for BUSY to clear */
1657 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1659 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1660 if (!(Status
& IDE_SR_BUSY
))
1664 ScsiPortStallExecution(10);
1666 DPRINT("status=%02x\n", Status
);
1667 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1668 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1670 DPRINT("Drive is BUSY for too long\n");
1671 return(SRB_STATUS_BUSY
);
1674 /* Select the desired drive */
1675 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1676 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1678 /* Wait a little while */
1679 ScsiPortStallExecution(50);
1682 /* Wait for BUSY to clear and DRDY to assert */
1683 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1685 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1686 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1690 ScsiPortStallExecution(10);
1692 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1693 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1695 DPRINT("Drive is BUSY for too long after drive select\n");
1696 return(SRB_STATUS_BUSY
);
1701 if ((DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
) &&
1702 (Srb
->Cdb
[0] == SCSIOP_READ
|| Srb
->Cdb
[0] == SCSIOP_WRITE
))
1704 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
1708 DeviceExtension
->UseDma
= FALSE
;
1712 if (DeviceExtension
->DataTransferLength
< 0x10000)
1714 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1715 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1719 ByteCountLow
= 0xFF;
1720 ByteCountHigh
= 0xFF;
1723 /* Set feature register */
1725 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, DeviceExtension
->UseDma
? 1 : 0);
1727 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1730 /* Set command packet length */
1731 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1732 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1734 /* Issue command to drive */
1736 if (DeviceExtension
->UseDma
)
1738 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiDmaPacketInterrupt
);
1743 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiPacketInterrupt
);
1746 /* Wait for DRQ to assert */
1747 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1749 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1750 if ((Status
& IDE_SR_DRQ
))
1754 ScsiPortStallExecution(10);
1757 /* Convert special SCSI SRBs to ATAPI format */
1758 switch (Srb
->Cdb
[0])
1760 case SCSIOP_FORMAT_UNIT
:
1761 case SCSIOP_MODE_SELECT
:
1762 AtapiScsiSrbToAtapi (Srb
);
1766 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
1767 DPRINT("CdbSize: %lu\n", CdbSize
);
1769 /* Write command packet */
1770 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1775 if (DeviceExtension
->UseDma
)
1779 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
1780 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
1783 DPRINT("AtapiSendAtapiCommand() done\n");
1785 return(SRB_STATUS_PENDING
);
1790 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1791 IN PSCSI_REQUEST_BLOCK Srb
)
1793 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1795 DPRINT("AtapiSendIdeCommand() called!\n");
1797 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1802 if (Srb
->PathId
!= 0)
1804 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1805 return(SRB_STATUS_INVALID_PATH_ID
);
1808 if (Srb
->TargetId
> 1)
1810 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1811 return(SRB_STATUS_INVALID_TARGET_ID
);
1816 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1817 return(SRB_STATUS_INVALID_LUN
);
1820 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1822 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1823 return(SRB_STATUS_NO_DEVICE
);
1826 switch (Srb
->Cdb
[0])
1828 case SCSIOP_INQUIRY
:
1829 SrbStatus
= AtapiInquiry(DeviceExtension
,
1833 case SCSIOP_READ_CAPACITY
:
1834 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1840 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1844 case SCSIOP_SYNCHRONIZE_CACHE
:
1845 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1849 case SCSIOP_TEST_UNIT_READY
:
1850 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1854 case SCSIOP_MODE_SENSE
:
1857 case SCSIOP_START_STOP_UNIT
:
1858 case SCSIOP_REQUEST_SENSE
:
1862 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1864 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1868 DPRINT("AtapiSendIdeCommand() done!\n");
1875 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1876 PSCSI_REQUEST_BLOCK Srb
)
1878 PIDE_DRIVE_IDENTIFY DeviceParams
;
1879 PINQUIRYDATA InquiryData
;
1882 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1883 DeviceExtension
, Srb
->TargetId
);
1885 InquiryData
= Srb
->DataBuffer
;
1886 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1889 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1891 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1894 /* set device class */
1895 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1897 /* get it from the ATAPI configuration word */
1898 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1899 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1901 /* Don't flush CD/DVD drives */
1902 if (InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)
1904 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] |= DEVICE_NO_FLUSH
;
1910 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1913 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1914 if (DeviceParams
->ConfigBits
& 0x80)
1916 DPRINT("Removable media!\n");
1917 InquiryData
->RemovableMedia
= 1;
1920 for (i
= 0; i
< 20; i
+= 2)
1922 InquiryData
->VendorId
[i
] =
1923 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1924 InquiryData
->VendorId
[i
+1] =
1925 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1928 for (i
= 0; i
< 4; i
++)
1930 InquiryData
->ProductId
[12+i
] = ' ';
1933 for (i
= 0; i
< 4; i
+= 2)
1935 InquiryData
->ProductRevisionLevel
[i
] =
1936 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1937 InquiryData
->ProductRevisionLevel
[i
+1] =
1938 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1941 InquiryData
->AdditionalLength
= 31;
1943 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1945 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1946 return(SRB_STATUS_SUCCESS
);
1951 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1952 PSCSI_REQUEST_BLOCK Srb
)
1954 PREAD_CAPACITY_DATA CapacityData
;
1955 PIDE_DRIVE_IDENTIFY DeviceParams
;
1956 LARGE_INTEGER LastSector
;
1958 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1959 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1960 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1962 /* Set sector (block) size to 512 bytes (big-endian). */
1963 CapacityData
->BytesPerBlock
= 0x20000;
1965 /* Calculate last sector (big-endian). */
1966 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1968 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
1970 ((PUSHORT
)&LastSector
)[0] = DeviceParams
->Max48BitAddress
[0];
1971 ((PUSHORT
)&LastSector
)[1] = DeviceParams
->Max48BitAddress
[1];
1972 ((PUSHORT
)&LastSector
)[2] = DeviceParams
->Max48BitAddress
[2];
1973 ((PUSHORT
)&LastSector
)[3] = DeviceParams
->Max48BitAddress
[3];
1974 LastSector
.QuadPart
-= 1;
1979 LastSector
.u
.HighPart
= 0;
1980 LastSector
.u
.LowPart
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1981 DeviceParams
->TMSectorCountLo
)-1;
1986 LastSector
.u
.HighPart
= 0;
1987 LastSector
.u
.LowPart
= (ULONG
)(DeviceParams
->LogicalCyls
*
1988 DeviceParams
->LogicalHeads
*
1989 DeviceParams
->SectorsPerTrack
)-1;
1991 if (LastSector
.u
.HighPart
)
1993 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector
.QuadPart
);
1997 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1998 (((PUCHAR
)&LastSector
)[1] << 16) |
1999 (((PUCHAR
)&LastSector
)[2] << 8) |
2000 ((PUCHAR
)&LastSector
)[3];
2002 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2005 CapacityData
->LogicalBlockAddress
);
2007 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2008 return(SRB_STATUS_SUCCESS
);
2013 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2014 PSCSI_REQUEST_BLOCK Srb
)
2016 PIDE_DRIVE_IDENTIFY DeviceParams
;
2017 ULONG StartingSector
;
2019 UCHAR CylinderHigh
[2];
2020 UCHAR CylinderLow
[2];
2022 UCHAR SectorNumber
[2];
2026 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION DevExt
);
2028 DPRINT("AtapiReadWrite() called!\n");
2029 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2032 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2034 /* Get starting sector number from CDB. */
2035 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2036 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2037 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2038 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2040 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2041 DeviceParams
->BytesPerSector
;
2043 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2045 Srb
->DataTransferLength
,
2048 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2050 SectorNumber
[0] = StartingSector
& 0xff;
2051 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2052 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2053 SectorNumber
[1] = (StartingSector
>> 24) & 0xff;
2055 CylinderHigh
[1] = 0;
2056 DrvHead
= (Srb
->TargetId
? IDE_DH_DRV1
: 0) | IDE_DH_LBA
;
2058 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2059 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2060 DeviceExtension
->CommandPortBase
,
2061 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2062 (SectorNumber
[1] << 24) +
2063 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + DectorNumberLow
[0],
2068 else if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2070 SectorNumber
[0] = StartingSector
& 0xff;
2071 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2072 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2073 SectorNumber
[1] = 0;
2075 CylinderHigh
[1] = 0;
2076 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2077 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2080 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2081 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2082 DeviceExtension
->CommandPortBase
,
2083 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2084 ((DrvHead
& 0x0f) << 24) +
2085 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + SectorNumber
[0],
2091 SectorNumber
[0] = (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2092 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2093 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2094 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2095 StartingSector
/= DeviceParams
->LogicalHeads
;
2096 CylinderLow
[0] = StartingSector
& 0xff;
2097 CylinderHigh
[0] = StartingSector
>> 8;
2098 SectorNumber
[1] = 0;
2100 CylinderHigh
[1] = 0;
2102 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2103 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2104 DeviceExtension
->CommandPortBase
,
2105 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2114 /* Set pointer to data buffer. */
2115 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2116 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2118 DeviceExtension
->CurrentSrb
= Srb
;
2120 /* wait for BUSY to clear */
2121 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2123 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2124 if (!(Status
& IDE_SR_BUSY
))
2128 ScsiPortStallExecution(10);
2130 DPRINT("status=%02x\n", Status
);
2131 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2132 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2134 DPRINT ("Drive is BUSY for too long\n");
2135 return(SRB_STATUS_BUSY
);
2138 /* Select the desired drive */
2139 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2140 IDE_DH_FIXED
| DrvHead
);
2142 ScsiPortStallExecution(10);
2144 /* wait for BUSY to clear and DRDY to assert */
2145 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2147 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2148 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2152 ScsiPortStallExecution(10);
2154 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2155 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2157 DPRINT("Drive is BUSY for too long after drive select\n");
2158 return(SRB_STATUS_BUSY
);
2162 /* Setup command parameters */
2163 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2165 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2166 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
>> 8);
2167 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[1]);
2168 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[1]);
2169 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[1]);
2172 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2173 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
& 0xff);
2174 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[0]);
2175 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[0]);
2176 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[0]);
2178 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2181 if (DeviceExtension
->PRDTable
&&
2182 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
)
2184 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2186 if (DeviceExtension
->UseDma
)
2188 Handler
= AtapiDmaInterrupt
;
2189 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2191 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA_EXT
: IDE_CMD_WRITE_DMA_EXT
;
2195 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA
: IDE_CMD_WRITE_DMA
;
2201 Handler
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? AtapiReadInterrupt
: AtapiWriteInterrupt
;
2202 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
)
2204 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2206 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE_EXT
: IDE_CMD_WRITE_MULTIPLE_EXT
;
2210 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE
: IDE_CMD_WRITE_MULTIPLE
;
2215 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2217 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_EXT
: IDE_CMD_WRITE_EXT
;
2221 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ
: IDE_CMD_WRITE
;
2226 AtapiExecuteCommand(DeviceExtension
, Command
, Handler
);
2229 if (DeviceExtension
->UseDma
)
2233 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2234 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2239 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2241 /* Write data block */
2242 PUCHAR TargetAddress
;
2245 /* Wait for controller ready */
2246 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2248 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2249 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2253 ScsiPortStallExecution(10);
2255 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2257 DPRINT1("Drive is BUSY for too long after sending write command\n");
2258 return(SRB_STATUS_BUSY
);
2261 /* Update DeviceExtension data */
2262 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2263 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2265 TransferSize
= DeviceExtension
->DataTransferLength
;
2268 TargetAddress
= DeviceExtension
->DataBuffer
;
2269 DeviceExtension
->DataBuffer
+= TransferSize
;
2270 DeviceExtension
->DataTransferLength
-= TransferSize
;
2272 /* Write data block */
2273 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2275 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2281 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2288 DPRINT("AtapiReadWrite() done!\n");
2290 /* Wait for interrupt. */
2291 return(SRB_STATUS_PENDING
);
2296 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2297 PSCSI_REQUEST_BLOCK Srb
)
2302 DPRINT("AtapiFlushCache() called!\n");
2303 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2306 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_NO_FLUSH
)
2309 * NOTE: Don't flush the cache for CD/DVD drives. Although
2310 * the ATAPI-6 standard allows that, it has been experimentally
2311 * proved that it can damage some broken LG drives. Afterall
2312 * it doesn't make sense to flush cache on devices we don't
2315 return SRB_STATUS_INVALID_REQUEST
;
2318 if (!(DeviceExtension
->DeviceParams
[Srb
->TargetId
].SupportedFeatures83
& 0x1000))
2320 /* The device states it doesn't support the command */
2321 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2322 return SRB_STATUS_INVALID_REQUEST
;
2325 /* Wait for BUSY to clear */
2326 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2328 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2329 if (!(Status
& IDE_SR_BUSY
))
2333 ScsiPortStallExecution(10);
2335 DPRINT("Status=%02x\n", Status
);
2336 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2337 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2339 DPRINT1("Drive is BUSY for too long\n");
2340 return(SRB_STATUS_BUSY
);
2343 /* Select the desired drive */
2344 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2345 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2346 ScsiPortStallExecution(10);
2348 /* Issue command to drive */
2349 AtapiExecuteCommand(DeviceExtension
,
2350 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
? IDE_CMD_FLUSH_CACHE_EXT
: IDE_CMD_FLUSH_CACHE
,
2351 AtapiNoDataInterrupt
);
2353 /* Wait for controller ready */
2354 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2356 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2357 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2361 ScsiPortStallExecution(10);
2363 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2365 DPRINT1("Drive is BUSY for too long after sending write command\n");
2366 DeviceExtension
->Handler
= NULL
;
2367 return(SRB_STATUS_BUSY
);
2370 DPRINT("AtapiFlushCache() done!\n");
2372 /* Wait for interrupt. */
2373 return(SRB_STATUS_PENDING
);
2378 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2379 PSCSI_REQUEST_BLOCK Srb
)
2385 DPRINT1("AtapiTestUnitReady() called!\n");
2387 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2390 /* Return success if media status is not supported */
2391 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2393 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2394 return(SRB_STATUS_SUCCESS
);
2397 /* Wait for BUSY to clear */
2398 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2400 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2401 if (!(Status
& IDE_SR_BUSY
))
2405 ScsiPortStallExecution(10);
2407 DPRINT1("Status=%02x\n", Status
);
2408 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2409 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2411 DPRINT1("Drive is BUSY for too long\n");
2412 return(SRB_STATUS_BUSY
);
2415 /* Select the desired drive */
2416 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2417 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2418 ScsiPortStallExecution(10);
2420 /* Issue command to drive */
2421 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2423 /* Wait for controller ready */
2424 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2426 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2427 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2431 ScsiPortStallExecution(10);
2433 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2435 DPRINT1("Drive is BUSY for too long after sending write command\n");
2436 DeviceExtension
->Handler
= NULL
;
2437 return(SRB_STATUS_BUSY
);
2440 if (Status
& IDE_SR_ERR
)
2442 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2443 if (Error
== IDE_ER_UNC
)
2446 /* Handle write protection 'error' */
2447 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2448 DeviceExtension
->Handler
= NULL
;
2449 return(SRB_STATUS_SUCCESS
);
2454 /* Indicate expecting an interrupt. */
2455 return(SRB_STATUS_PENDING
);
2459 DeviceExtension
->Handler
= NULL
;
2461 DPRINT1("AtapiTestUnitReady() done!\n");
2463 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2464 return(SRB_STATUS_SUCCESS
);
2469 AtapiErrorToScsi(PVOID DeviceExtension
,
2470 PSCSI_REQUEST_BLOCK Srb
)
2472 PATAPI_MINIPORT_EXTENSION DevExt
;
2473 ULONG CommandPortBase
;
2474 ULONG ControlPortBase
;
2479 DPRINT("AtapiErrorToScsi() called\n");
2481 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2483 CommandPortBase
= DevExt
->CommandPortBase
;
2484 ControlPortBase
= DevExt
->ControlPortBase
;
2486 ErrorReg
= IDEReadError(CommandPortBase
);
2488 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2490 switch (ErrorReg
>> 4)
2492 case SCSI_SENSE_NO_SENSE
:
2493 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2494 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2495 SrbStatus
= SRB_STATUS_ERROR
;
2498 case SCSI_SENSE_RECOVERED_ERROR
:
2499 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2501 SrbStatus
= SRB_STATUS_SUCCESS
;
2504 case SCSI_SENSE_NOT_READY
:
2505 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2506 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2507 SrbStatus
= SRB_STATUS_ERROR
;
2510 case SCSI_SENSE_MEDIUM_ERROR
:
2511 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2512 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2513 SrbStatus
= SRB_STATUS_ERROR
;
2516 case SCSI_SENSE_HARDWARE_ERROR
:
2517 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2518 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2519 SrbStatus
= SRB_STATUS_ERROR
;
2522 case SCSI_SENSE_ILLEGAL_REQUEST
:
2523 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2524 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2525 SrbStatus
= SRB_STATUS_ERROR
;
2528 case SCSI_SENSE_UNIT_ATTENTION
:
2529 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2530 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2531 SrbStatus
= SRB_STATUS_ERROR
;
2534 case SCSI_SENSE_DATA_PROTECT
:
2535 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2536 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2537 SrbStatus
= SRB_STATUS_ERROR
;
2540 case SCSI_SENSE_BLANK_CHECK
:
2541 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2542 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2543 SrbStatus
= SRB_STATUS_ERROR
;
2546 case SCSI_SENSE_ABORTED_COMMAND
:
2547 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2548 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2549 SrbStatus
= SRB_STATUS_ERROR
;
2553 DPRINT("ATAPI error: Invalid sense key\n");
2555 SrbStatus
= SRB_STATUS_ERROR
;
2561 DPRINT1("IDE error: %02x\n", ErrorReg
);
2564 SrbStatus
= SRB_STATUS_ERROR
;
2567 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2570 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2571 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2572 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2573 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2574 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2576 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2587 Srb
->ScsiStatus
= ScsiStatus
;
2589 DPRINT("AtapiErrorToScsi() done\n");
2596 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2598 DPRINT("AtapiConvertScsiToAtapi() called\n");
2600 Srb
->CdbLength
= 12;
2602 switch (Srb
->Cdb
[0])
2604 case SCSIOP_FORMAT_UNIT
:
2605 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2608 case SCSIOP_MODE_SELECT
:
2610 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2613 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2614 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2616 RtlZeroMemory (Srb
->Cdb
,
2618 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2619 AtapiModeSelect
->PFBit
= 1;
2620 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2621 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2627 static VOID FASTCALL
2628 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2631 PSCSI_REQUEST_BLOCK Srb
;
2632 Srb
= DevExt
->CurrentSrb
;
2634 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2636 Srb
->SrbStatus
= SrbStatus
;
2637 if (SrbStatus
== SRB_STATUS_ERROR
)
2639 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2641 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2643 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2646 DevExt
->Handler
= NULL
;
2647 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2648 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2652 static BOOLEAN FASTCALL
2653 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2662 DPRINT("AtapiPacketDmaInterrupt\n");
2664 DevExt
->UseDma
= FALSE
;
2667 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2668 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2669 /* get DMA status */
2670 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2671 /* clear the INTR & ERROR bits */
2672 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2674 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2675 DPRINT("DriveStatus: %x\n", Status
);
2677 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2679 if (Status
& IDE_SR_ERR
)
2681 Error
= IDEReadError(DevExt
->CommandPortBase
);
2682 SensKey
= Error
>> 4;
2683 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2685 SrbStatus
= SRB_STATUS_ERROR
;
2689 if ((DmaStatus
& 0x07) != 0x04)
2691 DPRINT("DmaStatus: %02x\n", DmaStatus
);
2692 SrbStatus
= SRB_STATUS_ERROR
;
2696 SrbStatus
= STATUS_SUCCESS
;
2699 AtapiCompleteRequest(DevExt
, SrbStatus
);
2700 DPRINT("AtapiDmaPacketInterrupt() done\n");
2705 static BOOLEAN FASTCALL
2706 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2708 PSCSI_REQUEST_BLOCK Srb
;
2714 PBYTE TargetAddress
;
2720 DPRINT("AtapiPacketInterrupt()\n");
2722 Srb
= DevExt
->CurrentSrb
;
2724 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2725 DPRINT("DriveStatus: %x\n", Status
);
2727 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2729 if (Status
& IDE_SR_ERR
)
2731 Error
= IDEReadError(DevExt
->CommandPortBase
);
2732 SensKey
= Error
>> 4;
2733 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2736 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2737 DPRINT("AtapiPacketInterrupt() done\n");
2741 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
2742 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
2743 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
2745 if (!(Status
& IDE_SR_DRQ
))
2747 if (DevExt
->DataTransferLength
> 0)
2749 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2750 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
2751 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
2755 SrbStatus
= SRB_STATUS_SUCCESS
;
2757 AtapiCompleteRequest(DevExt
, SrbStatus
);
2758 DPRINT("AtapiPacketInterrupt() done\n");
2762 TargetAddress
= DevExt
->DataBuffer
;
2764 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2766 DPRINT("read data\n");
2767 if (DevExt
->DataTransferLength
<= TransferSize
)
2769 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
2770 TransferSize
= DevExt
->DataTransferLength
;
2772 DevExt
->DataTransferLength
= 0;
2777 DevExt
->DataTransferLength
-= TransferSize
;
2778 IsLastBlock
= FALSE
;
2781 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
2783 DevExt
->DataBuffer
+= TransferSize
;
2785 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2790 /* Read remaining junk from device */
2791 while (JunkSize
> 0)
2793 IDEReadWord(DevExt
->CommandPortBase
);
2797 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
2799 ScsiPortStallExecution(10);
2802 /* Check for data overrun */
2803 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
2805 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2806 IDEReadWord(DevExt
->CommandPortBase
);
2810 SrbStatus
= SRB_STATUS_SUCCESS
;
2812 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2814 DPRINT("write data\n");
2815 if (DevExt
->DataTransferLength
< TransferSize
)
2817 TransferSize
= DevExt
->DataTransferLength
;
2820 TargetAddress
= DevExt
->DataBuffer
;
2822 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
2824 DevExt
->DataBuffer
+= TransferSize
;
2825 DevExt
->DataTransferLength
-= TransferSize
;
2827 /* Write the sector */
2828 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2829 SrbStatus
= SRB_STATUS_SUCCESS
;
2830 IsLastBlock
= FALSE
;
2834 DPRINT("Unspecified transfer direction!\n");
2835 SrbStatus
= SRB_STATUS_SUCCESS
;
2840 AtapiCompleteRequest(DevExt
, SrbStatus
);
2842 DPRINT("AtapiPacketInterrupt() done\n");
2846 static BOOLEAN FASTCALL
2847 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2851 DPRINT("AtapiNoDataInterrupt()\n");
2853 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2854 AtapiCompleteRequest(DevExt
,
2855 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
2857 DPRINT("AtapiNoDatanterrupt() done!\n");
2862 static BOOLEAN FASTCALL
2863 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2869 DPRINT("AtapiDmaInterrupt()\n");
2871 DevExt
->UseDma
= FALSE
;
2873 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2874 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2875 /* get DMA status */
2876 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2877 /* clear the INTR & ERROR bits */
2878 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2880 /* read the drive status */
2881 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2882 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
2883 (DmaStatus
& 0x07) == 4)
2885 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2886 DPRINT("AtapiDmaInterrupt() done\n");
2889 DPRINT1("Status %x\n", Status
);
2890 DPRINT1("%x\n", DmaStatus
);
2891 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2892 DPRINT1("AtapiDmaReadInterrupt() done\n");
2897 static BOOLEAN FASTCALL
2898 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2900 PSCSI_REQUEST_BLOCK Srb
;
2902 BOOLEAN IsLastBlock
;
2903 PUCHAR TargetAddress
;
2906 DPRINT("AtapiReadInterrupt() called!\n");
2908 Srb
= DevExt
->CurrentSrb
;
2910 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2911 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
2913 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
2915 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2916 DPRINT("AtapiReadInterrupt() done!\n");
2919 DPRINT("AtapiReadInterrupt() done!\n");
2923 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
2925 /* Update controller/device state variables */
2926 TargetAddress
= DevExt
->DataBuffer
;
2927 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2929 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2930 DPRINT("TransferSize: %lu\n", TransferSize
);
2932 if (DevExt
->DataTransferLength
<= TransferSize
)
2934 TransferSize
= DevExt
->DataTransferLength
;
2935 DevExt
->DataTransferLength
= 0;
2940 DevExt
->DataTransferLength
-= TransferSize
;
2941 IsLastBlock
= FALSE
;
2943 DevExt
->DataBuffer
+= TransferSize
;
2944 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
2946 /* Copy the block of data */
2947 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2949 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2953 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2958 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2961 DPRINT("AtapiReadInterrupt() done!\n");
2966 static BOOLEAN FASTCALL
2967 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
2969 PSCSI_REQUEST_BLOCK Srb
;
2971 BOOLEAN IsLastBlock
;
2972 PUCHAR TargetAddress
;
2975 DPRINT("AtapiWriteInterrupt() called!\n");
2977 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2978 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
2980 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
2982 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2983 DPRINT("AtapiWriteInterrupt() done!\n");
2986 DPRINT("AtapiWriteInterrupt() done!\n");
2991 Srb
= DevExt
->CurrentSrb
;
2992 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2993 if (DevExt
->DataTransferLength
< TransferSize
)
2995 TransferSize
= DevExt
->DataTransferLength
;
2997 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
2999 IsLastBlock
= FALSE
;
3000 TargetAddress
= DevExt
->DataBuffer
;
3001 DevExt
->DataBuffer
+= TransferSize
;
3002 DevExt
->DataTransferLength
-= TransferSize
;
3004 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
3005 DPRINT("TransferSize: %lu\n", TransferSize
);
3006 /* Write the sector */
3007 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
3009 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3013 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3016 else if (DeviceStatus
& IDE_SR_DRQ
)
3018 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3021 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
3023 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
3032 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3034 DPRINT("AtapiWriteInterrupt() done!\n");
3040 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
3042 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
3044 if (DevExt
->Handler
!= NULL
)
3046 DPRINT1("DevExt->Handler is already set!!\n");
3048 DevExt
->Handler
= Handler
;
3049 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
3050 ScsiPortStallExecution(1);
3055 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
3056 PSCSI_REQUEST_BLOCK Srb
,
3061 PPRD PRDEntry
= DevExt
->PRDTable
;
3062 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
3067 DPRINT("AtapiInitDma()\n");
3069 StartAddress
= Srb
->DataBuffer
;
3070 EndAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ Srb
->DataTransferLength
);
3071 DevExt
->PRDCount
= 0;
3073 while (StartAddress
< EndAddress
)
3075 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
3076 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
3083 /* calculate the length up to the next 64k boundary */
3084 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
3085 if (tmpLength
> Length
)
3090 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3094 if (tmpLength
== 0x10000)
3096 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3098 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3099 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3100 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3101 PRDEntry
->Length
= tmpLength
;
3104 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3108 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3109 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3110 Length
-= tmpLength
;
3111 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3113 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3114 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3115 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3116 PRDEntry
->Length
= tmpLength
;
3118 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3119 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3120 Length
-= tmpLength
;
3123 /* set the end marker in the last PRD */
3125 PRDEntry
->Length
|= 0x80000000;
3126 /* set the PDR table */
3127 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3128 /* write the DMA command */
3129 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3130 /* reset the status and interrupt bit */
3131 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3132 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);