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 91 static int ql_lun_count(ql_adapter_state_t *, ql_tgt_t *); 92 static int ql_report_lun(ql_adapter_state_t *, ql_tgt_t *); 93 static int ql_inq_scan(ql_adapter_state_t *, ql_tgt_t *, int); 94 static int ql_inq(ql_adapter_state_t *, ql_tgt_t *, int, ql_mbx_iocb_t *, 95 uint8_t); 96 static uint32_t ql_get_buffer_data(caddr_t, caddr_t, uint32_t, int); 97 static uint32_t ql_send_buffer_data(caddr_t, caddr_t, uint32_t, int); 98 static ql_tgt_t *ql_find_port(ql_adapter_state_t *, uint8_t *, uint16_t); 99 static int ql_flash_fcode_load(ql_adapter_state_t *, void *, uint32_t, int); 100 static int ql_load_fcode(ql_adapter_state_t *, uint8_t *, uint32_t); 101 static int ql_flash_fcode_dump(ql_adapter_state_t *, void *, uint32_t, int); 102 static int ql_program_flash_address(ql_adapter_state_t *, uint32_t, 103 uint8_t); 104 static void ql_set_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int); 105 static void ql_get_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int); 106 static int ql_reset_statistics(ql_adapter_state_t *, EXT_IOCTL *); 107 static void ql_get_statistics(ql_adapter_state_t *, EXT_IOCTL *, int); 108 static void ql_get_statistics_fc(ql_adapter_state_t *, EXT_IOCTL *, int); 109 static void ql_get_statistics_fc4(ql_adapter_state_t *, EXT_IOCTL *, int); 110 static void ql_set_led_state(ql_adapter_state_t *, EXT_IOCTL *, int); 111 static void ql_get_led_state(ql_adapter_state_t *, EXT_IOCTL *, int); 112 static void ql_drive_led(ql_adapter_state_t *, uint32_t); 113 static uint32_t ql_setup_led(ql_adapter_state_t *); 114 static uint32_t ql_wrapup_led(ql_adapter_state_t *); 115 static void ql_get_port_summary(ql_adapter_state_t *, EXT_IOCTL *, int); 116 static void ql_get_target_id(ql_adapter_state_t *, EXT_IOCTL *, int); 117 static void ql_get_sfp(ql_adapter_state_t *, EXT_IOCTL *, int); 118 static int ql_dump_sfp(ql_adapter_state_t *, void *, int); 119 static ql_fcache_t *ql_setup_fnode(ql_adapter_state_t *); 120 static void ql_get_fcache(ql_adapter_state_t *, EXT_IOCTL *, int); 121 static void ql_get_fcache_ex(ql_adapter_state_t *, EXT_IOCTL *, int); 122 static void ql_update_fcache(ql_adapter_state_t *, uint8_t *, uint32_t); 123 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *); 124 static void ql_port_param(ql_adapter_state_t *, EXT_IOCTL *, int); 125 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *); 126 static void ql_get_pci_data(ql_adapter_state_t *, EXT_IOCTL *, int); 127 static void ql_get_fwfcetrace(ql_adapter_state_t *, EXT_IOCTL *, int); 128 static void ql_get_fwexttrace(ql_adapter_state_t *, EXT_IOCTL *, int); 129 static void ql_menlo_reset(ql_adapter_state_t *, EXT_IOCTL *, int); 130 static void ql_menlo_get_fw_version(ql_adapter_state_t *, EXT_IOCTL *, int); 131 static void ql_menlo_update_fw(ql_adapter_state_t *, EXT_IOCTL *, int); 132 static void ql_menlo_manage_info(ql_adapter_state_t *, EXT_IOCTL *, int); 133 static int ql_suspend_hba(ql_adapter_state_t *, uint32_t); 134 static void ql_restart_hba(ql_adapter_state_t *); 135 static void ql_get_vp_cnt_id(ql_adapter_state_t *, EXT_IOCTL *, int); 136 static void ql_vp_ioctl(ql_adapter_state_t *, EXT_IOCTL *, int); 137 static void ql_qry_vport(ql_adapter_state_t *, EXT_IOCTL *, int); 138 139 /* ******************************************************************** */ 140 /* External IOCTL support. */ 141 /* ******************************************************************** */ 142 143 /* 144 * ql_alloc_xioctl_resource 145 * Allocates resources needed by module code. 146 * 147 * Input: 148 * ha: adapter state pointer. 149 * 150 * Returns: 151 * SYS_ERRNO 152 * 153 * Context: 154 * Kernel context. 155 */ 156 int 157 ql_alloc_xioctl_resource(ql_adapter_state_t *ha) 158 { 159 ql_xioctl_t *xp; 160 161 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 162 163 if (ha->xioctl != NULL) { 164 QL_PRINT_9(CE_CONT, "(%d): already allocated exiting\n", 165 ha->instance); 166 return (0); 167 } 168 169 xp = kmem_zalloc(sizeof (ql_xioctl_t), KM_SLEEP); 170 if (xp == NULL) { 171 EL(ha, "failed, kmem_zalloc\n"); 172 return (ENOMEM); 173 } 174 ha->xioctl = xp; 175 176 /* Allocate AEN tracking buffer */ 177 xp->aen_tracking_queue = kmem_zalloc(EXT_DEF_MAX_AEN_QUEUE * 178 sizeof (EXT_ASYNC_EVENT), KM_SLEEP); 179 if (xp->aen_tracking_queue == NULL) { 180 EL(ha, "failed, kmem_zalloc-2\n"); 181 ql_free_xioctl_resource(ha); 182 return (ENOMEM); 183 } 184 185 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 186 187 return (0); 188 } 189 190 /* 191 * ql_free_xioctl_resource 192 * Frees resources used by module code. 193 * 194 * Input: 195 * ha: adapter state pointer. 196 * 197 * Context: 198 * Kernel context. 199 */ 200 void 201 ql_free_xioctl_resource(ql_adapter_state_t *ha) 202 { 203 ql_xioctl_t *xp = ha->xioctl; 204 205 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 206 207 if (xp == NULL) { 208 QL_PRINT_9(CE_CONT, "(%d): already freed\n", ha->instance); 209 return; 210 } 211 212 if (xp->aen_tracking_queue != NULL) { 213 kmem_free(xp->aen_tracking_queue, EXT_DEF_MAX_AEN_QUEUE * 214 sizeof (EXT_ASYNC_EVENT)); 215 xp->aen_tracking_queue = NULL; 216 } 217 218 kmem_free(xp, sizeof (ql_xioctl_t)); 219 ha->xioctl = NULL; 220 221 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 222 } 223 224 /* 225 * ql_xioctl 226 * External IOCTL processing. 227 * 228 * Input: 229 * ha: adapter state pointer. 230 * cmd: function to perform 231 * arg: data type varies with request 232 * mode: flags 233 * cred_p: credentials pointer 234 * rval_p: pointer to result value 235 * 236 * Returns: 237 * 0: success 238 * ENXIO: No such device or address 239 * ENOPROTOOPT: Protocol not available 240 * 241 * Context: 242 * Kernel context. 243 */ 244 /* ARGSUSED */ 245 int 246 ql_xioctl(ql_adapter_state_t *ha, int cmd, intptr_t arg, int mode, 247 cred_t *cred_p, int *rval_p) 248 { 249 int rval; 250 251 QL_PRINT_9(CE_CONT, "(%d): entered, cmd=%d\n", ha->instance, cmd); 252 253 if (ha->xioctl == NULL) { 254 QL_PRINT_9(CE_CONT, "(%d): no context\n", ha->instance); 255 return (ENXIO); 256 } 257 258 switch (cmd) { 259 case EXT_CC_QUERY: 260 case EXT_CC_SEND_FCCT_PASSTHRU: 261 case EXT_CC_REG_AEN: 262 case EXT_CC_GET_AEN: 263 case EXT_CC_SEND_SCSI_PASSTHRU: 264 case EXT_CC_WWPN_TO_SCSIADDR: 265 case EXT_CC_SEND_ELS_RNID: 266 case EXT_CC_SET_DATA: 267 case EXT_CC_GET_DATA: 268 case EXT_CC_HOST_IDX: 269 case EXT_CC_READ_NVRAM: 270 case EXT_CC_UPDATE_NVRAM: 271 case EXT_CC_READ_OPTION_ROM: 272 case EXT_CC_READ_OPTION_ROM_EX: 273 case EXT_CC_UPDATE_OPTION_ROM: 274 case EXT_CC_UPDATE_OPTION_ROM_EX: 275 case EXT_CC_GET_VPD: 276 case EXT_CC_SET_VPD: 277 case EXT_CC_LOOPBACK: 278 case EXT_CC_GET_FCACHE: 279 case EXT_CC_GET_FCACHE_EX: 280 case EXT_CC_HOST_DRVNAME: 281 case EXT_CC_GET_SFP_DATA: 282 case EXT_CC_PORT_PARAM: 283 case EXT_CC_GET_PCI_DATA: 284 case EXT_CC_GET_FWEXTTRACE: 285 case EXT_CC_GET_FWFCETRACE: 286 case EXT_CC_GET_VP_CNT_ID: 287 case EXT_CC_VPORT_CMD: 288 rval = ql_sdm_ioctl(ha, cmd, (void *)arg, mode); 289 break; 290 default: 291 /* function not supported. */ 292 EL(ha, "function=%d not supported\n", cmd); 293 rval = ENOPROTOOPT; 294 } 295 296 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 297 298 return (rval); 299 } 300 301 /* 302 * ql_sdm_ioctl 303 * Provides ioctl functions for SAN/Device Management functions 304 * AKA External Ioctl functions. 305 * 306 * Input: 307 * ha: adapter state pointer. 308 * ioctl_code: ioctl function to perform 309 * arg: Pointer to EXT_IOCTL cmd data in application land. 310 * mode: flags 311 * 312 * Returns: 313 * 0: success 314 * ENOMEM: Alloc of local EXT_IOCTL struct failed. 315 * EFAULT: Copyin of caller's EXT_IOCTL struct failed or 316 * copyout of EXT_IOCTL status info failed. 317 * EINVAL: Signature or version of caller's EXT_IOCTL invalid. 318 * EBUSY: Device busy 319 * 320 * Context: 321 * Kernel context. 322 */ 323 static int 324 ql_sdm_ioctl(ql_adapter_state_t *ha, int ioctl_code, void *arg, int mode) 325 { 326 EXT_IOCTL *cmd; 327 int rval; 328 ql_adapter_state_t *vha; 329 330 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 331 332 /* Copy argument structure (EXT_IOCTL) from application land. */ 333 if ((rval = ql_sdm_setup(ha, &cmd, arg, mode, 334 ql_validate_signature)) != 0) { 335 /* 336 * a non-zero value at this time means a problem getting 337 * the requested information from application land, just 338 * return the error code and hope for the best. 339 */ 340 EL(ha, "failed, sdm_setup\n"); 341 return (rval); 342 } 343 344 /* 345 * Map the physical ha ptr (which the ioctl is called with) 346 * to the virtual ha that the caller is addressing. 347 */ 348 if (ha->flags & VP_ENABLED) { 349 /* 350 * Special case: HbaSelect == 0 is physical ha 351 */ 352 if (cmd->HbaSelect != 0) { 353 vha = ha->vp_next; 354 while (vha != NULL) { 355 if (vha->vp_index == cmd->HbaSelect) { 356 ha = vha; 357 break; 358 } 359 vha = vha->vp_next; 360 } 361 362 /* 363 * If we can't find the specified vp index then 364 * we probably have an error (vp indexes shifting 365 * under our feet?). 366 */ 367 if (vha == NULL) { 368 EL(ha, "Invalid HbaSelect vp index: %xh\n", 369 cmd->HbaSelect); 370 cmd->Status = EXT_STATUS_INVALID_VPINDEX; 371 cmd->ResponseLen = 0; 372 return (EFAULT); 373 } 374 } 375 } 376 377 /* 378 * If driver is suspended, stalled, or powered down rtn BUSY 379 */ 380 if (ha->flags & ADAPTER_SUSPENDED || 381 ha->task_daemon_flags & DRIVER_STALL || 382 ha->power_level != PM_LEVEL_D0) { 383 EL(ha, " %s\n", ha->flags & ADAPTER_SUSPENDED ? 384 "driver suspended" : 385 (ha->task_daemon_flags & DRIVER_STALL ? "driver stalled" : 386 "FCA powered down")); 387 cmd->Status = EXT_STATUS_BUSY; 388 cmd->ResponseLen = 0; 389 rval = EBUSY; 390 391 /* Return results to caller */ 392 if ((ql_sdm_return(ha, cmd, arg, mode)) == -1) { 393 EL(ha, "failed, sdm_return\n"); 394 rval = EFAULT; 395 } 396 return (rval); 397 } 398 399 switch (ioctl_code) { 400 case EXT_CC_QUERY_OS: 401 ql_query(ha, cmd, mode); 402 break; 403 case EXT_CC_SEND_FCCT_PASSTHRU_OS: 404 ql_fcct(ha, cmd, mode); 405 break; 406 case EXT_CC_REG_AEN_OS: 407 ql_aen_reg(ha, cmd, mode); 408 break; 409 case EXT_CC_GET_AEN_OS: 410 ql_aen_get(ha, cmd, mode); 411 break; 412 case EXT_CC_GET_DATA_OS: 413 ql_get_host_data(ha, cmd, mode); 414 break; 415 case EXT_CC_SET_DATA_OS: 416 ql_set_host_data(ha, cmd, mode); 417 break; 418 case EXT_CC_SEND_ELS_RNID_OS: 419 ql_send_els_rnid(ha, cmd, mode); 420 break; 421 case EXT_CC_SCSI_PASSTHRU_OS: 422 ql_scsi_passthru(ha, cmd, mode); 423 break; 424 case EXT_CC_WWPN_TO_SCSIADDR_OS: 425 ql_wwpn_to_scsiaddr(ha, cmd, mode); 426 break; 427 case EXT_CC_HOST_IDX_OS: 428 ql_host_idx(ha, cmd, mode); 429 break; 430 case EXT_CC_HOST_DRVNAME_OS: 431 ql_host_drvname(ha, cmd, mode); 432 break; 433 case EXT_CC_READ_NVRAM_OS: 434 ql_read_nvram(ha, cmd, mode); 435 break; 436 case EXT_CC_UPDATE_NVRAM_OS: 437 ql_write_nvram(ha, cmd, mode); 438 break; 439 case EXT_CC_READ_OPTION_ROM_OS: 440 case EXT_CC_READ_OPTION_ROM_EX_OS: 441 ql_read_flash(ha, cmd, mode); 442 break; 443 case EXT_CC_UPDATE_OPTION_ROM_OS: 444 case EXT_CC_UPDATE_OPTION_ROM_EX_OS: 445 ql_write_flash(ha, cmd, mode); 446 break; 447 case EXT_CC_LOOPBACK_OS: 448 ql_diagnostic_loopback(ha, cmd, mode); 449 break; 450 case EXT_CC_GET_VPD_OS: 451 ql_read_vpd(ha, cmd, mode); 452 break; 453 case EXT_CC_SET_VPD_OS: 454 ql_write_vpd(ha, cmd, mode); 455 break; 456 case EXT_CC_GET_FCACHE_OS: 457 ql_get_fcache(ha, cmd, mode); 458 break; 459 case EXT_CC_GET_FCACHE_EX_OS: 460 ql_get_fcache_ex(ha, cmd, mode); 461 break; 462 case EXT_CC_GET_SFP_DATA_OS: 463 ql_get_sfp(ha, cmd, mode); 464 break; 465 case EXT_CC_PORT_PARAM_OS: 466 ql_port_param(ha, cmd, mode); 467 break; 468 case EXT_CC_GET_PCI_DATA_OS: 469 ql_get_pci_data(ha, cmd, mode); 470 break; 471 case EXT_CC_GET_FWEXTTRACE_OS: 472 ql_get_fwexttrace(ha, cmd, mode); 473 break; 474 case EXT_CC_GET_FWFCETRACE_OS: 475 ql_get_fwfcetrace(ha, cmd, mode); 476 break; 477 case EXT_CC_MENLO_RESET: 478 ql_menlo_reset(ha, cmd, mode); 479 break; 480 case EXT_CC_MENLO_GET_FW_VERSION: 481 ql_menlo_get_fw_version(ha, cmd, mode); 482 break; 483 case EXT_CC_MENLO_UPDATE_FW: 484 ql_menlo_update_fw(ha, cmd, mode); 485 break; 486 case EXT_CC_MENLO_MANAGE_INFO: 487 ql_menlo_manage_info(ha, cmd, mode); 488 break; 489 case EXT_CC_GET_VP_CNT_ID_OS: 490 ql_get_vp_cnt_id(ha, cmd, mode); 491 break; 492 case EXT_CC_VPORT_CMD_OS: 493 ql_vp_ioctl(ha, cmd, mode); 494 break; 495 default: 496 /* function not supported. */ 497 EL(ha, "failed, function not supported=%d\n", ioctl_code); 498 499 cmd->Status = EXT_STATUS_INVALID_REQUEST; 500 cmd->ResponseLen = 0; 501 break; 502 } 503 504 /* Return results to caller */ 505 if (ql_sdm_return(ha, cmd, arg, mode) == -1) { 506 EL(ha, "failed, sdm_return\n"); 507 return (EFAULT); 508 } 509 510 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 511 512 return (0); 513 } 514 515 /* 516 * ql_sdm_setup 517 * Make a local copy of the EXT_IOCTL struct and validate it. 518 * 519 * Input: 520 * ha: adapter state pointer. 521 * cmd_struct: Pointer to location to store local adrs of EXT_IOCTL. 522 * arg: Address of application EXT_IOCTL cmd data 523 * mode: flags 524 * val_sig: Pointer to a function to validate the ioctl signature. 525 * 526 * Returns: 527 * 0: success 528 * EFAULT: Copy in error of application EXT_IOCTL struct. 529 * EINVAL: Invalid version, signature. 530 * ENOMEM: Local allocation of EXT_IOCTL failed. 531 * 532 * Context: 533 * Kernel context. 534 */ 535 static int 536 ql_sdm_setup(ql_adapter_state_t *ha, EXT_IOCTL **cmd_struct, void *arg, 537 int mode, boolean_t (*val_sig)(EXT_IOCTL *)) 538 { 539 int rval; 540 EXT_IOCTL *cmd; 541 542 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 543 544 /* Allocate local memory for EXT_IOCTL. */ 545 *cmd_struct = NULL; 546 cmd = (EXT_IOCTL *)kmem_zalloc(sizeof (EXT_IOCTL), KM_SLEEP); 547 if (cmd == NULL) { 548 EL(ha, "failed, kmem_zalloc\n"); 549 return (ENOMEM); 550 } 551 /* Get argument structure. */ 552 rval = ddi_copyin(arg, (void *)cmd, sizeof (EXT_IOCTL), mode); 553 if (rval != 0) { 554 EL(ha, "failed, ddi_copyin\n"); 555 rval = EFAULT; 556 } else { 557 /* 558 * Check signature and the version. 559 * If either are not valid then neither is the 560 * structure so don't attempt to return any error status 561 * because we can't trust what caller's arg points to. 562 * Just return the errno. 563 */ 564 if (val_sig(cmd) == 0) { 565 EL(ha, "failed, signature\n"); 566 rval = EINVAL; 567 } else if (cmd->Version > EXT_VERSION) { 568 EL(ha, "failed, version\n"); 569 rval = EINVAL; 570 } 571 } 572 573 if (rval == 0) { 574 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 575 *cmd_struct = cmd; 576 cmd->Status = EXT_STATUS_OK; 577 cmd->DetailStatus = 0; 578 } else { 579 kmem_free((void *)cmd, sizeof (EXT_IOCTL)); 580 } 581 582 return (rval); 583 } 584 585 /* 586 * ql_validate_signature 587 * Validate the signature string for an external ioctl call. 588 * 589 * Input: 590 * sg: Pointer to EXT_IOCTL signature to validate. 591 * 592 * Returns: 593 * B_TRUE: Signature is valid. 594 * B_FALSE: Signature is NOT valid. 595 * 596 * Context: 597 * Kernel context. 598 */ 599 static boolean_t 600 ql_validate_signature(EXT_IOCTL *cmd_struct) 601 { 602 /* 603 * Check signature. 604 * 605 * If signature is not valid then neither is the rest of 606 * the structure (e.g., can't trust it), so don't attempt 607 * to return any error status other than the errno. 608 */ 609 if (bcmp(&cmd_struct->Signature, "QLOGIC", 6) != 0) { 610 QL_PRINT_2(CE_CONT, "failed,\n"); 611 return (B_FALSE); 612 } 613 614 return (B_TRUE); 615 } 616 617 /* 618 * ql_sdm_return 619 * Copies return data/status to application land for 620 * ioctl call using the SAN/Device Management EXT_IOCTL call interface. 621 * 622 * Input: 623 * ha: adapter state pointer. 624 * cmd: Pointer to kernel copy of requestor's EXT_IOCTL struct. 625 * ioctl_code: ioctl function to perform 626 * arg: EXT_IOCTL cmd data in application land. 627 * mode: flags 628 * 629 * Returns: 630 * 0: success 631 * EFAULT: Copy out error. 632 * 633 * Context: 634 * Kernel context. 635 */ 636 /* ARGSUSED */ 637 static int 638 ql_sdm_return(ql_adapter_state_t *ha, EXT_IOCTL *cmd, void *arg, int mode) 639 { 640 int rval = 0; 641 642 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 643 644 rval |= ddi_copyout((void *)&cmd->ResponseLen, 645 (void *)&(((EXT_IOCTL*)arg)->ResponseLen), sizeof (uint32_t), 646 mode); 647 648 rval |= ddi_copyout((void *)&cmd->Status, 649 (void *)&(((EXT_IOCTL*)arg)->Status), 650 sizeof (cmd->Status), mode); 651 rval |= ddi_copyout((void *)&cmd->DetailStatus, 652 (void *)&(((EXT_IOCTL*)arg)->DetailStatus), 653 sizeof (cmd->DetailStatus), mode); 654 655 kmem_free((void *)cmd, sizeof (EXT_IOCTL)); 656 657 if (rval != 0) { 658 /* Some copyout operation failed */ 659 EL(ha, "failed, ddi_copyout\n"); 660 return (EFAULT); 661 } 662 663 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 664 665 return (0); 666 } 667 668 /* 669 * ql_query 670 * Performs all EXT_CC_QUERY functions. 671 * 672 * Input: 673 * ha: adapter state pointer. 674 * cmd: Local EXT_IOCTL cmd struct pointer. 675 * mode: flags. 676 * 677 * Returns: 678 * None, request status indicated in cmd->Status. 679 * 680 * Context: 681 * Kernel context. 682 */ 683 static void 684 ql_query(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 685 { 686 QL_PRINT_9(CE_CONT, "(%d): entered, cmd=%d\n", ha->instance, 687 cmd->SubCode); 688 689 /* case off on command subcode */ 690 switch (cmd->SubCode) { 691 case EXT_SC_QUERY_HBA_NODE: 692 ql_qry_hba_node(ha, cmd, mode); 693 break; 694 case EXT_SC_QUERY_HBA_PORT: 695 ql_qry_hba_port(ha, cmd, mode); 696 break; 697 case EXT_SC_QUERY_DISC_PORT: 698 ql_qry_disc_port(ha, cmd, mode); 699 break; 700 case EXT_SC_QUERY_DISC_TGT: 701 ql_qry_disc_tgt(ha, cmd, mode); 702 break; 703 case EXT_SC_QUERY_DRIVER: 704 ql_qry_driver(ha, cmd, mode); 705 break; 706 case EXT_SC_QUERY_FW: 707 ql_qry_fw(ha, cmd, mode); 708 break; 709 case EXT_SC_QUERY_CHIP: 710 ql_qry_chip(ha, cmd, mode); 711 break; 712 case EXT_SC_QUERY_DISC_LUN: 713 default: 714 /* function not supported. */ 715 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 716 EL(ha, "failed, Unsupported Subcode=%xh\n", 717 cmd->SubCode); 718 break; 719 } 720 721 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 722 } 723 724 /* 725 * ql_qry_hba_node 726 * Performs EXT_SC_QUERY_HBA_NODE subfunction. 727 * 728 * Input: 729 * ha: adapter state pointer. 730 * cmd: EXT_IOCTL cmd struct pointer. 731 * mode: flags. 732 * 733 * Returns: 734 * None, request status indicated in cmd->Status. 735 * 736 * Context: 737 * Kernel context. 738 */ 739 static void 740 ql_qry_hba_node(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 741 { 742 EXT_HBA_NODE tmp_node = {0}; 743 uint_t len; 744 caddr_t bufp; 745 ql_mbx_data_t mr; 746 747 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 748 749 if (cmd->ResponseLen < sizeof (EXT_HBA_NODE)) { 750 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 751 cmd->DetailStatus = sizeof (EXT_HBA_NODE); 752 EL(ha, "failed, ResponseLen < EXT_HBA_NODE, " 753 "Len=%xh\n", cmd->ResponseLen); 754 cmd->ResponseLen = 0; 755 return; 756 } 757 758 /* fill in the values */ 759 760 bcopy(ha->loginparams.node_ww_name.raw_wwn, tmp_node.WWNN, 761 EXT_DEF_WWN_NAME_SIZE); 762 763 (void) sprintf((char *)(tmp_node.Manufacturer), "QLogic Corporation"); 764 765 (void) sprintf((char *)(tmp_node.Model), "%x", ha->device_id); 766 767 bcopy(&tmp_node.WWNN[5], tmp_node.SerialNum, 3); 768 769 (void) sprintf((char *)(tmp_node.DriverVersion), QL_VERSION); 770 771 if (CFG_IST(ha, CFG_SBUS_CARD)) { 772 size_t verlen; 773 uint16_t w; 774 char *tmpptr; 775 776 verlen = strlen((char *)(tmp_node.DriverVersion)); 777 if (verlen + 5 > EXT_DEF_MAX_STR_SIZE) { 778 EL(ha, "failed, No room for fpga version string\n"); 779 } else { 780 w = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle, 781 (uint16_t *) 782 (ha->sbus_fpga_iobase + FPGA_REVISION)); 783 784 tmpptr = (char *)&(tmp_node.DriverVersion[verlen+1]); 785 if (tmpptr == NULL) { 786 EL(ha, "Unable to insert fpga version str\n"); 787 } else { 788 (void) sprintf(tmpptr, "%d.%d", 789 ((w & 0xf0) >> 4), (w & 0x0f)); 790 tmp_node.DriverAttr |= EXT_CC_HBA_NODE_SBUS; 791 } 792 } 793 } 794 (void) ql_get_fw_version(ha, &mr); 795 796 (void) sprintf((char *)(tmp_node.FWVersion), "%01d.%02d.%02d", 797 mr.mb[1], mr.mb[2], mr.mb[3]); 798 799 if ((CFG_IST(ha, CFG_CTRL_2425)) == 0) { 800 switch (mr.mb[6]) { 801 case FWATTRIB_EF: 802 (void) strcat((char *)(tmp_node.FWVersion), " EF"); 803 break; 804 case FWATTRIB_TP: 805 (void) strcat((char *)(tmp_node.FWVersion), " TP"); 806 break; 807 case FWATTRIB_IP: 808 (void) strcat((char *)(tmp_node.FWVersion), " IP"); 809 break; 810 case FWATTRIB_IPX: 811 (void) strcat((char *)(tmp_node.FWVersion), " IPX"); 812 break; 813 case FWATTRIB_FL: 814 (void) strcat((char *)(tmp_node.FWVersion), " FL"); 815 break; 816 case FWATTRIB_FPX: 817 (void) strcat((char *)(tmp_node.FWVersion), " FLX"); 818 break; 819 default: 820 break; 821 } 822 } 823 824 /* FCode version. */ 825 /*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/ 826 if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip, PROP_LEN_AND_VAL_ALLOC | 827 DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp, 828 (int *)&len) == DDI_PROP_SUCCESS) { 829 if (len < EXT_DEF_MAX_STR_SIZE) { 830 bcopy(bufp, tmp_node.OptRomVersion, len); 831 } else { 832 bcopy(bufp, tmp_node.OptRomVersion, 833 EXT_DEF_MAX_STR_SIZE - 1); 834 tmp_node.OptRomVersion[EXT_DEF_MAX_STR_SIZE - 1] = 835 '\0'; 836 } 837 kmem_free(bufp, len); 838 } else { 839 (void) sprintf((char *)tmp_node.OptRomVersion, "0"); 840 } 841 tmp_node.PortCount = 1; 842 tmp_node.InterfaceType = EXT_DEF_FC_INTF_TYPE; 843 844 if (ddi_copyout((void *)&tmp_node, 845 (void *)(uintptr_t)(cmd->ResponseAdr), 846 sizeof (EXT_HBA_NODE), mode) != 0) { 847 cmd->Status = EXT_STATUS_COPY_ERR; 848 cmd->ResponseLen = 0; 849 EL(ha, "failed, ddi_copyout\n"); 850 } else { 851 cmd->ResponseLen = sizeof (EXT_HBA_NODE); 852 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 853 } 854 } 855 856 /* 857 * ql_qry_hba_port 858 * Performs EXT_SC_QUERY_HBA_PORT subfunction. 859 * 860 * Input: 861 * ha: adapter state pointer. 862 * cmd: EXT_IOCTL cmd struct pointer. 863 * mode: flags. 864 * 865 * Returns: 866 * None, request status indicated in cmd->Status. 867 * 868 * Context: 869 * Kernel context. 870 */ 871 static void 872 ql_qry_hba_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 873 { 874 ql_link_t *link; 875 ql_tgt_t *tq; 876 ql_mbx_data_t mr; 877 EXT_HBA_PORT tmp_port = {0}; 878 int rval; 879 uint16_t port_cnt, tgt_cnt, index; 880 881 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 882 883 if (cmd->ResponseLen < sizeof (EXT_HBA_PORT)) { 884 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 885 cmd->DetailStatus = sizeof (EXT_HBA_PORT); 886 EL(ha, "failed, ResponseLen < EXT_HBA_NODE, Len=%xh\n", 887 cmd->ResponseLen); 888 cmd->ResponseLen = 0; 889 return; 890 } 891 892 /* fill in the values */ 893 894 bcopy(ha->loginparams.nport_ww_name.raw_wwn, tmp_port.WWPN, 895 EXT_DEF_WWN_NAME_SIZE); 896 tmp_port.Id[0] = 0; 897 tmp_port.Id[1] = ha->d_id.b.domain; 898 tmp_port.Id[2] = ha->d_id.b.area; 899 tmp_port.Id[3] = ha->d_id.b.al_pa; 900 901 /* For now we are initiator only driver */ 902 tmp_port.Type = EXT_DEF_INITIATOR_DEV; 903 904 if (ha->task_daemon_flags & LOOP_DOWN) { 905 tmp_port.State = EXT_DEF_HBA_LOOP_DOWN; 906 } else if (DRIVER_SUSPENDED(ha)) { 907 tmp_port.State = EXT_DEF_HBA_SUSPENDED; 908 } else { 909 tmp_port.State = EXT_DEF_HBA_OK; 910 } 911 912 if (ha->flags & POINT_TO_POINT) { 913 tmp_port.Mode = EXT_DEF_P2P_MODE; 914 } else { 915 tmp_port.Mode = EXT_DEF_LOOP_MODE; 916 } 917 /* 918 * fill in the portspeed values. 919 * 920 * default to not yet negotiated state 921 */ 922 tmp_port.PortSpeed = EXT_PORTSPEED_NOT_NEGOTIATED; 923 924 if (tmp_port.State == EXT_DEF_HBA_OK) { 925 if ((CFG_IST(ha, CFG_CTRL_2200)) == 0) { 926 mr.mb[1] = 0; 927 mr.mb[2] = 0; 928 rval = ql_data_rate(ha, &mr); 929 if (rval != QL_SUCCESS) { 930 EL(ha, "failed, data_rate=%xh\n", rval); 931 } else { 932 switch (mr.mb[1]) { 933 case 0: 934 tmp_port.PortSpeed = 935 EXT_DEF_PORTSPEED_1GBIT; 936 break; 937 case 1: 938 tmp_port.PortSpeed = 939 EXT_DEF_PORTSPEED_2GBIT; 940 break; 941 case 3: 942 tmp_port.PortSpeed = 943 EXT_DEF_PORTSPEED_4GBIT; 944 break; 945 case 4: 946 tmp_port.PortSpeed = 947 EXT_DEF_PORTSPEED_8GBIT; 948 break; 949 default: 950 tmp_port.PortSpeed = 951 EXT_DEF_PORTSPEED_UNKNOWN; 952 EL(ha, "failed, data rate=%xh\n", 953 mr.mb[1]); 954 break; 955 } 956 } 957 } else { 958 tmp_port.PortSpeed = EXT_DEF_PORTSPEED_1GBIT; 959 } 960 } 961 962 /* Report all supported port speeds */ 963 if (CFG_IST(ha, CFG_CTRL_25XX)) { 964 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_8GBIT | 965 EXT_DEF_PORTSPEED_4GBIT | EXT_DEF_PORTSPEED_2GBIT | 966 EXT_DEF_PORTSPEED_1GBIT); 967 /* 968 * Correct supported speeds based on type of 969 * sfp that is present 970 */ 971 switch (ha->sfp_stat) { 972 case 1: 973 /* no sfp detected */ 974 break; 975 case 2: 976 case 4: 977 /* 4GB sfp */ 978 tmp_port.PortSupportedSpeed &= 979 ~EXT_DEF_PORTSPEED_8GBIT; 980 break; 981 case 3: 982 case 5: 983 /* 8GB sfp */ 984 tmp_port.PortSupportedSpeed &= 985 ~EXT_DEF_PORTSPEED_1GBIT; 986 break; 987 default: 988 EL(ha, "sfp_stat: %xh\n", ha->sfp_stat); 989 break; 990 991 } 992 } else if (CFG_IST(ha, CFG_CTRL_2422)) { 993 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_4GBIT | 994 EXT_DEF_PORTSPEED_2GBIT | EXT_DEF_PORTSPEED_1GBIT); 995 } else if (CFG_IST(ha, CFG_CTRL_2300)) { 996 tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_2GBIT | 997 EXT_DEF_PORTSPEED_1GBIT); 998 } else if (CFG_IST(ha, CFG_CTRL_6322)) { 999 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_2GBIT; 1000 } else if (CFG_IST(ha, CFG_CTRL_2200)) { 1001 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_1GBIT; 1002 } else { 1003 tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_UNKNOWN; 1004 EL(ha, "unknown HBA type: %xh\n", ha->device_id); 1005 } 1006 tmp_port.sfp_status = LSB(ha->sfp_stat); 1007 port_cnt = 0; 1008 tgt_cnt = 0; 1009 1010 for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) { 1011 for (link = ha->dev[index].first; link != NULL; 1012 link = link->next) { 1013 tq = link->base_address; 1014 1015 if (!VALID_TARGET_ID(ha, tq->loop_id)) { 1016 continue; 1017 } 1018 1019 port_cnt++; 1020 if ((tq->flags & TQF_INITIATOR_DEVICE) == 0) { 1021 tgt_cnt++; 1022 } 1023 } 1024 } 1025 1026 tmp_port.DiscPortCount = port_cnt; 1027 tmp_port.DiscTargetCount = tgt_cnt; 1028 1029 tmp_port.DiscPortNameType = EXT_DEF_USE_NODE_NAME; 1030 1031 rval = ddi_copyout((void *)&tmp_port, 1032 (void *)(uintptr_t)(cmd->ResponseAdr), 1033 sizeof (EXT_HBA_PORT), mode); 1034 if (rval != 0) { 1035 cmd->Status = EXT_STATUS_COPY_ERR; 1036 cmd->ResponseLen = 0; 1037 EL(ha, "failed, ddi_copyout\n"); 1038 } else { 1039 cmd->ResponseLen = sizeof (EXT_HBA_PORT); 1040 QL_PRINT_9(CE_CONT, "(%d): exiting, ports=%d, targets=%d\n", 1041 ha->instance, port_cnt, tgt_cnt); 1042 } 1043 } 1044 1045 /* 1046 * ql_qry_disc_port 1047 * Performs EXT_SC_QUERY_DISC_PORT subfunction. 1048 * 1049 * Input: 1050 * ha: adapter state pointer. 1051 * cmd: EXT_IOCTL cmd struct pointer. 1052 * mode: flags. 1053 * 1054 * cmd->Instance = Port instance in fcport chain. 1055 * 1056 * Returns: 1057 * None, request status indicated in cmd->Status. 1058 * 1059 * Context: 1060 * Kernel context. 1061 */ 1062 static void 1063 ql_qry_disc_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1064 { 1065 EXT_DISC_PORT tmp_port = {0}; 1066 ql_link_t *link; 1067 ql_tgt_t *tq; 1068 uint16_t index; 1069 uint16_t inst = 0; 1070 1071 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1072 1073 if (cmd->ResponseLen < sizeof (EXT_DISC_PORT)) { 1074 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 1075 cmd->DetailStatus = sizeof (EXT_DISC_PORT); 1076 EL(ha, "failed, ResponseLen < EXT_DISC_PORT, Len=%xh\n", 1077 cmd->ResponseLen); 1078 cmd->ResponseLen = 0; 1079 return; 1080 } 1081 1082 for (link = NULL, index = 0; 1083 index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) { 1084 for (link = ha->dev[index].first; link != NULL; 1085 link = link->next) { 1086 tq = link->base_address; 1087 1088 if (!VALID_TARGET_ID(ha, tq->loop_id)) { 1089 continue; 1090 } 1091 if (inst != cmd->Instance) { 1092 inst++; 1093 continue; 1094 } 1095 1096 /* fill in the values */ 1097 bcopy(tq->node_name, tmp_port.WWNN, 1098 EXT_DEF_WWN_NAME_SIZE); 1099 bcopy(tq->port_name, tmp_port.WWPN, 1100 EXT_DEF_WWN_NAME_SIZE); 1101 1102 break; 1103 } 1104 } 1105 1106 if (link == NULL) { 1107 /* no matching device */ 1108 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 1109 EL(ha, "failed, port not found port=%d\n", cmd->Instance); 1110 cmd->ResponseLen = 0; 1111 return; 1112 } 1113 1114 tmp_port.Id[0] = 0; 1115 tmp_port.Id[1] = tq->d_id.b.domain; 1116 tmp_port.Id[2] = tq->d_id.b.area; 1117 tmp_port.Id[3] = tq->d_id.b.al_pa; 1118 1119 tmp_port.Type = 0; 1120 if (tq->flags & TQF_INITIATOR_DEVICE) { 1121 tmp_port.Type = (uint16_t)(tmp_port.Type | 1122 EXT_DEF_INITIATOR_DEV); 1123 } else if ((tq->flags & TQF_TAPE_DEVICE) == 0) { 1124 (void) ql_inq_scan(ha, tq, 1); 1125 } else if (tq->flags & TQF_TAPE_DEVICE) { 1126 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TAPE_DEV); 1127 } 1128 1129 if (tq->flags & TQF_FABRIC_DEVICE) { 1130 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_FABRIC_DEV); 1131 } else { 1132 tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TARGET_DEV); 1133 } 1134 1135 tmp_port.Status = 0; 1136 tmp_port.Bus = 0; /* Hard-coded for Solaris */ 1137 1138 bcopy(tq->port_name, &tmp_port.TargetId, 8); 1139 1140 if (ddi_copyout((void *)&tmp_port, 1141 (void *)(uintptr_t)(cmd->ResponseAdr), 1142 sizeof (EXT_DISC_PORT), mode) != 0) { 1143 cmd->Status = EXT_STATUS_COPY_ERR; 1144 cmd->ResponseLen = 0; 1145 EL(ha, "failed, ddi_copyout\n"); 1146 } else { 1147 cmd->ResponseLen = sizeof (EXT_DISC_PORT); 1148 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1149 } 1150 } 1151 1152 /* 1153 * ql_qry_disc_tgt 1154 * Performs EXT_SC_QUERY_DISC_TGT subfunction. 1155 * 1156 * Input: 1157 * ha: adapter state pointer. 1158 * cmd: EXT_IOCTL cmd struct pointer. 1159 * mode: flags. 1160 * 1161 * cmd->Instance = Port instance in fcport chain. 1162 * 1163 * Returns: 1164 * None, request status indicated in cmd->Status. 1165 * 1166 * Context: 1167 * Kernel context. 1168 */ 1169 static void 1170 ql_qry_disc_tgt(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1171 { 1172 EXT_DISC_TARGET tmp_tgt = {0}; 1173 ql_link_t *link; 1174 ql_tgt_t *tq; 1175 uint16_t index; 1176 uint16_t inst = 0; 1177 1178 QL_PRINT_9(CE_CONT, "(%d): entered, target=%d\n", ha->instance, 1179 cmd->Instance); 1180 1181 if (cmd->ResponseLen < sizeof (EXT_DISC_TARGET)) { 1182 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 1183 cmd->DetailStatus = sizeof (EXT_DISC_TARGET); 1184 EL(ha, "failed, ResponseLen < EXT_DISC_TARGET, Len=%xh\n", 1185 cmd->ResponseLen); 1186 cmd->ResponseLen = 0; 1187 return; 1188 } 1189 1190 /* Scan port list for requested target and fill in the values */ 1191 for (link = NULL, index = 0; 1192 index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) { 1193 for (link = ha->dev[index].first; link != NULL; 1194 link = link->next) { 1195 tq = link->base_address; 1196 1197 if (!VALID_TARGET_ID(ha, tq->loop_id) || 1198 tq->flags & TQF_INITIATOR_DEVICE) { 1199 continue; 1200 } 1201 if (inst != cmd->Instance) { 1202 inst++; 1203 continue; 1204 } 1205 1206 /* fill in the values */ 1207 bcopy(tq->node_name, tmp_tgt.WWNN, 1208 EXT_DEF_WWN_NAME_SIZE); 1209 bcopy(tq->port_name, tmp_tgt.WWPN, 1210 EXT_DEF_WWN_NAME_SIZE); 1211 1212 break; 1213 } 1214 } 1215 1216 if (link == NULL) { 1217 /* no matching device */ 1218 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 1219 cmd->DetailStatus = EXT_DSTATUS_TARGET; 1220 EL(ha, "failed, not found target=%d\n", cmd->Instance); 1221 cmd->ResponseLen = 0; 1222 return; 1223 } 1224 tmp_tgt.Id[0] = 0; 1225 tmp_tgt.Id[1] = tq->d_id.b.domain; 1226 tmp_tgt.Id[2] = tq->d_id.b.area; 1227 tmp_tgt.Id[3] = tq->d_id.b.al_pa; 1228 1229 tmp_tgt.LunCount = (uint16_t)ql_lun_count(ha, tq); 1230 1231 if ((tq->flags & TQF_TAPE_DEVICE) == 0) { 1232 (void) ql_inq_scan(ha, tq, 1); 1233 } 1234 1235 tmp_tgt.Type = 0; 1236 if (tq->flags & TQF_TAPE_DEVICE) { 1237 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TAPE_DEV); 1238 } 1239 1240 if (tq->flags & TQF_FABRIC_DEVICE) { 1241 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_FABRIC_DEV); 1242 } else { 1243 tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TARGET_DEV); 1244 } 1245 1246 tmp_tgt.Status = 0; 1247 1248 tmp_tgt.Bus = 0; /* Hard-coded for Solaris. */ 1249 1250 bcopy(tq->port_name, &tmp_tgt.TargetId, 8); 1251 1252 if (ddi_copyout((void *)&tmp_tgt, 1253 (void *)(uintptr_t)(cmd->ResponseAdr), 1254 sizeof (EXT_DISC_TARGET), mode) != 0) { 1255 cmd->Status = EXT_STATUS_COPY_ERR; 1256 cmd->ResponseLen = 0; 1257 EL(ha, "failed, ddi_copyout\n"); 1258 } else { 1259 cmd->ResponseLen = sizeof (EXT_DISC_TARGET); 1260 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1261 } 1262 } 1263 1264 /* 1265 * ql_qry_fw 1266 * Performs EXT_SC_QUERY_FW subfunction. 1267 * 1268 * Input: 1269 * ha: adapter state pointer. 1270 * cmd: EXT_IOCTL cmd struct pointer. 1271 * mode: flags. 1272 * 1273 * Returns: 1274 * None, request status indicated in cmd->Status. 1275 * 1276 * Context: 1277 * Kernel context. 1278 */ 1279 static void 1280 ql_qry_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1281 { 1282 ql_mbx_data_t mr; 1283 EXT_FW fw_info = {0}; 1284 1285 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1286 1287 if (cmd->ResponseLen < sizeof (EXT_FW)) { 1288 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 1289 cmd->DetailStatus = sizeof (EXT_FW); 1290 EL(ha, "failed, ResponseLen < EXT_FW, Len=%xh\n", 1291 cmd->ResponseLen); 1292 cmd->ResponseLen = 0; 1293 return; 1294 } 1295 1296 (void) ql_get_fw_version(ha, &mr); 1297 1298 (void) sprintf((char *)(fw_info.Version), "%d.%d.%d", mr.mb[1], 1299 mr.mb[2], mr.mb[2]); 1300 1301 fw_info.Attrib = mr.mb[6]; 1302 1303 if (ddi_copyout((void *)&fw_info, 1304 (void *)(uintptr_t)(cmd->ResponseAdr), 1305 sizeof (EXT_FW), mode) != 0) { 1306 cmd->Status = EXT_STATUS_COPY_ERR; 1307 cmd->ResponseLen = 0; 1308 EL(ha, "failed, ddi_copyout\n"); 1309 return; 1310 } else { 1311 cmd->ResponseLen = sizeof (EXT_FW); 1312 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1313 } 1314 } 1315 1316 /* 1317 * ql_qry_chip 1318 * Performs EXT_SC_QUERY_CHIP subfunction. 1319 * 1320 * Input: 1321 * ha: adapter state pointer. 1322 * cmd: EXT_IOCTL cmd struct pointer. 1323 * mode: flags. 1324 * 1325 * Returns: 1326 * None, request status indicated in cmd->Status. 1327 * 1328 * Context: 1329 * Kernel context. 1330 */ 1331 static void 1332 ql_qry_chip(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1333 { 1334 EXT_CHIP chip = {0}; 1335 1336 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1337 1338 if (cmd->ResponseLen < sizeof (EXT_CHIP)) { 1339 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 1340 cmd->DetailStatus = sizeof (EXT_CHIP); 1341 EL(ha, "failed, ResponseLen < EXT_CHIP, Len=%xh\n", 1342 cmd->ResponseLen); 1343 cmd->ResponseLen = 0; 1344 return; 1345 } 1346 1347 chip.VendorId = ha->ven_id; 1348 chip.DeviceId = ha->device_id; 1349 chip.SubVendorId = ha->subven_id; 1350 chip.SubSystemId = ha->subsys_id; 1351 chip.IoAddr = ql_pci_config_get32(ha, PCI_CONF_BASE0); 1352 chip.IoAddrLen = 0x100; 1353 chip.MemAddr = ql_pci_config_get32(ha, PCI_CONF_BASE1); 1354 chip.MemAddrLen = 0x100; 1355 chip.ChipRevID = ha->rev_id; 1356 1357 if (ddi_copyout((void *)&chip, 1358 (void *)(uintptr_t)(cmd->ResponseAdr), 1359 sizeof (EXT_CHIP), mode) != 0) { 1360 cmd->Status = EXT_STATUS_COPY_ERR; 1361 cmd->ResponseLen = 0; 1362 EL(ha, "failed, ddi_copyout\n"); 1363 } else { 1364 cmd->ResponseLen = sizeof (EXT_CHIP); 1365 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1366 } 1367 } 1368 1369 /* 1370 * ql_qry_driver 1371 * Performs EXT_SC_QUERY_DRIVER subfunction. 1372 * 1373 * Input: 1374 * ha: adapter state pointer. 1375 * cmd: EXT_IOCTL cmd struct pointer. 1376 * mode: flags. 1377 * 1378 * Returns: 1379 * None, request status indicated in cmd->Status. 1380 * 1381 * Context: 1382 * Kernel context. 1383 */ 1384 static void 1385 ql_qry_driver(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1386 { 1387 EXT_DRIVER qd = {0}; 1388 1389 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1390 1391 if (cmd->ResponseLen < sizeof (EXT_DRIVER)) { 1392 cmd->Status = EXT_STATUS_DATA_OVERRUN; 1393 cmd->DetailStatus = sizeof (EXT_DRIVER); 1394 EL(ha, "failed, ResponseLen < EXT_DRIVER, Len=%xh\n", 1395 cmd->ResponseLen); 1396 cmd->ResponseLen = 0; 1397 return; 1398 } 1399 1400 (void) strcpy((void *)&qd.Version[0], QL_VERSION); 1401 qd.NumOfBus = 1; /* Fixed for Solaris */ 1402 qd.TargetsPerBus = (uint16_t) 1403 (CFG_IST(ha, (CFG_CTRL_2425|CFG_EXT_FW_INTERFACE)) ? 1404 MAX_24_FIBRE_DEVICES : MAX_22_FIBRE_DEVICES); 1405 qd.LunsPerTarget = 2030; 1406 qd.MaxTransferLen = QL_DMA_MAX_XFER_SIZE; 1407 qd.MaxDataSegments = QL_DMA_SG_LIST_LENGTH; 1408 1409 if (ddi_copyout((void *)&qd, (void *)(uintptr_t)cmd->ResponseAdr, 1410 sizeof (EXT_DRIVER), mode) != 0) { 1411 cmd->Status = EXT_STATUS_COPY_ERR; 1412 cmd->ResponseLen = 0; 1413 EL(ha, "failed, ddi_copyout\n"); 1414 } else { 1415 cmd->ResponseLen = sizeof (EXT_DRIVER); 1416 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1417 } 1418 } 1419 1420 /* 1421 * ql_fcct 1422 * IOCTL management server FC-CT passthrough. 1423 * 1424 * Input: 1425 * ha: adapter state pointer. 1426 * cmd: User space CT arguments pointer. 1427 * mode: flags. 1428 * 1429 * Returns: 1430 * None, request status indicated in cmd->Status. 1431 * 1432 * Context: 1433 * Kernel context. 1434 */ 1435 static void 1436 ql_fcct(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1437 { 1438 ql_mbx_iocb_t *pkt; 1439 ql_mbx_data_t mr; 1440 dma_mem_t *dma_mem; 1441 caddr_t pld; 1442 uint32_t pkt_size, pld_byte_cnt, *long_ptr; 1443 int rval; 1444 ql_ct_iu_preamble_t *ct; 1445 ql_xioctl_t *xp = ha->xioctl; 1446 ql_tgt_t tq; 1447 uint16_t comp_status, loop_id; 1448 1449 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1450 1451 /* Get CT argument structure. */ 1452 if ((ha->topology & QL_SNS_CONNECTION) == 0) { 1453 EL(ha, "failed, No switch\n"); 1454 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 1455 cmd->ResponseLen = 0; 1456 return; 1457 } 1458 1459 if (DRIVER_SUSPENDED(ha)) { 1460 EL(ha, "failed, LOOP_NOT_READY\n"); 1461 cmd->Status = EXT_STATUS_BUSY; 1462 cmd->ResponseLen = 0; 1463 return; 1464 } 1465 1466 /* Login management server device. */ 1467 if ((xp->flags & QL_MGMT_SERVER_LOGIN) == 0) { 1468 tq.d_id.b.al_pa = 0xfa; 1469 tq.d_id.b.area = 0xff; 1470 tq.d_id.b.domain = 0xff; 1471 tq.loop_id = (uint16_t)(CFG_IST(ha, CFG_CTRL_2425) ? 1472 MANAGEMENT_SERVER_24XX_LOOP_ID : 1473 MANAGEMENT_SERVER_LOOP_ID); 1474 rval = ql_login_fport(ha, &tq, tq.loop_id, LFF_NO_PRLI, &mr); 1475 if (rval != QL_SUCCESS) { 1476 EL(ha, "failed, server login\n"); 1477 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 1478 cmd->ResponseLen = 0; 1479 return; 1480 } else { 1481 xp->flags |= QL_MGMT_SERVER_LOGIN; 1482 } 1483 } 1484 1485 QL_PRINT_9(CE_CONT, "(%d): cmd\n", ha->instance); 1486 QL_DUMP_9(cmd, 8, sizeof (EXT_IOCTL)); 1487 1488 /* Allocate a DMA Memory Descriptor */ 1489 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP); 1490 if (dma_mem == NULL) { 1491 EL(ha, "failed, kmem_zalloc\n"); 1492 cmd->Status = EXT_STATUS_NO_MEMORY; 1493 cmd->ResponseLen = 0; 1494 return; 1495 } 1496 /* Determine maximum buffer size. */ 1497 if (cmd->RequestLen < cmd->ResponseLen) { 1498 pld_byte_cnt = cmd->ResponseLen; 1499 } else { 1500 pld_byte_cnt = cmd->RequestLen; 1501 } 1502 1503 /* Allocate command block. */ 1504 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_byte_cnt); 1505 pkt = kmem_zalloc(pkt_size, KM_SLEEP); 1506 if (pkt == NULL) { 1507 EL(ha, "failed, kmem_zalloc\n"); 1508 cmd->Status = EXT_STATUS_NO_MEMORY; 1509 cmd->ResponseLen = 0; 1510 return; 1511 } 1512 pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t); 1513 1514 /* Get command payload data. */ 1515 if (ql_get_buffer_data((caddr_t)(uintptr_t)cmd->RequestAdr, pld, 1516 cmd->RequestLen, mode) != cmd->RequestLen) { 1517 EL(ha, "failed, get_buffer_data\n"); 1518 kmem_free(pkt, pkt_size); 1519 cmd->Status = EXT_STATUS_COPY_ERR; 1520 cmd->ResponseLen = 0; 1521 return; 1522 } 1523 1524 /* Get DMA memory for the IOCB */ 1525 if (ql_get_dma_mem(ha, dma_mem, pkt_size, LITTLE_ENDIAN_DMA, 1526 QL_DMA_RING_ALIGN) != QL_SUCCESS) { 1527 cmn_err(CE_WARN, "%s(%d): DMA memory " 1528 "alloc failed", QL_NAME, ha->instance); 1529 kmem_free(pkt, pkt_size); 1530 kmem_free(dma_mem, sizeof (dma_mem_t)); 1531 cmd->Status = EXT_STATUS_MS_NO_RESPONSE; 1532 cmd->ResponseLen = 0; 1533 return; 1534 } 1535 1536 /* Copy out going payload data to IOCB DMA buffer. */ 1537 ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld, 1538 (uint8_t *)dma_mem->bp, pld_byte_cnt, DDI_DEV_AUTOINCR); 1539 1540 /* Sync IOCB DMA buffer. */ 1541 (void) ddi_dma_sync(dma_mem->dma_handle, 0, pld_byte_cnt, 1542 DDI_DMA_SYNC_FORDEV); 1543 1544 /* 1545 * Setup IOCB 1546 */ 1547 ct = (ql_ct_iu_preamble_t *)pld; 1548 if (CFG_IST(ha, CFG_CTRL_2425)) { 1549 pkt->ms24.entry_type = CT_PASSTHRU_TYPE; 1550 pkt->ms24.entry_count = 1; 1551 1552 /* Set loop ID */ 1553 pkt->ms24.n_port_hdl = (uint16_t) 1554 (ct->gs_type == GS_TYPE_DIR_SERVER ? 1555 LE_16(SNS_24XX_HDL) : 1556 LE_16(MANAGEMENT_SERVER_24XX_LOOP_ID)); 1557 1558 /* Set ISP command timeout. */ 1559 pkt->ms24.timeout = LE_16(120); 1560 1561 /* Set cmd/response data segment counts. */ 1562 pkt->ms24.cmd_dseg_count = LE_16(1); 1563 pkt->ms24.resp_dseg_count = LE_16(1); 1564 1565 /* Load ct cmd byte count. */ 1566 pkt->ms24.cmd_byte_count = LE_32(cmd->RequestLen); 1567 1568 /* Load ct rsp byte count. */ 1569 pkt->ms24.resp_byte_count = LE_32(cmd->ResponseLen); 1570 1571 long_ptr = (uint32_t *)&pkt->ms24.dseg_0_address; 1572 1573 /* Load MS command entry data segments. */ 1574 *long_ptr++ = (uint32_t) 1575 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 1576 *long_ptr++ = (uint32_t) 1577 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 1578 *long_ptr++ = (uint32_t)(LE_32(cmd->RequestLen)); 1579 1580 /* Load MS response entry data segments. */ 1581 *long_ptr++ = (uint32_t) 1582 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 1583 *long_ptr++ = (uint32_t) 1584 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 1585 *long_ptr = (uint32_t)LE_32(cmd->ResponseLen); 1586 1587 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, 1588 sizeof (ql_mbx_iocb_t)); 1589 1590 comp_status = (uint16_t)LE_16(pkt->sts24.comp_status); 1591 if (comp_status == CS_DATA_UNDERRUN) { 1592 if ((BE_16(ct->max_residual_size)) == 0) { 1593 comp_status = CS_COMPLETE; 1594 } 1595 } 1596 1597 if (rval != QL_SUCCESS || (pkt->sts24.entry_status & 0x3c) != 1598 0) { 1599 EL(ha, "failed, I/O timeout or " 1600 "es=%xh, ss_l=%xh, rval=%xh\n", 1601 pkt->sts24.entry_status, 1602 pkt->sts24.scsi_status_l, rval); 1603 kmem_free(pkt, pkt_size); 1604 ql_free_dma_resource(ha, dma_mem); 1605 kmem_free(dma_mem, sizeof (dma_mem_t)); 1606 cmd->Status = EXT_STATUS_MS_NO_RESPONSE; 1607 cmd->ResponseLen = 0; 1608 return; 1609 } 1610 } else { 1611 pkt->ms.entry_type = MS_TYPE; 1612 pkt->ms.entry_count = 1; 1613 1614 /* Set loop ID */ 1615 loop_id = (uint16_t)(ct->gs_type == GS_TYPE_DIR_SERVER ? 1616 SIMPLE_NAME_SERVER_LOOP_ID : MANAGEMENT_SERVER_LOOP_ID); 1617 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 1618 pkt->ms.loop_id_l = LSB(loop_id); 1619 pkt->ms.loop_id_h = MSB(loop_id); 1620 } else { 1621 pkt->ms.loop_id_h = LSB(loop_id); 1622 } 1623 1624 /* Set ISP command timeout. */ 1625 pkt->ms.timeout = LE_16(120); 1626 1627 /* Set data segment counts. */ 1628 pkt->ms.cmd_dseg_count_l = 1; 1629 pkt->ms.total_dseg_count = LE_16(2); 1630 1631 /* Response total byte count. */ 1632 pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen); 1633 pkt->ms.dseg_1_length = LE_32(cmd->ResponseLen); 1634 1635 /* Command total byte count. */ 1636 pkt->ms.cmd_byte_count = LE_32(cmd->RequestLen); 1637 pkt->ms.dseg_0_length = LE_32(cmd->RequestLen); 1638 1639 /* Load command/response data segments. */ 1640 pkt->ms.dseg_0_address[0] = (uint32_t) 1641 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 1642 pkt->ms.dseg_0_address[1] = (uint32_t) 1643 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 1644 pkt->ms.dseg_1_address[0] = (uint32_t) 1645 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 1646 pkt->ms.dseg_1_address[1] = (uint32_t) 1647 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 1648 1649 rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, 1650 sizeof (ql_mbx_iocb_t)); 1651 1652 comp_status = (uint16_t)LE_16(pkt->sts.comp_status); 1653 if (comp_status == CS_DATA_UNDERRUN) { 1654 if ((BE_16(ct->max_residual_size)) == 0) { 1655 comp_status = CS_COMPLETE; 1656 } 1657 } 1658 if (rval != QL_SUCCESS || (pkt->sts.entry_status & 0x7e) != 0) { 1659 EL(ha, "failed, I/O timeout or " 1660 "es=%xh, rval=%xh\n", pkt->sts.entry_status, rval); 1661 kmem_free(pkt, pkt_size); 1662 ql_free_dma_resource(ha, dma_mem); 1663 kmem_free(dma_mem, sizeof (dma_mem_t)); 1664 cmd->Status = EXT_STATUS_MS_NO_RESPONSE; 1665 cmd->ResponseLen = 0; 1666 return; 1667 } 1668 } 1669 1670 /* Sync in coming DMA buffer. */ 1671 (void) ddi_dma_sync(dma_mem->dma_handle, 0, 1672 pld_byte_cnt, DDI_DMA_SYNC_FORKERNEL); 1673 /* Copy in coming DMA data. */ 1674 ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld, 1675 (uint8_t *)dma_mem->bp, pld_byte_cnt, 1676 DDI_DEV_AUTOINCR); 1677 1678 /* Copy response payload from DMA buffer to application. */ 1679 if (cmd->ResponseLen != 0) { 1680 QL_PRINT_9(CE_CONT, "(%d): ResponseLen=%d\n", ha->instance, 1681 cmd->ResponseLen); 1682 QL_DUMP_9(pld, 8, cmd->ResponseLen); 1683 1684 /* Send response payload. */ 1685 if (ql_send_buffer_data(pld, 1686 (caddr_t)(uintptr_t)cmd->ResponseAdr, 1687 cmd->ResponseLen, mode) != cmd->ResponseLen) { 1688 EL(ha, "failed, send_buffer_data\n"); 1689 cmd->Status = EXT_STATUS_COPY_ERR; 1690 cmd->ResponseLen = 0; 1691 } 1692 } 1693 1694 kmem_free(pkt, pkt_size); 1695 ql_free_dma_resource(ha, dma_mem); 1696 kmem_free(dma_mem, sizeof (dma_mem_t)); 1697 1698 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1699 } 1700 1701 /* 1702 * ql_aen_reg 1703 * IOCTL management server Asynchronous Event Tracking Enable/Disable. 1704 * 1705 * Input: 1706 * ha: adapter state pointer. 1707 * cmd: EXT_IOCTL cmd struct pointer. 1708 * mode: flags. 1709 * 1710 * Returns: 1711 * None, request status indicated in cmd->Status. 1712 * 1713 * Context: 1714 * Kernel context. 1715 */ 1716 static void 1717 ql_aen_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1718 { 1719 EXT_REG_AEN reg_struct; 1720 int rval = 0; 1721 ql_xioctl_t *xp = ha->xioctl; 1722 1723 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1724 1725 rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, ®_struct, 1726 cmd->RequestLen, mode); 1727 1728 if (rval == 0) { 1729 if (reg_struct.Enable) { 1730 xp->flags |= QL_AEN_TRACKING_ENABLE; 1731 } else { 1732 xp->flags &= ~QL_AEN_TRACKING_ENABLE; 1733 /* Empty the queue. */ 1734 INTR_LOCK(ha); 1735 xp->aen_q_head = 0; 1736 xp->aen_q_tail = 0; 1737 INTR_UNLOCK(ha); 1738 } 1739 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1740 } else { 1741 cmd->Status = EXT_STATUS_COPY_ERR; 1742 EL(ha, "failed, ddi_copyin\n"); 1743 } 1744 } 1745 1746 /* 1747 * ql_aen_get 1748 * IOCTL management server Asynchronous Event Record Transfer. 1749 * 1750 * Input: 1751 * ha: adapter state pointer. 1752 * cmd: EXT_IOCTL cmd struct pointer. 1753 * mode: flags. 1754 * 1755 * Returns: 1756 * None, request status indicated in cmd->Status. 1757 * 1758 * Context: 1759 * Kernel context. 1760 */ 1761 static void 1762 ql_aen_get(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1763 { 1764 uint32_t out_size; 1765 EXT_ASYNC_EVENT *tmp_q; 1766 EXT_ASYNC_EVENT aen[EXT_DEF_MAX_AEN_QUEUE]; 1767 uint8_t i; 1768 uint8_t queue_cnt; 1769 uint8_t request_cnt; 1770 ql_xioctl_t *xp = ha->xioctl; 1771 1772 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1773 1774 /* Compute the number of events that can be returned */ 1775 request_cnt = (uint8_t)(cmd->ResponseLen / sizeof (EXT_ASYNC_EVENT)); 1776 1777 if (request_cnt < EXT_DEF_MAX_AEN_QUEUE) { 1778 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 1779 cmd->DetailStatus = EXT_DEF_MAX_AEN_QUEUE; 1780 EL(ha, "failed, request_cnt < EXT_DEF_MAX_AEN_QUEUE, " 1781 "Len=%xh\n", request_cnt); 1782 cmd->ResponseLen = 0; 1783 return; 1784 } 1785 1786 /* 1st: Make a local copy of the entire queue content. */ 1787 tmp_q = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue; 1788 queue_cnt = 0; 1789 1790 INTR_LOCK(ha); 1791 i = xp->aen_q_head; 1792 1793 for (; queue_cnt < EXT_DEF_MAX_AEN_QUEUE; ) { 1794 if (tmp_q[i].AsyncEventCode != 0) { 1795 bcopy(&tmp_q[i], &aen[queue_cnt], 1796 sizeof (EXT_ASYNC_EVENT)); 1797 queue_cnt++; 1798 tmp_q[i].AsyncEventCode = 0; /* empty out the slot */ 1799 } 1800 if (i == xp->aen_q_tail) { 1801 /* done. */ 1802 break; 1803 } 1804 i++; 1805 if (i == EXT_DEF_MAX_AEN_QUEUE) { 1806 i = 0; 1807 } 1808 } 1809 1810 /* Empty the queue. */ 1811 xp->aen_q_head = 0; 1812 xp->aen_q_tail = 0; 1813 1814 INTR_UNLOCK(ha); 1815 1816 /* 2nd: Now transfer the queue content to user buffer */ 1817 /* Copy the entire queue to user's buffer. */ 1818 out_size = (uint32_t)(queue_cnt * sizeof (EXT_ASYNC_EVENT)); 1819 if (queue_cnt == 0) { 1820 cmd->ResponseLen = 0; 1821 } else if (ddi_copyout((void *)&aen[0], 1822 (void *)(uintptr_t)(cmd->ResponseAdr), 1823 out_size, mode) != 0) { 1824 cmd->Status = EXT_STATUS_COPY_ERR; 1825 cmd->ResponseLen = 0; 1826 EL(ha, "failed, ddi_copyout\n"); 1827 } else { 1828 cmd->ResponseLen = out_size; 1829 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1830 } 1831 } 1832 1833 /* 1834 * ql_enqueue_aen 1835 * 1836 * Input: 1837 * ha: adapter state pointer. 1838 * event_code: async event code of the event to add to queue. 1839 * payload: event payload for the queue. 1840 * INTR_LOCK must be already obtained. 1841 * 1842 * Context: 1843 * Interrupt or Kernel context, no mailbox commands allowed. 1844 */ 1845 void 1846 ql_enqueue_aen(ql_adapter_state_t *ha, uint16_t event_code, void *payload) 1847 { 1848 uint8_t new_entry; /* index to current entry */ 1849 uint16_t *mbx; 1850 EXT_ASYNC_EVENT *aen_queue; 1851 ql_xioctl_t *xp = ha->xioctl; 1852 1853 QL_PRINT_9(CE_CONT, "(%d): entered, event_code=%d\n", ha->instance, 1854 event_code); 1855 1856 if (xp == NULL) { 1857 QL_PRINT_9(CE_CONT, "(%d): no context\n", ha->instance); 1858 return; 1859 } 1860 aen_queue = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue; 1861 1862 if (aen_queue[xp->aen_q_tail].AsyncEventCode != NULL) { 1863 /* Need to change queue pointers to make room. */ 1864 1865 /* Increment tail for adding new entry. */ 1866 xp->aen_q_tail++; 1867 if (xp->aen_q_tail == EXT_DEF_MAX_AEN_QUEUE) { 1868 xp->aen_q_tail = 0; 1869 } 1870 if (xp->aen_q_head == xp->aen_q_tail) { 1871 /* 1872 * We're overwriting the oldest entry, so need to 1873 * update the head pointer. 1874 */ 1875 xp->aen_q_head++; 1876 if (xp->aen_q_head == EXT_DEF_MAX_AEN_QUEUE) { 1877 xp->aen_q_head = 0; 1878 } 1879 } 1880 } 1881 1882 new_entry = xp->aen_q_tail; 1883 aen_queue[new_entry].AsyncEventCode = event_code; 1884 1885 /* Update payload */ 1886 if (payload != NULL) { 1887 switch (event_code) { 1888 case MBA_LIP_OCCURRED: 1889 case MBA_LOOP_UP: 1890 case MBA_LOOP_DOWN: 1891 case MBA_LIP_F8: 1892 case MBA_LIP_RESET: 1893 case MBA_PORT_UPDATE: 1894 break; 1895 case MBA_RSCN_UPDATE: 1896 mbx = (uint16_t *)payload; 1897 /* al_pa */ 1898 aen_queue[new_entry].Payload.RSCN.RSCNInfo[0] = 1899 LSB(mbx[2]); 1900 /* area */ 1901 aen_queue[new_entry].Payload.RSCN.RSCNInfo[1] = 1902 MSB(mbx[2]); 1903 /* domain */ 1904 aen_queue[new_entry].Payload.RSCN.RSCNInfo[2] = 1905 LSB(mbx[1]); 1906 /* save in big endian */ 1907 BIG_ENDIAN_24(&aen_queue[new_entry]. 1908 Payload.RSCN.RSCNInfo[0]); 1909 1910 aen_queue[new_entry].Payload.RSCN.AddrFormat = 1911 MSB(mbx[1]); 1912 1913 break; 1914 default: 1915 /* Not supported */ 1916 EL(ha, "failed, event code not supported=%xh\n", 1917 event_code); 1918 aen_queue[new_entry].AsyncEventCode = 0; 1919 break; 1920 } 1921 } 1922 1923 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 1924 } 1925 1926 /* 1927 * ql_scsi_passthru 1928 * IOCTL SCSI passthrough. 1929 * 1930 * Input: 1931 * ha: adapter state pointer. 1932 * cmd: User space SCSI command pointer. 1933 * mode: flags. 1934 * 1935 * Returns: 1936 * None, request status indicated in cmd->Status. 1937 * 1938 * Context: 1939 * Kernel context. 1940 */ 1941 static void 1942 ql_scsi_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 1943 { 1944 ql_mbx_iocb_t *pkt; 1945 ql_mbx_data_t mr; 1946 dma_mem_t *dma_mem; 1947 caddr_t pld; 1948 uint32_t pkt_size, pld_size; 1949 uint16_t qlnt, retries, cnt, cnt2; 1950 uint8_t *name; 1951 EXT_FC_SCSI_PASSTHRU *ufc_req; 1952 EXT_SCSI_PASSTHRU *usp_req; 1953 int rval; 1954 union _passthru { 1955 EXT_SCSI_PASSTHRU sp_cmd; 1956 EXT_FC_SCSI_PASSTHRU fc_cmd; 1957 } pt_req; /* Passthru request */ 1958 uint32_t status, sense_sz = 0; 1959 ql_tgt_t *tq = NULL; 1960 EXT_SCSI_PASSTHRU *sp_req = &pt_req.sp_cmd; 1961 EXT_FC_SCSI_PASSTHRU *fc_req = &pt_req.fc_cmd; 1962 1963 /* SCSI request struct for SCSI passthrough IOs. */ 1964 struct { 1965 uint16_t lun; 1966 uint16_t sense_length; /* Sense buffer size */ 1967 size_t resid; /* Residual */ 1968 uint8_t *cdbp; /* Requestor's CDB */ 1969 uint8_t *u_sense; /* Requestor's sense buffer */ 1970 uint8_t cdb_len; /* Requestor's CDB length */ 1971 uint8_t direction; 1972 } scsi_req; 1973 1974 struct { 1975 uint8_t *rsp_info; 1976 uint8_t *req_sense_data; 1977 uint32_t residual_length; 1978 uint32_t rsp_info_length; 1979 uint32_t req_sense_length; 1980 uint16_t comp_status; 1981 uint8_t state_flags_l; 1982 uint8_t state_flags_h; 1983 uint8_t scsi_status_l; 1984 uint8_t scsi_status_h; 1985 } sts; 1986 1987 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 1988 1989 /* Verify Sub Code and set cnt to needed request size. */ 1990 if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) { 1991 pld_size = sizeof (EXT_SCSI_PASSTHRU); 1992 } else if (cmd->SubCode == EXT_SC_SEND_FC_SCSI_PASSTHRU) { 1993 pld_size = sizeof (EXT_FC_SCSI_PASSTHRU); 1994 } else { 1995 EL(ha, "failed, invalid SubCode=%xh\n", cmd->SubCode); 1996 cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE; 1997 cmd->ResponseLen = 0; 1998 return; 1999 } 2000 2001 dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP); 2002 if (dma_mem == NULL) { 2003 EL(ha, "failed, kmem_zalloc\n"); 2004 cmd->Status = EXT_STATUS_NO_MEMORY; 2005 cmd->ResponseLen = 0; 2006 return; 2007 } 2008 /* Verify the size of and copy in the passthru request structure. */ 2009 if (cmd->RequestLen != pld_size) { 2010 /* Return error */ 2011 EL(ha, "failed, RequestLen != cnt, is=%xh, expected=%xh\n", 2012 cmd->RequestLen, pld_size); 2013 cmd->Status = EXT_STATUS_INVALID_PARAM; 2014 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 2015 cmd->ResponseLen = 0; 2016 return; 2017 } 2018 2019 if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, &pt_req, 2020 pld_size, mode) != 0) { 2021 EL(ha, "failed, ddi_copyin\n"); 2022 cmd->Status = EXT_STATUS_COPY_ERR; 2023 cmd->ResponseLen = 0; 2024 return; 2025 } 2026 2027 /* 2028 * Find fc_port from SCSI PASSTHRU structure fill in the scsi_req 2029 * request data structure. 2030 */ 2031 if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) { 2032 scsi_req.lun = sp_req->TargetAddr.Lun; 2033 scsi_req.sense_length = sizeof (sp_req->SenseData); 2034 scsi_req.cdbp = &sp_req->Cdb[0]; 2035 scsi_req.cdb_len = sp_req->CdbLength; 2036 scsi_req.direction = sp_req->Direction; 2037 usp_req = (EXT_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr; 2038 scsi_req.u_sense = &usp_req->SenseData[0]; 2039 cmd->DetailStatus = EXT_DSTATUS_TARGET; 2040 2041 qlnt = QLNT_PORT; 2042 name = (uint8_t *)&sp_req->TargetAddr.Target; 2043 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, Target=%lld\n", 2044 ha->instance, cmd->SubCode, sp_req->TargetAddr.Target); 2045 tq = ql_find_port(ha, name, qlnt); 2046 } else { 2047 /* 2048 * Must be FC PASSTHRU, verified above. 2049 */ 2050 if (fc_req->FCScsiAddr.DestType == EXT_DEF_DESTTYPE_WWPN) { 2051 qlnt = QLNT_PORT; 2052 name = &fc_req->FCScsiAddr.DestAddr.WWPN[0]; 2053 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, " 2054 "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n", 2055 ha->instance, cmd->SubCode, name[0], name[1], 2056 name[2], name[3], name[4], name[5], name[6], 2057 name[7]); 2058 tq = ql_find_port(ha, name, qlnt); 2059 } else if (fc_req->FCScsiAddr.DestType == 2060 EXT_DEF_DESTTYPE_WWNN) { 2061 qlnt = QLNT_NODE; 2062 name = &fc_req->FCScsiAddr.DestAddr.WWNN[0]; 2063 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, " 2064 "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x\n", 2065 ha->instance, cmd->SubCode, name[0], name[1], 2066 name[2], name[3], name[4], name[5], name[6], 2067 name[7]); 2068 tq = ql_find_port(ha, name, qlnt); 2069 } else if (fc_req->FCScsiAddr.DestType == 2070 EXT_DEF_DESTTYPE_PORTID) { 2071 qlnt = QLNT_PID; 2072 name = &fc_req->FCScsiAddr.DestAddr.Id[0]; 2073 QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, PID=" 2074 "%02x%02x%02x\n", ha->instance, cmd->SubCode, 2075 name[0], name[1], name[2]); 2076 tq = ql_find_port(ha, name, qlnt); 2077 } else { 2078 EL(ha, "failed, SubCode=%xh invalid DestType=%xh\n", 2079 cmd->SubCode, fc_req->FCScsiAddr.DestType); 2080 cmd->Status = EXT_STATUS_INVALID_PARAM; 2081 cmd->ResponseLen = 0; 2082 return; 2083 } 2084 scsi_req.lun = fc_req->FCScsiAddr.Lun; 2085 scsi_req.sense_length = sizeof (fc_req->SenseData); 2086 scsi_req.cdbp = &sp_req->Cdb[0]; 2087 scsi_req.cdb_len = sp_req->CdbLength; 2088 ufc_req = (EXT_FC_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr; 2089 scsi_req.u_sense = &ufc_req->SenseData[0]; 2090 scsi_req.direction = fc_req->Direction; 2091 } 2092 2093 if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) { 2094 EL(ha, "failed, fc_port not found\n"); 2095 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 2096 cmd->ResponseLen = 0; 2097 return; 2098 } 2099 2100 if (tq->flags & TQF_NEED_AUTHENTICATION) { 2101 EL(ha, "target not available; loopid=%xh\n", tq->loop_id); 2102 cmd->Status = EXT_STATUS_DEVICE_OFFLINE; 2103 cmd->ResponseLen = 0; 2104 return; 2105 } 2106 2107 /* Allocate command block. */ 2108 if ((scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN || 2109 scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) && 2110 cmd->ResponseLen) { 2111 pld_size = cmd->ResponseLen; 2112 pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_size); 2113 pkt = kmem_zalloc(pkt_size, KM_SLEEP); 2114 if (pkt == NULL) { 2115 EL(ha, "failed, kmem_zalloc\n"); 2116 cmd->Status = EXT_STATUS_NO_MEMORY; 2117 cmd->ResponseLen = 0; 2118 return; 2119 } 2120 pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t); 2121 2122 /* Get DMA memory for the IOCB */ 2123 if (ql_get_dma_mem(ha, dma_mem, pld_size, LITTLE_ENDIAN_DMA, 2124 QL_DMA_DATA_ALIGN) != QL_SUCCESS) { 2125 cmn_err(CE_WARN, "%s(%d): request queue DMA memory " 2126 "alloc failed", QL_NAME, ha->instance); 2127 kmem_free(pkt, pkt_size); 2128 cmd->Status = EXT_STATUS_MS_NO_RESPONSE; 2129 cmd->ResponseLen = 0; 2130 return; 2131 } 2132 2133 if (scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) { 2134 scsi_req.direction = (uint8_t) 2135 (CFG_IST(ha, CFG_CTRL_2425) ? 2136 CF_RD : CF_DATA_IN | CF_STAG); 2137 } else { 2138 scsi_req.direction = (uint8_t) 2139 (CFG_IST(ha, CFG_CTRL_2425) ? 2140 CF_WR : CF_DATA_OUT | CF_STAG); 2141 cmd->ResponseLen = 0; 2142 2143 /* Get command payload. */ 2144 if (ql_get_buffer_data( 2145 (caddr_t)(uintptr_t)cmd->ResponseAdr, 2146 pld, pld_size, mode) != pld_size) { 2147 EL(ha, "failed, get_buffer_data\n"); 2148 cmd->Status = EXT_STATUS_COPY_ERR; 2149 2150 kmem_free(pkt, pkt_size); 2151 ql_free_dma_resource(ha, dma_mem); 2152 kmem_free(dma_mem, sizeof (dma_mem_t)); 2153 return; 2154 } 2155 2156 /* Copy out going data to DMA buffer. */ 2157 ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld, 2158 (uint8_t *)dma_mem->bp, pld_size, 2159 DDI_DEV_AUTOINCR); 2160 2161 /* Sync DMA buffer. */ 2162 (void) ddi_dma_sync(dma_mem->dma_handle, 0, 2163 dma_mem->size, DDI_DMA_SYNC_FORDEV); 2164 } 2165 } else { 2166 scsi_req.direction = (uint8_t) 2167 (CFG_IST(ha, CFG_CTRL_2425) ? 0 : CF_STAG); 2168 cmd->ResponseLen = 0; 2169 2170 pkt_size = sizeof (ql_mbx_iocb_t); 2171 pkt = kmem_zalloc(pkt_size, KM_SLEEP); 2172 if (pkt == NULL) { 2173 EL(ha, "failed, kmem_zalloc-2\n"); 2174 cmd->Status = EXT_STATUS_NO_MEMORY; 2175 return; 2176 } 2177 pld = NULL; 2178 pld_size = 0; 2179 } 2180 2181 /* retries = ha->port_down_retry_count; */ 2182 retries = 1; 2183 cmd->Status = EXT_STATUS_OK; 2184 cmd->DetailStatus = EXT_DSTATUS_NOADNL_INFO; 2185 2186 QL_PRINT_9(CE_CONT, "(%d): SCSI cdb\n", ha->instance); 2187 QL_DUMP_9(scsi_req.cdbp, 8, scsi_req.cdb_len); 2188 2189 do { 2190 if (DRIVER_SUSPENDED(ha)) { 2191 sts.comp_status = CS_LOOP_DOWN_ABORT; 2192 break; 2193 } 2194 2195 if (CFG_IST(ha, CFG_CTRL_2425)) { 2196 pkt->cmd24.entry_type = IOCB_CMD_TYPE_7; 2197 pkt->cmd24.entry_count = 1; 2198 2199 /* Set LUN number */ 2200 pkt->cmd24.fcp_lun[2] = LSB(scsi_req.lun); 2201 pkt->cmd24.fcp_lun[3] = MSB(scsi_req.lun); 2202 2203 /* Set N_port handle */ 2204 pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id); 2205 2206 /* Set VP Index */ 2207 pkt->cmd24.vp_index = ha->vp_index; 2208 2209 /* Set target ID */ 2210 pkt->cmd24.target_id[0] = tq->d_id.b.al_pa; 2211 pkt->cmd24.target_id[1] = tq->d_id.b.area; 2212 pkt->cmd24.target_id[2] = tq->d_id.b.domain; 2213 2214 /* Set ISP command timeout. */ 2215 pkt->cmd24.timeout = (uint16_t)LE_16(15); 2216 2217 /* Load SCSI CDB */ 2218 ddi_rep_put8(ha->hba_buf.acc_handle, scsi_req.cdbp, 2219 pkt->cmd24.scsi_cdb, scsi_req.cdb_len, 2220 DDI_DEV_AUTOINCR); 2221 for (cnt = 0; cnt < MAX_CMDSZ; 2222 cnt = (uint16_t)(cnt + 4)) { 2223 ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb 2224 + cnt, 4); 2225 } 2226 2227 /* Set tag queue control flags */ 2228 pkt->cmd24.task = TA_STAG; 2229 2230 if (pld_size) { 2231 /* Set transfer direction. */ 2232 pkt->cmd24.control_flags = scsi_req.direction; 2233 2234 /* Set data segment count. */ 2235 pkt->cmd24.dseg_count = LE_16(1); 2236 2237 /* Load total byte count. */ 2238 pkt->cmd24.total_byte_count = LE_32(pld_size); 2239 2240 /* Load data descriptor. */ 2241 pkt->cmd24.dseg_0_address[0] = (uint32_t) 2242 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 2243 pkt->cmd24.dseg_0_address[1] = (uint32_t) 2244 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 2245 pkt->cmd24.dseg_0_length = LE_32(pld_size); 2246 } 2247 } else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) { 2248 pkt->cmd3.entry_type = IOCB_CMD_TYPE_3; 2249 pkt->cmd3.entry_count = 1; 2250 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 2251 pkt->cmd3.target_l = LSB(tq->loop_id); 2252 pkt->cmd3.target_h = MSB(tq->loop_id); 2253 } else { 2254 pkt->cmd3.target_h = LSB(tq->loop_id); 2255 } 2256 pkt->cmd3.lun_l = LSB(scsi_req.lun); 2257 pkt->cmd3.lun_h = MSB(scsi_req.lun); 2258 pkt->cmd3.control_flags_l = scsi_req.direction; 2259 pkt->cmd3.timeout = LE_16(15); 2260 for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) { 2261 pkt->cmd3.scsi_cdb[cnt] = scsi_req.cdbp[cnt]; 2262 } 2263 if (pld_size) { 2264 pkt->cmd3.dseg_count = LE_16(1); 2265 pkt->cmd3.byte_count = LE_32(pld_size); 2266 pkt->cmd3.dseg_0_address[0] = (uint32_t) 2267 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 2268 pkt->cmd3.dseg_0_address[1] = (uint32_t) 2269 LE_32(MSD(dma_mem->cookie.dmac_laddress)); 2270 pkt->cmd3.dseg_0_length = LE_32(pld_size); 2271 } 2272 } else { 2273 pkt->cmd.entry_type = IOCB_CMD_TYPE_2; 2274 pkt->cmd.entry_count = 1; 2275 if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) { 2276 pkt->cmd.target_l = LSB(tq->loop_id); 2277 pkt->cmd.target_h = MSB(tq->loop_id); 2278 } else { 2279 pkt->cmd.target_h = LSB(tq->loop_id); 2280 } 2281 pkt->cmd.lun_l = LSB(scsi_req.lun); 2282 pkt->cmd.lun_h = MSB(scsi_req.lun); 2283 pkt->cmd.control_flags_l = scsi_req.direction; 2284 pkt->cmd.timeout = LE_16(15); 2285 for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) { 2286 pkt->cmd.scsi_cdb[cnt] = scsi_req.cdbp[cnt]; 2287 } 2288 if (pld_size) { 2289 pkt->cmd.dseg_count = LE_16(1); 2290 pkt->cmd.byte_count = LE_32(pld_size); 2291 pkt->cmd.dseg_0_address = (uint32_t) 2292 LE_32(LSD(dma_mem->cookie.dmac_laddress)); 2293 pkt->cmd.dseg_0_length = LE_32(pld_size); 2294 } 2295 } 2296 /* Go issue command and wait for completion. */ 2297 QL_PRINT_9(CE_CONT, "(%d): request pkt\n", ha->instance); 2298 QL_DUMP_9(pkt, 8, pkt_size); 2299 2300 status = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size); 2301 2302 if (pld_size) { 2303 /* Sync in coming DMA buffer. */ 2304 (void) ddi_dma_sync(dma_mem->dma_handle, 0, 2305 dma_mem->size, DDI_DMA_SYNC_FORKERNEL); 2306 /* Copy in coming DMA data. */ 2307 ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld, 2308 (uint8_t *)dma_mem->bp, pld_size, 2309 DDI_DEV_AUTOINCR); 2310 } 2311 2312 if (CFG_IST(ha, CFG_CTRL_2425)) { 2313 pkt->sts24.entry_status = (uint8_t) 2314 (pkt->sts24.entry_status & 0x3c); 2315 } else { 2316 pkt->sts.entry_status = (uint8_t) 2317 (pkt->sts.entry_status & 0x7e); 2318 } 2319 2320 if (status == QL_SUCCESS && pkt->sts.entry_status != 0) { 2321 EL(ha, "failed, entry_status=%xh, d_id=%xh\n", 2322 pkt->sts.entry_status, tq->d_id.b24); 2323 status = QL_FUNCTION_PARAMETER_ERROR; 2324 } 2325 2326 sts.comp_status = (uint16_t)(CFG_IST(ha, CFG_CTRL_2425) ? 2327 LE_16(pkt->sts24.comp_status) : 2328 LE_16(pkt->sts.comp_status)); 2329 2330 /* 2331 * We have verified about all the request that can be so far. 2332 * Now we need to start verification of our ability to 2333 * actually issue the CDB. 2334 */ 2335 if (DRIVER_SUSPENDED(ha)) { 2336 sts.comp_status = CS_LOOP_DOWN_ABORT; 2337 break; 2338 } else if (status == QL_SUCCESS && 2339 (sts.comp_status == CS_PORT_LOGGED_OUT || 2340 sts.comp_status == CS_PORT_UNAVAILABLE)) { 2341 EL(ha, "login retry d_id=%xh\n", tq->d_id.b24); 2342 if (tq->flags & TQF_FABRIC_DEVICE) { 2343 rval = ql_login_fport(ha, tq, tq->loop_id, 2344 LFF_NO_PLOGI, &mr); 2345 if (rval != QL_SUCCESS) { 2346 EL(ha, "failed, login_fport=%xh, " 2347 "d_id=%xh\n", rval, tq->d_id.b24); 2348 } 2349 } else { 2350 rval = ql_login_lport(ha, tq, tq->loop_id, 2351 LLF_NONE); 2352 if (rval != QL_SUCCESS) { 2353 EL(ha, "failed, login_lport=%xh, " 2354 "d_id=%xh\n", rval, tq->d_id.b24); 2355 } 2356 } 2357 } else { 2358 break; 2359 } 2360 2361 bzero((caddr_t)pkt, sizeof (ql_mbx_iocb_t)); 2362 2363 } while (retries--); 2364 2365 if (sts.comp_status == CS_LOOP_DOWN_ABORT) { 2366 /* Cannot issue command now, maybe later */ 2367 EL(ha, "failed, suspended\n"); 2368 kmem_free(pkt, pkt_size); 2369 ql_free_dma_resource(ha, dma_mem); 2370 kmem_free(dma_mem, sizeof (dma_mem_t)); 2371 cmd->Status = EXT_STATUS_SUSPENDED; 2372 cmd->ResponseLen = 0; 2373 return; 2374 } 2375 2376 if (status != QL_SUCCESS) { 2377 /* Command error */ 2378 EL(ha, "failed, I/O\n"); 2379 kmem_free(pkt, pkt_size); 2380 ql_free_dma_resource(ha, dma_mem); 2381 kmem_free(dma_mem, sizeof (dma_mem_t)); 2382 cmd->Status = EXT_STATUS_ERR; 2383 cmd->DetailStatus = status; 2384 cmd->ResponseLen = 0; 2385 return; 2386 } 2387 2388 /* Setup status. */ 2389 if (CFG_IST(ha, CFG_CTRL_2425)) { 2390 sts.scsi_status_l = pkt->sts24.scsi_status_l; 2391 sts.scsi_status_h = pkt->sts24.scsi_status_h; 2392 2393 /* Setup residuals. */ 2394 sts.residual_length = LE_32(pkt->sts24.residual_length); 2395 2396 /* Setup state flags. */ 2397 sts.state_flags_l = pkt->sts24.state_flags_l; 2398 sts.state_flags_h = pkt->sts24.state_flags_h; 2399 if (pld_size && sts.comp_status != CS_DATA_UNDERRUN) { 2400 sts.state_flags_h = (uint8_t)(sts.state_flags_h | 2401 SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD | 2402 SF_XFERRED_DATA | SF_GOT_STATUS); 2403 } else { 2404 sts.state_flags_h = (uint8_t)(sts.state_flags_h | 2405 SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD | 2406 SF_GOT_STATUS); 2407 } 2408 if (scsi_req.direction & CF_WR) { 2409 sts.state_flags_l = (uint8_t)(sts.state_flags_l | 2410 SF_DATA_OUT); 2411 } else if (scsi_req.direction & CF_RD) { 2412 sts.state_flags_l = (uint8_t)(sts.state_flags_l | 2413 SF_DATA_IN); 2414 } 2415 sts.state_flags_l = (uint8_t)(sts.state_flags_l | SF_SIMPLE_Q); 2416 2417 /* Setup FCP response info. */ 2418 sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ? 2419 LE_32(pkt->sts24.fcp_rsp_data_length) : 0; 2420 sts.rsp_info = &pkt->sts24.rsp_sense_data[0]; 2421 for (cnt = 0; cnt < sts.rsp_info_length; 2422 cnt = (uint16_t)(cnt + 4)) { 2423 ql_chg_endian(sts.rsp_info + cnt, 4); 2424 } 2425 2426 /* Setup sense data. */ 2427 if (sts.scsi_status_h & FCP_SNS_LEN_VALID) { 2428 sts.req_sense_length = 2429 LE_32(pkt->sts24.fcp_sense_length); 2430 sts.state_flags_h = (uint8_t)(sts.state_flags_h | 2431 SF_ARQ_DONE); 2432 } else { 2433 sts.req_sense_length = 0; 2434 } 2435 sts.req_sense_data = 2436 &pkt->sts24.rsp_sense_data[sts.rsp_info_length]; 2437 cnt2 = (uint16_t)(((uintptr_t)pkt + sizeof (sts_24xx_entry_t)) - 2438 (uintptr_t)sts.req_sense_data); 2439 for (cnt = 0; cnt < cnt2; cnt = (uint16_t)(cnt + 4)) { 2440 ql_chg_endian(sts.req_sense_data + cnt, 4); 2441 } 2442 } else { 2443 sts.scsi_status_l = pkt->sts.scsi_status_l; 2444 sts.scsi_status_h = pkt->sts.scsi_status_h; 2445 2446 /* Setup residuals. */ 2447 sts.residual_length = LE_32(pkt->sts.residual_length); 2448 2449 /* Setup state flags. */ 2450 sts.state_flags_l = pkt->sts.state_flags_l; 2451 sts.state_flags_h = pkt->sts.state_flags_h; 2452 2453 /* Setup FCP response info. */ 2454 sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ? 2455 LE_16(pkt->sts.rsp_info_length) : 0; 2456 sts.rsp_info = &pkt->sts.rsp_info[0]; 2457 2458 /* Setup sense data. */ 2459 sts.req_sense_length = sts.scsi_status_h & FCP_SNS_LEN_VALID ? 2460 LE_16(pkt->sts.req_sense_length) : 0; 2461 sts.req_sense_data = &pkt->sts.req_sense_data[0]; 2462 } 2463 2464 QL_PRINT_9(CE_CONT, "(%d): response pkt\n", ha->instance); 2465 QL_DUMP_9(&pkt->sts, 8, sizeof (sts_entry_t)); 2466 2467 switch (sts.comp_status) { 2468 case CS_INCOMPLETE: 2469 case CS_ABORTED: 2470 case CS_DEVICE_UNAVAILABLE: 2471 case CS_PORT_UNAVAILABLE: 2472 case CS_PORT_LOGGED_OUT: 2473 case CS_PORT_CONFIG_CHG: 2474 case CS_PORT_BUSY: 2475 case CS_LOOP_DOWN_ABORT: 2476 cmd->Status = EXT_STATUS_BUSY; 2477 break; 2478 case CS_RESET: 2479 case CS_QUEUE_FULL: 2480 cmd->Status = EXT_STATUS_ERR; 2481 break; 2482 case CS_TIMEOUT: 2483 cmd->Status = EXT_STATUS_ERR; 2484 break; 2485 case CS_DATA_OVERRUN: 2486 cmd->Status = EXT_STATUS_DATA_OVERRUN; 2487 break; 2488 case CS_DATA_UNDERRUN: 2489 cmd->Status = EXT_STATUS_DATA_UNDERRUN; 2490 break; 2491 } 2492 2493 /* 2494 * If non data transfer commands fix tranfer counts. 2495 */ 2496 if (scsi_req.cdbp[0] == SCMD_TEST_UNIT_READY || 2497 scsi_req.cdbp[0] == SCMD_REZERO_UNIT || 2498 scsi_req.cdbp[0] == SCMD_SEEK || 2499 scsi_req.cdbp[0] == SCMD_SEEK_G1 || 2500 scsi_req.cdbp[0] == SCMD_RESERVE || 2501 scsi_req.cdbp[0] == SCMD_RELEASE || 2502 scsi_req.cdbp[0] == SCMD_START_STOP || 2503 scsi_req.cdbp[0] == SCMD_DOORLOCK || 2504 scsi_req.cdbp[0] == SCMD_VERIFY || 2505 scsi_req.cdbp[0] == SCMD_WRITE_FILE_MARK || 2506 scsi_req.cdbp[0] == SCMD_VERIFY_G0 || 2507 scsi_req.cdbp[0] == SCMD_SPACE || 2508 scsi_req.cdbp[0] == SCMD_ERASE || 2509 (scsi_req.cdbp[0] == SCMD_FORMAT && 2510 (scsi_req.cdbp[1] & FPB_DATA) == 0)) { 2511 /* 2512 * Non data transfer command, clear sts_entry residual 2513 * length. 2514 */ 2515 sts.residual_length = 0; 2516 cmd->ResponseLen = 0; 2517 if (sts.comp_status == CS_DATA_UNDERRUN) { 2518 sts.comp_status = CS_COMPLETE; 2519 cmd->Status = EXT_STATUS_OK; 2520 } 2521 } else { 2522 cmd->ResponseLen = pld_size; 2523 } 2524 2525 /* Correct ISP completion status */ 2526 if (sts.comp_status == CS_COMPLETE && sts.scsi_status_l == 0 && 2527 (sts.scsi_status_h & FCP_RSP_MASK) == 0) { 2528 QL_PRINT_9(CE_CONT, "(%d): Correct completion\n", 2529 ha->instance); 2530 scsi_req.resid = 0; 2531 } else if (sts.comp_status == CS_DATA_UNDERRUN) { 2532 QL_PRINT_9(CE_CONT, "(%d): Correct UNDERRUN\n", 2533 ha->instance); 2534 scsi_req.resid = sts.residual_length; 2535 if (sts.scsi_status_h & FCP_RESID_UNDER) { 2536 cmd->Status = (uint32_t)EXT_STATUS_OK; 2537 2538 cmd->ResponseLen = (uint32_t) 2539 (pld_size - scsi_req.resid); 2540 } else { 2541 EL(ha, "failed, Transfer ERROR\n"); 2542 cmd->Status = EXT_STATUS_ERR; 2543 cmd->ResponseLen = 0; 2544 } 2545 } else { 2546 QL_PRINT_9(CE_CONT, "(%d): error d_id=%xh, comp_status=%xh, " 2547 "scsi_status_h=%xh, scsi_status_l=%xh\n", ha->instance, 2548 tq->d_id.b24, sts.comp_status, sts.scsi_status_h, 2549 sts.scsi_status_l); 2550 2551 scsi_req.resid = pld_size; 2552 /* 2553 * Handle residual count on SCSI check 2554 * condition. 2555 * 2556 * - If Residual Under / Over is set, use the 2557 * Residual Transfer Length field in IOCB. 2558 * - If Residual Under / Over is not set, and 2559 * Transferred Data bit is set in State Flags 2560 * field of IOCB, report residual value of 0 2561 * (you may want to do this for tape 2562 * Write-type commands only). This takes care 2563 * of logical end of tape problem and does 2564 * not break Unit Attention. 2565 * - If Residual Under / Over is not set, and 2566 * Transferred Data bit is not set in State 2567 * Flags, report residual value equal to 2568 * original data transfer length. 2569 */ 2570 if (sts.scsi_status_l & STATUS_CHECK) { 2571 cmd->Status = EXT_STATUS_SCSI_STATUS; 2572 cmd->DetailStatus = sts.scsi_status_l; 2573 if (sts.scsi_status_h & 2574 (FCP_RESID_OVER | FCP_RESID_UNDER)) { 2575 scsi_req.resid = sts.residual_length; 2576 } else if (sts.state_flags_h & 2577 STATE_XFERRED_DATA) { 2578 scsi_req.resid = 0; 2579 } 2580 } 2581 } 2582 2583 if (sts.scsi_status_l & STATUS_CHECK && 2584 sts.scsi_status_h & FCP_SNS_LEN_VALID && 2585 sts.req_sense_length) { 2586 /* 2587 * Check condition with vaild sense data flag set and sense 2588 * length != 0 2589 */ 2590 if (sts.req_sense_length > scsi_req.sense_length) { 2591 sense_sz = scsi_req.sense_length; 2592 } else { 2593 sense_sz = sts.req_sense_length; 2594 } 2595 2596 EL(ha, "failed, Check Condition Status, d_id=%xh\n", 2597 tq->d_id.b24); 2598 QL_DUMP_2(sts.req_sense_data, 8, sts.req_sense_length); 2599 2600 if (ddi_copyout(sts.req_sense_data, scsi_req.u_sense, 2601 (size_t)sense_sz, mode) != 0) { 2602 EL(ha, "failed, request sense ddi_copyout\n"); 2603 } 2604 2605 cmd->Status = EXT_STATUS_SCSI_STATUS; 2606 cmd->DetailStatus = sts.scsi_status_l; 2607 } 2608 2609 /* Copy response payload from DMA buffer to application. */ 2610 if (scsi_req.direction & (CF_RD | CF_DATA_IN) && 2611 cmd->ResponseLen != 0) { 2612 QL_PRINT_9(CE_CONT, "(%d): Data Return resid=%lu, " 2613 "byte_count=%u, ResponseLen=%xh\n", ha->instance, 2614 scsi_req.resid, pld_size, cmd->ResponseLen); 2615 QL_DUMP_9(pld, 8, cmd->ResponseLen); 2616 2617 /* Send response payload. */ 2618 if (ql_send_buffer_data(pld, 2619 (caddr_t)(uintptr_t)cmd->ResponseAdr, 2620 cmd->ResponseLen, mode) != cmd->ResponseLen) { 2621 EL(ha, "failed, send_buffer_data\n"); 2622 cmd->Status = EXT_STATUS_COPY_ERR; 2623 cmd->ResponseLen = 0; 2624 } 2625 } 2626 2627 if (cmd->Status != EXT_STATUS_OK) { 2628 EL(ha, "failed, cmd->Status=%xh, comp_status=%xh, " 2629 "d_id=%xh\n", cmd->Status, sts.comp_status, tq->d_id.b24); 2630 } else { 2631 /*EMPTY*/ 2632 QL_PRINT_9(CE_CONT, "(%d): exiting, ResponseLen=%d\n", 2633 ha->instance, cmd->ResponseLen); 2634 } 2635 2636 kmem_free(pkt, pkt_size); 2637 ql_free_dma_resource(ha, dma_mem); 2638 kmem_free(dma_mem, sizeof (dma_mem_t)); 2639 } 2640 2641 /* 2642 * ql_wwpn_to_scsiaddr 2643 * 2644 * Input: 2645 * ha: adapter state pointer. 2646 * cmd: EXT_IOCTL cmd struct pointer. 2647 * mode: flags. 2648 * 2649 * Context: 2650 * Kernel context. 2651 */ 2652 static void 2653 ql_wwpn_to_scsiaddr(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2654 { 2655 int status; 2656 uint8_t wwpn[EXT_DEF_WWN_NAME_SIZE]; 2657 EXT_SCSI_ADDR *tmp_addr; 2658 ql_tgt_t *tq; 2659 2660 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2661 2662 if (cmd->RequestLen != EXT_DEF_WWN_NAME_SIZE) { 2663 /* Return error */ 2664 EL(ha, "incorrect RequestLen\n"); 2665 cmd->Status = EXT_STATUS_INVALID_PARAM; 2666 cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN; 2667 return; 2668 } 2669 2670 status = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, wwpn, 2671 cmd->RequestLen, mode); 2672 2673 if (status != 0) { 2674 cmd->Status = EXT_STATUS_COPY_ERR; 2675 EL(ha, "failed, ddi_copyin\n"); 2676 return; 2677 } 2678 2679 tq = ql_find_port(ha, wwpn, QLNT_PORT); 2680 2681 if (tq == NULL || tq->flags & TQF_INITIATOR_DEVICE) { 2682 /* no matching device */ 2683 cmd->Status = EXT_STATUS_DEV_NOT_FOUND; 2684 EL(ha, "failed, device not found\n"); 2685 return; 2686 } 2687 2688 /* Copy out the IDs found. For now we can only return target ID. */ 2689 tmp_addr = (EXT_SCSI_ADDR *)(uintptr_t)cmd->ResponseAdr; 2690 2691 status = ddi_copyout((void *)wwpn, (void *)&tmp_addr->Target, 8, mode); 2692 2693 if (status != 0) { 2694 cmd->Status = EXT_STATUS_COPY_ERR; 2695 EL(ha, "failed, ddi_copyout\n"); 2696 } else { 2697 cmd->Status = EXT_STATUS_OK; 2698 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2699 } 2700 } 2701 2702 /* 2703 * ql_host_idx 2704 * Gets host order index. 2705 * 2706 * Input: 2707 * ha: adapter state pointer. 2708 * cmd: EXT_IOCTL cmd struct pointer. 2709 * mode: flags. 2710 * 2711 * Returns: 2712 * None, request status indicated in cmd->Status. 2713 * 2714 * Context: 2715 * Kernel context. 2716 */ 2717 static void 2718 ql_host_idx(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2719 { 2720 uint16_t idx; 2721 2722 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2723 2724 if (cmd->ResponseLen < sizeof (uint16_t)) { 2725 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 2726 cmd->DetailStatus = sizeof (uint16_t); 2727 EL(ha, "failed, ResponseLen < Len=%xh\n", cmd->ResponseLen); 2728 cmd->ResponseLen = 0; 2729 return; 2730 } 2731 2732 idx = (uint16_t)ha->instance; 2733 2734 if (ddi_copyout((void *)&idx, (void *)(uintptr_t)(cmd->ResponseAdr), 2735 sizeof (uint16_t), mode) != 0) { 2736 cmd->Status = EXT_STATUS_COPY_ERR; 2737 cmd->ResponseLen = 0; 2738 EL(ha, "failed, ddi_copyout\n"); 2739 } else { 2740 cmd->ResponseLen = sizeof (uint16_t); 2741 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2742 } 2743 } 2744 2745 /* 2746 * ql_host_drvname 2747 * Gets host driver name 2748 * 2749 * Input: 2750 * ha: adapter state pointer. 2751 * cmd: EXT_IOCTL cmd struct pointer. 2752 * mode: flags. 2753 * 2754 * Returns: 2755 * None, request status indicated in cmd->Status. 2756 * 2757 * Context: 2758 * Kernel context. 2759 */ 2760 static void 2761 ql_host_drvname(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2762 { 2763 2764 char drvname[] = QL_NAME; 2765 uint32_t qlnamelen; 2766 2767 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2768 2769 qlnamelen = (uint32_t)(strlen(QL_NAME)+1); 2770 2771 if (cmd->ResponseLen < qlnamelen) { 2772 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 2773 cmd->DetailStatus = qlnamelen; 2774 EL(ha, "failed, ResponseLen: %xh, needed: %xh\n", 2775 cmd->ResponseLen, qlnamelen); 2776 cmd->ResponseLen = 0; 2777 return; 2778 } 2779 2780 if (ddi_copyout((void *)&drvname, 2781 (void *)(uintptr_t)(cmd->ResponseAdr), 2782 qlnamelen, mode) != 0) { 2783 cmd->Status = EXT_STATUS_COPY_ERR; 2784 cmd->ResponseLen = 0; 2785 EL(ha, "failed, ddi_copyout\n"); 2786 } else { 2787 cmd->ResponseLen = qlnamelen-1; 2788 } 2789 2790 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2791 } 2792 2793 /* 2794 * ql_read_nvram 2795 * Get NVRAM contents. 2796 * 2797 * Input: 2798 * ha: adapter state pointer. 2799 * cmd: EXT_IOCTL cmd struct pointer. 2800 * mode: flags. 2801 * 2802 * Returns: 2803 * None, request status indicated in cmd->Status. 2804 * 2805 * Context: 2806 * Kernel context. 2807 */ 2808 static void 2809 ql_read_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2810 { 2811 uint32_t nv_size; 2812 2813 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2814 2815 nv_size = (uint32_t)(CFG_IST(ha, CFG_CTRL_2425) ? 2816 sizeof (nvram_24xx_t) : sizeof (nvram_t)); 2817 if (cmd->ResponseLen < nv_size) { 2818 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 2819 cmd->DetailStatus = nv_size; 2820 EL(ha, "failed, ResponseLen != NVRAM, Len=%xh\n", 2821 cmd->ResponseLen); 2822 cmd->ResponseLen = 0; 2823 return; 2824 } 2825 2826 /* Get NVRAM data. */ 2827 if (ql_nv_util_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr), 2828 mode) != 0) { 2829 cmd->Status = EXT_STATUS_COPY_ERR; 2830 cmd->ResponseLen = 0; 2831 EL(ha, "failed, copy error\n"); 2832 } else { 2833 cmd->ResponseLen = nv_size; 2834 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2835 } 2836 } 2837 2838 /* 2839 * ql_write_nvram 2840 * Loads NVRAM contents. 2841 * 2842 * Input: 2843 * ha: adapter state pointer. 2844 * cmd: EXT_IOCTL cmd struct pointer. 2845 * mode: flags. 2846 * 2847 * Returns: 2848 * None, request status indicated in cmd->Status. 2849 * 2850 * Context: 2851 * Kernel context. 2852 */ 2853 static void 2854 ql_write_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2855 { 2856 uint32_t nv_size; 2857 2858 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2859 2860 nv_size = (uint32_t)(CFG_IST(ha, CFG_CTRL_2425) ? 2861 sizeof (nvram_24xx_t) : sizeof (nvram_t)); 2862 if (cmd->RequestLen < nv_size) { 2863 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 2864 cmd->DetailStatus = sizeof (nvram_t); 2865 EL(ha, "failed, RequestLen != NVRAM, Len=%xh\n", 2866 cmd->RequestLen); 2867 return; 2868 } 2869 2870 /* Load NVRAM data. */ 2871 if (ql_nv_util_load(ha, (void *)(uintptr_t)(cmd->RequestAdr), 2872 mode) != 0) { 2873 cmd->Status = EXT_STATUS_COPY_ERR; 2874 EL(ha, "failed, copy error\n"); 2875 } else { 2876 /*EMPTY*/ 2877 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2878 } 2879 } 2880 2881 /* 2882 * ql_write_vpd 2883 * Loads VPD contents. 2884 * 2885 * Input: 2886 * ha: adapter state pointer. 2887 * cmd: EXT_IOCTL cmd struct pointer. 2888 * mode: flags. 2889 * 2890 * Returns: 2891 * None, request status indicated in cmd->Status. 2892 * 2893 * Context: 2894 * Kernel context. 2895 */ 2896 static void 2897 ql_write_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2898 { 2899 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2900 2901 int32_t rval = 0; 2902 2903 if ((CFG_IST(ha, CFG_CTRL_2425)) == 0) { 2904 cmd->Status = EXT_STATUS_INVALID_REQUEST; 2905 EL(ha, "failed, invalid request for HBA\n"); 2906 return; 2907 } 2908 2909 if (cmd->RequestLen < QL_24XX_VPD_SIZE) { 2910 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 2911 cmd->DetailStatus = QL_24XX_VPD_SIZE; 2912 EL(ha, "failed, RequestLen != VPD len, len passed=%xh\n", 2913 cmd->RequestLen); 2914 return; 2915 } 2916 2917 /* Load VPD data. */ 2918 if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)(cmd->RequestAdr), 2919 mode)) != 0) { 2920 cmd->Status = EXT_STATUS_COPY_ERR; 2921 cmd->DetailStatus = rval; 2922 EL(ha, "failed, errno=%x\n", rval); 2923 } else { 2924 /*EMPTY*/ 2925 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2926 } 2927 } 2928 2929 /* 2930 * ql_read_vpd 2931 * Dumps VPD contents. 2932 * 2933 * Input: 2934 * ha: adapter state pointer. 2935 * cmd: EXT_IOCTL cmd struct pointer. 2936 * mode: flags. 2937 * 2938 * Returns: 2939 * None, request status indicated in cmd->Status. 2940 * 2941 * Context: 2942 * Kernel context. 2943 */ 2944 static void 2945 ql_read_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2946 { 2947 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2948 2949 if ((CFG_IST(ha, CFG_CTRL_2425)) == 0) { 2950 cmd->Status = EXT_STATUS_INVALID_REQUEST; 2951 EL(ha, "failed, invalid request for HBA\n"); 2952 return; 2953 } 2954 2955 if (cmd->ResponseLen < QL_24XX_VPD_SIZE) { 2956 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 2957 cmd->DetailStatus = QL_24XX_VPD_SIZE; 2958 EL(ha, "failed, ResponseLen < VPD len, len passed=%xh\n", 2959 cmd->ResponseLen); 2960 return; 2961 } 2962 2963 /* Dump VPD data. */ 2964 if ((ql_vpd_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr), 2965 mode)) != 0) { 2966 cmd->Status = EXT_STATUS_COPY_ERR; 2967 EL(ha, "failed,\n"); 2968 } else { 2969 /*EMPTY*/ 2970 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 2971 } 2972 } 2973 2974 /* 2975 * ql_get_fcache 2976 * Dumps flash cache contents. 2977 * 2978 * Input: 2979 * ha: adapter state pointer. 2980 * cmd: EXT_IOCTL cmd struct pointer. 2981 * mode: flags. 2982 * 2983 * Returns: 2984 * None, request status indicated in cmd->Status. 2985 * 2986 * Context: 2987 * Kernel context. 2988 */ 2989 static void 2990 ql_get_fcache(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 2991 { 2992 uint32_t bsize, boff, types, cpsize, hsize; 2993 ql_fcache_t *fptr; 2994 2995 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 2996 2997 CACHE_LOCK(ha); 2998 2999 if (ha->fcache == NULL) { 3000 CACHE_UNLOCK(ha); 3001 cmd->Status = EXT_STATUS_ERR; 3002 EL(ha, "failed, adapter fcache not setup\n"); 3003 return; 3004 } 3005 3006 if ((CFG_IST(ha, CFG_CTRL_2425)) == 0) { 3007 bsize = 100; 3008 } else { 3009 bsize = 400; 3010 } 3011 3012 if (cmd->ResponseLen < bsize) { 3013 CACHE_UNLOCK(ha); 3014 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 3015 cmd->DetailStatus = bsize; 3016 EL(ha, "failed, ResponseLen < %d, len passed=%xh\n", 3017 bsize, cmd->ResponseLen); 3018 return; 3019 } 3020 3021 boff = 0; 3022 bsize = 0; 3023 fptr = ha->fcache; 3024 3025 /* 3026 * For backwards compatibility, get one of each image type 3027 */ 3028 types = (FTYPE_BIOS | FTYPE_FCODE | FTYPE_EFI); 3029 while ((fptr != NULL) && (fptr->buf != NULL) && (types != 0)) { 3030 /* Get the next image */ 3031 if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) { 3032 3033 cpsize = (fptr->buflen < 100 ? fptr->buflen : 100); 3034 3035 if (ddi_copyout(fptr->buf, 3036 (void *)(uintptr_t)(cmd->ResponseAdr + boff), 3037 cpsize, mode) != 0) { 3038 CACHE_UNLOCK(ha); 3039 EL(ha, "ddicopy failed, exiting\n"); 3040 cmd->Status = EXT_STATUS_COPY_ERR; 3041 cmd->DetailStatus = 0; 3042 return; 3043 } 3044 boff += 100; 3045 bsize += cpsize; 3046 types &= ~(fptr->type); 3047 } 3048 } 3049 3050 /* 3051 * Get the firmware image -- it needs to be last in the 3052 * buffer at offset 300 for backwards compatibility. Also for 3053 * backwards compatibility, the pci header is stripped off. 3054 */ 3055 if ((fptr = ql_get_fbuf(ha->fcache, FTYPE_FW)) != NULL) { 3056 3057 hsize = sizeof (pci_header_t) + sizeof (pci_data_t); 3058 if (hsize > fptr->buflen) { 3059 CACHE_UNLOCK(ha); 3060 EL(ha, "header size (%xh) exceeds buflen (%xh)\n", 3061 hsize, fptr->buflen); 3062 cmd->Status = EXT_STATUS_COPY_ERR; 3063 cmd->DetailStatus = 0; 3064 return; 3065 } 3066 3067 cpsize = ((fptr->buflen - hsize) < 100 ? 3068 fptr->buflen - hsize : 100); 3069 3070 if (ddi_copyout(fptr->buf+hsize, 3071 (void *)(uintptr_t)(cmd->ResponseAdr + 300), 3072 cpsize, mode) != 0) { 3073 CACHE_UNLOCK(ha); 3074 EL(ha, "fw ddicopy failed, exiting\n"); 3075 cmd->Status = EXT_STATUS_COPY_ERR; 3076 cmd->DetailStatus = 0; 3077 return; 3078 } 3079 bsize += 100; 3080 } 3081 3082 CACHE_UNLOCK(ha); 3083 cmd->Status = EXT_STATUS_OK; 3084 cmd->DetailStatus = bsize; 3085 3086 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 3087 } 3088 3089 /* 3090 * ql_get_fcache_ex 3091 * Dumps flash cache contents. 3092 * 3093 * Input: 3094 * ha: adapter state pointer. 3095 * cmd: EXT_IOCTL cmd struct pointer. 3096 * mode: flags. 3097 * 3098 * Returns: 3099 * None, request status indicated in cmd->Status. 3100 * 3101 * Context: 3102 * Kernel context. 3103 */ 3104 static void 3105 ql_get_fcache_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 3106 { 3107 uint32_t bsize = 0; 3108 uint32_t boff = 0; 3109 ql_fcache_t *fptr; 3110 3111 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 3112 3113 CACHE_LOCK(ha); 3114 if (ha->fcache == NULL) { 3115 CACHE_UNLOCK(ha); 3116 cmd->Status = EXT_STATUS_ERR; 3117 EL(ha, "failed, adapter fcache not setup\n"); 3118 return; 3119 } 3120 3121 /* Make sure user passed enough buffer space */ 3122 for (fptr = ha->fcache; fptr != NULL; fptr = fptr->next) { 3123 bsize += FBUFSIZE; 3124 } 3125 3126 if (cmd->ResponseLen < bsize) { 3127 CACHE_UNLOCK(ha); 3128 if (cmd->ResponseLen != 0) { 3129 EL(ha, "failed, ResponseLen < %d, len passed=%xh\n", 3130 bsize, cmd->ResponseLen); 3131 } 3132 cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL; 3133 cmd->DetailStatus = bsize; 3134 return; 3135 } 3136 3137 boff = 0; 3138 fptr = ha->fcache; 3139 while ((fptr != NULL) && (fptr->buf != NULL)) { 3140 /* Get the next image */ 3141 if (ddi_copyout(fptr->buf, 3142 (void *)(uintptr_t)(cmd->ResponseAdr + boff), 3143 (fptr->buflen < FBUFSIZE ? fptr->buflen : FBUFSIZE), 3144 mode) != 0) { 3145 CACHE_UNLOCK(ha); 3146 EL(ha, "failed, ddicopy at %xh, exiting\n", boff); 3147 cmd->Status = EXT_STATUS_COPY_ERR; 3148 cmd->DetailStatus = 0; 3149 return; 3150 } 3151 boff += FBUFSIZE; 3152 fptr = fptr->next; 3153 } 3154 3155 CACHE_UNLOCK(ha); 3156 cmd->Status = EXT_STATUS_OK; 3157 cmd->DetailStatus = bsize; 3158 3159 QL_PRINT_9(CE_CONT, "(%d): exiting\n", ha->instance); 3160 } 3161 3162 3163 /* 3164 * ql_read_flash 3165 * Get flash contents. 3166 * 3167 * Input: 3168 * ha: adapter state pointer. 3169 * cmd: EXT_IOCTL cmd struct pointer. 3170 * mode: flags. 3171 * 3172 * Returns: 3173 * None, request status indicated in cmd->Status. 3174 * 3175 * Context: 3176 * Kernel context. 3177 */ 3178 static void 3179 ql_read_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode) 3180 { 3181 ql_xioctl_t *xp = ha->xioctl; 3182 3183 QL_PRINT_9(CE_CONT, "(%d): entered\n", ha->instance); 3184 3185 if (ql_stall_driver(ha, 0) != QL_SUCCESS) { 3186 EL(ha, "ql_stall_driver failed\n"); 3187 cmd->Status = EXT_STATUS_BUSY; 3188 cmd->DetailStatus = xp->fdesc.flash_size; 3189 cmd->ResponseLen = 0; 3190 return; 3191 } 3192 3193 if (ql_setup_flash(ha) != QL_SUCCESS) { 3194 cmd->Status = EXT_STATUS_ERR; 3195 cmd->DetailStatus = xp->fdesc.flash_size; 3196 EL(ha, "failed, ResponseLen=%xh, flash size=%xh\n", 3197 cmd->ResponseLen, xp->fdesc.flash_size); 3198 cmd->ResponseLen = 0; 3199 } else { 3200 /* adjust read size to flash size */ 3201 if (cmd->ResponseLen > xp->fdesc.flash_size) { 3202