0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/types.h>
0011 #include <linux/string.h>
0012 #include <linux/errno.h>
0013 #include <linux/err.h>
0014 #include <linux/module.h>
0015 #include <asm/fcx.h>
0016 #include "cio.h"
0017
0018
0019
0020
0021
0022
0023
0024
0025 struct tcw *tcw_get_intrg(struct tcw *tcw)
0026 {
0027 return (struct tcw *) ((addr_t) tcw->intrg);
0028 }
0029 EXPORT_SYMBOL(tcw_get_intrg);
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 void *tcw_get_data(struct tcw *tcw)
0040 {
0041 if (tcw->r)
0042 return (void *) ((addr_t) tcw->input);
0043 if (tcw->w)
0044 return (void *) ((addr_t) tcw->output);
0045 return NULL;
0046 }
0047 EXPORT_SYMBOL(tcw_get_data);
0048
0049
0050
0051
0052
0053
0054
0055 struct tccb *tcw_get_tccb(struct tcw *tcw)
0056 {
0057 return (struct tccb *) ((addr_t) tcw->tccb);
0058 }
0059 EXPORT_SYMBOL(tcw_get_tccb);
0060
0061
0062
0063
0064
0065
0066
0067 struct tsb *tcw_get_tsb(struct tcw *tcw)
0068 {
0069 return (struct tsb *) ((addr_t) tcw->tsb);
0070 }
0071 EXPORT_SYMBOL(tcw_get_tsb);
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 void tcw_init(struct tcw *tcw, int r, int w)
0083 {
0084 memset(tcw, 0, sizeof(struct tcw));
0085 tcw->format = TCW_FORMAT_DEFAULT;
0086 tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT);
0087 if (r)
0088 tcw->r = 1;
0089 if (w)
0090 tcw->w = 1;
0091 }
0092 EXPORT_SYMBOL(tcw_init);
0093
0094 static inline size_t tca_size(struct tccb *tccb)
0095 {
0096 return tccb->tcah.tcal - 12;
0097 }
0098
0099 static u32 calc_dcw_count(struct tccb *tccb)
0100 {
0101 int offset;
0102 struct dcw *dcw;
0103 u32 count = 0;
0104 size_t size;
0105
0106 size = tca_size(tccb);
0107 for (offset = 0; offset < size;) {
0108 dcw = (struct dcw *) &tccb->tca[offset];
0109 count += dcw->count;
0110 if (!(dcw->flags & DCW_FLAGS_CC))
0111 break;
0112 offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4);
0113 }
0114 return count;
0115 }
0116
0117 static u32 calc_cbc_size(struct tidaw *tidaw, int num)
0118 {
0119 int i;
0120 u32 cbc_data;
0121 u32 cbc_count = 0;
0122 u64 data_count = 0;
0123
0124 for (i = 0; i < num; i++) {
0125 if (tidaw[i].flags & TIDAW_FLAGS_LAST)
0126 break;
0127
0128
0129
0130 data_count += tidaw[i].count;
0131 if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) {
0132 cbc_data = 4 + ALIGN(data_count, 4) - data_count;
0133 cbc_count += cbc_data;
0134 data_count += cbc_data;
0135 }
0136 }
0137 return cbc_count;
0138 }
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153 void tcw_finalize(struct tcw *tcw, int num_tidaws)
0154 {
0155 struct tidaw *tidaw;
0156 struct tccb *tccb;
0157 struct tccb_tcat *tcat;
0158 u32 count;
0159
0160
0161 tidaw = tcw_get_data(tcw);
0162 if (num_tidaws > 0)
0163 tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST;
0164
0165 tccb = tcw_get_tccb(tcw);
0166 tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)];
0167 memset(tcat, 0, sizeof(*tcat));
0168
0169 count = calc_dcw_count(tccb);
0170 if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA))
0171 count += calc_cbc_size(tidaw, num_tidaws);
0172 if (tcw->r)
0173 tcw->input_count = count;
0174 else if (tcw->w)
0175 tcw->output_count = count;
0176 tcat->count = ALIGN(count, 4) + 4;
0177
0178 tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) +
0179 sizeof(struct tccb_tcat) - 20) >> 2;
0180 }
0181 EXPORT_SYMBOL(tcw_finalize);
0182
0183
0184
0185
0186
0187
0188
0189
0190 void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw)
0191 {
0192 tcw->intrg = (u32) ((addr_t) intrg_tcw);
0193 }
0194 EXPORT_SYMBOL(tcw_set_intrg);
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 void tcw_set_data(struct tcw *tcw, void *data, int use_tidal)
0208 {
0209 if (tcw->r) {
0210 tcw->input = (u64) ((addr_t) data);
0211 if (use_tidal)
0212 tcw->flags |= TCW_FLAGS_INPUT_TIDA;
0213 } else if (tcw->w) {
0214 tcw->output = (u64) ((addr_t) data);
0215 if (use_tidal)
0216 tcw->flags |= TCW_FLAGS_OUTPUT_TIDA;
0217 }
0218 }
0219 EXPORT_SYMBOL(tcw_set_data);
0220
0221
0222
0223
0224
0225
0226
0227
0228 void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb)
0229 {
0230 tcw->tccb = (u64) ((addr_t) tccb);
0231 }
0232 EXPORT_SYMBOL(tcw_set_tccb);
0233
0234
0235
0236
0237
0238
0239
0240
0241 void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb)
0242 {
0243 tcw->tsb = (u64) ((addr_t) tsb);
0244 }
0245 EXPORT_SYMBOL(tcw_set_tsb);
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256 void tccb_init(struct tccb *tccb, size_t size, u32 sac)
0257 {
0258 memset(tccb, 0, size);
0259 tccb->tcah.format = TCCB_FORMAT_DEFAULT;
0260 tccb->tcah.sac = sac;
0261 tccb->tcah.tcal = 12;
0262 }
0263 EXPORT_SYMBOL(tccb_init);
0264
0265
0266
0267
0268
0269
0270
0271 void tsb_init(struct tsb *tsb)
0272 {
0273 memset(tsb, 0, sizeof(*tsb));
0274 }
0275 EXPORT_SYMBOL(tsb_init);
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295 struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags,
0296 void *cd, u8 cd_count, u32 count)
0297 {
0298 struct dcw *dcw;
0299 int size;
0300 int tca_offset;
0301
0302
0303 tca_offset = tca_size(tccb);
0304 size = ALIGN(sizeof(struct dcw) + cd_count, 4);
0305 if (sizeof(struct tccb_tcah) + tca_offset + size +
0306 sizeof(struct tccb_tcat) > tccb_size)
0307 return ERR_PTR(-ENOSPC);
0308
0309 dcw = (struct dcw *) &tccb->tca[tca_offset];
0310 memset(dcw, 0, size);
0311 dcw->cmd = cmd;
0312 dcw->flags = flags;
0313 dcw->count = count;
0314 dcw->cd_count = cd_count;
0315 if (cd)
0316 memcpy(&dcw->cd[0], cd, cd_count);
0317 tccb->tcah.tcal += size;
0318 return dcw;
0319 }
0320 EXPORT_SYMBOL(tccb_add_dcw);
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags,
0339 void *addr, u32 count)
0340 {
0341 struct tidaw *tidaw;
0342
0343
0344 tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws;
0345 memset(tidaw, 0, sizeof(struct tidaw));
0346 tidaw->flags = flags;
0347 tidaw->count = count;
0348 tidaw->addr = (u64) ((addr_t) addr);
0349 return tidaw;
0350 }
0351 EXPORT_SYMBOL(tcw_add_tidaw);