xref: /haiku/src/add-ons/kernel/busses/scsi/usb/sg_buffer.c (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
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 */
27 status_t
28 init_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 */
54 status_t
55 realloc_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 
77 status_t
78 sg_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 
99 status_t
100 sg_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 */
152 void
153 free_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 
164 status_t
165 sg_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