+ goto out;
+ }
+
+ ctask = session->cmds[itt];
+ switch(opcode) {
+ case ISCSI_OP_SCSI_CMD_RSP:
+ if (!ctask->sc) {
+ rc = ISCSI_ERR_NO_SCSI_CMD;
+ break;
+ }
+ BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
+ iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, datalen);
+ break;
+ case ISCSI_OP_SCSI_DATA_IN:
+ if (!ctask->sc) {
+ rc = ISCSI_ERR_NO_SCSI_CMD;
+ break;
+ }
+ BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
+ if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
+ conn->scsirsp_pdus_cnt++;
+ iscsi_update_cmdsn(session,
+ (struct iscsi_nopin*) hdr);
+ __iscsi_put_ctask(ctask);
+ }
+ break;
+ case ISCSI_OP_R2T:
+ /* LLD handles this for now */
+ break;
+ case ISCSI_OP_LOGOUT_RSP:
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+ if (datalen) {
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
+ conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+ goto recv_pdu;
+ case ISCSI_OP_LOGIN_RSP:
+ case ISCSI_OP_TEXT_RSP:
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+ /*
+ * login related PDU's exp_statsn is handled in
+ * userspace
+ */
+ goto recv_pdu;
+ case ISCSI_OP_SCSI_TMFUNC_RSP:
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+ if (datalen) {
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
+
+ iscsi_tmf_rsp(conn, hdr);
+ __iscsi_put_ctask(ctask);
+ break;
+ case ISCSI_OP_NOOP_IN:
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
+ if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
+ conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+
+ if (conn->ping_ctask != ctask)
+ /*
+ * If this is not in response to one of our
+ * nops then it must be from userspace.
+ */
+ goto recv_pdu;
+ __iscsi_put_ctask(ctask);
+ break;
+ default:
+ rc = ISCSI_ERR_BAD_OPCODE;
+ break;
+ }