3 * Copyright (C) 2001, 2002, 2003, 2004, 2005 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: drivers/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
33 * This driver is derived from Rex Jolliff's ide driver. Lots of his
34 * routines are still in here although they belong into the higher level
35 * drivers. They will be moved away as soon as possible.
40 * - implement sending of atapi commands
41 * - handle removable atapi non-cdrom drives
45 #define ENABLE_NATIVE_PCI
49 // -------------------------------------------------------------------------
51 #include <ddk/ntddk.h>
54 #include <ddk/ntddscsi.h>
55 #include <ddk/ntdddisk.h>
56 #include <ddk/ntddstor.h>
63 #define VERSION "0.0.1"
66 // ------------------------------------------------------- File Static Data
76 // ATAPI_MINIPORT_EXTENSION
79 // Extension to be placed in each port device object
82 // Allocated from NON-PAGED POOL
83 // Available at any IRQL
86 typedef struct _ATAPI_MINIPORT_EXTENSION
88 IDE_DRIVE_IDENTIFY DeviceParams
[2];
90 ULONG TransferSize
[2];
92 ULONG CommandPortBase
;
93 ULONG ControlPortBase
;
94 ULONG BusMasterRegisterBase
;
96 PSCSI_REQUEST_BLOCK CurrentSrb
;
99 ULONG DataTransferLength
;
101 BOOLEAN
FASTCALL (*Handler
)(IN
struct _ATAPI_MINIPORT_EXTENSION
* DevExt
);
107 SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress
;
109 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
112 #define DEVICE_PRESENT 0x00000001
113 #define DEVICE_ATAPI 0x00000002
114 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
115 #define DEVICE_DWORD_IO 0x00000008
116 #define DEVICE_48BIT_ADDRESS 0x00000010
117 #define DEVICE_MEDIA_STATUS 0x00000020
118 #define DEVICE_DMA_CMD 0x00000040
119 #define DEVICE_NO_FLUSH 0x00000080
122 typedef struct _UNIT_EXTENSION
125 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
127 PCI_SLOT_NUMBER LastSlotNumber
;
129 #ifdef ENABLE_NATIVE_PCI
130 typedef struct _PCI_NATIVE_CONTROLLER
135 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
137 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
141 0x4D68, // PDC20268, Ultra100TX2
145 0x4D30, // PDC20267, Ultra100
151 // ----------------------------------------------- Discardable Declarations
155 // make the initialization routines discardable, so that they
158 #pragma alloc_text(init, DriverEntry)
160 // make the PASSIVE_LEVEL routines pageable, so that they don't
161 // waste nonpaged memory
163 #endif /* ALLOC_PRAGMA */
165 // ---------------------------------------------------- Forward Declarations
169 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
170 PSCSI_REQUEST_BLOCK Srb
,
175 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
177 PVOID BusInformation
,
178 PCHAR ArgumentString
,
179 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
183 AtapiFindIsaBusController(PVOID DeviceExtension
,
185 PVOID BusInformation
,
186 PCHAR ArgumentString
,
187 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
191 AtapiFindNativePciController(PVOID DeviceExtension
,
193 PVOID BusInformation
,
194 PCHAR ArgumentString
,
195 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
198 static BOOLEAN STDCALL
199 AtapiInitialize(IN PVOID DeviceExtension
);
201 static BOOLEAN STDCALL
202 AtapiResetBus(IN PVOID DeviceExtension
,
205 static BOOLEAN STDCALL
206 AtapiStartIo(IN PVOID DeviceExtension
,
207 IN PSCSI_REQUEST_BLOCK Srb
);
210 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
212 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
));
214 static BOOLEAN STDCALL
215 AtapiInterrupt(IN PVOID DeviceExtension
);
217 static BOOLEAN FASTCALL
218 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
);
220 static BOOLEAN FASTCALL
221 AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
223 static BOOLEAN FASTCALL
224 AtapiSmartInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
226 static BOOLEAN FASTCALL
227 AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
230 static BOOLEAN FASTCALL
231 AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
233 static BOOLEAN FASTCALL
234 AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
237 static BOOLEAN FASTCALL
238 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
241 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
242 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
245 AtapiIdentifyDevice(IN ULONG CommandPort
,
246 IN ULONG ControlPort
,
249 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
252 AtapiPolledRead(IN ULONG CommandPort
,
253 IN ULONG ControlPort
,
257 IN UCHAR CylinderLow
,
258 IN UCHAR CylinderHigh
,
264 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
265 IN PSCSI_REQUEST_BLOCK Srb
);
268 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
269 IN PSCSI_REQUEST_BLOCK Srb
);
272 AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
273 IN PSCSI_REQUEST_BLOCK Srb
);
276 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
277 IN PSCSI_REQUEST_BLOCK Srb
);
280 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
281 IN PSCSI_REQUEST_BLOCK Srb
);
284 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
285 IN PSCSI_REQUEST_BLOCK Srb
);
288 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
289 PSCSI_REQUEST_BLOCK Srb
);
292 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
293 PSCSI_REQUEST_BLOCK Srb
);
296 AtapiErrorToScsi(PVOID DeviceExtension
,
297 PSCSI_REQUEST_BLOCK Srb
);
300 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
);
302 // ---------------------------------------------------------------- Inlines
305 IDESwapBytePairs(UCHAR
*Buf
,
311 for (i
= 0; i
< Cnt
; i
+= 2)
320 // ------------------------------------------------------- Public Interface
325 // This function initializes the driver, locates and claims
326 // hardware resources, and creates various NT objects needed
327 // to process I/O requests.
333 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
335 // IN PUNICODE_STRING RegistryPath Name of registry driver service
342 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
343 IN PUNICODE_STRING RegistryPath
)
345 HW_INITIALIZATION_DATA InitData
;
348 DPRINT("ATAPI Driver %s\n", VERSION
);
349 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
351 /* Initialize data structure */
352 RtlZeroMemory(&InitData
,
353 sizeof(HW_INITIALIZATION_DATA
));
354 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
355 InitData
.HwInitialize
= AtapiInitialize
;
356 InitData
.HwResetBus
= AtapiResetBus
;
357 InitData
.HwStartIo
= AtapiStartIo
;
358 InitData
.HwInterrupt
= AtapiInterrupt
;
360 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
361 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
363 InitData
.MapBuffers
= TRUE
;
365 /* Search the PCI bus for compatibility mode ide controllers */
367 InitData
.NeedPhysicalAddresses
= TRUE
;
369 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
370 InitData
.NumberOfAccessRanges
= 3;
371 InitData
.AdapterInterfaceType
= PCIBus
;
373 InitData
.VendorId
= NULL
;
374 InitData
.VendorIdLength
= 0;
375 InitData
.DeviceId
= NULL
;
376 InitData
.DeviceIdLength
= 0;
378 Status
= ScsiPortInitialize(DriverObject
,
382 // if (newStatus < statusToReturn)
383 // statusToReturn = newStatus;
386 /* Search the PCI bus for all ide controllers */
387 #ifdef ENABLE_NATIVE_PCI
388 InitData
.NeedPhysicalAddresses
= TRUE
;
390 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
391 InitData
.NumberOfAccessRanges
= 3;
392 InitData
.AdapterInterfaceType
= PCIBus
;
394 InitData
.VendorId
= 0;
395 InitData
.VendorIdLength
= 0;
396 InitData
.DeviceId
= 0;
397 InitData
.DeviceIdLength
= 0;
399 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
401 Status
= ScsiPortInitialize(DriverObject
,
405 // if (newStatus < statusToReturn)
406 // statusToReturn = newStatus;
409 /* Search the ISA bus for ide controllers */
411 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
412 InitData
.NumberOfAccessRanges
= 2;
413 InitData
.AdapterInterfaceType
= Isa
;
415 InitData
.VendorId
= NULL
;
416 InitData
.VendorIdLength
= 0;
417 InitData
.DeviceId
= NULL
;
418 InitData
.DeviceIdLength
= 0;
420 Status
= ScsiPortInitialize(DriverObject
,
424 // if (newStatus < statusToReturn)
425 // statusToReturn = newStatus;
428 DPRINT("Returning from DriverEntry\n");
435 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
436 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
437 INTERFACE_TYPE InterfaceType
,
438 ULONG CommandPortBase
,
439 ULONG ControlPortBase
,
440 ULONG BusMasterPortBase
,
441 ULONG InterruptVector
)
443 SCSI_PHYSICAL_ADDRESS IoAddress
;
448 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
449 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
451 ConfigInfo
->SystemIoBusNumber
,
459 DevExt
->Handler
= NULL
;
460 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
461 (*ConfigInfo
->AccessRanges
)[0].RangeStart
= IoAddress
;
462 (*ConfigInfo
->AccessRanges
)[0].RangeLength
= 8;
463 (*ConfigInfo
->AccessRanges
)[0].RangeInMemory
= FALSE
;
467 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
468 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
470 ConfigInfo
->SystemIoBusNumber
,
476 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
477 (PVOID
)DevExt
->CommandPortBase
);
480 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
481 (*ConfigInfo
->AccessRanges
)[1].RangeStart
= IoAddress
;
482 (*ConfigInfo
->AccessRanges
)[1].RangeLength
= 1;
483 (*ConfigInfo
->AccessRanges
)[1].RangeInMemory
= FALSE
;
485 if (BusMasterPortBase
)
487 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
488 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
490 ConfigInfo
->SystemIoBusNumber
,
496 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
497 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
500 DevExt
->BusMasterRegisterBase
= (ULONG
)IoBase
;
501 (*ConfigInfo
->AccessRanges
)[2].RangeStart
= IoAddress
;
502 (*ConfigInfo
->AccessRanges
)[2].RangeLength
= 8;
503 (*ConfigInfo
->AccessRanges
)[2].RangeInMemory
= FALSE
;
505 // ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
506 // ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
507 ConfigInfo
->DmaWidth
= Width32Bits
;
508 // ConfigInfo->DmaSpeed = Compatible;
509 ConfigInfo
->ScatterGather
= TRUE
;
510 ConfigInfo
->Master
= TRUE
;
511 ConfigInfo
->NumberOfPhysicalBreaks
= 0x10000 / PAGE_SIZE
+ 1;
512 ConfigInfo
->Dma32BitAddresses
= TRUE
;
513 ConfigInfo
->NeedPhysicalAddresses
= TRUE
;
514 ConfigInfo
->MapBuffers
= TRUE
;
516 DevExt
->PRDMaxCount
= PAGE_SIZE
/ sizeof(PRD
);
517 DevExt
->PRDTable
= ScsiPortGetUncachedExtension(DevExt
, ConfigInfo
, sizeof(PRD
) * DevExt
->PRDMaxCount
);
518 if (DevExt
->PRDTable
!= NULL
)
520 DevExt
->PRDTablePhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, NULL
, DevExt
->PRDTable
, &Length
);
522 if (DevExt
->PRDTable
== NULL
||
523 DevExt
->PRDTablePhysicalAddress
.QuadPart
== 0LL ||
524 Length
< sizeof(PRD
) * DevExt
->PRDMaxCount
)
526 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
527 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
528 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->BusMasterRegisterBase
);
533 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
534 ConfigInfo
->BusInterruptVector
= InterruptVector
;
535 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
537 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
539 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
541 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
543 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
551 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
553 PVOID BusInformation
,
554 PCHAR ArgumentString
,
555 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
558 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
559 PCI_SLOT_NUMBER SlotNumber
;
560 PCI_COMMON_CONFIG PciConfig
;
562 ULONG StartDeviceNumber
;
564 ULONG StartFunctionNumber
;
565 ULONG FunctionNumber
;
566 BOOLEAN ChannelFound
;
568 ULONG BusMasterBasePort
= 0;
570 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
571 ConfigInfo
->SystemIoBusNumber
,
572 ConfigInfo
->SlotNumber
);
576 /* both channels were claimed: exit */
577 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
578 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
579 return(SP_RETURN_NOT_FOUND
);
581 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
582 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
583 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
584 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
586 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
587 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
589 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
590 ChannelFound
= FALSE
;
593 DataSize
= ScsiPortGetBusData(DeviceExtension
,
595 ConfigInfo
->SystemIoBusNumber
,
596 SlotNumber
.u
.AsULONG
,
598 PCI_COMMON_HDR_LENGTH
);
599 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
601 if (FunctionNumber
== 0)
611 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
612 if (PciConfig
.BaseClass
== 0x01 &&
613 PciConfig
.SubClass
== 0x01) // &&
614 // (PciConfig.ProgIf & 0x05) == 0)
616 /* both channels are in compatibility mode */
617 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
618 ConfigInfo
->SystemIoBusNumber
,
619 SlotNumber
.u
.bits
.DeviceNumber
,
620 SlotNumber
.u
.bits
.FunctionNumber
,
623 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
625 DPRINT("Found IDE controller in compatibility mode!\n");
627 ConfigInfo
->NumberOfBuses
= 1;
628 ConfigInfo
->MaximumNumberOfTargets
= 2;
629 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
631 if (PciConfig
.ProgIf
& 0x80)
633 DPRINT("Found IDE Bus Master controller!\n");
634 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
636 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
637 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
640 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
642 /* Both channels unclaimed: Claim primary channel */
643 DPRINT("Primary channel!\n");
644 ChannelFound
= AtapiClaimHwResources(DevExt
,
653 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
655 /* Primary channel already claimed: claim secondary channel */
656 DPRINT("Secondary channel!\n");
658 ChannelFound
= AtapiClaimHwResources(DevExt
,
663 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
667 /* Find attached devices */
670 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
671 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
672 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
673 return(SP_RETURN_FOUND
);
676 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
681 StartFunctionNumber
= 0;
683 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
685 return(SP_RETURN_NOT_FOUND
);
692 AtapiFindIsaBusController(PVOID DeviceExtension
,
694 PVOID BusInformation
,
695 PCHAR ArgumentString
,
696 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
699 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
700 BOOLEAN ChannelFound
= FALSE
;
701 BOOLEAN DeviceFound
= FALSE
;
703 DPRINT("AtapiFindIsaBusController() called!\n");
707 ConfigInfo
->NumberOfBuses
= 1;
708 ConfigInfo
->MaximumNumberOfTargets
= 2;
709 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
711 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
713 /* Both channels unclaimed: Claim primary channel */
714 DPRINT("Primary channel!\n");
716 ChannelFound
= AtapiClaimHwResources(DevExt
,
725 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
727 /* Primary channel already claimed: claim secondary channel */
728 DPRINT("Secondary channel!\n");
730 ChannelFound
= AtapiClaimHwResources(DevExt
,
741 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
743 return(SP_RETURN_NOT_FOUND
);
746 /* Find attached devices */
749 DeviceFound
= AtapiFindDevices(DevExt
,
751 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
752 return(SP_RETURN_FOUND
);
755 return SP_RETURN_NOT_FOUND
;
760 #ifdef ENABLE_NATIVE_PCI
762 AtapiFindNativePciController(PVOID DeviceExtension
,
764 PVOID BusInformation
,
765 PCHAR ArgumentString
,
766 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
769 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
770 PCI_COMMON_CONFIG PciConfig
;
771 PCI_SLOT_NUMBER SlotNumber
;
774 ULONG StartDeviceNumber
;
775 ULONG FunctionNumber
;
776 ULONG StartFunctionNumber
;
777 ULONG BusMasterBasePort
;
779 BOOLEAN ChannelFound
;
781 DPRINT("AtapiFindNativePciController() called!\n");
783 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
784 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
785 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
786 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
788 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
789 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
791 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
792 DataSize
= ScsiPortGetBusData(DeviceExtension
,
794 ConfigInfo
->SystemIoBusNumber
,
795 SlotNumber
.u
.AsULONG
,
797 PCI_COMMON_HDR_LENGTH
);
798 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
802 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
804 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
805 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
810 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
812 /* We have found a known native pci ide controller */
813 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
815 DPRINT("Found IDE Bus Master controller!\n");
816 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
817 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
821 BusMasterBasePort
= 0;
824 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
825 ConfigInfo
->NumberOfBuses
= 1;
826 ConfigInfo
->MaximumNumberOfTargets
= 2;
827 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
830 We must not store and use the last tested slot number. If there is a recall
831 to the some device and we will claim the primary channel again than the call
832 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
833 claim the secondary channel.
835 ChannelFound
= FALSE
;
836 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
838 /* try to claim primary channel */
839 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
840 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
842 /* primary channel is enabled */
843 ChannelFound
= AtapiClaimHwResources(DevExt
,
846 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
847 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
849 PciConfig
.u
.type0
.InterruptLine
);
852 AtapiFindDevices(DevExt
, ConfigInfo
);
854 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
855 return SP_RETURN_FOUND
;
861 /* try to claim secondary channel */
862 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
863 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
865 /* secondary channel is enabled */
866 ChannelFound
= AtapiClaimHwResources(DevExt
,
869 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
870 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
871 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
872 PciConfig
.u
.type0
.InterruptLine
);
875 AtapiFindDevices(DevExt
, ConfigInfo
);
877 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
878 return SP_RETURN_FOUND
;
884 StartFunctionNumber
= 0;
887 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
888 DPRINT("AtapiFindNativePciController() done!\n");
890 return(SP_RETURN_NOT_FOUND
);
895 static BOOLEAN STDCALL
896 AtapiInitialize(IN PVOID DeviceExtension
)
902 static BOOLEAN STDCALL
903 AtapiResetBus(IN PVOID DeviceExtension
,
910 static BOOLEAN STDCALL
911 AtapiStartIo(IN PVOID DeviceExtension
,
912 IN PSCSI_REQUEST_BLOCK Srb
)
914 PATAPI_MINIPORT_EXTENSION DevExt
;
917 DPRINT("AtapiStartIo() called\n");
919 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
921 switch (Srb
->Function
)
923 case SRB_FUNCTION_EXECUTE_SCSI
:
924 DevExt
->CurrentSrb
= Srb
;
925 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
927 Result
= AtapiSendAtapiCommand(DevExt
,
932 Result
= AtapiSendIdeCommand(DevExt
,
937 case SRB_FUNCTION_ABORT_COMMAND
:
938 if (DevExt
->CurrentSrb
!= NULL
)
940 Result
= SRB_STATUS_ABORT_FAILED
;
944 Result
= SRB_STATUS_SUCCESS
;
948 case SRB_FUNCTION_IO_CONTROL
:
950 PSRB_IO_CONTROL SrbIoControl
= (PSRB_IO_CONTROL
)Srb
->DataBuffer
;
951 if (Srb
->DataTransferLength
< sizeof(SRB_IO_CONTROL
) ||
952 Srb
->DataTransferLength
< SrbIoControl
->Length
+ sizeof(SRB_IO_CONTROL
))
954 Result
= SRB_STATUS_INVALID_REQUEST
;
958 if (!_strnicmp((char*)SrbIoControl
->Signature
, "ScsiDisk", 8))
960 switch (SrbIoControl
->ControlCode
)
963 Result
= SRB_STATUS_INVALID_REQUEST
;
966 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
:
967 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
:
968 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
:
969 case IOCTL_SCSI_MINIPORT_ENABLE_SMART
:
970 case IOCTL_SCSI_MINIPORT_DISABLE_SMART
:
971 case IOCTL_SCSI_MINIPORT_RETURN_STATUS
:
972 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
:
973 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
:
974 case IOCTL_SCSI_MINIPORT_READ_SMART_LOG
:
976 case IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG
:
978 Result
= AtapiSendSmartCommand(DevExt
, Srb
);
981 case IOCTL_SCSI_MINIPORT_SMART_VERSION
:
983 GETVERSIONINPARAMS Version
;
986 DPRINT("IOCTL_SCSI_MINIPORT_SMART_VERSION\n");
988 RtlZeroMemory(&Version
, sizeof(GETVERSIONINPARAMS
));
989 Version
.bVersion
= 1;
990 Version
.bRevision
= 1;
991 for (i
= 0; i
< 2; i
++)
993 switch (DevExt
->DeviceFlags
[i
] & (DEVICE_PRESENT
|DEVICE_ATAPI
))
996 Version
.bIDEDeviceMap
|= 0x01 << i
;
999 case DEVICE_PRESENT|DEVICE_ATAPI:
1000 Version.bIDEDeviceMap |= 0x11 << i;
1005 Version
.fCapabilities
= CAP_ATA_ID_CMD
/*|CAP_ATAPI_ID_CMD|CAP_SMART_CMD*/;
1006 SrbIoControl
->Length
= min(sizeof(GETVERSIONINPARAMS
), Srb
->DataTransferLength
- sizeof(SRB_IO_CONTROL
));
1007 memcpy(SrbIoControl
+ 1, &Version
, SrbIoControl
->Length
);
1008 Result
= SRB_STATUS_SUCCESS
;
1012 case IOCTL_SCSI_MINIPORT_IDENTIFY
:
1014 SENDCMDOUTPARAMS OutParams
;
1015 SENDCMDINPARAMS InParams
= *(PSENDCMDINPARAMS
)(SrbIoControl
+ 1);
1017 DPRINT("IOCTL_SCSI_MINIPORT_IDENTIFY\n");
1019 if (Srb
->DataTransferLength
< sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDINPARAMS
) - 1)
1021 Result
= SRB_STATUS_INVALID_REQUEST
;
1025 RtlZeroMemory(&OutParams
, sizeof(SENDCMDOUTPARAMS
));
1027 if (InParams
.irDriveRegs
.bCommandReg
!= IDE_CMD_IDENT_ATA_DRV
)
1029 DPRINT("bCommandReg: %x\n", InParams
.irDriveRegs
.bCommandReg
);
1030 OutParams
.DriverStatus
.bIDEError
= 1;
1031 Result
= SRB_STATUS_INVALID_REQUEST
;
1033 else if (InParams
.bDriveNumber
> 1 ||
1034 (DevExt
->DeviceFlags
[InParams
.bDriveNumber
] & (DEVICE_PRESENT
|DEVICE_ATAPI
)) != DEVICE_PRESENT
)
1036 OutParams
.DriverStatus
.bIDEError
= 1;
1037 Result
= SRB_STATUS_NO_DEVICE
;
1041 Result
= SRB_STATUS_SUCCESS
;
1043 if (Result
== SRB_STATUS_SUCCESS
)
1045 SrbIoControl
->Length
= min(sizeof(SENDCMDOUTPARAMS
) - 1 + IDENTIFY_BUFFER_SIZE
, Srb
->DataTransferLength
- sizeof(SRB_IO_CONTROL
));
1049 SrbIoControl
->Length
= min(sizeof(SENDCMDOUTPARAMS
) - 1, Srb
->DataTransferLength
- sizeof(SRB_IO_CONTROL
));
1052 if (SrbIoControl
->Length
>= sizeof(SENDCMDOUTPARAMS
) - 1)
1054 OutParams
.cBufferSize
= min(SrbIoControl
->Length
, IDENTIFY_BUFFER_SIZE
);
1057 memcpy(SrbIoControl
+ 1, &OutParams
, min (SrbIoControl
->Length
, sizeof(SENDCMDOUTPARAMS
) - 1));
1059 if (SrbIoControl
->Length
> sizeof(SENDCMDOUTPARAMS
) - 1)
1061 RtlCopyMemory((PVOID
)((ULONG_PTR
)(SrbIoControl
+ 1) + sizeof(SENDCMDOUTPARAMS
) - 1), &DevExt
->DeviceParams
[InParams
.bDriveNumber
], OutParams
.cBufferSize
);
1069 Result
= SRB_STATUS_INVALID_REQUEST
;
1070 SrbIoControl
->Length
= 0;
1077 Result
= SRB_STATUS_INVALID_REQUEST
;
1081 Srb
->SrbStatus
= Result
;
1084 if (Result
!= SRB_STATUS_PENDING
)
1086 DevExt
->CurrentSrb
= NULL
;
1088 ScsiPortNotification(RequestComplete
,
1091 ScsiPortNotification(NextRequest
,
1097 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
1100 DPRINT("AtapiStartIo() done\n");
1105 static BOOLEAN STDCALL
1106 AtapiInterrupt(IN PVOID DeviceExtension
)
1108 PATAPI_MINIPORT_EXTENSION DevExt
;
1110 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
1112 if (DevExt
->Handler
== NULL
)
1114 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1115 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) != IDE_SR_DRDY
)
1117 static ULONG Count
= 0;
1119 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
1120 DevExt
->CommandPortBase
, Status
, Count
);
1127 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
1128 if (!(Status
& 0x04))
1136 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1137 if (Status
& IDE_SR_BUSY
)
1142 return DevExt
->Handler(DevExt
);
1145 // ---------------------------------------------------- Discardable statics
1149 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension
, ULONG UnitNumber
)
1151 BOOLEAN Result
= FALSE
;
1156 if (DeviceExtension
->PRDTable
)
1158 if (DeviceExtension
->DeviceParams
[UnitNumber
].Capabilities
& IDE_DRID_DMA_SUPPORTED
)
1160 if ((DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0004) &&
1161 (DeviceExtension
->DeviceParams
[UnitNumber
].UltraDmaModes
& 0x7F00))
1165 else if (DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0002)
1167 if ((DeviceExtension
->DeviceParams
[UnitNumber
].MultiDmaModes
& 0x0404) == 0x0404)
1173 * should we support single mode dma ?
1175 else if ((DeviceExtension
->DeviceParams
[UnitNumber
].DmaModes
& 0x0404) == 0x0404)
1181 Status
= IDEReadDMAStatus(DeviceExtension
->BusMasterRegisterBase
);
1184 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
| (UnitNumber
? 0x40 : 0x20));
1188 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
& (UnitNumber
? ~0x40 : ~0x20));
1197 /**********************************************************************
1202 * Searches for devices on the given port.
1209 * Port device specific information.
1212 * Port configuration information.
1215 * TRUE: At least one device is attached to the port.
1216 * FALSE: No device is attached to the port.
1220 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1221 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1223 BOOLEAN DeviceFound
= FALSE
;
1224 ULONG CommandPortBase
;
1225 ULONG ControlPortBase
;
1231 DPRINT("AtapiFindDevices() called\n");
1233 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
);
1234 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1236 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[1].RangeStart
);
1237 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1239 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1242 IDEWriteDriveHead(CommandPortBase
,
1243 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1244 ScsiPortStallExecution(500);
1246 /* Disable interrupts */
1247 IDEWriteDriveControl(ControlPortBase
,
1249 ScsiPortStallExecution(500);
1251 /* Check if a device is attached to the interface */
1252 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1253 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1255 High
= IDEReadCylinderHigh(CommandPortBase
);
1256 Low
= IDEReadCylinderLow(CommandPortBase
);
1258 IDEWriteCylinderHigh(CommandPortBase
, 0);
1259 IDEWriteCylinderLow(CommandPortBase
, 0);
1261 if (Low
!= 0x55 || High
!= 0xaa)
1263 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1267 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_RESET
, NULL
);
1269 for (Retries
= 0; Retries
< 20000; Retries
++)
1271 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1275 ScsiPortStallExecution(150);
1277 if (Retries
>= 20000)
1279 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1280 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1284 High
= IDEReadCylinderHigh(CommandPortBase
);
1285 Low
= IDEReadCylinderLow(CommandPortBase
);
1287 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1292 if (High
== 0xEB && Low
== 0x14)
1294 if (AtapiIdentifyDevice(CommandPortBase
,
1298 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1300 DPRINT(" ATAPI drive found!\n");
1301 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1302 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1303 DeviceExtension
->TransferSize
[UnitNumber
] =
1304 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1306 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1308 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1311 if (!(DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x1000) ||
1312 !(DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x1000))
1314 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1317 /* Don't flush CD/DVD drives */
1318 if (((DeviceExtension
->DeviceParams
[UnitNumber
].ConfigBits
>> 8) & 0x1F) == READ_ONLY_DIRECT_ACCESS_DEVICE
)
1320 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1326 DPRINT(" No ATAPI drive found!\n");
1331 if (AtapiIdentifyDevice(CommandPortBase
,
1335 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1337 DPRINT(" IDE drive found!\n");
1338 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1339 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1340 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1341 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1342 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1343 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1345 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1346 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1348 if (DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x0400 &&
1349 DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x0400)
1351 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_48BIT_ADDRESS
;
1353 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1355 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1358 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1360 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1363 if (DeviceExtension
->DeviceFlags
[UnitNumber
] & DEVICE_48BIT_ADDRESS
)
1365 if (!(DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x2000) ||
1366 !(DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x2000))
1368 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1373 if (!(DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x1000) ||
1374 !(DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x1000))
1376 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_NO_FLUSH
;
1383 DPRINT(" No IDE drive found!\n");
1388 /* Reset pending interrupts */
1389 IDEReadStatus(CommandPortBase
);
1390 /* Reenable interrupts */
1391 IDEWriteDriveControl(ControlPortBase
, 0);
1392 ScsiPortStallExecution(500);
1393 /* Return with drive 0 selected */
1394 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1395 ScsiPortStallExecution(500);
1397 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1399 return(DeviceFound
);
1404 * AtapiIdentifyDevice
1407 * Get the identification block from the drive
1414 * Address of the command port
1416 * Address of the control port
1418 * The drive index (0,1)
1420 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1422 * Address to write drive ident block
1425 * TRUE: The drive identification block was retrieved successfully
1426 * FALSE: an error ocurred
1430 AtapiIdentifyDevice(IN ULONG CommandPort
,
1431 IN ULONG ControlPort
,
1434 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1438 char SerialNumber
[20];
1439 char FirmwareRev
[8];
1440 char ModelNumber
[40];
1442 /* Get the Drive Identify block from drive or die */
1443 if (AtapiPolledRead(CommandPort
,
1450 (DriveNum
? IDE_DH_DRV1
: 0),
1451 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1452 (PUCHAR
)DrvParms
) == FALSE
)
1454 DPRINT("AtapiPolledRead() failed\n");
1458 /* Report on drive parameters if debug mode */
1459 memcpy(SerialNumber
, DrvParms
->SerialNumber
, 20);
1460 memcpy(FirmwareRev
, DrvParms
->FirmwareRev
, 8);
1461 memcpy(ModelNumber
, DrvParms
->ModelNumber
, 40);
1462 IDESwapBytePairs((PUCHAR
)SerialNumber
, 20);
1463 IDESwapBytePairs((PUCHAR
)FirmwareRev
, 8);
1464 IDESwapBytePairs((PUCHAR
)ModelNumber
, 40);
1465 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1466 DrvParms
->ConfigBits
,
1467 DrvParms
->LogicalCyls
,
1468 DrvParms
->LogicalHeads
,
1469 DrvParms
->SectorsPerTrack
,
1470 DrvParms
->InterSectorGap
,
1471 DrvParms
->InterSectorGapSize
);
1472 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1473 DrvParms
->BytesInPLO
,
1474 DrvParms
->VendorUniqueCnt
,
1476 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1477 DrvParms
->ControllerType
,
1478 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1479 DrvParms
->ECCByteCnt
,
1481 DPRINT("Model:[%.40s]\n", ModelNumber
);
1482 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1483 (DrvParms
->RWMultImplemented
),
1484 (DrvParms
->RWMultCurrent
) & 0xff,
1485 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1486 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1487 DrvParms
->MinPIOTransTime
,
1488 DrvParms
->MinDMATransTime
);
1489 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1490 DrvParms
->TMCylinders
,
1492 DrvParms
->TMSectorsPerTrk
,
1493 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1494 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1495 DrvParms
->TMSectorCountHi
,
1496 DrvParms
->TMSectorCountLo
,
1497 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1498 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms
->SupportedFeatures83
, DrvParms
->EnabledFeatures86
);
1499 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG
)DrvParms
->Max48BitAddress
);
1500 if (DrvParms
->TMFieldsValid
& 0x0004)
1502 if ((DrvParms
->UltraDmaModes
>> 8) && (DrvParms
->UltraDmaModes
& 0xff))
1505 while (!(DrvParms
->UltraDmaModes
& (0x0100 << mode
)))
1509 DPRINT("Ultra DMA mode %d is selected\n", mode
);
1511 else if ((DrvParms
->MultiDmaModes
>> 8) & (DrvParms
->MultiDmaModes
& 0x07))
1514 while(!(DrvParms
->MultiDmaModes
& (0x01 << mode
)))
1518 DPRINT("Multi DMA mode %d is selected\n", mode
);
1522 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1524 /* LBA ATA drives always have a sector size of 512 */
1525 DrvParms
->BytesPerSector
= 512;
1529 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1530 if (DrvParms
->BytesPerSector
== 0)
1532 DrvParms
->BytesPerSector
= 512;
1536 for (i
= 15; i
>= 0; i
--)
1538 if (DrvParms
->BytesPerSector
& (1 << i
))
1540 DrvParms
->BytesPerSector
= 1 << i
;
1546 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1555 // Read a sector of data from the drive in a polled fashion.
1561 // IN ULONG CommandPort Address of command port for drive
1562 // IN ULONG ControlPort Address of control port for drive
1563 // IN UCHAR PreComp Value to write to precomp register
1564 // IN UCHAR SectorCnt Value to write to sectorCnt register
1565 // IN UCHAR SectorNum Value to write to sectorNum register
1566 // IN UCHAR CylinderLow Value to write to CylinderLow register
1567 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1568 // IN UCHAR DrvHead Value to write to Drive/Head register
1569 // IN UCHAR Command Value to write to Command register
1570 // OUT PUCHAR Buffer Buffer for output data
1573 // BOOLEAN: TRUE success, FALSE error
1577 AtapiPolledRead(IN ULONG CommandPort
,
1578 IN ULONG ControlPort
,
1582 IN UCHAR CylinderLow
,
1583 IN UCHAR CylinderHigh
,
1588 ULONG SectorCount
= 0;
1590 BOOLEAN Junk
= FALSE
;
1593 /* Wait for BUSY to clear */
1594 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1596 Status
= IDEReadStatus(CommandPort
);
1597 if (!(Status
& IDE_SR_BUSY
))
1601 ScsiPortStallExecution(10);
1603 DPRINT("status=%02x\n", Status
);
1604 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1605 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1607 DPRINT("Drive is BUSY for too long\n");
1611 /* Write Drive/Head to select drive */
1612 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1613 ScsiPortStallExecution(500);
1615 /* Disable interrupts */
1616 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1617 ScsiPortStallExecution(500);
1620 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1621 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1623 Status
= IDEReadStatus(CommandPort
);
1624 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1628 ScsiPortStallExecution(10);
1630 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1636 /* Issue command to drive */
1637 if (DrvHead
& IDE_DH_LBA
)
1639 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1640 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1641 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1647 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1648 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1657 /* Setup command parameters */
1658 IDEWritePrecomp(CommandPort
, PreComp
);
1659 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1660 IDEWriteSectorNum(CommandPort
, SectorNum
);
1661 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1662 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1663 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1665 /* Issue the command */
1666 IDEWriteCommand(CommandPort
, Command
);
1667 ScsiPortStallExecution(50);
1669 /* wait for DRQ or error */
1670 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1672 Status
= IDEReadStatus(CommandPort
);
1673 if (!(Status
& IDE_SR_BUSY
))
1675 if (Status
& IDE_SR_ERR
)
1677 IDEWriteDriveControl(ControlPort
, 0);
1678 ScsiPortStallExecution(50);
1679 IDEReadStatus(CommandPort
);
1684 if (Status
& IDE_SR_DRQ
)
1690 IDEWriteDriveControl(ControlPort
, 0);
1691 ScsiPortStallExecution(50);
1692 IDEReadStatus(CommandPort
);
1697 ScsiPortStallExecution(10);
1701 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1703 IDEWriteDriveControl(ControlPort
, 0);
1704 ScsiPortStallExecution(50);
1705 IDEReadStatus(CommandPort
);
1712 /* Read data into buffer */
1715 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1716 Buffer
+= IDE_SECTOR_BUF_SZ
;
1720 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1721 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1725 /* Check for error or more sectors to read */
1726 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1728 Status
= IDEReadStatus(CommandPort
);
1729 if (!(Status
& IDE_SR_BUSY
))
1731 if (Status
& IDE_SR_ERR
)
1733 IDEWriteDriveControl(ControlPort
, 0);
1734 ScsiPortStallExecution(50);
1735 IDEReadStatus(CommandPort
);
1739 if (Status
& IDE_SR_DRQ
)
1741 if (SectorCount
>= SectorCnt
)
1743 DPRINT("Buffer size exceeded!\n");
1750 if (SectorCount
> SectorCnt
)
1752 DPRINT("Read %lu sectors of junk!\n",
1753 SectorCount
- SectorCnt
);
1755 IDEWriteDriveControl(ControlPort
, 0);
1756 ScsiPortStallExecution(50);
1757 IDEReadStatus(CommandPort
);
1767 // ------------------------------------------- Nondiscardable statics
1770 AtapiSendSmartCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1771 IN PSCSI_REQUEST_BLOCK Srb
)
1773 PSRB_IO_CONTROL SrbIoControl
= (PSRB_IO_CONTROL
)Srb
->DataBuffer
;
1774 SENDCMDINPARAMS InParams
;
1775 PSENDCMDOUTPARAMS OutParams
= (PSENDCMDOUTPARAMS
)(SrbIoControl
+ 1);
1779 if (Srb
->DataTransferLength
< sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
) - 1 ||
1780 SrbIoControl
->Length
< sizeof(SENDCMDOUTPARAMS
) - 1)
1782 return SRB_STATUS_INVALID_REQUEST
;
1784 InParams
= *(PSENDCMDINPARAMS
)(SrbIoControl
+ 1);
1786 DPRINT("%02x %02x %02x %02x %02x %02x %02x %02x\n",
1787 InParams
.irDriveRegs
.bFeaturesReg
,
1788 InParams
.irDriveRegs
.bSectorCountReg
,
1789 InParams
.irDriveRegs
.bSectorNumberReg
,
1790 InParams
.irDriveRegs
.bCylLowReg
,
1791 InParams
.irDriveRegs
.bCylHighReg
,
1792 InParams
.irDriveRegs
.bDriveHeadReg
,
1793 InParams
.irDriveRegs
.bCommandReg
,
1794 InParams
.irDriveRegs
.bReserved
);
1796 if (InParams
.bDriveNumber
> 1 ||
1797 (DeviceExtension
->DeviceFlags
[InParams
.bDriveNumber
] & (DEVICE_PRESENT
|DEVICE_ATAPI
)) != DEVICE_PRESENT
)
1799 RtlZeroMemory(&OutParams
, sizeof(SENDCMDOUTPARAMS
));
1800 OutParams
->DriverStatus
.bIDEError
= 1;
1801 return SRB_STATUS_NO_DEVICE
;
1804 DeviceExtension
->DataTransferLength
= 0;
1806 switch (SrbIoControl
->ControlCode
)
1808 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
:
1809 DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS\n");
1811 if (Srb
->DataTransferLength
< sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
) - 1 + READ_ATTRIBUTE_BUFFER_SIZE
||
1812 SrbIoControl
->Length
< sizeof(SENDCMDOUTPARAMS
) - 1 + READ_ATTRIBUTE_BUFFER_SIZE
||
1813 InParams
.irDriveRegs
.bFeaturesReg
!= READ_ATTRIBUTES
||
1814 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1815 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1816 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1818 return SRB_STATUS_INVALID_REQUEST
;
1820 InParams
.irDriveRegs
.bSectorCountReg
= 0;
1821 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1822 DeviceExtension
->DataTransferLength
= READ_ATTRIBUTE_BUFFER_SIZE
;
1825 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
:
1826 DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS\n");
1828 if (Srb
->DataTransferLength
< sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
) - 1 + READ_THRESHOLD_BUFFER_SIZE
||
1829 SrbIoControl
->Length
< sizeof(SENDCMDOUTPARAMS
) - 1 + READ_THRESHOLD_BUFFER_SIZE
||
1830 InParams
.irDriveRegs
.bFeaturesReg
!= READ_THRESHOLDS
||
1831 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1832 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1833 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1835 return SRB_STATUS_INVALID_REQUEST
;
1837 InParams
.irDriveRegs
.bSectorCountReg
= 0;
1838 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1839 DeviceExtension
->DataTransferLength
= READ_THRESHOLD_BUFFER_SIZE
;
1842 case IOCTL_SCSI_MINIPORT_READ_SMART_LOG
:
1843 DPRINT("IOCTL_SCSI_MINIPORT_READ_SMART_LOG\n");
1845 if (Srb
->DataTransferLength
< sizeof(SRB_IO_CONTROL
) + sizeof(SENDCMDOUTPARAMS
) - 1 + max(1, InParams
.irDriveRegs
.bSectorCountReg
) * SMART_LOG_SECTOR_SIZE
||
1846 SrbIoControl
->Length
< sizeof(SENDCMDOUTPARAMS
) - 1 + max(1, InParams
.irDriveRegs
.bSectorCountReg
) * SMART_LOG_SECTOR_SIZE
||
1847 InParams
.irDriveRegs
.bFeaturesReg
!= SMART_READ_LOG
||
1848 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1849 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1850 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1852 return SRB_STATUS_INVALID_REQUEST
;
1854 DeviceExtension
->DataTransferLength
= max(1, InParams
.irDriveRegs
.bSectorCountReg
) * SMART_LOG_SECTOR_SIZE
;
1857 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
:
1858 DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE\n");
1860 if (InParams
.irDriveRegs
.bFeaturesReg
!= ENABLE_DISABLE_AUTOSAVE
||
1861 (InParams
.irDriveRegs
.bSectorCountReg
!= 0 && InParams
.irDriveRegs
.bSectorCountReg
!= 1) ||
1862 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1863 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1864 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1866 return SRB_STATUS_INVALID_REQUEST
;
1868 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1871 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
:
1872 DPRINT("IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES\n");
1874 if (InParams
.irDriveRegs
.bFeaturesReg
!= SAVE_ATTRIBUTE_VALUES
||
1875 (InParams
.irDriveRegs
.bSectorCountReg
!= 0 && InParams
.irDriveRegs
.bSectorCountReg
!= 0xf1) ||
1876 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1877 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1878 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1880 return SRB_STATUS_INVALID_REQUEST
;
1882 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1885 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
:
1886 DPRINT("IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS\n");
1888 if (InParams
.irDriveRegs
.bFeaturesReg
!= EXECUTE_OFFLINE_DIAGS
||
1889 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1890 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1891 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1893 return SRB_STATUS_INVALID_REQUEST
;
1895 InParams
.irDriveRegs
.bSectorCountReg
= 0;
1898 case IOCTL_SCSI_MINIPORT_ENABLE_SMART
:
1899 DPRINT("IOCTL_SCSI_MINIPORT_ENABLE_SMART\n");
1901 if (InParams
.irDriveRegs
.bFeaturesReg
!= ENABLE_SMART
||
1902 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1903 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1904 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1906 return SRB_STATUS_INVALID_REQUEST
;
1908 InParams
.irDriveRegs
.bSectorCountReg
= 0;
1909 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1912 case IOCTL_SCSI_MINIPORT_DISABLE_SMART
:
1913 DPRINT("IOCTL_SCSI_MINIPORT_DISABLE_SMART\n");
1915 if (InParams
.irDriveRegs
.bFeaturesReg
!= DISABLE_SMART
||
1916 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1917 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1918 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1920 return SRB_STATUS_INVALID_REQUEST
;
1922 InParams
.irDriveRegs
.bSectorCountReg
= 0;
1923 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1926 case IOCTL_SCSI_MINIPORT_RETURN_STATUS
:
1927 DPRINT("IOCTL_SCSI_MINIPORT_RETURN_STATUS\n");
1929 if (InParams
.irDriveRegs
.bFeaturesReg
!= RETURN_SMART_STATUS
||
1930 InParams
.irDriveRegs
.bCylLowReg
!= SMART_CYL_LOW
||
1931 InParams
.irDriveRegs
.bCylHighReg
!= SMART_CYL_HI
||
1932 InParams
.irDriveRegs
.bCommandReg
!= SMART_CMD
)
1934 return SRB_STATUS_INVALID_REQUEST
;
1936 InParams
.irDriveRegs
.bSectorCountReg
= 0;
1937 InParams
.irDriveRegs
.bSectorNumberReg
= 0;
1941 Srb
->TargetId
= InParams
.bDriveNumber
;
1943 /* Set pointer to data buffer. */
1944 DeviceExtension
->DataBuffer
= (PUCHAR
)OutParams
->bBuffer
;
1946 DeviceExtension
->CurrentSrb
= Srb
;
1948 /* wait for BUSY to clear */
1949 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1951 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1952 if (!(Status
& IDE_SR_BUSY
))
1956 ScsiPortStallExecution(10);
1958 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1960 DPRINT ("Drive is BUSY for too long\n");
1961 return(SRB_STATUS_BUSY
);
1964 /* Select the desired drive */
1965 InParams
.irDriveRegs
.bDriveHeadReg
= (InParams
.bDriveNumber
? IDE_DH_DRV1
: IDE_DH_DRV0
) | IDE_DH_FIXED
;
1966 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, InParams
.irDriveRegs
.bDriveHeadReg
);
1967 ScsiPortStallExecution(2);
1969 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, InParams
.irDriveRegs
.bFeaturesReg
);
1970 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, InParams
.irDriveRegs
.bSectorCountReg
);
1971 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, InParams
.irDriveRegs
.bSectorNumberReg
);
1972 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, InParams
.irDriveRegs
.bCylLowReg
);
1973 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, InParams
.irDriveRegs
.bCylHighReg
);
1975 AtapiExecuteCommand(DeviceExtension
, InParams
.irDriveRegs
.bCommandReg
, AtapiSmartInterrupt
);
1977 /* Wait for interrupt. */
1978 return SRB_STATUS_PENDING
;
1983 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1984 IN PSCSI_REQUEST_BLOCK Srb
)
1986 UCHAR ByteCountHigh
;
1992 DPRINT("AtapiSendAtapiCommand() called!\n");
1994 if (Srb
->PathId
!= 0)
1996 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1997 return(SRB_STATUS_INVALID_PATH_ID
);
2000 if (Srb
->TargetId
> 1)
2002 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2003 return(SRB_STATUS_INVALID_TARGET_ID
);
2008 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2009 return(SRB_STATUS_INVALID_LUN
);
2012 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
2014 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2015 return(SRB_STATUS_NO_DEVICE
);
2018 if (Srb
->Cdb
[0] == SCSIOP_MODE_SENSE
)
2020 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2021 return (SRB_STATUS_INVALID_REQUEST
);
2024 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
2027 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
2028 return(AtapiInquiry(DeviceExtension
,
2031 /* Set pointer to data buffer. */
2032 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2033 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2034 DeviceExtension
->CurrentSrb
= Srb
;
2036 DPRINT("BufferAddress %x, BufferLength %d\n", Srb
->DataBuffer
, Srb
->DataTransferLength
);
2038 /* Wait for BUSY to clear */
2039 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2041 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2042 if (!(Status
& IDE_SR_BUSY
))
2046 ScsiPortStallExecution(10);
2048 DPRINT("status=%02x\n", Status
);
2049 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2050 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2052 DPRINT("Drive is BUSY for too long\n");
2053 return(SRB_STATUS_BUSY
);
2056 /* Select the desired drive */
2057 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2058 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2060 /* Wait a little while */
2061 ScsiPortStallExecution(50);
2064 /* Wait for BUSY to clear and DRDY to assert */
2065 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2067 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2068 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2072 ScsiPortStallExecution(10);
2074 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2075 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2077 DPRINT("Drive is BUSY for too long after drive select\n");
2078 return(SRB_STATUS_BUSY
);
2083 if ((DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
) &&
2084 (Srb
->Cdb
[0] == SCSIOP_READ
|| Srb
->Cdb
[0] == SCSIOP_WRITE
))
2086 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2090 DeviceExtension
->UseDma
= FALSE
;
2094 if (DeviceExtension
->DataTransferLength
< 0x10000)
2096 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
2097 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
2101 ByteCountLow
= 0xFF;
2102 ByteCountHigh
= 0xFF;
2105 /* Set feature register */
2107 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, DeviceExtension
->UseDma
? 1 : 0);
2109 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2112 /* Set command packet length */
2113 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
2114 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
2116 /* Issue command to drive */
2118 if (DeviceExtension
->UseDma
)
2120 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiDmaPacketInterrupt
);
2125 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiPacketInterrupt
);
2128 /* Wait for DRQ to assert */
2129 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2131 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2132 if ((Status
& IDE_SR_DRQ
))
2136 ScsiPortStallExecution(10);
2139 /* Convert special SCSI SRBs to ATAPI format */
2140 switch (Srb
->Cdb
[0])
2142 case SCSIOP_FORMAT_UNIT
:
2143 case SCSIOP_MODE_SELECT
:
2144 AtapiScsiSrbToAtapi (Srb
);
2148 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
2149 DPRINT("CdbSize: %lu\n", CdbSize
);
2151 /* Write command packet */
2152 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2157 if (DeviceExtension
->UseDma
)
2161 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2162 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2165 DPRINT("AtapiSendAtapiCommand() done\n");
2167 return(SRB_STATUS_PENDING
);
2172 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2173 IN PSCSI_REQUEST_BLOCK Srb
)
2175 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
2177 DPRINT("AtapiSendIdeCommand() called!\n");
2179 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
2184 if (Srb
->PathId
!= 0)
2186 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
2187 return(SRB_STATUS_INVALID_PATH_ID
);
2190 if (Srb
->TargetId
> 1)
2192 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2193 return(SRB_STATUS_INVALID_TARGET_ID
);
2198 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2199 return(SRB_STATUS_INVALID_LUN
);
2202 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
2204 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2205 return(SRB_STATUS_NO_DEVICE
);
2208 switch (Srb
->Cdb
[0])
2210 case SCSIOP_INQUIRY
:
2211 SrbStatus
= AtapiInquiry(DeviceExtension
,
2215 case SCSIOP_READ_CAPACITY
:
2216 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
2222 SrbStatus
= AtapiReadWrite(DeviceExtension
,
2226 case SCSIOP_SYNCHRONIZE_CACHE
:
2227 SrbStatus
= AtapiFlushCache(DeviceExtension
,
2231 case SCSIOP_TEST_UNIT_READY
:
2232 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
2236 case SCSIOP_MODE_SENSE
:
2239 case SCSIOP_START_STOP_UNIT
:
2240 case SCSIOP_REQUEST_SENSE
:
2244 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
2246 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
2250 DPRINT("AtapiSendIdeCommand() done!\n");
2257 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2258 PSCSI_REQUEST_BLOCK Srb
)
2260 PIDE_DRIVE_IDENTIFY DeviceParams
;
2261 PINQUIRYDATA InquiryData
;
2263 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
2264 DeviceExtension
, Srb
->TargetId
);
2266 InquiryData
= Srb
->DataBuffer
;
2267 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2270 memset(Srb
->DataBuffer
, 0, Srb
->DataTransferLength
);
2272 /* set device class */
2273 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2275 /* get it from the ATAPI configuration word */
2276 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
2277 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
2282 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
2285 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
2286 if (DeviceParams
->ConfigBits
& 0x80)
2288 DPRINT("Removable media!\n");
2289 InquiryData
->RemovableMedia
= 1;
2292 memcpy(InquiryData
->VendorId
, DeviceParams
->ModelNumber
, 20);
2293 IDESwapBytePairs(InquiryData
->VendorId
, 20);
2295 memcpy(&InquiryData
->ProductId
[12], " ", 4);
2297 memcpy(InquiryData
->ProductRevisionLevel
, DeviceParams
->FirmwareRev
, 4);
2298 IDESwapBytePairs(InquiryData
->ProductRevisionLevel
, 4);
2300 InquiryData
->AdditionalLength
= 31;
2302 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
2304 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2305 return(SRB_STATUS_SUCCESS
);
2310 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2311 PSCSI_REQUEST_BLOCK Srb
)
2313 PREAD_CAPACITY_DATA CapacityData
;
2314 PIDE_DRIVE_IDENTIFY DeviceParams
;
2315 LARGE_INTEGER LastSector
;
2317 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
2318 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
2319 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2321 /* Set sector (block) size to 512 bytes (big-endian). */
2322 CapacityData
->BytesPerBlock
= 0x20000;
2324 /* Calculate last sector (big-endian). */
2325 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2327 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2329 ((PUSHORT
)&LastSector
)[0] = DeviceParams
->Max48BitAddress
[0];
2330 ((PUSHORT
)&LastSector
)[1] = DeviceParams
->Max48BitAddress
[1];
2331 ((PUSHORT
)&LastSector
)[2] = DeviceParams
->Max48BitAddress
[2];
2332 ((PUSHORT
)&LastSector
)[3] = DeviceParams
->Max48BitAddress
[3];
2333 LastSector
.QuadPart
-= 1;
2338 LastSector
.u
.HighPart
= 0;
2339 LastSector
.u
.LowPart
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
2340 DeviceParams
->TMSectorCountLo
)-1;
2345 LastSector
.u
.HighPart
= 0;
2346 LastSector
.u
.LowPart
= (ULONG
)(DeviceParams
->LogicalCyls
*
2347 DeviceParams
->LogicalHeads
*
2348 DeviceParams
->SectorsPerTrack
)-1;
2350 if (LastSector
.u
.HighPart
)
2352 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector
.QuadPart
);
2356 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
2357 (((PUCHAR
)&LastSector
)[1] << 16) |
2358 (((PUCHAR
)&LastSector
)[2] << 8) |
2359 ((PUCHAR
)&LastSector
)[3];
2361 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2364 CapacityData
->LogicalBlockAddress
);
2366 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2367 return(SRB_STATUS_SUCCESS
);
2372 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2373 PSCSI_REQUEST_BLOCK Srb
)
2375 PIDE_DRIVE_IDENTIFY DeviceParams
;
2376 ULONG StartingSector
;
2378 UCHAR CylinderHigh
[2];
2379 UCHAR CylinderLow
[2];
2381 UCHAR SectorNumber
[2];
2385 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION DevExt
);
2387 DPRINT("AtapiReadWrite() called!\n");
2388 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2391 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2393 /* Get starting sector number from CDB. */
2394 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2395 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2396 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2397 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2399 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2400 DeviceParams
->BytesPerSector
;
2402 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2404 Srb
->DataTransferLength
,
2407 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2409 SectorNumber
[0] = StartingSector
& 0xff;
2410 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2411 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2412 SectorNumber
[1] = (StartingSector
>> 24) & 0xff;
2414 CylinderHigh
[1] = 0;
2415 DrvHead
= (Srb
->TargetId
? IDE_DH_DRV1
: 0) | IDE_DH_LBA
;
2417 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2418 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2419 DeviceExtension
->CommandPortBase
,
2420 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2421 (SectorNumber
[1] << 24) +
2422 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + DectorNumberLow
[0],
2427 else if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2429 SectorNumber
[0] = StartingSector
& 0xff;
2430 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2431 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2432 SectorNumber
[1] = 0;
2434 CylinderHigh
[1] = 0;
2435 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2436 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2439 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2440 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2441 DeviceExtension
->CommandPortBase
,
2442 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2443 ((DrvHead
& 0x0f) << 24) +
2444 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + SectorNumber
[0],
2450 SectorNumber
[0] = (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2451 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2452 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2453 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2454 StartingSector
/= DeviceParams
->LogicalHeads
;
2455 CylinderLow
[0] = StartingSector
& 0xff;
2456 CylinderHigh
[0] = StartingSector
>> 8;
2457 SectorNumber
[1] = 0;
2459 CylinderHigh
[1] = 0;
2461 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2462 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2463 DeviceExtension
->CommandPortBase
,
2464 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2473 /* Set pointer to data buffer. */
2474 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2475 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2477 DeviceExtension
->CurrentSrb
= Srb
;
2479 /* wait for BUSY to clear */
2480 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2482 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2483 if (!(Status
& IDE_SR_BUSY
))
2487 ScsiPortStallExecution(10);
2489 DPRINT("status=%02x\n", Status
);
2490 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2491 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2493 DPRINT ("Drive is BUSY for too long\n");
2494 return(SRB_STATUS_BUSY
);
2497 /* Select the desired drive */
2498 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2499 IDE_DH_FIXED
| DrvHead
);
2501 ScsiPortStallExecution(10);
2503 /* wait for BUSY to clear and DRDY to assert */
2504 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2506 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2507 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2511 ScsiPortStallExecution(10);
2513 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2514 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2516 DPRINT("Drive is BUSY for too long after drive select\n");
2517 return(SRB_STATUS_BUSY
);
2521 /* Setup command parameters */
2522 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2524 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2525 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
>> 8);
2526 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[1]);
2527 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[1]);
2528 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[1]);
2531 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2532 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
& 0xff);
2533 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[0]);
2534 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[0]);
2535 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[0]);
2538 if (DeviceExtension
->PRDTable
&&
2539 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
)
2541 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2543 if (DeviceExtension
->UseDma
)
2545 Handler
= AtapiDmaInterrupt
;
2546 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2548 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA_EXT
: IDE_CMD_WRITE_DMA_EXT
;
2552 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA
: IDE_CMD_WRITE_DMA
;
2558 Handler
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? AtapiReadInterrupt
: AtapiWriteInterrupt
;
2559 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
)
2561 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2563 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE_EXT
: IDE_CMD_WRITE_MULTIPLE_EXT
;
2567 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE
: IDE_CMD_WRITE_MULTIPLE
;
2572 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2574 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_EXT
: IDE_CMD_WRITE_EXT
;
2578 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ
: IDE_CMD_WRITE
;
2583 AtapiExecuteCommand(DeviceExtension
, Command
, Handler
);
2586 if (DeviceExtension
->UseDma
)
2590 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2591 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2596 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2598 /* Write data block */
2599 PUCHAR TargetAddress
;
2602 /* Wait for controller ready */
2603 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2605 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2606 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2610 ScsiPortStallExecution(10);
2612 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2614 DPRINT1("Drive is BUSY for too long after sending write command\n");
2615 return(SRB_STATUS_BUSY
);
2618 /* Update DeviceExtension data */
2619 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2620 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2622 TransferSize
= DeviceExtension
->DataTransferLength
;
2625 TargetAddress
= DeviceExtension
->DataBuffer
;
2626 DeviceExtension
->DataBuffer
+= TransferSize
;
2627 DeviceExtension
->DataTransferLength
-= TransferSize
;
2629 /* Write data block */
2630 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2632 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2638 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2645 DPRINT("AtapiReadWrite() done!\n");
2647 /* Wait for interrupt. */
2648 return(SRB_STATUS_PENDING
);
2653 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2654 PSCSI_REQUEST_BLOCK Srb
)
2659 DPRINT("AtapiFlushCache() called!\n");
2660 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2663 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_NO_FLUSH
)
2666 * NOTE: Don't flush the cache for CD/DVD drives. Although
2667 * the ATAPI-6 standard allows that, it has been experimentally
2668 * proved that it can damage some broken LG drives. Afterall
2669 * it doesn't make sense to flush cache on devices we don't
2673 /* The device states it doesn't support the command or it is disabled */
2674 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2675 return SRB_STATUS_INVALID_REQUEST
;
2678 /* Wait for BUSY to clear */
2679 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2681 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2682 if (!(Status
& IDE_SR_BUSY
))
2686 ScsiPortStallExecution(10);
2688 DPRINT("Status=%02x\n", Status
);
2689 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2690 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2692 DPRINT1("Drive is BUSY for too long\n");
2693 return(SRB_STATUS_BUSY
);
2696 /* Select the desired drive */
2697 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2698 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2699 ScsiPortStallExecution(10);
2701 /* Issue command to drive */
2702 AtapiExecuteCommand(DeviceExtension
,
2703 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
? IDE_CMD_FLUSH_CACHE_EXT
: IDE_CMD_FLUSH_CACHE
,
2704 AtapiNoDataInterrupt
);
2707 DPRINT("AtapiFlushCache() done!\n");
2709 /* Wait for interrupt. */
2710 return(SRB_STATUS_PENDING
);
2715 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2716 PSCSI_REQUEST_BLOCK Srb
)
2722 DPRINT1("AtapiTestUnitReady() called!\n");
2724 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2727 /* Return success if media status is not supported */
2728 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2730 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2731 return(SRB_STATUS_SUCCESS
);
2734 /* Wait for BUSY to clear */
2735 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2737 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2738 if (!(Status
& IDE_SR_BUSY
))
2742 ScsiPortStallExecution(10);
2744 DPRINT1("Status=%02x\n", Status
);
2745 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2746 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2748 DPRINT1("Drive is BUSY for too long\n");
2749 return(SRB_STATUS_BUSY
);
2752 /* Select the desired drive */
2753 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2754 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2755 ScsiPortStallExecution(10);
2757 /* Issue command to drive */
2758 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2760 /* Wait for controller ready */
2761 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2763 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2764 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2768 ScsiPortStallExecution(10);
2770 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2772 DPRINT1("Drive is BUSY for too long after sending write command\n");
2773 DeviceExtension
->Handler
= NULL
;
2774 return(SRB_STATUS_BUSY
);
2777 if (Status
& IDE_SR_ERR
)
2779 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2780 if (Error
== IDE_ER_UNC
)
2783 /* Handle write protection 'error' */
2784 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2785 DeviceExtension
->Handler
= NULL
;
2786 return(SRB_STATUS_SUCCESS
);
2791 /* Indicate expecting an interrupt. */
2792 return(SRB_STATUS_PENDING
);
2796 DeviceExtension
->Handler
= NULL
;
2798 DPRINT1("AtapiTestUnitReady() done!\n");
2800 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2801 return(SRB_STATUS_SUCCESS
);
2806 AtapiErrorToScsi(PVOID DeviceExtension
,
2807 PSCSI_REQUEST_BLOCK Srb
)
2809 PATAPI_MINIPORT_EXTENSION DevExt
;
2810 ULONG CommandPortBase
;
2811 ULONG ControlPortBase
;
2816 DPRINT("AtapiErrorToScsi() called\n");
2818 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2820 CommandPortBase
= DevExt
->CommandPortBase
;
2821 ControlPortBase
= DevExt
->ControlPortBase
;
2823 ErrorReg
= IDEReadError(CommandPortBase
);
2825 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2827 switch (ErrorReg
>> 4)
2829 case SCSI_SENSE_NO_SENSE
:
2830 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2831 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2832 SrbStatus
= SRB_STATUS_ERROR
;
2835 case SCSI_SENSE_RECOVERED_ERROR
:
2836 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2838 SrbStatus
= SRB_STATUS_SUCCESS
;
2841 case SCSI_SENSE_NOT_READY
:
2842 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2843 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2844 SrbStatus
= SRB_STATUS_ERROR
;
2847 case SCSI_SENSE_MEDIUM_ERROR
:
2848 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2849 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2850 SrbStatus
= SRB_STATUS_ERROR
;
2853 case SCSI_SENSE_HARDWARE_ERROR
:
2854 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2855 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2856 SrbStatus
= SRB_STATUS_ERROR
;
2859 case SCSI_SENSE_ILLEGAL_REQUEST
:
2860 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2861 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2862 SrbStatus
= SRB_STATUS_ERROR
;
2865 case SCSI_SENSE_UNIT_ATTENTION
:
2866 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2867 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2868 SrbStatus
= SRB_STATUS_ERROR
;
2871 case SCSI_SENSE_DATA_PROTECT
:
2872 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2873 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2874 SrbStatus
= SRB_STATUS_ERROR
;
2877 case SCSI_SENSE_BLANK_CHECK
:
2878 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2879 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2880 SrbStatus
= SRB_STATUS_ERROR
;
2883 case SCSI_SENSE_ABORTED_COMMAND
:
2884 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2885 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2886 SrbStatus
= SRB_STATUS_ERROR
;
2890 DPRINT("ATAPI error: Invalid sense key\n");
2892 SrbStatus
= SRB_STATUS_ERROR
;
2898 DPRINT1("IDE error: %02x\n", ErrorReg
);
2901 SrbStatus
= SRB_STATUS_ERROR
;
2904 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2907 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2908 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2909 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2910 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2911 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2913 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2924 Srb
->ScsiStatus
= ScsiStatus
;
2926 DPRINT("AtapiErrorToScsi() done\n");
2933 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2935 DPRINT("AtapiConvertScsiToAtapi() called\n");
2937 Srb
->CdbLength
= 12;
2939 switch (Srb
->Cdb
[0])
2941 case SCSIOP_FORMAT_UNIT
:
2942 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2945 case SCSIOP_MODE_SELECT
:
2947 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2950 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2951 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2953 RtlZeroMemory (Srb
->Cdb
,
2955 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2956 AtapiModeSelect
->PFBit
= 1;
2957 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2958 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2964 static VOID FASTCALL
2965 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2968 PSCSI_REQUEST_BLOCK Srb
;
2969 Srb
= DevExt
->CurrentSrb
;
2971 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2973 Srb
->SrbStatus
= SrbStatus
;
2974 if (SrbStatus
== SRB_STATUS_ERROR
)
2976 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2978 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2980 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2983 DevExt
->Handler
= NULL
;
2984 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2985 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2989 static BOOLEAN FASTCALL
2990 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2999 DPRINT("AtapiPacketDmaInterrupt\n");
3001 DevExt
->UseDma
= FALSE
;
3004 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
3005 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
3006 /* get DMA status */
3007 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3008 /* clear the INTR & ERROR bits */
3009 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
3011 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
3012 DPRINT("DriveStatus: %x\n", Status
);
3014 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
3016 if (Status
& IDE_SR_ERR
)
3018 Error
= IDEReadError(DevExt
->CommandPortBase
);
3019 SensKey
= Error
>> 4;
3020 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
3022 SrbStatus
= SRB_STATUS_ERROR
;
3026 if ((DmaStatus
& 0x07) != 0x04)
3028 DPRINT("DmaStatus: %02x\n", DmaStatus
);
3029 SrbStatus
= SRB_STATUS_ERROR
;
3033 SrbStatus
= STATUS_SUCCESS
;
3036 AtapiCompleteRequest(DevExt
, SrbStatus
);
3037 DPRINT("AtapiDmaPacketInterrupt() done\n");
3042 static BOOLEAN FASTCALL
3043 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
3045 PSCSI_REQUEST_BLOCK Srb
;
3051 PBYTE TargetAddress
;
3057 DPRINT("AtapiPacketInterrupt()\n");
3059 Srb
= DevExt
->CurrentSrb
;
3061 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
3062 DPRINT("DriveStatus: %x\n", Status
);
3064 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
3066 if (Status
& IDE_SR_ERR
)
3068 Error
= IDEReadError(DevExt
->CommandPortBase
);
3069 SensKey
= Error
>> 4;
3070 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
3073 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
3074 DPRINT("AtapiPacketInterrupt() done\n");
3078 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
3079 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
3080 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
3082 if (!(Status
& IDE_SR_DRQ
))
3084 if (DevExt
->DataTransferLength
> 0)
3086 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
3087 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
3088 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
3092 SrbStatus
= SRB_STATUS_SUCCESS
;
3094 AtapiCompleteRequest(DevExt
, SrbStatus
);
3095 DPRINT("AtapiPacketInterrupt() done\n");
3099 TargetAddress
= DevExt
->DataBuffer
;
3101 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
3103 DPRINT("read data\n");
3104 if (DevExt
->DataTransferLength
<= TransferSize
)
3106 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
3107 TransferSize
= DevExt
->DataTransferLength
;
3109 DevExt
->DataTransferLength
= 0;
3114 DevExt
->DataTransferLength
-= TransferSize
;
3115 IsLastBlock
= FALSE
;
3118 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
3120 DevExt
->DataBuffer
+= TransferSize
;
3122 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3127 /* Read remaining junk from device */
3128 while (JunkSize
> 0)
3130 IDEReadWord(DevExt
->CommandPortBase
);
3134 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
3136 ScsiPortStallExecution(10);
3139 /* Check for data overrun */
3140 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
3142 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
3143 IDEReadWord(DevExt
->CommandPortBase
);
3147 SrbStatus
= SRB_STATUS_SUCCESS
;
3149 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
3151 DPRINT("write data\n");
3152 if (DevExt
->DataTransferLength
< TransferSize
)
3154 TransferSize
= DevExt
->DataTransferLength
;
3157 TargetAddress
= DevExt
->DataBuffer
;
3159 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
3161 DevExt
->DataBuffer
+= TransferSize
;
3162 DevExt
->DataTransferLength
-= TransferSize
;
3164 /* Write the sector */
3165 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3166 SrbStatus
= SRB_STATUS_SUCCESS
;
3167 IsLastBlock
= FALSE
;
3171 DPRINT("Unspecified transfer direction!\n");
3172 SrbStatus
= SRB_STATUS_SUCCESS
;
3177 AtapiCompleteRequest(DevExt
, SrbStatus
);
3179 DPRINT("AtapiPacketInterrupt() done\n");
3183 static BOOLEAN FASTCALL
3184 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
3188 DPRINT("AtapiNoDataInterrupt()\n");
3190 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
3191 AtapiCompleteRequest(DevExt
,
3192 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
3194 DPRINT("AtapiNoDatanterrupt() done!\n");
3199 static BOOLEAN FASTCALL
3200 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
3206 DPRINT("AtapiDmaInterrupt()\n");
3208 DevExt
->UseDma
= FALSE
;
3210 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
3211 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
3212 /* get DMA status */
3213 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3214 /* clear the INTR & ERROR bits */
3215 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
3217 /* read the drive status */
3218 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
3219 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
3220 (DmaStatus
& 0x07) == 4)
3222 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3223 DPRINT("AtapiDmaInterrupt() done\n");
3226 DPRINT1("Status %x\n", Status
);
3227 DPRINT1("%x\n", DmaStatus
);
3228 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
3229 DPRINT1("AtapiDmaReadInterrupt() done\n");
3234 static BOOLEAN FASTCALL
3235 AtapiSmartInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
3237 PSCSI_REQUEST_BLOCK Srb
;
3239 PSRB_IO_CONTROL SrbIoControl
;
3240 PSENDCMDOUTPARAMS OutParams
;
3243 DPRINT("AtapiSmartInterrupt() called!\n");
3245 Srb
= DevExt
->CurrentSrb
;
3248 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
3249 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != (DevExt
->DataTransferLength
? IDE_SR_DRQ
: 0))
3251 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
3253 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
3254 DPRINT("AtapiSmartInterrupt() done!\n");
3257 DPRINT("AtapiSmartInterrupt() done!\n");
3261 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
3263 if (DevExt
->DataTransferLength
)
3265 IDEReadBlock(DevExt
->CommandPortBase
, DevExt
->DataBuffer
, 512);
3266 DevExt
->DataTransferLength
-= 512;
3267 DevExt
->DataBuffer
+= 512;
3270 if (DevExt
->DataTransferLength
== 0)
3272 SrbIoControl
= (PSRB_IO_CONTROL
)Srb
->DataBuffer
;
3273 OutParams
= (PSENDCMDOUTPARAMS
)(SrbIoControl
+ 1);
3275 OutParams
->DriverStatus
.bDriverError
= 0;
3276 OutParams
->DriverStatus
.bIDEError
= 0;
3278 if (SrbIoControl
->ControlCode
== IOCTL_SCSI_MINIPORT_RETURN_STATUS
)
3280 IdeRegs
= (PIDEREGS
)OutParams
->bBuffer
;
3282 IdeRegs
->bFeaturesReg
= RETURN_SMART_STATUS
;
3283 IdeRegs
->bSectorCountReg
= IDEReadSectorCount(DevExt
->CommandPortBase
);
3284 IdeRegs
->bSectorNumberReg
= IDEReadSectorNum(DevExt
->CommandPortBase
);
3285 IdeRegs
->bCylLowReg
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
3286 IdeRegs
->bCylHighReg
= IDEReadCylinderHigh(DevExt
->CommandPortBase
);
3287 IdeRegs
->bDriveHeadReg
= IDEReadDriveHead(DevExt
->CommandPortBase
);
3288 IdeRegs
->bCommandReg
= SMART_CMD
;
3289 IdeRegs
->bReserved
= 0;
3291 OutParams
->cBufferSize
= 8;
3295 OutParams
->cBufferSize
= DevExt
->DataBuffer
- OutParams
->bBuffer
;
3298 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3301 DPRINT("AtapiSmartInterrupt() done!\n");
3307 static BOOLEAN FASTCALL
3308 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
3310 PSCSI_REQUEST_BLOCK Srb
;
3312 BOOLEAN IsLastBlock
;
3313 PUCHAR TargetAddress
;
3316 DPRINT("AtapiReadInterrupt() called!\n");
3318 Srb
= DevExt
->CurrentSrb
;
3320 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
3321 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
3323 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
3325 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
3326 DPRINT("AtapiReadInterrupt() done!\n");
3329 DPRINT("AtapiReadInterrupt() done!\n");
3333 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
3335 /* Update controller/device state variables */
3336 TargetAddress
= DevExt
->DataBuffer
;
3337 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
3339 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
3340 DPRINT("TransferSize: %lu\n", TransferSize
);
3342 if (DevExt
->DataTransferLength
<= TransferSize
)
3344 TransferSize
= DevExt
->DataTransferLength
;
3345 DevExt
->DataTransferLength
= 0;
3350 DevExt
->DataTransferLength
-= TransferSize
;
3351 IsLastBlock
= FALSE
;
3353 DevExt
->DataBuffer
+= TransferSize
;
3354 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
3356 /* Copy the block of data */
3357 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
3359 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3363 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3368 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3371 DPRINT("AtapiReadInterrupt() done!\n");
3376 static BOOLEAN FASTCALL
3377 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
3379 PSCSI_REQUEST_BLOCK Srb
;
3381 BOOLEAN IsLastBlock
;
3382 PUCHAR TargetAddress
;
3385 DPRINT("AtapiWriteInterrupt() called!\n");
3387 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
3388 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
3390 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
3392 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
3393 DPRINT("AtapiWriteInterrupt() done!\n");
3396 DPRINT("AtapiWriteInterrupt() done!\n");
3401 Srb
= DevExt
->CurrentSrb
;
3402 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
3403 if (DevExt
->DataTransferLength
< TransferSize
)
3405 TransferSize
= DevExt
->DataTransferLength
;
3407 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
3409 IsLastBlock
= FALSE
;
3410 TargetAddress
= DevExt
->DataBuffer
;
3411 DevExt
->DataBuffer
+= TransferSize
;
3412 DevExt
->DataTransferLength
-= TransferSize
;
3414 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
3415 DPRINT("TransferSize: %lu\n", TransferSize
);
3416 /* Write the sector */
3417 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
3419 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3423 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3426 else if (DeviceStatus
& IDE_SR_DRQ
)
3428 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3431 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
3433 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
3442 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3444 DPRINT("AtapiWriteInterrupt() done!\n");
3450 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
3452 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
3454 if (DevExt
->Handler
!= NULL
)
3456 DPRINT1("DevExt->Handler is already set!!\n");
3458 DevExt
->Handler
= Handler
;
3459 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
3460 ScsiPortStallExecution(1);
3465 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
3466 PSCSI_REQUEST_BLOCK Srb
,
3471 PPRD PRDEntry
= DevExt
->PRDTable
;
3472 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
3477 DPRINT("AtapiInitDma()\n");
3479 StartAddress
= Srb
->DataBuffer
;
3480 EndAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ Srb
->DataTransferLength
);
3481 DevExt
->PRDCount
= 0;
3483 while (StartAddress
< EndAddress
)
3485 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
3486 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
3493 /* calculate the length up to the next 64k boundary */
3494 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
3495 if (tmpLength
> Length
)
3500 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3504 if (tmpLength
== 0x10000)
3506 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3508 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3509 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3510 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3511 PRDEntry
->Length
= tmpLength
;
3514 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3518 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3519 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3520 Length
-= tmpLength
;
3521 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3523 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3524 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3525 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3526 PRDEntry
->Length
= tmpLength
;
3528 StartAddress
= (PVOID
)((ULONG_PTR
)StartAddress
+ tmpLength
);
3529 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3530 Length
-= tmpLength
;
3533 /* set the end marker in the last PRD */
3535 PRDEntry
->Length
|= 0x80000000;
3536 /* set the PDR table */
3537 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3538 /* write the DMA command */
3539 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3540 /* reset the status and interrupt bit */
3541 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3542 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);