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