File:  [WindowsNT SDKs] / ntddk / src / scsi / qic117 / q117i_nt.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:31:12 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntddk-nov-1993, HEAD
Microsoft Windows NT Build 511 (DDK SDK) 11-01-1993

/*++

Copyright (c) 1993 - Colorado Memory Systems, Inc.
All Rights Reserved

Module Name:

    q117i_nt.c

Abstract:

    NT device driver entry point,  NT interface routines,
    and thread for low-level irp functions.

Revision History:




--*/

#include "ntddk.h"                        // various NT definitions
#include "ntdddisk.h"                    // disk device driver I/O control codes
#include "common.h"
#include "drvtask.h"                    // this driver's data declarations
#include "mt1defs.h"                    // this driver's data declarations
#include "mt1strc.h"                    // this driver's data declarations
#include "q117data.h"               // this driver's data declarations
#include "hilevel.h"

//
// This is the actual definition of FloppyDebugLevel.
// Note that it is only defined if this is a "debug"
// build.
//
#if DBG
// extern ULONG QIC117DebugLevel = QIC117DBGP | QIC117WARN | QIC117INFO |
//                                QIC117SHOWTD | QIC117SHOWQD |
//                                QIC117SHOWPOLL | QIC117STOP |
//                                QIC117MAKEBAD | QIC117SHOWBAD |
//                                QIC117DRVSTAT;

extern ULONG QIC117DebugLevel = 0x00000000;
//extern ULONG QIC117DebugLevel =  QIC117SHOWTD | QIC117DBGP | QIC117WARN | QIC117INFO;

#endif

#ifdef ALLOC_PRAGMA
#pragma alloc_text(init,DriverEntry)
#endif


NTSTATUS
DriverEntry(
   IN OUT PDRIVER_OBJECT DriverObject,
   IN PUNICODE_STRING RegistryPath
   )

/*++

Routine Description:

   This routine is the driver's entry point, called by the I/O system
   to load the driver. This routine can be called any number of times,
   as long as the IO system and the configuration manager conspire to
   give it an unmanaged controller to support at each call.    It could
   also be called a single time and given all of the controllers at
   once.

   It initializes the passed-in driver object, calls the configuration
   manager to learn about the devices that it is to support, and for
   each controller to be supported it calls a routine to initialize the
   controller (and all drives attached to it).

Arguments:

   DriverObject - a pointer to the object that represents this device
   driver.

Return Value:

   If we successfully initialize at least one drive, STATUS_SUCCESS is
   returned.

   If we don't (because the configuration manager returns an error, or
   the configuration manager says that there are no controllers or
   drives to support, or no controllers or drives can be successfully
   initialized), then the last error encountered is propogated.

--*/

{
   PCONFIG_DATA configData;            // pointer to config mgr's returned data
   NTSTATUS ntStatus;
   UCHAR controllerNumber;
   BOOLEAN partlySuccessful = FALSE;   // TRUE if any controller init'd properly

   UNREFERENCED_PARAMETER(RegistryPath);
   CheckedDump(QIC117INFO,( "DriverEntry...\n" ));

   //
   // Ask configuration manager for information on the hardware that
   // we're supposed to support.
   //

#if DBG

//    DbgBreakPoint();

#endif

   ntStatus = Q117iGetConfigurationInformation( &configData );

   //
   // If Q117iGetConfigurationInformation() failed, just exit and propogate
   // the error.   If it said that there are no controllers to support,
   // return an error.
   // Otherwise, try to init the controllers.  If at least one succeeds,
   // return STATUS_SUCCESS, otherwise return the last error.
   //

   configData->FloppyTapeCount = 0;

   if ( NT_SUCCESS( ntStatus ) ) {

      //
      // Call Q117iInitializeController() for each controller (and its
      // attached drives) that we're supposed to support.
      //
      // Return success if we successfully initialize at least one
      // device; propogate error otherwise.   Set an error first in
      // case there aren't any controllers.
      //

      ntStatus = STATUS_NO_SUCH_DEVICE;

      for ( controllerNumber = 0;
               controllerNumber < configData->NumberOfControllers;
               controllerNumber++ ) {

            ntStatus = Q117iInitializeController(
               configData,
               controllerNumber,
               DriverObject,
               RegistryPath );

            if ( NT_SUCCESS( ntStatus ) ) {

               partlySuccessful = TRUE;
            }
      }

      if ( partlySuccessful ) {

            ntStatus = STATUS_SUCCESS;

            //
            // Initialize the driver object with this driver's entry points.
            //

            DriverObject->MajorFunction[IRP_MJ_READ] =
               q117Read;
            DriverObject->MajorFunction[IRP_MJ_WRITE] =
               q117Write;
            DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] =
               q117DeviceControl;
            DriverObject->MajorFunction[IRP_MJ_CREATE] =
               q117Create;
            DriverObject->MajorFunction[IRP_MJ_CLOSE] =
               q117Close;
            //DriverObject->MajorFunction[IRP_MJ_CLEANUP] =
            //    q117Cleanup;
            DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
               Q117iTapeDispatchInternalDeviceControl;
      }
   }

   //
   // NOTE: FUTURE delete configdata, if config mgr design calls for it
   //

#if DBG

   if ( !NT_SUCCESS( ntStatus ) ) {

      CheckedDump((QIC117INFO | QIC117DBGP),( "q117i: exiting with error %lx\n", ntStatus ));
   }

#endif

   if (configData) {

      ExFreePool(configData);

   }

   return ntStatus;
}

NTSTATUS
Q117iTapeDispatchInternalDeviceControl(
   IN PDEVICE_OBJECT DeviceObject,
   IN OUT PIRP Irp
   )

/*++

Routine Description:

   This routine is called by the I/O system to perform a device I/O
   control function.

Arguments:

   DeviceObject - a pointer to the object that represents the device
   that I/O is to be done on.

   Irp - a pointer to the I/O Request Packet for this request.

Return Value:

   STATUS_SUCCESS or STATUS_PENDING if recognized I/O control code,
   STATUS_INVALID_DEVICE_REQUEST otherwise.

--*/

{
   PIO_STACK_LOCATION irpSp;
   NTSTATUS ntStatus;
   PTAPE_EXTENSION tapeExtension;

   tapeExtension = DeviceObject->DeviceExtension;

   irpSp = IoGetCurrentIrpStackLocation( Irp );


   switch( irpSp->Parameters.DeviceIoControl.IoControlCode) {

   case IOCTL_QIC117_CLEAR_QUEUE:

   (VOID) KeResetEvent( &tapeExtension->QControllerData->ClearQueueEvent );

   tapeExtension->QControllerData->ClearQueue = TRUE;
   tapeExtension->QControllerData->AbortRequested = TRUE;

            IoMarkIrpPending( Irp );

      (VOID) ExInterlockedInsertTailList(
            &tapeExtension->QControllerData->ListEntry,
            &Irp->Tail.Overlay.ListEntry,
            &tapeExtension->QControllerData->ListSpinLock );

      (VOID) KeReleaseSemaphore(
            &tapeExtension->QControllerData->RequestSemaphore,
            (KPRIORITY) 0,
            1,
            FALSE );


   (VOID) KeWaitForSingleObject(
            (PVOID) &tapeExtension->QControllerData->ClearQueueEvent,
            Suspended,
            KernelMode,
            FALSE,
            (PLARGE_INTEGER) NULL );

   tapeExtension->QControllerData->ClearQueue = FALSE;
      ntStatus = STATUS_SUCCESS;

      break;

   case IOCTL_QIC117_DRIVE_REQUEST:

            IoMarkIrpPending( Irp );

      (VOID) ExInterlockedInsertTailList(
            &tapeExtension->QControllerData->ListEntry,
            &Irp->Tail.Overlay.ListEntry,
            &tapeExtension->QControllerData->ListSpinLock );

      (VOID) KeReleaseSemaphore(
            &tapeExtension->QControllerData->RequestSemaphore,
            (KPRIORITY) 0,
            1,
            FALSE );

      ntStatus = STATUS_PENDING;
      break;

   default:
      CheckedDump(QIC117DBGP,("q117i: invalid device request %x\n",
      irpSp->Parameters.DeviceIoControl.IoControlCode ));

      ntStatus = STATUS_INVALID_DEVICE_REQUEST;

   }

   return ntStatus;
}

