/* * Copyright (c) 2011-2015, Emulex * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define IOCTL_BUFSIZE 64*1024 #define DPORT_DYNAMIC_MODE 0x1 #define DPORT_STATIC_MODE 0x2 #define DPORT_QUERY_DYNAMIC_MODE 0x3 static char* format_sli4_ip_address(uint32_t *address); static int ocs_mbox(elxu_device_t *device, mbox_command_t *mboxcmd, uint32_t mboxcmdLength, void *inbuf, uint32_t inbufLength, void *outbuf, uint32_t outbufLength); static int pt_mbox(elxu_device_t *device, mbox_command_t *mboxcmd, uint32_t mboxcmdLength, void *inbuf, uint32_t inbufLength, void *outbuf, uint32_t outbufLength); #define VPD_LARGE_RESOURCE_TYPE_ID_STRING_TAG 0x82 #define VPD_LARGE_RESOURCE_TYPE_R_TAG 0x90 #define VPD_LARGE_RESOURCE_TYPE_W_TAG 0x91 #define VPD_SMALL_RESOURCE_TYPE_END_TAG 0x78 typedef struct { uint8_t *buffer; uint32_t length; uint32_t offset; uint8_t checksum; } vpdbuf_t; static inline int vpddone(vpdbuf_t *vpd) { return vpd->offset >= vpd->length; } static inline int vpdnext(vpdbuf_t *vpd) { int rc = -1; if (vpd->offset < vpd->length) { rc = vpd->buffer[vpd->offset++]; vpd->checksum += rc; } return rc; } static inline uint8_t * vpdref(vpdbuf_t *vpd) { return &vpd->buffer[vpd->offset]; } static inline uint8_t * elx_find_vpd(uint8_t *vpddata, uint32_t vpddata_length, const char *key) { vpdbuf_t vpdbuf; uint8_t *pret = NULL; uint8_t c0 = key[0]; uint8_t c1 = key[1]; vpdbuf.buffer = (uint8_t*) vpddata; vpdbuf.length = vpddata_length; vpdbuf.offset = 0; vpdbuf.checksum = 0; while (!vpddone(&vpdbuf)) { int type = vpdnext(&vpdbuf); int len_lo; int len_hi; int len; int i; if (type == VPD_SMALL_RESOURCE_TYPE_END_TAG) { break; } len_lo = vpdnext(&vpdbuf); len_hi = vpdnext(&vpdbuf); len = len_lo + (len_hi << 8); if ((type == VPD_LARGE_RESOURCE_TYPE_R_TAG) || (type == VPD_LARGE_RESOURCE_TYPE_W_TAG)) { while (len > 0) { int rc0; int rc1; int sublen; uint8_t *pstart; rc0 = vpdnext(&vpdbuf); rc1 = vpdnext(&vpdbuf); /* Mark this location */ pstart = vpdref(&vpdbuf); sublen = vpdnext(&vpdbuf); /* Adjust remaining len */ len -= (sublen + 3); /* check for match with request */ if ((c0 == rc0) && (c1 == rc1)) { pret = pstart; for (i = 0; i < sublen; i++) { vpdnext(&vpdbuf); } /* check for "RV" end */ } else if ('R' == rc0 && 'V' == rc1) { /* Read the checksum */ for (i = 0; i < sublen; i++) { vpdnext(&vpdbuf); } /* The accumulated checksum should be zero here */ if (vpdbuf.checksum != 0) { printf("checksum error\n"); return NULL; } } else for (i = 0; i < sublen; i++) { vpdnext(&vpdbuf); } } } for (i = 0; i < len; i++) { vpdnext(&vpdbuf); } } return pret; } /** * @brief Issue read rev mailbox command * * Create a READ_REV mailbox command * * @param device device descriptor * * @return return zero for success, negative error code for error */ int mbox_read_rev(elxu_device_t *device) { char *value; value = elxu_device_get_value(device, "/ocs/fw_rev"); if (value) { printf("FW Rev: %s\n", value); } value = elxu_device_get_value(device, "/ocs/fw_rev2"); if (value) { printf("FW Rev2: %s\n", value); } value = elxu_device_get_value(device, "/ocs/hw_rev1"); if (value && (strlen(value) > 0)) { printf("HW Rev1: %s\n", value); } value = elxu_device_get_value(device, "/ocs/hw_rev2"); if (value && (strlen(value) > 0)) { printf("HW Rev2: %s\n", value); } value = elxu_device_get_value(device, "/ocs/hw_rev3"); if (value && (strlen(value) > 0)) { printf("HW Rev3: %s\n", value); } return 0; } static void parse_dport_result(mbox_res_fcoe_get_dport_results_t *rsp) { int no_of_desc = ((rsp->hdr.response_length - 16) / 12 ); int i = 0; printf("-------------------------------------------------------------- \n"); printf("Overall Test Result = %d \n", rsp->overall_test_result); printf("Num Phases = %d \n", rsp->num_phases); printf("Local Test Results = %d \n", rsp->local); printf("Remote Test Results = %d \n", rsp->remote); printf("Round Trip Latency = %d \n", rsp->round_trip_latency); printf("Link Distance = %d \n", rsp->link_distance); printf("Frame Size = %d \n", rsp->frame_size); printf("Buffers Required = %d \n\n", rsp->buffers_required); printf("Individual test results \n"); printf("=============================================================== \n"); for(i=0; i < no_of_desc; i++) { fcoe_test_result_descriptor_t *ptr = &(rsp->trd[i]); switch (ptr->test_phase) { case 0xD2: printf("Electrical Loopback Test: "); break; case 0xD3: printf("Optical Loopback Test: "); break; case 0xD4: printf("Reverse Optical Loopback Test: "); break; case 0xD5: printf("Link Traffic Test: "); break; case 0xD6: printf("Reverse Link Traffic Test: "); break; default: printf("Unknown"); } switch (ptr->test_phase_result) { case 0x00: printf("Passed; "); break; case 0x01: printf("Skipped; "); break; case 0x02: printf("Failed; "); break; case 0x03: printf("Stopped; "); break; default: printf("unknown; "); } if(!ptr->err) { printf("Phase Latency = 0x%X \n", ptr->w1); }else { printf("error = 0x%X \n", ptr->w1); } } printf("=============================================================== \n"); } static int mbox_set_link_diag_state(elxu_device_t *device, void *mqe, int enable) { int rval = -1; mbox_sli_config_t *sli_config = mqe; mbox_req_fcoe_set_link_diag_state_t *link_diag_req = mqe + sizeof(mbox_sli_config_t); mbox_res_fcoe_set_link_diag_state_t *link_diag_rsp = (mbox_res_fcoe_set_link_diag_state_t*)link_diag_req; memset(mqe, 0, MBOX_ENTRY_LENGTH); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; /* Embedded, Mbox Cmd data is placed in the 256 MQE */ sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(mbox_req_fcoe_set_link_diag_state_t);; link_diag_req->hdr.opcode = MBOX_SET_LINK_DIAG_STATE; link_diag_req->hdr.subsystem = MBOX_SUBSYSTEM_FCOE; link_diag_req->hdr.timeout = 0; link_diag_req->hdr.request_length = 4; link_diag_req->diag = enable; link_diag_req->div = 1; link_diag_req->link_number = device->phy_port_num; link_diag_req->link_type = 0x1; /* FC Link */ rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, link_diag_req, sizeof (*link_diag_req), link_diag_rsp, sizeof (*link_diag_rsp)); if(rval) { printf("mbox_set_link_diag_state command submission failed \n"); }else { if(link_diag_rsp->hdr.status) { printf("mbox_set_link_diag_state failed with status = %x, additional_status = %x \n", link_diag_rsp->hdr.status, link_diag_rsp->hdr.additional_status); rval = -1; } } return rval; } static int mbox_set_dport_mode(elxu_device_t *device, void *mqe, int mode, int enable) { int rval = -1; mbox_sli_config_t *sli_config = mqe; mbox_req_fcoe_set_dport_mode_t *dport_mode_req = mqe + sizeof(mbox_sli_config_t); mbox_res_fcoe_set_dport_mode_t *dport_mode_rsp = (mbox_res_fcoe_set_dport_mode_t*)dport_mode_req; memset(mqe, 0, MBOX_ENTRY_LENGTH); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; /* Embedded, Mbox Cmd data is placed in the 256 MQE */ sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(mbox_req_fcoe_set_dport_mode_t); dport_mode_req->hdr.opcode = MBOX_SET_DPORT_MODE; dport_mode_req->hdr.subsystem = MBOX_SUBSYSTEM_FCOE; dport_mode_req->hdr.request_length = 20; dport_mode_req->hdr.timeout = 0; dport_mode_req->dport_mode = mode; if (mode == DPORT_DYNAMIC_MODE) { dport_mode_req->enable = enable; } else if (mode == DPORT_STATIC_MODE) { dport_mode_req->stop = enable ? 0 : 1; } dport_mode_req->link_number = device->phy_port_num; dport_mode_req->link_type = 0x1; /* FC Link */ rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, dport_mode_req, sizeof (*dport_mode_req), dport_mode_rsp, sizeof (*dport_mode_rsp)); if(rval) { printf("mbox_set_dport_mode command submission failed \n"); } else { if(dport_mode_rsp->hdr.status) { printf("mbox_set_dport_mode failed with status = %x, additional_status = %x \n", dport_mode_rsp->hdr.status, dport_mode_rsp->hdr.additional_status); rval = -1; } else { /* If mode is query, return resp->enabled status. */ if ((mode == DPORT_QUERY_DYNAMIC_MODE) && (dport_mode_rsp->ev)) { rval = dport_mode_rsp->enabled; } } } return rval; } int mbox_query_dynamic_dport_status(elxu_device_t *device) { char mqe[MBOX_ENTRY_LENGTH]; int rval; rval = mbox_set_dport_mode(device, mqe, DPORT_QUERY_DYNAMIC_MODE, 0); if (rval < 0) { printf("Dport mode query failed \n"); } else { printf("Dynamic dport mode %s for device%d.\n", (rval == 0) ? "disabled" : "enabled", device->phy_port_num); } return rval; } int mbox_set_dynamic_dport(elxu_device_t *device, char *state_str) { char mqe[MBOX_ENTRY_LENGTH]; int rval = -1; int state = 0; if (strcasecmp(state_str, "enable") == 0){ state = 1; } rval = mbox_set_dport_mode(device, mqe, DPORT_DYNAMIC_MODE, state); printf("Set dynamic dport %s %s for device%d.\n", (state == 1) ? "enable" : "disable", (rval == 0) ? "successfull" : "failed", device->phy_port_num); return rval; } /** * @brief Issue Get dport stats mailbox command * Create a GET_DPORT_STAT mailbox command * @return return zero for success, negative error code for error */ int mbox_get_dport_stats(elxu_device_t *device) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_sli_config_t *sli_config = mqe; uint32_t link_status = 0; int rval = -1, dynamic_dport_enabled = 0; int retry = 0; assert(device); if (!mqe) { printf("Failed to alloc memory for mqe\n"); return -1; } printf("Running D_Port Tests. Please wait for 2 minutes. Polling for results \n"); rval = elxu_lancer_get_link_state(device, &link_status); if (rval < 0) { printf("Failed to get link status\n"); goto free_mqe; } /* Step0: Query for the dport dymanic status */ dynamic_dport_enabled = mbox_set_dport_mode(device, mqe, DPORT_QUERY_DYNAMIC_MODE, 0); if (dynamic_dport_enabled < 0) { printf("Failed to get dynamic dport status\n"); goto free_mqe; } if (dynamic_dport_enabled) { rval = mbox_set_dport_mode(device, mqe, DPORT_DYNAMIC_MODE, 0); if (rval < 0) { printf("Failed to reset dynamic dport state\n"); } } /* Step1: Set link to DIAG state */ rval = mbox_set_link_diag_state(device, mqe, 1); if (rval < 0) { printf(" Set link to DIAG state failed \n"); goto exit_mbox_get_dport_stats; } /* Step2: Enable dport mode */ rval = mbox_set_dport_mode(device, mqe, DPORT_STATIC_MODE, 1); if (rval < 0) { printf(" Set link to dport mode failed \n"); goto exit_mbox_get_dport_stats; } /* Step3: Poll dport results */ while(retry < 20) { mbox_req_fcoe_get_dport_results_t *dport_results_req = mqe + sizeof(mbox_sli_config_t); mbox_res_fcoe_get_dport_results_t *dport_results_rsp = (mbox_res_fcoe_get_dport_results_t*)dport_results_req; memset(mqe, 0, MBOX_ENTRY_LENGTH); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; /* Embedded, Mbox Cmd data is placed in the 256 MQE */ sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(mbox_req_fcoe_get_dport_results_t); dport_results_req->hdr.opcode = MBOX_GET_DPORT_RESULTS; dport_results_req->hdr.subsystem = MBOX_SUBSYSTEM_FCOE; dport_results_req->hdr.request_length = 4; dport_results_req->hdr.timeout = 0; dport_results_req->link_number = device->phy_port_num; dport_results_req->link_type = 0x1; /* FC Link */ dport_results_req->query_type = 0; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, dport_results_req, sizeof (*dport_results_req), dport_results_rsp, sizeof(*dport_results_rsp)); if( rval == 0 ) { if(dport_results_rsp->hdr.status == 0) { parse_dport_result(dport_results_rsp); break; } } sleep(10); retry++; } /* Step4: Stop DPORT mode */ rval = mbox_set_dport_mode(device, mqe, DPORT_STATIC_MODE, 0); if (rval < 0) { printf(" Disabling dport mode failed \n"); goto exit_mbox_get_dport_stats; } /* Step5: Set link to Normal mode from Diag mode */ rval = mbox_set_link_diag_state(device, mqe, 0); if (rval < 0) { printf(" Set link to Normal state failed \n"); goto exit_mbox_get_dport_stats; } exit_mbox_get_dport_stats: /* Do function reset even in case of failure. */ rval = elxu_device_exec(device, "/ocs/function_reset", NULL, 0, NULL, 0); if (rval < 0) { printf(" Function reset failed. \n"); } /* Set link to original state */ rval = elxu_lancer_set_link_state(device, &link_status); if (rval < 0) { printf("Failed to set link status\n"); } /* Set the original dynamic dport state */ if (dynamic_dport_enabled) { rval = mbox_set_dport_mode(device, mqe, DPORT_DYNAMIC_MODE, dynamic_dport_enabled); if (rval < 0) { printf("Failed to reset dynamic dport state\n"); } } free_mqe: if (mqe) { zfree(mqe); } return rval; } /** * @brief Issue set link diag loopback mailbox command * * Create a SET_LINK_DIAG_LOOPBACK mailbox command * * @param device device descriptor * @param mqe * @param type loopback test type * * @return return zero for success, negative error code for error */ int mbox_diag_loopback_tests(elxu_device_t *device, int loopback_type, int retry_count) { void *mqe = NULL; int rval = -1, i; uint32_t link_status = 0; assert(device); printf("\n============================================================\n\n"); if (loopback_type == INTERNAL_LOOPBACK) { printf("\nInternal Loopback test started......\n"); } else if (loopback_type == EXTERNAL_LOOPBACK) { printf("\nExternal Loopback test started......\n"); } else if (loopback_type == PCI_LOOPBACK) { printf("\nPCI Loopback test started......\n"); } else { printf("Error: Unsupported Loopback type(%d) provided.\n", loopback_type); printf("Usage(Loopback type)\n1 - Internal Loopback test\n"); printf(" 2 - External Loopback test\n"); printf(" 3 - PCI Loopback test\n"); goto exit_mbox_diag_loopback_tests; } mqe = zmalloc(MBOX_ENTRY_LENGTH); if (!mqe) { printf("Unable to allocate memory for mbox command\n"); goto exit_mbox_diag_loopback_tests; } if (loopback_type != PCI_LOOPBACK) { rval = elxu_lancer_get_link_state(device, &link_status); if (rval < 0) { printf("Failed to get link status\n"); goto exit_mbox_diag_loopback_tests; } /* Step1: Set link to DIAG state */ rval = mbox_set_link_diag_state(device, mqe, 1); if (rval < 0) { printf(" Set link to DIAG state failed \n"); goto exit_mbox_diag_loopback_tests; } /* Step3: Set link into loopback mode */ rval = elxu_lancer_set_loopback(device, NULL, &loopback_type); if (rval) { printf("Please install proper SFP and loopback cable before running tests\n"); mbox_set_link_diag_state(device, mqe, 0); goto exit_mbox_diag_loopback_tests; } printf("Loopback test is in progress. Polling for results.....\n\n"); for (i = 0; i <= retry_count; i++) { sleep(5); rval = elxu_lancer_run_loopback(device, NULL, loopback_type); if (rval < 0) { continue; } else { if (i) { printf("Loopback test passed after %d attempt\n", i+1); } printf(" Results: PASSED\n"); break; } } if (rval) { printf("No loopback cable connected. Please install loopback cable before running the test\n"); printf(" Results: FAILED\n"); } rval = mbox_set_link_diag_state(device, mqe, 0); if (rval < 0) { printf(" Set link to Normal state failed \n"); goto exit_mbox_diag_loopback_tests; } /* Set link to original state */ rval = elxu_lancer_set_link_state(device, &link_status); if (rval < 0) { printf("Failed to set link status\n"); goto exit_mbox_diag_loopback_tests; } } else { printf("PCI Loopback test is in progress. Polling for results.....\n\n"); for (i = 0; i <= retry_count; i++) { rval = elxu_lancer_run_loopback(device, NULL, loopback_type); if (rval < 0) { continue; } else { if (i) { printf("Loopback test passed after %d attempt\n", i+1); } printf(" Results: PASSED\n"); break; } sleep(2); } if (rval) { printf(" Results: FAILED\n"); } } exit_mbox_diag_loopback_tests: printf("============================================================\n\n"); if (mqe) { zfree(mqe); } return rval; } /** * @brief Issue read link status mailbox command * * Create a READ_LNK_STAT mailbox command * * @param device device descriptor * @param clof clear overflow flag * @param clrc clear all counters floag * * @return return zero for success, negative error code for error */ int mbox_read_link_status(elxu_device_t *device, int clof, int clrc) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_read_link_status_t *read_link_status = mqe; int rval = -1; assert(device); if (!mqe) goto done; read_link_status->command = MBOX_READ_LNK_STAT; read_link_status->clof = clof; read_link_status->clrc = clrc; read_link_status->rec = 1; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, 0, 0, 0, 0); if (rval < 0) { zfree(mqe); return rval; } /* printf("GEC: %d\n", read_link_status->gec); printf("W02Of: %d\n", read_link_status->w02of); printf("W03Of: %d\n", read_link_status->w03of); printf("W04Of: %d\n", read_link_status->w04of); printf("W05Of: %d\n", read_link_status->w05of); printf("W06Of: %d\n", read_link_status->w06of); printf("W07Of: %d\n", read_link_status->w07of); printf("W08Of: %d\n", read_link_status->w08of); printf("W09Of: %d\n", read_link_status->w09of); printf("W10Of: %d\n", read_link_status->w10of); printf("W11Of: %d\n", read_link_status->w11of); printf("W12Of: %d\n", read_link_status->w12of); printf("W13Of: %d\n", read_link_status->w13of); printf("W14Of: %d\n", read_link_status->w14of); printf("W15Of: %d\n", read_link_status->w15of); printf("W16Of: %d\n", read_link_status->w16of); printf("W17Of: %d\n", read_link_status->w17of); printf("W18Of: %d\n", read_link_status->w18of); printf("W19Of: %d\n", read_link_status->w19of); printf("W20Of: %d\n", read_link_status->w20of); printf("W21Of: %d\n", read_link_status->w21of); */ printf("\n"); printf("Loss of Sync error count: %d\n", read_link_status->loss_of_sync_error_count); printf("Loss of signal error count: %d\n", read_link_status->loss_of_signal_error_count); printf("Primitive sequence error count: %d\n", read_link_status->primitive_sequence_error_count); printf("Invalid TX word error count: %d\n", read_link_status->invalid_transmission_word_error_count); printf("CRC error count: %d\n", read_link_status->crc_error_count); printf("Primitive sequence event timeout count: %d\n", read_link_status->primitive_sequence_event_timeout_count); printf("Elastic buffer overrun error count: %d\n", read_link_status->elastic_buffer_overrun_error_count); printf("Arbitration (FC-AL) timeout-out count: %d\n", read_link_status->arbitration_timeout_count); printf("Advertised RX buffer-to-buffer credit: %d\n", read_link_status->advertised_receive_buffer_to_buffer_credit); printf("Current RX buffer-to-buffer credit: %d\n", read_link_status->current_receive_buffer_to_buffer_credit); printf("Advertised TX buffer-to-buffer credit: %d\n", read_link_status->advertised_transmit_buffer_to_buffer_credit); printf("Current TX buffer-to-buffer count: %d\n", read_link_status->current_transmit_buffer_to_buffer_credit); printf("RX EOFa count: %d\n", read_link_status->received_eofa_count); printf("RX EOFdti count: %d\n", read_link_status->received_eofdti_count); printf("RX EOFni count: %d\n", read_link_status->received_eofni_count); printf("RX SOFf count: %d\n", read_link_status->received_soff_count); printf("RX dropped no AER count: %d\n", read_link_status->received_dropped_no_aer_count); printf("RX dropped no available RPI resources count: %d\n", read_link_status->received_dropped_no_available_rpi_resources_count); printf("RX dropped no avialable XRI resources count: %d\n", read_link_status->received_dropped_no_available_xri_resources_count); printf("NOS count: %d\n", read_link_status->link_failure_error_count); printf("Error frames: %d\n", read_link_status->crc_error_count); printf(" Link failure error count: %d\n", read_link_status->link_failure_error_count); printf(" CRC error count: %d\n", read_link_status->crc_error_count); printf(" Received EOFa count: %d\n", read_link_status->received_eofa_count); printf(" Received EOFni count: %d\n", read_link_status->received_eofni_count); printf(" Received LRR count: %d\n", read_link_status->lrr_count_local); printf(" Received LR count: %d\n", read_link_status->lr_count_remote); printf(" LIP count: %s\n", elxu_device_get_value(device, "/ocs/lip_count")); printf(" Active RPI count: %s\n", elxu_device_get_value(device, "/ocs/active_rpi_count")); printf(" Active XRI count: %s\n", elxu_device_get_value(device, "/ocs/active_xri_count")); done: zfree(mqe); return rval; } /** * @brief Issue read status mailbox command * * Create a READ_STATUS mailbox command * * @param device device descriptor * @param clear_counter clear counter flag * * @return return zero for success, negative error code for error */ int mbox_read_status(elxu_device_t *device, uint32_t clear_counter) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_read_status_t *read_status = mqe; int rval = -1; assert(device); if (!mqe) goto done; read_status->command = MBOX_READ_STATUS; read_status->cc = clear_counter; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, 0, 0, 0, 0); if (rval < 0) { zfree(mqe); return rval; } printf("\n"); printf(" TX KBytes: %u\n", read_status->transmit_kbyte_count); printf(" RX KBytes: %u\n", read_status->receive_kbyte_count); printf(" TX Frames: %u\n", read_status->transmit_frame_count); printf(" RX Frames: %u\n", read_status->receive_frame_count); printf(" TX Bytes: %u\n", read_status->transmit_kbyte_count * 1024); printf(" RX Bytes: %u\n", read_status->receive_kbyte_count * 1024); printf(" TX Words: %u\n", read_status->transmit_kbyte_count * 256); printf(" RX Words: %u\n", read_status->receive_kbyte_count * 256); printf(" TX Sequences: %u\n", read_status->transmit_sequence_count); printf(" RX Sequences: %u\n", read_status->receive_sequence_count); printf("Total exchanges (Originator): %d\n", read_status->total_exchanges_originator); printf("Total exchanges (Responder): %d\n", read_status->total_exchanges_responder); printf("RX P_BSY count: %d\n", read_status->receive_p_bsy_count); printf("RX F_BSY count: %d\n", read_status->receive_f_bsy_count); // these fields seem not supported yet? /* printf("Dropped frames due to no RQ buffer count: %d\n", read_status->dropped_frames_due_to_no_rq_buffer_count); printf("Empty RQ timeout count: %d\n", read_status->empty_rq_timeout_count); printf("Dropped frames due to no XRI count: %d\n", read_status->dropped_frames_due_to_no_xri_count); printf("Empty XRI pool count: %d\n", read_status->empty_xri_pool_count); */ done: zfree(mqe); return rval; } /** * @brief Issue IOCTL_COMMON_ENABLE_DISABLE_PORT command * * create IOCTL_COMMON_ENABLE_DISABLE_PORT mailbox command * * @param device device descriptor * @param port_status ENABLE (1) or DISABLE (0) * * @return return zero for success, negative error code for error */ int mbox_ioctl_common_enable_disable_port(elxu_device_t *device, uint32_t port_status) { int rval=-1; void *mqe = NULL; sli4_ioctl_common_enable_disable_port_t *mbox = NULL; mbox_sli_config_t *sli_config = NULL; uint32_t request_Len = sizeof(sli4_ioctl_common_enable_disable_port_t) - sizeof(sli4_ioctl_header_t); assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (!mqe) return rval; sli_config = mqe; mbox = mqe + sizeof(mbox_sli_config_t); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; // Embedded sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(*mbox); mbox->hdr.req.opcode = OPCODE_COMMON_ENABLE_DISABLE_PORT; mbox->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; mbox->hdr.req.timeout = 0; mbox->hdr.req.request_length = request_Len; mbox->port_status = port_status; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, mbox, request_Len, mbox, request_Len); if (rval != 0) { printf ("Error: rval %d\n", rval); } else if (sli_config->status) { printf ("status 0x%02X addl 0x%02X\n", sli_config->status, mbox->hdr.res.additional_status); rval = -1; } zfree(mqe); return rval; } /** * @brief Issue IOCTL_COMMON_SET_BE_CONFIGRATION_AND_RESOURCES command * * create IOCTL_COMMON_SET_BE_CONFIGURATION_AND_RESOURCES mailbox command * * @param device device descriptor * @param mac_addr new MAC address * * @return return zero for success, negative error code for error */ int mbox_ioctl_common_set_be_configuration_and_resources(elxu_device_t *device, int *mac_addr) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_sli_config_t *sli_config = mqe; uint32_t request_Len = sizeof(sli4_ioctl_common_set_be_configuration_and_resources_t) - sizeof(sli4_ioctl_header_t); int rval = -1; sli4_ioctl_common_set_be_configuration_and_resources_t *set_mbox; assert(device); if (!mqe) goto done; set_mbox = mqe + sizeof(mbox_sli_config_t); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(*set_mbox); // set_be_configuration_and_resources set_mbox->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; set_mbox->hdr.req.opcode = OPCODE_COMMON_SET_BE_CONFIGURATION_AND_RESOURCES; set_mbox->hdr.req.version = 1; set_mbox->hdr.req.request_length = request_Len; set_mbox->resource_descriptor_count = 1; set_mbox->be_resources[0].resource_type = 0x2; set_mbox->be_resources[0].resource_descriptor.pf_num = device->deviceIndex + 2; set_mbox->be_resources[0].resource_descriptor.vf_domain = 0xFF; set_mbox->be_resources[0].resource_descriptor.valid_fields = 0; set_mbox->be_resources[0].resource_descriptor.session_count = UINT16_MAX; set_mbox->be_resources[0].resource_descriptor.icd_count = UINT16_MAX; set_mbox->be_resources[0].resource_descriptor.cq_count = UINT16_MAX; set_mbox->be_resources[0].resource_descriptor.iscsi_mac_address[0] = (uint8_t)mac_addr[0]; set_mbox->be_resources[0].resource_descriptor.iscsi_mac_address[1] = (uint8_t)mac_addr[1]; set_mbox->be_resources[0].resource_descriptor.iscsi_mac_address[2] = (uint8_t)mac_addr[2]; set_mbox->be_resources[0].resource_descriptor.iscsi_mac_address[3] = (uint8_t)mac_addr[3]; set_mbox->be_resources[0].resource_descriptor.iscsi_mac_address[4] = (uint8_t)mac_addr[4]; set_mbox->be_resources[0].resource_descriptor.iscsi_mac_address[5] = (uint8_t)mac_addr[5]; set_mbox->be_resources[0].resource_descriptor.mcc_queue_count = -1; set_mbox->be_resources[0].resource_descriptor.bw_percent = -1; set_mbox->be_resources[0].resource_descriptor.vlan_id = -1; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, set_mbox, request_Len, set_mbox, request_Len); if (rval != 0) { printf ("Error: rval %d\n", rval); } else if (sli_config->status) { printf ("status 0x%02X addl 0x%02X, MAC address may already be used\n", sli_config->status, set_mbox->hdr.res.additional_status); rval = -1; } done: zfree(mqe); return rval; } /** * @brief Soft assign MAC */ int mbox_soft_assign_mac(elxu_device_t *device, int *macaddr) { mbox_ioctl_common_enable_disable_port(device, DISABLE); mbox_ioctl_common_set_be_configuration_and_resources(device, macaddr); mbox_ioctl_common_enable_disable_port(device, ENABLE); return 0; } void mbox_get_mac_pt(elxu_device_t *device, uint8_t *mac_addr) { uint32_t mbox_words[256]; sli4_req_common_get_function_config_t *config_req; sli4_res_common_get_function_config_t *config_res; elx_pt_ioctl_mbox_t mbox; int rc; int i; int fd; if (device == NULL) { return; } if (mac_addr == NULL) { return; } fd = device->fd; bzero(mac_addr, 6); bzero(&mbox_words, sizeof(mbox_words)); config_res = (sli4_res_common_get_function_config_t *)&mbox_words; config_req = (sli4_req_common_get_function_config_t *)&mbox_words; config_req->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; config_req->hdr.req.opcode = OPCODE_COMMON_GET_FUNCTION_CONFIG; config_req->hdr.req.request_length = sizeof(mbox_words); if (is_skyhawk(device)) { config_req->hdr.req.version = 1; } else { config_req->hdr.req.version = 0; } mbox.words = (uint32_t *)config_req; mbox.num_words = (sizeof(mbox_words) + 3) / 4; rc = ioctl(fd, IOCTL_CMD_ELX_PT_MBOX, &mbox); if (rc == 0) { if (config_res->hdr.res.status == 0) { switch(config_res->desc[0] & 0xff) { case 0x41: /* NIC v0 */ { sli4_nic_resource_descriptor_v0_t *desc; desc = (sli4_nic_resource_descriptor_v0_t *) &config_res->desc[0]; for (i=0; i<6; i++) { mac_addr[i] = desc->mac_address[i]; } } break; case 0x51: /* NIC v1 */ { sli4_nic_resource_descriptor_v1_t *desc; desc = (sli4_nic_resource_descriptor_v1_t *) &config_res->desc[0]; for (i=0; i<6; i++) { mac_addr[i] = desc->mac_address[i]; } } break; case 0x52: /* iSCSI v1 */ { sli4_iscsi_resource_descriptor_v1_t *desc; desc = (sli4_iscsi_resource_descriptor_v1_t *) &config_res->desc[0]; for (i=0; i<6; i++) { mac_addr[i] = desc->mac_address[i]; } } break; default: break; } } } } void mbox_get_wwn_pt(int fd, uint8_t *wwnn, uint8_t *wwpn) { mbox_rw_nvparms_t req; elx_pt_ioctl_mbox_t mbox; int rc; bzero(wwnn, 8); bzero(wwpn, 8); bzero(&req, sizeof(req)); req.command = MBOX_READ_NVPARMS; mbox.words = (uint32_t *) &req; mbox.num_words = (sizeof(req) + 3) / 4; rc = ioctl(fd, IOCTL_CMD_ELX_PT_MBOX_FC, &mbox); if (rc == 0) { if (req.status == 0) { memcpy(wwnn, req.wwnn, sizeof(req.wwnn)); memcpy(wwpn, req.wwpn, sizeof(req.wwpn)); } } } int mbox_get_serialnum_pt(elxu_device_t *device, char *serial_num, int serial_num_size) { mbox_read_rev_t read_rev; elx_pt_ioctl_mbox_t mbox; int rc = 0; memref_t *dma_mem = NULL; bzero(&read_rev, sizeof(read_rev)); read_rev.command = MBOX_READ_REV; dma_mem = elx_pt_dma_alloc(device, 4096); if (dma_mem == NULL) { printf("%s: Failed to allocate DMA memory\n", __func__); return -1; } read_rev.vpd = 1; read_rev.available_length = dma_mem->size; read_rev.physical_address_low = (uint32_t)(dma_mem->paddr & 0xffffffffUL); read_rev.physical_address_high = (uint32_t)(dma_mem->paddr >> 32); mbox.words = (uint32_t *) &read_rev; mbox.num_words = (sizeof(read_rev) + 3) / 4; rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX_FC, &mbox); if (!rc && !read_rev.status) { int serial_num_len = 0; uint8_t *pserial = NULL; pserial = elx_find_vpd(dma_mem->vaddr,read_rev.returned_vpd_length, "SN"); if (pserial) { serial_num_len = *pserial++; if (serial_num_len > serial_num_size) serial_num_len = sizeof(serial_num); memcpy((uint8_t *)serial_num, pserial, serial_num_len); } } if (dma_mem) elx_pt_dma_free(dma_mem); return rc; } int mbox_set_nv_mac_pt(elxu_device_t *device, int *macaddr) { uint32_t mbox_words[1024]; elx_pt_ioctl_mbox_t mbox; sli4_req_common_get_profile_config_t *get_req; sli4_res_common_get_profile_config_t *get_res; sli4_req_common_set_profile_config_t *set_req; sli4_res_common_set_profile_config_t *set_res; char *p; int pf; int rc; uint32_t *desc_pointer; int i; int type; int len; uint8_t *mac_pointer; uint8_t *temp_descriptor = NULL; /* * For Skyhawk, need to send a COMMON_SET_PROFILE_CONFIG_V1. * For Lancer NIC we need to send COMMON_SET_PROFILE_CONFIG_V0 * The resource profile will need to be either a NIC profile or a * iSCSI profile depending on the type of port we're talking to. * * The ISAP bit needs to be off. * The NOSV bit needs to be off to make the change non-volatile. * Profile ID will be 0, indicating the current profile. */ /* Get the PCI function from the bus address */ p = strrchr(device->bus_addr, '.'); if (p == NULL) { /* Can't determine PCI function from bus address */ goto fail; } ++p; pf = strtol(p, NULL, 10); /* Send a COMMON_GET_PROFILE_CONFIG to the correct function */ bzero(&mbox_words, sizeof(mbox_words)); get_req = (sli4_req_common_get_profile_config_t *) mbox_words; get_req->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; get_req->hdr.req.opcode = OPCODE_COMMON_GET_PROFILE_CONFIG; if (is_skyhawk(device)) { get_req->hdr.req.version = 1; } else { get_req->hdr.req.version = 0; } get_req->hdr.req.request_length = sizeof(mbox_words); /* * NOTE: pf 0 means "all functions". To get data for one function you * need to use pf+1. */ get_req->hdr.req.pf_number = pf+1; get_req->typ = 0x01; /* Factory Default */ mbox.words = mbox_words; mbox.num_words = ARRAY_SIZE(mbox_words); rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX, &mbox); if (rc != 0) { goto fail; } get_res = (sli4_res_common_get_profile_config_t *) mbox_words; if (get_res->hdr.res.status != 0) { printf("Status is %d\n", get_res->hdr.res.status); printf("Addl status: 0x%x\n", get_res->hdr.res.additional_status); goto fail; } desc_pointer = (uint32_t *)get_res->desc; /* * Extract the NIC or iSCSI descriptor from the response. * Find the descriptor that contains the MAC address. For an * iSCSI function there should be one iSCSI descriptor. For * a NIC function there will be two descriptors - we want the * one that does not have the VFT bit set. */ mac_pointer = NULL; for (i=0; idesc_count; i++) { type = *desc_pointer & 0x000000ff; /* * Version 1 descriptors are variable length, with the length in the * second byte of the first word. Version 0 descriptors are fixed * at 72 bytes. */ if (is_skyhawk(device)) { len = (*desc_pointer & 0x0000ff00) >> 8; } else { len = 72; } if (type == 0x51) { /* NIC descriptor */ sli4_nic_resource_descriptor_v1_t *descriptor; descriptor = (sli4_nic_resource_descriptor_v1_t *) desc_pointer; if (descriptor->vft == 0) { mac_pointer = (uint8_t*) descriptor->mac_address; break; } } else if (type == 0x52) { /* iSCSI descriptor */ sli4_iscsi_resource_descriptor_v1_t *descriptor; descriptor = (sli4_iscsi_resource_descriptor_v1_t *) desc_pointer; mac_pointer = (uint8_t*) descriptor->mac_address; break; } else if (type == 0x41) { /* V0 NIC descriptor */ sli4_nic_resource_descriptor_v0_t *descriptor; descriptor = (sli4_nic_resource_descriptor_v0_t *) desc_pointer; mac_pointer = (uint8_t*) descriptor->mac_address; break; } desc_pointer += (len / sizeof(uint32_t)); } if (mac_pointer == NULL) { /* Didn't find the expected descriptor with a MAC address */ goto fail; } /* Modify the MAC address field */ for (i=0;i<6;i++) { mac_pointer[i] = macaddr[i]; } /* * The modified descriptor is sitting in the mbox word array. * Because we're about to build a new mailbox command we need * to save off this modified descriptor. */ temp_descriptor = malloc(len); if (temp_descriptor == NULL) { goto fail; } memcpy(temp_descriptor, (uint8_t *)desc_pointer, len); /* Send the descriptor back with COMMON_SET_PROFILE_CONFIG */ set_req = (sli4_req_common_set_profile_config_t *)mbox_words; bzero(&mbox_words, sizeof(mbox_words)); set_req->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; set_req->hdr.req.opcode = OPCODE_COMMON_SET_PROFILE_CONFIG; if (is_skyhawk(device)) { set_req->hdr.req.version = 1; } else { set_req->hdr.req.version = 0; } set_req->hdr.req.request_length = sizeof(mbox_words); set_req->desc_count = 1; memcpy((uint8_t *)set_req->desc, temp_descriptor, len); rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX, &mbox); if (rc != 0) { goto fail; } set_res = (sli4_res_common_set_profile_config_t *) mbox_words; if (set_res->hdr.res.status != 0) { printf("Status is %d\n", get_res->hdr.res.status); printf("Addl status: 0x%x\n", get_res->hdr.res.additional_status); goto fail; } free(temp_descriptor); return 0; fail: if (temp_descriptor) free(temp_descriptor); return -1; } /** * @brief Issue a set non-volatile WWNN/WWPN * * Create a WRITE NVPARAMS mailbox command * * @param device device descriptor * @param wwn world-wide name * @param name WWNN/WWPN flag to set * * @return return zero for success, negative error code for error */ int mbox_set_nv_wwn_pt(elxu_device_t *device, char *wwpn_p, char *wwnn_p) { elx_pt_ioctl_mbox_fc_t mbox; mbox_rw_nvparms_t req; int rc; bzero(&req, sizeof(req)); req.command = MBOX_READ_NVPARMS; mbox.words = (uint32_t *) &req; mbox.num_words = ((sizeof(req) + 3) / 4); rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX_FC, &mbox); if (rc != 0 || req.status != 0) { return -1; } if (wwpn_p != NULL) { rc = sscanf(wwpn_p, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &(req.wwpn[0]), &(req.wwpn[1]), &(req.wwpn[2]), &(req.wwpn[3]), &(req.wwpn[4]), &(req.wwpn[5]), &(req.wwpn[6]), &(req.wwpn[7])); if (rc != 8) { printf(" Invalid WWPN: %s\n", wwpn_p); return -1; } } if (wwnn_p != NULL) { rc = sscanf(wwnn_p, "%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", &(req.wwnn[0]), &(req.wwnn[1]), &(req.wwnn[2]), &(req.wwnn[3]), &(req.wwnn[4]), &(req.wwnn[5]), &(req.wwnn[6]), &(req.wwnn[7])); if (rc != 8) { printf(" Invalid WWNN: %s\n", wwnn_p); return -1; } } req.command = MBOX_WRITE_NVPARMS; rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX_FC, &mbox); if (rc != 0 || req.status != 0) { return -1; } return 0; } /** * @brief Issue read flashrom mailbox command * * Create a SLI_CONFIG Read Flashrom mailbox command * * @param device device descriptor * @param opcode READ/WRITE_FLASHROM opcode value * @param optype READ/WRITE_FLASHROM optype value * @param optype READ/WRITE_FLASHROM offset value * @param outbuf output buffer * @param outbufLength length in bytes of output buffer * * @return return zero for success, negative error code for error */ int mbox_read_flashrom(elxu_device_t *device, uint32_t opcode, uint32_t optype, uint32_t offset, void *outbuf, uint32_t outbufLength) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_sli_config_t *sli_config = mqe; mbox_common_read_flashrom_t *mbox = zmalloc(sizeof(*mbox)); mbox_common_read_flashrom_t *rsp; int rval = -1; uint32_t localOutbufLength; void *localOutbuf = NULL; assert(device); if (!mqe) goto done; if (!mbox) goto done; // Need to allocate a read buffer that's big enough for the response localOutbufLength = outbufLength + sizeof(*mbox); localOutbuf = zmalloc(localOutbufLength); if (!localOutbuf) goto done; rsp = (mbox_common_read_flashrom_t*)localOutbuf; sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 0; sli_config->pcmd_count = 1; sli_config->payload_length = localOutbufLength; sli_config->sge[0].address_low = ~0; sli_config->sge[0].address_high = ~0; sli_config->sge[0].length = localOutbufLength; mbox->common.subsystem = MBOX_SUBSYSTEM_COMMON; mbox->common.opcode = OPCODE_COMMON_READ_FLASHROM; mbox->common.word1.out.timeout = 0; mbox->common.request_length = outbufLength + 0x14; mbox->flashrom_access_op_code = opcode; mbox->flashrom_access_op_type = optype; mbox->data_buffer_size = outbufLength; mbox->offset = offset; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, (uint8_t*)mbox, sizeof (*mbox), localOutbuf, localOutbufLength); if (rval < 0) { zfree(mqe); return rval; } rval = rsp->common.word1.in.status; if (rval) { rval = -rval; } else { if (outbuf) memcpy(outbuf, ((uint8_t*)localOutbuf) + sizeof (*mbox), outbufLength); } done: zfree(localOutbuf); zfree(mbox); zfree(mqe); return rval; } /** * @brief Issue write flashrom mailbox command * * @param device device descriptor * @param opcode READ/WRITE_FLASHROM opcode value * @param optype READ/WRITE_FLASHROM optype value * @param optype READ/WRITE_FLASHROM offset value * @param inbuf input buffer * @param inbufLength length in bytes of input buffer * * @return return zero for success, negative error code for error */ int mbox_write_flashrom(elxu_device_t *device, uint32_t opcode, uint32_t optype, uint32_t offset, void *inbuf, uint32_t inbufLength) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_sli_config_t *sli_config = mqe; mbox_common_read_flashrom_t *mbox = NULL; mbox_common_read_flashrom_t *rsp = zmalloc(sizeof(*rsp)); int rval = -1; uint32_t localInbufLength = sizeof(*mbox) + inbufLength; assert(device); mbox = zmalloc(localInbufLength); if (!mqe) goto done; if (!rsp) goto done; if (!mbox) goto done; sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 0; sli_config->pcmd_count = 1; sli_config->payload_length = localInbufLength; sli_config->sge[0].address_low = ~0; sli_config->sge[0].address_high = ~0; sli_config->sge[0].length = localInbufLength; mbox->common.subsystem = MBOX_SUBSYSTEM_COMMON; mbox->common.opcode = OPCODE_COMMON_WRITE_FLASHROM; mbox->common.word1.out.timeout = 0; mbox->common.request_length = inbufLength + 0x14; mbox->flashrom_access_op_code = opcode; mbox->flashrom_access_op_type = optype; mbox->data_buffer_size = inbufLength; mbox->offset = offset; // Copy write payload if (inbuf) memcpy(&mbox[1], inbuf, inbufLength); rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, (uint8_t*)mbox, localInbufLength, (uint8_t*)rsp, sizeof(*rsp)); if (rval < 0) { zfree(mqe); return rval; } rval = rsp->common.word1.in.status; if (rval) { rval = -rval; } else { if (inbuf) memcpy(inbuf, &rsp[1], inbufLength); } done: zfree(mbox); zfree(rsp); zfree(mqe); return rval; } /** * @brief Issue COMMON_MANAGE_FAT mailbox commands * * This function issues Manage FAT mailbox commands. There are four supported operations: * * FAT_OPERATION_RETRIEVE read the FAT contents * FAT_OPERATION_QUERY return the length of the FAT (may be zero) * FAT_OPERATION_CLEAR clear the FAT * FAT_OPERATION_TRIGGER trigger a UE that will append to FAT * * @param device device descriptor * @param fat_opration requested FAT operation * @param read_log_offset read offset (for FAT_OPERATION_RETRIEVE) * @param buffer read buffer (for FAT_OPERATION_RETRIEVE) * @param bufferLength read buffer length in bytes (for FAT_OPERATION_RETRIEVE) * * @returns number of bytes read for FAT_OPERATION_RETRIEVE, or negative error code * @returns length of FAT for FAT_OPERATION_QUERY, or negative error code * @returns 0, or negative error code for FAT_OPERATION_CLEAR, FAT_OPERATION_TRIGGER */ int mbox_manage_fat(elxu_device_t *device, uint32_t fat_operation, uint32_t read_log_offset, void *buffer, uint32_t bufferLength) { void *mqe = zmalloc(MBOX_ENTRY_LENGTH); mbox_sli_config_t *sli_config = mqe; mbox_common_manage_fat_t *mbox = zmalloc(sizeof(*mbox)); mbox_common_manage_fat_t *rsp; int rval = -1; uint32_t localBufferLength; void *localBuffer = NULL; assert(device); if (!mqe) goto done; if (!mbox) goto done; // Need to allocate a read buffer that's big enough for the response localBufferLength = bufferLength + sizeof(*mbox); localBuffer = zmalloc(localBufferLength); if (!localBuffer) goto done; rsp = (mbox_common_manage_fat_t*)localBuffer; sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 0; sli_config->pcmd_count = 1; sli_config->payload_length = localBufferLength; sli_config->sge[0].address_low = ~0; sli_config->sge[0].address_high = ~0; sli_config->sge[0].length = localBufferLength; mbox->common.subsystem = MBOX_SUBSYSTEM_COMMON; mbox->common.opcode = OPCODE_COMMON_MANAGE_FAT; mbox->common.word1.out.timeout = 0; mbox->common.request_length = bufferLength + 0x14; mbox->params.request.fat_operation = fat_operation; mbox->params.request.read_log_offset = read_log_offset; mbox->params.request.read_log_length = bufferLength; mbox->params.request.data_buffer_size = bufferLength; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, (uint8_t*)mbox, sizeof (*mbox), localBuffer, localBufferLength); if (rval < 0) { zfree(mqe); return rval; } rval = rsp->common.word1.in.status; if (rval) { printf ("status 0x%02X addl 0x%02X\n", rsp->common.word1.in.status, rsp->common.word1.in.additional_status); rval = -rval; } else { switch (fat_operation) { case FAT_OPERATION_RETRIEVE: if (buffer) memcpy(buffer, ((uint8_t*)localBuffer) + sizeof (*mbox), bufferLength); // fall through case FAT_OPERATION_QUERY: rval = rsp->params.response.log_size; break; case FAT_OPERATION_CLEAR: case FAT_OPERATION_TRIGGER: break; } } done: zfree(localBuffer); zfree(mbox); zfree(mqe); return rval; } /** * @brief Issue EFD mailbox command * * Submits the mailbox command given by 'mbox' for 'mboxLength'. Note, that 'mboxLength' * will generally include a response payload * * @param device device descriptor * @param opcode common mailbox opcode * @param mbox pointer to common mailbox command + payload * @param mboxLength length of mailbox command + payload * * @return 0 if successful, a negative error code for failure */ int mbox_ext_fat(elxu_device_t *device, uint32_t opcode, void *mbox, uint32_t mboxLength) { void *mqe = NULL; mbox_common_t *hdr = NULL; mbox_sli_config_t *sli_config = NULL; mbox_common_t *rsp = NULL; int rval = -1; assert(device); assert(mbox); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (!mqe) return -1; sli_config = mqe; sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 0; // Not Embedded, Mbox Cmd data is a part of a payload buffer sli_config->pcmd_count = 1; sli_config->payload_length = mboxLength; sli_config->sge[0].address_low = ~0; sli_config->sge[0].address_high = ~0; sli_config->sge[0].length = mboxLength; hdr = mbox; hdr->subsystem = MBOX_SUBSYSTEM_COMMON; hdr->opcode = opcode; hdr->word1.out.timeout = 0; hdr->request_length = mboxLength; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, mbox, mboxLength, mbox, mboxLength); if (rval < 0) { zfree(mqe); return rval; } rsp = mbox; rval = rsp->word1.in.status; if (rval) { printf ("Error: status 0x%02X addl 0x%02X\n", rsp->word1.in.status, rsp->word1.in.additional_status); rval = -rval; } zfree(mqe); return rval; } /** * @brief Issue the Set TCP Parameters mbox command * * @param device device descriptor * @param request_flags flags indicating which values should be updated * @param ackFrequency ACK frequency * @param delayedAckTimerValue delayed ACK timer value, in milliseconds * * @return 0 if successful, a negative error code for failure */ int mbox_tcp_parameters(elxu_device_t *device, uint32_t request_flags, uint32_t ackFrequency, uint32_t delayedAckTimerValue) { void *mqe; mbox_sli_config_t *sli_config; mbox_common_iscsi_set_tcp_parameters_t *mbox = NULL; int request_len = sizeof(mbox_common_iscsi_set_tcp_parameters_t) - sizeof(mbox_common_t); int rval = -1; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (!mqe) { return -1; } sli_config = (mbox_sli_config_t *) mqe; mbox = (mbox_common_iscsi_set_tcp_parameters_t*)(&sli_config[1]); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; sli_config->pcmd_count = 1; sli_config->payload_length = sizeof(*mbox); mbox->common.subsystem = MBOX_SUBSYSTEM_COMMON_ISCSI; mbox->common.opcode = OPCODE_COMMON_ISCSI_SET_TCP_PARAMETERS; mbox->common.word1.out.timeout = 0; mbox->common.request_length = request_len; mbox->params.request.request_flags = request_flags; mbox->params.request.delayed_ack_timer = delayedAckTimerValue; mbox->params.request.ack_frequency = ackFrequency; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, mbox, request_len, mbox, request_len); if (sli_config->status) { printf("sli status 0x%02x, mbox status 0x%02X, mbox addl 0x%02X\n", sli_config->status, mbox->common.word1.in.status, mbox->common.word1.in.additional_status); rval = -1; } zfree(mqe); return rval; } /* * @brief Issue the Connection Update mbox command * * @param device device descriptor * @param request_flags flags indicating which values should be updated * @param constrainWindowValue number of bytes by which to reduce the TCP window size * * @return 0 if successful, a negative error code for failure */ int mbox_connection_update(elxu_device_t *device, uint32_t request_flags, uint16_t connectionId, uint32_t constrainWindowValue) { void *mqe; mbox_sli_config_t *sli_config; mbox_common_iscsi_connection_update_t *mbox = NULL; int request_len = sizeof(mbox_common_iscsi_connection_update_t); int rval = -1; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (!mqe) { return -1; } sli_config = (mbox_sli_config_t *) mqe; mbox = (mbox_common_iscsi_connection_update_t*)(&sli_config[1]); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(*mbox); mbox->common.subsystem = MBOX_SUBSYSTEM_COMMON_ISCSI; mbox->common.opcode = OPCODE_COMMON_ISCSI_CONNECTION_UPDATE; mbox->common.word1.out.timeout = 0; mbox->common.request_length = request_len; mbox->params.request.request_flags = request_flags; mbox->params.request.connection_id = connectionId; mbox->params.request.window_reduction = constrainWindowValue; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, mbox, request_len, mbox, request_len); if (sli_config->status) { printf("sli status 0x%02x, mbox status 0x%02X, mbox addl 0x%02X\n", sli_config->status, mbox->common.word1.in.status, mbox->common.word1.in.additional_status); rval = -1; } zfree(mqe); return rval; } /** * @brief Get connection info * * @param device device descriptor * @param connection the handle of the connection for which info is requested * * Only supported on Skyhawk * * @return 0 if successful, a negative error code for failure */ int mbox_get_connection_info(elxu_device_t *device, uint32_t connectionHandle) { void *mqe; mbox_sli_config_t *sli_config; mbox_common_iscsi_get_connection_info_t *mbox = NULL; int request_len = sizeof(mbox_common_iscsi_get_connection_info_t) - sizeof(mbox_common_t); int rval = -1; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (!mqe) { return -1; } sli_config = (mbox_sli_config_t *) mqe; mbox = (mbox_common_iscsi_get_connection_info_t*)(&sli_config[1]); sli_config->command = MBOX_SLI_CONFIG; sli_config->emb = 1; sli_config->pcmd_count = 0; sli_config->payload_length = sizeof(*mbox); mbox->common.subsystem = MBOX_SUBSYSTEM_COMMON_ISCSI; mbox->common.opcode = OPCODE_COMMON_ISCSI_GET_CONNECTION_INFO; mbox->common.word1.out.timeout = 0; mbox->common.request_length = request_len; mbox->params.request.connection_handle = connectionHandle; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, mbox, request_len, mbox, request_len); switch (sli_config->status) { case 0: // Success, report results printf(" Connection Handle: 0x%x\n", connectionHandle); printf(" Source Address: %s\n", format_sli4_ip_address(mbox->params.response.source_ip_address)); printf(" Source Port: %d\n", mbox->params.response.source_port); printf(" Dest Address: %s\n", format_sli4_ip_address(mbox->params.response.dest_ip_address)); printf(" Dest Port: %d\n", mbox->params.response.dest_port); printf(" MSS: %d\n", mbox->params.response.tcp_mss); printf(" Interface Handle: 0x%08x\n", mbox->params.response.interface_handle); printf(" Window Scale Shift Count: %d\n", mbox->params.response.window_scale_shift_count); rval = 0; break; case 0x20: // Invalid connection handle printf("%x is not a valid connection handle\n", connectionHandle); rval = -1; break; default: // Some other error printf("sli status 0x%02x, mbox status 0x%02X, mbox addl 0x%02X\n", sli_config->status, mbox->common.word1.in.status, mbox->common.word1.in.additional_status); rval = -1; break; } zfree(mqe); return rval; } static mbox_linkcfg_map_t mbox_linkcfg_str[] = { {OCS_CONFIG_LINKCFG_4X10G, CLP_LINKCFG_4X10G}, {OCS_CONFIG_LINKCFG_1X40G, CLP_LINKCFG_1X40G}, {OCS_CONFIG_LINKCFG_2X16G, CLP_LINKCFG_2X16G}, {OCS_CONFIG_LINKCFG_4X8G, CLP_LINKCFG_4X8G}, {OCS_CONFIG_LINKCFG_4X1G, CLP_LINKCFG_4X1G}, {OCS_CONFIG_LINKCFG_2X10G, CLP_LINKCFG_2X10G}, {OCS_CONFIG_LINKCFG_2X10G_2X8G, CLP_LINKCFG_2X10G_2X8G} }; /** * @brief Get the CLP string from the mgmt config string. * * @param mgmt_str mgmt string. * * @return Returns the CLP string corresponding to mgmt_str. */ static const char * mbox_get_clp_from_mgmt_linkcfg_str(char *mgmt_str) { uint32_t i; for (i = 0; i < ARRAY_SIZE(mbox_linkcfg_str); i++) { if (strncmp(mbox_linkcfg_str[i].mgmt_str, mgmt_str, strlen(mgmt_str)) == 0) { return mbox_linkcfg_str[i].clp_str; } } return NULL; } /** * @brief Get the mgmt config string from the CLP string. * * @param clp_str clp string. * * @return Returns the mgmt string corresponding to clp_str. */ static char * mbox_get_mgmt_from_clp_linkcfg_str(char *clp_str) { uint32_t i; for (i = 0; i < ARRAY_SIZE(mbox_linkcfg_str); i++) { if (strncmp(mbox_linkcfg_str[i].clp_str, clp_str, strlen(clp_str) - 2) == 0) { return mbox_linkcfg_str[i].mgmt_str; } } return NULL; } char *mbox_get_linkcfg_lancer_pt(elxu_device_t *device) { sli4_res_dmtf_exec_clp_cmd_t *response = NULL; sli4_req_dmtf_exec_clp_cmd_t *request; mbox_sli_config_t *sli_config = NULL; memref_t *clp_response = NULL; memref_t *clp_command = NULL; static char result[80]; void *mqe = NULL; char *resp_str; char *mgmt_str; int rval = -1; int rc; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { goto err; } clp_command = elx_pt_dma_alloc(device, 80); if (clp_command == NULL) { goto err; } clp_response = elx_pt_dma_alloc(device, 256); if (clp_response == NULL) { goto err; } response = zmalloc(sizeof(sli4_res_dmtf_exec_clp_cmd_t)); if (response == NULL) { goto err; } snprintf(clp_command->vaddr, 80, "show / OEMELX_LinkConfig"); sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_dmtf_exec_clp_cmd_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_DMTF; request->hdr.req.opcode = OPCODE_DMTF_EXEC_CLP_CMD; request->hdr.req.request_length = sizeof(*request) - sizeof(sli4_ioctl_header_t); request->cmd_buf_length = 80; request->cmd_buf_addr_high = addr32_hi(clp_command->paddr); request->cmd_buf_addr_low = addr32_lo(clp_command->paddr); request->resp_buf_length = 256; request->resp_buf_addr_high = addr32_hi(clp_response->paddr); request->resp_buf_addr_low = addr32_lo(clp_response->paddr); rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, sizeof(*request), response, sizeof(*response)); rc = response->hdr.res.status; if (rval != 0 || rc != 0) { printf("Status %02x:%02x\n", response->hdr.res.status, response->hdr.res.additional_status); printf("clp_status = %02X, clp_addl_status = %02X\n", response->clp_status, response->clp_detailed_status); printf("Mbox write failed\n"); goto err; } /* Parse the response */ resp_str = strstr(clp_response->vaddr, "endoutput"); if (resp_str == NULL) { printf("Parse failure\n"); goto err; } *resp_str = '\0'; resp_str = strstr(clp_response->vaddr, "retdata"); if (resp_str == NULL) { printf("Parse failure\n"); goto err; } resp_str += 8; mgmt_str = mbox_get_mgmt_from_clp_linkcfg_str(resp_str); if (mgmt_str != NULL && strlen(mgmt_str) < sizeof(result)) { strncpy(result, mgmt_str, sizeof(result)); } else { strncpy(result, "UNKNOWN", sizeof(result)); } elx_pt_dma_free(clp_response); elx_pt_dma_free(clp_command); /* Returning a static variable */ return result; err: if (response != NULL) { zfree(response); } if (clp_response != NULL) { elx_pt_dma_free(clp_response); } if (clp_command != NULL) { elx_pt_dma_free(clp_command); } if (mqe != NULL) { zfree(mqe); } return NULL; } char *mbox_get_linkcfg_skyhawk_pt(elxu_device_t *device) { sli4_res_get_reconfig_link_info_t *response = NULL; sli4_req_get_reconfig_link_info_t *request; mbox_sli_config_t *sli_config = NULL; static char linkcfg_str[32]; size_t response_len; void *mqe = NULL; int rval = -1; uint32_t i; int rc; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { goto err; } /* Allocate a buffer big enough for the response, including * MAX_LINK_CONFIG_DESCRIPTORS link descriptors. */ response_len = sizeof(sli4_res_get_reconfig_link_info_t) + MAX_LINK_CONFIG_DESCRIPTORS * sizeof(sli4_link_config_descriptor_t); response = zmalloc(response_len); if (response == NULL) { goto err; } sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_get_reconfig_link_info_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; request->hdr.req.opcode = OPCODE_COMMON_GET_RECONFIG_LINK_INFO; request->hdr.req.request_length = response_len; rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, sizeof(*request), response, response_len); rc = response->hdr.res.status; if (rval != 0 || rc != 0) { printf("Status %02x:%02x\n", response->hdr.res.status, response->hdr.res.additional_status); printf("Mbox write failed\n"); goto err; } strncpy(linkcfg_str, "UNKNOWN", sizeof(linkcfg_str)); for (i = 0; i < response->link_config_desc_count; i++) { if (response->desc[i].link_config_id == response->active_link_config_id) { memcpy(linkcfg_str, response->desc[i].config_description, sizeof(response->desc[i].config_description)); goto err; } } err: if (response != NULL) { zfree(response); } if (mqe != NULL) { zfree(mqe); } /* Returning a static variable */ return linkcfg_str; } /** * @brief Get Link configuration * * @par Description * Get Link configuration information via passthrough driver * * @param device device descriptor * * @return 0 if successful, a negative error code for failure */ char *mbox_get_linkcfg_pt(elxu_device_t *device) { char *linkcfg_str = NULL; if (is_lancer(device)) { linkcfg_str = mbox_get_linkcfg_lancer_pt(device); } else if(is_skyhawk(device)) { linkcfg_str = mbox_get_linkcfg_skyhawk_pt(device); } return linkcfg_str; } int mbox_set_linkcfg_lancer_pt(elxu_device_t *device, char *config) { sli4_res_dmtf_exec_clp_cmd_t *response = NULL; sli4_req_dmtf_exec_clp_cmd_t *request; mbox_sli_config_t *sli_config = NULL; memref_t *clp_response = NULL; memref_t *clp_command = NULL; const char *linkcfg_str; void *mqe = NULL; int clp_status; char *resp_str; int rval = -1; int rc; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { goto err; } clp_command = elx_pt_dma_alloc(device, 80); if (clp_command == NULL) { goto err; } clp_response = elx_pt_dma_alloc(device, 80); if (clp_response == NULL) { goto err; } response = zmalloc(sizeof(sli4_res_dmtf_exec_clp_cmd_t)); if (response == NULL) { goto err; } /* translate mgmt linkcfg string to CLP string */ linkcfg_str = mbox_get_clp_from_mgmt_linkcfg_str(config); snprintf(clp_command->vaddr, 80, "set / OEMELX_LinkConfig=%s", linkcfg_str); sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_dmtf_exec_clp_cmd_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_DMTF; request->hdr.req.opcode = OPCODE_DMTF_EXEC_CLP_CMD; request->hdr.req.request_length = sizeof(*request) - sizeof(sli4_ioctl_header_t); request->cmd_buf_length = 80; request->cmd_buf_addr_high = addr32_hi(clp_command->paddr); request->cmd_buf_addr_low = addr32_lo(clp_command->paddr); request->resp_buf_length = 80; request->resp_buf_addr_high = addr32_hi(clp_response->paddr); request->resp_buf_addr_low = addr32_lo(clp_response->paddr); rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, sizeof(*request), response, sizeof(*response)); rc = response->hdr.res.status; if (rval != 0 || rc != 0) { printf("Status %02x:%02x\n", response->hdr.res.status, response->hdr.res.additional_status); printf("clp_status = %#X, clp_addl_status = %0#X\n", response->clp_status, response->clp_detailed_status); printf("Mbox write failed\n"); goto err; } /* Parse the response */ resp_str = strstr(clp_response->vaddr, "status="); if (resp_str == NULL) { printf("Parse failure\n"); rval = -1; goto err; } resp_str += 7; clp_status = atoi(resp_str); if (clp_status != 0) { printf("Device returned status %d when setting link config.\n", clp_status); rval = -1; goto err; } err: if (response != NULL) { zfree(response); } if (clp_response != NULL) { elx_pt_dma_free(clp_response); } if (clp_command != NULL) { elx_pt_dma_free(clp_command); } if (mqe != NULL) { zfree(mqe); } return rval; } /** * @brief Mapping from mgmt string to Skyhawk config IDs * * This structure provides a mapping from the management string * (exposed to set-linkcfg) to the Skyhawk config IDs sent via * SET_RECONFIG_LINK_INFO command */ typedef struct mbox_skyhawk_linkcfg_map_s { char *mgmt_str; uint32_t config_id; } mbox_skyhawk_linkcfg_map_t; /** * @brief Mapping from mgmt string to Skyhawk config IDs */ static mbox_skyhawk_linkcfg_map_t mbox_skyhawk_linkcfg_map[] = { {OCS_CONFIG_LINKCFG_4X10G, 0x0a}, {OCS_CONFIG_LINKCFG_1X40G, 0x09} }; /** * @brief Get the config ID from the mgmt config string. * * @param mgmt_str mgmt string value. * * @return Returns the config ID value corresponding to mgmt_str. */ static uint32_t mbox_get_config_id_from_mgmt_str(char *mgmt_str) { uint32_t i; for (i = 0; i < ARRAY_SIZE(mbox_skyhawk_linkcfg_map); i++) { if (strncmp(mbox_skyhawk_linkcfg_map[i].mgmt_str, mgmt_str, strlen(mgmt_str)) == 0) { return mbox_skyhawk_linkcfg_map[i].config_id; } } return 0; } int mbox_set_linkcfg_skyhawk_pt(elxu_device_t *device, char *config) { sli4_res_set_reconfig_link_info_t *response = NULL; sli4_req_set_reconfig_link_info_t *request; mbox_sli_config_t *sli_config = NULL; void *mqe = NULL; int rval = -1; int rc = -1; assert(device); mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { goto err; } response = zmalloc(sizeof(sli4_res_set_reconfig_link_info_t)); if (response == NULL) { goto err; } sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_set_reconfig_link_info_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; request->hdr.req.opcode = OPCODE_COMMON_SET_RECONFIG_LINK_INFO; request->hdr.req.request_length = sizeof(*request) - sizeof(sli4_ioctl_header_t); request->next_link_config_id = mbox_get_config_id_from_mgmt_str(config); rval = mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, sizeof(*request), response, sizeof(*response)); rc = response->hdr.res.status; if (rval != 0 || rc != 0) { printf("Status %02x:%02x\n", response->hdr.res.status, response->hdr.res.additional_status); printf("Mbox write failed\n"); } err: if (response != NULL) { zfree(response); } if (mqe != NULL) { zfree(mqe); } return rc; } /** * @brief Set Link configuration * * @par Description * Sends a set_linkcfg command via passthrough driver * * @param device device descriptor * @param config new link configuration string * * @return 0 if successful, a negative error code for failure */ int mbox_set_linkcfg_pt(elxu_device_t *device, char *config) { int rc = -1; if (is_lancer(device)) { rc = mbox_set_linkcfg_lancer_pt(device, config); } else if(is_skyhawk(device)) { rc = mbox_set_linkcfg_skyhawk_pt(device,config); } return rc; } int create_vport(elxu_device_t *device_p, uint64_t wwnn, uint64_t wwpn, int targetFlag, int initiatorFlag) { ocs_ioctl_vport_t vport; int rc; memset(&vport, 0, sizeof(vport)); vport.req_create = 1; vport.enable_tgt = targetFlag; vport.enable_ini = initiatorFlag; vport.wwnn = wwnn; vport.wwpn = wwpn; rc = elxu_ioctl_device(device_p, OCS_IOCTL_CMD_VPORT, &vport); if (rc) { fprintf(stderr, "vport creation failed\n"); } return rc; } int remove_vport(elxu_device_t *device_p, uint64_t wwnn, uint64_t wwpn, int targetFlag, int initiatorFlag) { ocs_ioctl_vport_t vport; int rc; memset(&vport, 0, sizeof(vport)); vport.req_create = 0; vport.enable_tgt = targetFlag; vport.enable_ini = initiatorFlag; vport.wwnn = wwnn; vport.wwpn = wwpn; rc = elxu_ioctl_device(device_p, OCS_IOCTL_CMD_VPORT, &vport); if (rc) { perror("ioctl"); } return rc; } /** * @brief Given a 6-word IP address in the format specified in the SLI4 spec, return a printable IP address. * * @param address A pointer to an IP address in an array of six 32-bit words * * @return a pointer to a static array containing a printable IP address */ static char* format_sli4_ip_address(uint32_t *address) { static char ret[40]; int address_type; uint8_t *address_bytes = (uint8_t *)address; address_type = address_bytes[3]; // TODO: These IP type numbers should be #defines somewhere if (address_type < 3) { /* Print the IP address in IPV4 format */ sprintf(ret, "%d.%d.%d.%d", address_bytes[4], address_bytes[5], address_bytes[6], address_bytes[7]); } else { /* Print the IP address in IPV6 format */ sprintf(ret,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", address_bytes[4], address_bytes[5], address_bytes[6], address_bytes[7], address_bytes[8], address_bytes[9], address_bytes[10], address_bytes[11], address_bytes[12], address_bytes[13], address_bytes[14], address_bytes[15], address_bytes[16], address_bytes[17], address_bytes[18], address_bytes[19]); } return ret; } /** * @brief Send a mailbox command * * Populates a mailbox command passing input and output buffer to the device * * For SLI_CONFIG commands with non-embedded command, the command should be * put in the inbuf, the mboxcmd will point to just the SLI_CONFIG command + * buffer descriptor * * @param device device descriptor * @param mboxcmd pointer to mailbox command data * @param mboxcmdLength length of mailbox command in bytes * @param inbuf input buffer * @param inbufLength length in bytes of input buffer in bytes * @param outbuf output buffer * @param outbufLength length in bytes of output buffer in bytes * @param timeout the mailbox timeout for the command to be carried out * * @return return zero for success, negative error code for error */ int mbox_common(elxu_device_t *device, mbox_command_t *mboxcmd, uint32_t mboxcmdLength, void *inbuf, uint32_t inbufLength, void *outbuf, uint32_t outbufLength) { if (device == NULL) { return -1; } if (device->driver == DEVICE_DRIVER_OCS) { return ocs_mbox(device, mboxcmd, mboxcmdLength, inbuf, inbufLength, outbuf, outbufLength); } else if (device->driver == DEVICE_DRIVER_PT) { return pt_mbox(device, mboxcmd, mboxcmdLength, inbuf, inbufLength, outbuf, outbufLength); } else { return -1; } } static int pt_mbox(elxu_device_t *device, mbox_command_t *mboxcmd, uint32_t mboxcmdLength, void *inbuf, uint32_t inbufLength, void *outbuf, uint32_t outbufLength) { uint8_t *request; int rc; if (mboxcmd->request.command == MBOX_SLI_CONFIG) { elx_pt_ioctl_mbox_t mbox; /* * For a SLI_CONFIG command we can just send inbuf * to the elx_pt driver using the ELX_PT_MBOX ioctl. * The driver will handle creating a SLI_CONFIG MQE * and allocating DMA buffers. */ request = malloc(inbufLength); if (request == NULL) { return -1; } memcpy(request, inbuf, inbufLength); mbox.num_words = (inbufLength + (sizeof(uint32_t)-1)) / sizeof(uint32_t); mbox.words = (uint32_t *)request; rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX, &mbox); memcpy(outbuf, request, outbufLength); free(request); } else { elx_pt_ioctl_mbox_fc_t mbox; /* * The command is not a SLI_CONFIG. Just send it * as-is with ELX_PT_MBOX_FC */ request = malloc(mboxcmdLength); if (request == NULL) { return -1; } memcpy(request, &(mboxcmd->request), mboxcmdLength); mbox.num_words = (mboxcmdLength + 3) / 4; mbox.words = (uint32_t *)request; rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_MBOX_FC, &mbox); memcpy(&(mboxcmd->response), request, mboxcmdLength); free(request); } return rc; } static int ocs_mbox(elxu_device_t *device, mbox_command_t *mboxcmd, uint32_t mboxcmdLength, void *inbuf, uint32_t inbufLength, void *outbuf, uint32_t outbufLength) { int rval = -1; ocs_ioctl_elxu_mbox_t cmd; memset(&cmd, 0, sizeof(ocs_ioctl_elxu_mbox_t)); cmd.magic = ELXU_BSD_MAGIC; cmd.size = sizeof(ocs_ioctl_elxu_mbox_t); if (mboxcmdLength > sizeof(cmd.payload)) { printf("%s: mboxcmd too big (actual=%d allowed=%zu)\n", __func__, mboxcmdLength, sizeof(cmd.payload)); return -1; } memcpy(cmd.payload, mboxcmd, mboxcmdLength); switch (mboxcmd->request.command) { case MBOX_SLI_CONFIG: cmd.in_addr = (uint64_t)inbuf; cmd.in_bytes = inbufLength; cmd.out_addr = (uint64_t)outbuf; cmd.out_bytes = outbufLength; break; case MBOX_READ_REV: case MBOX_READ_STATUS: case MBOX_RUN_BIU_DIAG: case MBOX_READ_LNK_STAT: break; default: printf("%s, command %x not supported.\n", __func__, mboxcmd->request.command); break; } rval = elxu_ioctl_device(device, OCS_IOCTL_CMD_ELXU_MBOX, &cmd); if (rval < 0) { perror("ioctl"); } memcpy(mboxcmd, cmd.payload, mboxcmdLength); return rval; } /** * @brief Request a DMA allocation through elx_pt * * @par Description * Requests a DMA buffer allocation from the driver. * * @param device device structure * @param size Size of the requested buffer in bytes * * @return a pointer to a new memref_t on success, NULL on failure */ memref_t *elx_pt_dma_alloc(elxu_device_t *device, int size) { int rc; elx_pt_ioctl_dma_alloc_t dma_alloc; memref_t *memref; long pagesize; pagesize = sysconf(_SC_PAGESIZE); memref = malloc(sizeof(memref_t)); if (memref == NULL) { return NULL; } dma_alloc.req_size = size; rc = ioctl(device->fd, IOCTL_CMD_ELX_PT_DMA_ALLOC, &dma_alloc); if (rc != 0) { free(memref); return NULL; } memref->vaddr = mmap(NULL, ROUNDUP(size, pagesize), PROT_READ | PROT_WRITE, MAP_SHARED, device->fd, dma_alloc.tag * pagesize); if (memref->vaddr == MAP_FAILED) { perror("mmap"); elx_pt_ioctl_dma_free_t dma_free; memset(&dma_free, 0, sizeof(dma_free)); dma_free.tag = dma_alloc.tag; (void)ioctl(device->fd, IOCTL_CMD_ELX_PT_DMA_FREE, &dma_free); free(memref); memref = NULL; } else { memref->paddr = dma_alloc.paddr; memref->tag = dma_alloc.tag; memref->device = device; memref->size = size; } return memref; } /** * @brief Free a DMA allocation through elx_pt * * @par Description * Sends a DMA free request to the driver. * * @param memref The memref_t to be freed. * * @return nothing */ void elx_pt_dma_free(memref_t* memref) { elx_pt_ioctl_dma_free_t dma_free; long pagesize; pagesize = sysconf(_SC_PAGESIZE); if (memref == NULL) { return; } if (memref->vaddr != NULL) { munmap(memref->vaddr, ROUNDUP(memref->size, pagesize)); memset(&dma_free, 0, sizeof(dma_free)); dma_free.tag = memref->tag; ioctl(memref->device->fd, IOCTL_CMD_ELX_PT_DMA_FREE, &dma_free); } free(memref); } int mbox_fw_reset_pt(elxu_device_t *device, int dd) { uint32_t value; int i; if (is_lancer(device)) { /* Set the FRST bit */ value = SLI4_PHYSDEV_CONTROL_FRST; if (dd) { value |= SLI4_PHYSDEV_CONTROL_DD; } os_bar_write32(device, 0, SLI4_PHYSDEV_CONTROL, value); sleep(1); os_bar_read32(device, 0, SLI4_SLIPORT_STATUS, &value); /* Wait for SLIPORT_STATUS RDY */ if (dd) { i = 3000; } else { i = 1000; } while (i > 0) { os_bar_read32(device, 0, SLI4_SLIPORT_STATUS, &value); if (value & SLI4_SLIPORT_STATUS_RDY) { break; } usleep(10000); --i; } if (!(value & SLI4_SLIPORT_STATUS_RDY)) { printf("Timed out waiting for SLIPORT_STATUS RDY\n"); goto fail; } /* Wait for SLIPORT_SEMAPHORE ready */ i = 1000; while (i > 0) { os_bar_read32(device, 0, SLI4_SLIPORT_SEMAPHORE_LAN, &value); if ((value & SLI4_SLIPORT_PORT_STATUS_MASK) == SLI4_PORT_READY) { break; } usleep(10000); --i; } if ((value & SLI4_SLIPORT_PORT_STATUS_MASK) != SLI4_PORT_READY) { printf("Timed out waiting for SLIPORT_SEMAPHORE\n"); goto fail; } /* Wait for BMBX ready */ i = 1000; while (i > 0) { os_bar_read32(device, 0, SLI4_BMBX, &value); if (value & SLI4_BMBX_RDY) { break; } usleep(10000); --i; } if (!(value & SLI4_BMBX_RDY)) { printf("Timed out waiting for BMBX RDY\n"); goto fail; } /* Re-initialize */ mbox_sli4_init_pt(device); } else { /* Read the SOFT_RESET_CSR */ os_cfg_read32(device, SLI4_PCI_SOFT_RESET_CSR, &value); /* Set the SOFT_RESET bit */ value |= SLI4_PCI_SOFT_RESET_MASK; /* Write the value back to the SOFT_RESET_CSR */ os_cfg_write32(device, SLI4_PCI_SOFT_RESET_CSR, value); /* Wait for SLIPORT_SEMAPHORE ready */ i = 3000; while (i > 0) { os_bar_read32(device, 1, SLI4_SLIPORT_SEMAPHORE_SH, &value); if ((value & SLI4_SLIPORT_PORT_STATUS_MASK) == SLI4_PORT_READY) { break; } usleep(10000); --i; } /* Wait for BMBX ready */ i = 1000; while (i > 0) { os_bar_read32(device, 2, SLI4_BMBX, &value); if ((value & SLI4_BMBX_RDY)) { break; } usleep(10000); --i; } /* Send FW INIT */ mbox_sli4_init_pt(device); } return 0; fail: return -1; } int mbox_sli4_init_pt(elxu_device_t *device) { int i; uint32_t words[2]; uint32_t value; if (is_lancer(device)) { /* Write IP bit in SLIPORT_CONTROL */ os_bar_write32(device, 0, SLI4_SLIPORT_CONTROL, SLI4_SLIPORT_CONTROL_IP); /* Wait for SLIPORT_STATUS RDY */ i = 1000; while (i > 0) { os_bar_read32(device, 0, SLI4_SLIPORT_STATUS, &value); if (value & SLI4_SLIPORT_STATUS_RDY) { break; } usleep(10000); --i; } if (!(value & SLI4_SLIPORT_STATUS_RDY)) { printf("Timeout waiting for RDY\n"); } } else { words[0] = 0xff1234ff; words[1] = 0xff5678ff; mbox_common(device, (mbox_command_t *)words, sizeof(words), NULL, 0, NULL, 0); } return 0; } int mbox_get_profile_list_pt(elxu_device_t *device, char *result, int result_len) { sli4_res_common_get_profile_list_t *response = NULL; sli4_req_common_get_profile_list_t *request; void *mqe; mbox_sli_config_t *sli_config = NULL; size_t mbox_size; int rc = -1; assert(device); if (device->driver != DEVICE_DRIVER_PT) { return -1; } mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { return -1; } /* Allocate a buffer big enough for the response, including up to * 40 profile descriptors */ mbox_size = sizeof(sli4_res_common_get_profile_list_t) + 40 * (sizeof(sli4_profile_descriptor_t)); response = zmalloc(mbox_size); if (response == NULL) { goto err; } sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_common_get_profile_list_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; request->hdr.req.opcode = OPCODE_COMMON_GET_PROFILE_LIST; request->hdr.req.request_length = mbox_size; request->start_profile_index = 0; mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, mbox_size, response, mbox_size); rc = response->hdr.res.status; if (rc == 0) { int i; int remaining_len = result_len; char description[MAX_DESCRIPTION + 8]; result[0] = '\0'; for (i = 0; i < response->desc_count; i++) { snprintf(description, sizeof(description), "0x%02x: %s\n", response->desc[i].profile_id, response->desc[i].profile_description_string); if (remaining_len <= strlen(description)) { break; } strncat(result, description, remaining_len); remaining_len -= strlen(description); } } err: if (response != NULL) { zfree(response); } if (mqe != NULL) { zfree(mqe); } return rc; } int mbox_get_active_profile_pt(elxu_device_t *device, char *result, int result_len) { sli4_res_common_get_active_profile_t *response = NULL; sli4_req_common_get_active_profile_t *request; void *mqe; mbox_sli_config_t *sli_config = NULL; int rc = -1; assert(device); if (device->driver != DEVICE_DRIVER_PT) { return -1; } mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { return -1; } response = zmalloc(sizeof(sli4_res_common_get_active_profile_t)); if (response == NULL) { goto err; } sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_common_get_active_profile_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; request->hdr.req.opcode = OPCODE_COMMON_GET_ACTIVE_PROFILE; request->hdr.req.request_length = sizeof(*request) - sizeof(sli4_ioctl_header_t); mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, sizeof(*response), response, sizeof(*response)); rc = response->hdr.res.status; if (rc == 0) { char profile_list[5 * 1024]; char *result_p; char active_profile_str[8]; /* * We now have the current active profile's index, in response->active_profile_id. * In order to get the description for that profile we have to do a * get_profile_list to get the list of all of the possible profiles. */ rc = mbox_get_profile_list_pt(device, profile_list, sizeof(profile_list)); if (rc == 0) { /* * profile_list now has the list of all possible profiles, formatted * for printing. We need to find the current profile ID among that * list. */ sprintf(active_profile_str, "0x%02x:", response->active_profile_id); /* * active_profile_str is the printable form of the current index. * eg: if current profile is 0x13, active profile id is "0x13: " */ /* Locate the current profile index in the list */ result_p = strstr(profile_list, active_profile_str); if (result_p != NULL) { /* * result_p now points to the first character in the list * for the entry that we want. We now have to find the * end of that line and terminate the string there. */ char *c = strchr(result_p, '\n'); if (c != NULL) { *c = '\0'; strncpy(result, result_p, result_len); } else { /* Couldn't find the end of the line */ rc = -1; } } else { /* Couldn't find the current profile in the profile list */ rc = -1; } } } err: if (response != NULL) { zfree(response); } if (mqe != NULL) { zfree(mqe); } return rc; } int mbox_set_active_profile_pt(elxu_device_t *device, char *new_profile_id) { sli4_res_common_set_active_profile_t *response = NULL; sli4_req_common_set_active_profile_t *request; void *mqe; mbox_sli_config_t *sli_config = NULL; int32_t new_profile; int rc = -1; assert(device); if (device->driver != DEVICE_DRIVER_PT) { return -1; } mqe = zmalloc(MBOX_ENTRY_LENGTH); if (mqe == NULL) { return -1; } response = zmalloc(sizeof(sli4_res_common_set_active_profile_t)); if (response == NULL) { goto err; } new_profile = strtoul(new_profile_id, NULL, 0); sli_config = (mbox_sli_config_t *) mqe; sli_config->command = MBOX_SLI_CONFIG; request = (sli4_req_common_set_active_profile_t *)(&sli_config[1]); request->hdr.req.subsystem = MBOX_SUBSYSTEM_COMMON; request->hdr.req.opcode = OPCODE_COMMON_SET_ACTIVE_PROFILE; request->hdr.req.request_length = sizeof(*request) - sizeof(sli4_ioctl_header_t); request->active_profile_id = new_profile; mbox_common(device, mqe, MBOX_ENTRY_LENGTH, request, sizeof(*request), response, sizeof(*response)); rc = response->hdr.res.status; err: if (response != NULL) { zfree(response); } if (mqe != NULL) { zfree(mqe); } return rc; } /** * @page mbox_cmd.html Mailbox Command Construction * * The mbox_common API for Linux and FreeBSD operating systems provides * a common interface to send mailbox commands using the OneCore Storage IOCTL interface. * * The mbox_common() function sends mailbox commands using the OneCore Storage IOCTL interface. * */