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
)){
1386 BOOLEAN isSanyo
= FALSE
;
1390 // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc.
1393 for (j
= 0; j
< 13; j
+= 2) {
1396 // Build a buffer based on the identify data.
1399 vendorId
[j
] = ((PUCHAR
)deviceExtension
->IdentifyData
[i
].ModelNumber
)[j
+ 1];
1400 vendorId
[j
+1] = ((PUCHAR
)deviceExtension
->IdentifyData
[i
].ModelNumber
)[j
];
1403 if (!AtapiStringCmp ((PCHAR
)vendorId
, "CD-ROM CDR", 11)) {
1406 // Inquiry string for older model had a '-', newer is '_'
1409 if (vendorId
[12] == 'C') {
1412 // Torisan changer. Set the bit. This will be used in several places
1413 // acting like 1) a multi-lun device and 2) building the 'special' TUR's.
1416 deviceExtension
->DeviceFlags
[i
] |= (DFLAGS_CHANGER_INITED
| DFLAGS_SANYO_ATAPI_CHANGER
);
1417 deviceExtension
->DiscsPresent
[i
] = 3;
1424 // We need to get our device ready for action before
1425 // returning from this function
1427 // According to the atapi spec 2.5 or 2.6, an atapi device
1428 // clears its status BSY bit when it is ready for atapi commands.
1429 // However, some devices (Panasonic SQ-TC500N) are still
1430 // not ready even when the status BSY is clear. They don't react
1431 // to atapi commands.
1433 // Since there is really no other indication that tells us
1434 // the drive is really ready for action. We are going to check BSY
1435 // is clear and then just wait for an arbitrary amount of time!
1437 if (deviceExtension
->DeviceFlags
[i
] & DFLAGS_ATAPI_DEVICE
) {
1438 //PIDE_REGISTERS_1 baseIoAddress1 = deviceExtension->BaseIoAddress1[i >> 1];
1439 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[i
>> 1];
1442 // have to get out of the loop sometime!
1443 // 10000 * 100us = 1000,000us = 1000ms = 1s
1445 GetStatus(baseIoAddress2
, statusByte
);
1446 while ((statusByte
& IDE_STATUS_BUSY
) && waitCount
) {
1448 // Wait for Busy to drop.
1450 ScsiPortStallExecution(100);
1451 GetStatus(baseIoAddress2
, statusByte
);
1455 // 5000 * 100us = 500,000us = 500ms = 0.5s
1458 ScsiPortStallExecution(100);
1459 } while (waitCount
--);
1466 } // end AtapiHwInitialize()
1471 AtapiHwInitializeChanger (
1472 IN PVOID HwDeviceExtension
,
1474 IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus
)
1476 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
1478 if (MechanismStatus
) {
1479 deviceExtension
->DiscsPresent
[TargetId
] = MechanismStatus
->NumberAvailableSlots
;
1480 if (deviceExtension
->DiscsPresent
[TargetId
] > 1) {
1481 deviceExtension
->DeviceFlags
[TargetId
] |= DFLAGS_ATAPI_CHANGER
;
1492 IN PVOID HwDeviceExtension
,
1493 IN BOOLEAN AtapiOnly
,
1499 Routine Description:
1501 This routine is called from AtapiFindController to identify
1502 devices attached to an IDE controller.
1506 HwDeviceExtension - HBA miniport driver's adapter data storage
1507 AtapiOnly - Indicates that routine should return TRUE only if
1508 an ATAPI device is attached to the controller.
1512 TRUE - True if devices found.
1517 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
1518 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Channel
];
1519 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Channel
];
1520 BOOLEAN deviceResponded
= FALSE
,
1521 skipSetParameters
= FALSE
;
1522 ULONG waitCount
= 10000;
1530 // Clear expecting interrupt flag and current SRB field.
1533 deviceExtension
->ExpectingInterrupt
= FALSE
;
1534 deviceExtension
->CurrentSrb
= NULL
;
1537 // Search for devices.
1540 for (deviceNumber
= 0; deviceNumber
< 2; deviceNumber
++) {
1543 // Select the device.
1546 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1547 (UCHAR
)((deviceNumber
<< 4) | 0xA0));
1550 // Check here for some SCSI adapters that incorporate IDE emulation.
1553 GetStatus(baseIoAddress2
, statusByte
);
1554 if (statusByte
== 0xFF) {
1558 AtapiSoftReset(baseIoAddress1
,deviceNumber
);
1559 WaitOnBusy(baseIoAddress2
,statusByte
);
1561 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
1562 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
1564 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
1567 // ATAPI signature found.
1568 // Issue the ATAPI identify command if this
1569 // is not for the crash dump utility.
1574 if (!deviceExtension
->DriverMustPoll
) {
1577 // Issue ATAPI packet identify command.
1580 if (IssueIdentify(HwDeviceExtension
,
1583 IDE_COMMAND_ATAPI_IDENTIFY
)) {
1586 // Indicate ATAPI device.
1590 "FindDevices: Device %x is ATAPI\n",
1593 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] |= DFLAGS_ATAPI_DEVICE
;
1594 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] |= DFLAGS_DEVICE_PRESENT
;
1596 deviceResponded
= TRUE
;
1598 GetStatus(baseIoAddress2
, statusByte
);
1599 if (statusByte
& IDE_STATUS_ERROR
) {
1600 AtapiSoftReset(baseIoAddress1
, deviceNumber
);
1607 // Indicate no working device.
1611 "FindDevices: Device %x not responding\n",
1614 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] &= ~DFLAGS_DEVICE_PRESENT
;
1622 // Issue IDE Identify. If an Atapi device is actually present, the signature
1623 // will be asserted, and the drive will be recognized as such.
1626 if (IssueIdentify(HwDeviceExtension
,
1629 IDE_COMMAND_IDENTIFY
)) {
1637 "FindDevices: Device %x is IDE\n",
1640 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] |= DFLAGS_DEVICE_PRESENT
;
1643 deviceResponded
= TRUE
;
1647 // Indicate IDE - not ATAPI device.
1650 deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] &= ~DFLAGS_ATAPI_DEVICE
;
1656 // Look to see if an Atapi device is present.
1659 AtapiSoftReset(baseIoAddress1
,deviceNumber
);
1661 WaitOnBusy(baseIoAddress2
,statusByte
);
1663 signatureLow
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderLow
);
1664 signatureHigh
= ScsiPortReadPortUchar(&baseIoAddress1
->CylinderHigh
);
1666 if (signatureLow
== 0x14 && signatureHigh
== 0xEB) {
1673 for (i
= 0; i
< 2; i
++) {
1674 if ((deviceExtension
->DeviceFlags
[i
+ (Channel
* 2)] & DFLAGS_DEVICE_PRESENT
) &&
1675 (!(deviceExtension
->DeviceFlags
[i
+ (Channel
* 2)] & DFLAGS_ATAPI_DEVICE
)) && deviceResponded
) {
1678 // This hideous hack is to deal with ESDI devices that return
1679 // garbage geometry in the IDENTIFY data.
1680 // This is ONLY for the crashdump environment as
1681 // these are ESDI devices.
1684 if (deviceExtension
->IdentifyData
[i
].SectorsPerTrack
==
1686 deviceExtension
->IdentifyData
[i
].NumberOfHeads
==
1690 "FindDevices: Found nasty Compaq ESDI!\n"));
1693 // Change these values to something reasonable.
1696 deviceExtension
->IdentifyData
[i
].SectorsPerTrack
=
1698 deviceExtension
->IdentifyData
[i
].NumberOfHeads
=
1702 if (deviceExtension
->IdentifyData
[i
].SectorsPerTrack
==
1704 deviceExtension
->IdentifyData
[i
].NumberOfHeads
==
1708 "FindDevices: Found nasty Compaq ESDI!\n"));
1711 // Change these values to something reasonable.
1714 deviceExtension
->IdentifyData
[i
].SectorsPerTrack
=
1716 deviceExtension
->IdentifyData
[i
].NumberOfHeads
=
1721 if (deviceExtension
->IdentifyData
[i
].SectorsPerTrack
==
1723 deviceExtension
->IdentifyData
[i
].NumberOfHeads
==
1727 "FindDevices: Found nasty UltraStor ESDI!\n"));
1730 // Change these values to something reasonable.
1733 deviceExtension
->IdentifyData
[i
].SectorsPerTrack
=
1735 deviceExtension
->IdentifyData
[i
].NumberOfHeads
=
1737 skipSetParameters
= TRUE
;
1741 if (!skipSetParameters
) {
1743 WaitOnBusy(baseIoAddress2
,statusByte
);
1746 // Select the device.
1749 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1750 (UCHAR
)((i
<< 4) | 0xA0));
1752 GetStatus(baseIoAddress2
, statusByte
);
1754 if (statusByte
& IDE_STATUS_ERROR
) {
1757 // Reset the device.
1761 "FindDevices: Resetting controller before SetDriveParameters.\n"));
1763 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_RESET_CONTROLLER
);
1764 ScsiPortStallExecution(500 * 1000);
1765 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_REENABLE_CONTROLLER
);
1766 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
1767 (UCHAR
)((i
<< 4) | 0xA0));
1772 // Wait for Busy to drop.
1775 ScsiPortStallExecution(100);
1776 GetStatus(baseIoAddress2
, statusByte
);
1778 } while ((statusByte
& IDE_STATUS_BUSY
) && waitCount
--);
1781 WaitOnBusy(baseIoAddress2
,statusByte
);
1783 "FindDevices: Status before SetDriveParameters: (%x) (%x)\n",
1785 ScsiPortReadPortUchar(&baseIoAddress1
->DriveSelect
)));
1788 // Use the IDENTIFY data to set drive parameters.
1791 if (!SetDriveParameters(HwDeviceExtension
,i
,Channel
)) {
1794 "AtapHwInitialize: Set drive parameters for device %d failed\n",
1798 // Don't use this device as writes could cause corruption.
1801 deviceExtension
->DeviceFlags
[i
+ Channel
] = 0;
1805 if (deviceExtension
->DeviceFlags
[deviceNumber
+ (Channel
* 2)] & DFLAGS_REMOVABLE_DRIVE
) {
1808 // Pick up ALL IDE removable drives that conform to Yosemite V0.2...
1816 // Indicate that a device was found.
1820 deviceResponded
= TRUE
;
1827 // Make sure master device is selected on exit.
1830 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
, 0xA0);
1833 // Reset the controller. This is a feeble attempt to leave the ESDI
1834 // controllers in a state that ATDISK driver will recognize them.
1835 // The problem in ATDISK has to do with timings as it is not reproducible
1836 // in debug. The reset should restore the controller to its poweron state
1837 // and give the system enough time to settle.
1840 if (!deviceResponded
) {
1842 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_RESET_CONTROLLER
);
1843 ScsiPortStallExecution(50 * 1000);
1844 ScsiPortWritePortUchar(&baseIoAddress2
->AlternateStatus
,IDE_DC_REENABLE_CONTROLLER
);
1847 return deviceResponded
;
1849 } // end FindDevices()
1854 AtapiParseArgumentString(
1861 Routine Description:
1863 This routine will parse the string for a match on the keyword, then
1864 calculate the value for the keyword and return it to the caller.
1868 String - The ASCII string to parse.
1869 KeyWord - The keyword for the value desired.
1873 Zero if value not found
1874 Value converted from ASCII to binary.
1882 ULONG stringLength
= 0;
1883 ULONG keyWordLength
= 0;
1894 // Calculate the string length and lower case all characters.
1899 if (*cptr
>= 'A' && *cptr
<= 'Z') {
1900 *cptr
= *cptr
+ ('a' - 'A');
1907 // Calculate the keyword length and lower case all characters.
1913 if (*cptr
>= 'A' && *cptr
<= 'Z') {
1914 *cptr
= *cptr
+ ('a' - 'A');
1920 if (keyWordLength
> stringLength
) {
1923 // Can't possibly have a match.
1930 // Now setup and start the compare.
1938 // The input string may start with white space. Skip it.
1941 while (*cptr
== ' ' || *cptr
== '\t') {
1945 if (*cptr
== '\0') {
1955 while (*cptr
++ == *kptr
++) {
1957 if (*(cptr
- 1) == '\0') {
1967 if (*(kptr
- 1) == '\0') {
1970 // May have a match backup and check for blank or equals.
1974 while (*cptr
== ' ' || *cptr
== '\t') {
1979 // Found a match. Make sure there is an equals.
1985 // Not a match so move to the next semicolon.
1989 if (*cptr
++ == ';') {
1990 goto ContinueSearch
;
1997 // Skip the equals sign.
2003 // Skip white space.
2006 while ((*cptr
== ' ') || (*cptr
== '\t')) {
2010 if (*cptr
== '\0') {
2013 // Early end of string, return not found
2022 // This isn't it either.
2026 goto ContinueSearch
;
2030 if ((*cptr
== '0') && (*(cptr
+ 1) == 'x')) {
2033 // Value is in Hex. Skip the "0x"
2037 for (index
= 0; *(cptr
+ index
); index
++) {
2039 if (*(cptr
+ index
) == ' ' ||
2040 *(cptr
+ index
) == '\t' ||
2041 *(cptr
+ index
) == ';') {
2045 if ((*(cptr
+ index
) >= '0') && (*(cptr
+ index
) <= '9')) {
2046 value
= (16 * value
) + (*(cptr
+ index
) - '0');
2048 if ((*(cptr
+ index
) >= 'a') && (*(cptr
+ index
) <= 'f')) {
2049 value
= (16 * value
) + (*(cptr
+ index
) - 'a' + 10);
2053 // Syntax error, return not found.
2062 // Value is in Decimal.
2065 for (index
= 0; *(cptr
+ index
); index
++) {
2067 if (*(cptr
+ index
) == ' ' ||
2068 *(cptr
+ index
) == '\t' ||
2069 *(cptr
+ index
) == ';') {
2073 if ((*(cptr
+ index
) >= '0') && (*(cptr
+ index
) <= '9')) {
2074 value
= (10 * value
) + (*(cptr
+ index
) - '0');
2078 // Syntax error return not found.
2089 // Not a match check for ';' to continue search.
2093 if (*cptr
++ == ';') {
2094 goto ContinueSearch
;
2108 AtapiFindController(
2109 IN PVOID HwDeviceExtension
,
2111 IN PVOID BusInformation
,
2112 IN PCHAR ArgumentString
,
2113 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
2118 Routine Description:
2120 This function is called by the OS-specific port driver after
2121 the necessary storage has been allocated, to gather information
2122 about the adapter's configuration.
2126 HwDeviceExtension - HBA miniport driver's adapter data storage
2127 Context - Address of adapter count
2128 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
2129 ConfigInfo - Configuration information structure describing HBA
2130 Again - Indicates search for adapters to continue
2139 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
2140 PULONG adapterCount
= (PULONG
)Context
;
2141 PUCHAR ioSpace
= NULL
;
2146 PCI_SLOT_NUMBER slotData
;
2147 PPCI_COMMON_CONFIG pciData
;
2151 BOOLEAN preConfig
= FALSE
;
2153 // The following table specifies the ports to be checked when searching for
2154 // an IDE controller. A zero entry terminates the search.
2157 CONST ULONG AdapterAddresses
[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
2160 // The following table specifies interrupt levels corresponding to the
2161 // port addresses in the previous table.
2164 CONST ULONG InterruptLevels
[5] = {14, 15, 11, 10, 0};
2166 if (!deviceExtension
) {
2167 return SP_RETURN_ERROR
;
2171 // Check to see if this is a special configuration environment.
2175 if (ArgumentString
) {
2177 irq
= AtapiParseArgumentString(ArgumentString
, "Interrupt");
2181 // Both parameters must be present to proceed
2184 portBase
= AtapiParseArgumentString(ArgumentString
, "BaseAddress");
2188 // Try a default search for the part.
2199 // Scan though the adapter address looking for adapters.
2201 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
) != 0) {
2202 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2203 ConfigInfo
->AdapterInterfaceType
,
2204 ConfigInfo
->SystemIoBusNumber
,
2205 (*ConfigInfo
->AccessRanges
)[0].RangeStart
,
2206 (*ConfigInfo
->AccessRanges
)[0].RangeLength
,
2207 (BOOLEAN
) !((*ConfigInfo
->AccessRanges
)[0].RangeInMemory
));
2210 // Since we have pre-configured information we only need to go through this loop once
2213 portBase
= ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
);
2219 while (AdapterAddresses
[*adapterCount
] != 0) {
2223 for (i
= 0; i
< 4; i
++) {
2226 // Zero device fields to ensure that if earlier devices were found,
2227 // but not claimed, the fields are cleared.
2230 deviceExtension
->DeviceFlags
[i
] &= ~(DFLAGS_ATAPI_DEVICE
| DFLAGS_DEVICE_PRESENT
| DFLAGS_TAPE_DEVICE
);
2234 // Get the system physical address for this IO range.
2239 // Check if configInfo has the default information
2240 // if not, we go and find ourselves
2243 if (preConfig
== FALSE
) {
2246 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2247 ConfigInfo
->AdapterInterfaceType
,
2248 ConfigInfo
->SystemIoBusNumber
,
2249 ScsiPortConvertUlongToPhysicalAddress(portBase
),
2253 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2254 ConfigInfo
->AdapterInterfaceType
,
2255 ConfigInfo
->SystemIoBusNumber
,
2256 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
]),
2261 }// ConfigInfo check
2263 // Update the adapter count.
2269 // Check if ioSpace accessible.
2282 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xA0);
2285 // Check if card at this address.
2288 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2291 // Check if indentifier can be read back.
2294 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2297 "AtapiFindController: Identifier read back from Master (%x)\n",
2300 statusByte
= ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2
)ioSpace
)->AlternateStatus
);
2302 if (statusByte
& IDE_STATUS_BUSY
) {
2307 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
2308 // warm boots don't clear.
2312 ScsiPortStallExecution(1000);
2313 statusByte
= ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1
)ioSpace
)->Command
);
2315 "AtapiFindController: First access to status %x\n",
2317 } while ((statusByte
& IDE_STATUS_BUSY
) && ++i
< 10);
2319 if (retryCount
-- && (!(statusByte
& IDE_STATUS_BUSY
))) {
2320 goto retryIdentifier
;
2328 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xB0);
2331 // See if slave is present.
2334 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2336 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2339 "AtapiFindController: Identifier read back from Slave (%x)\n",
2344 // No controller at this base address.
2347 ScsiPortFreeDeviceBase(HwDeviceExtension
,
2355 // Record base IO address.
2358 deviceExtension
->BaseIoAddress1
[0] = (PIDE_REGISTERS_1
)(ioSpace
);
2361 // Fill in the access array information only if default params are not in there.
2363 if (preConfig
== FALSE
) {
2366 // An adapter has been found request another call, only if we didn't get preconfigured info.
2371 (*ConfigInfo
->AccessRanges
)[0].RangeStart
= ScsiPortConvertUlongToPhysicalAddress(portBase
);
2373 (*ConfigInfo
->AccessRanges
)[0].RangeStart
=
2374 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1]);
2377 (*ConfigInfo
->AccessRanges
)[0].RangeLength
= 8;
2378 (*ConfigInfo
->AccessRanges
)[0].RangeInMemory
= FALSE
;
2381 // Indicate the interrupt level corresponding to this IO range.
2385 ConfigInfo
->BusInterruptLevel
= irq
;
2387 ConfigInfo
->BusInterruptLevel
= InterruptLevels
[*adapterCount
- 1];
2390 if (ConfigInfo
->AdapterInterfaceType
== MicroChannel
) {
2391 ConfigInfo
->InterruptMode
= LevelSensitive
;
2393 ConfigInfo
->InterruptMode
= Latched
;
2397 // Get the system physical address for the second IO range.
2402 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2403 ConfigInfo
->AdapterInterfaceType
,
2404 ConfigInfo
->SystemIoBusNumber
,
2405 ScsiPortConvertUlongToPhysicalAddress(portBase
+ 0x206),
2409 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2410 ConfigInfo
->AdapterInterfaceType
,
2411 ConfigInfo
->SystemIoBusNumber
,
2412 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1] + 0x206),
2417 deviceExtension
->BaseIoAddress2
[0] = (PIDE_REGISTERS_2
)(ioSpace
);
2419 deviceExtension
->NumberChannels
= 1;
2421 ConfigInfo
->NumberOfBuses
= 1;
2422 ConfigInfo
->MaximumNumberOfTargets
= 2;
2425 // Indicate maximum transfer length is 64k.
2428 ConfigInfo
->MaximumTransferLength
= 0x10000;
2431 "AtapiFindController: Found IDE at %x\n",
2432 deviceExtension
->BaseIoAddress1
[0]));
2436 // For Daytona, the atdisk driver gets the first shot at the
2437 // primary and secondary controllers.
2440 if (preConfig
== FALSE
) {
2443 if (*adapterCount
- 1 < 2) {
2446 // Determine whether this driver is being initialized by the
2447 // system or as a crash dump driver.
2450 if (ArgumentString
) {
2452 if (AtapiParseArgumentString(ArgumentString
, "dump") == 1) {
2454 "AtapiFindController: Crash dump\n"));
2456 deviceExtension
->DriverMustPoll
= TRUE
;
2459 "AtapiFindController: Atapi Only\n"));
2461 deviceExtension
->DriverMustPoll
= FALSE
;
2466 "AtapiFindController: Atapi Only\n"));
2468 deviceExtension
->DriverMustPoll
= FALSE
;
2476 // If this is a PCI machine, pick up all devices.
2480 pciData
= (PPCI_COMMON_CONFIG
)&pciBuffer
;
2482 slotData
.u
.bits
.DeviceNumber
= 0;
2483 slotData
.u
.bits
.FunctionNumber
= 0;
2485 if (ScsiPortGetBusData(deviceExtension
,
2495 // Wait on doing this, until a reliable method
2496 // of determining support is found.
2500 deviceExtension
->DWordIO
= TRUE
;
2504 deviceExtension
->DWordIO
= FALSE
;
2510 deviceExtension
->DriverMustPoll
= FALSE
;
2515 // Save the Interrupe Mode for later use
2517 deviceExtension
->InterruptMode
= ConfigInfo
->InterruptMode
;
2520 // Search for devices on this controller.
2523 if (FindDevices(HwDeviceExtension
,
2528 // Claim primary or secondary ATA IO range.
2534 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
2535 deviceExtension
->PrimaryAddress
= FALSE
;
2538 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
2539 deviceExtension
->PrimaryAddress
= TRUE
;
2545 if (*adapterCount
== 1) {
2546 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
2547 deviceExtension
->PrimaryAddress
= TRUE
;
2548 } else if (*adapterCount
== 2) {
2549 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
2550 deviceExtension
->PrimaryAddress
= FALSE
;
2554 return(SP_RETURN_FOUND
);
2559 // The entire table has been searched and no adapters have been found.
2560 // There is no need to call again and the device base can now be freed.
2561 // Clear the adapter count for the next bus.
2565 *(adapterCount
) = 0;
2567 return(SP_RETURN_NOT_FOUND
);
2569 } // end AtapiFindController()
2577 FindBrokenController(
2578 IN PVOID DeviceExtension
,
2580 IN ULONG VendorIDLength
,
2582 IN ULONG DeviceIDLength
,
2583 IN OUT PULONG FunctionNumber
,
2584 IN OUT PULONG SlotNumber
,
2586 OUT PBOOLEAN LastSlot
2591 Routine Description:
2593 Walk PCI slot information looking for Vendor and Product ID matches.
2605 ULONG functionNumber
;
2606 PCI_SLOT_NUMBER slotData
;
2607 PPCI_COMMON_CONFIG pciData
;
2608 UCHAR vendorString
[5];
2609 UCHAR deviceString
[5];
2610 PUCHAR vendorStrPtr
;
2611 PUCHAR deviceStrPtr
;
2613 pciData
= (PPCI_COMMON_CONFIG
)&pciBuffer
;
2615 slotData
.u
.AsULONG
= 0;
2618 // Look at each device.
2621 for (slotNumber
= *SlotNumber
;
2625 slotData
.u
.bits
.DeviceNumber
= slotNumber
;
2628 // Look at each function.
2631 for (functionNumber
= *FunctionNumber
;
2635 slotData
.u
.bits
.FunctionNumber
= functionNumber
;
2637 if (!ScsiPortGetBusData(DeviceExtension
,
2652 if (pciData
->VendorID
== PCI_INVALID_VENDORID
) {
2655 // No PCI device, or no more functions on device
2656 // move to next PCI device.
2663 // Translate hex ids to strings.
2666 vendorStrPtr
= vendorString
;
2667 deviceStrPtr
= deviceString
;
2668 AtapiHexToString(pciData
->VendorID
, (PCHAR
*)&vendorStrPtr
);
2669 AtapiHexToString(pciData
->DeviceID
, (PCHAR
*)&deviceStrPtr
);
2672 "FindBrokenController: Bus %x Slot %x Function %x Vendor %s Product %s\n",
2683 if (AtapiStringCmp((PCHAR
)vendorString
,
2686 AtapiStringCmp((PCHAR
)deviceString
,
2691 // Not our PCI device. Try next device/function
2697 *FunctionNumber
= functionNumber
;
2698 *SlotNumber
= slotNumber
;
2701 } // next PCI function
2703 *FunctionNumber
= 0;
2709 } // end FindBrokenController
2714 AtapiFindNativeModeController(
2715 IN PVOID HwDeviceExtension
,
2717 IN PVOID BusInformation
,
2718 IN PCHAR ArgumentString
,
2719 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
2724 Routine Description:
2726 This function is called by the OS-specific port driver after
2727 the necessary storage has been allocated, to gather information
2728 about the adapter's configuration.
2732 HwDeviceExtension - HBA miniport driver's adapter data storage
2733 Context - Address of adapter count
2735 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
2736 ConfigInfo - Configuration information structure describing HBA
2737 Again - Indicates search for adapters to continue
2746 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
2747 ULONG nativeModeAdapterTableIndex
= (ULONG
)Context
;
2751 deviceFound
= FALSE
;
2753 PCI_SLOT_NUMBER slotData
;
2754 PCI_COMMON_CONFIG pciData
;
2757 UCHAR vendorString
[5];
2758 UCHAR deviceString
[5];
2759 PUCHAR vendorStrPtr
;
2760 PUCHAR deviceStrPtr
;
2761 SCSI_PHYSICAL_ADDRESS IoBasePort1
;
2762 SCSI_PHYSICAL_ADDRESS IoBasePort2
;
2765 // The following table specifies the ports to be checked when searching for
2766 // an IDE controller. A zero entry terminates the search.
2769 CONST ULONG AdapterAddresses
[3] = {0x1F0, 0x170, 0};
2771 if (!deviceExtension
) {
2772 return SP_RETURN_ERROR
;
2777 slotData
.u
.AsULONG
= 0;
2778 slotData
.u
.bits
.DeviceNumber
= ConfigInfo
->SlotNumber
;
2780 for (funcNumber
= 0; funcNumber
< 8; funcNumber
++) {
2782 slotData
.u
.bits
.FunctionNumber
= funcNumber
;
2784 busDataRead
= ScsiPortGetBusData(HwDeviceExtension
,
2786 ConfigInfo
->SystemIoBusNumber
,
2790 if (busDataRead
!= sizeof (pciData
)) {
2791 return SP_RETURN_ERROR
;
2793 if (pciData
.VendorID
== PCI_INVALID_VENDORID
) {
2794 return SP_RETURN_ERROR
;
2798 // Translate hex ids to strings.
2801 vendorStrPtr
= vendorString
;
2802 deviceStrPtr
= deviceString
;
2803 AtapiHexToString(pciData
.VendorID
, (PCHAR
*)&vendorStrPtr
);
2804 AtapiHexToString(pciData
.DeviceID
, (PCHAR
*)&deviceStrPtr
);
2810 if (AtapiStringCmp((PCHAR
)vendorString
,
2811 NativeModeAdapters
[nativeModeAdapterTableIndex
].VendorId
,
2812 NativeModeAdapters
[nativeModeAdapterTableIndex
].VendorIdLength
) ||
2813 AtapiStringCmp((PCHAR
)deviceString
,
2814 NativeModeAdapters
[nativeModeAdapterTableIndex
].DeviceId
,
2815 NativeModeAdapters
[nativeModeAdapterTableIndex
].DeviceIdLength
)) {
2819 if (pciData
.ProgIf
& ((1 << 2) | (1 << 0))) {
2820 // both primary and secondary channel are in native mode
2829 if (*Again
== TRUE
) {
2831 for (channel
= 0; channel
< 2; channel
++) {
2833 IoBasePort1
= (*ConfigInfo
->AccessRanges
)[channel
* 2 + 0].RangeStart
;
2834 IoBasePort2
= (*ConfigInfo
->AccessRanges
)[channel
* 2 + 1].RangeStart
;
2835 IoBasePort2
= ScsiPortConvertUlongToPhysicalAddress(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2
) + 2);
2838 // Get the system physical address for this IO range.
2841 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2842 ConfigInfo
->AdapterInterfaceType
,
2843 ConfigInfo
->SystemIoBusNumber
,
2849 // Check if ioSpace accessible.
2860 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xA0);
2863 // Check if card at this address.
2866 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2869 // Check if indentifier can be read back.
2872 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2875 "AtapiFindPciController: Identifier read back from Master (%x)\n",
2883 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xB0);
2886 // See if slave is present.
2889 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
2891 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
2894 "AtapiFindPciController: Identifier read back from Slave (%x)\n",
2899 // No controller at this base address.
2902 ScsiPortFreeDeviceBase(HwDeviceExtension
,
2906 // If the chip is there, but we couldn't find the primary channel, try the secondary.
2907 // If we couldn't find a secondary, who cares.
2912 goto setStatusAndExit
;
2921 // Record base IO address.
2924 deviceExtension
->BaseIoAddress1
[channel
] = (PIDE_REGISTERS_1
)(ioSpace
);
2927 // Get the system physical address for the second IO range.
2930 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
2931 ConfigInfo
->AdapterInterfaceType
,
2932 ConfigInfo
->SystemIoBusNumber
,
2937 deviceExtension
->BaseIoAddress2
[channel
] = (PIDE_REGISTERS_2
)(ioSpace
);
2939 deviceExtension
->NumberChannels
= 2;
2942 // Indicate only one bus.
2945 ConfigInfo
->NumberOfBuses
= 1;
2948 // Indicate four devices can be attached to the adapter, since we
2949 // have to serialize access to the two channels.
2952 ConfigInfo
->MaximumNumberOfTargets
= 4;
2955 // Indicate maximum transfer length is 64k.
2958 ConfigInfo
->MaximumTransferLength
= 0x10000;
2961 "AtapiFindPciController: Found native mode IDE at %x\n",
2962 deviceExtension
->BaseIoAddress1
[channel
]));
2965 // Since we will always pick up this part, and not atdisk, so indicate.
2971 // Save the Interrupe Mode for later use
2973 deviceExtension
->InterruptMode
= ConfigInfo
->InterruptMode
;
2976 // Search for devices on this controller.
2979 if (FindDevices(HwDeviceExtension
,
2986 // Claim primary or secondary ATA IO range.
2989 if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort1
) == AdapterAddresses
[0]) {
2990 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
2991 deviceExtension
->PrimaryAddress
= TRUE
;
2993 } else if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort2
) == AdapterAddresses
[1]) {
2994 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
2995 deviceExtension
->PrimaryAddress
= FALSE
;
3005 return SP_RETURN_FOUND
;
3009 return SP_RETURN_NOT_FOUND
;
3011 } // end AtapiFindNativeModeController()
3016 AtapiFindPCIController(
3017 IN PVOID HwDeviceExtension
,
3019 IN PVOID BusInformation
,
3020 IN PCHAR ArgumentString
,
3021 IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo
,
3026 Routine Description:
3028 This function is called by the OS-specific port driver after
3029 the necessary storage has been allocated, to gather information
3030 about the adapter's configuration.
3034 HwDeviceExtension - HBA miniport driver's adapter data storage
3035 Context - Address of adapter count
3037 ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
3038 ConfigInfo - Configuration information structure describing HBA
3039 Again - Indicates search for adapters to continue
3048 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
3049 PULONG adapterCount
= (PULONG
)Context
;
3051 static ULONG functionNumber
,
3058 controllerFound
= FALSE
,
3059 deviceFound
= FALSE
;
3063 // The following table specifies the ports to be checked when searching for
3064 // an IDE controller. A zero entry terminates the search.
3067 CONST ULONG AdapterAddresses
[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
3070 // The following table specifies interrupt levels corresponding to the
3071 // port addresses in the previous table.
3074 CONST ULONG InterruptLevels
[5] = {14, 15, 11, 10, 0};
3076 if (!deviceExtension
) {
3077 return SP_RETURN_ERROR
;
3081 // Since scsiport will call this function first before it calls AtapiFindController
3082 // we need to bypass it if we have data installed in ConfigInfo, by the pcmcia driver.
3083 // In that case atapifindcontroller should be called first.
3084 // Instead of modifying atapi driverEntry to search of PCIBus first (now its ISA)
3085 // the check is put here.
3088 if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo
->AccessRanges
)[0].RangeStart
) != 0) {
3090 return AtapiFindController(HwDeviceExtension
,
3100 // Gronk PCI config space looking for the broken PCI IDE controllers that have only
3101 // one FIFO for both channels.
3102 // Don't do this. It's incorrect and nasty. It has to be done to work around these
3103 // broken parts, no other reason can justify this.
3106 for (i
= controllers
; i
< BROKEN_ADAPTERS
; i
++) {
3109 // Determine if both channels are enabled and have devices.
3114 if (FindBrokenController(deviceExtension
,
3115 (PUCHAR
)BrokenAdapters
[i
].VendorId
,
3116 BrokenAdapters
[i
].VendorIdLength
,
3117 (PUCHAR
)BrokenAdapters
[i
].DeviceId
,
3118 BrokenAdapters
[i
].DeviceIdLength
,
3121 ConfigInfo
->SystemIoBusNumber
,
3126 controllerFound
= TRUE
;
3129 "Found broken PCI IDE controller: VendorId %s, DeviceId %s\n",
3130 BrokenAdapters
[i
].VendorId
,
3131 BrokenAdapters
[i
].DeviceId
));
3133 if (AdapterAddresses
[*adapterCount
] != 0) {
3135 for (j
= 0; j
< 2; j
++) {
3138 // Get the system physical address for this IO range.
3141 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
3142 ConfigInfo
->AdapterInterfaceType
,
3143 ConfigInfo
->SystemIoBusNumber
,
3144 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
]),
3149 // Update the adapter count.
3155 // Check if ioSpace accessible.
3166 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xA0);
3169 // Check if card at this address.
3172 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
3175 // Check if indentifier can be read back.
3178 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
3181 "AtapiFindPciController: Identifier read back from Master (%x)\n",
3189 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->DriveSelect
, 0xB0);
3192 // See if slave is present.
3195 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
, 0xAA);
3197 if ((statusByte
= ScsiPortReadPortUchar(&((PIDE_REGISTERS_1
)ioSpace
)->CylinderLow
)) != 0xAA) {
3200 "AtapiFindPciController: Identifier read back from Slave (%x)\n",
3205 // No controller at this base address.
3208 ScsiPortFreeDeviceBase(HwDeviceExtension
,
3212 // If the chip is there, but we couldn't find the primary channel, try the secondary.
3213 // If we couldn't find a secondary, who cares.
3218 goto setStatusAndExit
;
3226 if (controllerFound
) {
3229 // Record base IO address.
3232 deviceExtension
->BaseIoAddress1
[channel
] = (PIDE_REGISTERS_1
)(ioSpace
);
3235 // Fill in the access array information.
3238 (*ConfigInfo
->AccessRanges
)[channel
].RangeStart
=
3239 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1]);
3241 (*ConfigInfo
->AccessRanges
)[channel
].RangeLength
= 8;
3242 (*ConfigInfo
->AccessRanges
)[channel
].RangeInMemory
= FALSE
;
3245 // Indicate the interrupt level corresponding to this IO range.
3249 ConfigInfo
->BusInterruptLevel
= InterruptLevels
[*adapterCount
- 1];
3250 ConfigInfo
->InterruptMode
= Latched
;
3252 ConfigInfo
->BusInterruptLevel2
= InterruptLevels
[*adapterCount
- 1];
3253 ConfigInfo
->InterruptMode2
= Latched
;
3257 // Get the system physical address for the second IO range.
3260 ioSpace
= ScsiPortGetDeviceBase(HwDeviceExtension
,
3261 ConfigInfo
->AdapterInterfaceType
,
3262 ConfigInfo
->SystemIoBusNumber
,
3263 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses
[*adapterCount
- 1] + 0x206),
3267 deviceExtension
->BaseIoAddress2
[channel
] = (PIDE_REGISTERS_2
)(ioSpace
);
3269 deviceExtension
->NumberChannels
= 2;
3272 // Indicate only one bus.
3275 ConfigInfo
->NumberOfBuses
= 1;
3278 // Indicate four devices can be attached to the adapter, since we
3279 // have to serialize access to the two channels.
3282 ConfigInfo
->MaximumNumberOfTargets
= 4;
3285 // Indicate maximum transfer length is 64k.
3288 ConfigInfo
->MaximumTransferLength
= 0x10000;
3291 "AtapiFindPciController: Found broken IDE at %x\n",
3292 deviceExtension
->BaseIoAddress1
[channel
]));
3295 // Since we will always pick up this part, and not atdisk, so indicate.
3301 // Save the Interrupe Mode for later use
3303 deviceExtension
->InterruptMode
= ConfigInfo
->InterruptMode
;
3306 // Search for devices on this controller.
3309 if (FindDevices(HwDeviceExtension
,
3316 // Claim primary or secondary ATA IO range.
3319 if (*adapterCount
== 1) {
3320 ConfigInfo
->AtdiskPrimaryClaimed
= TRUE
;
3321 deviceExtension
->PrimaryAddress
= TRUE
;
3323 } else if (*adapterCount
== 2) {
3324 ConfigInfo
->AtdiskSecondaryClaimed
= TRUE
;
3325 deviceExtension
->PrimaryAddress
= FALSE
;
3341 if (controllerFound
&& deviceFound
) {
3344 return SP_RETURN_FOUND
;
3350 // The entire table has been searched and no adapters have been found.
3355 return SP_RETURN_NOT_FOUND
;
3357 } // end AtapiFindPCIController()
3363 IN PSCSI_REQUEST_BLOCK Srb
,
3364 IN
char *DataBuffer
,
3368 ULONG bytesAdjust
= 0;
3369 if (Srb
->Cdb
[0] == ATAPI_MODE_SENSE
) {
3371 PMODE_PARAMETER_HEADER_10 header_10
= (PMODE_PARAMETER_HEADER_10
)DataBuffer
;
3372 PMODE_PARAMETER_HEADER header
= (PMODE_PARAMETER_HEADER
)DataBuffer
;
3374 header
->ModeDataLength
= header_10
->ModeDataLengthLsb
;
3375 header
->MediumType
= header_10
->MediumType
;
3378 // ATAPI Mode Parameter Header doesn't have these fields.
3381 header
->DeviceSpecificParameter
= header_10
->Reserved
[0];
3382 header
->BlockDescriptorLength
= header_10
->Reserved
[1];
3384 ByteCount
-= sizeof(MODE_PARAMETER_HEADER_10
);
3386 ScsiPortMoveMemory(DataBuffer
+sizeof(MODE_PARAMETER_HEADER
),
3387 DataBuffer
+sizeof(MODE_PARAMETER_HEADER_10
),
3391 // Change ATAPI_MODE_SENSE opcode back to SCSIOP_MODE_SENSE
3392 // so that we don't convert again.
3395 Srb
->Cdb
[0] = SCSIOP_MODE_SENSE
;
3397 bytesAdjust
= sizeof(MODE_PARAMETER_HEADER_10
) -
3398 sizeof(MODE_PARAMETER_HEADER
);
3404 // Convert to words.
3407 return bytesAdjust
>> 1;
3414 IN PVOID HwDeviceExtension
3417 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
3418 PSCSI_REQUEST_BLOCK srb
= deviceExtension
->CurrentSrb
;
3419 PATAPI_REGISTERS_2 baseIoAddress2
;
3423 // If the last command was DSC restrictive, see if it's set. If so, the device is
3424 // ready for a new request. Otherwise, reset the timer and come back to here later.
3427 if (srb
&& (!(deviceExtension
->ExpectingInterrupt
))) {
3429 if (!IS_RDP((srb
->Cdb
[0]))) {
3431 "AtapiCallBack: Invalid CDB marked as RDP - %x\n",
3436 baseIoAddress2
= (PATAPI_REGISTERS_2
)deviceExtension
->BaseIoAddress2
[srb
->TargetId
>> 1];
3437 if (deviceExtension
->RDP
) {
3438 GetStatus(baseIoAddress2
, statusByte
);
3439 if (statusByte
& IDE_STATUS_DSC
) {
3441 ScsiPortNotification(RequestComplete
,
3446 // Clear current SRB.
3449 deviceExtension
->CurrentSrb
= NULL
;
3450 deviceExtension
->RDP
= FALSE
;
3453 // Ask for next request.
3456 ScsiPortNotification(NextRequest
,
3466 "AtapiCallBack: Requesting another timer for Op %x\n",
3467 deviceExtension
->CurrentSrb
->Cdb
[0]));
3469 ScsiPortNotification(RequestTimerCall
,
3479 "AtapiCallBack: Calling ISR directly due to BUSY\n"));
3480 AtapiInterrupt(HwDeviceExtension
);
3487 IN PVOID HwDeviceExtension
3492 Routine Description:
3494 This is the interrupt service routine for ATAPI IDE miniport driver.
3498 HwDeviceExtension - HBA miniport driver's adapter data storage
3502 TRUE if expecting an interrupt.
3507 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
3508 PSCSI_REQUEST_BLOCK srb
= deviceExtension
->CurrentSrb
;
3509 PATAPI_REGISTERS_1 baseIoAddress1
;
3510 PATAPI_REGISTERS_2 baseIoAddress2
;
3511 ULONG wordCount
= 0, wordsThisInterrupt
= 256;
3514 UCHAR statusByte
,interruptReason
;
3515 BOOLEAN atapiDev
= FALSE
;
3518 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[srb
->TargetId
>> 1];
3519 baseIoAddress2
= (PATAPI_REGISTERS_2
)deviceExtension
->BaseIoAddress2
[srb
->TargetId
>> 1];
3522 "AtapiInterrupt: CurrentSrb is NULL\n"));
3524 // We can only support one ATAPI IDE master on Carolina, so find
3525 // the base address that is non NULL and clear its interrupt before
3531 if ((PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[0] != NULL
) {
3532 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[0];
3534 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[1];
3537 GetBaseStatus(baseIoAddress1
, statusByte
);
3540 if (deviceExtension
->InterruptMode
== LevelSensitive
) {
3541 if (deviceExtension
->BaseIoAddress1
[0] != NULL
) {
3542 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[0];
3543 GetBaseStatus(baseIoAddress1
, statusByte
);
3545 if (deviceExtension
->BaseIoAddress1
[1] != NULL
) {
3546 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[1];
3547 GetBaseStatus(baseIoAddress1
, statusByte
);
3554 if (!(deviceExtension
->ExpectingInterrupt
)) {
3557 "AtapiInterrupt: Unexpected interrupt.\n"));
3562 // Clear interrupt by reading status.
3565 GetBaseStatus(baseIoAddress1
, statusByte
);
3568 "AtapiInterrupt: Entered with status (%x)\n",
3572 if (statusByte
& IDE_STATUS_BUSY
) {
3573 if (deviceExtension
->DriverMustPoll
) {
3576 // Crashdump is polling and we got caught with busy asserted.
3577 // Just go away, and we will be polled again shortly.
3581 "AtapiInterrupt: Hit BUSY while polling during crashdump.\n"));
3587 // Ensure BUSY is non-asserted.
3590 for (i
= 0; i
< 10; i
++) {
3592 GetBaseStatus(baseIoAddress1
, statusByte
);
3593 if (!(statusByte
& IDE_STATUS_BUSY
)) {
3596 ScsiPortStallExecution(5000);
3602 "AtapiInterrupt: BUSY on entry. Status %x, Base IO %x\n",
3606 ScsiPortNotification(RequestTimerCall
,
3616 // Check for error conditions.
3619 if (statusByte
& IDE_STATUS_ERROR
) {
3621 if (srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
) {
3624 // Fail this request.
3627 status
= SRB_STATUS_ERROR
;
3628 goto CompleteRequest
;
3633 // check reason for this interrupt.
3636 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3638 interruptReason
= (ScsiPortReadPortUchar(&baseIoAddress1
->InterruptReason
) & 0x3);
3640 wordsThisInterrupt
= 256;
3644 if (statusByte
& IDE_STATUS_DRQ
) {
3646 if (deviceExtension
->MaximumBlockXfer
[srb
->TargetId
]) {
3647 wordsThisInterrupt
= 256 * deviceExtension
->MaximumBlockXfer
[srb
->TargetId
];
3651 if (srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) {
3653 interruptReason
= 0x2;
3655 } else if (srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
) {
3656 interruptReason
= 0x0;
3659 status
= SRB_STATUS_ERROR
;
3660 goto CompleteRequest
;
3663 } else if (statusByte
& IDE_STATUS_BUSY
) {
3669 if (deviceExtension
->WordsLeft
) {
3674 // Funky behaviour seen with PCI IDE (not all, just one).
3675 // The ISR hits with DRQ low, but comes up later.
3678 for (k
= 0; k
< 5000; k
++) {
3679 GetStatus(baseIoAddress2
,statusByte
);
3680 if (!(statusByte
& IDE_STATUS_DRQ
)) {
3681 ScsiPortStallExecution(100);
3690 // reset the controller.
3694 "AtapiInterrupt: Resetting due to DRQ not up. Status %x, Base IO %x\n",
3698 AtapiResetController(HwDeviceExtension
,srb
->PathId
);
3702 interruptReason
= (srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) ? 0x2 : 0x0;
3708 // Command complete - verify, write, or the SMART enable/disable.
3710 // Also get_media_status
3712 interruptReason
= 0x3;
3717 if (interruptReason
== 0x1 && (statusByte
& IDE_STATUS_DRQ
)) {
3720 // Write the packet.
3724 "AtapiInterrupt: Writing Atapi packet.\n"));
3727 // Send CDB to device.
3730 WriteBuffer(baseIoAddress1
,
3736 } else if (interruptReason
== 0x0 && (statusByte
& IDE_STATUS_DRQ
)) {
3742 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3745 // Pick up bytes to transfer and convert to words.
3749 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountLow
);
3752 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountHigh
) << 8;
3755 // Covert bytes to words.
3760 if (wordCount
!= deviceExtension
->WordsLeft
) {
3762 "AtapiInterrupt: %d words requested; %d words xferred\n",
3763 deviceExtension
->WordsLeft
,
3768 // Verify this makes sense.
3771 if (wordCount
> deviceExtension
->WordsLeft
) {
3772 wordCount
= deviceExtension
->WordsLeft
;
3778 // IDE path. Check if words left is at least 256.
3781 if (deviceExtension
->WordsLeft
< wordsThisInterrupt
) {
3784 // Transfer only words requested.
3787 wordCount
= deviceExtension
->WordsLeft
;
3792 // Transfer next block.
3795 wordCount
= wordsThisInterrupt
;
3800 // Ensure that this is a write command.
3803 if (srb
->SrbFlags
& SRB_FLAGS_DATA_OUT
) {
3806 "AtapiInterrupt: Write interrupt\n"));
3808 WaitOnBusy(baseIoAddress2
,statusByte
);
3810 if (atapiDev
|| !deviceExtension
->DWordIO
) {
3812 WriteBuffer(baseIoAddress1
,
3813 deviceExtension
->DataBuffer
,
3817 PIDE_REGISTERS_3 address3
= (PIDE_REGISTERS_3
)baseIoAddress1
;
3819 WriteBuffer2(address3
,
3820 (PULONG
)(deviceExtension
->DataBuffer
),
3826 "AtapiInterrupt: Int reason %x, but srb is for a write %x.\n",
3831 // Fail this request.
3834 status
= SRB_STATUS_ERROR
;
3835 goto CompleteRequest
;
3840 // Advance data buffer pointer and bytes left.
3843 deviceExtension
->DataBuffer
+= wordCount
;
3844 deviceExtension
->WordsLeft
-= wordCount
;
3848 } else if (interruptReason
== 0x2 && (statusByte
& IDE_STATUS_DRQ
)) {
3851 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3854 // Pick up bytes to transfer and convert to words.
3858 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountLow
);
3861 ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountHigh
) << 8;
3864 // Covert bytes to words.
3869 if (wordCount
!= deviceExtension
->WordsLeft
) {
3871 "AtapiInterrupt: %d words requested; %d words xferred\n",
3872 deviceExtension
->WordsLeft
,
3877 // Verify this makes sense.
3880 if (wordCount
> deviceExtension
->WordsLeft
) {
3881 wordCount
= deviceExtension
->WordsLeft
;
3887 // Check if words left is at least 256.
3890 if (deviceExtension
->WordsLeft
< wordsThisInterrupt
) {
3893 // Transfer only words requested.
3896 wordCount
= deviceExtension
->WordsLeft
;
3901 // Transfer next block.
3904 wordCount
= wordsThisInterrupt
;
3909 // Ensure that this is a read command.
3912 if (srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) {
3915 "AtapiInterrupt: Read interrupt\n"));
3917 WaitOnBusy(baseIoAddress2
,statusByte
);
3919 if (atapiDev
|| !deviceExtension
->DWordIO
) {
3920 ReadBuffer(baseIoAddress1
,
3921 deviceExtension
->DataBuffer
,
3925 PIDE_REGISTERS_3 address3
= (PIDE_REGISTERS_3
)baseIoAddress1
;
3927 ReadBuffer2(address3
,
3928 (PULONG
)(deviceExtension
->DataBuffer
),
3934 "AtapiInterrupt: Int reason %x, but srb is for a read %x.\n",
3939 // Fail this request.
3942 status
= SRB_STATUS_ERROR
;
3943 goto CompleteRequest
;
3947 // Translate ATAPI data back to SCSI data if needed
3950 if (srb
->Cdb
[0] == ATAPI_MODE_SENSE
&&
3951 deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3954 //convert and adjust the wordCount
3957 wordCount
-= Atapi2Scsi(srb
, (char *)deviceExtension
->DataBuffer
,
3961 // Advance data buffer pointer and bytes left.
3964 deviceExtension
->DataBuffer
+= wordCount
;
3965 deviceExtension
->WordsLeft
-= wordCount
;
3968 // Check for read command complete.
3971 if (deviceExtension
->WordsLeft
== 0) {
3973 if (deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
3976 // Work around to make many atapi devices return correct sector size
3977 // of 2048. Also certain devices will have sector count == 0x00, check
3981 if ((srb
->Cdb
[0] == 0x25) &&
3982 ((deviceExtension
->IdentifyData
[srb
->TargetId
].GeneralConfiguration
>> 8) & 0x1f) == 0x05) {
3984 deviceExtension
->DataBuffer
-= wordCount
;
3985 if (deviceExtension
->DataBuffer
[0] == 0x00) {
3987 *((ULONG
*) &(deviceExtension
->DataBuffer
[0])) = 0xFFFFFF7F;
3991 *((ULONG
*) &(deviceExtension
->DataBuffer
[2])) = 0x00080000;
3992 deviceExtension
->DataBuffer
+= wordCount
;
3997 // Completion for IDE drives.
4001 if (deviceExtension
->WordsLeft
) {
4003 status
= SRB_STATUS_DATA_OVERRUN
;
4007 status
= SRB_STATUS_SUCCESS
;
4011 goto CompleteRequest
;
4018 } else if (interruptReason
== 0x3 && !(statusByte
& IDE_STATUS_DRQ
)) {
4021 // Command complete.
4024 if (deviceExtension
->WordsLeft
) {
4026 status
= SRB_STATUS_DATA_OVERRUN
;
4030 status
= SRB_STATUS_SUCCESS
;
4037 // Check and see if we are processing our secret (mechanism status/request sense) srb
4039 if (deviceExtension
->OriginalSrb
) {
4043 if (srb
->Cdb
[0] == SCSIOP_MECHANISM_STATUS
) {
4045 if (status
== SRB_STATUS_SUCCESS
) {
4047 AtapiHwInitializeChanger (HwDeviceExtension
,
4049 (PMECHANICAL_STATUS_INFORMATION_HEADER
) srb
->DataBuffer
);
4051 // Get ready to issue the original srb
4052 srb
= deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
4053 deviceExtension
->OriginalSrb
= NULL
;
4056 // failed! Get the sense key and maybe try again
4057 srb
= deviceExtension
->CurrentSrb
= BuildRequestSenseSrb (
4059 deviceExtension
->OriginalSrb
->PathId
,
4060 deviceExtension
->OriginalSrb
->TargetId
);
4063 srbStatus
= AtapiSendCommand(HwDeviceExtension
, deviceExtension
->CurrentSrb
);
4064 if (srbStatus
== SRB_STATUS_PENDING
) {
4068 } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
4070 PSENSE_DATA senseData
= (PSENSE_DATA
) srb
->DataBuffer
;
4072 if (status
== SRB_STATUS_DATA_OVERRUN
) {
4073 // Check to see if we at least get mininum number of bytes
4074 if ((srb
->DataTransferLength
- deviceExtension
->WordsLeft
) >
4075 (FIELD_OFFSET (SENSE_DATA
, AdditionalSenseLength
) + sizeof(senseData
->AdditionalSenseLength
))) {
4076 status
= SRB_STATUS_SUCCESS
;
4080 if (status
== SRB_STATUS_SUCCESS
) {
4081 if ((senseData
->SenseKey
!= SCSI_SENSE_ILLEGAL_REQUEST
) &&
4082 deviceExtension
->MechStatusRetryCount
) {
4084 // The sense key doesn't say the last request is illegal, so try again
4085 deviceExtension
->MechStatusRetryCount
--;
4086 srb
= deviceExtension
->CurrentSrb
= BuildMechanismStatusSrb (
4088 deviceExtension
->OriginalSrb
->PathId
,
4089 deviceExtension
->OriginalSrb
->TargetId
);
4092 // last request was illegal. No point trying again
4094 AtapiHwInitializeChanger (HwDeviceExtension
,
4096 (PMECHANICAL_STATUS_INFORMATION_HEADER
) NULL
);
4098 // Get ready to issue the original srb
4099 srb
= deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
4100 deviceExtension
->OriginalSrb
= NULL
;
4103 srbStatus
= AtapiSendCommand(HwDeviceExtension
, deviceExtension
->CurrentSrb
);
4104 if (srbStatus
== SRB_STATUS_PENDING
) {
4110 // If we get here, it means AtapiSendCommand() has failed
4111 // Can't recover. Pretend the original srb has failed and complete it.
4113 if (deviceExtension
->OriginalSrb
) {
4114 AtapiHwInitializeChanger (HwDeviceExtension
,
4116 (PMECHANICAL_STATUS_INFORMATION_HEADER
) NULL
);
4117 srb
= deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
4118 deviceExtension
->OriginalSrb
= NULL
;
4121 // fake an error and read no data
4122 status
= SRB_STATUS_ERROR
;
4123 srb
->ScsiStatus
= 0;
4124 deviceExtension
->DataBuffer
= srb
->DataBuffer
;
4125 deviceExtension
->WordsLeft
= srb
->DataTransferLength
;
4126 deviceExtension
->RDP
= FALSE
;
4128 } else if (status
== SRB_STATUS_ERROR
) {
4131 // Map error to specific SRB status and handle request sense.
4134 status
= MapError(deviceExtension
,
4137 deviceExtension
->RDP
= FALSE
;
4142 // Wait for busy to drop.
4145 for (i
= 0; i
< 30; i
++) {
4146 GetStatus(baseIoAddress2
,statusByte
);
4147 if (!(statusByte
& IDE_STATUS_BUSY
)) {
4150 ScsiPortStallExecution(500);
4156 // reset the controller.
4160 "AtapiInterrupt: Resetting due to BSY still up - %x. Base Io %x\n",
4163 AtapiResetController(HwDeviceExtension
,srb
->PathId
);
4168 // Check to see if DRQ is still up.
4171 if (statusByte
& IDE_STATUS_DRQ
) {
4173 for (i
= 0; i
< 500; i
++) {
4174 GetStatus(baseIoAddress2
,statusByte
);
4175 if (!(statusByte
& IDE_STATUS_DRQ
)) {
4178 ScsiPortStallExecution(100);
4185 // reset the controller.
4189 "AtapiInterrupt: Resetting due to DRQ still up - %x\n",
4191 AtapiResetController(HwDeviceExtension
,srb
->PathId
);
4200 // Clear interrupt expecting flag.
4203 deviceExtension
->ExpectingInterrupt
= FALSE
;
4206 // Sanity check that there is a current request.
4212 // Set status in SRB.
4215 srb
->SrbStatus
= (UCHAR
)status
;
4218 // Check for underflow.
4221 if (deviceExtension
->WordsLeft
) {
4224 // Subtract out residual words and update if filemark hit,
4225 // setmark hit , end of data, end of media...
4228 if (!(deviceExtension
->DeviceFlags
[srb
->TargetId
] & DFLAGS_TAPE_DEVICE
)) {
4229 if (status
== SRB_STATUS_DATA_OVERRUN
) {
4230 srb
->DataTransferLength
-= deviceExtension
->WordsLeft
;
4232 srb
->DataTransferLength
= 0;
4235 srb
->DataTransferLength
-= deviceExtension
->WordsLeft
;
4239 if (srb
->Function
!= SRB_FUNCTION_IO_CONTROL
) {
4242 // Indicate command complete.
4245 if (!(deviceExtension
->RDP
)) {
4246 ScsiPortNotification(RequestComplete
,
4253 PSENDCMDOUTPARAMS cmdOutParameters
= (PSENDCMDOUTPARAMS
)(((PUCHAR
)srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
4256 if (status
!= SRB_STATUS_SUCCESS
) {
4257 error
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
4261 // Build the SMART status block depending upon the completion status.
4264 cmdOutParameters
->cBufferSize
= wordCount
;
4265 cmdOutParameters
->DriverStatus
.bDriverError
= (error
) ? SMART_IDE_ERROR
: 0;
4266 cmdOutParameters
->DriverStatus
.bIDEError
= error
;
4269 // If the sub-command is return smart status, jam the value from cylinder low and high, into the
4273 if (deviceExtension
->SmartCommand
== RETURN_SMART_STATUS
) {
4274 cmdOutParameters
->bBuffer
[0] = RETURN_SMART_STATUS
;
4275 cmdOutParameters
->bBuffer
[1] = ScsiPortReadPortUchar(&baseIoAddress1
->InterruptReason
);
4276 cmdOutParameters
->bBuffer
[2] = ScsiPortReadPortUchar(&baseIoAddress1
->Unused1
);
4277 cmdOutParameters
->bBuffer
[3] = ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountLow
);
4278 cmdOutParameters
->bBuffer
[4] = ScsiPortReadPortUchar(&baseIoAddress1
->ByteCountHigh
);
4279 cmdOutParameters
->bBuffer
[5] = ScsiPortReadPortUchar(&baseIoAddress1
->DriveSelect
);
4280 cmdOutParameters
->bBuffer
[6] = SMART_CMD
;
4281 cmdOutParameters
->cBufferSize
= 8;
4285 // Indicate command complete.
4288 ScsiPortNotification(RequestComplete
,
4297 "AtapiInterrupt: No SRB!\n"));
4301 // Indicate ready for next request.
4304 if (!(deviceExtension
->RDP
)) {
4307 // Clear current SRB.
4310 deviceExtension
->CurrentSrb
= NULL
;
4312 ScsiPortNotification(NextRequest
,
4317 ScsiPortNotification(RequestTimerCall
,
4332 "AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n",
4340 } // end AtapiInterrupt()
4345 IdeSendSmartCommand(
4346 IN PVOID HwDeviceExtension
,
4347 IN PSCSI_REQUEST_BLOCK Srb
4352 Routine Description:
4354 This routine handles SMART enable, disable, read attributes and threshold commands.
4358 HwDeviceExtension - HBA miniport driver's adapter data storage
4359 Srb - IO request packet
4368 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
4369 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
4370 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
4371 PSENDCMDOUTPARAMS cmdOutParameters
= (PSENDCMDOUTPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
4372 SENDCMDINPARAMS cmdInParameters
= *(PSENDCMDINPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
4373 PIDEREGS regs
= &cmdInParameters
.irDriveRegs
;
4375 UCHAR statusByte
,targetId
;
4378 if (cmdInParameters
.irDriveRegs
.bCommandReg
== SMART_CMD
) {
4380 targetId
= cmdInParameters
.bDriveNumber
;
4382 //TODO optimize this check
4384 if ((!(deviceExtension
->DeviceFlags
[targetId
] & DFLAGS_DEVICE_PRESENT
)) ||
4385 (deviceExtension
->DeviceFlags
[targetId
] & DFLAGS_ATAPI_DEVICE
)) {
4387 return SRB_STATUS_SELECTION_TIMEOUT
;
4390 deviceExtension
->SmartCommand
= cmdInParameters
.irDriveRegs
.bFeaturesReg
;
4393 // Determine which of the commands to carry out.
4396 if ((cmdInParameters
.irDriveRegs
.bFeaturesReg
== READ_ATTRIBUTES
) ||
4397 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== READ_THRESHOLDS
)) {
4399 WaitOnBusy(baseIoAddress2
,statusByte
);
4401 if (statusByte
& IDE_STATUS_BUSY
) {
4403 "IdeSendSmartCommand: Returning BUSY status\n"));
4404 return SRB_STATUS_BUSY
;
4408 // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same).
4411 for (i
= 0; i
< (sizeof(SENDCMDOUTPARAMS
) + READ_ATTRIBUTE_BUFFER_SIZE
- 1); i
++) {
4412 ((PUCHAR
)cmdOutParameters
)[i
] = 0;
4416 // Set data buffer pointer and words left.
4419 deviceExtension
->DataBuffer
= (PUSHORT
)cmdOutParameters
->bBuffer
;
4420 deviceExtension
->WordsLeft
= READ_ATTRIBUTE_BUFFER_SIZE
/ 2;
4423 // Indicate expecting an interrupt.
4426 deviceExtension
->ExpectingInterrupt
= TRUE
;
4428 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,(UCHAR
)(((targetId
& 0x1) << 4) | 0xA0));
4429 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress1
+ 1,regs
->bFeaturesReg
);
4430 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,regs
->bSectorCountReg
);
4431 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,regs
->bSectorNumberReg
);
4432 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,regs
->bCylLowReg
);
4433 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,regs
->bCylHighReg
);
4434 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,regs
->bCommandReg
);
4437 // Wait for interrupt.
4440 return SRB_STATUS_PENDING
;
4442 } else if ((cmdInParameters
.irDriveRegs
.bFeaturesReg
== ENABLE_SMART
) ||
4443 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== DISABLE_SMART
) ||
4444 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== RETURN_SMART_STATUS
) ||
4445 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== ENABLE_DISABLE_AUTOSAVE
) ||
4446 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== EXECUTE_OFFLINE_DIAGS
) ||
4447 (cmdInParameters
.irDriveRegs
.bFeaturesReg
== SAVE_ATTRIBUTE_VALUES
)) {
4449 WaitOnBusy(baseIoAddress2
,statusByte
);
4451 if (statusByte
& IDE_STATUS_BUSY
) {
4453 "IdeSendSmartCommand: Returning BUSY status\n"));
4454 return SRB_STATUS_BUSY
;
4458 // Zero the ouput buffer as the input buffer info. has been saved off locally (the buffers are the same).
4461 for (i
= 0; i
< (sizeof(SENDCMDOUTPARAMS
) - 1); i
++) {
4462 ((PUCHAR
)cmdOutParameters
)[i
] = 0;
4466 // Set data buffer pointer and indicate no data transfer.
4469 deviceExtension
->DataBuffer
= (PUSHORT
)cmdOutParameters
->bBuffer
;
4470 deviceExtension
->WordsLeft
= 0;
4473 // Indicate expecting an interrupt.
4476 deviceExtension
->ExpectingInterrupt
= TRUE
;
4478 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,(UCHAR
)(((targetId
& 0x1) << 4) | 0xA0));
4479 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress1
+ 1,regs
->bFeaturesReg
);
4480 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,regs
->bSectorCountReg
);
4481 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,regs
->bSectorNumberReg
);
4482 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,regs
->bCylLowReg
);
4483 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,regs
->bCylHighReg
);
4484 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,regs
->bCommandReg
);
4487 // Wait for interrupt.
4490 return SRB_STATUS_PENDING
;
4494 return SRB_STATUS_INVALID_REQUEST
;
4496 } // end IdeSendSmartCommand()
4502 IN PVOID HwDeviceExtension
,
4503 IN PSCSI_REQUEST_BLOCK Srb
4508 Routine Description:
4510 This routine handles IDE read and writes.
4514 HwDeviceExtension - HBA miniport driver's adapter data storage
4515 Srb - IO request packet
4524 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
4525 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
4526 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
4527 ULONG startingSector
,i
;
4529 UCHAR statusByte
,statusByte2
;
4530 UCHAR cylinderHigh
,cylinderLow
,drvSelect
,sectorNumber
;
4533 // Select device 0 or 1.
4536 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
4537 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
4539 WaitOnBusy(baseIoAddress2
,statusByte2
);
4541 if (statusByte2
& IDE_STATUS_BUSY
) {
4543 "IdeReadWrite: Returning BUSY status\n"));
4544 return SRB_STATUS_BUSY
;
4548 // Set data buffer pointer and words left.
4551 deviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
4552 deviceExtension
->WordsLeft
= Srb
->DataTransferLength
/ 2;
4555 // Indicate expecting an interrupt.
4558 deviceExtension
->ExpectingInterrupt
= TRUE
;
4561 // Set up sector count register. Round up to next block.
4564 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,
4565 (UCHAR
)((Srb
->DataTransferLength
+ 0x1FF) / 0x200));
4568 // Get starting sector number from CDB.
4571 startingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
4572 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
4573 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
4574 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
4577 "IdeReadWrite: Starting sector is %x, Number of bytes %x\n",
4579 Srb
->DataTransferLength
));
4582 // Set up sector number register.
4585 sectorNumber
= (UCHAR
)((startingSector
% deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) + 1);
4586 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,sectorNumber
);
4589 // Set up cylinder low register.
4592 cylinderLow
= (UCHAR
)(startingSector
/ (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4593 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
));
4594 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,cylinderLow
);
4597 // Set up cylinder high register.
4600 cylinderHigh
= (UCHAR
)((startingSector
/ (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4601 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
)) >> 8);
4602 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,cylinderHigh
);
4605 // Set up head and drive select register.
4608 drvSelect
= (UCHAR
)(((startingSector
/ deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4609 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
) |((Srb
->TargetId
& 0x1) << 4) | 0xA0);
4610 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,drvSelect
);
4613 "IdeReadWrite: Cylinder %x Head %x Sector %x\n",
4615 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4616 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
),
4618 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4619 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
,
4621 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
+ 1));
4624 // Check if write request.
4627 if (Srb
->SrbFlags
& SRB_FLAGS_DATA_IN
) {
4630 // Send read command.
4633 if (deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
]) {
4634 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4635 IDE_COMMAND_READ_MULTIPLE
);
4638 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4645 // Send write command.
4648 if (deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
]) {
4649 wordCount
= 256 * deviceExtension
->MaximumBlockXfer
[Srb
->TargetId
];
4651 if (deviceExtension
->WordsLeft
< wordCount
) {
4654 // Transfer only words requested.
4657 wordCount
= deviceExtension
->WordsLeft
;
4660 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4661 IDE_COMMAND_WRITE_MULTIPLE
);
4665 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4670 // Wait for BSY and DRQ.
4673 WaitOnBaseBusy(baseIoAddress1
,statusByte
);
4675 if (statusByte
& IDE_STATUS_BUSY
) {
4678 "IdeReadWrite 2: Returning BUSY status %x\n",
4680 return SRB_STATUS_BUSY
;
4683 for (i
= 0; i
< 1000; i
++) {
4684 GetBaseStatus(baseIoAddress1
, statusByte
);
4685 if (statusByte
& IDE_STATUS_DRQ
) {
4688 ScsiPortStallExecution(200);
4692 if (!(statusByte
& IDE_STATUS_DRQ
)) {
4695 "IdeReadWrite: DRQ never asserted (%x) original status (%x)\n",
4699 deviceExtension
->WordsLeft
= 0;
4702 // Clear interrupt expecting flag.
4705 deviceExtension
->ExpectingInterrupt
= FALSE
;
4708 // Clear current SRB.
4711 deviceExtension
->CurrentSrb
= NULL
;
4713 return SRB_STATUS_TIMEOUT
;
4717 // Write next 256 words.
4720 WriteBuffer(baseIoAddress1
,
4721 deviceExtension
->DataBuffer
,
4725 // Adjust buffer address and words left count.
4728 deviceExtension
->WordsLeft
-= wordCount
;
4729 deviceExtension
->DataBuffer
+= wordCount
;
4734 // Wait for interrupt.
4737 return SRB_STATUS_PENDING
;
4739 } // end IdeReadWrite()
4746 IN PVOID HwDeviceExtension
,
4747 IN PSCSI_REQUEST_BLOCK Srb
4752 Routine Description:
4754 This routine handles IDE Verify.
4758 HwDeviceExtension - HBA miniport driver's adapter data storage
4759 Srb - IO request packet
4768 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
4769 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
4770 //PIDE_REGISTERS_2 baseIoAddress2 = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
4771 ULONG startingSector
;
4777 // Drive has these number sectors.
4780 sectors
= deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4781 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
*
4782 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfCylinders
;
4785 "IdeVerify: Total sectors %x\n",
4789 // Get starting sector number from CDB.
4792 startingSector
= ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte3
|
4793 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte2
<< 8 |
4794 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte1
<< 16 |
4795 ((PCDB
)Srb
->Cdb
)->CDB10
.LogicalBlockByte0
<< 24;
4798 "IdeVerify: Starting sector %x. Number of blocks %x\n",
4800 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
));
4802 sectorCount
= (USHORT
)(((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksMsb
<< 8 |
4803 ((PCDB
)Srb
->Cdb
)->CDB10
.TransferBlocksLsb
);
4804 endSector
= startingSector
+ sectorCount
;
4807 "IdeVerify: Ending sector %x\n",
4810 if (endSector
> sectors
) {
4813 // Too big, round down.
4817 "IdeVerify: Truncating request to %x blocks\n",
4818 sectors
- startingSector
- 1));
4820 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,
4821 (UCHAR
)(sectors
- startingSector
- 1));
4826 // Set up sector count register. Round up to next block.
4829 if (sectorCount
> 0xFF) {
4830 sectorCount
= (USHORT
)0xFF;
4833 ScsiPortWritePortUchar(&baseIoAddress1
->BlockCount
,(UCHAR
)sectorCount
);
4837 // Set data buffer pointer and words left.
4840 deviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
4841 deviceExtension
->WordsLeft
= Srb
->DataTransferLength
/ 2;
4844 // Indicate expecting an interrupt.
4847 deviceExtension
->ExpectingInterrupt
= TRUE
;
4850 // Set up sector number register.
4853 ScsiPortWritePortUchar(&baseIoAddress1
->BlockNumber
,
4854 (UCHAR
)((startingSector
%
4855 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) + 1));
4858 // Set up cylinder low register.
4861 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderLow
,
4862 (UCHAR
)(startingSector
/
4863 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4864 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
)));
4867 // Set up cylinder high register.
4870 ScsiPortWritePortUchar(&baseIoAddress1
->CylinderHigh
,
4871 (UCHAR
)((startingSector
/
4872 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4873 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
)) >> 8));
4876 // Set up head and drive select register.
4879 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
4880 (UCHAR
)(((startingSector
/
4881 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4882 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
) |
4883 ((Srb
->TargetId
& 0x1) << 4) | 0xA0));
4886 "IdeVerify: Cylinder %x Head %x Sector %x\n",
4888 (deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
*
4889 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
),
4891 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) %
4892 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
,
4894 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
+ 1));
4898 // Send verify command.
4901 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
4902 IDE_COMMAND_VERIFY
);
4905 // Wait for interrupt.
4908 return SRB_STATUS_PENDING
;
4910 } // end IdeVerify()
4916 IN PSCSI_REQUEST_BLOCK Srb
4921 Routine Description:
4923 Convert SCSI packet command to Atapi packet command.
4927 Srb - IO request packet
4936 // Change the cdb length
4939 Srb
->CdbLength
= 12;
4941 switch (Srb
->Cdb
[0]) {
4942 case SCSIOP_MODE_SENSE
: {
4943 PMODE_SENSE_10 modeSense10
= (PMODE_SENSE_10
)Srb
->Cdb
;
4944 UCHAR PageCode
= ((PCDB
)Srb
->Cdb
)->MODE_SENSE
.PageCode
;
4945 UCHAR Length
= ((PCDB
)Srb
->Cdb
)->MODE_SENSE
.AllocationLength
;
4947 AtapiZeroMemory(Srb
->Cdb
,MAXIMUM_CDB_SIZE
);
4949 modeSense10
->OperationCode
= ATAPI_MODE_SENSE
;
4950 modeSense10
->PageCode
= PageCode
;
4951 modeSense10
->ParameterListLengthMsb
= 0;
4952 modeSense10
->ParameterListLengthLsb
= Length
;
4956 case SCSIOP_MODE_SELECT
: {
4957 PMODE_SELECT_10 modeSelect10
= (PMODE_SELECT_10
)Srb
->Cdb
;
4958 UCHAR Length
= ((PCDB
)Srb
->Cdb
)->MODE_SELECT
.ParameterListLength
;
4961 // Zero the original cdb
4964 AtapiZeroMemory(Srb
->Cdb
,MAXIMUM_CDB_SIZE
);
4966 modeSelect10
->OperationCode
= ATAPI_MODE_SELECT
;
4967 modeSelect10
->PFBit
= 1;
4968 modeSelect10
->ParameterListLengthMsb
= 0;
4969 modeSelect10
->ParameterListLengthLsb
= Length
;
4973 case SCSIOP_FORMAT_UNIT
:
4974 Srb
->Cdb
[0] = ATAPI_FORMAT_UNIT
;
4984 IN PVOID HwDeviceExtension
,
4985 IN PSCSI_REQUEST_BLOCK Srb
4990 Routine Description:
4992 Send ATAPI packet command to device.
4996 HwDeviceExtension - HBA miniport driver's adapter data storage
4997 Srb - IO request packet
5005 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5006 PATAPI_REGISTERS_1 baseIoAddress1
= (PATAPI_REGISTERS_1
)deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
5007 PATAPI_REGISTERS_2 baseIoAddress2
= (PATAPI_REGISTERS_2
)deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
5010 UCHAR statusByte
,byteCountLow
,byteCountHigh
;
5013 // We need to know how many platters our atapi cd-rom device might have.
5014 // Before anyone tries to send a srb to our target for the first time,
5015 // we must "secretly" send down a separate mechanism status srb in order to
5016 // initialize our device extension changer data. That's how we know how
5017 // many platters our target has.
5019 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_CHANGER_INITED
) &&
5020 !deviceExtension
->OriginalSrb
) {
5025 // Set this flag now. If the device hangs on the mech. status
5026 // command, we will not have the change to set it.
5028 deviceExtension
->DeviceFlags
[Srb
->TargetId
] |= DFLAGS_CHANGER_INITED
;
5030 deviceExtension
->MechStatusRetryCount
= 3;
5031 deviceExtension
->CurrentSrb
= BuildMechanismStatusSrb (
5035 deviceExtension
->OriginalSrb
= Srb
;
5037 srbStatus
= AtapiSendCommand(HwDeviceExtension
, deviceExtension
->CurrentSrb
);
5038 if (srbStatus
== SRB_STATUS_PENDING
) {
5041 deviceExtension
->CurrentSrb
= deviceExtension
->OriginalSrb
;
5042 deviceExtension
->OriginalSrb
= NULL
;
5043 AtapiHwInitializeChanger (HwDeviceExtension
,
5045 (PMECHANICAL_STATUS_INFORMATION_HEADER
) NULL
);
5051 "AtapiSendCommand: Command %x to TargetId %d lun %d\n",
5057 // Make sure command is to ATAPI device.
5060 flags
= deviceExtension
->DeviceFlags
[Srb
->TargetId
];
5061 if (flags
& (DFLAGS_SANYO_ATAPI_CHANGER
| DFLAGS_ATAPI_CHANGER
)) {
5062 if ((Srb
->Lun
) > (deviceExtension
->DiscsPresent
[Srb
->TargetId
] - 1)) {
5065 // Indicate no device found at this address.
5068 return SRB_STATUS_SELECTION_TIMEOUT
;
5070 } else if (Srb
->Lun
> 0) {
5071 return SRB_STATUS_SELECTION_TIMEOUT
;
5074 if (!(flags
& DFLAGS_ATAPI_DEVICE
)) {
5075 return SRB_STATUS_SELECTION_TIMEOUT
;
5079 // Select device 0 or 1.
5082 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5083 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5086 // Verify that controller is ready for next command.
5089 GetStatus(baseIoAddress2
,statusByte
);
5092 "AtapiSendCommand: Entered with status %x\n",
5095 if (statusByte
& IDE_STATUS_BUSY
) {
5097 "AtapiSendCommand: Device busy (%x)\n",
5099 return SRB_STATUS_BUSY
;
5103 if (statusByte
& IDE_STATUS_ERROR
) {
5104 if (Srb
->Cdb
[0] != SCSIOP_REQUEST_SENSE
) {
5107 "AtapiSendCommand: Error on entry: (%x)\n",
5110 // Read the error reg. to clear it and fail this request.
5113 return MapError(deviceExtension
,
5119 // If a tape drive has doesn't have DSC set and the last command is restrictive, don't send
5120 // the next command. See discussion of Restrictive Delayed Process commands in QIC-157.
5123 if ((!(statusByte
& IDE_STATUS_DSC
)) &&
5124 (flags
& DFLAGS_TAPE_DEVICE
) && deviceExtension
->RDP
) {
5125 ScsiPortStallExecution(1000);
5126 DebugPrint((2,"AtapiSendCommand: DSC not set. %x\n",statusByte
));
5127 return SRB_STATUS_BUSY
;
5130 if (IS_RDP(Srb
->Cdb
[0])) {
5132 deviceExtension
->RDP
= TRUE
;
5135 "AtapiSendCommand: %x mapped as DSC restrictive\n",
5140 deviceExtension
->RDP
= FALSE
;
5143 if (statusByte
& IDE_STATUS_DRQ
) {
5146 "AtapiSendCommand: Entered with status (%x). Attempting to recover.\n",
5149 // Try to drain the data that one preliminary device thinks that it has
5150 // to transfer. Hopefully this random assertion of DRQ will not be present
5151 // in production devices.
5154 for (i
= 0; i
< 0x10000; i
++) {
5156 GetStatus(baseIoAddress2
, statusByte
);
5158 if (statusByte
& IDE_STATUS_DRQ
) {
5160 ScsiPortReadPortUshort(&baseIoAddress1
->Data
);
5171 "AtapiSendCommand: DRQ still asserted.Status (%x)\n",
5174 AtapiSoftReset(baseIoAddress1
,Srb
->TargetId
);
5177 "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
5180 // Re-initialize Atapi device.
5183 IssueIdentify(HwDeviceExtension
,
5184 (Srb
->TargetId
& 0x1),
5185 (Srb
->TargetId
>> 1),
5186 IDE_COMMAND_ATAPI_IDENTIFY
);
5189 // Inform the port driver that the bus has been reset.
5192 ScsiPortNotification(ResetDetected
, HwDeviceExtension
, 0);
5195 // Clean up device extension fields that AtapiStartIo won't.
5198 deviceExtension
->ExpectingInterrupt
= FALSE
;
5199 deviceExtension
->RDP
= FALSE
;
5201 return SRB_STATUS_BUS_RESET
;
5206 if (flags
& (DFLAGS_SANYO_ATAPI_CHANGER
| DFLAGS_ATAPI_CHANGER
)) {
5209 // As the cdrom driver sets the LUN field in the cdb, it must be removed.
5212 Srb
->Cdb
[1] &= ~0xE0;
5214 if ((Srb
->Cdb
[0] == SCSIOP_TEST_UNIT_READY
) && (flags
& DFLAGS_SANYO_ATAPI_CHANGER
)) {
5217 // Torisan changer. TUR's are overloaded to be platter switches.
5220 Srb
->Cdb
[7] = Srb
->Lun
;
5226 // Convert SCSI to ATAPI commands if needed
5229 switch (Srb
->Cdb
[0]) {
5230 case SCSIOP_MODE_SENSE
:
5231 case SCSIOP_MODE_SELECT
:
5232 case SCSIOP_FORMAT_UNIT
:
5233 if (!(flags
& DFLAGS_TAPE_DEVICE
)) {
5241 // Set data buffer pointer and words left.
5244 deviceExtension
->DataBuffer
= (PUSHORT
)Srb
->DataBuffer
;
5245 deviceExtension
->WordsLeft
= Srb
->DataTransferLength
/ 2;
5247 WaitOnBusy(baseIoAddress2
,statusByte
);
5250 // Write transfer byte count to registers.
5253 byteCountLow
= (UCHAR
)(Srb
->DataTransferLength
& 0xFF);
5254 byteCountHigh
= (UCHAR
)(Srb
->DataTransferLength
>> 8);
5256 if (Srb
->DataTransferLength
>= 0x10000) {
5257 byteCountLow
= byteCountHigh
= 0xFF;
5260 ScsiPortWritePortUchar(&baseIoAddress1
->ByteCountLow
,byteCountLow
);
5261 ScsiPortWritePortUchar(&baseIoAddress1
->ByteCountHigh
, byteCountHigh
);
5263 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress1
+ 1,0);
5266 if (flags
& DFLAGS_INT_DRQ
) {
5269 // This device interrupts when ready to receive the packet.
5271 // Write ATAPI packet command.
5274 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
5275 IDE_COMMAND_ATAPI_PACKET
);
5278 "AtapiSendCommand: Wait for int. to send packet. Status (%x)\n",
5281 deviceExtension
->ExpectingInterrupt
= TRUE
;
5283 return SRB_STATUS_PENDING
;
5288 // Write ATAPI packet command.
5291 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,
5292 IDE_COMMAND_ATAPI_PACKET
);
5298 WaitOnBusy(baseIoAddress2
, statusByte
);
5299 WaitForDrq(baseIoAddress2
, statusByte
);
5301 if (!(statusByte
& IDE_STATUS_DRQ
)) {
5304 "AtapiSendCommand: DRQ never asserted (%x)\n",
5306 return SRB_STATUS_ERROR
;
5311 // Need to read status register.
5314 GetBaseStatus(baseIoAddress1
, statusByte
);
5317 // Send CDB to device.
5320 WaitOnBusy(baseIoAddress2
,statusByte
);
5322 WriteBuffer(baseIoAddress1
,
5327 // Indicate expecting an interrupt and wait for it.
5330 deviceExtension
->ExpectingInterrupt
= TRUE
;
5332 return SRB_STATUS_PENDING
;
5334 } // end AtapiSendCommand()
5339 IN PVOID HwDeviceExtension
,
5340 IN PSCSI_REQUEST_BLOCK Srb
5345 Routine Description:
5347 Program ATA registers for IDE disk transfer.
5351 HwDeviceExtension - ATAPI driver storage.
5352 Srb - System request block.
5356 SRB status (pending if all goes well).
5361 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5362 PIDE_REGISTERS_1 baseIoAddress1
= deviceExtension
->BaseIoAddress1
[Srb
->TargetId
>> 1];
5363 PIDE_REGISTERS_2 baseIoAddress2
= deviceExtension
->BaseIoAddress2
[Srb
->TargetId
>> 1];
5366 UCHAR statusByte
,errorByte
;
5369 PMODE_PARAMETER_HEADER modeData
;
5372 "IdeSendCommand: Command %x to device %d\n",
5378 switch (Srb
->Cdb
[0]) {
5379 case SCSIOP_INQUIRY
:
5382 // Filter out all TIDs but 0 and 1 since this is an IDE interface
5383 // which support up to two devices.
5386 if ((Srb
->Lun
!= 0) ||
5387 (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
))) {
5390 // Indicate no device found at this address.
5393 status
= SRB_STATUS_SELECTION_TIMEOUT
;
5398 PINQUIRYDATA inquiryData
= Srb
->DataBuffer
;
5399 PIDENTIFY_DATA2 identifyData
= &deviceExtension
->IdentifyData
[Srb
->TargetId
];
5402 // Zero INQUIRY data structure.
5405 for (i
= 0; i
< Srb
->DataTransferLength
; i
++) {
5406 ((PUCHAR
)Srb
->DataBuffer
)[i
] = 0;
5410 // Standard IDE interface only supports disks.
5413 inquiryData
->DeviceType
= DIRECT_ACCESS_DEVICE
;
5416 // Set the removable bit, if applicable.
5419 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_REMOVABLE_DRIVE
) {
5420 inquiryData
->RemovableMedia
= 1;
5424 // Fill in vendor identification fields.
5427 for (i
= 0; i
< 8; i
+= 2) {
5428 inquiryData
->VendorId
[i
] =
5429 ((PUCHAR
)identifyData
->ModelNumber
)[i
+ 1];
5430 inquiryData
->VendorId
[i
+1] =
5431 ((PUCHAR
)identifyData
->ModelNumber
)[i
];
5434 for (i
= 0; i
< 12; i
+= 2) {
5435 inquiryData
->ProductId
[i
] =
5436 ((PUCHAR
)identifyData
->ModelNumber
)[i
+ 8 + 1];
5437 inquiryData
->ProductId
[i
+1] =
5438 ((PUCHAR
)identifyData
->ModelNumber
)[i
+ 8];
5442 // Initialize unused portion of product id.
5445 for (i
= 0; i
< 4; i
++) {
5446 inquiryData
->ProductId
[12+i
] = ' ';
5450 // Move firmware revision from IDENTIFY data to
5451 // product revision in INQUIRY data.
5454 for (i
= 0; i
< 4; i
+= 2) {
5455 inquiryData
->ProductRevisionLevel
[i
] =
5456 ((PUCHAR
)identifyData
->FirmwareRevision
)[i
+1];
5457 inquiryData
->ProductRevisionLevel
[i
+1] =
5458 ((PUCHAR
)identifyData
->FirmwareRevision
)[i
];
5461 status
= SRB_STATUS_SUCCESS
;
5466 case SCSIOP_MODE_SENSE
:
5469 // This is used to determine of the media is write-protected.
5470 // Since IDE does not support mode sense then we will modify just the portion we need
5471 // so the higher level driver can determine if media is protected.
5474 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
) {
5476 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5477 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5478 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,IDE_COMMAND_GET_MEDIA_STATUS
);
5479 WaitOnBusy(baseIoAddress2
,statusByte
);
5481 if (!(statusByte
& IDE_STATUS_ERROR
)){
5484 // no error occured return success, media is not protected
5487 deviceExtension
->ExpectingInterrupt
= FALSE
;
5488 status
= SRB_STATUS_SUCCESS
;
5493 // error occured, handle it locally, clear interrupt
5496 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
5498 GetBaseStatus(baseIoAddress1
, statusByte
);
5499 deviceExtension
->ExpectingInterrupt
= FALSE
;
5500 status
= SRB_STATUS_SUCCESS
;
5502 if (errorByte
& IDE_ERROR_DATA_ERROR
) {
5505 //media is write-protected, set bit in mode sense buffer
5508 modeData
= (PMODE_PARAMETER_HEADER
)Srb
->DataBuffer
;
5510 Srb
->DataTransferLength
= sizeof(MODE_PARAMETER_HEADER
);
5511 modeData
->DeviceSpecificParameter
|= MODE_DSP_WRITE_PROTECT
;
5514 status
= SRB_STATUS_SUCCESS
;
5516 status
= SRB_STATUS_INVALID_REQUEST
;
5520 case SCSIOP_TEST_UNIT_READY
:
5522 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
) {
5525 // Select device 0 or 1.
5528 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5529 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5530 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,IDE_COMMAND_GET_MEDIA_STATUS
);
5533 // Wait for busy. If media has not changed, return success
5536 WaitOnBusy(baseIoAddress2
,statusByte
);
5538 if (!(statusByte
& IDE_STATUS_ERROR
)){
5539 deviceExtension
->ExpectingInterrupt
= FALSE
;
5540 status
= SRB_STATUS_SUCCESS
;
5542 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress1
+ 1);
5543 if (errorByte
== IDE_ERROR_DATA_ERROR
){
5546 // Special case: If current media is write-protected,
5547 // the 0xDA command will always fail since the write-protect bit
5548 // is sticky,so we can ignore this error
5551 GetBaseStatus(baseIoAddress1
, statusByte
);
5552 deviceExtension
->ExpectingInterrupt
= FALSE
;
5553 status
= SRB_STATUS_SUCCESS
;
5558 // Request sense buffer to be build
5560 deviceExtension
->ExpectingInterrupt
= TRUE
;
5561 status
= SRB_STATUS_PENDING
;
5565 status
= SRB_STATUS_SUCCESS
;
5570 case SCSIOP_READ_CAPACITY
:
5573 // Claim 512 byte blocks (big-endian).
5576 ((PREAD_CAPACITY_DATA
)Srb
->DataBuffer
)->BytesPerBlock
= 0x20000;
5579 // Calculate last sector.
5583 i
= (deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
*
5584 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfCylinders
*
5585 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
) - 1;
5587 ((PREAD_CAPACITY_DATA
)Srb
->DataBuffer
)->LogicalBlockAddress
=
5588 (((PUCHAR
)&i
)[0] << 24) | (((PUCHAR
)&i
)[1] << 16) |
5589 (((PUCHAR
)&i
)[2] << 8) | ((PUCHAR
)&i
)[3];
5592 "IDE disk %x - #sectors %x, #heads %x, #cylinders %x\n",
5594 deviceExtension
->IdentifyData
[Srb
->TargetId
].SectorsPerTrack
,
5595 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfHeads
,
5596 deviceExtension
->IdentifyData
[Srb
->TargetId
].NumberOfCylinders
));
5599 status
= SRB_STATUS_SUCCESS
;
5603 status
= IdeVerify(HwDeviceExtension
,Srb
);
5610 status
= IdeReadWrite(HwDeviceExtension
,
5614 case SCSIOP_START_STOP_UNIT
:
5617 //Determine what type of operation we should perform
5619 cdb
= (PCDB
)Srb
->Cdb
;
5621 if (cdb
->START_STOP
.LoadEject
== 1){
5625 // first select device 0 or 1.
5627 ScsiPortWritePortUchar(&baseIoAddress1
->DriveSelect
,
5628 (UCHAR
)(((Srb
->TargetId
& 0x1) << 4) | 0xA0));
5629 ScsiPortWritePortUchar(&baseIoAddress1
->Command
,IDE_COMMAND_MEDIA_EJECT
);
5631 status
= SRB_STATUS_SUCCESS
;
5634 case SCSIOP_REQUEST_SENSE
:
5635 // this function makes sense buffers to report the results
5636 // of the original GET_MEDIA_STATUS command
5638 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_MEDIA_STATUS_ENABLED
) {
5639 status
= IdeBuildSenseBuffer(HwDeviceExtension
,Srb
);
5646 "IdeSendCommand: Unsupported command %x\n",
5649 status
= SRB_STATUS_INVALID_REQUEST
;
5655 } // end IdeSendCommand()
5661 IN PVOID HwDeviceExtension
,
5666 Routine Description:
5668 Enables disables media status notification
5672 HwDeviceExtension - ATAPI driver storage.
5677 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5678 PIDE_REGISTERS_1 baseIoAddress
= deviceExtension
->BaseIoAddress1
[Channel
>> 1];
5679 UCHAR statusByte
,errorByte
;
5682 if (EnableMSN
== TRUE
){
5685 // If supported enable Media Status Notification support
5688 if ((deviceExtension
->DeviceFlags
[Channel
] & DFLAGS_REMOVABLE_DRIVE
)) {
5693 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress
+ 1,(UCHAR
) (0x95));
5694 ScsiPortWritePortUchar(&baseIoAddress
->Command
,
5695 IDE_COMMAND_ENABLE_MEDIA_STATUS
);
5697 WaitOnBaseBusy(baseIoAddress
,statusByte
);
5699 if (statusByte
& IDE_STATUS_ERROR
) {
5701 // Read the error register.
5703 errorByte
= ScsiPortReadPortUchar((PUCHAR
)baseIoAddress
+ 1);
5706 "IdeMediaStatus: Error enabling media status. Status %x, error byte %x\n",
5710 deviceExtension
->DeviceFlags
[Channel
] |= DFLAGS_MEDIA_STATUS_ENABLED
;
5711 DebugPrint((1,"IdeMediaStatus: Media Status Notification Supported\n"));
5712 deviceExtension
->ReturningMediaStatus
= 0;
5717 } else { // end if EnableMSN == TRUE
5720 // disable if previously enabled
5722 if ((deviceExtension
->DeviceFlags
[Channel
] & DFLAGS_MEDIA_STATUS_ENABLED
)) {
5724 ScsiPortWritePortUchar((PUCHAR
)baseIoAddress
+ 1,(UCHAR
) (0x31));
5725 ScsiPortWritePortUchar(&baseIoAddress
->Command
,
5726 IDE_COMMAND_ENABLE_MEDIA_STATUS
);
5728 WaitOnBaseBusy(baseIoAddress
,statusByte
);
5729 deviceExtension
->DeviceFlags
[Channel
] &= ~DFLAGS_MEDIA_STATUS_ENABLED
;
5741 IdeBuildSenseBuffer(
5742 IN PVOID HwDeviceExtension
,
5743 IN PSCSI_REQUEST_BLOCK Srb
5748 Routine Description:
5750 Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS
5751 command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE.
5754 HwDeviceExtension - ATAPI driver storage.
5755 Srb - System request block.
5759 SRB status (ALWAYS SUCCESS).
5764 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5765 PSENSE_DATA senseBuffer
= (PSENSE_DATA
)Srb
->DataBuffer
;
5771 if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_MEDIA_CHANGE
) {
5773 senseBuffer
->ErrorCode
= 0x70;
5774 senseBuffer
->Valid
= 1;
5775 senseBuffer
->AdditionalSenseLength
= 0xb;
5776 senseBuffer
->SenseKey
= SCSI_SENSE_UNIT_ATTENTION
;
5777 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_MEDIUM_CHANGED
;
5778 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5779 } else if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_MEDIA_CHANGE_REQ
) {
5781 senseBuffer
->ErrorCode
= 0x70;
5782 senseBuffer
->Valid
= 1;
5783 senseBuffer
->AdditionalSenseLength
= 0xb;
5784 senseBuffer
->SenseKey
= SCSI_SENSE_UNIT_ATTENTION
;
5785 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_MEDIUM_CHANGED
;
5786 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5787 } else if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_END_OF_MEDIA
) {
5789 senseBuffer
->ErrorCode
= 0x70;
5790 senseBuffer
->Valid
= 1;
5791 senseBuffer
->AdditionalSenseLength
= 0xb;
5792 senseBuffer
->SenseKey
= SCSI_SENSE_NOT_READY
;
5793 senseBuffer
->AdditionalSenseCode
= SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
;
5794 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5795 } else if(deviceExtension
->ReturningMediaStatus
& IDE_ERROR_DATA_ERROR
) {
5797 senseBuffer
->ErrorCode
= 0x70;
5798 senseBuffer
->Valid
= 1;
5799 senseBuffer
->AdditionalSenseLength
= 0xb;
5800 senseBuffer
->SenseKey
= SCSI_SENSE_DATA_PROTECT
;
5801 senseBuffer
->AdditionalSenseCode
= 0;
5802 senseBuffer
->AdditionalSenseCodeQualifier
= 0;
5804 return SRB_STATUS_SUCCESS
;
5806 return SRB_STATUS_ERROR
;
5808 }// End of IdeBuildSenseBuffer
5816 IN PVOID HwDeviceExtension
,
5817 IN PSCSI_REQUEST_BLOCK Srb
5822 Routine Description:
5824 This routine is called from the SCSI port driver synchronized
5825 with the kernel to start an IO request.
5829 HwDeviceExtension - HBA miniport driver's adapter data storage
5830 Srb - IO request packet
5839 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
5843 // Determine which function.
5846 switch (Srb
->Function
) {
5848 case SRB_FUNCTION_EXECUTE_SCSI
:
5851 // Sanity check. Only one request can be outstanding on a
5855 if (deviceExtension
->CurrentSrb
) {
5858 "AtapiStartIo: Already have a request!\n"));
5859 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
5860 ScsiPortNotification(RequestComplete
,
5867 // Indicate that a request is active on the controller.
5870 deviceExtension
->CurrentSrb
= Srb
;
5873 // Send command to device.
5876 if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
) {
5878 status
= AtapiSendCommand(HwDeviceExtension
,
5881 } else if (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
) {
5883 status
= IdeSendCommand(HwDeviceExtension
,
5887 status
= SRB_STATUS_SELECTION_TIMEOUT
;
5892 case SRB_FUNCTION_ABORT_COMMAND
:
5895 // Verify that SRB to abort is still outstanding.
5898 if (!deviceExtension
->CurrentSrb
) {
5900 DebugPrint((1, "AtapiStartIo: SRB to abort already completed\n"));
5903 // Complete abort SRB.
5906 status
= SRB_STATUS_ABORT_FAILED
;
5912 // Abort function indicates that a request timed out.
5913 // Call reset routine. Card will only be reset if
5914 // status indicates something is wrong.
5915 // Fall through to reset code.
5918 case SRB_FUNCTION_RESET_BUS
:
5921 // Reset Atapi and SCSI bus.
5924 DebugPrint((1, "AtapiStartIo: Reset bus request received\n"));
5926 if (!AtapiResetController(deviceExtension
,
5929 DebugPrint((1,"AtapiStartIo: Reset bus failed\n"));
5932 // Log reset failure.
5941 SP_INTERNAL_ADAPTER_ERROR
,
5945 status
= SRB_STATUS_ERROR
;
5949 status
= SRB_STATUS_SUCCESS
;
5954 case SRB_FUNCTION_IO_CONTROL
:
5956 if (deviceExtension
->CurrentSrb
) {
5959 "AtapiStartIo: Already have a request!\n"));
5960 Srb
->SrbStatus
= SRB_STATUS_BUSY
;
5961 ScsiPortNotification(RequestComplete
,
5968 // Indicate that a request is active on the controller.
5971 deviceExtension
->CurrentSrb
= Srb
;
5973 if (AtapiStringCmp( (PCHAR
)((PSRB_IO_CONTROL
)(Srb
->DataBuffer
))->Signature
,"SCSIDISK",strlen("SCSIDISK"))) {
5976 "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s\n",
5977 ((PSRB_IO_CONTROL
)(Srb
->DataBuffer
))->Signature
,
5980 status
= SRB_STATUS_INVALID_REQUEST
;
5984 switch (((PSRB_IO_CONTROL
)(Srb
->DataBuffer
))->ControlCode
) {
5986 case IOCTL_SCSI_MINIPORT_SMART_VERSION
: {
5988 PGETVERSIONINPARAMS versionParameters
= (PGETVERSIONINPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
5992 // Version and revision per SMART 1.03
5995 versionParameters
->bVersion
= 1;
5996 versionParameters
->bRevision
= 1;
5997 versionParameters
->bReserved
= 0;
6000 // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
6003 versionParameters
->fCapabilities
= (CAP_ATA_ID_CMD
| CAP_ATAPI_ID_CMD
| CAP_SMART_CMD
);
6006 // This is done because of how the IOCTL_SCSI_MINIPORT
6007 // determines 'targetid's'. Disk.sys places the real target id value
6008 // in the DeviceMap field. Once we do some parameter checking, the value passed
6009 // back to the application will be determined.
6012 deviceNumber
= versionParameters
->bIDEDeviceMap
;
6014 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
) ||
6015 (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
)) {
6017 status
= SRB_STATUS_SELECTION_TIMEOUT
;
6022 // NOTE: This will only set the bit
6023 // corresponding to this drive's target id.
6024 // The bit mask is as follows:
6031 if (deviceExtension
->NumberChannels
== 1) {
6032 if (deviceExtension
->PrimaryAddress
) {
6033 deviceNumber
= 1 << Srb
->TargetId
;
6035 deviceNumber
= 4 << Srb
->TargetId
;
6038 deviceNumber
= 1 << Srb
->TargetId
;
6041 versionParameters
->bIDEDeviceMap
= deviceNumber
;
6043 status
= SRB_STATUS_SUCCESS
;
6047 case IOCTL_SCSI_MINIPORT_IDENTIFY
: {
6049 PSENDCMDOUTPARAMS cmdOutParameters
= (PSENDCMDOUTPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
6050 SENDCMDINPARAMS cmdInParameters
= *(PSENDCMDINPARAMS
)(((PUCHAR
)Srb
->DataBuffer
) + sizeof(SRB_IO_CONTROL
));
6055 if (cmdInParameters
.irDriveRegs
.bCommandReg
== ID_CMD
) {
6058 // Extract the target.
6061 targetId
= cmdInParameters
.bDriveNumber
;
6063 if (!(deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_DEVICE_PRESENT
) ||
6064 (deviceExtension
->DeviceFlags
[Srb
->TargetId
] & DFLAGS_ATAPI_DEVICE
)) {
6066 status
= SRB_STATUS_SELECTION_TIMEOUT
;
6071 // Zero the output buffer
6074 for (i
= 0; i
< (sizeof(SENDCMDOUTPARAMS
) + IDENTIFY_BUFFER_SIZE
- 1); i
++) {
6075 ((PUCHAR
)cmdOutParameters
)[i
] = 0;
6079 // Build status block.
6082 cmdOutParameters
->cBufferSize
= IDENTIFY_BUFFER_SIZE
;
6083 cmdOutParameters
->DriverStatus
.bDriverError
= 0;
6084 cmdOutParameters
->DriverStatus
.bIDEError
= 0;
6087 // Extract the identify data from the device extension.
6090 ScsiPortMoveMemory (cmdOutParameters
->bBuffer
, &deviceExtension
->IdentifyData
[targetId
], IDENTIFY_DATA_SIZE
);
6092 status
= SRB_STATUS_SUCCESS
;
6096 status
= SRB_STATUS_INVALID_REQUEST
;
6101 case IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS
:
6102 case IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS
:
6103 case IOCTL_SCSI_MINIPORT_ENABLE_SMART
:
6104 case IOCTL_SCSI_MINIPORT_DISABLE_SMART
:
6105 case IOCTL_SCSI_MINIPORT_RETURN_STATUS
:
6106 case IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE
:
6107 case IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES
:
6108 case IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS
:
6110 status
= IdeSendSmartCommand(HwDeviceExtension
,Srb
);
6115 status
= SRB_STATUS_INVALID_REQUEST
;
6125 // Indicate unsupported command.
6128 status
= SRB_STATUS_INVALID_REQUEST
;
6135 // Check if command complete.
6138 if (status
!= SRB_STATUS_PENDING
) {
6141 "AtapiStartIo: Srb %x complete with status %x\n",
6146 // Clear current SRB.
6149 deviceExtension
->CurrentSrb
= NULL
;
6152 // Set status in SRB.
6155 Srb
->SrbStatus
= (UCHAR
)status
;
6158 // Indicate command complete.
6161 ScsiPortNotification(RequestComplete
,
6166 // Indicate ready for next request.
6169 ScsiPortNotification(NextRequest
,
6176 } // end AtapiStartIo()
6182 IN PVOID DriverObject
,
6188 Routine Description:
6190 Installable driver initialization entry point for system.
6198 Status from ScsiPortInitialize()
6203 HW_INITIALIZATION_DATA hwInitializationData
;
6206 ULONG statusToReturn
, newStatus
;
6208 DebugPrint((1,"\n\nATAPI IDE MiniPort Driver\n"));
6210 statusToReturn
= 0xffffffff;
6213 // Zero out structure.
6216 AtapiZeroMemory(((PUCHAR
)&hwInitializationData
), sizeof(HW_INITIALIZATION_DATA
));
6219 // Set size of hwInitializationData.
6222 hwInitializationData
.HwInitializationDataSize
=
6223 sizeof(HW_INITIALIZATION_DATA
);
6226 // Set entry points.
6229 hwInitializationData
.HwInitialize
= AtapiHwInitialize
;
6230 hwInitializationData
.HwResetBus
= AtapiResetController
;
6231 hwInitializationData
.HwStartIo
= AtapiStartIo
;
6232 hwInitializationData
.HwInterrupt
= AtapiInterrupt
;
6235 // Specify size of extensions.
6238 hwInitializationData
.DeviceExtensionSize
= sizeof(HW_DEVICE_EXTENSION
);
6239 hwInitializationData
.SpecificLuExtensionSize
= sizeof(HW_LU_EXTENSION
);
6242 // Indicate PIO device.
6245 hwInitializationData
.MapBuffers
= TRUE
;
6248 // Native Mode Devices
6250 for (i
=0; i
<NUM_NATIVE_MODE_ADAPTERS
; i
++) {
6251 hwInitializationData
.HwFindAdapter
= AtapiFindNativeModeController
;
6252 hwInitializationData
.NumberOfAccessRanges
= 4;
6253 hwInitializationData
.AdapterInterfaceType
= PCIBus
;
6255 hwInitializationData
.VendorId
= NativeModeAdapters
[i
].VendorId
;
6256 hwInitializationData
.VendorIdLength
= (USHORT
) NativeModeAdapters
[i
].VendorIdLength
;
6257 hwInitializationData
.DeviceId
= NativeModeAdapters
[i
].DeviceId
;
6258 hwInitializationData
.DeviceIdLength
= (USHORT
) NativeModeAdapters
[i
].DeviceIdLength
;
6260 newStatus
= ScsiPortInitialize(DriverObject
,
6262 &hwInitializationData
,
6264 if (newStatus
< statusToReturn
)
6265 statusToReturn
= newStatus
;
6268 hwInitializationData
.VendorId
= 0;
6269 hwInitializationData
.VendorIdLength
= 0;
6270 hwInitializationData
.DeviceId
= 0;
6271 hwInitializationData
.DeviceIdLength
= 0;
6274 // The adapter count is used by the find adapter routine to track how
6275 // which adapter addresses have been tested.
6280 hwInitializationData
.HwFindAdapter
= AtapiFindPCIController
;
6281 hwInitializationData
.NumberOfAccessRanges
= 4;
6282 hwInitializationData
.AdapterInterfaceType
= Isa
;
6284 newStatus
= ScsiPortInitialize(DriverObject
,
6286 &hwInitializationData
,
6288 if (newStatus
< statusToReturn
)
6289 statusToReturn
= newStatus
;
6292 // Indicate 2 access ranges and reset FindAdapter.
6295 hwInitializationData
.NumberOfAccessRanges
= 2;
6296 hwInitializationData
.HwFindAdapter
= AtapiFindController
;
6299 // Indicate ISA bustype.
6302 hwInitializationData
.AdapterInterfaceType
= Isa
;
6305 // Call initialization for ISA bustype.
6308 newStatus
= ScsiPortInitialize(DriverObject
,
6310 &hwInitializationData
,
6312 if (newStatus
< statusToReturn
)
6313 statusToReturn
= newStatus
;
6319 hwInitializationData
.AdapterInterfaceType
= MicroChannel
;
6322 newStatus
= ScsiPortInitialize(DriverObject
,
6324 &hwInitializationData
,
6326 if (newStatus
< statusToReturn
)
6327 statusToReturn
= newStatus
;
6329 return statusToReturn
;
6331 } // end DriverEntry()
6352 first
= *FirstStr
++;
6353 last
= *SecondStr
++;
6355 if (first
!= last
) {
6358 // If no match, try lower-casing.
6361 if (first
>='A' && first
<='Z') {
6362 first
= first
- 'A' + 'a';
6364 if (last
>='A' && last
<='Z') {
6365 last
= last
- 'A' + 'a';
6367 if (first
!= last
) {
6373 return first
- last
;
6376 }while (--Count
&& first
);
6392 for (i
= 0; i
< Count
; i
++) {
6402 IN OUT PCHAR
*Buffer
6415 for (i
= 0; i
< 4; i
++) {
6416 digval
= (USHORT
)(Value
% 16);
6420 // convert to ascii and store. Note this will create
6421 // the buffer with the digits reversed.
6425 *string
++ = (char) (digval
- 10 + 'a');
6427 *string
++ = (char) (digval
+ '0');
6433 // Reverse the digits.
6440 *string
= *firstdig
;
6444 } while (firstdig
< string
);
6451 BuildMechanismStatusSrb (
6452 IN PVOID HwDeviceExtension
,
6457 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
6458 PSCSI_REQUEST_BLOCK srb
;
6461 srb
= &deviceExtension
->InternalSrb
;
6463 AtapiZeroMemory((PUCHAR
) srb
, sizeof(SCSI_REQUEST_BLOCK
));
6465 srb
->PathId
= (UCHAR
) PathId
;
6466 srb
->TargetId
= (UCHAR
) TargetId
;
6467 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6468 srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
6471 // Set flags to disable synchronous negociation.
6473 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6476 // Set timeout to 2 seconds.
6478 srb
->TimeOutValue
= 4;
6481 srb
->DataBuffer
= &deviceExtension
->MechStatusData
;
6482 srb
->DataTransferLength
= sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6485 // Set CDB operation code.
6487 cdb
= (PCDB
)srb
->Cdb
;
6488 cdb
->MECH_STATUS
.OperationCode
= SCSIOP_MECHANISM_STATUS
;
6489 cdb
->MECH_STATUS
.AllocationLength
[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER
);
6497 BuildRequestSenseSrb (
6498 IN PVOID HwDeviceExtension
,
6503 PHW_DEVICE_EXTENSION deviceExtension
= HwDeviceExtension
;
6504 PSCSI_REQUEST_BLOCK srb
;
6507 srb
= &deviceExtension
->InternalSrb
;
6509 AtapiZeroMemory((PUCHAR
) srb
, sizeof(SCSI_REQUEST_BLOCK
));
6511 srb
->PathId
= (UCHAR
) PathId
;
6512 srb
->TargetId
= (UCHAR
) TargetId
;
6513 srb
->Function
= SRB_FUNCTION_EXECUTE_SCSI
;
6514 srb
->Length
= sizeof(SCSI_REQUEST_BLOCK
);
6517 // Set flags to disable synchronous negociation.
6519 srb
->SrbFlags
= SRB_FLAGS_DATA_IN
| SRB_FLAGS_DISABLE_SYNCH_TRANSFER
;
6522 // Set timeout to 2 seconds.
6524 srb
->TimeOutValue
= 4;
6527 srb
->DataBuffer
= &deviceExtension
->MechStatusSense
;
6528 srb
->DataTransferLength
= sizeof(SENSE_DATA
);
6531 // Set CDB operation code.
6533 cdb
= (PCDB
)srb
->Cdb
;
6534 cdb
->CDB6INQUIRY
.OperationCode
= SCSIOP_REQUEST_SENSE
;
6535 cdb
->CDB6INQUIRY
.AllocationLength
= sizeof(SENSE_DATA
);