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.45 2003/11/13 14:17:51 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 AtapiPolledRead(IN ULONG CommandPort
,
204 IN ULONG ControlPort
,
208 IN UCHAR CylinderLow
,
209 IN UCHAR CylinderHigh
,
215 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
216 IN PSCSI_REQUEST_BLOCK Srb
);
219 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
220 IN PSCSI_REQUEST_BLOCK Srb
);
223 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
224 IN PSCSI_REQUEST_BLOCK Srb
);
227 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
228 IN PSCSI_REQUEST_BLOCK Srb
);
231 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
232 IN PSCSI_REQUEST_BLOCK Srb
);
235 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
236 PSCSI_REQUEST_BLOCK Srb
);
239 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
240 PSCSI_REQUEST_BLOCK Srb
);
243 AtapiErrorToScsi(PVOID DeviceExtension
,
244 PSCSI_REQUEST_BLOCK Srb
);
247 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
);
249 // ---------------------------------------------------------------- Inlines
252 IDESwapBytePairs(char *Buf
,
258 for (i
= 0; i
< Cnt
; i
+= 2)
267 // ------------------------------------------------------- Public Interface
272 // This function initializes the driver, locates and claims
273 // hardware resources, and creates various NT objects needed
274 // to process I/O requests.
280 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
282 // IN PUNICODE_STRING RegistryPath Name of registry driver service
289 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
290 IN PUNICODE_STRING RegistryPath
)
292 HW_INITIALIZATION_DATA InitData
;
295 DPRINT("ATAPI Driver %s\n", VERSION
);
296 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
298 /* Initialize data structure */
299 RtlZeroMemory(&InitData
,
300 sizeof(HW_INITIALIZATION_DATA
));
301 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
302 InitData
.HwInitialize
= AtapiInitialize
;
303 InitData
.HwResetBus
= AtapiResetBus
;
304 InitData
.HwStartIo
= AtapiStartIo
;
305 InitData
.HwInterrupt
= AtapiInterrupt
;
307 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
308 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
310 InitData
.MapBuffers
= TRUE
;
313 /* Search the PCI bus for compatibility mode ide controllers */
315 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
316 InitData
.NumberOfAccessRanges
= 3;
317 InitData
.AdapterInterfaceType
= PCIBus
;
319 InitData
.VendorId
= NULL
;
320 InitData
.VendorIdLength
= 0;
321 InitData
.DeviceId
= NULL
;
322 InitData
.DeviceIdLength
= 0;
324 Status
= ScsiPortInitialize(DriverObject
,
328 // if (newStatus < statusToReturn)
329 // statusToReturn = newStatus;
332 /* Search the PCI bus for all ide controllers */
333 #ifdef ENABLE_NATIVE_PCI
335 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
336 InitData
.NumberOfAccessRanges
= 3;
337 InitData
.AdapterInterfaceType
= PCIBus
;
339 InitData
.VendorId
= 0;
340 InitData
.VendorIdLength
= 0;
341 InitData
.DeviceId
= 0;
342 InitData
.DeviceIdLength
= 0;
344 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
346 Status
= ScsiPortInitialize(DriverObject
,
350 // if (newStatus < statusToReturn)
351 // statusToReturn = newStatus;
354 /* Search the ISA bus for ide controllers */
356 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
357 InitData
.NumberOfAccessRanges
= 2;
358 InitData
.AdapterInterfaceType
= Isa
;
360 InitData
.VendorId
= NULL
;
361 InitData
.VendorIdLength
= 0;
362 InitData
.DeviceId
= NULL
;
363 InitData
.DeviceIdLength
= 0;
365 Status
= ScsiPortInitialize(DriverObject
,
369 // if (newStatus < statusToReturn)
370 // statusToReturn = newStatus;
373 DPRINT("Returning from DriverEntry\n");
380 AtapiClaimHwResources(PATAPI_MINIPORT_EXTENSION DevExt
,
381 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
382 INTERFACE_TYPE InterfaceType
,
383 ULONG CommandPortBase
,
384 ULONG ControlPortBase
,
385 ULONG BusMasterPortBase
,
386 ULONG InterruptVector
)
388 SCSI_PHYSICAL_ADDRESS IoAddress
;
391 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(CommandPortBase
);
392 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
394 ConfigInfo
->SystemIoBusNumber
,
402 DevExt
->CommandPortBase
= (ULONG
)IoBase
;
403 ConfigInfo
->AccessRanges
[0].RangeStart
= IoAddress
;
404 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
405 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
409 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(ControlPortBase
+ 2);
410 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
412 ConfigInfo
->SystemIoBusNumber
,
418 ScsiPortFreeDeviceBase((PVOID
)DevExt
,
419 (PVOID
)DevExt
->CommandPortBase
);
422 DevExt
->ControlPortBase
= (ULONG
)IoBase
;
423 ConfigInfo
->AccessRanges
[1].RangeStart
= IoAddress
;
424 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
425 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
427 if (BusMasterPortBase
)
429 IoAddress
= ScsiPortConvertUlongToPhysicalAddress(BusMasterPortBase
);
430 IoBase
= ScsiPortGetDeviceBase((PVOID
)DevExt
,
432 ConfigInfo
->SystemIoBusNumber
,
438 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->CommandPortBase
);
439 ScsiPortFreeDeviceBase((PVOID
)DevExt
, (PVOID
)DevExt
->ControlPortBase
);
442 ConfigInfo
->AccessRanges
[2].RangeStart
= IoAddress
;
443 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
444 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
446 ConfigInfo
->BusInterruptLevel
= InterruptVector
;
447 ConfigInfo
->BusInterruptVector
= InterruptVector
;
448 ConfigInfo
->InterruptMode
= (InterfaceType
== Isa
) ? Latched
: LevelSensitive
;
450 if ((CommandPortBase
== 0x1F0 || ControlPortBase
== 0x3F4) && !ConfigInfo
->AtdiskPrimaryClaimed
)
452 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
454 if ((CommandPortBase
== 0x170 || ControlPortBase
== 0x374) && !ConfigInfo
->AtdiskSecondaryClaimed
)
456 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
464 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
466 PVOID BusInformation
,
467 PCHAR ArgumentString
,
468 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
471 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
472 PCI_SLOT_NUMBER SlotNumber
;
473 PCI_COMMON_CONFIG PciConfig
;
475 ULONG StartDeviceNumber
;
477 ULONG StartFunctionNumber
;
478 ULONG FunctionNumber
;
479 BOOLEAN ChannelFound
;
481 ULONG BusMasterBasePort
= 0;
483 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
484 ConfigInfo
->SystemIoBusNumber
,
485 ConfigInfo
->SlotNumber
);
489 /* both channels were claimed: exit */
490 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
491 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
492 return(SP_RETURN_NOT_FOUND
);
494 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
495 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
496 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
497 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
499 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
500 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
502 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
503 ChannelFound
= FALSE
;
506 DataSize
= ScsiPortGetBusData(DeviceExtension
,
508 ConfigInfo
->SystemIoBusNumber
,
509 SlotNumber
.u
.AsULONG
,
511 PCI_COMMON_HDR_LENGTH
);
512 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
514 if (FunctionNumber
== 0)
524 DPRINT("%x %x\n", PciConfig
.BaseClass
, PciConfig
.SubClass
);
525 if (PciConfig
.BaseClass
== 0x01 &&
526 PciConfig
.SubClass
== 0x01) // &&
527 // (PciConfig.ProgIf & 0x05) == 0)
529 /* both channels are in compatibility mode */
530 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
531 ConfigInfo
->SystemIoBusNumber
,
532 SlotNumber
.u
.bits
.DeviceNumber
,
533 SlotNumber
.u
.bits
.FunctionNumber
,
536 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
538 DPRINT("Found IDE controller in compatibility mode!\n");
540 ConfigInfo
->NumberOfBuses
= 1;
541 ConfigInfo
->MaximumNumberOfTargets
= 2;
542 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
544 if (PciConfig
.ProgIf
& 0x80)
546 DPRINT("Found IDE Bus Master controller!\n");
547 if (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
)
549 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
550 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
553 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
555 /* Both channels unclaimed: Claim primary channel */
556 DPRINT("Primary channel!\n");
557 ChannelFound
= AtapiClaimHwResources(DevExt
,
566 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
568 /* Primary channel already claimed: claim secondary channel */
569 DPRINT("Secondary channel!\n");
571 ChannelFound
= AtapiClaimHwResources(DevExt
,
576 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
580 /* Find attached devices */
583 DeviceFound
= AtapiFindDevices(DevExt
, ConfigInfo
);
584 ConfigInfo
->SlotNumber
= SlotNumber
.u
.AsULONG
;
585 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
586 return(SP_RETURN_FOUND
);
589 if (FunctionNumber
== 0 && !(PciConfig
.HeaderType
& PCI_MULTIFUNCTION
))
594 StartFunctionNumber
= 0;
596 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
598 return(SP_RETURN_NOT_FOUND
);
605 AtapiFindIsaBusController(PVOID DeviceExtension
,
607 PVOID BusInformation
,
608 PCHAR ArgumentString
,
609 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
612 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
613 BOOLEAN ChannelFound
= FALSE
;
614 BOOLEAN DeviceFound
= FALSE
;
616 DPRINT("AtapiFindIsaBusController() called!\n");
620 ConfigInfo
->NumberOfBuses
= 1;
621 ConfigInfo
->MaximumNumberOfTargets
= 2;
622 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
624 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
626 /* Both channels unclaimed: Claim primary channel */
627 DPRINT("Primary channel!\n");
629 ChannelFound
= AtapiClaimHwResources(DevExt
,
638 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
640 /* Primary channel already claimed: claim secondary channel */
641 DPRINT("Secondary channel!\n");
643 ChannelFound
= AtapiClaimHwResources(DevExt
,
654 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
656 return(SP_RETURN_NOT_FOUND
);
659 /* Find attached devices */
662 DeviceFound
= AtapiFindDevices(DevExt
,
664 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
665 return(SP_RETURN_FOUND
);
668 return SP_RETURN_NOT_FOUND
;
673 #ifdef ENABLE_NATIVE_PCI
675 AtapiFindNativePciController(PVOID DeviceExtension
,
677 PVOID BusInformation
,
678 PCHAR ArgumentString
,
679 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
682 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
683 PCI_COMMON_CONFIG PciConfig
;
684 PCI_SLOT_NUMBER SlotNumber
;
687 ULONG StartDeviceNumber
;
688 ULONG FunctionNumber
;
689 ULONG StartFunctionNumber
;
690 ULONG BusMasterBasePort
;
692 BOOLEAN ChannelFound
;
694 DPRINT("AtapiFindNativePciController() called!\n");
696 SlotNumber
.u
.AsULONG
= ConfigInfo
->SlotNumber
;
697 StartDeviceNumber
= SlotNumber
.u
.bits
.DeviceNumber
;
698 StartFunctionNumber
= SlotNumber
.u
.bits
.FunctionNumber
;
699 for (DeviceNumber
= StartDeviceNumber
; DeviceNumber
< PCI_MAX_DEVICES
; DeviceNumber
++)
701 SlotNumber
.u
.bits
.DeviceNumber
= DeviceNumber
;
702 for (FunctionNumber
= StartFunctionNumber
; FunctionNumber
< PCI_MAX_FUNCTION
; FunctionNumber
++)
704 SlotNumber
.u
.bits
.FunctionNumber
= FunctionNumber
;
705 DataSize
= ScsiPortGetBusData(DeviceExtension
,
707 ConfigInfo
->SystemIoBusNumber
,
708 SlotNumber
.u
.AsULONG
,
710 PCI_COMMON_HDR_LENGTH
);
711 if (DataSize
!= PCI_COMMON_HDR_LENGTH
)
715 for (Count
= 0; Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
); Count
++)
717 if (PciConfig
.VendorID
== PciNativeController
[Count
].VendorID
&&
718 PciConfig
.DeviceID
== PciNativeController
[Count
].DeviceID
)
723 if (Count
< sizeof(PciNativeController
)/sizeof(PCI_NATIVE_CONTROLLER
))
725 /* We have found a known native pci ide controller */
726 if ((PciConfig
.ProgIf
& 0x80) && (PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_SPACE
))
728 DPRINT("Found IDE Bus Master controller!\n");
729 BusMasterBasePort
= PciConfig
.u
.type0
.BaseAddresses
[4] & PCI_ADDRESS_IO_ADDRESS_MASK
;
730 DPRINT(" IDE Bus Master Registers at IO %lx\n", BusMasterBasePort
);
734 BusMasterBasePort
= 0;
737 DPRINT("VendorID: %04x, DeviceID: %04x\n", PciConfig
.VendorID
, PciConfig
.DeviceID
);
738 ConfigInfo
->NumberOfBuses
= 1;
739 ConfigInfo
->MaximumNumberOfTargets
= 2;
740 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
743 We must not store and use the last tested slot number. If there is a recall
744 to the some device and we will claim the primary channel again than the call
745 to ScsiPortGetDeviceBase in AtapiClaimHwResource will fail and we can try to
746 claim the secondary channel.
748 ChannelFound
= FALSE
;
749 if (LastSlotNumber
.u
.AsULONG
!= SlotNumber
.u
.AsULONG
)
751 /* try to claim primary channel */
752 if ((PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_SPACE
) &&
753 (PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_SPACE
))
755 /* primary channel is enabled */
756 ChannelFound
= AtapiClaimHwResources(DevExt
,
759 PciConfig
.u
.type0
.BaseAddresses
[0] & PCI_ADDRESS_IO_ADDRESS_MASK
,
760 PciConfig
.u
.type0
.BaseAddresses
[1] & PCI_ADDRESS_IO_ADDRESS_MASK
,
762 PciConfig
.u
.type0
.InterruptLine
);
765 AtapiFindDevices(DevExt
, ConfigInfo
);
767 ConfigInfo
->SlotNumber
= LastSlotNumber
.u
.AsULONG
= SlotNumber
.u
.AsULONG
;
768 return SP_RETURN_FOUND
;
774 /* try to claim secondary channel */
775 if ((PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_SPACE
) &&
776 (PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_SPACE
))
778 /* secondary channel is enabled */
779 ChannelFound
= AtapiClaimHwResources(DevExt
,
782 PciConfig
.u
.type0
.BaseAddresses
[2] & PCI_ADDRESS_IO_ADDRESS_MASK
,
783 PciConfig
.u
.type0
.BaseAddresses
[3] & PCI_ADDRESS_IO_ADDRESS_MASK
,
784 BusMasterBasePort
? BusMasterBasePort
+ 8 : 0,
785 PciConfig
.u
.type0
.InterruptLine
);
788 AtapiFindDevices(DevExt
, ConfigInfo
);
790 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
791 return SP_RETURN_FOUND
;
797 StartFunctionNumber
= 0;
800 LastSlotNumber
.u
.AsULONG
= 0xFFFFFFFF;
801 DPRINT("AtapiFindNativePciController() done!\n");
803 return(SP_RETURN_NOT_FOUND
);
808 static BOOLEAN STDCALL
809 AtapiInitialize(IN PVOID DeviceExtension
)
815 static BOOLEAN STDCALL
816 AtapiResetBus(IN PVOID DeviceExtension
,
823 static BOOLEAN STDCALL
824 AtapiStartIo(IN PVOID DeviceExtension
,
825 IN PSCSI_REQUEST_BLOCK Srb
)
827 PATAPI_MINIPORT_EXTENSION DevExt
;
830 DPRINT("AtapiStartIo() called\n");
832 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
834 switch (Srb
->Function
)
836 case SRB_FUNCTION_EXECUTE_SCSI
:
837 DevExt
->CurrentSrb
= Srb
;
838 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
840 Result
= AtapiSendAtapiCommand(DevExt
,
845 Result
= AtapiSendIdeCommand(DevExt
,
850 case SRB_FUNCTION_ABORT_COMMAND
:
851 if (DevExt
->CurrentSrb
!= NULL
)
853 Result
= SRB_STATUS_ABORT_FAILED
;
857 Result
= SRB_STATUS_SUCCESS
;
862 Result
= SRB_STATUS_INVALID_REQUEST
;
866 Srb
->SrbStatus
= Result
;
869 if (Result
!= SRB_STATUS_PENDING
)
871 DevExt
->CurrentSrb
= NULL
;
872 Srb
->SrbStatus
= (UCHAR
)Result
;
874 ScsiPortNotification(RequestComplete
,
877 ScsiPortNotification(NextRequest
,
883 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
886 DPRINT("AtapiStartIo() done\n");
892 static BOOLEAN STDCALL
893 AtapiInterrupt(IN PVOID DeviceExtension
)
895 PATAPI_MINIPORT_EXTENSION DevExt
;
896 PSCSI_REQUEST_BLOCK Srb
;
897 ULONG CommandPortBase
;
898 ULONG ControlPortBase
;
903 PUCHAR TargetAddress
;
908 DPRINT("AtapiInterrupt() called!\n");
910 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
912 CommandPortBase
= DevExt
->CommandPortBase
;
913 ControlPortBase
= DevExt
->ControlPortBase
;
915 if (DevExt
->ExpectingInterrupt
== FALSE
)
917 DeviceStatus
= IDEReadStatus(CommandPortBase
);
918 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase
);
922 /* check if it was our irq */
923 if ((DeviceStatus
= IDEReadAltStatus(ControlPortBase
)) & IDE_SR_BUSY
)
925 ScsiPortStallExecution(1);
926 if ((DeviceStatus
= IDEReadAltStatus(ControlPortBase
) & IDE_SR_BUSY
))
928 DPRINT("AtapiInterrupt(): Unexpected interrupt (port=%x)\n", CommandPortBase
);
933 Srb
= DevExt
->CurrentSrb
;
934 DPRINT("Srb: %p\n", Srb
);
936 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
938 IsAtapi
= (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
);
939 DPRINT("IsAtapi == %s\n", (IsAtapi
) ? "TRUE" : "FALSE");
943 DeviceStatus
= IDEReadStatus(CommandPortBase
);
944 DPRINT("DeviceStatus: %x\n", DeviceStatus
);
946 if ((DeviceStatus
& IDE_SR_ERR
) &&
947 (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
))
949 /* Report error condition */
950 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
955 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
957 DPRINT("Read data\n");
959 /* Update controller/device state variables */
960 TargetAddress
= DevExt
->DataBuffer
;
964 TransferSize
= IDEReadCylinderLow(CommandPortBase
);
965 TransferSize
+= IDEReadCylinderHigh(CommandPortBase
) << 8;
969 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
972 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
973 DPRINT("TransferSize: %lu\n", TransferSize
);
975 if (DevExt
->DataTransferLength
<= TransferSize
)
977 JunkSize
= TransferSize
- DevExt
->DataTransferLength
;
978 TransferSize
= DevExt
->DataTransferLength
;
983 DPRINT1("Junk data: %lu bytes\n", JunkSize
);
987 DevExt
->DataTransferLength
= 0;
992 DevExt
->DataTransferLength
-= TransferSize
;
995 DevExt
->DataBuffer
+= TransferSize
;
996 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
998 /* Wait for DRQ assertion */
999 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
1000 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
1003 KeStallExecutionProcessor(10);
1006 /* Copy the block of data */
1007 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
1009 IDEReadBlock32(CommandPortBase
,
1015 IDEReadBlock(CommandPortBase
,
1023 /* Read remaining junk from device */
1024 while (JunkSize
> 0)
1026 IDEReadBlock(CommandPortBase
,
1032 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
1033 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
1036 KeStallExecutionProcessor(10);
1039 /* Check for data overrun */
1040 while (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
1042 DPRINT1("AtapiInterrupt(): reading overrun data!\n");
1043 IDEReadWord(CommandPortBase
);
1047 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1049 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
1051 DPRINT("Write data\n");
1053 if (DevExt
->DataTransferLength
== 0)
1055 /* Check for data overrun */
1056 if (DeviceStatus
& IDE_SR_DRQ
)
1058 /* FIXME: Handle error! */
1059 /* This can occure if the irq is shared with an other and if the
1060 ide controller has a write buffer. We have write the last sectors
1061 and the other device has a irq before ours. The isr is called but
1062 we haven't a interrupt. The controller writes the sector buffer
1063 and the status register shows DRQ because the write is not ended. */
1064 DPRINT("AtapiInterrupt(): data overrun error!\n");
1070 /* Update DevExt data */
1071 TransferSize
= DevExt
->TransferSize
[Srb
->TargetId
];
1072 if (DevExt
->DataTransferLength
< TransferSize
)
1074 TransferSize
= DevExt
->DataTransferLength
;
1077 TargetAddress
= DevExt
->DataBuffer
;
1078 DevExt
->DataBuffer
+= TransferSize
;
1079 DevExt
->DataTransferLength
-= TransferSize
;
1081 /* Write the sector */
1082 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
1084 IDEWriteBlock32(CommandPortBase
,
1090 IDEWriteBlock(CommandPortBase
,
1096 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1100 DPRINT("Unspecified transfer direction!\n");
1101 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1107 if (Srb
->SrbStatus
== SRB_STATUS_ERROR
)
1109 Srb
->SrbStatus
= AtapiErrorToScsi(DeviceExtension
,
1114 /* complete this packet */
1117 DevExt
->ExpectingInterrupt
= FALSE
;
1119 ScsiPortNotification(RequestComplete
,
1123 ScsiPortNotification(NextRequest
,
1128 DPRINT("AtapiInterrupt() done!\n");
1133 // ---------------------------------------------------- Discardable statics
1136 /**********************************************************************
1141 * Searches for devices on the given port.
1148 * Port device specific information.
1151 * Port configuration information.
1154 * TRUE: At least one device is attached to the port.
1155 * FALSE: No device is attached to the port.
1159 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1160 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
1162 BOOLEAN DeviceFound
= FALSE
;
1163 ULONG CommandPortBase
;
1164 ULONG ControlPortBase
;
1170 DPRINT("AtapiFindDevices() called\n");
1172 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
1173 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
1175 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
1176 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
1178 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
1181 IDEWriteDriveHead(CommandPortBase
,
1182 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
1183 ScsiPortStallExecution(500);
1185 /* Disable interrupts */
1186 IDEWriteDriveControl(ControlPortBase
,
1188 ScsiPortStallExecution(500);
1190 /* Check if a device is attached to the interface */
1191 IDEWriteCylinderHigh(CommandPortBase
, 0xaa);
1192 IDEWriteCylinderLow(CommandPortBase
, 0x55);
1194 High
= IDEReadCylinderHigh(CommandPortBase
);
1195 Low
= IDEReadCylinderLow(CommandPortBase
);
1197 IDEWriteCylinderHigh(CommandPortBase
, 0);
1198 IDEWriteCylinderLow(CommandPortBase
, 0);
1200 if (Low
!= 0x55 || High
!= 0xaa)
1202 DPRINT("No Drive found. UnitNumber %d CommandPortBase %x\n", UnitNumber
, CommandPortBase
);
1206 IDEWriteCommand(CommandPortBase
, IDE_CMD_RESET
);
1208 for (Retries
= 0; Retries
< 20000; Retries
++)
1210 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1214 ScsiPortStallExecution(150);
1216 if (Retries
>= 20000)
1218 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1219 DeviceExtension
->DeviceFlags
[UnitNumber
] &= ~DEVICE_PRESENT
;
1223 High
= IDEReadCylinderHigh(CommandPortBase
);
1224 Low
= IDEReadCylinderLow(CommandPortBase
);
1226 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1231 if (High
== 0xEB && Low
== 0x14)
1233 if (AtapiIdentifyDevice(CommandPortBase
,
1237 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1239 DPRINT(" ATAPI drive found!\n");
1240 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1241 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_ATAPI
;
1242 DeviceExtension
->TransferSize
[UnitNumber
] =
1243 DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1248 DPRINT(" No ATAPI drive found!\n");
1253 if (AtapiIdentifyDevice(CommandPortBase
,
1257 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1259 DPRINT(" IDE drive found!\n");
1260 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_PRESENT
;
1261 DeviceExtension
->TransferSize
[UnitNumber
] = DeviceExtension
->DeviceParams
[UnitNumber
].BytesPerSector
;
1262 if ((DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0x8000) &&
1263 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultImplemented
& 0xff) &&
1264 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0x100) &&
1265 (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff))
1267 DeviceExtension
->TransferSize
[UnitNumber
] *= (DeviceExtension
->DeviceParams
[UnitNumber
].RWMultCurrent
& 0xff);
1268 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_MULTI_SECTOR_CMD
;
1271 if (DeviceExtension
->DeviceParams
[UnitNumber
].DWordIo
)
1273 DeviceExtension
->DeviceFlags
[UnitNumber
] |= DEVICE_DWORD_IO
;
1280 DPRINT(" No IDE drive found!\n");
1285 /* Reset pending interrupts */
1286 IDEReadStatus(CommandPortBase
);
1287 /* Reenable interrupts */
1288 IDEWriteDriveControl(ControlPortBase
, 0);
1289 ScsiPortStallExecution(500);
1290 /* Return with drive 0 selected */
1291 IDEWriteDriveHead(CommandPortBase
, IDE_DH_FIXED
);
1292 ScsiPortStallExecution(500);
1294 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1296 return(DeviceFound
);
1301 * AtapiIdentifyDevice
1304 * Get the identification block from the drive
1311 * Address of the command port
1313 * Address of the control port
1315 * The drive index (0,1)
1317 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1319 * Address to write drive ident block
1322 * TRUE: The drive identification block was retrieved successfully
1323 * FALSE: an error ocurred
1327 AtapiIdentifyDevice(IN ULONG CommandPort
,
1328 IN ULONG ControlPort
,
1331 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1335 /* Get the Drive Identify block from drive or die */
1336 if (AtapiPolledRead(CommandPort
,
1343 (DriveNum
? IDE_DH_DRV1
: 0),
1344 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1345 (PUCHAR
)DrvParms
) == FALSE
)
1347 DPRINT("IDEPolledRead() failed\n");
1351 /* Report on drive parameters if debug mode */
1352 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1353 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1354 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1355 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1356 DrvParms
->ConfigBits
,
1357 DrvParms
->LogicalCyls
,
1358 DrvParms
->LogicalHeads
,
1359 DrvParms
->SectorsPerTrack
,
1360 DrvParms
->InterSectorGap
,
1361 DrvParms
->InterSectorGapSize
);
1362 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1363 DrvParms
->BytesInPLO
,
1364 DrvParms
->VendorUniqueCnt
,
1365 DrvParms
->SerialNumber
);
1366 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1367 DrvParms
->ControllerType
,
1368 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1369 DrvParms
->ECCByteCnt
,
1370 DrvParms
->FirmwareRev
);
1371 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1372 DPRINT("RWMultMax?:%04x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1373 (DrvParms
->RWMultImplemented
),
1374 (DrvParms
->RWMultCurrent
) & 0xff,
1375 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1376 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1377 DrvParms
->MinPIOTransTime
,
1378 DrvParms
->MinDMATransTime
);
1379 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1380 DrvParms
->TMCylinders
,
1382 DrvParms
->TMSectorsPerTrk
,
1383 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1384 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1385 DrvParms
->TMSectorCountHi
,
1386 DrvParms
->TMSectorCountLo
,
1387 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1389 if (! Atapi
&& 0 != (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
))
1391 /* LBA ATA drives always have a sector size of 512 */
1392 DrvParms
->BytesPerSector
= 512;
1396 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1397 if (DrvParms
->BytesPerSector
== 0)
1399 DrvParms
->BytesPerSector
= 512;
1403 for (i
= 15; i
>= 0; i
--)
1405 if (DrvParms
->BytesPerSector
& (1 << i
))
1407 DrvParms
->BytesPerSector
= 1 << i
;
1413 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1422 // Read a sector of data from the drive in a polled fashion.
1428 // IN ULONG CommandPort Address of command port for drive
1429 // IN ULONG ControlPort Address of control port for drive
1430 // IN UCHAR PreComp Value to write to precomp register
1431 // IN UCHAR SectorCnt Value to write to sectorCnt register
1432 // IN UCHAR SectorNum Value to write to sectorNum register
1433 // IN UCHAR CylinderLow Value to write to CylinderLow register
1434 // IN UCHAR CylinderHigh Value to write to CylinderHigh register
1435 // IN UCHAR DrvHead Value to write to Drive/Head register
1436 // IN UCHAR Command Value to write to Command register
1437 // OUT PUCHAR Buffer Buffer for output data
1440 // BOOLEAN: TRUE success, FALSE error
1444 AtapiPolledRead(IN ULONG CommandPort
,
1445 IN ULONG ControlPort
,
1449 IN UCHAR CylinderLow
,
1450 IN UCHAR CylinderHigh
,
1455 ULONG SectorCount
= 0;
1457 BOOLEAN Junk
= FALSE
;
1460 /* Wait for BUSY to clear */
1461 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1463 Status
= IDEReadStatus(CommandPort
);
1464 if (!(Status
& IDE_SR_BUSY
))
1468 ScsiPortStallExecution(10);
1470 DPRINT("status=%02x\n", Status
);
1471 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1472 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1474 DPRINT("Drive is BUSY for too long\n");
1478 /* Write Drive/Head to select drive */
1479 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1480 ScsiPortStallExecution(500);
1482 /* Disable interrupts */
1483 IDEWriteDriveControl(ControlPort
, IDE_DC_nIEN
);
1484 ScsiPortStallExecution(500);
1487 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1488 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1490 Status
= IDEReadStatus(CommandPort
);
1491 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1495 ScsiPortStallExecution(10);
1497 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1503 /* Issue command to drive */
1504 if (DrvHead
& IDE_DH_LBA
)
1506 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1507 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1508 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1514 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1515 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1524 /* Setup command parameters */
1525 IDEWritePrecomp(CommandPort
, PreComp
);
1526 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1527 IDEWriteSectorNum(CommandPort
, SectorNum
);
1528 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1529 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1530 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1532 /* Issue the command */
1533 IDEWriteCommand(CommandPort
, Command
);
1534 ScsiPortStallExecution(50);
1536 /* wait for DRQ or error */
1537 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1539 Status
= IDEReadStatus(CommandPort
);
1540 if (!(Status
& IDE_SR_BUSY
))
1542 if (Status
& IDE_SR_ERR
)
1544 IDEWriteDriveControl(ControlPort
, 0);
1545 ScsiPortStallExecution(50);
1546 IDEReadStatus(CommandPort
);
1551 if (Status
& IDE_SR_DRQ
)
1557 IDEWriteDriveControl(ControlPort
, 0);
1558 ScsiPortStallExecution(50);
1559 IDEReadStatus(CommandPort
);
1564 ScsiPortStallExecution(10);
1568 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1570 IDEWriteDriveControl(ControlPort
, 0);
1571 ScsiPortStallExecution(50);
1572 IDEReadStatus(CommandPort
);
1579 /* Read data into buffer */
1582 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1583 Buffer
+= IDE_SECTOR_BUF_SZ
;
1587 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1588 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1592 /* Check for error or more sectors to read */
1593 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1595 Status
= IDEReadStatus(CommandPort
);
1596 if (!(Status
& IDE_SR_BUSY
))
1598 if (Status
& IDE_SR_ERR
)
1600 IDEWriteDriveControl(ControlPort
, 0);
1601 ScsiPortStallExecution(50);
1602 IDEReadStatus(CommandPort
);
1606 if (Status
& IDE_SR_DRQ
)
1608 if (SectorCount
>= SectorCnt
)
1610 DPRINT("Buffer size exceeded!\n");
1617 if (SectorCount
> SectorCnt
)
1619 DPRINT("Read %lu sectors of junk!\n",
1620 SectorCount
- SectorCnt
);
1622 IDEWriteDriveControl(ControlPort
, 0);
1623 ScsiPortStallExecution(50);
1624 IDEReadStatus(CommandPort
);
1634 // ------------------------------------------- Nondiscardable statics
1637 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1638 IN PSCSI_REQUEST_BLOCK Srb
)
1640 UCHAR ByteCountHigh
;
1646 DPRINT("AtapiSendAtapiCommand() called!\n");
1648 if (Srb
->PathId
!= 0)
1650 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1651 return(SRB_STATUS_INVALID_PATH_ID
);
1654 if (Srb
->TargetId
> 1)
1656 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1657 return(SRB_STATUS_INVALID_TARGET_ID
);
1662 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1663 return(SRB_STATUS_INVALID_LUN
);
1666 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1668 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1669 return(SRB_STATUS_NO_DEVICE
);
1672 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1675 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1676 return(AtapiInquiry(DeviceExtension
,
1679 /* Set pointer to data buffer. */
1680 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
1681 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
1682 DeviceExtension
->CurrentSrb
= Srb
;
1684 /* Wait for BUSY to clear */
1685 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1687 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1688 if (!(Status
& IDE_SR_BUSY
))
1692 ScsiPortStallExecution(10);
1694 DPRINT("status=%02x\n", Status
);
1695 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1696 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1698 DPRINT("Drive is BUSY for too long\n");
1699 return(SRB_STATUS_BUSY
);
1702 /* Select the desired drive */
1703 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1704 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1706 /* Wait a little while */
1707 ScsiPortStallExecution(50);
1710 /* Wait for BUSY to clear and DRDY to assert */
1711 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1713 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1714 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1718 ScsiPortStallExecution(10);
1720 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1721 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1723 DPRINT("Drive is BUSY for too long after drive select\n");
1724 return(SRB_STATUS_BUSY
);
1728 if (DeviceExtension
->DataTransferLength
< 0x10000)
1730 ByteCountLow
= (UCHAR
)(DeviceExtension
->DataTransferLength
& 0xFF);
1731 ByteCountHigh
= (UCHAR
)(DeviceExtension
->DataTransferLength
>> 8);
1735 ByteCountLow
= 0xFF;
1736 ByteCountHigh
= 0xFF;
1739 /* Set feature register */
1740 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1742 /* Set command packet length */
1743 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1744 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1746 /* Issue command to drive */
1747 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_PACKET
);
1749 /* Wait for DRQ to assert */
1750 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1752 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1753 if ((Status
& IDE_SR_DRQ
))
1757 ScsiPortStallExecution(10);
1760 /* Convert special SCSI SRBs to ATAPI format */
1761 switch (Srb
->Cdb
[0])
1763 case SCSIOP_FORMAT_UNIT
:
1764 case SCSIOP_MODE_SELECT
:
1765 case SCSIOP_MODE_SENSE
:
1766 AtapiScsiSrbToAtapi (Srb
);
1770 CdbSize
= ((DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3) == 1) ? 16 : 12;
1771 DPRINT("CdbSize: %lu\n", CdbSize
);
1773 /* Write command packet */
1774 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1778 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1780 DPRINT("AtapiSendAtapiCommand() done\n");
1782 return(SRB_STATUS_PENDING
);
1787 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1788 IN PSCSI_REQUEST_BLOCK Srb
)
1790 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1792 DPRINT("AtapiSendIdeCommand() called!\n");
1794 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1799 if (Srb
->PathId
!= 0)
1801 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1802 return(SRB_STATUS_INVALID_PATH_ID
);
1805 if (Srb
->TargetId
> 1)
1807 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1808 return(SRB_STATUS_INVALID_TARGET_ID
);
1813 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1814 return(SRB_STATUS_INVALID_LUN
);
1817 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_PRESENT
))
1819 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1820 return(SRB_STATUS_NO_DEVICE
);
1823 switch (Srb
->Cdb
[0])
1825 case SCSIOP_INQUIRY
:
1826 SrbStatus
= AtapiInquiry(DeviceExtension
,
1830 case SCSIOP_READ_CAPACITY
:
1831 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1837 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1841 case SCSIOP_SYNCHRONIZE_CACHE
:
1842 SrbStatus
= AtapiFlushCache(DeviceExtension
,
1846 case SCSIOP_TEST_UNIT_READY
:
1847 SrbStatus
= AtapiTestUnitReady(DeviceExtension
,
1851 case SCSIOP_MODE_SENSE
:
1854 case SCSIOP_START_STOP_UNIT
:
1855 case SCSIOP_REQUEST_SENSE
:
1859 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1861 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1865 DPRINT("AtapiSendIdeCommand() done!\n");
1872 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1873 PSCSI_REQUEST_BLOCK Srb
)
1875 PIDE_DRIVE_IDENTIFY DeviceParams
;
1876 PINQUIRYDATA InquiryData
;
1879 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1880 DeviceExtension
, Srb
->TargetId
);
1882 InquiryData
= Srb
->DataBuffer
;
1883 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1886 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1888 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1891 /* set device class */
1892 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
1894 /* get it from the ATAPI configuration word */
1895 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1896 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1901 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1904 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1905 if (DeviceParams
->ConfigBits
& 0x80)
1907 DPRINT("Removable media!\n");
1908 InquiryData
->RemovableMedia
= 1;
1911 for (i
= 0; i
< 20; i
+= 2)
1913 InquiryData
->VendorId
[i
] =
1914 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1915 InquiryData
->VendorId
[i
+1] =
1916 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1919 for (i
= 0; i
< 4; i
++)
1921 InquiryData
->ProductId
[12+i
] = ' ';
1924 for (i
= 0; i
< 4; i
+= 2)
1926 InquiryData
->ProductRevisionLevel
[i
] =
1927 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1928 InquiryData
->ProductRevisionLevel
[i
+1] =
1929 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1932 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1934 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1935 return(SRB_STATUS_SUCCESS
);
1940 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1941 PSCSI_REQUEST_BLOCK Srb
)
1943 PREAD_CAPACITY_DATA CapacityData
;
1944 PIDE_DRIVE_IDENTIFY DeviceParams
;
1947 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1948 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1949 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1951 /* Set sector (block) size to 512 bytes (big-endian). */
1952 CapacityData
->BytesPerBlock
= 0x20000;
1954 /* Calculate last sector (big-endian). */
1955 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1957 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1958 DeviceParams
->TMSectorCountLo
) - 1;
1962 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1963 DeviceParams
->LogicalHeads
*
1964 DeviceParams
->SectorsPerTrack
)-1;
1967 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1968 (((PUCHAR
)&LastSector
)[1] << 16) |
1969 (((PUCHAR
)&LastSector
)[2] << 8) |
1970 ((PUCHAR
)&LastSector
)[3];
1972 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1975 CapacityData
->LogicalBlockAddress
);
1977 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1978 return(SRB_STATUS_SUCCESS
);
1983 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1984 PSCSI_REQUEST_BLOCK Srb
)
1986 PIDE_DRIVE_IDENTIFY DeviceParams
;
1987 ULONG StartingSector
;
1997 DPRINT("AtapiReadWrite() called!\n");
1998 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
2001 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
2003 /* Get starting sector number from CDB. */
2004 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
2005 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
2006 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
2007 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
2009 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
2010 DeviceParams
->BytesPerSector
;
2012 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
2014 Srb
->DataTransferLength
,
2017 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
2019 SectorNumber
= StartingSector
& 0xff;
2020 CylinderLow
= (StartingSector
>> 8) & 0xff;
2021 CylinderHigh
= (StartingSector
>> 16) & 0xff;
2022 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
2023 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
2028 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
2029 StartingSector
/= DeviceParams
->SectorsPerTrack
;
2030 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
2031 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
2032 StartingSector
/= DeviceParams
->LogicalHeads
;
2033 CylinderLow
= StartingSector
& 0xff;
2034 CylinderHigh
= StartingSector
>> 8;
2038 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
2040 Command
= (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
) ? IDE_CMD_READ_MULTIPLE
: IDE_CMD_READ
;
2044 Command
= (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MULTI_SECTOR_CMD
) ? IDE_CMD_WRITE_MULTIPLE
: IDE_CMD_WRITE
;
2047 if (DrvHead
& IDE_DH_LBA
)
2049 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
2050 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2051 DeviceExtension
->CommandPortBase
,
2052 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2053 ((DrvHead
& 0x0f) << 24) +
2054 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
2060 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
2061 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
2062 DeviceExtension
->CommandPortBase
,
2063 DrvHead
& IDE_DH_DRV1
? 1 : 0,
2072 /* Set pointer to data buffer. */
2073 DeviceExtension
->DataBuffer
= (PUCHAR
)Srb
->DataBuffer
;
2074 DeviceExtension
->DataTransferLength
= Srb
->DataTransferLength
;
2076 DeviceExtension
->CurrentSrb
= Srb
;
2078 /* wait for BUSY to clear */
2079 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2081 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2082 if (!(Status
& IDE_SR_BUSY
))
2086 ScsiPortStallExecution(10);
2088 DPRINT("status=%02x\n", Status
);
2089 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
2090 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2092 DPRINT ("Drive is BUSY for too long\n");
2093 return(SRB_STATUS_BUSY
);
2096 /* Select the desired drive */
2097 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2098 IDE_DH_FIXED
| DrvHead
);
2100 ScsiPortStallExecution(10);
2102 /* wait for BUSY to clear and DRDY to assert */
2103 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2105 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2106 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
2110 ScsiPortStallExecution(10);
2112 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
2113 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2115 DPRINT("Drive is BUSY for too long after drive select\n");
2116 return(SRB_STATUS_BUSY
);
2120 /* Setup command parameters */
2121 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2122 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
2123 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
2124 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
2125 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
2126 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2128 /* Indicate expecting an interrupt. */
2129 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2131 /* Issue command to drive */
2132 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
2134 /* Write data block */
2135 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
2137 PUCHAR TargetAddress
;
2140 /* Wait for controller ready */
2141 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2143 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2144 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2148 KeStallExecutionProcessor(10);
2150 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2152 DPRINT1("Drive is BUSY for too long after sending write command\n");
2153 return(SRB_STATUS_BUSY
);
2156 /* Update DeviceExtension data */
2157 TransferSize
= DeviceExtension
->TransferSize
[Srb
->TargetId
];
2158 if (DeviceExtension
->DataTransferLength
< TransferSize
)
2160 TransferSize
= DeviceExtension
->DataTransferLength
;
2163 TargetAddress
= DeviceExtension
->DataBuffer
;
2164 DeviceExtension
->DataBuffer
+= TransferSize
;
2165 DeviceExtension
->DataTransferLength
-= TransferSize
;
2167 /* Write data block */
2168 if (DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_DWORD_IO
)
2170 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2176 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2182 DPRINT("AtapiReadWrite() done!\n");
2184 /* Wait for interrupt. */
2185 return(SRB_STATUS_PENDING
);
2190 AtapiFlushCache(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2191 PSCSI_REQUEST_BLOCK Srb
)
2196 DPRINT("AtapiFlushCache() called!\n");
2197 DPRINT("SCSIOP_SYNCRONIZE_CACHE: TargetId: %lu\n",
2200 /* Wait for BUSY to clear */
2201 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2203 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2204 if (!(Status
& IDE_SR_BUSY
))
2208 ScsiPortStallExecution(10);
2210 DPRINT("Status=%02x\n", Status
);
2211 DPRINT("Waited %ld usecs for busy to clear\n", Retries
* 10);
2212 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2214 DPRINT1("Drive is BUSY for too long\n");
2215 return(SRB_STATUS_BUSY
);
2218 /* Select the desired drive */
2219 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2220 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2221 ScsiPortStallExecution(10);
2223 /* Issue command to drive */
2224 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_FLUSH_CACHE
);
2226 /* Wait for controller ready */
2227 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2229 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2230 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2234 KeStallExecutionProcessor(10);
2236 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2238 DPRINT1("Drive is BUSY for too long after sending write command\n");
2239 return(SRB_STATUS_BUSY
);
2242 /* Indicate expecting an interrupt. */
2243 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2245 DPRINT("AtapiFlushCache() done!\n");
2247 /* Wait for interrupt. */
2248 return(SRB_STATUS_PENDING
);
2253 AtapiTestUnitReady(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
2254 PSCSI_REQUEST_BLOCK Srb
)
2260 DPRINT1("AtapiTestUnitReady() called!\n");
2262 DPRINT1("SCSIOP_TEST_UNIT_READY: TargetId: %lu\n",
2265 /* Return success if media status is not supported */
2266 if (!(DeviceExtension
->DeviceFlags
[Srb
->TargetId
] & DEVICE_MEDIA_STATUS
))
2268 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2269 return(SRB_STATUS_SUCCESS
);
2272 /* Wait for BUSY to clear */
2273 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
2275 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2276 if (!(Status
& IDE_SR_BUSY
))
2280 ScsiPortStallExecution(10);
2282 DPRINT1("Status=%02x\n", Status
);
2283 DPRINT1("Waited %ld usecs for busy to clear\n", Retries
* 10);
2284 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2286 DPRINT1("Drive is BUSY for too long\n");
2287 return(SRB_STATUS_BUSY
);
2290 /* Select the desired drive */
2291 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
2292 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
2293 ScsiPortStallExecution(10);
2295 /* Issue command to drive */
2296 IDEWriteCommand(DeviceExtension
->CommandPortBase
, IDE_CMD_GET_MEDIA_STATUS
);
2298 /* Wait for controller ready */
2299 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2301 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2302 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2306 KeStallExecutionProcessor(10);
2308 if (Retries
>= IDE_MAX_WRITE_RETRIES
)
2310 DPRINT1("Drive is BUSY for too long after sending write command\n");
2311 return(SRB_STATUS_BUSY
);
2314 if (Status
& IDE_SR_ERR
)
2316 Error
= IDEReadError(DeviceExtension
->CommandPortBase
);
2317 if (Error
== IDE_ER_UNC
)
2320 /* Handle write protection 'error' */
2321 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2322 return(SRB_STATUS_SUCCESS
);
2327 /* Indicate expecting an interrupt. */
2328 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2329 return(SRB_STATUS_PENDING
);
2333 DPRINT1("AtapiTestUnitReady() done!\n");
2335 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
2336 return(SRB_STATUS_SUCCESS
);
2341 AtapiErrorToScsi(PVOID DeviceExtension
,
2342 PSCSI_REQUEST_BLOCK Srb
)
2344 PATAPI_MINIPORT_EXTENSION DevExt
;
2345 ULONG CommandPortBase
;
2346 ULONG ControlPortBase
;
2351 DPRINT("AtapiErrorToScsi() called\n");
2353 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2355 CommandPortBase
= DevExt
->CommandPortBase
;
2356 ControlPortBase
= DevExt
->ControlPortBase
;
2358 ErrorReg
= IDEReadError(CommandPortBase
);
2360 if (DevExt
->DeviceFlags
[Srb
->TargetId
] & DEVICE_ATAPI
)
2362 switch (ErrorReg
>> 4)
2364 case SCSI_SENSE_NO_SENSE
:
2365 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2366 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2367 SrbStatus
= SRB_STATUS_ERROR
;
2370 case SCSI_SENSE_RECOVERED_ERROR
:
2371 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2373 SrbStatus
= SRB_STATUS_SUCCESS
;
2376 case SCSI_SENSE_NOT_READY
:
2377 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2378 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2379 SrbStatus
= SRB_STATUS_ERROR
;
2382 case SCSI_SENSE_MEDIUM_ERROR
:
2383 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2384 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2385 SrbStatus
= SRB_STATUS_ERROR
;
2388 case SCSI_SENSE_HARDWARE_ERROR
:
2389 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2390 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2391 SrbStatus
= SRB_STATUS_ERROR
;
2394 case SCSI_SENSE_ILLEGAL_REQUEST
:
2395 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2396 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2397 SrbStatus
= SRB_STATUS_ERROR
;
2400 case SCSI_SENSE_UNIT_ATTENTION
:
2401 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2402 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2403 SrbStatus
= SRB_STATUS_ERROR
;
2406 case SCSI_SENSE_DATA_PROTECT
:
2407 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2408 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2409 SrbStatus
= SRB_STATUS_ERROR
;
2412 case SCSI_SENSE_BLANK_CHECK
:
2413 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2414 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2415 SrbStatus
= SRB_STATUS_ERROR
;
2418 case SCSI_SENSE_ABORTED_COMMAND
:
2419 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2420 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2421 SrbStatus
= SRB_STATUS_ERROR
;
2425 DPRINT("ATAPI error: Invalid sense key\n");
2427 SrbStatus
= SRB_STATUS_ERROR
;
2433 DPRINT1("IDE error: %02x\n", ErrorReg
);
2436 SrbStatus
= SRB_STATUS_ERROR
;
2439 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2442 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2443 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2444 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2445 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2446 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2448 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2459 Srb
->ScsiStatus
= ScsiStatus
;
2461 DPRINT("AtapiErrorToScsi() done\n");
2468 AtapiScsiSrbToAtapi (PSCSI_REQUEST_BLOCK Srb
)
2470 DPRINT("AtapiConvertScsiToAtapi() called\n");
2472 Srb
->CdbLength
= 12;
2474 switch (Srb
->Cdb
[0])
2476 case SCSIOP_FORMAT_UNIT
:
2477 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
2480 case SCSIOP_MODE_SELECT
:
2482 PATAPI_MODE_SELECT12 AtapiModeSelect
;
2485 AtapiModeSelect
= (PATAPI_MODE_SELECT12
)Srb
->Cdb
;
2486 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
2488 RtlZeroMemory (Srb
->Cdb
,
2490 AtapiModeSelect
->OperationCode
= ATAPI_MODE_SELECT
;
2491 AtapiModeSelect
->PFBit
= 1;
2492 AtapiModeSelect
->ParameterListLengthMsb
= 0;
2493 AtapiModeSelect
->ParameterListLengthLsb
= Length
;
2497 case SCSIOP_MODE_SENSE
:
2499 PATAPI_MODE_SENSE12 AtapiModeSense
;
2503 AtapiModeSense
= (PATAPI_MODE_SENSE12
)Srb
->Cdb
;
2504 PageCode
= ((PCDB
)Srb
->Cdb
)->MODE_SENSE
.PageCode
;
2505 Length
= ((PCDB
)Srb
->Cdb
)->MODE_SENSE
.AllocationLength
;
2507 RtlZeroMemory (Srb
->Cdb
,
2509 AtapiModeSense
->OperationCode
= ATAPI_MODE_SENSE
;
2510 AtapiModeSense
->PageCode
= PageCode
;
2511 AtapiModeSense
->ParameterListLengthMsb
= 0;
2512 AtapiModeSense
->ParameterListLengthLsb
= Length
;