BOOLEAN
Q117iTapeInterruptService(
   IN PKINTERRUPT Interrupt,
   IN OUT PVOID Context
   )

/*++

Routine Description:

   This routine is called at DIRQL by the system when the controller
   interrupts.

Arguments:

   Interrupt - a pointer to the interrupt object.

   Context - a pointer to our controller data area for the controller
   that interrupted.   (This was set up by the call to
   IoConnectInterrupt).

Return Value:

   Normally returns TRUE, but will return FALSE if this interrupt was
   not expected.

--*/

{
    PTAPE_CONTROLLER_DATA controllerData;
    PDEVICE_OBJECT currentDeviceObject;
    SHORT i;
    UCHAR statusByte;
    BOOLEAN controllerStateError = FALSE;

    UNREFERENCED_PARAMETER( Interrupt );

    KeStallExecutionProcessor(10);

    controllerData = (PTAPE_CONTROLLER_DATA) Context;

    //
    // CurrentDeviceObject is set to the device object that is
    // expecting an interrupt.
    //

    currentDeviceObject = controllerData->CurrentDeviceObject;

    if (currentDeviceObject == NULL &&
        !controllerData->CurrentInterrupt) {

        return FALSE;

    } else {

			controllerData->CurrentDeviceObject = NULL;

			if ( controllerData->CommandHasResultPhase ) {

				 //
				 // Result phase of previous command.    (Note that we can't trust
				 // the CMD_BUSY bit in the status register to tell us whether
				 // there's result bytes or not; it's sometimes wrong).
				 // By reading the first result byte, we reset the interrupt.
				 // The other result bytes will be read by a thread.
				 // Note that we want to do this even if the interrupt is
				 // unexpected, to make sure the interrupt is dismissed.
				 //

				 if ( ( READ_CONTROLLER( &controllerData->FDC_Addr->MSDSR.msr )
					  & (MSR_RQM | MSR_DIO) ) == (MSR_RQM | MSR_DIO) ) {

					  controllerData->FifoByte =
							READ_CONTROLLER( &controllerData->FDC_Addr->dr );

				 } else {

					  //
					  // Should never get here.   If we do, DON'T wake up the thread;
					  // let it time out and reset the controller, or let another
					  // interrupt handle this.
					  //

					  CheckedDump(QIC117DBGP,( "q117i: controller not ready to be read in ISR\n" ));

					  controllerStateError = TRUE;

				 }

			} else {

				 //
				 // Previous command doesn't have a result phase. To read how it
				 // completed, issue a sense interrupt command.  Don't read
				 // the result bytes from the sense interrupt; that is the
				 // responsibility of the calling thread.
				 // Note that we want to do this even if the interrupt is
				 // unexpected, to make sure the interrupt is dismissed.
				 //

				 i = FDC_MSR_RETRIES;

				 do {

					  if ((READ_CONTROLLER(&controllerData->FDC_Addr->MSDSR.msr) & (MSR_RQM | MSR_DIO)) == MSR_RQM) {

								 break;

					  }

					  KeStallExecutionProcessor( 12 );

				 } while (--i > 0);

				 if (i != 0) {

					  WRITE_CONTROLLER(
					  &controllerData->FDC_Addr->dr,
					  FDC_SNS_INT );

					  KeStallExecutionProcessor( 12 );

					  //
					  // Wait for the controller to ACK the SenseInterrupt command, by
					  // showing busy.    On very fast machines we can end up running
					  // driver's system-thread before the controller has had time to
					  // set the busy bit.
					  //

					  for (i = FDC_MSR_RETRIES; i; i--) {

							if (READ_CONTROLLER(&controllerData->FDC_Addr->MSDSR.msr) & MSR_CB)
									  break;

							KeStallExecutionProcessor( 12 );

					  }

					  // Need to optimize the previous section

					  if ( currentDeviceObject == NULL ) {

							//
							// This is an unexpected interrupt, so nobody's going to
							// read the result bytes.   Read them now.
							//

							READ_CONTROLLER( &controllerData->FDC_Addr->dr );
							READ_CONTROLLER( &controllerData->FDC_Addr->dr );

					  }

				 } else {

					  //
					  // Shouldn't get here.  If we do, DON'T wake up the thread;
					  // let it time out and reset the controller, or let another
					  // interrupt take care of it.
					  //

					  CheckedDump(QIC117DBGP,( "q117i: no result, but can't write SenseIntr\n" ));

					  controllerStateError = TRUE;
				 }

			}

			//
			// We've written to the controller, and we're about to leave.   On
			// machines with levelsensitive interrupts, we'll get another interrupt
			// if we RETURN before the port is flushed. To make sure that doesn't
			// happen, we'll do a read here.
			//

			statusByte = READ_CONTROLLER( &controllerData->FDC_Addr->MSDSR.msr );

			//
			// Let the interrupt settle.
			//

			KeStallExecutionProcessor(10);

			if ( currentDeviceObject == NULL ) {

				 //
				 // We didn't expect this interrupt. We've dismissed it just
				 // in case, but now return FALSE withOUT waking up the thread.
				 //

				 CheckedDump(QIC117DBGP,( "q117i: unexpected interrupt\n" ));

				 return FALSE;

			}

			if ( !controllerStateError ) {

				 //
				 // Request a DPC for execution later to get the remainder of the
				 // floppy state.
				 //

				 IoRequestDpc(
				 currentDeviceObject,
				 currentDeviceObject->CurrentIrp,
				 (PVOID) NULL );

			}

			return TRUE;

    }

}

VOID
Q117iTapeDeferredProcedure(
   IN PKDPC Dpc,
   IN PVOID DeferredContext,
   IN PVOID SystemArgument1,
   IN PVOID SystemArgument2
   )

/*++

Routine Description:

   This routine is called at DISPATCH_LEVEL by the system at the
   request of Q117iTapeInterruptService(). It simply sets the interrupt
   event, which wakes up the floppy thread.

Arguments:

   Dpc - a pointer to the DPC object used to invoke this routine.

   DeferredContext - a pointer to the device object associated with this
   DPC.

   SystemArgument1 - unused.

   SystemArgument2 - unused.

Return Value:

   None.

--*/

