diff --git a/scst/include/scst.h b/scst/include/scst.h index 2668e001c..25d69f9d6 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -1808,6 +1808,7 @@ struct scst_cmd { int *write_sg_cnt; /* scst_get_sg_buf_[first,next]() support */ + struct scatterlist *get_sg_buf_cur_sg_entry; int get_sg_buf_entry_num; /* Bidirectional transfers support */ @@ -3345,31 +3346,35 @@ enum scst_sg_copy_dir { void scst_copy_sg(struct scst_cmd *cmd, enum scst_sg_copy_dir copy_dir); /* - * Functions for access to the commands data (SG) buffer, - * including HIGHMEM environment. Should be used instead of direct - * access. Returns the mapped buffer length for success, 0 for EOD, + * Functions for access to the commands data (SG) buffer. Should be used + * instead of direct access. Returns the buffer length for success, 0 for EOD, * negative error code otherwise. * * "Buf" argument returns the mapped buffer * * The "put" function unmaps the buffer. */ -static inline int __scst_get_buf(struct scst_cmd *cmd, struct scatterlist *sg, - int sg_cnt, uint8_t **buf) +static inline int __scst_get_buf(struct scst_cmd *cmd, int sg_cnt, + uint8_t **buf) { int res = 0; - int i = cmd->get_sg_buf_entry_num; + struct scatterlist *sg = cmd->get_sg_buf_cur_sg_entry; *buf = NULL; - if ((i >= sg_cnt) || unlikely(sg == NULL)) + if (cmd->get_sg_buf_entry_num >= sg_cnt) goto out; - *buf = page_address(sg_page(&sg[i])); - *buf += sg[i].offset; + if (unlikely(sg_is_chain(sg))) + sg = sg_chain_ptr(sg); + + *buf = page_address(sg_page(sg)); + *buf += sg->offset; + + res = sg->length; - res = sg[i].length; cmd->get_sg_buf_entry_num++; + cmd->get_sg_buf_cur_sg_entry = ++sg; out: return res; @@ -3377,14 +3382,17 @@ out: static inline int scst_get_buf_first(struct scst_cmd *cmd, uint8_t **buf) { + if (unlikely(cmd->sg == NULL)) + return 0; cmd->get_sg_buf_entry_num = 0; + cmd->get_sg_buf_cur_sg_entry = cmd->sg; cmd->may_need_dma_sync = 1; - return __scst_get_buf(cmd, cmd->sg, cmd->sg_cnt, buf); + return __scst_get_buf(cmd, cmd->sg_cnt, buf); } static inline int scst_get_buf_next(struct scst_cmd *cmd, uint8_t **buf) { - return __scst_get_buf(cmd, cmd->sg, cmd->sg_cnt, buf); + return __scst_get_buf(cmd, cmd->sg_cnt, buf); } static inline void scst_put_buf(struct scst_cmd *cmd, void *buf) @@ -3394,14 +3402,17 @@ static inline void scst_put_buf(struct scst_cmd *cmd, void *buf) static inline int scst_get_out_buf_first(struct scst_cmd *cmd, uint8_t **buf) { + if (unlikely(cmd->out_sg == NULL)) + return 0; cmd->get_sg_buf_entry_num = 0; + cmd->get_sg_buf_cur_sg_entry = cmd->out_sg; cmd->may_need_dma_sync = 1; - return __scst_get_buf(cmd, cmd->out_sg, cmd->out_sg_cnt, buf); + return __scst_get_buf(cmd, cmd->out_sg_cnt, buf); } static inline int scst_get_out_buf_next(struct scst_cmd *cmd, uint8_t **buf) { - return __scst_get_buf(cmd, cmd->out_sg, cmd->out_sg_cnt, buf); + return __scst_get_buf(cmd, cmd->out_sg_cnt, buf); } static inline void scst_put_out_buf(struct scst_cmd *cmd, void *buf) @@ -3412,15 +3423,18 @@ static inline void scst_put_out_buf(struct scst_cmd *cmd, void *buf) static inline int scst_get_sg_buf_first(struct scst_cmd *cmd, uint8_t **buf, struct scatterlist *sg, int sg_cnt) { + if (unlikely(sg == NULL)) + return 0; cmd->get_sg_buf_entry_num = 0; + cmd->get_sg_buf_cur_sg_entry = cmd->sg; cmd->may_need_dma_sync = 1; - return __scst_get_buf(cmd, sg, sg_cnt, buf); + return __scst_get_buf(cmd, sg_cnt, buf); } static inline int scst_get_sg_buf_next(struct scst_cmd *cmd, uint8_t **buf, struct scatterlist *sg, int sg_cnt) { - return __scst_get_buf(cmd, sg, sg_cnt, buf); + return __scst_get_buf(cmd, sg_cnt, buf); } static inline void scst_put_sg_buf(struct scst_cmd *cmd, void *buf, diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index d16de7bed..34868f20c 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -2028,30 +2028,36 @@ next: static void scst_adjust_sg(struct scst_cmd *cmd, struct scatterlist *sg, int *sg_cnt, int adjust_len) { - int i, l; + int i, j, l; TRACE_ENTRY(); l = 0; - for (i = 0; i < *sg_cnt; i++) { - l += sg[i].length; + for (i = 0, j = 0; i < *sg_cnt; i++, j++) { + TRACE_DBG("i %d, j %d, sg_cnt %d, sg %p, page_link %lx", i, j, + *sg_cnt, sg, sg[j].page_link); + if (unlikely(sg_is_chain(&sg[j]))) { + sg = sg_chain_ptr(&sg[j]); + j = 0; + } + l += sg[j].length; if (l >= adjust_len) { - int left = adjust_len - (l - sg[i].length); + int left = adjust_len - (l - sg[j].length); #ifdef CONFIG_SCST_DEBUG TRACE(TRACE_SG_OP|TRACE_MEMORY, "cmd %p (tag %llu), " - "sg %p, sg_cnt %d, adjust_len %d, i %d, " - "sg[i].length %d, left %d", + "sg %p, sg_cnt %d, adjust_len %d, i %d, j %d, " + "sg[j].length %d, left %d", cmd, (long long unsigned int)cmd->tag, - sg, *sg_cnt, adjust_len, i, - sg[i].length, left); + sg, *sg_cnt, adjust_len, i, j, + sg[j].length, left); #endif cmd->orig_sg = sg; cmd->p_orig_sg_cnt = sg_cnt; cmd->orig_sg_cnt = *sg_cnt; - cmd->orig_sg_entry = i; - cmd->orig_entry_len = sg[i].length; - *sg_cnt = (left > 0) ? i+1 : i; - sg[i].length = left; + cmd->orig_sg_entry = j; + cmd->orig_entry_len = sg[j].length; + *sg_cnt = (left > 0) ? j+1 : j; + sg[j].length = left; cmd->sg_buff_modified = 1; break; } diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 0675f412c..e68b7b0ca 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1332,7 +1332,7 @@ void scst_rx_data(struct scst_cmd *cmd, int status, case SCST_RX_STATUS_SUCCESS: #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) if (trace_flag & TRACE_RCV_BOT) { - int i; + int i, j; struct scatterlist *sg; if (cmd->out_sg != NULL) sg = cmd->out_sg; @@ -1347,9 +1347,13 @@ void scst_rx_data(struct scst_cmd *cmd, int status, "(sg_cnt %d, sg %p, sg[0].page %p)", cmd, cmd->tgt_sg_cnt, sg, (void *)sg_page(&sg[0])); - for (i = 0; i < cmd->tgt_sg_cnt; ++i) { + for (i = 0, j = 0; i < cmd->tgt_sg_cnt; ++i, ++j) { + if (unlikely(sg_is_chain(&sg[j]))) { + sg = sg_chain_ptr(&sg[j]); + j = 0; + } PRINT_BUFF_FLAG(TRACE_RCV_BOT, "RX sg", - sg_virt(&sg[i]), sg[i].length); + sg_virt(&sg[j]), sg[j].length); } } } @@ -1607,14 +1611,18 @@ static void scst_cmd_done_local(struct scst_cmd *cmd, int next_state, #if defined(CONFIG_SCST_DEBUG) if (next_state == SCST_CMD_STATE_PRE_DEV_DONE) { if ((trace_flag & TRACE_RCV_TOP) && (cmd->sg != NULL)) { - int i; + int i, j; struct scatterlist *sg = cmd->sg; TRACE_RECV_TOP("Exec'd %d S/G(s) at %p sg[0].page at " "%p", cmd->sg_cnt, sg, (void *)sg_page(&sg[0])); - for (i = 0; i < cmd->sg_cnt; ++i) { + for (i = 0, j = 0; i < cmd->sg_cnt; ++i, ++j) { + if (unlikely(sg_is_chain(&sg[j]))) { + sg = sg_chain_ptr(&sg[j]); + j = 0; + } TRACE_BUFF_FLAG(TRACE_RCV_TOP, - "Exec'd sg", sg_virt(&sg[i]), - sg[i].length); + "Exec'd sg", sg_virt(&sg[j]), + sg[j].length); } } } @@ -3480,7 +3488,7 @@ static int scst_xmit_response(struct scst_cmd *cmd) #if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) if (trace_flag & TRACE_SND_BOT) { - int i; + int i, j; struct scatterlist *sg; if (cmd->tgt_sg != NULL) sg = cmd->tgt_sg; @@ -3491,10 +3499,14 @@ static int scst_xmit_response(struct scst_cmd *cmd) "(sg_cnt %d, sg %p, sg[0].page %p)", cmd, cmd->tgt_sg_cnt, sg, (void *)sg_page(&sg[0])); - for (i = 0; i < cmd->tgt_sg_cnt; ++i) { + for (i = 0, j = 0; i < cmd->tgt_sg_cnt; ++i, ++j) { + if (unlikely(sg_is_chain(&sg[j]))) { + sg = sg_chain_ptr(&sg[j]); + j = 0; + } PRINT_BUFF_FLAG(TRACE_SND_BOT, - "Xmitting sg", sg_virt(&sg[i]), - sg[i].length); + "Xmitting sg", sg_virt(&sg[j]), + sg[j].length); } } } diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index 442a05a1d..bf0ec4256 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -43,10 +43,6 @@ #include #endif -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)) -#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist)) -#endif - #ifndef INSIDE_KERNEL_TREE #if defined(CONFIG_HIGHMEM4G) || defined(CONFIG_HIGHMEM64G) #warning "HIGHMEM kernel configurations are not supported by this module,\ @@ -1368,11 +1364,9 @@ static struct scsi_host_template scst_lcl_ini_driver_template = { #endif .can_queue = 256, .this_id = -1, - /* SCST doesn't support sg chaining */ - .sg_tablesize = SG_MAX_SINGLE_ALLOC, + .sg_tablesize = 0xFFFF, .cmd_per_lun = 32, .max_sectors = 0xffff, - /* SCST doesn't support sg chaining */ .use_clustering = ENABLE_CLUSTERING, .skip_settle_delay = 1, .module = THIS_MODULE,