/* * 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 usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * 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 2009 Emulex. All rights reserved. * Use is subject to License terms. */ #include #ifdef DFC_SUPPORT /* 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_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 */ #ifdef NPIV_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); #endif /* NPIV_SUPPORT */ #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(dfc_t *dfc, int32_t mode); static int32_t emlxs_dfc_sd_destroy_bucket(dfc_t *dfc); static int32_t emlxs_dfc_sd_get_bucket(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 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); #endif /* FCIO_SUPPORT */ uint32_t emlxs_loopback_tmo = 60; emlxs_table_t emlxs_dfc_table[] = { {EMLXS_GET_HBAINFO, "GET_HBAINFO"}, {EMLXS_GET_REV, "GET_REV"}, {EMLXS_SET_DIAG, "SET_DIAG"}, {EMLXS_SEND_MBOX, "SEND_MBOX"}, {EMLXS_READ_PCI, "READ_PCI"}, {EMLXS_WRITE_PCI, "WRITE_PCI"}, {EMLXS_GET_CFG, "GET_CFG"}, {EMLXS_SET_CFG, "SET_CFG"}, {EMLXS_SEND_CT, "SEND_CT"}, {EMLXS_SEND_CT_RSP, "SEND_CT_RSP"}, {EMLXS_SEND_MENLO, "SEND_MENLO"}, {EMLXS_WRITE_FLASH, "WRITE_FLASH"}, {EMLXS_READ_FLASH, "READ_FLASH"}, {EMLXS_SEND_ELS, "SEND_ELS"}, {EMLXS_LOOPBACK_TEST, "LOOPBACK_TEST"}, {EMLXS_GET_DUMPREGION, "GET_DUMPREGION"}, {EMLXS_LOOPBACK_MODE, "LOOPBACK_MODE"}, {EMLXS_GET_IOINFO, "GET_IOINFO"}, {EMLXS_GET_LINKINFO, "GET_LINKINFO"}, {EMLXS_GET_NODEINFO, "GET_NODEINFO"}, {EMLXS_READ_MEM, "READ_MEM"}, {EMLXS_WRITE_MEM, "WRITE_MEM"}, {EMLXS_WRITE_CTLREG, "WRITE_CTLREG"}, {EMLXS_READ_CTLREG, "READ_CTLREG"}, {EMLXS_SEND_SCSI, "SEND_SCSI"}, {EMLXS_GET_EVENT, "GET_EVENT"}, {EMLXS_SET_EVENT, "SET_EVENT"}, {EMLXS_GET_EVENTINFO, "GET_EVENTINFO"}, {EMLXS_GET_HBASTATS, "GET_HBASTATS"}, {EMLXS_GET_DRVSTATS, "GET_DRVSTATS"}, {EMLXS_CREATE_VPORT, "CREATE_VPORT"}, {EMLXS_DESTROY_VPORT, "DESTROY_VPORT"}, {EMLXS_GET_VPORTINFO, "GET_VPORTINFO"}, {EMLXS_NPIV_RESOURCE, "NPIV_RESOURCE"}, {EMLXS_NPIV_TEST, "NPIV_TEST"}, {EMLXS_INIT_AUTH, "INIT_AUTH"}, {EMLXS_GET_AUTH_CFG, "GET_AUTH_CFG"}, {EMLXS_SET_AUTH_CFG, "SET_AUTH_CFG"}, {EMLXS_GET_AUTH_PASSWORD, "GET_AUTH_PASSWORD"}, {EMLXS_SET_AUTH_PASSWORD, "SET_AUTH_PASSWORD"}, {EMLXS_GET_AUTH_STATUS, "GET_AUTH_STATUS"}, {EMLXS_GET_AUTH_CFG_TABLE, "GET_AUTH_CFG_TABLE"}, {EMLXS_GET_AUTH_KEY_TABLE, "GET_AUTH_KEY_TABLE"}, {EMLXS_FCIO_CMD, "FCIO_CMD"}, {EMLXS_GET_FCTSTAT, "GET_FCTSTAT"}, }; /* 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 sd_bucket_mutex; sd_bucket_info_t sd_bucket; #endif 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_table_t); for (i = 0; i < count; i++) { if (cmd == emlxs_dfc_table[i].code) { return (emlxs_dfc_table[i].string); } } (void) sprintf(buffer, "Cmd=0x%x", cmd); return (buffer); } /* emlxs_dfc_xlate() */ 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) sprintf(buffer, "Event=0x%x", event); return (buffer); } /* emlxs_dfc_event_xlate() */ extern int32_t emlxs_dfc_manage(emlxs_hba_t *hba, void *arg, int32_t mode) { emlxs_port_t *port = &PPORT; int rval = 0; dfc_t *dfc; if (!(dfc = (dfc_t *)kmem_zalloc(sizeof (dfc_t), KM_SLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate dfc buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } #ifdef _MULTI_DATAMODEL switch (ddi_model_convert_from(mode & FMODELS)) { case DDI_MODEL_ILP32: { dfc32_t dfc32; if (ddi_copyin((void *)arg, (void *)&dfc32, sizeof (dfc32_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; break; } dfc->cmd = dfc32.cmd; dfc->flag = dfc32.flag; dfc->buf1 = (void *)((unsigned long)dfc32.buf1); dfc->buf1_size = dfc32.buf1_size; dfc->data1 = dfc32.data1; dfc->buf2 = (void *)((unsigned long)dfc32.buf2); dfc->buf2_size = dfc32.buf2_size; dfc->data2 = dfc32.data2; dfc->buf3 = (void *)((unsigned long)dfc32.buf3); dfc->buf3_size = dfc32.buf3_size; dfc->data3 = dfc32.data3; dfc->buf4 = (void *)((unsigned long)dfc32.buf4); dfc->buf4_size = dfc32.buf4_size; dfc->data4 = dfc32.data4; break; } case DDI_MODEL_NONE: if (ddi_copyin((void *)arg, (void *)dfc, sizeof (dfc_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; } break; } #else /* _MULTI_DATAMODEL */ if (ddi_copyin((void *)arg, (void *)dfc, sizeof (dfc_t), mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; } #endif /* _MULTI_DATAMODEL */ switch (dfc->cmd) { case EMLXS_GET_HBAINFO: { rval = emlxs_dfc_get_hbainfo(hba, dfc, mode); break; } case EMLXS_GET_HBASTATS: { rval = emlxs_dfc_get_hbastats(hba, dfc, mode); break; } case EMLXS_GET_DRVSTATS: { rval = emlxs_dfc_get_drvstats(hba, dfc, mode); break; } case EMLXS_GET_NODEINFO: { rval = emlxs_dfc_get_nodeinfo(hba, dfc, mode); break; } case EMLXS_SET_DIAG: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_set_diag(hba, dfc, mode); break; } case EMLXS_SEND_MBOX: { rval = emlxs_dfc_send_mbox(hba, dfc, mode); break; } case EMLXS_READ_PCI: { rval = emlxs_dfc_read_pci(hba, dfc, mode); break; } case EMLXS_WRITE_PCI: { rval = emlxs_dfc_write_pci(hba, dfc, mode); break; } case EMLXS_GET_CFG: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_get_cfg(hba, dfc, mode); break; } case EMLXS_SET_CFG: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_set_cfg(hba, dfc, mode); break; } case EMLXS_SEND_CT: { rval = emlxs_dfc_send_ct(hba, dfc, mode); break; } case EMLXS_SEND_CT_RSP: { rval = emlxs_dfc_send_ct_rsp(hba, dfc, mode); break; } #ifdef MENLO_SUPPORT case EMLXS_SEND_MENLO: { rval = emlxs_dfc_send_menlo(hba, dfc, mode); break; } #endif /* MENLO_SUPPORT */ case EMLXS_WRITE_FLASH: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_write_flash(hba, dfc, mode); break; } case EMLXS_READ_FLASH: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_read_flash(hba, dfc, mode); break; } case EMLXS_SEND_ELS: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_send_els(hba, dfc, mode); break; } case EMLXS_LOOPBACK_TEST: { rval = emlxs_dfc_loopback_test(hba, dfc, mode); break; } case EMLXS_GET_DUMPREGION: { rval = emlxs_dfc_get_dump_region(hba, dfc, mode); break; } case EMLXS_LOOPBACK_MODE: { rval = emlxs_dfc_loopback_mode(hba, dfc, mode); break; } case EMLXS_GET_IOINFO: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_get_ioinfo(hba, dfc, mode); break; } case EMLXS_GET_LINKINFO: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_get_linkinfo(hba, dfc, mode); break; } #ifdef SFCT_SUPPORT case EMLXS_GET_FCTSTAT: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_get_fctstat(hba, dfc, mode); break; } #endif /* SFCT_SUPPORT */ case EMLXS_READ_MEM: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_read_mem(hba, dfc, mode); break; } case EMLXS_WRITE_MEM: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_write_mem(hba, dfc, mode); break; } case EMLXS_WRITE_CTLREG: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_write_ctlreg(hba, dfc, mode); break; } case EMLXS_READ_CTLREG: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_read_ctlreg(hba, dfc, mode); break; } case EMLXS_GET_EVENTINFO: { rval = emlxs_dfc_get_eventinfo(hba, dfc, mode); break; } case EMLXS_GET_EVENT: { rval = emlxs_dfc_get_event(hba, dfc, mode); break; } case EMLXS_SET_EVENT: { rval = emlxs_dfc_set_event(hba, dfc, mode); break; } case EMLXS_GET_REV: { rval = emlxs_dfc_get_rev(hba, dfc, mode); break; } case EMLXS_SEND_SCSI: { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); rval = emlxs_dfc_send_scsi_fcp(hba, dfc, mode); break; } #ifdef NPIV_SUPPORT case EMLXS_CREATE_VPORT: { rval = emlxs_dfc_create_vport(hba, dfc, mode); break; } case EMLXS_DESTROY_VPORT: { rval = emlxs_dfc_destroy_vport(hba, dfc, mode); break; } case EMLXS_GET_VPORTINFO: { rval = emlxs_dfc_get_vportinfo(hba, dfc, mode); break; } case EMLXS_NPIV_RESOURCE: { rval = emlxs_dfc_npiv_resource(hba, dfc, mode); break; } case EMLXS_NPIV_TEST: { rval = emlxs_dfc_npiv_test(hba, dfc, mode); break; } #endif /* NPIV_SUPPORT */ #ifdef DHCHAP_SUPPORT case EMLXS_INIT_AUTH: { rval = emlxs_dfc_init_auth(hba, dfc, mode); break; } case EMLXS_GET_AUTH_CFG: { rval = emlxs_dfc_get_auth_cfg(hba, dfc, mode); break; } case EMLXS_SET_AUTH_CFG: { rval = emlxs_dfc_set_auth_cfg(hba, dfc, mode); break; } case EMLXS_GET_AUTH_PASSWORD: { rval = emlxs_dfc_get_auth_pwd(hba, dfc, mode); break; } case EMLXS_SET_AUTH_PASSWORD: { rval = emlxs_dfc_set_auth_pwd(hba, dfc, mode); break; } case EMLXS_GET_AUTH_STATUS: { rval = emlxs_dfc_get_auth_status(hba, dfc, mode); break; } case EMLXS_GET_AUTH_CFG_TABLE: { rval = emlxs_dfc_get_auth_cfg_table(hba, dfc, mode); break; } case EMLXS_GET_AUTH_KEY_TABLE: { rval = emlxs_dfc_get_auth_key_table(hba, dfc, mode); break; } #endif /* DHCHAP_SUPPORT */ #ifdef FCIO_SUPPORT case EMLXS_FCIO_CMD: rval = emlxs_fcio_manage(hba, dfc, mode); break; #endif /* FCIO_SUPPORT */ #ifdef SAN_DIAG_SUPPORT case EMLXS_SD_SET_BUCKET: rval = emlxs_dfc_sd_set_bucket(dfc, mode); break; case EMLXS_SD_DESTROY_BUCKET: rval = emlxs_dfc_sd_destroy_bucket(dfc); break; case EMLXS_SD_GET_BUCKET: rval = emlxs_dfc_sd_get_bucket(dfc, mode); break; case EMLXS_SD_START_DATA_COLLECTION: rval = emlxs_dfc_sd_start_collection(hba, dfc, mode); break; case EMLXS_SD_STOP_DATA_COLLECTION: rval = emlxs_dfc_sd_stop_collection(hba, dfc, mode); break; case EMLXS_SD_RESET_DATA_COLLECTION: rval = emlxs_dfc_sd_reset_collection(hba, dfc, mode); break; case EMLXS_SD_GET_DATA: rval = emlxs_dfc_sd_get_data(hba, dfc, mode); break; case EMLXS_SD_SET_EVENT: rval = emlxs_dfc_sd_set_event(hba, dfc, mode); break; case EMLXS_SD_GET_EVENT: rval = emlxs_dfc_sd_get_event(hba, dfc, mode); break; #endif default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "Unknown command received. (0x%x)", dfc->cmd); rval = DFC_ARG_INVALID; } /* switch() */ kmem_free(dfc, sizeof (dfc_t)); return (rval); } /* emlxs_dfc_manage() */ #ifdef FCIO_SUPPORT emlxs_table_t emlxs_fcio_table[] = { {FCIO_GET_NUM_DEVS, "GET_NUM_DEVS"}, {FCIO_GET_DEV_LIST, "GET_DEV_LIST"}, {FCIO_GET_SYM_PNAME, "GET_SYM_PNAME"}, {FCIO_GET_SYM_NNAME, "GET_SYM_NNAME"}, {FCIO_SET_SYM_PNAME, "SET_SYM_PNAME"}, {FCIO_SET_SYM_NNAME, "SET_SYM_NNAME"}, {FCIO_GET_LOGI_PARAMS, "GET_LOGI_PARAMS"}, {FCIO_DEV_LOGIN, "DEV_LOGIN"}, {FCIO_DEV_LOGOUT, "DEV_LOGOUT"}, {FCIO_GET_STATE, "GET_STATE"}, {FCIO_DEV_REMOVE, "DEV_REMOVE"}, {FCIO_GET_FCODE_REV, "GET_FCODE_REV"}, {FCIO_GET_FW_REV, "GET_FW_REV"}, {FCIO_GET_DUMP_SIZE, "GET_DUMP_SIZE"}, {FCIO_FORCE_DUMP, "FORCE_DUMP"}, {FCIO_GET_DUMP, "GET_DUMP"}, {FCIO_GET_TOPOLOGY, "GET_TOPOLOGY"}, {FCIO_RESET_LINK, "RESET_LINK"}, {FCIO_RESET_HARD, "RESET_HARD"}, {FCIO_RESET_HARD_CORE, "RESET_HARD_CORE"}, {FCIO_DIAG, "DIAG"}, {FCIO_NS, "NS"}, {FCIO_DOWNLOAD_FW, "DOWNLOAD_FW"}, {FCIO_GET_HOST_PARAMS, "GET_HOST_PARAMS"}, {FCIO_LINK_STATUS, "LINK_STATUS"}, {FCIO_DOWNLOAD_FCODE, "DOWNLOAD_FCODE"}, {FCIO_GET_NODE_ID, "GET_NODE_ID"}, {FCIO_SET_NODE_ID, "SET_NODE_ID"}, {FCIO_SEND_NODE_ID, "SEND_NODE_ID"}, {FCIO_GET_ADAPTER_ATTRIBUTES, "GET_ADAPTER_ATTRIBUTES"}, {FCIO_GET_OTHER_ADAPTER_PORTS, "GET_OTHER_ADAPTER_PORTS"}, {FCIO_GET_ADAPTER_PORT_ATTRIBUTES, "GET_ADAPTER_PORT_ATTRIBUTES"}, {FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, "GET_DISCOVERED_PORT_ATTRIBUTES"}, {FCIO_GET_PORT_ATTRIBUTES, "GET_PORT_ATTRIBUTES"}, {FCIO_GET_ADAPTER_PORT_STATS, "GET_ADAPTER_PORT_STATS"}, }; /* 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_table_t); for (i = 0; i < count; i++) { if (cmd == emlxs_fcio_table[i].code) { return (emlxs_fcio_table[i].string); } } (void) sprintf(buffer, "Cmd=0x%x", cmd); return (buffer); } /* emlxs_fcio_xlate() */ static int32_t emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; emlxs_config_t *cfg = &CFG; int rval = 0; fcio_t local_fcio; fcio_t *fcio = &local_fcio; emlxs_vpd_t *vpd = &VPD; fc_hba_port_attributes_t *port_attrs; emlxs_node_t *ndlp; uint8_t *wwpn; uint32_t use32 = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: %s: requested.", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1)); if (!dfc->buf4 || !dfc->buf4_size) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1)); return (EFAULT); } if (dfc->buf4_size < sizeof (uint32_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: Buffer4 too small. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), dfc->buf4_size); return (EFAULT); } /* Map DFC to FCIO */ 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; fcio->fcio_errno = 0; /* dfc->buf4 on return */ if (dfc->buf1_size && dfc->buf1) { fcio->fcio_ilen = dfc->buf1_size; fcio->fcio_ibuf = kmem_zalloc(dfc->buf1_size, KM_SLEEP); if (!fcio->fcio_ibuf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: Unable to allocate ibuf. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_ilen); rval = EFAULT; goto done; } if (ddi_copyin(dfc->buf1, fcio->fcio_ibuf, fcio->fcio_ilen, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_ilen); rval = EFAULT; goto done; } } if (dfc->buf2_size && dfc->buf2) { fcio->fcio_olen = dfc->buf2_size; fcio->fcio_obuf = kmem_zalloc(dfc->buf2_size, KM_SLEEP); if (!fcio->fcio_obuf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: Unable to allocate obuf. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_olen); rval = EFAULT; goto done; } if (ddi_copyin(dfc->buf2, fcio->fcio_obuf, fcio->fcio_olen, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_olen); rval = EFAULT; goto done; } } if (dfc->buf3_size && dfc->buf3) { fcio->fcio_alen = dfc->buf3_size; fcio->fcio_abuf = kmem_zalloc(dfc->buf3_size, KM_SLEEP); if (!fcio->fcio_abuf) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: Unable to allocate abuf. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_alen); rval = EFAULT; goto done; } if (ddi_copyin(dfc->buf3, fcio->fcio_abuf, fcio->fcio_alen, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyin failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_alen); rval = EFAULT; goto done; } } #ifdef _MULTI_DATAMODEL if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { use32 = 1; } #endif /* _MULTI_DATAMODEL */ /* FCIO command */ switch (fcio->fcio_cmd) { case FCIO_DIAG: { fc_fca_pm_t pm; 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } } break; } case FCIO_GET_HOST_PARAMS: { uint32_t i; if (use32) { fc_port_dev32_t *port_dev; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen != sizeof (fc_port_dev32_t)) { rval = EINVAL; break; } port_dev = (fc_port_dev32_t *)fcio->fcio_obuf; port_dev->dev_did.port_id = port->did; port_dev->dev_hard_addr.hard_addr = cfg[CFG_ASSIGN_ALPA].current; port_dev->dev_state = port->ulp_statec; bcopy((caddr_t)&port->wwpn, (caddr_t)&port_dev->dev_pwwn, 8); bcopy((caddr_t)&port->wwnn, (caddr_t)&port_dev->dev_nwwn, 8); 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); break; } } } port_dev->dev_type[0] = SWAP_DATA32(0x00000120); port_dev->dev_type[1] = SWAP_DATA32(0x00000001); } else { fc_port_dev_t *port_dev; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen != sizeof (fc_port_dev_t)) { rval = EINVAL; break; } port_dev = (fc_port_dev_t *)fcio->fcio_obuf; port_dev->dev_did.port_id = port->did; port_dev->dev_hard_addr.hard_addr = cfg[CFG_ASSIGN_ALPA].current; port_dev->dev_state = port->ulp_statec; bcopy((caddr_t)&port->wwpn, (caddr_t)&port_dev->dev_pwwn, 8); bcopy((caddr_t)&port->wwnn, (caddr_t)&port_dev->dev_nwwn, 8); 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); break; } } } port_dev->dev_type[0] = SWAP_DATA32(0x00000120); port_dev->dev_type[1] = SWAP_DATA32(0x00000001); } break; } case FCIO_RESET_LINK: { uint8_t null_wwn[8]; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen != 8) { rval = EINVAL; break; } bzero(null_wwn, 8); if (bcmp((uint8_t *)fcio->fcio_ibuf, null_wwn, 8) == 0) { rval = emlxs_reset(port, FC_FCA_LINK_RESET); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } } else { rval = ENOTSUP; } break; } case FCIO_RESET_HARD: case FCIO_RESET_HARD_CORE: { rval = emlxs_reset(port, FC_FCA_RESET); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_DOWNLOAD_FW: { fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen <= 0) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_GET_FW_REV: { fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < FC_FW_REV_SIZE) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_GET_FCODE_REV: { fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < FC_FCODE_REV_SIZE) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_DOWNLOAD_FCODE: { fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen <= 0) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_GET_ADAPTER_ATTRIBUTES: { 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; break; } hba_attrs = (fc_hba_adapter_attributes32_t *)fcio->fcio_obuf; hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; (void) strncpy(hba_attrs->Manufacturer, "Emulex", sizeof (hba_attrs->Manufacturer)); (void) strncpy(hba_attrs->SerialNumber, vpd->serial_num, sizeof (hba_attrs->SerialNumber)); (void) strncpy(hba_attrs->Model, hba->model_info.model, sizeof (hba_attrs->Model)); (void) strncpy(hba_attrs->ModelDescription, hba->model_info.model_desc, sizeof (hba_attrs->ModelDescription)); 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)); (void) sprintf(hba_attrs->HardwareVersion, "%x", vpd->biuRev); (void) sprintf(hba_attrs->DriverVersion, "%s (%s)", emlxs_version, emlxs_revision); (void) strncpy(hba_attrs->OptionROMVersion, vpd->fcode_version, sizeof (hba_attrs->OptionROMVersion)); (void) sprintf(hba_attrs->FirmwareVersion, "%s (%s)", vpd->fw_version, vpd->fw_label); (void) strncpy(hba_attrs->DriverName, DRIVER_NAME, sizeof (hba_attrs->DriverName)); hba_attrs->VendorSpecificID = ((hba->model_info.device_id << 16) | PCI_VENDOR_ID_EMULEX); 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; break; } hba_attrs = (fc_hba_adapter_attributes_t *)fcio->fcio_obuf; hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION; (void) strncpy(hba_attrs->Manufacturer, "Emulex", sizeof (hba_attrs->Manufacturer)); (void) strncpy(hba_attrs->SerialNumber, vpd->serial_num, sizeof (hba_attrs->SerialNumber)); (void) strncpy(hba_attrs->Model, hba->model_info.model, sizeof (hba_attrs->Model)); (void) strncpy(hba_attrs->ModelDescription, hba->model_info.model_desc, sizeof (hba_attrs->ModelDescription)); 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)); (void) sprintf(hba_attrs->HardwareVersion, "%x", vpd->biuRev); (void) sprintf(hba_attrs->DriverVersion, "%s (%s)", emlxs_version, emlxs_revision); (void) strncpy(hba_attrs->OptionROMVersion, vpd->fcode_version, sizeof (hba_attrs->OptionROMVersion)); (void) sprintf(hba_attrs->FirmwareVersion, "%s (%s)", vpd->fw_version, vpd->fw_label); (void) strncpy(hba_attrs->DriverName, DRIVER_NAME, sizeof (hba_attrs->DriverName)); hba_attrs->VendorSpecificID = ((hba->model_info.device_id << 16) | PCI_VENDOR_ID_EMULEX); hba_attrs->NumberOfPorts = hba->num_of_ports; } break; } case FCIO_GET_ADAPTER_PORT_ATTRIBUTES: { uint32_t value1; uint32_t value2; if (use32) { fc_hba_port_attributes32_t *port_attrs; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_hba_port_attributes32_t)) { rval = EINVAL; break; } 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 (hba->state <= FC_LINK_DOWN) { /* 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) { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_NPORT; } ndlp = emlxs_node_find_did(port, Fabric_DID); if (ndlp) { bcopy(&ndlp->nlp_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; default: port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; } } port_attrs->PortSupportedClassofService = SWAP_DATA32(FC_NS_CLASS3); (void) strncpy((caddr_t)port_attrs->PortSymbolicName, (caddr_t)port->spn, sizeof (port_attrs->PortSymbolicName)); /* Set the hba speed limit */ 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; port_attrs->NumberofDiscoveredPorts = emlxs_nport_count(port); } else { fc_hba_port_attributes_t *port_attrs; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_hba_port_attributes_t)) { rval = EINVAL; break; } 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 (hba->state <= FC_LINK_DOWN) { /* 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) { port_attrs->PortType = FC_HBA_PORTTYPE_LPORT; } else { port_attrs->PortType = FC_HBA_PORTTYPE_NPORT; } ndlp = emlxs_node_find_did(port, Fabric_DID); if (ndlp) { bcopy(&ndlp->nlp_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; default: port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN; } } port_attrs->PortSupportedClassofService = SWAP_DATA32(FC_NS_CLASS3); (void) strncpy((caddr_t)port_attrs->PortSymbolicName, (caddr_t)port->spn, sizeof (port_attrs->PortSymbolicName)); /* Set the hba speed limit */ 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; port_attrs->NumberofDiscoveredPorts = emlxs_nport_count(port); } break; } case FCIO_GET_NODE_ID: { fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (fc_rnid_t)) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_SET_NODE_ID: { fc_fca_pm_t pm; if (fcio->fcio_xfer != FCIO_XFER_WRITE || fcio->fcio_ilen < sizeof (fc_rnid_t)) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } break; } case FCIO_GET_NUM_DEVS: { if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_olen < sizeof (uint32_t)) { rval = EINVAL; break; } *(uint32_t *)fcio->fcio_obuf = emlxs_nport_count(port); break; } case FCIO_GET_DEV_LIST: { uint32_t max_count; uint32_t i; uint32_t j; emlxs_node_t *nlp; uint32_t nport_count; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_alen < sizeof (uint32_t)) { rval = EINVAL; break; } if (use32) { fc_port_dev32_t *port_dev; 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); 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; break; } if (nport_count > max_count) { rw_exit(&port->node_rwlock); fcio->fcio_errno = FC_TOOMANY; rval = EIO; break; } 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] = SWAP_LONG(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; break; } } 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; 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); 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; break; } if (nport_count > max_count) { rw_exit(&port->node_rwlock); fcio->fcio_errno = FC_TOOMANY; rval = EIO; break; } 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] = SWAP_LONG(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; break; } } 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); } break; } case FCIO_GET_LOGI_PARAMS: { uint8_t null_wwn[8]; if (fcio->fcio_ilen != sizeof (la_wwn_t) || (fcio->fcio_xfer & FCIO_XFER_READ) == 0 || (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) { rval = EINVAL; break; } 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); if (ndlp) { bcopy((caddr_t)&ndlp->sparm, (caddr_t)fcio->fcio_obuf, fcio->fcio_olen); } else { rval = ENXIO; } } break; } case FCIO_GET_STATE: { uint8_t null_wwn[8]; uint32_t *statep; 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; break; } 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); if (ndlp) { *statep = PORT_DEVICE_VALID; } else { *statep = PORT_DEVICE_INVALID; } } break; } case FCIO_GET_TOPOLOGY: { uint32_t *tp; if (fcio->fcio_olen != 4 || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; break; } tp = (uint32_t *)fcio->fcio_obuf; if (hba->state <= FC_LINK_DOWN) { *tp = FC_TOP_UNKNOWN; } else { ndlp = emlxs_node_find_did(port, Fabric_DID); 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; } } } break; } case FCIO_LINK_STATUS: { 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; break; } if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) && (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; } } else { rval = ENOTSUP; } break; } case FCIO_GET_OTHER_ADAPTER_PORTS: { uint32_t index; char *path; if (fcio->fcio_olen < MAXPATHLEN || fcio->fcio_ilen != sizeof (uint32_t)) { rval = EINVAL; break; } index = *(uint32_t *)fcio->fcio_ibuf; path = (char *)fcio->fcio_obuf; if (index > hba->vpi_max - 1) { fcio->fcio_errno = FC_BADPORT; rval = EFAULT; break; } (void) ddi_pathname(hba->dip, path); break; } case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES: { uint32_t index; if (fcio->fcio_xfer != FCIO_XFER_READ || fcio->fcio_ilen < sizeof (uint32_t) || fcio->fcio_olen < sizeof (fc_hba_port_attributes_t)) { rval = EINVAL; break; } index = *(uint32_t *)fcio->fcio_ibuf; ndlp = emlxs_node_find_index(port, index, 1); if (!ndlp) { fcio->fcio_errno = FC_OUTOFBOUNDS; rval = EINVAL; break; } goto get_node_attrs; } /* Same as FCIO_GET_DISCOVERED_PORT_ATTRIBUTES */ /* except WWPN is used instead of index */ case FCIO_GET_PORT_ATTRIBUTES: { emlxs_node_t *ndlp2; if ((fcio->fcio_xfer != FCIO_XFER_READ) || (fcio->fcio_ilen < 8) || (fcio->fcio_olen < sizeof (fc_hba_port_attributes_t))) { rval = EINVAL; break; } wwpn = (uint8_t *)fcio->fcio_ibuf; ndlp = emlxs_node_find_wwpn(port, wwpn); if (!ndlp) { fcio->fcio_errno = FC_NOMAP; rval = EINVAL; break; } /* Filter fabric ports */ if ((ndlp->nlp_DID & 0xFFF000) == 0xFFF000) { fcio->fcio_errno = FC_NOMAP; rval = EINVAL; break; } get_node_attrs: 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 (hba->state > FC_LINK_UP) { ndlp2 = emlxs_node_find_did(port, Fabric_DID); port_attrs->PortFcId = ndlp->nlp_DID; port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE; /* no switch */ if (!ndlp2) { 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; } } /* 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; } } } } port_attrs->PortSupportedClassofService = SWAP_DATA32(FC_NS_CLASS3); /* port_attrs->PortSymbolicName */ /* port_attrs->PortSupportedSpeed */ /* port_attrs->PortSupportedFc4Types */ /* port_attrs->PortActiveFc4Types */ /* port_attrs->PortMaxFrameSize */ /* port_attrs->NumberofDiscoveredPorts */ break; } case FCIO_GET_SYM_PNAME: { if (fcio->fcio_olen < (strlen(port->spn)+1) || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; break; } (void) strcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->spn); break; } case FCIO_GET_SYM_NNAME: { if (fcio->fcio_olen < (strlen(port->snn)+1) || (fcio->fcio_xfer & FCIO_XFER_READ) == 0) { rval = EINVAL; break; } (void) strcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->snn); break; } case FCIO_FORCE_DUMP: { rval = emlxs_reset(port, FC_FCA_CORE); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; rval = EIO; break; } break; } case FCIO_GET_DUMP_SIZE: { fc_fca_pm_t pm; if (fcio->fcio_olen != sizeof (uint32_t) || fcio->fcio_xfer != FCIO_XFER_READ) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } } break; } case FCIO_GET_DUMP: { fc_fca_pm_t pm; uint32_t dump_size; if (fcio->fcio_xfer != FCIO_XFER_READ) { rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } break; } if (fcio->fcio_olen != dump_size) { fcio->fcio_errno = FC_NOMEM; rval = EINVAL; break; } 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_port_manage(port, &pm); if (rval != FC_SUCCESS) { fcio->fcio_errno = rval; if (rval == FC_INVALID_REQUEST) { rval = ENOTTY; } else { rval = EIO; } } break; } case FCIO_SET_SYM_PNAME: case FCIO_SET_SYM_NNAME: case FCIO_DEV_LOGIN: case FCIO_DEV_LOGOUT: case FCIO_DEV_REMOVE: case FCIO_NS: case FCIO_SEND_NODE_ID: case FCIO_GET_ADAPTER_PORT_STATS: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: Unsupported FCIO command.", emlxs_fcio_xlate(fcio->fcio_cmd)); rval = ENOTSUP; break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "Unknown FCIO command. (0x%x)", fcio->fcio_cmd); rval = EFAULT; } /* switch() */ done: if (rval != 0 && fcio->fcio_errno == 0) { fcio->fcio_errno = FC_FAILURE; } if (fcio->fcio_ibuf) { if (ddi_copyout(fcio->fcio_ibuf, dfc->buf1, fcio->fcio_ilen, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_ilen); rval = EFAULT; } kmem_free(fcio->fcio_ibuf, fcio->fcio_ilen); } if (fcio->fcio_obuf) { if (ddi_copyout(fcio->fcio_obuf, dfc->buf2, fcio->fcio_olen, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_olen); rval = EFAULT; } kmem_free(fcio->fcio_obuf, fcio->fcio_olen); } if (fcio->fcio_abuf) { if (ddi_copyout(fcio->fcio_abuf, dfc->buf3, fcio->fcio_alen, mode)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), fcio->fcio_alen); rval = EFAULT; } kmem_free(fcio->fcio_abuf, fcio->fcio_alen); } if (ddi_copyout((void *)&fcio->fcio_errno, (void *)dfc->buf4, dfc->buf4_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: %s: ddi_copyout failed. (size=%d)", emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1), dfc->buf4_size); rval = EFAULT; } return (rval); } /* emlxs_fcio_manage() */ #endif /* FCIO_SUPPORT */ #ifdef NPIV_SUPPORT 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; dfc_vportinfo_t dfc_vport; uint32_t vpi; uint32_t options; char name[256]; uint8_t wwn[8]; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } /* Read the dfc_vport object */ if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_vport, sizeof (dfc_vportinfo_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } 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, 0)) { 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] = vpi; } else { /* use one provided */ /* Make sure WWPN is unique */ if (emlxs_vport_find_wwpn(hba, dfc_vport.wwpn)) { 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] = vpi; } /* else use WWNN provided */ /* Generate the symbolic node name */ if (dfc_vport.snn[0]) { (void) strcpy(name, dfc_vport.snn); (void) sprintf(dfc_vport.snn, "%s %s", hba->snn, name); } else { (void) strcpy(dfc_vport.snn, hba->snn); } /* Generate the symbolic port name */ if (dfc_vport.spn[0]) { (void) strcpy(name, dfc_vport.spn); (void) sprintf(dfc_vport.spn, "%s VPort-%d VName-%s", hba->spn, vpi, name); } else { (void) sprintf(dfc_vport.spn, "%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, 256); (void) strncpy((caddr_t)vport->spn, (caddr_t)dfc_vport.spn, 256); vport->flag |= (EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLE); /* 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; } #ifdef SFCT_SUPPORT if (vport->tgt_mode) { emlxs_fct_bind_port(vport); } #endif /* SFCT_SUPPORT */ if (ddi_copyout((void *)&dfc_vport, (void *)dfc->buf1, sizeof (dfc_vportinfo_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } 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() */ 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]; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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 */ if (ddi_copyin((void *)dfc->buf1, (void *)wwpn, 8, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } /* 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, 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 = SWAP_DATA24_LO(Fabric_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 = SWAP_DATA32(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_ENABLE); rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_destroy_vport() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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_ENABLE) { 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; } if (ddi_copyout((void *)dfc_vport_list, (void *)dfc->buf1, dfc->buf1_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } 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() */ 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); } if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } mb = (MAILBOX *) mbq; emlxs_mb_read_config(hba, mb); rval = emlxs_sli_issue_mbox_cmd(hba, mb, 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; } bzero(&vres, sizeof (dfc_vport_resource_t)); 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; if (ddi_copyout((void *)&vres, (void *)dfc->buf1, sizeof (dfc_vport_resource_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; } done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_npiv_resource() */ 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) { 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; } } 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 = SWAP_DATA24_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()) */ els->un.logi.cmn.fcphHigh = 0x09; els->un.logi.cmn.fcphLow = 0x08; els->un.logi.cmn.bbCreditMsb = 0xff; els->un.logi.cmn.bbCreditlsb = 0xff; els->un.logi.cmn.reqMultipleNPort = 1; els->un.logi.cmn.bbRcvSizeMsb = 0x08; els->un.logi.cmn.bbRcvSizeLsb = 0x00; els->un.logi.cmn.w2.nPort.totalConcurrSeq = 0xff; els->un.logi.cmn.w2.nPort.roByCategoryMsb = 0xff; els->un.logi.cmn.w2.nPort.roByCategoryLsb = 0xff; els->un.logi.cmn.e_d_tov = 0x7d0; 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)&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); els->un.logi.cls1.openSeqPerXchgMsb = 0x00; els->un.logi.cls1.openSeqPerXchgLsb = 0x01; els->un.logi.cls2.classValid = 1; els->un.logi.cls2.rcvDataSizeMsb = 0x08; els->un.logi.cls2.rcvDataSizeLsb = 0x00; els->un.logi.cls2.concurrentSeqMsb = 0x00; els->un.logi.cls2.concurrentSeqLsb = 0xff; els->un.logi.cls2.EeCreditSeqMsb = 0x00; els->un.logi.cls2.EeCreditSeqLsb = 0x0c; els->un.logi.cls2.openSeqPerXchgMsb = 0x00; els->un.logi.cls2.openSeqPerXchgLsb = 0x01; els->un.logi.cls3.classValid = 1; els->un.logi.cls3.rcvDataSizeMsb = 0x08; els->un.logi.cls3.rcvDataSizeLsb = 0x00; els->un.logi.cls3.concurrentSeqMsb = 0x00; els->un.logi.cls3.concurrentSeqLsb = 0xff; els->un.logi.cls3.openSeqPerXchgMsb = 0x00; els->un.logi.cls3.openSeqPerXchgLsb = 0x01; 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 (!(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 = SWAP_DATA24_LO(Fabric_DID); pkt1->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; pkt1->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 = SWAP_DATA32(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; } 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; } } /* * Free up default RPIs and VPI */ free_resc: (void) emlxs_mb_unreg_rpi(vport, 0xffff, 0, 0, 0); (void) emlxs_mb_unreg_vpi(vport); done: if (ddi_copyout((void *)&checklist, (void *)dfc->buf1, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; } if (pkt) { /* Free the pkt */ emlxs_pkt_free(pkt); } if (pkt1) { /* Free the pkt */ emlxs_pkt_free(pkt1); } return (rval); } /* emlxs_dfc_npiv_test() */ #endif /* NPIV_SUPPORT */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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; if (ddi_copyout((void *)&rev, (void *)dfc->buf1, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_rev() */ 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; NODELIST *ndlp; char pathname[256]; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } bzero((void *) &hbainfo, sizeof (dfc_hbainfo_t)); (void) strncpy(hbainfo.vpd_serial_num, vpd->serial_num, sizeof (hbainfo.vpd_serial_num)); (void) strncpy(hbainfo.vpd_part_num, vpd->part_num, sizeof (hbainfo.vpd_part_num)); (void) strncpy(hbainfo.vpd_port_num, vpd->port_num, sizeof (hbainfo.vpd_port_num)); (void) strncpy(hbainfo.vpd_eng_change, vpd->eng_change, sizeof (hbainfo.vpd_eng_change)); (void) strncpy(hbainfo.vpd_manufacturer, vpd->manufacturer, sizeof (hbainfo.vpd_manufacturer)); (void) strncpy(hbainfo.vpd_model, vpd->model, sizeof (hbainfo.vpd_model)); (void) strncpy(hbainfo.vpd_model_desc, vpd->model_desc, sizeof (hbainfo.vpd_model_desc)); (void) strncpy(hbainfo.vpd_prog_types, vpd->prog_types, sizeof (hbainfo.vpd_prog_types)); (void) strncpy(hbainfo.vpd_id, vpd->id, sizeof (hbainfo.vpd_id)); hbainfo.device_id = hba->model_info.device_id; hbainfo.vendor_id = ddi_get32(hba->pci_acc_handle, (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER)) & 0xffff; 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)); bcopy(&hba->wwpn, hbainfo.wwpn, sizeof (hbainfo.wwpn)); (void) strncpy(hbainfo.spn, port->spn, sizeof (hbainfo.spn)); 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)); hbainfo.stub_rev = vpd->opFwRev; (void) strncpy(hbainfo.stub_name, vpd->opFwName, sizeof (hbainfo.stub_name)); hbainfo.sli1_rev = vpd->sli1FwRev; (void) strncpy(hbainfo.sli1_name, vpd->sli1FwName, sizeof (hbainfo.sli1_name)); hbainfo.sli2_rev = vpd->sli2FwRev; (void) strncpy(hbainfo.sli2_name, vpd->sli2FwName, sizeof (hbainfo.sli2_name)); hbainfo.sli3_rev = vpd->sli3FwRev; (void) strncpy(hbainfo.sli3_name, vpd->sli3FwName, sizeof (hbainfo.sli3_name)); hbainfo.sli4_rev = vpd->sli4FwRev; (void) strncpy(hbainfo.sli4_name, vpd->sli4FwName, sizeof (hbainfo.sli4_name)); 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; #ifdef NPIV_SUPPORT hbainfo.flags |= HBA_FLAG_NPIV; #endif /* NPIV_SUPPORT */ #ifdef DHCHAP_SUPPORT hbainfo.flags |= HBA_FLAG_DHCHAP; if (cfg[CFG_AUTH_E2E].current) { hbainfo.flags |= HBA_FLAG_E2E_AUTH; } #endif /* DHCHAP_SUPPORT */ #ifdef SFCT_SUPPORT hbainfo.flags |= HBA_FLAG_TARGET_MODE; if (hba->tgt_mode) { hbainfo.flags |= HBA_FLAG_TARGET_MODE_ENA; } #endif /* SFCT_SUPPORT */ (void) strncpy(hbainfo.fcode_version, vpd->fcode_version, sizeof (hbainfo.fcode_version)); (void) strncpy(hbainfo.boot_version, vpd->boot_version, sizeof (hbainfo.boot_version)); (void) strncpy(hbainfo.fw_version, vpd->fw_version, sizeof (hbainfo.fw_version)); (void) strncpy(hbainfo.drv_label, emlxs_label, sizeof (hbainfo.drv_label)); (void) strncpy(hbainfo.drv_module, emlxs_name, sizeof (hbainfo.drv_module)); (void) strncpy(hbainfo.drv_name, DRIVER_NAME, sizeof (hbainfo.drv_name)); (void) strncpy(hbainfo.drv_version, emlxs_version, sizeof (hbainfo.drv_version)); (void) strncpy(hbainfo.drv_revision, emlxs_revision, sizeof (hbainfo.drv_revision)); (void) strncpy(hbainfo.hostname, (char *)utsname.nodename, sizeof (hbainfo.hostname)); (void) ddi_pathname(hba->dip, pathname); (void) sprintf(hbainfo.os_devname, "/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) { ndlp = emlxs_node_find_did(port, Fabric_DID); if (hba->topology == TOPOLOGY_LOOP) { if (ndlp) { 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 (ndlp) { hbainfo.port_type = HBA_PORTTYPE_NPORT; hbainfo.topology = LNK_FABRIC; } else { hbainfo.port_type = HBA_PORTTYPE_PTP; hbainfo.topology = LNK_PT2PT; } } if (ndlp) { bcopy(&ndlp->nlp_nodename, hbainfo.fabric_wwnn, sizeof (hbainfo.fabric_wwnn)); bcopy(&ndlp->nlp_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 { hbainfo.port_speed = HBA_PORTSPEED_1GBIT; } hbainfo.node_count = port->node_count; } hbainfo.hard_alpa = cfg[CFG_ASSIGN_ALPA].current; hbainfo.supported_cos = SWAP_DATA32((FC_NS_CLASS3 | FC_NS_CLASS2)); hbainfo.supported_types[0] = SWAP_DATA32(0x00000120); hbainfo.supported_types[1] = SWAP_DATA32(0x00000001); hbainfo.active_types[0] = SWAP_DATA32(0x00000120); hbainfo.active_types[1] = SWAP_DATA32(0x00000001); if (!cfg[CFG_NETWORK_ON].current) { hbainfo.active_types[0] &= ~(SWAP_DATA32(0x00000020)); } 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; } } if (ddi_copyout((void *)&hbainfo, (void *)dfc->buf1, sizeof (dfc_hbainfo_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } #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() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } mb = (MAILBOX *)mbq; emlxs_mb_read_status(hba, mb); rval = emlxs_sli_issue_mbox_cmd(hba, mb, 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; } 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, mb); rval = emlxs_sli_issue_mbox_cmd(hba, mb, 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_FABRIC_ATTACHED) { stats.port_type = HBA_PORTTYPE_NPORT; stats.topology = LNK_FABRIC; } else { stats.port_type = HBA_PORTTYPE_PTP; stats.topology = LNK_PT2PT; } } 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 { stats.link_speed = HBA_PORTSPEED_1GBIT; } } if (ddi_copyout((void *)&stats, (void *)dfc->buf1, sizeof (dfc_hbastats_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } done: /* Free allocated mbox memory */ if (mbq) { kmem_free(mbq, sizeof (MAILBOXQ)); } return (rval); } /* emlxs_dfc_get_hbastats() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } 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 if (ddi_copyout((void *)&stats, (void *)dfc->buf1, dfc->buf1_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } 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); } 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); /* Reset with restart */ emlxs_sli_hba_reset(hba, 1, 1); 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); 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); /* Reset with no restart */ emlxs_sli_hba_reset(hba, 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); 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); mutex_enter(&EMLXS_PORT_LOCK); } else if (hba->state != FC_KILLED) { mutex_exit(&EMLXS_PORT_LOCK); emlxs_sli_offline(hba); mutex_enter(&EMLXS_PORT_LOCK); } break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_set_hba_mode: Invalid mode. mode%x", mode); } /* 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); } /* emlxs_set_hba_mode() */ 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); if (ddi_copyout((void *)&flag, (void *)dfc->buf1, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (rval); } /* emlxs_dfc_set_diag() */ 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 (!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; if ((extbuf = (uint8_t *)kmem_zalloc(extsize, KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox extension buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } if (dfc->buf3_size) { if (ddi_copyin((void *)dfc->buf3, (void *)extbuf, dfc->buf3_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin mbox extension data " "failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } } } #endif /* MBOX_EXT_SUPPORT */ if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } mb = (MAILBOX *) mbq; bzero((void *) mb, MAILBOX_CMD_BSIZE); if (ddi_copyin((void *)dfc->buf1, (void *)mb, dfc->buf1_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } #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=%x", 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); 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)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(rx_mp->phys); mb->un.varRdEvtLog.un.sp64.addrLow = putPaddrLow(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)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(rx_mp->phys); mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(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)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(rx_mp->phys); mb->un.varRdRPI.un.sp64.addrLow = putPaddrLow(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)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(tx_mp->phys); mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = putPaddrLow(tx_mp->phys); mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0; /* Initialize the receive buffer */ lptr = (uintptr_t)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(rx_mp->phys); mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = putPaddrLow(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)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(tx_mp->phys); mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(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)getPaddr(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 = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 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 = putPaddrHigh(rx_mp->phys); mb->un.varReadLA.un.lilpBde64.addrLow = putPaddrLow(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, mb, 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); } if (ddi_copyout((void *)mb, (void *)dfc->buf2, dfc->buf2_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed. cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand); rval = DFC_COPYOUT_ERROR; goto done; } 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) { if (ddi_copyout((void *)extbuf, (void *)dfc->buf4, dfc->buf4_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed for mbox extension data.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } } #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) { (void) emlxs_mem_buf_free(hba, (uint8_t *)rx_mp); } if (tx_mp) { (void) emlxs_mem_buf_free(hba, (uint8_t *)tx_mp); } return (rval); } /* emlxs_dfc_send_mbox() */ 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 *buffer; uint32_t *bptr; uint32_t value; uint32_t size; 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; } size = cnt; if (!(buffer = (uint32_t *)kmem_zalloc(size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } bptr = buffer; for (i = offset; i < (offset + cnt); i += 4) { value = ddi_get32(hba->pci_acc_handle, (uint32_t *)(hba->pci_addr + i)); *bptr++ = PCIMEM_LONG(value); } if (ddi_copyout((void *)buffer, (void *)dfc->buf1, outsz, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(buffer, size); return (DFC_COPYOUT_ERROR); } kmem_free(buffer, size); #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() */ 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; uint8_t buffer[256]; 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); } bzero(buffer, sizeof (buffer)); if (ddi_copyin((void *)dfc->buf1, (void *)buffer, cnt, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } bptr = (uint32_t *)buffer; for (i = offset; i < (offset + cnt); i += 4) { value = *bptr++; value = PCIMEM_LONG(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() */ 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 size; uint32_t count; uint32_t i; int32_t rval = 0; 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; } if (count > NUM_CFG_PARAM) { count = NUM_CFG_PARAM; } size = count * sizeof (dfc_cfgparam_t); if (!(cfgparam = (dfc_cfgparam_t *)kmem_zalloc(size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate cfgparm buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } cfg = &CFG; for (i = 0; i < count; i++) { (void) strncpy(cfgparam[i].a_string, cfg[i].string, sizeof (cfgparam[i].a_string)); 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; } 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)); } if (ddi_copyout((void *)cfgparam, (void *)dfc->buf1, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; } rval = 0; kmem_free(cfgparam, size); return (rval); } /* 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() */ 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; } if (ddi_copyin((void *)dfc->buf3, (void *)&destid, sizeof (dfc_destid_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to read destination id.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } if (destid.idType == 0) { if ((nlp = emlxs_node_find_wwpn(port, destid.wwpn)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, destid.wwpn)); rval = DFC_ARG_INVALID; goto done; } did = nlp->nlp_DID; } else { if (emlxs_node_find_did(port, destid.d_id) == 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 = SWAP_DATA24_LO(did); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 */ if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to read command buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } 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; } if (ddi_copyout((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to read response.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } rsp_size -= pkt->pkt_resp_resid; if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf4, dfc->buf4_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to write response.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_ct() */ 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 = SWAP_DATA24_LO(0); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_SOLICITED_CONTROL; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 */ if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to read command buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } 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 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.device_id != PCI_DEVICE_ID_LP21000_M) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Menlo device not present. device=%x,%x", emlxs_dfc_xlate(dfc->cmd), 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; if ((cmd_buf = (uint8_t *)kmem_zalloc(cmd_size, KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate command buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } rsp_size = dfc->buf2_size; if ((rsp_buf = (uint8_t *)kmem_zalloc(rsp_size, KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate response buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } /* Read the command buffer */ if (ddi_copyin((void *)dfc->buf1, (void *)cmd_buf, cmd_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to read command buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } /* Send the command */ rval = emlxs_send_menlo_cmd(hba, cmd_buf, cmd_size, rsp_buf, &rsp_size); if (rval == 0) { /* Return the response */ if (ddi_copyout((void *)rsp_buf, (void *)dfc->buf2, rsp_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to write response.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } /* Return the response size */ if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf3, dfc->buf3_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to write response size.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } } done: if (cmd_buf) { kmem_free(cmd_buf, dfc->buf1_size); } if (rsp_buf) { kmem_free(rsp_buf, dfc->buf2_size); } 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; uint32_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 = SWAP_LONG(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, "emlxs_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, "emlxs_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, "emlxs_send_menlo_cmd: Reset with Golden " "firmware requested."); } else { /* MENLO_FW_OPERATIONAL */ value = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "emlxs_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, "emlxs_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, "emlxs_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, "emlxs_send_menlo_cmd: " "Maintenance mode disable requested."); } addr = 0x103107; value = mm_mode; break; default: EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_send_menlo_cmd: " "Invalid command. cmd=%x", cmd_code); rval = DFC_ARG_INVALID; goto done; } if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_send_menlo_cmd: " "Unable to allocate mailbox buffer."); rval = DFC_SYSRES_ERROR; goto done; } mb = (MAILBOX *) mbq; /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mb, addr, value); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0); if (mbxstatus) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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, "emlxs_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, "emlxs_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, "emlxs_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, "emlxs_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 = SWAP_DATA24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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, "emlxs_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, "emlxs_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, "emlxs_send_menlo_cmd: " "Pkt Transport error. Response overrun."); rval = DFC_RSP_BUF_OVERRUN; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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 = SWAP_LONG(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, "emlxs_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 = SWAP_DATA24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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, "emlxs_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, "emlxs_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, "emlxs_send_menlo_cmd: " "Data Pkt Transport " "error. Response overrun."); rval = DFC_RSP_BUF_OVERRUN; } else { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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 = SWAP_DATA24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 = SWAP_LONG(cmd->code); cmd->length = SWAP_LONG(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 = SWAP_LONG(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 = SWAP_LONG(rsp->bb_credit); rsp->frame_size = SWAP_LONG(rsp->frame_size); rsp->fw_version = SWAP_LONG(rsp->fw_version); rsp->reset_status = SWAP_LONG(rsp->reset_status); rsp->maint_status = SWAP_LONG(rsp->maint_status); rsp->fw_type = SWAP_LONG(rsp->fw_type); rsp->fru_data_valid = SWAP_LONG(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 Emulex for repair."); } 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 */ 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 *buffer; 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); } if ((buffer = (uint8_t *)kmem_zalloc(cnt, KM_NOSLEEP)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } if (ddi_copyin((void *)dfc->buf1, (void *)buffer, cnt, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(buffer, cnt); return (DFC_COPYIN_ERROR); } bptr = buffer; for (i = 0; i < cnt; i++) { SBUS_WRITE_FLASH_COPY(hba, offset, *bptr); offset++; bptr++; } kmem_free(buffer, cnt); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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() */ 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 *buffer; 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; } if ((buffer = (uint8_t *)kmem_zalloc(outsz, KM_NOSLEEP)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } bptr = buffer; for (i = 0; i < outsz; i++) { *bptr++ = SBUS_READ_FLASH_COPY(hba, offset++); } if (ddi_copyout((void *)buffer, (void *)dfc->buf1, outsz, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(buffer, outsz); return (DFC_COPYOUT_ERROR); } kmem_free(buffer, outsz); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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() */ 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; } if (ddi_copyin((void *)dfc->buf3, (void *)&destid, sizeof (dfc_destid_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } if (destid.idType == 0) { if ((ndlp = emlxs_node_find_wwpn(port, destid.wwpn)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer, destid.wwpn)); rval = DFC_ARG_INVALID; goto done; } did = ndlp->nlp_DID; } else { if (emlxs_node_find_did(port, destid.d_id) == 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 = SWAP_DATA24_LO(did); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 */ if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } 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; } rsp_size -= pkt->pkt_resp_resid; if (ddi_copyout((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: rsp_buf ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf4, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: rsp_size ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_els() */ 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); } 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 < MAX_RINGS; 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; if (ddi_copyout((void *)&ioinfo, (void *)dfc->buf1, sizeof (dfc_ioinfo_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_ioinfo() */ 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); } 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_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); if (ddi_copyout((void *)&linkinfo, (void *)dfc->buf1, sizeof (dfc_linkinfo_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_linkinfo() */ #ifdef SFCT_SUPPORT 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); } bzero(&dfcstat, sizeof (dfcstat)); 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; } if (ddi_copyout((void *)&dfcstat, (void *)dfc->buf1, sizeof (dfc_tgtport_stat_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_fctstat() */ #endif /* SFCT_SUPPORT */ 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 *dfc_node; dfc_node_t *dnp; uint32_t node_count; NODELIST *nlp; uint32_t size; uint32_t i; port = &VPORT(dfc->data1); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } if (node_count > MAX_NODES) { node_count = MAX_NODES; } size = node_count * sizeof (dfc_node_t); if (!(dfc_node = (dfc_node_t *)kmem_zalloc(size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate dfc_node.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } dnp = dfc_node; rw_enter(&port->node_rwlock, RW_READER); for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { nlp = port->node_table[i]; while (nlp != NULL) { 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; } dnp++; nlp = (NODELIST *) nlp->nlp_list_next; } } rw_exit(&port->node_rwlock); if (ddi_copyout((void *)dfc_node, (void *)dfc->buf1, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(dfc_node, size); return (DFC_COPYOUT_ERROR); } if (ddi_copyout((void *)&node_count, (void *)dfc->buf2, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(dfc_node, size); return (DFC_COPYOUT_ERROR); } kmem_free(dfc_node, size); return (0); } /* emlxs_dfc_get_nodeinfo() */ 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 *buffer; 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 (!(buffer = (uint8_t *)kmem_zalloc(size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } if (hba->flag & FC_SLIM2_MODE) { slim = (uint8_t *)hba->slim2.virt + offset; emlxs_pcimem_bcopy((uint32_t *)slim, (uint32_t *)buffer, size); } else { slim = (uint8_t *)hba->slim_addr + offset; READ_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)slim, (size / 4)); } if (ddi_copyout((void *)buffer, (void *)dfc->buf1, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(buffer, size); return (DFC_COPYOUT_ERROR); } kmem_free(buffer, size); #ifdef FMA_SUPPORT if (!(hba->flag & FC_SLIM2_MODE)) { /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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() */ 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 *buffer; 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 (!(buffer = (uint8_t *)kmem_zalloc(size, KM_NOSLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_SYSRES_ERROR); } if (ddi_copyin((void *)dfc->buf1, (void *)buffer, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(buffer, size); return (DFC_COPYIN_ERROR); } if (hba->flag & FC_SLIM2_MODE) { slim = (uint8_t *)hba->slim2.virt + offset; emlxs_pcimem_bcopy((uint32_t *)buffer, (uint32_t *)slim, size); } else { slim = (uint8_t *)hba->slim_addr + offset; WRITE_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)slim, (size / 4)); } kmem_free(buffer, size); #ifdef FMA_SUPPORT if (!(hba->flag & FC_SLIM2_MODE)) { /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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->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->csr_addr + offset), value); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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() */ 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 (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->csr_addr + offset)); if (ddi_copyout((void *)&value, (void *)dfc->buf1, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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() */ 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; (void) emlxs_get_dfc_event(port, dfc_event, 0); if (dfc->buf1) { if (ddi_copyout((void *)&dfc_event->last_id, dfc->buf1, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } } /* * 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->log_events |= 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->log_events &= ~event; } } return (0); } /* emlxs_dfc_set_event() */ 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)); if (!(event_buffer = (HBA_EVENTINFO *)kmem_zalloc(size, KM_SLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer. size=%d", emlxs_dfc_xlate(dfc->cmd), size); return (DFC_SYSRES_ERROR); } if (emlxs_get_dfc_eventinfo(port, event_buffer, &event_count, &missed) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: emlxs_get_dfc_eventinfo failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_DRV_ERROR; goto done; } if (event_count) { if (ddi_copyout((void *)event_buffer, dfc->buf1, (event_count * sizeof (HBA_EVENTINFO)), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } } if (ddi_copyout((void *)&event_count, dfc->buf2, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } if (ddi_copyout((void *)&missed, dfc->buf3, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } 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() */ 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->log_events & 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; if ((rval = emlxs_get_dfc_event(port, dfc_event, sleep))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: %s. Exiting. pid=%d rsize=%d id=%d rval=%d", emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid, dfc_event->size, dfc_event->last_id, rval); return (rval); } if (dfc->buf2) { if (ddi_copyout((void *)&dfc_event->size, dfc->buf2, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } } if (dfc->buf3) { if (ddi_copyout((void *)&dfc_event->last_id, dfc->buf3, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } } 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; } switch (region) { case 0: /* SLI Registers */ if (size < (4 * sizeof (uint32_t))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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, hba->csr_addr)); wptr[1] = READ_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr)); wptr[2] = READ_CSR_REG(hba, FC_HS_REG(hba, hba->csr_addr)); wptr[3] = READ_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr)); #ifdef FMA_SUPPORT /* Access handle validation */ if (emlxs_fm_check_acc_handle(hba, hba->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->slim2.virt; emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer, size); } else { memptr = (uint8_t *)hba->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->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, "emlxs_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->slim2.virt)->pcb); emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer, size); break; case 3: /* MailBox */ if (size < MAILBOX_CMD_BSIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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->slim2.virt; emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer, size); } else { memptr = (uint8_t *)hba->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->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, "emlxs_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->slim_addr + hba->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->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, "emlxs_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->slim2.virt)->mbx.us.s2.port; emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer, size); break; case 6: /* Command/Response Ring */ if (size < SLI_IOCB_MAX_SIZE) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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->slim2.virt)->IOCBs; emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer, size); break; case 7: /* All driver specific structures */ if (size < sizeof (emlxs_hba_t)) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "emlxs_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, "emlxs_get_dump_region: Invalid region. (id=%d)", region); rval = DFC_ARG_INVALID; } done: *psize = size; return (rval); } /* emlxs_get_dump_region() */ 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; uint8_t *buffer = NULL; 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; } if (!(buffer = (uint8_t *)kmem_zalloc(size, KM_SLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate buffer. size=%d", emlxs_dfc_xlate(dfc->cmd), size); rval = DFC_SYSRES_ERROR; goto done; } /* Get the region data */ rval = emlxs_get_dump_region(hba, dfc->data1, buffer, &size); if (rval != 0) { goto done; } /* Return the region data */ if (ddi_copyout((void *)buffer, (void *) dfc->buf1, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } } /* Return the region size */ if (ddi_copyout((void *) &size, (void *) dfc->buf2, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } done: if (buffer) { kmem_free(buffer, size); } return (rval); } /* emlxs_dfc_get_dump_region() */ #ifdef MENLO_SUPPORT 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); } 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; if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox buffer.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_SYSRES_ERROR; goto done; } mb = (MAILBOX *)mbq; /* SET MENLO maint mode */ /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mb, 0x103107, 1); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, 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 = SWAP_DATA24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 = SWAP_LONG(MENLO_CMD_LOOPBACK); cmd->lb.context = SWAP_LONG(offset); cmd->lb.type = SWAP_LONG(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, mb, 0x103107, 0); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, 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); } 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 = SWAP_DATA24_LO(EMLXS_MENLO_DID); pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_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 = SWAP_LONG(MENLO_CMD_FTE_INSERT); cmd->fte_insert.fcid = SWAP_LONG(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); } 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; if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox buffer.", emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE)); rval = DFC_SYSRES_ERROR; goto done; } mb = (MAILBOX *)mbq; /* RESET MENLO */ /* Create the set_variable mailbox request */ emlxs_mb_set_var(hba, mb, 0x103007, 0); mbq->flag |= MBQ_PASSTHRU; /* issue the mbox cmd to the sli */ mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, 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; /* 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; 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.device_id == PCI_DEVICE_ID_LP21000_M) { 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 */ if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate mailbox buffer.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_SYSRES_ERROR; goto done; } mb = (MAILBOX *) mbq; /* Take the link down */ emlxs_mb_down_link(hba, mb); rval = emlxs_sli_issue_mbox_cmd(hba, mb, 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; } /* Reinitialize the link */ emlxs_mb_init_link(hba, mb, 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, mb, 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; } /* * Wait for adapter to come online. * 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: Linkup timeout.", emlxs_dfc_xlate(dfc->cmd)); goto done; } } /* Create host node */ if (emlxs_mb_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))); 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.device_id == PCI_DEVICE_ID_LP21000_M) { 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 */ /* Create host XRI */ (void) emlxs_create_xri(port, &hba->ring[FC_CT_RING], 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=%x", 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.device_id == PCI_DEVICE_ID_LP21000_M) { 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); } return (rval); } /* emlxs_dfc_loopback_mode() */ static int32_t emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; uint32_t rval = 0; NODELIST *ndlp; clock_t timeout; fc_packet_t *pkt = NULL; SLI_CT_REQUEST *CtCmd; uint16_t CtRsp; 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); 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; } if (!(pkt = emlxs_pkt_alloc(port, dfc->buf1_size + 16, dfc->buf2_size + 16, 0, KM_SLEEP))) { 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 = SWAP_DATA16(CtRsp); if (ddi_copyin((void *)dfc->buf1, (void *)&CtCmd->un.data, dfc->buf1_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } 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_CT_TYPE; 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; if (ddi_copyout((void *)&CtCmd->un.data, (void *)dfc->buf2, dfc->buf2_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } 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() */ extern int32_t emlxs_dfc_handle_event(emlxs_hba_t *hba, RING *rp, 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 (rp->ringno != FC_CT_RING) { HBASTATS.CtStray++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "CT Event: Invalid ring: ring=%d iocbq=%p", rp->ringno, 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, RING *rp, 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); /* * 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 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[8]; uint8_t rwwpn[8]; int32_t rval = 0; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } /* Read the lwwpn */ if (ddi_copyin((void *)dfc->buf1, (void *)&lwwpn, 8, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } /* Read the rwwpn */ if (ddi_copyin((void *)dfc->buf2, (void *)&rwwpn, 8, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } /* Initiate authentication here */ rval = emlxs_dhc_init_auth(hba, lwwpn, rwwpn); return (rval); } /* emlxs_dfc_init_auth() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } /* Read the fcsp_config */ if (ddi_copyin((void *)dfc->buf1, (void *)&fcsp_config, sizeof (dfc_fcsp_config_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } if ((rval = emlxs_dhc_get_auth_cfg(hba, &fcsp_config)) != 0) { return (rval); } if (ddi_copyout((void *)&fcsp_config, (void *)dfc->buf1, sizeof (dfc_fcsp_config_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_auth_cfg() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } /* Read the fcsp_config */ if (ddi_copyin((void *)dfc->buf1, (void *)&fcsp_config, sizeof (dfc_fcsp_config_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } /* Read the password */ if (ddi_copyin((void *)dfc->buf2, (void *)&dfc_pwd, sizeof (dfc_password_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } 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); } if (ddi_copyout((void *)&fcsp_config, (void *)dfc->buf1, sizeof (dfc_fcsp_config_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_set_auth_cfg() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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 */ if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_pwd, sizeof (dfc_auth_password_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } if ((rval = emlxs_dhc_get_auth_key(hba, &dfc_pwd)) != 0) { return (rval); } if (ddi_copyout((void *)&dfc_pwd, (void *)dfc->buf1, sizeof (dfc_auth_password_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_auth_pwd() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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 */ if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_pwd, sizeof (dfc_auth_password_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } if ((rval = emlxs_dhc_set_auth_key(hba, &dfc_pwd))) { return (rval); } if (ddi_copyout((void *)&dfc_pwd, (void *)dfc->buf1, sizeof (dfc_auth_password_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_set_auth_pwd() */ 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; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); 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); } /* Read the fcsp_config */ if (ddi_copyin((void *) dfc->buf1, (void *) &fcsp_status, sizeof (dfc_auth_status_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYIN_ERROR); } if ((rval = emlxs_dhc_get_auth_status(hba, &fcsp_status)) != 0) { return (rval); } if (ddi_copyout((void *) &fcsp_status, (void *) dfc->buf1, sizeof (dfc_auth_status_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); return (DFC_COPYOUT_ERROR); } return (0); } /* emlxs_dfc_get_auth_status() */ static int32_t emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_fcsp_config_t *fcsp_cfg; uint32_t count; uint32_t size; uint32_t rval = DFC_SUCCESS; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); /* 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); } if (ddi_copyout((void *)&hba->auth_cfg_count, (void *)dfc->buf2, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed for table count. count=%d", emlxs_dfc_xlate(dfc->cmd), hba->auth_cfg_count); mutex_exit(&hba->auth_lock); return (DFC_COPYOUT_ERROR); } 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); } size = hba->auth_cfg_count * sizeof (dfc_fcsp_config_t); if (!(fcsp_cfg = (dfc_fcsp_config_t *)kmem_zalloc(size, KM_SLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate table buffer.", emlxs_dfc_xlate(dfc->cmd)); mutex_exit(&hba->auth_lock); return (DFC_SYSRES_ERROR); } if ((rval = emlxs_dhc_get_auth_cfg_table(hba, fcsp_cfg)) != 0) { mutex_exit(&hba->auth_lock); kmem_free(fcsp_cfg, size); return (rval); } mutex_exit(&hba->auth_lock); if (ddi_copyout((void *)fcsp_cfg, (void *)dfc->buf1, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(fcsp_cfg, size); return (DFC_COPYOUT_ERROR); } kmem_free(fcsp_cfg, size); return (0); } /* emlxs_dfc_get_auth_cfg_table() */ static int32_t emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode) { emlxs_port_t *port = &PPORT; dfc_auth_password_t *auth_pwd; uint32_t count; uint32_t size; uint32_t rval = DFC_SUCCESS; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.", emlxs_dfc_xlate(dfc->cmd)); /* 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); } if (ddi_copyout((void *)&hba->auth_key_count, (void *)dfc->buf2, sizeof (uint32_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed for table count. count=%d", emlxs_dfc_xlate(dfc->cmd), hba->auth_key_count); mutex_exit(&hba->auth_lock); return (DFC_COPYOUT_ERROR); } 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); } size = hba->auth_key_count * sizeof (dfc_auth_password_t); if (!(auth_pwd = (dfc_auth_password_t *)kmem_zalloc(size, KM_SLEEP))) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: Unable to allocate table buffer.", emlxs_dfc_xlate(dfc->cmd)); mutex_exit(&hba->auth_lock); return (DFC_SYSRES_ERROR); } if ((rval = emlxs_dhc_get_auth_key_table(hba, auth_pwd)) != 0) { mutex_exit(&hba->auth_lock); kmem_free(auth_pwd, size); return (rval); } mutex_exit(&hba->auth_lock); if (ddi_copyout((void *)auth_pwd, (void *)dfc->buf1, size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); kmem_free(auth_pwd, size); return (DFC_COPYOUT_ERROR); } kmem_free(auth_pwd, size); return (0); } /* emlxs_dfc_get_auth_key_table() */ #endif /* DHCHAP_SUPPORT */ #ifdef SAN_DIAG_SUPPORT static int32_t emlxs_dfc_sd_set_bucket(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(&sd_bucket_mutex); state = sd_bucket.state; mutex_exit(&sd_bucket_mutex); 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 { (void) ddi_copyin(dfc->buf3, (void *) &sd_bucket, sizeof (sd_bucket_info_t), mode); mutex_enter(&sd_bucket_mutex); sd_bucket.state = SD_STOPPED; mutex_exit(&sd_bucket_mutex); } set_bucket_exit: return (rval); } static int32_t emlxs_dfc_sd_destroy_bucket(dfc_t *dfc) { uint32_t type; int32_t rval = DFC_SD_OK; type = dfc->data1; mutex_enter(&sd_bucket_mutex); if (sd_bucket.search_type == 0) rval = DFC_SD_ERROR_BUCKET_NOT_SET; else if (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 *)&sd_bucket, sizeof (sd_bucket_info_t)); destroy_bucket_exit: mutex_exit(&sd_bucket_mutex); return (rval); } static int32_t emlxs_dfc_sd_get_bucket(dfc_t *dfc, int32_t mode) { uint32_t type; int32_t rval = DFC_SD_OK; type = dfc->data1; if (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 (void) ddi_copyout(&sd_bucket, dfc->buf3, sizeof (sd_bucket_info_t), mode); return (rval); } 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 (sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto start_collect_exit; } /* Read the wwn object */ (void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode); /* 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(&sd_bucket_mutex); sd_bucket.state = SD_COLLECTING; mutex_exit(&sd_bucket_mutex); start_collect_exit: return (rval); } 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 (sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto stop_collect_exit; } /* Read the wwn object */ (void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode); /* 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(&sd_bucket_mutex); sd_bucket.state = SD_STOPPED; mutex_exit(&sd_bucket_mutex); stop_collect_exit: return (rval); } 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 (sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto reset_collect_exit; } /* Read the wwn object */ (void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode); /* 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); } 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 (sd_bucket.search_type == 0) { rval = DFC_SD_ERROR_BUCKET_NOT_SET; goto get_data_exit; } /* Read the wwn object */ (void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode); /* 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 */ (void) ddi_copyout((void *)&nlp->nlp_portname, (void *)((char *)dfc->buf4 + skip_bytes), sizeof (HBA_WWN), mode); skip_bytes += sizeof (HBA_WWN); /* copy bucket data */ (void) ddi_copyout((void *)&nlp->sd_dev_bucket[0], (void *)((char *)dfc->buf4 + skip_bytes), sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS, mode); 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: (void) ddi_copyout((void *)&count, (void *)dfc->buf2, sizeof (uint16_t), mode); get_data_exit: return (rval); } 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 */ (void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode); /* 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; (void) emlxs_get_sd_event(vport, dfc_event, 0); if (dfc->buf1) (void) ddi_copyout((void *) &dfc_event->last_id, dfc->buf1, sizeof (uint32_t), mode); vport->sd_reg_events |= 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_reg_events &= ~event; } set_sd_event_exit: return (rval); } /* emlxs_dfc_sd_set_event */ 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 */ (void) ddi_copyin((void *)dfc->buf4, (void *)wwpn, 8, mode); /* 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_reg_events & 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; if (emlxs_get_sd_event(vport, dfc_event, sleep)) return (DFC_SD_ERROR_GENERIC); /* * update rcv_size. */ if (dfc->buf2) (void) ddi_copyout((void *) &dfc_event->size, dfc->buf2, sizeof (uint32_t), mode); /* * update index */ if (dfc->buf3) (void) ddi_copyout((void *) &dfc_event->last_id, dfc->buf3, sizeof (uint32_t), mode); get_sd_event_exit: return (rval); } /* emlxs_dfc_sd_get_event */ #endif 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; } if (ddi_copyin((void *) dfc->buf1, (void *) &cmdinfo, sizeof (dfc_send_scsi_fcp_cmd_info_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } #ifdef NPIV_SUPPORT 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, (uint8_t *)&cmdinfo.src_wwn)); rval = DFC_ARG_INVALID; goto done; } } #endif /* NPIV_SUPPORT */ if ((ndlp = emlxs_node_find_wwpn(port, (uint8_t *)&cmdinfo.dst_wwn)) == NULL) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(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 */ if (ddi_copyin((void *)dfc->buf2, (void *)fcp_cmd, sizeof (FCP_CMND), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_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; /* Build the fc header */ pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(ndlp->nlp_DID); pkt->pkt_cmd_fhdr.r_ctl = FC_FCP_CMND; pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did); pkt->pkt_cmd_fhdr.type = FC_FCP_DATA; 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; if (ddi_copyin((void *)dfc->buf3, (void *)pkt->pkt_data, dfc->buf3_size, mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYIN_ERROR; goto done; } } 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 + SWAP_DATA32(fcp_rsp->rspSnsLen) + SWAP_DATA32(fcp_rsp->rspRspLen); ptr = (void *)fcp_rsp; } else { SCSI_SNS_CNT(cmdinfo) = SWAP_DATA32(fcp_rsp->rspSnsLen); ptr = (void *)&fcp_rsp->rspSnsInfo[0]; } if (ddi_copyout((void *) &cmdinfo, (void *) dfc->buf1, sizeof (dfc_send_scsi_fcp_cmd_info_t), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: rsp_buf ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } if (SCSI_SNS_CNT(cmdinfo)) { if (ddi_copyout(ptr, (void *)dfc->buf4, SCSI_SNS_CNT(cmdinfo), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: rsp_size ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } } if (SCSI_RSP_CNT(cmdinfo)) { if (ddi_copyout((void *)pkt->pkt_data, (void *)dfc->buf3, SCSI_RSP_CNT(cmdinfo), mode) != 0) { EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg, "%s: rsp_size ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd)); rval = DFC_COPYOUT_ERROR; goto done; } } rval = 0; done: if (pkt) { emlxs_pkt_free(pkt); } return (rval); } /* emlxs_dfc_send_scsi_fcp() */ #endif /* DFC_SUPPORT */