19e39c5baSBill Taylor /*
29e39c5baSBill Taylor * CDDL HEADER START
39e39c5baSBill Taylor *
49e39c5baSBill Taylor * The contents of this file are subject to the terms of the
59e39c5baSBill Taylor * Common Development and Distribution License (the "License").
69e39c5baSBill Taylor * You may not use this file except in compliance with the License.
79e39c5baSBill Taylor *
89e39c5baSBill Taylor * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99e39c5baSBill Taylor * or http://www.opensolaris.org/os/licensing.
109e39c5baSBill Taylor * See the License for the specific language governing permissions
119e39c5baSBill Taylor * and limitations under the License.
129e39c5baSBill Taylor *
139e39c5baSBill Taylor * When distributing Covered Code, include this CDDL HEADER in each
149e39c5baSBill Taylor * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159e39c5baSBill Taylor * If applicable, add the following below this CDDL HEADER, with the
169e39c5baSBill Taylor * fields enclosed by brackets "[]" replaced with your own identifying
179e39c5baSBill Taylor * information: Portions Copyright [yyyy] [name of copyright owner]
189e39c5baSBill Taylor *
199e39c5baSBill Taylor * CDDL HEADER END
209e39c5baSBill Taylor */
219e39c5baSBill Taylor
229e39c5baSBill Taylor /*
23*13cc0a0bSBill Taylor * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249e39c5baSBill Taylor */
259e39c5baSBill Taylor
269e39c5baSBill Taylor /*
279e39c5baSBill Taylor * hermon_ioctl.c
289e39c5baSBill Taylor * Hemron IOCTL Routines
299e39c5baSBill Taylor *
309e39c5baSBill Taylor * Implements all ioctl access into the driver. This includes all routines
319e39c5baSBill Taylor * necessary for updating firmware, accessing the hermon flash device, and
329e39c5baSBill Taylor * providing interfaces for VTS.
339e39c5baSBill Taylor */
349e39c5baSBill Taylor
359e39c5baSBill Taylor #include <sys/types.h>
369e39c5baSBill Taylor #include <sys/conf.h>
379e39c5baSBill Taylor #include <sys/ddi.h>
389e39c5baSBill Taylor #include <sys/sunddi.h>
399e39c5baSBill Taylor #include <sys/modctl.h>
409e39c5baSBill Taylor #include <sys/file.h>
419e39c5baSBill Taylor
429e39c5baSBill Taylor #include <sys/ib/adapters/hermon/hermon.h>
439e39c5baSBill Taylor
449e39c5baSBill Taylor /* Hemron HCA state pointer (extern) */
459e39c5baSBill Taylor extern void *hermon_statep;
469e39c5baSBill Taylor extern int hermon_verbose;
479e39c5baSBill Taylor
489e39c5baSBill Taylor #define DO_WRCONF 1
499e39c5baSBill Taylor static int do_bar0 = 1;
509e39c5baSBill Taylor
519e39c5baSBill Taylor /*
529e39c5baSBill Taylor * The ioctl declarations (for firmware flash burning, register read/write
539e39c5baSBill Taylor * (DEBUG-only), and VTS interfaces)
549e39c5baSBill Taylor */
559e39c5baSBill Taylor static int hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev,
569e39c5baSBill Taylor intptr_t arg, int mode);
579e39c5baSBill Taylor static int hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev,
589e39c5baSBill Taylor intptr_t arg, int mode);
599e39c5baSBill Taylor static int hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev,
609e39c5baSBill Taylor intptr_t arg, int mode);
619e39c5baSBill Taylor static int hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev,
629e39c5baSBill Taylor intptr_t arg, int mode);
639e39c5baSBill Taylor static int hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev);
649e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup(hermon_state_t *state);
659e39c5baSBill Taylor static int hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state);
669e39c5baSBill Taylor #ifdef DEBUG
679e39c5baSBill Taylor static int hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg,
689e39c5baSBill Taylor int mode);
699e39c5baSBill Taylor static int hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg,
709e39c5baSBill Taylor int mode);
719e39c5baSBill Taylor #endif /* DEBUG */
729e39c5baSBill Taylor static int hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev,
739e39c5baSBill Taylor intptr_t arg, int mode);
749e39c5baSBill Taylor static int hermon_ioctl_info(hermon_state_t *state, dev_t dev,
759e39c5baSBill Taylor intptr_t arg, int mode);
769e39c5baSBill Taylor static int hermon_ioctl_ports(hermon_state_t *state, intptr_t arg,
779e39c5baSBill Taylor int mode);
789e39c5baSBill Taylor static int hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg,
799e39c5baSBill Taylor int mode);
809e39c5baSBill Taylor
819e39c5baSBill Taylor /* Hemron Flash Functions */
829e39c5baSBill Taylor static void hermon_flash_spi_exec_command(hermon_state_t *state,
839e39c5baSBill Taylor ddi_acc_handle_t hdl, uint32_t cmd);
849e39c5baSBill Taylor static int hermon_flash_read_sector(hermon_state_t *state,
859e39c5baSBill Taylor uint32_t sector_num);
869e39c5baSBill Taylor static int hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
879e39c5baSBill Taylor uint32_t addr);
889e39c5baSBill Taylor static int hermon_flash_write_sector(hermon_state_t *state,
899e39c5baSBill Taylor uint32_t sector_num);
909e39c5baSBill Taylor static int hermon_flash_spi_write_dword(hermon_state_t *state,
919e39c5baSBill Taylor uint32_t addr, uint32_t data);
929e39c5baSBill Taylor static int hermon_flash_write_byte(hermon_state_t *state, uint32_t addr,
939e39c5baSBill Taylor uchar_t data);
949e39c5baSBill Taylor static int hermon_flash_erase_sector(hermon_state_t *state,
959e39c5baSBill Taylor uint32_t sector_num);
969e39c5baSBill Taylor static int hermon_flash_erase_chip(hermon_state_t *state);
979e39c5baSBill Taylor static int hermon_flash_bank(hermon_state_t *state, uint32_t addr);
989e39c5baSBill Taylor static uint32_t hermon_flash_read(hermon_state_t *state, uint32_t addr,
999e39c5baSBill Taylor int *err);
1009e39c5baSBill Taylor static void hermon_flash_write(hermon_state_t *state, uint32_t addr,
1019e39c5baSBill Taylor uchar_t data, int *err);
1029e39c5baSBill Taylor static int hermon_flash_spi_wait_wip(hermon_state_t *state);
1039e39c5baSBill Taylor static void hermon_flash_spi_write_enable(hermon_state_t *state);
1049e39c5baSBill Taylor static int hermon_flash_init(hermon_state_t *state);
1059e39c5baSBill Taylor static int hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
1069e39c5baSBill Taylor int *intel_xcmd);
1079e39c5baSBill Taylor static int hermon_flash_fini(hermon_state_t *state);
1089e39c5baSBill Taylor static int hermon_flash_reset(hermon_state_t *state);
1099e39c5baSBill Taylor static uint32_t hermon_flash_read_cfg(hermon_state_t *state,
1109e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr);
1119e39c5baSBill Taylor #ifdef DO_WRCONF
1129e39c5baSBill Taylor static void hermon_flash_write_cfg(hermon_state_t *state,
1139e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1149e39c5baSBill Taylor static void hermon_flash_write_cfg_helper(hermon_state_t *state,
1159e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1169e39c5baSBill Taylor static void hermon_flash_write_confirm(hermon_state_t *state,
1179e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl);
1189e39c5baSBill Taylor #endif
1199e39c5baSBill Taylor static void hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
1209e39c5baSBill Taylor static void hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
1219e39c5baSBill Taylor
1229e39c5baSBill Taylor /* Hemron loopback test functions */
1239e39c5baSBill Taylor static void hermon_loopback_free_qps(hermon_loopback_state_t *lstate);
1249e39c5baSBill Taylor static void hermon_loopback_free_state(hermon_loopback_state_t *lstate);
1259e39c5baSBill Taylor static int hermon_loopback_init(hermon_state_t *state,
1269e39c5baSBill Taylor hermon_loopback_state_t *lstate);
1279e39c5baSBill Taylor static void hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
1289e39c5baSBill Taylor hermon_loopback_comm_t *comm);
1299e39c5baSBill Taylor static int hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
1309e39c5baSBill Taylor hermon_loopback_comm_t *comm, int sz);
1319e39c5baSBill Taylor static int hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
1329e39c5baSBill Taylor hermon_loopback_comm_t *comm);
1339e39c5baSBill Taylor static int hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
1349e39c5baSBill Taylor hermon_loopback_comm_t *comm, uint_t qp_num);
1359e39c5baSBill Taylor static int hermon_loopback_copyout(hermon_loopback_ioctl_t *lb,
1369e39c5baSBill Taylor intptr_t arg, int mode);
1379e39c5baSBill Taylor static int hermon_loopback_post_send(hermon_loopback_state_t *lstate,
1389e39c5baSBill Taylor hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx);
1399e39c5baSBill Taylor static int hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
1409e39c5baSBill Taylor hermon_loopback_comm_t *comm);
1419e39c5baSBill Taylor
1429e39c5baSBill Taylor /* Patchable timeout values for flash operations */
1439e39c5baSBill Taylor int hermon_hw_flash_timeout_gpio_sema = HERMON_HW_FLASH_TIMEOUT_GPIO_SEMA;
1449e39c5baSBill Taylor int hermon_hw_flash_timeout_config = HERMON_HW_FLASH_TIMEOUT_CONFIG;
1459e39c5baSBill Taylor int hermon_hw_flash_timeout_write = HERMON_HW_FLASH_TIMEOUT_WRITE;
1469e39c5baSBill Taylor int hermon_hw_flash_timeout_erase = HERMON_HW_FLASH_TIMEOUT_ERASE;
1479e39c5baSBill Taylor
1489e39c5baSBill Taylor /*
1499e39c5baSBill Taylor * hermon_ioctl()
1509e39c5baSBill Taylor */
1519e39c5baSBill Taylor /* ARGSUSED */
1529e39c5baSBill Taylor int
hermon_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1539e39c5baSBill Taylor hermon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1549e39c5baSBill Taylor int *rvalp)
1559e39c5baSBill Taylor {
1569e39c5baSBill Taylor hermon_state_t *state;
1579e39c5baSBill Taylor minor_t instance;
1589e39c5baSBill Taylor int status;
1599e39c5baSBill Taylor
1609e39c5baSBill Taylor if (drv_priv(credp) != 0) {
1619e39c5baSBill Taylor return (EPERM);
1629e39c5baSBill Taylor }
1639e39c5baSBill Taylor
1649e39c5baSBill Taylor instance = HERMON_DEV_INSTANCE(dev);
1659e39c5baSBill Taylor if (instance == (minor_t)-1) {
1669e39c5baSBill Taylor return (EBADF);
1679e39c5baSBill Taylor }
1689e39c5baSBill Taylor
1699e39c5baSBill Taylor state = ddi_get_soft_state(hermon_statep, instance);
1709e39c5baSBill Taylor if (state == NULL) {
1719e39c5baSBill Taylor return (EBADF);
1729e39c5baSBill Taylor }
1739e39c5baSBill Taylor
1749e39c5baSBill Taylor status = 0;
1759e39c5baSBill Taylor
1769e39c5baSBill Taylor switch (cmd) {
1779e39c5baSBill Taylor case HERMON_IOCTL_FLASH_READ:
1789e39c5baSBill Taylor status = hermon_ioctl_flash_read(state, dev, arg, mode);
1799e39c5baSBill Taylor break;
1809e39c5baSBill Taylor
1819e39c5baSBill Taylor case HERMON_IOCTL_FLASH_WRITE:
1829e39c5baSBill Taylor status = hermon_ioctl_flash_write(state, dev, arg, mode);
1839e39c5baSBill Taylor break;
1849e39c5baSBill Taylor
1859e39c5baSBill Taylor case HERMON_IOCTL_FLASH_ERASE:
1869e39c5baSBill Taylor status = hermon_ioctl_flash_erase(state, dev, arg, mode);
1879e39c5baSBill Taylor break;
1889e39c5baSBill Taylor
1899e39c5baSBill Taylor case HERMON_IOCTL_FLASH_INIT:
1909e39c5baSBill Taylor status = hermon_ioctl_flash_init(state, dev, arg, mode);
1919e39c5baSBill Taylor break;
1929e39c5baSBill Taylor
1939e39c5baSBill Taylor case HERMON_IOCTL_FLASH_FINI:
1949e39c5baSBill Taylor status = hermon_ioctl_flash_fini(state, dev);
1959e39c5baSBill Taylor break;
1969e39c5baSBill Taylor
1979e39c5baSBill Taylor case HERMON_IOCTL_INFO:
1989e39c5baSBill Taylor status = hermon_ioctl_info(state, dev, arg, mode);
1999e39c5baSBill Taylor break;
2009e39c5baSBill Taylor
2019e39c5baSBill Taylor case HERMON_IOCTL_PORTS:
2029e39c5baSBill Taylor status = hermon_ioctl_ports(state, arg, mode);
2039e39c5baSBill Taylor break;
2049e39c5baSBill Taylor
2059e39c5baSBill Taylor case HERMON_IOCTL_LOOPBACK:
2069e39c5baSBill Taylor status = hermon_ioctl_loopback(state, arg, mode);
2079e39c5baSBill Taylor break;
2089e39c5baSBill Taylor
2099e39c5baSBill Taylor #ifdef DEBUG
2109e39c5baSBill Taylor case HERMON_IOCTL_REG_WRITE:
2119e39c5baSBill Taylor status = hermon_ioctl_reg_write(state, arg, mode);
2129e39c5baSBill Taylor break;
2139e39c5baSBill Taylor
2149e39c5baSBill Taylor case HERMON_IOCTL_REG_READ:
2159e39c5baSBill Taylor status = hermon_ioctl_reg_read(state, arg, mode);
2169e39c5baSBill Taylor break;
2179e39c5baSBill Taylor #endif /* DEBUG */
2189e39c5baSBill Taylor
2199e39c5baSBill Taylor case HERMON_IOCTL_DDR_READ:
2209e39c5baSBill Taylor /* XXX guard until the ioctl header is cleaned up */
2219e39c5baSBill Taylor status = ENODEV;
2229e39c5baSBill Taylor break;
2239e39c5baSBill Taylor
2249e39c5baSBill Taylor case HERMON_IOCTL_WRITE_BOOT_ADDR:
2259e39c5baSBill Taylor status = hermon_ioctl_write_boot_addr(state, dev, arg, mode);
2269e39c5baSBill Taylor break;
2279e39c5baSBill Taylor
2289e39c5baSBill Taylor default:
2299e39c5baSBill Taylor status = ENOTTY;
2309e39c5baSBill Taylor break;
2319e39c5baSBill Taylor }
2329e39c5baSBill Taylor *rvalp = status;
2339e39c5baSBill Taylor
2349e39c5baSBill Taylor return (status);
2359e39c5baSBill Taylor }
2369e39c5baSBill Taylor
2379e39c5baSBill Taylor /*
2389e39c5baSBill Taylor * hermon_ioctl_flash_read()
2399e39c5baSBill Taylor */
2409e39c5baSBill Taylor static int
hermon_ioctl_flash_read(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)2419e39c5baSBill Taylor hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, intptr_t arg,
2429e39c5baSBill Taylor int mode)
2439e39c5baSBill Taylor {
2449e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info;
2459e39c5baSBill Taylor int status = 0;
2469e39c5baSBill Taylor
2479e39c5baSBill Taylor /*
2489e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
2499e39c5baSBill Taylor * that the same dev_t that called init is the one calling read now.
2509e39c5baSBill Taylor */
2519e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
2529e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) ||
2539e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) {
2549e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
2559e39c5baSBill Taylor return (EIO);
2569e39c5baSBill Taylor }
2579e39c5baSBill Taylor
2589e39c5baSBill Taylor /* copy user struct to kernel */
2599e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
2609e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2619e39c5baSBill Taylor hermon_flash_ioctl32_t info32;
2629e39c5baSBill Taylor
2639e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
2649e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) {
2659e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
2669e39c5baSBill Taylor return (EFAULT);
2679e39c5baSBill Taylor }
2689e39c5baSBill Taylor ioctl_info.af_type = info32.af_type;
2699e39c5baSBill Taylor ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
2709e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num;
2719e39c5baSBill Taylor ioctl_info.af_addr = info32.af_addr;
2729e39c5baSBill Taylor } else
2739e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
2749e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
2759e39c5baSBill Taylor mode) != 0) {
2769e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
2779e39c5baSBill Taylor return (EFAULT);
2789e39c5baSBill Taylor }
2799e39c5baSBill Taylor
2809e39c5baSBill Taylor /*
2819e39c5baSBill Taylor * Determine type of READ ioctl
2829e39c5baSBill Taylor */
2839e39c5baSBill Taylor switch (ioctl_info.af_type) {
2849e39c5baSBill Taylor case HERMON_FLASH_READ_SECTOR:
2859e39c5baSBill Taylor /* Check if sector num is too large for flash device */
2869e39c5baSBill Taylor if (ioctl_info.af_sector_num >=
2879e39c5baSBill Taylor (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
2889e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
2899e39c5baSBill Taylor return (EFAULT);
2909e39c5baSBill Taylor }
2919e39c5baSBill Taylor
2929e39c5baSBill Taylor /* Perform the Sector Read */
2939e39c5baSBill Taylor if ((status = hermon_flash_reset(state)) != 0 ||
2949e39c5baSBill Taylor (status = hermon_flash_read_sector(state,
2959e39c5baSBill Taylor ioctl_info.af_sector_num)) != 0) {
2969e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
2979e39c5baSBill Taylor return (status);
2989e39c5baSBill Taylor }
2999e39c5baSBill Taylor
3009e39c5baSBill Taylor /* copyout the firmware sector image data */
3019e39c5baSBill Taylor if (ddi_copyout(&state->hs_fw_sector[0],
3029e39c5baSBill Taylor &ioctl_info.af_sector[0], 1 << state->hs_fw_log_sector_sz,
3039e39c5baSBill Taylor mode) != 0) {
3049e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3059e39c5baSBill Taylor return (EFAULT);
3069e39c5baSBill Taylor }
3079e39c5baSBill Taylor break;
3089e39c5baSBill Taylor
3099e39c5baSBill Taylor case HERMON_FLASH_READ_QUADLET:
3109e39c5baSBill Taylor /* Check if addr is too large for flash device */
3119e39c5baSBill Taylor if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
3129e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3139e39c5baSBill Taylor return (EFAULT);
3149e39c5baSBill Taylor }
3159e39c5baSBill Taylor
3169e39c5baSBill Taylor /* Perform the Quadlet Read */
3179e39c5baSBill Taylor if ((status = hermon_flash_reset(state)) != 0 ||
3189e39c5baSBill Taylor (status = hermon_flash_read_quadlet(state,
3199e39c5baSBill Taylor &ioctl_info.af_quadlet, ioctl_info.af_addr)) != 0) {
3209e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3219e39c5baSBill Taylor return (status);
3229e39c5baSBill Taylor }
3239e39c5baSBill Taylor break;
3249e39c5baSBill Taylor
3259e39c5baSBill Taylor default:
3269e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3279e39c5baSBill Taylor return (EINVAL);
3289e39c5baSBill Taylor }
3299e39c5baSBill Taylor
3309e39c5baSBill Taylor /* copy results back to userland */
3319e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3329e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3339e39c5baSBill Taylor hermon_flash_ioctl32_t info32;
3349e39c5baSBill Taylor
3359e39c5baSBill Taylor info32.af_quadlet = ioctl_info.af_quadlet;
3369e39c5baSBill Taylor info32.af_type = ioctl_info.af_type;
3379e39c5baSBill Taylor info32.af_sector_num = ioctl_info.af_sector_num;
3389e39c5baSBill Taylor info32.af_sector = (caddr32_t)(uintptr_t)ioctl_info.af_sector;
3399e39c5baSBill Taylor info32.af_addr = ioctl_info.af_addr;
3409e39c5baSBill Taylor
3419e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg,
3429e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3439e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3449e39c5baSBill Taylor return (EFAULT);
3459e39c5baSBill Taylor }
3469e39c5baSBill Taylor } else
3479e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3489e39c5baSBill Taylor if (ddi_copyout(&ioctl_info, (void *)arg,
3499e39c5baSBill Taylor sizeof (hermon_flash_ioctl_t), mode) != 0) {
3509e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3519e39c5baSBill Taylor return (EFAULT);
3529e39c5baSBill Taylor }
3539e39c5baSBill Taylor
3549e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3559e39c5baSBill Taylor return (status);
3569e39c5baSBill Taylor }
3579e39c5baSBill Taylor
3589e39c5baSBill Taylor /*
3599e39c5baSBill Taylor * hermon_ioctl_flash_write()
3609e39c5baSBill Taylor */
3619e39c5baSBill Taylor static int
hermon_ioctl_flash_write(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)3629e39c5baSBill Taylor hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, intptr_t arg,
3639e39c5baSBill Taylor int mode)
3649e39c5baSBill Taylor {
3659e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info;
3669e39c5baSBill Taylor int status = 0;
3679e39c5baSBill Taylor
3689e39c5baSBill Taylor /*
3699e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
3709e39c5baSBill Taylor * that the same dev_t that called init is the one calling write now.
3719e39c5baSBill Taylor */
3729e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
3739e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) ||
3749e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) {
3759e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3769e39c5baSBill Taylor return (EIO);
3779e39c5baSBill Taylor }
3789e39c5baSBill Taylor
3799e39c5baSBill Taylor /* copy user struct to kernel */
3809e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
3819e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3829e39c5baSBill Taylor hermon_flash_ioctl32_t info32;
3839e39c5baSBill Taylor
3849e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
3859e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3869e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3879e39c5baSBill Taylor return (EFAULT);
3889e39c5baSBill Taylor }
3899e39c5baSBill Taylor ioctl_info.af_type = info32.af_type;
3909e39c5baSBill Taylor ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
3919e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num;
3929e39c5baSBill Taylor ioctl_info.af_addr = info32.af_addr;
3939e39c5baSBill Taylor ioctl_info.af_byte = info32.af_byte;
3949e39c5baSBill Taylor } else
3959e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
3969e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info,
3979e39c5baSBill Taylor sizeof (hermon_flash_ioctl_t), mode) != 0) {
3989e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
3999e39c5baSBill Taylor return (EFAULT);
4009e39c5baSBill Taylor }
4019e39c5baSBill Taylor
4029e39c5baSBill Taylor /*
4039e39c5baSBill Taylor * Determine type of WRITE ioctl
4049e39c5baSBill Taylor */
4059e39c5baSBill Taylor switch (ioctl_info.af_type) {
4069e39c5baSBill Taylor case HERMON_FLASH_WRITE_SECTOR:
4079e39c5baSBill Taylor /* Check if sector num is too large for flash device */
4089e39c5baSBill Taylor if (ioctl_info.af_sector_num >=
4099e39c5baSBill Taylor (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
4109e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4119e39c5baSBill Taylor return (EFAULT);
4129e39c5baSBill Taylor }
4139e39c5baSBill Taylor
4149e39c5baSBill Taylor /* copy in fw sector image data */
4159e39c5baSBill Taylor if (ddi_copyin(&ioctl_info.af_sector[0],
4169e39c5baSBill Taylor &state->hs_fw_sector[0], 1 << state->hs_fw_log_sector_sz,
4179e39c5baSBill Taylor mode) != 0) {
4189e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4199e39c5baSBill Taylor return (EFAULT);
4209e39c5baSBill Taylor }
4219e39c5baSBill Taylor
4229e39c5baSBill Taylor /* Perform Write Sector */
4239e39c5baSBill Taylor status = hermon_flash_write_sector(state,
4249e39c5baSBill Taylor ioctl_info.af_sector_num);
4259e39c5baSBill Taylor break;
4269e39c5baSBill Taylor
4279e39c5baSBill Taylor case HERMON_FLASH_WRITE_BYTE:
4289e39c5baSBill Taylor /* Check if addr is too large for flash device */
4299e39c5baSBill Taylor if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
4309e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4319e39c5baSBill Taylor return (EFAULT);
4329e39c5baSBill Taylor }
4339e39c5baSBill Taylor
4349e39c5baSBill Taylor /* Perform Write Byte */
4359e39c5baSBill Taylor /*
4369e39c5baSBill Taylor * CMJ -- is a reset really needed before and after writing
4379e39c5baSBill Taylor * each byte? This code came from arbel, but we should look
4389e39c5baSBill Taylor * into this. Also, for SPI, no reset is actually performed.
4399e39c5baSBill Taylor */
4409e39c5baSBill Taylor if ((status = hermon_flash_bank(state,
4419e39c5baSBill Taylor ioctl_info.af_addr)) != 0 ||
4429e39c5baSBill Taylor (status = hermon_flash_reset(state)) != 0 ||
4439e39c5baSBill Taylor (status = hermon_flash_write_byte(state,
4449e39c5baSBill Taylor ioctl_info.af_addr, ioctl_info.af_byte)) != 0 ||
4459e39c5baSBill Taylor (status = hermon_flash_reset(state)) != 0) {
4469e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4479e39c5baSBill Taylor return (status);
4489e39c5baSBill Taylor }
4499e39c5baSBill Taylor break;
4509e39c5baSBill Taylor
4519e39c5baSBill Taylor default:
4529e39c5baSBill Taylor status = EINVAL;
4539e39c5baSBill Taylor break;
4549e39c5baSBill Taylor }
4559e39c5baSBill Taylor
4569e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4579e39c5baSBill Taylor return (status);
4589e39c5baSBill Taylor }
4599e39c5baSBill Taylor
4609e39c5baSBill Taylor /*
4619e39c5baSBill Taylor * hermon_ioctl_flash_erase()
4629e39c5baSBill Taylor */
4639e39c5baSBill Taylor static int
hermon_ioctl_flash_erase(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)4649e39c5baSBill Taylor hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, intptr_t arg,
4659e39c5baSBill Taylor int mode)
4669e39c5baSBill Taylor {
4679e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info;
4689e39c5baSBill Taylor int status = 0;
4699e39c5baSBill Taylor
4709e39c5baSBill Taylor /*
4719e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
4729e39c5baSBill Taylor * that the same dev_t that called init is the one calling erase now.
4739e39c5baSBill Taylor */
4749e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
4759e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) ||
4769e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) {
4779e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4789e39c5baSBill Taylor return (EIO);
4799e39c5baSBill Taylor }
4809e39c5baSBill Taylor
4819e39c5baSBill Taylor /* copy user struct to kernel */
4829e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
4839e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4849e39c5baSBill Taylor hermon_flash_ioctl32_t info32;
4859e39c5baSBill Taylor
4869e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
4879e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) {
4889e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4899e39c5baSBill Taylor return (EFAULT);
4909e39c5baSBill Taylor }
4919e39c5baSBill Taylor ioctl_info.af_type = info32.af_type;
4929e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num;
4939e39c5baSBill Taylor } else
4949e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
4959e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
4969e39c5baSBill Taylor mode) != 0) {
4979e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
4989e39c5baSBill Taylor return (EFAULT);
4999e39c5baSBill Taylor }
5009e39c5baSBill Taylor
5019e39c5baSBill Taylor /*
5029e39c5baSBill Taylor * Determine type of ERASE ioctl
5039e39c5baSBill Taylor */
5049e39c5baSBill Taylor switch (ioctl_info.af_type) {
5059e39c5baSBill Taylor case HERMON_FLASH_ERASE_SECTOR:
5069e39c5baSBill Taylor /* Check if sector num is too large for flash device */
5079e39c5baSBill Taylor if (ioctl_info.af_sector_num >=
5089e39c5baSBill Taylor (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
5099e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5109e39c5baSBill Taylor return (EFAULT);
5119e39c5baSBill Taylor }
5129e39c5baSBill Taylor
5139e39c5baSBill Taylor /* Perform Sector Erase */
5149e39c5baSBill Taylor status = hermon_flash_erase_sector(state,
5159e39c5baSBill Taylor ioctl_info.af_sector_num);
5169e39c5baSBill Taylor break;
5179e39c5baSBill Taylor
5189e39c5baSBill Taylor case HERMON_FLASH_ERASE_CHIP:
5199e39c5baSBill Taylor /* Perform Chip Erase */
5209e39c5baSBill Taylor status = hermon_flash_erase_chip(state);
5219e39c5baSBill Taylor break;
5229e39c5baSBill Taylor
5239e39c5baSBill Taylor default:
5249e39c5baSBill Taylor status = EINVAL;
5259e39c5baSBill Taylor break;
5269e39c5baSBill Taylor }
5279e39c5baSBill Taylor
5289e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5299e39c5baSBill Taylor return (status);
5309e39c5baSBill Taylor }
5319e39c5baSBill Taylor
5329e39c5baSBill Taylor /*
5339e39c5baSBill Taylor * hermon_ioctl_flash_init()
5349e39c5baSBill Taylor */
5359e39c5baSBill Taylor static int
hermon_ioctl_flash_init(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)5369e39c5baSBill Taylor hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, intptr_t arg,
5379e39c5baSBill Taylor int mode)
5389e39c5baSBill Taylor {
5399e39c5baSBill Taylor hermon_flash_init_ioctl_t init_info;
5409e39c5baSBill Taylor int ret;
5419e39c5baSBill Taylor int intel_xcmd = 0;
5429e39c5baSBill Taylor ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
5439e39c5baSBill Taylor
5449e39c5baSBill Taylor /* initialize the FMA retry loop */
5459e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
5469e39c5baSBill Taylor
5479e39c5baSBill Taylor state->hs_fw_sector = NULL;
5489e39c5baSBill Taylor
5499e39c5baSBill Taylor /*
5509e39c5baSBill Taylor * init cannot be called more than once. If we have already init'd the
5519e39c5baSBill Taylor * flash, return directly.
5529e39c5baSBill Taylor */
5539e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
5549e39c5baSBill Taylor if (state->hs_fw_flashstarted == 1) {
5559e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5569e39c5baSBill Taylor return (EINVAL);
5579e39c5baSBill Taylor }
5589e39c5baSBill Taylor
5599e39c5baSBill Taylor /* copyin the user struct to kernel */
5609e39c5baSBill Taylor if (ddi_copyin((void *)arg, &init_info,
5619e39c5baSBill Taylor sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
5629e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5639e39c5baSBill Taylor return (EFAULT);
5649e39c5baSBill Taylor }
5659e39c5baSBill Taylor
5669e39c5baSBill Taylor /* Init Flash */
5679e39c5baSBill Taylor if ((ret = hermon_flash_init(state)) != 0) {
5689e39c5baSBill Taylor if (ret == EIO) {
5699e39c5baSBill Taylor goto pio_error;
5709e39c5baSBill Taylor }
5719e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5729e39c5baSBill Taylor return (ret);
5739e39c5baSBill Taylor }
5749e39c5baSBill Taylor
5759e39c5baSBill Taylor /* Read CFI info */
5769e39c5baSBill Taylor if ((ret = hermon_flash_cfi_init(state, &init_info.af_cfi_info[0],
5779e39c5baSBill Taylor &intel_xcmd)) != 0) {
5789e39c5baSBill Taylor if (ret == EIO) {
5799e39c5baSBill Taylor goto pio_error;
5809e39c5baSBill Taylor }
5819e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5829e39c5baSBill Taylor return (ret);
5839e39c5baSBill Taylor }
5849e39c5baSBill Taylor
5859e39c5baSBill Taylor /*
5869e39c5baSBill Taylor * Return error if the command set is unknown.
5879e39c5baSBill Taylor */
5889e39c5baSBill Taylor if (state->hs_fw_cmdset == HERMON_FLASH_UNKNOWN_CMDSET) {
5899e39c5baSBill Taylor if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
5909e39c5baSBill Taylor if (ret == EIO) {
5919e39c5baSBill Taylor goto pio_error;
5929e39c5baSBill Taylor }
5939e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5949e39c5baSBill Taylor return (ret);
5959e39c5baSBill Taylor }
5969e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
5979e39c5baSBill Taylor return (EFAULT);
5989e39c5baSBill Taylor }
5999e39c5baSBill Taylor
6009e39c5baSBill Taylor /* the FMA retry loop starts. */
6019e39c5baSBill Taylor hermon_pio_start(state, pci_hdl, pio_error,
6029e39c5baSBill Taylor fm_loop_cnt, fm_status, fm_test);
6039e39c5baSBill Taylor
6049e39c5baSBill Taylor /* Read HWREV - least significant 8 bits is revision ID */
6059e39c5baSBill Taylor init_info.af_hwrev = pci_config_get32(pci_hdl,
6069e39c5baSBill Taylor HERMON_HW_FLASH_CFG_HWREV) & 0xFF;
6079e39c5baSBill Taylor
6089e39c5baSBill Taylor /* the FMA retry loop ends. */
6099e39c5baSBill Taylor hermon_pio_end(state, pci_hdl, pio_error, fm_loop_cnt,
6109e39c5baSBill Taylor fm_status, fm_test);
6119e39c5baSBill Taylor
6129e39c5baSBill Taylor /* Fill in the firmwate revision numbers */
6139e39c5baSBill Taylor init_info.af_fwrev.afi_maj = state->hs_fw.fw_rev_major;
6149e39c5baSBill Taylor init_info.af_fwrev.afi_min = state->hs_fw.fw_rev_minor;
6159e39c5baSBill Taylor init_info.af_fwrev.afi_sub = state->hs_fw.fw_rev_subminor;
6169e39c5baSBill Taylor
6179e39c5baSBill Taylor /* Alloc flash mem for one sector size */
6189e39c5baSBill Taylor state->hs_fw_sector = (uint32_t *)kmem_zalloc(1 <<
6199e39c5baSBill Taylor state->hs_fw_log_sector_sz, KM_SLEEP);
6209e39c5baSBill Taylor
6219e39c5baSBill Taylor /* Set HW part number and length */
6229e39c5baSBill Taylor init_info.af_pn_len = state->hs_hca_pn_len;
6239e39c5baSBill Taylor if (state->hs_hca_pn_len != 0) {
6249e39c5baSBill Taylor (void) memcpy(init_info.af_hwpn, state->hs_hca_pn,
6259e39c5baSBill Taylor state->hs_hca_pn_len);
6269e39c5baSBill Taylor }
6279e39c5baSBill Taylor
6289e39c5baSBill Taylor /* Copy ioctl results back to userland */
6299e39c5baSBill Taylor if (ddi_copyout(&init_info, (void *)arg,
6309e39c5baSBill Taylor sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
6319e39c5baSBill Taylor if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6329e39c5baSBill Taylor if (ret == EIO) {
6339e39c5baSBill Taylor goto pio_error;
6349e39c5baSBill Taylor }
6359e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
6369e39c5baSBill Taylor return (ret);
6379e39c5baSBill Taylor }
6389e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
6399e39c5baSBill Taylor return (EFAULT);
6409e39c5baSBill Taylor }
6419e39c5baSBill Taylor
6429e39c5baSBill Taylor /* Set flash state to started */
6439e39c5baSBill Taylor state->hs_fw_flashstarted = 1;
6449e39c5baSBill Taylor state->hs_fw_flashdev = dev;
6459e39c5baSBill Taylor
6469e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
6479e39c5baSBill Taylor
6489e39c5baSBill Taylor /*
6499e39c5baSBill Taylor * If "flash init" is successful, add an "on close" callback to the
6509e39c5baSBill Taylor * current dev node to ensure that "flash fini" gets called later
6519e39c5baSBill Taylor * even if the userland process prematurely exits.
6529e39c5baSBill Taylor */
6539e39c5baSBill Taylor ret = hermon_umap_db_set_onclose_cb(dev,
6549e39c5baSBill Taylor HERMON_ONCLOSE_FLASH_INPROGRESS,
6559e39c5baSBill Taylor (int (*)(void *))hermon_ioctl_flash_cleanup, state);
6569e39c5baSBill Taylor if (ret != DDI_SUCCESS) {
6579e39c5baSBill Taylor int status = hermon_ioctl_flash_fini(state, dev);
6589e39c5baSBill Taylor if (status != 0) {
6599e39c5baSBill Taylor if (status == EIO) {
6609e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
6619e39c5baSBill Taylor HCA_ERR_IOCTL);
6629e39c5baSBill Taylor return (EIO);
6639e39c5baSBill Taylor }
6649e39c5baSBill Taylor return (status);
6659e39c5baSBill Taylor }
6669e39c5baSBill Taylor }
6679e39c5baSBill Taylor return (0);
6689e39c5baSBill Taylor
6699e39c5baSBill Taylor pio_error:
6709e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
6719e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6729e39c5baSBill Taylor return (EIO);
6739e39c5baSBill Taylor }
6749e39c5baSBill Taylor
6759e39c5baSBill Taylor /*
6769e39c5baSBill Taylor * hermon_ioctl_flash_fini()
6779e39c5baSBill Taylor */
6789e39c5baSBill Taylor static int
hermon_ioctl_flash_fini(hermon_state_t * state,dev_t dev)6799e39c5baSBill Taylor hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev)
6809e39c5baSBill Taylor {
6819e39c5baSBill Taylor int ret;
6829e39c5baSBill Taylor
6839e39c5baSBill Taylor /*
6849e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
6859e39c5baSBill Taylor * that the same dev_t that called init is the one calling fini now.
6869e39c5baSBill Taylor */
6879e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
6889e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) ||
6899e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) {
6909e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
6919e39c5baSBill Taylor return (EINVAL);
6929e39c5baSBill Taylor }
6939e39c5baSBill Taylor
6949e39c5baSBill Taylor if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6959e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
6969e39c5baSBill Taylor if (ret == EIO) {
6979e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6989e39c5baSBill Taylor }
6999e39c5baSBill Taylor return (ret);
7009e39c5baSBill Taylor }
7019e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
7029e39c5baSBill Taylor
7039e39c5baSBill Taylor /*
7049e39c5baSBill Taylor * If "flash fini" is successful, remove the "on close" callback
7059e39c5baSBill Taylor * that was setup during "flash init".
7069e39c5baSBill Taylor */
7079e39c5baSBill Taylor ret = hermon_umap_db_clear_onclose_cb(dev,
7089e39c5baSBill Taylor HERMON_ONCLOSE_FLASH_INPROGRESS);
7099e39c5baSBill Taylor if (ret != DDI_SUCCESS) {
7109e39c5baSBill Taylor return (EFAULT);
7119e39c5baSBill Taylor }
7129e39c5baSBill Taylor return (0);
7139e39c5baSBill Taylor }
7149e39c5baSBill Taylor
7159e39c5baSBill Taylor
7169e39c5baSBill Taylor /*
7179e39c5baSBill Taylor * hermon_ioctl_flash_cleanup()
7189e39c5baSBill Taylor */
7199e39c5baSBill Taylor static int
hermon_ioctl_flash_cleanup(hermon_state_t * state)7209e39c5baSBill Taylor hermon_ioctl_flash_cleanup(hermon_state_t *state)
7219e39c5baSBill Taylor {
7229e39c5baSBill Taylor int status;
7239e39c5baSBill Taylor
7249e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
7259e39c5baSBill Taylor status = hermon_ioctl_flash_cleanup_nolock(state);
7269e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
7279e39c5baSBill Taylor
7289e39c5baSBill Taylor return (status);
7299e39c5baSBill Taylor }
7309e39c5baSBill Taylor
7319e39c5baSBill Taylor
7329e39c5baSBill Taylor /*
7339e39c5baSBill Taylor * hermon_ioctl_flash_cleanup_nolock()
7349e39c5baSBill Taylor */
7359e39c5baSBill Taylor static int
hermon_ioctl_flash_cleanup_nolock(hermon_state_t * state)7369e39c5baSBill Taylor hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state)
7379e39c5baSBill Taylor {
7389e39c5baSBill Taylor int status;
7399e39c5baSBill Taylor ASSERT(MUTEX_HELD(&state->hs_fw_flashlock));
7409e39c5baSBill Taylor
7419e39c5baSBill Taylor /* free flash mem */
7429e39c5baSBill Taylor if (state->hs_fw_sector) {
7439e39c5baSBill Taylor kmem_free(state->hs_fw_sector, 1 << state->hs_fw_log_sector_sz);
7449e39c5baSBill Taylor }
7459e39c5baSBill Taylor
7469e39c5baSBill Taylor /* Fini the Flash */
7479e39c5baSBill Taylor if ((status = hermon_flash_fini(state)) != 0)
7489e39c5baSBill Taylor return (status);
7499e39c5baSBill Taylor
7509e39c5baSBill Taylor /* Set flash state to fini */
7519e39c5baSBill Taylor state->hs_fw_flashstarted = 0;
7529e39c5baSBill Taylor state->hs_fw_flashdev = 0;
7539e39c5baSBill Taylor return (0);
7549e39c5baSBill Taylor }
7559e39c5baSBill Taylor
7569e39c5baSBill Taylor
7579e39c5baSBill Taylor /*
7589e39c5baSBill Taylor * hermon_ioctl_info()
7599e39c5baSBill Taylor */
7609e39c5baSBill Taylor static int
hermon_ioctl_info(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)7619e39c5baSBill Taylor hermon_ioctl_info(hermon_state_t *state, dev_t dev, intptr_t arg, int mode)
7629e39c5baSBill Taylor {
7639e39c5baSBill Taylor hermon_info_ioctl_t info;
7649e39c5baSBill Taylor hermon_flash_init_ioctl_t init_info;
7659e39c5baSBill Taylor
7669e39c5baSBill Taylor /*
7679e39c5baSBill Taylor * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
7689e39c5baSBill Taylor */
7699e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
7709e39c5baSBill Taylor return (EFAULT);
7719e39c5baSBill Taylor }
7729e39c5baSBill Taylor
7739e39c5baSBill Taylor /* copyin the user struct to kernel */
7749e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (hermon_info_ioctl_t),
7759e39c5baSBill Taylor mode) != 0) {
7769e39c5baSBill Taylor return (EFAULT);
7779e39c5baSBill Taylor }
7789e39c5baSBill Taylor
7799e39c5baSBill Taylor /*
7809e39c5baSBill Taylor * Check ioctl revision
7819e39c5baSBill Taylor */
7829e39c5baSBill Taylor if (info.ai_revision != HERMON_VTS_IOCTL_REVISION) {
7839e39c5baSBill Taylor return (EINVAL);
7849e39c5baSBill Taylor }
7859e39c5baSBill Taylor
7869e39c5baSBill Taylor /*
7879e39c5baSBill Taylor * If the 'fw_device_sz' has not been initialized yet, we initialize it
7889e39c5baSBill Taylor * here. This is done by leveraging the
7899e39c5baSBill Taylor * hermon_ioctl_flash_init()/fini() calls. We also hold our own mutex
7909e39c5baSBill Taylor * around this operation in case we have multiple VTS threads in
7919e39c5baSBill Taylor * process at the same time.
7929e39c5baSBill Taylor */
7939e39c5baSBill Taylor mutex_enter(&state->hs_info_lock);
7949e39c5baSBill Taylor if (state->hs_fw_device_sz == 0) {
7959e39c5baSBill Taylor if (hermon_ioctl_flash_init(state, dev, (intptr_t)&init_info,
7969e39c5baSBill Taylor (FKIOCTL | mode)) != 0) {
7979e39c5baSBill Taylor mutex_exit(&state->hs_info_lock);
7989e39c5baSBill Taylor return (EFAULT);
7999e39c5baSBill Taylor }
8009e39c5baSBill Taylor (void) hermon_ioctl_flash_fini(state, dev);
8019e39c5baSBill Taylor }
8029e39c5baSBill Taylor mutex_exit(&state->hs_info_lock);
8039e39c5baSBill Taylor
8049e39c5baSBill Taylor info.ai_hw_rev = state->hs_revision_id;
8059e39c5baSBill Taylor info.ai_flash_sz = state->hs_fw_device_sz;
8069e39c5baSBill Taylor info.ai_fw_rev.afi_maj = state->hs_fw.fw_rev_major;
8079e39c5baSBill Taylor info.ai_fw_rev.afi_min = state->hs_fw.fw_rev_minor;
8089e39c5baSBill Taylor info.ai_fw_rev.afi_sub = state->hs_fw.fw_rev_subminor;
8099e39c5baSBill Taylor
8109e39c5baSBill Taylor /* Copy ioctl results back to user struct */
8119e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (hermon_info_ioctl_t),
8129e39c5baSBill Taylor mode) != 0) {
8139e39c5baSBill Taylor return (EFAULT);
8149e39c5baSBill Taylor }
8159e39c5baSBill Taylor
8169e39c5baSBill Taylor return (0);
8179e39c5baSBill Taylor }
8189e39c5baSBill Taylor
8199e39c5baSBill Taylor /*
8209e39c5baSBill Taylor * hermon_ioctl_ports()
8219e39c5baSBill Taylor */
8229e39c5baSBill Taylor static int
hermon_ioctl_ports(hermon_state_t * state,intptr_t arg,int mode)8239e39c5baSBill Taylor hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, int mode)
8249e39c5baSBill Taylor {
8259e39c5baSBill Taylor hermon_ports_ioctl_t info;
8269e39c5baSBill Taylor hermon_stat_port_ioctl_t portstat;
8279e39c5baSBill Taylor ibt_hca_portinfo_t pi;
8289e39c5baSBill Taylor uint_t tbl_size;
8299e39c5baSBill Taylor ib_gid_t *sgid_tbl;
8309e39c5baSBill Taylor ib_pkey_t *pkey_tbl;
8319e39c5baSBill Taylor int i;
8329e39c5baSBill Taylor
8339e39c5baSBill Taylor /*
8349e39c5baSBill Taylor * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
8359e39c5baSBill Taylor */
8369e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
8379e39c5baSBill Taylor return (EFAULT);
8389e39c5baSBill Taylor }
8399e39c5baSBill Taylor
8409e39c5baSBill Taylor /* copyin the user struct to kernel */
8419e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
8429e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
8439e39c5baSBill Taylor hermon_ports_ioctl32_t info32;
8449e39c5baSBill Taylor
8459e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
8469e39c5baSBill Taylor sizeof (hermon_ports_ioctl32_t), mode) != 0) {
8479e39c5baSBill Taylor return (EFAULT);
8489e39c5baSBill Taylor }
8499e39c5baSBill Taylor info.ap_revision = info32.ap_revision;
8509e39c5baSBill Taylor info.ap_ports =
8519e39c5baSBill Taylor (hermon_stat_port_ioctl_t *)(uintptr_t)info32.ap_ports;
8529e39c5baSBill Taylor info.ap_num_ports = info32.ap_num_ports;
8539e39c5baSBill Taylor
8549e39c5baSBill Taylor } else
8559e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
8569e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info, sizeof (hermon_ports_ioctl_t),
8579e39c5baSBill Taylor mode) != 0) {
8589e39c5baSBill Taylor return (EFAULT);
8599e39c5baSBill Taylor }
8609e39c5baSBill Taylor
8619e39c5baSBill Taylor /*
8629e39c5baSBill Taylor * Check ioctl revision
8639e39c5baSBill Taylor */
8649e39c5baSBill Taylor if (info.ap_revision != HERMON_VTS_IOCTL_REVISION) {
8659e39c5baSBill Taylor return (EINVAL);
8669e39c5baSBill Taylor }
8679e39c5baSBill Taylor
8689e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */
8699e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
8709e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
8719e39c5baSBill Taylor KM_SLEEP);
8729e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
8739e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
8749e39c5baSBill Taylor KM_SLEEP);
8759e39c5baSBill Taylor
8769e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
8779e39c5baSBill Taylor
8789e39c5baSBill Taylor /*
8799e39c5baSBill Taylor * Setup the number of ports, then loop through all ports and
8809e39c5baSBill Taylor * query properties of each.
8819e39c5baSBill Taylor */
8829e39c5baSBill Taylor info.ap_num_ports = (uint8_t)state->hs_cfg_profile->cp_num_ports;
8839e39c5baSBill Taylor for (i = 0; i < info.ap_num_ports; i++) {
8849e39c5baSBill Taylor /*
8859e39c5baSBill Taylor * Get portstate information from the device. If
8869e39c5baSBill Taylor * hermon_port_query() fails, leave zeroes in user
8879e39c5baSBill Taylor * struct port entry and continue.
8889e39c5baSBill Taylor */
8899e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t));
8909e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl;
8919e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl;
8929e39c5baSBill Taylor (void) hermon_port_query(state, i + 1, &pi);
8939e39c5baSBill Taylor
8949e39c5baSBill Taylor portstat.asp_port_num = pi.p_port_num;
8959e39c5baSBill Taylor portstat.asp_state = pi.p_linkstate;
8969e39c5baSBill Taylor portstat.asp_guid = pi.p_sgid_tbl[0].gid_guid;
8979e39c5baSBill Taylor
8989e39c5baSBill Taylor /*
8999e39c5baSBill Taylor * Copy queried port results back to user struct. If
9009e39c5baSBill Taylor * this fails, then break out of loop, attempt to copy
9019e39c5baSBill Taylor * out remaining info to user struct, and return (without
9029e39c5baSBill Taylor * error).
9039e39c5baSBill Taylor */
9049e39c5baSBill Taylor if (ddi_copyout(&portstat,
9059e39c5baSBill Taylor &(((hermon_stat_port_ioctl_t *)info.ap_ports)[i]),
9069e39c5baSBill Taylor sizeof (hermon_stat_port_ioctl_t), mode) != 0) {
9079e39c5baSBill Taylor break;
9089e39c5baSBill Taylor }
9099e39c5baSBill Taylor }
9109e39c5baSBill Taylor
9119e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */
9129e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
9139e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
9149e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
9159e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
9169e39c5baSBill Taylor
9179e39c5baSBill Taylor /* Copy ioctl results back to user struct */
9189e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
9199e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9209e39c5baSBill Taylor hermon_ports_ioctl32_t info32;
9219e39c5baSBill Taylor
9229e39c5baSBill Taylor info32.ap_revision = info.ap_revision;
9239e39c5baSBill Taylor info32.ap_ports = (caddr32_t)(uintptr_t)info.ap_ports;
9249e39c5baSBill Taylor info32.ap_num_ports = info.ap_num_ports;
9259e39c5baSBill Taylor
9269e39c5baSBill Taylor if (ddi_copyout(&info32, (void *)arg,
9279e39c5baSBill Taylor sizeof (hermon_ports_ioctl32_t), mode) != 0) {
9289e39c5baSBill Taylor return (EFAULT);
9299e39c5baSBill Taylor }
9309e39c5baSBill Taylor } else
9319e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
9329e39c5baSBill Taylor if (ddi_copyout(&info, (void *)arg, sizeof (hermon_ports_ioctl_t),
9339e39c5baSBill Taylor mode) != 0) {
9349e39c5baSBill Taylor return (EFAULT);
9359e39c5baSBill Taylor }
9369e39c5baSBill Taylor
9379e39c5baSBill Taylor return (0);
9389e39c5baSBill Taylor }
9399e39c5baSBill Taylor
9409e39c5baSBill Taylor /*
9419e39c5baSBill Taylor * hermon_ioctl_loopback()
9429e39c5baSBill Taylor */
9439e39c5baSBill Taylor static int
hermon_ioctl_loopback(hermon_state_t * state,intptr_t arg,int mode)9449e39c5baSBill Taylor hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, int mode)
9459e39c5baSBill Taylor {
9469e39c5baSBill Taylor hermon_loopback_ioctl_t lb;
9479e39c5baSBill Taylor hermon_loopback_state_t lstate;
9489e39c5baSBill Taylor ibt_hca_portinfo_t pi;
9499e39c5baSBill Taylor uint_t tbl_size, loopmax, max_usec;
9509e39c5baSBill Taylor ib_gid_t *sgid_tbl;
9519e39c5baSBill Taylor ib_pkey_t *pkey_tbl;
9529e39c5baSBill Taylor int j, iter, ret;
9539e39c5baSBill Taylor
9549e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
9559e39c5baSBill Taylor
9569e39c5baSBill Taylor /*
9579e39c5baSBill Taylor * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
9589e39c5baSBill Taylor */
9599e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
9609e39c5baSBill Taylor return (EFAULT);
9619e39c5baSBill Taylor }
9629e39c5baSBill Taylor
9639e39c5baSBill Taylor /* copyin the user struct to kernel */
9649e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
9659e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9669e39c5baSBill Taylor hermon_loopback_ioctl32_t lb32;
9679e39c5baSBill Taylor
9689e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb32,
9699e39c5baSBill Taylor sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
9709e39c5baSBill Taylor return (EFAULT);
9719e39c5baSBill Taylor }
9729e39c5baSBill Taylor lb.alb_revision = lb32.alb_revision;
9739e39c5baSBill Taylor lb.alb_send_buf = (caddr_t)(uintptr_t)lb32.alb_send_buf;
9749e39c5baSBill Taylor lb.alb_fail_buf = (caddr_t)(uintptr_t)lb32.alb_fail_buf;
9759e39c5baSBill Taylor lb.alb_buf_sz = lb32.alb_buf_sz;
9769e39c5baSBill Taylor lb.alb_num_iter = lb32.alb_num_iter;
9779e39c5baSBill Taylor lb.alb_pass_done = lb32.alb_pass_done;
9789e39c5baSBill Taylor lb.alb_timeout = lb32.alb_timeout;
9799e39c5baSBill Taylor lb.alb_error_type = lb32.alb_error_type;
9809e39c5baSBill Taylor lb.alb_port_num = lb32.alb_port_num;
9819e39c5baSBill Taylor lb.alb_num_retry = lb32.alb_num_retry;
9829e39c5baSBill Taylor } else
9839e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
9849e39c5baSBill Taylor if (ddi_copyin((void *)arg, &lb, sizeof (hermon_loopback_ioctl_t),
9859e39c5baSBill Taylor mode) != 0) {
9869e39c5baSBill Taylor return (EFAULT);
9879e39c5baSBill Taylor }
9889e39c5baSBill Taylor
9899e39c5baSBill Taylor /* Initialize the internal loopback test state structure */
9909e39c5baSBill Taylor bzero(&lstate, sizeof (hermon_loopback_state_t));
9919e39c5baSBill Taylor
9929e39c5baSBill Taylor /*
9939e39c5baSBill Taylor * Check ioctl revision
9949e39c5baSBill Taylor */
9959e39c5baSBill Taylor if (lb.alb_revision != HERMON_VTS_IOCTL_REVISION) {
9969e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_INVALID_REVISION;
9979e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
9989e39c5baSBill Taylor return (EINVAL);
9999e39c5baSBill Taylor }
10009e39c5baSBill Taylor
10019e39c5baSBill Taylor /* Validate that specified port number is legal */
10029e39c5baSBill Taylor if (!hermon_portnum_is_valid(state, lb.alb_port_num)) {
10039e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10049e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
10059e39c5baSBill Taylor return (EINVAL);
10069e39c5baSBill Taylor }
10079e39c5baSBill Taylor
10089e39c5baSBill Taylor /* Allocate space for temporary GID table/PKey table */
10099e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10109e39c5baSBill Taylor sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
10119e39c5baSBill Taylor KM_SLEEP);
10129e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10139e39c5baSBill Taylor pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
10149e39c5baSBill Taylor KM_SLEEP);
10159e39c5baSBill Taylor
10169e39c5baSBill Taylor /*
10179e39c5baSBill Taylor * Get portstate information from specific port on device
10189e39c5baSBill Taylor */
10199e39c5baSBill Taylor bzero(&pi, sizeof (ibt_hca_portinfo_t));
10209e39c5baSBill Taylor pi.p_sgid_tbl = sgid_tbl;
10219e39c5baSBill Taylor pi.p_pkey_tbl = pkey_tbl;
10229e39c5baSBill Taylor if (hermon_port_query(state, lb.alb_port_num, &pi) != 0) {
10239e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */
10249e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10259e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10269e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10279e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10289e39c5baSBill Taylor
10299e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10309e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
10319e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
10329e39c5baSBill Taylor return (EINVAL);
10339e39c5baSBill Taylor }
10349e39c5baSBill Taylor
10359e39c5baSBill Taylor lstate.hls_port = pi.p_port_num;
10369e39c5baSBill Taylor lstate.hls_lid = pi.p_base_lid;
10379e39c5baSBill Taylor lstate.hls_pkey_ix = (pi.p_linkstate == HERMON_PORT_LINK_ACTIVE) ?
10389e39c5baSBill Taylor 1 : 0; /* XXX bogus assumption of a SUN subnet manager */
10399e39c5baSBill Taylor lstate.hls_state = state;
10409e39c5baSBill Taylor lstate.hls_retry = lb.alb_num_retry;
10419e39c5baSBill Taylor
10429e39c5baSBill Taylor /* Free the temporary space used for GID table/PKey table */
10439e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10449e39c5baSBill Taylor kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10459e39c5baSBill Taylor tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10469e39c5baSBill Taylor kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10479e39c5baSBill Taylor
10489e39c5baSBill Taylor /*
10499e39c5baSBill Taylor * Compute the timeout duration in usec per the formula:
10509e39c5baSBill Taylor * to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
10519e39c5baSBill Taylor * (plus we add a little fudge-factor here too)
10529e39c5baSBill Taylor */
10539e39c5baSBill Taylor lstate.hls_timeout = lb.alb_timeout;
10549e39c5baSBill Taylor max_usec = (4096 * (1 << lstate.hls_timeout)) / 1000;
10559e39c5baSBill Taylor max_usec = max_usec * (lstate.hls_retry + 1);
10569e39c5baSBill Taylor max_usec = max_usec + 10000;
10579e39c5baSBill Taylor
10589e39c5baSBill Taylor /*
10599e39c5baSBill Taylor * Determine how many times we should loop before declaring a
10609e39c5baSBill Taylor * timeout failure.
10619e39c5baSBill Taylor */
10629e39c5baSBill Taylor loopmax = max_usec/HERMON_VTS_LOOPBACK_MIN_WAIT_DUR;
10639e39c5baSBill Taylor if ((max_usec % HERMON_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
10649e39c5baSBill Taylor loopmax++;
10659e39c5baSBill Taylor }
10669e39c5baSBill Taylor
10679e39c5baSBill Taylor if (lb.alb_send_buf == NULL || lb.alb_buf_sz == 0) {
10689e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_INVALID;
10699e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
10709e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
10719e39c5baSBill Taylor return (EINVAL);
10729e39c5baSBill Taylor }
10739e39c5baSBill Taylor
10749e39c5baSBill Taylor /* Allocate protection domain (PD) */
10759e39c5baSBill Taylor if (hermon_loopback_init(state, &lstate) != 0) {
10769e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err;
10779e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
10789e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
10799e39c5baSBill Taylor return (EFAULT);
10809e39c5baSBill Taylor }
10819e39c5baSBill Taylor
10829e39c5baSBill Taylor /* Allocate and register a TX buffer */
10839e39c5baSBill Taylor if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_tx,
10849e39c5baSBill Taylor lb.alb_buf_sz) != 0) {
10859e39c5baSBill Taylor lb.alb_error_type =
10869e39c5baSBill Taylor HERMON_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
10879e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
10889e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
10899e39c5baSBill Taylor return (EFAULT);
10909e39c5baSBill Taylor }
10919e39c5baSBill Taylor
10929e39c5baSBill Taylor /* Allocate and register an RX buffer */
10939e39c5baSBill Taylor if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_rx,
10949e39c5baSBill Taylor lb.alb_buf_sz) != 0) {
10959e39c5baSBill Taylor lb.alb_error_type =
10969e39c5baSBill Taylor HERMON_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
10979e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
10989e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
10999e39c5baSBill Taylor return (EFAULT);
11009e39c5baSBill Taylor }
11019e39c5baSBill Taylor
11029e39c5baSBill Taylor /* Copy in the transmit buffer data */
11039e39c5baSBill Taylor if (ddi_copyin((void *)lb.alb_send_buf, lstate.hls_tx.hlc_buf,
11049e39c5baSBill Taylor lb.alb_buf_sz, mode) != 0) {
11059e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_COPY_FAIL;
11069e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11079e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11089e39c5baSBill Taylor return (EFAULT);
11099e39c5baSBill Taylor }
11109e39c5baSBill Taylor
11119e39c5baSBill Taylor /* Allocate the transmit QP and CQs */
11129e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
11139e39c5baSBill Taylor if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_tx) != 0) {
11149e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err;
11159e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11169e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11179e39c5baSBill Taylor return (EFAULT);
11189e39c5baSBill Taylor }
11199e39c5baSBill Taylor
11209e39c5baSBill Taylor /* Allocate the receive QP and CQs */
11219e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
11229e39c5baSBill Taylor if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_rx) != 0) {
11239e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err;
11249e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11259e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11269e39c5baSBill Taylor return (EFAULT);
11279e39c5baSBill Taylor }
11289e39c5baSBill Taylor
11299e39c5baSBill Taylor /* Activate the TX QP (connect to RX QP) */
11309e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_XMIT_QP_INIT_FAIL;
11319e39c5baSBill Taylor if (hermon_loopback_modify_qp(&lstate, &lstate.hls_tx,
11329e39c5baSBill Taylor lstate.hls_rx.hlc_qp_num) != 0) {
11339e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err;
11349e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11359e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11369e39c5baSBill Taylor return (EFAULT);
11379e39c5baSBill Taylor }
11389e39c5baSBill Taylor
11399e39c5baSBill Taylor /* Activate the RX QP (connect to TX QP) */
11409e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_RECV_QP_INIT_FAIL;
11419e39c5baSBill Taylor if (hermon_loopback_modify_qp(&lstate, &lstate.hls_rx,
11429e39c5baSBill Taylor lstate.hls_tx.hlc_qp_num) != 0) {
11439e39c5baSBill Taylor lb.alb_error_type = lstate.hls_err;
11449e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11459e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11469e39c5baSBill Taylor return (EFAULT);
11479e39c5baSBill Taylor }
11489e39c5baSBill Taylor
11499e39c5baSBill Taylor /* Run the loopback test (for specified number of iterations) */
11509e39c5baSBill Taylor lb.alb_pass_done = 0;
11519e39c5baSBill Taylor for (iter = 0; iter < lb.alb_num_iter; iter++) {
11529e39c5baSBill Taylor lstate.hls_err = 0;
11539e39c5baSBill Taylor bzero(lstate.hls_rx.hlc_buf, lb.alb_buf_sz);
11549e39c5baSBill Taylor
11559e39c5baSBill Taylor /* Post RDMA Write work request */
11569e39c5baSBill Taylor if (hermon_loopback_post_send(&lstate, &lstate.hls_tx,
11579e39c5baSBill Taylor &lstate.hls_rx) != IBT_SUCCESS) {
11589e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_WQE_POST_FAIL;
11599e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11609e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11619e39c5baSBill Taylor return (EFAULT);
11629e39c5baSBill Taylor }
11639e39c5baSBill Taylor
11649e39c5baSBill Taylor /* Poll the TX CQ for a completion every few ticks */
11659e39c5baSBill Taylor for (j = 0; j < loopmax; j++) {
11669e39c5baSBill Taylor delay(drv_usectohz(HERMON_VTS_LOOPBACK_MIN_WAIT_DUR));
11679e39c5baSBill Taylor
11689e39c5baSBill Taylor ret = hermon_loopback_poll_cq(&lstate, &lstate.hls_tx);
11699e39c5baSBill Taylor if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
11709e39c5baSBill Taylor ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
11719e39c5baSBill Taylor lb.alb_error_type =
11729e39c5baSBill Taylor HERMON_LOOPBACK_CQ_POLL_FAIL;
11739e39c5baSBill Taylor if (ddi_copyout(lstate.hls_rx.hlc_buf,
11749e39c5baSBill Taylor lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11759e39c5baSBill Taylor mode) != 0) {
11769e39c5baSBill Taylor return (EFAULT);
11779e39c5baSBill Taylor }
11789e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11799e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11809e39c5baSBill Taylor return (EFAULT);
11819e39c5baSBill Taylor } else if (ret == IBT_CQ_EMPTY) {
11829e39c5baSBill Taylor continue;
11839e39c5baSBill Taylor }
11849e39c5baSBill Taylor
11859e39c5baSBill Taylor /* Compare the data buffers */
11869e39c5baSBill Taylor if (bcmp(lstate.hls_tx.hlc_buf, lstate.hls_rx.hlc_buf,
11879e39c5baSBill Taylor lb.alb_buf_sz) == 0) {
11889e39c5baSBill Taylor break;
11899e39c5baSBill Taylor } else {
11909e39c5baSBill Taylor lb.alb_error_type =
11919e39c5baSBill Taylor HERMON_LOOPBACK_SEND_RECV_COMPARE_FAIL;
11929e39c5baSBill Taylor if (ddi_copyout(lstate.hls_rx.hlc_buf,
11939e39c5baSBill Taylor lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11949e39c5baSBill Taylor mode) != 0) {
11959e39c5baSBill Taylor return (EFAULT);
11969e39c5baSBill Taylor }
11979e39c5baSBill Taylor (void) hermon_loopback_copyout(&lb, arg, mode);
11989e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
11999e39c5baSBill Taylor return (EFAULT);
12009e39c5baSBill Taylor }
12019e39c5baSBill Taylor }
12029e39c5baSBill Taylor
12039e39c5baSBill Taylor lstate.hls_err = HERMON_LOOPBACK_SUCCESS;
12049e39c5baSBill Taylor lb.alb_pass_done = iter + 1;
12059e39c5baSBill Taylor }
12069e39c5baSBill Taylor
12079e39c5baSBill Taylor lb.alb_error_type = HERMON_LOOPBACK_SUCCESS;
12089e39c5baSBill Taylor
12099e39c5baSBill Taylor /* Copy ioctl results back to user struct */
12109e39c5baSBill Taylor ret = hermon_loopback_copyout(&lb, arg, mode);
12119e39c5baSBill Taylor
12129e39c5baSBill Taylor /* Free up everything and release all consumed resources */
12139e39c5baSBill Taylor hermon_loopback_free_state(&lstate);
12149e39c5baSBill Taylor
12159e39c5baSBill Taylor return (ret);
12169e39c5baSBill Taylor }
12179e39c5baSBill Taylor
12189e39c5baSBill Taylor #ifdef DEBUG
12199e39c5baSBill Taylor /*
12209e39c5baSBill Taylor * hermon_ioctl_reg_read()
12219e39c5baSBill Taylor */
12229e39c5baSBill Taylor static int
hermon_ioctl_reg_read(hermon_state_t * state,intptr_t arg,int mode)12239e39c5baSBill Taylor hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, int mode)
12249e39c5baSBill Taylor {
12259e39c5baSBill Taylor hermon_reg_ioctl_t rdreg;
12269e39c5baSBill Taylor uint32_t *addr;
12279e39c5baSBill Taylor uintptr_t baseaddr;
12289e39c5baSBill Taylor int status;
12299e39c5baSBill Taylor ddi_acc_handle_t handle;
12309e39c5baSBill Taylor
12319e39c5baSBill Taylor /* initialize the FMA retry loop */
12329e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
12339e39c5baSBill Taylor
12349e39c5baSBill Taylor /*
12359e39c5baSBill Taylor * Access to Hemron registers is not allowed in "maintenance mode".
12369e39c5baSBill Taylor * This is primarily because the device may not have BARs to access
12379e39c5baSBill Taylor */
12389e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
12399e39c5baSBill Taylor return (EFAULT);
12409e39c5baSBill Taylor }
12419e39c5baSBill Taylor
12429e39c5baSBill Taylor /* Copy in the hermon_reg_ioctl_t structure */
12439e39c5baSBill Taylor status = ddi_copyin((void *)arg, &rdreg, sizeof (hermon_reg_ioctl_t),
12449e39c5baSBill Taylor mode);
12459e39c5baSBill Taylor if (status != 0) {
12469e39c5baSBill Taylor return (EFAULT);
12479e39c5baSBill Taylor }
12489e39c5baSBill Taylor
12499e39c5baSBill Taylor /* Determine base address for requested register set */
12509e39c5baSBill Taylor switch (rdreg.arg_reg_set) {
12519e39c5baSBill Taylor case HERMON_CMD_BAR:
12529e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
12539e39c5baSBill Taylor handle = hermon_get_cmdhdl(state);
12549e39c5baSBill Taylor break;
12559e39c5baSBill Taylor
12569e39c5baSBill Taylor case HERMON_UAR_BAR:
12579e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
12589e39c5baSBill Taylor handle = hermon_get_uarhdl(state);
12599e39c5baSBill Taylor break;
12609e39c5baSBill Taylor
12619e39c5baSBill Taylor
12629e39c5baSBill Taylor default:
12639e39c5baSBill Taylor return (EINVAL);
12649e39c5baSBill Taylor }
12659e39c5baSBill Taylor
12669e39c5baSBill Taylor /* Ensure that address is properly-aligned */
12679e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + rdreg.arg_offset) & ~0x3);
12689e39c5baSBill Taylor
12699e39c5baSBill Taylor /* the FMA retry loop starts. */
12709e39c5baSBill Taylor hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
12719e39c5baSBill Taylor fm_status, fm_test);
12729e39c5baSBill Taylor
12739e39c5baSBill Taylor /* Read the register pointed to by addr */
12749e39c5baSBill Taylor rdreg.arg_data = ddi_get32(handle, addr);
12759e39c5baSBill Taylor
12769e39c5baSBill Taylor /* the FMA retry loop ends. */
12779e39c5baSBill Taylor hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
12789e39c5baSBill Taylor fm_test);
12799e39c5baSBill Taylor
12809e39c5baSBill Taylor /* Copy in the result into the hermon_reg_ioctl_t structure */
12819e39c5baSBill Taylor status = ddi_copyout(&rdreg, (void *)arg, sizeof (hermon_reg_ioctl_t),
12829e39c5baSBill Taylor mode);
12839e39c5baSBill Taylor if (status != 0) {
12849e39c5baSBill Taylor return (EFAULT);
12859e39c5baSBill Taylor }
12869e39c5baSBill Taylor return (0);
12879e39c5baSBill Taylor
12889e39c5baSBill Taylor pio_error:
12899e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
12909e39c5baSBill Taylor return (EIO);
12919e39c5baSBill Taylor }
12929e39c5baSBill Taylor
12939e39c5baSBill Taylor
12949e39c5baSBill Taylor /*
12959e39c5baSBill Taylor * hermon_ioctl_reg_write()
12969e39c5baSBill Taylor */
12979e39c5baSBill Taylor static int
hermon_ioctl_reg_write(hermon_state_t * state,intptr_t arg,int mode)12989e39c5baSBill Taylor hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, int mode)
12999e39c5baSBill Taylor {
13009e39c5baSBill Taylor hermon_reg_ioctl_t wrreg;
13019e39c5baSBill Taylor uint32_t *addr;
13029e39c5baSBill Taylor uintptr_t baseaddr;
13039e39c5baSBill Taylor int status;
13049e39c5baSBill Taylor ddi_acc_handle_t handle;
13059e39c5baSBill Taylor
13069e39c5baSBill Taylor /* initialize the FMA retry loop */
13079e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13089e39c5baSBill Taylor
13099e39c5baSBill Taylor /*
13109e39c5baSBill Taylor * Access to Hermon registers is not allowed in "maintenance mode".
13119e39c5baSBill Taylor * This is primarily because the device may not have BARs to access
13129e39c5baSBill Taylor */
13139e39c5baSBill Taylor if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
13149e39c5baSBill Taylor return (EFAULT);
13159e39c5baSBill Taylor }
13169e39c5baSBill Taylor
13179e39c5baSBill Taylor /* Copy in the hermon_reg_ioctl_t structure */
13189e39c5baSBill Taylor status = ddi_copyin((void *)arg, &wrreg, sizeof (hermon_reg_ioctl_t),
13199e39c5baSBill Taylor mode);
13209e39c5baSBill Taylor if (status != 0) {
13219e39c5baSBill Taylor return (EFAULT);
13229e39c5baSBill Taylor }
13239e39c5baSBill Taylor
13249e39c5baSBill Taylor /* Determine base address for requested register set */
13259e39c5baSBill Taylor switch (wrreg.arg_reg_set) {
13269e39c5baSBill Taylor case HERMON_CMD_BAR:
13279e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
13289e39c5baSBill Taylor handle = hermon_get_cmdhdl(state);
13299e39c5baSBill Taylor break;
13309e39c5baSBill Taylor
13319e39c5baSBill Taylor case HERMON_UAR_BAR:
13329e39c5baSBill Taylor baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
13339e39c5baSBill Taylor handle = hermon_get_uarhdl(state);
13349e39c5baSBill Taylor break;
13359e39c5baSBill Taylor
13369e39c5baSBill Taylor default:
13379e39c5baSBill Taylor return (EINVAL);
13389e39c5baSBill Taylor }
13399e39c5baSBill Taylor
13409e39c5baSBill Taylor /* Ensure that address is properly-aligned */
13419e39c5baSBill Taylor addr = (uint32_t *)((baseaddr + wrreg.arg_offset) & ~0x3);
13429e39c5baSBill Taylor
13439e39c5baSBill Taylor /* the FMA retry loop starts. */
13449e39c5baSBill Taylor hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
13459e39c5baSBill Taylor fm_status, fm_test);
13469e39c5baSBill Taylor
13479e39c5baSBill Taylor /* Write the data to the register pointed to by addr */
13489e39c5baSBill Taylor ddi_put32(handle, addr, wrreg.arg_data);
13499e39c5baSBill Taylor
13509e39c5baSBill Taylor /* the FMA retry loop ends. */
13519e39c5baSBill Taylor hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
13529e39c5baSBill Taylor fm_test);
13539e39c5baSBill Taylor return (0);
13549e39c5baSBill Taylor
13559e39c5baSBill Taylor pio_error:
13569e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
13579e39c5baSBill Taylor return (EIO);
13589e39c5baSBill Taylor }
13599e39c5baSBill Taylor #endif /* DEBUG */
13609e39c5baSBill Taylor
13619e39c5baSBill Taylor static int
hermon_ioctl_write_boot_addr(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)13629e39c5baSBill Taylor hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, intptr_t arg,
13639e39c5baSBill Taylor int mode)
13649e39c5baSBill Taylor {
13659e39c5baSBill Taylor hermon_flash_ioctl_t ioctl_info;
13669e39c5baSBill Taylor
13679e39c5baSBill Taylor /* initialize the FMA retry loop */
13689e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13699e39c5baSBill Taylor
13709e39c5baSBill Taylor /*
13719e39c5baSBill Taylor * Check that flash init ioctl has been called first. And check
13729e39c5baSBill Taylor * that the same dev_t that called init is the one calling write now.
13739e39c5baSBill Taylor */
13749e39c5baSBill Taylor mutex_enter(&state->hs_fw_flashlock);
13759e39c5baSBill Taylor if ((state->hs_fw_flashdev != dev) ||
13769e39c5baSBill Taylor (state->hs_fw_flashstarted == 0)) {
13779e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
13789e39c5baSBill Taylor return (EIO);
13799e39c5baSBill Taylor }
13809e39c5baSBill Taylor
13819e39c5baSBill Taylor /* copy user struct to kernel */
13829e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
13839e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
13849e39c5baSBill Taylor hermon_flash_ioctl32_t info32;
13859e39c5baSBill Taylor
13869e39c5baSBill Taylor if (ddi_copyin((void *)arg, &info32,
13879e39c5baSBill Taylor sizeof (hermon_flash_ioctl32_t), mode) != 0) {
13889e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
13899e39c5baSBill Taylor return (EFAULT);
13909e39c5baSBill Taylor }
13919e39c5baSBill Taylor ioctl_info.af_type = info32.af_type;
13929e39c5baSBill Taylor ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
13939e39c5baSBill Taylor ioctl_info.af_sector_num = info32.af_sector_num;
13949e39c5baSBill Taylor ioctl_info.af_addr = info32.af_addr;
13959e39c5baSBill Taylor ioctl_info.af_byte = info32.af_byte;
13969e39c5baSBill Taylor } else
13979e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
13989e39c5baSBill Taylor if (ddi_copyin((void *)arg, &ioctl_info,
13999e39c5baSBill Taylor sizeof (hermon_flash_ioctl_t), mode) != 0) {
14009e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
14019e39c5baSBill Taylor return (EFAULT);
14029e39c5baSBill Taylor }
14039e39c5baSBill Taylor
14049e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
14059e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
14069e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
14079e39c5baSBill Taylor break;
14089e39c5baSBill Taylor
14099e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
14109e39c5baSBill Taylor {
14119e39c5baSBill Taylor ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
14129e39c5baSBill Taylor
14139e39c5baSBill Taylor /* the FMA retry loop starts. */
14149e39c5baSBill Taylor hermon_pio_start(state, pci_hdl, pio_error,
14159e39c5baSBill Taylor fm_loop_cnt, fm_status, fm_test);
14169e39c5baSBill Taylor
14179e39c5baSBill Taylor hermon_flash_write_cfg(state, pci_hdl,
14189e39c5baSBill Taylor HERMON_HW_FLASH_SPI_BOOT_ADDR_REG,
14199e39c5baSBill Taylor (ioctl_info.af_addr << 8) | 0x06);
14209e39c5baSBill Taylor
14219e39c5baSBill Taylor /* the FMA retry loop ends. */
14229e39c5baSBill Taylor hermon_pio_end(state, pci_hdl, pio_error,
14239e39c5baSBill Taylor fm_loop_cnt, fm_status, fm_test);
14249e39c5baSBill Taylor break;
14259e39c5baSBill Taylor }
14269e39c5baSBill Taylor
14279e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
14289e39c5baSBill Taylor default:
14299e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
14309e39c5baSBill Taylor return (EINVAL);
14319e39c5baSBill Taylor }
14329e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
14339e39c5baSBill Taylor return (0);
14349e39c5baSBill Taylor
14359e39c5baSBill Taylor pio_error:
14369e39c5baSBill Taylor mutex_exit(&state->hs_fw_flashlock);
14379e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
14389e39c5baSBill Taylor return (EIO);
14399e39c5baSBill Taylor }
14409e39c5baSBill Taylor
14419e39c5baSBill Taylor /*
14429e39c5baSBill Taylor * hermon_flash_reset()
14439e39c5baSBill Taylor */
14449e39c5baSBill Taylor static int
hermon_flash_reset(hermon_state_t * state)14459e39c5baSBill Taylor hermon_flash_reset(hermon_state_t *state)
14469e39c5baSBill Taylor {
14479e39c5baSBill Taylor int status;
14489e39c5baSBill Taylor
14499e39c5baSBill Taylor /*
14509e39c5baSBill Taylor * Performs a reset to the flash device. After a reset the flash will
14519e39c5baSBill Taylor * be operating in normal mode (capable of read/write, etc.).
14529e39c5baSBill Taylor */
14539e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
14549e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
14559e39c5baSBill Taylor hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_AMD,
14569e39c5baSBill Taylor &status);
14579e39c5baSBill Taylor if (status != 0) {
14589e39c5baSBill Taylor return (status);
14599e39c5baSBill Taylor }
14609e39c5baSBill Taylor break;
14619e39c5baSBill Taylor
14629e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
14639e39c5baSBill Taylor hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_INTEL,
14649e39c5baSBill Taylor &status);
14659e39c5baSBill Taylor if (status != 0) {
14669e39c5baSBill Taylor return (status);
14679e39c5baSBill Taylor }
14689e39c5baSBill Taylor break;
14699e39c5baSBill Taylor
14709e39c5baSBill Taylor /* It appears no reset is needed for SPI */
14719e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
14729e39c5baSBill Taylor status = 0;
14739e39c5baSBill Taylor break;
14749e39c5baSBill Taylor
14759e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
14769e39c5baSBill Taylor default:
14779e39c5baSBill Taylor status = EINVAL;
14789e39c5baSBill Taylor break;
14799e39c5baSBill Taylor }
14809e39c5baSBill Taylor return (status);
14819e39c5baSBill Taylor }
14829e39c5baSBill Taylor
14839e39c5baSBill Taylor /*
14849e39c5baSBill Taylor * hermon_flash_read_sector()
14859e39c5baSBill Taylor */
14869e39c5baSBill Taylor static int
hermon_flash_read_sector(hermon_state_t * state,uint32_t sector_num)14879e39c5baSBill Taylor hermon_flash_read_sector(hermon_state_t *state, uint32_t sector_num)
14889e39c5baSBill Taylor {
14899e39c5baSBill Taylor uint32_t addr;
14909e39c5baSBill Taylor uint32_t end_addr;
14919e39c5baSBill Taylor uint32_t *image;
14929e39c5baSBill Taylor int i, status;
14939e39c5baSBill Taylor
14949e39c5baSBill Taylor image = (uint32_t *)&state->hs_fw_sector[0];
14959e39c5baSBill Taylor
14969e39c5baSBill Taylor /*
14979e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the
14989e39c5baSBill Taylor * sector number passed in.
14999e39c5baSBill Taylor */
15009e39c5baSBill Taylor addr = sector_num << state->hs_fw_log_sector_sz;
15019e39c5baSBill Taylor end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15029e39c5baSBill Taylor
15039e39c5baSBill Taylor /* Set the flash bank correctly for the given address */
15049e39c5baSBill Taylor if ((status = hermon_flash_bank(state, addr)) != 0)
15059e39c5baSBill Taylor return (status);
15069e39c5baSBill Taylor
15079e39c5baSBill Taylor /* Read the entire sector, one quadlet at a time */
15089e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr += 4) {
15099e39c5baSBill Taylor image[i] = hermon_flash_read(state, addr, &status);
15109e39c5baSBill Taylor if (status != 0) {
15119e39c5baSBill Taylor return (status);
15129e39c5baSBill Taylor }
15139e39c5baSBill Taylor }
15149e39c5baSBill Taylor return (0);
15159e39c5baSBill Taylor }
15169e39c5baSBill Taylor
15179e39c5baSBill Taylor /*
15189e39c5baSBill Taylor * hermon_flash_read_quadlet()
15199e39c5baSBill Taylor */
15209e39c5baSBill Taylor static int
hermon_flash_read_quadlet(hermon_state_t * state,uint32_t * data,uint32_t addr)15219e39c5baSBill Taylor hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
15229e39c5baSBill Taylor uint32_t addr)
15239e39c5baSBill Taylor {
15249e39c5baSBill Taylor int status;
15259e39c5baSBill Taylor
15269e39c5baSBill Taylor /* Set the flash bank correctly for the given address */
15279e39c5baSBill Taylor if ((status = hermon_flash_bank(state, addr)) != 0) {
15289e39c5baSBill Taylor return (status);
15299e39c5baSBill Taylor }
15309e39c5baSBill Taylor
15319e39c5baSBill Taylor /* Read one quadlet of data */
15329e39c5baSBill Taylor *data = hermon_flash_read(state, addr, &status);
15339e39c5baSBill Taylor if (status != 0) {
15349e39c5baSBill Taylor return (EIO);
15359e39c5baSBill Taylor }
15369e39c5baSBill Taylor
15379e39c5baSBill Taylor return (0);
15389e39c5baSBill Taylor }
15399e39c5baSBill Taylor
15409e39c5baSBill Taylor /*
15419e39c5baSBill Taylor * hermon_flash_write_sector()
15429e39c5baSBill Taylor */
15439e39c5baSBill Taylor static int
hermon_flash_write_sector(hermon_state_t * state,uint32_t sector_num)15449e39c5baSBill Taylor hermon_flash_write_sector(hermon_state_t *state, uint32_t sector_num)
15459e39c5baSBill Taylor {
15469e39c5baSBill Taylor uint32_t addr;
15479e39c5baSBill Taylor uint32_t end_addr;
15489e39c5baSBill Taylor uint32_t *databuf;
15499e39c5baSBill Taylor uchar_t *sector;
15509e39c5baSBill Taylor int status = 0;
15519e39c5baSBill Taylor int i;
15529e39c5baSBill Taylor
15539e39c5baSBill Taylor sector = (uchar_t *)&state->hs_fw_sector[0];
15549e39c5baSBill Taylor
15559e39c5baSBill Taylor /*
15569e39c5baSBill Taylor * Calculate the start and end address of the sector, based on the
15579e39c5baSBill Taylor * sector number passed in.
15589e39c5baSBill Taylor */
15599e39c5baSBill Taylor addr = sector_num << state->hs_fw_log_sector_sz;
15609e39c5baSBill Taylor end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15619e39c5baSBill Taylor
15629e39c5baSBill Taylor /* Set the flash bank correctly for the given address */
15639e39c5baSBill Taylor if ((status = hermon_flash_bank(state, addr)) != 0 ||
15649e39c5baSBill Taylor (status = hermon_flash_reset(state)) != 0) {
15659e39c5baSBill Taylor return (status);
15669e39c5baSBill Taylor }
15679e39c5baSBill Taylor
15689e39c5baSBill Taylor /* Erase the sector before writing */
15699e39c5baSBill Taylor status = hermon_flash_erase_sector(state, sector_num);
15709e39c5baSBill Taylor if (status != 0) {
15719e39c5baSBill Taylor return (status);
15729e39c5baSBill Taylor }
15739e39c5baSBill Taylor
15749e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
15759e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
15769e39c5baSBill Taylor databuf = (uint32_t *)(void *)sector;
15779e39c5baSBill Taylor /* Write the sector, one dword at a time */
15789e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr += 4) {
15799e39c5baSBill Taylor if ((status = hermon_flash_spi_write_dword(state, addr,
15809e39c5baSBill Taylor htonl(databuf[i]))) != 0) {
15819e39c5baSBill Taylor return (status);
15829e39c5baSBill Taylor }
15839e39c5baSBill Taylor }
15849e39c5baSBill Taylor status = hermon_flash_reset(state);
15859e39c5baSBill Taylor break;
15869e39c5baSBill Taylor
15879e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
15889e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
15899e39c5baSBill Taylor /* Write the sector, one byte at a time */
15909e39c5baSBill Taylor for (i = 0; addr < end_addr; i++, addr++) {
15919e39c5baSBill Taylor status = hermon_flash_write_byte(state, addr,
15929e39c5baSBill Taylor sector[i]);
15939e39c5baSBill Taylor if (status != 0) {
15949e39c5baSBill Taylor break;
15959e39c5baSBill Taylor }
15969e39c5baSBill Taylor }
15979e39c5baSBill Taylor status = hermon_flash_reset(state);
15989e39c5baSBill Taylor break;
15999e39c5baSBill Taylor
16009e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
16019e39c5baSBill Taylor default:
16029e39c5baSBill Taylor status = EINVAL;
16039e39c5baSBill Taylor break;
16049e39c5baSBill Taylor }
16059e39c5baSBill Taylor
16069e39c5baSBill Taylor return (status);
16079e39c5baSBill Taylor }
16089e39c5baSBill Taylor
16099e39c5baSBill Taylor /*
16109e39c5baSBill Taylor * hermon_flash_spi_write_dword()
16119e39c5baSBill Taylor *
16129e39c5baSBill Taylor * NOTE: This function assumes that "data" is in network byte order.
16139e39c5baSBill Taylor *
16149e39c5baSBill Taylor */
16159e39c5baSBill Taylor static int
hermon_flash_spi_write_dword(hermon_state_t * state,uint32_t addr,uint32_t data)16169e39c5baSBill Taylor hermon_flash_spi_write_dword(hermon_state_t *state, uint32_t addr,
16179e39c5baSBill Taylor uint32_t data)
16189e39c5baSBill Taylor {
16199e39c5baSBill Taylor int status;
16209e39c5baSBill Taylor ddi_acc_handle_t hdl;
16219e39c5baSBill Taylor
16229e39c5baSBill Taylor /* initialize the FMA retry loop */
16239e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
16249e39c5baSBill Taylor
16259e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
16269e39c5baSBill Taylor
16279e39c5baSBill Taylor /* the FMA retry loop starts. */
16289e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
16299e39c5baSBill Taylor fm_test);
16309e39c5baSBill Taylor
16319e39c5baSBill Taylor /* Issue Write Enable */
16329e39c5baSBill Taylor hermon_flash_spi_write_enable(state);
16339e39c5baSBill Taylor
16349e39c5baSBill Taylor /* Set the Address */
16359e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
16369e39c5baSBill Taylor addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
16379e39c5baSBill Taylor
16389e39c5baSBill Taylor /* Set the Data */
16399e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_DATA, data);
16409e39c5baSBill Taylor
16419e39c5baSBill Taylor /* Set the Page Program and execute */
16429e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl,
16439e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
16449e39c5baSBill Taylor HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
16459e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
16469e39c5baSBill Taylor HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
16479e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_PAGE_PROGRAM <<
16489e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT));
16499e39c5baSBill Taylor
16509e39c5baSBill Taylor /* Wait for write to complete */
16519e39c5baSBill Taylor if ((status = hermon_flash_spi_wait_wip(state)) != 0) {
16529e39c5baSBill Taylor return (status);
16539e39c5baSBill Taylor }
16549e39c5baSBill Taylor
16559e39c5baSBill Taylor /* the FMA retry loop ends. */
16569e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
16579e39c5baSBill Taylor return (0);
16589e39c5baSBill Taylor
16599e39c5baSBill Taylor pio_error:
16609e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
16619e39c5baSBill Taylor return (EIO);
16629e39c5baSBill Taylor }
16639e39c5baSBill Taylor
16649e39c5baSBill Taylor /*
16659e39c5baSBill Taylor * hermon_flash_write_byte()
16669e39c5baSBill Taylor */
16679e39c5baSBill Taylor static int
hermon_flash_write_byte(hermon_state_t * state,uint32_t addr,uchar_t data)16689e39c5baSBill Taylor hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, uchar_t data)
16699e39c5baSBill Taylor {
16709e39c5baSBill Taylor uint32_t stat;
16719e39c5baSBill Taylor int status = 0;
16729e39c5baSBill Taylor int dword_addr;
16739e39c5baSBill Taylor int byte_offset;
16749e39c5baSBill Taylor int i;
16759e39c5baSBill Taylor union {
16769e39c5baSBill Taylor uint8_t bytes[4];
16779e39c5baSBill Taylor uint32_t dword;
16789e39c5baSBill Taylor } dword;
16799e39c5baSBill Taylor
16809e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
16819e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
16829e39c5baSBill Taylor /* Issue Flash Byte program command */
16839e39c5baSBill Taylor hermon_flash_write(state, addr, 0xAA, &status);
16849e39c5baSBill Taylor if (status != 0) {
16859e39c5baSBill Taylor return (status);
16869e39c5baSBill Taylor }
16879e39c5baSBill Taylor
16889e39c5baSBill Taylor hermon_flash_write(state, addr, 0x55, &status);
16899e39c5baSBill Taylor if (status != 0) {
16909e39c5baSBill Taylor return (status);
16919e39c5baSBill Taylor }
16929e39c5baSBill Taylor
16939e39c5baSBill Taylor hermon_flash_write(state, addr, 0xA0, &status);
16949e39c5baSBill Taylor if (status != 0) {
16959e39c5baSBill Taylor return (status);
16969e39c5baSBill Taylor }
16979e39c5baSBill Taylor
16989e39c5baSBill Taylor hermon_flash_write(state, addr, data, &status);
16999e39c5baSBill Taylor if (status != 0) {
17009e39c5baSBill Taylor return (status);
17019e39c5baSBill Taylor }
17029e39c5baSBill Taylor
17039e39c5baSBill Taylor /* Wait for Write Byte to Complete */
17049e39c5baSBill Taylor i = 0;
17059e39c5baSBill Taylor do {
17069e39c5baSBill Taylor drv_usecwait(1);
17079e39c5baSBill Taylor stat = hermon_flash_read(state, addr & ~3, &status);
17089e39c5baSBill Taylor if (status != 0) {
17099e39c5baSBill Taylor return (status);
17109e39c5baSBill Taylor }
17119e39c5baSBill Taylor
17129e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_write) {
17139e39c5baSBill Taylor cmn_err(CE_WARN,
17149e39c5baSBill Taylor "hermon_flash_write_byte: ACS write "
17159e39c5baSBill Taylor "timeout: addr: 0x%x, data: 0x%x\n",
17169e39c5baSBill Taylor addr, data);
17179e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
17189e39c5baSBill Taylor HCA_ERR_IOCTL);
17199e39c5baSBill Taylor return (EIO);
17209e39c5baSBill Taylor }
17219e39c5baSBill Taylor i++;
17229e39c5baSBill Taylor } while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
17239e39c5baSBill Taylor
17249e39c5baSBill Taylor break;
17259e39c5baSBill Taylor
17269e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
17279e39c5baSBill Taylor /* Issue Flash Byte program command */
17289e39c5baSBill Taylor hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_WRITE,
17299e39c5baSBill Taylor &status);
17309e39c5baSBill Taylor if (status != 0) {
17319e39c5baSBill Taylor return (status);
17329e39c5baSBill Taylor }
17339e39c5baSBill Taylor hermon_flash_write(state, addr, data, &status);
17349e39c5baSBill Taylor if (status != 0) {
17359e39c5baSBill Taylor return (status);
17369e39c5baSBill Taylor }
17379e39c5baSBill Taylor
17389e39c5baSBill Taylor /* Wait for Write Byte to Complete */
17399e39c5baSBill Taylor i = 0;
17409e39c5baSBill Taylor do {
17419e39c5baSBill Taylor drv_usecwait(1);
17429e39c5baSBill Taylor stat = hermon_flash_read(state, addr & ~3, &status);
17439e39c5baSBill Taylor if (status != 0) {
17449e39c5baSBill Taylor return (status);
17459e39c5baSBill Taylor }
17469e39c5baSBill Taylor
17479e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_write) {
17489e39c5baSBill Taylor cmn_err(CE_WARN,
17499e39c5baSBill Taylor "hermon_flash_write_byte: ICS write "
17509e39c5baSBill Taylor "timeout: addr: %x, data: %x\n",
17519e39c5baSBill Taylor addr, data);
17529e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
17539e39c5baSBill Taylor HCA_ERR_IOCTL);
17549e39c5baSBill Taylor return (EIO);
17559e39c5baSBill Taylor }
17569e39c5baSBill Taylor i++;
17579e39c5baSBill Taylor } while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
17589e39c5baSBill Taylor
17599e39c5baSBill Taylor if (stat & HERMON_HW_FLASH_ICS_ERROR) {
17609e39c5baSBill Taylor cmn_err(CE_WARN,
17619e39c5baSBill Taylor "hermon_flash_write_byte: ICS write cmd error: "
17629e39c5baSBill Taylor "addr: %x, data: %x\n",
17639e39c5baSBill Taylor addr, data);
17649e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
17659e39c5baSBill Taylor return (EIO);
17669e39c5baSBill Taylor }
17679e39c5baSBill Taylor break;
17689e39c5baSBill Taylor
17699e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
17709e39c5baSBill Taylor /*
17719e39c5baSBill Taylor * Our lowest write granularity on SPI is a dword.
17729e39c5baSBill Taylor * To support this ioctl option, we can read in the
17739e39c5baSBill Taylor * dword that contains this byte, modify this byte,
17749e39c5baSBill Taylor * and write the dword back out.
17759e39c5baSBill Taylor */
17769e39c5baSBill Taylor
17779e39c5baSBill Taylor /* Determine dword offset and byte offset within the dword */
17789e39c5baSBill Taylor byte_offset = addr & 3;
17799e39c5baSBill Taylor dword_addr = addr - byte_offset;
17809e39c5baSBill Taylor #ifdef _LITTLE_ENDIAN
17819e39c5baSBill Taylor byte_offset = 3 - byte_offset;
17829e39c5baSBill Taylor #endif
17839e39c5baSBill Taylor
17849e39c5baSBill Taylor /* Read in dword */
17859e39c5baSBill Taylor if ((status = hermon_flash_read_quadlet(state, &dword.dword,
17869e39c5baSBill Taylor dword_addr)) != 0)
17879e39c5baSBill Taylor break;
17889e39c5baSBill Taylor
17899e39c5baSBill Taylor /* Set "data" to the appopriate byte */
17909e39c5baSBill Taylor dword.bytes[byte_offset] = data;
17919e39c5baSBill Taylor
17929e39c5baSBill Taylor /* Write modified dword back out */
17939e39c5baSBill Taylor status = hermon_flash_spi_write_dword(state, dword_addr,
17949e39c5baSBill Taylor dword.dword);
17959e39c5baSBill Taylor
17969e39c5baSBill Taylor break;
17979e39c5baSBill Taylor
17989e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
17999e39c5baSBill Taylor default:
18009e39c5baSBill Taylor cmn_err(CE_WARN,
18019e39c5baSBill Taylor "hermon_flash_write_byte: unknown cmd set: 0x%x\n",
18029e39c5baSBill Taylor state->hs_fw_cmdset);
18039e39c5baSBill Taylor status = EINVAL;
18049e39c5baSBill Taylor break;
18059e39c5baSBill Taylor }
18069e39c5baSBill Taylor
18079e39c5baSBill Taylor return (status);
18089e39c5baSBill Taylor }
18099e39c5baSBill Taylor
18109e39c5baSBill Taylor /*
18119e39c5baSBill Taylor * hermon_flash_erase_sector()
18129e39c5baSBill Taylor */
18139e39c5baSBill Taylor static int
hermon_flash_erase_sector(hermon_state_t * state,uint32_t sector_num)18149e39c5baSBill Taylor hermon_flash_erase_sector(hermon_state_t *state, uint32_t sector_num)
18159e39c5baSBill Taylor {
18169e39c5baSBill Taylor ddi_acc_handle_t hdl;
18179e39c5baSBill Taylor uint32_t addr;
18189e39c5baSBill Taylor uint32_t stat;
18199e39c5baSBill Taylor int status = 0;
18209e39c5baSBill Taylor int i;
18219e39c5baSBill Taylor
18229e39c5baSBill Taylor /* initialize the FMA retry loop */
18239e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
18249e39c5baSBill Taylor
18259e39c5baSBill Taylor /* Get address from sector num */
18269e39c5baSBill Taylor addr = sector_num << state->hs_fw_log_sector_sz;
18279e39c5baSBill Taylor
18289e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
18299e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
18309e39c5baSBill Taylor /* Issue Flash Sector Erase Command */
18319e39c5baSBill Taylor hermon_flash_write(state, addr, 0xAA, &status);
18329e39c5baSBill Taylor if (status != 0) {
18339e39c5baSBill Taylor return (status);
18349e39c5baSBill Taylor }
18359e39c5baSBill Taylor
18369e39c5baSBill Taylor hermon_flash_write(state, addr, 0x55, &status);
18379e39c5baSBill Taylor if (status != 0) {
18389e39c5baSBill Taylor return (status);
18399e39c5baSBill Taylor }
18409e39c5baSBill Taylor
18419e39c5baSBill Taylor hermon_flash_write(state, addr, 0x80, &status);
18429e39c5baSBill Taylor if (status != 0) {
18439e39c5baSBill Taylor return (status);
18449e39c5baSBill Taylor }
18459e39c5baSBill Taylor
18469e39c5baSBill Taylor hermon_flash_write(state, addr, 0xAA, &status);
18479e39c5baSBill Taylor if (status != 0) {
18489e39c5baSBill Taylor return (status);
18499e39c5baSBill Taylor }
18509e39c5baSBill Taylor
18519e39c5baSBill Taylor hermon_flash_write(state, addr, 0x55, &status);
18529e39c5baSBill Taylor if (status != 0) {
18539e39c5baSBill Taylor return (status);
18549e39c5baSBill Taylor }
18559e39c5baSBill Taylor
18569e39c5baSBill Taylor hermon_flash_write(state, addr, 0x30, &status);
18579e39c5baSBill Taylor if (status != 0) {
18589e39c5baSBill Taylor return (status);
18599e39c5baSBill Taylor }
18609e39c5baSBill Taylor
18619e39c5baSBill Taylor /* Wait for Sector Erase to complete */
18629e39c5baSBill Taylor i = 0;
18639e39c5baSBill Taylor do {
18649e39c5baSBill Taylor drv_usecwait(1);
18659e39c5baSBill Taylor stat = hermon_flash_read(state, addr, &status);
18669e39c5baSBill Taylor if (status != 0) {
18679e39c5baSBill Taylor return (status);
18689e39c5baSBill Taylor }
18699e39c5baSBill Taylor
18709e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_erase) {
18719e39c5baSBill Taylor cmn_err(CE_WARN,
18729e39c5baSBill Taylor "hermon_flash_erase_sector: "
18739e39c5baSBill Taylor "ACS erase timeout\n");
18749e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
18759e39c5baSBill Taylor HCA_ERR_IOCTL);
18769e39c5baSBill Taylor return (EIO);
18779e39c5baSBill Taylor }
18789e39c5baSBill Taylor i++;
18799e39c5baSBill Taylor } while (stat != 0xFFFFFFFF);
18809e39c5baSBill Taylor break;
18819e39c5baSBill Taylor
18829e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
18839e39c5baSBill Taylor /* Issue Flash Sector Erase Command */
18849e39c5baSBill Taylor hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_ERASE,
18859e39c5baSBill Taylor &status);
18869e39c5baSBill Taylor if (status != 0) {
18879e39c5baSBill Taylor return (status);
18889e39c5baSBill Taylor }
18899e39c5baSBill Taylor
18909e39c5baSBill Taylor hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_CONFIRM,
18919e39c5baSBill Taylor &status);
18929e39c5baSBill Taylor if (status != 0) {
18939e39c5baSBill Taylor return (status);
18949e39c5baSBill Taylor }
18959e39c5baSBill Taylor
18969e39c5baSBill Taylor /* Wait for Sector Erase to complete */
18979e39c5baSBill Taylor i = 0;
18989e39c5baSBill Taylor do {
18999e39c5baSBill Taylor drv_usecwait(1);
19009e39c5baSBill Taylor stat = hermon_flash_read(state, addr & ~3, &status);
19019e39c5baSBill Taylor if (status != 0) {
19029e39c5baSBill Taylor return (status);
19039e39c5baSBill Taylor }
19049e39c5baSBill Taylor
19059e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_erase) {
19069e39c5baSBill Taylor cmn_err(CE_WARN,
19079e39c5baSBill Taylor "hermon_flash_erase_sector: "
19089e39c5baSBill Taylor "ICS erase timeout\n");
19099e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
19109e39c5baSBill Taylor HCA_ERR_IOCTL);
19119e39c5baSBill Taylor return (EIO);
19129e39c5baSBill Taylor }
19139e39c5baSBill Taylor i++;
19149e39c5baSBill Taylor } while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
19159e39c5baSBill Taylor
19169e39c5baSBill Taylor if (stat & HERMON_HW_FLASH_ICS_ERROR) {
19179e39c5baSBill Taylor cmn_err(CE_WARN,
19189e39c5baSBill Taylor "hermon_flash_erase_sector: "
19199e39c5baSBill Taylor "ICS erase cmd error\n");
19209e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
19219e39c5baSBill Taylor HCA_ERR_IOCTL);
19229e39c5baSBill Taylor return (EIO);
19239e39c5baSBill Taylor }
19249e39c5baSBill Taylor break;
19259e39c5baSBill Taylor
19269e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
19279e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
19289e39c5baSBill Taylor
19299e39c5baSBill Taylor /* the FMA retry loop starts. */
19309e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
19319e39c5baSBill Taylor fm_test);
19329e39c5baSBill Taylor
19339e39c5baSBill Taylor /* Issue Write Enable */
19349e39c5baSBill Taylor hermon_flash_spi_write_enable(state);
19359e39c5baSBill Taylor
19369e39c5baSBill Taylor /* Set the Address */
19379e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
19389e39c5baSBill Taylor addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
19399e39c5baSBill Taylor
19409e39c5baSBill Taylor /* Issue Flash Sector Erase */
19419e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl,
19429e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
19439e39c5baSBill Taylor HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
19449e39c5baSBill Taylor ((uint32_t)(HERMON_HW_FLASH_SPI_SECTOR_ERASE) <<
19459e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT));
19469e39c5baSBill Taylor
19479e39c5baSBill Taylor /* the FMA retry loop ends. */
19489e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status,
19499e39c5baSBill Taylor fm_test);
19509e39c5baSBill Taylor
19519e39c5baSBill Taylor /* Wait for Sector Erase to complete */
19529e39c5baSBill Taylor status = hermon_flash_spi_wait_wip(state);
19539e39c5baSBill Taylor break;
19549e39c5baSBill Taylor
19559e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
19569e39c5baSBill Taylor default:
19579e39c5baSBill Taylor cmn_err(CE_WARN,
19589e39c5baSBill Taylor "hermon_flash_erase_sector: unknown cmd set: 0x%x\n",
19599e39c5baSBill Taylor state->hs_fw_cmdset);
19609e39c5baSBill Taylor status = EINVAL;
19619e39c5baSBill Taylor break;
19629e39c5baSBill Taylor }
19639e39c5baSBill Taylor
19649e39c5baSBill Taylor /* Reset the flash device */
19659e39c5baSBill Taylor if (status == 0) {
19669e39c5baSBill Taylor status = hermon_flash_reset(state);
19679e39c5baSBill Taylor }
19689e39c5baSBill Taylor return (status);
19699e39c5baSBill Taylor
19709e39c5baSBill Taylor pio_error:
19719e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
19729e39c5baSBill Taylor return (EIO);
19739e39c5baSBill Taylor }
19749e39c5baSBill Taylor
19759e39c5baSBill Taylor /*
19769e39c5baSBill Taylor * hermon_flash_erase_chip()
19779e39c5baSBill Taylor */
19789e39c5baSBill Taylor static int
hermon_flash_erase_chip(hermon_state_t * state)19799e39c5baSBill Taylor hermon_flash_erase_chip(hermon_state_t *state)
19809e39c5baSBill Taylor {
19819e39c5baSBill Taylor uint32_t stat;
19829e39c5baSBill Taylor uint_t size;
19839e39c5baSBill Taylor int status = 0;
19849e39c5baSBill Taylor int i;
19859e39c5baSBill Taylor int num_sect;
19869e39c5baSBill Taylor
19879e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
19889e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
19899e39c5baSBill Taylor /* Issue Flash Chip Erase Command */
19909e39c5baSBill Taylor hermon_flash_write(state, 0, 0xAA, &status);
19919e39c5baSBill Taylor if (status != 0) {
19929e39c5baSBill Taylor return (status);
19939e39c5baSBill Taylor }
19949e39c5baSBill Taylor
19959e39c5baSBill Taylor hermon_flash_write(state, 0, 0x55, &status);
19969e39c5baSBill Taylor if (status != 0) {
19979e39c5baSBill Taylor return (status);
19989e39c5baSBill Taylor }
19999e39c5baSBill Taylor
20009e39c5baSBill Taylor hermon_flash_write(state, 0, 0x80, &status);
20019e39c5baSBill Taylor if (status != 0) {
20029e39c5baSBill Taylor return (status);
20039e39c5baSBill Taylor }
20049e39c5baSBill Taylor
20059e39c5baSBill Taylor hermon_flash_write(state, 0, 0xAA, &status);
20069e39c5baSBill Taylor if (status != 0) {
20079e39c5baSBill Taylor return (status);
20089e39c5baSBill Taylor }
20099e39c5baSBill Taylor
20109e39c5baSBill Taylor hermon_flash_write(state, 0, 0x55, &status);
20119e39c5baSBill Taylor if (status != 0) {
20129e39c5baSBill Taylor return (status);
20139e39c5baSBill Taylor }
20149e39c5baSBill Taylor
20159e39c5baSBill Taylor hermon_flash_write(state, 0, 0x10, &status);
20169e39c5baSBill Taylor if (status != 0) {
20179e39c5baSBill Taylor return (status);
20189e39c5baSBill Taylor }
20199e39c5baSBill Taylor
20209e39c5baSBill Taylor /* Wait for Chip Erase to Complete */
20219e39c5baSBill Taylor i = 0;
20229e39c5baSBill Taylor do {
20239e39c5baSBill Taylor drv_usecwait(1);
20249e39c5baSBill Taylor stat = hermon_flash_read(state, 0, &status);
20259e39c5baSBill Taylor if (status != 0) {
20269e39c5baSBill Taylor return (status);
20279e39c5baSBill Taylor }
20289e39c5baSBill Taylor
20299e39c5baSBill Taylor if (i == hermon_hw_flash_timeout_erase) {
20309e39c5baSBill Taylor cmn_err(CE_WARN,
20319e39c5baSBill Taylor "hermon_flash_erase_chip: erase timeout\n");
20329e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR,
20339e39c5baSBill Taylor HCA_ERR_IOCTL);
20349e39c5baSBill Taylor return (EIO);
20359e39c5baSBill Taylor }
20369e39c5baSBill Taylor i++;
20379e39c5baSBill Taylor } while (stat != 0xFFFFFFFF);
20389e39c5baSBill Taylor break;
20399e39c5baSBill Taylor
20409e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
20419e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
20429e39c5baSBill Taylor /*
20439e39c5baSBill Taylor * These chips don't have a chip erase command, so erase
20449e39c5baSBill Taylor * all blocks one at a time.
20459e39c5baSBill Taylor */
20469e39c5baSBill Taylor size = (0x1 << state->hs_fw_log_sector_sz);
20479e39c5baSBill Taylor num_sect = state->hs_fw_device_sz / size;
20489e39c5baSBill Taylor
20499e39c5baSBill Taylor for (i = 0; i < num_sect; i++) {
20509e39c5baSBill Taylor status = hermon_flash_erase_sector(state, i);
20519e39c5baSBill Taylor if (status != 0) {
20529e39c5baSBill Taylor cmn_err(CE_WARN,
20539e39c5baSBill Taylor "hermon_flash_erase_chip: "
20549e39c5baSBill Taylor "sector %d erase error\n", i);
20559e39c5baSBill Taylor return (status);
20569e39c5baSBill Taylor }
20579e39c5baSBill Taylor }
20589e39c5baSBill Taylor break;
20599e39c5baSBill Taylor
20609e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
20619e39c5baSBill Taylor default:
20629e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_erase_chip: "
20639e39c5baSBill Taylor "unknown cmd set: 0x%x\n", state->hs_fw_cmdset);
20649e39c5baSBill Taylor status = EINVAL;
20659e39c5baSBill Taylor break;
20669e39c5baSBill Taylor }
20679e39c5baSBill Taylor
20689e39c5baSBill Taylor return (status);
20699e39c5baSBill Taylor }
20709e39c5baSBill Taylor
20719e39c5baSBill Taylor /*
20729e39c5baSBill Taylor * hermon_flash_spi_write_enable()
20739e39c5baSBill Taylor */
20749e39c5baSBill Taylor static void
hermon_flash_spi_write_enable(hermon_state_t * state)20759e39c5baSBill Taylor hermon_flash_spi_write_enable(hermon_state_t *state)
20769e39c5baSBill Taylor {
20779e39c5baSBill Taylor ddi_acc_handle_t hdl;
20789e39c5baSBill Taylor
20799e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
20809e39c5baSBill Taylor
20819e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl,
20829e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
20839e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_WRITE_ENABLE <<
20849e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT));
20859e39c5baSBill Taylor }
20869e39c5baSBill Taylor
20879e39c5baSBill Taylor /*
20889e39c5baSBill Taylor * hermon_flash_spi_wait_wip()
20899e39c5baSBill Taylor */
20909e39c5baSBill Taylor static int
hermon_flash_spi_wait_wip(hermon_state_t * state)20919e39c5baSBill Taylor hermon_flash_spi_wait_wip(hermon_state_t *state)
20929e39c5baSBill Taylor {
20939e39c5baSBill Taylor ddi_acc_handle_t hdl;
20949e39c5baSBill Taylor uint32_t status;
20959e39c5baSBill Taylor
20969e39c5baSBill Taylor /* initialize the FMA retry loop */
20979e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
20989e39c5baSBill Taylor
20999e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
21009e39c5baSBill Taylor
21019e39c5baSBill Taylor /* the FMA retry loop starts. */
21029e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
21039e39c5baSBill Taylor fm_test);
21049e39c5baSBill Taylor
21059e39c5baSBill Taylor /* wait on the gateway to clear busy */
21069e39c5baSBill Taylor do {
21079e39c5baSBill Taylor status = hermon_flash_read_cfg(state, hdl,
21089e39c5baSBill Taylor HERMON_HW_FLASH_SPI_GW);
21099e39c5baSBill Taylor } while (status & HERMON_HW_FLASH_SPI_BUSY);
21109e39c5baSBill Taylor
21119e39c5baSBill Taylor /* now, get the status and check for WIP to clear */
21129e39c5baSBill Taylor do {
21139e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl,
21149e39c5baSBill Taylor HERMON_HW_FLASH_SPI_READ_OP |
21159e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
21169e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
21179e39c5baSBill Taylor HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
21189e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_READ_STATUS_REG <<
21199e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT));
21209e39c5baSBill Taylor
21219e39c5baSBill Taylor status = hermon_flash_read_cfg(state, hdl,
21229e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA);
21239e39c5baSBill Taylor } while (status & HERMON_HW_FLASH_SPI_WIP);
21249e39c5baSBill Taylor
21259e39c5baSBill Taylor /* the FMA retry loop ends. */
21269e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
21279e39c5baSBill Taylor return (0);
21289e39c5baSBill Taylor
21299e39c5baSBill Taylor pio_error:
21309e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21319e39c5baSBill Taylor return (EIO);
21329e39c5baSBill Taylor }
21339e39c5baSBill Taylor
21349e39c5baSBill Taylor /*
21359e39c5baSBill Taylor * hermon_flash_bank()
21369e39c5baSBill Taylor */
21379e39c5baSBill Taylor static int
hermon_flash_bank(hermon_state_t * state,uint32_t addr)21389e39c5baSBill Taylor hermon_flash_bank(hermon_state_t *state, uint32_t addr)
21399e39c5baSBill Taylor {
21409e39c5baSBill Taylor ddi_acc_handle_t hdl;
21419e39c5baSBill Taylor uint32_t bank;
21429e39c5baSBill Taylor
21439e39c5baSBill Taylor /* initialize the FMA retry loop */
21449e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
21459e39c5baSBill Taylor
21469e39c5baSBill Taylor /* Set handle */
21479e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
21489e39c5baSBill Taylor
21499e39c5baSBill Taylor /* Determine the bank setting from the address */
21509e39c5baSBill Taylor bank = addr & HERMON_HW_FLASH_BANK_MASK;
21519e39c5baSBill Taylor
21529e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->hs_fw_flashbank))
21539e39c5baSBill Taylor
21549e39c5baSBill Taylor /*
21559e39c5baSBill Taylor * If the bank is different from the currently set bank, we need to
21569e39c5baSBill Taylor * change it. Also, if an 'addr' of 0 is given, this allows the
21579e39c5baSBill Taylor * capability to force the flash bank to 0. This is useful at init
21589e39c5baSBill Taylor * time to initially set the bank value
21599e39c5baSBill Taylor */
21609e39c5baSBill Taylor if (state->hs_fw_flashbank != bank || addr == 0) {
21619e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
21629e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
21639e39c5baSBill Taylor /* CMJ: not needed for hermon */
21649e39c5baSBill Taylor break;
21659e39c5baSBill Taylor
21669e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
21679e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
21689e39c5baSBill Taylor /* the FMA retry loop starts. */
21699e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt,
21709e39c5baSBill Taylor fm_status, fm_test);
21719e39c5baSBill Taylor
21729e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl,
21739e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_DATACLEAR, 0x70);
21749e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl,
21759e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_DATASET, (bank >> 15) & 0x70);
21769e39c5baSBill Taylor
21779e39c5baSBill Taylor /* the FMA retry loop ends. */
21789e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt,
21799e39c5baSBill Taylor fm_status, fm_test);
21809e39c5baSBill Taylor break;
21819e39c5baSBill Taylor
21829e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
21839e39c5baSBill Taylor default:
21849e39c5baSBill Taylor return (EINVAL);
21859e39c5baSBill Taylor }
21869e39c5baSBill Taylor
21879e39c5baSBill Taylor state->hs_fw_flashbank = bank;
21889e39c5baSBill Taylor }
21899e39c5baSBill Taylor return (0);
21909e39c5baSBill Taylor
21919e39c5baSBill Taylor pio_error:
21929e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21939e39c5baSBill Taylor return (EIO);
21949e39c5baSBill Taylor }
21959e39c5baSBill Taylor
21969e39c5baSBill Taylor /*
21979e39c5baSBill Taylor * hermon_flash_spi_exec_command()
21989e39c5baSBill Taylor */
21999e39c5baSBill Taylor static void
hermon_flash_spi_exec_command(hermon_state_t * state,ddi_acc_handle_t hdl,uint32_t cmd)22009e39c5baSBill Taylor hermon_flash_spi_exec_command(hermon_state_t *state, ddi_acc_handle_t hdl,
22019e39c5baSBill Taylor uint32_t cmd)
22029e39c5baSBill Taylor {
22039e39c5baSBill Taylor uint32_t data;
22049e39c5baSBill Taylor int timeout = 0;
22059e39c5baSBill Taylor
22069e39c5baSBill Taylor cmd |= HERMON_HW_FLASH_SPI_BUSY | HERMON_HW_FLASH_SPI_ENABLE_OFF;
22079e39c5baSBill Taylor
22089e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_GW, cmd);
22099e39c5baSBill Taylor
22109e39c5baSBill Taylor do {
22119e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl,
22129e39c5baSBill Taylor HERMON_HW_FLASH_SPI_GW);
22139e39c5baSBill Taylor timeout++;
22149e39c5baSBill Taylor } while ((data & HERMON_HW_FLASH_SPI_BUSY) &&
22159e39c5baSBill Taylor (timeout < hermon_hw_flash_timeout_config));
22169e39c5baSBill Taylor }
22179e39c5baSBill Taylor
22189e39c5baSBill Taylor /*
22199e39c5baSBill Taylor * hermon_flash_read()
22209e39c5baSBill Taylor */
22219e39c5baSBill Taylor static uint32_t
hermon_flash_read(hermon_state_t * state,uint32_t addr,int * err)22229e39c5baSBill Taylor hermon_flash_read(hermon_state_t *state, uint32_t addr, int *err)
22239e39c5baSBill Taylor {
22249e39c5baSBill Taylor ddi_acc_handle_t hdl;
22259e39c5baSBill Taylor uint32_t data = 0;
22269e39c5baSBill Taylor int timeout, status = 0;
22279e39c5baSBill Taylor
22289e39c5baSBill Taylor /* initialize the FMA retry loop */
22299e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
22309e39c5baSBill Taylor
22319e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
22329e39c5baSBill Taylor
22339e39c5baSBill Taylor /* the FMA retry loop starts. */
22349e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
22359e39c5baSBill Taylor fm_test);
22369e39c5baSBill Taylor
22379e39c5baSBill Taylor switch (state->hs_fw_cmdset) {
22389e39c5baSBill Taylor case HERMON_FLASH_SPI_CMDSET:
22399e39c5baSBill Taylor /* Set the transaction address */
22409e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
22419e39c5baSBill Taylor (addr & HERMON_HW_FLASH_SPI_ADDR_MASK));
22429e39c5baSBill Taylor
22439e39c5baSBill Taylor hermon_flash_spi_exec_command(state, hdl,
22449e39c5baSBill Taylor HERMON_HW_FLASH_SPI_READ_OP |
22459e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
22469e39c5baSBill Taylor HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
22479e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
22489e39c5baSBill Taylor HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
22499e39c5baSBill Taylor (HERMON_HW_FLASH_SPI_READ <<
22509e39c5baSBill Taylor HERMON_HW_FLASH_SPI_INSTR_SHIFT));
22519e39c5baSBill Taylor
22529e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl,
22539e39c5baSBill Taylor HERMON_HW_FLASH_SPI_DATA);
22549e39c5baSBill Taylor break;
22559e39c5baSBill Taylor
22569e39c5baSBill Taylor case HERMON_FLASH_INTEL_CMDSET:
22579e39c5baSBill Taylor case HERMON_FLASH_AMD_CMDSET:
22589e39c5baSBill Taylor /*
22599e39c5baSBill Taylor * The Read operation does the following:
22609e39c5baSBill Taylor * 1) Write the masked address to the HERMON_FLASH_ADDR
22619e39c5baSBill Taylor * register. Only the least significant 19 bits are valid.
22629e39c5baSBill Taylor * 2) Read back the register until the command has completed.
22639e39c5baSBill Taylor * 3) Read the data retrieved from the address at the
22649e39c5baSBill Taylor * HERMON_FLASH_DATA register.
22659e39c5baSBill Taylor */
22669e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
22679e39c5baSBill Taylor (addr & HERMON_HW_FLASH_ADDR_MASK) | (1 << 29));
22689e39c5baSBill Taylor
22699e39c5baSBill Taylor timeout = 0;
22709e39c5baSBill Taylor do {
22719e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl,
22729e39c5baSBill Taylor HERMON_HW_FLASH_ADDR);
22739e39c5baSBill Taylor timeout++;
22749e39c5baSBill Taylor } while ((data & HERMON_HW_FLASH_CMD_MASK) &&
22759e39c5baSBill Taylor (timeout < hermon_hw_flash_timeout_config));
22769e39c5baSBill Taylor
227726190627SShantkumar Hiremath if (timeout == hermon_hw_flash_timeout_config) {
227826190627SShantkumar Hiremath cmn_err(CE_WARN, "hermon_flash_read: command timed "
227926190627SShantkumar Hiremath "out.\n");
228026190627SShantkumar Hiremath *err = EIO;
228126190627SShantkumar Hiremath hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
228226190627SShantkumar Hiremath return (data);
228326190627SShantkumar Hiremath }
228426190627SShantkumar Hiremath
22859e39c5baSBill Taylor data = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_DATA);
22869e39c5baSBill Taylor break;
22879e39c5baSBill Taylor
22889e39c5baSBill Taylor case HERMON_FLASH_UNKNOWN_CMDSET:
22899e39c5baSBill Taylor default:
22909e39c5baSBill Taylor cmn_err(CE_CONT, "hermon_flash_read: unknown cmdset: 0x%x\n",
22919e39c5baSBill Taylor state->hs_fw_cmdset);
22929e39c5baSBill Taylor status = EINVAL;
22939e39c5baSBill Taylor break;
22949e39c5baSBill Taylor }
22959e39c5baSBill Taylor
22969e39c5baSBill Taylor
22979e39c5baSBill Taylor /* the FMA retry loop ends. */
22989e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
22999e39c5baSBill Taylor *err = status;
23009e39c5baSBill Taylor return (data);
23019e39c5baSBill Taylor
23029e39c5baSBill Taylor pio_error:
23039e39c5baSBill Taylor *err = EIO;
23049e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23059e39c5baSBill Taylor return (data);
23069e39c5baSBill Taylor }
23079e39c5baSBill Taylor
23089e39c5baSBill Taylor /*
23099e39c5baSBill Taylor * hermon_flash_write()
23109e39c5baSBill Taylor */
23119e39c5baSBill Taylor static void
hermon_flash_write(hermon_state_t * state,uint32_t addr,uchar_t data,int * err)23129e39c5baSBill Taylor hermon_flash_write(hermon_state_t *state, uint32_t addr, uchar_t data, int *err)
23139e39c5baSBill Taylor {
23149e39c5baSBill Taylor ddi_acc_handle_t hdl;
23159e39c5baSBill Taylor int cmd;
23169e39c5baSBill Taylor int timeout;
23179e39c5baSBill Taylor
23189e39c5baSBill Taylor /* initialize the FMA retry loop */
23199e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23209e39c5baSBill Taylor
23219e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
23229e39c5baSBill Taylor
23239e39c5baSBill Taylor /* the FMA retry loop starts. */
23249e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23259e39c5baSBill Taylor fm_test);
23269e39c5baSBill Taylor
23279e39c5baSBill Taylor /*
23289e39c5baSBill Taylor * The Write operation does the following:
23299e39c5baSBill Taylor * 1) Write the data to be written to the HERMON_FLASH_DATA offset.
23309e39c5baSBill Taylor * 2) Write the address to write the data to to the HERMON_FLASH_ADDR
23319e39c5baSBill Taylor * offset.
23329e39c5baSBill Taylor * 3) Wait until the write completes.
23339e39c5baSBill Taylor */
23349e39c5baSBill Taylor
23359e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_DATA, data << 24);
23369e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
23379e39c5baSBill Taylor (addr & 0x7FFFF) | (2 << 29));
23389e39c5baSBill Taylor
23399e39c5baSBill Taylor timeout = 0;
23409e39c5baSBill Taylor do {
23419e39c5baSBill Taylor cmd = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_ADDR);
23429e39c5baSBill Taylor timeout++;
23439e39c5baSBill Taylor } while ((cmd & HERMON_HW_FLASH_CMD_MASK) &&
23449e39c5baSBill Taylor (timeout < hermon_hw_flash_timeout_config));
23459e39c5baSBill Taylor
23469e39c5baSBill Taylor if (timeout == hermon_hw_flash_timeout_config) {
23479e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_write: config cmd timeout.\n");
23489e39c5baSBill Taylor *err = EIO;
23499e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23509e39c5baSBill Taylor return;
23519e39c5baSBill Taylor }
23529e39c5baSBill Taylor
23539e39c5baSBill Taylor /* the FMA retry loop ends. */
23549e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
23559e39c5baSBill Taylor *err = 0;
23569e39c5baSBill Taylor return;
23579e39c5baSBill Taylor
23589e39c5baSBill Taylor pio_error:
23599e39c5baSBill Taylor *err = EIO;
23609e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23619e39c5baSBill Taylor }
23629e39c5baSBill Taylor
23639e39c5baSBill Taylor /*
23649e39c5baSBill Taylor * hermon_flash_init()
23659e39c5baSBill Taylor */
23669e39c5baSBill Taylor static int
hermon_flash_init(hermon_state_t * state)23679e39c5baSBill Taylor hermon_flash_init(hermon_state_t *state)
23689e39c5baSBill Taylor {
23699e39c5baSBill Taylor uint32_t word;
23709e39c5baSBill Taylor ddi_acc_handle_t hdl;
23719e39c5baSBill Taylor int sema_cnt;
23729e39c5baSBill Taylor int gpio;
23739e39c5baSBill Taylor
23749e39c5baSBill Taylor /* initialize the FMA retry loop */
23759e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23769e39c5baSBill Taylor
23779e39c5baSBill Taylor /* Set handle */
23789e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
23799e39c5baSBill Taylor
23809e39c5baSBill Taylor /* the FMA retry loop starts. */
23819e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23829e39c5baSBill Taylor fm_test);
23839e39c5baSBill Taylor
23849e39c5baSBill Taylor /* Init the flash */
23859e39c5baSBill Taylor
23869e39c5baSBill Taylor #ifdef DO_WRCONF
23879e39c5baSBill Taylor /*
23889e39c5baSBill Taylor * Grab the WRCONF semaphore.
23899e39c5baSBill Taylor */
23909e39c5baSBill Taylor word = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_WRCONF_SEMA);
23919e39c5baSBill Taylor #endif
23929e39c5baSBill Taylor
23939e39c5baSBill Taylor /*
23949e39c5baSBill Taylor * Grab the GPIO semaphore. This allows us exclusive access to the
23959e39c5baSBill Taylor * GPIO settings on the Hermon for the duration of the flash burning
23969e39c5baSBill Taylor * procedure.
23979e39c5baSBill Taylor */
23989e39c5baSBill Taylor sema_cnt = 0;
23999e39c5baSBill Taylor do {
24009e39c5baSBill Taylor word = hermon_flash_read_cfg(state, hdl,
24019e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_SEMA);
24029e39c5baSBill Taylor if (word == 0) {
24039e39c5baSBill Taylor break;
24049e39c5baSBill Taylor }
24059e39c5baSBill Taylor
24069e39c5baSBill Taylor sema_cnt++;
24079e39c5baSBill Taylor drv_usecwait(1);
24089e39c5baSBill Taylor
24099e39c5baSBill Taylor } while (sema_cnt < hermon_hw_flash_timeout_gpio_sema);
24109e39c5baSBill Taylor
24119e39c5baSBill Taylor /*
24129e39c5baSBill Taylor * Determine if we timed out trying to grab the GPIO semaphore
24139e39c5baSBill Taylor */
24149e39c5baSBill Taylor if (sema_cnt == hermon_hw_flash_timeout_gpio_sema) {
24159e39c5baSBill Taylor cmn_err(CE_WARN, "hermon_flash_init: GPIO SEMA timeout\n");
24169e39c5baSBill Taylor cmn_err(CE_WARN, "GPIO_SEMA value: 0x%x\n", word);
24179e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24189e39c5baSBill Taylor return (EIO);
24199e39c5baSBill Taylor }
24209e39c5baSBill Taylor
24219e39c5baSBill Taylor /* Save away original GPIO Values */
24229e39c5baSBill Taylor state->hs_fw_gpio[0] = hermon_flash_read_cfg(state, hdl,
24239e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_DATA);
24249e39c5baSBill Taylor
24259e39c5baSBill Taylor /* Set new GPIO value */
24269e39c5baSBill Taylor gpio = state->hs_fw_gpio[0] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24279e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, gpio);
24289e39c5baSBill Taylor
24299e39c5baSBill Taylor /* Save away original GPIO Values */
24309e39c5baSBill Taylor state->hs_fw_gpio[1] = hermon_flash_read_cfg(state, hdl,
24319e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_MOD0);
24329e39c5baSBill Taylor state->hs_fw_gpio[2] = hermon_flash_read_cfg(state, hdl,
24339e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_MOD1);
24349e39c5baSBill Taylor
24359e39c5baSBill Taylor /* unlock GPIO */
24369e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
24379e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
24389e39c5baSBill Taylor
24399e39c5baSBill Taylor /*
24409e39c5baSBill Taylor * Set new GPIO values
24419e39c5baSBill Taylor */
24429e39c5baSBill Taylor gpio = state->hs_fw_gpio[1] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24439e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, gpio);
24449e39c5baSBill Taylor
24459e39c5baSBill Taylor gpio = state->hs_fw_gpio[2] & ~HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24469e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, gpio);
24479e39c5baSBill Taylor
24489e39c5baSBill Taylor /* re-lock GPIO */
24499e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
24509e39c5baSBill Taylor
24519e39c5baSBill Taylor /* Set CPUMODE to enable hermon to access the flash device */
24529e39c5baSBill Taylor /* CMJ This code came from arbel. Hermon doesn't seem to need it. */
24539e39c5baSBill Taylor /*
24549e39c5baSBill Taylor * hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_CPUMODE,
24559e39c5baSBill Taylor * 1 << HERMON_HW_FLASH_CPU_SHIFT);
24569e39c5baSBill Taylor */
24579e39c5baSBill Taylor
24589e39c5baSBill Taylor /* the FMA retry loop ends. */
24599e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
24609e39c5baSBill Taylor return (0);
24619e39c5baSBill Taylor
24629e39c5baSBill Taylor pio_error:
24639e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24649e39c5baSBill Taylor return (EIO);
24659e39c5baSBill Taylor }
24669e39c5baSBill Taylor
24679e39c5baSBill Taylor /*
24689e39c5baSBill Taylor * hermon_flash_cfi_init
24699e39c5baSBill Taylor * Implements access to the CFI (Common Flash Interface) data
24709e39c5baSBill Taylor */
24719e39c5baSBill Taylor static int
hermon_flash_cfi_init(hermon_state_t * state,uint32_t * cfi_info,int * intel_xcmd)24729e39c5baSBill Taylor hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
24739e39c5baSBill Taylor int *intel_xcmd)
24749e39c5baSBill Taylor {
24759e39c5baSBill Taylor uint32_t data;
24769e39c5baSBill Taylor uint32_t sector_sz_bytes;
24779e39c5baSBill Taylor uint32_t bit_count;
24789e39c5baSBill Taylor uint8_t cfi_ch_info[HERMON_CFI_INFO_SIZE];
24799e39c5baSBill Taylor int i;
24809e39c5baSBill Taylor int status;
24819e39c5baSBill Taylor
24829e39c5baSBill Taylor /* Right now, all hermon cards use SPI. */
2483*13cc0a0bSBill Taylor if (hermon_device_mode(state)) {
24849e39c5baSBill Taylor /*
24859e39c5baSBill Taylor * Don't use CFI for SPI part. Just fill in what we need
24869e39c5baSBill Taylor * and return.
24879e39c5baSBill Taylor */
24889e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_SPI_CMDSET;
24899e39c5baSBill Taylor state->hs_fw_log_sector_sz = HERMON_FLASH_SPI_LOG_SECTOR_SIZE;
24909e39c5baSBill Taylor state->hs_fw_device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
24919e39c5baSBill Taylor
24929e39c5baSBill Taylor /*
24939e39c5baSBill Taylor * set this to inform caller of cmdset type.
24949e39c5baSBill Taylor */
24959e39c5baSBill Taylor cfi_ch_info[0x13] = HERMON_FLASH_SPI_CMDSET;
24969e39c5baSBill Taylor hermon_flash_cfi_dword(&cfi_info[4], cfi_ch_info, 0x10);
24979e39c5baSBill Taylor return (0);
24989e39c5baSBill Taylor }
24999e39c5baSBill Taylor
25009e39c5baSBill Taylor /*
25019e39c5baSBill Taylor * Determine if the user command supports the Intel Extended
25029e39c5baSBill Taylor * Command Set. The query string is contained in the fourth
25039e39c5baSBill Taylor * quad word.
25049e39c5baSBill Taylor */
25059e39c5baSBill Taylor hermon_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
25069e39c5baSBill Taylor if (cfi_ch_info[0x10] == 'M' &&
25079e39c5baSBill Taylor cfi_ch_info[0x11] == 'X' &&
25089e39c5baSBill Taylor cfi_ch_info[0x12] == '2') {
25099e39c5baSBill Taylor *intel_xcmd = 1; /* support is there */
25109e39c5baSBill Taylor if (hermon_verbose) {
25119e39c5baSBill Taylor IBTF_DPRINTF_L2("hermon",
25129e39c5baSBill Taylor "Support for Intel X is present\n");
25139e39c5baSBill Taylor }
25149e39c5baSBill Taylor }
25159e39c5baSBill Taylor
25169e39c5baSBill Taylor /* CFI QUERY */
25179e39c5baSBill Taylor hermon_flash_write(state, 0x55, HERMON_FLASH_CFI_INIT, &status);
25189e39c5baSBill Taylor if (status != 0) {
25199e39c5baSBill Taylor return (status);
25209e39c5baSBill Taylor }
25219e39c5baSBill Taylor
25229e39c5baSBill Taylor /* temporarily set the cmdset in order to do the initial read */
25239e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_INTEL_CMDSET;
25249e39c5baSBill Taylor
25259e39c5baSBill Taylor /* Read in CFI data */
25269e39c5baSBill Taylor for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 4) {
25279e39c5baSBill Taylor data = hermon_flash_read(state, i, &status);
25289e39c5baSBill Taylor if (status != 0) {
25299e39c5baSBill Taylor return (status);
25309e39c5baSBill Taylor }
25319e39c5baSBill Taylor hermon_flash_cfi_byte(cfi_ch_info, data, i);
25329e39c5baSBill Taylor }
25339e39c5baSBill Taylor
25349e39c5baSBill Taylor /* Determine chip set */
25359e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25369e39c5baSBill Taylor if (cfi_ch_info[0x20] == 'Q' &&
25379e39c5baSBill Taylor cfi_ch_info[0x22] == 'R' &&
25389e39c5baSBill Taylor cfi_ch_info[0x24] == 'Y') {
25399e39c5baSBill Taylor /*
25409e39c5baSBill Taylor * Mode: x16 working in x8 mode (Intel).
25419e39c5baSBill Taylor * Pack data - skip spacing bytes.
25429e39c5baSBill Taylor */
25439e39c5baSBill Taylor if (hermon_verbose) {
25449e39c5baSBill Taylor IBTF_DPRINTF_L2("hermon",
25459e39c5baSBill Taylor "x16 working in x8 mode (Intel)\n");
25469e39c5baSBill Taylor }
25479e39c5baSBill Taylor for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 2) {
25489e39c5baSBill Taylor cfi_ch_info[i/2] = cfi_ch_info[i];
25499e39c5baSBill Taylor }
25509e39c5baSBill Taylor }
25519e39c5baSBill Taylor state->hs_fw_cmdset = cfi_ch_info[0x13];
25529e39c5baSBill Taylor
25539e39c5baSBill Taylor if (state->hs_fw_cmdset != HERMON_FLASH_INTEL_CMDSET &&
25549e39c5baSBill Taylor state->hs_fw_cmdset != HERMON_FLASH_AMD_CMDSET) {
25559e39c5baSBill Taylor cmn_err(CE_WARN,
25569e39c5baSBill Taylor "hermon_flash_cfi_init: UNKNOWN chip cmd set 0x%04x\n",
25579e39c5baSBill Taylor state->hs_fw_cmdset);
25589e39c5baSBill Taylor state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25599e39c5baSBill Taylor return (0);
25609e39c5baSBill Taylor }
25619e39c5baSBill Taylor
25629e39c5baSBill Taylor /* Determine total bytes in one sector size */
25639e39c5baSBill Taylor sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
25649e39c5baSBill Taylor
25659e39c5baSBill Taylor /* Calculate equivalent of log2 (n) */
25669e39c5baSBill Taylor for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
25679e39c5baSBill Taylor sector_sz_bytes >>= 1;
25689e39c5baSBill Taylor }
25699e39c5baSBill Taylor
25709e39c5baSBill Taylor /* Set sector size */
25719e39c5baSBill Taylor state->hs_fw_log_sector_sz = bit_count;
25729e39c5baSBill Taylor
25739e39c5baSBill Taylor /* Set flash size */
25749e39c5baSBill Taylor state->hs_fw_device_sz = 0x1 << cfi_ch_info[0x27];
25759e39c5baSBill Taylor
25769e39c5baSBill Taylor /* Reset to turn off CFI mode */
25779e39c5baSBill Taylor if ((status = hermon_flash_reset(state)) != 0)
25789e39c5baSBill Taylor goto out;
25799e39c5baSBill Taylor
25809e39c5baSBill Taylor /* Pass CFI data back to user command. */
25819e39c5baSBill Taylor for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
25829e39c5baSBill Taylor hermon_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
25839e39c5baSBill Taylor }
25849e39c5baSBill Taylor
25859e39c5baSBill Taylor if (*intel_xcmd == 1) {
25869e39c5baSBill Taylor /*
25879e39c5baSBill Taylor * Inform the user cmd that this driver does support the
25889e39c5baSBill Taylor * Intel Extended Command Set.
25899e39c5baSBill Taylor */
25909e39c5baSBill Taylor cfi_ch_info[0x10] = 'M';
25919e39c5baSBill Taylor cfi_ch_info[0x11] = 'X';
25929e39c5baSBill Taylor cfi_ch_info[0x12] = '2';
25939e39c5baSBill Taylor } else {
25949e39c5baSBill Taylor cfi_ch_info[0x10] = 'Q';
25959e39c5baSBill Taylor cfi_ch_info[0x11] = 'R';
25969e39c5baSBill Taylor cfi_ch_info[0x12] = 'Y';
25979e39c5baSBill Taylor }
25989e39c5baSBill Taylor cfi_ch_info[0x13] = state->hs_fw_cmdset;
25999e39c5baSBill Taylor hermon_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
26009e39c5baSBill Taylor out:
26019e39c5baSBill Taylor return (status);
26029e39c5baSBill Taylor }
26039e39c5baSBill Taylor
26049e39c5baSBill Taylor /*
26059e39c5baSBill Taylor * hermon_flash_fini()
26069e39c5baSBill Taylor */
26079e39c5baSBill Taylor static int
hermon_flash_fini(hermon_state_t * state)26089e39c5baSBill Taylor hermon_flash_fini(hermon_state_t *state)
26099e39c5baSBill Taylor {
26109e39c5baSBill Taylor int status;
26119e39c5baSBill Taylor ddi_acc_handle_t hdl;
26129e39c5baSBill Taylor
26139e39c5baSBill Taylor /* initialize the FMA retry loop */
26149e39c5baSBill Taylor hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
26159e39c5baSBill Taylor
26169e39c5baSBill Taylor /* Set handle */
26179e39c5baSBill Taylor hdl = hermon_get_pcihdl(state);
26189e39c5baSBill Taylor
26199e39c5baSBill Taylor if ((status = hermon_flash_bank(state, 0)) != 0)
26209e39c5baSBill Taylor return (status);
26219e39c5baSBill Taylor
26229e39c5baSBill Taylor /* the FMA retry loop starts. */
26239e39c5baSBill Taylor hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
26249e39c5baSBill Taylor fm_test);
26259e39c5baSBill Taylor
26269e39c5baSBill Taylor /*
26279e39c5baSBill Taylor * Restore original GPIO Values
26289e39c5baSBill Taylor */
26299e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA,
26309e39c5baSBill Taylor state->hs_fw_gpio[0]);
26319e39c5baSBill Taylor
26329e39c5baSBill Taylor /* unlock GPIOs */
26339e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
26349e39c5baSBill Taylor HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
26359e39c5baSBill Taylor
26369e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0,
26379e39c5baSBill Taylor state->hs_fw_gpio[1]);
26389e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1,
26399e39c5baSBill Taylor state->hs_fw_gpio[2]);
26409e39c5baSBill Taylor
26419e39c5baSBill Taylor /* re-lock GPIOs */
26429e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
26439e39c5baSBill Taylor
26449e39c5baSBill Taylor /* Give up gpio semaphore */
26459e39c5baSBill Taylor hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_SEMA, 0);
26469e39c5baSBill Taylor
26479e39c5baSBill Taylor /* the FMA retry loop ends. */
26489e39c5baSBill Taylor hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
26499e39c5baSBill Taylor return (0);
26509e39c5baSBill Taylor
26519e39c5baSBill Taylor pio_error:
26529e39c5baSBill Taylor hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
26539e39c5baSBill Taylor return (EIO);
26549e39c5baSBill Taylor }
26559e39c5baSBill Taylor
26569e39c5baSBill Taylor /*
26579e39c5baSBill Taylor * hermon_flash_read_cfg
26589e39c5baSBill Taylor */
26599e39c5baSBill Taylor static uint32_t
hermon_flash_read_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr)26609e39c5baSBill Taylor hermon_flash_read_cfg(hermon_state_t *state, ddi_acc_handle_t pci_config_hdl,
26619e39c5baSBill Taylor uint32_t addr)
26629e39c5baSBill Taylor {
26639e39c5baSBill Taylor uint32_t read;
26649e39c5baSBill Taylor
26659e39c5baSBill Taylor if (do_bar0) {
26669e39c5baSBill Taylor read = ddi_get32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
26679e39c5baSBill Taylor (state->hs_reg_cmd_baseaddr + addr));
26689e39c5baSBill Taylor } else {
26699e39c5baSBill Taylor /*
26709e39c5baSBill Taylor * Perform flash read operation:
26719e39c5baSBill Taylor * 1) Place addr to read from on the HERMON_HW_FLASH_CFG_ADDR
26729e39c5baSBill Taylor * register
26739e39c5baSBill Taylor * 2) Read data at that addr from the HERMON_HW_FLASH_CFG_DATA
26749e39c5baSBill Taylor * register
26759e39c5baSBill Taylor */
26769e39c5baSBill Taylor pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
26779e39c5baSBill Taylor addr);
26789e39c5baSBill Taylor read = pci_config_get32(pci_config_hdl,
26799e39c5baSBill Taylor HERMON_HW_FLASH_CFG_DATA);
26809e39c5baSBill Taylor }
26819e39c5baSBill Taylor
26829e39c5baSBill Taylor return (read);
26839e39c5baSBill Taylor }
26849e39c5baSBill Taylor
26859e39c5baSBill Taylor #ifdef DO_WRCONF
26869e39c5baSBill Taylor static void
hermon_flash_write_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)26879e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state,
26889e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
26899e39c5baSBill Taylor {
26909e39c5baSBill Taylor hermon_flash_write_cfg_helper(state, pci_config_hdl, addr, data);
26919e39c5baSBill Taylor hermon_flash_write_confirm(state, pci_config_hdl);
26929e39c5baSBill Taylor }
26939e39c5baSBill Taylor
26949e39c5baSBill Taylor static void
hermon_flash_write_confirm(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl)26959e39c5baSBill Taylor hermon_flash_write_confirm(hermon_state_t *state,
26969e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl)
26979e39c5baSBill Taylor {
26989e39c5baSBill Taylor uint32_t sem_value = 1;
26999e39c5baSBill Taylor
27009e39c5baSBill Taylor hermon_flash_write_cfg_helper(state, pci_config_hdl,
27019e39c5baSBill Taylor HERMON_HW_FLASH_WRCONF_SEMA, 0);
27029e39c5baSBill Taylor while (sem_value) {
27039e39c5baSBill Taylor sem_value = hermon_flash_read_cfg(state, pci_config_hdl,
27049e39c5baSBill Taylor HERMON_HW_FLASH_WRCONF_SEMA);
27059e39c5baSBill Taylor }
27069e39c5baSBill Taylor }
27079e39c5baSBill Taylor #endif
27089e39c5baSBill Taylor
27099e39c5baSBill Taylor /*
27109e39c5baSBill Taylor * hermon_flash_write_cfg
27119e39c5baSBill Taylor */
27129e39c5baSBill Taylor static void
27139e39c5baSBill Taylor #ifdef DO_WRCONF
hermon_flash_write_cfg_helper(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)27149e39c5baSBill Taylor hermon_flash_write_cfg_helper(hermon_state_t *state,
27159e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27169e39c5baSBill Taylor #else
27179e39c5baSBill Taylor hermon_flash_write_cfg(hermon_state_t *state,
27189e39c5baSBill Taylor ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27199e39c5baSBill Taylor #endif
27209e39c5baSBill Taylor {
27219e39c5baSBill Taylor if (do_bar0) {
27229e39c5baSBill Taylor ddi_put32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
27239e39c5baSBill Taylor (state->hs_reg_cmd_baseaddr + addr), data);
27249e39c5baSBill Taylor
27259e39c5baSBill Taylor } else {
27269e39c5baSBill Taylor
27279e39c5baSBill Taylor /*
27289e39c5baSBill Taylor * Perform flash write operation:
27299e39c5baSBill Taylor * 1) Place addr to write to on the HERMON_HW_FLASH_CFG_ADDR
27309e39c5baSBill Taylor * register
27319e39c5baSBill Taylor * 2) Place data to write on to the HERMON_HW_FLASH_CFG_DATA
27329e39c5baSBill Taylor * register
27339e39c5baSBill Taylor */
27349e39c5baSBill Taylor pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
27359e39c5baSBill Taylor addr);
27369e39c5baSBill Taylor pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_DATA,
27379e39c5baSBill Taylor data);
27389e39c5baSBill Taylor }
27399e39c5baSBill Taylor }
27409e39c5baSBill Taylor
27419e39c5baSBill Taylor /*
27429e39c5baSBill Taylor * Support routines to convert Common Flash Interface (CFI) data
27439e39c5baSBill Taylor * from a 32 bit word to a char array, and from a char array to
27449e39c5baSBill Taylor * a 32 bit word.
27459e39c5baSBill Taylor */
27469e39c5baSBill Taylor static void
hermon_flash_cfi_byte(uint8_t * ch,uint32_t dword,int i)27479e39c5baSBill Taylor hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
27489e39c5baSBill Taylor {
27499e39c5baSBill Taylor ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
27509e39c5baSBill Taylor ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
27519e39c5baSBill Taylor ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
27529e39c5baSBill Taylor ch[i+3] = (uint8_t)((dword & 0x000000FF));
27539e39c5baSBill Taylor }
27549e39c5baSBill Taylor
27559e39c5baSBill Taylor static void
hermon_flash_cfi_dword(uint32_t * dword,uint8_t * ch,int i)27569e39c5baSBill Taylor hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
27579e39c5baSBill Taylor {
27589e39c5baSBill Taylor *dword = (uint32_t)
27599e39c5baSBill Taylor ((uint32_t)ch[i] << 24 |
27609e39c5baSBill Taylor (uint32_t)ch[i+1] << 16 |
27619e39c5baSBill Taylor (uint32_t)ch[i+2] << 8 |
27629e39c5baSBill Taylor (uint32_t)ch[i+3]);
27639e39c5baSBill Taylor }
27649e39c5baSBill Taylor
27659e39c5baSBill Taylor /*
27669e39c5baSBill Taylor * hermon_loopback_free_qps
27679e39c5baSBill Taylor */
27689e39c5baSBill Taylor static void
hermon_loopback_free_qps(hermon_loopback_state_t * lstate)27699e39c5baSBill Taylor hermon_loopback_free_qps(hermon_loopback_state_t *lstate)
27709e39c5baSBill Taylor {
27719e39c5baSBill Taylor int i;
27729e39c5baSBill Taylor
27739e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
27749e39c5baSBill Taylor
27759e39c5baSBill Taylor if (lstate->hls_tx.hlc_qp_hdl != NULL) {
27769e39c5baSBill Taylor (void) hermon_qp_free(lstate->hls_state,
27779e39c5baSBill Taylor &lstate->hls_tx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27789e39c5baSBill Taylor HERMON_NOSLEEP);
27799e39c5baSBill Taylor }
27809e39c5baSBill Taylor if (lstate->hls_rx.hlc_qp_hdl != NULL) {
27819e39c5baSBill Taylor (void) hermon_qp_free(lstate->hls_state,
27829e39c5baSBill Taylor &lstate->hls_rx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27839e39c5baSBill Taylor HERMON_NOSLEEP);
27849e39c5baSBill Taylor }
27859e39c5baSBill Taylor lstate->hls_tx.hlc_qp_hdl = NULL;
27869e39c5baSBill Taylor lstate->hls_rx.hlc_qp_hdl = NULL;
27879e39c5baSBill Taylor for (i = 0; i < 2; i++) {
27889e39c5baSBill Taylor if (lstate->hls_tx.hlc_cqhdl[i] != NULL) {
27899e39c5baSBill Taylor (void) hermon_cq_free(lstate->hls_state,
27909e39c5baSBill Taylor &lstate->hls_tx.hlc_cqhdl[i], HERMON_NOSLEEP);
27919e39c5baSBill Taylor }
27929e39c5baSBill Taylor if (lstate->hls_rx.hlc_cqhdl[i] != NULL) {
27939e39c5baSBill Taylor (void) hermon_cq_free(lstate->hls_state,
27949e39c5baSBill Taylor &lstate->hls_rx.hlc_cqhdl[i], HERMON_NOSLEEP);
27959e39c5baSBill Taylor }
27969e39c5baSBill Taylor lstate->hls_tx.hlc_cqhdl[i] = NULL;
27979e39c5baSBill Taylor lstate->hls_rx.hlc_cqhdl[i] = NULL;
27989e39c5baSBill Taylor }
27999e39c5baSBill Taylor }
28009e39c5baSBill Taylor
28019e39c5baSBill Taylor /*
28029e39c5baSBill Taylor * hermon_loopback_free_state
28039e39c5baSBill Taylor */
28049e39c5baSBill Taylor static void
hermon_loopback_free_state(hermon_loopback_state_t * lstate)28059e39c5baSBill Taylor hermon_loopback_free_state(hermon_loopback_state_t *lstate)
28069e39c5baSBill Taylor {
28079e39c5baSBill Taylor hermon_loopback_free_qps(lstate);
28089e39c5baSBill Taylor if (lstate->hls_tx.hlc_mrhdl != NULL) {
28099e39c5baSBill Taylor (void) hermon_mr_deregister(lstate->hls_state,
28109e39c5baSBill Taylor &lstate->hls_tx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28119e39c5baSBill Taylor HERMON_NOSLEEP);
28129e39c5baSBill Taylor }
28139e39c5baSBill Taylor if (lstate->hls_rx.hlc_mrhdl != NULL) {
28149e39c5baSBill Taylor (void) hermon_mr_deregister(lstate->hls_state,
28159e39c5baSBill Taylor &lstate->hls_rx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28169e39c5baSBill Taylor HERMON_NOSLEEP);
28179e39c5baSBill Taylor }
28189e39c5baSBill Taylor if (lstate->hls_pd_hdl != NULL) {
28199e39c5baSBill Taylor (void) hermon_pd_free(lstate->hls_state, &lstate->hls_pd_hdl);
28209e39c5baSBill Taylor }
28219e39c5baSBill Taylor if (lstate->hls_tx.hlc_buf != NULL) {
28229e39c5baSBill Taylor kmem_free(lstate->hls_tx.hlc_buf, lstate->hls_tx.hlc_buf_sz);
28239e39c5baSBill Taylor }
28249e39c5baSBill Taylor if (lstate->hls_rx.hlc_buf != NULL) {
28259e39c5baSBill Taylor kmem_free(lstate->hls_rx.hlc_buf, lstate->hls_rx.hlc_buf_sz);
28269e39c5baSBill Taylor }
28279e39c5baSBill Taylor bzero(lstate, sizeof (hermon_loopback_state_t));
28289e39c5baSBill Taylor }
28299e39c5baSBill Taylor
28309e39c5baSBill Taylor /*
28319e39c5baSBill Taylor * hermon_loopback_init
28329e39c5baSBill Taylor */
28339e39c5baSBill Taylor static int
hermon_loopback_init(hermon_state_t * state,hermon_loopback_state_t * lstate)28349e39c5baSBill Taylor hermon_loopback_init(hermon_state_t *state, hermon_loopback_state_t *lstate)
28359e39c5baSBill Taylor {
28369e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
28379e39c5baSBill Taylor
28389e39c5baSBill Taylor lstate->hls_hca_hdl = (ibc_hca_hdl_t)state;
28399e39c5baSBill Taylor lstate->hls_status = hermon_pd_alloc(lstate->hls_state,
28409e39c5baSBill Taylor &lstate->hls_pd_hdl, HERMON_NOSLEEP);
28419e39c5baSBill Taylor if (lstate->hls_status != IBT_SUCCESS) {
28429e39c5baSBill Taylor lstate->hls_err = HERMON_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
28439e39c5baSBill Taylor return (EFAULT);
28449e39c5baSBill Taylor }
28459e39c5baSBill Taylor
28469e39c5baSBill Taylor return (0);
28479e39c5baSBill Taylor }
28489e39c5baSBill Taylor
28499e39c5baSBill Taylor /*
28509e39c5baSBill Taylor * hermon_loopback_init_qp_info
28519e39c5baSBill Taylor */
28529e39c5baSBill Taylor static void
hermon_loopback_init_qp_info(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)28539e39c5baSBill Taylor hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
28549e39c5baSBill Taylor hermon_loopback_comm_t *comm)
28559e39c5baSBill Taylor {
28569e39c5baSBill Taylor bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
28579e39c5baSBill Taylor bzero(&comm->hlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
28589e39c5baSBill Taylor bzero(&comm->hlc_qp_info, sizeof (ibt_qp_info_t));
28599e39c5baSBill Taylor
28609e39c5baSBill Taylor comm->hlc_wrid = 1;
28619e39c5baSBill Taylor comm->hlc_cq_attr.cq_size = 128;
28629e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
28639e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
28649e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_sq = 16;
28659e39c5baSBill Taylor comm->hlc_qp_attr.qp_sizes.cs_rq = 16;
28669e39c5baSBill Taylor comm->hlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
28679e39c5baSBill Taylor
28689e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_RESET;
28699e39c5baSBill Taylor comm->hlc_qp_info.qp_trans = IBT_RC_SRV;
28709e39c5baSBill Taylor comm->hlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
28719e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
28729e39c5baSBill Taylor lstate->hls_port;
28739e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
28749e39c5baSBill Taylor lstate->hls_pkey_ix;
28759e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
28769e39c5baSBill Taylor lstate->hls_timeout;
28779e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
28789e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
28799e39c5baSBill Taylor IBT_SRATE_4X;
28809e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
28819e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
28829e39c5baSBill Taylor lstate->hls_lid;
28839e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->hls_retry;
28849e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
28859e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
28869e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_in = 4;
28879e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
28889e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
28899e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
28909e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
28919e39c5baSBill Taylor }
28929e39c5baSBill Taylor
28939e39c5baSBill Taylor /*
28949e39c5baSBill Taylor * hermon_loopback_alloc_mem
28959e39c5baSBill Taylor */
28969e39c5baSBill Taylor static int
hermon_loopback_alloc_mem(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,int sz)28979e39c5baSBill Taylor hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
28989e39c5baSBill Taylor hermon_loopback_comm_t *comm, int sz)
28999e39c5baSBill Taylor {
29009e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29019e39c5baSBill Taylor
29029e39c5baSBill Taylor /* Allocate buffer of specified size */
29039e39c5baSBill Taylor comm->hlc_buf_sz = sz;
29049e39c5baSBill Taylor comm->hlc_buf = kmem_zalloc(sz, KM_NOSLEEP);
29059e39c5baSBill Taylor if (comm->hlc_buf == NULL) {
29069e39c5baSBill Taylor return (EFAULT);
29079e39c5baSBill Taylor }
29089e39c5baSBill Taylor
29099e39c5baSBill Taylor /* Register the buffer as a memory region */
29109e39c5baSBill Taylor comm->hlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->hlc_buf;
29119e39c5baSBill Taylor comm->hlc_memattr.mr_len = (ib_msglen_t)sz;
29129e39c5baSBill Taylor comm->hlc_memattr.mr_as = NULL;
29139e39c5baSBill Taylor comm->hlc_memattr.mr_flags = IBT_MR_NOSLEEP |
29149e39c5baSBill Taylor IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
29159e39c5baSBill Taylor
29169e39c5baSBill Taylor comm->hlc_status = hermon_mr_register(lstate->hls_state,
29179e39c5baSBill Taylor lstate->hls_pd_hdl, &comm->hlc_memattr, &comm->hlc_mrhdl,
29189e39c5baSBill Taylor NULL, HERMON_MPT_DMPT);
29199e39c5baSBill Taylor
29209e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->hlc_mrhdl))
29219e39c5baSBill Taylor
29229e39c5baSBill Taylor comm->hlc_mrdesc.md_vaddr = comm->hlc_mrhdl->mr_bindinfo.bi_addr;
29239e39c5baSBill Taylor comm->hlc_mrdesc.md_lkey = comm->hlc_mrhdl->mr_lkey;
29249e39c5baSBill Taylor comm->hlc_mrdesc.md_rkey = comm->hlc_mrhdl->mr_rkey;
29259e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) {
29269e39c5baSBill Taylor return (EFAULT);
29279e39c5baSBill Taylor }
29289e39c5baSBill Taylor return (0);
29299e39c5baSBill Taylor }
29309e39c5baSBill Taylor
29319e39c5baSBill Taylor /*
29329e39c5baSBill Taylor * hermon_loopback_alloc_qps
29339e39c5baSBill Taylor */
29349e39c5baSBill Taylor static int
hermon_loopback_alloc_qps(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)29359e39c5baSBill Taylor hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
29369e39c5baSBill Taylor hermon_loopback_comm_t *comm)
29379e39c5baSBill Taylor {
29389e39c5baSBill Taylor uint32_t i, real_size;
29399e39c5baSBill Taylor hermon_qp_info_t qpinfo;
29409e39c5baSBill Taylor
29419e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29429e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29439e39c5baSBill Taylor
29449e39c5baSBill Taylor /* Allocate send and recv CQs */
29459e39c5baSBill Taylor for (i = 0; i < 2; i++) {
29469e39c5baSBill Taylor bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
29479e39c5baSBill Taylor comm->hlc_cq_attr.cq_size = 128;
29489e39c5baSBill Taylor comm->hlc_status = hermon_cq_alloc(lstate->hls_state,
29499e39c5baSBill Taylor (ibt_cq_hdl_t)NULL, &comm->hlc_cq_attr, &real_size,
29509e39c5baSBill Taylor &comm->hlc_cqhdl[i], HERMON_NOSLEEP);
29519e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) {
29529e39c5baSBill Taylor lstate->hls_err += i;
29539e39c5baSBill Taylor return (EFAULT);
29549e39c5baSBill Taylor }
29559e39c5baSBill Taylor }
29569e39c5baSBill Taylor
29579e39c5baSBill Taylor /* Allocate the QP */
29589e39c5baSBill Taylor hermon_loopback_init_qp_info(lstate, comm);
29599e39c5baSBill Taylor comm->hlc_qp_attr.qp_pd_hdl = (ibt_pd_hdl_t)lstate->hls_pd_hdl;
29609e39c5baSBill Taylor comm->hlc_qp_attr.qp_scq_hdl = (ibt_cq_hdl_t)comm->hlc_cqhdl[0];
29619e39c5baSBill Taylor comm->hlc_qp_attr.qp_rcq_hdl = (ibt_cq_hdl_t)comm->hlc_cqhdl[1];
29629e39c5baSBill Taylor comm->hlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[0];
29639e39c5baSBill Taylor comm->hlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[1];
29649e39c5baSBill Taylor qpinfo.qpi_attrp = &comm->hlc_qp_attr;
29659e39c5baSBill Taylor qpinfo.qpi_type = IBT_RC_RQP;
29669e39c5baSBill Taylor qpinfo.qpi_ibt_qphdl = NULL;
29679e39c5baSBill Taylor qpinfo.qpi_queueszp = &comm->hlc_chan_sizes;
29689e39c5baSBill Taylor qpinfo.qpi_qpn = &comm->hlc_qp_num;
29699e39c5baSBill Taylor comm->hlc_status = hermon_qp_alloc(lstate->hls_state, &qpinfo,
29709e39c5baSBill Taylor HERMON_NOSLEEP);
29719e39c5baSBill Taylor if (comm->hlc_status == DDI_SUCCESS) {
29729e39c5baSBill Taylor comm->hlc_qp_hdl = qpinfo.qpi_qphdl;
29739e39c5baSBill Taylor }
29749e39c5baSBill Taylor
29759e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) {
29769e39c5baSBill Taylor lstate->hls_err += 2;
29779e39c5baSBill Taylor return (EFAULT);
29789e39c5baSBill Taylor }
29799e39c5baSBill Taylor return (0);
29809e39c5baSBill Taylor }
29819e39c5baSBill Taylor
29829e39c5baSBill Taylor /*
29839e39c5baSBill Taylor * hermon_loopback_modify_qp
29849e39c5baSBill Taylor */
29859e39c5baSBill Taylor static int
hermon_loopback_modify_qp(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,uint_t qp_num)29869e39c5baSBill Taylor hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
29879e39c5baSBill Taylor hermon_loopback_comm_t *comm, uint_t qp_num)
29889e39c5baSBill Taylor {
29899e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29909e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29919e39c5baSBill Taylor
29929e39c5baSBill Taylor /* Modify QP to INIT */
29939e39c5baSBill Taylor hermon_loopback_init_qp_info(lstate, comm);
29949e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_INIT;
29959e39c5baSBill Taylor comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
29969e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
29979e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) {
29989e39c5baSBill Taylor return (EFAULT);
29999e39c5baSBill Taylor }
30009e39c5baSBill Taylor
30019e39c5baSBill Taylor /*
30029e39c5baSBill Taylor * Modify QP to RTR (set destination LID and QP number to local
30039e39c5baSBill Taylor * LID and QP number)
30049e39c5baSBill Taylor */
30059e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_RTR;
30069e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
30079e39c5baSBill Taylor = lstate->hls_lid;
30089e39c5baSBill Taylor comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
30099e39c5baSBill Taylor comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30109e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30119e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) {
30129e39c5baSBill Taylor lstate->hls_err += 1;
30139e39c5baSBill Taylor return (EFAULT);
30149e39c5baSBill Taylor }
30159e39c5baSBill Taylor
30169e39c5baSBill Taylor /* Modify QP to RTS */
30179e39c5baSBill Taylor comm->hlc_qp_info.qp_current_state = IBT_STATE_RTR;
30189e39c5baSBill Taylor comm->hlc_qp_info.qp_state = IBT_STATE_RTS;
30199e39c5baSBill Taylor comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30209e39c5baSBill Taylor IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30219e39c5baSBill Taylor if (comm->hlc_status != IBT_SUCCESS) {
30229e39c5baSBill Taylor lstate->hls_err += 2;
30239e39c5baSBill Taylor return (EFAULT);
30249e39c5baSBill Taylor }
30259e39c5baSBill Taylor return (0);
30269e39c5baSBill Taylor }
30279e39c5baSBill Taylor
30289e39c5baSBill Taylor /*
30299e39c5baSBill Taylor * hermon_loopback_copyout
30309e39c5baSBill Taylor */
30319e39c5baSBill Taylor static int
hermon_loopback_copyout(hermon_loopback_ioctl_t * lb,intptr_t arg,int mode)30329e39c5baSBill Taylor hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, intptr_t arg, int mode)
30339e39c5baSBill Taylor {
30349e39c5baSBill Taylor #ifdef _MULTI_DATAMODEL
30359e39c5baSBill Taylor if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
30369e39c5baSBill Taylor hermon_loopback_ioctl32_t lb32;
30379e39c5baSBill Taylor
30389e39c5baSBill Taylor lb32.alb_revision = lb->alb_revision;
30399e39c5baSBill Taylor lb32.alb_send_buf =
30409e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->alb_send_buf;
30419e39c5baSBill Taylor lb32.alb_fail_buf =
30429e39c5baSBill Taylor (caddr32_t)(uintptr_t)lb->alb_fail_buf;
30439e39c5baSBill Taylor lb32.alb_buf_sz = lb->alb_buf_sz;
30449e39c5baSBill Taylor lb32.alb_num_iter = lb->alb_num_iter;
30459e39c5baSBill Taylor lb32.alb_pass_done = lb->alb_pass_done;
30469e39c5baSBill Taylor lb32.alb_timeout = lb->alb_timeout;
30479e39c5baSBill Taylor lb32.alb_error_type = lb->alb_error_type;
30489e39c5baSBill Taylor lb32.alb_port_num = lb->alb_port_num;
30499e39c5baSBill Taylor lb32.alb_num_retry = lb->alb_num_retry;
30509e39c5baSBill Taylor
30519e39c5baSBill Taylor if (ddi_copyout(&lb32, (void *)arg,
30529e39c5baSBill Taylor sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
30539e39c5baSBill Taylor return (EFAULT);
30549e39c5baSBill Taylor }
30559e39c5baSBill Taylor } else
30569e39c5baSBill Taylor #endif /* _MULTI_DATAMODEL */
30579e39c5baSBill Taylor if (ddi_copyout(lb, (void *)arg, sizeof (hermon_loopback_ioctl_t),
30589e39c5baSBill Taylor mode) != 0) {
30599e39c5baSBill Taylor return (EFAULT);
30609e39c5baSBill Taylor }
30619e39c5baSBill Taylor return (0);
30629e39c5baSBill Taylor }
30639e39c5baSBill Taylor
30649e39c5baSBill Taylor /*
30659e39c5baSBill Taylor * hermon_loopback_post_send
30669e39c5baSBill Taylor */
30679e39c5baSBill Taylor static int
hermon_loopback_post_send(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * tx,hermon_loopback_comm_t * rx)30689e39c5baSBill Taylor hermon_loopback_post_send(hermon_loopback_state_t *lstate,
30699e39c5baSBill Taylor hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx)
30709e39c5baSBill Taylor {
30719e39c5baSBill Taylor int ret;
30729e39c5baSBill Taylor
30739e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
30749e39c5baSBill Taylor
30759e39c5baSBill Taylor bzero(&tx->hlc_sgl, sizeof (ibt_wr_ds_t));
30769e39c5baSBill Taylor bzero(&tx->hlc_wr, sizeof (ibt_send_wr_t));
30779e39c5baSBill Taylor
30789e39c5baSBill Taylor /* Initialize local address for TX buffer */
30799e39c5baSBill Taylor tx->hlc_sgl.ds_va = tx->hlc_mrdesc.md_vaddr;
30809e39c5baSBill Taylor tx->hlc_sgl.ds_key = tx->hlc_mrdesc.md_lkey;
30819e39c5baSBill Taylor tx->hlc_sgl.ds_len = tx->hlc_buf_sz;
30829e39c5baSBill Taylor
30839e39c5baSBill Taylor /* Initialize the remaining details of the work request */
30849e39c5baSBill Taylor tx->hlc_wr.wr_id = tx->hlc_wrid++;
30859e39c5baSBill Taylor tx->hlc_wr.wr_flags = IBT_WR_SEND_SIGNAL;
30869e39c5baSBill Taylor tx->hlc_wr.wr_nds = 1;
30879e39c5baSBill Taylor tx->hlc_wr.wr_sgl = &tx->hlc_sgl;
30889e39c5baSBill Taylor tx->hlc_wr.wr_opcode = IBT_WRC_RDMAW;
30899e39c5baSBill Taylor tx->hlc_wr.wr_trans = IBT_RC_SRV;
30909e39c5baSBill Taylor
30919e39c5baSBill Taylor /* Initialize the remote address for RX buffer */
30929e39c5baSBill Taylor tx->hlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->hlc_mrdesc.md_vaddr;
30939e39c5baSBill Taylor tx->hlc_wr.wr.rc.rcwr.rdma.rdma_rkey = rx->hlc_mrdesc.md_rkey;
30949e39c5baSBill Taylor tx->hlc_complete = 0;
30959e39c5baSBill Taylor ret = hermon_post_send(lstate->hls_state, tx->hlc_qp_hdl, &tx->hlc_wr,
30969e39c5baSBill Taylor 1, NULL);
30979e39c5baSBill Taylor if (ret != IBT_SUCCESS) {
30989e39c5baSBill Taylor return (EFAULT);
30999e39c5baSBill Taylor }
31009e39c5baSBill Taylor return (0);
31019e39c5baSBill Taylor }
31029e39c5baSBill Taylor
31039e39c5baSBill Taylor /*
31049e39c5baSBill Taylor * hermon_loopback_poll_cq
31059e39c5baSBill Taylor */
31069e39c5baSBill Taylor static int
hermon_loopback_poll_cq(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)31079e39c5baSBill Taylor hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
31089e39c5baSBill Taylor hermon_loopback_comm_t *comm)
31099e39c5baSBill Taylor {
31109e39c5baSBill Taylor _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
31119e39c5baSBill Taylor
31129e39c5baSBill Taylor comm->hlc_wc.wc_status = 0;
31139e39c5baSBill Taylor comm->hlc_num_polled = 0;
31149e39c5baSBill Taylor comm->hlc_status = hermon_cq_poll(lstate->hls_state,
31159e39c5baSBill Taylor comm->hlc_cqhdl[0], &comm->hlc_wc, 1, &comm->hlc_num_polled);
31169e39c5baSBill Taylor if ((comm->hlc_status == IBT_SUCCESS) &&
31179e39c5baSBill Taylor (comm->hlc_wc.wc_status != IBT_WC_SUCCESS)) {
31189e39c5baSBill Taylor comm->hlc_status = ibc_get_ci_failure(0);
31199e39c5baSBill Taylor }
31209e39c5baSBill Taylor return (comm->hlc_status);
31219e39c5baSBill Taylor }
3122