1 /* $Id: atapi.c,v 1.7 2002/02/04 01:21:03 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
,
579 ScsiPortNotification(NextRequest
,
589 static BOOLEAN STDCALL
590 AtapiInterrupt(IN PVOID DeviceExtension
)
592 PATAPI_MINIPORT_EXTENSION DevExt
;
593 PSCSI_REQUEST_BLOCK Srb
;
594 ULONG CommandPortBase
;
595 ULONG ControlPortBase
;
598 BOOLEAN IsLastBlock
, AnErrorOccured
, RequestIsComplete
;
600 NTSTATUS ErrorStatus
;
601 ULONG ErrorInformation
;
602 PUCHAR TargetAddress
;
606 DPRINT1("AtapiInterrupt() called!\n");
608 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
609 Srb
= DevExt
->CurrentSrb
;
611 DPRINT1("Srb: %p\n", Srb
);
613 CommandPortBase
= DevExt
->CommandPortBase
;
614 ControlPortBase
= DevExt
->ControlPortBase
;
616 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
620 AnErrorOccured
= FALSE
;
621 RequestIsComplete
= FALSE
;
622 ErrorStatus
= STATUS_SUCCESS
;
623 ErrorInformation
= 0;
625 DeviceStatus
= IDEReadStatus(CommandPortBase
);
627 /* Handle error condition if it exists */
628 if (DeviceStatus
& IDE_SR_ERR
)
630 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
634 ErrorReg
= IDEReadError(CommandPortBase
);
635 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
636 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
637 DriveHead
= IDEReadDriveHead(CommandPortBase
);
638 SectorCount
= IDEReadSectorCount(CommandPortBase
);
639 SectorNum
= IDEReadSectorNum(CommandPortBase
);
641 /* FIXME: should use the NT error logging facility */
642 DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
643 0, //DeviceExtension->Operation,
651 /* FIXME: should retry the command and perhaps recalibrate the drive */
653 // Set error status information
654 AnErrorOccured
= TRUE
;
655 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
658 (((((((CylinderHigh
<< 8) + CylinderLow
) *
659 DeviceExtension
->LogicalHeads
) +
660 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
661 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
662 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
670 DPRINT1("SCSIOP_READ\n");
672 /* Update controller/device state variables */
673 TargetAddress
= Srb
->DataBuffer
;
674 Srb
->DataBuffer
+= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
675 Srb
->DataTransferLength
-= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
676 // DevExt->SectorsTransferred++;
678 /* Remember whether DRQ should be low at end (last block read) */
679 IsLastBlock
= Srb
->DataTransferLength
== 0;
681 /* Wait for DRQ assertion */
682 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
683 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
686 KeStallExecutionProcessor(10);
689 /* Copy the block of data */
690 IDEReadBlock(CommandPortBase
,
697 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
698 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
701 KeStallExecutionProcessor(10);
704 /* Check for data overrun */
705 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
707 AnErrorOccured
= TRUE
;
708 ErrorStatus
= STATUS_DATA_OVERRUN
;
709 ErrorInformation
= 0;
715 // Setup next transfer or set RequestIsComplete
716 if (DeviceExtension
->BytesRequested
>
717 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
719 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
720 DeviceExtension
->SectorsTransferred
= 0;
721 DeviceExtension
->BytesToTransfer
=
722 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
723 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
725 else if (DeviceExtension
->BytesRequested
> 0)
727 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
728 DeviceExtension
->SectorsTransferred
= 0;
729 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
730 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
734 RequestIsComplete
= TRUE
;
737 RequestIsComplete
= TRUE
;
743 DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
744 RequestIsComplete
= TRUE
;
750 /* If there was an error or the request is done, complete the packet */
751 if (AnErrorOccured
|| RequestIsComplete
)
754 /* Set the return status and info values */
755 Irp
= ControllerExtension
->CurrentIrp
;
756 Irp
->IoStatus
.Status
= ErrorStatus
;
757 Irp
->IoStatus
.Information
= ErrorInformation
;
759 /* Clear out controller fields */
760 ControllerExtension
->OperationInProgress
= FALSE
;
761 ControllerExtension
->DeviceStatus
= 0;
763 /* Queue the Dpc to finish up */
764 IoRequestDpc(DeviceExtension
->DeviceObject
,
766 ControllerExtension
);
769 else if (IsLastBlock
)
772 /* Else more data is needed, setup next device I/O */
773 IDEStartController((PVOID
)DeviceExtension
);
777 DPRINT1("AtapiInterrupt() done!\n");
787 // ---------------------------------------------------- Discardable statics
791 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
792 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
794 BOOLEAN DeviceFound
= FALSE
;
795 ULONG CommandPortBase
;
796 ULONG ControlPortBase
;
801 DPRINT("AtapiFindDevices() called\n");
803 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
804 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
805 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
807 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
808 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
809 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
811 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
813 /* disable interrupts */
814 IDEWriteDriveControl(CommandPortBase
,
818 IDEWriteDriveHead(CommandPortBase
,
819 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
820 ScsiPortStallExecution(500);
821 IDEWriteCylinderHigh(CommandPortBase
, 0);
822 IDEWriteCylinderLow(CommandPortBase
, 0);
823 IDEWriteCommand(CommandPortBase
, 0x08); /* IDE_COMMAND_ATAPI_RESET */
824 // ScsiPortStallExecution(1000*1000);
825 // IDEWriteDriveHead(CommandPortBase,
826 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
829 for (Retries
= 0; Retries
< 20000; Retries
++)
831 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
835 ScsiPortStallExecution(150);
837 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
839 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
843 High
= IDEReadCylinderHigh(CommandPortBase
);
844 Low
= IDEReadCylinderLow(CommandPortBase
);
846 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
851 if (High
== 0xEB && Low
== 0x14)
853 if (AtapiIdentifyDevice(CommandPortBase
,
857 &DeviceExtension
->DeviceParams
[UnitNumber
]))
859 DPRINT(" ATAPI drive found!\n");
860 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
861 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
866 DPRINT(" No ATAPI drive found!\n");
871 if (AtapiIdentifyDevice(CommandPortBase
,
875 &DeviceExtension
->DeviceParams
[UnitNumber
]))
877 DPRINT(" IDE drive found!\n");
878 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
879 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
884 DPRINT(" No IDE drive found!\n");
889 DPRINT("AtapiFindDrives() done\n");
895 // AtapiResetController
898 // Reset the controller and report completion status
904 // IN WORD CommandPort The address of the command port
905 // IN WORD ControlPort The address of the control port
911 AtapiResetController(IN WORD CommandPort
,
916 /* Assert drive reset line */
917 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
919 /* Wait for min. 25 microseconds */
920 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
922 /* Negate drive reset line */
923 IDEWriteDriveControl(ControlPort
, 0);
925 /* Wait for BUSY negation */
926 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
928 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
932 ScsiPortStallExecution(10);
936 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
943 // return TRUE if controller came back to life. and
944 // the registers are initialized correctly
945 return(IDEReadError(CommandPort
) == 1);
949 // AtapiIdentifyDevice
952 // Get the identification block from the drive
958 // IN int CommandPort Address of the command port
959 // IN int DriveNum The drive index (0,1)
960 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
963 // TRUE The drive identification block was retrieved successfully
967 AtapiIdentifyDevice(IN ULONG CommandPort
,
968 IN ULONG ControlPort
,
971 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
973 /* Get the Drive Identify block from drive or die */
974 if (AtapiPolledRead((WORD
)CommandPort
,
981 (DriveNum
? IDE_DH_DRV1
: 0),
982 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
983 (BYTE
*)DrvParms
) != 0) /* atapi_identify */
985 DPRINT1("IDEPolledRead() failed\n");
989 /* Report on drive parameters if debug mode */
990 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
991 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
992 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
993 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
994 DrvParms
->ConfigBits
,
995 DrvParms
->LogicalCyls
,
996 DrvParms
->LogicalHeads
,
997 DrvParms
->SectorsPerTrack
,
998 DrvParms
->InterSectorGap
,
999 DrvParms
->InterSectorGapSize
);
1000 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1001 DrvParms
->BytesInPLO
,
1002 DrvParms
->VendorUniqueCnt
,
1003 DrvParms
->SerialNumber
);
1004 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1005 DrvParms
->ControllerType
,
1006 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1007 DrvParms
->ECCByteCnt
,
1008 DrvParms
->FirmwareRev
);
1009 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1010 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1011 (DrvParms
->RWMultImplemented
) & 0xff,
1012 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1013 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1014 DrvParms
->MinPIOTransTime
,
1015 DrvParms
->MinDMATransTime
);
1016 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1017 DrvParms
->TMCylinders
,
1019 DrvParms
->TMSectorsPerTrk
,
1020 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1021 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1022 DrvParms
->TMSectorCountHi
,
1023 DrvParms
->TMSectorCountLo
,
1024 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1026 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1027 if (DrvParms
->BytesPerSector
== 0)
1028 DrvParms
->BytesPerSector
= 512;
1036 // Read a sector of data from the drive in a polled fashion.
1042 // IN WORD Address Address of command port for drive
1043 // IN BYTE PreComp Value to write to precomp register
1044 // IN BYTE SectorCnt Value to write to sectorCnt register
1045 // IN BYTE SectorNum Value to write to sectorNum register
1046 // IN BYTE CylinderLow Value to write to CylinderLow register
1047 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1048 // IN BYTE DrvHead Value to write to Drive/Head register
1049 // IN BYTE Command Value to write to Command register
1050 // OUT BYTE *Buffer Buffer for output data
1053 // int 0 is success, non 0 is an error code
1057 AtapiPolledRead(IN WORD Address
,
1058 IN WORD ControlPort
,
1062 IN BYTE CylinderLow
,
1063 IN BYTE CylinderHigh
,
1068 ULONG SectorCount
= 0;
1070 BOOLEAN Junk
= FALSE
;
1074 /* Disable interrupts */
1075 Control
= IDEReadAltStatus(ControlPort
);
1076 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1078 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1079 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1081 Status
= IDEReadStatus(Address
);
1082 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1086 ScsiPortStallExecution(10);
1088 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1090 return(IDE_ER_ABRT
);
1093 /* Write Drive/Head to select drive */
1094 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1096 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1097 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1099 Status
= IDEReadStatus(Address
);
1100 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1104 ScsiPortStallExecution(10);
1106 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1111 /* Issue command to drive */
1112 if (DrvHead
& IDE_DH_LBA
)
1114 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1115 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1116 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1122 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1123 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1132 /* Setup command parameters */
1133 IDEWritePrecomp(Address
, PreComp
);
1134 IDEWriteSectorCount(Address
, SectorCnt
);
1135 IDEWriteSectorNum(Address
, SectorNum
);
1136 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1137 IDEWriteCylinderLow(Address
, CylinderLow
);
1138 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1140 /* Issue the command */
1141 IDEWriteCommand(Address
, Command
);
1142 ScsiPortStallExecution(50);
1144 /* wait for DRQ or error */
1145 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1147 Status
= IDEReadStatus(Address
);
1148 if (!(Status
& IDE_SR_BUSY
))
1150 if (Status
& IDE_SR_ERR
)
1152 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1153 return(IDE_ER_ABRT
);
1155 if (Status
& IDE_SR_DRQ
)
1161 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1162 return(IDE_ER_ABRT
);
1165 ScsiPortStallExecution(10);
1169 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1171 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1172 return(IDE_ER_ABRT
);
1177 /* Read data into buffer */
1180 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1181 Buffer
+= IDE_SECTOR_BUF_SZ
;
1185 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1186 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1190 /* Check for error or more sectors to read */
1191 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1193 Status
= IDEReadStatus(Address
);
1194 if (!(Status
& IDE_SR_BUSY
))
1196 if (Status
& IDE_SR_ERR
)
1198 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1199 return(IDE_ER_ABRT
);
1201 if (Status
& IDE_SR_DRQ
)
1203 if (SectorCount
>= SectorCnt
)
1205 DPRINT("Buffer size exceeded!\n");
1212 if (SectorCount
> SectorCnt
)
1214 DPRINT("Read %lu sectors of junk!\n",
1215 SectorCount
- SectorCnt
);
1217 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1226 // ------------------------------------------- Nondiscardable statics
1229 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1230 IN PSCSI_REQUEST_BLOCK Srb
)
1232 DPRINT1("AtapiSendAtapiComamnd() called!\n");
1233 DPRINT1("Not implemented yet!\n");
1234 return(SRB_STATUS_SELECTION_TIMEOUT
);
1239 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1240 IN PSCSI_REQUEST_BLOCK Srb
)
1242 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1244 DPRINT("AtapiSendIdeCommand() called!\n");
1246 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1251 switch (Srb
->Cdb
[0])
1253 case SCSIOP_INQUIRY
:
1254 SrbStatus
= AtapiInquiry(DeviceExtension
,
1258 case SCSIOP_READ_CAPACITY
:
1259 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1265 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1269 case SCSIOP_MODE_SENSE
:
1270 case SCSIOP_TEST_UNIT_READY
:
1272 case SCSIOP_START_STOP_UNIT
:
1273 case SCSIOP_REQUEST_SENSE
:
1277 DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
1279 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1283 DPRINT("AtapiSendIdeCommand() done!\n");
1290 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1291 PSCSI_REQUEST_BLOCK Srb
)
1293 PIDE_DRIVE_IDENTIFY DeviceParams
;
1294 PINQUIRYDATA InquiryData
;
1297 DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb
->TargetId
);
1299 if ((Srb
->PathId
!= 0) ||
1300 (Srb
->TargetId
> 1) ||
1302 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1304 return(SRB_STATUS_SELECTION_TIMEOUT
);
1307 InquiryData
= Srb
->DataBuffer
;
1308 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1311 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1313 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1316 /* set device class */
1317 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1320 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1324 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1326 InquiryData
->DeviceType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1329 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1330 if (DeviceParams
->ConfigBits
& 0x80)
1332 DPRINT1("Removable media!\n");
1333 InquiryData
->RemovableMedia
= 1;
1336 for (i
= 0; i
< 20; i
+= 2)
1338 InquiryData
->VendorId
[i
] =
1339 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1340 InquiryData
->VendorId
[i
+1] =
1341 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1344 for (i
= 0; i
< 4; i
++)
1346 InquiryData
->ProductId
[12+i
] = ' ';
1349 for (i
= 0; i
< 4; i
+= 2)
1351 InquiryData
->ProductRevisionLevel
[i
] =
1352 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1353 InquiryData
->ProductRevisionLevel
[i
+1] =
1354 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1357 return(SRB_STATUS_SUCCESS
);
1362 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1363 PSCSI_REQUEST_BLOCK Srb
)
1365 PREAD_CAPACITY_DATA CapacityData
;
1366 PIDE_DRIVE_IDENTIFY DeviceParams
;
1369 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1371 if ((Srb
->PathId
!= 0) ||
1372 (Srb
->TargetId
> 1) ||
1374 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1376 return(SRB_STATUS_SELECTION_TIMEOUT
);
1380 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1381 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1383 /* Set sector (block) size to 512 bytes (big-endian). */
1384 CapacityData
->BytesPerBlock
= 0x20000;
1386 /* Calculate last sector (big-endian). */
1387 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1389 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1390 DeviceParams
->TMSectorCountLo
) - 1;
1394 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1395 DeviceParams
->LogicalHeads
*
1396 DeviceParams
->SectorsPerTrack
)-1;
1399 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1400 (((PUCHAR
)&LastSector
)[1] << 16) |
1401 (((PUCHAR
)&LastSector
)[2] << 8) |
1402 ((PUCHAR
)&LastSector
)[3];
1404 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1407 CapacityData
->LogicalBlockAddress
);
1409 return(SRB_STATUS_SUCCESS
);
1414 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1415 PSCSI_REQUEST_BLOCK Srb
)
1417 PIDE_DRIVE_IDENTIFY DeviceParams
;
1419 ULONG StartingSector
,i
;
1430 DPRINT("AtapiReadWrite() called!\n");
1432 if ((Srb
->PathId
!= 0) ||
1433 (Srb
->TargetId
> 1) ||
1435 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1437 return(SRB_STATUS_SELECTION_TIMEOUT
);
1440 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1443 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1445 /* Get starting sector number from CDB. */
1446 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1447 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1448 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1449 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1451 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1452 DeviceParams
->BytesPerSector
;
1454 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1456 Srb
->DataTransferLength
,
1459 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1461 SectorNumber
= StartingSector
& 0xff;
1462 CylinderLow
= (StartingSector
>> 8) & 0xff;
1463 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1464 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1465 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1470 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1471 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1472 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1473 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1474 StartingSector
/= DeviceParams
->LogicalHeads
;
1475 CylinderLow
= StartingSector
& 0xff;
1476 CylinderHigh
= StartingSector
>> 8;
1480 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1482 Command
= IDE_CMD_READ
;
1486 Command
= IDE_CMD_WRITE
;
1489 if (DrvHead
& IDE_DH_LBA
)
1491 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1492 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1493 DeviceExtension
->CommandPortBase
,
1494 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1495 ((DrvHead
& 0x0f) << 24) +
1496 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1502 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1503 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1504 DeviceExtension
->CommandPortBase
,
1505 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1514 /* Set pointer to data buffer. */
1515 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1517 DeviceExtension
->CurrentSrb
= Srb
;
1518 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1522 /* wait for BUSY to clear */
1523 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1525 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1526 if (!(Status
& IDE_SR_BUSY
))
1530 ScsiPortStallExecution(10);
1532 DPRINT ("status=%02x\n", Status
);
1533 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1534 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1536 DPRINT ("Drive is BUSY for too long\n");
1537 return(SRB_STATUS_BUSY
);
1539 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1541 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1542 Irp
= ControllerExtension
->CurrentIrp
;
1543 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1544 Irp
->IoStatus
.Information
= 0;
1550 DPRINT ("Beginning drive reset sequence\n");
1551 IDEBeginControllerReset(ControllerExtension
);
1558 /* Select the desired drive */
1559 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1560 IDE_DH_FIXED
| DrvHead
);
1562 /* wait for BUSY to clear and DRDY to assert */
1563 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1565 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1566 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1570 ScsiPortStallExecution(10);
1572 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1573 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1575 DPRINT ("Drive is BUSY for too long after drive select\n");
1576 return(SRB_STATUS_BUSY
);
1578 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1580 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1581 Irp
= ControllerExtension
->CurrentIrp
;
1582 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1583 Irp
->IoStatus
.Information
= 0;
1589 DPRINT ("Beginning drive reset sequence\n");
1590 IDEBeginControllerReset(ControllerExtension
);
1597 if (Command
== IDE_CMD_WRITE
)
1599 DPRINT1("Write not implemented yet!\n");
1600 return(SRB_STATUS_SUCCESS
);
1603 /* Indicate expecting an interrupt. */
1604 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1606 /* Setup command parameters */
1607 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1608 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1609 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1610 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1611 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1612 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1614 /* Issue command to drive */
1615 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1616 // ControllerExtension->TimerState = IDETimerCmdWait;
1617 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1620 /* FIXME: Write data here! */
1623 DPRINT("AtapiReadWrite() done!\n");
1625 /* Wait for interrupt. */
1626 return(SRB_STATUS_PENDING
);