/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at * http://www.opensource.org/licenses/cddl1.txt. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2004-2012 Emulex. All rights reserved. * Use is subject to license terms. * Copyright 2020 RackTop Systems, Inc. */ #include /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ EMLXS_MSG_DEF(EMLXS_DFC_C); static int32_t emlxs_dfc_get_rev(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_hbainfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_reset_port(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); #ifdef SFCT_SUPPORT static int32_t emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); #endif /* SFCT_SUPPORT */ static int32_t emlxs_dfc_create_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_destroy_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_vportinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_npiv_resource(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_npiv_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static emlxs_port_t *emlxs_vport_find_wwpn(emlxs_hba_t *hba, uint8_t *wwpn); #ifdef DHCHAP_SUPPORT static int32_t emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); #endif /* DHCHAP_SUPPORT */ #ifdef SAN_DIAG_SUPPORT static int32_t emlxs_dfc_sd_set_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_destroy_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_get_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_start_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); #endif /* SAN_DIAG_SUPPORT */ static int32_t emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); #ifdef FCIO_SUPPORT static int32_t emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_fcio_get_num_devs(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_dev_list(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_sym_pname(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_sym_nname(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_unsupported(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_logi_params(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_state(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_fcode_rev(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_fw_rev(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_dump_size(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_force_dump(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_dump(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_topology(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_reset_link(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_reset_hard(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_diag(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_download_fw(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_host_params(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_link_status(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_download_fcode(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_node_id(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_set_node_id(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_adapter_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_other_adapter_ports(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_adapter_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_disc_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode); static int32_t emlxs_fcio_get_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode); #endif /* FCIO_SUPPORT */ static int32_t emlxs_dfc_get_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_set_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); /* SLI-4 ioctls */ static int32_t emlxs_dfc_get_fcflist(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_send_mbox4(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int emlxs_dfc_rd_be_fcf(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int emlxs_dfc_set_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int emlxs_dfc_get_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); static int emlxs_dfc_get_qos(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); uint32_t emlxs_loopback_tmo = 60; typedef struct { uint32_t code; char string[32]; int (*func)(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode); } emlxs_dfc_table_t; emlxs_dfc_table_t emlxs_dfc_table[] = { {EMLXS_GET_HBAINFO, "GET_HBAINFO", emlxs_dfc_get_hbainfo}, {EMLXS_GET_REV, "GET_REV", emlxs_dfc_get_rev}, {EMLXS_SET_DIAG, "SET_DIAG", emlxs_dfc_set_diag}, {EMLXS_SEND_MBOX, "SEND_MBOX", emlxs_dfc_send_mbox}, {EMLXS_READ_PCI, "READ_PCI", emlxs_dfc_read_pci}, {EMLXS_WRITE_PCI, "WRITE_PCI", emlxs_dfc_write_pci}, {EMLXS_GET_CFG, "GET_CFG", emlxs_dfc_get_cfg}, {EMLXS_SET_CFG, "SET_CFG", emlxs_dfc_set_cfg}, {EMLXS_SEND_CT, "SEND_CT", emlxs_dfc_send_ct}, {EMLXS_SEND_CT_RSP, "SEND_CT_RSP", emlxs_dfc_send_ct_rsp}, {EMLXS_WRITE_FLASH, "WRITE_FLASH", emlxs_dfc_write_flash}, {EMLXS_READ_FLASH, "READ_FLASH", emlxs_dfc_read_flash}, {EMLXS_SEND_ELS, "SEND_ELS", emlxs_dfc_send_els}, {EMLXS_LOOPBACK_TEST, "LOOPBACK_TEST", emlxs_dfc_loopback_test}, {EMLXS_RESET_PORT, "RESET_PORT", emlxs_dfc_reset_port}, {EMLXS_GET_DUMPREGION, "GET_DUMPREGION", emlxs_dfc_get_dump_region}, {EMLXS_LOOPBACK_MODE, "LOOPBACK_MODE", emlxs_dfc_loopback_mode}, {EMLXS_GET_IOINFO, "GET_IOINFO", emlxs_dfc_get_ioinfo}, {EMLXS_GET_LINKINFO, "GET_LINKINFO", emlxs_dfc_get_linkinfo}, {EMLXS_GET_NODEINFO, "GET_NODEINFO", emlxs_dfc_get_nodeinfo}, {EMLXS_READ_MEM, "READ_MEM", emlxs_dfc_read_mem}, {EMLXS_WRITE_MEM, "WRITE_MEM", emlxs_dfc_write_mem}, {EMLXS_WRITE_CTLREG, "WRITE_CTLREG", emlxs_dfc_write_ctlreg}, {EMLXS_READ_CTLREG, "READ_CTLREG", emlxs_dfc_read_ctlreg}, {EMLXS_SEND_SCSI, "SEND_SCSI", emlxs_dfc_send_scsi_fcp}, {EMLXS_GET_EVENT, "GET_EVENT", emlxs_dfc_get_event}, {EMLXS_SET_EVENT, "SET_EVENT", emlxs_dfc_set_event}, {EMLXS_GET_EVENTINFO, "GET_EVENTINFO", emlxs_dfc_get_eventinfo}, {EMLXS_GET_HBASTATS, "GET_HBASTATS", emlxs_dfc_get_hbastats}, {EMLXS_GET_DRVSTATS, "GET_DRVSTATS", emlxs_dfc_get_drvstats}, {EMLXS_CREATE_VPORT, "CREATE_VPORT", emlxs_dfc_create_vport}, {EMLXS_DESTROY_VPORT, "DESTROY_VPORT", emlxs_dfc_destroy_vport}, {EMLXS_GET_VPORTINFO, "GET_VPORTINFO", emlxs_dfc_get_vportinfo}, {EMLXS_NPIV_RESOURCE, "NPIV_RESOURCE", emlxs_dfc_npiv_resource}, {EMLXS_NPIV_TEST, "NPIV_TEST", emlxs_dfc_npiv_test}, {EMLXS_GET_PERSIST_LINKDOWN, "GET_PERSIST_LINKDOWN", emlxs_dfc_get_persist_linkdown}, {EMLXS_SET_PERSIST_LINKDOWN, "SET_PERSIST_LINKDOWN", emlxs_dfc_set_persist_linkdown}, {EMLXS_GET_FCOE_FCFLIST, "GET_FCOE_FCFLIST", emlxs_dfc_get_fcflist}, {EMLXS_SEND_MBOX4, "SEND_MBOX4", emlxs_dfc_send_mbox4}, {EMLXS_RD_BE_FCF, "RD_BE_FCF", emlxs_dfc_rd_be_fcf}, {EMLXS_SET_BE_DCBX, "SET_BE_DCBX", emlxs_dfc_set_be_dcbx}, {EMLXS_GET_BE_DCBX, "GET_BE_DCBX", emlxs_dfc_get_be_dcbx}, {EMLXS_GET_QOS, "GET_QOS", emlxs_dfc_get_qos}, #ifdef MENLO_SUPPORT {EMLXS_SEND_MENLO, "SEND_MENLO", emlxs_dfc_send_menlo}, #endif /* MENLO_SUPPORT */ #ifdef DHCHAP_SUPPORT {EMLXS_INIT_AUTH, "INIT_AUTH", emlxs_dfc_init_auth}, {EMLXS_GET_AUTH_CFG, "GET_AUTH_CFG", emlxs_dfc_get_auth_cfg}, {EMLXS_SET_AUTH_CFG, "SET_AUTH_CFG", emlxs_dfc_set_auth_cfg}, {EMLXS_GET_AUTH_PASSWORD, "GET_AUTH_PASSWORD", emlxs_dfc_get_auth_pwd}, {EMLXS_SET_AUTH_PASSWORD, "SET_AUTH_PASSWORD", emlxs_dfc_set_auth_pwd}, {EMLXS_GET_AUTH_STATUS, "GET_AUTH_STATUS", emlxs_dfc_get_auth_status}, {EMLXS_GET_AUTH_CFG_TABLE, "GET_AUTH_CFG_TABLE", emlxs_dfc_get_auth_cfg_table}, {EMLXS_GET_AUTH_KEY_TABLE, "GET_AUTH_KEY_TABLE", emlxs_dfc_get_auth_key_table}, #endif /* DHCHAP_SUPPORT */ #ifdef FCIO_SUPPORT {EMLXS_FCIO_CMD, "FCIO_CMD", emlxs_fcio_manage}, #endif /* FCIO_SUPPORT */ #ifdef SFCT_SUPPORT {EMLXS_GET_FCTSTAT, "GET_FCTSTAT", emlxs_dfc_get_fctstat}, #endif /* SFCT_SUPPORT */ #ifdef SAN_DIAG_SUPPORT {EMLXS_SD_SET_BUCKET, "SD_SET_BUCKET", emlxs_dfc_sd_set_bucket}, {EMLXS_SD_DESTROY_BUCKET, "SD_DESTROY_BUCKET", emlxs_dfc_sd_destroy_bucket}, {EMLXS_SD_GET_BUCKET, "SD_GET_BUCKET", emlxs_dfc_sd_get_bucket}, {EMLXS_SD_START_DATA_COLLECTION, "SD_START_DATA_COLLECTION", emlxs_dfc_sd_start_collection}, {EMLXS_SD_STOP_DATA_COLLECTION, "SD_STOP_DATA_COLLECTION", emlxs_dfc_sd_stop_collection}, {EMLXS_SD_RESET_DATA_COLLECTION, "SD_RESET_DATA_COLLECTION", emlxs_dfc_sd_reset_collection}, {EMLXS_SD_GET_DATA, "SD_GET_DATA", emlxs_dfc_sd_get_data}, {EMLXS_SD_SET_EVENT, "SD_SET_EVENT", emlxs_dfc_sd_set_event}, {EMLXS_SD_GET_EVENT, "SD_GET_EVENT", emlxs_dfc_sd_get_event}, #endif /* SAN_DIAG_SUPPORT */ }; /* emlxs_dfc_table */ emlxs_table_t emlxs_dfc_event_table[] = { {FC_REG_LINK_EVENT, "LINK_EVENT"}, {FC_REG_RSCN_EVENT, "RSCN_EVENT"}, {FC_REG_CT_EVENT, "CT_EVENT"}, {FC_REG_DUMP_EVENT, "DUMP_EVENT"}, {FC_REG_TEMP_EVENT, "TEMP_EVENT"}, {FC_REG_VPORTRSCN_EVENT, "VPORTRSCN_EVENT"}, {FC_REG_FCOE_EVENT, "FCOE_EVENT"}, }; /* emlxs_dfc_event_table */ #ifdef SAN_DIAG_SUPPORT kmutex_t emlxs_sd_bucket_mutex; sd_bucket_info_t emlxs_sd_bucket; #endif /* SAN_DIAG_SUPPORT */ extern char * emlxs_dfc_xlate(uint16_t cmd) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_dfc_table) / sizeof (emlxs_dfc_table_t); for (i = 0; i < count; i++) { if (cmd == emlxs_dfc_table[i].code) { return (emlxs_dfc_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "Cmd=0x%x", cmd); return (buffer); } /* emlxs_dfc_xlate() */ static int emlxs_dfc_func(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t i; uint32_t count; int rval; count = sizeof (emlxs_dfc_table) / sizeof (emlxs_dfc_table_t); for (i = 0; i < count; i++) { if (dfc->cmd == emlxs_dfc_table[i].code) { if ((dfc->cmd != EMLXS_FCIO_CMD) || (dfc->data1 != FCIO_DIAG) || (dfc->data2 != EMLXS_LOG_GET)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_table[i].string); } rval = emlxs_dfc_table[i].func(hba, dfc, mode); return (rval); } } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "Unknown DFC command. (0x%x)", dfc->cmd); return (DFC_ARG_INVALID); } /* emlxs_dfc_func() */ extern char * emlxs_dfc_event_xlate(uint32_t event) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_dfc_event_table) / sizeof (emlxs_table_t); for (i = 0; i < count; i++) { if (event == emlxs_dfc_event_table[i].code) { return (emlxs_dfc_event_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "Event=0x%x", event); return (buffer); } /* emlxs_dfc_event_xlate() */ static int32_t emlxs_dfc_copyin(emlxs_hba_t *hba, void *arg, dfc_t *dfc1, dfc_t *dfc2, int32_t mode) { emlxs_port_t *port = &PPORT; int rval = 0; uint32_t use32 = 0; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { dfc32_t dfc32; if (ddi_copyin((void *)arg, (void *)&dfc32, sizeof (dfc32_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "ddi_copyin32 failed."); rval = DFC_COPYIN_ERROR; goto done; } dfc1->cmd = dfc32.cmd; dfc1->flag = dfc32.flag; dfc1->buf1 = (void *)((uintptr_t)dfc32.buf1); dfc1->buf1_size = dfc32.buf1_size; dfc1->data1 = dfc32.data1; dfc1->buf2 = (void *)((uintptr_t)dfc32.buf2); dfc1->buf2_size = dfc32.buf2_size; dfc1->data2 = dfc32.data2; dfc1->buf3 = (void *)((uintptr_t)dfc32.buf3); dfc1->buf3_size = dfc32.buf3_size; dfc1->data3 = dfc32.data3; dfc1->buf4 = (void *)((uintptr_t)dfc32.buf4); dfc1->buf4_size = dfc32.buf4_size; dfc1->data4 = dfc32.data4; } else { if (ddi_copyin((void *)arg, (void *)dfc1, sizeof (dfc_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "ddi_copyin failed."); rval = DFC_COPYIN_ERROR; goto done; } } /* Map dfc1 to dfc2 */ dfc2->cmd = dfc1->cmd; dfc2->flag = dfc1->flag; dfc2->data1 = dfc1->data1; dfc2->data2 = dfc1->data2; dfc2->data3 = dfc1->data3; dfc2->data4 = dfc1->data4; dfc2->buf1 = 0; dfc2->buf1_size = 0; dfc2->buf2 = 0; dfc2->buf2_size = 0; dfc2->buf3 = 0; dfc2->buf3_size = 0; dfc2->buf4 = 0; dfc2->buf4_size = 0; /* Copyin data buffers */ if (dfc1->buf1_size && dfc1->buf1) { dfc2->buf1_size = dfc1->buf1_size; dfc2->buf1 = kmem_zalloc(dfc1->buf1_size, KM_SLEEP); if (ddi_copyin(dfc1->buf1, dfc2->buf1, dfc1->buf1_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buf1 ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc1->cmd), dfc1->buf1_size); rval = DFC_COPYIN_ERROR; goto done; } } if (dfc1->buf2_size && dfc1->buf2) { dfc2->buf2_size = dfc1->buf2_size; dfc2->buf2 = kmem_zalloc(dfc1->buf2_size, KM_SLEEP); if (ddi_copyin(dfc1->buf2, dfc2->buf2, dfc1->buf2_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buf2 ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc1->cmd), dfc1->buf2_size); rval = DFC_COPYIN_ERROR; goto done; } } if (dfc1->buf3_size && dfc1->buf3) { dfc2->buf3_size = dfc1->buf3_size; dfc2->buf3 = kmem_zalloc(dfc1->buf3_size, KM_SLEEP); if (ddi_copyin(dfc1->buf3, dfc2->buf3, dfc1->buf3_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s buf3 ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc1->cmd), dfc1->buf3_size); rval = DFC_COPYIN_ERROR; goto done; } } if (dfc1->buf4_size && dfc1->buf4) { dfc2->buf4_size = dfc1->buf4_size; dfc2->buf4 = kmem_zalloc(dfc1->buf4_size, KM_SLEEP); if (ddi_copyin(dfc1->buf4, dfc2->buf4, dfc1->buf4_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buf4 ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc1->cmd), dfc1->buf4_size); rval = DFC_COPYIN_ERROR; goto done; } } done: return (rval); } /* emlxs_dfc_copyin() */ static int32_t emlxs_dfc_copyout(emlxs_hba_t *hba, void *arg, dfc_t *dfc2, dfc_t *dfc1, int32_t mode) { emlxs_port_t *port = &PPORT; int rval = 0; uint32_t use32 = 0; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ /* Copyout data buffers */ if (dfc2->buf1) { if (ddi_copyout(dfc2->buf1, dfc1->buf1, dfc1->buf1_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buf1 ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc2->cmd), dfc2->buf1_size); rval = DFC_COPYOUT_ERROR; } kmem_free(dfc2->buf1, dfc2->buf1_size); dfc2->buf1 = 0; } if (dfc2->buf2) { if (ddi_copyout(dfc2->buf2, dfc1->buf2, dfc1->buf2_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buf2 ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc2->cmd), dfc2->buf2_size); rval = DFC_COPYOUT_ERROR; } kmem_free(dfc2->buf2, dfc2->buf2_size); dfc2->buf2 = 0; } if (dfc2->buf3) { if (ddi_copyout(dfc2->buf3, dfc1->buf3, dfc1->buf3_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s buf3 ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc2->cmd), dfc2->buf3_size); rval = DFC_COPYOUT_ERROR; } kmem_free(dfc2->buf3, dfc2->buf3_size); dfc2->buf3 = 0; } if (dfc2->buf4) { if (ddi_copyout(dfc2->buf4, dfc1->buf4, dfc1->buf4_size, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buf4 ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc2->cmd), dfc2->buf4_size); rval = DFC_COPYOUT_ERROR; } kmem_free(dfc2->buf4, dfc2->buf4_size); dfc2->buf4 = 0; } if (use32) { dfc32_t dfc32; dfc32.cmd = dfc1->cmd; dfc32.flag = dfc1->flag; dfc32.buf1 = (uint32_t)((uintptr_t)dfc1->buf1); dfc32.buf1_size = dfc1->buf1_size; dfc32.data1 = dfc1->data1; dfc32.buf2 = (uint32_t)((uintptr_t)dfc1->buf2); dfc32.buf2_size = dfc1->buf2_size; dfc32.data2 = dfc1->data2; dfc32.buf3 = (uint32_t)((uintptr_t)dfc1->buf3); dfc32.buf3_size = dfc1->buf3_size; dfc32.data3 = dfc1->data3; dfc32.buf4 = (uint32_t)((uintptr_t)dfc1->buf4); dfc32.buf4_size = dfc1->buf4_size; dfc32.data4 = dfc1->data4; if (ddi_copyout((void *)&dfc32, (void *)arg, sizeof (dfc32_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "ddi_copyout32 failed."); rval = DFC_COPYOUT_ERROR; goto done; } } else { if (ddi_copyout((void *)dfc1, (void *)arg, sizeof (dfc_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "ddi_copyout failed."); rval = DFC_COPYOUT_ERROR; goto done; } } done: return (rval); } /* emlxs_dfc_copyout() */ extern int32_t emlxs_dfc_manage(emlxs_hba_t *hba, void *arg, int32_t mode) { dfc_t dfc1; dfc_t dfc2; int rval = 0; /* This copies arg data to dfc1 space, */ /* then creates local dfc2 buffers */ rval = emlxs_dfc_copyin(hba, arg, &dfc1, &dfc2, mode); if (rval) { return (rval); } rval = emlxs_dfc_func(hba, &dfc2, mode); if (rval) { return (rval); } /* This copies dfc2 local buffers back to dfc1 addresses */ rval = emlxs_dfc_copyout(hba, arg, &dfc2, &dfc1, mode); return (rval); } /* emlxs_dfc_manage() */ #ifdef FCIO_SUPPORT typedef struct { uint32_t code; char string[32]; int (*func)(emlxs_port_t *port, fcio_t *fcio, int32_t mode); } emlxs_fcio_table_t; emlxs_fcio_table_t emlxs_fcio_table[] = { {FCIO_GET_NUM_DEVS, "GET_NUM_DEVS", emlxs_fcio_get_num_devs}, {FCIO_GET_DEV_LIST, "GET_DEV_LIST", emlxs_fcio_get_dev_list}, {FCIO_GET_SYM_PNAME, "GET_SYM_PNAME", emlxs_fcio_get_sym_pname}, {FCIO_GET_SYM_NNAME, "GET_SYM_NNAME", emlxs_fcio_get_sym_nname}, {FCIO_SET_SYM_PNAME, "SET_SYM_PNAME", emlxs_fcio_unsupported}, {FCIO_SET_SYM_NNAME, "SET_SYM_NNAME", emlxs_fcio_unsupported}, {FCIO_GET_LOGI_PARAMS, "GET_LOGI_PARAMS", emlxs_fcio_get_logi_params}, {FCIO_DEV_LOGIN, "DEV_LOGIN", emlxs_fcio_unsupported}, {FCIO_DEV_LOGOUT, "DEV_LOGOUT", emlxs_fcio_unsupported}, {FCIO_GET_STATE, "GET_STATE", emlxs_fcio_get_state}, {FCIO_DEV_REMOVE, "DEV_REMOVE", emlxs_fcio_unsupported}, {FCIO_GET_FCODE_REV, "GET_FCODE_REV", emlxs_fcio_get_fcode_rev}, {FCIO_GET_FW_REV, "GET_FW_REV", emlxs_fcio_get_fw_rev}, {FCIO_GET_DUMP_SIZE, "GET_DUMP_SIZE", emlxs_fcio_get_dump_size}, {FCIO_FORCE_DUMP, "FORCE_DUMP", emlxs_fcio_force_dump}, {FCIO_GET_DUMP, "GET_DUMP", emlxs_fcio_get_dump}, {FCIO_GET_TOPOLOGY, "GET_TOPOLOGY", emlxs_fcio_get_topology}, {FCIO_RESET_LINK, "RESET_LINK", emlxs_fcio_reset_link}, {FCIO_RESET_HARD, "RESET_HARD", emlxs_fcio_reset_hard}, {FCIO_RESET_HARD_CORE, "RESET_HARD_CORE", emlxs_fcio_reset_hard}, {FCIO_DIAG, "DIAG", emlxs_fcio_diag}, {FCIO_NS, "NS", emlxs_fcio_unsupported}, {FCIO_DOWNLOAD_FW, "DOWNLOAD_FW", emlxs_fcio_download_fw}, {FCIO_GET_HOST_PARAMS, "GET_HOST_PARAMS", emlxs_fcio_get_host_params}, {FCIO_LINK_STATUS, "LINK_STATUS", emlxs_fcio_get_link_status}, {FCIO_DOWNLOAD_FCODE, "DOWNLOAD_FCODE", emlxs_fcio_download_fcode}, {FCIO_GET_NODE_ID, "GET_NODE_ID", emlxs_fcio_get_node_id}, {FCIO_SET_NODE_ID, "SET_NODE_ID", emlxs_fcio_set_node_id}, {FCIO_SEND_NODE_ID, "SEND_NODE_ID", emlxs_fcio_unsupported}, /* {FCIO_GET_P2P_INFO, "GET_P2P_INFO", emlxs_fcio_get_p2p_info}, */ {FCIO_GET_ADAPTER_ATTRIBUTES, "GET_ADAPTER_ATTRIBUTES", emlxs_fcio_get_adapter_attrs}, {FCIO_GET_OTHER_ADAPTER_PORTS, "GET_OTHER_ADAPTER_PORTS", emlxs_fcio_get_other_adapter_ports}, {FCIO_GET_ADAPTER_PORT_ATTRIBUTES, "GET_ADAPTER_PORT_ATTRIBUTES", emlxs_fcio_get_adapter_port_attrs}, {FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, "GET_DISCOVERED_PORT_ATTRIBUTES", emlxs_fcio_get_disc_port_attrs}, {FCIO_GET_PORT_ATTRIBUTES, "GET_PORT_ATTRIBUTES", emlxs_fcio_get_port_attrs}, {FCIO_GET_ADAPTER_PORT_STATS, "GET_ADAPTER_PORT_STATS", emlxs_fcio_unsupported}, }; /* emlxs_fcio_table */ extern char * emlxs_fcio_xlate(uint16_t cmd) { static char buffer[32]; uint32_t i; uint32_t count; count = sizeof (emlxs_fcio_table) / sizeof (emlxs_fcio_table_t); for (i = 0; i < count; i++) { if (cmd == emlxs_fcio_table[i].code) { return (emlxs_fcio_table[i].string); } } (void) snprintf(buffer, sizeof (buffer), "Cmd=0x%x", cmd); return (buffer); } /* emlxs_fcio_xlate() */ static int emlxs_fcio_func(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { uint32_t i; uint32_t count; int rval; count = sizeof (emlxs_fcio_table) / sizeof (emlxs_fcio_table_t); for (i = 0; i < count; i++) { if (fcio->fcio_cmd == emlxs_fcio_table[i].code) { if ((fcio->fcio_cmd != FCIO_DIAG) || (fcio->fcio_cmd_flags != EMLXS_LOG_GET)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_fcio_table[i].string); } rval = emlxs_fcio_table[i].func(port, fcio, mode); return (rval); } } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "Unknown FCIO command. (0x%x)", fcio->fcio_cmd); return (EFAULT); } /* emlxs_fcio_func() */ /* This is used by FCT ports to mimic SFS ports for FCIO support */ /*ARGSUSED*/ extern int32_t emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; int32_t rval = 0; fcio_t fcio; uint32_t vpi; /* Map DFC to FCIO */ vpi = (dfc->data4 < MAX_VPORTS)? dfc->data4:0; port = &VPORT(vpi); bzero(&fcio, sizeof (fcio_t)); fcio.fcio_flags = dfc->flag; fcio.fcio_cmd = dfc->data1; fcio.fcio_cmd_flags = dfc->data2; fcio.fcio_xfer = dfc->data3; if (dfc->buf1_size && dfc->buf1) { fcio.fcio_ilen = dfc->buf1_size; fcio.fcio_ibuf = dfc->buf1; } if (dfc->buf2_size && dfc->buf2) { fcio.fcio_olen = dfc->buf2_size; fcio.fcio_obuf = dfc->buf2; } if (dfc->buf3_size && dfc->buf3) { fcio.fcio_alen = dfc->buf3_size; fcio.fcio_abuf = dfc->buf3; } if (!dfc->buf4 || (dfc->buf4_size < sizeof (uint32_t))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: buf4 invalid. (buf4=%p size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), dfc->buf4, dfc->buf4_size); rval = EFAULT; goto done; } rval = emlxs_fcio_func(port, &fcio, mode); /* Map FCIO to DFC */ dfc->flag = fcio.fcio_flags; dfc->data1 = fcio.fcio_cmd; dfc->data2 = fcio.fcio_cmd_flags; dfc->data3 = fcio.fcio_xfer; done: /* Set fcio_errno if needed */ if ((rval != 0) && (fcio.fcio_errno == 0)) { fcio.fcio_errno = FC_FAILURE; } bcopy((void *)&fcio.fcio_errno, (void *)dfc->buf4, sizeof (uint32_t)); return (rval); } /* emlxs_fcio_manage() */ /*ARGSUSED*/ static int32_t emlxs_fcio_diag(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { fc_fca_pm_t pm; int32_t rval = 0; bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); pm.pm_cmd_len = fcio->fcio_ilen; pm.pm_cmd_buf = fcio->fcio_ibuf; pm.pm_data_len = fcio->fcio_alen; pm.pm_data_buf = fcio->fcio_abuf; pm.pm_stat_len = fcio->fcio_olen; pm.pm_stat_buf = fcio->fcio_obuf; pm.pm_cmd_code = FC_PORT_DIAG; pm.pm_cmd_flags = fcio->fcio_cmd_flags; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } } if (fcio->fcio_olen > pm.pm_stat_len) { fcio->fcio_olen = pm.pm_stat_len; } return (rval); } /* emlxs_fcio_diag() */ #ifndef _MULTI_DATAMODEL /* ARGSUSED */ #endif static int32_t emlxs_fcio_get_host_params(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t use32 = 0; emlxs_config_t *cfg = &CFG; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { fc_port_dev32_t *port_dev; uint32_t i; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen != sizeof (fc_port_dev32_t)) { rval = EINVAL; goto done; } port_dev = (fc_port_dev32_t *)fcio->fcio_obuf; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "fcio_get_host_params: fct_flags=%x ulp_statec=%x", port->fct_flags, port->ulp_statec); if ((port->mode == MODE_TARGET) && (port->fct_port) && (port->fct_flags & FCT_STATE_PORT_ONLINE)) { port_dev->dev_state = port->ulp_statec; port_dev->dev_did.port_id = port->did; if (hba->topology == TOPOLOGY_LOOP) { for (i = 0; i < port->alpa_map[0]; i++) { if (port->alpa_map[i + 1] == port->did) { port_dev->dev_did.priv_lilp_posit = (uint8_t)(i & 0xff); goto done; } } } } else { port_dev->dev_state = FC_STATE_OFFLINE; port_dev->dev_did.port_id = 0; } port_dev->dev_hard_addr.hard_addr = cfg[CFG_ASSIGN_ALPA].current; bcopy((caddr_t)&port->wwpn, (caddr_t)&port_dev->dev_pwwn, 8); bcopy((caddr_t)&port->wwnn, (caddr_t)&port_dev->dev_nwwn, 8); port_dev->dev_type[0] = LE_SWAP32(0x00000120); port_dev->dev_type[1] = LE_SWAP32(0x00000001); } else { fc_port_dev_t *port_dev; uint32_t i; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen != sizeof (fc_port_dev_t)) { rval = EINVAL; goto done; } port_dev = (fc_port_dev_t *)fcio->fcio_obuf; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "fcio_get_host_params: fct_flags=%x ulp_statec=%x", port->fct_flags, port->ulp_statec); if ((port->mode == MODE_TARGET) && (port->fct_port) && (port->fct_flags & FCT_STATE_PORT_ONLINE)) { port_dev->dev_state = port->ulp_statec; port_dev->dev_did.port_id = port->did; if (hba->topology == TOPOLOGY_LOOP) { for (i = 0; i < port->alpa_map[0]; i++) { if (port->alpa_map[i + 1] == port->did) { port_dev->dev_did.priv_lilp_posit = (uint8_t)(i & 0xff); goto done; } } } } else { port_dev->dev_state = FC_STATE_OFFLINE; port_dev->dev_did.port_id = 0; } port_dev->dev_hard_addr.hard_addr = cfg[CFG_ASSIGN_ALPA].current; bcopy((caddr_t)&port->wwpn, (caddr_t)&port_dev->dev_pwwn, 8); bcopy((caddr_t)&port->wwnn, (caddr_t)&port_dev->dev_nwwn, 8); port_dev->dev_type[0] = LE_SWAP32(0x00000120); port_dev->dev_type[1] = LE_SWAP32(0x00000001); } done: return (rval); } /* emlxs_fcio_get_host_params() */ /*ARGSUSED*/ static int32_t emlxs_fcio_reset_link(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; uint8_t null_wwn[8]; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen != 8) { rval = EINVAL; goto done; } if (port->mode != MODE_TARGET) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg, "fcio_reset_link failed. Port is not in target mode."); fcio->fcio_errno = FC_FAILURE; rval = EIO; goto done; } bzero(null_wwn, 8); if (bcmp((uint8_t *)fcio->fcio_ibuf, null_wwn, 8) == 0) { rval = emlxs_fca_reset(port, FC_FCA_LINK_RESET); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } } else { rval = ENOTSUP; } done: return (rval); } /* emlxs_fcio_reset_link() */ /*ARGSUSED*/ static int32_t emlxs_fcio_reset_hard(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; if (port->mode != MODE_TARGET) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg, "fcio_reset_hard failed. Port is not in target mode."); fcio->fcio_errno = FC_FAILURE; rval = EIO; goto done; } rval = emlxs_reset(port, FC_FCA_RESET); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_reset_hard() */ /*ARGSUSED*/ static int32_t emlxs_fcio_download_fw(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen == 0) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_WRITE; pm.pm_cmd_code = FC_PORT_DOWNLOAD_FW; pm.pm_data_len = fcio->fcio_ilen; pm.pm_data_buf = fcio->fcio_ibuf; rval = emlxs_fca_port_manage(port, &pm); if ((rval != FC_SUCCESS) && (rval != EMLXS_REBOOT_REQUIRED)) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_download_fw() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_fw_rev(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < FC_FW_REV_SIZE) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_READ; pm.pm_cmd_code = FC_PORT_GET_FW_REV; pm.pm_data_len = fcio->fcio_olen; pm.pm_data_buf = fcio->fcio_obuf; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_get_fw_rev() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_fcode_rev(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < FC_FCODE_REV_SIZE) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_READ; pm.pm_cmd_code = FC_PORT_GET_FCODE_REV; pm.pm_data_len = fcio->fcio_olen; pm.pm_data_buf = fcio->fcio_obuf; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_get_fcode_rev() */ /*ARGSUSED*/ static int32_t emlxs_fcio_download_fcode(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen == 0) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_WRITE; pm.pm_cmd_code = FC_PORT_DOWNLOAD_FCODE; pm.pm_data_len = fcio->fcio_ilen; pm.pm_data_buf = fcio->fcio_ibuf; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_download_fcode() */ #ifndef _MULTI_DATAMODEL /* ARGSUSED */ #endif static int32_t emlxs_fcio_get_adapter_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t use32 = 0; emlxs_vpd_t *vpd = &VPD; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { fc_hba_adapter_attributes32_t *hba_attrs; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_hba_adapter_attributes32_t)) { rval = EINVAL; goto done; } hba_attrs = (fc_hba_adapter_attributes32_t *)fcio->fcio_obuf; hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; (void) strncpy(hba_attrs->Manufacturer, hba->model_info.manufacturer, (sizeof (hba_attrs->Manufacturer)-1)); (void) strncpy(hba_attrs->SerialNumber, vpd->serial_num, (sizeof (hba_attrs->SerialNumber)-1)); (void) strncpy(hba_attrs->Model, hba->model_info.model, (sizeof (hba_attrs->Model)-1)); (void) strncpy(hba_attrs->ModelDescription, hba->model_info.model_desc, (sizeof (hba_attrs->ModelDescription)-1)); bcopy((caddr_t)&port->wwnn, (caddr_t)&hba_attrs->NodeWWN, 8); (void) strncpy((caddr_t)hba_attrs->NodeSymbolicName, (caddr_t)port->snn, (sizeof (hba_attrs->NodeSymbolicName)-1)); (void) snprintf(hba_attrs->HardwareVersion, (sizeof (hba_attrs->HardwareVersion)-1), "%x", vpd->biuRev); (void) snprintf(hba_attrs->DriverVersion, (sizeof (hba_attrs->DriverVersion)-1), "%s (%s)", emlxs_version, emlxs_revision); (void) strncpy(hba_attrs->OptionROMVersion, vpd->fcode_version, (sizeof (hba_attrs->OptionROMVersion)-1)); (void) snprintf(hba_attrs->FirmwareVersion, (sizeof (hba_attrs->FirmwareVersion)-1), "%s (%s)", vpd->fw_version, vpd->fw_label); (void) strncpy(hba_attrs->DriverName, DRIVER_NAME, (sizeof (hba_attrs->DriverName)-1)); hba_attrs->VendorSpecificID = (hba->model_info.device_id << 16) | hba->model_info.vendor_id; hba_attrs->NumberOfPorts = hba->num_of_ports; } else { fc_hba_adapter_attributes_t *hba_attrs; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_hba_adapter_attributes_t)) { rval = EINVAL; goto done; } hba_attrs = (fc_hba_adapter_attributes_t *)fcio->fcio_obuf; hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; (void) strncpy(hba_attrs->Manufacturer, hba->model_info.manufacturer, (sizeof (hba_attrs->Manufacturer)-1)); (void) strncpy(hba_attrs->SerialNumber, vpd->serial_num, (sizeof (hba_attrs->SerialNumber)-1)); (void) strncpy(hba_attrs->Model, hba->model_info.model, (sizeof (hba_attrs->Model)-1)); (void) strncpy(hba_attrs->ModelDescription, hba->model_info.model_desc, (sizeof (hba_attrs->ModelDescription)-1)); bcopy((caddr_t)&port->wwnn, (caddr_t)&hba_attrs->NodeWWN, 8); (void) strncpy((caddr_t)hba_attrs->NodeSymbolicName, (caddr_t)port->snn, (sizeof (hba_attrs->NodeSymbolicName)-1)); (void) snprintf(hba_attrs->HardwareVersion, (sizeof (hba_attrs->HardwareVersion)-1), "%x", vpd->biuRev); (void) snprintf(hba_attrs->DriverVersion, (sizeof (hba_attrs->DriverVersion)-1), "%s (%s)", emlxs_version, emlxs_revision); (void) strncpy(hba_attrs->OptionROMVersion, vpd->fcode_version, (sizeof (hba_attrs->OptionROMVersion)-1)); (void) snprintf(hba_attrs->FirmwareVersion, (sizeof (hba_attrs->FirmwareVersion)-1), "%s (%s)", vpd->fw_version, vpd->fw_label); (void) strncpy(hba_attrs->DriverName, DRIVER_NAME, (sizeof (hba_attrs->DriverName)-1)); hba_attrs->VendorSpecificID = (hba->model_info.device_id << 16) | hba->model_info.vendor_id; hba_attrs->NumberOfPorts = hba->num_of_ports; } done: return (rval); } /* emlxs_fcio_get_adapter_attrs() */ #ifndef _MULTI_DATAMODEL /* ARGSUSED */ #endif static int32_t emlxs_fcio_get_adapter_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t use32 = 0; emlxs_vpd_t *vpd = &VPD; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { fc_hba_port_attributes32_t *port_attrs; uint32_t value1; uint32_t value2; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_hba_port_attributes32_t)) { rval = EINVAL; goto done; } port_attrs = (fc_hba_port_attributes32_t *)fcio->fcio_obuf; port_attrs->version = FC_HBA_PORT_ATTRIBUTES_VERSION; port_attrs->lastChange = 0; port_attrs->fp_minor = 0; bcopy((caddr_t)&port->wwnn, (caddr_t)&port_attrs->NodeWWN, 8); bcopy((caddr_t)&port->wwpn, (caddr_t)&port_attrs->PortWWN, 8); if ((port->mode != MODE_TARGET) || (port->ulp_statec == FC_STATE_OFFLINE)) { /* port_attrs->PortFcId */ /* port_attrs->PortType */ /* port_attrs->PortSpeed */ /* port_attrs->FabricName */ port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE; } else { port_attrs->PortFcId = port->did; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; if (hba->topology == TOPOLOGY_LOOP) { if (hba->flag & FC_FABRIC_ATTACHED) { port_attrs->PortType = FC_HBA_PORTTYPE_NLPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } } else { if (hba->flag & FC_PT_TO_PT) { port_attrs->PortType = FC_HBA_PORTTYPE_PTP; } else { port_attrs->PortType = FC_HBA_PORTTYPE_NPORT; } } if (hba->flag & FC_FABRIC_ATTACHED) { bcopy(&port->fabric_sparam.portName, (caddr_t)&port_attrs->FabricName, sizeof (port_attrs->FabricName)); } switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; default: port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; } port_attrs->NumberofDiscoveredPorts = emlxs_nport_count(port); } port_attrs->PortSupportedClassofService = LE_SWAP32(FC_NS_CLASS3); (void) strncpy((caddr_t)port_attrs->PortSymbolicName, (caddr_t)port->spn, (sizeof (port_attrs->PortSymbolicName)-1)); /* Set the hba speed limit */ if (vpd->link_speed & LMT_32GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_32GBIT; } if (vpd->link_speed & LMT_16GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_16GBIT; } if (vpd->link_speed & LMT_10GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT; } if (vpd->link_speed & LMT_8GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT; } if (vpd->link_speed & LMT_4GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT; } if (vpd->link_speed & LMT_2GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_2GBIT; } if (vpd->link_speed & LMT_1GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_1GBIT; } value1 = 0x00000120; value2 = 0x00000001; bcopy((caddr_t)&value1, (caddr_t)&port_attrs->PortSupportedFc4Types[0], 4); bcopy((caddr_t)&value2, (caddr_t)&port_attrs->PortSupportedFc4Types[4], 4); bcopy((caddr_t)&value1, (caddr_t)&port_attrs->PortActiveFc4Types[0], 4); bcopy((caddr_t)&value2, (caddr_t)&port_attrs->PortActiveFc4Types[4], 4); port_attrs->PortMaxFrameSize = FF_FRAME_SIZE; } else { fc_hba_port_attributes_t *port_attrs; uint32_t value1; uint32_t value2; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_hba_port_attributes_t)) { rval = EINVAL; goto done; } port_attrs = (fc_hba_port_attributes_t *)fcio->fcio_obuf; port_attrs->version = FC_HBA_PORT_ATTRIBUTES_VERSION; port_attrs->lastChange = 0; port_attrs->fp_minor = 0; bcopy((caddr_t)&port->wwnn, (caddr_t)&port_attrs->NodeWWN, 8); bcopy((caddr_t)&port->wwpn, (caddr_t)&port_attrs->PortWWN, 8); if (port->mode != MODE_TARGET || (port->ulp_statec == FC_STATE_OFFLINE)) { /* port_attrs->PortFcId */ /* port_attrs->PortType */ /* port_attrs->PortSpeed */ /* port_attrs->FabricName */ port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE; } else { port_attrs->PortFcId = port->did; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; if (hba->topology == TOPOLOGY_LOOP) { if (hba->flag & FC_FABRIC_ATTACHED) { port_attrs->PortType = FC_HBA_PORTTYPE_NLPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } } else { if (hba->flag & FC_PT_TO_PT) { port_attrs->PortType = FC_HBA_PORTTYPE_PTP; } else { port_attrs->PortType = FC_HBA_PORTTYPE_NPORT; } } if (hba->flag & FC_FABRIC_ATTACHED) { bcopy(&port->fabric_sparam.portName, (caddr_t)&port_attrs->FabricName, sizeof (port_attrs->FabricName)); } switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; default: port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; } port_attrs->NumberofDiscoveredPorts = emlxs_nport_count(port); } port_attrs->PortSupportedClassofService = LE_SWAP32(FC_NS_CLASS3); (void) strncpy((caddr_t)port_attrs->PortSymbolicName, (caddr_t)port->spn, (sizeof (port_attrs->PortSymbolicName)-1)); /* Set the hba speed limit */ if (vpd->link_speed & LMT_32GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_32GBIT; } if (vpd->link_speed & LMT_16GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_16GBIT; } if (vpd->link_speed & LMT_10GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_10GBIT; } if (vpd->link_speed & LMT_8GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_8GBIT; } if (vpd->link_speed & LMT_4GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_4GBIT; } if (vpd->link_speed & LMT_2GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_2GBIT; } if (vpd->link_speed & LMT_1GB_CAPABLE) { port_attrs->PortSupportedSpeed |= FC_HBA_PORTSPEED_1GBIT; } value1 = 0x00000120; value2 = 0x00000001; bcopy((caddr_t)&value1, (caddr_t)&port_attrs->PortSupportedFc4Types[0], 4); bcopy((caddr_t)&value2, (caddr_t)&port_attrs->PortSupportedFc4Types[4], 4); bcopy((caddr_t)&value1, (caddr_t)&port_attrs->PortActiveFc4Types[0], 4); bcopy((caddr_t)&value2, (caddr_t)&port_attrs->PortActiveFc4Types[4], 4); port_attrs->PortMaxFrameSize = FF_FRAME_SIZE; } done: return (rval); } /* emlxs_fcio_get_adapter_port_attrs() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_node_id(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_rnid_t)) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_READ; pm.pm_cmd_code = FC_PORT_GET_NODE_ID; pm.pm_data_len = fcio->fcio_olen; pm.pm_data_buf = fcio->fcio_obuf; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_get_node_id() */ /*ARGSUSED*/ static int32_t emlxs_fcio_set_node_id(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen < sizeof (fc_rnid_t)) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_READ; pm.pm_cmd_code = FC_PORT_SET_NODE_ID; pm.pm_data_len = fcio->fcio_ilen; pm.pm_data_buf = fcio->fcio_ibuf; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } done: return (rval); } /* emlxs_fcio_set_node_id() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_num_devs(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (uint32_t)) { rval = EINVAL; goto done; } if (port->mode == MODE_TARGET) { *(uint32_t *)fcio->fcio_obuf = emlxs_nport_count(port); } done: return (rval); } /* emlxs_fcio_get_num_devs() */ #ifndef _MULTI_DATAMODEL /* ARGSUSED */ #endif static int32_t emlxs_fcio_get_dev_list(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t use32 = 0; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { fc_port_dev32_t *port_dev; uint32_t max_count; uint32_t i; uint32_t j; emlxs_node_t *nlp; uint32_t nport_count = 0; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_alen < sizeof (uint32_t)) { rval = EINVAL; goto done; } port_dev = (fc_port_dev32_t *)fcio->fcio_obuf; max_count = fcio->fcio_olen / sizeof (fc_port_dev32_t); rw_enter(&port->node_rwlock, RW_READER); if (port->mode == MODE_TARGET) { nport_count = emlxs_nport_count(port); } *(uint32_t *)fcio->fcio_abuf = nport_count; if (nport_count == 0) { rw_exit(&port->node_rwlock); fcio->fcio_errno = FC_NO_MAP; rval = EIO; goto done; } if (nport_count > max_count) { rw_exit(&port->node_rwlock); fcio->fcio_errno = FC_TOOMANY; rval = EIO; goto done; } for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = port->node_table[i]; while (nlp != NULL) { if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) { port_dev->dev_dtype = 0; port_dev->dev_type[0] = BE_SWAP32(0x00000100); port_dev->dev_state = PORT_DEVICE_LOGGED_IN; port_dev->dev_did.port_id = nlp->nlp_DID; port_dev->dev_did.priv_lilp_posit = 0; port_dev->dev_hard_addr.hard_addr = 0; if (hba->topology == TOPOLOGY_LOOP) { for (j = 1; j < port->alpa_map[0]; j++) { if (nlp->nlp_DID == port->alpa_map[j]) { port_dev->dev_did.priv_lilp_posit = j-1; goto done; } } port_dev->dev_hard_addr.hard_addr = nlp->nlp_DID; } bcopy((caddr_t)&nlp->nlp_portname, (caddr_t)&port_dev->dev_pwwn, 8); bcopy((caddr_t)&nlp->nlp_nodename, (caddr_t)&port_dev->dev_nwwn, 8); port_dev++; } nlp = (NODELIST *) nlp->nlp_list_next; } } rw_exit(&port->node_rwlock); } else { fc_port_dev_t *port_dev; uint32_t max_count; uint32_t i; uint32_t j; emlxs_node_t *nlp; uint32_t nport_count = 0; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_alen < sizeof (uint32_t)) { rval = EINVAL; goto done; } port_dev = (fc_port_dev_t *)fcio->fcio_obuf; max_count = fcio->fcio_olen / sizeof (fc_port_dev_t); rw_enter(&port->node_rwlock, RW_READER); if (port->mode == MODE_TARGET) { nport_count = emlxs_nport_count(port); } *(uint32_t *)fcio->fcio_abuf = nport_count; if (nport_count == 0) { rw_exit(&port->node_rwlock); fcio->fcio_errno = FC_NO_MAP; rval = EIO; goto done; } if (nport_count > max_count) { rw_exit(&port->node_rwlock); fcio->fcio_errno = FC_TOOMANY; rval = EIO; goto done; } for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = port->node_table[i]; while (nlp != NULL) { if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) { port_dev->dev_dtype = 0; port_dev->dev_type[0] = BE_SWAP32(0x00000100); port_dev->dev_state = PORT_DEVICE_LOGGED_IN; port_dev->dev_did.port_id = nlp->nlp_DID; port_dev->dev_did.priv_lilp_posit = 0; port_dev->dev_hard_addr.hard_addr = 0; if (hba->topology == TOPOLOGY_LOOP) { for (j = 1; j < port->alpa_map[0]; j++) { if (nlp->nlp_DID == port->alpa_map[j]) { port_dev->dev_did.priv_lilp_posit = j-1; goto done; } } port_dev->dev_hard_addr.hard_addr = nlp->nlp_DID; } bcopy((caddr_t)&nlp->nlp_portname, (caddr_t)&port_dev->dev_pwwn, 8); bcopy((caddr_t)&nlp->nlp_nodename, (caddr_t)&port_dev->dev_nwwn, 8); port_dev++; } nlp = (NODELIST *) nlp->nlp_list_next; } } rw_exit(&port->node_rwlock); } done: return (rval); } /* emlxs_fcio_get_dev_list() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_logi_params(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; uint8_t null_wwn[8]; uint8_t *wwpn; emlxs_node_t *ndlp; if (fcio->fcio_ilen != sizeof (la_wwn_t) || (fcio->fcio_xfer & FCIO_XFER_READ) == 0 || (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) { rval = EINVAL; goto done; } bzero(null_wwn, 8); wwpn = (uint8_t *)fcio->fcio_ibuf; if ((bcmp((caddr_t)wwpn, (caddr_t)null_wwn, 8) == 0) || (bcmp((caddr_t)wwpn, (caddr_t)&port->wwpn, 8) == 0)) { bcopy((caddr_t)&port->sparam, (caddr_t)fcio->fcio_obuf, fcio->fcio_olen); } else { ndlp = emlxs_node_find_wwpn(port, wwpn, 1); if (ndlp) { bcopy((caddr_t)&ndlp->sparm, (caddr_t)fcio->fcio_obuf, fcio->fcio_olen); } else { rval = ENXIO; } } done: return (rval); } /* emlxs_fcio_get_logi_params() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_state(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; uint8_t null_wwn[8]; uint32_t *statep; uint8_t *wwpn; emlxs_node_t *ndlp; if (fcio->fcio_ilen != 8 || fcio->fcio_olen != 4 || (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; goto done; } bzero(null_wwn, 8); wwpn = (uint8_t *)fcio->fcio_ibuf; statep = (uint32_t *)fcio->fcio_obuf; if ((bcmp((caddr_t)wwpn, (caddr_t)null_wwn, 8) == 0) || (bcmp((caddr_t)wwpn, (caddr_t)&port->wwpn, 8) == 0)) { *statep = PORT_DEVICE_VALID; } else { ndlp = emlxs_node_find_wwpn(port, wwpn, 1); if (ndlp) { *statep = PORT_DEVICE_VALID; } else { *statep = PORT_DEVICE_INVALID; } } done: return (rval); } /* emlxs_fcio_get_state() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_topology(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t *tp; emlxs_node_t *ndlp; if (fcio->fcio_olen != 4 || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; goto done; } tp = (uint32_t *)fcio->fcio_obuf; if ((port->mode != MODE_TARGET) || (port->ulp_statec == FC_STATE_OFFLINE)) { *tp = FC_TOP_UNKNOWN; } else { ndlp = emlxs_node_find_did(port, FABRIC_DID, 1); if (hba->topology == TOPOLOGY_LOOP) { if (ndlp) { *tp = FC_TOP_PUBLIC_LOOP; } else { *tp = FC_TOP_PRIVATE_LOOP; } } else { if (ndlp) { *tp = FC_TOP_FABRIC; } else { *tp = FC_TOP_PT_PT; } } } done: return (rval); } /* emlxs_fcio_get_topology() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_link_status(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_portid_t *portid; fc_rls_acc_t *rls; fc_fca_pm_t pm; if (fcio->fcio_ilen != sizeof (fc_portid_t) || fcio->fcio_olen != sizeof (fc_rls_acc_t) || fcio->fcio_xfer != FCIO_XFER_RW) { rval = EINVAL; goto done; } if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) && (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) { rval = EINVAL; goto done; } portid = (fc_portid_t *)fcio->fcio_ibuf; rls = (fc_rls_acc_t *)fcio->fcio_obuf; if (portid->port_id == 0 || portid->port_id == port->did) { bzero((caddr_t)&pm, sizeof (pm)); pm.pm_cmd_flags = FC_FCA_PM_READ; pm.pm_cmd_code = FC_PORT_RLS; pm.pm_data_len = sizeof (fc_rls_acc_t); pm.pm_data_buf = (caddr_t)rls; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } } else { rval = ENOTSUP; } done: return (rval); } /* emlxs_fcio_get_link_status() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_other_adapter_ports(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t index; char *path; if (fcio->fcio_olen < MAXPATHLEN || fcio->fcio_ilen != sizeof (uint32_t)) { rval = EINVAL; goto done; } index = *(uint32_t *)fcio->fcio_ibuf; path = (char *)fcio->fcio_obuf; if (index > hba->vpi_max) { fcio->fcio_errno = FC_BADPORT; rval = EFAULT; goto done; } (void) ddi_pathname(hba->dip, path); done: return (rval); } /* emlxs_fcio_get_other_adapter_ports() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_disc_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; uint32_t index; emlxs_node_t *ndlp; uint32_t use32 = 0; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { fc_hba_port_attributes32_t *port_attrs; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_ilen < sizeof (uint32_t) || fcio->fcio_olen < sizeof (fc_hba_port_attributes32_t)) { rval = EINVAL; goto done; } index = *(uint32_t *)fcio->fcio_ibuf; ndlp = emlxs_node_find_index(port, index, 1); if (!ndlp) { fcio->fcio_errno = FC_OUTOFBOUNDS; rval = EINVAL; goto done; } port_attrs = (fc_hba_port_attributes32_t *)fcio->fcio_obuf; port_attrs->version = FC_HBA_PORT_ATTRIBUTES_VERSION; /* port_attrs->lastChange */ /* port_attrs->fp_minor */ bcopy((caddr_t)&ndlp->nlp_nodename, (caddr_t)&port_attrs->NodeWWN, 8); bcopy((caddr_t)&ndlp->nlp_portname, (caddr_t)&port_attrs->PortWWN, 8); port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; port_attrs->PortType = FC_HBA_PORTTYPE_UNKNOWN; port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE; if ((port->mode == MODE_TARGET) && (hba->state >= FC_LINK_UP)) { port_attrs->PortFcId = ndlp->nlp_DID; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; /* no switch */ if (!(hba->flag & FC_FABRIC_ATTACHED)) { if (hba->topology == TOPOLOGY_LOOP) { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_PTP; } /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } /* public loop */ else if (hba->topology == TOPOLOGY_LOOP) { /* Check for common area and domain */ if ((ndlp->nlp_DID & 0xFFFF00) == (port->did & 0xFFFF00)) { port_attrs->PortType = FC_HBA_PORTTYPE_NLPORT; /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } } } port_attrs->PortSupportedClassofService = LE_SWAP32(FC_NS_CLASS3); /* port_attrs->PortSymbolicName */ /* port_attrs->PortSupportedSpeed */ /* port_attrs->PortSupportedFc4Types */ /* port_attrs->PortActiveFc4Types */ /* port_attrs->PortMaxFrameSize */ /* port_attrs->NumberofDiscoveredPorts */ } else { fc_hba_port_attributes_t *port_attrs; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_ilen < sizeof (uint32_t) || fcio->fcio_olen < sizeof (fc_hba_port_attributes_t)) { rval = EINVAL; goto done; } index = *(uint32_t *)fcio->fcio_ibuf; ndlp = emlxs_node_find_index(port, index, 1); if (!ndlp) { fcio->fcio_errno = FC_OUTOFBOUNDS; rval = EINVAL; goto done; } port_attrs = (fc_hba_port_attributes_t *)fcio->fcio_obuf; port_attrs->version = FC_HBA_PORT_ATTRIBUTES_VERSION; /* port_attrs->lastChange */ /* port_attrs->fp_minor */ bcopy((caddr_t)&ndlp->nlp_nodename, (caddr_t)&port_attrs->NodeWWN, 8); bcopy((caddr_t)&ndlp->nlp_portname, (caddr_t)&port_attrs->PortWWN, 8); port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; port_attrs->PortType = FC_HBA_PORTTYPE_UNKNOWN; port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE; if ((port->mode == MODE_TARGET) && (hba->state >= FC_LINK_UP)) { port_attrs->PortFcId = ndlp->nlp_DID; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; /* no switch */ if (!(hba->flag & FC_FABRIC_ATTACHED)) { if (hba->topology == TOPOLOGY_LOOP) { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_PTP; } /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } /* public loop */ else if (hba->topology == TOPOLOGY_LOOP) { /* Check for common area and domain */ if ((ndlp->nlp_DID & 0xFFFF00) == (port->did & 0xFFFF00)) { port_attrs->PortType = FC_HBA_PORTTYPE_NLPORT; /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } } } port_attrs->PortSupportedClassofService = LE_SWAP32(FC_NS_CLASS3); /* port_attrs->PortSymbolicName */ /* port_attrs->PortSupportedSpeed */ /* port_attrs->PortSupportedFc4Types */ /* port_attrs->PortActiveFc4Types */ /* port_attrs->PortMaxFrameSize */ /* port_attrs->NumberofDiscoveredPorts */ } done: return (rval); } /* emlxs_fcio_get_disc_port_attrs() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { emlxs_hba_t *hba = HBA; int32_t rval = 0; emlxs_node_t *ndlp; uint8_t *wwpn; uint32_t use32 = 0; #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ if (use32) { fc_hba_port_attributes32_t *port_attrs; if ((fcio->fcio_xfer != FCIO_XFER_READ) || (fcio->fcio_ilen < 8) || (fcio->fcio_olen < sizeof (fc_hba_port_attributes32_t))) { rval = EINVAL; goto done; } wwpn = (uint8_t *)fcio->fcio_ibuf; ndlp = emlxs_node_find_wwpn(port, wwpn, 1); if (!ndlp) { fcio->fcio_errno = FC_NOMAP; rval = EINVAL; goto done; } /* Filter fabric ports */ if ((ndlp->nlp_DID & 0xFFF000) == 0xFFF000) { fcio->fcio_errno = FC_NOMAP; rval = EINVAL; goto done; } port_attrs = (fc_hba_port_attributes32_t *)fcio->fcio_obuf; port_attrs->version = FC_HBA_PORT_ATTRIBUTES_VERSION; /* port_attrs->lastChange */ /* port_attrs->fp_minor */ bcopy((caddr_t)&ndlp->nlp_nodename, (caddr_t)&port_attrs->NodeWWN, 8); bcopy((caddr_t)&ndlp->nlp_portname, (caddr_t)&port_attrs->PortWWN, 8); port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; port_attrs->PortType = FC_HBA_PORTTYPE_UNKNOWN; port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE; if ((port->mode == MODE_TARGET) && (hba->state >= FC_LINK_UP)) { port_attrs->PortFcId = ndlp->nlp_DID; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; /* no switch */ if (!(hba->flag & FC_FABRIC_ATTACHED)) { if (hba->topology == TOPOLOGY_LOOP) { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_PTP; } /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } /* public loop */ else if (hba->topology == TOPOLOGY_LOOP) { /* Check for common area and domain */ if ((ndlp->nlp_DID & 0xFFFF00) == (port->did & 0xFFFF00)) { port_attrs->PortType = FC_HBA_PORTTYPE_NLPORT; /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } } } port_attrs->PortSupportedClassofService = LE_SWAP32(FC_NS_CLASS3); /* port_attrs->PortSymbolicName */ /* port_attrs->PortSupportedSpeed */ /* port_attrs->PortSupportedFc4Types */ /* port_attrs->PortActiveFc4Types */ /* port_attrs->PortMaxFrameSize */ /* port_attrs->NumberofDiscoveredPorts */ } else { fc_hba_port_attributes_t *port_attrs; if ((fcio->fcio_xfer != FCIO_XFER_READ) || (fcio->fcio_ilen < 8) || (fcio->fcio_olen < sizeof (fc_hba_port_attributes_t))) { rval = EINVAL; goto done; } wwpn = (uint8_t *)fcio->fcio_ibuf; ndlp = emlxs_node_find_wwpn(port, wwpn, 1); if (!ndlp) { fcio->fcio_errno = FC_NOMAP; rval = EINVAL; goto done; } /* Filter fabric ports */ if ((ndlp->nlp_DID & 0xFFF000) == 0xFFF000) { fcio->fcio_errno = FC_NOMAP; rval = EINVAL; goto done; } port_attrs = (fc_hba_port_attributes_t *)fcio->fcio_obuf; port_attrs->version = FC_HBA_PORT_ATTRIBUTES_VERSION; /* port_attrs->lastChange */ /* port_attrs->fp_minor */ bcopy((caddr_t)&ndlp->nlp_nodename, (caddr_t)&port_attrs->NodeWWN, 8); bcopy((caddr_t)&ndlp->nlp_portname, (caddr_t)&port_attrs->PortWWN, 8); port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; port_attrs->PortType = FC_HBA_PORTTYPE_UNKNOWN; port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE; if ((port->mode == MODE_TARGET) && (hba->state >= FC_LINK_UP)) { port_attrs->PortFcId = ndlp->nlp_DID; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; /* no switch */ if (!(hba->flag & FC_FABRIC_ATTACHED)) { if (hba->topology == TOPOLOGY_LOOP) { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_PTP; } /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } /* public loop */ else if (hba->topology == TOPOLOGY_LOOP) { /* Check for common area and domain */ if ((ndlp->nlp_DID & 0xFFFF00) == (port->did & 0xFFFF00)) { port_attrs->PortType = FC_HBA_PORTTYPE_NLPORT; /* We share a common speed */ switch (hba->linkspeed) { case 0: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_1GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_1GBIT; break; case LA_2GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_2GBIT; break; case LA_4GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_4GBIT; break; case LA_8GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_8GBIT; break; case LA_10GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_10GBIT; break; case LA_16GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_16GBIT; break; case LA_32GHZ_LINK: port_attrs->PortSpeed = HBA_PORTSPEED_32GBIT; break; } } } } port_attrs->PortSupportedClassofService = LE_SWAP32(FC_NS_CLASS3); /* port_attrs->PortSymbolicName */ /* port_attrs->PortSupportedSpeed */ /* port_attrs->PortSupportedFc4Types */ /* port_attrs->PortActiveFc4Types */ /* port_attrs->PortMaxFrameSize */ /* port_attrs->NumberofDiscoveredPorts */ } done: return (rval); } /* emlxs_fcio_get_port_attrs() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_sym_pname(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; if (fcio->fcio_olen < (strlen(port->spn)+1) || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; goto done; } (void) strlcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->spn, fcio->fcio_olen); done: return (rval); } /* emlxs_fcio_get_sym_pname() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_sym_nname(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; if (fcio->fcio_olen < (strlen(port->snn)+1) || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; goto done; } (void) strlcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->snn, fcio->fcio_olen); done: return (rval); } /* emlxs_fcio_get_sym_nname() */ /*ARGSUSED*/ static int32_t emlxs_fcio_force_dump(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; if (port->mode != MODE_TARGET) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg, "fcio_force_dump failed. Port is not in target mode."); fcio->fcio_errno = FC_FAILURE; rval = EIO; goto done; } rval = emlxs_reset(port, FC_FCA_CORE); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; goto done; } done: return (rval); } /* emlxs_fcio_force_dump() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_dump_size(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; if (fcio->fcio_olen != sizeof (uint32_t) || fcio->fcio_xfer != FCIO_XFER_READ) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); pm.pm_data_len = fcio->fcio_olen; pm.pm_data_buf = fcio->fcio_obuf; pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; pm.pm_cmd_flags = FC_FCA_PM_READ; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } } done: return (rval); } /* emlxs_fcio_get_dump_size() */ /*ARGSUSED*/ static int32_t emlxs_fcio_get_dump(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { int32_t rval = 0; fc_fca_pm_t pm; uint32_t dump_size; if (fcio->fcio_xfer != FCIO_XFER_READ) { rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); pm.pm_data_len = sizeof (uint32_t); pm.pm_data_buf = (caddr_t)&dump_size; pm.pm_cmd_code = FC_PORT_GET_DUMP_SIZE; pm.pm_cmd_flags = FC_FCA_PM_READ; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } goto done; } if (fcio->fcio_olen != dump_size) { fcio->fcio_errno = FC_NOMEM; rval = EINVAL; goto done; } bzero((caddr_t)&pm, sizeof (fc_fca_pm_t)); pm.pm_data_len = fcio->fcio_olen; pm.pm_data_buf = fcio->fcio_obuf; pm.pm_cmd_code = FC_PORT_GET_DUMP; pm.pm_cmd_flags = FC_FCA_PM_READ; rval = emlxs_fca_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } } done: return (rval); } /* emlxs_fcio_get_dump() */ /*ARGSUSED*/ static int32_t emlxs_fcio_unsupported(emlxs_port_t *port, fcio_t *fcio, int32_t mode) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: Command not supported.", emlxs_fcio_xlate(fcio->fcio_cmd)); return (ENOTSUP); } /* emlxs_fcio_unsupported() */ #endif /* FCIO_SUPPORT */ /*ARGSUSED*/ static int32_t emlxs_dfc_create_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_config_t *cfg = &CFG; emlxs_port_t *vport; emlxs_port_t *tport; dfc_vportinfo_t *dfc_vport; uint32_t vpi; uint32_t options; char name[256]; uint8_t wwn[8]; options = dfc->data1; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_vportinfo_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } dfc_vport = (dfc_vportinfo_t *)dfc->buf1; if (!(options & VPORT_OPT_AUTORETRY)) { if (!(hba->flag & FC_NPIV_ENABLED)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: NPIV currently not enabled.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NPIV_DISABLED); } if (!(hba->flag & FC_NPIV_SUPPORTED)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: NPIV currently not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NPIV_UNSUPPORTED); } } /* * Only the same WWNN and WWPN can be re-created */ bzero(wwn, 8); if (bcmp(wwn, dfc_vport->wwpn, 8) || bcmp(wwn, dfc_vport->wwnn, 8)) { for (vpi = 1; vpi <= hba->vpi_max; vpi++) { vport = &VPORT(vpi); if ((bcmp((caddr_t)&vport->wwnn, (caddr_t)dfc_vport->wwnn, 8) == 0) && (bcmp((caddr_t)&vport->wwpn, (caddr_t)dfc_vport->wwpn, 8) == 0)) { if (!(vport->flag & EMLXS_PORT_CONFIG) && (vport->flag & EMLXS_PORT_BOUND)) { dfc_vport->vpi = vpi; break; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: VPI already in use.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_INVALID); } } } } /* else auto assign */ /* Acquire a VPI */ if (dfc_vport->vpi == 0) { /* Auto Assign VPI */ for (vpi = 1; vpi <= hba->vpi_max; vpi++) { vport = &VPORT(vpi); if (!(vport->flag & EMLXS_PORT_CONFIG)) { break; } } if (vpi > hba->vpi_max) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Out of resources.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_DRVRES_ERROR); } dfc_vport->vpi = vpi; } /* Establish a WWPN */ bzero(wwn, 8); if (!(bcmp(wwn, dfc_vport->wwpn, 8))) { /* Generate new WWPN */ bcopy((caddr_t)&hba->wwpn, (caddr_t)dfc_vport->wwpn, 8); dfc_vport->wwpn[0] = 0x20; dfc_vport->wwpn[1] = (uint8_t)vpi; } else { /* use one provided */ /* Make sure WWPN is unique */ if (tport = emlxs_vport_find_wwpn(hba, dfc_vport->wwpn)) { if ((tport->flag & EMLXS_PORT_CONFIG) && (tport->flag & EMLXS_PORT_BOUND)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN already exists. vpi=%d", emlxs_dfc_xlate(dfc->cmd), vpi); return (DFC_ARG_INVALID); } } } /* Establish a WWNN */ bzero(wwn, 8); if (!(bcmp(wwn, dfc_vport->wwnn, 8))) { /* Generate new WWNN */ bcopy((caddr_t)&hba->wwnn, (caddr_t)dfc_vport->wwnn, 8); dfc_vport->wwnn[0] = 0x28; dfc_vport->wwnn[1] = (uint8_t)vpi; } /* else use WWNN provided */ /* Generate the symbolic node name */ if (dfc_vport->snn[0]) { (void) strncpy(name, dfc_vport->snn, (sizeof (name)-1)); (void) snprintf(dfc_vport->snn, (sizeof (dfc_vport->snn)-1), "%s %s", hba->snn, name); } else { (void) strncpy(dfc_vport->snn, hba->snn, (sizeof (dfc_vport->snn)-1)); } /* Generate the symbolic port name */ if (dfc_vport->spn[0]) { (void) strncpy(name, dfc_vport->spn, (sizeof (name)-1)); (void) snprintf(dfc_vport->spn, (sizeof (dfc_vport->spn)-1), "%s VPort-%d VName-%s", hba->spn, vpi, name); } else { (void) snprintf(dfc_vport->spn, (sizeof (dfc_vport->spn)-1), "%s VPort-%d", hba->spn, vpi); } dfc_vport->port_id = 0; dfc_vport->ulp_statec = FC_STATE_OFFLINE; dfc_vport->flags = VPORT_CONFIG; /* Set the highest configured vpi */ if (dfc_vport->vpi >= hba->vpi_high) { hba->vpi_high = dfc_vport->vpi; } /* Configure the port object */ bcopy((caddr_t)dfc_vport->wwnn, (caddr_t)&vport->wwnn, 8); bcopy((caddr_t)dfc_vport->wwpn, (caddr_t)&vport->wwpn, 8); (void) strncpy((caddr_t)vport->snn, (caddr_t)dfc_vport->snn, (sizeof (vport->snn)-1)); (void) strncpy((caddr_t)vport->spn, (caddr_t)dfc_vport->spn, (sizeof (vport->spn)-1)); vport->flag |= (EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLED); /* Adjust restricted flags */ vport->options &= ~EMLXS_OPT_RESTRICT_MASK; vport->flag &= ~EMLXS_PORT_RESTRICTED; if (options & VPORT_OPT_RESTRICT) { vport->options |= EMLXS_OPT_RESTRICT; vport->flag |= EMLXS_PORT_RESTRICTED; dfc_vport->flags |= VPORT_RESTRICTED; } else if (options & VPORT_OPT_UNRESTRICT) { vport->options |= EMLXS_OPT_UNRESTRICT; } else if (cfg[CFG_VPORT_RESTRICTED].current) { vport->flag |= EMLXS_PORT_RESTRICTED; dfc_vport->flags |= VPORT_RESTRICTED; } if (vport->flag & EMLXS_PORT_BOUND) { /* * The same WWNN, WWPN and VPI has been re-created. * Bring up the vport now! */ emlxs_port_online(vport); } return (0); } /* emlxs_dfc_create_vport() */ /*ARGSUSED*/ static int32_t emlxs_dfc_destroy_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_port_t *vport; uint8_t wwpn[8]; fc_packet_t *pkt = NULL; uint32_t rval = 0; ELS_PKT *els; char buffer[256]; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (dfc->buf1_size < 8) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); rval = DFC_ARG_TOOSMALL; goto done; } /* Read the wwn object */ bcopy((void *)dfc->buf1, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); /* Physical does not have EMLXS_PORT_CONFIG set */ if (!vport || !(vport->flag & EMLXS_PORT_CONFIG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, sizeof (buffer), wwpn)); rval = DFC_ARG_INVALID; goto done; } if (vport->did) { /* Fabric Logout */ if (!(pkt = emlxs_pkt_alloc(vport, sizeof (uint32_t) + sizeof (LOGO), sizeof (FCP_RSP), 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = 60; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(vport->did); pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; /* Build the command */ els = (ELS_PKT *) pkt->pkt_cmd; els->elsCode = 0x05; /* LOGO */ els->un.logo.un.nPortId32 = LE_SWAP32(vport->did); bcopy(&vport->wwpn, &els->un.logo.portName, 8); /* * Just send LOGO. Don't worry about result. * This is just a courtesy anyway. */ (void) emlxs_pkt_send(pkt, 1); /* Take the port offline */ (void) emlxs_port_offline(vport, 0xffffffff); } vport->flag &= ~(EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLED); rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_destroy_vport() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_vportinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_port_t *vport; dfc_vportinfo_t *dfc_vport; dfc_vportinfo_t *dfc_vport_list = NULL; uint32_t i; uint32_t size; uint32_t max_count; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } size = (sizeof (dfc_vportinfo_t) * MAX_VPORTS); if (!(dfc_vport_list = (dfc_vportinfo_t *)kmem_zalloc(size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate memory.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } max_count = 0; for (i = 0; i <= hba->vpi_max; i++) { vport = &VPORT(i); dfc_vport = &dfc_vport_list[i]; if (!(vport->flag & EMLXS_PORT_CONFIG)) { continue; } bcopy(vport->snn, dfc_vport->snn, 256); bcopy(vport->spn, dfc_vport->spn, 256); bcopy(&vport->wwpn, dfc_vport->wwpn, 8); bcopy(&vport->wwnn, dfc_vport->wwnn, 8); dfc_vport->port_id = vport->did; dfc_vport->vpi = vport->vpi; dfc_vport->ulp_statec = vport->ulp_statec; dfc_vport->flags = VPORT_CONFIG; if (vport->flag & EMLXS_PORT_ENABLED) { dfc_vport->flags |= VPORT_ENABLED; } if (vport->flag & EMLXS_PORT_BOUND) { dfc_vport->flags |= VPORT_BOUND; } if (vport->flag & EMLXS_PORT_IP_UP) { dfc_vport->flags |= VPORT_IP; } if (vport->flag & EMLXS_PORT_RESTRICTED) { dfc_vport->flags |= VPORT_RESTRICTED; } max_count++; } max_count *= sizeof (dfc_vportinfo_t); if (max_count > dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d > %d)", emlxs_dfc_xlate(dfc->cmd), max_count, dfc->buf1_size); rval = DFC_ARG_TOOSMALL; goto done; } bcopy((void *)dfc_vport_list, (void *)dfc->buf1, dfc->buf1_size); done: if (dfc_vport_list) { kmem_free(dfc_vport_list, size); } return (rval); } /* emlxs_dfc_get_vportinfo() */ static emlxs_port_t * emlxs_vport_find_wwpn(emlxs_hba_t *hba, uint8_t *wwpn) { emlxs_port_t *port; NODELIST *nlp; int i, j; for (i = 0; i <= hba->vpi_max; i++) { port = &VPORT(i); /* Check Local N-port, including physical port */ if (bcmp(&port->wwpn, wwpn, 8) == 0) { return (port); } /* Check Remote N-port */ rw_enter(&port->node_rwlock, RW_READER); for (j = 0; j < EMLXS_NUM_HASH_QUES; j++) { nlp = port->node_table[j]; while (nlp != NULL) { /* Check Local N-port */ if (bcmp(&nlp->nlp_portname, wwpn, 8) == 0) { rw_exit(&port->node_rwlock); return (port); } nlp = nlp->nlp_list_next; } } rw_exit(&port->node_rwlock); } return (0); } /* emlxs_vport_find_wwpn() */ /*ARGSUSED*/ static int32_t emlxs_dfc_npiv_resource(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_vport_resource_t *vres; MAILBOXQ *mbq = NULL; MAILBOX *mb; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_vport_resource_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } vres = (dfc_vport_resource_t *)dfc->buf1; bzero(vres, sizeof (dfc_vport_resource_t)); if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { int i; int total_rpi; emlxs_port_t *vport; vres->vpi_max = min(hba->sli.sli4.VPICount, MAX_VPORTS) - 1; total_rpi = 0; for (i = 0; i < vres->vpi_max; i++) { vport = &VPORT(i); total_rpi += vport->vpip->rpi_online; } vres->vpi_inuse = (port->vpip->vfip == NULL) ? 0 : (port->vpip->vfip->vpi_online - 1); vres->rpi_max = hba->sli.sli4.RPICount; vres->rpi_inuse = total_rpi; return (rval); } mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *) mbq; emlxs_mb_read_config(hba, mbq); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval == MBX_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Mailbox timed out. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_TIMEOUT; goto done; } if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_IO_ERROR; goto done; } vres->vpi_max = mb->un.varRdConfig.max_vpi; vres->vpi_inuse = (mb->un.varRdConfig.max_vpi <= mb->un.varRdConfig.avail_vpi) ? 0 : mb->un.varRdConfig.max_vpi - mb->un.varRdConfig.avail_vpi; vres->rpi_max = mb->un.varRdConfig.max_rpi; vres->rpi_inuse = (mb->un.varRdConfig.max_rpi <= mb->un.varRdConfig.avail_rpi) ? 0 : mb->un.varRdConfig.max_rpi - mb->un.varRdConfig.avail_rpi; done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_npiv_resource() */ /*ARGSUSED*/ static int32_t emlxs_dfc_npiv_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_port_t *vport = &VPORT(hba->vpi_max); emlxs_config_t *cfg = &CFG; fc_packet_t *pkt = NULL; fc_packet_t *pkt1 = NULL; ELS_PKT *els; LS_RJT *lsrjt; uint32_t checklist = 0; uint32_t mask = 0; uint32_t rval = DFC_SUCCESS; uint8_t wwn[8]; emlxs_vpd_t *vpd = &VPD; int i; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } if (cfg[CFG_NPIV_ENABLE].current) { checklist |= CL_NPIV_PARM_ENABLE; } if (hba->sli_mode >= 3) { checklist |= CL_SLI3_ENABLE; } if ((vpd->feaLevelHigh >= 0x09) || (hba->sli_mode >= 4)) { checklist |= CL_HBA_SUPPORT_NPIV; } if (hba->num_of_ports <= hba->vpi_max) { checklist |= CL_HBA_HAS_RESOURCES; } if (hba->state < FC_LINK_UP) { goto done; } checklist |= CL_HBA_LINKUP; if (hba->topology == TOPOLOGY_LOOP) { goto done; } if (!(hba->flag & FC_FABRIC_ATTACHED)) { goto done; } checklist |= CL_P2P_TOPOLOGY; if (!(hba->flag & FC_NPIV_SUPPORTED)) { goto done; } checklist |= CL_FABRIC_SUPPORTS_NPIV; mask = (CL_NPIV_PARM_ENABLE | CL_SLI3_ENABLE | CL_HBA_SUPPORT_NPIV | CL_HBA_HAS_RESOURCES); /* * Check if those four conditions are met */ if ((checklist & mask) != mask) { /* * One or more conditions are not met */ goto done; } /* Now check if fabric have resources */ for (i = 1; i <= hba->vpi_max; i++) { vport = &VPORT(i); if (vport->did) { checklist |= CL_FABRIC_HAS_RESOURCES; goto done; } } if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { (void) emlxs_vpi_port_bind_notify(vport); /* wait one second for INIT_VPI completion */ drv_usecwait(1000000); } vport->vpi = hba->vpi_max; vport->hba = hba; if (!(pkt = emlxs_pkt_alloc(vport, sizeof (uint32_t) + sizeof (SERV_PARM), sizeof (FCP_RSP), 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Unable to allocate packet."); goto done; } /* Build (FDISC) the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_UNSOL_CONTROL; pkt->pkt_cmd_fhdr.s_id = 0; pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xffff; pkt->pkt_cmd_fhdr.rx_id = 0xffff; pkt->pkt_cmd_fhdr.ro = 0; /* Build the command (FDISC) */ els = (ELS_PKT *) pkt->pkt_cmd; els->elsCode = 0x04; /* FLOGI - This will be changed automatically */ /* by the drive (See emlxs_send_els()) */ /* Copy latest service parameters to payload */ bcopy((void *)&port->sparam, (void *)&els->un.logi, sizeof (SERV_PARM)); bcopy((caddr_t)&hba->wwnn, (caddr_t)wwn, 8); wwn[0] = 0x28; wwn[1] = hba->vpi_max; bcopy((caddr_t)wwn, (caddr_t)&els->un.logi.nodeName, 8); bcopy((caddr_t)wwn, (caddr_t)&vport->wwnn, 8); bcopy((caddr_t)&hba->wwpn, (caddr_t)wwn, 8); wwn[0] = 0x20; wwn[1] = hba->vpi_max; bcopy((caddr_t)wwn, (caddr_t)&els->un.logi.portName, 8); bcopy((caddr_t)wwn, (caddr_t)&vport->wwpn, 8); bcopy((void *)&els->un.logi, (void *)&vport->sparam, sizeof (SERV_PARM)); /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = 60; if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd)); goto done; } if (pkt->pkt_state == FC_PKT_SUCCESS) { if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { (void) emlxs_vpi_port_unbind_notify(vport, 1); checklist |= CL_FABRIC_HAS_RESOURCES; } else { if (!(pkt1 = emlxs_pkt_alloc(vport, sizeof (uint32_t) + sizeof (LOGO), sizeof (FCP_RSP), 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Unable to allocate LOGO packet."); goto free_resc; } /* Make this a polled IO */ pkt1->pkt_tran_flags &= ~FC_TRAN_INTR; pkt1->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt1->pkt_comp = NULL; pkt1->pkt_tran_type = FC_PKT_EXCHANGE; pkt1->pkt_timeout = 60; /* Build (LOGO) the fc header */ pkt1->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID); pkt1->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; pkt1->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(pkt->pkt_resp_fhdr.d_id); pkt1->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; pkt1->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt1->pkt_cmd_fhdr.seq_id = 0; pkt1->pkt_cmd_fhdr.df_ctl = 0; pkt1->pkt_cmd_fhdr.seq_cnt = 0; pkt1->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt1->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt1->pkt_cmd_fhdr.ro = 0; /* Build the command (LOGO) */ els = (ELS_PKT *) pkt1->pkt_cmd; els->elsCode = 0x05; /* LOGO */ els->un.logo.un.nPortId32 = LE_SWAP32(pkt->pkt_resp_fhdr.d_id); bcopy((caddr_t)&hba->wwpn, (caddr_t)wwn, 8); wwn[0] = 0x20; wwn[1] = hba->vpi_max; bcopy(wwn, &els->un.logo.portName, 8); if (emlxs_pkt_send(pkt1, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd)); goto free_resc; } if (pkt1->pkt_state != FC_PKT_SUCCESS) { if (pkt1->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. " "Pkt Timeout.", emlxs_dfc_xlate(dfc->cmd)); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. state=%x", emlxs_dfc_xlate(dfc->cmd), pkt1->pkt_state); } goto free_resc; } checklist |= CL_FABRIC_HAS_RESOURCES; free_resc: /* Free default RPIs and VPI */ /* Unregister all nodes */ (void) EMLXS_SLI_UNREG_NODE(vport, 0, 0, 0, 0); (void) emlxs_mb_unreg_vpi(vport); } } else if (pkt->pkt_state == FC_PKT_LS_RJT) { lsrjt = (LS_RJT *) pkt->pkt_resp; if (lsrjt->un.b.lsRjtRsnCodeExp != LSEXP_OUT_OF_RESOURCE) { checklist |= CL_FABRIC_HAS_RESOURCES; } } done: bcopy((void *)&checklist, (void *)dfc->buf1, sizeof (uint32_t)); if (pkt) { /* Free the pkt */ emlxs_pkt_free(pkt); } if (pkt1) { /* Free the pkt */ emlxs_pkt_free(pkt1); } return (rval); } /* emlxs_dfc_npiv_test() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_rev(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t rev; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } rev = DFC_REV; bcopy((void *)&rev, (void *)dfc->buf1, sizeof (uint32_t)); return (0); } /* emlxs_dfc_get_rev() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_hbainfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_vpd_t *vpd = &VPD; emlxs_config_t *cfg = &CFG; dfc_hbainfo_t *hbainfo; char pathname[256]; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_hbainfo_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } hbainfo = (dfc_hbainfo_t *)dfc->buf1; bzero((void *) hbainfo, sizeof (dfc_hbainfo_t)); (void) strncpy(hbainfo->vpd_serial_num, vpd->serial_num, (sizeof (hbainfo->vpd_serial_num)-1)); (void) strncpy(hbainfo->vpd_part_num, vpd->part_num, (sizeof (hbainfo->vpd_part_num)-1)); (void) strncpy(hbainfo->vpd_port_num, vpd->port_num, (sizeof (hbainfo->vpd_port_num)-1)); (void) strncpy(hbainfo->vpd_eng_change, vpd->eng_change, (sizeof (hbainfo->vpd_eng_change)-1)); (void) strncpy(hbainfo->vpd_manufacturer, vpd->manufacturer, (sizeof (hbainfo->vpd_manufacturer)-1)); (void) strncpy(hbainfo->vpd_model, vpd->model, (sizeof (hbainfo->vpd_model)-1)); (void) strncpy(hbainfo->vpd_model_desc, vpd->model_desc, (sizeof (hbainfo->vpd_model_desc)-1)); (void) strncpy(hbainfo->vpd_prog_types, vpd->prog_types, (sizeof (hbainfo->vpd_prog_types)-1)); (void) strncpy(hbainfo->vpd_id, vpd->id, (sizeof (hbainfo->vpd_id)-1)); hbainfo->device_id = hba->model_info.device_id; hbainfo->vendor_id = hba->model_info.vendor_id; hbainfo->ports = hba->num_of_ports; hbainfo->port_index = vpd->port_index; bcopy(&hba->wwnn, hbainfo->wwnn, sizeof (hbainfo->wwnn)); (void) strncpy(hbainfo->snn, port->snn, (sizeof (hbainfo->snn)-1)); bcopy(&hba->wwpn, hbainfo->wwpn, sizeof (hbainfo->wwpn)); (void) strncpy(hbainfo->spn, port->spn, (sizeof (hbainfo->spn)-1)); hbainfo->biuRev = vpd->biuRev; hbainfo->smRev = vpd->smRev; hbainfo->smFwRev = vpd->smFwRev; hbainfo->endecRev = vpd->endecRev; hbainfo->rBit = vpd->rBit; hbainfo->fcphHigh = vpd->fcphHigh; hbainfo->fcphLow = vpd->fcphLow; hbainfo->feaLevelHigh = vpd->feaLevelHigh; hbainfo->feaLevelLow = vpd->feaLevelLow; hbainfo->kern_rev = vpd->postKernRev; (void) strncpy(hbainfo->kern_name, vpd->postKernName, (sizeof (hbainfo->kern_name)-1)); hbainfo->stub_rev = vpd->opFwRev; (void) strncpy(hbainfo->stub_name, vpd->opFwName, (sizeof (hbainfo->stub_name)-1)); hbainfo->sli1_rev = vpd->sli1FwRev; (void) strncpy(hbainfo->sli1_name, vpd->sli1FwName, (sizeof (hbainfo->sli1_name)-1)); hbainfo->sli2_rev = vpd->sli2FwRev; (void) strncpy(hbainfo->sli2_name, vpd->sli2FwName, (sizeof (hbainfo->sli2_name)-1)); hbainfo->sli3_rev = vpd->sli3FwRev; (void) strncpy(hbainfo->sli3_name, vpd->sli3FwName, (sizeof (hbainfo->sli3_name)-1)); hbainfo->sli4_rev = vpd->sli4FwRev; (void) strncpy(hbainfo->sli4_name, vpd->sli4FwName, (sizeof (hbainfo->sli4_name)-1)); hbainfo->sli_mode = hba->sli_mode; hbainfo->vpi_max = hba->vpi_max; hbainfo->vpi_high = hba->vpi_high; hbainfo->flags = 0; /* Set support flags */ hbainfo->flags = HBA_FLAG_DYN_WWN; hbainfo->flags |= HBA_FLAG_NPIV; #ifdef DHCHAP_SUPPORT hbainfo->flags |= HBA_FLAG_DHCHAP; if (cfg[CFG_AUTH_E2E].current) { hbainfo->flags |= HBA_FLAG_E2E_AUTH; } #endif /* DHCHAP_SUPPORT */ #ifdef SAN_DIAG_SUPPORT hbainfo->flags |= HBA_FLAG_SAN_DIAG; #endif /* SAN_DIAG_SUPPORT */ #ifdef SFCT_SUPPORT hbainfo->flags |= HBA_FLAG_TARGET_MODE; if (port->mode == MODE_TARGET) { hbainfo->flags |= HBA_FLAG_TARGET_MODE_ENA; } #endif /* SFCT_SUPPORT */ hbainfo->flags |= HBA_FLAG_PERSISTLINK; if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { hbainfo->flags |= HBA_FLAG_EXT_MBOX; if (SLI4_FCOE_MODE) { hbainfo->flags |= HBA_FLAG_FCOE; hbainfo->flags &= ~HBA_FLAG_PERSISTLINK; } } (void) strncpy(hbainfo->fcode_version, vpd->fcode_version, (sizeof (hbainfo->fcode_version)-1)); (void) strncpy(hbainfo->boot_version, vpd->boot_version, (sizeof (hbainfo->boot_version)-1)); (void) strncpy(hbainfo->fw_version, vpd->fw_version, (sizeof (hbainfo->fw_version)-1)); (void) strncpy(hbainfo->drv_label, emlxs_label, (sizeof (hbainfo->drv_label)-1)); (void) strncpy(hbainfo->drv_module, emlxs_name, (sizeof (hbainfo->drv_module)-1)); (void) strncpy(hbainfo->drv_name, DRIVER_NAME, (sizeof (hbainfo->drv_name)-1)); (void) strncpy(hbainfo->drv_version, emlxs_version, (sizeof (hbainfo->drv_version)-1)); (void) strncpy(hbainfo->drv_revision, emlxs_revision, (sizeof (hbainfo->drv_revision)-1)); (void) strncpy(hbainfo->hostname, (char *)utsname.nodename, (sizeof (hbainfo->hostname)-1)); (void) ddi_pathname(hba->dip, pathname); (void) snprintf(hbainfo->os_devname, (sizeof (hbainfo->os_devname)-1), "/devices%s", pathname); if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) { hbainfo->flags |= HBA_FLAG_OFFLINE; } hbainfo->drv_instance = hba->ddiinst; hbainfo->port_id = port->did; hbainfo->port_type = HBA_PORTTYPE_UNKNOWN; #ifdef MENLO_SUPPORT if (hba->flag & FC_MENLO_MODE) { hbainfo->topology = LNK_MENLO_MAINTENANCE; } else #endif /* MENLO_SUPPORT */ if (hba->state >= FC_LINK_UP) { if (hba->topology == TOPOLOGY_LOOP) { if (hba->flag & FC_FABRIC_ATTACHED) { hbainfo->port_type = HBA_PORTTYPE_NLPORT; hbainfo->topology = LNK_PUBLIC_LOOP; } else { hbainfo->port_type = HBA_PORTTYPE_LPORT; hbainfo->topology = LNK_LOOP; } hbainfo->alpa_count = port->alpa_map[0]; bcopy((void *)&port->alpa_map[1], hbainfo->alpa_map, hbainfo->alpa_count); } else { if (hba->flag & FC_PT_TO_PT) { hbainfo->port_type = HBA_PORTTYPE_PTP; hbainfo->topology = LNK_PT2PT; } else { hbainfo->port_type = HBA_PORTTYPE_NPORT; hbainfo->topology = LNK_FABRIC; } } if (hba->flag & FC_FABRIC_ATTACHED) { bcopy(&port->fabric_sparam.nodeName, hbainfo->fabric_wwnn, sizeof (hbainfo->fabric_wwnn)); bcopy(&port->fabric_sparam.portName, hbainfo->fabric_wwpn, sizeof (hbainfo->fabric_wwpn)); } if (hba->linkspeed == LA_2GHZ_LINK) { hbainfo->port_speed = HBA_PORTSPEED_2GBIT; } else if (hba->linkspeed == LA_4GHZ_LINK) { hbainfo->port_speed = HBA_PORTSPEED_4GBIT; } else if (hba->linkspeed == LA_8GHZ_LINK) { hbainfo->port_speed = HBA_PORTSPEED_8GBIT; } else if (hba->linkspeed == LA_10GHZ_LINK) { hbainfo->port_speed = HBA_PORTSPEED_10GBIT; } else if (hba->linkspeed == LA_16GHZ_LINK) { hbainfo->port_speed = HBA_PORTSPEED_16GBIT; } else if (hba->linkspeed == LA_32GHZ_LINK) { hbainfo->port_speed = HBA_PORTSPEED_32GBIT; } else { hbainfo->port_speed = HBA_PORTSPEED_1GBIT; } hbainfo->node_count = port->node_count; } hbainfo->hard_alpa = cfg[CFG_ASSIGN_ALPA].current; hbainfo->supported_cos = LE_SWAP32((FC_NS_CLASS3 | FC_NS_CLASS2)); hbainfo->supported_types[0] = LE_SWAP32(0x00000120); hbainfo->supported_types[1] = LE_SWAP32(0x00000001); hbainfo->active_types[0] = LE_SWAP32(0x00000120); hbainfo->active_types[1] = LE_SWAP32(0x00000001); if (!cfg[CFG_NETWORK_ON].current) { hbainfo->active_types[0] &= ~(LE_SWAP32(0x00000020)); } if (vpd->link_speed & LMT_32GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_32GBIT; } if (vpd->link_speed & LMT_16GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_16GBIT; } if (vpd->link_speed & LMT_10GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_10GBIT; } if (vpd->link_speed & LMT_8GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_8GBIT; } if (vpd->link_speed & LMT_4GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_4GBIT; } if (vpd->link_speed & LMT_2GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_2GBIT; } if (vpd->link_speed & LMT_1GB_CAPABLE) { hbainfo->supported_speeds |= FC_HBA_PORTSPEED_1GBIT; } hbainfo->max_frame_size = FF_FRAME_SIZE; if (hba->bus_type == SBUS_FC) { hbainfo->flags |= HBA_FLAG_SBUS; } if (hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE)) { hbainfo->flags |= HBA_FLAG_OFFLINE; hbainfo->port_state = HBA_PORTSTATE_UNKNOWN; } else if (hba->flag & FC_ONLINE_MODE) { if (hba->flag & FC_LOOPBACK_MODE) { hbainfo->port_state = HBA_PORTSTATE_LOOPBACK; } else if (hba->state <= FC_LINK_DOWN) { hbainfo->port_state = HBA_PORTSTATE_LINKDOWN; } #ifdef MENLO_SUPPORT else if (hba->flag & FC_MENLO_MODE) { hbainfo->port_state = HBA_PORTSTATE_LINKDOWN; } #endif /* MENLO_SUPPORT */ else { hbainfo->port_state = HBA_PORTSTATE_ONLINE; } } else { hbainfo->flags |= HBA_FLAG_OFFLINE; if (hba->state == FC_ERROR) { hbainfo->port_state = HBA_PORTSTATE_ERROR; } else { hbainfo->port_state = HBA_PORTSTATE_OFFLINE; } } hbainfo->pci_function_number = hba->pci_function_number; hbainfo->pci_device_number = hba->pci_device_number; hbainfo->pci_bus_number = hba->pci_bus_number; #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_get_hbainfo() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_hbastats_t *stats; MAILBOX *mb = NULL; MAILBOXQ *mbq = NULL; uint32_t rval = 0; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_hbastats_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *)mbq; emlxs_mb_read_status(hba, mbq); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval == MBX_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Mailbox timed out. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_TIMEOUT; goto done; } if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_IO_ERROR; goto done; } stats = (dfc_hbastats_t *)dfc->buf1; bzero((void *)stats, sizeof (dfc_hbastats_t)); stats->tx_frame_cnt = mb->un.varRdStatus.xmitFrameCnt; stats->rx_frame_cnt = mb->un.varRdStatus.rcvFrameCnt; stats->tx_kbyte_cnt = mb->un.varRdStatus.xmitByteCnt; stats->rx_kbyte_cnt = mb->un.varRdStatus.rcvByteCnt; stats->tx_seq_cnt = mb->un.varRdStatus.xmitSeqCnt; stats->rx_seq_cnt = mb->un.varRdStatus.rcvSeqCnt; stats->orig_exch_cnt = mb->un.varRdStatus.totalOrigExchanges; stats->resp_exch_cnt = mb->un.varRdStatus.totalRespExchanges; stats->pbsy_cnt = mb->un.varRdStatus.rcvPbsyCnt; stats->fbsy_cnt = mb->un.varRdStatus.rcvFbsyCnt; emlxs_mb_read_lnk_stat(hba, mbq); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval == MBX_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Mailbox timed out. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_TIMEOUT; goto done; } if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_IO_ERROR; goto done; } stats->link_failure_cnt = mb->un.varRdLnk.linkFailureCnt; stats->loss_sync_cnt = mb->un.varRdLnk.lossSyncCnt; stats->loss_signal_cnt = mb->un.varRdLnk.lossSignalCnt; stats->seq_error_cnt = mb->un.varRdLnk.primSeqErrCnt; stats->inval_tx_word_cnt = mb->un.varRdLnk.invalidXmitWord; stats->crc_error_cnt = mb->un.varRdLnk.crcCnt; stats->seq_timeout_cnt = mb->un.varRdLnk.primSeqTimeout; stats->elastic_overrun_cnt = mb->un.varRdLnk.elasticOverrun; stats->arb_timeout_cnt = mb->un.varRdLnk.arbTimeout; stats->rx_buf_credit = mb->un.varRdLnk.rxBufCredit; stats->rx_buf_cnt = mb->un.varRdLnk.rxBufCreditCur; stats->tx_buf_credit = mb->un.varRdLnk.txBufCredit; stats->tx_buf_cnt = mb->un.varRdLnk.txBufCreditCur; stats->EOFa_cnt = mb->un.varRdLnk.EOFaCnt; stats->EOFdti_cnt = mb->un.varRdLnk.EOFdtiCnt; stats->EOFni_cnt = mb->un.varRdLnk.EOFniCnt; stats->SOFf_cnt = mb->un.varRdLnk.SOFfCnt; stats->link_event_tag = hba->link_event_tag; stats->last_reset_time = hba->timer_tics - hba->stats.ResetTime; stats->port_type = HBA_PORTTYPE_UNKNOWN; #ifdef MENLO_SUPPORT if (hba->flag & FC_MENLO_MODE) { stats->topology = LNK_MENLO_MAINTENANCE; } else #endif /* MENLO_SUPPORT */ if (hba->state >= FC_LINK_UP) { if (hba->topology == TOPOLOGY_LOOP) { if (hba->flag & FC_FABRIC_ATTACHED) { stats->port_type = HBA_PORTTYPE_NLPORT; stats->topology = LNK_PUBLIC_LOOP; } else { stats->port_type = HBA_PORTTYPE_LPORT; stats->topology = LNK_LOOP; } } else { if (hba->flag & FC_PT_TO_PT) { stats->port_type = HBA_PORTTYPE_PTP; stats->topology = LNK_PT2PT; } else { stats->port_type = HBA_PORTTYPE_NPORT; stats->topology = LNK_FABRIC; } } if (hba->linkspeed == LA_2GHZ_LINK) { stats->link_speed = HBA_PORTSPEED_2GBIT; } else if (hba->linkspeed == LA_4GHZ_LINK) { stats->link_speed = HBA_PORTSPEED_4GBIT; } else if (hba->linkspeed == LA_8GHZ_LINK) { stats->link_speed = HBA_PORTSPEED_8GBIT; } else if (hba->linkspeed == LA_10GHZ_LINK) { stats->link_speed = HBA_PORTSPEED_10GBIT; } else if (hba->linkspeed == LA_16GHZ_LINK) { stats->link_speed = HBA_PORTSPEED_16GBIT; } else if (hba->linkspeed == LA_32GHZ_LINK) { stats->link_speed = HBA_PORTSPEED_32GBIT; } else { stats->link_speed = HBA_PORTSPEED_1GBIT; } } done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_get_hbastats() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_drvstats_t *stats; uint32_t rval = 0; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } stats = (dfc_drvstats_t *)dfc->buf1; bzero((void *)stats, sizeof (dfc_drvstats_t)); stats->LinkUp = hba->stats.LinkUp; stats->LinkDown = hba->stats.LinkDown; stats->LinkEvent = hba->stats.LinkEvent; stats->LinkMultiEvent = hba->stats.LinkMultiEvent; stats->MboxIssued = hba->stats.MboxIssued; stats->MboxCompleted = hba->stats.MboxCompleted; stats->MboxGood = hba->stats.MboxGood; stats->MboxError = hba->stats.MboxError; stats->MboxBusy = hba->stats.MboxBusy; stats->MboxInvalid = hba->stats.MboxInvalid; stats->IocbIssued[0] = hba->stats.IocbIssued[0]; stats->IocbIssued[1] = hba->stats.IocbIssued[1]; stats->IocbIssued[2] = hba->stats.IocbIssued[2]; stats->IocbIssued[3] = hba->stats.IocbIssued[3]; stats->IocbReceived[0] = hba->stats.IocbReceived[0]; stats->IocbReceived[1] = hba->stats.IocbReceived[1]; stats->IocbReceived[2] = hba->stats.IocbReceived[2]; stats->IocbReceived[3] = hba->stats.IocbReceived[3]; stats->IocbTxPut[0] = hba->stats.IocbTxPut[0]; stats->IocbTxPut[1] = hba->stats.IocbTxPut[1]; stats->IocbTxPut[2] = hba->stats.IocbTxPut[2]; stats->IocbTxPut[3] = hba->stats.IocbTxPut[3]; stats->IocbTxGet[0] = hba->stats.IocbTxGet[0]; stats->IocbTxGet[1] = hba->stats.IocbTxGet[1]; stats->IocbTxGet[2] = hba->stats.IocbTxGet[2]; stats->IocbTxGet[3] = hba->stats.IocbTxGet[3]; stats->IocbRingFull[0] = hba->stats.IocbRingFull[0]; stats->IocbRingFull[1] = hba->stats.IocbRingFull[1]; stats->IocbRingFull[2] = hba->stats.IocbRingFull[2]; stats->IocbRingFull[3] = hba->stats.IocbRingFull[3]; stats->IntrEvent[0] = hba->stats.IntrEvent[0]; stats->IntrEvent[1] = hba->stats.IntrEvent[1]; stats->IntrEvent[2] = hba->stats.IntrEvent[2]; stats->IntrEvent[3] = hba->stats.IntrEvent[3]; stats->IntrEvent[4] = hba->stats.IntrEvent[4]; stats->IntrEvent[5] = hba->stats.IntrEvent[5]; stats->IntrEvent[6] = hba->stats.IntrEvent[6]; stats->IntrEvent[7] = hba->stats.IntrEvent[7]; stats->FcpIssued = hba->stats.FcpIssued; stats->FcpCompleted = hba->stats.FcpCompleted; stats->FcpGood = hba->stats.FcpGood; stats->FcpError = hba->stats.FcpError; stats->FcpEvent = hba->stats.FcpEvent; stats->FcpStray = hba->stats.FcpStray; stats->ElsEvent = hba->stats.ElsEvent; stats->ElsStray = hba->stats.ElsStray; stats->ElsCmdIssued = hba->stats.ElsCmdIssued; stats->ElsCmdCompleted = hba->stats.ElsCmdCompleted; stats->ElsCmdGood = hba->stats.ElsCmdGood; stats->ElsCmdError = hba->stats.ElsCmdError; stats->ElsRspIssued = hba->stats.ElsRspIssued; stats->ElsRspCompleted = hba->stats.ElsRspCompleted; stats->ElsRcvEvent = hba->stats.ElsRcvEvent; stats->ElsRcvError = hba->stats.ElsRcvError; stats->ElsRcvDropped = hba->stats.ElsRcvDropped; stats->ElsCmdReceived = hba->stats.ElsCmdReceived; stats->ElsRscnReceived = hba->stats.ElsRscnReceived; stats->ElsPlogiReceived = hba->stats.ElsPlogiReceived; stats->ElsPrliReceived = hba->stats.ElsPrliReceived; stats->ElsPrloReceived = hba->stats.ElsPrloReceived; stats->ElsLogoReceived = hba->stats.ElsLogoReceived; stats->ElsAdiscReceived = hba->stats.ElsAdiscReceived; stats->ElsGenReceived = hba->stats.ElsGenReceived; stats->CtEvent = hba->stats.CtEvent; stats->CtStray = hba->stats.CtStray; stats->CtCmdIssued = hba->stats.CtCmdIssued; stats->CtCmdCompleted = hba->stats.CtCmdCompleted; stats->CtCmdGood = hba->stats.CtCmdGood; stats->CtCmdError = hba->stats.CtCmdError; stats->CtRspIssued = hba->stats.CtRspIssued; stats->CtRspCompleted = hba->stats.CtRspCompleted; stats->CtRcvEvent = hba->stats.CtRcvEvent; stats->CtRcvError = hba->stats.CtRcvError; stats->CtRcvDropped = hba->stats.CtRcvDropped; stats->CtCmdReceived = hba->stats.CtCmdReceived; stats->IpEvent = hba->stats.IpEvent; stats->IpStray = hba->stats.IpStray; stats->IpSeqIssued = hba->stats.IpSeqIssued; stats->IpSeqCompleted = hba->stats.IpSeqCompleted; stats->IpSeqGood = hba->stats.IpSeqGood; stats->IpSeqError = hba->stats.IpSeqError; stats->IpBcastIssued = hba->stats.IpBcastIssued; stats->IpBcastCompleted = hba->stats.IpBcastCompleted; stats->IpBcastGood = hba->stats.IpBcastGood; stats->IpBcastError = hba->stats.IpBcastError; stats->IpRcvEvent = hba->stats.IpRcvEvent; stats->IpDropped = hba->stats.IpDropped; stats->IpSeqReceived = hba->stats.IpSeqReceived; stats->IpBcastReceived = hba->stats.IpBcastReceived; stats->IpUbPosted = hba->stats.IpUbPosted; stats->ElsUbPosted = hba->stats.ElsUbPosted; stats->CtUbPosted = hba->stats.CtUbPosted; #if (DFC_REV >= 2) stats->IocbThrottled = hba->stats.IocbThrottled; stats->ElsAuthReceived = hba->stats.ElsAuthReceived; #endif return (rval); } /* emlxs_dfc_get_drvstats() */ extern uint32_t emlxs_set_hba_mode(emlxs_hba_t *hba, uint32_t mode) { emlxs_port_t *port = &PPORT; uint32_t i; mutex_enter(&EMLXS_PORT_LOCK); /* Wait if adapter is in transition */ i = 0; while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) { if (i++ > 30) { break; } mutex_exit(&EMLXS_PORT_LOCK); delay(drv_usectohz(1000000)); mutex_enter(&EMLXS_PORT_LOCK); } if (hba->sli_mode <= EMLXS_HBA_SLI3_MODE) { switch (mode) { case DDI_SHOW: break; case DDI_ONDI: if (hba->flag & FC_OFFLINE_MODE) { mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_online(hba); mutex_enter(&EMLXS_PORT_LOCK); } break; /* Killed + Restart state */ case DDI_OFFDI: if (hba->flag & FC_ONLINE_MODE) { mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_offline(hba, 0); /* Reset with restart */ EMLXS_SLI_HBA_RESET(hba, 1, 1, 0); mutex_enter(&EMLXS_PORT_LOCK); } else if (hba->state < FC_INIT_START) { mutex_exit(&EMLXS_PORT_LOCK); /* Reset with restart */ EMLXS_SLI_HBA_RESET(hba, 1, 1, 0); mutex_enter(&EMLXS_PORT_LOCK); } break; /* Killed + Reset state */ case DDI_WARMDI: if (hba->flag & FC_ONLINE_MODE) { mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_offline(hba, 0); /* Reset with no restart */ EMLXS_SLI_HBA_RESET(hba, 0, 0, 0); mutex_enter(&EMLXS_PORT_LOCK); } else if (hba->state != FC_WARM_START) { mutex_exit(&EMLXS_PORT_LOCK); /* Reset with no restart */ EMLXS_SLI_HBA_RESET(hba, 0, 0, 0); mutex_enter(&EMLXS_PORT_LOCK); } break; /* Killed */ case DDI_DIAGDI: if (hba->flag & FC_ONLINE_MODE) { mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_offline(hba, 0); mutex_enter(&EMLXS_PORT_LOCK); } else if (hba->state != FC_KILLED) { mutex_exit(&EMLXS_PORT_LOCK); EMLXS_SLI_HBA_KILL(hba); mutex_enter(&EMLXS_PORT_LOCK); } break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "set_hba_mode: Invalid mode. mode=%x", mode); mutex_exit(&EMLXS_PORT_LOCK); return (0); } /* Wait if adapter is in transition */ i = 0; while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) { if (i++ > 30) { break; } mutex_exit(&EMLXS_PORT_LOCK); delay(drv_usectohz(1000000)); mutex_enter(&EMLXS_PORT_LOCK); } /* Return current state */ if (hba->flag & FC_ONLINE_MODE) { mode = DDI_ONDI; } else if (hba->state == FC_KILLED) { mode = DDI_DIAGDI; } else if (hba->state == FC_WARM_START) { mode = DDI_WARMDI; } else { mode = DDI_OFFDI; } mutex_exit(&EMLXS_PORT_LOCK); return (mode); } else { /* SLI4 */ switch (mode) { case DDI_SHOW: break; case DDI_ONDI: if (hba->flag & FC_OFFLINE_MODE) { mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_online(hba); mutex_enter(&EMLXS_PORT_LOCK); } break; case DDI_OFFDI: if (hba->flag & FC_ONLINE_MODE) { mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_offline(hba, 0); /* Reset with restart */ EMLXS_SLI_HBA_RESET(hba, 1, 1, 0); mutex_enter(&EMLXS_PORT_LOCK); } else if (hba->state < FC_INIT_START) { mutex_exit(&EMLXS_PORT_LOCK); /* Reset with restart */ EMLXS_SLI_HBA_RESET(hba, 1, 1, 0); mutex_enter(&EMLXS_PORT_LOCK); } break; case DDI_DIAGDI: if (!(hba->model_info.chip & EMLXS_LANCER_CHIPS)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "set_hba_mode: Invalid mode. mode=%x", mode); mutex_exit(&EMLXS_PORT_LOCK); return (0); } mutex_exit(&EMLXS_PORT_LOCK); (void) emlxs_reset(port, EMLXS_DFC_RESET_ALL_FORCE_DUMP); return (mode); case DDI_WARMDI: default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "set_hba_mode: Invalid mode. mode=%x", mode); mutex_exit(&EMLXS_PORT_LOCK); return (0); } /* Wait if adapter is in transition */ i = 0; while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) { if (i++ > 30) { break; } mutex_exit(&EMLXS_PORT_LOCK); delay(drv_usectohz(1000000)); mutex_enter(&EMLXS_PORT_LOCK); } /* Return current state */ if (hba->flag & FC_ONLINE_MODE) { mode = DDI_ONDI; } else { mode = DDI_OFFDI; } mutex_exit(&EMLXS_PORT_LOCK); return (mode); } } /* emlxs_set_hba_mode() */ /*ARGSUSED*/ static int32_t emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; int32_t rval = 0; int32_t flag; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } flag = emlxs_set_hba_mode(hba, dfc->flag); bcopy((void *)&flag, (void *)dfc->buf1, sizeof (uint32_t)); return (rval); } /* emlxs_dfc_set_diag() */ /*ARGSUSED*/ static int32_t emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; MAILBOX *mb = NULL; MAILBOXQ *mbq = NULL; uint32_t size = 0; MATCHMAP *rx_mp = NULL; MATCHMAP *tx_mp = NULL; uintptr_t lptr; int32_t rval = 0; int32_t mbxstatus = 0; NODELIST *ndlp; uint32_t did; uint32_t extsize = 0; uint8_t *extbuf = NULL; if (hba->sli_mode > EMLXS_HBA_SLI3_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: SLI Mode %d not supported.", emlxs_dfc_xlate(dfc->cmd), hba->sli_mode); return (DFC_NOT_SUPPORTED); } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size > MAILBOX_CMD_BSIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too large. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOBIG); } #ifdef MBOX_EXT_SUPPORT if (dfc->buf3_size || dfc->buf4_size) { if (dfc->buf3_size && !dfc->buf3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf3_size > MBOX_EXTENSION_SIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buffer3 too large. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size); return (DFC_ARG_TOOBIG); } if (dfc->buf4_size && !dfc->buf4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf4_size > MBOX_EXTENSION_SIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: buffer4 too large. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size); return (DFC_ARG_TOOBIG); } extsize = (dfc->buf3_size > dfc->buf4_size) ? dfc->buf3_size : dfc->buf4_size; extbuf = (uint8_t *)kmem_zalloc(extsize, KM_SLEEP); if (dfc->buf3_size) { bcopy((void *)dfc->buf3, (void *)extbuf, dfc->buf3_size); } } #endif /* MBOX_EXT_SUPPORT */ mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *) mbq; bcopy((void *)dfc->buf1, (void *)mb, dfc->buf1_size); #ifdef _LP64 if ((mb->mbxCommand == MBX_READ_SPARM) || (mb->mbxCommand == MBX_READ_RPI) || (mb->mbxCommand == MBX_REG_LOGIN) || (mb->mbxCommand == MBX_READ_LA) || (mb->mbxCommand == MBX_RUN_BIU_DIAG)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid mailbox command. Must use 64bit version. " "cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); /* Must use 64 bit versions of these mbox cmds */ rval = DFC_ARG_INVALID; goto done; } #endif lptr = 0; size = 0; switch (mb->mbxCommand) { /* Offline only */ case MBX_CONFIG_LINK: /* 0x07 */ case MBX_PART_SLIM: /* 0x08 */ case MBX_CONFIG_RING: /* 0x09 */ case MBX_DUMP_CONTEXT: /* 0x18 */ case MBX_RUN_DIAGS: /* 0x19 */ case MBX_RESTART: /* 0x1A */ case MBX_SET_MASK: /* 0x20 */ case MBX_FLASH_WR_ULA: /* 0x98 */ if (!(hba->flag & FC_OFFLINE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Adapter not offline. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ONLINE_ERROR; goto done; } break; /* Online / Offline */ case MBX_UNREG_LOGIN: /* 0x14 */ ndlp = emlxs_node_find_rpi(port, mb->un.varUnregLogin.rpi); if (ndlp) { did = ndlp->nlp_DID; /* remove it */ emlxs_node_rm(port, ndlp); /* * If we just unregistered the host node then * clear the host DID */ if (did == port->did) { port->did = 0; } } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Node not found. cmd=%x rpi=%d", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, mb->un.varUnregLogin.rpi); /* Node does not exist */ rval = DFC_ARG_INVALID; goto done; } /* Send it */ break; case MBX_UNREG_D_ID: /* 0x23 */ did = mb->un.varRegLogin.did; if (did == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Node not found. cmd=%x did=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did); rval = DFC_ARG_INVALID; goto done; } if (did == 0xffffffff) { emlxs_node_destroy_all(port); break; } /* Check for base node */ if (did == BCAST_DID) { /* just flush base node */ (void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0); (void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0); /* Return now */ rval = 0; goto done; } /* Make sure the node does already exist */ ndlp = emlxs_node_find_did(port, did, 1); if (ndlp) { /* remove it */ emlxs_node_rm(port, ndlp); /* * If we just unregistered the host node then * clear the host DID */ if (did == port->did) { port->did = 0; } } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Node not found. cmd=%x did=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did); /* Node does not exist */ rval = DFC_ARG_INVALID; goto done; } /* Send it */ break; /* Online / Offline - with DMA */ case MBX_READ_EVENT_LOG: /* 0x38 */ lptr = (uintptr_t)PADDR(mb->un.varRdEvtLog.un.sp64.addrHigh, mb->un.varRdEvtLog.un.sp64.addrLow); size = (int)mb->un.varRdEvtLog.un.sp64.tus.f.bdeSize; if (!lptr || !size || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate receive buffer */ if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } mb->un.varRdEvtLog.un.sp64.addrHigh = PADDR_HI(rx_mp->phys); mb->un.varRdEvtLog.un.sp64.addrLow = PADDR_LO(rx_mp->phys); mb->un.varRdEvtLog.un.sp64.tus.f.bdeFlags = 0; break; case MBX_READ_SPARM: /* 0x0D */ case MBX_READ_SPARM64: /* 0x8D */ lptr = (uintptr_t)PADDR(mb->un.varRdSparm.un.sp64.addrHigh, mb->un.varRdSparm.un.sp64.addrLow); size = (int)mb->un.varRdSparm.un.sp64.tus.f.bdeSize; if (!lptr || !size || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate receive buffer */ if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } mb->un.varRdSparm.un.sp64.addrHigh = PADDR_HI(rx_mp->phys); mb->un.varRdSparm.un.sp64.addrLow = PADDR_LO(rx_mp->phys); mb->un.varRdSparm.un.sp64.tus.f.bdeFlags = 0; break; case MBX_READ_RPI: /* 0x0F */ case MBX_READ_RPI64: /* 0x8F */ lptr = (uintptr_t)PADDR(mb->un.varRdRPI.un.sp64.addrHigh, mb->un.varRdRPI.un.sp64.addrLow); size = (int)mb->un.varRdRPI.un.sp64.tus.f.bdeSize; if (!lptr || !size || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate receive buffer */ if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } mb->un.varRdRPI.un.sp64.addrHigh = PADDR_HI(rx_mp->phys); mb->un.varRdRPI.un.sp64.addrLow = PADDR_LO(rx_mp->phys); mb->un.varRdRPI.un.sp64.tus.f.bdeFlags = 0; break; case MBX_RUN_BIU_DIAG: /* 0x04 */ case MBX_RUN_BIU_DIAG64: /* 0x84 */ lptr = (uintptr_t)PADDR(mb->un.varBIUdiag.un.s2.xmit_bde64. addrHigh, mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow); size = (int)mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize; if (!lptr || !size || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid xmit BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate xmit buffer */ if ((tx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate xmit buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } /* Initialize the xmit buffer */ if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_COPYIN_ERROR; goto done; } EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size, DDI_DMA_SYNC_FORDEV); mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = PADDR_HI(tx_mp->phys); mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = PADDR_LO(tx_mp->phys); mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0; /* Initialize the receive buffer */ lptr = (uintptr_t)PADDR(mb->un.varBIUdiag.un.s2.rcv_bde64. addrHigh, mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow); size = (int)mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize; if (!lptr || !size || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid rcv BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate receive buffer */ if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = PADDR_HI(rx_mp->phys); mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = PADDR_LO(rx_mp->phys); mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeFlags = 0; break; case MBX_REG_LOGIN: /* 0x13 */ case MBX_REG_LOGIN64: /* 0x93 */ did = mb->un.varRegLogin.did; /* Check for invalid node ids to register */ if (did == 0 || (did & 0xff000000)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid node id. cmd=%x did=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did); rval = DFC_ARG_INVALID; goto done; } /* Check if the node limit has been reached */ if (port->node_count >= hba->max_nodes) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Too many nodes. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_HBARES_ERROR; goto done; } lptr = (uintptr_t)PADDR(mb->un.varRegLogin.un.sp64.addrHigh, mb->un.varRegLogin.un.sp64.addrLow); size = (int)mb->un.varRegLogin.un.sp64.tus.f.bdeSize; if (!lptr || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate xmit buffer */ if ((tx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate xmit buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } /* Initialize the xmit buffer */ if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate xmit buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_COPYIN_ERROR; goto done; } EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size, DDI_DMA_SYNC_FORDEV); mb->un.varRegLogin.un.sp64.addrHigh = PADDR_HI(tx_mp->phys); mb->un.varRegLogin.un.sp64.addrLow = PADDR_LO(tx_mp->phys); mb->un.varRegLogin.un.sp64.tus.f.bdeFlags = 0; break; case MBX_READ_LA: /* 0x15 */ case MBX_READ_LA64: /* 0x95 */ lptr = (uintptr_t)PADDR(mb->un.varReadLA.un.lilpBde64. addrHigh, mb->un.varReadLA.un.lilpBde64.addrLow); size = (int)mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize; if (!lptr || !size || (size > MEM_BUF_SIZE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; } /* Allocate receive buffer */ if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_DRVRES_ERROR; goto done; } mb->un.varReadLA.un.lilpBde64.addrHigh = PADDR_HI(rx_mp->phys); mb->un.varReadLA.un.lilpBde64.addrLow = PADDR_LO(rx_mp->phys); mb->un.varReadLA.un.lilpBde64.tus.f.bdeFlags = 0; break; /* Do not allow these commands */ case MBX_CONFIG_PORT: /* 0x88 */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Command not allowed. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_ARG_INVALID; goto done; /* Online / Offline */ default: break; } /* switch() */ mb->mbxOwner = OWN_HOST; /* Set or don't set the PASSTHRU bit. */ /* Setting will prevent the driver from processing it as its own */ switch (mb->mbxCommand) { case MBX_REG_LOGIN: /* 0x13 */ case MBX_REG_LOGIN64: /* 0x93 */ break; default: mbq->flag |= MBQ_PASSTHRU; } #ifdef MBOX_EXT_SUPPORT if (extbuf) { mbq->extbuf = extbuf; mbq->extsize = extsize; } #endif /* MBOX_EXT_SUPPORT */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: %s sent. (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), mb->un.varWords[0], mb->un.varWords[1], mb->un.varWords[2], mb->un.varWords[3]); /* issue the mbox cmd to the sli */ mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus); } bcopy((void *)mb, (void *)dfc->buf2, dfc->buf2_size); if (rx_mp) { EMLXS_MPDATA_SYNC(rx_mp->dma_handle, 0, size, DDI_DMA_SYNC_FORKERNEL); if (ddi_copyout((void *)rx_mp->virt, (void *)lptr, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed for receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_COPYOUT_ERROR; goto done; } } #ifdef MBOX_EXT_SUPPORT /* Any data needs to copy to mbox extension area */ if (dfc->buf4_size) { bcopy((void *)extbuf, (void *)dfc->buf4, dfc->buf4_size); } #endif /* MBOX_EXT_SUPPORT */ rval = 0; done: /* Free allocated mbox memory */ if (extbuf) { kmem_free(extbuf, extsize); } /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } /* Free allocated mbuf memory */ if (rx_mp) { #ifdef FMA_SUPPORT if (!rval) { if (emlxs_fm_check_dma_handle(hba, rx_mp->dma_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_dma_handle_msg, "dfc_send_mbox: hdl=%p", rx_mp->dma_handle); rval = DFC_IO_ERROR; } } #endif /* FMA_SUPPORT */ emlxs_mem_buf_free(hba, rx_mp); } if (tx_mp) { #ifdef FMA_SUPPORT if (!rval) { if (emlxs_fm_check_dma_handle(hba, tx_mp->dma_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_dma_handle_msg, "dfc_send_mbox: hdl=%p", tx_mp->dma_handle); rval = DFC_IO_ERROR; } } #endif /* FMA_SUPPORT */ emlxs_mem_buf_free(hba, tx_mp); } return (rval); } /* emlxs_dfc_send_mbox() */ /*ARGSUSED*/ static int32_t emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t cnt; uint32_t outsz; uint32_t i; uint32_t *bptr; uint32_t value; uint32_t max = 4096; offset = dfc->data1; cnt = dfc->data2; outsz = dfc->buf1_size; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt); if (!dfc->buf1_size || !dfc->buf1) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (offset & 0x3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset misaligned. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_MISALIGNED); } if (cnt & 0x3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count misaligned. (count=%d)", emlxs_dfc_xlate(dfc->cmd), cnt); return (DFC_ARG_MISALIGNED); } if (outsz & 0x3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Output size misaligned. (size=%d)", emlxs_dfc_xlate(dfc->cmd), outsz); return (DFC_ARG_MISALIGNED); } /* Get max PCI config range */ if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) { max = 256; } else { max = 4096; } if ((cnt + offset) > max) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset+Count too large. (offset=%d count=%d max=%d)", emlxs_dfc_xlate(dfc->cmd), offset, cnt, max); return (DFC_ARG_TOOBIG); } if (outsz > max) { outsz = max; } if (cnt > outsz) { cnt = outsz; } bptr = (uint32_t *)dfc->buf1; for (i = offset; i < (offset + cnt); i += 4) { value = ddi_get32(hba->pci_acc_handle, (uint32_t *)(hba->pci_addr + i)); *bptr++ = BE_SWAP32(value); } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_read_pci() */ /*ARGSUSED*/ static int32_t emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t cnt; uint32_t value; uint32_t i; uint32_t max; uint32_t *bptr; uint16_t word0; uint16_t word1; offset = dfc->data1; cnt = dfc->data2; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt); if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (offset & 0x3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset misaligned. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_MISALIGNED); } if (cnt > dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count too large. (count=%d)", emlxs_dfc_xlate(dfc->cmd), cnt); return (DFC_ARG_TOOBIG); } if (cnt & 0x3) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count misaligned. (count=%d)", emlxs_dfc_xlate(dfc->cmd), cnt); return (DFC_ARG_MISALIGNED); } /* Get max PCI config range */ if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) { max = 256; } else { max = 4096; } if ((cnt + offset) > max) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count+Offset too large. (offset=%d count=%d max=%d)", emlxs_dfc_xlate(dfc->cmd), offset, cnt, max); return (DFC_ARG_TOOBIG); } bptr = (uint32_t *)dfc->buf1; for (i = offset; i < (offset + cnt); i += 4) { value = *bptr++; value = BE_SWAP32(value); word0 = value & 0xFFFF; word1 = value >> 16; /* * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, * "%s: Writing. offset=%x cnt=%d value=%08x %04x %04x", * emlxs_dfc_xlate(dfc->cmd), i, value, word0, word1); */ /* word0 = PCIMEM_SHORT(word0); */ ddi_put16(hba->pci_acc_handle, (uint16_t *)(hba->pci_addr + i), (uint16_t)word0); /* word1 = PCIMEM_SHORT(word1); */ ddi_put16(hba->pci_acc_handle, (uint16_t *)(hba->pci_addr + i + 2), (uint16_t)word1); } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_write_pci() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_cfgparam_t *cfgparam; uint32_t count; uint32_t i; emlxs_config_t *cfg; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } count = dfc->buf1_size / sizeof (dfc_cfgparam_t); if (count > MAX_CFG_PARAM) { count = MAX_CFG_PARAM; } cfgparam = (dfc_cfgparam_t *)dfc->buf1; bzero(cfgparam, sizeof (dfc_cfgparam_t)); cfg = &CFG; for (i = 0; i < count; i++) { (void) strncpy(cfgparam[i].a_string, cfg[i].string, (sizeof (cfgparam[i].a_string)-1)); cfgparam[i].a_low = cfg[i].low; cfgparam[i].a_hi = cfg[i].hi; cfgparam[i].a_default = cfg[i].def; cfgparam[i].a_current = cfg[i].current; if (!(cfg[i].flags & PARM_HIDDEN)) { cfgparam[i].a_flag |= CFG_EXPORT; } cfgparam[i].a_flag |= CFG_COMMON; /* Adjust a_flag based on the hba model */ switch (i) { case CFG_NETWORK_ON: case CFG_TOPOLOGY: case CFG_LINK_SPEED: case CFG_CR_DELAY: case CFG_CR_COUNT: if (! ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE)) { cfgparam[i].a_flag |= CFG_APPLICABLE; } break; case CFG_NUM_WQ: if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { cfgparam[i].a_flag |= CFG_APPLICABLE; } break; case CFG_PERSIST_LINKDOWN: cfgparam[i].a_flag &= ~CFG_EXPORT; break; default: cfgparam[i].a_flag |= CFG_APPLICABLE; break; } if ((cfg[i].flags & PARM_DYNAMIC)) { if ((cfg[i].flags & PARM_DYNAMIC_RESET) == PARM_DYNAMIC_RESET) { cfgparam[i].a_changestate = CFG_RESTART; } else if ((cfg[i].flags & PARM_DYNAMIC_LINK) == PARM_DYNAMIC_LINK) { cfgparam[i].a_changestate = CFG_LINKRESET; } else { cfgparam[i].a_changestate = CFG_DYMANIC; } } else { cfgparam[i].a_changestate = CFG_REBOOT; } (void) strncpy(cfgparam[i].a_help, cfg[i].help, (sizeof (cfgparam[i].a_help)-1)); } return (0); } /* emlxs_dfc_get_cfg() */ /* ARGSUSED */ static int32_t emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t index; uint32_t new_value; uint32_t rc; index = dfc->data1; new_value = dfc->data2; rc = emlxs_set_parm(hba, index, new_value); if (rc) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to set parameter. code=%d", emlxs_dfc_xlate(dfc->cmd), rc); switch (rc) { case 2: return (DFC_NPIV_ACTIVE); default: return (DFC_ARG_INVALID); } } return (0); } /* emlxs_dfc_set_cfg() */ /*ARGSUSED*/ static int32_t emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint8_t *rsp_buf; uint8_t *cmd_buf; uint32_t did; uint32_t rsp_size; uint32_t cmd_size; uint32_t timeout; fc_packet_t *pkt = NULL; uint32_t rval = 0; dfc_destid_t *destid; NODELIST *nlp; char buffer[128]; cmd_buf = dfc->buf1; cmd_size = dfc->buf1_size; rsp_buf = dfc->buf2; rsp_size = dfc->buf2_size; timeout = dfc->data1; if (timeout < (2 * hba->fc_ratov)) { timeout = 2 * hba->fc_ratov; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), cmd_size, rsp_size); if (!cmd_size || !cmd_buf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!rsp_size || !rsp_buf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!dfc->buf3 || !dfc->buf3_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!dfc->buf4 || !dfc->buf4_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (rsp_size > MAX_CT_PAYLOAD) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too large. size=%d", emlxs_dfc_xlate(dfc->cmd), rsp_size); rval = DFC_ARG_TOOBIG; goto done; } if (cmd_size > MAX_CT_PAYLOAD) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too large. size=%d", emlxs_dfc_xlate(dfc->cmd), cmd_size); rval = DFC_ARG_TOOBIG; goto done; } if (dfc->buf3_size < sizeof (dfc_destid_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer3 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size); rval = DFC_ARG_TOOSMALL; goto done; } if (dfc->buf4_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer4 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size); rval = DFC_ARG_TOOSMALL; goto done; } destid = (dfc_destid_t *)dfc->buf3; if (destid->idType == 0) { if ((nlp = emlxs_node_find_wwpn(port, destid->wwpn, 1)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, sizeof (buffer), destid->wwpn)); rval = DFC_ARG_INVALID; goto done; } did = nlp->nlp_DID; } else { if (emlxs_node_find_did(port, destid->d_id, 1) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: DID does not exist. did=%x", emlxs_dfc_xlate(dfc->cmd), destid->d_id); rval = DFC_ARG_INVALID; goto done; } did = destid->d_id; } if (did == 0) { did = port->did; } if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = (timeout) ? timeout : 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; /* Copy in the command buffer */ bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_IO_ERROR; goto done; } if ((pkt->pkt_state != FC_PKT_SUCCESS) && (pkt->pkt_state != FC_PKT_FS_RJT)) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. Pkt Timeout."); rval = DFC_TIMEOUT; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size); rsp_size -= pkt->pkt_resp_resid; bcopy((void *)&rsp_size, (void *)dfc->buf4, sizeof (uint32_t)); rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_ct() */ /*ARGSUSED*/ static int32_t emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint8_t *cmd_buf; uint32_t rx_id; uint32_t cmd_size; uint32_t timeout; fc_packet_t *pkt = NULL; uint32_t rval = 0; cmd_buf = dfc->buf1; cmd_size = dfc->buf1_size; rx_id = dfc->flag; timeout = 2 * hba->fc_ratov; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: csize=%d", emlxs_dfc_xlate(dfc->cmd), cmd_size); if (!cmd_size || !cmd_buf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!(pkt = emlxs_pkt_alloc(port, cmd_size, 0, 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_OUTBOUND; pkt->pkt_timeout = (timeout) ? timeout : 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(0); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_SOLICITED_CONTROL; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_LAST_SEQ | F_CTL_END_SEQ | F_CTL_XCHG_CONTEXT; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xffff; pkt->pkt_cmd_fhdr.rx_id = rx_id; pkt->pkt_cmd_fhdr.ro = 0; /* Copy in the command buffer */ bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. Pkt Timeout."); rval = DFC_TIMEOUT; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_ct_rsp() */ #ifdef MENLO_SUPPORT /*ARGSUSED*/ static int32_t emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint8_t *rsp_buf = NULL; uint8_t *cmd_buf = NULL; uint32_t rsp_size = 0; uint32_t cmd_size = 0; uint32_t rval = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size, dfc->buf2_size); if (hba->model_info.vendor_id != PCI_VENDOR_ID_EMULEX || hba->model_info.device_id != PCI_DEVICE_ID_HORNET) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Menlo device not present. device=%x,%x,%x", emlxs_dfc_xlate(dfc->cmd), hba->model_info.vendor_id, hba->model_info.device_id, hba->model_info.ssdid); rval = DFC_INVALID_ADAPTER; goto done; } if (!dfc->buf1_size || !dfc->buf1) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!dfc->buf2_size || !dfc->buf2) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!dfc->buf3 || !dfc->buf3_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (dfc->buf3_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer3 too small. %d < %d", emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size, sizeof (uint32_t)); rval = DFC_ARG_TOOSMALL; goto done; } cmd_size = dfc->buf1_size; cmd_buf = (uint8_t *)dfc->buf1; rsp_size = dfc->buf2_size; rsp_buf = (uint8_t *)dfc->buf2; /* Send the command */ rval = emlxs_send_menlo_cmd(hba, cmd_buf, cmd_size, rsp_buf, &rsp_size); if (rval == 0) { /* Return the response & size */ bcopy((void *)rsp_buf, (void *)dfc->buf2, rsp_size); bcopy((void *)&rsp_size, (void *)dfc->buf3, sizeof (uint32_t)); } done: return (rval); } /* emlxs_dfc_send_menlo() */ extern int32_t emlxs_send_menlo_cmd(emlxs_hba_t *hba, uint8_t *cmd_buf, uint32_t cmd_size, uint8_t *rsp_buf, uint32_t *rsp_size) { emlxs_port_t *port = &PPORT; uint8_t *data_buf = NULL; uint32_t data_size = 0; fc_packet_t *pkt = NULL; int32_t rval = 0; menlo_set_cmd_t set_cmd; menlo_reset_cmd_t reset_cmd; uint32_t rsp_code; uint32_t mm_mode = 0; uint32_t cmd_code; clock_t timeout; MAILBOXQ *mbq = NULL; MAILBOX *mb; uint32_t addr; uint32_t value; uint32_t mbxstatus; cmd_code = *(uint32_t *)cmd_buf; cmd_code = BE_SWAP32(cmd_code); /* Look for Zephyr specific commands */ if (cmd_code & 0x80000000) { bzero((uint8_t *)&reset_cmd, sizeof (menlo_reset_cmd_t)); bzero((uint8_t *)&set_cmd, sizeof (menlo_set_cmd_t)); bzero((uint8_t *)&rsp_code, sizeof (uint32_t)); /* Validate response buffer */ if (*rsp_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: Response overrun."); rval = DFC_RSP_BUF_OVERRUN; goto done; } /* All of these responses will be 4 bytes only */ *rsp_size = sizeof (uint32_t); rsp_code = 0; /* Validate command buffer */ switch (cmd_code) { case MENLO_CMD_RESET: if (cmd_size < sizeof (menlo_reset_cmd_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Invalid command size. %d < %d", cmd_size, sizeof (menlo_reset_cmd_t)); rval = DFC_ARG_INVALID; goto done; } cmd_size = sizeof (menlo_reset_cmd_t); /* Read the command buffer */ bcopy((void *)cmd_buf, (void *)&reset_cmd, cmd_size); if (reset_cmd.firmware) { /* MENLO_FW_GOLDEN */ value = 1; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "send_menlo_cmd: Reset with Golden " "firmware requested."); } else { /* MENLO_FW_OPERATIONAL */ value = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "send_menlo_cmd: Reset with " "Operational firmware requested."); } addr = 0x103007; break; case MENLO_CMD_SET_MODE: if (cmd_size < sizeof (menlo_set_cmd_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Invalid command size. %d < %d", cmd_size, sizeof (menlo_set_cmd_t)); rval = DFC_ARG_INVALID; goto done; } cmd_size = sizeof (menlo_set_cmd_t); /* Read the command buffer */ bcopy((void *)cmd_buf, (void *)&set_cmd, cmd_size); if (set_cmd.value1) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "send_menlo_cmd: " "Maintenance mode enable requested."); /* Make sure the mode flag is cleared */ if (hba->flag & FC_MENLO_MODE) { mutex_enter(&EMLXS_PORT_LOCK); hba->flag &= ~FC_MENLO_MODE; mutex_exit(&EMLXS_PORT_LOCK); } mm_mode = 1; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "send_menlo_cmd: " "Maintenance mode disable requested."); } addr = 0x103107; value = mm_mode; break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Invalid command. cmd=%x", cmd_code); rval = DFC_ARG_INVALID; goto done; } mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *) mbq; /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mbq, addr, value); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: %s failed. mbxstatus=0x%x", emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus); if (mbxstatus == MBX_TIMEOUT) { rval = DFC_TIMEOUT; } else { rval = DFC_IO_ERROR; } goto done; } bcopy((void *)&rsp_code, (void *)rsp_buf, *rsp_size); /* Check if we need to wait for maintenance mode */ if (mm_mode && !(hba->flag & FC_MENLO_MODE)) { /* Wait for link to come up in maintenance mode */ mutex_enter(&EMLXS_LINKUP_LOCK); timeout = emlxs_timeout(hba, 30); rval = 0; while ((rval != -1) && !(hba->flag & FC_MENLO_MODE)) { rval = cv_timedwait(&EMLXS_LINKUP_CV, &EMLXS_LINKUP_LOCK, timeout); } mutex_exit(&EMLXS_LINKUP_LOCK); if (rval == -1) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Menlo maintenance mode error. Timeout."); rval = DFC_TIMEOUT; goto done; } } } else { /* Standard commands */ if (hba->state <= FC_LINK_DOWN) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: Adapter link down."); rval = DFC_LINKDOWN_ERROR; goto done; } if (cmd_code == MENLO_CMD_FW_DOWNLOAD) { /* Check cmd size */ /* Must be at least 12 bytes of command */ /* plus 4 bytes of data */ if (cmd_size < (12 + 4)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Invalid command size. %d < %d", cmd_size, (12 + 4)); rval = DFC_ARG_INVALID; goto done; } /* Extract data buffer from command buffer */ data_buf = cmd_buf + 12; data_size = cmd_size - 12; cmd_size = 12; } if (!(pkt = emlxs_pkt_alloc(port, cmd_size, *rsp_size, 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: Unable to allocate packet."); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; /* Copy in the command buffer */ bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: Unable to send packet."); rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Pkt Transport error. Pkt Timeout."); rval = DFC_TIMEOUT; } else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) && (pkt->pkt_reason == FC_REASON_OVERRUN)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Pkt Transport error. Response overrun."); rval = DFC_RSP_BUF_OVERRUN; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Pkt Transport error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } if (cmd_code == MENLO_CMD_FW_DOWNLOAD) { uint32_t *rsp; /* Check response code */ rsp = (uint32_t *)pkt->pkt_resp; rsp_code = *rsp; rsp_code = BE_SWAP32(rsp_code); if (rsp_code == MENLO_RSP_SUCCESS) { /* Now transmit the data phase */ /* Save last rx_id */ uint32_t rx_id = pkt->pkt_cmd_fhdr.rx_id; /* Free old pkt */ emlxs_pkt_free(pkt); /* Allocate data pkt */ if (!(pkt = emlxs_pkt_alloc(port, data_size, *rsp_size, 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Unable to allocate data " "packet."); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_OUTBOUND; pkt->pkt_timeout = 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = rx_id; pkt->pkt_cmd_fhdr.ro = 0; /* Copy in the data buffer */ bcopy((void *)data_buf, (void *)pkt->pkt_cmd, data_size); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Unable to send data packet."); rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Data Pkt Transport " "error. Pkt Timeout."); rval = DFC_TIMEOUT; } else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) && (pkt->pkt_reason == FC_REASON_OVERRUN)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Data Pkt Transport " "error. Response overrun."); rval = DFC_RSP_BUF_OVERRUN; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "send_menlo_cmd: " "Data Pkt Transport " "error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } } } bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, *rsp_size); *rsp_size = *rsp_size - pkt->pkt_resp_resid; } rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_send_menlo_cmd() */ /* ARGSUSED */ extern void emlxs_fcoe_attention_thread(emlxs_hba_t *hba, void *arg1, void *arg2) { emlxs_port_t *port = &PPORT; menlo_init_rsp_t *rsp; menlo_get_cmd_t *cmd; fc_packet_t *pkt = NULL; if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_get_cmd_t), sizeof (menlo_init_rsp_t), 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "FCoE attention: Unable to allocate packet."); return; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; cmd = (menlo_get_cmd_t *)pkt->pkt_cmd; cmd->code = MENLO_CMD_GET_INIT; cmd->context = 0; cmd->length = sizeof (menlo_init_rsp_t); /* Little Endian Swap */ cmd->code = BE_SWAP32(cmd->code); cmd->length = BE_SWAP32(cmd->length); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "FCoE attention: Unable to send packet."); goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "FCoE attention: Pkt Transport error. state=%x", pkt->pkt_state); goto done; } /* Check response code */ rsp = (menlo_init_rsp_t *)pkt->pkt_resp; rsp->code = BE_SWAP32(rsp->code); if (rsp->code != MENLO_RSP_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "FCoE attention: FCOE Response error =%x", rsp->code); goto done; } /* Little Endian Swap */ rsp->bb_credit = BE_SWAP32(rsp->bb_credit); rsp->frame_size = BE_SWAP32(rsp->frame_size); rsp->fw_version = BE_SWAP32(rsp->fw_version); rsp->reset_status = BE_SWAP32(rsp->reset_status); rsp->maint_status = BE_SWAP32(rsp->maint_status); rsp->fw_type = BE_SWAP32(rsp->fw_type); rsp->fru_data_valid = BE_SWAP32(rsp->fru_data_valid); /* Log the event */ emlxs_log_fcoe_event(port, rsp); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: bb_credit = 0x%x", rsp->bb_credit); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: frame_size = 0x%x", rsp->frame_size); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: fw_version = 0x%x", rsp->fw_version); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: reset_status = 0x%x", rsp->reset_status); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: maint_status = 0x%x", rsp->maint_status); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: fw_type = 0x%x", rsp->fw_type); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "MENLO_INIT: fru_data_valid = 0x%x", rsp->fru_data_valid); /* Perform attention checks */ if (rsp->fru_data_valid == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_error_msg, "Invalid FRU data found on adapter. " "Return adapter to %s for repair.", hba->model_info.manufacturer); } switch (rsp->fw_type) { case MENLO_FW_TYPE_GOLDEN: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_warning_msg, "FCoE chip is running Golden firmware. " "Update FCoE firmware immediately."); break; case MENLO_FW_TYPE_DIAG: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_notice_msg, "FCoE chip is running Diagnostic firmware. " "Operational use of the adapter is suspended."); break; } done: if (pkt) { emlxs_pkt_free(pkt); } return; } /* emlxs_fcoe_attention_thread() */ #endif /* MENLO_SUPPORT */ /*ARGSUSED*/ static int32_t emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t cnt; uint8_t *bptr; uint32_t i; if (hba->bus_type != SBUS_FC) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid bus_type. (bus_type=%x)", emlxs_dfc_xlate(dfc->cmd), hba->bus_type); return (DFC_ARG_INVALID); } if (!(hba->flag & FC_OFFLINE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ONLINE_ERROR); } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } offset = dfc->data1; cnt = dfc->data2; if (offset > (64 * 1024)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset too large. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_TOOBIG); } if (cnt > dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count too large. (count=%d)", emlxs_dfc_xlate(dfc->cmd), cnt); return (DFC_ARG_TOOBIG); } if ((cnt + offset) > (64 * 1024)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count+Offset too large. (count=%d offset=%d)", emlxs_dfc_xlate(dfc->cmd), cnt, offset); return (DFC_ARG_TOOBIG); } if (cnt == 0) { return (0); } bptr = (uint8_t *)dfc->buf1; for (i = 0; i < cnt; i++) { SBUS_WRITE_FLASH_COPY(hba, offset, *bptr); offset++; bptr++; } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_write_flash() */ /*ARGSUSED*/ static int32_t emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t count; uint32_t outsz; uint8_t *bptr; uint32_t i; if (hba->bus_type != SBUS_FC) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid bus_type. (bus_type=%x)", emlxs_dfc_xlate(dfc->cmd), hba->bus_type); return (DFC_ARG_INVALID); } if (!(hba->flag & FC_OFFLINE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ONLINE_ERROR); } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } offset = dfc->data1; count = dfc->data2; outsz = dfc->buf1_size; if (offset > (64 * 1024)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset too large. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_TOOBIG); } if ((count + offset) > (64 * 1024)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Count+Offset too large. (count=%d offset=%d)", emlxs_dfc_xlate(dfc->cmd), count, offset); return (DFC_ARG_TOOBIG); } if (count < outsz) { outsz = count; } bptr = (uint8_t *)dfc->buf1; for (i = 0; i < outsz; i++) { *bptr++ = SBUS_READ_FLASH_COPY(hba, offset++); } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_read_flash() */ /*ARGSUSED*/ static int32_t emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint8_t *rsp_buf; uint8_t *cmd_buf; dfc_destid_t *destid; uint32_t rsp_size; uint32_t cmd_size; uint32_t timeout; fc_packet_t *pkt = NULL; NODELIST *ndlp; uint32_t did; uint32_t rval = 0; char buffer[128]; cmd_buf = dfc->buf1; cmd_size = dfc->buf1_size; rsp_buf = dfc->buf2; rsp_size = dfc->buf2_size; timeout = 2 * hba->fc_ratov; if (!cmd_size || !cmd_buf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!rsp_buf || !rsp_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!dfc->buf3 || !dfc->buf3_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (dfc->buf3_size < sizeof (dfc_destid_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer3 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size); rval = DFC_ARG_TOOSMALL; goto done; } if (!dfc->buf4 || !dfc->buf4_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (dfc->buf4_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer4 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size); rval = DFC_ARG_TOOSMALL; goto done; } destid = (dfc_destid_t *)dfc->buf3; if (destid->idType == 0) { if ((ndlp = emlxs_node_find_wwpn(port, destid->wwpn, 1)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, sizeof (buffer), destid->wwpn)); rval = DFC_ARG_INVALID; goto done; } did = ndlp->nlp_DID; } else { if (emlxs_node_find_did(port, destid->d_id, 1) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: DID does not exist. did=%x", emlxs_dfc_xlate(dfc->cmd), destid->d_id); rval = DFC_ARG_INVALID; goto done; } did = destid->d_id; } if (did == 0) { did = port->did; } if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = (timeout) ? timeout : 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; /* Copy in the command buffer */ bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { rval = DFC_IO_ERROR; bzero((void *)rsp_buf, rsp_size); bzero((void *)dfc->buf4, sizeof (uint32_t)); goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_LS_RJT) { LS_RJT *ls_rjt; uint32_t *word; word = (uint32_t *)rsp_buf; word[0] = ELS_CMD_LS_RJT; word[1] = 0; ls_rjt = (LS_RJT *)&word[1]; ls_rjt->un.b.lsRjtRsnCode = pkt->pkt_reason; ls_rjt->un.b.lsRjtRsnCodeExp = pkt->pkt_expln; rsp_size = 8; bcopy((void *)&rsp_size, (void *)dfc->buf4, sizeof (uint32_t)); goto done; } else if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. Pkt Timeout."); rval = DFC_TIMEOUT; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } bzero((void *)rsp_buf, rsp_size); bzero((void *)dfc->buf4, sizeof (uint32_t)); goto done; } rsp_size -= pkt->pkt_resp_resid; bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size); bcopy((void *)&rsp_size, (void *)dfc->buf4, sizeof (uint32_t)); rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_els() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_ioinfo_t *ioinfo; uint32_t i; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_ioinfo_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } ioinfo = (dfc_ioinfo_t *)dfc->buf1; bzero(ioinfo, sizeof (dfc_ioinfo_t)); ioinfo->a_mboxCmd = HBASTATS.MboxIssued; ioinfo->a_mboxCmpl = HBASTATS.MboxCompleted; ioinfo->a_mboxErr = HBASTATS.MboxError; for (i = 0; i < hba->chan_count; i++) { ioinfo->a_iocbCmd += HBASTATS.IocbIssued[i]; ioinfo->a_iocbRsp += HBASTATS.IocbReceived[i]; } ioinfo->a_adapterIntr = HBASTATS.IntrEvent[0] + HBASTATS.IntrEvent[1] + HBASTATS.IntrEvent[2] + HBASTATS.IntrEvent[3] + HBASTATS.IntrEvent[4] + HBASTATS.IntrEvent[5] + HBASTATS.IntrEvent[6] + HBASTATS.IntrEvent[7]; ioinfo->a_fcpCmd = HBASTATS.FcpIssued; ioinfo->a_fcpCmpl = HBASTATS.FcpCompleted; ioinfo->a_fcpErr = HBASTATS.FcpCompleted - HBASTATS.FcpGood; ioinfo->a_seqXmit = HBASTATS.IpSeqIssued; ioinfo->a_seqRcv = HBASTATS.IpSeqReceived; ioinfo->a_seqXmitErr = HBASTATS.IpSeqCompleted - HBASTATS.IpSeqGood; ioinfo->a_bcastXmit = HBASTATS.IpBcastIssued; ioinfo->a_bcastRcv = HBASTATS.IpBcastReceived; ioinfo->a_elsXmit = HBASTATS.ElsCmdIssued; ioinfo->a_elsRcv = HBASTATS.ElsCmdReceived; ioinfo->a_elsXmitErr = HBASTATS.ElsCmdCompleted - HBASTATS.ElsCmdGood; ioinfo->a_RSCNRcv = HBASTATS.ElsRscnReceived; ioinfo->a_elsBufPost = HBASTATS.ElsUbPosted; ioinfo->a_ipBufPost = HBASTATS.IpUbPosted; ioinfo->a_cnt1 = 0; ioinfo->a_cnt2 = 0; ioinfo->a_cnt3 = 0; ioinfo->a_cnt4 = 0; return (0); } /* emlxs_dfc_get_ioinfo() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_linkinfo_t *linkinfo; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_linkinfo_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } linkinfo = (dfc_linkinfo_t *)dfc->buf1; bzero(linkinfo, sizeof (dfc_linkinfo_t)); linkinfo->a_linkEventTag = hba->link_event_tag; linkinfo->a_linkUp = HBASTATS.LinkUp; linkinfo->a_linkDown = HBASTATS.LinkDown; linkinfo->a_linkMulti = HBASTATS.LinkMultiEvent; linkinfo->a_DID = port->did; linkinfo->a_topology = 0; if (hba->state <= FC_LINK_DOWN) { linkinfo->a_linkState = LNK_DOWN; } #ifdef MENLO_SUPPORT else if (hba->flag & FC_MENLO_MODE) { linkinfo->a_linkState = LNK_DOWN; linkinfo->a_topology = LNK_MENLO_MAINTENANCE; } #endif /* MENLO_SUPPORT */ else if (hba->state == FC_LINK_DOWN_PERSIST) { linkinfo->a_linkState = LNK_DOWN_PERSIST; } else if (hba->state < FC_READY) { linkinfo->a_linkState = LNK_DISCOVERY; } else { linkinfo->a_linkState = LNK_READY; } if (linkinfo->a_linkState != LNK_DOWN) { if (hba->topology == TOPOLOGY_LOOP) { if (hba->flag & FC_FABRIC_ATTACHED) { linkinfo->a_topology = LNK_PUBLIC_LOOP; } else { linkinfo->a_topology = LNK_LOOP; } linkinfo->a_alpa = port->did & 0xff; linkinfo->a_alpaCnt = port->alpa_map[0]; if (linkinfo->a_alpaCnt > 127) { linkinfo->a_alpaCnt = 127; } bcopy((void *)&port->alpa_map[0], linkinfo->a_alpaMap, linkinfo->a_alpaCnt+1); } else { if (hba->flag & FC_FABRIC_ATTACHED) { linkinfo->a_topology = LNK_FABRIC; } else { linkinfo->a_topology = LNK_PT2PT; } } } bcopy(&hba->wwpn, linkinfo->a_wwpName, 8); bcopy(&hba->wwnn, linkinfo->a_wwnName, 8); return (0); } /* emlxs_dfc_get_linkinfo() */ #ifdef SFCT_SUPPORT /*ARGSUSED*/ static int32_t emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_tgtport_stat_t *statp = &TGTPORTSTAT; dfc_tgtport_stat_t *dfcstat; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (emlxs_tgtport_stat_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } dfcstat = (dfc_tgtport_stat_t *)dfc->buf1; bzero(dfcstat, sizeof (dfc_tgtport_stat_t)); dfcstat->Version = DFC_TGTPORT_STAT_VERSION; dfcstat->FctRcvDropped = statp->FctRcvDropped; dfcstat->FctOverQDepth = statp->FctOverQDepth; dfcstat->FctOutstandingIO = statp->FctOutstandingIO; dfcstat->FctFailedPortRegister = statp->FctFailedPortRegister; dfcstat->FctPortRegister = statp->FctPortRegister; dfcstat->FctPortDeregister = statp->FctPortDeregister; dfcstat->FctAbortSent = statp->FctAbortSent; dfcstat->FctNoBuffer = statp->FctNoBuffer; dfcstat->FctScsiStatusErr = statp->FctScsiStatusErr; dfcstat->FctScsiQfullErr = statp->FctScsiQfullErr; dfcstat->FctScsiResidOver = statp->FctScsiResidOver; dfcstat->FctScsiResidUnder = statp->FctScsiResidUnder; dfcstat->FctScsiSenseErr = statp->FctScsiSenseErr; dfcstat->FctEvent = statp->FctEvent; dfcstat->FctCompleted = statp->FctCompleted; dfcstat->FctCmplGood = statp->FctCmplGood; dfcstat->FctCmplError = statp->FctCmplError; dfcstat->FctStray = statp->FctStray; bcopy(&statp->FctP2IOWcnt[0], &dfcstat->FctP2IOWcnt[0], (sizeof (uint64_t) * MAX_TGTPORT_IOCNT)); bcopy(&statp->FctP2IORcnt[0], &dfcstat->FctP2IORcnt[0], (sizeof (uint64_t) * MAX_TGTPORT_IOCNT)); dfcstat->FctIOCmdCnt = statp->FctIOCmdCnt; dfcstat->FctReadBytes = statp->FctReadBytes; dfcstat->FctWriteBytes = statp->FctWriteBytes; dfcstat->FctCmdReceived = statp->FctCmdReceived; if (dfc->flag) { /* Clear counters after read */ bzero(&statp->FctP2IOWcnt[0], (sizeof (uint64_t) * MAX_TGTPORT_IOCNT)); bzero(&statp->FctP2IORcnt[0], (sizeof (uint64_t) * MAX_TGTPORT_IOCNT)); statp->FctIOCmdCnt = 0; statp->FctReadBytes = 0; statp->FctWriteBytes = 0; statp->FctCmdReceived = 0; } if (hba->state <= FC_LINK_DOWN) { dfcstat->FctLinkState = LNK_DOWN; } #ifdef MENLO_SUPPORT else if (hba->flag & FC_MENLO_MODE) { dfcstat->FctLinkState = LNK_DOWN; } #endif /* MENLO_SUPPORT */ else if (hba->state < FC_READY) { dfcstat->FctLinkState = LNK_DISCOVERY; } else { dfcstat->FctLinkState = LNK_READY; } return (0); } /* emlxs_dfc_get_fctstat() */ #endif /* SFCT_SUPPORT */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port; emlxs_config_t *cfg = &CFG; dfc_node_t *dnp; uint32_t node_count; NODELIST *nlp; uint32_t i; port = &VPORT(dfc->data1); if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < (sizeof (dfc_node_t) * MAX_NODES)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf2_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size); return (DFC_ARG_TOOSMALL); } node_count = port->node_count; if (node_count == 0) { return (0); } dnp = (dfc_node_t *)dfc->buf1; node_count = 0; rw_enter(&port->node_rwlock, RW_READER); for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = port->node_table[i]; while (nlp && nlp->nlp_active && *((uint64_t *)&nlp->nlp_portname)) { dnp->port_id = nlp->nlp_DID; dnp->rpi = nlp->nlp_Rpi; dnp->xri = nlp->nlp_Xri; bcopy((char *)&nlp->sparm, (char *)&dnp->sparm, sizeof (dnp->sparm)); if (nlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE) { dnp->flags |= PORT_FLAG_FCP_TARGET; } if (nlp->nlp_fcp_info & NLP_FCP_INI_DEVICE) { dnp->flags |= PORT_FLAG_FCP_INI; } if (nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { dnp->flags |= PORT_FLAG_FCP2; } if (cfg[CFG_NETWORK_ON].current && nlp->nlp_Xri) { dnp->flags |= PORT_FLAG_IP; } if (nlp->nlp_fcp_info & NLP_EMLX_VPORT) { dnp->flags |= PORT_FLAG_VPORT; } /* Copy our dfc_state */ dnp->flags |= ((nlp->dfc_state & 0xF) << 28); dnp->flags |= PORT_FLAG_DFC_STATE_VALID; dnp++; node_count++; nlp = (NODELIST *) nlp->nlp_list_next; } } rw_exit(&port->node_rwlock); bcopy((void *)&node_count, (void *)dfc->buf2, sizeof (uint32_t)); return (0); } /* emlxs_dfc_get_nodeinfo() */ /*ARGSUSED*/ static int32_t emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t size; uint32_t max_size; uint8_t *slim; offset = dfc->data1; size = dfc->data2; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (size > dfc->buf1_size) { size = dfc->buf1_size; } if (offset % 4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset misaligned. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_MISALIGNED); } if (size % 4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Size misaligned. (size=%d)", emlxs_dfc_xlate(dfc->cmd), size); return (DFC_ARG_MISALIGNED); } if (hba->flag & FC_SLIM2_MODE) { max_size = SLI2_SLIM2_SIZE; } else { max_size = 4096; } if (offset >= max_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset too large. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_TOOBIG); } if ((size + offset) > max_size) { size = (max_size - offset); } if (hba->flag & FC_SLIM2_MODE) { slim = (uint8_t *)hba->sli.sli3.slim2.virt + offset; BE_SWAP32_BCOPY((uint8_t *)slim, (uint8_t *)dfc->buf1, size); } else { slim = (uint8_t *)hba->sli.sli3.slim_addr + offset; READ_SLIM_COPY(hba, (uint32_t *)dfc->buf1, (uint32_t *)slim, (size / 4)); } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_read_mem() */ /*ARGSUSED*/ static int32_t emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t size; uint32_t max_size; uint8_t *slim; offset = dfc->data1; size = dfc->data2; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (size > dfc->buf1_size) { size = dfc->buf1_size; } if (offset % 4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset misaligned. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_MISALIGNED); } if (size % 4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Size misaligned. (szie=%d)", emlxs_dfc_xlate(dfc->cmd), size); return (DFC_ARG_MISALIGNED); } if (hba->flag & FC_SLIM2_MODE) { max_size = SLI2_SLIM2_SIZE; } else { max_size = 4096; } if (offset >= max_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset too large. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_TOOBIG); } if ((size + offset) > max_size) { size = (max_size - offset); } if (hba->flag & FC_SLIM2_MODE) { slim = (uint8_t *)hba->sli.sli3.slim2.virt + offset; BE_SWAP32_BCOPY((uint8_t *)dfc->buf1, (uint8_t *)slim, size); } else { slim = (uint8_t *)hba->sli.sli3.slim_addr + offset; WRITE_SLIM_COPY(hba, (uint32_t *)dfc->buf1, (uint32_t *)slim, (size / 4)); } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_write_mem() */ /* ARGSUSED */ static int32_t emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t value; offset = dfc->data1; value = dfc->data2; if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } if (!(hba->flag & FC_OFFLINE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ONLINE_ERROR); } if (offset % 4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset misaligned. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_MISALIGNED); } if (offset > 255) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset too large. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_TOOBIG); } WRITE_CSR_REG(hba, (hba->sli.sli3.csr_addr + offset), value); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_write_ctlreg() */ /*ARGSUSED*/ static int32_t emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t offset; uint32_t value; offset = dfc->data1; if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } if (offset % 4) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset misaligned. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_MISALIGNED); } if (offset > 255) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Offset too large. (offset=%d)", emlxs_dfc_xlate(dfc->cmd), offset); return (DFC_ARG_TOOBIG); } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } value = READ_CSR_REG(hba, (hba->sli.sli3.csr_addr + offset)); bcopy((void *)&value, (void *)dfc->buf1, sizeof (uint32_t)); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); return (DFC_DRV_ERROR); } #endif /* FMA_SUPPORT */ return (0); } /* emlxs_dfc_read_ctlreg() */ /*ARGSUSED*/ static int32_t emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t event; uint32_t enable; uint32_t pid; uint32_t count; uint32_t i; emlxs_dfc_event_t *dfc_event; event = dfc->data1; pid = dfc->data2; enable = dfc->flag; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: %s. pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, enable); switch (event) { case FC_REG_LINK_EVENT: case FC_REG_RSCN_EVENT: case FC_REG_CT_EVENT: case FC_REG_DUMP_EVENT: case FC_REG_TEMP_EVENT: case FC_REG_VPORTRSCN_EVENT: case FC_REG_FCOE_EVENT: break; case FC_REG_MULTIPULSE_EVENT: default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s. Invalid event. pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, enable); return (DFC_ARG_INVALID); } if (enable) { if (dfc->buf1_size < sizeof (uint32_t)) { dfc->buf1 = NULL; } else if (!dfc->buf1) { dfc->buf1_size = 0; } /* Make sure this pid/event is not already registered */ dfc_event = NULL; for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &hba->dfc_event[i]; if (dfc_event->pid == pid && dfc_event->event == event) { break; } } if (i == MAX_DFC_EVENTS) { /* Find next available event object */ for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &hba->dfc_event[i]; if (!dfc_event->pid && !dfc_event->event) { break; } } /* Return if all event objects are busy */ if (i == MAX_DFC_EVENTS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s. Too many events registered. " "pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, enable); return (DFC_DRVRES_ERROR); } } /* Initialize */ dfc_event->pid = pid; dfc_event->event = event; dfc_event->last_id = (uint32_t)-1; dfc_event->dataout = NULL; dfc_event->size = 0; dfc_event->mode = 0; emlxs_get_dfc_event(port, dfc_event, 0); if (dfc->buf1) { bcopy((void *)&dfc_event->last_id, dfc->buf1, sizeof (uint32_t)); } /* * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, * "%s: %s. Enabled. pid=%d id=%d", emlxs_dfc_xlate(dfc->cmd), * emlxs_dfc_event_xlate(event), pid, dfc_event->last_id); */ hba->event_mask |= event; } else { /* Disable */ /* Find the event entry */ dfc_event = NULL; for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &hba->dfc_event[i]; if (dfc_event->pid == pid && dfc_event->event == event) { break; } } if (i == MAX_DFC_EVENTS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s. Event not registered. pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, enable); return (DFC_ARG_INVALID); } /* Kill the event thread if it is sleeping */ (void) emlxs_kill_dfc_event(port, dfc_event); /* Count the number of pids still registered for this event */ count = 0; for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &hba->dfc_event[i]; if (dfc_event->event == event) { count++; } } /* If no more pids need this event, */ /* then disable logging for this event */ if (count == 0) { hba->event_mask &= ~event; } } return (0); } /* emlxs_dfc_set_event() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t size; int32_t rval = 0; HBA_EVENTINFO *event_buffer = NULL; uint32_t event_count = 0; uint32_t missed = 0; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } event_count = dfc->buf1_size / sizeof (HBA_EVENTINFO); if (!event_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf2_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size); return (DFC_ARG_TOOSMALL); } if (!dfc->buf3 || !dfc->buf3_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf3_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer3 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size); return (DFC_ARG_TOOSMALL); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s called. max=%d", emlxs_dfc_xlate(dfc->cmd), event_count); size = (event_count * sizeof (HBA_EVENTINFO)); event_buffer = (HBA_EVENTINFO *)kmem_zalloc(size, KM_SLEEP); if (emlxs_get_dfc_eventinfo(port, event_buffer, &event_count, &missed) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: get_dfc_eventinfo failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } if (event_count) { bcopy((void *)event_buffer, dfc->buf1, (event_count * sizeof (HBA_EVENTINFO))); } bcopy((void *)&event_count, dfc->buf2, sizeof (uint32_t)); bcopy((void *)&missed, dfc->buf3, sizeof (uint32_t)); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: events=%d missed=%d new=%d last_id=%d", emlxs_dfc_xlate(dfc->cmd), event_count, hba->hba_event.missed, hba->hba_event.new, hba->hba_event.last_id); done: if (event_buffer) { kmem_free(event_buffer, size); } return (rval); } /* emlxs_dfc_get_eventinfo() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t event; uint32_t pid; uint32_t sleep; uint32_t i; int32_t rval = DFC_SUCCESS; emlxs_dfc_event_t *dfc_event; event = dfc->data1; pid = dfc->data2; if (!dfc->buf1_size) { dfc->buf1 = NULL; } else if (!dfc->buf1) { dfc->buf1_size = 0; } if (dfc->buf2_size < sizeof (uint32_t)) { dfc->buf2 = NULL; } else if (!dfc->buf2) { dfc->buf2_size = 0; } if (dfc->buf3_size < sizeof (uint32_t)) { dfc->buf3 = NULL; } else if (!dfc->buf3) { dfc->buf3_size = 0; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: %s. pid=%d size=%d,%p rcv_size=%d,%p id=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, dfc->buf1_size, dfc->buf1, dfc->buf2_size, dfc->buf2, dfc->data3); /* Find the event entry */ dfc_event = NULL; for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &hba->dfc_event[i]; if (dfc_event->pid == pid && dfc_event->event == event) { break; } } if (i == MAX_DFC_EVENTS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s. Event not registered. pid=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid); return (DFC_ARG_INVALID); } if (!(hba->event_mask & dfc_event->event)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s. Event not registered. pid=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid); return (DFC_ARG_INVALID); } /* Initialize event buffer pointers */ dfc_event->dataout = dfc->buf1; dfc_event->size = dfc->buf1_size; dfc_event->last_id = dfc->data3; dfc_event->mode = mode; sleep = (dfc->flag & 0x01) ? 1 : 0; emlxs_get_dfc_event(port, dfc_event, sleep); if (dfc->buf2) { bcopy((void *)&dfc_event->size, dfc->buf2, sizeof (uint32_t)); } if (dfc->buf3) { bcopy((void *)&dfc_event->last_id, dfc->buf3, sizeof (uint32_t)); } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: %s. Completed. pid=%d rsize=%d id=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, dfc_event->size, dfc_event->last_id); return (rval); } /* emlxs_dfc_get_event() */ extern uint32_t emlxs_get_dump_region(emlxs_hba_t *hba, uint32_t region, uint8_t *buffer, uint32_t *psize) { emlxs_port_t *port = &PPORT; uint32_t size; uint32_t size_only; uint32_t rval = 0; uint8_t *memptr; uint32_t *wptr; if (!buffer || !(*psize)) { size_only = 1; size = 0xffffffff; } else { size_only = 0; size = *psize; } if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { if (region != 7) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Invalid sli4 region. " "(id=%d)", region); rval = DFC_ARG_INVALID; goto done; } } switch (region) { case 0: /* SLI Registers */ if (size < (4 * sizeof (uint32_t))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(SLI Registers: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = (4 * sizeof (uint32_t)); if (size_only) { break; } wptr = (uint32_t *)buffer; wptr[0] = READ_CSR_REG(hba, FC_HA_REG(hba)); wptr[1] = READ_CSR_REG(hba, FC_CA_REG(hba)); wptr[2] = READ_CSR_REG(hba, FC_HS_REG(hba)); wptr[3] = READ_CSR_REG(hba, FC_HC_REG(hba)); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); rval = DFC_DRV_ERROR; } #endif /* FMA_SUPPORT */ break; case 1: /* SLIM */ if (hba->flag & FC_SLIM2_MODE) { size = MIN(SLI2_SLIM2_SIZE, size); } else { size = MIN(4096, size); } if (size_only) { break; } if (hba->flag & FC_SLIM2_MODE) { memptr = (uint8_t *)hba->sli.sli3.slim2.virt; BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size); } else { memptr = (uint8_t *)hba->sli.sli3.slim_addr; READ_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)memptr, (size / 4)); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); rval = DFC_DRV_ERROR; } #endif /* FMA_SUPPORT */ } break; case 2: /* Port Control Block */ if (size < sizeof (PCB)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(PCB: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = sizeof (PCB); if (size_only) { break; } memptr = (uint8_t *)&(((SLIM2 *)hba->sli.sli3.slim2.virt)->pcb); BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size); break; case 3: /* MailBox */ if (size < MAILBOX_CMD_BSIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(Mailbox: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = MAILBOX_CMD_BSIZE; if (size_only) { break; } if (hba->flag & FC_SLIM2_MODE) { memptr = (uint8_t *)hba->sli.sli3.slim2.virt; BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size); } else { memptr = (uint8_t *)hba->sli.sli3.slim_addr; READ_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)memptr, (size / 4)); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); rval = DFC_DRV_ERROR; } #endif /* FMA_SUPPORT */ } break; case 4: /* Host Put/Get pointer array */ if (size < MAX_RINGS * sizeof (HGP)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(HGP: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = MAX_RINGS * sizeof (HGP); if (size_only) { break; } { memptr = (uint8_t *)hba->sli.sli3.slim_addr + hba->sli.sli3.hgp_ring_offset; READ_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)memptr, (size / 4)); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_access_handle_msg, NULL); rval = DFC_DRV_ERROR; } #endif /* FMA_SUPPORT */ } break; case 5: /* Port Get/Put pointer array */ if (size < MAX_RINGS * sizeof (PGP)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(PGP: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = MAX_RINGS * sizeof (PGP); if (size_only) { break; } memptr = (uint8_t *) ((SLIM2 *)hba->sli.sli3.slim2.virt)->mbx.us.s2.port; BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size); break; case 6: /* Command/Response Ring */ if (size < SLI_IOCB_MAX_SIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(Rings: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = SLI_IOCB_MAX_SIZE; if (size_only) { break; } memptr = (uint8_t *)((SLIM2 *)hba->sli.sli3.slim2.virt)->IOCBs; BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size); break; case 7: /* All driver specific structures */ if (size < sizeof (emlxs_hba_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Buffer too small. " "(Driver: size=%d)", size); rval = DFC_ARG_TOOSMALL; goto done; } size = sizeof (emlxs_hba_t); if (size_only) { break; } memptr = (uint8_t *)hba; bcopy((void *)memptr, (void *)buffer, size); break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "get_dump_region: Invalid region. (id=%d)", region); rval = DFC_ARG_INVALID; } done: *psize = size; return (rval); } /* emlxs_get_dump_region() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t size; uint32_t size_only = 0; uint32_t rval = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: region=%d size=%d", emlxs_dfc_xlate(dfc->cmd), dfc->data1, dfc->buf1_size); if (!dfc->buf1 || !dfc->buf1_size) { size_only = 1; } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf2_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size); return (DFC_ARG_TOOSMALL); } /* First get region size only */ size = 0; rval = emlxs_get_dump_region(hba, dfc->data1, NULL, &size); if (rval != 0) { goto done; } if (!size_only) { if (dfc->buf1_size < size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size: %d < %d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size, size); rval = DFC_ARG_TOOSMALL; goto done; } /* Get the region data */ rval = emlxs_get_dump_region(hba, dfc->data1, dfc->buf1, &size); if (rval != 0) { goto done; } } /* Return the region size */ bcopy((void *) &size, (void *) dfc->buf2, sizeof (uint32_t)); done: return (rval); } /* emlxs_dfc_get_dump_region() */ #ifdef MENLO_SUPPORT /*ARGSUSED*/ static int32_t emlxs_dfc_menlo_port_offset(emlxs_hba_t *hba) { uint32_t cnt; char pathname[256]; (void) ddi_pathname(hba->dip, pathname); cnt = strlen(pathname); if ((cnt < 4) || (strcmp(&pathname[cnt-3], "0,1") != 0)) return (0); return (1); } /*ARGSUSED*/ static int32_t emlxs_dfc_set_menlo_loopback(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; MAILBOXQ *mbq = NULL; MAILBOX *mb = NULL; fc_packet_t *pkt = NULL; uint32_t mbxstatus; uint32_t i; uint32_t offset; uint32_t rval = 0; menlo_cmd_t *cmd; mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *)mbq; /* SET MENLO maint mode */ /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mbq, 0x103107, 1); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus); rval = DFC_IO_ERROR; if (mbxstatus == MBX_TIMEOUT) rval = DFC_TIMEOUT; goto done; } /* Wait 30 sec for maint mode */ i = 0; do { if (i++ > 300) { break; } delay(drv_usectohz(100000)); } while (!(hba->flag & FC_MENLO_MODE)); if (!(hba->flag & FC_MENLO_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to enter maint mode.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_DRV_ERROR; goto done; } offset = emlxs_dfc_menlo_port_offset(hba); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Entered maint mode. Port offset: %d", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), offset); /* Issue Menlo loopback command */ if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t), sizeof (uint32_t), 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; cmd = (menlo_cmd_t *)pkt->pkt_cmd; cmd->code = BE_SWAP32(MENLO_CMD_LOOPBACK); cmd->lb.context = BE_SWAP32(offset); cmd->lb.type = BE_SWAP32(MENLO_LOOPBACK_ENABLE); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to send packet.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. Pkt Timeout.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_TIMEOUT; } else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) && (pkt->pkt_reason == FC_REASON_OVERRUN)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. Rsp overrun.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_RSP_BUF_OVERRUN; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. state=%x", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } /* CLEAR MENLO maint mode */ /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mbq, 0x103107, 0); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus); rval = DFC_IO_ERROR; if (mbxstatus == MBX_TIMEOUT) rval = DFC_TIMEOUT; } delay(drv_usectohz(1000000)); i = 0; while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) { delay(drv_usectohz(100000)); i++; if (i == 300) { rval = DFC_TIMEOUT; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Linkup timeout.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); goto done; } } done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /*ARGSUSED*/ static int32_t emlxs_dfc_set_menlo_fte(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; fc_packet_t *pkt = NULL; uint32_t rval = 0; menlo_cmd_t *cmd; /* Issue Menlo loopback command */ if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t), sizeof (uint32_t), 0, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_SYSRES_ERROR; goto done; } /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_tran_type = FC_PKT_EXCHANGE; pkt->pkt_timeout = 30; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE; pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; cmd = (menlo_cmd_t *)pkt->pkt_cmd; cmd->code = BE_SWAP32(MENLO_CMD_FTE_INSERT); cmd->fte_insert.fcid = BE_SWAP32(0); bcopy((caddr_t)&port->wwpn, (caddr_t)cmd->fte_insert.wwpn, 8); if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to send packet.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. Pkt Timeout.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_TIMEOUT; } else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) && (pkt->pkt_reason == FC_REASON_OVERRUN)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. Rsp overrun.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_RSP_BUF_OVERRUN; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Pkt Transport error. state=%x", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /*ARGSUSED*/ static int32_t emlxs_dfc_reset_menlo(emlxs_hba_t *hba) { emlxs_port_t *port = &PPORT; MAILBOXQ *mbq = NULL; MAILBOX *mb = NULL; uint32_t mbxstatus; uint32_t rval = 0; mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *)mbq; /* RESET MENLO */ /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mbq, 0x103007, 0); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus); rval = DFC_IO_ERROR; if (mbxstatus == MBX_TIMEOUT) rval = DFC_TIMEOUT; goto done; } done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } #endif /* MENLO_SUPPORT */ /* ARGSUSED */ static int32_t emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_config_t *cfg = &CFG; MAILBOXQ *mbq = NULL; MAILBOX *mb = NULL; uint32_t rval = DFC_SUCCESS; uint32_t i; uint32_t timeout; uint32_t topology; uint32_t speed; uint32_t new_mode; NODELIST *ndlp; XRIobj_t *xrip; if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } /* Reinitialize the link */ switch (dfc->flag) { case 0: /* Disable */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Disabling Loopback.", emlxs_dfc_xlate(dfc->cmd)); if (!(hba->flag & FC_LOOPBACK_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Loopback already disabled.", emlxs_dfc_xlate(dfc->cmd)); return (rval); } goto resetdone; case 1: /* Internal loopback */ new_mode = FC_ILB_MODE; topology = FLAGS_LOCAL_LB; speed = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Enabling ILB.", emlxs_dfc_xlate(dfc->cmd)); /* Check if mode already set */ if ((hba->flag & FC_ILB_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: ILB mode already enabled.", emlxs_dfc_xlate(dfc->cmd)); return (rval); } break; case 2: /* External loopback */ new_mode = FC_ELB_MODE; if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { topology = FLAGS_TOPOLOGY_MODE_LOOP_PT; } else { topology = FLAGS_TOPOLOGY_MODE_LOOP; } speed = cfg[CFG_LINK_SPEED].current; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Enabling ELB.", emlxs_dfc_xlate(dfc->cmd)); /* Check if mode already set */ if ((hba->flag & FC_ELB_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: ELB mode already enabled.", emlxs_dfc_xlate(dfc->cmd)); return (rval); } break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid loopback mode. (mode=%x)", emlxs_dfc_xlate(dfc->cmd), dfc->flag); return (DFC_ARG_INVALID); } /* Make sure adapter is online */ if (emlxs_online(hba)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to bring adapter online.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_OFFLINE_ERROR); } #ifdef MENLO_SUPPORT if (hba->model_info.vendor_id == PCI_VENDOR_ID_EMULEX && hba->model_info.device_id == PCI_DEVICE_ID_HORNET) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Menlo support detected: mode:x%x", emlxs_dfc_xlate(dfc->cmd), new_mode); if (new_mode == FC_ILB_MODE) { rval = emlxs_dfc_set_menlo_loopback(hba); if (rval) goto done; } } #endif /* MENLO_SUPPORT */ mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX *) mbq; /* Take the link down */ emlxs_mb_down_link(hba, mbq); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval == MBX_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Mailbox timed out. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_TIMEOUT; goto done; } if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_IO_ERROR; goto done; } /* * Need *2 since we wait 1/2 sec in while loop. */ timeout = dfc->data1; if (!timeout) { timeout = 60 * 2; } else { timeout = timeout * 2; } i = 0; while ((hba->state >= FC_LINK_UP) && (hba->state != FC_ERROR)) { delay(drv_usectohz(500000)); i++; if (i == timeout) { rval = DFC_TIMEOUT; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Linkdown timeout.", emlxs_dfc_xlate(dfc->cmd)); goto done; } } /* Reinitialize the link */ emlxs_mb_init_link(hba, mbq, topology, speed); /* Set the loopback mode and timer */ mutex_enter(&EMLXS_PORT_LOCK); hba->flag |= new_mode; hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo; mutex_exit(&EMLXS_PORT_LOCK); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval == MBX_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Mailbox timed out. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_TIMEOUT; goto done; } if (rval) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_IO_ERROR; goto done; } i = 0; while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) { delay(drv_usectohz(500000)); i++; if (i == timeout) { rval = DFC_TIMEOUT; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Linkup timeout.", emlxs_dfc_xlate(dfc->cmd)); goto done; } } /* Create host node */ if (EMLXS_SLI_REG_DID(port, port->did, (SERV_PARM *)&hba->sparam, NULL, NULL, NULL)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to register host node.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } i = 0; do { if (i++ > 300) { break; } delay(drv_usectohz(100000)); } while (!(ndlp = emlxs_node_find_did(port, port->did, 1))); if (!ndlp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to create host node.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Node created. node=%p", emlxs_dfc_xlate(dfc->cmd), ndlp); #ifdef MENLO_SUPPORT if (hba->model_info.vendor_id == PCI_VENDOR_ID_EMULEX && hba->model_info.device_id == PCI_DEVICE_ID_HORNET) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Menlo support detected: mode:x%x", emlxs_dfc_xlate(dfc->cmd), new_mode); rval = emlxs_dfc_set_menlo_fte(hba); if (rval) goto done; } #endif /* MENLO_SUPPORT */ if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) { /* Create host XRI */ (void) emlxs_create_xri(port, &hba->chan[hba->channel_ct], ndlp); i = 0; do { if (i++ > 300) { break; } delay(drv_usectohz(100000)); } while (!ndlp->nlp_Xri); if (!ndlp->nlp_Xri) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to create XRI.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: XRI created. xri=%d", emlxs_dfc_xlate(dfc->cmd), ndlp->nlp_Xri); } else { xrip = emlxs_sli4_reserve_xri(port, EMLXS_NODE_TO_RPI(port, ndlp), EMLXS_XRI_SOL_CT_TYPE, 0xffff); if (xrip == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to reserve XRI.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } ndlp->nlp_Xri = xrip->XRI; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: XRI reserved. xri=%d", emlxs_dfc_xlate(dfc->cmd), ndlp->nlp_Xri); } done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } if (rval) { resetdone: /* Reset the adapter */ #ifdef MENLO_SUPPORT if (hba->model_info.vendor_id == PCI_VENDOR_ID_EMULEX && hba->model_info.device_id == PCI_DEVICE_ID_HORNET) { rval = emlxs_dfc_reset_menlo(hba); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Menlo reset: rval:x%x", emlxs_dfc_xlate(dfc->cmd), rval); } #endif /* MENLO_SUPPORT */ /* Reset link whether we are bound to ULP or not */ (void) emlxs_reset_link(hba, 1, 1); } return (rval); } /* emlxs_dfc_loopback_mode() */ /*ARGSUSED*/ static int32_t emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; int32_t rval = 0; NODELIST *ndlp; clock_t timeout; fc_packet_t *pkt = NULL; SLI_CT_REQUEST *CtCmd; uint16_t CtRsp; if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } mutex_enter(&EMLXS_PORT_LOCK); if (!(hba->flag & FC_LOOPBACK_MODE)) { mutex_exit(&EMLXS_PORT_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Adapter not in loopback mode.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo; mutex_exit(&EMLXS_PORT_LOCK); if (!(hba->flag & FC_ONLINE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Adapter offline.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_OFFLINE_ERROR; goto done; } if (hba->state < FC_LINK_UP) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Link not up.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_OFFLINE_ERROR; goto done; } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } if (dfc->buf1_size > MAX_CT_PAYLOAD) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too large. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); rval = DFC_ARG_TOOBIG; goto done; } /* Check if we have a node for ourselves */ ndlp = emlxs_node_find_did(port, port->did, 1); if (!ndlp) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Host node not found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_INVALID; goto done; } if (!ndlp->nlp_Xri) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Host XRI not found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } pkt = emlxs_pkt_alloc(port, dfc->buf1_size + 16, dfc->buf2_size + 16, 0, KM_SLEEP); if (pkt == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate pkt.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } CtCmd = (SLI_CT_REQUEST*)pkt->pkt_cmd; CtRsp = SLI_CT_LOOPBACK; CtCmd->CommandResponse.bits.CmdRsp = LE_SWAP16(CtRsp); bcopy((void *)dfc->buf1, (void *)&CtCmd->un.data, dfc->buf1_size); pkt->pkt_tran_type = FC_PKT_OUTBOUND; pkt->pkt_timeout = 2 * hba->fc_ratov; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; pkt->pkt_cmd_fhdr.d_id = port->did; pkt->pkt_cmd_fhdr.r_ctl = FC_SOL_CTL; pkt->pkt_cmd_fhdr.s_id = port->did; pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; pkt->pkt_cmd_fhdr.f_ctl = 0; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xffff; pkt->pkt_cmd_fhdr.rx_id = ndlp->nlp_Xri; pkt->pkt_cmd_fhdr.ro = 0; mutex_enter(&EMLXS_PKT_LOCK); timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15)); if (hba->loopback_pkt) { rval = 0; while ((rval != -1) && hba->loopback_pkt) { rval = cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout); } if (rval == -1) { mutex_exit(&EMLXS_PKT_LOCK); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Loopback busy timeout."); rval = DFC_TIMEOUT; goto done; } } hba->loopback_pkt = (void *) pkt; mutex_exit(&EMLXS_PKT_LOCK); /* Send polled command */ if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. ret=%x state=%x", rval, pkt->pkt_state); rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. Pkt Timeout."); rval = DFC_TIMEOUT; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } /* Wait for sequence completion */ mutex_enter(&EMLXS_PKT_LOCK); rval = 0; while ((rval != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) { rval = cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout); } mutex_exit(&EMLXS_PKT_LOCK); if (rval == -1) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Loopback sequence timeout."); rval = DFC_TIMEOUT; goto done; } CtCmd = (SLI_CT_REQUEST*)pkt->pkt_resp; bcopy((void *)&CtCmd->un.data, (void *)dfc->buf2, dfc->buf2_size); rval = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Test completed.", emlxs_dfc_xlate(dfc->cmd)); done: if (rval) { mutex_enter(&EMLXS_PKT_LOCK); if (pkt && (hba->loopback_pkt == pkt)) { hba->loopback_pkt = NULL; } mutex_exit(&EMLXS_PKT_LOCK); /* Reset the adapter */ (void) emlxs_reset(port, FC_FCA_LINK_RESET); } if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_loopback_test() */ /*ARGSUSED*/ static int32_t emlxs_dfc_reset_port(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; int32_t rval = 0; switch (dfc->flag) { case 1: case 2: rval = emlxs_reset(port, FC_FCA_RESET); break; case 3: if ((hba->sli_mode < EMLXS_HBA_SLI4_MODE) || ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && (hba->model_info.chip & EMLXS_BE_CHIPS))) { rval = emlxs_reset(port, FC_FCA_RESET); } else { /* Perform All Firmware Reset */ rval = emlxs_reset(port, EMLXS_DFC_RESET_ALL); } break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid reset type. (mode=%x)", emlxs_dfc_xlate(dfc->cmd), dfc->flag); return (DFC_ARG_INVALID); } if (rval) { rval = DFC_HBA_ERROR; } return (rval); } /* emlxs_dfc_reset_port() */ extern int32_t emlxs_dfc_handle_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq) { emlxs_port_t *port = &PPORT; IOCB *cmd; emlxs_buf_t *sbp; cmd = &iocbq->iocb; HBASTATS.CtEvent++; sbp = (emlxs_buf_t *)iocbq->sbp; if (!sbp) { HBASTATS.CtStray++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Stray interrupt. cmd=0x%x iotag=0x%x status=0x%x " "perr=0x%x", (uint32_t)cmd->ULPCOMMAND, (uint32_t)cmd->ULPIOTAG, cmd->ULPSTATUS, cmd->un.ulpWord[4]); return (DFC_ARG_INVALID); } if (cp->channelno != hba->channel_ct) { HBASTATS.CtStray++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "CT Event: Invalid IO Channel:%d iocbq=%p", cp->channelno, iocbq); return (DFC_ARG_INVALID); } switch (cmd->ULPCOMMAND) { case CMD_XMIT_SEQUENCE_CR: case CMD_XMIT_SEQUENCE64_CR: case CMD_XMIT_SEQUENCE_CX: case CMD_XMIT_SEQUENCE64_CX: HBASTATS.CtCmdCompleted++; if (cmd->ULPSTATUS == 0) { HBASTATS.CtCmdGood++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "XMIT_SEQUENCE comp: status=0x%x", cmd->ULPSTATUS); } else { HBASTATS.CtCmdError++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "XMIT_SEQUENCE comp: status=0x%x [%08x,%08x]", cmd->ULPSTATUS, cmd->un.ulpWord[4], cmd->un.ulpWord[5]); } emlxs_pkt_complete(sbp, cmd->ULPSTATUS, cmd->un.grsp.perr.statLocalError, 1); break; default: HBASTATS.CtStray++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Invalid iocb: cmd=0x%x", cmd->ULPCOMMAND); emlxs_pkt_complete(sbp, cmd->ULPSTATUS, cmd->un.grsp.perr.statLocalError, 1); break; } /* switch(cmd->ULPCOMMAND) */ return (0); } /* emlxs_dfc_handle_event() */ /* ARGSUSED */ extern int emlxs_dfc_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size) { emlxs_hba_t *hba = HBA; IOCB *iocb; uint8_t *bp; fc_packet_t *pkt; iocb = &iocbq->iocb; bp = (uint8_t *)mp->virt; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "CT Receive: cmd=%x status=0x%x ", iocb->ULPCOMMAND, iocb->ULPSTATUS); if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { /* * No response sent on loopback; free the exchange now */ emlxs_abort_ct_exchange(hba, port, iocb->ULPCONTEXT); } /* * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, * "CT Receive: payload=%p size=%d [%02x,%02x, %02x, %02x]", bp, * size, bp[0], bp[1], bp[2],bp[3]); */ /* Return payload */ mutex_enter(&EMLXS_PKT_LOCK); if (hba->loopback_pkt) { pkt = (fc_packet_t *)hba->loopback_pkt; hba->loopback_pkt = NULL; size = MIN(size, pkt->pkt_rsplen); bcopy(bp, pkt->pkt_resp, size); pkt->pkt_tran_flags |= FC_TRAN_COMPLETED; cv_broadcast(&EMLXS_PKT_CV); } mutex_exit(&EMLXS_PKT_LOCK); return (0); } /* emlxs_dfc_handle_unsol_req() */ #ifdef DHCHAP_SUPPORT /*ARGSUSED*/ static int32_t emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint8_t *lwwpn; uint8_t *rwwpn; int32_t rval = 0; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < 8) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf2_size < 8) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } lwwpn = (uint8_t *)dfc->buf1; rwwpn = (uint8_t *)dfc->buf2; /* Initiate authentication here */ rval = emlxs_dhc_init_auth(hba, lwwpn, rwwpn); return (rval); } /* emlxs_dfc_init_auth() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_fcsp_config_t *fcsp_config; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } fcsp_config = (dfc_fcsp_config_t *)dfc->buf1; if ((rval = emlxs_dhc_get_auth_cfg(hba, fcsp_config)) != 0) { return (rval); } return (0); } /* emlxs_dfc_get_auth_cfg() */ /*ARGSUSED*/ static int32_t emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_fcsp_config_t *fcsp_config; dfc_password_t *dfc_pwd; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf2_size < sizeof (dfc_password_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } fcsp_config = (dfc_fcsp_config_t *)dfc->buf1; dfc_pwd = (dfc_password_t *)dfc->buf2; switch (dfc->flag) { case EMLXS_AUTH_CFG_ADD: rval = emlxs_dhc_add_auth_cfg(hba, fcsp_config, dfc_pwd); break; case EMLXS_AUTH_CFG_DELETE: rval = emlxs_dhc_delete_auth_cfg(hba, fcsp_config, dfc_pwd); break; } if (rval) { return (rval); } return (0); } /* emlxs_dfc_set_auth_cfg() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_auth_password_t *dfc_pwd; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_auth_password_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } /* Read the auth password */ dfc_pwd = (dfc_auth_password_t *)dfc->buf1; if ((rval = emlxs_dhc_get_auth_key(hba, dfc_pwd)) != 0) { return (rval); } return (0); } /* emlxs_dfc_get_auth_pwd() */ /*ARGSUSED*/ static int32_t emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_auth_password_t *dfc_pwd; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_auth_password_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } dfc_pwd = (dfc_auth_password_t *)dfc->buf1; if ((rval = emlxs_dhc_set_auth_key(hba, dfc_pwd))) { return (rval); } return (0); } /* emlxs_dfc_set_auth_pwd() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_auth_status_t *fcsp_status; uint32_t rval = DFC_SUCCESS; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (dfc_auth_status_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } fcsp_status = (dfc_auth_status_t *)dfc->buf1; if ((rval = emlxs_dhc_get_auth_status(hba, fcsp_status)) != 0) { return (rval); } return (0); } /* emlxs_dfc_get_auth_status() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t count; uint32_t rval = DFC_SUCCESS; /* Lock cfg table while we do this */ /* This prevents the table from changing while we get a copy */ mutex_enter(&hba->auth_lock); if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); mutex_exit(&hba->auth_lock); return (DFC_ARG_NULL); } if (dfc->buf2_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size); mutex_exit(&hba->auth_lock); return (DFC_ARG_TOOSMALL); } bcopy((void *)&hba->auth_cfg_count, (void *)dfc->buf2, sizeof (uint32_t)); if (!dfc->buf1 || !dfc->buf1_size) { mutex_exit(&hba->auth_lock); return (DFC_SUCCESS); } /* Check table size */ count = dfc->buf1_size / sizeof (dfc_fcsp_config_t); if (count < hba->auth_cfg_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)", emlxs_dfc_xlate(dfc->cmd), count, hba->auth_cfg_count); mutex_exit(&hba->auth_lock); return (DFC_ARG_TOOSMALL); } rval = emlxs_dhc_get_auth_cfg_table(hba, (dfc_fcsp_config_t *)dfc->buf1); mutex_exit(&hba->auth_lock); return (rval); } /* emlxs_dfc_get_auth_cfg_table() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t count; uint32_t rval = DFC_SUCCESS; /* Lock cfg table while we do this */ /* This prevents the table from changing while we get a copy */ mutex_enter(&hba->auth_lock); if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); mutex_exit(&hba->auth_lock); return (DFC_ARG_NULL); } if (dfc->buf2_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size); mutex_exit(&hba->auth_lock); return (DFC_ARG_TOOSMALL); } bcopy((void *)&hba->auth_key_count, (void *)dfc->buf2, sizeof (uint32_t)); if (!dfc->buf1 || !dfc->buf1_size) { mutex_exit(&hba->auth_lock); return (DFC_SUCCESS); } /* Check table size */ count = dfc->buf1_size / sizeof (dfc_auth_password_t); if (count < hba->auth_key_count) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)", emlxs_dfc_xlate(dfc->cmd), count, hba->auth_key_count); mutex_exit(&hba->auth_lock); return (DFC_ARG_TOOSMALL); } rval = emlxs_dhc_get_auth_key_table(hba, (dfc_auth_password_t *)dfc->buf1); mutex_exit(&hba->auth_lock); return (rval); } /* emlxs_dfc_get_auth_key_table() */ #endif /* DHCHAP_SUPPORT */ #ifdef SAN_DIAG_SUPPORT /*ARGSUSED*/ static int32_t emlxs_dfc_sd_set_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { uint32_t type, search_type; uint16_t state; int32_t rval = DFC_SD_OK; type = dfc->data1; search_type = dfc->data2; mutex_enter(&emlxs_sd_bucket_mutex); state = emlxs_sd_bucket.state; if (state == SD_COLLECTING) rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE; else if ((search_type < SD_SEARCH_LINEAR) || (search_type > SD_SEARCH_POWER_2)) rval = DFC_SD_ERROR_INVALID_ARG; else if (type != SD_SCSI_IO_LATENCY_TYPE) rval = DFC_SD_ERROR_NOT_SUPPORTED; else { bcopy(dfc->buf3, (void *) &emlxs_sd_bucket, sizeof (sd_bucket_info_t)); emlxs_sd_bucket.state = SD_STOPPED; } mutex_exit(&emlxs_sd_bucket_mutex); return (rval); } /*ARGSUSED*/ static int32_t emlxs_dfc_sd_destroy_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { uint32_t type; int32_t rval = DFC_SD_OK; type = dfc->data1; mutex_enter(&emlxs_sd_bucket_mutex); if (emlxs_sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; } else if (emlxs_sd_bucket.state == SD_COLLECTING) { rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE; } else if (type != SD_SCSI_IO_LATENCY_TYPE) { rval = DFC_SD_ERROR_NOT_SUPPORTED; } else { bzero((uint8_t *)&emlxs_sd_bucket, sizeof (sd_bucket_info_t)); } mutex_exit(&emlxs_sd_bucket_mutex); return (rval); } /* emlxs_dfc_sd_destroy_bucket() */ /*ARGSUSED*/ static int32_t emlxs_dfc_sd_get_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { uint32_t type; int32_t rval = DFC_SD_OK; type = dfc->data1; mutex_enter(&emlxs_sd_bucket_mutex); if (emlxs_sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; } else if (type != SD_SCSI_IO_LATENCY_TYPE) { rval = DFC_SD_ERROR_NOT_SUPPORTED; } else { bcopy(&emlxs_sd_bucket, dfc->buf3, sizeof (sd_bucket_info_t)); } mutex_exit(&emlxs_sd_bucket_mutex); return (rval); } /* emlxs_dfc_sd_get_bucket() */ /*ARGSUSED*/ static int32_t emlxs_dfc_sd_start_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *vport; NODELIST *nlp; uint8_t wwpn[8]; int32_t rval = DFC_SD_OK; int i; if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) { rval = DFC_SD_ERROR_NOT_SUPPORTED; goto start_collect_exit; } if (emlxs_sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto start_collect_exit; } /* Read the wwn object */ bcopy((void *)dfc->buf3, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); if (!vport) { rval = DFC_SD_ERROR_INVALID_PORT; goto start_collect_exit; } /* traverse list of nodes for this vport and reset counter */ rw_enter(&vport->node_rwlock, RW_READER); if (vport->sd_io_latency_state == SD_COLLECTING) { rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE; rw_exit(&vport->node_rwlock); goto start_collect_exit; } for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = vport->node_table[i]; while (nlp != NULL) { bzero((void *)&nlp->sd_dev_bucket[0], sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS); nlp = nlp->nlp_list_next; } } vport->sd_io_latency_state = SD_COLLECTING; rw_exit(&vport->node_rwlock); mutex_enter(&emlxs_sd_bucket_mutex); emlxs_sd_bucket.state = SD_COLLECTING; mutex_exit(&emlxs_sd_bucket_mutex); start_collect_exit: return (rval); } /*ARGSUSED*/ static int32_t emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *vport; emlxs_hba_t *temp_hba; uint8_t wwpn[8]; int32_t rval = DFC_SD_OK; int i, j; if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) { rval = DFC_SD_ERROR_NOT_SUPPORTED; goto stop_collect_exit; } if (emlxs_sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto stop_collect_exit; } /* Read the wwn object */ bcopy((void *)dfc->buf3, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); if (!vport) { rval = DFC_SD_ERROR_INVALID_PORT; goto stop_collect_exit; } rw_enter(&vport->node_rwlock, RW_READER); if (vport->sd_io_latency_state != SD_COLLECTING) { rval = DFC_SD_ERROR_DATA_COLLECTION_NOT_ACTIVE; rw_exit(&vport->node_rwlock); goto stop_collect_exit; } vport->sd_io_latency_state = SD_STOPPED; rw_exit(&vport->node_rwlock); /* see if any other port is collecting io latency */ for (i = 0; i < emlxs_device.hba_count; i++) { temp_hba = emlxs_device.hba[i]; for (j = 0; j < temp_hba->num_of_ports; j++) { vport = &temp_hba->port[j]; if (vport->sd_io_latency_state == SD_COLLECTING) goto stop_collect_exit; } } /* * if we get here, that means no one else is collecting * io latency data. */ mutex_enter(&emlxs_sd_bucket_mutex); emlxs_sd_bucket.state = SD_STOPPED; mutex_exit(&emlxs_sd_bucket_mutex); stop_collect_exit: return (rval); } /*ARGSUSED*/ static int32_t emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *vport; NODELIST *nlp; uint8_t wwpn[8]; int32_t rval = DFC_SD_OK; int i; if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) { rval = DFC_SD_ERROR_NOT_SUPPORTED; goto reset_collect_exit; } if (emlxs_sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto reset_collect_exit; } /* Read the wwn object */ bcopy((void *)dfc->buf3, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); if (!vport) { rval = DFC_SD_ERROR_INVALID_PORT; goto reset_collect_exit; } /* traverse list of nodes for this vport and reset counter */ rw_enter(&vport->node_rwlock, RW_READER); for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = vport->node_table[i]; while (nlp != NULL) { bzero((void *)&nlp->sd_dev_bucket[0], sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS); nlp = nlp->nlp_list_next; } } rw_exit(&vport->node_rwlock); reset_collect_exit: return (rval); } /*ARGSUSED*/ static int32_t emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *vport; uint8_t wwpn[8]; int i, skip_bytes; uint16_t count; uint32_t bufsize, size_needed; NODELIST *nlp; int32_t rval = DFC_SD_OK; if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) { rval = DFC_SD_ERROR_NOT_SUPPORTED; goto get_data_exit; } if (emlxs_sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto get_data_exit; } /* Read the wwn object */ bcopy((void *)dfc->buf3, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); if (!vport) { rval = DFC_SD_ERROR_INVALID_PORT; goto get_data_exit; } bufsize = dfc->buf4_size; /* * count # of targets to see if buffer is big enough */ count = 0; rw_enter(&vport->node_rwlock, RW_READER); for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = vport->node_table[i]; while (nlp != NULL) { count++; nlp = nlp->nlp_list_next; } } rw_exit(&vport->node_rwlock); size_needed = count * (sizeof (HBA_WWN) + sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS); if (bufsize < size_needed) { rval = DFC_SD_ERROR_MORE_DATA_AVAIL; goto update_count; /* not enough space, return */ } /* * return data collected, reset counter. */ count = 0; skip_bytes = 0; rw_enter(&vport->node_rwlock, RW_READER); for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = vport->node_table[i]; while (nlp != NULL) { /* copy port name */ bcopy((void *)&nlp->nlp_portname, (void *)((char *)dfc->buf4 + skip_bytes), sizeof (HBA_WWN)); skip_bytes += sizeof (HBA_WWN); /* copy bucket data */ bcopy((void *)&nlp->sd_dev_bucket[0], (void *)((char *)dfc->buf4 + skip_bytes), sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS); skip_bytes += sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS; bzero((void *)&nlp->sd_dev_bucket[0], sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS); count++; bufsize -= sizeof (struct SD_IO_Latency_Response); nlp = nlp->nlp_list_next; } } rw_exit(&vport->node_rwlock); update_count: bcopy((void *)&count, (void *)dfc->buf2, sizeof (uint16_t)); get_data_exit: return (rval); } /* emlxs_dfc_sd_get_data() */ /*ARGSUSED*/ static int32_t emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *vport; uint8_t wwpn[8]; uint32_t event, pid, enable; int32_t rval = DFC_SD_OK; int i, count; emlxs_dfc_event_t *dfc_event; /* * The value of "event" has been shifted left based on * the category that the application gave to libdfc. * * This is so the old Event handling code won't mistakenly * grab an SD Event. */ event = dfc->data1; pid = dfc->data3; enable = dfc->flag; /* Read the wwn object */ bcopy((void *)dfc->buf3, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); if (!vport) { rval = DFC_SD_ERROR_INVALID_PORT; goto set_sd_event_exit; } if (enable) { /* Find next available event object */ for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &vport->sd_events[i]; if (!dfc_event->pid && !dfc_event->event) break; } /* Return if all event objects are busy */ if (i == MAX_DFC_EVENTS) { rval = DFC_SD_ERROR_OUT_OF_HANDLES; goto set_sd_event_exit; } /* Initialize */ /* TODO: Should we add SUBCAT in dfc_event ??? */ dfc_event->pid = pid; dfc_event->event = event; dfc_event->last_id = (uint32_t)-1; dfc_event->dataout = NULL; dfc_event->size = 0; dfc_event->mode = 0; emlxs_get_sd_event(vport, dfc_event, 0); if (dfc->buf1) { bcopy((void *) &dfc_event->last_id, dfc->buf1, sizeof (uint32_t)); } vport->sd_event_mask |= event; } else { /* Disable */ /* find event entry */ for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &vport->sd_events[i]; if (dfc_event->pid == pid && dfc_event->event == event) break; } /* Return if not found */ if (i == MAX_DFC_EVENTS) { rval = DFC_SD_ERROR_INVALID_ARG; goto set_sd_event_exit; } /* Kill the event thread if it is sleeping */ (void) emlxs_kill_dfc_event(vport, dfc_event); /* Count the number of pids still registered for this event */ count = 0; for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &vport->sd_events[i]; if (dfc_event->event == event) count++; } /* * If no more pids need this event, * then disable logging for this event */ if (count == 0) vport->sd_event_mask &= ~event; } set_sd_event_exit: return (rval); } /* emlxs_dfc_sd_set_event */ /*ARGSUSED*/ static int32_t emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *vport; uint8_t wwpn[8]; uint32_t event, pid, sleep, i; int32_t rval = DFC_SD_OK; emlxs_dfc_event_t *dfc_event; event = dfc->data1; pid = dfc->data2; /* Read the wwn object */ bcopy((void *)dfc->buf4, (void *)wwpn, 8); /* Make sure WWPN is unique */ vport = emlxs_vport_find_wwpn(hba, wwpn); if (!vport) { rval = DFC_SD_ERROR_INVALID_PORT; goto get_sd_event_exit; } /* Find the event entry */ dfc_event = NULL; for (i = 0; i < MAX_DFC_EVENTS; i++) { dfc_event = &vport->sd_events[i]; if (dfc_event->pid == pid && dfc_event->event == event) break; } if (i == MAX_DFC_EVENTS) { rval = DFC_SD_ERROR_GENERIC; goto get_sd_event_exit; } if (!(vport->sd_event_mask & dfc_event->event)) { rval = DFC_SD_ERROR_GENERIC; goto get_sd_event_exit; } /* Initialize event buffer pointers */ dfc_event->dataout = dfc->buf1; dfc_event->size = dfc->buf1_size; dfc_event->last_id = dfc->data3; dfc_event->mode = mode; sleep = (dfc->flag & 0x01) ? 1 : 0; emlxs_get_sd_event(vport, dfc_event, sleep); /* * update rcv_size. */ if (dfc->buf2) { bcopy((void *) &dfc_event->size, dfc->buf2, sizeof (uint32_t)); } /* * update index */ if (dfc->buf3) { bcopy((void *) &dfc_event->last_id, dfc->buf3, sizeof (uint32_t)); } get_sd_event_exit: return (rval); } /* emlxs_dfc_sd_get_event */ #endif /*ARGSUSED*/ static int32_t emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; fc_packet_t *pkt = NULL; NODELIST *ndlp; FCP_CMND *fcp_cmd; FCP_RSP *fcp_rsp; void *ptr; char buffer[64]; dfc_send_scsi_fcp_cmd_info_t *cmdinfo; uint32_t rval = 0; /* cmd info */ if (!dfc->buf1 || (dfc->buf1_size != sizeof (dfc_send_scsi_fcp_cmd_info_t))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } /* reqBuffer info */ if (!dfc->buf2 || (dfc->buf2_size != sizeof (FCP_CMND))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } /* rspBuffer info, could be 0 for SCSI commands like TUR */ if (!dfc->buf3 && dfc->buf3_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } /* senseBuffer info */ if (!dfc->buf4 || !dfc->buf4_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_NULL; goto done; } cmdinfo = (dfc_send_scsi_fcp_cmd_info_t *)dfc->buf1; if (cmdinfo->ver == DFC_SEND_SCSI_FCP_V2) { port = emlxs_vport_find_wwpn(hba, (uint8_t *)&cmdinfo->src_wwn); if (port == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, sizeof (buffer), (uint8_t *)&cmdinfo->src_wwn)); rval = DFC_ARG_INVALID; goto done; } } if ((ndlp = emlxs_node_find_wwpn(port, (uint8_t *)&cmdinfo->dst_wwn, 1)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, sizeof (buffer), (uint8_t *)&cmdinfo->dst_wwn)); rval = DFC_ARG_INVALID; goto done; } if (!(pkt = emlxs_pkt_alloc(port, sizeof (FCP_CMND), sizeof (FCP_RSP), dfc->buf3_size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate packet.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } fcp_cmd = (FCP_CMND *) pkt->pkt_cmd; /* Copy in the command buffer */ bcopy((void *)dfc->buf2, (void *)fcp_cmd, sizeof (FCP_CMND)); /* Make this a polled IO */ pkt->pkt_tran_flags &= ~FC_TRAN_INTR; pkt->pkt_tran_flags |= FC_TRAN_NO_INTR; pkt->pkt_comp = NULL; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID); pkt->pkt_cmd_fhdr.r_ctl = FC_FCP_CMND; pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did); pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP; pkt->pkt_cmd_fhdr.seq_id = 0; pkt->pkt_cmd_fhdr.df_ctl = 0; pkt->pkt_cmd_fhdr.seq_cnt = 0; pkt->pkt_cmd_fhdr.ox_id = 0xFFFF; pkt->pkt_cmd_fhdr.rx_id = 0xFFFF; pkt->pkt_cmd_fhdr.ro = 0; pkt->pkt_timeout = 30; if ((fcp_cmd->fcpCntl3 == WRITE_DATA) && dfc->buf3_size) { pkt->pkt_tran_type = FC_PKT_FCP_WRITE; bcopy((void *)dfc->buf3, (void *)pkt->pkt_data, dfc->buf3_size); } else { pkt->pkt_tran_type = FC_PKT_FCP_READ; } if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { rval = DFC_IO_ERROR; goto done; } if (pkt->pkt_state != FC_PKT_SUCCESS) { if (pkt->pkt_state == FC_PKT_TIMEOUT) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. Pkt Timeout."); rval = DFC_TIMEOUT; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "Pkt Transport error. state=%x", pkt->pkt_state); rval = DFC_IO_ERROR; } goto done; } if (pkt->pkt_data_resid) { if (pkt->pkt_data_resid < dfc->buf3_size) dfc->buf3_size -= pkt->pkt_data_resid; else dfc->buf3_size = 0; } SCSI_RSP_CNT(cmdinfo) = dfc->buf3_size; fcp_rsp = (FCP_RSP *) pkt->pkt_resp; /* * This is sense count for flag = 0. * It is fcp response size for flag = 1. */ if (dfc->flag) { SCSI_SNS_CNT(cmdinfo) = 24 + LE_SWAP32(fcp_rsp->rspSnsLen) + LE_SWAP32(fcp_rsp->rspRspLen); ptr = (void *)fcp_rsp; } else { SCSI_SNS_CNT(cmdinfo) = LE_SWAP32(fcp_rsp->rspSnsLen); ptr = (void *)&fcp_rsp->rspSnsInfo[0]; } if (SCSI_SNS_CNT(cmdinfo)) { bcopy(ptr, (void *)dfc->buf4, SCSI_SNS_CNT(cmdinfo)); } if (SCSI_RSP_CNT(cmdinfo)) { bcopy((void *)pkt->pkt_data, (void *)dfc->buf3, SCSI_RSP_CNT(cmdinfo)); } rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_scsi_fcp() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_config_t *cfg = &CFG; uint16_t linkdown = 0; uint32_t rval = 0; if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } linkdown = (uint16_t)cfg[CFG_PERSIST_LINKDOWN].current; bcopy((void *)&linkdown, dfc->buf1, sizeof (uint16_t)); return (rval); } /* emlxs_dfc_get_persist_linkdown() */ /*ARGSUSED*/ static int32_t emlxs_dfc_set_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_config_t *cfg = &CFG; uint32_t rval = 0; if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } if (dfc->data1) { cfg[CFG_PERSIST_LINKDOWN].current = 1; } else { cfg[CFG_PERSIST_LINKDOWN].current = 0; } return (rval); } /* emlxs_dfc_set_persist_linkdown() */ /*ARGSUSED*/ static int32_t emlxs_dfc_get_fcflist(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; DFC_FCoEFCFInfo_t *fcflistentry; DFC_FCoEFCFList_t *fcflist; FCFIobj_t *fcfp; uint32_t size; uint32_t i; uint32_t count = 0; uint32_t rval = 0; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (dfc->buf1_size < sizeof (DFC_FCoEFCFList_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Buffer1 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_TOOSMALL); } if (! ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } if (hba->state != FC_READY) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: HBA not ready.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_DRV_ERROR); } size = sizeof (DFC_FCoEFCFList_t) + hba->sli.sli4.fcftab.table_count * sizeof (DFC_FCoEFCFInfo_t); fcflist = (DFC_FCoEFCFList_t *)kmem_zalloc(size, KM_SLEEP); bcopy(dfc->buf1, (void *)fcflist, sizeof (DFC_FCoEFCFList_t)); fcflistentry = fcflist->entries; mutex_enter(&EMLXS_FCF_LOCK); fcfp = hba->sli.sli4.fcftab.table; for (i = 0; i < hba->sli.sli4.fcftab.table_count; i++, fcfp++) { if ((fcfp->state != FCFI_STATE_FREE) && (fcfp->fcf_rec.fcf_valid)) { fcflistentry->Priority = fcfp->fcf_rec.fip_priority; if (fcfp->fcf_rec.fcf_available) { fcflistentry->State = FCF_AVAILABLE_STATE; } fcflistentry->LKA_Period = fcfp->fcf_rec.fka_adv_period; bcopy((void *)fcfp->fcf_rec.vlan_bitmap, (void *)fcflistentry->VLanBitMap, 512); bcopy((void *)fcfp->fcf_rec.fc_map, (void *)fcflistentry->FC_Map, 3); bcopy((void *)fcfp->fcf_rec.fabric_name_identifier, (void *)fcflistentry->FabricName, 8); bcopy((void *)fcfp->fcf_rec.switch_name_identifier, (void *)fcflistentry->SwitchName, 8); bcopy((void *)&fcfp->fcf_rec.fcf_mac_address_hi, (void *)fcflistentry->Mac, 6); count++; fcflistentry++; } } mutex_exit(&EMLXS_FCF_LOCK); fcflist->nActiveFCFs = hba->sli.sli4.fcftab.fcfi_count; if (count > fcflist->numberOfEntries) { rval = DFC_ARG_TOOSMALL; } i = sizeof (DFC_FCoEFCFList_t) + (fcflist->numberOfEntries - 1) * sizeof (DFC_FCoEFCFInfo_t); fcflist->numberOfEntries = (uint16_t)count; bcopy((void *)fcflist, dfc->buf1, i); done: kmem_free(fcflist, size); return (rval); } /* emlxs_dfc_get_fcflist() */ /*ARGSUSED*/ static int32_t emlxs_dfc_send_mbox4(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; MAILBOX4 *mb4 = NULL; MAILBOXQ *mbq = NULL; mbox_req_hdr_t *hdr_req; IOCTL_COMMON_WRITE_OBJECT *write_obj; MATCHMAP *mp = NULL, *tx_mp = NULL, *rx_mp = NULL; uintptr_t addr; /* Was uint64_t in Emulex drop... */ uint32_t size; int32_t mbxstatus = 0; uint32_t rval = 0; if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: SLI Mode %d not supported.", emlxs_dfc_xlate(dfc->cmd), hba->sli_mode); return (DFC_NOT_SUPPORTED); } if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if (!dfc->buf2 || !dfc->buf2_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } if ((dfc->buf1_size != dfc->buf2_size) || (dfc->buf1_size < sizeof (MAILBOX4))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid buffer size. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); return (DFC_ARG_INVALID); } mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb4 = (MAILBOX4 *) mbq; bcopy(dfc->buf1, (void *)mb4, sizeof (MAILBOX4)); /* * Now snoop the mailbox command */ switch (mb4->mbxCommand) { case MBX_SLI_CONFIG: if (! mb4->un.varSLIConfig.be.embedded) { if (mb4->un.varSLIConfig.be.sge_cnt > 1) { /* * Allow only one buffer descriptor * for non-embedded commands */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Only one buffer descriptor allowed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_INVALID; break; } if ((!mb4->un.varSLIConfig.be.payload_length) || (mb4->un.varSLIConfig.be.payload_length != (dfc->buf1_size - sizeof (MAILBOX4)))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid buffer size. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); rval = DFC_ARG_INVALID; break; } mp = emlxs_mem_buf_alloc(hba, mb4->un.varSLIConfig.be.payload_length); if (mp == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; break; } bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4), mp->virt, mp->size); EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size, DDI_DMA_SYNC_FORDEV); mbq->nonembed = (void *) mp; break; } hdr_req = (mbox_req_hdr_t *) &mb4->un.varSLIConfig.be.un_hdr.hdr_req; /* * WRITE_OBJECT, READ_OBJECT and READ_OBJECT_LIST are * special because they use buffer descriptors */ if ((hdr_req->subsystem == IOCTL_SUBSYSTEM_COMMON) && ((hdr_req->opcode == COMMON_OPCODE_WRITE_OBJ) || (hdr_req->opcode == COMMON_OPCODE_READ_OBJ_LIST) || (hdr_req->opcode == COMMON_OPCODE_READ_OBJ))) { write_obj = (IOCTL_COMMON_WRITE_OBJECT *)(hdr_req + 1); if (write_obj->params.request.buffer_desc_count > 1) { /* * Allow only one buffer descriptor * for embedded commands */ EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Only one buffer descriptor allowed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_ARG_INVALID; break; } if (write_obj->params.request.buffer_length != (dfc->buf1_size - sizeof (MAILBOX4))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid buffer size. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); rval = DFC_ARG_INVALID; break; } if (write_obj->params.request.buffer_length) { mp = emlxs_mem_buf_alloc(hba, write_obj->params.request.buffer_length); if (mp == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; break; } bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4), mp->virt, mp->size); EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size, DDI_DMA_SYNC_FORDEV); write_obj->params.request.buffer_addrlo = PADDR_LO(mp->phys); write_obj->params.request.buffer_addrhi = PADDR_HI(mp->phys); } break; } break; case MBX_DUMP_MEMORY: if (mb4->un.varDmp4.available_cnt == 0) break; if (mb4->un.varDmp4.available_cnt != (dfc->buf1_size - sizeof (MAILBOX4))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid buffer size. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); rval = DFC_ARG_INVALID; break; } mp = emlxs_mem_buf_alloc(hba, mb4->un.varDmp4.available_cnt); if (mp == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; break; } bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4), mp->virt, mp->size); EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size, DDI_DMA_SYNC_FORDEV); mb4->un.varDmp4.addrLow = PADDR_LO(mp->phys); mb4->un.varDmp4.addrHigh = PADDR_HI(mp->phys); break; case MBX_UPDATE_CFG: if (mb4->un.varUpdateCfg.Obit == 0) break; if (mb4->un.varUpdateCfg.byte_len != (dfc->buf1_size - sizeof (MAILBOX4))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid buffer size. (size=%d)", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size); rval = DFC_ARG_INVALID; break; } mp = emlxs_mem_buf_alloc(hba, mb4->un.varUpdateCfg.byte_len); if (mp == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; break; } bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4), mp->virt, mp->size); EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size, DDI_DMA_SYNC_FORDEV); mb4->un.varWords[5] = PADDR_LO(mp->phys); mb4->un.varWords[6] = PADDR_HI(mp->phys); break; case MBX_RUN_BIU_DIAG64: size = mb4->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize; addr = PADDR(mb4->un.varBIUdiag.un.s2.xmit_bde64.addrHigh, mb4->un.varBIUdiag.un.s2.xmit_bde64.addrLow); if (!addr || !size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid xmit BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand); rval = DFC_ARG_INVALID; break; } /* Allocate xmit buffer */ if ((tx_mp = emlxs_mem_buf_alloc(hba, size)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate xmit buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand); rval = DFC_DRVRES_ERROR; break; } /* Initialize the xmit buffer */ if (ddi_copyin((void *)addr, (void *)tx_mp->virt, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand); rval = DFC_COPYIN_ERROR; break; } EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size, DDI_DMA_SYNC_FORDEV); mb4->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = PADDR_HI(tx_mp->phys); mb4->un.varBIUdiag.un.s2.xmit_bde64.addrLow = PADDR_LO(tx_mp->phys); mb4->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0; size = mb4->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize; addr = PADDR(mb4->un.varBIUdiag.un.s2.rcv_bde64.addrHigh, mb4->un.varBIUdiag.un.s2.rcv_bde64.addrLow); if (!addr || !size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Invalid xmit BDE. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand); rval = DFC_ARG_INVALID; break; } /* Allocate receive buffer */ if ((rx_mp = emlxs_mem_buf_alloc(hba, size)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand); rval = DFC_DRVRES_ERROR; break; } mb4->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = PADDR_HI(rx_mp->phys); mb4->un.varBIUdiag.un.s2.rcv_bde64.addrLow = PADDR_LO(rx_mp->phys); mb4->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeFlags = 0; break; default: break; } if (rval) goto done; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: %s sent. (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb4->mbxCommand), mb4->un.varWords[0], mb4->un.varWords[1], mb4->un.varWords[2], mb4->un.varWords[3]); /* issue the mbox cmd to the sli */ mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb4->mbxCommand), mbxstatus); } bcopy((void *)mb4, dfc->buf2, sizeof (MAILBOX4)); if (mp) { bcopy(mp->virt, (uint8_t *)dfc->buf2 + sizeof (MAILBOX4), mp->size); } if (rx_mp) { EMLXS_MPDATA_SYNC(rx_mp->dma_handle, 0, size, DDI_DMA_SYNC_FORKERNEL); if (ddi_copyout((void *)rx_mp->virt, (void *)addr, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed for receive buffer. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand); rval = DFC_COPYOUT_ERROR; goto done; } } done: /* Free allocated memory */ if (mp) { emlxs_mem_buf_free(hba, mp); } if (tx_mp) { emlxs_mem_buf_free(hba, tx_mp); } if (rx_mp) { emlxs_mem_buf_free(hba, rx_mp); } if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_send_mbox4() */ /* ARGSUSED */ static int emlxs_dfc_rd_be_fcf(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; MATCHMAP *mp; MAILBOX4 *mb = NULL; MAILBOXQ *mbq = NULL; IOCTL_FCOE_READ_FCF_TABLE *fcf; mbox_req_hdr_t *hdr_req; mbox_rsp_hdr_t *hdr_rsp; FCF_RECORD_t *fcfrec; uint32_t rc = 0; uint32_t rval = 0; uint16_t index; if (!dfc->buf1 || !dfc->buf1_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_ARG_NULL); } mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); index = dfc->data1; mb = (MAILBOX4 *)mbq; bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE); if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) { rval = DFC_SYSRES_ERROR; goto done; } bzero(mp->virt, mp->size); /* * Signifies a non-embedded command */ mb->un.varSLIConfig.be.embedded = 0; mbq->nonembed = (void *)mp; mbq->mbox_cmpl = NULL; mb->mbxCommand = MBX_SLI_CONFIG; mb->mbxOwner = OWN_HOST; hdr_req = (mbox_req_hdr_t *)mp->virt; hdr_rsp = (mbox_rsp_hdr_t *)mp->virt; hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE; hdr_req->opcode = FCOE_OPCODE_READ_FCF_TABLE; hdr_req->timeout = 0; hdr_req->req_length = sizeof (IOCTL_FCOE_READ_FCF_TABLE); fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_req + 1); fcf->params.request.fcf_index = index; rc = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rc == MBX_SUCCESS) { fcfrec = &fcf->params.response.fcf_entry[0]; bcopy((void *)fcfrec, (void *)dfc->buf1, dfc->buf1_size); bcopy((void *)&fcf->params.response.next_valid_fcf_index, (void *)dfc->buf2, dfc->buf2_size); } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rc); if ((rc == MBX_NONEMBED_ERROR) && (hdr_rsp->status == MBX_RSP_STATUS_NO_FCF)) { rval = DFC_NO_DATA; } else { rval = DFC_IO_ERROR; } } done: if (mp) { emlxs_mem_put(hba, MEM_BUF, (void *)mp); } if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_rd_be_fcf() */ /*ARGSUSED*/ static int emlxs_dfc_set_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; MAILBOXQ *mbq = NULL; MAILBOX4 *mb; IOCTL_DCBX_SET_DCBX_MODE *dcbx_mode; uint32_t port_num = 0; uint32_t rval = 0; mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX4 *)mbq; /* * Signifies an embedded command */ mb->un.varSLIConfig.be.embedded = 1; mbq->mbox_cmpl = NULL; mb->mbxCommand = MBX_SLI_CONFIG; mb->mbxOwner = OWN_HOST; mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ; mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem = IOCTL_SUBSYSTEM_DCBX; mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = DCBX_OPCODE_SET_DCBX_MODE; mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0; mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length = sizeof (IOCTL_DCBX_SET_DCBX_MODE); dcbx_mode = (IOCTL_DCBX_SET_DCBX_MODE *)&mb->un.varSLIConfig.payload; dcbx_mode->params.request.port_num = (uint8_t)port_num; dcbx_mode->params.request.dcbx_mode = dfc->data1; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested on port %d.", emlxs_dfc_xlate(dfc->cmd), port_num); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval != MBX_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_DRV_ERROR; } done: if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_set_be_dcbx() */ /* ARGSUSED */ static int emlxs_dfc_get_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; MAILBOXQ *mbq = NULL; MAILBOX4 *mb; IOCTL_DCBX_GET_DCBX_MODE *dcbx_mode; uint32_t port_num = 0; uint32_t rval = 0; mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP); mb = (MAILBOX4 *)mbq; /* * Signifies an embedded command */ mb->un.varSLIConfig.be.embedded = 1; mbq->mbox_cmpl = NULL; mb->mbxCommand = MBX_SLI_CONFIG; mb->mbxOwner = OWN_HOST; mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ; mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem = IOCTL_SUBSYSTEM_DCBX; mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = DCBX_OPCODE_GET_DCBX_MODE; mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0; mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length = sizeof (IOCTL_DCBX_SET_DCBX_MODE); dcbx_mode = (IOCTL_DCBX_GET_DCBX_MODE *)&mb->un.varSLIConfig.payload; dcbx_mode->params.request.port_num = (uint8_t)port_num; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested on port %d.", emlxs_dfc_xlate(dfc->cmd), port_num); rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0); if (rval != MBX_SUCCESS) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd), emlxs_mb_cmd_xlate(mb->mbxCommand), rval); rval = DFC_DRV_ERROR; goto done; } bcopy((void *)&dcbx_mode->params.response.dcbx_mode, (void *)dfc->buf1, dfc->buf1_size); done: if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_get_be_dcbx() */ /* ARGSUSED */ static int emlxs_dfc_get_qos(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t rval = 0; if (! ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_NOT_SUPPORTED); } if (dfc->buf1_size) { bcopy((void *)&hba->qos_linkspeed, (void *)dfc->buf1, dfc->buf1_size); } return (rval); } /* emlxs_dfc_get_qos() */