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