xref: /reactos/drivers/storage/ide/atapi/atapi.c (revision 9393fc32)
1 /*
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
7  */
8 
9 #include <ntddk.h>
10 #include "atapi.h"               // includes scsi.h
11 #include <ntddscsi.h>
12 #include <ntdddisk.h>
13 #include <ntddstor.h>
14 
15 //#define NDEBUG
16 #include <debug.h>
17 
18 //
19 // Device extension
20 //
21 
22 typedef struct _HW_DEVICE_EXTENSION {
23 
24     //
25     // Current request on controller.
26     //
27 
28     PSCSI_REQUEST_BLOCK CurrentSrb;
29 
30     //
31     // Base register locations
32     //
33 
34     PIDE_REGISTERS_1 BaseIoAddress1[2];
35     PIDE_REGISTERS_2 BaseIoAddress2[2];
36 
37     //
38     // Interrupt level
39     //
40 
41     ULONG InterruptLevel;
42 
43     //
44     // Interrupt Mode (Level or Edge)
45     //
46 
47     ULONG InterruptMode;
48 
49     //
50     // Data buffer pointer.
51     //
52 
53     PUSHORT DataBuffer;
54 
55     //
56     // Data words left.
57     //
58 
59     ULONG WordsLeft;
60 
61     //
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
65     // to support them.
66     //
67 
68     ULONG NumberChannels;
69 
70     //
71     // Count of errors. Used to turn off features.
72     //
73 
74     ULONG ErrorCount;
75 
76     //
77     // Indicates number of platters on changer-ish devices.
78     //
79 
80     ULONG DiscsPresent[4];
81 
82     //
83     // Flags word for each possible device.
84     //
85 
86     USHORT DeviceFlags[4];
87 
88     //
89     // Indicates the number of blocks transferred per int. according to the
90     // identify data.
91     //
92 
93     UCHAR MaximumBlockXfer[4];
94 
95     //
96     // Indicates expecting an interrupt
97     //
98 
99     BOOLEAN ExpectingInterrupt;
100 
101     //
102     // Indicate last tape command was DSC Restrictive.
103     //
104 
105     BOOLEAN RDP;
106 
107     //
108     // Driver is being used by the crash dump utility or ntldr.
109     //
110 
111     BOOLEAN DriverMustPoll;
112 
113     //
114     // Indicates use of 32-bit PIO
115     //
116 
117     BOOLEAN DWordIO;
118 
119     //
120     // Indicates whether '0x1f0' is the base address. Used
121     // in SMART Ioctl calls.
122     //
123 
124     BOOLEAN PrimaryAddress;
125 
126     //
127     // Placeholder for the sub-command value of the last
128     // SMART command.
129     //
130 
131     UCHAR SmartCommand;
132 
133     //
134     // Placeholder for status register after a GET_MEDIA_STATUS command
135     //
136 
137     UCHAR ReturningMediaStatus;
138 
139     UCHAR Reserved[1];
140 
141     //
142     // Identify data for device
143     //
144 
145     IDENTIFY_DATA FullIdentifyData;
146     IDENTIFY_DATA2 IdentifyData[4];
147 
148     //
149     // Mechanism Status Srb Data
150     //
151     PSCSI_REQUEST_BLOCK OriginalSrb;
152     SCSI_REQUEST_BLOCK InternalSrb;
153     MECHANICAL_STATUS_INFORMATION_HEADER MechStatusData;
154     SENSE_DATA MechStatusSense;
155     ULONG MechStatusRetryCount;
156 
157 } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
158 
159 //
160 // Logical unit extension
161 //
162 
163 typedef struct _HW_LU_EXTENSION {
164    ULONG Reserved;
165 } HW_LU_EXTENSION, *PHW_LU_EXTENSION;
166 
167 PSCSI_REQUEST_BLOCK
168 NTAPI
169 BuildMechanismStatusSrb (
170     IN PVOID HwDeviceExtension,
171     IN ULONG PathId,
172     IN ULONG TargetId
173     );
174 
175 PSCSI_REQUEST_BLOCK
176 NTAPI
177 BuildRequestSenseSrb (
178     IN PVOID HwDeviceExtension,
179     IN ULONG PathId,
180     IN ULONG TargetId
181     );
182 
183 VOID
184 NTAPI
185 AtapiHwInitializeChanger (
186     IN PVOID HwDeviceExtension,
187     IN ULONG TargetId,
188     IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus
189     );
190 
191 ULONG
192 NTAPI
193 AtapiSendCommand(
194     IN PVOID HwDeviceExtension,
195     IN PSCSI_REQUEST_BLOCK Srb
196     );
197 
198 VOID
199 NTAPI
200 AtapiZeroMemory(
201     IN PUCHAR Buffer,
202     IN ULONG Count
203     );
204 
205 VOID
206 NTAPI
207 AtapiHexToString (
208     ULONG Value,
209     PCHAR *Buffer
210     );
211 
212 LONG
213 NTAPI
214 AtapiStringCmp (
215     PCHAR FirstStr,
216     PCHAR SecondStr,
217     ULONG Count
218     );
219 
220 BOOLEAN
221 NTAPI
222 AtapiInterrupt(
223     IN PVOID HwDeviceExtension
224     );
225 
226 BOOLEAN
227 NTAPI
228 AtapiHwInitialize(
229     IN PVOID HwDeviceExtension
230         );
231 
232 ULONG
233 NTAPI
234 IdeBuildSenseBuffer(
235     IN PVOID HwDeviceExtension,
236     IN PSCSI_REQUEST_BLOCK Srb
237     );
238 
239 VOID
240 NTAPI
241 IdeMediaStatus(
242     IN BOOLEAN EnableMSN,
243     IN PVOID HwDeviceExtension,
244     IN ULONG Channel
245     );
246 
247 
248 
249 BOOLEAN
250 NTAPI
251 IssueIdentify(
252     IN PVOID HwDeviceExtension,
253     IN ULONG DeviceNumber,
254     IN ULONG Channel,
255     IN UCHAR Command
256     )
257 
258 /*++
259 
260 Routine Description:
261 
262     Issue IDENTIFY command to a device.
263 
264 Arguments:
265 
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.
269 
270 Return Value:
271 
272     TRUE if all goes well.
273 
274 --*/
275 
276 {
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;
281     ULONG                i,j;
282     UCHAR                statusByte;
283     UCHAR                signatureLow,
284                          signatureHigh;
285 
286     //
287     // Select device 0 or 1.
288     //
289 
290     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
291                            (UCHAR)((DeviceNumber << 4) | 0xA0));
292 
293     //
294     // Check that the status register makes sense.
295     //
296 
297     GetBaseStatus(baseIoAddress1, statusByte);
298 
299     if (Command == IDE_COMMAND_IDENTIFY) {
300 
301         //
302         // Mask status byte ERROR bits.
303         //
304 
305         statusByte &= ~(IDE_STATUS_ERROR | IDE_STATUS_INDEX);
306 
307         DebugPrint((1,
308                     "IssueIdentify: Checking for IDE. Status (%x)\n",
309                     statusByte));
310 
311         //
312         // Check if register value is reasonable.
313         //
314 
315         if (statusByte != IDE_STATUS_IDLE) {
316 
317             //
318             // Reset the controller.
319             //
320 
321             AtapiSoftReset(baseIoAddress1,DeviceNumber);
322 
323             ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
324                                    (UCHAR)((DeviceNumber << 4) | 0xA0));
325 
326             WaitOnBusy(baseIoAddress2,statusByte);
327 
328             signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
329             signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
330 
331             if (signatureLow == 0x14 && signatureHigh == 0xEB) {
332 
333                 //
334                 // Device is Atapi.
335                 //
336 
337                 return FALSE;
338             }
339 
340             DebugPrint((1,
341                         "IssueIdentify: Resetting controller.\n"));
342 
343             ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
344             ScsiPortStallExecution(500 * 1000);
345             ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
346 
347 
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)
351             do {
352 
353                 //
354                 // Wait for Busy to drop.
355                 //
356 
357                 ScsiPortStallExecution(100);
358                 GetStatus(baseIoAddress2, statusByte);
359 
360             } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
361 
362             ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
363                                    (UCHAR)((DeviceNumber << 4) | 0xA0));
364 
365             //
366             // Another check for signature, to deal with one model Atapi that doesn't assert signature after
367             // a soft reset.
368             //
369 
370             signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
371             signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
372 
373             if (signatureLow == 0x14 && signatureHigh == 0xEB) {
374 
375                 //
376                 // Device is Atapi.
377                 //
378 
379                 return FALSE;
380             }
381 
382             statusByte &= ~IDE_STATUS_INDEX;
383 
384             if (statusByte != IDE_STATUS_IDLE) {
385 
386                 //
387                 // Give up on this.
388                 //
389 
390                 return FALSE;
391             }
392 
393         }
394 
395     } else {
396 
397         DebugPrint((1,
398                     "IssueIdentify: Checking for ATAPI. Status (%x)\n",
399                     statusByte));
400 
401     }
402 
403     //
404     // Load CylinderHigh and CylinderLow with number bytes to transfer.
405     //
406 
407     ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh, (0x200 >> 8));
408     ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,  (0x200 & 0xFF));
409 
410     for (j = 0; j < 2; j++) {
411 
412         //
413         // Send IDENTIFY command.
414         //
415 
416         WaitOnBusy(baseIoAddress2,statusByte);
417 
418         ScsiPortWritePortUchar(&baseIoAddress1->Command, Command);
419 
420         //
421         // Wait for DRQ.
422         //
423 
424         for (i = 0; i < 4; i++) {
425 
426             WaitForDrq(baseIoAddress2, statusByte);
427 
428             if (statusByte & IDE_STATUS_DRQ) {
429 
430                 //
431                 // Read status to acknowledge any interrupts generated.
432                 //
433 
434                 GetBaseStatus(baseIoAddress1, statusByte);
435 
436                 //
437                 // One last check for Atapi.
438                 //
439 
440 
441                 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
442                 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
443 
444                 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
445 
446                     //
447                     // Device is Atapi.
448                     //
449 
450                     return FALSE;
451                 }
452 
453                 break;
454             }
455 
456             if (Command == IDE_COMMAND_IDENTIFY) {
457 
458                 //
459                 // Check the signature. If DRQ didn't come up it's likely Atapi.
460                 //
461 
462                 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
463                 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
464 
465                 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
466 
467                     //
468                     // Device is Atapi.
469                     //
470 
471                     return FALSE;
472                 }
473             }
474 
475             WaitOnBusy(baseIoAddress2,statusByte);
476         }
477 
478         if (i == 4 && j == 0) {
479 
480             //
481             // Device didn't respond correctly. It will be given one more chances.
482             //
483 
484             DebugPrint((1,
485                         "IssueIdentify: DRQ never asserted (%x). Error reg (%x)\n",
486                         statusByte,
487                          ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1)));
488 
489             AtapiSoftReset(baseIoAddress1,DeviceNumber);
490 
491             GetStatus(baseIoAddress2,statusByte);
492 
493             DebugPrint((1,
494                        "IssueIdentify: Status after soft reset (%x)\n",
495                        statusByte));
496 
497         } else {
498 
499             break;
500 
501         }
502     }
503 
504     //
505     // Check for error on really stupid master devices that assert random
506     // patterns of bits in the status register at the slave address.
507     //
508 
509     if ((Command == IDE_COMMAND_IDENTIFY) && (statusByte & IDE_STATUS_ERROR)) {
510         return FALSE;
511     }
512 
513     DebugPrint((1,
514                "IssueIdentify: Status before read words %x\n",
515                statusByte));
516 
517     //
518     // Suck out 256 words. After waiting for one model that asserts busy
519     // after receiving the Packet Identify command.
520     //
521 
522     WaitOnBusy(baseIoAddress2,statusByte);
523 
524     if (!(statusByte & IDE_STATUS_DRQ)) {
525         return FALSE;
526     }
527 
528     ReadBuffer(baseIoAddress1,
529                (PUSHORT)&deviceExtension->FullIdentifyData,
530                256);
531 
532     //
533     // Check out a few capabilities / limitations of the device.
534     //
535 
536     if (deviceExtension->FullIdentifyData.SpecialFunctionsEnabled & 1) {
537 
538         //
539         // Determine if this drive supports the MSN functions.
540         //
541 
542         DebugPrint((2,"IssueIdentify: Marking drive %d as removable. SFE = %d\n",
543                     Channel * 2 + DeviceNumber,
544                     deviceExtension->FullIdentifyData.SpecialFunctionsEnabled));
545 
546 
547         deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_REMOVABLE_DRIVE;
548     }
549 
550     if (deviceExtension->FullIdentifyData.MaximumBlockTransfer) {
551 
552         //
553         // Determine max. block transfer for this device.
554         //
555 
556         deviceExtension->MaximumBlockXfer[(Channel * 2) + DeviceNumber] =
557             (UCHAR)(deviceExtension->FullIdentifyData.MaximumBlockTransfer & 0xFF);
558     }
559 
560     ScsiPortMoveMemory(&deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber],&deviceExtension->FullIdentifyData,sizeof(IDENTIFY_DATA2));
561 
562     if (deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0x20 &&
563         Command != IDE_COMMAND_IDENTIFY) {
564 
565         //
566         // This device interrupts with the assertion of DRQ after receiving
567         // Atapi Packet Command
568         //
569 
570         deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_INT_DRQ;
571 
572         DebugPrint((2,
573                     "IssueIdentify: Device interrupts on assertion of DRQ.\n"));
574 
575     } else {
576 
577         DebugPrint((2,
578                     "IssueIdentify: Device does not interrupt on assertion of DRQ.\n"));
579     }
580 
581     if (((deviceExtension->IdentifyData[(Channel * 2) + DeviceNumber].GeneralConfiguration & 0xF00) == 0x100) &&
582         Command != IDE_COMMAND_IDENTIFY) {
583 
584         //
585         // This is a tape.
586         //
587 
588         deviceExtension->DeviceFlags[(Channel * 2) + DeviceNumber] |= DFLAGS_TAPE_DEVICE;
589 
590         DebugPrint((2,
591                     "IssueIdentify: Device is a tape drive.\n"));
592 
593     } else {
594 
595         DebugPrint((2,
596                     "IssueIdentify: Device is not a tape drive.\n"));
597     }
598 
599     //
600     // Work around for some IDE and one model Atapi that will present more than
601     // 256 bytes for the Identify data.
602     //
603 
604     WaitOnBusy(baseIoAddress2,statusByte);
605 
606     for (i = 0; i < 0x10000; i++) {
607 
608         GetStatus(baseIoAddress2,statusByte);
609 
610         if (statusByte & IDE_STATUS_DRQ) {
611 
612             //
613             // Suck out any remaining bytes and throw away.
614             //
615 
616             ScsiPortReadPortUshort(&baseIoAddress1->Data);
617 
618         } else {
619 
620             break;
621 
622         }
623     }
624 
625     DebugPrint((3,
626                "IssueIdentify: Status after read words (%x)\n",
627                statusByte));
628 
629     return TRUE;
630 
631 } // end IssueIdentify()
632 
633 
634 BOOLEAN
635 NTAPI
636 SetDriveParameters(
637     IN PVOID HwDeviceExtension,
638     IN ULONG DeviceNumber,
639     IN ULONG Channel
640     )
641 
642 /*++
643 
644 Routine Description:
645 
646     Set drive parameters using the IDENTIFY data.
647 
648 Arguments:
649 
650     HwDeviceExtension - HBA miniport driver's adapter data storage
651     DeviceNumber - Indicates which device.
652 
653 Return Value:
654 
655     TRUE if all goes well.
656 
657 
658 --*/
659 
660 {
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];
665     ULONG i;
666     UCHAR statusByte;
667 
668     DebugPrint((1,
669                "SetDriveParameters: Number of heads %x\n",
670                identifyData->NumberOfHeads));
671 
672     DebugPrint((1,
673                "SetDriveParameters: Sectors per track %x\n",
674                 identifyData->SectorsPerTrack));
675 
676     //
677     // Set up registers for SET PARAMETER command.
678     //
679 
680     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
681                            (UCHAR)(((DeviceNumber << 4) | 0xA0) | (identifyData->NumberOfHeads - 1)));
682 
683     ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
684                            (UCHAR)identifyData->SectorsPerTrack);
685 
686     //
687     // Send SET PARAMETER command.
688     //
689 
690     ScsiPortWritePortUchar(&baseIoAddress1->Command,
691                            IDE_COMMAND_SET_DRIVE_PARAMETERS);
692 
693     //
694     // Wait for up to 30 milliseconds for ERROR or command complete.
695     //
696 
697     for (i=0; i<30 * 1000; i++) {
698 
699         UCHAR errorByte;
700 
701         GetStatus(baseIoAddress2, statusByte);
702 
703         if (statusByte & IDE_STATUS_ERROR) {
704             errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
705             DebugPrint((1,
706                         "SetDriveParameters: Error bit set. Status %x, error %x\n",
707                         errorByte,
708                         statusByte));
709 
710             return FALSE;
711         } else if ((statusByte & ~IDE_STATUS_INDEX ) == IDE_STATUS_IDLE) {
712             break;
713         } else {
714             ScsiPortStallExecution(100);
715         }
716     }
717 
718     //
719     // Check for timeout.
720     //
721 
722     if (i == 30 * 1000) {
723         return FALSE;
724     } else {
725         return TRUE;
726     }
727 
728 } // end SetDriveParameters()
729 
730 
731 BOOLEAN
732 NTAPI
733 AtapiResetController(
734     IN PVOID HwDeviceExtension,
735     IN ULONG PathId
736     )
737 
738 /*++
739 
740 Routine Description:
741 
742     Reset IDE controller and/or Atapi device.
743 
744 Arguments:
745 
746     HwDeviceExtension - HBA miniport driver's adapter data storage
747 
748 Return Value:
749 
750     Nothing.
751 
752 
753 --*/
754 
755 {
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;
761     ULONG i,j;
762     UCHAR statusByte;
763 
764     DebugPrint((2,"AtapiResetController: Reset IDE\n"));
765 
766     //
767     // Check and see if we are processing an internal srb
768     //
769     if (deviceExtension->OriginalSrb) {
770         deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
771         deviceExtension->OriginalSrb = NULL;
772     }
773 
774     //
775     // Check if request is in progress.
776     //
777 
778     if (deviceExtension->CurrentSrb) {
779 
780         //
781         // Complete outstanding request with SRB_STATUS_BUS_RESET.
782         //
783 
784         ScsiPortCompleteRequest(deviceExtension,
785                                 deviceExtension->CurrentSrb->PathId,
786                                 deviceExtension->CurrentSrb->TargetId,
787                                 deviceExtension->CurrentSrb->Lun,
788                                 (ULONG)SRB_STATUS_BUS_RESET);
789 
790         //
791         // Clear request tracking fields.
792         //
793 
794         deviceExtension->CurrentSrb = NULL;
795         deviceExtension->WordsLeft = 0;
796         deviceExtension->DataBuffer = NULL;
797 
798         //
799         // Indicate ready for next request.
800         //
801 
802         ScsiPortNotification(NextRequest,
803                              deviceExtension,
804                              NULL);
805     }
806 
807     //
808     // Clear expecting interrupt flag.
809     //
810 
811     deviceExtension->ExpectingInterrupt = FALSE;
812     deviceExtension->RDP = FALSE;
813 
814     for (j = 0; j < numberChannels; j++) {
815 
816         baseIoAddress1 = deviceExtension->BaseIoAddress1[j];
817         baseIoAddress2 = deviceExtension->BaseIoAddress2[j];
818 
819         //
820         // Do special processing for ATAPI and IDE disk devices.
821         //
822 
823         for (i = 0; i < 2; i++) {
824 
825             //
826             // Check if device present.
827             //
828 
829             if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_DEVICE_PRESENT) {
830 
831                 //
832                 // Check for ATAPI disk.
833                 //
834 
835                 if (deviceExtension->DeviceFlags[i + (j * 2)] & DFLAGS_ATAPI_DEVICE) {
836 
837                     //
838                     // Issue soft reset and issue identify.
839                     //
840 
841                     GetStatus(baseIoAddress2,statusByte);
842                     DebugPrint((1,
843                                 "AtapiResetController: Status before Atapi reset (%x).\n",
844                                 statusByte));
845 
846                     AtapiSoftReset(baseIoAddress1,i);
847 
848                     GetStatus(baseIoAddress2,statusByte);
849 
850                     if (statusByte == 0x0) {
851 
852                         IssueIdentify(HwDeviceExtension,
853                                       i,
854                                       j,
855                                       IDE_COMMAND_ATAPI_IDENTIFY);
856                     } else {
857 
858                         DebugPrint((1,
859                                    "AtapiResetController: Status after soft reset %x\n",
860                                    statusByte));
861                     }
862 
863                 } else {
864 
865                     //
866                     // Write IDE reset controller bits.
867                     //
868 
869                     IdeHardReset(baseIoAddress2,result);
870 
871                     if (!result) {
872                         return FALSE;
873                     }
874 
875                     //
876                     // Set disk geometry parameters.
877                     //
878 
879                     if (!SetDriveParameters(HwDeviceExtension,
880                                             i,
881                                             j)) {
882 
883                         DebugPrint((1,
884                                    "AtapiResetController: SetDriveParameters failed\n"));
885                     }
886                 }
887             }
888         }
889     }
890 
891     //
892     // Call the HwInitialize routine to setup multi-block.
893     //
894 
895     AtapiHwInitialize(HwDeviceExtension);
896 
897     return TRUE;
898 
899 } // end AtapiResetController()
900 
901 
902 
903 ULONG
904 NTAPI
905 MapError(
906     IN PVOID HwDeviceExtension,
907     IN PSCSI_REQUEST_BLOCK Srb
908     )
909 
910 /*++
911 
912 Routine Description:
913 
914     This routine maps ATAPI and IDE errors to specific SRB statuses.
915 
916 Arguments:
917 
918     HwDeviceExtension - HBA miniport driver's adapter data storage
919     Srb - IO request packet
920 
921 Return Value:
922 
923     SRB status
924 
925 --*/
926 
927 {
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];
931     ULONG i;
932     UCHAR errorByte;
933     UCHAR srbStatus = SRB_STATUS_ERROR;
934     UCHAR scsiStatus;
935 
936     //
937     // Read the error register.
938     //
939 
940     errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
941     DebugPrint((1,
942                "MapError: Error register is %x\n",
943                errorByte));
944 
945     if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
946 
947         switch (errorByte >> 4) {
948         case SCSI_SENSE_NO_SENSE:
949 
950             DebugPrint((1,
951                        "ATAPI: No sense information\n"));
952             scsiStatus = SCSISTAT_CHECK_CONDITION;
953             srbStatus = SRB_STATUS_ERROR;
954             break;
955 
956         case SCSI_SENSE_RECOVERED_ERROR:
957 
958             DebugPrint((1,
959                        "ATAPI: Recovered error\n"));
960             scsiStatus = 0;
961             srbStatus = SRB_STATUS_SUCCESS;
962             break;
963 
964         case SCSI_SENSE_NOT_READY:
965 
966             DebugPrint((1,
967                        "ATAPI: Device not ready\n"));
968             scsiStatus = SCSISTAT_CHECK_CONDITION;
969             srbStatus = SRB_STATUS_ERROR;
970             break;
971 
972         case SCSI_SENSE_MEDIUM_ERROR:
973 
974             DebugPrint((1,
975                        "ATAPI: Media error\n"));
976             scsiStatus = SCSISTAT_CHECK_CONDITION;
977             srbStatus = SRB_STATUS_ERROR;
978             break;
979 
980         case SCSI_SENSE_HARDWARE_ERROR:
981 
982             DebugPrint((1,
983                        "ATAPI: Hardware error\n"));
984             scsiStatus = SCSISTAT_CHECK_CONDITION;
985             srbStatus = SRB_STATUS_ERROR;
986             break;
987 
988         case SCSI_SENSE_ILLEGAL_REQUEST:
989 
990             DebugPrint((1,
991                        "ATAPI: Illegal request\n"));
992             scsiStatus = SCSISTAT_CHECK_CONDITION;
993             srbStatus = SRB_STATUS_ERROR;
994             break;
995 
996         case SCSI_SENSE_UNIT_ATTENTION:
997 
998             DebugPrint((1,
999                        "ATAPI: Unit attention\n"));
1000             scsiStatus = SCSISTAT_CHECK_CONDITION;
1001             srbStatus = SRB_STATUS_ERROR;
1002             break;
1003 
1004         case SCSI_SENSE_DATA_PROTECT:
1005 
1006             DebugPrint((1,
1007                        "ATAPI: Data protect\n"));
1008             scsiStatus = SCSISTAT_CHECK_CONDITION;
1009             srbStatus = SRB_STATUS_ERROR;
1010             break;
1011 
1012         case SCSI_SENSE_BLANK_CHECK:
1013 
1014             DebugPrint((1,
1015                        "ATAPI: Blank check\n"));
1016             scsiStatus = SCSISTAT_CHECK_CONDITION;
1017             srbStatus = SRB_STATUS_ERROR;
1018             break;
1019 
1020         case SCSI_SENSE_ABORTED_COMMAND:
1021             DebugPrint((1,
1022                         "Atapi: Command Aborted\n"));
1023             scsiStatus = SCSISTAT_CHECK_CONDITION;
1024             srbStatus = SRB_STATUS_ERROR;
1025             break;
1026 
1027         default:
1028 
1029             DebugPrint((1,
1030                        "ATAPI: Invalid sense information\n"));
1031             scsiStatus = 0;
1032             srbStatus = SRB_STATUS_ERROR;
1033             break;
1034         }
1035 
1036     } else {
1037 
1038         scsiStatus = 0;
1039 
1040         //
1041         // Save errorByte,to be used by SCSIOP_REQUEST_SENSE.
1042         //
1043 
1044         deviceExtension->ReturningMediaStatus = errorByte;
1045 
1046         if (errorByte & IDE_ERROR_MEDIA_CHANGE_REQ) {
1047             DebugPrint((1,
1048                        "IDE: Media change\n"));
1049             scsiStatus = SCSISTAT_CHECK_CONDITION;
1050             srbStatus = SRB_STATUS_ERROR;
1051 
1052         } else if (errorByte & IDE_ERROR_COMMAND_ABORTED) {
1053             DebugPrint((1,
1054                        "IDE: Command abort\n"));
1055             srbStatus = SRB_STATUS_ABORTED;
1056             scsiStatus = SCSISTAT_CHECK_CONDITION;
1057 
1058             if (Srb->SenseInfoBuffer) {
1059 
1060                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1061 
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;
1068 
1069                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1070             }
1071 
1072             deviceExtension->ErrorCount++;
1073 
1074         } else if (errorByte & IDE_ERROR_END_OF_MEDIA) {
1075 
1076             DebugPrint((1,
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++;
1082             }
1083 
1084         } else if (errorByte & IDE_ERROR_ILLEGAL_LENGTH) {
1085 
1086             DebugPrint((1,
1087                        "IDE: Illegal length\n"));
1088             srbStatus = SRB_STATUS_INVALID_REQUEST;
1089 
1090         } else if (errorByte & IDE_ERROR_BAD_BLOCK) {
1091 
1092             DebugPrint((1,
1093                        "IDE: Bad block\n"));
1094             srbStatus = SRB_STATUS_ERROR;
1095             scsiStatus = SCSISTAT_CHECK_CONDITION;
1096             if (Srb->SenseInfoBuffer) {
1097 
1098                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1099 
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;
1106 
1107                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1108             }
1109 
1110         } else if (errorByte & IDE_ERROR_ID_NOT_FOUND) {
1111 
1112             DebugPrint((1,
1113                        "IDE: Id not found\n"));
1114             srbStatus = SRB_STATUS_ERROR;
1115             scsiStatus = SCSISTAT_CHECK_CONDITION;
1116 
1117             if (Srb->SenseInfoBuffer) {
1118 
1119                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1120 
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;
1127 
1128                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1129             }
1130 
1131             deviceExtension->ErrorCount++;
1132 
1133         } else if (errorByte & IDE_ERROR_MEDIA_CHANGE) {
1134 
1135             DebugPrint((1,
1136                        "IDE: Media change\n"));
1137             scsiStatus = SCSISTAT_CHECK_CONDITION;
1138             srbStatus = SRB_STATUS_ERROR;
1139 
1140             if (Srb->SenseInfoBuffer) {
1141 
1142                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1143 
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;
1150 
1151                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1152             }
1153 
1154         } else if (errorByte & IDE_ERROR_DATA_ERROR) {
1155 
1156             DebugPrint((1,
1157                    "IDE: Data error\n"));
1158             scsiStatus = SCSISTAT_CHECK_CONDITION;
1159             srbStatus = SRB_STATUS_ERROR;
1160 
1161             if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED)){
1162                 deviceExtension->ErrorCount++;
1163             }
1164 
1165             //
1166             // Build sense buffer
1167             //
1168 
1169             if (Srb->SenseInfoBuffer) {
1170 
1171                 PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;
1172 
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;
1179 
1180                 srbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1181             }
1182         }
1183 
1184         if (deviceExtension->ErrorCount >= MAX_ERRORS) {
1185             deviceExtension->DWordIO = FALSE;
1186             deviceExtension->MaximumBlockXfer[Srb->TargetId] = 0;
1187 
1188             DebugPrint((1,
1189                         "MapError: Disabling 32-bit PIO and Multi-sector IOs\n"));
1190 
1191             //
1192             // Log the error.
1193             //
1194 
1195             ScsiPortLogError( HwDeviceExtension,
1196                               Srb,
1197                               Srb->PathId,
1198                               Srb->TargetId,
1199                               Srb->Lun,
1200                               SP_BAD_FW_WARNING,
1201                               4);
1202             //
1203             // Reprogram to not use Multi-sector.
1204             //
1205 
1206             for (i = 0; i < 4; i++) {
1207                 UCHAR statusByte;
1208 
1209                 if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT &&
1210                      !(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) {
1211 
1212                     //
1213                     // Select the device.
1214                     //
1215 
1216                     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
1217                                            (UCHAR)(((i & 0x1) << 4) | 0xA0));
1218 
1219                     //
1220                     // Setup sector count to reflect the # of blocks.
1221                     //
1222 
1223                     ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
1224                                            0);
1225 
1226                     //
1227                     // Issue the command.
1228                     //
1229 
1230                     ScsiPortWritePortUchar(&baseIoAddress1->Command,
1231                                            IDE_COMMAND_SET_MULTIPLE);
1232 
1233                     //
1234                     // Wait for busy to drop.
1235                     //
1236 
1237                     WaitOnBaseBusy(baseIoAddress1,statusByte);
1238 
1239                     //
1240                     // Check for errors. Reset the value to 0 (disable MultiBlock) if the
1241                     // command was aborted.
1242                     //
1243 
1244                     if (statusByte & IDE_STATUS_ERROR) {
1245 
1246                         //
1247                         // Read the error register.
1248                         //
1249 
1250                         errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
1251 
1252                         DebugPrint((1,
1253                                     "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n",
1254                                     statusByte,
1255                                     errorByte));
1256                         //
1257                         // Adjust the devExt. value, if necessary.
1258                         //
1259 
1260                         deviceExtension->MaximumBlockXfer[i] = 0;
1261 
1262                     }
1263                 }
1264             }
1265         }
1266     }
1267 
1268 
1269     //
1270     // Set SCSI status to indicate a check condition.
1271     //
1272 
1273     Srb->ScsiStatus = scsiStatus;
1274 
1275     return srbStatus;
1276 
1277 } // end MapError()
1278 
1279 
1280 BOOLEAN
1281 NTAPI
1282 AtapiHwInitialize(
1283     IN PVOID HwDeviceExtension
1284     )
1285 
1286 /*++
1287 
1288 Routine Description:
1289 
1290 Arguments:
1291 
1292     HwDeviceExtension - HBA miniport driver's adapter data storage
1293 
1294 Return Value:
1295 
1296     TRUE - if initialization successful.
1297     FALSE - if initialization unsuccessful.
1298 
1299 --*/
1300 
1301 {
1302     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
1303     PIDE_REGISTERS_1     baseIoAddress;
1304     ULONG i;
1305     UCHAR statusByte, errorByte;
1306 
1307 
1308     for (i = 0; i < 4; i++) {
1309         if (deviceExtension->DeviceFlags[i] & DFLAGS_DEVICE_PRESENT) {
1310 
1311             if (!(deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE)) {
1312 
1313                 //
1314                 // Enable media status notification
1315                 //
1316 
1317                 baseIoAddress = deviceExtension->BaseIoAddress1[i >> 1];
1318 
1319                 IdeMediaStatus(TRUE,HwDeviceExtension,i);
1320 
1321                 //
1322                 // If supported, setup Multi-block transfers.
1323                 //
1324                 if (deviceExtension->MaximumBlockXfer[i]) {
1325 
1326                     //
1327                     // Select the device.
1328                     //
1329 
1330                     ScsiPortWritePortUchar(&baseIoAddress->DriveSelect,
1331                                            (UCHAR)(((i & 0x1) << 4) | 0xA0));
1332 
1333                     //
1334                     // Setup sector count to reflect the # of blocks.
1335                     //
1336 
1337                     ScsiPortWritePortUchar(&baseIoAddress->BlockCount,
1338                                            deviceExtension->MaximumBlockXfer[i]);
1339 
1340                     //
1341                     // Issue the command.
1342                     //
1343 
1344                     ScsiPortWritePortUchar(&baseIoAddress->Command,
1345                                            IDE_COMMAND_SET_MULTIPLE);
1346 
1347                     //
1348                     // Wait for busy to drop.
1349                     //
1350 
1351                     WaitOnBaseBusy(baseIoAddress,statusByte);
1352 
1353                     //
1354                     // Check for errors. Reset the value to 0 (disable MultiBlock) if the
1355                     // command was aborted.
1356                     //
1357 
1358                     if (statusByte & IDE_STATUS_ERROR) {
1359 
1360                         //
1361                         // Read the error register.
1362                         //
1363 
1364                         errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1);
1365 
1366                         DebugPrint((1,
1367                                     "AtapiHwInitialize: Error setting multiple mode. Status %x, error byte %x\n",
1368                                     statusByte,
1369                                     errorByte));
1370                         //
1371                         // Adjust the devExt. value, if necessary.
1372                         //
1373 
1374                         deviceExtension->MaximumBlockXfer[i] = 0;
1375 
1376                     } else {
1377                         DebugPrint((2,
1378                                     "AtapiHwInitialize: Using Multiblock on Device %d. Blocks / int - %d\n",
1379                                     i,
1380                                     deviceExtension->MaximumBlockXfer[i]));
1381                     }
1382                 }
1383             } else if (!(deviceExtension->DeviceFlags[i] & DFLAGS_CHANGER_INITED)){
1384 
1385                 ULONG j;
1386                 UCHAR vendorId[26];
1387 
1388                 //
1389                 // Attempt to identify any special-case devices - psuedo-atapi changers, atapi changers, etc.
1390                 //
1391 
1392                 for (j = 0; j < 13; j += 2) {
1393 
1394                     //
1395                     // Build a buffer based on the identify data.
1396                     //
1397 
1398                     vendorId[j] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j + 1];
1399                     vendorId[j+1] = ((PUCHAR)deviceExtension->IdentifyData[i].ModelNumber)[j];
1400                 }
1401 
1402                 if (!AtapiStringCmp ((PCHAR)vendorId, "CD-ROM  CDR", 11)) {
1403 
1404                     //
1405                     // Inquiry string for older model had a '-', newer is '_'
1406                     //
1407 
1408                     if (vendorId[12] == 'C') {
1409 
1410                         //
1411                         // Torisan changer. Set the bit. This will be used in several places
1412                         // acting like 1) a multi-lun device and 2) building the 'special' TUR's.
1413                         //
1414 
1415                         deviceExtension->DeviceFlags[i] |= (DFLAGS_CHANGER_INITED | DFLAGS_SANYO_ATAPI_CHANGER);
1416                         deviceExtension->DiscsPresent[i] = 3;
1417                     }
1418                 }
1419             }
1420 
1421             //
1422             // We need to get our device ready for action before
1423             // returning from this function
1424             //
1425             // According to the atapi spec 2.5 or 2.6, an atapi device
1426             // clears its status BSY bit when it is ready for atapi commands.
1427             // However, some devices (Panasonic SQ-TC500N) are still
1428             // not ready even when the status BSY is clear.  They don't react
1429             // to atapi commands.
1430             //
1431             // Since there is really no other indication that tells us
1432             // the drive is really ready for action.  We are going to check BSY
1433             // is clear and then just wait for an arbitrary amount of time!
1434             //
1435             if (deviceExtension->DeviceFlags[i] & DFLAGS_ATAPI_DEVICE) {
1436                 //PIDE_REGISTERS_1     baseIoAddress1 = deviceExtension->BaseIoAddress1[i >> 1];
1437                 PIDE_REGISTERS_2     baseIoAddress2 = deviceExtension->BaseIoAddress2[i >> 1];
1438                 ULONG waitCount;
1439 
1440                 // have to get out of the loop sometime!
1441                 // 10000 * 100us = 1000,000us = 1000ms = 1s
1442                 waitCount = 10000;
1443                 GetStatus(baseIoAddress2, statusByte);
1444                 while ((statusByte & IDE_STATUS_BUSY) && waitCount) {
1445                     //
1446                     // Wait for Busy to drop.
1447                     //
1448                     ScsiPortStallExecution(100);
1449                     GetStatus(baseIoAddress2, statusByte);
1450                     waitCount--;
1451                 }
1452 
1453                 // 5000 * 100us = 500,000us = 500ms = 0.5s
1454                 waitCount = 5000;
1455                 do {
1456                     ScsiPortStallExecution(100);
1457                 } while (waitCount--);
1458             }
1459         }
1460     }
1461 
1462     return TRUE;
1463 
1464 } // end AtapiHwInitialize()
1465 
1466 
1467 VOID
1468 NTAPI
1469 AtapiHwInitializeChanger (
1470     IN PVOID HwDeviceExtension,
1471     IN ULONG TargetId,
1472     IN PMECHANICAL_STATUS_INFORMATION_HEADER MechanismStatus)
1473 {
1474     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
1475 
1476     if (MechanismStatus) {
1477         deviceExtension->DiscsPresent[TargetId] = MechanismStatus->NumberAvailableSlots;
1478         if (deviceExtension->DiscsPresent[TargetId] > 1) {
1479             deviceExtension->DeviceFlags[TargetId] |= DFLAGS_ATAPI_CHANGER;
1480         }
1481     }
1482     return;
1483 }
1484 
1485 
1486 
1487 BOOLEAN
1488 NTAPI
1489 FindDevices(
1490     IN PVOID HwDeviceExtension,
1491     IN BOOLEAN AtapiOnly,
1492     IN ULONG   Channel
1493     )
1494 
1495 /*++
1496 
1497 Routine Description:
1498 
1499     This routine is called from AtapiFindController to identify
1500     devices attached to an IDE controller.
1501 
1502 Arguments:
1503 
1504     HwDeviceExtension - HBA miniport driver's adapter data storage
1505     AtapiOnly - Indicates that routine should return TRUE only if
1506         an ATAPI device is attached to the controller.
1507 
1508 Return Value:
1509 
1510     TRUE - True if devices found.
1511 
1512 --*/
1513 
1514 {
1515     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
1516     PIDE_REGISTERS_1     baseIoAddress1 = deviceExtension->BaseIoAddress1[Channel];
1517     PIDE_REGISTERS_2     baseIoAddress2 = deviceExtension->BaseIoAddress2[Channel];
1518     BOOLEAN              deviceResponded = FALSE,
1519                          skipSetParameters = FALSE;
1520     ULONG                waitCount = 10000;
1521     ULONG                deviceNumber;
1522     ULONG                i;
1523     UCHAR                signatureLow,
1524                          signatureHigh;
1525     UCHAR                statusByte;
1526 
1527     //
1528     // Clear expecting interrupt flag and current SRB field.
1529     //
1530 
1531     deviceExtension->ExpectingInterrupt = FALSE;
1532     deviceExtension->CurrentSrb = NULL;
1533 
1534     //
1535     // Search for devices.
1536     //
1537 
1538     for (deviceNumber = 0; deviceNumber < 2; deviceNumber++) {
1539 
1540         //
1541         // Select the device.
1542         //
1543 
1544         ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
1545                                (UCHAR)((deviceNumber << 4) | 0xA0));
1546 
1547         //
1548         // Check here for some SCSI adapters that incorporate IDE emulation.
1549         //
1550 
1551         GetStatus(baseIoAddress2, statusByte);
1552         if (statusByte == 0xFF) {
1553             continue;
1554         }
1555 
1556         AtapiSoftReset(baseIoAddress1,deviceNumber);
1557         WaitOnBusy(baseIoAddress2,statusByte);
1558 
1559         signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
1560         signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
1561 
1562         if (signatureLow == 0x14 && signatureHigh == 0xEB) {
1563 
1564             //
1565             // ATAPI signature found.
1566             // Issue the ATAPI identify command if this
1567             // is not for the crash dump utility.
1568             //
1569 
1570 atapiIssueId:
1571 
1572             if (!deviceExtension->DriverMustPoll) {
1573 
1574                 //
1575                 // Issue ATAPI packet identify command.
1576                 //
1577 
1578                 if (IssueIdentify(HwDeviceExtension,
1579                                   deviceNumber,
1580                                   Channel,
1581                                   IDE_COMMAND_ATAPI_IDENTIFY)) {
1582 
1583                     //
1584                     // Indicate ATAPI device.
1585                     //
1586 
1587                     DebugPrint((1,
1588                                "FindDevices: Device %x is ATAPI\n",
1589                                deviceNumber));
1590 
1591                     deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_ATAPI_DEVICE;
1592                     deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT;
1593 
1594                     deviceResponded = TRUE;
1595 
1596                     GetStatus(baseIoAddress2, statusByte);
1597                     if (statusByte & IDE_STATUS_ERROR) {
1598                         AtapiSoftReset(baseIoAddress1, deviceNumber);
1599                     }
1600 
1601 
1602                 } else {
1603 
1604                     //
1605                     // Indicate no working device.
1606                     //
1607 
1608                     DebugPrint((1,
1609                                "FindDevices: Device %x not responding\n",
1610                                deviceNumber));
1611 
1612                     deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_DEVICE_PRESENT;
1613                 }
1614 
1615             }
1616 
1617         } else {
1618 
1619             //
1620             // Issue IDE Identify. If an Atapi device is actually present, the signature
1621             // will be asserted, and the drive will be recognized as such.
1622             //
1623 
1624             if (IssueIdentify(HwDeviceExtension,
1625                               deviceNumber,
1626                               Channel,
1627                               IDE_COMMAND_IDENTIFY)) {
1628 
1629                 //
1630                 // IDE drive found.
1631                 //
1632 
1633 
1634                 DebugPrint((1,
1635                            "FindDevices: Device %x is IDE\n",
1636                            deviceNumber));
1637 
1638                 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] |= DFLAGS_DEVICE_PRESENT;
1639 
1640                 if (!AtapiOnly) {
1641                     deviceResponded = TRUE;
1642                 }
1643 
1644                 //
1645                 // Indicate IDE - not ATAPI device.
1646                 //
1647 
1648                 deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] &= ~DFLAGS_ATAPI_DEVICE;
1649 
1650 
1651             } else {
1652 
1653                 //
1654                 // Look to see if an Atapi device is present.
1655                 //
1656 
1657                 AtapiSoftReset(baseIoAddress1,deviceNumber);
1658 
1659                 WaitOnBusy(baseIoAddress2,statusByte);
1660 
1661                 signatureLow = ScsiPortReadPortUchar(&baseIoAddress1->CylinderLow);
1662                 signatureHigh = ScsiPortReadPortUchar(&baseIoAddress1->CylinderHigh);
1663 
1664                 if (signatureLow == 0x14 && signatureHigh == 0xEB) {
1665                     goto atapiIssueId;
1666                 }
1667             }
1668         }
1669     }
1670 
1671     for (i = 0; i < 2; i++) {
1672         if ((deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_DEVICE_PRESENT) &&
1673             (!(deviceExtension->DeviceFlags[i + (Channel * 2)] & DFLAGS_ATAPI_DEVICE)) && deviceResponded) {
1674 
1675             //
1676             // This hideous hack is to deal with ESDI devices that return
1677             // garbage geometry in the IDENTIFY data.
1678             // This is ONLY for the crashdump environment as
1679             // these are ESDI devices.
1680             //
1681 
1682             if (deviceExtension->IdentifyData[i].SectorsPerTrack ==
1683                     0x35 &&
1684                 deviceExtension->IdentifyData[i].NumberOfHeads ==
1685                     0x07) {
1686 
1687                 DebugPrint((1,
1688                            "FindDevices: Found nasty Compaq ESDI!\n"));
1689 
1690                 //
1691                 // Change these values to something reasonable.
1692                 //
1693 
1694                 deviceExtension->IdentifyData[i].SectorsPerTrack =
1695                     0x34;
1696                 deviceExtension->IdentifyData[i].NumberOfHeads =
1697                     0x0E;
1698             }
1699 
1700             if (deviceExtension->IdentifyData[i].SectorsPerTrack ==
1701                     0x35 &&
1702                 deviceExtension->IdentifyData[i].NumberOfHeads ==
1703                     0x0F) {
1704 
1705                 DebugPrint((1,
1706                            "FindDevices: Found nasty Compaq ESDI!\n"));
1707 
1708                 //
1709                 // Change these values to something reasonable.
1710                 //
1711 
1712                 deviceExtension->IdentifyData[i].SectorsPerTrack =
1713                     0x34;
1714                 deviceExtension->IdentifyData[i].NumberOfHeads =
1715                     0x0F;
1716             }
1717 
1718 
1719             if (deviceExtension->IdentifyData[i].SectorsPerTrack ==
1720                     0x36 &&
1721                 deviceExtension->IdentifyData[i].NumberOfHeads ==
1722                     0x07) {
1723 
1724                 DebugPrint((1,
1725                            "FindDevices: Found nasty UltraStor ESDI!\n"));
1726 
1727                 //
1728                 // Change these values to something reasonable.
1729                 //
1730 
1731                 deviceExtension->IdentifyData[i].SectorsPerTrack =
1732                     0x3F;
1733                 deviceExtension->IdentifyData[i].NumberOfHeads =
1734                     0x10;
1735                 skipSetParameters = TRUE;
1736             }
1737 
1738 
1739             if (!skipSetParameters) {
1740 
1741                 WaitOnBusy(baseIoAddress2,statusByte);
1742 
1743                 //
1744                 // Select the device.
1745                 //
1746 
1747                 ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
1748                                        (UCHAR)((i << 4) | 0xA0));
1749 
1750                 GetStatus(baseIoAddress2, statusByte);
1751 
1752                 if (statusByte & IDE_STATUS_ERROR) {
1753 
1754                     //
1755                     // Reset the device.
1756                     //
1757 
1758                     DebugPrint((2,
1759                                 "FindDevices: Resetting controller before SetDriveParameters.\n"));
1760 
1761                     ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
1762                     ScsiPortStallExecution(500 * 1000);
1763                     ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
1764                     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
1765                                            (UCHAR)((i << 4) | 0xA0));
1766 
1767                     do {
1768 
1769                         //
1770                         // Wait for Busy to drop.
1771                         //
1772 
1773                         ScsiPortStallExecution(100);
1774                         GetStatus(baseIoAddress2, statusByte);
1775 
1776                     } while ((statusByte & IDE_STATUS_BUSY) && waitCount--);
1777                 }
1778 
1779                 WaitOnBusy(baseIoAddress2,statusByte);
1780                 DebugPrint((2,
1781                             "FindDevices: Status before SetDriveParameters: (%x) (%x)\n",
1782                             statusByte,
1783                             ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect)));
1784 
1785                 //
1786                 // Use the IDENTIFY data to set drive parameters.
1787                 //
1788 
1789                 if (!SetDriveParameters(HwDeviceExtension,i,Channel)) {
1790 
1791                     DebugPrint((0,
1792                                "AtapHwInitialize: Set drive parameters for device %d failed\n",
1793                                i));
1794 
1795                     //
1796                     // Don't use this device as writes could cause corruption.
1797                     //
1798 
1799                     deviceExtension->DeviceFlags[i + Channel] = 0;
1800                     continue;
1801 
1802                 }
1803                 if (deviceExtension->DeviceFlags[deviceNumber + (Channel * 2)] & DFLAGS_REMOVABLE_DRIVE) {
1804 
1805                     //
1806                     // Pick up ALL IDE removable drives that conform to Yosemite V0.2...
1807                     //
1808 
1809                     AtapiOnly = FALSE;
1810                 }
1811 
1812 
1813                 //
1814                 // Indicate that a device was found.
1815                 //
1816 
1817                 if (!AtapiOnly) {
1818                     deviceResponded = TRUE;
1819                 }
1820             }
1821         }
1822     }
1823 
1824     //
1825     // Make sure master device is selected on exit.
1826     //
1827 
1828     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect, 0xA0);
1829 
1830     //
1831     // Reset the controller. This is a feeble attempt to leave the ESDI
1832     // controllers in a state that ATDISK driver will recognize them.
1833     // The problem in ATDISK has to do with timings as it is not reproducible
1834     // in debug. The reset should restore the controller to its poweron state
1835     // and give the system enough time to settle.
1836     //
1837 
1838     if (!deviceResponded) {
1839 
1840         ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_RESET_CONTROLLER );
1841         ScsiPortStallExecution(50 * 1000);
1842         ScsiPortWritePortUchar(&baseIoAddress2->AlternateStatus,IDE_DC_REENABLE_CONTROLLER);
1843     }
1844 
1845     return deviceResponded;
1846 
1847 } // end FindDevices()
1848 
1849 
1850 ULONG
1851 NTAPI
1852 AtapiParseArgumentString(
1853     IN PCHAR String,
1854     IN PCHAR KeyWord
1855     )
1856 
1857 /*++
1858 
1859 Routine Description:
1860 
1861     This routine will parse the string for a match on the keyword, then
1862     calculate the value for the keyword and return it to the caller.
1863 
1864 Arguments:
1865 
1866     String - The ASCII string to parse.
1867     KeyWord - The keyword for the value desired.
1868 
1869 Return Values:
1870 
1871     Zero if value not found
1872     Value converted from ASCII to binary.
1873 
1874 --*/
1875 
1876 {
1877     PCHAR cptr;
1878     PCHAR kptr;
1879     ULONG value;
1880     ULONG stringLength = 0;
1881     ULONG keyWordLength = 0;
1882     ULONG index;
1883 
1884     if (!String) {
1885         return 0;
1886     }
1887     if (!KeyWord) {
1888         return 0;
1889     }
1890 
1891     //
1892     // Calculate the string length and lower case all characters.
1893     //
1894 
1895     cptr = String;
1896     while (*cptr) {
1897         if (*cptr >= 'A' && *cptr <= 'Z') {
1898             *cptr = *cptr + ('a' - 'A');
1899         }
1900         cptr++;
1901         stringLength++;
1902     }
1903 
1904     //
1905     // Calculate the keyword length and lower case all characters.
1906     //
1907 
1908     cptr = KeyWord;
1909     while (*cptr) {
1910 
1911         if (*cptr >= 'A' && *cptr <= 'Z') {
1912             *cptr = *cptr + ('a' - 'A');
1913         }
1914         cptr++;
1915         keyWordLength++;
1916     }
1917 
1918     if (keyWordLength > stringLength) {
1919 
1920         //
1921         // Can't possibly have a match.
1922         //
1923 
1924         return 0;
1925     }
1926 
1927     //
1928     // Now setup and start the compare.
1929     //
1930 
1931     cptr = String;
1932 
1933 ContinueSearch:
1934 
1935     //
1936     // The input string may start with white space.  Skip it.
1937     //
1938 
1939     while (*cptr == ' ' || *cptr == '\t') {
1940         cptr++;
1941     }
1942 
1943     if (*cptr == '\0') {
1944 
1945         //
1946         // end of string.
1947         //
1948 
1949         return 0;
1950     }
1951 
1952     kptr = KeyWord;
1953     while (*cptr++ == *kptr++) {
1954 
1955         if (*(cptr - 1) == '\0') {
1956 
1957             //
1958             // end of string
1959             //
1960 
1961             return 0;
1962         }
1963     }
1964 
1965     if (*(kptr - 1) == '\0') {
1966 
1967         //
1968         // May have a match backup and check for blank or equals.
1969         //
1970 
1971         cptr--;
1972         while (*cptr == ' ' || *cptr == '\t') {
1973             cptr++;
1974         }
1975 
1976         //
1977         // Found a match.  Make sure there is an equals.
1978         //
1979 
1980         if (*cptr != '=') {
1981 
1982             //
1983             // Not a match so move to the next semicolon.
1984             //
1985 
1986             while (*cptr) {
1987                 if (*cptr++ == ';') {
1988                     goto ContinueSearch;
1989                 }
1990             }
1991             return 0;
1992         }
1993 
1994         //
1995         // Skip the equals sign.
1996         //
1997 
1998         cptr++;
1999 
2000         //
2001         // Skip white space.
2002         //
2003 
2004         while ((*cptr == ' ') || (*cptr == '\t')) {
2005             cptr++;
2006         }
2007 
2008         if (*cptr == '\0') {
2009 
2010             //
2011             // Early end of string, return not found
2012             //
2013 
2014             return 0;
2015         }
2016 
2017         if (*cptr == ';') {
2018 
2019             //
2020             // This isn't it either.
2021             //
2022 
2023             cptr++;
2024             goto ContinueSearch;
2025         }
2026 
2027         value = 0;
2028         if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
2029 
2030             //
2031             // Value is in Hex.  Skip the "0x"
2032             //
2033 
2034             cptr += 2;
2035             for (index = 0; *(cptr + index); index++) {
2036 
2037                 if (*(cptr + index) == ' ' ||
2038                     *(cptr + index) == '\t' ||
2039                     *(cptr + index) == ';') {
2040                      break;
2041                 }
2042 
2043                 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
2044                     value = (16 * value) + (*(cptr + index) - '0');
2045                 } else {
2046                     if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
2047                         value = (16 * value) + (*(cptr + index) - 'a' + 10);
2048                     } else {
2049 
2050                         //
2051                         // Syntax error, return not found.
2052                         //
2053                         return 0;
2054                     }
2055                 }
2056             }
2057         } else {
2058 
2059             //
2060             // Value is in Decimal.
2061             //
2062 
2063             for (index = 0; *(cptr + index); index++) {
2064 
2065                 if (*(cptr + index) == ' ' ||
2066                     *(cptr + index) == '\t' ||
2067                     *(cptr + index) == ';') {
2068                      break;
2069                 }
2070 
2071                 if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
2072                     value = (10 * value) + (*(cptr + index) - '0');
2073                 } else {
2074 
2075                     //
2076                     // Syntax error return not found.
2077                     //
2078                     return 0;
2079                 }
2080             }
2081         }
2082 
2083         return value;
2084     } else {
2085 
2086         //
2087         // Not a match check for ';' to continue search.
2088         //
2089 
2090         while (*cptr) {
2091             if (*cptr++ == ';') {
2092                 goto ContinueSearch;
2093             }
2094         }
2095 
2096         return 0;
2097     }
2098 }
2099 
2100 
2101 
2102 
2103 
2104 ULONG
2105 NTAPI
2106 AtapiFindController(
2107     IN PVOID HwDeviceExtension,
2108     IN PVOID Context,
2109     IN PVOID BusInformation,
2110     IN PCHAR ArgumentString,
2111     IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2112     OUT PBOOLEAN Again
2113     )
2114 /*++
2115 
2116 Routine Description:
2117 
2118     This function is called by the OS-specific port driver after
2119     the necessary storage has been allocated, to gather information
2120     about the adapter's configuration.
2121 
2122 Arguments:
2123 
2124     HwDeviceExtension - HBA miniport driver's adapter data storage
2125     Context - Address of adapter count
2126     ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
2127     ConfigInfo - Configuration information structure describing HBA
2128     Again - Indicates search for adapters to continue
2129 
2130 Return Value:
2131 
2132     ULONG
2133 
2134 --*/
2135 
2136 {
2137     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
2138     PULONG               adapterCount    = (PULONG)Context;
2139     PUCHAR               ioSpace = NULL;
2140     ULONG                i;
2141     ULONG                irq;
2142     ULONG                portBase;
2143     ULONG                retryCount;
2144     PCI_SLOT_NUMBER      slotData;
2145     PPCI_COMMON_CONFIG   pciData;
2146     ULONG                pciBuffer;
2147     BOOLEAN              atapiOnly;
2148     UCHAR                statusByte;
2149     BOOLEAN              preConfig = FALSE;
2150     //
2151     // The following table specifies the ports to be checked when searching for
2152     // an IDE controller.  A zero entry terminates the search.
2153     //
2154 
2155     CONST ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
2156 
2157     //
2158     // The following table specifies interrupt levels corresponding to the
2159     // port addresses in the previous table.
2160     //
2161 
2162     CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0};
2163 
2164     if (!deviceExtension) {
2165         return SP_RETURN_ERROR;
2166     }
2167 
2168     //
2169     // Check to see if this is a special configuration environment.
2170     //
2171 
2172     portBase = irq = 0;
2173     if (ArgumentString) {
2174 
2175         irq = AtapiParseArgumentString(ArgumentString, "Interrupt");
2176         if (irq ) {
2177 
2178             //
2179             // Both parameters must be present to proceed
2180             //
2181 
2182             portBase = AtapiParseArgumentString(ArgumentString, "BaseAddress");
2183             if (!portBase) {
2184 
2185                 //
2186                 // Try a default search for the part.
2187                 //
2188 
2189                 irq = 0;
2190             }
2191         }
2192     }
2193 
2194 
2195 
2196     //
2197     // Scan though the adapter address looking for adapters.
2198     //
2199     if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
2200         ioSpace =  ScsiPortGetDeviceBase(HwDeviceExtension,
2201                                          ConfigInfo->AdapterInterfaceType,
2202                                          ConfigInfo->SystemIoBusNumber,
2203                                          (*ConfigInfo->AccessRanges)[0].RangeStart,
2204                                          (*ConfigInfo->AccessRanges)[0].RangeLength,
2205                                          (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
2206         *Again = FALSE;
2207         //
2208         // Since we have pre-configured information we only need to go through this loop once
2209         //
2210         preConfig = TRUE;
2211         portBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
2212 
2213     }
2214 
2215 
2216 
2217     while (AdapterAddresses[*adapterCount] != 0) {
2218 
2219         retryCount = 4;
2220 
2221         for (i = 0; i < 4; i++) {
2222 
2223             //
2224             // Zero device fields to ensure that if earlier devices were found,
2225             // but not claimed, the fields are cleared.
2226             //
2227 
2228             deviceExtension->DeviceFlags[i] &= ~(DFLAGS_ATAPI_DEVICE | DFLAGS_DEVICE_PRESENT | DFLAGS_TAPE_DEVICE);
2229         }
2230 
2231         //
2232         // Get the system physical address for this IO range.
2233         //
2234 
2235 
2236         //
2237         // Check if configInfo has the default information
2238         // if not, we go and find ourselves
2239         //
2240 
2241         if (preConfig == FALSE) {
2242 
2243             if (portBase) {
2244                 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
2245                                                 ConfigInfo->AdapterInterfaceType,
2246                                                 ConfigInfo->SystemIoBusNumber,
2247                                                 ScsiPortConvertUlongToPhysicalAddress(portBase),
2248                                                 8,
2249                                                 TRUE);
2250             } else {
2251                 ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
2252                                                 ConfigInfo->AdapterInterfaceType,
2253                                                 ConfigInfo->SystemIoBusNumber,
2254                                                 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]),
2255                                                 8,
2256                                                 TRUE);
2257             }
2258 
2259         }// ConfigInfo check
2260         //
2261         // Update the adapter count.
2262         //
2263 
2264         (*adapterCount)++;
2265 
2266         //
2267         // Check if ioSpace accessible.
2268         //
2269 
2270         if (!ioSpace) {
2271             continue;
2272         }
2273 
2274 retryIdentifier:
2275 
2276         //
2277         // Select master.
2278         //
2279 
2280         ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0);
2281 
2282         //
2283         // Check if card at this address.
2284         //
2285 
2286         ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA);
2287 
2288         //
2289         // Check if identifier can be read back.
2290         //
2291 
2292         if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {
2293 
2294             DebugPrint((2,
2295                         "AtapiFindController: Identifier read back from Master (%x)\n",
2296                         statusByte));
2297 
2298             statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_2)ioSpace)->AlternateStatus);
2299 
2300             if (statusByte & IDE_STATUS_BUSY) {
2301 
2302                 i = 0;
2303 
2304                 //
2305                 // Could be the TEAC in a thinkpad. Their dos driver puts it in a sleep-mode that
2306                 // warm boots don't clear.
2307                 //
2308 
2309                 do {
2310                     ScsiPortStallExecution(1000);
2311                     statusByte = ScsiPortReadPortUchar(&((PATAPI_REGISTERS_1)ioSpace)->Command);
2312                     DebugPrint((3,
2313                                 "AtapiFindController: First access to status %x\n",
2314                                 statusByte));
2315                 } while ((statusByte & IDE_STATUS_BUSY) && ++i < 10);
2316 
2317                 if (retryCount-- && (!(statusByte & IDE_STATUS_BUSY))) {
2318                     goto retryIdentifier;
2319                 }
2320             }
2321 
2322             //
2323             // Select slave.
2324             //
2325 
2326             ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0);
2327 
2328             //
2329             // See if slave is present.
2330             //
2331 
2332             ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA);
2333 
2334             if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {
2335 
2336                 DebugPrint((2,
2337                             "AtapiFindController: Identifier read back from Slave (%x)\n",
2338                             statusByte));
2339 
2340                 //
2341                 //
2342                 // No controller at this base address.
2343                 //
2344 
2345                 ScsiPortFreeDeviceBase(HwDeviceExtension,
2346                                        ioSpace);
2347 
2348                 continue;
2349             }
2350         }
2351 
2352         //
2353         // Record base IO address.
2354         //
2355 
2356         deviceExtension->BaseIoAddress1[0] = (PIDE_REGISTERS_1)(ioSpace);
2357 
2358         //
2359         // Fill in the access array information only if default params are not in there.
2360         //
2361         if (preConfig == FALSE) {
2362 
2363             //
2364             // An adapter has been found request another call, only if we didn't get preconfigured info.
2365             //
2366             *Again = TRUE;
2367 
2368                 if (portBase) {
2369                 (*ConfigInfo->AccessRanges)[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(portBase);
2370             } else {
2371                 (*ConfigInfo->AccessRanges)[0].RangeStart =
2372                     ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]);
2373             }
2374 
2375             (*ConfigInfo->AccessRanges)[0].RangeLength = 8;
2376             (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
2377 
2378             //
2379             // Indicate the interrupt level corresponding to this IO range.
2380             //
2381 
2382             if (irq) {
2383                 ConfigInfo->BusInterruptLevel = irq;
2384             } else {
2385                 ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1];
2386             }
2387 
2388             if (ConfigInfo->AdapterInterfaceType == MicroChannel) {
2389                 ConfigInfo->InterruptMode = LevelSensitive;
2390             } else {
2391                 ConfigInfo->InterruptMode = Latched;
2392             }
2393         }
2394         //
2395         // Get the system physical address for the second IO range.
2396         //
2397 
2398 
2399         if (portBase) {
2400             ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
2401                                             ConfigInfo->AdapterInterfaceType,
2402                                             ConfigInfo->SystemIoBusNumber,
2403                                             ScsiPortConvertUlongToPhysicalAddress(portBase + 0x206),
2404                                             1,
2405                                             TRUE);
2406         } else {
2407             ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
2408                                             ConfigInfo->AdapterInterfaceType,
2409                                             ConfigInfo->SystemIoBusNumber,
2410                                             ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206),
2411                                             1,
2412                                             TRUE);
2413         }
2414 
2415         deviceExtension->BaseIoAddress2[0] = (PIDE_REGISTERS_2)(ioSpace);
2416 
2417         deviceExtension->NumberChannels = 1;
2418 
2419         ConfigInfo->NumberOfBuses = 1;
2420         ConfigInfo->MaximumNumberOfTargets = 2;
2421 
2422         //
2423         // Indicate maximum transfer length is 64k.
2424         //
2425 
2426         ConfigInfo->MaximumTransferLength = 0x10000;
2427 
2428         DebugPrint((1,
2429                    "AtapiFindController: Found IDE at %x\n",
2430                    deviceExtension->BaseIoAddress1[0]));
2431 
2432 
2433         //
2434         // For Daytona, the atdisk driver gets the first shot at the
2435         // primary and secondary controllers.
2436         //
2437 
2438         if (preConfig == FALSE) {
2439 
2440 
2441             if (*adapterCount - 1 < 2) {
2442 
2443                 //
2444                 // Determine whether this driver is being initialized by the
2445                 // system or as a crash dump driver.
2446                 //
2447 
2448                 if (ArgumentString) {
2449 
2450                     if (AtapiParseArgumentString(ArgumentString, "dump") == 1) {
2451                         DebugPrint((3,
2452                                    "AtapiFindController: Crash dump\n"));
2453                         atapiOnly = FALSE;
2454                         deviceExtension->DriverMustPoll = TRUE;
2455                     } else {
2456                         DebugPrint((3,
2457                                    "AtapiFindController: Atapi Only\n"));
2458                         atapiOnly = TRUE;
2459                         deviceExtension->DriverMustPoll = FALSE;
2460                     }
2461                 } else {
2462 
2463                     DebugPrint((3,
2464                                "AtapiFindController: Atapi Only\n"));
2465                     atapiOnly = TRUE;
2466                     deviceExtension->DriverMustPoll = FALSE;
2467                 }
2468 
2469             } else {
2470                 atapiOnly = FALSE;
2471             }
2472 
2473             //
2474             // If this is a PCI machine, pick up all devices.
2475             //
2476 
2477 
2478             pciData = (PPCI_COMMON_CONFIG)&pciBuffer;
2479 
2480             slotData.u.bits.DeviceNumber = 0;
2481             slotData.u.bits.FunctionNumber = 0;
2482 
2483             if (ScsiPortGetBusData(deviceExtension,
2484                                    PCIConfiguration,
2485                                    0,                  // BusNumber
2486                                    slotData.u.AsULONG,
2487                                    pciData,
2488                                    sizeof(ULONG))) {
2489 
2490                 atapiOnly = FALSE;
2491 
2492                 //
2493                 // Wait on doing this, until a reliable method
2494                 // of determining support is found.
2495                 //
2496 
2497     #if 0
2498                 deviceExtension->DWordIO = TRUE;
2499     #endif
2500 
2501             } else {
2502                 deviceExtension->DWordIO = FALSE;
2503             }
2504 
2505         } else {
2506 
2507             atapiOnly = FALSE;
2508             deviceExtension->DriverMustPoll = FALSE;
2509 
2510         }// preConfig check
2511 
2512         //
2513         // Save the Interrupt Mode for later use
2514         //
2515         deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
2516 
2517         //
2518         // Search for devices on this controller.
2519         //
2520 
2521         if (FindDevices(HwDeviceExtension,
2522                         atapiOnly,
2523                         0)) {
2524 
2525             //
2526             // Claim primary or secondary ATA IO range.
2527             //
2528 
2529             if (portBase) {
2530                 switch (portBase) {
2531                 case 0x170:
2532                     ConfigInfo->AtdiskSecondaryClaimed = TRUE;
2533                     deviceExtension->PrimaryAddress = FALSE;
2534                     break;
2535                 case 0x1f0:
2536                     ConfigInfo->AtdiskPrimaryClaimed = TRUE;
2537                     deviceExtension->PrimaryAddress = TRUE;
2538                     break;
2539                 default:
2540                     break;
2541                 }
2542             } else {
2543                 if (*adapterCount == 1) {
2544                     ConfigInfo->AtdiskPrimaryClaimed = TRUE;
2545                     deviceExtension->PrimaryAddress = TRUE;
2546                 } else if (*adapterCount == 2) {
2547                     ConfigInfo->AtdiskSecondaryClaimed = TRUE;
2548                     deviceExtension->PrimaryAddress = FALSE;
2549                 }
2550             }
2551 
2552             return(SP_RETURN_FOUND);
2553         }
2554     }
2555 
2556     //
2557     // The entire table has been searched and no adapters have been found.
2558     // There is no need to call again and the device base can now be freed.
2559     // Clear the adapter count for the next bus.
2560     //
2561 
2562     *Again = FALSE;
2563     *(adapterCount) = 0;
2564 
2565     return(SP_RETURN_NOT_FOUND);
2566 
2567 } // end AtapiFindController()
2568 
2569 
2570 
2571 
2572 
2573 BOOLEAN
2574 NTAPI
2575 FindBrokenController(
2576     IN PVOID  DeviceExtension,
2577     IN PUCHAR VendorID,
2578     IN ULONG  VendorIDLength,
2579     IN PUCHAR DeviceID,
2580     IN ULONG  DeviceIDLength,
2581     IN OUT PULONG FunctionNumber,
2582     IN OUT PULONG SlotNumber,
2583     IN ULONG  BusNumber,
2584     OUT PBOOLEAN LastSlot
2585     )
2586 
2587 /*++
2588 
2589 Routine Description:
2590 
2591     Walk PCI slot information looking for Vendor and Product ID matches.
2592 
2593 Arguments:
2594 
2595 Return Value:
2596 
2597     TRUE if card found.
2598 
2599 --*/
2600 {
2601     ULONG               pciBuffer;
2602     ULONG               slotNumber;
2603     ULONG               functionNumber;
2604     PCI_SLOT_NUMBER     slotData;
2605     PPCI_COMMON_CONFIG  pciData;
2606     UCHAR               vendorString[5];
2607     UCHAR               deviceString[5];
2608     PUCHAR              vendorStrPtr;
2609     PUCHAR              deviceStrPtr;
2610 
2611     pciData = (PPCI_COMMON_CONFIG)&pciBuffer;
2612 
2613     slotData.u.AsULONG = 0;
2614 
2615     //
2616     // Look at each device.
2617     //
2618 
2619     for (slotNumber = *SlotNumber;
2620          slotNumber < 32;
2621          slotNumber++) {
2622 
2623         slotData.u.bits.DeviceNumber = slotNumber;
2624 
2625         //
2626         // Look at each function.
2627         //
2628 
2629         for (functionNumber= *FunctionNumber;
2630              functionNumber < 8;
2631              functionNumber++) {
2632 
2633             slotData.u.bits.FunctionNumber = functionNumber;
2634 
2635             if (!ScsiPortGetBusData(DeviceExtension,
2636                                     PCIConfiguration,
2637                                     BusNumber,
2638                                     slotData.u.AsULONG,
2639                                     pciData,
2640                                     sizeof(ULONG))) {
2641 
2642                 //
2643                 // Out of PCI data.
2644                 //
2645 
2646                 *LastSlot = TRUE;
2647                 return FALSE;
2648             }
2649 
2650             if (pciData->VendorID == PCI_INVALID_VENDORID) {
2651 
2652                 //
2653                 // No PCI device, or no more functions on device
2654                 // move to next PCI device.
2655                 //
2656 
2657                 break;
2658             }
2659 
2660             //
2661             // Translate hex ids to strings.
2662             //
2663 
2664             vendorStrPtr = vendorString;
2665             deviceStrPtr = deviceString;
2666             AtapiHexToString(pciData->VendorID, (PCHAR*)&vendorStrPtr);
2667             AtapiHexToString(pciData->DeviceID, (PCHAR*)&deviceStrPtr);
2668 
2669             DebugPrint((2,
2670                        "FindBrokenController: Bus %x Slot %x Function %x Vendor %s Product %s\n",
2671                        BusNumber,
2672                        slotNumber,
2673                        functionNumber,
2674                        vendorString,
2675                        deviceString));
2676 
2677             //
2678             // Compare strings.
2679             //
2680 
2681             if (AtapiStringCmp((PCHAR)vendorString,
2682                         (PCHAR)VendorID,
2683                         VendorIDLength) ||
2684                 AtapiStringCmp((PCHAR)deviceString,
2685                         (PCHAR)DeviceID,
2686                         DeviceIDLength)) {
2687 
2688                 //
2689                 // Not our PCI device. Try next device/function
2690                 //
2691 
2692                 continue;
2693             }
2694 
2695             *FunctionNumber = functionNumber;
2696             *SlotNumber     = slotNumber;
2697             return TRUE;
2698 
2699         }   // next PCI function
2700 
2701         *FunctionNumber = 0;
2702 
2703     }   // next PCI slot
2704 
2705     *LastSlot = TRUE;
2706     return FALSE;
2707 } // end FindBrokenController
2708 
2709 
2710 ULONG
2711 NTAPI
2712 AtapiFindNativeModeController(
2713     IN PVOID HwDeviceExtension,
2714     IN PVOID Context,
2715     IN PVOID BusInformation,
2716     IN PCHAR ArgumentString,
2717     IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
2718     OUT PBOOLEAN Again
2719     )
2720 /*++
2721 
2722 Routine Description:
2723 
2724     This function is called by the OS-specific port driver after
2725     the necessary storage has been allocated, to gather information
2726     about the adapter's configuration.
2727 
2728 Arguments:
2729 
2730     HwDeviceExtension - HBA miniport driver's adapter data storage
2731     Context - Address of adapter count
2732     BusInformation -
2733     ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
2734     ConfigInfo - Configuration information structure describing HBA
2735     Again - Indicates search for adapters to continue
2736 
2737 Return Value:
2738 
2739     ULONG
2740 
2741 --*/
2742 
2743 {
2744     PHW_DEVICE_EXTENSION  deviceExtension = HwDeviceExtension;
2745     ULONG                 nativeModeAdapterTableIndex = (ULONG_PTR)Context;
2746     ULONG                 channel;
2747     PUCHAR                ioSpace;
2748     BOOLEAN               atapiOnly,
2749                           deviceFound = FALSE;
2750     UCHAR                 statusByte;
2751     PCI_SLOT_NUMBER       slotData;
2752     PCI_COMMON_CONFIG     pciData;
2753     ULONG                 funcNumber;
2754     ULONG                 busDataRead;
2755     UCHAR                 vendorString[5];
2756     UCHAR                 deviceString[5];
2757     PUCHAR                vendorStrPtr;
2758     PUCHAR                deviceStrPtr;
2759     SCSI_PHYSICAL_ADDRESS IoBasePort1;
2760     SCSI_PHYSICAL_ADDRESS IoBasePort2;
2761 
2762     //
2763     // The following table specifies the ports to be checked when searching for
2764     // an IDE controller.  A zero entry terminates the search.
2765     //
2766 
2767     CONST ULONG AdapterAddresses[3] = {0x1F0, 0x170, 0};
2768 
2769     if (!deviceExtension) {
2770         return SP_RETURN_ERROR;
2771     }
2772 
2773     *Again = FALSE;
2774 
2775     slotData.u.AsULONG = 0;
2776     slotData.u.bits.DeviceNumber = ConfigInfo->SlotNumber;
2777 
2778     for (funcNumber= 0; funcNumber < 8; funcNumber++) {
2779 
2780         slotData.u.bits.FunctionNumber = funcNumber;
2781 
2782         busDataRead = ScsiPortGetBusData(HwDeviceExtension,
2783                                          PCIConfiguration,
2784                                          ConfigInfo->SystemIoBusNumber,
2785                                          slotData.u.AsULONG,
2786                                          &pciData,
2787                                          sizeof (pciData));
2788         if (busDataRead != sizeof (pciData)) {
2789             return SP_RETURN_ERROR;
2790         }
2791         if (pciData.VendorID == PCI_INVALID_VENDORID) {
2792             return SP_RETURN_ERROR;
2793         }
2794 
2795         //
2796         // Translate hex ids to strings.
2797         //
2798 
2799         vendorStrPtr = vendorString;
2800         deviceStrPtr = deviceString;
2801         AtapiHexToString(pciData.VendorID, (PCHAR*)&vendorStrPtr);
2802         AtapiHexToString(pciData.DeviceID, (PCHAR*)&deviceStrPtr);
2803 
2804         //
2805         // Compare strings.
2806         //
2807 
2808         if (AtapiStringCmp((PCHAR)vendorString,
2809                     NativeModeAdapters[nativeModeAdapterTableIndex].VendorId,
2810                     NativeModeAdapters[nativeModeAdapterTableIndex].VendorIdLength) ||
2811             AtapiStringCmp((PCHAR)deviceString,
2812                     NativeModeAdapters[nativeModeAdapterTableIndex].DeviceId,
2813                     NativeModeAdapters[nativeModeAdapterTableIndex].DeviceIdLength)) {
2814             continue;
2815         }
2816 
2817         if (pciData.ProgIf & ((1 << 2) | (1 << 0))) {
2818             // both primary and secondary channel are in native mode
2819 
2820             // Found our device
2821             *Again = TRUE;
2822 
2823             break;
2824         }
2825     }
2826 
2827     if (*Again != FALSE) {
2828 
2829         for (channel = 0; channel < 2; channel++) {
2830 
2831             IoBasePort1 = (*ConfigInfo->AccessRanges)[channel * 2 + 0].RangeStart;
2832             IoBasePort2 = (*ConfigInfo->AccessRanges)[channel * 2 + 1].RangeStart;
2833             IoBasePort2 = ScsiPortConvertUlongToPhysicalAddress(ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) + 2);
2834 
2835             //
2836             // Get the system physical address for this IO range.
2837             //
2838 
2839             ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
2840                                             ConfigInfo->AdapterInterfaceType,
2841                                             ConfigInfo->SystemIoBusNumber,
2842                                             IoBasePort1,
2843                                             8,
2844                                             TRUE);
2845 
2846             //
2847             // Check if ioSpace accessible.
2848             //
2849 
2850             if (!ioSpace) {
2851                 continue;
2852             }
2853 
2854             //
2855             // Select master.
2856             //
2857 
2858             ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0);
2859 
2860             //
2861             // Check if card at this address.
2862             //
2863 
2864             ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA);
2865 
2866             //
2867             // Check if identifier can be read back.
2868             //
2869 
2870             if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {
2871 
2872                 DebugPrint((2,
2873                             "AtapiFindPciController: Identifier read back from Master (%x)\n",
2874                             statusByte));
2875 
2876 
2877                 //
2878                 // Select slave.
2879                 //
2880 
2881                 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0);
2882 
2883                 //
2884                 // See if slave is present.
2885                 //
2886 
2887                 ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA);
2888 
2889                 if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {
2890 
2891                     DebugPrint((2,
2892                                 "AtapiFindPciController: Identifier read back from Slave (%x)\n",
2893                                 statusByte));
2894 
2895                     //
2896                     //
2897                     // No controller at this base address.
2898                     //
2899 
2900                     ScsiPortFreeDeviceBase(HwDeviceExtension,
2901                                            ioSpace);
2902 
2903                     //
2904                     // If the chip is there, but we couldn't find the primary channel, try the secondary.
2905                     // If we couldn't find a secondary, who cares.
2906                     //
2907 
2908                     if (channel == 1) {
2909 
2910                         goto setStatusAndExit;
2911 
2912                     } else {
2913                         continue;
2914                     }
2915                 }
2916             }
2917 
2918             //
2919             // Record base IO address.
2920             //
2921 
2922             deviceExtension->BaseIoAddress1[channel] = (PIDE_REGISTERS_1)(ioSpace);
2923 
2924             //
2925             // Get the system physical address for the second IO range.
2926             //
2927 
2928             ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
2929                                             ConfigInfo->AdapterInterfaceType,
2930                                             ConfigInfo->SystemIoBusNumber,
2931                                             IoBasePort2,
2932                                             1,
2933                                             TRUE);
2934 
2935             deviceExtension->BaseIoAddress2[channel] = (PIDE_REGISTERS_2)(ioSpace);
2936 
2937             deviceExtension->NumberChannels = 2;
2938 
2939             //
2940             // Indicate only one bus.
2941             //
2942 
2943             ConfigInfo->NumberOfBuses = 1;
2944 
2945             //
2946             // Indicate four devices can be attached to the adapter, since we
2947             // have to serialize access to the two channels.
2948             //
2949 
2950             ConfigInfo->MaximumNumberOfTargets = 4;
2951 
2952             //
2953             // Indicate maximum transfer length is 64k.
2954             //
2955 
2956             ConfigInfo->MaximumTransferLength = 0x10000;
2957 
2958             DebugPrint((1,
2959                        "AtapiFindPciController: Found native mode IDE at %x\n",
2960                        deviceExtension->BaseIoAddress1[channel]));
2961 
2962             //
2963             // Since we will always pick up this part, and not atdisk, so indicate.
2964             //
2965 
2966             atapiOnly = FALSE;
2967 
2968             //
2969             // Save the Interrupt Mode for later use
2970             //
2971             deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
2972 
2973             //
2974             // Search for devices on this controller.
2975             //
2976 
2977             if (FindDevices(HwDeviceExtension,
2978                         atapiOnly,
2979                         channel)){
2980                 deviceFound = TRUE;
2981             }
2982 
2983             //
2984             // Claim primary or secondary ATA IO range.
2985             //
2986 
2987             if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort1) == AdapterAddresses[0]) {
2988                 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
2989                 deviceExtension->PrimaryAddress = TRUE;
2990 
2991             } else if (ScsiPortConvertPhysicalAddressToUlong(IoBasePort2) == AdapterAddresses[1]) {
2992                 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
2993                 deviceExtension->PrimaryAddress = FALSE;
2994             }
2995         }
2996     }
2997 
2998 setStatusAndExit:
2999 
3000     if (deviceFound) {
3001 
3002         *Again = TRUE;
3003         return SP_RETURN_FOUND;
3004     }
3005 
3006     *Again = FALSE;
3007     return SP_RETURN_NOT_FOUND;
3008 
3009 } // end AtapiFindNativeModeController()
3010 
3011 
3012 ULONG
3013 NTAPI
3014 AtapiFindPCIController(
3015     IN PVOID HwDeviceExtension,
3016     IN PVOID Context,
3017     IN PVOID BusInformation,
3018     IN PCHAR ArgumentString,
3019     IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
3020     OUT PBOOLEAN Again
3021     )
3022 /*++
3023 
3024 Routine Description:
3025 
3026     This function is called by the OS-specific port driver after
3027     the necessary storage has been allocated, to gather information
3028     about the adapter's configuration.
3029 
3030 Arguments:
3031 
3032     HwDeviceExtension - HBA miniport driver's adapter data storage
3033     Context - Address of adapter count
3034     BusInformation -
3035     ArgumentString - Used to determine whether driver is client of ntldr or crash dump utility.
3036     ConfigInfo - Configuration information structure describing HBA
3037     Again - Indicates search for adapters to continue
3038 
3039 Return Value:
3040 
3041     ULONG
3042 
3043 --*/
3044 
3045 {
3046     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
3047     PULONG               adapterCount    = (PULONG)Context;
3048     ULONG                channel         = 0;
3049     static ULONG         functionNumber,
3050                          slotNumber,
3051                          controllers;
3052     ULONG                i,j;
3053     PUCHAR               ioSpace;
3054     BOOLEAN              atapiOnly,
3055                          lastSlot,
3056                          controllerFound = FALSE,
3057                          deviceFound = FALSE;
3058     UCHAR                statusByte;
3059 
3060     //
3061     // The following table specifies the ports to be checked when searching for
3062     // an IDE controller.  A zero entry terminates the search.
3063     //
3064 
3065     CONST ULONG AdapterAddresses[5] = {0x1F0, 0x170, 0x1e8, 0x168, 0};
3066 
3067     //
3068     // The following table specifies interrupt levels corresponding to the
3069     // port addresses in the previous table.
3070     //
3071 
3072     CONST ULONG InterruptLevels[5] = {14, 15, 11, 10, 0};
3073 
3074     if (!deviceExtension) {
3075         return SP_RETURN_ERROR;
3076     }
3077 
3078     //
3079     // Since scsiport will call this function first before it calls AtapiFindController
3080     // we need to bypass it if we have data installed in ConfigInfo, by the pcmcia driver.
3081     // In that case atapifindcontroller should be called first.
3082     // Instead of modifying atapi  driverEntry to search of PCIBus first (now its ISA)
3083     // the check is put here.
3084     //
3085 
3086     if (ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
3087 
3088         return AtapiFindController(HwDeviceExtension,
3089                                    Context,
3090                                    BusInformation,
3091                                    ArgumentString,
3092                                    ConfigInfo,
3093                                    Again);
3094     }
3095 
3096 
3097     //
3098     // Gronk PCI config space looking for the broken PCI IDE controllers that have only
3099     // one FIFO for both channels.
3100     // Don't do this. It's incorrect and nasty. It has to be done to work around these
3101     // broken parts, no other reason can justify this.
3102     //
3103 
3104     for (i = controllers; i < BROKEN_ADAPTERS; i++) {
3105 
3106         //
3107         // Determine if both channels are enabled and have devices.
3108         //
3109 
3110         lastSlot = FALSE;
3111 
3112         if (FindBrokenController(deviceExtension,
3113                                  (PUCHAR)BrokenAdapters[i].VendorId,
3114                                  BrokenAdapters[i].VendorIdLength,
3115                                  (PUCHAR)BrokenAdapters[i].DeviceId,
3116                                  BrokenAdapters[i].DeviceIdLength,
3117                                  &functionNumber,
3118                                  &slotNumber,
3119                                  ConfigInfo->SystemIoBusNumber,
3120                                  &lastSlot)) {
3121 
3122             slotNumber++;
3123             functionNumber = 0;
3124             controllerFound = TRUE;
3125 
3126             DebugPrint((1,
3127                         "Found broken PCI IDE controller: VendorId %s, DeviceId %s\n",
3128                         BrokenAdapters[i].VendorId,
3129                         BrokenAdapters[i].DeviceId));
3130 
3131             if (AdapterAddresses[*adapterCount] != 0) {
3132 
3133                 for (j = 0; j < 2; j++) {
3134 
3135                     //
3136                     // Get the system physical address for this IO range.
3137                     //
3138 
3139                     ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
3140                                                     ConfigInfo->AdapterInterfaceType,
3141                                                     ConfigInfo->SystemIoBusNumber,
3142                                                     ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount]),
3143                                                     8,
3144                                                     TRUE);
3145 
3146                     //
3147                     // Update the adapter count.
3148                     //
3149 
3150                     (*adapterCount)++;
3151 
3152                     //
3153                     // Check if ioSpace accessible.
3154                     //
3155 
3156                     if (!ioSpace) {
3157                         continue;
3158                     }
3159 
3160                     //
3161                     // Select master.
3162                     //
3163 
3164                     ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xA0);
3165 
3166                     //
3167                     // Check if card at this address.
3168                     //
3169 
3170                     ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA);
3171 
3172                     //
3173                     // Check if identifier can be read back.
3174                     //
3175 
3176                     if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {
3177 
3178                         DebugPrint((2,
3179                                     "AtapiFindPciController: Identifier read back from Master (%x)\n",
3180                                     statusByte));
3181 
3182 
3183                         //
3184                         // Select slave.
3185                         //
3186 
3187                         ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->DriveSelect, 0xB0);
3188 
3189                         //
3190                         // See if slave is present.
3191                         //
3192 
3193                         ScsiPortWritePortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow, 0xAA);
3194 
3195                         if ((statusByte = ScsiPortReadPortUchar(&((PIDE_REGISTERS_1)ioSpace)->CylinderLow)) != 0xAA) {
3196 
3197                             DebugPrint((2,
3198                                         "AtapiFindPciController: Identifier read back from Slave (%x)\n",
3199                                         statusByte));
3200 
3201                             //
3202                             //
3203                             // No controller at this base address.
3204                             //
3205 
3206                             ScsiPortFreeDeviceBase(HwDeviceExtension,
3207                                                    ioSpace);
3208 
3209                             //
3210                             // If the chip is there, but we couldn't find the primary channel, try the secondary.
3211                             // If we couldn't find a secondary, who cares.
3212                             //
3213 
3214                             if (j == 1) {
3215 
3216                                 goto setStatusAndExit;
3217 
3218                             } else {
3219                                 continue;
3220                             }
3221                         }
3222                     }
3223 
3224                     if (controllerFound) {
3225 
3226                         //
3227                         // Record base IO address.
3228                         //
3229 
3230                         deviceExtension->BaseIoAddress1[channel] = (PIDE_REGISTERS_1)(ioSpace);
3231 
3232                         //
3233                         // Fill in the access array information.
3234                         //
3235 
3236                         (*ConfigInfo->AccessRanges)[channel].RangeStart =
3237                                 ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1]);
3238 
3239                         (*ConfigInfo->AccessRanges)[channel].RangeLength = 8;
3240                         (*ConfigInfo->AccessRanges)[channel].RangeInMemory = FALSE;
3241 
3242                         //
3243                         // Indicate the interrupt level corresponding to this IO range.
3244                         //
3245 
3246                         if (channel == 0) {
3247                             ConfigInfo->BusInterruptLevel = InterruptLevels[*adapterCount - 1];
3248                             ConfigInfo->InterruptMode = Latched;
3249                         } else {
3250                             ConfigInfo->BusInterruptLevel2 = InterruptLevels[*adapterCount - 1];
3251                             ConfigInfo->InterruptMode2 = Latched;
3252                         }
3253 
3254                         //
3255                         // Get the system physical address for the second IO range.
3256                         //
3257 
3258                         ioSpace = ScsiPortGetDeviceBase(HwDeviceExtension,
3259                                                         ConfigInfo->AdapterInterfaceType,
3260                                                         ConfigInfo->SystemIoBusNumber,
3261                                                         ScsiPortConvertUlongToPhysicalAddress(AdapterAddresses[*adapterCount - 1] + 0x206),
3262                                                         1,
3263                                                         TRUE);
3264 
3265                         deviceExtension->BaseIoAddress2[channel] = (PIDE_REGISTERS_2)(ioSpace);
3266 
3267                         deviceExtension->NumberChannels = 2;
3268 
3269                         //
3270                         // Indicate only one bus.
3271                         //
3272 
3273                         ConfigInfo->NumberOfBuses = 1;
3274 
3275                         //
3276                         // Indicate four devices can be attached to the adapter, since we
3277                         // have to serialize access to the two channels.
3278                         //
3279 
3280                         ConfigInfo->MaximumNumberOfTargets = 4;
3281 
3282                         //
3283                         // Indicate maximum transfer length is 64k.
3284                         //
3285 
3286                         ConfigInfo->MaximumTransferLength = 0x10000;
3287 
3288                         DebugPrint((1,
3289                                    "AtapiFindPciController: Found broken IDE at %x\n",
3290                                    deviceExtension->BaseIoAddress1[channel]));
3291 
3292                         //
3293                         // Since we will always pick up this part, and not atdisk, so indicate.
3294                         //
3295 
3296                         atapiOnly = FALSE;
3297 
3298                         //
3299                         // Save the Interrupt Mode for later use
3300                         //
3301                         deviceExtension->InterruptMode = ConfigInfo->InterruptMode;
3302 
3303                         //
3304                         // Search for devices on this controller.
3305                         //
3306 
3307                         if (FindDevices(HwDeviceExtension,
3308                                     atapiOnly,
3309                                     channel++)){
3310                             deviceFound = TRUE;
3311                         }
3312 
3313                         //
3314                         // Claim primary or secondary ATA IO range.
3315                         //
3316 
3317                         if (*adapterCount == 1) {
3318                             ConfigInfo->AtdiskPrimaryClaimed = TRUE;
3319                             deviceExtension->PrimaryAddress = TRUE;
3320 
3321                         } else if (*adapterCount == 2) {
3322                             ConfigInfo->AtdiskSecondaryClaimed = TRUE;
3323                             deviceExtension->PrimaryAddress = FALSE;
3324                         }
3325                     }
3326                 }
3327             }
3328         }
3329 
3330 setStatusAndExit:
3331 
3332         if (lastSlot) {
3333             slotNumber = 0;
3334             functionNumber = 0;
3335         }
3336 
3337         controllers = i;
3338 
3339         if (controllerFound && deviceFound) {
3340 
3341             *Again = TRUE;
3342             return SP_RETURN_FOUND;
3343         }
3344     }
3345 
3346 
3347     //
3348     // The entire table has been searched and no adapters have been found.
3349     //
3350 
3351     *Again = FALSE;
3352 
3353     return SP_RETURN_NOT_FOUND;
3354 
3355 } // end AtapiFindPCIController()
3356 
3357 
3358 ULONG
3359 NTAPI
3360 Atapi2Scsi(
3361     IN PSCSI_REQUEST_BLOCK Srb,
3362     IN char *DataBuffer,
3363     IN ULONG ByteCount
3364     )
3365 {
3366     ULONG bytesAdjust = 0;
3367     if (Srb->Cdb[0] == ATAPI_MODE_SENSE) {
3368 
3369         PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)DataBuffer;
3370         PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)DataBuffer;
3371 
3372         header->ModeDataLength = header_10->ModeDataLengthLsb;
3373         header->MediumType = header_10->MediumType;
3374 
3375         //
3376         // ATAPI Mode Parameter Header doesn't have these fields.
3377         //
3378 
3379         header->DeviceSpecificParameter = header_10->Reserved[0];
3380         header->BlockDescriptorLength = header_10->Reserved[1];
3381 
3382         ByteCount -= sizeof(MODE_PARAMETER_HEADER_10);
3383         if (ByteCount > 0)
3384             ScsiPortMoveMemory(DataBuffer+sizeof(MODE_PARAMETER_HEADER),
3385                                DataBuffer+sizeof(MODE_PARAMETER_HEADER_10),
3386                                ByteCount);
3387 
3388         //
3389         // Change ATAPI_MODE_SENSE opcode back to SCSIOP_MODE_SENSE
3390         // so that we don't convert again.
3391         //
3392 
3393         Srb->Cdb[0] = SCSIOP_MODE_SENSE;
3394 
3395         bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
3396                       sizeof(MODE_PARAMETER_HEADER);
3397 
3398 
3399     }
3400 
3401     //
3402     // Convert to words.
3403     //
3404 
3405     return bytesAdjust >> 1;
3406 }
3407 
3408 
3409 VOID
3410 NTAPI
3411 AtapiCallBack(
3412     IN PVOID HwDeviceExtension
3413     )
3414 {
3415     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
3416     PSCSI_REQUEST_BLOCK  srb = deviceExtension->CurrentSrb;
3417     PATAPI_REGISTERS_2   baseIoAddress2;
3418     UCHAR statusByte;
3419 
3420     //
3421     // If the last command was DSC restrictive, see if it's set. If so, the device is
3422     // ready for a new request. Otherwise, reset the timer and come back to here later.
3423     //
3424 
3425     if (srb && (!(deviceExtension->ExpectingInterrupt))) {
3426 #if DBG
3427         if (!IS_RDP((srb->Cdb[0]))) {
3428             DebugPrint((1,
3429                         "AtapiCallBack: Invalid CDB marked as RDP - %x\n",
3430                         srb->Cdb[0]));
3431         }
3432 #endif
3433 
3434         baseIoAddress2 = (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1];
3435         if (deviceExtension->RDP) {
3436             GetStatus(baseIoAddress2, statusByte);
3437             if (statusByte & IDE_STATUS_DSC) {
3438 
3439                 ScsiPortNotification(RequestComplete,
3440                                      deviceExtension,
3441                                      srb);
3442 
3443                 //
3444                 // Clear current SRB.
3445                 //
3446 
3447                 deviceExtension->CurrentSrb = NULL;
3448                 deviceExtension->RDP = FALSE;
3449 
3450                 //
3451                 // Ask for next request.
3452                 //
3453 
3454                 ScsiPortNotification(NextRequest,
3455                                      deviceExtension,
3456                                      NULL);
3457 
3458 
3459                 return;
3460 
3461             } else {
3462 
3463                 DebugPrint((3,
3464                             "AtapiCallBack: Requesting another timer for Op %x\n",
3465                             deviceExtension->CurrentSrb->Cdb[0]));
3466 
3467                 ScsiPortNotification(RequestTimerCall,
3468                                      HwDeviceExtension,
3469                                      AtapiCallBack,
3470                                      1000);
3471                 return;
3472             }
3473         }
3474     }
3475 
3476     DebugPrint((2,
3477                 "AtapiCallBack: Calling ISR directly due to BUSY\n"));
3478     AtapiInterrupt(HwDeviceExtension);
3479 }
3480 
3481 
3482 BOOLEAN
3483 NTAPI
3484 AtapiInterrupt(
3485     IN PVOID HwDeviceExtension
3486     )
3487 
3488 /*++
3489 
3490 Routine Description:
3491 
3492     This is the interrupt service routine for ATAPI IDE miniport driver.
3493 
3494 Arguments:
3495 
3496     HwDeviceExtension - HBA miniport driver's adapter data storage
3497 
3498 Return Value:
3499 
3500     TRUE if expecting an interrupt.
3501 
3502 --*/
3503 
3504 {
3505     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
3506     PSCSI_REQUEST_BLOCK srb              = deviceExtension->CurrentSrb;
3507     PATAPI_REGISTERS_1 baseIoAddress1;
3508     PATAPI_REGISTERS_2 baseIoAddress2;
3509     ULONG wordCount = 0, wordsThisInterrupt = 256;
3510     ULONG status;
3511     ULONG i;
3512     UCHAR statusByte,interruptReason;
3513     BOOLEAN atapiDev = FALSE;
3514 
3515     if (srb) {
3516         baseIoAddress1 =    (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[srb->TargetId >> 1];
3517         baseIoAddress2 =    (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[srb->TargetId >> 1];
3518     } else {
3519         DebugPrint((2,
3520                     "AtapiInterrupt: CurrentSrb is NULL\n"));
3521         //
3522         // We can only support one ATAPI IDE master on Carolina, so find
3523         // the base address that is non NULL and clear its interrupt before
3524         // returning.
3525         //
3526 
3527 #ifdef _PPC_
3528 
3529         if ((PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0] != NULL) {
3530            baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0];
3531         } else {
3532            baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1];
3533         }
3534 
3535         GetBaseStatus(baseIoAddress1, statusByte);
3536 #else
3537 
3538         if (deviceExtension->InterruptMode == LevelSensitive) {
3539             if (deviceExtension->BaseIoAddress1[0] != NULL) {
3540                baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[0];
3541                GetBaseStatus(baseIoAddress1, statusByte);
3542             }
3543             if (deviceExtension->BaseIoAddress1[1] != NULL) {
3544                baseIoAddress1 = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[1];
3545                GetBaseStatus(baseIoAddress1, statusByte);
3546             }
3547         }
3548 #endif
3549         return FALSE;
3550     }
3551 
3552     if (!(deviceExtension->ExpectingInterrupt)) {
3553 
3554         DebugPrint((3,
3555                     "AtapiInterrupt: Unexpected interrupt.\n"));
3556         return FALSE;
3557     }
3558 
3559     //
3560     // Clear interrupt by reading status.
3561     //
3562 
3563     GetBaseStatus(baseIoAddress1, statusByte);
3564 
3565     DebugPrint((3,
3566                 "AtapiInterrupt: Entered with status (%x)\n",
3567                 statusByte));
3568 
3569 
3570     if (statusByte & IDE_STATUS_BUSY) {
3571         if (deviceExtension->DriverMustPoll) {
3572 
3573             //
3574             // Crashdump is polling and we got caught with busy asserted.
3575             // Just go away, and we will be polled again shortly.
3576             //
3577 
3578             DebugPrint((3,
3579                         "AtapiInterrupt: Hit BUSY while polling during crashdump.\n"));
3580 
3581             return TRUE;
3582         }
3583 
3584         //
3585         // Ensure BUSY is non-asserted.
3586         //
3587 
3588         for (i = 0; i < 10; i++) {
3589 
3590             GetBaseStatus(baseIoAddress1, statusByte);
3591             if (!(statusByte & IDE_STATUS_BUSY)) {
3592                 break;
3593             }
3594             ScsiPortStallExecution(5000);
3595         }
3596 
3597         if (i == 10) {
3598 
3599             DebugPrint((2,
3600                         "AtapiInterrupt: BUSY on entry. Status %x, Base IO %x\n",
3601                         statusByte,
3602                         baseIoAddress1));
3603 
3604             ScsiPortNotification(RequestTimerCall,
3605                                  HwDeviceExtension,
3606                                  AtapiCallBack,
3607                                  500);
3608             return TRUE;
3609         }
3610     }
3611 
3612 
3613     //
3614     // Check for error conditions.
3615     //
3616 
3617     if (statusByte & IDE_STATUS_ERROR) {
3618 
3619         if (srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
3620 
3621             //
3622             // Fail this request.
3623             //
3624 
3625             status = SRB_STATUS_ERROR;
3626             goto CompleteRequest;
3627         }
3628     }
3629 
3630     //
3631     // check reason for this interrupt.
3632     //
3633 
3634     if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
3635 
3636         interruptReason = (ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason) & 0x3);
3637         atapiDev = TRUE;
3638         wordsThisInterrupt = 256;
3639 
3640     } else {
3641 
3642         if (statusByte & IDE_STATUS_DRQ) {
3643 
3644             if (deviceExtension->MaximumBlockXfer[srb->TargetId]) {
3645                 wordsThisInterrupt = 256 * deviceExtension->MaximumBlockXfer[srb->TargetId];
3646 
3647             }
3648 
3649             if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
3650 
3651                 interruptReason =  0x2;
3652 
3653             } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
3654                 interruptReason = 0x0;
3655 
3656             } else {
3657                 status = SRB_STATUS_ERROR;
3658                 goto CompleteRequest;
3659             }
3660 
3661         } else if (statusByte & IDE_STATUS_BUSY) {
3662 
3663             return FALSE;
3664 
3665         } else {
3666 
3667             if (deviceExtension->WordsLeft) {
3668 
3669                 ULONG k;
3670 
3671                 //
3672                 // Funky behaviour seen with PCI IDE (not all, just one).
3673                 // The ISR hits with DRQ low, but comes up later.
3674                 //
3675 
3676                 for (k = 0; k < 5000; k++) {
3677                     GetStatus(baseIoAddress2,statusByte);
3678                     if (!(statusByte & IDE_STATUS_DRQ)) {
3679                         ScsiPortStallExecution(100);
3680                     } else {
3681                         break;
3682                     }
3683                 }
3684 
3685                 if (k == 5000) {
3686 
3687                     //
3688                     // reset the controller.
3689                     //
3690 
3691                     DebugPrint((1,
3692                                 "AtapiInterrupt: Resetting due to DRQ not up. Status %x, Base IO %x\n",
3693                                 statusByte,
3694                                 baseIoAddress1));
3695 
3696                     AtapiResetController(HwDeviceExtension,srb->PathId);
3697                     return TRUE;
3698                 } else {
3699 
3700                     interruptReason = (srb->SrbFlags & SRB_FLAGS_DATA_IN) ? 0x2 : 0x0;
3701                 }
3702 
3703             } else {
3704 
3705                 //
3706                 // Command complete - verify, write, or the SMART enable/disable.
3707                 //
3708                 // Also get_media_status
3709 
3710                 interruptReason = 0x3;
3711             }
3712         }
3713     }
3714 
3715     if (interruptReason == 0x1 && (statusByte & IDE_STATUS_DRQ)) {
3716 
3717         //
3718         // Write the packet.
3719         //
3720 
3721         DebugPrint((2,
3722                     "AtapiInterrupt: Writing Atapi packet.\n"));
3723 
3724         //
3725         // Send CDB to device.
3726         //
3727 
3728         WriteBuffer(baseIoAddress1,
3729                     (PUSHORT)srb->Cdb,
3730                     6);
3731 
3732         return TRUE;
3733 
3734     } else if (interruptReason == 0x0 && (statusByte & IDE_STATUS_DRQ)) {
3735 
3736         //
3737         // Write the data.
3738         //
3739 
3740         if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
3741 
3742             //
3743             // Pick up bytes to transfer and convert to words.
3744             //
3745 
3746             wordCount =
3747                 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);
3748 
3749             wordCount |=
3750                 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8;
3751 
3752             //
3753             // Covert bytes to words.
3754             //
3755 
3756             wordCount >>= 1;
3757 
3758             if (wordCount != deviceExtension->WordsLeft) {
3759                 DebugPrint((3,
3760                            "AtapiInterrupt: %d words requested; %d words xferred\n",
3761                            deviceExtension->WordsLeft,
3762                            wordCount));
3763             }
3764 
3765             //
3766             // Verify this makes sense.
3767             //
3768 
3769             if (wordCount > deviceExtension->WordsLeft) {
3770                 wordCount = deviceExtension->WordsLeft;
3771             }
3772 
3773         } else {
3774 
3775             //
3776             // IDE path. Check if words left is at least 256.
3777             //
3778 
3779             if (deviceExtension->WordsLeft < wordsThisInterrupt) {
3780 
3781                //
3782                // Transfer only words requested.
3783                //
3784 
3785                wordCount = deviceExtension->WordsLeft;
3786 
3787             } else {
3788 
3789                //
3790                // Transfer next block.
3791                //
3792 
3793                wordCount = wordsThisInterrupt;
3794             }
3795         }
3796 
3797         //
3798         // Ensure that this is a write command.
3799         //
3800 
3801         if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
3802 
3803            DebugPrint((3,
3804                       "AtapiInterrupt: Write interrupt\n"));
3805 
3806            WaitOnBusy(baseIoAddress2,statusByte);
3807 
3808            if (atapiDev || !deviceExtension->DWordIO) {
3809 
3810                WriteBuffer(baseIoAddress1,
3811                            deviceExtension->DataBuffer,
3812                            wordCount);
3813            } else {
3814 
3815                PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1;
3816 
3817                WriteBuffer2(address3,
3818                            (PULONG)(deviceExtension->DataBuffer),
3819                            wordCount / 2);
3820            }
3821         } else {
3822 
3823             DebugPrint((1,
3824                         "AtapiInterrupt: Int reason %x, but srb is for a write %x.\n",
3825                         interruptReason,
3826                         srb));
3827 
3828             //
3829             // Fail this request.
3830             //
3831 
3832             status = SRB_STATUS_ERROR;
3833             goto CompleteRequest;
3834         }
3835 
3836 
3837         //
3838         // Advance data buffer pointer and bytes left.
3839         //
3840 
3841         deviceExtension->DataBuffer += wordCount;
3842         deviceExtension->WordsLeft -= wordCount;
3843 
3844         return TRUE;
3845 
3846     } else if (interruptReason == 0x2 && (statusByte & IDE_STATUS_DRQ)) {
3847 
3848 
3849         if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
3850 
3851             //
3852             // Pick up bytes to transfer and convert to words.
3853             //
3854 
3855             wordCount =
3856                 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);
3857 
3858             wordCount |=
3859                 ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh) << 8;
3860 
3861             //
3862             // Covert bytes to words.
3863             //
3864 
3865             wordCount >>= 1;
3866 
3867             if (wordCount != deviceExtension->WordsLeft) {
3868                 DebugPrint((3,
3869                            "AtapiInterrupt: %d words requested; %d words xferred\n",
3870                            deviceExtension->WordsLeft,
3871                            wordCount));
3872             }
3873 
3874             //
3875             // Verify this makes sense.
3876             //
3877 
3878             if (wordCount > deviceExtension->WordsLeft) {
3879                 wordCount = deviceExtension->WordsLeft;
3880             }
3881 
3882         } else {
3883 
3884             //
3885             // Check if words left is at least 256.
3886             //
3887 
3888             if (deviceExtension->WordsLeft < wordsThisInterrupt) {
3889 
3890                //
3891                // Transfer only words requested.
3892                //
3893 
3894                wordCount = deviceExtension->WordsLeft;
3895 
3896             } else {
3897 
3898                //
3899                // Transfer next block.
3900                //
3901 
3902                wordCount = wordsThisInterrupt;
3903             }
3904         }
3905 
3906         //
3907         // Ensure that this is a read command.
3908         //
3909 
3910         if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
3911 
3912            DebugPrint((3,
3913                       "AtapiInterrupt: Read interrupt\n"));
3914 
3915            WaitOnBusy(baseIoAddress2,statusByte);
3916 
3917            if (atapiDev || !deviceExtension->DWordIO) {
3918                ReadBuffer(baseIoAddress1,
3919                          deviceExtension->DataBuffer,
3920                          wordCount);
3921 
3922            } else {
3923                PIDE_REGISTERS_3 address3 = (PIDE_REGISTERS_3)baseIoAddress1;
3924 
3925                ReadBuffer2(address3,
3926                           (PULONG)(deviceExtension->DataBuffer),
3927                           wordCount / 2);
3928            }
3929         } else {
3930 
3931             DebugPrint((1,
3932                         "AtapiInterrupt: Int reason %x, but srb is for a read %x.\n",
3933                         interruptReason,
3934                         srb));
3935 
3936             //
3937             // Fail this request.
3938             //
3939 
3940             status = SRB_STATUS_ERROR;
3941             goto CompleteRequest;
3942         }
3943 
3944         //
3945         // Translate ATAPI data back to SCSI data if needed
3946         //
3947 
3948         if (srb->Cdb[0] == ATAPI_MODE_SENSE &&
3949             deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
3950 
3951             //
3952             //convert and adjust the wordCount
3953             //
3954 
3955             wordCount -= Atapi2Scsi(srb, (char *)deviceExtension->DataBuffer,
3956                                      wordCount << 1);
3957         }
3958         //
3959         // Advance data buffer pointer and bytes left.
3960         //
3961 
3962         deviceExtension->DataBuffer += wordCount;
3963         deviceExtension->WordsLeft -= wordCount;
3964 
3965         //
3966         // Check for read command complete.
3967         //
3968 
3969         if (deviceExtension->WordsLeft == 0) {
3970 
3971             if (deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
3972 
3973                 //
3974                 // Work around to make many atapi devices return correct sector size
3975                 // of 2048. Also certain devices will have sector count == 0x00, check
3976                 // for that also.
3977                 //
3978 
3979                 if ((srb->Cdb[0] == 0x25) &&
3980                     ((deviceExtension->IdentifyData[srb->TargetId].GeneralConfiguration >> 8) & 0x1f) == 0x05) {
3981 
3982                     deviceExtension->DataBuffer -= wordCount;
3983                     if (deviceExtension->DataBuffer[0] == 0x00) {
3984 
3985                         *((ULONG *) &(deviceExtension->DataBuffer[0])) = 0xFFFFFF7F;
3986 
3987                     }
3988 
3989                     *((ULONG *) &(deviceExtension->DataBuffer[2])) = 0x00080000;
3990                     deviceExtension->DataBuffer += wordCount;
3991                 }
3992             } else {
3993 
3994                 //
3995                 // Completion for IDE drives.
3996                 //
3997 
3998 
3999                 if (deviceExtension->WordsLeft) {
4000 
4001                     status = SRB_STATUS_DATA_OVERRUN;
4002 
4003                 } else {
4004 
4005                     status = SRB_STATUS_SUCCESS;
4006 
4007                 }
4008 
4009                 goto CompleteRequest;
4010 
4011             }
4012         }
4013 
4014         return TRUE;
4015 
4016     } else if (interruptReason == 0x3  && !(statusByte & IDE_STATUS_DRQ)) {
4017 
4018         //
4019         // Command complete.
4020         //
4021 
4022         if (deviceExtension->WordsLeft) {
4023 
4024             status = SRB_STATUS_DATA_OVERRUN;
4025 
4026         } else {
4027 
4028             status = SRB_STATUS_SUCCESS;
4029 
4030         }
4031 
4032 CompleteRequest:
4033 
4034         //
4035         // Check and see if we are processing our secret (mechanism status/request sense) srb
4036         //
4037         if (deviceExtension->OriginalSrb) {
4038 
4039             ULONG srbStatus;
4040 
4041             if (srb->Cdb[0] == SCSIOP_MECHANISM_STATUS) {
4042 
4043                 if (status == SRB_STATUS_SUCCESS) {
4044                     // Bingo!!
4045                     AtapiHwInitializeChanger (HwDeviceExtension,
4046                                               srb->TargetId,
4047                                               (PMECHANICAL_STATUS_INFORMATION_HEADER) srb->DataBuffer);
4048 
4049                     // Get ready to issue the original srb
4050                     srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
4051                     deviceExtension->OriginalSrb = NULL;
4052 
4053                 } else {
4054                     // failed!  Get the sense key and maybe try again
4055                     srb = deviceExtension->CurrentSrb = BuildRequestSenseSrb (
4056                                                           HwDeviceExtension,
4057                                                           deviceExtension->OriginalSrb->PathId,
4058                                                           deviceExtension->OriginalSrb->TargetId);
4059                 }
4060 
4061                 srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb);
4062                 if (srbStatus == SRB_STATUS_PENDING) {
4063                     return TRUE;
4064                 }
4065 
4066             } else { // srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
4067 
4068                 PSENSE_DATA senseData = (PSENSE_DATA) srb->DataBuffer;
4069 
4070                 if (status == SRB_STATUS_DATA_OVERRUN) {
4071                     // Check to see if we at least get minimum number of bytes
4072                     if ((srb->DataTransferLength - deviceExtension->WordsLeft) >
4073                         (FIELD_OFFSET (SENSE_DATA, AdditionalSenseLength) + sizeof(senseData->AdditionalSenseLength))) {
4074                         status = SRB_STATUS_SUCCESS;
4075                     }
4076                 }
4077 
4078                 if (status == SRB_STATUS_SUCCESS) {
4079                     if ((senseData->SenseKey != SCSI_SENSE_ILLEGAL_REQUEST) &&
4080                         deviceExtension->MechStatusRetryCount) {
4081 
4082                         // The sense key doesn't say the last request is illegal, so try again
4083                         deviceExtension->MechStatusRetryCount--;
4084                         srb = deviceExtension->CurrentSrb = BuildMechanismStatusSrb (
4085                                                               HwDeviceExtension,
4086                                                               deviceExtension->OriginalSrb->PathId,
4087                                                               deviceExtension->OriginalSrb->TargetId);
4088                     } else {
4089 
4090                         // last request was illegal.  No point trying again
4091 
4092                         AtapiHwInitializeChanger (HwDeviceExtension,
4093                                                   srb->TargetId,
4094                                                   (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
4095 
4096                         // Get ready to issue the original srb
4097                         srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
4098                         deviceExtension->OriginalSrb = NULL;
4099                     }
4100 
4101                     srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb);
4102                     if (srbStatus == SRB_STATUS_PENDING) {
4103                         return TRUE;
4104                     }
4105                 }
4106             }
4107 
4108             // If we get here, it means AtapiSendCommand() has failed
4109             // Can't recover.  Pretend the original srb has failed and complete it.
4110 
4111             if (deviceExtension->OriginalSrb) {
4112                 AtapiHwInitializeChanger (HwDeviceExtension,
4113                                           srb->TargetId,
4114                                           (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
4115                 srb = deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
4116                 deviceExtension->OriginalSrb = NULL;
4117             }
4118 
4119             // fake an error and read no data
4120             status = SRB_STATUS_ERROR;
4121             srb->ScsiStatus = 0;
4122             deviceExtension->DataBuffer = srb->DataBuffer;
4123             deviceExtension->WordsLeft = srb->DataTransferLength;
4124             deviceExtension->RDP = FALSE;
4125 
4126         } else if (status == SRB_STATUS_ERROR) {
4127 
4128             //
4129             // Map error to specific SRB status and handle request sense.
4130             //
4131 
4132             status = MapError(deviceExtension,
4133                               srb);
4134 
4135             deviceExtension->RDP = FALSE;
4136 
4137         } else {
4138 
4139             //
4140             // Wait for busy to drop.
4141             //
4142 
4143             for (i = 0; i < 30; i++) {
4144                 GetStatus(baseIoAddress2,statusByte);
4145                 if (!(statusByte & IDE_STATUS_BUSY)) {
4146                     break;
4147                 }
4148                 ScsiPortStallExecution(500);
4149             }
4150 
4151             if (i == 30) {
4152 
4153                 //
4154                 // reset the controller.
4155                 //
4156 
4157                 DebugPrint((1,
4158                             "AtapiInterrupt: Resetting due to BSY still up - %x. Base Io %x\n",
4159                             statusByte,
4160                             baseIoAddress1));
4161                 AtapiResetController(HwDeviceExtension,srb->PathId);
4162                 return TRUE;
4163             }
4164 
4165             //
4166             // Check to see if DRQ is still up.
4167             //
4168 
4169             if (statusByte & IDE_STATUS_DRQ) {
4170 
4171                 for (i = 0; i < 500; i++) {
4172                     GetStatus(baseIoAddress2,statusByte);
4173                     if (!(statusByte & IDE_STATUS_DRQ)) {
4174                         break;
4175                     }
4176                     ScsiPortStallExecution(100);
4177 
4178                 }
4179 
4180                 if (i == 500) {
4181 
4182                     //
4183                     // reset the controller.
4184                     //
4185 
4186                     DebugPrint((1,
4187                                 "AtapiInterrupt: Resetting due to DRQ still up - %x\n",
4188                                 statusByte));
4189                     AtapiResetController(HwDeviceExtension,srb->PathId);
4190                     return TRUE;
4191                 }
4192 
4193             }
4194         }
4195 
4196 
4197         //
4198         // Clear interrupt expecting flag.
4199         //
4200 
4201         deviceExtension->ExpectingInterrupt = FALSE;
4202 
4203         //
4204         // Sanity check that there is a current request.
4205         //
4206 
4207         if (srb != NULL) {
4208 
4209             //
4210             // Set status in SRB.
4211             //
4212 
4213             srb->SrbStatus = (UCHAR)status;
4214 
4215             //
4216             // Check for underflow.
4217             //
4218 
4219             if (deviceExtension->WordsLeft) {
4220 
4221                 //
4222                 // Subtract out residual words and update if filemark hit,
4223                 // setmark hit , end of data, end of media...
4224                 //
4225 
4226                 if (!(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_TAPE_DEVICE)) {
4227                 if (status == SRB_STATUS_DATA_OVERRUN) {
4228                     srb->DataTransferLength -= deviceExtension->WordsLeft;
4229                 } else {
4230                     srb->DataTransferLength = 0;
4231                 }
4232                 } else {
4233                     srb->DataTransferLength -= deviceExtension->WordsLeft;
4234                 }
4235             }
4236 
4237             if (srb->Function != SRB_FUNCTION_IO_CONTROL) {
4238 
4239                 //
4240                 // Indicate command complete.
4241                 //
4242 
4243                 if (!(deviceExtension->RDP)) {
4244                     ScsiPortNotification(RequestComplete,
4245                                          deviceExtension,
4246                                          srb);
4247 
4248                 }
4249             } else {
4250 
4251                 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
4252                 UCHAR             error = 0;
4253 
4254                 if (status != SRB_STATUS_SUCCESS) {
4255                     error = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
4256                 }
4257 
4258                 //
4259                 // Build the SMART status block depending upon the completion status.
4260                 //
4261 
4262                 cmdOutParameters->cBufferSize = wordCount;
4263                 cmdOutParameters->DriverStatus.bDriverError = (error) ? SMART_IDE_ERROR : 0;
4264                 cmdOutParameters->DriverStatus.bIDEError = error;
4265 
4266                 //
4267                 // If the sub-command is return smart status, jam the value from cylinder low and high, into the
4268                 // data buffer.
4269                 //
4270 
4271                 if (deviceExtension->SmartCommand == RETURN_SMART_STATUS) {
4272                     cmdOutParameters->bBuffer[0] = RETURN_SMART_STATUS;
4273                     cmdOutParameters->bBuffer[1] = ScsiPortReadPortUchar(&baseIoAddress1->InterruptReason);
4274                     cmdOutParameters->bBuffer[2] = ScsiPortReadPortUchar(&baseIoAddress1->Unused1);
4275                     cmdOutParameters->bBuffer[3] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountLow);
4276                     cmdOutParameters->bBuffer[4] = ScsiPortReadPortUchar(&baseIoAddress1->ByteCountHigh);
4277                     cmdOutParameters->bBuffer[5] = ScsiPortReadPortUchar(&baseIoAddress1->DriveSelect);
4278                     cmdOutParameters->bBuffer[6] = SMART_CMD;
4279                     cmdOutParameters->cBufferSize = 8;
4280                 }
4281 
4282                 //
4283                 // Indicate command complete.
4284                 //
4285 
4286                 ScsiPortNotification(RequestComplete,
4287                                      deviceExtension,
4288                                      srb);
4289 
4290             }
4291 
4292         } else {
4293 
4294             DebugPrint((1,
4295                        "AtapiInterrupt: No SRB!\n"));
4296         }
4297 
4298         //
4299         // Indicate ready for next request.
4300         //
4301 
4302         if (!(deviceExtension->RDP)) {
4303 
4304             //
4305             // Clear current SRB.
4306             //
4307 
4308             deviceExtension->CurrentSrb = NULL;
4309 
4310             ScsiPortNotification(NextRequest,
4311                                  deviceExtension,
4312                                  NULL);
4313         } else {
4314 
4315             ScsiPortNotification(RequestTimerCall,
4316                                  HwDeviceExtension,
4317                                  AtapiCallBack,
4318                                  2000);
4319         }
4320 
4321         return TRUE;
4322 
4323     } else {
4324 
4325         //
4326         // Unexpected int.
4327         //
4328 
4329         DebugPrint((3,
4330                     "AtapiInterrupt: Unexpected interrupt. InterruptReason %x. Status %x.\n",
4331                     interruptReason,
4332                     statusByte));
4333         return FALSE;
4334     }
4335 
4336     return TRUE;
4337 
4338 } // end AtapiInterrupt()
4339 
4340 
4341 ULONG
4342 NTAPI
4343 IdeSendSmartCommand(
4344     IN PVOID HwDeviceExtension,
4345     IN PSCSI_REQUEST_BLOCK Srb
4346     )
4347 
4348 /*++
4349 
4350 Routine Description:
4351 
4352     This routine handles SMART enable, disable, read attributes and threshold commands.
4353 
4354 Arguments:
4355 
4356     HwDeviceExtension - HBA miniport driver's adapter data storage
4357     Srb - IO request packet
4358 
4359 Return Value:
4360 
4361     SRB status
4362 
4363 --*/
4364 
4365 {
4366     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
4367     PIDE_REGISTERS_1     baseIoAddress1  = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
4368     PIDE_REGISTERS_2     baseIoAddress2  = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
4369     PSENDCMDOUTPARAMS    cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
4370     SENDCMDINPARAMS      cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
4371     PIDEREGS             regs = &cmdInParameters.irDriveRegs;
4372     ULONG                i;
4373     UCHAR                statusByte,targetId;
4374 
4375 
4376     if (cmdInParameters.irDriveRegs.bCommandReg == SMART_CMD) {
4377 
4378         targetId = cmdInParameters.bDriveNumber;
4379 
4380         //TODO optimize this check
4381 
4382         if ((!(deviceExtension->DeviceFlags[targetId] & DFLAGS_DEVICE_PRESENT)) ||
4383              (deviceExtension->DeviceFlags[targetId] & DFLAGS_ATAPI_DEVICE)) {
4384 
4385             return SRB_STATUS_SELECTION_TIMEOUT;
4386         }
4387 
4388         deviceExtension->SmartCommand = cmdInParameters.irDriveRegs.bFeaturesReg;
4389 
4390         //
4391         // Determine which of the commands to carry out.
4392         //
4393 
4394         if ((cmdInParameters.irDriveRegs.bFeaturesReg == READ_ATTRIBUTES) ||
4395             (cmdInParameters.irDriveRegs.bFeaturesReg == READ_THRESHOLDS)) {
4396 
4397             WaitOnBusy(baseIoAddress2,statusByte);
4398 
4399             if (statusByte & IDE_STATUS_BUSY) {
4400                 DebugPrint((1,
4401                             "IdeSendSmartCommand: Returning BUSY status\n"));
4402                 return SRB_STATUS_BUSY;
4403             }
4404 
4405             //
4406             // Zero the output buffer as the input buffer info. has been saved off locally (the buffers are the same).
4407             //
4408 
4409             for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1); i++) {
4410                 ((PUCHAR)cmdOutParameters)[i] = 0;
4411             }
4412 
4413             //
4414             // Set data buffer pointer and words left.
4415             //
4416 
4417             deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
4418             deviceExtension->WordsLeft = READ_ATTRIBUTE_BUFFER_SIZE / 2;
4419 
4420             //
4421             // Indicate expecting an interrupt.
4422             //
4423 
4424             deviceExtension->ExpectingInterrupt = TRUE;
4425 
4426             ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0));
4427             ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg);
4428             ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg);
4429             ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg);
4430             ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg);
4431             ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg);
4432             ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg);
4433 
4434             //
4435             // Wait for interrupt.
4436             //
4437 
4438             return SRB_STATUS_PENDING;
4439 
4440         } else if ((cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_SMART) ||
4441                    (cmdInParameters.irDriveRegs.bFeaturesReg == DISABLE_SMART) ||
4442                    (cmdInParameters.irDriveRegs.bFeaturesReg == RETURN_SMART_STATUS) ||
4443                    (cmdInParameters.irDriveRegs.bFeaturesReg == ENABLE_DISABLE_AUTOSAVE) ||
4444                    (cmdInParameters.irDriveRegs.bFeaturesReg == EXECUTE_OFFLINE_DIAGS) ||
4445                    (cmdInParameters.irDriveRegs.bFeaturesReg == SAVE_ATTRIBUTE_VALUES)) {
4446 
4447             WaitOnBusy(baseIoAddress2,statusByte);
4448 
4449             if (statusByte & IDE_STATUS_BUSY) {
4450                 DebugPrint((1,
4451                             "IdeSendSmartCommand: Returning BUSY status\n"));
4452                 return SRB_STATUS_BUSY;
4453             }
4454 
4455             //
4456             // Zero the output buffer as the input buffer info. has been saved off locally (the buffers are the same).
4457             //
4458 
4459             for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) - 1); i++) {
4460                 ((PUCHAR)cmdOutParameters)[i] = 0;
4461             }
4462 
4463             //
4464             // Set data buffer pointer and indicate no data transfer.
4465             //
4466 
4467             deviceExtension->DataBuffer = (PUSHORT)cmdOutParameters->bBuffer;
4468             deviceExtension->WordsLeft = 0;
4469 
4470             //
4471             // Indicate expecting an interrupt.
4472             //
4473 
4474             deviceExtension->ExpectingInterrupt = TRUE;
4475 
4476             ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,(UCHAR)(((targetId & 0x1) << 4) | 0xA0));
4477             ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,regs->bFeaturesReg);
4478             ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,regs->bSectorCountReg);
4479             ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,regs->bSectorNumberReg);
4480             ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,regs->bCylLowReg);
4481             ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,regs->bCylHighReg);
4482             ScsiPortWritePortUchar(&baseIoAddress1->Command,regs->bCommandReg);
4483 
4484             //
4485             // Wait for interrupt.
4486             //
4487 
4488             return SRB_STATUS_PENDING;
4489         }
4490     }
4491 
4492     return SRB_STATUS_INVALID_REQUEST;
4493 
4494 } // end IdeSendSmartCommand()
4495 
4496 
4497 ULONG
4498 NTAPI
4499 IdeReadWrite(
4500     IN PVOID HwDeviceExtension,
4501     IN PSCSI_REQUEST_BLOCK Srb
4502     )
4503 
4504 /*++
4505 
4506 Routine Description:
4507 
4508     This routine handles IDE read and writes.
4509 
4510 Arguments:
4511 
4512     HwDeviceExtension - HBA miniport driver's adapter data storage
4513     Srb - IO request packet
4514 
4515 Return Value:
4516 
4517     SRB status
4518 
4519 --*/
4520 
4521 {
4522     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
4523     PIDE_REGISTERS_1     baseIoAddress1  = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
4524     PIDE_REGISTERS_2     baseIoAddress2  = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
4525     ULONG                startingSector,i;
4526     ULONG                wordCount;
4527     UCHAR                statusByte,statusByte2;
4528     UCHAR                cylinderHigh,cylinderLow,drvSelect,sectorNumber;
4529 
4530     //
4531     // Select device 0 or 1.
4532     //
4533 
4534     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
4535                             (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
4536 
4537     WaitOnBusy(baseIoAddress2,statusByte2);
4538 
4539     if (statusByte2 & IDE_STATUS_BUSY) {
4540         DebugPrint((1,
4541                     "IdeReadWrite: Returning BUSY status\n"));
4542         return SRB_STATUS_BUSY;
4543     }
4544 
4545     //
4546     // Set data buffer pointer and words left.
4547     //
4548 
4549     deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
4550     deviceExtension->WordsLeft = Srb->DataTransferLength / 2;
4551 
4552     //
4553     // Indicate expecting an interrupt.
4554     //
4555 
4556     deviceExtension->ExpectingInterrupt = TRUE;
4557 
4558     //
4559     // Set up sector count register. Round up to next block.
4560     //
4561 
4562     ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
4563                            (UCHAR)((Srb->DataTransferLength + 0x1FF) / 0x200));
4564 
4565     //
4566     // Get starting sector number from CDB.
4567     //
4568 
4569     startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
4570                      ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
4571                      ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
4572                      ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
4573 
4574     DebugPrint((2,
4575                "IdeReadWrite: Starting sector is %x, Number of bytes %x\n",
4576                startingSector,
4577                Srb->DataTransferLength));
4578 
4579     //
4580     // Set up sector number register.
4581     //
4582 
4583     sectorNumber =  (UCHAR)((startingSector % deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1);
4584     ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,sectorNumber);
4585 
4586     //
4587     // Set up cylinder low register.
4588     //
4589 
4590     cylinderLow =  (UCHAR)(startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4591                            deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads));
4592     ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,cylinderLow);
4593 
4594     //
4595     // Set up cylinder high register.
4596     //
4597 
4598     cylinderHigh = (UCHAR)((startingSector / (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4599                            deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8);
4600     ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,cylinderHigh);
4601 
4602     //
4603     // Set up head and drive select register.
4604     //
4605 
4606     drvSelect = (UCHAR)(((startingSector / deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
4607                       deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) |((Srb->TargetId & 0x1) << 4) | 0xA0);
4608     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,drvSelect);
4609 
4610     DebugPrint((2,
4611                "IdeReadWrite: Cylinder %x Head %x Sector %x\n",
4612                startingSector /
4613                (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4614                deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads),
4615                (startingSector /
4616                deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
4617                deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads,
4618                startingSector %
4619                deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1));
4620 
4621     //
4622     // Check if write request.
4623     //
4624 
4625     if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
4626 
4627         //
4628         // Send read command.
4629         //
4630 
4631         if (deviceExtension->MaximumBlockXfer[Srb->TargetId]) {
4632             ScsiPortWritePortUchar(&baseIoAddress1->Command,
4633                                    IDE_COMMAND_READ_MULTIPLE);
4634 
4635         } else {
4636             ScsiPortWritePortUchar(&baseIoAddress1->Command,
4637                                    IDE_COMMAND_READ);
4638         }
4639     } else {
4640 
4641 
4642         //
4643         // Send write command.
4644         //
4645 
4646         if (deviceExtension->MaximumBlockXfer[Srb->TargetId]) {
4647             wordCount = 256 * deviceExtension->MaximumBlockXfer[Srb->TargetId];
4648 
4649             if (deviceExtension->WordsLeft < wordCount) {
4650 
4651                //
4652                // Transfer only words requested.
4653                //
4654 
4655                wordCount = deviceExtension->WordsLeft;
4656 
4657             }
4658             ScsiPortWritePortUchar(&baseIoAddress1->Command,
4659                                    IDE_COMMAND_WRITE_MULTIPLE);
4660 
4661         } else {
4662             wordCount = 256;
4663             ScsiPortWritePortUchar(&baseIoAddress1->Command,
4664                                    IDE_COMMAND_WRITE);
4665         }
4666 
4667         //
4668         // Wait for BSY and DRQ.
4669         //
4670 
4671         WaitOnBaseBusy(baseIoAddress1,statusByte);
4672 
4673         if (statusByte & IDE_STATUS_BUSY) {
4674 
4675             DebugPrint((1,
4676                         "IdeReadWrite 2: Returning BUSY status %x\n",
4677                         statusByte));
4678             return SRB_STATUS_BUSY;
4679         }
4680 
4681         for (i = 0; i < 1000; i++) {
4682             GetBaseStatus(baseIoAddress1, statusByte);
4683             if (statusByte & IDE_STATUS_DRQ) {
4684                 break;
4685             }
4686             ScsiPortStallExecution(200);
4687 
4688         }
4689 
4690         if (!(statusByte & IDE_STATUS_DRQ)) {
4691 
4692             DebugPrint((1,
4693                        "IdeReadWrite: DRQ never asserted (%x) original status (%x)\n",
4694                        statusByte,
4695                        statusByte2));
4696 
4697             deviceExtension->WordsLeft = 0;
4698 
4699             //
4700             // Clear interrupt expecting flag.
4701             //
4702 
4703             deviceExtension->ExpectingInterrupt = FALSE;
4704 
4705             //
4706             // Clear current SRB.
4707             //
4708 
4709             deviceExtension->CurrentSrb = NULL;
4710 
4711             return SRB_STATUS_TIMEOUT;
4712         }
4713 
4714         //
4715         // Write next 256 words.
4716         //
4717 
4718         WriteBuffer(baseIoAddress1,
4719                     deviceExtension->DataBuffer,
4720                     wordCount);
4721 
4722         //
4723         // Adjust buffer address and words left count.
4724         //
4725 
4726         deviceExtension->WordsLeft -= wordCount;
4727         deviceExtension->DataBuffer += wordCount;
4728 
4729     }
4730 
4731     //
4732     // Wait for interrupt.
4733     //
4734 
4735     return SRB_STATUS_PENDING;
4736 
4737 } // end IdeReadWrite()
4738 
4739 
4740 
4741 ULONG
4742 NTAPI
4743 IdeVerify(
4744     IN PVOID HwDeviceExtension,
4745     IN PSCSI_REQUEST_BLOCK Srb
4746     )
4747 
4748 /*++
4749 
4750 Routine Description:
4751 
4752     This routine handles IDE Verify.
4753 
4754 Arguments:
4755 
4756     HwDeviceExtension - HBA miniport driver's adapter data storage
4757     Srb - IO request packet
4758 
4759 Return Value:
4760 
4761     SRB status
4762 
4763 --*/
4764 
4765 {
4766     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
4767     PIDE_REGISTERS_1     baseIoAddress1  = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
4768     //PIDE_REGISTERS_2     baseIoAddress2  = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
4769     ULONG                startingSector;
4770     ULONG                sectors;
4771     ULONG                endSector;
4772     USHORT               sectorCount;
4773 
4774     //
4775     // Drive has these number sectors.
4776     //
4777 
4778     sectors = deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4779               deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads *
4780               deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders;
4781 
4782     DebugPrint((3,
4783                 "IdeVerify: Total sectors %x\n",
4784                 sectors));
4785 
4786     //
4787     // Get starting sector number from CDB.
4788     //
4789 
4790     startingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
4791                      ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
4792                      ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
4793                      ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
4794 
4795     DebugPrint((3,
4796                 "IdeVerify: Starting sector %x. Number of blocks %x\n",
4797                 startingSector,
4798                 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb));
4799 
4800     sectorCount = (USHORT)(((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8 |
4801                            ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb );
4802     endSector = startingSector + sectorCount;
4803 
4804     DebugPrint((3,
4805                 "IdeVerify: Ending sector %x\n",
4806                 endSector));
4807 
4808     if (endSector > sectors) {
4809 
4810         //
4811         // Too big, round down.
4812         //
4813 
4814         DebugPrint((1,
4815                     "IdeVerify: Truncating request to %x blocks\n",
4816                     sectors - startingSector - 1));
4817 
4818         ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,
4819                                (UCHAR)(sectors - startingSector - 1));
4820 
4821     } else {
4822 
4823         //
4824         // Set up sector count register. Round up to next block.
4825         //
4826 
4827         if (sectorCount > 0xFF) {
4828             sectorCount = (USHORT)0xFF;
4829         }
4830 
4831         ScsiPortWritePortUchar(&baseIoAddress1->BlockCount,(UCHAR)sectorCount);
4832     }
4833 
4834     //
4835     // Set data buffer pointer and words left.
4836     //
4837 
4838     deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
4839     deviceExtension->WordsLeft = Srb->DataTransferLength / 2;
4840 
4841     //
4842     // Indicate expecting an interrupt.
4843     //
4844 
4845     deviceExtension->ExpectingInterrupt = TRUE;
4846 
4847     //
4848     // Set up sector number register.
4849     //
4850 
4851     ScsiPortWritePortUchar(&baseIoAddress1->BlockNumber,
4852                            (UCHAR)((startingSector %
4853                            deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) + 1));
4854 
4855     //
4856     // Set up cylinder low register.
4857     //
4858 
4859     ScsiPortWritePortUchar(&baseIoAddress1->CylinderLow,
4860                            (UCHAR)(startingSector /
4861                            (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4862                            deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)));
4863 
4864     //
4865     // Set up cylinder high register.
4866     //
4867 
4868     ScsiPortWritePortUchar(&baseIoAddress1->CylinderHigh,
4869                            (UCHAR)((startingSector /
4870                            (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4871                            deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads)) >> 8));
4872 
4873     //
4874     // Set up head and drive select register.
4875     //
4876 
4877     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
4878                            (UCHAR)(((startingSector /
4879                            deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
4880                            deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads) |
4881                            ((Srb->TargetId & 0x1) << 4) | 0xA0));
4882 
4883     DebugPrint((2,
4884                "IdeVerify: Cylinder %x Head %x Sector %x\n",
4885                startingSector /
4886                (deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack *
4887                deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads),
4888                (startingSector /
4889                deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) %
4890                deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads,
4891                startingSector %
4892                deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack + 1));
4893 
4894 
4895     //
4896     // Send verify command.
4897     //
4898 
4899     ScsiPortWritePortUchar(&baseIoAddress1->Command,
4900                            IDE_COMMAND_VERIFY);
4901 
4902     //
4903     // Wait for interrupt.
4904     //
4905 
4906     return SRB_STATUS_PENDING;
4907 
4908 } // end IdeVerify()
4909 
4910 
4911 VOID
4912 NTAPI
4913 Scsi2Atapi(
4914     IN PSCSI_REQUEST_BLOCK Srb
4915     )
4916 
4917 /*++
4918 
4919 Routine Description:
4920 
4921     Convert SCSI packet command to Atapi packet command.
4922 
4923 Arguments:
4924 
4925     Srb - IO request packet
4926 
4927 Return Value:
4928 
4929     None
4930 
4931 --*/
4932 {
4933     //
4934     // Change the cdb length
4935     //
4936 
4937     Srb->CdbLength = 12;
4938 
4939     switch (Srb->Cdb[0]) {
4940         case SCSIOP_MODE_SENSE: {
4941             PMODE_SENSE_10 modeSense10 = (PMODE_SENSE_10)Srb->Cdb;
4942             UCHAR PageCode = ((PCDB)Srb->Cdb)->MODE_SENSE.PageCode;
4943             UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SENSE.AllocationLength;
4944 
4945             AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE);
4946 
4947             modeSense10->OperationCode = ATAPI_MODE_SENSE;
4948             modeSense10->PageCode = PageCode;
4949             modeSense10->ParameterListLengthMsb = 0;
4950             modeSense10->ParameterListLengthLsb = Length;
4951             break;
4952         }
4953 
4954         case SCSIOP_MODE_SELECT: {
4955             PMODE_SELECT_10 modeSelect10 = (PMODE_SELECT_10)Srb->Cdb;
4956             UCHAR Length = ((PCDB)Srb->Cdb)->MODE_SELECT.ParameterListLength;
4957 
4958             //
4959             // Zero the original cdb
4960             //
4961 
4962             AtapiZeroMemory(Srb->Cdb,MAXIMUM_CDB_SIZE);
4963 
4964             modeSelect10->OperationCode = ATAPI_MODE_SELECT;
4965             modeSelect10->PFBit = 1;
4966             modeSelect10->ParameterListLengthMsb = 0;
4967             modeSelect10->ParameterListLengthLsb = Length;
4968             break;
4969         }
4970 
4971         case SCSIOP_FORMAT_UNIT:
4972         Srb->Cdb[0] = ATAPI_FORMAT_UNIT;
4973         break;
4974     }
4975 }
4976 
4977 
4978 
4979 ULONG
4980 NTAPI
4981 AtapiSendCommand(
4982     IN PVOID HwDeviceExtension,
4983     IN PSCSI_REQUEST_BLOCK Srb
4984     )
4985 
4986 /*++
4987 
4988 Routine Description:
4989 
4990     Send ATAPI packet command to device.
4991 
4992 Arguments:
4993 
4994     HwDeviceExtension - HBA miniport driver's adapter data storage
4995     Srb - IO request packet
4996 
4997 Return Value:
4998 
4999 
5000 --*/
5001 
5002 {
5003     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
5004     PATAPI_REGISTERS_1   baseIoAddress1  = (PATAPI_REGISTERS_1)deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
5005     PATAPI_REGISTERS_2   baseIoAddress2 =  (PATAPI_REGISTERS_2)deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
5006     ULONG i;
5007     ULONG flags;
5008     UCHAR statusByte,byteCountLow,byteCountHigh;
5009 
5010     //
5011     // We need to know how many platters our atapi cd-rom device might have.
5012     // Before anyone tries to send a srb to our target for the first time,
5013     // we must "secretly" send down a separate mechanism status srb in order to
5014     // initialize our device extension changer data.  That's how we know how
5015     // many platters our target has.
5016     //
5017     if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_CHANGER_INITED) &&
5018         !deviceExtension->OriginalSrb) {
5019 
5020         ULONG srbStatus;
5021 
5022         //
5023         // Set this flag now. If the device hangs on the mech. status
5024         // command, we will not have the change to set it.
5025         //
5026         deviceExtension->DeviceFlags[Srb->TargetId] |= DFLAGS_CHANGER_INITED;
5027 
5028         deviceExtension->MechStatusRetryCount = 3;
5029         deviceExtension->CurrentSrb = BuildMechanismStatusSrb (
5030                                         HwDeviceExtension,
5031                                         Srb->PathId,
5032                                         Srb->TargetId);
5033         deviceExtension->OriginalSrb = Srb;
5034 
5035         srbStatus = AtapiSendCommand(HwDeviceExtension, deviceExtension->CurrentSrb);
5036         if (srbStatus == SRB_STATUS_PENDING) {
5037             return srbStatus;
5038         } else {
5039             deviceExtension->CurrentSrb = deviceExtension->OriginalSrb;
5040             deviceExtension->OriginalSrb = NULL;
5041             AtapiHwInitializeChanger (HwDeviceExtension,
5042                                       Srb->TargetId,
5043                                       (PMECHANICAL_STATUS_INFORMATION_HEADER) NULL);
5044             // fall out
5045         }
5046     }
5047 
5048     DebugPrint((2,
5049                "AtapiSendCommand: Command %x to TargetId %d lun %d\n",
5050                Srb->Cdb[0],
5051                Srb->TargetId,
5052                Srb->Lun));
5053 
5054     //
5055     // Make sure command is to ATAPI device.
5056     //
5057 
5058     flags = deviceExtension->DeviceFlags[Srb->TargetId];
5059     if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
5060         if ((Srb->Lun) > (deviceExtension->DiscsPresent[Srb->TargetId] - 1)) {
5061 
5062             //
5063             // Indicate no device found at this address.
5064             //
5065 
5066             return SRB_STATUS_SELECTION_TIMEOUT;
5067         }
5068     } else if (Srb->Lun > 0) {
5069         return SRB_STATUS_SELECTION_TIMEOUT;
5070     }
5071 
5072     if (!(flags & DFLAGS_ATAPI_DEVICE)) {
5073         return SRB_STATUS_SELECTION_TIMEOUT;
5074     }
5075 
5076     //
5077     // Select device 0 or 1.
5078     //
5079 
5080     ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
5081                            (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
5082 
5083     //
5084     // Verify that controller is ready for next command.
5085     //
5086 
5087     GetStatus(baseIoAddress2,statusByte);
5088 
5089     DebugPrint((2,
5090                 "AtapiSendCommand: Entered with status %x\n",
5091                 statusByte));
5092 
5093     if (statusByte & IDE_STATUS_BUSY) {
5094         DebugPrint((1,
5095                     "AtapiSendCommand: Device busy (%x)\n",
5096                     statusByte));
5097         return SRB_STATUS_BUSY;
5098 
5099     }
5100 
5101     if (statusByte & IDE_STATUS_ERROR) {
5102         if (Srb->Cdb[0] != SCSIOP_REQUEST_SENSE) {
5103 
5104             DebugPrint((1,
5105                         "AtapiSendCommand: Error on entry: (%x)\n",
5106                         statusByte));
5107             //
5108             // Read the error reg. to clear it and fail this request.
5109             //
5110 
5111             return MapError(deviceExtension,
5112                             Srb);
5113         }
5114     }
5115 
5116     //
5117     // If a tape drive has doesn't have DSC set and the last command is restrictive, don't send
5118     // the next command. See discussion of Restrictive Delayed Process commands in QIC-157.
5119     //
5120 
5121     if ((!(statusByte & IDE_STATUS_DSC)) &&
5122           (flags & DFLAGS_TAPE_DEVICE) && deviceExtension->RDP) {
5123         ScsiPortStallExecution(1000);
5124         DebugPrint((2,"AtapiSendCommand: DSC not set. %x\n",statusByte));
5125         return SRB_STATUS_BUSY;
5126     }
5127 
5128     if (IS_RDP(Srb->Cdb[0])) {
5129 
5130         deviceExtension->RDP = TRUE;
5131 
5132         DebugPrint((3,
5133                     "AtapiSendCommand: %x mapped as DSC restrictive\n",
5134                     Srb->Cdb[0]));
5135 
5136     } else {
5137 
5138         deviceExtension->RDP = FALSE;
5139     }
5140 
5141     if (statusByte & IDE_STATUS_DRQ) {
5142 
5143         DebugPrint((1,
5144                     "AtapiSendCommand: Entered with status (%x). Attempting to recover.\n",
5145                     statusByte));
5146         //
5147         // Try to drain the data that one preliminary device thinks that it has
5148         // to transfer. Hopefully this random assertion of DRQ will not be present
5149         // in production devices.
5150         //
5151 
5152         for (i = 0; i < 0x10000; i++) {
5153 
5154            GetStatus(baseIoAddress2, statusByte);
5155 
5156            if (statusByte & IDE_STATUS_DRQ) {
5157 
5158               ScsiPortReadPortUshort(&baseIoAddress1->Data);
5159 
5160            } else {
5161 
5162               break;
5163            }
5164         }
5165 
5166         if (i == 0x10000) {
5167 
5168             DebugPrint((1,
5169                         "AtapiSendCommand: DRQ still asserted.Status (%x)\n",
5170                         statusByte));
5171 
5172             AtapiSoftReset(baseIoAddress1,Srb->TargetId);
5173 
5174             DebugPrint((1,
5175                          "AtapiSendCommand: Issued soft reset to Atapi device. \n"));
5176 
5177             //
5178             // Re-initialize Atapi device.
5179             //
5180 
5181             IssueIdentify(HwDeviceExtension,
5182                           (Srb->TargetId & 0x1),
5183                           (Srb->TargetId >> 1),
5184                           IDE_COMMAND_ATAPI_IDENTIFY);
5185 
5186             //
5187             // Inform the port driver that the bus has been reset.
5188             //
5189 
5190             ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
5191 
5192             //
5193             // Clean up device extension fields that AtapiStartIo won't.
5194             //
5195 
5196             deviceExtension->ExpectingInterrupt = FALSE;
5197             deviceExtension->RDP = FALSE;
5198 
5199             return SRB_STATUS_BUS_RESET;
5200 
5201         }
5202     }
5203 
5204     if (flags & (DFLAGS_SANYO_ATAPI_CHANGER | DFLAGS_ATAPI_CHANGER)) {
5205 
5206         //
5207         // As the cdrom driver sets the LUN field in the cdb, it must be removed.
5208         //
5209 
5210         Srb->Cdb[1] &= ~0xE0;
5211 
5212         if ((Srb->Cdb[0] == SCSIOP_TEST_UNIT_READY) && (flags & DFLAGS_SANYO_ATAPI_CHANGER)) {
5213 
5214             //
5215             // Torisan changer. TUR's are overloaded to be platter switches.
5216             //
5217 
5218             Srb->Cdb[7] = Srb->Lun;
5219 
5220         }
5221     }
5222 
5223     //
5224     // Convert SCSI to ATAPI commands if needed
5225     //
5226 
5227     switch (Srb->Cdb[0]) {
5228         case SCSIOP_MODE_SENSE:
5229         case SCSIOP_MODE_SELECT:
5230         case SCSIOP_FORMAT_UNIT:
5231             if (!(flags & DFLAGS_TAPE_DEVICE)) {
5232                 Scsi2Atapi(Srb);
5233             }
5234 
5235             break;
5236     }
5237 
5238     //
5239     // Set data buffer pointer and words left.
5240     //
5241 
5242     deviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
5243     deviceExtension->WordsLeft = Srb->DataTransferLength / 2;
5244 
5245     WaitOnBusy(baseIoAddress2,statusByte);
5246 
5247     //
5248     // Write transfer byte count to registers.
5249     //
5250 
5251     byteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
5252     byteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
5253 
5254     if (Srb->DataTransferLength >= 0x10000) {
5255         byteCountLow = byteCountHigh = 0xFF;
5256     }
5257 
5258     ScsiPortWritePortUchar(&baseIoAddress1->ByteCountLow,byteCountLow);
5259     ScsiPortWritePortUchar(&baseIoAddress1->ByteCountHigh, byteCountHigh);
5260 
5261     ScsiPortWritePortUchar((PUCHAR)baseIoAddress1 + 1,0);
5262 
5263 
5264     if (flags & DFLAGS_INT_DRQ) {
5265 
5266         //
5267         // This device interrupts when ready to receive the packet.
5268         //
5269         // Write ATAPI packet command.
5270         //
5271 
5272         ScsiPortWritePortUchar(&baseIoAddress1->Command,
5273                                IDE_COMMAND_ATAPI_PACKET);
5274 
5275         DebugPrint((3,
5276                    "AtapiSendCommand: Wait for int. to send packet. Status (%x)\n",
5277                    statusByte));
5278 
5279         deviceExtension->ExpectingInterrupt = TRUE;
5280 
5281         return SRB_STATUS_PENDING;
5282 
5283     } else {
5284 
5285         //
5286         // Write ATAPI packet command.
5287         //
5288 
5289         ScsiPortWritePortUchar(&baseIoAddress1->Command,
5290                                IDE_COMMAND_ATAPI_PACKET);
5291 
5292         //
5293         // Wait for DRQ.
5294         //
5295 
5296         WaitOnBusy(baseIoAddress2, statusByte);
5297         WaitForDrq(baseIoAddress2, statusByte);
5298 
5299         if (!(statusByte & IDE_STATUS_DRQ)) {
5300 
5301             DebugPrint((1,
5302                        "AtapiSendCommand: DRQ never asserted (%x)\n",
5303                        statusByte));
5304             return SRB_STATUS_ERROR;
5305         }
5306     }
5307 
5308     //
5309     // Need to read status register.
5310     //
5311 
5312     GetBaseStatus(baseIoAddress1, statusByte);
5313 
5314     //
5315     // Send CDB to device.
5316     //
5317 
5318     WaitOnBusy(baseIoAddress2,statusByte);
5319 
5320     WriteBuffer(baseIoAddress1,
5321                 (PUSHORT)Srb->Cdb,
5322                 6);
5323 
5324     //
5325     // Indicate expecting an interrupt and wait for it.
5326     //
5327 
5328     deviceExtension->ExpectingInterrupt = TRUE;
5329 
5330     return SRB_STATUS_PENDING;
5331 
5332 } // end AtapiSendCommand()
5333 
5334 ULONG
5335 NTAPI
5336 IdeSendCommand(
5337     IN PVOID HwDeviceExtension,
5338     IN PSCSI_REQUEST_BLOCK Srb
5339     )
5340 
5341 /*++
5342 
5343 Routine Description:
5344 
5345     Program ATA registers for IDE disk transfer.
5346 
5347 Arguments:
5348 
5349     HwDeviceExtension - ATAPI driver storage.
5350     Srb - System request block.
5351 
5352 Return Value:
5353 
5354     SRB status (pending if all goes well).
5355 
5356 --*/
5357 
5358 {
5359     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
5360     PIDE_REGISTERS_1     baseIoAddress1  = deviceExtension->BaseIoAddress1[Srb->TargetId >> 1];
5361     PIDE_REGISTERS_2     baseIoAddress2  = deviceExtension->BaseIoAddress2[Srb->TargetId >> 1];
5362     PCDB cdb;
5363 
5364     UCHAR statusByte,errorByte;
5365     ULONG status;
5366     ULONG i;
5367     PMODE_PARAMETER_HEADER   modeData;
5368 
5369     DebugPrint((2,
5370                "IdeSendCommand: Command %x to device %d\n",
5371                Srb->Cdb[0],
5372                Srb->TargetId));
5373 
5374 
5375 
5376     switch (Srb->Cdb[0]) {
5377     case SCSIOP_INQUIRY:
5378 
5379         //
5380         // Filter out all TIDs but 0 and 1 since this is an IDE interface
5381         // which support up to two devices.
5382         //
5383 
5384         if ((Srb->Lun != 0) ||
5385             (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT))) {
5386 
5387             //
5388             // Indicate no device found at this address.
5389             //
5390 
5391             status = SRB_STATUS_SELECTION_TIMEOUT;
5392             break;
5393 
5394         } else {
5395 
5396             PINQUIRYDATA    inquiryData  = Srb->DataBuffer;
5397             PIDENTIFY_DATA2 identifyData = &deviceExtension->IdentifyData[Srb->TargetId];
5398 
5399             //
5400             // Zero INQUIRY data structure.
5401             //
5402 
5403             for (i = 0; i < Srb->DataTransferLength; i++) {
5404                ((PUCHAR)Srb->DataBuffer)[i] = 0;
5405             }
5406 
5407             //
5408             // Standard IDE interface only supports disks.
5409             //
5410 
5411             inquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
5412 
5413             //
5414             // Set the removable bit, if applicable.
5415             //
5416 
5417             if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_REMOVABLE_DRIVE) {
5418                 inquiryData->RemovableMedia = 1;
5419             }
5420 
5421             //
5422             // Fill in vendor identification fields.
5423             //
5424 
5425             for (i = 0; i < 8; i += 2) {
5426                inquiryData->VendorId[i] =
5427                    ((PUCHAR)identifyData->ModelNumber)[i + 1];
5428                inquiryData->VendorId[i+1] =
5429                    ((PUCHAR)identifyData->ModelNumber)[i];
5430             }
5431 
5432             for (i = 0; i < 12; i += 2) {
5433                inquiryData->ProductId[i] =
5434                    ((PUCHAR)identifyData->ModelNumber)[i + 8 + 1];
5435                inquiryData->ProductId[i+1] =
5436                    ((PUCHAR)identifyData->ModelNumber)[i + 8];
5437             }
5438 
5439             //
5440             // Initialize unused portion of product id.
5441             //
5442 
5443             for (i = 0; i < 4; i++) {
5444                inquiryData->ProductId[12+i] = ' ';
5445             }
5446 
5447             //
5448             // Move firmware revision from IDENTIFY data to
5449             // product revision in INQUIRY data.
5450             //
5451 
5452             for (i = 0; i < 4; i += 2) {
5453                inquiryData->ProductRevisionLevel[i] =
5454                    ((PUCHAR)identifyData->FirmwareRevision)[i+1];
5455                inquiryData->ProductRevisionLevel[i+1] =
5456                    ((PUCHAR)identifyData->FirmwareRevision)[i];
5457             }
5458 
5459             status = SRB_STATUS_SUCCESS;
5460         }
5461 
5462         break;
5463 
5464     case SCSIOP_MODE_SENSE:
5465 
5466         //
5467         // This is used to determine of the media is write-protected.
5468         // Since IDE does not support mode sense then we will modify just the portion we need
5469         // so the higher level driver can determine if media is protected.
5470         //
5471 
5472         if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
5473 
5474             ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
5475                              (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
5476             ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS);
5477             WaitOnBusy(baseIoAddress2,statusByte);
5478 
5479             if (!(statusByte & IDE_STATUS_ERROR)){
5480 
5481                 //
5482                 // no error occured return success, media is not protected
5483                 //
5484 
5485                 deviceExtension->ExpectingInterrupt = FALSE;
5486 
5487             } else {
5488 
5489                 //
5490                 // error occured, handle it locally, clear interrupt
5491                 //
5492 
5493                 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
5494 
5495                 GetBaseStatus(baseIoAddress1, statusByte);
5496                 deviceExtension->ExpectingInterrupt = FALSE;
5497 
5498                 if (errorByte & IDE_ERROR_DATA_ERROR) {
5499 
5500                    //
5501                    //media is write-protected, set bit in mode sense buffer
5502                    //
5503 
5504                    modeData = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;
5505 
5506                    Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER);
5507                    modeData->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
5508                 }
5509             }
5510             status = SRB_STATUS_SUCCESS;
5511         } else {
5512             status = SRB_STATUS_INVALID_REQUEST;
5513         }
5514         break;
5515 
5516     case SCSIOP_TEST_UNIT_READY:
5517 
5518         if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
5519 
5520             //
5521             // Select device 0 or 1.
5522             //
5523 
5524             ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
5525                             (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
5526             ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_GET_MEDIA_STATUS);
5527 
5528             //
5529             // Wait for busy. If media has not changed, return success
5530             //
5531 
5532             WaitOnBusy(baseIoAddress2,statusByte);
5533 
5534             if (!(statusByte & IDE_STATUS_ERROR)){
5535                 deviceExtension->ExpectingInterrupt = FALSE;
5536                 status = SRB_STATUS_SUCCESS;
5537             } else {
5538                 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress1 + 1);
5539                 if (errorByte == IDE_ERROR_DATA_ERROR){
5540 
5541                     //
5542                     // Special case: If current media is write-protected,
5543                     // the 0xDA command will always fail since the write-protect bit
5544                     // is sticky,so we can ignore this error
5545                     //
5546 
5547                    GetBaseStatus(baseIoAddress1, statusByte);
5548                    deviceExtension->ExpectingInterrupt = FALSE;
5549                    status = SRB_STATUS_SUCCESS;
5550 
5551                 } else {
5552 
5553                     //
5554                     // Request sense buffer to be build
5555                     //
5556                     deviceExtension->ExpectingInterrupt = TRUE;
5557                     status = SRB_STATUS_PENDING;
5558                }
5559             }
5560         } else {
5561             status = SRB_STATUS_SUCCESS;
5562         }
5563 
5564         break;
5565 
5566     case SCSIOP_READ_CAPACITY:
5567 
5568         //
5569         // Claim 512 byte blocks (big-endian).
5570         //
5571 
5572         ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock = 0x20000;
5573 
5574        //
5575        // Calculate last sector.
5576        //
5577 
5578 
5579        i = (deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads *
5580             deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders *
5581             deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack) - 1;
5582 
5583        ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress =
5584            (((PUCHAR)&i)[0] << 24) |  (((PUCHAR)&i)[1] << 16) |
5585            (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3];
5586 
5587        DebugPrint((1,
5588                   "IDE disk %x - #sectors %x, #heads %x, #cylinders %x\n",
5589                   Srb->TargetId,
5590                   deviceExtension->IdentifyData[Srb->TargetId].SectorsPerTrack,
5591                   deviceExtension->IdentifyData[Srb->TargetId].NumberOfHeads,
5592                   deviceExtension->IdentifyData[Srb->TargetId].NumberOfCylinders));
5593 
5594 
5595        status = SRB_STATUS_SUCCESS;
5596        break;
5597 
5598     case SCSIOP_VERIFY:
5599        status = IdeVerify(HwDeviceExtension,Srb);
5600 
5601        break;
5602 
5603     case SCSIOP_READ:
5604     case SCSIOP_WRITE:
5605 
5606        status = IdeReadWrite(HwDeviceExtension,
5607                                   Srb);
5608        break;
5609 
5610     case SCSIOP_START_STOP_UNIT:
5611 
5612        //
5613        //Determine what type of operation we should perform
5614        //
5615        cdb = (PCDB)Srb->Cdb;
5616 
5617        if (cdb->START_STOP.LoadEject == 1){
5618 
5619            //
5620            // Eject media,
5621            // first select device 0 or 1.
5622            //
5623            ScsiPortWritePortUchar(&baseIoAddress1->DriveSelect,
5624                             (UCHAR)(((Srb->TargetId & 0x1) << 4) | 0xA0));
5625            ScsiPortWritePortUchar(&baseIoAddress1->Command,IDE_COMMAND_MEDIA_EJECT);
5626        }
5627        status = SRB_STATUS_SUCCESS;
5628        break;
5629 
5630     case SCSIOP_REQUEST_SENSE:
5631        // this function makes sense buffers to report the results
5632        // of the original GET_MEDIA_STATUS command
5633 
5634        if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
5635            status = IdeBuildSenseBuffer(HwDeviceExtension,Srb);
5636            break;
5637        }
5638 
5639     default:
5640 
5641        DebugPrint((1,
5642                   "IdeSendCommand: Unsupported command %x\n",
5643                   Srb->Cdb[0]));
5644 
5645        status = SRB_STATUS_INVALID_REQUEST;
5646 
5647     } // end switch
5648 
5649     return status;
5650 
5651 } // end IdeSendCommand()
5652 
5653 VOID
5654 NTAPI
5655 IdeMediaStatus(
5656     BOOLEAN EnableMSN,
5657     IN PVOID HwDeviceExtension,
5658     ULONG Channel
5659     )
5660 /*++
5661 
5662 Routine Description:
5663 
5664     Enables disables media status notification
5665 
5666 Arguments:
5667 
5668 HwDeviceExtension - ATAPI driver storage.
5669 
5670 --*/
5671 
5672 {
5673     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
5674     PIDE_REGISTERS_1     baseIoAddress = deviceExtension->BaseIoAddress1[Channel >> 1];
5675     UCHAR statusByte,errorByte;
5676 
5677 
5678     if (EnableMSN != FALSE){
5679 
5680         //
5681         // If supported enable Media Status Notification support
5682         //
5683 
5684         if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_REMOVABLE_DRIVE)) {
5685 
5686             //
5687             // enable
5688             //
5689             ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x95));
5690             ScsiPortWritePortUchar(&baseIoAddress->Command,
5691                                    IDE_COMMAND_ENABLE_MEDIA_STATUS);
5692 
5693             WaitOnBaseBusy(baseIoAddress,statusByte);
5694 
5695             if (statusByte & IDE_STATUS_ERROR) {
5696                 //
5697                 // Read the error register.
5698                 //
5699                 errorByte = ScsiPortReadPortUchar((PUCHAR)baseIoAddress + 1);
5700 
5701                 DebugPrint((1,
5702                             "IdeMediaStatus: Error enabling media status. Status %x, error byte %x\n",
5703                              statusByte,
5704                              errorByte));
5705             } else {
5706                 deviceExtension->DeviceFlags[Channel] |= DFLAGS_MEDIA_STATUS_ENABLED;
5707                 DebugPrint((1,"IdeMediaStatus: Media Status Notification Supported\n"));
5708                 deviceExtension->ReturningMediaStatus = 0;
5709 
5710             }
5711 
5712         }
5713     } else { // end if EnableMSN != FALSE
5714 
5715         //
5716         // disable if previously enabled
5717         //
5718         if ((deviceExtension->DeviceFlags[Channel] & DFLAGS_MEDIA_STATUS_ENABLED)) {
5719 
5720             ScsiPortWritePortUchar((PUCHAR)baseIoAddress + 1,(UCHAR) (0x31));
5721             ScsiPortWritePortUchar(&baseIoAddress->Command,
5722                                    IDE_COMMAND_ENABLE_MEDIA_STATUS);
5723 
5724             WaitOnBaseBusy(baseIoAddress,statusByte);
5725             deviceExtension->DeviceFlags[Channel] &= ~DFLAGS_MEDIA_STATUS_ENABLED;
5726         }
5727 
5728 
5729     }
5730 
5731 
5732 
5733 }
5734 
5735 ULONG
5736 NTAPI
5737 IdeBuildSenseBuffer(
5738     IN PVOID HwDeviceExtension,
5739     IN PSCSI_REQUEST_BLOCK Srb
5740     )
5741 
5742 /*++
5743 
5744 Routine Description:
5745 
5746     Builts an artificial sense buffer to report the results of a GET_MEDIA_STATUS
5747     command. This function is invoked to satisfy the SCSIOP_REQUEST_SENSE.
5748 Arguments:
5749 
5750     HwDeviceExtension - ATAPI driver storage.
5751     Srb - System request block.
5752 
5753 Return Value:
5754 
5755     SRB status (ALWAYS SUCCESS).
5756 
5757 --*/
5758 
5759 {
5760     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
5761     PSENSE_DATA  senseBuffer = (PSENSE_DATA)Srb->DataBuffer;
5762 
5763 
5764     if (senseBuffer){
5765 
5766 
5767         if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE) {
5768 
5769             senseBuffer->ErrorCode = 0x70;
5770             senseBuffer->Valid     = 1;
5771             senseBuffer->AdditionalSenseLength = 0xb;
5772             senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
5773             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
5774             senseBuffer->AdditionalSenseCodeQualifier = 0;
5775         } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_MEDIA_CHANGE_REQ) {
5776 
5777             senseBuffer->ErrorCode = 0x70;
5778             senseBuffer->Valid     = 1;
5779             senseBuffer->AdditionalSenseLength = 0xb;
5780             senseBuffer->SenseKey =  SCSI_SENSE_UNIT_ATTENTION;
5781             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_MEDIUM_CHANGED;
5782             senseBuffer->AdditionalSenseCodeQualifier = 0;
5783         } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_END_OF_MEDIA) {
5784 
5785             senseBuffer->ErrorCode = 0x70;
5786             senseBuffer->Valid     = 1;
5787             senseBuffer->AdditionalSenseLength = 0xb;
5788             senseBuffer->SenseKey =  SCSI_SENSE_NOT_READY;
5789             senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_NO_MEDIA_IN_DEVICE;
5790             senseBuffer->AdditionalSenseCodeQualifier = 0;
5791         } else if(deviceExtension->ReturningMediaStatus & IDE_ERROR_DATA_ERROR) {
5792 
5793             senseBuffer->ErrorCode = 0x70;
5794             senseBuffer->Valid     = 1;
5795             senseBuffer->AdditionalSenseLength = 0xb;
5796             senseBuffer->SenseKey =  SCSI_SENSE_DATA_PROTECT;
5797             senseBuffer->AdditionalSenseCode = 0;
5798             senseBuffer->AdditionalSenseCodeQualifier = 0;
5799         }
5800         return SRB_STATUS_SUCCESS;
5801     }
5802     return SRB_STATUS_ERROR;
5803 
5804 }// End of IdeBuildSenseBuffer
5805 
5806 
5807 
5808 
5809 BOOLEAN
5810 NTAPI
5811 AtapiStartIo(
5812     IN PVOID HwDeviceExtension,
5813     IN PSCSI_REQUEST_BLOCK Srb
5814     )
5815 
5816 /*++
5817 
5818 Routine Description:
5819 
5820     This routine is called from the SCSI port driver synchronized
5821     with the kernel to start an IO request.
5822 
5823 Arguments:
5824 
5825     HwDeviceExtension - HBA miniport driver's adapter data storage
5826     Srb - IO request packet
5827 
5828 Return Value:
5829 
5830     TRUE
5831 
5832 --*/
5833 
5834 {
5835     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
5836     ULONG status;
5837 
5838     //
5839     // Determine which function.
5840     //
5841 
5842     switch (Srb->Function) {
5843 
5844     case SRB_FUNCTION_EXECUTE_SCSI:
5845 
5846         //
5847         // Sanity check. Only one request can be outstanding on a
5848         // controller.
5849         //
5850 
5851         if (deviceExtension->CurrentSrb) {
5852 
5853             DebugPrint((1,
5854                        "AtapiStartIo: Already have a request!\n"));
5855             Srb->SrbStatus = SRB_STATUS_BUSY;
5856             ScsiPortNotification(RequestComplete,
5857                                  deviceExtension,
5858                                  Srb);
5859             return FALSE;
5860         }
5861 
5862         //
5863         // Indicate that a request is active on the controller.
5864         //
5865 
5866         deviceExtension->CurrentSrb = Srb;
5867 
5868         //
5869         // Send command to device.
5870         //
5871 
5872         if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE) {
5873 
5874            status = AtapiSendCommand(HwDeviceExtension,
5875                                      Srb);
5876 
5877         } else if (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) {
5878 
5879            status = IdeSendCommand(HwDeviceExtension,
5880                                    Srb);
5881         } else {
5882 
5883             status = SRB_STATUS_SELECTION_TIMEOUT;
5884         }
5885 
5886         break;
5887 
5888     case SRB_FUNCTION_ABORT_COMMAND:
5889 
5890         //
5891         // Verify that SRB to abort is still outstanding.
5892         //
5893 
5894         if (!deviceExtension->CurrentSrb) {
5895 
5896             DebugPrint((1, "AtapiStartIo: SRB to abort already completed\n"));
5897 
5898             //
5899             // Complete abort SRB.
5900             //
5901 
5902             status = SRB_STATUS_ABORT_FAILED;
5903 
5904             break;
5905         }
5906 
5907         //
5908         // Abort function indicates that a request timed out.
5909         // Call reset routine. Card will only be reset if
5910         // status indicates something is wrong.
5911         // Fall through to reset code.
5912         //
5913 
5914     case SRB_FUNCTION_RESET_BUS:
5915 
5916         //
5917         // Reset Atapi and SCSI bus.
5918         //
5919 
5920         DebugPrint((1, "AtapiStartIo: Reset bus request received\n"));
5921 
5922         if (!AtapiResetController(deviceExtension,
5923                              Srb->PathId)) {
5924 
5925               DebugPrint((1,"AtapiStartIo: Reset bus failed\n"));
5926 
5927             //
5928             // Log reset failure.
5929             //
5930 
5931             ScsiPortLogError(
5932                 HwDeviceExtension,
5933                 NULL,
5934                 0,
5935                 0,
5936                 0,
5937                 SP_INTERNAL_ADAPTER_ERROR,
5938                 5 << 8
5939                 );
5940 
5941               status = SRB_STATUS_ERROR;
5942 
5943         } else {
5944 
5945               status = SRB_STATUS_SUCCESS;
5946         }
5947 
5948         break;
5949 
5950     case SRB_FUNCTION_IO_CONTROL:
5951 
5952         if (deviceExtension->CurrentSrb) {
5953 
5954             DebugPrint((1,
5955                        "AtapiStartIo: Already have a request!\n"));
5956             Srb->SrbStatus = SRB_STATUS_BUSY;
5957             ScsiPortNotification(RequestComplete,
5958                                  deviceExtension,
5959                                  Srb);
5960             return FALSE;
5961         }
5962 
5963         //
5964         // Indicate that a request is active on the controller.
5965         //
5966 
5967         deviceExtension->CurrentSrb = Srb;
5968 
5969         if (AtapiStringCmp( (PCHAR)((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,"SCSIDISK",strlen("SCSIDISK"))) {
5970 
5971             DebugPrint((1,
5972                         "AtapiStartIo: IoControl signature incorrect. Send %s, expected %s\n",
5973                         ((PSRB_IO_CONTROL)(Srb->DataBuffer))->Signature,
5974                         "SCSIDISK"));
5975 
5976             status = SRB_STATUS_INVALID_REQUEST;
5977             break;
5978         }
5979 
5980         switch (((PSRB_IO_CONTROL)(Srb->DataBuffer))->ControlCode) {
5981 
5982             case IOCTL_SCSI_MINIPORT_SMART_VERSION: {
5983 
5984                 PGETVERSIONINPARAMS versionParameters = (PGETVERSIONINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
5985                 UCHAR deviceNumber;
5986 
5987                 //
5988                 // Version and revision per SMART 1.03
5989                 //
5990 
5991                 versionParameters->bVersion = 1;
5992                 versionParameters->bRevision = 1;
5993                 versionParameters->bReserved = 0;
5994 
5995                 //
5996                 // Indicate that support for IDE IDENTIFY, ATAPI IDENTIFY and SMART commands.
5997                 //
5998 
5999                 versionParameters->fCapabilities = (CAP_ATA_ID_CMD | CAP_ATAPI_ID_CMD | CAP_SMART_CMD);
6000 
6001                 //
6002                 // This is done because of how the IOCTL_SCSI_MINIPORT
6003                 // determines 'targetid's'. Disk.sys places the real target id value
6004                 // in the DeviceMap field. Once we do some parameter checking, the value passed
6005                 // back to the application will be determined.
6006                 //
6007 
6008                 deviceNumber = versionParameters->bIDEDeviceMap;
6009 
6010                 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) ||
6011                     (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) {
6012 
6013                     status = SRB_STATUS_SELECTION_TIMEOUT;
6014                     break;
6015                 }
6016 
6017                 //
6018                 // NOTE: This will only set the bit
6019                 // corresponding to this drive's target id.
6020                 // The bit mask is as follows:
6021                 //
6022                 //     Sec Pri
6023                 //     S M S M
6024                 //     3 2 1 0
6025                 //
6026 
6027                 if (deviceExtension->NumberChannels == 1) {
6028                     if (deviceExtension->PrimaryAddress) {
6029                         deviceNumber = 1 << Srb->TargetId;
6030                     } else {
6031                         deviceNumber = 4 << Srb->TargetId;
6032                     }
6033                 } else {
6034                     deviceNumber = 1 << Srb->TargetId;
6035                 }
6036 
6037                 versionParameters->bIDEDeviceMap = deviceNumber;
6038 
6039                 status = SRB_STATUS_SUCCESS;
6040                 break;
6041             }
6042 
6043             case IOCTL_SCSI_MINIPORT_IDENTIFY: {
6044 
6045                 PSENDCMDOUTPARAMS cmdOutParameters = (PSENDCMDOUTPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
6046                 SENDCMDINPARAMS   cmdInParameters = *(PSENDCMDINPARAMS)(((PUCHAR)Srb->DataBuffer) + sizeof(SRB_IO_CONTROL));
6047                 ULONG             i;
6048                 UCHAR             targetId;
6049 
6050 
6051                 if (cmdInParameters.irDriveRegs.bCommandReg == ID_CMD) {
6052 
6053                     //
6054                     // Extract the target.
6055                     //
6056 
6057                     targetId = cmdInParameters.bDriveNumber;
6058 
6059                 if (!(deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_DEVICE_PRESENT) ||
6060                      (deviceExtension->DeviceFlags[Srb->TargetId] & DFLAGS_ATAPI_DEVICE)) {
6061 
6062                         status = SRB_STATUS_SELECTION_TIMEOUT;
6063                         break;
6064                     }
6065 
6066                     //
6067                     // Zero the output buffer
6068                     //
6069 
6070                     for (i = 0; i < (sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1); i++) {
6071                         ((PUCHAR)cmdOutParameters)[i] = 0;
6072                     }
6073 
6074                     //
6075                     // Build status block.
6076                     //
6077 
6078                     cmdOutParameters->cBufferSize = IDENTIFY_BUFFER_SIZE;
6079                     cmdOutParameters->DriverStatus.bDriverError = 0;
6080                     cmdOutParameters->DriverStatus.bIDEError = 0;
6081 
6082                     //
6083                     // Extract the identify data from the device extension.
6084                     //
6085 
6086                     ScsiPortMoveMemory (cmdOutParameters->bBuffer, &deviceExtension->IdentifyData[targetId], IDENTIFY_DATA_SIZE);
6087 
6088                     status = SRB_STATUS_SUCCESS;
6089 
6090 
6091                 } else {
6092                     status = SRB_STATUS_INVALID_REQUEST;
6093                 }
6094                 break;
6095             }
6096 
6097             case  IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS:
6098             case  IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS:
6099             case  IOCTL_SCSI_MINIPORT_ENABLE_SMART:
6100             case  IOCTL_SCSI_MINIPORT_DISABLE_SMART:
6101             case  IOCTL_SCSI_MINIPORT_RETURN_STATUS:
6102             case  IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE:
6103             case  IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES:
6104             case  IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS:
6105 
6106                 status = IdeSendSmartCommand(HwDeviceExtension,Srb);
6107                 break;
6108 
6109             default :
6110 
6111                 status = SRB_STATUS_INVALID_REQUEST;
6112                 break;
6113 
6114         }
6115 
6116         break;
6117 
6118     default:
6119 
6120         //
6121         // Indicate unsupported command.
6122         //
6123 
6124         status = SRB_STATUS_INVALID_REQUEST;
6125 
6126         break;
6127 
6128     } // end switch
6129 
6130     //
6131     // Check if command complete.
6132     //
6133 
6134     if (status != SRB_STATUS_PENDING) {
6135 
6136         DebugPrint((2,
6137                    "AtapiStartIo: Srb %x complete with status %x\n",
6138                    Srb,
6139                    status));
6140 
6141         //
6142         // Clear current SRB.
6143         //
6144 
6145         deviceExtension->CurrentSrb = NULL;
6146 
6147         //
6148         // Set status in SRB.
6149         //
6150 
6151         Srb->SrbStatus = (UCHAR)status;
6152 
6153         //
6154         // Indicate command complete.
6155         //
6156 
6157         ScsiPortNotification(RequestComplete,
6158                              deviceExtension,
6159                              Srb);
6160 
6161         //
6162         // Indicate ready for next request.
6163         //
6164 
6165         ScsiPortNotification(NextRequest,
6166                              deviceExtension,
6167                              NULL);
6168     }
6169 
6170     return TRUE;
6171 
6172 } // end AtapiStartIo()
6173 
6174 
6175 ULONG
6176 NTAPI
6177 DriverEntry(
6178     IN PVOID DriverObject,
6179     IN PVOID Argument2
6180     )
6181 
6182 /*++
6183 
6184 Routine Description:
6185 
6186     Installable driver initialization entry point for system.
6187 
6188 Arguments:
6189 
6190     Driver Object
6191 
6192 Return Value:
6193 
6194     Status from ScsiPortInitialize()
6195 
6196 --*/
6197 
6198 {
6199     HW_INITIALIZATION_DATA hwInitializationData;
6200     ULONG                  adapterCount;
6201     ULONG                  i;
6202     ULONG                  statusToReturn, newStatus;
6203 
6204     DebugPrint((1,"\n\nATAPI IDE MiniPort Driver\n"));
6205 
6206     statusToReturn = 0xffffffff;
6207 
6208     //
6209     // Zero out structure.
6210     //
6211 
6212     AtapiZeroMemory(((PUCHAR)&hwInitializationData), sizeof(HW_INITIALIZATION_DATA));
6213 
6214     //
6215     // Set size of hwInitializationData.
6216     //
6217 
6218     hwInitializationData.HwInitializationDataSize =
6219       sizeof(HW_INITIALIZATION_DATA);
6220 
6221     //
6222     // Set entry points.
6223     //
6224 
6225     hwInitializationData.HwInitialize = AtapiHwInitialize;
6226     hwInitializationData.HwResetBus = AtapiResetController;
6227     hwInitializationData.HwStartIo = AtapiStartIo;
6228     hwInitializationData.HwInterrupt = AtapiInterrupt;
6229 
6230     //
6231     // Specify size of extensions.
6232     //
6233 
6234     hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
6235     hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
6236 
6237     //
6238     // Indicate PIO device.
6239     //
6240 
6241     hwInitializationData.MapBuffers = TRUE;
6242 
6243     //
6244     // Native Mode Devices
6245     //
6246     for (i=0; i <NUM_NATIVE_MODE_ADAPTERS; i++) {
6247         hwInitializationData.HwFindAdapter = AtapiFindNativeModeController;
6248         hwInitializationData.NumberOfAccessRanges = 4;
6249         hwInitializationData.AdapterInterfaceType = PCIBus;
6250 
6251         hwInitializationData.VendorId             = NativeModeAdapters[i].VendorId;
6252         hwInitializationData.VendorIdLength       = (USHORT) NativeModeAdapters[i].VendorIdLength;
6253         hwInitializationData.DeviceId             = NativeModeAdapters[i].DeviceId;
6254         hwInitializationData.DeviceIdLength       = (USHORT) NativeModeAdapters[i].DeviceIdLength;
6255 
6256         newStatus = ScsiPortInitialize(DriverObject,
6257                                        Argument2,
6258                                        &hwInitializationData,
6259                                        (PVOID)(ULONG_PTR)i);
6260         if (newStatus < statusToReturn)
6261             statusToReturn = newStatus;
6262     }
6263 
6264     hwInitializationData.VendorId             = 0;
6265     hwInitializationData.VendorIdLength       = 0;
6266     hwInitializationData.DeviceId             = 0;
6267     hwInitializationData.DeviceIdLength       = 0;
6268 
6269     //
6270     // The adapter count is used by the find adapter routine to track how
6271     // which adapter addresses have been tested.
6272     //
6273 
6274     adapterCount = 0;
6275 
6276     hwInitializationData.HwFindAdapter = AtapiFindPCIController;
6277     hwInitializationData.NumberOfAccessRanges = 4;
6278     hwInitializationData.AdapterInterfaceType = Isa;
6279 
6280     newStatus = ScsiPortInitialize(DriverObject,
6281                                    Argument2,
6282                                    &hwInitializationData,
6283                                    &adapterCount);
6284     if (newStatus < statusToReturn)
6285         statusToReturn = newStatus;
6286 
6287     //
6288     // Indicate 2 access ranges and reset FindAdapter.
6289     //
6290 
6291     hwInitializationData.NumberOfAccessRanges = 2;
6292     hwInitializationData.HwFindAdapter = AtapiFindController;
6293 
6294     //
6295     // Indicate ISA bustype.
6296     //
6297 
6298     hwInitializationData.AdapterInterfaceType = Isa;
6299 
6300     //
6301     // Call initialization for ISA bustype.
6302     //
6303 
6304     newStatus =  ScsiPortInitialize(DriverObject,
6305                                     Argument2,
6306                                     &hwInitializationData,
6307                                     &adapterCount);
6308     if (newStatus < statusToReturn)
6309         statusToReturn = newStatus;
6310 
6311     //
6312     // Set up for MCA
6313     //
6314 
6315     hwInitializationData.AdapterInterfaceType = MicroChannel;
6316     adapterCount = 0;
6317 
6318     newStatus =  ScsiPortInitialize(DriverObject,
6319                                     Argument2,
6320                                     &hwInitializationData,
6321                                     &adapterCount);
6322     if (newStatus < statusToReturn)
6323         statusToReturn = newStatus;
6324 
6325     return statusToReturn;
6326 
6327 } // end DriverEntry()
6328 
6329 
6330 
6331 LONG
6332 NTAPI
6333 AtapiStringCmp (
6334     PCHAR FirstStr,
6335     PCHAR SecondStr,
6336     ULONG Count
6337     )
6338 {
6339     UCHAR  first ,last;
6340 
6341     if (Count) {
6342         do {
6343 
6344             //
6345             // Get next char.
6346             //
6347 
6348             first = *FirstStr++;
6349             last = *SecondStr++;
6350 
6351             if (first != last) {
6352 
6353                 //
6354                 // If no match, try lower-casing.
6355                 //
6356 
6357                 if (first>='A' && first<='Z') {
6358                     first = first - 'A' + 'a';
6359                 }
6360                 if (last>='A' && last<='Z') {
6361                     last = last - 'A' + 'a';
6362                 }
6363                 if (first != last) {
6364 
6365                     //
6366                     // No match
6367                     //
6368 
6369                     return first - last;
6370                 }
6371             }
6372         }while (--Count && first);
6373     }
6374 
6375     return 0;
6376 }
6377 
6378 
6379 VOID
6380 NTAPI
6381 AtapiZeroMemory(
6382     IN PUCHAR Buffer,
6383     IN ULONG Count
6384     )
6385 {
6386     ULONG i;
6387 
6388     for (i = 0; i < Count; i++) {
6389         Buffer[i] = 0;
6390     }
6391 }
6392 
6393 
6394 VOID
6395 NTAPI
6396 AtapiHexToString (
6397     IN ULONG Value,
6398     IN OUT PCHAR *Buffer
6399     )
6400 {
6401     PCHAR  string;
6402     PCHAR  firstdig;
6403     CHAR   temp;
6404     ULONG i;
6405     USHORT digval;
6406 
6407     string = *Buffer;
6408 
6409     firstdig = string;
6410 
6411     for (i = 0; i < 4; i++) {
6412         digval = (USHORT)(Value % 16);
6413         Value /= 16;
6414 
6415         //
6416         // convert to ascii and store. Note this will create
6417         // the buffer with the digits reversed.
6418         //
6419 
6420         if (digval > 9) {
6421             *string++ = (char) (digval - 10 + 'a');
6422         } else {
6423             *string++ = (char) (digval + '0');
6424         }
6425 
6426     }
6427 
6428     //
6429     // Reverse the digits.
6430     //
6431 
6432     *string-- = '\0';
6433 
6434     do {
6435         temp = *string;
6436         *string = *firstdig;
6437         *firstdig = temp;
6438         --string;
6439         ++firstdig;
6440     } while (firstdig < string);
6441 }
6442 
6443 
6444 
6445 PSCSI_REQUEST_BLOCK
6446 NTAPI
6447 BuildMechanismStatusSrb (
6448     IN PVOID HwDeviceExtension,
6449     IN ULONG PathId,
6450     IN ULONG TargetId
6451     )
6452 {
6453     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
6454     PSCSI_REQUEST_BLOCK srb;
6455     PCDB cdb;
6456 
6457     srb = &deviceExtension->InternalSrb;
6458 
6459     AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK));
6460 
6461     srb->PathId     = (UCHAR) PathId;
6462     srb->TargetId   = (UCHAR) TargetId;
6463     srb->Function   = SRB_FUNCTION_EXECUTE_SCSI;
6464     srb->Length     = sizeof(SCSI_REQUEST_BLOCK);
6465 
6466     //
6467     // Set flags to disable synchronous negotiation.
6468     //
6469     srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6470 
6471     //
6472     // Set timeout to 2 seconds.
6473     //
6474     srb->TimeOutValue = 4;
6475 
6476     srb->CdbLength          = 6;
6477     srb->DataBuffer         = &deviceExtension->MechStatusData;
6478     srb->DataTransferLength = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
6479 
6480     //
6481     // Set CDB operation code.
6482     //
6483     cdb = (PCDB)srb->Cdb;
6484     cdb->MECH_STATUS.OperationCode       = SCSIOP_MECHANISM_STATUS;
6485     cdb->MECH_STATUS.AllocationLength[1] = sizeof(MECHANICAL_STATUS_INFORMATION_HEADER);
6486 
6487     return srb;
6488 }
6489 
6490 
6491 PSCSI_REQUEST_BLOCK
6492 NTAPI
6493 BuildRequestSenseSrb (
6494     IN PVOID HwDeviceExtension,
6495     IN ULONG PathId,
6496     IN ULONG TargetId
6497     )
6498 {
6499     PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
6500     PSCSI_REQUEST_BLOCK srb;
6501     PCDB cdb;
6502 
6503     srb = &deviceExtension->InternalSrb;
6504 
6505     AtapiZeroMemory((PUCHAR) srb, sizeof(SCSI_REQUEST_BLOCK));
6506 
6507     srb->PathId     = (UCHAR) PathId;
6508     srb->TargetId   = (UCHAR) TargetId;
6509     srb->Function   = SRB_FUNCTION_EXECUTE_SCSI;
6510     srb->Length     = sizeof(SCSI_REQUEST_BLOCK);
6511 
6512     //
6513     // Set flags to disable synchronous negotiation.
6514     //
6515     srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
6516 
6517     //
6518     // Set timeout to 2 seconds.
6519     //
6520     srb->TimeOutValue = 4;
6521 
6522     srb->CdbLength          = 6;
6523     srb->DataBuffer         = &deviceExtension->MechStatusSense;
6524     srb->DataTransferLength = sizeof(SENSE_DATA);
6525 
6526     //
6527     // Set CDB operation code.
6528     //
6529     cdb = (PCDB)srb->Cdb;
6530     cdb->CDB6INQUIRY.OperationCode    = SCSIOP_REQUEST_SENSE;
6531     cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
6532 
6533     return srb;
6534 }
6535 
6536 
6537 
6538 
6539 
6540