{
    PDEVICE_OBJECT deviceObject;
    PTAPE_EXTENSION tapeExtension;
    union format_header hdrData;      // sector id data
    FDC_STATUS fStat;                 // FDC status response
    SHORT statLength;                 // length of FDC status response
    ULONG  *hdrPtr;                   // pointer to sector id data for format
    PHYSICAL_ADDRESS val;
    struct seek_cmd seek;
    struct fdc_result result;
    SHORT i;

   UNREFERENCED_PARAMETER( Dpc );
   UNREFERENCED_PARAMETER( SystemArgument1 );
   UNREFERENCED_PARAMETER( SystemArgument2 );

   deviceObject = (PDEVICE_OBJECT) DeferredContext;
   tapeExtension = deviceObject->DeviceExtension;


    if (!tapeExtension->QControllerData->StartFormatMode) {

        (VOID) KeSetEvent(
				&tapeExtension->QControllerData->InterruptEvent,
				(KPRIORITY) 0,
				FALSE );

	  } else {

			//
			// Format all of the segments on the tape track.  Whenever a boundary
			// condition is reached (e.g. sectors > sectors per floppy track)
			// update the sector id information as necessary.
			//

			if (tapeExtension->FmtOp.Segments == (SHORT)tapeExtension->TapeParms.SegTtrack) {

				 IoFlushAdapterBuffers(
					  tapeExtension->QControllerData->AdapterObject,
					  tapeExtension->FmtOp.MdlAddress,
					  tapeExtension->QControllerData->MapRegisterBase,
					  (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
							+ tapeExtension->RdWrOp.BytesTransferredSoFar ),
					  tapeExtension->RdWrOp.TotalBytesOfTransfer,
					  DMA_READ );

				 if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
									  tapeExtension,
									  (CHAR *)&fStat,
									  &statLength)) == NoErr) {

					  if (fStat.ST0 & ST0_IC) {

							tapeExtension->FmtOp.retval = TimeOut;

                     (VOID) KeSetEvent(
				             &tapeExtension->QControllerData->InterruptEvent,
				             (KPRIORITY) 0,
				             FALSE );

					  }

				 }

				 tapeExtension->QControllerData->StartFormatMode = FALSE;

				 if (tapeExtension->QControllerData->FDC_Pcn < 128) {

					  seek.NCN = tapeExtension->QControllerData->FDC_Pcn + Report_Status;

				 } else {

					  seek.NCN = tapeExtension->QControllerData->FDC_Pcn - Report_Status;

				 }

				 seek.cmd = 0x0f;
				 seek.drive = (UCHAR)tapeExtension->DriveParms.DriveSelect;
				 tapeExtension->FmtOp.NCN = seek.NCN;

		       tapeExtension->QControllerData->CurrentDeviceObject =
				     tapeExtension->QDeviceObject;

				 if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
									  tapeExtension,
									  (CHAR *)&seek,
									  sizeof(seek),
									  FALSE)) == NoErr) {

					  tapeExtension->QControllerData->EndFormatMode = TRUE;

				 } else {

					  //
					  // Request a DPC for execution later to get the remainder of the
					  // floppy state.
					  //

                 (VOID) KeSetEvent(
				         &tapeExtension->QControllerData->InterruptEvent,
				         (KPRIORITY) 0,
				         FALSE );

				 }

			} else if (tapeExtension->FmtOp.Segments == 0) {

				  if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
															 tapeExtension,
															 (CHAR *)&result,
															 (SHORT *)&statLength)) == NoErr) {

						if ( !(result.ST0 & ST0_IC)) {

							 //
							 // If we timed out, then we did the sense interrupt status
							 // without clearing the interrupt from the interrupt controller.
							 // Since the FDC did not indicate an error, we assume that we
							 // missed the interrupt and send the EOI. Only needed for an
							 // 82072.
							 //

							 if (tapeExtension->QControllerData->InterfaceType != MicroChannel) {

								  if (result.ST0 !=
										(UCHAR)(tapeExtension->DriveParms.DriveSelect | ST0_SE)) {

										tapeExtension->FmtOp.retval = NECFlt;

								  }
							 }

							 if (tapeExtension->FmtOp.NCN != result.PCN) {

								  tapeExtension->FmtOp.retval = CmdFlt;

							 }

							 tapeExtension->QControllerData->FDC_Pcn = result.PCN;

						} else {

							 tapeExtension->FmtOp.retval = NECFlt;

						}

				  }

				 if (tapeExtension->FmtOp.retval == NoErr) {

					  hdrPtr = tapeExtension->FmtOp.HdrPtr;
					  hdrData.hdr_struct.C = tapeExtension->FmtOp.Cylinder;
					  hdrData.hdr_struct.H = tapeExtension->FmtOp.Head;
					  hdrData.hdr_struct.N = FMT_BPS;

					  for (i = 0; i < tapeExtension->TapeParms.FsectSeg; i++) {

							hdrData.hdr_struct.R = tapeExtension->FmtOp.Sector++;
							*hdrPtr = hdrData.hdr_all;
							++hdrPtr;

					  }

					  //
					  // Start the format by programming the DMA, starting the tape, and
					  // starting the floppy controller.
					  //
					  // Map the transfer through the DMA hardware.
					  //

					  tapeExtension->RdWrOp.BytesTransferredSoFar = 0l;
					  tapeExtension->RdWrOp.TotalBytesOfTransfer =
							tapeExtension->TapeParms.FsectSeg * sizeof(ULONG);

					  KeFlushIoBuffers( tapeExtension->FmtOp.MdlAddress, !DMA_READ, TRUE );

					  val = IoMapTransfer(
							tapeExtension->QControllerData->AdapterObject,
							tapeExtension->FmtOp.MdlAddress,
							tapeExtension->QControllerData->MapRegisterBase,
							(PVOID)( (ULONG) MmGetMdlVirtualAddress(tapeExtension->FmtOp.MdlAddress)
								 + tapeExtension->RdWrOp.BytesTransferredSoFar ),
							&tapeExtension->RdWrOp.TotalBytesOfTransfer,
							DMA_READ );

   				  tapeExtension->QControllerData->CurrentDeviceObject =
					      tapeExtension->QDeviceObject;

					  if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
																 tapeExtension,
																 (CHAR *)&tapeExtension->QControllerData->FmtCmd,
																 sizeof(FORMAT_CMD),
																 TRUE)) != NoErr) {

							IoFlushAdapterBuffers(
								 tapeExtension->QControllerData->AdapterObject,
								 tapeExtension->FmtOp.MdlAddress,
								 tapeExtension->QControllerData->MapRegisterBase,
								 (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
									  + tapeExtension->RdWrOp.BytesTransferredSoFar ),
								 tapeExtension->RdWrOp.TotalBytesOfTransfer,
								 DMA_READ );

                     (VOID) KeSetEvent(
				             &tapeExtension->QControllerData->InterruptEvent,
				             (KPRIORITY) 0,
				             FALSE );

					  }

					  tapeExtension->FmtOp.Segments++;
						  
				 } else {

                 (VOID) KeSetEvent(
				         &tapeExtension->QControllerData->InterruptEvent,
				         (KPRIORITY) 0,
				         FALSE );

				 }


			} else {

				 IoFlushAdapterBuffers(
					  tapeExtension->QControllerData->AdapterObject,
					  tapeExtension->FmtOp.MdlAddress,
					  tapeExtension->QControllerData->MapRegisterBase,
					  (PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
							+ tapeExtension->RdWrOp.BytesTransferredSoFar ),
					  tapeExtension->RdWrOp.TotalBytesOfTransfer,
					  DMA_READ );

				 if ((tapeExtension->FmtOp.retval = Q117iReadFDC(
									  tapeExtension,
									  (CHAR *)&fStat,
									  &statLength)) == NoErr) {

					  if (fStat.ST0 & ST0_IC) {

							tapeExtension->FmtOp.retval = TimeOut;

					  }
				 }

				 if (tapeExtension->FmtOp.retval != NoErr) {

                 (VOID) KeSetEvent(
				         &tapeExtension->QControllerData->InterruptEvent,
				         (KPRIORITY) 0,
				         FALSE );

				 }

				 if (tapeExtension->FmtOp.Sector > tapeExtension->TapeParms.FsectFtrack) {

					  tapeExtension->FmtOp.Sector = 1;
					  tapeExtension->FmtOp.Cylinder++;

					  if (tapeExtension->FmtOp.Cylinder ==
							(UCHAR)tapeExtension->TapeParms.FtrackFside) {

							tapeExtension->FmtOp.Cylinder = 0;
							tapeExtension->FmtOp.Head++;

					  }
				 }

				 //
				 // Set up the sector id information for this segment.
				 //


				 hdrPtr = tapeExtension->FmtOp.HdrPtr;
				 hdrData.hdr_struct.C = tapeExtension->FmtOp.Cylinder;
				 hdrData.hdr_struct.H = tapeExtension->FmtOp.Head;
				 hdrData.hdr_struct.N = FMT_BPS;

				 for (i = 0; i < tapeExtension->TapeParms.FsectSeg; i++) {

					  hdrData.hdr_struct.R = tapeExtension->FmtOp.Sector++;
					  *hdrPtr = hdrData.hdr_all;
					  ++hdrPtr;

				 }

				 //
				 // Start the format by programming the DMA, starting the tape, and
				 // starting the floppy controller.
				 //
				 // Map the transfer through the DMA hardware.
				 //

				 tapeExtension->RdWrOp.BytesTransferredSoFar = 0l;
				 tapeExtension->RdWrOp.TotalBytesOfTransfer =
					  tapeExtension->TapeParms.FsectSeg * sizeof(ULONG);

				 KeFlushIoBuffers( tapeExtension->FmtOp.MdlAddress, !DMA_READ, TRUE );

				 val = IoMapTransfer(
					  tapeExtension->QControllerData->AdapterObject,
					  tapeExtension->FmtOp.MdlAddress,
					  tapeExtension->QControllerData->MapRegisterBase,
					  (PVOID)( (ULONG) MmGetMdlVirtualAddress(tapeExtension->FmtOp.MdlAddress)
							+ tapeExtension->RdWrOp.BytesTransferredSoFar ),
					  &tapeExtension->RdWrOp.TotalBytesOfTransfer,
					  DMA_READ );

				 tapeExtension->QControllerData->CurrentDeviceObject =
				     tapeExtension->QDeviceObject;

				 if ((tapeExtension->FmtOp.retval = Q117iProgramFDC(
				                                 tapeExtension,
				                                 (CHAR *)&tapeExtension->QControllerData->FmtCmd,
				                                 sizeof(FORMAT_CMD),
				                                 TRUE)) != NoErr) {

					  IoFlushAdapterBuffers(
							tapeExtension->QControllerData->AdapterObject,
							tapeExtension->FmtOp.MdlAddress,
							tapeExtension->QControllerData->MapRegisterBase,
							(PVOID)( (ULONG) MmGetMdlVirtualAddress( tapeExtension->FmtOp.MdlAddress )
								 + tapeExtension->RdWrOp.BytesTransferredSoFar ),
							tapeExtension->RdWrOp.TotalBytesOfTransfer,
							DMA_READ );

                 (VOID) KeSetEvent(
				         &tapeExtension->QControllerData->InterruptEvent,
				         (KPRIORITY) 0,
				         FALSE );

				 }	

				 tapeExtension->FmtOp.Segments++;
					 
			}

	  }

}

