1 /* $Id: atapi.c,v 1.9 2002/03/04 22:31:06 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 Srb
= DevExt
->CurrentSrb
;
620 DPRINT("Srb: %p\n", Srb
);
622 CommandPortBase
= DevExt
->CommandPortBase
;
623 ControlPortBase
= DevExt
->ControlPortBase
;
625 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
629 AnErrorOccured
= FALSE
;
630 RequestIsComplete
= FALSE
;
631 ErrorStatus
= STATUS_SUCCESS
;
632 ErrorInformation
= 0;
634 DeviceStatus
= IDEReadStatus(CommandPortBase
);
636 /* Handle error condition if it exists */
637 if (DeviceStatus
& IDE_SR_ERR
)
639 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
643 ErrorReg
= IDEReadError(CommandPortBase
);
644 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
645 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
646 DriveHead
= IDEReadDriveHead(CommandPortBase
);
647 SectorCount
= IDEReadSectorCount(CommandPortBase
);
648 SectorNum
= IDEReadSectorNum(CommandPortBase
);
650 /* FIXME: should use the NT error logging facility */
651 DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
652 0, //DeviceExtension->Operation,
660 /* FIXME: should retry the command and perhaps recalibrate the drive */
662 // Set error status information
663 AnErrorOccured
= TRUE
;
664 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
667 (((((((CylinderHigh
<< 8) + CylinderLow
) *
668 DeviceExtension
->LogicalHeads
) +
669 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
670 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
671 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
679 DPRINT("SCSIOP_READ\n");
681 /* Update controller/device state variables */
682 TargetAddress
= Srb
->DataBuffer
;
683 Srb
->DataBuffer
+= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
684 Srb
->DataTransferLength
-= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
685 // DevExt->SectorsTransferred++;
687 /* Remember whether DRQ should be low at end (last block read) */
688 IsLastBlock
= (Srb
->DataTransferLength
== 0);
689 DPRINT("IsLastBlock == %s\n", (IsLastBlock
)?"TRUE":"FALSE");
691 /* Wait for DRQ assertion */
692 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
693 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
696 KeStallExecutionProcessor(10);
699 /* Copy the block of data */
700 IDEReadBlock(CommandPortBase
,
707 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
708 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
711 KeStallExecutionProcessor(10);
714 /* Check for data overrun */
715 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
717 AnErrorOccured
= TRUE
;
718 ErrorStatus
= STATUS_DATA_OVERRUN
;
719 ErrorInformation
= 0;
725 // Setup next transfer or set RequestIsComplete
726 if (DeviceExtension
->BytesRequested
>
727 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
)
729 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
730 DeviceExtension
->SectorsTransferred
= 0;
731 DeviceExtension
->BytesToTransfer
=
732 DeviceExtension
->BytesPerSector
* IDE_MAX_SECTORS_PER_XFER
;
733 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
735 else if (DeviceExtension
->BytesRequested
> 0)
737 DeviceExtension
->StartingSector
+= DeviceExtension
->SectorsTransferred
;
738 DeviceExtension
->SectorsTransferred
= 0;
739 DeviceExtension
->BytesToTransfer
= DeviceExtension
->BytesRequested
;
740 DeviceExtension
->BytesRequested
-= DeviceExtension
->BytesToTransfer
;
744 RequestIsComplete
= TRUE
;
747 RequestIsComplete
= TRUE
;
753 DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
754 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
);
790 DevExt
->ExpectingInterrupt
= FALSE
;
792 ScsiPortNotification(RequestComplete
,
796 ScsiPortNotification(NextRequest
,
802 DPRINT("AtapiInterrupt() done!\n");
812 // ---------------------------------------------------- Discardable statics
816 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
817 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
819 BOOLEAN DeviceFound
= FALSE
;
820 ULONG CommandPortBase
;
821 ULONG ControlPortBase
;
826 DPRINT("AtapiFindDevices() called\n");
828 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
829 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
830 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
832 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
833 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
834 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
836 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
838 /* disable interrupts */
839 IDEWriteDriveControl(ControlPortBase
,
843 IDEWriteDriveHead(CommandPortBase
,
844 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
845 ScsiPortStallExecution(500);
846 IDEWriteCylinderHigh(CommandPortBase
, 0);
847 IDEWriteCylinderLow(CommandPortBase
, 0);
848 IDEWriteCommand(CommandPortBase
, 0x08); /* IDE_COMMAND_ATAPI_RESET */
849 // ScsiPortStallExecution(1000*1000);
850 // IDEWriteDriveHead(CommandPortBase,
851 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
854 for (Retries
= 0; Retries
< 20000; Retries
++)
856 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
860 ScsiPortStallExecution(150);
862 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
864 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
868 High
= IDEReadCylinderHigh(CommandPortBase
);
869 Low
= IDEReadCylinderLow(CommandPortBase
);
871 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
876 if (High
== 0xEB && Low
== 0x14)
878 if (AtapiIdentifyDevice(CommandPortBase
,
882 &DeviceExtension
->DeviceParams
[UnitNumber
]))
884 DPRINT(" ATAPI drive found!\n");
885 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
886 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
891 DPRINT(" No ATAPI drive found!\n");
896 if (AtapiIdentifyDevice(CommandPortBase
,
900 &DeviceExtension
->DeviceParams
[UnitNumber
]))
902 DPRINT(" IDE drive found!\n");
903 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
904 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
909 DPRINT(" No IDE drive found!\n");
914 DPRINT("AtapiFindDrives() done\n");
920 // AtapiResetController
923 // Reset the controller and report completion status
929 // IN WORD CommandPort The address of the command port
930 // IN WORD ControlPort The address of the control port
936 AtapiResetController(IN WORD CommandPort
,
941 /* Assert drive reset line */
942 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
944 /* Wait for min. 25 microseconds */
945 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
947 /* Negate drive reset line */
948 IDEWriteDriveControl(ControlPort
, 0);
950 /* Wait for BUSY negation */
951 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
953 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
957 ScsiPortStallExecution(10);
961 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
968 // return TRUE if controller came back to life. and
969 // the registers are initialized correctly
970 return(IDEReadError(CommandPort
) == 1);
974 * AtapiIdentifyDevice
977 * Get the identification block from the drive
984 * Address of the command port
986 * Address of the control port
988 * The drive index (0,1)
990 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
992 * Address to write drive ident block
995 * TRUE: The drive identification block was retrieved successfully
996 * FALSE: an error ocurred
1000 AtapiIdentifyDevice(IN ULONG CommandPort
,
1001 IN ULONG ControlPort
,
1004 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1006 /* Get the Drive Identify block from drive or die */
1007 if (AtapiPolledRead((WORD
)CommandPort
,
1014 (DriveNum
? IDE_DH_DRV1
: 0),
1015 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1016 (BYTE
*)DrvParms
) != 0) /* atapi_identify */
1018 DPRINT1("IDEPolledRead() failed\n");
1022 /* Report on drive parameters if debug mode */
1023 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1024 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1025 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1026 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1027 DrvParms
->ConfigBits
,
1028 DrvParms
->LogicalCyls
,
1029 DrvParms
->LogicalHeads
,
1030 DrvParms
->SectorsPerTrack
,
1031 DrvParms
->InterSectorGap
,
1032 DrvParms
->InterSectorGapSize
);
1033 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1034 DrvParms
->BytesInPLO
,
1035 DrvParms
->VendorUniqueCnt
,
1036 DrvParms
->SerialNumber
);
1037 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1038 DrvParms
->ControllerType
,
1039 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1040 DrvParms
->ECCByteCnt
,
1041 DrvParms
->FirmwareRev
);
1042 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1043 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1044 (DrvParms
->RWMultImplemented
) & 0xff,
1045 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1046 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1047 DrvParms
->MinPIOTransTime
,
1048 DrvParms
->MinDMATransTime
);
1049 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1050 DrvParms
->TMCylinders
,
1052 DrvParms
->TMSectorsPerTrk
,
1053 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1054 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1055 DrvParms
->TMSectorCountHi
,
1056 DrvParms
->TMSectorCountLo
,
1057 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1059 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1060 if (DrvParms
->BytesPerSector
== 0)
1061 DrvParms
->BytesPerSector
= 512;
1069 // Read a sector of data from the drive in a polled fashion.
1075 // IN WORD Address Address of command port for drive
1076 // IN BYTE PreComp Value to write to precomp register
1077 // IN BYTE SectorCnt Value to write to sectorCnt register
1078 // IN BYTE SectorNum Value to write to sectorNum register
1079 // IN BYTE CylinderLow Value to write to CylinderLow register
1080 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1081 // IN BYTE DrvHead Value to write to Drive/Head register
1082 // IN BYTE Command Value to write to Command register
1083 // OUT BYTE *Buffer Buffer for output data
1086 // int 0 is success, non 0 is an error code
1090 AtapiPolledRead(IN WORD Address
,
1091 IN WORD ControlPort
,
1095 IN BYTE CylinderLow
,
1096 IN BYTE CylinderHigh
,
1101 ULONG SectorCount
= 0;
1103 BOOLEAN Junk
= FALSE
;
1107 /* Disable interrupts */
1108 Control
= IDEReadAltStatus(ControlPort
);
1109 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1111 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1112 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1114 Status
= IDEReadStatus(Address
);
1115 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1119 ScsiPortStallExecution(10);
1121 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1123 return(IDE_ER_ABRT
);
1126 /* Write Drive/Head to select drive */
1127 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1129 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1130 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1132 Status
= IDEReadStatus(Address
);
1133 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1137 ScsiPortStallExecution(10);
1139 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1144 /* Issue command to drive */
1145 if (DrvHead
& IDE_DH_LBA
)
1147 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1148 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1149 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1155 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1156 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1165 /* Setup command parameters */
1166 IDEWritePrecomp(Address
, PreComp
);
1167 IDEWriteSectorCount(Address
, SectorCnt
);
1168 IDEWriteSectorNum(Address
, SectorNum
);
1169 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1170 IDEWriteCylinderLow(Address
, CylinderLow
);
1171 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1173 /* Issue the command */
1174 IDEWriteCommand(Address
, Command
);
1175 ScsiPortStallExecution(50);
1177 /* wait for DRQ or error */
1178 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1180 Status
= IDEReadStatus(Address
);
1181 if (!(Status
& IDE_SR_BUSY
))
1183 if (Status
& IDE_SR_ERR
)
1185 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1186 return(IDE_ER_ABRT
);
1188 if (Status
& IDE_SR_DRQ
)
1194 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1195 return(IDE_ER_ABRT
);
1198 ScsiPortStallExecution(10);
1202 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1204 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1205 return(IDE_ER_ABRT
);
1210 /* Read data into buffer */
1213 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1214 Buffer
+= IDE_SECTOR_BUF_SZ
;
1218 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1219 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1223 /* Check for error or more sectors to read */
1224 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1226 Status
= IDEReadStatus(Address
);
1227 if (!(Status
& IDE_SR_BUSY
))
1229 if (Status
& IDE_SR_ERR
)
1231 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1232 return(IDE_ER_ABRT
);
1234 if (Status
& IDE_SR_DRQ
)
1236 if (SectorCount
>= SectorCnt
)
1238 DPRINT("Buffer size exceeded!\n");
1245 if (SectorCount
> SectorCnt
)
1247 DPRINT("Read %lu sectors of junk!\n",
1248 SectorCount
- SectorCnt
);
1250 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1259 // ------------------------------------------- Nondiscardable statics
1262 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1263 IN PSCSI_REQUEST_BLOCK Srb
)
1265 DPRINT1("AtapiSendAtapiComamnd() called!\n");
1266 DPRINT1("Not implemented yet!\n");
1267 return(SRB_STATUS_SELECTION_TIMEOUT
);
1272 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1273 IN PSCSI_REQUEST_BLOCK Srb
)
1275 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1277 DPRINT1("AtapiSendIdeCommand() called!\n");
1279 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1284 switch (Srb
->Cdb
[0])
1286 case SCSIOP_INQUIRY
:
1287 SrbStatus
= AtapiInquiry(DeviceExtension
,
1291 case SCSIOP_READ_CAPACITY
:
1292 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1298 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1302 case SCSIOP_MODE_SENSE
:
1303 case SCSIOP_TEST_UNIT_READY
:
1305 case SCSIOP_START_STOP_UNIT
:
1306 case SCSIOP_REQUEST_SENSE
:
1310 DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
1312 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1316 DPRINT1("AtapiSendIdeCommand() done!\n");
1323 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1324 PSCSI_REQUEST_BLOCK Srb
)
1326 PIDE_DRIVE_IDENTIFY DeviceParams
;
1327 PINQUIRYDATA InquiryData
;
1330 DPRINT1("SCSIOP_INQUIRY: TargetId: %lu\n", Srb
->TargetId
);
1332 if ((Srb
->PathId
!= 0) ||
1333 (Srb
->TargetId
> 1) ||
1335 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1337 return(SRB_STATUS_SELECTION_TIMEOUT
);
1340 InquiryData
= Srb
->DataBuffer
;
1341 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1344 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1346 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1349 /* set device class */
1350 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1353 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1357 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1359 InquiryData
->DeviceType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1362 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1363 if (DeviceParams
->ConfigBits
& 0x80)
1365 DPRINT1("Removable media!\n");
1366 InquiryData
->RemovableMedia
= 1;
1369 for (i
= 0; i
< 20; i
+= 2)
1371 InquiryData
->VendorId
[i
] =
1372 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1373 InquiryData
->VendorId
[i
+1] =
1374 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1377 for (i
= 0; i
< 4; i
++)
1379 InquiryData
->ProductId
[12+i
] = ' ';
1382 for (i
= 0; i
< 4; i
+= 2)
1384 InquiryData
->ProductRevisionLevel
[i
] =
1385 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1386 InquiryData
->ProductRevisionLevel
[i
+1] =
1387 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1390 return(SRB_STATUS_SUCCESS
);
1395 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1396 PSCSI_REQUEST_BLOCK Srb
)
1398 PREAD_CAPACITY_DATA CapacityData
;
1399 PIDE_DRIVE_IDENTIFY DeviceParams
;
1402 DPRINT1("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1404 if ((Srb
->PathId
!= 0) ||
1405 (Srb
->TargetId
> 1) ||
1407 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1409 return(SRB_STATUS_SELECTION_TIMEOUT
);
1413 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1414 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1416 /* Set sector (block) size to 512 bytes (big-endian). */
1417 CapacityData
->BytesPerBlock
= 0x20000;
1419 /* Calculate last sector (big-endian). */
1420 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1422 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1423 DeviceParams
->TMSectorCountLo
) - 1;
1427 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1428 DeviceParams
->LogicalHeads
*
1429 DeviceParams
->SectorsPerTrack
)-1;
1432 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1433 (((PUCHAR
)&LastSector
)[1] << 16) |
1434 (((PUCHAR
)&LastSector
)[2] << 8) |
1435 ((PUCHAR
)&LastSector
)[3];
1437 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1440 CapacityData
->LogicalBlockAddress
);
1442 return(SRB_STATUS_SUCCESS
);
1447 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1448 PSCSI_REQUEST_BLOCK Srb
)
1450 PIDE_DRIVE_IDENTIFY DeviceParams
;
1452 ULONG StartingSector
,i
;
1463 DPRINT1("AtapiReadWrite() called!\n");
1465 if ((Srb
->PathId
!= 0) ||
1466 (Srb
->TargetId
> 1) ||
1468 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1470 return(SRB_STATUS_SELECTION_TIMEOUT
);
1473 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1476 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1478 /* Get starting sector number from CDB. */
1479 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1480 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1481 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1482 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1484 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1485 DeviceParams
->BytesPerSector
;
1487 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1489 Srb
->DataTransferLength
,
1492 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1494 SectorNumber
= StartingSector
& 0xff;
1495 CylinderLow
= (StartingSector
>> 8) & 0xff;
1496 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1497 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1498 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1503 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1504 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1505 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1506 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1507 StartingSector
/= DeviceParams
->LogicalHeads
;
1508 CylinderLow
= StartingSector
& 0xff;
1509 CylinderHigh
= StartingSector
>> 8;
1513 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1515 Command
= IDE_CMD_READ
;
1519 Command
= IDE_CMD_WRITE
;
1522 if (DrvHead
& IDE_DH_LBA
)
1524 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1525 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1526 DeviceExtension
->CommandPortBase
,
1527 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1528 ((DrvHead
& 0x0f) << 24) +
1529 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1535 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1536 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1537 DeviceExtension
->CommandPortBase
,
1538 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1547 /* Set pointer to data buffer. */
1548 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1550 DeviceExtension
->CurrentSrb
= Srb
;
1551 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1555 /* wait for BUSY to clear */
1556 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1558 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1559 if (!(Status
& IDE_SR_BUSY
))
1563 ScsiPortStallExecution(10);
1565 DPRINT ("status=%02x\n", Status
);
1566 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1567 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1569 DPRINT ("Drive is BUSY for too long\n");
1570 return(SRB_STATUS_BUSY
);
1572 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1574 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1575 Irp
= ControllerExtension
->CurrentIrp
;
1576 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1577 Irp
->IoStatus
.Information
= 0;
1583 DPRINT ("Beginning drive reset sequence\n");
1584 IDEBeginControllerReset(ControllerExtension
);
1591 /* Select the desired drive */
1592 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1593 IDE_DH_FIXED
| DrvHead
);
1595 /* wait for BUSY to clear and DRDY to assert */
1596 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1598 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1599 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1603 ScsiPortStallExecution(10);
1605 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1606 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1608 DPRINT ("Drive is BUSY for too long after drive select\n");
1609 return(SRB_STATUS_BUSY
);
1611 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1613 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1614 Irp
= ControllerExtension
->CurrentIrp
;
1615 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1616 Irp
->IoStatus
.Information
= 0;
1622 DPRINT ("Beginning drive reset sequence\n");
1623 IDEBeginControllerReset(ControllerExtension
);
1630 if (Command
== IDE_CMD_WRITE
)
1632 DPRINT1("Write not implemented yet!\n");
1633 return(SRB_STATUS_SUCCESS
);
1636 /* Indicate expecting an interrupt. */
1637 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1639 /* Setup command parameters */
1640 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1641 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1642 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1643 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1644 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1645 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1647 /* Issue command to drive */
1648 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1649 // ControllerExtension->TimerState = IDETimerCmdWait;
1650 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1653 /* FIXME: Write data here! */
1656 DPRINT1("AtapiReadWrite() done!\n");
1658 /* Wait for interrupt. */
1659 return(SRB_STATUS_PENDING
);