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.

1561 lines
35 KiB

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