Windows NT 4.0 source code leak
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.

2150 lines
45 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. spock.c
  5. Abstract:
  6. This is the NT SCSI miniport driver for the IBM MCA SCSI adapter.
  7. Author:
  8. Mike Glass
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "miniport.h"
  15. #include "mca.h"
  16. #include "scsi.h"
  17. #define MAXIMUM_ERRORS 10
  18. //
  19. // The following table specifies the ports to be checked when searching for
  20. // an adapter. A zero entry terminates the search.
  21. //
  22. CONST ULONG AdapterAddresses[] = {0X3540, 0X3548, 0X3550, 0X3558,
  23. 0X3560, 0X3568, 0x3570, 0x3578, 0};
  24. //
  25. // Device extension
  26. //
  27. typedef struct _HW_DEVICE_EXTENSION {
  28. //
  29. // Adapter parameters
  30. //
  31. PMCA_REGISTERS Registers;
  32. //
  33. // Disk activity light count
  34. //
  35. ULONG ActiveRequests;
  36. ULONG ErrorCount;
  37. UCHAR HostTargetId;
  38. } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
  39. //
  40. // Logical unit extension
  41. //
  42. typedef struct _HW_LOGICAL_UNIT {
  43. PSCB Scb;
  44. PSCSI_REQUEST_BLOCK AbortSrb;
  45. PSCSI_REQUEST_BLOCK CurrentSrb;
  46. } HW_LOGICAL_UNIT, *PHW_LOGICAL_UNIT;
  47. //
  48. // Noncached version extension.
  49. //
  50. typedef struct _HW_ADAPTER_INFOMATION {
  51. SCB Scb;
  52. ADAPTER_INFORMATION AdapterInfo;
  53. }HW_ADAPTER_INFOMATION, *PHW_ADAPTER_INFOMATION;
  54. //
  55. // Function declarations
  56. //
  57. ULONG
  58. DriverEntry (
  59. IN PVOID DriverObject,
  60. IN PVOID Argument2
  61. );
  62. ULONG
  63. SpockConfiguration(
  64. IN PVOID HwDeviceExtension,
  65. IN PVOID Context,
  66. IN PVOID BusInformation,
  67. IN PCHAR ArgumentString,
  68. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  69. OUT PBOOLEAN Again
  70. );
  71. BOOLEAN
  72. SpockInitialize(
  73. IN PVOID HwDeviceExtension
  74. );
  75. BOOLEAN
  76. SpockStartIo(
  77. IN PVOID HwDeviceExtension,
  78. IN PSCSI_REQUEST_BLOCK Srb
  79. );
  80. BOOLEAN
  81. SpockInterrupt(
  82. IN PVOID HwDeviceExtension
  83. );
  84. BOOLEAN
  85. SpockResetBus(
  86. IN PVOID HwDeviceExtension,
  87. IN ULONG PathId
  88. );
  89. BOOLEAN
  90. SpockAbortIo(
  91. IN PVOID HwDeviceExtension,
  92. IN PSCSI_REQUEST_BLOCK Srb
  93. );
  94. VOID
  95. BuildScb(
  96. IN PHW_DEVICE_EXTENSION HwDeviceExtension,
  97. IN PSCSI_REQUEST_BLOCK Srb
  98. );
  99. VOID
  100. BuildSgl(
  101. IN PVOID DeviceExtension,
  102. IN PSCSI_REQUEST_BLOCK Srb
  103. );
  104. VOID
  105. BuildReadCapacity(
  106. IN PHW_DEVICE_EXTENSION DeviceExtension,
  107. IN PSCSI_REQUEST_BLOCK Srb
  108. );
  109. ULONG
  110. McaAdapterPresent(
  111. IN PHW_DEVICE_EXTENSION HwDeviceExtension,
  112. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  113. IN OUT PULONG AdapterCount,
  114. OUT PBOOLEAN Again
  115. );
  116. VOID
  117. MapTsbError(
  118. IN PHW_DEVICE_EXTENSION DeviceExtension,
  119. IN PSCSI_REQUEST_BLOCK Srb,
  120. IN PTSB Tsb
  121. );
  122. BOOLEAN
  123. IssueScbCommand(
  124. IN PVOID DeviceExtension,
  125. IN ULONG PhysicalScb,
  126. IN UCHAR TargetId
  127. );
  128. BOOLEAN
  129. IssueImmediateCommand(
  130. IN PVOID HwDeviceExtension,
  131. IN ULONG ImmediateCommand,
  132. IN UCHAR TargetId
  133. );
  134. //
  135. // Routines start
  136. //
  137. ULONG
  138. DriverEntry (
  139. IN PVOID DriverObject,
  140. IN PVOID Argument2
  141. )
  142. /*++
  143. Routine Description:
  144. Installable driver initialization entry point for system.
  145. Arguments:
  146. Driver Object is passed to ScsiPortInitialize()
  147. Return Value:
  148. Status from ScsiPortInitialize()
  149. --*/
  150. {
  151. HW_INITIALIZATION_DATA hwInitializationData;
  152. ULONG adapterCount;
  153. ULONG i;
  154. DebugPrint((1,"\n\nMCA SCSI Driver\n"));
  155. //
  156. // Zero out structure.
  157. //
  158. for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
  159. ((PUCHAR)&hwInitializationData)[i] = 0;
  160. }
  161. //
  162. // Set size of hwInitializationData.
  163. //
  164. hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
  165. //
  166. // Set entry points.
  167. //
  168. hwInitializationData.HwInitialize = SpockInitialize;
  169. hwInitializationData.HwFindAdapter = SpockConfiguration;
  170. hwInitializationData.HwStartIo = SpockStartIo;
  171. hwInitializationData.HwInterrupt = SpockInterrupt;
  172. hwInitializationData.HwResetBus = SpockResetBus;
  173. hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
  174. hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LOGICAL_UNIT);
  175. //
  176. // Set number of access ranges and bus type..
  177. //
  178. hwInitializationData.NumberOfAccessRanges = 1;
  179. hwInitializationData.AdapterInterfaceType = MicroChannel;
  180. //
  181. // Indicate no buffer mapping but will need physical addresses.
  182. //
  183. hwInitializationData.NeedPhysicalAddresses = TRUE;
  184. //
  185. // Ask for SRB extensions for SCBs.
  186. //
  187. hwInitializationData.SrbExtensionSize = sizeof(SCB);
  188. //
  189. // The adapter count is used by McaAdapterPresent routine to track
  190. // which adapter addresses have been searched.
  191. //
  192. adapterCount = 0;
  193. return ScsiPortInitialize(DriverObject,
  194. Argument2,
  195. &hwInitializationData,
  196. &adapterCount);
  197. } // end DriverEntry()
  198. ULONG
  199. SpockConfiguration(
  200. IN PVOID HwDeviceExtension,
  201. IN PVOID Context,
  202. IN PVOID BusInformation,
  203. IN PCHAR ArgumentString,
  204. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  205. OUT PBOOLEAN Again
  206. )
  207. /*++
  208. Routine Description:
  209. Called from ScsiPortInitialize to collect adapter configuration
  210. and capability information.
  211. Arguments:
  212. HwDevice Extension
  213. Context - Pointer to adapters initialized count
  214. BusInformation
  215. ArgumentString - Not used
  216. ConfigInfo - Configuration information structure describing HBA
  217. Again - Indicates init routine should be called again
  218. Return Value:
  219. ULONG
  220. --*/
  221. {
  222. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  223. PHW_ADAPTER_INFOMATION adapterInfo;
  224. ULONG physicalAdapterInfo;
  225. ULONG status;
  226. UCHAR basicStatus;
  227. //
  228. // Assume initialization will not need to be called again.
  229. //
  230. *Again = FALSE;
  231. //
  232. // Search for IBM SCSI adapters.
  233. //
  234. status = McaAdapterPresent(HwDeviceExtension,
  235. ConfigInfo,
  236. Context,
  237. Again);
  238. //
  239. // If there are not adapter's found then return.
  240. //
  241. if (status != SP_RETURN_FOUND) {
  242. return(status);
  243. }
  244. //
  245. // Set IRQ to 14.
  246. //
  247. ConfigInfo->BusInterruptLevel = 14;
  248. ConfigInfo->NumberOfBuses = 1;
  249. ConfigInfo->InterruptMode = LevelSensitive;
  250. ConfigInfo->InitiatorBusId[0] = 7;
  251. deviceExtension->HostTargetId = 7;
  252. ConfigInfo->Master = TRUE;
  253. ConfigInfo->ScatterGather = TRUE;
  254. //
  255. // Indicate maximum transfer length is 16M.
  256. //
  257. ConfigInfo->MaximumTransferLength = MAXIMUM_DATA_TRANSFER;
  258. //
  259. // Maximum number of physical segments is 16.
  260. //
  261. ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SDL_SIZE;
  262. //
  263. // Get an noncached extension for the adapter information.
  264. //
  265. adapterInfo = ScsiPortGetUncachedExtension(HwDeviceExtension,
  266. ConfigInfo,
  267. sizeof(HW_ADAPTER_INFOMATION));
  268. if (adapterInfo == NULL) {
  269. return SP_RETURN_BAD_CONFIG;
  270. }
  271. physicalAdapterInfo = ScsiPortConvertPhysicalAddressToUlong(
  272. ScsiPortGetPhysicalAddress(
  273. HwDeviceExtension,
  274. NULL,
  275. adapterInfo,
  276. &status));
  277. if (status == 0 || physicalAdapterInfo == SP_UNINITIALIZED_VALUE) {
  278. return SP_RETURN_BAD_CONFIG;
  279. }
  280. //
  281. // Disable the adapter interrupt. The interrupts will be enabled
  282. // when the adapter is initialized.
  283. //
  284. basicStatus = ScsiPortReadPortUchar(
  285. &deviceExtension->Registers->BaseControl);
  286. basicStatus &= ~INTERRUPT_ENABLE;
  287. ScsiPortWritePortUchar(&deviceExtension->Registers->BaseControl, basicStatus);
  288. //
  289. // Build a get POS and adapter information command.
  290. //
  291. adapterInfo->Scb.Command = SCB_COMMAND_GET_POS;
  292. adapterInfo->Scb.EnableFlags = SCB_ENABLE_READ | SCB_ENABLE_TSB_ON_ERROR |
  293. SCB_ENABLE_RETRY_ENABLE | SCB_ENABLE_BYPASS_BUFFER;
  294. adapterInfo->Scb.CdbSize = 0;
  295. adapterInfo->Scb.Reserved = 0;
  296. adapterInfo->Scb.BufferAddress = physicalAdapterInfo +
  297. offsetof(HW_ADAPTER_INFOMATION, AdapterInfo);
  298. adapterInfo->Scb.BufferLength = sizeof(adapterInfo->AdapterInfo);
  299. adapterInfo->Scb.StatusBlock = physicalAdapterInfo +
  300. offsetof(HW_ADAPTER_INFOMATION, Scb.Tsb);
  301. adapterInfo->Scb.NextScb = NULL;
  302. if (!IssueScbCommand(HwDeviceExtension, physicalAdapterInfo, 0x0f)) {
  303. DebugPrint((1, "SpockConfiguration: Could not issue get POS command.\n"));
  304. //
  305. // Assume this is a bad adapter. Force no disconnects for all
  306. // requests.
  307. //
  308. deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
  309. return SP_RETURN_FOUND;
  310. }
  311. //
  312. // Wait for the request to complete.
  313. //
  314. for (status = 0; status < 1000; status++) {
  315. basicStatus = ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus);
  316. if (basicStatus & BASIC_STATUS_INTERRUPT) {
  317. break;
  318. }
  319. ScsiPortStallExecution(10);
  320. }
  321. if (!(--deviceExtension->ActiveRequests)) {
  322. //
  323. // Turn disk activity light off.
  324. //
  325. DISK_ACTIVITY_LIGHT_OFF();
  326. }
  327. if (!(basicStatus & BASIC_STATUS_INTERRUPT)) {
  328. DebugPrint((1, "SpockConfiguration: Get POS command timed out.\n"));
  329. //
  330. // Assume this is a bad adapter. Force no disconnects for all
  331. // requests.
  332. //
  333. deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
  334. return SP_RETURN_FOUND;
  335. }
  336. //
  337. // Read interrupt status register to determine
  338. // interrupting device and status.
  339. //
  340. basicStatus = ScsiPortReadPortUchar(
  341. &deviceExtension->Registers->InterruptStatus);
  342. //
  343. // Acknowledge interrupt.
  344. //
  345. status = 0;
  346. while (ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) &
  347. BASIC_STATUS_BUSY){
  348. ScsiPortStallExecution(1);
  349. if (status++ > 10000) {
  350. DebugPrint((1, "SpockConfiguration: Wait for non-busy timed out.\n"));
  351. //
  352. // Assume this is a bad adapter. Force no disconnects for all
  353. // requests.
  354. //
  355. deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
  356. return SP_RETURN_FOUND;
  357. }
  358. }
  359. ScsiPortWritePortUchar(&deviceExtension->Registers->Attention,
  360. (0x0f | END_OF_INTERRUPT));
  361. //
  362. // Bits 4-7 are interrupt status id.
  363. //
  364. status = basicStatus >> 4;
  365. if (status != SCB_STATUS_SUCCESS &&
  366. status != SCB_STATUS_SUCCESS_WITH_RETRIES) {
  367. DebugPrint((1, "SpockConfiguration: Get POS command failed. Status = %hx\n", status));
  368. //
  369. // Assume this is a bad adapter. Force no disconnects for all
  370. // requests.
  371. //
  372. deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
  373. return SP_RETURN_FOUND;
  374. }
  375. DebugPrint((1, "SpockConfiguration: Retrived data is: %0.4hx\n",adapterInfo->AdapterInfo.RevisionLevel));
  376. if (adapterInfo->AdapterInfo.RevisionLevel == 0xf) {
  377. DebugPrint((1, "SpockConfiguration: Found old firmware disabling disconnect!\n"));
  378. deviceExtension->ErrorCount = MAXIMUM_ERRORS + 1;
  379. //
  380. // Log nasty firmware.
  381. //
  382. ScsiPortLogError(
  383. HwDeviceExtension,
  384. NULL,
  385. 0,
  386. deviceExtension->HostTargetId,
  387. 0,
  388. SP_BAD_FW_WARNING,
  389. (10 << 16));
  390. }
  391. return SP_RETURN_FOUND;
  392. } // end SpockConfiguration()
  393. BOOLEAN
  394. SpockInitialize(
  395. IN PVOID HwDeviceExtension
  396. )
  397. /*++
  398. Routine Description:
  399. Reset and inititialize Adapter.
  400. Arguments:
  401. DeviceExtension - Adapter object device extension.
  402. Return Value:
  403. TRUE
  404. --*/
  405. {
  406. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  407. UCHAR basicStatus;
  408. //
  409. // Issue feature control immediate command to disable
  410. // adapter timing of SCBs.
  411. //
  412. if (!IssueImmediateCommand(HwDeviceExtension,
  413. (ULONG)SCB_COMMAND_FEATURE_CONTROL,
  414. 0x0f)) {
  415. DebugPrint((1,"SpockInitialize: Set feature control failed\n"));
  416. }
  417. //
  418. // Enable the adapter interrupt.
  419. //
  420. basicStatus = ScsiPortReadPortUchar(&deviceExtension->Registers->BaseControl);
  421. basicStatus |= INTERRUPT_ENABLE;
  422. ScsiPortWritePortUchar(&deviceExtension->Registers->BaseControl, basicStatus);
  423. return TRUE;
  424. } // end SpockInitialize()
  425. BOOLEAN
  426. SpockStartIo(
  427. IN PVOID HwDeviceExtension,
  428. IN PSCSI_REQUEST_BLOCK Srb
  429. )
  430. /*++
  431. Routine Description:
  432. Issue call to build SCB and SDL and write address and
  433. command to adapter.
  434. Arguments:
  435. HwDeviceExtension
  436. Srb
  437. Return Value:
  438. TRUE.
  439. --*/
  440. {
  441. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  442. PSCB scb;
  443. ULONG physicalScb;
  444. ULONG length;
  445. PHW_LOGICAL_UNIT logicalUnit;
  446. //
  447. // Make sure that the request is for a valid SCSI bus and LUN as
  448. // the IBM SCSI card does random things if address is wrong.
  449. //
  450. if (Srb->PathId != 0 || Srb->Lun != 0) {
  451. //
  452. // The spock card only supports logical unit zero and one bus.
  453. //
  454. Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
  455. ScsiPortNotification(RequestComplete,
  456. deviceExtension,
  457. Srb);
  458. //
  459. // Adapter ready for next request.
  460. //
  461. ScsiPortNotification(NextRequest,
  462. deviceExtension,
  463. NULL);
  464. return TRUE;
  465. }
  466. //
  467. // Get logical unit extension.
  468. //
  469. logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
  470. Srb->PathId,
  471. Srb->TargetId,
  472. Srb->Lun);
  473. switch (Srb->Function) {
  474. case SRB_FUNCTION_EXECUTE_SCSI:
  475. //
  476. // Save SRB in logical unit extension.
  477. //
  478. ASSERT(!logicalUnit->CurrentSrb);
  479. logicalUnit->CurrentSrb = Srb;
  480. scb = Srb->SrbExtension;
  481. //
  482. // Save SRB back pointer in SCB.
  483. //
  484. scb->SrbAddress = Srb;
  485. //
  486. // Get SCB physical address.
  487. //
  488. physicalScb =
  489. ScsiPortConvertPhysicalAddressToUlong(
  490. ScsiPortGetPhysicalAddress(deviceExtension, NULL, scb, &length));
  491. //
  492. // Assume physical address is contiguous for size of SCB.
  493. //
  494. ASSERT(length >= sizeof(SCB));
  495. //
  496. // Save Scb in logical unit extension.
  497. //
  498. logicalUnit->Scb = scb;
  499. //
  500. // Build SCB.
  501. //
  502. BuildScb(deviceExtension, Srb);
  503. //
  504. // Issue send SCB command to adapter.
  505. //
  506. DebugPrint((2, "BuildSCB: Function %0.4hx LDN %0.4hx \n",
  507. Srb->Cdb[0], Srb->TargetId));
  508. if (!IssueScbCommand(deviceExtension,
  509. physicalScb,
  510. Srb->TargetId)) {
  511. //
  512. // Fail SRB.
  513. //
  514. DebugPrint((1, "SpockStartIo: IssueScbCommand failed\n"));
  515. Srb->SrbStatus = SRB_STATUS_TIMEOUT;
  516. logicalUnit->CurrentSrb = NULL;
  517. ScsiPortNotification(RequestComplete,
  518. deviceExtension,
  519. Srb);
  520. }
  521. break;
  522. case SRB_FUNCTION_ABORT_COMMAND:
  523. DebugPrint((3,"SpockStartIo: Abort command\n"));
  524. //
  525. // Check to see if SRB to abort is still around.
  526. //
  527. if (!logicalUnit->CurrentSrb) {
  528. //
  529. // Request must of already completed.
  530. //
  531. DebugPrint((1,"SpockStartIo: Srb to abort already complete\n"));
  532. //
  533. // Complete ABORT SRB.
  534. //
  535. Srb->SrbStatus = SRB_STATUS_ERROR;
  536. ScsiPortNotification(RequestComplete,
  537. deviceExtension,
  538. Srb);
  539. } else if (!SpockAbortIo(deviceExtension, Srb)) {
  540. DebugPrint((1,"SpockStartIo: Abort command failed\n"));
  541. Srb->SrbStatus = SRB_STATUS_ERROR;
  542. ScsiPortNotification(RequestComplete,
  543. deviceExtension,
  544. Srb);
  545. }
  546. break;
  547. default:
  548. //
  549. // Set error, complete request
  550. // and signal ready for next request.
  551. //
  552. DebugPrint((1,"SpockStartIo: Invalid SRB request\n"));
  553. Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  554. ScsiPortNotification(RequestComplete,
  555. deviceExtension,
  556. Srb);
  557. } // end switch
  558. //
  559. // Adapter ready for next request.
  560. //
  561. ScsiPortNotification(NextRequest,
  562. deviceExtension,
  563. NULL);
  564. return TRUE;
  565. } // end SpockStartIo()
  566. BOOLEAN
  567. SpockInterrupt(
  568. IN PVOID HwDeviceExtension
  569. )
  570. /*++
  571. Routine Description:
  572. This is the interrupt handler for the IBM MCA SCSI adapter.
  573. Arguments:
  574. Device Object
  575. Return Value:
  576. Returns TRUE if interrupt expected.
  577. --*/
  578. {
  579. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  580. PSCB scb;
  581. PSCSI_REQUEST_BLOCK srb;
  582. UCHAR srbStatus;
  583. UCHAR scsiStatus;
  584. PTSB tsb;
  585. UCHAR status;
  586. UCHAR targetId;
  587. PHW_LOGICAL_UNIT logicalUnit;
  588. ULONG logError = 0;
  589. BOOLEAN srbValid = TRUE;
  590. ULONG j;
  591. if (!(ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) &
  592. BASIC_STATUS_INTERRUPT)) {
  593. //
  594. // Spurious interrupt.
  595. //
  596. return FALSE;
  597. }
  598. //
  599. // Read interrupt status register to determine
  600. // interrupting device and status.
  601. //
  602. status = ScsiPortReadPortUchar(&deviceExtension->Registers->InterruptStatus);
  603. //
  604. // Bits 0-3 are device id and
  605. // bits 4-7 are interrupt id.
  606. //
  607. targetId = status & 0x0F;
  608. status = status >> 4;
  609. //
  610. // Acknowledge interrupt.
  611. //
  612. j = 0;
  613. while (ScsiPortReadPortUchar(&deviceExtension->Registers->BasicStatus) &
  614. BASIC_STATUS_BUSY){
  615. ScsiPortStallExecution(1);
  616. if (j++ > 10000) {
  617. ScsiPortLogError(
  618. HwDeviceExtension,
  619. NULL,
  620. 0,
  621. deviceExtension->HostTargetId,
  622. 0,
  623. SP_INTERNAL_ADAPTER_ERROR,
  624. (9 << 16) | status
  625. );
  626. }
  627. }
  628. ScsiPortWritePortUchar(&deviceExtension->Registers->Attention,
  629. (UCHAR)(targetId | END_OF_INTERRUPT));
  630. switch (status) {
  631. case SCB_STATUS_SUCCESS_WITH_RETRIES:
  632. case SCB_STATUS_SUCCESS:
  633. srbStatus = SRB_STATUS_SUCCESS;
  634. scsiStatus = SCSISTAT_GOOD;
  635. DebugPrint((2, "Interupt Success: %0.4hx \n",
  636. targetId));
  637. break;
  638. case SCB_STATUS_IMMEDIATE_COMMAND_COMPLETE:
  639. if ((targetId & 7) != 7) {
  640. DebugPrint((1, "SpockInterrupt: Abort command complete\n"));
  641. //
  642. // This is an ABORT command completion.
  643. //
  644. logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
  645. 0,
  646. targetId,
  647. 0);
  648. if (logicalUnit == NULL) {
  649. break;
  650. }
  651. if (logicalUnit->AbortSrb == NULL) {
  652. logicalUnit = NULL;
  653. break;
  654. }
  655. //
  656. // Get the SRB aborted.
  657. //
  658. srb = logicalUnit->AbortSrb->NextSrb;
  659. srb->SrbStatus = SRB_STATUS_TIMEOUT;
  660. //
  661. // Remove the aborted SRB from the logical unit.
  662. //
  663. logicalUnit->CurrentSrb = NULL;
  664. logicalUnit->Scb = NULL;
  665. //
  666. // Call notification routine for the SRB.
  667. //
  668. ScsiPortNotification(RequestComplete,
  669. (PVOID)deviceExtension,
  670. srb);
  671. //
  672. // Complete the ABORT SRB.
  673. //
  674. logicalUnit->AbortSrb->SrbStatus = SRB_STATUS_SUCCESS;
  675. ScsiPortNotification(RequestComplete,
  676. (PVOID)deviceExtension,
  677. logicalUnit->AbortSrb);
  678. } else {
  679. DebugPrint((1,"SpockInterrupt: Immediate command complete\n"));
  680. }
  681. return TRUE;
  682. case SCB_STATUS_ADAPTER_FAILED:
  683. case SCB_STATUS_COMMAND_ERROR:
  684. case SCB_STATUS_SOFTWARE_SEQUENCING_ERROR:
  685. logError = SP_INTERNAL_ADAPTER_ERROR;
  686. case SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE:
  687. DebugPrint((2, "SpockInterrupt: Error\n"));
  688. srbStatus = SRB_STATUS_ERROR;
  689. break;
  690. default:
  691. srbValid = FALSE;
  692. logError = SP_INTERNAL_ADAPTER_ERROR;
  693. return TRUE;
  694. } // end switch()
  695. if (srbValid) {
  696. //
  697. // Get SCB address from logical unit extension.
  698. //
  699. logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
  700. 0,
  701. targetId,
  702. 0);
  703. if (logicalUnit == NULL || logicalUnit->Scb == NULL) {
  704. ScsiPortLogError(
  705. HwDeviceExtension,
  706. NULL,
  707. 0,
  708. deviceExtension->HostTargetId,
  709. 0,
  710. SP_INTERNAL_ADAPTER_ERROR,
  711. (6 << 16) | status
  712. );
  713. return TRUE;
  714. }
  715. scb = logicalUnit->Scb;
  716. logicalUnit->Scb = NULL;
  717. }
  718. if (logError != 0 ) {
  719. deviceExtension->ErrorCount++;
  720. //
  721. // Log the error.
  722. //
  723. ScsiPortLogError(
  724. HwDeviceExtension,
  725. NULL,
  726. 0,
  727. deviceExtension->HostTargetId,
  728. 0,
  729. SP_INTERNAL_ADAPTER_ERROR,
  730. 1 << 16 | status
  731. );
  732. if (!srbValid) {
  733. //
  734. // If the srb is not valid for this type of interrupt the
  735. // return.
  736. //
  737. return TRUE;
  738. }
  739. }
  740. //
  741. // Get virtual TSB address.
  742. //
  743. tsb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(scb->StatusBlock));
  744. if (tsb == NULL) {
  745. deviceExtension->ErrorCount++;
  746. ScsiPortLogError(
  747. HwDeviceExtension,
  748. NULL,
  749. 0,
  750. deviceExtension->HostTargetId,
  751. 0,
  752. SP_INTERNAL_ADAPTER_ERROR,
  753. (5 << 16) | status
  754. );
  755. return TRUE;
  756. }
  757. //
  758. // Get SRB and update status.
  759. //
  760. srb = scb->SrbAddress;
  761. if (status == SCB_STATUS_COMMAND_COMPLETE_WITH_FAILURE) {
  762. //
  763. // Get statuses from TSB.
  764. //
  765. MapTsbError(deviceExtension, srb, tsb);
  766. } else {
  767. srb->SrbStatus = srbStatus;
  768. srb->ScsiStatus = scsiStatus;
  769. }
  770. //
  771. // Remove the SRB from the logical unit extension.
  772. //
  773. logicalUnit->CurrentSrb = NULL;
  774. //
  775. // Call notification routine for the SRB.
  776. //
  777. ScsiPortNotification(RequestComplete,
  778. (PVOID)deviceExtension,
  779. srb);
  780. if (!(--deviceExtension->ActiveRequests)) {
  781. //
  782. // Turn disk activity light off.
  783. //
  784. DISK_ACTIVITY_LIGHT_OFF();
  785. }
  786. return TRUE;
  787. } // end SpockInterrupt()
  788. BOOLEAN
  789. SpockResetBus(
  790. IN PVOID HwDeviceExtension,
  791. IN ULONG PathId
  792. )
  793. /*++
  794. Routine Description:
  795. Reset adapter and SCSI bus.
  796. Arguments:
  797. DeviceExtension
  798. Pathid - identifies which bus on adapter that supports multiple
  799. SCSI buses.
  800. Return Value:
  801. TRUE if reset completed
  802. --*/
  803. {
  804. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  805. PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
  806. ULONG i;
  807. UNREFERENCED_PARAMETER(PathId);
  808. deviceExtension->ErrorCount++;
  809. //
  810. // Issue RESET command.
  811. //
  812. if (!IssueImmediateCommand(HwDeviceExtension,
  813. (ULONG)SCB_COMMAND_RESET,
  814. 0x0f)) {
  815. DebugPrint((1,"SpockResetBus: Reset failed\n"));
  816. return FALSE;
  817. }
  818. //
  819. // Wait 2 seconds for bus to quiet down.
  820. //
  821. for (i=0; i<10; i++) {
  822. //
  823. // Stall 200 milliseconds.
  824. //
  825. ScsiPortStallExecution(200 * 1000);
  826. }
  827. //
  828. // Wait up to 3 more seconds for adapter to become ready.
  829. //
  830. for (i=0; i<100; i++) {
  831. //
  832. // Stall 3 milliseconds.
  833. //
  834. ScsiPortStallExecution(30 * 1000);
  835. //
  836. // If busy bit is set then reset adapter has not completed.
  837. //
  838. if (ScsiPortReadPortUchar(
  839. &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
  840. continue;
  841. } else {
  842. break;
  843. }
  844. }
  845. if (i == 100) {
  846. DebugPrint((1,"SpockResetBus: Reset failed\n"));
  847. ScsiPortLogError(
  848. deviceExtension,
  849. NULL,
  850. 0,
  851. deviceExtension->HostTargetId,
  852. 0,
  853. SP_INTERNAL_ADAPTER_ERROR,
  854. 7 << 16
  855. );
  856. return FALSE;
  857. }
  858. //
  859. // Issue feature control immediate command to disable
  860. // adapter timing of SCBs.
  861. //
  862. if (!IssueImmediateCommand(HwDeviceExtension,
  863. (ULONG)SCB_COMMAND_FEATURE_CONTROL,
  864. 0x0f)) {
  865. DebugPrint((1,"SpockResetBus: Set feature controls failed\n"));
  866. }
  867. //
  868. // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
  869. //
  870. ScsiPortCompleteRequest(deviceExtension,
  871. (UCHAR)PathId,
  872. 0xFF,
  873. 0xFF,
  874. (ULONG)SRB_STATUS_BUS_RESET);
  875. //
  876. // Turn disk activity light off.
  877. //
  878. DISK_ACTIVITY_LIGHT_OFF();
  879. deviceExtension->ActiveRequests = 0;
  880. return TRUE;
  881. } // end SpockResetBus()
  882. BOOLEAN
  883. SpockAbortIo(
  884. IN PVOID HwDeviceExtension,
  885. IN PSCSI_REQUEST_BLOCK Srb
  886. )
  887. /*++
  888. Routine Description:
  889. Abort command in progress.
  890. Arguments:
  891. DeviceExtension
  892. SRB
  893. Return Value:
  894. True, if command aborted.
  895. --*/
  896. {
  897. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  898. PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
  899. PHW_LOGICAL_UNIT logicalUnit;
  900. ULONG i;
  901. //
  902. // Wait up to 10 milliseconds until adapter is not busy.
  903. //
  904. for (i=0; i<1000; i++) {
  905. if (ScsiPortReadPortUchar(
  906. &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
  907. //
  908. // Wait 10 microseconds.
  909. //
  910. ScsiPortStallExecution(10);
  911. } else {
  912. //
  913. // Busy bit clear. Exit loop.
  914. //
  915. break;
  916. }
  917. }
  918. if (i < 1000) {
  919. //
  920. // Save SRB in logical unit extension.
  921. //
  922. logicalUnit = ScsiPortGetLogicalUnit(HwDeviceExtension,
  923. Srb->PathId,
  924. Srb->TargetId,
  925. Srb->Lun);
  926. logicalUnit->AbortSrb = Srb;
  927. //
  928. // Issue abort to the command interface register.
  929. //
  930. ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, SCB_COMMAND_ABORT);
  931. //
  932. // Write immediate command code to attention register.
  933. //
  934. ScsiPortWritePortUchar(&mcaRegisters->Attention, (UCHAR)(Srb->TargetId | IMMEDIATE_COMMAND));
  935. return TRUE;
  936. } else {
  937. //
  938. // Timed out waiting for adapter to be in state to accept
  939. // immediate command. Return TRUE so that the abort command
  940. // will appear to have been sent and will time out causing a
  941. // SCSI bus reset to occur.
  942. DebugPrint((1,"SpockAbortIo: Timed out waiting on BUSY adapter\n"));
  943. ScsiPortLogError(
  944. deviceExtension,
  945. NULL,
  946. 0,
  947. deviceExtension->HostTargetId,
  948. 0,
  949. SP_INTERNAL_ADAPTER_ERROR,
  950. 8 << 16
  951. );
  952. return TRUE;
  953. }
  954. } // end SpockAbortIo()
  955. VOID
  956. BuildScb(
  957. IN PHW_DEVICE_EXTENSION DeviceExtension,
  958. IN PSCSI_REQUEST_BLOCK Srb
  959. )
  960. /*++
  961. Routine Description:
  962. Build SCB
  963. Arguments:
  964. DeviceExtension
  965. SRB
  966. Return Value:
  967. Nothing.
  968. --*/
  969. {
  970. PSCB scb = Srb->SrbExtension;
  971. ULONG length;
  972. //
  973. // Check for read capacity CDB. IBM boot devices store IML
  974. // code near the end of the boot device that must be preserved.
  975. // Send the operation specific SCB instead of the generic
  976. // SCSI CDB.
  977. //
  978. if (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
  979. //
  980. // Call routine to build special SCB.
  981. //
  982. BuildReadCapacity(DeviceExtension,
  983. Srb);
  984. return;
  985. }
  986. scb->Command = SCB_COMMAND_SEND_SCSI;
  987. //
  988. // Set SCB command flags.
  989. //
  990. //
  991. // Some the spock controllers do not work well with multiple devices.
  992. // If too many errors are detected then disable disconnects.
  993. //
  994. if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT ||
  995. DeviceExtension->ErrorCount > MAXIMUM_ERRORS) {
  996. scb->Command |= SCB_NO_DISCONNECT;
  997. }
  998. if (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
  999. scb->Command |= SCB_NO_SYNCHRONOUS_TRANSFER;
  1000. }
  1001. //
  1002. // Set SCB request control flags.
  1003. //
  1004. if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
  1005. //
  1006. // Write request.
  1007. //
  1008. scb->EnableFlags = SCB_ENABLE_SG_LIST |
  1009. SCB_ENABLE_WRITE |
  1010. SCB_ENABLE_RETRY_ENABLE |
  1011. SCB_ENABLE_TSB_ON_ERROR;
  1012. } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
  1013. //
  1014. // Read request.
  1015. //
  1016. scb->EnableFlags = SCB_ENABLE_SG_LIST |
  1017. SCB_ENABLE_READ |
  1018. SCB_ENABLE_SHORT_TRANSFER |
  1019. SCB_ENABLE_RETRY_ENABLE |
  1020. SCB_ENABLE_TSB_ON_ERROR;
  1021. } else {
  1022. //
  1023. // No data transfer.
  1024. //
  1025. scb->EnableFlags = SCB_ENABLE_TSB_ON_ERROR;
  1026. }
  1027. //
  1028. // Set CDB length and copy to SCB.
  1029. //
  1030. scb->CdbSize = Srb->CdbLength;
  1031. ScsiPortMoveMemory(scb->Cdb, Srb->Cdb, Srb->CdbLength);
  1032. //
  1033. // Build SDL in SCB if data transfer.
  1034. //
  1035. if (Srb->DataTransferLength) {
  1036. BuildSgl(DeviceExtension, Srb);
  1037. } else {
  1038. scb->BufferAddress = 0;
  1039. scb->BufferLength = 0;
  1040. }
  1041. //
  1042. // Put physical address of TSB in SCB.
  1043. //
  1044. scb->StatusBlock = ScsiPortConvertPhysicalAddressToUlong(
  1045. ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
  1046. &scb->Tsb, &length));
  1047. return;
  1048. } // end BuildScb()
  1049. VOID
  1050. BuildSgl(
  1051. IN PVOID DeviceExtension,
  1052. IN PSCSI_REQUEST_BLOCK Srb
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. Build scatter/gather descriptor list in SCB.
  1057. Arguments:
  1058. DeviceExtension
  1059. SRB
  1060. Return Value:
  1061. Nothing.
  1062. --*/
  1063. {
  1064. PSCB scb = Srb->SrbExtension;
  1065. PVOID dataPointer = Srb->DataBuffer;
  1066. ULONG bytesLeft = Srb->DataTransferLength;
  1067. PSDL sdl = &scb->Sdl;
  1068. ULONG physicalSdl;
  1069. ULONG physicalAddress;
  1070. ULONG length;
  1071. ULONG descriptorCount = 0;
  1072. DebugPrint((3,"BuildSgl: Enter routine\n"));
  1073. //
  1074. // Zero first SDL descriptor.
  1075. //
  1076. sdl->Descriptor[descriptorCount].Address = 0;
  1077. sdl->Descriptor[descriptorCount].Length = 0;
  1078. //
  1079. // Get physical SDL address.
  1080. //
  1081. physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
  1082. ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
  1083. sdl, &length));
  1084. //
  1085. // Assume physical memory contiguous for sizeof(SDL) bytes.
  1086. //
  1087. ASSERT(length >= sizeof(SDL));
  1088. //
  1089. // Create SDL segment descriptors.
  1090. //
  1091. do {
  1092. DebugPrint((3, "BuildSgl: Data buffer %lx\n", dataPointer));
  1093. //
  1094. // Get physical address and length of contiguous
  1095. // physical buffer.
  1096. //
  1097. physicalAddress =
  1098. ScsiPortConvertPhysicalAddressToUlong(
  1099. ScsiPortGetPhysicalAddress(DeviceExtension,
  1100. Srb,
  1101. dataPointer,
  1102. &length));
  1103. DebugPrint((3, "BuildSgl: Physical address %lx\n", physicalAddress));
  1104. DebugPrint((3, "BuildSgl: Data length %lx\n", length));
  1105. DebugPrint((3, "BuildSgl: Bytes left %lx\n", bytesLeft));
  1106. //
  1107. // If length of physical memory is more
  1108. // than bytes left in transfer, use bytes
  1109. // left as final length.
  1110. //
  1111. if (length > bytesLeft) {
  1112. length = bytesLeft;
  1113. }
  1114. //
  1115. // Check for adjacent physical memory descriptors.
  1116. //
  1117. if (descriptorCount &&
  1118. ((sdl->Descriptor[descriptorCount-1].Address +
  1119. sdl->Descriptor[descriptorCount-1].Length) == physicalAddress)) {
  1120. DebugPrint((3,"BuildSgl: Concatenate adjacent descriptors\n"));
  1121. sdl->Descriptor[descriptorCount-1].Length += length;
  1122. } else {
  1123. sdl->Descriptor[descriptorCount].Address = physicalAddress;
  1124. sdl->Descriptor[descriptorCount].Length = length;
  1125. descriptorCount++;
  1126. }
  1127. //
  1128. // Adjust counts.
  1129. //
  1130. dataPointer = (PUCHAR)dataPointer + length;
  1131. bytesLeft -= length;
  1132. } while (bytesLeft);
  1133. //
  1134. // Write SDL length to SCB.
  1135. //
  1136. scb->BufferLength = descriptorCount * sizeof(SG_DESCRIPTOR);
  1137. DebugPrint((3,"BuildSgl: SDL length is %d\n", descriptorCount));
  1138. //
  1139. // Write SDL address to SCB.
  1140. //
  1141. scb->BufferAddress = physicalSdl;
  1142. DebugPrint((3,"BuildSgl: SDL address is %lx\n", sdl));
  1143. DebugPrint((3,"BuildSgl: SCB address is %lx\n", scb));
  1144. return;
  1145. } // end BuildSgl()
  1146. VOID
  1147. BuildReadCapacity(
  1148. IN PHW_DEVICE_EXTENSION DeviceExtension,
  1149. IN PSCSI_REQUEST_BLOCK Srb
  1150. )
  1151. /*++
  1152. Routine Description:
  1153. Build SCB for read capacity command.
  1154. Arguments:
  1155. DeviceExtension
  1156. SRB
  1157. Return Value:
  1158. Nothing.
  1159. --*/
  1160. {
  1161. PSCB scb = Srb->SrbExtension;
  1162. ULONG length;
  1163. DebugPrint((1, "Spock: BuildReadCapacity: Building spock read capacity\n"));
  1164. //
  1165. // Set SCB command.
  1166. //
  1167. scb->Command = SCB_COMMAND_READ_CAPACITY;
  1168. scb->Command |= SCB_NO_SYNCHRONOUS_TRANSFER | SCB_NO_DISCONNECT;
  1169. scb->EnableFlags = SCB_ENABLE_TSB_ON_ERROR |
  1170. SCB_ENABLE_READ |
  1171. SCB_ENABLE_BYPASS_BUFFER |
  1172. SCB_ENABLE_RETRY_ENABLE;
  1173. //
  1174. // Get physical buffer address.
  1175. //
  1176. scb->BufferAddress = (ScsiPortConvertPhysicalAddressToUlong(
  1177. ScsiPortGetPhysicalAddress(DeviceExtension,
  1178. Srb,
  1179. Srb->DataBuffer,
  1180. &length)));
  1181. scb->BufferLength = Srb->DataTransferLength;
  1182. //
  1183. // Put physical address of TSB in SCB.
  1184. //
  1185. scb->StatusBlock = ScsiPortConvertPhysicalAddressToUlong(
  1186. ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
  1187. &scb->Tsb, &length));
  1188. return;
  1189. } // end BuildReadCapacity()
  1190. ULONG
  1191. McaAdapterPresent(
  1192. IN PHW_DEVICE_EXTENSION HwDeviceExtension,
  1193. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  1194. IN OUT PULONG AdapterCount,
  1195. OUT PBOOLEAN Again
  1196. )
  1197. /*++
  1198. Routine Description:
  1199. Determine if Spock adapter present in sytem by reading
  1200. interrupt status register.
  1201. Arguments:
  1202. HwDeviceExtension - miniport device extension
  1203. ConfigInfo - Supplies the known configuraiton information.
  1204. AdapterCount - Supplies the count of adapter slots which have been tested.
  1205. Again - Returns whether the OS-specific driver should call again.
  1206. Return Value:
  1207. Returns TRUE if adapter exists
  1208. --*/
  1209. {
  1210. PMCA_REGISTERS baseIoAddress;
  1211. PUCHAR ioSpace;
  1212. //
  1213. // Get the system physical address for this card. The card uses I/O space.
  1214. //
  1215. ioSpace = ScsiPortGetDeviceBase(
  1216. HwDeviceExtension, // HwDeviceExtension
  1217. ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
  1218. ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
  1219. ScsiPortConvertUlongToPhysicalAddress(0),
  1220. 0x400, // NumberOfBytes
  1221. TRUE // InIoSpace
  1222. );
  1223. //
  1224. // Scan though the adapter address looking for adapters.
  1225. //
  1226. while (AdapterAddresses[*AdapterCount] != 0) {
  1227. //
  1228. // Check to see if adapter present in system.
  1229. //
  1230. baseIoAddress = (PMCA_REGISTERS)(ioSpace +
  1231. AdapterAddresses[*AdapterCount]);
  1232. //
  1233. // Update the adapter count.
  1234. //
  1235. (*AdapterCount)++;
  1236. if (ScsiPortReadPortUchar((PUCHAR)baseIoAddress) != 0xFF) {
  1237. DebugPrint((1,"Spock: Base IO address is %x\n", baseIoAddress));
  1238. //
  1239. // An adapter has been found. Set the base address in the device
  1240. // extension, and request another call.
  1241. //
  1242. HwDeviceExtension->Registers = baseIoAddress;
  1243. *Again = TRUE;
  1244. //
  1245. // Fill in the access array information.
  1246. //
  1247. (*ConfigInfo->AccessRanges)[0].RangeStart =
  1248. ScsiPortConvertUlongToPhysicalAddress(
  1249. AdapterAddresses[*AdapterCount - 1]);
  1250. (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(MCA_REGISTERS);
  1251. (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
  1252. return(SP_RETURN_FOUND);
  1253. }
  1254. }
  1255. //
  1256. // The entire table has been searched and no adapters have been found.
  1257. // There is no need to call again and the device base can now be freed.
  1258. // Clear the adapter count for the next bus.
  1259. //
  1260. *Again = FALSE;
  1261. *(AdapterCount) = 0;
  1262. ScsiPortFreeDeviceBase(
  1263. HwDeviceExtension,
  1264. ioSpace
  1265. );
  1266. return(SP_RETURN_NOT_FOUND);
  1267. } // end McaAdapterPresent()
  1268. BOOLEAN
  1269. IssueScbCommand(
  1270. IN PVOID HwDeviceExtension,
  1271. IN ULONG PhysicalScb,
  1272. IN UCHAR TargetId
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. Send SCB to adapter.
  1277. Arguments:
  1278. DeviceExtension
  1279. Physical SCB
  1280. TargeId
  1281. Return Value:
  1282. TRUE if command sent.
  1283. FALSE if wait for BUSY bit timed out.
  1284. --*/
  1285. {
  1286. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  1287. PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
  1288. ULONG i;
  1289. //
  1290. // Wait up to 10 milliseconds until adapter is not busy.
  1291. //
  1292. for (i=0; i<1000; i++) {
  1293. if (ScsiPortReadPortUchar(
  1294. &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
  1295. //
  1296. // Wait 10 microseconds.
  1297. //
  1298. ScsiPortStallExecution(10);
  1299. } else {
  1300. //
  1301. // Busy bit clear. Exit loop.
  1302. //
  1303. break;
  1304. }
  1305. }
  1306. if (i < 1000) {
  1307. //
  1308. // Write physical SCB address to command interface register.
  1309. //
  1310. ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, PhysicalScb);
  1311. //
  1312. // Write targetid and command code to attention register.
  1313. //
  1314. ScsiPortWritePortUchar(&mcaRegisters->Attention, (UCHAR)(TargetId | START_SCB));
  1315. if (!deviceExtension->ActiveRequests++) {
  1316. //
  1317. // Turn disk activity light on.
  1318. //
  1319. DISK_ACTIVITY_LIGHT_ON();
  1320. }
  1321. return TRUE;
  1322. } else {
  1323. ScsiPortLogError(
  1324. deviceExtension,
  1325. NULL,
  1326. 0,
  1327. deviceExtension->HostTargetId,
  1328. 0,
  1329. SP_INTERNAL_ADAPTER_ERROR,
  1330. 4 << 16
  1331. );
  1332. return FALSE;
  1333. }
  1334. } // end IssueScbCommand()
  1335. BOOLEAN
  1336. IssueImmediateCommand(
  1337. IN PVOID HwDeviceExtension,
  1338. IN ULONG ImmediateCommand,
  1339. IN UCHAR TargetId
  1340. )
  1341. /*++
  1342. Routine Description:
  1343. Send SCB to adapter.
  1344. Arguments:
  1345. DeviceExtension
  1346. ImmediateCommand
  1347. TargeId
  1348. Return Value:
  1349. TRUE if command sent.
  1350. FALSE if wait for BUSY bit timed out.
  1351. --*/
  1352. {
  1353. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  1354. PMCA_REGISTERS mcaRegisters = deviceExtension->Registers;
  1355. ULONG i;
  1356. //
  1357. // Wait up to 10 milliseconds until adapter is not busy.
  1358. //
  1359. for (i=0; i<1000; i++) {
  1360. if (ScsiPortReadPortUchar(
  1361. &mcaRegisters->BasicStatus) & BASIC_STATUS_BUSY) {
  1362. //
  1363. // Wait 10 microseconds.
  1364. //
  1365. ScsiPortStallExecution(10);
  1366. } else {
  1367. //
  1368. // Busy bit clear. Exit loop.
  1369. //
  1370. break;
  1371. }
  1372. }
  1373. if (i < 1000) {
  1374. //
  1375. // Write immediate command to command interface register.
  1376. //
  1377. ScsiPortWritePortUlong(&mcaRegisters->CommandInterface, ImmediateCommand);
  1378. //
  1379. // Write targetid and command code to attention register.
  1380. //
  1381. ScsiPortWritePortUchar(&mcaRegisters->Attention,
  1382. (UCHAR)(TargetId | IMMEDIATE_COMMAND));
  1383. return TRUE;
  1384. } else {
  1385. ScsiPortLogError(
  1386. deviceExtension,
  1387. NULL,
  1388. 0,
  1389. deviceExtension->HostTargetId,
  1390. 0,
  1391. SP_INTERNAL_ADAPTER_ERROR,
  1392. 4 << 16
  1393. );
  1394. return FALSE;
  1395. }
  1396. } // end IssueImmediateCommand()
  1397. VOID
  1398. MapTsbError(
  1399. IN PHW_DEVICE_EXTENSION DeviceExtension,
  1400. IN PSCSI_REQUEST_BLOCK Srb,
  1401. IN PTSB Tsb
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. Arguments:
  1406. TSB - Termination Status Block
  1407. Return Value:
  1408. SCSI error code
  1409. --*/
  1410. {
  1411. ULONG logError = 0;
  1412. DebugPrint((2, "MapTsbError: TSB ending status %lx\n", Tsb->ScbStatus));
  1413. switch (Tsb->ScbStatus & 0x003F) {
  1414. case TSB_STATUS_NO_ERROR:
  1415. //
  1416. // Check if device is not assigned.
  1417. //
  1418. if (Tsb->CommandError == TSB_COMMAND_ERROR_DEVICE_NOT_ASSIGNED) {
  1419. //
  1420. // Check for check condition.
  1421. //
  1422. if (Tsb->DeviceStatus == SCB_DEV_STATUS_CHECK_CONDITION) {
  1423. //
  1424. // Adjust count of bytes transferred.
  1425. //
  1426. Srb->DataTransferLength -= Tsb->ResidualByteCount;
  1427. }
  1428. Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  1429. } else {
  1430. Srb->SrbStatus = SRB_STATUS_ERROR;
  1431. }
  1432. break;
  1433. case TSB_STATUS_SHORT_RECORD:
  1434. DebugPrint((1, "MapTsbError: Short record exception\n"));
  1435. Srb->DataTransferLength -= Tsb->ResidualByteCount;
  1436. Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
  1437. break;
  1438. case TSB_STATUS_INVALID_COMMAND:
  1439. DebugPrint((1, "MapTsbError: Invalid command rejected\n"));
  1440. Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  1441. logError = SP_INTERNAL_ADAPTER_ERROR;
  1442. break;
  1443. case TSB_STATUS_SCB_REJECTED:
  1444. DebugPrint((1, "MapTsbError: SCB rejected\n"));
  1445. Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  1446. logError = SP_INTERNAL_ADAPTER_ERROR;
  1447. break;
  1448. case TSB_STATUS_SCB_SPECIFIC_CHECK:
  1449. DebugPrint((1, "MapTsbError: SCB speicific check\n"));
  1450. Srb->SrbStatus = SRB_STATUS_ERROR;
  1451. logError = SP_INTERNAL_ADAPTER_ERROR;
  1452. break;
  1453. case TSB_STATUS_LONG_RECORD:
  1454. DebugPrint((1, "MapTsbError: Long record exception\n"));
  1455. Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
  1456. break;
  1457. default:
  1458. DebugPrint((1, "MapTsbError: Unknown end status %lx\n",Tsb->ScbStatus));
  1459. logError = SP_INTERNAL_ADAPTER_ERROR;
  1460. Srb->SrbStatus = SRB_STATUS_ERROR;
  1461. } // end switch
  1462. DebugPrint((2,
  1463. "MapTsbError: Device status %x, DeviceError = %x\n",
  1464. Tsb->DeviceStatus,
  1465. Tsb->DeviceError));
  1466. DebugPrint((2,
  1467. "MapTsbError: Command status %x, CommandError = %x\n",
  1468. Tsb->CommandStatus,
  1469. Tsb->CommandError));
  1470. if (logError != 0) {
  1471. //
  1472. // Log error.
  1473. //
  1474. ScsiPortLogError(
  1475. DeviceExtension,
  1476. Srb,
  1477. Srb->PathId,
  1478. Srb->TargetId,
  1479. Srb->Lun,
  1480. logError,
  1481. 2 << 16 | Tsb->ScbStatus
  1482. );
  1483. }
  1484. Srb->ScsiStatus = Tsb->DeviceStatus;
  1485. return;
  1486. } // end MapTsbError()