1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Functions for assembling fcx enabled I/O control blocks. 4 * 5 * Copyright IBM Corp. 2008 6 * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/types.h> 11 #include <linux/string.h> 12 #include <linux/io.h> 13 #include <linux/errno.h> 14 #include <linux/err.h> 15 #include <linux/module.h> 16 #include <asm/fcx.h> 17 #include "cio.h" 18 19 /** 20 * tcw_get_intrg - return pointer to associated interrogate tcw 21 * @tcw: pointer to the original tcw 22 * 23 * Return a pointer to the interrogate tcw associated with the specified tcw 24 * or %NULL if there is no associated interrogate tcw. 25 */ 26 struct tcw *tcw_get_intrg(struct tcw *tcw) 27 { 28 return dma32_to_virt(tcw->intrg); 29 } 30 EXPORT_SYMBOL(tcw_get_intrg); 31 32 /** 33 * tcw_get_data - return pointer to input/output data associated with tcw 34 * @tcw: pointer to the tcw 35 * 36 * Return the input or output data address specified in the tcw depending 37 * on whether the r-bit or the w-bit is set. If neither bit is set, return 38 * %NULL. 39 */ 40 void *tcw_get_data(struct tcw *tcw) 41 { 42 if (tcw->r) 43 return dma64_to_virt(tcw->input); 44 if (tcw->w) 45 return dma64_to_virt(tcw->output); 46 return NULL; 47 } 48 EXPORT_SYMBOL(tcw_get_data); 49 50 /** 51 * tcw_get_tccb - return pointer to tccb associated with tcw 52 * @tcw: pointer to the tcw 53 * 54 * Return pointer to the tccb associated with this tcw. 55 */ 56 struct tccb *tcw_get_tccb(struct tcw *tcw) 57 { 58 return dma64_to_virt(tcw->tccb); 59 } 60 EXPORT_SYMBOL(tcw_get_tccb); 61 62 /** 63 * tcw_get_tsb - return pointer to tsb associated with tcw 64 * @tcw: pointer to the tcw 65 * 66 * Return pointer to the tsb associated with this tcw. 67 */ 68 struct tsb *tcw_get_tsb(struct tcw *tcw) 69 { 70 return dma64_to_virt(tcw->tsb); 71 } 72 EXPORT_SYMBOL(tcw_get_tsb); 73 74 /** 75 * tcw_init - initialize tcw data structure 76 * @tcw: pointer to the tcw to be initialized 77 * @r: initial value of the r-bit 78 * @w: initial value of the w-bit 79 * 80 * Initialize all fields of the specified tcw data structure with zero and 81 * fill in the format, flags, r and w fields. 82 */ 83 void tcw_init(struct tcw *tcw, int r, int w) 84 { 85 memset(tcw, 0, sizeof(struct tcw)); 86 tcw->format = TCW_FORMAT_DEFAULT; 87 tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT); 88 if (r) 89 tcw->r = 1; 90 if (w) 91 tcw->w = 1; 92 } 93 EXPORT_SYMBOL(tcw_init); 94 95 static inline size_t tca_size(struct tccb *tccb) 96 { 97 return tccb->tcah.tcal - 12; 98 } 99 100 static u32 calc_dcw_count(struct tccb *tccb) 101 { 102 int offset; 103 struct dcw *dcw; 104 u32 count = 0; 105 size_t size; 106 107 size = tca_size(tccb); 108 for (offset = 0; offset < size;) { 109 dcw = (struct dcw *) &tccb->tca[offset]; 110 count += dcw->count; 111 if (!(dcw->flags & DCW_FLAGS_CC)) 112 break; 113 offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4); 114 } 115 return count; 116 } 117 118 static u32 calc_cbc_size(struct tidaw *tidaw, int num) 119 { 120 int i; 121 u32 cbc_data; 122 u32 cbc_count = 0; 123 u64 data_count = 0; 124 125 for (i = 0; i < num; i++) { 126 if (tidaw[i].flags & TIDAW_FLAGS_LAST) 127 break; 128 /* TODO: find out if padding applies to total of data 129 * transferred or data transferred by this tidaw. Assumption: 130 * applies to total. */ 131 data_count += tidaw[i].count; 132 if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) { 133 cbc_data = 4 + ALIGN(data_count, 4) - data_count; 134 cbc_count += cbc_data; 135 data_count += cbc_data; 136 } 137 } 138 return cbc_count; 139 } 140 141 /** 142 * tcw_finalize - finalize tcw length fields and tidaw list 143 * @tcw: pointer to the tcw 144 * @num_tidaws: the number of tidaws used to address input/output data or zero 145 * if no tida is used 146 * 147 * Calculate the input-/output-count and tccbl field in the tcw, add a 148 * tcat the tccb and terminate the data tidaw list if used. 149 * 150 * Note: in case input- or output-tida is used, the tidaw-list must be stored 151 * in contiguous storage (no ttic). The tcal field in the tccb must be 152 * up-to-date. 153 */ 154 void tcw_finalize(struct tcw *tcw, int num_tidaws) 155 { 156 struct tidaw *tidaw; 157 struct tccb *tccb; 158 struct tccb_tcat *tcat; 159 u32 count; 160 161 /* Terminate tidaw list. */ 162 tidaw = tcw_get_data(tcw); 163 if (num_tidaws > 0) 164 tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST; 165 /* Add tcat to tccb. */ 166 tccb = tcw_get_tccb(tcw); 167 tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)]; 168 memset(tcat, 0, sizeof(*tcat)); 169 /* Calculate tcw input/output count and tcat transport count. */ 170 count = calc_dcw_count(tccb); 171 if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA)) 172 count += calc_cbc_size(tidaw, num_tidaws); 173 if (tcw->r) 174 tcw->input_count = count; 175 else if (tcw->w) 176 tcw->output_count = count; 177 tcat->count = ALIGN(count, 4) + 4; 178 /* Calculate tccbl. */ 179 tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) + 180 sizeof(struct tccb_tcat) - 20) >> 2; 181 } 182 EXPORT_SYMBOL(tcw_finalize); 183 184 /** 185 * tcw_set_intrg - set the interrogate tcw address of a tcw 186 * @tcw: the tcw address 187 * @intrg_tcw: the address of the interrogate tcw 188 * 189 * Set the address of the interrogate tcw in the specified tcw. 190 */ 191 void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw) 192 { 193 tcw->intrg = virt_to_dma32(intrg_tcw); 194 } 195 EXPORT_SYMBOL(tcw_set_intrg); 196 197 /** 198 * tcw_set_data - set data address and tida flag of a tcw 199 * @tcw: the tcw address 200 * @data: the data address 201 * @use_tidal: zero of the data address specifies a contiguous block of data, 202 * non-zero if it specifies a list if tidaws. 203 * 204 * Set the input/output data address of a tcw (depending on the value of the 205 * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag 206 * is set as well. 207 */ 208 void tcw_set_data(struct tcw *tcw, void *data, int use_tidal) 209 { 210 if (tcw->r) { 211 tcw->input = virt_to_dma64(data); 212 if (use_tidal) 213 tcw->flags |= TCW_FLAGS_INPUT_TIDA; 214 } else if (tcw->w) { 215 tcw->output = virt_to_dma64(data); 216 if (use_tidal) 217 tcw->flags |= TCW_FLAGS_OUTPUT_TIDA; 218 } 219 } 220 EXPORT_SYMBOL(tcw_set_data); 221 222 /** 223 * tcw_set_tccb - set tccb address of a tcw 224 * @tcw: the tcw address 225 * @tccb: the tccb address 226 * 227 * Set the address of the tccb in the specified tcw. 228 */ 229 void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb) 230 { 231 tcw->tccb = virt_to_dma64(tccb); 232 } 233 EXPORT_SYMBOL(tcw_set_tccb); 234 235 /** 236 * tcw_set_tsb - set tsb address of a tcw 237 * @tcw: the tcw address 238 * @tsb: the tsb address 239 * 240 * Set the address of the tsb in the specified tcw. 241 */ 242 void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb) 243 { 244 tcw->tsb = virt_to_dma64(tsb); 245 } 246 EXPORT_SYMBOL(tcw_set_tsb); 247 248 /** 249 * tccb_init - initialize tccb 250 * @tccb: the tccb address 251 * @size: the maximum size of the tccb 252 * @sac: the service-action-code to be user 253 * 254 * Initialize the header of the specified tccb by resetting all values to zero 255 * and filling in defaults for format, sac and initial tcal fields. 256 */ 257 void tccb_init(struct tccb *tccb, size_t size, u32 sac) 258 { 259 memset(tccb, 0, size); 260 tccb->tcah.format = TCCB_FORMAT_DEFAULT; 261 tccb->tcah.sac = sac; 262 tccb->tcah.tcal = 12; 263 } 264 EXPORT_SYMBOL(tccb_init); 265 266 /** 267 * tsb_init - initialize tsb 268 * @tsb: the tsb address 269 * 270 * Initialize the specified tsb by resetting all values to zero. 271 */ 272 void tsb_init(struct tsb *tsb) 273 { 274 memset(tsb, 0, sizeof(*tsb)); 275 } 276 EXPORT_SYMBOL(tsb_init); 277 278 /** 279 * tccb_add_dcw - add a dcw to the tccb 280 * @tccb: the tccb address 281 * @tccb_size: the maximum tccb size 282 * @cmd: the dcw command 283 * @flags: flags for the dcw 284 * @cd: pointer to control data for this dcw or NULL if none is required 285 * @cd_count: number of control data bytes for this dcw 286 * @count: number of data bytes for this dcw 287 * 288 * Add a new dcw to the specified tccb by writing the dcw information specified 289 * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return 290 * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw 291 * would exceed the available space as defined by @tccb_size. 292 * 293 * Note: the tcal field of the tccb header will be updates to reflect added 294 * content. 295 */ 296 struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags, 297 void *cd, u8 cd_count, u32 count) 298 { 299 struct dcw *dcw; 300 int size; 301 int tca_offset; 302 303 /* Check for space. */ 304 tca_offset = tca_size(tccb); 305 size = ALIGN(sizeof(struct dcw) + cd_count, 4); 306 if (sizeof(struct tccb_tcah) + tca_offset + size + 307 sizeof(struct tccb_tcat) > tccb_size) 308 return ERR_PTR(-ENOSPC); 309 /* Add dcw to tca. */ 310 dcw = (struct dcw *) &tccb->tca[tca_offset]; 311 memset(dcw, 0, size); 312 dcw->cmd = cmd; 313 dcw->flags = flags; 314 dcw->count = count; 315 dcw->cd_count = cd_count; 316 if (cd) 317 memcpy(&dcw->cd[0], cd, cd_count); 318 tccb->tcah.tcal += size; 319 return dcw; 320 } 321 EXPORT_SYMBOL(tccb_add_dcw); 322 323 /** 324 * tcw_add_tidaw - add a tidaw to a tcw 325 * @tcw: the tcw address 326 * @num_tidaws: the current number of tidaws 327 * @flags: flags for the new tidaw 328 * @addr: address value for the new tidaw 329 * @count: count value for the new tidaw 330 * 331 * Add a new tidaw to the input/output data tidaw-list of the specified tcw 332 * (depending on the value of the r-flag and w-flag) and return a pointer to 333 * the new tidaw. 334 * 335 * Note: the tidaw-list is assumed to be contiguous with no ttics. The caller 336 * must ensure that there is enough space for the new tidaw. The last-tidaw 337 * flag for the last tidaw in the list will be set by tcw_finalize. 338 */ 339 struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags, 340 void *addr, u32 count) 341 { 342 struct tidaw *tidaw; 343 344 /* Add tidaw to tidaw-list. */ 345 tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws; 346 memset(tidaw, 0, sizeof(struct tidaw)); 347 tidaw->flags = flags; 348 tidaw->count = count; 349 tidaw->addr = virt_to_dma64(addr); 350 return tidaw; 351 } 352 EXPORT_SYMBOL(tcw_add_tidaw); 353