Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6190 lines
145 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. scsiboot.c
  5. Abstract:
  6. This is the NT SCSI port driver.
  7. Author:
  8. Mike Glass
  9. Jeff Havens
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. This module is linked into the kernel.
  14. Revision History:
  15. --*/
  16. #if !defined(DECSTATION)
  17. #include "stdarg.h"
  18. #include "stdio.h"
  19. #if defined(_MIPS_)
  20. #include "..\fw\mips\fwp.h"
  21. #elif defined(_ALPHA_)
  22. #include "bldr.h"
  23. #elif defined(_PPC_)
  24. #include "..\fw\ppc\fwp.h"
  25. #elif defined(_IA64_)
  26. #include "bootia64.h"
  27. #else
  28. #include "bootx86.h"
  29. #endif
  30. #include "scsi.h"
  31. #include "scsiboot.h"
  32. #include "pci.h"
  33. #if DBG
  34. ULONG ScsiDebug = 0;
  35. #endif
  36. ULONG ScsiPortCount;
  37. PDEVICE_OBJECT ScsiPortDeviceObject[MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS];
  38. PINQUIRYDATA InquiryDataBuffer;
  39. FULL_SCSI_REQUEST_BLOCK PrimarySrb;
  40. FULL_SCSI_REQUEST_BLOCK RequestSenseSrb;
  41. FULL_SCSI_REQUEST_BLOCK AbortSrb;
  42. extern PDRIVER_UNLOAD AEDriverUnloadRoutine;
  43. //
  44. // Function declarations
  45. //
  46. ARC_STATUS
  47. ScsiPortDispatch(
  48. IN PDEVICE_OBJECT DeviceObject,
  49. IN PIRP Irp
  50. );
  51. VOID
  52. ScsiPortExecute(
  53. IN PDEVICE_OBJECT DeviceObject,
  54. IN PIRP Irp
  55. );
  56. VOID
  57. ScsiPortStartIo (
  58. IN PDEVICE_OBJECT DeviceObject,
  59. IN PIRP Irp
  60. );
  61. BOOLEAN
  62. ScsiPortInterrupt(
  63. IN PKINTERRUPT InterruptObject,
  64. IN PDEVICE_OBJECT DeviceObject
  65. );
  66. VOID
  67. ScsiPortCompletionDpc(
  68. IN PKDPC Dpc,
  69. IN PDEVICE_OBJECT DeviceObject,
  70. IN PIRP Irp,
  71. IN PVOID Context
  72. );
  73. VOID
  74. ScsiPortTickHandler(
  75. IN PDEVICE_OBJECT DeviceObject,
  76. IN PVOID Context
  77. );
  78. IO_ALLOCATION_ACTION
  79. ScsiPortAllocationRoutine (
  80. IN PDEVICE_OBJECT DeviceObject,
  81. IN PIRP Irp,
  82. IN PVOID MapRegisterBase,
  83. IN PVOID Context
  84. );
  85. ARC_STATUS
  86. IssueInquiry(
  87. IN PDEVICE_EXTENSION deviceExtension,
  88. IN PLUNINFO LunInfo
  89. );
  90. VOID
  91. IssueRequestSense(
  92. IN PDEVICE_EXTENSION deviceExtension,
  93. IN PSCSI_REQUEST_BLOCK FailingSrb
  94. );
  95. VOID
  96. ScsiPortInternalCompletion(
  97. PDEVICE_OBJECT DeviceObject,
  98. PIRP Irp,
  99. PVOID Context
  100. );
  101. PSCSI_BUS_SCAN_DATA
  102. ScsiBusScan(
  103. IN PDEVICE_EXTENSION DeviceExtension,
  104. IN UCHAR ScsiBus,
  105. IN UCHAR InitiatorBusId
  106. );
  107. PLOGICAL_UNIT_EXTENSION
  108. CreateLogicalUnitExtension(
  109. IN PDEVICE_EXTENSION DeviceExtension
  110. );
  111. BOOLEAN
  112. SpStartIoSynchronized (
  113. PVOID ServiceContext
  114. );
  115. VOID
  116. IssueAbortRequest(
  117. IN PDEVICE_EXTENSION DeviceExtension,
  118. IN PIRP FailingIrp
  119. );
  120. VOID
  121. SpCheckResetDelay(
  122. IN PDEVICE_EXTENSION deviceExtension
  123. );
  124. IO_ALLOCATION_ACTION
  125. SpBuildScatterGather(
  126. IN struct _DEVICE_OBJECT *DeviceObject,
  127. IN struct _IRP *Irp,
  128. IN PVOID MapRegisterBase,
  129. IN PVOID Context
  130. );
  131. BOOLEAN
  132. SpGetInterruptState(
  133. IN PVOID ServiceContext
  134. );
  135. VOID
  136. SpTimerDpc(
  137. IN PKDPC Dpc,
  138. IN PVOID Context,
  139. IN PVOID SystemContext1,
  140. IN PVOID SystemContext2
  141. );
  142. PLOGICAL_UNIT_EXTENSION
  143. GetLogicalUnitExtension(
  144. PDEVICE_EXTENSION DeviceExtension,
  145. UCHAR TargetId
  146. );
  147. NTSTATUS
  148. SpInitializeConfiguration(
  149. IN PDEVICE_EXTENSION DeviceExtension,
  150. IN PHW_INITIALIZATION_DATA HwInitData,
  151. OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  152. IN BOOLEAN InitialCall
  153. );
  154. NTSTATUS
  155. SpGetCommonBuffer(
  156. PDEVICE_EXTENSION DeviceExtension,
  157. ULONG NonCachedExtensionSize
  158. );
  159. BOOLEAN
  160. GetPciConfiguration(
  161. PDRIVER_OBJECT DriverObject,
  162. PDEVICE_OBJECT DeviceObject,
  163. PPORT_CONFIGURATION_INFORMATION ConfigInformation,
  164. ULONG NumberOfAccessRanges,
  165. PVOID RegistryPath,
  166. BOOLEAN IsMultiFunction,
  167. PULONG BusNumber,
  168. PULONG SlotNumber,
  169. PULONG FunctionNumber
  170. );
  171. BOOLEAN
  172. FindPciDevice(
  173. PHW_INITIALIZATION_DATA HwInitializationData,
  174. PULONG BusNumber,
  175. PULONG SlotNumber,
  176. PULONG FunctionNumber,
  177. PBOOLEAN IsMultiFunction
  178. );
  179. #ifdef i386
  180. ULONG
  181. HalpGetCmosData(
  182. IN ULONG SourceLocation,
  183. IN ULONG SourceAddress,
  184. IN PVOID ReturnBuffer,
  185. IN ULONG ByteCount
  186. );
  187. #endif
  188. VOID
  189. ScsiPortInitializeMdlPages (
  190. IN OUT PMDL Mdl
  191. );
  192. SCSI_ADAPTER_CONTROL_STATUS
  193. SpCallAdapterControl(
  194. IN PDEVICE_EXTENSION Adapter,
  195. IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
  196. IN PVOID Parameters
  197. );
  198. VOID
  199. SpGetSupportedAdapterControlFunctions(
  200. PDEVICE_EXTENSION Adapter
  201. );
  202. VOID
  203. SpUnload(
  204. IN PDRIVER_OBJECT DriverObject
  205. );
  206. //
  207. // Routines start
  208. //
  209. BOOLEAN
  210. GetNextPciBus(
  211. PULONG BusNumber
  212. )
  213. /*++
  214. Routine Description:
  215. Advance ConfigInformation to the next PCI bus if one exists in the
  216. system. Advances the bus number and calls HalGetBusDataByOffset to
  217. see if the bus number is valid.
  218. Note: *BusNumber has already been scanned in its entirety, we
  219. simply advance to the start of the next bus. No need to keep
  220. track of where we might be on this bus.
  221. Arguments:
  222. BusNumber Pointer to a ULONG containing the last BusNumber tested.
  223. Will be updated to the next bus number if another PCI
  224. bus exists.
  225. Return Value:
  226. TRUE If ConfigInformation has been advanced,
  227. FALSE If there are not more PCI busses in the system.
  228. --*/
  229. {
  230. ULONG pciBus;
  231. USHORT pciData;
  232. ULONG length = 0;
  233. pciBus = *BusNumber;
  234. DebugPrint((3,"GetNextPciBus: try to advance from bus %d\n", pciBus));
  235. if (++pciBus < 256) {
  236. length = HalGetBusDataByOffset(
  237. PCIConfiguration,
  238. pciBus,
  239. 0, // slot number
  240. &pciData,
  241. 0,
  242. sizeof(pciData));
  243. if (length == sizeof(pciData)) {
  244. //
  245. // HalGetBusDataByOffset returns zero when out of
  246. // busses. If not out of busses it should always
  247. // succeed a length = 2 read at offset 0 even if
  248. // just to return PCI_INVALID_VENDORID.
  249. //
  250. *BusNumber = pciBus;
  251. return TRUE;
  252. }
  253. }
  254. DebugPrint((3,"GetNextPciBus: test bus %d returned %d\n", pciBus, length));
  255. return FALSE;
  256. }
  257. ULONG
  258. ScsiPortInitialize(
  259. IN PVOID Argument1,
  260. IN PVOID Argument2,
  261. IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
  262. IN PVOID HwContext
  263. )
  264. /*++
  265. Routine Description:
  266. This routine initializes the port driver.
  267. Arguments:
  268. Argument1 - Pointer to driver object created by system
  269. HwInitializationData - Miniport initialization structure
  270. HwContext - Value passed to miniport driver's config routine
  271. Return Value:
  272. The function value is the final status from the initialization operation.
  273. --*/
  274. {
  275. PDRIVER_OBJECT driverObject = Argument1;
  276. PDEVICE_EXTENSION deviceExtension;
  277. PDEVICE_OBJECT deviceObject;
  278. BOOLEAN checkAdapterControl = FALSE;
  279. PORT_CONFIGURATION_INFORMATION configInfo;
  280. KEVENT allocateAdapterEvent;
  281. ULONG ExtensionAllocationSize;
  282. ULONG j;
  283. UCHAR scsiBus;
  284. PULONG scsiPortNumber;
  285. ULONG numberOfPageBreaks;
  286. PIO_SCSI_CAPABILITIES capabilities;
  287. BOOLEAN callAgain;
  288. UCHAR ldrString[] = {'n', 't', 'l', 'd','r','=', '1', ';', 0 };
  289. DEVICE_DESCRIPTION deviceDescription;
  290. ARC_CODES status;
  291. BOOLEAN isPci = FALSE;
  292. BOOLEAN isMultiFunction = FALSE;
  293. ULONG busNumber = 0;
  294. ULONG slotNumber = 0;
  295. ULONG functionNumber = 0;
  296. BOOLEAN foundOne = FALSE;
  297. UNREFERENCED_PARAMETER(Argument2);
  298. AEDriverUnloadRoutine = SpUnload;
  299. if (HwInitializationData->HwInitializationDataSize > sizeof(HW_INITIALIZATION_DATA)) {
  300. DebugPrint((0,"ScsiPortInitialize: Miniport driver wrong version\n"));
  301. return EBADF;
  302. }
  303. if (HwInitializationData->HwInitializationDataSize >=
  304. (FIELD_OFFSET(HW_INITIALIZATION_DATA, HwAdapterControl) +
  305. sizeof(PVOID))) {
  306. DebugPrint((2, "ScsiPortInitialize: Miniport may have adapter "
  307. "control routine\n"));
  308. checkAdapterControl = TRUE;
  309. }
  310. //
  311. // Check that each required entry is not NULL.
  312. //
  313. if ((!HwInitializationData->HwInitialize) ||
  314. (!HwInitializationData->HwFindAdapter) ||
  315. (!HwInitializationData->HwResetBus)) {
  316. DebugPrint((0,
  317. "ScsiPortInitialize: Miniport driver missing required entry\n"));
  318. return EBADF;
  319. }
  320. CallAgain:
  321. //
  322. // Get the configuration information
  323. //
  324. scsiPortNumber = &ScsiPortCount;
  325. //
  326. // Determine if there is room for the next port device object.
  327. //
  328. if (*scsiPortNumber >= MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS) {
  329. return foundOne ? ESUCCESS : EIO;
  330. }
  331. //
  332. // If this is a PCI card then do a quick scan to see if we can find
  333. // the device.
  334. //
  335. if (HwInitializationData->AdapterInterfaceType == PCIBus &&
  336. HwInitializationData->VendorIdLength > 0 &&
  337. HwInitializationData->DeviceIdLength > 0 &&
  338. HwInitializationData->DeviceId &&
  339. HwInitializationData->VendorId) {
  340. if (!FindPciDevice(HwInitializationData,
  341. &busNumber,
  342. &slotNumber,
  343. &functionNumber,
  344. &isMultiFunction)) {
  345. DebugPrint((1,
  346. "ScsiPortInitialize: FindPciDevice failed\n"));
  347. return foundOne ? ESUCCESS : EIO;
  348. }
  349. isPci = TRUE;
  350. }
  351. //
  352. // Determine size of extensions.
  353. //
  354. ExtensionAllocationSize = DEVICE_EXTENSION_SIZE +
  355. HwInitializationData->DeviceExtensionSize + sizeof(DEVICE_OBJECT);
  356. deviceObject = ExAllocatePool(NonPagedPool, ExtensionAllocationSize);
  357. if (deviceObject == NULL) {
  358. return ENOMEM;
  359. }
  360. RtlZeroMemory(deviceObject, ExtensionAllocationSize);
  361. //
  362. // Set up device extension pointers
  363. //
  364. deviceExtension = deviceObject->DeviceExtension = (PVOID) (deviceObject + 1);
  365. deviceExtension->DeviceObject = deviceObject;
  366. //
  367. // Save the dependent driver routines in the device extension.
  368. //
  369. deviceExtension->HwInitialize = HwInitializationData->HwInitialize;
  370. deviceExtension->HwStartIo = HwInitializationData->HwStartIo;
  371. deviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
  372. deviceExtension->HwReset = HwInitializationData->HwResetBus;
  373. deviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
  374. deviceExtension->HwLogicalUnitExtensionSize =
  375. HwInitializationData->SpecificLuExtensionSize;
  376. if(checkAdapterControl) {
  377. deviceExtension->HwAdapterControl = HwInitializationData->HwAdapterControl;
  378. }
  379. deviceExtension->HwDeviceExtension =
  380. (PVOID)(deviceExtension + 1);
  381. //
  382. // Set indicater as to whether adapter needs kernel mapped buffers.
  383. //
  384. deviceExtension->MapBuffers = HwInitializationData->MapBuffers;
  385. //
  386. // Mark this object as supporting direct I/O so that I/O system
  387. // will supply mdls in irps.
  388. //
  389. deviceObject->Flags |= DO_DIRECT_IO;
  390. //
  391. // Check if miniport driver requires any noncached memory.
  392. // SRB extensions will come from zoned memory. A page is
  393. // allocated as it is the smallest unit of noncached memory
  394. // allocation.
  395. //
  396. deviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
  397. //
  398. // Get the miniport configuration information.
  399. //
  400. capabilities = &deviceExtension->Capabilities;
  401. capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
  402. callAgain = FALSE;
  403. //
  404. // This call can't really fail - if it does something is seriously wrong and
  405. // should fail on the first try.
  406. //
  407. if (!NT_SUCCESS(SpInitializeConfiguration(
  408. deviceExtension,
  409. HwInitializationData,
  410. &configInfo,
  411. TRUE
  412. ))) {
  413. DebugPrint((2, "ScsiPortInitialize: No config info found\n"));
  414. return(ENODEV);
  415. }
  416. configInfo.NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
  417. configInfo.AccessRanges = ExAllocatePool(NonPagedPool,
  418. sizeof(ACCESS_RANGE) *
  419. HwInitializationData->NumberOfAccessRanges);
  420. if (configInfo.AccessRanges == NULL) {
  421. //
  422. // We're out of memory - it's probably not worth continuing on to
  423. // try and find more adapters.
  424. //
  425. return (foundOne ? ESUCCESS : EIO);
  426. }
  427. RtlZeroMemory(configInfo.AccessRanges,
  428. HwInitializationData->NumberOfAccessRanges * sizeof(ACCESS_RANGE));
  429. //
  430. // Initialize configuration information with slot information if PCI bus.
  431. //
  432. if (isPci) {
  433. if (!GetPciConfiguration(driverObject,
  434. deviceObject,
  435. &configInfo,
  436. HwInitializationData->NumberOfAccessRanges,
  437. Argument2,
  438. isMultiFunction,
  439. &busNumber,
  440. &slotNumber,
  441. &functionNumber)) {
  442. DebugPrint((1,
  443. "ScsiPortInitialize: GetPciConfiguration failed\n"));
  444. return foundOne ? ESUCCESS : EIO;
  445. }
  446. //
  447. // Call miniport driver's find adapter routine to search for adapters.
  448. //
  449. if (HwInitializationData->HwFindAdapter(
  450. deviceExtension->HwDeviceExtension, // DeviceExtension
  451. HwContext, // HwContext
  452. NULL, // BusInformation
  453. (PCHAR)ldrString, // ArgumentString
  454. &configInfo, // ConfigurationInformation
  455. &callAgain // Again
  456. ) != SP_RETURN_FOUND) {
  457. return foundOne ? ESUCCESS : EIO;
  458. }
  459. } else {
  460. //
  461. // Not PCI, or PCI but the miniport is fundamentally broken
  462. // and wants to do its own search.
  463. //
  464. //
  465. // Starting at the current config, examine each bus
  466. // until we run out of busses.
  467. //
  468. configInfo.SystemIoBusNumber = busNumber;
  469. if (HwInitializationData->HwFindAdapter(
  470. deviceExtension->HwDeviceExtension, // DeviceExtension
  471. HwContext, // HwContext
  472. NULL, // BusInformation
  473. (PCHAR)ldrString, // ArgumentString
  474. &configInfo, // ConfigurationInformation
  475. &callAgain // Again
  476. ) != SP_RETURN_FOUND) {
  477. //
  478. // No device found on this bus, try next bus.
  479. //
  480. if ((HwInitializationData->AdapterInterfaceType != PCIBus) ||
  481. !GetNextPciBus(&busNumber)) {
  482. return foundOne ? ESUCCESS : EIO;
  483. }
  484. goto CallAgain;
  485. }
  486. }
  487. DebugPrint((1,"ScsiPortInitialize: SCSI adapter IRQ is %d\n",
  488. configInfo.BusInterruptLevel));
  489. DebugPrint((1,"ScsiPortInitialize: SCSI adapter ID is %d\n",
  490. configInfo.InitiatorBusId[0]));
  491. deviceExtension->NumberOfBuses = configInfo.NumberOfBuses;
  492. //
  493. // Free the pointer to the bus data at map register base. This was
  494. // allocated by ScsiPortGetBusData.
  495. //
  496. if (deviceExtension->MapRegisterBase != NULL) {
  497. ExFreePool(deviceExtension->MapRegisterBase);
  498. }
  499. //
  500. // Get the adapter object for this card.
  501. //
  502. if ( deviceExtension->DmaAdapterObject == NULL &&
  503. (configInfo.Master || configInfo.DmaChannel != 0xFFFFFFFF) ) {
  504. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  505. deviceDescription.DmaChannel = configInfo.DmaChannel;
  506. deviceDescription.InterfaceType = configInfo.AdapterInterfaceType;
  507. deviceDescription.BusNumber = configInfo.SystemIoBusNumber;
  508. deviceDescription.DmaWidth = configInfo.DmaWidth;
  509. deviceDescription.DmaSpeed = configInfo.DmaSpeed;
  510. deviceDescription.DmaPort = configInfo.DmaPort;
  511. deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
  512. deviceDescription.ScatterGather = configInfo.ScatterGather;
  513. deviceDescription.Master = configInfo.Master;
  514. deviceDescription.AutoInitialize = FALSE;
  515. deviceDescription.DemandMode = FALSE;
  516. if (configInfo.MaximumTransferLength > 0x11000) {
  517. deviceDescription.MaximumLength = 0x11000;
  518. } else {
  519. deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
  520. }
  521. deviceExtension->DmaAdapterObject = HalGetAdapter(
  522. &deviceDescription,
  523. &numberOfPageBreaks
  524. );
  525. //
  526. // Set maximum number of page breaks.
  527. //
  528. if (numberOfPageBreaks > configInfo.NumberOfPhysicalBreaks) {
  529. capabilities->MaximumPhysicalPages = configInfo.NumberOfPhysicalBreaks;
  530. } else {
  531. capabilities->MaximumPhysicalPages = numberOfPageBreaks;
  532. }
  533. }
  534. //
  535. // Allocate memory for the non cached extension if it has not already been
  536. // allocated. If we can't get any abort the search for adapters but
  537. // succeed if we've managed to initialize at least one.
  538. //
  539. if (deviceExtension->SrbExtensionSize != 0 &&
  540. deviceExtension->SrbExtensionZonePool == NULL) {
  541. status = SpGetCommonBuffer(deviceExtension, 0);
  542. if (status != ESUCCESS) {
  543. return (foundOne ? ESUCCESS : status);
  544. }
  545. }
  546. capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
  547. capabilities->MaximumTransferLength = configInfo.MaximumTransferLength;
  548. DebugPrint((1,
  549. "Maximum physical page breaks = %d. Maximum transfer length = %x\n",
  550. capabilities->MaximumPhysicalPages,
  551. capabilities->MaximumTransferLength));
  552. if (HwInitializationData->ReceiveEvent) {
  553. capabilities->SupportedAsynchronousEvents |=
  554. SRBEV_SCSI_ASYNC_NOTIFICATION;
  555. }
  556. capabilities->TaggedQueuing = HwInitializationData->TaggedQueuing;
  557. capabilities->AdapterScansDown = configInfo.AdapterScansDown;
  558. capabilities->AlignmentMask = configInfo.AlignmentMask;
  559. //
  560. // Make sure maximum nuber of pages is set to a reasonable value.
  561. // This occurs for mini-ports with no Dma adapter.
  562. //
  563. if (capabilities->MaximumPhysicalPages == 0) {
  564. capabilities->MaximumPhysicalPages =
  565. (ULONG)ROUND_TO_PAGES(capabilities->MaximumTransferLength) + 1;
  566. //
  567. // Honor any limit requested by the mini-port.
  568. //
  569. if (configInfo.NumberOfPhysicalBreaks < capabilities->MaximumPhysicalPages) {
  570. capabilities->MaximumPhysicalPages =
  571. configInfo.NumberOfPhysicalBreaks;
  572. }
  573. }
  574. //
  575. // Get maximum target IDs.
  576. //
  577. if (configInfo.MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) {
  578. deviceExtension->MaximumTargetIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
  579. } else {
  580. deviceExtension->MaximumTargetIds =
  581. configInfo.MaximumNumberOfTargets;
  582. }
  583. if (deviceExtension->DmaAdapterObject != NULL &&
  584. !HwInitializationData->NeedPhysicalAddresses) {
  585. //
  586. // Allocate the adapter object. For the port driver the adapter object
  587. // and map registers are permentently allocated and used shared between
  588. // all logical units. The adapter is allocated by initializing an event,
  589. // calling IoAllocateAdapterChannel and waiting on the event. When the
  590. // adapter and map registers are available, ScsiPortAllocationRoutine is
  591. // called which set the event. In reality, all this takes zero time since
  592. // the stuff is available immediately.
  593. //
  594. // Allocate the AdapterObject. The number of registers is equal to the
  595. // maximum transfer length supported by the adapter + 1. This insures
  596. // that there will always be a sufficient number of registers.
  597. //
  598. /* TODO: Fix this for the case when there is no maximum transfer length. */
  599. IoAllocateAdapterChannel(
  600. deviceExtension->DmaAdapterObject,
  601. deviceObject,
  602. capabilities->MaximumPhysicalPages,
  603. ScsiPortAllocationRoutine,
  604. &allocateAdapterEvent
  605. );
  606. //
  607. // Wait for adapter object.
  608. //
  609. ASSERT(deviceExtension->MapRegisterBase);
  610. deviceExtension->MasterWithAdapter = FALSE;
  611. } else if (deviceExtension->DmaAdapterObject != NULL) {
  612. //
  613. // This SCSI adapter is a master with an adapter so a scatter/gather
  614. // list needs to be allocated for each transfer.
  615. //
  616. deviceExtension->MasterWithAdapter = TRUE;
  617. } else {
  618. deviceExtension->MasterWithAdapter = FALSE;
  619. } // end if (deviceExtension->DmaAdapterObject != NULL)
  620. //
  621. // Call the hardware dependent driver to do its initialization. If it fails
  622. // then continue the search for adapters.
  623. //
  624. if (!KeSynchronizeExecution(
  625. deviceExtension->InterruptObject,
  626. deviceExtension->HwInitialize,
  627. deviceExtension->HwDeviceExtension
  628. )) {
  629. DebugPrint((1,"ScsiPortInitialize: initialization failed\n"));
  630. if(callAgain) {
  631. goto CallAgain;
  632. } else {
  633. return foundOne ? ESUCCESS : ENODEV;
  634. }
  635. }
  636. //
  637. // Find out if the miniport supports AdapterControl routines to shutdown.
  638. //
  639. SpGetSupportedAdapterControlFunctions(deviceExtension);
  640. //
  641. // Allocate properly aligned INQUIRY buffer. If we can't get one we're
  642. // out of memory so searching for more adapters is pointless.
  643. //
  644. InquiryDataBuffer = ExAllocatePool(NonPagedPool, INQUIRYDATABUFFERSIZE);
  645. if (InquiryDataBuffer == NULL) {
  646. return foundOne ? ESUCCESS : ENOMEM;
  647. }
  648. //
  649. // Reset the scsi bus.
  650. //
  651. if (!deviceExtension->HwReset(
  652. deviceExtension->HwDeviceExtension,
  653. 0)){
  654. DebugPrint((1,"Reset SCSI bus failed\n"));
  655. }
  656. //
  657. // Call the interupt handler for a few microseconds to clear any reset
  658. // interrupts.
  659. //
  660. for (j = 0; j < 1000 * 100; j++) {
  661. FwStallExecution(10);
  662. if (deviceExtension->HwInterrupt != NULL) {
  663. deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension);
  664. }
  665. }
  666. deviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
  667. SpCheckResetDelay( deviceExtension );
  668. //
  669. // Find devices on each SCSI bus.
  670. //
  671. //
  672. // Allocate buffer for SCSI bus scan information.
  673. //
  674. deviceExtension->ScsiInfo = ExAllocatePool(NonPagedPool,
  675. deviceExtension->NumberOfBuses * sizeof(PSCSI_BUS_SCAN_DATA) +
  676. 4);
  677. if (deviceExtension->ScsiInfo) {
  678. deviceExtension->ScsiInfo->NumberOfBuses = deviceExtension->NumberOfBuses;
  679. //
  680. // Find devices on each SCSI bus.
  681. //
  682. for (scsiBus = 0; scsiBus < deviceExtension->NumberOfBuses; scsiBus++) {
  683. deviceExtension->ScsiInfo->BusScanData[scsiBus] =
  684. ScsiBusScan(deviceExtension,
  685. scsiBus,
  686. configInfo.InitiatorBusId[scsiBus]);
  687. }
  688. }
  689. //
  690. // Save the device object for use by the driver.
  691. //
  692. ScsiPortDeviceObject[*scsiPortNumber] = deviceObject;
  693. //
  694. // Bump SCSI host bus adapters count.
  695. //
  696. (*scsiPortNumber)++;
  697. foundOne = TRUE;
  698. //
  699. // If the adapter wants to be called again with the same configuration data
  700. // then start over from the beginning again.
  701. //
  702. if (callAgain) {
  703. goto CallAgain;
  704. }
  705. return ESUCCESS;
  706. } // end ScsiPortInitialize()
  707. IO_ALLOCATION_ACTION
  708. ScsiPortAllocationRoutine (
  709. IN PDEVICE_OBJECT DeviceObject,
  710. IN PIRP Irp,
  711. IN PVOID MapRegisterBase,
  712. IN PVOID Context
  713. )
  714. /*++
  715. Routine Description:
  716. This function is called by IoAllocateAdapterChannel when sufficent resources
  717. are available to the driver. This routine saves the MapRegisterBase in the
  718. device object and set the event pointed to by the context parameter.
  719. Arguments:
  720. DeviceObject - Pointer to the device object to which the adapter is being
  721. allocated.
  722. Irp - Unused.
  723. MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer.
  724. Context - Supplies a pointer to an event which is set to indicate the
  725. AdapterObject has been allocated.
  726. Return Value:
  727. KeepObject - Indicates the adapter and mapregisters should remain allocated
  728. after return.
  729. --*/
  730. {
  731. ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->MapRegisterBase =
  732. MapRegisterBase;
  733. UNREFERENCED_PARAMETER(Irp);
  734. UNREFERENCED_PARAMETER(Context);
  735. return(KeepObject);
  736. }
  737. IO_ALLOCATION_ACTION
  738. SpBuildScatterGather(
  739. IN struct _DEVICE_OBJECT *DeviceObject,
  740. IN struct _IRP *Irp,
  741. IN PVOID MapRegisterBase,
  742. IN PVOID Context
  743. )
  744. /*++
  745. Routine Description:
  746. This function is called by the I/O system when an adapter object and map
  747. registers have been allocated. This routine then builds a scatter/gather
  748. list for use by the mini-port driver. Next it sets the timeout and
  749. the current Irp for the logical unit. Finally it calls the mini-port
  750. StartIo routine. Once that routines complete, this routine will return
  751. requesting that the adapter be freed and but the registers remain allocated.
  752. The registers will be freed the request completes.
  753. Arguments:
  754. DeviceObject - Supplies a pointer to the port driver device object.
  755. Irp - Supplies a pointer to the current Irp.
  756. MapRegisterBase - Supplies a context pointer to be used with calls the
  757. adapter object routines.
  758. Context - Supplies a pointer to the logical unit structure.
  759. Return Value:
  760. Returns DeallocateObjectKeepRegisters so that the adapter object can be
  761. used by other logical units.
  762. --*/
  763. {
  764. BOOLEAN writeToDevice;
  765. PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
  766. PLOGICAL_UNIT_EXTENSION logicalUnit;
  767. PSCSI_REQUEST_BLOCK srb;
  768. PSRB_SCATTER_GATHER scatterList;
  769. ULONG totalLength;
  770. logicalUnit = Context;
  771. srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  772. scatterList = logicalUnit->ScatterGather;
  773. totalLength = 0;
  774. //
  775. // Save the MapRegisterBase for later use to deallocate the map registers.
  776. //
  777. logicalUnit->MapRegisterBase = MapRegisterBase;
  778. //
  779. // Build the scatter/gather list by looping throught the transfer calling
  780. // I/O map transfer.
  781. //
  782. writeToDevice = srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
  783. while (totalLength < srb->DataTransferLength) {
  784. //
  785. // Request that the rest of the transfer be mapped.
  786. //
  787. scatterList->Length = srb->DataTransferLength - totalLength;
  788. //
  789. // Since we are a master call I/O map transfer with a NULL adapter.
  790. //
  791. scatterList->PhysicalAddress = IoMapTransfer(
  792. NULL,
  793. Irp->MdlAddress,
  794. MapRegisterBase,
  795. (PCCHAR) srb->DataBuffer + totalLength,
  796. &scatterList->Length,
  797. writeToDevice
  798. ).LowPart;
  799. totalLength += scatterList->Length;
  800. scatterList++;
  801. }
  802. //
  803. // Set request timeout value from Srb SCSI extension in Irp.
  804. //
  805. logicalUnit->RequestTimeoutCounter = srb->TimeOutValue;
  806. //
  807. // Set current request for this logical unit.
  808. //
  809. logicalUnit->CurrentRequest = Irp;
  810. /* TODO: Check the return value. */
  811. KeSynchronizeExecution(
  812. ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->InterruptObject,
  813. SpStartIoSynchronized,
  814. DeviceObject
  815. );
  816. return(DeallocateObjectKeepRegisters);
  817. }
  818. VOID
  819. ScsiPortExecute(
  820. IN PDEVICE_OBJECT DeviceObject,
  821. IN PIRP Irp
  822. )
  823. /*++
  824. Routine Description:
  825. This routine calls the start I/O routine an waits for the request to
  826. complete. During the wait for complete the interrupt routine is called,
  827. also the timer routines are called at the appropriate times. After the
  828. request completes a check is made to determine if an request sense needs
  829. to be issued.
  830. Arguments:
  831. DeviceObject - Supplies pointer to Adapter device object.
  832. Irp - Supplies a pointer to an IRP.
  833. Return Value:
  834. Nothing.
  835. --*/
  836. {
  837. ULONG milliSecondTime;
  838. ULONG secondTime;
  839. ULONG completionDelay;
  840. PDEVICE_EXTENSION deviceExtension;
  841. PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
  842. PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  843. PVOID logicalUnit;
  844. deviceExtension = DeviceObject->DeviceExtension;
  845. logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
  846. if (logicalUnit == NULL) {
  847. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  848. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  849. return;
  850. }
  851. //
  852. // Make sure the adapter is ready to accept requests.
  853. //
  854. SpCheckResetDelay( deviceExtension );
  855. //
  856. // Mark IRP as pending.
  857. //
  858. Irp->PendingReturned = TRUE;
  859. //
  860. // Start the request.
  861. //
  862. ScsiPortStartIo( DeviceObject, Irp);
  863. //
  864. // The completion delay controls how long interrupts are serviced after
  865. // a request has been completed. This allows interrupts which occur after
  866. // a completion to be serviced.
  867. //
  868. completionDelay = COMPLETION_DELAY;
  869. //
  870. // Wait for the IRP to complete.
  871. //
  872. while (Irp->PendingReturned && completionDelay) {
  873. //
  874. // Wait 1 second then call the scsi port timer routine.
  875. //
  876. for (secondTime = 0; secondTime < 1000/ 250; secondTime++) {
  877. for (milliSecondTime = 0; milliSecondTime < (250 * 1000 / PD_INTERLOOP_STALL); milliSecondTime++) {
  878. ScsiPortInterrupt(NULL, DeviceObject);
  879. if (!Irp->PendingReturned) {
  880. if (completionDelay-- == 0) {
  881. goto done;
  882. }
  883. }
  884. if (deviceExtension->Flags & PD_ENABLE_CALL_REQUEST) {
  885. //
  886. // Call the mini-port requested routine.
  887. //
  888. deviceExtension->Flags &= ~PD_ENABLE_CALL_REQUEST;
  889. deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
  890. if (deviceExtension->Flags & PD_DISABLE_CALL_REQUEST) {
  891. deviceExtension->Flags &= ~(PD_DISABLE_INTERRUPTS | PD_DISABLE_CALL_REQUEST);
  892. deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
  893. }
  894. }
  895. if (deviceExtension->Flags & PD_CALL_DMA_STARTED) {
  896. deviceExtension->Flags &= ~PD_CALL_DMA_STARTED;
  897. //
  898. // Notify the mini-port driver that the DMA has been
  899. // started.
  900. //
  901. if (deviceExtension->HwDmaStarted) {
  902. KeSynchronizeExecution(
  903. &deviceExtension->InterruptObject,
  904. (PKSYNCHRONIZE_ROUTINE) deviceExtension->HwDmaStarted,
  905. deviceExtension->HwDeviceExtension
  906. );
  907. }
  908. }
  909. FwStallExecution(PD_INTERLOOP_STALL);
  910. //
  911. // Check the miniport timer.
  912. //
  913. if (deviceExtension->TimerValue != 0) {
  914. deviceExtension->TimerValue--;
  915. if (deviceExtension->TimerValue == 0) {
  916. //
  917. // The timer timed out so called requested timer routine.
  918. //
  919. deviceExtension->HwTimerRequest(deviceExtension->HwDeviceExtension);
  920. }
  921. }
  922. }
  923. }
  924. ScsiPortTickHandler(DeviceObject, NULL);
  925. }
  926. done:
  927. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  928. PSCSI_REQUEST_BLOCK Srb;
  929. irpstack = IoGetCurrentIrpStackLocation(Irp);
  930. Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  931. //
  932. // Determine if a REQUEST SENSE command needs to be done.
  933. // Check that a CHECK_CONDITION was received, an autosense has not
  934. // been done already, and that autosense has been requested.
  935. //
  936. if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
  937. !(srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  938. srb->SenseInfoBuffer) {
  939. //
  940. // Call IssueRequestSense and it will complete the request after
  941. // the REQUEST SENSE completes.
  942. //
  943. IssueRequestSense(deviceExtension, Srb);
  944. }
  945. }
  946. }
  947. VOID
  948. ScsiPortStartIo (
  949. IN PDEVICE_OBJECT DeviceObject,
  950. IN PIRP Irp
  951. )
  952. /*++
  953. Routine Description:
  954. Arguments:
  955. DeviceObject - Supplies pointer to Adapter device object.
  956. Irp - Supplies a pointer to an IRP.
  957. Return Value:
  958. Nothing.
  959. --*/
  960. {
  961. PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
  962. PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  963. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  964. PLOGICAL_UNIT_EXTENSION logicalUnit;
  965. PFULL_SCSI_REQUEST_BLOCK FullSrb;
  966. NTSTATUS status;
  967. DebugPrint((3,"ScsiPortStartIo: Enter routine\n"));
  968. FullSrb = CONTAINING_RECORD(Srb, FULL_SCSI_REQUEST_BLOCK, Srb);
  969. if (deviceExtension->SrbExtensionZonePool &&
  970. (Srb->SrbExtension == NULL ||
  971. (deviceExtension->SrbExtensionSize > FullSrb->SrbExtensionSize))) {
  972. //
  973. // Allocate SRB extension from zone.
  974. //
  975. Srb->SrbExtension = deviceExtension->SrbExtensionPointer;
  976. (PCCHAR) deviceExtension->SrbExtensionPointer +=
  977. deviceExtension->SrbExtensionSize;
  978. FullSrb->SrbExtensionSize = deviceExtension->SrbExtensionSize;
  979. if ((ULONG_PTR) deviceExtension->SrbExtensionPointer >
  980. (ULONG_PTR) deviceExtension->NonCachedExtension) {
  981. DebugPrint((0, "NtLdr: ScsiPortStartIo: Srb extension overflow. Too many srb extension allocated.\n"));
  982. DbgBreakPoint();
  983. }
  984. DebugPrint((3,"ExInterlockedAllocateFromZone: %lx\n",
  985. Srb->SrbExtension));
  986. DebugPrint((3,"Srb %lx\n",Srb));
  987. }
  988. //
  989. // Get logical unit extension.
  990. //
  991. logicalUnit = GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
  992. //
  993. // Flush the data buffer if necessary.
  994. //
  995. if (Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) {
  996. if (Srb->DataTransferLength > deviceExtension->Capabilities.MaximumTransferLength) {
  997. DebugPrint((1, "Scsiboot: ScsiPortStartIo Length Exceeds limit %x, %x\n",
  998. Srb->DataTransferLength,
  999. deviceExtension->Capabilities.MaximumTransferLength));
  1000. }
  1001. KeFlushIoBuffers(
  1002. Irp->MdlAddress,
  1003. (BOOLEAN) (Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE),
  1004. TRUE
  1005. );
  1006. //
  1007. // Determine if this adapter needs map registers
  1008. //
  1009. if (deviceExtension->MasterWithAdapter) {
  1010. //
  1011. // Calculate the number of map registers needed for this transfer.
  1012. //
  1013. logicalUnit->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  1014. Srb->DataBuffer,
  1015. Srb->DataTransferLength
  1016. );
  1017. //
  1018. // Allocate the adapter channel with sufficient map registers
  1019. // for the transfer.
  1020. //
  1021. status = IoAllocateAdapterChannel(
  1022. deviceExtension->DmaAdapterObject, // AdapterObject
  1023. DeviceObject, // DeviceObject.
  1024. logicalUnit->NumberOfMapRegisters, // NumberOfMapRegisters
  1025. SpBuildScatterGather, // ExecutionRoutine
  1026. logicalUnit // Context
  1027. );
  1028. if (!NT_SUCCESS(status)) {
  1029. ;
  1030. }
  1031. //
  1032. // The execution routine called by IoAllocateChannel will do the
  1033. // rest of the work so just return.
  1034. //
  1035. return;
  1036. }
  1037. }
  1038. //
  1039. // Set request timeout value from Srb SCSI extension in Irp.
  1040. //
  1041. logicalUnit->RequestTimeoutCounter = Srb->TimeOutValue;
  1042. //
  1043. // Set current request for this logical unit.
  1044. //
  1045. logicalUnit->CurrentRequest = Irp;
  1046. /* TODO: Check the return value. */
  1047. KeSynchronizeExecution(
  1048. deviceExtension->InterruptObject,
  1049. SpStartIoSynchronized,
  1050. DeviceObject
  1051. );
  1052. return;
  1053. } // end ScsiPortStartIO()
  1054. BOOLEAN
  1055. SpStartIoSynchronized (
  1056. PVOID ServiceContext
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. This routine calls the dependent driver start io routine.
  1061. Arguments:
  1062. ServiceContext - Supplies the pointer to the device object.
  1063. Return Value:
  1064. Returns the value returned by the dependent start I/O routine.
  1065. --*/
  1066. {
  1067. PDEVICE_OBJECT DeviceObject = ServiceContext;
  1068. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1069. PIO_STACK_LOCATION irpstack;
  1070. PSCSI_REQUEST_BLOCK Srb;
  1071. DebugPrint((3, "ScsiPortStartIoSynchronized: Enter routine\n"));
  1072. irpstack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
  1073. Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  1074. DebugPrint((3, "SpPortStartIoSynchronized: SRB %lx\n",
  1075. Srb));
  1076. DebugPrint((3, "SpPortStartIoSynchronized: IRP %lx\n",
  1077. DeviceObject->CurrentIrp));
  1078. //
  1079. // Disable all synchronous transfers.
  1080. //
  1081. Srb->SrbFlags |=
  1082. (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT | SRB_FLAGS_DISABLE_AUTOSENSE);
  1083. return deviceExtension->HwStartIo(
  1084. deviceExtension->HwDeviceExtension,
  1085. Srb
  1086. );
  1087. } // end SpStartIoSynchronized()
  1088. BOOLEAN
  1089. ScsiPortInterrupt(
  1090. IN PKINTERRUPT Interrupt,
  1091. IN PDEVICE_OBJECT DeviceObject
  1092. )
  1093. /*++
  1094. Routine Description:
  1095. Arguments:
  1096. Interrupt
  1097. Device Object
  1098. Return Value:
  1099. Returns TRUE if interrupt expected.
  1100. --*/
  1101. {
  1102. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1103. UNREFERENCED_PARAMETER(Interrupt);
  1104. if (deviceExtension->Flags & PD_DISABLE_INTERRUPTS) {
  1105. return FALSE;
  1106. }
  1107. if (deviceExtension->HwInterrupt != NULL) {
  1108. if (deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension)) {
  1109. return TRUE;
  1110. } else {
  1111. return FALSE;
  1112. }
  1113. }
  1114. return(FALSE);
  1115. } // end ScsiPortInterrupt()
  1116. VOID
  1117. ScsiPortCompletionDpc(
  1118. IN PKDPC Dpc,
  1119. IN PDEVICE_OBJECT DeviceObject,
  1120. IN PIRP Irp,
  1121. IN PVOID Context
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. Arguments:
  1126. Dpc
  1127. DeviceObject
  1128. Irp - not used
  1129. Context - not used
  1130. Return Value:
  1131. None.
  1132. --*/
  1133. {
  1134. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1135. PIO_STACK_LOCATION irpstack;
  1136. PSCSI_REQUEST_BLOCK Srb;
  1137. PLOGICAL_UNIT_EXTENSION luExtension;
  1138. UNREFERENCED_PARAMETER(Dpc);
  1139. UNREFERENCED_PARAMETER(Context);
  1140. DebugPrint((3, "ScsiPortCompletionDpc Entered\n"));
  1141. //
  1142. // Acquire the spinlock to protect the flags structure and the saved
  1143. // interrupt context.
  1144. //
  1145. KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
  1146. //
  1147. // Check for a flush DMA adapter object request.
  1148. //
  1149. if (deviceExtension->InterruptFlags & PD_FLUSH_ADAPTER_BUFFERS) {
  1150. //
  1151. // Call IoFlushAdapterBuffers using the parameters saved from the last
  1152. // IoMapTransfer call.
  1153. //
  1154. IoFlushAdapterBuffers(
  1155. deviceExtension->DmaAdapterObject,
  1156. ((PIRP)deviceExtension->FlushAdapterParameters.Srb->OriginalRequest)
  1157. ->MdlAddress,
  1158. deviceExtension->MapRegisterBase,
  1159. deviceExtension->FlushAdapterParameters.LogicalAddress,
  1160. deviceExtension->FlushAdapterParameters.Length,
  1161. (BOOLEAN)(deviceExtension->FlushAdapterParameters.Srb->SrbFlags
  1162. & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
  1163. );
  1164. deviceExtension->InterruptFlags &= ~PD_FLUSH_ADAPTER_BUFFERS;
  1165. }
  1166. //
  1167. // Check for an IoMapTransfer DMA request.
  1168. //
  1169. if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
  1170. //
  1171. // Call IoMapTransfer using the parameters saved from the
  1172. // interrupt level.
  1173. //
  1174. IoMapTransfer(
  1175. deviceExtension->DmaAdapterObject,
  1176. ((PIRP)deviceExtension->MapTransferParameters.Srb->OriginalRequest)
  1177. ->MdlAddress,
  1178. deviceExtension->MapRegisterBase,
  1179. deviceExtension->MapTransferParameters.LogicalAddress,
  1180. &deviceExtension->MapTransferParameters.Length,
  1181. (BOOLEAN)(deviceExtension->MapTransferParameters.Srb->SrbFlags
  1182. & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
  1183. );
  1184. //
  1185. // Save the paramters for IoFlushAdapterBuffers.
  1186. //
  1187. deviceExtension->FlushAdapterParameters =
  1188. deviceExtension->MapTransferParameters;
  1189. deviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
  1190. deviceExtension->Flags |= PD_CALL_DMA_STARTED;
  1191. }
  1192. //
  1193. // Process any completed requests.
  1194. //
  1195. while (deviceExtension->CompletedRequests != NULL) {
  1196. Irp = deviceExtension->CompletedRequests;
  1197. irpstack = IoGetCurrentIrpStackLocation(Irp);
  1198. Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  1199. luExtension =
  1200. GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
  1201. DebugPrint((3, "ScsiPortCompletionDpc: SRB %lx\n", Srb));
  1202. DebugPrint((3, "ScsiPortCompletionDpc: IRP %lx\n", Irp));
  1203. //
  1204. // Remove the request from the linked-list.
  1205. //
  1206. deviceExtension->CompletedRequests =
  1207. irpstack->Parameters.Others.Argument3;
  1208. //
  1209. // Check for very unlikely return of NULL.
  1210. //
  1211. if (luExtension == NULL) {
  1212. ASSERT(luExtension != NULL); // Debug why this happened. It should not.
  1213. //
  1214. // But in retail, if some reason it did, complete the IRP and continue.
  1215. //
  1216. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1217. Irp->IoStatus.Information = Srb->DataTransferLength;
  1218. //
  1219. // Free SrbExtension if allocated.
  1220. //
  1221. if (Srb->SrbExtension == (deviceExtension->SrbExtensionPointer -
  1222. deviceExtension->SrbExtensionSize) ) {
  1223. Srb->SrbExtension = NULL;
  1224. (PCCHAR) deviceExtension->SrbExtensionPointer -=
  1225. deviceExtension->SrbExtensionSize;
  1226. }
  1227. IoCompleteRequest(Irp, 2);
  1228. continue;
  1229. }
  1230. //
  1231. // Reset request timeout counter.
  1232. //
  1233. luExtension->RequestTimeoutCounter = -1;
  1234. //
  1235. // Flush the adapter buffers if necessary.
  1236. //
  1237. if (luExtension->MapRegisterBase) {
  1238. //
  1239. // Since we are a master call I/O flush adapter buffers with a NULL
  1240. // adapter.
  1241. //
  1242. IoFlushAdapterBuffers(
  1243. NULL,
  1244. Irp->MdlAddress,
  1245. luExtension->MapRegisterBase,
  1246. Srb->DataBuffer,
  1247. Srb->DataTransferLength,
  1248. (BOOLEAN) (Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
  1249. );
  1250. //
  1251. // Free the map registers.
  1252. //
  1253. IoFreeMapRegisters(
  1254. deviceExtension->DmaAdapterObject,
  1255. luExtension->MapRegisterBase,
  1256. luExtension->NumberOfMapRegisters
  1257. );
  1258. //
  1259. // Clear the MapRegisterBase.
  1260. //
  1261. luExtension->MapRegisterBase = NULL;
  1262. }
  1263. //
  1264. // Set IRP status. Class drivers will reset IRP status based
  1265. // on request sense if error.
  1266. //
  1267. if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
  1268. Irp->IoStatus.Status = STATUS_SUCCESS;
  1269. } else {
  1270. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1271. }
  1272. //
  1273. // Move bytes transfered to IRP.
  1274. //
  1275. Irp->IoStatus.Information = Srb->DataTransferLength;
  1276. //
  1277. // If success then start next packet.
  1278. // Not starting packet effectively
  1279. // freezes the queue.
  1280. //
  1281. if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
  1282. DebugPrint((
  1283. 2,
  1284. "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
  1285. Irp));
  1286. //
  1287. // Free SrbExtension if allocated.
  1288. //
  1289. if (Srb->SrbExtension == (deviceExtension->SrbExtensionPointer -
  1290. deviceExtension->SrbExtensionSize) ) {
  1291. Srb->SrbExtension = NULL;
  1292. (PCCHAR) deviceExtension->SrbExtensionPointer -=
  1293. deviceExtension->SrbExtensionSize;
  1294. }
  1295. IoCompleteRequest(Irp, 2);
  1296. } else {
  1297. if ( Srb->ScsiStatus == SCSISTAT_BUSY &&
  1298. (luExtension->RetryCount++ < 20)) {
  1299. //
  1300. // If busy status is returned, then indicate that the logical
  1301. // unit is busy. The timeout code will restart the request
  1302. // when it fires. Reset the status to pending.
  1303. //
  1304. Srb->SrbStatus = SRB_STATUS_PENDING;
  1305. luExtension->CurrentRequest = Irp;
  1306. luExtension->Flags |= PD_LOGICAL_UNIT_IS_BUSY;
  1307. //
  1308. // Restore the data transfer length.
  1309. //
  1310. if (Irp->MdlAddress != NULL) {
  1311. Srb->DataTransferLength = Irp->MdlAddress->ByteCount;
  1312. }
  1313. DebugPrint((1, "ScsiPortCompletionDpc: Busy returned. Length = %lx\n", Srb->DataTransferLength));
  1314. } else {
  1315. DebugPrint((
  1316. 3,
  1317. "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
  1318. Irp));
  1319. //
  1320. // Free SrbExtension if allocated.
  1321. //
  1322. if (Srb->SrbExtension == (deviceExtension->SrbExtensionPointer -
  1323. deviceExtension->SrbExtensionSize) ) {
  1324. Srb->SrbExtension = NULL;
  1325. (PCCHAR) deviceExtension->SrbExtensionPointer -=
  1326. deviceExtension->SrbExtensionSize;
  1327. }
  1328. IoCompleteRequest(Irp, 2);
  1329. }
  1330. }
  1331. }
  1332. //
  1333. // Release the spinlock.
  1334. //
  1335. KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
  1336. return;
  1337. } // end ScsiPortCompletionDpc()
  1338. ARC_STATUS
  1339. IssueInquiry(
  1340. IN PDEVICE_EXTENSION DeviceExtension,
  1341. IN PLUNINFO LunInfo
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. Build IRP, SRB and CDB for SCSI INQUIRY command.
  1346. Arguments:
  1347. DeviceExtension - address of adapter's device object extension.
  1348. LunInfo - address of buffer for INQUIRY information.
  1349. Return Value:
  1350. ARC_STATUS
  1351. --*/
  1352. {
  1353. PIRP irp;
  1354. PIO_STACK_LOCATION irpstack;
  1355. PCDB cdb;
  1356. PSCSI_REQUEST_BLOCK srb;
  1357. ARC_STATUS status;
  1358. ULONG retryCount = 0;
  1359. DebugPrint((3,"IssueInquiry: Enter routine\n"));
  1360. if (InquiryDataBuffer == NULL) {
  1361. return ENOMEM;
  1362. }
  1363. inquiryRetry:
  1364. //
  1365. // Build IRP for this request.
  1366. //
  1367. irp = InitializeIrp(
  1368. &PrimarySrb,
  1369. IRP_MJ_SCSI,
  1370. DeviceExtension->DeviceObject,
  1371. (PVOID)InquiryDataBuffer,
  1372. INQUIRYDATABUFFERSIZE
  1373. );
  1374. irpstack = IoGetNextIrpStackLocation(irp);
  1375. //
  1376. // Set major and minor codes.
  1377. //
  1378. irpstack->MajorFunction = IRP_MJ_SCSI;
  1379. //
  1380. // Fill in SRB fields.
  1381. //
  1382. irpstack->Parameters.Others.Argument1 = &PrimarySrb;
  1383. srb = &PrimarySrb.Srb;
  1384. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  1385. srb->PathId = LunInfo->PathId;
  1386. srb->TargetId = LunInfo->TargetId;
  1387. srb->Lun = LunInfo->Lun;
  1388. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1389. srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
  1390. srb->SrbStatus = srb->ScsiStatus = 0;
  1391. srb->OriginalRequest = irp;
  1392. srb->NextSrb = 0;
  1393. //
  1394. // Set timeout to 5 seconds.
  1395. //
  1396. srb->TimeOutValue = 5;
  1397. srb->CdbLength = 6;
  1398. srb->SenseInfoBufferLength = 0;
  1399. srb->SenseInfoBuffer = 0;
  1400. srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
  1401. srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
  1402. cdb = (PCDB)srb->Cdb;
  1403. //
  1404. // Set CDB operation code.
  1405. //
  1406. cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
  1407. //
  1408. // Set CDB LUN.
  1409. //
  1410. cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
  1411. cdb->CDB6INQUIRY.Reserved1 = 0;
  1412. //
  1413. // Set allocation length to inquiry data buffer size.
  1414. //
  1415. cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
  1416. //
  1417. // Zero reserve field and
  1418. // Set EVPD Page Code to zero.
  1419. // Set Control field to zero.
  1420. // (See SCSI-II Specification.)
  1421. //
  1422. cdb->CDB6INQUIRY.PageCode = 0;
  1423. cdb->CDB6INQUIRY.IReserved = 0;
  1424. cdb->CDB6INQUIRY.Control = 0;
  1425. //
  1426. // Call port driver to handle this request.
  1427. //
  1428. (VOID)IoCallDriver(DeviceExtension->DeviceObject, irp);
  1429. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  1430. DebugPrint((2,"IssueInquiry: Inquiry failed SRB status %x\n",
  1431. srb->SrbStatus));
  1432. //
  1433. // NOTE: if INQUIRY fails with a data underrun,
  1434. // indicate success and let the class drivers
  1435. // determine whether the inquiry information
  1436. // is useful.
  1437. //
  1438. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  1439. //
  1440. // Copy INQUIRY buffer to LUNINFO.
  1441. //
  1442. DebugPrint((1,"IssueInquiry: Data underrun at TID %d\n",
  1443. LunInfo->TargetId));
  1444. RtlMoveMemory(LunInfo->InquiryData,
  1445. InquiryDataBuffer,
  1446. INQUIRYDATABUFFERSIZE);
  1447. status = STATUS_SUCCESS;
  1448. } else if ((SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT) && (retryCount++ < 2)) {
  1449. //
  1450. // If the selection did not time out then retry the request.
  1451. //
  1452. DebugPrint((2,"IssueInquiry: Retry %d\n", retryCount));
  1453. goto inquiryRetry;
  1454. } else {
  1455. status = EIO;
  1456. }
  1457. } else {
  1458. //
  1459. // Copy INQUIRY buffer to LUNINFO.
  1460. //
  1461. RtlMoveMemory(LunInfo->InquiryData,
  1462. InquiryDataBuffer,
  1463. INQUIRYDATABUFFERSIZE);
  1464. status = STATUS_SUCCESS;
  1465. }
  1466. return status;
  1467. } // end IssueInquiry()
  1468. PSCSI_BUS_SCAN_DATA
  1469. ScsiBusScan(
  1470. IN PDEVICE_EXTENSION DeviceExtension,
  1471. IN UCHAR ScsiBus,
  1472. IN UCHAR InitiatorBusId
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. Arguments:
  1477. DeviceExtension
  1478. ScsiBus
  1479. Return Value:
  1480. SCSI configuration information
  1481. --*/
  1482. {
  1483. PSCSI_BUS_SCAN_DATA busScanData;
  1484. PLUNINFO lunInfo;
  1485. UCHAR target;
  1486. UCHAR device = 0;
  1487. PLOGICAL_UNIT_EXTENSION nextLogicalUnitExtension;
  1488. DebugPrint((3,"ScsiBusScan: Enter routine\n"));
  1489. busScanData = ExAllocatePool(NonPagedPool,
  1490. sizeof(SCSI_BUS_SCAN_DATA));
  1491. if (busScanData == NULL) {
  1492. //
  1493. // Insufficient system resources to complete bus scan.
  1494. //
  1495. return NULL;
  1496. }
  1497. RtlZeroMemory(busScanData,sizeof(SCSI_BUS_SCAN_DATA));
  1498. busScanData->Length = sizeof(SCSI_CONFIGURATION_INFO);
  1499. //
  1500. // Create first LUNINFO.
  1501. //
  1502. lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
  1503. if (lunInfo == NULL) {
  1504. //
  1505. // Insufficient system resources to complete bus scan.
  1506. //
  1507. return NULL;
  1508. }
  1509. RtlZeroMemory(lunInfo, sizeof(LUNINFO));
  1510. //
  1511. // Create first logical unit extension.
  1512. //
  1513. nextLogicalUnitExtension = CreateLogicalUnitExtension(DeviceExtension);
  1514. if (nextLogicalUnitExtension == NULL) {
  1515. return(NULL);
  1516. }
  1517. //
  1518. // Link logical unit extension on list.
  1519. //
  1520. nextLogicalUnitExtension->NextLogicalUnit = DeviceExtension->LogicalUnitList;
  1521. DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
  1522. //
  1523. // Issue inquiry command to each target id to find devices.
  1524. //
  1525. // NOTE: Does not handle multiple logical units per target id.
  1526. //
  1527. for (target = DeviceExtension->MaximumTargetIds; target > 0; target--) {
  1528. if (InitiatorBusId == target-1) {
  1529. continue;
  1530. }
  1531. //
  1532. // Record address.
  1533. //
  1534. nextLogicalUnitExtension->PathId = lunInfo->PathId = ScsiBus;
  1535. nextLogicalUnitExtension->TargetId = lunInfo->TargetId = target-1;
  1536. nextLogicalUnitExtension->Lun = lunInfo->Lun = 0;
  1537. //
  1538. // Rezero hardware logigal unit extension if it's being recycled.
  1539. //
  1540. if (DeviceExtension->HwLogicalUnitExtensionSize) {
  1541. if (nextLogicalUnitExtension->SpecificLuExtension) {
  1542. RtlZeroMemory(nextLogicalUnitExtension->SpecificLuExtension,
  1543. DeviceExtension->HwLogicalUnitExtensionSize);
  1544. }
  1545. }
  1546. //
  1547. // Issue inquiry command.
  1548. //
  1549. DebugPrint((2,"ScsiBusScan: Try TargetId %d LUN 0\n", target-1));
  1550. if (IssueInquiry(DeviceExtension, lunInfo) == ESUCCESS) {
  1551. PINQUIRYDATA inquiryData = (PINQUIRYDATA)lunInfo->InquiryData;
  1552. //
  1553. // Make sure we can use the device.
  1554. //
  1555. if (inquiryData->DeviceTypeQualifier & 0x04) {
  1556. //
  1557. // This device is not supported; continue looking for
  1558. // other devices.
  1559. //
  1560. continue;
  1561. }
  1562. DebugPrint((1,
  1563. "ScsiBusScan: Found Device %d at TID %d LUN %d\n",
  1564. device,
  1565. lunInfo->TargetId,
  1566. lunInfo->Lun));
  1567. //
  1568. // Link LUN information on list.
  1569. //
  1570. lunInfo->NextLunInfo = busScanData->LunInfoList;
  1571. busScanData->LunInfoList = lunInfo;
  1572. //
  1573. // This buffer is used. Get another.
  1574. //
  1575. lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
  1576. if (lunInfo == NULL) {
  1577. //
  1578. // Insufficient system resources to complete bus scan.
  1579. //
  1580. return busScanData;
  1581. }
  1582. RtlZeroMemory(lunInfo, sizeof(LUNINFO));
  1583. //
  1584. // Current logical unit extension claimed.
  1585. // Create next logical unit.
  1586. //
  1587. nextLogicalUnitExtension =
  1588. CreateLogicalUnitExtension(DeviceExtension);
  1589. if (nextLogicalUnitExtension == NULL) {
  1590. return busScanData;
  1591. }
  1592. //
  1593. // Link logical unit extension on list.
  1594. //
  1595. nextLogicalUnitExtension->NextLogicalUnit =
  1596. DeviceExtension->LogicalUnitList;
  1597. DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
  1598. device++;
  1599. }
  1600. } // end for (target ...
  1601. //
  1602. // Remove unused logicalunit extension from list.
  1603. //
  1604. DeviceExtension->LogicalUnitList =
  1605. DeviceExtension->LogicalUnitList->NextLogicalUnit;
  1606. ExFreePool(nextLogicalUnitExtension);
  1607. ExFreePool(lunInfo);
  1608. busScanData->NumberOfLogicalUnits = device;
  1609. DebugPrint((1,
  1610. "ScsiBusScan: Found %d devices on SCSI bus %d\n",
  1611. device,
  1612. ScsiBus));
  1613. return busScanData;
  1614. } // end ScsiBusScan()
  1615. PLOGICAL_UNIT_EXTENSION
  1616. CreateLogicalUnitExtension(
  1617. IN PDEVICE_EXTENSION DeviceExtension
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. Create logical unit extension.
  1622. Arguments:
  1623. DeviceExtension
  1624. PathId
  1625. Return Value:
  1626. Logical unit extension
  1627. --*/
  1628. {
  1629. PLOGICAL_UNIT_EXTENSION logicalUnitExtension;
  1630. //
  1631. // Create logical unit extension and link in chain.
  1632. //
  1633. logicalUnitExtension =
  1634. ExAllocatePool(NonPagedPool, sizeof(LOGICAL_UNIT_EXTENSION));
  1635. if (logicalUnitExtension == NULL) {
  1636. return(NULL);
  1637. }
  1638. //
  1639. // Zero logical unit extension.
  1640. //
  1641. RtlZeroMemory(logicalUnitExtension, sizeof(LOGICAL_UNIT_EXTENSION));
  1642. //
  1643. // Allocate miniport driver logical unit extension if necessary.
  1644. //
  1645. if (DeviceExtension->HwLogicalUnitExtensionSize) {
  1646. logicalUnitExtension->SpecificLuExtension =
  1647. ExAllocatePool(NonPagedPool,
  1648. DeviceExtension->HwLogicalUnitExtensionSize);
  1649. if (logicalUnitExtension->SpecificLuExtension == NULL) {
  1650. return(NULL);
  1651. }
  1652. //
  1653. // Zero hardware logical unit extension.
  1654. //
  1655. RtlZeroMemory(logicalUnitExtension->SpecificLuExtension,
  1656. DeviceExtension->HwLogicalUnitExtensionSize);
  1657. }
  1658. //
  1659. // Set timer counters in LogicalUnits to -1 to indicate no
  1660. // outstanding requests.
  1661. //
  1662. logicalUnitExtension->RequestTimeoutCounter = -1;
  1663. //
  1664. // Clear the current request field.
  1665. //
  1666. logicalUnitExtension->CurrentRequest = NULL;
  1667. return logicalUnitExtension;
  1668. } // end CreateLogicalUnitExtension()
  1669. //
  1670. // Routines providing service to hardware dependent driver.
  1671. //
  1672. SCSI_PHYSICAL_ADDRESS
  1673. ScsiPortGetPhysicalAddress(
  1674. IN PVOID HwDeviceExtension,
  1675. IN PSCSI_REQUEST_BLOCK Srb,
  1676. IN PVOID VirtualAddress,
  1677. OUT ULONG *Length
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. Arguments:
  1682. Return Value:
  1683. --*/
  1684. {
  1685. PDEVICE_EXTENSION deviceExtension =
  1686. ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  1687. PSRB_SCATTER_GATHER scatterList;
  1688. PIRP irp;
  1689. PMDL mdl;
  1690. ULONG byteOffset;
  1691. ULONG whichPage;
  1692. PULONG pages;
  1693. ULONG_PTR address;
  1694. if (Srb == NULL) {
  1695. //
  1696. // The virtual address is required to be within the non-cached extension
  1697. // and we can't allocate 4GB of non-cached extension in the loader so
  1698. // truncate the offset to a ULONG.
  1699. //
  1700. byteOffset = (ULONG) ((PUCHAR) deviceExtension->NonCachedExtension -
  1701. (PUCHAR) VirtualAddress);
  1702. if (deviceExtension->SrbExtensionZonePool) {
  1703. address = (PUCHAR) VirtualAddress -
  1704. (PUCHAR) deviceExtension->SrbExtensionZonePool +
  1705. deviceExtension->PhysicalZoneBase;
  1706. } else {
  1707. address = MmGetPhysicalAddress(VirtualAddress).LowPart;
  1708. }
  1709. //
  1710. // Return the requested length.
  1711. //
  1712. *Length = deviceExtension->NonCachedExtensionSize - byteOffset;
  1713. } else if (deviceExtension->MasterWithAdapter) {
  1714. //
  1715. // A scatter/gather list has already been allocated use it to determine
  1716. // the physical address and length. Get the scatter/gather list.
  1717. //
  1718. scatterList = GetLogicalUnitExtension(deviceExtension, Srb->TargetId)
  1719. ->ScatterGather;
  1720. //
  1721. // Calculate byte offset into the data buffer.
  1722. //
  1723. byteOffset = (ULONG)((PCHAR) VirtualAddress - (PCHAR) Srb->DataBuffer);
  1724. //
  1725. // Find the appropirate entry in the scatter/gatter list.
  1726. //
  1727. while (byteOffset >= scatterList->Length) {
  1728. byteOffset -= scatterList->Length;
  1729. scatterList++;
  1730. }
  1731. //
  1732. // Calculate the physical address and length to be returned.
  1733. //
  1734. *Length = scatterList->Length - byteOffset;
  1735. return(ScsiPortConvertUlongToPhysicalAddress(scatterList->PhysicalAddress + byteOffset));
  1736. } else {
  1737. //
  1738. // Get IRP from SRB.
  1739. //
  1740. irp = Srb->OriginalRequest;
  1741. //
  1742. // Get MDL from IRP.
  1743. //
  1744. mdl = irp->MdlAddress;
  1745. //
  1746. // Calculate byte offset from
  1747. // beginning of first physical page.
  1748. //
  1749. byteOffset = (ULONG)((PCHAR)VirtualAddress - (PCHAR)mdl->StartVa);
  1750. //
  1751. // Calculate which physical page.
  1752. //
  1753. whichPage = byteOffset >> PAGE_SHIFT;
  1754. //
  1755. // Calculate beginning of physical page array.
  1756. //
  1757. pages = (PULONG)(mdl + 1);
  1758. //
  1759. // Calculate physical address.
  1760. //
  1761. address = (pages[whichPage] << PAGE_SHIFT) +
  1762. BYTE_OFFSET(VirtualAddress);
  1763. //
  1764. // Assume the buffer is contiguous. Just return the requested length.
  1765. //
  1766. }
  1767. return ScsiPortConvertUlongToPhysicalAddress(address);
  1768. } // end ScsiPortGetPhysicalAddress()
  1769. PVOID
  1770. ScsiPortGetVirtualAddress(
  1771. IN PVOID HwDeviceExtension,
  1772. IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. This routine is returns a virtual address associated with a
  1777. physical address, if the physical address was obtained by a
  1778. call to ScsiPortGetPhysicalAddress.
  1779. Arguments:
  1780. PhysicalAddress
  1781. Return Value:
  1782. Virtual address if physical page hashed.
  1783. NULL if physical page not found in hash.
  1784. --*/
  1785. {
  1786. PDEVICE_EXTENSION deviceExtension =
  1787. ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  1788. PVOID address;
  1789. address = ScsiPortConvertPhysicalAddressToUlong(PhysicalAddress)
  1790. - deviceExtension->PhysicalZoneBase +
  1791. (PUCHAR)deviceExtension->SrbExtensionZonePool;
  1792. return address;
  1793. } // end ScsiPortGetVirtualAddress()
  1794. PVOID
  1795. ScsiPortGetLogicalUnit(
  1796. IN PVOID HwDeviceExtension,
  1797. IN UCHAR PathId,
  1798. IN UCHAR TargetId,
  1799. IN UCHAR Lun
  1800. )
  1801. /*++
  1802. Routine Description:
  1803. Walk port driver's logical unit extension list searching
  1804. for entry.
  1805. Arguments:
  1806. HwDeviceExtension - The port driver's device extension follows
  1807. the miniport's device extension and contains a pointer to
  1808. the logical device extension list.
  1809. PathId, TargetId and Lun - identify which logical unit on the
  1810. SCSI buses.
  1811. Return Value:
  1812. If entry found return miniport driver's logical unit extension.
  1813. Else, return NULL.
  1814. --*/
  1815. {
  1816. PDEVICE_EXTENSION deviceExtension;
  1817. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1818. //
  1819. // Get pointer to port driver device extension.
  1820. //
  1821. deviceExtension = (PDEVICE_EXTENSION)HwDeviceExtension -1;
  1822. //
  1823. // Get pointer to logical unit list.
  1824. //
  1825. logicalUnit = deviceExtension->LogicalUnitList;
  1826. //
  1827. // Walk list looking at target id for requested logical unit extension.
  1828. //
  1829. while (logicalUnit != NULL) {
  1830. if ((logicalUnit->TargetId == TargetId) &&
  1831. (logicalUnit->PathId == PathId) &&
  1832. (logicalUnit->Lun == Lun)) {
  1833. //
  1834. // Logical unit extension found.
  1835. // Return specific logical unit extension.
  1836. //
  1837. return logicalUnit->SpecificLuExtension;
  1838. }
  1839. //
  1840. // Get next logical unit.
  1841. //
  1842. logicalUnit = logicalUnit->NextLogicalUnit;
  1843. }
  1844. //
  1845. // Requested logical unit extension not found.
  1846. //
  1847. return NULL;
  1848. } // end ScsiPortGetLogicalUnit()
  1849. VOID
  1850. ScsiPortNotification(
  1851. IN SCSI_NOTIFICATION_TYPE NotificationType,
  1852. IN PVOID HwDeviceExtension,
  1853. ...
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. Arguments:
  1858. Return Value:
  1859. --*/
  1860. {
  1861. PDEVICE_EXTENSION deviceExtension =
  1862. (PDEVICE_EXTENSION) HwDeviceExtension - 1;
  1863. PIO_STACK_LOCATION irpstack;
  1864. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1865. PSCSI_REQUEST_BLOCK srb;
  1866. va_list(ap);
  1867. va_start(ap, HwDeviceExtension);
  1868. switch (NotificationType) {
  1869. case NextLuRequest:
  1870. case NextRequest:
  1871. //
  1872. // Start next packet on adapter's queue.
  1873. //
  1874. deviceExtension->InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
  1875. break;
  1876. case RequestComplete:
  1877. srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
  1878. if (srb->SrbStatus == SRB_STATUS_ERROR) {
  1879. }
  1880. //
  1881. // Link the completed request into a forward-linked list of IRPs.
  1882. //
  1883. irpstack = IoGetCurrentIrpStackLocation(
  1884. ((PIRP) srb->OriginalRequest)
  1885. );
  1886. irpstack->Parameters.Others.Argument3 =
  1887. deviceExtension->CompletedRequests;
  1888. deviceExtension->CompletedRequests = srb->OriginalRequest;
  1889. //
  1890. // Set logical unit current request to NULL
  1891. // to prevent race condition.
  1892. //
  1893. logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
  1894. if (logicalUnit != NULL) {
  1895. logicalUnit->CurrentRequest = NULL;
  1896. } else {
  1897. ASSERT(logicalUnit != NULL); // Logic error, must debug this.
  1898. }
  1899. break;
  1900. case ResetDetected:
  1901. deviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
  1902. break;
  1903. case CallDisableInterrupts:
  1904. ASSERT(deviceExtension->Flags & PD_DISABLE_INTERRUPTS);
  1905. //
  1906. // The mini-port wants us to call the specified routine
  1907. // with interrupts disabled. This is done after the current
  1908. // HwRequestInterrutp routine completes. Indicate the call is
  1909. // needed and save the routine to be called.
  1910. //
  1911. deviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;
  1912. deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
  1913. break;
  1914. case CallEnableInterrupts:
  1915. ASSERT(!(deviceExtension->Flags & PD_DISABLE_INTERRUPTS));
  1916. //
  1917. // The mini-port wants us to call the specified routine
  1918. // with interrupts enabled this is done from the DPC.
  1919. // Disable calls to the interrupt routine, indicate the call is
  1920. // needed and save the routine to be called.
  1921. //
  1922. deviceExtension->Flags |= PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;
  1923. deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
  1924. break;
  1925. case RequestTimerCall:
  1926. deviceExtension->HwTimerRequest = va_arg(ap, PHW_INTERRUPT);
  1927. deviceExtension->TimerValue = va_arg(ap, ULONG);
  1928. if (deviceExtension->TimerValue) {
  1929. //
  1930. // Round up the timer value to the stall time.
  1931. //
  1932. deviceExtension->TimerValue = (deviceExtension->TimerValue
  1933. + PD_INTERLOOP_STALL - 1)/ PD_INTERLOOP_STALL;
  1934. }
  1935. break;
  1936. }
  1937. va_end(ap);
  1938. //
  1939. // Check to see if the last DPC has been processed yet. If so
  1940. // queue another DPC.
  1941. //
  1942. ScsiPortCompletionDpc(
  1943. NULL, // Dpc
  1944. deviceExtension->DeviceObject, // DeviceObject
  1945. NULL, // Irp
  1946. NULL // Context
  1947. );
  1948. } // end ScsiPortNotification()
  1949. VOID
  1950. ScsiPortFlushDma(
  1951. IN PVOID HwDeviceExtension
  1952. )
  1953. /*++
  1954. Routine Description:
  1955. This routine checks to see if the perivious IoMapTransfer has been done
  1956. started. If it has not, then the PD_MAP_TRANSER flag is cleared, and the
  1957. routine returns; otherwise, this routine schedules a DPC which will call
  1958. IoFlushAdapter buffers.
  1959. Arguments:
  1960. HwDeviceExtension - Supplies a the hardware device extension for the
  1961. host bus adapter which will be doing the data transfer.
  1962. Return Value:
  1963. None.
  1964. --*/
  1965. {
  1966. PDEVICE_EXTENSION deviceExtension;
  1967. deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  1968. if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
  1969. //
  1970. // The transfer has not been started so just clear the map transfer
  1971. // flag and return.
  1972. //
  1973. deviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
  1974. return;
  1975. }
  1976. deviceExtension->InterruptFlags |= PD_FLUSH_ADAPTER_BUFFERS;
  1977. //
  1978. // Check to see if the last DPC has been processed yet. If so
  1979. // queue another DPC.
  1980. //
  1981. ScsiPortCompletionDpc(
  1982. NULL, // Dpc
  1983. deviceExtension->DeviceObject, // DeviceObject
  1984. NULL, // Irp
  1985. NULL // Context
  1986. );
  1987. return;
  1988. }
  1989. VOID
  1990. ScsiPortIoMapTransfer(
  1991. IN PVOID HwDeviceExtension,
  1992. IN PSCSI_REQUEST_BLOCK Srb,
  1993. IN PVOID LogicalAddress,
  1994. IN ULONG Length
  1995. )
  1996. /*++
  1997. Routine Description:
  1998. Saves the parameters for the call to IoMapTransfer and schedules the DPC
  1999. if necessary.
  2000. Arguments:
  2001. HwDeviceExtension - Supplies a the hardware device extension for the
  2002. host bus adapter which will be doing the data transfer.
  2003. Srb - Supplies the particular request that data transfer is for.
  2004. LogicalAddress - Supplies the logical address where the transfer should
  2005. begin.
  2006. Length - Supplies the maximum length in bytes of the transfer.
  2007. Return Value:
  2008. None.
  2009. --*/
  2010. {
  2011. PDEVICE_EXTENSION deviceExtension;
  2012. deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  2013. //
  2014. // Make sure this host bus adapter has an Dma adapter object.
  2015. //
  2016. if (deviceExtension->DmaAdapterObject == NULL) {
  2017. //
  2018. // No DMA adapter, no work.
  2019. //
  2020. return;
  2021. }
  2022. deviceExtension->MapTransferParameters.Srb = Srb;
  2023. deviceExtension->MapTransferParameters.LogicalAddress = LogicalAddress;
  2024. deviceExtension->MapTransferParameters.Length = Length;
  2025. deviceExtension->InterruptFlags |= PD_MAP_TRANSFER;
  2026. //
  2027. // Check to see if the last DPC has been processed yet. If so
  2028. // queue another DPC.
  2029. //
  2030. ScsiPortCompletionDpc(
  2031. NULL, // Dpc
  2032. deviceExtension->DeviceObject, // DeviceObject
  2033. NULL, // Irp
  2034. NULL // Context
  2035. );
  2036. } // end ScsiPortIoMapTransfer()
  2037. VOID
  2038. IssueRequestSense(
  2039. IN PDEVICE_EXTENSION deviceExtension,
  2040. IN PSCSI_REQUEST_BLOCK FailingSrb
  2041. )
  2042. /*++
  2043. Routine Description:
  2044. This routine creates a REQUEST SENSE request and uses IoCallDriver to
  2045. renter the driver. The completion routine cleans up the data structures
  2046. and processes the logical unit queue according to the flags.
  2047. A pointer to failing SRB is stored at the end of the request sense
  2048. Srb, so that the completion routine can find it.
  2049. Arguments:
  2050. DeviceExension - Supplies a pointer to the device extension for this
  2051. SCSI port.
  2052. FailingSrb - Supplies a pointer to the request that the request sense
  2053. is being done for.
  2054. Return Value:
  2055. None.
  2056. --*/
  2057. {
  2058. PIO_STACK_LOCATION irpstack;
  2059. PIRP Irp;
  2060. PSCSI_REQUEST_BLOCK Srb;
  2061. PCDB cdb;
  2062. PVOID *Pointer;
  2063. //
  2064. // Allocate Srb from non-paged pool
  2065. // plus room for a pointer to the failing IRP.
  2066. // Since this routine is in an error-handling
  2067. // path and a shortterm allocation
  2068. // NonPagedMustSucceed is requested.
  2069. //
  2070. Srb = &RequestSenseSrb.Srb;
  2071. //
  2072. // Allocate an IRP to issue the REQUEST SENSE request.
  2073. //
  2074. Irp = InitializeIrp(
  2075. &RequestSenseSrb,
  2076. IRP_MJ_READ,
  2077. deviceExtension->DeviceObject,
  2078. FailingSrb->SenseInfoBuffer,
  2079. FailingSrb->SenseInfoBufferLength
  2080. );
  2081. irpstack = IoGetNextIrpStackLocation(Irp);
  2082. irpstack->MajorFunction = IRP_MJ_SCSI;
  2083. //
  2084. // Save the Failing SRB after the request sense Srb.
  2085. //
  2086. Pointer = (PVOID *) (Srb+1);
  2087. *Pointer = FailingSrb;
  2088. //
  2089. // Build the REQUEST SENSE CDB.
  2090. //
  2091. Srb->CdbLength = 6;
  2092. cdb = (PCDB)Srb->Cdb;
  2093. cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
  2094. cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
  2095. cdb->CDB6INQUIRY.Reserved1 = 0;
  2096. cdb->CDB6INQUIRY.PageCode = 0;
  2097. cdb->CDB6INQUIRY.IReserved = 0;
  2098. cdb->CDB6INQUIRY.AllocationLength =
  2099. (UCHAR)FailingSrb->SenseInfoBufferLength;
  2100. cdb->CDB6INQUIRY.Control = 0;
  2101. //
  2102. // Save SRB address in next stack for port driver.
  2103. //
  2104. irpstack->Parameters.Others.Argument1 = (PVOID)Srb;
  2105. //
  2106. // Set up IRP Address.
  2107. //
  2108. Srb->OriginalRequest = Irp;
  2109. Srb->NextSrb = 0;
  2110. //
  2111. // Set up SCSI bus address.
  2112. //
  2113. Srb->TargetId = FailingSrb->TargetId;
  2114. Srb->Lun = FailingSrb->Lun;
  2115. Srb->PathId = FailingSrb->PathId;
  2116. Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  2117. Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2118. //
  2119. // Set timeout value to 2 seconds.
  2120. //
  2121. Srb->TimeOutValue = 2;
  2122. //
  2123. // Disable auto request sense.
  2124. //
  2125. Srb->SenseInfoBufferLength = 0;
  2126. //
  2127. // Sense buffer is in stack.
  2128. //
  2129. Srb->SenseInfoBuffer = NULL;
  2130. //
  2131. // Set read and bypass frozen queue bits in flags.
  2132. //
  2133. //
  2134. // Set a speical flags to indicate the logical unit queue should be by
  2135. // passed and that no queue processing should be done when the request
  2136. // completes.
  2137. //
  2138. Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
  2139. SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
  2140. Srb->DataBuffer = FailingSrb->SenseInfoBuffer;
  2141. //
  2142. // Set the transfer length.
  2143. //
  2144. Srb->DataTransferLength = FailingSrb->SenseInfoBufferLength;
  2145. //
  2146. // Zero out status.
  2147. //
  2148. Srb->ScsiStatus = Srb->SrbStatus = 0;
  2149. (VOID)IoCallDriver(deviceExtension->DeviceObject, Irp);
  2150. ScsiPortInternalCompletion(deviceExtension->DeviceObject, Irp, Srb);
  2151. return;
  2152. } // end IssueRequestSense()
  2153. VOID
  2154. ScsiPortInternalCompletion(
  2155. PDEVICE_OBJECT DeviceObject,
  2156. PIRP Irp,
  2157. PVOID Context
  2158. )
  2159. /*++
  2160. Routine Description:
  2161. Arguments:
  2162. Device object
  2163. IRP
  2164. Context - pointer to SRB
  2165. Return Value:
  2166. None.
  2167. --*/
  2168. {
  2169. PSCSI_REQUEST_BLOCK srb = Context;
  2170. PSCSI_REQUEST_BLOCK failingSrb;
  2171. PIRP failingIrp;
  2172. UNREFERENCED_PARAMETER(Irp);
  2173. UNREFERENCED_PARAMETER(DeviceObject);
  2174. //
  2175. // Request sense completed. If successful or data over/underrun
  2176. // get the failing SRB and indicate that the sense information
  2177. // is valid. The class driver will check for underrun and determine
  2178. // if there is enough sense information to be useful.
  2179. //
  2180. if ((SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
  2181. (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) {
  2182. //
  2183. // Get a pointer to failing Irp and Srb.
  2184. //
  2185. failingSrb = *((PVOID *) (srb+1));
  2186. failingIrp = failingSrb->OriginalRequest;
  2187. //
  2188. // Report sense buffer is valid.
  2189. //
  2190. failingSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
  2191. //
  2192. // Copy bytes transferred to failing SRB
  2193. // request sense length field to communicate
  2194. // to the class drivers the number of valid
  2195. // sense bytes.
  2196. //
  2197. failingSrb->SenseInfoBufferLength = (UCHAR) srb->DataTransferLength;
  2198. }
  2199. } // ScsiPortInternalCompletion()
  2200. VOID
  2201. ScsiPortTickHandler(
  2202. IN PDEVICE_OBJECT DeviceObject,
  2203. IN PVOID Context
  2204. )
  2205. /*++
  2206. Routine Description:
  2207. Arguments:
  2208. Return Value:
  2209. None.
  2210. --*/
  2211. {
  2212. PDEVICE_EXTENSION deviceExtension =
  2213. (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  2214. PLOGICAL_UNIT_EXTENSION logicalUnit;
  2215. UNREFERENCED_PARAMETER(Context);
  2216. logicalUnit = deviceExtension->LogicalUnitList;
  2217. //
  2218. // NOTE: The use of Current request needs to be synchronized with the
  2219. // clearing of current request.
  2220. //
  2221. while (logicalUnit != NULL) {
  2222. //
  2223. // Check for busy requests.
  2224. //
  2225. if (logicalUnit->Flags & PD_LOGICAL_UNIT_IS_BUSY) {
  2226. DebugPrint((1,"ScsiPortTickHandler: Retrying busy status request\n"));
  2227. //
  2228. // Clear the busy flag and retry the request.
  2229. //
  2230. logicalUnit->Flags &= ~PD_LOGICAL_UNIT_IS_BUSY;
  2231. ScsiPortStartIo(DeviceObject, logicalUnit->CurrentRequest);
  2232. } else if (logicalUnit->RequestTimeoutCounter == 0) {
  2233. //
  2234. // Request timed out.
  2235. //
  2236. DebugPrint((1, "ScsiPortTickHandler: Request timed out\n"));
  2237. //
  2238. // Reset request timeout counter to unused state.
  2239. //
  2240. logicalUnit->RequestTimeoutCounter = -1;
  2241. //
  2242. // Build and send request to abort command.
  2243. //
  2244. IssueAbortRequest(deviceExtension, logicalUnit->CurrentRequest);
  2245. } else if (logicalUnit->RequestTimeoutCounter != -1) {
  2246. DebugPrint((1, "ScsiPortTickHandler: Timeout value %lx\n",logicalUnit->RequestTimeoutCounter));
  2247. logicalUnit->RequestTimeoutCounter--;
  2248. }
  2249. logicalUnit = logicalUnit->NextLogicalUnit;
  2250. }
  2251. return;
  2252. } // end ScsiPortTickHandler()
  2253. VOID
  2254. IssueAbortRequest(
  2255. IN PDEVICE_EXTENSION DeviceExtension,
  2256. IN PIRP FailingIrp
  2257. )
  2258. /*++
  2259. Routine Description:
  2260. A request timed out and to clear the request at the HBA
  2261. an ABORT request is issued. But first, if the request
  2262. that timed out was an ABORT command, then reset the
  2263. adapter instead.
  2264. Arguments:
  2265. DeviceExension - Supplies a pointer to the device extension for this
  2266. SCSI port.
  2267. FailingIrp - Supplies a pointer to the request that is to be aborted.
  2268. Return Value:
  2269. None.
  2270. --*/
  2271. {
  2272. ULONG j;
  2273. UNREFERENCED_PARAMETER(FailingIrp);
  2274. //
  2275. // A request to abort failed.
  2276. // Need to reset the adapter.
  2277. //
  2278. DebugPrint((1,"IssueAbort: Request timed out, resetting the bus.\n"));
  2279. if (!DeviceExtension->HwReset(
  2280. DeviceExtension->HwDeviceExtension,
  2281. 0)){
  2282. DebugPrint((1,"Reset SCSI bus failed\n"));
  2283. }
  2284. //
  2285. // Call the interupt handler for a few microseconds to clear any reset
  2286. // interrupts.
  2287. //
  2288. for (j = 0; j < 1000 * 100; j++) {
  2289. FwStallExecution(10);
  2290. if (DeviceExtension->HwInterrupt != NULL) {
  2291. DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
  2292. }
  2293. }
  2294. DeviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
  2295. SpCheckResetDelay( DeviceExtension );
  2296. return;
  2297. } // end IssueAbortRequest()
  2298. VOID
  2299. SpCheckResetDelay(
  2300. IN PDEVICE_EXTENSION deviceExtension
  2301. )
  2302. /*++
  2303. Routine Description:
  2304. If there is a pending reset delay, this routine stalls the execution
  2305. for the specified number of seconds. During the delay the timer
  2306. routines are called at the appropriate times.
  2307. Arguments:
  2308. DeviceExension - Supplies a pointer to the device extension for this
  2309. SCSI port.
  2310. Return Value:
  2311. Nothing.
  2312. --*/
  2313. {
  2314. ULONG milliSecondTime;
  2315. //
  2316. // Check if the adapter is ready to accept requests.
  2317. //
  2318. while (deviceExtension->PortTimeoutCounter) {
  2319. deviceExtension->PortTimeoutCounter--;
  2320. //
  2321. // One second delay.
  2322. //
  2323. for ( milliSecondTime = 0;
  2324. milliSecondTime < ((1000*1000)/PD_INTERLOOP_STALL);
  2325. milliSecondTime++ ) {
  2326. FwStallExecution(PD_INTERLOOP_STALL);
  2327. //
  2328. // Check the miniport timer.
  2329. //
  2330. if (deviceExtension->TimerValue != 0) {
  2331. deviceExtension->TimerValue--;
  2332. if (deviceExtension->TimerValue == 0) {
  2333. //
  2334. // The timer timed out so called requested timer routine.
  2335. //
  2336. deviceExtension->HwTimerRequest(deviceExtension->HwDeviceExtension);
  2337. }
  2338. }
  2339. }
  2340. }
  2341. return;
  2342. }
  2343. BOOLEAN
  2344. SpGetInterruptState(
  2345. IN PVOID ServiceContext
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. This routine saves the InterruptFlags, MapTransferParameters and
  2350. CompletedRequests fields and clears the InterruptFlags.
  2351. Arguments:
  2352. ServiceContext - Supplies a pointer to the device extension for this
  2353. SCSI port.
  2354. Return Value:
  2355. Always returns TRUE.
  2356. Notes:
  2357. Called via KeSynchronizeExecution.
  2358. --*/
  2359. {
  2360. PDEVICE_EXTENSION deviceExtension = ServiceContext;
  2361. //
  2362. // Move the interrupt state to save area.
  2363. //
  2364. deviceExtension->InterruptFlags = deviceExtension->InterruptFlags;
  2365. deviceExtension->CompletedRequests = deviceExtension->CompletedRequests;
  2366. deviceExtension->MapTransferParameters = deviceExtension->MapTransferParameters;
  2367. //
  2368. // Clear the interrupt state.
  2369. //
  2370. deviceExtension->InterruptFlags = 0;
  2371. deviceExtension->CompletedRequests = NULL;
  2372. return(TRUE);
  2373. }
  2374. VOID
  2375. ScsiDebugPause(
  2376. VOID
  2377. )
  2378. {
  2379. #if DBG
  2380. #define SCSIDEBUG_PAUSE 0x100
  2381. #define SCSIDEBUG_PAUSE_LIMIT 20
  2382. static ULONG ScsiDebugPauseCount;
  2383. if (++ScsiDebugPauseCount > SCSIDEBUG_PAUSE_LIMIT) {
  2384. ScsiDebugPauseCount = 0;
  2385. if (ScsiDebug & SCSIDEBUG_PAUSE) {
  2386. DebugPrint((1, "Hit any key.\n"));
  2387. while(!GET_KEY()); // DEBUG Only!
  2388. }
  2389. }
  2390. #endif
  2391. }
  2392. VOID
  2393. ScsiPortLogError(
  2394. IN PVOID HwDeviceExtension,
  2395. IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
  2396. IN UCHAR PathId,
  2397. IN UCHAR TargetId,
  2398. IN UCHAR Lun,
  2399. IN ULONG ErrorCode,
  2400. IN ULONG UniqueId
  2401. )
  2402. /*++
  2403. Routine Description:
  2404. This routine allocates an error log entry, copies the supplied text
  2405. to it, and requests that it be written to the error log file.
  2406. Arguments:
  2407. DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
  2408. TargetId, Lun and PathId - specify device address on a SCSI bus.
  2409. ErrorCode - Supplies an error code indicating the type of error.
  2410. UniqueId - Supplies a unique identifier for the error.
  2411. Return Value:
  2412. None.
  2413. --*/
  2414. {
  2415. PCHAR errorCodeString;
  2416. UNREFERENCED_PARAMETER( HwDeviceExtension );
  2417. UNREFERENCED_PARAMETER( Srb );
  2418. #ifndef DEBUG
  2419. UNREFERENCED_PARAMETER( UniqueId );
  2420. UNREFERENCED_PARAMETER( Lun );
  2421. UNREFERENCED_PARAMETER( PathId );
  2422. UNREFERENCED_PARAMETER( TargetId );
  2423. #endif
  2424. switch (ErrorCode) {
  2425. case SP_BUS_PARITY_ERROR:
  2426. errorCodeString = "SCSI bus partity error";
  2427. break;
  2428. case SP_UNEXPECTED_DISCONNECT:
  2429. errorCodeString = "Unexpected disconnect";
  2430. break;
  2431. case SP_INVALID_RESELECTION:
  2432. errorCodeString = "Invalid reselection";
  2433. break;
  2434. case SP_BUS_TIME_OUT:
  2435. errorCodeString = "SCSI bus time out";
  2436. break;
  2437. case SP_PROTOCOL_ERROR:
  2438. errorCodeString = "SCSI protocol error";
  2439. break;
  2440. case SP_INTERNAL_ADAPTER_ERROR:
  2441. errorCodeString = "Internal adapter error";
  2442. break;
  2443. default:
  2444. errorCodeString = "Unknown error code";
  2445. break;
  2446. }
  2447. DebugPrint((1,"\n\nLogErrorEntry: Logging SCSI error packet. ErrorCode = %s.\n",
  2448. errorCodeString));
  2449. DebugPrint((1,
  2450. "PathId = %2x, TargetId = %2x, Lun = %2x, UniqueId = %x.\n\n",
  2451. PathId,
  2452. TargetId,
  2453. Lun,
  2454. UniqueId));
  2455. #if DBG
  2456. ScsiDebugPause();
  2457. #endif
  2458. return;
  2459. } // end ScsiPortLogError()
  2460. VOID
  2461. ScsiPortCompleteRequest(
  2462. IN PVOID HwDeviceExtension,
  2463. IN UCHAR PathId,
  2464. IN UCHAR TargetId,
  2465. IN UCHAR Lun,
  2466. IN UCHAR SrbStatus
  2467. )
  2468. /*++
  2469. Routine Description:
  2470. Complete all active requests for the specified logical unit.
  2471. Arguments:
  2472. DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
  2473. TargetId, Lun and PathId - specify device address on a SCSI bus.
  2474. SrbStatus - Status to be returned in each completed SRB.
  2475. Return Value:
  2476. None.
  2477. --*/
  2478. {
  2479. PDEVICE_EXTENSION deviceExtension =
  2480. ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  2481. PSCSI_REQUEST_BLOCK Srb;
  2482. PSCSI_REQUEST_BLOCK failingSrb;
  2483. PLOGICAL_UNIT_EXTENSION luExtension;
  2484. PIRP nextIrp;
  2485. PIO_STACK_LOCATION irpstack;
  2486. UNREFERENCED_PARAMETER(PathId);
  2487. UNREFERENCED_PARAMETER(Lun);
  2488. if (TargetId == (UCHAR)(-1)) {
  2489. //
  2490. // Complete requests for all units on this bus.
  2491. //
  2492. luExtension = deviceExtension->LogicalUnitList;
  2493. while (luExtension != NULL) {
  2494. //
  2495. // Complete requests until queue is empty.
  2496. //
  2497. if ((nextIrp = luExtension->CurrentRequest) != NULL &&
  2498. !(luExtension->Flags & PD_LOGICAL_UNIT_IS_BUSY)) {
  2499. //
  2500. // Get SRB address from current IRP stack.
  2501. //
  2502. irpstack = IoGetCurrentIrpStackLocation(nextIrp);
  2503. Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  2504. //
  2505. // Just in case this is an abort request,
  2506. // get pointer to failingSrb.
  2507. //
  2508. failingSrb = Srb->NextSrb;
  2509. //
  2510. // Update SRB status.
  2511. //
  2512. Srb->SrbStatus = SrbStatus;
  2513. //
  2514. // Indicate no bytes transferred.
  2515. //
  2516. Srb->DataTransferLength = 0;
  2517. //
  2518. // Set IRP status.
  2519. //
  2520. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  2521. //
  2522. // Move bytes transferred to IRP.
  2523. //
  2524. nextIrp->IoStatus.Information = Srb->DataTransferLength;
  2525. //
  2526. // Call notification routine.
  2527. //
  2528. ScsiPortNotification(RequestComplete,
  2529. (PVOID)HwDeviceExtension,
  2530. Srb);
  2531. if (failingSrb) {
  2532. //
  2533. // This was an abort request. The failing
  2534. // SRB must also be completed.
  2535. //
  2536. failingSrb->SrbStatus = SrbStatus;
  2537. failingSrb->DataTransferLength = 0;
  2538. //
  2539. // Get IRP from SRB.
  2540. //
  2541. nextIrp = failingSrb->OriginalRequest;
  2542. //
  2543. // Set IRP status.
  2544. //
  2545. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  2546. //
  2547. // Move bytes transferred to IRP.
  2548. //
  2549. nextIrp->IoStatus.Information =
  2550. failingSrb->DataTransferLength;
  2551. //
  2552. // Call notification routine.
  2553. //
  2554. ScsiPortNotification(RequestComplete,
  2555. (PVOID)HwDeviceExtension,
  2556. failingSrb);
  2557. }
  2558. } // end if
  2559. luExtension = luExtension->NextLogicalUnit;
  2560. } // end while
  2561. } else {
  2562. //
  2563. // Complete all requests for this logical unit.
  2564. //
  2565. luExtension =
  2566. GetLogicalUnitExtension(deviceExtension, TargetId);
  2567. ASSERT(luExtension != NULL);
  2568. //
  2569. // Complete requests until queue is empty.
  2570. //
  2571. if ((luExtension != NULL) && ((nextIrp = luExtension->CurrentRequest) != NULL)) {
  2572. //
  2573. // Get SRB address from current IRP stack.
  2574. //
  2575. irpstack = IoGetCurrentIrpStackLocation(nextIrp);
  2576. Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
  2577. //
  2578. // Update SRB status.
  2579. //
  2580. Srb->SrbStatus = SrbStatus;
  2581. //
  2582. // Indicate no bytes transferred.
  2583. //
  2584. Srb->DataTransferLength = 0;
  2585. //
  2586. // Set IRP status.
  2587. //
  2588. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  2589. //
  2590. // Move bytes transferred to IRP.
  2591. //
  2592. nextIrp->IoStatus.Information = Srb->DataTransferLength;
  2593. //
  2594. // Call notification routine.
  2595. //
  2596. ScsiPortNotification(RequestComplete,
  2597. (PVOID)HwDeviceExtension,
  2598. Srb);
  2599. } // end if
  2600. } // end if ... else
  2601. return;
  2602. } // end ScsiPortCompleteRequest()
  2603. VOID
  2604. ScsiPortMoveMemory(
  2605. IN PVOID WriteBuffer,
  2606. IN PVOID ReadBuffer,
  2607. IN ULONG Length
  2608. )
  2609. /*++
  2610. Routine Description:
  2611. Copy from one buffer into another.
  2612. Arguments:
  2613. ReadBuffer - source
  2614. WriteBuffer - destination
  2615. Length - number of bytes to copy
  2616. Return Value:
  2617. None.
  2618. --*/
  2619. {
  2620. RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
  2621. } // end ScsiPortMoveMemory()
  2622. VOID
  2623. ScsiPortStallExecution(
  2624. ULONG Delay
  2625. )
  2626. /*++
  2627. Routine Description:
  2628. Wait number of microseconds in tight processor loop.
  2629. Arguments:
  2630. Delay - number of microseconds to wait.
  2631. Return Value:
  2632. None.
  2633. --*/
  2634. {
  2635. FwStallExecution(Delay);
  2636. } // end ScsiPortStallExecution()
  2637. PLOGICAL_UNIT_EXTENSION
  2638. GetLogicalUnitExtension(
  2639. PDEVICE_EXTENSION deviceExtension,
  2640. UCHAR TargetId
  2641. )
  2642. /*++
  2643. Routine Description:
  2644. Walk logical unit extension list looking for
  2645. extension with matching target id.
  2646. Arguments:
  2647. deviceExtension
  2648. TargetId
  2649. Return Value:
  2650. Requested logical unit extension if found,
  2651. else NULL.
  2652. --*/
  2653. {
  2654. PLOGICAL_UNIT_EXTENSION logicalUnit = deviceExtension->LogicalUnitList;
  2655. while (logicalUnit != NULL) {
  2656. if (logicalUnit->TargetId == TargetId) {
  2657. return logicalUnit;
  2658. }
  2659. logicalUnit = logicalUnit->NextLogicalUnit;
  2660. }
  2661. //
  2662. // Logical unit extension not found.
  2663. //
  2664. return (PLOGICAL_UNIT_EXTENSION)NULL;
  2665. } // end GetLogicalUnitExtension()
  2666. #if DBG
  2667. VOID
  2668. ScsiDebugPrint(
  2669. ULONG DebugPrintLevel,
  2670. PCCHAR DebugMessage,
  2671. ...
  2672. )
  2673. /*++
  2674. Routine Description:
  2675. Debug print for all SCSI drivers
  2676. Arguments:
  2677. Debug print level between 0 and 3, with 3 being the most verbose.
  2678. Return Value:
  2679. None
  2680. --*/
  2681. {
  2682. va_list ap;
  2683. va_start( ap, DebugMessage );
  2684. if (DebugPrintLevel <= (ScsiDebug & (SCSIDEBUG_PAUSE-1))) {
  2685. char buffer[256];
  2686. _vsnprintf(buffer, sizeof(buffer), DebugMessage, ap);
  2687. #if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
  2688. FwPrint(buffer);
  2689. FwPrint("\r");
  2690. #else
  2691. BlPrint(buffer);
  2692. BlPrint("\r");
  2693. #endif
  2694. DbgPrint(buffer);
  2695. }
  2696. va_end(ap);
  2697. }
  2698. #else
  2699. //
  2700. // ScsiDebugPrint stub
  2701. //
  2702. VOID
  2703. ScsiDebugPrint(
  2704. ULONG DebugPrintLevel,
  2705. PCCHAR DebugMessage,
  2706. ...
  2707. )
  2708. {
  2709. UNREFERENCED_PARAMETER(DebugPrintLevel);
  2710. UNREFERENCED_PARAMETER(DebugMessage);
  2711. }
  2712. #endif
  2713. UCHAR
  2714. ScsiPortReadPortUchar(
  2715. IN PUCHAR Port
  2716. )
  2717. /*++
  2718. Routine Description:
  2719. Read from the specificed port address.
  2720. Arguments:
  2721. Port - Supplies a pointer to the port address.
  2722. Return Value:
  2723. Returns the value read from the specified port address.
  2724. --*/
  2725. {
  2726. #ifdef MIPS
  2727. return(READ_REGISTER_UCHAR(Port));
  2728. #else
  2729. return(READ_PORT_UCHAR(Port));
  2730. #endif
  2731. }
  2732. USHORT
  2733. ScsiPortReadPortUshort(
  2734. IN PUSHORT Port
  2735. )
  2736. /*++
  2737. Routine Description:
  2738. Read from the specificed port address.
  2739. Arguments:
  2740. Port - Supplies a pointer to the port address.
  2741. Return Value:
  2742. Returns the value read from the specified port address.
  2743. --*/
  2744. {
  2745. #ifdef MIPS
  2746. return(READ_REGISTER_USHORT(Port));
  2747. #else
  2748. return(READ_PORT_USHORT(Port));
  2749. #endif
  2750. }
  2751. ULONG
  2752. ScsiPortReadPortUlong(
  2753. IN PULONG Port
  2754. )
  2755. /*++
  2756. Routine Description:
  2757. Read from the specificed port address.
  2758. Arguments:
  2759. Port - Supplies a pointer to the port address.
  2760. Return Value:
  2761. Returns the value read from the specified port address.
  2762. --*/
  2763. {
  2764. #ifdef MIPS
  2765. return(READ_REGISTER_ULONG(Port));
  2766. #else
  2767. return(READ_PORT_ULONG(Port));
  2768. #endif
  2769. }
  2770. UCHAR
  2771. ScsiPortReadRegisterUchar(
  2772. IN PUCHAR Register
  2773. )
  2774. /*++
  2775. Routine Description:
  2776. Read from the specificed register address.
  2777. Arguments:
  2778. Register - Supplies a pointer to the register address.
  2779. Return Value:
  2780. Returns the value read from the specified register address.
  2781. --*/
  2782. {
  2783. return(READ_REGISTER_UCHAR(Register));
  2784. }
  2785. USHORT
  2786. ScsiPortReadRegisterUshort(
  2787. IN PUSHORT Register
  2788. )
  2789. /*++
  2790. Routine Description:
  2791. Read from the specificed register address.
  2792. Arguments:
  2793. Register - Supplies a pointer to the register address.
  2794. Return Value:
  2795. Returns the value read from the specified register address.
  2796. --*/
  2797. {
  2798. return(READ_REGISTER_USHORT(Register));
  2799. }
  2800. ULONG
  2801. ScsiPortReadRegisterUlong(
  2802. IN PULONG Register
  2803. )
  2804. /*++
  2805. Routine Description:
  2806. Read from the specificed register address.
  2807. Arguments:
  2808. Register - Supplies a pointer to the register address.
  2809. Return Value:
  2810. Returns the value read from the specified register address.
  2811. --*/
  2812. {
  2813. return(READ_REGISTER_ULONG(Register));
  2814. }
  2815. VOID
  2816. ScsiPortReadRegisterBufferUchar(
  2817. IN PUCHAR Register,
  2818. IN PUCHAR Buffer,
  2819. IN ULONG Count
  2820. )
  2821. /*++
  2822. Routine Description:
  2823. Read a buffer of unsigned bytes from the specified register address.
  2824. Arguments:
  2825. Register - Supplies a pointer to the port address.
  2826. Buffer - Supplies a pointer to the data buffer area.
  2827. Count - The count of items to move.
  2828. Return Value:
  2829. None
  2830. --*/
  2831. {
  2832. READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
  2833. }
  2834. VOID
  2835. ScsiPortReadRegisterBufferUshort(
  2836. IN PUSHORT Register,
  2837. IN PUSHORT Buffer,
  2838. IN ULONG Count
  2839. )
  2840. /*++
  2841. Routine Description:
  2842. Read a buffer of unsigned shorts from the specified register address.
  2843. Arguments:
  2844. Register - Supplies a pointer to the port address.
  2845. Buffer - Supplies a pointer to the data buffer area.
  2846. Count - The count of items to move.
  2847. Return Value:
  2848. None
  2849. --*/
  2850. {
  2851. READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
  2852. }
  2853. VOID
  2854. ScsiPortReadRegisterBufferUlong(
  2855. IN PULONG Register,
  2856. IN PULONG Buffer,
  2857. IN ULONG Count
  2858. )
  2859. /*++
  2860. Routine Description:
  2861. Read a buffer of unsigned longs from the specified register address.
  2862. Arguments:
  2863. Register - Supplies a pointer to the port address.
  2864. Buffer - Supplies a pointer to the data buffer area.
  2865. Count - The count of items to move.
  2866. Return Value:
  2867. None
  2868. --*/
  2869. {
  2870. READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
  2871. }
  2872. VOID
  2873. ScsiPortWritePortUchar(
  2874. IN PUCHAR Port,
  2875. IN UCHAR Value
  2876. )
  2877. /*++
  2878. Routine Description:
  2879. Write to the specificed port address.
  2880. Arguments:
  2881. Port - Supplies a pointer to the port address.
  2882. Value - Supplies the value to be written.
  2883. Return Value:
  2884. None
  2885. --*/
  2886. {
  2887. #ifdef MIPS
  2888. WRITE_REGISTER_UCHAR(Port, Value);
  2889. #else
  2890. WRITE_PORT_UCHAR(Port, Value);
  2891. #endif
  2892. }
  2893. VOID
  2894. ScsiPortWritePortUshort(
  2895. IN PUSHORT Port,
  2896. IN USHORT Value
  2897. )
  2898. /*++
  2899. Routine Description:
  2900. Write to the specificed port address.
  2901. Arguments:
  2902. Port - Supplies a pointer to the port address.
  2903. Value - Supplies the value to be written.
  2904. Return Value:
  2905. None
  2906. --*/
  2907. {
  2908. #ifdef MIPS
  2909. WRITE_REGISTER_USHORT(Port, Value);
  2910. #else
  2911. WRITE_PORT_USHORT(Port, Value);
  2912. #endif
  2913. }
  2914. VOID
  2915. ScsiPortWritePortUlong(
  2916. IN PULONG Port,
  2917. IN ULONG Value
  2918. )
  2919. /*++
  2920. Routine Description:
  2921. Write to the specificed port address.
  2922. Arguments:
  2923. Port - Supplies a pointer to the port address.
  2924. Value - Supplies the value to be written.
  2925. Return Value:
  2926. None
  2927. --*/
  2928. {
  2929. #ifdef MIPS
  2930. WRITE_REGISTER_ULONG(Port, Value);
  2931. #else
  2932. WRITE_PORT_ULONG(Port, Value);
  2933. #endif
  2934. }
  2935. VOID
  2936. ScsiPortWriteRegisterUchar(
  2937. IN PUCHAR Register,
  2938. IN UCHAR Value
  2939. )
  2940. /*++
  2941. Routine Description:
  2942. Write to the specificed register address.
  2943. Arguments:
  2944. Register - Supplies a pointer to the register address.
  2945. Value - Supplies the value to be written.
  2946. Return Value:
  2947. None
  2948. --*/
  2949. {
  2950. WRITE_REGISTER_UCHAR(Register, Value);
  2951. }
  2952. VOID
  2953. ScsiPortWriteRegisterUshort(
  2954. IN PUSHORT Register,
  2955. IN USHORT Value
  2956. )
  2957. /*++
  2958. Routine Description:
  2959. Write to the specificed register address.
  2960. Arguments:
  2961. Register - Supplies a pointer to the register address.
  2962. Value - Supplies the value to be written.
  2963. Return Value:
  2964. None
  2965. --*/
  2966. {
  2967. WRITE_REGISTER_USHORT(Register, Value);
  2968. }
  2969. VOID
  2970. ScsiPortWriteRegisterUlong(
  2971. IN PULONG Register,
  2972. IN ULONG Value
  2973. )
  2974. /*++
  2975. Routine Description:
  2976. Write to the specificed register address.
  2977. Arguments:
  2978. Register - Supplies a pointer to the register address.
  2979. Value - Supplies the value to be written.
  2980. Return Value:
  2981. None
  2982. --*/
  2983. {
  2984. WRITE_REGISTER_ULONG(Register, Value);
  2985. }
  2986. VOID
  2987. ScsiPortWriteRegisterBufferUchar(
  2988. IN PUCHAR Register,
  2989. IN PUCHAR Buffer,
  2990. IN ULONG Count
  2991. )
  2992. /*++
  2993. Routine Description:
  2994. Write a buffer of unsigned bytes from the specified register address.
  2995. Arguments:
  2996. Register - Supplies a pointer to the port address.
  2997. Buffer - Supplies a pointer to the data buffer area.
  2998. Count - The count of items to move.
  2999. Return Value:
  3000. None
  3001. --*/
  3002. {
  3003. WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
  3004. }
  3005. VOID
  3006. ScsiPortWriteRegisterBufferUshort(
  3007. IN PUSHORT Register,
  3008. IN PUSHORT Buffer,
  3009. IN ULONG Count
  3010. )
  3011. /*++
  3012. Routine Description:
  3013. Write a buffer of unsigned shorts from the specified register address.
  3014. Arguments:
  3015. Register - Supplies a pointer to the port address.
  3016. Buffer - Supplies a pointer to the data buffer area.
  3017. Count - The count of items to move.
  3018. Return Value:
  3019. None
  3020. --*/
  3021. {
  3022. WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
  3023. }
  3024. VOID
  3025. ScsiPortWriteRegisterBufferUlong(
  3026. IN PULONG Register,
  3027. IN PULONG Buffer,
  3028. IN ULONG Count
  3029. )
  3030. /*++
  3031. Routine Description:
  3032. Write a buffer of unsigned longs from the specified register address.
  3033. Arguments:
  3034. Register - Supplies a pointer to the port address.
  3035. Buffer - Supplies a pointer to the data buffer area.
  3036. Count - The count of items to move.
  3037. Return Value:
  3038. None
  3039. --*/
  3040. {
  3041. WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
  3042. }
  3043. SCSI_PHYSICAL_ADDRESS
  3044. ScsiPortConvertUlongToPhysicalAddress(
  3045. ULONG_PTR UlongAddress
  3046. )
  3047. {
  3048. SCSI_PHYSICAL_ADDRESS physicalAddress;
  3049. physicalAddress.QuadPart = UlongAddress;
  3050. return(physicalAddress);
  3051. }
  3052. #undef ScsiPortConvertPhysicalAddressToUlong
  3053. ULONG
  3054. ScsiPortConvertPhysicalAddressToUlong(
  3055. SCSI_PHYSICAL_ADDRESS Address
  3056. )
  3057. {
  3058. return(Address.LowPart);
  3059. }
  3060. PIRP
  3061. InitializeIrp(
  3062. PFULL_SCSI_REQUEST_BLOCK FullSrb,
  3063. CCHAR MajorFunction,
  3064. PVOID DeviceObject,
  3065. PVOID Buffer,
  3066. ULONG Length
  3067. )
  3068. /*++
  3069. Routine Description:
  3070. This funcition builds an IRP for use by the SCSI port driver and builds a
  3071. MDL list.
  3072. Arguments:
  3073. FullSrb - Supplies a pointer to the full srb structure which contains the
  3074. Irp and Mdl.
  3075. MajorFunction - Supplies the major function code to initialize the Irp
  3076. entry.
  3077. DeviceObject - Supplies the device Object pointer to initialize the Irp
  3078. with.
  3079. Buffer - Supplies the virual address of the buffer for which the
  3080. Mdl should be built.
  3081. Length - Supplies the size of buffer for which the Mdl should be built.
  3082. Return Value:
  3083. Returns a pointer to the initialized IRP.
  3084. --*/
  3085. {
  3086. PIRP irp;
  3087. PMDL mdl;
  3088. UNREFERENCED_PARAMETER( DeviceObject );
  3089. UNREFERENCED_PARAMETER( MajorFunction );
  3090. irp = &FullSrb->Irp;
  3091. mdl = &FullSrb->Mdl;
  3092. irp->Tail.Overlay.CurrentStackLocation = &FullSrb->IrpStack[IRP_STACK_SIZE];
  3093. if (Buffer != NULL && Length != 0) {
  3094. //
  3095. // Build the memory descriptor list.
  3096. //
  3097. irp->MdlAddress = mdl;
  3098. mdl->Next = NULL;
  3099. mdl->Size = (CSHORT)(sizeof(MDL) +
  3100. ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG));
  3101. mdl->StartVa = (PVOID)PAGE_ALIGN(Buffer);
  3102. mdl->ByteCount = Length;
  3103. mdl->ByteOffset = BYTE_OFFSET(Buffer);
  3104. mdl->MappedSystemVa = Buffer;
  3105. mdl->MdlFlags = MDL_MAPPED_TO_SYSTEM_VA;
  3106. ScsiPortInitializeMdlPages (mdl);
  3107. } else {
  3108. irp->MdlAddress = NULL;
  3109. }
  3110. return(irp);
  3111. }
  3112. PVOID
  3113. ScsiPortGetDeviceBase(
  3114. IN PVOID HwDeviceExtension,
  3115. IN INTERFACE_TYPE BusType,
  3116. IN ULONG SystemIoBusNumber,
  3117. SCSI_PHYSICAL_ADDRESS IoAddress,
  3118. ULONG NumberOfBytes,
  3119. BOOLEAN InMemorySpace
  3120. )
  3121. /*++
  3122. Routine Description:
  3123. This routine maps an IO address to system address space.
  3124. Use ScsiPortFreeDeviceBase to unmap address.
  3125. Arguments:
  3126. HwDeviceExtension - used to find port device extension.
  3127. BusType - what type of bus - eisa, mca, isa
  3128. SystemIoBusNumber - which IO bus (for machines with multiple buses).
  3129. IoAddress - base device address to be mapped.
  3130. NumberOfBytes - number of bytes for which address is valid.
  3131. Return Value:
  3132. Mapped address
  3133. --*/
  3134. {
  3135. PHYSICAL_ADDRESS cardAddress;
  3136. ULONG addressSpace = InMemorySpace;
  3137. PVOID mappedAddress;
  3138. UNREFERENCED_PARAMETER( HwDeviceExtension );
  3139. if (!HalTranslateBusAddress(
  3140. BusType, // AdapterInterfaceType
  3141. SystemIoBusNumber, // SystemIoBusNumber
  3142. IoAddress, // Bus Address
  3143. &addressSpace, // AddressSpace
  3144. &cardAddress // Translated address
  3145. )) {
  3146. return NULL;
  3147. }
  3148. //
  3149. // Map the device base address into the virtual address space
  3150. // if the address is in memory space.
  3151. //
  3152. if (!addressSpace) {
  3153. mappedAddress = MmMapIoSpace(cardAddress,
  3154. NumberOfBytes,
  3155. FALSE);
  3156. } else {
  3157. mappedAddress = (PVOID)((ULONG_PTR)cardAddress.LowPart);
  3158. }
  3159. return mappedAddress;
  3160. } // end ScsiPortGetDeviceBase()
  3161. VOID
  3162. ScsiPortFreeDeviceBase(
  3163. IN PVOID HwDeviceExtension,
  3164. IN PVOID MappedAddress
  3165. )
  3166. /*++
  3167. Routine Description:
  3168. This routine unmaps an IO address that has been previously mapped
  3169. to system address space using ScsiPortGetDeviceBase().
  3170. Arguments:
  3171. HwDeviceExtension - used to find port device extension.
  3172. MappedAddress - address to unmap.
  3173. NumberOfBytes - number of bytes mapped.
  3174. InIoSpace - addresses in IO space don't get mapped.
  3175. Return Value:
  3176. None
  3177. --*/
  3178. {
  3179. UNREFERENCED_PARAMETER(HwDeviceExtension);
  3180. UNREFERENCED_PARAMETER(MappedAddress);
  3181. return;
  3182. } // end ScsiPortFreeDeviceBase()
  3183. ARC_STATUS
  3184. GetAdapterCapabilities(
  3185. IN PDEVICE_OBJECT PortDeviceObject,
  3186. OUT PIO_SCSI_CAPABILITIES *PortCapabilities
  3187. )
  3188. /*++
  3189. Routine Description:
  3190. Arguments:
  3191. Return Value:
  3192. Status is returned.
  3193. --*/
  3194. {
  3195. *PortCapabilities = &((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
  3196. ->Capabilities;
  3197. return(ESUCCESS);
  3198. } // end GetAdapterCapabilities()
  3199. ARC_STATUS
  3200. GetInquiryData(
  3201. IN PDEVICE_OBJECT PortDeviceObject,
  3202. OUT PSCSI_CONFIGURATION_INFO *ConfigInfo
  3203. )
  3204. /*++
  3205. Routine Description:
  3206. This routine sends a request to a port driver to return
  3207. configuration information.
  3208. Arguments:
  3209. The address of the configuration information is returned in
  3210. the formal parameter ConfigInfo.
  3211. Return Value:
  3212. Status is returned.
  3213. --*/
  3214. {
  3215. *ConfigInfo = ((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
  3216. ->ScsiInfo;
  3217. return(ESUCCESS);
  3218. } // end GetInquiryData()
  3219. NTSTATUS
  3220. SpInitializeConfiguration(
  3221. IN PDEVICE_EXTENSION DeviceExtension,
  3222. IN PHW_INITIALIZATION_DATA HwInitData,
  3223. OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  3224. IN BOOLEAN InitialCall
  3225. )
  3226. /*++
  3227. Routine Description:
  3228. This routine initializes the port configuration information structure.
  3229. Any necessary information is extracted from the registery.
  3230. Arguments:
  3231. DeviceExtension - Supplies the device extension.
  3232. HwInitializationData - Supplies the initial miniport data.
  3233. ConfigInfo - Supplies the configuration information to be
  3234. initialized.
  3235. InitialCall - Indicates that this is first call to this function.
  3236. If InitialCall is FALSE, then the perivous configuration information
  3237. is used to determine the new information.
  3238. Return Value:
  3239. Returns a status indicating the success or fail of the initializaiton.
  3240. --*/
  3241. {
  3242. #ifdef i386
  3243. extern ULONG MachineType;
  3244. #endif
  3245. ULONG j;
  3246. UNREFERENCED_PARAMETER( DeviceExtension );
  3247. //
  3248. // If this is the initial call then zero the information and set
  3249. // the structure to the uninitialized values.
  3250. //
  3251. if (InitialCall) {
  3252. RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
  3253. ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
  3254. ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
  3255. ConfigInfo->InterruptMode = Latched;
  3256. ConfigInfo->MaximumTransferLength = 0xffffffff;
  3257. // ConfigInfo->NumberOfPhysicalBreaks = 0x17;
  3258. ConfigInfo->NumberOfPhysicalBreaks = 0xffffffff;
  3259. ConfigInfo->DmaChannel = 0xffffffff;
  3260. ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
  3261. ConfigInfo->MaximumNumberOfTargets = 8;
  3262. #if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
  3263. {
  3264. PCONFIGURATION_COMPONENT Component;
  3265. PCM_SCSI_DEVICE_DATA ScsiDeviceData;
  3266. UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
  3267. (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
  3268. sizeof(CM_SCSI_DEVICE_DATA)];
  3269. PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
  3270. ULONG Count;
  3271. ULONG ScsiHostId;
  3272. if (((Component = ArcGetComponent("scsi(0)")) != NULL) &&
  3273. (Component->Class == AdapterClass) && (Component->Type == ScsiAdapter) &&
  3274. (ArcGetConfigurationData((PVOID)Descriptor, Component) == ESUCCESS) &&
  3275. ((Count = Descriptor->Count) < 6)) {
  3276. ScsiDeviceData = (PCM_SCSI_DEVICE_DATA)&Descriptor->PartialDescriptors[Count];
  3277. if (ScsiDeviceData->HostIdentifier > 7) {
  3278. ScsiHostId = 7;
  3279. } else {
  3280. ScsiHostId = ScsiDeviceData->HostIdentifier;
  3281. }
  3282. } else {
  3283. ScsiHostId = 7;
  3284. }
  3285. for (j = 0; j < 8; j++) {
  3286. ConfigInfo->InitiatorBusId[j] = ScsiHostId;
  3287. }
  3288. }
  3289. #else
  3290. for (j = 0; j < 8; j++) {
  3291. ConfigInfo->InitiatorBusId[j] = (UCHAR)~0;
  3292. }
  3293. #endif
  3294. #if defined(i386)
  3295. switch (HwInitData->AdapterInterfaceType) {
  3296. case Isa:
  3297. if ((MachineType & 0xff) == MACHINE_TYPE_ISA) {
  3298. return(STATUS_SUCCESS);
  3299. }
  3300. case Eisa:
  3301. if ((MachineType & 0xff) == MACHINE_TYPE_EISA) {
  3302. return(STATUS_SUCCESS);
  3303. } else {
  3304. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3305. }
  3306. case MicroChannel:
  3307. if ((MachineType & 0xff) == MACHINE_TYPE_MCA) {
  3308. return(STATUS_SUCCESS);
  3309. } else {
  3310. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3311. }
  3312. case PCIBus:
  3313. return(STATUS_SUCCESS);
  3314. default:
  3315. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3316. }
  3317. #elif defined(_MIPS_)
  3318. if (HwInitData->AdapterInterfaceType != Internal) {
  3319. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3320. }
  3321. #elif defined(_ALPHA_)
  3322. if ( (HwInitData->AdapterInterfaceType != Internal) &&
  3323. (HwInitData->AdapterInterfaceType != Eisa) &&
  3324. (HwInitData->AdapterInterfaceType != PCIBus) &&
  3325. (HwInitData->AdapterInterfaceType != Isa) ) {
  3326. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3327. }
  3328. #elif defined(_PPC_)
  3329. if ( (HwInitData->AdapterInterfaceType != Internal) &&
  3330. (HwInitData->AdapterInterfaceType != Eisa) &&
  3331. (HwInitData->AdapterInterfaceType != Isa) ) {
  3332. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3333. }
  3334. #else
  3335. return(STATUS_SUCCESS);
  3336. #endif
  3337. } else {
  3338. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3339. }
  3340. }
  3341. NTSTATUS
  3342. SpGetCommonBuffer(
  3343. PDEVICE_EXTENSION DeviceExtension,
  3344. ULONG NonCachedExtensionSize
  3345. )
  3346. /*++
  3347. Routine Description:
  3348. This routine determines the required size of the common buffer. Allocates
  3349. the common buffer and finally sets up the srb extension zone. This routine
  3350. expects that the adapter object has already been allocated.
  3351. Arguments:
  3352. DeviceExtension - Supplies a pointer to the device extension.
  3353. NonCachedExtensionSize - Supplies the size of the noncached device
  3354. extension for the mini-port driver.
  3355. Return Value:
  3356. Returns the status of the allocate operation.
  3357. --*/
  3358. {
  3359. #ifdef AXP_FIRMWARE
  3360. PHYSICAL_ADDRESS pAddress;
  3361. #endif
  3362. PVOID buffer;
  3363. ULONG length;
  3364. ULONG blockSize;
  3365. //
  3366. // Calculate the block size for the zone elements based on the Srb
  3367. // Extension.
  3368. //
  3369. blockSize = DeviceExtension->SrbExtensionSize;
  3370. //
  3371. // Last three bits of blocksize must be zero.
  3372. // Round blocksize up.
  3373. //
  3374. blockSize = (blockSize + 7) & ~7;
  3375. //
  3376. // Same for the noncached extension size.
  3377. //
  3378. NonCachedExtensionSize += 7;
  3379. NonCachedExtensionSize &= ~7;
  3380. length = NonCachedExtensionSize + blockSize * MINIMUM_SRB_EXTENSIONS;
  3381. //
  3382. // Round the length up to a page size, since HalGetCommonBuffer allocates
  3383. // in pages anyway.
  3384. //
  3385. length = (ULONG)ROUND_TO_PAGES(length);
  3386. //
  3387. // Allocate one page for noncached deviceextension
  3388. // and srbextension zoned pool.
  3389. //
  3390. if (DeviceExtension->DmaAdapterObject == NULL) {
  3391. //
  3392. // Since there is no adapter just allocate from non-paged pool.
  3393. //
  3394. if ((buffer = MmAllocateNonCachedMemory(length)) != NULL) {
  3395. DeviceExtension->PhysicalZoneBase = MmGetPhysicalAddress(buffer).LowPart;
  3396. }
  3397. } else {
  3398. #ifdef AXP_FIRMWARE
  3399. buffer = HalAllocateCommonBuffer(DeviceExtension->DmaAdapterObject,
  3400. length,
  3401. &pAddress,
  3402. FALSE );
  3403. DeviceExtension->PhysicalZoneBase = pAddress.LowPart;
  3404. #else
  3405. if ((buffer = MmAllocateNonCachedMemory(length)) != NULL) {
  3406. DeviceExtension->PhysicalZoneBase = MmGetPhysicalAddress(buffer).LowPart;
  3407. }
  3408. #endif
  3409. }
  3410. if (buffer == NULL) {
  3411. return ENOMEM;
  3412. }
  3413. //
  3414. // Truncate Physical address to 32 bits.
  3415. //
  3416. // Determine length and starting address of zone.
  3417. // If noncached device extension required then
  3418. // subtract size from page leaving rest for zone.
  3419. //
  3420. length -= NonCachedExtensionSize;
  3421. DeviceExtension->NonCachedExtension = (PUCHAR)buffer + length;
  3422. DeviceExtension->NonCachedExtensionSize = NonCachedExtensionSize;
  3423. if (DeviceExtension->SrbExtensionSize) {
  3424. //
  3425. // Get block size.
  3426. //
  3427. blockSize = DeviceExtension->SrbExtensionSize;
  3428. //
  3429. // Record starting virtual address of zone.
  3430. //
  3431. DeviceExtension->SrbExtensionZonePool = buffer;
  3432. DeviceExtension->SrbExtensionPointer = buffer;
  3433. DeviceExtension->SrbExtensionSize = blockSize;
  3434. } else {
  3435. DeviceExtension->SrbExtensionZonePool = NULL;
  3436. }
  3437. return(ESUCCESS);
  3438. }
  3439. PVOID
  3440. ScsiPortGetUncachedExtension(
  3441. IN PVOID HwDeviceExtension,
  3442. IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  3443. IN ULONG NumberOfBytes
  3444. )
  3445. /*++
  3446. Routine Description:
  3447. This function allocates a common buffer to be used as the uncached device
  3448. extension for the mini-port driver. This function will also allocate any
  3449. required SRB extensions. The DmaAdapter is allocated if it has not been
  3450. allocated previously.
  3451. Arguments:
  3452. DeviceExtension - Supplies a pointer to the mini-ports device extension.
  3453. ConfigInfo - Supplies a pointer to the partially initialized configuraiton
  3454. information. This is used to get an DMA adapter object.
  3455. NumberOfBytes - Supplies the size of the extension which needs to be
  3456. allocated
  3457. Return Value:
  3458. A pointer to the uncached device extension or NULL if the extension could
  3459. not be allocated or was previously allocated.
  3460. --*/
  3461. {
  3462. DEVICE_DESCRIPTION deviceDescription;
  3463. PDEVICE_EXTENSION deviceExtension =
  3464. ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  3465. NTSTATUS status;
  3466. ULONG numberOfPageBreaks;
  3467. //
  3468. // Make sure that an common buffer has not already been allocated.
  3469. //
  3470. if (deviceExtension->SrbExtensionZonePool != NULL) {
  3471. return(NULL);
  3472. }
  3473. if ( deviceExtension->DmaAdapterObject == NULL ) {
  3474. RtlZeroMemory( &deviceDescription, sizeof(DEVICE_DESCRIPTION) );
  3475. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  3476. deviceDescription.DmaChannel = ConfigInfo->DmaChannel;
  3477. deviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
  3478. deviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
  3479. deviceDescription.DmaWidth = ConfigInfo->DmaWidth;
  3480. deviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
  3481. deviceDescription.DmaPort = ConfigInfo->DmaPort;
  3482. deviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
  3483. deviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
  3484. deviceDescription.ScatterGather = ConfigInfo->ScatterGather;
  3485. deviceDescription.Master = ConfigInfo->Master;
  3486. deviceDescription.AutoInitialize = FALSE;
  3487. deviceDescription.DemandMode = FALSE;
  3488. if (ConfigInfo->MaximumTransferLength > 0x11000) {
  3489. deviceDescription.MaximumLength = 0x11000;
  3490. } else {
  3491. deviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
  3492. }
  3493. deviceExtension->DmaAdapterObject = HalGetAdapter(
  3494. &deviceDescription,
  3495. &numberOfPageBreaks
  3496. );
  3497. //
  3498. // Set maximum number of page breaks.
  3499. //
  3500. if (numberOfPageBreaks > ConfigInfo->NumberOfPhysicalBreaks) {
  3501. deviceExtension->Capabilities.MaximumPhysicalPages =
  3502. ConfigInfo->NumberOfPhysicalBreaks;
  3503. } else {
  3504. deviceExtension->Capabilities.MaximumPhysicalPages =
  3505. numberOfPageBreaks;
  3506. }
  3507. }
  3508. //
  3509. // Allocate the common buffer.
  3510. //
  3511. status = SpGetCommonBuffer( deviceExtension, NumberOfBytes);
  3512. if (status != ESUCCESS) {
  3513. return(NULL);
  3514. }
  3515. return(deviceExtension->NonCachedExtension);
  3516. }
  3517. ULONG
  3518. ScsiPortGetBusData(
  3519. IN PVOID DeviceExtension,
  3520. IN ULONG BusDataType,
  3521. IN ULONG SystemIoBusNumber,
  3522. IN ULONG SlotNumber,
  3523. IN PVOID Buffer,
  3524. IN ULONG Length
  3525. )
  3526. /*++
  3527. Routine Description:
  3528. The function returns the bus data for an adapter slot or CMOS address.
  3529. Arguments:
  3530. BusDataType - Supplies the type of bus.
  3531. BusNumber - Indicates which bus.
  3532. Buffer - Supplies the space to store the data.
  3533. Length - Supplies a count in bytes of the maximum amount to return.
  3534. Return Value:
  3535. Returns the amount of data stored into the buffer.
  3536. --*/
  3537. {
  3538. ULONG DataLength = 0;
  3539. PDEVICE_EXTENSION deviceExtension =
  3540. (PDEVICE_EXTENSION) DeviceExtension - 1;
  3541. //
  3542. // If the length is non-zero, the the requested data.
  3543. //
  3544. if (Length != 0) {
  3545. ULONG ret;
  3546. ret = HalGetBusData( BusDataType,
  3547. SystemIoBusNumber,
  3548. SlotNumber,
  3549. Buffer,
  3550. Length
  3551. );
  3552. return ret;
  3553. }
  3554. //
  3555. // Free any previously allocated data.
  3556. //
  3557. if (deviceExtension->MapRegisterBase != NULL) {
  3558. ExFreePool(deviceExtension->MapRegisterBase);
  3559. }
  3560. if (BusDataType == EisaConfiguration) {
  3561. #if 0
  3562. //
  3563. // Deteremine the length to allocate based on the number of functions
  3564. // for the slot.
  3565. //
  3566. Length = HalGetBusData( BusDataType,
  3567. SystemIoBusNumber,
  3568. SlotNumber,
  3569. &slotInformation,
  3570. sizeof(CM_EISA_SLOT_INFORMATION));
  3571. if (Length < sizeof(CM_EISA_SLOT_INFORMATION)) {
  3572. //
  3573. // The data is messed up since this should never occur
  3574. //
  3575. DebugPrint((1, "ScsiPortGetBusData: Slot information not returned. Length = %d\n", Length));
  3576. return(0);
  3577. }
  3578. //
  3579. // Calculate the required length based on the number of functions.
  3580. //
  3581. Length = sizeof(CM_EISA_SLOT_INFORMATION) +
  3582. (sizeof(CM_EISA_FUNCTION_INFORMATION) * slotInformation.NumberFunctions);
  3583. #else
  3584. //
  3585. // Since the loader does not really support freeing data and the EISA
  3586. // configuration data can be very large. Hal get bus data has be changed
  3587. // to accept a length of zero for EIAS configuration data.
  3588. //
  3589. DataLength = HalGetBusData( BusDataType,
  3590. SystemIoBusNumber,
  3591. SlotNumber,
  3592. Buffer,
  3593. Length
  3594. );
  3595. DebugPrint((1, "ScsiPortGetBusData: Returning data. Length = %d\n", DataLength));
  3596. return(DataLength);
  3597. #endif
  3598. } else {
  3599. Length = PAGE_SIZE;
  3600. }
  3601. deviceExtension->MapRegisterBase = ExAllocatePool(NonPagedPool, Length);
  3602. if (deviceExtension->MapRegisterBase == NULL) {
  3603. DebugPrint((1, "ScsiPortGetBusData: Memory allocation failed. Length = %d\n", Length));
  3604. return(0);
  3605. }
  3606. //
  3607. // Return the pointer to the mini-port driver.
  3608. //
  3609. *((PVOID *)Buffer) = deviceExtension->MapRegisterBase;
  3610. DataLength = HalGetBusData( BusDataType,
  3611. SystemIoBusNumber,
  3612. SlotNumber,
  3613. deviceExtension->MapRegisterBase,
  3614. Length
  3615. );
  3616. return(DataLength);
  3617. }
  3618. PSCSI_REQUEST_BLOCK
  3619. ScsiPortGetSrb(
  3620. IN PVOID HwDeviceExtension,
  3621. IN UCHAR PathId,
  3622. IN UCHAR TargetId,
  3623. IN UCHAR Lun,
  3624. IN LONG QueueTag
  3625. )
  3626. /*++
  3627. Routine Description:
  3628. This routine retrieves an active SRB for a particuliar logical unit.
  3629. Arguments:
  3630. HwDeviceExtension
  3631. PathId, TargetId, Lun - identify logical unit on SCSI bus.
  3632. QueueTag - -1 indicates request is not tagged.
  3633. Return Value:
  3634. SRB, if one exists. Otherwise, NULL.
  3635. --*/
  3636. {
  3637. PDEVICE_EXTENSION deviceExtension =
  3638. ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
  3639. PLOGICAL_UNIT_EXTENSION luExtension;
  3640. PIRP irp;
  3641. PIO_STACK_LOCATION irpstack;
  3642. UNREFERENCED_PARAMETER( PathId );
  3643. UNREFERENCED_PARAMETER( Lun );
  3644. UNREFERENCED_PARAMETER( QueueTag );
  3645. luExtension = GetLogicalUnitExtension(deviceExtension, TargetId);
  3646. if (luExtension == NULL) {
  3647. return(NULL);
  3648. }
  3649. irp = luExtension->CurrentRequest;
  3650. irpstack = IoGetCurrentIrpStackLocation(irp);
  3651. return ((PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1);
  3652. } // end ScsiPortGetSrb()
  3653. BOOLEAN
  3654. ScsiPortValidateRange(
  3655. IN PVOID HwDeviceExtension,
  3656. IN INTERFACE_TYPE BusType,
  3657. IN ULONG SystemIoBusNumber,
  3658. IN SCSI_PHYSICAL_ADDRESS IoAddress,
  3659. IN ULONG NumberOfBytes,
  3660. IN BOOLEAN InIoSpace
  3661. )
  3662. /*++
  3663. Routine Description:
  3664. This routine should take an IO range and make sure that it is not already
  3665. in use by another adapter. This allows miniport drivers to probe IO where
  3666. an adapter could be, without worrying about messing up another card.
  3667. Arguments:
  3668. HwDeviceExtension - Used to find scsi managers internal structures
  3669. BusType - EISA, PCI, PC/MCIA, MCA, ISA, what?
  3670. SystemIoBusNumber - Which system bus?
  3671. IoAddress - Start of range
  3672. NumberOfBytes - Length of range
  3673. InIoSpace - Is range in IO space?
  3674. Return Value:
  3675. TRUE if range not claimed by another driver.
  3676. --*/
  3677. {
  3678. UNREFERENCED_PARAMETER( HwDeviceExtension );
  3679. UNREFERENCED_PARAMETER( BusType );
  3680. UNREFERENCED_PARAMETER( SystemIoBusNumber );
  3681. UNREFERENCED_PARAMETER( IoAddress );
  3682. UNREFERENCED_PARAMETER( NumberOfBytes );
  3683. UNREFERENCED_PARAMETER( InIoSpace );
  3684. //
  3685. // This is not implemented in NT.
  3686. //
  3687. return TRUE;
  3688. }
  3689. VOID
  3690. ScsiPortReadPortBufferUchar(
  3691. IN PUCHAR Port,
  3692. IN PUCHAR Buffer,
  3693. IN ULONG Count
  3694. )
  3695. /*++
  3696. Routine Description:
  3697. Read a buffer of unsigned bytes from the specified port address.
  3698. Arguments:
  3699. Port - Supplies a pointer to the port address.
  3700. Buffer - Supplies a pointer to the data buffer area.
  3701. Count - The count of items to move.
  3702. Return Value:
  3703. None
  3704. --*/
  3705. {
  3706. READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
  3707. }
  3708. VOID
  3709. ScsiPortReadPortBufferUshort(
  3710. IN PUSHORT Port,
  3711. IN PUSHORT Buffer,
  3712. IN ULONG Count
  3713. )
  3714. /*++
  3715. Routine Description:
  3716. Read a buffer of unsigned shorts from the specified port address.
  3717. Arguments:
  3718. Port - Supplies a pointer to the port address.
  3719. Buffer - Supplies a pointer to the data buffer area.
  3720. Count - The count of items to move.
  3721. Return Value:
  3722. None
  3723. --*/
  3724. {
  3725. READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
  3726. }
  3727. VOID
  3728. ScsiPortReadPortBufferUlong(
  3729. IN PULONG Port,
  3730. IN PULONG Buffer,
  3731. IN ULONG Count
  3732. )
  3733. /*++
  3734. Routine Description:
  3735. Read a buffer of unsigned longs from the specified port address.
  3736. Arguments:
  3737. Port - Supplies a pointer to the port address.
  3738. Buffer - Supplies a pointer to the data buffer area.
  3739. Count - The count of items to move.
  3740. Return Value:
  3741. None
  3742. --*/
  3743. {
  3744. READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
  3745. }
  3746. VOID
  3747. ScsiPortWritePortBufferUchar(
  3748. IN PUCHAR Port,
  3749. IN PUCHAR Buffer,
  3750. IN ULONG Count
  3751. )
  3752. /*++
  3753. Routine Description:
  3754. Write a buffer of unsigned bytes from the specified port address.
  3755. Arguments:
  3756. Port - Supplies a pointer to the port address.
  3757. Buffer - Supplies a pointer to the data buffer area.
  3758. Count - The count of items to move.
  3759. Return Value:
  3760. None
  3761. --*/
  3762. {
  3763. WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
  3764. }
  3765. VOID
  3766. ScsiPortWritePortBufferUshort(
  3767. IN PUSHORT Port,
  3768. IN PUSHORT Buffer,
  3769. IN ULONG Count
  3770. )
  3771. /*++
  3772. Routine Description:
  3773. Write a buffer of unsigned shorts from the specified port address.
  3774. Arguments:
  3775. Port - Supplies a pointer to the port address.
  3776. Buffer - Supplies a pointer to the data buffer area.
  3777. Count - The count of items to move.
  3778. Return Value:
  3779. None
  3780. --*/
  3781. {
  3782. WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
  3783. }
  3784. VOID
  3785. ScsiPortWritePortBufferUlong(
  3786. IN PULONG Port,
  3787. IN PULONG Buffer,
  3788. IN ULONG Count
  3789. )
  3790. /*++
  3791. Routine Description:
  3792. Write a buffer of unsigned longs from the specified port address.
  3793. Arguments:
  3794. Port - Supplies a pointer to the port address.
  3795. Buffer - Supplies a pointer to the data buffer area.
  3796. Count - The count of items to move.
  3797. Return Value:
  3798. None
  3799. --*/
  3800. {
  3801. WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
  3802. }
  3803. VOID
  3804. ScsiPortQuerySystemTime(
  3805. OUT PLARGE_INTEGER Port
  3806. )
  3807. /*++
  3808. Routine Description:
  3809. Return a dummy system time to caller. This routine is present only to
  3810. satisfy scsi miniport drivers that require the export.
  3811. Arguments:
  3812. CurrentTime - Supplies a pointer to a data buffer into which
  3813. to copy the system time.
  3814. Return Value:
  3815. None
  3816. --*/
  3817. {
  3818. Port->QuadPart = 0;
  3819. }
  3820. BOOLEAN
  3821. GetPciConfiguration(
  3822. PDRIVER_OBJECT DriverObject,
  3823. PDEVICE_OBJECT DeviceObject,
  3824. PPORT_CONFIGURATION_INFORMATION ConfigInformation,
  3825. ULONG NumberOfAccessRanges,
  3826. PVOID RegistryPath,
  3827. BOOLEAN IsMultiFunction,
  3828. PULONG BusNumber,
  3829. PULONG SlotNumber,
  3830. PULONG FunctionNumber
  3831. )
  3832. /*++
  3833. Routine Description:
  3834. Uses the Bus/Slot/Function numbers provided and gets slot information for
  3835. the device and register with hal for the resources.
  3836. Arguments:
  3837. DriverObject - Miniport driver object.
  3838. DeviceObject - Represents this adapter.
  3839. ConfigInformation - Template for configuration information passed to a
  3840. miniport driver via the FindAdapter routine.
  3841. NumberOfAccessRanges - from the HwInitializationData provided by the
  3842. miniport
  3843. RegistryPath - Service key path.
  3844. IsMultiFunctionDevice - as returned by FindPciDevice.
  3845. BusNumber - PCI Bus number provided by FindPciDevice.
  3846. SlotNumber - Slot number provided by FindPciDevice.
  3847. FunctionNumber - FunctionNumber provided by FindPciDevice.
  3848. Return Value:
  3849. TRUE if card found. BusNumber and Slotnumber will return values that
  3850. should be used to continue the search for additional cards, when a card
  3851. is found.
  3852. --*/
  3853. {
  3854. PCI_SLOT_NUMBER slotData;
  3855. PPCI_COMMON_CONFIG pciData;
  3856. PCI_COMMON_CONFIG pciBuffer;
  3857. ULONG pciBus = *BusNumber;
  3858. ULONG slotNumber = *SlotNumber;
  3859. ULONG functionNumber = *FunctionNumber;
  3860. ULONG i;
  3861. ULONG length;
  3862. ULONG rangeNumber = 0;
  3863. PACCESS_RANGE accessRange;
  3864. ULONG status;
  3865. PCM_RESOURCE_LIST resourceList;
  3866. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
  3867. UNICODE_STRING unicodeString;
  3868. CHAR vendorString[5];
  3869. CHAR deviceString[5];
  3870. pciData = &pciBuffer;
  3871. //
  3872. //
  3873. // typedef struct _PCI_SLOT_NUMBER {
  3874. // union {
  3875. // struct {
  3876. // ULONG DeviceNumber:5;
  3877. // ULONG FunctionNumber:3;
  3878. // ULONG Reserved:24;
  3879. // } bits;
  3880. // ULONG AsULONG;
  3881. // } u;
  3882. // } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
  3883. //
  3884. slotData.u.AsULONG = 0;
  3885. //
  3886. // Search each PCI bus.
  3887. //
  3888. //
  3889. // Look at each device.
  3890. //
  3891. slotData.u.bits.DeviceNumber = slotNumber;
  3892. slotData.u.bits.FunctionNumber = functionNumber;
  3893. //
  3894. // Look at each function.
  3895. //
  3896. length = HalGetBusDataByOffset(
  3897. PCIConfiguration,
  3898. pciBus,
  3899. slotData.u.AsULONG,
  3900. pciData,
  3901. 0,
  3902. FIELD_OFFSET(PCI_COMMON_CONFIG, DeviceSpecific));
  3903. ASSERT(length != 0);
  3904. ASSERT(pciData->VendorID != PCI_INVALID_VENDORID);
  3905. //
  3906. // Translate hex ids to strings.
  3907. //
  3908. sprintf(vendorString, "%04x", pciData->VendorID);
  3909. sprintf(deviceString, "%04x", pciData->DeviceID);
  3910. DebugPrint((1,
  3911. "GetPciConfiguration: Bus %x Slot %x Function %x Vendor %s Product %s %s\n",
  3912. pciBus,
  3913. slotNumber,
  3914. functionNumber,
  3915. vendorString,
  3916. deviceString,
  3917. (IsMultiFunction ? "MF" : "")));
  3918. //
  3919. // This is the miniport drivers slot. Allocate the
  3920. // resources.
  3921. //
  3922. RtlInitUnicodeString(&unicodeString, L"ScsiAdapter");
  3923. status = HalAssignSlotResources(RegistryPath,
  3924. &unicodeString,
  3925. DriverObject,
  3926. DeviceObject,
  3927. PCIBus,
  3928. pciBus,
  3929. slotData.u.AsULONG,
  3930. &resourceList);
  3931. if(!NT_SUCCESS(status)) {
  3932. DebugPrint((0, "GetPciConfiguration: HalAssignSlotResources failed with %x\n", status));
  3933. return FALSE;
  3934. }
  3935. //
  3936. // Walk resource list to update configuration information.
  3937. //
  3938. for (i = 0;
  3939. i < resourceList->List->PartialResourceList.Count;
  3940. i++) {
  3941. //
  3942. // Get resource descriptor.
  3943. //
  3944. resourceDescriptor =
  3945. &resourceList->List->PartialResourceList.PartialDescriptors[i];
  3946. //
  3947. // Check for interrupt descriptor.
  3948. //
  3949. if (resourceDescriptor->Type == CmResourceTypeInterrupt) {
  3950. ConfigInformation->BusInterruptLevel =
  3951. resourceDescriptor->u.Interrupt.Level;
  3952. ConfigInformation->BusInterruptVector =
  3953. resourceDescriptor->u.Interrupt.Vector;
  3954. //
  3955. // Check interrupt mode.
  3956. //
  3957. if ((resourceDescriptor->Flags ==
  3958. CM_RESOURCE_INTERRUPT_LATCHED)) {
  3959. ConfigInformation->InterruptMode = Latched;
  3960. } else if (resourceDescriptor->Flags ==
  3961. CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
  3962. ConfigInformation->InterruptMode = LevelSensitive;
  3963. }
  3964. }
  3965. //
  3966. // Check for port descriptor.
  3967. //
  3968. if (resourceDescriptor->Type == CmResourceTypePort) {
  3969. //
  3970. // Verify range count does not exceed what the
  3971. // miniport indicated.
  3972. //
  3973. if (NumberOfAccessRanges > rangeNumber) {
  3974. //
  3975. // Get next access range.
  3976. //
  3977. accessRange =
  3978. &((*(ConfigInformation->AccessRanges))[rangeNumber]);
  3979. accessRange->RangeStart =
  3980. resourceDescriptor->u.Port.Start;
  3981. accessRange->RangeLength =
  3982. resourceDescriptor->u.Port.Length;
  3983. accessRange->RangeInMemory = FALSE;
  3984. rangeNumber++;
  3985. }
  3986. }
  3987. //
  3988. // Check for memory descriptor.
  3989. //
  3990. if (resourceDescriptor->Type == CmResourceTypeMemory) {
  3991. //
  3992. // Verify range count does not exceed what the
  3993. // miniport indicated.
  3994. //
  3995. if (NumberOfAccessRanges > rangeNumber) {
  3996. //
  3997. // Get next access range.
  3998. //
  3999. accessRange =
  4000. &((*(ConfigInformation->AccessRanges))[rangeNumber]);
  4001. accessRange->RangeStart =
  4002. resourceDescriptor->u.Memory.Start;
  4003. accessRange->RangeLength =
  4004. resourceDescriptor->u.Memory.Length;
  4005. accessRange->RangeInMemory = TRUE;
  4006. rangeNumber++;
  4007. }
  4008. }
  4009. //
  4010. // Check for DMA descriptor.
  4011. //
  4012. if (resourceDescriptor->Type == CmResourceTypeDma) {
  4013. ConfigInformation->DmaChannel =
  4014. resourceDescriptor->u.Dma.Channel;
  4015. ConfigInformation->DmaPort =
  4016. resourceDescriptor->u.Dma.Port;
  4017. }
  4018. } // next resource descriptor
  4019. ExFreePool(resourceList);
  4020. //
  4021. // Update bus and slot numbers.
  4022. //
  4023. *BusNumber = pciBus;
  4024. *SlotNumber = slotNumber;
  4025. if(IsMultiFunction) {
  4026. //
  4027. // Save away the next function number to check.
  4028. //
  4029. *FunctionNumber = functionNumber + 1;
  4030. } else {
  4031. //
  4032. // this isn't multifunction so make sure we loop around
  4033. // to the next one.
  4034. //
  4035. *FunctionNumber = PCI_MAX_FUNCTION;
  4036. }
  4037. ConfigInformation->SystemIoBusNumber = pciBus;
  4038. ConfigInformation->SlotNumber = slotData.u.AsULONG;
  4039. return TRUE;
  4040. } // GetPciConfiguration()
  4041. ULONG
  4042. ScsiPortSetBusDataByOffset(
  4043. IN PVOID DeviceExtension,
  4044. IN ULONG BusDataType,
  4045. IN ULONG SystemIoBusNumber,
  4046. IN ULONG SlotNumber,
  4047. IN PVOID Buffer,
  4048. IN ULONG Offset,
  4049. IN ULONG Length
  4050. )
  4051. /*++
  4052. Routine Description:
  4053. The function returns writes bus data to a specific offset within a slot.
  4054. Arguments:
  4055. DeviceExtension - State information for a particular adapter.
  4056. BusDataType - Supplies the type of bus.
  4057. SystemIoBusNumber - Indicates which system IO bus.
  4058. SlotNumber - Indicates which slot.
  4059. Buffer - Supplies the data to write.
  4060. Offset - Byte offset to begin the write.
  4061. Length - Supplies a count in bytes of the maximum amount to return.
  4062. Return Value:
  4063. Number of bytes written.
  4064. --*/
  4065. {
  4066. UNREFERENCED_PARAMETER( DeviceExtension );
  4067. return(HalSetBusDataByOffset(BusDataType,
  4068. SystemIoBusNumber,
  4069. SlotNumber,
  4070. Buffer,
  4071. Offset,
  4072. Length));
  4073. } // end ScsiPortSetBusDataByOffset()
  4074. BOOLEAN
  4075. FindPciDevice(
  4076. PHW_INITIALIZATION_DATA HwInitializationData,
  4077. PULONG BusNumber,
  4078. PULONG SlotNumber,
  4079. PULONG FunctionNumber,
  4080. PBOOLEAN IsMultiFunction
  4081. )
  4082. /*++
  4083. Routine Description:
  4084. Walk PCI slot information looking for Vendor and Product ID matches.
  4085. Arguments:
  4086. HwInitializationData - Miniport description.
  4087. BusNumber - Starting PCI bus for this search.
  4088. SlotNumber - Starting slot number for this search.
  4089. FunctionNumber - Starting function number for this search.
  4090. Return Value:
  4091. TRUE if card found.
  4092. Bus, Slot and Function number will contain the address of the adapter
  4093. found once this routine completes. These values should be provided to
  4094. GetPciConfiguration.
  4095. --*/
  4096. {
  4097. PCI_SLOT_NUMBER slotData;
  4098. PPCI_COMMON_CONFIG pciData;
  4099. PCI_COMMON_CONFIG pciBuffer;
  4100. ULONG pciBus;
  4101. ULONG slotNumber;
  4102. ULONG functionNumber;
  4103. ULONG length;
  4104. BOOLEAN moreSlots = TRUE;
  4105. CHAR vendorString[5];
  4106. CHAR deviceString[5];
  4107. pciData = &pciBuffer;
  4108. //
  4109. //
  4110. // typedef struct _PCI_SLOT_NUMBER {
  4111. // union {
  4112. // struct {
  4113. // ULONG DeviceNumber:5;
  4114. // ULONG FunctionNumber:3;
  4115. // ULONG Reserved:24;
  4116. // } bits;
  4117. // ULONG AsULONG;
  4118. // } u;
  4119. // } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
  4120. //
  4121. slotData.u.AsULONG = 0;
  4122. //
  4123. // Search each PCI bus.
  4124. //
  4125. for (pciBus = *BusNumber; moreSlots && pciBus < 256; pciBus++) {
  4126. //
  4127. // Look at each device.
  4128. //
  4129. for (slotNumber = *SlotNumber;
  4130. moreSlots && slotNumber < PCI_MAX_DEVICES;
  4131. slotNumber++) {
  4132. slotData.u.bits.DeviceNumber = slotNumber;
  4133. *IsMultiFunction = FALSE;
  4134. //
  4135. // Look at each function.
  4136. //
  4137. for (functionNumber = *FunctionNumber;
  4138. moreSlots && functionNumber < PCI_MAX_FUNCTION;
  4139. functionNumber++) {
  4140. slotData.u.bits.FunctionNumber = functionNumber;
  4141. length = HalGetBusDataByOffset(
  4142. PCIConfiguration,
  4143. pciBus,
  4144. slotData.u.AsULONG,
  4145. pciData,
  4146. 0,
  4147. FIELD_OFFSET(PCI_COMMON_CONFIG, DeviceSpecific));
  4148. if (length == 0) {
  4149. //
  4150. // Out of PCI buses, all done.
  4151. //
  4152. moreSlots = FALSE;
  4153. break;
  4154. }
  4155. if (pciData->VendorID == PCI_INVALID_VENDORID) {
  4156. if(*IsMultiFunction) {
  4157. //
  4158. // Of course function numbers may be sparse - keep
  4159. // checking anyway.
  4160. //
  4161. continue;
  4162. } else {
  4163. //
  4164. // But since this isn't a multifunction card there's
  4165. // nothing else to check in this slot. Or if the
  4166. // function is zero then it's not MF.
  4167. //
  4168. break;
  4169. }
  4170. }
  4171. if((slotData.u.bits.FunctionNumber == 0) &&
  4172. PCI_MULTIFUNCTION_DEVICE(pciData)) {
  4173. *IsMultiFunction = TRUE;
  4174. }
  4175. //
  4176. // Translate hex ids to strings.
  4177. //
  4178. sprintf(vendorString, "%04x", pciData->VendorID);
  4179. sprintf(deviceString, "%04x", pciData->DeviceID);
  4180. DebugPrint((1,
  4181. "FindPciDevice: Bus %x Slot %x Function %x Vendor %s Product %s %s\n",
  4182. pciBus,
  4183. slotNumber,
  4184. functionNumber,
  4185. vendorString,
  4186. deviceString,
  4187. (*IsMultiFunction ? "MF" : "")));
  4188. //
  4189. // Compare strings.
  4190. //
  4191. if (_strnicmp(vendorString,
  4192. HwInitializationData->VendorId,
  4193. HwInitializationData->VendorIdLength) ||
  4194. _strnicmp(deviceString,
  4195. HwInitializationData->DeviceId,
  4196. HwInitializationData->DeviceIdLength)) {
  4197. //
  4198. // Not our PCI device. Try next device/function
  4199. //
  4200. if(*IsMultiFunction) {
  4201. // check next function.
  4202. continue;
  4203. } else {
  4204. // check next slot.
  4205. break;
  4206. }
  4207. }
  4208. *BusNumber = pciBus;
  4209. *SlotNumber = slotNumber;
  4210. *FunctionNumber = functionNumber;
  4211. return TRUE;
  4212. } // next PCI function
  4213. *FunctionNumber = 0;
  4214. } // next PCI slot
  4215. *SlotNumber = 0;
  4216. } // next PCI bus
  4217. return FALSE;
  4218. } // GetPciConfiguration()
  4219. VOID
  4220. SpGetSupportedAdapterControlFunctions(
  4221. PDEVICE_EXTENSION Adapter
  4222. )
  4223. /*++
  4224. Routine Description:
  4225. This routine will query the miniport to determine which adapter control
  4226. types are supported for the specified adapter. The
  4227. SupportedAdapterControlBitmap in the adapter extension will be updated with
  4228. the data returned by the miniport. These flags are used to determine
  4229. what functionality (for power management and such) the miniport will support
  4230. Arguments:
  4231. Adapter - the adapter to query
  4232. Return Value:
  4233. none
  4234. --*/
  4235. {
  4236. UCHAR buffer[sizeof(SCSI_SUPPORTED_CONTROL_TYPE_LIST) +
  4237. (sizeof(BOOLEAN) * (ScsiAdapterControlMax + 1))];
  4238. PSCSI_SUPPORTED_CONTROL_TYPE_LIST typeList =
  4239. (PSCSI_SUPPORTED_CONTROL_TYPE_LIST) buffer;
  4240. SCSI_ADAPTER_CONTROL_STATUS status;
  4241. if(Adapter->HwAdapterControl == NULL) {
  4242. //
  4243. // Adapter control is not supported by the miniport or the miniport
  4244. // isn't pnp (in which case it's not supported by scsiport) - the
  4245. // supported array has already been cleared so we can just quit now.
  4246. //
  4247. return;
  4248. }
  4249. RtlZeroMemory(typeList, (sizeof(SCSI_SUPPORTED_CONTROL_TYPE_LIST) +
  4250. sizeof(BOOLEAN) * (ScsiAdapterControlMax + 1)));
  4251. typeList->MaxControlType = ScsiAdapterControlMax;
  4252. #if DBG
  4253. typeList->SupportedTypeList[ScsiAdapterControlMax] = 0x63;
  4254. #endif
  4255. status = SpCallAdapterControl(Adapter,
  4256. ScsiQuerySupportedControlTypes,
  4257. typeList);
  4258. if(status == ScsiAdapterControlSuccess) {
  4259. Adapter->HasShutdown = typeList->SupportedTypeList[ScsiStopAdapter];
  4260. Adapter->HasSetBoot = typeList->SupportedTypeList[ScsiSetBootConfig];
  4261. }
  4262. return;
  4263. }
  4264. SCSI_ADAPTER_CONTROL_STATUS
  4265. SpCallAdapterControl(
  4266. IN PDEVICE_EXTENSION Adapter,
  4267. IN SCSI_ADAPTER_CONTROL_TYPE ControlType,
  4268. IN PVOID Parameters
  4269. )
  4270. {
  4271. DebugPrint((2, "SpCallAdapterControl: Calling adapter control %x for adapter %#08lx with param %#08lx\n", ControlType, Adapter, Parameters));
  4272. return Adapter->HwAdapterControl(
  4273. Adapter->HwDeviceExtension,
  4274. ControlType,
  4275. Parameters);
  4276. }
  4277. VOID
  4278. SpUnload(
  4279. IN PDRIVER_OBJECT DriverObject
  4280. )
  4281. {
  4282. ULONG i;
  4283. UNREFERENCED_PARAMETER( DriverObject );
  4284. for(i = 0; i < MAXIMUM_NUMBER_OF_SCSIPORT_OBJECTS; i++) {
  4285. PDEVICE_OBJECT deviceObject;
  4286. deviceObject = ScsiPortDeviceObject[i];
  4287. if(deviceObject != NULL) {
  4288. PDEVICE_EXTENSION deviceExtension;
  4289. deviceExtension = deviceObject->DeviceExtension;
  4290. if(deviceExtension->HasShutdown) {
  4291. SpCallAdapterControl(deviceExtension, ScsiStopAdapter, NULL);
  4292. if(deviceExtension->HasSetBoot) {
  4293. SpCallAdapterControl(deviceExtension,
  4294. ScsiSetBootConfig,
  4295. NULL);
  4296. }
  4297. }
  4298. }
  4299. //
  4300. // Now that we've shut this one down we can't use it anymore.
  4301. // Since the memory will be reclaimed by the OS we can just throw it
  4302. // away.
  4303. //
  4304. ScsiPortDeviceObject[i] = NULL;
  4305. }
  4306. return;
  4307. }
  4308. #endif /* DECSTATION */