VOID
Q117iTapeUnloadDriver(
   IN PDRIVER_OBJECT DriverObject
   )

/*++

Routine Description:

   This routine is called by the system to remove the driver from memory.

   When this routine is called, there is no I/O being done to this device.
   The driver object is passed in, and from this the driver can find and
   delete all of its device objects, extensions, etc.

Arguments:

   DriverObject - a pointer to the object associated with this device
   driver.

Return Value:

   None.

--*/

{
   UNREFERENCED_PARAMETER( DriverObject );

//  signal Q117iTapeThread() to unload itself
//  disable interrupts from controller(s?)
//  delete everything that's been allocated
}

VOID
Q117iTapeThread(
   PTAPE_CONTROLLER_DATA ControllerData
   )

/*++

Routine Description:

   This is the code executed by the system thread created when the
   floppy driver initializes.  This thread loops forever (or until a
   flag is set telling the thread to kill itself) processing packets
   put into the queue by the dispatch routines.

   For each packet, this thread calls appropriate routines to process
   the request, and then calls FlFinishOperation() to complete the
   packet.

Arguments:

   ControllerData - a pointer to our data area for the controller being
   supported (there is one thread per controller).

Return Value:

   None.

--*/

{
   PIRP irp;
   PIO_STACK_LOCATION irpSp;
   PLIST_ENTRY request;
   NTSTATUS ntStatus = 0;

   //
   // Set thread priority to lowest realtime level.
   //

   KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);

   do {

      //
      // Wait for a request from the dispatch routines.
      // KeWaitForSingleObject won't return error here - this thread
      // isn't alertable and won't take APCs, and we're not passing in
      // a timeout.
      //

      (VOID) KeWaitForSingleObject(
            (PVOID) &ControllerData->RequestSemaphore,
            UserRequest,
            KernelMode,
            FALSE,
            (PLARGE_INTEGER) NULL );

      if ( ControllerData->UnloadingDriver ) {

            CheckedDump(QIC117INFO,( "q117i: Thread asked to kill itself\n" ));

            PsTerminateSystemThread( STATUS_SUCCESS );
      }

      while ( !IsListEmpty( &( ControllerData->ListEntry ) ) ) {

            //
            // Get the request from the queue. We know there is one,
            // because of the check above.
            //

               request = ExInterlockedRemoveHeadList(
               &ControllerData->ListEntry,
               &ControllerData->ListSpinLock );


            ControllerData->QueueEmpty =
                  IsListEmpty( &( ControllerData->ListEntry ) );

            irp = CONTAINING_RECORD( request, IRP, Tail.Overlay.ListEntry );

            irpSp = IoGetCurrentIrpStackLocation( irp );

            if ( ControllerData->ClearQueue ||
               irpSp->Parameters.DeviceIoControl.IoControlCode ==
               IOCTL_QIC117_CLEAR_QUEUE) {

               if (irpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_QIC117_CLEAR_QUEUE) {

                  CheckedDump(QIC117INFO,("Q117i: processing IOCTL_QIC117_CLEAR_QUEUE : TRUE\n"));

                  irp->IoStatus.Status = Q117iClearIO( irp );

                  // NOTE: This is temporary until we ca find how to
                  // correctly free the Mdl using the io subsytem.
                  if (irp->MdlAddress != NULL) {
                        IoFreeMdl(irp->MdlAddress);
                        irp->MdlAddress = NULL;
                  }

                  IoCompleteRequest( irp, IO_DISK_INCREMENT );

                  (VOID) KeSetEvent(
                        &ControllerData->ClearQueueEvent,
                        (KPRIORITY) 0,
                        FALSE );

               } else {

                  CheckedDump(QIC117INFO,("Q117i: processing IOCTL_QIC117_DRIVE_REQUEST : TRUE\n"));

                  irp->IoStatus.Status = STATUS_CANCELLED;

                  // NOTE: This is temporary until we ca find how to
                  // correctly free the Mdl using the io subsytem.
                  if (irp->MdlAddress != NULL) {
                        IoFreeMdl(irp->MdlAddress);
                        irp->MdlAddress = NULL;
                  }

                  IoCompleteRequest( irp, IO_DISK_INCREMENT );

               }

            } else {

               irp->IoStatus.Status = Q117iProcessItem( irp );

               // NOTE: This is temporary until we ca find how to
               // correctly free the Mdl using the io subsytem.
               if (irp->MdlAddress != NULL) {
                  IoFreeMdl(irp->MdlAddress);
                  irp->MdlAddress = NULL;
               }

               IoCompleteRequest( irp, IO_DISK_INCREMENT );

            }

      }                                   //while there's packets to process

   } while ( TRUE );
}

IO_ALLOCATION_ACTION
Q117iTapeAllocateAdapterChannel(
   IN PDEVICE_OBJECT DeviceObject,
   IN PIRP Irp,
   IN PVOID MapRegisterBase,
   IN PVOID Context
   )

/*++

Routine Description:

   This DPC is called whenever the floppy thread is trying to allocate
   the adapter channel (like before doing a read or write).    It saves
   the MapRegisterBase in the controller data area, and sets the
   AllocateAdapterChannelEvent to awaken the thread.

Arguments:

   DeviceObject - unused.

   Irp - unused.

   MapRegisterBase - the base of the map registers that can be used
   for this transfer.

   Context - a pointer to our controller data area.

Return Value:

   Returns Allocation Action 'KeepObject' which means that the adapter
   object will be held for now (to be released explicitly later).

--*/
{
   PTAPE_CONTROLLER_DATA controllerData = (PTAPE_CONTROLLER_DATA) Context;

   UNREFERENCED_PARAMETER( DeviceObject );
   UNREFERENCED_PARAMETER( Irp );

   controllerData->MapRegisterBase = MapRegisterBase;

   (VOID) KeSetEvent(
      &controllerData->AllocateAdapterChannelEvent,
      0L,
      FALSE );

   return KeepObject;
}

