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