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