NTSTATUS
Q117iConfigCallBack(
   IN PVOID Context,
   IN PUNICODE_STRING PathName,
   IN INTERFACE_TYPE BusType,
   IN ULONG BusNumber,
   IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
   IN CONFIGURATION_TYPE ControllerType,
   IN ULONG ControllerNumber,
   IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
   IN CONFIGURATION_TYPE PeripheralType,
   IN ULONG PeripheralNumber,
   IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
   )

/*++

Routine Description:

   This routine is used to acquire all of the configuration
   information for each floppy disk controller and the
   peripheral driver attached to that controller.

Arguments:

   Context - Pointer to the confuration information we are building
               up.

   PathName - unicode registry path.   Not Used.

   BusType - Internal, Isa, ...

   BusNumber - Which bus if we are on a multibus system.

   BusInformation - Configuration information about the bus. Not Used.

   ControllerType - Should always be DiskController.

   ControllerNumber - Which controller if there is more than one
                        controller in the system.

   ControllerInformation - Array of pointers to the three pieces of
                           registry information.

   PeripheralType - Should always be FloppyDiskPeripheral.

   PeripheralNumber - Which floppy if this controller is maintaining
                        more than one.

   PeripheralInformation - Array of pointers to the three pieces of
                           registry information.

Return Value:

   STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
   if it couldn't map the base csr or acquire the adapter object, or
   all of the resource information couldn't be acquired.

--*/

{

   //
   // So we don't have to typecast the context.
   //
   PCONFIG_DATA config = Context;

   //
   // Simple iteration variable.
   //
   ULONG i;

   //
   // This boolean will be used to denote whether we've seen this
   // controller before.
   //
   BOOLEAN newController;

   //
   // This will be used to denote whether we even have room
   // for a new controller.
   //
   BOOLEAN outOfRoom;

   //
   // Iteration variable that will end up indexing to where
   // the controller information should be placed.
   //
   ULONG ControllerSlot;

   //
   // Short hand for referencing the particular controller config
   // information that we are building up.
   //
   PCONFIG_CONTROLLER_DATA controller;

   PCM_FULL_RESOURCE_DESCRIPTOR peripheralData = (PCM_FULL_RESOURCE_DESCRIPTOR)
      (((PUCHAR)PeripheralInformation[IoQueryDeviceConfigurationData]) +
      PeripheralInformation[IoQueryDeviceConfigurationData]->DataOffset);

   //
   // These three boolean will tell us whether we got all the
   // information that we needed.
   //
   BOOLEAN foundPort = FALSE;
   BOOLEAN foundInterrupt = FALSE;
   BOOLEAN foundDma = FALSE;

   ASSERT(ControllerType == DiskController);
   ASSERT(PeripheralType == FloppyDiskPeripheral);

   //
   // Loop through the "slots" that we have for a new controller.
   // Determine if this is a controller that we've already seen,
   // or a new controller.
   //

   outOfRoom = TRUE;
   for (
      ControllerSlot = 0;
      ControllerSlot < MAXIMUM_CONTROLLERS_PER_MACHINE;
      ControllerSlot++
      ) {

      if (config->Controller[ControllerSlot].ActualControllerNumber == -1) {

            newController = TRUE;
            outOfRoom = FALSE;
            config->Controller[ControllerSlot].ActualControllerNumber =
               ControllerNumber;
            config->NumberOfControllers++;
            break;

      } else if (config->Controller[ControllerSlot].ActualControllerNumber
                  == (LONG)ControllerNumber) {

            newController = FALSE;
            outOfRoom = FALSE;
            break;

      }

   }

   if (outOfRoom) {

      //
      // Just return and ignore the controller.
      //

      return STATUS_SUCCESS;

   }

   controller = &config->Controller[ControllerSlot];

   if (newController) {

      PCM_FULL_RESOURCE_DESCRIPTOR controllerData =
            (PCM_FULL_RESOURCE_DESCRIPTOR)
            (((PUCHAR)ControllerInformation[IoQueryDeviceConfigurationData]) +
            ControllerInformation[IoQueryDeviceConfigurationData]->DataOffset);

      //
      // We have the pointer. Save off the interface type and
      // the busnumber for use when we call the Hal and the
      // Io System.
      //

      controller->InterfaceType = BusType;
      controller->BusNumber = BusNumber;
      controller->SharableVector = TRUE;
      controller->SaveFloatState = FALSE;

      //
      // We need to get the following information out of the partial
      // resource descriptors.
      //
      // The irql and vector.
      //
      // The dma channel.
      //
      // The base address and span covered by the floppy controllers
      // registers.
      //
      // It is not defined how these appear in the partial resource
      // lists, so we will just loop over all of them.    If we find
      // something we don't recognize, we drop that information on
      // the floor.   When we have finished going through all the
      // partial information, we validate that we got the above
      // three.
      //

      CheckedDump(QIC117INFO,("Q117i: adding controller: %x slot: %x\n",ControllerNumber,ControllerSlot));

      for (
            i = 0;
            i < controllerData->PartialResourceList.Count;
            i++
            ) {

            PCM_PARTIAL_RESOURCE_DESCRIPTOR partial =
               &controllerData->PartialResourceList.PartialDescriptors[i];

            switch (partial->Type) {

               case CmResourceTypePort: {

                  BOOLEAN inIoSpace =
#ifdef i386
                              TRUE;
#else
                              FALSE;
#endif

                  foundPort = TRUE;

                  //
                  // Save of the pointer to the partial so
                  // that we can later use it to report resources
                  // and we can also use this later in the routine
                  // to make sure that we got all of our resources.
                  //

                  controller->SpanOfControllerAddress =
                        partial->u.Port.Length;
                  controller->OriginalBaseAddress =
                        partial->u.Port.Start;
                  controller->ControllerBaseAddress = (PTAPE_ADDRESS)
                        Q117iGetControllerBase(
                           BusType,
                           BusNumber,
                           partial->u.Port.Start,
                           controller->SpanOfControllerAddress,
                           inIoSpace,
                           &controller->MappedAddress
                           );

                  if (!controller->ControllerBaseAddress) {

                        return STATUS_INSUFFICIENT_RESOURCES;

                  }

                  break;
               }
               case CmResourceTypeInterrupt: {

                  foundInterrupt = TRUE;
                  if (partial->Flags & CM_RESOURCE_INTERRUPT_LATCHED) {

                        controller->InterruptMode = Latched;

                  } else {

                        controller->InterruptMode = LevelSensitive;

                  }

                  controller->OriginalIrql =  partial->u.Interrupt.Level;
                  controller->OriginalVector = partial->u.Interrupt.Vector;
                  controller->ControllerVector =
                        HalGetInterruptVector(
                           BusType,
                           BusNumber,
                           partial->u.Interrupt.Level,
                           partial->u.Interrupt.Vector,
                           &controller->ControllerIrql,
                           &controller->ProcessorMask
                           );

                  break;
               }
               case CmResourceTypeDma: {

                  DEVICE_DESCRIPTION deviceDesc;

                  RtlZeroMemory(&deviceDesc,sizeof(deviceDesc));
                  foundDma = TRUE;

                  controller->OriginalDmaChannel = partial->u.Dma.Channel;

                  deviceDesc.Version = DEVICE_DESCRIPTION_VERSION;
                  deviceDesc.DmaWidth = Width8Bits;
                  deviceDesc.DemandMode = TRUE;
                  deviceDesc.MaximumLength = 32l*1024l;
                  deviceDesc.AutoInitialize = FALSE;
                  deviceDesc.ScatterGather = FALSE;
                  deviceDesc.DmaChannel = partial->u.Dma.Channel;
                  deviceDesc.InterfaceType = BusType;
                  deviceDesc.DmaSpeed = TypeA;
                  controller->NumberOfMapRegisters = BYTES_TO_PAGES(32l*1024l);
                  controller->AdapterObject =
                        HalGetAdapter(
                           &deviceDesc,
                           &controller->NumberOfMapRegisters
                           );

                  CheckedDump(QIC117INFO,( "Q117i: Bus Type = %d\n",
                        BusType ));
                  CheckedDump(QIC117INFO,( "Q117i: Number of map registers = %d\n",
                        controller->NumberOfMapRegisters ));

                  if (!controller->AdapterObject) {

                        return STATUS_INSUFFICIENT_RESOURCES;

                  }

                  break;

               }
               default: {

                  break;

               }

            }

      }

      //
      // If we didn't get all the information then we return
      // insufficient resources.
      //

      if ((!foundPort) ||
            (!foundInterrupt) ||
            (!foundDma)) {

            return STATUS_INSUFFICIENT_RESOURCES;

      }
      controller->NumberOfTapeDrives++;
      controller->OkToUseThisController = TRUE;

   }


   return STATUS_SUCCESS;
}

