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 */
1002