int digest_rx_data(struct iscsi_cmnd *cmnd) { struct tio *tio; struct iscsi_cmnd *scsi_cmnd; struct iscsi_data_out_hdr *req; u32 offset, crc; switch (cmnd_opcode(cmnd)) { case ISCSI_OP_SCSI_REJECT: case ISCSI_OP_PDU_REJECT: case ISCSI_OP_DATA_REJECT: return 0; case ISCSI_OP_SCSI_DATA_OUT: scsi_cmnd = cmnd->req; req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs; tio = scsi_cmnd->tio; offset = be32_to_cpu(req->buffer_offset); break; default: tio = cmnd->tio; offset = 0; } digest_data(&cmnd->conn->rx_hash, cmnd, tio, offset, (u8 *) &crc); if (!cmnd->conn->read_overflow && (cmnd_opcode(cmnd) != ISCSI_OP_PDU_REJECT)) { if (crc != cmnd->ddigest) return -EIO; } return 0; }
/** * debug handling of header digest errors: * simulates a digest error after n PDUs / every n-th PDU of type * HDIGEST_ERR_CORRUPT_PDU_TYPE. */ static inline void __dbg_simulate_header_digest_error(struct iscsi_cmnd *cmnd) { #define HDIGEST_ERR_AFTER_N_CMNDS 1000 #define HDIGEST_ERR_ONLY_ONCE 1 #define HDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_CMD #define HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY 0 static int num_cmnds = 0; static int num_errs = 0; if (cmnd_opcode(cmnd) == HDIGEST_ERR_CORRUPT_PDU_TYPE) { if (HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY) { if (cmnd->pdu.datasize) num_cmnds++; } else num_cmnds++; } if ((num_cmnds == HDIGEST_ERR_AFTER_N_CMNDS) && (!(HDIGEST_ERR_ONLY_ONCE && num_errs))) { printk("*** Faking header digest error ***\n"); printk("\tcmnd: 0x%x, itt 0x%x, sn 0x%x\n", cmnd_opcode(cmnd), be32_to_cpu(cmnd->pdu.bhs.itt), be32_to_cpu(cmnd->pdu.bhs.sn)); cmnd->hdigest = ~cmnd->hdigest; /* make things even worse by manipulating header fields */ cmnd->pdu.datasize += 8; num_errs++; num_cmnds = 0; } return; }
static void isert_update_len_sn(struct iscsi_cmnd *cmnd) { TRACE_ENTRY(); iscsi_cmnd_set_length(&cmnd->pdu); switch (cmnd_opcode(cmnd)) { case ISCSI_OP_NOP_IN: if (cmnd->pdu.bhs.itt == ISCSI_RESERVED_TAG) cmnd->pdu.bhs.sn = (__force u32)cmnd_set_sn(cmnd, 0); else cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_SCSI_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_SCSI_TASK_MGT_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_TEXT_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_SCSI_DATA_IN: { struct iscsi_data_in_hdr *rsp = (struct iscsi_data_in_hdr *)&cmnd->pdu.bhs; cmnd_set_sn(cmnd, (rsp->flags & ISCSI_FLG_FINAL) ? 1 : 0); break; } case ISCSI_OP_LOGOUT_RSP: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_R2T: cmnd->pdu.bhs.sn = (__force u32)cmnd_set_sn(cmnd, 0); break; case ISCSI_OP_ASYNC_MSG: cmnd_set_sn(cmnd, 1); break; case ISCSI_OP_REJECT: cmnd_set_sn(cmnd, 1); break; default: PRINT_ERROR("Unexpected cmnd op %x", cmnd_opcode(cmnd)); break; } TRACE_EXIT(); }
/** * debug handling of data digest errors: * simulates a digest error after n PDUs / every n-th PDU of type * DDIGEST_ERR_CORRUPT_PDU_TYPE. */ static inline void __dbg_simulate_data_digest_error(struct iscsi_cmnd *cmnd) { #define DDIGEST_ERR_AFTER_N_CMNDS 50 #define DDIGEST_ERR_ONLY_ONCE 1 #define DDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_DATA_OUT #define DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY 0 static int num_cmnds = 0; static int num_errs = 0; if ((cmnd->pdu.datasize) && (cmnd_opcode(cmnd) == DDIGEST_ERR_CORRUPT_PDU_TYPE)) { switch (cmnd_opcode(cmnd)) { case ISCSI_OP_SCSI_DATA_OUT: if ((DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY) && (cmnd->pdu.bhs.ttt != ISCSI_RESERVED_TAG)) break; default: num_cmnds++; } } if ((num_cmnds == DDIGEST_ERR_AFTER_N_CMNDS) && (!(DDIGEST_ERR_ONLY_ONCE && num_errs)) && (cmnd->pdu.datasize) && (!cmnd->conn->read_overflow)) { printk("*** Faking data digest error: ***"); printk("\tcmnd 0x%x, itt 0x%x, sn 0x%x\n", cmnd_opcode(cmnd), be32_to_cpu(cmnd->pdu.bhs.itt), be32_to_cpu(cmnd->pdu.bhs.sn)); cmnd->ddigest = ~cmnd->ddigest; num_errs++; num_cmnds = 0; } }