3 * Copyright (C) 2001, 2002, 2003, 2004 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.
19 /* $Id: atapi.c,v 1.50 2004/09/03 04:19:12 navaraf Exp $
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
120 typedef struct _UNIT_EXTENSION
123 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
125 PCI_SLOT_NUMBER LastSlotNumber
;
127 #ifdef ENABLE_NATIVE_PCI
128 typedef struct _PCI_NATIVE_CONTROLLER
133 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
135 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
139 0x4D68, // PDC20268, Ultra100TX2
143 0x4D30, // PDC20267, Ultra100
149 // ----------------------------------------------- Discardable Declarations
153 // make the initialization routines discardable, so that they
156 #pragma alloc_text(init, DriverEntry)
158 // make the PASSIVE_LEVEL routines pageable, so that they don't
159 // waste nonpaged memory
161 #endif /* ALLOC_PRAGMA */
163 // ---------------------------------------------------- Forward Declarations
167 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
168 PSCSI_REQUEST_BLOCK Srb
,
174 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
176 PVOID BusInformation
,
177 PCHAR ArgumentString
,
178 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
184 AtapiFindIsaBusController(PVOID DeviceExtension
,
186 PVOID BusInformation
,
187 PCHAR ArgumentString
,
188 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
192 #ifdef ENABLE_NATIVE_PCI
194 AtapiFindNativePciController(PVOID DeviceExtension
,
196 PVOID BusInformation
,
197 PCHAR ArgumentString
,
198 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
202 static BOOLEAN STDCALL
203 AtapiInitialize(IN PVOID DeviceExtension
);
205 static BOOLEAN STDCALL
206 AtapiResetBus(IN PVOID DeviceExtension
,
209 static BOOLEAN STDCALL
210 AtapiStartIo(IN PVOID DeviceExtension
,
211 IN PSCSI_REQUEST_BLOCK Srb
);
214 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
216 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
));
218 static BOOLEAN STDCALL
219 AtapiInterrupt(IN PVOID DeviceExtension
);
221 static BOOLEAN FASTCALL
222 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
);
224 static BOOLEAN FASTCALL
225 AtapiPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
227 static BOOLEAN FASTCALL
228 AtapiReadInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
231 static BOOLEAN FASTCALL
232 AtapiDmaPacketInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
234 static BOOLEAN FASTCALL
235 AtapiDmaInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
238 static BOOLEAN FASTCALL
239 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
);
242 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
243 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
246 AtapiIdentifyDevice(IN ULONG CommandPort
,
247 IN ULONG ControlPort
,
250 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
253 AtapiPolledRead(IN ULONG CommandPort
,
254 IN ULONG ControlPort
,
258 IN UCHAR CylinderLow
,
259 IN UCHAR CylinderHigh
,
265 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
266 IN PSCSI_REQUEST_BLOCK Srb
);
269 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
270 IN PSCSI_REQUEST_BLOCK Srb
);
273 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
274 IN PSCSI_REQUEST_BLOCK Srb
);
277 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
278 IN PSCSI_REQUEST_BLOCK Srb
);
281 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
282 IN PSCSI_REQUEST_BLOCK Srb
);
285 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
286 PSCSI_REQUEST_BLOCK Srb
);
289 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
290 PSCSI_REQUEST_BLOCK Srb
);
293 AtapiErrorToScsi(PVOID DeviceExtension
,
294 PSCSI_REQUEST_BLOCK Srb
);
297 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
);
299 // ---------------------------------------------------------------- Inlines
302 IDESwapBytePairs(char *Buf
,
308 for (i
= 0; i
< Cnt
; i
+= 2)
317 // ------------------------------------------------------- Public Interface
322 // This function initializes the driver, locates and claims
323 // hardware resources, and creates various NT objects needed
324 // to process I/O requests.
330 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
332 // IN PUNICODE_STRING RegistryPath Name of registry driver service
339 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
340 IN PUNICODE_STRING RegistryPath
)
342 HW_INITIALIZATION_DATA InitData
;
345 DPRINT("ATAPI Driver %s\n", VERSION
);
346 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
348 /* Initialize data structure */
349 RtlZeroMemory(&InitData
,
350 sizeof(HW_INITIALIZATION_DATA
));
351 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
352 InitData
.HwInitialize
= AtapiInitialize
;
353 InitData
.HwResetBus
= AtapiResetBus
;
354 InitData
.HwStartIo
= AtapiStartIo
;
355 InitData
.HwInterrupt
= AtapiInterrupt
;
357 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
358 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
360 InitData
.MapBuffers
= TRUE
;
362 /* Search the PCI bus for compatibility mode ide controllers */
364 InitData
.NeedPhysicalAddresses
= TRUE
;
366 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
367 InitData
.NumberOfAccessRanges
= 3;
368 InitData
.AdapterInterfaceType
= PCIBus
;
370 InitData
.VendorId
= NULL
;
371 InitData
.VendorIdLength
= 0;
372 InitData
.DeviceId
= NULL
;
373 InitData
.DeviceIdLength
= 0;
375 Status
= ScsiPortInitialize(DriverObject
,
379 // if (newStatus < statusToReturn)
380 // statusToReturn = newStatus;
383 /* Search the PCI bus for all ide controllers */
384 #ifdef ENABLE_NATIVE_PCI
385 InitData
.NeedPhysicalAddresses
= TRUE
;
387 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
388 InitData
.NumberOfAccessRanges
= 3;
389 InitData
.AdapterInterfaceType
= PCIBus
;
391 InitData
.VendorId
= 0;
392 InitData
.VendorIdLength
= 0;
393 InitData
.DeviceId
= 0;
394 InitData
.DeviceIdLength
= 0;
396 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
398 Status
= ScsiPortInitialize(DriverObject
,
402 // if (newStatus < statusToReturn)
403 // statusToReturn = newStatus;
406 /* Search the ISA bus for ide controllers */
408 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
409 InitData
.NumberOfAccessRanges
= 2;
410 InitData
.AdapterInterfaceType
= Isa
;
412 InitData
.VendorId
= NULL
;
413 InitData
.VendorIdLength
= 0;
414 InitData
.DeviceId
= NULL
;
415 InitData
.DeviceIdLength
= 0;
417 Status
= ScsiPortInitialize(DriverObject
,
421 // if (newStatus < statusToReturn)
422 // statusToReturn = newStatus;
425 DPRINT("Returning from DriverEntry\n");
432 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
433 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
434 INTERFACE_TYPE InterfaceType
,
435 ULONG CommandPortBase
,
436 ULONG ControlPortBase
,
437 ULONG BusMasterPortBase
,
438 ULONG InterruptVector
)
440 SCSI_PHYSICAL_ADDRESS IoAddress
;
445 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
446 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
448 ConfigInfo
->SystemIoBusNumber
,
456 DevExt
->Handler
= NULL
;
457 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
458 ConfigInfo
->AccessRanges
[0].RangeStart
= IoAddress
;
459 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
460 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
464 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
465 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
467 ConfigInfo
->SystemIoBusNumber
,
473 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
474 (PVOID
)DevExt
->CommandPortBase
);
477 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
478 ConfigInfo
->AccessRanges
[1].RangeStart
= IoAddress
;
479 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
480 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
482 if (BusMasterPortBase
)
484 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
485 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
487 ConfigInfo
->SystemIoBusNumber
,
493 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
494 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
497 DevExt
->BusMasterRegisterBase
= (ULONG
)IoBase
;
498 ConfigInfo
->AccessRanges
[2].RangeStart
= IoAddress
;
499 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
500 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
502 // ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE;
503 // ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE;
504 ConfigInfo
->DmaWidth
= Width32Bits
;
505 // ConfigInfo->DmaSpeed = Compatible;
506 ConfigInfo
->ScatterGather
= TRUE
;
507 ConfigInfo
->Master
= TRUE
;
508 ConfigInfo
->NumberOfPhysicalBreaks
= 0x10000 / PAGE_SIZE
+ 1;
509 ConfigInfo
->Dma32BitAddresses
= TRUE
;
510 ConfigInfo
->NeedPhysicalAddresses
= TRUE
;
511 ConfigInfo
->MapBuffers
= TRUE
;
513 DevExt
->PRDMaxCount
= PAGE_SIZE
/ sizeof(PRD
);
514 DevExt
->PRDTable
= ScsiPortGetUncachedExtension(DevExt
, ConfigInfo
, sizeof(PRD
) * DevExt
->PRDMaxCount
);
515 if (DevExt
->PRDTable
!= NULL
)
517 DevExt
->PRDTablePhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, NULL
, DevExt
->PRDTable
, &Length
);
519 if (DevExt
->PRDTable
== NULL
||
520 DevExt
->PRDTablePhysicalAddress
.QuadPart
== 0LL ||
521 Length
< sizeof(PRD
) * DevExt
->PRDMaxCount
)
523 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
524 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
525 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->BusMasterRegisterBase
);
530 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
531 ConfigInfo
->BusInterruptVector
= InterruptVector
;
532 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
534 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
536 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
538 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
540 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
548 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
550 PVOID BusInformation
,
551 PCHAR ArgumentString
,
552 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
555 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
556 PCI_SLOT_NUMBER SlotNumber
;
557 PCI_COMMON_CONFIG PciConfig
;
559 ULONG StartDeviceNumber
;
561 ULONG StartFunctionNumber
;
562 ULONG FunctionNumber
;
563 BOOLEAN ChannelFound
;
565 ULONG BusMasterBasePort
= 0;
567 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
568 ConfigInfo
->SystemIoBusNumber
,
569 ConfigInfo
->SlotNumber
);
573 /* both channels were claimed: exit */
574 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
575 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
576 return(SP_RETURN_NOT_FOUND
);
578 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
579 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
580 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
581 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
583 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
584 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
586 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
587 ChannelFound
= FALSE
;
590 DataSize
= ScsiPortGetBusData(DeviceExtension
,
592 ConfigInfo
->SystemIoBusNumber
,
593 SlotNumber
.u
.AsULONG
,
595 PCI_COMMON_HDR_LENGTH
);
596 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
598 if (FunctionNumber
== 0)
608 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
609 if (PciConfig
.BaseClass
== 0x01 &&
610 PciConfig
.SubClass
== 0x01) // &&
611 // (PciConfig.ProgIf & 0x05) == 0)
613 /* both channels are in compatibility mode */
614 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
615 ConfigInfo
->SystemIoBusNumber
,
616 SlotNumber
.u
.bits
.DeviceNumber
,
617 SlotNumber
.u
.bits
.FunctionNumber
,
620 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
622 DPRINT("Found IDE controller in compatibility mode!\n");
624 ConfigInfo
->NumberOfBuses
= 1;
625 ConfigInfo
->MaximumNumberOfTargets
= 2;
626 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
628 if (PciConfig
.ProgIf
& 0x80)
630 DPRINT("Found IDE Bus Master controller!\n");
631 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
633 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
634 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
637 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
639 /* Both channels unclaimed: Claim primary channel */
640 DPRINT("Primary channel!\n");
641 ChannelFound
= AtapiClaimHwResources(DevExt
,
650 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
652 /* Primary channel already claimed: claim secondary channel */
653 DPRINT("Secondary channel!\n");
655 ChannelFound
= AtapiClaimHwResources(DevExt
,
660 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
664 /* Find attached devices */
667 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
668 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
669 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
670 return(SP_RETURN_FOUND
);
673 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
678 StartFunctionNumber
= 0;
680 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
682 return(SP_RETURN_NOT_FOUND
);
689 AtapiFindIsaBusController(PVOID DeviceExtension
,
691 PVOID BusInformation
,
692 PCHAR ArgumentString
,
693 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
696 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
697 BOOLEAN ChannelFound
= FALSE
;
698 BOOLEAN DeviceFound
= FALSE
;
700 DPRINT("AtapiFindIsaBusController() called!\n");
704 ConfigInfo
->NumberOfBuses
= 1;
705 ConfigInfo
->MaximumNumberOfTargets
= 2;
706 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
708 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
710 /* Both channels unclaimed: Claim primary channel */
711 DPRINT("Primary channel!\n");
713 ChannelFound
= AtapiClaimHwResources(DevExt
,
722 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
724 /* Primary channel already claimed: claim secondary channel */
725 DPRINT("Secondary channel!\n");
727 ChannelFound
= AtapiClaimHwResources(DevExt
,
738 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
740 return(SP_RETURN_NOT_FOUND
);
743 /* Find attached devices */
746 DeviceFound
= AtapiFindDevices(DevExt
,
748 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
749 return(SP_RETURN_FOUND
);
752 return SP_RETURN_NOT_FOUND
;
757 #ifdef ENABLE_NATIVE_PCI
759 AtapiFindNativePciController(PVOID DeviceExtension
,
761 PVOID BusInformation
,
762 PCHAR ArgumentString
,
763 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
766 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
767 PCI_COMMON_CONFIG PciConfig
;
768 PCI_SLOT_NUMBER SlotNumber
;
771 ULONG StartDeviceNumber
;
772 ULONG FunctionNumber
;
773 ULONG StartFunctionNumber
;
774 ULONG BusMasterBasePort
;
776 BOOLEAN ChannelFound
;
778 DPRINT("AtapiFindNativePciController() called!\n");
780 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
781 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
782 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
783 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
785 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
786 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
788 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
789 DataSize
= ScsiPortGetBusData(DeviceExtension
,
791 ConfigInfo
->SystemIoBusNumber
,
792 SlotNumber
.u
.AsULONG
,
794 PCI_COMMON_HDR_LENGTH
);
795 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
799 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
801 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
802 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
807 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
809 /* We have found a known native pci ide controller */
810 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
812 DPRINT("Found IDE Bus Master controller!\n");
813 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
814 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
818 BusMasterBasePort
= 0;
821 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
822 ConfigInfo
->NumberOfBuses
= 1;
823 ConfigInfo
->MaximumNumberOfTargets
= 2;
824 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
827 We must not store and use the last tested slot number. If there is a recall
828 to the some device and we will claim the primary channel again than the call
829 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
830 claim the secondary channel.
832 ChannelFound
= FALSE
;
833 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
835 /* try to claim primary channel */
836 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
837 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
839 /* primary channel is enabled */
840 ChannelFound
= AtapiClaimHwResources(DevExt
,
843 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
844 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
846 PciConfig
.u
.type0
.InterruptLine
);
849 AtapiFindDevices(DevExt
, ConfigInfo
);
851 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
852 return SP_RETURN_FOUND
;
858 /* try to claim secondary channel */
859 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
860 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
862 /* secondary channel is enabled */
863 ChannelFound
= AtapiClaimHwResources(DevExt
,
866 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
867 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
868 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
869 PciConfig
.u
.type0
.InterruptLine
);
872 AtapiFindDevices(DevExt
, ConfigInfo
);
874 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
875 return SP_RETURN_FOUND
;
881 StartFunctionNumber
= 0;
884 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
885 DPRINT("AtapiFindNativePciController() done!\n");
887 return(SP_RETURN_NOT_FOUND
);
892 static BOOLEAN STDCALL
893 AtapiInitialize(IN PVOID DeviceExtension
)
899 static BOOLEAN STDCALL
900 AtapiResetBus(IN PVOID DeviceExtension
,
907 static BOOLEAN STDCALL
908 AtapiStartIo(IN PVOID DeviceExtension
,
909 IN PSCSI_REQUEST_BLOCK Srb
)
911 PATAPI_MINIPORT_EXTENSION DevExt
;
914 DPRINT("AtapiStartIo() called\n");
916 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
918 switch (Srb
->Function
)
920 case SRB_FUNCTION_EXECUTE_SCSI
:
921 DevExt
->CurrentSrb
= Srb
;
922 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
924 Result
= AtapiSendAtapiCommand(DevExt
,
929 Result
= AtapiSendIdeCommand(DevExt
,
934 case SRB_FUNCTION_ABORT_COMMAND
:
935 if (DevExt
->CurrentSrb
!= NULL
)
937 Result
= SRB_STATUS_ABORT_FAILED
;
941 Result
= SRB_STATUS_SUCCESS
;
946 Result
= SRB_STATUS_INVALID_REQUEST
;
950 Srb
->SrbStatus
= Result
;
953 if (Result
!= SRB_STATUS_PENDING
)
955 DevExt
->CurrentSrb
= NULL
;
956 Srb
->SrbStatus
= (UCHAR
)Result
;
958 ScsiPortNotification(RequestComplete
,
961 ScsiPortNotification(NextRequest
,
967 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
970 DPRINT("AtapiStartIo() done\n");
975 static BOOLEAN STDCALL
976 AtapiInterrupt(IN PVOID DeviceExtension
)
978 PATAPI_MINIPORT_EXTENSION DevExt
;
980 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
982 if (DevExt
->Handler
== NULL
)
984 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
985 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) != IDE_SR_DRDY
)
987 static ULONG Count
= 0;
989 DPRINT1("Unexpected Interrupt, CommandPort=%04x, Status=%02x, Count=%ld\n",
990 DevExt
->CommandPortBase
, Status
, Count
);
997 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
998 if (!(Status
& 0x04))
1006 Status
= IDEReadAltStatus(DevExt
->ControlPortBase
);
1007 if (Status
& IDE_SR_BUSY
)
1012 return DevExt
->Handler(DevExt
);
1015 // ---------------------------------------------------- Discardable statics
1019 AtapiConfigDma(PATAPI_MINIPORT_EXTENSION DeviceExtension
, ULONG UnitNumber
)
1021 BOOLEAN Result
= FALSE
;
1026 if (DeviceExtension
->PRDTable
)
1028 if (DeviceExtension
->DeviceParams
[UnitNumber
].Capabilities
& IDE_DRID_DMA_SUPPORTED
)
1030 if ((DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0004) &&
1031 (DeviceExtension
->DeviceParams
[UnitNumber
].UltraDmaModes
& 0x7F00))
1035 else if (DeviceExtension
->DeviceParams
[UnitNumber
].TMFieldsValid
& 0x0002)
1037 if ((DeviceExtension
->DeviceParams
[UnitNumber
].MultiDmaModes
& 0x0404) == 0x0404)
1043 * should we support single mode dma ?
1045 else if ((DeviceExtension
->DeviceParams
[UnitNumber
].DmaModes
& 0x0404) == 0x0404)
1051 Status
= IDEReadDMAStatus(DeviceExtension
->BusMasterRegisterBase
);
1054 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
| (UnitNumber
? 0x40 : 0x20));
1058 IDEWriteDMAStatus(DeviceExtension
->BusMasterRegisterBase
, Status
& (UnitNumber
? ~0x40 : ~0x20));
1067 /**********************************************************************
1072 * Searches for devices on the given port.
1079 * Port device specific information.
1082 * Port configuration information.
1085 * TRUE: At least one device is attached to the port.
1086 * FALSE: No device is attached to the port.
1090 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1091 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1093 BOOLEAN DeviceFound
= FALSE
;
1094 ULONG CommandPortBase
;
1095 ULONG ControlPortBase
;
1101 DPRINT("AtapiFindDevices() called\n");
1103 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
1104 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1106 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
1107 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1109 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1112 IDEWriteDriveHead(CommandPortBase
,
1113 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1114 ScsiPortStallExecution(500);
1116 /* Disable interrupts */
1117 IDEWriteDriveControl(ControlPortBase
,
1119 ScsiPortStallExecution(500);
1121 /* Check if a device is attached to the interface */
1122 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1123 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1125 High
= IDEReadCylinderHigh(CommandPortBase
);
1126 Low
= IDEReadCylinderLow(CommandPortBase
);
1128 IDEWriteCylinderHigh(CommandPortBase
, 0);
1129 IDEWriteCylinderLow(CommandPortBase
, 0);
1131 if (Low
!= 0x55 || High
!= 0xaa)
1133 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1138 IDEWriteDriveControl(ControlPortBase
, IDE_DC_nIEN
| IDE_DC_SRST
);
1139 ScsiPortStallExecution(500);
1140 IDEWriteDriveControl(ControlPortBase
, IDE_DC_nIEN
);
1141 ScsiPortStallExecution(500);
1143 for (Retries
= 0; Retries
< 20000; Retries
++)
1145 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1149 ScsiPortStallExecution(150);
1151 if (Retries
>= 20000)
1153 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1154 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1158 High
= IDEReadCylinderHigh(CommandPortBase
);
1159 Low
= IDEReadCylinderLow(CommandPortBase
);
1161 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1166 if (High
== 0xEB && Low
== 0x14)
1168 if (AtapiIdentifyDevice(CommandPortBase
,
1172 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1174 DPRINT(" ATAPI drive found!\n");
1175 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1176 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1177 DeviceExtension
->TransferSize
[UnitNumber
] =
1178 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1180 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1182 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1185 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_RESET
, NULL
);
1186 ScsiPortStallExecution(500);
1191 DPRINT(" No ATAPI drive found!\n");
1196 if (AtapiIdentifyDevice(CommandPortBase
,
1200 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1202 DPRINT(" IDE drive found!\n");
1203 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1204 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1205 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1206 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1207 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1208 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1210 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1211 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1213 if (DeviceExtension
->DeviceParams
[UnitNumber
].SupportedFeatures83
& 0x0400 &&
1214 DeviceExtension
->DeviceParams
[UnitNumber
].EnabledFeatures86
& 0x0400)
1216 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_48BIT_ADDRESS
;
1218 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1220 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1223 if (AtapiConfigDma(DeviceExtension
, UnitNumber
))
1225 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DMA_CMD
;
1232 DPRINT(" No IDE drive found!\n");
1237 /* Reset pending interrupts */
1238 IDEReadStatus(CommandPortBase
);
1239 /* Reenable interrupts */
1240 IDEWriteDriveControl(ControlPortBase
, 0);
1241 ScsiPortStallExecution(500);
1242 /* Return with drive 0 selected */
1243 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1244 ScsiPortStallExecution(500);
1246 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1248 return(DeviceFound
);
1253 * AtapiIdentifyDevice
1256 * Get the identification block from the drive
1263 * Address of the command port
1265 * Address of the control port
1267 * The drive index (0,1)
1269 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1271 * Address to write drive ident block
1274 * TRUE: The drive identification block was retrieved successfully
1275 * FALSE: an error ocurred
1279 AtapiIdentifyDevice(IN ULONG CommandPort
,
1280 IN ULONG ControlPort
,
1283 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1288 /* Get the Drive Identify block from drive or die */
1289 if (AtapiPolledRead(CommandPort
,
1296 (DriveNum
? IDE_DH_DRV1
: 0),
1297 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1298 (PUCHAR
)DrvParms
) == FALSE
)
1300 DPRINT("AtapiPolledRead() failed\n");
1304 /* Report on drive parameters if debug mode */
1305 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1306 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1307 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1308 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1309 DrvParms
->ConfigBits
,
1310 DrvParms
->LogicalCyls
,
1311 DrvParms
->LogicalHeads
,
1312 DrvParms
->SectorsPerTrack
,
1313 DrvParms
->InterSectorGap
,
1314 DrvParms
->InterSectorGapSize
);
1315 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1316 DrvParms
->BytesInPLO
,
1317 DrvParms
->VendorUniqueCnt
,
1318 DrvParms
->SerialNumber
);
1319 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1320 DrvParms
->ControllerType
,
1321 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1322 DrvParms
->ECCByteCnt
,
1323 DrvParms
->FirmwareRev
);
1324 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1325 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1326 (DrvParms
->RWMultImplemented
),
1327 (DrvParms
->RWMultCurrent
) & 0xff,
1328 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1329 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1330 DrvParms
->MinPIOTransTime
,
1331 DrvParms
->MinDMATransTime
);
1332 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1333 DrvParms
->TMCylinders
,
1335 DrvParms
->TMSectorsPerTrk
,
1336 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1337 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1338 DrvParms
->TMSectorCountHi
,
1339 DrvParms
->TMSectorCountLo
,
1340 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1341 if (DrvParms
->TMFieldsValid
& 0x0004)
1343 if ((DrvParms
->UltraDmaModes
>> 8) && (DrvParms
->UltraDmaModes
& 0xff))
1346 while (!(DrvParms
->UltraDmaModes
& (0x0100 << mode
)))
1350 DPRINT("Ultra DMA mode %d is selected\n", mode
);
1352 else if ((DrvParms
->MultiDmaModes
>> 8) & (DrvParms
->MultiDmaModes
& 0x07))
1355 while(!(DrvParms
->MultiDmaModes
& (0x01 << mode
)))
1359 DPRINT("Multi DMA mode %d is selected\n", mode
);
1363 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1365 /* LBA ATA drives always have a sector size of 512 */
1366 DrvParms
->BytesPerSector
= 512;
1370 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1371 if (DrvParms
->BytesPerSector
== 0)
1373 DrvParms
->BytesPerSector
= 512;
1377 for (i
= 15; i
>= 0; i
--)
1379 if (DrvParms
->BytesPerSector
& (1 << i
))
1381 DrvParms
->BytesPerSector
= 1 << i
;
1387 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1396 // Read a sector of data from the drive in a polled fashion.
1402 // IN ULONG CommandPort Address of command port for drive
1403 // IN ULONG ControlPort Address of control port for drive
1404 // IN UCHAR PreComp Value to write to precomp register
1405 // IN UCHAR SectorCnt Value to write to sectorCnt register
1406 // IN UCHAR SectorNum Value to write to sectorNum register
1407 // IN UCHAR CylinderLow Value to write to CylinderLow register
1408 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1409 // IN UCHAR DrvHead Value to write to Drive/Head register
1410 // IN UCHAR Command Value to write to Command register
1411 // OUT PUCHAR Buffer Buffer for output data
1414 // BOOLEAN: TRUE success, FALSE error
1418 AtapiPolledRead(IN ULONG CommandPort
,
1419 IN ULONG ControlPort
,
1423 IN UCHAR CylinderLow
,
1424 IN UCHAR CylinderHigh
,
1429 ULONG SectorCount
= 0;
1431 BOOLEAN Junk
= FALSE
;
1434 /* Wait for BUSY to clear */
1435 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1437 Status
= IDEReadStatus(CommandPort
);
1438 if (!(Status
& IDE_SR_BUSY
))
1442 ScsiPortStallExecution(10);
1444 DPRINT("status=%02x\n", Status
);
1445 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1446 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1448 DPRINT("Drive is BUSY for too long\n");
1452 /* Write Drive/Head to select drive */
1453 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1454 ScsiPortStallExecution(500);
1456 /* Disable interrupts */
1457 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1458 ScsiPortStallExecution(500);
1461 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1462 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1464 Status
= IDEReadStatus(CommandPort
);
1465 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1469 ScsiPortStallExecution(10);
1471 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1477 /* Issue command to drive */
1478 if (DrvHead
& IDE_DH_LBA
)
1480 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1481 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1482 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1488 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1489 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1498 /* Setup command parameters */
1499 IDEWritePrecomp(CommandPort
, PreComp
);
1500 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1501 IDEWriteSectorNum(CommandPort
, SectorNum
);
1502 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1503 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1504 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1506 /* Issue the command */
1507 IDEWriteCommand(CommandPort
, Command
);
1508 ScsiPortStallExecution(50);
1510 /* wait for DRQ or error */
1511 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1513 Status
= IDEReadStatus(CommandPort
);
1514 if (!(Status
& IDE_SR_BUSY
))
1516 if (Status
& IDE_SR_ERR
)
1518 IDEWriteDriveControl(ControlPort
, 0);
1519 ScsiPortStallExecution(50);
1520 IDEReadStatus(CommandPort
);
1525 if (Status
& IDE_SR_DRQ
)
1531 IDEWriteDriveControl(ControlPort
, 0);
1532 ScsiPortStallExecution(50);
1533 IDEReadStatus(CommandPort
);
1538 ScsiPortStallExecution(10);
1542 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1544 IDEWriteDriveControl(ControlPort
, 0);
1545 ScsiPortStallExecution(50);
1546 IDEReadStatus(CommandPort
);
1553 /* Read data into buffer */
1556 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1557 Buffer
+= IDE_SECTOR_BUF_SZ
;
1561 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1562 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1566 /* Check for error or more sectors to read */
1567 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1569 Status
= IDEReadStatus(CommandPort
);
1570 if (!(Status
& IDE_SR_BUSY
))
1572 if (Status
& IDE_SR_ERR
)
1574 IDEWriteDriveControl(ControlPort
, 0);
1575 ScsiPortStallExecution(50);
1576 IDEReadStatus(CommandPort
);
1580 if (Status
& IDE_SR_DRQ
)
1582 if (SectorCount
>= SectorCnt
)
1584 DPRINT("Buffer size exceeded!\n");
1591 if (SectorCount
> SectorCnt
)
1593 DPRINT("Read %lu sectors of junk!\n",
1594 SectorCount
- SectorCnt
);
1596 IDEWriteDriveControl(ControlPort
, 0);
1597 ScsiPortStallExecution(50);
1598 IDEReadStatus(CommandPort
);
1608 // ------------------------------------------- Nondiscardable statics
1611 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1612 IN PSCSI_REQUEST_BLOCK Srb
)
1614 UCHAR ByteCountHigh
;
1620 DPRINT("AtapiSendAtapiCommand() called!\n");
1622 if (Srb
->PathId
!= 0)
1624 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1625 return(SRB_STATUS_INVALID_PATH_ID
);
1628 if (Srb
->TargetId
> 1)
1630 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1631 return(SRB_STATUS_INVALID_TARGET_ID
);
1636 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1637 return(SRB_STATUS_INVALID_LUN
);
1640 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1642 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1643 return(SRB_STATUS_NO_DEVICE
);
1646 if (Srb
->Cdb
[0] == SCSIOP_MODE_SENSE
)
1648 Srb
->SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1649 return (SRB_STATUS_INVALID_REQUEST
);
1652 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1655 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1656 return(AtapiInquiry(DeviceExtension
,
1659 /* Set pointer to data buffer. */
1660 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1661 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1662 DeviceExtension
->CurrentSrb
= Srb
;
1664 DPRINT("BufferAddress %x, BufferLength %d\n", Srb
->DataBuffer
, Srb
->DataTransferLength
);
1666 /* Wait for BUSY to clear */
1667 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1669 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1670 if (!(Status
& IDE_SR_BUSY
))
1674 ScsiPortStallExecution(10);
1676 DPRINT("status=%02x\n", Status
);
1677 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1678 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1680 DPRINT("Drive is BUSY for too long\n");
1681 return(SRB_STATUS_BUSY
);
1684 /* Select the desired drive */
1685 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1686 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1688 /* Wait a little while */
1689 ScsiPortStallExecution(50);
1692 /* Wait for BUSY to clear and DRDY to assert */
1693 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1695 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1696 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1700 ScsiPortStallExecution(10);
1702 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1703 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1705 DPRINT("Drive is BUSY for too long after drive select\n");
1706 return(SRB_STATUS_BUSY
);
1711 if ((DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
) &&
1712 (Srb
->Cdb
[0] == SCSIOP_READ
|| Srb
->Cdb
[0] == SCSIOP_WRITE
))
1714 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
1718 DeviceExtension
->UseDma
= FALSE
;
1722 if (DeviceExtension
->DataTransferLength
< 0x10000)
1724 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1725 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1729 ByteCountLow
= 0xFF;
1730 ByteCountHigh
= 0xFF;
1733 /* Set feature register */
1735 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, DeviceExtension
->UseDma
? 1 : 0);
1737 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1740 /* Set command packet length */
1741 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1742 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1744 /* Issue command to drive */
1746 if (DeviceExtension
->UseDma
)
1748 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiDmaPacketInterrupt
);
1753 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_PACKET
, AtapiPacketInterrupt
);
1756 /* Wait for DRQ to assert */
1757 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1759 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1760 if ((Status
& IDE_SR_DRQ
))
1764 ScsiPortStallExecution(10);
1767 /* Convert special SCSI SRBs to ATAPI format */
1768 switch (Srb
->Cdb
[0])
1770 case SCSIOP_FORMAT_UNIT
:
1771 case SCSIOP_MODE_SELECT
:
1772 AtapiScsiSrbToAtapi (Srb
);
1776 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
1777 DPRINT("CdbSize: %lu\n", CdbSize
);
1779 /* Write command packet */
1780 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1785 if (DeviceExtension
->UseDma
)
1789 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
1790 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
1793 DPRINT("AtapiSendAtapiCommand() done\n");
1795 return(SRB_STATUS_PENDING
);
1800 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1801 IN PSCSI_REQUEST_BLOCK Srb
)
1803 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1805 DPRINT("AtapiSendIdeCommand() called!\n");
1807 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1812 if (Srb
->PathId
!= 0)
1814 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1815 return(SRB_STATUS_INVALID_PATH_ID
);
1818 if (Srb
->TargetId
> 1)
1820 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1821 return(SRB_STATUS_INVALID_TARGET_ID
);
1826 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1827 return(SRB_STATUS_INVALID_LUN
);
1830 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1832 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1833 return(SRB_STATUS_NO_DEVICE
);
1836 switch (Srb
->Cdb
[0])
1838 case SCSIOP_INQUIRY
:
1839 SrbStatus
= AtapiInquiry(DeviceExtension
,
1843 case SCSIOP_READ_CAPACITY
:
1844 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1850 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1854 case SCSIOP_SYNCHRONIZE_CACHE
:
1855 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1859 case SCSIOP_TEST_UNIT_READY
:
1860 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1864 case SCSIOP_MODE_SENSE
:
1867 case SCSIOP_START_STOP_UNIT
:
1868 case SCSIOP_REQUEST_SENSE
:
1872 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1874 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1878 DPRINT("AtapiSendIdeCommand() done!\n");
1885 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1886 PSCSI_REQUEST_BLOCK Srb
)
1888 PIDE_DRIVE_IDENTIFY DeviceParams
;
1889 PINQUIRYDATA InquiryData
;
1892 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1893 DeviceExtension
, Srb
->TargetId
);
1895 InquiryData
= Srb
->DataBuffer
;
1896 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1899 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1901 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1904 /* set device class */
1905 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1907 /* get it from the ATAPI configuration word */
1908 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1909 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1914 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1917 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1918 if (DeviceParams
->ConfigBits
& 0x80)
1920 DPRINT("Removable media!\n");
1921 InquiryData
->RemovableMedia
= 1;
1924 for (i
= 0; i
< 20; i
+= 2)
1926 InquiryData
->VendorId
[i
] =
1927 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1928 InquiryData
->VendorId
[i
+1] =
1929 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1932 for (i
= 0; i
< 4; i
++)
1934 InquiryData
->ProductId
[12+i
] = ' ';
1937 for (i
= 0; i
< 4; i
+= 2)
1939 InquiryData
->ProductRevisionLevel
[i
] =
1940 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1941 InquiryData
->ProductRevisionLevel
[i
+1] =
1942 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1945 InquiryData
->AdditionalLength
= 31;
1947 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1949 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1950 return(SRB_STATUS_SUCCESS
);
1955 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1956 PSCSI_REQUEST_BLOCK Srb
)
1958 PREAD_CAPACITY_DATA CapacityData
;
1959 PIDE_DRIVE_IDENTIFY DeviceParams
;
1962 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1963 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1964 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1966 /* Set sector (block) size to 512 bytes (big-endian). */
1967 CapacityData
->BytesPerBlock
= 0x20000;
1969 /* Calculate last sector (big-endian). */
1970 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1972 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1973 DeviceParams
->TMSectorCountLo
) - 1;
1977 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1978 DeviceParams
->LogicalHeads
*
1979 DeviceParams
->SectorsPerTrack
)-1;
1982 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1983 (((PUCHAR
)&LastSector
)[1] << 16) |
1984 (((PUCHAR
)&LastSector
)[2] << 8) |
1985 ((PUCHAR
)&LastSector
)[3];
1987 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1990 CapacityData
->LogicalBlockAddress
);
1992 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1993 return(SRB_STATUS_SUCCESS
);
1998 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1999 PSCSI_REQUEST_BLOCK Srb
)
2001 PIDE_DRIVE_IDENTIFY DeviceParams
;
2002 ULONG StartingSector
;
2011 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION DevExt
);
2013 DPRINT("AtapiReadWrite() called!\n");
2014 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2017 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2019 /* Get starting sector number from CDB. */
2020 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2021 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2022 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2023 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2025 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2026 DeviceParams
->BytesPerSector
;
2028 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2030 Srb
->DataTransferLength
,
2033 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2035 SectorNumber
= StartingSector
& 0xff;
2036 CylinderLow
= (StartingSector
>> 8) & 0xff;
2037 CylinderHigh
= (StartingSector
>> 16) & 0xff;
2038 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2039 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2044 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2045 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2046 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2047 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2048 StartingSector
/= DeviceParams
->LogicalHeads
;
2049 CylinderLow
= StartingSector
& 0xff;
2050 CylinderHigh
= StartingSector
>> 8;
2053 if (DrvHead
& IDE_DH_LBA
)
2055 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2056 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2057 DeviceExtension
->CommandPortBase
,
2058 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2059 ((DrvHead
& 0x0f) << 24) +
2060 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
2066 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2067 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2068 DeviceExtension
->CommandPortBase
,
2069 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2078 /* Set pointer to data buffer. */
2079 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2080 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2082 DeviceExtension
->CurrentSrb
= Srb
;
2084 /* wait for BUSY to clear */
2085 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2087 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2088 if (!(Status
& IDE_SR_BUSY
))
2092 ScsiPortStallExecution(10);
2094 DPRINT("status=%02x\n", Status
);
2095 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2096 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2098 DPRINT ("Drive is BUSY for too long\n");
2099 return(SRB_STATUS_BUSY
);
2102 /* Select the desired drive */
2103 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2104 IDE_DH_FIXED
| DrvHead
);
2106 ScsiPortStallExecution(10);
2108 /* wait for BUSY to clear and DRDY to assert */
2109 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2111 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2112 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2116 ScsiPortStallExecution(10);
2118 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2119 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2121 DPRINT("Drive is BUSY for too long after drive select\n");
2122 return(SRB_STATUS_BUSY
);
2126 /* Setup command parameters */
2127 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2128 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
2129 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
2130 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
2131 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
2132 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2135 if (DeviceExtension
->PRDTable
&&
2136 DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DMA_CMD
)
2138 DeviceExtension
->UseDma
= AtapiInitDma(DeviceExtension
, Srb
, Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? 1 << 3 : 0);
2140 if (DeviceExtension
->UseDma
)
2142 Handler
= AtapiDmaInterrupt
;
2143 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_DMA
: IDE_CMD_WRITE_DMA
;
2148 Handler
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? AtapiReadInterrupt
: AtapiWriteInterrupt
;
2149 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
)
2151 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ_MULTIPLE
: IDE_CMD_WRITE_MULTIPLE
;
2155 Command
= Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
? IDE_CMD_READ
: IDE_CMD_WRITE
;
2159 AtapiExecuteCommand(DeviceExtension
, Command
, Handler
);
2162 if (DeviceExtension
->UseDma
)
2166 DmaCommand
= IDEReadDMACommand(DeviceExtension
->BusMasterRegisterBase
);
2167 IDEWriteDMACommand(DeviceExtension
->BusMasterRegisterBase
, DmaCommand
|0x01);
2172 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2174 /* Write data block */
2175 PUCHAR TargetAddress
;
2178 /* Wait for controller ready */
2179 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2181 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2182 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2186 ScsiPortStallExecution(10);
2188 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2190 DPRINT1("Drive is BUSY for too long after sending write command\n");
2191 return(SRB_STATUS_BUSY
);
2194 /* Update DeviceExtension data */
2195 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2196 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2198 TransferSize
= DeviceExtension
->DataTransferLength
;
2201 TargetAddress
= DeviceExtension
->DataBuffer
;
2202 DeviceExtension
->DataBuffer
+= TransferSize
;
2203 DeviceExtension
->DataTransferLength
-= TransferSize
;
2205 /* Write data block */
2206 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2208 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2214 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2221 DPRINT("AtapiReadWrite() done!\n");
2223 /* Wait for interrupt. */
2224 return(SRB_STATUS_PENDING
);
2229 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2230 PSCSI_REQUEST_BLOCK Srb
)
2235 DPRINT("AtapiFlushCache() called!\n");
2236 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2239 /* Wait for BUSY to clear */
2240 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2242 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2243 if (!(Status
& IDE_SR_BUSY
))
2247 ScsiPortStallExecution(10);
2249 DPRINT("Status=%02x\n", Status
);
2250 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2251 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2253 DPRINT1("Drive is BUSY for too long\n");
2254 return(SRB_STATUS_BUSY
);
2257 /* Select the desired drive */
2258 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2259 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2260 ScsiPortStallExecution(10);
2262 /* Issue command to drive */
2263 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_FLUSH_CACHE
, AtapiNoDataInterrupt
);
2265 /* Wait for controller ready */
2266 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2268 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2269 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2273 ScsiPortStallExecution(10);
2275 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2277 DPRINT1("Drive is BUSY for too long after sending write command\n");
2278 DeviceExtension
->Handler
= NULL
;
2279 return(SRB_STATUS_BUSY
);
2282 DPRINT("AtapiFlushCache() done!\n");
2284 /* Wait for interrupt. */
2285 return(SRB_STATUS_PENDING
);
2290 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2291 PSCSI_REQUEST_BLOCK Srb
)
2297 DPRINT1("AtapiTestUnitReady() called!\n");
2299 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2302 /* Return success if media status is not supported */
2303 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2305 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2306 return(SRB_STATUS_SUCCESS
);
2309 /* Wait for BUSY to clear */
2310 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2312 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2313 if (!(Status
& IDE_SR_BUSY
))
2317 ScsiPortStallExecution(10);
2319 DPRINT1("Status=%02x\n", Status
);
2320 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2321 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2323 DPRINT1("Drive is BUSY for too long\n");
2324 return(SRB_STATUS_BUSY
);
2327 /* Select the desired drive */
2328 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2329 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2330 ScsiPortStallExecution(10);
2332 /* Issue command to drive */
2333 AtapiExecuteCommand(DeviceExtension
, IDE_CMD_GET_MEDIA_STATUS
, AtapiNoDataInterrupt
);
2335 /* Wait for controller ready */
2336 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2338 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2339 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2343 ScsiPortStallExecution(10);
2345 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2347 DPRINT1("Drive is BUSY for too long after sending write command\n");
2348 DeviceExtension
->Handler
= NULL
;
2349 return(SRB_STATUS_BUSY
);
2352 if (Status
& IDE_SR_ERR
)
2354 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2355 if (Error
== IDE_ER_UNC
)
2358 /* Handle write protection 'error' */
2359 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2360 DeviceExtension
->Handler
= NULL
;
2361 return(SRB_STATUS_SUCCESS
);
2366 /* Indicate expecting an interrupt. */
2367 return(SRB_STATUS_PENDING
);
2371 DeviceExtension
->Handler
= NULL
;
2373 DPRINT1("AtapiTestUnitReady() done!\n");
2375 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2376 return(SRB_STATUS_SUCCESS
);
2381 AtapiErrorToScsi(PVOID DeviceExtension
,
2382 PSCSI_REQUEST_BLOCK Srb
)
2384 PATAPI_MINIPORT_EXTENSION DevExt
;
2385 ULONG CommandPortBase
;
2386 ULONG ControlPortBase
;
2391 DPRINT("AtapiErrorToScsi() called\n");
2393 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2395 CommandPortBase
= DevExt
->CommandPortBase
;
2396 ControlPortBase
= DevExt
->ControlPortBase
;
2398 ErrorReg
= IDEReadError(CommandPortBase
);
2400 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2402 switch (ErrorReg
>> 4)
2404 case SCSI_SENSE_NO_SENSE
:
2405 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2406 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2407 SrbStatus
= SRB_STATUS_ERROR
;
2410 case SCSI_SENSE_RECOVERED_ERROR
:
2411 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2413 SrbStatus
= SRB_STATUS_SUCCESS
;
2416 case SCSI_SENSE_NOT_READY
:
2417 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2418 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2419 SrbStatus
= SRB_STATUS_ERROR
;
2422 case SCSI_SENSE_MEDIUM_ERROR
:
2423 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2424 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2425 SrbStatus
= SRB_STATUS_ERROR
;
2428 case SCSI_SENSE_HARDWARE_ERROR
:
2429 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2430 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2431 SrbStatus
= SRB_STATUS_ERROR
;
2434 case SCSI_SENSE_ILLEGAL_REQUEST
:
2435 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2436 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2437 SrbStatus
= SRB_STATUS_ERROR
;
2440 case SCSI_SENSE_UNIT_ATTENTION
:
2441 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2442 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2443 SrbStatus
= SRB_STATUS_ERROR
;
2446 case SCSI_SENSE_DATA_PROTECT
:
2447 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2448 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2449 SrbStatus
= SRB_STATUS_ERROR
;
2452 case SCSI_SENSE_BLANK_CHECK
:
2453 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2454 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2455 SrbStatus
= SRB_STATUS_ERROR
;
2458 case SCSI_SENSE_ABORTED_COMMAND
:
2459 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2460 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2461 SrbStatus
= SRB_STATUS_ERROR
;
2465 DPRINT("ATAPI error: Invalid sense key\n");
2467 SrbStatus
= SRB_STATUS_ERROR
;
2473 DPRINT1("IDE error: %02x\n", ErrorReg
);
2476 SrbStatus
= SRB_STATUS_ERROR
;
2479 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2482 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2483 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2484 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2485 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2486 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2488 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2499 Srb
->ScsiStatus
= ScsiStatus
;
2501 DPRINT("AtapiErrorToScsi() done\n");
2508 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2510 DPRINT("AtapiConvertScsiToAtapi() called\n");
2512 Srb
->CdbLength
= 12;
2514 switch (Srb
->Cdb
[0])
2516 case SCSIOP_FORMAT_UNIT
:
2517 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2520 case SCSIOP_MODE_SELECT
:
2522 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2525 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2526 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2528 RtlZeroMemory (Srb
->Cdb
,
2530 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2531 AtapiModeSelect
->PFBit
= 1;
2532 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2533 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2539 static VOID FASTCALL
2540 AtapiCompleteRequest(PATAPI_MINIPORT_EXTENSION DevExt
,
2543 PSCSI_REQUEST_BLOCK Srb
;
2544 Srb
= DevExt
->CurrentSrb
;
2546 DPRINT("AtapiCompleteRequest(DevExt %x, SrbStatus %x)\n", DevExt
, SrbStatus
);
2548 Srb
->SrbStatus
= SrbStatus
;
2549 if (SrbStatus
== SRB_STATUS_ERROR
)
2551 Srb
->SrbStatus
= AtapiErrorToScsi((PVOID
)DevExt
, Srb
);
2553 else if (SrbStatus
== SRB_STATUS_DATA_OVERRUN
)
2555 Srb
->DataTransferLength
-= DevExt
->DataTransferLength
;
2558 DevExt
->Handler
= NULL
;
2559 ScsiPortNotification(RequestComplete
, (PVOID
)DevExt
, Srb
);
2560 ScsiPortNotification(NextRequest
, (PVOID
)DevExt
, NULL
);
2564 static BOOLEAN FASTCALL
2565 AtapiDmaPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2574 DPRINT("AtapiPacketDmaInterrupt\n");
2576 DevExt
->UseDma
= FALSE
;
2579 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2580 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2581 /* get DMA status */
2582 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2583 /* clear the INTR & ERROR bits */
2584 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2586 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2587 DPRINT("DriveStatus: %x\n", Status
);
2589 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2591 if (Status
& IDE_SR_ERR
)
2593 Error
= IDEReadError(DevExt
->CommandPortBase
);
2594 SensKey
= Error
>> 4;
2595 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2597 SrbStatus
= SRB_STATUS_ERROR
;
2601 if ((DmaStatus
& 0x07) != 0x04)
2603 DPRINT("DmaStatus: %02x\n", DmaStatus
);
2604 SrbStatus
= SRB_STATUS_ERROR
;
2608 SrbStatus
= STATUS_SUCCESS
;
2611 AtapiCompleteRequest(DevExt
, SrbStatus
);
2612 DPRINT("AtapiDmaPacketInterrupt() done\n");
2617 static BOOLEAN FASTCALL
2618 AtapiPacketInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2620 PSCSI_REQUEST_BLOCK Srb
;
2626 PBYTE TargetAddress
;
2632 DPRINT("AtapiPacketInterrupt()\n");
2634 Srb
= DevExt
->CurrentSrb
;
2636 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2637 DPRINT("DriveStatus: %x\n", Status
);
2639 if (Status
& (IDE_SR_BUSY
|IDE_SR_ERR
))
2641 if (Status
& IDE_SR_ERR
)
2643 Error
= IDEReadError(DevExt
->CommandPortBase
);
2644 SensKey
= Error
>> 4;
2645 DPRINT("DriveError: %x, SenseKey: %x\n", Error
, SensKey
);
2648 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2649 DPRINT("AtapiPacketInterrupt() done\n");
2653 IntReason
= IDEReadSectorCount(DevExt
->CommandPortBase
);
2654 TransferSize
= IDEReadCylinderLow(DevExt
->CommandPortBase
);
2655 TransferSize
+= IDEReadCylinderHigh(DevExt
->CommandPortBase
) << 8;
2657 if (!(Status
& IDE_SR_DRQ
))
2659 if (DevExt
->DataTransferLength
> 0)
2661 DPRINT1("AtapiPacketInterrupt: data underrun (%d bytes), command was %02x\n",
2662 DevExt
->DataTransferLength
, Srb
->Cdb
[0]);
2663 SrbStatus
= SRB_STATUS_DATA_OVERRUN
;
2667 SrbStatus
= SRB_STATUS_SUCCESS
;
2669 AtapiCompleteRequest(DevExt
, SrbStatus
);
2670 DPRINT("AtapiPacketInterrupt() done\n");
2674 TargetAddress
= DevExt
->DataBuffer
;
2676 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2678 DPRINT("read data\n");
2679 if (DevExt
->DataTransferLength
<= TransferSize
)
2681 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
2682 TransferSize
= DevExt
->DataTransferLength
;
2684 DevExt
->DataTransferLength
= 0;
2689 DevExt
->DataTransferLength
-= TransferSize
;
2690 IsLastBlock
= FALSE
;
2693 DPRINT("TargetAddress %x, TransferSize %d\n", TargetAddress
, TransferSize
);
2695 DevExt
->DataBuffer
+= TransferSize
;
2697 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2702 /* Read remaining junk from device */
2703 while (JunkSize
> 0)
2705 IDEReadWord(DevExt
->CommandPortBase
);
2709 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&& (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_BUSY
); Retries
++)
2711 ScsiPortStallExecution(10);
2714 /* Check for data overrun */
2715 while (IDEReadStatus(DevExt
->CommandPortBase
) & IDE_SR_DRQ
)
2717 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
2718 IDEReadWord(DevExt
->CommandPortBase
);
2722 SrbStatus
= SRB_STATUS_SUCCESS
;
2724 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2726 DPRINT("write data\n");
2727 if (DevExt
->DataTransferLength
< TransferSize
)
2729 TransferSize
= DevExt
->DataTransferLength
;
2732 TargetAddress
= DevExt
->DataBuffer
;
2734 DPRINT("TargetAddress %x, TransferSize %x\n", TargetAddress
, TransferSize
);
2736 DevExt
->DataBuffer
+= TransferSize
;
2737 DevExt
->DataTransferLength
-= TransferSize
;
2739 /* Write the sector */
2740 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2741 SrbStatus
= SRB_STATUS_SUCCESS
;
2742 IsLastBlock
= FALSE
;
2746 DPRINT("Unspecified transfer direction!\n");
2747 SrbStatus
= SRB_STATUS_SUCCESS
;
2752 AtapiCompleteRequest(DevExt
, SrbStatus
);
2754 DPRINT("AtapiPacketInterrupt() done\n");
2758 static BOOLEAN FASTCALL
2759 AtapiNoDataInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2763 DPRINT("AtapiNoDataInterrupt()\n");
2765 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2766 AtapiCompleteRequest(DevExt
,
2767 (Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
? SRB_STATUS_SUCCESS
: SRB_STATUS_ERROR
);
2769 DPRINT("AtapiNoDatanterrupt() done!\n");
2774 static BOOLEAN FASTCALL
2775 AtapiDmaInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2781 DPRINT("AtapiDmaInterrupt()\n");
2783 DevExt
->UseDma
= FALSE
;
2785 DmaCommand
= IDEReadDMACommand(DevExt
->BusMasterRegisterBase
);
2786 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, DmaCommand
& 0xfe);
2787 /* get DMA status */
2788 DmaStatus
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
2789 /* clear the INTR & ERROR bits */
2790 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, DmaStatus
| 0x06);
2792 /* read the drive status */
2793 Status
= IDEReadStatus(DevExt
->CommandPortBase
);
2794 if ((Status
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
|IDE_SR_DRQ
)) == IDE_SR_DRDY
&&
2795 (DmaStatus
& 0x07) == 4)
2797 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2798 DPRINT("AtapiDmaInterrupt() done\n");
2801 DPRINT1("Status %x\n", Status
);
2802 DPRINT1("%x\n", DmaStatus
);
2803 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2804 DPRINT1("AtapiDmaReadInterrupt() done\n");
2809 static BOOLEAN FASTCALL
2810 AtapiReadInterrupt(PATAPI_MINIPORT_EXTENSION DevExt
)
2812 PSCSI_REQUEST_BLOCK Srb
;
2814 BOOLEAN IsLastBlock
;
2815 PUCHAR TargetAddress
;
2818 DPRINT("AtapiReadInterrupt() called!\n");
2820 Srb
= DevExt
->CurrentSrb
;
2822 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2823 if ((DeviceStatus
& (IDE_SR_DRQ
|IDE_SR_BUSY
|IDE_SR_ERR
)) != IDE_SR_DRQ
)
2825 if (DeviceStatus
& (IDE_SR_ERR
|IDE_SR_DRQ
))
2827 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2828 DPRINT("AtapiReadInterrupt() done!\n");
2831 DPRINT("AtapiReadInterrupt() done!\n");
2835 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", DevExt
->CommandPortBase
, DevExt
->ControlPortBase
);
2837 /* Update controller/device state variables */
2838 TargetAddress
= DevExt
->DataBuffer
;
2839 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2841 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2842 DPRINT("TransferSize: %lu\n", TransferSize
);
2844 if (DevExt
->DataTransferLength
<= TransferSize
)
2846 TransferSize
= DevExt
->DataTransferLength
;
2847 DevExt
->DataTransferLength
= 0;
2852 DevExt
->DataTransferLength
-= TransferSize
;
2853 IsLastBlock
= FALSE
;
2855 DevExt
->DataBuffer
+= TransferSize
;
2856 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
2858 /* Copy the block of data */
2859 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2861 IDEReadBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2865 IDEReadBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2870 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2873 DPRINT("AtapiReadInterrupt() done!\n");
2878 static BOOLEAN FASTCALL
2879 AtapiWriteInterrupt(IN PATAPI_MINIPORT_EXTENSION DevExt
)
2881 PSCSI_REQUEST_BLOCK Srb
;
2883 BOOLEAN IsLastBlock
;
2884 PUCHAR TargetAddress
;
2887 DPRINT("AtapiWriteInterrupt() called!\n");
2889 DeviceStatus
= IDEReadStatus(DevExt
->CommandPortBase
);
2890 if ((DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_BUSY
|IDE_SR_ERR
|IDE_SR_WERR
)) != IDE_SR_DRDY
)
2892 if (DeviceStatus
& (IDE_SR_DRDY
|IDE_SR_ERR
|IDE_SR_WERR
))
2894 AtapiCompleteRequest(DevExt
, SRB_STATUS_ERROR
);
2895 DPRINT("AtapiWriteInterrupt() done!\n");
2898 DPRINT("AtapiWriteInterrupt() done!\n");
2903 Srb
= DevExt
->CurrentSrb
;
2904 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
2905 if (DevExt
->DataTransferLength
< TransferSize
)
2907 TransferSize
= DevExt
->DataTransferLength
;
2909 if (TransferSize
> 0 && (DeviceStatus
& IDE_SR_DRQ
))
2911 IsLastBlock
= FALSE
;
2912 TargetAddress
= DevExt
->DataBuffer
;
2913 DevExt
->DataBuffer
+= TransferSize
;
2914 DevExt
->DataTransferLength
-= TransferSize
;
2916 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
2917 DPRINT("TransferSize: %lu\n", TransferSize
);
2918 /* Write the sector */
2919 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2921 IDEWriteBlock32(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2925 IDEWriteBlock(DevExt
->CommandPortBase
, TargetAddress
, TransferSize
);
2928 else if (DeviceStatus
& IDE_SR_DRQ
)
2930 DPRINT("AtapiWriteInterrupt(): data overrun error!\n");
2933 else if (TransferSize
> 0 && !(DeviceStatus
& IDE_SR_DRQ
))
2935 DPRINT1("%d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", TransferSize
);
2944 AtapiCompleteRequest(DevExt
, SRB_STATUS_SUCCESS
);
2946 DPRINT("AtapiWriteInterrupt() done!\n");
2952 AtapiExecuteCommand(PATAPI_MINIPORT_EXTENSION DevExt
,
2954 BOOLEAN
FASTCALL (*Handler
)(PATAPI_MINIPORT_EXTENSION
))
2956 if (DevExt
->Handler
!= NULL
)
2958 DPRINT1("DevExt->Handler is already set!!\n");
2960 DevExt
->Handler
= Handler
;
2961 IDEWriteCommand(DevExt
->CommandPortBase
, command
);
2962 ScsiPortStallExecution(1);
2967 AtapiInitDma(PATAPI_MINIPORT_EXTENSION DevExt
,
2968 PSCSI_REQUEST_BLOCK Srb
,
2973 PPRD PRDEntry
= DevExt
->PRDTable
;
2974 SCSI_PHYSICAL_ADDRESS PhysicalAddress
;
2979 DPRINT("AtapiInitDma()\n");
2981 StartAddress
= Srb
->DataBuffer
;
2982 EndAddress
= StartAddress
+ Srb
->DataTransferLength
;
2983 DevExt
->PRDCount
= 0;
2985 while (StartAddress
< EndAddress
)
2987 PhysicalAddress
= ScsiPortGetPhysicalAddress(DevExt
, Srb
, StartAddress
, &Length
);
2988 if (PhysicalAddress
.QuadPart
== 0LL || Length
== 0)
2995 /* calculate the length up to the next 64k boundary */
2996 tmpLength
= 0x10000 - (PhysicalAddress
.u
.LowPart
& 0xffff);
2997 if (tmpLength
> Length
)
3002 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3006 if (tmpLength
== 0x10000)
3008 /* Some dirty controllers cannot handle 64k transfers. We split a 64k transfer in two 32k. */
3010 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3011 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3012 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3013 PRDEntry
->Length
= tmpLength
;
3016 if (DevExt
->PRDCount
> DevExt
->PRDMaxCount
)
3020 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3021 StartAddress
+= tmpLength
;
3022 Length
-= tmpLength
;
3023 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3025 DPRINT("PRD Nr. %d VirtualAddress %08x PhysicalAddress %08x, Length %04x\n",
3026 DevExt
->PRDCount
- 1, StartAddress
, PhysicalAddress
.u
.LowPart
, tmpLength
);
3027 PRDEntry
->PhysAddress
= PhysicalAddress
.u
.LowPart
;
3028 PRDEntry
->Length
= tmpLength
;
3030 StartAddress
+= tmpLength
;
3031 PhysicalAddress
.u
.LowPart
+= tmpLength
;
3032 Length
-= tmpLength
;
3035 /* set the end marker in the last PRD */
3037 PRDEntry
->Length
|= 0x80000000;
3038 /* set the PDR table */
3039 IDEWritePRDTable(DevExt
->BusMasterRegisterBase
, DevExt
->PRDTablePhysicalAddress
.u
.LowPart
);
3040 /* write the DMA command */
3041 IDEWriteDMACommand(DevExt
->BusMasterRegisterBase
, cmd
);
3042 /* reset the status and interrupt bit */
3043 Status
= IDEReadDMAStatus(DevExt
->BusMasterRegisterBase
);
3044 IDEWriteDMAStatus(DevExt
->BusMasterRegisterBase
, Status
| 0x06);