/** * iscsi_tcp_data_in - SCSI Data-In Response processing * @conn: iscsi connection * @task: scsi command task */ static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; int datasn = be32_to_cpu(rhdr->datasn); unsigned total_in_length = scsi_in(task->sc)->length; /* * lib iscsi will update this in the completion handling if there * is status. */ if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS)) iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr); if (tcp_conn->in.datalen == 0) return 0; if (tcp_task->exp_datasn != datasn) { ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->datasn(%d)" "\n", tcp_task->exp_datasn, datasn); return ISCSI_ERR_DATASN; } tcp_task->exp_datasn++; tcp_task->data_offset = be32_to_cpu(rhdr->offset); if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) { ISCSI_DBG_TCP(conn, "data_offset(%d) + data_len(%d) > " "total_length_in(%d)\n", tcp_task->data_offset, tcp_conn->in.datalen, total_in_length); return ISCSI_ERR_DATA_OFFSET; } conn->datain_pdus_cnt++; return 0; }
/** * iscsi_tcp_hdr_dissect - process PDU header * @conn: iSCSI connection * @hdr: PDU header * * This function analyzes the header of the PDU received, * and performs several sanity checks. If the PDU is accompanied * by data, the receive buffer is set up to copy the incoming data * to the correct location. */ static int iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) { int rc = 0, opcode, ahslen; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct iscsi_task *task; /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); if (tcp_conn->in.datalen > conn->max_recv_dlength) { iscsi_conn_printk(KERN_ERR, conn, "iscsi_tcp: datalen %d > %d\n", tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } /* Additional header segments. So far, we don't * process additional headers. */ ahslen = hdr->hlength << 2; opcode = hdr->opcode & ISCSI_OPCODE_MASK; /* verify itt (itt encoding: age+cid+itt) */ rc = iscsi_verify_itt(conn, hdr->itt); if (rc) return rc; ISCSI_DBG_TCP(conn, "opcode 0x%x ahslen %d datalen %d\n", opcode, ahslen, tcp_conn->in.datalen); switch(opcode) { case ISCSI_OP_SCSI_DATA_IN: spin_lock(&conn->session->lock); task = iscsi_itt_to_ctask(conn, hdr->itt); if (!task) rc = ISCSI_ERR_BAD_ITT; else rc = iscsi_tcp_data_in(conn, task); if (rc) { spin_unlock(&conn->session->lock); break; } if (tcp_conn->in.datalen) { struct iscsi_tcp_task *tcp_task = task->dd_data; struct hash_desc *rx_hash = NULL; struct scsi_data_buffer *sdb = scsi_in(task->sc); /* * Setup copy of Data-In into the Scsi_Cmnd * Scatterlist case: * We set up the iscsi_segment to point to the next * scatterlist entry to copy to. As we go along, * we move on to the next scatterlist entry and * update the digest per-entry. */ if (conn->datadgst_en && !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) rx_hash = tcp_conn->rx_hash; ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( " "offset=%d, datalen=%d)\n", tcp_task->data_offset, tcp_conn->in.datalen); task->last_xfer = jiffies; rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, sdb->table.sgl, sdb->table.nents, tcp_task->data_offset, tcp_conn->in.datalen, iscsi_tcp_process_data_in, rx_hash); spin_unlock(&conn->session->lock); return rc; } rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); spin_unlock(&conn->session->lock); break; case ISCSI_OP_SCSI_CMD_RSP: if (tcp_conn->in.datalen) { iscsi_tcp_data_recv_prep(tcp_conn); return 0; } rc = iscsi_complete_pdu(conn, hdr, NULL, 0); break; case ISCSI_OP_R2T: spin_lock(&conn->session->lock); task = iscsi_itt_to_ctask(conn, hdr->itt); if (!task) rc = ISCSI_ERR_BAD_ITT; else if (ahslen) rc = ISCSI_ERR_AHSLEN; else if (task->sc->sc_data_direction == DMA_TO_DEVICE) { task->last_xfer = jiffies; rc = iscsi_tcp_r2t_rsp(conn, task); } else rc = ISCSI_ERR_PROTO; spin_unlock(&conn->session->lock); break; case ISCSI_OP_LOGIN_RSP: case ISCSI_OP_TEXT_RSP: case ISCSI_OP_REJECT: case ISCSI_OP_ASYNC_EVENT: /* * It is possible that we could get a PDU with a buffer larger * than 8K, but there are no targets that currently do this. * For now we fail until we find a vendor that needs it */ if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { iscsi_conn_printk(KERN_ERR, conn, "iscsi_tcp: received buffer of " "len %u but conn buffer is only %u " "(opcode %0x)\n", tcp_conn->in.datalen, ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); rc = ISCSI_ERR_PROTO; break; } /* If there's data coming in with the response, * receive it to the connection's buffer. */ if (tcp_conn->in.datalen) { iscsi_tcp_data_recv_prep(tcp_conn); return 0; } /* fall through */ case ISCSI_OP_LOGOUT_RSP: case ISCSI_OP_NOOP_IN: case ISCSI_OP_SCSI_TMFUNC_RSP: rc = iscsi_complete_pdu(conn, hdr, NULL, 0); break; default: rc = ISCSI_ERR_BAD_OPCODE; break; } if (rc == 0) { /* Anything that comes with data should have * been handled above. */ if (tcp_conn->in.datalen) return ISCSI_ERR_PROTO; iscsi_tcp_hdr_recv_prep(tcp_conn); } return rc; }
static void tcm_loop_submission_work(struct work_struct *work) { struct tcm_loop_cmd *tl_cmd = container_of(work, struct tcm_loop_cmd, work); struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd; struct scsi_cmnd *sc = tl_cmd->sc; struct tcm_loop_nexus *tl_nexus; struct tcm_loop_hba *tl_hba; struct tcm_loop_tpg *tl_tpg; struct scatterlist *sgl_bidi = NULL; u32 sgl_bidi_count = 0; int ret; tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; /* * Ensure that this tl_tpg reference from the incoming sc->device->id * has already been configured via tcm_loop_make_naa_tpg(). */ if (!tl_tpg->tl_hba) { set_host_byte(sc, DID_NO_CONNECT); goto out_done; } tl_nexus = tl_hba->tl_nexus; if (!tl_nexus) { scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" " does not exist\n"); set_host_byte(sc, DID_ERROR); goto out_done; } transport_init_se_cmd(se_cmd, tl_tpg->tl_se_tpg.se_tpg_tfo, tl_nexus->se_sess, scsi_bufflen(sc), sc->sc_data_direction, tcm_loop_sam_attr(sc), &tl_cmd->tl_sense_buf[0]); if (scsi_bidi_cmnd(sc)) { struct scsi_data_buffer *sdb = scsi_in(sc); sgl_bidi = sdb->table.sgl; sgl_bidi_count = sdb->table.nents; se_cmd->se_cmd_flags |= SCF_BIDI; } if (transport_lookup_cmd_lun(se_cmd, tl_cmd->sc->device->lun) < 0) { kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); set_host_byte(sc, DID_NO_CONNECT); goto out_done; } /* * Because some userspace code via scsi-generic do not memset their * associated read buffers, go ahead and do that here for type * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB * by target core in target_setup_cmd_from_cdb() -> * transport_generic_cmd_sequencer(). */ if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && se_cmd->data_direction == DMA_FROM_DEVICE) { struct scatterlist *sg = scsi_sglist(sc); unsigned char *buf = kmap(sg_page(sg)) + sg->offset; if (buf != NULL) { memset(buf, 0, sg->length); kunmap(sg_page(sg)); } } ret = target_setup_cmd_from_cdb(se_cmd, sc->cmnd); if (ret == -ENOMEM) { transport_send_check_condition_and_sense(se_cmd, TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); transport_generic_free_cmd(se_cmd, 0); return; } else if (ret < 0) { if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) tcm_loop_queue_status(se_cmd); else transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); transport_generic_free_cmd(se_cmd, 0); return; } ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), scsi_sg_count(sc), sgl_bidi, sgl_bidi_count); if (ret) { transport_send_check_condition_and_sense(se_cmd, se_cmd->scsi_sense_reason, 0); transport_generic_free_cmd(se_cmd, 0); return; } transport_handle_cdb_direct(se_cmd); return; out_done: sc->scsi_done(sc); return; }
/* * Called by struct target_core_fabric_ops->new_cmd_map() * * Always called in process context. A non zero return value * here will signal to handle an exception based on the return code. */ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) { struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, struct tcm_loop_cmd, tl_se_cmd); struct scsi_cmnd *sc = tl_cmd->sc; struct scatterlist *sgl_bidi = NULL; u32 sgl_bidi_count = 0; int ret; /* * Allocate the necessary tasks to complete the received CDB+data */ ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd); if (ret == -ENOMEM) { /* Out of Resources */ return PYX_TRANSPORT_LU_COMM_FAILURE; } else if (ret == -EINVAL) { /* * Handle case for SAM_STAT_RESERVATION_CONFLICT */ if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) return PYX_TRANSPORT_RESERVATION_CONFLICT; /* * Otherwise, return SAM_STAT_CHECK_CONDITION and return * sense data. */ return PYX_TRANSPORT_USE_SENSE_REASON; } /* * For BIDI commands, pass in the extra READ buffer * to transport_generic_map_mem_to_cmd() below.. */ if (se_cmd->t_tasks_bidi) { struct scsi_data_buffer *sdb = scsi_in(sc); sgl_bidi = sdb->table.sgl; sgl_bidi_count = sdb->table.nents; } /* * Because some userspace code via scsi-generic do not memset their * associated read buffers, go ahead and do that here for type * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB * by target core in transport_generic_allocate_tasks() -> * transport_generic_cmd_sequencer(). */ if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && se_cmd->data_direction == DMA_FROM_DEVICE) { struct scatterlist *sg = scsi_sglist(sc); unsigned char *buf = kmap(sg_page(sg)) + sg->offset; if (buf != NULL) { memset(buf, 0, sg->length); kunmap(sg_page(sg)); } } /* Tell the core about our preallocated memory */ ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), scsi_sg_count(sc), sgl_bidi, sgl_bidi_count); if (ret < 0) return PYX_TRANSPORT_LU_COMM_FAILURE; return 0; }
static void tcm_loop_submission_work(struct work_struct *work) { struct tcm_loop_cmd *tl_cmd = container_of(work, struct tcm_loop_cmd, work); struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd; struct scsi_cmnd *sc = tl_cmd->sc; struct tcm_loop_nexus *tl_nexus; struct tcm_loop_hba *tl_hba; struct tcm_loop_tpg *tl_tpg; struct scatterlist *sgl_bidi = NULL; u32 sgl_bidi_count = 0, transfer_length; int rc; tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; /* * Ensure that this tl_tpg reference from the incoming sc->device->id * has already been configured via tcm_loop_make_naa_tpg(). */ if (!tl_tpg->tl_hba) { set_host_byte(sc, DID_NO_CONNECT); goto out_done; } if (tl_tpg->tl_transport_status == TCM_TRANSPORT_OFFLINE) { set_host_byte(sc, DID_TRANSPORT_DISRUPTED); goto out_done; } tl_nexus = tl_hba->tl_nexus; if (!tl_nexus) { scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" " does not exist\n"); set_host_byte(sc, DID_ERROR); goto out_done; } if (scsi_bidi_cmnd(sc)) { struct scsi_data_buffer *sdb = scsi_in(sc); sgl_bidi = sdb->table.sgl; sgl_bidi_count = sdb->table.nents; se_cmd->se_cmd_flags |= SCF_BIDI; } transfer_length = scsi_transfer_length(sc); if (!scsi_prot_sg_count(sc) && scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) { se_cmd->prot_pto = true; /* * loopback transport doesn't support * WRITE_GENERATE, READ_STRIP protection * information operations, go ahead unprotected. */ transfer_length = scsi_bufflen(sc); } rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, transfer_length, tcm_loop_sam_attr(sc), sc->sc_data_direction, 0, scsi_sglist(sc), scsi_sg_count(sc), sgl_bidi, sgl_bidi_count, scsi_prot_sglist(sc), scsi_prot_sg_count(sc)); if (rc < 0) { set_host_byte(sc, DID_NO_CONNECT); goto out_done; } return; out_done: sc->scsi_done(sc); return; }
/* * Called by struct target_core_fabric_ops->new_cmd_map() * * Always called in process context. A non zero return value * here will signal to handle an exception based on the return code. */ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) { struct tcm_loop_cmd *tl_cmd = container_of(se_cmd, struct tcm_loop_cmd, tl_se_cmd); struct scsi_cmnd *sc = tl_cmd->sc; void *mem_ptr, *mem_bidi_ptr = NULL; u32 sg_no_bidi = 0; int ret; /* * Allocate the necessary tasks to complete the received CDB+data */ ret = transport_generic_allocate_tasks(se_cmd, tl_cmd->sc->cmnd); if (ret == -1) { /* Out of Resources */ return PYX_TRANSPORT_LU_COMM_FAILURE; } else if (ret == -2) { /* * Handle case for SAM_STAT_RESERVATION_CONFLICT */ if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) return PYX_TRANSPORT_RESERVATION_CONFLICT; /* * Otherwise, return SAM_STAT_CHECK_CONDITION and return * sense data. */ return PYX_TRANSPORT_USE_SENSE_REASON; } /* * Setup the struct scatterlist memory from the received * struct scsi_cmnd. */ if (scsi_sg_count(sc)) { se_cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM; mem_ptr = (void *)scsi_sglist(sc); /* * For BIDI commands, pass in the extra READ buffer * to transport_generic_map_mem_to_cmd() below.. */ if (T_TASK(se_cmd)->t_tasks_bidi) { struct scsi_data_buffer *sdb = scsi_in(sc); mem_bidi_ptr = (void *)sdb->table.sgl; sg_no_bidi = sdb->table.nents; } } else { /* * Used for DMA_NONE */ mem_ptr = NULL; } /* * Map the SG memory into struct se_mem->page linked list using the same * physical memory at sg->page_link. */ ret = transport_generic_map_mem_to_cmd(se_cmd, mem_ptr, scsi_sg_count(sc), mem_bidi_ptr, sg_no_bidi); if (ret < 0) return PYX_TRANSPORT_LU_COMM_FAILURE; return 0; }
/* Lecture de la taille d'un lead-in et d'un lead-out d'une session */ int philips_read_session_info( unsigned short buf[2] ) { return scsi_in( set_cmd( 10, 0xEE, 0, 4, buf, 4 ) ); }