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