root/drivers/scsi/esas2r/esas2r_vda.c

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

DEFINITIONS

This source file includes following definitions.
  1. esas2r_process_vda_ioctl
  2. esas2r_complete_vda_ioctl
  3. esas2r_build_flash_req
  4. esas2r_build_mgt_req
  5. esas2r_build_ae_req
  6. esas2r_build_cli_req
  7. esas2r_build_ioctl_req
  8. esas2r_build_cfg_req
  9. clear_vda_request

   1 /*
   2  *  linux/drivers/scsi/esas2r/esas2r_vda.c
   3  *      esas2r driver VDA firmware interface functions
   4  *
   5  *  Copyright (c) 2001-2013 ATTO Technology, Inc.
   6  *  (mailto:linuxdrivers@attotech.com)
   7  */
   8 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
   9 /*
  10  *  This program is free software; you can redistribute it and/or modify
  11  *  it under the terms of the GNU General Public License as published by
  12  *  the Free Software Foundation; version 2 of the License.
  13  *
  14  *  This program is distributed in the hope that it will be useful,
  15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17  *  GNU General Public License for more details.
  18  *
  19  *  NO WARRANTY
  20  *  THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
  21  *  CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
  22  *  LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
  23  *  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
  24  *  solely responsible for determining the appropriateness of using and
  25  *  distributing the Program and assumes all risks associated with its
  26  *  exercise of rights under this Agreement, including but not limited to
  27  *  the risks and costs of program errors, damage to or loss of data,
  28  *  programs or equipment, and unavailability or interruption of operations.
  29  *
  30  *  DISCLAIMER OF LIABILITY
  31  *  NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
  32  *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33  *  DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
  34  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  35  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  36  *  USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
  37  *  HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
  38  *
  39  *  You should have received a copy of the GNU General Public License
  40  *  along with this program; if not, write to the Free Software
  41  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  42  */
  43 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
  44 
  45 #include "esas2r.h"
  46 
  47 static u8 esas2r_vdaioctl_versions[] = {
  48         ATTO_VDA_VER_UNSUPPORTED,
  49         ATTO_VDA_FLASH_VER,
  50         ATTO_VDA_VER_UNSUPPORTED,
  51         ATTO_VDA_VER_UNSUPPORTED,
  52         ATTO_VDA_CLI_VER,
  53         ATTO_VDA_VER_UNSUPPORTED,
  54         ATTO_VDA_CFG_VER,
  55         ATTO_VDA_MGT_VER,
  56         ATTO_VDA_GSV_VER
  57 };
  58 
  59 static void clear_vda_request(struct esas2r_request *rq);
  60 
  61 static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
  62                                       struct esas2r_request *rq);
  63 
  64 /* Prepare a VDA IOCTL request to be sent to the firmware. */
  65 bool esas2r_process_vda_ioctl(struct esas2r_adapter *a,
  66                               struct atto_ioctl_vda *vi,
  67                               struct esas2r_request *rq,
  68                               struct esas2r_sg_context *sgc)
  69 {
  70         u32 datalen = 0;
  71         struct atto_vda_sge *firstsg = NULL;
  72         u8 vercnt = (u8)ARRAY_SIZE(esas2r_vdaioctl_versions);
  73 
  74         vi->status = ATTO_STS_SUCCESS;
  75         vi->vda_status = RS_PENDING;
  76 
  77         if (vi->function >= vercnt) {
  78                 vi->status = ATTO_STS_INV_FUNC;
  79                 return false;
  80         }
  81 
  82         if (vi->version > esas2r_vdaioctl_versions[vi->function]) {
  83                 vi->status = ATTO_STS_INV_VERSION;
  84                 return false;
  85         }
  86 
  87         if (test_bit(AF_DEGRADED_MODE, &a->flags)) {
  88                 vi->status = ATTO_STS_DEGRADED;
  89                 return false;
  90         }
  91 
  92         if (vi->function != VDA_FUNC_SCSI)
  93                 clear_vda_request(rq);
  94 
  95         rq->vrq->scsi.function = vi->function;
  96         rq->interrupt_cb = esas2r_complete_vda_ioctl;
  97         rq->interrupt_cx = vi;
  98 
  99         switch (vi->function) {
 100         case VDA_FUNC_FLASH:
 101 
 102                 if (vi->cmd.flash.sub_func != VDA_FLASH_FREAD
 103                     && vi->cmd.flash.sub_func != VDA_FLASH_FWRITE
 104                     && vi->cmd.flash.sub_func != VDA_FLASH_FINFO) {
 105                         vi->status = ATTO_STS_INV_FUNC;
 106                         return false;
 107                 }
 108 
 109                 if (vi->cmd.flash.sub_func != VDA_FLASH_FINFO)
 110                         datalen = vi->data_length;
 111 
 112                 rq->vrq->flash.length = cpu_to_le32(datalen);
 113                 rq->vrq->flash.sub_func = vi->cmd.flash.sub_func;
 114 
 115                 memcpy(rq->vrq->flash.data.file.file_name,
 116                        vi->cmd.flash.data.file.file_name,
 117                        sizeof(vi->cmd.flash.data.file.file_name));
 118 
 119                 firstsg = rq->vrq->flash.data.file.sge;
 120                 break;
 121 
 122         case VDA_FUNC_CLI:
 123 
 124                 datalen = vi->data_length;
 125 
 126                 rq->vrq->cli.cmd_rsp_len =
 127                         cpu_to_le32(vi->cmd.cli.cmd_rsp_len);
 128                 rq->vrq->cli.length = cpu_to_le32(datalen);
 129 
 130                 firstsg = rq->vrq->cli.sge;
 131                 break;
 132 
 133         case VDA_FUNC_MGT:
 134         {
 135                 u8 *cmdcurr_offset = sgc->cur_offset
 136                                      - offsetof(struct atto_ioctl_vda, data)
 137                                      + offsetof(struct atto_ioctl_vda, cmd)
 138                                      + offsetof(struct atto_ioctl_vda_mgt_cmd,
 139                                                 data);
 140                 /*
 141                  * build the data payload SGL here first since
 142                  * esas2r_sgc_init() will modify the S/G list offset for the
 143                  * management SGL (which is built below where the data SGL is
 144                  * usually built).
 145                  */
 146 
 147                 if (vi->data_length) {
 148                         u32 payldlen = 0;
 149 
 150                         if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_HEALTH_REQ
 151                             || vi->cmd.mgt.mgt_func == VDAMGT_DEV_METRICS) {
 152                                 rq->vrq->mgt.payld_sglst_offset =
 153                                         (u8)offsetof(struct atto_vda_mgmt_req,
 154                                                      payld_sge);
 155 
 156                                 payldlen = vi->data_length;
 157                                 datalen = vi->cmd.mgt.data_length;
 158                         } else if (vi->cmd.mgt.mgt_func == VDAMGT_DEV_INFO2
 159                                    || vi->cmd.mgt.mgt_func ==
 160                                    VDAMGT_DEV_INFO2_BYADDR) {
 161                                 datalen = vi->data_length;
 162                                 cmdcurr_offset = sgc->cur_offset;
 163                         } else {
 164                                 vi->status = ATTO_STS_INV_PARAM;
 165                                 return false;
 166                         }
 167 
 168                         /* Setup the length so building the payload SGL works */
 169                         rq->vrq->mgt.length = cpu_to_le32(datalen);
 170 
 171                         if (payldlen) {
 172                                 rq->vrq->mgt.payld_length =
 173                                         cpu_to_le32(payldlen);
 174 
 175                                 esas2r_sgc_init(sgc, a, rq,
 176                                                 rq->vrq->mgt.payld_sge);
 177                                 sgc->length = payldlen;
 178 
 179                                 if (!esas2r_build_sg_list(a, rq, sgc)) {
 180                                         vi->status = ATTO_STS_OUT_OF_RSRC;
 181                                         return false;
 182                                 }
 183                         }
 184                 } else {
 185                         datalen = vi->cmd.mgt.data_length;
 186 
 187                         rq->vrq->mgt.length = cpu_to_le32(datalen);
 188                 }
 189 
 190                 /*
 191                  * Now that the payload SGL is built, if any, setup to build
 192                  * the management SGL.
 193                  */
 194                 firstsg = rq->vrq->mgt.sge;
 195                 sgc->cur_offset = cmdcurr_offset;
 196 
 197                 /* Finish initializing the management request. */
 198                 rq->vrq->mgt.mgt_func = vi->cmd.mgt.mgt_func;
 199                 rq->vrq->mgt.scan_generation = vi->cmd.mgt.scan_generation;
 200                 rq->vrq->mgt.dev_index =
 201                         cpu_to_le32(vi->cmd.mgt.dev_index);
 202 
 203                 esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
 204                 break;
 205         }
 206 
 207         case VDA_FUNC_CFG:
 208 
 209                 if (vi->data_length
 210                     || vi->cmd.cfg.data_length == 0) {
 211                         vi->status = ATTO_STS_INV_PARAM;
 212                         return false;
 213                 }
 214 
 215                 if (vi->cmd.cfg.cfg_func == VDA_CFG_INIT) {
 216                         vi->status = ATTO_STS_INV_FUNC;
 217                         return false;
 218                 }
 219 
 220                 rq->vrq->cfg.sub_func = vi->cmd.cfg.cfg_func;
 221                 rq->vrq->cfg.length = cpu_to_le32(vi->cmd.cfg.data_length);
 222 
 223                 if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
 224                         memcpy(&rq->vrq->cfg.data,
 225                                &vi->cmd.cfg.data,
 226                                vi->cmd.cfg.data_length);
 227 
 228                         esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
 229                                              &rq->vrq->cfg.data);
 230                 } else {
 231                         vi->status = ATTO_STS_INV_FUNC;
 232 
 233                         return false;
 234                 }
 235 
 236                 break;
 237 
 238         case VDA_FUNC_GSV:
 239 
 240                 vi->cmd.gsv.rsp_len = vercnt;
 241 
 242                 memcpy(vi->cmd.gsv.version_info, esas2r_vdaioctl_versions,
 243                        vercnt);
 244 
 245                 vi->vda_status = RS_SUCCESS;
 246                 break;
 247 
 248         default:
 249 
 250                 vi->status = ATTO_STS_INV_FUNC;
 251                 return false;
 252         }
 253 
 254         if (datalen) {
 255                 esas2r_sgc_init(sgc, a, rq, firstsg);
 256                 sgc->length = datalen;
 257 
 258                 if (!esas2r_build_sg_list(a, rq, sgc)) {
 259                         vi->status = ATTO_STS_OUT_OF_RSRC;
 260                         return false;
 261                 }
 262         }
 263 
 264         esas2r_start_request(a, rq);
 265 
 266         return true;
 267 }
 268 
 269 static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
 270                                       struct esas2r_request *rq)
 271 {
 272         struct atto_ioctl_vda *vi = (struct atto_ioctl_vda *)rq->interrupt_cx;
 273 
 274         vi->vda_status = rq->req_stat;
 275 
 276         switch (vi->function) {
 277         case VDA_FUNC_FLASH:
 278 
 279                 if (vi->cmd.flash.sub_func == VDA_FLASH_FINFO
 280                     || vi->cmd.flash.sub_func == VDA_FLASH_FREAD)
 281                         vi->cmd.flash.data.file.file_size =
 282                                 le32_to_cpu(rq->func_rsp.flash_rsp.file_size);
 283 
 284                 break;
 285 
 286         case VDA_FUNC_MGT:
 287 
 288                 vi->cmd.mgt.scan_generation =
 289                         rq->func_rsp.mgt_rsp.scan_generation;
 290                 vi->cmd.mgt.dev_index = le16_to_cpu(
 291                         rq->func_rsp.mgt_rsp.dev_index);
 292 
 293                 if (vi->data_length == 0)
 294                         vi->cmd.mgt.data_length =
 295                                 le32_to_cpu(rq->func_rsp.mgt_rsp.length);
 296 
 297                 esas2r_nuxi_mgt_data(rq->vrq->mgt.mgt_func, &vi->cmd.mgt.data);
 298                 break;
 299 
 300         case VDA_FUNC_CFG:
 301 
 302                 if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
 303                         struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
 304                         struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
 305                         char buf[sizeof(cfg->data.init.fw_release) + 1];
 306 
 307                         cfg->data_length =
 308                                 cpu_to_le32(sizeof(struct atto_vda_cfg_init));
 309                         cfg->data.init.vda_version =
 310                                 le32_to_cpu(rsp->vda_version);
 311                         cfg->data.init.fw_build = rsp->fw_build;
 312 
 313                         snprintf(buf, sizeof(buf), "%1.1u.%2.2u",
 314                                  (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
 315                                  (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
 316 
 317                         memcpy(&cfg->data.init.fw_release, buf,
 318                                sizeof(cfg->data.init.fw_release));
 319 
 320                         if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
 321                                 cfg->data.init.fw_version =
 322                                         cfg->data.init.fw_build;
 323                         else
 324                                 cfg->data.init.fw_version =
 325                                         cfg->data.init.fw_release;
 326                 } else {
 327                         esas2r_nuxi_cfg_data(rq->vrq->cfg.sub_func,
 328                                              &vi->cmd.cfg.data);
 329                 }
 330 
 331                 break;
 332 
 333         case VDA_FUNC_CLI:
 334 
 335                 vi->cmd.cli.cmd_rsp_len =
 336                         le32_to_cpu(rq->func_rsp.cli_rsp.cmd_rsp_len);
 337                 break;
 338 
 339         default:
 340 
 341                 break;
 342         }
 343 }
 344 
 345 /* Build a flash VDA request. */
 346 void esas2r_build_flash_req(struct esas2r_adapter *a,
 347                             struct esas2r_request *rq,
 348                             u8 sub_func,
 349                             u8 cksum,
 350                             u32 addr,
 351                             u32 length)
 352 {
 353         struct atto_vda_flash_req *vrq = &rq->vrq->flash;
 354 
 355         clear_vda_request(rq);
 356 
 357         rq->vrq->scsi.function = VDA_FUNC_FLASH;
 358 
 359         if (sub_func == VDA_FLASH_BEGINW
 360             || sub_func == VDA_FLASH_WRITE
 361             || sub_func == VDA_FLASH_READ)
 362                 vrq->sg_list_offset = (u8)offsetof(struct atto_vda_flash_req,
 363                                                    data.sge);
 364 
 365         vrq->length = cpu_to_le32(length);
 366         vrq->flash_addr = cpu_to_le32(addr);
 367         vrq->checksum = cksum;
 368         vrq->sub_func = sub_func;
 369 }
 370 
 371 /* Build a VDA management request. */
 372 void esas2r_build_mgt_req(struct esas2r_adapter *a,
 373                           struct esas2r_request *rq,
 374                           u8 sub_func,
 375                           u8 scan_gen,
 376                           u16 dev_index,
 377                           u32 length,
 378                           void *data)
 379 {
 380         struct atto_vda_mgmt_req *vrq = &rq->vrq->mgt;
 381 
 382         clear_vda_request(rq);
 383 
 384         rq->vrq->scsi.function = VDA_FUNC_MGT;
 385 
 386         vrq->mgt_func = sub_func;
 387         vrq->scan_generation = scan_gen;
 388         vrq->dev_index = cpu_to_le16(dev_index);
 389         vrq->length = cpu_to_le32(length);
 390 
 391         if (vrq->length) {
 392                 if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
 393                         vrq->sg_list_offset = (u8)offsetof(
 394                                 struct atto_vda_mgmt_req, sge);
 395 
 396                         vrq->sge[0].length = cpu_to_le32(SGE_LAST | length);
 397                         vrq->sge[0].address = cpu_to_le64(
 398                                 rq->vrq_md->phys_addr +
 399                                 sizeof(union atto_vda_req));
 400                 } else {
 401                         vrq->sg_list_offset = (u8)offsetof(
 402                                 struct atto_vda_mgmt_req, prde);
 403 
 404                         vrq->prde[0].ctl_len = cpu_to_le32(length);
 405                         vrq->prde[0].address = cpu_to_le64(
 406                                 rq->vrq_md->phys_addr +
 407                                 sizeof(union atto_vda_req));
 408                 }
 409         }
 410 
 411         if (data) {
 412                 esas2r_nuxi_mgt_data(sub_func, data);
 413 
 414                 memcpy(&rq->vda_rsp_data->mgt_data.data.bytes[0], data,
 415                        length);
 416         }
 417 }
 418 
 419 /* Build a VDA asyncronous event (AE) request. */
 420 void esas2r_build_ae_req(struct esas2r_adapter *a, struct esas2r_request *rq)
 421 {
 422         struct atto_vda_ae_req *vrq = &rq->vrq->ae;
 423 
 424         clear_vda_request(rq);
 425 
 426         rq->vrq->scsi.function = VDA_FUNC_AE;
 427 
 428         vrq->length = cpu_to_le32(sizeof(struct atto_vda_ae_data));
 429 
 430         if (test_bit(AF_LEGACY_SGE_MODE, &a->flags)) {
 431                 vrq->sg_list_offset =
 432                         (u8)offsetof(struct atto_vda_ae_req, sge);
 433                 vrq->sge[0].length = cpu_to_le32(SGE_LAST | vrq->length);
 434                 vrq->sge[0].address = cpu_to_le64(
 435                         rq->vrq_md->phys_addr +
 436                         sizeof(union atto_vda_req));
 437         } else {
 438                 vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ae_req,
 439                                                    prde);
 440                 vrq->prde[0].ctl_len = cpu_to_le32(vrq->length);
 441                 vrq->prde[0].address = cpu_to_le64(
 442                         rq->vrq_md->phys_addr +
 443                         sizeof(union atto_vda_req));
 444         }
 445 }
 446 
 447 /* Build a VDA CLI request. */
 448 void esas2r_build_cli_req(struct esas2r_adapter *a,
 449                           struct esas2r_request *rq,
 450                           u32 length,
 451                           u32 cmd_rsp_len)
 452 {
 453         struct atto_vda_cli_req *vrq = &rq->vrq->cli;
 454 
 455         clear_vda_request(rq);
 456 
 457         rq->vrq->scsi.function = VDA_FUNC_CLI;
 458 
 459         vrq->length = cpu_to_le32(length);
 460         vrq->cmd_rsp_len = cpu_to_le32(cmd_rsp_len);
 461         vrq->sg_list_offset = (u8)offsetof(struct atto_vda_cli_req, sge);
 462 }
 463 
 464 /* Build a VDA IOCTL request. */
 465 void esas2r_build_ioctl_req(struct esas2r_adapter *a,
 466                             struct esas2r_request *rq,
 467                             u32 length,
 468                             u8 sub_func)
 469 {
 470         struct atto_vda_ioctl_req *vrq = &rq->vrq->ioctl;
 471 
 472         clear_vda_request(rq);
 473 
 474         rq->vrq->scsi.function = VDA_FUNC_IOCTL;
 475 
 476         vrq->length = cpu_to_le32(length);
 477         vrq->sub_func = sub_func;
 478         vrq->sg_list_offset = (u8)offsetof(struct atto_vda_ioctl_req, sge);
 479 }
 480 
 481 /* Build a VDA configuration request. */
 482 void esas2r_build_cfg_req(struct esas2r_adapter *a,
 483                           struct esas2r_request *rq,
 484                           u8 sub_func,
 485                           u32 length,
 486                           void *data)
 487 {
 488         struct atto_vda_cfg_req *vrq = &rq->vrq->cfg;
 489 
 490         clear_vda_request(rq);
 491 
 492         rq->vrq->scsi.function = VDA_FUNC_CFG;
 493 
 494         vrq->sub_func = sub_func;
 495         vrq->length = cpu_to_le32(length);
 496 
 497         if (data) {
 498                 esas2r_nuxi_cfg_data(sub_func, data);
 499 
 500                 memcpy(&vrq->data, data, length);
 501         }
 502 }
 503 
 504 static void clear_vda_request(struct esas2r_request *rq)
 505 {
 506         u32 handle = rq->vrq->scsi.handle;
 507 
 508         memset(rq->vrq, 0, sizeof(*rq->vrq));
 509 
 510         rq->vrq->scsi.handle = handle;
 511 
 512         rq->req_stat = RS_PENDING;
 513 
 514         /* since the data buffer is separate clear that too */
 515 
 516         memset(rq->data_buf, 0, ESAS2R_DATA_BUF_LEN);
 517 
 518         /*
 519          * Setup next and prev pointer in case the request is not going through
 520          * esas2r_start_request().
 521          */
 522 
 523         INIT_LIST_HEAD(&rq->req_list);
 524 }

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