3 * Copyright (C) 2001, 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: atapi.c,v 1.13 2002/03/16 16:13:57 ekohl Exp $
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: services/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
32 * This driver is derived from Rex Jolliff's ide driver. Lots of his
33 * routines are still in here although they belong into the higher level
34 * drivers. They will be moved away as soon as possible.
39 * - implement sending of atapi commands
40 * - handle removable atapi non-cdrom drives
46 // -------------------------------------------------------------------------
48 #include <ddk/ntddk.h>
50 #include "../include/srb.h"
51 #include "../include/scsi.h"
52 #include "../include/ntddscsi.h"
59 #define VERSION "0.0.1"
62 // ------------------------------------------------------- File Static Data
64 // ATAPI_MINIPORT_EXTENSION
67 // Extension to be placed in each port device object
70 // Allocated from NON-PAGED POOL
71 // Available at any IRQL
74 typedef struct _ATAPI_MINIPORT_EXTENSION
76 IDE_DRIVE_IDENTIFY DeviceParams
[2];
77 BOOLEAN DevicePresent
[2];
78 BOOLEAN DeviceAtapi
[2];
80 ULONG CommandPortBase
;
81 ULONG ControlPortBase
;
83 BOOLEAN ExpectingInterrupt
;
84 PSCSI_REQUEST_BLOCK CurrentSrb
;
87 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
90 typedef struct _UNIT_EXTENSION
93 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
96 // ----------------------------------------------- Discardable Declarations
100 // make the initialization routines discardable, so that they
103 #pragma alloc_text(init, DriverEntry)
104 #pragma alloc_text(init, IDECreateController)
105 #pragma alloc_text(init, IDEPolledRead)
107 // make the PASSIVE_LEVEL routines pageable, so that they don't
108 // waste nonpaged memory
110 #pragma alloc_text(page, IDEShutdown)
111 #pragma alloc_text(page, IDEDispatchOpenClose)
112 #pragma alloc_text(page, IDEDispatchRead)
113 #pragma alloc_text(page, IDEDispatchWrite)
115 #endif /* ALLOC_PRAGMA */
117 // ---------------------------------------------------- Forward Declarations
120 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
122 PVOID BusInformation
,
123 PCHAR ArgumentString
,
124 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
128 AtapiFindIsaBusController(PVOID DeviceExtension
,
130 PVOID BusInformation
,
131 PCHAR ArgumentString
,
132 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
136 AtapiFindNativePciController(PVOID DeviceExtension
,
138 PVOID BusInformation
,
139 PCHAR ArgumentString
,
140 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
143 static BOOLEAN STDCALL
144 AtapiInitialize(IN PVOID DeviceExtension
);
146 static BOOLEAN STDCALL
147 AtapiResetBus(IN PVOID DeviceExtension
,
150 static BOOLEAN STDCALL
151 AtapiStartIo(IN PVOID DeviceExtension
,
152 IN PSCSI_REQUEST_BLOCK Srb
);
154 static BOOLEAN STDCALL
155 AtapiInterrupt(IN PVOID DeviceExtension
);
158 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
159 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
162 AtapiIdentifyDevice(IN ULONG CommandPort
,
163 IN ULONG ControlPort
,
166 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
169 IDEResetController(IN ULONG CommandPort
,
170 IN ULONG ControlPort
);
173 AtapiPolledRead(IN ULONG CommandPort
,
174 IN ULONG ControlPort
,
179 IN BYTE CylinderHigh
,
187 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
188 IN PSCSI_REQUEST_BLOCK Srb
);
191 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
192 IN PSCSI_REQUEST_BLOCK Srb
);
195 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
196 IN PSCSI_REQUEST_BLOCK Srb
);
199 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
200 IN PSCSI_REQUEST_BLOCK Srb
);
203 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
204 IN PSCSI_REQUEST_BLOCK Srb
);
206 // ---------------------------------------------------------------- Inlines
209 IDESwapBytePairs(char *Buf
,
215 for (i
= 0; i
< Cnt
; i
+= 2)
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 */
270 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
271 InitData
.NumberOfAccessRanges
= 2;
272 InitData
.AdapterInterfaceType
= PCIBus
;
274 InitData
.VendorId
= NULL
;
275 InitData
.VendorIdLength
= 0;
276 InitData
.DeviceId
= NULL
;
277 InitData
.DeviceIdLength
= 0;
279 Status
= ScsiPortInitialize(DriverObject
,
283 // if (newStatus < statusToReturn)
284 // statusToReturn = newStatus;
287 /* Search the ISA bus for ide controllers */
289 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
290 InitData
.NumberOfAccessRanges
= 2;
291 InitData
.AdapterInterfaceType
= Isa
;
293 InitData
.VendorId
= NULL
;
294 InitData
.VendorIdLength
= 0;
295 InitData
.DeviceId
= NULL
;
296 InitData
.DeviceIdLength
= 0;
298 Status
= ScsiPortInitialize(DriverObject
,
302 // if (newStatus < statusToReturn)
303 // statusToReturn = newStatus;
306 /* Search the PCI bus for native mode ide controllers */
308 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
309 InitData
.NumberOfAccessRanges
= 2;
310 InitData
.AdapterInterfaceType
= PCIBus
;
312 InitData
.VendorId
= NULL
;
313 InitData
.VendorIdLength
= 0;
314 InitData
.DeviceId
= NULL
;
315 InitData
.DeviceIdLength
= 0;
317 Status
= ScsiPortInitialize(DriverObject
,
321 // if (newStatus < statusToReturn)
322 // statusToReturn = newStatus;
325 DPRINT( "Returning from DriverEntry\n" );
332 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
334 PVOID BusInformation
,
335 PCHAR ArgumentString
,
336 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
339 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
340 PCI_SLOT_NUMBER SlotNumber
;
341 PCI_COMMON_CONFIG PciConfig
;
343 ULONG FunctionNumber
;
344 BOOLEAN ChannelFound
;
347 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
348 ConfigInfo
->SystemIoBusNumber
,
349 ConfigInfo
->SlotNumber
);
353 /* both channels were claimed: exit */
354 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
355 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
356 return(SP_RETURN_NOT_FOUND
);
359 SlotNumber
.u
.AsULONG
= 0;
360 for (FunctionNumber
= 0 /*ConfigInfo->SlotNumber*/; FunctionNumber
< 256; FunctionNumber
++)
362 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
363 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
364 SlotNumber
.u
.AsULONG
= FunctionNumber
;
366 ChannelFound
= FALSE
;
369 DataSize
= ScsiPortGetBusData(DeviceExtension
,
372 SlotNumber
.u
.AsULONG
,
374 sizeof(PCI_COMMON_CONFIG
));
375 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
376 // PciConfig.VendorID == PCI_INVALID_VENDORID)
379 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
380 // return(SP_RETURN_ERROR); /* No bus found */
383 // return(SP_RETURN_ERROR);
386 if (PciConfig
.BaseClass
== 0x01 &&
387 PciConfig
.SubClass
== 0x01) // &&
388 // (PciConfig.ProgIf & 0x05) == 0)
390 /* both channels are in compatibility mode */
391 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
392 ConfigInfo
->SystemIoBusNumber
,
393 SlotNumber
.u
.bits
.DeviceNumber
,
394 SlotNumber
.u
.bits
.FunctionNumber
,
397 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
399 DPRINT("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 DPRINT("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 DPRINT("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
;
480 BOOLEAN ChannelFound
= FALSE
;
481 BOOLEAN DeviceFound
= FALSE
;
483 DPRINT1("AtapiFindIsaBusController() called!\n");
487 ConfigInfo
->NumberOfBuses
= 1;
488 ConfigInfo
->MaximumNumberOfTargets
= 2;
489 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
491 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
493 /* Both channels unclaimed: Claim primary channel */
494 DPRINT1("Primary channel!\n");
496 DevExt
->CommandPortBase
= 0x01F0;
497 DevExt
->ControlPortBase
= 0x03F6;
499 ConfigInfo
->BusInterruptLevel
= 14;
500 ConfigInfo
->BusInterruptVector
= 14;
501 ConfigInfo
->InterruptMode
= LevelSensitive
;
503 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x01F0);
504 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
505 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
507 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x03F6);
508 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
509 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
511 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
513 *Again
= FALSE
/*TRUE*/;
515 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
517 /* Primary channel already claimed: claim secondary channel */
518 DPRINT1("Secondary channel!\n");
520 DevExt
->CommandPortBase
= 0x0170;
521 DevExt
->ControlPortBase
= 0x0376;
523 ConfigInfo
->BusInterruptLevel
= 15;
524 ConfigInfo
->BusInterruptVector
= 15;
525 ConfigInfo
->InterruptMode
= LevelSensitive
;
527 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0170);
528 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
529 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
531 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0376);
532 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
533 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
535 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
541 DPRINT1("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
543 return(SP_RETURN_NOT_FOUND
);
546 /* Find attached devices */
549 DeviceFound
= AtapiFindDevices(DevExt
,
553 DPRINT1("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
554 return(SP_RETURN_FOUND
);
559 AtapiFindNativePciController(PVOID DeviceExtension
,
561 PVOID BusInformation
,
562 PCHAR ArgumentString
,
563 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
566 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
568 DPRINT("AtapiFindNativePciController() called!\n");
572 DPRINT("AtapiFindNativePciController() done!\n");
574 return(SP_RETURN_NOT_FOUND
);
578 static BOOLEAN STDCALL
579 AtapiInitialize(IN PVOID DeviceExtension
)
585 static BOOLEAN STDCALL
586 AtapiResetBus(IN PVOID DeviceExtension
,
593 static BOOLEAN STDCALL
594 AtapiStartIo(IN PVOID DeviceExtension
,
595 IN PSCSI_REQUEST_BLOCK Srb
)
597 PATAPI_MINIPORT_EXTENSION DevExt
;
600 DPRINT("AtapiStartIo() called\n");
602 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
604 switch (Srb
->Function
)
606 case SRB_FUNCTION_EXECUTE_SCSI
:
607 DevExt
->CurrentSrb
= Srb
;
608 if (DevExt
->DeviceAtapi
[Srb
->TargetId
] == TRUE
)
610 Result
= AtapiSendAtapiCommand(DevExt
,
615 Result
= AtapiSendIdeCommand(DevExt
,
622 Srb
->SrbStatus
= Result
;
625 if (Result
!= SRB_STATUS_PENDING
)
627 DevExt
->CurrentSrb
= NULL
;
628 Srb
->SrbStatus
= (UCHAR
)Result
;
630 ScsiPortNotification(RequestComplete
,
633 ScsiPortNotification(NextRequest
,
639 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
642 DPRINT("AtapiStartIo() done\n");
648 static BOOLEAN STDCALL
649 AtapiInterrupt(IN PVOID DeviceExtension
)
651 PATAPI_MINIPORT_EXTENSION DevExt
;
652 PSCSI_REQUEST_BLOCK Srb
;
653 ULONG CommandPortBase
;
654 ULONG ControlPortBase
;
659 NTSTATUS ErrorStatus
;
660 ULONG ErrorInformation
;
661 PUCHAR TargetAddress
;
665 DPRINT("AtapiInterrupt() called!\n");
667 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
668 if (DevExt
->ExpectingInterrupt
== FALSE
)
673 Srb
= DevExt
->CurrentSrb
;
675 DPRINT("Srb: %p\n", Srb
);
677 CommandPortBase
= DevExt
->CommandPortBase
;
678 ControlPortBase
= DevExt
->ControlPortBase
;
680 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
683 ErrorStatus
= STATUS_SUCCESS
;
684 ErrorInformation
= 0;
686 DeviceStatus
= IDEReadStatus(CommandPortBase
);
688 /* Handle error condition if it exists */
689 if (DeviceStatus
& IDE_SR_ERR
)
691 BYTE ErrorReg
, SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
695 ErrorReg
= IDEReadError(CommandPortBase
);
696 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
697 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
698 DriveHead
= IDEReadDriveHead(CommandPortBase
);
699 SectorCount
= IDEReadSectorCount(CommandPortBase
);
700 SectorNum
= IDEReadSectorNum(CommandPortBase
);
702 /* FIXME: should use the NT error logging facility */
703 DbgPrint("ATAPI Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
704 0, //DeviceExtension->Operation,
712 /* FIXME: should retry the command and perhaps recalibrate the drive */
714 // Set error status information
715 ErrorStatus
= STATUS_DISK_OPERATION_FAILED
;
718 (((((((CylinderHigh
<< 8) + CylinderLow
) *
719 DeviceExtension
->LogicalHeads
) +
720 (DriveHead
% DeviceExtension
->LogicalHeads
)) *
721 DeviceExtension
->SectorsPerLogTrk
) + SectorNum
- 1) -
722 DeviceExtension
->StartingSector
) * DeviceExtension
->BytesPerSector
;
730 DPRINT("SCSIOP_READ\n");
732 /* Update controller/device state variables */
733 SectorSize
= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
734 TargetAddress
= Srb
->DataBuffer
;
735 Srb
->DataBuffer
+= SectorSize
;
736 Srb
->DataTransferLength
-= SectorSize
;
738 /* Remember whether DRQ should be low at end (last block read) */
739 IsLastBlock
= (Srb
->DataTransferLength
== 0);
740 DPRINT("IsLastBlock == %s\n", (IsLastBlock
)?"TRUE":"FALSE");
742 /* Wait for DRQ assertion */
743 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
744 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
747 KeStallExecutionProcessor(10);
750 /* Copy the block of data */
751 IDEReadBlock(CommandPortBase
,
758 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
759 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
762 KeStallExecutionProcessor(10);
765 /* Check for data overrun */
766 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
768 /* FIXME: Handle error! */
774 DPRINT("SCSIOP_WRITE\n");
775 if (Srb
->DataTransferLength
== 0)
778 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
779 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
782 KeStallExecutionProcessor(10);
785 /* Check for data overrun */
786 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
788 /* FIXME: Handle error! */
791 DevExt
->ExpectingInterrupt
= FALSE
;
796 /* Update SRB data */
797 SectorSize
= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
799 TargetAddress
= Srb
->DataBuffer
;
800 Srb
->DataBuffer
+= SectorSize
;
801 Srb
->DataTransferLength
-= SectorSize
;
803 /* Write the sector */
804 IDEWriteBlock(CommandPortBase
,
812 /* complete this packet */
815 DevExt
->ExpectingInterrupt
= FALSE
;
817 ScsiPortNotification(RequestComplete
,
821 ScsiPortNotification(NextRequest
,
826 DPRINT("AtapiInterrupt() done!\n");
836 // ---------------------------------------------------- Discardable statics
839 /**********************************************************************
844 * Searches for devices on the given port.
851 * Port device specific information.
854 * Port configuration information.
857 * TRUE: At least one device is attached to the port.
858 * FALSE: No device is attached to the port.
862 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
863 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
865 BOOLEAN DeviceFound
= FALSE
;
866 ULONG CommandPortBase
;
867 ULONG ControlPortBase
;
872 DPRINT("AtapiFindDevices() called\n");
874 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
875 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
876 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
878 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
879 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
880 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
882 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
885 IDEWriteDriveHead(CommandPortBase
,
886 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
887 ScsiPortStallExecution(500);
889 /* Disable interrupts */
890 IDEWriteDriveControl(ControlPortBase
,
892 ScsiPortStallExecution(500);
894 IDEWriteCylinderHigh(CommandPortBase
, 0);
895 IDEWriteCylinderLow(CommandPortBase
, 0);
896 IDEWriteCommand(CommandPortBase
, IDE_CMD_RESET
);
898 for (Retries
= 0; Retries
< 20000; Retries
++)
900 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
904 ScsiPortStallExecution(150);
906 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
908 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
912 High
= IDEReadCylinderHigh(CommandPortBase
);
913 Low
= IDEReadCylinderLow(CommandPortBase
);
915 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
920 if (High
== 0xEB && Low
== 0x14)
922 if (AtapiIdentifyDevice(CommandPortBase
,
926 &DeviceExtension
->DeviceParams
[UnitNumber
]))
928 DPRINT(" ATAPI drive found!\n");
929 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
930 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
935 DPRINT(" No ATAPI drive found!\n");
940 if (AtapiIdentifyDevice(CommandPortBase
,
944 &DeviceExtension
->DeviceParams
[UnitNumber
]))
946 DPRINT(" IDE drive found!\n");
947 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
948 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
953 DPRINT(" No IDE drive found!\n");
958 DPRINT("AtapiFindDrives() done\n");
964 // AtapiResetController
967 // Reset the controller and report completion status
973 // IN WORD CommandPort The address of the command port
974 // IN WORD ControlPort The address of the control port
980 AtapiResetController(IN ULONG CommandPort
,
981 IN ULONG ControlPort
)
985 /* Assert drive reset line */
986 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
988 /* Wait for min. 25 microseconds */
989 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
991 /* Negate drive reset line */
992 IDEWriteDriveControl(ControlPort
, 0);
994 /* Wait for BUSY negation */
995 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
997 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
1001 ScsiPortStallExecution(10);
1005 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
1012 // return TRUE if controller came back to life. and
1013 // the registers are initialized correctly
1014 return(IDEReadError(CommandPort
) == 1);
1018 * AtapiIdentifyDevice
1021 * Get the identification block from the drive
1028 * Address of the command port
1030 * Address of the control port
1032 * The drive index (0,1)
1034 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1036 * Address to write drive ident block
1039 * TRUE: The drive identification block was retrieved successfully
1040 * FALSE: an error ocurred
1044 AtapiIdentifyDevice(IN ULONG CommandPort
,
1045 IN ULONG ControlPort
,
1048 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1050 /* Get the Drive Identify block from drive or die */
1051 if (AtapiPolledRead(CommandPort
,
1058 (DriveNum
? IDE_DH_DRV1
: 0),
1059 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1060 (BYTE
*)DrvParms
) != 0)
1062 DPRINT1("IDEPolledRead() failed\n");
1066 /* Report on drive parameters if debug mode */
1067 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1068 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1069 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1070 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1071 DrvParms
->ConfigBits
,
1072 DrvParms
->LogicalCyls
,
1073 DrvParms
->LogicalHeads
,
1074 DrvParms
->SectorsPerTrack
,
1075 DrvParms
->InterSectorGap
,
1076 DrvParms
->InterSectorGapSize
);
1077 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1078 DrvParms
->BytesInPLO
,
1079 DrvParms
->VendorUniqueCnt
,
1080 DrvParms
->SerialNumber
);
1081 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1082 DrvParms
->ControllerType
,
1083 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1084 DrvParms
->ECCByteCnt
,
1085 DrvParms
->FirmwareRev
);
1086 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1087 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1088 (DrvParms
->RWMultImplemented
) & 0xff,
1089 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1090 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1091 DrvParms
->MinPIOTransTime
,
1092 DrvParms
->MinDMATransTime
);
1093 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1094 DrvParms
->TMCylinders
,
1096 DrvParms
->TMSectorsPerTrk
,
1097 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1098 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1099 DrvParms
->TMSectorCountHi
,
1100 DrvParms
->TMSectorCountLo
,
1101 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1103 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1104 if (DrvParms
->BytesPerSector
== 0)
1105 DrvParms
->BytesPerSector
= 512;
1113 // Read a sector of data from the drive in a polled fashion.
1119 // IN WORD Address Address of command port for drive
1120 // IN BYTE PreComp Value to write to precomp register
1121 // IN BYTE SectorCnt Value to write to sectorCnt register
1122 // IN BYTE SectorNum Value to write to sectorNum register
1123 // IN BYTE CylinderLow Value to write to CylinderLow register
1124 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1125 // IN BYTE DrvHead Value to write to Drive/Head register
1126 // IN BYTE Command Value to write to Command register
1127 // OUT BYTE *Buffer Buffer for output data
1130 // int 0 is success, non 0 is an error code
1134 AtapiPolledRead(IN ULONG CommandPort
,
1135 IN ULONG ControlPort
,
1139 IN BYTE CylinderLow
,
1140 IN BYTE CylinderHigh
,
1145 ULONG SectorCount
= 0;
1147 BOOLEAN Junk
= FALSE
;
1151 /* Write Drive/Head to select drive */
1152 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1153 ScsiPortStallExecution(500);
1155 /* Disable interrupts */
1156 Control
= IDEReadAltStatus(ControlPort
);
1157 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1158 ScsiPortStallExecution(500);
1160 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1161 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1163 Status
= IDEReadStatus(CommandPort
);
1164 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1168 ScsiPortStallExecution(10);
1170 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
1172 return(IDE_ER_ABRT
);
1175 /* Write Drive/Head to select drive */
1176 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1178 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1179 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1181 Status
= IDEReadStatus(CommandPort
);
1182 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1186 ScsiPortStallExecution(10);
1188 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1193 /* Issue command to drive */
1194 if (DrvHead
& IDE_DH_LBA
)
1196 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1197 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1198 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1204 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1205 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1214 /* Setup command parameters */
1215 IDEWritePrecomp(CommandPort
, PreComp
);
1216 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1217 IDEWriteSectorNum(CommandPort
, SectorNum
);
1218 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1219 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1220 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1222 /* Issue the command */
1223 IDEWriteCommand(CommandPort
, Command
);
1224 ScsiPortStallExecution(50);
1226 /* wait for DRQ or error */
1227 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1229 Status
= IDEReadStatus(CommandPort
);
1230 if (!(Status
& IDE_SR_BUSY
))
1232 if (Status
& IDE_SR_ERR
)
1234 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1235 return(IDE_ER_ABRT
);
1237 if (Status
& IDE_SR_DRQ
)
1243 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1244 return(IDE_ER_ABRT
);
1247 ScsiPortStallExecution(10);
1251 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1253 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1254 return(IDE_ER_ABRT
);
1259 /* Read data into buffer */
1262 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1263 Buffer
+= IDE_SECTOR_BUF_SZ
;
1267 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1268 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1272 /* Check for error or more sectors to read */
1273 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1275 Status
= IDEReadStatus(CommandPort
);
1276 if (!(Status
& IDE_SR_BUSY
))
1278 if (Status
& IDE_SR_ERR
)
1280 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1281 return(IDE_ER_ABRT
);
1283 if (Status
& IDE_SR_DRQ
)
1285 if (SectorCount
>= SectorCnt
)
1287 DPRINT("Buffer size exceeded!\n");
1294 if (SectorCount
> SectorCnt
)
1296 DPRINT("Read %lu sectors of junk!\n",
1297 SectorCount
- SectorCnt
);
1299 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1308 // ------------------------------------------- Nondiscardable statics
1311 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1312 IN PSCSI_REQUEST_BLOCK Srb
)
1315 // PIDE_DRIVE_IDENTIFY DeviceParams;
1317 // ULONG StartingSector,i;
1318 // ULONG SectorCount;
1319 UCHAR ByteCountHigh
;
1322 // UCHAR SectorNumber;
1327 DPRINT1("AtapiSendAtapiCommand() called!\n");
1329 if ((Srb
->PathId
!= 0) ||
1330 (Srb
->TargetId
> 1) ||
1332 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1334 return(SRB_STATUS_SELECTION_TIMEOUT
);
1337 DPRINT1("AtapiSendAtapiCommand(): TargetId: %lu\n",
1341 /* Set pointer to data buffer. */
1342 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1344 DeviceExtension
->CurrentSrb
= Srb
;
1345 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1348 /* wait for BUSY to clear */
1349 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1351 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1352 if (!(Status
& IDE_SR_BUSY
))
1356 ScsiPortStallExecution(10);
1358 DPRINT("status=%02x\n", Status
);
1359 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1360 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1362 DPRINT ("Drive is BUSY for too long\n");
1363 return(SRB_STATUS_BUSY
);
1365 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1367 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1368 Irp
= ControllerExtension
->CurrentIrp
;
1369 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1370 Irp
->IoStatus
.Information
= 0;
1376 DPRINT ("Beginning drive reset sequence\n");
1377 IDEBeginControllerReset(ControllerExtension
);
1384 /* Select the desired drive */
1385 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1386 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1388 /* wait for BUSY to clear and DRDY to assert */
1389 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1391 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1392 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1396 ScsiPortStallExecution(10);
1398 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1399 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1401 DPRINT("Drive is BUSY for too long after drive select\n");
1402 return(SRB_STATUS_BUSY
);
1404 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1406 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1407 Irp
= ControllerExtension
->CurrentIrp
;
1408 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1409 Irp
->IoStatus
.Information
= 0;
1415 DPRINT("Beginning drive reset sequence\n");
1416 IDEBeginControllerReset(ControllerExtension
);
1423 ByteCountLow
= (UCHAR
)(Srb
->DataTransferLength
& 0xFF);
1424 ByteCountHigh
= (UCHAR
)(Srb
->DataTransferLength
>> 8);
1426 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1427 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1428 // IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1430 /* Issue command to drive */
1431 IDEWriteCommand(DeviceExtension
->CommandPortBase
, 0xA0); /* Packet command */
1434 /* wait for DRQ to assert */
1435 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1437 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1438 if ((Status
& IDE_SR_DRQ
))
1442 ScsiPortStallExecution(10);
1445 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1450 DPRINT1("AtapiSendAtapiCommand() done\n");
1451 return(SRB_STATUS_PENDING
);
1455 ULONG SrbStatus
= SRB_STATUS_SELECTION_TIMEOUT
;
1457 DPRINT("AtapiSendAtapiCommand() called!\n");
1459 switch (Srb
->Cdb
[0])
1461 case SCSIOP_INQUIRY
:
1462 DPRINT(" SCSIOP_INQUIRY\n");
1463 SrbStatus
= AtapiInquiry(DeviceExtension
,
1467 case SCSIOP_READ_CAPACITY
:
1468 DPRINT1(" SCSIOP_READ_CAPACITY\n");
1472 DPRINT1(" SCSIOP_READ\n");
1476 DPRINT1(" SCSIOP_WRITE\n");
1479 case SCSIOP_MODE_SENSE
:
1480 DPRINT1(" SCSIOP_MODE_SENSE\n");
1483 case SCSIOP_TEST_UNIT_READY
:
1484 DPRINT1(" SCSIOP_TEST_UNIT_READY\n");
1488 DPRINT1(" SCSIOP_VERIFY\n");
1491 case SCSIOP_START_STOP_UNIT
:
1492 DPRINT1(" SCSIOP_START_STOP_UNIT\n");
1495 case SCSIOP_REQUEST_SENSE
:
1496 DPRINT1(" SCSIOP_REQUEST_SENSE\n");
1500 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1505 if (SrbStatus
== SRB_STATUS_SELECTION_TIMEOUT
)
1507 DPRINT1("Not implemented yet!\n");
1516 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1517 IN PSCSI_REQUEST_BLOCK Srb
)
1519 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1521 DPRINT("AtapiSendIdeCommand() called!\n");
1523 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1528 switch (Srb
->Cdb
[0])
1530 case SCSIOP_INQUIRY
:
1531 SrbStatus
= AtapiInquiry(DeviceExtension
,
1535 case SCSIOP_READ_CAPACITY
:
1536 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1542 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1546 case SCSIOP_MODE_SENSE
:
1547 case SCSIOP_TEST_UNIT_READY
:
1549 case SCSIOP_START_STOP_UNIT
:
1550 case SCSIOP_REQUEST_SENSE
:
1554 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1556 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1560 DPRINT("AtapiSendIdeCommand() done!\n");
1567 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1568 PSCSI_REQUEST_BLOCK Srb
)
1570 PIDE_DRIVE_IDENTIFY DeviceParams
;
1571 PINQUIRYDATA InquiryData
;
1574 DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb
->TargetId
);
1576 if ((Srb
->PathId
!= 0) ||
1577 (Srb
->TargetId
> 1) ||
1579 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1581 return(SRB_STATUS_SELECTION_TIMEOUT
);
1584 InquiryData
= Srb
->DataBuffer
;
1585 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1588 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1590 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1593 /* set device class */
1594 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1597 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1601 /* get it from the ATAPI configuration word */
1602 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1603 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1606 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1607 if (DeviceParams
->ConfigBits
& 0x80)
1609 DPRINT("Removable media!\n");
1610 InquiryData
->RemovableMedia
= 1;
1613 for (i
= 0; i
< 20; i
+= 2)
1615 InquiryData
->VendorId
[i
] =
1616 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1617 InquiryData
->VendorId
[i
+1] =
1618 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1621 for (i
= 0; i
< 4; i
++)
1623 InquiryData
->ProductId
[12+i
] = ' ';
1626 for (i
= 0; i
< 4; i
+= 2)
1628 InquiryData
->ProductRevisionLevel
[i
] =
1629 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1630 InquiryData
->ProductRevisionLevel
[i
+1] =
1631 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1634 return(SRB_STATUS_SUCCESS
);
1639 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1640 PSCSI_REQUEST_BLOCK Srb
)
1642 PREAD_CAPACITY_DATA CapacityData
;
1643 PIDE_DRIVE_IDENTIFY DeviceParams
;
1646 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1648 if ((Srb
->PathId
!= 0) ||
1649 (Srb
->TargetId
> 1) ||
1651 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1653 return(SRB_STATUS_SELECTION_TIMEOUT
);
1657 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1658 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1660 /* Set sector (block) size to 512 bytes (big-endian). */
1661 CapacityData
->BytesPerBlock
= 0x20000;
1663 /* Calculate last sector (big-endian). */
1664 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1666 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1667 DeviceParams
->TMSectorCountLo
) - 1;
1671 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1672 DeviceParams
->LogicalHeads
*
1673 DeviceParams
->SectorsPerTrack
)-1;
1676 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1677 (((PUCHAR
)&LastSector
)[1] << 16) |
1678 (((PUCHAR
)&LastSector
)[2] << 8) |
1679 ((PUCHAR
)&LastSector
)[3];
1681 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1684 CapacityData
->LogicalBlockAddress
);
1686 return(SRB_STATUS_SUCCESS
);
1691 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1692 PSCSI_REQUEST_BLOCK Srb
)
1694 PIDE_DRIVE_IDENTIFY DeviceParams
;
1696 ULONG StartingSector
,i
;
1707 DPRINT("AtapiReadWrite() called!\n");
1709 if ((Srb
->PathId
!= 0) ||
1710 (Srb
->TargetId
> 1) ||
1712 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1714 return(SRB_STATUS_SELECTION_TIMEOUT
);
1717 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1720 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1722 /* Get starting sector number from CDB. */
1723 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1724 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1725 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1726 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1728 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1729 DeviceParams
->BytesPerSector
;
1731 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1733 Srb
->DataTransferLength
,
1736 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1738 SectorNumber
= StartingSector
& 0xff;
1739 CylinderLow
= (StartingSector
>> 8) & 0xff;
1740 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1741 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1742 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1747 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1748 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1749 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1750 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1751 StartingSector
/= DeviceParams
->LogicalHeads
;
1752 CylinderLow
= StartingSector
& 0xff;
1753 CylinderHigh
= StartingSector
>> 8;
1757 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1759 Command
= IDE_CMD_READ
;
1763 Command
= IDE_CMD_WRITE
;
1766 if (DrvHead
& IDE_DH_LBA
)
1768 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1769 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1770 DeviceExtension
->CommandPortBase
,
1771 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1772 ((DrvHead
& 0x0f) << 24) +
1773 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1779 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1780 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1781 DeviceExtension
->CommandPortBase
,
1782 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1791 /* Set pointer to data buffer. */
1792 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1794 DeviceExtension
->CurrentSrb
= Srb
;
1795 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1799 /* wait for BUSY to clear */
1800 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1802 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1803 if (!(Status
& IDE_SR_BUSY
))
1807 ScsiPortStallExecution(10);
1809 DPRINT("status=%02x\n", Status
);
1810 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1811 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1813 DPRINT ("Drive is BUSY for too long\n");
1814 return(SRB_STATUS_BUSY
);
1816 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1818 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1819 Irp
= ControllerExtension
->CurrentIrp
;
1820 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1821 Irp
->IoStatus
.Information
= 0;
1827 DPRINT ("Beginning drive reset sequence\n");
1828 IDEBeginControllerReset(ControllerExtension
);
1835 /* Select the desired drive */
1836 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1837 IDE_DH_FIXED
| DrvHead
);
1839 /* wait for BUSY to clear and DRDY to assert */
1840 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1842 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1843 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1847 ScsiPortStallExecution(10);
1849 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1850 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1852 DPRINT("Drive is BUSY for too long after drive select\n");
1853 return(SRB_STATUS_BUSY
);
1855 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1857 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1858 Irp
= ControllerExtension
->CurrentIrp
;
1859 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1860 Irp
->IoStatus
.Information
= 0;
1866 DPRINT("Beginning drive reset sequence\n");
1867 IDEBeginControllerReset(ControllerExtension
);
1875 if (Command
== IDE_CMD_WRITE
)
1877 DPRINT1("Write not implemented yet!\n");
1878 return(SRB_STATUS_SUCCESS
);
1882 /* Indicate expecting an interrupt. */
1883 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1885 /* Setup command parameters */
1886 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1887 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1888 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1889 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1890 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1891 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1893 /* Issue command to drive */
1894 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1896 /* Write data block */
1897 if (Command
== IDE_CMD_WRITE
)
1899 PUCHAR TargetAddress
;
1902 /* Wait for controller ready */
1903 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
1905 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1906 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
1910 KeStallExecutionProcessor(10);
1912 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1914 DPRINT("Drive is BUSY for too long after sending write command\n");
1915 return(SRB_STATUS_BUSY
);
1917 if (DeviceExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1919 Irp
= ControllerExtension
->CurrentIrp
;
1920 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1921 Irp
->IoStatus
.Information
= 0;
1927 IDEBeginControllerReset(ControllerExtension
);
1934 /* Update SRB data */
1935 SectorSize
= DeviceExtension
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
1936 TargetAddress
= Srb
->DataBuffer
;
1937 Srb
->DataBuffer
+= SectorSize
;
1938 Srb
->DataTransferLength
-= SectorSize
;
1940 /* Write data block */
1941 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1947 DPRINT("AtapiReadWrite() done!\n");
1949 /* Wait for interrupt. */
1950 return(SRB_STATUS_PENDING
);