1 /* $Id: atapi.c,v 1.5 2002/01/31 14:57:37 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
;
65 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
68 typedef struct _UNIT_EXTENSION
71 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
74 // ----------------------------------------------- Discardable Declarations
78 // make the initialization routines discardable, so that they
81 #pragma alloc_text(init, DriverEntry)
82 #pragma alloc_text(init, IDECreateController)
83 #pragma alloc_text(init, IDEPolledRead)
85 // make the PASSIVE_LEVEL routines pageable, so that they don't
86 // waste nonpaged memory
88 #pragma alloc_text(page, IDEShutdown)
89 #pragma alloc_text(page, IDEDispatchOpenClose)
90 #pragma alloc_text(page, IDEDispatchRead)
91 #pragma alloc_text(page, IDEDispatchWrite)
93 #endif /* ALLOC_PRAGMA */
95 // ---------------------------------------------------- Forward Declarations
98 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
100 PVOID BusInformation
,
101 PCHAR ArgumentString
,
102 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
106 AtapiFindIsaBusController(PVOID DeviceExtension
,
108 PVOID BusInformation
,
109 PCHAR ArgumentString
,
110 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
114 AtapiFindNativePciController(PVOID DeviceExtension
,
116 PVOID BusInformation
,
117 PCHAR ArgumentString
,
118 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
121 static BOOLEAN STDCALL
122 AtapiInitialize(IN PVOID DeviceExtension
);
124 static BOOLEAN STDCALL
125 AtapiResetBus(IN PVOID DeviceExtension
,
128 static BOOLEAN STDCALL
129 AtapiStartIo(IN PVOID DeviceExtension
,
130 IN PSCSI_REQUEST_BLOCK Srb
);
132 static BOOLEAN STDCALL
133 AtapiInterrupt(IN PVOID DeviceExtension
);
136 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
137 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
140 AtapiIdentifyATADevice(IN ULONG CommandPort
,
142 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
145 AtapiIdentifyATAPIDevice(IN ULONG CommandPort
,
147 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
150 IDEResetController(IN WORD CommandPort
,
151 IN WORD ControlPort
);
154 AtapiPolledRead(IN WORD Address
,
159 IN BYTE CylinderHigh
,
168 AtapiExecuteScsi(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
169 IN PSCSI_REQUEST_BLOCK Srb
);
172 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
173 IN PSCSI_REQUEST_BLOCK Srb
);
176 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
177 IN PSCSI_REQUEST_BLOCK Srb
);
180 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
181 IN PSCSI_REQUEST_BLOCK Srb
);
183 // ---------------------------------------------------------------- Inlines
186 IDESwapBytePairs(char *Buf
,
192 for (i
= 0; i
< Cnt
; i
+= 2)
202 IdeFindDrive(int Address
,
207 DPRINT1("IdeFindDrive(Address %lx DriveIdx %lu) called!\n", Address
, DriveIdx
);
209 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| (DriveIdx
? IDE_DH_DRV1
: 0));
210 IDEWriteCylinderLow(Address
, 0x30);
212 Cyl
= IDEReadCylinderLow(Address
);
213 DPRINT1("Cylinder %lx\n", Cyl
);
216 DPRINT1("IdeFindDrive() done!\n");
222 // ------------------------------------------------------- Public Interface
227 // This function initializes the driver, locates and claims
228 // hardware resources, and creates various NT objects needed
229 // to process I/O requests.
235 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
237 // IN PUNICODE_STRING RegistryPath Name of registry driver service
244 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
245 IN PUNICODE_STRING RegistryPath
)
247 HW_INITIALIZATION_DATA InitData
;
250 DbgPrint("ATAPI Driver %s\n", VERSION
);
252 /* Initialize data structure */
253 RtlZeroMemory(&InitData
,
254 sizeof(HW_INITIALIZATION_DATA
));
255 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
256 InitData
.HwInitialize
= AtapiInitialize
;
257 InitData
.HwResetBus
= AtapiResetBus
;
258 InitData
.HwStartIo
= AtapiStartIo
;
259 InitData
.HwInterrupt
= AtapiInterrupt
;
261 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
262 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
264 InitData
.MapBuffers
= TRUE
;
266 /* Search the PCI bus for compatibility mode ide controllers */
267 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
268 InitData
.NumberOfAccessRanges
= 2;
269 InitData
.AdapterInterfaceType
= PCIBus
;
271 InitData
.VendorId
= NULL
;
272 InitData
.VendorIdLength
= 0;
273 InitData
.DeviceId
= NULL
;
274 InitData
.DeviceIdLength
= 0;
276 Status
= ScsiPortInitialize(DriverObject
,
280 // if (newStatus < statusToReturn)
281 // statusToReturn = newStatus;
283 /* Search the ISA bus for ide controllers */
285 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
286 InitData
.NumberOfAccessRanges
= 2;
287 InitData
.AdapterInterfaceType
= Isa
;
289 InitData
.VendorId
= NULL
;
290 InitData
.VendorIdLength
= 0;
291 InitData
.DeviceId
= NULL
;
292 InitData
.DeviceIdLength
= 0;
294 Status
= ScsiPortInitialize(DriverObject
,
298 // if (newStatus < statusToReturn)
299 // statusToReturn = newStatus;
302 /* Search the PCI bus for native mode ide controllers */
304 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
305 InitData
.NumberOfAccessRanges
= 2;
306 InitData
.AdapterInterfaceType
= PCIBus
;
308 InitData
.VendorId
= NULL
;
309 InitData
.VendorIdLength
= 0;
310 InitData
.DeviceId
= NULL
;
311 InitData
.DeviceIdLength
= 0;
313 Status
= ScsiPortInitialize(DriverObject
,
317 // if (newStatus < statusToReturn)
318 // statusToReturn = newStatus;
321 DPRINT1( "Returning from DriverEntry\n" );
328 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
330 PVOID BusInformation
,
331 PCHAR ArgumentString
,
332 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
335 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
336 PCI_SLOT_NUMBER SlotNumber
;
337 PCI_COMMON_CONFIG PciConfig
;
339 ULONG FunctionNumber
;
340 BOOLEAN ChannelFound
;
343 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
344 ConfigInfo
->SystemIoBusNumber
,
345 ConfigInfo
->SlotNumber
);
349 /* both channels were claimed: exit */
350 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
351 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
352 return(SP_RETURN_NOT_FOUND
);
355 SlotNumber
.u
.AsULONG
= 0;
356 for (FunctionNumber
= 0 /*ConfigInfo->SlotNumber*/; FunctionNumber
< 256; FunctionNumber
++)
358 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
359 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
360 SlotNumber
.u
.AsULONG
= FunctionNumber
;
362 ChannelFound
= FALSE
;
365 DataSize
= ScsiPortGetBusData(DeviceExtension
,
368 SlotNumber
.u
.AsULONG
,
370 sizeof(PCI_COMMON_CONFIG
));
371 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
372 // PciConfig.VendorID == PCI_INVALID_VENDORID)
375 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
376 // return(SP_RETURN_ERROR); /* No bus found */
379 // return(SP_RETURN_ERROR);
382 if (PciConfig
.BaseClass
== 0x01 &&
383 PciConfig
.SubClass
== 0x01) // &&
384 // (PciConfig.ProgIf & 0x05) == 0)
386 /* both channels are in compatibility mode */
387 DPRINT1("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
388 ConfigInfo
->SystemIoBusNumber
,
389 // SlotNumber.u.AsULONG >> 3,
390 // SlotNumber.u.AsULONG & 0x07,
391 SlotNumber
.u
.bits
.DeviceNumber
,
392 SlotNumber
.u
.bits
.FunctionNumber
,
395 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
397 DPRINT1("Found IDE controller in compatibility mode!\n");
399 ConfigInfo
->NumberOfBuses
= 1;
400 ConfigInfo
->MaximumNumberOfTargets
= 2;
401 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
403 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
405 /* Both channels unclaimed: Claim primary channel */
406 DPRINT1("Primary channel!\n");
408 DevExt
->CommandPortBase
= 0x01F0;
409 DevExt
->ControlPortBase
= 0x03F6;
411 ConfigInfo
->BusInterruptLevel
= 14;
412 ConfigInfo
->BusInterruptVector
= 14;
413 ConfigInfo
->InterruptMode
= LevelSensitive
;
415 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x01F0);
416 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
417 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
419 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x03F6);
420 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
421 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
423 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
427 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
429 /* Primary channel already claimed: claim secondary channel */
430 DPRINT1("Secondary channel!\n");
432 DevExt
->CommandPortBase
= 0x0170;
433 DevExt
->ControlPortBase
= 0x0376;
435 ConfigInfo
->BusInterruptLevel
= 15;
436 ConfigInfo
->BusInterruptVector
= 15;
437 ConfigInfo
->InterruptMode
= LevelSensitive
;
439 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0170);
440 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
441 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
443 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0376);
444 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
445 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
447 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
452 /* Find attached devices */
453 if (ChannelFound
== TRUE
)
455 DeviceFound
= AtapiFindDevices(DevExt
,
458 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
459 return(SP_RETURN_FOUND
);
463 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
465 return(SP_RETURN_NOT_FOUND
);
470 AtapiFindIsaBusController(PVOID DeviceExtension
,
472 PVOID BusInformation
,
473 PCHAR ArgumentString
,
474 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
477 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
479 DPRINT("AtapiFindIsaBusController() called!\n");
483 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
)
485 DPRINT("Primary IDE controller already claimed!\n");
489 if (ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
491 DPRINT("Secondary IDE controller already claimed!\n");
495 DPRINT("AtapiFindIsaBusController() done!\n");
497 return(SP_RETURN_NOT_FOUND
);
502 AtapiFindNativePciController(PVOID DeviceExtension
,
504 PVOID BusInformation
,
505 PCHAR ArgumentString
,
506 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
509 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
511 DPRINT("AtapiFindNativePciController() called!\n");
515 DPRINT("AtapiFindNativePciController() done!\n");
517 return(SP_RETURN_NOT_FOUND
);
521 static BOOLEAN STDCALL
522 AtapiInitialize(IN PVOID DeviceExtension
)
528 static BOOLEAN STDCALL
529 AtapiResetBus(IN PVOID DeviceExtension
,
536 static BOOLEAN STDCALL
537 AtapiStartIo(IN PVOID DeviceExtension
,
538 IN PSCSI_REQUEST_BLOCK Srb
)
540 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
543 DPRINT("AtapiStartIo() called\n");
545 switch (Srb
->Function
)
547 case SRB_FUNCTION_EXECUTE_SCSI
:
549 Result
= AtapiExecuteScsi(DevExt
,
556 Srb
->SrbStatus
= Result
;
562 static BOOLEAN STDCALL
563 AtapiInterrupt(IN PVOID DeviceExtension
)
565 DPRINT("AtapiInterrupt() called!\n");
575 // ---------------------------------------------------- Discardable statics
579 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
580 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
582 BOOLEAN DeviceFound
= FALSE
;
583 ULONG CommandPortBase
;
588 DPRINT("AtapiFindDevices() called\n");
590 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
591 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
593 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
595 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
597 /* disable interrupts */
598 IDEWriteDriveControl(CommandPortBase
,
602 IDEWriteDriveHead(CommandPortBase
,
603 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
604 ScsiPortStallExecution(500);
605 IDEWriteCylinderHigh(CommandPortBase
, 0);
606 IDEWriteCylinderLow(CommandPortBase
, 0);
607 IDEWriteCommand(CommandPortBase
, 0x08); /* IDE_COMMAND_ATAPI_RESET */
608 // ScsiPortStallExecution(1000*1000);
609 // IDEWriteDriveHead(CommandPortBase,
610 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
613 for (Retries
= 0; Retries
< 20000; Retries
++)
615 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
619 ScsiPortStallExecution(150);
621 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
623 DbgPrint("Timeout on drive %lu\n", UnitNumber
);
627 High
= IDEReadCylinderHigh(CommandPortBase
);
628 Low
= IDEReadCylinderLow(CommandPortBase
);
630 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
635 if (High
== 0xEB && Low
== 0x14)
637 if (AtapiIdentifyATAPIDevice(CommandPortBase
,
639 &DeviceExtension
->DeviceParams
[UnitNumber
]))
641 DPRINT(" ATAPI drive found!\n");
642 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
643 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
648 DPRINT(" No ATAPI drive found!\n");
653 if (AtapiIdentifyATADevice(CommandPortBase
,
655 &DeviceExtension
->DeviceParams
[UnitNumber
]))
657 DPRINT(" IDE drive found!\n");
658 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
659 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
664 DPRINT(" No IDE drive found!\n");
669 DPRINT("AtapiFindDrives() done\n");
675 // AtapiResetController
678 // Reset the controller and report completion status
684 // IN WORD CommandPort The address of the command port
685 // IN WORD ControlPort The address of the control port
691 AtapiResetController(IN WORD CommandPort
,
696 /* Assert drive reset line */
697 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
699 /* Wait for min. 25 microseconds */
700 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
702 /* Negate drive reset line */
703 IDEWriteDriveControl(ControlPort
, 0);
705 /* Wait for BUSY negation */
706 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
708 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
712 ScsiPortStallExecution(10);
716 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
723 // return TRUE if controller came back to life. and
724 // the registers are initialized correctly
725 return(IDEReadError(CommandPort
) == 1);
729 // AtapiIdentifyATADevice
732 // Get the identification block from the drive
738 // IN int CommandPort Address of the command port
739 // IN int DriveNum The drive index (0,1)
740 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
743 // TRUE The drive identification block was retrieved successfully
747 AtapiIdentifyATADevice(IN ULONG CommandPort
,
749 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
751 /* Get the Drive Identify block from drive or die */
752 if (AtapiPolledRead((WORD
)CommandPort
,
758 (DriveNum
? IDE_DH_DRV1
: 0),
759 IDE_CMD_IDENT_ATA_DRV
,
760 (BYTE
*)DrvParms
) != 0)
765 /* Report on drive parameters if debug mode */
766 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
767 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
768 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
769 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
770 DrvParms
->ConfigBits
,
771 DrvParms
->LogicalCyls
,
772 DrvParms
->LogicalHeads
,
773 DrvParms
->SectorsPerTrack
,
774 DrvParms
->InterSectorGap
,
775 DrvParms
->InterSectorGapSize
);
776 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
777 DrvParms
->BytesInPLO
,
778 DrvParms
->VendorUniqueCnt
,
779 DrvParms
->SerialNumber
);
780 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
781 DrvParms
->ControllerType
,
782 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
783 DrvParms
->ECCByteCnt
,
784 DrvParms
->FirmwareRev
);
785 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
786 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
787 (DrvParms
->RWMultImplemented
) & 0xff,
788 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
789 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
790 DrvParms
->MinPIOTransTime
,
791 DrvParms
->MinDMATransTime
);
792 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
793 DrvParms
->TMCylinders
,
795 DrvParms
->TMSectorsPerTrk
,
796 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
797 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
798 DrvParms
->TMSectorCountHi
,
799 DrvParms
->TMSectorCountLo
,
800 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
802 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
803 if (DrvParms
->BytesPerSector
== 0)
804 DrvParms
->BytesPerSector
= 512;
810 AtapiIdentifyATAPIDevice(IN ULONG CommandPort
,
812 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
814 /* Get the Drive Identify block from drive or die */
815 if (AtapiPolledRead((WORD
)CommandPort
,
821 (DriveNum
? IDE_DH_DRV1
: 0),
822 IDE_CMD_IDENT_ATAPI_DRV
,
823 (BYTE
*)DrvParms
) != 0) /* atapi_identify */
825 DPRINT1("IDEPolledRead() failed\n");
829 /* Report on drive parameters if debug mode */
830 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
831 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
832 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
833 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
834 DrvParms
->ConfigBits
,
835 DrvParms
->LogicalCyls
,
836 DrvParms
->LogicalHeads
,
837 DrvParms
->SectorsPerTrack
,
838 DrvParms
->InterSectorGap
,
839 DrvParms
->InterSectorGapSize
);
840 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
841 DrvParms
->BytesInPLO
,
842 DrvParms
->VendorUniqueCnt
,
843 DrvParms
->SerialNumber
);
844 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
845 DrvParms
->ControllerType
,
846 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
847 DrvParms
->ECCByteCnt
,
848 DrvParms
->FirmwareRev
);
849 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
850 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
851 (DrvParms
->RWMultImplemented
) & 0xff,
852 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
853 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
854 DrvParms
->MinPIOTransTime
,
855 DrvParms
->MinDMATransTime
);
856 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
857 DrvParms
->TMCylinders
,
859 DrvParms
->TMSectorsPerTrk
,
860 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
861 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
862 DrvParms
->TMSectorCountHi
,
863 DrvParms
->TMSectorCountLo
,
864 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
866 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
867 // DrvParms->BytesPerSector = 512; /* FIXME !!!*/
875 // Read a sector of data from the drive in a polled fashion.
881 // IN WORD Address Address of command port for drive
882 // IN BYTE PreComp Value to write to precomp register
883 // IN BYTE SectorCnt Value to write to sectorCnt register
884 // IN BYTE SectorNum Value to write to sectorNum register
885 // IN BYTE CylinderLow Value to write to CylinderLow register
886 // IN BYTE CylinderHigh Value to write to CylinderHigh register
887 // IN BYTE DrvHead Value to write to Drive/Head register
888 // IN BYTE Command Value to write to Command register
889 // OUT BYTE *Buffer Buffer for output data
892 // int 0 is success, non 0 is an error code
896 AtapiPolledRead(IN WORD Address
,
901 IN BYTE CylinderHigh
,
906 ULONG SectorCount
= 0;
908 BOOLEAN Junk
= FALSE
;
911 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
912 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
914 Status
= IDEReadStatus(Address
);
915 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
919 ScsiPortStallExecution(10);
921 if (RetryCount
== IDE_MAX_BUSY_RETRIES
)
926 /* Write Drive/Head to select drive */
927 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
929 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
930 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
932 Status
= IDEReadStatus(Address
);
933 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
937 ScsiPortStallExecution(10);
939 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
944 /* Issue command to drive */
945 if (DrvHead
& IDE_DH_LBA
)
947 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
948 DrvHead
& IDE_DH_DRV1
? 1 : 0,
949 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
955 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
956 DrvHead
& IDE_DH_DRV1
? 1 : 0,
965 /* Setup command parameters */
966 IDEWritePrecomp(Address
, PreComp
);
967 IDEWriteSectorCount(Address
, SectorCnt
);
968 IDEWriteSectorNum(Address
, SectorNum
);
969 IDEWriteCylinderHigh(Address
, CylinderHigh
);
970 IDEWriteCylinderLow(Address
, CylinderLow
);
971 IDEWriteDriveHead(Address
, IDE_DH_FIXED
| DrvHead
);
973 /* Issue the command */
974 IDEWriteCommand(Address
, Command
);
975 ScsiPortStallExecution(50);
977 /* wait for DRQ or error */
978 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
980 Status
= IDEReadStatus(Address
);
981 if (!(Status
& IDE_SR_BUSY
))
983 if (Status
& IDE_SR_ERR
)
987 if (Status
& IDE_SR_DRQ
)
996 ScsiPortStallExecution(10);
1000 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1002 return(IDE_ER_ABRT
);
1007 /* Read data into buffer */
1010 IDEReadBlock(Address
, Buffer
, IDE_SECTOR_BUF_SZ
);
1011 Buffer
+= IDE_SECTOR_BUF_SZ
;
1015 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1016 IDEReadBlock(Address
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1020 /* Check for error or more sectors to read */
1021 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1023 Status
= IDEReadStatus(Address
);
1024 if (!(Status
& IDE_SR_BUSY
))
1026 if (Status
& IDE_SR_ERR
)
1028 return(IDE_ER_ABRT
);
1030 if (Status
& IDE_SR_DRQ
)
1032 if (SectorCount
>= SectorCnt
)
1034 DPRINT("Buffer size exceeded!\n");
1041 if (SectorCount
> SectorCnt
)
1043 DPRINT("Read %lu sectors of junk!\n",
1044 SectorCount
- SectorCnt
);
1054 // ------------------------------------------- Nondiscardable statics
1058 AtapiExecuteScsi(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1059 IN PSCSI_REQUEST_BLOCK Srb
)
1061 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1063 DPRINT1("AtapiExecuteScsi() called!\n");
1065 DPRINT1("PathId: %lu TargetId: %lu Lun: %lu\n",
1070 switch (Srb
->Cdb
[0])
1072 case SCSIOP_INQUIRY
:
1073 SrbStatus
= AtapiInquiry(DeviceExtension
,
1077 case SCSIOP_READ_CAPACITY
:
1078 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1084 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1088 case SCSIOP_MODE_SENSE
:
1089 case SCSIOP_TEST_UNIT_READY
:
1091 case SCSIOP_START_STOP_UNIT
:
1092 case SCSIOP_REQUEST_SENSE
:
1096 DPRINT1("AtapiExecuteScsi():unknown command %x\n",
1098 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1102 DPRINT1("AtapiExecuteScsi() done!\n");
1109 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1110 PSCSI_REQUEST_BLOCK Srb
)
1112 PIDE_DRIVE_IDENTIFY DeviceParams
;
1113 PINQUIRYDATA InquiryData
;
1116 DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb
->TargetId
);
1118 if ((Srb
->PathId
!= 0) ||
1119 (Srb
->TargetId
> 1) ||
1121 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1123 return(SRB_STATUS_SELECTION_TIMEOUT
);
1126 InquiryData
= Srb
->DataBuffer
;
1127 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1130 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1132 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1135 /* set device class */
1136 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1139 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1143 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1145 InquiryData
->DeviceType
= READ_ONLY_DIRECT_ACCESS_DEVICE
;
1148 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1149 if (DeviceParams
->ConfigBits
& 0x80)
1151 DPRINT1("Removable media!\n");
1152 InquiryData
->RemovableMedia
= 1;
1155 for (i
= 0; i
< 20; i
+= 2)
1157 InquiryData
->VendorId
[i
] =
1158 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1159 InquiryData
->VendorId
[i
+1] =
1160 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1163 for (i
= 0; i
< 4; i
++)
1165 InquiryData
->ProductId
[12+i
] = ' ';
1168 for (i
= 0; i
< 4; i
+= 2)
1170 InquiryData
->ProductRevisionLevel
[i
] =
1171 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1172 InquiryData
->ProductRevisionLevel
[i
+1] =
1173 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1176 return(SRB_STATUS_SUCCESS
);
1181 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1182 PSCSI_REQUEST_BLOCK Srb
)
1184 PREAD_CAPACITY_DATA CapacityData
;
1185 PIDE_DRIVE_IDENTIFY DeviceParams
;
1188 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1190 if ((Srb
->PathId
!= 0) ||
1191 (Srb
->TargetId
> 1) ||
1193 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1195 return(SRB_STATUS_SELECTION_TIMEOUT
);
1199 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1200 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1202 /* Set sector (block) size to 512 bytes (big-endian). */
1203 CapacityData
->BytesPerBlock
= 0x20000;
1205 /* Calculate last sector (big-endian). */
1206 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1208 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1209 DeviceParams
->TMSectorCountLo
) - 1;
1213 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1214 DeviceParams
->LogicalHeads
*
1215 DeviceParams
->SectorsPerTrack
)-1;
1218 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1219 (((PUCHAR
)&LastSector
)[1] << 16) |
1220 (((PUCHAR
)&LastSector
)[2] << 8) |
1221 ((PUCHAR
)&LastSector
)[3];
1223 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1226 CapacityData
->LogicalBlockAddress
);
1228 return(SRB_STATUS_SUCCESS
);
1233 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1234 PSCSI_REQUEST_BLOCK Srb
)
1236 PIDE_DRIVE_IDENTIFY DeviceParams
;
1238 ULONG StartingSector
,i
;
1249 DPRINT1("AtapiReadWrite() called!\n");
1251 if ((Srb
->PathId
!= 0) ||
1252 (Srb
->TargetId
> 1) ||
1254 (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
))
1256 return(SRB_STATUS_SELECTION_TIMEOUT
);
1259 DPRINT1("SCSIOP_WRITE: TargetId: %lu\n",
1262 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1264 /* Get starting sector number from CDB. */
1265 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1266 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1267 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1268 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1270 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1271 DeviceParams
->BytesPerSector
;
1273 DPRINT1("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1275 Srb
->DataTransferLength
,
1278 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1280 SectorNumber
= StartingSector
& 0xff;
1281 CylinderLow
= (StartingSector
>> 8) & 0xff;
1282 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1283 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1284 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1289 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1290 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1291 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1292 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1293 StartingSector
/= DeviceParams
->LogicalHeads
;
1294 CylinderLow
= StartingSector
& 0xff;
1295 CylinderHigh
= StartingSector
>> 8;
1299 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1301 Command
= IDE_CMD_READ
;
1305 Command
= IDE_CMD_WRITE
;
1308 if (DrvHead
& IDE_DH_LBA
)
1310 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1311 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1312 DeviceExtension
->CommandPortBase
,
1313 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1314 ((DrvHead
& 0x0f) << 24) +
1315 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1321 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1322 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1323 DeviceExtension
->CommandPortBase
,
1324 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1333 /* Set pointer to data buffer. */
1334 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1339 /* wait for BUSY to clear */
1340 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1342 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1343 if (!(Status
& IDE_SR_BUSY
))
1347 ScsiPortStallExecution(10);
1349 DPRINT ("status=%02x\n", Status
);
1350 DPRINT ("waited %ld usecs for busy to clear\n", Retries
* 10);
1351 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1353 DPRINT ("Drive is BUSY for too long\n");
1354 return(SRB_STATUS_BUSY
);
1356 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1358 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1359 Irp
= ControllerExtension
->CurrentIrp
;
1360 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1361 Irp
->IoStatus
.Information
= 0;
1367 DPRINT ("Beginning drive reset sequence\n");
1368 IDEBeginControllerReset(ControllerExtension
);
1375 /* Select the desired drive */
1376 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1377 IDE_DH_FIXED
| DrvHead
);
1379 /* wait for BUSY to clear and DRDY to assert */
1380 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1382 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1383 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1387 ScsiPortStallExecution(10);
1389 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1390 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1392 DPRINT ("Drive is BUSY for too long after drive select\n");
1393 return(SRB_STATUS_BUSY
);
1395 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1397 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1398 Irp
= ControllerExtension
->CurrentIrp
;
1399 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1400 Irp
->IoStatus
.Information
= 0;
1406 DPRINT ("Beginning drive reset sequence\n");
1407 IDEBeginControllerReset(ControllerExtension
);
1414 /* Indicate expecting an interrupt. */
1415 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1417 /* Setup command parameters */
1418 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1419 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
1420 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
1421 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
1422 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
1423 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
1425 /* Issue command to drive */
1426 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
1427 // ControllerExtension->TimerState = IDETimerCmdWait;
1428 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1432 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
== 0)
1434 DPRINT1("Write not implemented yet!\n");
1437 DPRINT1("AtapiReadWrite() done!\n");
1439 /* Wait for interrupt. */
1440 return(SRB_STATUS_PENDING
);