1/**
2 *
3 * TODO: description
4 *
5 * This file is a part of USB SCSI CAM for Haiku.
6 * May be used under terms of the MIT License
7 *
8 * Author(s):
9 * 	Siarzhuk Zharski <imker@gmx.li>
10 *
11 *
12 */
13/** handling SCSI data-buffer (both usual "plain" and scatter/gather ones) */
14
15#include <string.h>
16
17#include "usb_scsi.h"
18
19#include <malloc.h>
20#include "tracing.h"
21#include "sg_buffer.h"
22
23/**
24	\fn:init_sg_buffer
25	TODO!!!
26*/
27status_t
28init_sg_buffer(sg_buffer *sgb, CCB_SCSIIO *ccbio)
29{
30	status_t status = B_NO_INIT;
31	if(0 != sgb){
32		memset(sgb, 0, sizeof(sg_buffer));
33		/* setup scatter/gather if exists in CCBIO*/
34		if(ccbio->cam_ch.cam_flags & CAM_SCATTER_VALID) {
35			sgb->piov	= (iovec *) ccbio->cam_data_ptr;
36			sgb->count = ccbio->cam_sglist_cnt;
37		} else {
38			sgb->iov.iov_base = (iovec *) ccbio->cam_data_ptr;
39			sgb->iov.iov_len	= ccbio->cam_dxfer_len;
40			sgb->piov	= &sgb->iov;
41			sgb->count = 1;
42		}
43		status = B_OK;
44	} else {
45		TRACE_ALWAYS("init_sg_buffer fatal: not initialized!\n");
46	}
47	return status;
48}
49
50/**
51	\fn:alloc_sg_buffer
52	TODO!!!
53*/
54status_t
55realloc_sg_buffer(sg_buffer *sgb, size_t size)
56{
57	status_t status = B_NO_INIT;
58	if(0 != sgb){
59		/* NOTE: no check for previously allocations! May be dangerous!*/
60		void *ptr = malloc(size);
61		status = (0 != ptr) ? B_OK : B_NO_MEMORY;
62		if(B_OK == status) {
63			memset(ptr, 0, size);
64			sgb->iov.iov_base = (iovec *)ptr;
65			sgb->iov.iov_len	= size;
66			sgb->piov	= &sgb->iov;
67			sgb->count = 1;
68			sgb->b_own = true;
69			status = B_OK;
70		}
71	} else {
72		TRACE_ALWAYS("realloc_sg_buffer fatal: not initialized!\n");
73	}
74	return status;
75}
76
77status_t
78sg_access_byte(sg_buffer *sgb, off_t offset, uchar *byte, bool b_set)
79{
80	status_t status = B_ERROR;
81	int i = 0;
82	for(; i < sgb->count; i++){
83		if(offset >= sgb->piov[i].iov_len){
84			offset -= sgb->piov[i].iov_len;
85		} else {
86			uchar *ptr = (uchar *)sgb->piov[i].iov_base;
87			if(b_set){
88				ptr[offset] = *byte;
89			}else{
90				*byte = ptr[offset];
91			}
92			status = B_OK;
93			break;
94		}
95	}
96	return status;
97}
98
99status_t
100sg_memcpy(sg_buffer *d_sgb, off_t d_offset,
101					sg_buffer *s_sgb, off_t s_offset, size_t size)
102{
103	status_t status = B_NO_INIT;
104	while(0 != d_sgb && 0 != s_sgb){
105		uchar *d_ptr = 0;
106		uchar *s_ptr = 0;
107		status = B_ERROR;
108		if(1 == d_sgb->count){
109			d_ptr = d_sgb->piov->iov_base + d_offset;
110			if((d_offset + size) > d_sgb->piov->iov_len){
111				TRACE_ALWAYS("sg_memcpy fatal: dest buffer overflow: has:%d req:%d\n",
112							 d_sgb->piov->iov_len, d_offset + size);
113				break;
114			}
115		}
116		if(1 == s_sgb->count){
117			s_ptr = s_sgb->piov->iov_base + s_offset;
118			if((s_offset + size) > s_sgb->piov->iov_len){
119				TRACE_ALWAYS("sg_memcpy fatal: src buffer overflow: has:%d req:%d\n",
120							 s_sgb->piov->iov_len, s_offset + size);
121				break;
122			}
123		}
124		if(0 != d_ptr && 0 != s_ptr){
125			memcpy(d_ptr, s_ptr, size);
126		} else {
127			uchar byte = 0;
128			int i = 0;
129			for(; i < size; i++){
130				status = sg_access_byte(s_sgb, s_offset + i, &byte, false);
131				if(B_OK == status)
132					status = sg_access_byte(d_sgb, d_offset + i, &byte, true);
133				if(B_OK != status){
134					TRACE_ALWAYS("sg_memcpy fatal: dest:%d src:%d size:%d/%d\n",
135										 d_offset, s_offset, i, size);
136					break;
137				}
138			}
139		}
140		status = B_OK;
141		break;
142	}
143	if(B_NO_INIT == status)
144		TRACE_ALWAYS("sg_memcpy fatal: not initialized");
145	return status;
146}
147
148/**
149	\fn:free_sg_buffer
150	TODO!!!
151*/
152void
153free_sg_buffer(sg_buffer *sgb)
154{
155	if(0 != sgb && sgb->b_own){
156		int i = 0;
157		for(; i < sgb->count; i++){
158			free(sgb->piov[i].iov_base);
159		}
160		memset(sgb, 0, sizeof(sg_buffer));
161	}
162}
163
164status_t
165sg_buffer_len(sg_buffer *sgb, size_t *size)
166{
167	status_t status = B_NO_INIT;
168	if(0!=sgb && 0!=size){
169		int i = 0;
170		*size = 0;
171		for(; i < sgb->count; i++){
172			*size += sgb->piov[i].iov_len;
173		}
174		status = B_OK;
175	} else {
176		TRACE_ALWAYS("sg_buffer_len fatal: not initialized (sgb:%x/size:%x)", sgb, size);
177	}
178	return status;
179}
180
181