NTSTATUS
Q117iGetConfigurationInformation(
   OUT PCONFIG_DATA *ConfigData
   )

/*++

Routine Description:

   This routine is called by DriverEntry() to get information about the
   devices to be supported from configuration mangement and/or the
   hardware architecture layer (HAL).

Arguments:

   ConfigData - a pointer to the pointer to a data structure that
   describes the controllers and the drives attached to them

Return Value:

   Returns STATUS_SUCCESS unless there is no drive 0 or we didn't get
   any configuration information.
   NOTE: FUTURE return values may change when config mgr is finished.

--*/

{
   INTERFACE_TYPE InterfaceType;
   NTSTATUS Status;
   ULONG i;

   *ConfigData = ExAllocatePool(
                        PagedPool,
                        sizeof(CONFIG_DATA)
                        );

   if (!*ConfigData) {

      return STATUS_INSUFFICIENT_RESOURCES;

   }

   //
   // Zero out the config structure and fill in the actual
   // controller numbers with -1's so that the callback routine
   // can recognize a new controller.
   //

   RtlZeroMemory(
      *ConfigData,
      sizeof(CONFIG_DATA)
      );

   for (
      i = 0;
      i < MAXIMUM_CONTROLLERS_PER_MACHINE;
      i++
      ) {

      (*ConfigData)->Controller[i].ActualControllerNumber = -1;

   }

   //
   // Go through all of the various bus types looking for
   // disk controllers.    The disk controller sections of the
   // hardware registry only deal with the floppy drives.
   // The callout routine that can get called will then
   // look for information pertaining to a particular
   // device on the controller.
   //

   for (
      InterfaceType = 0;
      InterfaceType < MaximumInterfaceType;
      InterfaceType++
      ) {

      CONFIGURATION_TYPE Dc = DiskController;
      CONFIGURATION_TYPE Fp = FloppyDiskPeripheral;

      Status = IoQueryDeviceDescription(
                     &InterfaceType,
                     NULL,
                     &Dc,
                     NULL,
                     &Fp,
                     NULL,
                     Q117iConfigCallBack,
                     *ConfigData
                     );

      if (!NT_SUCCESS(Status) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) {

            ExFreePool(*ConfigData);
            *ConfigData = NULL;
            return Status;

      }

   }

   return STATUS_SUCCESS;
}

NTSTATUS
Q117iInitializeController(
   IN PCONFIG_DATA ConfigData,
   IN UCHAR ControllerNumber,
   IN PDRIVER_OBJECT DriverObject,
   IN PUNICODE_STRING RegistryPath
   )

/*++

Routine Description:

   This routine is called at initialization time by DriverEntry() -
   once for each controller that the configuration manager tells it we
   have to support.

   When this routine is called, the configuration data has already been
   filled in.

Arguments:

   ConfigData - a pointer to the structure that describes the
   controller and the disks attached to it, as given to us by the
   configuration manager.

   ControllerNumber - which controller in ConfigData we are
   initializing.

   DriverObject - a pointer to the object that represents this device
   driver.

Return Value:

   STATUS_SUCCESS if this controller and at least one of its disks were
   initialized; an error otherwise.

--*/

{
   PTAPE_CONTROLLER_DATA controllerData;
   PVOID threadObject;
   NTSTATUS ntStatus;
   NTSTATUS ntStatus2;
   HANDLE threadHandle = 0;
   BOOLEAN partlySuccessful;
   LARGE_INTEGER timeout;
   UCHAR ntNameBuffer[256];
   STRING ntNameString;
   UNICODE_STRING ntUnicodeString;

   CheckedDump(QIC117INFO,( "Q117iInitializeController...\n" ));

   //
   // This routine will take attempt to "append" the resources
   // used by this controller into the resource map of the
   // registry.    If there was a conflict with previously "declared"
   // data, then this routine will return false, in which case we
   // will NOT try to initialize this particular controller.
   //

   if (!Q117iReportResources(
            DriverObject,
            ConfigData,
            ControllerNumber
            )) {

      return STATUS_INSUFFICIENT_RESOURCES;

   }

   //
   // Allocate and zero-initialize data to describe this controller
   //

   controllerData = (PTAPE_CONTROLLER_DATA) ExAllocatePool(
      NonPagedPool,
      sizeof( TAPE_CONTROLLER_DATA ) );

   if ( controllerData == NULL ) {

      return STATUS_INSUFFICIENT_RESOURCES;
   }

   RtlZeroMemory( controllerData, sizeof( TAPE_CONTROLLER_DATA ) );

   (VOID) sprintf(
      ntNameBuffer,
      "\\Device\\FloppyControllerEvent%d",
      ControllerNumber );

   RtlInitString( &ntNameString, ntNameBuffer );

   ntStatus = RtlAnsiStringToUnicodeString(
      &ntUnicodeString,
      &ntNameString,
      TRUE );

   controllerData->ControllerEvent = IoCreateSynchronizationEvent(
      &ntUnicodeString,
      &controllerData->ControllerEventHandle);

   RtlFreeUnicodeString( &ntUnicodeString );

   if ( controllerData->ControllerEvent == NULL ) {
      return STATUS_INSUFFICIENT_RESOURCES;
   }

   //
   // Fill in some items that we got from configuration management and
   // the HAL.
   //

   controllerData->FDC_Addr = (PTAPE_ADDRESS)
      ConfigData->Controller[ControllerNumber].ControllerBaseAddress;
   controllerData->InterfaceType =
      ConfigData->Controller[ControllerNumber].InterfaceType;
   controllerData->ActualControllerNumber =
      ConfigData->Controller[ControllerNumber].ActualControllerNumber;

   controllerData->DriveSelect.Selected = FALSE;
   controllerData->DriveSelect.DeselectByte = dselb;
   controllerData->DriveSelect.SelectByte = selb;

   ntStatus = IoConnectInterrupt(
      (PKINTERRUPT *) &controllerData->InterruptObject,
      (PKSERVICE_ROUTINE) Q117iTapeInterruptService,
      (PVOID) controllerData,
      (PKSPIN_LOCK)NULL,
      ConfigData->Controller[ControllerNumber].ControllerVector,
      ConfigData->Controller[ControllerNumber].ControllerIrql,
      ConfigData->Controller[ControllerNumber].ControllerIrql,
      ConfigData->Controller[ControllerNumber].InterruptMode,
      ConfigData->Controller[ControllerNumber].SharableVector,
      ConfigData->Controller[ControllerNumber].ProcessorMask,
      ConfigData->Controller[ControllerNumber].SaveFloatState);


   if ( NT_SUCCESS( ntStatus ) ) {
      //
      // Initialize the interlocked request queue, including a
      // counting semaphore to indicate items in the queue
      //

      KeInitializeSemaphore(
            &controllerData->RequestSemaphore,
            0L,
            MAXLONG );

      KeInitializeSpinLock( &controllerData->ListSpinLock );

      InitializeListHead( &controllerData->ListEntry );

      //
      // Initialize events to signal interrupts and adapter object
      // allocation
      //

      KeInitializeEvent(
            &controllerData->InterruptEvent,
            SynchronizationEvent,
            FALSE);


      KeInitializeEvent(
            &controllerData->AllocateAdapterChannelEvent,
            NotificationEvent,
            FALSE );


      KeInitializeEvent(
            &controllerData->ClearQueueEvent,
            SynchronizationEvent,
            FALSE);



      //
      // Create a thread with entry point Q117iTapeThread()
      //

      ntStatus = PsCreateSystemThread(
            &threadHandle,
            (ACCESS_MASK) 0L,
            (POBJECT_ATTRIBUTES) NULL,
            (HANDLE) 0L,
            (PCLIENT_ID) NULL,
            (PKSTART_ROUTINE) Q117iTapeThread,
            (PVOID) controllerData );

#if DBG
      if ( !NT_SUCCESS( ntStatus ) ) {

            CheckedDump(QIC117DBGP,( "q117i: error %x creating thread\n", ntStatus ));
      }
#endif

      if ( NT_SUCCESS( ntStatus ) ) {

            CheckedDump(QIC117INFO,("Q117iThread = %x\n",threadHandle));

            //
            // Call Q117iInitializeDrive() for each drive on the
            // controller
            //

            ConfigData->Controller[ControllerNumber].NumberOfTapeDrives++;

            ntStatus = STATUS_NO_SUCH_DEVICE;
            partlySuccessful = FALSE;

            ntStatus = Q117iInitializeDrive(
               ConfigData,
               controllerData,
               ControllerNumber,
               DriverObject,
               RegistryPath );
      }

   }

   //
   // If we're exiting with an error, clean up first.
   //

   if ( !NT_SUCCESS( ntStatus ) ) {

      CheckedDump(QIC117DBGP,( "q117i: InitializeController failing\n" ));

      //
      // If we created the thread, wake it up and tell it to kill itself.
      // Wait until it's dead.    (Note that since it's a system thread,
      // it has to kill itself - we can't do it).
      //

      if ( threadHandle != 0 ) {

            controllerData->UnloadingDriver = TRUE;

            ntStatus2 = ObReferenceObjectByHandle(
               threadHandle,
               THREAD_ALL_ACCESS,
               NULL,
               KernelMode,
               (PVOID *) &threadObject,
               NULL );

            (VOID) KeReleaseSemaphore(
               &controllerData->RequestSemaphore,
               (KPRIORITY) 0,
               1,
               FALSE );

            if ( NT_SUCCESS( ntStatus2 ) ) {

               //
               // The thread object will be signalled when it dies.
               //

               ntStatus2 = KeWaitForSingleObject(
                  (PVOID) threadObject,
                  Suspended,
                  KernelMode,
                  FALSE,
                  (PLARGE_INTEGER) NULL );

               ASSERT( ntStatus2 == STATUS_SUCCESS );

               ObDereferenceObject( threadObject );

            } else {

               //
               // We can't get the thread object for some reason; just
               // block for a while to give the thread a chance to run
               // and die.
               //

               CheckedDump(QIC117DBGP,( "q117i: couldn't get thread object\n" ));


               timeout =
                  RtlLargeIntegerNegate(
                  RtlEnlargedIntegerMultiply(
                        10,
                        10l * 1000l
                  )
               );
               (VOID) KeDelayExecutionThread(
                  KernelMode,
                  FALSE,
                  &timeout );
            }
      }


      if ( controllerData->InterruptObject != NULL ) {

          (VOID) KeSetEvent(
                    controllerData->ControllerEvent,
                    (KPRIORITY) 0,
                    FALSE );

          IoDisconnectInterrupt( controllerData->InterruptObject );
      }

      ExFreePool( controllerData );

   }

   return ntStatus;
}

