0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 #include "esas2r.h"
0046
0047 static u8 esas2r_vdaioctl_versions[] = {
0048 ATTO_VDA_VER_UNSUPPORTED,
0049 ATTO_VDA_FLASH_VER,
0050 ATTO_VDA_VER_UNSUPPORTED,
0051 ATTO_VDA_VER_UNSUPPORTED,
0052 ATTO_VDA_CLI_VER,
0053 ATTO_VDA_VER_UNSUPPORTED,
0054 ATTO_VDA_CFG_VER,
0055 ATTO_VDA_MGT_VER,
0056 ATTO_VDA_GSV_VER
0057 };
0058
0059 static void clear_vda_request(struct esas2r_request *rq);
0060
0061 static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
0062 struct esas2r_request *rq);
0063
0064
0065 bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
0066 struct atto_ioctl_vda *vi,
0067 struct esas2r_request *rq,
0068 struct esas2r_sg_context *sgc)
0069 {
0070 u32 datalen = 0;
0071 struct atto_vda_sge *firstsg = NULL;
0072 u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
0073
0074 vi->status = ATTO_STS_SUCCESS;
0075 vi->vda_status = RS_PENDING;
0076
0077 if (vi->function >= vercnt) {
0078 vi->status = ATTO_STS_INV_FUNC;
0079 return false;
0080 }
0081
0082 if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
0083 vi->status = ATTO_STS_INV_VERSION;
0084 return false;
0085 }
0086
0087 if (test_bit(AF_DEGRADED_MODE, &a->flags)) {
0088 vi->status = ATTO_STS_DEGRADED;
0089 return false;
0090 }
0091
0092 if (vi->function != VDA_FUNC_SCSI)
0093 clear_vda_request(rq);
0094
0095 rq->vrq->scsi.function = vi->function;
0096 rq->interrupt_cb = esas2r_complete_vda_ioctl;
0097 rq->interrupt_cx = vi;
0098
0099 switch (vi->function) {
0100 case VDA_FUNC_FLASH:
0101
0102 if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
0103 && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
0104 && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
0105 vi->status = ATTO_STS_INV_FUNC;
0106 return false;
0107 }
0108
0109 if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
0110 datalen = vi->data_length;
0111
0112 rq->vrq->flash.length = cpu_to_le32(datalen);
0113 rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
0114
0115 memcpy(rq->vrq->flash.data.file.file_name,
0116 vi->cmd.flash.data.file.file_name,
0117 sizeof(vi->cmd.flash.data.file.file_name));
0118
0119 firstsg = rq->vrq->flash.data.file.sge;
0120 break;
0121
0122 case VDA_FUNC_CLI:
0123
0124 datalen = vi->data_length;
0125
0126 rq->vrq->cli.cmd_rsp_len =
0127 cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
0128 rq->vrq->cli.length = cpu_to_le32(datalen);
0129
0130 firstsg = rq->vrq->cli.sge;
0131 break;
0132
0133 case VDA_FUNC_MGT:
0134 {
0135 u8 *cmdcurr_offset = sgc->cur_offset
0136 - offsetof(struct atto_ioctl_vda, data)
0137 + offsetof(struct atto_ioctl_vda, cmd)
0138 + offsetof(struct atto_ioctl_vda_mgt_cmd,
0139 data);
0140
0141
0142
0143
0144
0145
0146
0147 if (vi->data_length) {
0148 u32 payldlen = 0;
0149
0150 if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
0151 || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
0152 rq->vrq->mgt.payld_sglst_offset =
0153 (u8)offsetof(struct atto_vda_mgmt_req,
0154 payld_sge);
0155
0156 payldlen = vi->data_length;
0157 datalen = vi->cmd.mgt.data_length;
0158 } else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
0159 || vi->cmd.mgt.mgt_func ==
0160 VDAMGT_DEV_INFO2_BYADDR) {
0161 datalen = vi->data_length;
0162 cmdcurr_offset = sgc->cur_offset;
0163 } else {
0164 vi->status = ATTO_STS_INV_PARAM;
0165 return false;
0166 }
0167
0168
0169 rq->vrq->mgt.length = cpu_to_le32(datalen);
0170
0171 if (payldlen) {
0172 rq->vrq->mgt.payld_length =
0173 cpu_to_le32(payldlen);
0174
0175 esas2r_sgc_init(sgc, a, rq,
0176 rq->vrq->mgt.payld_sge);
0177 sgc->length = payldlen;
0178
0179 if (!esas2r_build_sg_list(a, rq, sgc)) {
0180 vi->status = ATTO_STS_OUT_OF_RSRC;
0181 return false;
0182 }
0183 }
0184 } else {
0185 datalen = vi->cmd.mgt.data_length;
0186
0187 rq->vrq->mgt.length = cpu_to_le32(datalen);
0188 }
0189
0190
0191
0192
0193
0194 firstsg = rq->vrq->mgt.sge;
0195 sgc->cur_offset = cmdcurr_offset;
0196
0197
0198 rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
0199 rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
0200 rq->vrq->mgt.dev_index =
0201 cpu_to_le32(vi->cmd.mgt.dev_index);
0202
0203 esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
0204 break;
0205 }
0206
0207 case VDA_FUNC_CFG:
0208
0209 if (vi->data_length
0210 || vi->cmd.cfg.data_length == 0) {
0211 vi->status = ATTO_STS_INV_PARAM;
0212 return false;
0213 }
0214
0215 if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
0216 vi->status = ATTO_STS_INV_FUNC;
0217 return false;
0218 }
0219
0220 rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
0221 rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
0222
0223 if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
0224 memcpy(&rq->vrq->cfg.data,
0225 &vi->cmd.cfg.data,
0226 vi->cmd.cfg.data_length);
0227
0228 esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
0229 &rq->vrq->cfg.data);
0230 } else {
0231 vi->status = ATTO_STS_INV_FUNC;
0232
0233 return false;
0234 }
0235
0236 break;
0237
0238 case VDA_FUNC_GSV:
0239
0240 vi->cmd.gsv.rsp_len = vercnt;
0241
0242 memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
0243 vercnt);
0244
0245 vi->vda_status = RS_SUCCESS;
0246 break;
0247
0248 default:
0249
0250 vi->status = ATTO_STS_INV_FUNC;
0251 return false;
0252 }
0253
0254 if (datalen) {
0255 esas2r_sgc_init(sgc, a, rq, firstsg);
0256 sgc->length = datalen;
0257
0258 if (!esas2r_build_sg_list(a, rq, sgc)) {
0259 vi->status = ATTO_STS_OUT_OF_RSRC;
0260 return false;
0261 }
0262 }
0263
0264 esas2r_start_request(a, rq);
0265
0266 return true;
0267 }
0268
0269 static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
0270 struct esas2r_request *rq)
0271 {
0272 struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
0273
0274 vi->vda_status = rq->req_stat;
0275
0276 switch (vi->function) {
0277 case VDA_FUNC_FLASH:
0278
0279 if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
0280 || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
0281 vi->cmd.flash.data.file.file_size =
0282 le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
0283
0284 break;
0285
0286 case VDA_FUNC_MGT:
0287
0288 vi->cmd.mgt.scan_generation =
0289 rq->func_rsp.mgt_rsp.scan_generation;
0290 vi->cmd.mgt.dev_index = le16_to_cpu(
0291 rq->func_rsp.mgt_rsp.dev_index);
0292
0293 if (vi->data_length == 0)
0294 vi->cmd.mgt.data_length =
0295 le32_to_cpu(rq->func_rsp.mgt_rsp.length);
0296
0297 esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
0298 break;
0299
0300 case VDA_FUNC_CFG:
0301
0302 if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
0303 struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
0304 struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
0305 char buf[sizeof(cfg->data.init.fw_release) + 1];
0306
0307 cfg->data_length =
0308 cpu_to_le32(sizeof(struct atto_vda_cfg_init));
0309 cfg->data.init.vda_version =
0310 le32_to_cpu(rsp->vda_version);
0311 cfg->data.init.fw_build = rsp->fw_build;
0312
0313 snprintf(buf, sizeof(buf), "%1.1u.%2.2u",
0314 (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
0315 (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
0316
0317 memcpy(&cfg->data.init.fw_release, buf,
0318 sizeof(cfg->data.init.fw_release));
0319
0320 if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
0321 cfg->data.init.fw_version =
0322 cfg->data.init.fw_build;
0323 else
0324 cfg->data.init.fw_version =
0325 cfg->data.init.fw_release;
0326 } else {
0327 esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
0328 &vi->cmd.cfg.data);
0329 }
0330
0331 break;
0332
0333 case VDA_FUNC_CLI:
0334
0335 vi->cmd.cli.cmd_rsp_len =
0336 le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
0337 break;
0338
0339 default:
0340
0341 break;
0342 }
0343 }
0344
0345
0346 void esas2r_build_flash_req(struct esas2r_adapter *a,
0347 struct esas2r_request *rq,
0348 u8 sub_func,
0349 u8 cksum,
0350 u32 addr,
0351 u32 length)
0352 {
0353 struct atto_vda_flash_req *vrq = &rq->vrq->flash;
0354
0355 clear_vda_request(rq);
0356
0357 rq->vrq->scsi.function = VDA_FUNC_FLASH;
0358
0359 if (sub_func == VDA_FLASH_BEGINW
0360 || sub_func == VDA_FLASH_WRITE
0361 || sub_func == VDA_FLASH_READ)
0362 vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
0363 data.sge);
0364
0365 vrq->length = cpu_to_le32(length);
0366 vrq->flash_addr = cpu_to_le32(addr);
0367 vrq->checksum = cksum;
0368 vrq->sub_func = sub_func;
0369 }
0370
0371
0372 void esas2r_build_mgt_req(struct esas2r_adapter *a,
0373 struct esas2r_request *rq,
0374 u8 sub_func,
0375 u8 scan_gen,
0376 u16 dev_index,
0377 u32 length,
0378 void *data)
0379 {
0380 struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
0381
0382 clear_vda_request(rq);
0383
0384 rq->vrq->scsi.function = VDA_FUNC_MGT;
0385
0386 vrq->mgt_func = sub_func;
0387 vrq->scan_generation = scan_gen;
0388 vrq->dev_index = cpu_to_le16(dev_index);
0389 vrq->length = cpu_to_le32(length);
0390
0391 if (vrq->length) {
0392 if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
0393 vrq->sg_list_offset = (u8)offsetof(
0394 struct atto_vda_mgmt_req, sge);
0395
0396 vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
0397 vrq->sge[0].address = cpu_to_le64(
0398 rq->vrq_md->phys_addr +
0399 sizeof(union atto_vda_req));
0400 } else {
0401 vrq->sg_list_offset = (u8)offsetof(
0402 struct atto_vda_mgmt_req, prde);
0403
0404 vrq->prde[0].ctl_len = cpu_to_le32(length);
0405 vrq->prde[0].address = cpu_to_le64(
0406 rq->vrq_md->phys_addr +
0407 sizeof(union atto_vda_req));
0408 }
0409 }
0410
0411 if (data) {
0412 esas2r_nuxi_mgt_data(sub_func, data);
0413
0414 memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
0415 length);
0416 }
0417 }
0418
0419
0420 void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
0421 {
0422 struct atto_vda_ae_req *vrq = &rq->vrq->ae;
0423
0424 clear_vda_request(rq);
0425
0426 rq->vrq->scsi.function = VDA_FUNC_AE;
0427
0428 vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
0429
0430 if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
0431 vrq->sg_list_offset =
0432 (u8)offsetof(struct atto_vda_ae_req, sge);
0433 vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
0434 vrq->sge[0].address = cpu_to_le64(
0435 rq->vrq_md->phys_addr +
0436 sizeof(union atto_vda_req));
0437 } else {
0438 vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
0439 prde);
0440 vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
0441 vrq->prde[0].address = cpu_to_le64(
0442 rq->vrq_md->phys_addr +
0443 sizeof(union atto_vda_req));
0444 }
0445 }
0446
0447
0448 void esas2r_build_cli_req(struct esas2r_adapter *a,
0449 struct esas2r_request *rq,
0450 u32 length,
0451 u32 cmd_rsp_len)
0452 {
0453 struct atto_vda_cli_req *vrq = &rq->vrq->cli;
0454
0455 clear_vda_request(rq);
0456
0457 rq->vrq->scsi.function = VDA_FUNC_CLI;
0458
0459 vrq->length = cpu_to_le32(length);
0460 vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
0461 vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
0462 }
0463
0464
0465 void esas2r_build_ioctl_req(struct esas2r_adapter *a,
0466 struct esas2r_request *rq,
0467 u32 length,
0468 u8 sub_func)
0469 {
0470 struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
0471
0472 clear_vda_request(rq);
0473
0474 rq->vrq->scsi.function = VDA_FUNC_IOCTL;
0475
0476 vrq->length = cpu_to_le32(length);
0477 vrq->sub_func = sub_func;
0478 vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
0479 }
0480
0481
0482 void esas2r_build_cfg_req(struct esas2r_adapter *a,
0483 struct esas2r_request *rq,
0484 u8 sub_func,
0485 u32 length,
0486 void *data)
0487 {
0488 struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
0489
0490 clear_vda_request(rq);
0491
0492 rq->vrq->scsi.function = VDA_FUNC_CFG;
0493
0494 vrq->sub_func = sub_func;
0495 vrq->length = cpu_to_le32(length);
0496
0497 if (data) {
0498 esas2r_nuxi_cfg_data(sub_func, data);
0499
0500 memcpy(&vrq->data, data, length);
0501 }
0502 }
0503
0504 static void clear_vda_request(struct esas2r_request *rq)
0505 {
0506 u32 handle = rq->vrq->scsi.handle;
0507
0508 memset(rq->vrq, 0, sizeof(*rq->vrq));
0509
0510 rq->vrq->scsi.handle = handle;
0511
0512 rq->req_stat = RS_PENDING;
0513
0514
0515
0516 memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
0517
0518
0519
0520
0521
0522
0523 INIT_LIST_HEAD(&rq->req_list);
0524 }