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 <ntos/kefuncs.h>
62 #define VERSION "0.0.1"
65 // ------------------------------------------------------- File Static Data
75 // ATAPI_MINIPORT_EXTENSION
78 // Extension to be placed in each port device object
81 // Allocated from NON-PAGED POOL
82 // Available at any IRQL
85 typedef struct _ATAPI_MINIPORT_EXTENSION
87 IDE_DRIVE_IDENTIFY DeviceParams
[2];
89 ULONG TransferSize
[2];
91 ULONG CommandPortBase
;
92 ULONG ControlPortBase
;
93 ULONG BusMasterRegisterBase
;
95 PSCSI_REQUEST_BLOCK CurrentSrb
;
98 ULONG DataTransferLength
;
100 BOOLEAN
FASTCALL (*Handler
)(IN
struct _ATAPI_MINIPORT_EXTENSION
* DevExt
);
106 SCSI_PHYSICAL_ADDRESS PRDTablePhysicalAddress
;
108 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
111 #define DEVICE_PRESENT 0x00000001
112 #define DEVICE_ATAPI 0x00000002
113 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
114 #define DEVICE_DWORD_IO 0x00000008
115 #define DEVICE_48BIT_ADDRESS 0x00000010
116 #define DEVICE_MEDIA_STATUS 0x00000020
117 #define DEVICE_DMA_CMD 0x00000040
118 #define DEVICE_NO_FLUSH 0x00000080
121 typedef struct _UNIT_EXTENSION
124 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
126 PCI_SLOT_NUMBER LastSlotNumber
;
128 #ifdef ENABLE_NATIVE_PCI
129 typedef struct _PCI_NATIVE_CONTROLLER
134 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
136 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
140 0x4D68, // PDC20268, Ultra100TX2
144 0x4D30, // PDC20267, Ultra100
150 // ----------------------------------------------- Discardable Declarations
154 // make the initialization routines discardable, so that they
157 #pragma alloc_text(init, DriverEntry)
159 // make the PASSIVE_LEVEL routines pageable, so that they don't
160 // waste nonpaged memory
162 #endif /* ALLOC_PRAGMA */
164 // ---------------------------------------------------- Forward Declarations
168 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
169 PSCSI_REQUEST_BLOCK Srb
,
174 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
176 PVOID BusInformation
,
177 PCHAR ArgumentString
,
178 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
182 AtapiFindIsaBusController(PVOID DeviceExtension
,
184 PVOID BusInformation
,
185 PCHAR ArgumentString
,
186 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
190 AtapiFindNativePciController(PVOID DeviceExtension
,
192 PVOID BusInformation
,
193 PCHAR ArgumentString
,
194 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
197 static BOOLEAN STDCALL
198 AtapiInitialize(IN PVOID DeviceExtension
);
200 static BOOLEAN STDCALL
201 AtapiResetBus(IN PVOID DeviceExtension
,
204 static BOOLEAN STDCALL
205 AtapiStartIo(IN PVOID DeviceExtension
,
206 IN PSCSI_REQUEST_BLOCK Srb
);
209 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
211 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
));
213 static BOOLEAN STDCALL
214 AtapiInterrupt(IN PVOID DeviceExtension
);
216 static BOOLEAN FASTCALL
217 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
);
219 static BOOLEAN FASTCALL
220 AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
222 static BOOLEAN FASTCALL
223 AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
226 static BOOLEAN FASTCALL
227 AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
229 static BOOLEAN FASTCALL
230 AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
233 static BOOLEAN FASTCALL
234 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
237 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
238 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
241 AtapiIdentifyDevice(IN ULONG CommandPort
,
242 IN ULONG ControlPort
,
245 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
248 AtapiPolledRead(IN ULONG CommandPort
,
249 IN ULONG ControlPort
,
253 IN UCHAR CylinderLow
,
254 IN UCHAR CylinderHigh
,
260 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
261 IN PSCSI_REQUEST_BLOCK Srb
);
264 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
265 IN PSCSI_REQUEST_BLOCK Srb
);
268 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
269 IN PSCSI_REQUEST_BLOCK Srb
);
272 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
273 IN PSCSI_REQUEST_BLOCK Srb
);
276 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
277 IN PSCSI_REQUEST_BLOCK Srb
);
280 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
281 PSCSI_REQUEST_BLOCK Srb
);
284 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
285 PSCSI_REQUEST_BLOCK Srb
);
288 AtapiErrorToScsi(PVOID DeviceExtension
,
289 PSCSI_REQUEST_BLOCK Srb
);
292 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
);
294 // ---------------------------------------------------------------- Inlines
297 IDESwapBytePairs(char *Buf
,
303 for (i
= 0; i
< Cnt
; i
+= 2)
312 // ------------------------------------------------------- Public Interface
317 // This function initializes the driver, locates and claims
318 // hardware resources, and creates various NT objects needed
319 // to process I/O requests.
325 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
327 // IN PUNICODE_STRING RegistryPath Name of registry driver service
334 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
335 IN PUNICODE_STRING RegistryPath
)
337 HW_INITIALIZATION_DATA InitData
;
340 DPRINT("ATAPI Driver %s\n", VERSION
);
341 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
343 /* Initialize data structure */
344 RtlZeroMemory(&InitData
,
345 sizeof(HW_INITIALIZATION_DATA
));
346 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
347 InitData
.HwInitialize
= AtapiInitialize
;
348 InitData
.HwResetBus
= AtapiResetBus
;
349 InitData
.HwStartIo
= AtapiStartIo
;
350 InitData
.HwInterrupt
= AtapiInterrupt
;
352 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
353 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
355 InitData
.MapBuffers
= TRUE
;
357 /* Search the PCI bus for compatibility mode ide controllers */
359 InitData
.NeedPhysicalAddresses
= TRUE
;
361 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
362 InitData
.NumberOfAccessRanges
= 3;
363 InitData
.AdapterInterfaceType
= PCIBus
;
365 InitData
.VendorId
= NULL
;
366 InitData
.VendorIdLength
= 0;
367 InitData
.DeviceId
= NULL
;
368 InitData
.DeviceIdLength
= 0;
370 Status
= ScsiPortInitialize(DriverObject
,
374 // if (newStatus < statusToReturn)
375 // statusToReturn = newStatus;
378 /* Search the PCI bus for all ide controllers */
379 #ifdef ENABLE_NATIVE_PCI
380 InitData
.NeedPhysicalAddresses
= TRUE
;
382 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
383 InitData
.NumberOfAccessRanges
= 3;
384 InitData
.AdapterInterfaceType
= PCIBus
;
386 InitData
.VendorId
= 0;
387 InitData
.VendorIdLength
= 0;
388 InitData
.DeviceId
= 0;
389 InitData
.DeviceIdLength
= 0;
391 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
393 Status
= ScsiPortInitialize(DriverObject
,
397 // if (newStatus < statusToReturn)
398 // statusToReturn = newStatus;
401 /* Search the ISA bus for ide controllers */
403 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
404 InitData
.NumberOfAccessRanges
= 2;
405 InitData
.AdapterInterfaceType
= Isa
;
407 InitData
.VendorId
= NULL
;
408 InitData
.VendorIdLength
= 0;
409 InitData
.DeviceId
= NULL
;
410 InitData
.DeviceIdLength
= 0;
412 Status
= ScsiPortInitialize(DriverObject
,
416 // if (newStatus < statusToReturn)
417 // statusToReturn = newStatus;
420 DPRINT("Returning from DriverEntry\n");
427 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
428 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
429 INTERFACE_TYPE InterfaceType
,
430 ULONG CommandPortBase
,
431 ULONG ControlPortBase
,
432 ULONG BusMasterPortBase
,
433 ULONG InterruptVector
)
435 SCSI_PHYSICAL_ADDRESS IoAddress
;
440 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
441 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
443 ConfigInfo
->SystemIoBusNumber
,
451 DevExt
->Handler
= NULL
;
452 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
453 ConfigInfo
->AccessRanges
[0].RangeStart
= IoAddress
;
454 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
455 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
459 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
460 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
462 ConfigInfo
->SystemIoBusNumber
,
468 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
469 (PVOID
)DevExt
->CommandPortBase
);
472 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
473 ConfigInfo
->AccessRanges
[1].RangeStart
= IoAddress
;
474 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
475 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
477 if (BusMasterPortBase
)
479 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
480 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
482 ConfigInfo
->SystemIoBusNumber
,
488 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
489 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
492 DevExt
->BusMasterRegisterBase
= (ULONG
)IoBase
;
493 ConfigInfo
->AccessRanges
[2].RangeStart
= IoAddress
;
494 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
495 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
497 // ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
498 // ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
499 ConfigInfo
->DmaWidth
= Width32Bits
;
500 // ConfigInfo->DmaSpeed = Compatible;
501 ConfigInfo
->ScatterGather
= TRUE
;
502 ConfigInfo
->Master
= TRUE
;
503 ConfigInfo
->NumberOfPhysicalBreaks
= 0x10000 / PAGE_SIZE
+ 1;
504 ConfigInfo
->Dma32BitAddresses
= TRUE
;
505 ConfigInfo
->NeedPhysicalAddresses
= TRUE
;
506 ConfigInfo
->MapBuffers
= TRUE
;
508 DevExt
->PRDMaxCount
= PAGE_SIZE
/ sizeof(PRD
);
509 DevExt
->PRDTable
= ScsiPortGetUncachedExtension(DevExt
, ConfigInfo
, sizeof(PRD
) * DevExt
->PRDMaxCount
);
510 if (DevExt
->PRDTable
!= NULL
)
512 DevExt
->PRDTablePhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, NULL
, DevExt
->PRDTable
, &Length
);
514 if (DevExt
->PRDTable
== NULL
||
515 DevExt
->PRDTablePhysicalAddress
.QuadPart
== 0LL ||
516 Length
< sizeof(PRD
) * DevExt
->PRDMaxCount
)
518 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
519 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
520 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->BusMasterRegisterBase
);
525 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
526 ConfigInfo
->BusInterruptVector
= InterruptVector
;
527 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
529 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
531 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
533 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
535 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
543 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
545 PVOID BusInformation
,
546 PCHAR ArgumentString
,
547 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
550 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
551 PCI_SLOT_NUMBER SlotNumber
;
552 PCI_COMMON_CONFIG PciConfig
;
554 ULONG StartDeviceNumber
;
556 ULONG StartFunctionNumber
;
557 ULONG FunctionNumber
;
558 BOOLEAN ChannelFound
;
560 ULONG BusMasterBasePort
= 0;
562 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
563 ConfigInfo
->SystemIoBusNumber
,
564 ConfigInfo
->SlotNumber
);
568 /* both channels were claimed: exit */
569 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
570 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
571 return(SP_RETURN_NOT_FOUND
);
573 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
574 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
575 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
576 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
578 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
579 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
581 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
582 ChannelFound
= FALSE
;
585 DataSize
= ScsiPortGetBusData(DeviceExtension
,
587 ConfigInfo
->SystemIoBusNumber
,
588 SlotNumber
.u
.AsULONG
,
590 PCI_COMMON_HDR_LENGTH
);
591 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
593 if (FunctionNumber
== 0)
603 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
604 if (PciConfig
.BaseClass
== 0x01 &&
605 PciConfig
.SubClass
== 0x01) // &&
606 // (PciConfig.ProgIf & 0x05) == 0)
608 /* both channels are in compatibility mode */
609 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
610 ConfigInfo
->SystemIoBusNumber
,
611 SlotNumber
.u
.bits
.DeviceNumber
,
612 SlotNumber
.u
.bits
.FunctionNumber
,
615 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
617 DPRINT("Found IDE controller in compatibility mode!\n");
619 ConfigInfo
->NumberOfBuses
= 1;
620 ConfigInfo
->MaximumNumberOfTargets
= 2;
621 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
623 if (PciConfig
.ProgIf
& 0x80)
625 DPRINT("Found IDE Bus Master controller!\n");
626 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
628 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
629 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
632 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
634 /* Both channels unclaimed: Claim primary channel */
635 DPRINT("Primary channel!\n");
636 ChannelFound
= AtapiClaimHwResources(DevExt
,
645 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
647 /* Primary channel already claimed: claim secondary channel */
648 DPRINT("Secondary channel!\n");
650 ChannelFound
= AtapiClaimHwResources(DevExt
,
655 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
659 /* Find attached devices */
662 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
663 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
664 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
665 return(SP_RETURN_FOUND
);
668 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
673 StartFunctionNumber
= 0;
675 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
677 return(SP_RETURN_NOT_FOUND
);
684 AtapiFindIsaBusController(PVOID DeviceExtension
,
686 PVOID BusInformation
,
687 PCHAR ArgumentString
,
688 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
691 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
692 BOOLEAN ChannelFound
= FALSE
;
693 BOOLEAN DeviceFound
= FALSE
;
695 DPRINT("AtapiFindIsaBusController() called!\n");
699 ConfigInfo
->NumberOfBuses
= 1;
700 ConfigInfo
->MaximumNumberOfTargets
= 2;
701 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
703 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
705 /* Both channels unclaimed: Claim primary channel */
706 DPRINT("Primary channel!\n");
708 ChannelFound
= AtapiClaimHwResources(DevExt
,
717 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
719 /* Primary channel already claimed: claim secondary channel */
720 DPRINT("Secondary channel!\n");
722 ChannelFound
= AtapiClaimHwResources(DevExt
,
733 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
735 return(SP_RETURN_NOT_FOUND
);
738 /* Find attached devices */
741 DeviceFound
= AtapiFindDevices(DevExt
,
743 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
744 return(SP_RETURN_FOUND
);
747 return SP_RETURN_NOT_FOUND
;
752 #ifdef ENABLE_NATIVE_PCI
754 AtapiFindNativePciController(PVOID DeviceExtension
,
756 PVOID BusInformation
,
757 PCHAR ArgumentString
,
758 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
761 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
762 PCI_COMMON_CONFIG PciConfig
;
763 PCI_SLOT_NUMBER SlotNumber
;
766 ULONG StartDeviceNumber
;
767 ULONG FunctionNumber
;
768 ULONG StartFunctionNumber
;
769 ULONG BusMasterBasePort
;
771 BOOLEAN ChannelFound
;
773 DPRINT("AtapiFindNativePciController() called!\n");
775 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
776 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
777 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
778 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
780 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
781 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
783 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
784 DataSize
= ScsiPortGetBusData(DeviceExtension
,
786 ConfigInfo
->SystemIoBusNumber
,
787 SlotNumber
.u
.AsULONG
,
789 PCI_COMMON_HDR_LENGTH
);
790 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
794 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
796 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
797 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
802 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
804 /* We have found a known native pci ide controller */
805 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
807 DPRINT("Found IDE Bus Master controller!\n");
808 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
809 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
813 BusMasterBasePort
= 0;
816 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
817 ConfigInfo
->NumberOfBuses
= 1;
818 ConfigInfo
->MaximumNumberOfTargets
= 2;
819 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
822 We must not store and use the last tested slot number. If there is a recall
823 to the some device and we will claim the primary channel again than the call
824 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
825 claim the secondary channel.
827 ChannelFound
= FALSE
;
828 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
830 /* try to claim primary channel */
831 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
832 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
834 /* primary channel is enabled */
835 ChannelFound
= AtapiClaimHwResources(DevExt
,
838 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
839 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
841 PciConfig
.u
.type0
.InterruptLine
);
844 AtapiFindDevices(DevExt
, ConfigInfo
);
846 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
847 return SP_RETURN_FOUND
;
853 /* try to claim secondary channel */
854 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
855 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
857 /* secondary channel is enabled */
858 ChannelFound
= AtapiClaimHwResources(DevExt
,
861 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
862 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
863 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
864 PciConfig
.u
.type0
.InterruptLine
);
867 AtapiFindDevices(DevExt
, ConfigInfo
);
869 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
870 return SP_RETURN_FOUND
;
876 StartFunctionNumber
= 0;
879 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
880 DPRINT("AtapiFindNativePciController() done!\n");
882 return(SP_RETURN_NOT_FOUND
);
887 static BOOLEAN STDCALL
888 AtapiInitialize(IN PVOID DeviceExtension
)
894 static BOOLEAN STDCALL
895 AtapiResetBus(IN PVOID DeviceExtension
,
902 static BOOLEAN STDCALL
903 AtapiStartIo(IN PVOID DeviceExtension
,
904 IN PSCSI_REQUEST_BLOCK Srb
)
906 PATAPI_MINIPORT_EXTENSION DevExt
;
909 DPRINT("AtapiStartIo() called\n");
911 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
913 switch (Srb
->Function
)
915 case SRB_FUNCTION_EXECUTE_SCSI
:
916 DevExt
->CurrentSrb
= Srb
;
917 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
919 Result
= AtapiSendAtapiCommand(DevExt
,
924 Result
= AtapiSendIdeCommand(DevExt
,
929 case SRB_FUNCTION_ABORT_COMMAND
:
930 if (DevExt
->CurrentSrb
!= NULL
)
932 Result
= SRB_STATUS_ABORT_FAILED
;
936 Result
= SRB_STATUS_SUCCESS
;
941 Result
= SRB_STATUS_INVALID_REQUEST
;
945 Srb
->SrbStatus
= Result
;
948 if (Result
!= SRB_STATUS_PENDING
)
950 DevExt
->CurrentSrb
= NULL
;
951 Srb
->SrbStatus
= (UCHAR
)Result
;
953 ScsiPortNotification(RequestComplete
,
956 ScsiPortNotification(NextRequest
,
962 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
965 DPRINT("AtapiStartIo() done\n");
970 static BOOLEAN STDCALL
971 AtapiInterrupt(IN PVOID DeviceExtension
)
973 PATAPI_MINIPORT_EXTENSION DevExt
;
975 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
977 if (DevExt
->Handler
== NULL
)
979 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
980 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) != IDE_SR_DRDY
)
982 static ULONG Count
= 0;
984 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
985 DevExt
->CommandPortBase
, Status
, Count
);
992 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
993 if (!(Status
& 0x04))
1001 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1002 if (Status
& IDE_SR_BUSY
)
1007 return DevExt
->Handler(DevExt
);
1010 // ---------------------------------------------------- Discardable statics
1014 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension
, ULONG UnitNumber
)
1016 BOOLEAN Result
= FALSE
;
1021 if (DeviceExtension
->PRDTable
)
1023 if (DeviceExtension
->DeviceParams
[UnitNumber
].Capabilities
& IDE_DRID_DMA_SUPPORTED
)
1025 if ((DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0004) &&
1026 (DeviceExtension
->DeviceParams
[UnitNumber
].UltraDmaModes
& 0x7F00))
1030 else if (DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0002)
1032 if ((DeviceExtension
->DeviceParams
[UnitNumber
].MultiDmaModes
& 0x0404) == 0x0404)
1038 * should we support single mode dma ?
1040 else if ((DeviceExtension
->DeviceParams
[UnitNumber
].DmaModes
& 0x0404) == 0x0404)
1046 Status
= IDEReadDMAStatus(DeviceExtension
->BusMasterRegisterBase
);
1049 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
| (UnitNumber
? 0x40 : 0x20));
1053 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
& (UnitNumber
? ~0x40 : ~0x20));
1062 /**********************************************************************
1067 * Searches for devices on the given port.
1074 * Port device specific information.
1077 * Port configuration information.
1080 * TRUE: At least one device is attached to the port.
1081 * FALSE: No device is attached to the port.
1085 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1086 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1088 BOOLEAN DeviceFound
= FALSE
;
1089 ULONG CommandPortBase
;
1090 ULONG ControlPortBase
;
1096 DPRINT("AtapiFindDevices() called\n");
1098 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
1099 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1101 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
1102 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1104 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1107 IDEWriteDriveHead(CommandPortBase
,
1108 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1109 ScsiPortStallExecution(500);
1111 /* Disable interrupts */
1112 IDEWriteDriveControl(ControlPortBase
,
1114 ScsiPortStallExecution(500);
1116 /* Check if a device is attached to the interface */
1117 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1118 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1120 High
= IDEReadCylinderHigh(CommandPortBase
);
1121 Low
= IDEReadCylinderLow(CommandPortBase
);
1123 IDEWriteCylinderHigh(CommandPortBase
, 0);
1124 IDEWriteCylinderLow(CommandPortBase
, 0);
1126 if (Low
!= 0x55 || High
!= 0xaa)
1128 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1132 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_RESET
, NULL
);
1134 for (Retries
= 0; Retries
< 20000; Retries
++)
1136 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1140 ScsiPortStallExecution(150);
1142 if (Retries
>= 20000)
1144 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1145 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1149 High
= IDEReadCylinderHigh(CommandPortBase
);
1150 Low
= IDEReadCylinderLow(CommandPortBase
);
1152 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1157 if (High
== 0xEB && Low
== 0x14)
1159 if (AtapiIdentifyDevice(CommandPortBase
,
1163 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1165 DPRINT(" ATAPI drive found!\n");
1166 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1167 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1168 DeviceExtension
->TransferSize
[UnitNumber
] =
1169 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1171 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1173 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1180 DPRINT(" No ATAPI drive found!\n");
1185 if (AtapiIdentifyDevice(CommandPortBase
,
1189 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1191 DPRINT(" IDE drive found!\n");
1192 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1193 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1194 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1195 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1196 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1197 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1199 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1200 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1202 if (DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x0400 &&
1203 DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x0400)
1205 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_48BIT_ADDRESS
;
1207 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1209 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1212 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1214 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1221 DPRINT(" No IDE drive found!\n");
1226 /* Reset pending interrupts */
1227 IDEReadStatus(CommandPortBase
);
1228 /* Reenable interrupts */
1229 IDEWriteDriveControl(ControlPortBase
, 0);
1230 ScsiPortStallExecution(500);
1231 /* Return with drive 0 selected */
1232 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1233 ScsiPortStallExecution(500);
1235 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1237 return(DeviceFound
);
1242 * AtapiIdentifyDevice
1245 * Get the identification block from the drive
1252 * Address of the command port
1254 * Address of the control port
1256 * The drive index (0,1)
1258 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1260 * Address to write drive ident block
1263 * TRUE: The drive identification block was retrieved successfully
1264 * FALSE: an error ocurred
1268 AtapiIdentifyDevice(IN ULONG CommandPort
,
1269 IN ULONG ControlPort
,
1272 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1277 /* Get the Drive Identify block from drive or die */
1278 if (AtapiPolledRead(CommandPort
,
1285 (DriveNum
? IDE_DH_DRV1
: 0),
1286 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1287 (PUCHAR
)DrvParms
) == FALSE
)
1289 DPRINT("AtapiPolledRead() failed\n");
1293 /* Report on drive parameters if debug mode */
1294 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1295 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1296 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1297 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1298 DrvParms
->ConfigBits
,
1299 DrvParms
->LogicalCyls
,
1300 DrvParms
->LogicalHeads
,
1301 DrvParms
->SectorsPerTrack
,
1302 DrvParms
->InterSectorGap
,
1303 DrvParms
->InterSectorGapSize
);
1304 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1305 DrvParms
->BytesInPLO
,
1306 DrvParms
->VendorUniqueCnt
,
1307 DrvParms
->SerialNumber
);
1308 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1309 DrvParms
->ControllerType
,
1310 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1311 DrvParms
->ECCByteCnt
,
1312 DrvParms
->FirmwareRev
);
1313 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1314 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1315 (DrvParms
->RWMultImplemented
),
1316 (DrvParms
->RWMultCurrent
) & 0xff,
1317 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1318 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1319 DrvParms
->MinPIOTransTime
,
1320 DrvParms
->MinDMATransTime
);
1321 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1322 DrvParms
->TMCylinders
,
1324 DrvParms
->TMSectorsPerTrk
,
1325 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1326 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1327 DrvParms
->TMSectorCountHi
,
1328 DrvParms
->TMSectorCountLo
,
1329 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1330 DPRINT("SupportedFeatures83: %x, EnabledFeatures86 %x\n", DrvParms
->SupportedFeatures83
, DrvParms
->EnabledFeatures86
);
1331 DPRINT("Max48BitAddress: %I64d\n", *(PULONGLONG
)DrvParms
->Max48BitAddress
);
1332 if (DrvParms
->TMFieldsValid
& 0x0004)
1334 if ((DrvParms
->UltraDmaModes
>> 8) && (DrvParms
->UltraDmaModes
& 0xff))
1337 while (!(DrvParms
->UltraDmaModes
& (0x0100 << mode
)))
1341 DPRINT("Ultra DMA mode %d is selected\n", mode
);
1343 else if ((DrvParms
->MultiDmaModes
>> 8) & (DrvParms
->MultiDmaModes
& 0x07))
1346 while(!(DrvParms
->MultiDmaModes
& (0x01 << mode
)))
1350 DPRINT("Multi DMA mode %d is selected\n", mode
);
1354 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1356 /* LBA ATA drives always have a sector size of 512 */
1357 DrvParms
->BytesPerSector
= 512;
1361 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1362 if (DrvParms
->BytesPerSector
== 0)
1364 DrvParms
->BytesPerSector
= 512;
1368 for (i
= 15; i
>= 0; i
--)
1370 if (DrvParms
->BytesPerSector
& (1 << i
))
1372 DrvParms
->BytesPerSector
= 1 << i
;
1378 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1387 // Read a sector of data from the drive in a polled fashion.
1393 // IN ULONG CommandPort Address of command port for drive
1394 // IN ULONG ControlPort Address of control port for drive
1395 // IN UCHAR PreComp Value to write to precomp register
1396 // IN UCHAR SectorCnt Value to write to sectorCnt register
1397 // IN UCHAR SectorNum Value to write to sectorNum register
1398 // IN UCHAR CylinderLow Value to write to CylinderLow register
1399 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1400 // IN UCHAR DrvHead Value to write to Drive/Head register
1401 // IN UCHAR Command Value to write to Command register
1402 // OUT PUCHAR Buffer Buffer for output data
1405 // BOOLEAN: TRUE success, FALSE error
1409 AtapiPolledRead(IN ULONG CommandPort
,
1410 IN ULONG ControlPort
,
1414 IN UCHAR CylinderLow
,
1415 IN UCHAR CylinderHigh
,
1420 ULONG SectorCount
= 0;
1422 BOOLEAN Junk
= FALSE
;
1425 /* Wait for BUSY to clear */
1426 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1428 Status
= IDEReadStatus(CommandPort
);
1429 if (!(Status
& IDE_SR_BUSY
))
1433 ScsiPortStallExecution(10);
1435 DPRINT("status=%02x\n", Status
);
1436 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1437 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1439 DPRINT("Drive is BUSY for too long\n");
1443 /* Write Drive/Head to select drive */
1444 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1445 ScsiPortStallExecution(500);
1447 /* Disable interrupts */
1448 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1449 ScsiPortStallExecution(500);
1452 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1453 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1455 Status
= IDEReadStatus(CommandPort
);
1456 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1460 ScsiPortStallExecution(10);
1462 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1468 /* Issue command to drive */
1469 if (DrvHead
& IDE_DH_LBA
)
1471 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1472 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1473 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1479 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1480 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1489 /* Setup command parameters */
1490 IDEWritePrecomp(CommandPort
, PreComp
);
1491 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1492 IDEWriteSectorNum(CommandPort
, SectorNum
);
1493 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1494 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1495 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1497 /* Issue the command */
1498 IDEWriteCommand(CommandPort
, Command
);
1499 ScsiPortStallExecution(50);
1501 /* wait for DRQ or error */
1502 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1504 Status
= IDEReadStatus(CommandPort
);
1505 if (!(Status
& IDE_SR_BUSY
))
1507 if (Status
& IDE_SR_ERR
)
1509 IDEWriteDriveControl(ControlPort
, 0);
1510 ScsiPortStallExecution(50);
1511 IDEReadStatus(CommandPort
);
1516 if (Status
& IDE_SR_DRQ
)
1522 IDEWriteDriveControl(ControlPort
, 0);
1523 ScsiPortStallExecution(50);
1524 IDEReadStatus(CommandPort
);
1529 ScsiPortStallExecution(10);
1533 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1535 IDEWriteDriveControl(ControlPort
, 0);
1536 ScsiPortStallExecution(50);
1537 IDEReadStatus(CommandPort
);
1544 /* Read data into buffer */
1547 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1548 Buffer
+= IDE_SECTOR_BUF_SZ
;
1552 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1553 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1557 /* Check for error or more sectors to read */
1558 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1560 Status
= IDEReadStatus(CommandPort
);
1561 if (!(Status
& IDE_SR_BUSY
))
1563 if (Status
& IDE_SR_ERR
)
1565 IDEWriteDriveControl(ControlPort
, 0);
1566 ScsiPortStallExecution(50);
1567 IDEReadStatus(CommandPort
);
1571 if (Status
& IDE_SR_DRQ
)
1573 if (SectorCount
>= SectorCnt
)
1575 DPRINT("Buffer size exceeded!\n");
1582 if (SectorCount
> SectorCnt
)
1584 DPRINT("Read %lu sectors of junk!\n",
1585 SectorCount
- SectorCnt
);
1587 IDEWriteDriveControl(ControlPort
, 0);
1588 ScsiPortStallExecution(50);
1589 IDEReadStatus(CommandPort
);
1599 // ------------------------------------------- Nondiscardable statics
1602 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1603 IN PSCSI_REQUEST_BLOCK Srb
)
1605 UCHAR ByteCountHigh
;
1611 DPRINT("AtapiSendAtapiCommand() called!\n");
1613 if (Srb
->PathId
!= 0)
1615 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1616 return(SRB_STATUS_INVALID_PATH_ID
);
1619 if (Srb
->TargetId
> 1)
1621 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1622 return(SRB_STATUS_INVALID_TARGET_ID
);
1627 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1628 return(SRB_STATUS_INVALID_LUN
);
1631 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1633 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1634 return(SRB_STATUS_NO_DEVICE
);
1637 if (Srb
->Cdb
[0] == SCSIOP_MODE_SENSE
)
1639 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1640 return (SRB_STATUS_INVALID_REQUEST
);
1643 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1646 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1647 return(AtapiInquiry(DeviceExtension
,
1650 /* Set pointer to data buffer. */
1651 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1652 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1653 DeviceExtension
->CurrentSrb
= Srb
;
1655 DPRINT("BufferAddress %x, BufferLength %d\n", Srb
->DataBuffer
, Srb
->DataTransferLength
);
1657 /* Wait for BUSY to clear */
1658 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1660 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1661 if (!(Status
& IDE_SR_BUSY
))
1665 ScsiPortStallExecution(10);
1667 DPRINT("status=%02x\n", Status
);
1668 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1669 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1671 DPRINT("Drive is BUSY for too long\n");
1672 return(SRB_STATUS_BUSY
);
1675 /* Select the desired drive */
1676 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1677 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1679 /* Wait a little while */
1680 ScsiPortStallExecution(50);
1683 /* Wait for BUSY to clear and DRDY to assert */
1684 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1686 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1687 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1691 ScsiPortStallExecution(10);
1693 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1694 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1696 DPRINT("Drive is BUSY for too long after drive select\n");
1697 return(SRB_STATUS_BUSY
);
1702 if ((DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
) &&
1703 (Srb
->Cdb
[0] == SCSIOP_READ
|| Srb
->Cdb
[0] == SCSIOP_WRITE
))
1705 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
1709 DeviceExtension
->UseDma
= FALSE
;
1713 if (DeviceExtension
->DataTransferLength
< 0x10000)
1715 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1716 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1720 ByteCountLow
= 0xFF;
1721 ByteCountHigh
= 0xFF;
1724 /* Set feature register */
1726 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, DeviceExtension
->UseDma
? 1 : 0);
1728 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1731 /* Set command packet length */
1732 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1733 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1735 /* Issue command to drive */
1737 if (DeviceExtension
->UseDma
)
1739 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiDmaPacketInterrupt
);
1744 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiPacketInterrupt
);
1747 /* Wait for DRQ to assert */
1748 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1750 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1751 if ((Status
& IDE_SR_DRQ
))
1755 ScsiPortStallExecution(10);
1758 /* Convert special SCSI SRBs to ATAPI format */
1759 switch (Srb
->Cdb
[0])
1761 case SCSIOP_FORMAT_UNIT
:
1762 case SCSIOP_MODE_SELECT
:
1763 AtapiScsiSrbToAtapi (Srb
);
1767 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
1768 DPRINT("CdbSize: %lu\n", CdbSize
);
1770 /* Write command packet */
1771 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1776 if (DeviceExtension
->UseDma
)
1780 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
1781 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
1784 DPRINT("AtapiSendAtapiCommand() done\n");
1786 return(SRB_STATUS_PENDING
);
1791 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1792 IN PSCSI_REQUEST_BLOCK Srb
)
1794 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1796 DPRINT("AtapiSendIdeCommand() called!\n");
1798 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1803 if (Srb
->PathId
!= 0)
1805 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1806 return(SRB_STATUS_INVALID_PATH_ID
);
1809 if (Srb
->TargetId
> 1)
1811 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1812 return(SRB_STATUS_INVALID_TARGET_ID
);
1817 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1818 return(SRB_STATUS_INVALID_LUN
);
1821 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1823 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1824 return(SRB_STATUS_NO_DEVICE
);
1827 switch (Srb
->Cdb
[0])
1829 case SCSIOP_INQUIRY
:
1830 SrbStatus
= AtapiInquiry(DeviceExtension
,
1834 case SCSIOP_READ_CAPACITY
:
1835 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1841 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1845 case SCSIOP_SYNCHRONIZE_CACHE
:
1846 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1850 case SCSIOP_TEST_UNIT_READY
:
1851 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1855 case SCSIOP_MODE_SENSE
:
1858 case SCSIOP_START_STOP_UNIT
:
1859 case SCSIOP_REQUEST_SENSE
:
1863 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1865 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1869 DPRINT("AtapiSendIdeCommand() done!\n");
1876 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1877 PSCSI_REQUEST_BLOCK Srb
)
1879 PIDE_DRIVE_IDENTIFY DeviceParams
;
1880 PINQUIRYDATA InquiryData
;
1883 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1884 DeviceExtension
, Srb
->TargetId
);
1886 InquiryData
= Srb
->DataBuffer
;
1887 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1890 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1892 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1895 /* set device class */
1896 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1898 /* get it from the ATAPI configuration word */
1899 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1900 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1902 /* Don't flush CD/DVD drives */
1903 if (InquiryData
->DeviceType
== READ_ONLY_DIRECT_ACCESS_DEVICE
)
1905 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] |= DEVICE_NO_FLUSH
;
1911 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1914 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1915 if (DeviceParams
->ConfigBits
& 0x80)
1917 DPRINT("Removable media!\n");
1918 InquiryData
->RemovableMedia
= 1;
1921 for (i
= 0; i
< 20; i
+= 2)
1923 InquiryData
->VendorId
[i
] =
1924 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1925 InquiryData
->VendorId
[i
+1] =
1926 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1929 for (i
= 0; i
< 4; i
++)
1931 InquiryData
->ProductId
[12+i
] = ' ';
1934 for (i
= 0; i
< 4; i
+= 2)
1936 InquiryData
->ProductRevisionLevel
[i
] =
1937 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1938 InquiryData
->ProductRevisionLevel
[i
+1] =
1939 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1942 InquiryData
->AdditionalLength
= 31;
1944 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1946 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1947 return(SRB_STATUS_SUCCESS
);
1952 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1953 PSCSI_REQUEST_BLOCK Srb
)
1955 PREAD_CAPACITY_DATA CapacityData
;
1956 PIDE_DRIVE_IDENTIFY DeviceParams
;
1957 LARGE_INTEGER LastSector
;
1959 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1960 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1961 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1963 /* Set sector (block) size to 512 bytes (big-endian). */
1964 CapacityData
->BytesPerBlock
= 0x20000;
1966 /* Calculate last sector (big-endian). */
1967 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1969 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
1971 ((PUSHORT
)&LastSector
)[0] = DeviceParams
->Max48BitAddress
[0];
1972 ((PUSHORT
)&LastSector
)[1] = DeviceParams
->Max48BitAddress
[1];
1973 ((PUSHORT
)&LastSector
)[2] = DeviceParams
->Max48BitAddress
[2];
1974 ((PUSHORT
)&LastSector
)[3] = DeviceParams
->Max48BitAddress
[3];
1975 LastSector
.QuadPart
-= 1;
1980 LastSector
.u
.HighPart
= 0;
1981 LastSector
.u
.LowPart
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1982 DeviceParams
->TMSectorCountLo
)-1;
1987 LastSector
.u
.HighPart
= 0;
1988 LastSector
.u
.LowPart
= (ULONG
)(DeviceParams
->LogicalCyls
*
1989 DeviceParams
->LogicalHeads
*
1990 DeviceParams
->SectorsPerTrack
)-1;
1992 if (LastSector
.u
.HighPart
)
1994 DPRINT1("Disk is too large for our implementation (%I64d sectors\n", LastSector
.QuadPart
);
1998 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1999 (((PUCHAR
)&LastSector
)[1] << 16) |
2000 (((PUCHAR
)&LastSector
)[2] << 8) |
2001 ((PUCHAR
)&LastSector
)[3];
2003 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2006 CapacityData
->LogicalBlockAddress
);
2008 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2009 return(SRB_STATUS_SUCCESS
);
2014 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2015 PSCSI_REQUEST_BLOCK Srb
)
2017 PIDE_DRIVE_IDENTIFY DeviceParams
;
2018 ULONG StartingSector
;
2020 UCHAR CylinderHigh
[2];
2021 UCHAR CylinderLow
[2];
2023 UCHAR SectorNumber
[2];
2027 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION DevExt
);
2029 DPRINT("AtapiReadWrite() called!\n");
2030 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2033 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2035 /* Get starting sector number from CDB. */
2036 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2037 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2038 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2039 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2041 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2042 DeviceParams
->BytesPerSector
;
2044 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2046 Srb
->DataTransferLength
,
2049 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2051 SectorNumber
[0] = StartingSector
& 0xff;
2052 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2053 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2054 SectorNumber
[1] = (StartingSector
>> 24) & 0xff;
2056 CylinderHigh
[1] = 0;
2057 DrvHead
= (Srb
->TargetId
? IDE_DH_DRV1
: 0) | IDE_DH_LBA
;
2059 DPRINT("%s:BUS=%04x:DRV=%d:LBA48=1:BLK=%08d:SC=%02x:CM=%02x\n",
2060 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2061 DeviceExtension
->CommandPortBase
,
2062 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2063 (SectorNumber
[1] << 24) +
2064 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + DectorNumberLow
[0],
2068 else if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2070 SectorNumber
[0] = StartingSector
& 0xff;
2071 CylinderLow
[0] = (StartingSector
>> 8) & 0xff;
2072 CylinderHigh
[0] = (StartingSector
>> 16) & 0xff;
2073 SectorNumber
[1] = 0;
2075 CylinderHigh
[1] = 0;
2076 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2077 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2080 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2081 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2082 DeviceExtension
->CommandPortBase
,
2083 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2084 ((DrvHead
& 0x0f) << 24) +
2085 (CylinderHigh
[0] << 16) + (CylinderLow
[0] << 8) + SectorNumber
[0],
2091 SectorNumber
[0] = (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2092 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2093 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2094 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2095 StartingSector
/= DeviceParams
->LogicalHeads
;
2096 CylinderLow
[0] = StartingSector
& 0xff;
2097 CylinderHigh
[0] = StartingSector
>> 8;
2098 SectorNumber
[1] = 0;
2100 CylinderHigh
[1] = 0;
2102 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2103 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2104 DeviceExtension
->CommandPortBase
,
2105 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2114 /* Set pointer to data buffer. */
2115 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2116 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2118 DeviceExtension
->CurrentSrb
= Srb
;
2120 /* wait for BUSY to clear */
2121 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2123 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2124 if (!(Status
& IDE_SR_BUSY
))
2128 ScsiPortStallExecution(10);
2130 DPRINT("status=%02x\n", Status
);
2131 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2132 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2134 DPRINT ("Drive is BUSY for too long\n");
2135 return(SRB_STATUS_BUSY
);
2138 /* Select the desired drive */
2139 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2140 IDE_DH_FIXED
| DrvHead
);
2142 ScsiPortStallExecution(10);
2144 /* wait for BUSY to clear and DRDY to assert */
2145 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2147 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2148 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2152 ScsiPortStallExecution(10);
2154 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2155 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2157 DPRINT("Drive is BUSY for too long after drive select\n");
2158 return(SRB_STATUS_BUSY
);
2162 /* Setup command parameters */
2163 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2165 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2166 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
>> 8);
2167 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[1]);
2168 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[1]);
2169 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[1]);
2172 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2173 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
& 0xff);
2174 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
[0]);
2175 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
[0]);
2176 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
[0]);
2178 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2181 if (DeviceExtension
->PRDTable
&&
2182 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
)
2184 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2186 if (DeviceExtension
->UseDma
)
2188 Handler
= AtapiDmaInterrupt
;
2189 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2191 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA_EXT
: IDE_CMD_WRITE_DMA_EXT
;
2195 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA
: IDE_CMD_WRITE_DMA
;
2201 Handler
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? AtapiReadInterrupt
: AtapiWriteInterrupt
;
2202 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
)
2204 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2206 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE_EXT
: IDE_CMD_WRITE_MULTIPLE_EXT
;
2210 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE
: IDE_CMD_WRITE_MULTIPLE
;
2215 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
)
2217 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_EXT
: IDE_CMD_WRITE_EXT
;
2221 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ
: IDE_CMD_WRITE
;
2226 AtapiExecuteCommand(DeviceExtension
, Command
, Handler
);
2229 if (DeviceExtension
->UseDma
)
2233 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2234 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2239 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2241 /* Write data block */
2242 PUCHAR TargetAddress
;
2245 /* Wait for controller ready */
2246 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2248 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2249 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2253 ScsiPortStallExecution(10);
2255 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2257 DPRINT1("Drive is BUSY for too long after sending write command\n");
2258 return(SRB_STATUS_BUSY
);
2261 /* Update DeviceExtension data */
2262 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2263 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2265 TransferSize
= DeviceExtension
->DataTransferLength
;
2268 TargetAddress
= DeviceExtension
->DataBuffer
;
2269 DeviceExtension
->DataBuffer
+= TransferSize
;
2270 DeviceExtension
->DataTransferLength
-= TransferSize
;
2272 /* Write data block */
2273 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2275 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2281 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2288 DPRINT("AtapiReadWrite() done!\n");
2290 /* Wait for interrupt. */
2291 return(SRB_STATUS_PENDING
);
2296 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2297 PSCSI_REQUEST_BLOCK Srb
)
2302 DPRINT("AtapiFlushCache() called!\n");
2303 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2306 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_NO_FLUSH
)
2309 * NOTE: Don't flush the cache for CD/DVD drives. Although
2310 * the ATAPI-6 standard allows that, it has been experimentally
2311 * proved that it can damage some broken LG drives. Afterall
2312 * it doesn't make sense to flush cache on devices we don't
2315 return SRB_STATUS_INVALID_REQUEST
;
2318 if (!(DeviceExtension
->DeviceParams
[Srb
->TargetId
].SupportedFeatures83
& 0x1000))
2320 /* The device states it doesn't support the command */
2321 DPRINT("The drive doesn't support FLUSH_CACHE\n");
2322 return SRB_STATUS_INVALID_REQUEST
;
2325 /* Wait for BUSY to clear */
2326 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2328 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2329 if (!(Status
& IDE_SR_BUSY
))
2333 ScsiPortStallExecution(10);
2335 DPRINT("Status=%02x\n", Status
);
2336 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2337 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2339 DPRINT1("Drive is BUSY for too long\n");
2340 return(SRB_STATUS_BUSY
);
2343 /* Select the desired drive */
2344 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2345 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2346 ScsiPortStallExecution(10);
2348 /* Issue command to drive */
2349 AtapiExecuteCommand(DeviceExtension
,
2350 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_48BIT_ADDRESS
? IDE_CMD_FLUSH_CACHE_EXT
: IDE_CMD_FLUSH_CACHE
,
2351 AtapiNoDataInterrupt
);
2353 /* Wait for controller ready */
2354 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2356 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2357 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2361 ScsiPortStallExecution(10);
2363 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2365 DPRINT1("Drive is BUSY for too long after sending write command\n");
2366 DeviceExtension
->Handler
= NULL
;
2367 return(SRB_STATUS_BUSY
);
2370 DPRINT("AtapiFlushCache() done!\n");
2372 /* Wait for interrupt. */
2373 return(SRB_STATUS_PENDING
);
2378 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2379 PSCSI_REQUEST_BLOCK Srb
)
2385 DPRINT1("AtapiTestUnitReady() called!\n");
2387 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2390 /* Return success if media status is not supported */
2391 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2393 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2394 return(SRB_STATUS_SUCCESS
);
2397 /* Wait for BUSY to clear */
2398 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2400 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2401 if (!(Status
& IDE_SR_BUSY
))
2405 ScsiPortStallExecution(10);
2407 DPRINT1("Status=%02x\n", Status
);
2408 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2409 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2411 DPRINT1("Drive is BUSY for too long\n");
2412 return(SRB_STATUS_BUSY
);
2415 /* Select the desired drive */
2416 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2417 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2418 ScsiPortStallExecution(10);
2420 /* Issue command to drive */
2421 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2423 /* Wait for controller ready */
2424 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2426 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2427 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2431 ScsiPortStallExecution(10);
2433 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2435 DPRINT1("Drive is BUSY for too long after sending write command\n");
2436 DeviceExtension
->Handler
= NULL
;
2437 return(SRB_STATUS_BUSY
);
2440 if (Status
& IDE_SR_ERR
)
2442 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2443 if (Error
== IDE_ER_UNC
)
2446 /* Handle write protection 'error' */
2447 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2448 DeviceExtension
->Handler
= NULL
;
2449 return(SRB_STATUS_SUCCESS
);
2454 /* Indicate expecting an interrupt. */
2455 return(SRB_STATUS_PENDING
);
2459 DeviceExtension
->Handler
= NULL
;
2461 DPRINT1("AtapiTestUnitReady() done!\n");
2463 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2464 return(SRB_STATUS_SUCCESS
);
2469 AtapiErrorToScsi(PVOID DeviceExtension
,
2470 PSCSI_REQUEST_BLOCK Srb
)
2472 PATAPI_MINIPORT_EXTENSION DevExt
;
2473 ULONG CommandPortBase
;
2474 ULONG ControlPortBase
;
2479 DPRINT("AtapiErrorToScsi() called\n");
2481 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2483 CommandPortBase
= DevExt
->CommandPortBase
;
2484 ControlPortBase
= DevExt
->ControlPortBase
;
2486 ErrorReg
= IDEReadError(CommandPortBase
);
2488 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2490 switch (ErrorReg
>> 4)
2492 case SCSI_SENSE_NO_SENSE
:
2493 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2494 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2495 SrbStatus
= SRB_STATUS_ERROR
;
2498 case SCSI_SENSE_RECOVERED_ERROR
:
2499 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2501 SrbStatus
= SRB_STATUS_SUCCESS
;
2504 case SCSI_SENSE_NOT_READY
:
2505 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2506 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2507 SrbStatus
= SRB_STATUS_ERROR
;
2510 case SCSI_SENSE_MEDIUM_ERROR
:
2511 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2512 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2513 SrbStatus
= SRB_STATUS_ERROR
;
2516 case SCSI_SENSE_HARDWARE_ERROR
:
2517 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2518 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2519 SrbStatus
= SRB_STATUS_ERROR
;
2522 case SCSI_SENSE_ILLEGAL_REQUEST
:
2523 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2524 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2525 SrbStatus
= SRB_STATUS_ERROR
;
2528 case SCSI_SENSE_UNIT_ATTENTION
:
2529 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2530 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2531 SrbStatus
= SRB_STATUS_ERROR
;
2534 case SCSI_SENSE_DATA_PROTECT
:
2535 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2536 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2537 SrbStatus
= SRB_STATUS_ERROR
;
2540 case SCSI_SENSE_BLANK_CHECK
:
2541 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2542 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2543 SrbStatus
= SRB_STATUS_ERROR
;
2546 case SCSI_SENSE_ABORTED_COMMAND
:
2547 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2548 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2549 SrbStatus
= SRB_STATUS_ERROR
;
2553 DPRINT("ATAPI error: Invalid sense key\n");
2555 SrbStatus
= SRB_STATUS_ERROR
;
2561 DPRINT1("IDE error: %02x\n", ErrorReg
);
2564 SrbStatus
= SRB_STATUS_ERROR
;
2567 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2570 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2571 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2572 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2573 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2574 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2576 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2587 Srb
->ScsiStatus
= ScsiStatus
;
2589 DPRINT("AtapiErrorToScsi() done\n");
2596 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2598 DPRINT("AtapiConvertScsiToAtapi() called\n");
2600 Srb
->CdbLength
= 12;
2602 switch (Srb
->Cdb
[0])
2604 case SCSIOP_FORMAT_UNIT
:
2605 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2608 case SCSIOP_MODE_SELECT
:
2610 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2613 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2614 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2616 RtlZeroMemory (Srb
->Cdb
,
2618 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2619 AtapiModeSelect
->PFBit
= 1;
2620 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2621 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2627 static VOID FASTCALL
2628 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2631 PSCSI_REQUEST_BLOCK Srb
;
2632 Srb
= DevExt
->CurrentSrb
;
2634 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2636 Srb
->SrbStatus
= SrbStatus
;
2637 if (SrbStatus
== SRB_STATUS_ERROR
)
2639 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2641 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2643 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2646 DevExt
->Handler
= NULL
;
2647 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2648 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2652 static BOOLEAN FASTCALL
2653 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2662 DPRINT("AtapiPacketDmaInterrupt\n");
2664 DevExt
->UseDma
= FALSE
;
2667 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2668 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2669 /* get DMA status */
2670 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2671 /* clear the INTR & ERROR bits */
2672 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2674 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2675 DPRINT("DriveStatus: %x\n", Status
);
2677 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2679 if (Status
& IDE_SR_ERR
)
2681 Error
= IDEReadError(DevExt
->CommandPortBase
);
2682 SensKey
= Error
>> 4;
2683 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2685 SrbStatus
= SRB_STATUS_ERROR
;
2689 if ((DmaStatus
& 0x07) != 0x04)
2691 DPRINT("DmaStatus: %02x\n", DmaStatus
);
2692 SrbStatus
= SRB_STATUS_ERROR
;
2696 SrbStatus
= STATUS_SUCCESS
;
2699 AtapiCompleteRequest(DevExt
, SrbStatus
);
2700 DPRINT("AtapiDmaPacketInterrupt() done\n");
2705 static BOOLEAN FASTCALL
2706 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2708 PSCSI_REQUEST_BLOCK Srb
;
2714 PBYTE TargetAddress
;
2720 DPRINT("AtapiPacketInterrupt()\n");
2722 Srb
= DevExt
->CurrentSrb
;
2724 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2725 DPRINT("DriveStatus: %x\n", Status
);
2727 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2729 if (Status
& IDE_SR_ERR
)
2731 Error
= IDEReadError(DevExt
->CommandPortBase
);
2732 SensKey
= Error
>> 4;
2733 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2736 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2737 DPRINT("AtapiPacketInterrupt() done\n");
2741 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
2742 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
2743 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
2745 if (!(Status
& IDE_SR_DRQ
))
2747 if (DevExt
->DataTransferLength
> 0)
2749 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2750 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
2751 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
2755 SrbStatus
= SRB_STATUS_SUCCESS
;
2757 AtapiCompleteRequest(DevExt
, SrbStatus
);
2758 DPRINT("AtapiPacketInterrupt() done\n");
2762 TargetAddress
= DevExt
->DataBuffer
;
2764 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2766 DPRINT("read data\n");
2767 if (DevExt
->DataTransferLength
<= TransferSize
)
2769 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
2770 TransferSize
= DevExt
->DataTransferLength
;
2772 DevExt
->DataTransferLength
= 0;
2777 DevExt
->DataTransferLength
-= TransferSize
;
2778 IsLastBlock
= FALSE
;
2781 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
2783 DevExt
->DataBuffer
+= TransferSize
;
2785 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2790 /* Read remaining junk from device */
2791 while (JunkSize
> 0)
2793 IDEReadWord(DevExt
->CommandPortBase
);
2797 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
2799 ScsiPortStallExecution(10);
2802 /* Check for data overrun */
2803 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
2805 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2806 IDEReadWord(DevExt
->CommandPortBase
);
2810 SrbStatus
= SRB_STATUS_SUCCESS
;
2812 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2814 DPRINT("write data\n");
2815 if (DevExt
->DataTransferLength
< TransferSize
)
2817 TransferSize
= DevExt
->DataTransferLength
;
2820 TargetAddress
= DevExt
->DataBuffer
;
2822 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
2824 DevExt
->DataBuffer
+= TransferSize
;
2825 DevExt
->DataTransferLength
-= TransferSize
;
2827 /* Write the sector */
2828 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2829 SrbStatus
= SRB_STATUS_SUCCESS
;
2830 IsLastBlock
= FALSE
;
2834 DPRINT("Unspecified transfer direction!\n");
2835 SrbStatus
= SRB_STATUS_SUCCESS
;
2840 AtapiCompleteRequest(DevExt
, SrbStatus
);
2842 DPRINT("AtapiPacketInterrupt() done\n");
2846 static BOOLEAN FASTCALL
2847 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2851 DPRINT("AtapiNoDataInterrupt()\n");
2853 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2854 AtapiCompleteRequest(DevExt
,
2855 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
2857 DPRINT("AtapiNoDatanterrupt() done!\n");
2862 static BOOLEAN FASTCALL
2863 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2869 DPRINT("AtapiDmaInterrupt()\n");
2871 DevExt
->UseDma
= FALSE
;
2873 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2874 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2875 /* get DMA status */
2876 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2877 /* clear the INTR & ERROR bits */
2878 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2880 /* read the drive status */
2881 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2882 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
2883 (DmaStatus
& 0x07) == 4)
2885 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2886 DPRINT("AtapiDmaInterrupt() done\n");
2889 DPRINT1("Status %x\n", Status
);
2890 DPRINT1("%x\n", DmaStatus
);
2891 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2892 DPRINT1("AtapiDmaReadInterrupt() done\n");
2897 static BOOLEAN FASTCALL
2898 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2900 PSCSI_REQUEST_BLOCK Srb
;
2902 BOOLEAN IsLastBlock
;
2903 PUCHAR TargetAddress
;
2906 DPRINT("AtapiReadInterrupt() called!\n");
2908 Srb
= DevExt
->CurrentSrb
;
2910 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2911 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
2913 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
2915 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2916 DPRINT("AtapiReadInterrupt() done!\n");
2919 DPRINT("AtapiReadInterrupt() done!\n");
2923 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
2925 /* Update controller/device state variables */
2926 TargetAddress
= DevExt
->DataBuffer
;
2927 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2929 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2930 DPRINT("TransferSize: %lu\n", TransferSize
);
2932 if (DevExt
->DataTransferLength
<= TransferSize
)
2934 TransferSize
= DevExt
->DataTransferLength
;
2935 DevExt
->DataTransferLength
= 0;
2940 DevExt
->DataTransferLength
-= TransferSize
;
2941 IsLastBlock
= FALSE
;
2943 DevExt
->DataBuffer
+= TransferSize
;
2944 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
2946 /* Copy the block of data */
2947 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2949 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2953 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2958 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2961 DPRINT("AtapiReadInterrupt() done!\n");
2966 static BOOLEAN FASTCALL
2967 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
2969 PSCSI_REQUEST_BLOCK Srb
;
2971 BOOLEAN IsLastBlock
;
2972 PUCHAR TargetAddress
;
2975 DPRINT("AtapiWriteInterrupt() called!\n");
2977 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2978 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
2980 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
2982 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2983 DPRINT("AtapiWriteInterrupt() done!\n");
2986 DPRINT("AtapiWriteInterrupt() done!\n");
2991 Srb
= DevExt
->CurrentSrb
;
2992 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2993 if (DevExt
->DataTransferLength
< TransferSize
)
2995 TransferSize
= DevExt
->DataTransferLength
;
2997 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
2999 IsLastBlock
= FALSE
;
3000 TargetAddress
= DevExt
->DataBuffer
;
3001 DevExt
->DataBuffer
+= TransferSize
;
3002 DevExt
->DataTransferLength
-= TransferSize
;
3004 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
3005 DPRINT("TransferSize: %lu\n", TransferSize
);
3006 /* Write the sector */
3007 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
3009 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3013 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
3016 else if (DeviceStatus
& IDE_SR_DRQ
)
3018 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
3021 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
3023 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
3032 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
3034 DPRINT("AtapiWriteInterrupt() done!\n");
3040 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
3042 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
3044 if (DevExt
->Handler
!= NULL
)
3046 DPRINT1("DevExt->Handler is already set!!\n");
3048 DevExt
->Handler
= Handler
;
3049 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
3050 ScsiPortStallExecution(1);
3055 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
3056 PSCSI_REQUEST_BLOCK Srb
,
3061 PPRD PRDEntry
= DevExt
->PRDTable
;
3062 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
3067 DPRINT("AtapiInitDma()\n");
3069 StartAddress
= Srb
->DataBuffer
;
3070 EndAddress
= StartAddress
+ Srb
->DataTransferLength
;
3071 DevExt
->PRDCount
= 0;
3073 while (StartAddress
< EndAddress
)
3075 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
3076 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
3083 /* calculate the length up to the next 64k boundary */
3084 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
3085 if (tmpLength
> Length
)
3090 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3094 if (tmpLength
== 0x10000)
3096 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3098 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3099 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3100 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3101 PRDEntry
->Length
= tmpLength
;
3104 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3108 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3109 StartAddress
+= tmpLength
;
3110 Length
-= tmpLength
;
3111 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3113 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3114 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3115 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3116 PRDEntry
->Length
= tmpLength
;
3118 StartAddress
+= tmpLength
;
3119 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3120 Length
-= tmpLength
;
3123 /* set the end marker in the last PRD */
3125 PRDEntry
->Length
|= 0x80000000;
3126 /* set the PDR table */
3127 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3128 /* write the DMA command */
3129 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3130 /* reset the status and interrupt bit */
3131 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3132 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);