Added ISA-Bus initialization by Hartmut Birr.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: atapi.c,v 1.13 2002/03/16 16:13:57 ekohl Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS ATAPI miniport driver
23 * FILE: services/storage/atapi/atapi.c
24 * PURPOSE: ATAPI miniport driver
25 * PROGRAMMERS: Eric Kohl (ekohl@rz-online.de)
26 * REVISIONS:
27 * 09-09-2001 Created
28 */
29
30 /*
31 * Note:
32 * This driver is derived from Rex Jolliff's ide driver. Lots of his
33 * routines are still in here although they belong into the higher level
34 * drivers. They will be moved away as soon as possible.
35 */
36
37 /*
38 * TODO:
39 * - implement sending of atapi commands
40 * - handle removable atapi non-cdrom drives
41 */
42
43 #define ENABLE_PCI
44 #define ENABLE_ISA
45
46 // -------------------------------------------------------------------------
47
48 #include <ddk/ntddk.h>
49
50 #include "../include/srb.h"
51 #include "../include/scsi.h"
52 #include "../include/ntddscsi.h"
53
54 #include "atapi.h"
55
56 #define NDEBUG
57 #include <debug.h>
58
59 #define VERSION "0.0.1"
60
61
62 // ------------------------------------------------------- File Static Data
63
64 // ATAPI_MINIPORT_EXTENSION
65 //
66 // DESCRIPTION:
67 // Extension to be placed in each port device object
68 //
69 // ACCESS:
70 // Allocated from NON-PAGED POOL
71 // Available at any IRQL
72 //
73
74 typedef struct _ATAPI_MINIPORT_EXTENSION
75 {
76 IDE_DRIVE_IDENTIFY DeviceParams[2];
77 BOOLEAN DevicePresent[2];
78 BOOLEAN DeviceAtapi[2];
79
80 ULONG CommandPortBase;
81 ULONG ControlPortBase;
82
83 BOOLEAN ExpectingInterrupt;
84 PSCSI_REQUEST_BLOCK CurrentSrb;
85
86 PUSHORT DataBuffer;
87 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
88
89
90 typedef struct _UNIT_EXTENSION
91 {
92 ULONG Dummy;
93 } UNIT_EXTENSION, *PUNIT_EXTENSION;
94
95
96 // ----------------------------------------------- Discardable Declarations
97
98 #ifdef ALLOC_PRAGMA
99
100 // make the initialization routines discardable, so that they
101 // don't waste space
102
103 #pragma alloc_text(init, DriverEntry)
104 #pragma alloc_text(init, IDECreateController)
105 #pragma alloc_text(init, IDEPolledRead)
106
107 // make the PASSIVE_LEVEL routines pageable, so that they don't
108 // waste nonpaged memory
109
110 #pragma alloc_text(page, IDEShutdown)
111 #pragma alloc_text(page, IDEDispatchOpenClose)
112 #pragma alloc_text(page, IDEDispatchRead)
113 #pragma alloc_text(page, IDEDispatchWrite)
114
115 #endif /* ALLOC_PRAGMA */
116
117 // ---------------------------------------------------- Forward Declarations
118
119 static ULONG STDCALL
120 AtapiFindCompatiblePciController(PVOID DeviceExtension,
121 PVOID HwContext,
122 PVOID BusInformation,
123 PCHAR ArgumentString,
124 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
125 PBOOLEAN Again);
126
127 static ULONG STDCALL
128 AtapiFindIsaBusController(PVOID DeviceExtension,
129 PVOID HwContext,
130 PVOID BusInformation,
131 PCHAR ArgumentString,
132 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
133 PBOOLEAN Again);
134
135 static ULONG STDCALL
136 AtapiFindNativePciController(PVOID DeviceExtension,
137 PVOID HwContext,
138 PVOID BusInformation,
139 PCHAR ArgumentString,
140 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
141 PBOOLEAN Again);
142
143 static BOOLEAN STDCALL
144 AtapiInitialize(IN PVOID DeviceExtension);
145
146 static BOOLEAN STDCALL
147 AtapiResetBus(IN PVOID DeviceExtension,
148 IN ULONG PathId);
149
150 static BOOLEAN STDCALL
151 AtapiStartIo(IN PVOID DeviceExtension,
152 IN PSCSI_REQUEST_BLOCK Srb);
153
154 static BOOLEAN STDCALL
155 AtapiInterrupt(IN PVOID DeviceExtension);
156
157 static BOOLEAN
158 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
159 PPORT_CONFIGURATION_INFORMATION ConfigInfo);
160
161 static BOOLEAN
162 AtapiIdentifyDevice(IN ULONG CommandPort,
163 IN ULONG ControlPort,
164 IN ULONG DriveNum,
165 IN BOOLEAN Atapi,
166 OUT PIDE_DRIVE_IDENTIFY DrvParms);
167
168 static BOOLEAN
169 IDEResetController(IN ULONG CommandPort,
170 IN ULONG ControlPort);
171
172 static int
173 AtapiPolledRead(IN ULONG CommandPort,
174 IN ULONG ControlPort,
175 IN BYTE PreComp,
176 IN BYTE SectorCnt,
177 IN BYTE SectorNum,
178 IN BYTE CylinderLow,
179 IN BYTE CylinderHigh,
180 IN BYTE DrvHead,
181 IN BYTE Command,
182 OUT BYTE *Buffer);
183
184
185
186 static ULONG
187 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
188 IN PSCSI_REQUEST_BLOCK Srb);
189
190 static ULONG
191 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
192 IN PSCSI_REQUEST_BLOCK Srb);
193
194 static ULONG
195 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
196 IN PSCSI_REQUEST_BLOCK Srb);
197
198 static ULONG
199 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
200 IN PSCSI_REQUEST_BLOCK Srb);
201
202 static ULONG
203 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
204 IN PSCSI_REQUEST_BLOCK Srb);
205
206 // ---------------------------------------------------------------- Inlines
207
208 void
209 IDESwapBytePairs(char *Buf,
210 int Cnt)
211 {
212 char t;
213 int i;
214
215 for (i = 0; i < Cnt; i += 2)
216 {
217 t = Buf[i];
218 Buf[i] = Buf[i+1];
219 Buf[i+1] = t;
220 }
221 }
222
223
224 // ------------------------------------------------------- Public Interface
225
226 // DriverEntry
227 //
228 // DESCRIPTION:
229 // This function initializes the driver, locates and claims
230 // hardware resources, and creates various NT objects needed
231 // to process I/O requests.
232 //
233 // RUN LEVEL:
234 // PASSIVE_LEVEL
235 //
236 // ARGUMENTS:
237 // IN PDRIVER_OBJECT DriverObject System allocated Driver Object
238 // for this driver
239 // IN PUNICODE_STRING RegistryPath Name of registry driver service
240 // key
241 //
242 // RETURNS:
243 // NTSTATUS
244
245 STDCALL NTSTATUS
246 DriverEntry(IN PDRIVER_OBJECT DriverObject,
247 IN PUNICODE_STRING RegistryPath)
248 {
249 HW_INITIALIZATION_DATA InitData;
250 NTSTATUS Status;
251
252 DbgPrint("ATAPI Driver %s\n", VERSION);
253
254 /* Initialize data structure */
255 RtlZeroMemory(&InitData,
256 sizeof(HW_INITIALIZATION_DATA));
257 InitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
258 InitData.HwInitialize = AtapiInitialize;
259 InitData.HwResetBus = AtapiResetBus;
260 InitData.HwStartIo = AtapiStartIo;
261 InitData.HwInterrupt = AtapiInterrupt;
262
263 InitData.DeviceExtensionSize = sizeof(ATAPI_MINIPORT_EXTENSION);
264 InitData.SpecificLuExtensionSize = sizeof(UNIT_EXTENSION);
265
266 InitData.MapBuffers = TRUE;
267
268 /* Search the PCI bus for compatibility mode ide controllers */
269 #ifdef ENABLE_PCI
270 InitData.HwFindAdapter = AtapiFindCompatiblePciController;
271 InitData.NumberOfAccessRanges = 2;
272 InitData.AdapterInterfaceType = PCIBus;
273
274 InitData.VendorId = NULL;
275 InitData.VendorIdLength = 0;
276 InitData.DeviceId = NULL;
277 InitData.DeviceIdLength = 0;
278
279 Status = ScsiPortInitialize(DriverObject,
280 RegistryPath,
281 &InitData,
282 NULL);
283 // if (newStatus < statusToReturn)
284 // statusToReturn = newStatus;
285 #endif
286
287 /* Search the ISA bus for ide controllers */
288 #ifdef ENABLE_ISA
289 InitData.HwFindAdapter = AtapiFindIsaBusController;
290 InitData.NumberOfAccessRanges = 2;
291 InitData.AdapterInterfaceType = Isa;
292
293 InitData.VendorId = NULL;
294 InitData.VendorIdLength = 0;
295 InitData.DeviceId = NULL;
296 InitData.DeviceIdLength = 0;
297
298 Status = ScsiPortInitialize(DriverObject,
299 RegistryPath,
300 &InitData,
301 NULL);
302 // if (newStatus < statusToReturn)
303 // statusToReturn = newStatus;
304 #endif
305
306 /* Search the PCI bus for native mode ide controllers */
307 #if 0
308 InitData.HwFindAdapter = AtapiFindNativePciController;
309 InitData.NumberOfAccessRanges = 2;
310 InitData.AdapterInterfaceType = PCIBus;
311
312 InitData.VendorId = NULL;
313 InitData.VendorIdLength = 0;
314 InitData.DeviceId = NULL;
315 InitData.DeviceIdLength = 0;
316
317 Status = ScsiPortInitialize(DriverObject,
318 RegistryPath,
319 &InitData,
320 (PVOID)i);
321 // if (newStatus < statusToReturn)
322 // statusToReturn = newStatus;
323 #endif
324
325 DPRINT( "Returning from DriverEntry\n" );
326
327 return(Status);
328 }
329
330
331 static ULONG STDCALL
332 AtapiFindCompatiblePciController(PVOID DeviceExtension,
333 PVOID HwContext,
334 PVOID BusInformation,
335 PCHAR ArgumentString,
336 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
337 PBOOLEAN Again)
338 {
339 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
340 PCI_SLOT_NUMBER SlotNumber;
341 PCI_COMMON_CONFIG PciConfig;
342 ULONG DataSize;
343 ULONG FunctionNumber;
344 BOOLEAN ChannelFound;
345 BOOLEAN DeviceFound;
346
347 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
348 ConfigInfo->SystemIoBusNumber,
349 ConfigInfo->SlotNumber);
350
351 *Again = FALSE;
352
353 /* both channels were claimed: exit */
354 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
355 ConfigInfo->AtdiskSecondaryClaimed == TRUE)
356 return(SP_RETURN_NOT_FOUND);
357
358
359 SlotNumber.u.AsULONG = 0;
360 for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
361 {
362 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
363 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
364 SlotNumber.u.AsULONG = FunctionNumber;
365
366 ChannelFound = FALSE;
367 DeviceFound = FALSE;
368
369 DataSize = ScsiPortGetBusData(DeviceExtension,
370 PCIConfiguration,
371 0,
372 SlotNumber.u.AsULONG,
373 &PciConfig,
374 sizeof(PCI_COMMON_CONFIG));
375 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
376 // PciConfig.VendorID == PCI_INVALID_VENDORID)
377 if (DataSize == 0)
378 {
379 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
380 // return(SP_RETURN_ERROR); /* No bus found */
381
382 continue;
383 // return(SP_RETURN_ERROR);
384 }
385
386 if (PciConfig.BaseClass == 0x01 &&
387 PciConfig.SubClass == 0x01) // &&
388 // (PciConfig.ProgIf & 0x05) == 0)
389 {
390 /* both channels are in compatibility mode */
391 DPRINT("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
392 ConfigInfo->SystemIoBusNumber,
393 SlotNumber.u.bits.DeviceNumber,
394 SlotNumber.u.bits.FunctionNumber,
395 PciConfig.VendorID,
396 PciConfig.DeviceID);
397 DPRINT("ProgIF 0x%02hx\n", PciConfig.ProgIf);
398
399 DPRINT("Found IDE controller in compatibility mode!\n");
400
401 ConfigInfo->NumberOfBuses = 1;
402 ConfigInfo->MaximumNumberOfTargets = 2;
403 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
404
405 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
406 {
407 /* Both channels unclaimed: Claim primary channel */
408 DPRINT("Primary channel!\n");
409
410 DevExt->CommandPortBase = 0x01F0;
411 DevExt->ControlPortBase = 0x03F6;
412
413 ConfigInfo->BusInterruptLevel = 14;
414 ConfigInfo->BusInterruptVector = 14;
415 ConfigInfo->InterruptMode = LevelSensitive;
416
417 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
418 ConfigInfo->AccessRanges[0].RangeLength = 8;
419 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
420
421 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
422 ConfigInfo->AccessRanges[1].RangeLength = 1;
423 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
424
425 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
426 ChannelFound = TRUE;
427 *Again = TRUE;
428 }
429 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
430 {
431 /* Primary channel already claimed: claim secondary channel */
432 DPRINT("Secondary channel!\n");
433
434 DevExt->CommandPortBase = 0x0170;
435 DevExt->ControlPortBase = 0x0376;
436
437 ConfigInfo->BusInterruptLevel = 15;
438 ConfigInfo->BusInterruptVector = 15;
439 ConfigInfo->InterruptMode = LevelSensitive;
440
441 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
442 ConfigInfo->AccessRanges[0].RangeLength = 8;
443 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
444
445 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
446 ConfigInfo->AccessRanges[1].RangeLength = 1;
447 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
448
449 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
450 ChannelFound = TRUE;
451 *Again = FALSE;
452 }
453
454 /* Find attached devices */
455 if (ChannelFound == TRUE)
456 {
457 DeviceFound = AtapiFindDevices(DevExt,
458 ConfigInfo);
459 }
460 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_FOUND\n");
461 return(SP_RETURN_FOUND);
462 }
463 }
464
465 DPRINT("AtapiFindCompatiblePciController() returns: SP_RETURN_NOT_FOUND\n");
466
467 return(SP_RETURN_NOT_FOUND);
468 }
469
470
471 static ULONG STDCALL
472 AtapiFindIsaBusController(PVOID DeviceExtension,
473 PVOID HwContext,
474 PVOID BusInformation,
475 PCHAR ArgumentString,
476 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
477 PBOOLEAN Again)
478 {
479 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
480 BOOLEAN ChannelFound = FALSE;
481 BOOLEAN DeviceFound = FALSE;
482
483 DPRINT1("AtapiFindIsaBusController() called!\n");
484
485 *Again = FALSE;
486
487 ConfigInfo->NumberOfBuses = 1;
488 ConfigInfo->MaximumNumberOfTargets = 2;
489 ConfigInfo->MaximumTransferLength = 0x10000; /* max 64Kbyte */
490
491 if (ConfigInfo->AtdiskPrimaryClaimed == FALSE)
492 {
493 /* Both channels unclaimed: Claim primary channel */
494 DPRINT1("Primary channel!\n");
495
496 DevExt->CommandPortBase = 0x01F0;
497 DevExt->ControlPortBase = 0x03F6;
498
499 ConfigInfo->BusInterruptLevel = 14;
500 ConfigInfo->BusInterruptVector = 14;
501 ConfigInfo->InterruptMode = LevelSensitive;
502
503 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x01F0);
504 ConfigInfo->AccessRanges[0].RangeLength = 8;
505 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
506
507 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x03F6);
508 ConfigInfo->AccessRanges[1].RangeLength = 1;
509 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
510
511 ConfigInfo->AtdiskPrimaryClaimed = TRUE;
512 ChannelFound = TRUE;
513 *Again = FALSE/*TRUE*/;
514 }
515 else if (ConfigInfo->AtdiskSecondaryClaimed == FALSE)
516 {
517 /* Primary channel already claimed: claim secondary channel */
518 DPRINT1("Secondary channel!\n");
519
520 DevExt->CommandPortBase = 0x0170;
521 DevExt->ControlPortBase = 0x0376;
522
523 ConfigInfo->BusInterruptLevel = 15;
524 ConfigInfo->BusInterruptVector = 15;
525 ConfigInfo->InterruptMode = LevelSensitive;
526
527 ConfigInfo->AccessRanges[0].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0170);
528 ConfigInfo->AccessRanges[0].RangeLength = 8;
529 ConfigInfo->AccessRanges[0].RangeInMemory = FALSE;
530
531 ConfigInfo->AccessRanges[1].RangeStart = ScsiPortConvertUlongToPhysicalAddress(0x0376);
532 ConfigInfo->AccessRanges[1].RangeLength = 1;
533 ConfigInfo->AccessRanges[1].RangeInMemory = FALSE;
534
535 ConfigInfo->AtdiskSecondaryClaimed = TRUE;
536 ChannelFound = TRUE;
537 *Again = FALSE;
538 }
539 else
540 {
541 DPRINT1("AtapiFindIsaBusController() both channels claimed. Returns: SP_RETURN_NOT_FOUND\n");
542 *Again = FALSE;
543 return(SP_RETURN_NOT_FOUND);
544 }
545
546 /* Find attached devices */
547 if (ChannelFound)
548 {
549 DeviceFound = AtapiFindDevices(DevExt,
550 ConfigInfo);
551 }
552
553 DPRINT1("AtapiFindIsaBusController() returns: SP_RETURN_FOUND\n");
554 return(SP_RETURN_FOUND);
555 }
556
557
558 static ULONG STDCALL
559 AtapiFindNativePciController(PVOID DeviceExtension,
560 PVOID HwContext,
561 PVOID BusInformation,
562 PCHAR ArgumentString,
563 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
564 PBOOLEAN Again)
565 {
566 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
567
568 DPRINT("AtapiFindNativePciController() called!\n");
569
570 *Again = FALSE;
571
572 DPRINT("AtapiFindNativePciController() done!\n");
573
574 return(SP_RETURN_NOT_FOUND);
575 }
576
577
578 static BOOLEAN STDCALL
579 AtapiInitialize(IN PVOID DeviceExtension)
580 {
581 return(TRUE);
582 }
583
584
585 static BOOLEAN STDCALL
586 AtapiResetBus(IN PVOID DeviceExtension,
587 IN ULONG PathId)
588 {
589 return(TRUE);
590 }
591
592
593 static BOOLEAN STDCALL
594 AtapiStartIo(IN PVOID DeviceExtension,
595 IN PSCSI_REQUEST_BLOCK Srb)
596 {
597 PATAPI_MINIPORT_EXTENSION DevExt;
598 ULONG Result;
599
600 DPRINT("AtapiStartIo() called\n");
601
602 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
603
604 switch (Srb->Function)
605 {
606 case SRB_FUNCTION_EXECUTE_SCSI:
607 DevExt->CurrentSrb = Srb;
608 if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
609 {
610 Result = AtapiSendAtapiCommand(DevExt,
611 Srb);
612 }
613 else
614 {
615 Result = AtapiSendIdeCommand(DevExt,
616 Srb);
617 }
618 break;
619
620 }
621
622 Srb->SrbStatus = Result;
623
624
625 if (Result != SRB_STATUS_PENDING)
626 {
627 DevExt->CurrentSrb = NULL;
628 Srb->SrbStatus = (UCHAR)Result;
629
630 ScsiPortNotification(RequestComplete,
631 DeviceExtension,
632 Srb);
633 ScsiPortNotification(NextRequest,
634 DeviceExtension,
635 NULL);
636 }
637 else
638 {
639 DPRINT("SrbStatus = SRB_STATUS_PENDING\n");
640 }
641
642 DPRINT("AtapiStartIo() done\n");
643
644 return(TRUE);
645 }
646
647
648 static BOOLEAN STDCALL
649 AtapiInterrupt(IN PVOID DeviceExtension)
650 {
651 PATAPI_MINIPORT_EXTENSION DevExt;
652 PSCSI_REQUEST_BLOCK Srb;
653 ULONG CommandPortBase;
654 ULONG ControlPortBase;
655
656 UCHAR DeviceStatus;
657 BOOLEAN IsLastBlock;
658 ULONG Retries;
659 NTSTATUS ErrorStatus;
660 ULONG ErrorInformation;
661 PUCHAR TargetAddress;
662 ULONG SectorSize;
663
664
665 DPRINT("AtapiInterrupt() called!\n");
666
667 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
668 if (DevExt->ExpectingInterrupt == FALSE)
669 {
670 return(FALSE);
671 }
672
673 Srb = DevExt->CurrentSrb;
674
675 DPRINT("Srb: %p\n", Srb);
676
677 CommandPortBase = DevExt->CommandPortBase;
678 ControlPortBase = DevExt->ControlPortBase;
679
680 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
681
682 IsLastBlock = FALSE;
683 ErrorStatus = STATUS_SUCCESS;
684 ErrorInformation = 0;
685
686 DeviceStatus = IDEReadStatus(CommandPortBase);
687
688 /* Handle error condition if it exists */
689 if (DeviceStatus & IDE_SR_ERR)
690 {
691 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
692 BYTE DriveHead;
693
694 /* Log the error */
695 ErrorReg = IDEReadError(CommandPortBase);
696 CylinderLow = IDEReadCylinderLow(CommandPortBase);
697 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
698 DriveHead = IDEReadDriveHead(CommandPortBase);
699 SectorCount = IDEReadSectorCount(CommandPortBase);
700 SectorNum = IDEReadSectorNum(CommandPortBase);
701
702 /* FIXME: should use the NT error logging facility */
703 DbgPrint("ATAPI Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
704 0, //DeviceExtension->Operation,
705 DeviceStatus,
706 ErrorReg,
707 CylinderLow,
708 CylinderHigh,
709 SectorCount,
710 SectorNum);
711
712 /* FIXME: should retry the command and perhaps recalibrate the drive */
713
714 // Set error status information
715 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
716 #if 0
717 ErrorInformation =
718 (((((((CylinderHigh << 8) + CylinderLow) *
719 DeviceExtension->LogicalHeads) +
720 (DriveHead % DeviceExtension->LogicalHeads)) *
721 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
722 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
723 #endif
724 }
725 else
726 {
727 switch (Srb->Cdb[0])
728 {
729 case SCSIOP_READ:
730 DPRINT("SCSIOP_READ\n");
731
732 /* Update controller/device state variables */
733 SectorSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
734 TargetAddress = Srb->DataBuffer;
735 Srb->DataBuffer += SectorSize;
736 Srb->DataTransferLength -= SectorSize;
737
738 /* Remember whether DRQ should be low at end (last block read) */
739 IsLastBlock = (Srb->DataTransferLength == 0);
740 DPRINT("IsLastBlock == %s\n", (IsLastBlock)?"TRUE":"FALSE");
741
742 /* Wait for DRQ assertion */
743 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
744 !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
745 Retries++)
746 {
747 KeStallExecutionProcessor(10);
748 }
749
750 /* Copy the block of data */
751 IDEReadBlock(CommandPortBase,
752 TargetAddress,
753 SectorSize);
754
755 /* check DRQ */
756 if (IsLastBlock)
757 {
758 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
759 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
760 Retries++)
761 {
762 KeStallExecutionProcessor(10);
763 }
764
765 /* Check for data overrun */
766 if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
767 {
768 /* FIXME: Handle error! */
769 }
770 }
771 break;
772
773 case SCSIOP_WRITE:
774 DPRINT("SCSIOP_WRITE\n");
775 if (Srb->DataTransferLength == 0)
776 {
777
778 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
779 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
780 Retries++)
781 {
782 KeStallExecutionProcessor(10);
783 }
784
785 /* Check for data overrun */
786 if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
787 {
788 /* FIXME: Handle error! */
789 }
790
791 DevExt->ExpectingInterrupt = FALSE;
792 IsLastBlock = TRUE;
793 }
794 else
795 {
796 /* Update SRB data */
797 SectorSize = DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
798
799 TargetAddress = Srb->DataBuffer;
800 Srb->DataBuffer += SectorSize;
801 Srb->DataTransferLength -= SectorSize;
802
803 /* Write the sector */
804 IDEWriteBlock(CommandPortBase,
805 TargetAddress,
806 SectorSize);
807 }
808 break;
809 }
810 }
811
812 /* complete this packet */
813 if (IsLastBlock)
814 {
815 DevExt->ExpectingInterrupt = FALSE;
816
817 ScsiPortNotification(RequestComplete,
818 DeviceExtension,
819 Srb);
820
821 ScsiPortNotification(NextRequest,
822 DeviceExtension,
823 NULL);
824 }
825
826 DPRINT("AtapiInterrupt() done!\n");
827
828 return(TRUE);
829 }
830
831
832
833
834
835
836 // ---------------------------------------------------- Discardable statics
837
838
839 /**********************************************************************
840 * NAME INTERNAL
841 * AtapiFindDevices
842 *
843 * DESCRIPTION
844 * Searches for devices on the given port.
845 *
846 * RUN LEVEL
847 * PASSIVE_LEVEL
848 *
849 * ARGUMENTS
850 * DeviceExtension
851 * Port device specific information.
852 *
853 * ConfigInfo
854 * Port configuration information.
855 *
856 * RETURN VALUE
857 * TRUE: At least one device is attached to the port.
858 * FALSE: No device is attached to the port.
859 */
860
861 static BOOLEAN
862 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
863 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
864 {
865 BOOLEAN DeviceFound = FALSE;
866 ULONG CommandPortBase;
867 ULONG ControlPortBase;
868 ULONG UnitNumber;
869 ULONG Retries;
870 BYTE High, Low;
871
872 DPRINT("AtapiFindDevices() called\n");
873
874 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
875 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
876 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
877
878 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
879 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
880 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
881
882 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
883 {
884 /* Select drive */
885 IDEWriteDriveHead(CommandPortBase,
886 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
887 ScsiPortStallExecution(500);
888
889 /* Disable interrupts */
890 IDEWriteDriveControl(ControlPortBase,
891 IDE_DC_nIEN);
892 ScsiPortStallExecution(500);
893
894 IDEWriteCylinderHigh(CommandPortBase, 0);
895 IDEWriteCylinderLow(CommandPortBase, 0);
896 IDEWriteCommand(CommandPortBase, IDE_CMD_RESET);
897
898 for (Retries = 0; Retries < 20000; Retries++)
899 {
900 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
901 {
902 break;
903 }
904 ScsiPortStallExecution(150);
905 }
906 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
907 {
908 DbgPrint("Timeout on drive %lu\n", UnitNumber);
909 return(DeviceFound);
910 }
911
912 High = IDEReadCylinderHigh(CommandPortBase);
913 Low = IDEReadCylinderLow(CommandPortBase);
914
915 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
916 UnitNumber,
917 High,
918 Low);
919
920 if (High == 0xEB && Low == 0x14)
921 {
922 if (AtapiIdentifyDevice(CommandPortBase,
923 ControlPortBase,
924 UnitNumber,
925 TRUE,
926 &DeviceExtension->DeviceParams[UnitNumber]))
927 {
928 DPRINT(" ATAPI drive found!\n");
929 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
930 DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
931 DeviceFound = TRUE;
932 }
933 else
934 {
935 DPRINT(" No ATAPI drive found!\n");
936 }
937 }
938 else
939 {
940 if (AtapiIdentifyDevice(CommandPortBase,
941 ControlPortBase,
942 UnitNumber,
943 FALSE,
944 &DeviceExtension->DeviceParams[UnitNumber]))
945 {
946 DPRINT(" IDE drive found!\n");
947 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
948 DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
949 DeviceFound = TRUE;
950 }
951 else
952 {
953 DPRINT(" No IDE drive found!\n");
954 }
955 }
956 }
957
958 DPRINT("AtapiFindDrives() done\n");
959
960 return(DeviceFound);
961 }
962
963
964 // AtapiResetController
965 //
966 // DESCRIPTION:
967 // Reset the controller and report completion status
968 //
969 // RUN LEVEL:
970 // PASSIVE_LEVEL
971 //
972 // ARGUMENTS:
973 // IN WORD CommandPort The address of the command port
974 // IN WORD ControlPort The address of the control port
975 //
976 // RETURNS:
977 //
978
979 static BOOLEAN
980 AtapiResetController(IN ULONG CommandPort,
981 IN ULONG ControlPort)
982 {
983 int Retries;
984
985 /* Assert drive reset line */
986 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
987
988 /* Wait for min. 25 microseconds */
989 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
990
991 /* Negate drive reset line */
992 IDEWriteDriveControl(ControlPort, 0);
993
994 /* Wait for BUSY negation */
995 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
996 {
997 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
998 {
999 break;
1000 }
1001 ScsiPortStallExecution(10);
1002 }
1003
1004 CHECKPOINT;
1005 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
1006 {
1007 return(FALSE);
1008 }
1009
1010 CHECKPOINT;
1011
1012 // return TRUE if controller came back to life. and
1013 // the registers are initialized correctly
1014 return(IDEReadError(CommandPort) == 1);
1015 }
1016
1017 /*
1018 * AtapiIdentifyDevice
1019 *
1020 * DESCRIPTION:
1021 * Get the identification block from the drive
1022 *
1023 * RUN LEVEL:
1024 * PASSIVE_LEVEL
1025 *
1026 * ARGUMENTS:
1027 * CommandPort
1028 * Address of the command port
1029 * ControlPort
1030 * Address of the control port
1031 * DriveNum
1032 * The drive index (0,1)
1033 * Atapi
1034 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
1035 * DrvParms
1036 * Address to write drive ident block
1037 *
1038 * RETURNS:
1039 * TRUE: The drive identification block was retrieved successfully
1040 * FALSE: an error ocurred
1041 */
1042
1043 static BOOLEAN
1044 AtapiIdentifyDevice(IN ULONG CommandPort,
1045 IN ULONG ControlPort,
1046 IN ULONG DriveNum,
1047 IN BOOLEAN Atapi,
1048 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1049 {
1050 /* Get the Drive Identify block from drive or die */
1051 if (AtapiPolledRead(CommandPort,
1052 ControlPort,
1053 0,
1054 1,
1055 0,
1056 0,
1057 0,
1058 (DriveNum ? IDE_DH_DRV1 : 0),
1059 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1060 (BYTE *)DrvParms) != 0)
1061 {
1062 DPRINT1("IDEPolledRead() failed\n");
1063 return FALSE;
1064 }
1065
1066 /* Report on drive parameters if debug mode */
1067 IDESwapBytePairs(DrvParms->SerialNumber, 20);
1068 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1069 IDESwapBytePairs(DrvParms->ModelNumber, 40);
1070 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1071 DrvParms->ConfigBits,
1072 DrvParms->LogicalCyls,
1073 DrvParms->LogicalHeads,
1074 DrvParms->SectorsPerTrack,
1075 DrvParms->InterSectorGap,
1076 DrvParms->InterSectorGapSize);
1077 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1078 DrvParms->BytesInPLO,
1079 DrvParms->VendorUniqueCnt,
1080 DrvParms->SerialNumber);
1081 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1082 DrvParms->ControllerType,
1083 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1084 DrvParms->ECCByteCnt,
1085 DrvParms->FirmwareRev);
1086 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1087 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1088 (DrvParms->RWMultImplemented) & 0xff,
1089 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1090 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1091 DrvParms->MinPIOTransTime,
1092 DrvParms->MinDMATransTime);
1093 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1094 DrvParms->TMCylinders,
1095 DrvParms->TMHeads,
1096 DrvParms->TMSectorsPerTrk,
1097 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1098 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1099 DrvParms->TMSectorCountHi,
1100 DrvParms->TMSectorCountLo,
1101 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1102
1103 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1104 if (DrvParms->BytesPerSector == 0)
1105 DrvParms->BytesPerSector = 512;
1106 return TRUE;
1107 }
1108
1109
1110 // AtapiPolledRead
1111 //
1112 // DESCRIPTION:
1113 // Read a sector of data from the drive in a polled fashion.
1114 //
1115 // RUN LEVEL:
1116 // PASSIVE_LEVEL
1117 //
1118 // ARGUMENTS:
1119 // IN WORD Address Address of command port for drive
1120 // IN BYTE PreComp Value to write to precomp register
1121 // IN BYTE SectorCnt Value to write to sectorCnt register
1122 // IN BYTE SectorNum Value to write to sectorNum register
1123 // IN BYTE CylinderLow Value to write to CylinderLow register
1124 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1125 // IN BYTE DrvHead Value to write to Drive/Head register
1126 // IN BYTE Command Value to write to Command register
1127 // OUT BYTE *Buffer Buffer for output data
1128 //
1129 // RETURNS:
1130 // int 0 is success, non 0 is an error code
1131 //
1132
1133 static int
1134 AtapiPolledRead(IN ULONG CommandPort,
1135 IN ULONG ControlPort,
1136 IN BYTE PreComp,
1137 IN BYTE SectorCnt,
1138 IN BYTE SectorNum,
1139 IN BYTE CylinderLow,
1140 IN BYTE CylinderHigh,
1141 IN BYTE DrvHead,
1142 IN BYTE Command,
1143 OUT BYTE *Buffer)
1144 {
1145 ULONG SectorCount = 0;
1146 ULONG RetryCount;
1147 BOOLEAN Junk = FALSE;
1148 UCHAR Status;
1149 UCHAR Control;
1150
1151 /* Write Drive/Head to select drive */
1152 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1153 ScsiPortStallExecution(500);
1154
1155 /* Disable interrupts */
1156 Control = IDEReadAltStatus(ControlPort);
1157 IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
1158 ScsiPortStallExecution(500);
1159
1160 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1161 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1162 {
1163 Status = IDEReadStatus(CommandPort);
1164 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1165 {
1166 break;
1167 }
1168 ScsiPortStallExecution(10);
1169 }
1170 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1171 {
1172 return(IDE_ER_ABRT);
1173 }
1174
1175 /* Write Drive/Head to select drive */
1176 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1177
1178 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1179 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1180 {
1181 Status = IDEReadStatus(CommandPort);
1182 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1183 {
1184 break;
1185 }
1186 ScsiPortStallExecution(10);
1187 }
1188 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1189 {
1190 return IDE_ER_ABRT;
1191 }
1192
1193 /* Issue command to drive */
1194 if (DrvHead & IDE_DH_LBA)
1195 {
1196 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1197 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1198 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1199 SectorCnt,
1200 Command);
1201 }
1202 else
1203 {
1204 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1205 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1206 CylinderHigh,
1207 CylinderLow,
1208 DrvHead & 0x0f,
1209 SectorNum,
1210 SectorCnt,
1211 Command);
1212 }
1213
1214 /* Setup command parameters */
1215 IDEWritePrecomp(CommandPort, PreComp);
1216 IDEWriteSectorCount(CommandPort, SectorCnt);
1217 IDEWriteSectorNum(CommandPort, SectorNum);
1218 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
1219 IDEWriteCylinderLow(CommandPort, CylinderLow);
1220 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
1221
1222 /* Issue the command */
1223 IDEWriteCommand(CommandPort, Command);
1224 ScsiPortStallExecution(50);
1225
1226 /* wait for DRQ or error */
1227 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1228 {
1229 Status = IDEReadStatus(CommandPort);
1230 if (!(Status & IDE_SR_BUSY))
1231 {
1232 if (Status & IDE_SR_ERR)
1233 {
1234 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1235 return(IDE_ER_ABRT);
1236 }
1237 if (Status & IDE_SR_DRQ)
1238 {
1239 break;
1240 }
1241 else
1242 {
1243 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1244 return(IDE_ER_ABRT);
1245 }
1246 }
1247 ScsiPortStallExecution(10);
1248 }
1249
1250 /* timed out */
1251 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1252 {
1253 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1254 return(IDE_ER_ABRT);
1255 }
1256
1257 while (1)
1258 {
1259 /* Read data into buffer */
1260 if (Junk == FALSE)
1261 {
1262 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
1263 Buffer += IDE_SECTOR_BUF_SZ;
1264 }
1265 else
1266 {
1267 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1268 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
1269 }
1270 SectorCount++;
1271
1272 /* Check for error or more sectors to read */
1273 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1274 {
1275 Status = IDEReadStatus(CommandPort);
1276 if (!(Status & IDE_SR_BUSY))
1277 {
1278 if (Status & IDE_SR_ERR)
1279 {
1280 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1281 return(IDE_ER_ABRT);
1282 }
1283 if (Status & IDE_SR_DRQ)
1284 {
1285 if (SectorCount >= SectorCnt)
1286 {
1287 DPRINT("Buffer size exceeded!\n");
1288 Junk = TRUE;
1289 }
1290 break;
1291 }
1292 else
1293 {
1294 if (SectorCount > SectorCnt)
1295 {
1296 DPRINT("Read %lu sectors of junk!\n",
1297 SectorCount - SectorCnt);
1298 }
1299 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1300 return(0);
1301 }
1302 }
1303 }
1304 }
1305 }
1306
1307
1308 // ------------------------------------------- Nondiscardable statics
1309
1310 static ULONG
1311 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1312 IN PSCSI_REQUEST_BLOCK Srb)
1313 {
1314 #if 0
1315 // PIDE_DRIVE_IDENTIFY DeviceParams;
1316
1317 // ULONG StartingSector,i;
1318 // ULONG SectorCount;
1319 UCHAR ByteCountHigh;
1320 UCHAR ByteCountLow;
1321 // UCHAR DrvHead;
1322 // UCHAR SectorNumber;
1323 // UCHAR Command;
1324 ULONG Retries;
1325 UCHAR Status;
1326
1327 DPRINT1("AtapiSendAtapiCommand() called!\n");
1328
1329 if ((Srb->PathId != 0) ||
1330 (Srb->TargetId > 1) ||
1331 (Srb->Lun != 0) ||
1332 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1333 {
1334 return(SRB_STATUS_SELECTION_TIMEOUT);
1335 }
1336
1337 DPRINT1("AtapiSendAtapiCommand(): TargetId: %lu\n",
1338 Srb->TargetId);
1339
1340
1341 /* Set pointer to data buffer. */
1342 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1343
1344 DeviceExtension->CurrentSrb = Srb;
1345 DeviceExtension->ExpectingInterrupt = TRUE;
1346
1347
1348 /* wait for BUSY to clear */
1349 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1350 {
1351 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1352 if (!(Status & IDE_SR_BUSY))
1353 {
1354 break;
1355 }
1356 ScsiPortStallExecution(10);
1357 }
1358 DPRINT("status=%02x\n", Status);
1359 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1360 if (Retries >= IDE_MAX_BUSY_RETRIES)
1361 {
1362 DPRINT ("Drive is BUSY for too long\n");
1363 return(SRB_STATUS_BUSY);
1364 #if 0
1365 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1366 {
1367 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1368 Irp = ControllerExtension->CurrentIrp;
1369 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1370 Irp->IoStatus.Information = 0;
1371
1372 return FALSE;
1373 }
1374 else
1375 {
1376 DPRINT ("Beginning drive reset sequence\n");
1377 IDEBeginControllerReset(ControllerExtension);
1378
1379 return TRUE;
1380 }
1381 #endif
1382 }
1383
1384 /* Select the desired drive */
1385 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1386 IDE_DH_FIXED | (Srb->TargetId ? IDE_DH_DRV1 : 0));
1387
1388 /* wait for BUSY to clear and DRDY to assert */
1389 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1390 {
1391 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1392 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1393 {
1394 break;
1395 }
1396 ScsiPortStallExecution(10);
1397 }
1398 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1399 if (Retries >= IDE_MAX_BUSY_RETRIES)
1400 {
1401 DPRINT("Drive is BUSY for too long after drive select\n");
1402 return(SRB_STATUS_BUSY);
1403 #if 0
1404 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1405 {
1406 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1407 Irp = ControllerExtension->CurrentIrp;
1408 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1409 Irp->IoStatus.Information = 0;
1410
1411 return FALSE;
1412 }
1413 else
1414 {
1415 DPRINT("Beginning drive reset sequence\n");
1416 IDEBeginControllerReset(ControllerExtension);
1417
1418 return TRUE;
1419 }
1420 #endif
1421 }
1422
1423 ByteCountLow = (UCHAR)(Srb->DataTransferLength & 0xFF);
1424 ByteCountHigh = (UCHAR)(Srb->DataTransferLength >> 8);
1425
1426 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, ByteCountHigh);
1427 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, ByteCountLow);
1428 // IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1429
1430 /* Issue command to drive */
1431 IDEWriteCommand(DeviceExtension->CommandPortBase, 0xA0); /* Packet command */
1432
1433
1434 /* wait for DRQ to assert */
1435 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1436 {
1437 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1438 if ((Status & IDE_SR_DRQ))
1439 {
1440 break;
1441 }
1442 ScsiPortStallExecution(10);
1443 }
1444
1445 IDEWriteBlock(DeviceExtension->CommandPortBase,
1446 (PUSHORT)Srb->Cdb,
1447 12);
1448
1449
1450 DPRINT1("AtapiSendAtapiCommand() done\n");
1451 return(SRB_STATUS_PENDING);
1452 #endif
1453
1454 //#if 0
1455 ULONG SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
1456
1457 DPRINT("AtapiSendAtapiCommand() called!\n");
1458
1459 switch (Srb->Cdb[0])
1460 {
1461 case SCSIOP_INQUIRY:
1462 DPRINT(" SCSIOP_INQUIRY\n");
1463 SrbStatus = AtapiInquiry(DeviceExtension,
1464 Srb);
1465 break;
1466
1467 case SCSIOP_READ_CAPACITY:
1468 DPRINT1(" SCSIOP_READ_CAPACITY\n");
1469 break;
1470
1471 case SCSIOP_READ:
1472 DPRINT1(" SCSIOP_READ\n");
1473 break;
1474
1475 case SCSIOP_WRITE:
1476 DPRINT1(" SCSIOP_WRITE\n");
1477 break;
1478
1479 case SCSIOP_MODE_SENSE:
1480 DPRINT1(" SCSIOP_MODE_SENSE\n");
1481 break;
1482
1483 case SCSIOP_TEST_UNIT_READY:
1484 DPRINT1(" SCSIOP_TEST_UNIT_READY\n");
1485 break;
1486
1487 case SCSIOP_VERIFY:
1488 DPRINT1(" SCSIOP_VERIFY\n");
1489 break;
1490
1491 case SCSIOP_START_STOP_UNIT:
1492 DPRINT1(" SCSIOP_START_STOP_UNIT\n");
1493 break;
1494
1495 case SCSIOP_REQUEST_SENSE:
1496 DPRINT1(" SCSIOP_REQUEST_SENSE\n");
1497 break;
1498
1499 default:
1500 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1501 Srb->Cdb[0]);
1502 break;
1503 }
1504
1505 if (SrbStatus == SRB_STATUS_SELECTION_TIMEOUT)
1506 {
1507 DPRINT1("Not implemented yet!\n");
1508 }
1509
1510 return(SrbStatus);
1511 //#endif
1512 }
1513
1514
1515 static ULONG
1516 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1517 IN PSCSI_REQUEST_BLOCK Srb)
1518 {
1519 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1520
1521 DPRINT("AtapiSendIdeCommand() called!\n");
1522
1523 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1524 Srb->PathId,
1525 Srb->TargetId,
1526 Srb->Lun);
1527
1528 switch (Srb->Cdb[0])
1529 {
1530 case SCSIOP_INQUIRY:
1531 SrbStatus = AtapiInquiry(DeviceExtension,
1532 Srb);
1533 break;
1534
1535 case SCSIOP_READ_CAPACITY:
1536 SrbStatus = AtapiReadCapacity(DeviceExtension,
1537 Srb);
1538 break;
1539
1540 case SCSIOP_READ:
1541 case SCSIOP_WRITE:
1542 SrbStatus = AtapiReadWrite(DeviceExtension,
1543 Srb);
1544 break;
1545
1546 case SCSIOP_MODE_SENSE:
1547 case SCSIOP_TEST_UNIT_READY:
1548 case SCSIOP_VERIFY:
1549 case SCSIOP_START_STOP_UNIT:
1550 case SCSIOP_REQUEST_SENSE:
1551 break;
1552
1553 default:
1554 DbgPrint("AtapiSendIdeCommand():unknown command %x\n",
1555 Srb->Cdb[0]);
1556 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1557 break;
1558 }
1559
1560 DPRINT("AtapiSendIdeCommand() done!\n");
1561
1562 return(SrbStatus);
1563 }
1564
1565
1566 static ULONG
1567 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1568 PSCSI_REQUEST_BLOCK Srb)
1569 {
1570 PIDE_DRIVE_IDENTIFY DeviceParams;
1571 PINQUIRYDATA InquiryData;
1572 ULONG i;
1573
1574 DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb->TargetId);
1575
1576 if ((Srb->PathId != 0) ||
1577 (Srb->TargetId > 1) ||
1578 (Srb->Lun != 0) ||
1579 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1580 {
1581 return(SRB_STATUS_SELECTION_TIMEOUT);
1582 }
1583
1584 InquiryData = Srb->DataBuffer;
1585 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1586
1587 /* clear buffer */
1588 for (i = 0; i < Srb->DataTransferLength; i++)
1589 {
1590 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1591 }
1592
1593 /* set device class */
1594 if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
1595 {
1596 /* hard-disk */
1597 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1598 }
1599 else
1600 {
1601 /* get it from the ATAPI configuration word */
1602 InquiryData->DeviceType = (DeviceParams->ConfigBits >> 8) & 0x1F;
1603 DPRINT("Device class: %u\n", InquiryData->DeviceType);
1604 }
1605
1606 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1607 if (DeviceParams->ConfigBits & 0x80)
1608 {
1609 DPRINT("Removable media!\n");
1610 InquiryData->RemovableMedia = 1;
1611 }
1612
1613 for (i = 0; i < 20; i += 2)
1614 {
1615 InquiryData->VendorId[i] =
1616 ((PUCHAR)DeviceParams->ModelNumber)[i];
1617 InquiryData->VendorId[i+1] =
1618 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1619 }
1620
1621 for (i = 0; i < 4; i++)
1622 {
1623 InquiryData->ProductId[12+i] = ' ';
1624 }
1625
1626 for (i = 0; i < 4; i += 2)
1627 {
1628 InquiryData->ProductRevisionLevel[i] =
1629 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1630 InquiryData->ProductRevisionLevel[i+1] =
1631 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1632 }
1633
1634 return(SRB_STATUS_SUCCESS);
1635 }
1636
1637
1638 static ULONG
1639 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1640 PSCSI_REQUEST_BLOCK Srb)
1641 {
1642 PREAD_CAPACITY_DATA CapacityData;
1643 PIDE_DRIVE_IDENTIFY DeviceParams;
1644 ULONG LastSector;
1645
1646 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1647
1648 if ((Srb->PathId != 0) ||
1649 (Srb->TargetId > 1) ||
1650 (Srb->Lun != 0) ||
1651 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1652 {
1653 return(SRB_STATUS_SELECTION_TIMEOUT);
1654 }
1655
1656
1657 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1658 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1659
1660 /* Set sector (block) size to 512 bytes (big-endian). */
1661 CapacityData->BytesPerBlock = 0x20000;
1662
1663 /* Calculate last sector (big-endian). */
1664 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1665 {
1666 LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1667 DeviceParams->TMSectorCountLo) - 1;
1668 }
1669 else
1670 {
1671 LastSector = (ULONG)(DeviceParams->LogicalCyls *
1672 DeviceParams->LogicalHeads *
1673 DeviceParams->SectorsPerTrack)-1;
1674 }
1675
1676 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1677 (((PUCHAR)&LastSector)[1] << 16) |
1678 (((PUCHAR)&LastSector)[2] << 8) |
1679 ((PUCHAR)&LastSector)[3];
1680
1681 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1682 LastSector,
1683 LastSector,
1684 CapacityData->LogicalBlockAddress);
1685
1686 return(SRB_STATUS_SUCCESS);
1687 }
1688
1689
1690 static ULONG
1691 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1692 PSCSI_REQUEST_BLOCK Srb)
1693 {
1694 PIDE_DRIVE_IDENTIFY DeviceParams;
1695
1696 ULONG StartingSector,i;
1697 ULONG SectorCount;
1698 UCHAR CylinderHigh;
1699 UCHAR CylinderLow;
1700 UCHAR DrvHead;
1701 UCHAR SectorNumber;
1702 UCHAR Command;
1703 ULONG Retries;
1704 UCHAR Status;
1705
1706
1707 DPRINT("AtapiReadWrite() called!\n");
1708
1709 if ((Srb->PathId != 0) ||
1710 (Srb->TargetId > 1) ||
1711 (Srb->Lun != 0) ||
1712 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1713 {
1714 return(SRB_STATUS_SELECTION_TIMEOUT);
1715 }
1716
1717 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1718 Srb->TargetId);
1719
1720 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1721
1722 /* Get starting sector number from CDB. */
1723 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
1724 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
1725 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
1726 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
1727
1728 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
1729 DeviceParams->BytesPerSector;
1730
1731 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1732 StartingSector,
1733 Srb->DataTransferLength,
1734 SectorCount);
1735
1736 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1737 {
1738 SectorNumber = StartingSector & 0xff;
1739 CylinderLow = (StartingSector >> 8) & 0xff;
1740 CylinderHigh = (StartingSector >> 16) & 0xff;
1741 DrvHead = ((StartingSector >> 24) & 0x0f) |
1742 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
1743 IDE_DH_LBA;
1744 }
1745 else
1746 {
1747 SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
1748 StartingSector /= DeviceParams->SectorsPerTrack;
1749 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
1750 (Srb->TargetId ? IDE_DH_DRV1 : 0);
1751 StartingSector /= DeviceParams->LogicalHeads;
1752 CylinderLow = StartingSector & 0xff;
1753 CylinderHigh = StartingSector >> 8;
1754 }
1755
1756
1757 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
1758 {
1759 Command = IDE_CMD_READ;
1760 }
1761 else
1762 {
1763 Command = IDE_CMD_WRITE;
1764 }
1765
1766 if (DrvHead & IDE_DH_LBA)
1767 {
1768 DPRINT("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1769 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1770 DeviceExtension->CommandPortBase,
1771 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1772 ((DrvHead & 0x0f) << 24) +
1773 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
1774 SectorCount,
1775 Command);
1776 }
1777 else
1778 {
1779 DPRINT("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1780 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1781 DeviceExtension->CommandPortBase,
1782 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1783 CylinderHigh,
1784 CylinderLow,
1785 DrvHead & 0x0f,
1786 SectorNumber,
1787 SectorCount,
1788 Command);
1789 }
1790
1791 /* Set pointer to data buffer. */
1792 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1793
1794 DeviceExtension->CurrentSrb = Srb;
1795 DeviceExtension->ExpectingInterrupt = TRUE;
1796
1797
1798
1799 /* wait for BUSY to clear */
1800 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1801 {
1802 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1803 if (!(Status & IDE_SR_BUSY))
1804 {
1805 break;
1806 }
1807 ScsiPortStallExecution(10);
1808 }
1809 DPRINT("status=%02x\n", Status);
1810 DPRINT("waited %ld usecs for busy to clear\n", Retries * 10);
1811 if (Retries >= IDE_MAX_BUSY_RETRIES)
1812 {
1813 DPRINT ("Drive is BUSY for too long\n");
1814 return(SRB_STATUS_BUSY);
1815 #if 0
1816 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1817 {
1818 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1819 Irp = ControllerExtension->CurrentIrp;
1820 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1821 Irp->IoStatus.Information = 0;
1822
1823 return FALSE;
1824 }
1825 else
1826 {
1827 DPRINT ("Beginning drive reset sequence\n");
1828 IDEBeginControllerReset(ControllerExtension);
1829
1830 return TRUE;
1831 }
1832 #endif
1833 }
1834
1835 /* Select the desired drive */
1836 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1837 IDE_DH_FIXED | DrvHead);
1838
1839 /* wait for BUSY to clear and DRDY to assert */
1840 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1841 {
1842 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1843 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1844 {
1845 break;
1846 }
1847 ScsiPortStallExecution(10);
1848 }
1849 DPRINT("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1850 if (Retries >= IDE_MAX_BUSY_RETRIES)
1851 {
1852 DPRINT("Drive is BUSY for too long after drive select\n");
1853 return(SRB_STATUS_BUSY);
1854 #if 0
1855 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1856 {
1857 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1858 Irp = ControllerExtension->CurrentIrp;
1859 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1860 Irp->IoStatus.Information = 0;
1861
1862 return FALSE;
1863 }
1864 else
1865 {
1866 DPRINT("Beginning drive reset sequence\n");
1867 IDEBeginControllerReset(ControllerExtension);
1868
1869 return TRUE;
1870 }
1871 #endif
1872 }
1873
1874 #if 0
1875 if (Command == IDE_CMD_WRITE)
1876 {
1877 DPRINT1("Write not implemented yet!\n");
1878 return(SRB_STATUS_SUCCESS);
1879 }
1880 #endif
1881
1882 /* Indicate expecting an interrupt. */
1883 DeviceExtension->ExpectingInterrupt = TRUE;
1884
1885 /* Setup command parameters */
1886 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1887 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
1888 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
1889 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
1890 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
1891 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1892
1893 /* Issue command to drive */
1894 IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
1895
1896 /* Write data block */
1897 if (Command == IDE_CMD_WRITE)
1898 {
1899 PUCHAR TargetAddress;
1900 ULONG SectorSize;
1901
1902 /* Wait for controller ready */
1903 for (Retries = 0; Retries < IDE_MAX_WRITE_RETRIES; Retries++)
1904 {
1905 BYTE Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1906 if (!(Status & IDE_SR_BUSY) || (Status & IDE_SR_ERR))
1907 {
1908 break;
1909 }
1910 KeStallExecutionProcessor(10);
1911 }
1912 if (Retries >= IDE_MAX_BUSY_RETRIES)
1913 {
1914 DPRINT("Drive is BUSY for too long after sending write command\n");
1915 return(SRB_STATUS_BUSY);
1916 #if 0
1917 if (DeviceExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1918 {
1919 Irp = ControllerExtension->CurrentIrp;
1920 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1921 Irp->IoStatus.Information = 0;
1922
1923 return FALSE;
1924 }
1925 else
1926 {
1927 IDEBeginControllerReset(ControllerExtension);
1928
1929 return TRUE;
1930 }
1931 #endif
1932 }
1933
1934 /* Update SRB data */
1935 SectorSize = DeviceExtension->DeviceParams[Srb->TargetId].BytesPerSector;
1936 TargetAddress = Srb->DataBuffer;
1937 Srb->DataBuffer += SectorSize;
1938 Srb->DataTransferLength -= SectorSize;
1939
1940 /* Write data block */
1941 IDEWriteBlock(DeviceExtension->CommandPortBase,
1942 TargetAddress,
1943 SectorSize);
1944 }
1945
1946
1947 DPRINT("AtapiReadWrite() done!\n");
1948
1949 /* Wait for interrupt. */
1950 return(SRB_STATUS_PENDING);
1951 }
1952
1953 /* EOF */