BOOLEAN
Q117iReportResources(
   IN PDRIVER_OBJECT DriverObject,
   IN PCONFIG_DATA ConfigData,
   IN UCHAR ControllerNumber
   )

/*++

Routine Description:

   This routine will build up a resource list using the
   data for this particular controller as well as all
   previous *successfully* configured controllers.

   N.B.  This routine assumes that it called in controller
   number order.

Arguments:

   DriverObject - a pointer to the object that represents this device
   driver.

   ConfigData - a pointer to the structure that describes the
   controller and the disks attached to it, as given to us by the
   configuration manager.

   ControllerNumber - which controller in ConfigData we are
   about to try to report.

Return Value:

   TRUE if no conflict was detected, FALSE otherwise.

--*/

{


   ULONG sizeOfResourceList;
   ULONG numberOfFrds;
   LONG i;
   PCM_RESOURCE_LIST resourceList;
   PCM_FULL_RESOURCE_DESCRIPTOR nextFrd;

   //
   // Loop through all of the controllers previous to this
   // controller.  If the controllers previous to this one
   // didn't have a conflict, then accumulate the size of the
   // CM_FULL_RESOURCE_DESCRIPTOR associated with it.
   //

   for (
      i = 0,numberOfFrds = 0,sizeOfResourceList = 0;
      i <= ControllerNumber;
      i++
      ) {

      if (ConfigData->Controller[i].OkToUseThisController) {

            sizeOfResourceList += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);

            //
            // The full resource descriptor already contains one
            // partial.  Make room for three more.
            //
            // It will hold the irq "prd", the controller "csr" "prd" which
            // is actually in two pieces since we don't use one of the
            // registers, and the controller dma "prd".
            //

            sizeOfResourceList += 3*sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
            numberOfFrds++;

      }

   }

   //
   // Now we increment the length of the resource list by field offset
   // of the first frd.   This will give us the length of what preceeds
   // the first frd in the resource list.
   //

   sizeOfResourceList += FIELD_OFFSET(
                              CM_RESOURCE_LIST,
                              List[0]
                              );

   resourceList = ExAllocatePool(
                     PagedPool,
                     sizeOfResourceList
                     );

   if (!resourceList) {

      return FALSE;

   }

   //
   // Zero out the field
   //

   RtlZeroMemory(
      resourceList,
      sizeOfResourceList
      );

   resourceList->Count = numberOfFrds;
   nextFrd = &resourceList->List[0];

   for (
      i = 0;
      numberOfFrds;
      i++
      ) {

      if (ConfigData->Controller[i].OkToUseThisController) {

            PCM_PARTIAL_RESOURCE_DESCRIPTOR partial;

            nextFrd->InterfaceType = ConfigData->Controller[i].InterfaceType;
            nextFrd->BusNumber = ConfigData->Controller[i].BusNumber;

            //
            // We are only going to report 4 items no matter what
            // was in the original.
            //

            nextFrd->PartialResourceList.Count = 4;

            //
            // Now fill in the port data.  We don't wish to share
            // this port range with anyone
            //

            partial = &nextFrd->PartialResourceList.PartialDescriptors[0];

            partial->Type = CmResourceTypePort;
            partial->ShareDisposition = CmResourceShareShared;
            partial->Flags = 0;
            partial->u.Port.Start =
               ConfigData->Controller[i].OriginalBaseAddress;
            partial->u.Port.Length = 6;

            partial++;

            partial->Type = CmResourceTypePort;
            partial->ShareDisposition = CmResourceShareShared;
            partial->Flags = 0;
            partial->u.Port.Start = RtlLargeIntegerAdd(
                        ConfigData->Controller[i].OriginalBaseAddress,
                        RtlConvertUlongToLargeInteger((ULONG)7)
                        );
            partial->u.Port.Length = 1;

            partial++;

            partial->Type = CmResourceTypeDma;
            partial->ShareDisposition = CmResourceShareShared;
            partial->Flags = 0;
            partial->u.Dma.Channel =
               ConfigData->Controller[i].OriginalDmaChannel;

            partial++;

            //
            // Now fill in the irq stuff.
            //

            partial->Type = CmResourceTypeInterrupt;
            partial->ShareDisposition = CmResourceShareShared;
            partial->u.Interrupt.Level =
               ConfigData->Controller[i].OriginalIrql;
            partial->u.Interrupt.Vector =
               ConfigData->Controller[i].OriginalVector;

            if (ConfigData->Controller[i].InterruptMode == Latched) {

               partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;

            } else {

               partial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;

            }

            partial++;

            nextFrd = (PVOID)partial;

            numberOfFrds--;

      }

   }

   IoReportResourceUsage(
      NULL,
      DriverObject,
      resourceList,
      sizeOfResourceList,
      NULL,
      NULL,
      0,
      FALSE,
      &ConfigData->Controller[ControllerNumber].OkToUseThisController
      );

   //
   // The above routine sets the boolean the parameter
   // to TRUE if a conflict was detected.
   //

   ConfigData->Controller[ControllerNumber].OkToUseThisController =
      !ConfigData->Controller[ControllerNumber].OkToUseThisController;

   ExFreePool(resourceList);

   return ConfigData->Controller[ControllerNumber].OkToUseThisController;

}

