Disk driver stack update.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
1 /* $Id: atapi.c,v 1.5 2002/01/31 14:57:37 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS ATAPI miniport driver
5 * FILE: services/storage/atapi/atapi.c
6 * PURPOSE: ATAPI miniport driver
7 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
8 * REVISIONS:
9 * 09-09-2001 Created
10 */
11
12 /*
13 * Note:
14 * This driver is derived from Rex Jolliff's ide driver. Lots of his
15 * routines are still in here although they belong into the higher level
16 * drivers. They will be moved away as soon as possible.
17 */
18
19 /*
20 * TODO:
21 * - implement sending of atapi commands
22 * - handle removable atapi non-cdrom drives
23 */
24
25 // -------------------------------------------------------------------------
26
27 #include <ddk/ntddk.h>
28
29 #include "../include/srb.h"
30 #include "../include/scsi.h"
31 #include "../include/ntddscsi.h"
32
33 #include "atapi.h"
34
35 #define NDEBUG
36 #include <debug.h>
37
38 #define VERSION "V0.0.1"
39
40
41 // ------------------------------------------------------- File Static Data
42
43 // ATAPI_MINIPORT_EXTENSION
44 //
45 // DESCRIPTION:
46 // Extension to be placed in each port device object
47 //
48 // ACCESS:
49 // Allocated from NON-PAGED POOL
50 // Available at any IRQL
51 //
52
53 typedef struct _ATAPI_MINIPORT_EXTENSION
54 {
55 IDE_DRIVE_IDENTIFY DeviceParams[2];
56 BOOLEAN DevicePresent[2];
57 BOOLEAN DeviceAtapi[2];
58
59 ULONG CommandPortBase;
60 ULONG ControlPortBase;
61
62 BOOLEAN ExpectingInterrupt;
63
64 PUSHORT DataBuffer;
65 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
66
67
68 typedef struct _UNIT_EXTENSION
69 {
70 ULONG Dummy;
71 } UNIT_EXTENSION, *PUNIT_EXTENSION;
72
73
74 // ----------------------------------------------- Discardable Declarations
75
76 #ifdef ALLOC_PRAGMA
77
78 // make the initialization routines discardable, so that they
79 // don't waste space
80
81 #pragma alloc_text(init, DriverEntry)
82 #pragma alloc_text(init, IDECreateController)
83 #pragma alloc_text(init, IDEPolledRead)
84
85 // make the PASSIVE_LEVEL routines pageable, so that they don't
86 // waste nonpaged memory
87
88 #pragma alloc_text(page, IDEShutdown)
89 #pragma alloc_text(page, IDEDispatchOpenClose)
90 #pragma alloc_text(page, IDEDispatchRead)
91 #pragma alloc_text(page, IDEDispatchWrite)
92
93 #endif /* ALLOC_PRAGMA */
94
95 // ---------------------------------------------------- Forward Declarations
96
97 static ULONG STDCALL
98 AtapiFindCompatiblePciController(PVOID DeviceExtension,
99 PVOID HwContext,
100 PVOID BusInformation,
101 PCHAR ArgumentString,
102 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
103 PBOOLEAN Again);
104
105 static ULONG STDCALL
106 AtapiFindIsaBusController(PVOID DeviceExtension,
107 PVOID HwContext,
108 PVOID BusInformation,
109 PCHAR ArgumentString,
110 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
111 PBOOLEAN Again);
112
113 static ULONG STDCALL
114 AtapiFindNativePciController(PVOID DeviceExtension,
115 PVOID HwContext,
116 PVOID BusInformation,
117 PCHAR ArgumentString,
118 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
119 PBOOLEAN Again);
120
121 static BOOLEAN STDCALL
122 AtapiInitialize(IN PVOID DeviceExtension);
123
124 static BOOLEAN STDCALL
125 AtapiResetBus(IN PVOID DeviceExtension,
126 IN ULONG PathId);
127
128 static BOOLEAN STDCALL
129 AtapiStartIo(IN PVOID DeviceExtension,
130 IN PSCSI_REQUEST_BLOCK Srb);
131
132 static BOOLEAN STDCALL
133 AtapiInterrupt(IN PVOID DeviceExtension);
134
135 static BOOLEAN
136 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
137 PPORT_CONFIGURATION_INFORMATION ConfigInfo);
138
139 static BOOLEAN
140 AtapiIdentifyATADevice(IN ULONG CommandPort,
141 IN ULONG DriveNum,
142 OUT PIDE_DRIVE_IDENTIFY DrvParms);
143
144 static BOOLEAN
145 AtapiIdentifyATAPIDevice(IN ULONG CommandPort,
146 IN ULONG DriveNum,
147 OUT PIDE_DRIVE_IDENTIFY DrvParms);
148
149 static BOOLEAN
150 IDEResetController(IN WORD CommandPort,
151 IN WORD ControlPort);
152
153 static int
154 AtapiPolledRead(IN WORD Address,
155 IN BYTE PreComp,
156 IN BYTE SectorCnt,
157 IN BYTE SectorNum,
158 IN BYTE CylinderLow,
159 IN BYTE CylinderHigh,
160 IN BYTE DrvHead,
161 IN BYTE Command,
162 OUT BYTE *Buffer);
163
164
165
166
167 static ULONG
168 AtapiExecuteScsi(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
169 IN PSCSI_REQUEST_BLOCK Srb);
170
171 static ULONG
172 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
173 IN PSCSI_REQUEST_BLOCK Srb);
174
175 static ULONG
176 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
177 IN PSCSI_REQUEST_BLOCK Srb);
178
179 static ULONG
180 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
181 IN PSCSI_REQUEST_BLOCK Srb);
182
183 // ---------------------------------------------------------------- Inlines
184
185 void
186 IDESwapBytePairs(char *Buf,
187 int Cnt)
188 {
189 char t;
190 int i;
191
192 for (i = 0; i < Cnt; i += 2)
193 {
194 t = Buf[i];
195 Buf[i] = Buf[i+1];
196 Buf[i+1] = t;
197 }
198 }
199
200
201 static BOOLEAN
202 IdeFindDrive(int Address,
203 int DriveIdx)
204 {
205 ULONG Cyl;
206
207 DPRINT1("IdeFindDrive(Address %lx DriveIdx %lu) called!\n", Address, DriveIdx);
208
209 IDEWriteDriveHead(Address, IDE_DH_FIXED | (DriveIdx ? IDE_DH_DRV1 : 0));
210 IDEWriteCylinderLow(Address, 0x30);
211
212 Cyl = IDEReadCylinderLow(Address);
213 DPRINT1("Cylinder %lx\n", Cyl);
214
215
216 DPRINT1("IdeFindDrive() done!\n");
217 // for(;;);
218 return(Cyl == 0x30);
219 }
220
221
222 // ------------------------------------------------------- Public Interface
223
224 // DriverEntry
225 //
226 // DESCRIPTION:
227 // This function initializes the driver, locates and claims
228 // hardware resources, and creates various NT objects needed
229 // to process I/O requests.
230 //
231 // RUN LEVEL:
232 // PASSIVE_LEVEL
233 //
234 // ARGUMENTS:
235 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
236 // for this driver
237 // IN PUNICODE_STRING RegistryPath Name of registry driver service
238 // key
239 //
240 // RETURNS:
241 // NTSTATUS
242
243 STDCALL NTSTATUS
244 DriverEntry(IN PDRIVER_OBJECT DriverObject,
245 IN PUNICODE_STRING RegistryPath)
246 {
247 HW_INITIALIZATION_DATA InitData;
248 NTSTATUS Status;
249
250 DbgPrint("ATAPI Driver %s\n", VERSION);
251
252 /* Initialize data structure */
253 RtlZeroMemory(&InitData,
254 sizeof(HW_INITIALIZATION_DATA));
255 InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
256 InitData.HwInitialize = AtapiInitialize;
257 InitData.HwResetBus = AtapiResetBus;
258 InitData.HwStartIo = AtapiStartIo;
259 InitData.HwInterrupt = AtapiInterrupt;
260
261 InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
262 InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
263
264 InitData.MapBuffers = TRUE;
265
266 /* Search the PCI bus for compatibility mode ide controllers */
267 InitData.HwFindAdapter = AtapiFindCompatiblePciController;
268 InitData.NumberOfAccessRanges = 2;
269 InitData.AdapterInterfaceType = PCIBus;
270
271 InitData.VendorId = NULL;
272 InitData.VendorIdLength = 0;
273 InitData.DeviceId = NULL;
274 InitData.DeviceIdLength = 0;
275
276 Status = ScsiPortInitialize(DriverObject,
277 RegistryPath,
278 &InitData,
279 NULL);
280 // if (newStatus < statusToReturn)
281 // statusToReturn = newStatus;
282
283 /* Search the ISA bus for ide controllers */
284 #if 0
285 InitData.HwFindAdapter = AtapiFindIsaBusController;
286 InitData.NumberOfAccessRanges = 2;
287 InitData.AdapterInterfaceType = Isa;
288
289 InitData.VendorId = NULL;
290 InitData.VendorIdLength = 0;
291 InitData.DeviceId = NULL;
292 InitData.DeviceIdLength = 0;
293
294 Status = ScsiPortInitialize(DriverObject,
295 RegistryPath,
296 &InitData,
297 NULL);
298 // if (newStatus < statusToReturn)
299 // statusToReturn = newStatus;
300 #endif
301
302 /* Search the PCI bus for native mode ide controllers */
303 #if 0
304 InitData.HwFindAdapter = AtapiFindNativePciController;
305 InitData.NumberOfAccessRanges = 2;
306 InitData.AdapterInterfaceType = PCIBus;
307
308 InitData.VendorId = NULL;
309 InitData.VendorIdLength = 0;
310 InitData.DeviceId = NULL;
311 InitData.DeviceIdLength = 0;
312
313 Status = ScsiPortInitialize(DriverObject,
314 RegistryPath,
315 &InitData,
316 (PVOID)i);
317 // if (newStatus < statusToReturn)
318 // statusToReturn = newStatus;
319 #endif
320
321 DPRINT1( "Returning from DriverEntry\n" );
322
323 return(Status);
324 }
325
326
327 static ULONG STDCALL
328 AtapiFindCompatiblePciController(PVOID DeviceExtension,
329 PVOID HwContext,
330 PVOID BusInformation,
331 PCHAR ArgumentString,
332 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
333 PBOOLEAN Again)
334 {
335 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
336 PCI_SLOT_NUMBER SlotNumber;
337 PCI_COMMON_CONFIG PciConfig;
338 ULONG DataSize;
339 ULONG FunctionNumber;
340 BOOLEAN ChannelFound;
341 BOOLEAN DeviceFound;
342
343 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
344 ConfigInfo->SystemIoBusNumber,
345 ConfigInfo->SlotNumber);
346
347 *Again = FALSE;
348
349 /* both channels were claimed: exit */
350 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
351 ConfigInfo->AtdiskSecondaryClaimed == TRUE)
352 return(SP_RETURN_NOT_FOUND);
353
354
355 SlotNumber.u.AsULONG = 0;
356 for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
357 {
358 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
359 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
360 SlotNumber.u.AsULONG = FunctionNumber;
361
362 ChannelFound = FALSE;
363 DeviceFound = FALSE;
364
365 DataSize = ScsiPortGetBusData(DeviceExtension,
366 PCIConfiguration,
367 0,
368 SlotNumber.u.AsULONG,
369 &PciConfig,
370 sizeof(PCI_COMMON_CONFIG));
371 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
372 // PciConfig.VendorID == PCI_INVALID_VENDORID)
373 if (DataSize == 0)
374 {
375 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
376 // return(SP_RETURN_ERROR); /* No bus found */
377
378 continue;
379 // return(SP_RETURN_ERROR);
380 }
381
382 if (PciConfig.BaseClass == 0x01 &&
383 PciConfig.SubClass == 0x01) // &&
384 // (PciConfig.ProgIf & 0x05) == 0)
385 {
386 /* both channels are in compatibility mode */
387 DPRINT1("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
388 ConfigInfo->SystemIoBusNumber,
389 // SlotNumber.u.AsULONG >> 3,
390 // SlotNumber.u.AsULONG & 0x07,
391 SlotNumber.u.bits.DeviceNumber,
392 SlotNumber.u.bits.FunctionNumber,
393 PciConfig.VendorID,
394 PciConfig.DeviceID);
395 DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
396
397 DPRINT1("Found IDE controller in compatibility mode!\n");
398
399 ConfigInfo->NumberOfBuses = 1;
400 ConfigInfo->MaximumNumberOfTargets = 2;
401 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
402
403 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
404 {
405 /* Both channels unclaimed: Claim primary channel */
406 DPRINT1("Primary channel!\n");
407
408 DevExt->CommandPortBase = 0x01F0;
409 DevExt->ControlPortBase = 0x03F6;
410
411 ConfigInfo->BusInterruptLevel = 14;
412 ConfigInfo->BusInterruptVector = 14;
413 ConfigInfo->InterruptMode = LevelSensitive;
414
415 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
416 ConfigInfo->AccessRanges[0].RangeLength = 8;
417 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
418
419 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
420 ConfigInfo->AccessRanges[1].RangeLength = 1;
421 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
422
423 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
424 ChannelFound = TRUE;
425 *Again = TRUE;
426 }
427 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
428 {
429 /* Primary channel already claimed: claim secondary channel */
430 DPRINT1("Secondary channel!\n");
431
432 DevExt->CommandPortBase = 0x0170;
433 DevExt->ControlPortBase = 0x0376;
434
435 ConfigInfo->BusInterruptLevel = 15;
436 ConfigInfo->BusInterruptVector = 15;
437 ConfigInfo->InterruptMode = LevelSensitive;
438
439 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
440 ConfigInfo->AccessRanges[0].RangeLength = 8;
441 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
442
443 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
444 ConfigInfo->AccessRanges[1].RangeLength = 1;
445 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
446
447 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
448 ChannelFound = TRUE;
449 *Again = FALSE;
450 }
451
452 /* Find attached devices */
453 if (ChannelFound == TRUE)
454 {
455 DeviceFound = AtapiFindDevices(DevExt,
456 ConfigInfo);
457 }
458 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
459 return(SP_RETURN_FOUND);
460 }
461 }
462
463 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
464
465 return(SP_RETURN_NOT_FOUND);
466 }
467
468
469 static ULONG STDCALL
470 AtapiFindIsaBusController(PVOID DeviceExtension,
471 PVOID HwContext,
472 PVOID BusInformation,
473 PCHAR ArgumentString,
474 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
475 PBOOLEAN Again)
476 {
477 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
478
479 DPRINT("AtapiFindIsaBusController() called!\n");
480
481 *Again = FALSE;
482
483 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE)
484 {
485 DPRINT("Primary IDE controller already claimed!\n");
486
487 }
488
489 if (ConfigInfo->AtdiskSecondaryClaimed == TRUE)
490 {
491 DPRINT("Secondary IDE controller already claimed!\n");
492
493 }
494
495 DPRINT("AtapiFindIsaBusController() done!\n");
496
497 return(SP_RETURN_NOT_FOUND);
498 }
499
500
501 static ULONG STDCALL
502 AtapiFindNativePciController(PVOID DeviceExtension,
503 PVOID HwContext,
504 PVOID BusInformation,
505 PCHAR ArgumentString,
506 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
507 PBOOLEAN Again)
508 {
509 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
510
511 DPRINT("AtapiFindNativePciController() called!\n");
512
513 *Again = FALSE;
514
515 DPRINT("AtapiFindNativePciController() done!\n");
516
517 return(SP_RETURN_NOT_FOUND);
518 }
519
520
521 static BOOLEAN STDCALL
522 AtapiInitialize(IN PVOID DeviceExtension)
523 {
524 return(TRUE);
525 }
526
527
528 static BOOLEAN STDCALL
529 AtapiResetBus(IN PVOID DeviceExtension,
530 IN ULONG PathId)
531 {
532 return(TRUE);
533 }
534
535
536 static BOOLEAN STDCALL
537 AtapiStartIo(IN PVOID DeviceExtension,
538 IN PSCSI_REQUEST_BLOCK Srb)
539 {
540 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
541 ULONG Result;
542
543 DPRINT("AtapiStartIo() called\n");
544
545 switch (Srb->Function)
546 {
547 case SRB_FUNCTION_EXECUTE_SCSI:
548
549 Result = AtapiExecuteScsi(DevExt,
550 Srb);
551
552 break;
553
554 }
555
556 Srb->SrbStatus = Result;
557
558 return(TRUE);
559 }
560
561
562 static BOOLEAN STDCALL
563 AtapiInterrupt(IN PVOID DeviceExtension)
564 {
565 DPRINT("AtapiInterrupt() called!\n");
566
567 return(TRUE);
568 }
569
570
571
572
573
574
575 // ---------------------------------------------------- Discardable statics
576
577
578 static BOOLEAN
579 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
580 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
581 {
582 BOOLEAN DeviceFound = FALSE;
583 ULONG CommandPortBase;
584 ULONG UnitNumber;
585 ULONG Retries;
586 BYTE High, Low;
587
588 DPRINT("AtapiFindDevices() called\n");
589
590 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
591 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
592
593 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
594
595 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
596 {
597 /* disable interrupts */
598 IDEWriteDriveControl(CommandPortBase,
599 IDE_DC_nIEN);
600
601 /* select drive */
602 IDEWriteDriveHead(CommandPortBase,
603 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
604 ScsiPortStallExecution(500);
605 IDEWriteCylinderHigh(CommandPortBase, 0);
606 IDEWriteCylinderLow(CommandPortBase, 0);
607 IDEWriteCommand(CommandPortBase, 0x08); /* IDE_COMMAND_ATAPI_RESET */
608 // ScsiPortStallExecution(1000*1000);
609 // IDEWriteDriveHead(CommandPortBase,
610 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
611 // IDE_DH_FIXED);
612
613 for (Retries = 0; Retries < 20000; Retries++)
614 {
615 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
616 {
617 break;
618 }
619 ScsiPortStallExecution(150);
620 }
621 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
622 {
623 DbgPrint("Timeout on drive %lu\n", UnitNumber);
624 return(DeviceFound);
625 }
626
627 High = IDEReadCylinderHigh(CommandPortBase);
628 Low = IDEReadCylinderLow(CommandPortBase);
629
630 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
631 UnitNumber,
632 High,
633 Low);
634
635 if (High == 0xEB && Low == 0x14)
636 {
637 if (AtapiIdentifyATAPIDevice(CommandPortBase,
638 UnitNumber,
639 &DeviceExtension->DeviceParams[UnitNumber]))
640 {
641 DPRINT(" ATAPI drive found!\n");
642 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
643 DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
644 DeviceFound = TRUE;
645 }
646 else
647 {
648 DPRINT(" No ATAPI drive found!\n");
649 }
650 }
651 else
652 {
653 if (AtapiIdentifyATADevice(CommandPortBase,
654 UnitNumber,
655 &DeviceExtension->DeviceParams[UnitNumber]))
656 {
657 DPRINT(" IDE drive found!\n");
658 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
659 DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
660 DeviceFound = TRUE;
661 }
662 else
663 {
664 DPRINT(" No IDE drive found!\n");
665 }
666 }
667 }
668
669 DPRINT("AtapiFindDrives() done\n");
670
671 return(DeviceFound);
672 }
673
674
675 // AtapiResetController
676 //
677 // DESCRIPTION:
678 // Reset the controller and report completion status
679 //
680 // RUN LEVEL:
681 // PASSIVE_LEVEL
682 //
683 // ARGUMENTS:
684 // IN WORD CommandPort The address of the command port
685 // IN WORD ControlPort The address of the control port
686 //
687 // RETURNS:
688 //
689
690 static BOOLEAN
691 AtapiResetController(IN WORD CommandPort,
692 IN WORD ControlPort)
693 {
694 int Retries;
695
696 /* Assert drive reset line */
697 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
698
699 /* Wait for min. 25 microseconds */
700 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
701
702 /* Negate drive reset line */
703 IDEWriteDriveControl(ControlPort, 0);
704
705 /* Wait for BUSY negation */
706 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
707 {
708 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
709 {
710 break;
711 }
712 ScsiPortStallExecution(10);
713 }
714
715 CHECKPOINT;
716 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
717 {
718 return(FALSE);
719 }
720
721 CHECKPOINT;
722
723 // return TRUE if controller came back to life. and
724 // the registers are initialized correctly
725 return(IDEReadError(CommandPort) == 1);
726 }
727
728
729 // AtapiIdentifyATADevice
730 //
731 // DESCRIPTION:
732 // Get the identification block from the drive
733 //
734 // RUN LEVEL:
735 // PASSIVE_LEVEL
736 //
737 // ARGUMENTS:
738 // IN int CommandPort Address of the command port
739 // IN int DriveNum The drive index (0,1)
740 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
741 //
742 // RETURNS:
743 // TRUE The drive identification block was retrieved successfully
744 //
745
746 static BOOLEAN
747 AtapiIdentifyATADevice(IN ULONG CommandPort,
748 IN ULONG DriveNum,
749 OUT PIDE_DRIVE_IDENTIFY DrvParms)
750 {
751 /* Get the Drive Identify block from drive or die */
752 if (AtapiPolledRead((WORD)CommandPort,
753 0,
754 1,
755 0,
756 0,
757 0,
758 (DriveNum ? IDE_DH_DRV1 : 0),
759 IDE_CMD_IDENT_ATA_DRV,
760 (BYTE *)DrvParms) != 0)
761 {
762 return FALSE;
763 }
764
765 /* Report on drive parameters if debug mode */
766 IDESwapBytePairs(DrvParms->SerialNumber, 20);
767 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
768 IDESwapBytePairs(DrvParms->ModelNumber, 40);
769 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
770 DrvParms->ConfigBits,
771 DrvParms->LogicalCyls,
772 DrvParms->LogicalHeads,
773 DrvParms->SectorsPerTrack,
774 DrvParms->InterSectorGap,
775 DrvParms->InterSectorGapSize);
776 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
777 DrvParms->BytesInPLO,
778 DrvParms->VendorUniqueCnt,
779 DrvParms->SerialNumber);
780 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
781 DrvParms->ControllerType,
782 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
783 DrvParms->ECCByteCnt,
784 DrvParms->FirmwareRev);
785 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
786 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
787 (DrvParms->RWMultImplemented) & 0xff,
788 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
789 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
790 DrvParms->MinPIOTransTime,
791 DrvParms->MinDMATransTime);
792 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
793 DrvParms->TMCylinders,
794 DrvParms->TMHeads,
795 DrvParms->TMSectorsPerTrk,
796 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
797 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
798 DrvParms->TMSectorCountHi,
799 DrvParms->TMSectorCountLo,
800 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
801
802 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
803 if (DrvParms->BytesPerSector == 0)
804 DrvParms->BytesPerSector = 512;
805 return TRUE;
806 }
807
808
809 static BOOLEAN
810 AtapiIdentifyATAPIDevice(IN ULONG CommandPort,
811 IN ULONG DriveNum,
812 OUT PIDE_DRIVE_IDENTIFY DrvParms)
813 {
814 /* Get the Drive Identify block from drive or die */
815 if (AtapiPolledRead((WORD)CommandPort,
816 0,
817 1,
818 0,
819 0,
820 0,
821 (DriveNum ? IDE_DH_DRV1 : 0),
822 IDE_CMD_IDENT_ATAPI_DRV,
823 (BYTE *)DrvParms) != 0) /* atapi_identify */
824 {
825 DPRINT1("IDEPolledRead() failed\n");
826 return FALSE;
827 }
828
829 /* Report on drive parameters if debug mode */
830 IDESwapBytePairs(DrvParms->SerialNumber, 20);
831 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
832 IDESwapBytePairs(DrvParms->ModelNumber, 40);
833 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
834 DrvParms->ConfigBits,
835 DrvParms->LogicalCyls,
836 DrvParms->LogicalHeads,
837 DrvParms->SectorsPerTrack,
838 DrvParms->InterSectorGap,
839 DrvParms->InterSectorGapSize);
840 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
841 DrvParms->BytesInPLO,
842 DrvParms->VendorUniqueCnt,
843 DrvParms->SerialNumber);
844 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
845 DrvParms->ControllerType,
846 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
847 DrvParms->ECCByteCnt,
848 DrvParms->FirmwareRev);
849 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
850 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
851 (DrvParms->RWMultImplemented) & 0xff,
852 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
853 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
854 DrvParms->MinPIOTransTime,
855 DrvParms->MinDMATransTime);
856 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
857 DrvParms->TMCylinders,
858 DrvParms->TMHeads,
859 DrvParms->TMSectorsPerTrk,
860 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
861 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
862 DrvParms->TMSectorCountHi,
863 DrvParms->TMSectorCountLo,
864 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
865
866 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
867 // DrvParms->BytesPerSector = 512; /* FIXME !!!*/
868 return TRUE;
869 }
870
871
872 // AtapiPolledRead
873 //
874 // DESCRIPTION:
875 // Read a sector of data from the drive in a polled fashion.
876 //
877 // RUN LEVEL:
878 // PASSIVE_LEVEL
879 //
880 // ARGUMENTS:
881 // IN WORD Address Address of command port for drive
882 // IN BYTE PreComp Value to write to precomp register
883 // IN BYTE SectorCnt Value to write to sectorCnt register
884 // IN BYTE SectorNum Value to write to sectorNum register
885 // IN BYTE CylinderLow Value to write to CylinderLow register
886 // IN BYTE CylinderHigh Value to write to CylinderHigh register
887 // IN BYTE DrvHead Value to write to Drive/Head register
888 // IN BYTE Command Value to write to Command register
889 // OUT BYTE *Buffer Buffer for output data
890 //
891 // RETURNS:
892 // int 0 is success, non 0 is an error code
893 //
894
895 static int
896 AtapiPolledRead(IN WORD Address,
897 IN BYTE PreComp,
898 IN BYTE SectorCnt,
899 IN BYTE SectorNum,
900 IN BYTE CylinderLow,
901 IN BYTE CylinderHigh,
902 IN BYTE DrvHead,
903 IN BYTE Command,
904 OUT BYTE *Buffer)
905 {
906 ULONG SectorCount = 0;
907 ULONG RetryCount;
908 BOOLEAN Junk = FALSE;
909 UCHAR Status;
910
911 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
912 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
913 {
914 Status = IDEReadStatus(Address);
915 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
916 {
917 break;
918 }
919 ScsiPortStallExecution(10);
920 }
921 if (RetryCount == IDE_MAX_BUSY_RETRIES)
922 {
923 return(IDE_ER_ABRT);
924 }
925
926 /* Write Drive/Head to select drive */
927 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
928
929 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
930 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
931 {
932 Status = IDEReadStatus(Address);
933 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
934 {
935 break;
936 }
937 ScsiPortStallExecution(10);
938 }
939 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
940 {
941 return IDE_ER_ABRT;
942 }
943
944 /* Issue command to drive */
945 if (DrvHead & IDE_DH_LBA)
946 {
947 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
948 DrvHead & IDE_DH_DRV1 ? 1 : 0,
949 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
950 SectorCnt,
951 Command);
952 }
953 else
954 {
955 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
956 DrvHead & IDE_DH_DRV1 ? 1 : 0,
957 CylinderHigh,
958 CylinderLow,
959 DrvHead & 0x0f,
960 SectorNum,
961 SectorCnt,
962 Command);
963 }
964
965 /* Setup command parameters */
966 IDEWritePrecomp(Address, PreComp);
967 IDEWriteSectorCount(Address, SectorCnt);
968 IDEWriteSectorNum(Address, SectorNum);
969 IDEWriteCylinderHigh(Address, CylinderHigh);
970 IDEWriteCylinderLow(Address, CylinderLow);
971 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
972
973 /* Issue the command */
974 IDEWriteCommand(Address, Command);
975 ScsiPortStallExecution(50);
976
977 /* wait for DRQ or error */
978 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
979 {
980 Status = IDEReadStatus(Address);
981 if (!(Status & IDE_SR_BUSY))
982 {
983 if (Status & IDE_SR_ERR)
984 {
985 return(IDE_ER_ABRT);
986 }
987 if (Status & IDE_SR_DRQ)
988 {
989 break;
990 }
991 else
992 {
993 return(IDE_ER_ABRT);
994 }
995 }
996 ScsiPortStallExecution(10);
997 }
998
999 /* timed out */
1000 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1001 {
1002 return(IDE_ER_ABRT);
1003 }
1004
1005 while (1)
1006 {
1007 /* Read data into buffer */
1008 if (Junk == FALSE)
1009 {
1010 IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1011 Buffer += IDE_SECTOR_BUF_SZ;
1012 }
1013 else
1014 {
1015 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1016 IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
1017 }
1018 SectorCount++;
1019
1020 /* Check for error or more sectors to read */
1021 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1022 {
1023 Status = IDEReadStatus(Address);
1024 if (!(Status & IDE_SR_BUSY))
1025 {
1026 if (Status & IDE_SR_ERR)
1027 {
1028 return(IDE_ER_ABRT);
1029 }
1030 if (Status & IDE_SR_DRQ)
1031 {
1032 if (SectorCount >= SectorCnt)
1033 {
1034 DPRINT("Buffer size exceeded!\n");
1035 Junk = TRUE;
1036 }
1037 break;
1038 }
1039 else
1040 {
1041 if (SectorCount > SectorCnt)
1042 {
1043 DPRINT("Read %lu sectors of junk!\n",
1044 SectorCount - SectorCnt);
1045 }
1046 return(0);
1047 }
1048 }
1049 }
1050 }
1051 }
1052
1053
1054 // ------------------------------------------- Nondiscardable statics
1055
1056
1057 static ULONG
1058 AtapiExecuteScsi(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1059 IN PSCSI_REQUEST_BLOCK Srb)
1060 {
1061 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1062
1063 DPRINT1("AtapiExecuteScsi() called!\n");
1064
1065 DPRINT1("PathId: %lu TargetId: %lu Lun: %lu\n",
1066 Srb->PathId,
1067 Srb->TargetId,
1068 Srb->Lun);
1069
1070 switch (Srb->Cdb[0])
1071 {
1072 case SCSIOP_INQUIRY:
1073 SrbStatus = AtapiInquiry(DeviceExtension,
1074 Srb);
1075 break;
1076
1077 case SCSIOP_READ_CAPACITY:
1078 SrbStatus = AtapiReadCapacity(DeviceExtension,
1079 Srb);
1080 break;
1081
1082 case SCSIOP_READ:
1083 case SCSIOP_WRITE:
1084 SrbStatus = AtapiReadWrite(DeviceExtension,
1085 Srb);
1086 break;
1087
1088 case SCSIOP_MODE_SENSE:
1089 case SCSIOP_TEST_UNIT_READY:
1090 case SCSIOP_VERIFY:
1091 case SCSIOP_START_STOP_UNIT:
1092 case SCSIOP_REQUEST_SENSE:
1093 break;
1094
1095 default:
1096 DPRINT1("AtapiExecuteScsi():unknown command %x\n",
1097 Srb->Cdb[0]);
1098 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1099 break;
1100 }
1101
1102 DPRINT1("AtapiExecuteScsi() done!\n");
1103
1104 return(SrbStatus);
1105 }
1106
1107
1108 static ULONG
1109 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1110 PSCSI_REQUEST_BLOCK Srb)
1111 {
1112 PIDE_DRIVE_IDENTIFY DeviceParams;
1113 PINQUIRYDATA InquiryData;
1114 ULONG i;
1115
1116 DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb->TargetId);
1117
1118 if ((Srb->PathId != 0) ||
1119 (Srb->TargetId > 1) ||
1120 (Srb->Lun != 0) ||
1121 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1122 {
1123 return(SRB_STATUS_SELECTION_TIMEOUT);
1124 }
1125
1126 InquiryData = Srb->DataBuffer;
1127 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1128
1129 /* clear buffer */
1130 for (i = 0; i < Srb->DataTransferLength; i++)
1131 {
1132 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1133 }
1134
1135 /* set device class */
1136 if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
1137 {
1138 /* hard-disk */
1139 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1140 }
1141 else
1142 {
1143 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1144 /* cdrom drive */
1145 InquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
1146 }
1147
1148 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1149 if (DeviceParams->ConfigBits & 0x80)
1150 {
1151 DPRINT1("Removable media!\n");
1152 InquiryData->RemovableMedia = 1;
1153 }
1154
1155 for (i = 0; i < 20; i += 2)
1156 {
1157 InquiryData->VendorId[i] =
1158 ((PUCHAR)DeviceParams->ModelNumber)[i];
1159 InquiryData->VendorId[i+1] =
1160 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1161 }
1162
1163 for (i = 0; i < 4; i++)
1164 {
1165 InquiryData->ProductId[12+i] = ' ';
1166 }
1167
1168 for (i = 0; i < 4; i += 2)
1169 {
1170 InquiryData->ProductRevisionLevel[i] =
1171 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1172 InquiryData->ProductRevisionLevel[i+1] =
1173 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1174 }
1175
1176 return(SRB_STATUS_SUCCESS);
1177 }
1178
1179
1180 static ULONG
1181 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1182 PSCSI_REQUEST_BLOCK Srb)
1183 {
1184 PREAD_CAPACITY_DATA CapacityData;
1185 PIDE_DRIVE_IDENTIFY DeviceParams;
1186 ULONG LastSector;
1187
1188 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1189
1190 if ((Srb->PathId != 0) ||
1191 (Srb->TargetId > 1) ||
1192 (Srb->Lun != 0) ||
1193 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1194 {
1195 return(SRB_STATUS_SELECTION_TIMEOUT);
1196 }
1197
1198
1199 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1200 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1201
1202 /* Set sector (block) size to 512 bytes (big-endian). */
1203 CapacityData->BytesPerBlock = 0x20000;
1204
1205 /* Calculate last sector (big-endian). */
1206 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1207 {
1208 LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1209 DeviceParams->TMSectorCountLo) - 1;
1210 }
1211 else
1212 {
1213 LastSector = (ULONG)(DeviceParams->LogicalCyls *
1214 DeviceParams->LogicalHeads *
1215 DeviceParams->SectorsPerTrack)-1;
1216 }
1217
1218 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1219 (((PUCHAR)&LastSector)[1] << 16) |
1220 (((PUCHAR)&LastSector)[2] << 8) |
1221 ((PUCHAR)&LastSector)[3];
1222
1223 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1224 LastSector,
1225 LastSector,
1226 CapacityData->LogicalBlockAddress);
1227
1228 return(SRB_STATUS_SUCCESS);
1229 }
1230
1231
1232 static ULONG
1233 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1234 PSCSI_REQUEST_BLOCK Srb)
1235 {
1236 PIDE_DRIVE_IDENTIFY DeviceParams;
1237
1238 ULONG StartingSector,i;
1239 ULONG SectorCount;
1240 UCHAR CylinderHigh;
1241 UCHAR CylinderLow;
1242 UCHAR DrvHead;
1243 UCHAR SectorNumber;
1244 UCHAR Command;
1245 ULONG Retries;
1246 UCHAR Status;
1247
1248
1249 DPRINT1("AtapiReadWrite() called!\n");
1250
1251 if ((Srb->PathId != 0) ||
1252 (Srb->TargetId > 1) ||
1253 (Srb->Lun != 0) ||
1254 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1255 {
1256 return(SRB_STATUS_SELECTION_TIMEOUT);
1257 }
1258
1259 DPRINT1("SCSIOP_WRITE: TargetId: %lu\n",
1260 Srb->TargetId);
1261
1262 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1263
1264 /* Get starting sector number from CDB. */
1265 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
1266 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
1267 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
1268 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
1269
1270 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
1271 DeviceParams->BytesPerSector;
1272
1273 DPRINT1("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1274 StartingSector,
1275 Srb->DataTransferLength,
1276 SectorCount);
1277
1278 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1279 {
1280 SectorNumber = StartingSector & 0xff;
1281 CylinderLow = (StartingSector >> 8) & 0xff;
1282 CylinderHigh = (StartingSector >> 16) & 0xff;
1283 DrvHead = ((StartingSector >> 24) & 0x0f) |
1284 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
1285 IDE_DH_LBA;
1286 }
1287 else
1288 {
1289 SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
1290 StartingSector /= DeviceParams->SectorsPerTrack;
1291 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
1292 (Srb->TargetId ? IDE_DH_DRV1 : 0);
1293 StartingSector /= DeviceParams->LogicalHeads;
1294 CylinderLow = StartingSector & 0xff;
1295 CylinderHigh = StartingSector >> 8;
1296 }
1297
1298
1299 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
1300 {
1301 Command = IDE_CMD_READ;
1302 }
1303 else
1304 {
1305 Command = IDE_CMD_WRITE;
1306 }
1307
1308 if (DrvHead & IDE_DH_LBA)
1309 {
1310 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1311 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1312 DeviceExtension->CommandPortBase,
1313 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1314 ((DrvHead & 0x0f) << 24) +
1315 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
1316 SectorCount,
1317 Command);
1318 }
1319 else
1320 {
1321 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1322 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1323 DeviceExtension->CommandPortBase,
1324 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1325 CylinderHigh,
1326 CylinderLow,
1327 DrvHead & 0x0f,
1328 SectorNumber,
1329 SectorCount,
1330 Command);
1331 }
1332
1333 /* Set pointer to data buffer. */
1334 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1335
1336
1337
1338
1339 /* wait for BUSY to clear */
1340 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1341 {
1342 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1343 if (!(Status & IDE_SR_BUSY))
1344 {
1345 break;
1346 }
1347 ScsiPortStallExecution(10);
1348 }
1349 DPRINT ("status=%02x\n", Status);
1350 DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
1351 if (Retries >= IDE_MAX_BUSY_RETRIES)
1352 {
1353 DPRINT ("Drive is BUSY for too long\n");
1354 return(SRB_STATUS_BUSY);
1355 #if 0
1356 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1357 {
1358 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1359 Irp = ControllerExtension->CurrentIrp;
1360 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1361 Irp->IoStatus.Information = 0;
1362
1363 return FALSE;
1364 }
1365 else
1366 {
1367 DPRINT ("Beginning drive reset sequence\n");
1368 IDEBeginControllerReset(ControllerExtension);
1369
1370 return TRUE;
1371 }
1372 #endif
1373 }
1374
1375 /* Select the desired drive */
1376 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1377 IDE_DH_FIXED | DrvHead);
1378
1379 /* wait for BUSY to clear and DRDY to assert */
1380 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1381 {
1382 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1383 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1384 {
1385 break;
1386 }
1387 ScsiPortStallExecution(10);
1388 }
1389 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1390 if (Retries >= IDE_MAX_BUSY_RETRIES)
1391 {
1392 DPRINT ("Drive is BUSY for too long after drive select\n");
1393 return(SRB_STATUS_BUSY);
1394 #if 0
1395 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1396 {
1397 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1398 Irp = ControllerExtension->CurrentIrp;
1399 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1400 Irp->IoStatus.Information = 0;
1401
1402 return FALSE;
1403 }
1404 else
1405 {
1406 DPRINT ("Beginning drive reset sequence\n");
1407 IDEBeginControllerReset(ControllerExtension);
1408
1409 return TRUE;
1410 }
1411 #endif
1412 }
1413
1414 /* Indicate expecting an interrupt. */
1415 DeviceExtension->ExpectingInterrupt = TRUE;
1416
1417 /* Setup command parameters */
1418 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1419 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
1420 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
1421 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
1422 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
1423 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1424
1425 /* Issue command to drive */
1426 IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
1427 // ControllerExtension->TimerState = IDETimerCmdWait;
1428 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1429
1430
1431
1432 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN == 0)
1433 {
1434 DPRINT1("Write not implemented yet!\n");
1435 }
1436
1437 DPRINT1("AtapiReadWrite() done!\n");
1438
1439 /* Wait for interrupt. */
1440 return(SRB_STATUS_PENDING);
1441 }
1442
1443 /* EOF */