2 * PROJECT: ReactOS Storage Stack
3 * LICENSE: DDK - see license.txt in the root dir
4 * FILE: drivers/storage/atapi/atapi.c
5 * PURPOSE: ATAPI IDE miniport driver
6 * PROGRAMMERS: Based on a source code sample from Microsoft NT4 DDK
10 #include "atapi.h" // includes scsi.h
22 typedef struct _HW_DEVICE_EXTENSION
{
25 // Current request on controller.
28 PSCSI_REQUEST_BLOCK CurrentSrb
;
31 // Base register locations
34 PIDE_REGISTERS_1 BaseIoAddress1
[2];
35 PIDE_REGISTERS_2 BaseIoAddress2
[2];
44 // Interrupt Mode (Level or Edge)
50 // Data buffer pointer.
62 // Number of channels being supported by one instantiation
63 // of the device extension. Normally (and correctly) one, but
64 // with so many broken PCI IDE controllers being sold, we have
71 // Count of errors. Used to turn off features.
77 // Indicates number of platters on changer-ish devices.
80 ULONG DiscsPresent
[4];
83 // Flags word for each possible device.
86 USHORT DeviceFlags
[4];
89 // Indicates the number of blocks transferred per int. according to the
93 UCHAR MaximumBlockXfer
[4];
96 // Indicates expecting an interrupt
99 BOOLEAN ExpectingInterrupt
;
102 // Indicate last tape command was DSC Restrictive.
108 // Driver is being used by the crash dump utility or ntldr.
111 BOOLEAN DriverMustPoll
;
114 // Indicates use of 32-bit PIO
120 // Indicates whether '0x1f0' is the base address. Used
121 // in SMART Ioctl calls.
124 BOOLEAN PrimaryAddress
;
127 // Placeholder for the sub-command value of the last
134 // Placeholder for status register after a GET_MEDIA_STATUS command
137 UCHAR ReturningMediaStatus
;
142 // Identify data for device
145 IDENTIFY_DATA FullIdentifyData
;
146 IDENTIFY_DATA2 IdentifyData
[4];
149 // Mechanism Status Srb Data
151 PSCSI_REQUEST_BLOCK OriginalSrb
;
152 SCSI_REQUEST_BLOCK InternalSrb
;
153 MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData
;
154 SENSE_DATA MechStatusSense
;
155 ULONG MechStatusRetryCount
;
157 } HW_DEVICE_EXTENSION
, *PHW_DEVICE_EXTENSION
;
160 // Logical unit extension
163 typedef struct _HW_LU_EXTENSION
{
165 } HW_LU_EXTENSION
, *PHW_LU_EXTENSION
;
169 BuildMechanismStatusSrb (
170 IN PVOID HwDeviceExtension
,
177 BuildRequestSenseSrb (
178 IN PVOID HwDeviceExtension
,
185 AtapiHwInitializeChanger (
186 IN PVOID HwDeviceExtension
,
188 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus
194 IN PVOID HwDeviceExtension
,
195 IN PSCSI_REQUEST_BLOCK Srb
223 IN PVOID HwDeviceExtension
229 IN PVOID HwDeviceExtension
235 IN PVOID HwDeviceExtension
,
236 IN PSCSI_REQUEST_BLOCK Srb
242 IN BOOLEAN EnableMSN
,
243 IN PVOID HwDeviceExtension
,
252 IN PVOID HwDeviceExtension
,
253 IN ULONG DeviceNumber
,
262 Issue IDENTIFY command to a device.
266 HwDeviceExtension - HBA miniport driver's adapter data storage
267 DeviceNumber - Indicates which device.
268 Command - Either the standard (EC) or the ATAPI packet (A1) IDENTIFY.
272 TRUE if all goes well.
277 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
278 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Channel
] ;
279 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Channel
];
280 ULONG waitCount
= 20000;
287 // Select device 0 or 1.
290 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
291 (UCHAR
)((DeviceNumber
<< 4) | 0xA0));
294 // Check that the status register makes sense.
297 GetBaseStatus(baseIoAddress1
, statusByte
);
299 if (Command
== IDE_COMMAND_IDENTIFY
) {
302 // Mask status byte ERROR bits.
305 statusByte
&= ~(IDE_STATUS_ERROR
| IDE_STATUS_INDEX
);
308 "IssueIdentify: Checking for IDE. Status (%x)\n",
312 // Check if register value is reasonable.
315 if (statusByte
!= IDE_STATUS_IDLE
) {
318 // Reset the controller.
321 AtapiSoftReset(baseIoAddress1
,DeviceNumber
);
323 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
324 (UCHAR
)((DeviceNumber
<< 4) | 0xA0));
326 WaitOnBusy(baseIoAddress2
,statusByte
);
328 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
329 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
331 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
341 "IssueIdentify: Resetting controller.\n"));
343 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_RESET_CONTROLLER
);
344 ScsiPortStallExecution(500 * 1000);
345 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_REENABLE_CONTROLLER
);
348 // We really should wait up to 31 seconds
349 // The ATA spec. allows device 0 to come back from BUSY in 31 seconds!
350 // (30 seconds for device 1)
354 // Wait for Busy to drop.
357 ScsiPortStallExecution(100);
358 GetStatus(baseIoAddress2
, statusByte
);
360 } while ((statusByte
& IDE_STATUS_BUSY
) && waitCount
--);
362 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
363 (UCHAR
)((DeviceNumber
<< 4) | 0xA0));
366 // Another check for signature, to deal with one model Atapi that doesn't assert signature after
370 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
371 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
373 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
382 statusByte
&= ~IDE_STATUS_INDEX
;
384 if (statusByte
!= IDE_STATUS_IDLE
) {
398 "IssueIdentify: Checking for ATAPI. Status (%x)\n",
404 // Load CylinderHigh and CylinderLow with number bytes to transfer.
407 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
, (0x200 >> 8));
408 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
, (0x200 & 0xFF));
410 for (j
= 0; j
< 2; j
++) {
413 // Send IDENTIFY command.
416 WaitOnBusy(baseIoAddress2
,statusByte
);
418 ScsiPortWritePortUchar(&baseIoAddress1
->Command
, Command
);
424 for (i
= 0; i
< 4; i
++) {
426 WaitForDrq(baseIoAddress2
, statusByte
);
428 if (statusByte
& IDE_STATUS_DRQ
) {
431 // Read status to acknowledge any interrupts generated.
434 GetBaseStatus(baseIoAddress1
, statusByte
);
437 // One last check for Atapi.
441 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
442 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
444 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
456 if (Command
== IDE_COMMAND_IDENTIFY
) {
459 // Check the signature. If DRQ didn't come up it's likely Atapi.
462 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
463 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
465 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
475 WaitOnBusy(baseIoAddress2
,statusByte
);
478 if (i
== 4 && j
== 0) {
481 // Device didn't respond correctly. It will be given one more chances.
485 "IssueIdentify: DRQ never asserted (%x). Error reg (%x)\n",
487 ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1)));
489 AtapiSoftReset(baseIoAddress1
,DeviceNumber
);
491 GetStatus(baseIoAddress2
,statusByte
);
494 "IssueIdentify: Status after soft reset (%x)\n",
505 // Check for error on really stupid master devices that assert random
506 // patterns of bits in the status register at the slave address.
509 if ((Command
== IDE_COMMAND_IDENTIFY
) && (statusByte
& IDE_STATUS_ERROR
)) {
514 "IssueIdentify: Status before read words %x\n",
518 // Suck out 256 words. After waiting for one model that asserts busy
519 // after receiving the Packet Identify command.
522 WaitOnBusy(baseIoAddress2
,statusByte
);
524 if (!(statusByte
& IDE_STATUS_DRQ
)) {
528 ReadBuffer(baseIoAddress1
,
529 (PUSHORT
)&deviceExtension
->FullIdentifyData
,
533 // Check out a few capabilities / limitations of the device.
536 if (deviceExtension
->FullIdentifyData
.SpecialFunctionsEnabled
& 1) {
539 // Determine if this drive supports the MSN functions.
542 DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d\n",
543 Channel
* 2 + DeviceNumber
,
544 deviceExtension
->FullIdentifyData
.SpecialFunctionsEnabled
));
547 deviceExtension
->DeviceFlags
[(Channel
* 2) + DeviceNumber
] |= DFLAGS_REMOVABLE_DRIVE
;
550 if (deviceExtension
->FullIdentifyData
.MaximumBlockTransfer
) {
553 // Determine max. block transfer for this device.
556 deviceExtension
->MaximumBlockXfer
[(Channel
* 2) + DeviceNumber
] =
557 (UCHAR
)(deviceExtension
->FullIdentifyData
.MaximumBlockTransfer
& 0xFF);
560 ScsiPortMoveMemory(&deviceExtension
->IdentifyData
[(Channel
* 2) + DeviceNumber
],&deviceExtension
->FullIdentifyData
,sizeof(IDENTIFY_DATA2
));
562 if (deviceExtension
->IdentifyData
[(Channel
* 2) + DeviceNumber
].GeneralConfiguration
& 0x20 &&
563 Command
!= IDE_COMMAND_IDENTIFY
) {
566 // This device interrupts with the assertion of DRQ after receiving
567 // Atapi Packet Command
570 deviceExtension
->DeviceFlags
[(Channel
* 2) + DeviceNumber
] |= DFLAGS_INT_DRQ
;
573 "IssueIdentify: Device interrupts on assertion of DRQ.\n"));
578 "IssueIdentify: Device does not interrupt on assertion of DRQ.\n"));
581 if (((deviceExtension
->IdentifyData
[(Channel
* 2) + DeviceNumber
].GeneralConfiguration
& 0xF00) == 0x100) &&
582 Command
!= IDE_COMMAND_IDENTIFY
) {
588 deviceExtension
->DeviceFlags
[(Channel
* 2) + DeviceNumber
] |= DFLAGS_TAPE_DEVICE
;
591 "IssueIdentify: Device is a tape drive.\n"));
596 "IssueIdentify: Device is not a tape drive.\n"));
600 // Work around for some IDE and one model Atapi that will present more than
601 // 256 bytes for the Identify data.
604 WaitOnBusy(baseIoAddress2
,statusByte
);
606 for (i
= 0; i
< 0x10000; i
++) {
608 GetStatus(baseIoAddress2
,statusByte
);
610 if (statusByte
& IDE_STATUS_DRQ
) {
613 // Suck out any remaining bytes and throw away.
616 ScsiPortReadPortUshort(&baseIoAddress1
->Data
);
626 "IssueIdentify: Status after read words (%x)\n",
631 } // end IssueIdentify()
637 IN PVOID HwDeviceExtension
,
638 IN ULONG DeviceNumber
,
646 Set drive parameters using the IDENTIFY data.
650 HwDeviceExtension - HBA miniport driver's adapter data storage
651 DeviceNumber - Indicates which device.
655 TRUE if all goes well.
661 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
662 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Channel
];
663 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Channel
];
664 PIDENTIFY_DATA2 identifyData
= &deviceExtension
->IdentifyData
[(Channel
* 2) + DeviceNumber
];
669 "SetDriveParameters: Number of heads %x\n",
670 identifyData
->NumberOfHeads
));
673 "SetDriveParameters: Sectors per track %x\n",
674 identifyData
->SectorsPerTrack
));
677 // Set up registers for SET PARAMETER command.
680 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
681 (UCHAR
)(((DeviceNumber
<< 4) | 0xA0) | (identifyData
->NumberOfHeads
- 1)));
683 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,
684 (UCHAR
)identifyData
->SectorsPerTrack
);
687 // Send SET PARAMETER command.
690 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
691 IDE_COMMAND_SET_DRIVE_PARAMETERS
);
694 // Wait for up to 30 milliseconds for ERROR or command complete.
697 for (i
=0; i
<30 * 1000; i
++) {
701 GetStatus(baseIoAddress2
, statusByte
);
703 if (statusByte
& IDE_STATUS_ERROR
) {
704 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
706 "SetDriveParameters: Error bit set. Status %x, error %x\n",
711 } else if ((statusByte
& ~IDE_STATUS_INDEX
) == IDE_STATUS_IDLE
) {
714 ScsiPortStallExecution(100);
719 // Check for timeout.
722 if (i
== 30 * 1000) {
728 } // end SetDriveParameters()
733 AtapiResetController(
734 IN PVOID HwDeviceExtension
,
742 Reset IDE controller and/or Atapi device.
746 HwDeviceExtension - HBA miniport driver's adapter data storage
756 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
757 ULONG numberChannels
= deviceExtension
->NumberChannels
;
758 PIDE_REGISTERS_1 baseIoAddress1
;
759 PIDE_REGISTERS_2 baseIoAddress2
;
760 BOOLEAN result
= FALSE
;
764 DebugPrint((2,"AtapiResetController: Reset IDE\n"));
767 // Check and see if we are processing an internal srb
769 if (deviceExtension
->OriginalSrb
) {
770 deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
771 deviceExtension
->OriginalSrb
= NULL
;
775 // Check if request is in progress.
778 if (deviceExtension
->CurrentSrb
) {
781 // Complete outstanding request with SRB_STATUS_BUS_RESET.
784 ScsiPortCompleteRequest(deviceExtension
,
785 deviceExtension
->CurrentSrb
->PathId
,
786 deviceExtension
->CurrentSrb
->TargetId
,
787 deviceExtension
->CurrentSrb
->Lun
,
788 (ULONG
)SRB_STATUS_BUS_RESET
);
791 // Clear request tracking fields.
794 deviceExtension
->CurrentSrb
= NULL
;
795 deviceExtension
->WordsLeft
= 0;
796 deviceExtension
->DataBuffer
= NULL
;
799 // Indicate ready for next request.
802 ScsiPortNotification(NextRequest
,
808 // Clear expecting interrupt flag.
811 deviceExtension
->ExpectingInterrupt
= FALSE
;
812 deviceExtension
->RDP
= FALSE
;
814 for (j
= 0; j
< numberChannels
; j
++) {
816 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[j
];
817 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[j
];
820 // Do special processing for ATAPI and IDE disk devices.
823 for (i
= 0; i
< 2; i
++) {
826 // Check if device present.
829 if (deviceExtension
->DeviceFlags
[i
+ (j
* 2)] & DFLAGS_DEVICE_PRESENT
) {
832 // Check for ATAPI disk.
835 if (deviceExtension
->DeviceFlags
[i
+ (j
* 2)] & DFLAGS_ATAPI_DEVICE
) {
838 // Issue soft reset and issue identify.
841 GetStatus(baseIoAddress2
,statusByte
);
843 "AtapiResetController: Status before Atapi reset (%x).\n",
846 AtapiSoftReset(baseIoAddress1
,i
);
848 GetStatus(baseIoAddress2
,statusByte
);
850 if (statusByte
== 0x0) {
852 IssueIdentify(HwDeviceExtension
,
855 IDE_COMMAND_ATAPI_IDENTIFY
);
859 "AtapiResetController: Status after soft reset %x\n",
866 // Write IDE reset controller bits.
869 IdeHardReset(baseIoAddress2
,result
);
876 // Set disk geometry parameters.
879 if (!SetDriveParameters(HwDeviceExtension
,
884 "AtapiResetController: SetDriveParameters failed\n"));
892 // Call the HwInitialize routine to setup multi-block.
895 AtapiHwInitialize(HwDeviceExtension
);
899 } // end AtapiResetController()
906 IN PVOID HwDeviceExtension
,
907 IN PSCSI_REQUEST_BLOCK Srb
914 This routine maps ATAPI and IDE errors to specific SRB statuses.
918 HwDeviceExtension - HBA miniport driver's adapter data storage
919 Srb - IO request packet
928 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
929 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
930 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
933 UCHAR srbStatus
= SRB_STATUS_ERROR
;
937 // Read the error register.
940 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
942 "MapError: Error register is %x\n",
945 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
947 switch (errorByte
>> 4) {
948 case SCSI_SENSE_NO_SENSE
:
951 "ATAPI: No sense information\n"));
952 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
953 srbStatus
= SRB_STATUS_ERROR
;
956 case SCSI_SENSE_RECOVERED_ERROR
:
959 "ATAPI: Recovered error\n"));
961 srbStatus
= SRB_STATUS_SUCCESS
;
964 case SCSI_SENSE_NOT_READY
:
967 "ATAPI: Device not ready\n"));
968 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
969 srbStatus
= SRB_STATUS_ERROR
;
972 case SCSI_SENSE_MEDIUM_ERROR
:
975 "ATAPI: Media error\n"));
976 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
977 srbStatus
= SRB_STATUS_ERROR
;
980 case SCSI_SENSE_HARDWARE_ERROR
:
983 "ATAPI: Hardware error\n"));
984 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
985 srbStatus
= SRB_STATUS_ERROR
;
988 case SCSI_SENSE_ILLEGAL_REQUEST
:
991 "ATAPI: Illegal request\n"));
992 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
993 srbStatus
= SRB_STATUS_ERROR
;
996 case SCSI_SENSE_UNIT_ATTENTION
:
999 "ATAPI: Unit attention\n"));
1000 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1001 srbStatus
= SRB_STATUS_ERROR
;
1004 case SCSI_SENSE_DATA_PROTECT
:
1007 "ATAPI: Data protect\n"));
1008 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1009 srbStatus
= SRB_STATUS_ERROR
;
1012 case SCSI_SENSE_BLANK_CHECK
:
1015 "ATAPI: Blank check\n"));
1016 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1017 srbStatus
= SRB_STATUS_ERROR
;
1020 case SCSI_SENSE_ABORTED_COMMAND
:
1022 "Atapi: Command Aborted\n"));
1023 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1024 srbStatus
= SRB_STATUS_ERROR
;
1030 "ATAPI: Invalid sense information\n"));
1032 srbStatus
= SRB_STATUS_ERROR
;
1041 // Save errorByte,to be used by SCSIOP_REQUEST_SENSE.
1044 deviceExtension
->ReturningMediaStatus
= errorByte
;
1046 if (errorByte
& IDE_ERROR_MEDIA_CHANGE_REQ
) {
1048 "IDE: Media change\n"));
1049 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1050 srbStatus
= SRB_STATUS_ERROR
;
1052 } else if (errorByte
& IDE_ERROR_COMMAND_ABORTED
) {
1054 "IDE: Command abort\n"));
1055 srbStatus
= SRB_STATUS_ABORTED
;
1056 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1058 if (Srb
->SenseInfoBuffer
) {
1060 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->SenseInfoBuffer
;
1062 senseBuffer
->ErrorCode
= 0x70;
1063 senseBuffer
->Valid
= 1;
1064 senseBuffer
->AdditionalSenseLength
= 0xb;
1065 senseBuffer
->SenseKey
= SCSI_SENSE_ABORTED_COMMAND
;
1066 senseBuffer
->AdditionalSenseCode
= 0;
1067 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
1069 srbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1072 deviceExtension
->ErrorCount
++;
1074 } else if (errorByte
& IDE_ERROR_END_OF_MEDIA
) {
1077 "IDE: End of media\n"));
1078 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1079 srbStatus
= SRB_STATUS_ERROR
;
1080 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
)){
1081 deviceExtension
->ErrorCount
++;
1084 } else if (errorByte
& IDE_ERROR_ILLEGAL_LENGTH
) {
1087 "IDE: Illegal length\n"));
1088 srbStatus
= SRB_STATUS_INVALID_REQUEST
;
1090 } else if (errorByte
& IDE_ERROR_BAD_BLOCK
) {
1093 "IDE: Bad block\n"));
1094 srbStatus
= SRB_STATUS_ERROR
;
1095 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1096 if (Srb
->SenseInfoBuffer
) {
1098 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->SenseInfoBuffer
;
1100 senseBuffer
->ErrorCode
= 0x70;
1101 senseBuffer
->Valid
= 1;
1102 senseBuffer
->AdditionalSenseLength
= 0xb;
1103 senseBuffer
->SenseKey
= SCSI_SENSE_MEDIUM_ERROR
;
1104 senseBuffer
->AdditionalSenseCode
= 0;
1105 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
1107 srbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1110 } else if (errorByte
& IDE_ERROR_ID_NOT_FOUND
) {
1113 "IDE: Id not found\n"));
1114 srbStatus
= SRB_STATUS_ERROR
;
1115 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1117 if (Srb
->SenseInfoBuffer
) {
1119 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->SenseInfoBuffer
;
1121 senseBuffer
->ErrorCode
= 0x70;
1122 senseBuffer
->Valid
= 1;
1123 senseBuffer
->AdditionalSenseLength
= 0xb;
1124 senseBuffer
->SenseKey
= SCSI_SENSE_MEDIUM_ERROR
;
1125 senseBuffer
->AdditionalSenseCode
= 0;
1126 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
1128 srbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1131 deviceExtension
->ErrorCount
++;
1133 } else if (errorByte
& IDE_ERROR_MEDIA_CHANGE
) {
1136 "IDE: Media change\n"));
1137 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1138 srbStatus
= SRB_STATUS_ERROR
;
1140 if (Srb
->SenseInfoBuffer
) {
1142 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->SenseInfoBuffer
;
1144 senseBuffer
->ErrorCode
= 0x70;
1145 senseBuffer
->Valid
= 1;
1146 senseBuffer
->AdditionalSenseLength
= 0xb;
1147 senseBuffer
->SenseKey
= SCSI_SENSE_UNIT_ATTENTION
;
1148 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_MEDIUM_CHANGED
;
1149 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
1151 srbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1154 } else if (errorByte
& IDE_ERROR_DATA_ERROR
) {
1157 "IDE: Data error\n"));
1158 scsiStatus
= SCSISTAT_CHECK_CONDITION
;
1159 srbStatus
= SRB_STATUS_ERROR
;
1161 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
)){
1162 deviceExtension
->ErrorCount
++;
1166 // Build sense buffer
1169 if (Srb
->SenseInfoBuffer
) {
1171 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->SenseInfoBuffer
;
1173 senseBuffer
->ErrorCode
= 0x70;
1174 senseBuffer
->Valid
= 1;
1175 senseBuffer
->AdditionalSenseLength
= 0xb;
1176 senseBuffer
->SenseKey
= SCSI_SENSE_MEDIUM_ERROR
;
1177 senseBuffer
->AdditionalSenseCode
= 0;
1178 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
1180 srbStatus
|= SRB_STATUS_AUTOSENSE_VALID
;
1184 if (deviceExtension
->ErrorCount
>= MAX_ERRORS
) {
1185 deviceExtension
->DWordIO
= FALSE
;
1186 deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
] = 0;
1189 "MapError: Disabling 32-bit PIO and Multi-sector IOs\n"));
1195 ScsiPortLogError( HwDeviceExtension
,
1203 // Reprogram to not use Multi-sector.
1206 for (i
= 0; i
< 4; i
++) {
1209 if (deviceExtension
->DeviceFlags
[i
] & DFLAGS_DEVICE_PRESENT
&&
1210 !(deviceExtension
->DeviceFlags
[i
] & DFLAGS_ATAPI_DEVICE
)) {
1213 // Select the device.
1216 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1217 (UCHAR
)(((i
& 0x1) << 4) | 0xA0));
1220 // Setup sector count to reflect the # of blocks.
1223 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,
1227 // Issue the command.
1230 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
1231 IDE_COMMAND_SET_MULTIPLE
);
1234 // Wait for busy to drop.
1237 WaitOnBaseBusy(baseIoAddress1
,statusByte
);
1240 // Check for errors. Reset the value to 0 (disable MultiBlock) if the
1241 // command was aborted.
1244 if (statusByte
& IDE_STATUS_ERROR
) {
1247 // Read the error register.
1250 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
1253 "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n",
1257 // Adjust the devExt. value, if necessary.
1260 deviceExtension
->MaximumBlockXfer
[i
] = 0;
1270 // Set SCSI status to indicate a check condition.
1273 Srb
->ScsiStatus
= scsiStatus
;
1283 IN PVOID HwDeviceExtension
1288 Routine Description:
1292 HwDeviceExtension - HBA miniport driver's adapter data storage
1296 TRUE - if initialization successful.
1297 FALSE - if initialization unsuccessful.
1302 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
1303 PIDE_REGISTERS_1 baseIoAddress
;
1305 UCHAR statusByte
, errorByte
;
1308 for (i
= 0; i
< 4; i
++) {
1309 if (deviceExtension
->DeviceFlags
[i
] & DFLAGS_DEVICE_PRESENT
) {
1311 if (!(deviceExtension
->DeviceFlags
[i
] & DFLAGS_ATAPI_DEVICE
)) {
1314 // Enable media status notification
1317 baseIoAddress
= deviceExtension
->BaseIoAddress1
[i
>> 1];
1319 IdeMediaStatus(TRUE
,HwDeviceExtension
,i
);
1322 // If supported, setup Multi-block transfers.
1324 if (deviceExtension
->MaximumBlockXfer
[i
]) {
1327 // Select the device.
1330 ScsiPortWritePortUchar(&baseIoAddress
->DriveSelect
,
1331 (UCHAR
)(((i
& 0x1) << 4) | 0xA0));
1334 // Setup sector count to reflect the # of blocks.
1337 ScsiPortWritePortUchar(&baseIoAddress
->BlockCount
,
1338 deviceExtension
->MaximumBlockXfer
[i
]);
1341 // Issue the command.
1344 ScsiPortWritePortUchar(&baseIoAddress
->Command
,
1345 IDE_COMMAND_SET_MULTIPLE
);
1348 // Wait for busy to drop.
1351 WaitOnBaseBusy(baseIoAddress
,statusByte
);
1354 // Check for errors. Reset the value to 0 (disable MultiBlock) if the
1355 // command was aborted.
1358 if (statusByte
& IDE_STATUS_ERROR
) {
1361 // Read the error register.
1364 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress
+ 1);
1367 "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n",
1371 // Adjust the devExt. value, if necessary.
1374 deviceExtension
->MaximumBlockXfer
[i
] = 0;
1378 "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n",
1380 deviceExtension
->MaximumBlockXfer
[i
]));
1383 } else if (!(deviceExtension
->DeviceFlags
[i
] & DFLAGS_CHANGER_INITED
)){
1389 // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc.
1392 for (j
= 0; j
< 13; j
+= 2) {
1395 // Build a buffer based on the identify data.
1398 vendorId
[j
] = ((PUCHAR
)deviceExtension
->IdentifyData
[i
].ModelNumber
)[j
+ 1];
1399 vendorId
[j
+1] = ((PUCHAR
)deviceExtension
->IdentifyData
[i
].ModelNumber
)[j
];
1402 if (!AtapiStringCmp ((PCHAR
)vendorId
, "CD-ROM CDR", 11)) {
1405 // Inquiry string for older model had a '-', newer is '_'
1408 if (vendorId
[12] == 'C') {
1411 // Torisan changer. Set the bit. This will be used in several places
1412 // acting like 1) a multi-lun device and 2) building the 'special' TUR's.
1415 deviceExtension
->DeviceFlags
[i
] |= (DFLAGS_CHANGER_INITED
| DFLAGS_SANYO_ATAPI_CHANGER
);
1416 deviceExtension
->DiscsPresent
[i
] = 3;
1422 // We need to get our device ready for action before
1423 // returning from this function
1425 // According to the atapi spec 2.5 or 2.6, an atapi device
1426 // clears its status BSY bit when it is ready for atapi commands.
1427 // However, some devices (Panasonic SQ-TC500N) are still
1428 // not ready even when the status BSY is clear. They don't react
1429 // to atapi commands.
1431 // Since there is really no other indication that tells us
1432 // the drive is really ready for action. We are going to check BSY
1433 // is clear and then just wait for an arbitrary amount of time!
1435 if (deviceExtension
->DeviceFlags
[i
] & DFLAGS_ATAPI_DEVICE
) {
1436 //PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[i >> 1];
1437 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[i
>> 1];
1440 // have to get out of the loop sometime!
1441 // 10000 * 100us = 1000,000us = 1000ms = 1s
1443 GetStatus(baseIoAddress2
, statusByte
);
1444 while ((statusByte
& IDE_STATUS_BUSY
) && waitCount
) {
1446 // Wait for Busy to drop.
1448 ScsiPortStallExecution(100);
1449 GetStatus(baseIoAddress2
, statusByte
);
1453 // 5000 * 100us = 500,000us = 500ms = 0.5s
1456 ScsiPortStallExecution(100);
1457 } while (waitCount
--);
1464 } // end AtapiHwInitialize()
1469 AtapiHwInitializeChanger (
1470 IN PVOID HwDeviceExtension
,
1472 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus
)
1474 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
1476 if (MechanismStatus
) {
1477 deviceExtension
->DiscsPresent
[TargetId
] = MechanismStatus
->NumberAvailableSlots
;
1478 if (deviceExtension
->DiscsPresent
[TargetId
] > 1) {
1479 deviceExtension
->DeviceFlags
[TargetId
] |= DFLAGS_ATAPI_CHANGER
;
1490 IN PVOID HwDeviceExtension
,
1491 IN BOOLEAN AtapiOnly
,
1497 Routine Description:
1499 This routine is called from AtapiFindController to identify
1500 devices attached to an IDE controller.
1504 HwDeviceExtension - HBA miniport driver's adapter data storage
1505 AtapiOnly - Indicates that routine should return TRUE only if
1506 an ATAPI device is attached to the controller.
1510 TRUE - True if devices found.
1515 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
1516 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Channel
];
1517 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Channel
];
1518 BOOLEAN deviceResponded
= FALSE
,
1519 skipSetParameters
= FALSE
;
1520 ULONG waitCount
= 10000;
1528 // Clear expecting interrupt flag and current SRB field.
1531 deviceExtension
->ExpectingInterrupt
= FALSE
;
1532 deviceExtension
->CurrentSrb
= NULL
;
1535 // Search for devices.
1538 for (deviceNumber
= 0; deviceNumber
< 2; deviceNumber
++) {
1541 // Select the device.
1544 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1545 (UCHAR
)((deviceNumber
<< 4) | 0xA0));
1548 // Check here for some SCSI adapters that incorporate IDE emulation.
1551 GetStatus(baseIoAddress2
, statusByte
);
1552 if (statusByte
== 0xFF) {
1556 AtapiSoftReset(baseIoAddress1
,deviceNumber
);
1557 WaitOnBusy(baseIoAddress2
,statusByte
);
1559 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
1560 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
1562 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
1565 // ATAPI signature found.
1566 // Issue the ATAPI identify command if this
1567 // is not for the crash dump utility.
1572 if (!deviceExtension
->DriverMustPoll
) {
1575 // Issue ATAPI packet identify command.
1578 if (IssueIdentify(HwDeviceExtension
,
1581 IDE_COMMAND_ATAPI_IDENTIFY
)) {
1584 // Indicate ATAPI device.
1588 "FindDevices: Device %x is ATAPI\n",
1591 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] |= DFLAGS_ATAPI_DEVICE
;
1592 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] |= DFLAGS_DEVICE_PRESENT
;
1594 deviceResponded
= TRUE
;
1596 GetStatus(baseIoAddress2
, statusByte
);
1597 if (statusByte
& IDE_STATUS_ERROR
) {
1598 AtapiSoftReset(baseIoAddress1
, deviceNumber
);
1605 // Indicate no working device.
1609 "FindDevices: Device %x not responding\n",
1612 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] &= ~DFLAGS_DEVICE_PRESENT
;
1620 // Issue IDE Identify. If an Atapi device is actually present, the signature
1621 // will be asserted, and the drive will be recognized as such.
1624 if (IssueIdentify(HwDeviceExtension
,
1627 IDE_COMMAND_IDENTIFY
)) {
1635 "FindDevices: Device %x is IDE\n",
1638 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] |= DFLAGS_DEVICE_PRESENT
;
1641 deviceResponded
= TRUE
;
1645 // Indicate IDE - not ATAPI device.
1648 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] &= ~DFLAGS_ATAPI_DEVICE
;
1654 // Look to see if an Atapi device is present.
1657 AtapiSoftReset(baseIoAddress1
,deviceNumber
);
1659 WaitOnBusy(baseIoAddress2
,statusByte
);
1661 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
1662 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
1664 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
1671 for (i
= 0; i
< 2; i
++) {
1672 if ((deviceExtension
->DeviceFlags
[i
+ (Channel
* 2)] & DFLAGS_DEVICE_PRESENT
) &&
1673 (!(deviceExtension
->DeviceFlags
[i
+ (Channel
* 2)] & DFLAGS_ATAPI_DEVICE
)) && deviceResponded
) {
1676 // This hideous hack is to deal with ESDI devices that return
1677 // garbage geometry in the IDENTIFY data.
1678 // This is ONLY for the crashdump environment as
1679 // these are ESDI devices.
1682 if (deviceExtension
->IdentifyData
[i
].SectorsPerTrack
==
1684 deviceExtension
->IdentifyData
[i
].NumberOfHeads
==
1688 "FindDevices: Found nasty Compaq ESDI!\n"));
1691 // Change these values to something reasonable.
1694 deviceExtension
->IdentifyData
[i
].SectorsPerTrack
=
1696 deviceExtension
->IdentifyData
[i
].NumberOfHeads
=
1700 if (deviceExtension
->IdentifyData
[i
].SectorsPerTrack
==
1702 deviceExtension
->IdentifyData
[i
].NumberOfHeads
==
1706 "FindDevices: Found nasty Compaq ESDI!\n"));
1709 // Change these values to something reasonable.
1712 deviceExtension
->IdentifyData
[i
].SectorsPerTrack
=
1714 deviceExtension
->IdentifyData
[i
].NumberOfHeads
=
1719 if (deviceExtension
->IdentifyData
[i
].SectorsPerTrack
==
1721 deviceExtension
->IdentifyData
[i
].NumberOfHeads
==
1725 "FindDevices: Found nasty UltraStor ESDI!\n"));
1728 // Change these values to something reasonable.
1731 deviceExtension
->IdentifyData
[i
].SectorsPerTrack
=
1733 deviceExtension
->IdentifyData
[i
].NumberOfHeads
=
1735 skipSetParameters
= TRUE
;
1739 if (!skipSetParameters
) {
1741 WaitOnBusy(baseIoAddress2
,statusByte
);
1744 // Select the device.
1747 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1748 (UCHAR
)((i
<< 4) | 0xA0));
1750 GetStatus(baseIoAddress2
, statusByte
);
1752 if (statusByte
& IDE_STATUS_ERROR
) {
1755 // Reset the device.
1759 "FindDevices: Resetting controller before SetDriveParameters.\n"));
1761 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_RESET_CONTROLLER
);
1762 ScsiPortStallExecution(500 * 1000);
1763 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_REENABLE_CONTROLLER
);
1764 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1765 (UCHAR
)((i
<< 4) | 0xA0));
1770 // Wait for Busy to drop.
1773 ScsiPortStallExecution(100);
1774 GetStatus(baseIoAddress2
, statusByte
);
1776 } while ((statusByte
& IDE_STATUS_BUSY
) && waitCount
--);
1779 WaitOnBusy(baseIoAddress2
,statusByte
);
1781 "FindDevices: Status before SetDriveParameters: (%x) (%x)\n",
1783 ScsiPortReadPortUchar(&baseIoAddress1
->DriveSelect
)));
1786 // Use the IDENTIFY data to set drive parameters.
1789 if (!SetDriveParameters(HwDeviceExtension
,i
,Channel
)) {
1792 "AtapHwInitialize: Set drive parameters for device %d failed\n",
1796 // Don't use this device as writes could cause corruption.
1799 deviceExtension
->DeviceFlags
[i
+ Channel
] = 0;
1803 if (deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] & DFLAGS_REMOVABLE_DRIVE
) {
1806 // Pick up ALL IDE removable drives that conform to Yosemite V0.2...
1814 // Indicate that a device was found.
1818 deviceResponded
= TRUE
;
1825 // Make sure master device is selected on exit.
1828 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
, 0xA0);
1831 // Reset the controller. This is a feeble attempt to leave the ESDI
1832 // controllers in a state that ATDISK driver will recognize them.
1833 // The problem in ATDISK has to do with timings as it is not reproducible
1834 // in debug. The reset should restore the controller to its poweron state
1835 // and give the system enough time to settle.
1838 if (!deviceResponded
) {
1840 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_RESET_CONTROLLER
);
1841 ScsiPortStallExecution(50 * 1000);
1842 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_REENABLE_CONTROLLER
);
1845 return deviceResponded
;
1847 } // end FindDevices()
1852 AtapiParseArgumentString(
1859 Routine Description:
1861 This routine will parse the string for a match on the keyword, then
1862 calculate the value for the keyword and return it to the caller.
1866 String - The ASCII string to parse.
1867 KeyWord - The keyword for the value desired.
1871 Zero if value not found
1872 Value converted from ASCII to binary.
1880 ULONG stringLength
= 0;
1881 ULONG keyWordLength
= 0;
1892 // Calculate the string length and lower case all characters.
1897 if (*cptr
>= 'A' && *cptr
<= 'Z') {
1898 *cptr
= *cptr
+ ('a' - 'A');
1905 // Calculate the keyword length and lower case all characters.
1911 if (*cptr
>= 'A' && *cptr
<= 'Z') {
1912 *cptr
= *cptr
+ ('a' - 'A');
1918 if (keyWordLength
> stringLength
) {
1921 // Can't possibly have a match.
1928 // Now setup and start the compare.
1936 // The input string may start with white space. Skip it.
1939 while (*cptr
== ' ' || *cptr
== '\t') {
1943 if (*cptr
== '\0') {
1953 while (*cptr
++ == *kptr
++) {
1955 if (*(cptr
- 1) == '\0') {
1965 if (*(kptr
- 1) == '\0') {
1968 // May have a match backup and check for blank or equals.
1972 while (*cptr
== ' ' || *cptr
== '\t') {
1977 // Found a match. Make sure there is an equals.
1983 // Not a match so move to the next semicolon.
1987 if (*cptr
++ == ';') {
1988 goto ContinueSearch
;
1995 // Skip the equals sign.
2001 // Skip white space.
2004 while ((*cptr
== ' ') || (*cptr
== '\t')) {
2008 if (*cptr
== '\0') {
2011 // Early end of string, return not found
2020 // This isn't it either.
2024 goto ContinueSearch
;
2028 if ((*cptr
== '0') && (*(cptr
+ 1) == 'x')) {
2031 // Value is in Hex. Skip the "0x"
2035 for (index
= 0; *(cptr
+ index
); index
++) {
2037 if (*(cptr
+ index
) == ' ' ||
2038 *(cptr
+ index
) == '\t' ||
2039 *(cptr
+ index
) == ';') {
2043 if ((*(cptr
+ index
) >= '0') && (*(cptr
+ index
) <= '9')) {
2044 value
= (16 * value
) + (*(cptr
+ index
) - '0');
2046 if ((*(cptr
+ index
) >= 'a') && (*(cptr
+ index
) <= 'f')) {
2047 value
= (16 * value
) + (*(cptr
+ index
) - 'a' + 10);
2051 // Syntax error, return not found.
2060 // Value is in Decimal.
2063 for (index
= 0; *(cptr
+ index
); index
++) {
2065 if (*(cptr
+ index
) == ' ' ||
2066 *(cptr
+ index
) == '\t' ||
2067 *(cptr
+ index
) == ';') {
2071 if ((*(cptr
+ index
) >= '0') && (*(cptr
+ index
) <= '9')) {
2072 value
= (10 * value
) + (*(cptr
+ index
) - '0');
2076 // Syntax error return not found.
2087 // Not a match check for ';' to continue search.
2091 if (*cptr
++ == ';') {
2092 goto ContinueSearch
;
2106 AtapiFindController(
2107 IN PVOID HwDeviceExtension
,
2109 IN PVOID BusInformation
,
2110 IN PCHAR ArgumentString
,
2111 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
2116 Routine Description:
2118 This function is called by the OS-specific port driver after
2119 the necessary storage has been allocated, to gather information
2120 about the adapter's configuration.
2124 HwDeviceExtension - HBA miniport driver's adapter data storage
2125 Context - Address of adapter count
2126 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
2127 ConfigInfo - Configuration information structure describing HBA
2128 Again - Indicates search for adapters to continue
2137 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
2138 PULONG adapterCount
= (PULONG
)Context
;
2139 PUCHAR ioSpace
= NULL
;
2144 PCI_SLOT_NUMBER slotData
;
2145 PPCI_COMMON_CONFIG pciData
;
2149 BOOLEAN preConfig
= FALSE
;
2151 // The following table specifies the ports to be checked when searching for
2152 // an IDE controller. A zero entry terminates the search.
2155 CONST ULONG AdapterAddresses
[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
2158 // The following table specifies interrupt levels corresponding to the
2159 // port addresses in the previous table.
2162 CONST ULONG InterruptLevels
[5] = {14, 15, 11, 10, 0};
2164 if (!deviceExtension
) {
2165 return SP_RETURN_ERROR
;
2169 // Check to see if this is a special configuration environment.
2173 if (ArgumentString
) {
2175 irq
= AtapiParseArgumentString(ArgumentString
, "Interrupt");
2179 // Both parameters must be present to proceed
2182 portBase
= AtapiParseArgumentString(ArgumentString
, "BaseAddress");
2186 // Try a default search for the part.
2197 // Scan though the adapter address looking for adapters.
2199 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
) != 0) {
2200 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2201 ConfigInfo
->AdapterInterfaceType
,
2202 ConfigInfo
->SystemIoBusNumber
,
2203 (*ConfigInfo
->AccessRanges
)[0].RangeStart
,
2204 (*ConfigInfo
->AccessRanges
)[0].RangeLength
,
2205 (BOOLEAN
) !((*ConfigInfo
->AccessRanges
)[0].RangeInMemory
));
2208 // Since we have pre-configured information we only need to go through this loop once
2211 portBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
);
2217 while (AdapterAddresses
[*adapterCount
] != 0) {
2221 for (i
= 0; i
< 4; i
++) {
2224 // Zero device fields to ensure that if earlier devices were found,
2225 // but not claimed, the fields are cleared.
2228 deviceExtension
->DeviceFlags
[i
] &= ~(DFLAGS_ATAPI_DEVICE
| DFLAGS_DEVICE_PRESENT
| DFLAGS_TAPE_DEVICE
);
2232 // Get the system physical address for this IO range.
2237 // Check if configInfo has the default information
2238 // if not, we go and find ourselves
2241 if (preConfig
== FALSE
) {
2244 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2245 ConfigInfo
->AdapterInterfaceType
,
2246 ConfigInfo
->SystemIoBusNumber
,
2247 ScsiPortConvertUlongToPhysicalAddress(portBase
),
2251 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2252 ConfigInfo
->AdapterInterfaceType
,
2253 ConfigInfo
->SystemIoBusNumber
,
2254 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
]),
2259 }// ConfigInfo check
2261 // Update the adapter count.
2267 // Check if ioSpace accessible.
2280 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xA0);
2283 // Check if card at this address.
2286 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2289 // Check if identifier can be read back.
2292 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2295 "AtapiFindController: Identifier read back from Master (%x)\n",
2298 statusByte
= ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2
)ioSpace
)->AlternateStatus
);
2300 if (statusByte
& IDE_STATUS_BUSY
) {
2305 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
2306 // warm boots don't clear.
2310 ScsiPortStallExecution(1000);
2311 statusByte
= ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1
)ioSpace
)->Command
);
2313 "AtapiFindController: First access to status %x\n",
2315 } while ((statusByte
& IDE_STATUS_BUSY
) && ++i
< 10);
2317 if (retryCount
-- && (!(statusByte
& IDE_STATUS_BUSY
))) {
2318 goto retryIdentifier
;
2326 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xB0);
2329 // See if slave is present.
2332 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2334 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2337 "AtapiFindController: Identifier read back from Slave (%x)\n",
2342 // No controller at this base address.
2345 ScsiPortFreeDeviceBase(HwDeviceExtension
,
2353 // Record base IO address.
2356 deviceExtension
->BaseIoAddress1
[0] = (PIDE_REGISTERS_1
)(ioSpace
);
2359 // Fill in the access array information only if default params are not in there.
2361 if (preConfig
== FALSE
) {
2364 // An adapter has been found request another call, only if we didn't get preconfigured info.
2369 (*ConfigInfo
->AccessRanges
)[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(portBase
);
2371 (*ConfigInfo
->AccessRanges
)[0].RangeStart
=
2372 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1]);
2375 (*ConfigInfo
->AccessRanges
)[0].RangeLength
= 8;
2376 (*ConfigInfo
->AccessRanges
)[0].RangeInMemory
= FALSE
;
2379 // Indicate the interrupt level corresponding to this IO range.
2383 ConfigInfo
->BusInterruptLevel
= irq
;
2385 ConfigInfo
->BusInterruptLevel
= InterruptLevels
[*adapterCount
- 1];
2388 if (ConfigInfo
->AdapterInterfaceType
== MicroChannel
) {
2389 ConfigInfo
->InterruptMode
= LevelSensitive
;
2391 ConfigInfo
->InterruptMode
= Latched
;
2395 // Get the system physical address for the second IO range.
2400 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2401 ConfigInfo
->AdapterInterfaceType
,
2402 ConfigInfo
->SystemIoBusNumber
,
2403 ScsiPortConvertUlongToPhysicalAddress(portBase
+ 0x206),
2407 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2408 ConfigInfo
->AdapterInterfaceType
,
2409 ConfigInfo
->SystemIoBusNumber
,
2410 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1] + 0x206),
2415 deviceExtension
->BaseIoAddress2
[0] = (PIDE_REGISTERS_2
)(ioSpace
);
2417 deviceExtension
->NumberChannels
= 1;
2419 ConfigInfo
->NumberOfBuses
= 1;
2420 ConfigInfo
->MaximumNumberOfTargets
= 2;
2423 // Indicate maximum transfer length is 64k.
2426 ConfigInfo
->MaximumTransferLength
= 0x10000;
2429 "AtapiFindController: Found IDE at %x\n",
2430 deviceExtension
->BaseIoAddress1
[0]));
2434 // For Daytona, the atdisk driver gets the first shot at the
2435 // primary and secondary controllers.
2438 if (preConfig
== FALSE
) {
2441 if (*adapterCount
- 1 < 2) {
2444 // Determine whether this driver is being initialized by the
2445 // system or as a crash dump driver.
2448 if (ArgumentString
) {
2450 if (AtapiParseArgumentString(ArgumentString
, "dump") == 1) {
2452 "AtapiFindController: Crash dump\n"));
2454 deviceExtension
->DriverMustPoll
= TRUE
;
2457 "AtapiFindController: Atapi Only\n"));
2459 deviceExtension
->DriverMustPoll
= FALSE
;
2464 "AtapiFindController: Atapi Only\n"));
2466 deviceExtension
->DriverMustPoll
= FALSE
;
2474 // If this is a PCI machine, pick up all devices.
2478 pciData
= (PPCI_COMMON_CONFIG
)&pciBuffer
;
2480 slotData
.u
.bits
.DeviceNumber
= 0;
2481 slotData
.u
.bits
.FunctionNumber
= 0;
2483 if (ScsiPortGetBusData(deviceExtension
,
2493 // Wait on doing this, until a reliable method
2494 // of determining support is found.
2498 deviceExtension
->DWordIO
= TRUE
;
2502 deviceExtension
->DWordIO
= FALSE
;
2508 deviceExtension
->DriverMustPoll
= FALSE
;
2513 // Save the Interrupt Mode for later use
2515 deviceExtension
->InterruptMode
= ConfigInfo
->InterruptMode
;
2518 // Search for devices on this controller.
2521 if (FindDevices(HwDeviceExtension
,
2526 // Claim primary or secondary ATA IO range.
2532 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
2533 deviceExtension
->PrimaryAddress
= FALSE
;
2536 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
2537 deviceExtension
->PrimaryAddress
= TRUE
;
2543 if (*adapterCount
== 1) {
2544 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
2545 deviceExtension
->PrimaryAddress
= TRUE
;
2546 } else if (*adapterCount
== 2) {
2547 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
2548 deviceExtension
->PrimaryAddress
= FALSE
;
2552 return(SP_RETURN_FOUND
);
2557 // The entire table has been searched and no adapters have been found.
2558 // There is no need to call again and the device base can now be freed.
2559 // Clear the adapter count for the next bus.
2563 *(adapterCount
) = 0;
2565 return(SP_RETURN_NOT_FOUND
);
2567 } // end AtapiFindController()
2575 FindBrokenController(
2576 IN PVOID DeviceExtension
,
2578 IN ULONG VendorIDLength
,
2580 IN ULONG DeviceIDLength
,
2581 IN OUT PULONG FunctionNumber
,
2582 IN OUT PULONG SlotNumber
,
2584 OUT PBOOLEAN LastSlot
2589 Routine Description:
2591 Walk PCI slot information looking for Vendor and Product ID matches.
2603 ULONG functionNumber
;
2604 PCI_SLOT_NUMBER slotData
;
2605 PPCI_COMMON_CONFIG pciData
;
2606 UCHAR vendorString
[5];
2607 UCHAR deviceString
[5];
2608 PUCHAR vendorStrPtr
;
2609 PUCHAR deviceStrPtr
;
2611 pciData
= (PPCI_COMMON_CONFIG
)&pciBuffer
;
2613 slotData
.u
.AsULONG
= 0;
2616 // Look at each device.
2619 for (slotNumber
= *SlotNumber
;
2623 slotData
.u
.bits
.DeviceNumber
= slotNumber
;
2626 // Look at each function.
2629 for (functionNumber
= *FunctionNumber
;
2633 slotData
.u
.bits
.FunctionNumber
= functionNumber
;
2635 if (!ScsiPortGetBusData(DeviceExtension
,
2650 if (pciData
->VendorID
== PCI_INVALID_VENDORID
) {
2653 // No PCI device, or no more functions on device
2654 // move to next PCI device.
2661 // Translate hex ids to strings.
2664 vendorStrPtr
= vendorString
;
2665 deviceStrPtr
= deviceString
;
2666 AtapiHexToString(pciData
->VendorID
, (PCHAR
*)&vendorStrPtr
);
2667 AtapiHexToString(pciData
->DeviceID
, (PCHAR
*)&deviceStrPtr
);
2670 "FindBrokenController: Bus %x Slot %x Function %x Vendor %s Product %s\n",
2681 if (AtapiStringCmp((PCHAR
)vendorString
,
2684 AtapiStringCmp((PCHAR
)deviceString
,
2689 // Not our PCI device. Try next device/function
2695 *FunctionNumber
= functionNumber
;
2696 *SlotNumber
= slotNumber
;
2699 } // next PCI function
2701 *FunctionNumber
= 0;
2707 } // end FindBrokenController
2712 AtapiFindNativeModeController(
2713 IN PVOID HwDeviceExtension
,
2715 IN PVOID BusInformation
,
2716 IN PCHAR ArgumentString
,
2717 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
2722 Routine Description:
2724 This function is called by the OS-specific port driver after
2725 the necessary storage has been allocated, to gather information
2726 about the adapter's configuration.
2730 HwDeviceExtension - HBA miniport driver's adapter data storage
2731 Context - Address of adapter count
2733 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
2734 ConfigInfo - Configuration information structure describing HBA
2735 Again - Indicates search for adapters to continue
2744 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
2745 ULONG nativeModeAdapterTableIndex
= (ULONG_PTR
)Context
;
2749 deviceFound
= FALSE
;
2751 PCI_SLOT_NUMBER slotData
;
2752 PCI_COMMON_CONFIG pciData
;
2755 UCHAR vendorString
[5];
2756 UCHAR deviceString
[5];
2757 PUCHAR vendorStrPtr
;
2758 PUCHAR deviceStrPtr
;
2759 SCSI_PHYSICAL_ADDRESS IoBasePort1
;
2760 SCSI_PHYSICAL_ADDRESS IoBasePort2
;
2763 // The following table specifies the ports to be checked when searching for
2764 // an IDE controller. A zero entry terminates the search.
2767 CONST ULONG AdapterAddresses
[3] = {0x1F0, 0x170, 0};
2769 if (!deviceExtension
) {
2770 return SP_RETURN_ERROR
;
2775 slotData
.u
.AsULONG
= 0;
2776 slotData
.u
.bits
.DeviceNumber
= ConfigInfo
->SlotNumber
;
2778 for (funcNumber
= 0; funcNumber
< 8; funcNumber
++) {
2780 slotData
.u
.bits
.FunctionNumber
= funcNumber
;
2782 busDataRead
= ScsiPortGetBusData(HwDeviceExtension
,
2784 ConfigInfo
->SystemIoBusNumber
,
2788 if (busDataRead
!= sizeof (pciData
)) {
2789 return SP_RETURN_ERROR
;
2791 if (pciData
.VendorID
== PCI_INVALID_VENDORID
) {
2792 return SP_RETURN_ERROR
;
2796 // Translate hex ids to strings.
2799 vendorStrPtr
= vendorString
;
2800 deviceStrPtr
= deviceString
;
2801 AtapiHexToString(pciData
.VendorID
, (PCHAR
*)&vendorStrPtr
);
2802 AtapiHexToString(pciData
.DeviceID
, (PCHAR
*)&deviceStrPtr
);
2808 if (AtapiStringCmp((PCHAR
)vendorString
,
2809 NativeModeAdapters
[nativeModeAdapterTableIndex
].VendorId
,
2810 NativeModeAdapters
[nativeModeAdapterTableIndex
].VendorIdLength
) ||
2811 AtapiStringCmp((PCHAR
)deviceString
,
2812 NativeModeAdapters
[nativeModeAdapterTableIndex
].DeviceId
,
2813 NativeModeAdapters
[nativeModeAdapterTableIndex
].DeviceIdLength
)) {
2817 if (pciData
.ProgIf
& ((1 << 2) | (1 << 0))) {
2818 // both primary and secondary channel are in native mode
2827 if (*Again
== TRUE
) {
2829 for (channel
= 0; channel
< 2; channel
++) {
2831 IoBasePort1
= (*ConfigInfo
->AccessRanges
)[channel
* 2 + 0].RangeStart
;
2832 IoBasePort2
= (*ConfigInfo
->AccessRanges
)[channel
* 2 + 1].RangeStart
;
2833 IoBasePort2
= ScsiPortConvertUlongToPhysicalAddress(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2
) + 2);
2836 // Get the system physical address for this IO range.
2839 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2840 ConfigInfo
->AdapterInterfaceType
,
2841 ConfigInfo
->SystemIoBusNumber
,
2847 // Check if ioSpace accessible.
2858 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xA0);
2861 // Check if card at this address.
2864 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2867 // Check if identifier can be read back.
2870 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2873 "AtapiFindPciController: Identifier read back from Master (%x)\n",
2881 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xB0);
2884 // See if slave is present.
2887 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2889 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2892 "AtapiFindPciController: Identifier read back from Slave (%x)\n",
2897 // No controller at this base address.
2900 ScsiPortFreeDeviceBase(HwDeviceExtension
,
2904 // If the chip is there, but we couldn't find the primary channel, try the secondary.
2905 // If we couldn't find a secondary, who cares.
2910 goto setStatusAndExit
;
2919 // Record base IO address.
2922 deviceExtension
->BaseIoAddress1
[channel
] = (PIDE_REGISTERS_1
)(ioSpace
);
2925 // Get the system physical address for the second IO range.
2928 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2929 ConfigInfo
->AdapterInterfaceType
,
2930 ConfigInfo
->SystemIoBusNumber
,
2935 deviceExtension
->BaseIoAddress2
[channel
] = (PIDE_REGISTERS_2
)(ioSpace
);
2937 deviceExtension
->NumberChannels
= 2;
2940 // Indicate only one bus.
2943 ConfigInfo
->NumberOfBuses
= 1;
2946 // Indicate four devices can be attached to the adapter, since we
2947 // have to serialize access to the two channels.
2950 ConfigInfo
->MaximumNumberOfTargets
= 4;
2953 // Indicate maximum transfer length is 64k.
2956 ConfigInfo
->MaximumTransferLength
= 0x10000;
2959 "AtapiFindPciController: Found native mode IDE at %x\n",
2960 deviceExtension
->BaseIoAddress1
[channel
]));
2963 // Since we will always pick up this part, and not atdisk, so indicate.
2969 // Save the Interrupt Mode for later use
2971 deviceExtension
->InterruptMode
= ConfigInfo
->InterruptMode
;
2974 // Search for devices on this controller.
2977 if (FindDevices(HwDeviceExtension
,
2984 // Claim primary or secondary ATA IO range.
2987 if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort1
) == AdapterAddresses
[0]) {
2988 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
2989 deviceExtension
->PrimaryAddress
= TRUE
;
2991 } else if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort2
) == AdapterAddresses
[1]) {
2992 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
2993 deviceExtension
->PrimaryAddress
= FALSE
;
3003 return SP_RETURN_FOUND
;
3007 return SP_RETURN_NOT_FOUND
;
3009 } // end AtapiFindNativeModeController()
3014 AtapiFindPCIController(
3015 IN PVOID HwDeviceExtension
,
3017 IN PVOID BusInformation
,
3018 IN PCHAR ArgumentString
,
3019 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
3024 Routine Description:
3026 This function is called by the OS-specific port driver after
3027 the necessary storage has been allocated, to gather information
3028 about the adapter's configuration.
3032 HwDeviceExtension - HBA miniport driver's adapter data storage
3033 Context - Address of adapter count
3035 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
3036 ConfigInfo - Configuration information structure describing HBA
3037 Again - Indicates search for adapters to continue
3046 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
3047 PULONG adapterCount
= (PULONG
)Context
;
3049 static ULONG functionNumber
,
3056 controllerFound
= FALSE
,
3057 deviceFound
= FALSE
;
3061 // The following table specifies the ports to be checked when searching for
3062 // an IDE controller. A zero entry terminates the search.
3065 CONST ULONG AdapterAddresses
[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
3068 // The following table specifies interrupt levels corresponding to the
3069 // port addresses in the previous table.
3072 CONST ULONG InterruptLevels
[5] = {14, 15, 11, 10, 0};
3074 if (!deviceExtension
) {
3075 return SP_RETURN_ERROR
;
3079 // Since scsiport will call this function first before it calls AtapiFindController
3080 // we need to bypass it if we have data installed in ConfigInfo, by the pcmcia driver.
3081 // In that case atapifindcontroller should be called first.
3082 // Instead of modifying atapi driverEntry to search of PCIBus first (now its ISA)
3083 // the check is put here.
3086 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
) != 0) {
3088 return AtapiFindController(HwDeviceExtension
,
3098 // Gronk PCI config space looking for the broken PCI IDE controllers that have only
3099 // one FIFO for both channels.
3100 // Don't do this. It's incorrect and nasty. It has to be done to work around these
3101 // broken parts, no other reason can justify this.
3104 for (i
= controllers
; i
< BROKEN_ADAPTERS
; i
++) {
3107 // Determine if both channels are enabled and have devices.
3112 if (FindBrokenController(deviceExtension
,
3113 (PUCHAR
)BrokenAdapters
[i
].VendorId
,
3114 BrokenAdapters
[i
].VendorIdLength
,
3115 (PUCHAR
)BrokenAdapters
[i
].DeviceId
,
3116 BrokenAdapters
[i
].DeviceIdLength
,
3119 ConfigInfo
->SystemIoBusNumber
,
3124 controllerFound
= TRUE
;
3127 "Found broken PCI IDE controller: VendorId %s, DeviceId %s\n",
3128 BrokenAdapters
[i
].VendorId
,
3129 BrokenAdapters
[i
].DeviceId
));
3131 if (AdapterAddresses
[*adapterCount
] != 0) {
3133 for (j
= 0; j
< 2; j
++) {
3136 // Get the system physical address for this IO range.
3139 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
3140 ConfigInfo
->AdapterInterfaceType
,
3141 ConfigInfo
->SystemIoBusNumber
,
3142 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
]),
3147 // Update the adapter count.
3153 // Check if ioSpace accessible.
3164 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xA0);
3167 // Check if card at this address.
3170 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
3173 // Check if identifier can be read back.
3176 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
3179 "AtapiFindPciController: Identifier read back from Master (%x)\n",
3187 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xB0);
3190 // See if slave is present.
3193 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
3195 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
3198 "AtapiFindPciController: Identifier read back from Slave (%x)\n",
3203 // No controller at this base address.
3206 ScsiPortFreeDeviceBase(HwDeviceExtension
,
3210 // If the chip is there, but we couldn't find the primary channel, try the secondary.
3211 // If we couldn't find a secondary, who cares.
3216 goto setStatusAndExit
;
3224 if (controllerFound
) {
3227 // Record base IO address.
3230 deviceExtension
->BaseIoAddress1
[channel
] = (PIDE_REGISTERS_1
)(ioSpace
);
3233 // Fill in the access array information.
3236 (*ConfigInfo
->AccessRanges
)[channel
].RangeStart
=
3237 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1]);
3239 (*ConfigInfo
->AccessRanges
)[channel
].RangeLength
= 8;
3240 (*ConfigInfo
->AccessRanges
)[channel
].RangeInMemory
= FALSE
;
3243 // Indicate the interrupt level corresponding to this IO range.
3247 ConfigInfo
->BusInterruptLevel
= InterruptLevels
[*adapterCount
- 1];
3248 ConfigInfo
->InterruptMode
= Latched
;
3250 ConfigInfo
->BusInterruptLevel2
= InterruptLevels
[*adapterCount
- 1];
3251 ConfigInfo
->InterruptMode2
= Latched
;
3255 // Get the system physical address for the second IO range.
3258 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
3259 ConfigInfo
->AdapterInterfaceType
,
3260 ConfigInfo
->SystemIoBusNumber
,
3261 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1] + 0x206),
3265 deviceExtension
->BaseIoAddress2
[channel
] = (PIDE_REGISTERS_2
)(ioSpace
);
3267 deviceExtension
->NumberChannels
= 2;
3270 // Indicate only one bus.
3273 ConfigInfo
->NumberOfBuses
= 1;
3276 // Indicate four devices can be attached to the adapter, since we
3277 // have to serialize access to the two channels.
3280 ConfigInfo
->MaximumNumberOfTargets
= 4;
3283 // Indicate maximum transfer length is 64k.
3286 ConfigInfo
->MaximumTransferLength
= 0x10000;
3289 "AtapiFindPciController: Found broken IDE at %x\n",
3290 deviceExtension
->BaseIoAddress1
[channel
]));
3293 // Since we will always pick up this part, and not atdisk, so indicate.
3299 // Save the Interrupt Mode for later use
3301 deviceExtension
->InterruptMode
= ConfigInfo
->InterruptMode
;
3304 // Search for devices on this controller.
3307 if (FindDevices(HwDeviceExtension
,
3314 // Claim primary or secondary ATA IO range.
3317 if (*adapterCount
== 1) {
3318 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
3319 deviceExtension
->PrimaryAddress
= TRUE
;
3321 } else if (*adapterCount
== 2) {
3322 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
3323 deviceExtension
->PrimaryAddress
= FALSE
;
3339 if (controllerFound
&& deviceFound
) {
3342 return SP_RETURN_FOUND
;
3348 // The entire table has been searched and no adapters have been found.
3353 return SP_RETURN_NOT_FOUND
;
3355 } // end AtapiFindPCIController()
3361 IN PSCSI_REQUEST_BLOCK Srb
,
3362 IN
char *DataBuffer
,
3366 ULONG bytesAdjust
= 0;
3367 if (Srb
->Cdb
[0] == ATAPI_MODE_SENSE
) {
3369 PMODE_PARAMETER_HEADER_10 header_10
= (PMODE_PARAMETER_HEADER_10
)DataBuffer
;
3370 PMODE_PARAMETER_HEADER header
= (PMODE_PARAMETER_HEADER
)DataBuffer
;
3372 header
->ModeDataLength
= header_10
->ModeDataLengthLsb
;
3373 header
->MediumType
= header_10
->MediumType
;
3376 // ATAPI Mode Parameter Header doesn't have these fields.
3379 header
->DeviceSpecificParameter
= header_10
->Reserved
[0];
3380 header
->BlockDescriptorLength
= header_10
->Reserved
[1];
3382 ByteCount
-= sizeof(MODE_PARAMETER_HEADER_10
);
3384 ScsiPortMoveMemory(DataBuffer
+sizeof(MODE_PARAMETER_HEADER
),
3385 DataBuffer
+sizeof(MODE_PARAMETER_HEADER_10
),
3389 // Change ATAPI_MODE_SENSE opcode back to SCSIOP_MODE_SENSE
3390 // so that we don't convert again.
3393 Srb
->Cdb
[0] = SCSIOP_MODE_SENSE
;
3395 bytesAdjust
= sizeof(MODE_PARAMETER_HEADER_10
) -
3396 sizeof(MODE_PARAMETER_HEADER
);
3402 // Convert to words.
3405 return bytesAdjust
>> 1;
3412 IN PVOID HwDeviceExtension
3415 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
3416 PSCSI_REQUEST_BLOCK srb
= deviceExtension
->CurrentSrb
;
3417 PATAPI_REGISTERS_2 baseIoAddress2
;
3421 // If the last command was DSC restrictive, see if it's set. If so, the device is
3422 // ready for a new request. Otherwise, reset the timer and come back to here later.
3425 if (srb
&& (!(deviceExtension
->ExpectingInterrupt
))) {
3427 if (!IS_RDP((srb
->Cdb
[0]))) {
3429 "AtapiCallBack: Invalid CDB marked as RDP - %x\n",
3434 baseIoAddress2
= (PATAPI_REGISTERS_2
)deviceExtension
->BaseIoAddress2
[srb
->TargetId
>> 1];
3435 if (deviceExtension
->RDP
) {
3436 GetStatus(baseIoAddress2
, statusByte
);
3437 if (statusByte
& IDE_STATUS_DSC
) {
3439 ScsiPortNotification(RequestComplete
,
3444 // Clear current SRB.
3447 deviceExtension
->CurrentSrb
= NULL
;
3448 deviceExtension
->RDP
= FALSE
;
3451 // Ask for next request.
3454 ScsiPortNotification(NextRequest
,
3464 "AtapiCallBack: Requesting another timer for Op %x\n",
3465 deviceExtension
->CurrentSrb
->Cdb
[0]));
3467 ScsiPortNotification(RequestTimerCall
,
3477 "AtapiCallBack: Calling ISR directly due to BUSY\n"));
3478 AtapiInterrupt(HwDeviceExtension
);
3485 IN PVOID HwDeviceExtension
3490 Routine Description:
3492 This is the interrupt service routine for ATAPI IDE miniport driver.
3496 HwDeviceExtension - HBA miniport driver's adapter data storage
3500 TRUE if expecting an interrupt.
3505 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
3506 PSCSI_REQUEST_BLOCK srb
= deviceExtension
->CurrentSrb
;
3507 PATAPI_REGISTERS_1 baseIoAddress1
;
3508 PATAPI_REGISTERS_2 baseIoAddress2
;
3509 ULONG wordCount
= 0, wordsThisInterrupt
= 256;
3512 UCHAR statusByte
,interruptReason
;
3513 BOOLEAN atapiDev
= FALSE
;
3516 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[srb
->TargetId
>> 1];
3517 baseIoAddress2
= (PATAPI_REGISTERS_2
)deviceExtension
->BaseIoAddress2
[srb
->TargetId
>> 1];
3520 "AtapiInterrupt: CurrentSrb is NULL\n"));
3522 // We can only support one ATAPI IDE master on Carolina, so find
3523 // the base address that is non NULL and clear its interrupt before
3529 if ((PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[0] != NULL
) {
3530 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[0];
3532 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[1];
3535 GetBaseStatus(baseIoAddress1
, statusByte
);
3538 if (deviceExtension
->InterruptMode
== LevelSensitive
) {
3539 if (deviceExtension
->BaseIoAddress1
[0] != NULL
) {
3540 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[0];
3541 GetBaseStatus(baseIoAddress1
, statusByte
);
3543 if (deviceExtension
->BaseIoAddress1
[1] != NULL
) {
3544 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[1];
3545 GetBaseStatus(baseIoAddress1
, statusByte
);
3552 if (!(deviceExtension
->ExpectingInterrupt
)) {
3555 "AtapiInterrupt: Unexpected interrupt.\n"));
3560 // Clear interrupt by reading status.
3563 GetBaseStatus(baseIoAddress1
, statusByte
);
3566 "AtapiInterrupt: Entered with status (%x)\n",
3570 if (statusByte
& IDE_STATUS_BUSY
) {
3571 if (deviceExtension
->DriverMustPoll
) {
3574 // Crashdump is polling and we got caught with busy asserted.
3575 // Just go away, and we will be polled again shortly.
3579 "AtapiInterrupt: Hit BUSY while polling during crashdump.\n"));
3585 // Ensure BUSY is non-asserted.
3588 for (i
= 0; i
< 10; i
++) {
3590 GetBaseStatus(baseIoAddress1
, statusByte
);
3591 if (!(statusByte
& IDE_STATUS_BUSY
)) {
3594 ScsiPortStallExecution(5000);
3600 "AtapiInterrupt: BUSY on entry. Status %x, Base IO %x\n",
3604 ScsiPortNotification(RequestTimerCall
,
3614 // Check for error conditions.
3617 if (statusByte
& IDE_STATUS_ERROR
) {
3619 if (srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
) {
3622 // Fail this request.
3625 status
= SRB_STATUS_ERROR
;
3626 goto CompleteRequest
;
3631 // check reason for this interrupt.
3634 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3636 interruptReason
= (ScsiPortReadPortUchar(&baseIoAddress1
->InterruptReason
) & 0x3);
3638 wordsThisInterrupt
= 256;
3642 if (statusByte
& IDE_STATUS_DRQ
) {
3644 if (deviceExtension
->MaximumBlockXfer
[srb
->TargetId
]) {
3645 wordsThisInterrupt
= 256 * deviceExtension
->MaximumBlockXfer
[srb
->TargetId
];
3649 if (srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) {
3651 interruptReason
= 0x2;
3653 } else if (srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
) {
3654 interruptReason
= 0x0;
3657 status
= SRB_STATUS_ERROR
;
3658 goto CompleteRequest
;
3661 } else if (statusByte
& IDE_STATUS_BUSY
) {
3667 if (deviceExtension
->WordsLeft
) {
3672 // Funky behaviour seen with PCI IDE (not all, just one).
3673 // The ISR hits with DRQ low, but comes up later.
3676 for (k
= 0; k
< 5000; k
++) {
3677 GetStatus(baseIoAddress2
,statusByte
);
3678 if (!(statusByte
& IDE_STATUS_DRQ
)) {
3679 ScsiPortStallExecution(100);
3688 // reset the controller.
3692 "AtapiInterrupt: Resetting due to DRQ not up. Status %x, Base IO %x\n",
3696 AtapiResetController(HwDeviceExtension
,srb
->PathId
);
3700 interruptReason
= (srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? 0x2 : 0x0;
3706 // Command complete - verify, write, or the SMART enable/disable.
3708 // Also get_media_status
3710 interruptReason
= 0x3;
3715 if (interruptReason
== 0x1 && (statusByte
& IDE_STATUS_DRQ
)) {
3718 // Write the packet.
3722 "AtapiInterrupt: Writing Atapi packet.\n"));
3725 // Send CDB to device.
3728 WriteBuffer(baseIoAddress1
,
3734 } else if (interruptReason
== 0x0 && (statusByte
& IDE_STATUS_DRQ
)) {
3740 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3743 // Pick up bytes to transfer and convert to words.
3747 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountLow
);
3750 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountHigh
) << 8;
3753 // Covert bytes to words.
3758 if (wordCount
!= deviceExtension
->WordsLeft
) {
3760 "AtapiInterrupt: %d words requested; %d words xferred\n",
3761 deviceExtension
->WordsLeft
,
3766 // Verify this makes sense.
3769 if (wordCount
> deviceExtension
->WordsLeft
) {
3770 wordCount
= deviceExtension
->WordsLeft
;
3776 // IDE path. Check if words left is at least 256.
3779 if (deviceExtension
->WordsLeft
< wordsThisInterrupt
) {
3782 // Transfer only words requested.
3785 wordCount
= deviceExtension
->WordsLeft
;
3790 // Transfer next block.
3793 wordCount
= wordsThisInterrupt
;
3798 // Ensure that this is a write command.
3801 if (srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
) {
3804 "AtapiInterrupt: Write interrupt\n"));
3806 WaitOnBusy(baseIoAddress2
,statusByte
);
3808 if (atapiDev
|| !deviceExtension
->DWordIO
) {
3810 WriteBuffer(baseIoAddress1
,
3811 deviceExtension
->DataBuffer
,
3815 PIDE_REGISTERS_3 address3
= (PIDE_REGISTERS_3
)baseIoAddress1
;
3817 WriteBuffer2(address3
,
3818 (PULONG
)(deviceExtension
->DataBuffer
),
3824 "AtapiInterrupt: Int reason %x, but srb is for a write %x.\n",
3829 // Fail this request.
3832 status
= SRB_STATUS_ERROR
;
3833 goto CompleteRequest
;
3838 // Advance data buffer pointer and bytes left.
3841 deviceExtension
->DataBuffer
+= wordCount
;
3842 deviceExtension
->WordsLeft
-= wordCount
;
3846 } else if (interruptReason
== 0x2 && (statusByte
& IDE_STATUS_DRQ
)) {
3849 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3852 // Pick up bytes to transfer and convert to words.
3856 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountLow
);
3859 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountHigh
) << 8;
3862 // Covert bytes to words.
3867 if (wordCount
!= deviceExtension
->WordsLeft
) {
3869 "AtapiInterrupt: %d words requested; %d words xferred\n",
3870 deviceExtension
->WordsLeft
,
3875 // Verify this makes sense.
3878 if (wordCount
> deviceExtension
->WordsLeft
) {
3879 wordCount
= deviceExtension
->WordsLeft
;
3885 // Check if words left is at least 256.
3888 if (deviceExtension
->WordsLeft
< wordsThisInterrupt
) {
3891 // Transfer only words requested.
3894 wordCount
= deviceExtension
->WordsLeft
;
3899 // Transfer next block.
3902 wordCount
= wordsThisInterrupt
;
3907 // Ensure that this is a read command.
3910 if (srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) {
3913 "AtapiInterrupt: Read interrupt\n"));
3915 WaitOnBusy(baseIoAddress2
,statusByte
);
3917 if (atapiDev
|| !deviceExtension
->DWordIO
) {
3918 ReadBuffer(baseIoAddress1
,
3919 deviceExtension
->DataBuffer
,
3923 PIDE_REGISTERS_3 address3
= (PIDE_REGISTERS_3
)baseIoAddress1
;
3925 ReadBuffer2(address3
,
3926 (PULONG
)(deviceExtension
->DataBuffer
),
3932 "AtapiInterrupt: Int reason %x, but srb is for a read %x.\n",
3937 // Fail this request.
3940 status
= SRB_STATUS_ERROR
;
3941 goto CompleteRequest
;
3945 // Translate ATAPI data back to SCSI data if needed
3948 if (srb
->Cdb
[0] == ATAPI_MODE_SENSE
&&
3949 deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3952 //convert and adjust the wordCount
3955 wordCount
-= Atapi2Scsi(srb
, (char *)deviceExtension
->DataBuffer
,
3959 // Advance data buffer pointer and bytes left.
3962 deviceExtension
->DataBuffer
+= wordCount
;
3963 deviceExtension
->WordsLeft
-= wordCount
;
3966 // Check for read command complete.
3969 if (deviceExtension
->WordsLeft
== 0) {
3971 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3974 // Work around to make many atapi devices return correct sector size
3975 // of 2048. Also certain devices will have sector count == 0x00, check
3979 if ((srb
->Cdb
[0] == 0x25) &&
3980 ((deviceExtension
->IdentifyData
[srb
->TargetId
].GeneralConfiguration
>> 8) & 0x1f) == 0x05) {
3982 deviceExtension
->DataBuffer
-= wordCount
;
3983 if (deviceExtension
->DataBuffer
[0] == 0x00) {
3985 *((ULONG
*) &(deviceExtension
->DataBuffer
[0])) = 0xFFFFFF7F;
3989 *((ULONG
*) &(deviceExtension
->DataBuffer
[2])) = 0x00080000;
3990 deviceExtension
->DataBuffer
+= wordCount
;
3995 // Completion for IDE drives.
3999 if (deviceExtension
->WordsLeft
) {
4001 status
= SRB_STATUS_DATA_OVERRUN
;
4005 status
= SRB_STATUS_SUCCESS
;
4009 goto CompleteRequest
;
4016 } else if (interruptReason
== 0x3 && !(statusByte
& IDE_STATUS_DRQ
)) {
4019 // Command complete.
4022 if (deviceExtension
->WordsLeft
) {
4024 status
= SRB_STATUS_DATA_OVERRUN
;
4028 status
= SRB_STATUS_SUCCESS
;
4035 // Check and see if we are processing our secret (mechanism status/request sense) srb
4037 if (deviceExtension
->OriginalSrb
) {
4041 if (srb
->Cdb
[0] == SCSIOP_MECHANISM_STATUS
) {
4043 if (status
== SRB_STATUS_SUCCESS
) {
4045 AtapiHwInitializeChanger (HwDeviceExtension
,
4047 (PMECHANICAL_STATUS_INFORMATION_HEADER
) srb
->DataBuffer
);
4049 // Get ready to issue the original srb
4050 srb
= deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
4051 deviceExtension
->OriginalSrb
= NULL
;
4054 // failed! Get the sense key and maybe try again
4055 srb
= deviceExtension
->CurrentSrb
= BuildRequestSenseSrb (
4057 deviceExtension
->OriginalSrb
->PathId
,
4058 deviceExtension
->OriginalSrb
->TargetId
);
4061 srbStatus
= AtapiSendCommand(HwDeviceExtension
, deviceExtension
->CurrentSrb
);
4062 if (srbStatus
== SRB_STATUS_PENDING
) {
4066 } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
4068 PSENSE_DATA senseData
= (PSENSE_DATA
) srb
->DataBuffer
;
4070 if (status
== SRB_STATUS_DATA_OVERRUN
) {
4071 // Check to see if we at least get minimum number of bytes
4072 if ((srb
->DataTransferLength
- deviceExtension
->WordsLeft
) >
4073 (FIELD_OFFSET (SENSE_DATA
, AdditionalSenseLength
) + sizeof(senseData
->AdditionalSenseLength
))) {
4074 status
= SRB_STATUS_SUCCESS
;
4078 if (status
== SRB_STATUS_SUCCESS
) {
4079 if ((senseData
->SenseKey
!= SCSI_SENSE_ILLEGAL_REQUEST
) &&
4080 deviceExtension
->MechStatusRetryCount
) {
4082 // The sense key doesn't say the last request is illegal, so try again
4083 deviceExtension
->MechStatusRetryCount
--;
4084 srb
= deviceExtension
->CurrentSrb
= BuildMechanismStatusSrb (
4086 deviceExtension
->OriginalSrb
->PathId
,
4087 deviceExtension
->OriginalSrb
->TargetId
);
4090 // last request was illegal. No point trying again
4092 AtapiHwInitializeChanger (HwDeviceExtension
,
4094 (PMECHANICAL_STATUS_INFORMATION_HEADER
) NULL
);
4096 // Get ready to issue the original srb
4097 srb
= deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
4098 deviceExtension
->OriginalSrb
= NULL
;
4101 srbStatus
= AtapiSendCommand(HwDeviceExtension
, deviceExtension
->CurrentSrb
);
4102 if (srbStatus
== SRB_STATUS_PENDING
) {
4108 // If we get here, it means AtapiSendCommand() has failed
4109 // Can't recover. Pretend the original srb has failed and complete it.
4111 if (deviceExtension
->OriginalSrb
) {
4112 AtapiHwInitializeChanger (HwDeviceExtension
,
4114 (PMECHANICAL_STATUS_INFORMATION_HEADER
) NULL
);
4115 srb
= deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
4116 deviceExtension
->OriginalSrb
= NULL
;
4119 // fake an error and read no data
4120 status
= SRB_STATUS_ERROR
;
4121 srb
->ScsiStatus
= 0;
4122 deviceExtension
->DataBuffer
= srb
->DataBuffer
;
4123 deviceExtension
->WordsLeft
= srb
->DataTransferLength
;
4124 deviceExtension
->RDP
= FALSE
;
4126 } else if (status
== SRB_STATUS_ERROR
) {
4129 // Map error to specific SRB status and handle request sense.
4132 status
= MapError(deviceExtension
,
4135 deviceExtension
->RDP
= FALSE
;
4140 // Wait for busy to drop.
4143 for (i
= 0; i
< 30; i
++) {
4144 GetStatus(baseIoAddress2
,statusByte
);
4145 if (!(statusByte
& IDE_STATUS_BUSY
)) {
4148 ScsiPortStallExecution(500);
4154 // reset the controller.
4158 "AtapiInterrupt: Resetting due to BSY still up - %x. Base Io %x\n",
4161 AtapiResetController(HwDeviceExtension
,srb
->PathId
);
4166 // Check to see if DRQ is still up.
4169 if (statusByte
& IDE_STATUS_DRQ
) {
4171 for (i
= 0; i
< 500; i
++) {
4172 GetStatus(baseIoAddress2
,statusByte
);
4173 if (!(statusByte
& IDE_STATUS_DRQ
)) {
4176 ScsiPortStallExecution(100);
4183 // reset the controller.
4187 "AtapiInterrupt: Resetting due to DRQ still up - %x\n",
4189 AtapiResetController(HwDeviceExtension
,srb
->PathId
);
4198 // Clear interrupt expecting flag.
4201 deviceExtension
->ExpectingInterrupt
= FALSE
;
4204 // Sanity check that there is a current request.
4210 // Set status in SRB.
4213 srb
->SrbStatus
= (UCHAR
)status
;
4216 // Check for underflow.
4219 if (deviceExtension
->WordsLeft
) {
4222 // Subtract out residual words and update if filemark hit,
4223 // setmark hit , end of data, end of media...
4226 if (!(deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_TAPE_DEVICE
)) {
4227 if (status
== SRB_STATUS_DATA_OVERRUN
) {
4228 srb
->DataTransferLength
-= deviceExtension
->WordsLeft
;
4230 srb
->DataTransferLength
= 0;
4233 srb
->DataTransferLength
-= deviceExtension
->WordsLeft
;
4237 if (srb
->Function
!= SRB_FUNCTION_IO_CONTROL
) {
4240 // Indicate command complete.
4243 if (!(deviceExtension
->RDP
)) {
4244 ScsiPortNotification(RequestComplete
,
4251 PSENDCMDOUTPARAMS cmdOutParameters
= (PSENDCMDOUTPARAMS
)(((PUCHAR
)srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
4254 if (status
!= SRB_STATUS_SUCCESS
) {
4255 error
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
4259 // Build the SMART status block depending upon the completion status.
4262 cmdOutParameters
->cBufferSize
= wordCount
;
4263 cmdOutParameters
->DriverStatus
.bDriverError
= (error
) ? SMART_IDE_ERROR
: 0;
4264 cmdOutParameters
->DriverStatus
.bIDEError
= error
;
4267 // If the sub-command is return smart status, jam the value from cylinder low and high, into the
4271 if (deviceExtension
->SmartCommand
== RETURN_SMART_STATUS
) {
4272 cmdOutParameters
->bBuffer
[0] = RETURN_SMART_STATUS
;
4273 cmdOutParameters
->bBuffer
[1] = ScsiPortReadPortUchar(&baseIoAddress1
->InterruptReason
);
4274 cmdOutParameters
->bBuffer
[2] = ScsiPortReadPortUchar(&baseIoAddress1
->Unused1
);
4275 cmdOutParameters
->bBuffer
[3] = ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountLow
);
4276 cmdOutParameters
->bBuffer
[4] = ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountHigh
);
4277 cmdOutParameters
->bBuffer
[5] = ScsiPortReadPortUchar(&baseIoAddress1
->DriveSelect
);
4278 cmdOutParameters
->bBuffer
[6] = SMART_CMD
;
4279 cmdOutParameters
->cBufferSize
= 8;
4283 // Indicate command complete.
4286 ScsiPortNotification(RequestComplete
,
4295 "AtapiInterrupt: No SRB!\n"));
4299 // Indicate ready for next request.
4302 if (!(deviceExtension
->RDP
)) {
4305 // Clear current SRB.
4308 deviceExtension
->CurrentSrb
= NULL
;
4310 ScsiPortNotification(NextRequest
,
4315 ScsiPortNotification(RequestTimerCall
,
4330 "AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n",
4338 } // end AtapiInterrupt()
4343 IdeSendSmartCommand(
4344 IN PVOID HwDeviceExtension
,
4345 IN PSCSI_REQUEST_BLOCK Srb
4350 Routine Description:
4352 This routine handles SMART enable, disable, read attributes and threshold commands.
4356 HwDeviceExtension - HBA miniport driver's adapter data storage
4357 Srb - IO request packet
4366 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
4367 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
4368 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
4369 PSENDCMDOUTPARAMS cmdOutParameters
= (PSENDCMDOUTPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
4370 SENDCMDINPARAMS cmdInParameters
= *(PSENDCMDINPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
4371 PIDEREGS regs
= &cmdInParameters
.irDriveRegs
;
4373 UCHAR statusByte
,targetId
;
4376 if (cmdInParameters
.irDriveRegs
.bCommandReg
== SMART_CMD
) {
4378 targetId
= cmdInParameters
.bDriveNumber
;
4380 //TODO optimize this check
4382 if ((!(deviceExtension
->DeviceFlags
[targetId
] & DFLAGS_DEVICE_PRESENT
)) ||
4383 (deviceExtension
->DeviceFlags
[targetId
] & DFLAGS_ATAPI_DEVICE
)) {
4385 return SRB_STATUS_SELECTION_TIMEOUT
;
4388 deviceExtension
->SmartCommand
= cmdInParameters
.irDriveRegs
.bFeaturesReg
;
4391 // Determine which of the commands to carry out.
4394 if ((cmdInParameters
.irDriveRegs
.bFeaturesReg
== READ_ATTRIBUTES
) ||
4395 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== READ_THRESHOLDS
)) {
4397 WaitOnBusy(baseIoAddress2
,statusByte
);
4399 if (statusByte
& IDE_STATUS_BUSY
) {
4401 "IdeSendSmartCommand: Returning BUSY status\n"));
4402 return SRB_STATUS_BUSY
;
4406 // Zero the output buffer as the input buffer info. has been saved off locally (the buffers are the same).
4409 for (i
= 0; i
< (sizeof(SENDCMDOUTPARAMS
) + READ_ATTRIBUTE_BUFFER_SIZE
- 1); i
++) {
4410 ((PUCHAR
)cmdOutParameters
)[i
] = 0;
4414 // Set data buffer pointer and words left.
4417 deviceExtension
->DataBuffer
= (PUSHORT
)cmdOutParameters
->bBuffer
;
4418 deviceExtension
->WordsLeft
= READ_ATTRIBUTE_BUFFER_SIZE
/ 2;
4421 // Indicate expecting an interrupt.
4424 deviceExtension
->ExpectingInterrupt
= TRUE
;
4426 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,(UCHAR
)(((targetId
& 0x1) << 4) | 0xA0));
4427 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress1
+ 1,regs
->bFeaturesReg
);
4428 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,regs
->bSectorCountReg
);
4429 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,regs
->bSectorNumberReg
);
4430 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,regs
->bCylLowReg
);
4431 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,regs
->bCylHighReg
);
4432 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,regs
->bCommandReg
);
4435 // Wait for interrupt.
4438 return SRB_STATUS_PENDING
;
4440 } else if ((cmdInParameters
.irDriveRegs
.bFeaturesReg
== ENABLE_SMART
) ||
4441 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== DISABLE_SMART
) ||
4442 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) ||
4443 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== ENABLE_DISABLE_AUTOSAVE
) ||
4444 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== EXECUTE_OFFLINE_DIAGS
) ||
4445 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== SAVE_ATTRIBUTE_VALUES
)) {
4447 WaitOnBusy(baseIoAddress2
,statusByte
);
4449 if (statusByte
& IDE_STATUS_BUSY
) {
4451 "IdeSendSmartCommand: Returning BUSY status\n"));
4452 return SRB_STATUS_BUSY
;
4456 // Zero the output buffer as the input buffer info. has been saved off locally (the buffers are the same).
4459 for (i
= 0; i
< (sizeof(SENDCMDOUTPARAMS
) - 1); i
++) {
4460 ((PUCHAR
)cmdOutParameters
)[i
] = 0;
4464 // Set data buffer pointer and indicate no data transfer.
4467 deviceExtension
->DataBuffer
= (PUSHORT
)cmdOutParameters
->bBuffer
;
4468 deviceExtension
->WordsLeft
= 0;
4471 // Indicate expecting an interrupt.
4474 deviceExtension
->ExpectingInterrupt
= TRUE
;
4476 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,(UCHAR
)(((targetId
& 0x1) << 4) | 0xA0));
4477 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress1
+ 1,regs
->bFeaturesReg
);
4478 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,regs
->bSectorCountReg
);
4479 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,regs
->bSectorNumberReg
);
4480 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,regs
->bCylLowReg
);
4481 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,regs
->bCylHighReg
);
4482 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,regs
->bCommandReg
);
4485 // Wait for interrupt.
4488 return SRB_STATUS_PENDING
;
4492 return SRB_STATUS_INVALID_REQUEST
;
4494 } // end IdeSendSmartCommand()
4500 IN PVOID HwDeviceExtension
,
4501 IN PSCSI_REQUEST_BLOCK Srb
4506 Routine Description:
4508 This routine handles IDE read and writes.
4512 HwDeviceExtension - HBA miniport driver's adapter data storage
4513 Srb - IO request packet
4522 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
4523 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
4524 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
4525 ULONG startingSector
,i
;
4527 UCHAR statusByte
,statusByte2
;
4528 UCHAR cylinderHigh
,cylinderLow
,drvSelect
,sectorNumber
;
4531 // Select device 0 or 1.
4534 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
4535 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
4537 WaitOnBusy(baseIoAddress2
,statusByte2
);
4539 if (statusByte2
& IDE_STATUS_BUSY
) {
4541 "IdeReadWrite: Returning BUSY status\n"));
4542 return SRB_STATUS_BUSY
;
4546 // Set data buffer pointer and words left.
4549 deviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
4550 deviceExtension
->WordsLeft
= Srb
->DataTransferLength
/ 2;
4553 // Indicate expecting an interrupt.
4556 deviceExtension
->ExpectingInterrupt
= TRUE
;
4559 // Set up sector count register. Round up to next block.
4562 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,
4563 (UCHAR
)((Srb
->DataTransferLength
+ 0x1FF) / 0x200));
4566 // Get starting sector number from CDB.
4569 startingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
4570 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
4571 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
4572 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
4575 "IdeReadWrite: Starting sector is %x, Number of bytes %x\n",
4577 Srb
->DataTransferLength
));
4580 // Set up sector number register.
4583 sectorNumber
= (UCHAR
)((startingSector
% deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) + 1);
4584 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,sectorNumber
);
4587 // Set up cylinder low register.
4590 cylinderLow
= (UCHAR
)(startingSector
/ (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4591 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
));
4592 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,cylinderLow
);
4595 // Set up cylinder high register.
4598 cylinderHigh
= (UCHAR
)((startingSector
/ (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4599 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
)) >> 8);
4600 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,cylinderHigh
);
4603 // Set up head and drive select register.
4606 drvSelect
= (UCHAR
)(((startingSector
/ deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4607 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
) |((Srb
->TargetId
& 0x1) << 4) | 0xA0);
4608 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,drvSelect
);
4611 "IdeReadWrite: Cylinder %x Head %x Sector %x\n",
4613 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4614 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
),
4616 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4617 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
,
4619 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
+ 1));
4622 // Check if write request.
4625 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) {
4628 // Send read command.
4631 if (deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
]) {
4632 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4633 IDE_COMMAND_READ_MULTIPLE
);
4636 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4643 // Send write command.
4646 if (deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
]) {
4647 wordCount
= 256 * deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
];
4649 if (deviceExtension
->WordsLeft
< wordCount
) {
4652 // Transfer only words requested.
4655 wordCount
= deviceExtension
->WordsLeft
;
4658 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4659 IDE_COMMAND_WRITE_MULTIPLE
);
4663 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4668 // Wait for BSY and DRQ.
4671 WaitOnBaseBusy(baseIoAddress1
,statusByte
);
4673 if (statusByte
& IDE_STATUS_BUSY
) {
4676 "IdeReadWrite 2: Returning BUSY status %x\n",
4678 return SRB_STATUS_BUSY
;
4681 for (i
= 0; i
< 1000; i
++) {
4682 GetBaseStatus(baseIoAddress1
, statusByte
);
4683 if (statusByte
& IDE_STATUS_DRQ
) {
4686 ScsiPortStallExecution(200);
4690 if (!(statusByte
& IDE_STATUS_DRQ
)) {
4693 "IdeReadWrite: DRQ never asserted (%x) original status (%x)\n",
4697 deviceExtension
->WordsLeft
= 0;
4700 // Clear interrupt expecting flag.
4703 deviceExtension
->ExpectingInterrupt
= FALSE
;
4706 // Clear current SRB.
4709 deviceExtension
->CurrentSrb
= NULL
;
4711 return SRB_STATUS_TIMEOUT
;
4715 // Write next 256 words.
4718 WriteBuffer(baseIoAddress1
,
4719 deviceExtension
->DataBuffer
,
4723 // Adjust buffer address and words left count.
4726 deviceExtension
->WordsLeft
-= wordCount
;
4727 deviceExtension
->DataBuffer
+= wordCount
;
4732 // Wait for interrupt.
4735 return SRB_STATUS_PENDING
;
4737 } // end IdeReadWrite()
4744 IN PVOID HwDeviceExtension
,
4745 IN PSCSI_REQUEST_BLOCK Srb
4750 Routine Description:
4752 This routine handles IDE Verify.
4756 HwDeviceExtension - HBA miniport driver's adapter data storage
4757 Srb - IO request packet
4766 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
4767 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
4768 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
4769 ULONG startingSector
;
4775 // Drive has these number sectors.
4778 sectors
= deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4779 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
*
4780 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfCylinders
;
4783 "IdeVerify: Total sectors %x\n",
4787 // Get starting sector number from CDB.
4790 startingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
4791 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
4792 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
4793 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
4796 "IdeVerify: Starting sector %x. Number of blocks %x\n",
4798 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
));
4800 sectorCount
= (USHORT
)(((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8 |
4801 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
);
4802 endSector
= startingSector
+ sectorCount
;
4805 "IdeVerify: Ending sector %x\n",
4808 if (endSector
> sectors
) {
4811 // Too big, round down.
4815 "IdeVerify: Truncating request to %x blocks\n",
4816 sectors
- startingSector
- 1));
4818 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,
4819 (UCHAR
)(sectors
- startingSector
- 1));
4824 // Set up sector count register. Round up to next block.
4827 if (sectorCount
> 0xFF) {
4828 sectorCount
= (USHORT
)0xFF;
4831 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,(UCHAR
)sectorCount
);
4835 // Set data buffer pointer and words left.
4838 deviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
4839 deviceExtension
->WordsLeft
= Srb
->DataTransferLength
/ 2;
4842 // Indicate expecting an interrupt.
4845 deviceExtension
->ExpectingInterrupt
= TRUE
;
4848 // Set up sector number register.
4851 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,
4852 (UCHAR
)((startingSector
%
4853 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) + 1));
4856 // Set up cylinder low register.
4859 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,
4860 (UCHAR
)(startingSector
/
4861 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4862 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
)));
4865 // Set up cylinder high register.
4868 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,
4869 (UCHAR
)((startingSector
/
4870 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4871 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
)) >> 8));
4874 // Set up head and drive select register.
4877 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
4878 (UCHAR
)(((startingSector
/
4879 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4880 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
) |
4881 ((Srb
->TargetId
& 0x1) << 4) | 0xA0));
4884 "IdeVerify: Cylinder %x Head %x Sector %x\n",
4886 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4887 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
),
4889 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4890 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
,
4892 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
+ 1));
4896 // Send verify command.
4899 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4900 IDE_COMMAND_VERIFY
);
4903 // Wait for interrupt.
4906 return SRB_STATUS_PENDING
;
4908 } // end IdeVerify()
4914 IN PSCSI_REQUEST_BLOCK Srb
4919 Routine Description:
4921 Convert SCSI packet command to Atapi packet command.
4925 Srb - IO request packet
4934 // Change the cdb length
4937 Srb
->CdbLength
= 12;
4939 switch (Srb
->Cdb
[0]) {
4940 case SCSIOP_MODE_SENSE
: {
4941 PMODE_SENSE_10 modeSense10
= (PMODE_SENSE_10
)Srb
->Cdb
;
4942 UCHAR PageCode
= ((PCDB
)Srb
->Cdb
)->MODE_SENSE
.PageCode
;
4943 UCHAR Length
= ((PCDB
)Srb
->Cdb
)->MODE_SENSE
.AllocationLength
;
4945 AtapiZeroMemory(Srb
->Cdb
,MAXIMUM_CDB_SIZE
);
4947 modeSense10
->OperationCode
= ATAPI_MODE_SENSE
;
4948 modeSense10
->PageCode
= PageCode
;
4949 modeSense10
->ParameterListLengthMsb
= 0;
4950 modeSense10
->ParameterListLengthLsb
= Length
;
4954 case SCSIOP_MODE_SELECT
: {
4955 PMODE_SELECT_10 modeSelect10
= (PMODE_SELECT_10
)Srb
->Cdb
;
4956 UCHAR Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
4959 // Zero the original cdb
4962 AtapiZeroMemory(Srb
->Cdb
,MAXIMUM_CDB_SIZE
);
4964 modeSelect10
->OperationCode
= ATAPI_MODE_SELECT
;
4965 modeSelect10
->PFBit
= 1;
4966 modeSelect10
->ParameterListLengthMsb
= 0;
4967 modeSelect10
->ParameterListLengthLsb
= Length
;
4971 case SCSIOP_FORMAT_UNIT
:
4972 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
4982 IN PVOID HwDeviceExtension
,
4983 IN PSCSI_REQUEST_BLOCK Srb
4988 Routine Description:
4990 Send ATAPI packet command to device.
4994 HwDeviceExtension - HBA miniport driver's adapter data storage
4995 Srb - IO request packet
5003 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5004 PATAPI_REGISTERS_1 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
5005 PATAPI_REGISTERS_2 baseIoAddress2
= (PATAPI_REGISTERS_2
)deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
5008 UCHAR statusByte
,byteCountLow
,byteCountHigh
;
5011 // We need to know how many platters our atapi cd-rom device might have.
5012 // Before anyone tries to send a srb to our target for the first time,
5013 // we must "secretly" send down a separate mechanism status srb in order to
5014 // initialize our device extension changer data. That's how we know how
5015 // many platters our target has.
5017 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_CHANGER_INITED
) &&
5018 !deviceExtension
->OriginalSrb
) {
5023 // Set this flag now. If the device hangs on the mech. status
5024 // command, we will not have the change to set it.
5026 deviceExtension
->DeviceFlags
[Srb
->TargetId
] |= DFLAGS_CHANGER_INITED
;
5028 deviceExtension
->MechStatusRetryCount
= 3;
5029 deviceExtension
->CurrentSrb
= BuildMechanismStatusSrb (
5033 deviceExtension
->OriginalSrb
= Srb
;
5035 srbStatus
= AtapiSendCommand(HwDeviceExtension
, deviceExtension
->CurrentSrb
);
5036 if (srbStatus
== SRB_STATUS_PENDING
) {
5039 deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
5040 deviceExtension
->OriginalSrb
= NULL
;
5041 AtapiHwInitializeChanger (HwDeviceExtension
,
5043 (PMECHANICAL_STATUS_INFORMATION_HEADER
) NULL
);
5049 "AtapiSendCommand: Command %x to TargetId %d lun %d\n",
5055 // Make sure command is to ATAPI device.
5058 flags
= deviceExtension
->DeviceFlags
[Srb
->TargetId
];
5059 if (flags
& (DFLAGS_SANYO_ATAPI_CHANGER
| DFLAGS_ATAPI_CHANGER
)) {
5060 if ((Srb
->Lun
) > (deviceExtension
->DiscsPresent
[Srb
->TargetId
] - 1)) {
5063 // Indicate no device found at this address.
5066 return SRB_STATUS_SELECTION_TIMEOUT
;
5068 } else if (Srb
->Lun
> 0) {
5069 return SRB_STATUS_SELECTION_TIMEOUT
;
5072 if (!(flags
& DFLAGS_ATAPI_DEVICE
)) {
5073 return SRB_STATUS_SELECTION_TIMEOUT
;
5077 // Select device 0 or 1.
5080 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5081 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5084 // Verify that controller is ready for next command.
5087 GetStatus(baseIoAddress2
,statusByte
);
5090 "AtapiSendCommand: Entered with status %x\n",
5093 if (statusByte
& IDE_STATUS_BUSY
) {
5095 "AtapiSendCommand: Device busy (%x)\n",
5097 return SRB_STATUS_BUSY
;
5101 if (statusByte
& IDE_STATUS_ERROR
) {
5102 if (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
) {
5105 "AtapiSendCommand: Error on entry: (%x)\n",
5108 // Read the error reg. to clear it and fail this request.
5111 return MapError(deviceExtension
,
5117 // If a tape drive has doesn't have DSC set and the last command is restrictive, don't send
5118 // the next command. See discussion of Restrictive Delayed Process commands in QIC-157.
5121 if ((!(statusByte
& IDE_STATUS_DSC
)) &&
5122 (flags
& DFLAGS_TAPE_DEVICE
) && deviceExtension
->RDP
) {
5123 ScsiPortStallExecution(1000);
5124 DebugPrint((2,"AtapiSendCommand: DSC not set. %x\n",statusByte
));
5125 return SRB_STATUS_BUSY
;
5128 if (IS_RDP(Srb
->Cdb
[0])) {
5130 deviceExtension
->RDP
= TRUE
;
5133 "AtapiSendCommand: %x mapped as DSC restrictive\n",
5138 deviceExtension
->RDP
= FALSE
;
5141 if (statusByte
& IDE_STATUS_DRQ
) {
5144 "AtapiSendCommand: Entered with status (%x). Attempting to recover.\n",
5147 // Try to drain the data that one preliminary device thinks that it has
5148 // to transfer. Hopefully this random assertion of DRQ will not be present
5149 // in production devices.
5152 for (i
= 0; i
< 0x10000; i
++) {
5154 GetStatus(baseIoAddress2
, statusByte
);
5156 if (statusByte
& IDE_STATUS_DRQ
) {
5158 ScsiPortReadPortUshort(&baseIoAddress1
->Data
);
5169 "AtapiSendCommand: DRQ still asserted.Status (%x)\n",
5172 AtapiSoftReset(baseIoAddress1
,Srb
->TargetId
);
5175 "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
5178 // Re-initialize Atapi device.
5181 IssueIdentify(HwDeviceExtension
,
5182 (Srb
->TargetId
& 0x1),
5183 (Srb
->TargetId
>> 1),
5184 IDE_COMMAND_ATAPI_IDENTIFY
);
5187 // Inform the port driver that the bus has been reset.
5190 ScsiPortNotification(ResetDetected
, HwDeviceExtension
, 0);
5193 // Clean up device extension fields that AtapiStartIo won't.
5196 deviceExtension
->ExpectingInterrupt
= FALSE
;
5197 deviceExtension
->RDP
= FALSE
;
5199 return SRB_STATUS_BUS_RESET
;
5204 if (flags
& (DFLAGS_SANYO_ATAPI_CHANGER
| DFLAGS_ATAPI_CHANGER
)) {
5207 // As the cdrom driver sets the LUN field in the cdb, it must be removed.
5210 Srb
->Cdb
[1] &= ~0xE0;
5212 if ((Srb
->Cdb
[0] == SCSIOP_TEST_UNIT_READY
) && (flags
& DFLAGS_SANYO_ATAPI_CHANGER
)) {
5215 // Torisan changer. TUR's are overloaded to be platter switches.
5218 Srb
->Cdb
[7] = Srb
->Lun
;
5224 // Convert SCSI to ATAPI commands if needed
5227 switch (Srb
->Cdb
[0]) {
5228 case SCSIOP_MODE_SENSE
:
5229 case SCSIOP_MODE_SELECT
:
5230 case SCSIOP_FORMAT_UNIT
:
5231 if (!(flags
& DFLAGS_TAPE_DEVICE
)) {
5239 // Set data buffer pointer and words left.
5242 deviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
5243 deviceExtension
->WordsLeft
= Srb
->DataTransferLength
/ 2;
5245 WaitOnBusy(baseIoAddress2
,statusByte
);
5248 // Write transfer byte count to registers.
5251 byteCountLow
= (UCHAR
)(Srb
->DataTransferLength
& 0xFF);
5252 byteCountHigh
= (UCHAR
)(Srb
->DataTransferLength
>> 8);
5254 if (Srb
->DataTransferLength
>= 0x10000) {
5255 byteCountLow
= byteCountHigh
= 0xFF;
5258 ScsiPortWritePortUchar(&baseIoAddress1
->ByteCountLow
,byteCountLow
);
5259 ScsiPortWritePortUchar(&baseIoAddress1
->ByteCountHigh
, byteCountHigh
);
5261 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress1
+ 1,0);
5264 if (flags
& DFLAGS_INT_DRQ
) {
5267 // This device interrupts when ready to receive the packet.
5269 // Write ATAPI packet command.
5272 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
5273 IDE_COMMAND_ATAPI_PACKET
);
5276 "AtapiSendCommand: Wait for int. to send packet. Status (%x)\n",
5279 deviceExtension
->ExpectingInterrupt
= TRUE
;
5281 return SRB_STATUS_PENDING
;
5286 // Write ATAPI packet command.
5289 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
5290 IDE_COMMAND_ATAPI_PACKET
);
5296 WaitOnBusy(baseIoAddress2
, statusByte
);
5297 WaitForDrq(baseIoAddress2
, statusByte
);
5299 if (!(statusByte
& IDE_STATUS_DRQ
)) {
5302 "AtapiSendCommand: DRQ never asserted (%x)\n",
5304 return SRB_STATUS_ERROR
;
5309 // Need to read status register.
5312 GetBaseStatus(baseIoAddress1
, statusByte
);
5315 // Send CDB to device.
5318 WaitOnBusy(baseIoAddress2
,statusByte
);
5320 WriteBuffer(baseIoAddress1
,
5325 // Indicate expecting an interrupt and wait for it.
5328 deviceExtension
->ExpectingInterrupt
= TRUE
;
5330 return SRB_STATUS_PENDING
;
5332 } // end AtapiSendCommand()
5337 IN PVOID HwDeviceExtension
,
5338 IN PSCSI_REQUEST_BLOCK Srb
5343 Routine Description:
5345 Program ATA registers for IDE disk transfer.
5349 HwDeviceExtension - ATAPI driver storage.
5350 Srb - System request block.
5354 SRB status (pending if all goes well).
5359 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5360 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
5361 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
5364 UCHAR statusByte
,errorByte
;
5367 PMODE_PARAMETER_HEADER modeData
;
5370 "IdeSendCommand: Command %x to device %d\n",
5376 switch (Srb
->Cdb
[0]) {
5377 case SCSIOP_INQUIRY
:
5380 // Filter out all TIDs but 0 and 1 since this is an IDE interface
5381 // which support up to two devices.
5384 if ((Srb
->Lun
!= 0) ||
5385 (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
))) {
5388 // Indicate no device found at this address.
5391 status
= SRB_STATUS_SELECTION_TIMEOUT
;
5396 PINQUIRYDATA inquiryData
= Srb
->DataBuffer
;
5397 PIDENTIFY_DATA2 identifyData
= &deviceExtension
->IdentifyData
[Srb
->TargetId
];
5400 // Zero INQUIRY data structure.
5403 for (i
= 0; i
< Srb
->DataTransferLength
; i
++) {
5404 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
5408 // Standard IDE interface only supports disks.
5411 inquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
5414 // Set the removable bit, if applicable.
5417 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_REMOVABLE_DRIVE
) {
5418 inquiryData
->RemovableMedia
= 1;
5422 // Fill in vendor identification fields.
5425 for (i
= 0; i
< 8; i
+= 2) {
5426 inquiryData
->VendorId
[i
] =
5427 ((PUCHAR
)identifyData
->ModelNumber
)[i
+ 1];
5428 inquiryData
->VendorId
[i
+1] =
5429 ((PUCHAR
)identifyData
->ModelNumber
)[i
];
5432 for (i
= 0; i
< 12; i
+= 2) {
5433 inquiryData
->ProductId
[i
] =
5434 ((PUCHAR
)identifyData
->ModelNumber
)[i
+ 8 + 1];
5435 inquiryData
->ProductId
[i
+1] =
5436 ((PUCHAR
)identifyData
->ModelNumber
)[i
+ 8];
5440 // Initialize unused portion of product id.
5443 for (i
= 0; i
< 4; i
++) {
5444 inquiryData
->ProductId
[12+i
] = ' ';
5448 // Move firmware revision from IDENTIFY data to
5449 // product revision in INQUIRY data.
5452 for (i
= 0; i
< 4; i
+= 2) {
5453 inquiryData
->ProductRevisionLevel
[i
] =
5454 ((PUCHAR
)identifyData
->FirmwareRevision
)[i
+1];
5455 inquiryData
->ProductRevisionLevel
[i
+1] =
5456 ((PUCHAR
)identifyData
->FirmwareRevision
)[i
];
5459 status
= SRB_STATUS_SUCCESS
;
5464 case SCSIOP_MODE_SENSE
:
5467 // This is used to determine of the media is write-protected.
5468 // Since IDE does not support mode sense then we will modify just the portion we need
5469 // so the higher level driver can determine if media is protected.
5472 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
) {
5474 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5475 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5476 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,IDE_COMMAND_GET_MEDIA_STATUS
);
5477 WaitOnBusy(baseIoAddress2
,statusByte
);
5479 if (!(statusByte
& IDE_STATUS_ERROR
)){
5482 // no error occured return success, media is not protected
5485 deviceExtension
->ExpectingInterrupt
= FALSE
;
5490 // error occured, handle it locally, clear interrupt
5493 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
5495 GetBaseStatus(baseIoAddress1
, statusByte
);
5496 deviceExtension
->ExpectingInterrupt
= FALSE
;
5498 if (errorByte
& IDE_ERROR_DATA_ERROR
) {
5501 //media is write-protected, set bit in mode sense buffer
5504 modeData
= (PMODE_PARAMETER_HEADER
)Srb
->DataBuffer
;
5506 Srb
->DataTransferLength
= sizeof(MODE_PARAMETER_HEADER
);
5507 modeData
->DeviceSpecificParameter
|= MODE_DSP_WRITE_PROTECT
;
5510 status
= SRB_STATUS_SUCCESS
;
5512 status
= SRB_STATUS_INVALID_REQUEST
;
5516 case SCSIOP_TEST_UNIT_READY
:
5518 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
) {
5521 // Select device 0 or 1.
5524 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5525 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5526 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,IDE_COMMAND_GET_MEDIA_STATUS
);
5529 // Wait for busy. If media has not changed, return success
5532 WaitOnBusy(baseIoAddress2
,statusByte
);
5534 if (!(statusByte
& IDE_STATUS_ERROR
)){
5535 deviceExtension
->ExpectingInterrupt
= FALSE
;
5536 status
= SRB_STATUS_SUCCESS
;
5538 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
5539 if (errorByte
== IDE_ERROR_DATA_ERROR
){
5542 // Special case: If current media is write-protected,
5543 // the 0xDA command will always fail since the write-protect bit
5544 // is sticky,so we can ignore this error
5547 GetBaseStatus(baseIoAddress1
, statusByte
);
5548 deviceExtension
->ExpectingInterrupt
= FALSE
;
5549 status
= SRB_STATUS_SUCCESS
;
5554 // Request sense buffer to be build
5556 deviceExtension
->ExpectingInterrupt
= TRUE
;
5557 status
= SRB_STATUS_PENDING
;
5561 status
= SRB_STATUS_SUCCESS
;
5566 case SCSIOP_READ_CAPACITY
:
5569 // Claim 512 byte blocks (big-endian).
5572 ((PREAD_CAPACITY_DATA
)Srb
->DataBuffer
)->BytesPerBlock
= 0x20000;
5575 // Calculate last sector.
5579 i
= (deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
*
5580 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfCylinders
*
5581 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) - 1;
5583 ((PREAD_CAPACITY_DATA
)Srb
->DataBuffer
)->LogicalBlockAddress
=
5584 (((PUCHAR
)&i
)[0] << 24) | (((PUCHAR
)&i
)[1] << 16) |
5585 (((PUCHAR
)&i
)[2] << 8) | ((PUCHAR
)&i
)[3];
5588 "IDE disk %x - #sectors %x, #heads %x, #cylinders %x\n",
5590 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
,
5591 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
,
5592 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfCylinders
));
5595 status
= SRB_STATUS_SUCCESS
;
5599 status
= IdeVerify(HwDeviceExtension
,Srb
);
5606 status
= IdeReadWrite(HwDeviceExtension
,
5610 case SCSIOP_START_STOP_UNIT
:
5613 //Determine what type of operation we should perform
5615 cdb
= (PCDB
)Srb
->Cdb
;
5617 if (cdb
->START_STOP
.LoadEject
== 1){
5621 // first select device 0 or 1.
5623 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5624 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5625 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,IDE_COMMAND_MEDIA_EJECT
);
5627 status
= SRB_STATUS_SUCCESS
;
5630 case SCSIOP_REQUEST_SENSE
:
5631 // this function makes sense buffers to report the results
5632 // of the original GET_MEDIA_STATUS command
5634 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
) {
5635 status
= IdeBuildSenseBuffer(HwDeviceExtension
,Srb
);
5642 "IdeSendCommand: Unsupported command %x\n",
5645 status
= SRB_STATUS_INVALID_REQUEST
;
5651 } // end IdeSendCommand()
5657 IN PVOID HwDeviceExtension
,
5662 Routine Description:
5664 Enables disables media status notification
5668 HwDeviceExtension - ATAPI driver storage.
5673 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5674 PIDE_REGISTERS_1 baseIoAddress
= deviceExtension
->BaseIoAddress1
[Channel
>> 1];
5675 UCHAR statusByte
,errorByte
;
5678 if (EnableMSN
== TRUE
){
5681 // If supported enable Media Status Notification support
5684 if ((deviceExtension
->DeviceFlags
[Channel
] & DFLAGS_REMOVABLE_DRIVE
)) {
5689 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress
+ 1,(UCHAR
) (0x95));
5690 ScsiPortWritePortUchar(&baseIoAddress
->Command
,
5691 IDE_COMMAND_ENABLE_MEDIA_STATUS
);
5693 WaitOnBaseBusy(baseIoAddress
,statusByte
);
5695 if (statusByte
& IDE_STATUS_ERROR
) {
5697 // Read the error register.
5699 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress
+ 1);
5702 "IdeMediaStatus: Error enabling media status. Status %x, error byte %x\n",
5706 deviceExtension
->DeviceFlags
[Channel
] |= DFLAGS_MEDIA_STATUS_ENABLED
;
5707 DebugPrint((1,"IdeMediaStatus: Media Status Notification Supported\n"));
5708 deviceExtension
->ReturningMediaStatus
= 0;
5713 } else { // end if EnableMSN == TRUE
5716 // disable if previously enabled
5718 if ((deviceExtension
->DeviceFlags
[Channel
] & DFLAGS_MEDIA_STATUS_ENABLED
)) {
5720 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress
+ 1,(UCHAR
) (0x31));
5721 ScsiPortWritePortUchar(&baseIoAddress
->Command
,
5722 IDE_COMMAND_ENABLE_MEDIA_STATUS
);
5724 WaitOnBaseBusy(baseIoAddress
,statusByte
);
5725 deviceExtension
->DeviceFlags
[Channel
] &= ~DFLAGS_MEDIA_STATUS_ENABLED
;
5737 IdeBuildSenseBuffer(
5738 IN PVOID HwDeviceExtension
,
5739 IN PSCSI_REQUEST_BLOCK Srb
5744 Routine Description:
5746 Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS
5747 command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE.
5750 HwDeviceExtension - ATAPI driver storage.
5751 Srb - System request block.
5755 SRB status (ALWAYS SUCCESS).
5760 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5761 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->DataBuffer
;
5767 if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_MEDIA_CHANGE
) {
5769 senseBuffer
->ErrorCode
= 0x70;
5770 senseBuffer
->Valid
= 1;
5771 senseBuffer
->AdditionalSenseLength
= 0xb;
5772 senseBuffer
->SenseKey
= SCSI_SENSE_UNIT_ATTENTION
;
5773 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_MEDIUM_CHANGED
;
5774 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5775 } else if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_MEDIA_CHANGE_REQ
) {
5777 senseBuffer
->ErrorCode
= 0x70;
5778 senseBuffer
->Valid
= 1;
5779 senseBuffer
->AdditionalSenseLength
= 0xb;
5780 senseBuffer
->SenseKey
= SCSI_SENSE_UNIT_ATTENTION
;
5781 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_MEDIUM_CHANGED
;
5782 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5783 } else if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_END_OF_MEDIA
) {
5785 senseBuffer
->ErrorCode
= 0x70;
5786 senseBuffer
->Valid
= 1;
5787 senseBuffer
->AdditionalSenseLength
= 0xb;
5788 senseBuffer
->SenseKey
= SCSI_SENSE_NOT_READY
;
5789 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
;
5790 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5791 } else if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_DATA_ERROR
) {
5793 senseBuffer
->ErrorCode
= 0x70;
5794 senseBuffer
->Valid
= 1;
5795 senseBuffer
->AdditionalSenseLength
= 0xb;
5796 senseBuffer
->SenseKey
= SCSI_SENSE_DATA_PROTECT
;
5797 senseBuffer
->AdditionalSenseCode
= 0;
5798 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5800 return SRB_STATUS_SUCCESS
;
5802 return SRB_STATUS_ERROR
;
5804 }// End of IdeBuildSenseBuffer
5812 IN PVOID HwDeviceExtension
,
5813 IN PSCSI_REQUEST_BLOCK Srb
5818 Routine Description:
5820 This routine is called from the SCSI port driver synchronized
5821 with the kernel to start an IO request.
5825 HwDeviceExtension - HBA miniport driver's adapter data storage
5826 Srb - IO request packet
5835 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5839 // Determine which function.
5842 switch (Srb
->Function
) {
5844 case SRB_FUNCTION_EXECUTE_SCSI
:
5847 // Sanity check. Only one request can be outstanding on a
5851 if (deviceExtension
->CurrentSrb
) {
5854 "AtapiStartIo: Already have a request!\n"));
5855 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
5856 ScsiPortNotification(RequestComplete
,
5863 // Indicate that a request is active on the controller.
5866 deviceExtension
->CurrentSrb
= Srb
;
5869 // Send command to device.
5872 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
5874 status
= AtapiSendCommand(HwDeviceExtension
,
5877 } else if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
) {
5879 status
= IdeSendCommand(HwDeviceExtension
,
5883 status
= SRB_STATUS_SELECTION_TIMEOUT
;
5888 case SRB_FUNCTION_ABORT_COMMAND
:
5891 // Verify that SRB to abort is still outstanding.
5894 if (!deviceExtension
->CurrentSrb
) {
5896 DebugPrint((1, "AtapiStartIo: SRB to abort already completed\n"));
5899 // Complete abort SRB.
5902 status
= SRB_STATUS_ABORT_FAILED
;
5908 // Abort function indicates that a request timed out.
5909 // Call reset routine. Card will only be reset if
5910 // status indicates something is wrong.
5911 // Fall through to reset code.
5914 case SRB_FUNCTION_RESET_BUS
:
5917 // Reset Atapi and SCSI bus.
5920 DebugPrint((1, "AtapiStartIo: Reset bus request received\n"));
5922 if (!AtapiResetController(deviceExtension
,
5925 DebugPrint((1,"AtapiStartIo: Reset bus failed\n"));
5928 // Log reset failure.
5937 SP_INTERNAL_ADAPTER_ERROR
,
5941 status
= SRB_STATUS_ERROR
;
5945 status
= SRB_STATUS_SUCCESS
;
5950 case SRB_FUNCTION_IO_CONTROL
:
5952 if (deviceExtension
->CurrentSrb
) {
5955 "AtapiStartIo: Already have a request!\n"));
5956 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
5957 ScsiPortNotification(RequestComplete
,
5964 // Indicate that a request is active on the controller.
5967 deviceExtension
->CurrentSrb
= Srb
;
5969 if (AtapiStringCmp( (PCHAR
)((PSRB_IO_CONTROL
)(Srb
->DataBuffer
))->Signature
,"SCSIDISK",strlen("SCSIDISK"))) {
5972 "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s\n",
5973 ((PSRB_IO_CONTROL
)(Srb
->DataBuffer
))->Signature
,
5976 status
= SRB_STATUS_INVALID_REQUEST
;
5980 switch (((PSRB_IO_CONTROL
)(Srb
->DataBuffer
))->ControlCode
) {
5982 case IOCTL_SCSI_MINIPORT_SMART_VERSION
: {
5984 PGETVERSIONINPARAMS versionParameters
= (PGETVERSIONINPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
5988 // Version and revision per SMART 1.03
5991 versionParameters
->bVersion
= 1;
5992 versionParameters
->bRevision
= 1;
5993 versionParameters
->bReserved
= 0;
5996 // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
5999 versionParameters
->fCapabilities
= (CAP_ATA_ID_CMD
| CAP_ATAPI_ID_CMD
| CAP_SMART_CMD
);
6002 // This is done because of how the IOCTL_SCSI_MINIPORT
6003 // determines 'targetid's'. Disk.sys places the real target id value
6004 // in the DeviceMap field. Once we do some parameter checking, the value passed
6005 // back to the application will be determined.
6008 deviceNumber
= versionParameters
->bIDEDeviceMap
;
6010 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
) ||
6011 (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
)) {
6013 status
= SRB_STATUS_SELECTION_TIMEOUT
;
6018 // NOTE: This will only set the bit
6019 // corresponding to this drive's target id.
6020 // The bit mask is as follows:
6027 if (deviceExtension
->NumberChannels
== 1) {
6028 if (deviceExtension
->PrimaryAddress
) {
6029 deviceNumber
= 1 << Srb
->TargetId
;
6031 deviceNumber
= 4 << Srb
->TargetId
;
6034 deviceNumber
= 1 << Srb
->TargetId
;
6037 versionParameters
->bIDEDeviceMap
= deviceNumber
;
6039 status
= SRB_STATUS_SUCCESS
;
6043 case IOCTL_SCSI_MINIPORT_IDENTIFY
: {
6045 PSENDCMDOUTPARAMS cmdOutParameters
= (PSENDCMDOUTPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
6046 SENDCMDINPARAMS cmdInParameters
= *(PSENDCMDINPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
6051 if (cmdInParameters
.irDriveRegs
.bCommandReg
== ID_CMD
) {
6054 // Extract the target.
6057 targetId
= cmdInParameters
.bDriveNumber
;
6059 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
) ||
6060 (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
)) {
6062 status
= SRB_STATUS_SELECTION_TIMEOUT
;
6067 // Zero the output buffer
6070 for (i
= 0; i
< (sizeof(SENDCMDOUTPARAMS
) + IDENTIFY_BUFFER_SIZE
- 1); i
++) {
6071 ((PUCHAR
)cmdOutParameters
)[i
] = 0;
6075 // Build status block.
6078 cmdOutParameters
->cBufferSize
= IDENTIFY_BUFFER_SIZE
;
6079 cmdOutParameters
->DriverStatus
.bDriverError
= 0;
6080 cmdOutParameters
->DriverStatus
.bIDEError
= 0;
6083 // Extract the identify data from the device extension.
6086 ScsiPortMoveMemory (cmdOutParameters
->bBuffer
, &deviceExtension
->IdentifyData
[targetId
], IDENTIFY_DATA_SIZE
);
6088 status
= SRB_STATUS_SUCCESS
;
6092 status
= SRB_STATUS_INVALID_REQUEST
;
6097 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
:
6098 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
:
6099 case IOCTL_SCSI_MINIPORT_ENABLE_SMART
:
6100 case IOCTL_SCSI_MINIPORT_DISABLE_SMART
:
6101 case IOCTL_SCSI_MINIPORT_RETURN_STATUS
:
6102 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
:
6103 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
:
6104 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
:
6106 status
= IdeSendSmartCommand(HwDeviceExtension
,Srb
);
6111 status
= SRB_STATUS_INVALID_REQUEST
;
6121 // Indicate unsupported command.
6124 status
= SRB_STATUS_INVALID_REQUEST
;
6131 // Check if command complete.
6134 if (status
!= SRB_STATUS_PENDING
) {
6137 "AtapiStartIo: Srb %x complete with status %x\n",
6142 // Clear current SRB.
6145 deviceExtension
->CurrentSrb
= NULL
;
6148 // Set status in SRB.
6151 Srb
->SrbStatus
= (UCHAR
)status
;
6154 // Indicate command complete.
6157 ScsiPortNotification(RequestComplete
,
6162 // Indicate ready for next request.
6165 ScsiPortNotification(NextRequest
,
6172 } // end AtapiStartIo()
6178 IN PVOID DriverObject
,
6184 Routine Description:
6186 Installable driver initialization entry point for system.
6194 Status from ScsiPortInitialize()
6199 HW_INITIALIZATION_DATA hwInitializationData
;
6202 ULONG statusToReturn
, newStatus
;
6204 DebugPrint((1,"\n\nATAPI IDE MiniPort Driver\n"));
6206 statusToReturn
= 0xffffffff;
6209 // Zero out structure.
6212 AtapiZeroMemory(((PUCHAR
)&hwInitializationData
), sizeof(HW_INITIALIZATION_DATA
));
6215 // Set size of hwInitializationData.
6218 hwInitializationData
.HwInitializationDataSize
=
6219 sizeof(HW_INITIALIZATION_DATA
);
6222 // Set entry points.
6225 hwInitializationData
.HwInitialize
= AtapiHwInitialize
;
6226 hwInitializationData
.HwResetBus
= AtapiResetController
;
6227 hwInitializationData
.HwStartIo
= AtapiStartIo
;
6228 hwInitializationData
.HwInterrupt
= AtapiInterrupt
;
6231 // Specify size of extensions.
6234 hwInitializationData
.DeviceExtensionSize
= sizeof(HW_DEVICE_EXTENSION
);
6235 hwInitializationData
.SpecificLuExtensionSize
= sizeof(HW_LU_EXTENSION
);
6238 // Indicate PIO device.
6241 hwInitializationData
.MapBuffers
= TRUE
;
6244 // Native Mode Devices
6246 for (i
=0; i
<NUM_NATIVE_MODE_ADAPTERS
; i
++) {
6247 hwInitializationData
.HwFindAdapter
= AtapiFindNativeModeController
;
6248 hwInitializationData
.NumberOfAccessRanges
= 4;
6249 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
6251 hwInitializationData
.VendorId
= NativeModeAdapters
[i
].VendorId
;
6252 hwInitializationData
.VendorIdLength
= (USHORT
) NativeModeAdapters
[i
].VendorIdLength
;
6253 hwInitializationData
.DeviceId
= NativeModeAdapters
[i
].DeviceId
;
6254 hwInitializationData
.DeviceIdLength
= (USHORT
) NativeModeAdapters
[i
].DeviceIdLength
;
6256 newStatus
= ScsiPortInitialize(DriverObject
,
6258 &hwInitializationData
,
6259 (PVOID
)(ULONG_PTR
)i
);
6260 if (newStatus
< statusToReturn
)
6261 statusToReturn
= newStatus
;
6264 hwInitializationData
.VendorId
= 0;
6265 hwInitializationData
.VendorIdLength
= 0;
6266 hwInitializationData
.DeviceId
= 0;
6267 hwInitializationData
.DeviceIdLength
= 0;
6270 // The adapter count is used by the find adapter routine to track how
6271 // which adapter addresses have been tested.
6276 hwInitializationData
.HwFindAdapter
= AtapiFindPCIController
;
6277 hwInitializationData
.NumberOfAccessRanges
= 4;
6278 hwInitializationData
.AdapterInterfaceType
= Isa
;
6280 newStatus
= ScsiPortInitialize(DriverObject
,
6282 &hwInitializationData
,
6284 if (newStatus
< statusToReturn
)
6285 statusToReturn
= newStatus
;
6288 // Indicate 2 access ranges and reset FindAdapter.
6291 hwInitializationData
.NumberOfAccessRanges
= 2;
6292 hwInitializationData
.HwFindAdapter
= AtapiFindController
;
6295 // Indicate ISA bustype.
6298 hwInitializationData
.AdapterInterfaceType
= Isa
;
6301 // Call initialization for ISA bustype.
6304 newStatus
= ScsiPortInitialize(DriverObject
,
6306 &hwInitializationData
,
6308 if (newStatus
< statusToReturn
)
6309 statusToReturn
= newStatus
;
6315 hwInitializationData
.AdapterInterfaceType
= MicroChannel
;
6318 newStatus
= ScsiPortInitialize(DriverObject
,
6320 &hwInitializationData
,
6322 if (newStatus
< statusToReturn
)
6323 statusToReturn
= newStatus
;
6325 return statusToReturn
;
6327 } // end DriverEntry()
6348 first
= *FirstStr
++;
6349 last
= *SecondStr
++;
6351 if (first
!= last
) {
6354 // If no match, try lower-casing.
6357 if (first
>='A' && first
<='Z') {
6358 first
= first
- 'A' + 'a';
6360 if (last
>='A' && last
<='Z') {
6361 last
= last
- 'A' + 'a';
6363 if (first
!= last
) {
6369 return first
- last
;
6372 }while (--Count
&& first
);
6388 for (i
= 0; i
< Count
; i
++) {
6398 IN OUT PCHAR
*Buffer
6411 for (i
= 0; i
< 4; i
++) {
6412 digval
= (USHORT
)(Value
% 16);
6416 // convert to ascii and store. Note this will create
6417 // the buffer with the digits reversed.
6421 *string
++ = (char) (digval
- 10 + 'a');
6423 *string
++ = (char) (digval
+ '0');
6429 // Reverse the digits.
6436 *string
= *firstdig
;
6440 } while (firstdig
< string
);
6447 BuildMechanismStatusSrb (
6448 IN PVOID HwDeviceExtension
,
6453 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
6454 PSCSI_REQUEST_BLOCK srb
;
6457 srb
= &deviceExtension
->InternalSrb
;
6459 AtapiZeroMemory((PUCHAR
) srb
, sizeof(SCSI_REQUEST_BLOCK
));
6461 srb
->PathId
= (UCHAR
) PathId
;
6462 srb
->TargetId
= (UCHAR
) TargetId
;
6463 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6464 srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
6467 // Set flags to disable synchronous negotiation.
6469 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6472 // Set timeout to 2 seconds.
6474 srb
->TimeOutValue
= 4;
6477 srb
->DataBuffer
= &deviceExtension
->MechStatusData
;
6478 srb
->DataTransferLength
= sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6481 // Set CDB operation code.
6483 cdb
= (PCDB
)srb
->Cdb
;
6484 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6485 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6493 BuildRequestSenseSrb (
6494 IN PVOID HwDeviceExtension
,
6499 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
6500 PSCSI_REQUEST_BLOCK srb
;
6503 srb
= &deviceExtension
->InternalSrb
;
6505 AtapiZeroMemory((PUCHAR
) srb
, sizeof(SCSI_REQUEST_BLOCK
));
6507 srb
->PathId
= (UCHAR
) PathId
;
6508 srb
->TargetId
= (UCHAR
) TargetId
;
6509 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6510 srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
6513 // Set flags to disable synchronous negotiation.
6515 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6518 // Set timeout to 2 seconds.
6520 srb
->TimeOutValue
= 4;
6523 srb
->DataBuffer
= &deviceExtension
->MechStatusSense
;
6524 srb
->DataTransferLength
= sizeof(SENSE_DATA
);
6527 // Set CDB operation code.
6529 cdb
= (PCDB
)srb
->Cdb
;
6530 cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
6531 cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);