Fixed a typo, thanks to Hartmut Birr.
[reactos.git] / reactos / drivers / storage / atapi / atapi.c
1 /* $Id: atapi.c,v 1.8 2002/03/03 19:37:41 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
575 ScsiPortNotification(RequestComplete,
576 DeviceExtension,
577 Srb);
578 ScsiPortNotification(NextRequest,
579 DeviceExtension,
580 NULL);
581 }
582 else
583 {
584 DPRINT1("SrbStatus = SRB_STATUS_PENDING\n");
585 }
586
587 DPRINT1("AtapiStartIo() done\n");
588
589 return(TRUE);
590 }
591
592
593 static BOOLEAN STDCALL
594 AtapiInterrupt(IN PVOID DeviceExtension)
595 {
596 PATAPI_MINIPORT_EXTENSION DevExt;
597 PSCSI_REQUEST_BLOCK Srb;
598 ULONG CommandPortBase;
599 ULONG ControlPortBase;
600
601 UCHAR DeviceStatus;
602 BOOLEAN IsLastBlock, AnErrorOccured, RequestIsComplete;
603 ULONG Retries;
604 NTSTATUS ErrorStatus;
605 ULONG ErrorInformation;
606 PUCHAR TargetAddress;
607
608
609
610 DPRINT("AtapiInterrupt() called!\n");
611
612 DevExt = (PATAPI_MINIPORT_EXTENSION)DeviceExtension;
613 if (DevExt->ExpectingInterrupt == FALSE)
614 {
615 return(FALSE);
616 }
617
618 DevExt->ExpectingInterrupt = FALSE;
619
620 Srb = DevExt->CurrentSrb;
621
622 DPRINT("Srb: %p\n", Srb);
623
624 CommandPortBase = DevExt->CommandPortBase;
625 ControlPortBase = DevExt->ControlPortBase;
626
627 DPRINT("CommandPortBase: %lx ControlPortBase: %lx\n", CommandPortBase, ControlPortBase);
628
629
630 IsLastBlock = FALSE;
631 AnErrorOccured = FALSE;
632 RequestIsComplete = FALSE;
633 ErrorStatus = STATUS_SUCCESS;
634 ErrorInformation = 0;
635
636 DeviceStatus = IDEReadStatus(CommandPortBase);
637
638 /* Handle error condition if it exists */
639 if (DeviceStatus & IDE_SR_ERR)
640 {
641 BYTE ErrorReg, SectorCount, SectorNum, CylinderLow, CylinderHigh;
642 BYTE DriveHead;
643
644 /* Log the error */
645 ErrorReg = IDEReadError(CommandPortBase);
646 CylinderLow = IDEReadCylinderLow(CommandPortBase);
647 CylinderHigh = IDEReadCylinderHigh(CommandPortBase);
648 DriveHead = IDEReadDriveHead(CommandPortBase);
649 SectorCount = IDEReadSectorCount(CommandPortBase);
650 SectorNum = IDEReadSectorNum(CommandPortBase);
651
652 /* FIXME: should use the NT error logging facility */
653 DbgPrint("ATAPT Error: OP:%02x STAT:%02x ERR:%02x CYLLO:%02x CYLHI:%02x SCNT:%02x SNUM:%02x\n",
654 0, //DeviceExtension->Operation,
655 DeviceStatus,
656 ErrorReg,
657 CylinderLow,
658 CylinderHigh,
659 SectorCount,
660 SectorNum);
661
662 /* FIXME: should retry the command and perhaps recalibrate the drive */
663
664 // Set error status information
665 AnErrorOccured = TRUE;
666 ErrorStatus = STATUS_DISK_OPERATION_FAILED;
667 #if 0
668 ErrorInformation =
669 (((((((CylinderHigh << 8) + CylinderLow) *
670 DeviceExtension->LogicalHeads) +
671 (DriveHead % DeviceExtension->LogicalHeads)) *
672 DeviceExtension->SectorsPerLogTrk) + SectorNum - 1) -
673 DeviceExtension->StartingSector) * DeviceExtension->BytesPerSector;
674 #endif
675 }
676 else
677 {
678 switch (Srb->Cdb[0])
679 {
680 case SCSIOP_READ:
681 DPRINT1("SCSIOP_READ\n");
682
683 /* Update controller/device state variables */
684 TargetAddress = Srb->DataBuffer;
685 Srb->DataBuffer += DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
686 Srb->DataTransferLength -= DevExt->DeviceParams[Srb->TargetId].BytesPerSector;
687 // DevExt->SectorsTransferred++;
688
689 /* Remember whether DRQ should be low at end (last block read) */
690 IsLastBlock = Srb->DataTransferLength == 0;
691
692 /* Wait for DRQ assertion */
693 for (Retries = 0; Retries < IDE_MAX_DRQ_RETRIES &&
694 !(IDEReadStatus(CommandPortBase) & IDE_SR_DRQ);
695 Retries++)
696 {
697 KeStallExecutionProcessor(10);
698 }
699
700 /* Copy the block of data */
701 IDEReadBlock(CommandPortBase,
702 TargetAddress,
703 IDE_SECTOR_BUF_SZ);
704
705 /* check DRQ */
706 if (IsLastBlock)
707 {
708 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES &&
709 (IDEReadStatus(CommandPortBase) & IDE_SR_BUSY);
710 Retries++)
711 {
712 KeStallExecutionProcessor(10);
713 }
714
715 /* Check for data overrun */
716 if (IDEReadStatus(CommandPortBase) & IDE_SR_DRQ)
717 {
718 AnErrorOccured = TRUE;
719 ErrorStatus = STATUS_DATA_OVERRUN;
720 ErrorInformation = 0;
721 }
722 else
723 {
724
725 #if 0
726 // Setup next transfer or set RequestIsComplete
727 if (DeviceExtension->BytesRequested >
728 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER)
729 {
730 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
731 DeviceExtension->SectorsTransferred = 0;
732 DeviceExtension->BytesToTransfer =
733 DeviceExtension->BytesPerSector * IDE_MAX_SECTORS_PER_XFER;
734 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
735 }
736 else if (DeviceExtension->BytesRequested > 0)
737 {
738 DeviceExtension->StartingSector += DeviceExtension->SectorsTransferred;
739 DeviceExtension->SectorsTransferred = 0;
740 DeviceExtension->BytesToTransfer = DeviceExtension->BytesRequested;
741 DeviceExtension->BytesRequested -= DeviceExtension->BytesToTransfer;
742 }
743 else
744 {
745 RequestIsComplete = TRUE;
746 }
747 #endif
748 RequestIsComplete = TRUE;
749 }
750 }
751 break;
752
753 case SCSIOP_WRITE:
754 DPRINT1("AtapiInterrupt(): SCSIOP_WRITE not implemented yet!\n");
755 RequestIsComplete = TRUE;
756 break;
757 }
758 }
759
760
761 /* If there was an error or the request is done, complete the packet */
762 if (AnErrorOccured || RequestIsComplete)
763 {
764 #if 0
765 /* Set the return status and info values */
766 Irp = ControllerExtension->CurrentIrp;
767 Irp->IoStatus.Status = ErrorStatus;
768 Irp->IoStatus.Information = ErrorInformation;
769
770 /* Clear out controller fields */
771 ControllerExtension->OperationInProgress = FALSE;
772 ControllerExtension->DeviceStatus = 0;
773
774 /* Queue the Dpc to finish up */
775 IoRequestDpc(DeviceExtension->DeviceObject,
776 Irp,
777 ControllerExtension);
778 #endif
779 }
780 else if (IsLastBlock)
781 {
782 #if 0
783 /* Else more data is needed, setup next device I/O */
784 IDEStartController((PVOID)DeviceExtension);
785 #endif
786 }
787
788 ScsiPortNotification(RequestComplete,
789 DeviceExtension,
790 Srb);
791
792 ScsiPortNotification(NextRequest,
793 DeviceExtension,
794 NULL);
795
796
797 DPRINT("AtapiInterrupt() done!\n");
798
799 return(TRUE);
800 }
801
802
803
804
805
806
807 // ---------------------------------------------------- Discardable statics
808
809
810 static BOOLEAN
811 AtapiFindDevices(PATAPI_MINIPORT_EXTENSION DeviceExtension,
812 PPORT_CONFIGURATION_INFORMATION ConfigInfo)
813 {
814 BOOLEAN DeviceFound = FALSE;
815 ULONG CommandPortBase;
816 ULONG ControlPortBase;
817 ULONG UnitNumber;
818 ULONG Retries;
819 BYTE High, Low;
820
821 DPRINT("AtapiFindDevices() called\n");
822
823 // CommandPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[0].RangeStart);
824 CommandPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[0].RangeStart);
825 DPRINT(" CommandPortBase: %x\n", CommandPortBase);
826
827 // ControlPortBase = ScsiPortConvertPhysicalAddressToUlong((*ConfigInfo->AccessRanges)[1].RangeStart);
828 ControlPortBase = ScsiPortConvertPhysicalAddressToUlong(ConfigInfo->AccessRanges[1].RangeStart);
829 DPRINT(" ControlPortBase: %x\n", ControlPortBase);
830
831 for (UnitNumber = 0; UnitNumber < 2; UnitNumber++)
832 {
833 /* disable interrupts */
834 IDEWriteDriveControl(ControlPortBase,
835 IDE_DC_nIEN);
836
837 /* select drive */
838 IDEWriteDriveHead(CommandPortBase,
839 IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
840 ScsiPortStallExecution(500);
841 IDEWriteCylinderHigh(CommandPortBase, 0);
842 IDEWriteCylinderLow(CommandPortBase, 0);
843 IDEWriteCommand(CommandPortBase, 0x08); /* IDE_COMMAND_ATAPI_RESET */
844 // ScsiPortStallExecution(1000*1000);
845 // IDEWriteDriveHead(CommandPortBase,
846 // IDE_DH_FIXED | (UnitNumber ? IDE_DH_DRV1 : 0));
847 // IDE_DH_FIXED);
848
849 for (Retries = 0; Retries < 20000; Retries++)
850 {
851 if (!(IDEReadStatus(CommandPortBase) & IDE_SR_BUSY))
852 {
853 break;
854 }
855 ScsiPortStallExecution(150);
856 }
857 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
858 {
859 DbgPrint("Timeout on drive %lu\n", UnitNumber);
860 return(DeviceFound);
861 }
862
863 High = IDEReadCylinderHigh(CommandPortBase);
864 Low = IDEReadCylinderLow(CommandPortBase);
865
866 DPRINT(" Check drive %lu: High 0x%x Low 0x%x\n",
867 UnitNumber,
868 High,
869 Low);
870
871 if (High == 0xEB && Low == 0x14)
872 {
873 if (AtapiIdentifyDevice(CommandPortBase,
874 ControlPortBase,
875 UnitNumber,
876 TRUE,
877 &DeviceExtension->DeviceParams[UnitNumber]))
878 {
879 DPRINT(" ATAPI drive found!\n");
880 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
881 DeviceExtension->DeviceAtapi[UnitNumber] = TRUE;
882 DeviceFound = TRUE;
883 }
884 else
885 {
886 DPRINT(" No ATAPI drive found!\n");
887 }
888 }
889 else
890 {
891 if (AtapiIdentifyDevice(CommandPortBase,
892 ControlPortBase,
893 UnitNumber,
894 FALSE,
895 &DeviceExtension->DeviceParams[UnitNumber]))
896 {
897 DPRINT(" IDE drive found!\n");
898 DeviceExtension->DevicePresent[UnitNumber] = TRUE;
899 DeviceExtension->DeviceAtapi[UnitNumber] = FALSE;
900 DeviceFound = TRUE;
901 }
902 else
903 {
904 DPRINT(" No IDE drive found!\n");
905 }
906 }
907 }
908
909 DPRINT("AtapiFindDrives() done\n");
910
911 return(DeviceFound);
912 }
913
914
915 // AtapiResetController
916 //
917 // DESCRIPTION:
918 // Reset the controller and report completion status
919 //
920 // RUN LEVEL:
921 // PASSIVE_LEVEL
922 //
923 // ARGUMENTS:
924 // IN WORD CommandPort The address of the command port
925 // IN WORD ControlPort The address of the control port
926 //
927 // RETURNS:
928 //
929
930 static BOOLEAN
931 AtapiResetController(IN WORD CommandPort,
932 IN WORD ControlPort)
933 {
934 int Retries;
935
936 /* Assert drive reset line */
937 IDEWriteDriveControl(ControlPort, IDE_DC_SRST);
938
939 /* Wait for min. 25 microseconds */
940 ScsiPortStallExecution(IDE_RESET_PULSE_LENGTH);
941
942 /* Negate drive reset line */
943 IDEWriteDriveControl(ControlPort, 0);
944
945 /* Wait for BUSY negation */
946 for (Retries = 0; Retries < IDE_RESET_BUSY_TIMEOUT * 1000; Retries++)
947 {
948 if (!(IDEReadStatus(CommandPort) & IDE_SR_BUSY))
949 {
950 break;
951 }
952 ScsiPortStallExecution(10);
953 }
954
955 CHECKPOINT;
956 if (Retries >= IDE_RESET_BUSY_TIMEOUT * 1000)
957 {
958 return(FALSE);
959 }
960
961 CHECKPOINT;
962
963 // return TRUE if controller came back to life. and
964 // the registers are initialized correctly
965 return(IDEReadError(CommandPort) == 1);
966 }
967
968 /*
969 * AtapiIdentifyDevice
970 *
971 * DESCRIPTION:
972 * Get the identification block from the drive
973 *
974 * RUN LEVEL:
975 * PASSIVE_LEVEL
976 *
977 * ARGUMENTS:
978 * CommandPort
979 * Address of the command port
980 * ControlPort
981 * Address of the control port
982 * DriveNum
983 * The drive index (0,1)
984 * Atapi
985 * Send an ATA(FALSE) or an ATAPI(TRUE) identify comand
986 * DrvParms
987 * Address to write drive ident block
988 *
989 * RETURNS:
990 * TRUE: The drive identification block was retrieved successfully
991 * FALSE: an error ocurred
992 */
993
994 static BOOLEAN
995 AtapiIdentifyDevice(IN ULONG CommandPort,
996 IN ULONG ControlPort,
997 IN ULONG DriveNum,
998 IN BOOLEAN Atapi,
999 OUT PIDE_DRIVE_IDENTIFY DrvParms)
1000 {
1001 /* Get the Drive Identify block from drive or die */
1002 if (AtapiPolledRead((WORD)CommandPort,
1003 (WORD)ControlPort,
1004 0,
1005 1,
1006 0,
1007 0,
1008 0,
1009 (DriveNum ? IDE_DH_DRV1 : 0),
1010 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
1011 (BYTE *)DrvParms) != 0) /* atapi_identify */
1012 {
1013 DPRINT1("IDEPolledRead() failed\n");
1014 return FALSE;
1015 }
1016
1017 /* Report on drive parameters if debug mode */
1018 IDESwapBytePairs(DrvParms->SerialNumber, 20);
1019 IDESwapBytePairs(DrvParms->FirmwareRev, 8);
1020 IDESwapBytePairs(DrvParms->ModelNumber, 40);
1021 DPRINT("Config:%04x Cyls:%5d Heads:%2d Sectors/Track:%3d Gaps:%02d %02d\n",
1022 DrvParms->ConfigBits,
1023 DrvParms->LogicalCyls,
1024 DrvParms->LogicalHeads,
1025 DrvParms->SectorsPerTrack,
1026 DrvParms->InterSectorGap,
1027 DrvParms->InterSectorGapSize);
1028 DPRINT("Bytes/PLO:%3d Vendor Cnt:%2d Serial number:[%.20s]\n",
1029 DrvParms->BytesInPLO,
1030 DrvParms->VendorUniqueCnt,
1031 DrvParms->SerialNumber);
1032 DPRINT("Cntlr type:%2d BufSiz:%5d ECC bytes:%3d Firmware Rev:[%.8s]\n",
1033 DrvParms->ControllerType,
1034 DrvParms->BufferSize * IDE_SECTOR_BUF_SZ,
1035 DrvParms->ECCByteCnt,
1036 DrvParms->FirmwareRev);
1037 DPRINT("Model:[%.40s]\n", DrvParms->ModelNumber);
1038 DPRINT("RWMult?:%02x LBA:%d DMA:%d MinPIO:%d ns MinDMA:%d ns\n",
1039 (DrvParms->RWMultImplemented) & 0xff,
1040 (DrvParms->Capabilities & IDE_DRID_LBA_SUPPORTED) ? 1 : 0,
1041 (DrvParms->Capabilities & IDE_DRID_DMA_SUPPORTED) ? 1 : 0,
1042 DrvParms->MinPIOTransTime,
1043 DrvParms->MinDMATransTime);
1044 DPRINT("TM:Cyls:%d Heads:%d Sectors/Trk:%d Capacity:%ld\n",
1045 DrvParms->TMCylinders,
1046 DrvParms->TMHeads,
1047 DrvParms->TMSectorsPerTrk,
1048 (ULONG)(DrvParms->TMCapacityLo + (DrvParms->TMCapacityHi << 16)));
1049 DPRINT("TM:SectorCount: 0x%04x%04x = %lu\n",
1050 DrvParms->TMSectorCountHi,
1051 DrvParms->TMSectorCountLo,
1052 (ULONG)((DrvParms->TMSectorCountHi << 16) + DrvParms->TMSectorCountLo));
1053
1054 DPRINT("BytesPerSector %d\n", DrvParms->BytesPerSector);
1055 if (DrvParms->BytesPerSector == 0)
1056 DrvParms->BytesPerSector = 512;
1057 return TRUE;
1058 }
1059
1060
1061 // AtapiPolledRead
1062 //
1063 // DESCRIPTION:
1064 // Read a sector of data from the drive in a polled fashion.
1065 //
1066 // RUN LEVEL:
1067 // PASSIVE_LEVEL
1068 //
1069 // ARGUMENTS:
1070 // IN WORD Address Address of command port for drive
1071 // IN BYTE PreComp Value to write to precomp register
1072 // IN BYTE SectorCnt Value to write to sectorCnt register
1073 // IN BYTE SectorNum Value to write to sectorNum register
1074 // IN BYTE CylinderLow Value to write to CylinderLow register
1075 // IN BYTE CylinderHigh Value to write to CylinderHigh register
1076 // IN BYTE DrvHead Value to write to Drive/Head register
1077 // IN BYTE Command Value to write to Command register
1078 // OUT BYTE *Buffer Buffer for output data
1079 //
1080 // RETURNS:
1081 // int 0 is success, non 0 is an error code
1082 //
1083
1084 static int
1085 AtapiPolledRead(IN WORD Address,
1086 IN WORD ControlPort,
1087 IN BYTE PreComp,
1088 IN BYTE SectorCnt,
1089 IN BYTE SectorNum,
1090 IN BYTE CylinderLow,
1091 IN BYTE CylinderHigh,
1092 IN BYTE DrvHead,
1093 IN BYTE Command,
1094 OUT BYTE *Buffer)
1095 {
1096 ULONG SectorCount = 0;
1097 ULONG RetryCount;
1098 BOOLEAN Junk = FALSE;
1099 UCHAR Status;
1100 UCHAR Control;
1101
1102 /* Disable interrupts */
1103 Control = IDEReadAltStatus(ControlPort);
1104 IDEWriteDriveControl(ControlPort, Control | IDE_DC_nIEN);
1105
1106 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1107 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1108 {
1109 Status = IDEReadStatus(Address);
1110 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1111 {
1112 break;
1113 }
1114 ScsiPortStallExecution(10);
1115 }
1116 if (RetryCount == IDE_MAX_BUSY_RETRIES)
1117 {
1118 return(IDE_ER_ABRT);
1119 }
1120
1121 /* Write Drive/Head to select drive */
1122 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1123
1124 /* Wait for STATUS.BUSY and STATUS.DRQ to clear */
1125 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1126 {
1127 Status = IDEReadStatus(Address);
1128 if (!(Status & IDE_SR_BUSY) && !(Status & IDE_SR_DRQ))
1129 {
1130 break;
1131 }
1132 ScsiPortStallExecution(10);
1133 }
1134 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
1135 {
1136 return IDE_ER_ABRT;
1137 }
1138
1139 /* Issue command to drive */
1140 if (DrvHead & IDE_DH_LBA)
1141 {
1142 DPRINT("READ:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1143 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1144 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
1145 SectorCnt,
1146 Command);
1147 }
1148 else
1149 {
1150 DPRINT("READ:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1151 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1152 CylinderHigh,
1153 CylinderLow,
1154 DrvHead & 0x0f,
1155 SectorNum,
1156 SectorCnt,
1157 Command);
1158 }
1159
1160 /* Setup command parameters */
1161 IDEWritePrecomp(Address, PreComp);
1162 IDEWriteSectorCount(Address, SectorCnt);
1163 IDEWriteSectorNum(Address, SectorNum);
1164 IDEWriteCylinderHigh(Address, CylinderHigh);
1165 IDEWriteCylinderLow(Address, CylinderLow);
1166 IDEWriteDriveHead(Address, IDE_DH_FIXED | DrvHead);
1167
1168 /* Issue the command */
1169 IDEWriteCommand(Address, Command);
1170 ScsiPortStallExecution(50);
1171
1172 /* wait for DRQ or error */
1173 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
1174 {
1175 Status = IDEReadStatus(Address);
1176 if (!(Status & IDE_SR_BUSY))
1177 {
1178 if (Status & IDE_SR_ERR)
1179 {
1180 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1181 return(IDE_ER_ABRT);
1182 }
1183 if (Status & IDE_SR_DRQ)
1184 {
1185 break;
1186 }
1187 else
1188 {
1189 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1190 return(IDE_ER_ABRT);
1191 }
1192 }
1193 ScsiPortStallExecution(10);
1194 }
1195
1196 /* timed out */
1197 if (RetryCount >= IDE_MAX_POLL_RETRIES)
1198 {
1199 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1200 return(IDE_ER_ABRT);
1201 }
1202
1203 while (1)
1204 {
1205 /* Read data into buffer */
1206 if (Junk == FALSE)
1207 {
1208 IDEReadBlock(Address, Buffer, IDE_SECTOR_BUF_SZ);
1209 Buffer += IDE_SECTOR_BUF_SZ;
1210 }
1211 else
1212 {
1213 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
1214 IDEReadBlock(Address, JunkBuffer, IDE_SECTOR_BUF_SZ);
1215 }
1216 SectorCount++;
1217
1218 /* Check for error or more sectors to read */
1219 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
1220 {
1221 Status = IDEReadStatus(Address);
1222 if (!(Status & IDE_SR_BUSY))
1223 {
1224 if (Status & IDE_SR_ERR)
1225 {
1226 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1227 return(IDE_ER_ABRT);
1228 }
1229 if (Status & IDE_SR_DRQ)
1230 {
1231 if (SectorCount >= SectorCnt)
1232 {
1233 DPRINT("Buffer size exceeded!\n");
1234 Junk = TRUE;
1235 }
1236 break;
1237 }
1238 else
1239 {
1240 if (SectorCount > SectorCnt)
1241 {
1242 DPRINT("Read %lu sectors of junk!\n",
1243 SectorCount - SectorCnt);
1244 }
1245 IDEWriteDriveControl(ControlPort, Control & ~IDE_DC_nIEN);
1246 return(0);
1247 }
1248 }
1249 }
1250 }
1251 }
1252
1253
1254 // ------------------------------------------- Nondiscardable statics
1255
1256 static ULONG
1257 AtapiSendAtapiCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1258 IN PSCSI_REQUEST_BLOCK Srb)
1259 {
1260 DPRINT1("AtapiSendAtapiComamnd() called!\n");
1261 DPRINT1("Not implemented yet!\n");
1262 return(SRB_STATUS_SELECTION_TIMEOUT);
1263 }
1264
1265
1266 static ULONG
1267 AtapiSendIdeCommand(IN PATAPI_MINIPORT_EXTENSION DeviceExtension,
1268 IN PSCSI_REQUEST_BLOCK Srb)
1269 {
1270 ULONG SrbStatus = SRB_STATUS_SUCCESS;
1271
1272 DPRINT1("AtapiSendIdeCommand() called!\n");
1273
1274 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n",
1275 Srb->PathId,
1276 Srb->TargetId,
1277 Srb->Lun);
1278
1279 switch (Srb->Cdb[0])
1280 {
1281 case SCSIOP_INQUIRY:
1282 SrbStatus = AtapiInquiry(DeviceExtension,
1283 Srb);
1284 break;
1285
1286 case SCSIOP_READ_CAPACITY:
1287 SrbStatus = AtapiReadCapacity(DeviceExtension,
1288 Srb);
1289 break;
1290
1291 case SCSIOP_READ:
1292 case SCSIOP_WRITE:
1293 SrbStatus = AtapiReadWrite(DeviceExtension,
1294 Srb);
1295 break;
1296
1297 case SCSIOP_MODE_SENSE:
1298 case SCSIOP_TEST_UNIT_READY:
1299 case SCSIOP_VERIFY:
1300 case SCSIOP_START_STOP_UNIT:
1301 case SCSIOP_REQUEST_SENSE:
1302 break;
1303
1304 default:
1305 DPRINT1("AtapiSendIdeCommand():unknown command %x\n",
1306 Srb->Cdb[0]);
1307 SrbStatus = SRB_STATUS_INVALID_REQUEST;
1308 break;
1309 }
1310
1311 DPRINT1("AtapiSendIdeCommand() done!\n");
1312
1313 return(SrbStatus);
1314 }
1315
1316
1317 static ULONG
1318 AtapiInquiry(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1319 PSCSI_REQUEST_BLOCK Srb)
1320 {
1321 PIDE_DRIVE_IDENTIFY DeviceParams;
1322 PINQUIRYDATA InquiryData;
1323 ULONG i;
1324
1325 DPRINT1("SCSIOP_INQUIRY: TargetId: %lu\n", Srb->TargetId);
1326
1327 if ((Srb->PathId != 0) ||
1328 (Srb->TargetId > 1) ||
1329 (Srb->Lun != 0) ||
1330 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1331 {
1332 return(SRB_STATUS_SELECTION_TIMEOUT);
1333 }
1334
1335 InquiryData = Srb->DataBuffer;
1336 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1337
1338 /* clear buffer */
1339 for (i = 0; i < Srb->DataTransferLength; i++)
1340 {
1341 ((PUCHAR)Srb->DataBuffer)[i] = 0;
1342 }
1343
1344 /* set device class */
1345 if (DeviceExtension->DeviceAtapi[Srb->TargetId] == FALSE)
1346 {
1347 /* hard-disk */
1348 InquiryData->DeviceType = DIRECT_ACCESS_DEVICE;
1349 }
1350 else
1351 {
1352 /* FIXME: this is incorrect use SCSI-INQUIRY command!! */
1353 /* cdrom drive */
1354 InquiryData->DeviceType = READ_ONLY_DIRECT_ACCESS_DEVICE;
1355 }
1356
1357 DPRINT("ConfigBits: 0x%x\n", DeviceParams->ConfigBits);
1358 if (DeviceParams->ConfigBits & 0x80)
1359 {
1360 DPRINT1("Removable media!\n");
1361 InquiryData->RemovableMedia = 1;
1362 }
1363
1364 for (i = 0; i < 20; i += 2)
1365 {
1366 InquiryData->VendorId[i] =
1367 ((PUCHAR)DeviceParams->ModelNumber)[i];
1368 InquiryData->VendorId[i+1] =
1369 ((PUCHAR)DeviceParams->ModelNumber)[i+1];
1370 }
1371
1372 for (i = 0; i < 4; i++)
1373 {
1374 InquiryData->ProductId[12+i] = ' ';
1375 }
1376
1377 for (i = 0; i < 4; i += 2)
1378 {
1379 InquiryData->ProductRevisionLevel[i] =
1380 ((PUCHAR)DeviceParams->FirmwareRev)[i];
1381 InquiryData->ProductRevisionLevel[i+1] =
1382 ((PUCHAR)DeviceParams->FirmwareRev)[i+1];
1383 }
1384
1385 return(SRB_STATUS_SUCCESS);
1386 }
1387
1388
1389 static ULONG
1390 AtapiReadCapacity(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1391 PSCSI_REQUEST_BLOCK Srb)
1392 {
1393 PREAD_CAPACITY_DATA CapacityData;
1394 PIDE_DRIVE_IDENTIFY DeviceParams;
1395 ULONG LastSector;
1396
1397 DPRINT1("SCSIOP_READ_CAPACITY: TargetId: %lu\n", Srb->TargetId);
1398
1399 if ((Srb->PathId != 0) ||
1400 (Srb->TargetId > 1) ||
1401 (Srb->Lun != 0) ||
1402 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1403 {
1404 return(SRB_STATUS_SELECTION_TIMEOUT);
1405 }
1406
1407
1408 CapacityData = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
1409 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1410
1411 /* Set sector (block) size to 512 bytes (big-endian). */
1412 CapacityData->BytesPerBlock = 0x20000;
1413
1414 /* Calculate last sector (big-endian). */
1415 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1416 {
1417 LastSector = (ULONG)((DeviceParams->TMSectorCountHi << 16) +
1418 DeviceParams->TMSectorCountLo) - 1;
1419 }
1420 else
1421 {
1422 LastSector = (ULONG)(DeviceParams->LogicalCyls *
1423 DeviceParams->LogicalHeads *
1424 DeviceParams->SectorsPerTrack)-1;
1425 }
1426
1427 CapacityData->LogicalBlockAddress = (((PUCHAR)&LastSector)[0] << 24) |
1428 (((PUCHAR)&LastSector)[1] << 16) |
1429 (((PUCHAR)&LastSector)[2] << 8) |
1430 ((PUCHAR)&LastSector)[3];
1431
1432 DPRINT("LastCount: %lu (%08lx / %08lx)\n",
1433 LastSector,
1434 LastSector,
1435 CapacityData->LogicalBlockAddress);
1436
1437 return(SRB_STATUS_SUCCESS);
1438 }
1439
1440
1441 static ULONG
1442 AtapiReadWrite(PATAPI_MINIPORT_EXTENSION DeviceExtension,
1443 PSCSI_REQUEST_BLOCK Srb)
1444 {
1445 PIDE_DRIVE_IDENTIFY DeviceParams;
1446
1447 ULONG StartingSector,i;
1448 ULONG SectorCount;
1449 UCHAR CylinderHigh;
1450 UCHAR CylinderLow;
1451 UCHAR DrvHead;
1452 UCHAR SectorNumber;
1453 UCHAR Command;
1454 ULONG Retries;
1455 UCHAR Status;
1456
1457
1458 DPRINT1("AtapiReadWrite() called!\n");
1459
1460 if ((Srb->PathId != 0) ||
1461 (Srb->TargetId > 1) ||
1462 (Srb->Lun != 0) ||
1463 (DeviceExtension->DevicePresent[Srb->TargetId] == FALSE))
1464 {
1465 return(SRB_STATUS_SELECTION_TIMEOUT);
1466 }
1467
1468 DPRINT("SCSIOP_WRITE: TargetId: %lu\n",
1469 Srb->TargetId);
1470
1471 DeviceParams = &DeviceExtension->DeviceParams[Srb->TargetId];
1472
1473 /* Get starting sector number from CDB. */
1474 StartingSector = ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte3 |
1475 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte2 << 8 |
1476 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte1 << 16 |
1477 ((PCDB)Srb->Cdb)->CDB10.LogicalBlockByte0 << 24;
1478
1479 SectorCount = (Srb->DataTransferLength + DeviceParams->BytesPerSector - 1) /
1480 DeviceParams->BytesPerSector;
1481
1482 DPRINT("Starting sector %lu Number of bytes %lu Sectors %lu\n",
1483 StartingSector,
1484 Srb->DataTransferLength,
1485 SectorCount);
1486
1487 if (DeviceParams->Capabilities & IDE_DRID_LBA_SUPPORTED)
1488 {
1489 SectorNumber = StartingSector & 0xff;
1490 CylinderLow = (StartingSector >> 8) & 0xff;
1491 CylinderHigh = (StartingSector >> 16) & 0xff;
1492 DrvHead = ((StartingSector >> 24) & 0x0f) |
1493 (Srb->TargetId ? IDE_DH_DRV1 : 0) |
1494 IDE_DH_LBA;
1495 }
1496 else
1497 {
1498 SectorNumber = (StartingSector % DeviceParams->SectorsPerTrack) + 1;
1499 StartingSector /= DeviceParams->SectorsPerTrack;
1500 DrvHead = (StartingSector % DeviceParams->LogicalHeads) |
1501 (Srb->TargetId ? IDE_DH_DRV1 : 0);
1502 StartingSector /= DeviceParams->LogicalHeads;
1503 CylinderLow = StartingSector & 0xff;
1504 CylinderHigh = StartingSector >> 8;
1505 }
1506
1507
1508 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN)
1509 {
1510 Command = IDE_CMD_READ;
1511 }
1512 else
1513 {
1514 Command = IDE_CMD_WRITE;
1515 }
1516
1517 if (DrvHead & IDE_DH_LBA)
1518 {
1519 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=1:BLK=%08d:SC=%02x:CM=%02x\n",
1520 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1521 DeviceExtension->CommandPortBase,
1522 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1523 ((DrvHead & 0x0f) << 24) +
1524 (CylinderHigh << 16) + (CylinderLow << 8) + SectorNumber,
1525 SectorCount,
1526 Command);
1527 }
1528 else
1529 {
1530 DPRINT1("%s:BUS=%04x:DRV=%d:LBA=0:CH=%02x:CL=%02x:HD=%01x:SN=%02x:SC=%02x:CM=%02x\n",
1531 (Srb->SrbFlags & SRB_FLAGS_DATA_IN) ? "READ" : "WRITE",
1532 DeviceExtension->CommandPortBase,
1533 DrvHead & IDE_DH_DRV1 ? 1 : 0,
1534 CylinderHigh,
1535 CylinderLow,
1536 DrvHead & 0x0f,
1537 SectorNumber,
1538 SectorCount,
1539 Command);
1540 }
1541
1542 /* Set pointer to data buffer. */
1543 DeviceExtension->DataBuffer = (PUSHORT)Srb->DataBuffer;
1544
1545 DeviceExtension->CurrentSrb = Srb;
1546 DeviceExtension->ExpectingInterrupt = TRUE;
1547
1548
1549
1550 /* wait for BUSY to clear */
1551 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1552 {
1553 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1554 if (!(Status & IDE_SR_BUSY))
1555 {
1556 break;
1557 }
1558 ScsiPortStallExecution(10);
1559 }
1560 DPRINT ("status=%02x\n", Status);
1561 DPRINT ("waited %ld usecs for busy to clear\n", Retries * 10);
1562 if (Retries >= IDE_MAX_BUSY_RETRIES)
1563 {
1564 DPRINT ("Drive is BUSY for too long\n");
1565 return(SRB_STATUS_BUSY);
1566 #if 0
1567 if (++ControllerExtension->Retries > IDE_MAX_CMD_RETRIES)
1568 {
1569 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1570 Irp = ControllerExtension->CurrentIrp;
1571 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1572 Irp->IoStatus.Information = 0;
1573
1574 return FALSE;
1575 }
1576 else
1577 {
1578 DPRINT ("Beginning drive reset sequence\n");
1579 IDEBeginControllerReset(ControllerExtension);
1580
1581 return TRUE;
1582 }
1583 #endif
1584 }
1585
1586 /* Select the desired drive */
1587 IDEWriteDriveHead(DeviceExtension->CommandPortBase,
1588 IDE_DH_FIXED | DrvHead);
1589
1590 /* wait for BUSY to clear and DRDY to assert */
1591 for (Retries = 0; Retries < IDE_MAX_BUSY_RETRIES; Retries++)
1592 {
1593 Status = IDEReadStatus(DeviceExtension->CommandPortBase);
1594 if (!(Status & IDE_SR_BUSY) && (Status & IDE_SR_DRDY))
1595 {
1596 break;
1597 }
1598 ScsiPortStallExecution(10);
1599 }
1600 DPRINT ("waited %ld usecs for busy to clear after drive select\n", Retries * 10);
1601 if (Retries >= IDE_MAX_BUSY_RETRIES)
1602 {
1603 DPRINT ("Drive is BUSY for too long after drive select\n");
1604 return(SRB_STATUS_BUSY);
1605 #if 0
1606 if (ControllerExtension->Retries++ > IDE_MAX_CMD_RETRIES)
1607 {
1608 DbgPrint ("Max Retries on Drive reset reached, returning failure\n");
1609 Irp = ControllerExtension->CurrentIrp;
1610 Irp->IoStatus.Status = STATUS_DISK_OPERATION_FAILED;
1611 Irp->IoStatus.Information = 0;
1612
1613 return FALSE;
1614 }
1615 else
1616 {
1617 DPRINT ("Beginning drive reset sequence\n");
1618 IDEBeginControllerReset(ControllerExtension);
1619
1620 return TRUE;
1621 }
1622 #endif
1623 }
1624
1625 if (Command == IDE_CMD_WRITE)
1626 {
1627 DPRINT1("Write not implemented yet!\n");
1628 return(SRB_STATUS_SUCCESS);
1629 }
1630
1631 /* Indicate expecting an interrupt. */
1632 DeviceExtension->ExpectingInterrupt = TRUE;
1633
1634 /* Setup command parameters */
1635 IDEWritePrecomp(DeviceExtension->CommandPortBase, 0);
1636 IDEWriteSectorCount(DeviceExtension->CommandPortBase, SectorCount);
1637 IDEWriteSectorNum(DeviceExtension->CommandPortBase, SectorNumber);
1638 IDEWriteCylinderHigh(DeviceExtension->CommandPortBase, CylinderHigh);
1639 IDEWriteCylinderLow(DeviceExtension->CommandPortBase, CylinderLow);
1640 IDEWriteDriveHead(DeviceExtension->CommandPortBase, IDE_DH_FIXED | DrvHead);
1641
1642 /* Issue command to drive */
1643 IDEWriteCommand(DeviceExtension->CommandPortBase, Command);
1644 // ControllerExtension->TimerState = IDETimerCmdWait;
1645 // ControllerExtension->TimerCount = IDE_CMD_TIMEOUT;
1646
1647
1648 /* FIXME: Write data here! */
1649
1650
1651 DPRINT1("AtapiReadWrite() done!\n");
1652
1653 /* Wait for interrupt. */
1654 return(SRB_STATUS_PENDING);
1655 }
1656
1657 /* EOF */