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 (DRIVER_SUSPENDED(ha) || ql_stall_driver(ha, 0) != QL_SUCCESS) { 3388 EL(ha, "failed, LOOP_NOT_READY\n"); 3389 kmem_free(bp, plbreq.TransferCount); 3390 cmd->Status = EXT_STATUS_BUSY; 3391 cmd->ResponseLen = 0; 3392 return; 3393 } 3394 3395 /* Shutdown IP. */ 3396 if (ha->flags & IP_INITIALIZED) { 3397 (void) ql_shutdown_ip(ha); 3398 } 3399 3400 /* determine topology so we can send the loopback or the echo */ 3401 /* Echo is supported on 2300's only and above */ 3402 3403 if ((ha->topology & QL_F_PORT) && ha->device_id >= 0x2300) { 3404 QL_PRINT_9(CE_CONT, "(%d): F_PORT topology -- using echo\n", 3405 ha->instance); 3406 plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD; 3407 rval = ql_diag_echo(ha, 0, bp, plbreq.TransferCount, 0, &mr); 3408 } else { 3409 plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD; 3410 rval = ql_diag_loopback(ha, 0, bp, plbreq.TransferCount, 3411 plbreq.Options, plbreq.IterationCount, &mr); 3412 } 3413 3414 ql_restart_driver(ha); 3415 3416 /* Restart IP if it was shutdown. */ 3417 if (ha->flags & IP_ENABLED && !(ha->flags & IP_INITIALIZED)) { 3418 (void) ql_initialize_ip(ha); 3419 ql_isp_rcvbuf(ha); 3420 } 3421 3422 if (rval != QL_SUCCESS) { 3423 EL(ha, "failed, diagnostic_loopback_mbx=%xh\n", rval); 3424 kmem_free(bp, plbreq.TransferCount); 3425 cmd->Status = EXT_STATUS_MAILBOX; 3426 cmd->DetailStatus = rval; 3427 cmd->ResponseLen = 0; 3428 return; 3429 } 3430 3431 /* Return loopback data. */ 3432 if (ql_send_buffer_data(bp, (caddr_t)(uintptr_t)plbreq.BufferAddress, 3433 plbreq.TransferCount, mode) != plbreq.TransferCount) { 3434 EL(ha, "failed, ddi_copyout\n"); 3435 kmem_free(bp, plbreq.TransferCount); 3436 cmd->Status = EXT_STATUS_COPY_ERR; 3437 cmd->ResponseLen = 0; 3438 return; 3439 } 3440 kmem_free(bp, plbreq.TransferCount); 3441 3442 /* Return loopback results. */ 3443 plbrsp.BufferAddress = plbreq.BufferAddress; 3444 plbrsp.BufferLength = plbreq.TransferCount; 3445 plbrsp.CompletionStatus = mr.mb[0]; 3446 3447 if (plbrsp.CommandSent == INT_DEF_LB_ECHO_CMD) { 3448 plbrsp.CrcErrorCount = 0; 3449 plbrsp.DisparityErrorCount = 0; 3450 plbrsp.FrameLengthErrorCount = 0; 3451 plbrsp.IterationCountLastError = 0; 3452 } else { 3453 plbrsp.CrcErrorCount = mr.mb[1]; 3454 plbrsp.DisparityErrorCount = mr.mb[2]; 3455 plbrsp.FrameLengthErrorCount = mr.mb[3]; 3456 plbrsp.IterationCountLastError = (mr.mb[19] >> 16) | mr.mb[18]; 3457 } 3458 3459 rval = ddi_copyout((void *)&plbrsp, 3460 (void *)(uintptr_t)cmd->ResponseAdr, 3461 sizeof (EXT_LOOPBACK_RSP), mode); 3462 if (rval != 0) { 3463 EL(ha, "failed, ddi_copyout-2\n"); 3464 cmd->Status = EXT_STATUS_COPY_ERR; 3465 cmd->ResponseLen = 0; 3466 return; 3467 } 3468 cmd->ResponseLen = sizeof (EXT_LOOPBACK_RSP); 3469 3470 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 3471 } 3472 3473 /* 3474 * ql_send_els_rnid 3475 * IOCTL for extended link service RNID command. 3476 * 3477 * Input: 3478 * ha: adapter state pointer. 3479 * cmd: User space CT arguments pointer. 3480 * mode: flags. 3481 * 3482 * Returns: 3483 * None, request status indicated in cmd->Status. 3484 * 3485 * Context: 3486 * Kernel context. 3487 */ 3488 static void 3489 ql_send_els_rnid(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 3490 { 3491 EXT_RNID_REQ tmp_rnid; 3492 port_id_t tmp_fcid; 3493 caddr_t tmp_buf, bptr; 3494 uint32_t copy_len; 3495 ql_tgt_t *tq; 3496 EXT_RNID_DATA rnid_data; 3497 uint32_t loop_ready_wait = 10 * 60 * 10; 3498 int rval = 0; 3499 uint32_t local_hba = 0; 3500 3501 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 3502 3503 if (DRIVER_SUSPENDED(ha)) { 3504 EL(ha, "failed, LOOP_NOT_READY\n"); 3505 cmd->Status = EXT_STATUS_BUSY; 3506 cmd->ResponseLen = 0; 3507 return; 3508 } 3509 3510 if (cmd->RequestLen != sizeof (EXT_RNID_REQ)) { 3511 /* parameter error */ 3512 EL(ha, "failed, RequestLen < EXT_RNID_REQ, Len=%xh\n", 3513 cmd->RequestLen); 3514 cmd->Status = EXT_STATUS_INVALID_PARAM; 3515 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 3516 cmd->ResponseLen = 0; 3517 return; 3518 } 3519 3520 if (ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, 3521 &tmp_rnid, cmd->RequestLen, mode) != 0) { 3522 EL(ha, "failed, ddi_copyin\n"); 3523 cmd->Status = EXT_STATUS_COPY_ERR; 3524 cmd->ResponseLen = 0; 3525 return; 3526 } 3527 3528 /* Find loop ID of the device */ 3529 if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWNN) { 3530 bptr = CFG_IST(ha, CFG_CTRL_242581) ? 3531 (caddr_t)&ha->init_ctrl_blk.cb24.node_name : 3532 (caddr_t)&ha->init_ctrl_blk.cb.node_name; 3533 if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWNN, 3534 EXT_DEF_WWN_NAME_SIZE) == 0) { 3535 local_hba = 1; 3536 } else { 3537 tq = ql_find_port(ha, 3538 (uint8_t *)tmp_rnid.Addr.FcAddr.WWNN, QLNT_NODE); 3539 } 3540 } else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWPN) { 3541 bptr = CFG_IST(ha, CFG_CTRL_242581) ? 3542 (caddr_t)&ha->init_ctrl_blk.cb24.port_name : 3543 (caddr_t)&ha->init_ctrl_blk.cb.port_name; 3544 if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWPN, 3545 EXT_DEF_WWN_NAME_SIZE) == 0) { 3546 local_hba = 1; 3547 } else { 3548 tq = ql_find_port(ha, 3549 (uint8_t *)tmp_rnid.Addr.FcAddr.WWPN, QLNT_PORT); 3550 } 3551 } else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_PORTID) { 3552 /* 3553 * Copy caller's d_id to tmp space. 3554 */ 3555 bcopy(&tmp_rnid.Addr.FcAddr.Id[1], tmp_fcid.r.d_id, 3556 EXT_DEF_PORTID_SIZE_ACTUAL); 3557 BIG_ENDIAN_24(&tmp_fcid.r.d_id[0]); 3558 3559 if (bcmp((void *)&ha->d_id, (void *)tmp_fcid.r.d_id, 3560 EXT_DEF_PORTID_SIZE_ACTUAL) == 0) { 3561 local_hba = 1; 3562 } else { 3563 tq = ql_find_port(ha, (uint8_t *)tmp_fcid.r.d_id, 3564 QLNT_PID); 3565 } 3566 } 3567 3568 /* Allocate memory for command. */ 3569 tmp_buf = kmem_zalloc(SEND_RNID_RSP_SIZE, KM_SLEEP); 3570 if (tmp_buf == NULL) { 3571 EL(ha, "failed, kmem_zalloc\n"); 3572 cmd->Status = EXT_STATUS_NO_MEMORY; 3573 cmd->ResponseLen = 0; 3574 return; 3575 } 3576 3577 if (local_hba) { 3578 rval = ql_get_rnid_params(ha, SEND_RNID_RSP_SIZE, tmp_buf); 3579 if (rval != QL_SUCCESS) { 3580 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval); 3581 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE); 3582 cmd->Status = EXT_STATUS_ERR; 3583 cmd->ResponseLen = 0; 3584 return; 3585 } 3586 3587 /* Save gotten RNID data. */ 3588 bcopy(tmp_buf, &rnid_data, sizeof (EXT_RNID_DATA)); 3589 3590 /* Now build the Send RNID response */ 3591 tmp_buf[0] = (char)(EXT_DEF_RNID_DFORMAT_TOPO_DISC); 3592 tmp_buf[1] = (2 * EXT_DEF_WWN_NAME_SIZE); 3593 tmp_buf[2] = 0; 3594 tmp_buf[3] = sizeof (EXT_RNID_DATA); 3595 3596 if (CFG_IST(ha, CFG_CTRL_242581)) { 3597 bcopy(ha->init_ctrl_blk.cb24.port_name, &tmp_buf[4], 3598 EXT_DEF_WWN_NAME_SIZE); 3599 bcopy(ha->init_ctrl_blk.cb24.node_name, 3600 &tmp_buf[4 + EXT_DEF_WWN_NAME_SIZE], 3601 EXT_DEF_WWN_NAME_SIZE); 3602 } else { 3603 bcopy(ha->init_ctrl_blk.cb.port_name, &tmp_buf[4], 3604 EXT_DEF_WWN_NAME_SIZE); 3605 bcopy(ha->init_ctrl_blk.cb.node_name, 3606 &tmp_buf[4 + EXT_DEF_WWN_NAME_SIZE], 3607 EXT_DEF_WWN_NAME_SIZE); 3608 } 3609 3610 bcopy((uint8_t *)&rnid_data, 3611 &tmp_buf[4 + 2 * EXT_DEF_WWN_NAME_SIZE], 3612 sizeof (EXT_RNID_DATA)); 3613 } else { 3614 if (tq == NULL) { 3615 /* no matching device */ 3616 EL(ha, "failed, device not found\n"); 3617 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE); 3618 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 3619 cmd->DetailStatus = EXT_DSTATUS_TARGET; 3620 cmd->ResponseLen = 0; 3621 return; 3622 } 3623 3624 /* Send command */ 3625 rval = ql_send_rnid_els(ha, tq->loop_id, 3626 (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE, tmp_buf); 3627 if (rval != QL_SUCCESS) { 3628 EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n", 3629 rval, tq->loop_id); 3630 while (LOOP_NOT_READY(ha)) { 3631 ql_delay(ha, 100000); 3632 if (loop_ready_wait-- == 0) { 3633 EL(ha, "failed, loop not ready\n"); 3634 cmd->Status = EXT_STATUS_ERR; 3635 cmd->ResponseLen = 0; 3636 } 3637 } 3638 rval = ql_send_rnid_els(ha, tq->loop_id, 3639 (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE, 3640 tmp_buf); 3641 if (rval != QL_SUCCESS) { 3642 /* error */ 3643 EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n", 3644 rval, tq->loop_id); 3645 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE); 3646 cmd->Status = EXT_STATUS_ERR; 3647 cmd->ResponseLen = 0; 3648 return; 3649 } 3650 } 3651 } 3652 3653 /* Copy the response */ 3654 copy_len = (cmd->ResponseLen > SEND_RNID_RSP_SIZE) ? 3655 SEND_RNID_RSP_SIZE : cmd->ResponseLen; 3656 3657 if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)cmd->ResponseAdr, 3658 copy_len, mode) != copy_len) { 3659 cmd->Status = EXT_STATUS_COPY_ERR; 3660 EL(ha, "failed, ddi_copyout\n"); 3661 } else { 3662 cmd->ResponseLen = copy_len; 3663 if (copy_len < SEND_RNID_RSP_SIZE) { 3664 cmd->Status = EXT_STATUS_DATA_OVERRUN; 3665 EL(ha, "failed, EXT_STATUS_DATA_OVERRUN\n"); 3666 3667 } else if (cmd->ResponseLen > SEND_RNID_RSP_SIZE) { 3668 cmd->Status = EXT_STATUS_DATA_UNDERRUN; 3669 EL(ha, "failed, EXT_STATUS_DATA_UNDERRUN\n"); 3670 } else { 3671 cmd->Status = EXT_STATUS_OK; 3672 QL_PRINT_9(CE_CONT, "(%d): done\n", 3673 ha->instance); 3674 } 3675 } 3676 3677 kmem_free(tmp_buf, SEND_RNID_RSP_SIZE); 3678 } 3679 3680 /* 3681 * ql_set_host_data 3682 * Process IOCTL subcommand to set host/adapter related data. 3683 * 3684 * Input: 3685 * ha: adapter state pointer. 3686 * cmd: User space CT arguments pointer. 3687 * mode: flags. 3688 * 3689 * Returns: 3690 * None, request status indicated in cmd->Status. 3691 * 3692 * Context: 3693 * Kernel context. 3694 */ 3695 static void 3696 ql_set_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 3697 { 3698 QL_PRINT_9(CE_CONT, "(%d): started, SubCode=%d\n", ha->instance, 3699 cmd->SubCode); 3700 3701 /* 3702 * case off on command subcode 3703 */ 3704 switch (cmd->SubCode) { 3705 case EXT_SC_SET_RNID: 3706 ql_set_rnid_parameters(ha, cmd, mode); 3707 break; 3708 case EXT_SC_RST_STATISTICS: 3709 (void) ql_reset_statistics(ha, cmd); 3710 break; 3711 case EXT_SC_SET_BEACON_STATE: 3712 ql_set_led_state(ha, cmd, mode); 3713 break; 3714 case EXT_SC_SET_PARMS: 3715 case EXT_SC_SET_BUS_MODE: 3716 case EXT_SC_SET_DR_DUMP_BUF: 3717 case EXT_SC_SET_RISC_CODE: 3718 case EXT_SC_SET_FLASH_RAM: 3719 case EXT_SC_SET_LUN_BITMASK: 3720 case EXT_SC_SET_RETRY_CNT: 3721 case EXT_SC_SET_RTIN: 3722 case EXT_SC_SET_FC_LUN_BITMASK: 3723 case EXT_SC_ADD_TARGET_DEVICE: 3724 case EXT_SC_SWAP_TARGET_DEVICE: 3725 case EXT_SC_SET_SEL_TIMEOUT: 3726 default: 3727 /* function not supported. */ 3728 EL(ha, "failed, function not supported=%d\n", cmd->SubCode); 3729 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 3730 break; 3731 } 3732 3733 if (cmd->Status != EXT_STATUS_OK) { 3734 EL(ha, "failed, Status=%d\n", cmd->Status); 3735 } else { 3736 /*EMPTY*/ 3737 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 3738 } 3739 } 3740 3741 /* 3742 * ql_get_host_data 3743 * Performs EXT_CC_GET_DATA subcommands. 3744 * 3745 * Input: 3746 * ha: adapter state pointer. 3747 * cmd: Local EXT_IOCTL cmd struct pointer. 3748 * mode: flags. 3749 * 3750 * Returns: 3751 * None, request status indicated in cmd->Status. 3752 * 3753 * Context: 3754 * Kernel context. 3755 */ 3756 static void 3757 ql_get_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 3758 { 3759 int out_size = 0; 3760 3761 QL_PRINT_9(CE_CONT, "(%d): started, SubCode=%d\n", ha->instance, 3762 cmd->SubCode); 3763 3764 /* case off on command subcode */ 3765 switch (cmd->SubCode) { 3766 case EXT_SC_GET_STATISTICS: 3767 out_size = sizeof (EXT_HBA_PORT_STAT); 3768 break; 3769 case EXT_SC_GET_FC_STATISTICS: 3770 out_size = sizeof (EXT_HBA_PORT_STAT); 3771 break; 3772 case EXT_SC_GET_PORT_SUMMARY: 3773 out_size = sizeof (EXT_DEVICEDATA); 3774 break; 3775 case EXT_SC_GET_RNID: 3776 out_size = sizeof (EXT_RNID_DATA); 3777 break; 3778 case EXT_SC_GET_TARGET_ID: 3779 out_size = sizeof (EXT_DEST_ADDR); 3780 break; 3781 case EXT_SC_GET_BEACON_STATE: 3782 out_size = sizeof (EXT_BEACON_CONTROL); 3783 break; 3784 case EXT_SC_GET_FC4_STATISTICS: 3785 out_size = sizeof (EXT_HBA_FC4STATISTICS); 3786 break; 3787 case EXT_SC_GET_DCBX_PARAM: 3788 out_size = EXT_DEF_DCBX_PARAM_BUF_SIZE; 3789 break; 3790 case EXT_SC_GET_SCSI_ADDR: 3791 case EXT_SC_GET_ERR_DETECTIONS: 3792 case EXT_SC_GET_BUS_MODE: 3793 case EXT_SC_GET_DR_DUMP_BUF: 3794 case EXT_SC_GET_RISC_CODE: 3795 case EXT_SC_GET_FLASH_RAM: 3796 case EXT_SC_GET_LINK_STATUS: 3797 case EXT_SC_GET_LOOP_ID: 3798 case EXT_SC_GET_LUN_BITMASK: 3799 case EXT_SC_GET_PORT_DATABASE: 3800 case EXT_SC_GET_PORT_DATABASE_MEM: 3801 case EXT_SC_GET_POSITION_MAP: 3802 case EXT_SC_GET_RETRY_CNT: 3803 case EXT_SC_GET_RTIN: 3804 case EXT_SC_GET_FC_LUN_BITMASK: 3805 case EXT_SC_GET_SEL_TIMEOUT: 3806 default: 3807 /* function not supported. */ 3808 EL(ha, "failed, function not supported=%d\n", cmd->SubCode); 3809 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 3810 cmd->ResponseLen = 0; 3811 return; 3812 } 3813 3814 if (cmd->ResponseLen < out_size) { 3815 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 3816 cmd->DetailStatus = out_size; 3817 EL(ha, "failed, ResponseLen=%xh, size=%xh\n", 3818 cmd->ResponseLen, out_size); 3819 cmd->ResponseLen = 0; 3820 return; 3821 } 3822 3823 switch (cmd->SubCode) { 3824 case EXT_SC_GET_RNID: 3825 ql_get_rnid_parameters(ha, cmd, mode); 3826 break; 3827 case EXT_SC_GET_STATISTICS: 3828 ql_get_statistics(ha, cmd, mode); 3829 break; 3830 case EXT_SC_GET_FC_STATISTICS: 3831 ql_get_statistics_fc(ha, cmd, mode); 3832 break; 3833 case EXT_SC_GET_FC4_STATISTICS: 3834 ql_get_statistics_fc4(ha, cmd, mode); 3835 break; 3836 case EXT_SC_GET_PORT_SUMMARY: 3837 ql_get_port_summary(ha, cmd, mode); 3838 break; 3839 case EXT_SC_GET_TARGET_ID: 3840 ql_get_target_id(ha, cmd, mode); 3841 break; 3842 case EXT_SC_GET_BEACON_STATE: 3843 ql_get_led_state(ha, cmd, mode); 3844 break; 3845 case EXT_SC_GET_DCBX_PARAM: 3846 ql_get_dcbx_parameters(ha, cmd, mode); 3847 break; 3848 } 3849 3850 if (cmd->Status != EXT_STATUS_OK) { 3851 EL(ha, "failed, Status=%d\n", cmd->Status); 3852 } else { 3853 /*EMPTY*/ 3854 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 3855 } 3856 } 3857 3858 /* ******************************************************************** */ 3859 /* Helper Functions */ 3860 /* ******************************************************************** */ 3861 3862 /* 3863 * ql_lun_count 3864 * Get numbers of LUNS on target. 3865 * 3866 * Input: 3867 * ha: adapter state pointer. 3868 * q: device queue pointer. 3869 * 3870 * Returns: 3871 * Number of LUNs. 3872 * 3873 * Context: 3874 * Kernel context. 3875 */ 3876 static int 3877 ql_lun_count(ql_adapter_state_t *ha, ql_tgt_t *tq) 3878 { 3879 int cnt; 3880 3881 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 3882 3883 /* Bypass LUNs that failed. */ 3884 cnt = ql_report_lun(ha, tq); 3885 if (cnt == 0) { 3886 cnt = ql_inq_scan(ha, tq, ha->maximum_luns_per_target); 3887 } 3888 3889 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 3890 3891 return (cnt); 3892 } 3893 3894 /* 3895 * ql_report_lun 3896 * Get numbers of LUNS using report LUN command. 3897 * 3898 * Input: 3899 * ha: adapter state pointer. 3900 * q: target queue pointer. 3901 * 3902 * Returns: 3903 * Number of LUNs. 3904 * 3905 * Context: 3906 * Kernel context. 3907 */ 3908 static int 3909 ql_report_lun(ql_adapter_state_t *ha, ql_tgt_t *tq) 3910 { 3911 int rval; 3912 uint8_t retries; 3913 ql_mbx_iocb_t *pkt; 3914 ql_rpt_lun_lst_t *rpt; 3915 dma_mem_t dma_mem; 3916 uint32_t pkt_size, cnt; 3917 uint16_t comp_status; 3918 uint8_t scsi_status_h, scsi_status_l, *reqs; 3919 3920 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 3921 3922 if (DRIVER_SUSPENDED(ha)) { 3923 EL(ha, "failed, LOOP_NOT_READY\n"); 3924 return (0); 3925 } 3926 3927 pkt_size = sizeof (ql_mbx_iocb_t) + sizeof (ql_rpt_lun_lst_t); 3928 pkt = kmem_zalloc(pkt_size, KM_SLEEP); 3929 if (pkt == NULL) { 3930 EL(ha, "failed, kmem_zalloc\n"); 3931 return (0); 3932 } 3933 rpt = (ql_rpt_lun_lst_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t)); 3934 3935 /* Get DMA memory for the IOCB */ 3936 if (ql_get_dma_mem(ha, &dma_mem, sizeof (ql_rpt_lun_lst_t), 3937 LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) { 3938 cmn_err(CE_WARN, "%s(%d): DMA memory " 3939 "alloc failed", QL_NAME, ha->instance); 3940 kmem_free(pkt, pkt_size); 3941 return (0); 3942 } 3943 3944 for (retries = 0; retries < 4; retries++) { 3945 if (CFG_IST(ha, CFG_CTRL_242581)) { 3946 pkt->cmd24.entry_type = IOCB_CMD_TYPE_7; 3947 pkt->cmd24.entry_count = 1; 3948 3949 /* Set N_port handle */ 3950 pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id); 3951 3952 /* Set target ID */ 3953 pkt->cmd24.target_id[0] = tq->d_id.b.al_pa; 3954 pkt->cmd24.target_id[1] = tq->d_id.b.area; 3955 pkt->cmd24.target_id[2] = tq->d_id.b.domain; 3956 3957 /* Set ISP command timeout. */ 3958 pkt->cmd24.timeout = LE_16(15); 3959 3960 /* Load SCSI CDB */ 3961 pkt->cmd24.scsi_cdb[0] = SCMD_REPORT_LUNS; 3962 pkt->cmd24.scsi_cdb[6] = 3963 MSB(MSW(sizeof (ql_rpt_lun_lst_t))); 3964 pkt->cmd24.scsi_cdb[7] = 3965 LSB(MSW(sizeof (ql_rpt_lun_lst_t))); 3966 pkt->cmd24.scsi_cdb[8] = 3967 MSB(LSW(sizeof (ql_rpt_lun_lst_t))); 3968 pkt->cmd24.scsi_cdb[9] = 3969 LSB(LSW(sizeof (ql_rpt_lun_lst_t))); 3970 for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) { 3971 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb 3972 + cnt, 4); 3973 } 3974 3975 /* Set tag queue control flags */ 3976 pkt->cmd24.task = TA_STAG; 3977 3978 /* Set transfer direction. */ 3979 pkt->cmd24.control_flags = CF_RD; 3980 3981 /* Set data segment count. */ 3982 pkt->cmd24.dseg_count = LE_16(1); 3983 3984 /* Load total byte count. */ 3985 /* Load data descriptor. */ 3986 pkt->cmd24.dseg_0_address[0] = (uint32_t) 3987 LE_32(LSD(dma_mem.cookie.dmac_laddress)); 3988 pkt->cmd24.dseg_0_address[1] = (uint32_t) 3989 LE_32(MSD(dma_mem.cookie.dmac_laddress)); 3990 pkt->cmd24.total_byte_count = 3991 LE_32(sizeof (ql_rpt_lun_lst_t)); 3992 pkt->cmd24.dseg_0_length = 3993 LE_32(sizeof (ql_rpt_lun_lst_t)); 3994 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) { 3995 pkt->cmd3.entry_type = IOCB_CMD_TYPE_3; 3996 pkt->cmd3.entry_count = 1; 3997 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 3998 pkt->cmd3.target_l = LSB(tq->loop_id); 3999 pkt->cmd3.target_h = MSB(tq->loop_id); 4000 } else { 4001 pkt->cmd3.target_h = LSB(tq->loop_id); 4002 } 4003 pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG; 4004 pkt->cmd3.timeout = LE_16(15); 4005 pkt->cmd3.dseg_count = LE_16(1); 4006 pkt->cmd3.scsi_cdb[0] = SCMD_REPORT_LUNS; 4007 pkt->cmd3.scsi_cdb[6] = 4008 MSB(MSW(sizeof (ql_rpt_lun_lst_t))); 4009 pkt->cmd3.scsi_cdb[7] = 4010 LSB(MSW(sizeof (ql_rpt_lun_lst_t))); 4011 pkt->cmd3.scsi_cdb[8] = 4012 MSB(LSW(sizeof (ql_rpt_lun_lst_t))); 4013 pkt->cmd3.scsi_cdb[9] = 4014 LSB(LSW(sizeof (ql_rpt_lun_lst_t))); 4015 pkt->cmd3.byte_count = 4016 LE_32(sizeof (ql_rpt_lun_lst_t)); 4017 pkt->cmd3.dseg_0_address[0] = (uint32_t) 4018 LE_32(LSD(dma_mem.cookie.dmac_laddress)); 4019 pkt->cmd3.dseg_0_address[1] = (uint32_t) 4020 LE_32(MSD(dma_mem.cookie.dmac_laddress)); 4021 pkt->cmd3.dseg_0_length = 4022 LE_32(sizeof (ql_rpt_lun_lst_t)); 4023 } else { 4024 pkt->cmd.entry_type = IOCB_CMD_TYPE_2; 4025 pkt->cmd.entry_count = 1; 4026 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 4027 pkt->cmd.target_l = LSB(tq->loop_id); 4028 pkt->cmd.target_h = MSB(tq->loop_id); 4029 } else { 4030 pkt->cmd.target_h = LSB(tq->loop_id); 4031 } 4032 pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG; 4033 pkt->cmd.timeout = LE_16(15); 4034 pkt->cmd.dseg_count = LE_16(1); 4035 pkt->cmd.scsi_cdb[0] = SCMD_REPORT_LUNS; 4036 pkt->cmd.scsi_cdb[6] = 4037 MSB(MSW(sizeof (ql_rpt_lun_lst_t))); 4038 pkt->cmd.scsi_cdb[7] = 4039 LSB(MSW(sizeof (ql_rpt_lun_lst_t))); 4040 pkt->cmd.scsi_cdb[8] = 4041 MSB(LSW(sizeof (ql_rpt_lun_lst_t))); 4042 pkt->cmd.scsi_cdb[9] = 4043 LSB(LSW(sizeof (ql_rpt_lun_lst_t))); 4044 pkt->cmd.byte_count = 4045 LE_32(sizeof (ql_rpt_lun_lst_t)); 4046 pkt->cmd.dseg_0_address = (uint32_t) 4047 LE_32(LSD(dma_mem.cookie.dmac_laddress)); 4048 pkt->cmd.dseg_0_length = 4049 LE_32(sizeof (ql_rpt_lun_lst_t)); 4050 } 4051 4052 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, 4053 sizeof (ql_mbx_iocb_t)); 4054 4055 /* Sync in coming DMA buffer. */ 4056 (void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size, 4057 DDI_DMA_SYNC_FORKERNEL); 4058 /* Copy in coming DMA data. */ 4059 ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)rpt, 4060 (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR); 4061 4062 if (CFG_IST(ha, CFG_CTRL_242581)) { 4063 pkt->sts24.entry_status = (uint8_t) 4064 (pkt->sts24.entry_status & 0x3c); 4065 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status); 4066 scsi_status_h = pkt->sts24.scsi_status_h; 4067 scsi_status_l = pkt->sts24.scsi_status_l; 4068 cnt = scsi_status_h & FCP_RSP_LEN_VALID ? 4069 LE_32(pkt->sts24.fcp_rsp_data_length) : 0; 4070 reqs = &pkt->sts24.rsp_sense_data[cnt]; 4071 } else { 4072 pkt->sts.entry_status = (uint8_t) 4073 (pkt->sts.entry_status & 0x7e); 4074 comp_status = (uint16_t)LE_16(pkt->sts.comp_status); 4075 scsi_status_h = pkt->sts.scsi_status_h; 4076 scsi_status_l = pkt->sts.scsi_status_l; 4077 reqs = &pkt->sts.req_sense_data[0]; 4078 } 4079 if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) { 4080 EL(ha, "failed, entry_status=%xh, d_id=%xh\n", 4081 pkt->sts.entry_status, tq->d_id.b24); 4082 rval = QL_FUNCTION_PARAMETER_ERROR; 4083 } 4084 4085 if (rval != QL_SUCCESS || comp_status != CS_COMPLETE || 4086 scsi_status_l & STATUS_CHECK) { 4087 /* Device underrun, treat as OK. */ 4088 if (rval == QL_SUCCESS && 4089 comp_status == CS_DATA_UNDERRUN && 4090 scsi_status_h & FCP_RESID_UNDER) { 4091 break; 4092 } 4093 4094 EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, " 4095 "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24, 4096 comp_status, scsi_status_h, scsi_status_l); 4097 4098 if (rval == QL_SUCCESS) { 4099 if ((comp_status == CS_TIMEOUT) || 4100 (comp_status == CS_PORT_UNAVAILABLE) || 4101 (comp_status == CS_PORT_LOGGED_OUT)) { 4102 rval = QL_FUNCTION_TIMEOUT; 4103 break; 4104 } 4105 rval = QL_FUNCTION_FAILED; 4106 } else if (rval == QL_ABORTED) { 4107 break; 4108 } 4109 4110 if (scsi_status_l & STATUS_CHECK) { 4111 EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh" 4112 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh" 4113 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0], 4114 reqs[1], reqs[2], reqs[3], reqs[4], 4115 reqs[5], reqs[6], reqs[7], reqs[8], 4116 reqs[9], reqs[10], reqs[11], reqs[12], 4117 reqs[13], reqs[14], reqs[15], reqs[16], 4118 reqs[17]); 4119 } 4120 } else { 4121 break; 4122 } 4123 bzero((caddr_t)pkt, pkt_size); 4124 } 4125 4126 if (rval != QL_SUCCESS) { 4127 EL(ha, "failed=%xh\n", rval); 4128 rval = 0; 4129 } else { 4130 QL_PRINT_9(CE_CONT, "(%d): LUN list\n", ha->instance); 4131 QL_DUMP_9(rpt, 8, rpt->hdr.len + 8); 4132 rval = (int)(BE_32(rpt->hdr.len) / 8); 4133 } 4134 4135 kmem_free(pkt, pkt_size); 4136 ql_free_dma_resource(ha, &dma_mem); 4137 4138 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 4139 4140 return (rval); 4141 } 4142 4143 /* 4144 * ql_inq_scan 4145 * Get numbers of LUNS using inquiry command. 4146 * 4147 * Input: 4148 * ha: adapter state pointer. 4149 * tq: target queue pointer. 4150 * count: scan for the number of existing LUNs. 4151 * 4152 * Returns: 4153 * Number of LUNs. 4154 * 4155 * Context: 4156 * Kernel context. 4157 */ 4158 static int 4159 ql_inq_scan(ql_adapter_state_t *ha, ql_tgt_t *tq, int count) 4160 { 4161 int lun, cnt, rval; 4162 ql_mbx_iocb_t *pkt; 4163 uint8_t *inq; 4164 uint32_t pkt_size; 4165 4166 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 4167 4168 pkt_size = sizeof (ql_mbx_iocb_t) + INQ_DATA_SIZE; 4169 pkt = kmem_zalloc(pkt_size, KM_SLEEP); 4170 if (pkt == NULL) { 4171 EL(ha, "failed, kmem_zalloc\n"); 4172 return (0); 4173 } 4174 inq = (uint8_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t)); 4175 4176 cnt = 0; 4177 for (lun = 0; lun < MAX_LUNS; lun++) { 4178 4179 if (DRIVER_SUSPENDED(ha)) { 4180 rval = QL_LOOP_DOWN; 4181 cnt = 0; 4182 break; 4183 } 4184 4185 rval = ql_inq(ha, tq, lun, pkt, INQ_DATA_SIZE); 4186 if (rval == QL_SUCCESS) { 4187 switch (*inq) { 4188 case DTYPE_DIRECT: 4189 case DTYPE_PROCESSOR: /* Appliance. */ 4190 case DTYPE_WORM: 4191 case DTYPE_RODIRECT: 4192 case DTYPE_SCANNER: 4193 case DTYPE_OPTICAL: 4194 case DTYPE_CHANGER: 4195 case DTYPE_ESI: 4196 cnt++; 4197 break; 4198 case DTYPE_SEQUENTIAL: 4199 cnt++; 4200 tq->flags |= TQF_TAPE_DEVICE; 4201 break; 4202 default: 4203 QL_PRINT_9(CE_CONT, "(%d): failed, " 4204 "unsupported device id=%xh, lun=%d, " 4205 "type=%xh\n", ha->instance, tq->loop_id, 4206 lun, *inq); 4207 break; 4208 } 4209 4210 if (*inq == DTYPE_ESI || cnt >= count) { 4211 break; 4212 } 4213 } else if (rval == QL_ABORTED || rval == QL_FUNCTION_TIMEOUT) { 4214 cnt = 0; 4215 break; 4216 } 4217 } 4218 4219 kmem_free(pkt, pkt_size); 4220 4221 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 4222 4223 return (cnt); 4224 } 4225 4226 /* 4227 * ql_inq 4228 * Issue inquiry command. 4229 * 4230 * Input: 4231 * ha: adapter state pointer. 4232 * tq: target queue pointer. 4233 * lun: LUN number. 4234 * pkt: command and buffer pointer. 4235 * inq_len: amount of inquiry data. 4236 * 4237 * Returns: 4238 * ql local function return status code. 4239 * 4240 * Context: 4241 * Kernel context. 4242 */ 4243 static int 4244 ql_inq(ql_adapter_state_t *ha, ql_tgt_t *tq, int lun, ql_mbx_iocb_t *pkt, 4245 uint8_t inq_len) 4246 { 4247 dma_mem_t dma_mem; 4248 int rval, retries; 4249 uint32_t pkt_size, cnt; 4250 uint16_t comp_status; 4251 uint8_t scsi_status_h, scsi_status_l, *reqs; 4252 caddr_t inq_data; 4253 4254 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 4255 4256 if (DRIVER_SUSPENDED(ha)) { 4257 EL(ha, "failed, loop down\n"); 4258 return (QL_FUNCTION_TIMEOUT); 4259 } 4260 4261 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + inq_len); 4262 bzero((caddr_t)pkt, pkt_size); 4263 4264 inq_data = (caddr_t)pkt + sizeof (ql_mbx_iocb_t); 4265 4266 /* Get DMA memory for the IOCB */ 4267 if (ql_get_dma_mem(ha, &dma_mem, inq_len, 4268 LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) { 4269 cmn_err(CE_WARN, "%s(%d): DMA memory " 4270 "alloc failed", QL_NAME, ha->instance); 4271 return (0); 4272 } 4273 4274 for (retries = 0; retries < 4; retries++) { 4275 if (CFG_IST(ha, CFG_CTRL_242581)) { 4276 pkt->cmd24.entry_type = IOCB_CMD_TYPE_7; 4277 pkt->cmd24.entry_count = 1; 4278 4279 /* Set LUN number */ 4280 pkt->cmd24.fcp_lun[2] = LSB(lun); 4281 pkt->cmd24.fcp_lun[3] = MSB(lun); 4282 4283 /* Set N_port handle */ 4284 pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id); 4285 4286 /* Set target ID */ 4287 pkt->cmd24.target_id[0] = tq->d_id.b.al_pa; 4288 pkt->cmd24.target_id[1] = tq->d_id.b.area; 4289 pkt->cmd24.target_id[2] = tq->d_id.b.domain; 4290 4291 /* Set ISP command timeout. */ 4292 pkt->cmd24.timeout = LE_16(15); 4293 4294 /* Load SCSI CDB */ 4295 pkt->cmd24.scsi_cdb[0] = SCMD_INQUIRY; 4296 pkt->cmd24.scsi_cdb[4] = inq_len; 4297 for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) { 4298 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb 4299 + cnt, 4); 4300 } 4301 4302 /* Set tag queue control flags */ 4303 pkt->cmd24.task = TA_STAG; 4304 4305 /* Set transfer direction. */ 4306 pkt->cmd24.control_flags = CF_RD; 4307 4308 /* Set data segment count. */ 4309 pkt->cmd24.dseg_count = LE_16(1); 4310 4311 /* Load total byte count. */ 4312 pkt->cmd24.total_byte_count = LE_32(inq_len); 4313 4314 /* Load data descriptor. */ 4315 pkt->cmd24.dseg_0_address[0] = (uint32_t) 4316 LE_32(LSD(dma_mem.cookie.dmac_laddress)); 4317 pkt->cmd24.dseg_0_address[1] = (uint32_t) 4318 LE_32(MSD(dma_mem.cookie.dmac_laddress)); 4319 pkt->cmd24.dseg_0_length = LE_32(inq_len); 4320 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) { 4321 pkt->cmd3.entry_type = IOCB_CMD_TYPE_3; 4322 cnt = CMD_TYPE_3_DATA_SEGMENTS; 4323 4324 pkt->cmd3.entry_count = 1; 4325 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 4326 pkt->cmd3.target_l = LSB(tq->loop_id); 4327 pkt->cmd3.target_h = MSB(tq->loop_id); 4328 } else { 4329 pkt->cmd3.target_h = LSB(tq->loop_id); 4330 } 4331 pkt->cmd3.lun_l = LSB(lun); 4332 pkt->cmd3.lun_h = MSB(lun); 4333 pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG; 4334 pkt->cmd3.timeout = LE_16(15); 4335 pkt->cmd3.scsi_cdb[0] = SCMD_INQUIRY; 4336 pkt->cmd3.scsi_cdb[4] = inq_len; 4337 pkt->cmd3.dseg_count = LE_16(1); 4338 pkt->cmd3.byte_count = LE_32(inq_len); 4339 pkt->cmd3.dseg_0_address[0] = (uint32_t) 4340 LE_32(LSD(dma_mem.cookie.dmac_laddress)); 4341 pkt->cmd3.dseg_0_address[1] = (uint32_t) 4342 LE_32(MSD(dma_mem.cookie.dmac_laddress)); 4343 pkt->cmd3.dseg_0_length = LE_32(inq_len); 4344 } else { 4345 pkt->cmd.entry_type = IOCB_CMD_TYPE_2; 4346 cnt = CMD_TYPE_2_DATA_SEGMENTS; 4347 4348 pkt->cmd.entry_count = 1; 4349 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 4350 pkt->cmd.target_l = LSB(tq->loop_id); 4351 pkt->cmd.target_h = MSB(tq->loop_id); 4352 } else { 4353 pkt->cmd.target_h = LSB(tq->loop_id); 4354 } 4355 pkt->cmd.lun_l = LSB(lun); 4356 pkt->cmd.lun_h = MSB(lun); 4357 pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG; 4358 pkt->cmd.timeout = LE_16(15); 4359 pkt->cmd.scsi_cdb[0] = SCMD_INQUIRY; 4360 pkt->cmd.scsi_cdb[4] = inq_len; 4361 pkt->cmd.dseg_count = LE_16(1); 4362 pkt->cmd.byte_count = LE_32(inq_len); 4363 pkt->cmd.dseg_0_address = (uint32_t) 4364 LE_32(LSD(dma_mem.cookie.dmac_laddress)); 4365 pkt->cmd.dseg_0_length = LE_32(inq_len); 4366 } 4367 4368 /* rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size); */ 4369 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, 4370 sizeof (ql_mbx_iocb_t)); 4371 4372 /* Sync in coming IOCB DMA buffer. */ 4373 (void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size, 4374 DDI_DMA_SYNC_FORKERNEL); 4375 /* Copy in coming DMA data. */ 4376 ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)inq_data, 4377 (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR); 4378 4379 if (CFG_IST(ha, CFG_CTRL_242581)) { 4380 pkt->sts24.entry_status = (uint8_t) 4381 (pkt->sts24.entry_status & 0x3c); 4382 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status); 4383 scsi_status_h = pkt->sts24.scsi_status_h; 4384 scsi_status_l = pkt->sts24.scsi_status_l; 4385 cnt = scsi_status_h & FCP_RSP_LEN_VALID ? 4386 LE_32(pkt->sts24.fcp_rsp_data_length) : 0; 4387 reqs = &pkt->sts24.rsp_sense_data[cnt]; 4388 } else { 4389 pkt->sts.entry_status = (uint8_t) 4390 (pkt->sts.entry_status & 0x7e); 4391 comp_status = (uint16_t)LE_16(pkt->sts.comp_status); 4392 scsi_status_h = pkt->sts.scsi_status_h; 4393 scsi_status_l = pkt->sts.scsi_status_l; 4394 reqs = &pkt->sts.req_sense_data[0]; 4395 } 4396 if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) { 4397 EL(ha, "failed, entry_status=%xh, d_id=%xh\n", 4398 pkt->sts.entry_status, tq->d_id.b24); 4399 rval = QL_FUNCTION_PARAMETER_ERROR; 4400 } 4401 4402 if (rval != QL_SUCCESS || comp_status != CS_COMPLETE || 4403 scsi_status_l & STATUS_CHECK) { 4404 EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, " 4405 "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24, 4406 comp_status, scsi_status_h, scsi_status_l); 4407 4408 if (rval == QL_SUCCESS) { 4409 if ((comp_status == CS_TIMEOUT) || 4410 (comp_status == CS_PORT_UNAVAILABLE) || 4411 (comp_status == CS_PORT_LOGGED_OUT)) { 4412 rval = QL_FUNCTION_TIMEOUT; 4413 break; 4414 } 4415 rval = QL_FUNCTION_FAILED; 4416 } 4417 4418 if (scsi_status_l & STATUS_CHECK) { 4419 EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh" 4420 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh" 4421 "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0], 4422 reqs[1], reqs[2], reqs[3], reqs[4], 4423 reqs[5], reqs[6], reqs[7], reqs[8], 4424 reqs[9], reqs[10], reqs[11], reqs[12], 4425 reqs[13], reqs[14], reqs[15], reqs[16], 4426 reqs[17]); 4427 } 4428 } else { 4429 break; 4430 } 4431 } 4432 ql_free_dma_resource(ha, &dma_mem); 4433 4434 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 4435 4436 return (rval); 4437 } 4438 4439 /* 4440 * ql_get_buffer_data 4441 * Copies data from user space to kernal buffer. 4442 * 4443 * Input: 4444 * src: User source buffer address. 4445 * dst: Kernal destination buffer address. 4446 * size: Amount of data. 4447 * mode: flags. 4448 * 4449 * Returns: 4450 * Returns number of bytes transferred. 4451 * 4452 * Context: 4453 * Kernel context. 4454 */ 4455 static uint32_t 4456 ql_get_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode) 4457 { 4458 uint32_t cnt; 4459 4460 for (cnt = 0; cnt < size; cnt++) { 4461 if (ddi_copyin(src++, dst++, 1, mode) != 0) { 4462 QL_PRINT_2(CE_CONT, "failed, ddi_copyin\n"); 4463 break; 4464 } 4465 } 4466 4467 return (cnt); 4468 } 4469 4470 /* 4471 * ql_send_buffer_data 4472 * Copies data from kernal buffer to user space. 4473 * 4474 * Input: 4475 * src: Kernal source buffer address. 4476 * dst: User destination buffer address. 4477 * size: Amount of data. 4478 * mode: flags. 4479 * 4480 * Returns: 4481 * Returns number of bytes transferred. 4482 * 4483 * Context: 4484 * Kernel context. 4485 */ 4486 static uint32_t 4487 ql_send_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode) 4488 { 4489 uint32_t cnt; 4490 4491 for (cnt = 0; cnt < size; cnt++) { 4492 if (ddi_copyout(src++, dst++, 1, mode) != 0) { 4493 QL_PRINT_2(CE_CONT, "failed, ddi_copyin\n"); 4494 break; 4495 } 4496 } 4497 4498 return (cnt); 4499 } 4500 4501 /* 4502 * ql_find_port 4503 * Locates device queue. 4504 * 4505 * Input: 4506 * ha: adapter state pointer. 4507 * name: device port name. 4508 * 4509 * Returns: 4510 * Returns target queue pointer. 4511 * 4512 * Context: 4513 * Kernel context. 4514 */ 4515 static ql_tgt_t * 4516 ql_find_port(ql_adapter_state_t *ha, uint8_t *name, uint16_t type) 4517 { 4518 ql_link_t *link; 4519 ql_tgt_t *tq; 4520 uint16_t index; 4521 4522 /* Scan port list for requested target */ 4523 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) { 4524 for (link = ha->dev[index].first; link != NULL; 4525 link = link->next) { 4526 tq = link->base_address; 4527 4528 switch (type) { 4529 case QLNT_LOOP_ID: 4530 if (bcmp(name, &tq->loop_id, 4531 sizeof (uint16_t)) == 0) { 4532 return (tq); 4533 } 4534 break; 4535 case QLNT_PORT: 4536 if (bcmp(name, tq->port_name, 8) == 0) { 4537 return (tq); 4538 } 4539 break; 4540 case QLNT_NODE: 4541 if (bcmp(name, tq->node_name, 8) == 0) { 4542 return (tq); 4543 } 4544 break; 4545 case QLNT_PID: 4546 if (bcmp(name, tq->d_id.r.d_id, 4547 sizeof (tq->d_id.r.d_id)) == 0) { 4548 return (tq); 4549 } 4550 break; 4551 default: 4552 EL(ha, "failed, invalid type=%d\n", type); 4553 return (NULL); 4554 } 4555 } 4556 } 4557 4558 return (NULL); 4559 } 4560 4561 /* 4562 * ql_24xx_flash_desc 4563 * Get flash descriptor table. 4564 * 4565 * Input: 4566 * ha: adapter state pointer. 4567 * 4568 * Returns: 4569 * ql local function return status code. 4570 * 4571 * Context: 4572 * Kernel context. 4573 */ 4574 static int 4575 ql_24xx_flash_desc(ql_adapter_state_t *ha) 4576 { 4577 uint32_t cnt; 4578 uint16_t chksum, *bp, data; 4579 int rval; 4580 flash_desc_t *fdesc; 4581 ql_xioctl_t *xp = ha->xioctl; 4582 4583 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 4584 4585 if (ha->flash_desc_addr == 0) { 4586 EL(ha, "desc ptr=0\n"); 4587 return (QL_FUNCTION_FAILED); 4588 } 4589 4590 if ((fdesc = kmem_zalloc(sizeof (flash_desc_t), KM_SLEEP)) == NULL) { 4591 EL(ha, "kmem_zalloc=null\n"); 4592 return (QL_MEMORY_ALLOC_FAILED); 4593 } 4594 rval = ql_dump_fcode(ha, (uint8_t *)fdesc, sizeof (flash_desc_t), 4595 ha->flash_desc_addr << 2); 4596 if (rval != QL_SUCCESS) { 4597 EL(ha, "read status=%xh\n", rval); 4598 kmem_free(fdesc, sizeof (flash_desc_t)); 4599 return (rval); 4600 } 4601 4602 chksum = 0; 4603 bp = (uint16_t *)fdesc; 4604 for (cnt = 0; cnt < (sizeof (flash_desc_t)) / 2; cnt++) { 4605 data = *bp++; 4606 LITTLE_ENDIAN_16(&data); 4607 chksum += data; 4608 } 4609 4610 LITTLE_ENDIAN_32(&fdesc->flash_valid); 4611 LITTLE_ENDIAN_16(&fdesc->flash_version); 4612 LITTLE_ENDIAN_16(&fdesc->flash_len); 4613 LITTLE_ENDIAN_16(&fdesc->flash_checksum); 4614 LITTLE_ENDIAN_16(&fdesc->flash_manuf); 4615 LITTLE_ENDIAN_16(&fdesc->flash_id); 4616 LITTLE_ENDIAN_32(&fdesc->block_size); 4617 LITTLE_ENDIAN_32(&fdesc->alt_block_size); 4618 LITTLE_ENDIAN_32(&fdesc->flash_size); 4619 LITTLE_ENDIAN_32(&fdesc->write_enable_data); 4620 LITTLE_ENDIAN_32(&fdesc->read_timeout); 4621 4622 /* flash size in desc table is in 1024 bytes */ 4623 fdesc->flash_size = fdesc->flash_size * 0x400; 4624 4625 if (chksum != 0 || fdesc->flash_valid != FLASH_DESC_VAILD || 4626 fdesc->flash_version != FLASH_DESC_VERSION) { 4627 EL(ha, "invalid descriptor table\n"); 4628 kmem_free(fdesc, sizeof (flash_desc_t)); 4629 return (QL_FUNCTION_FAILED); 4630 } 4631 4632 bcopy(fdesc, &xp->fdesc, sizeof (flash_desc_t)); 4633 kmem_free(fdesc, sizeof (flash_desc_t)); 4634 4635 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 4636 4637 return (QL_SUCCESS); 4638 } 4639 4640 /* 4641 * ql_setup_flash 4642 * Gets the manufacturer and id number of the flash chip, and 4643 * sets up the size parameter. 4644 * 4645 * Input: 4646 * ha: adapter state pointer. 4647 * 4648 * Returns: 4649 * int: ql local function return status code. 4650 * 4651 * Context: 4652 * Kernel context. 4653 */ 4654 static int 4655 ql_setup_flash(ql_adapter_state_t *ha) 4656 { 4657 ql_xioctl_t *xp = ha->xioctl; 4658 int rval = QL_SUCCESS; 4659 4660 if (xp->fdesc.flash_size != 0) { 4661 return (rval); 4662 } 4663 4664 if (CFG_IST(ha, CFG_CTRL_2200) && !ha->subven_id) { 4665 return (QL_FUNCTION_FAILED); 4666 } 4667 4668 if (CFG_IST(ha, CFG_CTRL_2581)) { 4669 /* 4670 * Temporarily set the ha->xioctl->fdesc.flash_size to 4671 * 25xx flash size to avoid failing of ql_dump_focde. 4672 */ 4673 ha->xioctl->fdesc.flash_size = CFG_IST(ha, CFG_CTRL_25XX) ? 4674 0x200000 : 0x400000; 4675 if (ql_24xx_flash_desc(ha) == QL_SUCCESS) { 4676 EL(ha, "flash desc table ok, exit\n"); 4677 return (rval); 4678 } 4679 (void) ql_24xx_flash_id(ha); 4680 4681 } else if (CFG_IST(ha, CFG_CTRL_242581)) { 4682 (void) ql_24xx_flash_id(ha); 4683 } else { 4684 ql_flash_enable(ha); 4685 4686 ql_write_flash_byte(ha, 0x5555, 0xaa); 4687 ql_write_flash_byte(ha, 0x2aaa, 0x55); 4688 ql_write_flash_byte(ha, 0x5555, 0x90); 4689 xp->fdesc.flash_manuf = (uint8_t)ql_read_flash_byte(ha, 0x0000); 4690 4691 if (CFG_IST(ha, CFG_SBUS_CARD)) { 4692 ql_write_flash_byte(ha, 0xaaaa, 0xaa); 4693 ql_write_flash_byte(ha, 0x5555, 0x55); 4694 ql_write_flash_byte(ha, 0xaaaa, 0x90); 4695 xp->fdesc.flash_id = (uint16_t) 4696 ql_read_flash_byte(ha, 0x0002); 4697 } else { 4698 ql_write_flash_byte(ha, 0x5555, 0xaa); 4699 ql_write_flash_byte(ha, 0x2aaa, 0x55); 4700 ql_write_flash_byte(ha, 0x5555, 0x90); 4701 xp->fdesc.flash_id = (uint16_t) 4702 ql_read_flash_byte(ha, 0x0001); 4703 } 4704 4705 ql_write_flash_byte(ha, 0x5555, 0xaa); 4706 ql_write_flash_byte(ha, 0x2aaa, 0x55); 4707 ql_write_flash_byte(ha, 0x5555, 0xf0); 4708 4709 ql_flash_disable(ha); 4710 } 4711 4712 /* Default flash descriptor table. */ 4713 xp->fdesc.write_statusreg_cmd = 1; 4714 xp->fdesc.write_enable_bits = 0; 4715 xp->fdesc.unprotect_sector_cmd = 0; 4716 xp->fdesc.protect_sector_cmd = 0; 4717 xp->fdesc.write_disable_bits = 0x9c; 4718 xp->fdesc.block_size = 0x10000; 4719 xp->fdesc.erase_cmd = 0xd8; 4720 4721 switch (xp->fdesc.flash_manuf) { 4722 case AMD_FLASH: 4723 switch (xp->fdesc.flash_id) { 4724 case SPAN_FLASHID_2048K: 4725 xp->fdesc.flash_size = 0x200000; 4726 break; 4727 case AMD_FLASHID_1024K: 4728 xp->fdesc.flash_size = 0x100000; 4729 break; 4730 case AMD_FLASHID_512K: 4731 case AMD_FLASHID_512Kt: 4732 case AMD_FLASHID_512Kb: 4733 if (CFG_IST(ha, CFG_SBUS_CARD)) { 4734 xp->fdesc.flash_size = QL_SBUS_FCODE_SIZE; 4735 } else { 4736 xp->fdesc.flash_size = 0x80000; 4737 } 4738 break; 4739 case AMD_FLASHID_128K: 4740 xp->fdesc.flash_size = 0x20000; 4741 break; 4742 default: 4743 rval = QL_FUNCTION_FAILED; 4744 break; 4745 } 4746 break; 4747 case ST_FLASH: 4748 switch (xp->fdesc.flash_id) { 4749 case ST_FLASHID_128K: 4750 xp->fdesc.flash_size = 0x20000; 4751 break; 4752 case ST_FLASHID_512K: 4753 xp->fdesc.flash_size = 0x80000; 4754 break; 4755 case ST_FLASHID_M25PXX: 4756 if (xp->fdesc.flash_len == 0x14) { 4757 xp->fdesc.flash_size = 0x100000; 4758 } else if (xp->fdesc.flash_len == 0x15) { 4759 xp->fdesc.flash_size = 0x200000; 4760 } else { 4761 rval = QL_FUNCTION_FAILED; 4762 } 4763 break; 4764 default: 4765 rval = QL_FUNCTION_FAILED; 4766 break; 4767 } 4768 break; 4769 case SST_FLASH: 4770 switch (xp->fdesc.flash_id) { 4771 case SST_FLASHID_128K: 4772 xp->fdesc.flash_size = 0x20000; 4773 break; 4774 case SST_FLASHID_1024K_A: 4775 xp->fdesc.flash_size = 0x100000; 4776 xp->fdesc.block_size = 0x8000; 4777 xp->fdesc.erase_cmd = 0x52; 4778 break; 4779 case SST_FLASHID_1024K: 4780 case SST_FLASHID_1024K_B: 4781 xp->fdesc.flash_size = 0x100000; 4782 break; 4783 case SST_FLASHID_2048K: 4784 xp->fdesc.flash_size = 0x200000; 4785 break; 4786 default: 4787 rval = QL_FUNCTION_FAILED; 4788 break; 4789 } 4790 break; 4791 case MXIC_FLASH: 4792 switch (xp->fdesc.flash_id) { 4793 case MXIC_FLASHID_512K: 4794 xp->fdesc.flash_size = 0x80000; 4795 break; 4796 case MXIC_FLASHID_1024K: 4797 xp->fdesc.flash_size = 0x100000; 4798 break; 4799 case MXIC_FLASHID_25LXX: 4800 if (xp->fdesc.flash_len == 0x14) { 4801 xp->fdesc.flash_size = 0x100000; 4802 } else if (xp->fdesc.flash_len == 0x15) { 4803 xp->fdesc.flash_size = 0x200000; 4804 } else { 4805 rval = QL_FUNCTION_FAILED; 4806 } 4807 break; 4808 default: 4809 rval = QL_FUNCTION_FAILED; 4810 break; 4811 } 4812 break; 4813 case ATMEL_FLASH: 4814 switch (xp->fdesc.flash_id) { 4815 case ATMEL_FLASHID_1024K: 4816 xp->fdesc.flash_size = 0x100000; 4817 xp->fdesc.write_disable_bits = 0xbc; 4818 xp->fdesc.unprotect_sector_cmd = 0x39; 4819 xp->fdesc.protect_sector_cmd = 0x36; 4820 break; 4821 default: 4822 rval = QL_FUNCTION_FAILED; 4823 break; 4824 } 4825 break; 4826 case WINBOND_FLASH: 4827 switch (xp->fdesc.flash_id) { 4828 case WINBOND_FLASHID: 4829 if (xp->fdesc.flash_len == 0x15) { 4830 xp->fdesc.flash_size = 0x200000; 4831 } else if (xp->fdesc.flash_len == 0x16) { 4832 xp->fdesc.flash_size = 0x400000; 4833 } else if (xp->fdesc.flash_len == 0x17) { 4834 xp->fdesc.flash_size = 0x800000; 4835 } else { 4836 rval = QL_FUNCTION_FAILED; 4837 } 4838 break; 4839 default: 4840 rval = QL_FUNCTION_FAILED; 4841 break; 4842 } 4843 break; 4844 case INTEL_FLASH: 4845 switch (xp->fdesc.flash_id) { 4846 case INTEL_FLASHID: 4847 if (xp->fdesc.flash_len == 0x11) { 4848 xp->fdesc.flash_size = 0x200000; 4849 } else if (xp->fdesc.flash_len == 0x12) { 4850 xp->fdesc.flash_size = 0x400000; 4851 } else if (xp->fdesc.flash_len == 0x13) { 4852 xp->fdesc.flash_size = 0x800000; 4853 } else { 4854 rval = QL_FUNCTION_FAILED; 4855 } 4856 break; 4857 default: 4858 rval = QL_FUNCTION_FAILED; 4859 break; 4860 } 4861 break; 4862 default: 4863 rval = QL_FUNCTION_FAILED; 4864 break; 4865 } 4866 4867 /* Try flash table later. */ 4868 if (rval != QL_SUCCESS && CFG_IST(ha, CFG_CTRL_242581)) { 4869 EL(ha, "no default id\n"); 4870 return (QL_SUCCESS); 4871 } 4872 4873 /* 4874 * hack for non std 2312 and 6312 boards. hardware people need to 4875 * use either the 128k flash chip (original), or something larger. 4876 * For driver purposes, we'll treat it as a 128k flash chip. 4877 */ 4878 if ((ha->device_id == 0x2312 || ha->device_id == 0x6312 || 4879 ha->device_id == 0x6322) && (xp->fdesc.flash_size > 0x20000) && 4880 (CFG_IST(ha, CFG_SBUS_CARD) == 0)) { 4881 EL(ha, "chip exceeds max size: %xh, using 128k\n", 4882 xp->fdesc.flash_size); 4883 xp->fdesc.flash_size = 0x20000; 4884 } 4885 4886 if (rval == QL_SUCCESS) { 4887 EL(ha, "man_id=%xh, flash_id=%xh, size=%xh\n", 4888 xp->fdesc.flash_manuf, xp->fdesc.flash_id, 4889 xp->fdesc.flash_size); 4890 } else { 4891 EL(ha, "unsupported mfr / type: man_id=%xh, flash_id=%xh\n", 4892 xp->fdesc.flash_manuf, xp->fdesc.flash_id); 4893 } 4894 4895 return (rval); 4896 } 4897 4898 /* 4899 * ql_flash_fcode_load 4900 * Loads fcode data into flash from application. 4901 * 4902 * Input: 4903 * ha: adapter state pointer. 4904 * bp: user buffer address. 4905 * size: user buffer size. 4906 * mode: flags 4907 * 4908 * Returns: 4909 * 4910 * Context: 4911 * Kernel context. 4912 */ 4913 static int 4914 ql_flash_fcode_load(ql_adapter_state_t *ha, void *bp, uint32_t bsize, 4915 int mode) 4916 { 4917 uint8_t *bfp; 4918 ql_xioctl_t *xp = ha->xioctl; 4919 int rval = 0; 4920 4921 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 4922 4923 if (bsize > xp->fdesc.flash_size) { 4924 EL(ha, "failed, bufsize: %xh, flash size: %xh\n", bsize, 4925 xp->fdesc.flash_size); 4926 return (ENOMEM); 4927 } 4928 4929 if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) { 4930 EL(ha, "failed, kmem_zalloc\n"); 4931 rval = ENOMEM; 4932 } else { 4933 if (ddi_copyin(bp, bfp, bsize, mode) != 0) { 4934 EL(ha, "failed, ddi_copyin\n"); 4935 rval = EFAULT; 4936 } else if (ql_load_fcode(ha, bfp, bsize, 0) != QL_SUCCESS) { 4937 EL(ha, "failed, load_fcode\n"); 4938 rval = EFAULT; 4939 } else { 4940 /* Reset caches on all adapter instances. */ 4941 ql_update_flash_caches(ha); 4942 rval = 0; 4943 } 4944 kmem_free(bfp, bsize); 4945 } 4946 4947 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 4948 4949 return (rval); 4950 } 4951 4952 /* 4953 * ql_load_fcode 4954 * Loads fcode in to flash. 4955 * 4956 * Input: 4957 * ha: adapter state pointer. 4958 * dp: data pointer. 4959 * size: data length. 4960 * addr: flash byte address. 4961 * 4962 * Returns: 4963 * ql local function return status code. 4964 * 4965 * Context: 4966 * Kernel context. 4967 */ 4968 int 4969 ql_load_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size, uint32_t addr) 4970 { 4971 uint32_t cnt; 4972 int rval; 4973 4974 if (CFG_IST(ha, CFG_CTRL_242581)) { 4975 return (ql_24xx_load_flash(ha, dp, size, addr)); 4976 } 4977 4978 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 4979 4980 if (CFG_IST(ha, CFG_SBUS_CARD)) { 4981 /* 4982 * sbus has an additional check to make 4983 * sure they don't brick the HBA. 4984 */ 4985 if (dp[0] != 0xf1) { 4986 EL(ha, "failed, incorrect fcode for sbus\n"); 4987 return (QL_FUNCTION_PARAMETER_ERROR); 4988 } 4989 } 4990 4991 GLOBAL_HW_LOCK(); 4992 4993 /* Enable Flash Read/Write. */ 4994 ql_flash_enable(ha); 4995 4996 /* Erase flash prior to write. */ 4997 rval = ql_erase_flash(ha, 0); 4998 4999 if (rval == QL_SUCCESS) { 5000 /* Write fcode data to flash. */ 5001 for (cnt = 0; cnt < (uint32_t)size; cnt++) { 5002 /* Allow other system activity. */ 5003 if (cnt % 0x1000 == 0) { 5004 drv_usecwait(1); 5005 } 5006 rval = ql_program_flash_address(ha, addr++, *dp++); 5007 if (rval != QL_SUCCESS) 5008 break; 5009 } 5010 } 5011 5012 ql_flash_disable(ha); 5013 5014 GLOBAL_HW_UNLOCK(); 5015 5016 if (rval != QL_SUCCESS) { 5017 EL(ha, "failed, rval=%xh\n", rval); 5018 } else { 5019 /*EMPTY*/ 5020 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5021 } 5022 return (rval); 5023 } 5024 5025 /* 5026 * ql_flash_fcode_dump 5027 * Dumps FLASH to application. 5028 * 5029 * Input: 5030 * ha: adapter state pointer. 5031 * bp: user buffer address. 5032 * bsize: user buffer size 5033 * faddr: flash byte address 5034 * mode: flags 5035 * 5036 * Returns: 5037 * 5038 * Context: 5039 * Kernel context. 5040 */ 5041 static int 5042 ql_flash_fcode_dump(ql_adapter_state_t *ha, void *bp, uint32_t bsize, 5043 uint32_t faddr, int mode) 5044 { 5045 uint8_t *bfp; 5046 int rval; 5047 ql_xioctl_t *xp = ha->xioctl; 5048 5049 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5050 5051 /* adjust max read size to flash size */ 5052 if (bsize > xp->fdesc.flash_size) { 5053 EL(ha, "adjusting req=%xh, max=%xh\n", bsize, 5054 xp->fdesc.flash_size); 5055 bsize = xp->fdesc.flash_size; 5056 } 5057 5058 if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) { 5059 EL(ha, "failed, kmem_zalloc\n"); 5060 rval = ENOMEM; 5061 } else { 5062 /* Dump Flash fcode. */ 5063 rval = ql_dump_fcode(ha, bfp, bsize, faddr); 5064 5065 if (rval != QL_SUCCESS) { 5066 EL(ha, "failed, dump_fcode = %x\n", rval); 5067 rval = EFAULT; 5068 } else if (ddi_copyout(bfp, bp, bsize, mode) != 0) { 5069 EL(ha, "failed, ddi_copyout\n"); 5070 rval = EFAULT; 5071 } else { 5072 rval = 0; 5073 } 5074 kmem_free(bfp, bsize); 5075 } 5076 5077 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5078 5079 return (rval); 5080 } 5081 5082 /* 5083 * ql_dump_fcode 5084 * Dumps fcode from flash. 5085 * 5086 * Input: 5087 * ha: adapter state pointer. 5088 * dp: data pointer. 5089 * size: data length in bytes. 5090 * startpos: starting position in flash (byte address). 5091 * 5092 * Returns: 5093 * ql local function return status code. 5094 * 5095 * Context: 5096 * Kernel context. 5097 * 5098 */ 5099 int 5100 ql_dump_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size, 5101 uint32_t startpos) 5102 { 5103 uint32_t cnt, data, addr; 5104 uint8_t bp[4]; 5105 int rval = QL_SUCCESS; 5106 5107 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5108 5109 /* make sure startpos+size doesn't exceed flash */ 5110 if (size + startpos > ha->xioctl->fdesc.flash_size) { 5111 EL(ha, "exceeded flash range, sz=%xh, stp=%xh, flsz=%xh\n", 5112 size, startpos, ha->xioctl->fdesc.flash_size); 5113 return (QL_FUNCTION_PARAMETER_ERROR); 5114 } 5115 5116 if (CFG_IST(ha, CFG_CTRL_242581)) { 5117 /* check start addr is 32 bit aligned for 24xx */ 5118 if ((startpos & 0x3) != 0) { 5119 rval = ql_24xx_read_flash(ha, 5120 ha->flash_data_addr | startpos >> 2, &data); 5121 if (rval != QL_SUCCESS) { 5122 EL(ha, "failed2, rval = %xh\n", rval); 5123 return (rval); 5124 } 5125 bp[0] = LSB(LSW(data)); 5126 bp[1] = MSB(LSW(data)); 5127 bp[2] = LSB(MSW(data)); 5128 bp[3] = MSB(MSW(data)); 5129 while (size && startpos & 0x3) { 5130 *dp++ = bp[startpos & 0x3]; 5131 startpos++; 5132 size--; 5133 } 5134 if (size == 0) { 5135 QL_PRINT_9(CE_CONT, "(%d): done2\n", 5136 ha->instance); 5137 return (rval); 5138 } 5139 } 5140 5141 /* adjust 24xx start addr for 32 bit words */ 5142 addr = startpos / 4 | ha->flash_data_addr; 5143 } 5144 5145 GLOBAL_HW_LOCK(); 5146 5147 /* Enable Flash Read/Write. */ 5148 if (CFG_IST(ha, CFG_CTRL_242581) == 0) { 5149 ql_flash_enable(ha); 5150 } 5151 5152 /* Read fcode data from flash. */ 5153 while (size) { 5154 /* Allow other system activity. */ 5155 if (size % 0x1000 == 0) { 5156 ql_delay(ha, 100000); 5157 } 5158 if (CFG_IST(ha, CFG_CTRL_242581)) { 5159 rval = ql_24xx_read_flash(ha, addr++, &data); 5160 if (rval != QL_SUCCESS) { 5161 break; 5162 } 5163 bp[0] = LSB(LSW(data)); 5164 bp[1] = MSB(LSW(data)); 5165 bp[2] = LSB(MSW(data)); 5166 bp[3] = MSB(MSW(data)); 5167 for (cnt = 0; size && cnt < 4; size--) { 5168 *dp++ = bp[cnt++]; 5169 } 5170 } else { 5171 *dp++ = (uint8_t)ql_read_flash_byte(ha, startpos++); 5172 size--; 5173 } 5174 } 5175 5176 if (CFG_IST(ha, CFG_CTRL_242581) == 0) { 5177 ql_flash_disable(ha); 5178 } 5179 5180 GLOBAL_HW_UNLOCK(); 5181 5182 if (rval != QL_SUCCESS) { 5183 EL(ha, "failed, rval = %xh\n", rval); 5184 } else { 5185 /*EMPTY*/ 5186 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5187 } 5188 return (rval); 5189 } 5190 5191 /* 5192 * ql_program_flash_address 5193 * Program flash address. 5194 * 5195 * Input: 5196 * ha: adapter state pointer. 5197 * addr: flash byte address. 5198 * data: data to be written to flash. 5199 * 5200 * Returns: 5201 * ql local function return status code. 5202 * 5203 * Context: 5204 * Kernel context. 5205 */ 5206 static int 5207 ql_program_flash_address(ql_adapter_state_t *ha, uint32_t addr, 5208 uint8_t data) 5209 { 5210 int rval; 5211 5212 /* Write Program Command Sequence */ 5213 if (CFG_IST(ha, CFG_SBUS_CARD)) { 5214 ql_write_flash_byte(ha, 0x5555, 0xa0); 5215 ql_write_flash_byte(ha, addr, data); 5216 } else { 5217 ql_write_flash_byte(ha, 0x5555, 0xaa); 5218 ql_write_flash_byte(ha, 0x2aaa, 0x55); 5219 ql_write_flash_byte(ha, 0x5555, 0xa0); 5220 ql_write_flash_byte(ha, addr, data); 5221 } 5222 5223 /* Wait for write to complete. */ 5224 rval = ql_poll_flash(ha, addr, data); 5225 5226 if (rval != QL_SUCCESS) { 5227 EL(ha, "failed, rval=%xh\n", rval); 5228 } 5229 return (rval); 5230 } 5231 5232 /* 5233 * ql_set_rnid_parameters 5234 * Set RNID parameters. 5235 * 5236 * Input: 5237 * ha: adapter state pointer. 5238 * cmd: User space CT arguments pointer. 5239 * mode: flags. 5240 */ 5241 static void 5242 ql_set_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5243 { 5244 EXT_SET_RNID_REQ tmp_set; 5245 EXT_RNID_DATA *tmp_buf; 5246 int rval = 0; 5247 5248 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5249 5250 if (DRIVER_SUSPENDED(ha)) { 5251 EL(ha, "failed, LOOP_NOT_READY\n"); 5252 cmd->Status = EXT_STATUS_BUSY; 5253 cmd->ResponseLen = 0; 5254 return; 5255 } 5256 5257 cmd->ResponseLen = 0; /* NO response to caller. */ 5258 if (cmd->RequestLen != sizeof (EXT_SET_RNID_REQ)) { 5259 /* parameter error */ 5260 EL(ha, "failed, RequestLen < EXT_SET_RNID_REQ, Len=%xh\n", 5261 cmd->RequestLen); 5262 cmd->Status = EXT_STATUS_INVALID_PARAM; 5263 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 5264 cmd->ResponseLen = 0; 5265 return; 5266 } 5267 5268 rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &tmp_set, 5269 cmd->RequestLen, mode); 5270 if (rval != 0) { 5271 EL(ha, "failed, ddi_copyin\n"); 5272 cmd->Status = EXT_STATUS_COPY_ERR; 5273 cmd->ResponseLen = 0; 5274 return; 5275 } 5276 5277 /* Allocate memory for command. */ 5278 tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP); 5279 if (tmp_buf == NULL) { 5280 EL(ha, "failed, kmem_zalloc\n"); 5281 cmd->Status = EXT_STATUS_NO_MEMORY; 5282 cmd->ResponseLen = 0; 5283 return; 5284 } 5285 5286 rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA), 5287 (caddr_t)tmp_buf); 5288 if (rval != QL_SUCCESS) { 5289 /* error */ 5290 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval); 5291 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA)); 5292 cmd->Status = EXT_STATUS_ERR; 5293 cmd->ResponseLen = 0; 5294 return; 5295 } 5296 5297 /* Now set the requested params. */ 5298 bcopy(tmp_set.IPVersion, tmp_buf->IPVersion, 2); 5299 bcopy(tmp_set.UDPPortNumber, tmp_buf->UDPPortNumber, 2); 5300 bcopy(tmp_set.IPAddress, tmp_buf->IPAddress, 16); 5301 5302 rval = ql_set_rnid_params(ha, sizeof (EXT_RNID_DATA), 5303 (caddr_t)tmp_buf); 5304 if (rval != QL_SUCCESS) { 5305 /* error */ 5306 EL(ha, "failed, set_rnid_params_mbx=%xh\n", rval); 5307 cmd->Status = EXT_STATUS_ERR; 5308 cmd->ResponseLen = 0; 5309 } 5310 5311 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA)); 5312 5313 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5314 } 5315 5316 /* 5317 * ql_get_rnid_parameters 5318 * Get RNID parameters. 5319 * 5320 * Input: 5321 * ha: adapter state pointer. 5322 * cmd: User space CT arguments pointer. 5323 * mode: flags. 5324 */ 5325 static void 5326 ql_get_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5327 { 5328 EXT_RNID_DATA *tmp_buf; 5329 uint32_t rval; 5330 5331 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5332 5333 if (DRIVER_SUSPENDED(ha)) { 5334 EL(ha, "failed, LOOP_NOT_READY\n"); 5335 cmd->Status = EXT_STATUS_BUSY; 5336 cmd->ResponseLen = 0; 5337 return; 5338 } 5339 5340 /* Allocate memory for command. */ 5341 tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP); 5342 if (tmp_buf == NULL) { 5343 EL(ha, "failed, kmem_zalloc\n"); 5344 cmd->Status = EXT_STATUS_NO_MEMORY; 5345 cmd->ResponseLen = 0; 5346 return; 5347 } 5348 5349 /* Send command */ 5350 rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA), 5351 (caddr_t)tmp_buf); 5352 if (rval != QL_SUCCESS) { 5353 /* error */ 5354 EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval); 5355 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA)); 5356 cmd->Status = EXT_STATUS_ERR; 5357 cmd->ResponseLen = 0; 5358 return; 5359 } 5360 5361 /* Copy the response */ 5362 if (ql_send_buffer_data((caddr_t)tmp_buf, 5363 (caddr_t)(uintptr_t)cmd->ResponseAdr, 5364 sizeof (EXT_RNID_DATA), mode) != sizeof (EXT_RNID_DATA)) { 5365 EL(ha, "failed, ddi_copyout\n"); 5366 cmd->Status = EXT_STATUS_COPY_ERR; 5367 cmd->ResponseLen = 0; 5368 } else { 5369 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5370 cmd->ResponseLen = sizeof (EXT_RNID_DATA); 5371 } 5372 5373 kmem_free(tmp_buf, sizeof (EXT_RNID_DATA)); 5374 } 5375 5376 /* 5377 * ql_reset_statistics 5378 * Performs EXT_SC_RST_STATISTICS subcommand. of EXT_CC_SET_DATA. 5379 * 5380 * Input: 5381 * ha: adapter state pointer. 5382 * cmd: Local EXT_IOCTL cmd struct pointer. 5383 * 5384 * Returns: 5385 * None, request status indicated in cmd->Status. 5386 * 5387 * Context: 5388 * Kernel context. 5389 */ 5390 static int 5391 ql_reset_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd) 5392 { 5393 ql_xioctl_t *xp = ha->xioctl; 5394 int rval = 0; 5395 5396 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5397 5398 if (DRIVER_SUSPENDED(ha)) { 5399 EL(ha, "failed, LOOP_NOT_READY\n"); 5400 cmd->Status = EXT_STATUS_BUSY; 5401 cmd->ResponseLen = 0; 5402 return (QL_FUNCTION_SUSPENDED); 5403 } 5404 5405 rval = ql_reset_link_status(ha); 5406 if (rval != QL_SUCCESS) { 5407 EL(ha, "failed, reset_link_status_mbx=%xh\n", rval); 5408 cmd->Status = EXT_STATUS_MAILBOX; 5409 cmd->DetailStatus = rval; 5410 cmd->ResponseLen = 0; 5411 } 5412 5413 TASK_DAEMON_LOCK(ha); 5414 xp->IosRequested = 0; 5415 xp->BytesRequested = 0; 5416 xp->IOInputRequests = 0; 5417 xp->IOOutputRequests = 0; 5418 xp->IOControlRequests = 0; 5419 xp->IOInputMByteCnt = 0; 5420 xp->IOOutputMByteCnt = 0; 5421 xp->IOOutputByteCnt = 0; 5422 xp->IOInputByteCnt = 0; 5423 TASK_DAEMON_UNLOCK(ha); 5424 5425 INTR_LOCK(ha); 5426 xp->ControllerErrorCount = 0; 5427 xp->DeviceErrorCount = 0; 5428 xp->TotalLipResets = 0; 5429 xp->TotalInterrupts = 0; 5430 INTR_UNLOCK(ha); 5431 5432 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5433 5434 return (rval); 5435 } 5436 5437 /* 5438 * ql_get_statistics 5439 * Performs EXT_SC_GET_STATISTICS subcommand. of EXT_CC_GET_DATA. 5440 * 5441 * Input: 5442 * ha: adapter state pointer. 5443 * cmd: Local EXT_IOCTL cmd struct pointer. 5444 * mode: flags. 5445 * 5446 * Returns: 5447 * None, request status indicated in cmd->Status. 5448 * 5449 * Context: 5450 * Kernel context. 5451 */ 5452 static void 5453 ql_get_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5454 { 5455 EXT_HBA_PORT_STAT ps = {0}; 5456 ql_link_stats_t *ls; 5457 int rval; 5458 ql_xioctl_t *xp = ha->xioctl; 5459 int retry = 10; 5460 5461 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5462 5463 while (ha->task_daemon_flags & 5464 (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) { 5465 ql_delay(ha, 10000000); /* 10 second delay */ 5466 5467 retry--; 5468 5469 if (retry == 0) { /* effectively 100 seconds */ 5470 EL(ha, "failed, LOOP_NOT_READY\n"); 5471 cmd->Status = EXT_STATUS_BUSY; 5472 cmd->ResponseLen = 0; 5473 return; 5474 } 5475 } 5476 5477 /* Allocate memory for command. */ 5478 ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP); 5479 if (ls == NULL) { 5480 EL(ha, "failed, kmem_zalloc\n"); 5481 cmd->Status = EXT_STATUS_NO_MEMORY; 5482 cmd->ResponseLen = 0; 5483 return; 5484 } 5485 5486 /* 5487 * I think these are supposed to be port statistics 5488 * the loop ID or port ID should be in cmd->Instance. 5489 */ 5490 rval = ql_get_status_counts(ha, (uint16_t) 5491 (ha->task_daemon_flags & LOOP_DOWN ? 0xFF : ha->loop_id), 5492 sizeof (ql_link_stats_t), (caddr_t)ls, 0); 5493 if (rval != QL_SUCCESS) { 5494 EL(ha, "failed, get_link_status=%xh, id=%xh\n", rval, 5495 ha->loop_id); 5496 cmd->Status = EXT_STATUS_MAILBOX; 5497 cmd->DetailStatus = rval; 5498 cmd->ResponseLen = 0; 5499 } else { 5500 ps.ControllerErrorCount = xp->ControllerErrorCount; 5501 ps.DeviceErrorCount = xp->DeviceErrorCount; 5502 ps.IoCount = (uint32_t)(xp->IOInputRequests + 5503 xp->IOOutputRequests + xp->IOControlRequests); 5504 ps.MBytesCount = (uint32_t)(xp->IOInputMByteCnt + 5505 xp->IOOutputMByteCnt); 5506 ps.LipResetCount = xp->TotalLipResets; 5507 ps.InterruptCount = xp->TotalInterrupts; 5508 ps.LinkFailureCount = LE_32(ls->link_fail_cnt); 5509 ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt); 5510 ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt); 5511 ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt); 5512 ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt); 5513 ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt); 5514 5515 rval = ddi_copyout((void *)&ps, 5516 (void *)(uintptr_t)cmd->ResponseAdr, 5517 sizeof (EXT_HBA_PORT_STAT), mode); 5518 if (rval != 0) { 5519 EL(ha, "failed, ddi_copyout\n"); 5520 cmd->Status = EXT_STATUS_COPY_ERR; 5521 cmd->ResponseLen = 0; 5522 } else { 5523 cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT); 5524 } 5525 } 5526 5527 kmem_free(ls, sizeof (ql_link_stats_t)); 5528 5529 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5530 } 5531 5532 /* 5533 * ql_get_statistics_fc 5534 * Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA. 5535 * 5536 * Input: 5537 * ha: adapter state pointer. 5538 * cmd: Local EXT_IOCTL cmd struct pointer. 5539 * mode: flags. 5540 * 5541 * Returns: 5542 * None, request status indicated in cmd->Status. 5543 * 5544 * Context: 5545 * Kernel context. 5546 */ 5547 static void 5548 ql_get_statistics_fc(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5549 { 5550 EXT_HBA_PORT_STAT ps = {0}; 5551 ql_link_stats_t *ls; 5552 int rval; 5553 uint16_t qlnt; 5554 EXT_DEST_ADDR pextdestaddr; 5555 uint8_t *name; 5556 ql_tgt_t *tq = NULL; 5557 int retry = 10; 5558 5559 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5560 5561 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, 5562 (void *)&pextdestaddr, sizeof (EXT_DEST_ADDR), mode) != 0) { 5563 EL(ha, "failed, ddi_copyin\n"); 5564 cmd->Status = EXT_STATUS_COPY_ERR; 5565 cmd->ResponseLen = 0; 5566 return; 5567 } 5568 5569 qlnt = QLNT_PORT; 5570 name = pextdestaddr.DestAddr.WWPN; 5571 5572 QL_PRINT_9(CE_CONT, "(%d): wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n", 5573 ha->instance, name[0], name[1], name[2], name[3], name[4], 5574 name[5], name[6], name[7]); 5575 5576 tq = ql_find_port(ha, name, qlnt); 5577 5578 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) { 5579 EL(ha, "failed, fc_port not found\n"); 5580 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 5581 cmd->ResponseLen = 0; 5582 return; 5583 } 5584 5585 while (ha->task_daemon_flags & 5586 (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) { 5587 ql_delay(ha, 10000000); /* 10 second delay */ 5588 5589 retry--; 5590 5591 if (retry == 0) { /* effectively 100 seconds */ 5592 EL(ha, "failed, LOOP_NOT_READY\n"); 5593 cmd->Status = EXT_STATUS_BUSY; 5594 cmd->ResponseLen = 0; 5595 return; 5596 } 5597 } 5598 5599 /* Allocate memory for command. */ 5600 ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP); 5601 if (ls == NULL) { 5602 EL(ha, "failed, kmem_zalloc\n"); 5603 cmd->Status = EXT_STATUS_NO_MEMORY; 5604 cmd->ResponseLen = 0; 5605 return; 5606 } 5607 5608 rval = ql_get_link_status(ha, tq->loop_id, sizeof (ql_link_stats_t), 5609 (caddr_t)ls, 0); 5610 if (rval != QL_SUCCESS) { 5611 EL(ha, "failed, get_link_status=%xh, d_id=%xh\n", rval, 5612 tq->d_id.b24); 5613 cmd->Status = EXT_STATUS_MAILBOX; 5614 cmd->DetailStatus = rval; 5615 cmd->ResponseLen = 0; 5616 } else { 5617 ps.LinkFailureCount = LE_32(ls->link_fail_cnt); 5618 ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt); 5619 ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt); 5620 ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt); 5621 ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt); 5622 ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt); 5623 5624 rval = ddi_copyout((void *)&ps, 5625 (void *)(uintptr_t)cmd->ResponseAdr, 5626 sizeof (EXT_HBA_PORT_STAT), mode); 5627 5628 if (rval != 0) { 5629 EL(ha, "failed, ddi_copyout\n"); 5630 cmd->Status = EXT_STATUS_COPY_ERR; 5631 cmd->ResponseLen = 0; 5632 } else { 5633 cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT); 5634 } 5635 } 5636 5637 kmem_free(ls, sizeof (ql_link_stats_t)); 5638 5639 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5640 } 5641 5642 /* 5643 * ql_get_statistics_fc4 5644 * Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA. 5645 * 5646 * Input: 5647 * ha: adapter state pointer. 5648 * cmd: Local EXT_IOCTL cmd struct pointer. 5649 * mode: flags. 5650 * 5651 * Returns: 5652 * None, request status indicated in cmd->Status. 5653 * 5654 * Context: 5655 * Kernel context. 5656 */ 5657 static void 5658 ql_get_statistics_fc4(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5659 { 5660 uint32_t rval; 5661 EXT_HBA_FC4STATISTICS fc4stats = {0}; 5662 ql_xioctl_t *xp = ha->xioctl; 5663 5664 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5665 5666 fc4stats.InputRequests = xp->IOInputRequests; 5667 fc4stats.OutputRequests = xp->IOOutputRequests; 5668 fc4stats.ControlRequests = xp->IOControlRequests; 5669 fc4stats.InputMegabytes = xp->IOInputMByteCnt; 5670 fc4stats.OutputMegabytes = xp->IOOutputMByteCnt; 5671 5672 rval = ddi_copyout((void *)&fc4stats, 5673 (void *)(uintptr_t)cmd->ResponseAdr, 5674 sizeof (EXT_HBA_FC4STATISTICS), mode); 5675 5676 if (rval != 0) { 5677 EL(ha, "failed, ddi_copyout\n"); 5678 cmd->Status = EXT_STATUS_COPY_ERR; 5679 cmd->ResponseLen = 0; 5680 } else { 5681 cmd->ResponseLen = sizeof (EXT_HBA_FC4STATISTICS); 5682 } 5683 5684 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5685 } 5686 5687 /* 5688 * ql_set_led_state 5689 * Performs EXT_SET_BEACON_STATE subcommand of EXT_CC_SET_DATA. 5690 * 5691 * Input: 5692 * ha: adapter state pointer. 5693 * cmd: Local EXT_IOCTL cmd struct pointer. 5694 * mode: flags. 5695 * 5696 * Returns: 5697 * None, request status indicated in cmd->Status. 5698 * 5699 * Context: 5700 * Kernel context. 5701 */ 5702 static void 5703 ql_set_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5704 { 5705 EXT_BEACON_CONTROL bstate; 5706 uint32_t rval; 5707 ql_xioctl_t *xp = ha->xioctl; 5708 5709 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5710 5711 if (cmd->RequestLen < sizeof (EXT_BEACON_CONTROL)) { 5712 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 5713 cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL); 5714 EL(ha, "done - failed, RequestLen < EXT_BEACON_CONTROL," 5715 " Len=%xh\n", cmd->RequestLen); 5716 cmd->ResponseLen = 0; 5717 return; 5718 } 5719 5720 if (ha->device_id < 0x2300) { 5721 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 5722 cmd->DetailStatus = 0; 5723 EL(ha, "done - failed, Invalid function for HBA model\n"); 5724 cmd->ResponseLen = 0; 5725 return; 5726 } 5727 5728 rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &bstate, 5729 cmd->RequestLen, mode); 5730 5731 if (rval != 0) { 5732 cmd->Status = EXT_STATUS_COPY_ERR; 5733 EL(ha, "done - failed, ddi_copyin\n"); 5734 return; 5735 } 5736 5737 switch (bstate.State) { 5738 case EXT_DEF_GRN_BLINK_OFF: /* turn beacon off */ 5739 if (xp->ledstate.BeaconState == BEACON_OFF) { 5740 /* not quite an error -- LED state is already off */ 5741 cmd->Status = EXT_STATUS_OK; 5742 EL(ha, "LED off request -- LED is already off\n"); 5743 break; 5744 } 5745 5746 xp->ledstate.BeaconState = BEACON_OFF; 5747 xp->ledstate.LEDflags = LED_ALL_OFF; 5748 5749 if ((rval = ql_wrapup_led(ha)) != QL_SUCCESS) { 5750 cmd->Status = EXT_STATUS_MAILBOX; 5751 } else { 5752 cmd->Status = EXT_STATUS_OK; 5753 } 5754 break; 5755 5756 case EXT_DEF_GRN_BLINK_ON: /* turn beacon on */ 5757 if (xp->ledstate.BeaconState == BEACON_ON) { 5758 /* not quite an error -- LED state is already on */ 5759 cmd->Status = EXT_STATUS_OK; 5760 EL(ha, "LED on request - LED is already on\n"); 5761 break; 5762 } 5763 5764 if ((rval = ql_setup_led(ha)) != QL_SUCCESS) { 5765 cmd->Status = EXT_STATUS_MAILBOX; 5766 break; 5767 } 5768 5769 if (CFG_IST(ha, CFG_CTRL_242581)) { 5770 xp->ledstate.LEDflags = LED_YELLOW_24 | LED_AMBER_24; 5771 } else { 5772 xp->ledstate.LEDflags = LED_GREEN; 5773 } 5774 xp->ledstate.BeaconState = BEACON_ON; 5775 5776 cmd->Status = EXT_STATUS_OK; 5777 break; 5778 default: 5779 cmd->Status = EXT_STATUS_ERR; 5780 EL(ha, "failed, unknown state request %xh\n", bstate.State); 5781 break; 5782 } 5783 5784 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5785 } 5786 5787 /* 5788 * ql_get_led_state 5789 * Performs EXT_GET_BEACON_STATE subcommand of EXT_CC_GET_DATA. 5790 * 5791 * Input: 5792 * ha: adapter state pointer. 5793 * cmd: Local EXT_IOCTL cmd struct pointer. 5794 * mode: flags. 5795 * 5796 * Returns: 5797 * None, request status indicated in cmd->Status. 5798 * 5799 * Context: 5800 * Kernel context. 5801 */ 5802 static void 5803 ql_get_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 5804 { 5805 EXT_BEACON_CONTROL bstate = {0}; 5806 uint32_t rval; 5807 ql_xioctl_t *xp = ha->xioctl; 5808 5809 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5810 5811 if (cmd->ResponseLen < sizeof (EXT_BEACON_CONTROL)) { 5812 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 5813 cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL); 5814 EL(ha, "done - failed, ResponseLen < EXT_BEACON_CONTROL," 5815 "Len=%xh\n", cmd->ResponseLen); 5816 cmd->ResponseLen = 0; 5817 return; 5818 } 5819 5820 if (ha->device_id < 0x2300) { 5821 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 5822 cmd->DetailStatus = 0; 5823 EL(ha, "done - failed, Invalid function for HBA model\n"); 5824 cmd->ResponseLen = 0; 5825 return; 5826 } 5827 5828 if (ha->task_daemon_flags & ABORT_ISP_ACTIVE) { 5829 cmd->Status = EXT_STATUS_BUSY; 5830 EL(ha, "done - failed, isp abort active\n"); 5831 cmd->ResponseLen = 0; 5832 return; 5833 } 5834 5835 /* inform the user of the current beacon state (off or on) */ 5836 bstate.State = xp->ledstate.BeaconState; 5837 5838 rval = ddi_copyout((void *)&bstate, 5839 (void *)(uintptr_t)cmd->ResponseAdr, 5840 sizeof (EXT_BEACON_CONTROL), mode); 5841 5842 if (rval != 0) { 5843 EL(ha, "failed, ddi_copyout\n"); 5844 cmd->Status = EXT_STATUS_COPY_ERR; 5845 cmd->ResponseLen = 0; 5846 } else { 5847 cmd->Status = EXT_STATUS_OK; 5848 cmd->ResponseLen = sizeof (EXT_BEACON_CONTROL); 5849 } 5850 5851 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5852 } 5853 5854 /* 5855 * ql_blink_led 5856 * Determine the next state of the LED and drive it 5857 * 5858 * Input: 5859 * ha: adapter state pointer. 5860 * 5861 * Context: 5862 * Interrupt context. 5863 */ 5864 void 5865 ql_blink_led(ql_adapter_state_t *ha) 5866 { 5867 uint32_t nextstate; 5868 ql_xioctl_t *xp = ha->xioctl; 5869 5870 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5871 5872 if (xp->ledstate.BeaconState == BEACON_ON) { 5873 /* determine the next led state */ 5874 if (CFG_IST(ha, CFG_CTRL_242581)) { 5875 nextstate = (xp->ledstate.LEDflags) & 5876 (~(RD32_IO_REG(ha, gpiod))); 5877 } else { 5878 nextstate = (xp->ledstate.LEDflags) & 5879 (~(RD16_IO_REG(ha, gpiod))); 5880 } 5881 5882 /* turn the led on or off */ 5883 ql_drive_led(ha, nextstate); 5884 } 5885 5886 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5887 } 5888 5889 /* 5890 * ql_drive_led 5891 * drive the led's as determined by LEDflags 5892 * 5893 * Input: 5894 * ha: adapter state pointer. 5895 * LEDflags: LED flags 5896 * 5897 * Context: 5898 * Kernel/Interrupt context. 5899 */ 5900 static void 5901 ql_drive_led(ql_adapter_state_t *ha, uint32_t LEDflags) 5902 { 5903 5904 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5905 5906 if (CFG_IST(ha, (CFG_CTRL_2300 | CFG_CTRL_6322))) { 5907 5908 uint16_t gpio_enable, gpio_data; 5909 5910 /* setup to send new data */ 5911 gpio_enable = (uint16_t)RD16_IO_REG(ha, gpioe); 5912 gpio_enable = (uint16_t)(gpio_enable | LED_MASK); 5913 WRT16_IO_REG(ha, gpioe, gpio_enable); 5914 5915 /* read current data and clear out old led data */ 5916 gpio_data = (uint16_t)RD16_IO_REG(ha, gpiod); 5917 gpio_data = (uint16_t)(gpio_data & ~LED_MASK); 5918 5919 /* set in the new led data. */ 5920 gpio_data = (uint16_t)(gpio_data | LEDflags); 5921 5922 /* write out the new led data */ 5923 WRT16_IO_REG(ha, gpiod, gpio_data); 5924 5925 } else if (CFG_IST(ha, CFG_CTRL_242581)) { 5926 5927 uint32_t gpio_data; 5928 5929 /* setup to send new data */ 5930 gpio_data = RD32_IO_REG(ha, gpiod); 5931 gpio_data |= LED_MASK_UPDATE_24; 5932 WRT32_IO_REG(ha, gpiod, gpio_data); 5933 5934 /* read current data and clear out old led data */ 5935 gpio_data = RD32_IO_REG(ha, gpiod); 5936 gpio_data &= ~LED_MASK_COLORS_24; 5937 5938 /* set in the new led data */ 5939 gpio_data |= LEDflags; 5940 5941 /* write out the new led data */ 5942 WRT32_IO_REG(ha, gpiod, gpio_data); 5943 5944 } else { 5945 EL(ha, "unsupported HBA: %xh", ha->device_id); 5946 } 5947 5948 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5949 } 5950 5951 /* 5952 * ql_setup_led 5953 * Setup LED for driver control 5954 * 5955 * Input: 5956 * ha: adapter state pointer. 5957 * 5958 * Context: 5959 * Kernel/Interrupt context. 5960 */ 5961 static uint32_t 5962 ql_setup_led(ql_adapter_state_t *ha) 5963 { 5964 uint32_t rval; 5965 ql_mbx_data_t mr; 5966 5967 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 5968 5969 /* decouple the LED control from the fw */ 5970 rval = ql_get_firmware_option(ha, &mr); 5971 if (rval != QL_SUCCESS) { 5972 EL(ha, "failed, get_firmware_option=%xh\n", rval); 5973 return (rval); 5974 } 5975 5976 /* set the appropriate options */ 5977 mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_GPIO); 5978 5979 /* send it back to the firmware */ 5980 rval = ql_set_firmware_option(ha, &mr); 5981 if (rval != QL_SUCCESS) { 5982 EL(ha, "failed, set_firmware_option=%xh\n", rval); 5983 return (rval); 5984 } 5985 5986 /* initally, turn the LED's off */ 5987 ql_drive_led(ha, LED_ALL_OFF); 5988 5989 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 5990 5991 return (rval); 5992 } 5993 5994 /* 5995 * ql_wrapup_led 5996 * Return LED control to the firmware 5997 * 5998 * Input: 5999 * ha: adapter state pointer. 6000 * 6001 * Context: 6002 * Kernel/Interrupt context. 6003 */ 6004 static uint32_t 6005 ql_wrapup_led(ql_adapter_state_t *ha) 6006 { 6007 uint32_t rval; 6008 ql_mbx_data_t mr; 6009 6010 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 6011 6012 /* Turn all LED's off */ 6013 ql_drive_led(ha, LED_ALL_OFF); 6014 6015 if (CFG_IST(ha, CFG_CTRL_242581)) { 6016 6017 uint32_t gpio_data; 6018 6019 /* disable the LED update mask */ 6020 gpio_data = RD32_IO_REG(ha, gpiod); 6021 gpio_data &= ~LED_MASK_UPDATE_24; 6022 6023 /* write out the data */ 6024 WRT32_IO_REG(ha, gpiod, gpio_data); 6025 } 6026 6027 /* give LED control back to the f/w */ 6028 rval = ql_get_firmware_option(ha, &mr); 6029 if (rval != QL_SUCCESS) { 6030 EL(ha, "failed, get_firmware_option=%xh\n", rval); 6031 return (rval); 6032 } 6033 6034 mr.mb[1] = (uint16_t)(mr.mb[1] & ~FO1_DISABLE_GPIO); 6035 6036 rval = ql_set_firmware_option(ha, &mr); 6037 if (rval != QL_SUCCESS) { 6038 EL(ha, "failed, set_firmware_option=%xh\n", rval); 6039 return (rval); 6040 } 6041 6042 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 6043 6044 return (rval); 6045 } 6046 6047 /* 6048 * ql_get_port_summary 6049 * Performs EXT_SC_GET_PORT_SUMMARY subcommand. of EXT_CC_GET_DATA. 6050 * 6051 * The EXT_IOCTL->RequestAdr points to a single 6052 * UINT32 which identifies the device type. 6053 * 6054 * Input: 6055 * ha: adapter state pointer. 6056 * cmd: Local EXT_IOCTL cmd struct pointer. 6057 * mode: flags. 6058 * 6059 * Returns: 6060 * None, request status indicated in cmd->Status. 6061 * 6062 * Context: 6063 * Kernel context. 6064 */ 6065 static void 6066 ql_get_port_summary(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 6067 { 6068 EXT_DEVICEDATA dd = {0}; 6069 EXT_DEVICEDATA *uddp; 6070 ql_link_t *link; 6071 ql_tgt_t *tq; 6072 uint32_t rlen, dev_type, index; 6073 int rval = 0; 6074 EXT_DEVICEDATAENTRY *uddep, *ddep; 6075 6076 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 6077 6078 ddep = &dd.EntryList[0]; 6079 6080 /* 6081 * Get the type of device the requestor is looking for. 6082 * 6083 * We ignore this for now. 6084 */ 6085 rval = ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, 6086 (void *)&dev_type, sizeof (dev_type), mode); 6087 if (rval != 0) { 6088 cmd->Status = EXT_STATUS_COPY_ERR; 6089 cmd->ResponseLen = 0; 6090 EL(ha, "failed, ddi_copyin\n"); 6091 return; 6092 } 6093 /* 6094 * Count the number of entries to be returned. Count devices 6095 * that are offlline, but have been persistently bound. 6096 */ 6097 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) { 6098 for (link = ha->dev[index].first; link != NULL; 6099 link = link->next) { 6100 tq = link->base_address; 6101 if (tq->flags & TQF_INITIATOR_DEVICE || 6102 !VALID_TARGET_ID(ha, tq->loop_id)) { 6103 continue; /* Skip this one */ 6104 } 6105 dd.TotalDevices++; 6106 } 6107 } 6108 /* 6109 * Compute the number of entries that can be returned 6110 * based upon the size of caller's response buffer. 6111 */ 6112 dd.ReturnListEntryCount = 0; 6113 if (dd.TotalDevices == 0) { 6114 rlen = sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY); 6115 } else { 6116 rlen = (uint32_t)(sizeof (EXT_DEVICEDATA) + 6117 (sizeof (EXT_DEVICEDATAENTRY) * (dd.TotalDevices - 1))); 6118 } 6119 if (rlen > cmd->ResponseLen) { 6120 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 6121 cmd->DetailStatus = rlen; 6122 EL(ha, "failed, rlen > ResponseLen, rlen=%d, Len=%d\n", 6123 rlen, cmd->ResponseLen); 6124 cmd->ResponseLen = 0; 6125 return; 6126 } 6127 cmd->ResponseLen = 0; 6128 uddp = (EXT_DEVICEDATA *)(uintptr_t)cmd->ResponseAdr; 6129 uddep = &uddp->EntryList[0]; 6130 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) { 6131 for (link = ha->dev[index].first; link != NULL; 6132 link = link->next) { 6133 tq = link->base_address; 6134 if (tq->flags & TQF_INITIATOR_DEVICE || 6135 !VALID_TARGET_ID(ha, tq->loop_id)) { 6136 continue; /* Skip this one */ 6137 } 6138 6139 bzero((void *)ddep, sizeof (EXT_DEVICEDATAENTRY)); 6140 6141 bcopy(tq->node_name, ddep->NodeWWN, 8); 6142 bcopy(tq->port_name, ddep->PortWWN, 8); 6143 6144 ddep->PortID[0] = tq->d_id.b.domain; 6145 ddep->PortID[1] = tq->d_id.b.area; 6146 ddep->PortID[2] = tq->d_id.b.al_pa; 6147 6148 bcopy(tq->port_name, 6149 (caddr_t)&ddep->TargetAddress.Target, 8); 6150 6151 ddep->DeviceFlags = tq->flags; 6152 ddep->LoopID = tq->loop_id; 6153 QL_PRINT_9(CE_CONT, "(%d): Tgt=%lld, loop=%xh, " 6154 "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x, " 6155 "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n", 6156 ha->instance, ddep->TargetAddress.Target, 6157 ddep->LoopID, ddep->NodeWWN[0], ddep->NodeWWN[1], 6158 ddep->NodeWWN[2], ddep->NodeWWN[3], 6159 ddep->NodeWWN[4], ddep->NodeWWN[5], 6160 ddep->NodeWWN[6], ddep->NodeWWN[7], 6161 ddep->PortWWN[0], ddep->PortWWN[1], 6162 ddep->PortWWN[2], ddep->PortWWN[3], 6163 ddep->PortWWN[4], ddep->PortWWN[5], 6164 ddep->PortWWN[6], ddep->PortWWN[7]); 6165 rval = ddi_copyout((void *)ddep, (void *)uddep, 6166 sizeof (EXT_DEVICEDATAENTRY), mode); 6167 6168 if (rval != 0) { 6169 cmd->Status = EXT_STATUS_COPY_ERR; 6170 cmd->ResponseLen = 0; 6171 EL(ha, "failed, ddi_copyout\n"); 6172 break; 6173 } 6174 dd.ReturnListEntryCount++; 6175 uddep++; 6176 cmd->ResponseLen += (uint32_t) 6177 sizeof (EXT_DEVICEDATAENTRY); 6178 } 6179 } 6180 rval = ddi_copyout((void *)&dd, (void *)uddp, 6181 sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY), mode); 6182 6183 if (rval != 0) { 6184 cmd->Status = EXT_STATUS_COPY_ERR; 6185 cmd->ResponseLen = 0; 6186 EL(ha, "failed, ddi_copyout-2\n"); 6187 } else { 6188 cmd->ResponseLen += (uint32_t)sizeof (EXT_DEVICEDATAENTRY); 6189 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 6190 } 6191 } 6192 6193 /* 6194 * ql_get_target_id 6195 * Performs EXT_SC_GET_TARGET_ID subcommand. of EXT_CC_GET_DATA. 6196 * 6197 * Input: 6198 * ha: adapter state pointer. 6199 * cmd: Local EXT_IOCTL cmd struct pointer. 6200 * mode: flags. 6201 * 6202 * Returns: 6203 * None, request status indicated in cmd->Status. 6204 * 6205 * Context: 6206 * Kernel context. 6207 */ 6208 static void 6209 ql_get_target_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 6210 { 6211 uint32_t rval; 6212 uint16_t qlnt; 6213 EXT_DEST_ADDR extdestaddr = {0}; 6214 uint8_t *name; 6215 uint8_t wwpn[EXT_DEF_WWN_NAME_SIZE]; 6216 ql_tgt_t *tq; 6217 6218 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 6219 6220 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, 6221 (void*)wwpn, sizeof (EXT_DEST_ADDR), mode) != 0) { 6222 EL(ha, "failed, ddi_copyin\n"); 6223 cmd->Status = EXT_STATUS_COPY_ERR; 6224 cmd->ResponseLen = 0; 6225 return; 6226 } 6227 6228 qlnt = QLNT_PORT; 6229 name = wwpn; 6230 QL_PRINT_9(CE_CONT, "(%d): wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n", 6231 ha->instance, name[0], name[1], name[2], name[3], name[4], 6232 name[5], name[6], name[7]); 6233 6234 tq = ql_find_port(ha, name, qlnt); 6235 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) { 6236 EL(ha, "failed, fc_port not found\n"); 6237 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 6238 cmd->ResponseLen = 0; 6239 return; 6240 } 6241 6242 bcopy(tq->port_name, (caddr_t)&extdestaddr.DestAddr.ScsiAddr.Target, 8); 6243 6244 rval = ddi_copyout((void *)&extdestaddr, 6245 (void *)(uintptr_t)cmd->ResponseAdr, sizeof (EXT_DEST_ADDR), mode); 6246 if (rval != 0) { 6247 EL(ha, "failed, ddi_copyout\n"); 6248 cmd->Status = EXT_STATUS_COPY_ERR; 6249 cmd->ResponseLen = 0; 6250 } 6251 6252 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 6253 } 6254 6255 /* 6256 * ql_setup_fcache 6257 * Populates selected flash sections into the cache 6258 * 6259 * Input: 6260 * ha = adapter state pointer. 6261 * 6262 * Returns: 6263 * ql local function return status code. 6264 * 6265 * Context: 6266 * Kernel context. 6267 * 6268 * Note: 6269 * Driver must be in stalled state prior to entering or 6270 * add code to this function prior to calling ql_setup_flash() 6271 */ 6272 int 6273 ql_setup_fcache(ql_adapter_state_t *ha) 6274 { 6275 int rval; 6276 uint32_t freadpos = 0; 6277 uint32_t fw_done = 0; 6278 ql_fcache_t *head = NULL; 6279 ql_fcache_t *tail = NULL; 6280 ql_fcache_t *ftmp; 6281 6282 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 6283 6284 CACHE_LOCK(ha); 6285 6286 /* If we already have populated it, rtn */ 6287 if (ha->fcache != NULL) { 6288 CACHE_UNLOCK(ha); 6289 EL(ha, "buffer already populated\n"); 6290 return (QL_SUCCESS); 6291 } 6292 6293 ql_flash_nvram_defaults(ha); 6294 6295 if ((rval = ql_setup_flash(ha)) != QL_SUCCESS) { 6296 CACHE_UNLOCK(ha); 6297 EL(ha, "unable to setup flash; rval=%xh\n", rval); 6298 return (rval); 6299 } 6300 6301 while (freadpos != 0xffffffff) { 6302 6303 /* Allocate & populate this node */ 6304 6305 if ((ftmp = ql_setup_fnode(ha)) == NULL) { 6306 EL(ha, "node alloc failed\n"); 6307 rval = QL_FUNCTION_FAILED; 6308 break; 6309 } 6310 6311 /* link in the new node */ 6312 if (head == NULL) { 6313 head = tail = ftmp; 6314 } else { 6315 tail->next = ftmp; 6316 tail = ftmp; 6317 } 6318 6319 /* Do the firmware node first for 24xx/25xx's */ 6320 if (fw_done == 0) { 6321 if (CFG_IST(ha, CFG_CTRL_242581)) { 6322 freadpos = ha->flash_fw_addr << 2; 6323 } 6324 fw_done = 1; 6325 } 6326 6327 if ((rval = ql_dump_fcode(ha, ftmp->buf, FBUFSIZE, 6328 freadpos)) != QL_SUCCESS) { 6329 EL(ha, "failed, 24xx dump_fcode" 6330 " pos=%xh rval=%xh\n", freadpos, rval); 6331 rval = QL_FUNCTION_FAILED; 6332 break; 6333 } 6334 6335 /* checkout the pci data / format */ 6336 if (ql_check_pci(ha, ftmp, &freadpos)) { 6337 EL(ha, "flash header incorrect\n"); 6338 rval = QL_FUNCTION_FAILED; 6339 break; 6340 } 6341 } 6342 6343 if (rval != QL_SUCCESS) { 6344 /* release all resources we have */ 6345 ftmp = head; 6346 while (ftmp != NULL) { 6347 tail = ftmp->next; 6348 kmem_free(ftmp->buf, FBUFSIZE); 6349 kmem_free(ftmp, sizeof (ql_fcache_t)); 6350 ftmp = tail; 6351 } 6352 6353 EL(ha, "failed, done\n"); 6354 } else { 6355 ha->fcache = head; 6356 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 6357 } 6358 CACHE_UNLOCK(ha); 6359 6360 return (rval); 6361 } 6362 6363 /* 6364 * ql_update_fcache 6365 * re-populates updated flash into the fcache. If 6366 * fcache does not exist (e.g., flash was empty/invalid on 6367 * boot), this routine will create and the populate it. 6368 * 6369 * Input: 6370 * ha = adapter state pointer. 6371 * *bpf = Pointer to flash buffer. 6372 * bsize = Size of flash buffer. 6373 * 6374 * Returns: 6375 * 6376 * Context: 6377 * Kernel context. 6378 */ 6379 void 6380 ql_update_fcache(ql_adapter_state_t *ha, uint8_t *bfp, uint32_t bsize) 6381 { 6382 int rval = QL_SUCCESS; 6383 uint32_t freadpos = 0; 6384 uint32_t fw_done = 0; 6385 ql_fcache_t *head = NULL; 6386 ql_fcache_t *tail = NULL; 6387 ql_fcache_t *ftmp; 6388 6389 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 6390 6391 while (freadpos != 0xffffffff) { 6392 6393 /* Allocate & populate this node */ 6394 6395 if ((ftmp = ql_setup_fnode(ha)) == NULL) { 6396 EL(ha, "node alloc failed\n"); 6397 rval = QL_FUNCTION_FAILED; 6398 break; 6399 } 6400 6401 /* link in the new node */ 6402 if (head == NULL) { 6403 head = tail = ftmp; 6404 } else { 6405 tail->next = ftmp; 6406 tail = ftmp; 6407 } 6408 6409 /* Do the firmware node first for 24xx's */ 6410 if (fw_done == 0) { 6411 if (CFG_IST(ha, CFG_CTRL_242581)) { 6412 freadpos = ha->flash_fw_addr << 2; 6413 } 6414 fw_done = 1; 6415 } 6416 6417 /* read in first FBUFSIZE bytes of this flash section */ 6418 if (freadpos+FBUFSIZE > bsize) { 6419 EL(ha, "passed buffer too small; fr=%xh, bsize=%xh\n", 6420 freadpos, bsize); 6421 rval = QL_FUNCTION_FAILED; 6422 break; 6423 } 6424 bcopy(bfp+freadpos, ftmp->buf, FBUFSIZE); 6425 6426 /* checkout the pci data / format */ 6427 if (ql_check_pci(ha, ftmp, &freadpos)) { 6428 EL(ha, "flash header incorrect\n"); 6429 rval = QL_FUNCTION_FAILED; 6430 break; 6431 } 6432 } 6433 6434 if (rval != QL_SUCCESS) { 6435 /* 6436 * release all resources we have 6437 */ 6438 ql_fcache_rel(head); 6439 EL(ha, "failed, done\n"); 6440 } else { 6441 /* 6442 * Release previous fcache resources and update with new 6443 */ 6444 CACHE_LOCK(ha); 6445 ql_fcache_rel(ha->fcache); 6446 ha->fcache = head; 6447 CACHE_UNLOCK(ha); 6448 6449 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 6450 } 6451 } 6452 6453 /* 6454 * ql_setup_fnode 6455 * Allocates fcache node 6456 * 6457 * Input: 6458 * ha = adapter state pointer. 6459 * node = point to allocated fcache node (NULL = failed) 6460 * 6461 * Returns: 6462 * 6463 * Context: 6464 * Kernel context. 6465 * 6466 * Note: 6467 * Driver must be in stalled state prior to entering or 6468 * add code to this function prior to calling ql_setup_flash() 6469 */ 6470 static ql_fcache_t * 6471 ql_setup_fnode(ql_adapter_state_t *ha) 6472 { 6473 ql_fcache_t *fnode = NULL; 6474 6475 if ((fnode = (ql_fcache_t *)(kmem_zalloc(sizeof (ql_fcache_t), 6476 KM_SLEEP))) == NULL) { 6477 EL(ha, "fnode alloc failed\n"); 6478 fnode = NULL; 6479 } else if ((fnode->buf = (uint8_t *)(kmem_zalloc(FBUFSIZE, 6480 KM_SLEEP))) == NULL) { 6481 EL(ha, "buf alloc failed\n"); 6482 kmem_free(fnode, sizeof (ql_fcache_t)); 6483 fnode = NULL; 6484 } else { 6485 fnode->buflen = FBUFSIZE; 6486 } 6487 6488 return (fnode); 6489 } 6490 6491 /* 6492 * ql_fcache_rel 6493 * Releases the fcache resources 6494 * 6495 * Input: 6496 * ha = adapter state pointer. 6497 * head = Pointer to fcache linked list 6498 * 6499 * Returns: 6500 * 6501 * Context: 6502 * Kernel context. 6503 * 6504 */ 6505 void 6506 ql_fcache_rel(ql_fcache_t *head) 6507 { 6508 ql_fcache_t *ftmp = head; 6509 ql_fcache_t *tail; 6510 6511 /* release all resources we have */ 6512 while (ftmp != NULL) { 6513 tail = ftmp->next; 6514 kmem_free(ftmp->buf, FBUFSIZE); 6515 kmem_free(ftmp, sizeof (ql_fcache_t)); 6516 ftmp = tail; 6517 } 6518 } 6519 6520 /* 6521 * ql_update_flash_caches 6522 * Updates driver flash caches 6523 * 6524 * Input: 6525 * ha: adapter state pointer. 6526 * 6527 * Context: 6528 * Kernel context. 6529 */ 6530 static void 6531 ql_update_flash_caches(ql_adapter_state_t *ha) 6532 { 6533 uint32_t len; 6534 ql_link_t *link; 6535 ql_adapter_state_t *ha2; 6536 6537 QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance); 6538 6539 /* Get base path length. */ 6540 for (len = (uint32_t)strlen(ha->devpath); len; len--) { 6541 if (ha->devpath[len] == ',' || 6542 ha->devpath[len] == '@') { 6543 break; 6544 } 6545 } 6546 6547 /* Reset fcache on all adapter instances. */ 6548 for (link = ql_hba.first; link != NULL; link = link->next) { 6549 ha2 = link->base_address; 6550 6551 if (strncmp(ha->devpath, ha2->devpath, len) != 0) { 6552 continue; 6553 } 6554 6555 CACHE_LOCK(ha2); 6556 ql_fcache_rel(ha2->fcache); 6557 ha2->fcache = NULL; 6558 6559 if (CFG_IST(ha, CFG_CTRL_242581)) { 6560 if (ha2->vcache != NULL) { 6561 kmem_free(ha2->vcache, QL_24XX_VPD_SIZE); 6562 ha2->vcache = NULL; 6563 } 6564 } 6565 CACHE_UNLOCK(ha2); 6566 6567 (void) ql_setup_fcache(ha2); 6568 } 6569 6570 QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance); 6571 } 6572 6573 /* 6574 * ql_get_fbuf 6575 * Search the fcache list for the type specified 6576 * 6577 * Input: 6578 * fptr = Pointer to fcache linked list 6579 * ftype = Type of image to be returned. 6580 * 6581 * Returns: 6582 * Pointer to ql_fcache_t. 6583 * NULL means not found. 6584 * 6585 * Context: 6586 * Kernel context. 6587 * 6588 * 6589 */ 6590 ql_fcache_t * 6591 ql_get_fbuf(ql_fcache_t *fptr, uint32_t ftype) 6592 { 6593 while (fptr != NULL) { 6594 /* does this image meet criteria? */ 6595 if (ftype & fptr->type) { 6596 break; 6597 } 6598 fptr = fptr->next; 6599 } 6600 return (fptr); 6601 } 6602 6603 /* 6604 * ql_check_pci 6605 * 6606 * checks the passed buffer for a valid pci signature and 6607 * expected (and in range) pci length values. 6608 * 6609 * For firmware type, a pci header is added since the image in 6610 * the flash does not have one (!!!). 6611 * 6612 * On successful pci check, nextpos adjusted to next pci header. 6613 * 6614 * Returns: 6615 * -1 --> last pci image 6616 * 0 --> pci header valid 6617 * 1 --> pci header invalid. 6618 * 6619 * Context: 6620 * Kernel context. 6621 */ 6622 static int 6623 ql_check_pci(ql_adapter_state_t *ha, ql_fcache_t *fcache, uint32_t *nextpos) 6624 { 6625 pci_header_t *pcih; 6626 pci_data_t *pcid; 6627 uint32_t doff; 6628 uint8_t *pciinfo; 6629 6630 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 6631 6632 if (fcache != NULL) { 6633 pciinfo = fcache->buf; 6634 } else { 6635 EL(ha, "failed, null fcache ptr passed\n"); 6636 return (1); 6637 } 6638 6639 if (pciinfo == NULL) { 6640 EL(ha, "failed, null pciinfo ptr passed\n"); 6641 return (1); 6642 } 6643 6644 if (CFG_IST(ha, CFG_SBUS_CARD)) { 6645 caddr_t bufp; 6646 uint_t len; 6647 6648 if (pciinfo[0] != SBUS_CODE_FCODE) { 6649 EL(ha, "failed, unable to detect sbus fcode\n"); 6650 return (1); 6651 } 6652 fcache->type = FTYPE_FCODE; 6653 6654 /*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/ 6655 if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip, 6656 PROP_LEN_AND_VAL_ALLOC | DDI_PROP_DONTPASS | 6657 DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp, 6658 (int *)&len) == DDI_PROP_SUCCESS) { 6659 6660 (void) snprintf(fcache->verstr, 6661 FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp); 6662 kmem_free(bufp, len); 6663 } 6664 6665 *nextpos = 0xffffffff; 6666 6667 QL_PRINT_9(CE_CONT, "(%d): CFG_SBUS_CARD, done\n", 6668 ha->instance); 6669 6670 return (0); 6671 } 6672 6673 if (*nextpos == ha->flash_fw_addr << 2) { 6674 6675 pci_header_t fwh = {0}; 6676 pci_data_t fwd = {0}; 6677 uint8_t *buf, *bufp; 6678 6679 /* 6680 * Build a pci header for the firmware module 6681 */ 6682 if ((buf = (uint8_t *)(kmem_zalloc(FBUFSIZE, KM_SLEEP))) == 6683 NULL) { 6684 EL(ha, "failed, unable to allocate buffer\n"); 6685 return (1); 6686 } 6687 6688 fwh.signature[0] = PCI_HEADER0; 6689 fwh.signature[1] = PCI_HEADER1; 6690 fwh.dataoffset[0] = LSB(sizeof (pci_header_t)); 6691 fwh.dataoffset[1] = MSB(sizeof (pci_header_t)); 6692 6693 fwd.signature[0] = 'P'; 6694 fwd.signature[1] = 'C'; 6695 fwd.signature[2] = 'I'; 6696 fwd.signature[3] = 'R'; 6697 fwd.codetype = PCI_CODE_FW; 6698 fwd.pcidatalen[0] = LSB(sizeof (pci_data_t)); 6699 fwd.pcidatalen[1] = MSB(sizeof (pci_data_t)); 6700 6701 bufp = buf; 6702 bcopy(&fwh, bufp, sizeof (pci_header_t)); 6703 bufp += sizeof (pci_header_t); 6704 bcopy(&fwd, bufp, sizeof (pci_data_t)); 6705 bufp += sizeof (pci_data_t); 6706 6707 bcopy(fcache->buf, bufp, (FBUFSIZE - sizeof (pci_header_t) - 6708 sizeof (pci_data_t))); 6709 bcopy(buf, fcache->buf, FBUFSIZE); 6710 6711 fcache->type = FTYPE_FW; 6712 6713 (void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN, 6714 "%d.%02d.%02d", fcache->buf[19], fcache->buf[23], 6715 fcache->buf[27]); 6716 6717 *nextpos = CFG_IST(ha, CFG_CTRL_81XX) ? 0x200000 : 0; 6718 kmem_free(buf, FBUFSIZE); 6719 6720 QL_PRINT_9(CE_CONT, "(%d): FTYPE_FW, done\n", ha->instance); 6721 6722 return (0); 6723 } 6724 6725 /* get to the pci header image length */ 6726 pcih = (pci_header_t *)pciinfo; 6727 6728 doff = pcih->dataoffset[0] | (pcih->dataoffset[1] << 8); 6729 6730 /* some header section sanity check */ 6731 if (pcih->signature[0] != PCI_HEADER0 || 6732 pcih->signature[1] != PCI_HEADER1 || doff > 50) { 6733 EL(ha, "buffer format error: s0=%xh, s1=%xh, off=%xh\n", 6734 pcih->signature[0], pcih->signature[1], doff); 6735 return (1); 6736 } 6737 6738 pcid = (pci_data_t *)(pciinfo + doff); 6739 6740 /* a slight sanity data section check */ 6741 if (pcid->signature[0] != 'P' || pcid->signature[1] != 'C' || 6742 pcid->signature[2] != 'I' || pcid->signature[3] != 'R') { 6743 EL(ha, "failed, data sig mismatch!\n"); 6744 return (1); 6745 } 6746 6747 if (pcid->indicator == PCI_IND_LAST_IMAGE) { 6748 EL(ha, "last image\n"); 6749 if (CFG_IST(ha, CFG_CTRL_242581)) { 6750 ql_flash_layout_table(ha, *nextpos + 6751 (pcid->imagelength[0] | (pcid->imagelength[1] << 6752 8)) * PCI_SECTOR_SIZE); 6753 ql_24xx_flash_desc(ha); 6754 } 6755 *nextpos = 0xffffffff; 6756 } else { 6757 /* adjust the next flash read start position */ 6758 *nextpos += (pcid->imagelength[0] | 6759 (pcid->imagelength[1] << 8)) * PCI_SECTOR_SIZE; 6760 } 6761 6762 switch (pcid->codetype) { 6763 case PCI_CODE_X86PC: 6764 fcache->type = FTYPE_BIOS; 6765 break; 6766 case PCI_CODE_FCODE: 6767 fcache->type = FTYPE_FCODE; 6768 break; 6769 case PCI_CODE_EFI: 6770 fcache->type = FTYPE_EFI; 6771 break; 6772 case PCI_CODE_HPPA: 6773 fcache->type = FTYPE_HPPA; 6774 break; 6775 default: 6776 fcache->type = FTYPE_UNKNOWN; 6777 break; 6778 } 6779 6780 (void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN, 6781 "%d.%d", pcid->revisionlevel[1], pcid->revisionlevel[0]); 6782 6783 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 6784 6785 return (0); 6786 } 6787 6788 /* 6789 * ql_flash_layout_table 6790 * Obtains flash addresses from table 6791 * 6792 * Input: 6793 * ha: adapter state pointer. 6794 * flt_paddr: flash layout pointer address. 6795 * 6796 * Context: 6797 * Kernel context. 6798 */ 6799 static void 6800 ql_flash_layout_table(ql_adapter_state_t *ha, uint32_t flt_paddr) 6801 { 6802 ql_flt_ptr_t *fptr; 6803 ql_flt_hdr_t *fhdr; 6804 ql_flt_region_t *frgn; 6805 uint8_t *bp; 6806 int rval; 6807 uint32_t len, faddr, cnt; 6808 uint16_t chksum, w16; 6809 6810 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 6811 6812 /* Process flash layout table header */ 6813 if ((bp = kmem_zalloc(FLASH_LAYOUT_TABLE_SIZE, KM_SLEEP)) == NULL) { 6814 EL(ha, "kmem_zalloc=null\n"); 6815 return; 6816 } 6817 6818 /* Process pointer to flash layout table */ 6819 if ((rval = ql_dump_fcode(ha, bp, sizeof (ql_flt_ptr_t), flt_paddr)) != 6820 QL_SUCCESS) { 6821 EL(ha, "fptr dump_flash pos=%xh, status=%xh\n", flt_paddr, 6822 rval); 6823 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE); 6824 return; 6825 } 6826 fptr = (ql_flt_ptr_t *)bp; 6827 6828 /* Verify pointer to flash layout table. */ 6829 for (chksum = 0, cnt = 0; cnt < sizeof (ql_flt_ptr_t); cnt += 2) { 6830 w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]); 6831 chksum += w16; 6832 } 6833 if (chksum != 0 || fptr->sig[0] != 'Q' || fptr->sig[1] != 'F' || 6834 fptr->sig[2] != 'L' || fptr->sig[3] != 'T') { 6835 EL(ha, "ptr chksum=%xh, sig=%c%c%c%c\n", chksum, fptr->sig[0], 6836 fptr->sig[1], fptr->sig[2], fptr->sig[3]); 6837 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE); 6838 return; 6839 } 6840 faddr = CHAR_TO_LONG(fptr->addr[0], fptr->addr[1], fptr->addr[2], 6841 fptr->addr[3]); 6842 6843 /* Process flash layout table. */ 6844 if ((rval = ql_dump_fcode(ha, bp, FLASH_LAYOUT_TABLE_SIZE, faddr)) != 6845 QL_SUCCESS) { 6846 EL(ha, "fhdr dump_flash pos=%xh, status=%xh\n", faddr, rval); 6847 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE); 6848 return; 6849 } 6850 fhdr = (ql_flt_hdr_t *)bp; 6851 6852 /* Verify flash layout table. */ 6853 len = (uint16_t)(CHAR_TO_SHORT(fhdr->len[0], fhdr->len[1]) + 6854 sizeof (ql_flt_hdr_t)); 6855 if (len > FLASH_LAYOUT_TABLE_SIZE) { 6856 chksum = 0xffff; 6857 } else { 6858 for (chksum = 0, cnt = 0; cnt < len; cnt += 2) { 6859 w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]); 6860 chksum += w16; 6861 } 6862 } 6863 w16 = CHAR_TO_SHORT(fhdr->version[0], fhdr->version[1]); 6864 if (chksum != 0 || w16 != 1) { 6865 EL(ha, "table chksum=%xh, version=%d\n", chksum, w16); 6866 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE); 6867 return; 6868 } 6869 6870 /* Process flash layout table regions */ 6871 for (frgn = (ql_flt_region_t *)(bp + sizeof (ql_flt_hdr_t)); 6872 (caddr_t)frgn < (caddr_t)(bp + FLASH_LAYOUT_TABLE_SIZE); frgn++) { 6873 faddr = CHAR_TO_LONG(frgn->beg_addr[0], frgn->beg_addr[1], 6874 frgn->beg_addr[2], frgn->beg_addr[3]); 6875 faddr >>= 2; 6876 6877 switch (frgn->region) { 6878 case FLASH_FW_REGION: 6879 ha->flash_fw_addr = faddr; 6880 QL_PRINT_9(CE_CONT, "(%d): flash_fw_addr=%xh\n", 6881 ha->instance, faddr); 6882 break; 6883 case FLASH_GOLDEN_FW_REGION: 6884 ha->flash_golden_fw_addr = faddr; 6885 QL_PRINT_9(CE_CONT, "(%d): flash_golden_fw_addr=%xh\n", 6886 ha->instance, faddr); 6887 break; 6888 case FLASH_VPD_0_REGION: 6889 if (!(ha->flags & FUNCTION_1)) { 6890 ha->flash_vpd_addr = faddr; 6891 QL_PRINT_9(CE_CONT, "(%d): flash_vpd_addr=%xh" 6892 "\n", ha->instance, faddr); 6893 } 6894 break; 6895 case FLASH_NVRAM_0_REGION: 6896 if (!(ha->flags & FUNCTION_1)) { 6897 ha->flash_nvram_addr = faddr; 6898 QL_PRINT_9(CE_CONT, "(%d): flash_nvram_addr=" 6899 "%xh\n", ha->instance, faddr); 6900 } 6901 break; 6902 case FLASH_VPD_1_REGION: 6903 if (ha->flags & FUNCTION_1) { 6904 ha->flash_vpd_addr = faddr; 6905 QL_PRINT_9(CE_CONT, "(%d): flash_vpd_addr=%xh" 6906 "\n", ha->instance, faddr); 6907 } 6908 break; 6909 case FLASH_NVRAM_1_REGION: 6910 if (ha->flags & FUNCTION_1) { 6911 ha->flash_nvram_addr = faddr; 6912 QL_PRINT_9(CE_CONT, "(%d): flash_nvram_addr=" 6913 "%xh\n", ha->instance, faddr); 6914 } 6915 break; 6916 case FLASH_DESC_TABLE_REGION: 6917 ha->flash_desc_addr = faddr; 6918 QL_PRINT_9(CE_CONT, "(%d): flash_desc_addr=%xh\n", 6919 ha->instance, faddr); 6920 break; 6921 case FLASH_ERROR_LOG_0_REGION: 6922 if (!(ha->flags & FUNCTION_1)) { 6923 ha->flash_errlog_start = faddr; 6924 QL_PRINT_9(CE_CONT, "(%d): flash_errlog_addr=" 6925 "%xh\n", ha->instance, faddr); 6926 } 6927 break; 6928 case FLASH_ERROR_LOG_1_REGION: 6929 if (ha->flags & FUNCTION_1) { 6930 ha->flash_errlog_start = faddr; 6931 QL_PRINT_9(CE_CONT, "(%d): flash_errlog_addr=" 6932 "%xh\n", ha->instance, faddr); 6933 } 6934 break; 6935 default: 6936 break; 6937 } 6938 } 6939 kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE); 6940 6941 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 6942 } 6943 6944 /* 6945 * ql_flash_nvram_defaults 6946 * Flash default addresses. 6947 * 6948 * Input: 6949 * ha: adapter state pointer. 6950 * 6951 * Returns: 6952 * ql local function return status code. 6953 * 6954 * Context: 6955 * Kernel context. 6956 */ 6957 static void 6958 ql_flash_nvram_defaults(ql_adapter_state_t *ha) 6959 { 6960 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 6961 6962 if (ha->flags & FUNCTION_1) { 6963 if (CFG_IST(ha, CFG_CTRL_2300)) { 6964 ha->flash_nvram_addr = NVRAM_2300_FUNC1_ADDR; 6965 ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR; 6966 } else if (CFG_IST(ha, CFG_CTRL_2422)) { 6967 ha->flash_data_addr = FLASH_24_25_DATA_ADDR; 6968 ha->flash_nvram_addr = NVRAM_2400_FUNC1_ADDR; 6969 ha->flash_vpd_addr = VPD_2400_FUNC1_ADDR; 6970 ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_1; 6971 ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE; 6972 ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR; 6973 } else if (CFG_IST(ha, CFG_CTRL_25XX)) { 6974 ha->flash_data_addr = FLASH_24_25_DATA_ADDR; 6975 ha->flash_nvram_addr = NVRAM_2500_FUNC1_ADDR; 6976 ha->flash_vpd_addr = VPD_2500_FUNC1_ADDR; 6977 ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_1; 6978 ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE; 6979 ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR; 6980 } else if (CFG_IST(ha, CFG_CTRL_81XX)) { 6981 ha->flash_data_addr = FLASH_8100_DATA_ADDR; 6982 ha->flash_nvram_addr = NVRAM_8100_FUNC1_ADDR; 6983 ha->flash_vpd_addr = VPD_8100_FUNC1_ADDR; 6984 ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_1; 6985 ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE; 6986 ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR; 6987 } 6988 } else { 6989 if (CFG_IST(ha, CFG_CTRL_2200)) { 6990 ha->flash_nvram_addr = NVRAM_2200_FUNC0_ADDR; 6991 ha->flash_fw_addr = FLASH_2200_FIRMWARE_ADDR; 6992 } else if (CFG_IST(ha, CFG_CTRL_2300)) { 6993 ha->flash_nvram_addr = NVRAM_2300_FUNC0_ADDR; 6994 ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR; 6995 } else if (CFG_IST(ha, CFG_CTRL_2422)) { 6996 ha->flash_data_addr = FLASH_24_25_DATA_ADDR; 6997 ha->flash_nvram_addr = NVRAM_2400_FUNC0_ADDR; 6998 ha->flash_vpd_addr = VPD_2400_FUNC0_ADDR; 6999 ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_0; 7000 ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE; 7001 ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR; 7002 } else if (CFG_IST(ha, CFG_CTRL_25XX)) { 7003 ha->flash_data_addr = FLASH_24_25_DATA_ADDR; 7004 ha->flash_nvram_addr = NVRAM_2500_FUNC0_ADDR; 7005 ha->flash_vpd_addr = VPD_2500_FUNC0_ADDR; 7006 ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_0; 7007 ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE; 7008 ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR; 7009 } else if (CFG_IST(ha, CFG_CTRL_81XX)) { 7010 ha->flash_data_addr = FLASH_8100_DATA_ADDR; 7011 ha->flash_nvram_addr = NVRAM_8100_FUNC0_ADDR; 7012 ha->flash_vpd_addr = VPD_8100_FUNC0_ADDR; 7013 ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_0; 7014 ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE; 7015 ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR; 7016 } 7017 } 7018 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7019 } 7020 7021 /* 7022 * ql_get_sfp 7023 * Returns sfp data to sdmapi caller 7024 * 7025 * Input: 7026 * ha: adapter state pointer. 7027 * cmd: Local EXT_IOCTL cmd struct pointer. 7028 * mode: flags. 7029 * 7030 * Returns: 7031 * None, request status indicated in cmd->Status. 7032 * 7033 * Context: 7034 * Kernel context. 7035 */ 7036 static void 7037 ql_get_sfp(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7038 { 7039 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7040 7041 if ((CFG_IST(ha, CFG_CTRL_242581)) == 0) { 7042 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7043 EL(ha, "failed, invalid request for HBA\n"); 7044 return; 7045 } 7046 7047 if (cmd->ResponseLen < QL_24XX_SFP_SIZE) { 7048 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 7049 cmd->DetailStatus = QL_24XX_SFP_SIZE; 7050 EL(ha, "failed, ResponseLen < SFP len, len passed=%xh\n", 7051 cmd->ResponseLen); 7052 return; 7053 } 7054 7055 /* Dump SFP data in user buffer */ 7056 if ((ql_dump_sfp(ha, (void *)(uintptr_t)(cmd->ResponseAdr), 7057 mode)) != 0) { 7058 cmd->Status = EXT_STATUS_COPY_ERR; 7059 EL(ha, "failed, copy error\n"); 7060 } else { 7061 cmd->Status = EXT_STATUS_OK; 7062 } 7063 7064 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7065 } 7066 7067 /* 7068 * ql_dump_sfp 7069 * Dumps SFP. 7070 * 7071 * Input: 7072 * ha: adapter state pointer. 7073 * bp: buffer address. 7074 * mode: flags 7075 * 7076 * Returns: 7077 * 7078 * Context: 7079 * Kernel context. 7080 */ 7081 static int 7082 ql_dump_sfp(ql_adapter_state_t *ha, void *bp, int mode) 7083 { 7084 dma_mem_t mem; 7085 uint32_t cnt; 7086 int rval2, rval = 0; 7087 uint32_t dxfer; 7088 7089 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7090 7091 /* Get memory for SFP. */ 7092 7093 if ((rval2 = ql_get_dma_mem(ha, &mem, 64, LITTLE_ENDIAN_DMA, 7094 QL_DMA_DATA_ALIGN)) != QL_SUCCESS) { 7095 EL(ha, "failed, ql_get_dma_mem=%xh\n", rval2); 7096 return (ENOMEM); 7097 } 7098 7099 for (cnt = 0; cnt < QL_24XX_SFP_SIZE; cnt += mem.size) { 7100 rval2 = ql_read_sfp(ha, &mem, 7101 (uint16_t)(cnt < 256 ? 0xA0 : 0xA2), 7102 (uint16_t)(cnt & 0xff)); 7103 if (rval2 != QL_SUCCESS) { 7104 EL(ha, "failed, read_sfp=%xh\n", rval2); 7105 rval = EFAULT; 7106 break; 7107 } 7108 7109 /* copy the data back */ 7110 if ((dxfer = ql_send_buffer_data(mem.bp, bp, mem.size, 7111 mode)) != mem.size) { 7112 /* ddi copy error */ 7113 EL(ha, "failed, ddi copy; byte cnt = %xh", dxfer); 7114 rval = EFAULT; 7115 break; 7116 } 7117 7118 /* adjust the buffer pointer */ 7119 bp = (caddr_t)bp + mem.size; 7120 } 7121 7122 ql_free_phys(ha, &mem); 7123 7124 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7125 7126 return (rval); 7127 } 7128 7129 /* 7130 * ql_port_param 7131 * Retrieves or sets the firmware port speed settings 7132 * 7133 * Input: 7134 * ha: adapter state pointer. 7135 * cmd: Local EXT_IOCTL cmd struct pointer. 7136 * mode: flags. 7137 * 7138 * Returns: 7139 * None, request status indicated in cmd->Status. 7140 * 7141 * Context: 7142 * Kernel context. 7143 * 7144 */ 7145 static void 7146 ql_port_param(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7147 { 7148 uint8_t *name; 7149 ql_tgt_t *tq; 7150 EXT_PORT_PARAM port_param = {0}; 7151 uint32_t rval = QL_SUCCESS; 7152 uint32_t idma_rate; 7153 7154 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7155 7156 if (CFG_IST(ha, CFG_CTRL_242581) == 0) { 7157 EL(ha, "invalid request for this HBA\n"); 7158 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7159 cmd->ResponseLen = 0; 7160 return; 7161 } 7162 7163 if (LOOP_NOT_READY(ha)) { 7164 EL(ha, "failed, loop not ready\n"); 7165 cmd->Status = EXT_STATUS_DEVICE_OFFLINE; 7166 cmd->ResponseLen = 0; 7167 return; 7168 } 7169 7170 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, 7171 (void*)&port_param, sizeof (EXT_PORT_PARAM), mode) != 0) { 7172 EL(ha, "failed, ddi_copyin\n"); 7173 cmd->Status = EXT_STATUS_COPY_ERR; 7174 cmd->ResponseLen = 0; 7175 return; 7176 } 7177 7178 if (port_param.FCScsiAddr.DestType != EXT_DEF_DESTTYPE_WWPN) { 7179 EL(ha, "Unsupported dest lookup type: %xh\n", 7180 port_param.FCScsiAddr.DestType); 7181 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 7182 cmd->ResponseLen = 0; 7183 return; 7184 } 7185 7186 name = port_param.FCScsiAddr.DestAddr.WWPN; 7187 7188 QL_PRINT_9(CE_CONT, "(%d): wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n", 7189 ha->instance, name[0], name[1], name[2], name[3], name[4], 7190 name[5], name[6], name[7]); 7191 7192 tq = ql_find_port(ha, name, (uint16_t)QLNT_PORT); 7193 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) { 7194 EL(ha, "failed, fc_port not found\n"); 7195 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 7196 cmd->ResponseLen = 0; 7197 return; 7198 } 7199 7200 cmd->Status = EXT_STATUS_OK; 7201 cmd->DetailStatus = EXT_STATUS_OK; 7202 7203 switch (port_param.Mode) { 7204 case EXT_IIDMA_MODE_GET: 7205 /* 7206 * Report the firmware's port rate for the wwpn 7207 */ 7208 rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate, 7209 port_param.Mode); 7210 7211 if (rval != QL_SUCCESS) { 7212 EL(ha, "iidma get failed: %xh\n", rval); 7213 cmd->Status = EXT_STATUS_MAILBOX; 7214 cmd->DetailStatus = rval; 7215 cmd->ResponseLen = 0; 7216 } else { 7217 switch (idma_rate) { 7218 case IIDMA_RATE_1GB: 7219 port_param.Speed = 7220 EXT_DEF_PORTSPEED_1GBIT; 7221 break; 7222 case IIDMA_RATE_2GB: 7223 port_param.Speed = 7224 EXT_DEF_PORTSPEED_2GBIT; 7225 break; 7226 case IIDMA_RATE_4GB: 7227 port_param.Speed = 7228 EXT_DEF_PORTSPEED_4GBIT; 7229 break; 7230 case IIDMA_RATE_8GB: 7231 port_param.Speed = 7232 EXT_DEF_PORTSPEED_8GBIT; 7233 break; 7234 case IIDMA_RATE_10GB: 7235 port_param.Speed = 7236 EXT_DEF_PORTSPEED_10GBIT; 7237 break; 7238 default: 7239 port_param.Speed = 7240 EXT_DEF_PORTSPEED_UNKNOWN; 7241 EL(ha, "failed, Port speed rate=%xh\n", 7242 idma_rate); 7243 break; 7244 } 7245 7246 /* Copy back the data */ 7247 rval = ddi_copyout((void *)&port_param, 7248 (void *)(uintptr_t)cmd->ResponseAdr, 7249 sizeof (EXT_PORT_PARAM), mode); 7250 7251 if (rval != 0) { 7252 cmd->Status = EXT_STATUS_COPY_ERR; 7253 cmd->ResponseLen = 0; 7254 EL(ha, "failed, ddi_copyout\n"); 7255 } else { 7256 cmd->ResponseLen = (uint32_t) 7257 sizeof (EXT_PORT_PARAM); 7258 } 7259 } 7260 break; 7261 7262 case EXT_IIDMA_MODE_SET: 7263 /* 7264 * Set the firmware's port rate for the wwpn 7265 */ 7266 switch (port_param.Speed) { 7267 case EXT_DEF_PORTSPEED_1GBIT: 7268 idma_rate = IIDMA_RATE_1GB; 7269 break; 7270 case EXT_DEF_PORTSPEED_2GBIT: 7271 idma_rate = IIDMA_RATE_2GB; 7272 break; 7273 case EXT_DEF_PORTSPEED_4GBIT: 7274 idma_rate = IIDMA_RATE_4GB; 7275 break; 7276 case EXT_DEF_PORTSPEED_8GBIT: 7277 idma_rate = IIDMA_RATE_8GB; 7278 break; 7279 case EXT_DEF_PORTSPEED_10GBIT: 7280 port_param.Speed = IIDMA_RATE_10GB; 7281 break; 7282 default: 7283 EL(ha, "invalid set iidma rate: %x\n", 7284 port_param.Speed); 7285 cmd->Status = EXT_STATUS_INVALID_PARAM; 7286 cmd->ResponseLen = 0; 7287 rval = QL_PARAMETER_ERROR; 7288 break; 7289 } 7290 7291 if (rval == QL_SUCCESS) { 7292 rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate, 7293 port_param.Mode); 7294 if (rval != QL_SUCCESS) { 7295 EL(ha, "iidma set failed: %xh\n", rval); 7296 cmd->Status = EXT_STATUS_MAILBOX; 7297 cmd->DetailStatus = rval; 7298 cmd->ResponseLen = 0; 7299 } 7300 } 7301 break; 7302 default: 7303 EL(ha, "invalid mode specified: %x\n", port_param.Mode); 7304 cmd->Status = EXT_STATUS_INVALID_PARAM; 7305 cmd->ResponseLen = 0; 7306 cmd->DetailStatus = 0; 7307 break; 7308 } 7309 7310 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7311 } 7312 7313 /* 7314 * ql_get_fwexttrace 7315 * Dumps f/w extended trace buffer 7316 * 7317 * Input: 7318 * ha: adapter state pointer. 7319 * bp: buffer address. 7320 * mode: flags 7321 * 7322 * Returns: 7323 * 7324 * Context: 7325 * Kernel context. 7326 */ 7327 /* ARGSUSED */ 7328 static void 7329 ql_get_fwexttrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7330 { 7331 int rval; 7332 caddr_t payload; 7333 7334 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7335 7336 if (CFG_IST(ha, CFG_CTRL_242581) == 0) { 7337 EL(ha, "invalid request for this HBA\n"); 7338 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7339 cmd->ResponseLen = 0; 7340 return; 7341 } 7342 7343 if ((CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) == 0) || 7344 (ha->fwexttracebuf.bp == NULL)) { 7345 EL(ha, "f/w extended trace is not enabled\n"); 7346 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7347 cmd->ResponseLen = 0; 7348 return; 7349 } 7350 7351 if (cmd->ResponseLen < FWEXTSIZE) { 7352 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 7353 cmd->DetailStatus = FWEXTSIZE; 7354 EL(ha, "failed, ResponseLen (%xh) < %xh (FWEXTSIZE)\n", 7355 cmd->ResponseLen, FWEXTSIZE); 7356 cmd->ResponseLen = 0; 7357 return; 7358 } 7359 7360 /* Time Stamp */ 7361 rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_INSERT_TIME_STAMP); 7362 if (rval != QL_SUCCESS) { 7363 EL(ha, "f/w extended trace insert" 7364 "time stamp failed: %xh\n", rval); 7365 cmd->Status = EXT_STATUS_ERR; 7366 cmd->ResponseLen = 0; 7367 return; 7368 } 7369 7370 /* Disable Tracing */ 7371 rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_EXT_TRACE_DISABLE); 7372 if (rval != QL_SUCCESS) { 7373 EL(ha, "f/w extended trace disable failed: %xh\n", rval); 7374 cmd->Status = EXT_STATUS_ERR; 7375 cmd->ResponseLen = 0; 7376 return; 7377 } 7378 7379 /* Allocate payload buffer */ 7380 payload = kmem_zalloc(FWEXTSIZE, KM_SLEEP); 7381 if (payload == NULL) { 7382 EL(ha, "failed, kmem_zalloc\n"); 7383 cmd->Status = EXT_STATUS_NO_MEMORY; 7384 cmd->ResponseLen = 0; 7385 return; 7386 } 7387 7388 /* Sync DMA buffer. */ 7389 (void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0, 7390 FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL); 7391 7392 /* Copy trace buffer data. */ 7393 ddi_rep_get8(ha->fwexttracebuf.acc_handle, (uint8_t *)payload, 7394 (uint8_t *)ha->fwexttracebuf.bp, FWEXTSIZE, 7395 DDI_DEV_AUTOINCR); 7396 7397 /* Send payload to application. */ 7398 if (ql_send_buffer_data(payload, (caddr_t)(uintptr_t)cmd->ResponseAdr, 7399 cmd->ResponseLen, mode) != cmd->ResponseLen) { 7400 EL(ha, "failed, send_buffer_data\n"); 7401 cmd->Status = EXT_STATUS_COPY_ERR; 7402 cmd->ResponseLen = 0; 7403 } else { 7404 cmd->Status = EXT_STATUS_OK; 7405 } 7406 7407 kmem_free(payload, FWEXTSIZE); 7408 7409 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7410 } 7411 7412 /* 7413 * ql_get_fwfcetrace 7414 * Dumps f/w fibre channel event trace buffer 7415 * 7416 * Input: 7417 * ha: adapter state pointer. 7418 * bp: buffer address. 7419 * mode: flags 7420 * 7421 * Returns: 7422 * 7423 * Context: 7424 * Kernel context. 7425 */ 7426 /* ARGSUSED */ 7427 static void 7428 ql_get_fwfcetrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7429 { 7430 int rval; 7431 caddr_t payload; 7432 7433 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7434 7435 if (CFG_IST(ha, CFG_CTRL_242581) == 0) { 7436 EL(ha, "invalid request for this HBA\n"); 7437 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7438 cmd->ResponseLen = 0; 7439 return; 7440 } 7441 7442 if ((CFG_IST(ha, CFG_ENABLE_FWFCETRACE) == 0) || 7443 (ha->fwfcetracebuf.bp == NULL)) { 7444 EL(ha, "f/w FCE trace is not enabled\n"); 7445 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7446 cmd->ResponseLen = 0; 7447 return; 7448 } 7449 7450 if (cmd->ResponseLen < FWFCESIZE) { 7451 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 7452 cmd->DetailStatus = FWFCESIZE; 7453 EL(ha, "failed, ResponseLen (%xh) < %xh (FWFCESIZE)\n", 7454 cmd->ResponseLen, FWFCESIZE); 7455 cmd->ResponseLen = 0; 7456 return; 7457 } 7458 7459 /* Disable Tracing */ 7460 rval = ql_fw_etrace(ha, &ha->fwfcetracebuf, FTO_FCE_TRACE_DISABLE); 7461 if (rval != QL_SUCCESS) { 7462 EL(ha, "f/w FCE trace disable failed: %xh\n", rval); 7463 cmd->Status = EXT_STATUS_ERR; 7464 cmd->ResponseLen = 0; 7465 return; 7466 } 7467 7468 /* Allocate payload buffer */ 7469 payload = kmem_zalloc(FWEXTSIZE, KM_SLEEP); 7470 if (payload == NULL) { 7471 EL(ha, "failed, kmem_zalloc\n"); 7472 cmd->Status = EXT_STATUS_NO_MEMORY; 7473 cmd->ResponseLen = 0; 7474 return; 7475 } 7476 7477 /* Sync DMA buffer. */ 7478 (void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0, 7479 FWFCESIZE, DDI_DMA_SYNC_FORKERNEL); 7480 7481 /* Copy trace buffer data. */ 7482 ddi_rep_get8(ha->fwfcetracebuf.acc_handle, (uint8_t *)payload, 7483 (uint8_t *)ha->fwfcetracebuf.bp, FWFCESIZE, 7484 DDI_DEV_AUTOINCR); 7485 7486 /* Send payload to application. */ 7487 if (ql_send_buffer_data(payload, (caddr_t)(uintptr_t)cmd->ResponseAdr, 7488 cmd->ResponseLen, mode) != cmd->ResponseLen) { 7489 EL(ha, "failed, send_buffer_data\n"); 7490 cmd->Status = EXT_STATUS_COPY_ERR; 7491 cmd->ResponseLen = 0; 7492 } else { 7493 cmd->Status = EXT_STATUS_OK; 7494 } 7495 7496 kmem_free(payload, FWFCESIZE); 7497 7498 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7499 } 7500 7501 /* 7502 * ql_get_pci_data 7503 * Retrieves pci config space data 7504 * 7505 * Input: 7506 * ha: adapter state pointer. 7507 * cmd: Local EXT_IOCTL cmd struct pointer. 7508 * mode: flags. 7509 * 7510 * Returns: 7511 * None, request status indicated in cmd->Status. 7512 * 7513 * Context: 7514 * Kernel context. 7515 * 7516 */ 7517 static void 7518 ql_get_pci_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7519 { 7520 uint8_t cap_ptr; 7521 uint8_t cap_id; 7522 uint32_t buf_size = 256; 7523 7524 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7525 7526 /* 7527 * First check the "Capabilities List" bit of the status register. 7528 */ 7529 if (ql_pci_config_get16(ha, PCI_CONF_STAT) & PCI_STAT_CAP) { 7530 /* 7531 * Now get the capability pointer 7532 */ 7533 cap_ptr = (uint8_t)ql_pci_config_get8(ha, PCI_CONF_CAP_PTR); 7534 while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) { 7535 /* 7536 * Check for the pcie capability. 7537 */ 7538 cap_id = (uint8_t)ql_pci_config_get8(ha, cap_ptr); 7539 if (cap_id == PCI_CAP_ID_PCI_E) { 7540 buf_size = 4096; 7541 break; 7542 } 7543 cap_ptr = (uint8_t)ql_pci_config_get8(ha, 7544 (cap_ptr + PCI_CAP_NEXT_PTR)); 7545 } 7546 } 7547 7548 if (cmd->ResponseLen < buf_size) { 7549 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 7550 cmd->DetailStatus = buf_size; 7551 EL(ha, "failed ResponseLen < buf_size, len passed=%xh\n", 7552 cmd->ResponseLen); 7553 return; 7554 } 7555 7556 /* Dump PCI config data. */ 7557 if ((ql_pci_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr), 7558 buf_size, mode)) != 0) { 7559 cmd->Status = EXT_STATUS_COPY_ERR; 7560 cmd->DetailStatus = 0; 7561 EL(ha, "failed, copy err pci_dump\n"); 7562 } else { 7563 cmd->Status = EXT_STATUS_OK; 7564 cmd->DetailStatus = buf_size; 7565 } 7566 7567 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7568 } 7569 7570 /* 7571 * ql_pci_dump 7572 * Dumps PCI config data to application buffer. 7573 * 7574 * Input: 7575 * ha = adapter state pointer. 7576 * bp = user buffer address. 7577 * 7578 * Returns: 7579 * 7580 * Context: 7581 * Kernel context. 7582 */ 7583 int 7584 ql_pci_dump(ql_adapter_state_t *ha, uint32_t *bp, uint32_t pci_size, int mode) 7585 { 7586 uint32_t pci_os; 7587 uint32_t *ptr32, *org_ptr32; 7588 7589 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7590 7591 ptr32 = kmem_zalloc(pci_size, KM_SLEEP); 7592 if (ptr32 == NULL) { 7593 EL(ha, "failed kmem_zalloc\n"); 7594 return (ENOMEM); 7595 } 7596 7597 /* store the initial value of ptr32 */ 7598 org_ptr32 = ptr32; 7599 for (pci_os = 0; pci_os < pci_size; pci_os += 4) { 7600 *ptr32 = (uint32_t)ql_pci_config_get32(ha, pci_os); 7601 LITTLE_ENDIAN_32(ptr32); 7602 ptr32++; 7603 } 7604 7605 if (ddi_copyout((void *)org_ptr32, (void *)bp, pci_size, mode) != 7606 0) { 7607 EL(ha, "failed ddi_copyout\n"); 7608 kmem_free(org_ptr32, pci_size); 7609 return (EFAULT); 7610 } 7611 7612 QL_DUMP_9(org_ptr32, 8, pci_size); 7613 7614 kmem_free(org_ptr32, pci_size); 7615 7616 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7617 7618 return (0); 7619 } 7620 7621 /* 7622 * ql_menlo_reset 7623 * Reset Menlo 7624 * 7625 * Input: 7626 * ha: adapter state pointer. 7627 * bp: buffer address. 7628 * mode: flags 7629 * 7630 * Returns: 7631 * 7632 * Context: 7633 * Kernel context. 7634 */ 7635 static void 7636 ql_menlo_reset(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7637 { 7638 EXT_MENLO_RESET rst; 7639 ql_mbx_data_t mr; 7640 int rval; 7641 7642 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7643 7644 if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) { 7645 EL(ha, "failed, invalid request for HBA\n"); 7646 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7647 cmd->ResponseLen = 0; 7648 return; 7649 } 7650 7651 /* 7652 * TODO: only vp_index 0 can do this (?) 7653 */ 7654 7655 /* Verify the size of request structure. */ 7656 if (cmd->RequestLen < sizeof (EXT_MENLO_RESET)) { 7657 /* Return error */ 7658 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen, 7659 sizeof (EXT_MENLO_RESET)); 7660 cmd->Status = EXT_STATUS_INVALID_PARAM; 7661 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 7662 cmd->ResponseLen = 0; 7663 return; 7664 } 7665 7666 /* Get reset request. */ 7667 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, 7668 (void *)&rst, sizeof (EXT_MENLO_RESET), mode) != 0) { 7669 EL(ha, "failed, ddi_copyin\n"); 7670 cmd->Status = EXT_STATUS_COPY_ERR; 7671 cmd->ResponseLen = 0; 7672 return; 7673 } 7674 7675 /* Wait for I/O to stop and daemon to stall. */ 7676 if (ql_suspend_hba(ha, 0) != QL_SUCCESS) { 7677 EL(ha, "ql_stall_driver failed\n"); 7678 ql_restart_hba(ha); 7679 cmd->Status = EXT_STATUS_BUSY; 7680 cmd->ResponseLen = 0; 7681 return; 7682 } 7683 7684 rval = ql_reset_menlo(ha, &mr, rst.Flags); 7685 if (rval != QL_SUCCESS) { 7686 EL(ha, "failed, status=%xh\n", rval); 7687 cmd->Status = EXT_STATUS_MAILBOX; 7688 cmd->DetailStatus = rval; 7689 cmd->ResponseLen = 0; 7690 } else if (mr.mb[1] != 0) { 7691 EL(ha, "failed, substatus=%d\n", mr.mb[1]); 7692 cmd->Status = EXT_STATUS_ERR; 7693 cmd->DetailStatus = mr.mb[1]; 7694 cmd->ResponseLen = 0; 7695 } 7696 7697 ql_restart_hba(ha); 7698 7699 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7700 } 7701 7702 /* 7703 * ql_menlo_get_fw_version 7704 * Get Menlo firmware version. 7705 * 7706 * Input: 7707 * ha: adapter state pointer. 7708 * bp: buffer address. 7709 * mode: flags 7710 * 7711 * Returns: 7712 * 7713 * Context: 7714 * Kernel context. 7715 */ 7716 static void 7717 ql_menlo_get_fw_version(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7718 { 7719 int rval; 7720 ql_mbx_iocb_t *pkt; 7721 EXT_MENLO_GET_FW_VERSION ver = {0}; 7722 7723 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7724 7725 if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) { 7726 EL(ha, "failed, invalid request for HBA\n"); 7727 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7728 cmd->ResponseLen = 0; 7729 return; 7730 } 7731 7732 if (cmd->ResponseLen < sizeof (EXT_MENLO_GET_FW_VERSION)) { 7733 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 7734 cmd->DetailStatus = sizeof (EXT_MENLO_GET_FW_VERSION); 7735 EL(ha, "ResponseLen=%d < %d\n", cmd->ResponseLen, 7736 sizeof (EXT_MENLO_GET_FW_VERSION)); 7737 cmd->ResponseLen = 0; 7738 return; 7739 } 7740 7741 /* Allocate packet. */ 7742 pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP); 7743 if (pkt == NULL) { 7744 EL(ha, "failed, kmem_zalloc\n"); 7745 cmd->Status = EXT_STATUS_NO_MEMORY; 7746 cmd->ResponseLen = 0; 7747 return; 7748 } 7749 7750 pkt->mvfy.entry_type = VERIFY_MENLO_TYPE; 7751 pkt->mvfy.entry_count = 1; 7752 pkt->mvfy.options_status = LE_16(VMF_DO_NOT_UPDATE_FW); 7753 7754 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t)); 7755 LITTLE_ENDIAN_16(&pkt->mvfy.options_status); 7756 LITTLE_ENDIAN_16(&pkt->mvfy.failure_code); 7757 ver.FwVersion = LE_32(pkt->mvfy.fw_version); 7758 7759 if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 || 7760 pkt->mvfy.options_status != CS_COMPLETE) { 7761 /* Command error */ 7762 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval, 7763 pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status, 7764 pkt->mvfy.failure_code); 7765 cmd->Status = EXT_STATUS_ERR; 7766 cmd->DetailStatus = rval != QL_SUCCESS ? rval : 7767 QL_FUNCTION_FAILED; 7768 cmd->ResponseLen = 0; 7769 } else if (ddi_copyout((void *)&ver, 7770 (void *)(uintptr_t)cmd->ResponseAdr, 7771 sizeof (EXT_MENLO_GET_FW_VERSION), mode) != 0) { 7772 EL(ha, "failed, ddi_copyout\n"); 7773 cmd->Status = EXT_STATUS_COPY_ERR; 7774 cmd->ResponseLen = 0; 7775 } else { 7776 cmd->ResponseLen = sizeof (EXT_MENLO_GET_FW_VERSION); 7777 } 7778 7779 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 7780 7781 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7782 } 7783 7784 /* 7785 * ql_menlo_update_fw 7786 * Get Menlo update firmware. 7787 * 7788 * Input: 7789 * ha: adapter state pointer. 7790 * bp: buffer address. 7791 * mode: flags 7792 * 7793 * Returns: 7794 * 7795 * Context: 7796 * Kernel context. 7797 */ 7798 static void 7799 ql_menlo_update_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7800 { 7801 ql_mbx_iocb_t *pkt; 7802 dma_mem_t *dma_mem; 7803 EXT_MENLO_UPDATE_FW fw; 7804 uint32_t *ptr32; 7805 int rval; 7806 7807 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7808 7809 if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) { 7810 EL(ha, "failed, invalid request for HBA\n"); 7811 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7812 cmd->ResponseLen = 0; 7813 return; 7814 } 7815 7816 /* 7817 * TODO: only vp_index 0 can do this (?) 7818 */ 7819 7820 /* Verify the size of request structure. */ 7821 if (cmd->RequestLen < sizeof (EXT_MENLO_UPDATE_FW)) { 7822 /* Return error */ 7823 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen, 7824 sizeof (EXT_MENLO_UPDATE_FW)); 7825 cmd->Status = EXT_STATUS_INVALID_PARAM; 7826 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 7827 cmd->ResponseLen = 0; 7828 return; 7829 } 7830 7831 /* Get update fw request. */ 7832 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr, (caddr_t)&fw, 7833 sizeof (EXT_MENLO_UPDATE_FW), mode) != 0) { 7834 EL(ha, "failed, ddi_copyin\n"); 7835 cmd->Status = EXT_STATUS_COPY_ERR; 7836 cmd->ResponseLen = 0; 7837 return; 7838 } 7839 7840 /* Wait for I/O to stop and daemon to stall. */ 7841 if (ql_suspend_hba(ha, 0) != QL_SUCCESS) { 7842 EL(ha, "ql_stall_driver failed\n"); 7843 ql_restart_hba(ha); 7844 cmd->Status = EXT_STATUS_BUSY; 7845 cmd->ResponseLen = 0; 7846 return; 7847 } 7848 7849 /* Allocate packet. */ 7850 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP); 7851 if (dma_mem == NULL) { 7852 EL(ha, "failed, kmem_zalloc\n"); 7853 cmd->Status = EXT_STATUS_NO_MEMORY; 7854 cmd->ResponseLen = 0; 7855 return; 7856 } 7857 pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP); 7858 if (pkt == NULL) { 7859 EL(ha, "failed, kmem_zalloc\n"); 7860 kmem_free(dma_mem, sizeof (dma_mem_t)); 7861 ql_restart_hba(ha); 7862 cmd->Status = EXT_STATUS_NO_MEMORY; 7863 cmd->ResponseLen = 0; 7864 return; 7865 } 7866 7867 /* Get DMA memory for the IOCB */ 7868 if (ql_get_dma_mem(ha, dma_mem, fw.TotalByteCount, LITTLE_ENDIAN_DMA, 7869 QL_DMA_DATA_ALIGN) != QL_SUCCESS) { 7870 cmn_err(CE_WARN, "%s(%d): request queue DMA memory " 7871 "alloc failed", QL_NAME, ha->instance); 7872 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 7873 kmem_free(dma_mem, sizeof (dma_mem_t)); 7874 ql_restart_hba(ha); 7875 cmd->Status = EXT_STATUS_MS_NO_RESPONSE; 7876 cmd->ResponseLen = 0; 7877 return; 7878 } 7879 7880 /* Get firmware data. */ 7881 if (ql_get_buffer_data((caddr_t)(uintptr_t)fw.pFwDataBytes, dma_mem->bp, 7882 fw.TotalByteCount, mode) != fw.TotalByteCount) { 7883 EL(ha, "failed, get_buffer_data\n"); 7884 ql_free_dma_resource(ha, dma_mem); 7885 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 7886 kmem_free(dma_mem, sizeof (dma_mem_t)); 7887 ql_restart_hba(ha); 7888 cmd->Status = EXT_STATUS_COPY_ERR; 7889 cmd->ResponseLen = 0; 7890 return; 7891 } 7892 7893 /* Sync DMA buffer. */ 7894 (void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size, 7895 DDI_DMA_SYNC_FORDEV); 7896 7897 pkt->mvfy.entry_type = VERIFY_MENLO_TYPE; 7898 pkt->mvfy.entry_count = 1; 7899 pkt->mvfy.options_status = (uint16_t)LE_16(fw.Flags); 7900 ptr32 = dma_mem->bp; 7901 pkt->mvfy.fw_version = LE_32(ptr32[2]); 7902 pkt->mvfy.fw_size = LE_32(fw.TotalByteCount); 7903 pkt->mvfy.fw_sequence_size = LE_32(fw.TotalByteCount); 7904 pkt->mvfy.dseg_count = LE_16(1); 7905 pkt->mvfy.dseg_0_address[0] = (uint32_t) 7906 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 7907 pkt->mvfy.dseg_0_address[1] = (uint32_t) 7908 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 7909 pkt->mvfy.dseg_0_length = LE_32(fw.TotalByteCount); 7910 7911 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t)); 7912 LITTLE_ENDIAN_16(&pkt->mvfy.options_status); 7913 LITTLE_ENDIAN_16(&pkt->mvfy.failure_code); 7914 7915 if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 || 7916 pkt->mvfy.options_status != CS_COMPLETE) { 7917 /* Command error */ 7918 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval, 7919 pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status, 7920 pkt->mvfy.failure_code); 7921 cmd->Status = EXT_STATUS_ERR; 7922 cmd->DetailStatus = rval != QL_SUCCESS ? rval : 7923 QL_FUNCTION_FAILED; 7924 cmd->ResponseLen = 0; 7925 } 7926 7927 ql_free_dma_resource(ha, dma_mem); 7928 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 7929 kmem_free(dma_mem, sizeof (dma_mem_t)); 7930 ql_restart_hba(ha); 7931 7932 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 7933 } 7934 7935 /* 7936 * ql_menlo_manage_info 7937 * Get Menlo manage info. 7938 * 7939 * Input: 7940 * ha: adapter state pointer. 7941 * bp: buffer address. 7942 * mode: flags 7943 * 7944 * Returns: 7945 * 7946 * Context: 7947 * Kernel context. 7948 */ 7949 static void 7950 ql_menlo_manage_info(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 7951 { 7952 ql_mbx_iocb_t *pkt; 7953 dma_mem_t *dma_mem = NULL; 7954 EXT_MENLO_MANAGE_INFO info; 7955 int rval; 7956 7957 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 7958 7959 7960 /* The call is only supported for Schultz right now */ 7961 if (CFG_IST(ha, CFG_CTRL_81XX)) { 7962 ql_get_xgmac_statistics(ha, cmd, mode); 7963 QL_PRINT_9(CE_CONT, "(%d): CFG_CTRL_81XX done\n", 7964 ha->instance); 7965 return; 7966 } 7967 7968 if (!CFG_IST(ha, CFG_CTRL_81XX) || !CFG_IST(ha, CFG_CTRL_MENLO)) { 7969 EL(ha, "failed, invalid request for HBA\n"); 7970 cmd->Status = EXT_STATUS_INVALID_REQUEST; 7971 cmd->ResponseLen = 0; 7972 return; 7973 } 7974 7975 /* Verify the size of request structure. */ 7976 if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) { 7977 /* Return error */ 7978 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen, 7979 sizeof (EXT_MENLO_MANAGE_INFO)); 7980 cmd->Status = EXT_STATUS_INVALID_PARAM; 7981 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 7982 cmd->ResponseLen = 0; 7983 return; 7984 } 7985 7986 /* Get manage info request. */ 7987 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr, 7988 (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) { 7989 EL(ha, "failed, ddi_copyin\n"); 7990 cmd->Status = EXT_STATUS_COPY_ERR; 7991 cmd->ResponseLen = 0; 7992 return; 7993 } 7994 7995 /* Allocate packet. */ 7996 pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP); 7997 if (pkt == NULL) { 7998 EL(ha, "failed, kmem_zalloc\n"); 7999 ql_restart_driver(ha); 8000 cmd->Status = EXT_STATUS_NO_MEMORY; 8001 cmd->ResponseLen = 0; 8002 return; 8003 } 8004 8005 pkt->mdata.entry_type = MENLO_DATA_TYPE; 8006 pkt->mdata.entry_count = 1; 8007 pkt->mdata.options_status = (uint16_t)LE_16(info.Operation); 8008 8009 /* Get DMA memory for the IOCB */ 8010 if (info.Operation == MENLO_OP_READ_MEM || 8011 info.Operation == MENLO_OP_WRITE_MEM) { 8012 pkt->mdata.total_byte_count = LE_32(info.TotalByteCount); 8013 pkt->mdata.parameter_1 = 8014 LE_32(info.Parameters.ap.MenloMemory.StartingAddr); 8015 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), 8016 KM_SLEEP); 8017 if (dma_mem == NULL) { 8018 EL(ha, "failed, kmem_zalloc\n"); 8019 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 8020 cmd->Status = EXT_STATUS_NO_MEMORY; 8021 cmd->ResponseLen = 0; 8022 return; 8023 } 8024 if (ql_get_dma_mem(ha, dma_mem, info.TotalByteCount, 8025 LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN) != QL_SUCCESS) { 8026 cmn_err(CE_WARN, "%s(%d): request queue DMA memory " 8027 "alloc failed", QL_NAME, ha->instance); 8028 kmem_free(dma_mem, sizeof (dma_mem_t)); 8029 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 8030 cmd->Status = EXT_STATUS_MS_NO_RESPONSE; 8031 cmd->ResponseLen = 0; 8032 return; 8033 } 8034 if (info.Operation == MENLO_OP_WRITE_MEM) { 8035 /* Get data. */ 8036 if (ql_get_buffer_data( 8037 (caddr_t)(uintptr_t)info.pDataBytes, 8038 dma_mem->bp, info.TotalByteCount, mode) != 8039 info.TotalByteCount) { 8040 EL(ha, "failed, get_buffer_data\n"); 8041 ql_free_dma_resource(ha, dma_mem); 8042 kmem_free(dma_mem, sizeof (dma_mem_t)); 8043 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 8044 cmd->Status = EXT_STATUS_COPY_ERR; 8045 cmd->ResponseLen = 0; 8046 return; 8047 } 8048 (void) ddi_dma_sync(dma_mem->dma_handle, 0, 8049 dma_mem->size, DDI_DMA_SYNC_FORDEV); 8050 } 8051 pkt->mdata.dseg_count = LE_16(1); 8052 pkt->mdata.dseg_0_address[0] = (uint32_t) 8053 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 8054 pkt->mdata.dseg_0_address[1] = (uint32_t) 8055 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 8056 pkt->mdata.dseg_0_length = LE_32(info.TotalByteCount); 8057 } else if (info.Operation & MENLO_OP_CHANGE_CONFIG) { 8058 pkt->mdata.parameter_1 = 8059 LE_32(info.Parameters.ap.MenloConfig.ConfigParamID); 8060 pkt->mdata.parameter_2 = 8061 LE_32(info.Parameters.ap.MenloConfig.ConfigParamData0); 8062 pkt->mdata.parameter_3 = 8063 LE_32(info.Parameters.ap.MenloConfig.ConfigParamData1); 8064 } else if (info.Operation & MENLO_OP_GET_INFO) { 8065 pkt->mdata.parameter_1 = 8066 LE_32(info.Parameters.ap.MenloInfo.InfoDataType); 8067 pkt->mdata.parameter_2 = 8068 LE_32(info.Parameters.ap.MenloInfo.InfoContext); 8069 } 8070 8071 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t)); 8072 LITTLE_ENDIAN_16(&pkt->mdata.options_status); 8073 LITTLE_ENDIAN_16(&pkt->mdata.failure_code); 8074 8075 if (rval != QL_SUCCESS || (pkt->mdata.entry_status & 0x3c) != 0 || 8076 pkt->mdata.options_status != CS_COMPLETE) { 8077 /* Command error */ 8078 EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval, 8079 pkt->mdata.entry_status & 0x3c, pkt->mdata.options_status, 8080 pkt->mdata.failure_code); 8081 cmd->Status = EXT_STATUS_ERR; 8082 cmd->DetailStatus = rval != QL_SUCCESS ? rval : 8083 QL_FUNCTION_FAILED; 8084 cmd->ResponseLen = 0; 8085 } else if (info.Operation == MENLO_OP_READ_MEM) { 8086 (void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size, 8087 DDI_DMA_SYNC_FORKERNEL); 8088 if (ql_send_buffer_data((caddr_t)(uintptr_t)info.pDataBytes, 8089 dma_mem->bp, info.TotalByteCount, mode) != 8090 info.TotalByteCount) { 8091 cmd->Status = EXT_STATUS_COPY_ERR; 8092 cmd->ResponseLen = 0; 8093 } 8094 } 8095 8096 ql_free_dma_resource(ha, dma_mem); 8097 kmem_free(dma_mem, sizeof (dma_mem_t)); 8098 kmem_free(pkt, sizeof (ql_mbx_iocb_t)); 8099 8100 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8101 } 8102 8103 /* 8104 * ql_suspend_hba 8105 * Suspends all adapter ports. 8106 * 8107 * Input: 8108 * ha: adapter state pointer. 8109 * options: BIT_0 --> leave driver stalled on exit if 8110 * failed. 8111 * 8112 * Returns: 8113 * ql local function return status code. 8114 * 8115 * Context: 8116 * Kernel context. 8117 */ 8118 static int 8119 ql_suspend_hba(ql_adapter_state_t *ha, uint32_t opt) 8120 { 8121 ql_adapter_state_t *ha2; 8122 ql_link_t *link; 8123 int rval = QL_SUCCESS; 8124 8125 /* Quiesce I/O on all adapter ports */ 8126 for (link = ql_hba.first; link != NULL; link = link->next) { 8127 ha2 = link->base_address; 8128 8129 if (ha2->fru_hba_index != ha->fru_hba_index) { 8130 continue; 8131 } 8132 8133 if ((rval = ql_stall_driver(ha2, opt)) != QL_SUCCESS) { 8134 EL(ha, "ql_stall_driver status=%xh\n", rval); 8135 break; 8136 } 8137 } 8138 8139 return (rval); 8140 } 8141 8142 /* 8143 * ql_restart_hba 8144 * Restarts adapter. 8145 * 8146 * Input: 8147 * ha: adapter state pointer. 8148 * 8149 * Context: 8150 * Kernel context. 8151 */ 8152 static void 8153 ql_restart_hba(ql_adapter_state_t *ha) 8154 { 8155 ql_adapter_state_t *ha2; 8156 ql_link_t *link; 8157 8158 /* Resume I/O on all adapter ports */ 8159 for (link = ql_hba.first; link != NULL; link = link->next) { 8160 ha2 = link->base_address; 8161 8162 if (ha2->fru_hba_index != ha->fru_hba_index) { 8163 continue; 8164 } 8165 8166 ql_restart_driver(ha2); 8167 } 8168 } 8169 8170 /* 8171 * ql_get_vp_cnt_id 8172 * Retrieves pci config space data 8173 * 8174 * Input: 8175 * ha: adapter state pointer. 8176 * cmd: Local EXT_IOCTL cmd struct pointer. 8177 * mode: flags. 8178 * 8179 * Returns: 8180 * None, request status indicated in cmd->Status. 8181 * 8182 * Context: 8183 * Kernel context. 8184 * 8185 */ 8186 static void 8187 ql_get_vp_cnt_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 8188 { 8189 ql_adapter_state_t *vha; 8190 PEXT_VPORT_ID_CNT ptmp_vp; 8191 int id = 0; 8192 int rval; 8193 char name[MAXPATHLEN]; 8194 8195 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 8196 8197 /* 8198 * To be backward compatible with older API 8199 * check for the size of old EXT_VPORT_ID_CNT 8200 */ 8201 if (cmd->ResponseLen < sizeof (EXT_VPORT_ID_CNT) && 8202 (cmd->ResponseLen != EXT_OLD_VPORT_ID_CNT_SIZE)) { 8203 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 8204 cmd->DetailStatus = sizeof (EXT_VPORT_ID_CNT); 8205 EL(ha, "failed, ResponseLen < EXT_VPORT_ID_CNT, Len=%xh\n", 8206 cmd->ResponseLen); 8207 cmd->ResponseLen = 0; 8208 return; 8209 } 8210 8211 ptmp_vp = (EXT_VPORT_ID_CNT *) 8212 kmem_zalloc(sizeof (EXT_VPORT_ID_CNT), KM_SLEEP); 8213 if (ptmp_vp == NULL) { 8214 EL(ha, "failed, kmem_zalloc\n"); 8215 cmd->ResponseLen = 0; 8216 return; 8217 } 8218 vha = ha->vp_next; 8219 while (vha != NULL) { 8220 ptmp_vp->VpCnt++; 8221 ptmp_vp->VpId[id] = vha->vp_index; 8222 (void) ddi_pathname(vha->dip, name); 8223 (void) strcpy((char *)ptmp_vp->vp_path[id], name); 8224 ptmp_vp->VpDrvInst[id] = (int32_t)vha->instance; 8225 id++; 8226 vha = vha->vp_next; 8227 } 8228 rval = ddi_copyout((void *)ptmp_vp, 8229 (void *)(uintptr_t)(cmd->ResponseAdr), 8230 cmd->ResponseLen, mode); 8231 if (rval != 0) { 8232 cmd->Status = EXT_STATUS_COPY_ERR; 8233 cmd->ResponseLen = 0; 8234 EL(ha, "failed, ddi_copyout\n"); 8235 } else { 8236 cmd->ResponseLen = sizeof (EXT_VPORT_ID_CNT); 8237 QL_PRINT_9(CE_CONT, "(%d): done, vport_cnt=%d\n", 8238 ha->instance, ptmp_vp->VpCnt); 8239 } 8240 8241 } 8242 8243 /* 8244 * ql_vp_ioctl 8245 * Performs all EXT_CC_VPORT_CMD functions. 8246 * 8247 * Input: 8248 * ha: adapter state pointer. 8249 * cmd: Local EXT_IOCTL cmd struct pointer. 8250 * mode: flags. 8251 * 8252 * Returns: 8253 * None, request status indicated in cmd->Status. 8254 * 8255 * Context: 8256 * Kernel context. 8257 */ 8258 static void 8259 ql_vp_ioctl(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 8260 { 8261 QL_PRINT_9(CE_CONT, "(%d): started, cmd=%d\n", ha->instance, 8262 cmd->SubCode); 8263 8264 /* case off on command subcode */ 8265 switch (cmd->SubCode) { 8266 case EXT_VF_SC_VPORT_GETINFO: 8267 ql_qry_vport(ha, cmd, mode); 8268 break; 8269 default: 8270 /* function not supported. */ 8271 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 8272 EL(ha, "failed, Unsupported Subcode=%xh\n", 8273 cmd->SubCode); 8274 break; 8275 } 8276 8277 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8278 } 8279 8280 /* 8281 * ql_qry_vport 8282 * Performs EXT_VF_SC_VPORT_GETINFO subfunction. 8283 * 8284 * Input: 8285 * ha: adapter state pointer. 8286 * cmd: EXT_IOCTL cmd struct pointer. 8287 * mode: flags. 8288 * 8289 * Returns: 8290 * None, request status indicated in cmd->Status. 8291 * 8292 * Context: 8293 * Kernel context. 8294 */ 8295 static void 8296 ql_qry_vport(ql_adapter_state_t *vha, EXT_IOCTL *cmd, int mode) 8297 { 8298 ql_adapter_state_t *tmp_vha; 8299 EXT_VPORT_INFO tmp_vport = {0}; 8300 int max_vport; 8301 8302 QL_PRINT_9(CE_CONT, "(%d): started\n", vha->instance); 8303 8304 if (cmd->ResponseLen < sizeof (EXT_VPORT_INFO)) { 8305 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 8306 cmd->DetailStatus = sizeof (EXT_VPORT_INFO); 8307 EL(vha, "failed, ResponseLen < EXT_VPORT_INFO, Len=%xh\n", 8308 cmd->ResponseLen); 8309 cmd->ResponseLen = 0; 8310 return; 8311 } 8312 8313 /* Fill in the vport information. */ 8314 bcopy(vha->loginparams.node_ww_name.raw_wwn, tmp_vport.wwnn, 8315 EXT_DEF_WWN_NAME_SIZE); 8316 bcopy(vha->loginparams.nport_ww_name.raw_wwn, tmp_vport.wwpn, 8317 EXT_DEF_WWN_NAME_SIZE); 8318 tmp_vport.state = vha->state; 8319 8320 tmp_vha = vha->pha->vp_next; 8321 while (tmp_vha != NULL) { 8322 tmp_vport.used++; 8323 tmp_vha = tmp_vha->vp_next; 8324 } 8325 8326 max_vport = (CFG_IST(vha, CFG_CTRL_2422) ? MAX_24_VIRTUAL_PORTS : 8327 MAX_25_VIRTUAL_PORTS); 8328 if (max_vport > tmp_vport.used) { 8329 tmp_vport.free = max_vport - tmp_vport.used; 8330 } 8331 8332 if (ddi_copyout((void *)&tmp_vport, 8333 (void *)(uintptr_t)(cmd->ResponseAdr), 8334 sizeof (EXT_VPORT_INFO), mode) != 0) { 8335 cmd->Status = EXT_STATUS_COPY_ERR; 8336 cmd->ResponseLen = 0; 8337 EL(vha, "failed, ddi_copyout\n"); 8338 } else { 8339 cmd->ResponseLen = sizeof (EXT_VPORT_INFO); 8340 QL_PRINT_9(CE_CONT, "(%d): done\n", vha->instance); 8341 } 8342 } 8343 8344 /* 8345 * ql_access_flash 8346 * Performs all EXT_CC_ACCESS_FLASH_OS functions. 8347 * 8348 * Input: 8349 * pi: port info pointer. 8350 * cmd: Local EXT_IOCTL cmd struct pointer. 8351 * mode: flags. 8352 * 8353 * Returns: 8354 * None, request status indicated in cmd->Status. 8355 * 8356 * Context: 8357 * Kernel context. 8358 */ 8359 static void 8360 ql_access_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 8361 { 8362 int rval; 8363 8364 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 8365 8366 switch (cmd->SubCode) { 8367 case EXT_SC_FLASH_READ: 8368 if ((rval = ql_flash_fcode_dump(ha, 8369 (void *)(uintptr_t)(cmd->ResponseAdr), 8370 (size_t)(cmd->ResponseLen), cmd->Reserved1, mode)) != 0) { 8371 cmd->Status = EXT_STATUS_COPY_ERR; 8372 cmd->ResponseLen = 0; 8373 EL(ha, "flash_fcode_dump status=%xh\n", rval); 8374 } 8375 break; 8376 case EXT_SC_FLASH_WRITE: 8377 if ((rval = ql_r_m_w_flash(ha, 8378 (void *)(uintptr_t)(cmd->RequestAdr), 8379 (size_t)(cmd->RequestLen), cmd->Reserved1, mode)) != 8380 QL_SUCCESS) { 8381 cmd->Status = EXT_STATUS_COPY_ERR; 8382 cmd->ResponseLen = 0; 8383 EL(ha, "r_m_w_flash status=%xh\n", rval); 8384 } else { 8385 /* Reset caches on all adapter instances. */ 8386 ql_update_flash_caches(ha); 8387 } 8388 break; 8389 default: 8390 EL(ha, "unknown subcode=%xh\n", cmd->SubCode); 8391 cmd->Status = EXT_STATUS_ERR; 8392 cmd->ResponseLen = 0; 8393 break; 8394 } 8395 8396 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8397 } 8398 8399 /* 8400 * ql_reset_cmd 8401 * Performs all EXT_CC_RESET_FW_OS functions. 8402 * 8403 * Input: 8404 * ha: adapter state pointer. 8405 * cmd: Local EXT_IOCTL cmd struct pointer. 8406 * 8407 * Returns: 8408 * None, request status indicated in cmd->Status. 8409 * 8410 * Context: 8411 * Kernel context. 8412 */ 8413 static void 8414 ql_reset_cmd(ql_adapter_state_t *ha, EXT_IOCTL *cmd) 8415 { 8416 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 8417 8418 switch (cmd->SubCode) { 8419 case EXT_SC_RESET_FC_FW: 8420 EL(ha, "isp_abort_needed\n"); 8421 ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0); 8422 break; 8423 case EXT_SC_RESET_MPI_FW: 8424 if (!(CFG_IST(ha, CFG_CTRL_81XX))) { 8425 EL(ha, "invalid request for HBA\n"); 8426 cmd->Status = EXT_STATUS_INVALID_REQUEST; 8427 cmd->ResponseLen = 0; 8428 } else { 8429 /* Wait for I/O to stop and daemon to stall. */ 8430 if (ql_suspend_hba(ha, 0) != QL_SUCCESS) { 8431 EL(ha, "ql_suspend_hba failed\n"); 8432 cmd->Status = EXT_STATUS_BUSY; 8433 cmd->ResponseLen = 0; 8434 } else if (ql_restart_mpi(ha) != QL_SUCCESS) { 8435 cmd->Status = EXT_STATUS_ERR; 8436 cmd->ResponseLen = 0; 8437 } 8438 ql_restart_hba(ha); 8439 } 8440 break; 8441 default: 8442 EL(ha, "unknown subcode=%xh\n", cmd->SubCode); 8443 cmd->Status = EXT_STATUS_ERR; 8444 cmd->ResponseLen = 0; 8445 break; 8446 } 8447 8448 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8449 } 8450 8451 /* 8452 * ql_get_dcbx_parameters 8453 * Get DCBX parameters. 8454 * 8455 * Input: 8456 * ha: adapter state pointer. 8457 * cmd: User space CT arguments pointer. 8458 * mode: flags. 8459 */ 8460 static void 8461 ql_get_dcbx_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 8462 { 8463 uint8_t *tmp_buf; 8464 int rval; 8465 8466 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 8467 8468 if (!(CFG_IST(ha, CFG_CTRL_81XX))) { 8469 EL(ha, "invalid request for HBA\n"); 8470 cmd->Status = EXT_STATUS_INVALID_REQUEST; 8471 cmd->ResponseLen = 0; 8472 return; 8473 } 8474 8475 /* Allocate memory for command. */ 8476 tmp_buf = kmem_zalloc(EXT_DEF_DCBX_PARAM_BUF_SIZE, KM_SLEEP); 8477 if (tmp_buf == NULL) { 8478 EL(ha, "failed, kmem_zalloc\n"); 8479 cmd->Status = EXT_STATUS_NO_MEMORY; 8480 cmd->ResponseLen = 0; 8481 return; 8482 } 8483 /* Send command */ 8484 rval = ql_get_dcbx_params(ha, EXT_DEF_DCBX_PARAM_BUF_SIZE, 8485 (caddr_t)tmp_buf); 8486 if (rval != QL_SUCCESS) { 8487 /* error */ 8488 EL(ha, "failed, get_dcbx_params_mbx=%xh\n", rval); 8489 kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE); 8490 cmd->Status = EXT_STATUS_ERR; 8491 cmd->ResponseLen = 0; 8492 return; 8493 } 8494 8495 /* Copy the response */ 8496 if (ql_send_buffer_data((caddr_t)tmp_buf, 8497 (caddr_t)(uintptr_t)cmd->ResponseAdr, 8498 EXT_DEF_DCBX_PARAM_BUF_SIZE, mode) != EXT_DEF_DCBX_PARAM_BUF_SIZE) { 8499 EL(ha, "failed, ddi_copyout\n"); 8500 cmd->Status = EXT_STATUS_COPY_ERR; 8501 cmd->ResponseLen = 0; 8502 } else { 8503 cmd->ResponseLen = EXT_DEF_DCBX_PARAM_BUF_SIZE; 8504 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8505 } 8506 kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE); 8507 8508 } 8509 8510 /* 8511 * ql_qry_cna_port 8512 * Performs EXT_SC_QUERY_CNA_PORT subfunction. 8513 * 8514 * Input: 8515 * ha: adapter state pointer. 8516 * cmd: EXT_IOCTL cmd struct pointer. 8517 * mode: flags. 8518 * 8519 * Returns: 8520 * None, request status indicated in cmd->Status. 8521 * 8522 * Context: 8523 * Kernel context. 8524 */ 8525 static void 8526 ql_qry_cna_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 8527 { 8528 EXT_CNA_PORT cna_port = {0}; 8529 8530 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 8531 8532 if (!(CFG_IST(ha, CFG_CTRL_81XX))) { 8533 EL(ha, "invalid request for HBA\n"); 8534 cmd->Status = EXT_STATUS_INVALID_REQUEST; 8535 cmd->ResponseLen = 0; 8536 return; 8537 } 8538 8539 if (cmd->ResponseLen < sizeof (EXT_CNA_PORT)) { 8540 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 8541 cmd->DetailStatus = sizeof (EXT_CNA_PORT); 8542 EL(ha, "failed, ResponseLen < EXT_CNA_PORT, Len=%xh\n", 8543 cmd->ResponseLen); 8544 cmd->ResponseLen = 0; 8545 return; 8546 } 8547 8548 cna_port.VLanId = ha->fcoe_vlan_id; 8549 cna_port.FabricParam = ha->fabric_params; 8550 bcopy(ha->fcoe_vnport_mac, cna_port.VNPortMACAddress, 8551 EXT_DEF_MAC_ADDRESS_SIZE); 8552 8553 if (ddi_copyout((void *)&cna_port, 8554 (void *)(uintptr_t)(cmd->ResponseAdr), 8555 sizeof (EXT_CNA_PORT), mode) != 0) { 8556 cmd->Status = EXT_STATUS_COPY_ERR; 8557 cmd->ResponseLen = 0; 8558 EL(ha, "failed, ddi_copyout\n"); 8559 } else { 8560 cmd->ResponseLen = sizeof (EXT_CNA_PORT); 8561 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8562 } 8563 } 8564 8565 /* 8566 * ql_get_xgmac_statistics 8567 * Get XgMac information 8568 * 8569 * Input: 8570 * ha: adapter state pointer. 8571 * cmd: EXT_IOCTL cmd struct pointer. 8572 * mode: flags. 8573 * 8574 * Returns: 8575 * None, request status indicated in cmd->Status. 8576 * 8577 * Context: 8578 * Kernel context. 8579 */ 8580 static void 8581 ql_get_xgmac_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 8582 { 8583 int rval; 8584 uint32_t size; 8585 int8_t *tmp_buf; 8586 EXT_MENLO_MANAGE_INFO info; 8587 8588 QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance); 8589 8590 /* Verify the size of request structure. */ 8591 if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) { 8592 /* Return error */ 8593 EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen, 8594 sizeof (EXT_MENLO_MANAGE_INFO)); 8595 cmd->Status = EXT_STATUS_INVALID_PARAM; 8596 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 8597 cmd->ResponseLen = 0; 8598 return; 8599 } 8600 8601 /* Get manage info request. */ 8602 if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr, 8603 (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) { 8604 EL(ha, "failed, ddi_copyin\n"); 8605 cmd->Status = EXT_STATUS_COPY_ERR; 8606 cmd->ResponseLen = 0; 8607 return; 8608 } 8609 8610 size = info.TotalByteCount; 8611 if (!size) { 8612 /* parameter error */ 8613 cmd->Status = EXT_STATUS_INVALID_PARAM; 8614 cmd->DetailStatus = 0; 8615 EL(ha, "failed, size=%xh\n", size); 8616 cmd->ResponseLen = 0; 8617 return; 8618 } 8619 8620 /* Allocate memory for command. */ 8621 tmp_buf = kmem_zalloc(size, KM_SLEEP); 8622 if (tmp_buf == NULL) { 8623 EL(ha, "failed, kmem_zalloc\n"); 8624 cmd->Status = EXT_STATUS_NO_MEMORY; 8625 cmd->ResponseLen = 0; 8626 return; 8627 } 8628 8629 if (!(info.Operation & MENLO_OP_GET_INFO)) { 8630 EL(ha, "Invalid request for 81XX\n"); 8631 kmem_free(tmp_buf, size); 8632 cmd->Status = EXT_STATUS_ERR; 8633 cmd->ResponseLen = 0; 8634 return; 8635 } 8636 8637 rval = ql_get_xgmac_stats(ha, size, (caddr_t)tmp_buf); 8638 8639 if (rval != QL_SUCCESS) { 8640 /* error */ 8641 EL(ha, "failed, get_xgmac_stats =%xh\n", rval); 8642 kmem_free(tmp_buf, size); 8643 cmd->Status = EXT_STATUS_ERR; 8644 cmd->ResponseLen = 0; 8645 return; 8646 } 8647 8648 if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)info.pDataBytes, 8649 size, mode) != size) { 8650 EL(ha, "failed, ddi_copyout\n"); 8651 cmd->Status = EXT_STATUS_COPY_ERR; 8652 cmd->ResponseLen = 0; 8653 } else { 8654 cmd->ResponseLen = info.TotalByteCount; 8655 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8656 } 8657 kmem_free(tmp_buf, size); 8658 QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance); 8659 } 8660