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