ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

xferpkt.c
Go to the documentation of this file.
00001 /*++
00002 
00003 Copyright (C) Microsoft Corporation, 1991 - 1999
00004 
00005 Module Name:
00006 
00007     xferpkt.c
00008 
00009 Abstract:
00010 
00011     Packet routines for CLASSPNP
00012 
00013 Environment:
00014 
00015     kernel mode only
00016 
00017 Notes:
00018 
00019 
00020 Revision History:
00021 
00022 --*/
00023 
00024 #include "classp.h"
00025 #include "debug.h"
00026 
00027 #ifdef ALLOC_PRAGMA
00028     #pragma alloc_text(PAGE, InitializeTransferPackets)
00029     #pragma alloc_text(PAGE, DestroyAllTransferPackets)
00030     #pragma alloc_text(PAGE, SetupEjectionTransferPacket)
00031     #pragma alloc_text(PAGE, SetupModeSenseTransferPacket)
00032 #endif
00033 
00034 
00035 ULONG MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer;
00036 ULONG MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer;
00037 
00038 
00039 /*
00040  *  InitializeTransferPackets
00041  *
00042  *      Allocate/initialize TRANSFER_PACKETs and related resources.
00043  */
00044 NTSTATUS InitializeTransferPackets(PDEVICE_OBJECT Fdo)
00045 {
00046     PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension;
00047     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
00048     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00049     PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor;
00050     ULONG hwMaxPages;
00051     NTSTATUS status = STATUS_SUCCESS;
00052 
00053     PAGED_CODE();
00054     
00055     /*
00056      *  Precompute the maximum transfer length
00057      */
00058     ASSERT(adapterDesc->MaximumTransferLength);
00059     ASSERT(adapterDesc->MaximumPhysicalPages);
00060     hwMaxPages = adapterDesc->MaximumPhysicalPages ? adapterDesc->MaximumPhysicalPages-1 : 0;
00061 
00062 #if defined(_AMD64_SIMULATOR_)
00063 
00064     //
00065     // The simulator appears to have a problem with large transfers.
00066     //
00067 
00068     if (hwMaxPages > 4) {
00069         hwMaxPages = 4;
00070     }
00071 
00072 #endif
00073 
00074     fdoData->HwMaxXferLen = MIN(adapterDesc->MaximumTransferLength, hwMaxPages << PAGE_SHIFT);
00075     fdoData->HwMaxXferLen = MAX(fdoData->HwMaxXferLen, PAGE_SIZE);
00076 
00077     fdoData->NumTotalTransferPackets = 0;
00078     fdoData->NumFreeTransferPackets = 0;
00079     InitializeSListHead(&fdoData->FreeTransferPacketsList);
00080     InitializeListHead(&fdoData->AllTransferPacketsList);
00081     InitializeListHead(&fdoData->DeferredClientIrpList);
00082         
00083     /*
00084      *  Set the packet threshold numbers based on the Windows SKU.
00085      */
00086     if (ExVerifySuite(Personal)){
00087         // this is Windows Personal
00088         MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer;
00089         MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer;
00090     }
00091     else if (ExVerifySuite(Enterprise) || ExVerifySuite(DataCenter)){
00092         // this is Advanced Server or Datacenter
00093         MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Enterprise;
00094         MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Enterprise;
00095     }
00096     else if (ExVerifySuite(TerminalServer)){
00097         // this is standard Server or Pro with terminal server
00098         MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Server;
00099         MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Server;
00100     }
00101     else {
00102         // this is Professional without terminal server
00103         MinWorkingSetTransferPackets = MIN_WORKINGSET_TRANSFER_PACKETS_Consumer;
00104         MaxWorkingSetTransferPackets = MAX_WORKINGSET_TRANSFER_PACKETS_Consumer;
00105     }
00106 
00107     while (fdoData->NumFreeTransferPackets < MIN_INITIAL_TRANSFER_PACKETS){
00108         PTRANSFER_PACKET pkt = NewTransferPacket(Fdo);
00109         if (pkt){
00110             InterlockedIncrement(&fdoData->NumTotalTransferPackets);
00111             EnqueueFreeTransferPacket(Fdo, pkt);
00112         }
00113         else {
00114             status = STATUS_INSUFFICIENT_RESOURCES;
00115             break;
00116         }
00117     }
00118     fdoData->DbgPeakNumTransferPackets = fdoData->NumTotalTransferPackets;
00119     
00120     /*
00121      *  Pre-initialize our SCSI_REQUEST_BLOCK template with all
00122      *  the constant fields.  This will save a little time for each xfer.
00123      *  NOTE: a CdbLength field of 10 may not always be appropriate
00124      */
00125     RtlZeroMemory(&fdoData->SrbTemplate, sizeof(SCSI_REQUEST_BLOCK));
00126     fdoData->SrbTemplate.Length = sizeof(SCSI_REQUEST_BLOCK);
00127     fdoData->SrbTemplate.Function = SRB_FUNCTION_EXECUTE_SCSI;
00128     fdoData->SrbTemplate.QueueAction = SRB_SIMPLE_TAG_REQUEST;
00129     fdoData->SrbTemplate.SenseInfoBufferLength = sizeof(SENSE_DATA);
00130     fdoData->SrbTemplate.CdbLength = 10;
00131 
00132     return status;
00133 }
00134 
00135 
00136 VOID DestroyAllTransferPackets(PDEVICE_OBJECT Fdo)
00137 {
00138     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
00139     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00140     TRANSFER_PACKET *pkt;
00141 
00142     PAGED_CODE();
00143     
00144     ASSERT(IsListEmpty(&fdoData->DeferredClientIrpList));
00145 
00146     while (pkt = DequeueFreeTransferPacket(Fdo, FALSE)){
00147         DestroyTransferPacket(pkt);
00148         InterlockedDecrement(&fdoData->NumTotalTransferPackets);    
00149     }
00150 
00151     ASSERT(fdoData->NumTotalTransferPackets == 0);
00152 }
00153 
00154 
00155 PTRANSFER_PACKET NewTransferPacket(PDEVICE_OBJECT Fdo)
00156 {
00157     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
00158     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00159     PTRANSFER_PACKET newPkt;
00160 
00161     newPkt = ExAllocatePoolWithTag(NonPagedPool, sizeof(TRANSFER_PACKET), 'pnPC');
00162     if (newPkt){
00163         RtlZeroMemory(newPkt, sizeof(TRANSFER_PACKET)); // just to be sure
00164 
00165         /*
00166          *  Allocate resources for the packet.
00167          */
00168         newPkt->Irp = IoAllocateIrp(Fdo->StackSize, FALSE);
00169         if (newPkt->Irp){
00170             KIRQL oldIrql;
00171             
00172             newPkt->Fdo = Fdo;
00173 
00174             /*
00175              *  Enqueue the packet in our static AllTransferPacketsList
00176              *  (just so we can find it during debugging if its stuck somewhere).
00177              */
00178             KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
00179             InsertTailList(&fdoData->AllTransferPacketsList, &newPkt->AllPktsListEntry);
00180             KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
00181         }
00182         else {
00183             ExFreePool(newPkt);
00184             newPkt = NULL;
00185         }
00186     }
00187 
00188     return newPkt;
00189 }
00190 
00191 
00192 /*
00193  *  DestroyTransferPacket
00194  *
00195  */
00196 VOID DestroyTransferPacket(PTRANSFER_PACKET Pkt)
00197 {
00198     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
00199     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00200     KIRQL oldIrql;
00201 
00202     ASSERT(!Pkt->SlistEntry.Next);
00203     ASSERT(!Pkt->OriginalIrp);
00204 
00205     KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
00206 
00207     /*
00208      *  Delete the packet from our all-packets queue.
00209      */
00210     ASSERT(!IsListEmpty(&Pkt->AllPktsListEntry));
00211     ASSERT(!IsListEmpty(&fdoData->AllTransferPacketsList));
00212     RemoveEntryList(&Pkt->AllPktsListEntry);
00213     InitializeListHead(&Pkt->AllPktsListEntry);
00214 
00215     KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
00216 
00217     IoFreeIrp(Pkt->Irp);
00218     ExFreePool(Pkt);
00219 }
00220 
00221 
00222 VOID EnqueueFreeTransferPacket(PDEVICE_OBJECT Fdo, PTRANSFER_PACKET Pkt)
00223 {
00224     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
00225     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00226     KIRQL oldIrql;
00227     ULONG newNumPkts;
00228     
00229     ASSERT(!Pkt->SlistEntry.Next);
00230 
00231     InterlockedPushEntrySList(&fdoData->FreeTransferPacketsList, &Pkt->SlistEntry);
00232     newNumPkts = InterlockedIncrement(&fdoData->NumFreeTransferPackets);
00233     ASSERT(newNumPkts <= fdoData->NumTotalTransferPackets);
00234 
00235     /*
00236      *  If the total number of packets is larger than MinWorkingSetTransferPackets,
00237      *  that means that we've been in stress.  If all those packets are now
00238      *  free, then we are now out of stress and can free the extra packets.
00239      *  Free down to MaxWorkingSetTransferPackets immediately, and
00240      *  down to MinWorkingSetTransferPackets lazily (one at a time).
00241      */
00242     if (fdoData->NumFreeTransferPackets >= fdoData->NumTotalTransferPackets){
00243 
00244         /*
00245          *  1.  Immediately snap down to our UPPER threshold.
00246          */
00247         if (fdoData->NumTotalTransferPackets > MaxWorkingSetTransferPackets){
00248             SINGLE_LIST_ENTRY pktList;
00249             PSINGLE_LIST_ENTRY slistEntry;
00250             PTRANSFER_PACKET pktToDelete;
00251 
00252             DBGTRACE(ClassDebugTrace, ("Exiting stress, block freeing (%d-%d) packets.", fdoData->NumTotalTransferPackets, MaxWorkingSetTransferPackets));
00253 
00254             /*
00255              *  Check the counter again with lock held.  This eliminates a race condition
00256              *  while still allowing us to not grab the spinlock in the common codepath.
00257              *
00258              *  Note that the spinlock does not synchronize with threads dequeuing free
00259              *  packets to send (DequeueFreeTransferPacket does that with a lightweight
00260              *  interlocked exchange); the spinlock prevents multiple threads in this function
00261              *  from deciding to free too many extra packets at once.
00262              */
00263             SimpleInitSlistHdr(&pktList);
00264             KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
00265             while ((fdoData->NumFreeTransferPackets >= fdoData->NumTotalTransferPackets) && 
00266                    (fdoData->NumTotalTransferPackets > MaxWorkingSetTransferPackets)){
00267                    
00268                 pktToDelete = DequeueFreeTransferPacket(Fdo, FALSE);   
00269                 if (pktToDelete){
00270                     SimplePushSlist(&pktList, &pktToDelete->SlistEntry);
00271                     InterlockedDecrement(&fdoData->NumTotalTransferPackets);    
00272                 }
00273                 else {
00274                     DBGTRACE(ClassDebugTrace, ("Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (1).", MaxWorkingSetTransferPackets, Fdo, fdoData->NumTotalTransferPackets));
00275                     break;
00276                 }
00277             }
00278             KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
00279 
00280             while (slistEntry = SimplePopSlist(&pktList)){
00281                 pktToDelete = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
00282                 DestroyTransferPacket(pktToDelete);
00283             }
00284 
00285         }
00286 
00287         /*
00288          *  2.  Lazily work down to our LOWER threshold (by only freeing one packet at a time).
00289          */
00290         if (fdoData->NumTotalTransferPackets > MinWorkingSetTransferPackets){
00291             /*
00292              *  Check the counter again with lock held.  This eliminates a race condition
00293              *  while still allowing us to not grab the spinlock in the common codepath.
00294              *
00295              *  Note that the spinlock does not synchronize with threads dequeuing free
00296              *  packets to send (DequeueFreeTransferPacket does that with a lightweight
00297              *  interlocked exchange); the spinlock prevents multiple threads in this function
00298              *  from deciding to free too many extra packets at once.
00299              */
00300             PTRANSFER_PACKET pktToDelete = NULL; 
00301 
00302             DBGTRACE(ClassDebugTrace, ("Exiting stress, lazily freeing one of %d/%d packets.", fdoData->NumTotalTransferPackets, MinWorkingSetTransferPackets));
00303             
00304             KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
00305             if ((fdoData->NumFreeTransferPackets >= fdoData->NumTotalTransferPackets) &&
00306                 (fdoData->NumTotalTransferPackets > MinWorkingSetTransferPackets)){
00307                 
00308                 pktToDelete = DequeueFreeTransferPacket(Fdo, FALSE);
00309                 if (pktToDelete){
00310                     InterlockedDecrement(&fdoData->NumTotalTransferPackets);    
00311                 }
00312                 else {
00313                     DBGTRACE(ClassDebugTrace, ("Extremely unlikely condition (non-fatal): %d packets dequeued at once for Fdo %p. NumTotalTransferPackets=%d (2).", MinWorkingSetTransferPackets, Fdo, fdoData->NumTotalTransferPackets));
00314                 }
00315             }
00316             KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
00317 
00318             if (pktToDelete){
00319                 DestroyTransferPacket(pktToDelete);
00320             }
00321         }
00322 
00323     }
00324   
00325 }
00326 
00327 
00328 PTRANSFER_PACKET DequeueFreeTransferPacket(PDEVICE_OBJECT Fdo, BOOLEAN AllocIfNeeded)
00329 {
00330     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
00331     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00332     PTRANSFER_PACKET pkt;
00333     PSINGLE_LIST_ENTRY slistEntry;
00334     KIRQL oldIrql;
00335 
00336     slistEntry = InterlockedPopEntrySList(&fdoData->FreeTransferPacketsList);
00337     if (slistEntry){
00338         slistEntry->Next = NULL;
00339         pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
00340         ASSERT(fdoData->NumFreeTransferPackets > 0);
00341         InterlockedDecrement(&fdoData->NumFreeTransferPackets);
00342     }
00343     else {
00344         if (AllocIfNeeded){
00345             /*
00346              *  We are in stress and have run out of lookaside packets.
00347              *  In order to service the current transfer, 
00348              *  allocate an extra packet.  
00349              *  We will free it lazily when we are out of stress.
00350              */
00351             pkt = NewTransferPacket(Fdo);
00352             if (pkt){
00353                 InterlockedIncrement(&fdoData->NumTotalTransferPackets);
00354                 fdoData->DbgPeakNumTransferPackets = max(fdoData->DbgPeakNumTransferPackets, fdoData->NumTotalTransferPackets);
00355             }
00356             else {
00357                 DBGWARN(("DequeueFreeTransferPacket: packet allocation failed"));
00358             }
00359         }
00360         else {
00361             pkt = NULL;
00362         }
00363     }
00364     
00365     return pkt;
00366 }
00367 
00368 
00369 
00370 /*
00371  *  SetupReadWriteTransferPacket
00372  *
00373  *        This function is called once to set up the first attempt to send a packet.
00374  *        It is not called before a retry, as SRB fields may be modified for the retry.
00375  *
00376  *      Set up the Srb of the TRANSFER_PACKET for the transfer.
00377  *        The Irp is set up in SubmitTransferPacket because it must be reset
00378  *        for each packet submission.
00379  */
00380 VOID SetupReadWriteTransferPacket(  PTRANSFER_PACKET Pkt, 
00381                                             PVOID Buf, 
00382                                             ULONG Len, 
00383                                             LARGE_INTEGER DiskLocation,
00384                                             PIRP OriginalIrp)
00385 {
00386     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
00387     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00388     PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(OriginalIrp);
00389     UCHAR majorFunc = origCurSp->MajorFunction;
00390     ULONG logicalBlockAddr;
00391     ULONG numTransferBlocks;
00392     PCDB pCdb;
00393   
00394     logicalBlockAddr = (ULONG)Int64ShrlMod32(DiskLocation.QuadPart, fdoExt->SectorShift);
00395     numTransferBlocks = Len >> fdoExt->SectorShift;
00396 
00397     /*
00398      *  Slap the constant SRB fields in from our pre-initialized template.
00399      *  We'll then only have to fill in the unique fields for this transfer.
00400      *  Tell lower drivers to sort the SRBs by the logical block address 
00401      *  so that disk seeks are minimized.
00402      */
00403     Pkt->Srb = fdoData->SrbTemplate;    // copies _contents_ of SRB blocks
00404     Pkt->Srb.DataBuffer = Buf;
00405     Pkt->Srb.DataTransferLength = Len;
00406     Pkt->Srb.QueueSortKey = logicalBlockAddr;  
00407     Pkt->Srb.OriginalRequest = Pkt->Irp;
00408     Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
00409     Pkt->Srb.TimeOutValue = (Len/0x10000) + ((Len%0x10000) ? 1 : 0);
00410     Pkt->Srb.TimeOutValue *= fdoExt->TimeOutValue;
00411 
00412     /*
00413      *  Arrange values in CDB in big-endian format.
00414      */
00415     pCdb = (PCDB)Pkt->Srb.Cdb;
00416     pCdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte3;
00417     pCdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte2;
00418     pCdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte1;
00419     pCdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr)->Byte0;
00420     pCdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1;
00421     pCdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0;
00422     pCdb->CDB10.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ : SCSIOP_WRITE;
00423 
00424     /*
00425      *  Set SRB and IRP flags    
00426      */
00427     Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
00428     if (TEST_FLAG(OriginalIrp->Flags, IRP_PAGING_IO) ||
00429         TEST_FLAG(OriginalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)){
00430         SET_FLAG(Pkt->Srb.SrbFlags, SRB_CLASS_FLAGS_PAGING);
00431     }
00432     SET_FLAG(Pkt->Srb.SrbFlags, (majorFunc==IRP_MJ_READ) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT);
00433 
00434     /*
00435      *  Allow caching only if this is not a write-through request.
00436      *  If write-through and caching is enabled on the device, force
00437      *  media access.
00438      */
00439     if (TEST_FLAG(origCurSp->Flags, SL_WRITE_THROUGH)){
00440         if (TEST_FLAG(fdoExt->DeviceFlags, DEV_WRITE_CACHE)){
00441             pCdb->CDB10.ForceUnitAccess = TRUE;
00442         }
00443     }
00444     else {
00445         SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE);
00446     } 
00447 
00448     /*
00449      *  Remember the buf and len in the SRB because miniports
00450      *  can overwrite SRB.DataTransferLength and we may need it again
00451      *  for the retry.
00452      */
00453     Pkt->BufPtrCopy = Buf;
00454     Pkt->BufLenCopy = Len;
00455     Pkt->TargetLocationCopy = DiskLocation;
00456     
00457     Pkt->OriginalIrp = OriginalIrp;
00458     Pkt->NumRetries = MAXIMUM_RETRIES;    
00459     Pkt->SyncEventPtr = NULL;
00460     Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE;
00461 }
00462 
00463 
00464 /*
00465  *  SubmitTransferPacket
00466  *
00467  *        Set up the IRP for the TRANSFER_PACKET submission and send it down.
00468  */
00469 VOID SubmitTransferPacket(PTRANSFER_PACKET Pkt)
00470 {
00471     PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
00472     PDEVICE_OBJECT nextDevObj = commonExtension->LowerDeviceObject;
00473     PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(Pkt->Irp);
00474     
00475     ASSERT(Pkt->Irp->CurrentLocation == Pkt->Irp->StackCount+1);
00476 
00477     /*
00478      *  Attach the SRB to the IRP.
00479      *  The reused IRP's stack location has to be rewritten for each retry
00480      *  call because IoCompleteRequest clears the stack locations.
00481      */
00482     IoReuseIrp(Pkt->Irp, STATUS_NOT_SUPPORTED);
00483     nextSp->MajorFunction = IRP_MJ_SCSI;
00484     nextSp->Parameters.Scsi.Srb = &Pkt->Srb;
00485     Pkt->Srb.ScsiStatus = Pkt->Srb.SrbStatus = 0;
00486     if (Pkt->CompleteOriginalIrpWhenLastPacketCompletes){
00487         /*
00488          *  Only dereference the "original IRP"'s stack location
00489          *  if its a real client irp (as opposed to a static irp 
00490          *  we're using just for result status for one of the non-IO scsi commands).
00491          *
00492          *  For read/write, propagate the storage-specific IRP stack location flags
00493          *  (e.g. SL_OVERRIDE_VERIFY_VOLUME, SL_WRITE_THROUGH).
00494          */
00495         PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);
00496         nextSp->Flags = origCurSp->Flags;
00497     }
00498 
00499     /*
00500      *  Write MDL address to new IRP. In the port driver the SRB DataBuffer
00501      *  field is used as the actual buffer pointer within the MDL, 
00502      *  so the same MDL can be used for each partial transfer. 
00503      *  This saves having to build a new MDL for each partial transfer.
00504      */
00505     Pkt->Irp->MdlAddress = Pkt->OriginalIrp->MdlAddress;
00506     
00507     IoSetCompletionRoutine(Pkt->Irp, TransferPktComplete, Pkt, TRUE, TRUE, TRUE);
00508     IoCallDriver(nextDevObj, Pkt->Irp);
00509 }
00510 
00511 
00512 NTSTATUS TransferPktComplete(IN PDEVICE_OBJECT NullFdo, IN PIRP Irp, IN PVOID Context)
00513 {
00514     PTRANSFER_PACKET pkt = (PTRANSFER_PACKET)Context;
00515     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = pkt->Fdo->DeviceExtension;
00516     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00517     PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(pkt->OriginalIrp);
00518     BOOLEAN packetDone = FALSE;
00519 
00520     /*
00521      *  Put all the assertions and spew in here so we don't have to look at them.
00522      */
00523     DBGCHECKRETURNEDPKT(pkt);    
00524     
00525     if (SRB_STATUS(pkt->Srb.SrbStatus) == SRB_STATUS_SUCCESS){
00526         
00527         fdoData->LoggedTURFailureSinceLastIO = FALSE;
00528         
00529         /*
00530          *  The port driver should not have allocated a sense buffer
00531          *  if the SRB succeeded.
00532          */
00533         ASSERT(!PORT_ALLOCATED_SENSE(fdoExt, &pkt->Srb));
00534 
00535         /*
00536          *  Add this packet's transferred length to the original IRP's.
00537          */
00538         InterlockedExchangeAdd((PLONG)&pkt->OriginalIrp->IoStatus.Information, 
00539                               (LONG)pkt->Srb.DataTransferLength);
00540 
00541         if (pkt->InLowMemRetry){
00542             packetDone = StepLowMemRetry(pkt);
00543         }
00544         else {
00545             packetDone = TRUE;
00546         }
00547         
00548     }
00549     else {
00550         /*
00551          *  The packet failed.  We may retry it if possible.
00552          */
00553         BOOLEAN shouldRetry;
00554         
00555         /*
00556          *  Make sure IRP status matches SRB error status (since we propagate it).
00557          */
00558         if (NT_SUCCESS(Irp->IoStatus.Status)){
00559             Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
00560         }
00561 
00562         /*
00563          *  Interpret the SRB error (to a meaningful IRP status)
00564          *  and determine if we should retry this packet.
00565          *  This call looks at the returned SENSE info to figure out what to do.
00566          */
00567         shouldRetry = InterpretTransferPacketError(pkt);
00568 
00569         /*
00570          *  Sometimes the port driver can allocates a new 'sense' buffer
00571          *  to report transfer errors, e.g. when the default sense buffer
00572          *  is too small.  If so, it is up to us to free it.
00573          *  Now that we're done interpreting the sense info, free it if appropriate.
00574          */
00575         if (PORT_ALLOCATED_SENSE(fdoExt, &pkt->Srb)) {
00576             DBGTRACE(ClassDebugSenseInfo, ("Freeing port-allocated sense buffer for pkt %ph.", pkt));
00577             FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExt, &pkt->Srb);
00578             pkt->Srb.SenseInfoBuffer = &pkt->SrbErrorSenseData;
00579             pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
00580         }
00581 
00582         /*
00583          *  If the SRB queue is locked-up, release it.
00584          *  Do this after calling the error handler.
00585          */
00586         if (pkt->Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN){
00587             ClassReleaseQueue(pkt->Fdo);
00588         }
00589         
00590         if (shouldRetry && (pkt->NumRetries > 0)){           
00591             packetDone = RetryTransferPacket(pkt);
00592         }
00593         else {
00594             packetDone = TRUE;
00595         }
00596         
00597     }
00598 
00599     /*
00600      *  If the packet is completed, put it back in the free list.
00601      *  If it is the last packet servicing the original request, complete the original irp.
00602      */
00603     if (packetDone){
00604         LONG numPacketsRemaining;
00605         PIRP deferredIrp;
00606         PDEVICE_OBJECT Fdo = pkt->Fdo;
00607         UCHAR uniqueAddr;
00608         
00609         /*
00610          *  In case a remove is pending, bump the lock count so we don't get freed
00611          *  right after we complete the original irp.
00612          */
00613         ClassAcquireRemoveLock(Fdo, (PIRP)&uniqueAddr);        
00614 
00615         /*
00616          *  The original IRP should get an error code
00617          *  if any one of the packets failed.
00618          */
00619         if (!NT_SUCCESS(Irp->IoStatus.Status)){
00620             pkt->OriginalIrp->IoStatus.Status = Irp->IoStatus.Status;
00621 
00622             /*
00623              *  If the original I/O originated in user space (i.e. it is thread-queued), 
00624              *  and the error is user-correctable (e.g. media is missing, for removable media),
00625              *  alert the user.
00626              *  Since this is only one of possibly several packets completing for the original IRP,
00627              *  we may do this more than once for a single request.  That's ok; this allows
00628              *  us to test each returned status with IoIsErrorUserInduced().
00629              */
00630             if (IoIsErrorUserInduced(Irp->IoStatus.Status) &&
00631                 pkt->CompleteOriginalIrpWhenLastPacketCompletes &&
00632                 pkt->OriginalIrp->Tail.Overlay.Thread){
00633 
00634                 IoSetHardErrorOrVerifyDevice(pkt->OriginalIrp, pkt->Fdo);
00635             }
00636         }
00637 
00638         /*
00639          *  We use a field in the original IRP to count
00640          *  down the transfer pieces as they complete.
00641          */
00642         numPacketsRemaining = InterlockedDecrement(
00643             (PLONG)&pkt->OriginalIrp->Tail.Overlay.DriverContext[0]);
00644             
00645         if (numPacketsRemaining > 0){
00646             /*
00647              *  More transfer pieces remain for the original request.
00648              *  Wait for them to complete before completing the original irp.
00649              */
00650         }
00651         else {
00652 
00653             /*
00654              *  All the transfer pieces are done.
00655              *  Complete the original irp if appropriate.
00656              */
00657             ASSERT(numPacketsRemaining == 0);
00658             if (pkt->CompleteOriginalIrpWhenLastPacketCompletes){  
00659                 if (NT_SUCCESS(pkt->OriginalIrp->IoStatus.Status)){
00660                     ASSERT((ULONG)pkt->OriginalIrp->IoStatus.Information == origCurrentSp->Parameters.Read.Length);
00661                     ClasspPerfIncrementSuccessfulIo(fdoExt);
00662                 }
00663                 ClassReleaseRemoveLock(pkt->Fdo, pkt->OriginalIrp);
00664 
00665                 ClassCompleteRequest(pkt->Fdo, pkt->OriginalIrp, IO_DISK_INCREMENT);
00666 
00667                 /*
00668                  *  We may have been called by one of the class drivers (e.g. cdrom)
00669                  *  via the legacy API ClassSplitRequest.  
00670                  *  This is the only case for which the packet engine is called for an FDO
00671                  *  with a StartIo routine; in that case, we have to call IoStartNextPacket
00672                  *  now that the original irp has been completed.
00673                  */
00674                 if (fdoExt->CommonExtension.DriverExtension->InitData.ClassStartIo) {
00675                     if (TEST_FLAG(pkt->Srb.SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET)){
00676                         DBGTRAP(("SRB_FLAGS_DONT_START_NEXT_PACKET should never be set here (?)"));
00677                     }
00678                     else {
00679                         KIRQL oldIrql;
00680                         KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
00681                         IoStartNextPacket(pkt->Fdo, FALSE);
00682                         KeLowerIrql(oldIrql);
00683                     }
00684                 }              
00685             }            
00686         }
00687 
00688         /*
00689          *  If the packet was synchronous, write the final
00690          *  result back to the issuer's status buffer and
00691          *  signal his event.
00692          */
00693         if (pkt->SyncEventPtr){
00694             KeSetEvent(pkt->SyncEventPtr, 0, FALSE);
00695             pkt->SyncEventPtr = NULL;
00696         }
00697 
00698         /*
00699          *  Free the completed packet.
00700          */
00701         pkt->OriginalIrp = NULL;
00702         pkt->InLowMemRetry = FALSE;
00703         EnqueueFreeTransferPacket(pkt->Fdo, pkt);
00704 
00705         /*
00706          *  Now that we have freed some resources,
00707          *  try again to send one of the previously deferred irps.
00708          */
00709         deferredIrp = DequeueDeferredClientIrp(fdoData);
00710         if (deferredIrp){
00711             DBGWARN(("... retrying deferred irp %xh.", deferredIrp)); 
00712             ServiceTransferRequest(pkt->Fdo, deferredIrp);
00713         }
00714 
00715         ClassReleaseRemoveLock(Fdo, (PIRP)&uniqueAddr);        
00716     }
00717 
00718     return STATUS_MORE_PROCESSING_REQUIRED;
00719 }
00720 
00721 
00722 /*
00723  *  SetupEjectionTransferPacket
00724  *
00725  *      Set up a transferPacket for a synchronous Ejection Control transfer.
00726  */
00727 VOID SetupEjectionTransferPacket(   TRANSFER_PACKET *Pkt,
00728                                         BOOLEAN PreventMediaRemoval,
00729                                         PKEVENT SyncEventPtr,
00730                                         PIRP OriginalIrp)
00731 {
00732     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
00733     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00734     PCDB pCdb;
00735 
00736     PAGED_CODE();
00737 
00738     RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
00739     
00740     Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00741     Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00742     Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;   
00743     Pkt->Srb.CdbLength = 6;
00744     Pkt->Srb.OriginalRequest = Pkt->Irp;
00745     Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
00746     Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
00747     Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
00748 
00749     Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
00750     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
00751     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
00752 
00753     pCdb = (PCDB)Pkt->Srb.Cdb;
00754     pCdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
00755     pCdb->MEDIA_REMOVAL.Prevent = PreventMediaRemoval;
00756 
00757     Pkt->BufPtrCopy = NULL;
00758     Pkt->BufLenCopy = 0;
00759 
00760     Pkt->OriginalIrp = OriginalIrp;
00761     Pkt->NumRetries = NUM_LOCKMEDIAREMOVAL_RETRIES;          
00762     Pkt->SyncEventPtr = SyncEventPtr;
00763     Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
00764 }
00765                                 
00766 
00767 /*
00768  *  SetupModeSenseTransferPacket
00769  *
00770  *      Set up a transferPacket for a synchronous Mode Sense transfer.
00771  */
00772 VOID SetupModeSenseTransferPacket(   TRANSFER_PACKET *Pkt,
00773                                         PKEVENT SyncEventPtr,
00774                                         PVOID ModeSenseBuffer,
00775                                         UCHAR ModeSenseBufferLen,
00776                                         UCHAR PageMode,
00777                                         PIRP OriginalIrp)
00778 {
00779     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
00780     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00781     PCDB pCdb;
00782 
00783     PAGED_CODE();
00784 
00785     RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
00786     
00787     Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00788     Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00789     Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;   
00790     Pkt->Srb.CdbLength = 6;
00791     Pkt->Srb.OriginalRequest = Pkt->Irp;
00792     Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
00793     Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
00794     Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
00795     Pkt->Srb.DataBuffer = ModeSenseBuffer;
00796     Pkt->Srb.DataTransferLength = ModeSenseBufferLen;
00797 
00798     Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
00799     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);    
00800     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
00801     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
00802 
00803     pCdb = (PCDB)Pkt->Srb.Cdb;
00804     pCdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
00805     pCdb->MODE_SENSE.PageCode = PageMode;
00806     pCdb->MODE_SENSE.AllocationLength = (UCHAR)ModeSenseBufferLen;
00807 
00808     Pkt->BufPtrCopy = ModeSenseBuffer;
00809     Pkt->BufLenCopy = ModeSenseBufferLen;
00810         
00811     Pkt->OriginalIrp = OriginalIrp;
00812     Pkt->NumRetries = NUM_MODESENSE_RETRIES;          
00813     Pkt->SyncEventPtr = SyncEventPtr;
00814     Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
00815 }
00816 
00817 
00818 /*
00819  *  SetupDriveCapacityTransferPacket
00820  *
00821  *      Set up a transferPacket for a synchronous Drive Capacity transfer.
00822  */
00823 VOID SetupDriveCapacityTransferPacket(   TRANSFER_PACKET *Pkt,
00824                                         PVOID ReadCapacityBuffer,
00825                                         ULONG ReadCapacityBufferLen,
00826                                         PKEVENT SyncEventPtr,
00827                                         PIRP OriginalIrp)
00828 {
00829     PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
00830     PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00831     PCDB pCdb;
00832 
00833     RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
00834     
00835     Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00836     Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00837     Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;   
00838     Pkt->Srb.CdbLength = 10;
00839     Pkt->Srb.OriginalRequest = Pkt->Irp;
00840     Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
00841     Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
00842     Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
00843     Pkt->Srb.DataBuffer = ReadCapacityBuffer;
00844     Pkt->Srb.DataTransferLength = ReadCapacityBufferLen;
00845 
00846     Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
00847     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);    
00848     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
00849     SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
00850 
00851     pCdb = (PCDB)Pkt->Srb.Cdb;
00852     pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
00853 
00854     Pkt->BufPtrCopy = ReadCapacityBuffer;
00855     Pkt->BufLenCopy = ReadCapacityBufferLen;
00856 
00857     Pkt->OriginalIrp = OriginalIrp;
00858     Pkt->NumRetries = NUM_DRIVECAPACITY_RETRIES;          
00859     Pkt->SyncEventPtr = SyncEventPtr;
00860     Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
00861 }
00862 
00863 
00864 #if 0
00865     /*
00866      *  SetupSendStartUnitTransferPacket
00867      *
00868      *      Set up a transferPacket for a synchronous Send Start Unit transfer.
00869      */
00870     VOID SetupSendStartUnitTransferPacket(   TRANSFER_PACKET *Pkt,
00871                                                     PIRP OriginalIrp)
00872     {
00873         PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
00874         PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
00875         PCDB pCdb;
00876 
00877         PAGED_CODE();
00878 
00879         RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));
00880 
00881         /*
00882          *  Initialize the SRB.
00883          *  Use a very long timeout value to give the drive time to spin up.
00884          */
00885         Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
00886         Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
00887         Pkt->Srb.TimeOutValue = START_UNIT_TIMEOUT;
00888         Pkt->Srb.CdbLength = 6;
00889         Pkt->Srb.OriginalRequest = Pkt->Irp;
00890         Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
00891         Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
00892         Pkt->Srb.Lun = 0;
00893         
00894         SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER);    
00895         SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
00896         SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
00897 
00898         pCdb = (PCDB)Pkt->Srb.Cdb;
00899         pCdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
00900         pCdb->START_STOP.Start = 1;
00901         pCdb->START_STOP.Immediate = 0;
00902         pCdb->START_STOP.LogicalUnitNumber = 0;
00903 
00904         Pkt->OriginalIrp = OriginalIrp;
00905         Pkt->NumRetries = 0;          
00906         Pkt->SyncEventPtr = NULL;
00907         Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
00908     }
00909 #endif
00910 
00911 

Generated on Fri May 25 2012 04:26:38 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.