Fixed a typo.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
1 /* $Id: atapi.c,v 1.7 2002/02/04 01:21:03 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 PSCSI_REQUEST_BLOCK CurrentSrb;
64
65 PUSHORT DataBuffer;
66 } ATAPI_MINIPORT_EXTENSION, *PATAPI_MINIPORT_EXTENSION;
67
68
69 typedef struct _UNIT_EXTENSION
70 {
71 ULONG Dummy;
72 } UNIT_EXTENSION, *PUNIT_EXTENSION;
73
74
75 // ----------------------------------------------- Discardable Declarations
76
77 #ifdef ALLOC_PRAGMA
78
79 // make the initialization routines discardable, so that they
80 // don't waste space
81
82 #pragma alloc_text(init, DriverEntry)
83 #pragma alloc_text(init, IDECreateController)
84 #pragma alloc_text(init, IDEPolledRead)
85
86 // make the PASSIVE_LEVEL routines pageable, so that they don't
87 // waste nonpaged memory
88
89 #pragma alloc_text(page, IDEShutdown)
90 #pragma alloc_text(page, IDEDispatchOpenClose)
91 #pragma alloc_text(page, IDEDispatchRead)
92 #pragma alloc_text(page, IDEDispatchWrite)
93
94 #endif /* ALLOC_PRAGMA */
95
96 // ---------------------------------------------------- Forward Declarations
97
98 static ULONG STDCALL
99 AtapiFindCompatiblePciController(PVOID DeviceExtension,
100 PVOID HwContext,
101 PVOID BusInformation,
102 PCHAR ArgumentString,
103 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
104 PBOOLEAN Again);
105
106 static ULONG STDCALL
107 AtapiFindIsaBusController(PVOID DeviceExtension,
108 PVOID HwContext,
109 PVOID BusInformation,
110 PCHAR ArgumentString,
111 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
112 PBOOLEAN Again);
113
114 static ULONG STDCALL
115 AtapiFindNativePciController(PVOID DeviceExtension,
116 PVOID HwContext,
117 PVOID BusInformation,
118 PCHAR ArgumentString,
119 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
120 PBOOLEAN Again);
121
122 static BOOLEAN STDCALL
123 AtapiInitialize(IN PVOID DeviceExtension);
124
125 static BOOLEAN STDCALL
126 AtapiResetBus(IN PVOID DeviceExtension,
127 IN ULONG PathId);
128
129 static BOOLEAN STDCALL
130 AtapiStartIo(IN PVOID DeviceExtension,
131 IN PSCSI_REQUEST_BLOCK Srb);
132
133 static BOOLEAN STDCALL
134 AtapiInterrupt(IN PVOID DeviceExtension);
135
136 static BOOLEAN
137 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
138 PPORT_CONFIGURATION_INFORMATION ConfigInfo);
139
140 static BOOLEAN
141 AtapiIdentifyDevice(IN ULONG CommandPort,
142 IN ULONG ControlPort,
143 IN ULONG DriveNum,
144 IN BOOLEAN Atapi,
145 OUT PIDE_DRIVE_IDENTIFY DrvParms);
146
147 static BOOLEAN
148 IDEResetController(IN WORD CommandPort,
149 IN WORD ControlPort);
150
151 static int
152 AtapiPolledRead(IN WORD CommandPort,
153 IN WORD ControlPort,
154 IN BYTE PreComp,
155 IN BYTE SectorCnt,
156 IN BYTE SectorNum,
157 IN BYTE CylinderLow,
158 IN BYTE CylinderHigh,
159 IN BYTE DrvHead,
160 IN BYTE Command,
161 OUT BYTE *Buffer);
162
163
164
165 static ULONG
166 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
167 IN PSCSI_REQUEST_BLOCK Srb);
168
169 static ULONG
170 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
171 IN PSCSI_REQUEST_BLOCK Srb);
172
173 static ULONG
174 AtapiInquiry(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
175 IN PSCSI_REQUEST_BLOCK Srb);
176
177 static ULONG
178 AtapiReadCapacity(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
179 IN PSCSI_REQUEST_BLOCK Srb);
180
181 static ULONG
182 AtapiReadWrite(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
183 IN PSCSI_REQUEST_BLOCK Srb);
184
185 // ---------------------------------------------------------------- Inlines
186
187 void
188 IDESwapBytePairs(char *Buf,
189 int Cnt)
190 {
191 char t;
192 int i;
193
194 for (i = 0; i < Cnt; i += 2)
195 {
196 t = Buf[i];
197 Buf[i] = Buf[i+1];
198 Buf[i+1] = t;
199 }
200 }
201
202
203 static BOOLEAN
204 IdeFindDrive(int Address,
205 int DriveIdx)
206 {
207 ULONG Cyl;
208
209 DPRINT1("IdeFindDrive(Address %lx DriveIdx %lu) called!\n", Address, DriveIdx);
210
211 IDEWriteDriveHead(Address, IDE_DH_FIXED | (DriveIdx ? IDE_DH_DRV1 : 0));
212 IDEWriteCylinderLow(Address, 0x30);
213
214 Cyl = IDEReadCylinderLow(Address);
215 DPRINT1("Cylinder %lx\n", Cyl);
216
217
218 DPRINT1("IdeFindDrive() done!\n");
219 // for(;;);
220 return(Cyl == 0x30);
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 InitData.HwFindAdapter = AtapiFindCompatiblePciController;
270 InitData.NumberOfAccessRanges = 2;
271 InitData.AdapterInterfaceType = PCIBus;
272
273 InitData.VendorId = NULL;
274 InitData.VendorIdLength = 0;
275 InitData.DeviceId = NULL;
276 InitData.DeviceIdLength = 0;
277
278 Status = ScsiPortInitialize(DriverObject,
279 RegistryPath,
280 &InitData,
281 NULL);
282 // if (newStatus < statusToReturn)
283 // statusToReturn = newStatus;
284
285 /* Search the ISA bus for ide controllers */
286 #if 0
287 InitData.HwFindAdapter = AtapiFindIsaBusController;
288 InitData.NumberOfAccessRanges = 2;
289 InitData.AdapterInterfaceType = Isa;
290
291 InitData.VendorId = NULL;
292 InitData.VendorIdLength = 0;
293 InitData.DeviceId = NULL;
294 InitData.DeviceIdLength = 0;
295
296 Status = ScsiPortInitialize(DriverObject,
297 RegistryPath,
298 &InitData,
299 NULL);
300 // if (newStatus < statusToReturn)
301 // statusToReturn = newStatus;
302 #endif
303
304 /* Search the PCI bus for native mode ide controllers */
305 #if 0
306 InitData.HwFindAdapter = AtapiFindNativePciController;
307 InitData.NumberOfAccessRanges = 2;
308 InitData.AdapterInterfaceType = PCIBus;
309
310 InitData.VendorId = NULL;
311 InitData.VendorIdLength = 0;
312 InitData.DeviceId = NULL;
313 InitData.DeviceIdLength = 0;
314
315 Status = ScsiPortInitialize(DriverObject,
316 RegistryPath,
317 &InitData,
318 (PVOID)i);
319 // if (newStatus < statusToReturn)
320 // statusToReturn = newStatus;
321 #endif
322
323 DPRINT1( "Returning from DriverEntry\n" );
324
325 return(Status);
326 }
327
328
329 static ULONG STDCALL
330 AtapiFindCompatiblePciController(PVOID DeviceExtension,
331 PVOID HwContext,
332 PVOID BusInformation,
333 PCHAR ArgumentString,
334 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
335 PBOOLEAN Again)
336 {
337 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
338 PCI_SLOT_NUMBER SlotNumber;
339 PCI_COMMON_CONFIG PciConfig;
340 ULONG DataSize;
341 ULONG FunctionNumber;
342 BOOLEAN ChannelFound;
343 BOOLEAN DeviceFound;
344
345 DPRINT("AtapiFindCompatiblePciController() Bus: %lu Slot: %lu\n",
346 ConfigInfo->SystemIoBusNumber,
347 ConfigInfo->SlotNumber);
348
349 *Again = FALSE;
350
351 /* both channels were claimed: exit */
352 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE &&
353 ConfigInfo->AtdiskSecondaryClaimed == TRUE)
354 return(SP_RETURN_NOT_FOUND);
355
356
357 SlotNumber.u.AsULONG = 0;
358 for (FunctionNumber = 0 /*ConfigInfo->SlotNumber*/; FunctionNumber < 256; FunctionNumber++)
359 {
360 // SlotNumber.u.bits.FunctionNumber = FunctionNumber;
361 // SlotNumber.u.AsULONG = (FunctionNumber & 0x07);
362 SlotNumber.u.AsULONG = FunctionNumber;
363
364 ChannelFound = FALSE;
365 DeviceFound = FALSE;
366
367 DataSize = ScsiPortGetBusData(DeviceExtension,
368 PCIConfiguration,
369 0,
370 SlotNumber.u.AsULONG,
371 &PciConfig,
372 sizeof(PCI_COMMON_CONFIG));
373 // if (DataSize != sizeof(PCI_COMMON_CONFIG) ||
374 // PciConfig.VendorID == PCI_INVALID_VENDORID)
375 if (DataSize == 0)
376 {
377 // if ((SlotNumber.u.AsULONG & 0x07) == 0)
378 // return(SP_RETURN_ERROR); /* No bus found */
379
380 continue;
381 // return(SP_RETURN_ERROR);
382 }
383
384 if (PciConfig.BaseClass == 0x01 &&
385 PciConfig.SubClass == 0x01) // &&
386 // (PciConfig.ProgIf & 0x05) == 0)
387 {
388 /* both channels are in compatibility mode */
389 DPRINT1("Bus %1lu Device %2lu Func %1lu VenID 0x%04hx DevID 0x%04hx\n",
390 ConfigInfo->SystemIoBusNumber,
391 // SlotNumber.u.AsULONG >> 3,
392 // SlotNumber.u.AsULONG & 0x07,
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 DPRINT1("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 DPRINT1("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 DPRINT1("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
481 DPRINT("AtapiFindIsaBusController() called!\n");
482
483 *Again = FALSE;
484
485 if (ConfigInfo->AtdiskPrimaryClaimed == TRUE)
486 {
487 DPRINT("Primary IDE controller already claimed!\n");
488
489 }
490
491 if (ConfigInfo->AtdiskSecondaryClaimed == TRUE)
492 {
493 DPRINT("Secondary IDE controller already claimed!\n");
494
495 }
496
497 DPRINT("AtapiFindIsaBusController() done!\n");
498
499 return(SP_RETURN_NOT_FOUND);
500 }
501
502
503 static ULONG STDCALL
504 AtapiFindNativePciController(PVOID DeviceExtension,
505 PVOID HwContext,
506 PVOID BusInformation,
507 PCHAR ArgumentString,
508 PPORT_CONFIGURATION_INFORMATION ConfigInfo,
509 PBOOLEAN Again)
510 {
511 PATAPI_MINIPORT_EXTENSION DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
512
513 DPRINT("AtapiFindNativePciController() called!\n");
514
515 *Again = FALSE;
516
517 DPRINT("AtapiFindNativePciController() done!\n");
518
519 return(SP_RETURN_NOT_FOUND);
520 }
521
522
523 static BOOLEAN STDCALL
524 AtapiInitialize(IN PVOID DeviceExtension)
525 {
526 return(TRUE);
527 }
528
529
530 static BOOLEAN STDCALL
531 AtapiResetBus(IN PVOID DeviceExtension,
532 IN ULONG PathId)
533 {
534 return(TRUE);
535 }
536
537
538 static BOOLEAN STDCALL
539 AtapiStartIo(IN PVOID DeviceExtension,
540 IN PSCSI_REQUEST_BLOCK Srb)
541 {
542 PATAPI_MINIPORT_EXTENSION DevExt;
543 ULONG Result;
544
545 DPRINT1("AtapiStartIo() called\n");
546
547 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
548
549 switch (Srb->Function)
550 {
551 case SRB_FUNCTION_EXECUTE_SCSI:
552 DevExt->CurrentSrb = Srb;
553 if (DevExt->DeviceAtapi[Srb->TargetId] == TRUE)
554 {
555 Result = AtapiSendAtapiCommand(DevExt,
556 Srb);
557 }
558 else
559 {
560 Result = AtapiSendIdeCommand(DevExt,
561 Srb);
562 }
563 break;
564
565 }
566
567 Srb->SrbStatus = Result;
568
569
570 if (Result != SRB_STATUS_PENDING)
571 {
572 DevExt->CurrentSrb = NULL;
573 Srb->SrbStatus = (UCHAR)Result;
574 #if 0
575 ScsiPortNotification(RequestComplete,
576 DeviceExtension,
577 Srb);
578
579 ScsiPortNotification(NextRequest,
580 DeviceExtension,
581 NULL);
582 #endif
583 }
584
585 return(TRUE);
586 }
587
588
589 static BOOLEAN STDCALL
590 AtapiInterrupt(IN PVOID DeviceExtension)
591 {
592 PATAPI_MINIPORT_EXTENSION DevExt;
593 PSCSI_REQUEST_BLOCK Srb;
594 ULONG CommandPortBase;
595 ULONG ControlPortBase;
596
597 UCHAR DeviceStatus;
598 BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
599 ULONG Retries;
600 NTSTATUS ErrorStatus;
601 ULONG ErrorInformation;
602 PUCHAR TargetAddress;
603
604
605
606 DPRINT1("AtapiInterrupt() called!\n");
607
608 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
609 Srb = DevExt->CurrentSrb;
610
611 DPRINT1("Srb: %p\n", Srb);
612
613 CommandPortBase = DevExt->CommandPortBase;
614 ControlPortBase = DevExt->ControlPortBase;
615
616 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
617
618
619 IsLastBlock = FALSE;
620 AnErrorOccured = FALSE;
621 RequestIsComplete = FALSE;
622 ErrorStatus = STATUS_SUCCESS;
623 ErrorInformation = 0;
624
625 DeviceStatus = IDEReadStatus(CommandPortBase);
626
627 /* Handle error condition if it exists */
628 if (DeviceStatus & IDE_SR_ERR)
629 {
630 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
631 BYTE DriveHead;
632
633 /* Log the error */
634 ErrorReg = IDEReadError(CommandPortBase);
635 CylinderLow = IDEReadCylinderLow(CommandPortBase);
636 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
637 DriveHead = IDEReadDriveHead(CommandPortBase);
638 SectorCount = IDEReadSectorCount(CommandPortBase);
639 SectorNum = IDEReadSectorNum(CommandPortBase);
640
641 /* FIXME: should use the NT error logging facility */
642 DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
643 0, //DeviceExtension->Operation,
644 DeviceStatus,
645 ErrorReg,
646 CylinderLow,
647 CylinderHigh,
648 SectorCount,
649 SectorNum);
650
651 /* FIXME: should retry the command and perhaps recalibrate the drive */
652
653 // Set error status information
654 AnErrorOccured = TRUE;
655 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
656 #if 0
657 ErrorInformation =
658 (((((((CylinderHigh << 8) + CylinderLow) *
659 DeviceExtension->LogicalHeads) +
660 (DriveHead % DeviceExtension->LogicalHeads)) *
661 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
662 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
663 #endif
664 }
665 else
666 {
667 switch (Srb->Cdb[0])
668 {
669 case SCSIOP_READ:
670 DPRINT1("SCSIOP_READ\n");
671
672 /* Update controller/device state variables */
673 TargetAddress = Srb->DataBuffer;
674 Srb->DataBuffer += DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
675 Srb->DataTransferLength -= DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
676 // DevExt->SectorsTransferred++;
677
678 /* Remember whether DRQ should be low at end (last block read) */
679 IsLastBlock = Srb->DataTransferLength == 0;
680
681 /* Wait for DRQ assertion */
682 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
683 !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
684 Retries++)
685 {
686 KeStallExecutionProcessor(10);
687 }
688
689 /* Copy the block of data */
690 IDEReadBlock(CommandPortBase,
691 TargetAddress,
692 IDE_SECTOR_BUF_SZ);
693
694 /* check DRQ */
695 if (IsLastBlock)
696 {
697 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
698 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
699 Retries++)
700 {
701 KeStallExecutionProcessor(10);
702 }
703
704 /* Check for data overrun */
705 if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
706 {
707 AnErrorOccured = TRUE;
708 ErrorStatus = STATUS_DATA_OVERRUN;
709 ErrorInformation = 0;
710 }
711 else
712 {
713
714 #if 0
715 // Setup next transfer or set RequestIsComplete
716 if (DeviceExtension->BytesRequested >
717 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
718 {
719 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
720 DeviceExtension->SectorsTransferred = 0;
721 DeviceExtension->BytesToTransfer =
722 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
723 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
724 }
725 else if (DeviceExtension->BytesRequested > 0)
726 {
727 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
728 DeviceExtension->SectorsTransferred = 0;
729 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
730 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
731 }
732 else
733 {
734 RequestIsComplete = TRUE;
735 }
736 #endif
737 RequestIsComplete = TRUE;
738 }
739 }
740 break;
741
742 case SCSIOP_WRITE:
743 DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
744 RequestIsComplete = TRUE;
745 break;
746 }
747 }
748
749
750 /* If there was an error or the request is done, complete the packet */
751 if (AnErrorOccured || RequestIsComplete)
752 {
753 #if 0
754 /* Set the return status and info values */
755 Irp = ControllerExtension->CurrentIrp;
756 Irp->IoStatus.Status = ErrorStatus;
757 Irp->IoStatus.Information = ErrorInformation;
758
759 /* Clear out controller fields */
760 ControllerExtension->OperationInProgress = FALSE;
761 ControllerExtension->DeviceStatus = 0;
762
763 /* Queue the Dpc to finish up */
764 IoRequestDpc(DeviceExtension->DeviceObject,
765 Irp,
766 ControllerExtension);
767 #endif
768 }
769 else if (IsLastBlock)
770 {
771 #if 0
772 /* Else more data is needed, setup next device I/O */
773 IDEStartController((PVOID)DeviceExtension);
774 #endif
775 }
776
777 DPRINT1("AtapiInterrupt() done!\n");
778
779 return(TRUE);
780 }
781
782
783
784
785
786
787 // ---------------------------------------------------- Discardable statics
788
789
790 static BOOLEAN
791 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
792 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
793 {
794 BOOLEAN DeviceFound = FALSE;
795 ULONG CommandPortBase;
796 ULONG ControlPortBase;
797 ULONG UnitNumber;
798 ULONG Retries;
799 BYTE High, Low;
800
801 DPRINT("AtapiFindDevices() called\n");
802
803 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
804 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
805 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
806
807 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
808 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
809 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
810
811 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
812 {
813 /* disable interrupts */
814 IDEWriteDriveControl(CommandPortBase,
815 IDE_DC_nIEN);
816
817 /* select drive */
818 IDEWriteDriveHead(CommandPortBase,
819 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
820 ScsiPortStallExecution(500);
821 IDEWriteCylinderHigh(CommandPortBase, 0);
822 IDEWriteCylinderLow(CommandPortBase, 0);
823 IDEWriteCommand(CommandPortBase, 0x08); /* IDE_COMMAND_ATAPI_RESET */
824 // ScsiPortStallExecution(1000*1000);
825 // IDEWriteDriveHead(CommandPortBase,
826 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
827 // IDE_DH_FIXED);
828
829 for (Retries = 0; Retries < 20000; Retries++)
830 {
831 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
832 {
833 break;
834 }
835 ScsiPortStallExecution(150);
836 }
837 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
838 {
839 DbgPrint("Timeout on drive %lu\n", UnitNumber);
840 return(DeviceFound);
841 }
842
843 High = IDEReadCylinderHigh(CommandPortBase);
844 Low = IDEReadCylinderLow(CommandPortBase);
845
846 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
847 UnitNumber,
848 High,
849 Low);
850
851 if (High == 0xEB && Low == 0x14)
852 {
853 if (AtapiIdentifyDevice(CommandPortBase,
854 ControlPortBase,
855 UnitNumber,
856 TRUE,
857 &DeviceExtension->DeviceParams[UnitNumber]))
858 {
859 DPRINT(" ATAPI drive found!\n");
860 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
861 DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
862 DeviceFound = TRUE;
863 }
864 else
865 {
866 DPRINT(" No ATAPI drive found!\n");
867 }
868 }
869 else
870 {
871 if (AtapiIdentifyDevice(CommandPortBase,
872 ControlPortBase,
873 UnitNumber,
874 FALSE,
875 &DeviceExtension->DeviceParams[UnitNumber]))
876 {
877 DPRINT(" IDE drive found!\n");
878 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
879 DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
880 DeviceFound = TRUE;
881 }
882 else
883 {
884 DPRINT(" No IDE drive found!\n");
885 }
886 }
887 }
888
889 DPRINT("AtapiFindDrives() done\n");
890
891 return(DeviceFound);
892 }
893
894
895 // AtapiResetController
896 //
897 // DESCRIPTION:
898 // Reset the controller and report completion status
899 //
900 // RUN LEVEL:
901 // PASSIVE_LEVEL
902 //
903 // ARGUMENTS:
904 // IN WORD CommandPort The address of the command port
905 // IN WORD ControlPort The address of the control port
906 //
907 // RETURNS:
908 //
909
910 static BOOLEAN
911 AtapiResetController(IN WORD CommandPort,
912 IN WORD ControlPort)
913 {
914 int Retries;
915
916 /* Assert drive reset line */
917 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
918
919 /* Wait for min. 25 microseconds */
920 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
921
922 /* Negate drive reset line */
923 IDEWriteDriveControl(ControlPort, 0);
924
925 /* Wait for BUSY negation */
926 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
927 {
928 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
929 {
930 break;
931 }
932 ScsiPortStallExecution(10);
933 }
934
935 CHECKPOINT;
936 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
937 {
938 return(FALSE);
939 }
940
941 CHECKPOINT;
942
943 // return TRUE if controller came back to life. and
944 // the registers are initialized correctly
945 return(IDEReadError(CommandPort) == 1);
946 }
947
948
949 // AtapiIdentifyDevice
950 //
951 // DESCRIPTION:
952 // Get the identification block from the drive
953 //
954 // RUN LEVEL:
955 // PASSIVE_LEVEL
956 //
957 // ARGUMENTS:
958 // IN int CommandPort Address of the command port
959 // IN int DriveNum The drive index (0,1)
960 // OUT PIDE_DRIVE_IDENTIFY DrvParms Address to write drive ident block
961 //
962 // RETURNS:
963 // TRUE The drive identification block was retrieved successfully
964 //
965
966 static BOOLEAN
967 AtapiIdentifyDevice(IN ULONG CommandPort,
968 IN ULONG ControlPort,
969 IN ULONG DriveNum,
970 IN BOOLEAN Atapi,
971 OUT PIDE_DRIVE_IDENTIFY DrvParms)
972 {
973 /* Get the Drive Identify block from drive or die */
974 if (AtapiPolledRead((WORD)CommandPort,
975 (WORD)ControlPort,
976 0,
977 1,
978 0,
979 0,
980 0,
981 (DriveNum ? IDE_DH_DRV1 : 0),
982 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
983 (BYTE *)DrvParms) != 0) /* atapi_identify */
984 {
985 DPRINT1("IDEPolledRead() failed\n");
986 return FALSE;
987 }
988
989 /* Report on drive parameters if debug mode */
990 IDESwapBytePairs(DrvParms->SerialNumber, 20);
991 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
992 IDESwapBytePairs(DrvParms->ModelNumber, 40);
993 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
994 DrvParms->ConfigBits,
995 DrvParms->LogicalCyls,
996 DrvParms->LogicalHeads,
997 DrvParms->SectorsPerTrack,
998 DrvParms->InterSectorGap,
999 DrvParms->InterSectorGapSize);
1000 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1001 DrvParms->BytesInPLO,
1002 DrvParms->VendorUniqueCnt,
1003 DrvParms->SerialNumber);
1004 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1005 DrvParms->ControllerType,
1006 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1007 DrvParms->ECCByteCnt,
1008 DrvParms->FirmwareRev);
1009 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1010 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1011 (DrvParms->RWMultImplemented) & 0xff,
1012 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1013 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1014 DrvParms->MinPIOTransTime,
1015 DrvParms->MinDMATransTime);
1016 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1017 DrvParms->TMCylinders,
1018 DrvParms->TMHeads,
1019 DrvParms->TMSectorsPerTrk,
1020 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1021 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1022 DrvParms->TMSectorCountHi,
1023 DrvParms->TMSectorCountLo,
1024 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1025
1026 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1027 if (DrvParms->BytesPerSector == 0)
1028 DrvParms->BytesPerSector = 512;
1029 return TRUE;
1030 }
1031
1032
1033 // AtapiPolledRead
1034 //
1035 // DESCRIPTION:
1036 // Read a sector of data from the drive in a polled fashion.
1037 //
1038 // RUN LEVEL:
1039 // PASSIVE_LEVEL
1040 //
1041 // ARGUMENTS:
1042 // IN WORD Address Address of command port for drive
1043 // IN BYTE PreComp Value to write to precomp register
1044 // IN BYTE SectorCnt Value to write to sectorCnt register
1045 // IN BYTE SectorNum Value to write to sectorNum register
1046 // IN BYTE CylinderLow Value to write to CylinderLow register
1047 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1048 // IN BYTE DrvHead Value to write to Drive/Head register
1049 // IN BYTE Command Value to write to Command register
1050 // OUT BYTE *Buffer Buffer for output data
1051 //
1052 // RETURNS:
1053 // int 0 is success, non 0 is an error code
1054 //
1055
1056 static int
1057 AtapiPolledRead(IN WORD Address,
1058 IN WORD ControlPort,
1059 IN BYTE PreComp,
1060 IN BYTE SectorCnt,
1061 IN BYTE SectorNum,
1062 IN BYTE CylinderLow,
1063 IN BYTE CylinderHigh,
1064 IN BYTE DrvHead,
1065 IN BYTE Command,
1066 OUT BYTE *Buffer)
1067 {
1068 ULONG SectorCount = 0;
1069 ULONG RetryCount;
1070 BOOLEAN Junk = FALSE;
1071 UCHAR Status;
1072 UCHAR Control;
1073
1074 /* Disable interrupts */
1075 Control = IDEReadAltStatus(ControlPort);
1076 IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
1077
1078 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1079 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1080 {
1081 Status = IDEReadStatus(Address);
1082 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1083 {
1084 break;
1085 }
1086 ScsiPortStallExecution(10);
1087 }
1088 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1089 {
1090 return(IDE_ER_ABRT);
1091 }
1092
1093 /* Write Drive/Head to select drive */
1094 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1095
1096 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1097 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1098 {
1099 Status = IDEReadStatus(Address);
1100 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1101 {
1102 break;
1103 }
1104 ScsiPortStallExecution(10);
1105 }
1106 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1107 {
1108 return IDE_ER_ABRT;
1109 }
1110
1111 /* Issue command to drive */
1112 if (DrvHead & IDE_DH_LBA)
1113 {
1114 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1115 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1116 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1117 SectorCnt,
1118 Command);
1119 }
1120 else
1121 {
1122 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1123 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1124 CylinderHigh,
1125 CylinderLow,
1126 DrvHead & 0x0f,
1127 SectorNum,
1128 SectorCnt,
1129 Command);
1130 }
1131
1132 /* Setup command parameters */
1133 IDEWritePrecomp(Address, PreComp);
1134 IDEWriteSectorCount(Address, SectorCnt);
1135 IDEWriteSectorNum(Address, SectorNum);
1136 IDEWriteCylinderHigh(Address, CylinderHigh);
1137 IDEWriteCylinderLow(Address, CylinderLow);
1138 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1139
1140 /* Issue the command */
1141 IDEWriteCommand(Address, Command);
1142 ScsiPortStallExecution(50);
1143
1144 /* wait for DRQ or error */
1145 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1146 {
1147 Status = IDEReadStatus(Address);
1148 if (!(Status & IDE_SR_BUSY))
1149 {
1150 if (Status & IDE_SR_ERR)
1151 {
1152 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1153 return(IDE_ER_ABRT);
1154 }
1155 if (Status & IDE_SR_DRQ)
1156 {
1157 break;
1158 }
1159 else
1160 {
1161 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1162 return(IDE_ER_ABRT);
1163 }
1164 }
1165 ScsiPortStallExecution(10);
1166 }
1167
1168 /* timed out */
1169 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1170 {
1171 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1172 return(IDE_ER_ABRT);
1173 }
1174
1175 while (1)
1176 {
1177 /* Read data into buffer */
1178 if (Junk == FALSE)
1179 {
1180 IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1181 Buffer += IDE_SECTOR_BUF_SZ;
1182 }
1183 else
1184 {
1185 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1186 IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
1187 }
1188 SectorCount++;
1189
1190 /* Check for error or more sectors to read */
1191 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1192 {
1193 Status = IDEReadStatus(Address);
1194 if (!(Status & IDE_SR_BUSY))
1195 {
1196 if (Status & IDE_SR_ERR)
1197 {
1198 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1199 return(IDE_ER_ABRT);
1200 }
1201 if (Status & IDE_SR_DRQ)
1202 {
1203 if (SectorCount >= SectorCnt)
1204 {
1205 DPRINT("Buffer size exceeded!\n");
1206 Junk = TRUE;
1207 }
1208 break;
1209 }
1210 else
1211 {
1212 if (SectorCount > SectorCnt)
1213 {
1214 DPRINT("Read %lu sectors of junk!\n",
1215 SectorCount - SectorCnt);
1216 }
1217 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1218 return(0);
1219 }
1220 }
1221 }
1222 }
1223 }
1224
1225
1226 // ------------------------------------------- Nondiscardable statics
1227
1228 static ULONG
1229 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1230 IN PSCSI_REQUEST_BLOCK Srb)
1231 {
1232 DPRINT1("AtapiSendAtapiComamnd() called!\n");
1233 DPRINT1("Not implemented yet!\n");
1234 return(SRB_STATUS_SELECTION_TIMEOUT);
1235 }
1236
1237
1238 static ULONG
1239 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1240 IN PSCSI_REQUEST_BLOCK Srb)
1241 {
1242 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1243
1244 DPRINT("AtapiSendIdeCommand() called!\n");
1245
1246 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1247 Srb->PathId,
1248 Srb->TargetId,
1249 Srb->Lun);
1250
1251 switch (Srb->Cdb[0])
1252 {
1253 case SCSIOP_INQUIRY:
1254 SrbStatus = AtapiInquiry(DeviceExtension,
1255 Srb);
1256 break;
1257
1258 case SCSIOP_READ_CAPACITY:
1259 SrbStatus = AtapiReadCapacity(DeviceExtension,
1260 Srb);
1261 break;
1262
1263 case SCSIOP_READ:
1264 case SCSIOP_WRITE:
1265 SrbStatus = AtapiReadWrite(DeviceExtension,
1266 Srb);
1267 break;
1268
1269 case SCSIOP_MODE_SENSE:
1270 case SCSIOP_TEST_UNIT_READY:
1271 case SCSIOP_VERIFY:
1272 case SCSIOP_START_STOP_UNIT:
1273 case SCSIOP_REQUEST_SENSE:
1274 break;
1275
1276 default:
1277 DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
1278 Srb->Cdb[0]);
1279 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1280 break;
1281 }
1282
1283 DPRINT("AtapiSendIdeCommand() done!\n");
1284
1285 return(SrbStatus);
1286 }
1287
1288
1289 static ULONG
1290 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1291 PSCSI_REQUEST_BLOCK Srb)
1292 {
1293 PIDE_DRIVE_IDENTIFY DeviceParams;
1294 PINQUIRYDATA InquiryData;
1295 ULONG i;
1296
1297 DPRINT("SCSIOP_INQUIRY: TargetId: %lu\n", Srb->TargetId);
1298
1299 if ((Srb->PathId != 0) ||
1300 (Srb->TargetId > 1) ||
1301 (Srb->Lun != 0) ||
1302 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1303 {
1304 return(SRB_STATUS_SELECTION_TIMEOUT);
1305 }
1306
1307 InquiryData = Srb->DataBuffer;
1308 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1309
1310 /* clear buffer */
1311 for (i = 0; i < Srb->DataTransferLength; i++)
1312 {
1313 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1314 }
1315
1316 /* set device class */
1317 if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
1318 {
1319 /* hard-disk */
1320 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1321 }
1322 else
1323 {
1324 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1325 /* cdrom drive */
1326 InquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
1327 }
1328
1329 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1330 if (DeviceParams->ConfigBits & 0x80)
1331 {
1332 DPRINT1("Removable media!\n");
1333 InquiryData->RemovableMedia = 1;
1334 }
1335
1336 for (i = 0; i < 20; i += 2)
1337 {
1338 InquiryData->VendorId[i] =
1339 ((PUCHAR)DeviceParams->ModelNumber)[i];
1340 InquiryData->VendorId[i+1] =
1341 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1342 }
1343
1344 for (i = 0; i < 4; i++)
1345 {
1346 InquiryData->ProductId[12+i] = ' ';
1347 }
1348
1349 for (i = 0; i < 4; i += 2)
1350 {
1351 InquiryData->ProductRevisionLevel[i] =
1352 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1353 InquiryData->ProductRevisionLevel[i+1] =
1354 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1355 }
1356
1357 return(SRB_STATUS_SUCCESS);
1358 }
1359
1360
1361 static ULONG
1362 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1363 PSCSI_REQUEST_BLOCK Srb)
1364 {
1365 PREAD_CAPACITY_DATA CapacityData;
1366 PIDE_DRIVE_IDENTIFY DeviceParams;
1367 ULONG LastSector;
1368
1369 DPRINT("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1370
1371 if ((Srb->PathId != 0) ||
1372 (Srb->TargetId > 1) ||
1373 (Srb->Lun != 0) ||
1374 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1375 {
1376 return(SRB_STATUS_SELECTION_TIMEOUT);
1377 }
1378
1379
1380 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1381 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1382
1383 /* Set sector (block) size to 512 bytes (big-endian). */
1384 CapacityData->BytesPerBlock = 0x20000;
1385
1386 /* Calculate last sector (big-endian). */
1387 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1388 {
1389 LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1390 DeviceParams->TMSectorCountLo) - 1;
1391 }
1392 else
1393 {
1394 LastSector = (ULONG)(DeviceParams->LogicalCyls *
1395 DeviceParams->LogicalHeads *
1396 DeviceParams->SectorsPerTrack)-1;
1397 }
1398
1399 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1400 (((PUCHAR)&LastSector)[1] << 16) |
1401 (((PUCHAR)&LastSector)[2] << 8) |
1402 ((PUCHAR)&LastSector)[3];
1403
1404 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1405 LastSector,
1406 LastSector,
1407 CapacityData->LogicalBlockAddress);
1408
1409 return(SRB_STATUS_SUCCESS);
1410 }
1411
1412
1413 static ULONG
1414 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1415 PSCSI_REQUEST_BLOCK Srb)
1416 {
1417 PIDE_DRIVE_IDENTIFY DeviceParams;
1418
1419 ULONG StartingSector,i;
1420 ULONG SectorCount;
1421 UCHAR CylinderHigh;
1422 UCHAR CylinderLow;
1423 UCHAR DrvHead;
1424 UCHAR SectorNumber;
1425 UCHAR Command;
1426 ULONG Retries;
1427 UCHAR Status;
1428
1429
1430 DPRINT("AtapiReadWrite() called!\n");
1431
1432 if ((Srb->PathId != 0) ||
1433 (Srb->TargetId > 1) ||
1434 (Srb->Lun != 0) ||
1435 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1436 {
1437 return(SRB_STATUS_SELECTION_TIMEOUT);
1438 }
1439
1440 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1441 Srb->TargetId);
1442
1443 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1444
1445 /* Get starting sector number from CDB. */
1446 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
1447 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
1448 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
1449 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
1450
1451 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
1452 DeviceParams->BytesPerSector;
1453
1454 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1455 StartingSector,
1456 Srb->DataTransferLength,
1457 SectorCount);
1458
1459 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1460 {
1461 SectorNumber = StartingSector & 0xff;
1462 CylinderLow = (StartingSector >> 8) & 0xff;
1463 CylinderHigh = (StartingSector >> 16) & 0xff;
1464 DrvHead = ((StartingSector >> 24) & 0x0f) |
1465 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
1466 IDE_DH_LBA;
1467 }
1468 else
1469 {
1470 SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
1471 StartingSector /= DeviceParams->SectorsPerTrack;
1472 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
1473 (Srb->TargetId ? IDE_DH_DRV1 : 0);
1474 StartingSector /= DeviceParams->LogicalHeads;
1475 CylinderLow = StartingSector & 0xff;
1476 CylinderHigh = StartingSector >> 8;
1477 }
1478
1479
1480 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
1481 {
1482 Command = IDE_CMD_READ;
1483 }
1484 else
1485 {
1486 Command = IDE_CMD_WRITE;
1487 }
1488
1489 if (DrvHead & IDE_DH_LBA)
1490 {
1491 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1492 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1493 DeviceExtension->CommandPortBase,
1494 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1495 ((DrvHead & 0x0f) << 24) +
1496 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
1497 SectorCount,
1498 Command);
1499 }
1500 else
1501 {
1502 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1503 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1504 DeviceExtension->CommandPortBase,
1505 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1506 CylinderHigh,
1507 CylinderLow,
1508 DrvHead & 0x0f,
1509 SectorNumber,
1510 SectorCount,
1511 Command);
1512 }
1513
1514 /* Set pointer to data buffer. */
1515 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1516
1517 DeviceExtension->CurrentSrb = Srb;
1518 DeviceExtension->ExpectingInterrupt = TRUE;
1519
1520
1521
1522 /* wait for BUSY to clear */
1523 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1524 {
1525 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1526 if (!(Status & IDE_SR_BUSY))
1527 {
1528 break;
1529 }
1530 ScsiPortStallExecution(10);
1531 }
1532 DPRINT ("status=%02x\n", Status);
1533 DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
1534 if (Retries >= IDE_MAX_BUSY_RETRIES)
1535 {
1536 DPRINT ("Drive is BUSY for too long\n");
1537 return(SRB_STATUS_BUSY);
1538 #if 0
1539 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1540 {
1541 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1542 Irp = ControllerExtension->CurrentIrp;
1543 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1544 Irp->IoStatus.Information = 0;
1545
1546 return FALSE;
1547 }
1548 else
1549 {
1550 DPRINT ("Beginning drive reset sequence\n");
1551 IDEBeginControllerReset(ControllerExtension);
1552
1553 return TRUE;
1554 }
1555 #endif
1556 }
1557
1558 /* Select the desired drive */
1559 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1560 IDE_DH_FIXED | DrvHead);
1561
1562 /* wait for BUSY to clear and DRDY to assert */
1563 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1564 {
1565 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1566 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1567 {
1568 break;
1569 }
1570 ScsiPortStallExecution(10);
1571 }
1572 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1573 if (Retries >= IDE_MAX_BUSY_RETRIES)
1574 {
1575 DPRINT ("Drive is BUSY for too long after drive select\n");
1576 return(SRB_STATUS_BUSY);
1577 #if 0
1578 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1579 {
1580 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1581 Irp = ControllerExtension->CurrentIrp;
1582 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1583 Irp->IoStatus.Information = 0;
1584
1585 return FALSE;
1586 }
1587 else
1588 {
1589 DPRINT ("Beginning drive reset sequence\n");
1590 IDEBeginControllerReset(ControllerExtension);
1591
1592 return TRUE;
1593 }
1594 #endif
1595 }
1596
1597 if (Command == IDE_CMD_WRITE)
1598 {
1599 DPRINT1("Write not implemented yet!\n");
1600 return(SRB_STATUS_SUCCESS);
1601 }
1602
1603 /* Indicate expecting an interrupt. */
1604 DeviceExtension->ExpectingInterrupt = TRUE;
1605
1606 /* Setup command parameters */
1607 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1608 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
1609 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
1610 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
1611 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
1612 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1613
1614 /* Issue command to drive */
1615 IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
1616 // ControllerExtension->TimerState = IDETimerCmdWait;
1617 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1618
1619
1620 /* FIXME: Write data here! */
1621
1622
1623 DPRINT("AtapiReadWrite() done!\n");
1624
1625 /* Wait for interrupt. */
1626 return(SRB_STATUS_PENDING);
1627 }
1628
1629 /* EOF */