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.39 2003/06/24 12:29:02 ekohl 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];
78 ULONG TransferSize
[2];
80 ULONG CommandPortBase
;
81 ULONG ControlPortBase
;
82 ULONG BusMasterRegisterBase
;
84 BOOLEAN ExpectingInterrupt
;
85 PSCSI_REQUEST_BLOCK CurrentSrb
;
89 ULONG DataTransferLength
;
90 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
93 #define DEVICE_PRESENT 0x00000001
94 #define DEVICE_ATAPI 0x00000002
95 #define DEVICE_MULTI_SECTOR_CMD 0x00000004
96 #define DEVICE_DWORD_IO 0x00000008
97 #define DEVICE_48BIT_ADDRESS 0x00000010
98 #define DEVICE_MEDIA_STATUS 0x00000020
101 typedef struct _UNIT_EXTENSION
104 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
106 PCI_SLOT_NUMBER LastSlotNumber
;
108 #ifdef ENABLE_NATIVE_PCI
109 typedef struct _PCI_NATIVE_CONTROLLER
114 PCI_NATIVE_CONTROLLER
, *PPCI_NATIVE_CONTROLLER
;
116 PCI_NATIVE_CONTROLLER
const PciNativeController
[] =
120 0x4D68, // PDC20268, Ultra100TX2
124 0x4D30, // PDC20267, Ultra100
130 // ----------------------------------------------- Discardable Declarations
134 // make the initialization routines discardable, so that they
137 #pragma alloc_text(init, DriverEntry)
138 #pragma alloc_text(init, IDECreateController)
139 #pragma alloc_text(init, IDEPolledRead)
141 // make the PASSIVE_LEVEL routines pageable, so that they don't
142 // waste nonpaged memory
144 #pragma alloc_text(page, IDEShutdown)
145 #pragma alloc_text(page, IDEDispatchOpenClose)
146 #pragma alloc_text(page, IDEDispatchRead)
147 #pragma alloc_text(page, IDEDispatchWrite)
149 #endif /* ALLOC_PRAGMA */
151 // ---------------------------------------------------- Forward Declarations
154 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
156 PVOID BusInformation
,
157 PCHAR ArgumentString
,
158 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
162 AtapiFindIsaBusController(PVOID DeviceExtension
,
164 PVOID BusInformation
,
165 PCHAR ArgumentString
,
166 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
170 AtapiFindNativePciController(PVOID DeviceExtension
,
172 PVOID BusInformation
,
173 PCHAR ArgumentString
,
174 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
177 static BOOLEAN STDCALL
178 AtapiInitialize(IN PVOID DeviceExtension
);
180 static BOOLEAN STDCALL
181 AtapiResetBus(IN PVOID DeviceExtension
,
184 static BOOLEAN STDCALL
185 AtapiStartIo(IN PVOID DeviceExtension
,
186 IN PSCSI_REQUEST_BLOCK Srb
);
188 static BOOLEAN STDCALL
189 AtapiInterrupt(IN PVOID DeviceExtension
);
192 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
193 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
196 AtapiIdentifyDevice(IN ULONG CommandPort
,
197 IN ULONG ControlPort
,
200 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
203 IDEResetController(IN ULONG CommandPort
,
204 IN ULONG ControlPort
);
207 AtapiPolledRead(IN ULONG CommandPort
,
208 IN ULONG ControlPort
,
213 IN BYTE CylinderHigh
,
221 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
222 IN PSCSI_REQUEST_BLOCK Srb
);
225 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
226 IN PSCSI_REQUEST_BLOCK Srb
);
229 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
230 IN PSCSI_REQUEST_BLOCK Srb
);
233 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
234 IN PSCSI_REQUEST_BLOCK Srb
);
237 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
238 IN PSCSI_REQUEST_BLOCK Srb
);
241 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
242 PSCSI_REQUEST_BLOCK Srb
);
245 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
246 PSCSI_REQUEST_BLOCK Srb
);
249 AtapiErrorToScsi(PVOID DeviceExtension
,
250 PSCSI_REQUEST_BLOCK Srb
);
252 // ---------------------------------------------------------------- Inlines
255 IDESwapBytePairs(char *Buf
,
261 for (i
= 0; i
< Cnt
; i
+= 2)
270 // ------------------------------------------------------- Public Interface
275 // This function initializes the driver, locates and claims
276 // hardware resources, and creates various NT objects needed
277 // to process I/O requests.
283 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
285 // IN PUNICODE_STRING RegistryPath Name of registry driver service
292 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
293 IN PUNICODE_STRING RegistryPath
)
295 HW_INITIALIZATION_DATA InitData
;
298 DPRINT("ATAPI Driver %s\n", VERSION
);
299 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
301 /* Initialize data structure */
302 RtlZeroMemory(&InitData
,
303 sizeof(HW_INITIALIZATION_DATA
));
304 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
305 InitData
.HwInitialize
= AtapiInitialize
;
306 InitData
.HwResetBus
= AtapiResetBus
;
307 InitData
.HwStartIo
= AtapiStartIo
;
308 InitData
.HwInterrupt
= AtapiInterrupt
;
310 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
311 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
313 InitData
.MapBuffers
= TRUE
;
316 /* Search the PCI bus for compatibility mode ide controllers */
318 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
319 InitData
.NumberOfAccessRanges
= 3;
320 InitData
.AdapterInterfaceType
= PCIBus
;
322 InitData
.VendorId
= NULL
;
323 InitData
.VendorIdLength
= 0;
324 InitData
.DeviceId
= NULL
;
325 InitData
.DeviceIdLength
= 0;
327 Status
= ScsiPortInitialize(DriverObject
,
331 // if (newStatus < statusToReturn)
332 // statusToReturn = newStatus;
335 /* Search the PCI bus for all ide controllers */
336 #ifdef ENABLE_NATIVE_PCI
338 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
339 InitData
.NumberOfAccessRanges
= 3;
340 InitData
.AdapterInterfaceType
= PCIBus
;
342 InitData
.VendorId
= 0;
343 InitData
.VendorIdLength
= 0;
344 InitData
.DeviceId
= 0;
345 InitData
.DeviceIdLength
= 0;
347 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
349 Status
= ScsiPortInitialize(DriverObject
,
353 // if (newStatus < statusToReturn)
354 // statusToReturn = newStatus;
357 /* Search the ISA bus for ide controllers */
359 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
360 InitData
.NumberOfAccessRanges
= 2;
361 InitData
.AdapterInterfaceType
= Isa
;
363 InitData
.VendorId
= NULL
;
364 InitData
.VendorIdLength
= 0;
365 InitData
.DeviceId
= NULL
;
366 InitData
.DeviceIdLength
= 0;
368 Status
= ScsiPortInitialize(DriverObject
,
372 // if (newStatus < statusToReturn)
373 // statusToReturn = newStatus;
376 DPRINT("Returning from DriverEntry\n");
383 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
384 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
385 INTERFACE_TYPE InterfaceType
,
386 ULONG CommandPortBase
,
387 ULONG ControlPortBase
,
388 ULONG BusMasterPortBase
,
389 ULONG InterruptVector
)
391 SCSI_PHYSICAL_ADDRESS IoAddress
;
394 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
395 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
397 ConfigInfo
->SystemIoBusNumber
,
405 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
406 ConfigInfo
->AccessRanges
[0].RangeStart
= IoAddress
;
407 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
408 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
412 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
413 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
415 ConfigInfo
->SystemIoBusNumber
,
421 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
422 (PVOID
)DevExt
->CommandPortBase
);
425 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
426 ConfigInfo
->AccessRanges
[1].RangeStart
= IoAddress
;
427 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
428 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
430 if (BusMasterPortBase
)
432 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
433 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
435 ConfigInfo
->SystemIoBusNumber
,
441 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
442 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
445 ConfigInfo
->AccessRanges
[2].RangeStart
= IoAddress
;
446 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
447 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
449 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
450 ConfigInfo
->BusInterruptVector
= InterruptVector
;
451 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
453 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
455 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
457 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
459 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
467 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
469 PVOID BusInformation
,
470 PCHAR ArgumentString
,
471 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
474 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
475 PCI_SLOT_NUMBER SlotNumber
;
476 PCI_COMMON_CONFIG PciConfig
;
478 ULONG StartDeviceNumber
;
480 ULONG StartFunctionNumber
;
481 ULONG FunctionNumber
;
482 BOOLEAN ChannelFound
;
484 ULONG BusMasterBasePort
= 0;
486 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
487 ConfigInfo
->SystemIoBusNumber
,
488 ConfigInfo
->SlotNumber
);
492 /* both channels were claimed: exit */
493 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
494 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
495 return(SP_RETURN_NOT_FOUND
);
497 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
498 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
499 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
500 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
502 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
503 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
505 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
506 ChannelFound
= FALSE
;
509 DataSize
= ScsiPortGetBusData(DeviceExtension
,
511 ConfigInfo
->SystemIoBusNumber
,
512 SlotNumber
.u
.AsULONG
,
514 PCI_COMMON_HDR_LENGTH
);
515 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
517 if (FunctionNumber
== 0)
527 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
528 if (PciConfig
.BaseClass
== 0x01 &&
529 PciConfig
.SubClass
== 0x01) // &&
530 // (PciConfig.ProgIf & 0x05) == 0)
532 /* both channels are in compatibility mode */
533 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
534 ConfigInfo
->SystemIoBusNumber
,
535 SlotNumber
.u
.bits
.DeviceNumber
,
536 SlotNumber
.u
.bits
.FunctionNumber
,
539 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
541 DPRINT("Found IDE controller in compatibility mode!\n");
543 ConfigInfo
->NumberOfBuses
= 1;
544 ConfigInfo
->MaximumNumberOfTargets
= 2;
545 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
547 if (PciConfig
.ProgIf
& 0x80)
549 DPRINT("Found IDE Bus Master controller!\n");
550 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
552 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
553 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
556 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
558 /* Both channels unclaimed: Claim primary channel */
559 DPRINT("Primary channel!\n");
560 ChannelFound
= AtapiClaimHwResources(DevExt
,
569 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
571 /* Primary channel already claimed: claim secondary channel */
572 DPRINT("Secondary channel!\n");
574 ChannelFound
= AtapiClaimHwResources(DevExt
,
579 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
583 /* Find attached devices */
586 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
587 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
588 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
589 return(SP_RETURN_FOUND
);
592 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
597 StartFunctionNumber
= 0;
599 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
601 return(SP_RETURN_NOT_FOUND
);
608 AtapiFindIsaBusController(PVOID DeviceExtension
,
610 PVOID BusInformation
,
611 PCHAR ArgumentString
,
612 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
615 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
616 BOOLEAN ChannelFound
= FALSE
;
617 BOOLEAN DeviceFound
= FALSE
;
619 DPRINT("AtapiFindIsaBusController() called!\n");
623 ConfigInfo
->NumberOfBuses
= 1;
624 ConfigInfo
->MaximumNumberOfTargets
= 2;
625 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
627 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
629 /* Both channels unclaimed: Claim primary channel */
630 DPRINT("Primary channel!\n");
632 ChannelFound
= AtapiClaimHwResources(DevExt
,
641 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
643 /* Primary channel already claimed: claim secondary channel */
644 DPRINT("Secondary channel!\n");
646 ChannelFound
= AtapiClaimHwResources(DevExt
,
657 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
659 return(SP_RETURN_NOT_FOUND
);
662 /* Find attached devices */
665 DeviceFound
= AtapiFindDevices(DevExt
,
667 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
668 return(SP_RETURN_FOUND
);
671 return SP_RETURN_NOT_FOUND
;
676 #ifdef ENABLE_NATIVE_PCI
678 AtapiFindNativePciController(PVOID DeviceExtension
,
680 PVOID BusInformation
,
681 PCHAR ArgumentString
,
682 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
685 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
686 PCI_COMMON_CONFIG PciConfig
;
687 PCI_SLOT_NUMBER SlotNumber
;
690 ULONG StartDeviceNumber
;
691 ULONG FunctionNumber
;
692 ULONG StartFunctionNumber
;
693 ULONG BusMasterBasePort
;
695 BOOLEAN ChannelFound
;
697 DPRINT("AtapiFindNativePciController() called!\n");
699 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
700 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
701 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
702 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
704 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
705 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
707 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
708 DataSize
= ScsiPortGetBusData(DeviceExtension
,
710 ConfigInfo
->SystemIoBusNumber
,
711 SlotNumber
.u
.AsULONG
,
713 PCI_COMMON_HDR_LENGTH
);
714 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
718 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
720 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
721 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
726 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
728 /* We have found a known native pci ide controller */
729 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
731 DPRINT("Found IDE Bus Master controller!\n");
732 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
733 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
737 BusMasterBasePort
= 0;
740 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
741 ConfigInfo
->NumberOfBuses
= 1;
742 ConfigInfo
->MaximumNumberOfTargets
= 2;
743 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
746 We must not store and use the last tested slot number. If there is a recall
747 to the some device and we will claim the primary channel again than the call
748 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
749 claim the secondary channel.
751 ChannelFound
= FALSE
;
752 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
754 /* try to claim primary channel */
755 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
756 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
758 /* primary channel is enabled */
759 ChannelFound
= AtapiClaimHwResources(DevExt
,
762 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
763 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
765 PciConfig
.u
.type0
.InterruptLine
);
768 AtapiFindDevices(DevExt
, ConfigInfo
);
770 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
771 return SP_RETURN_FOUND
;
777 /* try to claim secondary channel */
778 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
779 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
781 /* secondary channel is enabled */
782 ChannelFound
= AtapiClaimHwResources(DevExt
,
785 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
786 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
787 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
788 PciConfig
.u
.type0
.InterruptLine
);
791 AtapiFindDevices(DevExt
, ConfigInfo
);
793 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
794 return SP_RETURN_FOUND
;
800 StartFunctionNumber
= 0;
803 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
804 DPRINT("AtapiFindNativePciController() done!\n");
806 return(SP_RETURN_NOT_FOUND
);
811 static BOOLEAN STDCALL
812 AtapiInitialize(IN PVOID DeviceExtension
)
818 static BOOLEAN STDCALL
819 AtapiResetBus(IN PVOID DeviceExtension
,
826 static BOOLEAN STDCALL
827 AtapiStartIo(IN PVOID DeviceExtension
,
828 IN PSCSI_REQUEST_BLOCK Srb
)
830 PATAPI_MINIPORT_EXTENSION DevExt
;
833 DPRINT("AtapiStartIo() called\n");
835 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
837 switch (Srb
->Function
)
839 case SRB_FUNCTION_EXECUTE_SCSI
:
840 DevExt
->CurrentSrb
= Srb
;
841 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
843 Result
= AtapiSendAtapiCommand(DevExt
,
848 Result
= AtapiSendIdeCommand(DevExt
,
855 Srb
->SrbStatus
= Result
;
858 if (Result
!= SRB_STATUS_PENDING
)
860 DevExt
->CurrentSrb
= NULL
;
861 Srb
->SrbStatus
= (UCHAR
)Result
;
863 ScsiPortNotification(RequestComplete
,
866 ScsiPortNotification(NextRequest
,
872 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
875 DPRINT("AtapiStartIo() done\n");
881 static BOOLEAN STDCALL
882 AtapiInterrupt(IN PVOID DeviceExtension
)
884 PATAPI_MINIPORT_EXTENSION DevExt
;
885 PSCSI_REQUEST_BLOCK Srb
;
886 ULONG CommandPortBase
;
887 ULONG ControlPortBase
;
893 PUCHAR TargetAddress
;
896 DPRINT("AtapiInterrupt() called!\n");
898 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
900 CommandPortBase
= DevExt
->CommandPortBase
;
901 ControlPortBase
= DevExt
->ControlPortBase
;
903 if (DevExt
->ExpectingInterrupt
== FALSE
)
905 DeviceStatus
= IDEReadStatus(CommandPortBase
);
906 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase
);
910 /* check if it was our irq */
911 if ((DeviceStatus
= IDEReadAltStatus(ControlPortBase
)) & IDE_SR_BUSY
)
913 ScsiPortStallExecution(1);
914 if ((DeviceStatus
= IDEReadAltStatus(ControlPortBase
) & IDE_SR_BUSY
))
916 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase
);
921 Srb
= DevExt
->CurrentSrb
;
922 DPRINT("Srb: %p\n", Srb
);
924 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
926 IsAtapi
= (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
);
927 DPRINT("IsAtapi == %s\n", (IsAtapi
) ? "TRUE" : "FALSE");
931 DeviceStatus
= IDEReadStatus(CommandPortBase
);
932 DPRINT("DeviceStatus: %x\n", DeviceStatus
);
934 if ((DeviceStatus
& IDE_SR_ERR
) &&
935 (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
))
937 /* Report error condition */
938 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
943 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
945 DPRINT("Read data\n");
947 /* Update controller/device state variables */
948 TargetAddress
= DevExt
->DataBuffer
;
952 TransferSize
= IDEReadCylinderLow(CommandPortBase
);
953 TransferSize
+= IDEReadCylinderHigh(CommandPortBase
) << 8;
957 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
960 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
961 DPRINT("TransferSize: %lu\n", TransferSize
);
963 if (DevExt
->DataTransferLength
<= TransferSize
)
967 TransferSize
= DevExt
->DataTransferLength
;
969 DevExt
->DataTransferLength
= 0;
974 DevExt
->DataTransferLength
-= TransferSize
;
977 DevExt
->DataBuffer
+= TransferSize
;
978 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
980 /* Wait for DRQ assertion */
981 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
982 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
985 KeStallExecutionProcessor(10);
988 /* Copy the block of data */
989 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
991 IDEReadBlock32(CommandPortBase
,
997 IDEReadBlock(CommandPortBase
,
1005 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1006 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
1009 KeStallExecutionProcessor(10);
1012 /* Check for data overrun */
1013 while (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
1015 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
1016 IDEReadWord(CommandPortBase
);
1020 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1022 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
1024 DPRINT("Write data\n");
1026 if (DevExt
->DataTransferLength
== 0)
1028 /* Check for data overrun */
1029 if (DeviceStatus
& IDE_SR_DRQ
)
1031 /* FIXME: Handle error! */
1032 /* This can occure if the irq is shared with an other and if the
1033 ide controller has a write buffer. We have write the last sectors
1034 and the other device has a irq before ours. The isr is called but
1035 we haven't a interrupt. The controller writes the sector buffer
1036 and the status register shows DRQ because the write is not ended. */
1037 DPRINT("AtapiInterrupt(): data overrun error!\n");
1043 /* Update DevExt data */
1044 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
1045 if (DevExt
->DataTransferLength
< TransferSize
)
1047 TransferSize
= DevExt
->DataTransferLength
;
1050 TargetAddress
= DevExt
->DataBuffer
;
1051 DevExt
->DataBuffer
+= TransferSize
;
1052 DevExt
->DataTransferLength
-= TransferSize
;
1054 /* Write the sector */
1055 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
1057 IDEWriteBlock32(CommandPortBase
,
1063 IDEWriteBlock(CommandPortBase
,
1069 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1073 DPRINT1("Unspecified transfer direction!\n");
1074 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
; // SRB_STATUS_ERROR;
1080 if (Srb
->SrbStatus
== SRB_STATUS_ERROR
)
1082 Srb
->SrbStatus
= AtapiErrorToScsi(DeviceExtension
,
1087 /* complete this packet */
1090 DevExt
->ExpectingInterrupt
= FALSE
;
1092 ScsiPortNotification(RequestComplete
,
1096 ScsiPortNotification(NextRequest
,
1101 DPRINT("AtapiInterrupt() done!\n");
1106 // ---------------------------------------------------- Discardable statics
1109 /**********************************************************************
1114 * Searches for devices on the given port.
1121 * Port device specific information.
1124 * Port configuration information.
1127 * TRUE: At least one device is attached to the port.
1128 * FALSE: No device is attached to the port.
1132 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1133 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1135 BOOLEAN DeviceFound
= FALSE
;
1136 ULONG CommandPortBase
;
1137 ULONG ControlPortBase
;
1142 DPRINT("AtapiFindDevices() called\n");
1144 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
1145 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1147 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
1148 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1150 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1153 IDEWriteDriveHead(CommandPortBase
,
1154 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1155 ScsiPortStallExecution(500);
1157 /* Disable interrupts */
1158 IDEWriteDriveControl(ControlPortBase
,
1160 ScsiPortStallExecution(500);
1162 /* Check if a device is attached to the interface */
1163 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1164 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1166 High
= IDEReadCylinderHigh(CommandPortBase
);
1167 Low
= IDEReadCylinderLow(CommandPortBase
);
1169 IDEWriteCylinderHigh(CommandPortBase
, 0);
1170 IDEWriteCylinderLow(CommandPortBase
, 0);
1172 if (Low
!= 0x55 || High
!= 0xaa)
1174 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1178 IDEWriteCommand(CommandPortBase
, IDE_CMD_RESET
);
1180 for (Retries
= 0; Retries
< 20000; Retries
++)
1182 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1186 ScsiPortStallExecution(150);
1188 if (Retries
>= 20000)
1190 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1191 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1195 High
= IDEReadCylinderHigh(CommandPortBase
);
1196 Low
= IDEReadCylinderLow(CommandPortBase
);
1198 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1203 if (High
== 0xEB && Low
== 0x14)
1205 if (AtapiIdentifyDevice(CommandPortBase
,
1209 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1211 DPRINT(" ATAPI drive found!\n");
1212 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1213 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1214 DeviceExtension
->TransferSize
[UnitNumber
] =
1215 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1220 DPRINT(" No ATAPI drive found!\n");
1225 if (AtapiIdentifyDevice(CommandPortBase
,
1229 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1231 DPRINT(" IDE drive found!\n");
1232 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1233 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1234 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1235 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1236 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1237 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1239 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1240 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1243 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1245 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1252 DPRINT(" No IDE drive found!\n");
1257 /* Reset pending interrupts */
1258 IDEReadStatus(CommandPortBase
);
1259 /* Reenable interrupts */
1260 IDEWriteDriveControl(ControlPortBase
, 0);
1261 ScsiPortStallExecution(500);
1262 /* Return with drive 0 selected */
1263 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1264 ScsiPortStallExecution(500);
1266 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1268 return(DeviceFound
);
1272 // AtapiResetController
1275 // Reset the controller and report completion status
1281 // IN WORD CommandPort The address of the command port
1282 // IN WORD ControlPort The address of the control port
1288 AtapiResetController(IN ULONG CommandPort
,
1289 IN ULONG ControlPort
)
1293 /* Assert drive reset line */
1294 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
1296 /* Wait for min. 25 microseconds */
1297 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
1299 /* Negate drive reset line */
1300 IDEWriteDriveControl(ControlPort
, 0);
1302 /* Wait for BUSY negation */
1303 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
1305 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
1309 ScsiPortStallExecution(10);
1312 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
1317 // return TRUE if controller came back to life. and
1318 // the registers are initialized correctly
1319 return(IDEReadError(CommandPort
) == 1);
1323 * AtapiIdentifyDevice
1326 * Get the identification block from the drive
1333 * Address of the command port
1335 * Address of the control port
1337 * The drive index (0,1)
1339 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1341 * Address to write drive ident block
1344 * TRUE: The drive identification block was retrieved successfully
1345 * FALSE: an error ocurred
1349 AtapiIdentifyDevice(IN ULONG CommandPort
,
1350 IN ULONG ControlPort
,
1353 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1357 /* Get the Drive Identify block from drive or die */
1358 if (AtapiPolledRead(CommandPort
,
1365 (DriveNum
? IDE_DH_DRV1
: 0),
1366 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1367 (BYTE
*)DrvParms
) != 0)
1369 DPRINT("IDEPolledRead() failed\n");
1373 /* Report on drive parameters if debug mode */
1374 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1375 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1376 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1377 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1378 DrvParms
->ConfigBits
,
1379 DrvParms
->LogicalCyls
,
1380 DrvParms
->LogicalHeads
,
1381 DrvParms
->SectorsPerTrack
,
1382 DrvParms
->InterSectorGap
,
1383 DrvParms
->InterSectorGapSize
);
1384 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1385 DrvParms
->BytesInPLO
,
1386 DrvParms
->VendorUniqueCnt
,
1387 DrvParms
->SerialNumber
);
1388 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1389 DrvParms
->ControllerType
,
1390 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1391 DrvParms
->ECCByteCnt
,
1392 DrvParms
->FirmwareRev
);
1393 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1394 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1395 (DrvParms
->RWMultImplemented
),
1396 (DrvParms
->RWMultCurrent
) & 0xff,
1397 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1398 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1399 DrvParms
->MinPIOTransTime
,
1400 DrvParms
->MinDMATransTime
);
1401 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1402 DrvParms
->TMCylinders
,
1404 DrvParms
->TMSectorsPerTrk
,
1405 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1406 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1407 DrvParms
->TMSectorCountHi
,
1408 DrvParms
->TMSectorCountLo
,
1409 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1411 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1413 /* LBA ATA drives always have a sector size of 512 */
1414 DrvParms
->BytesPerSector
= 512;
1418 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1419 if (DrvParms
->BytesPerSector
== 0)
1421 DrvParms
->BytesPerSector
= 512;
1425 for (i
= 15; i
>= 0; i
--)
1427 if (DrvParms
->BytesPerSector
& (1 << i
))
1429 DrvParms
->BytesPerSector
= 1 << i
;
1435 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1444 // Read a sector of data from the drive in a polled fashion.
1450 // IN WORD Address Address of command port for drive
1451 // IN BYTE PreComp Value to write to precomp register
1452 // IN BYTE SectorCnt Value to write to sectorCnt register
1453 // IN BYTE SectorNum Value to write to sectorNum register
1454 // IN BYTE CylinderLow Value to write to CylinderLow register
1455 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1456 // IN BYTE DrvHead Value to write to Drive/Head register
1457 // IN BYTE Command Value to write to Command register
1458 // OUT BYTE *Buffer Buffer for output data
1461 // int 0 is success, non 0 is an error code
1465 AtapiPolledRead(IN ULONG CommandPort
,
1466 IN ULONG ControlPort
,
1470 IN BYTE CylinderLow
,
1471 IN BYTE CylinderHigh
,
1476 ULONG SectorCount
= 0;
1478 BOOLEAN Junk
= FALSE
;
1482 /* Wait for BUSY to clear */
1483 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1485 Status
= IDEReadStatus(CommandPort
);
1486 if (!(Status
& IDE_SR_BUSY
))
1490 ScsiPortStallExecution(10);
1492 DPRINT("status=%02x\n", Status
);
1493 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1494 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1496 DPRINT("Drive is BUSY for too long\n");
1497 return(IDE_ER_ABRT
);
1501 /* Write Drive/Head to select drive */
1502 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1503 ScsiPortStallExecution(500);
1505 /* Disable interrupts */
1506 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1507 ScsiPortStallExecution(500);
1510 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1511 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1513 Status
= IDEReadStatus(CommandPort
);
1514 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1518 ScsiPortStallExecution(10);
1520 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1526 /* Issue command to drive */
1527 if (DrvHead
& IDE_DH_LBA
)
1529 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1530 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1531 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1537 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1538 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1547 /* Setup command parameters */
1548 IDEWritePrecomp(CommandPort
, PreComp
);
1549 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1550 IDEWriteSectorNum(CommandPort
, SectorNum
);
1551 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1552 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1553 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1555 /* Issue the command */
1556 IDEWriteCommand(CommandPort
, Command
);
1557 ScsiPortStallExecution(50);
1559 /* wait for DRQ or error */
1560 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1562 Status
= IDEReadStatus(CommandPort
);
1563 if (!(Status
& IDE_SR_BUSY
))
1565 if (Status
& IDE_SR_ERR
)
1567 IDEWriteDriveControl(ControlPort
, 0);
1568 ScsiPortStallExecution(50);
1569 IDEReadStatus(CommandPort
);
1571 return(IDE_ER_ABRT
);
1573 if (Status
& IDE_SR_DRQ
)
1579 IDEWriteDriveControl(ControlPort
, 0);
1580 ScsiPortStallExecution(50);
1581 IDEReadStatus(CommandPort
);
1583 return(IDE_ER_ABRT
);
1586 ScsiPortStallExecution(10);
1590 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1592 IDEWriteDriveControl(ControlPort
, 0);
1593 ScsiPortStallExecution(50);
1594 IDEReadStatus(CommandPort
);
1596 return(IDE_ER_ABRT
);
1601 /* Read data into buffer */
1604 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1605 Buffer
+= IDE_SECTOR_BUF_SZ
;
1609 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1610 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1614 /* Check for error or more sectors to read */
1615 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1617 Status
= IDEReadStatus(CommandPort
);
1618 if (!(Status
& IDE_SR_BUSY
))
1620 if (Status
& IDE_SR_ERR
)
1622 IDEWriteDriveControl(ControlPort
, 0);
1623 ScsiPortStallExecution(50);
1624 IDEReadStatus(CommandPort
);
1626 return(IDE_ER_ABRT
);
1628 if (Status
& IDE_SR_DRQ
)
1630 if (SectorCount
>= SectorCnt
)
1632 DPRINT("Buffer size exceeded!\n");
1639 if (SectorCount
> SectorCnt
)
1641 DPRINT("Read %lu sectors of junk!\n",
1642 SectorCount
- SectorCnt
);
1644 IDEWriteDriveControl(ControlPort
, 0);
1645 ScsiPortStallExecution(50);
1646 IDEReadStatus(CommandPort
);
1656 // ------------------------------------------- Nondiscardable statics
1659 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1660 IN PSCSI_REQUEST_BLOCK Srb
)
1662 UCHAR ByteCountHigh
;
1668 DPRINT("AtapiSendAtapiCommand() called!\n");
1670 if (Srb
->PathId
!= 0)
1672 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1673 return(SRB_STATUS_INVALID_PATH_ID
);
1676 if (Srb
->TargetId
> 1)
1678 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1679 return(SRB_STATUS_INVALID_TARGET_ID
);
1684 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1685 return(SRB_STATUS_INVALID_LUN
);
1688 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1690 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1691 return(SRB_STATUS_NO_DEVICE
);
1694 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1697 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1698 return(AtapiInquiry(DeviceExtension
,
1701 /* Set pointer to data buffer. */
1702 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1703 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1704 DeviceExtension
->CurrentSrb
= Srb
;
1706 /* Wait for BUSY to clear */
1707 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1709 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1710 if (!(Status
& IDE_SR_BUSY
))
1714 ScsiPortStallExecution(10);
1716 DPRINT("status=%02x\n", Status
);
1717 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1718 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1720 DPRINT("Drive is BUSY for too long\n");
1721 return(SRB_STATUS_BUSY
);
1724 /* Select the desired drive */
1725 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1726 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1728 /* Wait a little while */
1729 ScsiPortStallExecution(50);
1732 /* Wait for BUSY to clear and DRDY to assert */
1733 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1735 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1736 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1740 ScsiPortStallExecution(10);
1742 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1743 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1745 DPRINT("Drive is BUSY for too long after drive select\n");
1746 return(SRB_STATUS_BUSY
);
1750 if (DeviceExtension
->DataTransferLength
< 0x10000)
1752 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1753 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1757 ByteCountLow
= 0xFF;
1758 ByteCountHigh
= 0xFF;
1761 /* Set feature register */
1762 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1764 /* Set command packet length */
1765 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1766 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1768 /* Issue command to drive */
1769 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_PACKET
);
1771 /* Wait for DRQ to assert */
1772 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1774 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1775 if ((Status
& IDE_SR_DRQ
))
1779 ScsiPortStallExecution(10);
1782 CdbSize
= (DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3 == 1) ? 16 : 12;
1783 DPRINT("CdbSize: %lu\n", CdbSize
);
1785 /* Write command packet */
1786 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1790 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1792 DPRINT("AtapiSendAtapiCommand() done\n");
1794 return(SRB_STATUS_PENDING
);
1799 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1800 IN PSCSI_REQUEST_BLOCK Srb
)
1802 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1804 DPRINT("AtapiSendIdeCommand() called!\n");
1806 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1811 switch (Srb
->Cdb
[0])
1813 case SCSIOP_INQUIRY
:
1814 SrbStatus
= AtapiInquiry(DeviceExtension
,
1818 case SCSIOP_READ_CAPACITY
:
1819 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1825 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1829 case SCSIOP_SYNCHRONIZE_CACHE
:
1830 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1834 case SCSIOP_TEST_UNIT_READY
:
1835 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1839 case SCSIOP_MODE_SENSE
:
1841 case SCSIOP_START_STOP_UNIT
:
1842 case SCSIOP_REQUEST_SENSE
:
1846 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1848 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1852 DPRINT("AtapiSendIdeCommand() done!\n");
1859 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1860 PSCSI_REQUEST_BLOCK Srb
)
1862 PIDE_DRIVE_IDENTIFY DeviceParams
;
1863 PINQUIRYDATA InquiryData
;
1866 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1867 DeviceExtension
, Srb
->TargetId
);
1869 if (Srb
->PathId
!= 0)
1871 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1872 return(SRB_STATUS_INVALID_PATH_ID
);
1875 if (Srb
->TargetId
> 1)
1877 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1878 return(SRB_STATUS_INVALID_TARGET_ID
);
1883 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1884 return(SRB_STATUS_INVALID_LUN
);
1887 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1889 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1890 return(SRB_STATUS_NO_DEVICE
);
1893 InquiryData
= Srb
->DataBuffer
;
1894 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1897 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1899 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1902 /* set device class */
1903 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1905 /* get it from the ATAPI configuration word */
1906 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1907 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1912 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1915 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1916 if (DeviceParams
->ConfigBits
& 0x80)
1918 DPRINT("Removable media!\n");
1919 InquiryData
->RemovableMedia
= 1;
1922 for (i
= 0; i
< 20; i
+= 2)
1924 InquiryData
->VendorId
[i
] =
1925 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1926 InquiryData
->VendorId
[i
+1] =
1927 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1930 for (i
= 0; i
< 4; i
++)
1932 InquiryData
->ProductId
[12+i
] = ' ';
1935 for (i
= 0; i
< 4; i
+= 2)
1937 InquiryData
->ProductRevisionLevel
[i
] =
1938 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1939 InquiryData
->ProductRevisionLevel
[i
+1] =
1940 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1943 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1945 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1946 return(SRB_STATUS_SUCCESS
);
1951 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1952 PSCSI_REQUEST_BLOCK Srb
)
1954 PREAD_CAPACITY_DATA CapacityData
;
1955 PIDE_DRIVE_IDENTIFY DeviceParams
;
1958 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1960 if (Srb
->PathId
!= 0)
1962 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1963 return(SRB_STATUS_INVALID_PATH_ID
);
1966 if (Srb
->TargetId
> 1)
1968 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1969 return(SRB_STATUS_INVALID_TARGET_ID
);
1974 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1975 return(SRB_STATUS_INVALID_LUN
);
1978 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1980 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1981 return(SRB_STATUS_NO_DEVICE
);
1984 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1985 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1987 /* Set sector (block) size to 512 bytes (big-endian). */
1988 CapacityData
->BytesPerBlock
= 0x20000;
1990 /* Calculate last sector (big-endian). */
1991 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1993 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1994 DeviceParams
->TMSectorCountLo
) - 1;
1998 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1999 DeviceParams
->LogicalHeads
*
2000 DeviceParams
->SectorsPerTrack
)-1;
2003 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
2004 (((PUCHAR
)&LastSector
)[1] << 16) |
2005 (((PUCHAR
)&LastSector
)[2] << 8) |
2006 ((PUCHAR
)&LastSector
)[3];
2008 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
2011 CapacityData
->LogicalBlockAddress
);
2013 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2014 return(SRB_STATUS_SUCCESS
);
2019 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2020 PSCSI_REQUEST_BLOCK Srb
)
2022 PIDE_DRIVE_IDENTIFY DeviceParams
;
2023 ULONG StartingSector
;
2033 DPRINT("AtapiReadWrite() called!\n");
2035 if (Srb
->PathId
!= 0)
2037 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
2038 return(SRB_STATUS_INVALID_PATH_ID
);
2041 if (Srb
->TargetId
> 1)
2043 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2044 return(SRB_STATUS_INVALID_TARGET_ID
);
2049 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2050 return(SRB_STATUS_INVALID_LUN
);
2053 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
2055 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2056 return(SRB_STATUS_NO_DEVICE
);
2059 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2062 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2064 /* Get starting sector number from CDB. */
2065 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2066 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2067 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2068 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2070 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2071 DeviceParams
->BytesPerSector
;
2073 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2075 Srb
->DataTransferLength
,
2078 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2080 SectorNumber
= StartingSector
& 0xff;
2081 CylinderLow
= (StartingSector
>> 8) & 0xff;
2082 CylinderHigh
= (StartingSector
>> 16) & 0xff;
2083 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2084 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2089 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2090 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2091 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2092 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2093 StartingSector
/= DeviceParams
->LogicalHeads
;
2094 CylinderLow
= StartingSector
& 0xff;
2095 CylinderHigh
= StartingSector
>> 8;
2099 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2101 Command
= (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
) ? IDE_CMD_READ_MULTIPLE
: IDE_CMD_READ
;
2105 Command
= (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
) ? IDE_CMD_WRITE_MULTIPLE
: IDE_CMD_WRITE
;
2108 if (DrvHead
& IDE_DH_LBA
)
2110 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2111 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2112 DeviceExtension
->CommandPortBase
,
2113 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2114 ((DrvHead
& 0x0f) << 24) +
2115 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
2121 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2122 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2123 DeviceExtension
->CommandPortBase
,
2124 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2133 /* Set pointer to data buffer. */
2134 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2135 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2137 DeviceExtension
->CurrentSrb
= Srb
;
2139 /* wait for BUSY to clear */
2140 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2142 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2143 if (!(Status
& IDE_SR_BUSY
))
2147 ScsiPortStallExecution(10);
2149 DPRINT("status=%02x\n", Status
);
2150 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2151 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2153 DPRINT ("Drive is BUSY for too long\n");
2154 return(SRB_STATUS_BUSY
);
2157 /* Select the desired drive */
2158 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2159 IDE_DH_FIXED
| DrvHead
);
2161 ScsiPortStallExecution(10);
2163 /* wait for BUSY to clear and DRDY to assert */
2164 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2166 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2167 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2171 ScsiPortStallExecution(10);
2173 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2174 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2176 DPRINT("Drive is BUSY for too long after drive select\n");
2177 return(SRB_STATUS_BUSY
);
2181 /* Setup command parameters */
2182 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2183 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
2184 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
2185 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
2186 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
2187 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2189 /* Indicate expecting an interrupt. */
2190 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2192 /* Issue command to drive */
2193 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
2195 /* Write data block */
2196 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2198 PUCHAR TargetAddress
;
2201 /* Wait for controller ready */
2202 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2204 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2205 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2209 KeStallExecutionProcessor(10);
2211 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2213 DPRINT1("Drive is BUSY for too long after sending write command\n");
2214 return(SRB_STATUS_BUSY
);
2217 /* Update DeviceExtension data */
2218 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2219 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2221 TransferSize
= DeviceExtension
->DataTransferLength
;
2224 TargetAddress
= DeviceExtension
->DataBuffer
;
2225 DeviceExtension
->DataBuffer
+= TransferSize
;
2226 DeviceExtension
->DataTransferLength
-= TransferSize
;
2228 /* Write data block */
2229 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2231 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2237 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2243 DPRINT("AtapiReadWrite() done!\n");
2245 /* Wait for interrupt. */
2246 return(SRB_STATUS_PENDING
);
2251 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2252 PSCSI_REQUEST_BLOCK Srb
)
2257 DPRINT1("AtapiFlushCache() called!\n");
2259 if (Srb
->PathId
!= 0)
2261 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
2262 return(SRB_STATUS_INVALID_PATH_ID
);
2265 if (Srb
->TargetId
> 1)
2267 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2268 return(SRB_STATUS_INVALID_TARGET_ID
);
2273 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2274 return(SRB_STATUS_INVALID_LUN
);
2277 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
2279 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2280 return(SRB_STATUS_NO_DEVICE
);
2283 DPRINT1("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2286 /* Wait for BUSY to clear */
2287 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2289 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2290 if (!(Status
& IDE_SR_BUSY
))
2294 ScsiPortStallExecution(10);
2296 DPRINT1("Status=%02x\n", Status
);
2297 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2298 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2300 DPRINT1("Drive is BUSY for too long\n");
2301 return(SRB_STATUS_BUSY
);
2304 /* Select the desired drive */
2305 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2306 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2307 ScsiPortStallExecution(10);
2309 /* Issue command to drive */
2310 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_FLUSH_CACHE
);
2312 /* Wait for controller ready */
2313 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2315 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2316 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2320 KeStallExecutionProcessor(10);
2322 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2324 DPRINT1("Drive is BUSY for too long after sending write command\n");
2325 return(SRB_STATUS_BUSY
);
2328 /* Indicate expecting an interrupt. */
2329 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2331 DPRINT1("AtapiFlushCache() done!\n");
2333 /* Wait for interrupt. */
2334 return(SRB_STATUS_PENDING
);
2339 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2340 PSCSI_REQUEST_BLOCK Srb
)
2346 DPRINT1("AtapiTestUnitReady() called!\n");
2348 if (Srb
->PathId
!= 0)
2350 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
2351 return(SRB_STATUS_INVALID_PATH_ID
);
2354 if (Srb
->TargetId
> 1)
2356 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
2357 return(SRB_STATUS_INVALID_TARGET_ID
);
2362 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
2363 return(SRB_STATUS_INVALID_LUN
);
2366 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
2368 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
2369 return(SRB_STATUS_NO_DEVICE
);
2372 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2375 /* Return success if media status is not supported */
2376 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2378 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2379 return(SRB_STATUS_SUCCESS
);
2382 /* Wait for BUSY to clear */
2383 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2385 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2386 if (!(Status
& IDE_SR_BUSY
))
2390 ScsiPortStallExecution(10);
2392 DPRINT1("Status=%02x\n", Status
);
2393 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2394 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2396 DPRINT1("Drive is BUSY for too long\n");
2397 return(SRB_STATUS_BUSY
);
2400 /* Select the desired drive */
2401 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2402 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2403 ScsiPortStallExecution(10);
2405 /* Issue command to drive */
2406 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_GET_MEDIA_STATUS
);
2408 /* Wait for controller ready */
2409 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2411 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2412 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2416 KeStallExecutionProcessor(10);
2418 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2420 DPRINT1("Drive is BUSY for too long after sending write command\n");
2421 return(SRB_STATUS_BUSY
);
2424 if (Status
& IDE_SR_ERR
)
2426 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2427 if (Error
== IDE_ER_UNC
)
2429 /* Handle write protection 'error' */
2430 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2431 return(SRB_STATUS_SUCCESS
);
2435 /* Indicate expecting an interrupt. */
2436 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2437 return(SRB_STATUS_PENDING
);
2441 DPRINT1("AtapiTestUnitReady() done!\n");
2443 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2444 return(SRB_STATUS_SUCCESS
);
2449 AtapiErrorToScsi(PVOID DeviceExtension
,
2450 PSCSI_REQUEST_BLOCK Srb
)
2452 PATAPI_MINIPORT_EXTENSION DevExt
;
2453 ULONG CommandPortBase
;
2454 ULONG ControlPortBase
;
2459 DPRINT("AtapiErrorToScsi() called\n");
2461 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2463 CommandPortBase
= DevExt
->CommandPortBase
;
2464 ControlPortBase
= DevExt
->ControlPortBase
;
2466 ErrorReg
= IDEReadError(CommandPortBase
);
2468 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2470 switch (ErrorReg
>> 4)
2472 case SCSI_SENSE_NO_SENSE
:
2473 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2474 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2475 SrbStatus
= SRB_STATUS_ERROR
;
2478 case SCSI_SENSE_RECOVERED_ERROR
:
2479 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2481 SrbStatus
= SRB_STATUS_SUCCESS
;
2484 case SCSI_SENSE_NOT_READY
:
2485 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2486 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2487 SrbStatus
= SRB_STATUS_ERROR
;
2490 case SCSI_SENSE_MEDIUM_ERROR
:
2491 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2492 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2493 SrbStatus
= SRB_STATUS_ERROR
;
2496 case SCSI_SENSE_HARDWARE_ERROR
:
2497 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2498 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2499 SrbStatus
= SRB_STATUS_ERROR
;
2502 case SCSI_SENSE_ILLEGAL_REQUEST
:
2503 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2504 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2505 SrbStatus
= SRB_STATUS_ERROR
;
2508 case SCSI_SENSE_UNIT_ATTENTION
:
2509 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2510 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2511 SrbStatus
= SRB_STATUS_ERROR
;
2514 case SCSI_SENSE_DATA_PROTECT
:
2515 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2516 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2517 SrbStatus
= SRB_STATUS_ERROR
;
2520 case SCSI_SENSE_BLANK_CHECK
:
2521 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2522 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2523 SrbStatus
= SRB_STATUS_ERROR
;
2526 case SCSI_SENSE_ABORTED_COMMAND
:
2527 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2528 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2529 SrbStatus
= SRB_STATUS_ERROR
;
2533 DPRINT("ATAPI error: Invalid sense key\n");
2535 SrbStatus
= SRB_STATUS_ERROR
;
2541 DPRINT1("IDE error: %02x\n", ErrorReg
);
2544 SrbStatus
= SRB_STATUS_ERROR
;
2547 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2550 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2551 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2552 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2553 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2554 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2556 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2567 Srb
->ScsiStatus
= ScsiStatus
;
2569 DPRINT("AtapiErrorToScsi() done\n");