/* * Send TX_RDY (transfer ready). */ int ft_write_pending(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct fc_frame *fp; struct fcp_txrdy *txrdy; struct fc_lport *lport; struct fc_exch *ep; struct fc_frame_header *fh; u32 f_ctl; ft_dump_cmd(cmd, __func__); ep = fc_seq_exch(cmd->seq); lport = ep->lp; fp = fc_frame_alloc(lport, sizeof(*txrdy)); if (!fp) return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); memset(txrdy, 0, sizeof(*txrdy)); txrdy->ft_burst_len = htonl(se_cmd->data_length); cmd->seq = lport->tt.seq_start_next(cmd->seq); fc_fill_fc_hdr(fp, FC_RCTL_DD_DATA_DESC, ep->did, ep->sid, FC_TYPE_FCP, FC_FC_EX_CTX | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); fh = fc_frame_header_get(fp); f_ctl = ntoh24(fh->fh_f_ctl); /* Only if it is 'Exchange Responder' */ if (f_ctl & FC_FC_EX_CTX) { /* Target is 'exchange responder' and sending XFER_READY * to 'exchange initiator (initiator)' */ if ((ep->xid <= lport->lro_xid) && (fh->fh_r_ctl == FC_RCTL_DD_DATA_DESC)) { if (se_cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) { /* * Map se_mem list to scatterlist, so that * DDP can be setup. DDP setup function require * scatterlist. se_mem_list is internal to * TCM/LIO target */ transport_do_task_sg_chain(se_cmd); cmd->sg = T_TASK(se_cmd)->t_tasks_sg_chained; cmd->sg_cnt = T_TASK(se_cmd)->t_tasks_sg_chained_no; } if (cmd->sg && lport->tt.ddp_setup(lport, ep->xid, cmd->sg, cmd->sg_cnt)) cmd->was_ddp_setup = 1; } } lport->tt.seq_send(lport, cmd->seq, fp); return 0; }
/* * Deliver read data back to initiator. * XXX TBD handle resource problems later. */ int ft_queue_data_in(struct se_cmd *se_cmd) { struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); struct se_transport_task *task; struct fc_frame *fp = NULL; struct fc_exch *ep; struct fc_lport *lport; struct se_mem *mem; size_t remaining; u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF; u32 mem_off; u32 fh_off = 0; u32 frame_off = 0; size_t frame_len = 0; size_t mem_len; size_t tlen; size_t off_in_page; struct page *page; int use_sg; int error; void *page_addr; void *from; void *to = NULL; ep = fc_seq_exch(cmd->seq); lport = ep->lp; cmd->seq = lport->tt.seq_start_next(cmd->seq); task = T_TASK(se_cmd); BUG_ON(!task); remaining = se_cmd->data_length; /* * Setup to use first mem list entry if any. */ if (task->t_tasks_se_num) { mem = list_first_entry(task->t_mem_list, struct se_mem, se_list); mem_len = mem->se_len; mem_off = mem->se_off; page = mem->se_page; } else {
/* * Dump cmd state for debugging. */ void ft_dump_cmd(struct ft_cmd *cmd, const char *caller) { struct fc_exch *ep; struct fc_seq *sp; struct se_cmd *se_cmd; struct se_mem *mem; struct se_transport_task *task; if (!(ft_debug_logging & FT_DEBUG_IO)) return; se_cmd = &cmd->se_cmd; // printk(KERN_INFO "%s: cmd %p state %d sess %p seq %p se_cmd %p\n", ; // printk(KERN_INFO "%s: cmd %p cdb %p\n", ; ; task = T_TASK(se_cmd); // printk(KERN_INFO "%s: cmd %p task %p se_num %u buf %p len %u se_cmd_flags <0x%x>\n", // caller, cmd, task, task->t_tasks_se_num, ; if (task->t_mem_list) list_for_each_entry(mem, task->t_mem_list, se_list) // printk(KERN_INFO "%s: cmd %p mem %p page %p " // "len 0x%x off 0x%x\n", // caller, cmd, mem, ; sp = cmd->seq; if (sp) { ep = fc_seq_exch(sp); // printk(KERN_INFO "%s: cmd %p sid %x did %x " // "ox_id %x rx_id %x seq_id %x e_stat %x\n", // caller, cmd, ep->sid, ep->did, ep->oxid, ep->rxid, ; } print_hex_dump(KERN_INFO, "ft_dump_cmd ", DUMP_PREFIX_NONE, 16, 4, cmd->cdb, MAX_COMMAND_SIZE, 0); }
/* * Allocate a tcm_loop cmd descriptor from target_core_mod code * * Can be called from interrupt context in tcm_loop_queuecommand() below */ static struct se_cmd *tcm_loop_allocate_core_cmd( struct tcm_loop_hba *tl_hba, struct se_portal_group *se_tpg, struct scsi_cmnd *sc) { struct se_cmd *se_cmd; struct se_session *se_sess; struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; struct tcm_loop_cmd *tl_cmd; int sam_task_attr; if (!tl_nexus) { scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" " does not exist\n"); set_host_byte(sc, DID_ERROR); return NULL; } se_sess = tl_nexus->se_sess; tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); if (!tl_cmd) { printk(KERN_ERR "Unable to allocate struct tcm_loop_cmd\n"); set_host_byte(sc, DID_ERROR); return NULL; } se_cmd = &tl_cmd->tl_se_cmd; /* * Save the pointer to struct scsi_cmnd *sc */ tl_cmd->sc = sc; /* * Locate the SAM Task Attr from struct scsi_cmnd * */ if (sc->device->tagged_supported) { switch (sc->tag) { case HEAD_OF_QUEUE_TAG: sam_task_attr = MSG_HEAD_TAG; break; case ORDERED_QUEUE_TAG: sam_task_attr = MSG_ORDERED_TAG; break; default: sam_task_attr = MSG_SIMPLE_TAG; break; } } else sam_task_attr = MSG_SIMPLE_TAG; /* * Initialize struct se_cmd descriptor from target_core_mod infrastructure */ transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, &tl_cmd->tl_sense_buf[0]); /* * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi */ if (scsi_bidi_cmnd(sc)) T_TASK(se_cmd)->t_tasks_bidi = 1; /* * Locate the struct se_lun pointer and attach it to struct se_cmd */ if (transport_get_lun_for_cmd(se_cmd, NULL, tl_cmd->sc->device->lun) < 0) { kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); set_host_byte(sc, DID_NO_CONNECT); return NULL; } /* * 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)); } } transport_device_setup_cmd(se_cmd); return se_cmd; }
/* * 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; }
/* * Allocate a tcm_loop cmd descriptor from target_core_mod code * * Can be called from interrupt context in tcm_loop_queuecommand() below */ static struct se_cmd *tcm_loop_allocate_core_cmd( struct tcm_loop_hba *tl_hba, struct se_portal_group *se_tpg, struct scsi_cmnd *sc) { struct se_cmd *se_cmd; struct se_session *se_sess; struct tcm_loop_nexus *tl_nexus = tl_hba->tl_nexus; struct tcm_loop_cmd *tl_cmd; int sam_task_attr; if (!tl_nexus) { scmd_printk(KERN_ERR, sc, "TCM_Loop I_T Nexus" " does not exist\n"); set_host_byte(sc, DID_ERROR); return NULL; } se_sess = tl_nexus->se_sess; tl_cmd = kmem_cache_zalloc(tcm_loop_cmd_cache, GFP_ATOMIC); if (!tl_cmd) { printk(KERN_ERR "Unable to allocate struct tcm_loop_cmd\n"); set_host_byte(sc, DID_ERROR); return NULL; } se_cmd = &tl_cmd->tl_se_cmd; /* * Save the pointer to struct scsi_cmnd *sc */ tl_cmd->sc = sc; /* * Locate the SAM Task Attr from struct scsi_cmnd * */ if (sc->device->tagged_supported) { switch (sc->tag) { case HEAD_OF_QUEUE_TAG: sam_task_attr = TASK_ATTR_HOQ; break; case ORDERED_QUEUE_TAG: sam_task_attr = TASK_ATTR_ORDERED; break; default: sam_task_attr = TASK_ATTR_SIMPLE; break; } } else sam_task_attr = TASK_ATTR_SIMPLE; /* * Initialize struct se_cmd descriptor from target_core_mod infrastructure */ transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, &tl_cmd->tl_sense_buf[0]); /* * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi */ if (scsi_bidi_cmnd(sc)) T_TASK(se_cmd)->t_tasks_bidi = 1; /* * Locate the struct se_lun pointer and attach it to struct se_cmd */ if (transport_get_lun_for_cmd(se_cmd, NULL, tl_cmd->sc->device->lun) < 0) { kmem_cache_free(tcm_loop_cmd_cache, tl_cmd); set_host_byte(sc, DID_NO_CONNECT); return NULL; } transport_device_setup_cmd(se_cmd); return se_cmd; }