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