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

2414 lines
56 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. port.c
  5. Abstract:
  6. This is the NT SCSI port driver.
  7. Authors:
  8. Mike Glass
  9. Jeff Havens
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. This module is a dll for the kernel.
  14. Revision History:
  15. --*/
  16. #include "port.h"
  17. #if DBG
  18. static const char *__file__ = __FILE__;
  19. #endif
  20. #if SCSIDBG_ENABLED
  21. ULONG ScsiDebug = 0;
  22. ULONG ScsiPortCheckSrbDataHashTable = 1;
  23. #endif
  24. #ifdef POOL_TAGGING
  25. #ifdef ExAllocatePool
  26. #undef ExAllocatePool
  27. #endif
  28. #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'PscS')
  29. #endif
  30. //
  31. // Routines providing service to hardware dependent driver.
  32. //
  33. PVOID
  34. ScsiPortGetLogicalUnit(
  35. IN PVOID HwDeviceExtension,
  36. IN UCHAR PathId,
  37. IN UCHAR TargetId,
  38. IN UCHAR Lun
  39. )
  40. /*++
  41. Routine Description:
  42. Walk port driver's logical unit extension list searching
  43. for entry.
  44. Arguments:
  45. HwDeviceExtension - The port driver's device extension follows
  46. the miniport's device extension and contains a pointer to
  47. the logical device extension list.
  48. PathId, TargetId and Lun - identify which logical unit on the
  49. SCSI buses.
  50. Return Value:
  51. If entry found return miniport driver's logical unit extension.
  52. Else, return NULL.
  53. --*/
  54. {
  55. PADAPTER_EXTENSION deviceExtension;
  56. PLOGICAL_UNIT_EXTENSION logicalUnit;
  57. DebugPrint((3, "ScsiPortGetLogicalUnit: TargetId %d\n",
  58. TargetId));
  59. //
  60. // Get pointer to port driver device extension.
  61. //
  62. deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  63. //
  64. // Get a pointer to the logical unit.
  65. //
  66. logicalUnit = GetLogicalUnitExtension(deviceExtension,
  67. PathId,
  68. TargetId,
  69. Lun,
  70. FALSE,
  71. FALSE);
  72. if(logicalUnit != NULL) {
  73. return logicalUnit->HwLogicalUnitExtension;
  74. }
  75. return NULL;
  76. } // end ScsiPortGetLogicalUnit()
  77. BOOLEAN SpLunIoLogActive = TRUE;
  78. VOID
  79. ScsiPortNotification(
  80. IN SCSI_NOTIFICATION_TYPE NotificationType,
  81. IN PVOID HwDeviceExtension,
  82. ...
  83. )
  84. /*++
  85. Routine Description:
  86. Arguments:
  87. Return Value:
  88. --*/
  89. {
  90. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  91. PLOGICAL_UNIT_EXTENSION logicalUnit;
  92. PSRB_DATA srbData;
  93. PSCSI_REQUEST_BLOCK srb;
  94. UCHAR pathId;
  95. UCHAR targetId;
  96. UCHAR lun;
  97. va_list ap;
  98. va_start(ap, HwDeviceExtension);
  99. switch (NotificationType) {
  100. case NextRequest:
  101. //
  102. // Start next packet on adapter's queue.
  103. //
  104. deviceExtension->InterruptData.InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
  105. break;
  106. case RequestComplete:
  107. srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
  108. ASSERT(srb->SrbStatus != SRB_STATUS_PENDING);
  109. ASSERT(srb->SrbStatus != SRB_STATUS_SUCCESS ||
  110. srb->ScsiStatus == SCSISTAT_GOOD ||
  111. srb->Function != SRB_FUNCTION_EXECUTE_SCSI);
  112. //
  113. // If this srb has already been completed then return, otherwise
  114. // clear the active flag.
  115. //
  116. if (srb->SrbFlags & SRB_FLAGS_IS_ACTIVE) {
  117. srb->SrbFlags &= ~SRB_FLAGS_IS_ACTIVE;
  118. } else {
  119. va_end(ap);
  120. return;
  121. }
  122. //
  123. // Treat abort completions as a special case.
  124. //
  125. if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
  126. ASSERT(FALSE);
  127. logicalUnit = GetLogicalUnitExtension(deviceExtension,
  128. srb->PathId,
  129. srb->TargetId,
  130. srb->Lun,
  131. FALSE,
  132. FALSE);
  133. logicalUnit->CompletedAbort =
  134. deviceExtension->InterruptData.CompletedAbort;
  135. deviceExtension->InterruptData.CompletedAbort = logicalUnit;
  136. } else {
  137. //
  138. // Validate the srb data.
  139. //
  140. srbData = srb->OriginalRequest;
  141. #if DBG
  142. ASSERT_SRB_DATA(srbData);
  143. ASSERT(srbData->CurrentSrb == srb);
  144. ASSERT(srbData->CurrentSrb != NULL &&
  145. srbData->CompletedRequests == NULL);
  146. if ((srb->SrbStatus == SRB_STATUS_SUCCESS) &&
  147. (IS_READ(srb) || IS_WRITE(srb))) {
  148. ASSERT(srb->DataTransferLength);
  149. }
  150. #endif
  151. //
  152. // Append this request to the LUN's IO history log.
  153. //
  154. if (SpLunIoLogActive == TRUE &&
  155. srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
  156. PSP_LUN_IO_LOG ioLogEntry;
  157. ULONG index;
  158. PLOGICAL_UNIT_EXTENSION luExt = ((PSRB_DATA)(srb->OriginalRequest))->LogicalUnit;
  159. index = luExt->IoLogIndex;
  160. ioLogEntry = &luExt->IoLog[index];
  161. ioLogEntry->TickCount = ((PSRB_DATA)(srb->OriginalRequest))->TickCount;
  162. ioLogEntry->SrbStatus = srb->SrbStatus;
  163. ioLogEntry->ScsiStatus = srb->ScsiStatus;
  164. ioLogEntry->CdbLength = srb->CdbLength;
  165. ioLogEntry->Tag = srb->QueueTag;
  166. ioLogEntry->SenseDataLength = srb->SenseInfoBufferLength;
  167. ioLogEntry->InternalStatus = srb->InternalStatus;
  168. RtlMoveMemory(ioLogEntry->Cdb, srb->Cdb, srb->CdbLength);
  169. if (ioLogEntry->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  170. RtlMoveMemory(ioLogEntry->SenseData,
  171. srb->SenseInfoBuffer,
  172. (srb->SenseInfoBufferLength <= 18) ?
  173. srb->SenseInfoBufferLength : 18);
  174. }
  175. index++;
  176. if (index == 10) {
  177. index = 0;
  178. }
  179. luExt->IoLogIndex = index;
  180. if (luExt->IoLogEntries < 10) {
  181. luExt->IoLogEntries++;
  182. }
  183. }
  184. if (srb->SrbStatus == SRB_STATUS_BUSY) {
  185. DebugPrint((0, "ScsiPortNotification: lun is busy (srb %p)\n", srb));
  186. }
  187. if(((srb->SrbStatus == SRB_STATUS_SUCCESS) ||
  188. (srb->SrbStatus == SRB_STATUS_DATA_OVERRUN)) &&
  189. (TEST_FLAG(srb->SrbFlags, SRB_FLAGS_UNSPECIFIED_DIRECTION))) {
  190. ASSERT(srbData->OriginalDataTransferLength >=
  191. srb->DataTransferLength);
  192. }
  193. srbData->CompletedRequests =
  194. deviceExtension->InterruptData.CompletedRequests;
  195. deviceExtension->InterruptData.CompletedRequests = srbData;
  196. //
  197. // Cache away the last logical unit we touched in the miniport.
  198. // This is cleared when we come out of the miniport
  199. // synchronization but provides a shortcut for finding the
  200. // logical unit before going into the hash table.
  201. //
  202. deviceExtension->CachedLogicalUnit = srbData->LogicalUnit;
  203. }
  204. break;
  205. case ResetDetected:
  206. //
  207. // Notifiy the port driver that a reset has been reported.
  208. //
  209. deviceExtension->InterruptData.InterruptFlags |=
  210. PD_RESET_REPORTED | PD_RESET_HOLD;
  211. break;
  212. case NextLuRequest:
  213. //
  214. // The miniport driver is ready for the next request and
  215. // can accept a request for this logical unit.
  216. //
  217. pathId = va_arg(ap, UCHAR);
  218. targetId = va_arg(ap, UCHAR);
  219. lun = va_arg(ap, UCHAR);
  220. //
  221. // A next request is impiled by this notification so set the
  222. // ready for next reqeust flag.
  223. //
  224. deviceExtension->InterruptData.InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
  225. logicalUnit = deviceExtension->CachedLogicalUnit;
  226. if((logicalUnit == NULL) ||
  227. (logicalUnit->TargetId != targetId) ||
  228. (logicalUnit->PathId != pathId) ||
  229. (logicalUnit->Lun != lun)) {
  230. logicalUnit = GetLogicalUnitExtension(deviceExtension,
  231. pathId,
  232. targetId,
  233. lun,
  234. FALSE,
  235. FALSE);
  236. }
  237. if (logicalUnit != NULL && logicalUnit->ReadyLogicalUnit != NULL) {
  238. //
  239. // Since our ReadyLogicalUnit link field is not NULL we must
  240. // have already been linked onto a ReadyLogicalUnit list.
  241. // There is nothing to do.
  242. //
  243. break;
  244. }
  245. //
  246. // Don't process this as request for the next logical unit, if
  247. // there is a untagged request for active for this logical unit.
  248. // The logical unit will be started when untagged request completes.
  249. //
  250. if (logicalUnit != NULL && logicalUnit->CurrentUntaggedRequest == NULL) {
  251. //
  252. // Add the logical unit to the chain of logical units that
  253. // another request maybe processed for.
  254. //
  255. logicalUnit->ReadyLogicalUnit =
  256. deviceExtension->InterruptData.ReadyLogicalUnit;
  257. deviceExtension->InterruptData.ReadyLogicalUnit = logicalUnit;
  258. }
  259. break;
  260. case CallDisableInterrupts:
  261. ASSERT(deviceExtension->InterruptData.InterruptFlags &
  262. PD_DISABLE_INTERRUPTS);
  263. //
  264. // The miniport wants us to call the specified routine
  265. // with interrupts disabled. This is done after the current
  266. // HwRequestInterrutp routine completes. Indicate the call is
  267. // needed and save the routine to be called.
  268. //
  269. deviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;
  270. if (SpVerifierActive(deviceExtension)) {
  271. deviceExtension->VerifierExtension->RealHwRequestInterrupt =
  272. va_arg(ap, PHW_INTERRUPT);
  273. deviceExtension->HwRequestInterrupt = SpHwRequestInterruptVrfy;
  274. } else {
  275. deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
  276. }
  277. break;
  278. case CallEnableInterrupts:
  279. //
  280. // The miniport wants us to call the specified routine
  281. // with interrupts enabled this is done from the DPC.
  282. // Disable calls to the interrupt routine, indicate the call is
  283. // needed and save the routine to be called.
  284. //
  285. deviceExtension->InterruptData.InterruptFlags |=
  286. PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;
  287. if (SpVerifierActive(deviceExtension)) {
  288. deviceExtension->VerifierExtension->RealHwRequestInterrupt =
  289. va_arg(ap, PHW_INTERRUPT);
  290. deviceExtension->HwRequestInterrupt = SpHwRequestInterruptVrfy;
  291. } else {
  292. deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
  293. }
  294. break;
  295. case RequestTimerCall:
  296. //
  297. // The driver wants to set the miniport timer.
  298. // Save the timer parameters.
  299. //
  300. deviceExtension->InterruptData.InterruptFlags |=
  301. PD_TIMER_CALL_REQUEST;
  302. deviceExtension->InterruptData.HwTimerRequest =
  303. va_arg(ap, PHW_INTERRUPT);
  304. deviceExtension->InterruptData.MiniportTimerValue =
  305. va_arg(ap, ULONG);
  306. break;
  307. case WMIEvent: {
  308. //
  309. // The miniport wishes to post a WMI event for the adapter
  310. // or a specified SCSI target.
  311. //
  312. PWMI_MINIPORT_REQUEST_ITEM lastMiniPortRequest;
  313. PWMI_MINIPORT_REQUEST_ITEM wmiMiniPortRequest;
  314. PWNODE_EVENT_ITEM wnodeEventItem;
  315. PWNODE_EVENT_ITEM wnodeEventItemCopy;
  316. wnodeEventItem = va_arg(ap, PWNODE_EVENT_ITEM);
  317. pathId = va_arg(ap, UCHAR);
  318. //
  319. // if pathID is 0xFF, that means that the WmiEevent is from the
  320. // adapter, no targetId or lun is neccesary
  321. //
  322. if (pathId != 0xFF) {
  323. targetId = va_arg(ap, UCHAR);
  324. lun = va_arg(ap, UCHAR);
  325. }
  326. //
  327. // Validate the event first. Then attempt to obtain a free
  328. // WMI_MINIPORT_REQUEST_ITEM structure so that we may store
  329. // this request and process it at DPC level later. If none
  330. // are obtained or the event is bad, we ignore the request.
  331. //
  332. if ((wnodeEventItem == NULL) ||
  333. (wnodeEventItem->WnodeHeader.BufferSize >
  334. WMI_MINIPORT_EVENT_ITEM_MAX_SIZE)) {
  335. va_end(ap); // size, no free WMI_MINIPORT_REQUEST_ITEMs left]
  336. return;
  337. }
  338. //
  339. // Remove the WMI_MINIPORT_REQUEST_ITEM from the free list.
  340. //
  341. wmiMiniPortRequest = SpWmiPopFreeRequestItem(deviceExtension);
  342. //
  343. // Log an error if a free request item could not be dequeued
  344. // (log only once in the lifetime of this adapter).
  345. //
  346. if (wmiMiniPortRequest == NULL) {
  347. if (!deviceExtension->WmiFreeMiniPortRequestsExhausted) {
  348. deviceExtension->WmiFreeMiniPortRequestsExhausted = TRUE;
  349. //
  350. // If pathId is 0xFF that means that pathId and targetId
  351. // will be not be defined
  352. //
  353. if (pathId != 0xFF) {
  354. ScsiPortLogError(HwDeviceExtension,
  355. NULL,
  356. pathId,
  357. targetId,
  358. lun,
  359. SP_LOST_WMI_MINIPORT_REQUEST,
  360. 0);
  361. } else {
  362. ScsiPortLogError(HwDeviceExtension,
  363. NULL,
  364. pathId,
  365. 0,
  366. 0,
  367. SP_LOST_WMI_MINIPORT_REQUEST,
  368. 0);
  369. } // pathId != 0xFF
  370. }
  371. va_end(ap);
  372. return;
  373. }
  374. //
  375. // Save information pertaining to this WMI request for later
  376. // processing.
  377. //
  378. deviceExtension->InterruptData.InterruptFlags |= PD_WMI_REQUEST;
  379. wmiMiniPortRequest->TypeOfRequest = (UCHAR)WMIEvent;
  380. wmiMiniPortRequest->PathId = pathId;
  381. //
  382. // If pathId was 0xFF, then there is no defined value for
  383. // targetId or lun
  384. //
  385. if (pathId != 0xFF) {
  386. wmiMiniPortRequest->TargetId = targetId;
  387. wmiMiniPortRequest->Lun = lun;
  388. }
  389. RtlCopyMemory(wmiMiniPortRequest->WnodeEventItem,
  390. wnodeEventItem,
  391. wnodeEventItem->WnodeHeader.BufferSize);
  392. //
  393. // Queue the new WMI_MINIPORT_REQUEST_ITEM to the end of list in the
  394. // interrupt data structure.
  395. //
  396. wmiMiniPortRequest->NextRequest = NULL;
  397. lastMiniPortRequest =
  398. deviceExtension->InterruptData.WmiMiniPortRequests;
  399. if (lastMiniPortRequest) {
  400. while (lastMiniPortRequest->NextRequest) {
  401. lastMiniPortRequest = lastMiniPortRequest->NextRequest;
  402. }
  403. lastMiniPortRequest->NextRequest = wmiMiniPortRequest;
  404. } else {
  405. deviceExtension->InterruptData.WmiMiniPortRequests =
  406. wmiMiniPortRequest;
  407. }
  408. break;
  409. }
  410. case WMIReregister: {
  411. //
  412. // The miniport wishes to re-register the GUIDs for the adapter or
  413. // a specified SCSI target.
  414. //
  415. PWMI_MINIPORT_REQUEST_ITEM lastMiniPortRequest;
  416. PWMI_MINIPORT_REQUEST_ITEM wmiMiniPortRequest;
  417. pathId = va_arg(ap, UCHAR);
  418. //
  419. // if pathID is 0xFF, that means that we're re-registering the
  420. // adapter no targetId or lun is neccesary
  421. //
  422. if (pathId != 0xFF) {
  423. targetId = va_arg(ap, UCHAR);
  424. lun = va_arg(ap, UCHAR);
  425. }
  426. //
  427. // Attempt to obtain a free WMI_MINIPORT_REQUEST_ITEM structure
  428. // so that we may store this request and process it at DPC
  429. // level later. If none are obtained or the event is bad, we
  430. // ignore the request.
  431. //
  432. // Remove a WMI_MINPORT_REQUEST_ITEM from the free list.
  433. //
  434. wmiMiniPortRequest = SpWmiPopFreeRequestItem(deviceExtension);
  435. if (wmiMiniPortRequest == NULL) {
  436. //
  437. // Log an error if a free request item could not be dequeued
  438. // (log only once in the lifetime of this adapter).
  439. //
  440. if (!deviceExtension->WmiFreeMiniPortRequestsExhausted) {
  441. deviceExtension->WmiFreeMiniPortRequestsExhausted = TRUE;
  442. //
  443. // If pathId is 0xFF that means that pathId and targetId
  444. // will be not be defined
  445. //
  446. if (pathId != 0xFF) {
  447. ScsiPortLogError(HwDeviceExtension,
  448. NULL,
  449. pathId,
  450. targetId,
  451. lun,
  452. SP_LOST_WMI_MINIPORT_REQUEST,
  453. 0);
  454. } else {
  455. ScsiPortLogError(HwDeviceExtension,
  456. NULL,
  457. pathId,
  458. 0,
  459. 0,
  460. SP_LOST_WMI_MINIPORT_REQUEST,
  461. 0);
  462. } // pathId != 0xFF
  463. }
  464. va_end(ap);
  465. return;
  466. }
  467. //
  468. // Save information pertaining to this WMI request for later
  469. // processing.
  470. //
  471. deviceExtension->InterruptData.InterruptFlags |= PD_WMI_REQUEST;
  472. wmiMiniPortRequest->TypeOfRequest = (UCHAR)WMIReregister;
  473. wmiMiniPortRequest->PathId = pathId;
  474. //
  475. // If pathId was 0xFF, then there is no defined value for
  476. // targetId or lun
  477. //
  478. if (pathId != 0xFF) {
  479. wmiMiniPortRequest->TargetId = targetId;
  480. wmiMiniPortRequest->Lun = lun;
  481. }
  482. //
  483. // Queue the new WMI_MINIPORT_REQUEST_ITEM to the end of list in the
  484. // interrupt data structure.
  485. //
  486. wmiMiniPortRequest->NextRequest = NULL;
  487. lastMiniPortRequest =
  488. deviceExtension->InterruptData.WmiMiniPortRequests;
  489. if (lastMiniPortRequest) {
  490. while (lastMiniPortRequest->NextRequest) {
  491. lastMiniPortRequest = lastMiniPortRequest->NextRequest;
  492. }
  493. lastMiniPortRequest->NextRequest = wmiMiniPortRequest;
  494. } else {
  495. deviceExtension->InterruptData.WmiMiniPortRequests =
  496. wmiMiniPortRequest;
  497. }
  498. break;
  499. }
  500. case BusChangeDetected: {
  501. SET_FLAG(deviceExtension->InterruptData.InterruptFlags,
  502. PD_BUS_CHANGE_DETECTED);
  503. break;
  504. }
  505. default: {
  506. ASSERT(0);
  507. break;
  508. }
  509. }
  510. va_end(ap);
  511. //
  512. // Request a DPC be queued after the interrupt completes.
  513. //
  514. deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;
  515. } // end ScsiPortNotification()
  516. VOID
  517. ScsiPortFlushDma(
  518. IN PVOID HwDeviceExtension
  519. )
  520. /*++
  521. Routine Description:
  522. This routine checks to see if the perivious IoMapTransfer has been done
  523. started. If it has not, then the PD_MAP_TRANSER flag is cleared, and the
  524. routine returns; otherwise, this routine schedules a DPC which will call
  525. IoFlushAdapter buffers.
  526. Arguments:
  527. HwDeviceExtension - Supplies a the hardware device extension for the
  528. host bus adapter which will be doing the data transfer.
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  534. if(Sp64BitPhysicalAddresses) {
  535. KeBugCheckEx(PORT_DRIVER_INTERNAL,
  536. 0,
  537. STATUS_NOT_SUPPORTED,
  538. (ULONG_PTR) HwDeviceExtension,
  539. (ULONG_PTR) deviceExtension->DeviceObject->DriverObject);
  540. }
  541. if (deviceExtension->InterruptData.InterruptFlags & PD_MAP_TRANSFER) {
  542. //
  543. // The transfer has not been started so just clear the map transfer
  544. // flag and return.
  545. //
  546. deviceExtension->InterruptData.InterruptFlags &= ~PD_MAP_TRANSFER;
  547. return;
  548. }
  549. deviceExtension->InterruptData.InterruptFlags |= PD_FLUSH_ADAPTER_BUFFERS;
  550. //
  551. // Request a DPC be queued after the interrupt completes.
  552. //
  553. deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;
  554. return;
  555. }
  556. VOID
  557. ScsiPortIoMapTransfer(
  558. IN PVOID HwDeviceExtension,
  559. IN PSCSI_REQUEST_BLOCK Srb,
  560. IN PVOID LogicalAddress,
  561. IN ULONG Length
  562. )
  563. /*++
  564. Routine Description:
  565. Saves the parameters for the call to IoMapTransfer and schedules the DPC
  566. if necessary.
  567. Arguments:
  568. HwDeviceExtension - Supplies a the hardware device extension for the
  569. host bus adapter which will be doing the data transfer.
  570. Srb - Supplies the particular request that data transfer is for.
  571. LogicalAddress - Supplies the logical address where the transfer should
  572. begin.
  573. Length - Supplies the maximum length in bytes of the transfer.
  574. Return Value:
  575. None.
  576. --*/
  577. {
  578. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  579. PSRB_DATA srbData = Srb->OriginalRequest;
  580. ASSERT_SRB_DATA(srbData);
  581. //
  582. // If this is a 64-bit system then this call is illegal. Bugcheck.
  583. //
  584. if(Sp64BitPhysicalAddresses) {
  585. KeBugCheckEx(PORT_DRIVER_INTERNAL,
  586. 1,
  587. STATUS_NOT_SUPPORTED,
  588. (ULONG_PTR) HwDeviceExtension,
  589. (ULONG_PTR) deviceExtension->DeviceObject->DriverObject);
  590. }
  591. //
  592. // Make sure this host bus adapter has an Dma adapter object.
  593. //
  594. if (deviceExtension->DmaAdapterObject == NULL) {
  595. //
  596. // No DMA adapter, no work.
  597. //
  598. return;
  599. }
  600. ASSERT((Srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) != SRB_FLAGS_UNSPECIFIED_DIRECTION);
  601. deviceExtension->InterruptData.MapTransferParameters.SrbData = srbData;
  602. deviceExtension->InterruptData.MapTransferParameters.LogicalAddress = LogicalAddress;
  603. deviceExtension->InterruptData.MapTransferParameters.Length = Length;
  604. deviceExtension->InterruptData.MapTransferParameters.SrbFlags = Srb->SrbFlags;
  605. deviceExtension->InterruptData.InterruptFlags |= PD_MAP_TRANSFER;
  606. //
  607. // Request a DPC be queued after the interrupt completes.
  608. //
  609. deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;
  610. } // end ScsiPortIoMapTransfer()
  611. VOID
  612. ScsiPortLogError(
  613. IN PVOID HwDeviceExtension,
  614. IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
  615. IN UCHAR PathId,
  616. IN UCHAR TargetId,
  617. IN UCHAR Lun,
  618. IN ULONG ErrorCode,
  619. IN ULONG UniqueId
  620. )
  621. /*++
  622. Routine Description:
  623. This routine saves the error log information, and queues a DPC if necessary.
  624. Arguments:
  625. HwDeviceExtension - Supplies the HBA miniport driver's adapter data storage.
  626. Srb - Supplies an optional pointer to srb if there is one.
  627. TargetId, Lun and PathId - specify device address on a SCSI bus.
  628. ErrorCode - Supplies an error code indicating the type of error.
  629. UniqueId - Supplies a unique identifier for the error.
  630. Return Value:
  631. None.
  632. --*/
  633. {
  634. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  635. PDEVICE_OBJECT DeviceObject = deviceExtension->CommonExtension.DeviceObject;
  636. PSRB_DATA srbData;
  637. PERROR_LOG_ENTRY errorLogEntry;
  638. //
  639. // If the error log entry is already full, then dump the error.
  640. //
  641. if (deviceExtension->InterruptData.InterruptFlags & PD_LOG_ERROR) {
  642. #if SCSIDBG_ENABLED
  643. DebugPrint((1,"ScsiPortLogError: Dumping scsi error log packet.\n"));
  644. DebugPrint((1,
  645. "PathId = %2x, TargetId = %2x, Lun = %2x, ErrorCode = %x, UniqueId = %x.",
  646. PathId,
  647. TargetId,
  648. Lun,
  649. ErrorCode,
  650. UniqueId
  651. ));
  652. #endif
  653. return;
  654. }
  655. //
  656. // Save the error log data in the log entry.
  657. //
  658. errorLogEntry = &deviceExtension->InterruptData.LogEntry;
  659. errorLogEntry->ErrorCode = ErrorCode;
  660. errorLogEntry->TargetId = TargetId;
  661. errorLogEntry->Lun = Lun;
  662. errorLogEntry->PathId = PathId;
  663. errorLogEntry->UniqueId = UniqueId;
  664. //
  665. // Get the sequence number from the SRB data.
  666. //
  667. if (Srb != NULL) {
  668. srbData = Srb->OriginalRequest;
  669. ASSERT_SRB_DATA(srbData);
  670. errorLogEntry->SequenceNumber = srbData->SequenceNumber;
  671. errorLogEntry->ErrorLogRetryCount = srbData->ErrorLogRetryCount++;
  672. } else {
  673. errorLogEntry->SequenceNumber = 0;
  674. errorLogEntry->ErrorLogRetryCount = 0;
  675. }
  676. //
  677. // Indicate that the error log entry is in use.
  678. //
  679. deviceExtension->InterruptData.InterruptFlags |= PD_LOG_ERROR;
  680. //
  681. // Request a DPC be queued after the interrupt completes.
  682. //
  683. deviceExtension->InterruptData.InterruptFlags |= PD_NOTIFICATION_REQUIRED;
  684. return;
  685. } // end ScsiPortLogError()
  686. VOID
  687. ScsiPortCompleteRequest(
  688. IN PVOID HwDeviceExtension,
  689. IN UCHAR PathId,
  690. IN UCHAR TargetId,
  691. IN UCHAR Lun,
  692. IN UCHAR SrbStatus
  693. )
  694. /*++
  695. Routine Description:
  696. Complete all active requests for the specified logical unit.
  697. Arguments:
  698. DeviceExtenson - Supplies the HBA miniport driver's adapter data storage.
  699. TargetId, Lun and PathId - specify device address on a SCSI bus.
  700. SrbStatus - Status to be returned in each completed SRB.
  701. Return Value:
  702. None.
  703. --*/
  704. {
  705. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  706. ULONG binNumber;
  707. for (binNumber = 0; binNumber < NUMBER_LOGICAL_UNIT_BINS; binNumber++) {
  708. PLOGICAL_UNIT_BIN bin = &deviceExtension->LogicalUnitList[binNumber];
  709. PLOGICAL_UNIT_EXTENSION logicalUnit;
  710. ULONG limit = 0;
  711. logicalUnit = bin->List;
  712. DebugPrint((2, "ScsiPortCompleteRequest: Completing requests in "
  713. "bin %d [%#p]\n",
  714. binNumber, bin));
  715. for(logicalUnit = bin->List;
  716. logicalUnit != NULL;
  717. logicalUnit = logicalUnit->NextLogicalUnit) {
  718. PLIST_ENTRY entry;
  719. ASSERT(limit++ < 1000);
  720. //
  721. // See if this logical unit matches the pattern. Check for -1
  722. // first since this seems to be the most popular way to complete
  723. // requests.
  724. //
  725. if (((PathId == SP_UNTAGGED) || (PathId == logicalUnit->PathId)) &&
  726. ((TargetId == SP_UNTAGGED) ||
  727. (TargetId == logicalUnit->TargetId)) &&
  728. ((Lun == SP_UNTAGGED) || (Lun == logicalUnit->Lun))) {
  729. //
  730. // Complete any pending abort reqeusts.
  731. //
  732. if (logicalUnit->AbortSrb != NULL) {
  733. logicalUnit->AbortSrb->SrbStatus = SrbStatus;
  734. ScsiPortNotification(
  735. RequestComplete,
  736. HwDeviceExtension,
  737. logicalUnit->AbortSrb
  738. );
  739. }
  740. if(logicalUnit->CurrentUntaggedRequest != NULL) {
  741. SpCompleteSrb(deviceExtension,
  742. logicalUnit->CurrentUntaggedRequest,
  743. SrbStatus);
  744. }
  745. //
  746. // Complete each of the requests in the queue.
  747. //
  748. entry = logicalUnit->RequestList.Flink;
  749. while (entry != &logicalUnit->RequestList) {
  750. PSRB_DATA srbData;
  751. ASSERT(limit++ < 1000);
  752. srbData = CONTAINING_RECORD(entry, SRB_DATA, RequestList);
  753. SpCompleteSrb(deviceExtension, srbData, SrbStatus);
  754. entry = srbData->RequestList.Flink;
  755. }
  756. }
  757. }
  758. }
  759. return;
  760. } // end ScsiPortCompleteRequest()
  761. VOID
  762. ScsiPortMoveMemory(
  763. IN PVOID WriteBuffer,
  764. IN PVOID ReadBuffer,
  765. IN ULONG Length
  766. )
  767. /*++
  768. Routine Description:
  769. Copy from one buffer into another.
  770. Arguments:
  771. ReadBuffer - source
  772. WriteBuffer - destination
  773. Length - number of bytes to copy
  774. Return Value:
  775. None.
  776. --*/
  777. {
  778. //
  779. // See if the length, source and desitination are word aligned.
  780. //
  781. if (Length & LONG_ALIGN || (ULONG_PTR) WriteBuffer & LONG_ALIGN ||
  782. (ULONG_PTR) ReadBuffer & LONG_ALIGN) {
  783. PCHAR destination = WriteBuffer;
  784. PCHAR source = ReadBuffer;
  785. for (; Length > 0; Length--) {
  786. *destination++ = *source++;
  787. }
  788. } else {
  789. PLONG destination = WriteBuffer;
  790. PLONG source = ReadBuffer;
  791. Length /= sizeof(LONG);
  792. for (; Length > 0; Length--) {
  793. *destination++ = *source++;
  794. }
  795. }
  796. } // end ScsiPortMoveMemory()
  797. #if SCSIDBG_ENABLED
  798. VOID
  799. ScsiDebugPrint(
  800. ULONG DebugPrintLevel,
  801. PCCHAR DebugMessage,
  802. ...
  803. )
  804. /*++
  805. Routine Description:
  806. Debug print for scsi miniports.
  807. Arguments:
  808. Debug print level between 0 and 3, with 3 being the most verbose.
  809. Return Value:
  810. None
  811. Note:
  812. Using the new debug API (systemwide API) DebugPrintEx
  813. renders the variable scsidebug meaningless, since the
  814. level of debug is now controlled int he debug filter
  815. the mask for scsiprot is Kd_ScsiMiniPort_Mask
  816. From the debugger do: ed Kd_ScsiPort_Mask X
  817. where X is the desired value of debug spew.
  818. DPFLTR_ERROR_LEVEL - Are always printed.
  819. DPFLTR_WARNING_LEVEL - 0x01 (bit 1)
  820. DPFLTR_TRACE_LEVEL - 0x02 (bit 2)
  821. DPFLTR_INFO_LEVEL - 0x04 (bit 3)
  822. If you'd like to get WARNING and TRACE, you muyst set bit 1 and 2 (etc)
  823. The Mask is a 32-bit value
  824. I can only see 1 bad thing about changing this function.
  825. Before the _vsnprintf operations would only occurr if we KNEW
  826. that the debug message was going to be printed. Now it
  827. occurs before we deternime wether it will be printed. This changes
  828. the timing of the checked build a bit.
  829. --*/
  830. {
  831. va_list ap;
  832. ULONG DebugLevel;
  833. //
  834. // This code should be removed soon
  835. // Its place here is to remind people debugging scsiport
  836. // that the methods that control debug spew have changed
  837. //
  838. // NOTE - Eventually we should be able to remove this.
  839. //
  840. if (ScsiDebug != 0) {
  841. // This means that someone changed the value of ScsiDebug
  842. // (ie. they want debug spew)
  843. DbgPrintEx(DPFLTR_SCSIMINIPORT_ID, DPFLTR_ERROR_LEVEL,
  844. "Debug messages in SCSI Miniports are no longer controlled by\n"
  845. "scsiport!scsidebug. Please use the correct debug maski\n\n"
  846. "Kd_ScsiPort_Mask -- controls debug msgs from ScsiPort\n"
  847. "Kd_ScsiMiniPort_Mask -- controls debug msgs from SCSI-Miniports\n\n"
  848. "\t0x01 - Error Level\t(bit 0)\n"
  849. "\t0x02 - Warning Level\t(bit 1)\n"
  850. "\t0x04 - Trace Level\t(bit 2)\n"
  851. "\t0x08 - Info Level\t(bit 3)\n\n"
  852. "To get multiple levels, OR the bit-values\n");
  853. DbgBreakPoint();
  854. ScsiDebug = 0;
  855. }
  856. va_start(ap, DebugMessage);
  857. //
  858. // Map the debugprintlevels of scsiport into the new
  859. // debug print API
  860. //
  861. switch (DebugPrintLevel) {
  862. case 0:
  863. DebugLevel = DPFLTR_WARNING_LEVEL;
  864. break;
  865. case 1:
  866. case 2:
  867. DebugLevel = DPFLTR_TRACE_LEVEL;
  868. break;
  869. case 3:
  870. DebugLevel = DPFLTR_INFO_LEVEL;
  871. break;
  872. default:
  873. DebugLevel = DebugPrintLevel;
  874. break;
  875. }
  876. vDbgPrintExWithPrefix("ScsiMiniport: ",
  877. DPFLTR_SCSIMINIPORT_ID,
  878. DebugLevel,
  879. DebugMessage,
  880. ap);
  881. va_end(ap);
  882. } // end ScsiDebugPrint()
  883. VOID
  884. ScsiDebugPrintInt(
  885. ULONG DebugPrintLevel,
  886. PCCHAR DebugMessage,
  887. ...
  888. )
  889. /*++
  890. Routine Description:
  891. Debug print for Internal DebugPrints (SCSIPORT Internal).
  892. Arguments:
  893. Debug print level between 0 and 3, with 3 being the most verbose.
  894. Return Value:
  895. None
  896. Note:
  897. Using the new debug API (systemwide API) DebugPrintEx
  898. renders the variable scsidebug meaningless, since the
  899. level of debug is now controlled int he debug filter
  900. the mask for scsiprot is Kd_ScsiPort_Mask
  901. From the debugger do: ed Kd_ScsiPort_Mask X
  902. where X is the desired value of debug spew.
  903. DPFLTR_ERROR_LEVEL - Are always printed.
  904. DPFLTR_WARNING_LEVEL - 0x01 (bit 1)
  905. DPFLTR_TRACE_LEVEL - 0x02 (bit 2)
  906. DPFLTR_INFO_LEVEL - 0x04 (bit 3)
  907. The Mask is a 32-bit value
  908. I can only see 1 bad thing about changing this function.
  909. Before the _vsnprintf operations would only occurr if we KNEW
  910. that the debug message was going to be printed. Now it
  911. occurs before we deternime wether it will be printed. This changes
  912. the timing of the checked build a bit.
  913. --*/
  914. {
  915. va_list ap;
  916. ULONG DebugLevel;
  917. //
  918. // This code should be removed soon
  919. // Its place here is to remind people debugging scsiport
  920. // that the methods that control debug spew have changed
  921. //
  922. // NOTE - Eventually we should be able to remove this.
  923. //
  924. if (ScsiDebug != 0) {
  925. // This means that someone changed the value of ScsiDebug
  926. // (ie. they want debug spew)
  927. DbgPrintEx(DPFLTR_SCSIPORT_ID, DPFLTR_ERROR_LEVEL,
  928. "Debug messages in SCSI Miniports are no longer controlled by\n"
  929. "scsiport!scsidebug. Please use the correct debug maski\n\n"
  930. "Kd_ScsiPort_Mask -- controls debug msgs from ScsiPort\n"
  931. "Kd_ScsiMiniPort_Mask -- controls debug msgs from SCSI-Miniports\n\n"
  932. "\t0x01 - Error Level\t(bit 0)\n"
  933. "\t0x02 - Warning Level\t(bit 1)\n"
  934. "\t0x04 - Trace Level\t(bit 2)\n"
  935. "\t0x08 - Info Level\t(bit 3)\n\n"
  936. "To get multiple levels, OR the bit-values\n");
  937. DbgBreakPoint();
  938. ScsiDebug = 0;
  939. }
  940. va_start(ap, DebugMessage);
  941. //
  942. // Map the debugprintlevels of scsiport into the new
  943. // debug print API
  944. //
  945. switch (DebugPrintLevel) {
  946. case 0:
  947. DebugLevel = DPFLTR_ERROR_LEVEL;
  948. break;
  949. case 1:
  950. case 2:
  951. DebugLevel = DPFLTR_WARNING_LEVEL;
  952. break;
  953. case 3:
  954. DebugLevel = DPFLTR_TRACE_LEVEL;
  955. break;
  956. default:
  957. DebugLevel = DPFLTR_INFO_LEVEL;
  958. break;
  959. }
  960. vDbgPrintExWithPrefix("ScsiPort: ",
  961. DPFLTR_SCSIPORT_ID,
  962. DebugLevel,
  963. DebugMessage,
  964. ap);
  965. va_end(ap);
  966. } // end ScsiDebugPrint()
  967. #else
  968. //
  969. // ScsiDebugPrint stub
  970. //
  971. VOID
  972. ScsiDebugPrint(
  973. ULONG DebugPrintLevel,
  974. PCCHAR DebugMessage,
  975. ...
  976. )
  977. {
  978. }
  979. VOID
  980. ScsiDebugPrintInt(
  981. ULONG DebugPrintLevel,
  982. PCCHAR DebugMessage,
  983. ...
  984. )
  985. {
  986. }
  987. #endif
  988. //
  989. // The below I/O access routines are forwarded to the HAL or NTOSKRNL on
  990. // Alpha and Intel platforms.
  991. //
  992. #if !defined(_ALPHA_) && !defined(_X86_)
  993. UCHAR
  994. ScsiPortReadPortUchar(
  995. IN PUCHAR Port
  996. )
  997. /*++
  998. Routine Description:
  999. Read from the specified port address.
  1000. Arguments:
  1001. Port - Supplies a pointer to the port address.
  1002. Return Value:
  1003. Returns the value read from the specified port address.
  1004. --*/
  1005. {
  1006. return(READ_PORT_UCHAR(Port));
  1007. }
  1008. USHORT
  1009. ScsiPortReadPortUshort(
  1010. IN PUSHORT Port
  1011. )
  1012. /*++
  1013. Routine Description:
  1014. Read from the specified port address.
  1015. Arguments:
  1016. Port - Supplies a pointer to the port address.
  1017. Return Value:
  1018. Returns the value read from the specified port address.
  1019. --*/
  1020. {
  1021. return(READ_PORT_USHORT(Port));
  1022. }
  1023. ULONG
  1024. ScsiPortReadPortUlong(
  1025. IN PULONG Port
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. Read from the specified port address.
  1030. Arguments:
  1031. Port - Supplies a pointer to the port address.
  1032. Return Value:
  1033. Returns the value read from the specified port address.
  1034. --*/
  1035. {
  1036. return(READ_PORT_ULONG(Port));
  1037. }
  1038. VOID
  1039. ScsiPortReadPortBufferUchar(
  1040. IN PUCHAR Port,
  1041. IN PUCHAR Buffer,
  1042. IN ULONG Count
  1043. )
  1044. /*++
  1045. Routine Description:
  1046. Read a buffer of unsigned bytes from the specified port address.
  1047. Arguments:
  1048. Port - Supplies a pointer to the port address.
  1049. Buffer - Supplies a pointer to the data buffer area.
  1050. Count - The count of items to move.
  1051. Return Value:
  1052. None
  1053. --*/
  1054. {
  1055. READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
  1056. }
  1057. VOID
  1058. ScsiPortReadPortBufferUshort(
  1059. IN PUSHORT Port,
  1060. IN PUSHORT Buffer,
  1061. IN ULONG Count
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. Read a buffer of unsigned shorts from the specified port address.
  1066. Arguments:
  1067. Port - Supplies a pointer to the port address.
  1068. Buffer - Supplies a pointer to the data buffer area.
  1069. Count - The count of items to move.
  1070. Return Value:
  1071. None
  1072. --*/
  1073. {
  1074. READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
  1075. }
  1076. VOID
  1077. ScsiPortReadPortBufferUlong(
  1078. IN PULONG Port,
  1079. IN PULONG Buffer,
  1080. IN ULONG Count
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. Read a buffer of unsigned longs from the specified port address.
  1085. Arguments:
  1086. Port - Supplies a pointer to the port address.
  1087. Buffer - Supplies a pointer to the data buffer area.
  1088. Count - The count of items to move.
  1089. Return Value:
  1090. None
  1091. --*/
  1092. {
  1093. READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
  1094. }
  1095. UCHAR
  1096. ScsiPortReadRegisterUchar(
  1097. IN PUCHAR Register
  1098. )
  1099. /*++
  1100. Routine Description:
  1101. Read from the specificed register address.
  1102. Arguments:
  1103. Register - Supplies a pointer to the register address.
  1104. Return Value:
  1105. Returns the value read from the specified register address.
  1106. --*/
  1107. {
  1108. return(READ_REGISTER_UCHAR(Register));
  1109. }
  1110. USHORT
  1111. ScsiPortReadRegisterUshort(
  1112. IN PUSHORT Register
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. Read from the specified register address.
  1117. Arguments:
  1118. Register - Supplies a pointer to the register address.
  1119. Return Value:
  1120. Returns the value read from the specified register address.
  1121. --*/
  1122. {
  1123. return(READ_REGISTER_USHORT(Register));
  1124. }
  1125. ULONG
  1126. ScsiPortReadRegisterUlong(
  1127. IN PULONG Register
  1128. )
  1129. /*++
  1130. Routine Description:
  1131. Read from the specified register address.
  1132. Arguments:
  1133. Register - Supplies a pointer to the register address.
  1134. Return Value:
  1135. Returns the value read from the specified register address.
  1136. --*/
  1137. {
  1138. return(READ_REGISTER_ULONG(Register));
  1139. }
  1140. VOID
  1141. ScsiPortReadRegisterBufferUchar(
  1142. IN PUCHAR Register,
  1143. IN PUCHAR Buffer,
  1144. IN ULONG Count
  1145. )
  1146. /*++
  1147. Routine Description:
  1148. Read a buffer of unsigned bytes from the specified register address.
  1149. Arguments:
  1150. Register - Supplies a pointer to the port address.
  1151. Buffer - Supplies a pointer to the data buffer area.
  1152. Count - The count of items to move.
  1153. Return Value:
  1154. None
  1155. --*/
  1156. {
  1157. READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
  1158. }
  1159. VOID
  1160. ScsiPortReadRegisterBufferUshort(
  1161. IN PUSHORT Register,
  1162. IN PUSHORT Buffer,
  1163. IN ULONG Count
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Read a buffer of unsigned shorts from the specified register address.
  1168. Arguments:
  1169. Register - Supplies a pointer to the port address.
  1170. Buffer - Supplies a pointer to the data buffer area.
  1171. Count - The count of items to move.
  1172. Return Value:
  1173. None
  1174. --*/
  1175. {
  1176. READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
  1177. }
  1178. VOID
  1179. ScsiPortReadRegisterBufferUlong(
  1180. IN PULONG Register,
  1181. IN PULONG Buffer,
  1182. IN ULONG Count
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. Read a buffer of unsigned longs from the specified register address.
  1187. Arguments:
  1188. Register - Supplies a pointer to the port address.
  1189. Buffer - Supplies a pointer to the data buffer area.
  1190. Count - The count of items to move.
  1191. Return Value:
  1192. None
  1193. --*/
  1194. {
  1195. READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
  1196. }
  1197. VOID
  1198. ScsiPortWritePortUchar(
  1199. IN PUCHAR Port,
  1200. IN UCHAR Value
  1201. )
  1202. /*++
  1203. Routine Description:
  1204. Write to the specificed port address.
  1205. Arguments:
  1206. Port - Supplies a pointer to the port address.
  1207. Value - Supplies the value to be written.
  1208. Return Value:
  1209. None
  1210. --*/
  1211. {
  1212. WRITE_PORT_UCHAR(Port, Value);
  1213. }
  1214. VOID
  1215. ScsiPortWritePortUshort(
  1216. IN PUSHORT Port,
  1217. IN USHORT Value
  1218. )
  1219. /*++
  1220. Routine Description:
  1221. Write to the specificed port address.
  1222. Arguments:
  1223. Port - Supplies a pointer to the port address.
  1224. Value - Supplies the value to be written.
  1225. Return Value:
  1226. None
  1227. --*/
  1228. {
  1229. WRITE_PORT_USHORT(Port, Value);
  1230. }
  1231. VOID
  1232. ScsiPortWritePortUlong(
  1233. IN PULONG Port,
  1234. IN ULONG Value
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. Write to the specificed port address.
  1239. Arguments:
  1240. Port - Supplies a pointer to the port address.
  1241. Value - Supplies the value to be written.
  1242. Return Value:
  1243. None
  1244. --*/
  1245. {
  1246. WRITE_PORT_ULONG(Port, Value);
  1247. }
  1248. VOID
  1249. ScsiPortWritePortBufferUchar(
  1250. IN PUCHAR Port,
  1251. IN PUCHAR Buffer,
  1252. IN ULONG Count
  1253. )
  1254. /*++
  1255. Routine Description:
  1256. Write a buffer of unsigned bytes from the specified port address.
  1257. Arguments:
  1258. Port - Supplies a pointer to the port address.
  1259. Buffer - Supplies a pointer to the data buffer area.
  1260. Count - The count of items to move.
  1261. Return Value:
  1262. None
  1263. --*/
  1264. {
  1265. WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
  1266. }
  1267. VOID
  1268. ScsiPortWritePortBufferUshort(
  1269. IN PUSHORT Port,
  1270. IN PUSHORT Buffer,
  1271. IN ULONG Count
  1272. )
  1273. /*++
  1274. Routine Description:
  1275. Write a buffer of unsigned shorts from the specified port address.
  1276. Arguments:
  1277. Port - Supplies a pointer to the port address.
  1278. Buffer - Supplies a pointer to the data buffer area.
  1279. Count - The count of items to move.
  1280. Return Value:
  1281. None
  1282. --*/
  1283. {
  1284. WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
  1285. }
  1286. VOID
  1287. ScsiPortWritePortBufferUlong(
  1288. IN PULONG Port,
  1289. IN PULONG Buffer,
  1290. IN ULONG Count
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. Write a buffer of unsigned longs from the specified port address.
  1295. Arguments:
  1296. Port - Supplies a pointer to the port address.
  1297. Buffer - Supplies a pointer to the data buffer area.
  1298. Count - The count of items to move.
  1299. Return Value:
  1300. None
  1301. --*/
  1302. {
  1303. WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
  1304. }
  1305. VOID
  1306. ScsiPortWriteRegisterUchar(
  1307. IN PUCHAR Register,
  1308. IN UCHAR Value
  1309. )
  1310. /*++
  1311. Routine Description:
  1312. Write to the specificed register address.
  1313. Arguments:
  1314. Register - Supplies a pointer to the register address.
  1315. Value - Supplies the value to be written.
  1316. Return Value:
  1317. None
  1318. --*/
  1319. {
  1320. WRITE_REGISTER_UCHAR(Register, Value);
  1321. }
  1322. VOID
  1323. ScsiPortWriteRegisterUshort(
  1324. IN PUSHORT Register,
  1325. IN USHORT Value
  1326. )
  1327. /*++
  1328. Routine Description:
  1329. Write to the specificed register address.
  1330. Arguments:
  1331. Register - Supplies a pointer to the register address.
  1332. Value - Supplies the value to be written.
  1333. Return Value:
  1334. None
  1335. --*/
  1336. {
  1337. WRITE_REGISTER_USHORT(Register, Value);
  1338. }
  1339. VOID
  1340. ScsiPortWriteRegisterBufferUchar(
  1341. IN PUCHAR Register,
  1342. IN PUCHAR Buffer,
  1343. IN ULONG Count
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. Write a buffer of unsigned bytes from the specified register address.
  1348. Arguments:
  1349. Register - Supplies a pointer to the port address.
  1350. Buffer - Supplies a pointer to the data buffer area.
  1351. Count - The count of items to move.
  1352. Return Value:
  1353. None
  1354. --*/
  1355. {
  1356. WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
  1357. }
  1358. VOID
  1359. ScsiPortWriteRegisterBufferUshort(
  1360. IN PUSHORT Register,
  1361. IN PUSHORT Buffer,
  1362. IN ULONG Count
  1363. )
  1364. /*++
  1365. Routine Description:
  1366. Write a buffer of unsigned shorts from the specified register address.
  1367. Arguments:
  1368. Register - Supplies a pointer to the port address.
  1369. Buffer - Supplies a pointer to the data buffer area.
  1370. Count - The count of items to move.
  1371. Return Value:
  1372. None
  1373. --*/
  1374. {
  1375. WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
  1376. }
  1377. VOID
  1378. ScsiPortWriteRegisterBufferUlong(
  1379. IN PULONG Register,
  1380. IN PULONG Buffer,
  1381. IN ULONG Count
  1382. )
  1383. /*++
  1384. Routine Description:
  1385. Write a buffer of unsigned longs from the specified register address.
  1386. Arguments:
  1387. Register - Supplies a pointer to the port address.
  1388. Buffer - Supplies a pointer to the data buffer area.
  1389. Count - The count of items to move.
  1390. Return Value:
  1391. None
  1392. --*/
  1393. {
  1394. WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
  1395. }
  1396. VOID
  1397. ScsiPortWriteRegisterUlong(
  1398. IN PULONG Register,
  1399. IN ULONG Value
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. Write to the specificed register address.
  1404. Arguments:
  1405. Register - Supplies a pointer to the register address.
  1406. Value - Supplies the value to be written.
  1407. Return Value:
  1408. None
  1409. --*/
  1410. {
  1411. WRITE_REGISTER_ULONG(Register, Value);
  1412. }
  1413. #endif // !defined(_ALPHA_) && !defined(_X86_)
  1414. PSCSI_REQUEST_BLOCK
  1415. ScsiPortGetSrb(
  1416. IN PVOID HwDeviceExtension,
  1417. IN UCHAR PathId,
  1418. IN UCHAR TargetId,
  1419. IN UCHAR Lun,
  1420. IN LONG QueueTag
  1421. )
  1422. /*++
  1423. Routine Description:
  1424. This routine retrieves an active SRB for a particuliar logical unit.
  1425. Arguments:
  1426. HwDeviceExtension
  1427. PathId, TargetId, Lun - identify logical unit on SCSI bus.
  1428. QueueTag - -1 indicates request is not tagged.
  1429. Return Value:
  1430. SRB, if one exists. Otherwise, NULL.
  1431. --*/
  1432. {
  1433. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  1434. PSRB_DATA srbData;
  1435. PSCSI_REQUEST_BLOCK srb;
  1436. UCHAR pathId;
  1437. UCHAR targetId;
  1438. UCHAR lun;
  1439. srbData = SpGetSrbData(deviceExtension,
  1440. PathId,
  1441. TargetId,
  1442. Lun,
  1443. (UCHAR)QueueTag,
  1444. FALSE);
  1445. if (srbData == NULL || srbData->CurrentSrb == NULL) {
  1446. return(NULL);
  1447. }
  1448. srb = srbData->CurrentSrb;
  1449. //
  1450. // If the srb is not active then return NULL;
  1451. //
  1452. if (!(srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) {
  1453. return(NULL);
  1454. }
  1455. return (srb);
  1456. } // end ScsiPortGetSrb()
  1457. SCSI_PHYSICAL_ADDRESS
  1458. ScsiPortGetPhysicalAddress(
  1459. IN PVOID HwDeviceExtension,
  1460. IN PSCSI_REQUEST_BLOCK Srb,
  1461. IN PVOID VirtualAddress,
  1462. OUT ULONG *Length
  1463. )
  1464. /*++
  1465. Routine Description:
  1466. Convert virtual address to physical address for DMA.
  1467. Arguments:
  1468. Return Value:
  1469. --*/
  1470. {
  1471. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  1472. ULONG byteOffset;
  1473. PHYSICAL_ADDRESS address;
  1474. ULONG length;
  1475. if (Srb == NULL || Srb->SenseInfoBuffer == VirtualAddress) {
  1476. byteOffset = (ULONG)((PCCHAR) VirtualAddress - (PCCHAR)
  1477. deviceExtension->SrbExtensionBuffer);
  1478. ASSERT(byteOffset < deviceExtension->CommonBufferSize);
  1479. length = deviceExtension->CommonBufferSize - byteOffset;
  1480. address.QuadPart = deviceExtension->PhysicalCommonBuffer.QuadPart + byteOffset;
  1481. } else if (deviceExtension->MasterWithAdapter) {
  1482. PSRB_SCATTER_GATHER scatterList;
  1483. PSRB_DATA srbData;
  1484. //
  1485. // A scatter/gather list has already been allocated use it to determine
  1486. // the physical address and length. Get the scatter/gather list.
  1487. //
  1488. srbData = Srb->OriginalRequest;
  1489. ASSERT_SRB_DATA(srbData);
  1490. scatterList = srbData->ScatterGatherList;
  1491. //
  1492. // Calculate byte offset into the data buffer.
  1493. //
  1494. byteOffset = (ULONG)((PCHAR) VirtualAddress - (PCHAR) Srb->DataBuffer);
  1495. //
  1496. // Find the appropriate entry in the scatter/gatter list.
  1497. //
  1498. while (byteOffset >= scatterList->Length) {
  1499. byteOffset -= scatterList->Length;
  1500. scatterList++;
  1501. }
  1502. //
  1503. // Calculate the physical address and length to be returned.
  1504. //
  1505. length = scatterList->Length - byteOffset;
  1506. address.QuadPart = scatterList->Address.QuadPart + byteOffset;
  1507. } else {
  1508. length = 0;
  1509. address.QuadPart = (LONGLONG)(SP_UNINITIALIZED_VALUE);
  1510. }
  1511. *Length = length;
  1512. return address;
  1513. } // end ScsiPortGetPhysicalAddress()
  1514. PVOID
  1515. ScsiPortGetVirtualAddress(
  1516. IN PVOID HwDeviceExtension,
  1517. IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
  1518. )
  1519. /*++
  1520. Routine Description:
  1521. This routine is returns a virtual address associated with a
  1522. physical address, if the physical address was obtained by a
  1523. call to ScsiPortGetPhysicalAddress.
  1524. Arguments:
  1525. PhysicalAddress
  1526. Return Value:
  1527. Virtual address
  1528. --*/
  1529. {
  1530. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  1531. PVOID address;
  1532. ULONG smallphysicalBase;
  1533. ULONG smallAddress;
  1534. smallAddress = ScsiPortConvertPhysicalAddressToUlong(PhysicalAddress);
  1535. smallphysicalBase = ScsiPortConvertPhysicalAddressToUlong(deviceExtension->PhysicalCommonBuffer);
  1536. //
  1537. // Check that the physical address is within the proper range.
  1538. //
  1539. if (smallAddress < smallphysicalBase ||
  1540. smallAddress >= smallphysicalBase + deviceExtension->CommonBufferSize) {
  1541. //
  1542. // This is a bugous physical address return back NULL.
  1543. //
  1544. return(NULL);
  1545. }
  1546. address = smallAddress - smallphysicalBase +
  1547. (PUCHAR) deviceExtension->SrbExtensionBuffer;
  1548. return address;
  1549. } // end ScsiPortGetVirtualAddress()
  1550. BOOLEAN
  1551. ScsiPortValidateRange(
  1552. IN PVOID HwDeviceExtension,
  1553. IN INTERFACE_TYPE BusType,
  1554. IN ULONG SystemIoBusNumber,
  1555. IN SCSI_PHYSICAL_ADDRESS IoAddress,
  1556. IN ULONG NumberOfBytes,
  1557. IN BOOLEAN InIoSpace
  1558. )
  1559. /*++
  1560. Routine Description:
  1561. This routine should take an IO range and make sure that it is not already
  1562. in use by another adapter. This allows miniport drivers to probe IO where
  1563. an adapter could be, without worrying about messing up another card.
  1564. Arguments:
  1565. HwDeviceExtension - Used to find scsi managers internal structures
  1566. BusType - EISA, PCI, PC/MCIA, MCA, ISA, what?
  1567. SystemIoBusNumber - Which system bus?
  1568. IoAddress - Start of range
  1569. NumberOfBytes - Length of range
  1570. InIoSpace - Is range in IO space?
  1571. Return Value:
  1572. TRUE if range not claimed by another driver.
  1573. --*/
  1574. {
  1575. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  1576. //
  1577. // This is not implemented in NT.
  1578. //
  1579. return TRUE;
  1580. }
  1581. SCSI_PHYSICAL_ADDRESS
  1582. ScsiPortConvertUlongToPhysicalAddress(
  1583. ULONG_PTR UlongAddress
  1584. )
  1585. {
  1586. SCSI_PHYSICAL_ADDRESS physicalAddress;
  1587. physicalAddress.QuadPart = UlongAddress;
  1588. return(physicalAddress);
  1589. }
  1590. //
  1591. // Leave these routines at the end of the file.
  1592. //
  1593. #undef ScsiPortConvertPhysicalAddressToUlong
  1594. ULONG
  1595. ScsiPortConvertPhysicalAddressToUlong(
  1596. SCSI_PHYSICAL_ADDRESS Address
  1597. )
  1598. /*++
  1599. Routine Description:
  1600. This routine converts a 64-bit physical address to a ULONG
  1601. Arguments:
  1602. Address - Supplies a 64-bit address to be converted.
  1603. Return Value:
  1604. Returns a 32-bit address.
  1605. --*/
  1606. {
  1607. return(Address.LowPart);
  1608. }
  1609. VOID
  1610. ScsiPortStallExecution(
  1611. ULONG Delay
  1612. )
  1613. /*++
  1614. Routine Description:
  1615. This routine stalls the process for the specified number of microseconds.
  1616. Arguments:
  1617. Delay - the number of microseconds to stall.
  1618. Return Value:
  1619. --*/
  1620. {
  1621. KeStallExecutionProcessor(Delay);
  1622. }
  1623. #if defined(_AMD64_)
  1624. VOID
  1625. ScsiPortQuerySystemTime (
  1626. OUT PLARGE_INTEGER CurrentTime
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This function returns the current system time.
  1631. Arguments:
  1632. CurrentTime - Supplies a pointer to a variable that will receive the
  1633. current system time.
  1634. Return Value:
  1635. None.
  1636. --*/
  1637. {
  1638. KeQuerySystemTime(CurrentTime);
  1639. return;
  1640. }
  1641. #endif