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