1 /* $Id: atapi.c,v 1.10 2002/03/05 00:05:28 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
,
801 DPRINT("AtapiInterrupt() done!\n");
811 // ---------------------------------------------------- Discardable statics
815 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
816 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
818 BOOLEAN DeviceFound
= FALSE
;
819 ULONG CommandPortBase
;
820 ULONG ControlPortBase
;
825 DPRINT("AtapiFindDevices() called\n");
827 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
828 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
829 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
831 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
832 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
833 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
835 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
837 /* disable interrupts */
838 IDEWriteDriveControl(ControlPortBase
,
842 IDEWriteDriveHead(CommandPortBase
,
843 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
844 ScsiPortStallExecution(500);
845 IDEWriteCylinderHigh(CommandPortBase
, 0);
846 IDEWriteCylinderLow(CommandPortBase
, 0);
847 IDEWriteCommand(CommandPortBase
, 0x08); /* IDE_COMMAND_ATAPI_RESET */
848 // ScsiPortStallExecution(1000*1000);
849 // IDEWriteDriveHead(CommandPortBase,
850 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
853 for (Retries
= 0; Retries
< 20000; Retries
++)
855 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
859 ScsiPortStallExecution(150);
861 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
863 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
867 High
= IDEReadCylinderHigh(CommandPortBase
);
868 Low
= IDEReadCylinderLow(CommandPortBase
);
870 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
875 if (High
== 0xEB && Low
== 0x14)
877 if (AtapiIdentifyDevice(CommandPortBase
,
881 &DeviceExtension
->DeviceParams
[UnitNumber
]))
883 DPRINT(" ATAPI drive found!\n");
884 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
885 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
890 DPRINT(" No ATAPI drive found!\n");
895 if (AtapiIdentifyDevice(CommandPortBase
,
899 &DeviceExtension
->DeviceParams
[UnitNumber
]))
901 DPRINT(" IDE drive found!\n");
902 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
903 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
908 DPRINT(" No IDE drive found!\n");
913 DPRINT("AtapiFindDrives() done\n");
919 // AtapiResetController
922 // Reset the controller and report completion status
928 // IN WORD CommandPort The address of the command port
929 // IN WORD ControlPort The address of the control port
935 AtapiResetController(IN WORD CommandPort
,
940 /* Assert drive reset line */
941 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
943 /* Wait for min. 25 microseconds */
944 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
946 /* Negate drive reset line */
947 IDEWriteDriveControl(ControlPort
, 0);
949 /* Wait for BUSY negation */
950 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
952 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
956 ScsiPortStallExecution(10);
960 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
967 // return TRUE if controller came back to life. and
968 // the registers are initialized correctly
969 return(IDEReadError(CommandPort
) == 1);
973 * AtapiIdentifyDevice
976 * Get the identification block from the drive
983 * Address of the command port
985 * Address of the control port
987 * The drive index (0,1)
989 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
991 * Address to write drive ident block
994 * TRUE: The drive identification block was retrieved successfully
995 * FALSE: an error ocurred
999 AtapiIdentifyDevice(IN ULONG CommandPort
,
1000 IN ULONG ControlPort
,
1003 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1005 /* Get the Drive Identify block from drive or die */
1006 if (AtapiPolledRead((WORD
)CommandPort
,
1013 (DriveNum
? IDE_DH_DRV1
: 0),
1014 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1015 (BYTE
*)DrvParms
) != 0) /* atapi_identify */
1017 DPRINT1("IDEPolledRead() failed\n");
1021 /* Report on drive parameters if debug mode */
1022 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1023 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1024 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1025 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1026 DrvParms
->ConfigBits
,
1027 DrvParms
->LogicalCyls
,
1028 DrvParms
->LogicalHeads
,
1029 DrvParms
->SectorsPerTrack
,
1030 DrvParms
->InterSectorGap
,
1031 DrvParms
->InterSectorGapSize
);
1032 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1033 DrvParms
->BytesInPLO
,
1034 DrvParms
->VendorUniqueCnt
,
1035 DrvParms
->SerialNumber
);
1036 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1037 DrvParms
->ControllerType
,
1038 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1039 DrvParms
->ECCByteCnt
,
1040 DrvParms
->FirmwareRev
);
1041 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1042 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1043 (DrvParms
->RWMultImplemented
) & 0xff,
1044 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1045 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1046 DrvParms
->MinPIOTransTime
,
1047 DrvParms
->MinDMATransTime
);
1048 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1049 DrvParms
->TMCylinders
,
1051 DrvParms
->TMSectorsPerTrk
,
1052 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1053 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1054 DrvParms
->TMSectorCountHi
,
1055 DrvParms
->TMSectorCountLo
,
1056 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1058 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1059 if (DrvParms
->BytesPerSector
== 0)
1060 DrvParms
->BytesPerSector
= 512;
1068 // Read a sector of data from the drive in a polled fashion.
1074 // IN WORD Address Address of command port for drive
1075 // IN BYTE PreComp Value to write to precomp register
1076 // IN BYTE SectorCnt Value to write to sectorCnt register
1077 // IN BYTE SectorNum Value to write to sectorNum register
1078 // IN BYTE CylinderLow Value to write to CylinderLow register
1079 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1080 // IN BYTE DrvHead Value to write to Drive/Head register
1081 // IN BYTE Command Value to write to Command register
1082 // OUT BYTE *Buffer Buffer for output data
1085 // int 0 is success, non 0 is an error code
1089 AtapiPolledRead(IN WORD Address
,
1090 IN WORD ControlPort
,
1094 IN BYTE CylinderLow
,
1095 IN BYTE CylinderHigh
,
1100 ULONG SectorCount
= 0;
1102 BOOLEAN Junk
= FALSE
;
1106 /* Disable interrupts */
1107 Control
= IDEReadAltStatus(ControlPort
);
1108 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1110 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1111 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1113 Status
= IDEReadStatus(Address
);
1114 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1118 ScsiPortStallExecution(10);
1120 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1122 return(IDE_ER_ABRT
);
1125 /* Write Drive/Head to select drive */
1126 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1128 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1129 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1131 Status
= IDEReadStatus(Address
);
1132 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1136 ScsiPortStallExecution(10);
1138 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1143 /* Issue command to drive */
1144 if (DrvHead
& IDE_DH_LBA
)
1146 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1147 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1148 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1154 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1155 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1164 /* Setup command parameters */
1165 IDEWritePrecomp(Address
, PreComp
);
1166 IDEWriteSectorCount(Address
, SectorCnt
);
1167 IDEWriteSectorNum(Address
, SectorNum
);
1168 IDEWriteCylinderHigh(Address
, CylinderHigh
);
1169 IDEWriteCylinderLow(Address
, CylinderLow
);
1170 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
1172 /* Issue the command */
1173 IDEWriteCommand(Address
, Command
);
1174 ScsiPortStallExecution(50);
1176 /* wait for DRQ or error */
1177 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1179 Status
= IDEReadStatus(Address
);
1180 if (!(Status
& IDE_SR_BUSY
))
1182 if (Status
& IDE_SR_ERR
)
1184 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1185 return(IDE_ER_ABRT
);
1187 if (Status
& IDE_SR_DRQ
)
1193 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1194 return(IDE_ER_ABRT
);
1197 ScsiPortStallExecution(10);
1201 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1203 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1204 return(IDE_ER_ABRT
);
1209 /* Read data into buffer */
1212 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1213 Buffer
+= IDE_SECTOR_BUF_SZ
;
1217 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1218 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1222 /* Check for error or more sectors to read */
1223 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1225 Status
= IDEReadStatus(Address
);
1226 if (!(Status
& IDE_SR_BUSY
))
1228 if (Status
& IDE_SR_ERR
)
1230 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1231 return(IDE_ER_ABRT
);
1233 if (Status
& IDE_SR_DRQ
)
1235 if (SectorCount
>= SectorCnt
)
1237 DPRINT("Buffer size exceeded!\n");
1244 if (SectorCount
> SectorCnt
)
1246 DPRINT("Read %lu sectors of junk!\n",
1247 SectorCount
- SectorCnt
);
1249 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1258 // ------------------------------------------- Nondiscardable statics
1261 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1262 IN PSCSI_REQUEST_BLOCK Srb
)
1264 DPRINT1("AtapiSendAtapiComamnd() called!\n");
1265 DPRINT1("Not implemented yet!\n");
1266 return(SRB_STATUS_SELECTION_TIMEOUT
);
1271 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1272 IN PSCSI_REQUEST_BLOCK Srb
)
1274 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1276 DPRINT1("AtapiSendIdeCommand() called!\n");
1278 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1283 switch (Srb
->Cdb
[0])
1285 case SCSIOP_INQUIRY
:
1286 SrbStatus
= AtapiInquiry(DeviceExtension
,
1290 case SCSIOP_READ_CAPACITY
:
1291 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1297 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1301 case SCSIOP_MODE_SENSE
:
1302 case SCSIOP_TEST_UNIT_READY
:
1304 case SCSIOP_START_STOP_UNIT
:
1305 case SCSIOP_REQUEST_SENSE
:
1309 DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
1311 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1315 DPRINT1("AtapiSendIdeCommand() done!\n");
1322 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1323 PSCSI_REQUEST_BLOCK Srb
)
1325 PIDE_DRIVE_IDENTIFY DeviceParams
;
1326 PINQUIRYDATA InquiryData
;
1329 DPRINT1("SCSIOP_INQUIRY: TargetId: %lu\n", Srb
->TargetId
);
1331 if ((Srb
->PathId
!= 0) ||
1332 (Srb
->TargetId
> 1) ||
1334 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1336 return(SRB_STATUS_SELECTION_TIMEOUT
);
1339 InquiryData
= Srb
->DataBuffer
;
1340 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1343 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1345 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1348 /* set device class */
1349 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1352 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1356 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1358 InquiryData
->DeviceType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1361 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1362 if (DeviceParams
->ConfigBits
& 0x80)
1364 DPRINT1("Removable media!\n");
1365 InquiryData
->RemovableMedia
= 1;
1368 for (i
= 0; i
< 20; i
+= 2)
1370 InquiryData
->VendorId
[i
] =
1371 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1372 InquiryData
->VendorId
[i
+1] =
1373 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1376 for (i
= 0; i
< 4; i
++)
1378 InquiryData
->ProductId
[12+i
] = ' ';
1381 for (i
= 0; i
< 4; i
+= 2)
1383 InquiryData
->ProductRevisionLevel
[i
] =
1384 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1385 InquiryData
->ProductRevisionLevel
[i
+1] =
1386 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1389 return(SRB_STATUS_SUCCESS
);
1394 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1395 PSCSI_REQUEST_BLOCK Srb
)
1397 PREAD_CAPACITY_DATA CapacityData
;
1398 PIDE_DRIVE_IDENTIFY DeviceParams
;
1401 DPRINT1("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1403 if ((Srb
->PathId
!= 0) ||
1404 (Srb
->TargetId
> 1) ||
1406 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1408 return(SRB_STATUS_SELECTION_TIMEOUT
);
1412 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1413 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1415 /* Set sector (block) size to 512 bytes (big-endian). */
1416 CapacityData
->BytesPerBlock
= 0x20000;
1418 /* Calculate last sector (big-endian). */
1419 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1421 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1422 DeviceParams
->TMSectorCountLo
) - 1;
1426 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1427 DeviceParams
->LogicalHeads
*
1428 DeviceParams
->SectorsPerTrack
)-1;
1431 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1432 (((PUCHAR
)&LastSector
)[1] << 16) |
1433 (((PUCHAR
)&LastSector
)[2] << 8) |
1434 ((PUCHAR
)&LastSector
)[3];
1436 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1439 CapacityData
->LogicalBlockAddress
);
1441 return(SRB_STATUS_SUCCESS
);
1446 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1447 PSCSI_REQUEST_BLOCK Srb
)
1449 PIDE_DRIVE_IDENTIFY DeviceParams
;
1451 ULONG StartingSector
,i
;
1462 DPRINT1("AtapiReadWrite() called!\n");
1464 if ((Srb
->PathId
!= 0) ||
1465 (Srb
->TargetId
> 1) ||
1467 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1469 return(SRB_STATUS_SELECTION_TIMEOUT
);
1472 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1475 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1477 /* Get starting sector number from CDB. */
1478 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1479 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1480 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1481 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1483 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1484 DeviceParams
->BytesPerSector
;
1486 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1488 Srb
->DataTransferLength
,
1491 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1493 SectorNumber
= StartingSector
& 0xff;
1494 CylinderLow
= (StartingSector
>> 8) & 0xff;
1495 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1496 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1497 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1502 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1503 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1504 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1505 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1506 StartingSector
/= DeviceParams
->LogicalHeads
;
1507 CylinderLow
= StartingSector
& 0xff;
1508 CylinderHigh
= StartingSector
>> 8;
1512 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1514 Command
= IDE_CMD_READ
;
1518 Command
= IDE_CMD_WRITE
;
1521 if (DrvHead
& IDE_DH_LBA
)
1523 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1524 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1525 DeviceExtension
->CommandPortBase
,
1526 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1527 ((DrvHead
& 0x0f) << 24) +
1528 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1534 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1535 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1536 DeviceExtension
->CommandPortBase
,
1537 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1546 /* Set pointer to data buffer. */
1547 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1549 DeviceExtension
->CurrentSrb
= Srb
;
1550 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1554 /* wait for BUSY to clear */
1555 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1557 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1558 if (!(Status
& IDE_SR_BUSY
))
1562 ScsiPortStallExecution(10);
1564 DPRINT ("status=%02x\n", Status
);
1565 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1566 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1568 DPRINT ("Drive is BUSY for too long\n");
1569 return(SRB_STATUS_BUSY
);
1571 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1573 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1574 Irp
= ControllerExtension
->CurrentIrp
;
1575 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1576 Irp
->IoStatus
.Information
= 0;
1582 DPRINT ("Beginning drive reset sequence\n");
1583 IDEBeginControllerReset(ControllerExtension
);
1590 /* Select the desired drive */
1591 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1592 IDE_DH_FIXED
| DrvHead
);
1594 /* wait for BUSY to clear and DRDY to assert */
1595 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1597 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1598 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1602 ScsiPortStallExecution(10);
1604 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1605 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1607 DPRINT ("Drive is BUSY for too long after drive select\n");
1608 return(SRB_STATUS_BUSY
);
1610 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1612 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1613 Irp
= ControllerExtension
->CurrentIrp
;
1614 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1615 Irp
->IoStatus
.Information
= 0;
1621 DPRINT ("Beginning drive reset sequence\n");
1622 IDEBeginControllerReset(ControllerExtension
);
1629 if (Command
== IDE_CMD_WRITE
)
1631 DPRINT1("Write not implemented yet!\n");
1632 return(SRB_STATUS_SUCCESS
);
1635 /* Indicate expecting an interrupt. */
1636 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1638 /* Setup command parameters */
1639 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1640 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1641 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1642 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1643 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1644 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1646 /* Issue command to drive */
1647 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1648 // ControllerExtension->TimerState = IDETimerCmdWait;
1649 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1652 /* FIXME: Write data here! */
1655 DPRINT1("AtapiReadWrite() done!\n");
1657 /* Wait for interrupt. */
1658 return(SRB_STATUS_PENDING
);