sync with trunk r46493
[reactos.git] / drivers / storage / ide / atapi / atapi.c
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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 \f
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