Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenxferpkt.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
1.7.6.1
|