int isert_pdu_rx(struct iscsi_cmnd *cmnd) { int res = 0; scst_data_direction dir; TRACE_ENTRY(); #ifdef CONFIG_SCST_EXTRACHECKS cmnd->conn->rd_task = current; #endif iscsi_cmnd_init(cmnd->conn, cmnd, NULL); cmnd_rx_start(cmnd); if (unlikely(!cmnd->scst_cmd)) { cmnd_rx_end(cmnd); goto out; } if (unlikely(scst_cmd_prelim_completed(cmnd->scst_cmd) || unlikely(cmnd->prelim_compl_flags != 0))) { set_bit(ISCSI_CMD_PRELIM_COMPLETED, &cmnd->prelim_compl_flags); cmnd_rx_end(cmnd); goto out; } dir = scst_cmd_get_data_direction(cmnd->scst_cmd); if (dir & SCST_DATA_WRITE) { res = iscsi_cmnd_set_write_buf(cmnd); if (unlikely(res)) goto out; res = isert_request_data_out(cmnd); cmnd->r2t_len_to_receive = 0; cmnd->r2t_len_to_send = 0; cmnd->outstanding_r2t = 0; } else { cmnd_rx_end(cmnd); } out: TRACE_EXIT_RES(res); return res; }
/* * Receive write data frame. */ void ft_recv_write_data(struct scst_cmd *cmd, struct fc_frame *fp) { struct ft_cmd *fcmd; struct fc_frame_header *fh; unsigned int bufflen; u32 rel_off; size_t frame_len; size_t mem_len; size_t tlen; void *from; void *to; int dir; u8 *buf; dir = scst_cmd_get_data_direction(cmd); if (dir == SCST_DATA_BIDI) { mem_len = scst_get_out_buf_first(cmd, &buf); bufflen = scst_cmd_get_out_bufflen(cmd); } else { mem_len = scst_get_buf_first(cmd, &buf); bufflen = scst_cmd_get_bufflen(cmd); } to = buf; fcmd = scst_cmd_get_tgt_priv(cmd); fh = fc_frame_header_get(fp); frame_len = fr_len(fp); rel_off = ntohl(fh->fh_parm_offset); FT_IO_DBG("sid %x oxid %x payload_len %zd rel_off %x\n", ntoh24(fh->fh_s_id), ntohs(fh->fh_ox_id), frame_len - sizeof(*fh), rel_off); if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) goto drop; if (frame_len <= sizeof(*fh)) goto drop; frame_len -= sizeof(*fh); from = fc_frame_payload_get(fp, 0); if (rel_off >= bufflen) goto drop; if (frame_len + rel_off > bufflen) frame_len = bufflen - rel_off; while (frame_len) { if (!mem_len) { if (dir == SCST_DATA_BIDI) { scst_put_out_buf(cmd, buf); mem_len = scst_get_out_buf_next(cmd, &buf); } else { scst_put_buf(cmd, buf); mem_len = scst_get_buf_next(cmd, &buf); } to = buf; if (!mem_len) break; } if (rel_off) { if (rel_off >= mem_len) { rel_off -= mem_len; mem_len = 0; continue; } mem_len -= rel_off; to += rel_off; rel_off = 0; } tlen = min(mem_len, frame_len); memcpy(to, from, tlen); from += tlen; frame_len -= tlen; mem_len -= tlen; to += tlen; fcmd->write_data_len += tlen; } if (mem_len) { if (dir == SCST_DATA_BIDI) scst_put_out_buf(cmd, buf); else scst_put_buf(cmd, buf); } if (fcmd->write_data_len == cmd->data_len) scst_rx_data(cmd, SCST_RX_STATUS_SUCCESS, SCST_CONTEXT_THREAD); drop: fc_frame_free(fp); }