root/drivers/s390/cio/fcx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tcw_get_intrg
  2. tcw_get_data
  3. tcw_get_tccb
  4. tcw_get_tsb
  5. tcw_init
  6. tca_size
  7. calc_dcw_count
  8. calc_cbc_size
  9. tcw_finalize
  10. tcw_set_intrg
  11. tcw_set_data
  12. tcw_set_tccb
  13. tcw_set_tsb
  14. tccb_init
  15. tsb_init
  16. tccb_add_dcw
  17. tcw_add_tidaw

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

/* [<][>][^][v][top][bottom][index][help] */