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(char *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],
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
);
2352 /* Wait for controller ready */
2353 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2355 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2356 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2360 ScsiPortStallExecution(10);
2362 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2364 DPRINT1("Drive is BUSY for too long after sending write command\n");
2365 DeviceExtension
->Handler
= NULL
;
2366 return(SRB_STATUS_BUSY
);
2369 DPRINT("AtapiFlushCache() done!\n");
2371 /* Wait for interrupt. */
2372 return(SRB_STATUS_PENDING
);
2377 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2378 PSCSI_REQUEST_BLOCK Srb
)
2384 DPRINT1("AtapiTestUnitReady() called!\n");
2386 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2389 /* Return success if media status is not supported */
2390 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2392 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2393 return(SRB_STATUS_SUCCESS
);
2396 /* Wait for BUSY to clear */
2397 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2399 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2400 if (!(Status
& IDE_SR_BUSY
))
2404 ScsiPortStallExecution(10);
2406 DPRINT1("Status=%02x\n", Status
);
2407 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2408 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2410 DPRINT1("Drive is BUSY for too long\n");
2411 return(SRB_STATUS_BUSY
);
2414 /* Select the desired drive */
2415 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2416 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2417 ScsiPortStallExecution(10);
2419 /* Issue command to drive */
2420 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2422 /* Wait for controller ready */
2423 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2425 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2426 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2430 ScsiPortStallExecution(10);
2432 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2434 DPRINT1("Drive is BUSY for too long after sending write command\n");
2435 DeviceExtension
->Handler
= NULL
;
2436 return(SRB_STATUS_BUSY
);
2439 if (Status
& IDE_SR_ERR
)
2441 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2442 if (Error
== IDE_ER_UNC
)
2445 /* Handle write protection 'error' */
2446 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2447 DeviceExtension
->Handler
= NULL
;
2448 return(SRB_STATUS_SUCCESS
);
2453 /* Indicate expecting an interrupt. */
2454 return(SRB_STATUS_PENDING
);
2458 DeviceExtension
->Handler
= NULL
;
2460 DPRINT1("AtapiTestUnitReady() done!\n");
2462 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2463 return(SRB_STATUS_SUCCESS
);
2468 AtapiErrorToScsi(PVOID DeviceExtension
,
2469 PSCSI_REQUEST_BLOCK Srb
)
2471 PATAPI_MINIPORT_EXTENSION DevExt
;
2472 ULONG CommandPortBase
;
2473 ULONG ControlPortBase
;
2478 DPRINT("AtapiErrorToScsi() called\n");
2480 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2482 CommandPortBase
= DevExt
->CommandPortBase
;
2483 ControlPortBase
= DevExt
->ControlPortBase
;
2485 ErrorReg
= IDEReadError(CommandPortBase
);
2487 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2489 switch (ErrorReg
>> 4)
2491 case SCSI_SENSE_NO_SENSE
:
2492 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2493 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2494 SrbStatus
= SRB_STATUS_ERROR
;
2497 case SCSI_SENSE_RECOVERED_ERROR
:
2498 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2500 SrbStatus
= SRB_STATUS_SUCCESS
;
2503 case SCSI_SENSE_NOT_READY
:
2504 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2505 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2506 SrbStatus
= SRB_STATUS_ERROR
;
2509 case SCSI_SENSE_MEDIUM_ERROR
:
2510 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2511 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2512 SrbStatus
= SRB_STATUS_ERROR
;
2515 case SCSI_SENSE_HARDWARE_ERROR
:
2516 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2517 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2518 SrbStatus
= SRB_STATUS_ERROR
;
2521 case SCSI_SENSE_ILLEGAL_REQUEST
:
2522 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2523 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2524 SrbStatus
= SRB_STATUS_ERROR
;
2527 case SCSI_SENSE_UNIT_ATTENTION
:
2528 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2529 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2530 SrbStatus
= SRB_STATUS_ERROR
;
2533 case SCSI_SENSE_DATA_PROTECT
:
2534 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2535 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2536 SrbStatus
= SRB_STATUS_ERROR
;
2539 case SCSI_SENSE_BLANK_CHECK
:
2540 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2541 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2542 SrbStatus
= SRB_STATUS_ERROR
;
2545 case SCSI_SENSE_ABORTED_COMMAND
:
2546 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2547 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2548 SrbStatus
= SRB_STATUS_ERROR
;
2552 DPRINT("ATAPI error: Invalid sense key\n");
2554 SrbStatus
= SRB_STATUS_ERROR
;
2560 DPRINT1("IDE error: %02x\n", ErrorReg
);
2563 SrbStatus
= SRB_STATUS_ERROR
;
2566 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2569 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2570 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2571 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2572 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2573 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2575 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2586 Srb
->ScsiStatus
= ScsiStatus
;
2588 DPRINT("AtapiErrorToScsi() done\n");
2595 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2597 DPRINT("AtapiConvertScsiToAtapi() called\n");
2599 Srb
->CdbLength
= 12;
2601 switch (Srb
->Cdb
[0])
2603 case SCSIOP_FORMAT_UNIT
:
2604 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2607 case SCSIOP_MODE_SELECT
:
2609 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2612 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2613 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2615 RtlZeroMemory (Srb
->Cdb
,
2617 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2618 AtapiModeSelect
->PFBit
= 1;
2619 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2620 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2626 static VOID FASTCALL
2627 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2630 PSCSI_REQUEST_BLOCK Srb
;
2631 Srb
= DevExt
->CurrentSrb
;
2633 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2635 Srb
->SrbStatus
= SrbStatus
;
2636 if (SrbStatus
== SRB_STATUS_ERROR
)
2638 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2640 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2642 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2645 DevExt
->Handler
= NULL
;
2646 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2647 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2651 static BOOLEAN FASTCALL
2652 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2661 DPRINT("AtapiPacketDmaInterrupt\n");
2663 DevExt
->UseDma
= FALSE
;
2666 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2667 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2668 /* get DMA status */
2669 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2670 /* clear the INTR & ERROR bits */
2671 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2673 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2674 DPRINT("DriveStatus: %x\n", Status
);
2676 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2678 if (Status
& IDE_SR_ERR
)
2680 Error
= IDEReadError(DevExt
->CommandPortBase
);
2681 SensKey
= Error
>> 4;
2682 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2684 SrbStatus
= SRB_STATUS_ERROR
;
2688 if ((DmaStatus
& 0x07) != 0x04)
2690 DPRINT("DmaStatus: %02x\n", DmaStatus
);
2691 SrbStatus
= SRB_STATUS_ERROR
;
2695 SrbStatus
= STATUS_SUCCESS
;
2698 AtapiCompleteRequest(DevExt
, SrbStatus
);
2699 DPRINT("AtapiDmaPacketInterrupt() done\n");
2704 static BOOLEAN FASTCALL
2705 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2707 PSCSI_REQUEST_BLOCK Srb
;
2713 PBYTE TargetAddress
;
2719 DPRINT("AtapiPacketInterrupt()\n");
2721 Srb
= DevExt
->CurrentSrb
;
2723 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2724 DPRINT("DriveStatus: %x\n", Status
);
2726 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2728 if (Status
& IDE_SR_ERR
)
2730 Error
= IDEReadError(DevExt
->CommandPortBase
);
2731 SensKey
= Error
>> 4;
2732 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2735 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2736 DPRINT("AtapiPacketInterrupt() done\n");
2740 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
2741 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
2742 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
2744 if (!(Status
& IDE_SR_DRQ
))
2746 if (DevExt
->DataTransferLength
> 0)
2748 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2749 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
2750 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
2754 SrbStatus
= SRB_STATUS_SUCCESS
;
2756 AtapiCompleteRequest(DevExt
, SrbStatus
);
2757 DPRINT("AtapiPacketInterrupt() done\n");
2761 TargetAddress
= DevExt
->DataBuffer
;
2763 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2765 DPRINT("read data\n");
2766 if (DevExt
->DataTransferLength
<= TransferSize
)
2768 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
2769 TransferSize
= DevExt
->DataTransferLength
;
2771 DevExt
->DataTransferLength
= 0;
2776 DevExt
->DataTransferLength
-= TransferSize
;
2777 IsLastBlock
= FALSE
;
2780 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
2782 DevExt
->DataBuffer
+= TransferSize
;
2784 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2789 /* Read remaining junk from device */
2790 while (JunkSize
> 0)
2792 IDEReadWord(DevExt
->CommandPortBase
);
2796 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
2798 ScsiPortStallExecution(10);
2801 /* Check for data overrun */
2802 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
2804 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2805 IDEReadWord(DevExt
->CommandPortBase
);
2809 SrbStatus
= SRB_STATUS_SUCCESS
;
2811 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2813 DPRINT("write data\n");
2814 if (DevExt
->DataTransferLength
< TransferSize
)
2816 TransferSize
= DevExt
->DataTransferLength
;
2819 TargetAddress
= DevExt
->DataBuffer
;
2821 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
2823 DevExt
->DataBuffer
+= TransferSize
;
2824 DevExt
->DataTransferLength
-= TransferSize
;
2826 /* Write the sector */
2827 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2828 SrbStatus
= SRB_STATUS_SUCCESS
;
2829 IsLastBlock
= FALSE
;
2833 DPRINT("Unspecified transfer direction!\n");
2834 SrbStatus
= SRB_STATUS_SUCCESS
;
2839 AtapiCompleteRequest(DevExt
, SrbStatus
);
2841 DPRINT("AtapiPacketInterrupt() done\n");
2845 static BOOLEAN FASTCALL
2846 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2850 DPRINT("AtapiNoDataInterrupt()\n");
2852 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2853 AtapiCompleteRequest(DevExt
,
2854 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
2856 DPRINT("AtapiNoDatanterrupt() done!\n");
2861 static BOOLEAN FASTCALL
2862 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2868 DPRINT("AtapiDmaInterrupt()\n");
2870 DevExt
->UseDma
= FALSE
;
2872 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2873 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2874 /* get DMA status */
2875 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2876 /* clear the INTR & ERROR bits */
2877 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2879 /* read the drive status */
2880 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2881 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
2882 (DmaStatus
& 0x07) == 4)
2884 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2885 DPRINT("AtapiDmaInterrupt() done\n");
2888 DPRINT1("Status %x\n", Status
);
2889 DPRINT1("%x\n", DmaStatus
);
2890 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2891 DPRINT1("AtapiDmaReadInterrupt() done\n");
2896 static BOOLEAN FASTCALL
2897 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2899 PSCSI_REQUEST_BLOCK Srb
;
2901 BOOLEAN IsLastBlock
;
2902 PUCHAR TargetAddress
;
2905 DPRINT("AtapiReadInterrupt() called!\n");
2907 Srb
= DevExt
->CurrentSrb
;
2909 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2910 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
2912 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
2914 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2915 DPRINT("AtapiReadInterrupt() done!\n");
2918 DPRINT("AtapiReadInterrupt() done!\n");
2922 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
2924 /* Update controller/device state variables */
2925 TargetAddress
= DevExt
->DataBuffer
;
2926 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2928 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2929 DPRINT("TransferSize: %lu\n", TransferSize
);
2931 if (DevExt
->DataTransferLength
<= TransferSize
)
2933 TransferSize
= DevExt
->DataTransferLength
;
2934 DevExt
->DataTransferLength
= 0;
2939 DevExt
->DataTransferLength
-= TransferSize
;
2940 IsLastBlock
= FALSE
;
2942 DevExt
->DataBuffer
+= TransferSize
;
2943 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
2945 /* Copy the block of data */
2946 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2948 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2952 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2957 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2960 DPRINT("AtapiReadInterrupt() done!\n");
2965 static BOOLEAN FASTCALL
2966 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
2968 PSCSI_REQUEST_BLOCK Srb
;
2970 BOOLEAN IsLastBlock
;
2971 PUCHAR TargetAddress
;
2974 DPRINT("AtapiWriteInterrupt() called!\n");
2976 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2977 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
2979 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
2981 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2982 DPRINT("AtapiWriteInterrupt() done!\n");
2985 DPRINT("AtapiWriteInterrupt() done!\n");
2990 Srb
= DevExt
->CurrentSrb
;
2991 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2992 if (DevExt
->DataTransferLength
< TransferSize
)
2994 TransferSize
= DevExt
->DataTransferLength
;
2996 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
2998 IsLastBlock
= FALSE
;
2999 TargetAddress
= DevExt
->DataBuffer
;
3000 DevExt
->DataBuffer
+= TransferSize
;
3001 DevExt
->DataTransferLength
-= TransferSize
;
3003 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
3004 DPRINT("TransferSize: %lu\n", TransferSize
);
3005 /* Write the sector */
3006 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
3008 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3012 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3015 else if (DeviceStatus
& IDE_SR_DRQ
)
3017 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3020 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
3022 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
3031 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3033 DPRINT("AtapiWriteInterrupt() done!\n");
3039 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
3041 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
3043 if (DevExt
->Handler
!= NULL
)
3045 DPRINT1("DevExt->Handler is already set!!\n");
3047 DevExt
->Handler
= Handler
;
3048 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
3049 ScsiPortStallExecution(1);
3054 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
3055 PSCSI_REQUEST_BLOCK Srb
,
3060 PPRD PRDEntry
= DevExt
->PRDTable
;
3061 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
3066 DPRINT("AtapiInitDma()\n");
3068 StartAddress
= Srb
->DataBuffer
;
3069 EndAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ Srb
->DataTransferLength
);
3070 DevExt
->PRDCount
= 0;
3072 while (StartAddress
< EndAddress
)
3074 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
3075 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
3082 /* calculate the length up to the next 64k boundary */
3083 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
3084 if (tmpLength
> Length
)
3089 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3093 if (tmpLength
== 0x10000)
3095 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3097 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3098 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3099 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3100 PRDEntry
->Length
= tmpLength
;
3103 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3107 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3108 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3109 Length
-= tmpLength
;
3110 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3112 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3113 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3114 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3115 PRDEntry
->Length
= tmpLength
;
3117 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3118 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3119 Length
-= tmpLength
;
3122 /* set the end marker in the last PRD */
3124 PRDEntry
->Length
|= 0x80000000;
3125 /* set the PDR table */
3126 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3127 /* write the DMA command */
3128 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3129 /* reset the status and interrupt bit */
3130 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3131 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);