1 /* $Id: atapi.c,v 1.8 2002/03/03 19:37:41 ekohl Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS ATAPI miniport driver
5 * FILE: services/storage/atapi/atapi.c
6 * PURPOSE: ATAPI miniport driver
7 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
14 * This driver is derived from Rex Jolliff's ide driver. Lots of his
15 * routines are still in here although they belong into the higher level
16 * drivers. They will be moved away as soon as possible.
21 * - implement sending of atapi commands
22 * - handle removable atapi non-cdrom drives
25 // -------------------------------------------------------------------------
27 #include <ddk/ntddk.h>
29 #include "../include/srb.h"
30 #include "../include/scsi.h"
31 #include "../include/ntddscsi.h"
38 #define VERSION "V0.0.1"
41 // ------------------------------------------------------- File Static Data
43 // ATAPI_MINIPORT_EXTENSION
46 // Extension to be placed in each port device object
49 // Allocated from NON-PAGED POOL
50 // Available at any IRQL
53 typedef struct _ATAPI_MINIPORT_EXTENSION
55 IDE_DRIVE_IDENTIFY DeviceParams
[2];
56 BOOLEAN DevicePresent
[2];
57 BOOLEAN DeviceAtapi
[2];
59 ULONG CommandPortBase
;
60 ULONG ControlPortBase
;
62 BOOLEAN ExpectingInterrupt
;
63 PSCSI_REQUEST_BLOCK CurrentSrb
;
66 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
69 typedef struct _UNIT_EXTENSION
72 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
75 // ----------------------------------------------- Discardable Declarations
79 // make the initialization routines discardable, so that they
82 #pragma alloc_text(init, DriverEntry)
83 #pragma alloc_text(init, IDECreateController)
84 #pragma alloc_text(init, IDEPolledRead)
86 // make the PASSIVE_LEVEL routines pageable, so that they don't
87 // waste nonpaged memory
89 #pragma alloc_text(page, IDEShutdown)
90 #pragma alloc_text(page, IDEDispatchOpenClose)
91 #pragma alloc_text(page, IDEDispatchRead)
92 #pragma alloc_text(page, IDEDispatchWrite)
94 #endif /* ALLOC_PRAGMA */
96 // ---------------------------------------------------- Forward Declarations
99 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
101 PVOID BusInformation
,
102 PCHAR ArgumentString
,
103 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
107 AtapiFindIsaBusController(PVOID DeviceExtension
,
109 PVOID BusInformation
,
110 PCHAR ArgumentString
,
111 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
115 AtapiFindNativePciController(PVOID DeviceExtension
,
117 PVOID BusInformation
,
118 PCHAR ArgumentString
,
119 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
122 static BOOLEAN STDCALL
123 AtapiInitialize(IN PVOID DeviceExtension
);
125 static BOOLEAN STDCALL
126 AtapiResetBus(IN PVOID DeviceExtension
,
129 static BOOLEAN STDCALL
130 AtapiStartIo(IN PVOID DeviceExtension
,
131 IN PSCSI_REQUEST_BLOCK Srb
);
133 static BOOLEAN STDCALL
134 AtapiInterrupt(IN PVOID DeviceExtension
);
137 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
138 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
141 AtapiIdentifyDevice(IN ULONG CommandPort
,
142 IN ULONG ControlPort
,
145 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
148 IDEResetController(IN WORD CommandPort
,
149 IN WORD ControlPort
);
152 AtapiPolledRead(IN WORD CommandPort
,
158 IN BYTE CylinderHigh
,
166 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
167 IN PSCSI_REQUEST_BLOCK Srb
);
170 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
171 IN PSCSI_REQUEST_BLOCK Srb
);
174 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
175 IN PSCSI_REQUEST_BLOCK Srb
);
178 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
179 IN PSCSI_REQUEST_BLOCK Srb
);
182 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
183 IN PSCSI_REQUEST_BLOCK Srb
);
185 // ---------------------------------------------------------------- Inlines
188 IDESwapBytePairs(char *Buf
,
194 for (i
= 0; i
< Cnt
; i
+= 2)
204 IdeFindDrive(int Address
,
209 DPRINT1("IdeFindDrive(Address %lx DriveIdx %lu) called!\n", Address
, DriveIdx
);
211 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| (DriveIdx
? IDE_DH_DRV1
: 0));
212 IDEWriteCylinderLow(Address
, 0x30);
214 Cyl
= IDEReadCylinderLow(Address
);
215 DPRINT1("Cylinder %lx\n", Cyl
);
218 DPRINT1("IdeFindDrive() done!\n");
224 // ------------------------------------------------------- Public Interface
229 // This function initializes the driver, locates and claims
230 // hardware resources, and creates various NT objects needed
231 // to process I/O requests.
237 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
239 // IN PUNICODE_STRING RegistryPath Name of registry driver service
246 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
247 IN PUNICODE_STRING RegistryPath
)
249 HW_INITIALIZATION_DATA InitData
;
252 DbgPrint("ATAPI Driver %s\n", VERSION
);
254 /* Initialize data structure */
255 RtlZeroMemory(&InitData
,
256 sizeof(HW_INITIALIZATION_DATA
));
257 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
258 InitData
.HwInitialize
= AtapiInitialize
;
259 InitData
.HwResetBus
= AtapiResetBus
;
260 InitData
.HwStartIo
= AtapiStartIo
;
261 InitData
.HwInterrupt
= AtapiInterrupt
;
263 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
264 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
266 InitData
.MapBuffers
= TRUE
;
268 /* Search the PCI bus for compatibility mode ide controllers */
269 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
270 InitData
.NumberOfAccessRanges
= 2;
271 InitData
.AdapterInterfaceType
= PCIBus
;
273 InitData
.VendorId
= NULL
;
274 InitData
.VendorIdLength
= 0;
275 InitData
.DeviceId
= NULL
;
276 InitData
.DeviceIdLength
= 0;
278 Status
= ScsiPortInitialize(DriverObject
,
282 // if (newStatus < statusToReturn)
283 // statusToReturn = newStatus;
285 /* Search the ISA bus for ide controllers */
287 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
288 InitData
.NumberOfAccessRanges
= 2;
289 InitData
.AdapterInterfaceType
= Isa
;
291 InitData
.VendorId
= NULL
;
292 InitData
.VendorIdLength
= 0;
293 InitData
.DeviceId
= NULL
;
294 InitData
.DeviceIdLength
= 0;
296 Status
= ScsiPortInitialize(DriverObject
,
300 // if (newStatus < statusToReturn)
301 // statusToReturn = newStatus;
304 /* Search the PCI bus for native mode ide controllers */
306 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
307 InitData
.NumberOfAccessRanges
= 2;
308 InitData
.AdapterInterfaceType
= PCIBus
;
310 InitData
.VendorId
= NULL
;
311 InitData
.VendorIdLength
= 0;
312 InitData
.DeviceId
= NULL
;
313 InitData
.DeviceIdLength
= 0;
315 Status
= ScsiPortInitialize(DriverObject
,
319 // if (newStatus < statusToReturn)
320 // statusToReturn = newStatus;
323 DPRINT1( "Returning from DriverEntry\n" );
330 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
332 PVOID BusInformation
,
333 PCHAR ArgumentString
,
334 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
337 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
338 PCI_SLOT_NUMBER SlotNumber
;
339 PCI_COMMON_CONFIG PciConfig
;
341 ULONG FunctionNumber
;
342 BOOLEAN ChannelFound
;
345 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
346 ConfigInfo
->SystemIoBusNumber
,
347 ConfigInfo
->SlotNumber
);
351 /* both channels were claimed: exit */
352 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
353 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
354 return(SP_RETURN_NOT_FOUND
);
357 SlotNumber
.u
.AsULONG
= 0;
358 for (FunctionNumber
= 0 /*ConfigInfo->SlotNumber*/; FunctionNumber
< 256; FunctionNumber
++)
360 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
361 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
362 SlotNumber
.u
.AsULONG
= FunctionNumber
;
364 ChannelFound
= FALSE
;
367 DataSize
= ScsiPortGetBusData(DeviceExtension
,
370 SlotNumber
.u
.AsULONG
,
372 sizeof(PCI_COMMON_CONFIG
));
373 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
374 // PciConfig.VendorID == PCI_INVALID_VENDORID)
377 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
378 // return(SP_RETURN_ERROR); /* No bus found */
381 // return(SP_RETURN_ERROR);
384 if (PciConfig
.BaseClass
== 0x01 &&
385 PciConfig
.SubClass
== 0x01) // &&
386 // (PciConfig.ProgIf & 0x05) == 0)
388 /* both channels are in compatibility mode */
389 DPRINT1("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
390 ConfigInfo
->SystemIoBusNumber
,
391 // SlotNumber.u.AsULONG >> 3,
392 // SlotNumber.u.AsULONG & 0x07,
393 SlotNumber
.u
.bits
.DeviceNumber
,
394 SlotNumber
.u
.bits
.FunctionNumber
,
397 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
399 DPRINT1("Found IDE controller in compatibility mode!\n");
401 ConfigInfo
->NumberOfBuses
= 1;
402 ConfigInfo
->MaximumNumberOfTargets
= 2;
403 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
405 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
407 /* Both channels unclaimed: Claim primary channel */
408 DPRINT1("Primary channel!\n");
410 DevExt
->CommandPortBase
= 0x01F0;
411 DevExt
->ControlPortBase
= 0x03F6;
413 ConfigInfo
->BusInterruptLevel
= 14;
414 ConfigInfo
->BusInterruptVector
= 14;
415 ConfigInfo
->InterruptMode
= LevelSensitive
;
417 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x01F0);
418 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
419 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
421 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x03F6);
422 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
423 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
425 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
429 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
431 /* Primary channel already claimed: claim secondary channel */
432 DPRINT1("Secondary channel!\n");
434 DevExt
->CommandPortBase
= 0x0170;
435 DevExt
->ControlPortBase
= 0x0376;
437 ConfigInfo
->BusInterruptLevel
= 15;
438 ConfigInfo
->BusInterruptVector
= 15;
439 ConfigInfo
->InterruptMode
= LevelSensitive
;
441 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0170);
442 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
443 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
445 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0376);
446 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
447 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
449 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
454 /* Find attached devices */
455 if (ChannelFound
== TRUE
)
457 DeviceFound
= AtapiFindDevices(DevExt
,
460 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
461 return(SP_RETURN_FOUND
);
465 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
467 return(SP_RETURN_NOT_FOUND
);
472 AtapiFindIsaBusController(PVOID DeviceExtension
,
474 PVOID BusInformation
,
475 PCHAR ArgumentString
,
476 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
479 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
481 DPRINT("AtapiFindIsaBusController() called!\n");
485 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
)
487 DPRINT("Primary IDE controller already claimed!\n");
491 if (ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
493 DPRINT("Secondary IDE controller already claimed!\n");
497 DPRINT("AtapiFindIsaBusController() done!\n");
499 return(SP_RETURN_NOT_FOUND
);
504 AtapiFindNativePciController(PVOID DeviceExtension
,
506 PVOID BusInformation
,
507 PCHAR ArgumentString
,
508 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
511 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
513 DPRINT("AtapiFindNativePciController() called!\n");
517 DPRINT("AtapiFindNativePciController() done!\n");
519 return(SP_RETURN_NOT_FOUND
);
523 static BOOLEAN STDCALL
524 AtapiInitialize(IN PVOID DeviceExtension
)
530 static BOOLEAN STDCALL
531 AtapiResetBus(IN PVOID DeviceExtension
,
538 static BOOLEAN STDCALL
539 AtapiStartIo(IN PVOID DeviceExtension
,
540 IN PSCSI_REQUEST_BLOCK Srb
)
542 PATAPI_MINIPORT_EXTENSION DevExt
;
545 DPRINT1("AtapiStartIo() called\n");
547 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
549 switch (Srb
->Function
)
551 case SRB_FUNCTION_EXECUTE_SCSI
:
552 DevExt
->CurrentSrb
= Srb
;
553 if (DevExt
->DeviceAtapi
[Srb
->TargetId
] == TRUE
)
555 Result
= AtapiSendAtapiCommand(DevExt
,
560 Result
= AtapiSendIdeCommand(DevExt
,
567 Srb
->SrbStatus
= Result
;
570 if (Result
!= SRB_STATUS_PENDING
)
572 DevExt
->CurrentSrb
= NULL
;
573 Srb
->SrbStatus
= (UCHAR
)Result
;
575 ScsiPortNotification(RequestComplete
,
578 ScsiPortNotification(NextRequest
,
584 DPRINT1("SrbStatus = SRB_STATUS_PENDING\n");
587 DPRINT1("AtapiStartIo() done\n");
593 static BOOLEAN STDCALL
594 AtapiInterrupt(IN PVOID DeviceExtension
)
596 PATAPI_MINIPORT_EXTENSION DevExt
;
597 PSCSI_REQUEST_BLOCK Srb
;
598 ULONG CommandPortBase
;
599 ULONG ControlPortBase
;
602 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
604 NTSTATUS ErrorStatus
;
605 ULONG ErrorInformation
;
606 PUCHAR TargetAddress
;
610 DPRINT("AtapiInterrupt() called!\n");
612 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
613 if (DevExt
->ExpectingInterrupt
== FALSE
)
618 DevExt
->ExpectingInterrupt
= FALSE
;
620 Srb
= DevExt
->CurrentSrb
;
622 DPRINT("Srb: %p\n", Srb
);
624 CommandPortBase
= DevExt
->CommandPortBase
;
625 ControlPortBase
= DevExt
->ControlPortBase
;
627 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
631 AnErrorOccured
= FALSE
;
632 RequestIsComplete
= FALSE
;
633 ErrorStatus
= STATUS_SUCCESS
;
634 ErrorInformation
= 0;
636 DeviceStatus
= IDEReadStatus(CommandPortBase
);
638 /* Handle error condition if it exists */
639 if (DeviceStatus
& IDE_SR_ERR
)
641 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
645 ErrorReg
= IDEReadError(CommandPortBase
);
646 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
647 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
648 DriveHead
= IDEReadDriveHead(CommandPortBase
);
649 SectorCount
= IDEReadSectorCount(CommandPortBase
);
650 SectorNum
= IDEReadSectorNum(CommandPortBase
);
652 /* FIXME: should use the NT error logging facility */
653 DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
654 0, //DeviceExtension->Operation,
662 /* FIXME: should retry the command and perhaps recalibrate the drive */
664 // Set error status information
665 AnErrorOccured
= TRUE
;
666 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
669 (((((((CylinderHigh
<< 8) + CylinderLow
) *
670 DeviceExtension
->LogicalHeads
) +
671 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
672 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
673 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
681 DPRINT1("SCSIOP_READ\n");
683 /* Update controller/device state variables */
684 TargetAddress
= Srb
->DataBuffer
;
685 Srb
->DataBuffer
+= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
686 Srb
->DataTransferLength
-= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
687 // DevExt->SectorsTransferred++;
689 /* Remember whether DRQ should be low at end (last block read) */
690 IsLastBlock
= Srb
->DataTransferLength
== 0;
692 /* Wait for DRQ assertion */
693 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
694 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
697 KeStallExecutionProcessor(10);
700 /* Copy the block of data */
701 IDEReadBlock(CommandPortBase
,
708 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
709 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
712 KeStallExecutionProcessor(10);
715 /* Check for data overrun */
716 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
718 AnErrorOccured
= TRUE
;
719 ErrorStatus
= STATUS_DATA_OVERRUN
;
720 ErrorInformation
= 0;
726 // Setup next transfer or set RequestIsComplete
727 if (DeviceExtension
->BytesRequested
>
728 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
730 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
731 DeviceExtension
->SectorsTransferred
= 0;
732 DeviceExtension
->BytesToTransfer
=
733 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
734 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
736 else if (DeviceExtension
->BytesRequested
> 0)
738 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
739 DeviceExtension
->SectorsTransferred
= 0;
740 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
741 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
745 RequestIsComplete
= TRUE
;
748 RequestIsComplete
= TRUE
;
754 DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
755 RequestIsComplete
= TRUE
;
761 /* If there was an error or the request is done, complete the packet */
762 if (AnErrorOccured
|| RequestIsComplete
)
765 /* Set the return status and info values */
766 Irp
= ControllerExtension
->CurrentIrp
;
767 Irp
->IoStatus
.Status
= ErrorStatus
;
768 Irp
->IoStatus
.Information
= ErrorInformation
;
770 /* Clear out controller fields */
771 ControllerExtension
->OperationInProgress
= FALSE
;
772 ControllerExtension
->DeviceStatus
= 0;
774 /* Queue the Dpc to finish up */
775 IoRequestDpc(DeviceExtension
->DeviceObject
,
777 ControllerExtension
);
780 else if (IsLastBlock
)
783 /* Else more data is needed, setup next device I/O */
784 IDEStartController((PVOID
)DeviceExtension
);
788 ScsiPortNotification(RequestComplete
,
792 ScsiPortNotification(NextRequest
,
797 DPRINT("AtapiInterrupt() done!\n");
807 // ---------------------------------------------------- Discardable statics
811 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
812 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
814 BOOLEAN DeviceFound
= FALSE
;
815 ULONG CommandPortBase
;
816 ULONG ControlPortBase
;
821 DPRINT("AtapiFindDevices() called\n");
823 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
824 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
825 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
827 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
828 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
829 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
831 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
833 /* disable interrupts */
834 IDEWriteDriveControl(ControlPortBase
,
838 IDEWriteDriveHead(CommandPortBase
,
839 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
840 ScsiPortStallExecution(500);
841 IDEWriteCylinderHigh(CommandPortBase
, 0);
842 IDEWriteCylinderLow(CommandPortBase
, 0);
843 IDEWriteCommand(CommandPortBase
, 0x08); /* IDE_COMMAND_ATAPI_RESET */
844 // ScsiPortStallExecution(1000*1000);
845 // IDEWriteDriveHead(CommandPortBase,
846 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
849 for (Retries
= 0; Retries
< 20000; Retries
++)
851 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
855 ScsiPortStallExecution(150);
857 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
859 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
863 High
= IDEReadCylinderHigh(CommandPortBase
);
864 Low
= IDEReadCylinderLow(CommandPortBase
);
866 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
871 if (High
== 0xEB && Low
== 0x14)
873 if (AtapiIdentifyDevice(CommandPortBase
,
877 &DeviceExtension
->DeviceParams
[UnitNumber
]))
879 DPRINT(" ATAPI drive found!\n");
880 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
881 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
886 DPRINT(" No ATAPI drive found!\n");
891 if (AtapiIdentifyDevice(CommandPortBase
,
895 &DeviceExtension
->DeviceParams
[UnitNumber
]))
897 DPRINT(" IDE drive found!\n");
898 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
899 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
904 DPRINT(" No IDE drive found!\n");
909 DPRINT("AtapiFindDrives() done\n");
915 // AtapiResetController
918 // Reset the controller and report completion status
924 // IN WORD CommandPort The address of the command port
925 // IN WORD ControlPort The address of the control port
931 AtapiResetController(IN WORD CommandPort
,
936 /* Assert drive reset line */
937 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
939 /* Wait for min. 25 microseconds */
940 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
942 /* Negate drive reset line */
943 IDEWriteDriveControl(ControlPort
, 0);
945 /* Wait for BUSY negation */
946 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
948 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
952 ScsiPortStallExecution(10);
956 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
963 // return TRUE if controller came back to life. and
964 // the registers are initialized correctly
965 return(IDEReadError(CommandPort
) == 1);
969 * AtapiIdentifyDevice
972 * Get the identification block from the drive
979 * Address of the command port
981 * Address of the control port
983 * The drive index (0,1)
985 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
987 * Address to write drive ident block
990 * TRUE: The drive identification block was retrieved successfully
991 * FALSE: an error ocurred
995 AtapiIdentifyDevice(IN ULONG CommandPort
,
996 IN ULONG ControlPort
,
999 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1001 /* Get the Drive Identify block from drive or die */
1002 if (AtapiPolledRead((WORD
)CommandPort
,
1009 (DriveNum
? IDE_DH_DRV1
: 0),
1010 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1011 (BYTE
*)DrvParms
) != 0) /* atapi_identify */
1013 DPRINT1("IDEPolledRead() failed\n");
1017 /* Report on drive parameters if debug mode */
1018 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1019 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1020 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1021 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1022 DrvParms
->ConfigBits
,
1023 DrvParms
->LogicalCyls
,
1024 DrvParms
->LogicalHeads
,
1025 DrvParms
->SectorsPerTrack
,
1026 DrvParms
->InterSectorGap
,
1027 DrvParms
->InterSectorGapSize
);
1028 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1029 DrvParms
->BytesInPLO
,
1030 DrvParms
->VendorUniqueCnt
,
1031 DrvParms
->SerialNumber
);
1032 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1033 DrvParms
->ControllerType
,
1034 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1035 DrvParms
->ECCByteCnt
,
1036 DrvParms
->FirmwareRev
);
1037 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1038 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1039 (DrvParms
->RWMultImplemented
) & 0xff,
1040 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1041 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1042 DrvParms
->MinPIOTransTime
,
1043 DrvParms
->MinDMATransTime
);
1044 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1045 DrvParms
->TMCylinders
,
1047 DrvParms
->TMSectorsPerTrk
,
1048 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1049 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1050 DrvParms
->TMSectorCountHi
,
1051 DrvParms
->TMSectorCountLo
,
1052 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1054 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1055 if (DrvParms
->BytesPerSector
== 0)
1056 DrvParms
->BytesPerSector
= 512;
1064 // Read a sector of data from the drive in a polled fashion.
1070 // IN WORD Address Address of command port for drive
1071 // IN BYTE PreComp Value to write to precomp register
1072 // IN BYTE SectorCnt Value to write to sectorCnt register
1073 // IN BYTE SectorNum Value to write to sectorNum register
1074 // IN BYTE CylinderLow Value to write to CylinderLow register
1075 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1076 // IN BYTE DrvHead Value to write to Drive/Head register
1077 // IN BYTE Command Value to write to Command register
1078 // OUT BYTE *Buffer Buffer for output data
1081 // int 0 is success, non 0 is an error code
1085 AtapiPolledRead(IN WORD Address
,
1086 IN WORD ControlPort
,
1090 IN BYTE CylinderLow
,
1091 IN BYTE CylinderHigh
,
1096 ULONG SectorCount
= 0;
1098 BOOLEAN Junk
= FALSE
;
1102 /* Disable interrupts */
1103 Control
= IDEReadAltStatus(ControlPort
);
1104 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1106 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1107 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1109 Status
= IDEReadStatus(Address
);
1110 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1114 ScsiPortStallExecution(10);
1116 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1118 return(IDE_ER_ABRT
);
1121 /* Write Drive/Head to select drive */
1122 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1124 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1125 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1127 Status
= IDEReadStatus(Address
);
1128 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1132 ScsiPortStallExecution(10);
1134 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1139 /* Issue command to drive */
1140 if (DrvHead
& IDE_DH_LBA
)
1142 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1143 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1144 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1150 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1151 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1160 /* Setup command parameters */
1161 IDEWritePrecomp(Address
, PreComp
);
1162 IDEWriteSectorCount(Address
, SectorCnt
);
1163 IDEWriteSectorNum(Address
, SectorNum
);
1164 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1165 IDEWriteCylinderLow(Address
, CylinderLow
);
1166 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1168 /* Issue the command */
1169 IDEWriteCommand(Address
, Command
);
1170 ScsiPortStallExecution(50);
1172 /* wait for DRQ or error */
1173 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1175 Status
= IDEReadStatus(Address
);
1176 if (!(Status
& IDE_SR_BUSY
))
1178 if (Status
& IDE_SR_ERR
)
1180 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1181 return(IDE_ER_ABRT
);
1183 if (Status
& IDE_SR_DRQ
)
1189 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1190 return(IDE_ER_ABRT
);
1193 ScsiPortStallExecution(10);
1197 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1199 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1200 return(IDE_ER_ABRT
);
1205 /* Read data into buffer */
1208 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1209 Buffer
+= IDE_SECTOR_BUF_SZ
;
1213 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1214 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1218 /* Check for error or more sectors to read */
1219 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1221 Status
= IDEReadStatus(Address
);
1222 if (!(Status
& IDE_SR_BUSY
))
1224 if (Status
& IDE_SR_ERR
)
1226 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1227 return(IDE_ER_ABRT
);
1229 if (Status
& IDE_SR_DRQ
)
1231 if (SectorCount
>= SectorCnt
)
1233 DPRINT("Buffer size exceeded!\n");
1240 if (SectorCount
> SectorCnt
)
1242 DPRINT("Read %lu sectors of junk!\n",
1243 SectorCount
- SectorCnt
);
1245 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1254 // ------------------------------------------- Nondiscardable statics
1257 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1258 IN PSCSI_REQUEST_BLOCK Srb
)
1260 DPRINT1("AtapiSendAtapiComamnd() called!\n");
1261 DPRINT1("Not implemented yet!\n");
1262 return(SRB_STATUS_SELECTION_TIMEOUT
);
1267 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1268 IN PSCSI_REQUEST_BLOCK Srb
)
1270 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1272 DPRINT1("AtapiSendIdeCommand() called!\n");
1274 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1279 switch (Srb
->Cdb
[0])
1281 case SCSIOP_INQUIRY
:
1282 SrbStatus
= AtapiInquiry(DeviceExtension
,
1286 case SCSIOP_READ_CAPACITY
:
1287 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1293 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1297 case SCSIOP_MODE_SENSE
:
1298 case SCSIOP_TEST_UNIT_READY
:
1300 case SCSIOP_START_STOP_UNIT
:
1301 case SCSIOP_REQUEST_SENSE
:
1305 DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
1307 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1311 DPRINT1("AtapiSendIdeCommand() done!\n");
1318 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1319 PSCSI_REQUEST_BLOCK Srb
)
1321 PIDE_DRIVE_IDENTIFY DeviceParams
;
1322 PINQUIRYDATA InquiryData
;
1325 DPRINT1("SCSIOP_INQUIRY: TargetId: %lu\n", Srb
->TargetId
);
1327 if ((Srb
->PathId
!= 0) ||
1328 (Srb
->TargetId
> 1) ||
1330 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1332 return(SRB_STATUS_SELECTION_TIMEOUT
);
1335 InquiryData
= Srb
->DataBuffer
;
1336 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1339 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1341 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1344 /* set device class */
1345 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1348 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1352 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1354 InquiryData
->DeviceType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1357 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1358 if (DeviceParams
->ConfigBits
& 0x80)
1360 DPRINT1("Removable media!\n");
1361 InquiryData
->RemovableMedia
= 1;
1364 for (i
= 0; i
< 20; i
+= 2)
1366 InquiryData
->VendorId
[i
] =
1367 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1368 InquiryData
->VendorId
[i
+1] =
1369 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1372 for (i
= 0; i
< 4; i
++)
1374 InquiryData
->ProductId
[12+i
] = ' ';
1377 for (i
= 0; i
< 4; i
+= 2)
1379 InquiryData
->ProductRevisionLevel
[i
] =
1380 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1381 InquiryData
->ProductRevisionLevel
[i
+1] =
1382 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1385 return(SRB_STATUS_SUCCESS
);
1390 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1391 PSCSI_REQUEST_BLOCK Srb
)
1393 PREAD_CAPACITY_DATA CapacityData
;
1394 PIDE_DRIVE_IDENTIFY DeviceParams
;
1397 DPRINT1("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1399 if ((Srb
->PathId
!= 0) ||
1400 (Srb
->TargetId
> 1) ||
1402 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1404 return(SRB_STATUS_SELECTION_TIMEOUT
);
1408 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1409 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1411 /* Set sector (block) size to 512 bytes (big-endian). */
1412 CapacityData
->BytesPerBlock
= 0x20000;
1414 /* Calculate last sector (big-endian). */
1415 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1417 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1418 DeviceParams
->TMSectorCountLo
) - 1;
1422 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1423 DeviceParams
->LogicalHeads
*
1424 DeviceParams
->SectorsPerTrack
)-1;
1427 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1428 (((PUCHAR
)&LastSector
)[1] << 16) |
1429 (((PUCHAR
)&LastSector
)[2] << 8) |
1430 ((PUCHAR
)&LastSector
)[3];
1432 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1435 CapacityData
->LogicalBlockAddress
);
1437 return(SRB_STATUS_SUCCESS
);
1442 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1443 PSCSI_REQUEST_BLOCK Srb
)
1445 PIDE_DRIVE_IDENTIFY DeviceParams
;
1447 ULONG StartingSector
,i
;
1458 DPRINT1("AtapiReadWrite() called!\n");
1460 if ((Srb
->PathId
!= 0) ||
1461 (Srb
->TargetId
> 1) ||
1463 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1465 return(SRB_STATUS_SELECTION_TIMEOUT
);
1468 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1471 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1473 /* Get starting sector number from CDB. */
1474 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1475 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1476 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1477 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1479 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1480 DeviceParams
->BytesPerSector
;
1482 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1484 Srb
->DataTransferLength
,
1487 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1489 SectorNumber
= StartingSector
& 0xff;
1490 CylinderLow
= (StartingSector
>> 8) & 0xff;
1491 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1492 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1493 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1498 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1499 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1500 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1501 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1502 StartingSector
/= DeviceParams
->LogicalHeads
;
1503 CylinderLow
= StartingSector
& 0xff;
1504 CylinderHigh
= StartingSector
>> 8;
1508 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1510 Command
= IDE_CMD_READ
;
1514 Command
= IDE_CMD_WRITE
;
1517 if (DrvHead
& IDE_DH_LBA
)
1519 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1520 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1521 DeviceExtension
->CommandPortBase
,
1522 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1523 ((DrvHead
& 0x0f) << 24) +
1524 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1530 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1531 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1532 DeviceExtension
->CommandPortBase
,
1533 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1542 /* Set pointer to data buffer. */
1543 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1545 DeviceExtension
->CurrentSrb
= Srb
;
1546 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1550 /* wait for BUSY to clear */
1551 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1553 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1554 if (!(Status
& IDE_SR_BUSY
))
1558 ScsiPortStallExecution(10);
1560 DPRINT ("status=%02x\n", Status
);
1561 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1562 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1564 DPRINT ("Drive is BUSY for too long\n");
1565 return(SRB_STATUS_BUSY
);
1567 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1569 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1570 Irp
= ControllerExtension
->CurrentIrp
;
1571 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1572 Irp
->IoStatus
.Information
= 0;
1578 DPRINT ("Beginning drive reset sequence\n");
1579 IDEBeginControllerReset(ControllerExtension
);
1586 /* Select the desired drive */
1587 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1588 IDE_DH_FIXED
| DrvHead
);
1590 /* wait for BUSY to clear and DRDY to assert */
1591 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1593 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1594 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1598 ScsiPortStallExecution(10);
1600 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1601 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1603 DPRINT ("Drive is BUSY for too long after drive select\n");
1604 return(SRB_STATUS_BUSY
);
1606 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1608 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1609 Irp
= ControllerExtension
->CurrentIrp
;
1610 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1611 Irp
->IoStatus
.Information
= 0;
1617 DPRINT ("Beginning drive reset sequence\n");
1618 IDEBeginControllerReset(ControllerExtension
);
1625 if (Command
== IDE_CMD_WRITE
)
1627 DPRINT1("Write not implemented yet!\n");
1628 return(SRB_STATUS_SUCCESS
);
1631 /* Indicate expecting an interrupt. */
1632 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1634 /* Setup command parameters */
1635 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1636 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1637 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1638 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1639 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1640 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1642 /* Issue command to drive */
1643 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1644 // ControllerExtension->TimerState = IDETimerCmdWait;
1645 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1648 /* FIXME: Write data here! */
1651 DPRINT1("AtapiReadWrite() done!\n");
1653 /* Wait for interrupt. */
1654 return(SRB_STATUS_PENDING
);