Source code of Windows XP (NT5)
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.

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