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.

1401 lines
30 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. ultra24f.c
  5. Abstract:
  6. This is the port driver for the ULTRASTOR 24F EISA SCSI adapter.
  7. Authors:
  8. Mike Glass
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "miniport.h"
  15. #include "ultra24f.h" // includes scsi.h
  16. //
  17. // Device extension
  18. //
  19. typedef struct _HW_DEVICE_EXTENSION {
  20. PEISA_CONTROLLER EisaController;
  21. UCHAR HostTargetId;
  22. } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
  23. //
  24. // Function declarations
  25. //
  26. // Functions that start with 'Ultra24f' are entry points
  27. // for the OS port driver.
  28. //
  29. ULONG
  30. DriverEntry(
  31. IN PVOID DriverObject,
  32. IN PVOID Argument2
  33. );
  34. ULONG
  35. Ultra24fFindAdapter(
  36. IN PVOID DeviceExtension,
  37. IN PVOID Context,
  38. IN PVOID BusInformation,
  39. IN PCHAR ArgumentString,
  40. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  41. OUT PBOOLEAN Again
  42. );
  43. BOOLEAN
  44. Ultra24fInitialize(
  45. IN PVOID DeviceExtension
  46. );
  47. BOOLEAN
  48. Ultra24fStartIo(
  49. IN PVOID DeviceExtension,
  50. IN PSCSI_REQUEST_BLOCK Srb
  51. );
  52. BOOLEAN
  53. Ultra24fInterrupt(
  54. IN PVOID DeviceExtension
  55. );
  56. BOOLEAN
  57. Ultra24fResetBus(
  58. IN PVOID HwDeviceExtension,
  59. IN ULONG PathId
  60. );
  61. //
  62. // This function is called from Ultra24fStartIo.
  63. //
  64. VOID
  65. BuildMscp(
  66. IN PHW_DEVICE_EXTENSION DeviceExtension,
  67. IN PSCSI_REQUEST_BLOCK Srb
  68. );
  69. //
  70. // This function is called from BuildMscp.
  71. //
  72. VOID
  73. BuildSgl(
  74. IN PHW_DEVICE_EXTENSION DeviceExtension,
  75. IN PSCSI_REQUEST_BLOCK Srb
  76. );
  77. BOOLEAN
  78. SendCommand(
  79. IN PHW_DEVICE_EXTENSION DeviceExtension,
  80. IN UCHAR OperationCode,
  81. IN ULONG Address
  82. );
  83. //
  84. // This function is called from Ultra24fInterrupt.
  85. //
  86. VOID
  87. MapErrorToSrbStatus(
  88. IN PHW_DEVICE_EXTENSION DeviceExtension,
  89. IN PSCSI_REQUEST_BLOCK Srb
  90. );
  91. ULONG
  92. DriverEntry (
  93. IN PVOID DriverObject,
  94. IN PVOID Argument2
  95. )
  96. /*++
  97. Routine Description:
  98. Installable driver initialization entry point for system.
  99. Arguments:
  100. Driver Object
  101. Return Value:
  102. Status from ScsiPortInitialize()
  103. --*/
  104. {
  105. HW_INITIALIZATION_DATA hwInitializationData;
  106. ULONG i;
  107. ULONG AdapterCount = 0;
  108. DebugPrint((1,"\n\nSCSI UltraStor 24f MiniPort Driver\n"));
  109. //
  110. // Zero out structure.
  111. //
  112. for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
  113. ((PUCHAR)&hwInitializationData)[i] = 0;
  114. }
  115. //
  116. // Set size of hwInitializationData.
  117. //
  118. hwInitializationData.HwInitializationDataSize =
  119. sizeof(HW_INITIALIZATION_DATA);
  120. //
  121. // Set entry points.
  122. //
  123. hwInitializationData.HwInitialize = Ultra24fInitialize;
  124. hwInitializationData.HwFindAdapter = Ultra24fFindAdapter;
  125. hwInitializationData.HwStartIo = Ultra24fStartIo;
  126. hwInitializationData.HwInterrupt = Ultra24fInterrupt;
  127. hwInitializationData.HwResetBus = Ultra24fResetBus;
  128. //
  129. // Set number of access ranges and bus type.
  130. //
  131. hwInitializationData.NumberOfAccessRanges = 1;
  132. hwInitializationData.AdapterInterfaceType = Eisa;
  133. //
  134. // Indicate no buffer mapping but will need physical addresses.
  135. //
  136. hwInitializationData.NeedPhysicalAddresses = TRUE;
  137. //
  138. // Indicate auto request sense is supported.
  139. //
  140. hwInitializationData.AutoRequestSense = TRUE;
  141. //
  142. // Specify size of extensions.
  143. //
  144. hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
  145. //
  146. // Ask for SRB extensions for MSCPs.
  147. //
  148. hwInitializationData.SrbExtensionSize = sizeof(MSCP);
  149. return ScsiPortInitialize(DriverObject,
  150. Argument2,
  151. &hwInitializationData,
  152. &AdapterCount);
  153. } // end DriverEntry()
  154. ULONG
  155. Ultra24fFindAdapter(
  156. IN PVOID HwDeviceExtension,
  157. IN PVOID Context,
  158. IN PVOID BusInformation,
  159. IN PCHAR ArgumentString,
  160. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  161. OUT PBOOLEAN Again
  162. )
  163. /*++
  164. Routine Description:
  165. This function is called by the OS-specific port driver after
  166. the necessary storage has been allocated, to gather information
  167. about the adapter's configuration.
  168. Arguments:
  169. HwDeviceExtension - HBA miniport driver's adapter data storage
  170. ConfigInfo - Configuration information structure describing HBA
  171. Return Value:
  172. TRUE if adapter present in system
  173. --*/
  174. {
  175. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  176. PEISA_CONTROLLER eisaController;
  177. ULONG eisaSlotNumber;
  178. PVOID eisaAddress;
  179. PULONG adapterCount = Context;
  180. UCHAR interruptLevel;
  181. //
  182. // Check to see if adapter present in system.
  183. //
  184. for (eisaSlotNumber=*adapterCount + 1;
  185. eisaSlotNumber<MAXIMUM_EISA_SLOTS;
  186. eisaSlotNumber++) {
  187. //
  188. // Update the adapter count to indicate this slot has been checked.
  189. //
  190. (*adapterCount)++;
  191. //
  192. // Get the system address for this card.
  193. // The card uses I/O space.
  194. //
  195. eisaAddress = ScsiPortGetDeviceBase(deviceExtension,
  196. ConfigInfo->AdapterInterfaceType,
  197. ConfigInfo->SystemIoBusNumber,
  198. ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber),
  199. 0x1000,
  200. TRUE);
  201. eisaController =
  202. (PEISA_CONTROLLER)((PUCHAR)eisaAddress + EISA_ADDRESS_BASE);
  203. if (ScsiPortReadPortUlong(&eisaController->BoardId) ==
  204. ULTRASTOR_24F_EISA_ID) {
  205. DebugPrint((1,
  206. "Ultra24f: Adapter found at EISA slot %d\n",
  207. eisaSlotNumber));
  208. break;
  209. }
  210. //
  211. // If an adapter was not found unmap it.
  212. //
  213. ScsiPortFreeDeviceBase(deviceExtension,
  214. eisaAddress);
  215. } // end for (eisaSlotNumber ...
  216. if (!(eisaSlotNumber < MAXIMUM_EISA_SLOTS)) {
  217. //
  218. // No adapter was found. Indicate that we are done and there are no
  219. // more adapters here. Clear the adapter count for the next bus.
  220. //
  221. *Again = FALSE;
  222. *adapterCount = 0;
  223. return SP_RETURN_NOT_FOUND;
  224. }
  225. //
  226. // There is still more to look at.
  227. //
  228. *Again = TRUE;
  229. //
  230. // Store base address of EISA registers in device extension.
  231. //
  232. deviceExtension->EisaController = eisaController;
  233. deviceExtension->HostTargetId = ConfigInfo->InitiatorBusId[0] =
  234. ScsiPortReadPortUchar(&eisaController->HostAdapterId) & 0x07;
  235. //
  236. // Indicate maximum transfer length in bytes.
  237. //
  238. ConfigInfo->MaximumTransferLength = MAXIMUM_TRANSFER_LENGTH;
  239. //
  240. // Maximum number of physical segments is 32.
  241. //
  242. ConfigInfo->NumberOfPhysicalBreaks = MAXIMUM_SG_DESCRIPTORS;
  243. ConfigInfo->ScatterGather = TRUE;
  244. ConfigInfo->Master = TRUE;
  245. ConfigInfo->NumberOfBuses = 1;
  246. //
  247. // Get the system interrupt vector and IRQL.
  248. //
  249. interruptLevel =
  250. ScsiPortReadPortUchar(&eisaController->InterruptLevel) & 0xF0;
  251. switch (interruptLevel) {
  252. case US_INTERRUPT_LEVEL_15:
  253. ConfigInfo->BusInterruptLevel = 15;
  254. break;
  255. case US_INTERRUPT_LEVEL_14:
  256. ConfigInfo->BusInterruptLevel = 14;
  257. break;
  258. case US_INTERRUPT_LEVEL_11:
  259. ConfigInfo->BusInterruptLevel = 11;
  260. break;
  261. case US_INTERRUPT_LEVEL_10:
  262. ConfigInfo->BusInterruptLevel = 10;
  263. break;
  264. default:
  265. DebugPrint((1,"Ultra24fFindAdapter: No interrupt level\n"));
  266. return SP_RETURN_ERROR;
  267. }
  268. //
  269. // Set interrupt level.
  270. //
  271. ConfigInfo->InterruptMode = Latched;
  272. //
  273. // Check is ISA TSR port is enabled and the primary address is indicated.
  274. //
  275. if (!(ScsiPortReadPortUchar(&eisaController->InterruptLevel) &
  276. US_SECONDARY_ADDRESS)) {
  277. //
  278. // If this bit is set then the unsupported secondary address is
  279. // treated as an indication that the WD1003 compatibility mode
  280. // is disabled. If it is not set then the ATDISK primary address
  281. // must be claimed.
  282. //
  283. DebugPrint((1,
  284. "Ultra24fFindAdapter: ATDISK emulation at Primary address\n"));
  285. // ConfigInfo->AtdiskPrimaryClaimed = TRUE;
  286. }
  287. //
  288. // Fill in the access array information.
  289. //
  290. (*ConfigInfo->AccessRanges)[0].RangeStart =
  291. ScsiPortConvertUlongToPhysicalAddress(0x1000 * eisaSlotNumber + 0xC80);
  292. (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(EISA_CONTROLLER);
  293. (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
  294. return SP_RETURN_FOUND;
  295. } // end Ultra24fFindAdapter()
  296. BOOLEAN
  297. Ultra24fInitialize(
  298. IN PVOID HwDeviceExtension
  299. )
  300. /*++
  301. Routine Description:
  302. Inititialize adapter by enabling system doorbell interrupts.
  303. Arguments:
  304. HwDeviceExtension - HBA miniport driver's adapter data storage
  305. Return Value:
  306. TRUE - if initialization successful.
  307. FALSE - if initialization unsuccessful.
  308. --*/
  309. {
  310. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  311. PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
  312. //
  313. // Enable system doorbell interrupt.
  314. //
  315. ScsiPortWritePortUchar(&eisaController->SystemDoorBellMask,
  316. US_ENABLE_DOORBELL_INTERRUPT);
  317. ScsiPortWritePortUchar(&eisaController->SystemInterrupt,
  318. US_ENABLE_SYSTEM_DOORBELL);
  319. return(TRUE);
  320. } // end Ultra24fInitialize()
  321. BOOLEAN
  322. Ultra24fStartIo(
  323. IN PVOID HwDeviceExtension,
  324. IN PSCSI_REQUEST_BLOCK Srb
  325. )
  326. /*++
  327. Routine Description:
  328. This routine is called from the SCSI port driver synchronized
  329. with the kernel to send an MSCP.
  330. Arguments:
  331. HwDeviceExtension - HBA miniport driver's adapter data storage
  332. Srb - IO request packet
  333. Return Value:
  334. TRUE
  335. --*/
  336. {
  337. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  338. PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
  339. PMSCP mscp;
  340. PSCSI_REQUEST_BLOCK abortedSrb;
  341. UCHAR opCode;
  342. ULONG physicalMscp;
  343. ULONG length;
  344. ULONG i = 0;
  345. ASSERT(Srb->SrbStatus == SRB_STATUS_PENDING);
  346. //
  347. // Make sure that the request is for LUN 0. This
  348. // is because the Ultra24F scsi adapter echoes devices
  349. // on extra LUNs.
  350. //
  351. if (Srb->Lun != 0) {
  352. //
  353. // The Ultra24F card only supports logical unit zero.
  354. //
  355. Srb->SrbStatus = SRB_STATUS_INVALID_LUN;
  356. ScsiPortNotification(RequestComplete,
  357. deviceExtension,
  358. Srb);
  359. //
  360. // Adapter ready for next request.
  361. //
  362. ScsiPortNotification(NextRequest,
  363. deviceExtension,
  364. NULL);
  365. return TRUE;
  366. }
  367. //
  368. // Check if this is an abort function.
  369. //
  370. if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
  371. //
  372. // Verify that SRB to abort is still outstanding.
  373. //
  374. abortedSrb = ScsiPortGetSrb(deviceExtension,
  375. Srb->PathId,
  376. Srb->TargetId,
  377. Srb->Lun,
  378. Srb->QueueTag);
  379. if (abortedSrb != Srb->NextSrb ||
  380. abortedSrb->SrbStatus != SRB_STATUS_PENDING) {
  381. DebugPrint((1, "Ultra24fStartIo: SRB to abort already completed\n"));
  382. //
  383. // Complete abort SRB.
  384. //
  385. Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
  386. ScsiPortNotification(RequestComplete,
  387. deviceExtension,
  388. Srb);
  389. //
  390. // Adapter ready for next request.
  391. //
  392. ScsiPortNotification(NextRequest,
  393. deviceExtension,
  394. NULL);
  395. return TRUE;
  396. }
  397. //
  398. // Get MSCP to abort.
  399. //
  400. mscp = Srb->NextSrb->SrbExtension;
  401. //
  402. // Set abort SRB for completion.
  403. //
  404. mscp->AbortSrb = Srb;
  405. } else {
  406. //
  407. // This is a request to a device.
  408. //
  409. mscp = Srb->SrbExtension;
  410. //
  411. // Save SRB back pointer in MSCP and
  412. // clear ABORT SRB field.
  413. //
  414. mscp->SrbAddress = Srb;
  415. mscp->AbortSrb = NULL;
  416. }
  417. //
  418. // Get MSCP physical address.
  419. //
  420. physicalMscp =
  421. ScsiPortConvertPhysicalAddressToUlong(
  422. ScsiPortGetPhysicalAddress(deviceExtension, NULL, mscp, &length));
  423. //
  424. // Assume physical address is contiguous for size of ECB.
  425. //
  426. ASSERT(length >= sizeof(MSCP));
  427. switch (Srb->Function) {
  428. case SRB_FUNCTION_EXECUTE_SCSI:
  429. //
  430. // Build MSCP for this request.
  431. //
  432. BuildMscp(deviceExtension, Srb);
  433. opCode = OGM_COMMAND_SLOT_ACTIVE;
  434. break;
  435. case SRB_FUNCTION_ABORT_COMMAND:
  436. DebugPrint((1, "Ultra24fStartIo: Abort request received\n"));
  437. opCode = OGM_COMMAND_SLOT_ABORT;
  438. break;
  439. default:
  440. DebugPrint((1, "Ultra24fStartIo: Unrecognized SRB function\n"));
  441. //
  442. // Set error, complete request
  443. // and signal ready for next request.
  444. //
  445. Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  446. ScsiPortNotification(RequestComplete,
  447. deviceExtension,
  448. Srb);
  449. ScsiPortNotification(NextRequest,
  450. deviceExtension,
  451. NULL);
  452. return TRUE;
  453. } // end switch
  454. //
  455. // Write MSCP pointer and command to mailbox.
  456. //
  457. for (i=0; i<500; i++) {
  458. if (ScsiPortReadPortUchar(&eisaController->OutGoingMailCommand) ==
  459. OGM_COMMAND_SLOT_FREE) {
  460. break;
  461. } else {
  462. //
  463. // Stall 1 microsecond before trying again.
  464. //
  465. ScsiPortStallExecution(1);
  466. }
  467. }
  468. if (i == 500) {
  469. //
  470. // Let operating system time out SRB.
  471. //
  472. DebugPrint((1,"Ultra24fStartIo: Timed out waiting for mailbox\n"));
  473. } else {
  474. //
  475. // Write MSCP pointer to mailbox. This 4-byte register is not
  476. // dword aligned so it must be read a byte at a time.
  477. //
  478. ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer),
  479. (UCHAR)(physicalMscp & 0xff));
  480. ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer)+1,
  481. (UCHAR)((physicalMscp>>8) & 0xff));
  482. ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer)+2,
  483. (UCHAR)((physicalMscp>>16) & 0xff));
  484. ScsiPortWritePortUchar((UCHAR *)(&eisaController->OutGoingMailPointer)+3,
  485. (UCHAR)((physicalMscp>>24) & 0xff));
  486. //
  487. // Write command to mailbox.
  488. //
  489. ScsiPortWritePortUchar(&eisaController->OutGoingMailCommand, opCode);
  490. //
  491. // Ring the local doorbell.
  492. //
  493. ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
  494. US_MSCP_AVAILABLE);
  495. }
  496. //
  497. // Adapter ready for next request.
  498. //
  499. ScsiPortNotification(NextLuRequest,
  500. deviceExtension,
  501. Srb->PathId,
  502. Srb->TargetId,
  503. Srb->Lun);
  504. return TRUE;
  505. } // end Ultra24fStartIo()
  506. BOOLEAN
  507. Ultra24fInterrupt(
  508. IN PVOID HwDeviceExtension
  509. )
  510. /*++
  511. Routine Description:
  512. This is the interrupt service routine for the Ultra24f SCSI adapter.
  513. It reads the interrupt register to determine if the adapter is indeed
  514. the source of the interrupt and clears the interrupt at the device.
  515. If the adapter is interrupting because a mailbox is full, the MSCP is
  516. retrieved to complete the request.
  517. Arguments:
  518. HwDeviceExtension - HBA miniport driver's adapter data storage
  519. Return Value:
  520. TRUE if MailboxIn full
  521. --*/
  522. {
  523. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  524. PMSCP mscp;
  525. PSCSI_REQUEST_BLOCK srb;
  526. PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
  527. ULONG physicalMscp;
  528. UCHAR mscpStatus;
  529. //
  530. // Check interrupt pending.
  531. //
  532. if (ScsiPortReadPortUchar(&eisaController->SystemDoorBellInterrupt) &
  533. US_RESET_MSCP_COMPLETE) {
  534. //
  535. // Reset system doorbell interrupt.
  536. //
  537. ScsiPortWritePortUchar(&eisaController->SystemDoorBellInterrupt,
  538. US_RESET_MSCP_COMPLETE);
  539. } else {
  540. //
  541. // Handle spurious interrupt.
  542. //
  543. return FALSE;
  544. }
  545. //
  546. // Check status of completing MSCP in mailbox.
  547. //
  548. mscpStatus = ScsiPortReadPortUchar(&eisaController->InComingMailStatus);
  549. switch (mscpStatus) {
  550. case ICM_STATUS_COMPLETE_SUCCESS:
  551. case ICM_STATUS_COMPLETE_ERROR:
  552. //
  553. // Get physical address of MSCP
  554. //
  555. physicalMscp = ScsiPortReadPortUlong(&eisaController->InComingMailPointer);
  556. //
  557. // Get virtual MSCP address.
  558. //
  559. mscp = ScsiPortGetVirtualAddress(deviceExtension,
  560. ScsiPortConvertUlongToPhysicalAddress(physicalMscp));
  561. //
  562. // Make sure the physical address was valid.
  563. //
  564. if (mscp == NULL) {
  565. break;
  566. }
  567. //
  568. // Get SRB from MSCP.
  569. //
  570. srb = mscp->SrbAddress;
  571. //
  572. // Update SRB statuses.
  573. //
  574. if (mscpStatus == ICM_STATUS_COMPLETE_ERROR) {
  575. //
  576. // Translate adapter status to SRB status
  577. // and log error if necessary.
  578. //
  579. MapErrorToSrbStatus(deviceExtension, srb);
  580. } else {
  581. srb->SrbStatus = SRB_STATUS_SUCCESS;
  582. srb->ScsiStatus = SCSISTAT_GOOD;
  583. }
  584. //
  585. // Call notification routine for the SRB.
  586. //
  587. ScsiPortNotification(RequestComplete,
  588. (PVOID)deviceExtension,
  589. srb);
  590. break;
  591. case ICM_STATUS_ABORT_SUCCESS:
  592. case ICM_STATUS_ABORT_FAILED:
  593. DebugPrint((1,"Ultra24fInterrupt: Abort command completed\n"));
  594. break;
  595. case ICM_STATUS_SLOT_FREE:
  596. DebugPrint((1, "Ultra24fInterrupt: Mailbox empty\n"));
  597. return TRUE;
  598. default:
  599. DebugPrint((1,
  600. "Ultra24fInterrupt: Unexpected mailbox status %x\n",
  601. mscpStatus));
  602. //
  603. // Log the error.
  604. //
  605. ScsiPortLogError(
  606. HwDeviceExtension,
  607. NULL,
  608. 0,
  609. deviceExtension->HostTargetId,
  610. 0,
  611. SP_INTERNAL_ADAPTER_ERROR,
  612. 1 << 16 | mscpStatus
  613. );
  614. break;
  615. } // end switch(mscpStatus)
  616. //
  617. // Clear incoming mailbox status.
  618. //
  619. ScsiPortWritePortUchar(&eisaController->InComingMailStatus,
  620. ICM_STATUS_SLOT_FREE);
  621. return TRUE;
  622. } // end Ultra24fInterrupt()
  623. VOID
  624. BuildMscp(
  625. IN PHW_DEVICE_EXTENSION DeviceExtension,
  626. IN PSCSI_REQUEST_BLOCK Srb
  627. )
  628. /*++
  629. Routine Description:
  630. Build MSCP for Ultra24f from SRB.
  631. Arguments:
  632. DeviceExtenson
  633. SRB
  634. Return Value:
  635. Nothing.
  636. --*/
  637. {
  638. PMSCP mscp = Srb->SrbExtension;
  639. ULONG length;
  640. //
  641. // Set MSCP command.
  642. //
  643. mscp->OperationCode = MSCP_OPERATION_SCSI_COMMAND;
  644. //
  645. // Check SRB for disabled disconnect.
  646. //
  647. // NOTE: UltraStor 24f SCSI adapter does not
  648. // support disabling synchronous transfer
  649. // per request.
  650. //
  651. if (Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
  652. mscp->DisableDisconnect = TRUE;
  653. }
  654. //
  655. // Set channel, target id and lun.
  656. //
  657. mscp->Channel = Srb->PathId;
  658. mscp->TargetId = Srb->TargetId;
  659. mscp->Lun = Srb->Lun;
  660. //
  661. // Set CDB length and copy to MSCP.
  662. //
  663. mscp->CdbLength = Srb->CdbLength;
  664. ScsiPortMoveMemory(mscp->Cdb, Srb->Cdb, Srb->CdbLength);
  665. //
  666. // Build SGL in MSCP if data transfer.
  667. //
  668. if (Srb->DataTransferLength > 0) {
  669. //
  670. // Build scattergather descriptor list.
  671. //
  672. BuildSgl(DeviceExtension, Srb);
  673. //
  674. // Set transfer direction.
  675. //
  676. if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
  677. //
  678. // Write request.
  679. //
  680. mscp->TransferDirection = MSCP_TRANSFER_OUT;
  681. } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
  682. //
  683. // Read request.
  684. //
  685. mscp->TransferDirection = MSCP_TRANSFER_IN;
  686. }
  687. } else {
  688. //
  689. // Set up MSCP for no data transfer.
  690. //
  691. mscp->TransferDirection = MSCP_NO_TRANSFER;
  692. mscp->DataLength = 0;
  693. mscp->ScatterGather = FALSE;
  694. mscp->SgDescriptorCount = 0;
  695. }
  696. //
  697. // Setup auto sense if necessary.
  698. //
  699. if (Srb->SenseInfoBufferLength != 0 &&
  700. !(Srb->SrbFlags & SRB_FLAGS_DISABLE_AUTOSENSE)) {
  701. //
  702. // Set the flag to enable auto sense and fill in the address and length
  703. // of the sense buffer.
  704. //
  705. mscp->RequestSenseLength = Srb->SenseInfoBufferLength;
  706. mscp->RequestSensePointer = ScsiPortConvertPhysicalAddressToUlong(
  707. ScsiPortGetPhysicalAddress(DeviceExtension,
  708. Srb,
  709. Srb->SenseInfoBuffer,
  710. &length));
  711. ASSERT(length >= Srb->SenseInfoBufferLength);
  712. } else {
  713. //
  714. // Ultra24F uses nonzero request sense pointer
  715. // as an indication of autorequestsense.
  716. //
  717. mscp->RequestSenseLength = 0;
  718. mscp->RequestSensePointer = 0;
  719. }
  720. //
  721. // Zero out command link, status and abort fields.
  722. //
  723. mscp->CommandLink = 0;
  724. mscp->AdapterStatus = 0;
  725. mscp->TargetStatus = 0;
  726. mscp->AbortSrb = 0;
  727. //
  728. // Bypass cache.
  729. //
  730. mscp->UseCache = FALSE;
  731. return;
  732. } // end BuildMscp()
  733. VOID
  734. BuildSgl(
  735. IN PHW_DEVICE_EXTENSION DeviceExtension,
  736. IN PSCSI_REQUEST_BLOCK Srb
  737. )
  738. /*++
  739. Routine Description:
  740. This routine builds a scatter/gather descriptor list in the MSCP.
  741. Arguments:
  742. DeviceExtension
  743. Srb
  744. Return Value:
  745. None
  746. --*/
  747. {
  748. PVOID dataPointer = Srb->DataBuffer;
  749. ULONG bytesLeft = Srb->DataTransferLength;
  750. PMSCP mscp = Srb->SrbExtension;
  751. PSDL sdl = &mscp->Sdl;
  752. ULONG physicalSdl;
  753. ULONG physicalAddress;
  754. ULONG length;
  755. ULONG descriptorCount = 0;
  756. //
  757. // Get physical SDL address.
  758. //
  759. physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
  760. ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
  761. sdl, &length));
  762. //
  763. // Assume physical memory contiguous for sizeof(SGL) bytes.
  764. //
  765. ASSERT(length >= sizeof(SDL));
  766. //
  767. // Create SDL segment descriptors.
  768. //
  769. do {
  770. //
  771. // Get physical address and length of contiguous
  772. // physical buffer.
  773. //
  774. physicalAddress =
  775. ScsiPortConvertPhysicalAddressToUlong(
  776. ScsiPortGetPhysicalAddress(DeviceExtension,
  777. Srb,
  778. dataPointer,
  779. &length));
  780. //
  781. // If length of physical memory is more
  782. // than bytes left in transfer, use bytes
  783. // left as final length.
  784. //
  785. if (length > bytesLeft) {
  786. length = bytesLeft;
  787. }
  788. sdl->Descriptor[descriptorCount].Address = physicalAddress;
  789. sdl->Descriptor[descriptorCount].Length = length;
  790. //
  791. // Adjust counts.
  792. //
  793. dataPointer = (PUCHAR)dataPointer + length;
  794. bytesLeft -= length;
  795. descriptorCount++;
  796. } while (bytesLeft);
  797. //
  798. // Check for only one descriptor. As an optimization, in these
  799. // cases, use nonscattergather requests.
  800. //
  801. if (descriptorCount == 1) {
  802. //
  803. // Set descriptor count to 0.
  804. //
  805. mscp->SgDescriptorCount = 0;
  806. //
  807. // Set data pointer to data buffer.
  808. //
  809. mscp->DataPointer = physicalAddress;
  810. //
  811. // Set data transfer length.
  812. //
  813. mscp->DataLength = Srb->DataTransferLength;
  814. //
  815. // Clear scattergather bit.
  816. //
  817. mscp->ScatterGather = FALSE;
  818. } else {
  819. //
  820. // Write SDL count to MSCP.
  821. //
  822. mscp->SgDescriptorCount = (UCHAR)descriptorCount;
  823. //
  824. // Write SGL address to ECB.
  825. //
  826. mscp->DataPointer = physicalSdl;
  827. //
  828. // Zero data transfer length as an indication
  829. // of scattergater.
  830. //
  831. mscp->DataLength = 0;
  832. mscp->DataLength = Srb->DataTransferLength;
  833. //
  834. // Indicate scattergather operation.
  835. //
  836. mscp->ScatterGather = TRUE;
  837. }
  838. return;
  839. } // end BuildSgl()
  840. BOOLEAN
  841. Ultra24fResetBus(
  842. IN PVOID HwDeviceExtension,
  843. IN ULONG PathId
  844. )
  845. /*++
  846. Routine Description:
  847. Reset Ultra24f SCSI adapter and SCSI bus.
  848. Arguments:
  849. HwDeviceExtension - HBA miniport driver's adapter data storage
  850. Return Value:
  851. Nothing.
  852. --*/
  853. {
  854. PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
  855. PEISA_CONTROLLER eisaController = deviceExtension->EisaController;
  856. ULONG j;
  857. //
  858. // The Ultra24F only supports a single SCSI channel.
  859. //
  860. UNREFERENCED_PARAMETER(PathId);
  861. DebugPrint((2,"ResetBus: Reset Ultra24f and SCSI bus\n"));
  862. //
  863. // Reset SCSI bus.
  864. //
  865. ScsiPortWritePortUchar(&eisaController->LocalDoorBellInterrupt,
  866. (US_SCSI_BUS_RESET | US_HBA_RESET));
  867. //
  868. // Complete all outstanding requests.
  869. //
  870. ScsiPortCompleteRequest(deviceExtension,
  871. (UCHAR)0,
  872. (UCHAR)-1,
  873. (UCHAR)-1,
  874. SRB_STATUS_BUS_RESET);
  875. //
  876. // Wait for local processor to clear reset bit.
  877. //
  878. for (j=0; j<200000; j++) {
  879. if (!(ScsiPortReadPortUchar(&eisaController->LocalDoorBellInterrupt) &
  880. US_SCSI_BUS_RESET)) {
  881. break;
  882. }
  883. ScsiPortStallExecution(10);
  884. } // end for (j=0 ...
  885. if (j == 200000) {
  886. //
  887. // Busy has not gone low. Assume the card is gone.
  888. // Log the error and fail the request.
  889. //
  890. ScsiPortLogError(deviceExtension,
  891. NULL,
  892. 0,
  893. deviceExtension->HostTargetId,
  894. 0,
  895. SP_INTERNAL_ADAPTER_ERROR,
  896. 3 << 16);
  897. return FALSE;
  898. }
  899. return TRUE;
  900. } // end Ultra24fResetBus()
  901. VOID
  902. MapErrorToSrbStatus(
  903. IN PHW_DEVICE_EXTENSION DeviceExtension,
  904. IN PSCSI_REQUEST_BLOCK Srb
  905. )
  906. /*++
  907. Routine Description:
  908. Translate Ultra24f error to SRB error.
  909. Arguments:
  910. Device Extension for logging error
  911. SRB
  912. Return Value:
  913. Updated SRB
  914. --*/
  915. {
  916. ULONG logError = 0;
  917. UCHAR srbStatus;
  918. PMSCP mscp = Srb->SrbExtension;
  919. switch (mscp->AdapterStatus) {
  920. case MSCP_NO_ERROR:
  921. srbStatus = SRB_STATUS_ERROR | SRB_STATUS_AUTOSENSE_VALID;
  922. break;
  923. case MSCP_SELECTION_TIMEOUT:
  924. srbStatus = SRB_STATUS_SELECTION_TIMEOUT;
  925. break;
  926. case MSCP_BUS_UNDER_OVERRUN:
  927. DebugPrint((1,"MapErrorToSrbStatus: Data over/underrun\n"));
  928. logError = SP_PROTOCOL_ERROR;
  929. srbStatus = SRB_STATUS_DATA_OVERRUN;
  930. break;
  931. case MSCP_UNEXPECTED_BUS_FREE:
  932. DebugPrint((1,"MapErrorToSrbStatus: Unexpected bus free\n"));
  933. logError = SP_PROTOCOL_ERROR;
  934. srbStatus = SRB_STATUS_UNEXPECTED_BUS_FREE;
  935. break;
  936. case MSCP_INVALID_PHASE_CHANGE:
  937. DebugPrint((1,"MapErrorToSrbStatus: Invalid bus phase\n"));
  938. logError = SP_PROTOCOL_ERROR;
  939. srbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
  940. break;
  941. case MSCP_INVALID_COMMAND:
  942. case MSCP_INVALID_PARAMETER:
  943. case MSCP_INVALID_DATA_LIST:
  944. case MSCP_INVALID_SG_LIST:
  945. case MSCP_ILLEGAL_SCSI_COMMAND:
  946. DebugPrint((1,"MapErrorToSrbStatus: Invalid command\n"));
  947. srbStatus = SRB_STATUS_INVALID_REQUEST;
  948. break;
  949. case MSCP_BUS_RESET_ERROR:
  950. DebugPrint((1,"MapErrorToSrbStatus: Bus reset\n"));
  951. srbStatus = SRB_STATUS_BUS_RESET;
  952. break;
  953. case MSCP_ABORT_NOT_FOUND:
  954. case MSCP_SCSI_BUS_ABORT_ERROR:
  955. DebugPrint((1,"MapErrorToSrbStatus: Abort not found\n"));
  956. srbStatus = SRB_STATUS_ABORT_FAILED;
  957. break;
  958. default:
  959. logError = SP_PROTOCOL_ERROR;
  960. srbStatus = SRB_STATUS_ERROR;
  961. break;
  962. } // end switch ...
  963. //
  964. // Log error if indicated.
  965. //
  966. if (logError) {
  967. ScsiPortLogError(
  968. DeviceExtension,
  969. Srb,
  970. Srb->PathId,
  971. Srb->TargetId,
  972. Srb->Lun,
  973. logError,
  974. 2 << 16 | mscp->AdapterStatus
  975. );
  976. }
  977. //
  978. // Set SRB status.
  979. //
  980. Srb->SrbStatus = srbStatus;
  981. //
  982. // Set target SCSI status in SRB.
  983. //
  984. Srb->ScsiStatus = mscp->TargetStatus;
  985. return;
  986. } // end MapErrorToSrbStatus()