Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenscsiport.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS kernel 00003 * Copyright (C) 2001, 2002 ReactOS Team 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along 00016 * with this program; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 */ 00019 /* 00020 * COPYRIGHT: See COPYING in the top level directory 00021 * PROJECT: ReactOS Storage Stack 00022 * FILE: drivers/storage/scsiport/scsiport.c 00023 * PURPOSE: SCSI port driver 00024 * PROGRAMMER: Eric Kohl 00025 * Aleksey Bragin (aleksey reactos org) 00026 */ 00027 00028 /* INCLUDES *****************************************************************/ 00029 00030 #include "precomp.h" 00031 00032 #ifndef NDEBUG 00033 #define NDEBUG 00034 #endif 00035 #include <debug.h> 00036 00037 ULONG InternalDebugLevel = 0x00; 00038 00039 #undef ScsiPortMoveMemory 00040 00041 /* TYPES *********************************************************************/ 00042 00043 /* GLOBALS *******************************************************************/ 00044 00045 static BOOLEAN 00046 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject, 00047 IN PDEVICE_OBJECT DeviceObject, 00048 IN struct _HW_INITIALIZATION_DATA *HwInitializationData, 00049 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, 00050 IN PUNICODE_STRING RegistryPath, 00051 IN ULONG BusNumber, 00052 IN OUT PPCI_SLOT_NUMBER NextSlotNumber); 00053 00054 static NTSTATUS NTAPI 00055 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject, 00056 IN PIRP Irp); 00057 00058 static DRIVER_DISPATCH ScsiPortDispatchScsi; 00059 static NTSTATUS NTAPI 00060 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject, 00061 IN PIRP Irp); 00062 00063 static NTSTATUS NTAPI 00064 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject, 00065 IN PIRP Irp); 00066 00067 static DRIVER_STARTIO ScsiPortStartIo; 00068 static VOID NTAPI 00069 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject, 00070 IN PIRP Irp); 00071 00072 static BOOLEAN NTAPI 00073 ScsiPortStartPacket(IN OUT PVOID Context); 00074 00075 IO_ALLOCATION_ACTION 00076 NTAPI 00077 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, PIRP Irp, 00078 PVOID MapRegisterBase, PVOID Context); 00079 00080 static PSCSI_PORT_LUN_EXTENSION 00081 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); 00082 00083 static PSCSI_PORT_LUN_EXTENSION 00084 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00085 IN UCHAR PathId, 00086 IN UCHAR TargetId, 00087 IN UCHAR Lun); 00088 00089 static PSCSI_REQUEST_BLOCK_INFO 00090 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00091 PSCSI_PORT_LUN_EXTENSION LunExtension, 00092 PSCSI_REQUEST_BLOCK Srb); 00093 00094 static NTSTATUS 00095 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject, 00096 IN PSCSI_LUN_INFO LunInfo); 00097 00098 static VOID 00099 SpiScanAdapter (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); 00100 00101 static NTSTATUS 00102 SpiGetInquiryData (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00103 IN PIRP Irp); 00104 00105 static PSCSI_REQUEST_BLOCK_INFO 00106 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00107 IN UCHAR PathId, 00108 IN UCHAR TargetId, 00109 IN UCHAR Lun, 00110 IN UCHAR QueueTag); 00111 00112 static BOOLEAN NTAPI 00113 ScsiPortIsr(IN PKINTERRUPT Interrupt, 00114 IN PVOID ServiceContext); 00115 00116 static VOID NTAPI 00117 ScsiPortDpcForIsr(IN PKDPC Dpc, 00118 IN PDEVICE_OBJECT DpcDeviceObject, 00119 IN PIRP DpcIrp, 00120 IN PVOID DpcContext); 00121 00122 static VOID NTAPI 00123 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, 00124 PVOID Context); 00125 00126 IO_ALLOCATION_ACTION 00127 NTAPI 00128 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject, 00129 IN PIRP Irp, 00130 IN PVOID MapRegisterBase, 00131 IN PVOID Context); 00132 00133 static NTSTATUS 00134 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00135 PUNICODE_STRING RegistryPath); 00136 00137 static NTSTATUS 00138 SpiStatusSrbToNt(UCHAR SrbStatus); 00139 00140 static VOID 00141 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00142 IN PSCSI_REQUEST_BLOCK Srb); 00143 00144 static IO_COMPLETION_ROUTINE SpiCompletionRoutine; 00145 NTSTATUS NTAPI 00146 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject, 00147 PIRP Irp, 00148 PVOID Context); 00149 00150 static VOID 00151 NTAPI 00152 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00153 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo, 00154 OUT PBOOLEAN NeedToCallStartIo); 00155 00156 VOID NTAPI 00157 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00158 IN PSCSI_PORT_LUN_EXTENSION LunExtension); 00159 00160 VOID NTAPI 00161 SpiMiniportTimerDpc(IN struct _KDPC *Dpc, 00162 IN PVOID DeviceObject, 00163 IN PVOID SystemArgument1, 00164 IN PVOID SystemArgument2); 00165 00166 static NTSTATUS 00167 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00168 PHW_INITIALIZATION_DATA HwInitData, 00169 PCONFIGURATION_INFO InternalConfigInfo, 00170 PPORT_CONFIGURATION_INFORMATION ConfigInfo, 00171 BOOLEAN FirstCall); 00172 00173 NTSTATUS NTAPI 00174 SpQueryDeviceCallout(IN PVOID Context, 00175 IN PUNICODE_STRING PathName, 00176 IN INTERFACE_TYPE BusType, 00177 IN ULONG BusNumber, 00178 IN PKEY_VALUE_FULL_INFORMATION *BusInformation, 00179 IN CONFIGURATION_TYPE ControllerType, 00180 IN ULONG ControllerNumber, 00181 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, 00182 IN CONFIGURATION_TYPE PeripheralType, 00183 IN ULONG PeripheralNumber, 00184 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation); 00185 00186 static VOID 00187 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00188 IN HANDLE Key, 00189 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, 00190 IN PCONFIGURATION_INFO InternalConfigInfo, 00191 IN PUCHAR Buffer); 00192 00193 static VOID 00194 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData, 00195 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor, 00196 IN PPORT_CONFIGURATION_INFORMATION PortConfig); 00197 00198 static PCM_RESOURCE_LIST 00199 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00200 PPORT_CONFIGURATION_INFORMATION PortConfig); 00201 00202 static VOID 00203 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension); 00204 00205 static NTSTATUS 00206 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 00207 PIRP Irp); 00208 00209 static NTSTATUS 00210 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize); 00211 00212 NTHALAPI ULONG NTAPI HalGetBusData(BUS_DATA_TYPE, ULONG, ULONG, PVOID, ULONG); 00213 NTHALAPI ULONG NTAPI HalGetInterruptVector(INTERFACE_TYPE, ULONG, ULONG, ULONG, PKIRQL, PKAFFINITY); 00214 NTHALAPI NTSTATUS NTAPI HalAssignSlotResources(PUNICODE_STRING, PUNICODE_STRING, PDRIVER_OBJECT, PDEVICE_OBJECT, INTERFACE_TYPE, ULONG, ULONG, PCM_RESOURCE_LIST *); 00215 00216 /* FUNCTIONS *****************************************************************/ 00217 00218 /********************************************************************** 00219 * NAME EXPORTED 00220 * DriverEntry 00221 * 00222 * DESCRIPTION 00223 * This function initializes the driver. 00224 * 00225 * RUN LEVEL 00226 * PASSIVE_LEVEL 00227 * 00228 * ARGUMENTS 00229 * DriverObject 00230 * System allocated Driver Object for this driver. 00231 * 00232 * RegistryPath 00233 * Name of registry driver service key. 00234 * 00235 * RETURN VALUE 00236 * Status. 00237 */ 00238 00239 NTSTATUS NTAPI 00240 DriverEntry(IN PDRIVER_OBJECT DriverObject, 00241 IN PUNICODE_STRING RegistryPath) 00242 { 00243 DPRINT("ScsiPort Driver %s\n", VERSION); 00244 return(STATUS_SUCCESS); 00245 } 00246 00247 00248 /********************************************************************** 00249 * NAME EXPORTED 00250 * ScsiDebugPrint 00251 * 00252 * DESCRIPTION 00253 * Prints debugging messages. 00254 * 00255 * RUN LEVEL 00256 * PASSIVE_LEVEL 00257 * 00258 * ARGUMENTS 00259 * DebugPrintLevel 00260 * Debug level of the given message. 00261 * 00262 * DebugMessage 00263 * Pointer to printf()-compatible format string. 00264 * 00265 * ... 00266 Additional output data (see printf()). 00267 * 00268 * RETURN VALUE 00269 * None. 00270 * 00271 * @implemented 00272 */ 00273 00274 VOID 00275 ScsiDebugPrint(IN ULONG DebugPrintLevel, 00276 IN PCHAR DebugMessage, 00277 ...) 00278 { 00279 char Buffer[256]; 00280 va_list ap; 00281 00282 if (DebugPrintLevel > InternalDebugLevel) 00283 return; 00284 00285 va_start(ap, DebugMessage); 00286 vsprintf(Buffer, DebugMessage, ap); 00287 va_end(ap); 00288 00289 DbgPrint(Buffer); 00290 } 00291 00292 /* An internal helper function for ScsiPortCompleteRequest */ 00293 VOID 00294 NTAPI 00295 SpiCompleteRequest(IN PVOID HwDeviceExtension, 00296 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo, 00297 IN UCHAR SrbStatus) 00298 { 00299 PSCSI_REQUEST_BLOCK Srb; 00300 00301 /* Get current SRB */ 00302 Srb = SrbInfo->Srb; 00303 00304 /* Return if there is no SRB or it is not active */ 00305 if (!Srb || !(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) return; 00306 00307 /* Set status */ 00308 Srb->SrbStatus = SrbStatus; 00309 00310 /* Set data transfered to 0 */ 00311 Srb->DataTransferLength = 0; 00312 00313 /* Notify */ 00314 ScsiPortNotification(RequestComplete, 00315 HwDeviceExtension, 00316 Srb); 00317 } 00318 00319 /* 00320 * @unimplemented 00321 */ 00322 VOID NTAPI 00323 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension, 00324 IN UCHAR PathId, 00325 IN UCHAR TargetId, 00326 IN UCHAR Lun, 00327 IN UCHAR SrbStatus) 00328 { 00329 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00330 PSCSI_PORT_LUN_EXTENSION LunExtension; 00331 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 00332 PLIST_ENTRY ListEntry; 00333 ULONG BusNumber; 00334 ULONG Target; 00335 00336 DPRINT("ScsiPortCompleteRequest() called\n"); 00337 00338 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00339 SCSI_PORT_DEVICE_EXTENSION, 00340 MiniPortDeviceExtension); 00341 00342 /* Go through all buses */ 00343 for (BusNumber = 0; BusNumber < 8; BusNumber++) 00344 { 00345 /* Go through all targets */ 00346 for (Target = 0; Target < DeviceExtension->MaxTargedIds; Target++) 00347 { 00348 /* Get logical unit list head */ 00349 LunExtension = DeviceExtension->LunExtensionList[Target % 8]; 00350 00351 /* Go through all logical units */ 00352 while (LunExtension) 00353 { 00354 /* Now match what caller asked with what we are at now */ 00355 if ((PathId == SP_UNTAGGED || PathId == LunExtension->PathId) && 00356 (TargetId == SP_UNTAGGED || TargetId == LunExtension->TargetId) && 00357 (Lun == SP_UNTAGGED || Lun == LunExtension->Lun)) 00358 { 00359 /* Yes, that's what caller asked for. Complete abort requests */ 00360 if (LunExtension->CompletedAbortRequests) 00361 { 00362 /* TODO: Save SrbStatus in this request */ 00363 DPRINT1("Completing abort request without setting SrbStatus!\n"); 00364 00365 /* Issue a notification request */ 00366 ScsiPortNotification(RequestComplete, 00367 HwDeviceExtension, 00368 LunExtension->CompletedAbortRequests); 00369 } 00370 00371 /* Complete the request using our helper */ 00372 SpiCompleteRequest(HwDeviceExtension, 00373 &LunExtension->SrbInfo, 00374 SrbStatus); 00375 00376 /* Go through the queue and complete everything there too */ 00377 ListEntry = LunExtension->SrbInfo.Requests.Flink; 00378 while (ListEntry != &LunExtension->SrbInfo.Requests) 00379 { 00380 /* Get the actual SRB info entry */ 00381 SrbInfo = CONTAINING_RECORD(ListEntry, 00382 SCSI_REQUEST_BLOCK_INFO, 00383 Requests); 00384 00385 /* Complete it */ 00386 SpiCompleteRequest(HwDeviceExtension, 00387 SrbInfo, 00388 SrbStatus); 00389 00390 /* Advance to the next request in queue */ 00391 ListEntry = SrbInfo->Requests.Flink; 00392 } 00393 } 00394 00395 /* Advance to the next one */ 00396 LunExtension = LunExtension->Next; 00397 } 00398 } 00399 } 00400 } 00401 00402 /* 00403 * @unimplemented 00404 */ 00405 VOID NTAPI 00406 ScsiPortFlushDma(IN PVOID HwDeviceExtension) 00407 { 00408 DPRINT("ScsiPortFlushDma()\n"); 00409 UNIMPLEMENTED; 00410 } 00411 00412 00413 /* 00414 * @implemented 00415 */ 00416 VOID NTAPI 00417 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension, 00418 IN PVOID MappedAddress) 00419 { 00420 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00421 PMAPPED_ADDRESS NextMa, LastMa; 00422 00423 //DPRINT("ScsiPortFreeDeviceBase() called\n"); 00424 00425 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00426 SCSI_PORT_DEVICE_EXTENSION, 00427 MiniPortDeviceExtension); 00428 00429 /* Initialize our pointers */ 00430 NextMa = DeviceExtension->MappedAddressList; 00431 LastMa = NextMa; 00432 00433 while (NextMa) 00434 { 00435 if (NextMa->MappedAddress == MappedAddress) 00436 { 00437 /* Unmap it first */ 00438 MmUnmapIoSpace(MappedAddress, NextMa->NumberOfBytes); 00439 00440 /* Remove it from the list */ 00441 if (NextMa == DeviceExtension->MappedAddressList) 00442 { 00443 /* Remove the first entry */ 00444 DeviceExtension->MappedAddressList = NextMa->NextMappedAddress; 00445 } 00446 else 00447 { 00448 LastMa->NextMappedAddress = NextMa->NextMappedAddress; 00449 } 00450 00451 /* Free the resources and quit */ 00452 ExFreePool(NextMa); 00453 00454 return; 00455 } 00456 else 00457 { 00458 LastMa = NextMa; 00459 NextMa = NextMa->NextMappedAddress; 00460 } 00461 } 00462 } 00463 00464 00465 /* 00466 * @implemented 00467 */ 00468 ULONG NTAPI 00469 ScsiPortGetBusData(IN PVOID DeviceExtension, 00470 IN ULONG BusDataType, 00471 IN ULONG SystemIoBusNumber, 00472 IN ULONG SlotNumber, 00473 IN PVOID Buffer, 00474 IN ULONG Length) 00475 { 00476 DPRINT("ScsiPortGetBusData()\n"); 00477 00478 if (Length) 00479 { 00480 /* If Length is non-zero, just forward the call to 00481 HalGetBusData() function */ 00482 return HalGetBusData(BusDataType, 00483 SystemIoBusNumber, 00484 SlotNumber, 00485 Buffer, 00486 Length); 00487 } 00488 00489 /* We have a more complex case here */ 00490 UNIMPLEMENTED; 00491 return 0; 00492 } 00493 00494 /* 00495 * @implemented 00496 */ 00497 ULONG NTAPI 00498 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension, 00499 IN ULONG BusDataType, 00500 IN ULONG SystemIoBusNumber, 00501 IN ULONG SlotNumber, 00502 IN PVOID Buffer, 00503 IN ULONG Offset, 00504 IN ULONG Length) 00505 { 00506 DPRINT("ScsiPortSetBusDataByOffset()\n"); 00507 return HalSetBusDataByOffset(BusDataType, 00508 SystemIoBusNumber, 00509 SlotNumber, 00510 Buffer, 00511 Offset, 00512 Length); 00513 } 00514 00515 /* 00516 * @implemented 00517 */ 00518 PVOID NTAPI 00519 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension, 00520 IN INTERFACE_TYPE BusType, 00521 IN ULONG SystemIoBusNumber, 00522 IN SCSI_PHYSICAL_ADDRESS IoAddress, 00523 IN ULONG NumberOfBytes, 00524 IN BOOLEAN InIoSpace) 00525 { 00526 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00527 PHYSICAL_ADDRESS TranslatedAddress; 00528 PMAPPED_ADDRESS DeviceBase; 00529 ULONG AddressSpace; 00530 PVOID MappedAddress; 00531 00532 //DPRINT ("ScsiPortGetDeviceBase() called\n"); 00533 00534 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00535 SCSI_PORT_DEVICE_EXTENSION, 00536 MiniPortDeviceExtension); 00537 00538 AddressSpace = (ULONG)InIoSpace; 00539 if (HalTranslateBusAddress(BusType, 00540 SystemIoBusNumber, 00541 IoAddress, 00542 &AddressSpace, 00543 &TranslatedAddress) == FALSE) 00544 { 00545 return NULL; 00546 } 00547 00548 /* i/o space */ 00549 if (AddressSpace != 0) 00550 return((PVOID)(ULONG_PTR)TranslatedAddress.QuadPart); 00551 00552 MappedAddress = MmMapIoSpace(TranslatedAddress, 00553 NumberOfBytes, 00554 FALSE); 00555 00556 DeviceBase = ExAllocatePoolWithTag(NonPagedPool, 00557 sizeof(MAPPED_ADDRESS), TAG_SCSIPORT); 00558 00559 if (DeviceBase == NULL) 00560 return MappedAddress; 00561 00562 DeviceBase->MappedAddress = MappedAddress; 00563 DeviceBase->NumberOfBytes = NumberOfBytes; 00564 DeviceBase->IoAddress = IoAddress; 00565 DeviceBase->BusNumber = SystemIoBusNumber; 00566 00567 /* Link it to the Device Extension list */ 00568 DeviceBase->NextMappedAddress = DeviceExtension->MappedAddressList; 00569 DeviceExtension->MappedAddressList = DeviceBase; 00570 00571 return MappedAddress; 00572 } 00573 00574 /* 00575 * @unimplemented 00576 */ 00577 PVOID NTAPI 00578 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension, 00579 IN UCHAR PathId, 00580 IN UCHAR TargetId, 00581 IN UCHAR Lun) 00582 { 00583 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00584 PSCSI_PORT_LUN_EXTENSION LunExtension; 00585 00586 DPRINT("ScsiPortGetLogicalUnit() called\n"); 00587 00588 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00589 SCSI_PORT_DEVICE_EXTENSION, 00590 MiniPortDeviceExtension); 00591 00592 /* Check the extension size */ 00593 if (!DeviceExtension->LunExtensionSize) 00594 { 00595 /* They didn't want one */ 00596 return NULL; 00597 } 00598 00599 LunExtension = SpiGetLunExtension(DeviceExtension, 00600 PathId, 00601 TargetId, 00602 Lun); 00603 /* Check that the logical unit exists */ 00604 if (!LunExtension) 00605 { 00606 /* Nope, return NULL */ 00607 return NULL; 00608 } 00609 00610 /* Return the logical unit miniport extension */ 00611 return (LunExtension + 1); 00612 } 00613 00614 00615 /* 00616 * @implemented 00617 */ 00618 SCSI_PHYSICAL_ADDRESS NTAPI 00619 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension, 00620 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, 00621 IN PVOID VirtualAddress, 00622 OUT ULONG *Length) 00623 { 00624 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00625 SCSI_PHYSICAL_ADDRESS PhysicalAddress; 00626 ULONG BufferLength = 0; 00627 ULONG Offset; 00628 PSCSI_SG_ADDRESS SGList; 00629 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 00630 00631 DPRINT("ScsiPortGetPhysicalAddress(%p %p %p %p)\n", 00632 HwDeviceExtension, Srb, VirtualAddress, Length); 00633 00634 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00635 SCSI_PORT_DEVICE_EXTENSION, 00636 MiniPortDeviceExtension); 00637 00638 if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress) 00639 { 00640 /* Simply look it up in the allocated common buffer */ 00641 Offset = (PUCHAR)VirtualAddress - (PUCHAR)DeviceExtension->SrbExtensionBuffer; 00642 00643 BufferLength = DeviceExtension->CommonBufferLength - Offset; 00644 PhysicalAddress.QuadPart = DeviceExtension->PhysicalAddress.QuadPart + Offset; 00645 } 00646 else if (DeviceExtension->MapRegisters) 00647 { 00648 /* Scatter-gather list must be used */ 00649 SrbInfo = SpiGetSrbData(DeviceExtension, 00650 Srb->PathId, 00651 Srb->TargetId, 00652 Srb->Lun, 00653 Srb->QueueTag); 00654 00655 SGList = SrbInfo->ScatterGather; 00656 00657 /* Find needed item in the SG list */ 00658 Offset = (PCHAR)VirtualAddress - (PCHAR)Srb->DataBuffer; 00659 while (Offset >= SGList->Length) 00660 { 00661 Offset -= SGList->Length; 00662 SGList++; 00663 } 00664 00665 /* We're done, store length and physical address */ 00666 BufferLength = SGList->Length - Offset; 00667 PhysicalAddress.QuadPart = SGList->PhysicalAddress.QuadPart + Offset; 00668 } 00669 else 00670 { 00671 /* Nothing */ 00672 *Length = 0; 00673 PhysicalAddress.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE); 00674 } 00675 00676 *Length = BufferLength; 00677 return PhysicalAddress; 00678 } 00679 00680 00681 /* 00682 * @unimplemented 00683 */ 00684 PSCSI_REQUEST_BLOCK NTAPI 00685 ScsiPortGetSrb(IN PVOID DeviceExtension, 00686 IN UCHAR PathId, 00687 IN UCHAR TargetId, 00688 IN UCHAR Lun, 00689 IN LONG QueueTag) 00690 { 00691 DPRINT1("ScsiPortGetSrb() unimplemented\n"); 00692 UNIMPLEMENTED; 00693 return NULL; 00694 } 00695 00696 00697 /* 00698 * @implemented 00699 */ 00700 PVOID NTAPI 00701 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension, 00702 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, 00703 IN ULONG NumberOfBytes) 00704 { 00705 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00706 DEVICE_DESCRIPTION DeviceDescription; 00707 ULONG MapRegistersCount; 00708 NTSTATUS Status; 00709 00710 DPRINT("ScsiPortGetUncachedExtension(%p %p %lu)\n", 00711 HwDeviceExtension, ConfigInfo, NumberOfBytes); 00712 00713 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00714 SCSI_PORT_DEVICE_EXTENSION, 00715 MiniPortDeviceExtension); 00716 00717 /* Check for allocated common DMA buffer */ 00718 if (DeviceExtension->SrbExtensionBuffer != NULL) 00719 { 00720 DPRINT1("The HBA has already got a common DMA buffer!\n"); 00721 return NULL; 00722 } 00723 00724 /* Check for DMA adapter object */ 00725 if (DeviceExtension->AdapterObject == NULL) 00726 { 00727 /* Initialize DMA adapter description */ 00728 RtlZeroMemory(&DeviceDescription, sizeof(DEVICE_DESCRIPTION)); 00729 00730 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; 00731 DeviceDescription.Master = ConfigInfo->Master; 00732 DeviceDescription.ScatterGather = ConfigInfo->ScatterGather; 00733 DeviceDescription.DemandMode = ConfigInfo->DemandMode; 00734 DeviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses; 00735 DeviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber; 00736 DeviceDescription.DmaChannel = ConfigInfo->DmaChannel; 00737 DeviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType; 00738 DeviceDescription.DmaWidth = ConfigInfo->DmaWidth; 00739 DeviceDescription.DmaSpeed = ConfigInfo->DmaSpeed; 00740 DeviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength; 00741 DeviceDescription.DmaPort = ConfigInfo->DmaPort; 00742 00743 /* Get a DMA adapter object */ 00744 DeviceExtension->AdapterObject = 00745 HalGetAdapter(&DeviceDescription, &MapRegistersCount); 00746 00747 /* Fail in case of error */ 00748 if (DeviceExtension->AdapterObject == NULL) 00749 { 00750 DPRINT1("HalGetAdapter() failed\n"); 00751 return NULL; 00752 } 00753 00754 /* Set number of physical breaks */ 00755 if (ConfigInfo->NumberOfPhysicalBreaks != 0 && 00756 MapRegistersCount > ConfigInfo->NumberOfPhysicalBreaks) 00757 { 00758 DeviceExtension->PortCapabilities.MaximumPhysicalPages = 00759 ConfigInfo->NumberOfPhysicalBreaks; 00760 } 00761 else 00762 { 00763 DeviceExtension->PortCapabilities.MaximumPhysicalPages = MapRegistersCount; 00764 } 00765 } 00766 00767 /* Update auto request sense feature */ 00768 DeviceExtension->SupportsAutoSense = ConfigInfo->AutoRequestSense; 00769 00770 /* Update Srb extension size */ 00771 if (DeviceExtension->SrbExtensionSize != ConfigInfo->SrbExtensionSize) 00772 DeviceExtension->SrbExtensionSize = ConfigInfo->SrbExtensionSize; 00773 00774 /* Update Srb extension alloc flag */ 00775 if (ConfigInfo->AutoRequestSense || DeviceExtension->SrbExtensionSize) 00776 DeviceExtension->NeedSrbExtensionAlloc = TRUE; 00777 00778 /* Allocate a common DMA buffer */ 00779 Status = SpiAllocateCommonBuffer(DeviceExtension, NumberOfBytes); 00780 00781 if (!NT_SUCCESS(Status)) 00782 { 00783 DPRINT1("SpiAllocateCommonBuffer() failed with Status = 0x%08X!\n", Status); 00784 return NULL; 00785 } 00786 00787 return DeviceExtension->NonCachedExtension; 00788 } 00789 00790 static NTSTATUS 00791 SpiAllocateCommonBuffer(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, ULONG NonCachedSize) 00792 { 00793 PVOID *SrbExtension, CommonBuffer; 00794 ULONG CommonBufferLength, BufSize; 00795 00796 /* If size is 0, set it to 16 */ 00797 if (!DeviceExtension->SrbExtensionSize) 00798 DeviceExtension->SrbExtensionSize = 16; 00799 00800 /* Calculate size */ 00801 BufSize = DeviceExtension->SrbExtensionSize; 00802 00803 /* Add autosense data size if needed */ 00804 if (DeviceExtension->SupportsAutoSense) 00805 BufSize += sizeof(SENSE_DATA); 00806 00807 00808 /* Round it */ 00809 BufSize = (BufSize + sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1); 00810 00811 /* Sum up into the total common buffer length, and round it to page size */ 00812 CommonBufferLength = 00813 ROUND_TO_PAGES(NonCachedSize + BufSize * DeviceExtension->RequestsNumber); 00814 00815 /* Allocate it */ 00816 if (!DeviceExtension->AdapterObject) 00817 { 00818 /* From nonpaged pool if there is no DMA */ 00819 CommonBuffer = ExAllocatePoolWithTag(NonPagedPool, CommonBufferLength, TAG_SCSIPORT); 00820 } 00821 else 00822 { 00823 /* Perform a full request since we have a DMA adapter*/ 00824 CommonBuffer = HalAllocateCommonBuffer(DeviceExtension->AdapterObject, 00825 CommonBufferLength, 00826 &DeviceExtension->PhysicalAddress, 00827 FALSE ); 00828 } 00829 00830 /* Fail in case of error */ 00831 if (!CommonBuffer) 00832 return STATUS_INSUFFICIENT_RESOURCES; 00833 00834 /* Zero it */ 00835 RtlZeroMemory(CommonBuffer, CommonBufferLength); 00836 00837 /* Store its size in Device Extension */ 00838 DeviceExtension->CommonBufferLength = CommonBufferLength; 00839 00840 /* SrbExtension buffer is located at the beginning of the buffer */ 00841 DeviceExtension->SrbExtensionBuffer = CommonBuffer; 00842 00843 /* Non-cached extension buffer is located at the end of 00844 the common buffer */ 00845 if (NonCachedSize) 00846 { 00847 CommonBufferLength -= NonCachedSize; 00848 DeviceExtension->NonCachedExtension = (PUCHAR)CommonBuffer + CommonBufferLength; 00849 } 00850 else 00851 { 00852 DeviceExtension->NonCachedExtension = NULL; 00853 } 00854 00855 if (DeviceExtension->NeedSrbExtensionAlloc) 00856 { 00857 /* Look up how many SRB data structures we need */ 00858 DeviceExtension->SrbDataCount = CommonBufferLength / BufSize; 00859 00860 /* Initialize the free SRB extensions list */ 00861 SrbExtension = (PVOID *)CommonBuffer; 00862 DeviceExtension->FreeSrbExtensions = SrbExtension; 00863 00864 /* Fill the remainding pointers (if we have more than 1 SRB) */ 00865 while (CommonBufferLength >= 2 * BufSize) 00866 { 00867 *SrbExtension = (PVOID*)((PCHAR)SrbExtension + BufSize); 00868 SrbExtension = *SrbExtension; 00869 00870 CommonBufferLength -= BufSize; 00871 } 00872 } 00873 00874 return STATUS_SUCCESS; 00875 } 00876 00877 00878 00879 /* 00880 * @implemented 00881 */ 00882 PVOID NTAPI 00883 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension, 00884 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress) 00885 { 00886 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 00887 ULONG Offset; 00888 00889 DPRINT("ScsiPortGetVirtualAddress(%p %I64x)\n", 00890 HwDeviceExtension, PhysicalAddress.QuadPart); 00891 00892 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 00893 SCSI_PORT_DEVICE_EXTENSION, 00894 MiniPortDeviceExtension); 00895 00896 if (DeviceExtension->PhysicalAddress.QuadPart > PhysicalAddress.QuadPart) 00897 return NULL; 00898 00899 Offset = (ULONG)(PhysicalAddress.QuadPart - DeviceExtension->PhysicalAddress.QuadPart); 00900 00901 if (Offset >= DeviceExtension->CommonBufferLength) 00902 return NULL; 00903 00904 return (PVOID)((ULONG_PTR)DeviceExtension->SrbExtensionBuffer + Offset); 00905 } 00906 00907 static VOID 00908 SpiInitOpenKeys(PCONFIGURATION_INFO ConfigInfo, PUNICODE_STRING RegistryPath) 00909 { 00910 OBJECT_ATTRIBUTES ObjectAttributes; 00911 UNICODE_STRING KeyName; 00912 NTSTATUS Status; 00913 00914 /* Open the service key */ 00915 InitializeObjectAttributes(&ObjectAttributes, 00916 RegistryPath, 00917 OBJ_CASE_INSENSITIVE, 00918 NULL, 00919 NULL); 00920 00921 Status = ZwOpenKey(&ConfigInfo->ServiceKey, 00922 KEY_READ, 00923 &ObjectAttributes); 00924 00925 if (!NT_SUCCESS(Status)) 00926 { 00927 DPRINT("Unable to open driver's registry key %wZ, status 0x%08x\n", RegistryPath, Status); 00928 ConfigInfo->ServiceKey = NULL; 00929 } 00930 00931 /* If we could open driver's service key, then proceed to the Parameters key */ 00932 if (ConfigInfo->ServiceKey != NULL) 00933 { 00934 RtlInitUnicodeString(&KeyName, L"Parameters"); 00935 InitializeObjectAttributes(&ObjectAttributes, 00936 &KeyName, 00937 OBJ_CASE_INSENSITIVE, 00938 ConfigInfo->ServiceKey, 00939 (PSECURITY_DESCRIPTOR) NULL); 00940 00941 /* Try to open it */ 00942 Status = ZwOpenKey(&ConfigInfo->DeviceKey, 00943 KEY_READ, 00944 &ObjectAttributes); 00945 00946 if (NT_SUCCESS(Status)) 00947 { 00948 /* Yes, Parameters key exist, and it must be used instead of 00949 the Service key */ 00950 ZwClose(ConfigInfo->ServiceKey); 00951 ConfigInfo->ServiceKey = ConfigInfo->DeviceKey; 00952 ConfigInfo->DeviceKey = NULL; 00953 } 00954 } 00955 00956 if (ConfigInfo->ServiceKey != NULL) 00957 { 00958 /* Open the Device key */ 00959 RtlInitUnicodeString(&KeyName, L"Device"); 00960 InitializeObjectAttributes(&ObjectAttributes, 00961 &KeyName, 00962 OBJ_CASE_INSENSITIVE, 00963 ConfigInfo->ServiceKey, 00964 NULL); 00965 00966 /* We don't check for failure here - not needed */ 00967 ZwOpenKey(&ConfigInfo->DeviceKey, 00968 KEY_READ, 00969 &ObjectAttributes); 00970 } 00971 } 00972 00973 00974 /********************************************************************** 00975 * NAME EXPORTED 00976 * ScsiPortInitialize 00977 * 00978 * DESCRIPTION 00979 * Initializes SCSI port driver specific data. 00980 * 00981 * RUN LEVEL 00982 * PASSIVE_LEVEL 00983 * 00984 * ARGUMENTS 00985 * Argument1 00986 * Pointer to the miniport driver's driver object. 00987 * 00988 * Argument2 00989 * Pointer to the miniport driver's registry path. 00990 * 00991 * HwInitializationData 00992 * Pointer to port driver specific configuration data. 00993 * 00994 * HwContext 00995 Miniport driver specific context. 00996 * 00997 * RETURN VALUE 00998 * Status. 00999 * 01000 * @implemented 01001 */ 01002 01003 ULONG NTAPI 01004 ScsiPortInitialize(IN PVOID Argument1, 01005 IN PVOID Argument2, 01006 IN struct _HW_INITIALIZATION_DATA *HwInitializationData, 01007 IN PVOID HwContext) 01008 { 01009 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1; 01010 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2; 01011 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = NULL; 01012 PCONFIGURATION_INFORMATION SystemConfig; 01013 PPORT_CONFIGURATION_INFORMATION PortConfig; 01014 PORT_CONFIGURATION_INFORMATION InitialPortConfig; 01015 CONFIGURATION_INFO ConfigInfo; 01016 ULONG DeviceExtensionSize; 01017 ULONG PortConfigSize; 01018 BOOLEAN Again; 01019 BOOLEAN DeviceFound = FALSE; 01020 BOOLEAN FirstConfigCall = TRUE; 01021 ULONG Result; 01022 NTSTATUS Status; 01023 ULONG MaxBus; 01024 ULONG BusNumber = 0; 01025 PCI_SLOT_NUMBER SlotNumber; 01026 01027 PDEVICE_OBJECT PortDeviceObject; 01028 WCHAR NameBuffer[80]; 01029 UNICODE_STRING DeviceName; 01030 WCHAR DosNameBuffer[80]; 01031 UNICODE_STRING DosDeviceName; 01032 PIO_SCSI_CAPABILITIES PortCapabilities; 01033 01034 KIRQL OldIrql; 01035 PCM_RESOURCE_LIST ResourceList; 01036 BOOLEAN Conflict; 01037 01038 01039 DPRINT ("ScsiPortInitialize() called!\n"); 01040 01041 /* Check params for validity */ 01042 if ((HwInitializationData->HwInitialize == NULL) || 01043 (HwInitializationData->HwStartIo == NULL) || 01044 (HwInitializationData->HwInterrupt == NULL) || 01045 (HwInitializationData->HwFindAdapter == NULL) || 01046 (HwInitializationData->HwResetBus == NULL)) 01047 { 01048 return STATUS_INVALID_PARAMETER; 01049 } 01050 01051 /* Set handlers */ 01052 DriverObject->DriverStartIo = ScsiPortStartIo; 01053 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose; 01054 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose; 01055 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl; 01056 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi; 01057 01058 /* Obtain configuration information */ 01059 SystemConfig = IoGetConfigurationInformation(); 01060 01061 /* Zero the internal configuration info structure */ 01062 RtlZeroMemory(&ConfigInfo, sizeof(CONFIGURATION_INFO)); 01063 01064 /* Zero starting slot number */ 01065 SlotNumber.u.AsULONG = 0; 01066 01067 /* Allocate space for access ranges */ 01068 if (HwInitializationData->NumberOfAccessRanges) 01069 { 01070 ConfigInfo.AccessRanges = 01071 ExAllocatePoolWithTag(PagedPool, 01072 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE), TAG_SCSIPORT); 01073 01074 /* Fail if failed */ 01075 if (ConfigInfo.AccessRanges == NULL) 01076 return STATUS_INSUFFICIENT_RESOURCES; 01077 } 01078 01079 /* Open registry keys */ 01080 SpiInitOpenKeys(&ConfigInfo, (PUNICODE_STRING)Argument2); 01081 01082 /* Last adapter number = not known */ 01083 ConfigInfo.LastAdapterNumber = SP_UNINITIALIZED_VALUE; 01084 01085 /* Calculate sizes of DeviceExtension and PortConfig */ 01086 DeviceExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) + 01087 HwInitializationData->DeviceExtensionSize; 01088 01089 MaxBus = (HwInitializationData->AdapterInterfaceType == PCIBus) ? 8 : 1; 01090 DPRINT("MaxBus: %lu\n", MaxBus); 01091 01092 while (TRUE) 01093 { 01094 /* Create a unicode device name */ 01095 swprintf(NameBuffer, 01096 L"\\Device\\ScsiPort%lu", 01097 SystemConfig->ScsiPortCount); 01098 RtlInitUnicodeString(&DeviceName, NameBuffer); 01099 01100 DPRINT("Creating device: %wZ\n", &DeviceName); 01101 01102 /* Create the port device */ 01103 Status = IoCreateDevice(DriverObject, 01104 DeviceExtensionSize, 01105 &DeviceName, 01106 FILE_DEVICE_CONTROLLER, 01107 0, 01108 FALSE, 01109 &PortDeviceObject); 01110 01111 if (!NT_SUCCESS(Status)) 01112 { 01113 DPRINT1("IoCreateDevice call failed! (Status 0x%lX)\n", Status); 01114 PortDeviceObject = NULL; 01115 break; 01116 } 01117 01118 DPRINT ("Created device: %wZ (%p)\n", &DeviceName, PortDeviceObject); 01119 01120 /* Set the buffering strategy here... */ 01121 PortDeviceObject->Flags |= DO_DIRECT_IO; 01122 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; /* FIXME: Is this really needed? */ 01123 01124 /* Fill Device Extension */ 01125 DeviceExtension = PortDeviceObject->DeviceExtension; 01126 RtlZeroMemory(DeviceExtension, DeviceExtensionSize); 01127 DeviceExtension->Length = DeviceExtensionSize; 01128 DeviceExtension->DeviceObject = PortDeviceObject; 01129 DeviceExtension->PortNumber = SystemConfig->ScsiPortCount; 01130 01131 /* Driver's routines... */ 01132 DeviceExtension->HwInitialize = HwInitializationData->HwInitialize; 01133 DeviceExtension->HwStartIo = HwInitializationData->HwStartIo; 01134 DeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt; 01135 DeviceExtension->HwResetBus = HwInitializationData->HwResetBus; 01136 DeviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted; 01137 01138 /* Extensions sizes */ 01139 DeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize; 01140 DeviceExtension->LunExtensionSize = HwInitializationData->SpecificLuExtensionSize; 01141 DeviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize; 01142 01143 /* Round Srb extension size to the quadword */ 01144 DeviceExtension->SrbExtensionSize = 01145 ~(sizeof(LONGLONG) - 1) & (DeviceExtension->SrbExtensionSize + 01146 sizeof(LONGLONG) - 1); 01147 01148 /* Fill some numbers (bus count, lun count, etc) */ 01149 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; 01150 DeviceExtension->RequestsNumber = 16; 01151 01152 /* Initialize the spin lock in the controller extension */ 01153 KeInitializeSpinLock(&DeviceExtension->IrqLock); 01154 KeInitializeSpinLock(&DeviceExtension->SpinLock); 01155 01156 /* Initialize the DPC object */ 01157 IoInitializeDpcRequest(PortDeviceObject, 01158 ScsiPortDpcForIsr); 01159 01160 /* Initialize the device timer */ 01161 DeviceExtension->TimerCount = -1; 01162 IoInitializeTimer(PortDeviceObject, 01163 ScsiPortIoTimer, 01164 DeviceExtension); 01165 01166 /* Initialize miniport timer */ 01167 KeInitializeTimer(&DeviceExtension->MiniportTimer); 01168 KeInitializeDpc(&DeviceExtension->MiniportTimerDpc, 01169 SpiMiniportTimerDpc, 01170 PortDeviceObject); 01171 01172 CreatePortConfig: 01173 01174 Status = SpiCreatePortConfig(DeviceExtension, 01175 HwInitializationData, 01176 &ConfigInfo, 01177 &InitialPortConfig, 01178 FirstConfigCall); 01179 01180 if (!NT_SUCCESS(Status)) 01181 { 01182 DPRINT("SpiCreatePortConfig() failed with Status 0x%08X\n", Status); 01183 break; 01184 } 01185 01186 /* Allocate and initialize port configuration info */ 01187 PortConfigSize = (sizeof(PORT_CONFIGURATION_INFORMATION) + 01188 HwInitializationData->NumberOfAccessRanges * 01189 sizeof(ACCESS_RANGE) + 7) & ~7; 01190 DeviceExtension->PortConfig = ExAllocatePoolWithTag(NonPagedPool, PortConfigSize, TAG_SCSIPORT); 01191 01192 /* Fail if failed */ 01193 if (DeviceExtension->PortConfig == NULL) 01194 { 01195 Status = STATUS_INSUFFICIENT_RESOURCES; 01196 break; 01197 } 01198 01199 PortConfig = DeviceExtension->PortConfig; 01200 01201 /* Copy information here */ 01202 RtlCopyMemory(PortConfig, 01203 &InitialPortConfig, 01204 sizeof(PORT_CONFIGURATION_INFORMATION)); 01205 01206 01207 /* Copy extension sizes into the PortConfig */ 01208 PortConfig->SpecificLuExtensionSize = DeviceExtension->LunExtensionSize; 01209 PortConfig->SrbExtensionSize = DeviceExtension->SrbExtensionSize; 01210 01211 /* Initialize Access ranges */ 01212 if (HwInitializationData->NumberOfAccessRanges != 0) 01213 { 01214 PortConfig->AccessRanges = (PVOID)(PortConfig+1); 01215 01216 /* Align to LONGLONG */ 01217 PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) + 7); 01218 PortConfig->AccessRanges = (PVOID)((ULONG_PTR)(PortConfig->AccessRanges) & ~7); 01219 01220 /* Copy the data */ 01221 RtlCopyMemory(PortConfig->AccessRanges, 01222 ConfigInfo.AccessRanges, 01223 HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)); 01224 } 01225 01226 /* Search for matching PCI device */ 01227 if ((HwInitializationData->AdapterInterfaceType == PCIBus) && 01228 (HwInitializationData->VendorIdLength > 0) && 01229 (HwInitializationData->VendorId != NULL) && 01230 (HwInitializationData->DeviceIdLength > 0) && 01231 (HwInitializationData->DeviceId != NULL)) 01232 { 01233 PortConfig->BusInterruptLevel = 0; 01234 01235 /* Get PCI device data */ 01236 DPRINT("VendorId '%.*s' DeviceId '%.*s'\n", 01237 HwInitializationData->VendorIdLength, 01238 HwInitializationData->VendorId, 01239 HwInitializationData->DeviceIdLength, 01240 HwInitializationData->DeviceId); 01241 01242 if (!SpiGetPciConfigData(DriverObject, 01243 PortDeviceObject, 01244 HwInitializationData, 01245 PortConfig, 01246 RegistryPath, 01247 ConfigInfo.BusNumber, 01248 &SlotNumber)) 01249 { 01250 /* Continue to the next bus, nothing here */ 01251 ConfigInfo.BusNumber++; 01252 DeviceExtension->PortConfig = NULL; 01253 ExFreePool(PortConfig); 01254 Again = FALSE; 01255 goto CreatePortConfig; 01256 } 01257 01258 if (!PortConfig->BusInterruptLevel) 01259 { 01260 /* Bypass this slot, because no interrupt was assigned */ 01261 DeviceExtension->PortConfig = NULL; 01262 ExFreePool(PortConfig); 01263 goto CreatePortConfig; 01264 } 01265 } 01266 else 01267 { 01268 DPRINT("Non-pci bus\n"); 01269 } 01270 01271 /* Note: HwFindAdapter is called once for each bus */ 01272 Again = FALSE; 01273 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber); 01274 Result = (HwInitializationData->HwFindAdapter)(&DeviceExtension->MiniPortDeviceExtension, 01275 HwContext, 01276 0, /* BusInformation */ 01277 ConfigInfo.Parameter, /* ArgumentString */ 01278 PortConfig, 01279 &Again); 01280 01281 DPRINT("HwFindAdapter() Result: %lu Again: %s\n", 01282 Result, (Again) ? "True" : "False"); 01283 01284 /* Free MapRegisterBase, it's not needed anymore */ 01285 if (DeviceExtension->MapRegisterBase != NULL) 01286 { 01287 ExFreePool(DeviceExtension->MapRegisterBase); 01288 DeviceExtension->MapRegisterBase = NULL; 01289 } 01290 01291 /* If result is nothing good... */ 01292 if (Result != SP_RETURN_FOUND) 01293 { 01294 DPRINT("HwFindAdapter() Result: %lu\n", Result); 01295 01296 if (Result == SP_RETURN_NOT_FOUND) 01297 { 01298 /* We can continue on the next bus */ 01299 ConfigInfo.BusNumber++; 01300 Again = FALSE; 01301 01302 DeviceExtension->PortConfig = NULL; 01303 ExFreePool(PortConfig); 01304 goto CreatePortConfig; 01305 } 01306 01307 /* Otherwise, break */ 01308 Status = STATUS_INTERNAL_ERROR; 01309 break; 01310 } 01311 01312 DPRINT("ScsiPortInitialize(): Found HBA! (%x), adapter Id %d\n", 01313 PortConfig->BusInterruptVector, PortConfig->InitiatorBusId[0]); 01314 01315 /* If the SRB extension size was updated */ 01316 if (!DeviceExtension->NonCachedExtension && 01317 (PortConfig->SrbExtensionSize != DeviceExtension->SrbExtensionSize)) 01318 { 01319 /* Set it (rounding to LONGLONG again) */ 01320 DeviceExtension->SrbExtensionSize = 01321 (PortConfig->SrbExtensionSize + 01322 sizeof(LONGLONG)) & ~(sizeof(LONGLONG) - 1); 01323 } 01324 01325 /* The same with LUN extension size */ 01326 if (PortConfig->SpecificLuExtensionSize != DeviceExtension->LunExtensionSize) 01327 DeviceExtension->LunExtensionSize = PortConfig->SpecificLuExtensionSize; 01328 01329 01330 if (!((HwInitializationData->AdapterInterfaceType == PCIBus) && 01331 (HwInitializationData->VendorIdLength > 0) && 01332 (HwInitializationData->VendorId != NULL) && 01333 (HwInitializationData->DeviceIdLength > 0) && 01334 (HwInitializationData->DeviceId != NULL))) 01335 { 01336 /* Construct a resource list */ 01337 ResourceList = SpiConfigToResource(DeviceExtension, 01338 PortConfig); 01339 01340 if (ResourceList) 01341 { 01342 UNICODE_STRING UnicodeString; 01343 RtlInitUnicodeString(&UnicodeString, L"ScsiAdapter"); 01344 DPRINT("Reporting resources\n"); 01345 Status = IoReportResourceUsage(&UnicodeString, 01346 DriverObject, 01347 NULL, 01348 0, 01349 PortDeviceObject, 01350 ResourceList, 01351 FIELD_OFFSET(CM_RESOURCE_LIST, 01352 List[0].PartialResourceList.PartialDescriptors) + 01353 ResourceList->List[0].PartialResourceList.Count 01354 * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), 01355 FALSE, 01356 &Conflict); 01357 ExFreePool(ResourceList); 01358 01359 /* In case of a failure or a conflict, break */ 01360 if (Conflict || (!NT_SUCCESS(Status))) 01361 { 01362 if (Conflict) 01363 Status = STATUS_CONFLICTING_ADDRESSES; 01364 break; 01365 } 01366 } 01367 } 01368 01369 /* Reset the Conflict var */ 01370 Conflict = FALSE; 01371 01372 /* Copy all stuff which we ever need from PortConfig to the DeviceExtension */ 01373 if (PortConfig->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) 01374 DeviceExtension->MaxTargedIds = SCSI_MAXIMUM_TARGETS_PER_BUS; 01375 else 01376 DeviceExtension->MaxTargedIds = PortConfig->MaximumNumberOfTargets; 01377 01378 DeviceExtension->BusNum = PortConfig->NumberOfBuses; 01379 DeviceExtension->CachesData = PortConfig->CachesData; 01380 DeviceExtension->ReceiveEvent = PortConfig->ReceiveEvent; 01381 DeviceExtension->SupportsTaggedQueuing = PortConfig->TaggedQueuing; 01382 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu; 01383 01384 /* If something was disabled via registry - apply it */ 01385 if (ConfigInfo.DisableMultipleLun) 01386 DeviceExtension->MultipleReqsPerLun = PortConfig->MultipleRequestPerLu = FALSE; 01387 01388 if (ConfigInfo.DisableTaggedQueueing) 01389 DeviceExtension->SupportsTaggedQueuing = PortConfig->MultipleRequestPerLu = FALSE; 01390 01391 /* Check if we need to alloc SRB data */ 01392 if (DeviceExtension->SupportsTaggedQueuing || 01393 DeviceExtension->MultipleReqsPerLun) 01394 { 01395 DeviceExtension->NeedSrbDataAlloc = TRUE; 01396 } 01397 else 01398 { 01399 DeviceExtension->NeedSrbDataAlloc = FALSE; 01400 } 01401 01402 /* Get a pointer to the port capabilities */ 01403 PortCapabilities = &DeviceExtension->PortCapabilities; 01404 01405 /* Copy one field there */ 01406 DeviceExtension->MapBuffers = PortConfig->MapBuffers; 01407 PortCapabilities->AdapterUsesPio = PortConfig->MapBuffers; 01408 01409 if (DeviceExtension->AdapterObject == NULL && 01410 (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || PortConfig->Master)) 01411 { 01412 DPRINT1("DMA is not supported yet\n"); 01413 ASSERT(FALSE); 01414 } 01415 01416 if (DeviceExtension->SrbExtensionBuffer == NULL && 01417 (DeviceExtension->SrbExtensionSize != 0 || 01418 PortConfig->AutoRequestSense)) 01419 { 01420 DeviceExtension->SupportsAutoSense = PortConfig->AutoRequestSense; 01421 DeviceExtension->NeedSrbExtensionAlloc = TRUE; 01422 01423 /* Allocate common buffer */ 01424 Status = SpiAllocateCommonBuffer(DeviceExtension, 0); 01425 01426 /* Check for failure */ 01427 if (!NT_SUCCESS(Status)) 01428 break; 01429 } 01430 01431 /* Allocate SrbData, if needed */ 01432 if (DeviceExtension->NeedSrbDataAlloc) 01433 { 01434 ULONG Count; 01435 PSCSI_REQUEST_BLOCK_INFO SrbData; 01436 01437 if (DeviceExtension->SrbDataCount != 0) 01438 Count = DeviceExtension->SrbDataCount; 01439 else 01440 Count = DeviceExtension->RequestsNumber * 2; 01441 01442 /* Allocate the data */ 01443 SrbData = ExAllocatePoolWithTag(NonPagedPool, Count * sizeof(SCSI_REQUEST_BLOCK_INFO), TAG_SCSIPORT); 01444 if (SrbData == NULL) 01445 return STATUS_INSUFFICIENT_RESOURCES; 01446 01447 RtlZeroMemory(SrbData, Count * sizeof(SCSI_REQUEST_BLOCK_INFO)); 01448 01449 DeviceExtension->SrbInfo = SrbData; 01450 DeviceExtension->FreeSrbInfo = SrbData; 01451 DeviceExtension->SrbDataCount = Count; 01452 01453 /* Link it to the list */ 01454 while (Count > 0) 01455 { 01456 SrbData->Requests.Flink = (PLIST_ENTRY)(SrbData + 1); 01457 SrbData++; 01458 Count--; 01459 } 01460 01461 /* Mark the last entry of the list */ 01462 SrbData--; 01463 SrbData->Requests.Flink = NULL; 01464 } 01465 01466 /* Initialize port capabilities */ 01467 PortCapabilities = &DeviceExtension->PortCapabilities; 01468 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES); 01469 PortCapabilities->MaximumTransferLength = PortConfig->MaximumTransferLength; 01470 01471 if (PortConfig->ReceiveEvent) 01472 PortCapabilities->SupportedAsynchronousEvents |= SRBEV_SCSI_ASYNC_NOTIFICATION; 01473 01474 PortCapabilities->TaggedQueuing = DeviceExtension->SupportsTaggedQueuing; 01475 PortCapabilities->AdapterScansDown = PortConfig->AdapterScansDown; 01476 01477 if (PortConfig->AlignmentMask > PortDeviceObject->AlignmentRequirement) 01478 PortDeviceObject->AlignmentRequirement = PortConfig->AlignmentMask; 01479 01480 PortCapabilities->AlignmentMask = PortDeviceObject->AlignmentRequirement; 01481 01482 if (PortCapabilities->MaximumPhysicalPages == 0) 01483 { 01484 PortCapabilities->MaximumPhysicalPages = 01485 BYTES_TO_PAGES(PortCapabilities->MaximumTransferLength); 01486 01487 /* Apply miniport's limits */ 01488 if (PortConfig->NumberOfPhysicalBreaks < PortCapabilities->MaximumPhysicalPages) 01489 { 01490 PortCapabilities->MaximumPhysicalPages = PortConfig->NumberOfPhysicalBreaks; 01491 } 01492 } 01493 01494 /* Deal with interrupts */ 01495 if (DeviceExtension->HwInterrupt == NULL || 01496 (PortConfig->BusInterruptLevel == 0 && PortConfig->BusInterruptVector == 0)) 01497 { 01498 /* No interrupts */ 01499 DeviceExtension->InterruptCount = 0; 01500 01501 DPRINT1("Interrupt Count: 0\n"); 01502 01503 UNIMPLEMENTED; 01504 01505 /* This code path will ALWAYS crash so stop it now */ 01506 while(TRUE); 01507 } 01508 else 01509 { 01510 BOOLEAN InterruptShareable; 01511 KINTERRUPT_MODE InterruptMode[2]; 01512 ULONG InterruptVector[2], i, MappedIrq[2]; 01513 KIRQL Dirql[2], MaxDirql; 01514 KAFFINITY Affinity[2]; 01515 01516 DeviceExtension->InterruptLevel[0] = PortConfig->BusInterruptLevel; 01517 DeviceExtension->InterruptLevel[1] = PortConfig->BusInterruptLevel2; 01518 01519 InterruptVector[0] = PortConfig->BusInterruptVector; 01520 InterruptVector[1] = PortConfig->BusInterruptVector2; 01521 01522 InterruptMode[0] = PortConfig->InterruptMode; 01523 InterruptMode[1] = PortConfig->InterruptMode2; 01524 01525 DeviceExtension->InterruptCount = (PortConfig->BusInterruptLevel2 != 0 || PortConfig->BusInterruptVector2 != 0) ? 2 : 1; 01526 01527 for (i = 0; i < DeviceExtension->InterruptCount; i++) 01528 { 01529 /* Register an interrupt handler for this device */ 01530 MappedIrq[i] = HalGetInterruptVector(PortConfig->AdapterInterfaceType, 01531 PortConfig->SystemIoBusNumber, 01532 DeviceExtension->InterruptLevel[i], 01533 InterruptVector[i], 01534 &Dirql[i], 01535 &Affinity[i]); 01536 } 01537 01538 if (DeviceExtension->InterruptCount == 1 || Dirql[0] > Dirql[1]) 01539 MaxDirql = Dirql[0]; 01540 else 01541 MaxDirql = Dirql[1]; 01542 01543 for (i = 0; i < DeviceExtension->InterruptCount; i++) 01544 { 01545 /* Determing IRQ sharability as usual */ 01546 if (PortConfig->AdapterInterfaceType == MicroChannel || 01547 InterruptMode[i] == LevelSensitive) 01548 { 01549 InterruptShareable = TRUE; 01550 } 01551 else 01552 { 01553 InterruptShareable = FALSE; 01554 } 01555 01556 Status = IoConnectInterrupt(&DeviceExtension->Interrupt[i], 01557 (PKSERVICE_ROUTINE)ScsiPortIsr, 01558 DeviceExtension, 01559 &DeviceExtension->IrqLock, 01560 MappedIrq[i], 01561 Dirql[i], 01562 MaxDirql, 01563 InterruptMode[i], 01564 InterruptShareable, 01565 Affinity[i], 01566 FALSE); 01567 01568 if (!(NT_SUCCESS(Status))) 01569 { 01570 DPRINT1("Could not connect interrupt %d\n", 01571 InterruptVector[i]); 01572 DeviceExtension->Interrupt[i] = NULL; 01573 break; 01574 } 01575 } 01576 01577 if (!NT_SUCCESS(Status)) 01578 break; 01579 } 01580 01581 /* Save IoAddress (from access ranges) */ 01582 if (HwInitializationData->NumberOfAccessRanges != 0) 01583 { 01584 DeviceExtension->IoAddress = 01585 ((*(PortConfig->AccessRanges))[0]).RangeStart.LowPart; 01586 01587 DPRINT("Io Address %x\n", DeviceExtension->IoAddress); 01588 } 01589 01590 /* Set flag that it's allowed to disconnect during this command */ 01591 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED; 01592 01593 /* Initialize counter of active requests (-1 means there are none) */ 01594 DeviceExtension->ActiveRequestCounter = -1; 01595 01596 /* Analyze what we have about DMA */ 01597 if (DeviceExtension->AdapterObject != NULL && 01598 PortConfig->Master && 01599 PortConfig->NeedPhysicalAddresses) 01600 { 01601 DeviceExtension->MapRegisters = TRUE; 01602 } 01603 else 01604 { 01605 DeviceExtension->MapRegisters = FALSE; 01606 } 01607 01608 /* Call HwInitialize at DISPATCH_LEVEL */ 01609 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 01610 01611 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 01612 DeviceExtension->HwInitialize, 01613 DeviceExtension->MiniPortDeviceExtension)) 01614 { 01615 DPRINT1("HwInitialize() failed!\n"); 01616 KeLowerIrql(OldIrql); 01617 Status = STATUS_ADAPTER_HARDWARE_ERROR; 01618 break; 01619 } 01620 01621 /* Check if a notification is needed */ 01622 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 01623 { 01624 /* Call DPC right away, because we're already at DISPATCH_LEVEL */ 01625 ScsiPortDpcForIsr(NULL, 01626 DeviceExtension->DeviceObject, 01627 NULL, 01628 NULL); 01629 } 01630 01631 /* Lower irql back to what it was */ 01632 KeLowerIrql(OldIrql); 01633 01634 /* Start our timer */ 01635 IoStartTimer(PortDeviceObject); 01636 01637 /* Initialize bus scanning information */ 01638 DeviceExtension->BusesConfig = ExAllocatePoolWithTag(PagedPool, 01639 sizeof(PVOID) * DeviceExtension->PortConfig->NumberOfBuses 01640 + sizeof(ULONG), TAG_SCSIPORT); 01641 01642 if (!DeviceExtension->BusesConfig) 01643 { 01644 DPRINT1("Out of resources!\n"); 01645 Status = STATUS_INSUFFICIENT_RESOURCES; 01646 break; 01647 } 01648 01649 /* Zero it */ 01650 RtlZeroMemory(DeviceExtension->BusesConfig, 01651 sizeof(PVOID) * DeviceExtension->PortConfig->NumberOfBuses 01652 + sizeof(ULONG)); 01653 01654 /* Store number of buses there */ 01655 DeviceExtension->BusesConfig->NumberOfBuses = (UCHAR)DeviceExtension->BusNum; 01656 01657 /* Scan the adapter for devices */ 01658 SpiScanAdapter(DeviceExtension); 01659 01660 /* Build the registry device map */ 01661 SpiBuildDeviceMap(DeviceExtension, 01662 (PUNICODE_STRING)Argument2); 01663 01664 /* Create the dos device link */ 01665 swprintf(DosNameBuffer, 01666 L"\\??\\Scsi%lu:", 01667 SystemConfig->ScsiPortCount); 01668 RtlInitUnicodeString(&DosDeviceName, DosNameBuffer); 01669 IoCreateSymbolicLink(&DosDeviceName, &DeviceName); 01670 01671 /* Increase the port count */ 01672 SystemConfig->ScsiPortCount++; 01673 FirstConfigCall = FALSE; 01674 01675 /* Increase adapter number and bus number respectively */ 01676 ConfigInfo.AdapterNumber++; 01677 01678 if (!Again) 01679 ConfigInfo.BusNumber++; 01680 01681 DPRINT("Bus: %lu MaxBus: %lu\n", BusNumber, MaxBus); 01682 01683 DeviceFound = TRUE; 01684 } 01685 01686 /* Clean up the mess */ 01687 SpiCleanupAfterInit(DeviceExtension); 01688 01689 /* Close registry keys */ 01690 if (ConfigInfo.ServiceKey != NULL) 01691 ZwClose(ConfigInfo.ServiceKey); 01692 01693 if (ConfigInfo.DeviceKey != NULL) 01694 ZwClose(ConfigInfo.DeviceKey); 01695 01696 if (ConfigInfo.BusKey != NULL) 01697 ZwClose(ConfigInfo.BusKey); 01698 01699 if (ConfigInfo.AccessRanges != NULL) 01700 ExFreePool(ConfigInfo.AccessRanges); 01701 01702 if (ConfigInfo.Parameter != NULL) 01703 ExFreePool(ConfigInfo.Parameter); 01704 01705 DPRINT("ScsiPortInitialize() done, Status = 0x%08X, DeviceFound = %d!\n", 01706 Status, DeviceFound); 01707 01708 return (DeviceFound == FALSE) ? Status : STATUS_SUCCESS; 01709 } 01710 01711 static VOID 01712 SpiCleanupAfterInit(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) 01713 { 01714 PSCSI_LUN_INFO LunInfo; 01715 PVOID Ptr; 01716 ULONG Bus, Lun; 01717 01718 /* Check if we have something to clean up */ 01719 if (DeviceExtension == NULL) 01720 return; 01721 01722 /* Stop the timer */ 01723 IoStopTimer(DeviceExtension->DeviceObject); 01724 01725 /* Disconnect the interrupts */ 01726 while (DeviceExtension->InterruptCount) 01727 { 01728 if (DeviceExtension->Interrupt[--DeviceExtension->InterruptCount]) 01729 IoDisconnectInterrupt(DeviceExtension->Interrupt[DeviceExtension->InterruptCount]); 01730 } 01731 01732 /* Delete ConfigInfo */ 01733 if (DeviceExtension->BusesConfig) 01734 { 01735 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) 01736 { 01737 if (!DeviceExtension->BusesConfig->BusScanInfo[Bus]) 01738 continue; 01739 01740 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo; 01741 01742 while (LunInfo) 01743 { 01744 /* Free current, but save pointer to the next one */ 01745 Ptr = LunInfo->Next; 01746 ExFreePool(LunInfo); 01747 LunInfo = Ptr; 01748 } 01749 01750 ExFreePool(DeviceExtension->BusesConfig->BusScanInfo[Bus]); 01751 } 01752 01753 ExFreePool(DeviceExtension->BusesConfig); 01754 } 01755 01756 /* Free PortConfig */ 01757 if (DeviceExtension->PortConfig) 01758 ExFreePool(DeviceExtension->PortConfig); 01759 01760 /* Free LUNs*/ 01761 for(Lun = 0; Lun < LUS_NUMBER; Lun++) 01762 { 01763 while (DeviceExtension->LunExtensionList[Lun]) 01764 { 01765 Ptr = DeviceExtension->LunExtensionList[Lun]; 01766 DeviceExtension->LunExtensionList[Lun] = DeviceExtension->LunExtensionList[Lun]->Next; 01767 01768 ExFreePool(Ptr); 01769 } 01770 } 01771 01772 /* Free common buffer (if it exists) */ 01773 if (DeviceExtension->SrbExtensionBuffer != NULL && 01774 DeviceExtension->CommonBufferLength != 0) 01775 { 01776 if (!DeviceExtension->AdapterObject) 01777 { 01778 ExFreePool(DeviceExtension->SrbExtensionBuffer); 01779 } 01780 else 01781 { 01782 HalFreeCommonBuffer(DeviceExtension->AdapterObject, 01783 DeviceExtension->CommonBufferLength, 01784 DeviceExtension->PhysicalAddress, 01785 DeviceExtension->SrbExtensionBuffer, 01786 FALSE); 01787 } 01788 } 01789 01790 /* Free SRB info */ 01791 if (DeviceExtension->SrbInfo != NULL) 01792 ExFreePool(DeviceExtension->SrbInfo); 01793 01794 /* Unmap mapped addresses */ 01795 while (DeviceExtension->MappedAddressList != NULL) 01796 { 01797 MmUnmapIoSpace(DeviceExtension->MappedAddressList->MappedAddress, 01798 DeviceExtension->MappedAddressList->NumberOfBytes); 01799 01800 Ptr = DeviceExtension->MappedAddressList; 01801 DeviceExtension->MappedAddressList = DeviceExtension->MappedAddressList->NextMappedAddress; 01802 01803 ExFreePool(Ptr); 01804 } 01805 01806 /* Finally delete the device object */ 01807 DPRINT("Deleting device %p\n", DeviceExtension->DeviceObject); 01808 IoDeleteDevice(DeviceExtension->DeviceObject); 01809 } 01810 01811 /* 01812 * @unimplemented 01813 */ 01814 VOID NTAPI 01815 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension, 01816 IN PSCSI_REQUEST_BLOCK Srb, 01817 IN PVOID LogicalAddress, 01818 IN ULONG Length) 01819 { 01820 DPRINT1("ScsiPortIoMapTransfer()\n"); 01821 UNIMPLEMENTED; 01822 } 01823 01824 /* 01825 * @unimplemented 01826 */ 01827 VOID NTAPI 01828 ScsiPortLogError(IN PVOID HwDeviceExtension, 01829 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL, 01830 IN UCHAR PathId, 01831 IN UCHAR TargetId, 01832 IN UCHAR Lun, 01833 IN ULONG ErrorCode, 01834 IN ULONG UniqueId) 01835 { 01836 //PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 01837 01838 DPRINT1("ScsiPortLogError() called\n"); 01839 01840 //DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, SCSI_PORT_DEVICE_EXTENSION, MiniPortDeviceExtension); 01841 01842 01843 DPRINT("ScsiPortLogError() done\n"); 01844 } 01845 01846 /* 01847 * @implemented 01848 */ 01849 VOID NTAPI 01850 ScsiPortMoveMemory(OUT PVOID Destination, 01851 IN PVOID Source, 01852 IN ULONG Length) 01853 { 01854 RtlMoveMemory(Destination, 01855 Source, 01856 Length); 01857 } 01858 01859 01860 /* 01861 * @implemented 01862 */ 01863 VOID 01864 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType, 01865 IN PVOID HwDeviceExtension, 01866 ...) 01867 { 01868 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 01869 va_list ap; 01870 01871 DPRINT("ScsiPortNotification() called\n"); 01872 01873 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension, 01874 SCSI_PORT_DEVICE_EXTENSION, 01875 MiniPortDeviceExtension); 01876 01877 DPRINT("DeviceExtension %p\n", DeviceExtension); 01878 01879 va_start(ap, HwDeviceExtension); 01880 01881 switch (NotificationType) 01882 { 01883 case RequestComplete: 01884 { 01885 PSCSI_REQUEST_BLOCK Srb; 01886 PSCSI_REQUEST_BLOCK_INFO SrbData; 01887 01888 Srb = (PSCSI_REQUEST_BLOCK) va_arg (ap, PSCSI_REQUEST_BLOCK); 01889 01890 DPRINT("Notify: RequestComplete (Srb %p)\n", Srb); 01891 01892 /* Make sure Srb is allright */ 01893 ASSERT(Srb->SrbStatus != SRB_STATUS_PENDING); 01894 ASSERT(Srb->Function != SRB_FUNCTION_EXECUTE_SCSI || Srb->SrbStatus != SRB_STATUS_SUCCESS || Srb->ScsiStatus == SCSISTAT_GOOD); 01895 01896 if (!(Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) 01897 { 01898 /* It's been already completed */ 01899 va_end(ap); 01900 return; 01901 } 01902 01903 /* It's not active anymore */ 01904 Srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE; 01905 01906 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 01907 { 01908 /* TODO: Treat it specially */ 01909 ASSERT(FALSE); 01910 } 01911 else 01912 { 01913 /* Get the SRB data */ 01914 SrbData = SpiGetSrbData(DeviceExtension, 01915 Srb->PathId, 01916 Srb->TargetId, 01917 Srb->Lun, 01918 Srb->QueueTag); 01919 01920 /* Make sure there are no CompletedRequests and there is a Srb */ 01921 ASSERT(SrbData->CompletedRequests == NULL && SrbData->Srb != NULL); 01922 01923 /* If it's a read/write request, make sure it has data inside it */ 01924 if ((Srb->SrbStatus == SRB_STATUS_SUCCESS) && 01925 ((Srb->Cdb[0] == SCSIOP_READ) || (Srb->Cdb[0] == SCSIOP_WRITE))) 01926 { 01927 ASSERT(Srb->DataTransferLength); 01928 } 01929 01930 SrbData->CompletedRequests = DeviceExtension->InterruptData.CompletedRequests; 01931 DeviceExtension->InterruptData.CompletedRequests = SrbData; 01932 } 01933 } 01934 break; 01935 01936 case NextRequest: 01937 DPRINT("Notify: NextRequest\n"); 01938 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; 01939 break; 01940 01941 case NextLuRequest: 01942 { 01943 UCHAR PathId; 01944 UCHAR TargetId; 01945 UCHAR Lun; 01946 PSCSI_PORT_LUN_EXTENSION LunExtension; 01947 01948 PathId = (UCHAR) va_arg (ap, int); 01949 TargetId = (UCHAR) va_arg (ap, int); 01950 Lun = (UCHAR) va_arg (ap, int); 01951 01952 DPRINT("Notify: NextLuRequest(PathId %u TargetId %u Lun %u)\n", 01953 PathId, TargetId, Lun); 01954 01955 /* Mark it in the flags field */ 01956 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NEXT_REQUEST_READY; 01957 01958 /* Get the LUN extension */ 01959 LunExtension = SpiGetLunExtension(DeviceExtension, 01960 PathId, 01961 TargetId, 01962 Lun); 01963 01964 /* If returned LunExtension is NULL, break out */ 01965 if (!LunExtension) break; 01966 01967 /* This request should not be processed if */ 01968 if ((LunExtension->ReadyLun) || 01969 (LunExtension->SrbInfo.Srb)) 01970 { 01971 /* Nothing to do here */ 01972 break; 01973 } 01974 01975 /* Add this LUN to the list */ 01976 LunExtension->ReadyLun = DeviceExtension->InterruptData.ReadyLun; 01977 DeviceExtension->InterruptData.ReadyLun = LunExtension; 01978 } 01979 break; 01980 01981 case ResetDetected: 01982 DPRINT("Notify: ResetDetected\n"); 01983 /* Add RESET flags */ 01984 DeviceExtension->InterruptData.Flags |= 01985 SCSI_PORT_RESET | SCSI_PORT_RESET_REPORTED; 01986 break; 01987 01988 case CallDisableInterrupts: 01989 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallDisableInterrupts!\n"); 01990 break; 01991 01992 case CallEnableInterrupts: 01993 DPRINT1("UNIMPLEMENTED SCSI Notification called: CallEnableInterrupts!\n"); 01994 break; 01995 01996 case RequestTimerCall: 01997 DPRINT("Notify: RequestTimerCall\n"); 01998 DeviceExtension->InterruptData.Flags |= SCSI_PORT_TIMER_NEEDED; 01999 DeviceExtension->InterruptData.HwScsiTimer = (PHW_TIMER)va_arg(ap, PHW_TIMER); 02000 DeviceExtension->InterruptData.MiniportTimerValue = (ULONG)va_arg(ap, ULONG); 02001 break; 02002 02003 case BusChangeDetected: 02004 DPRINT1("UNIMPLEMENTED SCSI Notification called: BusChangeDetected!\n"); 02005 break; 02006 02007 default: 02008 DPRINT1 ("Unsupported notification from WMI: %lu\n", NotificationType); 02009 break; 02010 } 02011 02012 va_end(ap); 02013 02014 /* Request a DPC after we're done with the interrupt */ 02015 DeviceExtension->InterruptData.Flags |= SCSI_PORT_NOTIFICATION_NEEDED; 02016 } 02017 02018 /* 02019 * @implemented 02020 */ 02021 BOOLEAN NTAPI 02022 ScsiPortValidateRange(IN PVOID HwDeviceExtension, 02023 IN INTERFACE_TYPE BusType, 02024 IN ULONG SystemIoBusNumber, 02025 IN SCSI_PHYSICAL_ADDRESS IoAddress, 02026 IN ULONG NumberOfBytes, 02027 IN BOOLEAN InIoSpace) 02028 { 02029 DPRINT("ScsiPortValidateRange()\n"); 02030 return(TRUE); 02031 } 02032 02033 02034 /* INTERNAL FUNCTIONS ********************************************************/ 02035 02036 static VOID 02037 SpiResourceToConfig(IN PHW_INITIALIZATION_DATA HwInitializationData, 02038 IN PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor, 02039 IN PPORT_CONFIGURATION_INFORMATION PortConfig) 02040 { 02041 PACCESS_RANGE AccessRange; 02042 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialData; 02043 ULONG RangeNumber; 02044 ULONG Index; 02045 ULONG Interrupt = 0; 02046 ULONG Dma = 0; 02047 02048 RangeNumber = 0; 02049 02050 /* Loop through all entries */ 02051 for (Index = 0; Index < ResourceDescriptor->PartialResourceList.Count; Index++) 02052 { 02053 PartialData = &ResourceDescriptor->PartialResourceList.PartialDescriptors[Index]; 02054 02055 switch (PartialData->Type) 02056 { 02057 case CmResourceTypePort: 02058 /* Copy access ranges */ 02059 if (RangeNumber < HwInitializationData->NumberOfAccessRanges) 02060 { 02061 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]); 02062 02063 AccessRange->RangeStart = PartialData->u.Port.Start; 02064 AccessRange->RangeLength = PartialData->u.Port.Length; 02065 02066 AccessRange->RangeInMemory = FALSE; 02067 RangeNumber++; 02068 } 02069 break; 02070 02071 case CmResourceTypeMemory: 02072 /* Copy access ranges */ 02073 if (RangeNumber < HwInitializationData->NumberOfAccessRanges) 02074 { 02075 AccessRange = &((*(PortConfig->AccessRanges))[RangeNumber]); 02076 02077 AccessRange->RangeStart = PartialData->u.Memory.Start; 02078 AccessRange->RangeLength = PartialData->u.Memory.Length; 02079 02080 AccessRange->RangeInMemory = TRUE; 02081 RangeNumber++; 02082 } 02083 break; 02084 02085 case CmResourceTypeInterrupt: 02086 02087 if (Interrupt == 0) 02088 { 02089 /* Copy interrupt data */ 02090 PortConfig->BusInterruptLevel = PartialData->u.Interrupt.Level; 02091 PortConfig->BusInterruptVector = PartialData->u.Interrupt.Vector; 02092 02093 /* Set interrupt mode accordingly to the resource */ 02094 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) 02095 { 02096 PortConfig->InterruptMode = Latched; 02097 } 02098 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) 02099 { 02100 PortConfig->InterruptMode = LevelSensitive; 02101 } 02102 } 02103 else if (Interrupt == 1) 02104 { 02105 /* Copy interrupt data */ 02106 PortConfig->BusInterruptLevel2 = PartialData->u.Interrupt.Level; 02107 PortConfig->BusInterruptVector2 = PartialData->u.Interrupt.Vector; 02108 02109 /* Set interrupt mode accordingly to the resource */ 02110 if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) 02111 { 02112 PortConfig->InterruptMode2 = Latched; 02113 } 02114 else if (PartialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) 02115 { 02116 PortConfig->InterruptMode2 = LevelSensitive; 02117 } 02118 } 02119 02120 Interrupt++; 02121 break; 02122 02123 case CmResourceTypeDma: 02124 02125 if (Dma == 0) 02126 { 02127 PortConfig->DmaChannel = PartialData->u.Dma.Channel; 02128 PortConfig->DmaPort = PartialData->u.Dma.Port; 02129 02130 if (PartialData->Flags & CM_RESOURCE_DMA_8) 02131 PortConfig->DmaWidth = Width8Bits; 02132 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) || 02133 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 02134 PortConfig->DmaWidth = Width16Bits; 02135 else if (PartialData->Flags & CM_RESOURCE_DMA_32) 02136 PortConfig->DmaWidth = Width32Bits; 02137 } 02138 else if (Dma == 1) 02139 { 02140 PortConfig->DmaChannel2 = PartialData->u.Dma.Channel; 02141 PortConfig->DmaPort2 = PartialData->u.Dma.Port; 02142 02143 if (PartialData->Flags & CM_RESOURCE_DMA_8) 02144 PortConfig->DmaWidth2 = Width8Bits; 02145 else if ((PartialData->Flags & CM_RESOURCE_DMA_16) || 02146 (PartialData->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 02147 PortConfig->DmaWidth2 = Width16Bits; 02148 else if (PartialData->Flags & CM_RESOURCE_DMA_32) 02149 PortConfig->DmaWidth2 = Width32Bits; 02150 } 02151 break; 02152 } 02153 } 02154 } 02155 02156 static PCM_RESOURCE_LIST 02157 SpiConfigToResource(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 02158 PPORT_CONFIGURATION_INFORMATION PortConfig) 02159 { 02160 PCONFIGURATION_INFORMATION ConfigInfo; 02161 PCM_RESOURCE_LIST ResourceList; 02162 PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor; 02163 PACCESS_RANGE AccessRange; 02164 ULONG ListLength = 0, i, FullSize; 02165 ULONG Interrupt, Dma; 02166 02167 /* Get current Atdisk usage from the system */ 02168 ConfigInfo = IoGetConfigurationInformation(); 02169 02170 if (PortConfig->AtdiskPrimaryClaimed) 02171 ConfigInfo->AtDiskPrimaryAddressClaimed = TRUE; 02172 02173 if (PortConfig->AtdiskSecondaryClaimed) 02174 ConfigInfo->AtDiskSecondaryAddressClaimed = TRUE; 02175 02176 /* Do we use DMA? */ 02177 if (PortConfig->DmaChannel != SP_UNINITIALIZED_VALUE || 02178 PortConfig->DmaPort != SP_UNINITIALIZED_VALUE) 02179 { 02180 Dma = 1; 02181 02182 if (PortConfig->DmaChannel2 != SP_UNINITIALIZED_VALUE || 02183 PortConfig->DmaPort2 != SP_UNINITIALIZED_VALUE) 02184 Dma++; 02185 } 02186 else 02187 { 02188 Dma = 0; 02189 } 02190 ListLength += Dma; 02191 02192 /* How many interrupts to we have? */ 02193 Interrupt = DeviceExtension->InterruptCount; 02194 ListLength += Interrupt; 02195 02196 /* How many access ranges do we use? */ 02197 AccessRange = &((*(PortConfig->AccessRanges))[0]); 02198 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++) 02199 { 02200 if (AccessRange->RangeLength != 0) 02201 ListLength++; 02202 02203 AccessRange++; 02204 } 02205 02206 /* Allocate the resource list, since we know its size now */ 02207 FullSize = sizeof(CM_RESOURCE_LIST) + (ListLength - 1) * 02208 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR); 02209 02210 ResourceList = (PCM_RESOURCE_LIST)ExAllocatePoolWithTag(PagedPool, FullSize, TAG_SCSIPORT); 02211 02212 if (!ResourceList) 02213 return NULL; 02214 02215 /* Zero it */ 02216 RtlZeroMemory(ResourceList, FullSize); 02217 02218 /* Initialize it */ 02219 ResourceList->Count = 1; 02220 ResourceList->List[0].InterfaceType = PortConfig->AdapterInterfaceType; 02221 ResourceList->List[0].BusNumber = PortConfig->SystemIoBusNumber; 02222 ResourceList->List[0].PartialResourceList.Count = ListLength; 02223 ResourceDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors; 02224 02225 /* Copy access ranges array over */ 02226 for (i = 0; i < PortConfig->NumberOfAccessRanges; i++) 02227 { 02228 AccessRange = &((*(PortConfig->AccessRanges))[i]); 02229 02230 /* If the range is empty - skip it */ 02231 if (AccessRange->RangeLength == 0) 02232 continue; 02233 02234 if (AccessRange->RangeInMemory) 02235 { 02236 ResourceDescriptor->Type = CmResourceTypeMemory; 02237 ResourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; 02238 } 02239 else 02240 { 02241 ResourceDescriptor->Type = CmResourceTypePort; 02242 ResourceDescriptor->Flags = CM_RESOURCE_PORT_IO; 02243 } 02244 02245 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; 02246 02247 ResourceDescriptor->u.Memory.Start = AccessRange->RangeStart; 02248 ResourceDescriptor->u.Memory.Length = AccessRange->RangeLength; 02249 02250 ResourceDescriptor++; 02251 } 02252 02253 /* If we use interrupt(s), copy them */ 02254 while (Interrupt) 02255 { 02256 ResourceDescriptor->Type = CmResourceTypeInterrupt; 02257 02258 if (PortConfig->AdapterInterfaceType == MicroChannel || 02259 ((Interrupt == 2) ? PortConfig->InterruptMode2 : PortConfig->InterruptMode) == LevelSensitive) 02260 { 02261 ResourceDescriptor->ShareDisposition = CmResourceShareShared; 02262 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; 02263 } 02264 else 02265 { 02266 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; 02267 ResourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED; 02268 } 02269 02270 ResourceDescriptor->u.Interrupt.Level = (Interrupt == 2) ? PortConfig->BusInterruptLevel2 : PortConfig->BusInterruptLevel; 02271 ResourceDescriptor->u.Interrupt.Vector = (Interrupt == 2) ? PortConfig->BusInterruptVector2 : PortConfig->BusInterruptVector; 02272 ResourceDescriptor->u.Interrupt.Affinity = 0; 02273 02274 ResourceDescriptor++; 02275 Interrupt--; 02276 } 02277 02278 /* Copy DMA data */ 02279 while (Dma) 02280 { 02281 ResourceDescriptor->Type = CmResourceTypeDma; 02282 ResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; 02283 ResourceDescriptor->u.Dma.Channel = (Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel; 02284 ResourceDescriptor->u.Dma.Port = (Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort; 02285 ResourceDescriptor->Flags = 0; 02286 02287 if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width8Bits) 02288 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_8; 02289 else if (((Dma == 2) ? PortConfig->DmaWidth2 : PortConfig->DmaWidth) == Width16Bits) 02290 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_16; 02291 else 02292 ResourceDescriptor->Flags |= CM_RESOURCE_DMA_32; 02293 02294 if (((Dma == 2) ? PortConfig->DmaChannel2 : PortConfig->DmaChannel) == SP_UNINITIALIZED_VALUE) 02295 ResourceDescriptor->u.Dma.Channel = 0; 02296 02297 if (((Dma == 2) ? PortConfig->DmaPort2 : PortConfig->DmaPort) == SP_UNINITIALIZED_VALUE) 02298 ResourceDescriptor->u.Dma.Port = 0; 02299 02300 ResourceDescriptor++; 02301 Dma--; 02302 } 02303 02304 return ResourceList; 02305 } 02306 02307 02308 static BOOLEAN 02309 SpiGetPciConfigData(IN PDRIVER_OBJECT DriverObject, 02310 IN PDEVICE_OBJECT DeviceObject, 02311 IN struct _HW_INITIALIZATION_DATA *HwInitializationData, 02312 IN OUT PPORT_CONFIGURATION_INFORMATION PortConfig, 02313 IN PUNICODE_STRING RegistryPath, 02314 IN ULONG BusNumber, 02315 IN OUT PPCI_SLOT_NUMBER NextSlotNumber) 02316 { 02317 PCI_COMMON_CONFIG PciConfig; 02318 PCI_SLOT_NUMBER SlotNumber; 02319 ULONG DataSize; 02320 ULONG DeviceNumber; 02321 ULONG FunctionNumber; 02322 CHAR VendorIdString[8]; 02323 CHAR DeviceIdString[8]; 02324 UNICODE_STRING UnicodeStr; 02325 PCM_RESOURCE_LIST ResourceList = NULL; 02326 NTSTATUS Status; 02327 02328 DPRINT ("SpiGetPciConfiguration() called\n"); 02329 02330 SlotNumber.u.AsULONG = 0; 02331 02332 /* Loop through all devices */ 02333 for (DeviceNumber = NextSlotNumber->u.bits.DeviceNumber; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber++) 02334 { 02335 SlotNumber.u.bits.DeviceNumber = DeviceNumber; 02336 02337 /* Loop through all functions */ 02338 for (FunctionNumber = NextSlotNumber->u.bits.FunctionNumber; FunctionNumber < PCI_MAX_FUNCTION; FunctionNumber++) 02339 { 02340 SlotNumber.u.bits.FunctionNumber = FunctionNumber; 02341 02342 /* Get PCI config bytes */ 02343 DataSize = HalGetBusData(PCIConfiguration, 02344 BusNumber, 02345 SlotNumber.u.AsULONG, 02346 &PciConfig, 02347 sizeof(ULONG)); 02348 02349 /* If result of HalGetBusData is 0, then the bus is wrong */ 02350 if (DataSize == 0) 02351 return FALSE; 02352 02353 /* If result is PCI_INVALID_VENDORID, then this device has no more 02354 "Functions" */ 02355 if (PciConfig.VendorID == PCI_INVALID_VENDORID) 02356 break; 02357 02358 sprintf (VendorIdString, "%04hx", PciConfig.VendorID); 02359 sprintf (DeviceIdString, "%04hx", PciConfig.DeviceID); 02360 02361 if (_strnicmp(VendorIdString, HwInitializationData->VendorId, HwInitializationData->VendorIdLength) || 02362 _strnicmp(DeviceIdString, HwInitializationData->DeviceId, HwInitializationData->DeviceIdLength)) 02363 { 02364 /* It is not our device */ 02365 continue; 02366 } 02367 02368 DPRINT("Found device 0x%04hx 0x%04hx at %1lu %2lu %1lu\n", 02369 PciConfig.VendorID, 02370 PciConfig.DeviceID, 02371 BusNumber, 02372 SlotNumber.u.bits.DeviceNumber, 02373 SlotNumber.u.bits.FunctionNumber); 02374 02375 02376 RtlInitUnicodeString(&UnicodeStr, L"ScsiAdapter"); 02377 Status = HalAssignSlotResources(RegistryPath, 02378 &UnicodeStr, 02379 DriverObject, 02380 DeviceObject, 02381 PCIBus, 02382 BusNumber, 02383 SlotNumber.u.AsULONG, 02384 &ResourceList); 02385 02386 if (!NT_SUCCESS(Status)) 02387 break; 02388 02389 /* Create configuration information */ 02390 SpiResourceToConfig(HwInitializationData, 02391 ResourceList->List, 02392 PortConfig); 02393 02394 /* Free the resource list */ 02395 ExFreePool(ResourceList); 02396 02397 /* Set dev & fn numbers */ 02398 NextSlotNumber->u.bits.DeviceNumber = DeviceNumber; 02399 NextSlotNumber->u.bits.FunctionNumber = FunctionNumber + 1; 02400 02401 /* Save the slot number */ 02402 PortConfig->SlotNumber = SlotNumber.u.AsULONG; 02403 02404 return TRUE; 02405 } 02406 NextSlotNumber->u.bits.FunctionNumber = 0; 02407 } 02408 02409 NextSlotNumber->u.bits.DeviceNumber = 0; 02410 DPRINT ("No device found\n"); 02411 02412 return FALSE; 02413 } 02414 02415 02416 02417 /********************************************************************** 02418 * NAME INTERNAL 02419 * ScsiPortCreateClose 02420 * 02421 * DESCRIPTION 02422 * Answer requests for Create/Close calls: a null operation. 02423 * 02424 * RUN LEVEL 02425 * PASSIVE_LEVEL 02426 * 02427 * ARGUMENTS 02428 * DeviceObject 02429 * Pointer to a device object. 02430 * 02431 * Irp 02432 * Pointer to an IRP. 02433 * 02434 * RETURN VALUE 02435 * Status. 02436 */ 02437 02438 static NTSTATUS NTAPI 02439 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject, 02440 IN PIRP Irp) 02441 { 02442 DPRINT("ScsiPortCreateClose()\n"); 02443 02444 Irp->IoStatus.Status = STATUS_SUCCESS; 02445 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02446 02447 return STATUS_SUCCESS; 02448 } 02449 02450 static NTSTATUS 02451 SpiHandleAttachRelease(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 02452 PIRP Irp) 02453 { 02454 PSCSI_LUN_INFO LunInfo; 02455 PIO_STACK_LOCATION IrpStack; 02456 PDEVICE_OBJECT DeviceObject; 02457 PSCSI_REQUEST_BLOCK Srb; 02458 KIRQL Irql; 02459 02460 /* Get pointer to the SRB */ 02461 IrpStack = IoGetCurrentIrpStackLocation(Irp); 02462 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; 02463 02464 /* Check if PathId matches number of buses */ 02465 if (DeviceExtension->BusesConfig == NULL || 02466 DeviceExtension->BusesConfig->NumberOfBuses <= Srb->PathId) 02467 { 02468 Srb->SrbStatus = SRB_STATUS_NO_DEVICE; 02469 return STATUS_DEVICE_DOES_NOT_EXIST; 02470 } 02471 02472 /* Get pointer to LunInfo */ 02473 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Srb->PathId]->LunInfo; 02474 02475 /* Find matching LunInfo */ 02476 while (LunInfo) 02477 { 02478 if (LunInfo->PathId == Srb->PathId && 02479 LunInfo->TargetId == Srb->TargetId && 02480 LunInfo->Lun == Srb->Lun) 02481 { 02482 break; 02483 } 02484 02485 LunInfo = LunInfo->Next; 02486 } 02487 02488 /* If we couldn't find it - exit */ 02489 if (LunInfo == NULL) 02490 return STATUS_DEVICE_DOES_NOT_EXIST; 02491 02492 02493 /* Get spinlock */ 02494 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 02495 02496 /* Release, if asked */ 02497 if (Srb->Function == SRB_FUNCTION_RELEASE_DEVICE) 02498 { 02499 LunInfo->DeviceClaimed = FALSE; 02500 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02501 Srb->SrbStatus = SRB_STATUS_SUCCESS; 02502 02503 return STATUS_SUCCESS; 02504 } 02505 02506 /* Attach, if not already claimed */ 02507 if (LunInfo->DeviceClaimed) 02508 { 02509 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02510 Srb->SrbStatus = SRB_STATUS_BUSY; 02511 02512 return STATUS_DEVICE_BUSY; 02513 } 02514 02515 /* Save the device object */ 02516 DeviceObject = LunInfo->DeviceObject; 02517 02518 if (Srb->Function == SRB_FUNCTION_CLAIM_DEVICE) 02519 LunInfo->DeviceClaimed = TRUE; 02520 02521 if (Srb->Function == SRB_FUNCTION_ATTACH_DEVICE) 02522 LunInfo->DeviceObject = Srb->DataBuffer; 02523 02524 Srb->DataBuffer = DeviceObject; 02525 02526 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02527 Srb->SrbStatus = SRB_STATUS_SUCCESS; 02528 02529 return STATUS_SUCCESS; 02530 } 02531 02532 02533 /********************************************************************** 02534 * NAME INTERNAL 02535 * ScsiPortDispatchScsi 02536 * 02537 * DESCRIPTION 02538 * Answer requests for SCSI calls 02539 * 02540 * RUN LEVEL 02541 * PASSIVE_LEVEL 02542 * 02543 * ARGUMENTS 02544 * Standard dispatch arguments 02545 * 02546 * RETURNS 02547 * NTSTATUS 02548 */ 02549 02550 static NTSTATUS NTAPI 02551 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject, 02552 IN PIRP Irp) 02553 { 02554 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 02555 PSCSI_PORT_LUN_EXTENSION LunExtension; 02556 PIO_STACK_LOCATION Stack; 02557 PSCSI_REQUEST_BLOCK Srb; 02558 KIRQL Irql; 02559 NTSTATUS Status = STATUS_SUCCESS; 02560 PIRP NextIrp, IrpList; 02561 PKDEVICE_QUEUE_ENTRY Entry; 02562 02563 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n", 02564 DeviceObject, Irp); 02565 02566 DeviceExtension = DeviceObject->DeviceExtension; 02567 Stack = IoGetCurrentIrpStackLocation(Irp); 02568 02569 Srb = Stack->Parameters.Scsi.Srb; 02570 if (Srb == NULL) 02571 { 02572 DPRINT1("ScsiPortDispatchScsi() called with Srb = NULL!\n"); 02573 Status = STATUS_UNSUCCESSFUL; 02574 02575 Irp->IoStatus.Status = Status; 02576 Irp->IoStatus.Information = 0; 02577 02578 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02579 02580 return(Status); 02581 } 02582 02583 DPRINT("Srb: %p\n", Srb); 02584 DPRINT("Srb->Function: %lu\n", Srb->Function); 02585 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun); 02586 02587 LunExtension = SpiGetLunExtension(DeviceExtension, 02588 Srb->PathId, 02589 Srb->TargetId, 02590 Srb->Lun); 02591 if (LunExtension == NULL) 02592 { 02593 DPRINT("ScsiPortDispatchScsi() called with an invalid LUN\n"); 02594 Status = STATUS_NO_SUCH_DEVICE; 02595 02596 Srb->SrbStatus = SRB_STATUS_NO_DEVICE; 02597 Irp->IoStatus.Status = Status; 02598 Irp->IoStatus.Information = 0; 02599 02600 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02601 02602 return(Status); 02603 } 02604 02605 switch (Srb->Function) 02606 { 02607 case SRB_FUNCTION_SHUTDOWN: 02608 case SRB_FUNCTION_FLUSH: 02609 DPRINT (" SRB_FUNCTION_SHUTDOWN or FLUSH\n"); 02610 if (DeviceExtension->CachesData == FALSE) 02611 { 02612 /* All success here */ 02613 Srb->SrbStatus = SRB_STATUS_SUCCESS; 02614 Irp->IoStatus.Status = STATUS_SUCCESS; 02615 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02616 return STATUS_SUCCESS; 02617 } 02618 /* Fall through to a usual execute operation */ 02619 02620 case SRB_FUNCTION_EXECUTE_SCSI: 02621 case SRB_FUNCTION_IO_CONTROL: 02622 /* Mark IRP as pending in all cases */ 02623 IoMarkIrpPending(Irp); 02624 02625 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) 02626 { 02627 /* Start IO directly */ 02628 IoStartPacket(DeviceObject, Irp, NULL, NULL); 02629 } 02630 else 02631 { 02632 KIRQL oldIrql; 02633 02634 /* We need to be at DISPATCH_LEVEL */ 02635 KeRaiseIrql (DISPATCH_LEVEL, &oldIrql); 02636 02637 /* Insert IRP into the queue */ 02638 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue, 02639 &Irp->Tail.Overlay.DeviceQueueEntry, 02640 Srb->QueueSortKey)) 02641 { 02642 /* It means the queue is empty, and we just start this request */ 02643 IoStartPacket(DeviceObject, Irp, NULL, NULL); 02644 } 02645 02646 /* Back to the old IRQL */ 02647 KeLowerIrql (oldIrql); 02648 } 02649 return STATUS_PENDING; 02650 02651 case SRB_FUNCTION_CLAIM_DEVICE: 02652 case SRB_FUNCTION_ATTACH_DEVICE: 02653 DPRINT (" SRB_FUNCTION_CLAIM_DEVICE or ATTACH\n"); 02654 02655 /* Reference device object and keep the device object */ 02656 Status = SpiHandleAttachRelease(DeviceExtension, Irp); 02657 break; 02658 02659 case SRB_FUNCTION_RELEASE_DEVICE: 02660 DPRINT (" SRB_FUNCTION_RELEASE_DEVICE\n"); 02661 02662 /* Dereference device object and clear the device object */ 02663 Status = SpiHandleAttachRelease(DeviceExtension, Irp); 02664 break; 02665 02666 case SRB_FUNCTION_RELEASE_QUEUE: 02667 DPRINT(" SRB_FUNCTION_RELEASE_QUEUE\n"); 02668 02669 /* Guard with the spinlock */ 02670 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 02671 02672 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE)) 02673 { 02674 DPRINT("Queue is not frozen really\n"); 02675 02676 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02677 Srb->SrbStatus = SRB_STATUS_SUCCESS; 02678 Status = STATUS_SUCCESS; 02679 break; 02680 02681 } 02682 02683 /* Unfreeze the queue */ 02684 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE; 02685 02686 if (LunExtension->SrbInfo.Srb == NULL) 02687 { 02688 /* Get next logical unit request */ 02689 SpiGetNextRequestFromLun(DeviceExtension, LunExtension); 02690 02691 /* SpiGetNextRequestFromLun() releases the spinlock */ 02692 KeLowerIrql(Irql); 02693 } 02694 else 02695 { 02696 DPRINT("The queue has active request\n"); 02697 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02698 } 02699 02700 02701 Srb->SrbStatus = SRB_STATUS_SUCCESS; 02702 Status = STATUS_SUCCESS; 02703 break; 02704 02705 case SRB_FUNCTION_FLUSH_QUEUE: 02706 DPRINT(" SRB_FUNCTION_FLUSH_QUEUE\n"); 02707 02708 /* Guard with the spinlock */ 02709 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 02710 02711 if (!(LunExtension->Flags & LUNEX_FROZEN_QUEUE)) 02712 { 02713 DPRINT("Queue is not frozen really\n"); 02714 02715 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02716 Status = STATUS_INVALID_DEVICE_REQUEST; 02717 break; 02718 } 02719 02720 /* Make sure there is no active request */ 02721 ASSERT(LunExtension->SrbInfo.Srb == NULL); 02722 02723 /* Compile a list from the device queue */ 02724 IrpList = NULL; 02725 while ((Entry = KeRemoveDeviceQueue(&LunExtension->DeviceQueue)) != NULL) 02726 { 02727 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 02728 02729 /* Get the Srb */ 02730 Stack = IoGetCurrentIrpStackLocation(NextIrp); 02731 Srb = Stack->Parameters.Scsi.Srb; 02732 02733 /* Set statuse */ 02734 Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED; 02735 NextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL; 02736 02737 /* Add then to the list */ 02738 NextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)IrpList; 02739 IrpList = NextIrp; 02740 } 02741 02742 /* Unfreeze the queue */ 02743 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE; 02744 02745 /* Release the spinlock */ 02746 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 02747 02748 /* Complete those requests */ 02749 while (IrpList) 02750 { 02751 NextIrp = IrpList; 02752 IrpList = (PIRP)NextIrp->Tail.Overlay.ListEntry.Flink; 02753 02754 IoCompleteRequest(NextIrp, 0); 02755 } 02756 02757 Status = STATUS_SUCCESS; 02758 break; 02759 02760 default: 02761 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function); 02762 Status = STATUS_NOT_IMPLEMENTED; 02763 break; 02764 } 02765 02766 Irp->IoStatus.Status = Status; 02767 02768 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02769 02770 return(Status); 02771 } 02772 02773 02774 /********************************************************************** 02775 * NAME INTERNAL 02776 * ScsiPortDeviceControl 02777 * 02778 * DESCRIPTION 02779 * Answer requests for device control calls 02780 * 02781 * RUN LEVEL 02782 * PASSIVE_LEVEL 02783 * 02784 * ARGUMENTS 02785 * Standard dispatch arguments 02786 * 02787 * RETURNS 02788 * NTSTATUS 02789 */ 02790 02791 static NTSTATUS NTAPI 02792 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject, 02793 IN PIRP Irp) 02794 { 02795 PIO_STACK_LOCATION Stack; 02796 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 02797 PDUMP_POINTERS DumpPointers; 02798 NTSTATUS Status; 02799 02800 DPRINT("ScsiPortDeviceControl()\n"); 02801 02802 Irp->IoStatus.Information = 0; 02803 02804 Stack = IoGetCurrentIrpStackLocation(Irp); 02805 DeviceExtension = DeviceObject->DeviceExtension; 02806 02807 switch (Stack->Parameters.DeviceIoControl.IoControlCode) 02808 { 02809 case IOCTL_SCSI_GET_DUMP_POINTERS: 02810 DPRINT(" IOCTL_SCSI_GET_DUMP_POINTERS\n"); 02811 02812 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DUMP_POINTERS)) 02813 { 02814 Status = STATUS_BUFFER_OVERFLOW; 02815 Irp->IoStatus.Information = sizeof(DUMP_POINTERS); 02816 break; 02817 } 02818 02819 DumpPointers = Irp->AssociatedIrp.SystemBuffer; 02820 DumpPointers->DeviceObject = DeviceObject; 02821 /* More data.. ? */ 02822 02823 Status = STATUS_SUCCESS; 02824 Irp->IoStatus.Information = sizeof(DUMP_POINTERS); 02825 break; 02826 02827 case IOCTL_SCSI_GET_CAPABILITIES: 02828 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n"); 02829 if (Stack->Parameters.DeviceIoControl.OutputBufferLength == sizeof(PVOID)) 02830 { 02831 *((PVOID *)Irp->AssociatedIrp.SystemBuffer) = &DeviceExtension->PortCapabilities; 02832 02833 Irp->IoStatus.Information = sizeof(PVOID); 02834 Status = STATUS_SUCCESS; 02835 break; 02836 } 02837 02838 if (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(IO_SCSI_CAPABILITIES)) 02839 { 02840 Status = STATUS_BUFFER_TOO_SMALL; 02841 break; 02842 } 02843 02844 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, 02845 &DeviceExtension->PortCapabilities, 02846 sizeof(IO_SCSI_CAPABILITIES)); 02847 02848 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES); 02849 Status = STATUS_SUCCESS; 02850 break; 02851 02852 case IOCTL_SCSI_GET_INQUIRY_DATA: 02853 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n"); 02854 02855 /* Copy inquiry data to the port device extension */ 02856 Status = SpiGetInquiryData(DeviceExtension, Irp); 02857 break; 02858 02859 case IOCTL_SCSI_MINIPORT: 02860 DPRINT1("IOCTL_SCSI_MINIPORT unimplemented!\n"); 02861 Status = STATUS_NOT_IMPLEMENTED; 02862 break; 02863 02864 case IOCTL_SCSI_PASS_THROUGH: 02865 DPRINT1("IOCTL_SCSI_PASS_THROUGH unimplemented!\n"); 02866 Status = STATUS_NOT_IMPLEMENTED; 02867 break; 02868 02869 default: 02870 DPRINT1(" unknown ioctl code: 0x%lX\n", Stack->Parameters.DeviceIoControl.IoControlCode); 02871 Status = STATUS_NOT_IMPLEMENTED; 02872 break; 02873 } 02874 02875 /* Complete the request with the given status */ 02876 Irp->IoStatus.Status = Status; 02877 IoCompleteRequest(Irp, IO_NO_INCREMENT); 02878 02879 return Status; 02880 } 02881 02882 02883 static VOID NTAPI 02884 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject, 02885 IN PIRP Irp) 02886 { 02887 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 02888 PSCSI_PORT_LUN_EXTENSION LunExtension; 02889 PIO_STACK_LOCATION IrpStack; 02890 PSCSI_REQUEST_BLOCK Srb; 02891 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 02892 LONG CounterResult; 02893 NTSTATUS Status; 02894 02895 DPRINT("ScsiPortStartIo() called!\n"); 02896 02897 DeviceExtension = DeviceObject->DeviceExtension; 02898 IrpStack = IoGetCurrentIrpStackLocation(Irp); 02899 02900 DPRINT("DeviceExtension %p\n", DeviceExtension); 02901 02902 Srb = IrpStack->Parameters.Scsi.Srb; 02903 02904 /* Apply "default" flags */ 02905 Srb->SrbFlags |= DeviceExtension->SrbFlags; 02906 02907 /* Get LUN extension */ 02908 LunExtension = SpiGetLunExtension(DeviceExtension, 02909 Srb->PathId, 02910 Srb->TargetId, 02911 Srb->Lun); 02912 02913 if (DeviceExtension->NeedSrbDataAlloc || 02914 DeviceExtension->NeedSrbExtensionAlloc) 02915 { 02916 /* Allocate them */ 02917 SrbInfo = SpiAllocateSrbStructures(DeviceExtension, 02918 LunExtension, 02919 Srb); 02920 02921 /* Couldn't alloc one or both data structures, return */ 02922 if (SrbInfo == NULL) 02923 { 02924 /* We have to call IoStartNextPacket, because this request 02925 was not started */ 02926 if (LunExtension->Flags & LUNEX_REQUEST_PENDING) 02927 IoStartNextPacket(DeviceObject, FALSE); 02928 02929 return; 02930 } 02931 } 02932 else 02933 { 02934 /* No allocations are needed */ 02935 SrbInfo = &LunExtension->SrbInfo; 02936 Srb->SrbExtension = NULL; 02937 Srb->QueueTag = SP_UNTAGGED; 02938 } 02939 02940 /* Increase sequence number of SRB */ 02941 if (!SrbInfo->SequenceNumber) 02942 { 02943 /* Increase global sequence number */ 02944 DeviceExtension->SequenceNumber++; 02945 02946 /* Assign it */ 02947 SrbInfo->SequenceNumber = DeviceExtension->SequenceNumber; 02948 } 02949 02950 /* Check some special SRBs */ 02951 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 02952 { 02953 /* Some special handling */ 02954 DPRINT1("Abort command! Unimplemented now\n"); 02955 } 02956 else 02957 { 02958 SrbInfo->Srb = Srb; 02959 } 02960 02961 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) 02962 { 02963 // Store the MDL virtual address in SrbInfo structure 02964 SrbInfo->DataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress); 02965 02966 if (DeviceExtension->MapBuffers) 02967 { 02968 /* Calculate offset within DataBuffer */ 02969 SrbInfo->DataOffset = MmGetSystemAddressForMdl(Irp->MdlAddress); 02970 Srb->DataBuffer = SrbInfo->DataOffset + 02971 (ULONG)((PUCHAR)Srb->DataBuffer - 02972 (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress)); 02973 } 02974 02975 if (DeviceExtension->AdapterObject) 02976 { 02977 /* Flush buffers */ 02978 KeFlushIoBuffers(Irp->MdlAddress, 02979 Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE, 02980 TRUE); 02981 } 02982 02983 if (DeviceExtension->MapRegisters) 02984 { 02985 /* Calculate number of needed map registers */ 02986 SrbInfo->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( 02987 Srb->DataBuffer, 02988 Srb->DataTransferLength); 02989 02990 /* Allocate adapter channel */ 02991 Status = IoAllocateAdapterChannel(DeviceExtension->AdapterObject, 02992 DeviceExtension->DeviceObject, 02993 SrbInfo->NumberOfMapRegisters, 02994 SpiAdapterControl, 02995 SrbInfo); 02996 02997 if (!NT_SUCCESS(Status)) 02998 { 02999 DPRINT1("IoAllocateAdapterChannel() failed!\n"); 03000 03001 Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; 03002 ScsiPortNotification(RequestComplete, 03003 DeviceExtension + 1, 03004 Srb); 03005 03006 ScsiPortNotification(NextRequest, 03007 DeviceExtension + 1); 03008 03009 /* Request DPC for that work */ 03010 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 03011 } 03012 03013 /* Control goes to SpiAdapterControl */ 03014 return; 03015 } 03016 } 03017 03018 /* Increase active request counter */ 03019 CounterResult = InterlockedIncrement(&DeviceExtension->ActiveRequestCounter); 03020 03021 if (CounterResult == 0 && 03022 DeviceExtension->AdapterObject != NULL && 03023 !DeviceExtension->MapRegisters) 03024 { 03025 IoAllocateAdapterChannel( 03026 DeviceExtension->AdapterObject, 03027 DeviceObject, 03028 DeviceExtension->PortCapabilities.MaximumPhysicalPages, 03029 ScsiPortAllocateAdapterChannel, 03030 LunExtension 03031 ); 03032 03033 return; 03034 } 03035 03036 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 03037 03038 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 03039 ScsiPortStartPacket, 03040 DeviceObject)) 03041 { 03042 DPRINT("Synchronization failed!\n"); 03043 03044 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL; 03045 Irp->IoStatus.Information = 0; 03046 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03047 03048 IoCompleteRequest(Irp, IO_NO_INCREMENT); 03049 } 03050 else 03051 { 03052 /* Release the spinlock only */ 03053 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03054 } 03055 03056 03057 DPRINT("ScsiPortStartIo() done\n"); 03058 } 03059 03060 03061 static BOOLEAN NTAPI 03062 ScsiPortStartPacket(IN OUT PVOID Context) 03063 { 03064 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 03065 PIO_STACK_LOCATION IrpStack; 03066 PSCSI_REQUEST_BLOCK Srb; 03067 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context; 03068 PSCSI_PORT_LUN_EXTENSION LunExtension; 03069 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 03070 BOOLEAN Result; 03071 BOOLEAN StartTimer; 03072 03073 DPRINT("ScsiPortStartPacket() called\n"); 03074 03075 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 03076 03077 IrpStack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp); 03078 Srb = IrpStack->Parameters.Scsi.Srb; 03079 03080 /* Get LUN extension */ 03081 LunExtension = SpiGetLunExtension(DeviceExtension, 03082 Srb->PathId, 03083 Srb->TargetId, 03084 Srb->Lun); 03085 03086 /* Check if we are in a reset state */ 03087 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET) 03088 { 03089 /* Mark the we've got requests while being in the reset state */ 03090 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET_REQUEST; 03091 return TRUE; 03092 } 03093 03094 /* Set the time out value */ 03095 DeviceExtension->TimerCount = Srb->TimeOutValue; 03096 03097 /* We are busy */ 03098 DeviceExtension->Flags |= SCSI_PORT_DEVICE_BUSY; 03099 03100 if (LunExtension->RequestTimeout != -1) 03101 { 03102 /* Timer already active */ 03103 StartTimer = FALSE; 03104 } 03105 else 03106 { 03107 /* It hasn't been initialized yet */ 03108 LunExtension->RequestTimeout = Srb->TimeOutValue; 03109 StartTimer = TRUE; 03110 } 03111 03112 if (Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) 03113 { 03114 /* Handle bypass-requests */ 03115 03116 /* Is this an abort request? */ 03117 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 03118 { 03119 /* Get pointer to SRB info structure */ 03120 SrbInfo = SpiGetSrbData(DeviceExtension, 03121 Srb->PathId, 03122 Srb->TargetId, 03123 Srb->Lun, 03124 Srb->QueueTag); 03125 03126 /* Check if the request is still "active" */ 03127 if (SrbInfo == NULL || 03128 SrbInfo->Srb == NULL || 03129 !(SrbInfo->Srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) 03130 { 03131 /* It's not, mark it as active then */ 03132 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE; 03133 03134 if (StartTimer) 03135 LunExtension->RequestTimeout = -1; 03136 03137 DPRINT("Request has been already completed, but abort request came\n"); 03138 Srb->SrbStatus = SRB_STATUS_ABORT_FAILED; 03139 03140 /* Notify about request complete */ 03141 ScsiPortNotification(RequestComplete, 03142 DeviceExtension->MiniPortDeviceExtension, 03143 Srb); 03144 03145 /* and about readiness for the next request */ 03146 ScsiPortNotification(NextRequest, 03147 DeviceExtension->MiniPortDeviceExtension); 03148 03149 /* They might ask for some work, so queue the DPC for them */ 03150 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 03151 03152 /* We're done in this branch */ 03153 return TRUE; 03154 } 03155 } 03156 else 03157 { 03158 /* Add number of queued requests */ 03159 LunExtension->QueueCount++; 03160 } 03161 03162 /* Bypass requests don't need request sense */ 03163 LunExtension->Flags &= ~LUNEX_NEED_REQUEST_SENSE; 03164 03165 /* Is disconnect disabled for this request? */ 03166 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 03167 { 03168 /* Set the corresponding flag */ 03169 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED; 03170 } 03171 03172 /* Transfer timeout value from Srb to Lun */ 03173 LunExtension->RequestTimeout = Srb->TimeOutValue; 03174 } 03175 else 03176 { 03177 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 03178 { 03179 /* It's a disconnect, so no more requests can go */ 03180 DeviceExtension->Flags &= ~SCSI_PORT_DISCONNECT_ALLOWED; 03181 } 03182 03183 LunExtension->Flags |= SCSI_PORT_LU_ACTIVE; 03184 03185 /* Increment queue count */ 03186 LunExtension->QueueCount++; 03187 03188 /* If it's tagged - special thing */ 03189 if (Srb->QueueTag != SP_UNTAGGED) 03190 { 03191 SrbInfo = &DeviceExtension->SrbInfo[Srb->QueueTag - 1]; 03192 03193 /* Chek for consistency */ 03194 ASSERT(SrbInfo->Requests.Blink == NULL); 03195 03196 /* Insert it into the list of requests */ 03197 InsertTailList(&LunExtension->SrbInfo.Requests, &SrbInfo->Requests); 03198 } 03199 } 03200 03201 /* Mark this Srb active */ 03202 Srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE; 03203 03204 /* Call HwStartIo routine */ 03205 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension, 03206 Srb); 03207 03208 /* If notification is needed, then request a DPC */ 03209 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 03210 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 03211 03212 return Result; 03213 } 03214 03215 IO_ALLOCATION_ACTION 03216 NTAPI 03217 SpiAdapterControl(PDEVICE_OBJECT DeviceObject, 03218 PIRP Irp, 03219 PVOID MapRegisterBase, 03220 PVOID Context) 03221 { 03222 PSCSI_REQUEST_BLOCK Srb; 03223 PSCSI_SG_ADDRESS ScatterGatherList; 03224 KIRQL CurrentIrql; 03225 PIO_STACK_LOCATION IrpStack; 03226 ULONG TotalLength = 0; 03227 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 03228 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 03229 PUCHAR DataVA; 03230 BOOLEAN WriteToDevice; 03231 03232 /* Get pointers to SrbInfo and DeviceExtension */ 03233 SrbInfo = (PSCSI_REQUEST_BLOCK_INFO)Context; 03234 DeviceExtension = DeviceObject->DeviceExtension; 03235 03236 /* Get pointer to SRB */ 03237 IrpStack = IoGetCurrentIrpStackLocation(Irp); 03238 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; 03239 03240 /* Depending on the map registers number, we allocate 03241 either from NonPagedPool, or from our static list */ 03242 if (SrbInfo->NumberOfMapRegisters > MAX_SG_LIST) 03243 { 03244 SrbInfo->ScatterGather = ExAllocatePoolWithTag( 03245 NonPagedPool, SrbInfo->NumberOfMapRegisters * sizeof(SCSI_SG_ADDRESS), TAG_SCSIPORT); 03246 03247 if (SrbInfo->ScatterGather == NULL) 03248 ASSERT(FALSE); 03249 03250 Srb->SrbFlags |= SRB_FLAGS_SGLIST_FROM_POOL; 03251 } 03252 else 03253 { 03254 SrbInfo->ScatterGather = SrbInfo->ScatterGatherList; 03255 } 03256 03257 /* Use chosen SG list source */ 03258 ScatterGatherList = SrbInfo->ScatterGather; 03259 03260 /* Save map registers base */ 03261 SrbInfo->BaseOfMapRegister = MapRegisterBase; 03262 03263 /* Determine WriteToDevice flag */ 03264 WriteToDevice = Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE; 03265 03266 /* Get virtual address of the data buffer */ 03267 DataVA = (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) + 03268 ((PCHAR)Srb->DataBuffer - SrbInfo->DataOffset); 03269 03270 /* Build the actual SG list */ 03271 while (TotalLength < Srb->DataTransferLength) 03272 { 03273 if (!ScatterGatherList) 03274 break; 03275 03276 ScatterGatherList->Length = Srb->DataTransferLength - TotalLength; 03277 ScatterGatherList->PhysicalAddress = IoMapTransfer(NULL, 03278 Irp->MdlAddress, 03279 MapRegisterBase, 03280 DataVA + TotalLength, 03281 &ScatterGatherList->Length, 03282 WriteToDevice); 03283 03284 TotalLength += ScatterGatherList->Length; 03285 ScatterGatherList++; 03286 } 03287 03288 /* Schedule an active request */ 03289 InterlockedIncrement(&DeviceExtension->ActiveRequestCounter ); 03290 KeAcquireSpinLock(&DeviceExtension->SpinLock, &CurrentIrql); 03291 KeSynchronizeExecution(DeviceExtension->Interrupt[0], 03292 ScsiPortStartPacket, 03293 DeviceObject); 03294 KeReleaseSpinLock(&DeviceExtension->SpinLock, CurrentIrql); 03295 03296 return DeallocateObjectKeepRegisters; 03297 } 03298 03299 static PSCSI_PORT_LUN_EXTENSION 03300 SpiAllocateLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) 03301 { 03302 PSCSI_PORT_LUN_EXTENSION LunExtension; 03303 ULONG LunExtensionSize; 03304 03305 DPRINT("SpiAllocateLunExtension (%p)\n", 03306 DeviceExtension); 03307 03308 /* Round LunExtensionSize first to the sizeof LONGLONG */ 03309 LunExtensionSize = (DeviceExtension->LunExtensionSize + 03310 sizeof(LONGLONG) - 1) & ~(sizeof(LONGLONG) - 1); 03311 03312 LunExtensionSize += sizeof(SCSI_PORT_LUN_EXTENSION); 03313 DPRINT("LunExtensionSize %lu\n", LunExtensionSize); 03314 03315 LunExtension = ExAllocatePoolWithTag(NonPagedPool, LunExtensionSize, TAG_SCSIPORT); 03316 if (LunExtension == NULL) 03317 { 03318 DPRINT1("Out of resources!\n"); 03319 return NULL; 03320 } 03321 03322 /* Zero everything */ 03323 RtlZeroMemory(LunExtension, LunExtensionSize); 03324 03325 /* Initialize a list of requests */ 03326 InitializeListHead(&LunExtension->SrbInfo.Requests); 03327 03328 /* Initialize timeout counter */ 03329 LunExtension->RequestTimeout = -1; 03330 03331 /* Set maximum queue size */ 03332 LunExtension->MaxQueueCount = 256; 03333 03334 /* Initialize request queue */ 03335 KeInitializeDeviceQueue (&LunExtension->DeviceQueue); 03336 03337 return LunExtension; 03338 } 03339 03340 static PSCSI_PORT_LUN_EXTENSION 03341 SpiGetLunExtension (IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 03342 IN UCHAR PathId, 03343 IN UCHAR TargetId, 03344 IN UCHAR Lun) 03345 { 03346 PSCSI_PORT_LUN_EXTENSION LunExtension; 03347 03348 DPRINT("SpiGetLunExtension(%p %u %u %u) called\n", 03349 DeviceExtension, PathId, TargetId, Lun); 03350 03351 /* Get appropriate list */ 03352 LunExtension = DeviceExtension->LunExtensionList[(TargetId + Lun) % LUS_NUMBER]; 03353 03354 /* Iterate it until we find what we need */ 03355 while (LunExtension) 03356 { 03357 if (LunExtension->TargetId == TargetId && 03358 LunExtension->Lun == Lun && 03359 LunExtension->PathId == PathId) 03360 { 03361 /* All matches, return */ 03362 return LunExtension; 03363 } 03364 03365 /* Advance to the next item */ 03366 LunExtension = LunExtension->Next; 03367 } 03368 03369 /* We did not find anything */ 03370 DPRINT("Nothing found\n"); 03371 return NULL; 03372 } 03373 03374 static PSCSI_REQUEST_BLOCK_INFO 03375 SpiAllocateSrbStructures(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 03376 PSCSI_PORT_LUN_EXTENSION LunExtension, 03377 PSCSI_REQUEST_BLOCK Srb) 03378 { 03379 PCHAR SrbExtension; 03380 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 03381 03382 /* Spinlock must be held while this function executes */ 03383 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 03384 03385 /* Allocate SRB data structure */ 03386 if (DeviceExtension->NeedSrbDataAlloc) 03387 { 03388 /* Treat the abort request in a special way */ 03389 if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) 03390 { 03391 SrbInfo = SpiGetSrbData(DeviceExtension, 03392 Srb->PathId, 03393 Srb->TargetId, 03394 Srb->Lun, 03395 Srb->QueueTag); 03396 } 03397 else if (Srb->SrbFlags & 03398 (SRB_FLAGS_QUEUE_ACTION_ENABLE | SRB_FLAGS_NO_QUEUE_FREEZE) && 03399 !(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 03400 ) 03401 { 03402 /* Do not process tagged commands if need request sense is set */ 03403 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) 03404 { 03405 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING)); 03406 03407 LunExtension->PendingRequest = Srb->OriginalRequest; 03408 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE; 03409 03410 /* Relese the spinlock and return */ 03411 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03412 return NULL; 03413 } 03414 03415 ASSERT(LunExtension->SrbInfo.Srb == NULL); 03416 SrbInfo = DeviceExtension->FreeSrbInfo; 03417 03418 if (SrbInfo == NULL) 03419 { 03420 /* No SRB structures left in the list. We have to leave 03421 and wait while we are called again */ 03422 03423 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING; 03424 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03425 return NULL; 03426 } 03427 03428 DeviceExtension->FreeSrbInfo = (PSCSI_REQUEST_BLOCK_INFO)SrbInfo->Requests.Flink; 03429 03430 /* QueueTag must never be 0, so +1 to it */ 03431 Srb->QueueTag = (UCHAR)(SrbInfo - DeviceExtension->SrbInfo) + 1; 03432 } 03433 else 03434 { 03435 /* Usual untagged command */ 03436 if ( 03437 (!IsListEmpty(&LunExtension->SrbInfo.Requests) || 03438 LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) && 03439 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) 03440 ) 03441 { 03442 /* Mark it as pending and leave */ 03443 ASSERT(!(LunExtension->Flags & LUNEX_REQUEST_PENDING)); 03444 LunExtension->Flags |= LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE; 03445 LunExtension->PendingRequest = Srb->OriginalRequest; 03446 03447 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03448 return(NULL); 03449 } 03450 03451 Srb->QueueTag = SP_UNTAGGED; 03452 SrbInfo = &LunExtension->SrbInfo; 03453 } 03454 } 03455 else 03456 { 03457 Srb->QueueTag = SP_UNTAGGED; 03458 SrbInfo = &LunExtension->SrbInfo; 03459 } 03460 03461 /* Allocate SRB extension structure */ 03462 if (DeviceExtension->NeedSrbExtensionAlloc) 03463 { 03464 /* Check the list of free extensions */ 03465 SrbExtension = DeviceExtension->FreeSrbExtensions; 03466 03467 /* If no free extensions... */ 03468 if (SrbExtension == NULL) 03469 { 03470 /* Free SRB data */ 03471 if (Srb->Function != SRB_FUNCTION_ABORT_COMMAND && 03472 Srb->QueueTag != SP_UNTAGGED) 03473 { 03474 SrbInfo->Requests.Blink = NULL; 03475 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo; 03476 DeviceExtension->FreeSrbInfo = SrbInfo; 03477 } 03478 03479 /* Return, in order to be called again later */ 03480 DeviceExtension->Flags |= SCSI_PORT_REQUEST_PENDING; 03481 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03482 return NULL; 03483 } 03484 03485 /* Remove that free SRB extension from the list (since 03486 we're going to use it) */ 03487 DeviceExtension->FreeSrbExtensions = *((PVOID *)SrbExtension); 03488 03489 /* Spinlock can be released now */ 03490 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03491 03492 Srb->SrbExtension = SrbExtension; 03493 03494 if (Srb->SenseInfoBuffer != NULL && 03495 DeviceExtension->SupportsAutoSense) 03496 { 03497 /* Store pointer to the SenseInfo buffer */ 03498 SrbInfo->SaveSenseRequest = Srb->SenseInfoBuffer; 03499 03500 /* Does data fit the buffer? */ 03501 if (Srb->SenseInfoBufferLength > sizeof(SENSE_DATA)) 03502 { 03503 /* No, disabling autosense at all */ 03504 Srb->SrbFlags |= SRB_FLAGS_DISABLE_AUTOSENSE; 03505 } 03506 else 03507 { 03508 /* Yes, update the buffer pointer */ 03509 Srb->SenseInfoBuffer = SrbExtension + DeviceExtension->SrbExtensionSize; 03510 } 03511 } 03512 } 03513 else 03514 { 03515 /* Cleanup... */ 03516 Srb->SrbExtension = NULL; 03517 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 03518 } 03519 03520 return SrbInfo; 03521 } 03522 03523 03524 static NTSTATUS 03525 SpiSendInquiry (IN PDEVICE_OBJECT DeviceObject, 03526 IN PSCSI_LUN_INFO LunInfo) 03527 { 03528 IO_STATUS_BLOCK IoStatusBlock; 03529 PIO_STACK_LOCATION IrpStack; 03530 KEVENT Event; 03531 KIRQL Irql; 03532 PIRP Irp; 03533 NTSTATUS Status; 03534 PINQUIRYDATA InquiryBuffer; 03535 PSENSE_DATA SenseBuffer; 03536 BOOLEAN KeepTrying = TRUE; 03537 ULONG RetryCount = 0; 03538 SCSI_REQUEST_BLOCK Srb; 03539 PCDB Cdb; 03540 PSCSI_PORT_LUN_EXTENSION LunExtension; 03541 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 03542 03543 DPRINT ("SpiSendInquiry() called\n"); 03544 03545 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 03546 03547 InquiryBuffer = ExAllocatePoolWithTag (NonPagedPool, INQUIRYDATABUFFERSIZE, TAG_SCSIPORT); 03548 if (InquiryBuffer == NULL) 03549 return STATUS_INSUFFICIENT_RESOURCES; 03550 03551 SenseBuffer = ExAllocatePoolWithTag (NonPagedPool, SENSE_BUFFER_SIZE, TAG_SCSIPORT); 03552 if (SenseBuffer == NULL) 03553 { 03554 ExFreePool(InquiryBuffer); 03555 return STATUS_INSUFFICIENT_RESOURCES; 03556 } 03557 03558 while (KeepTrying) 03559 { 03560 /* Initialize event for waiting */ 03561 KeInitializeEvent(&Event, 03562 NotificationEvent, 03563 FALSE); 03564 03565 /* Create an IRP */ 03566 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_IN, 03567 DeviceObject, 03568 NULL, 03569 0, 03570 InquiryBuffer, 03571 INQUIRYDATABUFFERSIZE, 03572 TRUE, 03573 &Event, 03574 &IoStatusBlock); 03575 if (Irp == NULL) 03576 { 03577 DPRINT("IoBuildDeviceIoControlRequest() failed\n"); 03578 return STATUS_INSUFFICIENT_RESOURCES; 03579 } 03580 03581 /* Prepare SRB */ 03582 RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK)); 03583 03584 Srb.Length = sizeof(SCSI_REQUEST_BLOCK); 03585 Srb.OriginalRequest = Irp; 03586 Srb.PathId = LunInfo->PathId; 03587 Srb.TargetId = LunInfo->TargetId; 03588 Srb.Lun = LunInfo->Lun; 03589 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI; 03590 Srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 03591 Srb.TimeOutValue = 4; 03592 Srb.CdbLength = 6; 03593 03594 Srb.SenseInfoBuffer = SenseBuffer; 03595 Srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE; 03596 03597 Srb.DataBuffer = InquiryBuffer; 03598 Srb.DataTransferLength = INQUIRYDATABUFFERSIZE; 03599 03600 /* Attach Srb to the Irp */ 03601 IrpStack = IoGetNextIrpStackLocation (Irp); 03602 IrpStack->Parameters.Scsi.Srb = &Srb; 03603 03604 /* Fill in CDB */ 03605 Cdb = (PCDB)Srb.Cdb; 03606 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY; 03607 Cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun; 03608 Cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE; 03609 03610 /* Call the driver */ 03611 Status = IoCallDriver(DeviceObject, Irp); 03612 03613 /* Wait for it to complete */ 03614 if (Status == STATUS_PENDING) 03615 { 03616 DPRINT("SpiSendInquiry(): Waiting for the driver to process request...\n"); 03617 KeWaitForSingleObject(&Event, 03618 Executive, 03619 KernelMode, 03620 FALSE, 03621 NULL); 03622 Status = IoStatusBlock.Status; 03623 } 03624 03625 DPRINT("SpiSendInquiry(): Request processed by driver, status = 0x%08X\n", Status); 03626 03627 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_SUCCESS) 03628 { 03629 /* All fine, copy data over */ 03630 RtlCopyMemory(LunInfo->InquiryData, 03631 InquiryBuffer, 03632 INQUIRYDATABUFFERSIZE); 03633 03634 Status = STATUS_SUCCESS; 03635 KeepTrying = FALSE; 03636 } 03637 else 03638 { 03639 DPRINT("Inquiry SRB failed with SrbStatus 0x%08X\n", Srb.SrbStatus); 03640 /* Check if the queue is frozen */ 03641 if (Srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) 03642 { 03643 /* Something weird happened, deal with it (unfreeze the queue) */ 03644 KeepTrying = FALSE; 03645 03646 DPRINT("SpiSendInquiry(): the queue is frozen at TargetId %d\n", Srb.TargetId); 03647 03648 LunExtension = SpiGetLunExtension(DeviceExtension, 03649 LunInfo->PathId, 03650 LunInfo->TargetId, 03651 LunInfo->Lun); 03652 03653 /* Clear frozen flag */ 03654 LunExtension->Flags &= ~LUNEX_FROZEN_QUEUE; 03655 03656 /* Acquire the spinlock */ 03657 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 03658 03659 /* Process the request */ 03660 SpiGetNextRequestFromLun(DeviceObject->DeviceExtension, LunExtension); 03661 03662 /* SpiGetNextRequestFromLun() releases the spinlock, 03663 so we just lower irql back to what it was before */ 03664 KeLowerIrql(Irql); 03665 } 03666 03667 /* Check if data overrun happened */ 03668 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) 03669 { 03670 DPRINT("Data overrun at TargetId %d\n", LunInfo->TargetId); 03671 /* Nothing dramatic, just copy data, but limiting the size */ 03672 RtlCopyMemory(LunInfo->InquiryData, 03673 InquiryBuffer, 03674 (Srb.DataTransferLength > INQUIRYDATABUFFERSIZE) ? 03675 INQUIRYDATABUFFERSIZE : Srb.DataTransferLength); 03676 03677 Status = STATUS_SUCCESS; 03678 KeepTrying = FALSE; 03679 } 03680 else if ((Srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 03681 SenseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) 03682 { 03683 /* LUN is not valid, but some device responds there. 03684 Mark it as invalid anyway */ 03685 03686 Status = STATUS_INVALID_DEVICE_REQUEST; 03687 KeepTrying = FALSE; 03688 } 03689 else 03690 { 03691 /* Retry a couple of times if no timeout happened */ 03692 if ((RetryCount < 2) && 03693 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_NO_DEVICE) && 03694 (SRB_STATUS(Srb.SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT)) 03695 { 03696 RetryCount++; 03697 KeepTrying = TRUE; 03698 } 03699 else 03700 { 03701 /* That's all, go to exit */ 03702 KeepTrying = FALSE; 03703 03704 /* Set status according to SRB status */ 03705 if (SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_FUNCTION || 03706 SRB_STATUS(Srb.SrbStatus) == SRB_STATUS_BAD_SRB_BLOCK_LENGTH) 03707 { 03708 Status = STATUS_INVALID_DEVICE_REQUEST; 03709 } 03710 else 03711 { 03712 Status = STATUS_IO_DEVICE_ERROR; 03713 } 03714 } 03715 } 03716 } 03717 } 03718 03719 /* Free buffers */ 03720 ExFreePool(InquiryBuffer); 03721 ExFreePool(SenseBuffer); 03722 03723 DPRINT("SpiSendInquiry() done with Status 0x%08X\n", Status); 03724 03725 return Status; 03726 } 03727 03728 03729 /* Scans all SCSI buses */ 03730 static VOID 03731 SpiScanAdapter(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension) 03732 { 03733 PSCSI_PORT_LUN_EXTENSION LunExtension; 03734 ULONG Bus; 03735 ULONG Target; 03736 ULONG Lun; 03737 PSCSI_BUS_SCAN_INFO BusScanInfo; 03738 PSCSI_LUN_INFO LastLunInfo, LunInfo, LunInfoExists; 03739 BOOLEAN DeviceExists; 03740 ULONG Hint; 03741 NTSTATUS Status; 03742 ULONG DevicesFound; 03743 03744 DPRINT("SpiScanAdapter() called\n"); 03745 03746 /* Scan all buses */ 03747 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) 03748 { 03749 DPRINT(" Scanning bus %d\n", Bus); 03750 DevicesFound = 0; 03751 03752 /* Get pointer to the scan information */ 03753 BusScanInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]; 03754 03755 if (BusScanInfo) 03756 { 03757 /* Find the last LUN info in the list */ 03758 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo; 03759 LastLunInfo = LunInfo; 03760 03761 while (LunInfo != NULL) 03762 { 03763 LastLunInfo = LunInfo; 03764 LunInfo = LunInfo->Next; 03765 } 03766 } 03767 else 03768 { 03769 /* We need to allocate this buffer */ 03770 BusScanInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_BUS_SCAN_INFO), TAG_SCSIPORT); 03771 03772 if (!BusScanInfo) 03773 { 03774 DPRINT1("Out of resources!\n"); 03775 return; 03776 } 03777 03778 /* Store the pointer in the BusScanInfo array */ 03779 DeviceExtension->BusesConfig->BusScanInfo[Bus] = BusScanInfo; 03780 03781 /* Fill this struct (length and bus ids for now) */ 03782 BusScanInfo->Length = sizeof(SCSI_BUS_SCAN_INFO); 03783 BusScanInfo->LogicalUnitsCount = 0; 03784 BusScanInfo->BusIdentifier = DeviceExtension->PortConfig->InitiatorBusId[Bus]; 03785 BusScanInfo->LunInfo = NULL; 03786 03787 /* Set pointer to the last LUN info to NULL */ 03788 LastLunInfo = NULL; 03789 } 03790 03791 /* Create LUN information structure */ 03792 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT); 03793 03794 if (LunInfo == NULL) 03795 { 03796 DPRINT1("Out of resources!\n"); 03797 return; 03798 } 03799 03800 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO)); 03801 03802 /* Create LunExtension */ 03803 LunExtension = SpiAllocateLunExtension (DeviceExtension); 03804 03805 /* And send INQUIRY to every target */ 03806 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++) 03807 { 03808 /* TODO: Support scan bottom-up */ 03809 03810 /* Skip if it's the same address */ 03811 if (Target == BusScanInfo->BusIdentifier) 03812 continue; 03813 03814 /* Try to find an existing device here */ 03815 DeviceExists = FALSE; 03816 LunInfoExists = BusScanInfo->LunInfo; 03817 03818 /* Find matching address on this bus */ 03819 while (LunInfoExists) 03820 { 03821 if (LunInfoExists->TargetId == Target) 03822 { 03823 DeviceExists = TRUE; 03824 break; 03825 } 03826 03827 /* Advance to the next one */ 03828 LunInfoExists = LunInfoExists->Next; 03829 } 03830 03831 /* No need to bother rescanning, since we already did that before */ 03832 if (DeviceExists) 03833 continue; 03834 03835 /* Scan all logical units */ 03836 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++) 03837 { 03838 if ((!LunExtension) || (!LunInfo)) 03839 break; 03840 03841 /* Add extension to the list */ 03842 Hint = (Target + Lun) % LUS_NUMBER; 03843 LunExtension->Next = DeviceExtension->LunExtensionList[Hint]; 03844 DeviceExtension->LunExtensionList[Hint] = LunExtension; 03845 03846 /* Fill Path, Target, Lun fields */ 03847 LunExtension->PathId = LunInfo->PathId = (UCHAR)Bus; 03848 LunExtension->TargetId = LunInfo->TargetId = (UCHAR) Target; 03849 LunExtension->Lun = LunInfo->Lun = (UCHAR)Lun; 03850 03851 /* Set flag to prevent race conditions */ 03852 LunExtension->Flags |= SCSI_PORT_SCAN_IN_PROGRESS; 03853 03854 /* Zero LU extension contents */ 03855 if (DeviceExtension->LunExtensionSize) 03856 { 03857 RtlZeroMemory(LunExtension + 1, 03858 DeviceExtension->LunExtensionSize); 03859 } 03860 03861 /* Finally send the inquiry command */ 03862 Status = SpiSendInquiry(DeviceExtension->DeviceObject, LunInfo); 03863 03864 if (NT_SUCCESS(Status)) 03865 { 03866 /* Let's see if we really found a device */ 03867 PINQUIRYDATA InquiryData = (PINQUIRYDATA)LunInfo->InquiryData; 03868 03869 /* Check if this device is unsupported */ 03870 if (InquiryData->DeviceTypeQualifier == DEVICE_QUALIFIER_NOT_SUPPORTED) 03871 { 03872 DeviceExtension->LunExtensionList[Hint] = 03873 DeviceExtension->LunExtensionList[Hint]->Next; 03874 03875 continue; 03876 } 03877 03878 /* Clear the "in scan" flag */ 03879 LunExtension->Flags &= ~SCSI_PORT_SCAN_IN_PROGRESS; 03880 03881 DPRINT("SpiScanAdapter(): Found device of type %d at bus %d tid %d lun %d\n", 03882 InquiryData->DeviceType, Bus, Target, Lun); 03883 03884 /* Add this info to the linked list */ 03885 LunInfo->Next = NULL; 03886 if (LastLunInfo) 03887 LastLunInfo->Next = LunInfo; 03888 else 03889 BusScanInfo->LunInfo = LunInfo; 03890 03891 /* Store the last LUN info */ 03892 LastLunInfo = LunInfo; 03893 03894 /* Store DeviceObject */ 03895 LunInfo->DeviceObject = DeviceExtension->DeviceObject; 03896 03897 /* Allocate another buffer */ 03898 LunInfo = ExAllocatePoolWithTag(PagedPool, sizeof(SCSI_LUN_INFO), TAG_SCSIPORT); 03899 03900 if (!LunInfo) 03901 { 03902 DPRINT1("Out of resources!\n"); 03903 break; 03904 } 03905 03906 RtlZeroMemory(LunInfo, sizeof(SCSI_LUN_INFO)); 03907 03908 /* Create a new LU extension */ 03909 LunExtension = SpiAllocateLunExtension(DeviceExtension); 03910 03911 DevicesFound++; 03912 } 03913 else 03914 { 03915 /* Remove this LUN from the list */ 03916 DeviceExtension->LunExtensionList[Hint] = 03917 DeviceExtension->LunExtensionList[Hint]->Next; 03918 03919 /* Decide whether we are continuing or not */ 03920 if (Status == STATUS_INVALID_DEVICE_REQUEST) 03921 continue; 03922 else 03923 break; 03924 } 03925 } 03926 } 03927 03928 /* Free allocated buffers */ 03929 if (LunExtension) 03930 ExFreePool(LunExtension); 03931 03932 if (LunInfo) 03933 ExFreePool(LunInfo); 03934 03935 /* Sum what we found */ 03936 BusScanInfo->LogicalUnitsCount += (UCHAR) DevicesFound; 03937 DPRINT(" Found %d devices on bus %d\n", DevicesFound, Bus); 03938 } 03939 03940 DPRINT ("SpiScanAdapter() done\n"); 03941 } 03942 03943 03944 static NTSTATUS 03945 SpiGetInquiryData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 03946 PIRP Irp) 03947 { 03948 ULONG InquiryDataSize; 03949 PSCSI_LUN_INFO LunInfo; 03950 ULONG BusCount, LunCount, Length; 03951 PIO_STACK_LOCATION IrpStack; 03952 PSCSI_ADAPTER_BUS_INFO AdapterBusInfo; 03953 PSCSI_INQUIRY_DATA InquiryData; 03954 PSCSI_BUS_DATA BusData; 03955 ULONG Bus; 03956 PUCHAR Buffer; 03957 03958 DPRINT("SpiGetInquiryData() called\n"); 03959 03960 /* Get pointer to the buffer */ 03961 IrpStack = IoGetCurrentIrpStackLocation(Irp); 03962 Buffer = Irp->AssociatedIrp.SystemBuffer; 03963 03964 /* Initialize bus and LUN counters */ 03965 BusCount = DeviceExtension->BusesConfig->NumberOfBuses; 03966 LunCount = 0; 03967 03968 /* Calculate total number of LUNs */ 03969 for (Bus = 0; Bus < BusCount; Bus++) 03970 LunCount += DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount; 03971 03972 /* Calculate size of inquiry data, rounding up to sizeof(ULONG) */ 03973 InquiryDataSize = 03974 ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE + 03975 sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1)); 03976 03977 /* Calculate data size */ 03978 Length = sizeof(SCSI_ADAPTER_BUS_INFO) + (BusCount - 1) * 03979 sizeof(SCSI_BUS_DATA); 03980 03981 Length += InquiryDataSize * LunCount; 03982 03983 /* Check, if all data is going to fit into provided buffer */ 03984 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < Length) 03985 { 03986 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 03987 return STATUS_BUFFER_TOO_SMALL; 03988 } 03989 03990 /* Store data size in the IRP */ 03991 Irp->IoStatus.Information = Length; 03992 03993 DPRINT("Data size: %lu\n", Length); 03994 03995 AdapterBusInfo = (PSCSI_ADAPTER_BUS_INFO)Buffer; 03996 03997 AdapterBusInfo->NumberOfBuses = (UCHAR)BusCount; 03998 03999 /* Point InquiryData to the corresponding place inside Buffer */ 04000 InquiryData = (PSCSI_INQUIRY_DATA)(Buffer + sizeof(SCSI_ADAPTER_BUS_INFO) + 04001 (BusCount - 1) * sizeof(SCSI_BUS_DATA)); 04002 04003 /* Loop each bus */ 04004 for (Bus = 0; Bus < BusCount; Bus++) 04005 { 04006 BusData = &AdapterBusInfo->BusData[Bus]; 04007 04008 /* Calculate and save an offset of the inquiry data */ 04009 BusData->InquiryDataOffset = (PUCHAR)InquiryData - Buffer; 04010 04011 /* Get a pointer to the LUN information structure */ 04012 LunInfo = DeviceExtension->BusesConfig->BusScanInfo[Bus]->LunInfo; 04013 04014 /* Store Initiator Bus Id */ 04015 BusData->InitiatorBusId = 04016 DeviceExtension->BusesConfig->BusScanInfo[Bus]->BusIdentifier; 04017 04018 /* Store LUN count */ 04019 BusData->NumberOfLogicalUnits = 04020 DeviceExtension->BusesConfig->BusScanInfo[Bus]->LogicalUnitsCount; 04021 04022 /* Loop all LUNs */ 04023 while (LunInfo != NULL) 04024 { 04025 DPRINT("(Bus %lu Target %lu Lun %lu)\n", 04026 Bus, LunInfo->TargetId, LunInfo->Lun); 04027 04028 /* Fill InquiryData with values */ 04029 InquiryData->PathId = LunInfo->PathId; 04030 InquiryData->TargetId = LunInfo->TargetId; 04031 InquiryData->Lun = LunInfo->Lun; 04032 InquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE; 04033 InquiryData->DeviceClaimed = LunInfo->DeviceClaimed; 04034 InquiryData->NextInquiryDataOffset = 04035 (PUCHAR)InquiryData + InquiryDataSize - Buffer; 04036 04037 /* Copy data in it */ 04038 RtlCopyMemory(InquiryData->InquiryData, 04039 LunInfo->InquiryData, 04040 INQUIRYDATABUFFERSIZE); 04041 04042 /* Move to the next LUN */ 04043 LunInfo = LunInfo->Next; 04044 InquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR)InquiryData + InquiryDataSize); 04045 } 04046 04047 /* Either mark the end, or set offset to 0 */ 04048 if (BusData->NumberOfLogicalUnits != 0) 04049 ((PSCSI_INQUIRY_DATA) ((PCHAR) InquiryData - InquiryDataSize))->NextInquiryDataOffset = 0; 04050 else 04051 BusData->InquiryDataOffset = 0; 04052 } 04053 04054 /* Finish with success */ 04055 Irp->IoStatus.Status = STATUS_SUCCESS; 04056 return STATUS_SUCCESS; 04057 } 04058 04059 static PSCSI_REQUEST_BLOCK_INFO 04060 SpiGetSrbData(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 04061 IN UCHAR PathId, 04062 IN UCHAR TargetId, 04063 IN UCHAR Lun, 04064 IN UCHAR QueueTag) 04065 { 04066 PSCSI_PORT_LUN_EXTENSION LunExtension; 04067 04068 if (QueueTag == SP_UNTAGGED) 04069 { 04070 /* Untagged request, get LU and return pointer to SrbInfo */ 04071 LunExtension = SpiGetLunExtension(DeviceExtension, 04072 PathId, 04073 TargetId, 04074 Lun); 04075 04076 /* Return NULL in case of error */ 04077 if (!LunExtension) 04078 return(NULL); 04079 04080 /* Return the pointer to SrbInfo */ 04081 return &LunExtension->SrbInfo; 04082 } 04083 else 04084 { 04085 /* Make sure the tag is valid, if it is - return the data */ 04086 if (QueueTag > DeviceExtension->SrbDataCount || QueueTag < 1) 04087 return NULL; 04088 else 04089 return &DeviceExtension->SrbInfo[QueueTag -1]; 04090 } 04091 } 04092 04093 static VOID 04094 SpiSendRequestSense(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 04095 IN PSCSI_REQUEST_BLOCK InitialSrb) 04096 { 04097 PSCSI_REQUEST_BLOCK Srb; 04098 PCDB Cdb; 04099 PIRP Irp; 04100 PIO_STACK_LOCATION IrpStack; 04101 LARGE_INTEGER LargeInt; 04102 PVOID *Ptr; 04103 04104 DPRINT("SpiSendRequestSense() entered, InitialSrb %p\n", InitialSrb); 04105 04106 /* Allocate Srb */ 04107 Srb = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID), TAG_SCSIPORT); 04108 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK)); 04109 04110 /* Allocate IRP */ 04111 LargeInt.QuadPart = (LONGLONG) 1; 04112 Irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ, 04113 DeviceExtension->DeviceObject, 04114 InitialSrb->SenseInfoBuffer, 04115 InitialSrb->SenseInfoBufferLength, 04116 &LargeInt, 04117 NULL); 04118 04119 IoSetCompletionRoutine(Irp, 04120 (PIO_COMPLETION_ROUTINE)SpiCompletionRoutine, 04121 Srb, 04122 TRUE, 04123 TRUE, 04124 TRUE); 04125 04126 if (!Srb) 04127 { 04128 DPRINT("SpiSendRequestSense() failed, Srb %p\n", Srb); 04129 return; 04130 } 04131 04132 IrpStack = IoGetNextIrpStackLocation(Irp); 04133 IrpStack->MajorFunction = IRP_MJ_SCSI; 04134 04135 /* Put Srb address into Irp... */ 04136 IrpStack->Parameters.Others.Argument1 = (PVOID)Srb; 04137 04138 /* ...and vice versa */ 04139 Srb->OriginalRequest = Irp; 04140 04141 /* Save Srb */ 04142 Ptr = (PVOID *)(Srb+1); 04143 *Ptr = InitialSrb; 04144 04145 /* Build CDB for REQUEST SENSE */ 04146 Srb->CdbLength = 6; 04147 Cdb = (PCDB)Srb->Cdb; 04148 04149 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE; 04150 Cdb->CDB6INQUIRY.LogicalUnitNumber = 0; 04151 Cdb->CDB6INQUIRY.Reserved1 = 0; 04152 Cdb->CDB6INQUIRY.PageCode = 0; 04153 Cdb->CDB6INQUIRY.IReserved = 0; 04154 Cdb->CDB6INQUIRY.AllocationLength = (UCHAR)InitialSrb->SenseInfoBufferLength; 04155 Cdb->CDB6INQUIRY.Control = 0; 04156 04157 /* Set address */ 04158 Srb->TargetId = InitialSrb->TargetId; 04159 Srb->Lun = InitialSrb->Lun; 04160 Srb->PathId = InitialSrb->PathId; 04161 04162 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 04163 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 04164 04165 /* Timeout will be 2 seconds */ 04166 Srb->TimeOutValue = 2; 04167 04168 /* No auto request sense */ 04169 Srb->SenseInfoBufferLength = 0; 04170 Srb->SenseInfoBuffer = NULL; 04171 04172 /* Set necessary flags */ 04173 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE | 04174 SRB_FLAGS_DISABLE_DISCONNECT; 04175 04176 /* Transfer disable synch transfer flag */ 04177 if (InitialSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) 04178 Srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 04179 04180 Srb->DataBuffer = InitialSrb->SenseInfoBuffer; 04181 04182 /* Fill the transfer length */ 04183 Srb->DataTransferLength = InitialSrb->SenseInfoBufferLength; 04184 04185 /* Clear statuses */ 04186 Srb->ScsiStatus = Srb->SrbStatus = 0; 04187 Srb->NextSrb = 0; 04188 04189 /* Call the driver */ 04190 (VOID)IoCallDriver(DeviceExtension->DeviceObject, Irp); 04191 04192 DPRINT("SpiSendRequestSense() done\n"); 04193 } 04194 04195 04196 static 04197 VOID 04198 NTAPI 04199 SpiProcessCompletedRequest(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 04200 IN PSCSI_REQUEST_BLOCK_INFO SrbInfo, 04201 OUT PBOOLEAN NeedToCallStartIo) 04202 { 04203 PSCSI_REQUEST_BLOCK Srb; 04204 PSCSI_PORT_LUN_EXTENSION LunExtension; 04205 LONG Result; 04206 PIRP Irp; 04207 //ULONG SequenceNumber; 04208 04209 Srb = SrbInfo->Srb; 04210 Irp = Srb->OriginalRequest; 04211 04212 /* Get Lun extension */ 04213 LunExtension = SpiGetLunExtension(DeviceExtension, 04214 Srb->PathId, 04215 Srb->TargetId, 04216 Srb->Lun); 04217 04218 if (Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION && 04219 DeviceExtension->MapBuffers && 04220 Irp->MdlAddress) 04221 { 04222 /* MDL is shared if transfer is broken into smaller parts */ 04223 Srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress) + 04224 ((PCCHAR)Srb->DataBuffer - SrbInfo->DataOffset); 04225 04226 /* In case of data going in, flush the buffers */ 04227 if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) 04228 { 04229 KeFlushIoBuffers(Irp->MdlAddress, 04230 TRUE, 04231 FALSE); 04232 } 04233 } 04234 04235 /* Flush adapter if needed */ 04236 if (SrbInfo->BaseOfMapRegister) 04237 { 04238 /* TODO: Implement */ 04239 ASSERT(FALSE); 04240 } 04241 04242 /* Clear the request */ 04243 SrbInfo->Srb = NULL; 04244 04245 /* If disconnect is disabled... */ 04246 if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) 04247 { 04248 /* Acquire the spinlock since we mess with flags */ 04249 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 04250 04251 /* Set corresponding flag */ 04252 DeviceExtension->Flags |= SCSI_PORT_DISCONNECT_ALLOWED; 04253 04254 /* Clear the timer if needed */ 04255 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET)) 04256 DeviceExtension->TimerCount = -1; 04257 04258 /* Spinlock is not needed anymore */ 04259 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04260 04261 if (!(DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) && 04262 !(DeviceExtension->Flags & SCSI_PORT_DEVICE_BUSY) && 04263 !(*NeedToCallStartIo)) 04264 { 04265 /* We're not busy, but we have a request pending */ 04266 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE); 04267 } 04268 } 04269 04270 /* Scatter/gather */ 04271 if (Srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL) 04272 { 04273 /* TODO: Implement */ 04274 ASSERT(FALSE); 04275 } 04276 04277 /* Acquire spinlock (we're freeing SrbExtension) */ 04278 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 04279 04280 /* Free it (if needed) */ 04281 if (Srb->SrbExtension) 04282 { 04283 if (Srb->SenseInfoBuffer != NULL && DeviceExtension->SupportsAutoSense) 04284 { 04285 ASSERT(Srb->SenseInfoBuffer == NULL || SrbInfo->SaveSenseRequest != NULL); 04286 04287 if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) 04288 { 04289 /* Copy sense data to the buffer */ 04290 RtlCopyMemory(SrbInfo->SaveSenseRequest, 04291 Srb->SenseInfoBuffer, 04292 Srb->SenseInfoBufferLength); 04293 } 04294 04295 /* And restore the pointer */ 04296 Srb->SenseInfoBuffer = SrbInfo->SaveSenseRequest; 04297 } 04298 04299 /* Put it into the free srb extensions list */ 04300 *((PVOID *)Srb->SrbExtension) = DeviceExtension->FreeSrbExtensions; 04301 DeviceExtension->FreeSrbExtensions = Srb->SrbExtension; 04302 } 04303 04304 /* Save transfer length in the IRP */ 04305 Irp->IoStatus.Information = Srb->DataTransferLength; 04306 04307 //SequenceNumber = SrbInfo->SequenceNumber; 04308 SrbInfo->SequenceNumber = 0; 04309 04310 /* Decrement the queue count */ 04311 LunExtension->QueueCount--; 04312 04313 /* Free Srb, if needed*/ 04314 if (Srb->QueueTag != SP_UNTAGGED) 04315 { 04316 /* Put it into the free list */ 04317 SrbInfo->Requests.Blink = NULL; 04318 SrbInfo->Requests.Flink = (PLIST_ENTRY)DeviceExtension->FreeSrbInfo; 04319 DeviceExtension->FreeSrbInfo = SrbInfo; 04320 } 04321 04322 /* SrbInfo is not used anymore */ 04323 SrbInfo = NULL; 04324 04325 if (DeviceExtension->Flags & SCSI_PORT_REQUEST_PENDING) 04326 { 04327 /* Clear the flag */ 04328 DeviceExtension->Flags &= ~SCSI_PORT_REQUEST_PENDING; 04329 04330 /* Note the caller about StartIo */ 04331 *NeedToCallStartIo = TRUE; 04332 } 04333 04334 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) 04335 { 04336 /* Start the packet */ 04337 Irp->IoStatus.Status = STATUS_SUCCESS; 04338 04339 if (!(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) && 04340 LunExtension->RequestTimeout == -1) 04341 { 04342 /* Start the next packet */ 04343 SpiGetNextRequestFromLun(DeviceExtension, LunExtension); 04344 } 04345 else 04346 { 04347 /* Release the spinlock */ 04348 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04349 } 04350 04351 DPRINT("IoCompleting request IRP 0x%p\n", Irp); 04352 04353 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 04354 04355 /* Decrement number of active requests, and analyze the result */ 04356 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter); 04357 04358 if (Result < 0 && 04359 !DeviceExtension->MapRegisters && 04360 DeviceExtension->AdapterObject != NULL) 04361 { 04362 /* Nullify map registers */ 04363 DeviceExtension->MapRegisterBase = NULL; 04364 IoFreeAdapterChannel(DeviceExtension->AdapterObject); 04365 } 04366 04367 /* Exit, we're done */ 04368 return; 04369 } 04370 04371 /* Decrement number of active requests, and analyze the result */ 04372 Result = InterlockedDecrement(&DeviceExtension->ActiveRequestCounter); 04373 04374 if (Result < 0 && 04375 !DeviceExtension->MapRegisters && 04376 DeviceExtension->AdapterObject != NULL) 04377 { 04378 /* Result is negative, so this is a slave, free map registers */ 04379 DeviceExtension->MapRegisterBase = NULL; 04380 IoFreeAdapterChannel(DeviceExtension->AdapterObject); 04381 } 04382 04383 /* Convert status */ 04384 Irp->IoStatus.Status = SpiStatusSrbToNt(Srb->SrbStatus); 04385 04386 /* It's not a bypass, it's busy or the queue is full? */ 04387 if ((Srb->ScsiStatus == SCSISTAT_BUSY || 04388 Srb->SrbStatus == SRB_STATUS_BUSY || 04389 Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) && 04390 !(Srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)) 04391 { 04392 04393 DPRINT("Busy SRB status %x\n", Srb->SrbStatus); 04394 04395 /* Requeu, if needed */ 04396 if (LunExtension->Flags & (LUNEX_FROZEN_QUEUE | LUNEX_BUSY)) 04397 { 04398 DPRINT("it's being requeued\n"); 04399 04400 Srb->SrbStatus = SRB_STATUS_PENDING; 04401 Srb->ScsiStatus = 0; 04402 04403 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue, 04404 &Irp->Tail.Overlay.DeviceQueueEntry, 04405 Srb->QueueSortKey)) 04406 { 04407 /* It's a big f.ck up if we got here */ 04408 Srb->SrbStatus = SRB_STATUS_ERROR; 04409 Srb->ScsiStatus = SCSISTAT_BUSY; 04410 04411 ASSERT(FALSE); 04412 goto Error; 04413 } 04414 04415 /* Release the spinlock */ 04416 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04417 04418 } 04419 else if (LunExtension->AttemptCount++ < 20) 04420 { 04421 /* LUN is still busy */ 04422 Srb->ScsiStatus = 0; 04423 Srb->SrbStatus = SRB_STATUS_PENDING; 04424 04425 LunExtension->BusyRequest = Irp; 04426 LunExtension->Flags |= LUNEX_BUSY; 04427 04428 /* Release the spinlock */ 04429 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04430 } 04431 else 04432 { 04433 Error: 04434 /* Freeze the queue*/ 04435 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN; 04436 LunExtension->Flags |= LUNEX_FROZEN_QUEUE; 04437 04438 /* "Unfull" the queue */ 04439 LunExtension->Flags &= ~LUNEX_FULL_QUEUE; 04440 04441 /* Release the spinlock */ 04442 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04443 04444 /* Return status that the device is not ready */ 04445 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY; 04446 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 04447 } 04448 04449 return; 04450 } 04451 04452 /* Start the next request, if LUN is idle, and this is sense request */ 04453 if (((Srb->ScsiStatus != SCSISTAT_CHECK_CONDITION) || 04454 (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) || 04455 !Srb->SenseInfoBuffer || !Srb->SenseInfoBufferLength) 04456 && (Srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE)) 04457 { 04458 if (LunExtension->RequestTimeout == -1) 04459 SpiGetNextRequestFromLun(DeviceExtension, LunExtension); 04460 else 04461 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04462 } 04463 else 04464 { 04465 /* Freeze the queue */ 04466 Srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN; 04467 LunExtension->Flags |= LUNEX_FROZEN_QUEUE; 04468 04469 /* Do we need a request sense? */ 04470 if (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION && 04471 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 04472 Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength) 04473 { 04474 /* If LUN is busy, we have to requeue it in order to allow request sense */ 04475 if (LunExtension->Flags & LUNEX_BUSY) 04476 { 04477 DPRINT("Requeueing busy request to allow request sense\n"); 04478 04479 if (!KeInsertByKeyDeviceQueue(&LunExtension->DeviceQueue, 04480 &LunExtension->BusyRequest->Tail.Overlay.DeviceQueueEntry, 04481 Srb->QueueSortKey)) 04482 { 04483 /* We should never get here */ 04484 ASSERT(FALSE); 04485 04486 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04487 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 04488 return; 04489 04490 } 04491 04492 /* Clear busy flags */ 04493 LunExtension->Flags &= ~(LUNEX_FULL_QUEUE | LUNEX_BUSY); 04494 } 04495 04496 /* Release the spinlock */ 04497 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04498 04499 /* Send RequestSense */ 04500 SpiSendRequestSense(DeviceExtension, Srb); 04501 04502 /* Exit */ 04503 return; 04504 } 04505 04506 /* Release the spinlock */ 04507 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04508 } 04509 04510 /* Complete the request */ 04511 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 04512 } 04513 04514 NTSTATUS 04515 NTAPI 04516 SpiCompletionRoutine(PDEVICE_OBJECT DeviceObject, 04517 PIRP Irp, 04518 PVOID Context) 04519 { 04520 PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)Context; 04521 PSCSI_REQUEST_BLOCK InitialSrb; 04522 PIRP InitialIrp; 04523 04524 DPRINT("SpiCompletionRoutine() entered, IRP %p \n", Irp); 04525 04526 if ((Srb->Function == SRB_FUNCTION_RESET_BUS) || 04527 (Srb->Function == SRB_FUNCTION_ABORT_COMMAND)) 04528 { 04529 /* Deallocate SRB and IRP and exit */ 04530 ExFreePool(Srb); 04531 IoFreeIrp(Irp); 04532 04533 return STATUS_MORE_PROCESSING_REQUIRED; 04534 } 04535 04536 /* Get a pointer to the SRB and IRP which were initially sent */ 04537 InitialSrb = *((PVOID *)(Srb+1)); 04538 InitialIrp = InitialSrb->OriginalRequest; 04539 04540 if ((SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) || 04541 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) 04542 { 04543 /* Sense data is OK */ 04544 InitialSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; 04545 04546 /* Set length to be the same */ 04547 InitialSrb->SenseInfoBufferLength = (UCHAR)Srb->DataTransferLength; 04548 } 04549 04550 /* Make sure initial SRB's queue is frozen */ 04551 ASSERT(InitialSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN); 04552 04553 /* Complete this request */ 04554 IoCompleteRequest(InitialIrp, IO_DISK_INCREMENT); 04555 04556 /* Deallocate everything (internal) */ 04557 ExFreePool(Srb); 04558 04559 if (Irp->MdlAddress != NULL) 04560 { 04561 MmUnlockPages(Irp->MdlAddress); 04562 IoFreeMdl(Irp->MdlAddress); 04563 Irp->MdlAddress = NULL; 04564 } 04565 04566 IoFreeIrp(Irp); 04567 return STATUS_MORE_PROCESSING_REQUIRED; 04568 } 04569 04570 static BOOLEAN NTAPI 04571 ScsiPortIsr(IN PKINTERRUPT Interrupt, 04572 IN PVOID ServiceContext) 04573 { 04574 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 04575 04576 DPRINT("ScsiPortIsr() called!\n"); 04577 04578 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext; 04579 04580 /* If interrupts are disabled - we don't expect any */ 04581 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_DISABLE_INTERRUPTS) 04582 return FALSE; 04583 04584 /* Call miniport's HwInterrupt routine */ 04585 DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension); 04586 04587 /* If flag of notification is set - queue a DPC */ 04588 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 04589 { 04590 IoRequestDpc(DeviceExtension->DeviceObject, 04591 DeviceExtension->CurrentIrp, 04592 DeviceExtension); 04593 } 04594 04595 return TRUE; 04596 } 04597 04598 BOOLEAN 04599 NTAPI 04600 SpiSaveInterruptData(IN PVOID Context) 04601 { 04602 PSCSI_PORT_SAVE_INTERRUPT InterruptContext = Context; 04603 PSCSI_PORT_LUN_EXTENSION LunExtension; 04604 PSCSI_REQUEST_BLOCK Srb; 04605 PSCSI_REQUEST_BLOCK_INFO SrbInfo, NextSrbInfo; 04606 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 04607 BOOLEAN IsTimed; 04608 04609 /* Get pointer to the device extension */ 04610 DeviceExtension = InterruptContext->DeviceExtension; 04611 04612 /* If we don't have anything pending - return */ 04613 if (!(DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED)) 04614 return FALSE; 04615 04616 /* Actually save the interrupt data */ 04617 *InterruptContext->InterruptData = DeviceExtension->InterruptData; 04618 04619 /* Clear the data stored in the device extension */ 04620 DeviceExtension->InterruptData.Flags &= 04621 (SCSI_PORT_RESET | SCSI_PORT_RESET_REQUEST | SCSI_PORT_DISABLE_INTERRUPTS); 04622 DeviceExtension->InterruptData.CompletedAbort = NULL; 04623 DeviceExtension->InterruptData.ReadyLun = NULL; 04624 DeviceExtension->InterruptData.CompletedRequests = NULL; 04625 04626 /* Loop through the list of completed requests */ 04627 SrbInfo = InterruptContext->InterruptData->CompletedRequests; 04628 04629 while (SrbInfo) 04630 { 04631 /* Make sure we have SRV */ 04632 ASSERT(SrbInfo->Srb); 04633 04634 /* Get SRB and LunExtension */ 04635 Srb = SrbInfo->Srb; 04636 04637 LunExtension = SpiGetLunExtension(DeviceExtension, 04638 Srb->PathId, 04639 Srb->TargetId, 04640 Srb->Lun); 04641 04642 /* We have to check special cases if request is unsuccessfull*/ 04643 if (Srb->SrbStatus != SRB_STATUS_SUCCESS) 04644 { 04645 /* Check if we need request sense by a few conditions */ 04646 if (Srb->SenseInfoBuffer && Srb->SenseInfoBufferLength && 04647 Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION && 04648 !(Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID)) 04649 { 04650 if (LunExtension->Flags & LUNEX_NEED_REQUEST_SENSE) 04651 { 04652 /* It means: we tried to send REQUEST SENSE, but failed */ 04653 04654 Srb->ScsiStatus = 0; 04655 Srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED; 04656 } 04657 else 04658 { 04659 /* Set the corresponding flag, so that REQUEST SENSE 04660 will be sent */ 04661 LunExtension->Flags |= LUNEX_NEED_REQUEST_SENSE; 04662 } 04663 04664 } 04665 04666 /* Check for a full queue */ 04667 if (Srb->ScsiStatus == SCSISTAT_QUEUE_FULL) 04668 { 04669 /* TODO: Implement when it's encountered */ 04670 ASSERT(FALSE); 04671 } 04672 } 04673 04674 /* Let's decide if we need to watch timeout or not */ 04675 if (Srb->QueueTag == SP_UNTAGGED) 04676 { 04677 IsTimed = TRUE; 04678 } 04679 else 04680 { 04681 if (LunExtension->SrbInfo.Requests.Flink == &SrbInfo->Requests) 04682 IsTimed = TRUE; 04683 else 04684 IsTimed = FALSE; 04685 04686 /* Remove it from the queue */ 04687 RemoveEntryList(&SrbInfo->Requests); 04688 } 04689 04690 if (IsTimed) 04691 { 04692 /* We have to maintain timeout counter */ 04693 if (IsListEmpty(&LunExtension->SrbInfo.Requests)) 04694 { 04695 LunExtension->RequestTimeout = -1; 04696 } 04697 else 04698 { 04699 NextSrbInfo = CONTAINING_RECORD(LunExtension->SrbInfo.Requests.Flink, 04700 SCSI_REQUEST_BLOCK_INFO, 04701 Requests); 04702 04703 Srb = NextSrbInfo->Srb; 04704 04705 /* Update timeout counter */ 04706 LunExtension->RequestTimeout = Srb->TimeOutValue; 04707 } 04708 } 04709 04710 SrbInfo = SrbInfo->CompletedRequests; 04711 } 04712 04713 return TRUE; 04714 } 04715 04716 VOID 04717 NTAPI 04718 SpiGetNextRequestFromLun(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 04719 IN PSCSI_PORT_LUN_EXTENSION LunExtension) 04720 { 04721 PIO_STACK_LOCATION IrpStack; 04722 PIRP NextIrp; 04723 PKDEVICE_QUEUE_ENTRY Entry; 04724 PSCSI_REQUEST_BLOCK Srb; 04725 04726 04727 /* If LUN is not active or queue is more than maximum allowed */ 04728 if (LunExtension->QueueCount >= LunExtension->MaxQueueCount || 04729 !(LunExtension->Flags & SCSI_PORT_LU_ACTIVE)) 04730 { 04731 /* Release the spinlock and exit */ 04732 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04733 return; 04734 } 04735 04736 /* Check if we can get a next request */ 04737 if (LunExtension->Flags & 04738 (LUNEX_NEED_REQUEST_SENSE | LUNEX_BUSY | 04739 LUNEX_FULL_QUEUE | LUNEX_FROZEN_QUEUE | LUNEX_REQUEST_PENDING)) 04740 { 04741 /* Pending requests can only be started if the queue is empty */ 04742 if (IsListEmpty(&LunExtension->SrbInfo.Requests) && 04743 !(LunExtension->Flags & 04744 (LUNEX_BUSY | LUNEX_FROZEN_QUEUE | LUNEX_FULL_QUEUE | LUNEX_NEED_REQUEST_SENSE))) 04745 { 04746 /* Make sure we have SRB */ 04747 ASSERT(LunExtension->SrbInfo.Srb == NULL); 04748 04749 /* Clear active and pending flags */ 04750 LunExtension->Flags &= ~(LUNEX_REQUEST_PENDING | SCSI_PORT_LU_ACTIVE); 04751 04752 /* Get next Irp, and clear pending requests list */ 04753 NextIrp = LunExtension->PendingRequest; 04754 LunExtension->PendingRequest = NULL; 04755 04756 /* Set attempt counter to zero */ 04757 LunExtension->AttemptCount = 0; 04758 04759 /* Release the spinlock */ 04760 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04761 04762 /* Start the next pending request */ 04763 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL); 04764 04765 return; 04766 } 04767 else 04768 { 04769 /* Release the spinlock, without clearing any flags and exit */ 04770 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04771 04772 return; 04773 } 04774 } 04775 04776 /* Reset active flag */ 04777 LunExtension->Flags &= ~SCSI_PORT_LU_ACTIVE; 04778 04779 /* Set attempt counter to zero */ 04780 LunExtension->AttemptCount = 0; 04781 04782 /* Remove packet from the device queue */ 04783 Entry = KeRemoveByKeyDeviceQueue(&LunExtension->DeviceQueue, LunExtension->SortKey); 04784 04785 if (Entry != NULL) 04786 { 04787 /* Get pointer to the next irp */ 04788 NextIrp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.DeviceQueueEntry); 04789 04790 /* Get point to the SRB */ 04791 IrpStack = IoGetCurrentIrpStackLocation(NextIrp); 04792 Srb = (PSCSI_REQUEST_BLOCK)IrpStack->Parameters.Others.Argument1; 04793 04794 /* Set new key*/ 04795 LunExtension->SortKey = Srb->QueueSortKey; 04796 LunExtension->SortKey++; 04797 04798 /* Release the spinlock */ 04799 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04800 04801 /* Start the next pending request */ 04802 IoStartPacket(DeviceExtension->DeviceObject, NextIrp, (PULONG)NULL, NULL); 04803 } 04804 else 04805 { 04806 /* Release the spinlock */ 04807 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04808 } 04809 } 04810 04811 04812 04813 // ScsiPortDpcForIsr 04814 // DESCRIPTION: 04815 // 04816 // RUN LEVEL: 04817 // 04818 // ARGUMENTS: 04819 // IN PKDPC Dpc 04820 // IN PDEVICE_OBJECT DpcDeviceObject 04821 // IN PIRP DpcIrp 04822 // IN PVOID DpcContext 04823 // 04824 static VOID NTAPI 04825 ScsiPortDpcForIsr(IN PKDPC Dpc, 04826 IN PDEVICE_OBJECT DpcDeviceObject, 04827 IN PIRP DpcIrp, 04828 IN PVOID DpcContext) 04829 { 04830 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DpcDeviceObject->DeviceExtension; 04831 SCSI_PORT_INTERRUPT_DATA InterruptData; 04832 SCSI_PORT_SAVE_INTERRUPT Context; 04833 PSCSI_PORT_LUN_EXTENSION LunExtension; 04834 BOOLEAN NeedToStartIo; 04835 PSCSI_REQUEST_BLOCK_INFO SrbInfo; 04836 LARGE_INTEGER TimerValue; 04837 04838 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n", 04839 Dpc, DpcDeviceObject, DpcIrp, DpcContext); 04840 04841 /* We need to acquire spinlock */ 04842 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 04843 04844 RtlZeroMemory(&InterruptData, sizeof(SCSI_PORT_INTERRUPT_DATA)); 04845 04846 TryAgain: 04847 04848 /* Interrupt structure must be snapshotted, and only then analyzed */ 04849 Context.InterruptData = &InterruptData; 04850 Context.DeviceExtension = DeviceExtension; 04851 04852 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 04853 SpiSaveInterruptData, 04854 &Context)) 04855 { 04856 /* Nothing - just return (don't forget to release the spinlock */ 04857 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04858 DPRINT("ScsiPortDpcForIsr() done\n"); 04859 return; 04860 } 04861 04862 /* If flush of adapters is needed - do it */ 04863 if (InterruptData.Flags & SCSI_PORT_FLUSH_ADAPTERS) 04864 { 04865 /* TODO: Implement */ 04866 ASSERT(FALSE); 04867 } 04868 04869 /* Check for IoMapTransfer */ 04870 if (InterruptData.Flags & SCSI_PORT_MAP_TRANSFER) 04871 { 04872 /* TODO: Implement */ 04873 ASSERT(FALSE); 04874 } 04875 04876 /* Check if timer is needed */ 04877 if (InterruptData.Flags & SCSI_PORT_TIMER_NEEDED) 04878 { 04879 /* Save the timer routine */ 04880 DeviceExtension->HwScsiTimer = InterruptData.HwScsiTimer; 04881 04882 if (InterruptData.MiniportTimerValue == 0) 04883 { 04884 /* Cancel the timer */ 04885 KeCancelTimer(&DeviceExtension->MiniportTimer); 04886 } 04887 else 04888 { 04889 /* Convert timer value */ 04890 TimerValue.QuadPart = Int32x32To64(InterruptData.MiniportTimerValue, -10); 04891 04892 /* Set the timer */ 04893 KeSetTimer(&DeviceExtension->MiniportTimer, 04894 TimerValue, 04895 &DeviceExtension->MiniportTimerDpc); 04896 } 04897 } 04898 04899 /* If it's ready for the next request */ 04900 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY) 04901 { 04902 /* Check for a duplicate request (NextRequest+NextLuRequest) */ 04903 if ((DeviceExtension->Flags & 04904 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) == 04905 (SCSI_PORT_DEVICE_BUSY | SCSI_PORT_DISCONNECT_ALLOWED)) 04906 { 04907 /* Clear busy flag set by ScsiPortStartPacket() */ 04908 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY; 04909 04910 if (!(InterruptData.Flags & SCSI_PORT_RESET)) 04911 { 04912 /* Ready for next, and no reset is happening */ 04913 DeviceExtension->TimerCount = -1; 04914 } 04915 } 04916 else 04917 { 04918 /* Not busy, but not ready for the next request */ 04919 DeviceExtension->Flags &= ~SCSI_PORT_DEVICE_BUSY; 04920 InterruptData.Flags &= ~SCSI_PORT_NEXT_REQUEST_READY; 04921 } 04922 } 04923 04924 /* Any resets? */ 04925 if (InterruptData.Flags & SCSI_PORT_RESET_REPORTED) 04926 { 04927 /* Hold for a bit */ 04928 DeviceExtension->TimerCount = 4; 04929 } 04930 04931 /* Any ready LUN? */ 04932 if (InterruptData.ReadyLun != NULL) 04933 { 04934 04935 /* Process all LUNs from the list*/ 04936 while (TRUE) 04937 { 04938 /* Remove it from the list first (as processed) */ 04939 LunExtension = InterruptData.ReadyLun; 04940 InterruptData.ReadyLun = LunExtension->ReadyLun; 04941 LunExtension->ReadyLun = NULL; 04942 04943 /* Get next request for this LUN */ 04944 SpiGetNextRequestFromLun(DeviceExtension, LunExtension); 04945 04946 /* Still ready requests exist? 04947 If yes - get spinlock, if no - stop here */ 04948 if (InterruptData.ReadyLun != NULL) 04949 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 04950 else 04951 break; 04952 } 04953 } 04954 else 04955 { 04956 /* Release the spinlock */ 04957 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 04958 } 04959 04960 /* If we ready for next packet, start it */ 04961 if (InterruptData.Flags & SCSI_PORT_NEXT_REQUEST_READY) 04962 IoStartNextPacket(DeviceExtension->DeviceObject, FALSE); 04963 04964 NeedToStartIo = FALSE; 04965 04966 /* Loop the completed request list */ 04967 while (InterruptData.CompletedRequests) 04968 { 04969 /* Remove the request */ 04970 SrbInfo = InterruptData.CompletedRequests; 04971 InterruptData.CompletedRequests = SrbInfo->CompletedRequests; 04972 SrbInfo->CompletedRequests = NULL; 04973 04974 /* Process it */ 04975 SpiProcessCompletedRequest(DeviceExtension, 04976 SrbInfo, 04977 &NeedToStartIo); 04978 } 04979 04980 /* Loop abort request list */ 04981 while (InterruptData.CompletedAbort) 04982 { 04983 LunExtension = InterruptData.CompletedAbort; 04984 04985 /* Remove the request */ 04986 InterruptData.CompletedAbort = LunExtension->CompletedAbortRequests; 04987 04988 /* Get spinlock since we're going to change flags */ 04989 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 04990 04991 /* TODO: Put SrbExtension to the list of free extensions */ 04992 ASSERT(FALSE); 04993 } 04994 04995 /* If we need - call StartIo routine */ 04996 if (NeedToStartIo) 04997 { 04998 /* Make sure CurrentIrp is not null! */ 04999 ASSERT(DpcDeviceObject->CurrentIrp != NULL); 05000 ScsiPortStartIo(DpcDeviceObject, DpcDeviceObject->CurrentIrp); 05001 } 05002 05003 /* Everything has been done, check */ 05004 if (InterruptData.Flags & SCSI_PORT_ENABLE_INT_REQUEST) 05005 { 05006 /* Synchronize using spinlock */ 05007 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 05008 05009 /* Request an interrupt */ 05010 DeviceExtension->HwInterrupt(DeviceExtension->MiniPortDeviceExtension); 05011 05012 ASSERT(DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET); 05013 05014 /* Should interrupts be enabled again? */ 05015 if (DeviceExtension->Flags & SCSI_PORT_DISABLE_INT_REQUESET) 05016 { 05017 /* Clear this flag */ 05018 DeviceExtension->Flags &= ~SCSI_PORT_DISABLE_INT_REQUESET; 05019 05020 /* Call a special routine to do this */ 05021 ASSERT(FALSE); 05022 #if 0 05023 KeSynchronizeExecution(DeviceExtension->Interrupt, 05024 SpiEnableInterrupts, 05025 DeviceExtension); 05026 #endif 05027 } 05028 05029 /* If we need a notification again - loop */ 05030 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 05031 goto TryAgain; 05032 05033 /* Release the spinlock */ 05034 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 05035 } 05036 05037 DPRINT("ScsiPortDpcForIsr() done\n"); 05038 } 05039 05040 BOOLEAN 05041 NTAPI 05042 SpiProcessTimeout(PVOID ServiceContext) 05043 { 05044 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)ServiceContext; 05045 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 05046 ULONG Bus; 05047 05048 DPRINT("SpiProcessTimeout() entered\n"); 05049 05050 DeviceExtension->TimerCount = -1; 05051 05052 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET) 05053 { 05054 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET; 05055 05056 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_RESET_REQUEST) 05057 { 05058 DeviceExtension->InterruptData.Flags &= ~SCSI_PORT_RESET_REQUEST; 05059 ScsiPortStartPacket(ServiceContext); 05060 } 05061 05062 return FALSE; 05063 } 05064 else 05065 { 05066 DPRINT("Resetting the bus\n"); 05067 05068 for (Bus = 0; Bus < DeviceExtension->BusNum; Bus++) 05069 { 05070 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, Bus); 05071 05072 /* Reset flags and set reset timeout to 4 seconds */ 05073 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET; 05074 DeviceExtension->TimerCount = 4; 05075 } 05076 05077 /* If miniport requested - request a dpc for it */ 05078 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 05079 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 05080 } 05081 05082 return TRUE; 05083 } 05084 05085 05086 BOOLEAN 05087 NTAPI 05088 SpiResetBus(PVOID ServiceContext) 05089 { 05090 PRESETBUS_PARAMS ResetParams = (PRESETBUS_PARAMS)ServiceContext; 05091 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 05092 05093 /* Perform the bus reset */ 05094 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ResetParams->DeviceExtension; 05095 DeviceExtension->HwResetBus(DeviceExtension->MiniPortDeviceExtension, 05096 ResetParams->PathId); 05097 05098 /* Set flags and start the timer */ 05099 DeviceExtension->InterruptData.Flags |= SCSI_PORT_RESET; 05100 DeviceExtension->TimerCount = 4; 05101 05102 /* If miniport requested - give him a DPC */ 05103 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 05104 IoRequestDpc(DeviceExtension->DeviceObject, NULL, NULL); 05105 05106 return TRUE; 05107 } 05108 05109 // ScsiPortIoTimer 05110 // DESCRIPTION: 05111 // This function handles timeouts and other time delayed processing 05112 // 05113 // RUN LEVEL: 05114 // 05115 // ARGUMENTS: 05116 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer 05117 // IN PVOID Context the Controller extension for the 05118 // controller the device is on 05119 // 05120 static VOID NTAPI 05121 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject, 05122 PVOID Context) 05123 { 05124 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 05125 PSCSI_PORT_LUN_EXTENSION LunExtension; 05126 ULONG Lun; 05127 PIRP Irp; 05128 05129 DPRINT("ScsiPortIoTimer()\n"); 05130 05131 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 05132 05133 /* Protect with the spinlock */ 05134 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 05135 05136 /* Check timeouts */ 05137 if (DeviceExtension->TimerCount > 0) 05138 { 05139 /* Decrease the timeout counter */ 05140 DeviceExtension->TimerCount--; 05141 05142 if (DeviceExtension->TimerCount == 0) 05143 { 05144 /* Timeout, process it */ 05145 if (KeSynchronizeExecution(DeviceExtension->Interrupt[0], 05146 SpiProcessTimeout, 05147 DeviceExtension->DeviceObject)) 05148 { 05149 DPRINT("Error happened during processing timeout, but nothing critical\n"); 05150 } 05151 } 05152 05153 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 05154 05155 /* We should exit now, since timeout is processed */ 05156 return; 05157 } 05158 05159 /* Per-Lun scanning of timeouts is needed... */ 05160 for (Lun = 0; Lun < LUS_NUMBER; Lun++) 05161 { 05162 LunExtension = DeviceExtension->LunExtensionList[Lun]; 05163 05164 while (LunExtension) 05165 { 05166 if (LunExtension->Flags & LUNEX_BUSY) 05167 { 05168 if (!(LunExtension->Flags & 05169 (LUNEX_NEED_REQUEST_SENSE | LUNEX_FROZEN_QUEUE))) 05170 { 05171 DPRINT("Retrying busy request\n"); 05172 05173 /* Clear flags, and retry busy request */ 05174 LunExtension->Flags &= ~(LUNEX_BUSY | LUNEX_FULL_QUEUE); 05175 Irp = LunExtension->BusyRequest; 05176 05177 /* Clearing busy request */ 05178 LunExtension->BusyRequest = NULL; 05179 05180 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 05181 05182 IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL); 05183 05184 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 05185 } 05186 } 05187 else if (LunExtension->RequestTimeout == 0) 05188 { 05189 RESETBUS_PARAMS ResetParams; 05190 05191 LunExtension->RequestTimeout = -1; 05192 05193 DPRINT("Request timed out, resetting bus\n"); 05194 05195 /* Pass params to the bus reset routine */ 05196 ResetParams.PathId = LunExtension->PathId; 05197 ResetParams.DeviceExtension = DeviceExtension; 05198 05199 if (!KeSynchronizeExecution(DeviceExtension->Interrupt[0], 05200 SpiResetBus, 05201 &ResetParams)) 05202 { 05203 DPRINT1("Reset failed\n"); 05204 } 05205 } 05206 else if (LunExtension->RequestTimeout > 0) 05207 { 05208 /* Decrement the timeout counter */ 05209 LunExtension->RequestTimeout--; 05210 } 05211 05212 LunExtension = LunExtension->Next; 05213 } 05214 } 05215 05216 /* Release the spinlock */ 05217 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 05218 } 05219 05220 /********************************************************************** 05221 * NAME INTERNAL 05222 * SpiBuildDeviceMap 05223 * 05224 * DESCRIPTION 05225 * Builds the registry device map of all device which are attached 05226 * to the given SCSI HBA port. The device map is located at: 05227 * \Registry\Machine\DeviceMap\Scsi 05228 * 05229 * RUN LEVEL 05230 * PASSIVE_LEVEL 05231 * 05232 * ARGUMENTS 05233 * DeviceExtension 05234 * ... 05235 * 05236 * RegistryPath 05237 * Name of registry driver service key. 05238 * 05239 * RETURNS 05240 * NTSTATUS 05241 */ 05242 05243 static NTSTATUS 05244 SpiBuildDeviceMap (PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 05245 PUNICODE_STRING RegistryPath) 05246 { 05247 PSCSI_PORT_LUN_EXTENSION LunExtension; 05248 OBJECT_ATTRIBUTES ObjectAttributes; 05249 UNICODE_STRING KeyName; 05250 UNICODE_STRING ValueName; 05251 WCHAR NameBuffer[64]; 05252 ULONG Disposition; 05253 HANDLE ScsiKey; 05254 HANDLE ScsiPortKey = NULL; 05255 HANDLE ScsiBusKey = NULL; 05256 HANDLE ScsiInitiatorKey = NULL; 05257 HANDLE ScsiTargetKey = NULL; 05258 HANDLE ScsiLunKey = NULL; 05259 ULONG BusNumber; 05260 ULONG Target; 05261 ULONG CurrentTarget; 05262 ULONG Lun; 05263 PWCHAR DriverName; 05264 ULONG UlongData; 05265 PWCHAR TypeName; 05266 NTSTATUS Status; 05267 05268 DPRINT("SpiBuildDeviceMap() called\n"); 05269 05270 if (DeviceExtension == NULL || RegistryPath == NULL) 05271 { 05272 DPRINT1("Invalid parameter\n"); 05273 return(STATUS_INVALID_PARAMETER); 05274 } 05275 05276 /* Open or create the 'Scsi' subkey */ 05277 RtlInitUnicodeString(&KeyName, 05278 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi"); 05279 InitializeObjectAttributes(&ObjectAttributes, 05280 &KeyName, 05281 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 05282 0, 05283 NULL); 05284 Status = ZwCreateKey(&ScsiKey, 05285 KEY_ALL_ACCESS, 05286 &ObjectAttributes, 05287 0, 05288 NULL, 05289 REG_OPTION_VOLATILE, 05290 &Disposition); 05291 if (!NT_SUCCESS(Status)) 05292 { 05293 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); 05294 return(Status); 05295 } 05296 05297 /* Create new 'Scsi Port X' subkey */ 05298 DPRINT("Scsi Port %lu\n", 05299 DeviceExtension->PortNumber); 05300 05301 swprintf(NameBuffer, 05302 L"Scsi Port %lu", 05303 DeviceExtension->PortNumber); 05304 RtlInitUnicodeString(&KeyName, 05305 NameBuffer); 05306 InitializeObjectAttributes(&ObjectAttributes, 05307 &KeyName, 05308 0, 05309 ScsiKey, 05310 NULL); 05311 Status = ZwCreateKey(&ScsiPortKey, 05312 KEY_ALL_ACCESS, 05313 &ObjectAttributes, 05314 0, 05315 NULL, 05316 REG_OPTION_VOLATILE, 05317 &Disposition); 05318 ZwClose(ScsiKey); 05319 if (!NT_SUCCESS(Status)) 05320 { 05321 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); 05322 return(Status); 05323 } 05324 05325 /* 05326 * Create port-specific values 05327 */ 05328 05329 /* Set 'DMA Enabled' (REG_DWORD) value */ 05330 UlongData = (ULONG)!DeviceExtension->PortCapabilities.AdapterUsesPio; 05331 DPRINT(" DMA Enabled = %s\n", (UlongData) ? "TRUE" : "FALSE"); 05332 RtlInitUnicodeString(&ValueName, 05333 L"DMA Enabled"); 05334 Status = ZwSetValueKey(ScsiPortKey, 05335 &ValueName, 05336 0, 05337 REG_DWORD, 05338 &UlongData, 05339 sizeof(ULONG)); 05340 if (!NT_SUCCESS(Status)) 05341 { 05342 DPRINT("ZwSetValueKey('DMA Enabled') failed (Status %lx)\n", Status); 05343 ZwClose(ScsiPortKey); 05344 return(Status); 05345 } 05346 05347 /* Set 'Driver' (REG_SZ) value */ 05348 DriverName = wcsrchr(RegistryPath->Buffer, L'\\') + 1; 05349 RtlInitUnicodeString(&ValueName, 05350 L"Driver"); 05351 Status = ZwSetValueKey(ScsiPortKey, 05352 &ValueName, 05353 0, 05354 REG_SZ, 05355 DriverName, 05356 (wcslen(DriverName) + 1) * sizeof(WCHAR)); 05357 if (!NT_SUCCESS(Status)) 05358 { 05359 DPRINT("ZwSetValueKey('Driver') failed (Status %lx)\n", Status); 05360 ZwClose(ScsiPortKey); 05361 return(Status); 05362 } 05363 05364 /* Set 'Interrupt' (REG_DWORD) value (NT4 only) */ 05365 UlongData = (ULONG)DeviceExtension->PortConfig->BusInterruptLevel; 05366 DPRINT(" Interrupt = %lu\n", UlongData); 05367 RtlInitUnicodeString(&ValueName, 05368 L"Interrupt"); 05369 Status = ZwSetValueKey(ScsiPortKey, 05370 &ValueName, 05371 0, 05372 REG_DWORD, 05373 &UlongData, 05374 sizeof(ULONG)); 05375 if (!NT_SUCCESS(Status)) 05376 { 05377 DPRINT("ZwSetValueKey('Interrupt') failed (Status %lx)\n", Status); 05378 ZwClose(ScsiPortKey); 05379 return(Status); 05380 } 05381 05382 /* Set 'IOAddress' (REG_DWORD) value (NT4 only) */ 05383 UlongData = ScsiPortConvertPhysicalAddressToUlong((*DeviceExtension->PortConfig->AccessRanges)[0].RangeStart); 05384 DPRINT(" IOAddress = %lx\n", UlongData); 05385 RtlInitUnicodeString(&ValueName, 05386 L"IOAddress"); 05387 Status = ZwSetValueKey(ScsiPortKey, 05388 &ValueName, 05389 0, 05390 REG_DWORD, 05391 &UlongData, 05392 sizeof(ULONG)); 05393 if (!NT_SUCCESS(Status)) 05394 { 05395 DPRINT("ZwSetValueKey('IOAddress') failed (Status %lx)\n", Status); 05396 ZwClose(ScsiPortKey); 05397 return(Status); 05398 } 05399 05400 /* Enumerate buses */ 05401 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig->NumberOfBuses; BusNumber++) 05402 { 05403 /* Create 'Scsi Bus X' key */ 05404 DPRINT(" Scsi Bus %lu\n", BusNumber); 05405 swprintf(NameBuffer, 05406 L"Scsi Bus %lu", 05407 BusNumber); 05408 RtlInitUnicodeString(&KeyName, 05409 NameBuffer); 05410 InitializeObjectAttributes(&ObjectAttributes, 05411 &KeyName, 05412 0, 05413 ScsiPortKey, 05414 NULL); 05415 Status = ZwCreateKey(&ScsiBusKey, 05416 KEY_ALL_ACCESS, 05417 &ObjectAttributes, 05418 0, 05419 NULL, 05420 REG_OPTION_VOLATILE, 05421 &Disposition); 05422 if (!NT_SUCCESS(Status)) 05423 { 05424 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); 05425 goto ByeBye; 05426 } 05427 05428 /* Create 'Initiator Id X' key */ 05429 DPRINT(" Initiator Id %u\n", 05430 DeviceExtension->PortConfig->InitiatorBusId[BusNumber]); 05431 swprintf(NameBuffer, 05432 L"Initiator Id %u", 05433 (unsigned int)(UCHAR)DeviceExtension->PortConfig->InitiatorBusId[BusNumber]); 05434 RtlInitUnicodeString(&KeyName, 05435 NameBuffer); 05436 InitializeObjectAttributes(&ObjectAttributes, 05437 &KeyName, 05438 0, 05439 ScsiBusKey, 05440 NULL); 05441 Status = ZwCreateKey(&ScsiInitiatorKey, 05442 KEY_ALL_ACCESS, 05443 &ObjectAttributes, 05444 0, 05445 NULL, 05446 REG_OPTION_VOLATILE, 05447 &Disposition); 05448 if (!NT_SUCCESS(Status)) 05449 { 05450 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); 05451 goto ByeBye; 05452 } 05453 05454 /* FIXME: Are there any initiator values (??) */ 05455 05456 ZwClose(ScsiInitiatorKey); 05457 ScsiInitiatorKey = NULL; 05458 05459 05460 /* Enumerate targets */ 05461 CurrentTarget = (ULONG)-1; 05462 ScsiTargetKey = NULL; 05463 for (Target = 0; Target < DeviceExtension->PortConfig->MaximumNumberOfTargets; Target++) 05464 { 05465 for (Lun = 0; Lun < SCSI_MAXIMUM_LOGICAL_UNITS; Lun++) 05466 { 05467 LunExtension = SpiGetLunExtension(DeviceExtension, 05468 (UCHAR)BusNumber, 05469 (UCHAR)Target, 05470 (UCHAR)Lun); 05471 if (LunExtension != NULL) 05472 { 05473 if (Target != CurrentTarget) 05474 { 05475 /* Close old target key */ 05476 if (ScsiTargetKey != NULL) 05477 { 05478 ZwClose(ScsiTargetKey); 05479 ScsiTargetKey = NULL; 05480 } 05481 05482 /* Create 'Target Id X' key */ 05483 DPRINT(" Target Id %lu\n", Target); 05484 swprintf(NameBuffer, 05485 L"Target Id %lu", 05486 Target); 05487 RtlInitUnicodeString(&KeyName, 05488 NameBuffer); 05489 InitializeObjectAttributes(&ObjectAttributes, 05490 &KeyName, 05491 0, 05492 ScsiBusKey, 05493 NULL); 05494 Status = ZwCreateKey(&ScsiTargetKey, 05495 KEY_ALL_ACCESS, 05496 &ObjectAttributes, 05497 0, 05498 NULL, 05499 REG_OPTION_VOLATILE, 05500 &Disposition); 05501 if (!NT_SUCCESS(Status)) 05502 { 05503 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); 05504 goto ByeBye; 05505 } 05506 05507 CurrentTarget = Target; 05508 } 05509 05510 /* Create 'Logical Unit Id X' key */ 05511 DPRINT(" Logical Unit Id %lu\n", Lun); 05512 swprintf(NameBuffer, 05513 L"Logical Unit Id %lu", 05514 Lun); 05515 RtlInitUnicodeString(&KeyName, 05516 NameBuffer); 05517 InitializeObjectAttributes(&ObjectAttributes, 05518 &KeyName, 05519 0, 05520 ScsiTargetKey, 05521 NULL); 05522 Status = ZwCreateKey(&ScsiLunKey, 05523 KEY_ALL_ACCESS, 05524 &ObjectAttributes, 05525 0, 05526 NULL, 05527 REG_OPTION_VOLATILE, 05528 &Disposition); 05529 if (!NT_SUCCESS(Status)) 05530 { 05531 DPRINT("ZwCreateKey() failed (Status %lx)\n", Status); 05532 goto ByeBye; 05533 } 05534 05535 /* Set 'Identifier' (REG_SZ) value */ 05536 swprintf(NameBuffer, 05537 L"%.8S%.16S%.4S", 05538 LunExtension->InquiryData.VendorId, 05539 LunExtension->InquiryData.ProductId, 05540 LunExtension->InquiryData.ProductRevisionLevel); 05541 DPRINT(" Identifier = '%S'\n", NameBuffer); 05542 RtlInitUnicodeString(&ValueName, 05543 L"Identifier"); 05544 Status = ZwSetValueKey(ScsiLunKey, 05545 &ValueName, 05546 0, 05547 REG_SZ, 05548 NameBuffer, 05549 (wcslen(NameBuffer) + 1) * sizeof(WCHAR)); 05550 if (!NT_SUCCESS(Status)) 05551 { 05552 DPRINT("ZwSetValueKey('Identifier') failed (Status %lx)\n", Status); 05553 goto ByeBye; 05554 } 05555 05556 /* Set 'Type' (REG_SZ) value */ 05557 switch (LunExtension->InquiryData.DeviceType) 05558 { 05559 case 0: 05560 TypeName = L"DiskPeripheral"; 05561 break; 05562 case 1: 05563 TypeName = L"TapePeripheral"; 05564 break; 05565 case 2: 05566 TypeName = L"PrinterPeripheral"; 05567 break; 05568 case 4: 05569 TypeName = L"WormPeripheral"; 05570 break; 05571 case 5: 05572 TypeName = L"CdRomPeripheral"; 05573 break; 05574 case 6: 05575 TypeName = L"ScannerPeripheral"; 05576 break; 05577 case 7: 05578 TypeName = L"OpticalDiskPeripheral"; 05579 break; 05580 case 8: 05581 TypeName = L"MediumChangerPeripheral"; 05582 break; 05583 case 9: 05584 TypeName = L"CommunicationPeripheral"; 05585 break; 05586 default: 05587 TypeName = L"OtherPeripheral"; 05588 break; 05589 } 05590 DPRINT(" Type = '%S'\n", TypeName); 05591 RtlInitUnicodeString(&ValueName, 05592 L"Type"); 05593 Status = ZwSetValueKey(ScsiLunKey, 05594 &ValueName, 05595 0, 05596 REG_SZ, 05597 TypeName, 05598 (wcslen(TypeName) + 1) * sizeof(WCHAR)); 05599 if (!NT_SUCCESS(Status)) 05600 { 05601 DPRINT("ZwSetValueKey('Type') failed (Status %lx)\n", Status); 05602 goto ByeBye; 05603 } 05604 05605 ZwClose(ScsiLunKey); 05606 ScsiLunKey = NULL; 05607 } 05608 } 05609 05610 /* Close old target key */ 05611 if (ScsiTargetKey != NULL) 05612 { 05613 ZwClose(ScsiTargetKey); 05614 ScsiTargetKey = NULL; 05615 } 05616 } 05617 05618 ZwClose(ScsiBusKey); 05619 ScsiBusKey = NULL; 05620 } 05621 05622 ByeBye: 05623 if (ScsiLunKey != NULL) 05624 ZwClose (ScsiLunKey); 05625 05626 if (ScsiInitiatorKey != NULL) 05627 ZwClose (ScsiInitiatorKey); 05628 05629 if (ScsiTargetKey != NULL) 05630 ZwClose (ScsiTargetKey); 05631 05632 if (ScsiBusKey != NULL) 05633 ZwClose (ScsiBusKey); 05634 05635 if (ScsiPortKey != NULL) 05636 ZwClose (ScsiPortKey); 05637 05638 DPRINT("SpiBuildDeviceMap() done\n"); 05639 05640 return Status; 05641 } 05642 05643 VOID 05644 NTAPI 05645 SpiMiniportTimerDpc(IN struct _KDPC *Dpc, 05646 IN PVOID DeviceObject, 05647 IN PVOID SystemArgument1, 05648 IN PVOID SystemArgument2) 05649 { 05650 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension; 05651 05652 DPRINT("Miniport timer DPC\n"); 05653 05654 DeviceExtension = ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; 05655 05656 /* Acquire the spinlock */ 05657 KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock); 05658 05659 /* Call the timer routine */ 05660 if (DeviceExtension->HwScsiTimer != NULL) 05661 { 05662 DeviceExtension->HwScsiTimer(&DeviceExtension->MiniPortDeviceExtension); 05663 } 05664 05665 /* Release the spinlock */ 05666 KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock); 05667 05668 if (DeviceExtension->InterruptData.Flags & SCSI_PORT_NOTIFICATION_NEEDED) 05669 { 05670 ScsiPortDpcForIsr(NULL, 05671 DeviceExtension->DeviceObject, 05672 NULL, 05673 NULL); 05674 } 05675 } 05676 05677 static NTSTATUS 05678 SpiCreatePortConfig(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 05679 PHW_INITIALIZATION_DATA HwInitData, 05680 PCONFIGURATION_INFO InternalConfigInfo, 05681 PPORT_CONFIGURATION_INFORMATION ConfigInfo, 05682 BOOLEAN ZeroStruct) 05683 { 05684 UNICODE_STRING UnicodeString; 05685 OBJECT_ATTRIBUTES ObjectAttributes; 05686 PCONFIGURATION_INFORMATION DdkConfigInformation; 05687 HANDLE RootKey, Key; 05688 BOOLEAN Found; 05689 WCHAR DeviceBuffer[16]; 05690 WCHAR StrBuffer[512]; 05691 ULONG Bus; 05692 NTSTATUS Status; 05693 05694 /* Zero out the struct if told so */ 05695 if (ZeroStruct) 05696 { 05697 /* First zero the portconfig */ 05698 RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION)); 05699 05700 /* Then access ranges */ 05701 RtlZeroMemory(InternalConfigInfo->AccessRanges, 05702 HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)); 05703 05704 /* Initialize the struct */ 05705 ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION); 05706 ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType; 05707 ConfigInfo->InterruptMode = Latched; 05708 ConfigInfo->DmaChannel = SP_UNINITIALIZED_VALUE; 05709 ConfigInfo->DmaPort = SP_UNINITIALIZED_VALUE; 05710 ConfigInfo->DmaChannel2 = SP_UNINITIALIZED_VALUE; 05711 ConfigInfo->DmaPort2 = SP_UNINITIALIZED_VALUE; 05712 ConfigInfo->MaximumTransferLength = SP_UNINITIALIZED_VALUE; 05713 ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges; 05714 ConfigInfo->MaximumNumberOfTargets = 8; 05715 05716 /* Store parameters */ 05717 ConfigInfo->NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses; 05718 ConfigInfo->MapBuffers = HwInitData->MapBuffers; 05719 ConfigInfo->AutoRequestSense = HwInitData->AutoRequestSense; 05720 ConfigInfo->ReceiveEvent = HwInitData->ReceiveEvent; 05721 ConfigInfo->TaggedQueuing = HwInitData->TaggedQueuing; 05722 ConfigInfo->MultipleRequestPerLu = HwInitData->MultipleRequestPerLu; 05723 05724 /* Get the disk usage */ 05725 DdkConfigInformation = IoGetConfigurationInformation(); 05726 ConfigInfo->AtdiskPrimaryClaimed = DdkConfigInformation->AtDiskPrimaryAddressClaimed; 05727 ConfigInfo->AtdiskSecondaryClaimed = DdkConfigInformation->AtDiskSecondaryAddressClaimed; 05728 05729 /* Initiator bus id is not set */ 05730 for (Bus = 0; Bus < 8; Bus++) 05731 ConfigInfo->InitiatorBusId[Bus] = (CCHAR)SP_UNINITIALIZED_VALUE; 05732 } 05733 05734 ConfigInfo->NumberOfPhysicalBreaks = 17; 05735 05736 /* Clear this information */ 05737 InternalConfigInfo->DisableTaggedQueueing = FALSE; 05738 InternalConfigInfo->DisableMultipleLun = FALSE; 05739 05740 /* Store Bus Number */ 05741 ConfigInfo->SystemIoBusNumber = InternalConfigInfo->BusNumber; 05742 05743 TryNextAd: 05744 05745 if (ConfigInfo->AdapterInterfaceType == Internal) 05746 { 05747 /* Open registry key for HW database */ 05748 InitializeObjectAttributes(&ObjectAttributes, 05749 DeviceExtension->DeviceObject->DriverObject->HardwareDatabase, 05750 OBJ_CASE_INSENSITIVE, 05751 NULL, 05752 NULL); 05753 05754 Status = ZwOpenKey(&RootKey, 05755 KEY_READ, 05756 &ObjectAttributes); 05757 05758 if (NT_SUCCESS(Status)) 05759 { 05760 /* Create name for it */ 05761 swprintf(StrBuffer, L"ScsiAdapter\\%lu", 05762 InternalConfigInfo->AdapterNumber); 05763 05764 RtlInitUnicodeString(&UnicodeString, StrBuffer); 05765 05766 /* Open device key */ 05767 InitializeObjectAttributes(&ObjectAttributes, 05768 &UnicodeString, 05769 OBJ_CASE_INSENSITIVE, 05770 RootKey, 05771 NULL); 05772 05773 Status = ZwOpenKey(&Key, 05774 KEY_READ, 05775 &ObjectAttributes); 05776 05777 ZwClose(RootKey); 05778 05779 if (NT_SUCCESS(Status)) 05780 { 05781 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber) 05782 { 05783 DPRINT("Hardware info found at %S\n", StrBuffer); 05784 05785 /* Parse it */ 05786 SpiParseDeviceInfo(DeviceExtension, 05787 Key, 05788 ConfigInfo, 05789 InternalConfigInfo, 05790 (PUCHAR)StrBuffer); 05791 05792 InternalConfigInfo->BusNumber = 0; 05793 } 05794 else 05795 { 05796 /* Try the next adapter */ 05797 InternalConfigInfo->AdapterNumber++; 05798 goto TryNextAd; 05799 } 05800 } 05801 else 05802 { 05803 /* Info was not found, exit */ 05804 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status); 05805 return STATUS_DEVICE_DOES_NOT_EXIST; 05806 } 05807 } 05808 else 05809 { 05810 DPRINT1("ZwOpenKey() failed with Status=0x%08X\n", Status); 05811 } 05812 } 05813 05814 /* Look at device params */ 05815 Key = NULL; 05816 if (InternalConfigInfo->Parameter) 05817 { 05818 ExFreePool(InternalConfigInfo->Parameter); 05819 InternalConfigInfo->Parameter = NULL; 05820 } 05821 05822 if (InternalConfigInfo->ServiceKey != NULL) 05823 { 05824 swprintf(DeviceBuffer, L"Device%lu", InternalConfigInfo->AdapterNumber); 05825 RtlInitUnicodeString(&UnicodeString, DeviceBuffer); 05826 05827 /* Open the service key */ 05828 InitializeObjectAttributes(&ObjectAttributes, 05829 &UnicodeString, 05830 OBJ_CASE_INSENSITIVE, 05831 InternalConfigInfo->ServiceKey, 05832 NULL); 05833 05834 Status = ZwOpenKey(&Key, 05835 KEY_READ, 05836 &ObjectAttributes); 05837 } 05838 05839 /* Parse device key */ 05840 if (InternalConfigInfo->DeviceKey != NULL) 05841 { 05842 SpiParseDeviceInfo(DeviceExtension, 05843 InternalConfigInfo->DeviceKey, 05844 ConfigInfo, 05845 InternalConfigInfo, 05846 (PUCHAR)StrBuffer); 05847 } 05848 05849 /* Then parse hw info */ 05850 if (Key != NULL) 05851 { 05852 if (InternalConfigInfo->LastAdapterNumber != InternalConfigInfo->AdapterNumber) 05853 { 05854 SpiParseDeviceInfo(DeviceExtension, 05855 Key, 05856 ConfigInfo, 05857 InternalConfigInfo, 05858 (PUCHAR)StrBuffer); 05859 05860 /* Close the key */ 05861 ZwClose(Key); 05862 } 05863 else 05864 { 05865 /* Adapter not found, go try the next one */ 05866 InternalConfigInfo->AdapterNumber++; 05867 05868 /* Close the key */ 05869 ZwClose(Key); 05870 05871 goto TryNextAd; 05872 } 05873 } 05874 05875 /* Update the last adapter number */ 05876 InternalConfigInfo->LastAdapterNumber = InternalConfigInfo->AdapterNumber; 05877 05878 /* Do we have this kind of bus at all? */ 05879 Found = FALSE; 05880 Status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType, 05881 &InternalConfigInfo->BusNumber, 05882 NULL, 05883 NULL, 05884 NULL, 05885 NULL, 05886 SpQueryDeviceCallout, 05887 &Found); 05888 05889 /* This bus was not found */ 05890 if (!Found) 05891 { 05892 INTERFACE_TYPE InterfaceType = Eisa; 05893 05894 /* Check for EISA */ 05895 if (HwInitData->AdapterInterfaceType == Isa) 05896 { 05897 Status = IoQueryDeviceDescription(&InterfaceType, 05898 &InternalConfigInfo->BusNumber, 05899 NULL, 05900 NULL, 05901 NULL, 05902 NULL, 05903 SpQueryDeviceCallout, 05904 &Found); 05905 05906 /* Return respectively */ 05907 if (Found) 05908 return STATUS_SUCCESS; 05909 else 05910 return STATUS_DEVICE_DOES_NOT_EXIST; 05911 } 05912 else 05913 { 05914 return STATUS_DEVICE_DOES_NOT_EXIST; 05915 } 05916 } 05917 else 05918 { 05919 return STATUS_SUCCESS; 05920 } 05921 } 05922 05923 static VOID 05924 SpiParseDeviceInfo(IN PSCSI_PORT_DEVICE_EXTENSION DeviceExtension, 05925 IN HANDLE Key, 05926 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo, 05927 IN PCONFIGURATION_INFO InternalConfigInfo, 05928 IN PUCHAR Buffer) 05929 { 05930 PKEY_VALUE_FULL_INFORMATION KeyValueInformation; 05931 PCM_FULL_RESOURCE_DESCRIPTOR FullResource; 05932 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 05933 PCM_SCSI_DEVICE_DATA ScsiDeviceData; 05934 ULONG Length, Count, Dma = 0, Interrupt = 0; 05935 ULONG Index = 0, RangeCount = 0; 05936 UNICODE_STRING UnicodeString; 05937 ANSI_STRING AnsiString; 05938 NTSTATUS Status = STATUS_SUCCESS; 05939 05940 05941 KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer; 05942 05943 /* Loop through all values in the device node */ 05944 while(TRUE) 05945 { 05946 Status = ZwEnumerateValueKey(Key, 05947 Index, 05948 KeyValueFullInformation, 05949 Buffer, 05950 512, 05951 &Length); 05952 05953 if (!NT_SUCCESS(Status)) 05954 return; 05955 05956 Index++; 05957 05958 /* Length for DWORD is ok? */ 05959 if (KeyValueInformation->Type == REG_DWORD && 05960 KeyValueInformation->DataLength != sizeof(ULONG)) 05961 { 05962 continue; 05963 } 05964 05965 /* Get MaximumLogicalUnit */ 05966 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumLogicalUnit", 05967 KeyValueInformation->NameLength/2) == 0) 05968 { 05969 05970 if (KeyValueInformation->Type != REG_DWORD) 05971 { 05972 DPRINT("Bad data type for MaximumLogicalUnit\n"); 05973 continue; 05974 } 05975 05976 DeviceExtension->MaxLunCount = *((PUCHAR) 05977 (Buffer + KeyValueInformation->DataOffset)); 05978 05979 /* Check / reset if needed */ 05980 if (DeviceExtension->MaxLunCount > SCSI_MAXIMUM_LOGICAL_UNITS) 05981 DeviceExtension->MaxLunCount = SCSI_MAXIMUM_LOGICAL_UNITS; 05982 05983 DPRINT("MaximumLogicalUnit = %d\n", DeviceExtension->MaxLunCount); 05984 } 05985 05986 /* Get InitiatorTargetId */ 05987 if (_wcsnicmp(KeyValueInformation->Name, L"InitiatorTargetId", 05988 KeyValueInformation->NameLength / 2) == 0) 05989 { 05990 05991 if (KeyValueInformation->Type != REG_DWORD) 05992 { 05993 DPRINT("Bad data type for InitiatorTargetId\n"); 05994 continue; 05995 } 05996 05997 ConfigInfo->InitiatorBusId[0] = *((PUCHAR) 05998 (Buffer + KeyValueInformation->DataOffset)); 05999 06000 /* Check / reset if needed */ 06001 if (ConfigInfo->InitiatorBusId[0] > ConfigInfo->MaximumNumberOfTargets - 1) 06002 ConfigInfo->InitiatorBusId[0] = (CCHAR)-1; 06003 06004 DPRINT("InitiatorTargetId = %d\n", ConfigInfo->InitiatorBusId[0]); 06005 } 06006 06007 /* Get ScsiDebug */ 06008 if (_wcsnicmp(KeyValueInformation->Name, L"ScsiDebug", 06009 KeyValueInformation->NameLength/2) == 0) 06010 { 06011 DPRINT("ScsiDebug key not supported\n"); 06012 } 06013 06014 /* Check for a breakpoint */ 06015 if (_wcsnicmp(KeyValueInformation->Name, L"BreakPointOnEntry", 06016 KeyValueInformation->NameLength/2) == 0) 06017 { 06018 DPRINT1("Breakpoint on entry requested!\n"); 06019 DbgBreakPoint(); 06020 } 06021 06022 /* Get DisableSynchronousTransfers */ 06023 if (_wcsnicmp(KeyValueInformation->Name, L"DisableSynchronousTransfers", 06024 KeyValueInformation->NameLength/2) == 0) 06025 { 06026 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 06027 DPRINT("Synch transfers disabled\n"); 06028 } 06029 06030 /* Get DisableDisconnects */ 06031 if (_wcsnicmp(KeyValueInformation->Name, L"DisableDisconnects", 06032 KeyValueInformation->NameLength/2) == 0) 06033 { 06034 DeviceExtension->SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT; 06035 DPRINT("Disconnects disabled\n"); 06036 } 06037 06038 /* Get DisableTaggedQueuing */ 06039 if (_wcsnicmp(KeyValueInformation->Name, L"DisableTaggedQueuing", 06040 KeyValueInformation->NameLength/2) == 0) 06041 { 06042 InternalConfigInfo->DisableTaggedQueueing = TRUE; 06043 DPRINT("Tagged queueing disabled\n"); 06044 } 06045 06046 /* Get DisableMultipleRequests */ 06047 if (_wcsnicmp(KeyValueInformation->Name, L"DisableMultipleRequests", 06048 KeyValueInformation->NameLength/2) == 0) 06049 { 06050 InternalConfigInfo->DisableMultipleLun = TRUE; 06051 DPRINT("Multiple requests disabled\n"); 06052 } 06053 06054 /* Get DriverParameters */ 06055 if (_wcsnicmp(KeyValueInformation->Name, L"DriverParameters", 06056 KeyValueInformation->NameLength/2) == 0) 06057 { 06058 /* Skip if nothing */ 06059 if (KeyValueInformation->DataLength == 0) 06060 continue; 06061 06062 /* If there was something previously allocated - free it */ 06063 if (InternalConfigInfo->Parameter != NULL) 06064 ExFreePool(InternalConfigInfo->Parameter); 06065 06066 /* Allocate it */ 06067 InternalConfigInfo->Parameter = ExAllocatePoolWithTag(NonPagedPool, 06068 KeyValueInformation->DataLength, TAG_SCSIPORT); 06069 06070 if (InternalConfigInfo->Parameter != NULL) 06071 { 06072 if (KeyValueInformation->Type != REG_SZ) 06073 { 06074 /* Just copy */ 06075 RtlCopyMemory( 06076 InternalConfigInfo->Parameter, 06077 (PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset, 06078 KeyValueInformation->DataLength); 06079 } 06080 else 06081 { 06082 /* If it's a unicode string, convert it to ansi */ 06083 UnicodeString.Length = (USHORT)KeyValueInformation->DataLength; 06084 UnicodeString.MaximumLength = (USHORT)KeyValueInformation->DataLength; 06085 UnicodeString.Buffer = 06086 (PWSTR)((PCCHAR)KeyValueInformation + KeyValueInformation->DataOffset); 06087 06088 AnsiString.Length = 0; 06089 AnsiString.MaximumLength = (USHORT)KeyValueInformation->DataLength; 06090 AnsiString.Buffer = (PCHAR)InternalConfigInfo->Parameter; 06091 06092 Status = RtlUnicodeStringToAnsiString(&AnsiString, 06093 &UnicodeString, 06094 FALSE); 06095 06096 /* In case of error, free the allocated space */ 06097 if (!NT_SUCCESS(Status)) 06098 { 06099 ExFreePool(InternalConfigInfo->Parameter); 06100 InternalConfigInfo->Parameter = NULL; 06101 } 06102 06103 } 06104 } 06105 06106 DPRINT("Found driver parameter\n"); 06107 } 06108 06109 /* Get MaximumSGList */ 06110 if (_wcsnicmp(KeyValueInformation->Name, L"MaximumSGList", 06111 KeyValueInformation->NameLength/2) == 0) 06112 { 06113 if (KeyValueInformation->Type != REG_DWORD) 06114 { 06115 DPRINT("Bad data type for MaximumSGList\n"); 06116 continue; 06117 } 06118 06119 ConfigInfo->NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset)); 06120 06121 /* Check / fix */ 06122 if (ConfigInfo->NumberOfPhysicalBreaks > SCSI_MAXIMUM_PHYSICAL_BREAKS) 06123 { 06124 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS; 06125 } 06126 else if (ConfigInfo->NumberOfPhysicalBreaks < SCSI_MINIMUM_PHYSICAL_BREAKS) 06127 { 06128 ConfigInfo->NumberOfPhysicalBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS; 06129 } 06130 06131 DPRINT("MaximumSGList = %d\n", ConfigInfo->NumberOfPhysicalBreaks); 06132 } 06133 06134 /* Get NumberOfRequests */ 06135 if (_wcsnicmp(KeyValueInformation->Name, L"NumberOfRequests", 06136 KeyValueInformation->NameLength/2) == 0) 06137 { 06138 if (KeyValueInformation->Type != REG_DWORD) 06139 { 06140 DPRINT("NumberOfRequests has wrong data type\n"); 06141 continue; 06142 } 06143 06144 DeviceExtension->RequestsNumber = *((PUCHAR)(Buffer + KeyValueInformation->DataOffset)); 06145 06146 /* Check / fix */ 06147 if (DeviceExtension->RequestsNumber < 16) 06148 { 06149 DeviceExtension->RequestsNumber = 16; 06150 } 06151 else if (DeviceExtension->RequestsNumber > 512) 06152 { 06153 DeviceExtension->RequestsNumber = 512; 06154 } 06155 06156 DPRINT("Number Of Requests = %d\n", DeviceExtension->RequestsNumber); 06157 } 06158 06159 /* Get resource list */ 06160 if (_wcsnicmp(KeyValueInformation->Name, L"ResourceList", 06161 KeyValueInformation->NameLength/2) == 0 || 06162 _wcsnicmp(KeyValueInformation->Name, L"Configuration Data", 06163 KeyValueInformation->NameLength/2) == 0 ) 06164 { 06165 if (KeyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR || 06166 KeyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR)) 06167 { 06168 DPRINT("Bad data type for ResourceList\n"); 06169 continue; 06170 } 06171 else 06172 { 06173 DPRINT("Found ResourceList\n"); 06174 } 06175 06176 FullResource = (PCM_FULL_RESOURCE_DESCRIPTOR)(Buffer + KeyValueInformation->DataOffset); 06177 06178 /* Copy some info from it */ 06179 InternalConfigInfo->BusNumber = FullResource->BusNumber; 06180 ConfigInfo->SystemIoBusNumber = FullResource->BusNumber; 06181 06182 /* Loop through it */ 06183 for (Count = 0; Count < FullResource->PartialResourceList.Count; Count++) 06184 { 06185 /* Get partial descriptor */ 06186 PartialDescriptor = 06187 &FullResource->PartialResourceList.PartialDescriptors[Count]; 06188 06189 /* Check datalength */ 06190 if ((ULONG)((PCHAR)(PartialDescriptor + 1) - 06191 (PCHAR)FullResource) > KeyValueInformation->DataLength) 06192 { 06193 DPRINT("Resource data is of incorrect size\n"); 06194 break; 06195 } 06196 06197 switch (PartialDescriptor->Type) 06198 { 06199 case CmResourceTypePort: 06200 if (RangeCount >= ConfigInfo->NumberOfAccessRanges) 06201 { 06202 DPRINT("Too many access ranges\n"); 06203 continue; 06204 } 06205 06206 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = FALSE; 06207 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Port.Start; 06208 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Port.Length; 06209 RangeCount++; 06210 06211 break; 06212 06213 case CmResourceTypeMemory: 06214 if (RangeCount >= ConfigInfo->NumberOfAccessRanges) 06215 { 06216 DPRINT("Too many access ranges\n"); 06217 continue; 06218 } 06219 06220 InternalConfigInfo->AccessRanges[RangeCount].RangeInMemory = TRUE; 06221 InternalConfigInfo->AccessRanges[RangeCount].RangeStart = PartialDescriptor->u.Memory.Start; 06222 InternalConfigInfo->AccessRanges[RangeCount].RangeLength = PartialDescriptor->u.Memory.Length; 06223 RangeCount++; 06224 06225 break; 06226 06227 case CmResourceTypeInterrupt: 06228 06229 if (Interrupt == 0) 06230 { 06231 ConfigInfo->BusInterruptLevel = 06232 PartialDescriptor->u.Interrupt.Level; 06233 06234 ConfigInfo->BusInterruptVector = 06235 PartialDescriptor->u.Interrupt.Vector; 06236 06237 ConfigInfo->InterruptMode = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; 06238 } 06239 else if (Interrupt == 1) 06240 { 06241 ConfigInfo->BusInterruptLevel2 = 06242 PartialDescriptor->u.Interrupt.Level; 06243 06244 ConfigInfo->BusInterruptVector2 = 06245 PartialDescriptor->u.Interrupt.Vector; 06246 06247 ConfigInfo->InterruptMode2 = (PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? Latched : LevelSensitive; 06248 } 06249 06250 Interrupt++; 06251 break; 06252 06253 case CmResourceTypeDma: 06254 06255 if (Dma == 0) 06256 { 06257 ConfigInfo->DmaChannel = PartialDescriptor->u.Dma.Channel; 06258 ConfigInfo->DmaPort = PartialDescriptor->u.Dma.Port; 06259 06260 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8) 06261 ConfigInfo->DmaWidth = Width8Bits; 06262 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) || 06263 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 06264 ConfigInfo->DmaWidth = Width16Bits; 06265 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32) 06266 ConfigInfo->DmaWidth = Width32Bits; 06267 } 06268 else if (Dma == 1) 06269 { 06270 ConfigInfo->DmaChannel2 = PartialDescriptor->u.Dma.Channel; 06271 ConfigInfo->DmaPort2 = PartialDescriptor->u.Dma.Port; 06272 06273 if (PartialDescriptor->Flags & CM_RESOURCE_DMA_8) 06274 ConfigInfo->DmaWidth2 = Width8Bits; 06275 else if ((PartialDescriptor->Flags & CM_RESOURCE_DMA_16) || 06276 (PartialDescriptor->Flags & CM_RESOURCE_DMA_8_AND_16)) //??? 06277 ConfigInfo->DmaWidth2 = Width16Bits; 06278 else if (PartialDescriptor->Flags & CM_RESOURCE_DMA_32) 06279 ConfigInfo->DmaWidth2 = Width32Bits; 06280 } 06281 06282 Dma++; 06283 break; 06284 06285 case CmResourceTypeDeviceSpecific: 06286 if (PartialDescriptor->u.DeviceSpecificData.DataSize < 06287 sizeof(CM_SCSI_DEVICE_DATA) || 06288 (PCHAR) (PartialDescriptor + 1) - (PCHAR)FullResource + 06289 PartialDescriptor->u.DeviceSpecificData.DataSize > 06290 KeyValueInformation->DataLength) 06291 { 06292 DPRINT("Resource data length is incorrect"); 06293 break; 06294 } 06295 06296 /* Set only one field from it */ 06297 ScsiDeviceData = (PCM_SCSI_DEVICE_DATA) (PartialDescriptor+1); 06298 ConfigInfo->InitiatorBusId[0] = ScsiDeviceData->HostIdentifier; 06299 break; 06300 } 06301 } 06302 } 06303 } 06304 } 06305 06306 NTSTATUS 06307 NTAPI 06308 SpQueryDeviceCallout(IN PVOID Context, 06309 IN PUNICODE_STRING PathName, 06310 IN INTERFACE_TYPE BusType, 06311 IN ULONG BusNumber, 06312 IN PKEY_VALUE_FULL_INFORMATION *BusInformation, 06313 IN CONFIGURATION_TYPE ControllerType, 06314 IN ULONG ControllerNumber, 06315 IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation, 06316 IN CONFIGURATION_TYPE PeripheralType, 06317 IN ULONG PeripheralNumber, 06318 IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation) 06319 { 06320 PBOOLEAN Found = (PBOOLEAN)Context; 06321 /* We just set our Found variable to TRUE */ 06322 06323 *Found = TRUE; 06324 return STATUS_SUCCESS; 06325 } 06326 06327 IO_ALLOCATION_ACTION 06328 NTAPI 06329 ScsiPortAllocateAdapterChannel(IN PDEVICE_OBJECT DeviceObject, 06330 IN PIRP Irp, 06331 IN PVOID MapRegisterBase, 06332 IN PVOID Context) 06333 { 06334 KIRQL Irql; 06335 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 06336 06337 /* Guard access with the spinlock */ 06338 KeAcquireSpinLock(&DeviceExtension->SpinLock, &Irql); 06339 06340 /* Save MapRegisterBase we've got here */ 06341 DeviceExtension->MapRegisterBase = MapRegisterBase; 06342 06343 /* Start pending request */ 06344 KeSynchronizeExecution(DeviceExtension->Interrupt[0], 06345 ScsiPortStartPacket, DeviceObject); 06346 06347 /* Release spinlock we took */ 06348 KeReleaseSpinLock(&DeviceExtension->SpinLock, Irql); 06349 06350 return KeepObject; 06351 } 06352 06353 static 06354 NTSTATUS 06355 SpiStatusSrbToNt(UCHAR SrbStatus) 06356 { 06357 switch (SRB_STATUS(SrbStatus)) 06358 { 06359 case SRB_STATUS_TIMEOUT: 06360 case SRB_STATUS_COMMAND_TIMEOUT: 06361 return STATUS_IO_TIMEOUT; 06362 06363 case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: 06364 case SRB_STATUS_BAD_FUNCTION: 06365 return STATUS_INVALID_DEVICE_REQUEST; 06366 06367 case SRB_STATUS_NO_DEVICE: 06368 case SRB_STATUS_INVALID_LUN: 06369 case SRB_STATUS_INVALID_TARGET_ID: 06370 case SRB_STATUS_NO_HBA: 06371 return STATUS_DEVICE_DOES_NOT_EXIST; 06372 06373 case SRB_STATUS_DATA_OVERRUN: 06374 return STATUS_BUFFER_OVERFLOW; 06375 06376 case SRB_STATUS_SELECTION_TIMEOUT: 06377 return STATUS_DEVICE_NOT_CONNECTED; 06378 06379 default: 06380 return STATUS_IO_DEVICE_ERROR; 06381 } 06382 06383 return STATUS_IO_DEVICE_ERROR; 06384 } 06385 06386 06387 #undef ScsiPortConvertPhysicalAddressToUlong 06388 /* 06389 * @implemented 06390 */ 06391 ULONG NTAPI 06392 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address) 06393 { 06394 DPRINT("ScsiPortConvertPhysicalAddressToUlong()\n"); 06395 return(Address.u.LowPart); 06396 } 06397 06398 06399 /* EOF */ Generated on Mon May 28 2012 04:18:55 for ReactOS by
1.7.6.1
|