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