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.30 2002/11/11 21:51:33 hbirr 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
45 #define ENABLE_MULTIMODE // enables multiple sector commands
46 #define ENABLE_32BIT // enables 32Bit I/O for disk transfer (not for ATAPI)
48 // -------------------------------------------------------------------------
50 #include <ddk/ntddk.h>
53 #include <ddk/ntddscsi.h>
60 #define VERSION "0.0.1"
63 // ------------------------------------------------------- File Static Data
65 // ATAPI_MINIPORT_EXTENSION
68 // Extension to be placed in each port device object
71 // Allocated from NON-PAGED POOL
72 // Available at any IRQL
75 typedef struct _ATAPI_MINIPORT_EXTENSION
77 IDE_DRIVE_IDENTIFY DeviceParams
[2];
78 BOOLEAN DevicePresent
[2];
79 BOOLEAN DeviceAtapi
[2];
81 ULONG CommandPortBase
;
82 ULONG ControlPortBase
;
83 ULONG BusMasterRegisterBase
;
85 BOOLEAN ExpectingInterrupt
;
86 PSCSI_REQUEST_BLOCK CurrentSrb
;
89 } ATAPI_MINIPORT_EXTENSION
, *PATAPI_MINIPORT_EXTENSION
;
92 typedef struct _UNIT_EXTENSION
95 } UNIT_EXTENSION
, *PUNIT_EXTENSION
;
98 // ----------------------------------------------- Discardable Declarations
102 // make the initialization routines discardable, so that they
105 #pragma alloc_text(init, DriverEntry)
106 #pragma alloc_text(init, IDECreateController)
107 #pragma alloc_text(init, IDEPolledRead)
109 // make the PASSIVE_LEVEL routines pageable, so that they don't
110 // waste nonpaged memory
112 #pragma alloc_text(page, IDEShutdown)
113 #pragma alloc_text(page, IDEDispatchOpenClose)
114 #pragma alloc_text(page, IDEDispatchRead)
115 #pragma alloc_text(page, IDEDispatchWrite)
117 #endif /* ALLOC_PRAGMA */
119 // ---------------------------------------------------- Forward Declarations
122 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
124 PVOID BusInformation
,
125 PCHAR ArgumentString
,
126 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
130 AtapiFindIsaBusController(PVOID DeviceExtension
,
132 PVOID BusInformation
,
133 PCHAR ArgumentString
,
134 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
138 AtapiFindNativePciController(PVOID DeviceExtension
,
140 PVOID BusInformation
,
141 PCHAR ArgumentString
,
142 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
145 static BOOLEAN STDCALL
146 AtapiInitialize(IN PVOID DeviceExtension
);
148 static BOOLEAN STDCALL
149 AtapiResetBus(IN PVOID DeviceExtension
,
152 static BOOLEAN STDCALL
153 AtapiStartIo(IN PVOID DeviceExtension
,
154 IN PSCSI_REQUEST_BLOCK Srb
);
156 static BOOLEAN STDCALL
157 AtapiInterrupt(IN PVOID DeviceExtension
);
160 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
161 PPORT_CONFIGURATION_INFORMATION ConfigInfo
);
164 AtapiIdentifyDevice(IN ULONG CommandPort
,
165 IN ULONG ControlPort
,
168 OUT PIDE_DRIVE_IDENTIFY DrvParms
);
171 IDEResetController(IN ULONG CommandPort
,
172 IN ULONG ControlPort
);
175 AtapiPolledRead(IN ULONG CommandPort
,
176 IN ULONG ControlPort
,
181 IN BYTE CylinderHigh
,
189 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
190 IN PSCSI_REQUEST_BLOCK Srb
);
193 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
194 IN PSCSI_REQUEST_BLOCK Srb
);
197 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
198 IN PSCSI_REQUEST_BLOCK Srb
);
201 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
202 IN PSCSI_REQUEST_BLOCK Srb
);
205 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
206 IN PSCSI_REQUEST_BLOCK Srb
);
210 AtapiErrorToScsi(PVOID DeviceExtension
,
211 PSCSI_REQUEST_BLOCK Srb
);
213 // ---------------------------------------------------------------- Inlines
216 IDESwapBytePairs(char *Buf
,
222 for (i
= 0; i
< Cnt
; i
+= 2)
231 // ------------------------------------------------------- Public Interface
236 // This function initializes the driver, locates and claims
237 // hardware resources, and creates various NT objects needed
238 // to process I/O requests.
244 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
246 // IN PUNICODE_STRING RegistryPath Name of registry driver service
253 DriverEntry(IN PDRIVER_OBJECT DriverObject
,
254 IN PUNICODE_STRING RegistryPath
)
256 HW_INITIALIZATION_DATA InitData
;
259 DPRINT("ATAPI Driver %s\n", VERSION
);
260 DPRINT("RegistryPath: '%wZ'\n", RegistryPath
);
262 /* Initialize data structure */
263 RtlZeroMemory(&InitData
,
264 sizeof(HW_INITIALIZATION_DATA
));
265 InitData
.HwInitializationDataSize
= sizeof(HW_INITIALIZATION_DATA
);
266 InitData
.HwInitialize
= AtapiInitialize
;
267 InitData
.HwResetBus
= AtapiResetBus
;
268 InitData
.HwStartIo
= AtapiStartIo
;
269 InitData
.HwInterrupt
= AtapiInterrupt
;
271 InitData
.DeviceExtensionSize
= sizeof(ATAPI_MINIPORT_EXTENSION
);
272 InitData
.SpecificLuExtensionSize
= sizeof(UNIT_EXTENSION
);
274 InitData
.MapBuffers
= TRUE
;
276 /* Search the PCI bus for compatibility mode ide controllers */
278 InitData
.HwFindAdapter
= AtapiFindCompatiblePciController
;
279 InitData
.NumberOfAccessRanges
= 3;
280 InitData
.AdapterInterfaceType
= PCIBus
;
282 InitData
.VendorId
= NULL
;
283 InitData
.VendorIdLength
= 0;
284 InitData
.DeviceId
= NULL
;
285 InitData
.DeviceIdLength
= 0;
287 Status
= ScsiPortInitialize(DriverObject
,
291 // if (newStatus < statusToReturn)
292 // statusToReturn = newStatus;
295 /* Search the ISA bus for ide controllers */
297 InitData
.HwFindAdapter
= AtapiFindIsaBusController
;
298 InitData
.NumberOfAccessRanges
= 2;
299 InitData
.AdapterInterfaceType
= Isa
;
301 InitData
.VendorId
= NULL
;
302 InitData
.VendorIdLength
= 0;
303 InitData
.DeviceId
= NULL
;
304 InitData
.DeviceIdLength
= 0;
306 Status
= ScsiPortInitialize(DriverObject
,
310 // if (newStatus < statusToReturn)
311 // statusToReturn = newStatus;
314 /* Search the PCI bus for native mode ide controllers */
316 InitData
.HwFindAdapter
= AtapiFindNativePciController
;
317 InitData
.NumberOfAccessRanges
= 2;
318 InitData
.AdapterInterfaceType
= PCIBus
;
320 InitData
.VendorId
= NULL
;
321 InitData
.VendorIdLength
= 0;
322 InitData
.DeviceId
= NULL
;
323 InitData
.DeviceIdLength
= 0;
325 Status
= ScsiPortInitialize(DriverObject
,
329 // if (newStatus < statusToReturn)
330 // statusToReturn = newStatus;
333 DPRINT("Returning from DriverEntry\n");
340 AtapiFindCompatiblePciController(PVOID DeviceExtension
,
342 PVOID BusInformation
,
343 PCHAR ArgumentString
,
344 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
347 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
348 PCI_SLOT_NUMBER SlotNumber
;
349 PCI_COMMON_CONFIG PciConfig
;
351 ULONG FunctionNumber
;
352 BOOLEAN ChannelFound
;
355 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
356 ConfigInfo
->SystemIoBusNumber
,
357 ConfigInfo
->SlotNumber
);
361 /* both channels were claimed: exit */
362 if (ConfigInfo
->AtdiskPrimaryClaimed
== TRUE
&&
363 ConfigInfo
->AtdiskSecondaryClaimed
== TRUE
)
364 return(SP_RETURN_NOT_FOUND
);
367 SlotNumber
.u
.AsULONG
= 0;
368 for (FunctionNumber
= 0 /*ConfigInfo->SlotNumber*/; FunctionNumber
< 256; FunctionNumber
++)
370 SlotNumber
.u
.AsULONG
= FunctionNumber
;
372 ChannelFound
= FALSE
;
375 DataSize
= ScsiPortGetBusData(DeviceExtension
,
378 SlotNumber
.u
.AsULONG
,
380 sizeof(PCI_COMMON_CONFIG
));
381 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
382 // PciConfig.VendorID == PCI_INVALID_VENDORID)
385 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
386 // return(SP_RETURN_ERROR); /* No bus found */
389 // return(SP_RETURN_ERROR);
392 if (PciConfig
.BaseClass
== 0x01 &&
393 PciConfig
.SubClass
== 0x01) // &&
394 // (PciConfig.ProgIf & 0x05) == 0)
396 /* both channels are in compatibility mode */
397 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
398 ConfigInfo
->SystemIoBusNumber
,
399 SlotNumber
.u
.bits
.DeviceNumber
,
400 SlotNumber
.u
.bits
.FunctionNumber
,
403 DPRINT("ProgIF 0x%02hx\n", PciConfig
.ProgIf
);
405 DPRINT("Found IDE controller in compatibility mode!\n");
407 ConfigInfo
->NumberOfBuses
= 1;
408 ConfigInfo
->MaximumNumberOfTargets
= 2;
409 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
411 if (PciConfig
.ProgIf
& 0x80)
413 DPRINT("Found IDE Bus Master controller!\n");
414 if (PciConfig
.u
.type0
.BaseAddresses
[4] & 0x00000001)
416 DPRINT(" IDE Bus Master Registers at IO %lx\n",
417 PciConfig
.u
.type0
.BaseAddresses
[4] & ~0x00000003);
421 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
423 /* Both channels unclaimed: Claim primary channel */
424 DPRINT("Primary channel!\n");
426 DevExt
->CommandPortBase
= 0x01F0;
427 DevExt
->ControlPortBase
= 0x03F6;
429 ConfigInfo
->BusInterruptLevel
= 14;
430 ConfigInfo
->BusInterruptVector
= 14;
431 ConfigInfo
->InterruptMode
= LevelSensitive
;
433 ConfigInfo
->AccessRanges
[0].RangeStart
=
434 ScsiPortConvertUlongToPhysicalAddress(0x01F0);
435 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
436 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
438 ConfigInfo
->AccessRanges
[1].RangeStart
=
439 ScsiPortConvertUlongToPhysicalAddress(0x03F6);
440 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
441 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
443 /* Claim bus master registers */
444 if (PciConfig
.ProgIf
& 0x80)
446 DevExt
->BusMasterRegisterBase
=
447 PciConfig
.u
.type0
.BaseAddresses
[4] & ~0x00000003;
449 ConfigInfo
->AccessRanges
[2].RangeStart
=
450 ScsiPortConvertUlongToPhysicalAddress(DevExt
->BusMasterRegisterBase
);
451 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
452 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
455 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
459 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
461 /* Primary channel already claimed: claim secondary channel */
462 DPRINT("Secondary channel!\n");
464 DevExt
->CommandPortBase
= 0x0170;
465 DevExt
->ControlPortBase
= 0x0376;
467 ConfigInfo
->BusInterruptLevel
= 15;
468 ConfigInfo
->BusInterruptVector
= 15;
469 ConfigInfo
->InterruptMode
= LevelSensitive
;
471 ConfigInfo
->AccessRanges
[0].RangeStart
=
472 ScsiPortConvertUlongToPhysicalAddress(0x0170);
473 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
474 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
476 ConfigInfo
->AccessRanges
[1].RangeStart
=
477 ScsiPortConvertUlongToPhysicalAddress(0x0376);
478 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
479 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
481 /* Claim bus master registers */
482 if (PciConfig
.ProgIf
& 0x80)
484 DevExt
->BusMasterRegisterBase
=
485 (PciConfig
.u
.type0
.BaseAddresses
[4] & ~0x00000003) + 8;
487 ConfigInfo
->AccessRanges
[2].RangeStart
=
488 ScsiPortConvertUlongToPhysicalAddress(DevExt
->BusMasterRegisterBase
);
489 ConfigInfo
->AccessRanges
[2].RangeLength
= 8;
490 ConfigInfo
->AccessRanges
[2].RangeInMemory
= FALSE
;
493 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
498 /* Find attached devices */
499 if (ChannelFound
== TRUE
)
501 DeviceFound
= AtapiFindDevices(DevExt
,
504 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
505 return(SP_RETURN_FOUND
);
509 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
511 return(SP_RETURN_NOT_FOUND
);
516 AtapiFindIsaBusController(PVOID DeviceExtension
,
518 PVOID BusInformation
,
519 PCHAR ArgumentString
,
520 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
523 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
524 BOOLEAN ChannelFound
= FALSE
;
525 BOOLEAN DeviceFound
= FALSE
;
527 DPRINT("AtapiFindIsaBusController() called!\n");
531 ConfigInfo
->NumberOfBuses
= 1;
532 ConfigInfo
->MaximumNumberOfTargets
= 2;
533 ConfigInfo
->MaximumTransferLength
= 0x10000; /* max 64Kbyte */
535 if (ConfigInfo
->AtdiskPrimaryClaimed
== FALSE
)
537 /* Both channels unclaimed: Claim primary channel */
538 DPRINT("Primary channel!\n");
540 DevExt
->CommandPortBase
= 0x01F0;
541 DevExt
->ControlPortBase
= 0x03F6;
543 ConfigInfo
->BusInterruptLevel
= 14;
544 ConfigInfo
->BusInterruptVector
= 14;
545 ConfigInfo
->InterruptMode
= LevelSensitive
;
547 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x01F0);
548 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
549 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
551 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x03F6);
552 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
553 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
555 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
559 else if (ConfigInfo
->AtdiskSecondaryClaimed
== FALSE
)
561 /* Primary channel already claimed: claim secondary channel */
562 DPRINT("Secondary channel!\n");
564 DevExt
->CommandPortBase
= 0x0170;
565 DevExt
->ControlPortBase
= 0x0376;
567 ConfigInfo
->BusInterruptLevel
= 15;
568 ConfigInfo
->BusInterruptVector
= 15;
569 ConfigInfo
->InterruptMode
= LevelSensitive
;
571 ConfigInfo
->AccessRanges
[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0170);
572 ConfigInfo
->AccessRanges
[0].RangeLength
= 8;
573 ConfigInfo
->AccessRanges
[0].RangeInMemory
= FALSE
;
575 ConfigInfo
->AccessRanges
[1].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(0x0376);
576 ConfigInfo
->AccessRanges
[1].RangeLength
= 1;
577 ConfigInfo
->AccessRanges
[1].RangeInMemory
= FALSE
;
579 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
585 DPRINT("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
587 return(SP_RETURN_NOT_FOUND
);
590 /* Find attached devices */
593 DeviceFound
= AtapiFindDevices(DevExt
,
597 DPRINT("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
598 return(SP_RETURN_FOUND
);
603 AtapiFindNativePciController(PVOID DeviceExtension
,
605 PVOID BusInformation
,
606 PCHAR ArgumentString
,
607 PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
610 PATAPI_MINIPORT_EXTENSION DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
612 DPRINT("AtapiFindNativePciController() called!\n");
616 DPRINT("AtapiFindNativePciController() done!\n");
618 return(SP_RETURN_NOT_FOUND
);
622 static BOOLEAN STDCALL
623 AtapiInitialize(IN PVOID DeviceExtension
)
629 static BOOLEAN STDCALL
630 AtapiResetBus(IN PVOID DeviceExtension
,
637 static BOOLEAN STDCALL
638 AtapiStartIo(IN PVOID DeviceExtension
,
639 IN PSCSI_REQUEST_BLOCK Srb
)
641 PATAPI_MINIPORT_EXTENSION DevExt
;
644 DPRINT("AtapiStartIo() called\n");
646 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
648 switch (Srb
->Function
)
650 case SRB_FUNCTION_EXECUTE_SCSI
:
651 DevExt
->CurrentSrb
= Srb
;
652 if (DevExt
->DeviceAtapi
[Srb
->TargetId
] == TRUE
)
654 Result
= AtapiSendAtapiCommand(DevExt
,
659 Result
= AtapiSendIdeCommand(DevExt
,
666 Srb
->SrbStatus
= Result
;
669 if (Result
!= SRB_STATUS_PENDING
)
671 DevExt
->CurrentSrb
= NULL
;
672 Srb
->SrbStatus
= (UCHAR
)Result
;
674 ScsiPortNotification(RequestComplete
,
677 ScsiPortNotification(NextRequest
,
683 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
686 DPRINT("AtapiStartIo() done\n");
692 static BOOLEAN STDCALL
693 AtapiInterrupt(IN PVOID DeviceExtension
)
695 PATAPI_MINIPORT_EXTENSION DevExt
;
696 PSCSI_REQUEST_BLOCK Srb
;
697 ULONG CommandPortBase
;
698 ULONG ControlPortBase
;
704 PUCHAR TargetAddress
;
707 DPRINT("AtapiInterrupt() called!\n");
709 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
710 if (DevExt
->ExpectingInterrupt
== FALSE
)
712 DPRINT("AtapiInterrupt(): Unexpected interrupt\n");
716 Srb
= DevExt
->CurrentSrb
;
717 DPRINT("Srb: %p\n", Srb
);
719 CommandPortBase
= DevExt
->CommandPortBase
;
720 ControlPortBase
= DevExt
->ControlPortBase
;
721 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase
, ControlPortBase
);
723 IsAtapi
= DevExt
->DeviceAtapi
[Srb
->TargetId
];
724 DPRINT("IsAtapi == %s\n", (IsAtapi
) ? "TRUE" : "FALSE");
728 DeviceStatus
= IDEReadStatus(CommandPortBase
);
729 DPRINT("DeviceStatus: %x\n", DeviceStatus
);
731 if (DeviceStatus
& IDE_SR_BUSY
)
733 /* Wait for BUSY to drop */
734 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
736 DeviceStatus
= IDEReadStatus(CommandPortBase
);
737 if (!(DeviceStatus
& IDE_SR_BUSY
))
741 ScsiPortStallExecution(10);
743 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
745 DPRINT1("Drive is BUSY for too long\n");
746 /* FIXME: handle timeout */
750 if ((DeviceStatus
& IDE_SR_ERR
) &&
751 (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
))
753 /* Report error condition */
754 Srb
->SrbStatus
= SRB_STATUS_ERROR
;
759 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
761 DPRINT("Read data\n");
763 /* Update controller/device state variables */
764 TargetAddress
= Srb
->DataBuffer
;
768 TransferSize
= IDEReadCylinderLow(CommandPortBase
);
769 TransferSize
+= IDEReadCylinderHigh(CommandPortBase
) << 8;
773 TransferSize
= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
774 #ifdef ENABLE_MULTIMODE
775 if (DevExt
->DeviceParams
[Srb
->TargetId
].RWMultCurrent
& 0xff)
777 TransferSize
*= (DevExt
->DeviceParams
[Srb
->TargetId
].RWMultCurrent
& 0xff);
782 DPRINT("TransferLength: %lu\n", Srb
->DataTransferLength
);
783 DPRINT("TransferSize: %lu\n", TransferSize
);
785 if (Srb
->DataTransferLength
<= TransferSize
)
787 #ifdef ENABLE_MULTIMODE
790 TransferSize
= Srb
->DataTransferLength
;
793 Srb
->DataTransferLength
= 0;
798 Srb
->DataTransferLength
-= TransferSize
;
801 Srb
->DataBuffer
+= TransferSize
;
802 DPRINT("IsLastBlock == %s\n", (IsLastBlock
) ? "TRUE" : "FALSE");
804 /* Wait for DRQ assertion */
805 for (Retries
= 0; Retries
< IDE_MAX_DRQ_RETRIES
&&
806 !(IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
);
809 KeStallExecutionProcessor(10);
812 /* Copy the block of data */
816 IDEReadBlock(CommandPortBase
,
822 IDEReadBlock32(CommandPortBase
,
827 IDEReadBlock(CommandPortBase
,
834 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
835 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
838 KeStallExecutionProcessor(10);
841 /* Check for data overrun */
842 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
844 /* FIXME: Handle error! */
845 DPRINT1("AtapiInterrupt(): data overrun error!");
849 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
851 else if (Srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
)
853 DPRINT("Write data\n");
855 if (Srb
->DataTransferLength
== 0)
858 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
&&
859 (IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
);
862 KeStallExecutionProcessor(10);
865 /* Check for data overrun */
866 if (IDEReadStatus(CommandPortBase
) & IDE_SR_DRQ
)
868 /* FIXME: Handle error! */
869 DPRINT1("AtapiInterrupt(): data overrun error!");
872 DevExt
->ExpectingInterrupt
= FALSE
;
877 /* Update SRB data */
878 TransferSize
= DevExt
->DeviceParams
[Srb
->TargetId
].BytesPerSector
;
879 #ifdef ENABLE_MULTIMODE
880 if (DevExt
->DeviceParams
[Srb
->TargetId
].RWMultCurrent
& 0xff)
882 TransferSize
*= (DevExt
->DeviceParams
[Srb
->TargetId
].RWMultCurrent
& 0xff);
885 if (Srb
->DataTransferLength
<= TransferSize
)
887 TransferSize
= Srb
->DataTransferLength
;
890 TargetAddress
= Srb
->DataBuffer
;
891 Srb
->DataBuffer
+= TransferSize
;
892 Srb
->DataTransferLength
-= TransferSize
;
894 /* Write the sector */
896 IDEWriteBlock32(CommandPortBase
,
900 IDEWriteBlock(CommandPortBase
,
906 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
910 DPRINT1("Unspecified transfer direction!\n");
911 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
; // SRB_STATUS_ERROR;
917 if (Srb
->SrbStatus
== SRB_STATUS_ERROR
)
919 Srb
->SrbStatus
= AtapiErrorToScsi(DeviceExtension
,
924 /* complete this packet */
927 DevExt
->ExpectingInterrupt
= FALSE
;
929 ScsiPortNotification(RequestComplete
,
933 ScsiPortNotification(NextRequest
,
938 DPRINT("AtapiInterrupt() done!\n");
948 // ---------------------------------------------------- Discardable statics
951 /**********************************************************************
956 * Searches for devices on the given port.
963 * Port device specific information.
966 * Port configuration information.
969 * TRUE: At least one device is attached to the port.
970 * FALSE: No device is attached to the port.
974 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
975 PPORT_CONFIGURATION_INFORMATION ConfigInfo
)
977 BOOLEAN DeviceFound
= FALSE
;
978 ULONG CommandPortBase
;
979 ULONG ControlPortBase
;
984 DPRINT("AtapiFindDevices() called\n");
986 CommandPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[0].RangeStart
);
987 DPRINT(" CommandPortBase: %x\n", CommandPortBase
);
989 ControlPortBase
= ScsiPortConvertPhysicalAddressToUlong(ConfigInfo
->AccessRanges
[1].RangeStart
);
990 DPRINT(" ControlPortBase: %x\n", ControlPortBase
);
992 for (UnitNumber
= 0; UnitNumber
< 2; UnitNumber
++)
995 IDEWriteDriveHead(CommandPortBase
,
996 IDE_DH_FIXED
| (UnitNumber
? IDE_DH_DRV1
: 0));
997 ScsiPortStallExecution(500);
999 /* Disable interrupts */
1000 IDEWriteDriveControl(ControlPortBase
,
1002 ScsiPortStallExecution(500);
1004 IDEWriteCylinderHigh(CommandPortBase
, 0);
1005 IDEWriteCylinderLow(CommandPortBase
, 0);
1006 IDEWriteCommand(CommandPortBase
, IDE_CMD_RESET
);
1008 for (Retries
= 0; Retries
< 20000; Retries
++)
1010 if (!(IDEReadStatus(CommandPortBase
) & IDE_SR_BUSY
))
1014 ScsiPortStallExecution(150);
1016 if (Retries
>= 20000)
1018 DPRINT("Timeout on drive %lu\n", UnitNumber
);
1019 DeviceExtension
->DevicePresent
[UnitNumber
] = FALSE
;
1023 High
= IDEReadCylinderHigh(CommandPortBase
);
1024 Low
= IDEReadCylinderLow(CommandPortBase
);
1026 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
1031 if (High
== 0xEB && Low
== 0x14)
1033 if (AtapiIdentifyDevice(CommandPortBase
,
1037 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1039 DPRINT(" ATAPI drive found!\n");
1040 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
1041 DeviceExtension
->DeviceAtapi
[UnitNumber
] = TRUE
;
1046 DPRINT(" No ATAPI drive found!\n");
1051 if (AtapiIdentifyDevice(CommandPortBase
,
1055 &DeviceExtension
->DeviceParams
[UnitNumber
]))
1057 DPRINT(" IDE drive found!\n");
1058 DeviceExtension
->DevicePresent
[UnitNumber
] = TRUE
;
1059 DeviceExtension
->DeviceAtapi
[UnitNumber
] = FALSE
;
1064 DPRINT(" No IDE drive found!\n");
1070 DPRINT("AtapiFindDrives() done (DeviceFound %s)\n", (DeviceFound
) ? "TRUE" : "FALSE");
1072 return(DeviceFound
);
1076 // AtapiResetController
1079 // Reset the controller and report completion status
1085 // IN WORD CommandPort The address of the command port
1086 // IN WORD ControlPort The address of the control port
1092 AtapiResetController(IN ULONG CommandPort
,
1093 IN ULONG ControlPort
)
1097 /* Assert drive reset line */
1098 IDEWriteDriveControl(ControlPort
, IDE_DC_SRST
);
1100 /* Wait for min. 25 microseconds */
1101 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH
);
1103 /* Negate drive reset line */
1104 IDEWriteDriveControl(ControlPort
, 0);
1106 /* Wait for BUSY negation */
1107 for (Retries
= 0; Retries
< IDE_RESET_BUSY_TIMEOUT
* 1000; Retries
++)
1109 if (!(IDEReadStatus(CommandPort
) & IDE_SR_BUSY
))
1113 ScsiPortStallExecution(10);
1116 if (Retries
>= IDE_RESET_BUSY_TIMEOUT
* 1000)
1121 // return TRUE if controller came back to life. and
1122 // the registers are initialized correctly
1123 return(IDEReadError(CommandPort
) == 1);
1127 * AtapiIdentifyDevice
1130 * Get the identification block from the drive
1137 * Address of the command port
1139 * Address of the control port
1141 * The drive index (0,1)
1143 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1145 * Address to write drive ident block
1148 * TRUE: The drive identification block was retrieved successfully
1149 * FALSE: an error ocurred
1153 AtapiIdentifyDevice(IN ULONG CommandPort
,
1154 IN ULONG ControlPort
,
1157 OUT PIDE_DRIVE_IDENTIFY DrvParms
)
1161 /* Get the Drive Identify block from drive or die */
1162 if (AtapiPolledRead(CommandPort
,
1169 (DriveNum
? IDE_DH_DRV1
: 0),
1170 (Atapi
? IDE_CMD_IDENT_ATAPI_DRV
: IDE_CMD_IDENT_ATA_DRV
),
1171 (BYTE
*)DrvParms
) != 0)
1173 DPRINT("IDEPolledRead() failed\n");
1177 /* Report on drive parameters if debug mode */
1178 IDESwapBytePairs(DrvParms
->SerialNumber
, 20);
1179 IDESwapBytePairs(DrvParms
->FirmwareRev
, 8);
1180 IDESwapBytePairs(DrvParms
->ModelNumber
, 40);
1181 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1182 DrvParms
->ConfigBits
,
1183 DrvParms
->LogicalCyls
,
1184 DrvParms
->LogicalHeads
,
1185 DrvParms
->SectorsPerTrack
,
1186 DrvParms
->InterSectorGap
,
1187 DrvParms
->InterSectorGapSize
);
1188 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1189 DrvParms
->BytesInPLO
,
1190 DrvParms
->VendorUniqueCnt
,
1191 DrvParms
->SerialNumber
);
1192 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1193 DrvParms
->ControllerType
,
1194 DrvParms
->BufferSize
* IDE_SECTOR_BUF_SZ
,
1195 DrvParms
->ECCByteCnt
,
1196 DrvParms
->FirmwareRev
);
1197 DPRINT("Model:[%.40s]\n", DrvParms
->ModelNumber
);
1198 DPRINT("RWMultMax?:%02x RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1199 (DrvParms
->RWMultImplemented
) & 0xff,
1200 (DrvParms
->RWMultCurrent
) & 0xff,
1201 (DrvParms
->Capabilities
& IDE_DRID_LBA_SUPPORTED
) ? 1 : 0,
1202 (DrvParms
->Capabilities
& IDE_DRID_DMA_SUPPORTED
) ? 1 : 0,
1203 DrvParms
->MinPIOTransTime
,
1204 DrvParms
->MinDMATransTime
);
1205 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1206 DrvParms
->TMCylinders
,
1208 DrvParms
->TMSectorsPerTrk
,
1209 (ULONG
)(DrvParms
->TMCapacityLo
+ (DrvParms
->TMCapacityHi
<< 16)));
1210 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1211 DrvParms
->TMSectorCountHi
,
1212 DrvParms
->TMSectorCountLo
,
1213 (ULONG
)((DrvParms
->TMSectorCountHi
<< 16) + DrvParms
->TMSectorCountLo
));
1215 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1216 if (DrvParms
->BytesPerSector
== 0)
1218 DrvParms
->BytesPerSector
= 512;
1222 for (i
= 15; i
>= 0; i
--)
1224 if (DrvParms
->BytesPerSector
& (1 << i
))
1226 DrvParms
->BytesPerSector
= 1 << i
;
1231 DPRINT("BytesPerSector %d\n", DrvParms
->BytesPerSector
);
1240 // Read a sector of data from the drive in a polled fashion.
1246 // IN WORD Address Address of command port for drive
1247 // IN BYTE PreComp Value to write to precomp register
1248 // IN BYTE SectorCnt Value to write to sectorCnt register
1249 // IN BYTE SectorNum Value to write to sectorNum register
1250 // IN BYTE CylinderLow Value to write to CylinderLow register
1251 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1252 // IN BYTE DrvHead Value to write to Drive/Head register
1253 // IN BYTE Command Value to write to Command register
1254 // OUT BYTE *Buffer Buffer for output data
1257 // int 0 is success, non 0 is an error code
1261 AtapiPolledRead(IN ULONG CommandPort
,
1262 IN ULONG ControlPort
,
1266 IN BYTE CylinderLow
,
1267 IN BYTE CylinderHigh
,
1272 ULONG SectorCount
= 0;
1274 BOOLEAN Junk
= FALSE
;
1279 /* Wait for BUSY to clear */
1280 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1282 Status
= IDEReadStatus(CommandPort
);
1283 if (!(Status
& IDE_SR_BUSY
))
1287 ScsiPortStallExecution(10);
1289 DPRINT("status=%02x\n", Status
);
1290 DPRINT("waited %ld usecs for busy to clear\n", RetryCount
* 10);
1291 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1293 DPRINT("Drive is BUSY for too long\n");
1294 return(IDE_ER_ABRT
);
1298 /* Write Drive/Head to select drive */
1299 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1300 ScsiPortStallExecution(500);
1302 /* Disable interrupts */
1303 Control
= IDEReadAltStatus(ControlPort
);
1304 IDEWriteDriveControl(ControlPort
, Control
| IDE_DC_nIEN
);
1305 ScsiPortStallExecution(500);
1308 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1309 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1311 Status
= IDEReadStatus(CommandPort
);
1312 if (!(Status
& IDE_SR_BUSY
) && !(Status
& IDE_SR_DRQ
))
1316 ScsiPortStallExecution(10);
1318 if (RetryCount
>= IDE_MAX_BUSY_RETRIES
)
1324 /* Issue command to drive */
1325 if (DrvHead
& IDE_DH_LBA
)
1327 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1328 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1329 ((DrvHead
& 0x0f) << 24) + (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNum
,
1335 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1336 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1345 /* Setup command parameters */
1346 IDEWritePrecomp(CommandPort
, PreComp
);
1347 IDEWriteSectorCount(CommandPort
, SectorCnt
);
1348 IDEWriteSectorNum(CommandPort
, SectorNum
);
1349 IDEWriteCylinderHigh(CommandPort
, CylinderHigh
);
1350 IDEWriteCylinderLow(CommandPort
, CylinderLow
);
1351 IDEWriteDriveHead(CommandPort
, IDE_DH_FIXED
| DrvHead
);
1353 /* Issue the command */
1354 IDEWriteCommand(CommandPort
, Command
);
1355 ScsiPortStallExecution(50);
1357 /* wait for DRQ or error */
1358 for (RetryCount
= 0; RetryCount
< IDE_MAX_POLL_RETRIES
; RetryCount
++)
1360 Status
= IDEReadStatus(CommandPort
);
1361 if (!(Status
& IDE_SR_BUSY
))
1363 if (Status
& IDE_SR_ERR
)
1365 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1366 return(IDE_ER_ABRT
);
1368 if (Status
& IDE_SR_DRQ
)
1374 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1375 return(IDE_ER_ABRT
);
1378 ScsiPortStallExecution(10);
1382 if (RetryCount
>= IDE_MAX_POLL_RETRIES
)
1384 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1385 return(IDE_ER_ABRT
);
1390 /* Read data into buffer */
1393 IDEReadBlock(CommandPort
, Buffer
, IDE_SECTOR_BUF_SZ
);
1394 Buffer
+= IDE_SECTOR_BUF_SZ
;
1398 UCHAR JunkBuffer
[IDE_SECTOR_BUF_SZ
];
1399 IDEReadBlock(CommandPort
, JunkBuffer
, IDE_SECTOR_BUF_SZ
);
1403 /* Check for error or more sectors to read */
1404 for (RetryCount
= 0; RetryCount
< IDE_MAX_BUSY_RETRIES
; RetryCount
++)
1406 Status
= IDEReadStatus(CommandPort
);
1407 if (!(Status
& IDE_SR_BUSY
))
1409 if (Status
& IDE_SR_ERR
)
1411 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1412 return(IDE_ER_ABRT
);
1414 if (Status
& IDE_SR_DRQ
)
1416 if (SectorCount
>= SectorCnt
)
1418 DPRINT("Buffer size exceeded!\n");
1425 if (SectorCount
> SectorCnt
)
1427 DPRINT("Read %lu sectors of junk!\n",
1428 SectorCount
- SectorCnt
);
1430 IDEWriteDriveControl(ControlPort
, Control
& ~IDE_DC_nIEN
);
1439 // ------------------------------------------- Nondiscardable statics
1442 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1443 IN PSCSI_REQUEST_BLOCK Srb
)
1445 UCHAR ByteCountHigh
;
1451 DPRINT("AtapiSendAtapiCommand() called!\n");
1453 if (Srb
->PathId
!= 0)
1455 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1456 return(SRB_STATUS_INVALID_PATH_ID
);
1459 if (Srb
->TargetId
> 1)
1461 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1462 return(SRB_STATUS_INVALID_TARGET_ID
);
1467 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1468 return(SRB_STATUS_INVALID_LUN
);
1471 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1473 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1474 return(SRB_STATUS_NO_DEVICE
);
1477 DPRINT("AtapiSendAtapiCommand(): TargetId: %lu\n",
1480 if (Srb
->Cdb
[0] == SCSIOP_INQUIRY
)
1481 return(AtapiInquiry(DeviceExtension
,
1484 /* Set pointer to data buffer. */
1485 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1486 DeviceExtension
->CurrentSrb
= Srb
;
1488 /* Wait for BUSY to clear */
1489 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1491 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1492 if (!(Status
& IDE_SR_BUSY
))
1496 ScsiPortStallExecution(10);
1498 DPRINT("status=%02x\n", Status
);
1499 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1500 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1502 DPRINT("Drive is BUSY for too long\n");
1503 return(SRB_STATUS_BUSY
);
1506 /* Select the desired drive */
1507 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1508 IDE_DH_FIXED
| (Srb
->TargetId
? IDE_DH_DRV1
: 0));
1510 /* Wait a little while */
1511 ScsiPortStallExecution(50);
1514 /* Wait for BUSY to clear and DRDY to assert */
1515 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1517 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1518 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1522 ScsiPortStallExecution(10);
1524 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1525 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1527 DPRINT("Drive is BUSY for too long after drive select\n");
1528 return(SRB_STATUS_BUSY
);
1532 if (Srb
->DataTransferLength
< 0x10000)
1534 ByteCountLow
= (UCHAR
)(Srb
->DataTransferLength
& 0xFF);
1535 ByteCountHigh
= (UCHAR
)(Srb
->DataTransferLength
>> 8);
1539 ByteCountLow
= 0xFF;
1540 ByteCountHigh
= 0xFF;
1543 /* Set feature register */
1544 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
1546 /* Set command packet length */
1547 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, ByteCountHigh
);
1548 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, ByteCountLow
);
1550 /* Issue command to drive */
1551 IDEWriteCommand(DeviceExtension
->CommandPortBase
, 0xA0); /* Packet command */
1553 /* Wait for DRQ to assert */
1554 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1556 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1557 if ((Status
& IDE_SR_DRQ
))
1561 ScsiPortStallExecution(10);
1564 CdbSize
= (DeviceExtension
->DeviceParams
[Srb
->TargetId
].ConfigBits
& 0x3 == 1) ? 16 : 12;
1565 DPRINT("CdbSize: %lu\n", CdbSize
);
1567 /* Write command packet */
1568 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
1572 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1574 DPRINT("AtapiSendAtapiCommand() done\n");
1576 return(SRB_STATUS_PENDING
);
1581 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1582 IN PSCSI_REQUEST_BLOCK Srb
)
1584 ULONG SrbStatus
= SRB_STATUS_SUCCESS
;
1586 DPRINT("AtapiSendIdeCommand() called!\n");
1588 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1593 switch (Srb
->Cdb
[0])
1595 case SCSIOP_INQUIRY
:
1596 SrbStatus
= AtapiInquiry(DeviceExtension
,
1600 case SCSIOP_READ_CAPACITY
:
1601 SrbStatus
= AtapiReadCapacity(DeviceExtension
,
1607 SrbStatus
= AtapiReadWrite(DeviceExtension
,
1611 case SCSIOP_MODE_SENSE
:
1612 case SCSIOP_TEST_UNIT_READY
:
1614 case SCSIOP_START_STOP_UNIT
:
1615 case SCSIOP_REQUEST_SENSE
:
1619 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1621 SrbStatus
= SRB_STATUS_INVALID_REQUEST
;
1625 DPRINT("AtapiSendIdeCommand() done!\n");
1632 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1633 PSCSI_REQUEST_BLOCK Srb
)
1635 PIDE_DRIVE_IDENTIFY DeviceParams
;
1636 PINQUIRYDATA InquiryData
;
1639 DPRINT("SCSIOP_INQUIRY: DeviceExtension %p TargetId: %lu\n",
1640 DeviceExtension
, Srb
->TargetId
);
1642 if (Srb
->PathId
!= 0)
1644 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1645 return(SRB_STATUS_INVALID_PATH_ID
);
1648 if (Srb
->TargetId
> 1)
1650 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1651 return(SRB_STATUS_INVALID_TARGET_ID
);
1656 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1657 return(SRB_STATUS_INVALID_LUN
);
1660 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1662 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1663 return(SRB_STATUS_NO_DEVICE
);
1666 InquiryData
= Srb
->DataBuffer
;
1667 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1670 for (i
= 0; i
< Srb
->DataTransferLength
; i
++)
1672 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
1675 /* set device class */
1676 if (DeviceExtension
->DeviceAtapi
[Srb
->TargetId
] == FALSE
)
1679 InquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
1683 /* get it from the ATAPI configuration word */
1684 InquiryData
->DeviceType
= (DeviceParams
->ConfigBits
>> 8) & 0x1F;
1685 DPRINT("Device class: %u\n", InquiryData
->DeviceType
);
1688 DPRINT("ConfigBits: 0x%x\n", DeviceParams
->ConfigBits
);
1689 if (DeviceParams
->ConfigBits
& 0x80)
1691 DPRINT("Removable media!\n");
1692 InquiryData
->RemovableMedia
= 1;
1695 for (i
= 0; i
< 20; i
+= 2)
1697 InquiryData
->VendorId
[i
] =
1698 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
];
1699 InquiryData
->VendorId
[i
+1] =
1700 ((PUCHAR
)DeviceParams
->ModelNumber
)[i
+1];
1703 for (i
= 0; i
< 4; i
++)
1705 InquiryData
->ProductId
[12+i
] = ' ';
1708 for (i
= 0; i
< 4; i
+= 2)
1710 InquiryData
->ProductRevisionLevel
[i
] =
1711 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
];
1712 InquiryData
->ProductRevisionLevel
[i
+1] =
1713 ((PUCHAR
)DeviceParams
->FirmwareRev
)[i
+1];
1716 DPRINT("VendorId: '%.20s'\n", InquiryData
->VendorId
);
1718 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1719 return(SRB_STATUS_SUCCESS
);
1724 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1725 PSCSI_REQUEST_BLOCK Srb
)
1727 PREAD_CAPACITY_DATA CapacityData
;
1728 PIDE_DRIVE_IDENTIFY DeviceParams
;
1731 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb
->TargetId
);
1733 if (Srb
->PathId
!= 0)
1735 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1736 return(SRB_STATUS_INVALID_PATH_ID
);
1739 if (Srb
->TargetId
> 1)
1741 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1742 return(SRB_STATUS_INVALID_TARGET_ID
);
1747 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1748 return(SRB_STATUS_INVALID_LUN
);
1751 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1753 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1754 return(SRB_STATUS_NO_DEVICE
);
1757 CapacityData
= (PREAD_CAPACITY_DATA
)Srb
->DataBuffer
;
1758 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1760 /* Set sector (block) size to 512 bytes (big-endian). */
1761 CapacityData
->BytesPerBlock
= 0x20000;
1763 /* Calculate last sector (big-endian). */
1764 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1766 LastSector
= (ULONG
)((DeviceParams
->TMSectorCountHi
<< 16) +
1767 DeviceParams
->TMSectorCountLo
) - 1;
1771 LastSector
= (ULONG
)(DeviceParams
->LogicalCyls
*
1772 DeviceParams
->LogicalHeads
*
1773 DeviceParams
->SectorsPerTrack
)-1;
1776 CapacityData
->LogicalBlockAddress
= (((PUCHAR
)&LastSector
)[0] << 24) |
1777 (((PUCHAR
)&LastSector
)[1] << 16) |
1778 (((PUCHAR
)&LastSector
)[2] << 8) |
1779 ((PUCHAR
)&LastSector
)[3];
1781 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1784 CapacityData
->LogicalBlockAddress
);
1786 Srb
->SrbStatus
= SRB_STATUS_SUCCESS
;
1787 return(SRB_STATUS_SUCCESS
);
1792 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension
,
1793 PSCSI_REQUEST_BLOCK Srb
)
1795 PIDE_DRIVE_IDENTIFY DeviceParams
;
1796 ULONG StartingSector
;
1806 DPRINT("AtapiReadWrite() called!\n");
1808 if (Srb
->PathId
!= 0)
1810 Srb
->SrbStatus
= SRB_STATUS_INVALID_PATH_ID
;
1811 return(SRB_STATUS_INVALID_PATH_ID
);
1814 if (Srb
->TargetId
> 1)
1816 Srb
->SrbStatus
= SRB_STATUS_INVALID_TARGET_ID
;
1817 return(SRB_STATUS_INVALID_TARGET_ID
);
1822 Srb
->SrbStatus
= SRB_STATUS_INVALID_LUN
;
1823 return(SRB_STATUS_INVALID_LUN
);
1826 if (DeviceExtension
->DevicePresent
[Srb
->TargetId
] == FALSE
)
1828 Srb
->SrbStatus
= SRB_STATUS_NO_DEVICE
;
1829 return(SRB_STATUS_NO_DEVICE
);
1832 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1835 DeviceParams
= &DeviceExtension
->DeviceParams
[Srb
->TargetId
];
1837 /* Get starting sector number from CDB. */
1838 StartingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
1839 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
1840 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
1841 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
1843 SectorCount
= (Srb
->DataTransferLength
+ DeviceParams
->BytesPerSector
- 1) /
1844 DeviceParams
->BytesPerSector
;
1846 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1848 Srb
->DataTransferLength
,
1851 if (DeviceParams
->Capabilities
& IDE_DRID_LBA_SUPPORTED
)
1853 SectorNumber
= StartingSector
& 0xff;
1854 CylinderLow
= (StartingSector
>> 8) & 0xff;
1855 CylinderHigh
= (StartingSector
>> 16) & 0xff;
1856 DrvHead
= ((StartingSector
>> 24) & 0x0f) |
1857 (Srb
->TargetId
? IDE_DH_DRV1
: 0) |
1862 SectorNumber
= (StartingSector
% DeviceParams
->SectorsPerTrack
) + 1;
1863 StartingSector
/= DeviceParams
->SectorsPerTrack
;
1864 DrvHead
= (StartingSector
% DeviceParams
->LogicalHeads
) |
1865 (Srb
->TargetId
? IDE_DH_DRV1
: 0);
1866 StartingSector
/= DeviceParams
->LogicalHeads
;
1867 CylinderLow
= StartingSector
& 0xff;
1868 CylinderHigh
= StartingSector
>> 8;
1872 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
)
1874 #ifdef ENABLE_MULTIMODE
1875 Command
= DeviceParams
->RWMultCurrent
& 0xff ? IDE_CMD_READ_MULTIPLE
: IDE_CMD_READ
;
1877 Command
= IDE_CMD_READ
;
1882 #ifdef ENABLE_MULTIMODE
1883 Command
= DeviceParams
->RWMultCurrent
& 0xff ? IDE_CMD_WRITE_MULTIPLE
: IDE_CMD_WRITE
;
1885 Command
= IDE_CMD_WRITE
;
1889 if (DrvHead
& IDE_DH_LBA
)
1891 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1892 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1893 DeviceExtension
->CommandPortBase
,
1894 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1895 ((DrvHead
& 0x0f) << 24) +
1896 (CylinderHigh
<< 16) + (CylinderLow
<< 8) + SectorNumber
,
1902 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1903 (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? "READ" : "WRITE",
1904 DeviceExtension
->CommandPortBase
,
1905 DrvHead
& IDE_DH_DRV1
? 1 : 0,
1914 /* Set pointer to data buffer. */
1915 DeviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
1917 DeviceExtension
->CurrentSrb
= Srb
;
1918 DeviceExtension
->ExpectingInterrupt
= TRUE
;
1922 /* wait for BUSY to clear */
1923 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1925 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1926 if (!(Status
& IDE_SR_BUSY
))
1930 ScsiPortStallExecution(10);
1932 DPRINT("status=%02x\n", Status
);
1933 DPRINT("waited %ld usecs for busy to clear\n", Retries
* 10);
1934 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1936 DPRINT ("Drive is BUSY for too long\n");
1937 return(SRB_STATUS_BUSY
);
1939 if (++ControllerExtension
->Retries
> IDE_MAX_CMD_RETRIES
)
1941 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1942 Irp
= ControllerExtension
->CurrentIrp
;
1943 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1944 Irp
->IoStatus
.Information
= 0;
1950 DPRINT ("Beginning drive reset sequence\n");
1951 IDEBeginControllerReset(ControllerExtension
);
1958 /* Select the desired drive */
1959 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
,
1960 IDE_DH_FIXED
| DrvHead
);
1962 ScsiPortStallExecution(10);
1964 /* wait for BUSY to clear and DRDY to assert */
1965 for (Retries
= 0; Retries
< IDE_MAX_BUSY_RETRIES
; Retries
++)
1967 Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
1968 if (!(Status
& IDE_SR_BUSY
) && (Status
& IDE_SR_DRDY
))
1972 ScsiPortStallExecution(10);
1974 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries
* 10);
1975 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
1977 DPRINT("Drive is BUSY for too long after drive select\n");
1978 return(SRB_STATUS_BUSY
);
1980 if (ControllerExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
1982 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1983 Irp
= ControllerExtension
->CurrentIrp
;
1984 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
1985 Irp
->IoStatus
.Information
= 0;
1991 DPRINT("Beginning drive reset sequence\n");
1992 IDEBeginControllerReset(ControllerExtension
);
2000 /* Indicate expecting an interrupt. */
2001 DeviceExtension
->ExpectingInterrupt
= TRUE
;
2003 /* Setup command parameters */
2004 IDEWritePrecomp(DeviceExtension
->CommandPortBase
, 0);
2005 IDEWriteSectorCount(DeviceExtension
->CommandPortBase
, SectorCount
);
2006 IDEWriteSectorNum(DeviceExtension
->CommandPortBase
, SectorNumber
);
2007 IDEWriteCylinderHigh(DeviceExtension
->CommandPortBase
, CylinderHigh
);
2008 IDEWriteCylinderLow(DeviceExtension
->CommandPortBase
, CylinderLow
);
2009 IDEWriteDriveHead(DeviceExtension
->CommandPortBase
, IDE_DH_FIXED
| DrvHead
);
2011 /* Issue command to drive */
2012 IDEWriteCommand(DeviceExtension
->CommandPortBase
, Command
);
2014 /* Write data block */
2015 #ifdef ENABLE_MULTIMODE
2016 if (Command
== IDE_CMD_WRITE
|| Command
== IDE_CMD_WRITE_MULTIPLE
)
2018 if (Command
== IDE_CMD_WRITE
)
2021 PUCHAR TargetAddress
;
2024 /* Wait for controller ready */
2025 for (Retries
= 0; Retries
< IDE_MAX_WRITE_RETRIES
; Retries
++)
2027 BYTE Status
= IDEReadStatus(DeviceExtension
->CommandPortBase
);
2028 if (!(Status
& IDE_SR_BUSY
) || (Status
& IDE_SR_ERR
))
2032 KeStallExecutionProcessor(10);
2034 if (Retries
>= IDE_MAX_BUSY_RETRIES
)
2036 DPRINT("Drive is BUSY for too long after sending write command\n");
2037 return(SRB_STATUS_BUSY
);
2039 if (DeviceExtension
->Retries
++ > IDE_MAX_CMD_RETRIES
)
2041 Irp
= ControllerExtension
->CurrentIrp
;
2042 Irp
->IoStatus
.Status
= STATUS_DISK_OPERATION_FAILED
;
2043 Irp
->IoStatus
.Information
= 0;
2049 IDEBeginControllerReset(ControllerExtension
);
2056 /* Update SRB data */
2057 SectorSize
= DeviceParams
->BytesPerSector
;
2058 #ifdef ENABLE_MULTIMODE
2059 if (DeviceParams
->RWMultCurrent
& 0xff)
2061 SectorSize
*= (DeviceParams
->RWMultCurrent
& 0xff);
2063 if (Srb
->DataTransferLength
< SectorSize
)
2065 SectorSize
= Srb
->DataTransferLength
;
2069 TargetAddress
= Srb
->DataBuffer
;
2070 Srb
->DataBuffer
+= SectorSize
;
2071 Srb
->DataTransferLength
-= SectorSize
;
2073 /* Write data block */
2075 IDEWriteBlock32(DeviceExtension
->CommandPortBase
,
2079 IDEWriteBlock(DeviceExtension
->CommandPortBase
,
2086 DPRINT("AtapiReadWrite() done!\n");
2088 /* Wait for interrupt. */
2089 return(SRB_STATUS_PENDING
);
2094 AtapiErrorToScsi(PVOID DeviceExtension
,
2095 PSCSI_REQUEST_BLOCK Srb
)
2097 PATAPI_MINIPORT_EXTENSION DevExt
;
2098 ULONG CommandPortBase
;
2099 ULONG ControlPortBase
;
2104 DPRINT("AtapiErrorToScsi() called\n");
2106 DevExt
= (PATAPI_MINIPORT_EXTENSION
)DeviceExtension
;
2108 CommandPortBase
= DevExt
->CommandPortBase
;
2109 ControlPortBase
= DevExt
->ControlPortBase
;
2111 ErrorReg
= IDEReadError(CommandPortBase
);
2113 if (DevExt
->DeviceAtapi
[Srb
->TargetId
])
2115 switch (ErrorReg
>> 4)
2117 case SCSI_SENSE_NO_SENSE
:
2118 DPRINT("ATAPI error: SCSI_SENSE_NO_SENSE\n");
2119 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2120 SrbStatus
= SRB_STATUS_ERROR
;
2123 case SCSI_SENSE_RECOVERED_ERROR
:
2124 DPRINT("ATAPI error: SCSI_SENSE_RECOVERED_SENSE\n");
2126 SrbStatus
= SRB_STATUS_SUCCESS
;
2129 case SCSI_SENSE_NOT_READY
:
2130 DPRINT("ATAPI error: SCSI_SENSE_NOT_READY\n");
2131 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2132 SrbStatus
= SRB_STATUS_ERROR
;
2135 case SCSI_SENSE_MEDIUM_ERROR
:
2136 DPRINT("ATAPI error: SCSI_SENSE_MEDIUM_ERROR\n");
2137 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2138 SrbStatus
= SRB_STATUS_ERROR
;
2141 case SCSI_SENSE_HARDWARE_ERROR
:
2142 DPRINT("ATAPI error: SCSI_SENSE_HARDWARE_ERROR\n");
2143 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2144 SrbStatus
= SRB_STATUS_ERROR
;
2147 case SCSI_SENSE_ILLEGAL_REQUEST
:
2148 DPRINT("ATAPI error: SCSI_SENSE_ILLEGAL_REQUEST\n");
2149 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2150 SrbStatus
= SRB_STATUS_ERROR
;
2153 case SCSI_SENSE_UNIT_ATTENTION
:
2154 DPRINT("ATAPI error: SCSI_SENSE_UNIT_ATTENTION\n");
2155 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2156 SrbStatus
= SRB_STATUS_ERROR
;
2159 case SCSI_SENSE_DATA_PROTECT
:
2160 DPRINT("ATAPI error: SCSI_SENSE_DATA_PROTECT\n");
2161 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2162 SrbStatus
= SRB_STATUS_ERROR
;
2165 case SCSI_SENSE_BLANK_CHECK
:
2166 DPRINT("ATAPI error: SCSI_SENSE_BLANK_CHECK\n");
2167 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2168 SrbStatus
= SRB_STATUS_ERROR
;
2171 case SCSI_SENSE_ABORTED_COMMAND
:
2172 DPRINT("ATAPI error: SCSI_SENSE_ABORTED_COMMAND\n");
2173 ScsiStatus
= SCSISTAT_CHECK_CONDITION
;
2174 SrbStatus
= SRB_STATUS_ERROR
;
2178 DPRINT("ATAPI error: Invalid sense key\n");
2180 SrbStatus
= SRB_STATUS_ERROR
;
2186 DPRINT1("IDE error: %02x\n", ErrorReg
);
2189 SrbStatus
= SRB_STATUS_ERROR
;
2192 UCHAR SectorCount
, SectorNum
, CylinderLow
, CylinderHigh
;
2195 CylinderLow
= IDEReadCylinderLow(CommandPortBase
);
2196 CylinderHigh
= IDEReadCylinderHigh(CommandPortBase
);
2197 DriveHead
= IDEReadDriveHead(CommandPortBase
);
2198 SectorCount
= IDEReadSectorCount(CommandPortBase
);
2199 SectorNum
= IDEReadSectorNum(CommandPortBase
);
2201 DPRINT1("IDE Error: ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
2212 Srb
->ScsiStatus
= ScsiStatus
;
2214 DPRINT("AtapiErrorToScsi() done\n");