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 /* Copyright 2015 QLogic Corporation */
  23 
  24 /*
  25  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
  26  */
  27 
  28 /*
  29  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  30  */
  31 
  32 #pragma ident   "Copyright 2015 QLogic Corporation; ql_xioctl.c"
  33 
  34 /*
  35  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
  36  *
  37  * ***********************************************************************
  38  * *                                                                    **
  39  * *                            NOTICE                                  **
  40  * *            COPYRIGHT (C) 1996-2015 QLOGIC CORPORATION              **
  41  * *                    ALL RIGHTS RESERVED                             **
  42  * *                                                                    **
  43  * ***********************************************************************
  44  *
  45  */
  46 
  47 #include <ql_apps.h>
  48 #include <ql_api.h>
  49 #include <ql_debug.h>
  50 #include <ql_init.h>
  51 #include <ql_iocb.h>
  52 #include <ql_ioctl.h>
  53 #include <ql_mbx.h>
  54 #include <ql_nx.h>
  55 #include <ql_xioctl.h>
  56 
  57 /*
  58  * Local data
  59  */
  60 
  61 /*
  62  * Local prototypes
  63  */
  64 static int ql_sdm_ioctl(ql_adapter_state_t *, int, void *, int);
  65 static int ql_sdm_setup(ql_adapter_state_t *, EXT_IOCTL **, void *, int,
  66     boolean_t (*)(EXT_IOCTL *));
  67 static boolean_t ql_validate_signature(EXT_IOCTL *);
  68 static int ql_sdm_return(ql_adapter_state_t *, EXT_IOCTL *, void *, int);
  69 static void ql_query(ql_adapter_state_t *, EXT_IOCTL *, int);
  70 static void ql_qry_hba_node(ql_adapter_state_t *, EXT_IOCTL *, int);
  71 static void ql_qry_hba_port(ql_adapter_state_t *, EXT_IOCTL *, int);
  72 static void ql_qry_disc_port(ql_adapter_state_t *, EXT_IOCTL *, int);
  73 static void ql_qry_disc_tgt(ql_adapter_state_t *, EXT_IOCTL *, int);
  74 static void ql_qry_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
  75 static void ql_qry_chip(ql_adapter_state_t *, EXT_IOCTL *, int);
  76 static void ql_qry_driver(ql_adapter_state_t *, EXT_IOCTL *, int);
  77 static void ql_fcct(ql_adapter_state_t *, EXT_IOCTL *, int);
  78 static void ql_aen_reg(ql_adapter_state_t *, EXT_IOCTL *, int);
  79 static void ql_aen_get(ql_adapter_state_t *, EXT_IOCTL *, int);
  80 static void ql_scsi_passthru(ql_adapter_state_t *, EXT_IOCTL *, int);
  81 static void ql_wwpn_to_scsiaddr(ql_adapter_state_t *, EXT_IOCTL *, int);
  82 static void ql_host_idx(ql_adapter_state_t *, EXT_IOCTL *, int);
  83 static void ql_host_drvname(ql_adapter_state_t *, EXT_IOCTL *, int);
  84 static void ql_read_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
  85 static void ql_write_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
  86 static void ql_read_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
  87 static void ql_write_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
  88 static void ql_write_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
  89 static void ql_read_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
  90 static void ql_diagnostic_loopback(ql_adapter_state_t *, EXT_IOCTL *, int);
  91 static void ql_send_els_rnid(ql_adapter_state_t *, EXT_IOCTL *, int);
  92 static void ql_set_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
  93 static void ql_get_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
  94 static void ql_qry_cna_port(ql_adapter_state_t *, EXT_IOCTL *, int);
  95 
  96 static int ql_lun_count(ql_adapter_state_t *, ql_tgt_t *);
  97 static int ql_report_lun(ql_adapter_state_t *, ql_tgt_t *);
  98 static int ql_inq_scan(ql_adapter_state_t *, ql_tgt_t *, int);
  99 static int ql_inq(ql_adapter_state_t *, ql_tgt_t *, int, ql_mbx_iocb_t *,
 100     uint32_t);
 101 static uint32_t ql_get_buffer_data(caddr_t, caddr_t, uint32_t, int);
 102 static uint32_t ql_send_buffer_data(caddr_t, caddr_t, uint32_t, int);
 103 static int ql_24xx_flash_desc(ql_adapter_state_t *);
 104 static int ql_setup_flash(ql_adapter_state_t *);
 105 static ql_tgt_t *ql_find_port(ql_adapter_state_t *, uint8_t *, uint16_t);
 106 static int ql_flash_fcode_load(ql_adapter_state_t *, void *, uint32_t, int);
 107 static int ql_flash_fcode_dump(ql_adapter_state_t *, void *, uint32_t,
 108     uint32_t, int);
 109 static int ql_program_flash_address(ql_adapter_state_t *, uint32_t,
 110     uint8_t);
 111 static void ql_set_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
 112 static void ql_get_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
 113 static int ql_reset_statistics(ql_adapter_state_t *, EXT_IOCTL *);
 114 static void ql_get_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
 115 static void ql_get_statistics_fc(ql_adapter_state_t *, EXT_IOCTL *, int);
 116 static void ql_get_statistics_fc4(ql_adapter_state_t *, EXT_IOCTL *, int);
 117 static void ql_set_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
 118 static void ql_get_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
 119 static void ql_drive_led(ql_adapter_state_t *, uint32_t);
 120 static int ql_setup_led(ql_adapter_state_t *);
 121 static int ql_wrapup_led(ql_adapter_state_t *);
 122 static void ql_get_port_summary(ql_adapter_state_t *, EXT_IOCTL *, int);
 123 static void ql_get_target_id(ql_adapter_state_t *, EXT_IOCTL *, int);
 124 static void ql_get_sfp(ql_adapter_state_t *, EXT_IOCTL *, int);
 125 static int ql_dump_sfp(ql_adapter_state_t *, void *, int);
 126 static ql_fcache_t *ql_setup_fnode(ql_adapter_state_t *);
 127 static void ql_get_fcache(ql_adapter_state_t *, EXT_IOCTL *, int);
 128 static void ql_get_fcache_ex(ql_adapter_state_t *, EXT_IOCTL *, int);
 129 void ql_update_fcache(ql_adapter_state_t *, uint8_t *, uint32_t);
 130 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
 131 static void ql_flash_layout_table(ql_adapter_state_t *, uint32_t);
 132 static void ql_process_flt(ql_adapter_state_t *, uint32_t);
 133 static void ql_flash_nvram_defaults(ql_adapter_state_t *);
 134 static void ql_port_param(ql_adapter_state_t *, EXT_IOCTL *, int);
 135 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
 136 static void ql_get_pci_data(ql_adapter_state_t *, EXT_IOCTL *, int);
 137 static void ql_get_fwfcetrace(ql_adapter_state_t *, EXT_IOCTL *, int);
 138 static void ql_get_fwexttrace(ql_adapter_state_t *, EXT_IOCTL *, int);
 139 static void ql_menlo_reset(ql_adapter_state_t *, EXT_IOCTL *, int);
 140 static void ql_menlo_get_fw_version(ql_adapter_state_t *, EXT_IOCTL *, int);
 141 static void ql_menlo_update_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
 142 static void ql_menlo_manage_info(ql_adapter_state_t *, EXT_IOCTL *, int);
 143 static int ql_suspend_hba(ql_adapter_state_t *, uint32_t);
 144 static void ql_restart_hba(ql_adapter_state_t *);
 145 static void ql_get_vp_cnt_id(ql_adapter_state_t *, EXT_IOCTL *, int);
 146 static void ql_vp_ioctl(ql_adapter_state_t *, EXT_IOCTL *, int);
 147 static void ql_qry_vport(ql_adapter_state_t *, EXT_IOCTL *, int);
 148 static void ql_access_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
 149 static void ql_reset_cmd(ql_adapter_state_t *, EXT_IOCTL *);
 150 static void ql_update_flash_caches(ql_adapter_state_t *);
 151 static void ql_get_dcbx_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
 152 static void ql_get_xgmac_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
 153 static void ql_get_fcf_list(ql_adapter_state_t *, EXT_IOCTL *, int);
 154 static void ql_get_resource_counts(ql_adapter_state_t *, EXT_IOCTL *, int);
 155 static void ql_qry_adapter_versions(ql_adapter_state_t *, EXT_IOCTL *, int);
 156 static void ql_get_temperature(ql_adapter_state_t *, EXT_IOCTL *, int);
 157 static void ql_dump_cmd(ql_adapter_state_t *, EXT_IOCTL *, int);
 158 static void ql_serdes_reg(ql_adapter_state_t *, EXT_IOCTL *, int);
 159 static void ql_serdes_reg_ex(ql_adapter_state_t *, EXT_IOCTL *, int);
 160 static void ql_els_passthru(ql_adapter_state_t *, EXT_IOCTL *, int);
 161 static void ql_flash_update_caps(ql_adapter_state_t *, EXT_IOCTL *, int);
 162 static void ql_get_bbcr_data(ql_adapter_state_t *, EXT_IOCTL *, int);
 163 static void ql_get_priv_stats(ql_adapter_state_t *, EXT_IOCTL *, int);
 164 
 165 /* ******************************************************************** */
 166 /*                      External IOCTL support.                         */
 167 /* ******************************************************************** */
 168 
 169 /*
 170  * ql_alloc_xioctl_resource
 171  *      Allocates resources needed by module code.
 172  *
 173  * Input:
 174  *      ha:             adapter state pointer.
 175  *
 176  * Returns:
 177  *      SYS_ERRNO
 178  *
 179  * Context:
 180  *      Kernel context.
 181  */
 182 int
 183 ql_alloc_xioctl_resource(ql_adapter_state_t *ha)
 184 {
 185         ql_xioctl_t     *xp;
 186 
 187         QL_PRINT_9(ha, "started\n");
 188 
 189         if (ha->xioctl != NULL) {
 190                 QL_PRINT_9(ha, "already allocated done\n",
 191                     ha->instance);
 192                 return (0);
 193         }
 194 
 195         xp = kmem_zalloc(sizeof (ql_xioctl_t), KM_SLEEP);
 196         if (xp == NULL) {
 197                 EL(ha, "failed, kmem_zalloc\n");
 198                 return (ENOMEM);
 199         }
 200         ha->xioctl = xp;
 201 
 202         /* Allocate AEN tracking buffer */
 203         xp->aen_tracking_queue = kmem_zalloc(EXT_DEF_MAX_AEN_QUEUE *
 204             sizeof (EXT_ASYNC_EVENT), KM_SLEEP);
 205         if (xp->aen_tracking_queue == NULL) {
 206                 EL(ha, "failed, kmem_zalloc-2\n");
 207                 ql_free_xioctl_resource(ha);
 208                 return (ENOMEM);
 209         }
 210 
 211         QL_PRINT_9(ha, "done\n");
 212 
 213         return (0);
 214 }
 215 
 216 /*
 217  * ql_free_xioctl_resource
 218  *      Frees resources used by module code.
 219  *
 220  * Input:
 221  *      ha:             adapter state pointer.
 222  *
 223  * Context:
 224  *      Kernel context.
 225  */
 226 void
 227 ql_free_xioctl_resource(ql_adapter_state_t *ha)
 228 {
 229         ql_xioctl_t     *xp = ha->xioctl;
 230 
 231         QL_PRINT_9(ha, "started\n");
 232 
 233         if (xp == NULL) {
 234                 QL_PRINT_9(ha, "already freed\n");
 235                 return;
 236         }
 237 
 238         if (xp->aen_tracking_queue != NULL) {
 239                 kmem_free(xp->aen_tracking_queue, EXT_DEF_MAX_AEN_QUEUE *
 240                     sizeof (EXT_ASYNC_EVENT));
 241                 xp->aen_tracking_queue = NULL;
 242         }
 243 
 244         kmem_free(xp, sizeof (ql_xioctl_t));
 245         ha->xioctl = NULL;
 246 
 247         QL_PRINT_9(ha, "done\n");
 248 }
 249 
 250 /*
 251  * ql_xioctl
 252  *      External IOCTL processing.
 253  *
 254  * Input:
 255  *      ha:     adapter state pointer.
 256  *      cmd:    function to perform
 257  *      arg:    data type varies with request
 258  *      mode:   flags
 259  *      cred_p: credentials pointer
 260  *      rval_p: pointer to result value
 261  *
 262  * Returns:
 263  *      0:              success
 264  *      ENXIO:          No such device or address
 265  *      ENOPROTOOPT:    Protocol not available
 266  *
 267  * Context:
 268  *      Kernel context.
 269  */
 270 /* ARGSUSED */
 271 int
 272 ql_xioctl(ql_adapter_state_t *ha, int cmd, intptr_t arg, int mode,
 273     cred_t *cred_p, int *rval_p)
 274 {
 275         int     rval;
 276 
 277         QL_PRINT_9(ha, "started, cmd=%d\n", cmd);
 278 
 279         if (ha->xioctl == NULL) {
 280                 QL_PRINT_9(ha, "no context\n");
 281                 return (ENXIO);
 282         }
 283 
 284         switch (cmd) {
 285         case EXT_CC_QUERY:
 286         case EXT_CC_SEND_FCCT_PASSTHRU:
 287         case EXT_CC_REG_AEN:
 288         case EXT_CC_GET_AEN:
 289         case EXT_CC_SEND_SCSI_PASSTHRU:
 290         case EXT_CC_WWPN_TO_SCSIADDR:
 291         case EXT_CC_SEND_ELS_RNID:
 292         case EXT_CC_SET_DATA:
 293         case EXT_CC_GET_DATA:
 294         case EXT_CC_HOST_IDX:
 295         case EXT_CC_READ_NVRAM:
 296         case EXT_CC_UPDATE_NVRAM:
 297         case EXT_CC_READ_OPTION_ROM:
 298         case EXT_CC_READ_OPTION_ROM_EX:
 299         case EXT_CC_UPDATE_OPTION_ROM:
 300         case EXT_CC_UPDATE_OPTION_ROM_EX:
 301         case EXT_CC_GET_VPD:
 302         case EXT_CC_SET_VPD:
 303         case EXT_CC_LOOPBACK:
 304         case EXT_CC_GET_FCACHE:
 305         case EXT_CC_GET_FCACHE_EX:
 306         case EXT_CC_HOST_DRVNAME:
 307         case EXT_CC_GET_SFP_DATA:
 308         case EXT_CC_PORT_PARAM:
 309         case EXT_CC_GET_PCI_DATA:
 310         case EXT_CC_GET_FWEXTTRACE:
 311         case EXT_CC_GET_FWFCETRACE:
 312         case EXT_CC_GET_VP_CNT_ID:
 313         case EXT_CC_VPORT_CMD:
 314         case EXT_CC_ACCESS_FLASH:
 315         case EXT_CC_RESET_FW:
 316         case EXT_CC_MENLO_MANAGE_INFO:
 317         case EXT_CC_I2C_DATA:
 318         case EXT_CC_DUMP:
 319         case EXT_CC_SERDES_REG_OP:
 320         case EXT_CC_VF_STATE:
 321         case EXT_CC_SERDES_REG_OP_EX:
 322         case EXT_CC_ELS_PASSTHRU_OS:
 323         case EXT_CC_FLASH_UPDATE_CAPS_OS:
 324         case EXT_CC_GET_BBCR_DATA_OS:
 325                 rval = ql_sdm_ioctl(ha, cmd, (void *)arg, mode);
 326                 break;
 327         default:
 328                 /* function not supported. */
 329                 EL(ha, "function=%d not supported\n", cmd);
 330                 rval = ENOPROTOOPT;
 331         }
 332 
 333         QL_PRINT_9(ha, "done\n");
 334 
 335         return (rval);
 336 }
 337 
 338 /*
 339  * ql_sdm_ioctl
 340  *      Provides ioctl functions for SAN/Device Management functions
 341  *      AKA External Ioctl functions.
 342  *
 343  * Input:
 344  *      ha:             adapter state pointer.
 345  *      ioctl_code:     ioctl function to perform
 346  *      arg:            Pointer to EXT_IOCTL cmd data in application land.
 347  *      mode:           flags
 348  *
 349  * Returns:
 350  *      0:      success
 351  *      ENOMEM: Alloc of local EXT_IOCTL struct failed.
 352  *      EFAULT: Copyin of caller's EXT_IOCTL struct failed or
 353  *              copyout of EXT_IOCTL status info failed.
 354  *      EINVAL: Signature or version of caller's EXT_IOCTL invalid.
 355  *      EBUSY:  Device busy
 356  *
 357  * Context:
 358  *      Kernel context.
 359  */
 360 static int
 361 ql_sdm_ioctl(ql_adapter_state_t *ha, int ioctl_code, void *arg, int mode)
 362 {
 363         EXT_IOCTL               *cmd;
 364         int                     rval;
 365         ql_adapter_state_t      *vha;
 366 
 367         QL_PRINT_9(ha, "started\n");
 368 
 369         /* Copy argument structure (EXT_IOCTL) from application land. */
 370         if ((rval = ql_sdm_setup(ha, &cmd, arg, mode,
 371             ql_validate_signature)) != 0) {
 372                 /*
 373                  * a non-zero value at this time means a problem getting
 374                  * the requested information from application land, just
 375                  * return the error code and hope for the best.
 376                  */
 377                 EL(ha, "failed, sdm_setup\n");
 378                 return (rval);
 379         }
 380 
 381         /*
 382          * Map the physical ha ptr (which the ioctl is called with)
 383          * to the virtual ha that the caller is addressing.
 384          */
 385         if (ha->flags & VP_ENABLED) {
 386                 /* Check that it is within range. */
 387                 if (cmd->HbaSelect > ha->max_vports) {
 388                         EL(ha, "Invalid HbaSelect vp index: %xh\n",
 389                             cmd->HbaSelect);
 390                         cmd->Status = EXT_STATUS_INVALID_VPINDEX;
 391                         cmd->ResponseLen = 0;
 392                         return (EFAULT);
 393                 }
 394                 /*
 395                  * Special case: HbaSelect == 0 is physical ha
 396                  */
 397                 if (cmd->HbaSelect != 0) {
 398                         vha = ha->vp_next;
 399                         while (vha != NULL) {
 400                                 if (vha->vp_index == cmd->HbaSelect) {
 401                                         ha = vha;
 402                                         break;
 403                                 }
 404                                 vha = vha->vp_next;
 405                         }
 406                         /*
 407                          * The specified vp index may be valid(within range)
 408                          * but it's not in the list. Currently this is all
 409                          * we can say.
 410                          */
 411                         if (vha == NULL || !(vha->flags & VP_ENABLED)) {
 412                                 cmd->Status = EXT_STATUS_INVALID_VPINDEX;
 413                                 cmd->ResponseLen = 0;
 414                                 return (EFAULT);
 415                         }
 416                 }
 417         }
 418 
 419         /*
 420          * If driver is suspended, stalled, or powered down rtn BUSY
 421          */
 422         if (ha->flags & ADAPTER_SUSPENDED ||
 423             (ha->task_daemon_flags & (DRIVER_STALL | ISP_ABORT_NEEDED |
 424             ABORT_ISP_ACTIVE | LOOP_RESYNC_NEEDED | LOOP_RESYNC_ACTIVE)) ||
 425             ha->power_level != PM_LEVEL_D0) {
 426                 EL(ha, " %s\n", ha->flags & ADAPTER_SUSPENDED ?
 427                     "driver suspended" :
 428                     (ha->task_daemon_flags & (DRIVER_STALL | ISP_ABORT_NEEDED |
 429                     ABORT_ISP_ACTIVE | LOOP_RESYNC_NEEDED |
 430                     LOOP_RESYNC_ACTIVE) ? "driver stalled" :
 431                     "FCA powered down"));
 432                 cmd->Status = EXT_STATUS_BUSY;
 433                 cmd->ResponseLen = 0;
 434                 rval = EBUSY;
 435 
 436                 /* Return results to caller */
 437                 if ((ql_sdm_return(ha, cmd, arg, mode)) == -1) {
 438                         EL(ha, "failed, sdm_return\n");
 439                         rval = EFAULT;
 440                 }
 441                 return (rval);
 442         }
 443 
 444         switch (ioctl_code) {
 445         case EXT_CC_QUERY_OS:
 446                 ql_query(ha, cmd, mode);
 447                 break;
 448         case EXT_CC_SEND_FCCT_PASSTHRU_OS:
 449                 ql_fcct(ha, cmd, mode);
 450                 break;
 451         case EXT_CC_REG_AEN_OS:
 452                 ql_aen_reg(ha, cmd, mode);
 453                 break;
 454         case EXT_CC_GET_AEN_OS:
 455                 ql_aen_get(ha, cmd, mode);
 456                 break;
 457         case EXT_CC_GET_DATA_OS:
 458                 ql_get_host_data(ha, cmd, mode);
 459                 break;
 460         case EXT_CC_SET_DATA_OS:
 461                 ql_set_host_data(ha, cmd, mode);
 462                 break;
 463         case EXT_CC_SEND_ELS_RNID_OS:
 464                 ql_send_els_rnid(ha, cmd, mode);
 465                 break;
 466         case EXT_CC_SCSI_PASSTHRU_OS:
 467                 ql_scsi_passthru(ha, cmd, mode);
 468                 break;
 469         case EXT_CC_WWPN_TO_SCSIADDR_OS:
 470                 ql_wwpn_to_scsiaddr(ha, cmd, mode);
 471                 break;
 472         case EXT_CC_HOST_IDX_OS:
 473                 ql_host_idx(ha, cmd, mode);
 474                 break;
 475         case EXT_CC_HOST_DRVNAME_OS:
 476                 ql_host_drvname(ha, cmd, mode);
 477                 break;
 478         case EXT_CC_READ_NVRAM_OS:
 479                 ql_read_nvram(ha, cmd, mode);
 480                 break;
 481         case EXT_CC_UPDATE_NVRAM_OS:
 482                 ql_write_nvram(ha, cmd, mode);
 483                 break;
 484         case EXT_CC_READ_OPTION_ROM_OS:
 485         case EXT_CC_READ_OPTION_ROM_EX_OS:
 486                 ql_read_flash(ha, cmd, mode);
 487                 break;
 488         case EXT_CC_UPDATE_OPTION_ROM_OS:
 489         case EXT_CC_UPDATE_OPTION_ROM_EX_OS:
 490                 ql_write_flash(ha, cmd, mode);
 491                 break;
 492         case EXT_CC_LOOPBACK_OS:
 493                 ql_diagnostic_loopback(ha, cmd, mode);
 494                 break;
 495         case EXT_CC_GET_VPD_OS:
 496                 ql_read_vpd(ha, cmd, mode);
 497                 break;
 498         case EXT_CC_SET_VPD_OS:
 499                 ql_write_vpd(ha, cmd, mode);
 500                 break;
 501         case EXT_CC_GET_FCACHE_OS:
 502                 ql_get_fcache(ha, cmd, mode);
 503                 break;
 504         case EXT_CC_GET_FCACHE_EX_OS:
 505                 ql_get_fcache_ex(ha, cmd, mode);
 506                 break;
 507         case EXT_CC_GET_SFP_DATA_OS:
 508                 ql_get_sfp(ha, cmd, mode);
 509                 break;
 510         case EXT_CC_PORT_PARAM_OS:
 511                 ql_port_param(ha, cmd, mode);
 512                 break;
 513         case EXT_CC_GET_PCI_DATA_OS:
 514                 ql_get_pci_data(ha, cmd, mode);
 515                 break;
 516         case EXT_CC_GET_FWEXTTRACE_OS:
 517                 ql_get_fwexttrace(ha, cmd, mode);
 518                 break;
 519         case EXT_CC_GET_FWFCETRACE_OS:
 520                 ql_get_fwfcetrace(ha, cmd, mode);
 521                 break;
 522         case EXT_CC_MENLO_RESET:
 523                 ql_menlo_reset(ha, cmd, mode);
 524                 break;
 525         case EXT_CC_MENLO_GET_FW_VERSION:
 526                 ql_menlo_get_fw_version(ha, cmd, mode);
 527                 break;
 528         case EXT_CC_MENLO_UPDATE_FW:
 529                 ql_menlo_update_fw(ha, cmd, mode);
 530                 break;
 531         case EXT_CC_MENLO_MANAGE_INFO:
 532                 ql_menlo_manage_info(ha, cmd, mode);
 533                 break;
 534         case EXT_CC_GET_VP_CNT_ID_OS:
 535                 ql_get_vp_cnt_id(ha, cmd, mode);
 536                 break;
 537         case EXT_CC_VPORT_CMD_OS:
 538                 ql_vp_ioctl(ha, cmd, mode);
 539                 break;
 540         case EXT_CC_ACCESS_FLASH_OS:
 541                 ql_access_flash(ha, cmd, mode);
 542                 break;
 543         case EXT_CC_RESET_FW_OS:
 544                 ql_reset_cmd(ha, cmd);
 545                 break;
 546         case EXT_CC_I2C_DATA:
 547                 ql_get_temperature(ha, cmd, mode);
 548                 break;
 549         case EXT_CC_DUMP_OS:
 550                 ql_dump_cmd(ha, cmd, mode);
 551                 break;
 552         case EXT_CC_SERDES_REG_OP:
 553                 ql_serdes_reg(ha, cmd, mode);
 554                 break;
 555         case EXT_CC_SERDES_REG_OP_EX:
 556                 ql_serdes_reg_ex(ha, cmd, mode);
 557                 break;
 558         case EXT_CC_ELS_PASSTHRU_OS:
 559                 ql_els_passthru(ha, cmd, mode);
 560                 break;
 561         case EXT_CC_FLASH_UPDATE_CAPS_OS:
 562                 ql_flash_update_caps(ha, cmd, mode);
 563                 break;
 564         case EXT_CC_GET_BBCR_DATA_OS:
 565                 ql_get_bbcr_data(ha, cmd, mode);
 566                 break;
 567         default:
 568                 /* function not supported. */
 569                 EL(ha, "failed, function not supported=%d\n", ioctl_code);
 570 
 571                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
 572                 cmd->ResponseLen = 0;
 573                 break;
 574         }
 575 
 576         /* Return results to caller */
 577         if (ql_sdm_return(ha, cmd, arg, mode) == -1) {
 578                 EL(ha, "failed, sdm_return\n");
 579                 return (EFAULT);
 580         }
 581 
 582         QL_PRINT_9(ha, "done\n");
 583 
 584         return (0);
 585 }
 586 
 587 /*
 588  * ql_sdm_setup
 589  *      Make a local copy of the EXT_IOCTL struct and validate it.
 590  *
 591  * Input:
 592  *      ha:             adapter state pointer.
 593  *      cmd_struct:     Pointer to location to store local adrs of EXT_IOCTL.
 594  *      arg:            Address of application EXT_IOCTL cmd data
 595  *      mode:           flags
 596  *      val_sig:        Pointer to a function to validate the ioctl signature.
 597  *
 598  * Returns:
 599  *      0:              success
 600  *      EFAULT:         Copy in error of application EXT_IOCTL struct.
 601  *      EINVAL:         Invalid version, signature.
 602  *      ENOMEM:         Local allocation of EXT_IOCTL failed.
 603  *
 604  * Context:
 605  *      Kernel context.
 606  */
 607 static int
 608 ql_sdm_setup(ql_adapter_state_t *ha, EXT_IOCTL **cmd_struct, void *arg,
 609     int mode, boolean_t (*val_sig)(EXT_IOCTL *))
 610 {
 611         int             rval;
 612         EXT_IOCTL       *cmd;
 613 
 614         QL_PRINT_9(ha, "started\n");
 615 
 616         /* Allocate local memory for EXT_IOCTL. */
 617         *cmd_struct = NULL;
 618         cmd = (EXT_IOCTL *)kmem_zalloc(sizeof (EXT_IOCTL), KM_SLEEP);
 619         if (cmd == NULL) {
 620                 EL(ha, "failed, kmem_zalloc\n");
 621                 return (ENOMEM);
 622         }
 623         /* Get argument structure. */
 624         rval = ddi_copyin(arg, (void *)cmd, sizeof (EXT_IOCTL), mode);
 625         if (rval != 0) {
 626                 EL(ha, "failed, ddi_copyin\n");
 627                 rval = EFAULT;
 628         } else {
 629                 /*
 630                  * Check signature and the version.
 631                  * If either are not valid then neither is the
 632                  * structure so don't attempt to return any error status
 633                  * because we can't trust what caller's arg points to.
 634                  * Just return the errno.
 635                  */
 636                 if (val_sig(cmd) == 0) {
 637                         EL(ha, "failed, signature\n");
 638                         rval = EINVAL;
 639                 } else if (cmd->Version > EXT_VERSION) {
 640                         EL(ha, "failed, version\n");
 641                         rval = EINVAL;
 642                 }
 643         }
 644 
 645         if (rval == 0) {
 646                 QL_PRINT_9(ha, "done\n");
 647                 *cmd_struct = cmd;
 648                 cmd->Status = EXT_STATUS_OK;
 649                 cmd->DetailStatus = 0;
 650         } else {
 651                 kmem_free((void *)cmd, sizeof (EXT_IOCTL));
 652         }
 653 
 654         return (rval);
 655 }
 656 
 657 /*
 658  * ql_validate_signature
 659  *      Validate the signature string for an external ioctl call.
 660  *
 661  * Input:
 662  *      sg:     Pointer to EXT_IOCTL signature to validate.
 663  *
 664  * Returns:
 665  *      B_TRUE:         Signature is valid.
 666  *      B_FALSE:        Signature is NOT valid.
 667  *
 668  * Context:
 669  *      Kernel context.
 670  */
 671 static boolean_t
 672 ql_validate_signature(EXT_IOCTL *cmd_struct)
 673 {
 674         /*
 675          * Check signature.
 676          *
 677          * If signature is not valid then neither is the rest of
 678          * the structure (e.g., can't trust it), so don't attempt
 679          * to return any error status other than the errno.
 680          */
 681         if (bcmp(&cmd_struct->Signature, "QLOGIC", 6) != 0) {
 682                 QL_PRINT_2(NULL, "failed,\n");
 683                 return (B_FALSE);
 684         }
 685 
 686         return (B_TRUE);
 687 }
 688 
 689 /*
 690  * ql_sdm_return
 691  *      Copies return data/status to application land for
 692  *      ioctl call using the SAN/Device Management EXT_IOCTL call interface.
 693  *
 694  * Input:
 695  *      ha:             adapter state pointer.
 696  *      cmd:            Pointer to kernel copy of requestor's EXT_IOCTL struct.
 697  *      ioctl_code:     ioctl function to perform
 698  *      arg:            EXT_IOCTL cmd data in application land.
 699  *      mode:           flags
 700  *
 701  * Returns:
 702  *      0:      success
 703  *      EFAULT: Copy out error.
 704  *
 705  * Context:
 706  *      Kernel context.
 707  */
 708 /* ARGSUSED */
 709 static int
 710 ql_sdm_return(ql_adapter_state_t *ha, EXT_IOCTL *cmd, void *arg, int mode)
 711 {
 712         int     rval = 0;
 713 
 714         QL_PRINT_9(ha, "started\n");
 715 
 716         rval |= ddi_copyout((void *)&cmd->ResponseLen,
 717             (void *)&(((EXT_IOCTL*)arg)->ResponseLen), sizeof (uint32_t),
 718             mode);
 719 
 720         rval |= ddi_copyout((void *)&cmd->Status,
 721             (void *)&(((EXT_IOCTL*)arg)->Status),
 722             sizeof (cmd->Status), mode);
 723         rval |= ddi_copyout((void *)&cmd->DetailStatus,
 724             (void *)&(((EXT_IOCTL*)arg)->DetailStatus),
 725             sizeof (cmd->DetailStatus), mode);
 726 
 727         kmem_free((void *)cmd, sizeof (EXT_IOCTL));
 728 
 729         if (rval != 0) {
 730                 /* Some copyout operation failed */
 731                 EL(ha, "failed, ddi_copyout\n");
 732                 return (EFAULT);
 733         }
 734 
 735         QL_PRINT_9(ha, "done\n");
 736 
 737         return (0);
 738 }
 739 
 740 /*
 741  * ql_query
 742  *      Performs all EXT_CC_QUERY functions.
 743  *
 744  * Input:
 745  *      ha:     adapter state pointer.
 746  *      cmd:    Local EXT_IOCTL cmd struct pointer.
 747  *      mode:   flags.
 748  *
 749  * Returns:
 750  *      None, request status indicated in cmd->Status.
 751  *
 752  * Context:
 753  *      Kernel context.
 754  */
 755 static void
 756 ql_query(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
 757 {
 758         QL_PRINT_9(ha, "started, cmd=%d\n",
 759             cmd->SubCode);
 760 
 761         /* case off on command subcode */
 762         switch (cmd->SubCode) {
 763         case EXT_SC_QUERY_HBA_NODE:
 764                 ql_qry_hba_node(ha, cmd, mode);
 765                 break;
 766         case EXT_SC_QUERY_HBA_PORT:
 767                 ql_qry_hba_port(ha, cmd, mode);
 768                 break;
 769         case EXT_SC_QUERY_DISC_PORT:
 770                 ql_qry_disc_port(ha, cmd, mode);
 771                 break;
 772         case EXT_SC_QUERY_DISC_TGT:
 773                 ql_qry_disc_tgt(ha, cmd, mode);
 774                 break;
 775         case EXT_SC_QUERY_DRIVER:
 776                 ql_qry_driver(ha, cmd, mode);
 777                 break;
 778         case EXT_SC_QUERY_FW:
 779                 ql_qry_fw(ha, cmd, mode);
 780                 break;
 781         case EXT_SC_QUERY_CHIP:
 782                 ql_qry_chip(ha, cmd, mode);
 783                 break;
 784         case EXT_SC_QUERY_CNA_PORT:
 785                 ql_qry_cna_port(ha, cmd, mode);
 786                 break;
 787         case EXT_SC_QUERY_ADAPTER_VERSIONS:
 788                 ql_qry_adapter_versions(ha, cmd, mode);
 789                 break;
 790         case EXT_SC_QUERY_DISC_LUN:
 791         default:
 792                 /* function not supported. */
 793                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
 794                 EL(ha, "failed, Unsupported Subcode=%xh\n",
 795                     cmd->SubCode);
 796                 break;
 797         }
 798 
 799         QL_PRINT_9(ha, "done\n");
 800 }
 801 
 802 /*
 803  * ql_qry_hba_node
 804  *      Performs EXT_SC_QUERY_HBA_NODE subfunction.
 805  *
 806  * Input:
 807  *      ha:     adapter state pointer.
 808  *      cmd:    EXT_IOCTL cmd struct pointer.
 809  *      mode:   flags.
 810  *
 811  * Returns:
 812  *      None, request status indicated in cmd->Status.
 813  *
 814  * Context:
 815  *      Kernel context.
 816  */
 817 static void
 818 ql_qry_hba_node(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
 819 {
 820         EXT_HBA_NODE    tmp_node = {0};
 821         uint_t          len;
 822         caddr_t         bufp;
 823 
 824         QL_PRINT_9(ha, "started\n");
 825 
 826         if (cmd->ResponseLen < sizeof (EXT_HBA_NODE)) {
 827                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
 828                 cmd->DetailStatus = sizeof (EXT_HBA_NODE);
 829                 EL(ha, "failed, ResponseLen < EXT_HBA_NODE, "
 830                     "Len=%xh\n", cmd->ResponseLen);
 831                 cmd->ResponseLen = 0;
 832                 return;
 833         }
 834 
 835         /* fill in the values */
 836 
 837         bcopy(ha->loginparams.node_ww_name.raw_wwn, tmp_node.WWNN,
 838             EXT_DEF_WWN_NAME_SIZE);
 839 
 840         (void) sprintf((char *)(tmp_node.Manufacturer), "QLogic Corporation");
 841 
 842         (void) sprintf((char *)(tmp_node.Model), "%x", ha->device_id);
 843 
 844         bcopy(&tmp_node.WWNN[5], tmp_node.SerialNum, 3);
 845 
 846         (void) sprintf((char *)(tmp_node.DriverVersion), QL_VERSION);
 847 
 848         if (CFG_IST(ha, CFG_SBUS_CARD)) {
 849                 size_t          verlen;
 850                 uint16_t        w;
 851                 char            *tmpptr;
 852 
 853                 verlen = strlen((char *)(tmp_node.DriverVersion));
 854                 if (verlen + 5 > EXT_DEF_MAX_STR_SIZE) {
 855                         EL(ha, "failed, No room for fpga version string\n");
 856                 } else {
 857                         w = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
 858                             (uint16_t *)
 859                             (ha->sbus_fpga_iobase + FPGA_REVISION));
 860 
 861                         tmpptr = (char *)&(tmp_node.DriverVersion[verlen + 1]);
 862                         if (tmpptr == NULL) {
 863                                 EL(ha, "Unable to insert fpga version str\n");
 864                         } else {
 865                                 (void) sprintf(tmpptr, "%d.%d",
 866                                     ((w & 0xf0) >> 4), (w & 0x0f));
 867                                 tmp_node.DriverAttr |= EXT_CC_HBA_NODE_SBUS;
 868                         }
 869                 }
 870         }
 871 
 872         (void) sprintf((char *)(tmp_node.FWVersion), "%01d.%02d.%02d",
 873             ha->fw_major_version, ha->fw_minor_version,
 874             ha->fw_subminor_version);
 875 
 876         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
 877                 switch (ha->fw_attributes) {
 878                 case FWATTRIB_EF:
 879                         (void) strcat((char *)(tmp_node.FWVersion), " EF");
 880                         break;
 881                 case FWATTRIB_TP:
 882                         (void) strcat((char *)(tmp_node.FWVersion), " TP");
 883                         break;
 884                 case FWATTRIB_IP:
 885                         (void) strcat((char *)(tmp_node.FWVersion), " IP");
 886                         break;
 887                 case FWATTRIB_IPX:
 888                         (void) strcat((char *)(tmp_node.FWVersion), " IPX");
 889                         break;
 890                 case FWATTRIB_FL:
 891                         (void) strcat((char *)(tmp_node.FWVersion), " FL");
 892                         break;
 893                 case FWATTRIB_FPX:
 894                         (void) strcat((char *)(tmp_node.FWVersion), " FLX");
 895                         break;
 896                 default:
 897                         break;
 898                 }
 899         }
 900 
 901         /* FCode version. */
 902         /*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
 903         if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip, PROP_LEN_AND_VAL_ALLOC |
 904             DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
 905             (int *)&len) == DDI_PROP_SUCCESS) {
 906                 if (len < EXT_DEF_MAX_STR_SIZE) {
 907                         bcopy(bufp, tmp_node.OptRomVersion, len);
 908                 } else {
 909                         bcopy(bufp, tmp_node.OptRomVersion,
 910                             EXT_DEF_MAX_STR_SIZE - 1);
 911                         tmp_node.OptRomVersion[EXT_DEF_MAX_STR_SIZE - 1] =
 912                             '\0';
 913                 }
 914                 kmem_free(bufp, len);
 915         } else {
 916                 (void) sprintf((char *)tmp_node.OptRomVersion, "0");
 917         }
 918         tmp_node.PortCount = 1;
 919         tmp_node.InterfaceType = EXT_DEF_FC_INTF_TYPE;
 920 
 921         tmp_node.MpiVersion[0] = ha->mpi_fw_major_version;
 922         tmp_node.MpiVersion[1] = ha->mpi_fw_minor_version;
 923         tmp_node.MpiVersion[2] = ha->mpi_fw_subminor_version;
 924         tmp_node.PepFwVersion[0] = ha->phy_fw_major_version;
 925         tmp_node.PepFwVersion[1] = ha->phy_fw_minor_version;
 926         tmp_node.PepFwVersion[2] = ha->phy_fw_subminor_version;
 927         if (ddi_copyout((void *)&tmp_node,
 928             (void *)(uintptr_t)(cmd->ResponseAdr),
 929             sizeof (EXT_HBA_NODE), mode) != 0) {
 930                 cmd->Status = EXT_STATUS_COPY_ERR;
 931                 cmd->ResponseLen = 0;
 932                 EL(ha, "failed, ddi_copyout\n");
 933         } else {
 934                 cmd->ResponseLen = sizeof (EXT_HBA_NODE);
 935                 QL_PRINT_9(ha, "done\n");
 936         }
 937 }
 938 
 939 /*
 940  * ql_qry_hba_port
 941  *      Performs EXT_SC_QUERY_HBA_PORT subfunction.
 942  *
 943  * Input:
 944  *      ha:     adapter state pointer.
 945  *      cmd:    EXT_IOCTL cmd struct pointer.
 946  *      mode:   flags.
 947  *
 948  * Returns:
 949  *      None, request status indicated in cmd->Status.
 950  *
 951  * Context:
 952  *      Kernel context.
 953  */
 954 static void
 955 ql_qry_hba_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
 956 {
 957         ql_link_t       *link;
 958         ql_tgt_t        *tq;
 959         ql_mbx_data_t   mr = {0};
 960         EXT_HBA_PORT    tmp_port = {0};
 961         int             rval;
 962         uint16_t        port_cnt, tgt_cnt, index;
 963 
 964         QL_PRINT_9(ha, "started\n");
 965 
 966         if (cmd->ResponseLen < sizeof (EXT_HBA_PORT)) {
 967                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
 968                 cmd->DetailStatus = sizeof (EXT_HBA_PORT);
 969                 EL(ha, "failed, ResponseLen < EXT_HBA_NODE, Len=%xh\n",
 970                     cmd->ResponseLen);
 971                 cmd->ResponseLen = 0;
 972                 return;
 973         }
 974 
 975         /* fill in the values */
 976 
 977         bcopy(ha->loginparams.nport_ww_name.raw_wwn, tmp_port.WWPN,
 978             EXT_DEF_WWN_NAME_SIZE);
 979         tmp_port.Id[0] = 0;
 980         tmp_port.Id[1] = ha->d_id.b.domain;
 981         tmp_port.Id[2] = ha->d_id.b.area;
 982         tmp_port.Id[3] = ha->d_id.b.al_pa;
 983 
 984         /* For now we are initiator only driver */
 985         tmp_port.Type = EXT_DEF_INITIATOR_DEV;
 986 
 987         if (ha->task_daemon_flags & LOOP_DOWN) {
 988                 tmp_port.State = EXT_DEF_HBA_LOOP_DOWN;
 989         } else if (DRIVER_SUSPENDED(ha)) {
 990                 tmp_port.State = EXT_DEF_HBA_SUSPENDED;
 991         } else {
 992                 tmp_port.State = EXT_DEF_HBA_OK;
 993         }
 994 
 995         if (ha->flags & POINT_TO_POINT) {
 996                 tmp_port.Mode = EXT_DEF_P2P_MODE;
 997         } else {
 998                 tmp_port.Mode = EXT_DEF_LOOP_MODE;
 999         }
1000         /*
1001          * fill in the portspeed values.
1002          *
1003          * default to not yet negotiated state
1004          */
1005         tmp_port.PortSpeed = EXT_PORTSPEED_NOT_NEGOTIATED;
1006 
1007         if (tmp_port.State == EXT_DEF_HBA_OK) {
1008                 switch (ha->iidma_rate) {
1009                 case IIDMA_RATE_1GB:
1010                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_1GBIT;
1011                         break;
1012                 case IIDMA_RATE_2GB:
1013                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_2GBIT;
1014                         break;
1015                 case IIDMA_RATE_4GB:
1016                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_4GBIT;
1017                         break;
1018                 case IIDMA_RATE_8GB:
1019                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_8GBIT;
1020                         break;
1021                 case IIDMA_RATE_10GB:
1022                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_10GBIT;
1023                         break;
1024                 case IIDMA_RATE_16GB:
1025                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_16GBIT;
1026                         break;
1027                 case IIDMA_RATE_32GB:
1028                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_32GBIT;
1029                         break;
1030                 default:
1031                         tmp_port.PortSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
1032                         EL(ha, "failed, data rate=%xh\n", mr.mb[1]);
1033                         break;
1034                 }
1035         }
1036 
1037         /* Report all supported port speeds */
1038         if (CFG_IST(ha, CFG_CTRL_25XX)) {
1039                 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_8GBIT |
1040                     EXT_DEF_PORTSPEED_4GBIT | EXT_DEF_PORTSPEED_2GBIT |
1041                     EXT_DEF_PORTSPEED_1GBIT);
1042                 /*
1043                  * Correct supported speeds based on type of
1044                  * sfp that is present
1045                  */
1046                 switch (ha->sfp_stat) {
1047                 case 1:
1048                         /* no sfp detected */
1049                         break;
1050                 case 2:
1051                 case 4:
1052                         /* 4GB sfp */
1053                         tmp_port.PortSupportedSpeed &=
1054                             ~EXT_DEF_PORTSPEED_8GBIT;
1055                         break;
1056                 case 3:
1057                 case 5:
1058                         /* 8GB sfp */
1059                         tmp_port.PortSupportedSpeed &=
1060                             ~EXT_DEF_PORTSPEED_1GBIT;
1061                         break;
1062                 default:
1063                         EL(ha, "sfp_stat: %xh\n", ha->sfp_stat);
1064                         break;
1065 
1066                 }
1067         } else if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
1068                 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_10GBIT;
1069         } else if (CFG_IST(ha, CFG_CTRL_24XX)) {
1070                 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_4GBIT |
1071                     EXT_DEF_PORTSPEED_2GBIT | EXT_DEF_PORTSPEED_1GBIT);
1072         } else if (CFG_IST(ha, CFG_CTRL_23XX)) {
1073                 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_2GBIT |
1074                     EXT_DEF_PORTSPEED_1GBIT);
1075         } else if (CFG_IST(ha, CFG_CTRL_63XX)) {
1076                 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_2GBIT;
1077         } else if (CFG_IST(ha, CFG_CTRL_22XX)) {
1078                 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_1GBIT;
1079         } else if (CFG_IST(ha, CFG_CTRL_83XX)) {
1080                 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_4GBIT |
1081                     EXT_DEF_PORTSPEED_8GBIT | EXT_DEF_PORTSPEED_16GBIT;
1082         } else if (CFG_IST(ha, CFG_CTRL_27XX)) {
1083                 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_4GBIT |
1084                     EXT_DEF_PORTSPEED_8GBIT | EXT_DEF_PORTSPEED_16GBIT |
1085                     EXT_DEF_PORTSPEED_32GBIT;
1086         } else {
1087                 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
1088                 EL(ha, "unknown HBA type: %xh\n", ha->device_id);
1089         }
1090 
1091         if (ha->task_daemon_flags & LOOP_DOWN) {
1092                 (void) ql_get_firmware_state(ha, NULL);
1093         }
1094 
1095         tmp_port.LinkState1 = ha->fw_state[1];
1096         tmp_port.LinkState2 = LSB(ha->sfp_stat);
1097         tmp_port.LinkState3 = ha->fw_state[3];
1098         tmp_port.LinkState6 = ha->fw_state[6];
1099 
1100         port_cnt = 0;
1101         tgt_cnt = 0;
1102 
1103         for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
1104                 for (link = ha->dev[index].first; link != NULL;
1105                     link = link->next) {
1106                         tq = link->base_address;
1107 
1108                         if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1109                             tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
1110                                 continue;
1111                         }
1112 
1113                         if (tq->flags & (TQF_RSCN_RCVD | TQF_IIDMA_NEEDED |
1114                             TQF_NEED_AUTHENTICATION | TQF_PLOGI_PROGRS)) {
1115                                 continue;
1116                         }
1117 
1118                         port_cnt++;
1119                         if ((tq->flags & TQF_INITIATOR_DEVICE) == 0) {
1120                                 tgt_cnt++;
1121                         }
1122                 }
1123         }
1124 
1125         tmp_port.DiscPortCount = port_cnt;
1126         tmp_port.DiscTargetCount = tgt_cnt;
1127 
1128         tmp_port.DiscPortNameType = EXT_DEF_USE_NODE_NAME;
1129 
1130         rval = ddi_copyout((void *)&tmp_port,
1131             (void *)(uintptr_t)(cmd->ResponseAdr),
1132             sizeof (EXT_HBA_PORT), mode);
1133         if (rval != 0) {
1134                 cmd->Status = EXT_STATUS_COPY_ERR;
1135                 cmd->ResponseLen = 0;
1136                 EL(ha, "failed, ddi_copyout\n");
1137         } else {
1138                 cmd->ResponseLen = sizeof (EXT_HBA_PORT);
1139                 QL_PRINT_9(ha, "done, ports=%d, targets=%d\n",
1140                     ha->instance, port_cnt, tgt_cnt);
1141         }
1142 }
1143 
1144 /*
1145  * ql_qry_disc_port
1146  *      Performs EXT_SC_QUERY_DISC_PORT subfunction.
1147  *
1148  * Input:
1149  *      ha:     adapter state pointer.
1150  *      cmd:    EXT_IOCTL cmd struct pointer.
1151  *      mode:   flags.
1152  *
1153  *      cmd->Instance = Port instance in fcport chain.
1154  *
1155  * Returns:
1156  *      None, request status indicated in cmd->Status.
1157  *
1158  * Context:
1159  *      Kernel context.
1160  */
1161 static void
1162 ql_qry_disc_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1163 {
1164         EXT_DISC_PORT   tmp_port = {0};
1165         ql_link_t       *link;
1166         ql_tgt_t        *tq;
1167         uint16_t        index;
1168         uint16_t        inst = 0;
1169 
1170         QL_PRINT_9(ha, "started\n");
1171 
1172         if (cmd->ResponseLen < sizeof (EXT_DISC_PORT)) {
1173                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1174                 cmd->DetailStatus = sizeof (EXT_DISC_PORT);
1175                 EL(ha, "failed, ResponseLen < EXT_DISC_PORT, Len=%xh\n",
1176                     cmd->ResponseLen);
1177                 cmd->ResponseLen = 0;
1178                 return;
1179         }
1180 
1181         for (link = NULL, index = 0;
1182             index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1183                 for (link = ha->dev[index].first; link != NULL;
1184                     link = link->next) {
1185                         tq = link->base_address;
1186 
1187                         if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1188                             tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
1189                                 continue;
1190                         }
1191 
1192                         if (tq->flags & (TQF_RSCN_RCVD | TQF_IIDMA_NEEDED |
1193                             TQF_NEED_AUTHENTICATION | TQF_PLOGI_PROGRS)) {
1194                                 continue;
1195                         }
1196 
1197                         if (inst != cmd->Instance) {
1198                                 inst++;
1199                                 continue;
1200                         }
1201 
1202                         /* fill in the values */
1203                         bcopy(tq->node_name, tmp_port.WWNN,
1204                             EXT_DEF_WWN_NAME_SIZE);
1205                         bcopy(tq->port_name, tmp_port.WWPN,
1206                             EXT_DEF_WWN_NAME_SIZE);
1207 
1208                         break;
1209                 }
1210         }
1211 
1212         if (link == NULL) {
1213                 /* no matching device */
1214                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1215                 EL(ha, "failed, port not found port=%d\n", cmd->Instance);
1216                 cmd->ResponseLen = 0;
1217                 return;
1218         }
1219 
1220         tmp_port.Id[0] = 0;
1221         tmp_port.Id[1] = tq->d_id.b.domain;
1222         tmp_port.Id[2] = tq->d_id.b.area;
1223         tmp_port.Id[3] = tq->d_id.b.al_pa;
1224 
1225         tmp_port.Type = 0;
1226         if (tq->flags & TQF_INITIATOR_DEVICE) {
1227                 tmp_port.Type = (uint16_t)(tmp_port.Type |
1228                     EXT_DEF_INITIATOR_DEV);
1229         } else if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1230                 (void) ql_inq_scan(ha, tq, 1);
1231         } else if (tq->flags & TQF_TAPE_DEVICE) {
1232                 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TAPE_DEV);
1233         }
1234 
1235         if (tq->flags & TQF_FABRIC_DEVICE) {
1236                 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_FABRIC_DEV);
1237         } else {
1238                 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TARGET_DEV);
1239         }
1240 
1241         tmp_port.Status = 0;
1242         tmp_port.Bus = 0;  /* Hard-coded for Solaris */
1243 
1244         bcopy(tq->port_name, &tmp_port.TargetId, 8);
1245 
1246         if (ddi_copyout((void *)&tmp_port,
1247             (void *)(uintptr_t)(cmd->ResponseAdr),
1248             sizeof (EXT_DISC_PORT), mode) != 0) {
1249                 cmd->Status = EXT_STATUS_COPY_ERR;
1250                 cmd->ResponseLen = 0;
1251                 EL(ha, "failed, ddi_copyout\n");
1252         } else {
1253                 cmd->ResponseLen = sizeof (EXT_DISC_PORT);
1254                 QL_PRINT_9(ha, "done\n");
1255         }
1256 }
1257 
1258 /*
1259  * ql_qry_disc_tgt
1260  *      Performs EXT_SC_QUERY_DISC_TGT subfunction.
1261  *
1262  * Input:
1263  *      ha:             adapter state pointer.
1264  *      cmd:            EXT_IOCTL cmd struct pointer.
1265  *      mode:           flags.
1266  *
1267  *      cmd->Instance = Port instance in fcport chain.
1268  *
1269  * Returns:
1270  *      None, request status indicated in cmd->Status.
1271  *
1272  * Context:
1273  *      Kernel context.
1274  */
1275 static void
1276 ql_qry_disc_tgt(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1277 {
1278         EXT_DISC_TARGET tmp_tgt = {0};
1279         ql_link_t       *link;
1280         ql_tgt_t        *tq;
1281         uint16_t        index;
1282         uint16_t        inst = 0;
1283 
1284         QL_PRINT_9(ha, "started, target=%d\n",
1285             cmd->Instance);
1286 
1287         if (cmd->ResponseLen < sizeof (EXT_DISC_TARGET)) {
1288                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1289                 cmd->DetailStatus = sizeof (EXT_DISC_TARGET);
1290                 EL(ha, "failed, ResponseLen < EXT_DISC_TARGET, Len=%xh\n",
1291                     cmd->ResponseLen);
1292                 cmd->ResponseLen = 0;
1293                 return;
1294         }
1295 
1296         /* Scan port list for requested target and fill in the values */
1297         for (link = NULL, index = 0;
1298             index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1299                 for (link = ha->dev[index].first; link != NULL;
1300                     link = link->next) {
1301                         tq = link->base_address;
1302 
1303                         if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1304                             tq->flags & TQF_INITIATOR_DEVICE ||
1305                             tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
1306                                 continue;
1307                         }
1308                         if (inst != cmd->Instance) {
1309                                 inst++;
1310                                 continue;
1311                         }
1312 
1313                         /* fill in the values */
1314                         bcopy(tq->node_name, tmp_tgt.WWNN,
1315                             EXT_DEF_WWN_NAME_SIZE);
1316                         bcopy(tq->port_name, tmp_tgt.WWPN,
1317                             EXT_DEF_WWN_NAME_SIZE);
1318 
1319                         break;
1320                 }
1321         }
1322 
1323         if (link == NULL) {
1324                 /* no matching device */
1325                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1326                 cmd->DetailStatus = EXT_DSTATUS_TARGET;
1327                 EL(ha, "failed, not found target=%d\n", cmd->Instance);
1328                 cmd->ResponseLen = 0;
1329                 return;
1330         }
1331         tmp_tgt.Id[0] = 0;
1332         tmp_tgt.Id[1] = tq->d_id.b.domain;
1333         tmp_tgt.Id[2] = tq->d_id.b.area;
1334         tmp_tgt.Id[3] = tq->d_id.b.al_pa;
1335 
1336         tmp_tgt.LunCount = (uint16_t)ql_lun_count(ha, tq);
1337 
1338         if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1339                 (void) ql_inq_scan(ha, tq, 1);
1340         }
1341 
1342         tmp_tgt.Type = 0;
1343         if (tq->flags & TQF_TAPE_DEVICE) {
1344                 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TAPE_DEV);
1345         }
1346 
1347         if (tq->flags & TQF_FABRIC_DEVICE) {
1348                 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_FABRIC_DEV);
1349         } else {
1350                 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TARGET_DEV);
1351         }
1352 
1353         tmp_tgt.Status = 0;
1354 
1355         tmp_tgt.Bus = 0;  /* Hard-coded for Solaris. */
1356 
1357         bcopy(tq->port_name, &tmp_tgt.TargetId, 8);
1358 
1359         if (ddi_copyout((void *)&tmp_tgt,
1360             (void *)(uintptr_t)(cmd->ResponseAdr),
1361             sizeof (EXT_DISC_TARGET), mode) != 0) {
1362                 cmd->Status = EXT_STATUS_COPY_ERR;
1363                 cmd->ResponseLen = 0;
1364                 EL(ha, "failed, ddi_copyout\n");
1365         } else {
1366                 cmd->ResponseLen = sizeof (EXT_DISC_TARGET);
1367                 QL_PRINT_9(ha, "done\n");
1368         }
1369 }
1370 
1371 /*
1372  * ql_qry_fw
1373  *      Performs EXT_SC_QUERY_FW subfunction.
1374  *
1375  * Input:
1376  *      ha:     adapter state pointer.
1377  *      cmd:    EXT_IOCTL cmd struct pointer.
1378  *      mode:   flags.
1379  *
1380  * Returns:
1381  *      None, request status indicated in cmd->Status.
1382  *
1383  * Context:
1384  *      Kernel context.
1385  */
1386 static void
1387 ql_qry_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1388 {
1389         EXT_FW          fw_info = {0};
1390 
1391         QL_PRINT_9(ha, "started\n");
1392 
1393         if (cmd->ResponseLen < sizeof (EXT_FW)) {
1394                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1395                 cmd->DetailStatus = sizeof (EXT_FW);
1396                 EL(ha, "failed, ResponseLen < EXT_FW, Len=%xh\n",
1397                     cmd->ResponseLen);
1398                 cmd->ResponseLen = 0;
1399                 return;
1400         }
1401 
1402         (void) sprintf((char *)(fw_info.Version), "%d.%02d.%02d",
1403             ha->fw_major_version, ha->fw_minor_version,
1404             ha->fw_subminor_version);
1405 
1406         fw_info.Attrib = ha->fw_attributes;
1407 
1408         if (ddi_copyout((void *)&fw_info,
1409             (void *)(uintptr_t)(cmd->ResponseAdr),
1410             sizeof (EXT_FW), mode) != 0) {
1411                 cmd->Status = EXT_STATUS_COPY_ERR;
1412                 cmd->ResponseLen = 0;
1413                 EL(ha, "failed, ddi_copyout\n");
1414                 return;
1415         } else {
1416                 cmd->ResponseLen = sizeof (EXT_FW);
1417                 QL_PRINT_9(ha, "done\n");
1418         }
1419 }
1420 
1421 /*
1422  * ql_qry_chip
1423  *      Performs EXT_SC_QUERY_CHIP subfunction.
1424  *
1425  * Input:
1426  *      ha:     adapter state pointer.
1427  *      cmd:    EXT_IOCTL cmd struct pointer.
1428  *      mode:   flags.
1429  *
1430  * Returns:
1431  *      None, request status indicated in cmd->Status.
1432  *
1433  * Context:
1434  *      Kernel context.
1435  */
1436 static void
1437 ql_qry_chip(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1438 {
1439         EXT_CHIP        chip = {0};
1440         uint16_t        PciDevNumber;
1441 
1442         QL_PRINT_9(ha, "started\n");
1443 
1444         if (cmd->ResponseLen < sizeof (EXT_CHIP)) {
1445                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1446                 cmd->DetailStatus = sizeof (EXT_CHIP);
1447                 EL(ha, "failed, ResponseLen < EXT_CHIP, Len=%xh\n",
1448                     cmd->ResponseLen);
1449                 cmd->ResponseLen = 0;
1450                 return;
1451         }
1452 
1453         chip.VendorId = ha->ven_id;
1454         chip.DeviceId = ha->device_id;
1455         chip.SubVendorId = ha->subven_id;
1456         chip.SubSystemId = ha->subsys_id;
1457         chip.IoAddr = ql_pci_config_get32(ha, PCI_CONF_BASE0);
1458         chip.IoAddrLen = 0x100;
1459         chip.MemAddr = ql_pci_config_get32(ha, PCI_CONF_BASE1);
1460         chip.MemAddrLen = 0x100;
1461         chip.ChipRevID = ha->rev_id;
1462         chip.FuncNo = ha->pci_function_number;
1463         chip.PciBusNumber = (uint16_t)
1464             ((ha->pci_bus_addr & PCI_REG_BUS_M) >> PCI_REG_BUS_SHIFT);
1465 
1466         PciDevNumber = (uint16_t)
1467             ((ha->pci_bus_addr & PCI_REG_DEV_M) >> PCI_REG_DEV_SHIFT);
1468         chip.PciSlotNumber = (uint16_t)(((PciDevNumber << 3) & 0xF8) |
1469             (chip.FuncNo & 0x7));
1470 
1471         if (ddi_copyout((void *)&chip,
1472             (void *)(uintptr_t)(cmd->ResponseAdr),
1473             sizeof (EXT_CHIP), mode) != 0) {
1474                 cmd->Status = EXT_STATUS_COPY_ERR;
1475                 cmd->ResponseLen = 0;
1476                 EL(ha, "failed, ddi_copyout\n");
1477         } else {
1478                 cmd->ResponseLen = sizeof (EXT_CHIP);
1479                 QL_PRINT_9(ha, "done\n");
1480         }
1481 }
1482 
1483 /*
1484  * ql_qry_driver
1485  *      Performs EXT_SC_QUERY_DRIVER subfunction.
1486  *
1487  * Input:
1488  *      ha:     adapter state pointer.
1489  *      cmd:    EXT_IOCTL cmd struct pointer.
1490  *      mode:   flags.
1491  *
1492  * Returns:
1493  *      None, request status indicated in cmd->Status.
1494  *
1495  * Context:
1496  *      Kernel context.
1497  */
1498 static void
1499 ql_qry_driver(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1500 {
1501         EXT_DRIVER      qd = {0};
1502 
1503         QL_PRINT_9(ha, "started\n");
1504 
1505         if (cmd->ResponseLen < sizeof (EXT_DRIVER)) {
1506                 cmd->Status = EXT_STATUS_DATA_OVERRUN;
1507                 cmd->DetailStatus = sizeof (EXT_DRIVER);
1508                 EL(ha, "failed, ResponseLen < EXT_DRIVER, Len=%xh\n",
1509                     cmd->ResponseLen);
1510                 cmd->ResponseLen = 0;
1511                 return;
1512         }
1513 
1514         (void) strcpy((void *)&qd.Version[0], QL_VERSION);
1515         qd.NumOfBus = 1;        /* Fixed for Solaris */
1516         qd.TargetsPerBus = (uint16_t)
1517             (CFG_IST(ha, (CFG_ISP_FW_TYPE_2 | CFG_EXT_FW_INTERFACE)) ?
1518             MAX_24_FIBRE_DEVICES : MAX_22_FIBRE_DEVICES);
1519         qd.LunsPerTarget = 2030;
1520         qd.MaxTransferLen = QL_DMA_MAX_XFER_SIZE;
1521         qd.MaxDataSegments = QL_DMA_SG_LIST_LENGTH;
1522 
1523         if (ddi_copyout((void *)&qd, (void *)(uintptr_t)cmd->ResponseAdr,
1524             sizeof (EXT_DRIVER), mode) != 0) {
1525                 cmd->Status = EXT_STATUS_COPY_ERR;
1526                 cmd->ResponseLen = 0;
1527                 EL(ha, "failed, ddi_copyout\n");
1528         } else {
1529                 cmd->ResponseLen = sizeof (EXT_DRIVER);
1530                 QL_PRINT_9(ha, "done\n");
1531         }
1532 }
1533 
1534 /*
1535  * ql_fcct
1536  *      IOCTL management server FC-CT passthrough.
1537  *
1538  * Input:
1539  *      ha:     adapter state pointer.
1540  *      cmd:    User space CT arguments pointer.
1541  *      mode:   flags.
1542  *
1543  * Returns:
1544  *      None, request status indicated in cmd->Status.
1545  *
1546  * Context:
1547  *      Kernel context.
1548  */
1549 static void
1550 ql_fcct(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1551 {
1552         ql_mbx_iocb_t           *pkt;
1553         ql_mbx_data_t           mr;
1554         dma_mem_t               *dma_mem;
1555         caddr_t                 pld;
1556         uint32_t                pkt_size, pld_byte_cnt, *long_ptr;
1557         int                     rval;
1558         ql_ct_iu_preamble_t     *ct;
1559         ql_xioctl_t             *xp = ha->xioctl;
1560         ql_tgt_t                tq;
1561         uint16_t                comp_status, loop_id;
1562 
1563         QL_PRINT_9(ha, "started\n");
1564 
1565         /* Get CT argument structure. */
1566         if ((ha->topology & QL_FABRIC_CONNECTION) == 0) {
1567                 EL(ha, "failed, No switch\n");
1568                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1569                 cmd->ResponseLen = 0;
1570                 return;
1571         }
1572 
1573         if (DRIVER_SUSPENDED(ha)) {
1574                 EL(ha, "failed, LOOP_NOT_READY\n");
1575                 cmd->Status = EXT_STATUS_BUSY;
1576                 cmd->ResponseLen = 0;
1577                 return;
1578         }
1579 
1580         /* Login management server device. */
1581         if ((xp->flags & QL_MGMT_SERVER_LOGIN) == 0) {
1582                 tq.d_id.b.al_pa = 0xfa;
1583                 tq.d_id.b.area = 0xff;
1584                 tq.d_id.b.domain = 0xff;
1585                 tq.loop_id = (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
1586                     MANAGEMENT_SERVER_24XX_LOOP_ID :
1587                     MANAGEMENT_SERVER_LOOP_ID);
1588                 rval = ql_login_fport(ha, &tq, tq.loop_id, LFF_NO_PRLI, &mr);
1589                 if (rval != QL_SUCCESS) {
1590                         EL(ha, "failed, server login\n");
1591                         cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1592                         cmd->ResponseLen = 0;
1593                         return;
1594                 } else {
1595                         xp->flags |= QL_MGMT_SERVER_LOGIN;
1596                 }
1597         }
1598 
1599         QL_PRINT_9(ha, "cmd\n");
1600         QL_DUMP_9(cmd, 8, sizeof (EXT_IOCTL));
1601 
1602         /* Allocate a DMA Memory Descriptor */
1603         dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
1604         if (dma_mem == NULL) {
1605                 EL(ha, "failed, kmem_zalloc\n");
1606                 cmd->Status = EXT_STATUS_NO_MEMORY;
1607                 cmd->ResponseLen = 0;
1608                 return;
1609         }
1610         /* Determine maximum buffer size. */
1611         if (cmd->RequestLen < cmd->ResponseLen) {
1612                 pld_byte_cnt = cmd->ResponseLen;
1613         } else {
1614                 pld_byte_cnt = cmd->RequestLen;
1615         }
1616 
1617         /* Allocate command block. */
1618         pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_byte_cnt);
1619         pkt = kmem_zalloc(pkt_size, KM_SLEEP);
1620         if (pkt == NULL) {
1621                 EL(ha, "failed, kmem_zalloc\n");
1622                 cmd->Status = EXT_STATUS_NO_MEMORY;
1623                 cmd->ResponseLen = 0;
1624                 return;
1625         }
1626         pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
1627 
1628         /* Get command payload data. */
1629         if (ql_get_buffer_data((caddr_t)(uintptr_t)cmd->RequestAdr, pld,
1630             cmd->RequestLen, mode) != cmd->RequestLen) {
1631                 EL(ha, "failed, get_buffer_data\n");
1632                 kmem_free(pkt, pkt_size);
1633                 cmd->Status = EXT_STATUS_COPY_ERR;
1634                 cmd->ResponseLen = 0;
1635                 return;
1636         }
1637 
1638         /* Get DMA memory for the IOCB */
1639         if (ql_get_dma_mem(ha, dma_mem, pkt_size, LITTLE_ENDIAN_DMA,
1640             QL_DMA_RING_ALIGN) != QL_SUCCESS) {
1641                 cmn_err(CE_WARN, "%sDMA memory "
1642                     "alloc failed", QL_NAME);
1643                 kmem_free(pkt, pkt_size);
1644                 kmem_free(dma_mem, sizeof (dma_mem_t));
1645                 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1646                 cmd->ResponseLen = 0;
1647                 return;
1648         }
1649 
1650         /* Copy out going payload data to IOCB DMA buffer. */
1651         ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
1652             (uint8_t *)dma_mem->bp, pld_byte_cnt, DDI_DEV_AUTOINCR);
1653 
1654         /* Sync IOCB DMA buffer. */
1655         (void) ddi_dma_sync(dma_mem->dma_handle, 0, pld_byte_cnt,
1656             DDI_DMA_SYNC_FORDEV);
1657 
1658         /*
1659          * Setup IOCB
1660          */
1661         ct = (ql_ct_iu_preamble_t *)pld;
1662         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
1663                 pkt->ms24.entry_type = CT_PASSTHRU_TYPE;
1664                 pkt->ms24.entry_count = 1;
1665 
1666                 pkt->ms24.vp_index = ha->vp_index;
1667 
1668                 /* Set loop ID */
1669                 pkt->ms24.n_port_hdl = (uint16_t)
1670                     (ct->gs_type == GS_TYPE_DIR_SERVER ?
1671                     LE_16(SNS_24XX_HDL) :
1672                     LE_16(MANAGEMENT_SERVER_24XX_LOOP_ID));
1673 
1674                 /* Set ISP command timeout. */
1675                 pkt->ms24.timeout = LE_16(120);
1676 
1677                 /* Set cmd/response data segment counts. */
1678                 pkt->ms24.cmd_dseg_count = LE_16(1);
1679                 pkt->ms24.resp_dseg_count = LE_16(1);
1680 
1681                 /* Load ct cmd byte count. */
1682                 pkt->ms24.cmd_byte_count = LE_32(cmd->RequestLen);
1683 
1684                 /* Load ct rsp byte count. */
1685                 pkt->ms24.resp_byte_count = LE_32(cmd->ResponseLen);
1686 
1687                 long_ptr = (uint32_t *)&pkt->ms24.dseg;
1688 
1689                 /* Load MS command entry data segments. */
1690                 *long_ptr++ = (uint32_t)
1691                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
1692                 *long_ptr++ = (uint32_t)
1693                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
1694                 *long_ptr++ = (uint32_t)(LE_32(cmd->RequestLen));
1695 
1696                 /* Load MS response entry data segments. */
1697                 *long_ptr++ = (uint32_t)
1698                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
1699                 *long_ptr++ = (uint32_t)
1700                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
1701                 *long_ptr = (uint32_t)LE_32(cmd->ResponseLen);
1702 
1703                 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1704                     sizeof (ql_mbx_iocb_t));
1705 
1706                 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
1707                 if (comp_status == CS_DATA_UNDERRUN) {
1708                         if ((BE_16(ct->max_residual_size)) == 0) {
1709                                 comp_status = CS_COMPLETE;
1710                         }
1711                 }
1712 
1713                 if (rval != QL_SUCCESS || (pkt->sts24.entry_status & 0x3c) !=
1714                     0) {
1715                         EL(ha, "failed, I/O timeout or "
1716                             "es=%xh, ss_l=%xh, rval=%xh\n",
1717                             pkt->sts24.entry_status,
1718                             pkt->sts24.scsi_status_l, rval);
1719                         kmem_free(pkt, pkt_size);
1720                         ql_free_dma_resource(ha, dma_mem);
1721                         kmem_free(dma_mem, sizeof (dma_mem_t));
1722                         cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1723                         cmd->ResponseLen = 0;
1724                         return;
1725                 }
1726         } else {
1727                 pkt->ms.entry_type = MS_TYPE;
1728                 pkt->ms.entry_count = 1;
1729 
1730                 /* Set loop ID */
1731                 loop_id = (uint16_t)(ct->gs_type == GS_TYPE_DIR_SERVER ?
1732                     SIMPLE_NAME_SERVER_LOOP_ID : MANAGEMENT_SERVER_LOOP_ID);
1733                 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
1734                         pkt->ms.loop_id_l = LSB(loop_id);
1735                         pkt->ms.loop_id_h = MSB(loop_id);
1736                 } else {
1737                         pkt->ms.loop_id_h = LSB(loop_id);
1738                 }
1739 
1740                 /* Set ISP command timeout. */
1741                 pkt->ms.timeout = LE_16(120);
1742 
1743                 /* Set data segment counts. */
1744                 pkt->ms.cmd_dseg_count_l = 1;
1745                 pkt->ms.total_dseg_count = LE_16(2);
1746 
1747                 /* Response total byte count. */
1748                 pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen);
1749                 pkt->ms.dseg[1].length = LE_32(cmd->ResponseLen);
1750 
1751                 /* Command total byte count. */
1752                 pkt->ms.cmd_byte_count = LE_32(cmd->RequestLen);
1753                 pkt->ms.dseg[0].length = LE_32(cmd->RequestLen);
1754 
1755                 /* Load command/response data segments. */
1756                 pkt->ms.dseg[0].address[0] = (uint32_t)
1757                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
1758                 pkt->ms.dseg[0].address[1] = (uint32_t)
1759                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
1760                 pkt->ms.dseg[1].address[0] = (uint32_t)
1761                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
1762                 pkt->ms.dseg[1].address[1] = (uint32_t)
1763                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
1764 
1765                 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1766                     sizeof (ql_mbx_iocb_t));
1767 
1768                 comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
1769                 if (comp_status == CS_DATA_UNDERRUN) {
1770                         if ((BE_16(ct->max_residual_size)) == 0) {
1771                                 comp_status = CS_COMPLETE;
1772                         }
1773                 }
1774                 if (rval != QL_SUCCESS || (pkt->sts.entry_status & 0x7e) != 0) {
1775                         EL(ha, "failed, I/O timeout or "
1776                             "es=%xh, rval=%xh\n", pkt->sts.entry_status, rval);
1777                         kmem_free(pkt, pkt_size);
1778                         ql_free_dma_resource(ha, dma_mem);
1779                         kmem_free(dma_mem, sizeof (dma_mem_t));
1780                         cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1781                         cmd->ResponseLen = 0;
1782                         return;
1783                 }
1784         }
1785 
1786         /* Sync in coming DMA buffer. */
1787         (void) ddi_dma_sync(dma_mem->dma_handle, 0,
1788             pld_byte_cnt, DDI_DMA_SYNC_FORKERNEL);
1789         /* Copy in coming DMA data. */
1790         ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
1791             (uint8_t *)dma_mem->bp, pld_byte_cnt,
1792             DDI_DEV_AUTOINCR);
1793 
1794         /* Copy response payload from DMA buffer to application. */
1795         if (cmd->ResponseLen != 0) {
1796                 QL_PRINT_9(ha, "ResponseLen=%d\n",
1797                     cmd->ResponseLen);
1798                 QL_DUMP_9(pld, 8, cmd->ResponseLen);
1799 
1800                 /* Send response payload. */
1801                 if (ql_send_buffer_data(pld,
1802                     (caddr_t)(uintptr_t)cmd->ResponseAdr,
1803                     cmd->ResponseLen, mode) != cmd->ResponseLen) {
1804                         EL(ha, "failed, send_buffer_data\n");
1805                         cmd->Status = EXT_STATUS_COPY_ERR;
1806                         cmd->ResponseLen = 0;
1807                 }
1808         }
1809 
1810         kmem_free(pkt, pkt_size);
1811         ql_free_dma_resource(ha, dma_mem);
1812         kmem_free(dma_mem, sizeof (dma_mem_t));
1813 
1814         QL_PRINT_9(ha, "done\n");
1815 }
1816 
1817 /*
1818  * ql_aen_reg
1819  *      IOCTL management server Asynchronous Event Tracking Enable/Disable.
1820  *
1821  * Input:
1822  *      ha:     adapter state pointer.
1823  *      cmd:    EXT_IOCTL cmd struct pointer.
1824  *      mode:   flags.
1825  *
1826  * Returns:
1827  *      None, request status indicated in cmd->Status.
1828  *
1829  * Context:
1830  *      Kernel context.
1831  */
1832 static void
1833 ql_aen_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1834 {
1835         EXT_REG_AEN     reg_struct;
1836         int             rval = 0;
1837         ql_xioctl_t     *xp = ha->xioctl;
1838 
1839         QL_PRINT_9(ha, "started\n");
1840 
1841         rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &reg_struct,
1842             cmd->RequestLen, mode);
1843 
1844         if (rval == 0) {
1845                 if (reg_struct.Enable) {
1846                         xp->flags |= QL_AEN_TRACKING_ENABLE;
1847                 } else {
1848                         xp->flags &= ~QL_AEN_TRACKING_ENABLE;
1849                         /* Empty the queue. */
1850                         INTR_LOCK(ha);
1851                         xp->aen_q_head = 0;
1852                         xp->aen_q_tail = 0;
1853                         INTR_UNLOCK(ha);
1854                 }
1855                 QL_PRINT_9(ha, "done\n");
1856         } else {
1857                 cmd->Status = EXT_STATUS_COPY_ERR;
1858                 EL(ha, "failed, ddi_copyin\n");
1859         }
1860 }
1861 
1862 /*
1863  * ql_aen_get
1864  *      IOCTL management server Asynchronous Event Record Transfer.
1865  *
1866  * Input:
1867  *      ha:     adapter state pointer.
1868  *      cmd:    EXT_IOCTL cmd struct pointer.
1869  *      mode:   flags.
1870  *
1871  * Returns:
1872  *      None, request status indicated in cmd->Status.
1873  *
1874  * Context:
1875  *      Kernel context.
1876  */
1877 static void
1878 ql_aen_get(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1879 {
1880         uint32_t        out_size;
1881         EXT_ASYNC_EVENT *tmp_q;
1882         EXT_ASYNC_EVENT aen[EXT_DEF_MAX_AEN_QUEUE];
1883         uint8_t         i;
1884         uint8_t         queue_cnt;
1885         uint8_t         request_cnt;
1886         ql_xioctl_t     *xp = ha->xioctl;
1887 
1888         QL_PRINT_9(ha, "started\n");
1889 
1890         /* Compute the number of events that can be returned */
1891         request_cnt = (uint8_t)(cmd->ResponseLen / sizeof (EXT_ASYNC_EVENT));
1892 
1893         if (request_cnt < EXT_DEF_MAX_AEN_QUEUE) {
1894                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1895                 cmd->DetailStatus = EXT_DEF_MAX_AEN_QUEUE;
1896                 EL(ha, "failed, request_cnt < EXT_DEF_MAX_AEN_QUEUE, "
1897                     "Len=%xh\n", request_cnt);
1898                 cmd->ResponseLen = 0;
1899                 return;
1900         }
1901 
1902         /* 1st: Make a local copy of the entire queue content. */
1903         tmp_q = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1904         queue_cnt = 0;
1905 
1906         INTR_LOCK(ha);
1907         i = xp->aen_q_head;
1908 
1909         for (; queue_cnt < EXT_DEF_MAX_AEN_QUEUE; ) {
1910                 if (tmp_q[i].AsyncEventCode != 0) {
1911                         bcopy(&tmp_q[i], &aen[queue_cnt],
1912                             sizeof (EXT_ASYNC_EVENT));
1913                         queue_cnt++;
1914                         tmp_q[i].AsyncEventCode = 0; /* empty out the slot */
1915                 }
1916                 if (i == xp->aen_q_tail) {
1917                         /* done. */
1918                         break;
1919                 }
1920                 i++;
1921                 if (i == EXT_DEF_MAX_AEN_QUEUE) {
1922                         i = 0;
1923                 }
1924         }
1925 
1926         /* Empty the queue. */
1927         xp->aen_q_head = 0;
1928         xp->aen_q_tail = 0;
1929 
1930         INTR_UNLOCK(ha);
1931 
1932         /* 2nd: Now transfer the queue content to user buffer */
1933         /* Copy the entire queue to user's buffer. */
1934         out_size = (uint32_t)(queue_cnt * sizeof (EXT_ASYNC_EVENT));
1935         if (queue_cnt == 0) {
1936                 cmd->ResponseLen = 0;
1937         } else if (ddi_copyout((void *)&aen[0],
1938             (void *)(uintptr_t)(cmd->ResponseAdr),
1939             out_size, mode) != 0) {
1940                 cmd->Status = EXT_STATUS_COPY_ERR;
1941                 cmd->ResponseLen = 0;
1942                 EL(ha, "failed, ddi_copyout\n");
1943         } else {
1944                 cmd->ResponseLen = out_size;
1945                 QL_PRINT_9(ha, "done\n");
1946         }
1947 }
1948 
1949 /*
1950  * ql_enqueue_aen
1951  *
1952  * Input:
1953  *      ha:             adapter state pointer.
1954  *      event_code:     async event code of the event to add to queue.
1955  *      payload:        event payload for the queue.
1956  *      INTR_LOCK must be already obtained.
1957  *
1958  * Context:
1959  *      Interrupt or Kernel context, no mailbox commands allowed.
1960  */
1961 void
1962 ql_enqueue_aen(ql_adapter_state_t *ha, uint16_t event_code, void *payload)
1963 {
1964         uint8_t                 new_entry;      /* index to current entry */
1965         uint16_t                *mbx;
1966         EXT_ASYNC_EVENT         *aen_queue;
1967         ql_xioctl_t             *xp = ha->xioctl;
1968 
1969         QL_PRINT_9(ha, "started, event_code=%d\n",
1970             event_code);
1971 
1972         if (xp == NULL) {
1973                 QL_PRINT_9(ha, "no context\n");
1974                 return;
1975         }
1976         aen_queue = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1977 
1978         if (aen_queue[xp->aen_q_tail].AsyncEventCode != NULL) {
1979                 /* Need to change queue pointers to make room. */
1980 
1981                 /* Increment tail for adding new entry. */
1982                 xp->aen_q_tail++;
1983                 if (xp->aen_q_tail == EXT_DEF_MAX_AEN_QUEUE) {
1984                         xp->aen_q_tail = 0;
1985                 }
1986                 if (xp->aen_q_head == xp->aen_q_tail) {
1987                         /*
1988                          * We're overwriting the oldest entry, so need to
1989                          * update the head pointer.
1990                          */
1991                         xp->aen_q_head++;
1992                         if (xp->aen_q_head == EXT_DEF_MAX_AEN_QUEUE) {
1993                                 xp->aen_q_head = 0;
1994                         }
1995                 }
1996         }
1997 
1998         new_entry = xp->aen_q_tail;
1999         aen_queue[new_entry].AsyncEventCode = event_code;
2000 
2001         /* Update payload */
2002         if (payload != NULL) {
2003                 switch (event_code) {
2004                 case MBA_LIP_OCCURRED:
2005                 case MBA_LOOP_UP:
2006                 case MBA_LOOP_DOWN:
2007                 case MBA_LIP_F8:
2008                 case MBA_LIP_RESET:
2009                 case MBA_PORT_UPDATE:
2010                         break;
2011                 case MBA_RSCN_UPDATE:
2012                         mbx = (uint16_t *)payload;
2013                         /* al_pa */
2014                         aen_queue[new_entry].Payload.RSCN.RSCNInfo[0] =
2015                             LSB(mbx[2]);
2016                         /* area */
2017                         aen_queue[new_entry].Payload.RSCN.RSCNInfo[1] =
2018                             MSB(mbx[2]);
2019                         /* domain */
2020                         aen_queue[new_entry].Payload.RSCN.RSCNInfo[2] =
2021                             LSB(mbx[1]);
2022                         /* save in big endian */
2023                         BIG_ENDIAN_24(&aen_queue[new_entry].
2024                             Payload.RSCN.RSCNInfo[0]);
2025 
2026                         aen_queue[new_entry].Payload.RSCN.AddrFormat =
2027                             MSB(mbx[1]);
2028 
2029                         break;
2030                 default:
2031                         /* Not supported */
2032                         EL(ha, "failed, event code not supported=%xh\n",
2033                             event_code);
2034                         aen_queue[new_entry].AsyncEventCode = 0;
2035                         break;
2036                 }
2037         }
2038 
2039         QL_PRINT_9(ha, "done\n");
2040 }
2041 
2042 /*
2043  * ql_scsi_passthru
2044  *      IOCTL SCSI passthrough.
2045  *
2046  * Input:
2047  *      ha:     adapter state pointer.
2048  *      cmd:    User space SCSI command pointer.
2049  *      mode:   flags.
2050  *
2051  * Returns:
2052  *      None, request status indicated in cmd->Status.
2053  *
2054  * Context:
2055  *      Kernel context.
2056  */
2057 static void
2058 ql_scsi_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2059 {
2060         ql_mbx_iocb_t           *pkt;
2061         ql_mbx_data_t           mr;
2062         dma_mem_t               *dma_mem;
2063         caddr_t                 pld;
2064         uint32_t                pkt_size, pld_size;
2065         uint16_t                qlnt, retries, cnt, cnt2;
2066         uint8_t                 *name;
2067         EXT_FC_SCSI_PASSTHRU    *ufc_req;
2068         EXT_SCSI_PASSTHRU       *usp_req;
2069         int                     rval;
2070         union _passthru {
2071                 EXT_SCSI_PASSTHRU       sp_cmd;
2072                 EXT_FC_SCSI_PASSTHRU    fc_cmd;
2073         } pt_req;               /* Passthru request */
2074         uint32_t                status, sense_sz = 0;
2075         ql_tgt_t                *tq = NULL;
2076         EXT_SCSI_PASSTHRU       *sp_req = &pt_req.sp_cmd;
2077         EXT_FC_SCSI_PASSTHRU    *fc_req = &pt_req.fc_cmd;
2078 
2079         /* SCSI request struct for SCSI passthrough IOs. */
2080         struct {
2081                 uint16_t        lun;
2082                 uint16_t        sense_length;   /* Sense buffer size */
2083                 size_t          resid;          /* Residual */
2084                 uint8_t         *cdbp;          /* Requestor's CDB */
2085                 uint8_t         *u_sense;       /* Requestor's sense buffer */
2086                 uint8_t         cdb_len;        /* Requestor's CDB length */
2087                 uint8_t         direction;
2088         } scsi_req;
2089 
2090         struct {
2091                 uint8_t         *rsp_info;
2092                 uint8_t         *req_sense_data;
2093                 uint32_t        residual_length;
2094                 uint32_t        rsp_info_length;
2095                 uint32_t        req_sense_length;
2096                 uint16_t        comp_status;
2097                 uint8_t         state_flags_l;
2098                 uint8_t         state_flags_h;
2099                 uint8_t         scsi_status_l;
2100                 uint8_t         scsi_status_h;
2101         } sts;
2102 
2103         QL_PRINT_9(ha, "started\n");
2104 
2105         /* Verify Sub Code and set cnt to needed request size. */
2106         if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2107                 pld_size = sizeof (EXT_SCSI_PASSTHRU);
2108         } else if (cmd->SubCode == EXT_SC_SEND_FC_SCSI_PASSTHRU) {
2109                 pld_size = sizeof (EXT_FC_SCSI_PASSTHRU);
2110         } else {
2111                 EL(ha, "failed, invalid SubCode=%xh\n", cmd->SubCode);
2112                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
2113                 cmd->ResponseLen = 0;
2114                 return;
2115         }
2116 
2117         dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
2118         if (dma_mem == NULL) {
2119                 EL(ha, "failed, kmem_zalloc\n");
2120                 cmd->Status = EXT_STATUS_NO_MEMORY;
2121                 cmd->ResponseLen = 0;
2122                 return;
2123         }
2124         /*  Verify the size of and copy in the passthru request structure. */
2125         if (cmd->RequestLen != pld_size) {
2126                 /* Return error */
2127                 EL(ha, "failed, RequestLen != cnt, is=%xh, expected=%xh\n",
2128                     cmd->RequestLen, pld_size);
2129                 cmd->Status = EXT_STATUS_INVALID_PARAM;
2130                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2131                 cmd->ResponseLen = 0;
2132                 return;
2133         }
2134 
2135         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, &pt_req,
2136             pld_size, mode) != 0) {
2137                 EL(ha, "failed, ddi_copyin\n");
2138                 cmd->Status = EXT_STATUS_COPY_ERR;
2139                 cmd->ResponseLen = 0;
2140                 return;
2141         }
2142 
2143         /*
2144          * Find fc_port from SCSI PASSTHRU structure fill in the scsi_req
2145          * request data structure.
2146          */
2147         if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2148                 scsi_req.lun = sp_req->TargetAddr.Lun;
2149                 scsi_req.sense_length = sizeof (sp_req->SenseData);
2150                 scsi_req.cdbp = &sp_req->Cdb[0];
2151                 scsi_req.cdb_len = sp_req->CdbLength;
2152                 scsi_req.direction = sp_req->Direction;
2153                 usp_req = (EXT_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2154                 scsi_req.u_sense = &usp_req->SenseData[0];
2155                 cmd->DetailStatus = EXT_DSTATUS_TARGET;
2156 
2157                 qlnt = QLNT_PORT;
2158                 name = (uint8_t *)&sp_req->TargetAddr.Target;
2159                 QL_PRINT_9(ha, "SubCode=%xh, Target=%lld\n",
2160                     ha->instance, cmd->SubCode, sp_req->TargetAddr.Target);
2161                 tq = ql_find_port(ha, name, qlnt);
2162         } else {
2163                 /*
2164                  * Must be FC PASSTHRU, verified above.
2165                  */
2166                 if (fc_req->FCScsiAddr.DestType == EXT_DEF_DESTTYPE_WWPN) {
2167                         qlnt = QLNT_PORT;
2168                         name = &fc_req->FCScsiAddr.DestAddr.WWPN[0];
2169                         QL_PRINT_9(ha, "SubCode=%xh, "
2170                             "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2171                             ha->instance, cmd->SubCode, name[0], name[1],
2172                             name[2], name[3], name[4], name[5], name[6],
2173                             name[7]);
2174                         tq = ql_find_port(ha, name, qlnt);
2175                 } else if (fc_req->FCScsiAddr.DestType ==
2176                     EXT_DEF_DESTTYPE_WWNN) {
2177                         qlnt = QLNT_NODE;
2178                         name = &fc_req->FCScsiAddr.DestAddr.WWNN[0];
2179                         QL_PRINT_9(ha, "SubCode=%xh, "
2180                             "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2181                             ha->instance, cmd->SubCode, name[0], name[1],
2182                             name[2], name[3], name[4], name[5], name[6],
2183                             name[7]);
2184                         tq = ql_find_port(ha, name, qlnt);
2185                 } else if (fc_req->FCScsiAddr.DestType ==
2186                     EXT_DEF_DESTTYPE_PORTID) {
2187                         qlnt = QLNT_PID;
2188                         name = &fc_req->FCScsiAddr.DestAddr.Id[0];
2189                         QL_PRINT_9(ha, "SubCode=%xh, PID="
2190                             "%02x%02x%02x\n", cmd->SubCode,
2191                             name[0], name[1], name[2]);
2192                         tq = ql_find_port(ha, name, qlnt);
2193                 } else {
2194                         EL(ha, "failed, SubCode=%xh invalid DestType=%xh\n",
2195                             cmd->SubCode, fc_req->FCScsiAddr.DestType);
2196                         cmd->Status = EXT_STATUS_INVALID_PARAM;
2197                         cmd->ResponseLen = 0;
2198                         return;
2199                 }
2200                 scsi_req.lun = fc_req->FCScsiAddr.Lun;
2201                 scsi_req.sense_length = sizeof (fc_req->SenseData);
2202                 scsi_req.cdbp = &sp_req->Cdb[0];
2203                 scsi_req.cdb_len = sp_req->CdbLength;
2204                 ufc_req = (EXT_FC_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2205                 scsi_req.u_sense = &ufc_req->SenseData[0];
2206                 scsi_req.direction = fc_req->Direction;
2207         }
2208 
2209         if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
2210                 EL(ha, "failed, fc_port not found\n");
2211                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2212                 cmd->ResponseLen = 0;
2213                 return;
2214         }
2215 
2216         if (tq->flags & TQF_NEED_AUTHENTICATION) {
2217                 EL(ha, "target not available; loopid=%xh\n", tq->loop_id);
2218                 cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
2219                 cmd->ResponseLen = 0;
2220                 return;
2221         }
2222 
2223         /* Allocate command block. */
2224         if ((scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN ||
2225             scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) &&
2226             cmd->ResponseLen) {
2227                 pld_size = cmd->ResponseLen;
2228                 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_size);
2229                 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2230                 if (pkt == NULL) {
2231                         EL(ha, "failed, kmem_zalloc\n");
2232                         cmd->Status = EXT_STATUS_NO_MEMORY;
2233                         cmd->ResponseLen = 0;
2234                         return;
2235                 }
2236                 pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
2237 
2238                 /* Get DMA memory for the IOCB */
2239                 if (ql_get_dma_mem(ha, dma_mem, pld_size, LITTLE_ENDIAN_DMA,
2240                     QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
2241                         cmn_err(CE_WARN, "%srequest queue DMA memory "
2242                             "alloc failed", QL_NAME);
2243                         kmem_free(pkt, pkt_size);
2244                         cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
2245                         cmd->ResponseLen = 0;
2246                         return;
2247                 }
2248 
2249                 if (scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) {
2250                         scsi_req.direction = (uint8_t)
2251                             (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2252                             CF_RD : CF_DATA_IN | CF_STAG);
2253                 } else {
2254                         scsi_req.direction = (uint8_t)
2255                             (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2256                             CF_WR : CF_DATA_OUT | CF_STAG);
2257                         cmd->ResponseLen = 0;
2258 
2259                         /* Get command payload. */
2260                         if (ql_get_buffer_data(
2261                             (caddr_t)(uintptr_t)cmd->ResponseAdr,
2262                             pld, pld_size, mode) != pld_size) {
2263                                 EL(ha, "failed, get_buffer_data\n");
2264                                 cmd->Status = EXT_STATUS_COPY_ERR;
2265 
2266                                 kmem_free(pkt, pkt_size);
2267                                 ql_free_dma_resource(ha, dma_mem);
2268                                 kmem_free(dma_mem, sizeof (dma_mem_t));
2269                                 return;
2270                         }
2271 
2272                         /* Copy out going data to DMA buffer. */
2273                         ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
2274                             (uint8_t *)dma_mem->bp, pld_size,
2275                             DDI_DEV_AUTOINCR);
2276 
2277                         /* Sync DMA buffer. */
2278                         (void) ddi_dma_sync(dma_mem->dma_handle, 0,
2279                             dma_mem->size, DDI_DMA_SYNC_FORDEV);
2280                 }
2281         } else {
2282                 scsi_req.direction = (uint8_t)
2283                     (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ? 0 : CF_STAG);
2284                 cmd->ResponseLen = 0;
2285 
2286                 pkt_size = sizeof (ql_mbx_iocb_t);
2287                 pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2288                 if (pkt == NULL) {
2289                         EL(ha, "failed, kmem_zalloc-2\n");
2290                         cmd->Status = EXT_STATUS_NO_MEMORY;
2291                         return;
2292                 }
2293                 pld = NULL;
2294                 pld_size = 0;
2295         }
2296 
2297         /* retries = ha->port_down_retry_count; */
2298         retries = 1;
2299         cmd->Status = EXT_STATUS_OK;
2300         cmd->DetailStatus = EXT_DSTATUS_NOADNL_INFO;
2301 
2302         QL_PRINT_9(ha, "SCSI cdb\n");
2303         QL_DUMP_9(scsi_req.cdbp, 8, scsi_req.cdb_len);
2304 
2305         do {
2306                 if (DRIVER_SUSPENDED(ha)) {
2307                         sts.comp_status = CS_LOOP_DOWN_ABORT;
2308                         break;
2309                 }
2310 
2311                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
2312                         uint64_t                lun_addr = 0;
2313                         fcp_ent_addr_t          *fcp_ent_addr = 0;
2314 
2315                         pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
2316                         pkt->cmd24.entry_count = 1;
2317 
2318                         /* Set LUN number and address method */
2319                         lun_addr = ql_get_lun_addr(tq, scsi_req.lun);
2320                         fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
2321 
2322                         pkt->cmd24.fcp_lun[2] =
2323                             lobyte(fcp_ent_addr->ent_addr_0);
2324                         pkt->cmd24.fcp_lun[3] =
2325                             hibyte(fcp_ent_addr->ent_addr_0);
2326                         pkt->cmd24.fcp_lun[0] =
2327                             lobyte(fcp_ent_addr->ent_addr_1);
2328                         pkt->cmd24.fcp_lun[1] =
2329                             hibyte(fcp_ent_addr->ent_addr_1);
2330                         pkt->cmd24.fcp_lun[6] =
2331                             lobyte(fcp_ent_addr->ent_addr_2);
2332                         pkt->cmd24.fcp_lun[7] =
2333                             hibyte(fcp_ent_addr->ent_addr_2);
2334                         pkt->cmd24.fcp_lun[4] =
2335                             lobyte(fcp_ent_addr->ent_addr_3);
2336                         pkt->cmd24.fcp_lun[5] =
2337                             hibyte(fcp_ent_addr->ent_addr_3);
2338 
2339                         /* Set N_port handle */
2340                         pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
2341 
2342                         /* Set VP Index */
2343                         pkt->cmd24.vp_index = ha->vp_index;
2344 
2345                         /* Set target ID */
2346                         pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
2347                         pkt->cmd24.target_id[1] = tq->d_id.b.area;
2348                         pkt->cmd24.target_id[2] = tq->d_id.b.domain;
2349 
2350                         /* Set ISP command timeout. */
2351                         pkt->cmd24.timeout = (uint16_t)LE_16(15);
2352 
2353                         /* Load SCSI CDB */
2354                         ddi_rep_put8(ha->req_q[0]->req_ring.acc_handle,
2355                             scsi_req.cdbp, pkt->cmd24.scsi_cdb,
2356                             scsi_req.cdb_len, DDI_DEV_AUTOINCR);
2357                         for (cnt = 0; cnt < MAX_CMDSZ;
2358                             cnt = (uint16_t)(cnt + 4)) {
2359                                 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
2360                                     + cnt, 4);
2361                         }
2362 
2363                         /* Set tag queue control flags */
2364                         pkt->cmd24.task = TA_STAG;
2365 
2366                         if (pld_size) {
2367                                 /* Set transfer direction. */
2368                                 pkt->cmd24.control_flags = scsi_req.direction;
2369 
2370                                 /* Set data segment count. */
2371                                 pkt->cmd24.dseg_count = LE_16(1);
2372 
2373                                 /* Load total byte count. */
2374                                 pkt->cmd24.total_byte_count = LE_32(pld_size);
2375 
2376                                 /* Load data descriptor. */
2377                                 pkt->cmd24.dseg.address[0] = (uint32_t)
2378                                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
2379                                 pkt->cmd24.dseg.address[1] = (uint32_t)
2380                                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
2381                                 pkt->cmd24.dseg.length = LE_32(pld_size);
2382                         }
2383                 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
2384                         pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
2385                         pkt->cmd3.entry_count = 1;
2386                         if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2387                                 pkt->cmd3.target_l = LSB(tq->loop_id);
2388                                 pkt->cmd3.target_h = MSB(tq->loop_id);
2389                         } else {
2390                                 pkt->cmd3.target_h = LSB(tq->loop_id);
2391                         }
2392                         pkt->cmd3.lun_l = LSB(scsi_req.lun);
2393                         pkt->cmd3.lun_h = MSB(scsi_req.lun);
2394                         pkt->cmd3.control_flags_l = scsi_req.direction;
2395                         pkt->cmd3.timeout = LE_16(15);
2396                         for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2397                                 pkt->cmd3.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2398                         }
2399                         if (pld_size) {
2400                                 pkt->cmd3.dseg_count = LE_16(1);
2401                                 pkt->cmd3.byte_count = LE_32(pld_size);
2402                                 pkt->cmd3.dseg[0].address[0] = (uint32_t)
2403                                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
2404                                 pkt->cmd3.dseg[0].address[1] = (uint32_t)
2405                                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
2406                                 pkt->cmd3.dseg[0].length = LE_32(pld_size);
2407                         }
2408                 } else {
2409                         pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
2410                         pkt->cmd.entry_count = 1;
2411                         if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2412                                 pkt->cmd.target_l = LSB(tq->loop_id);
2413                                 pkt->cmd.target_h = MSB(tq->loop_id);
2414                         } else {
2415                                 pkt->cmd.target_h = LSB(tq->loop_id);
2416                         }
2417                         pkt->cmd.lun_l = LSB(scsi_req.lun);
2418                         pkt->cmd.lun_h = MSB(scsi_req.lun);
2419                         pkt->cmd.control_flags_l = scsi_req.direction;
2420                         pkt->cmd.timeout = LE_16(15);
2421                         for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2422                                 pkt->cmd.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2423                         }
2424                         if (pld_size) {
2425                                 pkt->cmd.dseg_count = LE_16(1);
2426                                 pkt->cmd.byte_count = LE_32(pld_size);
2427                                 pkt->cmd.dseg[0].address = (uint32_t)
2428                                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
2429                                 pkt->cmd.dseg[0].length = LE_32(pld_size);
2430                         }
2431                 }
2432                 /* Go issue command and wait for completion. */
2433                 QL_PRINT_9(ha, "request pkt\n");
2434                 QL_DUMP_9(pkt, 8, pkt_size);
2435 
2436                 status = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size);
2437 
2438                 if (pld_size) {
2439                         /* Sync in coming DMA buffer. */
2440                         (void) ddi_dma_sync(dma_mem->dma_handle, 0,
2441                             dma_mem->size, DDI_DMA_SYNC_FORKERNEL);
2442                         /* Copy in coming DMA data. */
2443                         ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
2444                             (uint8_t *)dma_mem->bp, pld_size,
2445                             DDI_DEV_AUTOINCR);
2446                 }
2447 
2448                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
2449                         pkt->sts24.entry_status = (uint8_t)
2450                             (pkt->sts24.entry_status & 0x3c);
2451                 } else {
2452                         pkt->sts.entry_status = (uint8_t)
2453                             (pkt->sts.entry_status & 0x7e);
2454                 }
2455 
2456                 if (status == QL_SUCCESS && pkt->sts.entry_status != 0) {
2457                         EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
2458                             pkt->sts.entry_status, tq->d_id.b24);
2459                         status = QL_FUNCTION_PARAMETER_ERROR;
2460                 }
2461 
2462                 sts.comp_status = (uint16_t)
2463                     (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2464                     LE_16(pkt->sts24.comp_status) :
2465                     LE_16(pkt->sts.comp_status));
2466 
2467                 /*
2468                  * We have verified about all the request that can be so far.
2469                  * Now we need to start verification of our ability to
2470                  * actually issue the CDB.
2471                  */
2472                 if (DRIVER_SUSPENDED(ha)) {
2473                         sts.comp_status = CS_LOOP_DOWN_ABORT;
2474                         break;
2475                 } else if (status == QL_SUCCESS &&
2476                     (sts.comp_status == CS_PORT_LOGGED_OUT ||
2477                     sts.comp_status == CS_PORT_UNAVAILABLE)) {
2478                         EL(ha, "login retry d_id=%xh\n", tq->d_id.b24);
2479                         if (tq->flags & TQF_FABRIC_DEVICE) {
2480                                 rval = ql_login_fport(ha, tq, tq->loop_id,
2481                                     LFF_NO_PLOGI, &mr);
2482                                 if (rval != QL_SUCCESS) {
2483                                         EL(ha, "failed, login_fport=%xh, "
2484                                             "d_id=%xh\n", rval, tq->d_id.b24);
2485                                 }
2486                         } else {
2487                                 rval = ql_login_lport(ha, tq, tq->loop_id,
2488                                     LLF_NONE);
2489                                 if (rval != QL_SUCCESS) {
2490                                         EL(ha, "failed, login_lport=%xh, "
2491                                             "d_id=%xh\n", rval, tq->d_id.b24);
2492                                 }
2493                         }
2494                 } else {
2495                         break;
2496                 }
2497 
2498                 bzero((caddr_t)pkt, sizeof (ql_mbx_iocb_t));
2499 
2500         } while (retries--);
2501 
2502         if (sts.comp_status == CS_LOOP_DOWN_ABORT) {
2503                 /* Cannot issue command now, maybe later */
2504                 EL(ha, "failed, suspended\n");
2505                 kmem_free(pkt, pkt_size);
2506                 ql_free_dma_resource(ha, dma_mem);
2507                 kmem_free(dma_mem, sizeof (dma_mem_t));
2508                 cmd->Status = EXT_STATUS_SUSPENDED;
2509                 cmd->ResponseLen = 0;
2510                 return;
2511         }
2512 
2513         if (status != QL_SUCCESS) {
2514                 /* Command error */
2515                 EL(ha, "failed, I/O\n");
2516                 kmem_free(pkt, pkt_size);
2517                 ql_free_dma_resource(ha, dma_mem);
2518                 kmem_free(dma_mem, sizeof (dma_mem_t));
2519                 cmd->Status = EXT_STATUS_ERR;
2520                 cmd->DetailStatus = status;
2521                 cmd->ResponseLen = 0;
2522                 return;
2523         }
2524 
2525         /* Setup status. */
2526         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
2527                 sts.scsi_status_l = pkt->sts24.scsi_status_l;
2528                 sts.scsi_status_h = pkt->sts24.scsi_status_h;
2529 
2530                 /* Setup residuals. */
2531                 sts.residual_length = LE_32(pkt->sts24.residual_length);
2532 
2533                 /* Setup state flags. */
2534                 sts.state_flags_l = pkt->sts24.state_flags_l;
2535                 sts.state_flags_h = pkt->sts24.state_flags_h;
2536                 if (pld_size && sts.comp_status != CS_DATA_UNDERRUN) {
2537                         sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2538                             SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2539                             SF_XFERRED_DATA | SF_GOT_STATUS);
2540                 } else {
2541                         sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2542                             SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2543                             SF_GOT_STATUS);
2544                 }
2545                 if (scsi_req.direction & CF_WR) {
2546                         sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2547                             SF_DATA_OUT);
2548                 } else if (scsi_req.direction & CF_RD) {
2549                         sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2550                             SF_DATA_IN);
2551                 }
2552                 sts.state_flags_l = (uint8_t)(sts.state_flags_l | SF_SIMPLE_Q);
2553 
2554                 /* Setup FCP response info. */
2555                 sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2556                     LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
2557                 sts.rsp_info = &pkt->sts24.rsp_sense_data[0];
2558                 for (cnt = 0; cnt < sts.rsp_info_length;
2559                     cnt = (uint16_t)(cnt + 4)) {
2560                         ql_chg_endian(sts.rsp_info + cnt, 4);
2561                 }
2562 
2563                 /* Setup sense data. */
2564                 if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2565                         sts.req_sense_length =
2566                             LE_32(pkt->sts24.fcp_sense_length);
2567                         sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2568                             SF_ARQ_DONE);
2569                 } else {
2570                         sts.req_sense_length = 0;
2571                 }
2572                 sts.req_sense_data =
2573                     &pkt->sts24.rsp_sense_data[sts.rsp_info_length];
2574                 cnt2 = (uint16_t)(((uintptr_t)pkt + sizeof (sts_24xx_entry_t)) -
2575                     (uintptr_t)sts.req_sense_data);
2576                 for (cnt = 0; cnt < cnt2; cnt = (uint16_t)(cnt + 4)) {
2577                         ql_chg_endian(sts.req_sense_data + cnt, 4);
2578                 }
2579         } else {
2580                 sts.scsi_status_l = pkt->sts.scsi_status_l;
2581                 sts.scsi_status_h = pkt->sts.scsi_status_h;
2582 
2583                 /* Setup residuals. */
2584                 sts.residual_length = LE_32(pkt->sts.residual_length);
2585 
2586                 /* Setup state flags. */
2587                 sts.state_flags_l = pkt->sts.state_flags_l;
2588                 sts.state_flags_h = pkt->sts.state_flags_h;
2589 
2590                 /* Setup FCP response info. */
2591                 sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2592                     LE_16(pkt->sts.rsp_info_length) : 0;
2593                 sts.rsp_info = &pkt->sts.rsp_info[0];
2594 
2595                 /* Setup sense data. */
2596                 sts.req_sense_length = sts.scsi_status_h & FCP_SNS_LEN_VALID ?
2597                     LE_16(pkt->sts.req_sense_length) : 0;
2598                 sts.req_sense_data = &pkt->sts.req_sense_data[0];
2599         }
2600 
2601         QL_PRINT_9(ha, "response pkt\n");
2602         QL_DUMP_9(&pkt->sts, 8, sizeof (sts_entry_t));
2603 
2604         switch (sts.comp_status) {
2605         case CS_INCOMPLETE:
2606         case CS_ABORTED:
2607         case CS_DEVICE_UNAVAILABLE:
2608         case CS_PORT_UNAVAILABLE:
2609         case CS_PORT_LOGGED_OUT:
2610         case CS_PORT_CONFIG_CHG:
2611         case CS_PORT_BUSY:
2612         case CS_LOOP_DOWN_ABORT:
2613                 cmd->Status = EXT_STATUS_BUSY;
2614                 break;
2615         case CS_RESET:
2616         case CS_QUEUE_FULL:
2617                 cmd->Status = EXT_STATUS_ERR;
2618                 break;
2619         case CS_TIMEOUT:
2620                 cmd->Status = EXT_STATUS_ERR;
2621                 break;
2622         case CS_DATA_OVERRUN:
2623                 cmd->Status = EXT_STATUS_DATA_OVERRUN;
2624                 break;
2625         case CS_DATA_UNDERRUN:
2626                 cmd->Status = EXT_STATUS_DATA_UNDERRUN;
2627                 break;
2628         }
2629 
2630         /*
2631          * If non data transfer commands fix tranfer counts.
2632          */
2633         if (scsi_req.cdbp[0] == SCMD_TEST_UNIT_READY ||
2634             scsi_req.cdbp[0] == SCMD_REZERO_UNIT ||
2635             scsi_req.cdbp[0] == SCMD_SEEK ||
2636             scsi_req.cdbp[0] == SCMD_SEEK_G1 ||
2637             scsi_req.cdbp[0] == SCMD_RESERVE ||
2638             scsi_req.cdbp[0] == SCMD_RELEASE ||
2639             scsi_req.cdbp[0] == SCMD_START_STOP ||
2640             scsi_req.cdbp[0] == SCMD_DOORLOCK ||
2641             scsi_req.cdbp[0] == SCMD_VERIFY ||
2642             scsi_req.cdbp[0] == SCMD_WRITE_FILE_MARK ||
2643             scsi_req.cdbp[0] == SCMD_VERIFY_G0 ||
2644             scsi_req.cdbp[0] == SCMD_SPACE ||
2645             scsi_req.cdbp[0] == SCMD_ERASE ||
2646             (scsi_req.cdbp[0] == SCMD_FORMAT &&
2647             (scsi_req.cdbp[1] & FPB_DATA) == 0)) {
2648                 /*
2649                  * Non data transfer command, clear sts_entry residual
2650                  * length.
2651                  */
2652                 sts.residual_length = 0;
2653                 cmd->ResponseLen = 0;
2654                 if (sts.comp_status == CS_DATA_UNDERRUN) {
2655                         sts.comp_status = CS_COMPLETE;
2656                         cmd->Status = EXT_STATUS_OK;
2657                 }
2658         } else {
2659                 cmd->ResponseLen = pld_size;
2660         }
2661 
2662         /* Correct ISP completion status */
2663         if (sts.comp_status == CS_COMPLETE && sts.scsi_status_l == 0 &&
2664             (sts.scsi_status_h & FCP_RSP_MASK) == 0) {
2665                 QL_PRINT_9(ha, "Correct completion\n",
2666                     ha->instance);
2667                 scsi_req.resid = 0;
2668         } else if (sts.comp_status == CS_DATA_UNDERRUN) {
2669                 QL_PRINT_9(ha, "Correct UNDERRUN\n",
2670                     ha->instance);
2671                 scsi_req.resid = sts.residual_length;
2672                 if (sts.scsi_status_h & FCP_RESID_UNDER) {
2673                         cmd->Status = (uint32_t)EXT_STATUS_OK;
2674 
2675                         cmd->ResponseLen = (uint32_t)
2676                             (pld_size - scsi_req.resid);
2677                 } else {
2678                         EL(ha, "failed, Transfer ERROR\n");
2679                         cmd->Status = EXT_STATUS_ERR;
2680                         cmd->ResponseLen = 0;
2681                 }
2682         } else {
2683                 QL_PRINT_9(ha, "error d_id=%xh, comp_status=%xh, "
2684                     "scsi_status_h=%xh, scsi_status_l=%xh\n",
2685                     tq->d_id.b24, sts.comp_status, sts.scsi_status_h,
2686                     sts.scsi_status_l);
2687 
2688                 scsi_req.resid = pld_size;
2689                 /*
2690                  * Handle residual count on SCSI check
2691                  * condition.
2692                  *
2693                  * - If Residual Under / Over is set, use the
2694                  *   Residual Transfer Length field in IOCB.
2695                  * - If Residual Under / Over is not set, and
2696                  *   Transferred Data bit is set in State Flags
2697                  *   field of IOCB, report residual value of 0
2698                  *   (you may want to do this for tape
2699                  *   Write-type commands only). This takes care
2700                  *   of logical end of tape problem and does
2701                  *   not break Unit Attention.
2702                  * - If Residual Under / Over is not set, and
2703                  *   Transferred Data bit is not set in State
2704                  *   Flags, report residual value equal to
2705                  *   original data transfer length.
2706                  */
2707                 if (sts.scsi_status_l & STATUS_CHECK) {
2708                         cmd->Status = EXT_STATUS_SCSI_STATUS;
2709                         cmd->DetailStatus = sts.scsi_status_l;
2710                         if (sts.scsi_status_h &
2711                             (FCP_RESID_OVER | FCP_RESID_UNDER)) {
2712                                 scsi_req.resid = sts.residual_length;
2713                         } else if (sts.state_flags_h &
2714                             STATE_XFERRED_DATA) {
2715                                 scsi_req.resid = 0;
2716                         }
2717                 }
2718         }
2719 
2720         if (sts.scsi_status_l & STATUS_CHECK &&
2721             sts.scsi_status_h & FCP_SNS_LEN_VALID &&
2722             sts.req_sense_length) {
2723                 /*
2724                  * Check condition with vaild sense data flag set and sense
2725                  * length != 0
2726                  */
2727                 if (sts.req_sense_length > scsi_req.sense_length) {
2728                         sense_sz = scsi_req.sense_length;
2729                 } else {
2730                         sense_sz = sts.req_sense_length;
2731                 }
2732 
2733                 EL(ha, "failed, Check Condition Status, d_id=%xh\n",
2734                     tq->d_id.b24);
2735                 QL_DUMP_2(sts.req_sense_data, 8, sts.req_sense_length);
2736 
2737                 if (ddi_copyout(sts.req_sense_data, scsi_req.u_sense,
2738                     (size_t)sense_sz, mode) != 0) {
2739                         EL(ha, "failed, request sense ddi_copyout\n");
2740                 }
2741 
2742                 cmd->Status = EXT_STATUS_SCSI_STATUS;
2743                 cmd->DetailStatus = sts.scsi_status_l;
2744         }
2745 
2746         /* Copy response payload from DMA buffer to application. */
2747         if (scsi_req.direction & (CF_RD | CF_DATA_IN) &&
2748             cmd->ResponseLen != 0) {
2749                 QL_PRINT_9(ha, "Data Return resid=%lu, "
2750                     "byte_count=%u, ResponseLen=%xh\n",
2751                     scsi_req.resid, pld_size, cmd->ResponseLen);
2752                 QL_DUMP_9(pld, 8, cmd->ResponseLen);
2753 
2754                 /* Send response payload. */
2755                 if (ql_send_buffer_data(pld,
2756                     (caddr_t)(uintptr_t)cmd->ResponseAdr,
2757                     cmd->ResponseLen, mode) != cmd->ResponseLen) {
2758                         EL(ha, "failed, send_buffer_data\n");
2759                         cmd->Status = EXT_STATUS_COPY_ERR;
2760                         cmd->ResponseLen = 0;
2761                 }
2762         }
2763 
2764         if (cmd->Status != EXT_STATUS_OK) {
2765                 EL(ha, "failed, cmd->Status=%xh, comp_status=%xh, "
2766                     "d_id=%xh\n", cmd->Status, sts.comp_status, tq->d_id.b24);
2767         } else {
2768                 /*EMPTY*/
2769                 QL_PRINT_9(ha, "done, ResponseLen=%d\n",
2770                     ha->instance, cmd->ResponseLen);
2771         }
2772 
2773         kmem_free(pkt, pkt_size);
2774         ql_free_dma_resource(ha, dma_mem);
2775         kmem_free(dma_mem, sizeof (dma_mem_t));
2776 }
2777 
2778 /*
2779  * ql_wwpn_to_scsiaddr
2780  *
2781  * Input:
2782  *      ha:     adapter state pointer.
2783  *      cmd:    EXT_IOCTL cmd struct pointer.
2784  *      mode:   flags.
2785  *
2786  * Context:
2787  *      Kernel context.
2788  */
2789 static void
2790 ql_wwpn_to_scsiaddr(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2791 {
2792         int             status;
2793         uint8_t         wwpn[EXT_DEF_WWN_NAME_SIZE];
2794         EXT_SCSI_ADDR   *tmp_addr;
2795         ql_tgt_t        *tq;
2796 
2797         QL_PRINT_9(ha, "started\n");
2798 
2799         if (cmd->RequestLen != EXT_DEF_WWN_NAME_SIZE) {
2800                 /* Return error */
2801                 EL(ha, "incorrect RequestLen\n");
2802                 cmd->Status = EXT_STATUS_INVALID_PARAM;
2803                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2804                 return;
2805         }
2806 
2807         status = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, wwpn,
2808             cmd->RequestLen, mode);
2809 
2810         if (status != 0) {
2811                 cmd->Status = EXT_STATUS_COPY_ERR;
2812                 EL(ha, "failed, ddi_copyin\n");
2813                 return;
2814         }
2815 
2816         tq = ql_find_port(ha, wwpn, QLNT_PORT);
2817 
2818         if (tq == NULL || tq->flags & TQF_INITIATOR_DEVICE) {
2819                 /* no matching device */
2820                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2821                 EL(ha, "failed, device not found\n");
2822                 return;
2823         }
2824 
2825         /* Copy out the IDs found.  For now we can only return target ID. */
2826         tmp_addr = (EXT_SCSI_ADDR *)(uintptr_t)cmd->ResponseAdr;
2827 
2828         status = ddi_copyout((void *)wwpn, (void *)&tmp_addr->Target, 8, mode);
2829 
2830         if (status != 0) {
2831                 cmd->Status = EXT_STATUS_COPY_ERR;
2832                 EL(ha, "failed, ddi_copyout\n");
2833         } else {
2834                 cmd->Status = EXT_STATUS_OK;
2835                 QL_PRINT_9(ha, "done\n");
2836         }
2837 }
2838 
2839 /*
2840  * ql_host_idx
2841  *      Gets host order index.
2842  *
2843  * Input:
2844  *      ha:     adapter state pointer.
2845  *      cmd:    EXT_IOCTL cmd struct pointer.
2846  *      mode:   flags.
2847  *
2848  * Returns:
2849  *      None, request status indicated in cmd->Status.
2850  *
2851  * Context:
2852  *      Kernel context.
2853  */
2854 static void
2855 ql_host_idx(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2856 {
2857         uint16_t        idx;
2858 
2859         QL_PRINT_9(ha, "started\n");
2860 
2861         if (cmd->ResponseLen < sizeof (uint16_t)) {
2862                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2863                 cmd->DetailStatus = sizeof (uint16_t);
2864                 EL(ha, "failed, ResponseLen < Len=%xh\n", cmd->ResponseLen);
2865                 cmd->ResponseLen = 0;
2866                 return;
2867         }
2868 
2869         idx = (uint16_t)ha->instance;
2870 
2871         if (ddi_copyout((void *)&idx, (void *)(uintptr_t)(cmd->ResponseAdr),
2872             sizeof (uint16_t), mode) != 0) {
2873                 cmd->Status = EXT_STATUS_COPY_ERR;
2874                 cmd->ResponseLen = 0;
2875                 EL(ha, "failed, ddi_copyout\n");
2876         } else {
2877                 cmd->ResponseLen = sizeof (uint16_t);
2878                 QL_PRINT_9(ha, "done\n");
2879         }
2880 }
2881 
2882 /*
2883  * ql_host_drvname
2884  *      Gets host driver name
2885  *
2886  * Input:
2887  *      ha:     adapter state pointer.
2888  *      cmd:    EXT_IOCTL cmd struct pointer.
2889  *      mode:   flags.
2890  *
2891  * Returns:
2892  *      None, request status indicated in cmd->Status.
2893  *
2894  * Context:
2895  *      Kernel context.
2896  */
2897 static void
2898 ql_host_drvname(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2899 {
2900 
2901         char            drvname[] = QL_NAME;
2902         uint32_t        qlnamelen;
2903 
2904         QL_PRINT_9(ha, "started\n");
2905 
2906         qlnamelen = (uint32_t)(strlen(QL_NAME) + 1);
2907 
2908         if (cmd->ResponseLen < qlnamelen) {
2909                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2910                 cmd->DetailStatus = qlnamelen;
2911                 EL(ha, "failed, ResponseLen: %xh, needed: %xh\n",
2912                     cmd->ResponseLen, qlnamelen);
2913                 cmd->ResponseLen = 0;
2914                 return;
2915         }
2916 
2917         if (ddi_copyout((void *)&drvname,
2918             (void *)(uintptr_t)(cmd->ResponseAdr),
2919             qlnamelen, mode) != 0) {
2920                 cmd->Status = EXT_STATUS_COPY_ERR;
2921                 cmd->ResponseLen = 0;
2922                 EL(ha, "failed, ddi_copyout\n");
2923         } else {
2924                 cmd->ResponseLen = qlnamelen - 1;
2925         }
2926 
2927         QL_PRINT_9(ha, "done\n");
2928 }
2929 
2930 /*
2931  * ql_read_nvram
2932  *      Get NVRAM contents.
2933  *
2934  * Input:
2935  *      ha:     adapter state pointer.
2936  *      cmd:    EXT_IOCTL cmd struct pointer.
2937  *      mode:   flags.
2938  *
2939  * Returns:
2940  *      None, request status indicated in cmd->Status.
2941  *
2942  * Context:
2943  *      Kernel context.
2944  */
2945 static void
2946 ql_read_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2947 {
2948 
2949         QL_PRINT_9(ha, "started\n");
2950 
2951         if (cmd->ResponseLen < ha->nvram_cache->size) {
2952                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2953                 cmd->DetailStatus = ha->nvram_cache->size;
2954                 EL(ha, "failed, ResponseLen != NVRAM, Len=%xh\n",
2955                     cmd->ResponseLen);
2956                 cmd->ResponseLen = 0;
2957                 return;
2958         }
2959 
2960         /* Get NVRAM data. */
2961         if (ql_nv_util_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
2962             mode) != 0) {
2963                 cmd->Status = EXT_STATUS_COPY_ERR;
2964                 cmd->ResponseLen = 0;
2965                 EL(ha, "failed, copy error\n");
2966         } else {
2967                 cmd->ResponseLen = ha->nvram_cache->size;
2968                 QL_PRINT_9(ha, "done\n");
2969         }
2970 }
2971 
2972 /*
2973  * ql_write_nvram
2974  *      Loads NVRAM contents.
2975  *
2976  * Input:
2977  *      ha:     adapter state pointer.
2978  *      cmd:    EXT_IOCTL cmd struct pointer.
2979  *      mode:   flags.
2980  *
2981  * Returns:
2982  *      None, request status indicated in cmd->Status.
2983  *
2984  * Context:
2985  *      Kernel context.
2986  */
2987 static void
2988 ql_write_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2989 {
2990 
2991         QL_PRINT_9(ha, "started\n");
2992 
2993         if (cmd->RequestLen < ha->nvram_cache->size) {
2994                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2995                 cmd->DetailStatus = ha->nvram_cache->size;
2996                 EL(ha, "failed, RequestLen != NVRAM, Len=%xh\n",
2997                     cmd->RequestLen);
2998                 return;
2999         }
3000 
3001         /* Load NVRAM data. */
3002         if (ql_nv_util_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
3003             mode) != 0) {
3004                 cmd->Status = EXT_STATUS_COPY_ERR;
3005                 EL(ha, "failed, copy error\n");
3006         } else {
3007                 /*EMPTY*/
3008                 QL_PRINT_9(ha, "done\n");
3009         }
3010 }
3011 
3012 /*
3013  * ql_write_vpd
3014  *      Loads VPD contents.
3015  *
3016  * Input:
3017  *      ha:     adapter state pointer.
3018  *      cmd:    EXT_IOCTL cmd struct pointer.
3019  *      mode:   flags.
3020  *
3021  * Returns:
3022  *      None, request status indicated in cmd->Status.
3023  *
3024  * Context:
3025  *      Kernel context.
3026  */
3027 static void
3028 ql_write_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3029 {
3030         QL_PRINT_9(ha, "started\n");
3031 
3032         int32_t         rval = 0;
3033 
3034         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3035                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
3036                 EL(ha, "failed, invalid request for HBA\n");
3037                 return;
3038         }
3039 
3040         if (cmd->RequestLen < QL_24XX_VPD_SIZE) {
3041                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3042                 cmd->DetailStatus = QL_24XX_VPD_SIZE;
3043                 EL(ha, "failed, RequestLen != VPD len, len passed=%xh\n",
3044                     cmd->RequestLen);
3045                 return;
3046         }
3047 
3048         /* Load VPD data. */
3049         if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
3050             mode)) != 0) {
3051                 cmd->Status = EXT_STATUS_COPY_ERR;
3052                 cmd->DetailStatus = rval;
3053                 EL(ha, "failed, errno=%x\n", rval);
3054         } else {
3055                 /*EMPTY*/
3056                 QL_PRINT_9(ha, "done\n");
3057         }
3058 }
3059 
3060 /*
3061  * ql_read_vpd
3062  *      Dumps VPD contents.
3063  *
3064  * Input:
3065  *      ha:     adapter state pointer.
3066  *      cmd:    EXT_IOCTL cmd struct pointer.
3067  *      mode:   flags.
3068  *
3069  * Returns:
3070  *      None, request status indicated in cmd->Status.
3071  *
3072  * Context:
3073  *      Kernel context.
3074  */
3075 static void
3076 ql_read_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3077 {
3078         QL_PRINT_9(ha, "started\n");
3079 
3080         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3081                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
3082                 EL(ha, "failed, invalid request for HBA\n");
3083                 return;
3084         }
3085 
3086         if (cmd->ResponseLen < QL_24XX_VPD_SIZE) {
3087                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3088                 cmd->DetailStatus = QL_24XX_VPD_SIZE;
3089                 EL(ha, "failed, ResponseLen < VPD len, len passed=%xh\n",
3090                     cmd->ResponseLen);
3091                 return;
3092         }
3093 
3094         /* Dump VPD data. */
3095         if ((ql_vpd_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
3096             mode)) != 0) {
3097                 cmd->Status = EXT_STATUS_COPY_ERR;
3098                 EL(ha, "failed,\n");
3099         } else {
3100                 /*EMPTY*/
3101                 QL_PRINT_9(ha, "done\n");
3102         }
3103 }
3104 
3105 /*
3106  * ql_get_fcache
3107  *      Dumps flash cache contents.
3108  *
3109  * Input:
3110  *      ha:     adapter state pointer.
3111  *      cmd:    EXT_IOCTL cmd struct pointer.
3112  *      mode:   flags.
3113  *
3114  * Returns:
3115  *      None, request status indicated in cmd->Status.
3116  *
3117  * Context:
3118  *      Kernel context.
3119  */
3120 static void
3121 ql_get_fcache(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3122 {
3123         uint32_t        bsize, boff, types, cpsize, hsize;
3124         ql_fcache_t     *fptr;
3125 
3126         QL_PRINT_9(ha, "started\n");
3127 
3128         if (ha->fcache == NULL) {
3129                 cmd->Status = EXT_STATUS_ERR;
3130                 EL(ha, "failed, adapter fcache not setup\n");
3131                 return;
3132         }
3133 
3134         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3135                 bsize = 100;
3136         } else {
3137                 bsize = 400;
3138         }
3139 
3140         if (cmd->ResponseLen < bsize) {
3141                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3142                 cmd->DetailStatus = bsize;
3143                 EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3144                     bsize, cmd->ResponseLen);
3145                 return;
3146         }
3147 
3148         boff = 0;
3149         bsize = 0;
3150         fptr = ha->fcache;
3151 
3152         /*
3153          * For backwards compatibility, get one of each image type
3154          */
3155         types = (FTYPE_BIOS | FTYPE_FCODE | FTYPE_EFI);
3156         while ((fptr != NULL) && (fptr->buf != NULL) && (types != 0)) {
3157                 /* Get the next image */
3158                 if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) {
3159 
3160                         cpsize = (fptr->buflen < 100 ? fptr->buflen : 100);
3161 
3162                         if (ddi_copyout(fptr->buf,
3163                             (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3164                             cpsize, mode) != 0) {
3165                                 EL(ha, "ddicopy failed, done\n");
3166                                 cmd->Status = EXT_STATUS_COPY_ERR;
3167                                 cmd->DetailStatus = 0;
3168                                 return;
3169                         }
3170                         boff += 100;
3171                         bsize += cpsize;
3172                         types &= ~(fptr->type);
3173                 }
3174         }
3175 
3176         /*
3177          * Get the firmware image -- it needs to be last in the
3178          * buffer at offset 300 for backwards compatibility. Also for
3179          * backwards compatibility, the pci header is stripped off.
3180          */
3181         if ((fptr = ql_get_fbuf(ha->fcache, FTYPE_FW)) != NULL) {
3182 
3183                 hsize = sizeof (pci_header_t) + sizeof (pci_data_t);
3184                 if (hsize > fptr->buflen) {
3185                         EL(ha, "header size (%xh) exceeds buflen (%xh)\n",
3186                             hsize, fptr->buflen);
3187                         cmd->Status = EXT_STATUS_COPY_ERR;
3188                         cmd->DetailStatus = 0;
3189                         return;
3190                 }
3191 
3192                 cpsize = ((fptr->buflen - hsize) < 100 ?
3193                     fptr->buflen - hsize : 100);
3194 
3195                 if (ddi_copyout(fptr->buf + hsize,
3196                     (void *)(uintptr_t)(cmd->ResponseAdr + 300),
3197                     cpsize, mode) != 0) {
3198                         EL(ha, "fw ddicopy failed, done\n");
3199                         cmd->Status = EXT_STATUS_COPY_ERR;
3200                         cmd->DetailStatus = 0;
3201                         return;
3202                 }
3203                 bsize += 100;
3204         }
3205 
3206         cmd->Status = EXT_STATUS_OK;
3207         cmd->DetailStatus = bsize;
3208 
3209         QL_PRINT_9(ha, "done\n");
3210 }
3211 
3212 /*
3213  * ql_get_fcache_ex
3214  *      Dumps flash cache contents.
3215  *
3216  * Input:
3217  *      ha:     adapter state pointer.
3218  *      cmd:    EXT_IOCTL cmd struct pointer.
3219  *      mode:   flags.
3220  *
3221  * Returns:
3222  *      None, request status indicated in cmd->Status.
3223  *
3224  * Context:
3225  *      Kernel context.
3226  */
3227 static void
3228 ql_get_fcache_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3229 {
3230         uint32_t        bsize = 0;
3231         uint32_t        boff = 0;
3232         ql_fcache_t     *fptr;
3233 
3234         QL_PRINT_9(ha, "started\n");
3235 
3236         if (ha->fcache == NULL) {
3237                 cmd->Status = EXT_STATUS_ERR;
3238                 EL(ha, "failed, adapter fcache not setup\n");
3239                 return;
3240         }
3241 
3242         /* Make sure user passed enough buffer space */
3243         for (fptr = ha->fcache; fptr != NULL; fptr = fptr->next) {
3244                 bsize += FBUFSIZE;
3245         }
3246 
3247         if (cmd->ResponseLen < bsize) {
3248                 if (cmd->ResponseLen != 0) {
3249                         EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3250                             bsize, cmd->ResponseLen);
3251                 }
3252                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3253                 cmd->DetailStatus = bsize;
3254                 return;
3255         }
3256 
3257         boff = 0;
3258         fptr = ha->fcache;
3259         while ((fptr != NULL) && (fptr->buf != NULL)) {
3260                 /* Get the next image */
3261                 if (ddi_copyout(fptr->buf,
3262                     (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3263                     (fptr->buflen < FBUFSIZE ? fptr->buflen : FBUFSIZE),
3264                     mode) != 0) {
3265                         EL(ha, "failed, ddicopy at %xh, done\n", boff);
3266                         cmd->Status = EXT_STATUS_COPY_ERR;
3267                         cmd->DetailStatus = 0;
3268                         return;
3269                 }
3270                 boff += FBUFSIZE;
3271                 fptr = fptr->next;
3272         }
3273 
3274         cmd->Status = EXT_STATUS_OK;
3275         cmd->DetailStatus = bsize;
3276 
3277         QL_PRINT_9(ha, "done\n");
3278 }
3279 
3280 /*
3281  * ql_read_flash
3282  *      Get flash contents.
3283  *
3284  * Input:
3285  *      ha:     adapter state pointer.
3286  *      cmd:    EXT_IOCTL cmd struct pointer.
3287  *      mode:   flags.
3288  *
3289  * Returns:
3290  *      None, request status indicated in cmd->Status.
3291  *
3292  * Context:
3293  *      Kernel context.
3294  */
3295 static void
3296 ql_read_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3297 {
3298         ql_xioctl_t     *xp = ha->xioctl;
3299 
3300         QL_PRINT_9(ha, "started\n");
3301 
3302         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) &&
3303             ql_stall_driver(ha, 0) != QL_SUCCESS) {
3304                 EL(ha, "ql_stall_driver failed\n");
3305                 ql_restart_driver(ha);
3306                 cmd->Status = EXT_STATUS_BUSY;
3307                 cmd->DetailStatus = xp->fdesc.flash_size;
3308                 cmd->ResponseLen = 0;
3309                 return;
3310         }
3311 
3312         if (ql_setup_fcache(ha) != QL_SUCCESS) {
3313                 cmd->Status = EXT_STATUS_ERR;
3314                 cmd->DetailStatus = xp->fdesc.flash_size;
3315                 EL(ha, "failed, ResponseLen=%xh, flash size=%xh\n",
3316                     cmd->ResponseLen, xp->fdesc.flash_size);
3317                 cmd->ResponseLen = 0;
3318         } else {
3319                 /* adjust read size to flash size */
3320                 if (cmd->ResponseLen > xp->fdesc.flash_size) {
3321                         EL(ha, "adjusting req=%xh, max=%xh\n",
3322                             cmd->ResponseLen, xp->fdesc.flash_size);
3323                         cmd->ResponseLen = xp->fdesc.flash_size;
3324                 }
3325 
3326                 /* Get flash data. */
3327                 if (ql_flash_fcode_dump(ha,
3328                     (void *)(uintptr_t)(cmd->ResponseAdr),
3329                     (size_t)(cmd->ResponseLen), 0, mode) != 0) {
3330                         cmd->Status = EXT_STATUS_COPY_ERR;
3331                         cmd->ResponseLen = 0;
3332                         EL(ha, "failed,\n");
3333                 }
3334         }
3335 
3336         /* Resume I/O */
3337         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3338                 EL(ha, "isp_abort_needed for restart\n");
3339                 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
3340                     DRIVER_STALL);
3341         }
3342 
3343         QL_PRINT_9(ha, "done\n");
3344 }
3345 
3346 /*
3347  * ql_write_flash
3348  *      Loads flash contents.
3349  *
3350  * Input:
3351  *      ha:     adapter state pointer.
3352  *      cmd:    EXT_IOCTL cmd struct pointer.
3353  *      mode:   flags.
3354  *
3355  * Returns:
3356  *      None, request status indicated in cmd->Status.
3357  *
3358  * Context:
3359  *      Kernel context.
3360  */
3361 static void
3362 ql_write_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3363 {
3364         ql_xioctl_t     *xp = ha->xioctl;
3365 
3366         QL_PRINT_9(ha, "started\n");
3367 
3368         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) &&
3369             ql_stall_driver(ha, 0) != QL_SUCCESS) {
3370                 EL(ha, "ql_stall_driver failed\n");
3371                 ql_restart_driver(ha);
3372                 cmd->Status = EXT_STATUS_BUSY;
3373                 cmd->DetailStatus = xp->fdesc.flash_size;
3374                 cmd->ResponseLen = 0;
3375                 return;
3376         }
3377 
3378         if (ql_setup_fcache(ha) != QL_SUCCESS) {
3379                 cmd->Status = EXT_STATUS_ERR;
3380                 cmd->DetailStatus = xp->fdesc.flash_size;
3381                 EL(ha, "failed, RequestLen=%xh, size=%xh\n",
3382                     cmd->RequestLen, xp->fdesc.flash_size);
3383                 cmd->ResponseLen = 0;
3384         } else {
3385                 /* Load flash data. */
3386                 if (cmd->RequestLen > xp->fdesc.flash_size) {
3387                         cmd->Status = EXT_STATUS_ERR;
3388                         cmd->DetailStatus = xp->fdesc.flash_size;
3389                         EL(ha, "failed, RequestLen=%xh, flash size=%xh\n",
3390                             cmd->RequestLen, xp->fdesc.flash_size);
3391                 } else if (ql_flash_fcode_load(ha,
3392                     (void *)(uintptr_t)(cmd->RequestAdr),
3393                     (size_t)(cmd->RequestLen), mode) != 0) {
3394                         cmd->Status = EXT_STATUS_COPY_ERR;
3395                         EL(ha, "failed,\n");
3396                 }
3397         }
3398 
3399         /* Resume I/O */
3400         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3401                 EL(ha, "isp_abort_needed for restart\n");
3402                 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
3403                     DRIVER_STALL);
3404         }
3405 
3406         QL_PRINT_9(ha, "done\n");
3407 }
3408 
3409 /*
3410  * ql_diagnostic_loopback
3411  *      Performs EXT_CC_LOOPBACK Command
3412  *
3413  * Input:
3414  *      ha:     adapter state pointer.
3415  *      cmd:    Local EXT_IOCTL cmd struct pointer.
3416  *      mode:   flags.
3417  *
3418  * Returns:
3419  *      None, request status indicated in cmd->Status.
3420  *
3421  * Context:
3422  *      Kernel context.
3423  */
3424 static void
3425 ql_diagnostic_loopback(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3426 {
3427         EXT_LOOPBACK_REQ        plbreq;
3428         EXT_LOOPBACK_RSP        plbrsp;
3429         ql_mbx_data_t           mr;
3430         uint32_t                rval, timer, bpsize;
3431         caddr_t                 bp, pld;
3432         uint16_t                opt;
3433         boolean_t               loop_up;
3434 
3435         QL_PRINT_9(ha, "started\n");
3436 
3437         /* Get loop back request. */
3438         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
3439             (void *)&plbreq, sizeof (EXT_LOOPBACK_REQ), mode) != 0) {
3440                 EL(ha, "failed, ddi_copyin\n");
3441                 cmd->Status = EXT_STATUS_COPY_ERR;
3442                 cmd->ResponseLen = 0;
3443                 return;
3444         }
3445 
3446         /* Check transfer length fits in buffer. */
3447         if (plbreq.BufferLength < plbreq.TransferCount) {
3448                 EL(ha, "failed, BufferLength=%d, xfercnt=%d\n",
3449 
3450                     plbreq.BufferLength, plbreq.TransferCount);
3451                 cmd->Status = EXT_STATUS_INVALID_PARAM;
3452                 cmd->ResponseLen = 0;
3453                 return;
3454         }
3455 
3456         /* Allocate command memory. */
3457         bpsize = plbreq.TransferCount + 4; /* Include opcode size */
3458         bp = kmem_zalloc(bpsize, KM_SLEEP);
3459         if (bp == NULL) {
3460                 EL(ha, "failed, kmem_zalloc\n");
3461                 cmd->Status = EXT_STATUS_NO_MEMORY;
3462                 cmd->ResponseLen = 0;
3463                 return;
3464         }
3465         pld = bp + 4;
3466         *bp = 0x10;     /* opcode */
3467 
3468         /* Get loopback data. */
3469         if (ql_get_buffer_data((caddr_t)(uintptr_t)plbreq.BufferAddress,
3470             pld, plbreq.TransferCount, mode) != plbreq.TransferCount) {
3471                 EL(ha, "failed, ddi_copyin-2\n");
3472                 kmem_free(bp, bpsize);
3473                 cmd->Status = EXT_STATUS_COPY_ERR;
3474                 cmd->ResponseLen = 0;
3475                 return;
3476         }
3477 
3478         if (LOOP_RECONFIGURE(ha) ||
3479             ql_stall_driver(ha, 0) != QL_SUCCESS) {
3480                 EL(ha, "failed, LOOP_NOT_READY\n");
3481                 ql_restart_driver(ha);
3482                 kmem_free(bp, bpsize);
3483                 cmd->Status = EXT_STATUS_BUSY;
3484                 cmd->ResponseLen = 0;
3485                 return;
3486         }
3487         loop_up = ha->task_daemon_flags & LOOP_DOWN ? B_FALSE : B_TRUE;
3488 
3489         /* Shutdown IP. */
3490         if (ha->flags & IP_INITIALIZED) {
3491                 (void) ql_shutdown_ip(ha);
3492         }
3493 
3494         /* determine topology so we can send the loopback or the echo */
3495         /* Echo is supported on 2300's only and above */
3496 
3497         ADAPTER_STATE_LOCK(ha);
3498         ha->flags |= LOOPBACK_ACTIVE;
3499         ADAPTER_STATE_UNLOCK(ha);
3500 
3501         opt = plbreq.Options;
3502 
3503         if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
3504                 opt = (uint16_t)(plbreq.Options & MBC_LOOPBACK_POINT_MASK);
3505                 if (loop_up && opt == MBC_LOOPBACK_POINT_EXTERNAL) {
3506                         if (plbreq.TransferCount > 252) {
3507                                 EL(ha, "transfer count (%d) > 252\n",
3508                                     plbreq.TransferCount);
3509                                 ql_restart_driver(ha);
3510                                 kmem_free(bp, bpsize);
3511                                 cmd->Status = EXT_STATUS_INVALID_PARAM;
3512                                 cmd->ResponseLen = 0;
3513                                 return;
3514                         }
3515                         plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD;
3516                         rval = ql_diag_echo(ha, pld, plbreq.TransferCount,
3517                             MBC_ECHO_ELS, &mr);
3518                 } else {
3519                         if (CFG_IST(ha, CFG_LOOP_POINT_SUPPORT)) {
3520                                 (void) ql_set_loop_point(ha, opt);
3521                         }
3522                         plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD;
3523                         rval = ql_diag_loopback(ha, pld, plbreq.TransferCount,
3524                             opt, plbreq.IterationCount, &mr);
3525                         if (mr.mb[0] == 0x4005 && mr.mb[1] == 0x17) {
3526                                 (void) ql_abort_isp(ha);
3527                         }
3528                         if (CFG_IST(ha, CFG_LOOP_POINT_SUPPORT)) {
3529                                 (void) ql_set_loop_point(ha, 0);
3530                         }
3531                 }
3532         } else {
3533                 if (loop_up && (ha->topology & QL_F_PORT) &&
3534                     CFG_IST(ha, CFG_LB_ECHO_SUPPORT)) {
3535                         QL_PRINT_9(ha, "F_PORT topology -- using "
3536                             "echo\n");
3537                         plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD;
3538                         if ((rval = ql_diag_echo(ha, bp, bpsize,
3539                             (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_1) ?
3540                             MBC_ECHO_64BIT : MBC_ECHO_ELS), &mr)) !=
3541                             QL_SUCCESS) {
3542                                 rval = ql_diag_echo(ha, pld,
3543                                     plbreq.TransferCount,
3544                                     (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_1) ?
3545                                     MBC_ECHO_64BIT : 0), &mr);
3546                         }
3547                 } else {
3548                         plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD;
3549                         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3550                                 opt = (uint16_t)(opt | MBC_LOOPBACK_64BIT);
3551                         }
3552                         rval = ql_diag_loopback(ha, pld, plbreq.TransferCount,
3553                             opt, plbreq.IterationCount, &mr);
3554                 }
3555         }
3556         ADAPTER_STATE_LOCK(ha);
3557         ha->flags &= ~LOOPBACK_ACTIVE;
3558         ADAPTER_STATE_UNLOCK(ha);
3559 
3560         ql_restart_driver(ha);
3561         if (loop_up && opt == MBC_LOOPBACK_POINT_INTERNAL) {
3562                 timer = 30;
3563                 do {
3564                         delay(100);
3565                 } while (timer-- && LOOP_NOT_READY(ha));
3566         }
3567 
3568         /* Restart IP if it was shutdown. */
3569         if (ha->flags & IP_ENABLED && !(ha->flags & IP_INITIALIZED)) {
3570                 (void) ql_initialize_ip(ha);
3571                 ql_isp_rcvbuf(ha);
3572         }
3573 
3574         if (rval != QL_SUCCESS) {
3575                 EL(ha, "failed, diagnostic_loopback_mbx=%xh\n", rval);
3576                 kmem_free(bp, bpsize);
3577                 cmd->Status = EXT_STATUS_MAILBOX;
3578                 cmd->DetailStatus = rval;
3579                 cmd->ResponseLen = 0;
3580                 return;
3581         }
3582 
3583         /* Return loopback data. */
3584         if (ql_send_buffer_data(pld, (caddr_t)(uintptr_t)plbreq.BufferAddress,
3585             plbreq.TransferCount, mode) != plbreq.TransferCount) {
3586                 EL(ha, "failed, ddi_copyout\n");
3587                 kmem_free(bp, bpsize);
3588                 cmd->Status = EXT_STATUS_COPY_ERR;
3589                 cmd->ResponseLen = 0;
3590                 return;
3591         }
3592         kmem_free(bp, bpsize);
3593 
3594         /* Return loopback results. */
3595         plbrsp.BufferAddress = plbreq.BufferAddress;
3596         plbrsp.BufferLength = plbreq.TransferCount;
3597         plbrsp.CompletionStatus = mr.mb[0];
3598 
3599         if (plbrsp.CommandSent == INT_DEF_LB_ECHO_CMD) {
3600                 plbrsp.CrcErrorCount = 0;
3601                 plbrsp.DisparityErrorCount = 0;
3602                 plbrsp.FrameLengthErrorCount = 0;
3603                 plbrsp.IterationCountLastError = 0;
3604         } else {
3605                 plbrsp.CrcErrorCount = mr.mb[1];
3606                 plbrsp.DisparityErrorCount = mr.mb[2];
3607                 plbrsp.FrameLengthErrorCount = mr.mb[3];
3608                 plbrsp.IterationCountLastError =
3609                     SHORT_TO_LONG(mr.mb[18], mr.mb[19]);
3610         }
3611 
3612         rval = ddi_copyout((void *)&plbrsp,
3613             (void *)(uintptr_t)cmd->ResponseAdr,
3614             sizeof (EXT_LOOPBACK_RSP), mode);
3615         if (rval != 0) {
3616                 EL(ha, "failed, ddi_copyout-2\n");
3617                 cmd->Status = EXT_STATUS_COPY_ERR;
3618                 cmd->ResponseLen = 0;
3619                 return;
3620         }
3621         cmd->ResponseLen = sizeof (EXT_LOOPBACK_RSP);
3622 
3623         QL_PRINT_9(ha, "done\n");
3624 }
3625 
3626 /*
3627  * ql_set_loop_point
3628  *      Setup loop point for port configuration.
3629  *
3630  * Input:
3631  *      ha:     adapter state structure.
3632  *      opt:    loop point option.
3633  *
3634  * Returns:
3635  *      ql local function return status code.
3636  *
3637  * Context:
3638  *      Kernel context.
3639  */
3640 int
3641 ql_set_loop_point(ql_adapter_state_t *ha, uint16_t opt)
3642 {
3643         ql_mbx_data_t   mr;
3644         int             rval;
3645         uint32_t        timer;
3646 
3647         QL_PRINT_9(ha, "started\n");
3648 
3649         /*
3650          * We get the current port config, modify the loopback field and
3651          * write it back out.
3652          */
3653         if ((rval = ql_get_port_config(ha, &mr)) != QL_SUCCESS) {
3654                 EL(ha, "get_port_config status=%xh\n", rval);
3655                 return (rval);
3656         }
3657         /*
3658          * Set the loopback mode field while maintaining the others.
3659          */
3660         mr.mb[1] = (uint16_t)(mr.mb[1] & ~LOOPBACK_MODE_FIELD_MASK);
3661         if (opt == MBC_LOOPBACK_POINT_INTERNAL) {
3662                 mr.mb[1] = (uint16_t)(mr.mb[1] | LOOPBACK_MODE_INTERNAL);
3663         } else if (CFG_IST(ha, CFG_CTRL_80XX) &&
3664             opt == MBC_LOOPBACK_POINT_EXTERNAL) {
3665                 mr.mb[1] = (uint16_t)(mr.mb[1] | LOOPBACK_MODE_EXTERNAL);
3666         }
3667         /*
3668          * Changing the port configuration will cause the port state to cycle
3669          * down and back up. The indication that this has happened is that
3670          * the point to point flag gets set.
3671          */
3672         ADAPTER_STATE_LOCK(ha);
3673         ha->flags &= ~POINT_TO_POINT;
3674         ADAPTER_STATE_UNLOCK(ha);
3675         if ((rval = ql_set_port_config(ha, &mr)) != QL_SUCCESS) {
3676                 EL(ha, "set_port_config status=%xh\n", rval);
3677         }
3678 
3679         /* wait for a while */
3680         for (timer = opt ? 10 : 0; timer; timer--) {
3681                 if (ha->flags & POINT_TO_POINT) {
3682                         break;
3683                 }
3684                 /* Delay for 1000000 usec (1 second). */
3685                 ql_delay(ha, 1000000);
3686         }
3687 
3688         QL_PRINT_9(ha, "done\n");
3689 
3690         return (rval);
3691 }
3692 
3693 /*
3694  * ql_send_els_rnid
3695  *      IOCTL for extended link service RNID command.
3696  *
3697  * Input:
3698  *      ha:     adapter state pointer.
3699  *      cmd:    User space CT arguments pointer.
3700  *      mode:   flags.
3701  *
3702  * Returns:
3703  *      None, request status indicated in cmd->Status.
3704  *
3705  * Context:
3706  *      Kernel context.
3707  */
3708 static void
3709 ql_send_els_rnid(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3710 {
3711         EXT_RNID_REQ    tmp_rnid;
3712         port_id_t       tmp_fcid;
3713         caddr_t         tmp_buf, bptr;
3714         uint32_t        copy_len;
3715         ql_tgt_t        *tq = NULL;
3716         EXT_RNID_DATA   rnid_data;
3717         uint32_t        loop_ready_wait = 10 * 60 * 10;
3718         int             rval = 0;
3719         uint32_t        local_hba = 0;
3720 
3721         QL_PRINT_9(ha, "started\n");
3722 
3723         if (DRIVER_SUSPENDED(ha)) {
3724                 EL(ha, "failed, LOOP_NOT_READY\n");
3725                 cmd->Status = EXT_STATUS_BUSY;
3726                 cmd->ResponseLen = 0;
3727                 return;
3728         }
3729 
3730         if (cmd->RequestLen != sizeof (EXT_RNID_REQ)) {
3731                 /* parameter error */
3732                 EL(ha, "failed, RequestLen < EXT_RNID_REQ, Len=%xh\n",
3733                     cmd->RequestLen);
3734                 cmd->Status = EXT_STATUS_INVALID_PARAM;
3735                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
3736                 cmd->ResponseLen = 0;
3737                 return;
3738         }
3739 
3740         if (ddi_copyin((void*)(uintptr_t)cmd->RequestAdr,
3741             &tmp_rnid, cmd->RequestLen, mode) != 0) {
3742                 EL(ha, "failed, ddi_copyin\n");
3743                 cmd->Status = EXT_STATUS_COPY_ERR;
3744                 cmd->ResponseLen = 0;
3745                 return;
3746         }
3747 
3748         /* Find loop ID of the device */
3749         if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWNN) {
3750                 bptr = (caddr_t)ha->loginparams.node_ww_name.raw_wwn;
3751                 if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWNN,
3752                     EXT_DEF_WWN_NAME_SIZE) == 0) {
3753                         local_hba = 1;
3754                 } else {
3755                         tq = ql_find_port(ha,
3756                             (uint8_t *)tmp_rnid.Addr.FcAddr.WWNN, QLNT_NODE);
3757                 }
3758         } else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWPN) {
3759                 bptr = (caddr_t)ha->loginparams.nport_ww_name.raw_wwn;
3760                 if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWPN,
3761                     EXT_DEF_WWN_NAME_SIZE) == 0) {
3762                         local_hba = 1;
3763                 } else {
3764                         tq = ql_find_port(ha,
3765                             (uint8_t *)tmp_rnid.Addr.FcAddr.WWPN, QLNT_PORT);
3766                 }
3767         } else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_PORTID) {
3768                 /*
3769                  * Copy caller's d_id to tmp space.
3770                  */
3771                 bcopy(&tmp_rnid.Addr.FcAddr.Id[1], tmp_fcid.r.d_id,
3772                     EXT_DEF_PORTID_SIZE_ACTUAL);
3773                 BIG_ENDIAN_24(&tmp_fcid.r.d_id[0]);
3774 
3775                 if (bcmp((void *)&ha->d_id, (void *)tmp_fcid.r.d_id,
3776                     EXT_DEF_PORTID_SIZE_ACTUAL) == 0) {
3777                         local_hba = 1;
3778                 } else {
3779                         tq = ql_find_port(ha, (uint8_t *)tmp_fcid.r.d_id,
3780                             QLNT_PID);
3781                 }
3782         }
3783 
3784         /* Allocate memory for command. */
3785         tmp_buf = kmem_zalloc(SEND_RNID_RSP_SIZE, KM_SLEEP);
3786         if (tmp_buf == NULL) {
3787                 EL(ha, "failed, kmem_zalloc\n");
3788                 cmd->Status = EXT_STATUS_NO_MEMORY;
3789                 cmd->ResponseLen = 0;
3790                 return;
3791         }
3792 
3793         if (local_hba) {
3794                 rval = ql_get_rnid_params(ha, SEND_RNID_RSP_SIZE, tmp_buf);
3795                 if (rval != QL_SUCCESS) {
3796                         EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
3797                         kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3798                         cmd->Status = EXT_STATUS_ERR;
3799                         cmd->ResponseLen = 0;
3800                         return;
3801                 }
3802 
3803                 /* Save gotten RNID data. */
3804                 bcopy(tmp_buf, &rnid_data, sizeof (EXT_RNID_DATA));
3805 
3806                 /* Now build the Send RNID response */
3807                 tmp_buf[0] = (char)(EXT_DEF_RNID_DFORMAT_TOPO_DISC);
3808                 tmp_buf[1] = (2 * EXT_DEF_WWN_NAME_SIZE);
3809                 tmp_buf[2] = 0;
3810                 tmp_buf[3] = sizeof (EXT_RNID_DATA);
3811                 bcopy(ha->loginparams.nport_ww_name.raw_wwn, &tmp_buf[4],
3812                     EXT_DEF_WWN_NAME_SIZE);
3813                 bcopy(ha->loginparams.node_ww_name.raw_wwn,
3814                     &tmp_buf[4 + EXT_DEF_WWN_NAME_SIZE],
3815                     EXT_DEF_WWN_NAME_SIZE);
3816                 bcopy((uint8_t *)&rnid_data,
3817                     &tmp_buf[4 + 2 * EXT_DEF_WWN_NAME_SIZE],
3818                     sizeof (EXT_RNID_DATA));
3819         } else {
3820                 if (tq == NULL) {
3821                         /* no matching device */
3822                         EL(ha, "failed, device not found\n");
3823                         kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3824                         cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
3825                         cmd->DetailStatus = EXT_DSTATUS_TARGET;
3826                         cmd->ResponseLen = 0;
3827                         return;
3828                 }
3829 
3830                 /* Send command */
3831                 rval = ql_send_rnid_els(ha, tq->loop_id,
3832                     (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE, tmp_buf);
3833                 if (rval != QL_SUCCESS) {
3834                         EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n",
3835                             rval, tq->loop_id);
3836                         while (LOOP_NOT_READY(ha)) {
3837                                 ql_delay(ha, 100000);
3838                                 if (loop_ready_wait-- == 0) {
3839                                         EL(ha, "failed, loop not ready\n");
3840                                         cmd->Status = EXT_STATUS_ERR;
3841                                         cmd->ResponseLen = 0;
3842                                 }
3843                         }
3844                         rval = ql_send_rnid_els(ha, tq->loop_id,
3845                             (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE,
3846                             tmp_buf);
3847                         if (rval != QL_SUCCESS) {
3848                                 /* error */
3849                                 EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n",
3850                                     rval, tq->loop_id);
3851                                 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3852                                 cmd->Status = EXT_STATUS_ERR;
3853                                 cmd->ResponseLen = 0;
3854                                 return;
3855                         }
3856                 }
3857         }
3858 
3859         /* Copy the response */
3860         copy_len = (cmd->ResponseLen > SEND_RNID_RSP_SIZE) ?
3861             SEND_RNID_RSP_SIZE : cmd->ResponseLen;
3862 
3863         if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)cmd->ResponseAdr,
3864             copy_len, mode) != copy_len) {
3865                 cmd->Status = EXT_STATUS_COPY_ERR;
3866                 EL(ha, "failed, ddi_copyout\n");
3867         } else {
3868                 cmd->ResponseLen = copy_len;
3869                 if (copy_len < SEND_RNID_RSP_SIZE) {
3870                         cmd->Status = EXT_STATUS_DATA_OVERRUN;
3871                         EL(ha, "failed, EXT_STATUS_DATA_OVERRUN\n");
3872 
3873                 } else if (cmd->ResponseLen > SEND_RNID_RSP_SIZE) {
3874                         cmd->Status = EXT_STATUS_DATA_UNDERRUN;
3875                         EL(ha, "failed, EXT_STATUS_DATA_UNDERRUN\n");
3876                 } else {
3877                         cmd->Status = EXT_STATUS_OK;
3878                         QL_PRINT_9(ha, "done\n",
3879                             ha->instance);
3880                 }
3881         }
3882 
3883         kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3884 }
3885 
3886 /*
3887  * ql_set_host_data
3888  *      Process IOCTL subcommand to set host/adapter related data.
3889  *
3890  * Input:
3891  *      ha:     adapter state pointer.
3892  *      cmd:    User space CT arguments pointer.
3893  *      mode:   flags.
3894  *
3895  * Returns:
3896  *      None, request status indicated in cmd->Status.
3897  *
3898  * Context:
3899  *      Kernel context.
3900  */
3901 static void
3902 ql_set_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3903 {
3904         QL_PRINT_9(ha, "started, SubCode=%d\n",
3905             cmd->SubCode);
3906 
3907         /*
3908          * case off on command subcode
3909          */
3910         switch (cmd->SubCode) {
3911         case EXT_SC_SET_RNID:
3912                 ql_set_rnid_parameters(ha, cmd, mode);
3913                 break;
3914         case EXT_SC_RST_STATISTICS:
3915                 (void) ql_reset_statistics(ha, cmd);
3916                 break;
3917         case EXT_SC_SET_BEACON_STATE:
3918                 ql_set_led_state(ha, cmd, mode);
3919                 break;
3920         case EXT_SC_SET_PARMS:
3921         case EXT_SC_SET_BUS_MODE:
3922         case EXT_SC_SET_DR_DUMP_BUF:
3923         case EXT_SC_SET_RISC_CODE:
3924         case EXT_SC_SET_FLASH_RAM:
3925         case EXT_SC_SET_LUN_BITMASK:
3926         case EXT_SC_SET_RETRY_CNT:
3927         case EXT_SC_SET_RTIN:
3928         case EXT_SC_SET_FC_LUN_BITMASK:
3929         case EXT_SC_ADD_TARGET_DEVICE:
3930         case EXT_SC_SWAP_TARGET_DEVICE:
3931         case EXT_SC_SET_SEL_TIMEOUT:
3932         default:
3933                 /* function not supported. */
3934                 EL(ha, "failed, function not supported=%d\n", cmd->SubCode);
3935                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
3936                 break;
3937         }
3938 
3939         if (cmd->Status != EXT_STATUS_OK) {
3940                 EL(ha, "failed, Status=%d\n", cmd->Status);
3941         } else {
3942                 /*EMPTY*/
3943                 QL_PRINT_9(ha, "done\n");
3944         }
3945 }
3946 
3947 /*
3948  * ql_get_host_data
3949  *      Performs EXT_CC_GET_DATA subcommands.
3950  *
3951  * Input:
3952  *      ha:     adapter state pointer.
3953  *      cmd:    Local EXT_IOCTL cmd struct pointer.
3954  *      mode:   flags.
3955  *
3956  * Returns:
3957  *      None, request status indicated in cmd->Status.
3958  *
3959  * Context:
3960  *      Kernel context.
3961  */
3962 static void
3963 ql_get_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3964 {
3965         int     out_size = 0;
3966 
3967         QL_PRINT_9(ha, "started, SubCode=%d\n",
3968             cmd->SubCode);
3969 
3970         /* case off on command subcode */
3971         switch (cmd->SubCode) {
3972         case EXT_SC_GET_STATISTICS:
3973                 out_size = sizeof (EXT_HBA_PORT_STAT);
3974                 break;
3975         case EXT_SC_GET_FC_STATISTICS:
3976                 out_size = sizeof (EXT_HBA_PORT_STAT);
3977                 break;
3978         case EXT_SC_GET_PORT_SUMMARY:
3979                 out_size = sizeof (EXT_DEVICEDATA);
3980                 break;
3981         case EXT_SC_GET_RNID:
3982                 out_size = sizeof (EXT_RNID_DATA);
3983                 break;
3984         case EXT_SC_GET_TARGET_ID:
3985                 out_size = sizeof (EXT_DEST_ADDR);
3986                 break;
3987         case EXT_SC_GET_BEACON_STATE:
3988                 out_size = sizeof (EXT_BEACON_CONTROL);
3989                 break;
3990         case EXT_SC_GET_FC4_STATISTICS:
3991                 out_size = sizeof (EXT_HBA_FC4STATISTICS);
3992                 break;
3993         case EXT_SC_GET_DCBX_PARAM:
3994                 out_size = EXT_DEF_DCBX_PARAM_BUF_SIZE;
3995                 break;
3996         case EXT_SC_GET_RESOURCE_CNTS:
3997                 out_size = sizeof (EXT_RESOURCE_CNTS);
3998                 break;
3999         case EXT_SC_GET_FCF_LIST:
4000                 out_size = sizeof (EXT_FCF_LIST);
4001                 break;
4002         case EXT_SC_GET_PRIV_STATS:
4003                 out_size = cmd->ResponseLen;
4004                 break;
4005         case EXT_SC_GET_SCSI_ADDR:
4006         case EXT_SC_GET_ERR_DETECTIONS:
4007         case EXT_SC_GET_BUS_MODE:
4008         case EXT_SC_GET_DR_DUMP_BUF:
4009         case EXT_SC_GET_RISC_CODE:
4010         case EXT_SC_GET_FLASH_RAM:
4011         case EXT_SC_GET_LINK_STATUS:
4012         case EXT_SC_GET_LOOP_ID:
4013         case EXT_SC_GET_LUN_BITMASK:
4014         case EXT_SC_GET_PORT_DATABASE:
4015         case EXT_SC_GET_PORT_DATABASE_MEM:
4016         case EXT_SC_GET_POSITION_MAP:
4017         case EXT_SC_GET_RETRY_CNT:
4018         case EXT_SC_GET_RTIN:
4019         case EXT_SC_GET_FC_LUN_BITMASK:
4020         case EXT_SC_GET_SEL_TIMEOUT:
4021         default:
4022                 /* function not supported. */
4023                 EL(ha, "failed, function not supported=%d\n", cmd->SubCode);
4024                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
4025                 cmd->ResponseLen = 0;
4026                 return;
4027         }
4028 
4029         if (cmd->ResponseLen < out_size) {
4030                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
4031                 cmd->DetailStatus = out_size;
4032                 EL(ha, "failed, ResponseLen=%xh, size=%xh\n",
4033                     cmd->ResponseLen, out_size);
4034                 cmd->ResponseLen = 0;
4035                 return;
4036         }
4037 
4038         switch (cmd->SubCode) {
4039         case EXT_SC_GET_RNID:
4040                 ql_get_rnid_parameters(ha, cmd, mode);
4041                 break;
4042         case EXT_SC_GET_STATISTICS:
4043                 ql_get_statistics(ha, cmd, mode);
4044                 break;
4045         case EXT_SC_GET_FC_STATISTICS:
4046                 ql_get_statistics_fc(ha, cmd, mode);
4047                 break;
4048         case EXT_SC_GET_FC4_STATISTICS:
4049                 ql_get_statistics_fc4(ha, cmd, mode);
4050                 break;
4051         case EXT_SC_GET_PORT_SUMMARY:
4052                 ql_get_port_summary(ha, cmd, mode);
4053                 break;
4054         case EXT_SC_GET_TARGET_ID:
4055                 ql_get_target_id(ha, cmd, mode);
4056                 break;
4057         case EXT_SC_GET_BEACON_STATE:
4058                 ql_get_led_state(ha, cmd, mode);
4059                 break;
4060         case EXT_SC_GET_DCBX_PARAM:
4061                 ql_get_dcbx_parameters(ha, cmd, mode);
4062                 break;
4063         case EXT_SC_GET_FCF_LIST:
4064                 ql_get_fcf_list(ha, cmd, mode);
4065                 break;
4066         case EXT_SC_GET_RESOURCE_CNTS:
4067                 ql_get_resource_counts(ha, cmd, mode);
4068                 break;
4069         case EXT_SC_GET_PRIV_STATS:
4070                 ql_get_priv_stats(ha, cmd, mode);
4071                 break;
4072         }
4073 
4074         if (cmd->Status != EXT_STATUS_OK) {
4075                 EL(ha, "failed, Status=%d\n", cmd->Status);
4076         } else {
4077                 /*EMPTY*/
4078                 QL_PRINT_9(ha, "done\n");
4079         }
4080 }
4081 
4082 /* ******************************************************************** */
4083 /*                      Helper Functions                                */
4084 /* ******************************************************************** */
4085 
4086 /*
4087  * ql_lun_count
4088  *      Get numbers of LUNS on target.
4089  *
4090  * Input:
4091  *      ha:     adapter state pointer.
4092  *      q:      device queue pointer.
4093  *
4094  * Returns:
4095  *      Number of LUNs.
4096  *
4097  * Context:
4098  *      Kernel context.
4099  */
4100 static int
4101 ql_lun_count(ql_adapter_state_t *ha, ql_tgt_t *tq)
4102 {
4103         int     cnt;
4104 
4105         QL_PRINT_9(ha, "started\n");
4106 
4107         /* Bypass LUNs that failed. */
4108         cnt = ql_report_lun(ha, tq);
4109         if (cnt == 0) {
4110                 cnt = ql_inq_scan(ha, tq, ha->maximum_luns_per_target);
4111         }
4112 
4113         QL_PRINT_9(ha, "done\n");
4114 
4115         return (cnt);
4116 }
4117 
4118 /*
4119  * ql_report_lun
4120  *      Get numbers of LUNS using report LUN command.
4121  *
4122  * Input:
4123  *      ha:     adapter state pointer.
4124  *      q:      target queue pointer.
4125  *
4126  * Returns:
4127  *      Number of LUNs.
4128  *
4129  * Context:
4130  *      Kernel context.
4131  */
4132 static int
4133 ql_report_lun(ql_adapter_state_t *ha, ql_tgt_t *tq)
4134 {
4135         int                     rval;
4136         uint8_t                 retries;
4137         ql_mbx_iocb_t           *pkt;
4138         ql_rpt_lun_lst_t        *rpt;
4139         dma_mem_t               dma_mem;
4140         uint32_t                pkt_size, cnt;
4141         uint16_t                comp_status;
4142         uint8_t                 scsi_status_h, scsi_status_l, *reqs;
4143 
4144         QL_PRINT_9(ha, "started\n");
4145 
4146         if (DRIVER_SUSPENDED(ha)) {
4147                 EL(ha, "failed, LOOP_NOT_READY\n");
4148                 return (0);
4149         }
4150 
4151         pkt_size = sizeof (ql_mbx_iocb_t) + sizeof (ql_rpt_lun_lst_t);
4152         pkt = kmem_zalloc(pkt_size, KM_SLEEP);
4153         if (pkt == NULL) {
4154                 EL(ha, "failed, kmem_zalloc\n");
4155                 return (0);
4156         }
4157         rpt = (ql_rpt_lun_lst_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t));
4158 
4159         /* Get DMA memory for the IOCB */
4160         if (ql_get_dma_mem(ha, &dma_mem, sizeof (ql_rpt_lun_lst_t),
4161             LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) {
4162                 cmn_err(CE_WARN, "%s(%d) DMA memory "
4163                     "alloc failed", QL_NAME, ha->instance);
4164                 kmem_free(pkt, pkt_size);
4165                 return (0);
4166         }
4167 
4168         for (retries = 0; retries < 4; retries++) {
4169                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4170                         pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
4171                         pkt->cmd24.entry_count = 1;
4172 
4173                         /* Set N_port handle */
4174                         pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
4175 
4176                         /* Set target ID */
4177                         pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
4178                         pkt->cmd24.target_id[1] = tq->d_id.b.area;
4179                         pkt->cmd24.target_id[2] = tq->d_id.b.domain;
4180 
4181                         /* Set Virtual Port ID */
4182                         pkt->cmd24.vp_index = ha->vp_index;
4183 
4184                         /* Set ISP command timeout. */
4185                         pkt->cmd24.timeout = LE_16(15);
4186 
4187                         /* Load SCSI CDB */
4188                         pkt->cmd24.scsi_cdb[0] = SCMD_REPORT_LUNS;
4189                         pkt->cmd24.scsi_cdb[6] =
4190                             MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4191                         pkt->cmd24.scsi_cdb[7] =
4192                             LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4193                         pkt->cmd24.scsi_cdb[8] =
4194                             MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4195                         pkt->cmd24.scsi_cdb[9] =
4196                             LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4197                         for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) {
4198                                 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
4199                                     + cnt, 4);
4200                         }
4201 
4202                         /* Set tag queue control flags */
4203                         pkt->cmd24.task = TA_STAG;
4204 
4205                         /* Set transfer direction. */
4206                         pkt->cmd24.control_flags = CF_RD;
4207 
4208                         /* Set data segment count. */
4209                         pkt->cmd24.dseg_count = LE_16(1);
4210 
4211                         /* Load total byte count. */
4212                         /* Load data descriptor. */
4213                         pkt->cmd24.dseg.address[0] = (uint32_t)
4214                             LE_32(LSD(dma_mem.cookie.dmac_laddress));
4215                         pkt->cmd24.dseg.address[1] = (uint32_t)
4216                             LE_32(MSD(dma_mem.cookie.dmac_laddress));
4217                         pkt->cmd24.total_byte_count =
4218                             LE_32(sizeof (ql_rpt_lun_lst_t));
4219                         pkt->cmd24.dseg.length =
4220                             LE_32(sizeof (ql_rpt_lun_lst_t));
4221                 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
4222                         pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
4223                         pkt->cmd3.entry_count = 1;
4224                         if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4225                                 pkt->cmd3.target_l = LSB(tq->loop_id);
4226                                 pkt->cmd3.target_h = MSB(tq->loop_id);
4227                         } else {
4228                                 pkt->cmd3.target_h = LSB(tq->loop_id);
4229                         }
4230                         pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG;
4231                         pkt->cmd3.timeout = LE_16(15);
4232                         pkt->cmd3.dseg_count = LE_16(1);
4233                         pkt->cmd3.scsi_cdb[0] = SCMD_REPORT_LUNS;
4234                         pkt->cmd3.scsi_cdb[6] =
4235                             MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4236                         pkt->cmd3.scsi_cdb[7] =
4237                             LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4238                         pkt->cmd3.scsi_cdb[8] =
4239                             MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4240                         pkt->cmd3.scsi_cdb[9] =
4241                             LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4242                         pkt->cmd3.byte_count =
4243                             LE_32(sizeof (ql_rpt_lun_lst_t));
4244                         pkt->cmd3.dseg[0].address[0] = (uint32_t)
4245                             LE_32(LSD(dma_mem.cookie.dmac_laddress));
4246                         pkt->cmd3.dseg[0].address[1] = (uint32_t)
4247                             LE_32(MSD(dma_mem.cookie.dmac_laddress));
4248                         pkt->cmd3.dseg[0].length =
4249                             LE_32(sizeof (ql_rpt_lun_lst_t));
4250                 } else {
4251                         pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
4252                         pkt->cmd.entry_count = 1;
4253                         if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4254                                 pkt->cmd.target_l = LSB(tq->loop_id);
4255                                 pkt->cmd.target_h = MSB(tq->loop_id);
4256                         } else {
4257                                 pkt->cmd.target_h = LSB(tq->loop_id);
4258                         }
4259                         pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG;
4260                         pkt->cmd.timeout = LE_16(15);
4261                         pkt->cmd.dseg_count = LE_16(1);
4262                         pkt->cmd.scsi_cdb[0] = SCMD_REPORT_LUNS;
4263                         pkt->cmd.scsi_cdb[6] =
4264                             MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4265                         pkt->cmd.scsi_cdb[7] =
4266                             LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4267                         pkt->cmd.scsi_cdb[8] =
4268                             MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4269                         pkt->cmd.scsi_cdb[9] =
4270                             LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4271                         pkt->cmd.byte_count =
4272                             LE_32(sizeof (ql_rpt_lun_lst_t));
4273                         pkt->cmd.dseg[0].address = (uint32_t)
4274                             LE_32(LSD(dma_mem.cookie.dmac_laddress));
4275                         pkt->cmd.dseg[0].length =
4276                             LE_32(sizeof (ql_rpt_lun_lst_t));
4277                 }
4278 
4279                 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
4280                     sizeof (ql_mbx_iocb_t));
4281 
4282                 /* Sync in coming DMA buffer. */
4283                 (void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size,
4284                     DDI_DMA_SYNC_FORKERNEL);
4285                 /* Copy in coming DMA data. */
4286                 ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)rpt,
4287                     (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR);
4288 
4289                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4290                         pkt->sts24.entry_status = (uint8_t)
4291                             (pkt->sts24.entry_status & 0x3c);
4292                         comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
4293                         scsi_status_h = pkt->sts24.scsi_status_h;
4294                         scsi_status_l = pkt->sts24.scsi_status_l;
4295                         cnt = scsi_status_h & FCP_RSP_LEN_VALID ?
4296                             LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
4297                         reqs = &pkt->sts24.rsp_sense_data[cnt];
4298                 } else {
4299                         pkt->sts.entry_status = (uint8_t)
4300                             (pkt->sts.entry_status & 0x7e);
4301                         comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
4302                         scsi_status_h = pkt->sts.scsi_status_h;
4303                         scsi_status_l = pkt->sts.scsi_status_l;
4304                         reqs = &pkt->sts.req_sense_data[0];
4305                 }
4306                 if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) {
4307                         EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
4308                             pkt->sts.entry_status, tq->d_id.b24);
4309                         rval = QL_FUNCTION_PARAMETER_ERROR;
4310                 }
4311 
4312                 if (rval != QL_SUCCESS || comp_status != CS_COMPLETE ||
4313                     scsi_status_l & STATUS_CHECK) {
4314                         /* Device underrun, treat as OK. */
4315                         if (rval == QL_SUCCESS &&
4316                             comp_status == CS_DATA_UNDERRUN &&
4317                             scsi_status_h & FCP_RESID_UNDER) {
4318                                 break;
4319                         }
4320 
4321                         EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, "
4322                             "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24,
4323                             comp_status, scsi_status_h, scsi_status_l);
4324 
4325                         if (rval == QL_SUCCESS) {
4326                                 if ((comp_status == CS_TIMEOUT) ||
4327                                     (comp_status == CS_PORT_UNAVAILABLE) ||
4328                                     (comp_status == CS_PORT_LOGGED_OUT)) {
4329                                         rval = QL_FUNCTION_TIMEOUT;
4330                                         break;
4331                                 }
4332                                 rval = QL_FUNCTION_FAILED;
4333                         } else if (rval == QL_ABORTED) {
4334                                 break;
4335                         }
4336 
4337                         if (scsi_status_l & STATUS_CHECK) {
4338                                 EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh"
4339                                     "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
4340                                     "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0],
4341                                     reqs[1], reqs[2], reqs[3], reqs[4],
4342                                     reqs[5], reqs[6], reqs[7], reqs[8],
4343                                     reqs[9], reqs[10], reqs[11], reqs[12],
4344                                     reqs[13], reqs[14], reqs[15], reqs[16],
4345                                     reqs[17]);
4346                         }
4347                 } else {
4348                         break;
4349                 }
4350                 bzero((caddr_t)pkt, pkt_size);
4351         }
4352 
4353         if (rval != QL_SUCCESS) {
4354                 EL(ha, "failed=%xh\n", rval);
4355                 rval = 0;
4356         } else {
4357                 QL_PRINT_9(ha, "LUN list\n");
4358                 QL_DUMP_9(rpt, 8, rpt->hdr.len + 8);
4359                 rval = (int)(BE_32(rpt->hdr.len) / 8);
4360         }
4361 
4362         kmem_free(pkt, pkt_size);
4363         ql_free_dma_resource(ha, &dma_mem);
4364 
4365         QL_PRINT_9(ha, "done\n");
4366 
4367         return (rval);
4368 }
4369 
4370 /*
4371  * ql_inq_scan
4372  *      Get numbers of LUNS using inquiry command.
4373  *
4374  * Input:
4375  *      ha:             adapter state pointer.
4376  *      tq:             target queue pointer.
4377  *      count:          scan for the number of existing LUNs.
4378  *
4379  * Returns:
4380  *      Number of LUNs.
4381  *
4382  * Context:
4383  *      Kernel context.
4384  */
4385 static int
4386 ql_inq_scan(ql_adapter_state_t *ha, ql_tgt_t *tq, int count)
4387 {
4388         int             lun, cnt, rval;
4389         ql_mbx_iocb_t   *pkt;
4390         uint8_t         *inq;
4391         uint32_t        pkt_size;
4392 
4393         QL_PRINT_9(ha, "started\n");
4394 
4395         pkt_size = sizeof (ql_mbx_iocb_t) + INQ_DATA_SIZE;
4396         pkt = kmem_zalloc(pkt_size, KM_SLEEP);
4397         if (pkt == NULL) {
4398                 EL(ha, "failed, kmem_zalloc\n");
4399                 return (0);
4400         }
4401         inq = (uint8_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t));
4402 
4403         cnt = 0;
4404         for (lun = 0; lun < MAX_LUNS; lun++) {
4405 
4406                 if (DRIVER_SUSPENDED(ha)) {
4407                         rval = QL_LOOP_DOWN;
4408                         cnt = 0;
4409                         break;
4410                 }
4411 
4412                 rval = ql_inq(ha, tq, lun, pkt, INQ_DATA_SIZE);
4413                 if (rval == QL_SUCCESS) {
4414                         switch (*inq) {
4415                         case DTYPE_DIRECT:
4416                         case DTYPE_PROCESSOR:   /* Appliance. */
4417                         case DTYPE_WORM:
4418                         case DTYPE_RODIRECT:
4419                         case DTYPE_SCANNER:
4420                         case DTYPE_OPTICAL:
4421                         case DTYPE_CHANGER:
4422                         case DTYPE_ESI:
4423                                 cnt++;
4424                                 break;
4425                         case DTYPE_SEQUENTIAL:
4426                                 cnt++;
4427                                 tq->flags |= TQF_TAPE_DEVICE;
4428                                 break;
4429                         default:
4430                                 QL_PRINT_9(ha, "failed, "
4431                                     "unsupported device id=%xh, lun=%d, "
4432                                     "type=%xh\n", tq->loop_id,
4433                                     lun, *inq);
4434                                 break;
4435                         }
4436 
4437                         if (*inq == DTYPE_ESI || cnt >= count) {
4438                                 break;
4439                         }
4440                 } else if (rval == QL_ABORTED || rval == QL_FUNCTION_TIMEOUT) {
4441                         cnt = 0;
4442                         break;
4443                 }
4444         }
4445 
4446         kmem_free(pkt, pkt_size);
4447 
4448         QL_PRINT_9(ha, "done\n");
4449 
4450         return (cnt);
4451 }
4452 
4453 /*
4454  * ql_inq
4455  *      Issue inquiry command.
4456  *
4457  * Input:
4458  *      ha:             adapter state pointer.
4459  *      tq:             target queue pointer.
4460  *      lun:            LUN number.
4461  *      pkt:            command and buffer pointer.
4462  *      inq_len:        amount of inquiry data.
4463  *
4464  * Returns:
4465  *      ql local function return status code.
4466  *
4467  * Context:
4468  *      Kernel context.
4469  */
4470 static int
4471 ql_inq(ql_adapter_state_t *ha, ql_tgt_t *tq, int lun, ql_mbx_iocb_t *pkt,
4472     uint32_t inq_len)
4473 {
4474         dma_mem_t       dma_mem;
4475         int             rval, retries;
4476         uint32_t        pkt_size, cnt;
4477         uint16_t        comp_status;
4478         uint8_t         scsi_status_h, scsi_status_l, *reqs;
4479         caddr_t         inq_data;
4480         uint64_t        lun_addr;
4481         fcp_ent_addr_t  *fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
4482 
4483         QL_PRINT_9(ha, "started\n");
4484 
4485         if (DRIVER_SUSPENDED(ha)) {
4486                 EL(ha, "failed, loop down\n");
4487                 return (QL_FUNCTION_TIMEOUT);
4488         }
4489 
4490         pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + inq_len);
4491         bzero((caddr_t)pkt, pkt_size);
4492 
4493         inq_data = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
4494 
4495         /* Get DMA memory for the IOCB */
4496         if (ql_get_dma_mem(ha, &dma_mem, inq_len,
4497             LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) {
4498                 cmn_err(CE_WARN, "%s(%d) DMA memory "
4499                     "alloc failed", QL_NAME, ha->instance);
4500                 return (0);
4501         }
4502 
4503         for (retries = 0; retries < 4; retries++) {
4504                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4505                         pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
4506                         pkt->cmd24.entry_count = 1;
4507 
4508                         /* Set LUN number */
4509                         lun_addr = ql_get_lun_addr(tq, lun);
4510                         fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
4511                         pkt->cmd24.fcp_lun[2] =
4512                             lobyte(fcp_ent_addr->ent_addr_0);
4513                         pkt->cmd24.fcp_lun[3] =
4514                             hibyte(fcp_ent_addr->ent_addr_0);
4515                         pkt->cmd24.fcp_lun[0] =
4516                             lobyte(fcp_ent_addr->ent_addr_1);
4517                         pkt->cmd24.fcp_lun[1] =
4518                             hibyte(fcp_ent_addr->ent_addr_1);
4519                         pkt->cmd24.fcp_lun[6] =
4520                             lobyte(fcp_ent_addr->ent_addr_2);
4521                         pkt->cmd24.fcp_lun[7] =
4522                             hibyte(fcp_ent_addr->ent_addr_2);
4523                         pkt->cmd24.fcp_lun[4] =
4524                             lobyte(fcp_ent_addr->ent_addr_3);
4525                         pkt->cmd24.fcp_lun[5] =
4526                             hibyte(fcp_ent_addr->ent_addr_3);
4527 
4528                         /* Set N_port handle */
4529                         pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
4530 
4531                         /* Set target ID */
4532                         pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
4533                         pkt->cmd24.target_id[1] = tq->d_id.b.area;
4534                         pkt->cmd24.target_id[2] = tq->d_id.b.domain;
4535 
4536                         /* Set Virtual Port ID */
4537                         pkt->cmd24.vp_index = ha->vp_index;
4538 
4539                         /* Set ISP command timeout. */
4540                         pkt->cmd24.timeout = LE_16(15);
4541 
4542                         /* Load SCSI CDB */
4543                         pkt->cmd24.scsi_cdb[0] = SCMD_INQUIRY;
4544                         pkt->cmd24.scsi_cdb[4] = LSB(LSW(inq_len));
4545                         for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) {
4546                                 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
4547                                     + cnt, 4);
4548                         }
4549 
4550                         /* Set tag queue control flags */
4551                         pkt->cmd24.task = TA_STAG;
4552 
4553                         /* Set transfer direction. */
4554                         pkt->cmd24.control_flags = CF_RD;
4555 
4556                         /* Set data segment count. */
4557                         pkt->cmd24.dseg_count = LE_16(1);
4558 
4559                         /* Load total byte count. */
4560                         pkt->cmd24.total_byte_count = LE_32(inq_len);
4561 
4562                         /* Load data descriptor. */
4563                         pkt->cmd24.dseg.address[0] = (uint32_t)
4564                             LE_32(LSD(dma_mem.cookie.dmac_laddress));
4565                         pkt->cmd24.dseg.address[1] = (uint32_t)
4566                             LE_32(MSD(dma_mem.cookie.dmac_laddress));
4567                         pkt->cmd24.dseg.length = LE_32(inq_len);
4568                 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
4569                         pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
4570                         cnt = CMD_TYPE_3_DATA_SEGMENTS;
4571 
4572                         pkt->cmd3.entry_count = 1;
4573                         if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4574                                 pkt->cmd3.target_l = LSB(tq->loop_id);
4575                                 pkt->cmd3.target_h = MSB(tq->loop_id);
4576                         } else {
4577                                 pkt->cmd3.target_h = LSB(tq->loop_id);
4578                         }
4579                         pkt->cmd3.lun_l = LSB(lun);
4580                         pkt->cmd3.lun_h = MSB(lun);
4581                         pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG;
4582                         pkt->cmd3.timeout = LE_16(15);
4583                         pkt->cmd3.scsi_cdb[0] = SCMD_INQUIRY;
4584                         pkt->cmd3.scsi_cdb[4] = LSB(LSW(inq_len));
4585                         pkt->cmd3.dseg_count = LE_16(1);
4586                         pkt->cmd3.byte_count = LE_32(inq_len);
4587                         pkt->cmd3.dseg[0].address[0] = (uint32_t)
4588                             LE_32(LSD(dma_mem.cookie.dmac_laddress));
4589                         pkt->cmd3.dseg[0].address[1] = (uint32_t)
4590                             LE_32(MSD(dma_mem.cookie.dmac_laddress));
4591                         pkt->cmd3.dseg[0].length = LE_32(inq_len);
4592                 } else {
4593                         pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
4594                         cnt = CMD_TYPE_2_DATA_SEGMENTS;
4595 
4596                         pkt->cmd.entry_count = 1;
4597                         if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4598                                 pkt->cmd.target_l = LSB(tq->loop_id);
4599                                 pkt->cmd.target_h = MSB(tq->loop_id);
4600                         } else {
4601                                 pkt->cmd.target_h = LSB(tq->loop_id);
4602                         }
4603                         pkt->cmd.lun_l = LSB(lun);
4604                         pkt->cmd.lun_h = MSB(lun);
4605                         pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG;
4606                         pkt->cmd.timeout = LE_16(15);
4607                         pkt->cmd.scsi_cdb[0] = SCMD_INQUIRY;
4608                         pkt->cmd.scsi_cdb[4] = LSB(LSW(inq_len));
4609                         pkt->cmd.dseg_count = LE_16(1);
4610                         pkt->cmd.byte_count = LE_32(inq_len);
4611                         pkt->cmd.dseg[0].address = (uint32_t)
4612                             LE_32(LSD(dma_mem.cookie.dmac_laddress));
4613                         pkt->cmd.dseg[0].length = LE_32(inq_len);
4614                 }
4615 
4616 /*              rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size); */
4617                 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
4618                     sizeof (ql_mbx_iocb_t));
4619 
4620                 /* Sync in coming IOCB DMA buffer. */
4621                 (void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size,
4622                     DDI_DMA_SYNC_FORKERNEL);
4623                 /* Copy in coming DMA data. */
4624                 ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)inq_data,
4625                     (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR);
4626 
4627                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4628                         pkt->sts24.entry_status = (uint8_t)
4629                             (pkt->sts24.entry_status & 0x3c);
4630                         comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
4631                         scsi_status_h = pkt->sts24.scsi_status_h;
4632                         scsi_status_l = pkt->sts24.scsi_status_l;
4633                         cnt = scsi_status_h & FCP_RSP_LEN_VALID ?
4634                             LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
4635                         reqs = &pkt->sts24.rsp_sense_data[cnt];
4636                 } else {
4637                         pkt->sts.entry_status = (uint8_t)
4638                             (pkt->sts.entry_status & 0x7e);
4639                         comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
4640                         scsi_status_h = pkt->sts.scsi_status_h;
4641                         scsi_status_l = pkt->sts.scsi_status_l;
4642                         reqs = &pkt->sts.req_sense_data[0];
4643                 }
4644                 if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) {
4645                         EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
4646                             pkt->sts.entry_status, tq->d_id.b24);
4647                         rval = QL_FUNCTION_PARAMETER_ERROR;
4648                 }
4649 
4650                 if (rval != QL_SUCCESS || comp_status != CS_COMPLETE ||
4651                     scsi_status_l & STATUS_CHECK) {
4652                         EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, "
4653                             "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24,
4654                             comp_status, scsi_status_h, scsi_status_l);
4655 
4656                         if (rval == QL_SUCCESS) {
4657                                 if ((comp_status == CS_TIMEOUT) ||
4658                                     (comp_status == CS_PORT_UNAVAILABLE) ||
4659                                     (comp_status == CS_PORT_LOGGED_OUT)) {
4660                                         rval = QL_FUNCTION_TIMEOUT;
4661                                         break;
4662                                 }
4663                                 rval = QL_FUNCTION_FAILED;
4664                         }
4665 
4666                         if (scsi_status_l & STATUS_CHECK) {
4667                                 EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh"
4668                                     "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
4669                                     "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0],
4670                                     reqs[1], reqs[2], reqs[3], reqs[4],
4671                                     reqs[5], reqs[6], reqs[7], reqs[8],
4672                                     reqs[9], reqs[10], reqs[11], reqs[12],
4673                                     reqs[13], reqs[14], reqs[15], reqs[16],
4674                                     reqs[17]);
4675                         }
4676                 } else {
4677                         break;
4678                 }
4679         }
4680         ql_free_dma_resource(ha, &dma_mem);
4681 
4682         QL_PRINT_9(ha, "done\n");
4683 
4684         return (rval);
4685 }
4686 
4687 /*
4688  * ql_get_buffer_data
4689  *      Copies data from user space to kernal buffer.
4690  *
4691  * Input:
4692  *      src:    User source buffer address.
4693  *      dst:    Kernal destination buffer address.
4694  *      size:   Amount of data.
4695  *      mode:   flags.
4696  *
4697  * Returns:
4698  *      Returns number of bytes transferred.
4699  *
4700  * Context:
4701  *      Kernel context.
4702  */
4703 static uint32_t
4704 ql_get_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode)
4705 {
4706         uint32_t        cnt;
4707 
4708         for (cnt = 0; cnt < size; cnt++) {
4709                 if (ddi_copyin(src++, dst++, 1, mode) != 0) {
4710                         QL_PRINT_2(NULL, "failed, ddi_copyin\n");
4711                         break;
4712                 }
4713         }
4714 
4715         return (cnt);
4716 }
4717 
4718 /*
4719  * ql_send_buffer_data
4720  *      Copies data from kernal buffer to user space.
4721  *
4722  * Input:
4723  *      src:    Kernal source buffer address.
4724  *      dst:    User destination buffer address.
4725  *      size:   Amount of data.
4726  *      mode:   flags.
4727  *
4728  * Returns:
4729  *      Returns number of bytes transferred.
4730  *
4731  * Context:
4732  *      Kernel context.
4733  */
4734 static uint32_t
4735 ql_send_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode)
4736 {
4737         uint32_t        cnt;
4738 
4739         for (cnt = 0; cnt < size; cnt++) {
4740                 if (ddi_copyout(src++, dst++, 1, mode) != 0) {
4741                         QL_PRINT_2(NULL, "failed, ddi_copyin\n");
4742                         break;
4743                 }
4744         }
4745 
4746         return (cnt);
4747 }
4748 
4749 /*
4750  * ql_find_port
4751  *      Locates device queue.
4752  *
4753  * Input:
4754  *      ha:     adapter state pointer.
4755  *      name:   device port name.
4756  *
4757  * Returns:
4758  *      Returns target queue pointer.
4759  *
4760  * Context:
4761  *      Kernel context.
4762  */
4763 static ql_tgt_t *
4764 ql_find_port(ql_adapter_state_t *ha, uint8_t *name, uint16_t type)
4765 {
4766         ql_link_t       *link;
4767         ql_tgt_t        *tq;
4768         uint16_t        index;
4769 
4770         /* Scan port list for requested target */
4771         for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
4772                 for (link = ha->dev[index].first; link != NULL;
4773                     link = link->next) {
4774                         tq = link->base_address;
4775 
4776                         switch (type) {
4777                         case QLNT_LOOP_ID:
4778                                 if (bcmp(name, &tq->loop_id,
4779                                     sizeof (uint16_t)) == 0) {
4780                                         return (tq);
4781                                 }
4782                                 break;
4783                         case QLNT_PORT:
4784                                 if (bcmp(name, tq->port_name, 8) == 0) {
4785                                         return (tq);
4786                                 }
4787                                 break;
4788                         case QLNT_NODE:
4789                                 if (bcmp(name, tq->node_name, 8) == 0) {
4790                                         return (tq);
4791                                 }
4792                                 break;
4793                         case QLNT_PID:
4794                                 if (bcmp(name, tq->d_id.r.d_id,
4795                                     sizeof (tq->d_id.r.d_id)) == 0) {
4796                                         return (tq);
4797                                 }
4798                                 break;
4799                         default:
4800                                 EL(ha, "failed, invalid type=%d\n", type);
4801                                 return (NULL);
4802                         }
4803                 }
4804         }
4805 
4806         return (NULL);
4807 }
4808 
4809 /*
4810  * ql_24xx_flash_desc
4811  *      Get flash descriptor table.
4812  *
4813  * Input:
4814  *      ha:             adapter state pointer.
4815  *
4816  * Returns:
4817  *      ql local function return status code.
4818  *
4819  * Context:
4820  *      Kernel context.
4821  */
4822 static int
4823 ql_24xx_flash_desc(ql_adapter_state_t *ha)
4824 {
4825         uint32_t        cnt;
4826         uint16_t        chksum, *bp, data;
4827         int             rval;
4828         flash_desc_t    *fdesc;
4829         ql_xioctl_t     *xp = ha->xioctl;
4830 
4831         QL_PRINT_9(ha, "started\n");
4832 
4833         if (ha->flash_desc_addr == 0) {
4834                 QL_PRINT_9(ha, "desc ptr=0\n");
4835                 return (QL_FUNCTION_FAILED);
4836         }
4837 
4838         if ((fdesc = kmem_zalloc(sizeof (flash_desc_t), KM_SLEEP)) == NULL) {
4839                 EL(ha, "kmem_zalloc=null\n");
4840                 return (QL_MEMORY_ALLOC_FAILED);
4841         }
4842         rval = ql_dump_fcode(ha, (uint8_t *)fdesc, sizeof (flash_desc_t),
4843             ha->flash_desc_addr << 2);
4844         if (rval != QL_SUCCESS) {
4845                 EL(ha, "read status=%xh\n", rval);
4846                 kmem_free(fdesc, sizeof (flash_desc_t));
4847                 return (rval);
4848         }
4849 
4850         chksum = 0;
4851         bp = (uint16_t *)fdesc;
4852         for (cnt = 0; cnt < (sizeof (flash_desc_t)) / 2; cnt++) {
4853                 data = *bp++;
4854                 LITTLE_ENDIAN_16(&data);
4855                 chksum += data;
4856         }
4857 
4858         LITTLE_ENDIAN_32(&fdesc->flash_valid);
4859         LITTLE_ENDIAN_16(&fdesc->flash_version);
4860         LITTLE_ENDIAN_16(&fdesc->flash_len);
4861         LITTLE_ENDIAN_16(&fdesc->flash_checksum);
4862         LITTLE_ENDIAN_16(&fdesc->flash_manuf);
4863         LITTLE_ENDIAN_16(&fdesc->flash_id);
4864         LITTLE_ENDIAN_32(&fdesc->block_size);
4865         LITTLE_ENDIAN_32(&fdesc->alt_block_size);
4866         LITTLE_ENDIAN_32(&fdesc->flash_size);
4867         LITTLE_ENDIAN_32(&fdesc->write_enable_data);
4868         LITTLE_ENDIAN_32(&fdesc->read_timeout);
4869 
4870         /* flash size in desc table is in 1024 bytes */
4871         fdesc->flash_size = fdesc->flash_size * 0x400;
4872 
4873         if (chksum != 0 || fdesc->flash_valid != FLASH_DESC_VAILD ||
4874             fdesc->flash_version != FLASH_DESC_VERSION) {
4875                 EL(ha, "invalid descriptor table\n");
4876                 kmem_free(fdesc, sizeof (flash_desc_t));
4877                 return (QL_FUNCTION_FAILED);
4878         }
4879 
4880         bcopy(fdesc, &xp->fdesc, sizeof (flash_desc_t));
4881         kmem_free(fdesc, sizeof (flash_desc_t));
4882 
4883         QL_PRINT_9(ha, "done\n");
4884 
4885         return (QL_SUCCESS);
4886 }
4887 
4888 /*
4889  * ql_setup_flash
4890  *      Gets the manufacturer and id number of the flash chip, and
4891  *      sets up the size parameter.
4892  *
4893  * Input:
4894  *      ha:     adapter state pointer.
4895  *
4896  * Returns:
4897  *      int:    ql local function return status code.
4898  *
4899  * Context:
4900  *      Kernel context.
4901  */
4902 static int
4903 ql_setup_flash(ql_adapter_state_t *ha)
4904 {
4905         ql_xioctl_t     *xp = ha->xioctl;
4906         int             rval = QL_SUCCESS;
4907 
4908         if (xp->fdesc.flash_size != 0) {
4909                 return (rval);
4910         }
4911 
4912         if (CFG_IST(ha, CFG_CTRL_22XX) && !ha->subven_id) {
4913                 return (QL_FUNCTION_FAILED);
4914         }
4915 
4916         if (CFG_IST(ha, CFG_CTRL_252780818283)) {
4917                 /*
4918                  * Temporarily set the ha->xioctl->fdesc.flash_size to
4919                  * 25xx flash size to avoid failing of ql_dump_focde.
4920                  */
4921                 if (CFG_IST(ha, CFG_CTRL_278083)) {
4922                         ha->xioctl->fdesc.flash_size = 0x1000000;
4923                 } else if (CFG_IST(ha, CFG_CTRL_82XX)) {
4924                         ha->xioctl->fdesc.flash_size = 0x800000;
4925                 } else if (CFG_IST(ha, CFG_CTRL_25XX)) {
4926                         ha->xioctl->fdesc.flash_size = 0x200000;
4927                 } else {
4928                         ha->xioctl->fdesc.flash_size = 0x400000;
4929                 }
4930 
4931                 if (ql_24xx_flash_desc(ha) == QL_SUCCESS) {
4932                         EL(ha, "flash desc table ok, exit\n");
4933                         return (rval);
4934                 }
4935                 if (CFG_IST(ha, CFG_CTRL_82XX)) {
4936                         xp->fdesc.flash_manuf = MXIC_FLASH;
4937                         xp->fdesc.flash_id = MXIC_FLASHID_25LXX;
4938                         xp->fdesc.flash_len = 0x17;
4939                 } else {
4940                         (void) ql_24xx_flash_id(ha);
4941                 }
4942 
4943         } else if (CFG_IST(ha, CFG_CTRL_24XX)) {
4944                 (void) ql_24xx_flash_id(ha);
4945         } else {
4946                 ql_flash_enable(ha);
4947 
4948                 ql_write_flash_byte(ha, 0x5555, 0xaa);
4949                 ql_write_flash_byte(ha, 0x2aaa, 0x55);
4950                 ql_write_flash_byte(ha, 0x5555, 0x90);
4951                 xp->fdesc.flash_manuf = (uint8_t)ql_read_flash_byte(ha, 0x0000);
4952 
4953                 if (CFG_IST(ha, CFG_SBUS_CARD)) {
4954                         ql_write_flash_byte(ha, 0xaaaa, 0xaa);
4955                         ql_write_flash_byte(ha, 0x5555, 0x55);
4956                         ql_write_flash_byte(ha, 0xaaaa, 0x90);
4957                         xp->fdesc.flash_id = (uint16_t)
4958                             ql_read_flash_byte(ha, 0x0002);
4959                 } else {
4960                         ql_write_flash_byte(ha, 0x5555, 0xaa);
4961                         ql_write_flash_byte(ha, 0x2aaa, 0x55);
4962                         ql_write_flash_byte(ha, 0x5555, 0x90);
4963                         xp->fdesc.flash_id = (uint16_t)
4964                             ql_read_flash_byte(ha, 0x0001);
4965                 }
4966 
4967                 ql_write_flash_byte(ha, 0x5555, 0xaa);
4968                 ql_write_flash_byte(ha, 0x2aaa, 0x55);
4969                 ql_write_flash_byte(ha, 0x5555, 0xf0);
4970 
4971                 ql_flash_disable(ha);
4972         }
4973 
4974         /* Default flash descriptor table. */
4975         xp->fdesc.write_statusreg_cmd = 1;
4976         xp->fdesc.write_enable_bits = 0;
4977         xp->fdesc.unprotect_sector_cmd = 0;
4978         xp->fdesc.protect_sector_cmd = 0;
4979         xp->fdesc.write_disable_bits = 0xbc;
4980         xp->fdesc.block_size = 0x10000;
4981         xp->fdesc.erase_cmd = 0xd8;
4982 
4983         switch (xp->fdesc.flash_manuf) {
4984         case AMD_FLASH:
4985                 switch (xp->fdesc.flash_id) {
4986                 case SPAN_FLASHID_16384K:
4987                         if (xp->fdesc.flash_len == 0x18) {
4988                                 xp->fdesc.flash_size = 0x1000000;
4989                         } else {
4990                                 rval = QL_FUNCTION_FAILED;
4991                         }
4992                         break;
4993                 case SPAN_FLASHID_2048K:
4994                         xp->fdesc.flash_size = 0x200000;
4995                         break;
4996                 case AMD_FLASHID_1024K:
4997                         xp->fdesc.flash_size = 0x100000;
4998                         break;
4999                 case AMD_FLASHID_512K:
5000                 case AMD_FLASHID_512Kt:
5001                 case AMD_FLASHID_512Kb:
5002                         if (CFG_IST(ha, CFG_SBUS_CARD)) {
5003                                 xp->fdesc.flash_size = QL_SBUS_FCODE_SIZE;
5004                         } else {
5005                                 xp->fdesc.flash_size = 0x80000;
5006                         }
5007                         break;
5008                 case AMD_FLASHID_128K:
5009                         xp->fdesc.flash_size = 0x20000;
5010                         break;
5011                 default:
5012                         rval = QL_FUNCTION_FAILED;
5013                         break;
5014                 }
5015                 break;
5016         case ST_FLASH:
5017                 switch (xp->fdesc.flash_id) {
5018                 case ST_FLASHID_128K:
5019                         xp->fdesc.flash_size = 0x20000;
5020                         break;
5021                 case ST_FLASHID_512K:
5022                         xp->fdesc.flash_size = 0x80000;
5023                         break;
5024                 case ST_FLASHID_M25PXX:
5025                         if (xp->fdesc.flash_len == 0x14) {
5026                                 xp->fdesc.flash_size = 0x100000;
5027                         } else if (xp->fdesc.flash_len == 0x15) {
5028                                 xp->fdesc.flash_size = 0x200000;
5029                         } else {
5030                                 rval = QL_FUNCTION_FAILED;
5031                         }
5032                         break;
5033                 case ST_FLASHID_N25QXXX:
5034                         if (xp->fdesc.flash_len == 0x18) {
5035                                 xp->fdesc.flash_size = 0x1000000;
5036                         } else {
5037                                 rval = QL_FUNCTION_FAILED;
5038                         }
5039                         break;
5040                 default:
5041                         rval = QL_FUNCTION_FAILED;
5042                         break;
5043                 }
5044                 break;
5045         case SST_FLASH:
5046                 switch (xp->fdesc.flash_id) {
5047                 case SST_FLASHID_128K:
5048                         xp->fdesc.flash_size = 0x20000;
5049                         break;
5050                 case SST_FLASHID_1024K_A:
5051                         xp->fdesc.flash_size = 0x100000;
5052                         xp->fdesc.block_size = 0x8000;
5053                         xp->fdesc.erase_cmd = 0x52;
5054                         break;
5055                 case SST_FLASHID_1024K:
5056                 case SST_FLASHID_1024K_B:
5057                         xp->fdesc.flash_size = 0x100000;
5058                         break;
5059                 case SST_FLASHID_2048K:
5060                         xp->fdesc.flash_size = 0x200000;
5061                         break;
5062                 default:
5063                         rval = QL_FUNCTION_FAILED;
5064                         break;
5065                 }
5066                 break;
5067         case MXIC_FLASH:
5068                 switch (xp->fdesc.flash_id) {
5069                 case MXIC_FLASHID_512K:
5070                         xp->fdesc.flash_size = 0x80000;
5071                         break;
5072                 case MXIC_FLASHID_1024K:
5073                         xp->fdesc.flash_size = 0x100000;
5074                         break;
5075                 case MXIC_FLASHID_25LXX:
5076                         xp->fdesc.write_disable_bits = 0xbc;
5077                         if (xp->fdesc.flash_len == 0x14) {
5078                                 xp->fdesc.flash_size = 0x100000;
5079                         } else if (xp->fdesc.flash_len == 0x15) {
5080                                 xp->fdesc.flash_size = 0x200000;
5081                         } else if (xp->fdesc.flash_len == 0x16) {
5082                                 xp->fdesc.flash_size = 0x400000;
5083                         } else if (xp->fdesc.flash_len == 0x17) {
5084                                 xp->fdesc.flash_size = 0x800000;
5085                         } else if (xp->fdesc.flash_len == 0x18) {
5086                                 xp->fdesc.flash_size = 0x1000000;
5087                         } else {
5088                                 rval = QL_FUNCTION_FAILED;
5089                         }
5090                         break;
5091                 default:
5092                         rval = QL_FUNCTION_FAILED;
5093                         break;
5094                 }
5095                 break;
5096         case ATMEL_FLASH:
5097                 switch (xp->fdesc.flash_id) {
5098                 case ATMEL_FLASHID_1024K:
5099                         xp->fdesc.flash_size = 0x100000;
5100                         xp->fdesc.write_disable_bits = 0xbc;
5101                         xp->fdesc.unprotect_sector_cmd = 0x39;
5102                         xp->fdesc.protect_sector_cmd = 0x36;
5103                         break;
5104                 default:
5105                         rval = QL_FUNCTION_FAILED;
5106                         break;
5107                 }
5108                 break;
5109         case WINBOND_FLASH:
5110                 switch (xp->fdesc.flash_id) {
5111                 case WINBOND_FLASHID:
5112                         if (xp->fdesc.flash_len == 0x15) {
5113                                 xp->fdesc.flash_size = 0x200000;
5114                         } else if (xp->fdesc.flash_len == 0x16) {
5115                                 xp->fdesc.flash_size = 0x400000;
5116                         } else if (xp->fdesc.flash_len == 0x17) {
5117                                 xp->fdesc.flash_size = 0x800000;
5118                         } else if (xp->fdesc.flash_len == 0x18) {
5119                                 xp->fdesc.flash_size = 0x1000000;
5120                         } else {
5121                                 rval = QL_FUNCTION_FAILED;
5122                         }
5123                         break;
5124                 default:
5125                         rval = QL_FUNCTION_FAILED;
5126                         break;
5127                 }
5128                 break;
5129         case INTEL_FLASH:
5130                 switch (xp->fdesc.flash_id) {
5131                 case INTEL_FLASHID:
5132                         if (xp->fdesc.flash_len == 0x11) {
5133                                 xp->fdesc.flash_size = 0x200000;
5134                         } else if (xp->fdesc.flash_len == 0x12) {
5135                                 xp->fdesc.flash_size = 0x400000;
5136                         } else if (xp->fdesc.flash_len == 0x13) {
5137                                 xp->fdesc.flash_size = 0x800000;
5138                         } else {
5139                                 rval = QL_FUNCTION_FAILED;
5140                         }
5141                         break;
5142                 default:
5143                         rval = QL_FUNCTION_FAILED;
5144                         break;
5145                 }
5146                 break;
5147         case EON_FLASH:
5148                 switch (xp->fdesc.flash_id) {
5149                 case EON_FLASHID_EN25QXXX:
5150                         if (xp->fdesc.flash_len == 0x18) {
5151                                 xp->fdesc.flash_size = 0x1000000;
5152                         } else {
5153                                 rval = QL_FUNCTION_FAILED;
5154                         }
5155                         break;
5156                 default:
5157                         rval = QL_FUNCTION_FAILED;
5158                         break;
5159                 }
5160                 break;
5161         default:
5162                 rval = QL_FUNCTION_FAILED;
5163                 break;
5164         }
5165 
5166         /* Try flash table later. */
5167         if (rval != QL_SUCCESS && CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5168                 EL(ha, "no default id\n");
5169                 return (QL_SUCCESS);
5170         }
5171 
5172         /*
5173          * hack for non std 2312/2322 and 6312/6322 boards. hardware people
5174          * need to use either the 128k flash chip (original), or something
5175          * larger. For driver purposes, we'll treat it as a 128k flash chip.
5176          */
5177         if ((ha->device_id == 0x2312 || ha->device_id == 0x6312 ||
5178             ha->device_id == 0x2322 || ha->device_id == 0x6322) &&
5179             (xp->fdesc.flash_size > 0x20000) &&
5180             (CFG_IST(ha, CFG_SBUS_CARD) == 0)) {
5181                 EL(ha, "chip exceeds max size: %xh, using 128k\n",
5182                     xp->fdesc.flash_size);
5183                 xp->fdesc.flash_size = 0x20000;
5184         }
5185 
5186         if (rval == QL_SUCCESS) {
5187                 EL(ha, "man_id=%xh, flash_id=%xh, size=%xh\n",
5188                     xp->fdesc.flash_manuf, xp->fdesc.flash_id,
5189                     xp->fdesc.flash_size);
5190         } else {
5191                 EL(ha, "unsupported mfr / type: man_id=%xh, flash_id=%xh\n",
5192                     xp->fdesc.flash_manuf, xp->fdesc.flash_id);
5193         }
5194 
5195         return (rval);
5196 }
5197 
5198 /*
5199  * ql_flash_fcode_load
5200  *      Loads fcode data into flash from application.
5201  *
5202  * Input:
5203  *      ha:     adapter state pointer.
5204  *      bp:     user buffer address.
5205  *      size:   user buffer size.
5206  *      mode:   flags
5207  *
5208  * Returns:
5209  *
5210  * Context:
5211  *      Kernel context.
5212  */
5213 static int
5214 ql_flash_fcode_load(ql_adapter_state_t *ha, void *bp, uint32_t bsize,
5215     int mode)
5216 {
5217         uint8_t         *bfp;
5218         ql_xioctl_t     *xp = ha->xioctl;
5219         int             rval = 0;
5220 
5221         QL_PRINT_9(ha, "started\n");
5222 
5223         if (bsize > xp->fdesc.flash_size) {
5224                 EL(ha, "failed, bufsize: %xh, flash size: %xh\n", bsize,
5225                     xp->fdesc.flash_size);
5226                 return (ENOMEM);
5227         }
5228 
5229         if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
5230                 EL(ha, "failed, kmem_zalloc\n");
5231                 rval = ENOMEM;
5232         } else {
5233                 if (ddi_copyin(bp, bfp, bsize, mode) != 0) {
5234                         EL(ha, "failed, ddi_copyin\n");
5235                         rval = EFAULT;
5236                 } else if (ql_load_fcode(ha, bfp, bsize, 0) != QL_SUCCESS) {
5237                         EL(ha, "failed, load_fcode\n");
5238                         rval = EFAULT;
5239                 } else {
5240                         /* Reset caches on all adapter instances. */
5241                         ql_update_flash_caches(ha);
5242                         rval = 0;
5243                 }
5244                 kmem_free(bfp, bsize);
5245         }
5246 
5247         QL_PRINT_9(ha, "done\n");
5248 
5249         return (rval);
5250 }
5251 
5252 /*
5253  * ql_load_fcode
5254  *      Loads fcode in to flash.
5255  *
5256  * Input:
5257  *      ha:     adapter state pointer.
5258  *      dp:     data pointer.
5259  *      size:   data length.
5260  *      addr:   flash byte address.
5261  *
5262  * Returns:
5263  *      ql local function return status code.
5264  *
5265  * Context:
5266  *      Kernel context.
5267  */
5268 int
5269 ql_load_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size, uint32_t addr)
5270 {
5271         uint32_t        cnt;
5272         int             rval;
5273 
5274         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5275                 return (ql_24xx_load_flash(ha, dp, size, addr));
5276         }
5277 
5278         QL_PRINT_9(ha, "started\n");
5279 
5280         if (CFG_IST(ha, CFG_SBUS_CARD)) {
5281                 /*
5282                  * sbus has an additional check to make
5283                  * sure they don't brick the HBA.
5284                  */
5285                 if (dp[0] != 0xf1) {
5286                         EL(ha, "failed, incorrect fcode for sbus\n");
5287                         return (QL_FUNCTION_PARAMETER_ERROR);
5288                 }
5289         }
5290 
5291         GLOBAL_HW_LOCK();
5292 
5293         /* Enable Flash Read/Write. */
5294         ql_flash_enable(ha);
5295 
5296         /* Erase flash prior to write. */
5297         rval = ql_erase_flash(ha, 0);
5298 
5299         if (rval == QL_SUCCESS) {
5300                 /* Write fcode data to flash. */
5301                 for (cnt = 0; cnt < (uint32_t)size; cnt++) {
5302                         /* Allow other system activity. */
5303                         if (cnt % 0x1000 == 0) {
5304                                 drv_usecwait(1);
5305                         }
5306                         rval = ql_program_flash_address(ha, addr++, *dp++);
5307                         if (rval != QL_SUCCESS)
5308                                 break;
5309                 }
5310         }
5311 
5312         ql_flash_disable(ha);
5313 
5314         GLOBAL_HW_UNLOCK();
5315 
5316         if (rval != QL_SUCCESS) {
5317                 EL(ha, "failed, rval=%xh\n", rval);
5318         } else {
5319                 /*EMPTY*/
5320                 QL_PRINT_9(ha, "done\n");
5321         }
5322         return (rval);
5323 }
5324 
5325 /*
5326  * ql_flash_fcode_dump
5327  *      Dumps FLASH to application.
5328  *
5329  * Input:
5330  *      ha:     adapter state pointer.
5331  *      bp:     user buffer address.
5332  *      bsize:  user buffer size
5333  *      faddr:  flash byte address
5334  *      mode:   flags
5335  *
5336  * Returns:
5337  *
5338  * Context:
5339  *      Kernel context.
5340  */
5341 static int
5342 ql_flash_fcode_dump(ql_adapter_state_t *ha, void *bp, uint32_t bsize,
5343     uint32_t faddr, int mode)
5344 {
5345         uint8_t         *bfp;
5346         int             rval;
5347         ql_xioctl_t     *xp = ha->xioctl;
5348 
5349         QL_PRINT_9(ha, "started\n");
5350 
5351         /* adjust max read size to flash size */
5352         if (bsize > xp->fdesc.flash_size) {
5353                 EL(ha, "adjusting req=%xh, max=%xh\n", bsize,
5354                     xp->fdesc.flash_size);
5355                 bsize = xp->fdesc.flash_size;
5356         }
5357 
5358         if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
5359                 EL(ha, "failed, kmem_zalloc\n");
5360                 rval = ENOMEM;
5361         } else {
5362                 /* Dump Flash fcode. */
5363                 rval = ql_dump_fcode(ha, bfp, bsize, faddr);
5364 
5365                 if (rval != QL_SUCCESS) {
5366                         EL(ha, "failed, dump_fcode = %x\n", rval);
5367                         rval = EFAULT;
5368                 } else if (ddi_copyout(bfp, bp, bsize, mode) != 0) {
5369                         EL(ha, "failed, ddi_copyout\n");
5370                         rval = EFAULT;
5371                 } else {
5372                         rval = 0;
5373                 }
5374                 kmem_free(bfp, bsize);
5375         }
5376 
5377         QL_PRINT_9(ha, "done\n");
5378 
5379         return (rval);
5380 }
5381 
5382 /*
5383  * ql_dump_fcode
5384  *      Dumps fcode from flash.
5385  *
5386  * Input:
5387  *      ha:             adapter state pointer.
5388  *      dp:             data pointer.
5389  *      size:           data length in bytes.
5390  *      startpos:       starting position in flash (byte address).
5391  *
5392  * Returns:
5393  *      ql local function return status code.
5394  *
5395  * Context:
5396  *      Kernel context.
5397  *
5398  */
5399 int
5400 ql_dump_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size,
5401     uint32_t startpos)
5402 {
5403         uint32_t        cnt, data, addr;
5404         uint8_t         bp[4], *src;
5405         int             fp_rval, rval = QL_SUCCESS;
5406         dma_mem_t       mem;
5407 
5408         QL_PRINT_9(ha, "started\n");
5409 
5410         /* make sure startpos+size doesn't exceed flash */
5411         if (size + startpos > ha->xioctl->fdesc.flash_size) {
5412                 EL(ha, "exceeded flash range, sz=%xh, stp=%xh, flsz=%xh\n",
5413                     size, startpos, ha->xioctl->fdesc.flash_size);
5414                 return (QL_FUNCTION_PARAMETER_ERROR);
5415         }
5416 
5417         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5418                 /* check start addr is 32 bit aligned for 24xx */
5419                 if ((startpos & 0x3) != 0) {
5420                         rval = ql_24xx_read_flash(ha,
5421                             ha->flash_data_addr | startpos >> 2, &data);
5422                         if (rval != QL_SUCCESS) {
5423                                 EL(ha, "failed2, rval = %xh\n", rval);
5424                                 return (rval);
5425                         }
5426                         bp[0] = LSB(LSW(data));
5427                         bp[1] = MSB(LSW(data));
5428                         bp[2] = LSB(MSW(data));
5429                         bp[3] = MSB(MSW(data));
5430                         while (size && startpos & 0x3) {
5431                                 *dp++ = bp[startpos & 0x3];
5432                                 startpos++;
5433                                 size--;
5434                         }
5435                         if (size == 0) {
5436                                 QL_PRINT_9(ha, "done2\n",
5437                                     ha->instance);
5438                                 return (rval);
5439                         }
5440                 }
5441 
5442                 /* adjust 24xx start addr for 32 bit words */
5443                 addr = startpos / 4 | ha->flash_data_addr;
5444         }
5445 
5446         bzero(&mem, sizeof (dma_mem_t));
5447         /* Check for Fast page is supported */
5448         if ((ha->pha->task_daemon_flags & FIRMWARE_UP) &&
5449             (CFG_IST(ha, CFG_FLASH_DMA_SUPPORT))) {
5450                 fp_rval = QL_SUCCESS;
5451                 /* Setup DMA buffer. */
5452                 rval = ql_get_dma_mem(ha, &mem, size,
5453                     LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN);
5454                 if (rval != QL_SUCCESS) {
5455                         EL(ha, "failed, ql_get_dma_mem=%xh\n",
5456                             rval);
5457                         return (ENOMEM);
5458                 }
5459         } else {
5460                 fp_rval = QL_NOT_SUPPORTED;
5461         }
5462 
5463         GLOBAL_HW_LOCK();
5464 
5465         /* Enable Flash Read/Write. */
5466         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
5467                 ql_flash_enable(ha);
5468         }
5469 
5470         /* Read fcode data from flash. */
5471         while (size) {
5472                 /* Allow other system activity. */
5473                 if (size % 0x1000 == 0) {
5474                         ql_delay(ha, 10000);
5475                 }
5476                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5477                         if (fp_rval == QL_SUCCESS && (addr & 0x3f) == 0) {
5478                                 cnt = (size + 3) >> 2;
5479                                 fp_rval = ql_rd_risc_ram(ha, addr,
5480                                     mem.cookie.dmac_laddress, cnt);
5481                                 if (fp_rval == QL_SUCCESS) {
5482                                         for (src = mem.bp; size; size--) {
5483                                                 *dp++ = *src++;
5484                                         }
5485                                         addr += cnt;
5486                                         continue;
5487                                 }
5488                         }
5489                         rval = ql_24xx_read_flash(ha, addr++,
5490                             &data);
5491                         if (rval != QL_SUCCESS) {
5492                                 break;
5493                         }
5494                         bp[0] = LSB(LSW(data));
5495                         bp[1] = MSB(LSW(data));
5496                         bp[2] = LSB(MSW(data));
5497                         bp[3] = MSB(MSW(data));
5498                         for (cnt = 0; size && cnt < 4; size--) {
5499                                 *dp++ = bp[cnt++];
5500                         }
5501                 } else {
5502                         *dp++ = (uint8_t)ql_read_flash_byte(ha, startpos++);
5503                         size--;
5504                 }
5505         }
5506 
5507         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
5508                 ql_flash_disable(ha);
5509         }
5510 
5511         GLOBAL_HW_UNLOCK();
5512 
5513         if (mem.dma_handle != NULL) {
5514                 ql_free_dma_resource(ha, &mem);
5515         }
5516 
5517         if (rval != QL_SUCCESS) {
5518                 EL(ha, "failed, rval = %xh\n", rval);
5519         } else {
5520                 /*EMPTY*/
5521                 QL_PRINT_9(ha, "done\n");
5522         }
5523         return (rval);
5524 }
5525 
5526 /*
5527  * ql_program_flash_address
5528  *      Program flash address.
5529  *
5530  * Input:
5531  *      ha:     adapter state pointer.
5532  *      addr:   flash byte address.
5533  *      data:   data to be written to flash.
5534  *
5535  * Returns:
5536  *      ql local function return status code.
5537  *
5538  * Context:
5539  *      Kernel context.
5540  */
5541 static int
5542 ql_program_flash_address(ql_adapter_state_t *ha, uint32_t addr,
5543     uint8_t data)
5544 {
5545         int     rval;
5546 
5547         /* Write Program Command Sequence */
5548         if (CFG_IST(ha, CFG_SBUS_CARD)) {
5549                 ql_write_flash_byte(ha, 0x5555, 0xa0);
5550                 ql_write_flash_byte(ha, addr, data);
5551         } else {
5552                 ql_write_flash_byte(ha, 0x5555, 0xaa);
5553                 ql_write_flash_byte(ha, 0x2aaa, 0x55);
5554                 ql_write_flash_byte(ha, 0x5555, 0xa0);
5555                 ql_write_flash_byte(ha, addr, data);
5556         }
5557 
5558         /* Wait for write to complete. */
5559         rval = ql_poll_flash(ha, addr, data);
5560 
5561         if (rval != QL_SUCCESS) {
5562                 EL(ha, "failed, rval=%xh\n", rval);
5563         }
5564         return (rval);
5565 }
5566 
5567 /*
5568  * ql_set_rnid_parameters
5569  *      Set RNID parameters.
5570  *
5571  * Input:
5572  *      ha:     adapter state pointer.
5573  *      cmd:    User space CT arguments pointer.
5574  *      mode:   flags.
5575  */
5576 static void
5577 ql_set_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5578 {
5579         EXT_SET_RNID_REQ        tmp_set;
5580         EXT_RNID_DATA           *tmp_buf;
5581         int                     rval = 0;
5582 
5583         QL_PRINT_9(ha, "started\n");
5584 
5585         if (DRIVER_SUSPENDED(ha)) {
5586                 EL(ha, "failed, LOOP_NOT_READY\n");
5587                 cmd->Status = EXT_STATUS_BUSY;
5588                 cmd->ResponseLen = 0;
5589                 return;
5590         }
5591 
5592         cmd->ResponseLen = 0; /* NO response to caller. */
5593         if (cmd->RequestLen != sizeof (EXT_SET_RNID_REQ)) {
5594                 /* parameter error */
5595                 EL(ha, "failed, RequestLen < EXT_SET_RNID_REQ, Len=%xh\n",
5596                     cmd->RequestLen);
5597                 cmd->Status = EXT_STATUS_INVALID_PARAM;
5598                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
5599                 cmd->ResponseLen = 0;
5600                 return;
5601         }
5602 
5603         rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &tmp_set,
5604             cmd->RequestLen, mode);
5605         if (rval != 0) {
5606                 EL(ha, "failed, ddi_copyin\n");
5607                 cmd->Status = EXT_STATUS_COPY_ERR;
5608                 cmd->ResponseLen = 0;
5609                 return;
5610         }
5611 
5612         /* Allocate memory for command. */
5613         tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP);
5614         if (tmp_buf == NULL) {
5615                 EL(ha, "failed, kmem_zalloc\n");
5616                 cmd->Status = EXT_STATUS_NO_MEMORY;
5617                 cmd->ResponseLen = 0;
5618                 return;
5619         }
5620 
5621         rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA),
5622             (caddr_t)tmp_buf);
5623         if (rval != QL_SUCCESS) {
5624                 /* error */
5625                 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
5626                 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5627                 cmd->Status = EXT_STATUS_ERR;
5628                 cmd->ResponseLen = 0;
5629                 return;
5630         }
5631 
5632         /* Now set the requested params. */
5633         bcopy(tmp_set.IPVersion, tmp_buf->IPVersion, 2);
5634         bcopy(tmp_set.UDPPortNumber, tmp_buf->UDPPortNumber, 2);
5635         bcopy(tmp_set.IPAddress, tmp_buf->IPAddress, 16);
5636 
5637         rval = ql_set_rnid_params(ha, sizeof (EXT_RNID_DATA),
5638             (caddr_t)tmp_buf);
5639         if (rval != QL_SUCCESS) {
5640                 /* error */
5641                 EL(ha, "failed, set_rnid_params_mbx=%xh\n", rval);
5642                 cmd->Status = EXT_STATUS_ERR;
5643                 cmd->ResponseLen = 0;
5644         }
5645 
5646         kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5647 
5648         QL_PRINT_9(ha, "done\n");
5649 }
5650 
5651 /*
5652  * ql_get_rnid_parameters
5653  *      Get RNID parameters.
5654  *
5655  * Input:
5656  *      ha:     adapter state pointer.
5657  *      cmd:    User space CT arguments pointer.
5658  *      mode:   flags.
5659  */
5660 static void
5661 ql_get_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5662 {
5663         EXT_RNID_DATA   *tmp_buf;
5664         uint32_t        rval;
5665 
5666         QL_PRINT_9(ha, "started\n");
5667 
5668         if (DRIVER_SUSPENDED(ha)) {
5669                 EL(ha, "failed, LOOP_NOT_READY\n");
5670                 cmd->Status = EXT_STATUS_BUSY;
5671                 cmd->ResponseLen = 0;
5672                 return;
5673         }
5674 
5675         /* Allocate memory for command. */
5676         tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP);
5677         if (tmp_buf == NULL) {
5678                 EL(ha, "failed, kmem_zalloc\n");
5679                 cmd->Status = EXT_STATUS_NO_MEMORY;
5680                 cmd->ResponseLen = 0;
5681                 return;
5682         }
5683 
5684         /* Send command */
5685         rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA),
5686             (caddr_t)tmp_buf);
5687         if (rval != QL_SUCCESS) {
5688                 /* error */
5689                 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
5690                 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5691                 cmd->Status = EXT_STATUS_ERR;
5692                 cmd->ResponseLen = 0;
5693                 return;
5694         }
5695 
5696         /* Copy the response */
5697         if (ql_send_buffer_data((caddr_t)tmp_buf,
5698             (caddr_t)(uintptr_t)cmd->ResponseAdr,
5699             sizeof (EXT_RNID_DATA), mode) != sizeof (EXT_RNID_DATA)) {
5700                 EL(ha, "failed, ddi_copyout\n");
5701                 cmd->Status = EXT_STATUS_COPY_ERR;
5702                 cmd->ResponseLen = 0;
5703         } else {
5704                 QL_PRINT_9(ha, "done\n");
5705                 cmd->ResponseLen = sizeof (EXT_RNID_DATA);
5706         }
5707 
5708         kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5709 }
5710 
5711 /*
5712  * ql_reset_statistics
5713  *      Performs EXT_SC_RST_STATISTICS subcommand. of EXT_CC_SET_DATA.
5714  *
5715  * Input:
5716  *      ha:     adapter state pointer.
5717  *      cmd:    Local EXT_IOCTL cmd struct pointer.
5718  *
5719  * Returns:
5720  *      None, request status indicated in cmd->Status.
5721  *
5722  * Context:
5723  *      Kernel context.
5724  */
5725 static int
5726 ql_reset_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd)
5727 {
5728         ql_xioctl_t             *xp = ha->xioctl;
5729         int                     rval = 0;
5730 
5731         QL_PRINT_9(ha, "started\n");
5732 
5733         if (DRIVER_SUSPENDED(ha)) {
5734                 EL(ha, "failed, LOOP_NOT_READY\n");
5735                 cmd->Status = EXT_STATUS_BUSY;
5736                 cmd->ResponseLen = 0;
5737                 return (QL_FUNCTION_SUSPENDED);
5738         }
5739 
5740         rval = ql_reset_link_status(ha);
5741         if (rval != QL_SUCCESS) {
5742                 EL(ha, "failed, reset_link_status_mbx=%xh\n", rval);
5743                 cmd->Status = EXT_STATUS_MAILBOX;
5744                 cmd->DetailStatus = rval;
5745                 cmd->ResponseLen = 0;
5746         }
5747 
5748         TASK_DAEMON_LOCK(ha);
5749         xp->IosRequested = 0;
5750         xp->BytesRequested = 0;
5751         xp->IOInputRequests = 0;
5752         xp->IOOutputRequests = 0;
5753         xp->IOControlRequests = 0;
5754         xp->IOInputMByteCnt = 0;
5755         xp->IOOutputMByteCnt = 0;
5756         xp->IOOutputByteCnt = 0;
5757         xp->IOInputByteCnt = 0;
5758         TASK_DAEMON_UNLOCK(ha);
5759 
5760         INTR_LOCK(ha);
5761         xp->ControllerErrorCount = 0;
5762         xp->DeviceErrorCount = 0;
5763         xp->TotalLipResets = 0;
5764         xp->TotalInterrupts = 0;
5765         INTR_UNLOCK(ha);
5766 
5767         QL_PRINT_9(ha, "done\n");
5768 
5769         return (rval);
5770 }
5771 
5772 /*
5773  * ql_get_statistics
5774  *      Performs EXT_SC_GET_STATISTICS subcommand. of EXT_CC_GET_DATA.
5775  *
5776  * Input:
5777  *      ha:     adapter state pointer.
5778  *      cmd:    Local EXT_IOCTL cmd struct pointer.
5779  *      mode:   flags.
5780  *
5781  * Returns:
5782  *      None, request status indicated in cmd->Status.
5783  *
5784  * Context:
5785  *      Kernel context.
5786  */
5787 static void
5788 ql_get_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5789 {
5790         EXT_HBA_PORT_STAT       ps = {0};
5791         ql_link_stats_t         *ls;
5792         int                     rval;
5793         ql_xioctl_t             *xp = ha->xioctl;
5794         int                     retry = 10;
5795 
5796         QL_PRINT_9(ha, "started\n");
5797 
5798         while (ha->task_daemon_flags &
5799             (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) {
5800                 ql_delay(ha, 10000000); /* 10 second delay */
5801 
5802                 retry--;
5803 
5804                 if (retry == 0) { /* effectively 100 seconds */
5805                         EL(ha, "failed, LOOP_NOT_READY\n");
5806                         cmd->Status = EXT_STATUS_BUSY;
5807                         cmd->ResponseLen = 0;
5808                         return;
5809                 }
5810         }
5811 
5812         /* Allocate memory for command. */
5813         ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP);
5814         if (ls == NULL) {
5815                 EL(ha, "failed, kmem_zalloc\n");
5816                 cmd->Status = EXT_STATUS_NO_MEMORY;
5817                 cmd->ResponseLen = 0;
5818                 return;
5819         }
5820 
5821         /*
5822          * I think these are supposed to be port statistics
5823          * the loop ID or port ID should be in cmd->Instance.
5824          */
5825         rval = ql_get_status_counts(ha, (uint16_t)
5826             (ha->task_daemon_flags & LOOP_DOWN ? 0xFF : ha->loop_id),
5827             sizeof (ql_link_stats_t), (caddr_t)ls, 0);
5828         if (rval != QL_SUCCESS) {
5829                 EL(ha, "failed, get_link_status=%xh, id=%xh\n", rval,
5830                     ha->loop_id);
5831                 cmd->Status = EXT_STATUS_MAILBOX;
5832                 cmd->DetailStatus = rval;
5833                 cmd->ResponseLen = 0;
5834         } else {
5835                 ps.ControllerErrorCount = xp->ControllerErrorCount;
5836                 ps.DeviceErrorCount = xp->DeviceErrorCount;
5837                 ps.IoCount = (uint32_t)(xp->IOInputRequests +
5838                     xp->IOOutputRequests + xp->IOControlRequests);
5839                 ps.MBytesCount = (uint32_t)(xp->IOInputMByteCnt +
5840                     xp->IOOutputMByteCnt);
5841                 ps.LipResetCount = xp->TotalLipResets;
5842                 ps.InterruptCount = xp->TotalInterrupts;
5843                 ps.LinkFailureCount = LE_32(ls->link_fail_cnt);
5844                 ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt);
5845                 ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt);
5846                 ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt);
5847                 ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt);
5848                 ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt);
5849 
5850                 rval = ddi_copyout((void *)&ps,
5851                     (void *)(uintptr_t)cmd->ResponseAdr,
5852                     sizeof (EXT_HBA_PORT_STAT), mode);
5853                 if (rval != 0) {
5854                         EL(ha, "failed, ddi_copyout\n");
5855                         cmd->Status = EXT_STATUS_COPY_ERR;
5856                         cmd->ResponseLen = 0;
5857                 } else {
5858                         cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT);
5859                 }
5860         }
5861 
5862         kmem_free(ls, sizeof (ql_link_stats_t));
5863 
5864         QL_PRINT_9(ha, "done\n");
5865 }
5866 
5867 /*
5868  * ql_get_statistics_fc
5869  *      Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA.
5870  *
5871  * Input:
5872  *      ha:     adapter state pointer.
5873  *      cmd:    Local EXT_IOCTL cmd struct pointer.
5874  *      mode:   flags.
5875  *
5876  * Returns:
5877  *      None, request status indicated in cmd->Status.
5878  *
5879  * Context:
5880  *      Kernel context.
5881  */
5882 static void
5883 ql_get_statistics_fc(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5884 {
5885         EXT_HBA_PORT_STAT       ps = {0};
5886         ql_link_stats_t         *ls;
5887         int                     rval;
5888         uint16_t                qlnt;
5889         EXT_DEST_ADDR           pextdestaddr;
5890         uint8_t                 *name;
5891         ql_tgt_t                *tq = NULL;
5892         int                     retry = 10;
5893 
5894         QL_PRINT_9(ha, "started\n");
5895 
5896         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
5897             (void *)&pextdestaddr, sizeof (EXT_DEST_ADDR), mode) != 0) {
5898                 EL(ha, "failed, ddi_copyin\n");
5899                 cmd->Status = EXT_STATUS_COPY_ERR;
5900                 cmd->ResponseLen = 0;
5901                 return;
5902         }
5903 
5904         qlnt = QLNT_PORT;
5905         name = pextdestaddr.DestAddr.WWPN;
5906 
5907         QL_PRINT_9(ha, "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
5908             ha->instance, name[0], name[1], name[2], name[3], name[4],
5909             name[5], name[6], name[7]);
5910 
5911         tq = ql_find_port(ha, name, qlnt);
5912 
5913         if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
5914                 EL(ha, "failed, fc_port not found\n");
5915                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
5916                 cmd->ResponseLen = 0;
5917                 return;
5918         }
5919 
5920         while (ha->task_daemon_flags &
5921             (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) {
5922                 ql_delay(ha, 10000000); /* 10 second delay */
5923 
5924                 retry--;
5925 
5926                 if (retry == 0) { /* effectively 100 seconds */
5927                         EL(ha, "failed, LOOP_NOT_READY\n");
5928                         cmd->Status = EXT_STATUS_BUSY;
5929                         cmd->ResponseLen = 0;
5930                         return;
5931                 }
5932         }
5933 
5934         /* Allocate memory for command. */
5935         ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP);
5936         if (ls == NULL) {
5937                 EL(ha, "failed, kmem_zalloc\n");
5938                 cmd->Status = EXT_STATUS_NO_MEMORY;
5939                 cmd->ResponseLen = 0;
5940                 return;
5941         }
5942 
5943         rval = ql_get_link_status(ha, tq->loop_id, sizeof (ql_link_stats_t),
5944             (caddr_t)ls, 0);
5945         if (rval != QL_SUCCESS) {
5946                 EL(ha, "failed, get_link_status=%xh, d_id=%xh\n", rval,
5947                     tq->d_id.b24);
5948                 cmd->Status = EXT_STATUS_MAILBOX;
5949                 cmd->DetailStatus = rval;
5950                 cmd->ResponseLen = 0;
5951         } else {
5952                 ps.LinkFailureCount = LE_32(ls->link_fail_cnt);
5953                 ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt);
5954                 ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt);
5955                 ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt);
5956                 ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt);
5957                 ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt);
5958 
5959                 rval = ddi_copyout((void *)&ps,
5960                     (void *)(uintptr_t)cmd->ResponseAdr,
5961                     sizeof (EXT_HBA_PORT_STAT), mode);
5962 
5963                 if (rval != 0) {
5964                         EL(ha, "failed, ddi_copyout\n");
5965                         cmd->Status = EXT_STATUS_COPY_ERR;
5966                         cmd->ResponseLen = 0;
5967                 } else {
5968                         cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT);
5969                 }
5970         }
5971 
5972         kmem_free(ls, sizeof (ql_link_stats_t));
5973 
5974         QL_PRINT_9(ha, "done\n");
5975 }
5976 
5977 /*
5978  * ql_get_statistics_fc4
5979  *      Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA.
5980  *
5981  * Input:
5982  *      ha:     adapter state pointer.
5983  *      cmd:    Local EXT_IOCTL cmd struct pointer.
5984  *      mode:   flags.
5985  *
5986  * Returns:
5987  *      None, request status indicated in cmd->Status.
5988  *
5989  * Context:
5990  *      Kernel context.
5991  */
5992 static void
5993 ql_get_statistics_fc4(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5994 {
5995         uint32_t                rval;
5996         EXT_HBA_FC4STATISTICS   fc4stats = {0};
5997         ql_xioctl_t             *xp = ha->xioctl;
5998 
5999         QL_PRINT_9(ha, "started\n");
6000 
6001         fc4stats.InputRequests = xp->IOInputRequests;
6002         fc4stats.OutputRequests = xp->IOOutputRequests;
6003         fc4stats.ControlRequests = xp->IOControlRequests;
6004         fc4stats.InputMegabytes = xp->IOInputMByteCnt;
6005         fc4stats.OutputMegabytes = xp->IOOutputMByteCnt;
6006 
6007         rval = ddi_copyout((void *)&fc4stats,
6008             (void *)(uintptr_t)cmd->ResponseAdr,
6009             sizeof (EXT_HBA_FC4STATISTICS), mode);
6010 
6011         if (rval != 0) {
6012                 EL(ha, "failed, ddi_copyout\n");
6013                 cmd->Status = EXT_STATUS_COPY_ERR;
6014                 cmd->ResponseLen = 0;
6015         } else {
6016                 cmd->ResponseLen = sizeof (EXT_HBA_FC4STATISTICS);
6017         }
6018 
6019         QL_PRINT_9(ha, "done\n");
6020 }
6021 
6022 /*
6023  * ql_set_led_state
6024  *      Performs EXT_SET_BEACON_STATE subcommand of EXT_CC_SET_DATA.
6025  *
6026  * Input:
6027  *      ha:     adapter state pointer.
6028  *      cmd:    Local EXT_IOCTL cmd struct pointer.
6029  *      mode:   flags.
6030  *
6031  * Returns:
6032  *      None, request status indicated in cmd->Status.
6033  *
6034  * Context:
6035  *      Kernel context.
6036  */
6037 static void
6038 ql_set_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6039 {
6040         EXT_BEACON_CONTROL      bstate;
6041         int                     rval;
6042         ql_mbx_data_t           mr;
6043 
6044         QL_PRINT_9(ha, "started\n");
6045 
6046         if (cmd->RequestLen < sizeof (EXT_BEACON_CONTROL)) {
6047                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6048                 cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL);
6049                 EL(ha, "done - failed, RequestLen < EXT_BEACON_CONTROL,"
6050                     " Len=%xh\n", cmd->RequestLen);
6051                 cmd->ResponseLen = 0;
6052                 return;
6053         }
6054 
6055         if (!CFG_IST(ha, CFG_SET_LEDS_SUPPORT)) {
6056                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
6057                 cmd->DetailStatus = 0;
6058                 EL(ha, "done - failed, Invalid function for HBA model\n");
6059                 cmd->ResponseLen = 0;
6060                 return;
6061         }
6062 
6063         rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &bstate,
6064             cmd->RequestLen, mode);
6065 
6066         if (rval != 0) {
6067                 cmd->Status = EXT_STATUS_COPY_ERR;
6068                 EL(ha, "done -  failed, ddi_copyin\n");
6069                 return;
6070         }
6071 
6072         switch (bstate.State) {
6073         case EXT_DEF_GRN_BLINK_OFF:     /* turn beacon off */
6074                 if (ha->ledstate.BeaconState == BEACON_OFF) {
6075                         /* not quite an error -- LED state is already off */
6076                         cmd->Status = EXT_STATUS_OK;
6077                         EL(ha, "LED off request -- LED is already off\n");
6078                         break;
6079                 }
6080 
6081                 if (CFG_IST(ha, CFG_CTRL_82XX)) {
6082                         rval = ql_diag_beacon(ha, QL_BEACON_DISABLE,
6083                             &mr);
6084 
6085                         if (rval == QL_SUCCESS) {
6086                                 ha->ledstate.BeaconState = BEACON_OFF;
6087                                 ha->ledstate.LEDflags = LED_ALL_OFF;
6088                                 cmd->Status = EXT_STATUS_OK;
6089                         } else {
6090                                 cmd->Status = EXT_STATUS_ERR;
6091                                 EL(ha, "failed, disable beacon request %xh\n",
6092                                     bstate.State);
6093                         }
6094                         break;
6095                 }
6096 
6097                 ha->ledstate.BeaconState = BEACON_OFF;
6098                 ha->ledstate.LEDflags = LED_ALL_OFF;
6099 
6100                 if ((rval = ql_wrapup_led(ha)) != QL_SUCCESS) {
6101                         cmd->Status = EXT_STATUS_MAILBOX;
6102                 } else {
6103                         cmd->Status = EXT_STATUS_OK;
6104                 }
6105                 break;
6106 
6107         case EXT_DEF_GRN_BLINK_ON:      /* turn beacon on */
6108                 if (ha->ledstate.BeaconState == BEACON_ON) {
6109                         /* not quite an error -- LED state is already on */
6110                         cmd->Status = EXT_STATUS_OK;
6111                         EL(ha, "LED on request  - LED is already on\n");
6112                         break;
6113                 }
6114 
6115                 if (CFG_IST(ha, CFG_CTRL_82XX)) {
6116                         rval = ql_diag_beacon(ha, QL_BEACON_ENABLE,
6117                             &mr);
6118 
6119                         if (rval == QL_SUCCESS) {
6120                                 ha->ledstate.BeaconState = BEACON_ON;
6121                                 ha->ledstate.LEDflags = LED_GREEN;
6122                                 cmd->Status = EXT_STATUS_OK;
6123                         } else {
6124                                 cmd->Status = EXT_STATUS_ERR;
6125                                 EL(ha, "failed, enable beacon request %xh\n",
6126                                     bstate.State);
6127                         }
6128                         break;
6129                 }
6130 
6131                 if ((rval = ql_setup_led(ha)) != QL_SUCCESS) {
6132                         cmd->Status = EXT_STATUS_MAILBOX;
6133                         break;
6134                 }
6135 
6136                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
6137                         ha->ledstate.LEDflags = LED_YELLOW_24 | LED_AMBER_24;
6138                 } else {
6139                         ha->ledstate.LEDflags = LED_GREEN;
6140                 }
6141                 ha->ledstate.BeaconState = BEACON_ON;
6142 
6143                 cmd->Status = EXT_STATUS_OK;
6144                 break;
6145         default:
6146                 cmd->Status = EXT_STATUS_ERR;
6147                 EL(ha, "failed, unknown state request %xh\n", bstate.State);
6148                 break;
6149         }
6150 
6151         QL_PRINT_9(ha, "done\n");
6152 }
6153 
6154 /*
6155  * ql_get_led_state
6156  *      Performs EXT_GET_BEACON_STATE subcommand of EXT_CC_GET_DATA.
6157  *
6158  * Input:
6159  *      ha:     adapter state pointer.
6160  *      cmd:    Local EXT_IOCTL cmd struct pointer.
6161  *      mode:   flags.
6162  *
6163  * Returns:
6164  *      None, request status indicated in cmd->Status.
6165  *
6166  * Context:
6167  *      Kernel context.
6168  */
6169 static void
6170 ql_get_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6171 {
6172         EXT_BEACON_CONTROL      bstate = {0};
6173         uint32_t                rval;
6174 
6175         QL_PRINT_9(ha, "started\n");
6176 
6177         if (cmd->ResponseLen < sizeof (EXT_BEACON_CONTROL)) {
6178                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6179                 cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL);
6180                 EL(ha, "done - failed, ResponseLen < EXT_BEACON_CONTROL,"
6181                     "Len=%xh\n", cmd->ResponseLen);
6182                 cmd->ResponseLen = 0;
6183                 return;
6184         }
6185 
6186         if (!CFG_IST(ha, CFG_SET_LEDS_SUPPORT)) {
6187                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
6188                 cmd->DetailStatus = 0;
6189                 EL(ha, "done - failed, Invalid function for HBA model\n");
6190                 cmd->ResponseLen = 0;
6191                 return;
6192         }
6193 
6194         if (ha->task_daemon_flags & ABORT_ISP_ACTIVE) {
6195                 cmd->Status = EXT_STATUS_BUSY;
6196                 EL(ha, "done -  failed, isp abort active\n");
6197                 cmd->ResponseLen = 0;
6198                 return;
6199         }
6200 
6201         /* inform the user of the current beacon state (off or on) */
6202         bstate.State = ha->ledstate.BeaconState;
6203 
6204         rval = ddi_copyout((void *)&bstate,
6205             (void *)(uintptr_t)cmd->ResponseAdr,
6206             sizeof (EXT_BEACON_CONTROL), mode);
6207 
6208         if (rval != 0) {
6209                 EL(ha, "failed, ddi_copyout\n");
6210                 cmd->Status = EXT_STATUS_COPY_ERR;
6211                 cmd->ResponseLen = 0;
6212         } else {
6213                 cmd->Status = EXT_STATUS_OK;
6214                 cmd->ResponseLen = sizeof (EXT_BEACON_CONTROL);
6215         }
6216 
6217         QL_PRINT_9(ha, "done\n");
6218 }
6219 
6220 /*
6221  * ql_blink_led
6222  *      Determine the next state of the LED and drive it
6223  *
6224  * Input:
6225  *      ha:     adapter state pointer.
6226  *
6227  * Context:
6228  *      Interrupt context.
6229  */
6230 void
6231 ql_blink_led(ql_adapter_state_t *ha)
6232 {
6233         uint32_t        nextstate;
6234         ql_mbx_data_t   mr;
6235 
6236         QL_PRINT_9(ha, "started\n");
6237 
6238         if (ha->ledstate.BeaconState == BEACON_ON) {
6239                 if (CFG_IST(ha, CFG_CTRL_2363 | CFG_CTRL_2425)) {
6240                         /* determine the next led state */
6241                         if (CFG_IST(ha, CFG_CTRL_2425)) {
6242                                 nextstate = (ha->ledstate.LEDflags) &
6243                                     (~(RD32_IO_REG(ha, gpiod)));
6244                         } else {
6245                                 nextstate = (ha->ledstate.LEDflags) &
6246                                     (~(RD16_IO_REG(ha, gpiod)));
6247                         }
6248 
6249                         /* turn the led on or off */
6250                         ql_drive_led(ha, nextstate);
6251                 } else if (CFG_IST(ha, CFG_CTRL_81XX)) {
6252                         if (ha->ledstate.flags & LED_ACTIVE) {
6253                                 mr.mb[1] = 0x2000;
6254                                 mr.mb[2] = 0x4000;
6255                                 ha->ledstate.flags &= ~LED_ACTIVE;
6256                         } else {
6257                                 mr.mb[1] = 0x4000;
6258                                 mr.mb[2] = 0x2000;
6259                                 ha->ledstate.flags |= LED_ACTIVE;
6260                         }
6261                         (void) ql_set_led_config(ha, &mr);
6262                 } else if (CFG_IST(ha, CFG_CTRL_80XX)) {
6263                         if (ha->ledstate.flags & LED_ACTIVE) {
6264                                 mr.mb[1] = 0x4000;
6265                                 mr.mb[2] = 0x2000;
6266                                 mr.mb[3] = 0x4000;
6267                                 mr.mb[4] = 0x4000;
6268                                 mr.mb[5] = 0;
6269                                 mr.mb[6] = 0x2000;
6270                                 (void) ql_set_led_config(ha, &mr);
6271                                 ha->ledstate.flags &= ~LED_ACTIVE;
6272                         } else {
6273                                 mr.mb[1] = 0x4000;
6274                                 mr.mb[2] = 0x4000;
6275                                 mr.mb[3] = 0x4000;
6276                                 mr.mb[4] = 0x2000;
6277                                 mr.mb[5] = 0;
6278                                 mr.mb[6] = 0x2000;
6279                                 (void) ql_set_led_config(ha, &mr);
6280                                 ha->ledstate.flags |= LED_ACTIVE;
6281                         }
6282                 } else if (CFG_IST(ha, CFG_CTRL_83XX)) {
6283                         if (ha->ledstate.flags & LED_ACTIVE) {
6284                                 (void) ql_write_remote_reg(ha,
6285                                     ha->ledstate.select,
6286                                     0x40004000);
6287                                 (void) ql_write_remote_reg(ha,
6288                                     ha->ledstate.select + 4,
6289                                     0x40004000);
6290                                 ha->ledstate.flags &= ~LED_ACTIVE;
6291                         } else {
6292                                 (void) ql_write_remote_reg(ha,
6293                                     ha->ledstate.select,
6294                                     0x40002000);
6295                                 (void) ql_write_remote_reg(ha,
6296                                     ha->ledstate.select + 4,
6297                                     0x40002000);
6298                                 ha->ledstate.flags |= LED_ACTIVE;
6299                         }
6300                 } else if (!CFG_IST(ha, CFG_CTRL_27XX)) {
6301                         EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6302                 }
6303         }
6304 
6305         QL_PRINT_9(ha, "done\n");
6306 }
6307 
6308 /*
6309  * ql_drive_led
6310  *      drive the led's as determined by LEDflags
6311  *
6312  * Input:
6313  *      ha:             adapter state pointer.
6314  *      LEDflags:       LED flags
6315  *
6316  * Context:
6317  *      Kernel/Interrupt context.
6318  */
6319 static void
6320 ql_drive_led(ql_adapter_state_t *ha, uint32_t LEDflags)
6321 {
6322         QL_PRINT_9(ha, "started\n");
6323 
6324         if (CFG_IST(ha, CFG_CTRL_2363)) {
6325 
6326                 uint16_t        gpio_enable, gpio_data;
6327 
6328                 /* setup to send new data */
6329                 gpio_enable = (uint16_t)RD16_IO_REG(ha, gpioe);
6330                 gpio_enable = (uint16_t)(gpio_enable | LED_MASK);
6331                 WRT16_IO_REG(ha, gpioe, gpio_enable);
6332 
6333                 /* read current data and clear out old led data */
6334                 gpio_data = (uint16_t)RD16_IO_REG(ha, gpiod);
6335                 gpio_data = (uint16_t)(gpio_data & ~LED_MASK);
6336 
6337                 /* set in the new led data. */
6338                 gpio_data = (uint16_t)(gpio_data | LEDflags);
6339 
6340                 /* write out the new led data */
6341                 WRT16_IO_REG(ha, gpiod, gpio_data);
6342 
6343         } else if (CFG_IST(ha, CFG_CTRL_2425)) {
6344                 uint32_t        gpio_data;
6345 
6346                 /* setup to send new data */
6347                 gpio_data = RD32_IO_REG(ha, gpiod);
6348                 gpio_data |= LED_MASK_UPDATE_24;
6349                 WRT32_IO_REG(ha, gpiod, gpio_data);
6350 
6351                 /* read current data and clear out old led data */
6352                 gpio_data = RD32_IO_REG(ha, gpiod);
6353                 gpio_data &= ~LED_MASK_COLORS_24;
6354 
6355                 /* set in the new led data */
6356                 gpio_data |= LEDflags;
6357 
6358                 /* write out the new led data */
6359                 WRT32_IO_REG(ha, gpiod, gpio_data);
6360 
6361         } else {
6362                 EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6363         }
6364 
6365         QL_PRINT_9(ha, "done\n");
6366 }
6367 
6368 /*
6369  * ql_setup_led
6370  *      Setup LED for driver control
6371  *
6372  * Input:
6373  *      ha:     adapter state pointer.
6374  *
6375  * Context:
6376  *      Kernel/Interrupt context.
6377  */
6378 static int
6379 ql_setup_led(ql_adapter_state_t *ha)
6380 {
6381         int             rval = QL_SUCCESS;
6382         ql_mbx_data_t   mr;
6383 
6384         QL_PRINT_9(ha, "started\n");
6385 
6386         if (CFG_IST(ha, CFG_CTRL_2363 | CFG_CTRL_2425)) {
6387                 /* decouple the LED control from the fw */
6388                 rval = ql_get_firmware_option(ha, &mr);
6389                 if (rval != QL_SUCCESS) {
6390                         EL(ha, "failed, get_firmware_option=%xh\n", rval);
6391                         return (rval);
6392                 }
6393 
6394                 /* set the appropriate options */
6395                 mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_GPIO);
6396 
6397                 /* send it back to the firmware */
6398                 rval = ql_set_firmware_option(ha, &mr);
6399                 if (rval != QL_SUCCESS) {
6400                         EL(ha, "failed, set_firmware_option=%xh\n", rval);
6401                         return (rval);
6402                 }
6403 
6404                 /* initally, turn the LED's off */
6405                 ql_drive_led(ha, LED_ALL_OFF);
6406 
6407         } else if (CFG_IST(ha, CFG_CTRL_81XX)) {
6408                 (void) ql_get_led_config(ha, &ha->ledstate.cfg);
6409                 mr.mb[1] = 0x2000;
6410                 mr.mb[2] = 0x2000;
6411                 rval = ql_set_led_config(ha, &mr);
6412 
6413         } else if (CFG_IST(ha, CFG_CTRL_80XX)) {
6414                 /* Save initial value */
6415                 rval = ql_get_led_config(ha, &ha->ledstate.cfg);
6416                 if (rval != QL_SUCCESS) {
6417                         EL(ha, "failed, get_led_config=%xh\n", rval);
6418                         return (rval);
6419                 }
6420                 mr.mb[1] = 0x4000;
6421                 mr.mb[2] = 0x4000;
6422                 mr.mb[3] = 0x4000;
6423                 mr.mb[4] = 0x2000;
6424                 mr.mb[5] = 0;
6425                 mr.mb[6] = 0x2000;
6426                 rval = ql_set_led_config(ha, &mr);
6427 
6428         } else if (CFG_IST(ha, CFG_CTRL_83XX)) {
6429                 rval = ql_get_firmware_option(ha, &mr);
6430                 if (rval != QL_SUCCESS) {
6431                         EL(ha, "failed, get_firmware_option=%xh\n", rval);
6432                         return (rval);
6433                 }
6434 
6435                 mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_LEDS);
6436 
6437                 rval = ql_set_firmware_option(ha, &mr);
6438                 if (rval != QL_SUCCESS) {
6439                         EL(ha, "failed, set_firmware_option=%xh\n", rval);
6440                         return (rval);
6441                 }
6442 
6443                 (void) ql_write_remote_reg(ha, ha->ledstate.select,
6444                     0x40002000);
6445                 (void) ql_write_remote_reg(ha, ha->ledstate.select + 4,
6446                     0x40002000);
6447 
6448         } else if (CFG_IST(ha, CFG_CTRL_27XX)) {
6449                 /* take control of LED */
6450                 rval = ql_get_firmware_option(ha, &mr);
6451                 if (rval != QL_SUCCESS) {
6452                         EL(ha, "failed, get_firmware_option=%xh\n", rval);
6453                         return (rval);
6454                 }
6455 
6456                 mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_LEDS);
6457 
6458                 rval = ql_set_firmware_option(ha, &mr);
6459                 if (rval != QL_SUCCESS) {
6460                         EL(ha, "failed, set_firmware_option=%xh\n", rval);
6461                         return (rval);
6462                 }
6463 
6464                 mr.mb[1] = 0xf;
6465                 mr.mb[2] = 0x230;
6466                 mr.mb[3] = 0x230;
6467                 mr.mb[4] = 0x4000;
6468                 rval = ql_led_config(ha, &mr);
6469                 if (rval != QL_SUCCESS) {
6470                         EL(ha, "failed, led_config=%xh\n", rval);
6471                         return (rval);
6472                 }
6473         } else {
6474                 EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6475         }
6476         ha->ledstate.flags |= LED_ACTIVE;
6477 
6478         QL_PRINT_9(ha, "done\n");
6479 
6480         return (rval);
6481 }
6482 
6483 /*
6484  * ql_wrapup_led
6485  *      Return LED control to the firmware
6486  *
6487  * Input:
6488  *      ha:     adapter state pointer.
6489  *
6490  * Context:
6491  *      Kernel/Interrupt context.
6492  */
6493 static int
6494 ql_wrapup_led(ql_adapter_state_t *ha)
6495 {
6496         int             rval = QL_SUCCESS;
6497         ql_mbx_data_t   mr;
6498 
6499         QL_PRINT_9(ha, "started\n");
6500 
6501 
6502         if (CFG_IST(ha, CFG_CTRL_2363 | CFG_CTRL_2425)) {
6503                 uint32_t        gpio_data;
6504 
6505                 /* Turn all LED's off */
6506                 ql_drive_led(ha, LED_ALL_OFF);
6507 
6508                 if (CFG_IST(ha, CFG_CTRL_2425)) {
6509                         /* disable the LED update mask */
6510                         gpio_data = RD32_IO_REG(ha, gpiod);
6511                         gpio_data &= ~LED_MASK_UPDATE_24;
6512 
6513                         /* write out the data */
6514                         WRT32_IO_REG(ha, gpiod, gpio_data);
6515                         /* give LED control back to the f/w */
6516                 }
6517                 rval = ql_get_firmware_option(ha, &mr);
6518                 if (rval != QL_SUCCESS) {
6519                         EL(ha, "failed, get_firmware_option=%xh\n", rval);
6520                         return (rval);
6521                 }
6522 
6523                 mr.mb[1] = (uint16_t)(mr.mb[1] & ~FO1_DISABLE_GPIO);
6524 
6525                 rval = ql_set_firmware_option(ha, &mr);
6526                 if (rval != QL_SUCCESS) {
6527                         EL(ha, "failed, set_firmware_option=%xh\n", rval);
6528                         return (rval);
6529                 }
6530         } else if (CFG_IST(ha, CFG_CTRL_8081)) {
6531                 rval = ql_set_led_config(ha, &ha->ledstate.cfg);
6532 
6533         } else if (CFG_IST(ha, CFG_CTRL_2783)) {
6534                 /* give LED control back to the f/w */
6535                 rval = ql_get_firmware_option(ha, &mr);
6536                 if (rval != QL_SUCCESS) {
6537                         EL(ha, "failed, get_firmware_option=%xh\n", rval);
6538                         return (rval);
6539                 }
6540 
6541                 mr.mb[1] = (uint16_t)(mr.mb[1] & ~FO1_DISABLE_LEDS);
6542 
6543                 rval = ql_set_firmware_option(ha, &mr);
6544                 if (rval != QL_SUCCESS) {
6545                         EL(ha, "failed, set_firmware_option=%xh\n", rval);
6546                         return (rval);
6547                 }
6548 
6549         } else {
6550                 EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6551         }
6552 
6553         QL_PRINT_9(ha, "done\n");
6554 
6555         return (rval);
6556 }
6557 
6558 /*
6559  * ql_get_port_summary
6560  *      Performs EXT_SC_GET_PORT_SUMMARY subcommand. of EXT_CC_GET_DATA.
6561  *
6562  *      The EXT_IOCTL->RequestAdr points to a single
6563  *      UINT32 which identifies the device type.
6564  *
6565  * Input:
6566  *      ha:     adapter state pointer.
6567  *      cmd:    Local EXT_IOCTL cmd struct pointer.
6568  *      mode:   flags.
6569  *
6570  * Returns:
6571  *      None, request status indicated in cmd->Status.
6572  *
6573  * Context:
6574  *      Kernel context.
6575  */
6576 static void
6577 ql_get_port_summary(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6578 {
6579         EXT_DEVICEDATA          dd = {0};
6580         EXT_DEVICEDATA          *uddp;
6581         ql_link_t               *link;
6582         ql_tgt_t                *tq;
6583         uint32_t                rlen, dev_type, index;
6584         int                     rval = 0;
6585         EXT_DEVICEDATAENTRY     *uddep, *ddep;
6586 
6587         QL_PRINT_9(ha, "started\n");
6588 
6589         ddep = &dd.EntryList[0];
6590 
6591         /*
6592          * Get the type of device the requestor is looking for.
6593          *
6594          * We ignore this for now.
6595          */
6596         rval = ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
6597             (void *)&dev_type, sizeof (dev_type), mode);
6598         if (rval != 0) {
6599                 cmd->Status = EXT_STATUS_COPY_ERR;
6600                 cmd->ResponseLen = 0;
6601                 EL(ha, "failed, ddi_copyin\n");
6602                 return;
6603         }
6604         /*
6605          * Count the number of entries to be returned. Count devices
6606          * that are offlline, but have been persistently bound.
6607          */
6608         for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
6609                 for (link = ha->dev[index].first; link != NULL;
6610                     link = link->next) {
6611                         tq = link->base_address;
6612                         if (tq->flags & TQF_INITIATOR_DEVICE ||
6613                             !VALID_TARGET_ID(ha, tq->loop_id)) {
6614                                 continue;       /* Skip this one */
6615                         }
6616                         dd.TotalDevices++;
6617                 }
6618         }
6619         /*
6620          * Compute the number of entries that can be returned
6621          * based upon the size of caller's response buffer.
6622          */
6623         dd.ReturnListEntryCount = 0;
6624         if (dd.TotalDevices == 0) {
6625                 rlen = sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY);
6626         } else {
6627                 rlen = (uint32_t)(sizeof (EXT_DEVICEDATA) +
6628                     (sizeof (EXT_DEVICEDATAENTRY) * (dd.TotalDevices - 1)));
6629         }
6630         if (rlen > cmd->ResponseLen) {
6631                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6632                 cmd->DetailStatus = rlen;
6633                 EL(ha, "failed, rlen > ResponseLen, rlen=%d, Len=%d\n",
6634                     rlen, cmd->ResponseLen);
6635                 cmd->ResponseLen = 0;
6636                 return;
6637         }
6638         cmd->ResponseLen = 0;
6639         uddp = (EXT_DEVICEDATA *)(uintptr_t)cmd->ResponseAdr;
6640         uddep = &uddp->EntryList[0];
6641         for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
6642                 for (link = ha->dev[index].first; link != NULL;
6643                     link = link->next) {
6644                         tq = link->base_address;
6645                         if (tq->flags & TQF_INITIATOR_DEVICE ||
6646                             !VALID_TARGET_ID(ha, tq->loop_id) ||
6647                             tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
6648                                 continue;       /* Skip this one */
6649                         }
6650 
6651                         bzero((void *)ddep, sizeof (EXT_DEVICEDATAENTRY));
6652 
6653                         bcopy(tq->node_name, ddep->NodeWWN, 8);
6654                         bcopy(tq->port_name, ddep->PortWWN, 8);
6655 
6656                         ddep->PortID[0] = tq->d_id.b.domain;
6657                         ddep->PortID[1] = tq->d_id.b.area;
6658                         ddep->PortID[2] = tq->d_id.b.al_pa;
6659 
6660                         bcopy(tq->port_name,
6661                             (caddr_t)&ddep->TargetAddress.Target, 8);
6662 
6663                         ddep->DeviceFlags = tq->flags;
6664                         ddep->LoopID = tq->loop_id;
6665                         QL_PRINT_9(ha, "Tgt=%lld, loop=%xh, "
6666                             "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x, "
6667                             "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
6668                             ha->instance, ddep->TargetAddress.Target,
6669                             ddep->LoopID, ddep->NodeWWN[0], ddep->NodeWWN[1],
6670                             ddep->NodeWWN[2], ddep->NodeWWN[3],
6671                             ddep->NodeWWN[4], ddep->NodeWWN[5],
6672                             ddep->NodeWWN[6], ddep->NodeWWN[7],
6673                             ddep->PortWWN[0], ddep->PortWWN[1],
6674                             ddep->PortWWN[2], ddep->PortWWN[3],
6675                             ddep->PortWWN[4], ddep->PortWWN[5],
6676                             ddep->PortWWN[6], ddep->PortWWN[7]);
6677                         rval = ddi_copyout((void *)ddep, (void *)uddep,
6678                             sizeof (EXT_DEVICEDATAENTRY), mode);
6679 
6680                         if (rval != 0) {
6681                                 cmd->Status = EXT_STATUS_COPY_ERR;
6682                                 cmd->ResponseLen = 0;
6683                                 EL(ha, "failed, ddi_copyout\n");
6684                                 break;
6685                         }
6686                         dd.ReturnListEntryCount++;
6687                         uddep++;
6688                         cmd->ResponseLen += (uint32_t)
6689                             sizeof (EXT_DEVICEDATAENTRY);
6690                 }
6691         }
6692         rval = ddi_copyout((void *)&dd, (void *)uddp,
6693             sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY), mode);
6694 
6695         if (rval != 0) {
6696                 cmd->Status = EXT_STATUS_COPY_ERR;
6697                 cmd->ResponseLen = 0;
6698                 EL(ha, "failed, ddi_copyout-2\n");
6699         } else {
6700                 cmd->ResponseLen += (uint32_t)sizeof (EXT_DEVICEDATAENTRY);
6701                 QL_PRINT_9(ha, "done\n");
6702         }
6703 }
6704 
6705 /*
6706  * ql_get_target_id
6707  *      Performs EXT_SC_GET_TARGET_ID subcommand. of EXT_CC_GET_DATA.
6708  *
6709  * Input:
6710  *      ha:     adapter state pointer.
6711  *      cmd:    Local EXT_IOCTL cmd struct pointer.
6712  *      mode:   flags.
6713  *
6714  * Returns:
6715  *      None, request status indicated in cmd->Status.
6716  *
6717  * Context:
6718  *      Kernel context.
6719  */
6720 static void
6721 ql_get_target_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6722 {
6723         uint32_t                rval;
6724         uint16_t                qlnt;
6725         EXT_DEST_ADDR           extdestaddr = {0};
6726         uint8_t                 *name;
6727         uint8_t                 wwpn[EXT_DEF_WWN_NAME_SIZE];
6728         ql_tgt_t                *tq;
6729 
6730         QL_PRINT_9(ha, "started\n");
6731 
6732         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
6733             (void*)wwpn, sizeof (EXT_DEST_ADDR), mode) != 0) {
6734                 EL(ha, "failed, ddi_copyin\n");
6735                 cmd->Status = EXT_STATUS_COPY_ERR;
6736                 cmd->ResponseLen = 0;
6737                 return;
6738         }
6739 
6740         qlnt = QLNT_PORT;
6741         name = wwpn;
6742         QL_PRINT_9(ha, "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
6743             ha->instance, name[0], name[1], name[2], name[3], name[4],
6744             name[5], name[6], name[7]);
6745 
6746         tq = ql_find_port(ha, name, qlnt);
6747         if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
6748                 EL(ha, "failed, fc_port not found\n");
6749                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
6750                 cmd->ResponseLen = 0;
6751                 return;
6752         }
6753 
6754         bcopy(tq->port_name, (caddr_t)&extdestaddr.DestAddr.ScsiAddr.Target, 8);
6755 
6756         rval = ddi_copyout((void *)&extdestaddr,
6757             (void *)(uintptr_t)cmd->ResponseAdr, sizeof (EXT_DEST_ADDR), mode);
6758         if (rval != 0) {
6759                 EL(ha, "failed, ddi_copyout\n");
6760                 cmd->Status = EXT_STATUS_COPY_ERR;
6761                 cmd->ResponseLen = 0;
6762         }
6763 
6764         QL_PRINT_9(ha, "done\n");
6765 }
6766 
6767 /*
6768  * ql_setup_fcache
6769  *      Populates selected flash sections into the cache
6770  *
6771  * Input:
6772  *      ha = adapter state pointer.
6773  *
6774  * Returns:
6775  *      ql local function return status code.
6776  *
6777  * Context:
6778  *      Kernel context.
6779  *
6780  * Note:
6781  *      Driver must be in stalled state prior to entering or
6782  *      add code to this function prior to calling ql_setup_flash()
6783  */
6784 int
6785 ql_setup_fcache(ql_adapter_state_t *ha)
6786 {
6787         int             rval;
6788         uint32_t        freadpos = 0;
6789         uint32_t        fw_done = 0;
6790         ql_fcache_t     *head = NULL;
6791         ql_fcache_t     *tail = NULL;
6792         ql_fcache_t     *ftmp;
6793 
6794         QL_PRINT_10(ha, "started cfg=0x%llx\n", ha->cfg_flags);
6795 
6796         /* If we already have populated it, rtn */
6797         if (ha->fcache != NULL) {
6798                 EL(ha, "buffer already populated\n");
6799                 return (QL_SUCCESS);
6800         }
6801 
6802         ql_flash_nvram_defaults(ha);
6803 
6804         if ((rval = ql_setup_flash(ha)) != QL_SUCCESS) {
6805                 EL(ha, "unable to setup flash; rval=%xh\n", rval);
6806                 return (rval);
6807         }
6808 
6809         while (freadpos != 0xffffffff) {
6810                 /* Allocate & populate this node */
6811                 if ((ftmp = ql_setup_fnode(ha)) == NULL) {
6812                         EL(ha, "node alloc failed\n");
6813                         rval = QL_FUNCTION_FAILED;
6814                         break;
6815                 }
6816 
6817                 /* link in the new node */
6818                 if (head == NULL) {
6819                         head = tail = ftmp;
6820                 } else {
6821                         tail->next = ftmp;
6822                         tail = ftmp;
6823                 }
6824 
6825                 /* Do the firmware node first for 24xx/25xx's */
6826                 if (fw_done == 0) {
6827                         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
6828                                 freadpos = ha->flash_fw_addr << 2;
6829                         }
6830                         fw_done = 1;
6831                 }
6832 
6833                 if ((rval = ql_dump_fcode(ha, ftmp->buf, FBUFSIZE,
6834                     freadpos)) != QL_SUCCESS) {
6835                         EL(ha, "failed, 24xx dump_fcode"
6836                             " pos=%xh rval=%xh\n", freadpos, rval);
6837                         rval = QL_FUNCTION_FAILED;
6838                         break;
6839                 }
6840 
6841                 /* checkout the pci data / format */
6842                 if (ql_check_pci(ha, ftmp, &freadpos)) {
6843                         EL(ha, "flash header incorrect\n");
6844                         rval = QL_FUNCTION_FAILED;
6845                         break;
6846                 }
6847         }
6848 
6849         if (rval != QL_SUCCESS) {
6850                 /* release all resources we have */
6851                 ftmp = head;
6852                 while (ftmp != NULL) {
6853                         tail = ftmp->next;
6854                         kmem_free(ftmp->buf, FBUFSIZE);
6855                         kmem_free(ftmp, sizeof (ql_fcache_t));
6856                         ftmp = tail;
6857                 }
6858 
6859                 EL(ha, "failed, done\n");
6860         } else {
6861                 ha->fcache = head;
6862                 QL_PRINT_10(ha, "done\n");
6863         }
6864 
6865         return (rval);
6866 }
6867 
6868 /*
6869  * ql_update_fcache
6870  *      re-populates updated flash into the fcache. If
6871  *      fcache does not exist (e.g., flash was empty/invalid on
6872  *      boot), this routine will create and the populate it.
6873  *
6874  * Input:
6875  *      ha      = adapter state pointer.
6876  *      *bpf    = Pointer to flash buffer.
6877  *      bsize   = Size of flash buffer.
6878  *
6879  * Returns:
6880  *
6881  * Context:
6882  *      Kernel context.
6883  */
6884 void
6885 ql_update_fcache(ql_adapter_state_t *ha, uint8_t *bfp, uint32_t bsize)
6886 {
6887         int             rval = QL_SUCCESS;
6888         uint32_t        freadpos = 0;
6889         uint32_t        fw_done = 0;
6890         ql_fcache_t     *head = NULL;
6891         ql_fcache_t     *tail = NULL;
6892         ql_fcache_t     *ftmp;
6893 
6894         QL_PRINT_3(ha, "started\n");
6895 
6896         while (freadpos != 0xffffffff) {
6897 
6898                 /* Allocate & populate this node */
6899 
6900                 if ((ftmp = ql_setup_fnode(ha)) == NULL) {
6901                         EL(ha, "node alloc failed\n");
6902                         rval = QL_FUNCTION_FAILED;
6903                         break;
6904                 }
6905 
6906                 /* link in the new node */
6907                 if (head == NULL) {
6908                         head = tail = ftmp;
6909                 } else {
6910                         tail->next = ftmp;
6911                         tail = ftmp;
6912                 }
6913 
6914                 /* Do the firmware node first for 24xx's */
6915                 if (fw_done == 0) {
6916                         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
6917                                 freadpos = ha->flash_fw_addr << 2;
6918                         }
6919                         fw_done = 1;
6920                 }
6921 
6922                 /* read in first FBUFSIZE bytes of this flash section */
6923                 if (freadpos + FBUFSIZE > bsize) {
6924                         EL(ha, "passed buffer too small; fr=%xh, bsize=%xh\n",
6925                             freadpos, bsize);
6926                         rval = QL_FUNCTION_FAILED;
6927                         break;
6928                 }
6929                 bcopy(bfp + freadpos, ftmp->buf, FBUFSIZE);
6930 
6931                 /* checkout the pci data / format */
6932                 if (ql_check_pci(ha, ftmp, &freadpos)) {
6933                         EL(ha, "flash header incorrect\n");
6934                         rval = QL_FUNCTION_FAILED;
6935                         break;
6936                 }
6937         }
6938 
6939         if (rval != QL_SUCCESS) {
6940                 /*
6941                  * release all resources we have
6942                  */
6943                 ql_fcache_rel(head);
6944                 EL(ha, "failed, done\n");
6945         } else {
6946                 /*
6947                  * Release previous fcache resources and update with new
6948                  */
6949                 ql_fcache_rel(ha->fcache);
6950                 ha->fcache = head;
6951 
6952                 QL_PRINT_3(ha, "done\n");
6953         }
6954 }
6955 
6956 /*
6957  * ql_setup_fnode
6958  *      Allocates fcache node
6959  *
6960  * Input:
6961  *      ha = adapter state pointer.
6962  *      node = point to allocated fcache node (NULL = failed)
6963  *
6964  * Returns:
6965  *
6966  * Context:
6967  *      Kernel context.
6968  *
6969  * Note:
6970  *      Driver must be in stalled state prior to entering or
6971  *      add code to this function prior to calling ql_setup_flash()
6972  */
6973 static ql_fcache_t *
6974 ql_setup_fnode(ql_adapter_state_t *ha)
6975 {
6976         ql_fcache_t     *fnode = NULL;
6977 
6978         if ((fnode = (ql_fcache_t *)(kmem_zalloc(sizeof (ql_fcache_t),
6979             KM_SLEEP))) == NULL) {
6980                 EL(ha, "fnode alloc failed\n");
6981                 fnode = NULL;
6982         } else if ((fnode->buf = (uint8_t *)(kmem_zalloc(FBUFSIZE,
6983             KM_SLEEP))) == NULL) {
6984                 EL(ha, "buf alloc failed\n");
6985                 kmem_free(fnode, sizeof (ql_fcache_t));
6986                 fnode = NULL;
6987         } else {
6988                 fnode->buflen = FBUFSIZE;
6989         }
6990 
6991         return (fnode);
6992 }
6993 
6994 /*
6995  * ql_fcache_rel
6996  *      Releases the fcache resources
6997  *
6998  * Input:
6999  *      ha      = adapter state pointer.
7000  *      head    = Pointer to fcache linked list
7001  *
7002  * Returns:
7003  *
7004  * Context:
7005  *      Kernel context.
7006  *
7007  */
7008 void
7009 ql_fcache_rel(ql_fcache_t *head)
7010 {
7011         ql_fcache_t     *ftmp = head;
7012         ql_fcache_t     *tail;
7013 
7014         /* release all resources we have */
7015         while (ftmp != NULL) {
7016                 tail = ftmp->next;
7017                 kmem_free(ftmp->buf, FBUFSIZE);
7018                 kmem_free(ftmp, sizeof (ql_fcache_t));
7019                 ftmp = tail;
7020         }
7021 }
7022 
7023 /*
7024  * ql_update_flash_caches
7025  *      Updates driver flash caches
7026  *
7027  * Input:
7028  *      ha:     adapter state pointer.
7029  *
7030  * Context:
7031  *      Kernel context.
7032  */
7033 static void
7034 ql_update_flash_caches(ql_adapter_state_t *ha)
7035 {
7036         uint32_t                len;
7037         ql_link_t               *link;
7038         ql_adapter_state_t      *ha2;
7039 
7040         QL_PRINT_3(ha, "started\n");
7041 
7042         /* Get base path length. */
7043         for (len = (uint32_t)strlen(ha->devpath); len; len--) {
7044                 if (ha->devpath[len] == ',' ||
7045                     ha->devpath[len] == '@') {
7046                         break;
7047                 }
7048         }
7049 
7050         /* Reset fcache on all adapter instances. */
7051         for (link = ql_hba.first; link != NULL; link = link->next) {
7052                 ha2 = link->base_address;
7053 
7054                 if (strncmp(ha->devpath, ha2->devpath, len) != 0) {
7055                         continue;
7056                 }
7057 
7058                 ql_fcache_rel(ha2->fcache);
7059                 ha2->fcache = NULL;
7060 
7061                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
7062                         if (ha2->vcache != NULL) {
7063                                 kmem_free(ha2->vcache, QL_24XX_VPD_SIZE);
7064                                 ha2->vcache = NULL;
7065                         }
7066                 }
7067 
7068                 (void) ql_setup_fcache(ha2);
7069         }
7070 
7071         QL_PRINT_3(ha, "done\n");
7072 }
7073 
7074 /*
7075  * ql_get_fbuf
7076  *      Search the fcache list for the type specified
7077  *
7078  * Input:
7079  *      fptr    = Pointer to fcache linked list
7080  *      ftype   = Type of image to be returned.
7081  *
7082  * Returns:
7083  *      Pointer to ql_fcache_t.
7084  *      NULL means not found.
7085  *
7086  * Context:
7087  *      Kernel context.
7088  *
7089  *
7090  */
7091 ql_fcache_t *
7092 ql_get_fbuf(ql_fcache_t *fptr, uint32_t ftype)
7093 {
7094         while (fptr != NULL) {
7095                 /* does this image meet criteria? */
7096                 if (ftype & fptr->type) {
7097                         break;
7098                 }
7099                 fptr = fptr->next;
7100         }
7101         return (fptr);
7102 }
7103 
7104 /*
7105  * ql_check_pci
7106  *
7107  *      checks the passed buffer for a valid pci signature and
7108  *      expected (and in range) pci length values.
7109  *
7110  *      For firmware type, a pci header is added since the image in
7111  *      the flash does not have one (!!!).
7112  *
7113  *      On successful pci check, nextpos adjusted to next pci header.
7114  *
7115  * Returns:
7116  *      -1 --> last pci image
7117  *      0 --> pci header valid
7118  *      1 --> pci header invalid.
7119  *
7120  * Context:
7121  *      Kernel context.
7122  */
7123 static int
7124 ql_check_pci(ql_adapter_state_t *ha, ql_fcache_t *fcache, uint32_t *nextpos)
7125 {
7126         pci_header_t    *pcih;
7127         pci_data_t      *pcid;
7128         uint32_t        doff;
7129         uint8_t         *pciinfo;
7130 
7131         QL_PRINT_3(ha, "started\n");
7132 
7133         if (fcache != NULL) {
7134                 pciinfo = fcache->buf;
7135         } else {
7136                 EL(ha, "failed, null fcache ptr passed\n");
7137                 return (1);
7138         }
7139 
7140         if (pciinfo == NULL) {
7141                 EL(ha, "failed, null pciinfo ptr passed\n");
7142                 return (1);
7143         }
7144 
7145         if (CFG_IST(ha, CFG_SBUS_CARD)) {
7146                 caddr_t bufp;
7147                 uint_t  len;
7148 
7149                 if (pciinfo[0] != SBUS_CODE_FCODE) {
7150                         EL(ha, "failed, unable to detect sbus fcode\n");
7151                         return (1);
7152                 }
7153                 fcache->type = FTYPE_FCODE;
7154 
7155                 /*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
7156                 if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
7157                     PROP_LEN_AND_VAL_ALLOC | DDI_PROP_DONTPASS |
7158                     DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
7159                     (int *)&len) == DDI_PROP_SUCCESS) {
7160 
7161                         (void) snprintf(fcache->verstr,
7162                             FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp);
7163                         kmem_free(bufp, len);
7164                 }
7165 
7166                 *nextpos = 0xffffffff;
7167 
7168                 QL_PRINT_3(ha, "CFG_SBUS_CARD, done\n");
7169 
7170                 return (0);
7171         }
7172 
7173         if (*nextpos == ha->flash_fw_addr << 2) {
7174 
7175                 pci_header_t    fwh = {0};
7176                 pci_data_t      fwd = {0};
7177                 uint8_t         *buf, *bufp;
7178 
7179                 /*
7180                  * Build a pci header for the firmware module
7181                  */
7182                 if ((buf = (uint8_t *)(kmem_zalloc(FBUFSIZE, KM_SLEEP))) ==
7183                     NULL) {
7184                         EL(ha, "failed, unable to allocate buffer\n");
7185                         return (1);
7186                 }
7187 
7188                 fwh.signature[0] = PCI_HEADER0;
7189                 fwh.signature[1] = PCI_HEADER1;
7190                 fwh.dataoffset[0] = LSB(sizeof (pci_header_t));
7191                 fwh.dataoffset[1] = MSB(sizeof (pci_header_t));
7192 
7193                 fwd.signature[0] = 'P';
7194                 fwd.signature[1] = 'C';
7195                 fwd.signature[2] = 'I';
7196                 fwd.signature[3] = 'R';
7197                 fwd.codetype = PCI_CODE_FW;
7198                 fwd.pcidatalen[0] = LSB(sizeof (pci_data_t));
7199                 fwd.pcidatalen[1] = MSB(sizeof (pci_data_t));
7200 
7201                 bufp = buf;
7202                 bcopy(&fwh, bufp, sizeof (pci_header_t));
7203                 bufp += sizeof (pci_header_t);
7204                 bcopy(&fwd, bufp, sizeof (pci_data_t));
7205                 bufp += sizeof (pci_data_t);
7206 
7207                 bcopy(fcache->buf, bufp, (FBUFSIZE - sizeof (pci_header_t) -
7208                     sizeof (pci_data_t)));
7209                 bcopy(buf, fcache->buf, FBUFSIZE);
7210 
7211                 fcache->type = FTYPE_FW;
7212 
7213                 (void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN,
7214                     "%d.%02d.%02d", fcache->buf[19], fcache->buf[23],
7215                     fcache->buf[27]);
7216 
7217                 *nextpos = ha->boot_code_addr << 2;
7218                 kmem_free(buf, FBUFSIZE);
7219 
7220                 QL_PRINT_3(ha, "FTYPE_FW, done\n");
7221 
7222                 return (0);
7223         }
7224 
7225         /* get to the pci header image length */
7226         pcih = (pci_header_t *)pciinfo;
7227 
7228         doff = pcih->dataoffset[0] | (pcih->dataoffset[1] << 8);
7229 
7230         /* some header section sanity check */
7231         if (pcih->signature[0] != PCI_HEADER0 ||
7232             pcih->signature[1] != PCI_HEADER1 || doff > 50) {
7233                 EL(ha, "buffer format error: s0=%xh, s1=%xh, off=%xh\n",
7234                     pcih->signature[0], pcih->signature[1], doff);
7235                 return (1);
7236         }
7237 
7238         pcid = (pci_data_t *)(pciinfo + doff);
7239 
7240         /* a slight sanity data section check */
7241         if (pcid->signature[0] != 'P' || pcid->signature[1] != 'C' ||
7242             pcid->signature[2] != 'I' || pcid->signature[3] != 'R') {
7243                 EL(ha, "failed, data sig mismatch!\n");
7244                 return (1);
7245         }
7246 
7247         if (pcid->indicator == PCI_IND_LAST_IMAGE) {
7248                 QL_PRINT_3(ha, "last image\n");
7249                 if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
7250                         ql_flash_layout_table(ha, *nextpos +
7251                             (pcid->imagelength[0] | (pcid->imagelength[1] <<
7252                             8)) * PCI_SECTOR_SIZE);
7253                         (void) ql_24xx_flash_desc(ha);
7254                 }
7255                 *nextpos = 0xffffffff;
7256         } else {
7257                 /* adjust the next flash read start position */
7258                 *nextpos += (pcid->imagelength[0] |
7259                     (pcid->imagelength[1] << 8)) * PCI_SECTOR_SIZE;
7260         }
7261 
7262         switch (pcid->codetype) {
7263         case PCI_CODE_X86PC:
7264                 fcache->type = FTYPE_BIOS;
7265                 break;
7266         case PCI_CODE_FCODE:
7267                 fcache->type = FTYPE_FCODE;
7268                 break;
7269         case PCI_CODE_EFI:
7270                 fcache->type = FTYPE_EFI;
7271                 break;
7272         case PCI_CODE_HPPA:
7273                 fcache->type = FTYPE_HPPA;
7274                 break;
7275         default:
7276                 fcache->type = FTYPE_UNKNOWN;
7277                 break;
7278         }
7279 
7280         (void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN,
7281             "%d.%02d", pcid->revisionlevel[1], pcid->revisionlevel[0]);
7282 
7283         QL_PRINT_3(ha, "done\n");
7284 
7285         return (0);
7286 }
7287 
7288 /*
7289  * ql_flash_layout_table
7290  *      Obtains flash addresses from table
7291  *
7292  * Input:
7293  *      ha:             adapter state pointer.
7294  *      flt_paddr:      flash layout pointer address.
7295  *
7296  * Context:
7297  *      Kernel context.
7298  */
7299 static void
7300 ql_flash_layout_table(ql_adapter_state_t *ha, uint32_t flt_paddr)
7301 {
7302         ql_flt_ptr_t    *fptr;
7303         uint8_t         *bp;
7304         int             rval;
7305         uint32_t        len, faddr, cnt;
7306         uint16_t        chksum, w16;
7307 
7308         QL_PRINT_9(ha, "started\n");
7309 
7310         /* Process flash layout table header */
7311         len = sizeof (ql_flt_ptr_t);
7312         if ((bp = kmem_zalloc(len, KM_SLEEP)) == NULL) {
7313                 EL(ha, "kmem_zalloc=null\n");
7314                 return;
7315         }
7316 
7317         /* Process pointer to flash layout table */
7318         if ((rval = ql_dump_fcode(ha, bp, len, flt_paddr)) != QL_SUCCESS) {
7319                 EL(ha, "fptr dump_flash pos=%xh, status=%xh\n", flt_paddr,
7320                     rval);
7321                 kmem_free(bp, len);
7322                 return;
7323         }
7324         fptr = (ql_flt_ptr_t *)bp;
7325 
7326         /* Verify pointer to flash layout table. */
7327         for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7328                 w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]);
7329                 chksum += w16;
7330         }
7331         if (chksum != 0 || fptr->sig[0] != 'Q' || fptr->sig[1] != 'F' ||
7332             fptr->sig[2] != 'L' || fptr->sig[3] != 'T') {
7333                 EL(ha, "ptr chksum=%xh, sig=%c%c%c%c \n",
7334                     chksum, fptr->sig[0],
7335                     fptr->sig[1], fptr->sig[2], fptr->sig[3]);
7336                 kmem_free(bp, len);
7337                 return;
7338         }
7339         faddr = CHAR_TO_LONG(fptr->addr[0], fptr->addr[1], fptr->addr[2],
7340             fptr->addr[3]);
7341 
7342         kmem_free(bp, len);
7343 
7344         ql_process_flt(ha, faddr);
7345 
7346         QL_PRINT_9(ha, "done\n");
7347 }
7348 
7349 /*
7350  * ql_process_flt
7351  *      Obtains flash addresses from flash layout table
7352  *
7353  * Input:
7354  *      ha:     adapter state pointer.
7355  *      faddr:  flash layout table byte address.
7356  *
7357  * Context:
7358  *      Kernel context.
7359  */
7360 static void
7361 ql_process_flt(ql_adapter_state_t *ha, uint32_t faddr)
7362 {
7363         ql_flt_hdr_t    *fhdr;
7364         ql_flt_region_t *frgn;
7365         uint8_t         *bp, *eaddr, nv_rg, vpd_rg;
7366         int             rval;
7367         uint32_t        len, cnt, fe_addr;
7368         uint16_t        chksum, w16;
7369 
7370         QL_PRINT_9(ha, "started faddr=%xh\n", faddr);
7371 
7372         /* Process flash layout table header */
7373         if ((bp = kmem_zalloc(FLASH_LAYOUT_TABLE_SIZE, KM_SLEEP)) == NULL) {
7374                 EL(ha, "kmem_zalloc=null\n");
7375                 return;
7376         }
7377         fhdr = (ql_flt_hdr_t *)bp;
7378 
7379         /* Process flash layout table. */
7380         if ((rval = ql_dump_fcode(ha, bp, FLASH_LAYOUT_TABLE_SIZE, faddr)) !=
7381             QL_SUCCESS) {
7382                 EL(ha, "fhdr dump_flash pos=%xh, status=%xh\n", faddr, rval);
7383                 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7384                 return;
7385         }
7386 
7387         /* Verify flash layout table. */
7388         len = (uint32_t)(CHAR_TO_SHORT(fhdr->len[0], fhdr->len[1]) +
7389             sizeof (ql_flt_hdr_t) + sizeof (ql_flt_region_t));
7390         if (len > FLASH_LAYOUT_TABLE_SIZE) {
7391                 chksum = 0xffff;
7392         } else {
7393                 for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7394                         w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]);
7395                         chksum += w16;
7396                 }
7397         }
7398         w16 = CHAR_TO_SHORT(fhdr->version[0], fhdr->version[1]);
7399         if (chksum != 0 || w16 != 1) {
7400                 EL(ha, "table chksum=%xh, version=%d\n", chksum, w16);
7401                 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7402                 return;
7403         }
7404         eaddr = bp + len;
7405 
7406         /* Process Function/Port Configuration Map. */
7407         nv_rg = vpd_rg = 0;
7408         if (CFG_IST(ha, CFG_CTRL_82XX)) {
7409                 uint16_t        i;
7410                 uint8_t         *mbp = eaddr;
7411                 ql_fp_cfg_map_t *cmp = (ql_fp_cfg_map_t *)mbp;
7412 
7413                 len = (uint32_t)(CHAR_TO_SHORT(cmp->hdr.len[0],
7414                     cmp->hdr.len[1]));
7415                 if (len > FLASH_LAYOUT_TABLE_SIZE) {
7416                         chksum = 0xffff;
7417                 } else {
7418                         for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7419                                 w16 = (uint16_t)CHAR_TO_SHORT(mbp[cnt],
7420                                     mbp[cnt + 1]);
7421                                 chksum += w16;
7422                         }
7423                 }
7424                 w16 = CHAR_TO_SHORT(cmp->hdr.version[0], cmp->hdr.version[1]);
7425                 if (chksum != 0 || w16 != 1 ||
7426                     cmp->hdr.Signature[0] != 'F' ||
7427                     cmp->hdr.Signature[1] != 'P' ||
7428                     cmp->hdr.Signature[2] != 'C' ||
7429                     cmp->hdr.Signature[3] != 'M') {
7430                         EL(ha, "cfg_map chksum=%xh, version=%d, "
7431                             "sig=%c%c%c%c \n", chksum, w16,
7432                             cmp->hdr.Signature[0], cmp->hdr.Signature[1],
7433                             cmp->hdr.Signature[2], cmp->hdr.Signature[3]);
7434                 } else {
7435                         cnt = (uint16_t)
7436                             (CHAR_TO_SHORT(cmp->hdr.NumberEntries[0],
7437                             cmp->hdr.NumberEntries[1]));
7438                         /* Locate entry for function. */
7439                         for (i = 0; i < cnt; i++) {
7440                                 if (cmp->cfg[i].FunctionType == FT_FC &&
7441                                     cmp->cfg[i].FunctionNumber[0] ==
7442                                     ha->pci_function_number &&
7443                                     cmp->cfg[i].FunctionNumber[1] == 0) {
7444                                         nv_rg = cmp->cfg[i].ConfigRegion;
7445                                         vpd_rg = cmp->cfg[i].VpdRegion;
7446                                         break;
7447                                 }
7448                         }
7449 
7450                         if (nv_rg == 0 || vpd_rg == 0) {
7451                                 EL(ha, "cfg_map nv_rg=%d, vpd_rg=%d\n", nv_rg,
7452                                     vpd_rg);
7453                                 nv_rg = vpd_rg = 0;
7454                         }
7455                 }
7456         }
7457 
7458         /* Process flash layout table regions */
7459         for (frgn = (ql_flt_region_t *)(bp + sizeof (ql_flt_hdr_t));
7460             (uint8_t *)frgn < eaddr; frgn++) {
7461                 faddr = CHAR_TO_LONG(frgn->beg_addr[0], frgn->beg_addr[1],
7462                     frgn->beg_addr[2], frgn->beg_addr[3]);
7463                 faddr >>= 2;
7464                 fe_addr = CHAR_TO_LONG(frgn->end_addr[0], frgn->end_addr[1],
7465                     frgn->end_addr[2], frgn->end_addr[3]);
7466                 fe_addr >>= 2;
7467 
7468                 switch (frgn->region) {
7469                 case FLASH_8021_BOOTLOADER_REGION:
7470                         ha->bootloader_addr = faddr;
7471                         ha->bootloader_size = (fe_addr - faddr) + 1;
7472                         QL_PRINT_9(ha, "bootloader_addr=%xh, "
7473                             "size=%xh\n", faddr,
7474                             ha->bootloader_size);
7475                         break;
7476                 case FLASH_FW_REGION:
7477                 case FLASH_8021_FW_REGION:
7478                         ha->flash_fw_addr = faddr;
7479                         ha->flash_fw_size = (fe_addr - faddr) + 1;
7480                         QL_PRINT_9(ha, "flash_fw_addr=%xh, "
7481                             "size=%xh\n", faddr,
7482                             ha->flash_fw_size);
7483                         break;
7484                 case FLASH_GOLDEN_FW_REGION:
7485                 case FLASH_8021_GOLDEN_FW_REGION:
7486                         ha->flash_golden_fw_addr = faddr;
7487                         QL_PRINT_9(ha, "flash_golden_fw_addr=%xh\n",
7488                             ha->instance, faddr);
7489                         break;
7490                 case FLASH_8021_VPD_REGION:
7491                         if (!vpd_rg || vpd_rg == FLASH_8021_VPD_REGION) {
7492                                 ha->flash_vpd_addr = faddr;
7493                                 QL_PRINT_9(ha, "8021_flash_vpd_"
7494                                     "addr=%xh\n", faddr);
7495                         }
7496                         break;
7497                 case FLASH_VPD_0_REGION:
7498                         if (vpd_rg) {
7499                                 if (vpd_rg == FLASH_VPD_0_REGION) {
7500                                         ha->flash_vpd_addr = faddr;
7501                                         QL_PRINT_9(ha, "vpd_rg  "
7502                                             "flash_vpd_addr=%xh\n",
7503                                             ha->instance, faddr);
7504                                 }
7505                         } else if (ha->function_number == 0 &&
7506                             !(CFG_IST(ha, CFG_CTRL_82XX))) {
7507                                 ha->flash_vpd_addr = faddr;
7508                                 QL_PRINT_9(ha, "flash_vpd_addr=%xh"
7509                                     "\n", faddr);
7510                         }
7511                         break;
7512                 case FLASH_NVRAM_0_REGION:
7513                         if (nv_rg) {
7514                                 if (nv_rg == FLASH_NVRAM_0_REGION) {
7515                                         ADAPTER_STATE_LOCK(ha);
7516                                         ha->function_number = 0;
7517                                         ADAPTER_STATE_UNLOCK(ha);
7518                                         ha->flash_nvram_addr = faddr;
7519                                         QL_PRINT_9(ha, "nv_rg "
7520                                             "flash_nvram_addr=%xh\n",
7521                                             ha->instance, faddr);
7522                                 }
7523                         } else if (ha->function_number == 0) {
7524                                 ha->flash_nvram_addr = faddr;
7525                                 QL_PRINT_9(ha, "flash_nvram_addr="
7526                                     "%xh\n", faddr);
7527                         }
7528                         break;
7529                 case FLASH_VPD_1_REGION:
7530                         if (vpd_rg) {
7531                                 if (vpd_rg == FLASH_VPD_1_REGION) {
7532                                         ha->flash_vpd_addr = faddr;
7533                                         QL_PRINT_9(ha, "vpd_rg "
7534                                             "flash_vpd_addr=%xh\n",
7535                                             ha->instance, faddr);
7536                                 }
7537                         } else if (ha->function_number &&
7538                             !(CFG_IST(ha, CFG_CTRL_82XX))) {
7539                                 ha->flash_vpd_addr = faddr;
7540                                 QL_PRINT_9(ha, "flash_vpd_addr=%xh"
7541                                     "\n", faddr);
7542                         }
7543                         break;
7544                 case FLASH_NVRAM_1_REGION:
7545                         if (nv_rg) {
7546                                 if (nv_rg == FLASH_NVRAM_1_REGION) {
7547                                         ADAPTER_STATE_LOCK(ha);
7548                                         ha->function_number = 1;
7549                                         ADAPTER_STATE_UNLOCK(ha);
7550                                         ha->flash_nvram_addr = faddr;
7551                                         QL_PRINT_9(ha, "nv_rg "
7552                                             "flash_nvram_addr=%xh\n",
7553                                             ha->instance, faddr);
7554                                 }
7555                         } else if (ha->function_number) {
7556                                 ha->flash_nvram_addr = faddr;
7557                                 QL_PRINT_9(ha, "flash_nvram_addr="
7558                                     "%xh\n", faddr);
7559                         }
7560                         break;
7561                 case FLASH_DESC_TABLE_REGION:
7562                         if (!(CFG_IST(ha, CFG_CTRL_82XX))) {
7563                                 ha->flash_desc_addr = faddr;
7564                                 QL_PRINT_9(ha, "flash_desc_addr="
7565                                     "%xh\n", faddr);
7566                         }
7567                         break;
7568                 case FLASH_ERROR_LOG_0_REGION:
7569                         if (ha->function_number == 0) {
7570                                 ha->flash_errlog_start = faddr;
7571                                 QL_PRINT_9(ha, "flash_errlog_addr="
7572                                     "%xh\n", faddr);
7573                         }
7574                         break;
7575                 case FLASH_ERROR_LOG_1_REGION:
7576                         if (ha->function_number) {
7577                                 ha->flash_errlog_start = faddr;
7578                                 QL_PRINT_9(ha, "flash_errlog_addr="
7579                                     "%xh\n", faddr);
7580                         }
7581                         break;
7582                 default:
7583                         break;
7584                 }
7585         }
7586         kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7587 
7588         QL_PRINT_9(ha, "done\n");
7589 }
7590 
7591 /*
7592  * ql_flash_nvram_defaults
7593  *      Flash default addresses.
7594  *
7595  * Input:
7596  *      ha:             adapter state pointer.
7597  *
7598  * Returns:
7599  *      ql local function return status code.
7600  *
7601  * Context:
7602  *      Kernel context.
7603  */
7604 static void
7605 ql_flash_nvram_defaults(ql_adapter_state_t *ha)
7606 {
7607         QL_PRINT_10(ha, "started\n");
7608 
7609         if (ha->function_number == 3) {
7610                 if (CFG_IST(ha, CFG_CTRL_27XX)) {
7611                         ha->flash_nvram_addr = NVRAM_2700_FUNC3_ADDR;
7612                         ha->flash_vpd_addr = VPD_2700_FUNC3_ADDR;
7613                         ha->ledstate.select = BEACON_2700_FUNC3_ADDR;
7614                         ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7615                         ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7616                         ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7617                         ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7618                         ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7619                 } else {
7620                         EL(ha, "unassigned flash fn%d addr: %x\n",
7621                             ha->function_number, ha->device_id);
7622                 }
7623         } else if (ha->function_number == 2) {
7624                 if (CFG_IST(ha, CFG_CTRL_27XX)) {
7625                         ha->flash_nvram_addr = NVRAM_2700_FUNC2_ADDR;
7626                         ha->flash_vpd_addr = VPD_2700_FUNC2_ADDR;
7627                         ha->ledstate.select = BEACON_2700_FUNC2_ADDR;
7628                         ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7629                         ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7630                         ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7631                         ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7632                         ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7633                 } else {
7634                         EL(ha, "unassigned flash fn%d addr: %x\n",
7635                             ha->function_number, ha->device_id);
7636                 }
7637         } else if (ha->function_number == 1) {
7638                 if (CFG_IST(ha, CFG_CTRL_23XX) ||
7639                     (CFG_IST(ha, CFG_CTRL_63XX))) {
7640                         ha->flash_nvram_addr = NVRAM_2300_FUNC1_ADDR;
7641                         ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR;
7642                         ha->boot_code_addr = FLASH_2300_BOOT_CODE_ADDR;
7643                 } else if (CFG_IST(ha, CFG_CTRL_24XX)) {
7644                         ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7645                         ha->flash_nvram_addr = NVRAM_2400_FUNC1_ADDR;
7646                         ha->flash_vpd_addr = VPD_2400_FUNC1_ADDR;
7647                         ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_1;
7648                         ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE;
7649                         ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR;
7650                         ha->boot_code_addr = FLASH_2400_BOOT_CODE_ADDR;
7651                 } else if (CFG_IST(ha, CFG_CTRL_25XX)) {
7652                         ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7653                         ha->flash_nvram_addr = NVRAM_2500_FUNC1_ADDR;
7654                         ha->flash_vpd_addr = VPD_2500_FUNC1_ADDR;
7655                         ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_1;
7656                         ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE;
7657                         ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR;
7658                         ha->boot_code_addr = FLASH_2500_BOOT_CODE_ADDR;
7659                 } else if (CFG_IST(ha, CFG_CTRL_81XX)) {
7660                         ha->flash_data_addr = FLASH_8100_DATA_ADDR;
7661                         ha->flash_nvram_addr = NVRAM_8100_FUNC1_ADDR;
7662                         ha->flash_vpd_addr = VPD_8100_FUNC1_ADDR;
7663                         ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_1;
7664                         ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE;
7665                         ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR;
7666                         ha->boot_code_addr = FLASH_8100_BOOT_CODE_ADDR;
7667                 } else if (CFG_IST(ha, CFG_CTRL_82XX)) {
7668                         ha->flash_data_addr = 0;
7669                         ha->flash_nvram_addr = NVRAM_8021_FUNC1_ADDR;
7670                         ha->flash_vpd_addr = VPD_8021_FUNC1_ADDR;
7671                         ha->flash_errlog_start = 0;
7672                         ha->flash_desc_addr = FLASH_8021_DESCRIPTOR_TABLE;
7673                         ha->flash_fw_addr = FLASH_8021_FIRMWARE_ADDR;
7674                         ha->flash_fw_size = FLASH_8021_FIRMWARE_SIZE;
7675                         ha->bootloader_addr = FLASH_8021_BOOTLOADER_ADDR;
7676                         ha->bootloader_size = FLASH_8021_BOOTLOADER_SIZE;
7677                         ha->boot_code_addr = FLASH_8021_BOOT_CODE_ADDR;
7678                 } else if (CFG_IST(ha, CFG_CTRL_83XX)) {
7679                         ha->flash_nvram_addr = NVRAM_8300_FC_FUNC1_ADDR;
7680                         ha->flash_vpd_addr = VPD_8300_FC_FUNC1_ADDR;
7681                         ha->ledstate.select = BEACON_8300_FC_FUNC1_ADDR;
7682                         ha->flash_errlog_start = FLASH_8300_ERRLOG_START_ADDR_1;
7683                         ha->flash_data_addr = FLASH_8300_DATA_ADDR;
7684                         ha->flash_desc_addr = FLASH_8300_DESCRIPTOR_TABLE;
7685                         ha->flash_fw_addr = FLASH_8300_FC_FIRMWARE_ADDR;
7686                         ha->flash_fw_size = FLASH_8300_FIRMWARE_SIZE;
7687                         ha->bootloader_addr = FLASH_8300_BOOTLOADER_ADDR;
7688                         ha->bootloader_size = FLASH_8300_BOOTLOADER_SIZE;
7689                         ha->boot_code_addr = FLASH_8300_BOOT_CODE_ADDR;
7690                 } else if (CFG_IST(ha, CFG_CTRL_27XX)) {
7691                         ha->flash_nvram_addr = NVRAM_2700_FUNC1_ADDR;
7692                         ha->flash_vpd_addr = VPD_2700_FUNC1_ADDR;
7693                         ha->ledstate.select = BEACON_2700_FUNC1_ADDR;
7694                         ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7695                         ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7696                         ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7697                         ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7698                         ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7699                 } else {
7700                         EL(ha, "unassigned flash fn%d addr: %x\n",
7701                             ha->function_number, ha->device_id);
7702                 }
7703         } else if (ha->function_number == 0) {
7704                 if (CFG_IST(ha, CFG_CTRL_22XX)) {
7705                         ha->flash_nvram_addr = NVRAM_2200_FUNC0_ADDR;
7706                         ha->flash_fw_addr = FLASH_2200_FIRMWARE_ADDR;
7707                         ha->boot_code_addr = FLASH_2200_BOOT_CODE_ADDR;
7708                 } else if (CFG_IST(ha, CFG_CTRL_23XX) ||
7709                     (CFG_IST(ha, CFG_CTRL_63XX))) {
7710                         ha->flash_nvram_addr = NVRAM_2300_FUNC0_ADDR;
7711                         ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR;
7712                         ha->boot_code_addr = FLASH_2300_BOOT_CODE_ADDR;
7713                 } else if (CFG_IST(ha, CFG_CTRL_24XX)) {
7714                         ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7715                         ha->flash_nvram_addr = NVRAM_2400_FUNC0_ADDR;
7716                         ha->flash_vpd_addr = VPD_2400_FUNC0_ADDR;
7717                         ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_0;
7718                         ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE;
7719                         ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR;
7720                         ha->boot_code_addr = FLASH_2400_BOOT_CODE_ADDR;
7721                 } else if (CFG_IST(ha, CFG_CTRL_25XX)) {
7722                         ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7723                         ha->flash_nvram_addr = NVRAM_2500_FUNC0_ADDR;
7724                         ha->flash_vpd_addr = VPD_2500_FUNC0_ADDR;
7725                         ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_0;
7726                         ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE;
7727                         ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR;
7728                         ha->boot_code_addr = FLASH_2500_BOOT_CODE_ADDR;
7729                 } else if (CFG_IST(ha, CFG_CTRL_81XX)) {
7730                         ha->flash_data_addr = FLASH_8100_DATA_ADDR;
7731                         ha->flash_nvram_addr = NVRAM_8100_FUNC0_ADDR;
7732                         ha->flash_vpd_addr = VPD_8100_FUNC0_ADDR;
7733                         ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_0;
7734                         ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE;
7735                         ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR;
7736                         ha->boot_code_addr = FLASH_8100_BOOT_CODE_ADDR;
7737                 } else if (CFG_IST(ha, CFG_CTRL_82XX)) {
7738                         ha->flash_data_addr = 0;
7739                         ha->flash_nvram_addr = NVRAM_8021_FUNC0_ADDR;
7740                         ha->flash_vpd_addr = VPD_8021_FUNC0_ADDR;
7741                         ha->flash_errlog_start = 0;
7742                         ha->flash_desc_addr = FLASH_8021_DESCRIPTOR_TABLE;
7743                         ha->flash_fw_addr = FLASH_8021_FIRMWARE_ADDR;
7744                         ha->flash_fw_size = FLASH_8021_FIRMWARE_SIZE;
7745                         ha->bootloader_addr = FLASH_8021_BOOTLOADER_ADDR;
7746                         ha->bootloader_size = FLASH_8021_BOOTLOADER_SIZE;
7747                         ha->boot_code_addr = FLASH_8021_BOOT_CODE_ADDR;
7748                 } else if (CFG_IST(ha, CFG_CTRL_83XX)) {
7749                         ha->flash_nvram_addr = NVRAM_8300_FC_FUNC0_ADDR;
7750                         ha->flash_vpd_addr = VPD_8300_FC_FUNC0_ADDR;
7751                         ha->ledstate.select = BEACON_8300_FCOE_FUNC0_ADDR;
7752                         ha->flash_errlog_start = FLASH_8300_ERRLOG_START_ADDR_0;
7753                         ha->flash_data_addr = FLASH_8300_DATA_ADDR;
7754                         ha->flash_desc_addr = FLASH_8300_DESCRIPTOR_TABLE;
7755                         ha->flash_fw_addr = FLASH_8300_FC_FIRMWARE_ADDR;
7756                         ha->flash_fw_size = FLASH_8300_FIRMWARE_SIZE;
7757                         ha->bootloader_addr = FLASH_8300_BOOTLOADER_ADDR;
7758                         ha->bootloader_size = FLASH_8300_BOOTLOADER_SIZE;
7759                         ha->boot_code_addr = FLASH_8300_BOOT_CODE_ADDR;
7760                 } else if (CFG_IST(ha, CFG_CTRL_27XX)) {
7761                         ha->flash_nvram_addr = NVRAM_2700_FUNC0_ADDR;
7762                         ha->flash_vpd_addr = VPD_2700_FUNC0_ADDR;
7763                         ha->ledstate.select = BEACON_2700_FUNC0_ADDR;
7764                         ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7765                         ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7766                         ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7767                         ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7768                         ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7769                 } else {
7770                         EL(ha, "unassigned flash fn%d addr: %x\n",
7771                             ha->function_number, ha->device_id);
7772                 }
7773         } else {
7774                 EL(ha, "known function=%d, device_id=%x\n",
7775                     ha->function_number, ha->device_id);
7776         }
7777         QL_PRINT_10(ha, "done\n");
7778 }
7779 
7780 /*
7781  * ql_get_sfp
7782  *      Returns sfp data to sdmapi caller
7783  *
7784  * Input:
7785  *      ha:     adapter state pointer.
7786  *      cmd:    Local EXT_IOCTL cmd struct pointer.
7787  *      mode:   flags.
7788  *
7789  * Returns:
7790  *      None, request status indicated in cmd->Status.
7791  *
7792  * Context:
7793  *      Kernel context.
7794  */
7795 static void
7796 ql_get_sfp(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7797 {
7798         QL_PRINT_9(ha, "started\n");
7799 
7800         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
7801                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7802                 EL(ha, "failed, invalid request for HBA\n");
7803                 return;
7804         }
7805 
7806         if (cmd->ResponseLen < QL_24XX_SFP_SIZE) {
7807                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
7808                 cmd->DetailStatus = QL_24XX_SFP_SIZE;
7809                 EL(ha, "failed, ResponseLen < SFP len, len passed=%xh\n",
7810                     cmd->ResponseLen);
7811                 return;
7812         }
7813 
7814         /* Dump SFP data in user buffer */
7815         if ((ql_dump_sfp(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
7816             mode)) != 0) {
7817                 cmd->Status = EXT_STATUS_COPY_ERR;
7818                 EL(ha, "failed, copy error\n");
7819         } else {
7820                 cmd->Status = EXT_STATUS_OK;
7821         }
7822 
7823         QL_PRINT_9(ha, "done\n");
7824 }
7825 
7826 /*
7827  * ql_dump_sfp
7828  *      Dumps SFP.
7829  *
7830  * Input:
7831  *      ha:     adapter state pointer.
7832  *      bp:     buffer address.
7833  *      mode:   flags
7834  *
7835  * Returns:
7836  *
7837  * Context:
7838  *      Kernel context.
7839  */
7840 static int
7841 ql_dump_sfp(ql_adapter_state_t *ha, void *bp, int mode)
7842 {
7843         dma_mem_t       mem;
7844         uint32_t        cnt;
7845         int             rval2, rval = 0;
7846         uint32_t        dxfer;
7847 
7848         QL_PRINT_9(ha, "started\n");
7849 
7850         /* Get memory for SFP. */
7851 
7852         if ((rval2 = ql_get_dma_mem(ha, &mem, 64, LITTLE_ENDIAN_DMA,
7853             QL_DMA_DATA_ALIGN)) != QL_SUCCESS) {
7854                 EL(ha, "failed, ql_get_dma_mem=%xh\n", rval2);
7855                 return (ENOMEM);
7856         }
7857 
7858         for (cnt = 0; cnt < QL_24XX_SFP_SIZE; cnt += mem.size) {
7859                 rval2 = ql_read_sfp(ha, &mem,
7860                     (uint16_t)(cnt < 256 ? 0xA0 : 0xA2),
7861                     (uint16_t)(cnt & 0xff));
7862                 if (rval2 != QL_SUCCESS) {
7863                         EL(ha, "failed, read_sfp=%xh\n", rval2);
7864                         rval = EFAULT;
7865                         break;
7866                 }
7867 
7868                 /* copy the data back */
7869                 if ((dxfer = ql_send_buffer_data(mem.bp, bp, mem.size,
7870                     mode)) != mem.size) {
7871                         /* ddi copy error */
7872                         EL(ha, "failed, ddi copy; byte cnt = %xh", dxfer);
7873                         rval = EFAULT;
7874                         break;
7875                 }
7876 
7877                 /* adjust the buffer pointer */
7878                 bp = (caddr_t)bp + mem.size;
7879         }
7880 
7881         ql_free_phys(ha, &mem);
7882 
7883         QL_PRINT_9(ha, "done\n");
7884 
7885         return (rval);
7886 }
7887 
7888 /*
7889  * ql_port_param
7890  *      Retrieves or sets the firmware port speed settings
7891  *
7892  * Input:
7893  *      ha:     adapter state pointer.
7894  *      cmd:    Local EXT_IOCTL cmd struct pointer.
7895  *      mode:   flags.
7896  *
7897  * Returns:
7898  *      None, request status indicated in cmd->Status.
7899  *
7900  * Context:
7901  *      Kernel context.
7902  *
7903  */
7904 static void
7905 ql_port_param(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7906 {
7907         uint8_t                 *name;
7908         ql_tgt_t                *tq;
7909         EXT_PORT_PARAM          port_param = {0};
7910         uint32_t                rval = QL_SUCCESS;
7911         uint32_t                idma_rate;
7912 
7913         QL_PRINT_9(ha, "started\n");
7914 
7915         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
7916                 EL(ha, "invalid request for this HBA\n");
7917                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
7918                 cmd->ResponseLen = 0;
7919                 return;
7920         }
7921 
7922         if (LOOP_NOT_READY(ha)) {
7923                 EL(ha, "failed, loop not ready\n");
7924                 cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
7925                 cmd->ResponseLen = 0;
7926                 return;
7927         }
7928 
7929         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
7930             (void*)&port_param, sizeof (EXT_PORT_PARAM), mode) != 0) {
7931                 EL(ha, "failed, ddi_copyin\n");
7932                 cmd->Status = EXT_STATUS_COPY_ERR;
7933                 cmd->ResponseLen = 0;
7934                 return;
7935         }
7936 
7937         if (port_param.FCScsiAddr.DestType != EXT_DEF_DESTTYPE_WWPN) {
7938                 EL(ha, "Unsupported dest lookup type: %xh\n",
7939                     port_param.FCScsiAddr.DestType);
7940                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
7941                 cmd->ResponseLen = 0;
7942                 return;
7943         }
7944 
7945         name = port_param.FCScsiAddr.DestAddr.WWPN;
7946 
7947         QL_PRINT_9(ha, "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
7948             ha->instance, name[0], name[1], name[2], name[3], name[4],
7949             name[5], name[6], name[7]);
7950 
7951         tq = ql_find_port(ha, name, (uint16_t)QLNT_PORT);
7952         if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id) ||
7953             tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
7954                 EL(ha, "failed, fc_port not found\n");
7955                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
7956                 cmd->ResponseLen = 0;
7957                 return;
7958         }
7959 
7960         cmd->Status = EXT_STATUS_OK;
7961         cmd->DetailStatus = EXT_STATUS_OK;
7962 
7963         switch (port_param.Mode) {
7964         case EXT_IIDMA_MODE_GET:
7965                 /*
7966                  * Report the firmware's port rate for the wwpn
7967                  */
7968                 rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate,
7969                     port_param.Mode);
7970 
7971                 if (rval != QL_SUCCESS) {
7972                         EL(ha, "iidma get failed: %xh\n", rval);
7973                         cmd->Status = EXT_STATUS_MAILBOX;
7974                         cmd->DetailStatus = rval;
7975                         cmd->ResponseLen = 0;
7976                 } else {
7977                         switch (idma_rate) {
7978                         case IIDMA_RATE_1GB:
7979                                 port_param.Speed =
7980                                     EXT_DEF_PORTSPEED_1GBIT;
7981                                 break;
7982                         case IIDMA_RATE_2GB:
7983                                 port_param.Speed =
7984                                     EXT_DEF_PORTSPEED_2GBIT;
7985                                 break;
7986                         case IIDMA_RATE_4GB:
7987                                 port_param.Speed =
7988                                     EXT_DEF_PORTSPEED_4GBIT;
7989                                 break;
7990                         case IIDMA_RATE_8GB:
7991                                 port_param.Speed =
7992                                     EXT_DEF_PORTSPEED_8GBIT;
7993                                 break;
7994                         case IIDMA_RATE_10GB:
7995                                 port_param.Speed =
7996                                     EXT_DEF_PORTSPEED_10GBIT;
7997                                 break;
7998                         case IIDMA_RATE_16GB:
7999                                 port_param.Speed =
8000                                     EXT_DEF_PORTSPEED_16GBIT;
8001                                 break;
8002                         case IIDMA_RATE_32GB:
8003                                 port_param.Speed =
8004                                     EXT_DEF_PORTSPEED_32GBIT;
8005                                 break;
8006                         default:
8007                                 port_param.Speed =
8008                                     EXT_DEF_PORTSPEED_UNKNOWN;
8009                                 EL(ha, "failed, Port speed rate=%xh\n",
8010                                     idma_rate);
8011                                 break;
8012                         }
8013 
8014                         /* Copy back the data */
8015                         rval = ddi_copyout((void *)&port_param,
8016                             (void *)(uintptr_t)cmd->ResponseAdr,
8017                             sizeof (EXT_PORT_PARAM), mode);
8018 
8019                         if (rval != 0) {
8020                                 cmd->Status = EXT_STATUS_COPY_ERR;
8021                                 cmd->ResponseLen = 0;
8022                                 EL(ha, "failed, ddi_copyout\n");
8023                         } else {
8024                                 cmd->ResponseLen = (uint32_t)
8025                                     sizeof (EXT_PORT_PARAM);
8026                         }
8027                 }
8028                 break;
8029 
8030         case EXT_IIDMA_MODE_SET:
8031                 /*
8032                  * Set the firmware's port rate for the wwpn
8033                  */
8034                 switch (port_param.Speed) {
8035                 case EXT_DEF_PORTSPEED_1GBIT:
8036                         idma_rate = IIDMA_RATE_1GB;
8037                         break;
8038                 case EXT_DEF_PORTSPEED_2GBIT:
8039                         idma_rate = IIDMA_RATE_2GB;
8040                         break;
8041                 case EXT_DEF_PORTSPEED_4GBIT:
8042                         idma_rate = IIDMA_RATE_4GB;
8043                         break;
8044                 case EXT_DEF_PORTSPEED_8GBIT:
8045                         idma_rate = IIDMA_RATE_8GB;
8046                         break;
8047                 case EXT_DEF_PORTSPEED_10GBIT:
8048                         idma_rate = IIDMA_RATE_10GB;
8049                         break;
8050                 case EXT_DEF_PORTSPEED_16GBIT:
8051                         idma_rate = IIDMA_RATE_16GB;
8052                         break;
8053                 case EXT_DEF_PORTSPEED_32GBIT:
8054                         idma_rate = IIDMA_RATE_32GB;
8055                         break;
8056                 default:
8057                         EL(ha, "invalid set iidma rate: %x\n",
8058                             port_param.Speed);
8059                         cmd->Status = EXT_STATUS_INVALID_PARAM;
8060                         cmd->ResponseLen = 0;
8061                         rval = QL_PARAMETER_ERROR;
8062                         break;
8063                 }
8064 
8065                 if (rval == QL_SUCCESS) {
8066                         rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate,
8067                             port_param.Mode);
8068                         if (rval != QL_SUCCESS) {
8069                                 EL(ha, "iidma set failed: %xh\n", rval);
8070                                 cmd->Status = EXT_STATUS_MAILBOX;
8071                                 cmd->DetailStatus = rval;
8072                                 cmd->ResponseLen = 0;
8073                         }
8074                 }
8075                 break;
8076         default:
8077                 EL(ha, "invalid mode specified: %x\n", port_param.Mode);
8078                 cmd->Status = EXT_STATUS_INVALID_PARAM;
8079                 cmd->ResponseLen = 0;
8080                 cmd->DetailStatus = 0;
8081                 break;
8082         }
8083 
8084         QL_PRINT_9(ha, "done\n");
8085 }
8086 
8087 /*
8088  * ql_get_fwexttrace
8089  *      Dumps f/w extended trace buffer
8090  *
8091  * Input:
8092  *      ha:     adapter state pointer.
8093  *      bp:     buffer address.
8094  *      mode:   flags
8095  *
8096  * Returns:
8097  *
8098  * Context:
8099  *      Kernel context.
8100  */
8101 /* ARGSUSED */
8102 static void
8103 ql_get_fwexttrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8104 {
8105         int     rval;
8106         caddr_t payload;
8107 
8108         QL_PRINT_9(ha, "started\n");
8109 
8110         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
8111                 EL(ha, "invalid request for this HBA\n");
8112                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8113                 cmd->ResponseLen = 0;
8114                 return;
8115         }
8116 
8117         if ((CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) == 0) ||
8118             (ha->fwexttracebuf.bp == NULL)) {
8119                 EL(ha, "f/w extended trace is not enabled\n");
8120                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8121                 cmd->ResponseLen = 0;
8122                 return;
8123         }
8124 
8125         if (cmd->ResponseLen < FWEXTSIZE) {
8126                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8127                 cmd->DetailStatus = FWEXTSIZE;
8128                 EL(ha, "failed, ResponseLen (%xh) < %xh (FWEXTSIZE)\n",
8129                     cmd->ResponseLen, FWEXTSIZE);
8130                 cmd->ResponseLen = 0;
8131                 return;
8132         }
8133 
8134         /* Time Stamp */
8135         rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_INSERT_TIME_STAMP,
8136             NULL);
8137         if (rval != QL_SUCCESS) {
8138                 EL(ha, "f/w extended trace insert"
8139                     "time stamp failed: %xh\n", rval);
8140                 cmd->Status = EXT_STATUS_ERR;
8141                 cmd->ResponseLen = 0;
8142                 return;
8143         }
8144 
8145         /* Disable Tracing */
8146         rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_EXT_TRACE_DISABLE,
8147             NULL);
8148         if (rval != QL_SUCCESS) {
8149                 EL(ha, "f/w extended trace disable failed: %xh\n", rval);
8150                 cmd->Status = EXT_STATUS_ERR;
8151                 cmd->ResponseLen = 0;
8152                 return;
8153         }
8154 
8155         /* Allocate payload buffer */
8156         payload = kmem_zalloc(FWEXTSIZE, KM_SLEEP);
8157         if (payload == NULL) {
8158                 EL(ha, "failed, kmem_zalloc\n");
8159                 cmd->Status = EXT_STATUS_NO_MEMORY;
8160                 cmd->ResponseLen = 0;
8161                 return;
8162         }
8163 
8164         /* Sync DMA buffer. */
8165         (void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
8166             FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL);
8167 
8168         /* Copy trace buffer data. */
8169         ddi_rep_get8(ha->fwexttracebuf.acc_handle, (uint8_t *)payload,
8170             (uint8_t *)ha->fwexttracebuf.bp, FWEXTSIZE,
8171             DDI_DEV_AUTOINCR);
8172 
8173         /* Send payload to application. */
8174         if (ql_send_buffer_data(payload, (caddr_t)(uintptr_t)cmd->ResponseAdr,
8175             cmd->ResponseLen, mode) != cmd->ResponseLen) {
8176                 EL(ha, "failed, send_buffer_data\n");
8177                 cmd->Status = EXT_STATUS_COPY_ERR;
8178                 cmd->ResponseLen = 0;
8179         } else {
8180                 cmd->Status = EXT_STATUS_OK;
8181         }
8182 
8183         kmem_free(payload, FWEXTSIZE);
8184 
8185         QL_PRINT_9(ha, "done\n");
8186 }
8187 
8188 /*
8189  * ql_get_fwfcetrace
8190  *      Dumps f/w fibre channel event trace buffer
8191  *
8192  * Input:
8193  *      ha:     adapter state pointer.
8194  *      bp:     buffer address.
8195  *      mode:   flags
8196  *
8197  * Returns:
8198  *
8199  * Context:
8200  *      Kernel context.
8201  */
8202 /* ARGSUSED */
8203 static void
8204 ql_get_fwfcetrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8205 {
8206         int                     rval;
8207         caddr_t                 fce_trace_p;
8208         ql_mbx_data_t           mr;
8209         EXT_FW_FCE_TRACE        *fce_trace;
8210         size_t                  cnt;
8211         uint32_t                *bp;
8212 
8213         QL_PRINT_9(ha, "started\n");
8214 
8215         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
8216                 EL(ha, "invalid request for this HBA\n");
8217                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8218                 cmd->ResponseLen = 0;
8219                 return;
8220         }
8221 
8222         if ((CFG_IST(ha, CFG_ENABLE_FWFCETRACE) == 0) ||
8223             (ha->fwfcetracebuf.bp == NULL)) {
8224                 EL(ha, "f/w FCE trace is not enabled\n");
8225                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8226                 cmd->ResponseLen = 0;
8227                 return;
8228         }
8229 
8230         if (cmd->ResponseLen < FWFCESIZE) {
8231                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8232                 cmd->DetailStatus = FWFCESIZE;
8233                 EL(ha, "failed, ResponseLen (%xh) < %xh (FWFCESIZE)\n",
8234                     cmd->ResponseLen, FWFCESIZE);
8235                 cmd->ResponseLen = 0;
8236                 return;
8237         }
8238 
8239         /* Disable Tracing */
8240         rval = ql_fw_etrace(ha, &ha->fwfcetracebuf, FTO_FCE_TRACE_DISABLE, &mr);
8241         if (rval != QL_SUCCESS) {
8242                 EL(ha, "f/w FCE trace disable failed: %xh\n", rval);
8243                 cmd->Status = EXT_STATUS_ERR;
8244                 cmd->ResponseLen = 0;
8245                 return;
8246         }
8247 
8248         /* Allocate payload buffer */
8249         fce_trace = kmem_zalloc(FWFCESIZE, KM_SLEEP);
8250         if (fce_trace == NULL) {
8251                 EL(ha, "failed, kmem_zalloc\n");
8252                 cmd->Status = EXT_STATUS_NO_MEMORY;
8253                 cmd->ResponseLen = 0;
8254                 return;
8255         }
8256         fce_trace_p = (caddr_t)&fce_trace->TraceData[0];
8257 
8258         /* Copy In Ponter and Base Pointer values */
8259         fce_trace->Registers[0] = mr.mb[2];
8260         fce_trace->Registers[1] = mr.mb[3];
8261         fce_trace->Registers[2] = mr.mb[4];
8262         fce_trace->Registers[3] = mr.mb[5];
8263 
8264         fce_trace->Registers[4] = LSW(ha->fwexttracebuf.cookies->dmac_address);
8265         fce_trace->Registers[5] = MSW(ha->fwexttracebuf.cookies->dmac_address);
8266         fce_trace->Registers[6] = LSW(ha->fwexttracebuf.cookies->dmac_notused);
8267         fce_trace->Registers[7] = MSW(ha->fwexttracebuf.cookies->dmac_notused);
8268 
8269         /* Copy FCE Trace Enable Registers */
8270         fce_trace->Registers[8] = ha->fw_fce_trace_enable.mb[0];
8271         fce_trace->Registers[9] = ha->fw_fce_trace_enable.mb[2];
8272         fce_trace->Registers[10] = ha->fw_fce_trace_enable.mb[3];
8273         fce_trace->Registers[11] = ha->fw_fce_trace_enable.mb[4];
8274         fce_trace->Registers[12] = ha->fw_fce_trace_enable.mb[5];
8275         fce_trace->Registers[13] = ha->fw_fce_trace_enable.mb[6];
8276 
8277         /* Sync DMA buffer. */
8278         (void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
8279             FWFCESIZE, DDI_DMA_SYNC_FORKERNEL);
8280 
8281         /* Copy trace buffer data. */
8282         ddi_rep_get8(ha->fwfcetracebuf.acc_handle, (uint8_t *)fce_trace_p,
8283             (uint8_t *)ha->fwfcetracebuf.bp, FWFCESIZE,
8284             DDI_DEV_AUTOINCR);
8285 
8286         /* Swap bytes in buffer in case of Big Endian */
8287         bp = (uint32_t *)&fce_trace->TraceData[0];
8288         for (cnt = 0; cnt < (FWFCESIZE / sizeof (uint32_t)); cnt++) {
8289                 LITTLE_ENDIAN_32(bp);
8290                 bp++;
8291         }
8292 
8293         /* Send payload to application. */
8294         if (ql_send_buffer_data((caddr_t)fce_trace,
8295             (caddr_t)(uintptr_t)cmd->ResponseAdr,
8296             cmd->ResponseLen, mode) != cmd->ResponseLen) {
8297                 EL(ha, "failed, send_buffer_data\n");
8298                 cmd->Status = EXT_STATUS_COPY_ERR;
8299                 cmd->ResponseLen = 0;
8300         } else {
8301                 cmd->Status = EXT_STATUS_OK;
8302         }
8303 
8304         /* Re-enable Tracing */
8305         bzero(ha->fwfcetracebuf.bp, ha->fwfcetracebuf.size);
8306         if ((rval = ql_fw_etrace(ha, &ha->fwfcetracebuf,
8307             FTO_FCE_TRACE_ENABLE, &mr)) != QL_SUCCESS) {
8308                 EL(ha, "fcetrace enable failed: %xh\n", rval);
8309         } else {
8310                 ha->fw_fce_trace_enable = mr;
8311                 EL(ha, "FCE Trace Re-Enabled\n");
8312         }
8313 
8314         kmem_free(fce_trace, FWFCESIZE);
8315 
8316         QL_PRINT_9(ha, "done\n");
8317 }
8318 
8319 /*
8320  * ql_get_pci_data
8321  *      Retrieves pci config space data
8322  *
8323  * Input:
8324  *      ha:     adapter state pointer.
8325  *      cmd:    Local EXT_IOCTL cmd struct pointer.
8326  *      mode:   flags.
8327  *
8328  * Returns:
8329  *      None, request status indicated in cmd->Status.
8330  *
8331  * Context:
8332  *      Kernel context.
8333  *
8334  */
8335 static void
8336 ql_get_pci_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8337 {
8338         uint8_t         cap_ptr;
8339         uint8_t         cap_id;
8340         uint32_t        buf_size = 256;
8341 
8342         QL_PRINT_9(ha, "started\n");
8343 
8344         /*
8345          * First check the "Capabilities List" bit of the status register.
8346          */
8347         if (ql_pci_config_get16(ha, PCI_CONF_STAT) & PCI_STAT_CAP) {
8348                 /*
8349                  * Now get the capability pointer
8350                  */
8351                 cap_ptr = (uint8_t)ql_pci_config_get8(ha, PCI_CONF_CAP_PTR);
8352                 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
8353                         /*
8354                          * Check for the pcie capability.
8355                          */
8356                         cap_id = (uint8_t)ql_pci_config_get8(ha, cap_ptr);
8357                         if (cap_id == PCI_CAP_ID_PCI_E) {
8358                                 buf_size = 4096;
8359                                 break;
8360                         }
8361                         cap_ptr = (uint8_t)ql_pci_config_get8(ha,
8362                             (cap_ptr + PCI_CAP_NEXT_PTR));
8363                 }
8364         }
8365 
8366         if (cmd->ResponseLen < buf_size) {
8367                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8368                 cmd->DetailStatus = buf_size;
8369                 EL(ha, "failed ResponseLen < buf_size, len passed=%xh\n",
8370                     cmd->ResponseLen);
8371                 return;
8372         }
8373 
8374         /* Dump PCI config data. */
8375         if ((ql_pci_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
8376             buf_size, mode)) != 0) {
8377                 cmd->Status = EXT_STATUS_COPY_ERR;
8378                 cmd->DetailStatus = 0;
8379                 EL(ha, "failed, copy err pci_dump\n");
8380         } else {
8381                 cmd->Status = EXT_STATUS_OK;
8382                 cmd->DetailStatus = buf_size;
8383         }
8384 
8385         QL_PRINT_9(ha, "done\n");
8386 }
8387 
8388 /*
8389  * ql_pci_dump
8390  *      Dumps PCI config data to application buffer.
8391  *
8392  * Input:
8393  *      ha = adapter state pointer.
8394  *      bp = user buffer address.
8395  *
8396  * Returns:
8397  *
8398  * Context:
8399  *      Kernel context.
8400  */
8401 int
8402 ql_pci_dump(ql_adapter_state_t *ha, uint32_t *bp, uint32_t pci_size, int mode)
8403 {
8404         uint32_t        pci_os;
8405         uint32_t        *ptr32, *org_ptr32;
8406 
8407         QL_PRINT_9(ha, "started\n");
8408 
8409         ptr32 = kmem_zalloc(pci_size, KM_SLEEP);
8410         if (ptr32 == NULL) {
8411                 EL(ha, "failed kmem_zalloc\n");
8412                 return (ENOMEM);
8413         }
8414 
8415         /* store the initial value of ptr32 */
8416         org_ptr32 = ptr32;
8417         for (pci_os = 0; pci_os < pci_size; pci_os += 4) {
8418                 *ptr32 = (uint32_t)ql_pci_config_get32(ha, pci_os);
8419                 LITTLE_ENDIAN_32(ptr32);
8420                 ptr32++;
8421         }
8422 
8423         if (ddi_copyout((void *)org_ptr32, (void *)bp, pci_size, mode) !=
8424             0) {
8425                 EL(ha, "failed ddi_copyout\n");
8426                 kmem_free(org_ptr32, pci_size);
8427                 return (EFAULT);
8428         }
8429 
8430         QL_DUMP_9(org_ptr32, 8, pci_size);
8431 
8432         kmem_free(org_ptr32, pci_size);
8433 
8434         QL_PRINT_9(ha, "done\n");
8435 
8436         return (0);
8437 }
8438 
8439 /*
8440  * ql_menlo_reset
8441  *      Reset Menlo
8442  *
8443  * Input:
8444  *      ha:     adapter state pointer.
8445  *      bp:     buffer address.
8446  *      mode:   flags
8447  *
8448  * Returns:
8449  *
8450  * Context:
8451  *      Kernel context.
8452  */
8453 static void
8454 ql_menlo_reset(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8455 {
8456         EXT_MENLO_RESET rst;
8457         ql_mbx_data_t   mr;
8458         int             rval;
8459 
8460         QL_PRINT_9(ha, "started\n");
8461 
8462         if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8463                 EL(ha, "failed, invalid request for HBA\n");
8464                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8465                 cmd->ResponseLen = 0;
8466                 return;
8467         }
8468 
8469         /*
8470          * TODO: only vp_index 0 can do this (?)
8471          */
8472 
8473         /*  Verify the size of request structure. */
8474         if (cmd->RequestLen < sizeof (EXT_MENLO_RESET)) {
8475                 /* Return error */
8476                 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8477                     sizeof (EXT_MENLO_RESET));
8478                 cmd->Status = EXT_STATUS_INVALID_PARAM;
8479                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8480                 cmd->ResponseLen = 0;
8481                 return;
8482         }
8483 
8484         /* Get reset request. */
8485         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
8486             (void *)&rst, sizeof (EXT_MENLO_RESET), mode) != 0) {
8487                 EL(ha, "failed, ddi_copyin\n");
8488                 cmd->Status = EXT_STATUS_COPY_ERR;
8489                 cmd->ResponseLen = 0;
8490                 return;
8491         }
8492 
8493         /* Wait for I/O to stop and daemon to stall. */
8494         if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8495                 EL(ha, "ql_stall_driver failed\n");
8496                 ql_restart_hba(ha);
8497                 cmd->Status = EXT_STATUS_BUSY;
8498                 cmd->ResponseLen = 0;
8499                 return;
8500         }
8501 
8502         rval = ql_reset_menlo(ha, &mr, rst.Flags);
8503         if (rval != QL_SUCCESS) {
8504                 EL(ha, "failed, status=%xh\n", rval);
8505                 cmd->Status = EXT_STATUS_MAILBOX;
8506                 cmd->DetailStatus = rval;
8507                 cmd->ResponseLen = 0;
8508         } else if (mr.mb[1] != 0) {
8509                 EL(ha, "failed, substatus=%d\n", mr.mb[1]);
8510                 cmd->Status = EXT_STATUS_ERR;
8511                 cmd->DetailStatus = mr.mb[1];
8512                 cmd->ResponseLen = 0;
8513         }
8514 
8515         ql_restart_hba(ha);
8516 
8517         QL_PRINT_9(ha, "done\n");
8518 }
8519 
8520 /*
8521  * ql_menlo_get_fw_version
8522  *      Get Menlo firmware version.
8523  *
8524  * Input:
8525  *      ha:     adapter state pointer.
8526  *      bp:     buffer address.
8527  *      mode:   flags
8528  *
8529  * Returns:
8530  *
8531  * Context:
8532  *      Kernel context.
8533  */
8534 static void
8535 ql_menlo_get_fw_version(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8536 {
8537         int                             rval;
8538         ql_mbx_iocb_t                   *pkt;
8539         EXT_MENLO_GET_FW_VERSION        ver = {0};
8540 
8541         QL_PRINT_9(ha, "started\n");
8542 
8543         if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8544                 EL(ha, "failed, invalid request for HBA\n");
8545                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8546                 cmd->ResponseLen = 0;
8547                 return;
8548         }
8549 
8550         if (cmd->ResponseLen < sizeof (EXT_MENLO_GET_FW_VERSION)) {
8551                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8552                 cmd->DetailStatus = sizeof (EXT_MENLO_GET_FW_VERSION);
8553                 EL(ha, "ResponseLen=%d < %d\n", cmd->ResponseLen,
8554                     sizeof (EXT_MENLO_GET_FW_VERSION));
8555                 cmd->ResponseLen = 0;
8556                 return;
8557         }
8558 
8559         /* Allocate packet. */
8560         pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8561         if (pkt == NULL) {
8562                 EL(ha, "failed, kmem_zalloc\n");
8563                 cmd->Status = EXT_STATUS_NO_MEMORY;
8564                 cmd->ResponseLen = 0;
8565                 return;
8566         }
8567 
8568         pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
8569         pkt->mvfy.entry_count = 1;
8570         pkt->mvfy.options_status = LE_16(VMF_DO_NOT_UPDATE_FW);
8571 
8572         rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8573         LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
8574         LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
8575         ver.FwVersion = LE_32(pkt->mvfy.fw_version);
8576 
8577         if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 ||
8578             pkt->mvfy.options_status != CS_COMPLETE) {
8579                 /* Command error */
8580                 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8581                     pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status,
8582                     pkt->mvfy.failure_code);
8583                 cmd->Status = EXT_STATUS_ERR;
8584                 cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8585                     QL_FUNCTION_FAILED;
8586                 cmd->ResponseLen = 0;
8587         } else if (ddi_copyout((void *)&ver,
8588             (void *)(uintptr_t)cmd->ResponseAdr,
8589             sizeof (EXT_MENLO_GET_FW_VERSION), mode) != 0) {
8590                 EL(ha, "failed, ddi_copyout\n");
8591                 cmd->Status = EXT_STATUS_COPY_ERR;
8592                 cmd->ResponseLen = 0;
8593         } else {
8594                 cmd->ResponseLen = sizeof (EXT_MENLO_GET_FW_VERSION);
8595         }
8596 
8597         kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8598 
8599         QL_PRINT_9(ha, "done\n");
8600 }
8601 
8602 /*
8603  * ql_menlo_update_fw
8604  *      Get Menlo update firmware.
8605  *
8606  * Input:
8607  *      ha:     adapter state pointer.
8608  *      bp:     buffer address.
8609  *      mode:   flags
8610  *
8611  * Returns:
8612  *
8613  * Context:
8614  *      Kernel context.
8615  */
8616 static void
8617 ql_menlo_update_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8618 {
8619         ql_mbx_iocb_t           *pkt;
8620         dma_mem_t               *dma_mem;
8621         EXT_MENLO_UPDATE_FW     fw;
8622         uint32_t                *ptr32;
8623         int                     rval;
8624 
8625         QL_PRINT_9(ha, "started\n");
8626 
8627         if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8628                 EL(ha, "failed, invalid request for HBA\n");
8629                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8630                 cmd->ResponseLen = 0;
8631                 return;
8632         }
8633 
8634         /*
8635          * TODO: only vp_index 0 can do this (?)
8636          */
8637 
8638         /*  Verify the size of request structure. */
8639         if (cmd->RequestLen < sizeof (EXT_MENLO_UPDATE_FW)) {
8640                 /* Return error */
8641                 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8642                     sizeof (EXT_MENLO_UPDATE_FW));
8643                 cmd->Status = EXT_STATUS_INVALID_PARAM;
8644                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8645                 cmd->ResponseLen = 0;
8646                 return;
8647         }
8648 
8649         /* Get update fw request. */
8650         if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr, (caddr_t)&fw,
8651             sizeof (EXT_MENLO_UPDATE_FW), mode) != 0) {
8652                 EL(ha, "failed, ddi_copyin\n");
8653                 cmd->Status = EXT_STATUS_COPY_ERR;
8654                 cmd->ResponseLen = 0;
8655                 return;
8656         }
8657 
8658         /* Wait for I/O to stop and daemon to stall. */
8659         if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8660                 EL(ha, "ql_stall_driver failed\n");
8661                 ql_restart_hba(ha);
8662                 cmd->Status = EXT_STATUS_BUSY;
8663                 cmd->ResponseLen = 0;
8664                 return;
8665         }
8666 
8667         /* Allocate packet. */
8668         dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
8669         if (dma_mem == NULL) {
8670                 EL(ha, "failed, kmem_zalloc\n");
8671                 cmd->Status = EXT_STATUS_NO_MEMORY;
8672                 cmd->ResponseLen = 0;
8673                 return;
8674         }
8675         pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8676         if (pkt == NULL) {
8677                 EL(ha, "failed, kmem_zalloc\n");
8678                 kmem_free(dma_mem, sizeof (dma_mem_t));
8679                 ql_restart_hba(ha);
8680                 cmd->Status = EXT_STATUS_NO_MEMORY;
8681                 cmd->ResponseLen = 0;
8682                 return;
8683         }
8684 
8685         /* Get DMA memory for the IOCB */
8686         if (ql_get_dma_mem(ha, dma_mem, fw.TotalByteCount, LITTLE_ENDIAN_DMA,
8687             QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
8688                 cmn_err(CE_WARN, "%srequest queue DMA memory "
8689                     "alloc failed", QL_NAME);
8690                 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8691                 kmem_free(dma_mem, sizeof (dma_mem_t));
8692                 ql_restart_hba(ha);
8693                 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
8694                 cmd->ResponseLen = 0;
8695                 return;
8696         }
8697 
8698         /* Get firmware data. */
8699         if (ql_get_buffer_data((caddr_t)(uintptr_t)fw.pFwDataBytes, dma_mem->bp,
8700             fw.TotalByteCount, mode) != fw.TotalByteCount) {
8701                 EL(ha, "failed, get_buffer_data\n");
8702                 ql_free_dma_resource(ha, dma_mem);
8703                 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8704                 kmem_free(dma_mem, sizeof (dma_mem_t));
8705                 ql_restart_hba(ha);
8706                 cmd->Status = EXT_STATUS_COPY_ERR;
8707                 cmd->ResponseLen = 0;
8708                 return;
8709         }
8710 
8711         /* Sync DMA buffer. */
8712         (void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size,
8713             DDI_DMA_SYNC_FORDEV);
8714 
8715         pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
8716         pkt->mvfy.entry_count = 1;
8717         pkt->mvfy.options_status = (uint16_t)LE_16(fw.Flags);
8718         ptr32 = dma_mem->bp;
8719         pkt->mvfy.fw_version = LE_32(ptr32[2]);
8720         pkt->mvfy.fw_size = LE_32(fw.TotalByteCount);
8721         pkt->mvfy.fw_sequence_size = LE_32(fw.TotalByteCount);
8722         pkt->mvfy.dseg_count = LE_16(1);
8723         pkt->mvfy.dseg.address[0] = (uint32_t)
8724             LE_32(LSD(dma_mem->cookie.dmac_laddress));
8725         pkt->mvfy.dseg.address[1] = (uint32_t)
8726             LE_32(MSD(dma_mem->cookie.dmac_laddress));
8727         pkt->mvfy.dseg.length = LE_32(fw.TotalByteCount);
8728 
8729         rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8730         LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
8731         LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
8732 
8733         if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 ||
8734             pkt->mvfy.options_status != CS_COMPLETE) {
8735                 /* Command error */
8736                 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8737                     pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status,
8738                     pkt->mvfy.failure_code);
8739                 cmd->Status = EXT_STATUS_ERR;
8740                 cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8741                     QL_FUNCTION_FAILED;
8742                 cmd->ResponseLen = 0;
8743         }
8744 
8745         ql_free_dma_resource(ha, dma_mem);
8746         kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8747         kmem_free(dma_mem, sizeof (dma_mem_t));
8748         ql_restart_hba(ha);
8749 
8750         QL_PRINT_9(ha, "done\n");
8751 }
8752 
8753 /*
8754  * ql_menlo_manage_info
8755  *      Get Menlo manage info.
8756  *
8757  * Input:
8758  *      ha:     adapter state pointer.
8759  *      bp:     buffer address.
8760  *      mode:   flags
8761  *
8762  * Returns:
8763  *
8764  * Context:
8765  *      Kernel context.
8766  */
8767 static void
8768 ql_menlo_manage_info(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8769 {
8770         ql_mbx_iocb_t           *pkt;
8771         dma_mem_t               *dma_mem = NULL;
8772         EXT_MENLO_MANAGE_INFO   info;
8773         int                     rval;
8774 
8775         QL_PRINT_9(ha, "started\n");
8776 
8777 
8778         /* The call is only supported for Schultz right now */
8779         if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
8780                 ql_get_xgmac_statistics(ha, cmd, mode);
8781                 QL_PRINT_9(ha, "CFG_FCOE_SUPPORT done\n");
8782                 return;
8783         }
8784 
8785         if (!CFG_IST(ha, CFG_CTRL_MENLO)) {
8786                 EL(ha, "failed, invalid request for HBA\n");
8787                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
8788                 cmd->ResponseLen = 0;
8789                 return;
8790         }
8791 
8792         /*  Verify the size of request structure. */
8793         if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) {
8794                 /* Return error */
8795                 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8796                     sizeof (EXT_MENLO_MANAGE_INFO));
8797                 cmd->Status = EXT_STATUS_INVALID_PARAM;
8798                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8799                 cmd->ResponseLen = 0;
8800                 return;
8801         }
8802 
8803         /* Get manage info request. */
8804         if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
8805             (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) {
8806                 EL(ha, "failed, ddi_copyin\n");
8807                 cmd->Status = EXT_STATUS_COPY_ERR;
8808                 cmd->ResponseLen = 0;
8809                 return;
8810         }
8811 
8812         /* Allocate packet. */
8813         pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8814         if (pkt == NULL) {
8815                 EL(ha, "failed, kmem_zalloc\n");
8816                 ql_restart_driver(ha);
8817                 cmd->Status = EXT_STATUS_NO_MEMORY;
8818                 cmd->ResponseLen = 0;
8819                 return;
8820         }
8821 
8822         pkt->mdata.entry_type = MENLO_DATA_TYPE;
8823         pkt->mdata.entry_count = 1;
8824         pkt->mdata.options_status = (uint16_t)LE_16(info.Operation);
8825 
8826         /* Get DMA memory for the IOCB */
8827         if (info.Operation == MENLO_OP_READ_MEM ||
8828             info.Operation == MENLO_OP_WRITE_MEM) {
8829                 pkt->mdata.total_byte_count = LE_32(info.TotalByteCount);
8830                 pkt->mdata.parameter_1 =
8831                     LE_32(info.Parameters.ap.MenloMemory.StartingAddr);
8832                 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t),
8833                     KM_SLEEP);
8834                 if (dma_mem == NULL) {
8835                         EL(ha, "failed, kmem_zalloc\n");
8836                         kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8837                         cmd->Status = EXT_STATUS_NO_MEMORY;
8838                         cmd->ResponseLen = 0;
8839                         return;
8840                 }
8841                 if (ql_get_dma_mem(ha, dma_mem, info.TotalByteCount,
8842                     LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
8843                         cmn_err(CE_WARN, "%srequest queue DMA memory "
8844                             "alloc failed", QL_NAME);
8845                         kmem_free(dma_mem, sizeof (dma_mem_t));
8846                         kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8847                         cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
8848                         cmd->ResponseLen = 0;
8849                         return;
8850                 }
8851                 if (info.Operation == MENLO_OP_WRITE_MEM) {
8852                         /* Get data. */
8853                         if (ql_get_buffer_data(
8854                             (caddr_t)(uintptr_t)info.pDataBytes,
8855                             dma_mem->bp, info.TotalByteCount, mode) !=
8856                             info.TotalByteCount) {
8857                                 EL(ha, "failed, get_buffer_data\n");
8858                                 ql_free_dma_resource(ha, dma_mem);
8859                                 kmem_free(dma_mem, sizeof (dma_mem_t));
8860                                 kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8861                                 cmd->Status = EXT_STATUS_COPY_ERR;
8862                                 cmd->ResponseLen = 0;
8863                                 return;
8864                         }
8865                         (void) ddi_dma_sync(dma_mem->dma_handle, 0,
8866                             dma_mem->size, DDI_DMA_SYNC_FORDEV);
8867                 }
8868                 pkt->mdata.dseg_count = LE_16(1);
8869                 pkt->mdata.dseg.address[0] = (uint32_t)
8870                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
8871                 pkt->mdata.dseg.address[1] = (uint32_t)
8872                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
8873                 pkt->mdata.dseg.length = LE_32(info.TotalByteCount);
8874         } else if (info.Operation & MENLO_OP_CHANGE_CONFIG) {
8875                 pkt->mdata.parameter_1 =
8876                     LE_32(info.Parameters.ap.MenloConfig.ConfigParamID);
8877                 pkt->mdata.parameter_2 =
8878                     LE_32(info.Parameters.ap.MenloConfig.ConfigParamData0);
8879                 pkt->mdata.parameter_3 =
8880                     LE_32(info.Parameters.ap.MenloConfig.ConfigParamData1);
8881         } else if (info.Operation & MENLO_OP_GET_INFO) {
8882                 pkt->mdata.parameter_1 =
8883                     LE_32(info.Parameters.ap.MenloInfo.InfoDataType);
8884                 pkt->mdata.parameter_2 =
8885                     LE_32(info.Parameters.ap.MenloInfo.InfoContext);
8886         }
8887 
8888         rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8889         LITTLE_ENDIAN_16(&pkt->mdata.options_status);
8890         LITTLE_ENDIAN_16(&pkt->mdata.failure_code);
8891 
8892         if (rval != QL_SUCCESS || (pkt->mdata.entry_status & 0x3c) != 0 ||
8893             pkt->mdata.options_status != CS_COMPLETE) {
8894                 /* Command error */
8895                 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8896                     pkt->mdata.entry_status & 0x3c, pkt->mdata.options_status,
8897                     pkt->mdata.failure_code);
8898                 cmd->Status = EXT_STATUS_ERR;
8899                 cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8900                     QL_FUNCTION_FAILED;
8901                 cmd->ResponseLen = 0;
8902         } else if (info.Operation == MENLO_OP_READ_MEM) {
8903                 (void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size,
8904                     DDI_DMA_SYNC_FORKERNEL);
8905                 if (ql_send_buffer_data((caddr_t)(uintptr_t)info.pDataBytes,
8906                     dma_mem->bp, info.TotalByteCount, mode) !=
8907                     info.TotalByteCount) {
8908                         cmd->Status = EXT_STATUS_COPY_ERR;
8909                         cmd->ResponseLen = 0;
8910                 }
8911         }
8912 
8913         ql_free_dma_resource(ha, dma_mem);
8914         kmem_free(dma_mem, sizeof (dma_mem_t));
8915         kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8916 
8917         QL_PRINT_9(ha, "done\n");
8918 }
8919 
8920 /*
8921  * ql_suspend_hba
8922  *      Suspends all adapter ports.
8923  *
8924  * Input:
8925  *      ha:             adapter state pointer.
8926  *      options:        BIT_0 --> leave driver stalled on exit if
8927  *                                failed.
8928  *
8929  * Returns:
8930  *      ql local function return status code.
8931  *
8932  * Context:
8933  *      Kernel context.
8934  */
8935 static int
8936 ql_suspend_hba(ql_adapter_state_t *ha, uint32_t opt)
8937 {
8938         ql_adapter_state_t      *ha2;
8939         ql_link_t               *link;
8940         int                     rval = QL_SUCCESS;
8941 
8942         /* Quiesce I/O on all adapter ports */
8943         for (link = ql_hba.first; link != NULL; link = link->next) {
8944                 ha2 = link->base_address;
8945 
8946                 if (ha2->fru_hba_index != ha->fru_hba_index) {
8947                         continue;
8948                 }
8949 
8950                 if ((rval = ql_stall_driver(ha2, opt)) != QL_SUCCESS) {
8951                         EL(ha, "ql_stall_driver status=%xh\n", rval);
8952                         break;
8953                 }
8954         }
8955 
8956         return (rval);
8957 }
8958 
8959 /*
8960  * ql_restart_hba
8961  *      Restarts adapter.
8962  *
8963  * Input:
8964  *      ha:     adapter state pointer.
8965  *
8966  * Context:
8967  *      Kernel context.
8968  */
8969 static void
8970 ql_restart_hba(ql_adapter_state_t *ha)
8971 {
8972         ql_adapter_state_t      *ha2;
8973         ql_link_t               *link;
8974 
8975         /* Resume I/O on all adapter ports */
8976         for (link = ql_hba.first; link != NULL; link = link->next) {
8977                 ha2 = link->base_address;
8978 
8979                 if (ha2->fru_hba_index != ha->fru_hba_index) {
8980                         continue;
8981                 }
8982 
8983                 ql_restart_driver(ha2);
8984         }
8985 }
8986 
8987 /*
8988  * ql_get_vp_cnt_id
8989  *      Retrieves pci config space data
8990  *
8991  * Input:
8992  *      ha:     adapter state pointer.
8993  *      cmd:    Local EXT_IOCTL cmd struct pointer.
8994  *      mode:   flags.
8995  *
8996  * Returns:
8997  *      None, request status indicated in cmd->Status.
8998  *
8999  * Context:
9000  *      Kernel context.
9001  *
9002  */
9003 static void
9004 ql_get_vp_cnt_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9005 {
9006         ql_adapter_state_t      *vha;
9007         PEXT_VPORT_ID_CNT       ptmp_vp;
9008         int                     id = 0;
9009         int                     rval;
9010         char                    name[MAXPATHLEN];
9011 
9012         QL_PRINT_9(ha, "started\n");
9013 
9014         /*
9015          * To be backward compatible with older API
9016          * check for the size of old EXT_VPORT_ID_CNT
9017          */
9018         if (cmd->ResponseLen < sizeof (EXT_VPORT_ID_CNT) &&
9019             (cmd->ResponseLen != EXT_OLD_VPORT_ID_CNT_SIZE)) {
9020                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9021                 cmd->DetailStatus = sizeof (EXT_VPORT_ID_CNT);
9022                 EL(ha, "failed, ResponseLen < EXT_VPORT_ID_CNT, Len=%xh\n",
9023                     cmd->ResponseLen);
9024                 cmd->ResponseLen = 0;
9025                 return;
9026         }
9027 
9028         ptmp_vp = (EXT_VPORT_ID_CNT *)
9029             kmem_zalloc(sizeof (EXT_VPORT_ID_CNT), KM_SLEEP);
9030         if (ptmp_vp == NULL) {
9031                 EL(ha, "failed, kmem_zalloc\n");
9032                 cmd->ResponseLen = 0;
9033                 return;
9034         }
9035         vha = ha->vp_next;
9036         while (vha != NULL) {
9037                 ptmp_vp->VpCnt++;
9038                 ptmp_vp->VpId[id] = vha->vp_index;
9039                 (void) ddi_pathname(vha->dip, name);
9040                 (void) strncpy((char *)ptmp_vp->vp_path[id], name,
9041                     (sizeof (ptmp_vp->vp_path[id]) -1));
9042                 ptmp_vp->VpDrvInst[id] = (int32_t)vha->instance;
9043                 id++;
9044                 vha = vha->vp_next;
9045         }
9046         rval = ddi_copyout((void *)ptmp_vp,
9047             (void *)(uintptr_t)(cmd->ResponseAdr),
9048             cmd->ResponseLen, mode);
9049         if (rval != 0) {
9050                 cmd->Status = EXT_STATUS_COPY_ERR;
9051                 cmd->ResponseLen = 0;
9052                 EL(ha, "failed, ddi_copyout\n");
9053         } else {
9054                 cmd->ResponseLen = sizeof (EXT_VPORT_ID_CNT);
9055                 QL_PRINT_9(ha, "done, vport_cnt=%d\n",
9056                     ha->instance, ptmp_vp->VpCnt);
9057         }
9058         kmem_free(ptmp_vp, sizeof (EXT_VPORT_ID_CNT));
9059 }
9060 
9061 /*
9062  * ql_vp_ioctl
9063  *      Performs all EXT_CC_VPORT_CMD functions.
9064  *
9065  * Input:
9066  *      ha:     adapter state pointer.
9067  *      cmd:    Local EXT_IOCTL cmd struct pointer.
9068  *      mode:   flags.
9069  *
9070  * Returns:
9071  *      None, request status indicated in cmd->Status.
9072  *
9073  * Context:
9074  *      Kernel context.
9075  */
9076 static void
9077 ql_vp_ioctl(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9078 {
9079         QL_PRINT_9(ha, "started, cmd=%d\n",
9080             cmd->SubCode);
9081 
9082         /* case off on command subcode */
9083         switch (cmd->SubCode) {
9084         case EXT_VF_SC_VPORT_GETINFO:
9085                 ql_qry_vport(ha, cmd, mode);
9086                 break;
9087         default:
9088                 /* function not supported. */
9089                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
9090                 EL(ha, "failed, Unsupported Subcode=%xh\n",
9091                     cmd->SubCode);
9092                 break;
9093         }
9094 
9095         QL_PRINT_9(ha, "done\n");
9096 }
9097 
9098 /*
9099  * ql_qry_vport
9100  *      Performs EXT_VF_SC_VPORT_GETINFO subfunction.
9101  *
9102  * Input:
9103  *      ha:     adapter state pointer.
9104  *      cmd:    EXT_IOCTL cmd struct pointer.
9105  *      mode:   flags.
9106  *
9107  * Returns:
9108  *      None, request status indicated in cmd->Status.
9109  *
9110  * Context:
9111  *      Kernel context.
9112  */
9113 static void
9114 ql_qry_vport(ql_adapter_state_t *vha, EXT_IOCTL *cmd, int mode)
9115 {
9116         ql_adapter_state_t      *tmp_vha;
9117         EXT_VPORT_INFO          tmp_vport = {0};
9118 
9119         QL_PRINT_9(vha, "started\n", vha->instance);
9120 
9121         if (cmd->ResponseLen < sizeof (EXT_VPORT_INFO)) {
9122                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9123                 cmd->DetailStatus = sizeof (EXT_VPORT_INFO);
9124                 EL(vha, "failed, ResponseLen < EXT_VPORT_INFO, Len=%xh\n",
9125                     cmd->ResponseLen);
9126                 cmd->ResponseLen = 0;
9127                 return;
9128         }
9129 
9130         /* Fill in the vport information. */
9131         bcopy(vha->loginparams.node_ww_name.raw_wwn, tmp_vport.wwnn,
9132             EXT_DEF_WWN_NAME_SIZE);
9133         bcopy(vha->loginparams.nport_ww_name.raw_wwn, tmp_vport.wwpn,
9134             EXT_DEF_WWN_NAME_SIZE);
9135         tmp_vport.state = vha->state;
9136         tmp_vport.id = vha->vp_index;
9137 
9138         tmp_vha = vha->pha->vp_next;
9139         while (tmp_vha != NULL) {
9140                 tmp_vport.used++;
9141                 tmp_vha = tmp_vha->vp_next;
9142         }
9143 
9144         if (vha->max_vports > tmp_vport.used) {
9145                 tmp_vport.free = vha->max_vports - tmp_vport.used;
9146         }
9147 
9148         if (ddi_copyout((void *)&tmp_vport,
9149             (void *)(uintptr_t)(cmd->ResponseAdr),
9150             sizeof (EXT_VPORT_INFO), mode) != 0) {
9151                 cmd->Status = EXT_STATUS_COPY_ERR;
9152                 cmd->ResponseLen = 0;
9153                 EL(vha, "failed, ddi_copyout\n");
9154         } else {
9155                 cmd->ResponseLen = sizeof (EXT_VPORT_INFO);
9156                 QL_PRINT_9(vha, "done\n", vha->instance);
9157         }
9158 }
9159 
9160 /*
9161  * ql_access_flash
9162  *      Performs all EXT_CC_ACCESS_FLASH_OS functions.
9163  *
9164  * Input:
9165  *      pi:     port info pointer.
9166  *      cmd:    Local EXT_IOCTL cmd struct pointer.
9167  *      mode:   flags.
9168  *
9169  * Returns:
9170  *      None, request status indicated in cmd->Status.
9171  *
9172  * Context:
9173  *      Kernel context.
9174  */
9175 static void
9176 ql_access_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9177 {
9178         int     rval;
9179 
9180         QL_PRINT_9(ha, "started\n");
9181 
9182         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) &&
9183             ql_stall_driver(ha, 0) != QL_SUCCESS) {
9184                 EL(ha, "ql_stall_driver failed\n");
9185                 ql_restart_driver(ha);
9186                 cmd->Status = EXT_STATUS_BUSY;
9187                 cmd->ResponseLen = 0;
9188                 return;
9189         }
9190 
9191         switch (cmd->SubCode) {
9192         case EXT_SC_FLASH_READ:
9193                 if ((rval = ql_flash_fcode_dump(ha,
9194                     (void *)(uintptr_t)(cmd->ResponseAdr),
9195                     (size_t)(cmd->ResponseLen), cmd->Reserved1, mode)) != 0) {
9196                         cmd->Status = EXT_STATUS_COPY_ERR;
9197                         cmd->ResponseLen = 0;
9198                         EL(ha, "flash_fcode_dump status=%xh\n", rval);
9199                 }
9200                 break;
9201         case EXT_SC_FLASH_WRITE:
9202                 if ((rval = ql_r_m_w_flash(ha,
9203                     (void *)(uintptr_t)(cmd->RequestAdr),
9204                     (size_t)(cmd->RequestLen), cmd->Reserved1, mode)) !=
9205                     QL_SUCCESS) {
9206                         cmd->Status = EXT_STATUS_COPY_ERR;
9207                         cmd->ResponseLen = 0;
9208                         EL(ha, "r_m_w_flash status=%xh\n", rval);
9209                 } else {
9210                         /* Reset caches on all adapter instances. */
9211                         ql_update_flash_caches(ha);
9212                 }
9213                 break;
9214         default:
9215                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9216                 cmd->Status = EXT_STATUS_ERR;
9217                 cmd->ResponseLen = 0;
9218                 break;
9219         }
9220 
9221         /* Resume I/O */
9222         if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
9223                 EL(ha, "isp_abort_needed for restart\n");
9224                 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
9225                     DRIVER_STALL);
9226         }
9227 
9228         QL_PRINT_9(ha, "done\n");
9229 }
9230 
9231 /*
9232  * ql_reset_cmd
9233  *      Performs all EXT_CC_RESET_FW_OS functions.
9234  *
9235  * Input:
9236  *      ha:     adapter state pointer.
9237  *      cmd:    Local EXT_IOCTL cmd struct pointer.
9238  *
9239  * Returns:
9240  *      None, request status indicated in cmd->Status.
9241  *
9242  * Context:
9243  *      Kernel context.
9244  */
9245 static void
9246 ql_reset_cmd(ql_adapter_state_t *ha, EXT_IOCTL *cmd)
9247 {
9248         uint8_t timer;
9249 
9250         QL_PRINT_9(ha, "started\n");
9251 
9252         switch (cmd->SubCode) {
9253         case EXT_SC_RESET_FC_FW:
9254                 if (CFG_IST(ha, CFG_CTRL_82XX)) {
9255                         (void) ql_8021_reset_fw(ha);
9256                 } else {
9257                         EL(ha, "isp_abort_needed\n");
9258                         ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0);
9259                 }
9260                 for (timer = 180; timer; timer--) {
9261                         ql_awaken_task_daemon(ha, NULL, 0, 0);
9262                         /* Delay for 1 second. */
9263                         delay(100);
9264                         if (!(ha->task_daemon_flags & (ISP_ABORT_NEEDED |
9265                             ABORT_ISP_ACTIVE | LOOP_RESYNC_NEEDED |
9266                             LOOP_RESYNC_ACTIVE))) {
9267                                 break;
9268                         }
9269                 }
9270                 break;
9271         case EXT_SC_RESET_MPI_FW:
9272                 if (!(CFG_IST(ha, CFG_CTRL_8081))) {
9273                         EL(ha, "invalid request for HBA\n");
9274                         cmd->Status = EXT_STATUS_INVALID_REQUEST;
9275                         cmd->ResponseLen = 0;
9276                 } else {
9277                         ADAPTER_STATE_LOCK(ha);
9278                         ha->flags |= DISABLE_NIC_FW_DMP;
9279                         ADAPTER_STATE_UNLOCK(ha);
9280 
9281                         /* Wait for I/O to stop and daemon to stall. */
9282                         if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
9283                                 EL(ha, "ql_suspend_hba failed\n");
9284                                 cmd->Status = EXT_STATUS_BUSY;
9285                                 cmd->ResponseLen = 0;
9286                         } else if (ql_restart_mpi(ha) != QL_SUCCESS) {
9287                                 cmd->Status = EXT_STATUS_ERR;
9288                                 cmd->ResponseLen = 0;
9289                         } else {
9290                                 /*
9291                                  * While the restart_mpi mailbox cmd may be
9292                                  * done the MPI is not. Wait at least 6 sec. or
9293                                  * exit if the loop comes up.
9294                                  */
9295                                 for (timer = 6; timer; timer--) {
9296                                         if (!(ha->task_daemon_flags &
9297                                             LOOP_DOWN)) {
9298                                                 break;
9299                                         }
9300                                         /* Delay for 1 second. */
9301                                         ql_delay(ha, 1000000);
9302                                 }
9303                         }
9304                         ql_restart_hba(ha);
9305 
9306                         ADAPTER_STATE_LOCK(ha);
9307                         ha->flags &= ~DISABLE_NIC_FW_DMP;
9308                         ADAPTER_STATE_UNLOCK(ha);
9309                 }
9310                 break;
9311         default:
9312                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9313                 cmd->Status = EXT_STATUS_ERR;
9314                 cmd->ResponseLen = 0;
9315                 break;
9316         }
9317 
9318         QL_PRINT_9(ha, "done\n");
9319 }
9320 
9321 /*
9322  * ql_get_dcbx_parameters
9323  *      Get DCBX parameters.
9324  *
9325  * Input:
9326  *      ha:     adapter state pointer.
9327  *      cmd:    User space CT arguments pointer.
9328  *      mode:   flags.
9329  */
9330 static void
9331 ql_get_dcbx_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9332 {
9333         uint8_t         *tmp_buf;
9334         int             rval;
9335 
9336         QL_PRINT_9(ha, "started\n");
9337 
9338         if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
9339                 EL(ha, "invalid request for HBA\n");
9340                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9341                 cmd->ResponseLen = 0;
9342                 return;
9343         }
9344 
9345         /* Allocate memory for command. */
9346         tmp_buf = kmem_zalloc(EXT_DEF_DCBX_PARAM_BUF_SIZE, KM_SLEEP);
9347         if (tmp_buf == NULL) {
9348                 EL(ha, "failed, kmem_zalloc\n");
9349                 cmd->Status = EXT_STATUS_NO_MEMORY;
9350                 cmd->ResponseLen = 0;
9351                 return;
9352         }
9353         /* Send command */
9354         rval = ql_get_dcbx_params(ha, EXT_DEF_DCBX_PARAM_BUF_SIZE,
9355             (caddr_t)tmp_buf);
9356         if (rval != QL_SUCCESS) {
9357                 /* error */
9358                 EL(ha, "failed, get_dcbx_params_mbx=%xh\n", rval);
9359                 kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE);
9360                 cmd->Status = EXT_STATUS_ERR;
9361                 cmd->ResponseLen = 0;
9362                 return;
9363         }
9364 
9365         /* Copy the response */
9366         if (ql_send_buffer_data((caddr_t)tmp_buf,
9367             (caddr_t)(uintptr_t)cmd->ResponseAdr,
9368             EXT_DEF_DCBX_PARAM_BUF_SIZE, mode) != EXT_DEF_DCBX_PARAM_BUF_SIZE) {
9369                 EL(ha, "failed, ddi_copyout\n");
9370                 cmd->Status = EXT_STATUS_COPY_ERR;
9371                 cmd->ResponseLen = 0;
9372         } else {
9373                 cmd->ResponseLen = EXT_DEF_DCBX_PARAM_BUF_SIZE;
9374                 QL_PRINT_9(ha, "done\n");
9375         }
9376         kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE);
9377 
9378 }
9379 
9380 /*
9381  * ql_qry_cna_port
9382  *      Performs EXT_SC_QUERY_CNA_PORT subfunction.
9383  *
9384  * Input:
9385  *      ha:     adapter state pointer.
9386  *      cmd:    EXT_IOCTL cmd struct pointer.
9387  *      mode:   flags.
9388  *
9389  * Returns:
9390  *      None, request status indicated in cmd->Status.
9391  *
9392  * Context:
9393  *      Kernel context.
9394  */
9395 static void
9396 ql_qry_cna_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9397 {
9398         EXT_CNA_PORT    cna_port = {0};
9399 
9400         QL_PRINT_9(ha, "started\n");
9401 
9402         if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
9403                 EL(ha, "invalid request for HBA\n");
9404                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9405                 cmd->ResponseLen = 0;
9406                 return;
9407         }
9408 
9409         if (cmd->ResponseLen < sizeof (EXT_CNA_PORT)) {
9410                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9411                 cmd->DetailStatus = sizeof (EXT_CNA_PORT);
9412                 EL(ha, "failed, ResponseLen < EXT_CNA_PORT, Len=%xh\n",
9413                     cmd->ResponseLen);
9414                 cmd->ResponseLen = 0;
9415                 return;
9416         }
9417 
9418         cna_port.VLanId = ha->fcoe_vlan_id;
9419         cna_port.FabricParam = ha->fabric_params;
9420         bcopy(ha->fcoe_vnport_mac, cna_port.VNPortMACAddress,
9421             EXT_DEF_MAC_ADDRESS_SIZE);
9422 
9423         if (ddi_copyout((void *)&cna_port,
9424             (void *)(uintptr_t)(cmd->ResponseAdr),
9425             sizeof (EXT_CNA_PORT), mode) != 0) {
9426                 cmd->Status = EXT_STATUS_COPY_ERR;
9427                 cmd->ResponseLen = 0;
9428                 EL(ha, "failed, ddi_copyout\n");
9429         } else {
9430                 cmd->ResponseLen = sizeof (EXT_CNA_PORT);
9431                 QL_PRINT_9(ha, "done\n");
9432         }
9433 }
9434 
9435 /*
9436  * ql_qry_adapter_versions
9437  *      Performs EXT_SC_QUERY_ADAPTER_VERSIONS subfunction.
9438  *
9439  * Input:
9440  *      ha:     adapter state pointer.
9441  *      cmd:    EXT_IOCTL cmd struct pointer.
9442  *      mode:   flags.
9443  *
9444  * Returns:
9445  *      None, request status indicated in cmd->Status.
9446  *
9447  * Context:
9448  *      Kernel context.
9449  */
9450 static void
9451 ql_qry_adapter_versions(ql_adapter_state_t *ha, EXT_IOCTL *cmd,
9452     int mode)
9453 {
9454         uint8_t                         is_8142, mpi_cap;
9455         uint32_t                        ver_len, transfer_size;
9456         PEXT_ADAPTERREGIONVERSION       padapter_ver = NULL;
9457 
9458         QL_PRINT_9(ha, "started\n");
9459 
9460         /* 8142s do not have a EDC PHY firmware. */
9461         mpi_cap = (uint8_t)(ha->mpi_capability_list >> 8);
9462 
9463         is_8142 = 0;
9464         /* Sizeof (Length + Reserved) = 8 Bytes */
9465         if (mpi_cap == 0x02 || mpi_cap == 0x04) {
9466                 ver_len = (sizeof (EXT_REGIONVERSION) * (NO_OF_VERSIONS - 1))
9467                     + 8;
9468                 is_8142 = 1;
9469         } else {
9470                 ver_len = (sizeof (EXT_REGIONVERSION) * NO_OF_VERSIONS) + 8;
9471         }
9472 
9473         /* Allocate local memory for EXT_ADAPTERREGIONVERSION */
9474         padapter_ver = (EXT_ADAPTERREGIONVERSION *)kmem_zalloc(ver_len,
9475             KM_SLEEP);
9476 
9477         if (padapter_ver == NULL) {
9478                 EL(ha, "failed, kmem_zalloc\n");
9479                 cmd->Status = EXT_STATUS_NO_MEMORY;
9480                 cmd->ResponseLen = 0;
9481                 return;
9482         }
9483 
9484         padapter_ver->Length = 1;
9485         /* Copy MPI version */
9486         padapter_ver->RegionVersion[0].Region =
9487             EXT_OPT_ROM_REGION_MPI_RISC_FW;
9488         padapter_ver->RegionVersion[0].Version[0] =
9489             ha->mpi_fw_major_version;
9490         padapter_ver->RegionVersion[0].Version[1] =
9491             ha->mpi_fw_minor_version;
9492         padapter_ver->RegionVersion[0].Version[2] =
9493             ha->mpi_fw_subminor_version;
9494         padapter_ver->RegionVersion[0].VersionLength = 3;
9495         padapter_ver->RegionVersion[0].Location = RUNNING_VERSION;
9496 
9497         if (!is_8142) {
9498                 padapter_ver->RegionVersion[1].Region =
9499                     EXT_OPT_ROM_REGION_EDC_PHY_FW;
9500                 padapter_ver->RegionVersion[1].Version[0] =
9501                     ha->phy_fw_major_version;
9502                 padapter_ver->RegionVersion[1].Version[1] =
9503                     ha->phy_fw_minor_version;
9504                 padapter_ver->RegionVersion[1].Version[2] =
9505                     ha->phy_fw_subminor_version;
9506                 padapter_ver->RegionVersion[1].VersionLength = 3;
9507                 padapter_ver->RegionVersion[1].Location = RUNNING_VERSION;
9508                 padapter_ver->Length = NO_OF_VERSIONS;
9509         }
9510 
9511         if (cmd->ResponseLen < ver_len) {
9512                 EL(ha, "failed, ResponseLen < ver_len, ",
9513                     "RespLen=%xh ver_len=%xh\n", cmd->ResponseLen, ver_len);
9514                 /* Calculate the No. of valid versions being returned. */
9515                 padapter_ver->Length = (uint32_t)
9516                     ((cmd->ResponseLen - 8) / sizeof (EXT_REGIONVERSION));
9517                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9518                 cmd->DetailStatus = ver_len;
9519                 transfer_size = cmd->ResponseLen;
9520         } else {
9521                 transfer_size = ver_len;
9522         }
9523 
9524         if (ddi_copyout((void *)padapter_ver,
9525             (void *)(uintptr_t)(cmd->ResponseAdr),
9526             transfer_size, mode) != 0) {
9527                 cmd->Status = EXT_STATUS_COPY_ERR;
9528                 cmd->ResponseLen = 0;
9529                 EL(ha, "failed, ddi_copyout\n");
9530         } else {
9531                 cmd->ResponseLen = ver_len;
9532                 QL_PRINT_9(ha, "done\n");
9533         }
9534 
9535         kmem_free(padapter_ver, ver_len);
9536 }
9537 
9538 /*
9539  * ql_get_xgmac_statistics
9540  *      Get XgMac information
9541  *
9542  * Input:
9543  *      ha:     adapter state pointer.
9544  *      cmd:    EXT_IOCTL cmd struct pointer.
9545  *      mode:   flags.
9546  *
9547  * Returns:
9548  *      None, request status indicated in cmd->Status.
9549  *
9550  * Context:
9551  *      Kernel context.
9552  */
9553 static void
9554 ql_get_xgmac_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9555 {
9556         int                     rval;
9557         uint32_t                size;
9558         int8_t                  *tmp_buf;
9559         EXT_MENLO_MANAGE_INFO   info;
9560 
9561         QL_PRINT_9(ha, "started\n");
9562 
9563         /*  Verify the size of request structure. */
9564         if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) {
9565                 /* Return error */
9566                 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
9567                     sizeof (EXT_MENLO_MANAGE_INFO));
9568                 cmd->Status = EXT_STATUS_INVALID_PARAM;
9569                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
9570                 cmd->ResponseLen = 0;
9571                 return;
9572         }
9573 
9574         /* Get manage info request. */
9575         if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
9576             (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) {
9577                 EL(ha, "failed, ddi_copyin\n");
9578                 cmd->Status = EXT_STATUS_COPY_ERR;
9579                 cmd->ResponseLen = 0;
9580                 return;
9581         }
9582 
9583         size = info.TotalByteCount;
9584         if (!size) {
9585                 /* parameter error */
9586                 cmd->Status = EXT_STATUS_INVALID_PARAM;
9587                 cmd->DetailStatus = 0;
9588                 EL(ha, "failed, size=%xh\n", size);
9589                 cmd->ResponseLen = 0;
9590                 return;
9591         }
9592 
9593         /* Allocate memory for command. */
9594         tmp_buf = kmem_zalloc(size, KM_SLEEP);
9595         if (tmp_buf == NULL) {
9596                 EL(ha, "failed, kmem_zalloc\n");
9597                 cmd->Status = EXT_STATUS_NO_MEMORY;
9598                 cmd->ResponseLen = 0;
9599                 return;
9600         }
9601 
9602         if (!(info.Operation & MENLO_OP_GET_INFO)) {
9603                 EL(ha, "Invalid request for 81XX\n");
9604                 kmem_free(tmp_buf, size);
9605                 cmd->Status = EXT_STATUS_ERR;
9606                 cmd->ResponseLen = 0;
9607                 return;
9608         }
9609 
9610         rval = ql_get_xgmac_stats(ha, size, (caddr_t)tmp_buf);
9611 
9612         if (rval != QL_SUCCESS) {
9613                 /* error */
9614                 EL(ha, "failed, get_xgmac_stats =%xh\n", rval);
9615                 kmem_free(tmp_buf, size);
9616                 cmd->Status = EXT_STATUS_ERR;
9617                 cmd->ResponseLen = 0;
9618                 return;
9619         }
9620 
9621         if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)info.pDataBytes,
9622             size, mode) != size) {
9623                 EL(ha, "failed, ddi_copyout\n");
9624                 cmd->Status = EXT_STATUS_COPY_ERR;
9625                 cmd->ResponseLen = 0;
9626         } else {
9627                 cmd->ResponseLen = info.TotalByteCount;
9628                 QL_PRINT_9(ha, "done\n");
9629         }
9630         kmem_free(tmp_buf, size);
9631         QL_PRINT_9(ha, "done\n");
9632 }
9633 
9634 /*
9635  * ql_get_fcf_list
9636  *      Get FCF list.
9637  *
9638  * Input:
9639  *      ha:     adapter state pointer.
9640  *      cmd:    User space CT arguments pointer.
9641  *      mode:   flags.
9642  */
9643 static void
9644 ql_get_fcf_list(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9645 {
9646         uint8_t                 *tmp_buf;
9647         int                     rval;
9648         EXT_FCF_LIST            fcf_list = {0};
9649         ql_fcf_list_desc_t      mb_fcf_list = {0};
9650 
9651         QL_PRINT_9(ha, "started\n");
9652 
9653         if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
9654                 EL(ha, "invalid request for HBA\n");
9655                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9656                 cmd->ResponseLen = 0;
9657                 return;
9658         }
9659         /* Get manage info request. */
9660         if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
9661             (caddr_t)&fcf_list, sizeof (EXT_FCF_LIST), mode) != 0) {
9662                 EL(ha, "failed, ddi_copyin\n");
9663                 cmd->Status = EXT_STATUS_COPY_ERR;
9664                 cmd->ResponseLen = 0;
9665                 return;
9666         }
9667 
9668         if (!(fcf_list.BufSize)) {
9669                 /* Return error */
9670                 EL(ha, "failed, fcf_list BufSize is=%xh\n",
9671                     fcf_list.BufSize);
9672                 cmd->Status = EXT_STATUS_INVALID_PARAM;
9673                 cmd->ResponseLen = 0;
9674                 return;
9675         }
9676         /* Allocate memory for command. */
9677         tmp_buf = kmem_zalloc(fcf_list.BufSize, KM_SLEEP);
9678         if (tmp_buf == NULL) {
9679                 EL(ha, "failed, kmem_zalloc\n");
9680                 cmd->Status = EXT_STATUS_NO_MEMORY;
9681                 cmd->ResponseLen = 0;
9682                 return;
9683         }
9684         /* build the descriptor */
9685         if (fcf_list.Options) {
9686                 mb_fcf_list.options = FCF_LIST_RETURN_ONE;
9687         } else {
9688                 mb_fcf_list.options = FCF_LIST_RETURN_ALL;
9689         }
9690         mb_fcf_list.fcf_index = (uint16_t)fcf_list.FcfIndex;
9691         mb_fcf_list.buffer_size = fcf_list.BufSize;
9692 
9693         /* Send command */
9694         rval = ql_get_fcf_list_mbx(ha, &mb_fcf_list, (caddr_t)tmp_buf);
9695         if (rval != QL_SUCCESS) {
9696                 /* error */
9697                 EL(ha, "failed, get_fcf_list_mbx=%xh\n", rval);
9698                 kmem_free(tmp_buf, fcf_list.BufSize);
9699                 cmd->Status = EXT_STATUS_ERR;
9700                 cmd->ResponseLen = 0;
9701                 return;
9702         }
9703 
9704         /* Copy the response */
9705         if (ql_send_buffer_data((caddr_t)tmp_buf,
9706             (caddr_t)(uintptr_t)cmd->ResponseAdr,
9707             fcf_list.BufSize, mode) != fcf_list.BufSize) {
9708                 EL(ha, "failed, ddi_copyout\n");
9709                 cmd->Status = EXT_STATUS_COPY_ERR;
9710                 cmd->ResponseLen = 0;
9711         } else {
9712                 cmd->ResponseLen = mb_fcf_list.buffer_size;
9713                 QL_PRINT_9(ha, "done\n");
9714         }
9715 
9716         kmem_free(tmp_buf, fcf_list.BufSize);
9717 }
9718 
9719 /*
9720  * ql_get_resource_counts
9721  *      Get Resource counts:
9722  *
9723  * Input:
9724  *      ha:     adapter state pointer.
9725  *      cmd:    User space CT arguments pointer.
9726  *      mode:   flags.
9727  */
9728 static void
9729 ql_get_resource_counts(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9730 {
9731         int                     rval;
9732         ql_mbx_data_t           mr;
9733         EXT_RESOURCE_CNTS       tmp_rc_cnt = {0};
9734 
9735         QL_PRINT_9(ha, "started\n");
9736 
9737         if (cmd->ResponseLen < sizeof (EXT_RESOURCE_CNTS)) {
9738                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9739                 cmd->DetailStatus = sizeof (EXT_RESOURCE_CNTS);
9740                 EL(ha, "failed, ResponseLen < EXT_RESOURCE_CNTS, "
9741                     "Len=%xh\n", cmd->ResponseLen);
9742                 cmd->ResponseLen = 0;
9743                 return;
9744         }
9745 
9746         rval = ql_get_resource_cnts(ha, &mr);
9747         if (rval != QL_SUCCESS) {
9748                 EL(ha, "resource cnt mbx failed\n");
9749                 cmd->Status = EXT_STATUS_ERR;
9750                 cmd->ResponseLen = 0;
9751                 return;
9752         }
9753 
9754         tmp_rc_cnt.OrgTgtXchgCtrlCnt = (uint32_t)mr.mb[1];
9755         tmp_rc_cnt.CurTgtXchgCtrlCnt = (uint32_t)mr.mb[2];
9756         tmp_rc_cnt.CurXchgCtrlCnt = (uint32_t)mr.mb[3];
9757         tmp_rc_cnt.OrgXchgCtrlCnt = (uint32_t)mr.mb[6];
9758         tmp_rc_cnt.CurIocbBufCnt = (uint32_t)mr.mb[7];
9759         tmp_rc_cnt.OrgIocbBufCnt = (uint32_t)mr.mb[10];
9760         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
9761                 tmp_rc_cnt.NoOfSupVPs = (uint32_t)mr.mb[11];
9762         }
9763         if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
9764                 tmp_rc_cnt.NoOfSupFCFs = (uint32_t)mr.mb[12];
9765         }
9766 
9767         rval = ddi_copyout((void *)&tmp_rc_cnt,
9768             (void *)(uintptr_t)(cmd->ResponseAdr),
9769             sizeof (EXT_RESOURCE_CNTS), mode);
9770         if (rval != 0) {
9771                 cmd->Status = EXT_STATUS_COPY_ERR;
9772                 cmd->ResponseLen = 0;
9773                 EL(ha, "failed, ddi_copyout\n");
9774         } else {
9775                 cmd->ResponseLen = sizeof (EXT_RESOURCE_CNTS);
9776                 QL_PRINT_9(ha, "done\n");
9777         }
9778 }
9779 
9780 /*
9781  * ql_get_temperature
9782  *      Get ASIC temperature data
9783  *
9784  * Input:
9785  *      ha:     adapter state pointer.
9786  *      cmd:    EXT_IOCTL cmd struct pointer.
9787  *      mode:   flags
9788  *
9789  * Returns:
9790  *      None, request status indicated in cmd->Status.
9791  *
9792  * Context:
9793  *      Kernel context.
9794  */
9795 static void
9796 ql_get_temperature(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9797 {
9798         ql_mbx_data_t   mr;
9799         int             rval = 0;
9800         EXT_BOARD_TEMP  board_temp = {0};
9801 
9802         QL_PRINT_9(ha, "started\n");
9803 
9804         if (!(ha->fw_ext_attributes & TEMP_SUPPORT_ISP)) {
9805                 EL(ha, "invalid request for HBA\n");
9806                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9807                 cmd->ResponseLen = 0;
9808                 return;
9809         }
9810 
9811         if (cmd->ResponseLen < sizeof (EXT_BOARD_TEMP)) {
9812                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9813                 cmd->DetailStatus = sizeof (EXT_BOARD_TEMP);
9814                 EL(ha, "failed, ResponseLen < EXT_BOARD_TEMP, "
9815                     "Len=%xh \n", cmd->ResponseLen);
9816                 cmd->ResponseLen = 0;
9817                 return;
9818         }
9819 
9820         switch (cmd->SubCode) {
9821         case EXT_SC_GET_BOARD_TEMP:
9822                 rval = ql_get_temp(ha, &mr);
9823                 if (rval != QL_SUCCESS) {
9824                         /* error */
9825                         EL(ha, "failed, get_temperature_mbx=%xh\n", rval);
9826                         cmd->Status = EXT_STATUS_ERR;
9827                         cmd->ResponseLen = 0;
9828                         break;
9829                 }
9830                 board_temp.IntTemp = mr.mb[1];
9831 
9832                 rval = ddi_copyout((void *)&board_temp,
9833                     (void *)(uintptr_t)(cmd->ResponseAdr),
9834                     sizeof (EXT_BOARD_TEMP), mode);
9835                 if (rval != 0) {
9836                         cmd->Status = EXT_STATUS_COPY_ERR;
9837                         cmd->ResponseLen = 0;
9838                         EL(ha, "failed, ddi_copyout\n");
9839                 } else {
9840                         cmd->ResponseLen = sizeof (EXT_BOARD_TEMP);
9841                 }
9842                 break;
9843         default:
9844                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9845                 cmd->Status = EXT_STATUS_ERR;
9846                 cmd->ResponseLen = 0;
9847                 break;
9848         }
9849 
9850         QL_PRINT_9(ha, "done\n");
9851 }
9852 
9853 /*
9854  * ql_dump_cmd
9855  *      Performs all EXT_CC_DUMP_OS functions.
9856  *
9857  * Input:
9858  *      ha:     adapter state pointer.
9859  *      cmd:    Local EXT_IOCTL cmd struct pointer.
9860  *
9861  * Returns:
9862  *      None, request status indicated in cmd->Status.
9863  *
9864  * Context:
9865  *      Kernel context.
9866  */
9867 static void
9868 ql_dump_cmd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9869 {
9870         caddr_t         dump;
9871         uint32_t        sdm_valid_dump = 0;
9872         int             rval = 0;
9873 
9874         QL_PRINT_9(ha, "started\n");
9875 
9876         if (ha->ql_dump_state & QL_DUMP_VALID &&
9877             !(ha->ql_dump_state & QL_DUMP_UPLOADED) &&
9878             ha->ql_dump_state != NULL) {
9879                 sdm_valid_dump = 1;
9880         } else {
9881                 EL(ha, "dump does not exist for instance %d (%x, %p)\n",
9882                     ha->instance, ha->ql_dump_state, ha->ql_dump_ptr);
9883         }
9884 
9885         cmd->Status = EXT_STATUS_OK;
9886         cmd->DetailStatus = 0;
9887 
9888         switch (cmd->SubCode) {
9889         case EXT_SC_DUMP_SIZE:
9890                 cmd->ResponseLen = 0;
9891                 if (sdm_valid_dump) {
9892                         cmd->DetailStatus = ha->risc_dump_size;
9893                 }
9894                 break;
9895         case EXT_SC_DUMP_READ:
9896                 if (!sdm_valid_dump) {
9897                         cmd->Status = EXT_STATUS_INVALID_REQUEST;
9898                         cmd->ResponseLen = 0;
9899                         break;
9900                 }
9901 
9902                 if (cmd->ResponseLen < ha->risc_dump_size) {
9903                         cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9904                         cmd->DetailStatus = ha->risc_dump_size;
9905                         EL(ha, "failed, ResponseLen < %x, "
9906                             "Len=%xh\n", ha->risc_dump_size,
9907                             cmd->ResponseLen);
9908                         break;
9909                 }
9910 
9911                 ADAPTER_STATE_LOCK(ha);
9912                 ha->flags |= DISABLE_NIC_FW_DMP;
9913                 ADAPTER_STATE_UNLOCK(ha);
9914 
9915                 QL_DUMP_LOCK(ha);
9916 
9917                 dump = kmem_zalloc(ha->risc_dump_size, KM_SLEEP);
9918                 cmd->ResponseLen = (uint32_t)ql_ascii_fw_dump(ha, dump);
9919 
9920                 if ((rval = ddi_copyout((void *)dump,
9921                     (void *)(uintptr_t)(cmd->ResponseAdr), cmd->ResponseLen,
9922                     mode)) != 0) {
9923                         ha->ql_dump_state &= ~QL_DUMP_UPLOADED;
9924                         EL(ha, "failed, ddi_copyout\n");
9925                         cmd->Status = EXT_STATUS_COPY_ERR;
9926                         cmd->ResponseLen = 0;
9927                 } else {
9928                         ha->ql_dump_state |= QL_DUMP_UPLOADED;
9929                 }
9930 
9931                 kmem_free(dump, ha->risc_dump_size);
9932 
9933                 QL_DUMP_UNLOCK(ha);
9934 
9935                 ADAPTER_STATE_LOCK(ha);
9936                 ha->flags &= ~DISABLE_NIC_FW_DMP;
9937                 ADAPTER_STATE_UNLOCK(ha);
9938                 break;
9939         case EXT_SC_DUMP_TRIGGER:
9940                 cmd->ResponseLen = 0;
9941 
9942                 ADAPTER_STATE_LOCK(ha);
9943                 ha->flags |= DISABLE_NIC_FW_DMP;
9944                 ADAPTER_STATE_UNLOCK(ha);
9945 
9946                 if (sdm_valid_dump) {
9947                         cmd->Status = EXT_STATUS_INVALID_REQUEST;
9948                         EL(ha, "Existing dump file needs to be retrieved.\n");
9949                 } else {
9950                         rval = ql_dump_firmware(ha);
9951 
9952                         if (rval != QL_SUCCESS && rval != QL_DATA_EXISTS) {
9953                                 cmd->Status = EXT_STATUS_ERR;
9954                         }
9955                 }
9956 
9957                 ADAPTER_STATE_LOCK(ha);
9958                 ha->flags &= ~DISABLE_NIC_FW_DMP;
9959                 ADAPTER_STATE_UNLOCK(ha);
9960                 break;
9961         default:
9962                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9963                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
9964                 cmd->ResponseLen = 0;
9965                 break;
9966         }
9967 
9968         QL_PRINT_9(ha, "done\n");
9969 }
9970 
9971 /*
9972  * ql_serdes_reg
9973  *      Performs all EXT_CC_SERDES_REG_OP functions.
9974  *
9975  * Input:
9976  *      ha:     adapter state pointer.
9977  *      cmd:    EXT_IOCTL cmd struct pointer.
9978  *      mode:   flags
9979  *
9980  * Returns:
9981  *      None, request status indicated in cmd->Status.
9982  *
9983  * Context:
9984  *      Kernel context.
9985  */
9986 static void
9987 ql_serdes_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9988 {
9989         ql_mbx_data_t   mr = {0};
9990         int             rval = 0;
9991         EXT_SERDES_REG  serdes_reg = {0};
9992 
9993         QL_PRINT_9(ha, "started\n");
9994 
9995         /* Check if request valid for HBA */
9996         if (!(CFG_IST(ha, CFG_SERDES_SUPPORT))) {
9997                 EL(ha, "invalid request for HBA\n");
9998                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
9999                 cmd->ResponseLen = 0;
10000                 return;
10001         }
10002 
10003         /* Copy in the request structure. */
10004         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
10005             (void *)&serdes_reg, sizeof (EXT_SERDES_REG), mode) != 0) {
10006                 EL(ha, "failed, ddi_copyin\n");
10007                 cmd->Status = EXT_STATUS_COPY_ERR;
10008                 cmd->ResponseLen = 0;
10009                 return;
10010         }
10011 
10012         switch (cmd->SubCode) {
10013         case EXT_SC_WRITE_SERDES_REG:
10014                 mr.mb[1] = serdes_reg.addr;
10015                 mr.mb[2] = LSB(serdes_reg.val);
10016                 mr.mb[3] = 0;
10017                 mr.mb[4] = MSB(serdes_reg.val);
10018                 if ((rval = ql_write_serdes(ha, &mr)) != QL_SUCCESS) {
10019                         /* error */
10020                         EL(ha, "failed, write_serdes_mbx=%xh\n", rval);
10021                         cmd->Status = EXT_STATUS_ERR;
10022                         cmd->ResponseLen = 0;
10023                         break;
10024                 } else {
10025                         cmd->Status = EXT_STATUS_OK;
10026                 }
10027                 break;
10028         case EXT_SC_READ_SERDES_REG:
10029                 /* Verify the size of response structure. */
10030                 if (cmd->ResponseLen < sizeof (EXT_SERDES_REG)) {
10031                         cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10032                         cmd->DetailStatus = sizeof (EXT_SERDES_REG);
10033                         EL(ha, "failed, ResponseLen < EXT_SERDES_REG, "
10034                             "Len=%xh \n", cmd->ResponseLen);
10035                         cmd->ResponseLen = 0;
10036                         break;
10037                 }
10038                 mr.mb[1] = serdes_reg.addr;
10039                 if ((rval = ql_read_serdes(ha, &mr)) != QL_SUCCESS) {
10040                         /* error */
10041                         EL(ha, "failed, read_serdes_mbx=%xh\n", rval);
10042                         cmd->Status = EXT_STATUS_ERR;
10043                         cmd->ResponseLen = 0;
10044                         break;
10045                 }
10046                 serdes_reg.val = CHAR_TO_SHORT(LSB(mr.mb[1]), LSB(mr.mb[2]));
10047                 /* Copy back the response data */
10048                 if (ddi_copyout((void *)&serdes_reg,
10049                     (void *)(uintptr_t)(cmd->ResponseAdr),
10050                     sizeof (EXT_SERDES_REG), mode) != 0) {
10051                         cmd->Status = EXT_STATUS_COPY_ERR;
10052                         cmd->ResponseLen = 0;
10053                         EL(ha, "failed, ddi_copyout\n");
10054                 } else {
10055                         cmd->Status = EXT_STATUS_OK;
10056                         cmd->ResponseLen = sizeof (EXT_SERDES_REG);
10057                 }
10058                 break;
10059         default:
10060                 /* Subcode not supported. */
10061                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
10062                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
10063                 cmd->ResponseLen = 0;
10064                 break;
10065         }
10066 
10067         QL_PRINT_9(ha, "done\n");
10068 }
10069 
10070 /*
10071  * ql_serdes_reg_ex
10072  *      Performs all EXT_CC_SERDES_REG_OP_EX functions.
10073  *
10074  * Input:
10075  *      ha:     adapter state pointer.
10076  *      cmd:    EXT_IOCTL cmd struct pointer.
10077  *      mode:   flags
10078  *
10079  * Returns:
10080  *      None, request status indicated in cmd->Status.
10081  *
10082  * Context:
10083  *      Kernel context.
10084  */
10085 static void
10086 ql_serdes_reg_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10087 {
10088         ql_mbx_data_t           mr = {0};
10089         int                     rval = 0;
10090         EXT_SERDES_REG_EX       serdes_reg_ex = {0};
10091 
10092         QL_PRINT_9(ha, "started\n");
10093 
10094         /* Check if request valid for HBA */
10095         if (!(CFG_IST(ha, CFG_SERDES_SUPPORT))) {
10096                 EL(ha, "invalid request for HBA\n");
10097                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
10098                 cmd->ResponseLen = 0;
10099                 return;
10100         }
10101 
10102         /* Copy in the request structure. */
10103         if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
10104             (void *)&serdes_reg_ex, sizeof (EXT_SERDES_REG_EX), mode) != 0) {
10105                 EL(ha, "failed, ddi_copyin\n");
10106                 cmd->Status = EXT_STATUS_COPY_ERR;
10107                 cmd->ResponseLen = 0;
10108                 return;
10109         }
10110 
10111         switch (cmd->SubCode) {
10112         case EXT_SC_WRITE_SERDES_REG:
10113                 mr.mb[3] = LSW(serdes_reg_ex.addr);
10114                 mr.mb[4] = MSW(serdes_reg_ex.addr);
10115                 mr.mb[5] = LSW(serdes_reg_ex.val);
10116                 mr.mb[6] = MSW(serdes_reg_ex.val);
10117                 if ((rval = ql_write_serdes(ha, &mr)) != QL_SUCCESS) {
10118                         /* error */
10119                         EL(ha, "failed, write_serdes_mbx=%xh\n", rval);
10120                         cmd->Status = EXT_STATUS_ERR;
10121                         cmd->ResponseLen = 0;
10122                         break;
10123                 } else {
10124                         cmd->Status = EXT_STATUS_OK;
10125                 }
10126                 break;
10127         case EXT_SC_READ_SERDES_REG:
10128                 /* Verify the size of response structure. */
10129                 if (cmd->ResponseLen < sizeof (EXT_SERDES_REG_EX)) {
10130                         cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10131                         cmd->DetailStatus = sizeof (EXT_SERDES_REG_EX);
10132                         EL(ha, "failed, ResponseLen < EXT_SERDES_REG_EX, "
10133                             "Len=%xh\n", cmd->ResponseLen);
10134                         cmd->ResponseLen = 0;
10135                         break;
10136                 }
10137                 mr.mb[3] = LSW(serdes_reg_ex.addr);
10138                 mr.mb[4] = MSW(serdes_reg_ex.addr);
10139                 if ((rval = ql_read_serdes(ha, &mr)) != QL_SUCCESS) {
10140                         /* error */
10141                         EL(ha, "failed, read_serdes_mbx=%xh\n", rval);
10142                         cmd->Status = EXT_STATUS_ERR;
10143                         cmd->ResponseLen = 0;
10144                         break;
10145                 }
10146                 serdes_reg_ex.val = SHORT_TO_LONG(mr.mb[1], mr.mb[2]);
10147                 /* Copy back the response data */
10148                 if (ddi_copyout((void *)&serdes_reg_ex,
10149                     (void *)(uintptr_t)(cmd->ResponseAdr),
10150                     sizeof (EXT_SERDES_REG_EX), mode) != 0) {
10151                         cmd->Status = EXT_STATUS_COPY_ERR;
10152                         cmd->ResponseLen = 0;
10153                         EL(ha, "failed, ddi_copyout\n");
10154                 } else {
10155                         cmd->Status = EXT_STATUS_OK;
10156                         cmd->ResponseLen = sizeof (EXT_SERDES_REG_EX);
10157                 }
10158                 break;
10159         default:
10160                 /* Subcode not supported. */
10161                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
10162                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
10163                 cmd->ResponseLen = 0;
10164                 break;
10165         }
10166 
10167         QL_PRINT_9(ha, "done\n");
10168 }
10169 
10170 /*
10171  * ql_els_passthru
10172  *      IOCTL for extended link service passthru command.
10173  *
10174  * Input:
10175  *      ha:     adapter state pointer.
10176  *      cmd:    User space CT arguments pointer.
10177  *      mode:   flags.
10178  *
10179  * Returns:
10180  *      None, request status indicated in cmd->Status.
10181  *
10182  * Context:
10183  *      Kernel context.
10184  */
10185 static void
10186 ql_els_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10187 {
10188         ql_mbx_iocb_t           *pkt;
10189         dma_mem_t               *dma_mem;
10190         caddr_t                 bp, pld;
10191         uint32_t                pkt_size, pld_byte_cnt, cmd_size, *long_ptr;
10192         EXT_ELS_PT_REQ          *pt_req;
10193         boolean_t               local_hba = B_FALSE;
10194         ql_tgt_t                *tq = NULL;
10195         port_id_t               tmp_fcid;
10196         int                     rval;
10197         uint16_t                comp_status;
10198 
10199         QL_PRINT_9(ha, "started\n");
10200 
10201         if (DRIVER_SUSPENDED(ha)) {
10202                 EL(ha, "failed, LOOP_NOT_READY\n");
10203                 cmd->Status = EXT_STATUS_BUSY;
10204                 cmd->ResponseLen = 0;
10205                 return;
10206         }
10207 
10208         if (cmd->RequestLen < sizeof (EXT_ELS_PT_REQ)) {
10209                 /* parameter error */
10210                 EL(ha, "failed, RequestLen < EXT_ELS_PT_REQ, Len=%xh\n",
10211                     cmd->RequestLen);
10212                 cmd->Status = EXT_STATUS_INVALID_PARAM;
10213                 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
10214                 cmd->ResponseLen = 0;
10215                 return;
10216         }
10217 
10218         /* Allocate memory for command. */
10219         bp = kmem_zalloc(cmd->RequestLen, KM_SLEEP);
10220 
10221         if (ddi_copyin((void*)(uintptr_t)cmd->RequestAdr,
10222             bp, cmd->RequestLen, mode) != 0) {
10223                 EL(ha, "failed, ddi_copyin\n");
10224                 kmem_free(bp, cmd->RequestLen);
10225                 cmd->Status = EXT_STATUS_COPY_ERR;
10226                 cmd->ResponseLen = 0;
10227                 return;
10228         }
10229         pt_req = (EXT_ELS_PT_REQ *)bp;
10230 
10231         QL_PRINT_9(ha, "EXT_ELS_PT_REQ\n");
10232         QL_DUMP_9((uint8_t *)pt_req, 8, sizeof (EXT_ELS_PT_REQ));
10233 
10234         /* Find loop ID of the device */
10235         if (pt_req->ValidMask & EXT_DEF_WWPN_VALID) {
10236                 if (bcmp(ha->loginparams.nport_ww_name.raw_wwn, pt_req->WWPN,
10237                     EXT_DEF_WWN_NAME_SIZE) == 0) {
10238                         local_hba = B_TRUE;
10239                 } else {
10240                         tq = ql_find_port(ha, pt_req->WWPN, QLNT_PORT);
10241                 }
10242         } else if (pt_req->ValidMask & EXT_DEF_PID_VALID) {
10243                 /*
10244                  * Copy caller's d_id to tmp space.
10245                  */
10246                 bcopy(&pt_req->Id[1], tmp_fcid.r.d_id,
10247                     EXT_DEF_PORTID_SIZE_ACTUAL);
10248                 BIG_ENDIAN_24(&tmp_fcid.r.d_id[0]);
10249 
10250                 if (bcmp((void *)&ha->d_id, (void *)tmp_fcid.r.d_id,
10251                     EXT_DEF_PORTID_SIZE_ACTUAL) == 0) {
10252                         local_hba = B_TRUE;
10253                 } else {
10254                         tq = ql_find_port(ha, (uint8_t *)tmp_fcid.r.d_id,
10255                             QLNT_PID);
10256                 }
10257         } else if (pt_req->ValidMask & EXT_DEF_WWNN_VALID) {
10258                 if (bcmp(ha->loginparams.node_ww_name.raw_wwn, pt_req->WWNN,
10259                     EXT_DEF_WWN_NAME_SIZE) == 0) {
10260                         local_hba = B_TRUE;
10261                 } else {
10262                         tq = ql_find_port(ha, pt_req->WWNN, QLNT_NODE);
10263                 }
10264         }
10265 
10266         if (local_hba == B_TRUE) {
10267                 EL(ha, "failed, els to adapter\n");
10268                 kmem_free(bp, cmd->RequestLen);
10269                 cmd->Status = EXT_STATUS_ERR;
10270                 cmd->ResponseLen = 0;
10271                 return;
10272         }
10273 
10274         if (tq == NULL) {
10275                 /* no matching device */
10276                 EL(ha, "failed, device not found\n");
10277                 kmem_free(bp, cmd->RequestLen);
10278                 cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
10279                 cmd->DetailStatus = EXT_DSTATUS_TARGET;
10280                 cmd->ResponseLen = 0;
10281                 return;
10282         }
10283 
10284         /* Allocate a DMA Memory Descriptor */
10285         dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
10286         if (dma_mem == NULL) {
10287                 EL(ha, "failed, kmem_zalloc\n");
10288                 kmem_free(bp, cmd->RequestLen);
10289                 cmd->Status = EXT_STATUS_NO_MEMORY;
10290                 cmd->ResponseLen = 0;
10291                 return;
10292         }
10293         /* Determine maximum buffer size. */
10294         cmd_size = cmd->RequestLen - sizeof (EXT_ELS_PT_REQ);
10295         pld_byte_cnt = cmd_size < cmd->ResponseLen ? cmd->ResponseLen :
10296             cmd_size;
10297         pld = (caddr_t)(bp + sizeof (EXT_ELS_PT_REQ));
10298 
10299         /* Allocate command block. */
10300         pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t));
10301         pkt = kmem_zalloc(pkt_size, KM_SLEEP);
10302         if (pkt == NULL) {
10303                 EL(ha, "failed, kmem_zalloc\n");
10304                 kmem_free(dma_mem, sizeof (dma_mem_t));
10305                 kmem_free(bp, cmd->RequestLen);
10306                 cmd->Status = EXT_STATUS_NO_MEMORY;
10307                 cmd->ResponseLen = 0;
10308                 return;
10309         }
10310 
10311         /* Get DMA memory for the payload */
10312         if (ql_get_dma_mem(ha, dma_mem, pld_byte_cnt, LITTLE_ENDIAN_DMA,
10313             QL_DMA_RING_ALIGN) != QL_SUCCESS) {
10314                 cmn_err(CE_WARN, "%sDMA memory alloc failed", QL_NAME);
10315                 kmem_free(pkt, pkt_size);
10316                 kmem_free(dma_mem, sizeof (dma_mem_t));
10317                 kmem_free(bp, cmd->RequestLen);
10318                 cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
10319                 cmd->ResponseLen = 0;
10320                 return;
10321         }
10322 
10323         /* Copy out going payload data to IOCB DMA buffer. */
10324         ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
10325             (uint8_t *)dma_mem->bp, cmd_size, DDI_DEV_AUTOINCR);
10326 
10327         /* Sync IOCB DMA buffer. */
10328         (void) ddi_dma_sync(dma_mem->dma_handle, 0, cmd_size,
10329             DDI_DMA_SYNC_FORDEV);
10330 
10331         /*
10332          * Setup IOCB
10333          */
10334         if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
10335                 pkt->els.entry_type = ELS_PASSTHRU_TYPE;
10336                 pkt->els.entry_count = 1;
10337 
10338                 /* Set loop ID */
10339                 pkt->els.n_port_hdl = tq->loop_id;
10340 
10341                 /* Set cmd/response data segment counts. */
10342                 pkt->els.xmt_dseg_count = LE_16(1);
10343                 pkt->els.vp_index = ha->vp_index;
10344                 pkt->els.rcv_dseg_count = LE_16(1);
10345 
10346                 pkt->els.els_cmd_opcode = pld[0];
10347 
10348                 pkt->els.d_id_7_0 = tq->d_id.b.al_pa;
10349                 pkt->els.d_id_15_8 = tq->d_id.b.area;
10350                 pkt->els.d_id_23_16 = tq->d_id.b.domain;
10351 
10352                 pkt->els.s_id_7_0 = ha->d_id.b.al_pa;
10353                 pkt->els.s_id_15_8 = ha->d_id.b.area;
10354                 pkt->els.s_id_23_16 = ha->d_id.b.domain;
10355 
10356                 /* Load rsp byte count. */
10357                 pkt->els.rcv_payld_data_bcnt = LE_32(cmd->ResponseLen);
10358 
10359                 /* Load cmd byte count. */
10360                 pkt->els.xmt_payld_data_bcnt = LE_32(cmd_size);
10361 
10362                 long_ptr = (uint32_t *)&pkt->els.dseg;
10363 
10364                 /* Load MS command entry data segments. */
10365                 *long_ptr++ = (uint32_t)
10366                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
10367                 *long_ptr++ = (uint32_t)
10368                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
10369                 *long_ptr++ = LE_32(cmd_size);
10370 
10371                 /* Load MS response entry data segments. */
10372                 *long_ptr++ = (uint32_t)
10373                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
10374                 *long_ptr++ = (uint32_t)
10375                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
10376                 *long_ptr = LE_32(cmd->ResponseLen);
10377 
10378                 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
10379                     sizeof (ql_mbx_iocb_t));
10380 
10381                 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
10382                 if (rval == QL_SUCCESS && comp_status == CS_DATA_UNDERRUN) {
10383                         comp_status = CS_COMPLETE;
10384                 }
10385                 if (rval != QL_SUCCESS ||
10386                     (pkt->sts24.entry_status & 0x3c) != 0 ||
10387                     comp_status != CS_COMPLETE) {
10388                         EL(ha, "failed, I/O timeout, cs=%xh, es=%xh, "
10389                             "rval=%xh\n",
10390                             comp_status, pkt->sts24.entry_status, rval);
10391                         ql_free_dma_resource(ha, dma_mem);
10392                         kmem_free(pkt, pkt_size);
10393                         kmem_free(dma_mem, sizeof (dma_mem_t));
10394                         kmem_free(bp, cmd->RequestLen);
10395                         cmd->Status = EXT_STATUS_ERR;
10396                         cmd->ResponseLen = 0;
10397                         return;
10398                 }
10399         } else {
10400                 pkt->ms.entry_type = MS_TYPE;
10401                 pkt->ms.entry_count = 1;
10402 
10403                 /* Set loop ID */
10404                 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
10405                         pkt->ms.loop_id_l = LSB(tq->loop_id);
10406                         pkt->ms.loop_id_h = MSB(tq->loop_id);
10407                 } else {
10408                         pkt->ms.loop_id_h = LSB(tq->loop_id);
10409                 }
10410 
10411                 pkt->ms.control_flags_h = CF_ELS_PASSTHROUGH;
10412 
10413                 /* Set ISP command timeout. */
10414                 pkt->ms.timeout = LE_16(120);
10415 
10416                 /* Set data segment counts. */
10417                 pkt->ms.cmd_dseg_count_l = 1;
10418                 pkt->ms.total_dseg_count = LE_16(2);
10419 
10420                 /* Response total byte count. */
10421                 pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen);
10422                 pkt->ms.dseg[1].length = LE_32(cmd->ResponseLen);
10423 
10424                 /* Command total byte count. */
10425                 pkt->ms.cmd_byte_count = LE_32(cmd_size);
10426                 pkt->ms.dseg[0].length = LE_32(cmd_size);
10427 
10428                 /* Load command/response data segments. */
10429                 pkt->ms.dseg[0].address[0] = (uint32_t)
10430                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
10431                 pkt->ms.dseg[0].address[1] = (uint32_t)
10432                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
10433                 pkt->ms.dseg[1].address[0] = (uint32_t)
10434                     LE_32(LSD(dma_mem->cookie.dmac_laddress));
10435                 pkt->ms.dseg[1].address[1] = (uint32_t)
10436                     LE_32(MSD(dma_mem->cookie.dmac_laddress));
10437 
10438                 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
10439                     sizeof (ql_mbx_iocb_t));
10440 
10441                 comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
10442                 if (rval == QL_SUCCESS && comp_status == CS_DATA_UNDERRUN) {
10443                         comp_status = CS_COMPLETE;
10444                 }
10445                 if (rval != QL_SUCCESS ||
10446                     (pkt->sts.entry_status & 0x7e) != 0 ||
10447                     comp_status != CS_COMPLETE) {
10448                         EL(ha, "failed, I/O timeout, cs=%xh, es=%xh, "
10449                             "rval=%xh\n",
10450                             comp_status, pkt->sts.entry_status, rval);
10451                         ql_free_dma_resource(ha, dma_mem);
10452                         kmem_free(pkt, pkt_size);
10453                         kmem_free(dma_mem, sizeof (dma_mem_t));
10454                         kmem_free(bp, cmd->RequestLen);
10455                         cmd->Status = EXT_STATUS_ERR;
10456                         cmd->ResponseLen = 0;
10457                         return;
10458                 }
10459         }
10460 
10461         /* Sync payload DMA buffer. */
10462         (void) ddi_dma_sync(dma_mem->dma_handle, 0, cmd->ResponseLen,
10463             DDI_DMA_SYNC_FORKERNEL);
10464 
10465         if (ql_send_buffer_data(dma_mem->bp,
10466             (caddr_t)(uintptr_t)cmd->ResponseAdr,
10467             cmd->ResponseLen, mode) != cmd->ResponseLen) {
10468                 cmd->Status = EXT_STATUS_COPY_ERR;
10469                 EL(ha, "failed, ddi_copyout\n");
10470         } else {
10471                 QL_PRINT_9(ha, "els_rsp\n");
10472                 QL_DUMP_9(pld, 8, cmd->ResponseLen);
10473                 cmd->Status = EXT_STATUS_OK;
10474                 QL_PRINT_9(ha, "done\n");
10475         }
10476 
10477         ql_free_dma_resource(ha, dma_mem);
10478         kmem_free(pkt, pkt_size);
10479         kmem_free(dma_mem, sizeof (dma_mem_t));
10480         kmem_free(bp, cmd->RequestLen);
10481 }
10482 
10483 /*
10484  * ql_flash_update_caps
10485  *      IOCTL for flash update capabilities command.
10486  *
10487  * Input:
10488  *      ha:     adapter state pointer.
10489  *      cmd:    User space CT arguments pointer.
10490  *      mode:   flags.
10491  *
10492  * Returns:
10493  *      None, request status indicated in cmd->Status.
10494  *
10495  * Context:
10496  *      Kernel context.
10497  */
10498 static void
10499 ql_flash_update_caps(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10500 {
10501         int                     rval;
10502         uint64_t                cb;
10503         EXT_FLASH_UPDATE_CAPS   caps = {0};
10504 
10505         QL_PRINT_9(ha, "started\n");
10506 
10507         cb = LONG_TO_LLONG(ha->fw_attributes, ha->fw_ext_attributes);
10508 
10509         switch (cmd->SubCode) {
10510         case EXT_SC_GET_FLASH_UPDATE_CAPS:
10511                 if (cmd->ResponseLen < sizeof (EXT_FLASH_UPDATE_CAPS)) {
10512                         cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10513                         cmd->DetailStatus = sizeof (EXT_FLASH_UPDATE_CAPS);
10514                         EL(ha, "failed, ResponseLen < 0x%x, Len=0x%x\n",
10515                             sizeof (EXT_FLASH_UPDATE_CAPS), cmd->ResponseLen);
10516                         cmd->ResponseLen = 0;
10517                         return;
10518                 }
10519                 caps.Capabilities = cb;
10520                 caps.OutageDuration = 300;      /* seconds */
10521 
10522                 rval = ddi_copyout((void *)&caps,
10523                     (void *)(uintptr_t)(cmd->ResponseAdr),
10524                     sizeof (EXT_FLASH_UPDATE_CAPS), mode);
10525                 if (rval != 0) {
10526                         cmd->Status = EXT_STATUS_COPY_ERR;
10527                         cmd->ResponseLen = 0;
10528                         EL(ha, "failed, ddi_copyout\n");
10529                 } else {
10530                         cmd->ResponseLen = sizeof (EXT_FLASH_UPDATE_CAPS);
10531                 }
10532                 break;
10533         case EXT_SC_SET_FLASH_UPDATE_CAPS:
10534                 if (cmd->RequestLen < sizeof (EXT_FLASH_UPDATE_CAPS)) {
10535                         /* parameter error */
10536                         EL(ha, "failed, RequestLen < EXT_FLASH_UPDATE_CAPS, "
10537                             "Len=%xh\n", cmd->RequestLen);
10538                         cmd->Status = EXT_STATUS_INVALID_PARAM;
10539                         cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
10540                         cmd->ResponseLen = 0;
10541                         return;
10542                 }
10543 
10544                 /* Copy in the request structure. */
10545                 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
10546                     (void *)&caps, sizeof (EXT_FLASH_UPDATE_CAPS), mode) != 0) {
10547                         EL(ha, "failed, ddi_copyin\n");
10548                         cmd->Status = EXT_STATUS_COPY_ERR;
10549                         cmd->ResponseLen = 0;
10550                         return;
10551                 }
10552 
10553                 if (cb != caps.Capabilities || caps.OutageDuration < 300) {
10554                         cmd->Status = EXT_STATUS_ERR;
10555                         cmd->ResponseLen = 0;
10556                 }
10557                 break;
10558         default:
10559                 /* Subcode not supported. */
10560                 EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
10561                 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
10562                 cmd->ResponseLen = 0;
10563                 break;
10564         }
10565 
10566         QL_PRINT_9(ha, "done\n");
10567 }
10568 
10569 /*
10570  * ql_get_bbcr_data
10571  *      IOCTL for get buffer to buffer credits command.
10572  *
10573  * Input:
10574  *      ha:     adapter state pointer.
10575  *      cmd:    User space CT arguments pointer.
10576  *      mode:   flags.
10577  *
10578  * Returns:
10579  *      None, request status indicated in cmd->Status.
10580  *
10581  * Context:
10582  *      Kernel context.
10583  */
10584 static void
10585 ql_get_bbcr_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10586 {
10587         int             rval;
10588         ql_mbx_data_t   mr;
10589         EXT_BBCR_DATA   bb = {0};
10590 
10591         QL_PRINT_9(ha, "started\n");
10592 
10593         if (cmd->ResponseLen < sizeof (EXT_BBCR_DATA)) {
10594                 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10595                 cmd->DetailStatus = sizeof (EXT_BBCR_DATA);
10596                 EL(ha, "failed, ResponseLen < 0x%x, Len=0x%x\n",
10597                     sizeof (EXT_BBCR_DATA), cmd->ResponseLen);
10598                 cmd->ResponseLen = 0;
10599                 return;
10600         }
10601 
10602         if (!(CFG_IST(ha, CFG_BBCR_SUPPORT))) {
10603                 EL(ha, "invalid request for HBA\n");
10604                 cmd->Status = EXT_STATUS_INVALID_REQUEST;
10605                 cmd->ResponseLen = 0;
10606                 return;
10607         }
10608         if (ha->task_daemon_flags & LOOP_DOWN) {
10609                 rval = ql_get_adapter_id(ha, &mr);
10610                 ha->bbcr_initial = LSB(mr.mb[15]);
10611                 ha->bbcr_runtime = MSB(mr.mb[15]);
10612                 bb.ConfiguredBBSCN = ha->bbcr_initial & BBCR_INITIAL_MASK;
10613                 bb.NegotiatedBBSCN = ha->bbcr_runtime & BBCR_RUNTIME_MASK;
10614                 bb.Status = EXT_DEF_BBCR_STATUS_UNKNOWN;
10615                 bb.State = EXT_DEF_BBCR_STATE_OFFLINE;
10616                 if (rval == 0x4005) {
10617                         bb.mbx1 = mr.mb[1];
10618                 }
10619         } else {
10620                 bb.ConfiguredBBSCN = ha->bbcr_initial & BBCR_INITIAL_MASK;
10621                 bb.NegotiatedBBSCN = ha->bbcr_runtime & BBCR_RUNTIME_MASK;
10622 
10623                 if (bb.ConfiguredBBSCN) {
10624                         bb.Status = EXT_DEF_BBCR_STATUS_ENABLED;
10625                         if (bb.NegotiatedBBSCN &&
10626                             !(ha->bbcr_runtime & BBCR_RUNTIME_REJECT)) {
10627                                 bb.State = EXT_DEF_BBCR_STATE_ONLINE;
10628                         } else {
10629                                 bb.State = EXT_DEF_BBCR_STATE_OFFLINE;
10630                                 if (ha->bbcr_runtime & BBCR_RUNTIME_REJECT) {
10631                                         bb.OfflineReasonCode =
10632                                             EXT_DEF_BBCR_REASON_LOGIN_REJECT;
10633                                 } else {
10634                                         bb.OfflineReasonCode =
10635                                             EXT_DEF_BBCR_REASON_SWITCH;
10636                                 }
10637                         }
10638                 } else {
10639                         bb.Status = EXT_DEF_BBCR_STATUS_DISABLED;
10640                 }
10641         }
10642 
10643         rval = ddi_copyout((void *)&bb, (void *)(uintptr_t)(cmd->ResponseAdr),
10644             sizeof (EXT_BBCR_DATA), mode);
10645         if (rval != 0) {
10646                 cmd->Status = EXT_STATUS_COPY_ERR;
10647                 cmd->ResponseLen = 0;
10648                 EL(ha, "failed, ddi_copyout\n");
10649         } else {
10650                 cmd->ResponseLen = sizeof (EXT_BBCR_DATA);
10651         }
10652 
10653         QL_PRINT_9(ha, "done\n");
10654 }
10655 
10656 /*
10657  * ql_get_priv_stats
10658  *      Performs EXT_SC_GET_PRIV_STATS subcommand. of EXT_CC_GET_DATA.
10659  *
10660  * Input:
10661  *      ha:     adapter state pointer.
10662  *      cmd:    Local EXT_IOCTL cmd struct pointer.
10663  *      mode:   flags.
10664  *
10665  * Returns:
10666  *      None, request status indicated in cmd->Status.
10667  *
10668  * Context:
10669  *      Kernel context.
10670  */
10671 static void
10672 ql_get_priv_stats(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10673 {
10674         uint8_t *ls;
10675         int     rval;
10676         int     retry = 10;
10677 
10678         QL_PRINT_9(ha, "started\n");
10679 
10680         while (ha->task_daemon_flags & (DRIVER_STALL | ABORT_ISP_ACTIVE |
10681             LOOP_RESYNC_ACTIVE)) {
10682                 ql_delay(ha, 10000000); /* 10 second delay */
10683 
10684                 retry--;
10685 
10686                 if (retry == 0) { /* effectively 100 seconds */
10687                         EL(ha, "failed, LOOP_NOT_READY\n");
10688                         cmd->Status = EXT_STATUS_BUSY;
10689                         cmd->ResponseLen = 0;
10690                         return;
10691                 }
10692         }
10693 
10694         /* Allocate memory for command. */
10695         ls = kmem_zalloc(cmd->ResponseLen, KM_SLEEP);
10696 
10697         /*
10698          * I think these are supposed to be port statistics
10699          * the loop ID or port ID should be in cmd->Instance.
10700          */
10701         rval = ql_get_status_counts(ha,
10702             ha->task_daemon_flags & LOOP_DOWN ? 0xFF : ha->loop_id,
10703             cmd->ResponseLen, (caddr_t)ls, 0);
10704         if (rval != QL_SUCCESS) {
10705                 EL(ha, "failed, get_link_status=%xh, id=%xh\n", rval,
10706                     ha->loop_id);
10707                 cmd->Status = EXT_STATUS_MAILBOX;
10708                 cmd->DetailStatus = rval;
10709                 cmd->ResponseLen = 0;
10710         } else {
10711                 rval = ddi_copyout((void *)&ls,
10712                     (void *)(uintptr_t)cmd->ResponseAdr, cmd->ResponseLen,
10713                     mode);
10714                 if (rval != 0) {
10715                         EL(ha, "failed, ddi_copyout\n");
10716                         cmd->Status = EXT_STATUS_COPY_ERR;
10717                         cmd->ResponseLen = 0;
10718                 }
10719         }
10720 
10721         kmem_free(ls, cmd->ResponseLen);
10722 
10723         QL_PRINT_9(ha, "done\n");
10724 }