NTSTATUS
Q117iInitializeDrive(
   IN PCONFIG_DATA ConfigData,
   IN PTAPE_CONTROLLER_DATA ControllerData,
   IN UCHAR ControllerNum,
   IN PDRIVER_OBJECT DriverObject,
   IN PUNICODE_STRING RegistryPath
   )

/*++

Routine Description:

   This routine is called at initialization time by
   Q117iInitializeController(), once for each disk that we are supporting
   on the controller.

Arguments:

   ConfigData - a pointer to the structure that describes the
   controller and the disks attached to it, as given to us by the
   configuration manager.

   ControllerData - a pointer to our data area for this controller.

   ControllerNum - which controller in ConfigData we're working on.

   DisketteNum - which logical disk on the current controller we're
   working on.

   DisketteUnit - which physical disk on the current controller we're
   working on. Only different from DisketteNum when we're creating a
   secondary device object for a previously initialized drive.

   DriverObject - a pointer to the object that represents this device
   driver.

Return Value:

   STATUS_SUCCESS if this disk is initialized; an error otherwise.

--*/

{
   UCHAR ntNameBuffer[256];
   STRING ntNameString;
   UNICODE_STRING ntUnicodeString;
   NTSTATUS ntStatus;
   PDEVICE_OBJECT deviceObject = NULL;
   PTAPE_EXTENSION tapeExtension;
   STATUS retval;

   CheckedDump(QIC117INFO,( "Q117iInitializeDrive...\n" ));

   (VOID) sprintf(
      ntNameBuffer,
      "\\Device\\q117i%d", ConfigData->FloppyTapeCount);

   RtlInitString( &ntNameString, ntNameBuffer );

   ntStatus = RtlAnsiStringToUnicodeString(
      &ntUnicodeString,
      &ntNameString,
      TRUE );

   if ( NT_SUCCESS( ntStatus ) ) {

      //
      // Create a device object for this floppy drive.
      //

      ntStatus = IoCreateDevice(
            DriverObject,
            sizeof( TAPE_EXTENSION ),
            &ntUnicodeString,
            FILE_DEVICE_TAPE,
            FILE_REMOVABLE_MEDIA,
            FALSE,
            &deviceObject );

      RtlFreeUnicodeString(&ntUnicodeString);

   }



   if ( NT_SUCCESS( ntStatus ) ) {

      IoInitializeDpcRequest( deviceObject, Q117iTapeDeferredProcedure );

      tapeExtension = deviceObject->DeviceExtension;
      tapeExtension->SpeedChangeOK = FALSE;
      tapeExtension->PegasusSupported = TRUE;
      tapeExtension->Found = FALSE;
      tapeExtension->NoCart = TRUE;
      tapeExtension->ErrorSequence = 0;
      tapeExtension->TapeNumber = IoGetConfigurationInformation()->TapeCount;
      tapeExtension->DriveParms.Mode = PRIMARY_MODE;
      tapeExtension->DriveParms.Flavor = (UCHAR) UNKNOWN;
      tapeExtension->QDeviceObject = deviceObject;
      tapeExtension->QControllerData = ControllerData;
      tapeExtension->QControllerData->StartFormatMode = FALSE;
      tapeExtension->QControllerData->EndFormatMode = FALSE;
      tapeExtension->QControllerData->ClearQueue = FALSE;
      tapeExtension->QControllerData->AbortRequested = FALSE;
      tapeExtension->QControllerData->AdapterLocked = FALSE;
      tapeExtension->QControllerData->PerpendicularMode = FALSE;
      tapeExtension->XferRate.XferRate = SLOW;
      tapeExtension->XferRate.TapeSlow = TAPE_250Kbps;
      tapeExtension->XferRate.TapeFast = TAPE_500Kbps;
      tapeExtension->XferRate.FDC_Slow = FDC_250Kbps;
      tapeExtension->XferRate.FDC_Fast = FDC_500Kbps;
      tapeExtension->XferRate.SRT_Slow = SRT_250Kbps;
      tapeExtension->XferRate.SRT_Fast = SRT_500Kbps;

      tapeExtension->QControllerData->AdapterObject =
            ConfigData->Controller[ControllerNum].AdapterObject;

      tapeExtension->QControllerData->NumberOfMapRegisters =
            ConfigData->Controller[ControllerNum].NumberOfMapRegisters;

      tapeExtension->QControllerData->TapeExtension = tapeExtension;

#if DBG
      tapeExtension->DbgHead = tapeExtension->DbgTail = 0;
#endif

      tapeExtension->QControllerData->CurrentInterrupt = TRUE;


		retval = Q117iDLocateDrv(tapeExtension);

      tapeExtension->PersistentNewCart = FALSE;
      ntStatus = Q117iTranslateError( deviceObject, retval );
      tapeExtension->PersistentNewCart = TRUE;

      tapeExtension->QControllerData->CurrentInterrupt = FALSE;
   }

   //
   // Initialize the filer level tape device
   //

   if ( NT_SUCCESS( ntStatus ) ) {

      ntStatus = q117Initialize(
                        DriverObject,
                        deviceObject,
                        RegistryPath,
                        ConfigData->Controller[ControllerNum].AdapterObject,
                        ConfigData->Controller[ControllerNum].NumberOfMapRegisters
                        );

   }

   if ( NT_SUCCESS( ntStatus ) ) {

      ConfigData->FloppyTapeCount++;

   } else {

      //
      // If we're failing, clean up and delete the device object.
      //

     CheckedDump(QIC117DBGP,( "Q117i: InitializeDrive failing %x\n", ntStatus ));

      if ( deviceObject != NULL ) {

            IoDeleteDevice( deviceObject );
      }
   }

   return ntStatus;
}

ULONG
Q117iGetControllerBase(
   IN INTERFACE_TYPE BusType,
   IN ULONG BusNumber,
   PHYSICAL_ADDRESS IoAddress,
   ULONG NumberOfBytes,
   BOOLEAN InIoSpace,
   PBOOLEAN MappedAddress
   )

/*++

Routine Description:

   This routine maps an IO address to system address space.

Arguments:

   BusType - what type of bus - eisa, mca, isa
   IoBusNumber - which IO bus (for machines with multiple buses).
   IoAddress - base device address to be mapped.
   NumberOfBytes - number of bytes for which address is valid.
   InIoSpace - indicates an IO address.
   MappedAddress - indicates whether the address was mapped.
                  This only has meaning if the address returned
                  is non-null.

Return Value:

   Mapped address

--*/

{
   PHYSICAL_ADDRESS cardAddress;
   ULONG addressSpace = InIoSpace;
   ULONG Address;

   HalTranslateBusAddress(
            BusType,
            BusNumber,
            IoAddress,
            &addressSpace,
            &cardAddress
            );

   //
   // Map the device base address into the virtual address space
   // if the address is in memory space.
   //

   if (!addressSpace) {

      Address = (ULONG)MmMapIoSpace(
                        cardAddress,
                        NumberOfBytes,
                        FALSE
                        );

      *MappedAddress = (BOOLEAN)((Address)?(TRUE):(FALSE));


   } else {

      Address = (ULONG)cardAddress.LowPart;
   }

   return Address;

}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.