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