Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2799 lines
80 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 2001
  3. Module Name:
  4. sbp2scsi.c
  5. Abstract:
  6. module for the SBP-2 SCSI interface routines
  7. Author:
  8. George Chrysanthakopoulos January-1997 (started)
  9. Environment:
  10. Kernel mode
  11. Revision History :
  12. --*/
  13. #include "sbp2port.h"
  14. NTSTATUS
  15. Sbp2ScsiRequests(
  16. IN PDEVICE_OBJECT DeviceObject,
  17. IN PIRP Irp
  18. )
  19. /*++
  20. Routine Description:
  21. This routine handles all IRP_MJ_SCSI requests and queues them on
  22. our device queue. Then it calls StartNextPacket so our StartIo
  23. will run and process the request.
  24. Arguments:
  25. DeviceObject - this driver's device object
  26. Irp - the class driver request
  27. Return Value:
  28. NTSTATUS
  29. --*/
  30. {
  31. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  32. PSCSI_REQUEST_BLOCK srb;
  33. NTSTATUS status;
  34. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  35. KIRQL cIrql;
  36. status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
  37. if (!NT_SUCCESS (status)) {
  38. Irp->IoStatus.Status = status;
  39. Irp->IoStatus.Information = 0;
  40. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  41. return status;
  42. }
  43. //
  44. // Get a pointer to the SRB.
  45. //
  46. srb = irpStack->Parameters.Scsi.Srb;
  47. switch (srb->Function) {
  48. case SRB_FUNCTION_EXECUTE_SCSI:
  49. if (TEST_FLAG(
  50. deviceExtension->DeviceFlags,
  51. (DEVICE_FLAG_REMOVED | DEVICE_FLAG_PNP_STOPPED |
  52. DEVICE_FLAG_DEVICE_FAILED)
  53. )) {
  54. //
  55. // we got a REMOVE/STOP, we can't accept any more requests...
  56. //
  57. status = STATUS_DEVICE_DOES_NOT_EXIST;
  58. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  59. srb->InternalStatus = status;
  60. DEBUGPRINT2((
  61. "Sbp2Port: ScsiReq: ext=x%p rmv/stop (fl=x%x), status=x%x\n",
  62. deviceExtension,
  63. deviceExtension->DeviceFlags,
  64. status
  65. ));
  66. Irp->IoStatus.Status = srb->InternalStatus;
  67. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  68. IoCompleteRequest (Irp,IO_NO_INCREMENT);
  69. return status;
  70. }
  71. //
  72. // check if this is a request that can be failed if we are powered down..
  73. //
  74. if (TEST_FLAG(srb->SrbFlags,SRB_FLAGS_NO_KEEP_AWAKE)) {
  75. //
  76. // if we are in d3 punt this irp...
  77. //
  78. if (deviceExtension->DevicePowerState == PowerDeviceD3) {
  79. DEBUGPRINT2((
  80. "Sbp2Port: ScsiReq: ext=x%p power down, punt irp=x%p\n",
  81. deviceExtension,
  82. Irp
  83. ));
  84. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  85. srb->SrbStatus = SRB_STATUS_NOT_POWERED;
  86. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  87. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  88. return STATUS_UNSUCCESSFUL;
  89. }
  90. }
  91. IoMarkIrpPending (Irp);
  92. if (TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_QUEUE_LOCKED) &&
  93. TEST_FLAG(srb->SrbFlags,SRB_FLAGS_BYPASS_LOCKED_QUEUE)) {
  94. //
  95. // by pass queueing, this guy has to be processed immediately.
  96. // Since queue is locked, no other requests are being processed
  97. //
  98. if (TEST_FLAG(deviceExtension->DeviceFlags,(DEVICE_FLAG_LOGIN_IN_PROGRESS | DEVICE_FLAG_RECONNECT))){
  99. //
  100. // we are in the middle of a bus reset reconnect..
  101. // defere this until after we have established a connection again
  102. //
  103. Sbp2DeferPendingRequest (deviceExtension, Irp);
  104. } else {
  105. KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
  106. Sbp2StartIo (DeviceObject, Irp);
  107. KeLowerIrql (cIrql);
  108. }
  109. } else {
  110. Sbp2StartPacket (DeviceObject, Irp, &srb->QueueSortKey);
  111. }
  112. return STATUS_PENDING;
  113. break;
  114. case SRB_FUNCTION_CLAIM_DEVICE:
  115. KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
  116. if (TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_CLAIMED)) {
  117. status = STATUS_DEVICE_BUSY;
  118. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  119. srb->InternalStatus = STATUS_DEVICE_BUSY;
  120. } else {
  121. SET_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_CLAIMED);
  122. srb->DataBuffer = DeviceObject;
  123. srb->SrbStatus = SRB_STATUS_SUCCESS;
  124. status = STATUS_SUCCESS;
  125. }
  126. KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
  127. break;
  128. case SRB_FUNCTION_RELEASE_DEVICE:
  129. KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
  130. CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_CLAIMED);
  131. KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
  132. srb->SrbStatus = SRB_STATUS_SUCCESS;
  133. status = STATUS_SUCCESS;
  134. break;
  135. case SRB_FUNCTION_FLUSH_QUEUE:
  136. case SRB_FUNCTION_FLUSH:
  137. DEBUGPRINT3(("Sbp2Port: ScsiReq: Flush Queue/ORB list\n" ));
  138. if (TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_STOPPED)) {
  139. CleanupOrbList(deviceExtension,STATUS_REQUEST_ABORTED);
  140. srb->SrbStatus = SRB_STATUS_SUCCESS;
  141. status = STATUS_SUCCESS;
  142. } else {
  143. //
  144. // ISSUE-georgioc-2000/02/20 FLUSH_QUEUE should be failed if they
  145. // cannot be handled.
  146. //
  147. DEBUGPRINT3(("Sbp2Port: ScsiReq: Cannot Flush active queue\n" ));
  148. srb->SrbStatus = SRB_STATUS_SUCCESS;
  149. status = STATUS_SUCCESS;
  150. }
  151. break;
  152. case SRB_FUNCTION_RESET_BUS:
  153. status = Sbp2Issue1394BusReset(deviceExtension);
  154. DEBUGPRINT3(("Sbp2Port: ScsiReq: Issuing a 1394 bus reset. \n" ));
  155. if (!NT_SUCCESS(status)) {
  156. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  157. srb->InternalStatus = status;
  158. } else {
  159. srb->SrbStatus = SRB_STATUS_SUCCESS;
  160. }
  161. break;
  162. case SRB_FUNCTION_LOCK_QUEUE:
  163. //
  164. // lock the queue
  165. //
  166. if (TEST_FLAG(deviceExtension->DeviceFlags,(DEVICE_FLAG_REMOVED | DEVICE_FLAG_STOPPED)) ) {
  167. status = STATUS_DEVICE_DOES_NOT_EXIST;
  168. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  169. srb->InternalStatus = STATUS_DEVICE_DOES_NOT_EXIST;
  170. } else {
  171. KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
  172. SET_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_QUEUE_LOCKED);
  173. KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
  174. status = STATUS_SUCCESS;
  175. srb->SrbStatus = SRB_STATUS_SUCCESS;
  176. DEBUGPRINT2(("Sbp2Port: ScsiReq: ext=x%p, LOCK_QUEUE\n", deviceExtension));
  177. }
  178. break;
  179. case SRB_FUNCTION_UNLOCK_QUEUE:
  180. //
  181. // re-enable the device queue...
  182. //
  183. DEBUGPRINT2(("Sbp2Port: ScsiReq: ext=x%p, UNLOCK_QUEUE\n", deviceExtension));
  184. KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
  185. CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_QUEUE_LOCKED);
  186. KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
  187. //
  188. // check if there was a request that was deferred until we were powerd up..
  189. //
  190. //
  191. if (deviceExtension->PowerDeferredIrp) {
  192. PIRP tIrp = deviceExtension->PowerDeferredIrp;
  193. DEBUGPRINT2((
  194. "Sbp2Port: ScsiReq: restart powerDeferredIrp=x%p\n",
  195. tIrp
  196. ));
  197. KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
  198. deviceExtension->PowerDeferredIrp = NULL;
  199. KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
  200. Sbp2StartPacket (DeviceObject, tIrp, NULL);
  201. }
  202. if (deviceExtension->DevicePowerState == PowerDeviceD0) {
  203. //
  204. // the queue was just unlocked and we are in D0, which means we can resume
  205. // packet processing...
  206. //
  207. KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
  208. Sbp2StartNextPacketByKey(
  209. DeviceObject,
  210. deviceExtension->CurrentKey
  211. );
  212. KeLowerIrql (cIrql);
  213. }
  214. if (TEST_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED)) {
  215. status = STATUS_DEVICE_DOES_NOT_EXIST;
  216. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  217. srb->InternalStatus = STATUS_DEVICE_DOES_NOT_EXIST;
  218. break;
  219. } else if (deviceExtension->DevicePowerState == PowerDeviceD3) {
  220. //
  221. // Clean up any deferred FREEs so we HAVE to use the ORB_POINTER
  222. // write on the next insertion to the pending list
  223. //
  224. KeAcquireSpinLock(&deviceExtension->OrbListSpinLock,&cIrql);
  225. if (deviceExtension->NextContextToFree) {
  226. FreeAsyncRequestContext(deviceExtension,deviceExtension->NextContextToFree);
  227. deviceExtension->NextContextToFree = NULL;
  228. }
  229. KeReleaseSpinLock (&deviceExtension->OrbListSpinLock,cIrql);
  230. if (deviceExtension->SystemPowerState != PowerSystemWorking) {
  231. KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
  232. //
  233. // we need to invalidate our generation because on resume we might try to issue
  234. // a request BEFORE we get the bus reset notification..
  235. //
  236. deviceExtension->CurrentGeneration = 0xFFFFFFFF;
  237. KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
  238. }
  239. srb->SrbStatus = SRB_STATUS_SUCCESS;
  240. Irp->IoStatus.Status = STATUS_SUCCESS;
  241. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  242. if (deviceExtension->SystemPowerState == PowerSystemWorking) {
  243. #if DBG
  244. if (!IsListEmpty (&DeviceObject->DeviceQueue.DeviceListHead)) {
  245. DEBUGPRINT2((
  246. "\nSbp2Port: ScsiReq: ext=x%p, RESTARTING NON-EMPTY " \
  247. "DEV_Q AT D3!\n",
  248. deviceExtension
  249. ));
  250. }
  251. #endif
  252. KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
  253. Sbp2StartNextPacketByKey(
  254. DeviceObject,
  255. deviceExtension->CurrentKey
  256. );
  257. KeLowerIrql (cIrql);
  258. }
  259. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  260. return STATUS_SUCCESS;
  261. }
  262. status = STATUS_SUCCESS;
  263. srb->SrbStatus = SRB_STATUS_SUCCESS;
  264. break;
  265. default:
  266. status = STATUS_NOT_SUPPORTED;
  267. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  268. srb->InternalStatus = STATUS_NOT_SUPPORTED;
  269. DEBUGPRINT3(("Sbp2Port: ScsiReq: SRB Function not handled, srb->CdbLength %x, Exiting.\n",srb->CdbLength ));
  270. break;
  271. }
  272. if (!NT_SUCCESS(status)) {
  273. //
  274. // it'll either have gone to the StartIo routine or have been
  275. // failed before hitting the device. Therefore ensure that
  276. // srb->InternalStatus is set correctly.
  277. //
  278. ASSERT(srb->SrbStatus == SRB_STATUS_INTERNAL_ERROR);
  279. ASSERT((LONG)srb->InternalStatus == status);
  280. }
  281. Irp->IoStatus.Status = status;
  282. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  283. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  284. return status;
  285. }
  286. VOID
  287. Sbp2StartIo(
  288. IN PDEVICE_OBJECT DeviceObject,
  289. IN PIRP Irp
  290. )
  291. /*++
  292. Routine Description:
  293. Takes incoming, queued requests, and sends them down to the 1394 bus
  294. Arguments:
  295. DeviceObject - Our device object
  296. Irp - Request from class drivers,
  297. Return Value:
  298. --*/
  299. {
  300. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  301. PSCSI_REQUEST_BLOCK srb;
  302. NTSTATUS status;
  303. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  304. PASYNC_REQUEST_CONTEXT context;
  305. //
  306. // Get a pointer to the SRB.
  307. //
  308. srb = irpStack->Parameters.Scsi.Srb;
  309. Irp->IoStatus.Status = STATUS_PENDING;
  310. srb->SrbStatus = SRB_STATUS_PENDING;
  311. if (TEST_FLAG(
  312. deviceExtension->DeviceFlags,
  313. (DEVICE_FLAG_REMOVED | DEVICE_FLAG_PNP_STOPPED |
  314. DEVICE_FLAG_DEVICE_FAILED | DEVICE_FLAG_ABSENT_ON_POWER_UP)
  315. )) {
  316. //
  317. // Removed, stopped, or absent, so can't accept any more requests
  318. //
  319. status = STATUS_DEVICE_DOES_NOT_EXIST;
  320. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  321. Irp->IoStatus.Status = status;
  322. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  323. DEBUGPRINT2((
  324. "Sbp2Port: StartIo: dev stopped/removed/absent, fail irp=x%p\n",
  325. Irp
  326. ));
  327. Sbp2StartNextPacketByKey (DeviceObject, 0);
  328. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  329. return;
  330. }
  331. if (TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_QUEUE_LOCKED)) {
  332. if (!TEST_FLAG(srb->SrbFlags,SRB_FLAGS_BYPASS_LOCKED_QUEUE)) {
  333. if (!Sbp2InsertByKeyDeviceQueue(
  334. &DeviceObject->DeviceQueue,
  335. &Irp->Tail.Overlay.DeviceQueueEntry,
  336. srb->QueueSortKey)) {
  337. //
  338. // ISSUE-georgioc-2000/02/20 deadlock possible because
  339. // queue is now busy and noone has called StartIo().
  340. // should instead queue the request and then later,
  341. // after an UNLOCK arrives, process this queue of
  342. // requests that occurred when the queue was locked.
  343. // OR should comment why this is not a deadlock
  344. //
  345. DEBUGPRINT2((
  346. "Sbp2Port: StartIo: insert failed, compl irp=x%p\n",
  347. Irp
  348. ));
  349. srb->SrbStatus = SRB_STATUS_BUSY;
  350. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  351. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  352. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  353. }
  354. return;
  355. }
  356. } else {
  357. //
  358. // CASE 1: Device powered Down, but system running.
  359. //
  360. // Queue this request, Power up device, then when done start
  361. // processing requests
  362. //
  363. if ((deviceExtension->DevicePowerState == PowerDeviceD3) &&
  364. (deviceExtension->SystemPowerState == PowerSystemWorking)) {
  365. BOOLEAN queued;
  366. POWER_STATE state;
  367. queued = Sbp2InsertByKeyDeviceQueue(
  368. &DeviceObject->DeviceQueue,
  369. &Irp->Tail.Overlay.DeviceQueueEntry,
  370. srb->QueueSortKey
  371. );
  372. if (!queued) {
  373. DEBUGPRINT2((
  374. "Sbp2Port: StartIo: dev q not busy, defer irp=x%p\n",
  375. Irp
  376. ));
  377. ASSERT(deviceExtension->PowerDeferredIrp == NULL);
  378. KeAcquireSpinLockAtDpcLevel(
  379. &deviceExtension->ExtensionDataSpinLock
  380. );
  381. deviceExtension->PowerDeferredIrp = Irp;
  382. KeReleaseSpinLockFromDpcLevel(
  383. &deviceExtension->ExtensionDataSpinLock
  384. );
  385. }
  386. //
  387. // We need to send our own stack a d0 irp, so the device
  388. // powers up and can process this request.
  389. // Block until the Start_STOP_UNIT to start, is called.
  390. // This has to happen in two steps:
  391. // 1: Send D Irp to stack, which might power up the controller
  392. // 2: Wait for completion of START UNIT send by class driver,
  393. // if success start processing requests...
  394. //
  395. DEBUGPRINT2((
  396. "Sbp2Port: StartIo: dev powered down, q(%x) irp=x%p " \
  397. "til power up\n",
  398. queued,
  399. Irp
  400. ));
  401. state.DeviceState = PowerDeviceD0;
  402. DEBUGPRINT1((
  403. "Sbp2Port: StartIo: sending D irp for state %x\n",
  404. state
  405. ));
  406. status = PoRequestPowerIrp(
  407. deviceExtension->DeviceObject,
  408. IRP_MN_SET_POWER,
  409. state,
  410. NULL,
  411. NULL,
  412. NULL);
  413. if (!NT_SUCCESS(status)) {
  414. //
  415. // not good, we cant power up the device..
  416. //
  417. DEBUGPRINT1(("Sbp2Port: StartIo: D irp err=x%x\n", status));
  418. if (!queued) {
  419. KeAcquireSpinLockAtDpcLevel(
  420. &deviceExtension->ExtensionDataSpinLock
  421. );
  422. if (deviceExtension->PowerDeferredIrp == Irp) {
  423. deviceExtension->PowerDeferredIrp = NULL;
  424. } else {
  425. Irp = NULL;
  426. }
  427. KeReleaseSpinLockFromDpcLevel(
  428. &deviceExtension->ExtensionDataSpinLock
  429. );
  430. } else {
  431. //
  432. // If the irp is still in the device queue then remove it.
  433. // Don't worry about the queue's busy flag - if irp found
  434. // then queue gets restarted by StartNextPacket below,
  435. // else another thread processed the irp, thereby
  436. // restarting the queue.
  437. //
  438. PIRP qIrp = NULL;
  439. PLIST_ENTRY entry;
  440. PKDEVICE_QUEUE queue = &DeviceObject->DeviceQueue;
  441. KeAcquireSpinLockAtDpcLevel (&queue->Lock);
  442. for(
  443. entry = queue->DeviceListHead.Flink;
  444. entry != &queue->DeviceListHead;
  445. entry = entry->Flink
  446. ) {
  447. qIrp = CONTAINING_RECORD(
  448. entry,
  449. IRP,
  450. Tail.Overlay.DeviceQueueEntry.DeviceListEntry
  451. );
  452. if (qIrp == Irp) {
  453. RemoveEntryList (entry);
  454. break;
  455. }
  456. }
  457. KeReleaseSpinLockFromDpcLevel (&queue->Lock);
  458. if (qIrp != Irp) {
  459. Irp = NULL;
  460. }
  461. }
  462. if (Irp) {
  463. srb->SrbStatus = SRB_STATUS_ERROR;
  464. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  465. IoCompleteRequest (Irp,IO_NO_INCREMENT);
  466. Sbp2StartNextPacketByKey (DeviceObject, 0);
  467. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  468. } else {
  469. //
  470. // Another thread processed this irp, it will take
  471. // care of the cleanup
  472. //
  473. DEBUGPRINT1(("Sbp2Port: StartIo: ... irp NOT FOUND!\n"));
  474. }
  475. }
  476. return;
  477. }
  478. //
  479. // case 2: Reset in progress (either reconnect or login in progress)
  480. //
  481. // Queue request until we are done. When reset over, start
  482. // processing again.
  483. //
  484. if (TEST_FLAG(
  485. deviceExtension->DeviceFlags,
  486. DEVICE_FLAG_RESET_IN_PROGRESS
  487. )) {
  488. //
  489. // Queue request (twice, in case queue wasn't busy the 1st time).
  490. // We acquire the spinlock to prevent the case where we try to
  491. // insert to a non-busy queue, then a 2nd thread completing
  492. // the reset calls StartNextPacket (which would reset the q busy
  493. // flag), then we try to insert again and fail - the result
  494. // being deadlock since no one will restart the queue.
  495. //
  496. KeAcquireSpinLockAtDpcLevel(
  497. &deviceExtension->ExtensionDataSpinLock
  498. );
  499. if (TEST_FLAG(
  500. deviceExtension->DeviceFlags,
  501. DEVICE_FLAG_RESET_IN_PROGRESS
  502. )) {
  503. if (Sbp2InsertByKeyDeviceQueue(
  504. &DeviceObject->DeviceQueue,
  505. &Irp->Tail.Overlay.DeviceQueueEntry,
  506. srb->QueueSortKey
  507. ) ||
  508. Sbp2InsertByKeyDeviceQueue(
  509. &DeviceObject->DeviceQueue,
  510. &Irp->Tail.Overlay.DeviceQueueEntry,
  511. srb->QueueSortKey
  512. )) {
  513. KeReleaseSpinLockFromDpcLevel(
  514. &deviceExtension->ExtensionDataSpinLock
  515. );
  516. DEBUGPRINT2((
  517. "Sbp2Port: StartIo: ext=x%p resetting, q irp=x%p\n",
  518. deviceExtension,
  519. Irp
  520. ));
  521. return;
  522. }
  523. KeReleaseSpinLockFromDpcLevel(
  524. &deviceExtension->ExtensionDataSpinLock
  525. );
  526. DEBUGPRINT1((
  527. "Sbp2Port: StartIo: ext=x%p 2xQ err, fail irp=x%p\n",
  528. deviceExtension,
  529. Irp
  530. ));
  531. ASSERT (FALSE); // should never get here
  532. srb->SrbStatus = SRB_STATUS_BUSY;
  533. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  534. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  535. IoCompleteRequest(Irp,IO_NO_INCREMENT);
  536. return;
  537. }
  538. KeReleaseSpinLockFromDpcLevel(
  539. &deviceExtension->ExtensionDataSpinLock
  540. );
  541. }
  542. //
  543. // CASE 3: System is powered down, and so is device (better be).
  544. // Queue all requests until system comes up from sleep
  545. //
  546. if ((deviceExtension->DevicePowerState != PowerDeviceD0) &&
  547. (deviceExtension->SystemPowerState != PowerSystemWorking)) {
  548. //
  549. // our device is powered down AND the system is powered down.
  550. // just queue this request...
  551. //
  552. if (!Sbp2InsertByKeyDeviceQueue(
  553. &DeviceObject->DeviceQueue,
  554. &Irp->Tail.Overlay.DeviceQueueEntry,
  555. srb->QueueSortKey)) {
  556. ASSERT(deviceExtension->PowerDeferredIrp == NULL);
  557. KeAcquireSpinLockAtDpcLevel(
  558. &deviceExtension->ExtensionDataSpinLock
  559. );
  560. deviceExtension->PowerDeferredIrp = Irp;
  561. KeReleaseSpinLockFromDpcLevel(
  562. &deviceExtension->ExtensionDataSpinLock
  563. );
  564. DEBUGPRINT2((
  565. "Sbp2Port: StartIo: powered down, defer irp=x%p\n",
  566. Irp
  567. ));
  568. } else {
  569. DEBUGPRINT2((
  570. "Sbp2Port: StartIo: powered down, q irp=%p\n",
  571. Irp
  572. ));
  573. }
  574. return;
  575. }
  576. }
  577. if (!TEST_FLAG (srb->SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE)) {
  578. if (deviceExtension->IdleCounter) {
  579. PoSetDeviceBusy (deviceExtension->IdleCounter);
  580. }
  581. }
  582. //
  583. // create a context ,a CMD orb and the appropriate data descriptor
  584. //
  585. Create1394TransactionForSrb (deviceExtension, srb, &context);
  586. return;
  587. }
  588. VOID
  589. Create1394TransactionForSrb(
  590. IN PDEVICE_EXTENSION DeviceExtension,
  591. IN PSCSI_REQUEST_BLOCK Srb,
  592. IN OUT PASYNC_REQUEST_CONTEXT *RequestContext
  593. )
  594. /*++
  595. Routine Description:
  596. Always called at DPC level...
  597. This routine is responsible for allocating all the data structures and
  598. getting all the 1394 addresses required for incoming scsi requests.
  599. It will fill in Command ORBs, create page table if necessery, and
  600. most importantly setup a request Context, so when the status callback
  601. is called, we can find the srb Associated with completed ORB. Since we
  602. have a FreeList, this request will always use pre-allocated contexts
  603. and page tables, so we dont have to do it dynamically...
  604. Arguments:
  605. DeviceObject - Our device object
  606. Srb - SRB from class drivers,
  607. RequestContext - Pointer To Context used for this request.
  608. Mdl - MDL with data buffer for this request
  609. Return Value:
  610. --*/
  611. {
  612. NTSTATUS status= STATUS_SUCCESS;
  613. PMDL requestMdl;
  614. PASYNC_REQUEST_CONTEXT callbackContext;
  615. PVOID mdlVa;
  616. //
  617. // Allocate a context for this requestfrom our freeList
  618. //
  619. callbackContext = (PASYNC_REQUEST_CONTEXT) ExInterlockedPopEntrySList(
  620. &DeviceExtension->FreeContextListHead,
  621. &DeviceExtension->FreeContextLock
  622. );
  623. if (callbackContext) {
  624. callbackContext = RETRIEVE_CONTEXT(callbackContext,LookasideList);
  625. } else {
  626. DEBUGPRINT1((
  627. "Sbp2Port: Create1394XactForSrb: ERROR! ext=x%p, no ctx's\n",
  628. DeviceExtension
  629. ));
  630. status = STATUS_INSUFFICIENT_RESOURCES;
  631. Srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  632. Srb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
  633. Sbp2CreateRequestErrorLog(DeviceExtension->DeviceObject,NULL,status);
  634. goto exitCreate1394ReqForSrb;
  635. }
  636. //
  637. // Acquire the OrbListSpinLock to serialize this OrbListDepth
  638. // change & save with those done in Sbp2GlobalStatusCallback
  639. // (when freeing async requests), to insure we won't make too
  640. // many or too few calls to StartNextPacket
  641. //
  642. KeAcquireSpinLockAtDpcLevel (&DeviceExtension->OrbListSpinLock);
  643. callbackContext->OrbListDepth = InterlockedIncrement(
  644. &DeviceExtension->OrbListDepth
  645. );
  646. KeReleaseSpinLockFromDpcLevel (&DeviceExtension->OrbListSpinLock);
  647. *RequestContext = callbackContext;
  648. //
  649. // Initialize srb-related entries in our context
  650. //
  651. callbackContext->OriginalSrb = NULL;
  652. callbackContext->DataMappingHandle = NULL;
  653. callbackContext->Packet = NULL;
  654. callbackContext->Tag = SBP2_ASYNC_CONTEXT_TAG;
  655. callbackContext->Srb = Srb;
  656. callbackContext->DeviceObject = DeviceExtension->DeviceObject;
  657. callbackContext->Flags = 0;
  658. //
  659. // filter commands so they conform to RBC..
  660. //
  661. status = Sbp2_SCSI_RBC_Conversion(callbackContext);
  662. if (status != STATUS_PENDING){
  663. //
  664. // the call was handled immediately. Complete the irp here...
  665. //
  666. callbackContext->Srb = NULL;
  667. FreeAsyncRequestContext(DeviceExtension,callbackContext);
  668. if (NT_SUCCESS(status)) {
  669. Srb->SrbStatus = SRB_STATUS_SUCCESS;
  670. ((PIRP) Srb->OriginalRequest)->IoStatus.Information = Srb->DataTransferLength;
  671. } else {
  672. DEBUGPRINT1((
  673. "Sbp2Port: Create1394XactForSrb: RBC translation failed!!!\n"
  674. ));
  675. //
  676. // since translation errors are always internal errors,
  677. // set SRB_STATUS to reflect an internal (not device) error
  678. //
  679. Srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  680. Srb->InternalStatus = status;
  681. ((PIRP)Srb->OriginalRequest)->IoStatus.Information = 0;
  682. }
  683. ((PIRP)Srb->OriginalRequest)->IoStatus.Status = status;
  684. IoCompleteRequest (((PIRP) Srb->OriginalRequest), IO_NO_INCREMENT);
  685. Sbp2StartNextPacketByKey(
  686. DeviceExtension->DeviceObject,
  687. DeviceExtension->CurrentKey
  688. );
  689. IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
  690. return;
  691. }
  692. status = STATUS_SUCCESS;
  693. //
  694. // Figure the maximum number of different 1394 addresses we need to span this request's data buffer
  695. //
  696. if ((Srb->DataTransferLength == 0) || TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_DATA_TRANSFER)) {
  697. //
  698. // No need to get a 1394 address for data, since there is none
  699. //
  700. Sbp2InitializeOrb (DeviceExtension, callbackContext);
  701. } else {
  702. //
  703. // if this request is apart of split request, we need to make our own mdl...
  704. //
  705. requestMdl = ((PIRP) Srb->OriginalRequest)->MdlAddress;
  706. mdlVa = MmGetMdlVirtualAddress (requestMdl);
  707. if (mdlVa != (PVOID) Srb->DataBuffer) {
  708. //
  709. // split request
  710. //
  711. callbackContext->PartialMdl = IoAllocateMdl(Srb->DataBuffer,Srb->DataTransferLength,FALSE,FALSE,NULL);
  712. if (!callbackContext->PartialMdl) {
  713. status = STATUS_INSUFFICIENT_RESOURCES;
  714. Srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  715. Srb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
  716. DEBUGPRINT1((
  717. "Sbp2Port: Create1394XactForSrb: REQ_ALLOC addr err!\n"
  718. ));
  719. goto exitCreate1394ReqForSrb;
  720. }
  721. IoBuildPartialMdl(requestMdl,callbackContext->PartialMdl,Srb->DataBuffer, Srb->DataTransferLength );
  722. requestMdl = callbackContext->PartialMdl;
  723. DEBUGPRINT4(("Sbp2Port: Create1394TransactionForSrb: Allocating Partial Mdl %p\n",requestMdl));
  724. } else {
  725. callbackContext->PartialMdl = NULL;
  726. }
  727. callbackContext->RequestMdl = requestMdl;
  728. //
  729. // according to what the port driver can handle, map the data buffer to 1394 addresses and create
  730. // an sbp2 page table if necessery
  731. //
  732. status = Sbp2BusMapTransfer(DeviceExtension,callbackContext);
  733. //
  734. // NOTE: On success, above returns STATUS_PENDING
  735. // all errors are internal errors.
  736. //
  737. if (!NT_SUCCESS(status)) {
  738. DEBUGPRINT1(("\n Sbp2Create1394TransactionForSrb failed %x\n",status));
  739. if (callbackContext->PartialMdl) {
  740. IoFreeMdl(callbackContext->PartialMdl);
  741. callbackContext->PartialMdl = NULL;
  742. }
  743. }
  744. }
  745. exitCreate1394ReqForSrb:
  746. if (status == STATUS_PENDING) {
  747. //
  748. // Sbp2StartNextPacketByKey will be called when the
  749. // notification alloc callback is called
  750. //
  751. return;
  752. } else if (status == STATUS_SUCCESS) { // ISSUE-geogioc-2000/02/20 - NT_SUCCESS(status) should be used
  753. //
  754. // SUCCESS, place
  755. //
  756. Sbp2InsertTailList(DeviceExtension,callbackContext);
  757. return;
  758. } else {
  759. //
  760. // since the request could not have actually been processed by
  761. // the device, this is an internal error and should be propogated
  762. // up the stack as such.
  763. //
  764. if (callbackContext) {
  765. callbackContext->Srb = NULL;
  766. FreeAsyncRequestContext(DeviceExtension,callbackContext);
  767. }
  768. Srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  769. Srb->InternalStatus = status;
  770. ((PIRP)Srb->OriginalRequest)->IoStatus.Status = status;
  771. ((PIRP)Srb->OriginalRequest)->IoStatus.Information = 0;
  772. IoCompleteRequest(((PIRP)Srb->OriginalRequest),IO_NO_INCREMENT);
  773. Sbp2StartNextPacketByKey (DeviceExtension->DeviceObject, 0);
  774. IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
  775. return;
  776. }
  777. return;
  778. }
  779. NTSTATUS
  780. Sbp2_SCSI_RBC_Conversion(
  781. IN PASYNC_REQUEST_CONTEXT Context
  782. )
  783. /*++
  784. Routine Description:
  785. Always called at DPC level...
  786. It translates scsi commands to their RBC equivalents, ONLY if they differ in each spec
  787. The translation is done before request is issued and in some cases, after the request is
  788. completed
  789. Arguments:
  790. DeviceExtension - Sbp2 extension
  791. RequestContext - Pointer To Context used for this request.
  792. Return Value:
  793. --*/
  794. {
  795. PCDB cdb;
  796. if (TEST_FLAG(Context->Flags, ASYNC_CONTEXT_FLAG_COMPLETED)) {
  797. //
  798. // completed request translation
  799. //
  800. if ( ((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->InquiryData.DeviceType == \
  801. RBC_DEVICE){
  802. return Rbc_Scsi_Conversion(Context->Srb,
  803. &(PSCSI_REQUEST_BLOCK)Context->OriginalSrb,
  804. &((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->DeviceModeHeaderAndPage,
  805. FALSE,
  806. ((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->InquiryData.RemovableMedia
  807. );
  808. }
  809. } else {
  810. //
  811. // outgoing request translation
  812. //
  813. if (((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->InquiryData.DeviceType == \
  814. RBC_DEVICE){
  815. return Rbc_Scsi_Conversion(Context->Srb,
  816. &(PSCSI_REQUEST_BLOCK)Context->OriginalSrb,
  817. &((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->DeviceModeHeaderAndPage,
  818. TRUE,
  819. ((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->InquiryData.RemovableMedia
  820. );
  821. } else if (((PDEVICE_EXTENSION)Context->DeviceObject->DeviceExtension)->InquiryData.DeviceType == \
  822. READ_ONLY_DIRECT_ACCESS_DEVICE){
  823. switch (Context->Srb->Cdb[0]) {
  824. case SCSIOP_MODE_SENSE10:
  825. //
  826. // mmc2 type of device..
  827. //
  828. cdb = (PCDB) &Context->Srb->Cdb[0];
  829. cdb->MODE_SENSE10.Dbd = 1;
  830. break;
  831. }
  832. }
  833. }
  834. return STATUS_PENDING;
  835. }
  836. NTSTATUS
  837. Sbp2BusMapTransfer(
  838. PDEVICE_EXTENSION DeviceExtension,
  839. PASYNC_REQUEST_CONTEXT CallbackContext
  840. )
  841. /*++
  842. Routine Description:
  843. Always called at DPC level...
  844. It calls the port driver to map the data buffer to physical/1394 addresses
  845. Arguments:
  846. DeviceExtension - Sbp2 extension
  847. RequestContext - Pointer To Context used for this request.
  848. Mdl - MDL with data buffer for this request
  849. Return Value:
  850. --*/
  851. {
  852. NTSTATUS status;
  853. #if DBG
  854. ULONG maxNumberOfPages;
  855. maxNumberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  856. CallbackContext->Srb->DataBuffer,
  857. CallbackContext->Srb->DataTransferLength
  858. );
  859. ASSERT (CallbackContext->PageTableContext.PageTable != NULL);
  860. ASSERT (maxNumberOfPages <= SBP2_NUM_PAGE_TABLE_ENTRIES);
  861. #endif
  862. //
  863. // Do the DATA alloc.
  864. //
  865. SET_FLAG(CallbackContext->Flags, ASYNC_CONTEXT_FLAG_PAGE_ALLOC);
  866. CallbackContext->Packet = NULL;
  867. Sbp2AllocComplete (CallbackContext);
  868. DEBUGPRINT4((
  869. "Sbp2Port: Sbp2MapAddress: alloc done, ctx=x%p, dataHandle=x%p\n",
  870. CallbackContext,
  871. CallbackContext->DataMappingHandle
  872. ));
  873. if (TEST_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC_FAILED)) {
  874. CLEAR_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC);
  875. CLEAR_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC_FAILED);
  876. DEBUGPRINT1((
  877. "Sbp2Port: Sbp2MapAddress: (page table present) REQ_ALLOC data " \
  878. "err, ctx=x%p\n",
  879. CallbackContext
  880. ));
  881. return STATUS_INSUFFICIENT_RESOURCES;
  882. }
  883. return STATUS_PENDING;
  884. }
  885. VOID
  886. Sbp2AllocComplete(
  887. IN PASYNC_REQUEST_CONTEXT CallbackContext
  888. )
  889. {
  890. PDEVICE_EXTENSION deviceExtension = CallbackContext->DeviceObject->DeviceExtension;
  891. PIRBIRP packet = CallbackContext->Packet;
  892. PPORT_PHYS_ADDR_ROUTINE routine = deviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
  893. PSCSI_REQUEST_BLOCK srb;
  894. NTSTATUS status;
  895. BOOLEAN bDirectCall = FALSE;
  896. DEBUGPRINT4(("Sbp2AllocateComplete: ctx=x%p, flags=x%x\n",CallbackContext,CallbackContext->Flags));
  897. //
  898. // this same function is used for the alloc complete notification of a pagetable
  899. // AND of the actuall data tranfser. So we have to check which case this is
  900. // This is a simple state machine with two states:
  901. // startIo-> A: PAGE TABLE ALLOC -> B
  902. // B: DATA ALLOC ->exit
  903. //
  904. if (TEST_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_PAGE_ALLOC)) {
  905. CLEAR_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_PAGE_ALLOC);
  906. if (CallbackContext->Packet) {
  907. //
  908. // we have just received the page table alloc...
  909. //
  910. ASSERT (FALSE); // should never get here any more
  911. } else {
  912. //
  913. // We were called directly since a sufficient page table was
  914. // already in the context
  915. //
  916. AllocateIrpAndIrb (deviceExtension,&packet);
  917. if (!packet) {
  918. return;
  919. }
  920. CallbackContext->Packet = packet;
  921. bDirectCall = TRUE;
  922. }
  923. //
  924. // indicate that now we are in the DATA transfer alloc case
  925. //
  926. SET_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC);
  927. //
  928. // reuse the same irb/irp
  929. // prepare the irb for calling the 1394 bus/port driver synchronously
  930. //
  931. packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
  932. //
  933. // we only want a call back when we get a status from the target
  934. // Now allocate 1394 addresses for the data buffer with no notification
  935. //
  936. packet->Irb->u.AllocateAddressRange.nLength = CallbackContext->Srb->DataTransferLength;
  937. packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_NEVER;
  938. if (TEST_FLAG(CallbackContext->Srb->SrbFlags,SRB_FLAGS_DATA_IN)) {
  939. packet->Irb->u.AllocateAddressRange.fulAccessType = ACCESS_FLAGS_TYPE_WRITE;
  940. } else {
  941. packet->Irb->u.AllocateAddressRange.fulAccessType = ACCESS_FLAGS_TYPE_READ;
  942. }
  943. packet->Irb->u.AllocateAddressRange.fulFlags = ALLOCATE_ADDRESS_FLAGS_USE_BIG_ENDIAN;
  944. //
  945. // the callback for physical address is used to notify that the async allocate request
  946. // is now complete..
  947. //
  948. packet->Irb->u.AllocateAddressRange.Callback= Sbp2AllocComplete;
  949. packet->Irb->u.AllocateAddressRange.Context= CallbackContext;
  950. packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
  951. packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
  952. packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
  953. packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
  954. packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
  955. packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
  956. packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE) &(CallbackContext->PageTableContext.PageTable[0]);
  957. packet->Irb->u.AllocateAddressRange.Mdl = CallbackContext->RequestMdl; //MDL from original request
  958. packet->Irb->u.AllocateAddressRange.MaxSegmentSize = (SBP2_MAX_DIRECT_BUFFER_SIZE+1)/2;
  959. CallbackContext->Packet = packet;
  960. //
  961. // Send allocateRange request to bus driver , indicating that we dont want the irp to be freed
  962. // If the port driver supports a direct mapping routine, call that instead
  963. //
  964. status = (*routine) (deviceExtension->HostRoutineAPI.Context,packet->Irb);
  965. if (status == STATUS_SUCCESS) {
  966. return;
  967. } else {
  968. DEBUGPRINT1(("Sbp2Port: Sbp2AllocComplete: REQUEST_ALLOCATE Address failed, ctx=x%p, direct=%x!!\n",CallbackContext,bDirectCall));
  969. DeAllocateIrpAndIrb(deviceExtension,packet);
  970. CallbackContext->Packet = NULL;
  971. CallbackContext->DataMappingHandle = NULL;
  972. SET_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC_FAILED);
  973. if (bDirectCall) {
  974. return;
  975. } else {
  976. //
  977. // we were indirectly called, so the irp has already been marked pending..
  978. // we must abort it here and complete the context with error...
  979. //
  980. srb = CallbackContext->Srb;
  981. CallbackContext->Srb = NULL;
  982. FreeAsyncRequestContext(deviceExtension,CallbackContext);
  983. srb->SrbStatus = SRB_STATUS_ERROR;
  984. ((PIRP)srb->OriginalRequest)->IoStatus.Status = status;
  985. ((PIRP)srb->OriginalRequest)->IoStatus.Information = 0;
  986. IoCompleteRequest(((PIRP)srb->OriginalRequest),IO_NO_INCREMENT);
  987. Sbp2StartNextPacketByKey (deviceExtension->DeviceObject, 0);
  988. IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
  989. return;
  990. }
  991. }
  992. }
  993. if (TEST_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC)) {
  994. //
  995. // we have a page table so this means we just been notified that the DATA alloc is over
  996. // Save the handle to the data descriptor's memory range
  997. //
  998. CLEAR_FLAG(CallbackContext->Flags,ASYNC_CONTEXT_FLAG_DATA_ALLOC);
  999. CallbackContext->DataMappingHandle = CallbackContext->Packet->Irb->u.AllocateAddressRange.hAddressRange;
  1000. //
  1001. // number of page table elements required
  1002. //
  1003. CallbackContext->PageTableContext.NumberOfPages = CallbackContext->Packet->Irb->u.AllocateAddressRange.AddressesReturned;
  1004. DeAllocateIrpAndIrb(deviceExtension,CallbackContext->Packet);
  1005. CallbackContext->Packet = NULL;
  1006. Sbp2InitializeOrb(deviceExtension,CallbackContext);
  1007. Sbp2InsertTailList(deviceExtension,CallbackContext);
  1008. }
  1009. return;
  1010. }
  1011. VOID
  1012. Sbp2InitializeOrb(
  1013. IN PDEVICE_EXTENSION DeviceExtension,
  1014. PASYNC_REQUEST_CONTEXT CallbackContext
  1015. )
  1016. {
  1017. ULONG i, size;
  1018. //
  1019. // zero the ORB CDB and ORB Flags fields
  1020. //
  1021. CallbackContext->CmdOrb->OrbInfo.QuadPart = 0;
  1022. if (!CallbackContext->DataMappingHandle) {
  1023. CallbackContext->PageTableContext.NumberOfPages = 0;
  1024. CallbackContext->CmdOrb->DataDescriptor.OctletPart = 0xFFFFFFFFFFFFFFFF;
  1025. } else {
  1026. if (CallbackContext->PageTableContext.NumberOfPages > 1) {
  1027. CallbackContext->CmdOrb->DataDescriptor.BusAddress = \
  1028. CallbackContext->PageTableContext.AddressContext.Address.BusAddress;
  1029. octbswap(CallbackContext->CmdOrb->DataDescriptor);
  1030. //
  1031. // If the host does not convert the table to big endian (or
  1032. // there's an associated scatter gather list), do it here
  1033. //
  1034. if ((DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine == NULL)
  1035. || (CallbackContext->RequestMdl == NULL)) {
  1036. for (i=0;i<CallbackContext->PageTableContext.NumberOfPages;i++) {
  1037. octbswap(CallbackContext->PageTableContext.PageTable[i]); // convert to big endian
  1038. }
  1039. }
  1040. //
  1041. // setup the cmd orb for a page table
  1042. //
  1043. CallbackContext->CmdOrb->OrbInfo.u.HighPart |= ORB_PAGE_TABLE_BIT_MASK;
  1044. //
  1045. // we define a data size equal (since we are in page table mode)
  1046. // to number of pages. The page table has already been allocated .
  1047. //
  1048. CallbackContext->CmdOrb->OrbInfo.u.LowPart = (USHORT) CallbackContext->PageTableContext.NumberOfPages;
  1049. } else {
  1050. CallbackContext->CmdOrb->DataDescriptor = CallbackContext->PageTableContext.PageTable[0];
  1051. //
  1052. // If the host does not convert the table to big endian (or
  1053. // there's an associated scatter gather list), do it here
  1054. //
  1055. if ((DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine == NULL)
  1056. || (CallbackContext->RequestMdl == NULL)) {
  1057. CallbackContext->CmdOrb->DataDescriptor.BusAddress.NodeId = DeviceExtension->InitiatorAddressId;
  1058. octbswap(CallbackContext->CmdOrb->DataDescriptor);
  1059. } else {
  1060. //
  1061. // address already in big endian, just put the NodeID in the proper place
  1062. //
  1063. CallbackContext->CmdOrb->DataDescriptor.ByteArray.Byte0 = *((PUCHAR)&DeviceExtension->InitiatorAddressId+1);
  1064. CallbackContext->CmdOrb->DataDescriptor.ByteArray.Byte1 = *((PUCHAR)&DeviceExtension->InitiatorAddressId);
  1065. }
  1066. //
  1067. // Data size of buffer data descriptor points to
  1068. //
  1069. CallbackContext->CmdOrb->OrbInfo.u.LowPart = (USHORT) CallbackContext->Srb->DataTransferLength;
  1070. }
  1071. }
  1072. //
  1073. // Start building the ORB used to carry this srb
  1074. // By default notify bit, rq_fmt field and page_size field are all zero..
  1075. // Also the nextOrbAddress is NULL ( which is 0xFFFF..F)
  1076. //
  1077. CallbackContext->CmdOrb->NextOrbAddress.OctletPart = 0xFFFFFFFFFFFFFFFF;
  1078. //
  1079. // Max speed supported
  1080. //
  1081. CallbackContext->CmdOrb->OrbInfo.u.HighPart |= (0x0700 & ((DeviceExtension->MaxControllerPhySpeed) << 8));
  1082. //
  1083. // set notify bit for this command ORB
  1084. //
  1085. CallbackContext->CmdOrb->OrbInfo.u.HighPart |= ORB_NOTIFY_BIT_MASK;
  1086. if (TEST_FLAG(CallbackContext->Srb->SrbFlags,SRB_FLAGS_DATA_IN)) {
  1087. //
  1088. // Read request. Set direction bit to 1
  1089. //
  1090. CallbackContext->CmdOrb->OrbInfo.u.HighPart |= ORB_DIRECTION_BIT_MASK;
  1091. // Max payload size, (its entered in the orb, in the form of 2^(size+2)
  1092. CallbackContext->CmdOrb->OrbInfo.u.HighPart |= DeviceExtension->OrbReadPayloadMask ;
  1093. } else {
  1094. //
  1095. // Write request, direction bit is zero
  1096. //
  1097. CallbackContext->CmdOrb->OrbInfo.u.HighPart &= ~ORB_DIRECTION_BIT_MASK;
  1098. CallbackContext->CmdOrb->OrbInfo.u.HighPart |= DeviceExtension->OrbWritePayloadMask ;
  1099. }
  1100. //
  1101. // Now copy the CDB from the SRB to our ORB
  1102. //
  1103. ASSERT (CallbackContext->Srb->CdbLength >= 6);
  1104. ASSERT (CallbackContext->Srb->CdbLength <= SBP2_MAX_CDB_SIZE);
  1105. size = min (SBP2_MAX_CDB_SIZE, CallbackContext->Srb->CdbLength);
  1106. RtlZeroMemory(&CallbackContext->CmdOrb->Cdb, SBP2_MAX_CDB_SIZE);
  1107. RtlCopyMemory(&CallbackContext->CmdOrb->Cdb, CallbackContext->Srb->Cdb,size);
  1108. //
  1109. // we are done here.... convert command ORB to Big Endian...
  1110. //
  1111. CallbackContext->CmdOrb->OrbInfo.QuadPart = bswap(CallbackContext->CmdOrb->OrbInfo.QuadPart);
  1112. }
  1113. VOID
  1114. Sbp2InsertTailList(
  1115. IN PDEVICE_EXTENSION DeviceExtension,
  1116. IN PASYNC_REQUEST_CONTEXT Context
  1117. )
  1118. {
  1119. ULONG orbListDepth, timeOutValue;
  1120. OCTLET newAddr ;
  1121. NTSTATUS status;
  1122. PASYNC_REQUEST_CONTEXT prevCtx;
  1123. orbListDepth = Context->OrbListDepth;
  1124. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->OrbListSpinLock);
  1125. DeviceExtension->CurrentKey = Context->Srb->QueueSortKey+1;
  1126. if (IsListEmpty (&DeviceExtension->PendingOrbList)) {
  1127. //
  1128. // Empty list, this is the first request
  1129. // This ORB is now at end-of-list, its next_ORB address is set to NULL
  1130. //
  1131. Context->CmdOrb->NextOrbAddress.OctletPart = 0xFFFFFFFFFFFFFFFF;
  1132. //
  1133. // start the timer tracking this request
  1134. // If the list is non empty, only the head of the list is timed...
  1135. //
  1136. timeOutValue = Context->Srb->TimeOutValue;
  1137. DeviceExtension->DueTime.QuadPart =
  1138. ((LONGLONG) timeOutValue) * (-10*1000*1000);
  1139. SET_FLAG(Context->Flags, ASYNC_CONTEXT_FLAG_TIMER_STARTED);
  1140. KeSetTimer(
  1141. &Context->Timer,
  1142. DeviceExtension->DueTime,
  1143. &Context->TimerDpc
  1144. );
  1145. InsertTailList (&DeviceExtension->PendingOrbList,&Context->OrbList);
  1146. newAddr = Context->CmdOrbAddress;
  1147. //
  1148. // ISSUE: Seems like we should always be able to write to the
  1149. // dev's orb pointer at this point, but we were seeing
  1150. // timeouts on some devices if we did that (notably
  1151. // hd's with Oxford Semiconductor silicon doing dv cam
  1152. // captures), so am sticking with the piggyback logic
  1153. // for WinXP. This is a perf hit, because dev has to
  1154. // read in the old orb to get the next orb addr, then
  1155. // fetch the new orb. DanKn 25-Jun-2001
  1156. //
  1157. if (DeviceExtension->NextContextToFree &&
  1158. DeviceExtension->AppendToNextContextToFree) {
  1159. DeviceExtension->AppendToNextContextToFree = FALSE;
  1160. //
  1161. // There is an end-of-list ORB, just piggy back on it
  1162. //
  1163. octbswap (newAddr);
  1164. DeviceExtension->NextContextToFree->CmdOrb->NextOrbAddress =
  1165. newAddr;
  1166. DeviceExtension->NextContextToFree->CmdOrb->NextOrbAddress.
  1167. ByteArray.Byte0 = 0; // make Null bit zero
  1168. DeviceExtension->NextContextToFree->CmdOrb->NextOrbAddress.
  1169. ByteArray.Byte1 = 0; // make Null bit zero
  1170. //
  1171. // The guy that was the end of the list cannot be freed
  1172. // until this ORB is fetched
  1173. //
  1174. KeReleaseSpinLockFromDpcLevel (&DeviceExtension->OrbListSpinLock);
  1175. DEBUGPRINT3((
  1176. "Sbp2Port: InsertTailList: empty, ring bell, ctx=x%p\n",
  1177. Context
  1178. ));
  1179. status = Sbp2AccessRegister(
  1180. DeviceExtension,
  1181. &DeviceExtension->Reserved,
  1182. DOORBELL_REG | REG_WRITE_ASYNC
  1183. );
  1184. } else {
  1185. //
  1186. // list is empty, write directly to orb_pointer
  1187. //
  1188. KeReleaseSpinLockFromDpcLevel (&DeviceExtension->OrbListSpinLock);
  1189. DEBUGPRINT3((
  1190. "Sbp2Port: InsertTailList: write ORB_PTR, ctx=x%p\n",
  1191. Context
  1192. ));
  1193. status = Sbp2AccessRegister(
  1194. DeviceExtension,
  1195. &newAddr,
  1196. ORB_POINTER_REG | REG_WRITE_ASYNC
  1197. );
  1198. }
  1199. //
  1200. // The following handles the case where a device is removed
  1201. // while machine is on standby, and then machine is resumed.
  1202. // In the storage case, classpnp.sys sends down a start unit
  1203. // srb (in reponse to the power D-irp) with a timeout of
  1204. // 240 seconds. The problem is that sbp2port.sys does not get
  1205. // notified of the remove until *after* the start unit has
  1206. // timed out (the power irp blocks the pnp irp), and the user
  1207. // gets a bad 240-second wait experience.
  1208. //
  1209. // So what we do here in the case of an invalid generation error
  1210. // & a lengthy timeout is to reset the timer with a more reasonable
  1211. // timeout value. If the device is still around the bus reset
  1212. // notification routine should get called & clean everything up
  1213. // anyway, and same goes for normal remove (while machine is not
  1214. // hibernated).
  1215. //
  1216. if (status == STATUS_INVALID_GENERATION) {
  1217. KeAcquireSpinLockAtDpcLevel (&DeviceExtension->OrbListSpinLock);
  1218. if ((DeviceExtension->PendingOrbList.Flink == &Context->OrbList) &&
  1219. (timeOutValue > 5)) {
  1220. KeCancelTimer (&Context->Timer);
  1221. DeviceExtension->DueTime.QuadPart = (-5 * 10 * 1000 * 1000);
  1222. KeSetTimer(
  1223. &Context->Timer,
  1224. DeviceExtension->DueTime,
  1225. &Context->TimerDpc
  1226. );
  1227. #if DBG
  1228. timeOutValue = 1;
  1229. } else {
  1230. timeOutValue = 0;
  1231. #endif
  1232. }
  1233. KeReleaseSpinLockFromDpcLevel (&DeviceExtension->OrbListSpinLock);
  1234. if (timeOutValue) {
  1235. DEBUGPRINT1((
  1236. "Sbp2port: InsertTailList: ext=x%p, lowered req timeout\n",
  1237. DeviceExtension
  1238. ));
  1239. }
  1240. }
  1241. } else {
  1242. //
  1243. // We have already a list in memory. Append this request to list,
  1244. // modify last request's ORB to point to this ORB.
  1245. //
  1246. newAddr = Context->CmdOrbAddress;
  1247. //
  1248. // Init the list pointer for this request context
  1249. //
  1250. Context->CmdOrb->NextOrbAddress.OctletPart = 0xFFFFFFFFFFFFFFFF;
  1251. //
  1252. // Modify the previous request's command ORB next_ORB address,
  1253. // to point to this ORB. Convert our address to BigEndian first,
  1254. // since the prev command ORB is stored in BigEndian.
  1255. //
  1256. // Note that the previous end-of-list orb may be the completed
  1257. // one pointed at by NextContextToFree (rather the last one in
  1258. // the PendingOrbList), and AppendToNextContextToFree will tell
  1259. // whether that is really the case.
  1260. //
  1261. octbswap (newAddr);
  1262. if (DeviceExtension->NextContextToFree &&
  1263. DeviceExtension->AppendToNextContextToFree) {
  1264. prevCtx = DeviceExtension->NextContextToFree;
  1265. DeviceExtension->AppendToNextContextToFree = FALSE;
  1266. } else {
  1267. prevCtx = (PASYNC_REQUEST_CONTEXT)
  1268. DeviceExtension->PendingOrbList.Blink;
  1269. }
  1270. prevCtx->CmdOrb->NextOrbAddress = newAddr;
  1271. prevCtx->CmdOrb->NextOrbAddress.ByteArray.Byte0 = 0; //make addr active
  1272. prevCtx->CmdOrb->NextOrbAddress.ByteArray.Byte1 = 0;
  1273. //
  1274. // update the end of list
  1275. //
  1276. InsertTailList (&DeviceExtension->PendingOrbList, &Context->OrbList);
  1277. KeReleaseSpinLockFromDpcLevel (&DeviceExtension->OrbListSpinLock);
  1278. DEBUGPRINT3((
  1279. "Sbp2Port: InsertTailList: ring bell, !empty, dep=%d, ctx=x%p\n",
  1280. DeviceExtension->OrbListDepth,
  1281. Context
  1282. ));
  1283. //
  1284. // Ring the door bell to notify the target that our linked list
  1285. // of ORB's has changed
  1286. //
  1287. Sbp2AccessRegister(
  1288. DeviceExtension,
  1289. &DeviceExtension->Reserved,
  1290. DOORBELL_REG | REG_WRITE_ASYNC
  1291. );
  1292. }
  1293. if (orbListDepth < DeviceExtension->MaxOrbListDepth) {
  1294. Sbp2StartNextPacketByKey(
  1295. DeviceExtension->DeviceObject,
  1296. DeviceExtension->CurrentKey
  1297. );
  1298. }
  1299. }
  1300. NTSTATUS
  1301. Sbp2IssueInternalCommand(
  1302. IN PDEVICE_EXTENSION DeviceExtension,
  1303. IN UCHAR Scsiop
  1304. )
  1305. /*++
  1306. Routine Description:
  1307. This routine will a SCSI inquiry command to the target, so we can retireve information about the device
  1308. It should be called only after login and BEFORE we start issueing requests to the device
  1309. It copies the inquiry data into the device extension, for future use
  1310. Arguments:
  1311. DeviceExtension - extension for sbp2 driver
  1312. Return Value:
  1313. --*/
  1314. {
  1315. PSCSI_REQUEST_BLOCK srb;
  1316. PCDB cdb;
  1317. PSENSE_DATA senseInfoBuffer;
  1318. NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
  1319. ULONG retryCount = 0;
  1320. PREQUEST_CONTEXT context = NULL;
  1321. PMDL inquiryMdl;
  1322. PIRP irp;
  1323. PIO_STACK_LOCATION irpStack;
  1324. PMDL modeMdl;
  1325. KEVENT event;
  1326. LARGE_INTEGER waitValue;
  1327. ULONG i;
  1328. //
  1329. // Sense buffer is in non-paged pool.
  1330. //
  1331. context = (PREQUEST_CONTEXT) \
  1332. ExInterlockedPopEntrySList(&DeviceExtension->BusRequestContextListHead,&DeviceExtension->BusRequestLock);
  1333. if (!context) {
  1334. DEBUGPRINT1(("Sbp2Port: IssueIntl: can't allocate request context\n"));
  1335. return status;
  1336. }
  1337. context->RequestType = SYNC_1394_REQUEST;
  1338. context->DeviceExtension = DeviceExtension;
  1339. context->Packet = NULL;
  1340. senseInfoBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1341. SENSE_BUFFER_SIZE,'2pbs');
  1342. if (senseInfoBuffer == NULL) {
  1343. DEBUGPRINT1(("Sbp2Port: IssueIntl: can't allocate request sense buffer\n"));
  1344. return status;
  1345. }
  1346. srb = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1347. sizeof(SCSI_REQUEST_BLOCK),'2pbs');
  1348. if (srb == NULL) {
  1349. ExFreePool(senseInfoBuffer);
  1350. ExInterlockedPushEntrySList (&DeviceExtension->BusRequestContextListHead,
  1351. &context->ListPointer,
  1352. &DeviceExtension->BusRequestLock);
  1353. DEBUGPRINT1(("Sbp2Port: IssueIntl: can't allocate request sense buffer\n"));
  1354. return status;
  1355. }
  1356. irp = IoAllocateIrp((CCHAR)(DeviceExtension->DeviceObject->StackSize), FALSE);
  1357. if (irp == NULL) {
  1358. ExFreePool(senseInfoBuffer);
  1359. ExFreePool(srb);
  1360. ExInterlockedPushEntrySList (&DeviceExtension->BusRequestContextListHead,
  1361. &context->ListPointer,
  1362. &DeviceExtension->BusRequestLock);
  1363. DEBUGPRINT1(("Sbp2Port: IssueIntl: can't allocate IRP\n"));
  1364. return status;
  1365. }
  1366. do {
  1367. //
  1368. // Construct the IRP stack for the lower level driver.
  1369. //
  1370. irpStack = IoGetNextIrpStackLocation(irp);
  1371. irpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1372. irpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_SCSI_EXECUTE_IN;
  1373. irpStack->Parameters.Scsi.Srb = srb;
  1374. //
  1375. // Fill in SRB fieldsthat Create1394RequestFromSrb needs.
  1376. //
  1377. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  1378. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1379. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  1380. //
  1381. // Set flags to disable synchronous negociation.
  1382. //
  1383. srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  1384. srb->SrbStatus = srb->ScsiStatus = 0;
  1385. //
  1386. // Set timeout to 12 seconds.
  1387. //
  1388. srb->TimeOutValue = 24;
  1389. srb->CdbLength = 6;
  1390. //
  1391. // Enable auto request sense.
  1392. //
  1393. srb->SenseInfoBuffer = senseInfoBuffer;
  1394. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1395. cdb = (PCDB)srb->Cdb;
  1396. switch (Scsiop) {
  1397. case SCSIOP_INQUIRY:
  1398. srb->DataBuffer = &DeviceExtension->InquiryData;
  1399. srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
  1400. //
  1401. // Set CDB LUN.
  1402. //
  1403. cdb->CDB6INQUIRY.LogicalUnitNumber = (UCHAR) DeviceExtension->DeviceInfo->Lun.u.LowPart;
  1404. cdb->CDB6INQUIRY.Reserved1 = 0;
  1405. cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
  1406. //
  1407. // Zero reserve field and
  1408. // Set EVPD Page Code to zero.
  1409. // Set Control field to zero.
  1410. // (See SCSI-II Specification.)
  1411. //
  1412. cdb->CDB6INQUIRY.PageCode = 0;
  1413. cdb->CDB6INQUIRY.IReserved = 0;
  1414. cdb->CDB6INQUIRY.Control = 0;
  1415. if (!retryCount) {
  1416. inquiryMdl = IoAllocateMdl(&DeviceExtension->InquiryData, INQUIRYDATABUFFERSIZE,FALSE,FALSE,NULL);
  1417. if (!inquiryMdl) {
  1418. goto exitSbp2Internal;
  1419. }
  1420. MmBuildMdlForNonPagedPool(inquiryMdl);
  1421. }
  1422. irp->MdlAddress = inquiryMdl;
  1423. break;
  1424. case SCSIOP_MODE_SENSE:
  1425. srb->DataBuffer = &DeviceExtension->DeviceModeHeaderAndPage;
  1426. srb->DataTransferLength = sizeof(DeviceExtension->DeviceModeHeaderAndPage);
  1427. //
  1428. // Setup CDB.
  1429. //
  1430. cdb->MODE_SENSE.Dbd = 1; // disable block descriptors
  1431. cdb->MODE_SENSE.PageCode = MODE_PAGE_RBC_DEVICE_PARAMETERS;
  1432. cdb->MODE_SENSE.Pc = 0; // get current values
  1433. cdb->MODE_SENSE.AllocationLength = sizeof(DeviceExtension->DeviceModeHeaderAndPage);
  1434. if (!retryCount) {
  1435. modeMdl = IoAllocateMdl(
  1436. &DeviceExtension->DeviceModeHeaderAndPage,
  1437. sizeof (DeviceExtension->DeviceModeHeaderAndPage),
  1438. FALSE,
  1439. FALSE,
  1440. NULL
  1441. );
  1442. if (!modeMdl) {
  1443. goto exitSbp2Internal;
  1444. }
  1445. MmBuildMdlForNonPagedPool(modeMdl);
  1446. }
  1447. irp->MdlAddress = modeMdl;
  1448. break;
  1449. }
  1450. //
  1451. // Set CDB operation code.
  1452. //
  1453. cdb->CDB6GENERIC.OperationCode = Scsiop;
  1454. srb->OriginalRequest = irp;
  1455. KeInitializeEvent(&context->Event,
  1456. NotificationEvent,
  1457. FALSE);
  1458. IoSetCompletionRoutine(irp,
  1459. Sbp2RequestCompletionRoutine,
  1460. context,
  1461. TRUE,
  1462. TRUE,
  1463. TRUE);
  1464. DEBUGPRINT2(("Sbp2Port: IssueIntl: sending scsiop x%x, irp=x%p\n", Scsiop, irp));
  1465. status = IoCallDriver(DeviceExtension->DeviceObject, irp);
  1466. if(!NT_SUCCESS(irp->IoStatus.Status) && status!=STATUS_PENDING) {
  1467. status = irp->IoStatus.Status;
  1468. DEBUGPRINT1(("Sbp2Port: IssueIntl: scsiop=x%x irp=x%p err, sts=x%x srbSts=x%x\n",Scsiop,irp, status,srb->SrbStatus));
  1469. break;
  1470. }
  1471. KeWaitForSingleObject (&context->Event, Executive, KernelMode, FALSE, NULL);
  1472. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  1473. DEBUGPRINT3(("Sbp2Port: IssueIntl: scsiop=x%x err, srbSts=%x\n",Scsiop, srb->SrbStatus));
  1474. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  1475. DEBUGPRINT1(("Sbp2Port: IssueIntl: Data underrun \n"));
  1476. status = STATUS_SUCCESS;
  1477. } else if ((srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  1478. senseInfoBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST){
  1479. //
  1480. // A sense key of illegal request was recieved. This indicates
  1481. // that the logical unit number of not valid but there is a
  1482. // target device out there.
  1483. //
  1484. status = STATUS_INVALID_DEVICE_REQUEST;
  1485. retryCount++;
  1486. } else {
  1487. //
  1488. // If the device timed out the request chances are the
  1489. // irp will have been completed by CleanupOrbList with
  1490. // and SRB...FLUSHED error, and we don't want to
  1491. // entertain any devices which are timing out requests
  1492. //
  1493. if ((SRB_STATUS(srb->SrbStatus) ==
  1494. SRB_STATUS_REQUEST_FLUSHED) &&
  1495. (retryCount > 0)) {
  1496. status = STATUS_DEVICE_BUSY;
  1497. break;
  1498. }
  1499. retryCount++;
  1500. DEBUGPRINT1((
  1501. "Sbp2Port: IssueIntl: ext=x%p, cdb=x%x, retry %d\n",
  1502. DeviceExtension,
  1503. Scsiop,
  1504. retryCount
  1505. ));
  1506. status = STATUS_UNSUCCESSFUL;
  1507. }
  1508. //
  1509. // If unsuccessful & a reset is in progress & retries not max'd
  1510. // then give things some time to settle before retry. Check at
  1511. // one second intervals for a few seconds to give soft & hard
  1512. // resets time to complete :
  1513. //
  1514. // SBP2_RESET_TIMEOUT + SBP2_HARD_RESET_TIMEOUT + etc
  1515. //
  1516. if ((status != STATUS_SUCCESS) &&
  1517. (DeviceExtension->DeviceFlags &
  1518. DEVICE_FLAG_RESET_IN_PROGRESS) &&
  1519. (retryCount < 3)) {
  1520. DEBUGPRINT1((
  1521. "Sbp2Port: IssueIntl: ext=x%p, reset in progress, " \
  1522. "so wait...\n",
  1523. DeviceExtension,
  1524. Scsiop,
  1525. retryCount
  1526. ));
  1527. for (i = 0; i < 6; i++) {
  1528. ASSERT(InterlockedIncrement(&DeviceExtension->ulInternalEventCount) == 1);
  1529. KeInitializeEvent (&event, NotificationEvent, FALSE);
  1530. waitValue.QuadPart = -1 * 1000 * 1000 * 10;
  1531. KeWaitForSingleObject(
  1532. &event,
  1533. Executive,
  1534. KernelMode,
  1535. FALSE,
  1536. &waitValue
  1537. );
  1538. ASSERT(InterlockedDecrement(&DeviceExtension->ulInternalEventCount) == 0);
  1539. if (!(DeviceExtension->DeviceFlags &
  1540. DEVICE_FLAG_RESET_IN_PROGRESS)) {
  1541. break;
  1542. }
  1543. }
  1544. }
  1545. } else {
  1546. status = STATUS_SUCCESS;
  1547. }
  1548. } while ((retryCount < 3) && (status != STATUS_SUCCESS));
  1549. exitSbp2Internal:
  1550. //
  1551. // Free request sense buffer.
  1552. //
  1553. ExFreePool(senseInfoBuffer);
  1554. ExFreePool(srb);
  1555. IoFreeMdl(irp->MdlAddress);
  1556. IoFreeIrp(irp);
  1557. ExInterlockedPushEntrySList (&DeviceExtension->BusRequestContextListHead,
  1558. &context->ListPointer,
  1559. &DeviceExtension->BusRequestLock);
  1560. return status;
  1561. }
  1562. NTSTATUS
  1563. Sbp2SendPassThrough (
  1564. IN PDEVICE_EXTENSION DeviceExtension,
  1565. IN PIRP RequestIrp
  1566. )
  1567. /*++
  1568. Routine Description:
  1569. This function sends a user specified SCSI request block.
  1570. It creates an srb which is processed normally by the port driver.
  1571. This call is synchornous.
  1572. Arguments:
  1573. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  1574. RequestIrp - Supplies a pointe to the Irp which made the original request.
  1575. Return Value:
  1576. Returns a status indicating the success or failure of the operation.
  1577. --*/
  1578. {
  1579. PIRP irp;
  1580. PIO_STACK_LOCATION irpStack;
  1581. PSCSI_PASS_THROUGH srbControl;
  1582. SCSI_REQUEST_BLOCK srb;
  1583. KEVENT event;
  1584. LARGE_INTEGER startingOffset;
  1585. IO_STATUS_BLOCK ioStatusBlock;
  1586. ULONG outputLength;
  1587. ULONG length;
  1588. ULONG_PTR bufferOffset;
  1589. PVOID buffer;
  1590. PVOID endByte;
  1591. PVOID senseBuffer;
  1592. UCHAR majorCode;
  1593. NTSTATUS status;
  1594. PAGED_CODE();
  1595. startingOffset.QuadPart = (LONGLONG) 1;
  1596. //
  1597. // Get a pointer to the control block.
  1598. //
  1599. irpStack = IoGetCurrentIrpStackLocation(RequestIrp);
  1600. srbControl = RequestIrp->AssociatedIrp.SystemBuffer;
  1601. //
  1602. // Validate the user buffer.
  1603. //
  1604. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
  1605. DEBUGPRINT1(("Sbp2Passthrough: Input buffer too small \n"));
  1606. return(STATUS_INVALID_PARAMETER);
  1607. }
  1608. if (srbControl->Length != sizeof(SCSI_PASS_THROUGH) &&
  1609. srbControl->Length != sizeof(SCSI_PASS_THROUGH_DIRECT)) {
  1610. DEBUGPRINT1(("Sbp2Passthrough: Revision mismatch, control buffer wrong size\n"));
  1611. return(STATUS_REVISION_MISMATCH);
  1612. }
  1613. outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1614. //
  1615. // Validate the rest of the buffer parameters.
  1616. //
  1617. if (srbControl->CdbLength > 16) {
  1618. DEBUGPRINT1(("Sbp2Passthrough: CdbLength >16, invalid\n"));
  1619. return(STATUS_INVALID_PARAMETER);
  1620. }
  1621. if (srbControl->SenseInfoLength != 0 &&
  1622. (srbControl->Length > srbControl->SenseInfoOffset) ||
  1623. ((srbControl->SenseInfoOffset + srbControl->SenseInfoLength) >
  1624. srbControl->DataBufferOffset && (srbControl->DataTransferLength != 0)) ) {
  1625. DEBUGPRINT1(("Sbp2Passthrough: Sense buffer length and offset is wrong\n"));
  1626. return(STATUS_INVALID_PARAMETER);
  1627. }
  1628. majorCode = !srbControl->DataIn ? IRP_MJ_WRITE : IRP_MJ_READ;
  1629. if (srbControl->DataTransferLength == 0) {
  1630. length = 0;
  1631. buffer = NULL;
  1632. bufferOffset = 0;
  1633. majorCode = IRP_MJ_FLUSH_BUFFERS;
  1634. DEBUGPRINT1(("Sbp2Passthrough: No data transfer since data length is zero\n"));
  1635. } else if (srbControl->DataBufferOffset > outputLength &&
  1636. srbControl->DataBufferOffset > irpStack->Parameters.DeviceIoControl.InputBufferLength) {
  1637. //
  1638. // The data buffer offset is greater than system buffer. Assume this
  1639. // is a user mode address.
  1640. //
  1641. if (srbControl->SenseInfoOffset + srbControl->SenseInfoLength > outputLength
  1642. && srbControl->SenseInfoLength) {
  1643. DEBUGPRINT1(("Sbp2Passthrough: senseinfo offset/length too large"));
  1644. return(STATUS_INVALID_PARAMETER);
  1645. }
  1646. //
  1647. // Make sure the buffer is properly aligned.
  1648. //
  1649. if (srbControl->DataBufferOffset & SBP2_ALIGNMENT_MASK) {
  1650. DEBUGPRINT1(("Sbp2Passthrough: Buffer not aligned on a quad boundary"));
  1651. return(STATUS_INVALID_PARAMETER);
  1652. }
  1653. length = srbControl->DataTransferLength;
  1654. buffer = (PCHAR) srbControl->DataBufferOffset;
  1655. bufferOffset = 0;
  1656. //
  1657. // make sure the user buffer is valid
  1658. //
  1659. if (RequestIrp->RequestorMode != KernelMode) {
  1660. if (length) {
  1661. endByte = (PVOID)((PCHAR)buffer + length - 1);
  1662. if (buffer >= endByte) {
  1663. DEBUGPRINT1(("Sbp2Passthrough: Buffer larger than what claimed in length\n"));
  1664. return STATUS_INVALID_USER_BUFFER;
  1665. }
  1666. }
  1667. }
  1668. } else {
  1669. if (srbControl->DataIn != SCSI_IOCTL_DATA_IN) {
  1670. if ((srbControl->SenseInfoOffset + srbControl->SenseInfoLength > outputLength
  1671. && srbControl->SenseInfoLength != 0) ||
  1672. srbControl->DataBufferOffset + srbControl->DataTransferLength >
  1673. irpStack->Parameters.DeviceIoControl.InputBufferLength ||
  1674. srbControl->Length > srbControl->DataBufferOffset) {
  1675. DEBUGPRINT1(("Sbp2Passthrough: Sense buffer length and offset is wrong\n"));
  1676. return STATUS_INVALID_PARAMETER;
  1677. }
  1678. }
  1679. if (srbControl->DataIn) {
  1680. if (srbControl->DataBufferOffset + srbControl->DataTransferLength > outputLength ||
  1681. srbControl->Length > srbControl->DataBufferOffset) {
  1682. DEBUGPRINT1(("Sbp2Passthrough: Data length and offset is too big\n"));
  1683. return STATUS_INVALID_PARAMETER;
  1684. }
  1685. }
  1686. #ifdef _WIN64
  1687. //
  1688. // This code path should be examined more closely.
  1689. //
  1690. ASSERT( srbControl->DataBufferOffset + srbControl->DataTransferLength <=
  1691. (ULONG)0xFFFFFFFF );
  1692. #endif
  1693. length = (ULONG)(srbControl->DataBufferOffset +
  1694. srbControl->DataTransferLength);
  1695. buffer = (PUCHAR) srbControl;
  1696. bufferOffset = srbControl->DataBufferOffset;
  1697. }
  1698. //
  1699. // Validate that the request isn't too large
  1700. //
  1701. if (srbControl->DataTransferLength &&
  1702. ((ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  1703. ((PUCHAR)buffer+bufferOffset),
  1704. srbControl->DataTransferLength
  1705. ) > DeviceExtension->DeviceInfo->MaxClassTransferSize/PAGE_SIZE) ||
  1706. (DeviceExtension->DeviceInfo->MaxClassTransferSize < srbControl->DataTransferLength))) {
  1707. DEBUGPRINT1(("Sbp2Passthrough: Data length larger than max transfer size\n"));
  1708. return(STATUS_INVALID_PARAMETER);
  1709. }
  1710. if (srbControl->TimeOutValue == 0 ||
  1711. srbControl->TimeOutValue > 30 * 60 * 60) {
  1712. DEBUGPRINT1(("Sbp2Passthrough: Timeout either zero or too big\n"));
  1713. return STATUS_INVALID_PARAMETER;
  1714. }
  1715. //
  1716. // Check for illegal command codes.
  1717. //
  1718. if (srbControl->Cdb[0] == SCSIOP_COPY ||
  1719. srbControl->Cdb[0] == SCSIOP_COMPARE ||
  1720. srbControl->Cdb[0] == SCSIOP_COPY_COMPARE) {
  1721. DEBUGPRINT1(("Sbp2Passthrough: Invalid Cdb SCSIOP, copy, copy/compare not supported\n"));
  1722. return STATUS_INVALID_DEVICE_REQUEST;
  1723. }
  1724. //
  1725. // If this request came through a normal device control rather than from
  1726. // class driver then the device must exist and be unclaimed. Class drivers
  1727. // will set the minor function code for the device control. It is always
  1728. // zero for a user request.
  1729. //
  1730. if((irpStack->MinorFunction == 0) && (DeviceExtension->DeviceFlags & DEVICE_FLAG_CLAIMED)) {
  1731. DEBUGPRINT1(("Sbp2Passthrough: This came down from class driver, should not happen, irp %p\n",RequestIrp));
  1732. return STATUS_INVALID_DEVICE_REQUEST;
  1733. }
  1734. //
  1735. // Allocate an aligned request sense buffer.
  1736. //
  1737. if (srbControl->SenseInfoLength != 0) {
  1738. senseBuffer = ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
  1739. srbControl->SenseInfoLength,'2pbs');
  1740. if (senseBuffer == NULL) {
  1741. return(STATUS_INSUFFICIENT_RESOURCES);
  1742. }
  1743. } else {
  1744. senseBuffer = NULL;
  1745. }
  1746. //
  1747. // Initialize the notification event.
  1748. //
  1749. KeInitializeEvent (&event, NotificationEvent, FALSE);
  1750. //
  1751. // Build IRP for this request.
  1752. // Note we do this synchronously for two reasons. If it was done
  1753. // asynchonously then the completion code would have to make a special
  1754. // check to deallocate the buffer. Second if a completion routine were
  1755. // used then an addation stack locate would be needed.
  1756. //
  1757. try {
  1758. irp = IoBuildSynchronousFsdRequest(
  1759. majorCode,
  1760. DeviceExtension->DeviceObject,
  1761. buffer,
  1762. length,
  1763. &startingOffset,
  1764. &event,
  1765. &ioStatusBlock);
  1766. } except(EXCEPTION_EXECUTE_HANDLER) {
  1767. //
  1768. // An exception was incurred while attempting to probe the
  1769. // caller's parameters. Dereference the file object and return
  1770. // an appropriate error status code.
  1771. //
  1772. if (senseBuffer != NULL) {
  1773. ExFreePool(senseBuffer);
  1774. }
  1775. return GetExceptionCode();
  1776. }
  1777. if (irp == NULL) {
  1778. if (senseBuffer != NULL) {
  1779. ExFreePool(senseBuffer);
  1780. }
  1781. return(STATUS_INSUFFICIENT_RESOURCES);
  1782. }
  1783. irpStack = IoGetNextIrpStackLocation(irp);
  1784. //
  1785. // Set major code.
  1786. //
  1787. irpStack->MajorFunction = IRP_MJ_SCSI;
  1788. irpStack->MinorFunction = 1;
  1789. //
  1790. // Fill in SRB fields.
  1791. //
  1792. irpStack->Parameters.Others.Argument1 = &srb;
  1793. //
  1794. // Zero out the srb.
  1795. //
  1796. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  1797. //
  1798. // Fill in the srb.
  1799. //
  1800. srb.Length = SCSI_REQUEST_BLOCK_SIZE;
  1801. srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  1802. srb.SrbStatus = SRB_STATUS_PENDING;
  1803. srb.PathId = 0;
  1804. srb.TargetId = 0;
  1805. srb.Lun = 0;
  1806. srb.CdbLength = srbControl->CdbLength;
  1807. srb.SenseInfoBufferLength = srbControl->SenseInfoLength;
  1808. switch (srbControl->DataIn) {
  1809. case SCSI_IOCTL_DATA_OUT:
  1810. if (srbControl->DataTransferLength) {
  1811. srb.SrbFlags = SRB_FLAGS_DATA_OUT;
  1812. }
  1813. break;
  1814. case SCSI_IOCTL_DATA_IN:
  1815. if (srbControl->DataTransferLength) {
  1816. srb.SrbFlags = SRB_FLAGS_DATA_IN;
  1817. }
  1818. break;
  1819. default:
  1820. srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT;
  1821. break;
  1822. }
  1823. if (srbControl->DataTransferLength == 0) {
  1824. srb.SrbFlags = 0;
  1825. } else {
  1826. //
  1827. // Flush the data buffer for output. This will insure that the data is
  1828. // written back to memory.
  1829. //
  1830. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  1831. }
  1832. srb.DataTransferLength = srbControl->DataTransferLength;
  1833. srb.TimeOutValue = srbControl->TimeOutValue;
  1834. srb.DataBuffer = (PCHAR) buffer + bufferOffset;
  1835. srb.SenseInfoBuffer = senseBuffer;
  1836. // srb.OriginalRequest = irp;
  1837. srb.OriginalRequest = irp;
  1838. RtlCopyMemory(srb.Cdb, srbControl->Cdb, srbControl->CdbLength);
  1839. //
  1840. // Disable autosense if there's no sense buffer to put the data in.
  1841. //
  1842. if (senseBuffer == NULL) {
  1843. SET_FLAG(srb.SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
  1844. }
  1845. //
  1846. // Call port driver to handle this request.
  1847. //
  1848. status = IoCallDriver(DeviceExtension->DeviceObject, irp);
  1849. //
  1850. // Wait for request to complete.
  1851. //
  1852. if (status == STATUS_PENDING) {
  1853. KeWaitForSingleObject(&event,
  1854. Executive,
  1855. KernelMode,
  1856. FALSE,
  1857. NULL);
  1858. }
  1859. //
  1860. // Copy the returned values from the srb to the control structure.
  1861. //
  1862. srbControl->ScsiStatus = srb.ScsiStatus;
  1863. if (srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  1864. //
  1865. // Set the status to success so that the data is returned.
  1866. //
  1867. ioStatusBlock.Status = STATUS_SUCCESS;
  1868. srbControl->SenseInfoLength = srb.SenseInfoBufferLength;
  1869. //
  1870. // Copy the sense data to the system buffer.
  1871. //
  1872. RtlCopyMemory((PUCHAR) srbControl + srbControl->SenseInfoOffset,
  1873. senseBuffer,
  1874. srb.SenseInfoBufferLength);
  1875. } else {
  1876. srbControl->SenseInfoLength = 0;
  1877. }
  1878. //
  1879. // Free the sense buffer.
  1880. //
  1881. if (senseBuffer != NULL) {
  1882. ExFreePool(senseBuffer);
  1883. }
  1884. //
  1885. // If the srb status is buffer underrun then set the status to success.
  1886. // This insures that the data will be returned to the caller.
  1887. //
  1888. if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  1889. ioStatusBlock.Status = STATUS_SUCCESS;
  1890. }
  1891. srbControl->DataTransferLength = srb.DataTransferLength;
  1892. //
  1893. // Set the information length
  1894. //
  1895. if (!srbControl->DataIn || bufferOffset == 0) {
  1896. RequestIrp->IoStatus.Information = srbControl->SenseInfoOffset +
  1897. srbControl->SenseInfoLength;
  1898. } else {
  1899. RequestIrp->IoStatus.Information = srbControl->DataBufferOffset +
  1900. srbControl->DataTransferLength;
  1901. }
  1902. RequestIrp->IoStatus.Status = ioStatusBlock.Status;
  1903. return ioStatusBlock.Status;
  1904. }
  1905. BOOLEAN
  1906. ConvertSbp2SenseDataToScsi(
  1907. IN PSTATUS_FIFO_BLOCK StatusBlock,
  1908. OUT PUCHAR SenseBuffer,
  1909. ULONG SenseBufferLength
  1910. )
  1911. /*++
  1912. Routine Description:
  1913. This routine will convert the sense information returned in an SBP-2 status block, to SCSI-2/3 sense data
  1914. and put them the translated on the SenseBuffer passed as an argument
  1915. Arguments:
  1916. StatusBlock - Sbp2 staus for completed ORB
  1917. SenseBuffer - Buffer to fill in with translated Sense Data. This buffer comes with the original SRB
  1918. Return Value:
  1919. --*/
  1920. {
  1921. BOOLEAN validSense = FALSE;
  1922. if (!SenseBuffer || (SenseBufferLength < 0xE) ) {
  1923. return FALSE;
  1924. }
  1925. RtlZeroMemory(SenseBuffer,SenseBufferLength);
  1926. //
  1927. // determine sense error code
  1928. //
  1929. if ((StatusBlock->Contents[0].ByteArray.Byte0 & STATUS_BLOCK_SFMT_MASK) == SENSE_DATA_STATUS_BLOCK ) {
  1930. SenseBuffer[0] = 0x70;
  1931. validSense = TRUE;
  1932. } else if ((StatusBlock->Contents[0].ByteArray.Byte0 & STATUS_BLOCK_SFMT_MASK) == SENSE_DATA_DEFF_STATUS_BLOCK){
  1933. SenseBuffer[0] = 0x71;
  1934. validSense = TRUE;
  1935. }
  1936. if (validSense) {
  1937. SenseBuffer[0] |= 0x80 & StatusBlock->Contents[0].ByteArray.Byte1; // valid bit
  1938. SenseBuffer[1] = 0; // segment number not supported in sbp2
  1939. SenseBuffer[2] = (0x70 & StatusBlock->Contents[0].ByteArray.Byte1) << 1; // filemark bit, eom bit, ILI bit
  1940. SenseBuffer[2] |= 0x0f & StatusBlock->Contents[0].ByteArray.Byte1; // sense key
  1941. SenseBuffer[3] = StatusBlock->Contents[0].ByteArray.Byte4; // Information field
  1942. SenseBuffer[4] = StatusBlock->Contents[0].ByteArray.Byte5;
  1943. SenseBuffer[5] = StatusBlock->Contents[0].ByteArray.Byte6;
  1944. SenseBuffer[6] = StatusBlock->Contents[0].ByteArray.Byte7;
  1945. SenseBuffer[7] = 0xb; // additional sense length
  1946. SenseBuffer[8] = StatusBlock->Contents[1].ByteArray.Byte0; // Command Block dependent bytes
  1947. SenseBuffer[9] = StatusBlock->Contents[1].ByteArray.Byte1;
  1948. SenseBuffer[10] = StatusBlock->Contents[1].ByteArray.Byte2;
  1949. SenseBuffer[11] = StatusBlock->Contents[1].ByteArray.Byte3;
  1950. SenseBuffer[12] = StatusBlock->Contents[0].ByteArray.Byte2; // sense code
  1951. SenseBuffer[13] = StatusBlock->Contents[0].ByteArray.Byte3; // additional sense code qualifier
  1952. if (SenseBufferLength >= SENSE_BUFFER_SIZE ) {
  1953. // FRU byte
  1954. SenseBuffer[14] |= StatusBlock->Contents[1].ByteArray.Byte4;
  1955. // Sense key dependent bytes
  1956. SenseBuffer[15] = StatusBlock->Contents[1].ByteArray.Byte5;
  1957. SenseBuffer[16] = StatusBlock->Contents[1].ByteArray.Byte6;
  1958. SenseBuffer[17] = StatusBlock->Contents[1].ByteArray.Byte7;
  1959. }
  1960. }
  1961. return validSense;
  1962. }