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
init_sg_buffer(sg_buffer * sgb,CCB_SCSIIO * ccbio)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
realloc_sg_buffer(sg_buffer * sgb,size_t size)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
sg_access_byte(sg_buffer * sgb,off_t offset,uchar * byte,bool b_set)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
sg_memcpy(sg_buffer * d_sgb,off_t d_offset,sg_buffer * s_sgb,off_t s_offset,size_t size)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
free_sg_buffer(sg_buffer * sgb)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
sg_buffer_len(sg_buffer * sgb,size_t * size)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