1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * tavor_ioctl.c
  29  *    Tavor IOCTL Routines
  30  *
  31  *    Implements all ioctl access into the driver.  This includes all routines
  32  *    necessary for updating firmware, accessing the tavor flash device, and
  33  *    providing interfaces for VTS.
  34  */
  35 
  36 #include <sys/types.h>
  37 #include <sys/conf.h>
  38 #include <sys/ddi.h>
  39 #include <sys/sunddi.h>
  40 #include <sys/modctl.h>
  41 #include <sys/file.h>
  42 
  43 #include <sys/ib/adapters/tavor/tavor.h>
  44 
  45 /* Tavor HCA state pointer (extern) */
  46 extern void     *tavor_statep;
  47 
  48 /*
  49  * The ioctl declarations (for firmware flash burning, register read/write
  50  * (DEBUG-only), and VTS interfaces)
  51  */
  52 static int tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev,
  53     intptr_t arg, int mode);
  54 static int tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev,
  55     intptr_t arg, int mode);
  56 static int tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev,
  57     intptr_t arg, int mode);
  58 static int tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev,
  59     intptr_t arg, int mode);
  60 static int tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev);
  61 static void tavor_ioctl_flash_cleanup(tavor_state_t *state);
  62 static void tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state);
  63 #ifdef  DEBUG
  64 static int tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg,
  65     int mode);
  66 static int tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg,
  67     int mode);
  68 #endif  /* DEBUG */
  69 static int tavor_ioctl_info(tavor_state_t *state, dev_t dev,
  70     intptr_t arg, int mode);
  71 static int tavor_ioctl_ports(tavor_state_t *state, intptr_t arg,
  72     int mode);
  73 static int tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg,
  74     int mode);
  75 static int tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg,
  76     int mode);
  77 
  78 /* Tavor Flash Functions */
  79 static void tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num);
  80 static void tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data,
  81     uint32_t addr);
  82 static int  tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num);
  83 static int  tavor_flash_write_byte(tavor_state_t *state, uint32_t addr,
  84     uchar_t data);
  85 static int  tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num);
  86 static int  tavor_flash_erase_chip(tavor_state_t *state);
  87 static void tavor_flash_bank(tavor_state_t *state, uint32_t addr);
  88 static uint32_t tavor_flash_read(tavor_state_t *state, uint32_t addr);
  89 static void tavor_flash_write(tavor_state_t *state, uint32_t addr,
  90     uchar_t data);
  91 static void tavor_flash_init(tavor_state_t *state);
  92 static void tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info,
  93     int *intel_xcmd);
  94 static void tavor_flash_fini(tavor_state_t *state);
  95 static void tavor_flash_reset(tavor_state_t *state);
  96 static uint32_t tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl,
  97     uint32_t addr);
  98 static void tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl,
  99     uint32_t addr, uint32_t data);
 100 static void tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
 101 static void tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
 102 
 103 /* Tavor loopback test functions */
 104 static void tavor_loopback_free_qps(tavor_loopback_state_t *lstate);
 105 static void tavor_loopback_free_state(tavor_loopback_state_t *lstate);
 106 static int tavor_loopback_init(tavor_state_t *state,
 107     tavor_loopback_state_t *lstate);
 108 static void tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate,
 109     tavor_loopback_comm_t *comm);
 110 static int tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate,
 111     tavor_loopback_comm_t *comm, int sz);
 112 static int tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate,
 113     tavor_loopback_comm_t *comm);
 114 static int tavor_loopback_modify_qp(tavor_loopback_state_t *lstate,
 115     tavor_loopback_comm_t *comm, uint_t qp_num);
 116 static int tavor_loopback_copyout(tavor_loopback_ioctl_t *lb,
 117     intptr_t arg, int mode);
 118 static int tavor_loopback_post_send(tavor_loopback_state_t *lstate,
 119     tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx);
 120 static int tavor_loopback_poll_cq(tavor_loopback_state_t *lstate,
 121     tavor_loopback_comm_t *comm);
 122 
 123 /* Patchable timeout values for flash operations */
 124 int tavor_hw_flash_timeout_gpio_sema = TAVOR_HW_FLASH_TIMEOUT_GPIO_SEMA;
 125 int tavor_hw_flash_timeout_config = TAVOR_HW_FLASH_TIMEOUT_CONFIG;
 126 int tavor_hw_flash_timeout_write = TAVOR_HW_FLASH_TIMEOUT_WRITE;
 127 int tavor_hw_flash_timeout_erase = TAVOR_HW_FLASH_TIMEOUT_ERASE;
 128 
 129 /*
 130  * tavor_ioctl()
 131  */
 132 /* ARGSUSED */
 133 int
 134 tavor_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
 135     int *rvalp)
 136 {
 137         tavor_state_t   *state;
 138         minor_t         instance;
 139         int             status;
 140 
 141         TAVOR_TNF_ENTER(tavor_ioctl);
 142 
 143         if (drv_priv(credp) != 0) {
 144                 TNF_PROBE_0(tavor_ioctl_priv_fail, TAVOR_TNF_ERROR, "");
 145                 TAVOR_TNF_EXIT(tavor_ioctl);
 146                 return (EPERM);
 147         }
 148 
 149         instance = TAVOR_DEV_INSTANCE(dev);
 150         if (instance == -1) {
 151                 TNF_PROBE_0(tavor_ioctl_inst_fail, TAVOR_TNF_ERROR, "");
 152                 TAVOR_TNF_EXIT(tavor_ioctl);
 153                 return (EBADF);
 154         }
 155 
 156         state = ddi_get_soft_state(tavor_statep, instance);
 157         if (state == NULL) {
 158                 TNF_PROBE_0(tavor_ioctl_gss_fail, TAVOR_TNF_ERROR, "");
 159                 TAVOR_TNF_EXIT(tavor_ioctl);
 160                 return (EBADF);
 161         }
 162 
 163         status = 0;
 164 
 165         switch (cmd) {
 166         case TAVOR_IOCTL_FLASH_READ:
 167                 status = tavor_ioctl_flash_read(state, dev, arg, mode);
 168                 break;
 169 
 170         case TAVOR_IOCTL_FLASH_WRITE:
 171                 status = tavor_ioctl_flash_write(state, dev, arg, mode);
 172                 break;
 173 
 174         case TAVOR_IOCTL_FLASH_ERASE:
 175                 status = tavor_ioctl_flash_erase(state, dev, arg, mode);
 176                 break;
 177 
 178         case TAVOR_IOCTL_FLASH_INIT:
 179                 status = tavor_ioctl_flash_init(state, dev, arg, mode);
 180                 break;
 181 
 182         case TAVOR_IOCTL_FLASH_FINI:
 183                 status = tavor_ioctl_flash_fini(state, dev);
 184                 break;
 185 
 186         case TAVOR_IOCTL_INFO:
 187                 status = tavor_ioctl_info(state, dev, arg, mode);
 188                 break;
 189 
 190         case TAVOR_IOCTL_PORTS:
 191                 status = tavor_ioctl_ports(state, arg, mode);
 192                 break;
 193 
 194         case TAVOR_IOCTL_DDR_READ:
 195                 status = tavor_ioctl_ddr_read(state, arg, mode);
 196                 break;
 197 
 198         case TAVOR_IOCTL_LOOPBACK:
 199                 status = tavor_ioctl_loopback(state, arg, mode);
 200                 break;
 201 
 202 #ifdef  DEBUG
 203         case TAVOR_IOCTL_REG_WRITE:
 204                 status = tavor_ioctl_reg_write(state, arg, mode);
 205                 break;
 206 
 207         case TAVOR_IOCTL_REG_READ:
 208                 status = tavor_ioctl_reg_read(state, arg, mode);
 209                 break;
 210 #endif  /* DEBUG */
 211 
 212         default:
 213                 status = ENOTTY;
 214                 TNF_PROBE_0(tavor_ioctl_default_fail, TAVOR_TNF_ERROR, "");
 215                 break;
 216         }
 217         *rvalp = status;
 218 
 219         TAVOR_TNF_EXIT(tavor_ioctl);
 220         return (status);
 221 }
 222 
 223 /*
 224  * tavor_ioctl_flash_read()
 225  */
 226 static int
 227 tavor_ioctl_flash_read(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
 228 {
 229         tavor_flash_ioctl_t ioctl_info;
 230         int status = 0;
 231 
 232         TAVOR_TNF_ENTER(tavor_ioctl_flash_read);
 233 
 234         /*
 235          * Check that flash init ioctl has been called first.  And check
 236          * that the same dev_t that called init is the one calling read now.
 237          */
 238         mutex_enter(&state->ts_fw_flashlock);
 239         if ((state->ts_fw_flashdev != dev) ||
 240             (state->ts_fw_flashstarted == 0)) {
 241                 mutex_exit(&state->ts_fw_flashlock);
 242                 TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
 243                 TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 244                 return (EIO);
 245         }
 246 
 247         /* copy user struct to kernel */
 248 #ifdef _MULTI_DATAMODEL
 249         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 250                 tavor_flash_ioctl32_t info32;
 251 
 252                 if (ddi_copyin((void *)arg, &info32,
 253                     sizeof (tavor_flash_ioctl32_t), mode) != 0) {
 254                         mutex_exit(&state->ts_fw_flashlock);
 255                         TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail,
 256                             TAVOR_TNF_ERROR, "");
 257                         TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 258                         return (EFAULT);
 259                 }
 260                 ioctl_info.tf_type = info32.tf_type;
 261                 ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector;
 262                 ioctl_info.tf_sector_num = info32.tf_sector_num;
 263                 ioctl_info.tf_addr = info32.tf_addr;
 264         } else
 265 #endif /* _MULTI_DATAMODEL */
 266         if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t),
 267             mode) != 0) {
 268                 mutex_exit(&state->ts_fw_flashlock);
 269                 TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail,
 270                     TAVOR_TNF_ERROR, "");
 271                 TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 272                 return (EFAULT);
 273         }
 274 
 275         /*
 276          * Determine type of READ ioctl
 277          */
 278         switch (ioctl_info.tf_type) {
 279         case TAVOR_FLASH_READ_SECTOR:
 280                 /* Check if sector num is too large for flash device */
 281                 if (ioctl_info.tf_sector_num >=
 282                     (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
 283                         mutex_exit(&state->ts_fw_flashlock);
 284                         TNF_PROBE_0(tavor_flash_read_sector_num_too_large,
 285                             TAVOR_TNF_ERROR, "");
 286                         TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 287                         return (EFAULT);
 288                 }
 289 
 290                 /* Perform the Sector Read */
 291                 tavor_flash_reset(state);
 292                 tavor_flash_read_sector(state, ioctl_info.tf_sector_num);
 293 
 294                 /* copyout the firmware sector image data */
 295                 if (ddi_copyout(&state->ts_fw_sector[0],
 296                     &ioctl_info.tf_sector[0], 1 << state->ts_fw_log_sector_sz,
 297                     mode) != 0) {
 298                         mutex_exit(&state->ts_fw_flashlock);
 299                         TNF_PROBE_0(tavor_flash_read_copyout_fail,
 300                             TAVOR_TNF_ERROR, "");
 301                         TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 302                         return (EFAULT);
 303                 }
 304                 break;
 305 
 306         case TAVOR_FLASH_READ_QUADLET:
 307                 /* Check if addr is too large for flash device */
 308                 if (ioctl_info.tf_addr >= state->ts_fw_device_sz) {
 309                         mutex_exit(&state->ts_fw_flashlock);
 310                         TNF_PROBE_0(tavor_flash_read_quad_addr_too_large,
 311                             TAVOR_TNF_ERROR, "");
 312                         TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 313                         return (EFAULT);
 314                 }
 315 
 316                 /* Perform the Quadlet Read */
 317                 tavor_flash_reset(state);
 318                 tavor_flash_read_quadlet(state, &ioctl_info.tf_quadlet,
 319                     ioctl_info.tf_addr);
 320                 break;
 321 
 322         default:
 323                 TNF_PROBE_0(tavor_ioctl_flash_read_invalid_type,
 324                     TAVOR_TNF_ERROR, "");
 325                 status = EIO;
 326                 break;
 327         }
 328 
 329         /* copy results back to userland */
 330 #ifdef _MULTI_DATAMODEL
 331         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 332                 tavor_flash_ioctl32_t info32;
 333 
 334                 info32.tf_quadlet = ioctl_info.tf_quadlet;
 335                 info32.tf_type = ioctl_info.tf_type;
 336                 info32.tf_sector_num = ioctl_info.tf_sector_num;
 337                 info32.tf_sector = (caddr32_t)(uintptr_t)ioctl_info.tf_sector;
 338                 info32.tf_addr = ioctl_info.tf_addr;
 339 
 340                 if (ddi_copyout(&info32, (void *)arg,
 341                     sizeof (tavor_flash_ioctl32_t), mode) != 0) {
 342                         mutex_exit(&state->ts_fw_flashlock);
 343                         TNF_PROBE_0(tavor_flash_read_copyout_fail,
 344                             TAVOR_TNF_ERROR, "");
 345                         TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 346                         return (EFAULT);
 347                 }
 348         } else
 349 #endif /* _MULTI_DATAMODEL */
 350         if (ddi_copyout(&ioctl_info, (void *)arg,
 351             sizeof (tavor_flash_ioctl_t), mode) != 0) {
 352                 mutex_exit(&state->ts_fw_flashlock);
 353                 TNF_PROBE_0(tavor_flash_read_copyout_fail,
 354                     TAVOR_TNF_ERROR, "");
 355                 TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 356                 return (EFAULT);
 357         }
 358 
 359         mutex_exit(&state->ts_fw_flashlock);
 360         TAVOR_TNF_EXIT(tavor_ioctl_flash_read);
 361         return (status);
 362 }
 363 
 364 /*
 365  * tavor_ioctl_flash_write()
 366  */
 367 static int
 368 tavor_ioctl_flash_write(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
 369 {
 370         tavor_flash_ioctl_t     ioctl_info;
 371         int status = 0;
 372 
 373         TAVOR_TNF_ENTER(tavor_ioctl_flash_write);
 374 
 375         /*
 376          * Check that flash init ioctl has been called first.  And check
 377          * that the same dev_t that called init is the one calling write now.
 378          */
 379         mutex_enter(&state->ts_fw_flashlock);
 380         if ((state->ts_fw_flashdev != dev) ||
 381             (state->ts_fw_flashstarted == 0)) {
 382                 mutex_exit(&state->ts_fw_flashlock);
 383                 TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
 384                 TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 385                 return (EIO);
 386         }
 387 
 388         /* copy user struct to kernel */
 389 #ifdef _MULTI_DATAMODEL
 390         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 391                 tavor_flash_ioctl32_t info32;
 392 
 393                 if (ddi_copyin((void *)arg, &info32,
 394                     sizeof (tavor_flash_ioctl32_t), mode) != 0) {
 395                         mutex_exit(&state->ts_fw_flashlock);
 396                         TNF_PROBE_0(tavor_ioctl_flash_write_copyin_fail,
 397                             TAVOR_TNF_ERROR, "");
 398                         TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 399                         return (EFAULT);
 400                 }
 401                 ioctl_info.tf_type = info32.tf_type;
 402                 ioctl_info.tf_sector = (caddr_t)(uintptr_t)info32.tf_sector;
 403                 ioctl_info.tf_sector_num = info32.tf_sector_num;
 404                 ioctl_info.tf_addr = info32.tf_addr;
 405                 ioctl_info.tf_byte = info32.tf_byte;
 406         } else
 407 #endif /* _MULTI_DATAMODEL */
 408         if (ddi_copyin((void *)arg, &ioctl_info,
 409             sizeof (tavor_flash_ioctl_t), mode) != 0) {
 410                 mutex_exit(&state->ts_fw_flashlock);
 411                 TNF_PROBE_0(tavor_ioctl_flash_write_ci_fail,
 412                     TAVOR_TNF_ERROR, "");
 413                 TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 414                 return (EFAULT);
 415         }
 416 
 417         /*
 418          * Determine type of WRITE ioctl
 419          */
 420         switch (ioctl_info.tf_type) {
 421         case TAVOR_FLASH_WRITE_SECTOR:
 422                 /* Check if sector num is too large for flash device */
 423                 if (ioctl_info.tf_sector_num >=
 424                     (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
 425                         mutex_exit(&state->ts_fw_flashlock);
 426                         TNF_PROBE_0(tavor_flash_write_sector_num_too_large,
 427                             TAVOR_TNF_ERROR, "");
 428                         TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 429                         return (EFAULT);
 430                 }
 431 
 432                 /* copy in fw sector image data */
 433                 if (ddi_copyin(&ioctl_info.tf_sector[0],
 434                     &state->ts_fw_sector[0], 1 << state->ts_fw_log_sector_sz,
 435                     mode) != 0) {
 436                         mutex_exit(&state->ts_fw_flashlock);
 437                         TNF_PROBE_0(tavor_ioctl_flash_write_fw_sector_ci_fail,
 438                             TAVOR_TNF_ERROR, "");
 439                         TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 440                         return (EFAULT);
 441                 }
 442 
 443                 /* Perform Write Sector */
 444                 status = tavor_flash_write_sector(state,
 445                     ioctl_info.tf_sector_num);
 446                 break;
 447 
 448         case TAVOR_FLASH_WRITE_BYTE:
 449                 /* Check if addr is too large for flash device */
 450                 if (ioctl_info.tf_addr >= state->ts_fw_device_sz) {
 451                         mutex_exit(&state->ts_fw_flashlock);
 452                         TNF_PROBE_0(tavor_flash_write_byte_addr_too_large,
 453                             TAVOR_TNF_ERROR, "");
 454                         TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 455                         return (EFAULT);
 456                 }
 457 
 458                 /* Perform Write Byte */
 459                 tavor_flash_bank(state, ioctl_info.tf_addr);
 460                 tavor_flash_reset(state);
 461                 status = tavor_flash_write_byte(state, ioctl_info.tf_addr,
 462                     ioctl_info.tf_byte);
 463                 tavor_flash_reset(state);
 464                 break;
 465 
 466         default:
 467                 TNF_PROBE_0(tavor_ioctl_flash_write_invalid_type,
 468                     TAVOR_TNF_ERROR, "");
 469                 status = EIO;
 470                 break;
 471         }
 472 
 473         mutex_exit(&state->ts_fw_flashlock);
 474         TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 475         return (status);
 476 }
 477 
 478 /*
 479  * tavor_ioctl_flash_erase()
 480  */
 481 static int
 482 tavor_ioctl_flash_erase(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
 483 {
 484         tavor_flash_ioctl_t     ioctl_info;
 485         int status = 0;
 486 
 487         TAVOR_TNF_ENTER(tavor_ioctl_flash_erase);
 488 
 489         /*
 490          * Check that flash init ioctl has been called first.  And check
 491          * that the same dev_t that called init is the one calling erase now.
 492          */
 493         mutex_enter(&state->ts_fw_flashlock);
 494         if ((state->ts_fw_flashdev != dev) ||
 495             (state->ts_fw_flashstarted == 0)) {
 496                 mutex_exit(&state->ts_fw_flashlock);
 497                 TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
 498                 TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
 499                 return (EIO);
 500         }
 501 
 502         /* copy user struct to kernel */
 503 #ifdef _MULTI_DATAMODEL
 504         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 505                 tavor_flash_ioctl32_t info32;
 506 
 507                 if (ddi_copyin((void *)arg, &info32,
 508                     sizeof (tavor_flash_ioctl32_t), mode) != 0) {
 509                         mutex_exit(&state->ts_fw_flashlock);
 510                         TNF_PROBE_0(tavor_ioctl_flash_read_copyin_fail,
 511                             TAVOR_TNF_ERROR, "");
 512                         TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
 513                         return (EFAULT);
 514                 }
 515                 ioctl_info.tf_type = info32.tf_type;
 516                 ioctl_info.tf_sector_num = info32.tf_sector_num;
 517         } else
 518 #endif /* _MULTI_DATAMODEL */
 519         if (ddi_copyin((void *)arg, &ioctl_info, sizeof (tavor_flash_ioctl_t),
 520             mode) != 0) {
 521                 mutex_exit(&state->ts_fw_flashlock);
 522                 TNF_PROBE_0(tavor_ioctl_flash_erase_ci_fail,
 523                     TAVOR_TNF_ERROR, "");
 524                 TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
 525                 return (EFAULT);
 526         }
 527 
 528         /*
 529          * Determine type of ERASE ioctl
 530          */
 531         switch (ioctl_info.tf_type) {
 532         case TAVOR_FLASH_ERASE_SECTOR:
 533                 /* Check if sector num is too large for flash device */
 534                 if (ioctl_info.tf_sector_num >=
 535                     (state->ts_fw_device_sz >> state->ts_fw_log_sector_sz)) {
 536                         mutex_exit(&state->ts_fw_flashlock);
 537                         TNF_PROBE_0(tavor_flash_erase_sector_num_too_large,
 538                             TAVOR_TNF_ERROR, "");
 539                         TAVOR_TNF_EXIT(tavor_ioctl_flash_write);
 540                         return (EFAULT);
 541                 }
 542 
 543                 /* Perform Sector Erase */
 544                 status = tavor_flash_erase_sector(state,
 545                     ioctl_info.tf_sector_num);
 546                 break;
 547 
 548         case TAVOR_FLASH_ERASE_CHIP:
 549                 /* Perform Chip Erase */
 550                 status = tavor_flash_erase_chip(state);
 551                 break;
 552 
 553         default:
 554                 TNF_PROBE_0(tavor_ioctl_flash_erase_invalid_type,
 555                     TAVOR_TNF_ERROR, "");
 556                 status = EIO;
 557                 break;
 558         }
 559 
 560         mutex_exit(&state->ts_fw_flashlock);
 561         TAVOR_TNF_EXIT(tavor_ioctl_flash_erase);
 562         return (status);
 563 }
 564 
 565 /*
 566  * tavor_ioctl_flash_init()
 567  */
 568 static int
 569 tavor_ioctl_flash_init(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
 570 {
 571         tavor_flash_init_ioctl_t init_info;
 572         int ret;
 573         int intel_xcmd = 0;
 574 
 575         TAVOR_TNF_ENTER(tavor_ioctl_flash_init);
 576 
 577         /*
 578          * init cannot be called more than once.  If we have already init'd the
 579          * flash, return directly.
 580          */
 581         mutex_enter(&state->ts_fw_flashlock);
 582         if (state->ts_fw_flashstarted == 1) {
 583                 mutex_exit(&state->ts_fw_flashlock);
 584                 TNF_PROBE_0(tavor_ioctl_flash_init_already_started,
 585                     TAVOR_TNF_ERROR, "");
 586                 TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
 587                 return (EIO);
 588         }
 589 
 590         /* copyin the user struct to kernel */
 591         if (ddi_copyin((void *)arg, &init_info,
 592             sizeof (tavor_flash_init_ioctl_t), mode) != 0) {
 593                 mutex_exit(&state->ts_fw_flashlock);
 594                 TNF_PROBE_0(tavor_flash_init_ioctl_copyin_fail,
 595                     TAVOR_TNF_ERROR, "");
 596                 TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
 597                 return (EFAULT);
 598         }
 599 
 600         /* Init Flash */
 601         tavor_flash_init(state);
 602 
 603         /* Read CFI info */
 604         tavor_flash_cfi_init(state, &init_info.tf_cfi_info[0], &intel_xcmd);
 605 
 606         /*
 607          * Return error if the command set is unknown.
 608          */
 609         if (state->ts_fw_cmdset == TAVOR_FLASH_UNKNOWN_CMDSET) {
 610                 mutex_exit(&state->ts_fw_flashlock);
 611                 TNF_PROBE_1(tavor_ioctl_flash_init_cmdset_fail,
 612                     TAVOR_TNF_ERROR, "", tnf_string, errmsg,
 613                     "UNKNOWN flash command set");
 614                 TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
 615                 return (EFAULT);
 616         }
 617 
 618         /* Read HWREV - least significant 8 bits is revision ID */
 619         init_info.tf_hwrev = pci_config_get32(state->ts_pci_cfghdl,
 620             TAVOR_HW_FLASH_CFG_HWREV) & 0xFF;
 621 
 622         /* Fill in the firmwate revision numbers */
 623         init_info.tf_fwrev.tfi_maj      = state->ts_fw.fw_rev_major;
 624         init_info.tf_fwrev.tfi_min      = state->ts_fw.fw_rev_minor;
 625         init_info.tf_fwrev.tfi_sub      = state->ts_fw.fw_rev_subminor;
 626 
 627         /* Alloc flash mem for one sector size */
 628         state->ts_fw_sector = (uint32_t *)kmem_zalloc(1 <<
 629             state->ts_fw_log_sector_sz, KM_SLEEP);
 630 
 631         /* Set HW part number and length */
 632         init_info.tf_pn_len = state->ts_hca_pn_len;
 633         if (state->ts_hca_pn_len != 0) {
 634                 (void) memcpy(init_info.tf_hwpn, state->ts_hca_pn,
 635                     state->ts_hca_pn_len);
 636         }
 637 
 638         /* Copy ioctl results back to userland */
 639         if (ddi_copyout(&init_info, (void *)arg,
 640             sizeof (tavor_flash_init_ioctl_t), mode) != 0) {
 641 
 642                 tavor_ioctl_flash_cleanup_nolock(state);
 643 
 644                 mutex_exit(&state->ts_fw_flashlock);
 645                 TNF_PROBE_0(tavor_ioctl_flash_init_copyout_fail,
 646                     TAVOR_TNF_ERROR, "");
 647                 TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
 648                 return (EFAULT);
 649         }
 650 
 651         /* Set flash state to started */
 652         state->ts_fw_flashstarted = 1;
 653         state->ts_fw_flashdev          = dev;
 654 
 655         mutex_exit(&state->ts_fw_flashlock);
 656 
 657         /*
 658          * If "flash init" is successful, add an "on close" callback to the
 659          * current dev node to ensure that "flash fini" gets called later
 660          * even if the userland process prematurely exits.
 661          */
 662         ret = tavor_umap_db_set_onclose_cb(dev,
 663             TAVOR_ONCLOSE_FLASH_INPROGRESS,
 664             (void (*)(void *))tavor_ioctl_flash_cleanup, state);
 665         if (ret != DDI_SUCCESS) {
 666                 (void) tavor_ioctl_flash_fini(state, dev);
 667 
 668                 TNF_PROBE_0(tavor_ioctl_flash_init_set_cb_fail,
 669                     TAVOR_TNF_ERROR, "");
 670                 TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
 671                 return (EFAULT);
 672         }
 673 
 674         TAVOR_TNF_EXIT(tavor_ioctl_flash_init);
 675         return (0);
 676 }
 677 
 678 /*
 679  * tavor_ioctl_flash_fini()
 680  */
 681 static int
 682 tavor_ioctl_flash_fini(tavor_state_t *state, dev_t dev)
 683 {
 684         int ret;
 685 
 686         TAVOR_TNF_ENTER(tavor_ioctl_flash_fini);
 687 
 688         /*
 689          * Check that flash init ioctl has been called first.  And check
 690          * that the same dev_t that called init is the one calling fini now.
 691          */
 692         mutex_enter(&state->ts_fw_flashlock);
 693         if ((state->ts_fw_flashdev != dev) ||
 694             (state->ts_fw_flashstarted == 0)) {
 695                 mutex_exit(&state->ts_fw_flashlock);
 696                 TNF_PROBE_0(tavor_flash_bad_state, TAVOR_TNF_ERROR, "");
 697                 TAVOR_TNF_EXIT(tavor_ioctl_flash_fini);
 698                 return (EIO);
 699         }
 700 
 701         tavor_ioctl_flash_cleanup_nolock(state);
 702 
 703         mutex_exit(&state->ts_fw_flashlock);
 704 
 705         /*
 706          * If "flash fini" is successful, remove the "on close" callback
 707          * that was setup during "flash init".
 708          */
 709         ret = tavor_umap_db_clear_onclose_cb(dev,
 710             TAVOR_ONCLOSE_FLASH_INPROGRESS);
 711         if (ret != DDI_SUCCESS) {
 712                 TNF_PROBE_0(tavor_flash_fini_clear_cb_fail, TAVOR_TNF_ERROR,
 713                     "");
 714                 TAVOR_TNF_EXIT(tavor_ioctl_flash_fini);
 715                 return (EFAULT);
 716         }
 717 
 718         TAVOR_TNF_EXIT(tavor_ioctl_flash_fini);
 719         return (0);
 720 }
 721 
 722 
 723 /*
 724  * tavor_ioctl_flash_cleanup()
 725  */
 726 static void
 727 tavor_ioctl_flash_cleanup(tavor_state_t *state)
 728 {
 729         TAVOR_TNF_ENTER(tavor_ioctl_flash_cleanup);
 730 
 731         mutex_enter(&state->ts_fw_flashlock);
 732         tavor_ioctl_flash_cleanup_nolock(state);
 733         mutex_exit(&state->ts_fw_flashlock);
 734 
 735         TAVOR_TNF_EXIT(tavor_ioctl_flash_cleanup);
 736 }
 737 
 738 
 739 /*
 740  * tavor_ioctl_flash_cleanup_nolock()
 741  */
 742 static void
 743 tavor_ioctl_flash_cleanup_nolock(tavor_state_t *state)
 744 {
 745         TAVOR_TNF_ENTER(tavor_ioctl_flash_cleanup_nolock);
 746 
 747         ASSERT(MUTEX_HELD(&state->ts_fw_flashlock));
 748 
 749         /* free flash mem */
 750         kmem_free(state->ts_fw_sector, 1 << state->ts_fw_log_sector_sz);
 751 
 752         /* Fini the Flash */
 753         tavor_flash_fini(state);
 754 
 755         /* Set flash state to fini */
 756         state->ts_fw_flashstarted = 0;
 757         state->ts_fw_flashdev          = 0;
 758 
 759         TAVOR_TNF_EXIT(tavor_ioctl_flash_cleanup_nolock);
 760 }
 761 
 762 
 763 /*
 764  * tavor_ioctl_info()
 765  */
 766 static int
 767 tavor_ioctl_info(tavor_state_t *state, dev_t dev, intptr_t arg, int mode)
 768 {
 769         tavor_info_ioctl_t       info;
 770         tavor_flash_init_ioctl_t init_info;
 771 
 772         TAVOR_TNF_ENTER(tavor_ioctl_info);
 773 
 774         /*
 775          * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
 776          */
 777         if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
 778                 TNF_PROBE_0(tavor_ioctl_info_maintenance_mode_fail,
 779                     TAVOR_TNF_ERROR, "");
 780                 TAVOR_TNF_EXIT(tavor_ioctl_info);
 781                 return (EFAULT);
 782         }
 783 
 784         /* copyin the user struct to kernel */
 785         if (ddi_copyin((void *)arg, &info, sizeof (tavor_info_ioctl_t),
 786             mode) != 0) {
 787                 TNF_PROBE_0(tavor_ioctl_info_copyin_fail, TAVOR_TNF_ERROR, "");
 788                 TAVOR_TNF_EXIT(tavor_ioctl_info);
 789                 return (EFAULT);
 790         }
 791 
 792         /*
 793          * Check ioctl revision
 794          */
 795         if (info.ti_revision != TAVOR_VTS_IOCTL_REVISION) {
 796                 TNF_PROBE_0(tavor_ioctl_info_bad_rev, TAVOR_TNF_ERROR, "");
 797                 TAVOR_TNF_EXIT(tavor_ioctl_info);
 798                 return (EINVAL);
 799         }
 800 
 801         /*
 802          * If the 'fw_device_sz' has not been initialized yet, we initialize it
 803          * here.  This is done by leveraging the
 804          * tavor_ioctl_flash_init()/fini() calls.  We also hold our own mutex
 805          * around this operation in case we have multiple VTS threads in
 806          * process at the same time.
 807          */
 808         mutex_enter(&state->ts_info_lock);
 809         if (state->ts_fw_device_sz == 0) {
 810                 if (tavor_ioctl_flash_init(state, dev, (intptr_t)&init_info,
 811                     (FKIOCTL | mode)) != 0) {
 812                         mutex_exit(&state->ts_info_lock);
 813                         TNF_PROBE_0(tavor_ioctl_info_flash_init_fail,
 814                             TAVOR_TNF_ERROR, "");
 815                         TAVOR_TNF_EXIT(tavor_ioctl_info);
 816                         return (EFAULT);
 817                 }
 818                 (void) tavor_ioctl_flash_fini(state, dev);
 819         }
 820         mutex_exit(&state->ts_info_lock);
 821 
 822         info.ti_hw_rev           = state->ts_adapter.rev_id;
 823         info.ti_flash_sz         = state->ts_fw_device_sz;
 824         info.ti_fw_rev.tfi_maj   = state->ts_fw.fw_rev_major;
 825         info.ti_fw_rev.tfi_min   = state->ts_fw.fw_rev_minor;
 826         info.ti_fw_rev.tfi_sub   = state->ts_fw.fw_rev_subminor;
 827         info.ti_mem_start_offset = 0;
 828         info.ti_mem_end_offset   = state->ts_ddr.ddr_endaddr -
 829             state->ts_ddr.ddr_baseaddr;
 830 
 831         /* Copy ioctl results back to user struct */
 832         if (ddi_copyout(&info, (void *)arg, sizeof (tavor_info_ioctl_t),
 833             mode) != 0) {
 834                 TNF_PROBE_0(tavor_ioctl_info_copyout_fail, TAVOR_TNF_ERROR, "");
 835                 TAVOR_TNF_EXIT(tavor_ioctl_info);
 836                 return (EFAULT);
 837         }
 838 
 839         TAVOR_TNF_EXIT(tavor_ioctl_info);
 840         return (0);
 841 }
 842 
 843 /*
 844  * tavor_ioctl_ports()
 845  */
 846 static int
 847 tavor_ioctl_ports(tavor_state_t *state, intptr_t arg, int mode)
 848 {
 849         tavor_ports_ioctl_t     info;
 850         tavor_stat_port_ioctl_t portstat;
 851         ibt_hca_portinfo_t      pi;
 852         uint_t                  tbl_size;
 853         ib_gid_t                *sgid_tbl;
 854         ib_pkey_t               *pkey_tbl;
 855         int                     i;
 856 
 857         TAVOR_TNF_ENTER(tavor_ioctl_ports);
 858 
 859         /*
 860          * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
 861          */
 862         if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
 863                 TNF_PROBE_0(tavor_ioctl_ports_maintenance_mode_fail,
 864                     TAVOR_TNF_ERROR, "");
 865                 TAVOR_TNF_EXIT(tavor_ioctl_ports);
 866                 return (EFAULT);
 867         }
 868 
 869         /* copyin the user struct to kernel */
 870 #ifdef _MULTI_DATAMODEL
 871         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 872                 tavor_ports_ioctl32_t info32;
 873 
 874                 if (ddi_copyin((void *)arg, &info32,
 875                     sizeof (tavor_ports_ioctl32_t), mode) != 0) {
 876                         TNF_PROBE_0(tavor_ioctl_ports_copyin_fail,
 877                             TAVOR_TNF_ERROR, "");
 878                         TAVOR_TNF_EXIT(tavor_ioctl_ports);
 879                         return (EFAULT);
 880                 }
 881                 info.tp_revision  = info32.tp_revision;
 882                 info.tp_ports     =
 883                     (tavor_stat_port_ioctl_t *)(uintptr_t)info32.tp_ports;
 884                 info.tp_num_ports = info32.tp_num_ports;
 885 
 886         } else
 887 #endif /* _MULTI_DATAMODEL */
 888         if (ddi_copyin((void *)arg, &info, sizeof (tavor_ports_ioctl_t),
 889             mode) != 0) {
 890                 TNF_PROBE_0(tavor_ioctl_ports_copyin_fail, TAVOR_TNF_ERROR, "");
 891                 TAVOR_TNF_EXIT(tavor_ioctl_ports);
 892                 return (EFAULT);
 893         }
 894 
 895         /*
 896          * Check ioctl revision
 897          */
 898         if (info.tp_revision != TAVOR_VTS_IOCTL_REVISION) {
 899                 TNF_PROBE_0(tavor_ioctl_ports_bad_rev, TAVOR_TNF_ERROR, "");
 900                 TAVOR_TNF_EXIT(tavor_ioctl_ports);
 901                 return (EINVAL);
 902         }
 903 
 904         /* Allocate space for temporary GID table/PKey table */
 905         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
 906         sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
 907             KM_SLEEP);
 908         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
 909         pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
 910             KM_SLEEP);
 911 
 912         /*
 913          * Setup the number of ports, then loop through all ports and
 914          * query properties of each.
 915          */
 916         info.tp_num_ports = (uint8_t)state->ts_cfg_profile->cp_num_ports;
 917         for (i = 0; i < info.tp_num_ports; i++) {
 918                 /*
 919                  * Get portstate information from the device.  If
 920                  * tavor_port_query() fails, leave zeroes in user
 921                  * struct port entry and continue.
 922                  */
 923                 bzero(&pi, sizeof (ibt_hca_portinfo_t));
 924                 pi.p_sgid_tbl = sgid_tbl;
 925                 pi.p_pkey_tbl = pkey_tbl;
 926                 if (tavor_port_query(state, i + 1, &pi) != 0) {
 927                         TNF_PROBE_0(tavor_ioctl_ports_query_failed,
 928                             TAVOR_TNF_ERROR, "");
 929                 }
 930 
 931                 portstat.tsp_port_num   = pi.p_port_num;
 932                 portstat.tsp_state      = pi.p_linkstate;
 933                 portstat.tsp_guid       = pi.p_sgid_tbl[0].gid_guid;
 934 
 935                 /*
 936                  * Copy queried port results back to user struct.  If
 937                  * this fails, then break out of loop, attempt to copy
 938                  * out remaining info to user struct, and return (without
 939                  * error).
 940                  */
 941                 if (ddi_copyout(&portstat,
 942                     &(((tavor_stat_port_ioctl_t *)info.tp_ports)[i]),
 943                     sizeof (tavor_stat_port_ioctl_t), mode) != 0) {
 944                         break;
 945                 }
 946         }
 947 
 948         /* Free the temporary space used for GID table/PKey table */
 949         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
 950         kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
 951         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
 952         kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
 953 
 954         /* Copy ioctl results back to user struct */
 955 #ifdef _MULTI_DATAMODEL
 956         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
 957                 tavor_ports_ioctl32_t info32;
 958 
 959                 info32.tp_revision  = info.tp_revision;
 960                 info32.tp_ports     = (caddr32_t)(uintptr_t)info.tp_ports;
 961                 info32.tp_num_ports = info.tp_num_ports;
 962 
 963                 if (ddi_copyout(&info32, (void *)arg,
 964                     sizeof (tavor_ports_ioctl32_t), mode) != 0) {
 965                         TNF_PROBE_0(tavor_ioctl_ports_copyout_fail,
 966                             TAVOR_TNF_ERROR, "");
 967                         TAVOR_TNF_EXIT(tavor_ioctl_ports);
 968                         return (EFAULT);
 969                 }
 970         } else
 971 #endif /* _MULTI_DATAMODEL */
 972         if (ddi_copyout(&info, (void *)arg, sizeof (tavor_ports_ioctl_t),
 973             mode) != 0) {
 974                 TNF_PROBE_0(tavor_ioctl_ports_copyout_fail,
 975                     TAVOR_TNF_ERROR, "");
 976                 TAVOR_TNF_EXIT(tavor_ioctl_ports);
 977                 return (EFAULT);
 978         }
 979 
 980         TAVOR_TNF_EXIT(tavor_ioctl_ports);
 981         return (0);
 982 }
 983 
 984 /*
 985  * tavor_ioctl_loopback()
 986  */
 987 static int
 988 tavor_ioctl_loopback(tavor_state_t *state, intptr_t arg, int mode)
 989 {
 990         tavor_loopback_ioctl_t  lb;
 991         tavor_loopback_state_t  lstate;
 992         ibt_hca_portinfo_t      pi;
 993         uint_t                  tbl_size, loopmax, max_usec;
 994         ib_gid_t                *sgid_tbl;
 995         ib_pkey_t               *pkey_tbl;
 996         int                     j, iter, ret;
 997 
 998         TAVOR_TNF_ENTER(tavor_ioctl_loopback);
 999 
1000         /*
1001          * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
1002          */
1003         if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1004                 TNF_PROBE_0(tavor_ioctl_loopback_maintenance_mode_fail,
1005                     TAVOR_TNF_ERROR, "");
1006                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1007                 return (EFAULT);
1008         }
1009 
1010         /* copyin the user struct to kernel */
1011 #ifdef _MULTI_DATAMODEL
1012         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1013                 tavor_loopback_ioctl32_t lb32;
1014 
1015                 if (ddi_copyin((void *)arg, &lb32,
1016                     sizeof (tavor_loopback_ioctl32_t), mode) != 0) {
1017                         TNF_PROBE_0(tavor_ioctl_loopback_copyin_fail,
1018                             TAVOR_TNF_ERROR, "");
1019                         TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1020                         return (EFAULT);
1021                 }
1022                 lb.tlb_revision     = lb32.tlb_revision;
1023                 lb.tlb_send_buf     = (caddr_t)(uintptr_t)lb32.tlb_send_buf;
1024                 lb.tlb_fail_buf     = (caddr_t)(uintptr_t)lb32.tlb_fail_buf;
1025                 lb.tlb_buf_sz       = lb32.tlb_buf_sz;
1026                 lb.tlb_num_iter     = lb32.tlb_num_iter;
1027                 lb.tlb_pass_done    = lb32.tlb_pass_done;
1028                 lb.tlb_timeout      = lb32.tlb_timeout;
1029                 lb.tlb_error_type   = lb32.tlb_error_type;
1030                 lb.tlb_port_num     = lb32.tlb_port_num;
1031                 lb.tlb_num_retry    = lb32.tlb_num_retry;
1032         } else
1033 #endif /* _MULTI_DATAMODEL */
1034         if (ddi_copyin((void *)arg, &lb, sizeof (tavor_loopback_ioctl_t),
1035             mode) != 0) {
1036                 TNF_PROBE_0(tavor_ioctl_loopback_copyin_fail,
1037                     TAVOR_TNF_ERROR, "");
1038                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1039                 return (EFAULT);
1040         }
1041 
1042         /* Initialize the internal loopback test state structure */
1043         bzero(&lstate, sizeof (tavor_loopback_state_t));
1044 
1045         /*
1046          * Check ioctl revision
1047          */
1048         if (lb.tlb_revision != TAVOR_VTS_IOCTL_REVISION) {
1049                 lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_REVISION;
1050                 (void) tavor_loopback_copyout(&lb, arg, mode);
1051                 TNF_PROBE_0(tavor_ioctl_loopback_bad_rev,
1052                     TAVOR_TNF_ERROR, "");
1053                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1054                 return (EINVAL);
1055         }
1056 
1057         /* Validate that specified port number is legal */
1058         if (!tavor_portnum_is_valid(state, lb.tlb_port_num)) {
1059                 lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT;
1060                 (void) tavor_loopback_copyout(&lb, arg, mode);
1061                 TNF_PROBE_0(tavor_ioctl_loopback_inv_port,
1062                     TAVOR_TNF_ERROR, "");
1063                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1064                 return (EINVAL);
1065         }
1066 
1067         /* Allocate space for temporary GID table/PKey table */
1068         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
1069         sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
1070             KM_SLEEP);
1071         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
1072         pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
1073             KM_SLEEP);
1074 
1075         /*
1076          * Get portstate information from specific port on device
1077          */
1078         bzero(&pi, sizeof (ibt_hca_portinfo_t));
1079         pi.p_sgid_tbl = sgid_tbl;
1080         pi.p_pkey_tbl = pkey_tbl;
1081         if (tavor_port_query(state, lb.tlb_port_num, &pi) != 0) {
1082                 /* Free the temporary space used for GID table/PKey table */
1083                 tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
1084                 kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
1085                 tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
1086                 kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
1087 
1088                 lb.tlb_error_type = TAVOR_LOOPBACK_INVALID_PORT;
1089                 (void) tavor_loopback_copyout(&lb, arg, mode);
1090                 tavor_loopback_free_state(&lstate);
1091                 TNF_PROBE_0(tavor_ioctl_loopback_bad_port,
1092                     TAVOR_TNF_ERROR, "");
1093                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1094                 return (EINVAL);
1095         }
1096 
1097         lstate.tls_port    = pi.p_port_num;
1098         lstate.tls_lid     = pi.p_base_lid;
1099         lstate.tls_pkey_ix = (pi.p_linkstate == TAVOR_PORT_LINK_ACTIVE) ? 1 : 0;
1100         lstate.tls_state   = state;
1101         lstate.tls_retry   = lb.tlb_num_retry;
1102 
1103         /* Free the temporary space used for GID table/PKey table */
1104         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_gidtbl);
1105         kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
1106         tbl_size = (1 << state->ts_cfg_profile->cp_log_max_pkeytbl);
1107         kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
1108 
1109         /*
1110          * Compute the timeout duration in usec per the formula:
1111          *    to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
1112          * (plus we add a little fudge-factor here too)
1113          */
1114         lstate.tls_timeout = lb.tlb_timeout;
1115         max_usec = (4096 * (1 << lstate.tls_timeout)) / 1000;
1116         max_usec = max_usec * (lstate.tls_retry + 1);
1117         max_usec = max_usec + 10000;
1118 
1119         /*
1120          * Determine how many times we should loop before declaring a
1121          * timeout failure.
1122          */
1123         loopmax  = max_usec/TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR;
1124         if ((max_usec % TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
1125                 loopmax++;
1126         }
1127 
1128         if (lb.tlb_send_buf == NULL || lb.tlb_buf_sz == 0) {
1129                 lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_INVALID;
1130                 (void) tavor_loopback_copyout(&lb, arg, mode);
1131                 tavor_loopback_free_state(&lstate);
1132                 TNF_PROBE_0(tavor_ioctl_loopback_buf_null,
1133                     TAVOR_TNF_ERROR, "");
1134                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1135                 return (EINVAL);
1136         }
1137 
1138         /* Allocate protection domain (PD) */
1139         if (tavor_loopback_init(state, &lstate) != 0) {
1140                 lb.tlb_error_type = lstate.tls_err;
1141                 (void) tavor_loopback_copyout(&lb, arg, mode);
1142                 tavor_loopback_free_state(&lstate);
1143                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1144                 return (EFAULT);
1145         }
1146 
1147         /* Allocate and register a TX buffer */
1148         if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_tx,
1149             lb.tlb_buf_sz) != 0) {
1150                 lb.tlb_error_type =
1151                     TAVOR_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
1152                 (void) tavor_loopback_copyout(&lb, arg, mode);
1153                 tavor_loopback_free_state(&lstate);
1154                 TNF_PROBE_0(tavor_ioctl_loopback_txbuf_alloc_fail,
1155                     TAVOR_TNF_ERROR, "");
1156                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1157                 return (EFAULT);
1158         }
1159 
1160         /* Allocate and register an RX buffer */
1161         if (tavor_loopback_alloc_mem(&lstate, &lstate.tls_rx,
1162             lb.tlb_buf_sz) != 0) {
1163                 lb.tlb_error_type =
1164                     TAVOR_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
1165                 (void) tavor_loopback_copyout(&lb, arg, mode);
1166                 tavor_loopback_free_state(&lstate);
1167                 TNF_PROBE_0(tavor_ioctl_loopback_rxbuf_alloc_fail,
1168                     TAVOR_TNF_ERROR, "");
1169                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1170                 return (EFAULT);
1171         }
1172 
1173         /* Copy in the transmit buffer data */
1174         if (ddi_copyin((void *)lb.tlb_send_buf, lstate.tls_tx.tlc_buf,
1175             lb.tlb_buf_sz, mode) != 0) {
1176                 lb.tlb_error_type = TAVOR_LOOPBACK_SEND_BUF_COPY_FAIL;
1177                 (void) tavor_loopback_copyout(&lb, arg, mode);
1178                 tavor_loopback_free_state(&lstate);
1179                 TNF_PROBE_0(tavor_ioctl_loopback_tx_copyin_fail,
1180                     TAVOR_TNF_ERROR, "");
1181                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1182                 return (EFAULT);
1183         }
1184 
1185         /* Allocate the transmit QP and CQs */
1186         lstate.tls_err = TAVOR_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
1187         if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_tx) != 0) {
1188                 lb.tlb_error_type = lstate.tls_err;
1189                 (void) tavor_loopback_copyout(&lb, arg, mode);
1190                 tavor_loopback_free_state(&lstate);
1191                 TNF_PROBE_0(tavor_ioctl_loopback_txqp_alloc_fail,
1192                     TAVOR_TNF_ERROR, "");
1193                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1194                 return (EFAULT);
1195         }
1196 
1197         /* Allocate the receive QP and CQs */
1198         lstate.tls_err = TAVOR_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
1199         if (tavor_loopback_alloc_qps(&lstate, &lstate.tls_rx) != 0) {
1200                 lb.tlb_error_type = lstate.tls_err;
1201                 (void) tavor_loopback_copyout(&lb, arg, mode);
1202                 tavor_loopback_free_state(&lstate);
1203                 TNF_PROBE_0(tavor_ioctl_loopback_rxqp_alloc_fail,
1204                     TAVOR_TNF_ERROR, "");
1205                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1206                 return (EFAULT);
1207         }
1208 
1209         /* Activate the TX QP (connect to RX QP) */
1210         lstate.tls_err = TAVOR_LOOPBACK_XMIT_QP_INIT_FAIL;
1211         if (tavor_loopback_modify_qp(&lstate, &lstate.tls_tx,
1212             lstate.tls_rx.tlc_qp_num) != 0) {
1213                 lb.tlb_error_type = lstate.tls_err;
1214                 (void) tavor_loopback_copyout(&lb, arg, mode);
1215                 tavor_loopback_free_state(&lstate);
1216                 TNF_PROBE_0(tavor_ioctl_loopback_txqp_init_fail,
1217                     TAVOR_TNF_ERROR, "");
1218                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1219                 return (EFAULT);
1220         }
1221 
1222         /* Activate the RX QP (connect to TX QP) */
1223         lstate.tls_err = TAVOR_LOOPBACK_RECV_QP_INIT_FAIL;
1224         if (tavor_loopback_modify_qp(&lstate, &lstate.tls_rx,
1225             lstate.tls_tx.tlc_qp_num) != 0) {
1226                 lb.tlb_error_type = lstate.tls_err;
1227                 (void) tavor_loopback_copyout(&lb, arg, mode);
1228                 tavor_loopback_free_state(&lstate);
1229                 TNF_PROBE_0(tavor_ioctl_loopback_rxqp_init_fail,
1230                     TAVOR_TNF_ERROR, "");
1231                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1232                 return (EFAULT);
1233         }
1234 
1235         /* Run the loopback test (for specified number of iterations) */
1236         lb.tlb_pass_done = 0;
1237         for (iter = 0; iter < lb.tlb_num_iter; iter++) {
1238                 lstate.tls_err = 0;
1239                 bzero(lstate.tls_rx.tlc_buf, lb.tlb_buf_sz);
1240 
1241                 /* Post RDMA Write work request */
1242                 if (tavor_loopback_post_send(&lstate, &lstate.tls_tx,
1243                     &lstate.tls_rx) != IBT_SUCCESS) {
1244                         lb.tlb_error_type = TAVOR_LOOPBACK_WQE_POST_FAIL;
1245                         (void) tavor_loopback_copyout(&lb, arg, mode);
1246                         tavor_loopback_free_state(&lstate);
1247                         TNF_PROBE_0(tavor_ioctl_loopback_wqe_post_fail,
1248                             TAVOR_TNF_ERROR, "");
1249                         TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1250                         return (EFAULT);
1251                 }
1252 
1253                 /* Poll the TX CQ for a completion every few ticks */
1254                 for (j = 0; j < loopmax; j++) {
1255                         delay(drv_usectohz(TAVOR_VTS_LOOPBACK_MIN_WAIT_DUR));
1256 
1257                         ret = tavor_loopback_poll_cq(&lstate, &lstate.tls_tx);
1258                         if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
1259                             ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
1260                                 lb.tlb_error_type = TAVOR_LOOPBACK_CQ_POLL_FAIL;
1261                                 if (ddi_copyout(lstate.tls_rx.tlc_buf,
1262                                     lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz,
1263                                     mode) != 0) {
1264                                         TNF_PROBE_0(
1265                                             tavor_ioctl_loopback_xfer_co_fail,
1266                                             TAVOR_TNF_ERROR, "");
1267                                         TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1268                                         return (EFAULT);
1269                                 }
1270                                 (void) tavor_loopback_copyout(&lb, arg, mode);
1271                                 tavor_loopback_free_state(&lstate);
1272                                 TNF_PROBE_0(tavor_ioctl_loopback_xfer_fail,
1273                                     TAVOR_TNF_ERROR, "");
1274                                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1275                                 return (EFAULT);
1276                         } else if (ret == IBT_CQ_EMPTY) {
1277                                 continue;
1278                         }
1279 
1280                         /* Compare the data buffers */
1281                         if (bcmp(lstate.tls_tx.tlc_buf, lstate.tls_rx.tlc_buf,
1282                             lb.tlb_buf_sz) == 0) {
1283                                 break;
1284                         } else {
1285                                 lb.tlb_error_type =
1286                                     TAVOR_LOOPBACK_SEND_RECV_COMPARE_FAIL;
1287                                 if (ddi_copyout(lstate.tls_rx.tlc_buf,
1288                                     lb.tlb_fail_buf, lstate.tls_tx.tlc_buf_sz,
1289                                     mode) != 0) {
1290                                         TNF_PROBE_0(
1291                                             tavor_ioctl_loopback_bcmp_co_fail,
1292                                             TAVOR_TNF_ERROR, "");
1293                                         TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1294                                         return (EFAULT);
1295                                 }
1296                                 (void) tavor_loopback_copyout(&lb, arg, mode);
1297                                 tavor_loopback_free_state(&lstate);
1298                                 TNF_PROBE_0(tavor_ioctl_loopback_bcmp_fail,
1299                                     TAVOR_TNF_ERROR, "");
1300                                 TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1301                                 return (EFAULT);
1302                         }
1303                 }
1304 
1305                 lstate.tls_err   = TAVOR_LOOPBACK_SUCCESS;
1306                 lb.tlb_pass_done = iter + 1;
1307         }
1308 
1309         lb.tlb_error_type = TAVOR_LOOPBACK_SUCCESS;
1310 
1311         /* Copy ioctl results back to user struct */
1312         ret = tavor_loopback_copyout(&lb, arg, mode);
1313 
1314         /* Free up everything and release all consumed resources */
1315         tavor_loopback_free_state(&lstate);
1316 
1317         TAVOR_TNF_EXIT(tavor_ioctl_loopback);
1318         return (ret);
1319 }
1320 
1321 /*
1322  * tavor_ioctl_ddr_read()
1323  */
1324 static int
1325 tavor_ioctl_ddr_read(tavor_state_t *state, intptr_t arg, int mode)
1326 {
1327         tavor_ddr_read_ioctl_t  rdreg;
1328         uint32_t                *addr;
1329         uintptr_t               baseaddr;
1330         uint64_t                ddr_size;
1331 
1332         TAVOR_TNF_ENTER(tavor_ioctl_ddr_read);
1333 
1334         /*
1335          * Access to Tavor VTS ioctls is not allowed in "maintenance mode".
1336          */
1337         if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1338                 TNF_PROBE_0(tavor_ioctl_ddr_read_maintenance_mode_fail,
1339                     TAVOR_TNF_ERROR, "");
1340                 TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1341                 return (EFAULT);
1342         }
1343 
1344         /* copyin the user struct to kernel */
1345         if (ddi_copyin((void *)arg, &rdreg, sizeof (tavor_ddr_read_ioctl_t),
1346             mode) != 0) {
1347                 TNF_PROBE_0(tavor_ioctl_ddr_read_copyin_fail,
1348                     TAVOR_TNF_ERROR, "");
1349                 TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1350                 return (EFAULT);
1351         }
1352 
1353         /*
1354          * Check ioctl revision
1355          */
1356         if (rdreg.tdr_revision != TAVOR_VTS_IOCTL_REVISION) {
1357                 TNF_PROBE_0(tavor_ioctl_ddr_read_bad_rev, TAVOR_TNF_ERROR, "");
1358                 TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1359                 return (EINVAL);
1360         }
1361 
1362         /*
1363          * Check for valid offset
1364          */
1365         ddr_size = (state->ts_ddr.ddr_endaddr - state->ts_ddr.ddr_baseaddr + 1);
1366         if ((uint64_t)rdreg.tdr_offset >= ddr_size) {
1367                 TNF_PROBE_0(tavor_ioctl_ddr_read_bad_offset,
1368                     TAVOR_TNF_ERROR, "");
1369                 TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1370                 return (EINVAL);
1371         }
1372 
1373         /* Determine base address for requested register read */
1374         baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
1375 
1376         /* Ensure that address is properly-aligned */
1377         addr = (uint32_t *)((baseaddr + rdreg.tdr_offset) & ~0x3);
1378 
1379         /* Read the register pointed to by addr */
1380         rdreg.tdr_data = ddi_get32(state->ts_reg_cmdhdl, addr);
1381 
1382         /* Copy ioctl results back to user struct */
1383         if (ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_ddr_read_ioctl_t),
1384             mode) != 0) {
1385                 TNF_PROBE_0(tavor_ioctl_ddr_read_copyout_fail,
1386                     TAVOR_TNF_ERROR, "");
1387                 TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1388                 return (EFAULT);
1389         }
1390 
1391         TAVOR_TNF_EXIT(tavor_ioctl_ddr_read);
1392         return (0);
1393 }
1394 
1395 
1396 #ifdef  DEBUG
1397 /*
1398  * tavor_ioctl_reg_read()
1399  */
1400 static int
1401 tavor_ioctl_reg_read(tavor_state_t *state, intptr_t arg, int mode)
1402 {
1403         tavor_reg_ioctl_t       rdreg;
1404         uint32_t                *addr;
1405         uintptr_t               baseaddr;
1406         int                     status;
1407 
1408         TAVOR_TNF_ENTER(tavor_ioctl_reg_read);
1409 
1410         /*
1411          * Access to Tavor registers is not allowed in "maintenance mode".
1412          * This is primarily because the device may not have BARs to access
1413          */
1414         if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1415                 TNF_PROBE_0(tavor_ioctl_reg_read_maintence_mode_fail,
1416                     TAVOR_TNF_ERROR, "");
1417                 TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1418                 return (EFAULT);
1419         }
1420 
1421         /* Copy in the tavor_reg_ioctl_t structure */
1422         status = ddi_copyin((void *)arg, &rdreg, sizeof (tavor_reg_ioctl_t),
1423             mode);
1424         if (status != 0) {
1425                 TNF_PROBE_0(tavor_ioctl_reg_read_copyin_fail,
1426                     TAVOR_TNF_ERROR, "");
1427                 TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1428                 return (EFAULT);
1429         }
1430 
1431         /* Determine base address for requested register set */
1432         switch (rdreg.trg_reg_set) {
1433         case TAVOR_CMD_BAR:
1434                 baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr;
1435                 break;
1436 
1437         case TAVOR_UAR_BAR:
1438                 baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr;
1439                 break;
1440 
1441         case TAVOR_DDR_BAR:
1442                 baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
1443                 break;
1444 
1445         default:
1446                 TNF_PROBE_0(tavor_ioctl_reg_read_invregset_fail,
1447                     TAVOR_TNF_ERROR, "");
1448                 TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1449                 return (EFAULT);
1450         }
1451 
1452         /* Ensure that address is properly-aligned */
1453         addr = (uint32_t *)((baseaddr + rdreg.trg_offset) & ~0x3);
1454 
1455         /* Read the register pointed to by addr */
1456         rdreg.trg_data = ddi_get32(state->ts_reg_cmdhdl, addr);
1457 
1458         /* Copy in the result into the tavor_reg_ioctl_t structure */
1459         status = ddi_copyout(&rdreg, (void *)arg, sizeof (tavor_reg_ioctl_t),
1460             mode);
1461         if (status != 0) {
1462                 TNF_PROBE_0(tavor_ioctl_reg_read_copyout_fail,
1463                     TAVOR_TNF_ERROR, "");
1464                 TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1465                 return (EFAULT);
1466         }
1467 
1468         TAVOR_TNF_EXIT(tavor_ioctl_reg_read);
1469         return (0);
1470 }
1471 
1472 
1473 /*
1474  * tavor_ioctl_reg_write()
1475  */
1476 static int
1477 tavor_ioctl_reg_write(tavor_state_t *state, intptr_t arg, int mode)
1478 {
1479         tavor_reg_ioctl_t       wrreg;
1480         uint32_t                *addr;
1481         uintptr_t               baseaddr;
1482         int                     status;
1483 
1484         TAVOR_TNF_ENTER(tavor_ioctl_reg_write);
1485 
1486         /*
1487          * Access to Tavor registers is not allowed in "maintenance mode".
1488          * This is primarily because the device may not have BARs to access
1489          */
1490         if (state->ts_operational_mode == TAVOR_MAINTENANCE_MODE) {
1491                 TNF_PROBE_0(tavor_ioctl_reg_write_maintence_mode_fail,
1492                     TAVOR_TNF_ERROR, "");
1493                 TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1494                 return (EFAULT);
1495         }
1496 
1497         /* Copy in the tavor_reg_ioctl_t structure */
1498         status = ddi_copyin((void *)arg, &wrreg, sizeof (tavor_reg_ioctl_t),
1499             mode);
1500         if (status != 0) {
1501                 TNF_PROBE_0(tavor_ioctl_reg_write_copyin_fail,
1502                     TAVOR_TNF_ERROR, "");
1503                 TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1504                 return (EFAULT);
1505         }
1506 
1507         /* Determine base address for requested register set */
1508         switch (wrreg.trg_reg_set) {
1509         case TAVOR_CMD_BAR:
1510                 baseaddr = (uintptr_t)state->ts_reg_cmd_baseaddr;
1511                 break;
1512 
1513         case TAVOR_UAR_BAR:
1514                 baseaddr = (uintptr_t)state->ts_reg_uar_baseaddr;
1515                 break;
1516 
1517         case TAVOR_DDR_BAR:
1518                 baseaddr = (uintptr_t)state->ts_reg_ddr_baseaddr;
1519                 break;
1520 
1521         default:
1522                 TNF_PROBE_0(tavor_ioctl_reg_write_invregset_fail,
1523                     TAVOR_TNF_ERROR, "");
1524                 TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1525                 return (EFAULT);
1526         }
1527 
1528         /* Ensure that address is properly-aligned */
1529         addr = (uint32_t *)((baseaddr + wrreg.trg_offset) & ~0x3);
1530 
1531         /* Write the data to the register pointed to by addr */
1532         ddi_put32(state->ts_reg_cmdhdl, addr, wrreg.trg_data);
1533 
1534         TAVOR_TNF_EXIT(tavor_ioctl_reg_write);
1535         return (0);
1536 }
1537 #endif  /* DEBUG */
1538 
1539 /*
1540  * tavor_flash_reset()
1541  */
1542 static void
1543 tavor_flash_reset(tavor_state_t *state)
1544 {
1545         TAVOR_TNF_ENTER(tavor_flash_reset);
1546 
1547         /*
1548          * Performs a reset to the flash device.  After a reset the flash will
1549          * be operating in normal mode (capable of read/write, etc.).
1550          */
1551         switch (state->ts_fw_cmdset) {
1552         case TAVOR_FLASH_AMD_CMDSET:
1553                 tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_AMD);
1554                 break;
1555 
1556         case TAVOR_FLASH_INTEL_CMDSET:
1557                 tavor_flash_write(state, 0x555, TAVOR_HW_FLASH_RESET_INTEL);
1558                 break;
1559 
1560         default:
1561                 break;
1562         }
1563 
1564         TAVOR_TNF_EXIT(tavor_flash_reset);
1565 }
1566 
1567 /*
1568  * tavor_flash_read_sector()
1569  */
1570 static void
1571 tavor_flash_read_sector(tavor_state_t *state, uint32_t sector_num)
1572 {
1573         uint32_t addr;
1574         uint32_t end_addr;
1575         uint32_t *image;
1576         int i;
1577 
1578         TAVOR_TNF_ENTER(tavor_flash_read_sector);
1579 
1580         image = (uint32_t *)&state->ts_fw_sector[0];
1581 
1582         /*
1583          * Calculate the start and end address of the sector, based on the
1584          * sector number passed in.
1585          */
1586         addr = sector_num << state->ts_fw_log_sector_sz;
1587         end_addr = addr + (1 << state->ts_fw_log_sector_sz);
1588 
1589         /* Set the flash bank correctly for the given address */
1590         tavor_flash_bank(state, addr);
1591 
1592         /* Read the entire sector, one quadlet at a time */
1593         for (i = 0; addr < end_addr; i++, addr += 4) {
1594                 image[i] = tavor_flash_read(state, addr);
1595         }
1596 
1597         TAVOR_TNF_EXIT(tavor_flash_read_sector);
1598 }
1599 
1600 /*
1601  * tavor_flash_read_quadlet()
1602  */
1603 static void
1604 tavor_flash_read_quadlet(tavor_state_t *state, uint32_t *data,
1605     uint32_t addr)
1606 {
1607         TAVOR_TNF_ENTER(tavor_flash_read_quadlet);
1608 
1609         /* Set the flash bank correctly for the given address */
1610         tavor_flash_bank(state, addr);
1611 
1612         /* Read one quadlet of data */
1613         *data = tavor_flash_read(state, addr);
1614 
1615         TAVOR_TNF_EXIT(tavor_flash_read_quadlet);
1616 }
1617 
1618 /*
1619  * tavor_flash_write_sector()
1620  */
1621 static int
1622 tavor_flash_write_sector(tavor_state_t *state, uint32_t sector_num)
1623 {
1624         uint32_t addr;
1625         uint32_t end_addr;
1626         uchar_t *sector;
1627         int     status = 0;
1628         int     i;
1629 
1630         TAVOR_TNF_ENTER(tavor_flash_write_sector);
1631 
1632         sector = (uchar_t *)&state->ts_fw_sector[0];
1633 
1634         /*
1635          * Calculate the start and end address of the sector, based on the
1636          * sector number passed in.
1637          */
1638         addr = sector_num << state->ts_fw_log_sector_sz;
1639         end_addr = addr + (1 << state->ts_fw_log_sector_sz);
1640 
1641         /* Set the flash bank correctly for the given address */
1642         tavor_flash_bank(state, addr);
1643 
1644         /* Erase the sector before writing */
1645         tavor_flash_reset(state);
1646         status = tavor_flash_erase_sector(state, sector_num);
1647         if (status != 0) {
1648                 TAVOR_TNF_EXIT(tavor_flash_write_sector);
1649                 return (status);
1650         }
1651 
1652         /* Write the entire sector, one byte at a time */
1653         for (i = 0; addr < end_addr; i++, addr++) {
1654                 status = tavor_flash_write_byte(state, addr, sector[i]);
1655                 if (status != 0) {
1656                         break;
1657                 }
1658         }
1659 
1660         tavor_flash_reset(state);
1661         TAVOR_TNF_EXIT(tavor_flash_write_sector);
1662         return (status);
1663 }
1664 
1665 /*
1666  * tavor_flash_write_byte()
1667  */
1668 static int
1669 tavor_flash_write_byte(tavor_state_t *state, uint32_t addr, uchar_t data)
1670 {
1671         uint32_t stat;
1672         int status = 0;
1673         int i;
1674 
1675         TAVOR_TNF_ENTER(tavor_flash_write_byte);
1676 
1677         switch (state->ts_fw_cmdset) {
1678         case TAVOR_FLASH_AMD_CMDSET:
1679                 /* Issue Flash Byte program command */
1680                 tavor_flash_write(state, addr, 0xAA);
1681                 tavor_flash_write(state, addr, 0x55);
1682                 tavor_flash_write(state, addr, 0xA0);
1683                 tavor_flash_write(state, addr, data);
1684 
1685                 /*
1686                  * Wait for Write Byte to Complete:
1687                  *   1) Wait 1usec
1688                  *   2) Read status of the write operation
1689                  *   3) Determine if we have timed out the write operation
1690                  *   4) Compare correct data value to the status value that
1691                  *      was read from the same address.
1692                  */
1693                 i = 0;
1694                 do {
1695                         drv_usecwait(1);
1696                         stat = tavor_flash_read(state, addr & ~3);
1697 
1698                         if (i == tavor_hw_flash_timeout_write) {
1699                                 cmn_err(CE_WARN,
1700                                     "tavor_flash_write_byte: ACS write "
1701                                     "timeout: addr: 0x%x, data: 0x%x\n",
1702                                     addr, data);
1703                                 status = EIO;
1704                                 break;
1705                         }
1706 
1707                         i++;
1708                 } while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
1709                 break;
1710 
1711         case TAVOR_FLASH_INTEL_CMDSET:
1712                 /* Issue Flash Byte program command */
1713                 tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_WRITE);
1714                 tavor_flash_write(state, addr, data);
1715 
1716                 /* wait for completion */
1717                 i = 0;
1718                 do {
1719                         drv_usecwait(1);
1720                         stat = tavor_flash_read(state, addr & ~3);
1721 
1722                         if (i == tavor_hw_flash_timeout_write) {
1723                                 cmn_err(CE_WARN,
1724                                     "tavor_flash_write_byte: ICS write "
1725                                     "timeout: addr: %x, data: %x\n",
1726                                     addr, data);
1727                                 status = EIO;
1728                                 break;
1729                         }
1730 
1731                         i++;
1732                 } while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0);
1733 
1734                 if (stat & TAVOR_HW_FLASH_ICS_ERROR) {
1735                         cmn_err(CE_WARN,
1736                             "tavor_flash_write_byte: ICS write cmd error: "
1737                             "addr: %x, data: %x\n",
1738                             addr, data);
1739                         status = EIO;
1740                 }
1741                 break;
1742 
1743         default:
1744                 cmn_err(CE_WARN,
1745                     "tavor_flash_write_byte: unknown cmd set: 0x%x\n",
1746                     state->ts_fw_cmdset);
1747                 status = EIO;
1748                 break;
1749         }
1750 
1751         TAVOR_TNF_EXIT(tavor_flash_write_byte);
1752         return (status);
1753 }
1754 
1755 /*
1756  * tavor_flash_erase_sector()
1757  */
1758 static int
1759 tavor_flash_erase_sector(tavor_state_t *state, uint32_t sector_num)
1760 {
1761         uint32_t addr;
1762         uint32_t stat;
1763         int status = 0;
1764         int i;
1765 
1766         TAVOR_TNF_ENTER(tavor_flash_erase_sector);
1767 
1768         /* Get address from sector num */
1769         addr = sector_num << state->ts_fw_log_sector_sz;
1770 
1771         switch (state->ts_fw_cmdset) {
1772         case TAVOR_FLASH_AMD_CMDSET:
1773                 /* Issue Flash Sector Erase Command */
1774                 tavor_flash_write(state, addr, 0xAA);
1775                 tavor_flash_write(state, addr, 0x55);
1776                 tavor_flash_write(state, addr, 0x80);
1777                 tavor_flash_write(state, addr, 0xAA);
1778                 tavor_flash_write(state, addr, 0x55);
1779                 tavor_flash_write(state, addr, 0x30);
1780 
1781                 /*
1782                  * Wait for Sector Erase to Complete
1783                  *   1) Wait 1usec
1784                  *   2) read the status at the base addr of the sector
1785                  *   3) Determine if we have timed out
1786                  *   4) Compare status of address with the value of a fully
1787                  *      erased quadlet. If these are equal, the sector
1788                  *      has been erased.
1789                  */
1790                 i = 0;
1791                 do {
1792                         /* wait 1usec */
1793                         drv_usecwait(1);
1794                         stat = tavor_flash_read(state, addr);
1795 
1796                         if (i == tavor_hw_flash_timeout_erase) {
1797                                 cmn_err(CE_WARN,
1798                                     "tavor_flash_erase_sector: "
1799                                     "ACS erase timeout\n");
1800                                 status = EIO;
1801                                 break;
1802                         }
1803 
1804                         i++;
1805                 } while (stat != 0xFFFFFFFF);
1806                 break;
1807 
1808         case TAVOR_FLASH_INTEL_CMDSET:
1809                 /* Issue Erase Command */
1810                 tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_ERASE);
1811                 tavor_flash_write(state, addr, TAVOR_HW_FLASH_ICS_CONFIRM);
1812 
1813                 /* wait for completion */
1814                 i = 0;
1815                 do {
1816                         drv_usecwait(1);
1817                         stat = tavor_flash_read(state, addr & ~3);
1818 
1819                         if (i == tavor_hw_flash_timeout_erase) {
1820                                 cmn_err(CE_WARN,
1821                                     "tavor_flash_erase_sector: "
1822                                     "ICS erase timeout\n");
1823                                 status = EIO;
1824                                 break;
1825                         }
1826 
1827                         i++;
1828                 } while ((stat & TAVOR_HW_FLASH_ICS_READY) == 0);
1829 
1830                 if (stat & TAVOR_HW_FLASH_ICS_ERROR) {
1831                         cmn_err(CE_WARN,
1832                             "tavor_flash_erase_sector: "
1833                             "ICS erase cmd error\n");
1834                         status = EIO;
1835                 }
1836                 break;
1837 
1838         default:
1839                 cmn_err(CE_WARN,
1840                     "tavor_flash_erase_sector: unknown cmd set: 0x%x\n",
1841                     state->ts_fw_cmdset);
1842                 status = EIO;
1843                 break;
1844         }
1845 
1846         tavor_flash_reset(state);
1847 
1848         TAVOR_TNF_EXIT(tavor_flash_erase_sector);
1849         return (status);
1850 }
1851 
1852 /*
1853  * tavor_flash_erase_chip()
1854  */
1855 static int
1856 tavor_flash_erase_chip(tavor_state_t *state)
1857 {
1858         uint_t size;
1859         uint32_t stat;
1860         int status = 0;
1861         int num_sect;
1862         int i;
1863 
1864         TAVOR_TNF_ENTER(tavor_flash_erase_chip);
1865 
1866         switch (state->ts_fw_cmdset) {
1867         case TAVOR_FLASH_AMD_CMDSET:
1868                 /* Issue Flash Chip Erase Command */
1869                 tavor_flash_write(state, 0, 0xAA);
1870                 tavor_flash_write(state, 0, 0x55);
1871                 tavor_flash_write(state, 0, 0x80);
1872                 tavor_flash_write(state, 0, 0xAA);
1873                 tavor_flash_write(state, 0, 0x55);
1874                 tavor_flash_write(state, 0, 0x10);
1875 
1876                 /*
1877                  * Wait for Chip Erase to Complete
1878                  *   1) Wait 1usec
1879                  *   2) read the status at the base addr of the sector
1880                  *   3) Determine if we have timed out
1881                  *   4) Compare status of address with the value of a
1882                  *      fully erased quadlet. If these are equal, the
1883                  *      chip has been erased.
1884                  */
1885                 i = 0;
1886                 do {
1887                         /* wait 1usec */
1888                         drv_usecwait(1);
1889                         stat = tavor_flash_read(state, 0);
1890 
1891                         if (i == tavor_hw_flash_timeout_erase) {
1892                                 cmn_err(CE_WARN,
1893                                     "tavor_flash_erase_chip: erase timeout\n");
1894                                 status = EIO;
1895                                 break;
1896                         }
1897 
1898                         i++;
1899                 } while (stat != 0xFFFFFFFF);
1900                 break;
1901 
1902         case TAVOR_FLASH_INTEL_CMDSET:
1903                 /*
1904                  * The Intel chip doesn't have a chip erase command, so erase
1905                  * all blocks one at a time.
1906                  */
1907                 size = (0x1 << state->ts_fw_log_sector_sz);
1908                 num_sect = state->ts_fw_device_sz / size;
1909 
1910                 for (i = 0; i < num_sect; i++) {
1911                         status = tavor_flash_erase_sector(state, i);
1912                         if (status != 0) {
1913                                 cmn_err(CE_WARN,
1914                                     "tavor_flash_erase_chip: "
1915                                     "ICS sector %d erase error\n", i);
1916                                 status = EIO;
1917                                 break;
1918                         }
1919                 }
1920                 break;
1921 
1922         default:
1923                 cmn_err(CE_WARN, "tavor_flash_erase_chip: "
1924                     "unknown cmd set: 0x%x\n", state->ts_fw_cmdset);
1925                 status = EIO;
1926                 break;
1927         }
1928 
1929         TAVOR_TNF_EXIT(tavor_flash_erase_chip);
1930         return (status);
1931 }
1932 
1933 /*
1934  * tavor_flash_bank()
1935  */
1936 static void
1937 tavor_flash_bank(tavor_state_t *state, uint32_t addr)
1938 {
1939         ddi_acc_handle_t        hdl;
1940         uint32_t                bank;
1941 
1942         TAVOR_TNF_ENTER(tavor_flash_bank);
1943 
1944         /* Set handle */
1945         hdl = state->ts_pci_cfghdl;
1946 
1947         /* Determine the bank setting from the address */
1948         bank = addr & TAVOR_HW_FLASH_BANK_MASK;
1949 
1950         /*
1951          * If the bank is different from the currently set bank, we need to
1952          * change it.  Also, if an 'addr' of 0 is given, this allows the
1953          * capability to force the flash bank to 0.  This is useful at init
1954          * time to initially set the bank value
1955          */
1956         if (state->ts_fw_flashbank != bank || addr == 0) {
1957                 /* Set bank using the GPIO settings */
1958                 tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATACLEAR, 0x70);
1959                 tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DATASET,
1960                     (bank >> 15) & 0x70);
1961 
1962                 /* Save the bank state */
1963                 state->ts_fw_flashbank = bank;
1964         }
1965 
1966         TAVOR_TNF_EXIT(tavor_flash_bank);
1967 }
1968 
1969 /*
1970  * tavor_flash_read()
1971  */
1972 static uint32_t
1973 tavor_flash_read(tavor_state_t *state, uint32_t addr)
1974 {
1975         ddi_acc_handle_t        hdl;
1976         uint32_t                data;
1977         int                     timeout;
1978 
1979         TAVOR_TNF_ENTER(tavor_flash_read);
1980 
1981         /* Set handle */
1982         hdl = state->ts_pci_cfghdl;
1983 
1984         /*
1985          * The Read operation does the following:
1986          *   1) Write the masked address to the TAVOR_FLASH_ADDR register.
1987          *      Only the least significant 19 bits are valid.
1988          *   2) Read back the register until the command has completed.
1989          *   3) Read the data retrieved from the address at the TAVOR_FLASH_DATA
1990          *      register.
1991          */
1992         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR,
1993             (addr & TAVOR_HW_FLASH_ADDR_MASK) | (1 << 29));
1994 
1995         timeout = 0;
1996         do {
1997                 data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR);
1998                 timeout++;
1999         } while ((data & TAVOR_HW_FLASH_CMD_MASK) &&
2000             (timeout < tavor_hw_flash_timeout_config));
2001 
2002         if (timeout == tavor_hw_flash_timeout_config) {
2003                 cmn_err(CE_WARN, "tavor_flash_read: config command timeout.\n");
2004         }
2005 
2006         data = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_DATA);
2007 
2008         TAVOR_TNF_EXIT(tavor_flash_read);
2009         return (data);
2010 }
2011 
2012 /*
2013  * tavor_flash_write()
2014  */
2015 static void
2016 tavor_flash_write(tavor_state_t *state, uint32_t addr, uchar_t data)
2017 {
2018         ddi_acc_handle_t        hdl;
2019         int                     cmd;
2020         int                     timeout;
2021 
2022         TAVOR_TNF_ENTER(tavor_flash_write);
2023 
2024         /* Set handle */
2025         hdl = state->ts_pci_cfghdl;
2026 
2027         /*
2028          * The Write operation does the following:
2029          *   1) Write the data to be written to the TAVOR_FLASH_DATA offset.
2030          *   2) Write the address to write the data to to the TAVOR_FLASH_ADDR
2031          *      offset.
2032          *   3) Wait until the write completes.
2033          */
2034         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_DATA, data << 24);
2035         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_ADDR,
2036             (addr & 0x7FFFF) | (2 << 29));
2037 
2038         timeout = 0;
2039         do {
2040                 cmd = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_ADDR);
2041                 timeout++;
2042         } while ((cmd & TAVOR_HW_FLASH_CMD_MASK) &&
2043             (timeout < tavor_hw_flash_timeout_config));
2044 
2045         if (timeout == tavor_hw_flash_timeout_config) {
2046                 cmn_err(CE_WARN, "tavor_flash_write: config cmd timeout.\n");
2047         }
2048 
2049         TAVOR_TNF_EXIT(tavor_flash_write);
2050 }
2051 
2052 /*
2053  * tavor_flash_init()
2054  */
2055 static void
2056 tavor_flash_init(tavor_state_t *state)
2057 {
2058         uint32_t                word;
2059         ddi_acc_handle_t        hdl;
2060         int                     sema_cnt;
2061         int                     gpio;
2062 
2063         TAVOR_TNF_ENTER(tavor_flash_init);
2064 
2065         /* Set handle */
2066         hdl = state->ts_pci_cfghdl;
2067 
2068         /* Init the flash */
2069 
2070         /*
2071          * Grab the GPIO semaphore.  This allows us exclusive access to the
2072          * GPIO settings on the Tavor for the duration of the flash burning
2073          * procedure.
2074          */
2075         sema_cnt = 0;
2076         do {
2077                 word = tavor_flash_read_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA);
2078                 if (word == 0) {
2079                         break;
2080                 }
2081 
2082                 sema_cnt++;
2083                 drv_usecwait(1);
2084         } while (sema_cnt < tavor_hw_flash_timeout_gpio_sema);
2085 
2086         /*
2087          * Determine if we timed out trying to grab the GPIO semaphore
2088          */
2089         if (sema_cnt == tavor_hw_flash_timeout_gpio_sema) {
2090                 cmn_err(CE_WARN, "tavor_flash_init: GPIO SEMA timeout\n");
2091         }
2092 
2093         /* Save away original GPIO Values */
2094         state->ts_fw_gpio[0] = tavor_flash_read_cfg(hdl,
2095             TAVOR_HW_FLASH_GPIO_DIR);
2096         state->ts_fw_gpio[1] = tavor_flash_read_cfg(hdl,
2097             TAVOR_HW_FLASH_GPIO_POL);
2098         state->ts_fw_gpio[2] = tavor_flash_read_cfg(hdl,
2099             TAVOR_HW_FLASH_GPIO_MOD);
2100         state->ts_fw_gpio[3] = tavor_flash_read_cfg(hdl,
2101             TAVOR_HW_FLASH_GPIO_DAT);
2102 
2103         /* Set New GPIO Values */
2104         gpio = state->ts_fw_gpio[0] | 0x70;
2105         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR, gpio);
2106 
2107         gpio = state->ts_fw_gpio[1] & ~0x70;
2108         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL, gpio);
2109 
2110         gpio = state->ts_fw_gpio[2] & ~0x70;
2111         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD, gpio);
2112 
2113         /* Set CPUMODE to enable tavor to access the flash device */
2114         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_CPUMODE,
2115             1 << TAVOR_HW_FLASH_CPU_SHIFT);
2116 
2117         /* Initialize to bank 0 */
2118         tavor_flash_bank(state, 0);
2119 
2120         TAVOR_TNF_EXIT(tavor_flash_init);
2121 }
2122 
2123 /*
2124  * tavor_flash_cfi_init
2125  *   Implements access to the CFI (Common Flash Interface) data
2126  */
2127 static void
2128 tavor_flash_cfi_init(tavor_state_t *state, uint32_t *cfi_info, int *intel_xcmd)
2129 {
2130         uint32_t        data;
2131         uint32_t        sector_sz_bytes;
2132         uint32_t        bit_count;
2133         uint8_t         cfi_ch_info[TAVOR_CFI_INFO_SIZE];
2134         uint32_t        cfi_dw_info[TAVOR_CFI_INFO_QSIZE];
2135         int             i;
2136 
2137         TAVOR_TNF_ENTER(tavor_flash_cfi_init);
2138 
2139         /*
2140          * Determine if the user command supports the Intel Extended
2141          * Command Set. The query string is contained in the fourth
2142          * quad word.
2143          */
2144         tavor_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
2145         if (cfi_ch_info[0x10] == 'M' &&
2146             cfi_ch_info[0x11] == 'X' &&
2147             cfi_ch_info[0x12] == '2') {
2148                 *intel_xcmd = 1; /* support is there */
2149         }
2150 
2151         /* CFI QUERY */
2152         tavor_flash_write(state, 0x55, TAVOR_FLASH_CFI_INIT);
2153 
2154         /* Read in CFI data */
2155         for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 4) {
2156                 data = tavor_flash_read(state, i);
2157                 cfi_dw_info[i >> 2] = data;
2158                 tavor_flash_cfi_byte(cfi_ch_info, data, i);
2159         }
2160 
2161         /* Determine chip set */
2162         state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET;
2163         if (cfi_ch_info[0x20] == 'Q' &&
2164             cfi_ch_info[0x22] == 'R' &&
2165             cfi_ch_info[0x24] == 'Y') {
2166                 /*
2167                  * Mode: x16 working in x8 mode (Intel).
2168                  * Pack data - skip spacing bytes.
2169                  */
2170                 for (i = 0; i < TAVOR_CFI_INFO_SIZE; i += 2) {
2171                         cfi_ch_info[i/2] = cfi_ch_info[i];
2172                 }
2173         }
2174         state->ts_fw_cmdset = cfi_ch_info[0x13];
2175         if (state->ts_fw_cmdset != TAVOR_FLASH_INTEL_CMDSET &&
2176             state->ts_fw_cmdset != TAVOR_FLASH_AMD_CMDSET) {
2177                 cmn_err(CE_WARN,
2178                     "tavor_flash_cfi_init: UNKNOWN chip cmd set\n");
2179                 state->ts_fw_cmdset = TAVOR_FLASH_UNKNOWN_CMDSET;
2180                 goto out;
2181         }
2182 
2183         /* Determine total bytes in one sector size */
2184         sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
2185 
2186         /* Calculate equivalent of log2 (n) */
2187         for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
2188                 sector_sz_bytes >>= 1;
2189         }
2190 
2191         /* Set sector size */
2192         state->ts_fw_log_sector_sz = bit_count;
2193 
2194         /* Set flash size */
2195         state->ts_fw_device_sz = 0x1 << cfi_ch_info[0x27];
2196 
2197         /* Reset to turn off CFI mode */
2198         tavor_flash_reset(state);
2199 
2200         /*
2201          * Pass CFI data back to user command.
2202          */
2203         for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) {
2204                 tavor_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
2205         }
2206 
2207         if (*intel_xcmd == 1) {
2208                 /*
2209                  * Inform the user cmd that this driver does support the
2210                  * Intel Extended Command Set.
2211                  */
2212                 cfi_ch_info[0x10] = 'M';
2213                 cfi_ch_info[0x11] = 'X';
2214                 cfi_ch_info[0x12] = '2';
2215         } else {
2216                 cfi_ch_info[0x10] = 'Q';
2217                 cfi_ch_info[0x11] = 'R';
2218                 cfi_ch_info[0x12] = 'Y';
2219         }
2220         cfi_ch_info[0x13] = state->ts_fw_cmdset;
2221         tavor_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
2222 out:
2223         TAVOR_TNF_EXIT(tavor_flash_cfi_init);
2224 }
2225 
2226 /*
2227  * tavor_flash_fini()
2228  */
2229 static void
2230 tavor_flash_fini(tavor_state_t *state)
2231 {
2232         ddi_acc_handle_t hdl;
2233 
2234         TAVOR_TNF_ENTER(tavor_flash_fini);
2235 
2236         /* Set handle */
2237         hdl = state->ts_pci_cfghdl;
2238 
2239         /* Restore original GPIO Values */
2240         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DIR,
2241             state->ts_fw_gpio[0]);
2242         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_POL,
2243             state->ts_fw_gpio[1]);
2244         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_MOD,
2245             state->ts_fw_gpio[2]);
2246         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_DAT,
2247             state->ts_fw_gpio[3]);
2248 
2249         /* Give up semaphore */
2250         tavor_flash_write_cfg(hdl, TAVOR_HW_FLASH_GPIO_SEMA, 0);
2251 
2252         TAVOR_TNF_EXIT(tavor_flash_fini);
2253 }
2254 
2255 /*
2256  * tavor_flash_read_cfg
2257  */
2258 static uint32_t
2259 tavor_flash_read_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr)
2260 {
2261         uint32_t        read;
2262 
2263         TAVOR_TNF_ENTER(tavor_flash_read_cfg);
2264 
2265         /*
2266          * Perform flash read operation:
2267          *   1) Place addr to read from on the TAVOR_HW_FLASH_CFG_ADDR register
2268          *   2) Read data at that addr from the TAVOR_HW_FLASH_CFG_DATA register
2269          */
2270         pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr);
2271         read = pci_config_get32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA);
2272 
2273         TAVOR_TNF_EXIT(tavor_flash_read_cfg);
2274 
2275         return (read);
2276 }
2277 
2278 /*
2279  * tavor_flash_write_cfg
2280  */
2281 static void
2282 tavor_flash_write_cfg(ddi_acc_handle_t pci_config_hdl, uint32_t addr,
2283     uint32_t data)
2284 {
2285         TAVOR_TNF_ENTER(tavor_flash_write_cfg);
2286 
2287         /*
2288          * Perform flash write operation:
2289          *   1) Place addr to write to on the TAVOR_HW_FLASH_CFG_ADDR register
2290          *   2) Place data to write on to the TAVOR_HW_FLASH_CFG_DATA register
2291          */
2292         pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_ADDR, addr);
2293         pci_config_put32(pci_config_hdl, TAVOR_HW_FLASH_CFG_DATA, data);
2294 
2295         TAVOR_TNF_EXIT(tavor_flash_write_cfg);
2296 }
2297 
2298 /*
2299  * Support routines to convert Common Flash Interface (CFI) data
2300  * from a 32  bit word to a char array, and from a char array to
2301  * a 32 bit word.
2302  */
2303 static void
2304 tavor_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
2305 {
2306         ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
2307         ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
2308         ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
2309         ch[i+3] = (uint8_t)((dword & 0x000000FF));
2310 }
2311 
2312 static void
2313 tavor_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
2314 {
2315         *dword = (uint32_t)
2316             ((uint32_t)ch[i] << 24 |
2317             (uint32_t)ch[i+1] << 16 |
2318             (uint32_t)ch[i+2] << 8 |
2319             (uint32_t)ch[i+3]);
2320 }
2321 
2322 /*
2323  * tavor_loopback_free_qps
2324  */
2325 static void
2326 tavor_loopback_free_qps(tavor_loopback_state_t *lstate)
2327 {
2328         int i;
2329 
2330         if (lstate->tls_tx.tlc_qp_hdl != NULL) {
2331                 (void) tavor_qp_free(lstate->tls_state,
2332                     &lstate->tls_tx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
2333                     TAVOR_NOSLEEP);
2334         }
2335         if (lstate->tls_rx.tlc_qp_hdl != NULL) {
2336                 (void) tavor_qp_free(lstate->tls_state,
2337                     &lstate->tls_rx.tlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
2338                     TAVOR_NOSLEEP);
2339         }
2340         lstate->tls_tx.tlc_qp_hdl = NULL;
2341         lstate->tls_rx.tlc_qp_hdl = NULL;
2342         for (i = 0; i < 2; i++) {
2343                 if (lstate->tls_tx.tlc_cqhdl[i] != NULL) {
2344                         (void) tavor_cq_free(lstate->tls_state,
2345                             &lstate->tls_tx.tlc_cqhdl[i], TAVOR_NOSLEEP);
2346                 }
2347                 if (lstate->tls_rx.tlc_cqhdl[i] != NULL) {
2348                         (void) tavor_cq_free(lstate->tls_state,
2349                             &lstate->tls_rx.tlc_cqhdl[i], TAVOR_NOSLEEP);
2350                 }
2351                 lstate->tls_tx.tlc_cqhdl[i] = NULL;
2352                 lstate->tls_rx.tlc_cqhdl[i] = NULL;
2353         }
2354 }
2355 
2356 /*
2357  * tavor_loopback_free_state
2358  */
2359 static void
2360 tavor_loopback_free_state(tavor_loopback_state_t *lstate)
2361 {
2362         tavor_loopback_free_qps(lstate);
2363         if (lstate->tls_tx.tlc_mrhdl != NULL) {
2364                 (void) tavor_mr_deregister(lstate->tls_state,
2365                     &lstate->tls_tx.tlc_mrhdl, TAVOR_MR_DEREG_ALL,
2366                     TAVOR_NOSLEEP);
2367         }
2368         if (lstate->tls_rx.tlc_mrhdl !=  NULL) {
2369                 (void) tavor_mr_deregister(lstate->tls_state,
2370                     &lstate->tls_rx.tlc_mrhdl, TAVOR_MR_DEREG_ALL,
2371                     TAVOR_NOSLEEP);
2372         }
2373         if (lstate->tls_pd_hdl != NULL) {
2374                 (void) tavor_pd_free(lstate->tls_state, &lstate->tls_pd_hdl);
2375         }
2376         if (lstate->tls_tx.tlc_buf != NULL) {
2377                 kmem_free(lstate->tls_tx.tlc_buf, lstate->tls_tx.tlc_buf_sz);
2378         }
2379         if (lstate->tls_rx.tlc_buf != NULL) {
2380                 kmem_free(lstate->tls_rx.tlc_buf, lstate->tls_rx.tlc_buf_sz);
2381         }
2382         bzero(lstate, sizeof (tavor_loopback_state_t));
2383 }
2384 
2385 /*
2386  * tavor_loopback_init
2387  */
2388 static int
2389 tavor_loopback_init(tavor_state_t *state, tavor_loopback_state_t *lstate)
2390 {
2391         lstate->tls_hca_hdl = (ibc_hca_hdl_t)state;
2392         lstate->tls_status  = tavor_pd_alloc(lstate->tls_state,
2393             &lstate->tls_pd_hdl, TAVOR_NOSLEEP);
2394         if (lstate->tls_status != IBT_SUCCESS) {
2395                 lstate->tls_err = TAVOR_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
2396                 TNF_PROBE_0(tavor_ioctl_loopback_alloc_pd_fail,
2397                     TAVOR_TNF_ERROR, "");
2398                 return (EFAULT);
2399         }
2400 
2401         return (0);
2402 }
2403 
2404 /*
2405  * tavor_loopback_init_qp_info
2406  */
2407 static void
2408 tavor_loopback_init_qp_info(tavor_loopback_state_t *lstate,
2409     tavor_loopback_comm_t *comm)
2410 {
2411         bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t));
2412         bzero(&comm->tlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
2413         bzero(&comm->tlc_qp_info, sizeof (ibt_qp_info_t));
2414 
2415         comm->tlc_wrid = 1;
2416         comm->tlc_cq_attr.cq_size = 128;
2417         comm->tlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
2418         comm->tlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
2419         comm->tlc_qp_attr.qp_sizes.cs_sq = 16;
2420         comm->tlc_qp_attr.qp_sizes.cs_rq = 16;
2421         comm->tlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
2422 
2423         comm->tlc_qp_info.qp_state = IBT_STATE_RESET;
2424         comm->tlc_qp_info.qp_trans = IBT_RC_SRV;
2425         comm->tlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
2426         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
2427             lstate->tls_port;
2428         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
2429             lstate->tls_pkey_ix;
2430         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
2431             lstate->tls_timeout;
2432         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
2433         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
2434             IBT_SRATE_4X;
2435         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
2436         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
2437             lstate->tls_lid;
2438         comm->tlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->tls_retry;
2439         comm->tlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
2440         comm->tlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
2441         comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_in       = 4;
2442         comm->tlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
2443         comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
2444         comm->tlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
2445         comm->tlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
2446 }
2447 
2448 /*
2449  * tavor_loopback_alloc_mem
2450  */
2451 static int
2452 tavor_loopback_alloc_mem(tavor_loopback_state_t *lstate,
2453     tavor_loopback_comm_t *comm, int sz)
2454 {
2455         /* Allocate buffer of specified size */
2456         comm->tlc_buf_sz = sz;
2457         comm->tlc_buf         = kmem_zalloc(sz, KM_NOSLEEP);
2458         if (comm->tlc_buf == NULL) {
2459                 return (EFAULT);
2460         }
2461 
2462         /* Register the buffer as a memory region */
2463         comm->tlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->tlc_buf;
2464         comm->tlc_memattr.mr_len   = (ib_msglen_t)sz;
2465         comm->tlc_memattr.mr_as         = NULL;
2466         comm->tlc_memattr.mr_flags = IBT_MR_NOSLEEP |
2467             IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
2468 
2469         comm->tlc_status = tavor_mr_register(lstate->tls_state,
2470             lstate->tls_pd_hdl, &comm->tlc_memattr, &comm->tlc_mrhdl, NULL);
2471 
2472         comm->tlc_mrdesc.md_vaddr  = comm->tlc_mrhdl->mr_bindinfo.bi_addr;
2473         comm->tlc_mrdesc.md_lkey   = comm->tlc_mrhdl->mr_lkey;
2474         comm->tlc_mrdesc.md_rkey   = comm->tlc_mrhdl->mr_rkey;
2475         if (comm->tlc_status != IBT_SUCCESS) {
2476                 return (EFAULT);
2477         }
2478         return (0);
2479 }
2480 
2481 /*
2482  * tavor_loopback_alloc_qps
2483  */
2484 static int
2485 tavor_loopback_alloc_qps(tavor_loopback_state_t *lstate,
2486     tavor_loopback_comm_t *comm)
2487 {
2488         uint32_t                i, real_size;
2489         tavor_qp_info_t         qpinfo;
2490 
2491         /* Allocate send and recv CQs */
2492         for (i = 0; i < 2; i++) {
2493                 bzero(&comm->tlc_cq_attr, sizeof (ibt_cq_attr_t));
2494                 comm->tlc_cq_attr.cq_size = 128;
2495                 comm->tlc_status = tavor_cq_alloc(lstate->tls_state,
2496                     (ibt_cq_hdl_t)NULL, &comm->tlc_cq_attr, &real_size,
2497                     &comm->tlc_cqhdl[i], TAVOR_NOSLEEP);
2498                 if (comm->tlc_status != IBT_SUCCESS) {
2499                         lstate->tls_err += i;
2500                         return (EFAULT);
2501                 }
2502         }
2503 
2504         /* Allocate the QP */
2505         tavor_loopback_init_qp_info(lstate, comm);
2506         comm->tlc_qp_attr.qp_pd_hdl   = (ibt_pd_hdl_t)lstate->tls_pd_hdl;
2507         comm->tlc_qp_attr.qp_scq_hdl  = (ibt_cq_hdl_t)comm->tlc_cqhdl[0];
2508         comm->tlc_qp_attr.qp_rcq_hdl  = (ibt_cq_hdl_t)comm->tlc_cqhdl[1];
2509         comm->tlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[0];
2510         comm->tlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->tlc_cqhdl[1];
2511         qpinfo.qpi_attrp        = &comm->tlc_qp_attr;
2512         qpinfo.qpi_type         = IBT_RC_RQP;
2513         qpinfo.qpi_ibt_qphdl    = NULL;
2514         qpinfo.qpi_queueszp     = &comm->tlc_chan_sizes;
2515         qpinfo.qpi_qpn          = &comm->tlc_qp_num;
2516         comm->tlc_status = tavor_qp_alloc(lstate->tls_state, &qpinfo,
2517             TAVOR_NOSLEEP, NULL);
2518         if (comm->tlc_status == DDI_SUCCESS) {
2519                 comm->tlc_qp_hdl = qpinfo.qpi_qphdl;
2520         }
2521 
2522         if (comm->tlc_status != IBT_SUCCESS) {
2523                 lstate->tls_err += 2;
2524                 return (EFAULT);
2525         }
2526         return (0);
2527 }
2528 
2529 /*
2530  * tavor_loopback_modify_qp
2531  */
2532 static int
2533 tavor_loopback_modify_qp(tavor_loopback_state_t *lstate,
2534     tavor_loopback_comm_t *comm, uint_t qp_num)
2535 {
2536         /* Modify QP to INIT */
2537         tavor_loopback_init_qp_info(lstate, comm);
2538         comm->tlc_qp_info.qp_state = IBT_STATE_INIT;
2539         comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
2540             IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
2541         if (comm->tlc_status != IBT_SUCCESS) {
2542                 return (EFAULT);
2543         }
2544 
2545         /*
2546          * Modify QP to RTR (set destination LID and QP number to local
2547          * LID and QP number)
2548          */
2549         comm->tlc_qp_info.qp_state = IBT_STATE_RTR;
2550         comm->tlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
2551             = lstate->tls_lid;
2552         comm->tlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
2553         comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
2554             IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
2555         if (comm->tlc_status != IBT_SUCCESS) {
2556                 lstate->tls_err += 1;
2557                 return (EFAULT);
2558         }
2559 
2560         /* Modify QP to RTS */
2561         comm->tlc_qp_info.qp_current_state = IBT_STATE_RTR;
2562         comm->tlc_qp_info.qp_state = IBT_STATE_RTS;
2563         comm->tlc_status = tavor_qp_modify(lstate->tls_state, comm->tlc_qp_hdl,
2564             IBT_CEP_SET_STATE, &comm->tlc_qp_info, &comm->tlc_queue_sizes);
2565         if (comm->tlc_status != IBT_SUCCESS) {
2566                 lstate->tls_err += 2;
2567                 return (EFAULT);
2568         }
2569         return (0);
2570 }
2571 
2572 /*
2573  * tavor_loopback_copyout
2574  */
2575 static int
2576 tavor_loopback_copyout(tavor_loopback_ioctl_t *lb, intptr_t arg, int mode)
2577 {
2578 #ifdef _MULTI_DATAMODEL
2579         if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2580                 tavor_loopback_ioctl32_t lb32;
2581 
2582                 lb32.tlb_revision       = lb->tlb_revision;
2583                 lb32.tlb_send_buf       =
2584                     (caddr32_t)(uintptr_t)lb->tlb_send_buf;
2585                 lb32.tlb_fail_buf       =
2586                     (caddr32_t)(uintptr_t)lb->tlb_fail_buf;
2587                 lb32.tlb_buf_sz         = lb->tlb_buf_sz;
2588                 lb32.tlb_num_iter       = lb->tlb_num_iter;
2589                 lb32.tlb_pass_done      = lb->tlb_pass_done;
2590                 lb32.tlb_timeout        = lb->tlb_timeout;
2591                 lb32.tlb_error_type     = lb->tlb_error_type;
2592                 lb32.tlb_port_num       = lb->tlb_port_num;
2593                 lb32.tlb_num_retry      = lb->tlb_num_retry;
2594 
2595                 if (ddi_copyout(&lb32, (void *)arg,
2596                     sizeof (tavor_loopback_ioctl32_t), mode) != 0) {
2597                         TNF_PROBE_0(tavor_ioctl_loopback_copyout_fail,
2598                             TAVOR_TNF_ERROR, "");
2599                         return (EFAULT);
2600                 }
2601         } else
2602 #endif /* _MULTI_DATAMODEL */
2603         if (ddi_copyout(lb, (void *)arg, sizeof (tavor_loopback_ioctl_t),
2604             mode) != 0) {
2605                 TNF_PROBE_0(tavor_ioctl_loopback_copyout_fail,
2606                     TAVOR_TNF_ERROR, "");
2607                 return (EFAULT);
2608         }
2609         return (0);
2610 }
2611 
2612 /*
2613  * tavor_loopback_post_send
2614  */
2615 static int
2616 tavor_loopback_post_send(tavor_loopback_state_t *lstate,
2617     tavor_loopback_comm_t *tx, tavor_loopback_comm_t *rx)
2618 {
2619         int      ret;
2620 
2621         bzero(&tx->tlc_sgl, sizeof (ibt_wr_ds_t));
2622         bzero(&tx->tlc_wr, sizeof (ibt_send_wr_t));
2623 
2624         /* Initialize local address for TX buffer */
2625         tx->tlc_sgl.ds_va   = tx->tlc_mrdesc.md_vaddr;
2626         tx->tlc_sgl.ds_key  = tx->tlc_mrdesc.md_lkey;
2627         tx->tlc_sgl.ds_len  = tx->tlc_buf_sz;
2628 
2629         /* Initialize the remaining details of the work request */
2630         tx->tlc_wr.wr_id = tx->tlc_wrid++;
2631         tx->tlc_wr.wr_flags  = IBT_WR_SEND_SIGNAL;
2632         tx->tlc_wr.wr_nds    = 1;
2633         tx->tlc_wr.wr_sgl    = &tx->tlc_sgl;
2634         tx->tlc_wr.wr_opcode = IBT_WRC_RDMAW;
2635         tx->tlc_wr.wr_trans  = IBT_RC_SRV;
2636 
2637         /* Initialize the remote address for RX buffer */
2638         tx->tlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->tlc_mrdesc.md_vaddr;
2639         tx->tlc_wr.wr.rc.rcwr.rdma.rdma_rkey  = rx->tlc_mrdesc.md_rkey;
2640         tx->tlc_complete = 0;
2641         ret = tavor_post_send(lstate->tls_state, tx->tlc_qp_hdl, &tx->tlc_wr,
2642             1, NULL);
2643         if (ret != IBT_SUCCESS) {
2644                 return (EFAULT);
2645         }
2646         return (0);
2647 }
2648 
2649 /*
2650  * tavor_loopback_poll_cq
2651  */
2652 static int
2653 tavor_loopback_poll_cq(tavor_loopback_state_t *lstate,
2654     tavor_loopback_comm_t *comm)
2655 {
2656         comm->tlc_wc.wc_status       = 0;
2657         comm->tlc_num_polled = 0;
2658         comm->tlc_status = tavor_cq_poll(lstate->tls_state,
2659             comm->tlc_cqhdl[0], &comm->tlc_wc, 1, &comm->tlc_num_polled);
2660         if ((comm->tlc_status == IBT_SUCCESS) &&
2661             (comm->tlc_wc.wc_status != IBT_WC_SUCCESS)) {
2662                 comm->tlc_status = ibc_get_ci_failure(0);
2663         }
2664         return (comm->tlc_status);
2665 }