3 * Copyright (C) 2001, 2002 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.38 2003/04/06 10:45:15 chorns Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: services/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
32 * This driver is derived from Rex Jolliff's ide driver. Lots of his
33 * routines are still in here although they belong into the higher level
34 * drivers. They will be moved away as soon as possible.
39 * - implement sending of atapi commands
40 * - handle removable atapi non-cdrom drives
44 #define ENABLE_NATIVE_PCI
47 // -------------------------------------------------------------------------
49 #include <ddk/ntddk.h>
52 #include <ddk/ntddscsi.h>
59 #define VERSION "0.0.1"
62 // ------------------------------------------------------- File Static Data
64 // ATAPI_MINIPORT_EXTENSION
67 // Extension to be placed in each port device object
70 // Allocated from NON-PAGED POOL
71 // Available at any IRQL
74 typedef struct _ATAPI_MINIPORT_EXTENSION
76 IDE_DRIVE_IDENTIFY DeviceParams
[2];
77 BOOLEAN DevicePresent
[2];
78 BOOLEAN DeviceAtapi
[2];
79 ULONG TransferSize
[2];
80 BOOLEAN MultiSectorCommand
[2];
84 ULONG CommandPortBase
;
85 ULONG ControlPortBase
;
86 ULONG BusMasterRegisterBase
;
88 BOOLEAN ExpectingInterrupt
;
89 PSCSI_REQUEST_BLOCK CurrentSrb
;
93 ULONG DataTransferLength
;
94 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
97 typedef struct _UNIT_EXTENSION
100 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
102 PCI_SLOT_NUMBER LastSlotNumber
;
104 #ifdef ENABLE_NATIVE_PCI
105 typedef struct _PCI_NATIVE_CONTROLLER
110 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
112 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
116 0x4D68, // PDC20268, Ultra100TX2
120 0x4D30, // PDC20267, Ultra100
126 // ----------------------------------------------- Discardable Declarations
130 // make the initialization routines discardable, so that they
133 #pragma alloc_text(init, DriverEntry)
134 #pragma alloc_text(init, IDECreateController)
135 #pragma alloc_text(init, IDEPolledRead)
137 // make the PASSIVE_LEVEL routines pageable, so that they don't
138 // waste nonpaged memory
140 #pragma alloc_text(page, IDEShutdown)
141 #pragma alloc_text(page, IDEDispatchOpenClose)
142 #pragma alloc_text(page, IDEDispatchRead)
143 #pragma alloc_text(page, IDEDispatchWrite)
145 #endif /* ALLOC_PRAGMA */
147 // ---------------------------------------------------- Forward Declarations
150 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
152 PVOID BusInformation
,
153 PCHAR ArgumentString
,
154 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
158 AtapiFindIsaBusController(PVOID DeviceExtension
,
160 PVOID BusInformation
,
161 PCHAR ArgumentString
,
162 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
166 AtapiFindNativePciController(PVOID DeviceExtension
,
168 PVOID BusInformation
,
169 PCHAR ArgumentString
,
170 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
173 static BOOLEAN STDCALL
174 AtapiInitialize(IN PVOID DeviceExtension
);
176 static BOOLEAN STDCALL
177 AtapiResetBus(IN PVOID DeviceExtension
,
180 static BOOLEAN STDCALL
181 AtapiStartIo(IN PVOID DeviceExtension
,
182 IN PSCSI_REQUEST_BLOCK Srb
);
184 static BOOLEAN STDCALL
185 AtapiInterrupt(IN PVOID DeviceExtension
);
188 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
189 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
192 AtapiIdentifyDevice(IN ULONG CommandPort
,
193 IN ULONG ControlPort
,
196 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
199 IDEResetController(IN ULONG CommandPort
,
200 IN ULONG ControlPort
);
203 AtapiPolledRead(IN ULONG CommandPort
,
204 IN ULONG ControlPort
,
209 IN BYTE CylinderHigh
,
217 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
218 IN PSCSI_REQUEST_BLOCK Srb
);
221 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
222 IN PSCSI_REQUEST_BLOCK Srb
);
225 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
226 IN PSCSI_REQUEST_BLOCK Srb
);
229 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
230 IN PSCSI_REQUEST_BLOCK Srb
);
233 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
234 IN PSCSI_REQUEST_BLOCK Srb
);
237 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
238 PSCSI_REQUEST_BLOCK Srb
);
241 AtapiErrorToScsi(PVOID DeviceExtension
,
242 PSCSI_REQUEST_BLOCK Srb
);
244 // ---------------------------------------------------------------- Inlines
247 IDESwapBytePairs(char *Buf
,
253 for (i
= 0; i
< Cnt
; i
+= 2)
262 // ------------------------------------------------------- Public Interface
267 // This function initializes the driver, locates and claims
268 // hardware resources, and creates various NT objects needed
269 // to process I/O requests.
275 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
277 // IN PUNICODE_STRING RegistryPath Name of registry driver service
284 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
285 IN PUNICODE_STRING RegistryPath
)
287 HW_INITIALIZATION_DATA InitData
;
290 DPRINT("ATAPI Driver %s\n", VERSION
);
291 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
293 /* Initialize data structure */
294 RtlZeroMemory(&InitData
,
295 sizeof(HW_INITIALIZATION_DATA
));
296 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
297 InitData
.HwInitialize
= AtapiInitialize
;
298 InitData
.HwResetBus
= AtapiResetBus
;
299 InitData
.HwStartIo
= AtapiStartIo
;
300 InitData
.HwInterrupt
= AtapiInterrupt
;
302 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
303 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
305 InitData
.MapBuffers
= TRUE
;
308 /* Search the PCI bus for compatibility mode ide controllers */
310 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
311 InitData
.NumberOfAccessRanges
= 3;
312 InitData
.AdapterInterfaceType
= PCIBus
;
314 InitData
.VendorId
= NULL
;
315 InitData
.VendorIdLength
= 0;
316 InitData
.DeviceId
= NULL
;
317 InitData
.DeviceIdLength
= 0;
319 Status
= ScsiPortInitialize(DriverObject
,
323 // if (newStatus < statusToReturn)
324 // statusToReturn = newStatus;
327 /* Search the PCI bus for all ide controllers */
328 #ifdef ENABLE_NATIVE_PCI
330 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
331 InitData
.NumberOfAccessRanges
= 3;
332 InitData
.AdapterInterfaceType
= PCIBus
;
334 InitData
.VendorId
= 0;
335 InitData
.VendorIdLength
= 0;
336 InitData
.DeviceId
= 0;
337 InitData
.DeviceIdLength
= 0;
339 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
341 Status
= ScsiPortInitialize(DriverObject
,
345 // if (newStatus < statusToReturn)
346 // statusToReturn = newStatus;
349 /* Search the ISA bus for ide controllers */
351 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
352 InitData
.NumberOfAccessRanges
= 2;
353 InitData
.AdapterInterfaceType
= Isa
;
355 InitData
.VendorId
= NULL
;
356 InitData
.VendorIdLength
= 0;
357 InitData
.DeviceId
= NULL
;
358 InitData
.DeviceIdLength
= 0;
360 Status
= ScsiPortInitialize(DriverObject
,
364 // if (newStatus < statusToReturn)
365 // statusToReturn = newStatus;
368 DPRINT("Returning from DriverEntry\n");
375 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
376 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
377 INTERFACE_TYPE InterfaceType
,
378 ULONG CommandPortBase
,
379 ULONG ControlPortBase
,
380 ULONG BusMasterPortBase
,
381 ULONG InterruptVector
)
383 SCSI_PHYSICAL_ADDRESS IoAddress
;
386 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
387 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
389 ConfigInfo
->SystemIoBusNumber
,
397 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
398 ConfigInfo
->AccessRanges
[0].RangeStart
= IoAddress
;
399 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
400 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
404 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
405 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
407 ConfigInfo
->SystemIoBusNumber
,
413 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
414 (PVOID
)DevExt
->CommandPortBase
);
417 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
418 ConfigInfo
->AccessRanges
[1].RangeStart
= IoAddress
;
419 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
420 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
422 if (BusMasterPortBase
)
424 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
425 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
427 ConfigInfo
->SystemIoBusNumber
,
433 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
434 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
437 ConfigInfo
->AccessRanges
[2].RangeStart
= IoAddress
;
438 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
439 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
441 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
442 ConfigInfo
->BusInterruptVector
= InterruptVector
;
443 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
445 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
447 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
449 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
451 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
459 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
461 PVOID BusInformation
,
462 PCHAR ArgumentString
,
463 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
466 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
467 PCI_SLOT_NUMBER SlotNumber
;
468 PCI_COMMON_CONFIG PciConfig
;
470 ULONG StartDeviceNumber
;
472 ULONG StartFunctionNumber
;
473 ULONG FunctionNumber
;
474 BOOLEAN ChannelFound
;
476 ULONG BusMasterBasePort
= 0;
478 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
479 ConfigInfo
->SystemIoBusNumber
,
480 ConfigInfo
->SlotNumber
);
484 /* both channels were claimed: exit */
485 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
486 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
487 return(SP_RETURN_NOT_FOUND
);
489 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
490 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
491 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
492 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
494 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
495 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
497 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
498 ChannelFound
= FALSE
;
501 DataSize
= ScsiPortGetBusData(DeviceExtension
,
503 ConfigInfo
->SystemIoBusNumber
,
504 SlotNumber
.u
.AsULONG
,
506 PCI_COMMON_HDR_LENGTH
);
507 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
509 if (FunctionNumber
== 0)
519 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
520 if (PciConfig
.BaseClass
== 0x01 &&
521 PciConfig
.SubClass
== 0x01) // &&
522 // (PciConfig.ProgIf & 0x05) == 0)
524 /* both channels are in compatibility mode */
525 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
526 ConfigInfo
->SystemIoBusNumber
,
527 SlotNumber
.u
.bits
.DeviceNumber
,
528 SlotNumber
.u
.bits
.FunctionNumber
,
531 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
533 DPRINT("Found IDE controller in compatibility mode!\n");
535 ConfigInfo
->NumberOfBuses
= 1;
536 ConfigInfo
->MaximumNumberOfTargets
= 2;
537 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
539 if (PciConfig
.ProgIf
& 0x80)
541 DPRINT("Found IDE Bus Master controller!\n");
542 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
544 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
545 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
548 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
550 /* Both channels unclaimed: Claim primary channel */
551 DPRINT("Primary channel!\n");
552 ChannelFound
= AtapiClaimHwResources(DevExt
,
561 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
563 /* Primary channel already claimed: claim secondary channel */
564 DPRINT("Secondary channel!\n");
566 ChannelFound
= AtapiClaimHwResources(DevExt
,
571 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
575 /* Find attached devices */
578 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
579 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
580 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
581 return(SP_RETURN_FOUND
);
584 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
589 StartFunctionNumber
= 0;
591 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
593 return(SP_RETURN_NOT_FOUND
);
600 AtapiFindIsaBusController(PVOID DeviceExtension
,
602 PVOID BusInformation
,
603 PCHAR ArgumentString
,
604 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
607 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
608 BOOLEAN ChannelFound
= FALSE
;
609 BOOLEAN DeviceFound
= FALSE
;
611 DPRINT("AtapiFindIsaBusController() called!\n");
615 ConfigInfo
->NumberOfBuses
= 1;
616 ConfigInfo
->MaximumNumberOfTargets
= 2;
617 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
619 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
621 /* Both channels unclaimed: Claim primary channel */
622 DPRINT("Primary channel!\n");
624 ChannelFound
= AtapiClaimHwResources(DevExt
,
633 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
635 /* Primary channel already claimed: claim secondary channel */
636 DPRINT("Secondary channel!\n");
638 ChannelFound
= AtapiClaimHwResources(DevExt
,
649 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
651 return(SP_RETURN_NOT_FOUND
);
654 /* Find attached devices */
657 DeviceFound
= AtapiFindDevices(DevExt
,
659 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
660 return(SP_RETURN_FOUND
);
663 return SP_RETURN_NOT_FOUND
;
668 #ifdef ENABLE_NATIVE_PCI
670 AtapiFindNativePciController(PVOID DeviceExtension
,
672 PVOID BusInformation
,
673 PCHAR ArgumentString
,
674 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
677 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
678 PCI_COMMON_CONFIG PciConfig
;
679 PCI_SLOT_NUMBER SlotNumber
;
682 ULONG StartDeviceNumber
;
683 ULONG FunctionNumber
;
684 ULONG StartFunctionNumber
;
685 ULONG BusMasterBasePort
;
687 BOOLEAN ChannelFound
;
689 DPRINT("AtapiFindNativePciController() called!\n");
691 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
692 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
693 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
694 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
696 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
697 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
699 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
700 DataSize
= ScsiPortGetBusData(DeviceExtension
,
702 ConfigInfo
->SystemIoBusNumber
,
703 SlotNumber
.u
.AsULONG
,
705 PCI_COMMON_HDR_LENGTH
);
706 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
710 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
712 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
713 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
718 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
720 /* We have found a known native pci ide controller */
721 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
723 DPRINT("Found IDE Bus Master controller!\n");
724 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
725 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
729 BusMasterBasePort
= 0;
732 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
733 ConfigInfo
->NumberOfBuses
= 1;
734 ConfigInfo
->MaximumNumberOfTargets
= 2;
735 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
738 We must not store and use the last tested slot number. If there is a recall
739 to the some device and we will claim the primary channel again than the call
740 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
741 claim the secondary channel.
743 ChannelFound
= FALSE
;
744 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
746 /* try to claim primary channel */
747 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
748 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
750 /* primary channel is enabled */
751 ChannelFound
= AtapiClaimHwResources(DevExt
,
754 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
755 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
757 PciConfig
.u
.type0
.InterruptLine
);
760 AtapiFindDevices(DevExt
, ConfigInfo
);
762 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
763 return SP_RETURN_FOUND
;
769 /* try to claim secondary channel */
770 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
771 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
773 /* secondary channel is enabled */
774 ChannelFound
= AtapiClaimHwResources(DevExt
,
777 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
778 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
779 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
780 PciConfig
.u
.type0
.InterruptLine
);
783 AtapiFindDevices(DevExt
, ConfigInfo
);
785 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
786 return SP_RETURN_FOUND
;
792 StartFunctionNumber
= 0;
795 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
796 DPRINT("AtapiFindNativePciController() done!\n");
798 return(SP_RETURN_NOT_FOUND
);
803 static BOOLEAN STDCALL
804 AtapiInitialize(IN PVOID DeviceExtension
)
810 static BOOLEAN STDCALL
811 AtapiResetBus(IN PVOID DeviceExtension
,
818 static BOOLEAN STDCALL
819 AtapiStartIo(IN PVOID DeviceExtension
,
820 IN PSCSI_REQUEST_BLOCK Srb
)
822 PATAPI_MINIPORT_EXTENSION DevExt
;
825 DPRINT("AtapiStartIo() called\n");
827 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
829 switch (Srb
->Function
)
831 case SRB_FUNCTION_EXECUTE_SCSI
:
832 DevExt
->CurrentSrb
= Srb
;
833 if (DevExt
->DeviceAtapi
[Srb
->TargetId
] == TRUE
)
835 Result
= AtapiSendAtapiCommand(DevExt
,
840 Result
= AtapiSendIdeCommand(DevExt
,
847 Srb
->SrbStatus
= Result
;
850 if (Result
!= SRB_STATUS_PENDING
)
852 DevExt
->CurrentSrb
= NULL
;
853 Srb
->SrbStatus
= (UCHAR
)Result
;
855 ScsiPortNotification(RequestComplete
,
858 ScsiPortNotification(NextRequest
,
864 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
867 DPRINT("AtapiStartIo() done\n");
873 static BOOLEAN STDCALL
874 AtapiInterrupt(IN PVOID DeviceExtension
)
876 PATAPI_MINIPORT_EXTENSION DevExt
;
877 PSCSI_REQUEST_BLOCK Srb
;
878 ULONG CommandPortBase
;
879 ULONG ControlPortBase
;
885 PUCHAR TargetAddress
;
888 DPRINT("AtapiInterrupt() called!\n");
890 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
892 CommandPortBase
= DevExt
->CommandPortBase
;
893 ControlPortBase
= DevExt
->ControlPortBase
;
895 if (DevExt
->ExpectingInterrupt
== FALSE
)
897 DeviceStatus
= IDEReadStatus(CommandPortBase
);
898 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase
);
902 /* check if it was our irq */
903 if ((DeviceStatus
= IDEReadAltStatus(ControlPortBase
)) & IDE_SR_BUSY
)
905 ScsiPortStallExecution(1);
906 if ((DeviceStatus
= IDEReadAltStatus(ControlPortBase
) & IDE_SR_BUSY
))
908 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase
);
913 Srb
= DevExt
->CurrentSrb
;
914 DPRINT("Srb: %p\n", Srb
);
916 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
918 IsAtapi
= DevExt
->DeviceAtapi
[Srb
->TargetId
];
919 DPRINT("IsAtapi == %s\n", (IsAtapi
) ? "TRUE" : "FALSE");
923 DeviceStatus
= IDEReadStatus(CommandPortBase
);
924 DPRINT("DeviceStatus: %x\n", DeviceStatus
);
926 if ((DeviceStatus
& IDE_SR_ERR
) &&
927 (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
))
929 /* Report error condition */
930 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
935 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
937 DPRINT("Read data\n");
939 /* Update controller/device state variables */
940 TargetAddress
= DevExt
->DataBuffer
;
944 TransferSize
= IDEReadCylinderLow(CommandPortBase
);
945 TransferSize
+= IDEReadCylinderHigh(CommandPortBase
) << 8;
949 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
952 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
953 DPRINT("TransferSize: %lu\n", TransferSize
);
955 if (DevExt
->DataTransferLength
<= TransferSize
)
959 TransferSize
= DevExt
->DataTransferLength
;
961 DevExt
->DataTransferLength
= 0;
966 DevExt
->DataTransferLength
-= TransferSize
;
969 DevExt
->DataBuffer
+= TransferSize
;
970 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
972 /* Wait for DRQ assertion */
973 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
974 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
977 KeStallExecutionProcessor(10);
980 /* Copy the block of data */
981 if (DevExt
->DWordIo
[Srb
->TargetId
])
983 IDEReadBlock32(CommandPortBase
,
989 IDEReadBlock(CommandPortBase
,
996 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
997 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
1000 KeStallExecutionProcessor(10);
1003 /* Check for data overrun */
1004 while (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
1006 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
1007 IDEReadWord(CommandPortBase
);
1011 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1013 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
1015 DPRINT("Write data\n");
1017 if (DevExt
->DataTransferLength
== 0)
1019 /* Check for data overrun */
1020 if (DeviceStatus
& IDE_SR_DRQ
)
1022 /* FIXME: Handle error! */
1023 /* This can occure if the irq is shared with an other and if the
1024 ide controller has a write buffer. We have write the last sectors
1025 and the other device has a irq before ours. The isr is called but
1026 we haven't a interrupt. The controller writes the sector buffer
1027 and the status register shows DRQ because the write is not ended. */
1028 DPRINT("AtapiInterrupt(): data overrun error!\n");
1034 /* Update DevExt data */
1035 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
1036 if (DevExt
->DataTransferLength
< TransferSize
)
1038 TransferSize
= DevExt
->DataTransferLength
;
1041 TargetAddress
= DevExt
->DataBuffer
;
1042 DevExt
->DataBuffer
+= TransferSize
;
1043 DevExt
->DataTransferLength
-= TransferSize
;
1045 /* Write the sector */
1046 if (DevExt
->DWordIo
[Srb
->TargetId
])
1048 IDEWriteBlock32(CommandPortBase
,
1054 IDEWriteBlock(CommandPortBase
,
1060 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1064 DPRINT1("Unspecified transfer direction!\n");
1065 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
; // SRB_STATUS_ERROR;
1071 if (Srb
->SrbStatus
== SRB_STATUS_ERROR
)
1073 Srb
->SrbStatus
= AtapiErrorToScsi(DeviceExtension
,
1078 /* complete this packet */
1081 DevExt
->ExpectingInterrupt
= FALSE
;
1083 ScsiPortNotification(RequestComplete
,
1087 ScsiPortNotification(NextRequest
,
1092 DPRINT("AtapiInterrupt() done!\n");
1097 // ---------------------------------------------------- Discardable statics
1100 /**********************************************************************
1105 * Searches for devices on the given port.
1112 * Port device specific information.
1115 * Port configuration information.
1118 * TRUE: At least one device is attached to the port.
1119 * FALSE: No device is attached to the port.
1123 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1124 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1126 BOOLEAN DeviceFound
= FALSE
;
1127 ULONG CommandPortBase
;
1128 ULONG ControlPortBase
;
1133 DPRINT("AtapiFindDevices() called\n");
1135 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
1136 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1138 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
1139 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1141 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1144 IDEWriteDriveHead(CommandPortBase
,
1145 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1146 ScsiPortStallExecution(500);
1148 /* Disable interrupts */
1149 IDEWriteDriveControl(ControlPortBase
,
1151 ScsiPortStallExecution(500);
1153 /* Check if a device is attached to the interface */
1154 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1155 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1157 High
= IDEReadCylinderHigh(CommandPortBase
);
1158 Low
= IDEReadCylinderLow(CommandPortBase
);
1160 IDEWriteCylinderHigh(CommandPortBase
, 0);
1161 IDEWriteCylinderLow(CommandPortBase
, 0);
1163 if (Low
!= 0x55 || High
!= 0xaa)
1165 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1169 IDEWriteCommand(CommandPortBase
, IDE_CMD_RESET
);
1171 for (Retries
= 0; Retries
< 20000; Retries
++)
1173 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1177 ScsiPortStallExecution(150);
1179 if (Retries
>= 20000)
1181 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1182 DeviceExtension
->DevicePresent
[UnitNumber
] = FALSE
;
1186 High
= IDEReadCylinderHigh(CommandPortBase
);
1187 Low
= IDEReadCylinderLow(CommandPortBase
);
1189 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1194 if (High
== 0xEB && Low
== 0x14)
1196 if (AtapiIdentifyDevice(CommandPortBase
,
1200 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1202 DPRINT(" ATAPI drive found!\n");
1203 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
1204 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
1205 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1206 DeviceExtension
->MultiSectorCommand
[UnitNumber
] = FALSE
;
1207 DeviceExtension
->DWordIo
[UnitNumber
] = FALSE
;
1212 DPRINT(" No ATAPI drive found!\n");
1217 if (AtapiIdentifyDevice(CommandPortBase
,
1221 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1223 DPRINT(" IDE drive found!\n");
1224 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
1225 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
1226 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1227 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1228 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1229 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1230 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1232 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1233 DeviceExtension
->MultiSectorCommand
[UnitNumber
] = TRUE
;
1237 DeviceExtension
->MultiSectorCommand
[UnitNumber
] = FALSE
;
1239 DeviceExtension
->DWordIo
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
? TRUE
: FALSE
;
1244 DPRINT(" No IDE drive found!\n");
1249 /* Reset pending interrupts */
1250 IDEReadStatus(CommandPortBase
);
1251 /* Reenable interrupts */
1252 IDEWriteDriveControl(ControlPortBase
, 0);
1253 ScsiPortStallExecution(500);
1254 /* Return with drive 0 selected */
1255 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1256 ScsiPortStallExecution(500);
1258 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1260 return(DeviceFound
);
1264 // AtapiResetController
1267 // Reset the controller and report completion status
1273 // IN WORD CommandPort The address of the command port
1274 // IN WORD ControlPort The address of the control port
1280 AtapiResetController(IN ULONG CommandPort
,
1281 IN ULONG ControlPort
)
1285 /* Assert drive reset line */
1286 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
1288 /* Wait for min. 25 microseconds */
1289 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
1291 /* Negate drive reset line */
1292 IDEWriteDriveControl(ControlPort
, 0);
1294 /* Wait for BUSY negation */
1295 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
1297 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
1301 ScsiPortStallExecution(10);
1304 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
1309 // return TRUE if controller came back to life. and
1310 // the registers are initialized correctly
1311 return(IDEReadError(CommandPort
) == 1);
1315 * AtapiIdentifyDevice
1318 * Get the identification block from the drive
1325 * Address of the command port
1327 * Address of the control port
1329 * The drive index (0,1)
1331 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1333 * Address to write drive ident block
1336 * TRUE: The drive identification block was retrieved successfully
1337 * FALSE: an error ocurred
1341 AtapiIdentifyDevice(IN ULONG CommandPort
,
1342 IN ULONG ControlPort
,
1345 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1349 /* Get the Drive Identify block from drive or die */
1350 if (AtapiPolledRead(CommandPort
,
1357 (DriveNum
? IDE_DH_DRV1
: 0),
1358 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1359 (BYTE
*)DrvParms
) != 0)
1361 DPRINT("IDEPolledRead() failed\n");
1365 /* Report on drive parameters if debug mode */
1366 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1367 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1368 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1369 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1370 DrvParms
->ConfigBits
,
1371 DrvParms
->LogicalCyls
,
1372 DrvParms
->LogicalHeads
,
1373 DrvParms
->SectorsPerTrack
,
1374 DrvParms
->InterSectorGap
,
1375 DrvParms
->InterSectorGapSize
);
1376 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1377 DrvParms
->BytesInPLO
,
1378 DrvParms
->VendorUniqueCnt
,
1379 DrvParms
->SerialNumber
);
1380 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1381 DrvParms
->ControllerType
,
1382 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1383 DrvParms
->ECCByteCnt
,
1384 DrvParms
->FirmwareRev
);
1385 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1386 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1387 (DrvParms
->RWMultImplemented
),
1388 (DrvParms
->RWMultCurrent
) & 0xff,
1389 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1390 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1391 DrvParms
->MinPIOTransTime
,
1392 DrvParms
->MinDMATransTime
);
1393 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1394 DrvParms
->TMCylinders
,
1396 DrvParms
->TMSectorsPerTrk
,
1397 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1398 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1399 DrvParms
->TMSectorCountHi
,
1400 DrvParms
->TMSectorCountLo
,
1401 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1403 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1405 /* LBA ATA drives always have a sector size of 512 */
1406 DrvParms
->BytesPerSector
= 512;
1410 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1411 if (DrvParms
->BytesPerSector
== 0)
1413 DrvParms
->BytesPerSector
= 512;
1417 for (i
= 15; i
>= 0; i
--)
1419 if (DrvParms
->BytesPerSector
& (1 << i
))
1421 DrvParms
->BytesPerSector
= 1 << i
;
1427 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1436 // Read a sector of data from the drive in a polled fashion.
1442 // IN WORD Address Address of command port for drive
1443 // IN BYTE PreComp Value to write to precomp register
1444 // IN BYTE SectorCnt Value to write to sectorCnt register
1445 // IN BYTE SectorNum Value to write to sectorNum register
1446 // IN BYTE CylinderLow Value to write to CylinderLow register
1447 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1448 // IN BYTE DrvHead Value to write to Drive/Head register
1449 // IN BYTE Command Value to write to Command register
1450 // OUT BYTE *Buffer Buffer for output data
1453 // int 0 is success, non 0 is an error code
1457 AtapiPolledRead(IN ULONG CommandPort
,
1458 IN ULONG ControlPort
,
1462 IN BYTE CylinderLow
,
1463 IN BYTE CylinderHigh
,
1468 ULONG SectorCount
= 0;
1470 BOOLEAN Junk
= FALSE
;
1474 /* Wait for BUSY to clear */
1475 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1477 Status
= IDEReadStatus(CommandPort
);
1478 if (!(Status
& IDE_SR_BUSY
))
1482 ScsiPortStallExecution(10);
1484 DPRINT("status=%02x\n", Status
);
1485 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1486 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1488 DPRINT("Drive is BUSY for too long\n");
1489 return(IDE_ER_ABRT
);
1493 /* Write Drive/Head to select drive */
1494 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1495 ScsiPortStallExecution(500);
1497 /* Disable interrupts */
1498 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1499 ScsiPortStallExecution(500);
1502 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1503 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1505 Status
= IDEReadStatus(CommandPort
);
1506 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1510 ScsiPortStallExecution(10);
1512 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1518 /* Issue command to drive */
1519 if (DrvHead
& IDE_DH_LBA
)
1521 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1522 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1523 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1529 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1530 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1539 /* Setup command parameters */
1540 IDEWritePrecomp(CommandPort
, PreComp
);
1541 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1542 IDEWriteSectorNum(CommandPort
, SectorNum
);
1543 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1544 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1545 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1547 /* Issue the command */
1548 IDEWriteCommand(CommandPort
, Command
);
1549 ScsiPortStallExecution(50);
1551 /* wait for DRQ or error */
1552 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1554 Status
= IDEReadStatus(CommandPort
);
1555 if (!(Status
& IDE_SR_BUSY
))
1557 if (Status
& IDE_SR_ERR
)
1559 IDEWriteDriveControl(ControlPort
, 0);
1560 ScsiPortStallExecution(50);
1561 IDEReadStatus(CommandPort
);
1563 return(IDE_ER_ABRT
);
1565 if (Status
& IDE_SR_DRQ
)
1571 IDEWriteDriveControl(ControlPort
, 0);
1572 ScsiPortStallExecution(50);
1573 IDEReadStatus(CommandPort
);
1575 return(IDE_ER_ABRT
);
1578 ScsiPortStallExecution(10);
1582 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1584 IDEWriteDriveControl(ControlPort
, 0);
1585 ScsiPortStallExecution(50);
1586 IDEReadStatus(CommandPort
);
1588 return(IDE_ER_ABRT
);
1593 /* Read data into buffer */
1596 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1597 Buffer
+= IDE_SECTOR_BUF_SZ
;
1601 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1602 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1606 /* Check for error or more sectors to read */
1607 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1609 Status
= IDEReadStatus(CommandPort
);
1610 if (!(Status
& IDE_SR_BUSY
))
1612 if (Status
& IDE_SR_ERR
)
1614 IDEWriteDriveControl(ControlPort
, 0);
1615 ScsiPortStallExecution(50);
1616 IDEReadStatus(CommandPort
);
1618 return(IDE_ER_ABRT
);
1620 if (Status
& IDE_SR_DRQ
)
1622 if (SectorCount
>= SectorCnt
)
1624 DPRINT("Buffer size exceeded!\n");
1631 if (SectorCount
> SectorCnt
)
1633 DPRINT("Read %lu sectors of junk!\n",
1634 SectorCount
- SectorCnt
);
1636 IDEWriteDriveControl(ControlPort
, 0);
1637 ScsiPortStallExecution(50);
1638 IDEReadStatus(CommandPort
);
1648 // ------------------------------------------- Nondiscardable statics
1651 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1652 IN PSCSI_REQUEST_BLOCK Srb
)
1654 UCHAR ByteCountHigh
;
1660 DPRINT("AtapiSendAtapiCommand() called!\n");
1662 if (Srb
->PathId
!= 0)
1664 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1665 return(SRB_STATUS_INVALID_PATH_ID
);
1668 if (Srb
->TargetId
> 1)
1670 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1671 return(SRB_STATUS_INVALID_TARGET_ID
);
1676 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1677 return(SRB_STATUS_INVALID_LUN
);
1680 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1682 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1683 return(SRB_STATUS_NO_DEVICE
);
1686 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1689 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1690 return(AtapiInquiry(DeviceExtension
,
1693 /* Set pointer to data buffer. */
1694 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1695 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1696 DeviceExtension
->CurrentSrb
= Srb
;
1698 /* Wait for BUSY to clear */
1699 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1701 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1702 if (!(Status
& IDE_SR_BUSY
))
1706 ScsiPortStallExecution(10);
1708 DPRINT("status=%02x\n", Status
);
1709 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1710 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1712 DPRINT("Drive is BUSY for too long\n");
1713 return(SRB_STATUS_BUSY
);
1716 /* Select the desired drive */
1717 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1718 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1720 /* Wait a little while */
1721 ScsiPortStallExecution(50);
1724 /* Wait for BUSY to clear and DRDY to assert */
1725 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1727 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1728 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1732 ScsiPortStallExecution(10);
1734 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1735 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1737 DPRINT("Drive is BUSY for too long after drive select\n");
1738 return(SRB_STATUS_BUSY
);
1742 if (DeviceExtension
->DataTransferLength
< 0x10000)
1744 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1745 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1749 ByteCountLow
= 0xFF;
1750 ByteCountHigh
= 0xFF;
1753 /* Set feature register */
1754 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1756 /* Set command packet length */
1757 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1758 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1760 /* Issue command to drive */
1761 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_PACKET
);
1763 /* Wait for DRQ to assert */
1764 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1766 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1767 if ((Status
& IDE_SR_DRQ
))
1771 ScsiPortStallExecution(10);
1774 CdbSize
= (DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3 == 1) ? 16 : 12;
1775 DPRINT("CdbSize: %lu\n", CdbSize
);
1777 /* Write command packet */
1778 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1782 DeviceExtension
->ExpectingInterrupt
= TRUE
;
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 switch (Srb
->Cdb
[0])
1805 case SCSIOP_INQUIRY
:
1806 SrbStatus
= AtapiInquiry(DeviceExtension
,
1810 case SCSIOP_READ_CAPACITY
:
1811 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1817 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1821 case SCSIOP_SYNCHRONIZE_CACHE
:
1822 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1826 case SCSIOP_MODE_SENSE
:
1827 case SCSIOP_TEST_UNIT_READY
:
1829 case SCSIOP_START_STOP_UNIT
:
1830 case SCSIOP_REQUEST_SENSE
:
1834 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1836 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1840 DPRINT("AtapiSendIdeCommand() done!\n");
1847 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1848 PSCSI_REQUEST_BLOCK Srb
)
1850 PIDE_DRIVE_IDENTIFY DeviceParams
;
1851 PINQUIRYDATA InquiryData
;
1854 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1855 DeviceExtension
, Srb
->TargetId
);
1857 if (Srb
->PathId
!= 0)
1859 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1860 return(SRB_STATUS_INVALID_PATH_ID
);
1863 if (Srb
->TargetId
> 1)
1865 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1866 return(SRB_STATUS_INVALID_TARGET_ID
);
1871 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1872 return(SRB_STATUS_INVALID_LUN
);
1875 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1877 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1878 return(SRB_STATUS_NO_DEVICE
);
1881 InquiryData
= Srb
->DataBuffer
;
1882 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1885 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1887 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1890 /* set device class */
1891 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1894 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1898 /* get it from the ATAPI configuration word */
1899 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1900 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1903 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1904 if (DeviceParams
->ConfigBits
& 0x80)
1906 DPRINT("Removable media!\n");
1907 InquiryData
->RemovableMedia
= 1;
1910 for (i
= 0; i
< 20; i
+= 2)
1912 InquiryData
->VendorId
[i
] =
1913 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1914 InquiryData
->VendorId
[i
+1] =
1915 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1918 for (i
= 0; i
< 4; i
++)
1920 InquiryData
->ProductId
[12+i
] = ' ';
1923 for (i
= 0; i
< 4; i
+= 2)
1925 InquiryData
->ProductRevisionLevel
[i
] =
1926 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1927 InquiryData
->ProductRevisionLevel
[i
+1] =
1928 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1931 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1933 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1934 return(SRB_STATUS_SUCCESS
);
1939 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1940 PSCSI_REQUEST_BLOCK Srb
)
1942 PREAD_CAPACITY_DATA CapacityData
;
1943 PIDE_DRIVE_IDENTIFY DeviceParams
;
1946 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1948 if (Srb
->PathId
!= 0)
1950 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1951 return(SRB_STATUS_INVALID_PATH_ID
);
1954 if (Srb
->TargetId
> 1)
1956 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1957 return(SRB_STATUS_INVALID_TARGET_ID
);
1962 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1963 return(SRB_STATUS_INVALID_LUN
);
1966 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1968 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1969 return(SRB_STATUS_NO_DEVICE
);
1972 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1973 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1975 /* Set sector (block) size to 512 bytes (big-endian). */
1976 CapacityData
->BytesPerBlock
= 0x20000;
1978 /* Calculate last sector (big-endian). */
1979 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1981 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1982 DeviceParams
->TMSectorCountLo
) - 1;
1986 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1987 DeviceParams
->LogicalHeads
*
1988 DeviceParams
->SectorsPerTrack
)-1;
1991 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1992 (((PUCHAR
)&LastSector
)[1] << 16) |
1993 (((PUCHAR
)&LastSector
)[2] << 8) |
1994 ((PUCHAR
)&LastSector
)[3];
1996 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1999 CapacityData
->LogicalBlockAddress
);
2001 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2002 return(SRB_STATUS_SUCCESS
);
2007 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2008 PSCSI_REQUEST_BLOCK Srb
)
2010 PIDE_DRIVE_IDENTIFY DeviceParams
;
2011 ULONG StartingSector
;
2021 DPRINT("AtapiReadWrite() called!\n");
2023 if (Srb
->PathId
!= 0)
2025 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
2026 return(SRB_STATUS_INVALID_PATH_ID
);
2029 if (Srb
->TargetId
> 1)
2031 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2032 return(SRB_STATUS_INVALID_TARGET_ID
);
2037 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2038 return(SRB_STATUS_INVALID_LUN
);
2041 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
2043 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2044 return(SRB_STATUS_NO_DEVICE
);
2047 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2050 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2052 /* Get starting sector number from CDB. */
2053 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2054 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2055 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2056 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2058 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2059 DeviceParams
->BytesPerSector
;
2061 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2063 Srb
->DataTransferLength
,
2066 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2068 SectorNumber
= StartingSector
& 0xff;
2069 CylinderLow
= (StartingSector
>> 8) & 0xff;
2070 CylinderHigh
= (StartingSector
>> 16) & 0xff;
2071 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2072 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2077 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2078 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2079 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2080 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2081 StartingSector
/= DeviceParams
->LogicalHeads
;
2082 CylinderLow
= StartingSector
& 0xff;
2083 CylinderHigh
= StartingSector
>> 8;
2087 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2089 Command
= DeviceExtension
->MultiSectorCommand
[Srb
->TargetId
] ? IDE_CMD_READ_MULTIPLE
: IDE_CMD_READ
;
2093 Command
= DeviceExtension
->MultiSectorCommand
[Srb
->TargetId
] ? IDE_CMD_WRITE_MULTIPLE
: IDE_CMD_WRITE
;
2096 if (DrvHead
& IDE_DH_LBA
)
2098 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2099 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2100 DeviceExtension
->CommandPortBase
,
2101 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2102 ((DrvHead
& 0x0f) << 24) +
2103 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
2109 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2110 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2111 DeviceExtension
->CommandPortBase
,
2112 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2121 /* Set pointer to data buffer. */
2122 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2123 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2125 DeviceExtension
->CurrentSrb
= Srb
;
2127 /* wait for BUSY to clear */
2128 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2130 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2131 if (!(Status
& IDE_SR_BUSY
))
2135 ScsiPortStallExecution(10);
2137 DPRINT("status=%02x\n", Status
);
2138 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2139 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2141 DPRINT ("Drive is BUSY for too long\n");
2142 return(SRB_STATUS_BUSY
);
2145 /* Select the desired drive */
2146 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2147 IDE_DH_FIXED
| DrvHead
);
2149 ScsiPortStallExecution(10);
2151 /* wait for BUSY to clear and DRDY to assert */
2152 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2154 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2155 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2159 ScsiPortStallExecution(10);
2161 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2162 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2164 DPRINT("Drive is BUSY for too long after drive select\n");
2165 return(SRB_STATUS_BUSY
);
2169 /* Setup command parameters */
2170 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2171 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
2172 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
2173 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
2174 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
2175 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2177 /* Indicate expecting an interrupt. */
2178 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2180 /* Issue command to drive */
2181 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
2183 /* Write data block */
2184 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2186 PUCHAR TargetAddress
;
2189 /* Wait for controller ready */
2190 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2192 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2193 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2197 KeStallExecutionProcessor(10);
2199 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2201 DPRINT1("Drive is BUSY for too long after sending write command\n");
2202 return(SRB_STATUS_BUSY
);
2205 /* Update DeviceExtension data */
2206 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2207 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2209 TransferSize
= DeviceExtension
->DataTransferLength
;
2212 TargetAddress
= DeviceExtension
->DataBuffer
;
2213 DeviceExtension
->DataBuffer
+= TransferSize
;
2214 DeviceExtension
->DataTransferLength
-= TransferSize
;
2216 /* Write data block */
2217 if (DeviceExtension
->DWordIo
[Srb
->TargetId
])
2219 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2225 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2231 DPRINT("AtapiReadWrite() done!\n");
2233 /* Wait for interrupt. */
2234 return(SRB_STATUS_PENDING
);
2239 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2240 PSCSI_REQUEST_BLOCK Srb
)
2245 DPRINT1("AtapiFlushCache() called!\n");
2247 if (Srb
->PathId
!= 0)
2249 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
2250 return(SRB_STATUS_INVALID_PATH_ID
);
2253 if (Srb
->TargetId
> 1)
2255 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2256 return(SRB_STATUS_INVALID_TARGET_ID
);
2261 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2262 return(SRB_STATUS_INVALID_LUN
);
2265 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
2267 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2268 return(SRB_STATUS_NO_DEVICE
);
2271 DPRINT1("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2274 /* Wait for BUSY to clear */
2275 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2277 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2278 if (!(Status
& IDE_SR_BUSY
))
2282 ScsiPortStallExecution(10);
2284 DPRINT1("Status=%02x\n", Status
);
2285 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2286 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2288 DPRINT1("Drive is BUSY for too long\n");
2289 return(SRB_STATUS_BUSY
);
2292 /* Select the desired drive */
2293 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2294 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2295 ScsiPortStallExecution(10);
2297 /* Issue command to drive */
2298 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_FLUSH_CACHE
);
2300 /* Wait for controller ready */
2301 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2303 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2304 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2308 KeStallExecutionProcessor(10);
2310 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2312 DPRINT1("Drive is BUSY for too long after sending write command\n");
2313 return(SRB_STATUS_BUSY
);
2316 /* Indicate expecting an interrupt. */
2317 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2319 DPRINT1("AtapiFlushCache() done!\n");
2321 /* Wait for interrupt. */
2322 return(SRB_STATUS_PENDING
);
2327 AtapiErrorToScsi(PVOID DeviceExtension
,
2328 PSCSI_REQUEST_BLOCK Srb
)
2330 PATAPI_MINIPORT_EXTENSION DevExt
;
2331 ULONG CommandPortBase
;
2332 ULONG ControlPortBase
;
2337 DPRINT("AtapiErrorToScsi() called\n");
2339 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2341 CommandPortBase
= DevExt
->CommandPortBase
;
2342 ControlPortBase
= DevExt
->ControlPortBase
;
2344 ErrorReg
= IDEReadError(CommandPortBase
);
2346 if (DevExt
->DeviceAtapi
[Srb
->TargetId
])
2348 switch (ErrorReg
>> 4)
2350 case SCSI_SENSE_NO_SENSE
:
2351 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2352 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2353 SrbStatus
= SRB_STATUS_ERROR
;
2356 case SCSI_SENSE_RECOVERED_ERROR
:
2357 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2359 SrbStatus
= SRB_STATUS_SUCCESS
;
2362 case SCSI_SENSE_NOT_READY
:
2363 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2364 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2365 SrbStatus
= SRB_STATUS_ERROR
;
2368 case SCSI_SENSE_MEDIUM_ERROR
:
2369 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2370 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2371 SrbStatus
= SRB_STATUS_ERROR
;
2374 case SCSI_SENSE_HARDWARE_ERROR
:
2375 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2376 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2377 SrbStatus
= SRB_STATUS_ERROR
;
2380 case SCSI_SENSE_ILLEGAL_REQUEST
:
2381 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2382 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2383 SrbStatus
= SRB_STATUS_ERROR
;
2386 case SCSI_SENSE_UNIT_ATTENTION
:
2387 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2388 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2389 SrbStatus
= SRB_STATUS_ERROR
;
2392 case SCSI_SENSE_DATA_PROTECT
:
2393 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2394 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2395 SrbStatus
= SRB_STATUS_ERROR
;
2398 case SCSI_SENSE_BLANK_CHECK
:
2399 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2400 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2401 SrbStatus
= SRB_STATUS_ERROR
;
2404 case SCSI_SENSE_ABORTED_COMMAND
:
2405 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2406 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2407 SrbStatus
= SRB_STATUS_ERROR
;
2411 DPRINT("ATAPI error: Invalid sense key\n");
2413 SrbStatus
= SRB_STATUS_ERROR
;
2419 DPRINT1("IDE error: %02x\n", ErrorReg
);
2422 SrbStatus
= SRB_STATUS_ERROR
;
2425 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2428 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2429 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2430 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2431 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2432 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2434 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2445 Srb
->ScsiStatus
= ScsiStatus
;
2447 DPRINT("AtapiErrorToScsi() done\n");