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.

1251 lines
38 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. protocol.c
  5. Abstract:
  6. This file contains iSCSI protocol related routines.
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. --*/
  11. #include "port.h"
  12. LONG GlobalSessionID;
  13. LONG InitiatorSessionID;
  14. #define ISCSI_TARGET "target:"
  15. #define ISCSI_TARGET_LENGTH 7
  16. #define ISCSI_USE_RTT "UseRtt:no"
  17. #define ISCSI_USE_RTT_LENGTH 9
  18. ULONG
  19. iSpGetActiveClientRequestIndex(
  20. PISCSI_CONNECTION IScsiConnection,
  21. ULONG TaskTag
  22. );
  23. ULONG
  24. iSpGetReqIndexUsingCmdRN(
  25. PISCSI_CONNECTION IScsiConnection,
  26. ULONG CmdRN
  27. );
  28. NTSTATUS
  29. iSpSendLoginCommand(
  30. IN PISCSI_PDO_EXTENSION PdoExtension
  31. )
  32. {
  33. PISCSI_CONNECTION iScsiConnection;
  34. PISCSI_LOGIN_COMMAND iscsiLoginCommand;
  35. PUCHAR loginParameters;
  36. NTSTATUS status;
  37. ULONG bytesSent;
  38. ULONG tempULong;
  39. ULONG packetSize;
  40. ULONG targetLength;
  41. iScsiConnection = PdoExtension->ClientNodeInfo;
  42. ASSERT((iScsiConnection != NULL));
  43. ASSERT((iScsiConnection->Type) == ISCSI_CONNECTION_TYPE);
  44. targetLength = strlen(PdoExtension->TargetName);
  45. packetSize = (sizeof(ISCSI_LOGIN_COMMAND) + ISCSI_TARGET_LENGTH +
  46. targetLength + ISCSI_USE_RTT_LENGTH + 2);
  47. iscsiLoginCommand = iSpAllocatePool(
  48. NonPagedPool,
  49. packetSize,
  50. ISCSI_TAG_LOGIN_CMD);
  51. if (iscsiLoginCommand == NULL) {
  52. DebugPrint((0, "Failed to allocate logon packet\n"));
  53. return STATUS_INSUFFICIENT_RESOURCES;
  54. }
  55. RtlZeroMemory(iscsiLoginCommand,
  56. packetSize);
  57. iscsiLoginCommand->OpCode = ISCSIOP_LOGIN_COMMAND;
  58. //
  59. // No authentication performed
  60. //
  61. iscsiLoginCommand->LoginType = ISCSI_LOGINTYPE_NONE;
  62. //
  63. // Connection ID for this session
  64. //
  65. tempULong = InterlockedIncrement(&GlobalSessionID);
  66. iscsiLoginCommand->ConnectionID[0] = (UCHAR) ((tempULong & 0xFF00) >> 8);
  67. iscsiLoginCommand->ConnectionID[1] = (UCHAR) (tempULong & 0xFF);
  68. //
  69. // Command Reference number starting from 1
  70. //
  71. iscsiLoginCommand->InitCmdRN[3] = 1;
  72. tempULong = InterlockedIncrement(&InitiatorSessionID);
  73. iscsiLoginCommand->ISID[0] = (UCHAR) ((tempULong & 0xFF00) >> 8);
  74. iscsiLoginCommand->ISID[1] = (UCHAR) (tempULong & 0xFF);
  75. //
  76. // Identifier for the target device is passed as parameters
  77. // in the Login packet
  78. //
  79. // "target:<TargetName>" -- Target device name
  80. // "UseRtt:no" -- Do NOT use RTT
  81. //
  82. loginParameters = (PUCHAR) (iscsiLoginCommand + 1);
  83. RtlCopyMemory(loginParameters, ISCSI_TARGET, ISCSI_TARGET_LENGTH);
  84. loginParameters += ISCSI_TARGET_LENGTH;
  85. RtlCopyMemory(loginParameters, PdoExtension->TargetName, targetLength);
  86. loginParameters += targetLength + 1;
  87. RtlCopyMemory(loginParameters, ISCSI_USE_RTT, ISCSI_USE_RTT_LENGTH);
  88. iscsiLoginCommand->Length[3] =
  89. ISCSI_TARGET_LENGTH + (UCHAR) targetLength + ISCSI_USE_RTT_LENGTH + 2;
  90. /*
  91. {
  92. ULONG inx0, inx1, len;
  93. DebugPrint((1, "\n Logon Packet\n"));
  94. len = (ISCSI_TARGET_LENGTH + targetLength +
  95. ISCSI_USE_RTT_LENGTH + 2 + 48);
  96. inx0 = 0;
  97. while(inx0 < len) {
  98. inx1 = 0;
  99. DebugPrint((1, "\t"));
  100. while ((inx1 < 4) &&
  101. ((inx0+inx1) < len)) {
  102. DebugPrint((1, "0x%02x ",
  103. ((PUCHAR)iscsiLoginCommand)[inx0+inx1]));
  104. inx1++;
  105. }
  106. DebugPrint((1, "\n"));
  107. inx0 += 4;
  108. }
  109. DebugPrint((1, "\n"));
  110. }
  111. */
  112. //
  113. // Save away the connection ID in our device extension
  114. //
  115. PdoExtension->SavedConnectionID[0] = iscsiLoginCommand->ConnectionID[0];
  116. PdoExtension->SavedConnectionID[1] = iscsiLoginCommand->ConnectionID[1];
  117. status = iSpSendData(iScsiConnection->ConnectionDeviceObject,
  118. iScsiConnection->ConnectionFileObject,
  119. iscsiLoginCommand,
  120. packetSize,
  121. &bytesSent);
  122. if (NT_SUCCESS(status)) {
  123. DebugPrint((3, "Send succeeded for logon. Bytes sent : %d\n",
  124. bytesSent));
  125. } else {
  126. DebugPrint((0, "Failed to logon packet. Status : %x\n",
  127. status));
  128. PdoExtension->SavedConnectionID[0] = 0;
  129. PdoExtension->SavedConnectionID[1] = 0;
  130. }
  131. return status;
  132. }
  133. NTSTATUS
  134. iSpSendScsiCommand(
  135. IN PDEVICE_OBJECT DeviceObject,
  136. IN PIRP Irp
  137. )
  138. {
  139. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  140. PISCSI_PDO_EXTENSION pdoExtension = NULL;
  141. PISCSI_CONNECTION iScsiConnection = NULL;
  142. PISCSI_SCSI_COMMAND iScsiScsiCommand = NULL;
  143. PACTIVE_REQUESTS currentRequest;
  144. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  145. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  146. PVOID requestBuffer = NULL;
  147. PVOID originalDataBuffer = NULL;
  148. ULONG_PTR offset;
  149. PVOID receiveBuffer = NULL;
  150. ULONG receiveBufferSize = 0;
  151. ULONG cmdRN;
  152. ULONG expectedDataLen;
  153. ULONG packetSize;
  154. ULONG inx;
  155. ULONG bytesSent;
  156. NTSTATUS status;
  157. KIRQL oldIrql;
  158. BOOLEAN writeToDevice;
  159. ASSERT(commonExtension->IsPdo);
  160. pdoExtension = (PISCSI_PDO_EXTENSION)(DeviceObject->DeviceExtension);
  161. iScsiConnection = pdoExtension->ClientNodeInfo;
  162. if ((iScsiConnection->ConnectionState) != ConnectionStateConnected) {
  163. DebugPrint((0, "Not connected to target. Connection State : %d\n",
  164. (iScsiConnection->ConnectionState)));
  165. Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
  166. Irp->IoStatus.Information = 0L;
  167. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  168. return STATUS_DEVICE_NOT_CONNECTED;
  169. }
  170. ASSERT((pdoExtension->CurrentProtocolState) == PSFullFeaturePhase);
  171. //
  172. // Get the lock to synchronize access to iSCSI
  173. // Connection structure
  174. //
  175. KeAcquireSpinLock(&(iScsiConnection->RequestLock),
  176. &oldIrql);
  177. if ((iScsiConnection->NumberOfReqsInProgress) >=
  178. (iScsiConnection->MaxPendingRequests)) {
  179. //
  180. // Queue it to the request list for this connection
  181. //
  182. IoMarkIrpPending(Irp);
  183. ExInterlockedInsertTailList(&(iScsiConnection->RequestList),
  184. &(Irp->Tail.Overlay.ListEntry),
  185. &(iScsiConnection->ListSpinLock));
  186. KeReleaseSpinLock(&(iScsiConnection->RequestLock),
  187. oldIrql);
  188. return STATUS_PENDING;
  189. }
  190. expectedDataLen = 0;
  191. writeToDevice = FALSE;
  192. packetSize = sizeof(ISCSI_SCSI_COMMAND);
  193. if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
  194. expectedDataLen = srb->DataTransferLength;
  195. } else if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
  196. //
  197. // If we are writing to the device, the data
  198. // is sent as immediate data
  199. //
  200. packetSize += srb->DataTransferLength;
  201. writeToDevice = TRUE;
  202. }
  203. if (Irp->MdlAddress) {
  204. offset = (ULONG_PTR) ((ULONG_PTR) srb->DataBuffer -
  205. (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress));
  206. DebugPrint((3, "Srb DataBuffer : 0x%x, Offset into the MDL : 0x%x\n",
  207. srb->DataBuffer, offset));
  208. requestBuffer = MmGetSystemAddressForMdlSafe(
  209. Irp->MdlAddress,
  210. ((Irp->RequestorMode == KernelMode) ?
  211. HighPagePriority :
  212. NormalPagePriority));
  213. if (requestBuffer != NULL) {
  214. UCHAR readChar;
  215. //
  216. // Save the original DataBuffer passed in the SRB
  217. //
  218. originalDataBuffer = srb->DataBuffer;
  219. DebugPrint((3, "SendCommand : Original DataBuffer - 0x%08x\n",
  220. originalDataBuffer));
  221. srb->DataBuffer = (PVOID) ((ULONG_PTR) requestBuffer +
  222. (ULONG_PTR) offset);
  223. //
  224. // This is for catching the case where the Srb DataBuffer
  225. // we have generated is not valid
  226. //
  227. readChar = *((PUCHAR)(srb->DataBuffer));
  228. DebugPrint((3,
  229. "OpCode : %d, SRB DataBuffer : %x. ReadChar : %d\n",
  230. srb->Cdb[0],
  231. srb->DataBuffer,
  232. readChar));
  233. DebugPrint((3, "System address for requestBuffer : 0x%08x\n",
  234. requestBuffer));
  235. } else {
  236. DebugPrint((1, "Failed to get System Address for MDL\n"));
  237. status = STATUS_INSUFFICIENT_RESOURCES;
  238. Irp->IoStatus.Status = status;
  239. Irp->IoStatus.Information = 0L;
  240. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  241. goto iSpSendScsiCommandExit;
  242. }
  243. }
  244. iScsiScsiCommand = iSpAllocatePool(
  245. NonPagedPool,
  246. packetSize,
  247. ISCSI_TAG_SCSI_CMD);
  248. if (iScsiScsiCommand == NULL) {
  249. DebugPrint((1, "Could not allocate iSCSI Command packet\n"));
  250. //
  251. // Restore the original DataBuffer in the SRB
  252. //
  253. if (originalDataBuffer != NULL) {
  254. srb->DataBuffer = originalDataBuffer;
  255. }
  256. status = STATUS_INSUFFICIENT_RESOURCES;
  257. Irp->IoStatus.Status = status;
  258. Irp->IoStatus.Information = 0L;
  259. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  260. goto iSpSendScsiCommandExit;
  261. }
  262. RtlZeroMemory(iScsiScsiCommand, packetSize);
  263. iScsiScsiCommand->OpCode = ISCSIOP_SCSI_COMMAND;
  264. if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
  265. iScsiScsiCommand->Read = SETBITON;
  266. }
  267. if (writeToDevice == TRUE) {
  268. SetUlongInArray((iScsiScsiCommand->Length),
  269. (srb->DataTransferLength));
  270. SetUlongInArray((iScsiScsiCommand->ExpDataXferLength),
  271. (srb->DataTransferLength));
  272. //
  273. // Issue : nramas : 01/02/2001
  274. // This should be later changed to chained MDLs
  275. //
  276. RtlCopyMemory((iScsiScsiCommand + 1),
  277. (srb->DataBuffer),
  278. srb->DataTransferLength);
  279. }
  280. if (expectedDataLen != 0) {
  281. SetUlongInArray((iScsiScsiCommand->ExpDataXferLength),
  282. expectedDataLen);
  283. }
  284. SetUlongInArray((iScsiScsiCommand->CmdRN),
  285. (iScsiConnection->CommandRefNum));
  286. SetUlongInArray((iScsiScsiCommand->ExpStatRN),
  287. (iScsiConnection->CurrentStatusRefNum));
  288. //DebugPrint((3, "Exp StatRN : 0x%x\n",
  289. // (iScsiConnection->ExpStatusRefNum)));
  290. SetUlongInArray((iScsiScsiCommand->TaskTag),
  291. (iScsiConnection->InitiatorTaskTag));
  292. ASSERT((srb->CdbLength) <= 16);
  293. DebugPrint((3, "CDB : "));
  294. for (inx = 0; inx < (srb->CdbLength); inx++) {
  295. DebugPrint((3, "0x%02x ", srb->Cdb[inx]));
  296. }
  297. DebugPrint((3, "\n"));
  298. RtlCopyMemory((iScsiScsiCommand->Cdb),
  299. (srb->Cdb),
  300. (srb->CdbLength));
  301. cmdRN = (iScsiConnection->CommandRefNum);
  302. inx = cmdRN % (iScsiConnection->MaxPendingRequests);
  303. if (inx == 0) {
  304. inx = (iScsiConnection->MaxPendingRequests);
  305. }
  306. DebugPrint((3, "Request will be added to slot %d\n",
  307. inx));
  308. currentRequest = &(iScsiConnection->ActiveClientRequests[inx]);
  309. ASSERT((currentRequest->InUse) == FALSE);
  310. currentRequest->CommandRefNum = iScsiConnection->CommandRefNum;
  311. currentRequest->Irp = Irp;
  312. currentRequest->DeviceObject = DeviceObject;
  313. currentRequest->TaskTag = iScsiConnection->InitiatorTaskTag;
  314. if (originalDataBuffer != NULL) {
  315. currentRequest->OriginalDataBuffer = originalDataBuffer;
  316. }
  317. currentRequest->RequestBuffer = srb->DataBuffer;
  318. currentRequest->RequestBufferOffset = 0;
  319. currentRequest->InUse = TRUE;
  320. currentRequest->Completed = FALSE;
  321. (iScsiConnection->InitiatorTaskTag)++;
  322. if ((iScsiConnection->InitiatorTaskTag) == 0) {
  323. iScsiConnection->InitiatorTaskTag = 1;
  324. }
  325. (iScsiConnection->CommandRefNum)++;
  326. (iScsiConnection->NumberOfReqsInProgress)++;
  327. DebugPrint((3, "Number of requests in progress %d\n",
  328. (iScsiConnection->NumberOfReqsInProgress)));
  329. DebugPrint((3,
  330. "CmdRN %d. PacketSize %d, Expected Xfer Length %d\n",
  331. cmdRN, packetSize, expectedDataLen));
  332. DebugPrint((3, "SCSI packet : %x\n", iScsiScsiCommand));
  333. status = iSpSendData(iScsiConnection->ConnectionDeviceObject,
  334. iScsiConnection->ConnectionFileObject,
  335. iScsiScsiCommand,
  336. packetSize,
  337. &bytesSent);
  338. if (NT_SUCCESS(status)) {
  339. //
  340. // Command packet successfully sent. Mark the IRP pending,
  341. // and return STATUS_PENDING
  342. //
  343. IoMarkIrpPending(Irp);
  344. status = STATUS_PENDING;
  345. } else {
  346. DebugPrint((0, "Failed to send SCSI Command. Status : 0x%08x\n",
  347. status));
  348. if (currentRequest->OriginalDataBuffer) {
  349. srb->DataBuffer = currentRequest->OriginalDataBuffer;
  350. }
  351. (iScsiConnection->InitiatorTaskTag)--;
  352. (iScsiConnection->CommandRefNum)--;
  353. (iScsiConnection->NumberOfReqsInProgress)--;
  354. RtlZeroMemory(currentRequest, sizeof(ACTIVE_REQUESTS));
  355. Irp->IoStatus.Status = status;
  356. Irp->IoStatus.Information = 0L;
  357. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  358. }
  359. iSpSendScsiCommandExit:
  360. KeReleaseSpinLock(&(iScsiConnection->RequestLock),
  361. oldIrql);
  362. return status;
  363. }
  364. NTSTATUS
  365. iSpProcessScsiResponse(
  366. PISCSI_CONNECTION IScsiConnection,
  367. PISCSI_SCSI_RESPONSE IScsiScsiResponse
  368. )
  369. {
  370. PISCSI_PDO_EXTENSION pdoExtension;
  371. PCOMMON_EXTENSION commonExtension;
  372. PIO_STACK_LOCATION irpStack;
  373. PSCSI_REQUEST_BLOCK srb;
  374. PIRP irp;
  375. PDEVICE_OBJECT deviceObject;
  376. PACTIVE_REQUESTS currentRequest;
  377. ULONG inx;
  378. ULONG taskTag;
  379. ULONG cmdStatus;
  380. ULONG iScsiStatus;
  381. ULONG statusRN;
  382. ULONG length;
  383. ULONG expCmdRefNum;
  384. NTSTATUS status;
  385. ASSERT((IScsiScsiResponse->OpCode) == ISCSIOP_SCSI_RESPONSE);
  386. ASSERT(IScsiConnection->Type == ISCSI_CONNECTION_TYPE);
  387. currentRequest = IScsiConnection->CurrentRequest;
  388. GetUlongFromArray((IScsiScsiResponse->TaskTag),
  389. taskTag);
  390. GetUlongFromArray((IScsiScsiResponse->StatusRN),
  391. statusRN);
  392. IScsiConnection->CurrentStatusRefNum = statusRN;
  393. DebugPrint((3, "iSpProcessScsiResponse - TaskTag 0x%08x\n",
  394. taskTag));
  395. (IScsiConnection->NumberOfReqsInProgress)--;
  396. commonExtension =
  397. (currentRequest->DeviceObject)->DeviceExtension;
  398. pdoExtension = (PISCSI_PDO_EXTENSION) commonExtension;
  399. irp = currentRequest->Irp;
  400. deviceObject = currentRequest->DeviceObject;
  401. irpStack = IoGetCurrentIrpStackLocation(irp);
  402. srb = irpStack->Parameters.Scsi.Srb;
  403. cmdStatus = IScsiScsiResponse->CmdStatus;
  404. iScsiStatus = IScsiScsiResponse->iSCSIStatus;
  405. GetUlongFromArray((IScsiScsiResponse->ExpCmdRN),
  406. (expCmdRefNum));
  407. GetUlongFromArray((IScsiScsiResponse->MaxCmdRN),
  408. (IScsiConnection->MaxCommandRefNum));
  409. DebugPrint((3,
  410. "SCSI Response : Expected CmdRefNum %d, MaxCmdRN %d\n",
  411. expCmdRefNum,
  412. (IScsiConnection->MaxCommandRefNum)));
  413. //
  414. // Retrieve the size of immediate data
  415. //
  416. GetUlongFromArray((IScsiScsiResponse->Length),
  417. length);
  418. if (cmdStatus == SCSISTAT_GOOD) {
  419. ASSERT(iScsiStatus == ISCSISTAT_GOOD);
  420. irp->IoStatus.Status = STATUS_SUCCESS;
  421. if ((srb->SrbFlags) & SRB_FLAGS_DATA_IN) {
  422. //
  423. // Read request. Fill the number of bytes read
  424. //
  425. irp->IoStatus.Information = currentRequest->ReceivedDataLength;
  426. srb->DataTransferLength = currentRequest->ReceivedDataLength;
  427. } else if ((srb->SrbFlags) & SRB_FLAGS_DATA_OUT) {
  428. //
  429. // Write request. Set IoStatus Information to
  430. // number of bytes written (srb->DataTransferLength)
  431. //
  432. irp->IoStatus.Information = srb->DataTransferLength;
  433. } else {
  434. //
  435. // No I/O involved in this request.
  436. //
  437. irp->IoStatus.Information = 0;
  438. }
  439. srb->SrbStatus = SRB_STATUS_SUCCESS;
  440. srb->ScsiStatus = SCSISTAT_GOOD;
  441. DebugPrint((3, "Info : 0x%x\n", irp->IoStatus.Information));
  442. } else {
  443. DebugPrint((0, "Command failed\n"));
  444. srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
  445. //
  446. // Should map SRB status error using sense data
  447. //
  448. srb->SrbStatus = SRB_STATUS_ERROR;
  449. //
  450. // If the upper driver passed a valid senseinfo buffer,
  451. // and the target sent sense data, copy it to the buffer
  452. //
  453. if ((srb->SenseInfoBufferLength) && (length > 0)) {
  454. ULONG senseInx;
  455. if (length > (srb->SenseInfoBufferLength)) {
  456. DebugPrint((0,
  457. "Sense info greater than buffer size. Size %d\n",
  458. length));
  459. length = srb->SenseInfoBufferLength;
  460. }
  461. DebugPrint((0, "Command 0x%02x failed. Sense Data : ",
  462. srb->Cdb[0]));
  463. for (senseInx = 0; senseInx < length; senseInx++) {
  464. DebugPrint((0, "%02x ", currentRequest->SenseData[senseInx]));
  465. }
  466. DebugPrint((0, "\n"));
  467. RtlCopyMemory(srb->SenseInfoBuffer,
  468. currentRequest->SenseData,
  469. length);
  470. srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
  471. srb->SenseInfoBufferLength = (UCHAR) length;
  472. }
  473. //
  474. // ISSUE : nramas : 01/15/2001
  475. // Need to determine the correct NTSTATUS here
  476. //
  477. irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
  478. irp->IoStatus.Information = 0;
  479. }
  480. //
  481. // Restore the original DataBuffer in the SRB
  482. //
  483. if ((currentRequest->OriginalDataBuffer) != NULL) {
  484. DebugPrint((3, "ProcessResponse : Original DataBuffer - 0x%08x\n",
  485. currentRequest->OriginalDataBuffer));
  486. srb->DataBuffer = currentRequest->OriginalDataBuffer;
  487. }
  488. DebugPrint((3, "Irp done : 0x%x\n", irp));
  489. IoCompleteRequest(irp, IO_NO_INCREMENT);
  490. RtlZeroMemory(currentRequest, sizeof(ACTIVE_REQUESTS));
  491. return STATUS_SUCCESS;
  492. }
  493. NTSTATUS
  494. iSpProcessReceivedData(
  495. IN PISCSI_CONNECTION IScsiConnection,
  496. IN ULONG BytesIndicated,
  497. OUT ULONG *BytesTaken,
  498. IN PVOID DataBuffer
  499. )
  500. {
  501. PUCHAR requestBuffer = NULL;
  502. PISCSI_GENERIC_HEADER iScsiHeader = NULL;
  503. PISCSI_SCSI_RESPONSE iScsiResponse = NULL;
  504. PISCSI_SCSI_DATA_READ iScsiDataRead = NULL;
  505. PACTIVE_REQUESTS currentRequest = NULL;
  506. ULONG length;
  507. ULONG receivedDataLen;
  508. ULONG inx;
  509. ULONG taskTag;
  510. ULONG statusRefNum;
  511. ULONG expCmdRN;
  512. LONG byteCount;
  513. NTSTATUS status = STATUS_SUCCESS;
  514. UCHAR opCode;
  515. KIRQL oldIrql;
  516. //
  517. // We always take all the data given to us
  518. // in this routine. So set BytesTaken to
  519. // BytesIndicated
  520. *BytesTaken = BytesIndicated;
  521. byteCount = (LONG) BytesIndicated;
  522. DebugPrint((3, "Bytes indicated : %d\n", BytesIndicated));
  523. //
  524. // Get the lock to synchronize access to iSCSI
  525. // Connection structure
  526. //
  527. KeAcquireSpinLock(&(IScsiConnection->RequestLock),
  528. &oldIrql);
  529. while (byteCount > 0) {
  530. if ((IScsiConnection->ReceiveState) == ReceiveHeader) {
  531. DebugPrint((3, "Receiving header\n"));
  532. if ((IScsiConnection->CompleteHeaderReceived)== FALSE) {
  533. LONG bytesToCopy;
  534. BOOLEAN headerComplete = FALSE;
  535. bytesToCopy = sizeof(ISCSI_GENERIC_HEADER) -
  536. (IScsiConnection->IScsiPacketOffset);
  537. DebugPrint((0, "CHR False. ToCopy : %d, Count : %d\n",
  538. bytesToCopy, byteCount));
  539. if (byteCount < bytesToCopy) {
  540. bytesToCopy = byteCount;
  541. } else {
  542. headerComplete = TRUE;
  543. }
  544. RtlCopyMemory((IScsiConnection->IScsiPacket) +
  545. (IScsiConnection->IScsiPacketOffset),
  546. DataBuffer,
  547. bytesToCopy);
  548. if (headerComplete == FALSE) {
  549. DebugPrint((0, "CHR still FALSE\n"));
  550. IScsiConnection->IScsiPacketOffset += bytesToCopy;
  551. KeReleaseSpinLock(&(IScsiConnection->RequestLock),
  552. oldIrql);
  553. return STATUS_SUCCESS;
  554. } else {
  555. DebugPrint((0, "Header complete\n"));
  556. IScsiConnection->IScsiPacketOffset = 0;
  557. IScsiConnection->CompleteHeaderReceived = TRUE;
  558. byteCount -= bytesToCopy;
  559. ASSERT(byteCount >= 0);
  560. (PUCHAR) DataBuffer += bytesToCopy;
  561. }
  562. } else if (byteCount < sizeof(ISCSI_GENERIC_HEADER)) {
  563. DebugPrint((0,
  564. "Complete header NOT received. Count : %d\n",
  565. byteCount));
  566. IScsiConnection->CompleteHeaderReceived = FALSE;
  567. RtlCopyMemory((IScsiConnection->IScsiPacket),
  568. DataBuffer,
  569. byteCount);
  570. IScsiConnection->IScsiPacketOffset = byteCount;
  571. KeReleaseSpinLock(&(IScsiConnection->RequestLock),
  572. oldIrql);
  573. return STATUS_SUCCESS;
  574. } else {
  575. RtlCopyMemory((IScsiConnection->IScsiPacket),
  576. DataBuffer,
  577. sizeof(ISCSI_GENERIC_HEADER));
  578. byteCount -= sizeof(ISCSI_GENERIC_HEADER);
  579. ASSERT(byteCount >= 0);
  580. (PUCHAR) DataBuffer += sizeof(ISCSI_GENERIC_HEADER);
  581. }
  582. //
  583. // At this point, we should have the complete header
  584. // available
  585. //
  586. iScsiHeader =
  587. (PISCSI_GENERIC_HEADER) (IScsiConnection->IScsiPacket);
  588. opCode = iScsiHeader->OpCode;
  589. //
  590. // Retrieve the length of immediate data
  591. // associated with this iSCSI packet
  592. //
  593. GetUlongFromArray((iScsiHeader->Length),
  594. length);
  595. DebugPrint((3, "Opcode : %x, Length : %x\n",
  596. opCode, length));
  597. switch (opCode) {
  598. case ISCSIOP_SCSI_DATA_READ: {
  599. iScsiDataRead = (PISCSI_SCSI_DATA_READ) iScsiHeader;
  600. GetUlongFromArray((iScsiDataRead->InitiatorTransferTag),
  601. taskTag);
  602. DebugPrint((3, "XfrTag - 0x%08x\n", taskTag));
  603. if ((IScsiConnection->CurrentRequest) == NULL) {
  604. inx = iSpGetActiveClientRequestIndex(
  605. IScsiConnection,
  606. taskTag);
  607. DebugPrint((3, "ActiveClientRequest index : %d\n", inx));
  608. ASSERT((inx <= (IScsiConnection->MaxPendingRequests)));
  609. currentRequest = &(IScsiConnection->ActiveClientRequests[inx]);
  610. IScsiConnection->CurrentRequest = currentRequest;
  611. } else {
  612. DebugPrint((0, "CurrentRequest not null in data\n"));
  613. currentRequest = IScsiConnection->CurrentRequest;
  614. }
  615. currentRequest->CommandStatus = iScsiDataRead->CommandStatus;
  616. //
  617. // If the command status is not SCSISTAT_GOOD, use
  618. // SenseData buffer to read the sense info. Else, use
  619. // RequestBuffer to read input data
  620. //
  621. if ((iScsiDataRead->CommandStatus) != SCSISTAT_GOOD) {
  622. DebugPrint((0, "Command status is %x\n",
  623. iScsiDataRead->CommandStatus));
  624. requestBuffer = currentRequest->SenseData;
  625. } else {
  626. requestBuffer = currentRequest->RequestBuffer;
  627. }
  628. //
  629. // If immediate data is available, copy that
  630. //
  631. if (length != 0) {
  632. ULONG receivedDataLen;
  633. IScsiConnection->ReceiveState = ReceiveData;
  634. if ((LONG)length <= byteCount ) {
  635. receivedDataLen = length;
  636. } else {
  637. receivedDataLen = byteCount;
  638. }
  639. if ((iScsiDataRead->CommandStatus) != SCSISTAT_GOOD) {
  640. ASSERT(receivedDataLen <= sizeof(currentRequest->SenseData));
  641. }
  642. RtlCopyMemory(requestBuffer,
  643. DataBuffer,
  644. receivedDataLen);
  645. (PUCHAR) DataBuffer += receivedDataLen;
  646. byteCount -= receivedDataLen;
  647. ASSERT(byteCount >= 0);
  648. if (byteCount != 0) {
  649. DebugPrint((1, "More bytes available\n"));
  650. }
  651. currentRequest->ExpectedDataLength = length;
  652. currentRequest->RequestBufferOffset = receivedDataLen;
  653. currentRequest->ReceivedDataLength = receivedDataLen;
  654. if ((currentRequest->ExpectedDataLength) ==
  655. currentRequest->ReceivedDataLength) {
  656. IScsiConnection->ReceiveState = ReceiveHeader;
  657. }
  658. }
  659. break;
  660. }
  661. case ISCSIOP_SCSI_RESPONSE: {
  662. BOOLEAN responseComplete = FALSE;
  663. iScsiResponse = (PISCSI_SCSI_RESPONSE) iScsiHeader;
  664. IScsiConnection->ReceiveState = ReceiveHeader;
  665. GetUlongFromArray((iScsiResponse->TaskTag),
  666. taskTag);
  667. DebugPrint((3, "ResTag - 0x%08x\n", taskTag));
  668. if ((IScsiConnection->CurrentRequest) == NULL) {
  669. inx = iSpGetActiveClientRequestIndex(
  670. IScsiConnection,
  671. taskTag);
  672. DebugPrint((3, "ActiveClientRequest index : %d\n", inx));
  673. if (inx > (IScsiConnection->MaxPendingRequests)) {
  674. ULONG cmdRN;
  675. DebugPrint((0,
  676. "Tag : %x. Will use cmdRN to search\n",
  677. taskTag));
  678. GetUlongFromArray((iScsiResponse->ExpCmdRN),
  679. cmdRN);
  680. inx = iSpGetReqIndexUsingCmdRN(IScsiConnection,
  681. (cmdRN - 1));
  682. DebugPrint((0, "Inx returned : 0x%x\n", inx));
  683. }
  684. ASSERT((inx <= (IScsiConnection->MaxPendingRequests)));
  685. currentRequest = &(IScsiConnection->ActiveClientRequests[inx]);
  686. IScsiConnection->CurrentRequest = currentRequest;
  687. } else {
  688. currentRequest = IScsiConnection->CurrentRequest;
  689. }
  690. currentRequest->CommandStatus = iScsiResponse->CmdStatus;
  691. if ((iScsiResponse->CmdStatus) != SCSISTAT_GOOD) {
  692. DebugPrint((0, "Command status is %x. Length : %d\n",
  693. iScsiResponse->CmdStatus,
  694. length));
  695. requestBuffer = currentRequest->SenseData;
  696. } else {
  697. requestBuffer = currentRequest->RequestBuffer;
  698. }
  699. if (length != 0) {
  700. ULONG receivedDataLen;
  701. DebugPrint((3, "Non-zero length in response : %d\n",
  702. length));
  703. IScsiConnection->ReceiveState = ReceiveData;
  704. if ((LONG)length <= byteCount ) {
  705. receivedDataLen = length;
  706. } else {
  707. receivedDataLen = byteCount;
  708. }
  709. if ((iScsiResponse->CmdStatus) != SCSISTAT_GOOD) {
  710. ASSERT(receivedDataLen <= sizeof(currentRequest->SenseData));
  711. }
  712. RtlCopyMemory(requestBuffer,
  713. DataBuffer,
  714. receivedDataLen);
  715. (PUCHAR) DataBuffer += receivedDataLen;
  716. byteCount -= receivedDataLen;
  717. ASSERT(byteCount >= 0);
  718. currentRequest->ExpectedDataLength = length;
  719. currentRequest->RequestBufferOffset = receivedDataLen;
  720. currentRequest->ReceivedDataLength = receivedDataLen;
  721. if ((currentRequest->ExpectedDataLength) ==
  722. currentRequest->ReceivedDataLength) {
  723. IScsiConnection->ReceiveState = ReceiveHeader;
  724. responseComplete = TRUE;
  725. DebugPrint((3, "Response complete. Will process it\n"));
  726. }
  727. } else {
  728. responseComplete = TRUE;
  729. }
  730. //
  731. // Should use this field to determine
  732. // Data Overrun\Underrun cases
  733. //
  734. if ((iScsiResponse->OverFlow) ||
  735. (iScsiResponse->UnderFlow)) {
  736. ULONG residualCount;
  737. GetUlongFromArray((iScsiResponse->ResidualCount),
  738. residualCount);
  739. DebugPrint((0, "Residualcount is : %d\n",
  740. residualCount));
  741. }
  742. if (responseComplete == TRUE) {
  743. if ((iScsiResponse->CmdStatus) != SCSISTAT_GOOD) {
  744. PUCHAR resBuff =
  745. (PUCHAR) (IScsiConnection->IScsiPacket);
  746. ULONG inx0, inx1;
  747. ULONG sizeRequired = sizeof(ISCSI_SCSI_RESPONSE);
  748. DebugPrint((1, "\n Beginning Of Data\n"));
  749. inx0 = 0;
  750. while (inx0 < sizeRequired) {
  751. inx1 = 0;
  752. DebugPrint((1, "\t"));
  753. while ((inx1 < 4) && ((inx0+inx1) < sizeRequired)) {
  754. DebugPrint((1, "%02x ",
  755. resBuff[inx0+inx1]));
  756. inx1++;
  757. }
  758. DebugPrint((1, "\n"));
  759. inx0 += 4;
  760. }
  761. DebugPrint((1, " End Of Data\n"));
  762. }
  763. iSpProcessScsiResponse(
  764. IScsiConnection,
  765. (PISCSI_SCSI_RESPONSE)(IScsiConnection->IScsiPacket));
  766. IScsiConnection->CurrentRequest = NULL;
  767. }
  768. break;
  769. }
  770. case ISCSIOP_NOP_IN_MESSAGE: {
  771. PISCSI_NOP_IN iScsiNopIn = (PISCSI_NOP_IN) iScsiHeader;
  772. IScsiConnection->ReceiveState = ReceiveHeader;
  773. if (iScsiNopIn->Poll) {
  774. //
  775. // Need to handle this case. Should send
  776. // response to the target
  777. //
  778. DebugPrint((0, "Target expects NOP OUT message\n"));
  779. } else {
  780. DebugPrint((1, "No NOP OUT message needed.\n"));
  781. }
  782. break;
  783. }
  784. default: {
  785. ULONG inx0, inx1;
  786. //
  787. // Opcode that we don't currently handle.
  788. // For the timebeing, just dump the iSCSI
  789. // packet.
  790. //
  791. DebugPrint((0, "Unknown opcode : 0x%02x\n", opCode));
  792. inx0 = 0;
  793. while(inx0 < 48) {
  794. inx1 = 0;
  795. DebugPrint((0, "\t"));
  796. while ((inx1 < 4) &&
  797. ((inx0+inx1) < 48)) {
  798. DebugPrint((0, "0x%02x ",
  799. ((PUCHAR)(iScsiHeader))[inx0+inx1]));
  800. inx1++;
  801. }
  802. DebugPrint((0, "\n"));
  803. inx0 += 4;
  804. }
  805. DebugPrint((0, "\n"));
  806. break;
  807. }
  808. } // switch (opCode)
  809. } else {
  810. ULONG bytesToCopy;
  811. UCHAR opCode;
  812. //
  813. // We are receiving the data portion of the packet
  814. //
  815. ASSERT((IScsiConnection->ReceiveState) == ReceiveData);
  816. ASSERT(IScsiConnection->CurrentRequest);
  817. DebugPrint((3, "Receiving data\n"));
  818. currentRequest = IScsiConnection->CurrentRequest;
  819. if ((currentRequest->CommandStatus) != SCSISTAT_GOOD) {
  820. requestBuffer = currentRequest->SenseData;
  821. } else {
  822. requestBuffer = currentRequest->RequestBuffer;
  823. }
  824. requestBuffer += currentRequest->RequestBufferOffset;
  825. bytesToCopy = ((currentRequest->ExpectedDataLength) -
  826. (currentRequest->ReceivedDataLength));
  827. if ((LONG)bytesToCopy > byteCount) {
  828. bytesToCopy = byteCount;
  829. } else {
  830. DebugPrint((3, "More bytes in current buffer than expected\n"));
  831. }
  832. RtlCopyMemory(requestBuffer, DataBuffer, bytesToCopy);
  833. byteCount -= bytesToCopy;
  834. (PUCHAR) DataBuffer += bytesToCopy;
  835. ASSERT(byteCount >= 0);
  836. currentRequest->RequestBufferOffset += bytesToCopy;
  837. currentRequest->ReceivedDataLength += bytesToCopy;
  838. if ((currentRequest->ExpectedDataLength) ==
  839. currentRequest->ReceivedDataLength) {
  840. DebugPrint((3, "Got all data. Bytes left %d\n",
  841. byteCount));
  842. IScsiConnection->ReceiveState = ReceiveHeader;
  843. opCode = IScsiConnection->IScsiPacket[0];
  844. if (opCode == ISCSIOP_SCSI_RESPONSE) {
  845. DebugPrint((3, "Will process the response\n"));
  846. iSpProcessScsiResponse(
  847. IScsiConnection,
  848. (PISCSI_SCSI_RESPONSE)(IScsiConnection->IScsiPacket));
  849. IScsiConnection->CurrentRequest = NULL;
  850. }
  851. }
  852. }
  853. }
  854. KeReleaseSpinLock(&(IScsiConnection->RequestLock),
  855. oldIrql);
  856. return status;
  857. }
  858. ULONG
  859. iSpGetActiveClientRequestIndex(
  860. PISCSI_CONNECTION IScsiConnection,
  861. ULONG TaskTag
  862. )
  863. {
  864. ULONG retIndex = ~0;
  865. ULONG inx;
  866. DebugPrint((3, "Given Task Tag : 0x%08x\n", TaskTag));
  867. for (inx = 1; inx <= (IScsiConnection->MaxPendingRequests); inx++) {
  868. DebugPrint((3, "Index %d : CmdRN - 0x%08x\n",
  869. inx,
  870. ((IScsiConnection->ActiveClientRequests[inx]).TaskTag)));
  871. if (((IScsiConnection->ActiveClientRequests[inx]).TaskTag)
  872. == TaskTag) {
  873. retIndex = inx;
  874. DebugPrint((1, "inx : 0x%04x\n", retIndex));
  875. break;
  876. }
  877. }
  878. if (retIndex > (IScsiConnection->MaxPendingRequests)) {
  879. DebugPrint((0, "Tag : Did not find the request for this response\n"));
  880. }
  881. return retIndex;
  882. }
  883. ULONG
  884. iSpGetReqIndexUsingCmdRN(
  885. PISCSI_CONNECTION IScsiConnection,
  886. ULONG CmdRN
  887. )
  888. {
  889. ULONG retIndex = ~0;
  890. ULONG inx;
  891. DebugPrint((3, "Given CmdRN : 0x%08x\n", CmdRN));
  892. for (inx = 1; inx <= (IScsiConnection->MaxPendingRequests); inx++) {
  893. if (((IScsiConnection->ActiveClientRequests[inx]).CommandRefNum)
  894. == CmdRN) {
  895. retIndex = inx;
  896. DebugPrint((1, "inx : 0x%04x\n", retIndex));
  897. break;
  898. }
  899. }
  900. if (retIndex > (IScsiConnection->MaxPendingRequests)) {
  901. ASSERTMSG("CmdRN : Did not find the request for this response\n",
  902. FALSE);
  903. }
  904. return retIndex;
  905. }