19517SBill.Taylor@Sun.COM /*
29517SBill.Taylor@Sun.COM * CDDL HEADER START
39517SBill.Taylor@Sun.COM *
49517SBill.Taylor@Sun.COM * The contents of this file are subject to the terms of the
59517SBill.Taylor@Sun.COM * Common Development and Distribution License (the "License").
69517SBill.Taylor@Sun.COM * You may not use this file except in compliance with the License.
79517SBill.Taylor@Sun.COM *
89517SBill.Taylor@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99517SBill.Taylor@Sun.COM * or http://www.opensolaris.org/os/licensing.
109517SBill.Taylor@Sun.COM * See the License for the specific language governing permissions
119517SBill.Taylor@Sun.COM * and limitations under the License.
129517SBill.Taylor@Sun.COM *
139517SBill.Taylor@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149517SBill.Taylor@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159517SBill.Taylor@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169517SBill.Taylor@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179517SBill.Taylor@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189517SBill.Taylor@Sun.COM *
199517SBill.Taylor@Sun.COM * CDDL HEADER END
209517SBill.Taylor@Sun.COM */
219517SBill.Taylor@Sun.COM
229517SBill.Taylor@Sun.COM /*
23*12688SWilliam.Taylor@Oracle.COM * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
249517SBill.Taylor@Sun.COM */
259517SBill.Taylor@Sun.COM
269517SBill.Taylor@Sun.COM /*
279517SBill.Taylor@Sun.COM * hermon_ioctl.c
289517SBill.Taylor@Sun.COM * Hemron IOCTL Routines
299517SBill.Taylor@Sun.COM *
309517SBill.Taylor@Sun.COM * Implements all ioctl access into the driver. This includes all routines
319517SBill.Taylor@Sun.COM * necessary for updating firmware, accessing the hermon flash device, and
329517SBill.Taylor@Sun.COM * providing interfaces for VTS.
339517SBill.Taylor@Sun.COM */
349517SBill.Taylor@Sun.COM
359517SBill.Taylor@Sun.COM #include <sys/types.h>
369517SBill.Taylor@Sun.COM #include <sys/conf.h>
379517SBill.Taylor@Sun.COM #include <sys/ddi.h>
389517SBill.Taylor@Sun.COM #include <sys/sunddi.h>
399517SBill.Taylor@Sun.COM #include <sys/modctl.h>
409517SBill.Taylor@Sun.COM #include <sys/file.h>
419517SBill.Taylor@Sun.COM
429517SBill.Taylor@Sun.COM #include <sys/ib/adapters/hermon/hermon.h>
439517SBill.Taylor@Sun.COM
449517SBill.Taylor@Sun.COM /* Hemron HCA state pointer (extern) */
459517SBill.Taylor@Sun.COM extern void *hermon_statep;
469517SBill.Taylor@Sun.COM extern int hermon_verbose;
479517SBill.Taylor@Sun.COM
489517SBill.Taylor@Sun.COM #define DO_WRCONF 1
499517SBill.Taylor@Sun.COM static int do_bar0 = 1;
509517SBill.Taylor@Sun.COM
519517SBill.Taylor@Sun.COM /*
529517SBill.Taylor@Sun.COM * The ioctl declarations (for firmware flash burning, register read/write
539517SBill.Taylor@Sun.COM * (DEBUG-only), and VTS interfaces)
549517SBill.Taylor@Sun.COM */
559517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev,
569517SBill.Taylor@Sun.COM intptr_t arg, int mode);
579517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev,
589517SBill.Taylor@Sun.COM intptr_t arg, int mode);
599517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev,
609517SBill.Taylor@Sun.COM intptr_t arg, int mode);
619517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev,
629517SBill.Taylor@Sun.COM intptr_t arg, int mode);
639517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev);
649517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_cleanup(hermon_state_t *state);
659517SBill.Taylor@Sun.COM static int hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state);
669517SBill.Taylor@Sun.COM #ifdef DEBUG
679517SBill.Taylor@Sun.COM static int hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg,
689517SBill.Taylor@Sun.COM int mode);
699517SBill.Taylor@Sun.COM static int hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg,
709517SBill.Taylor@Sun.COM int mode);
719517SBill.Taylor@Sun.COM #endif /* DEBUG */
729517SBill.Taylor@Sun.COM static int hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev,
739517SBill.Taylor@Sun.COM intptr_t arg, int mode);
749517SBill.Taylor@Sun.COM static int hermon_ioctl_info(hermon_state_t *state, dev_t dev,
759517SBill.Taylor@Sun.COM intptr_t arg, int mode);
769517SBill.Taylor@Sun.COM static int hermon_ioctl_ports(hermon_state_t *state, intptr_t arg,
779517SBill.Taylor@Sun.COM int mode);
789517SBill.Taylor@Sun.COM static int hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg,
799517SBill.Taylor@Sun.COM int mode);
809517SBill.Taylor@Sun.COM
819517SBill.Taylor@Sun.COM /* Hemron Flash Functions */
829517SBill.Taylor@Sun.COM static void hermon_flash_spi_exec_command(hermon_state_t *state,
839517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl, uint32_t cmd);
849517SBill.Taylor@Sun.COM static int hermon_flash_read_sector(hermon_state_t *state,
859517SBill.Taylor@Sun.COM uint32_t sector_num);
869517SBill.Taylor@Sun.COM static int hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
879517SBill.Taylor@Sun.COM uint32_t addr);
889517SBill.Taylor@Sun.COM static int hermon_flash_write_sector(hermon_state_t *state,
899517SBill.Taylor@Sun.COM uint32_t sector_num);
909517SBill.Taylor@Sun.COM static int hermon_flash_spi_write_dword(hermon_state_t *state,
919517SBill.Taylor@Sun.COM uint32_t addr, uint32_t data);
929517SBill.Taylor@Sun.COM static int hermon_flash_write_byte(hermon_state_t *state, uint32_t addr,
939517SBill.Taylor@Sun.COM uchar_t data);
949517SBill.Taylor@Sun.COM static int hermon_flash_erase_sector(hermon_state_t *state,
959517SBill.Taylor@Sun.COM uint32_t sector_num);
969517SBill.Taylor@Sun.COM static int hermon_flash_erase_chip(hermon_state_t *state);
979517SBill.Taylor@Sun.COM static int hermon_flash_bank(hermon_state_t *state, uint32_t addr);
989517SBill.Taylor@Sun.COM static uint32_t hermon_flash_read(hermon_state_t *state, uint32_t addr,
999517SBill.Taylor@Sun.COM int *err);
1009517SBill.Taylor@Sun.COM static void hermon_flash_write(hermon_state_t *state, uint32_t addr,
1019517SBill.Taylor@Sun.COM uchar_t data, int *err);
1029517SBill.Taylor@Sun.COM static int hermon_flash_spi_wait_wip(hermon_state_t *state);
1039517SBill.Taylor@Sun.COM static void hermon_flash_spi_write_enable(hermon_state_t *state);
1049517SBill.Taylor@Sun.COM static int hermon_flash_init(hermon_state_t *state);
1059517SBill.Taylor@Sun.COM static int hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
1069517SBill.Taylor@Sun.COM int *intel_xcmd);
1079517SBill.Taylor@Sun.COM static int hermon_flash_fini(hermon_state_t *state);
1089517SBill.Taylor@Sun.COM static int hermon_flash_reset(hermon_state_t *state);
1099517SBill.Taylor@Sun.COM static uint32_t hermon_flash_read_cfg(hermon_state_t *state,
1109517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl, uint32_t addr);
1119517SBill.Taylor@Sun.COM #ifdef DO_WRCONF
1129517SBill.Taylor@Sun.COM static void hermon_flash_write_cfg(hermon_state_t *state,
1139517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1149517SBill.Taylor@Sun.COM static void hermon_flash_write_cfg_helper(hermon_state_t *state,
1159517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data);
1169517SBill.Taylor@Sun.COM static void hermon_flash_write_confirm(hermon_state_t *state,
1179517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl);
1189517SBill.Taylor@Sun.COM #endif
1199517SBill.Taylor@Sun.COM static void hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i);
1209517SBill.Taylor@Sun.COM static void hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i);
1219517SBill.Taylor@Sun.COM
1229517SBill.Taylor@Sun.COM /* Hemron loopback test functions */
1239517SBill.Taylor@Sun.COM static void hermon_loopback_free_qps(hermon_loopback_state_t *lstate);
1249517SBill.Taylor@Sun.COM static void hermon_loopback_free_state(hermon_loopback_state_t *lstate);
1259517SBill.Taylor@Sun.COM static int hermon_loopback_init(hermon_state_t *state,
1269517SBill.Taylor@Sun.COM hermon_loopback_state_t *lstate);
1279517SBill.Taylor@Sun.COM static void hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
1289517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm);
1299517SBill.Taylor@Sun.COM static int hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
1309517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm, int sz);
1319517SBill.Taylor@Sun.COM static int hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
1329517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm);
1339517SBill.Taylor@Sun.COM static int hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
1349517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm, uint_t qp_num);
1359517SBill.Taylor@Sun.COM static int hermon_loopback_copyout(hermon_loopback_ioctl_t *lb,
1369517SBill.Taylor@Sun.COM intptr_t arg, int mode);
1379517SBill.Taylor@Sun.COM static int hermon_loopback_post_send(hermon_loopback_state_t *lstate,
1389517SBill.Taylor@Sun.COM hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx);
1399517SBill.Taylor@Sun.COM static int hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
1409517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm);
1419517SBill.Taylor@Sun.COM
1429517SBill.Taylor@Sun.COM /* Patchable timeout values for flash operations */
1439517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_gpio_sema = HERMON_HW_FLASH_TIMEOUT_GPIO_SEMA;
1449517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_config = HERMON_HW_FLASH_TIMEOUT_CONFIG;
1459517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_write = HERMON_HW_FLASH_TIMEOUT_WRITE;
1469517SBill.Taylor@Sun.COM int hermon_hw_flash_timeout_erase = HERMON_HW_FLASH_TIMEOUT_ERASE;
1479517SBill.Taylor@Sun.COM
1489517SBill.Taylor@Sun.COM /*
1499517SBill.Taylor@Sun.COM * hermon_ioctl()
1509517SBill.Taylor@Sun.COM */
1519517SBill.Taylor@Sun.COM /* ARGSUSED */
1529517SBill.Taylor@Sun.COM int
hermon_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1539517SBill.Taylor@Sun.COM hermon_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1549517SBill.Taylor@Sun.COM int *rvalp)
1559517SBill.Taylor@Sun.COM {
1569517SBill.Taylor@Sun.COM hermon_state_t *state;
1579517SBill.Taylor@Sun.COM minor_t instance;
1589517SBill.Taylor@Sun.COM int status;
1599517SBill.Taylor@Sun.COM
1609517SBill.Taylor@Sun.COM if (drv_priv(credp) != 0) {
1619517SBill.Taylor@Sun.COM return (EPERM);
1629517SBill.Taylor@Sun.COM }
1639517SBill.Taylor@Sun.COM
1649517SBill.Taylor@Sun.COM instance = HERMON_DEV_INSTANCE(dev);
1659517SBill.Taylor@Sun.COM if (instance == (minor_t)-1) {
1669517SBill.Taylor@Sun.COM return (EBADF);
1679517SBill.Taylor@Sun.COM }
1689517SBill.Taylor@Sun.COM
1699517SBill.Taylor@Sun.COM state = ddi_get_soft_state(hermon_statep, instance);
1709517SBill.Taylor@Sun.COM if (state == NULL) {
1719517SBill.Taylor@Sun.COM return (EBADF);
1729517SBill.Taylor@Sun.COM }
1739517SBill.Taylor@Sun.COM
1749517SBill.Taylor@Sun.COM status = 0;
1759517SBill.Taylor@Sun.COM
1769517SBill.Taylor@Sun.COM switch (cmd) {
1779517SBill.Taylor@Sun.COM case HERMON_IOCTL_FLASH_READ:
1789517SBill.Taylor@Sun.COM status = hermon_ioctl_flash_read(state, dev, arg, mode);
1799517SBill.Taylor@Sun.COM break;
1809517SBill.Taylor@Sun.COM
1819517SBill.Taylor@Sun.COM case HERMON_IOCTL_FLASH_WRITE:
1829517SBill.Taylor@Sun.COM status = hermon_ioctl_flash_write(state, dev, arg, mode);
1839517SBill.Taylor@Sun.COM break;
1849517SBill.Taylor@Sun.COM
1859517SBill.Taylor@Sun.COM case HERMON_IOCTL_FLASH_ERASE:
1869517SBill.Taylor@Sun.COM status = hermon_ioctl_flash_erase(state, dev, arg, mode);
1879517SBill.Taylor@Sun.COM break;
1889517SBill.Taylor@Sun.COM
1899517SBill.Taylor@Sun.COM case HERMON_IOCTL_FLASH_INIT:
1909517SBill.Taylor@Sun.COM status = hermon_ioctl_flash_init(state, dev, arg, mode);
1919517SBill.Taylor@Sun.COM break;
1929517SBill.Taylor@Sun.COM
1939517SBill.Taylor@Sun.COM case HERMON_IOCTL_FLASH_FINI:
1949517SBill.Taylor@Sun.COM status = hermon_ioctl_flash_fini(state, dev);
1959517SBill.Taylor@Sun.COM break;
1969517SBill.Taylor@Sun.COM
1979517SBill.Taylor@Sun.COM case HERMON_IOCTL_INFO:
1989517SBill.Taylor@Sun.COM status = hermon_ioctl_info(state, dev, arg, mode);
1999517SBill.Taylor@Sun.COM break;
2009517SBill.Taylor@Sun.COM
2019517SBill.Taylor@Sun.COM case HERMON_IOCTL_PORTS:
2029517SBill.Taylor@Sun.COM status = hermon_ioctl_ports(state, arg, mode);
2039517SBill.Taylor@Sun.COM break;
2049517SBill.Taylor@Sun.COM
2059517SBill.Taylor@Sun.COM case HERMON_IOCTL_LOOPBACK:
2069517SBill.Taylor@Sun.COM status = hermon_ioctl_loopback(state, arg, mode);
2079517SBill.Taylor@Sun.COM break;
2089517SBill.Taylor@Sun.COM
2099517SBill.Taylor@Sun.COM #ifdef DEBUG
2109517SBill.Taylor@Sun.COM case HERMON_IOCTL_REG_WRITE:
2119517SBill.Taylor@Sun.COM status = hermon_ioctl_reg_write(state, arg, mode);
2129517SBill.Taylor@Sun.COM break;
2139517SBill.Taylor@Sun.COM
2149517SBill.Taylor@Sun.COM case HERMON_IOCTL_REG_READ:
2159517SBill.Taylor@Sun.COM status = hermon_ioctl_reg_read(state, arg, mode);
2169517SBill.Taylor@Sun.COM break;
2179517SBill.Taylor@Sun.COM #endif /* DEBUG */
2189517SBill.Taylor@Sun.COM
2199517SBill.Taylor@Sun.COM case HERMON_IOCTL_DDR_READ:
2209517SBill.Taylor@Sun.COM /* XXX guard until the ioctl header is cleaned up */
2219517SBill.Taylor@Sun.COM status = ENODEV;
2229517SBill.Taylor@Sun.COM break;
2239517SBill.Taylor@Sun.COM
2249517SBill.Taylor@Sun.COM case HERMON_IOCTL_WRITE_BOOT_ADDR:
2259517SBill.Taylor@Sun.COM status = hermon_ioctl_write_boot_addr(state, dev, arg, mode);
2269517SBill.Taylor@Sun.COM break;
2279517SBill.Taylor@Sun.COM
2289517SBill.Taylor@Sun.COM default:
2299517SBill.Taylor@Sun.COM status = ENOTTY;
2309517SBill.Taylor@Sun.COM break;
2319517SBill.Taylor@Sun.COM }
2329517SBill.Taylor@Sun.COM *rvalp = status;
2339517SBill.Taylor@Sun.COM
2349517SBill.Taylor@Sun.COM return (status);
2359517SBill.Taylor@Sun.COM }
2369517SBill.Taylor@Sun.COM
2379517SBill.Taylor@Sun.COM /*
2389517SBill.Taylor@Sun.COM * hermon_ioctl_flash_read()
2399517SBill.Taylor@Sun.COM */
2409517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_read(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)2419517SBill.Taylor@Sun.COM hermon_ioctl_flash_read(hermon_state_t *state, dev_t dev, intptr_t arg,
2429517SBill.Taylor@Sun.COM int mode)
2439517SBill.Taylor@Sun.COM {
2449517SBill.Taylor@Sun.COM hermon_flash_ioctl_t ioctl_info;
2459517SBill.Taylor@Sun.COM int status = 0;
2469517SBill.Taylor@Sun.COM
2479517SBill.Taylor@Sun.COM /*
2489517SBill.Taylor@Sun.COM * Check that flash init ioctl has been called first. And check
2499517SBill.Taylor@Sun.COM * that the same dev_t that called init is the one calling read now.
2509517SBill.Taylor@Sun.COM */
2519517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
2529517SBill.Taylor@Sun.COM if ((state->hs_fw_flashdev != dev) ||
2539517SBill.Taylor@Sun.COM (state->hs_fw_flashstarted == 0)) {
2549517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
2559517SBill.Taylor@Sun.COM return (EIO);
2569517SBill.Taylor@Sun.COM }
2579517SBill.Taylor@Sun.COM
2589517SBill.Taylor@Sun.COM /* copy user struct to kernel */
2599517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
2609517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2619517SBill.Taylor@Sun.COM hermon_flash_ioctl32_t info32;
2629517SBill.Taylor@Sun.COM
2639517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info32,
2649517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl32_t), mode) != 0) {
2659517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
2669517SBill.Taylor@Sun.COM return (EFAULT);
2679517SBill.Taylor@Sun.COM }
2689517SBill.Taylor@Sun.COM ioctl_info.af_type = info32.af_type;
2699517SBill.Taylor@Sun.COM ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
2709517SBill.Taylor@Sun.COM ioctl_info.af_sector_num = info32.af_sector_num;
2719517SBill.Taylor@Sun.COM ioctl_info.af_addr = info32.af_addr;
2729517SBill.Taylor@Sun.COM } else
2739517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
2749517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
2759517SBill.Taylor@Sun.COM mode) != 0) {
2769517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
2779517SBill.Taylor@Sun.COM return (EFAULT);
2789517SBill.Taylor@Sun.COM }
2799517SBill.Taylor@Sun.COM
2809517SBill.Taylor@Sun.COM /*
2819517SBill.Taylor@Sun.COM * Determine type of READ ioctl
2829517SBill.Taylor@Sun.COM */
2839517SBill.Taylor@Sun.COM switch (ioctl_info.af_type) {
2849517SBill.Taylor@Sun.COM case HERMON_FLASH_READ_SECTOR:
2859517SBill.Taylor@Sun.COM /* Check if sector num is too large for flash device */
2869517SBill.Taylor@Sun.COM if (ioctl_info.af_sector_num >=
2879517SBill.Taylor@Sun.COM (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
2889517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
2899517SBill.Taylor@Sun.COM return (EFAULT);
2909517SBill.Taylor@Sun.COM }
2919517SBill.Taylor@Sun.COM
2929517SBill.Taylor@Sun.COM /* Perform the Sector Read */
2939517SBill.Taylor@Sun.COM if ((status = hermon_flash_reset(state)) != 0 ||
2949517SBill.Taylor@Sun.COM (status = hermon_flash_read_sector(state,
2959517SBill.Taylor@Sun.COM ioctl_info.af_sector_num)) != 0) {
2969517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
2979517SBill.Taylor@Sun.COM return (status);
2989517SBill.Taylor@Sun.COM }
2999517SBill.Taylor@Sun.COM
3009517SBill.Taylor@Sun.COM /* copyout the firmware sector image data */
3019517SBill.Taylor@Sun.COM if (ddi_copyout(&state->hs_fw_sector[0],
3029517SBill.Taylor@Sun.COM &ioctl_info.af_sector[0], 1 << state->hs_fw_log_sector_sz,
3039517SBill.Taylor@Sun.COM mode) != 0) {
3049517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3059517SBill.Taylor@Sun.COM return (EFAULT);
3069517SBill.Taylor@Sun.COM }
3079517SBill.Taylor@Sun.COM break;
3089517SBill.Taylor@Sun.COM
3099517SBill.Taylor@Sun.COM case HERMON_FLASH_READ_QUADLET:
3109517SBill.Taylor@Sun.COM /* Check if addr is too large for flash device */
3119517SBill.Taylor@Sun.COM if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
3129517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3139517SBill.Taylor@Sun.COM return (EFAULT);
3149517SBill.Taylor@Sun.COM }
3159517SBill.Taylor@Sun.COM
3169517SBill.Taylor@Sun.COM /* Perform the Quadlet Read */
3179517SBill.Taylor@Sun.COM if ((status = hermon_flash_reset(state)) != 0 ||
3189517SBill.Taylor@Sun.COM (status = hermon_flash_read_quadlet(state,
3199517SBill.Taylor@Sun.COM &ioctl_info.af_quadlet, ioctl_info.af_addr)) != 0) {
3209517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3219517SBill.Taylor@Sun.COM return (status);
3229517SBill.Taylor@Sun.COM }
3239517SBill.Taylor@Sun.COM break;
3249517SBill.Taylor@Sun.COM
3259517SBill.Taylor@Sun.COM default:
3269517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3279517SBill.Taylor@Sun.COM return (EINVAL);
3289517SBill.Taylor@Sun.COM }
3299517SBill.Taylor@Sun.COM
3309517SBill.Taylor@Sun.COM /* copy results back to userland */
3319517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
3329517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3339517SBill.Taylor@Sun.COM hermon_flash_ioctl32_t info32;
3349517SBill.Taylor@Sun.COM
3359517SBill.Taylor@Sun.COM info32.af_quadlet = ioctl_info.af_quadlet;
3369517SBill.Taylor@Sun.COM info32.af_type = ioctl_info.af_type;
3379517SBill.Taylor@Sun.COM info32.af_sector_num = ioctl_info.af_sector_num;
3389517SBill.Taylor@Sun.COM info32.af_sector = (caddr32_t)(uintptr_t)ioctl_info.af_sector;
3399517SBill.Taylor@Sun.COM info32.af_addr = ioctl_info.af_addr;
3409517SBill.Taylor@Sun.COM
3419517SBill.Taylor@Sun.COM if (ddi_copyout(&info32, (void *)arg,
3429517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3439517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3449517SBill.Taylor@Sun.COM return (EFAULT);
3459517SBill.Taylor@Sun.COM }
3469517SBill.Taylor@Sun.COM } else
3479517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
3489517SBill.Taylor@Sun.COM if (ddi_copyout(&ioctl_info, (void *)arg,
3499517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl_t), mode) != 0) {
3509517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3519517SBill.Taylor@Sun.COM return (EFAULT);
3529517SBill.Taylor@Sun.COM }
3539517SBill.Taylor@Sun.COM
3549517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3559517SBill.Taylor@Sun.COM return (status);
3569517SBill.Taylor@Sun.COM }
3579517SBill.Taylor@Sun.COM
3589517SBill.Taylor@Sun.COM /*
3599517SBill.Taylor@Sun.COM * hermon_ioctl_flash_write()
3609517SBill.Taylor@Sun.COM */
3619517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_write(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)3629517SBill.Taylor@Sun.COM hermon_ioctl_flash_write(hermon_state_t *state, dev_t dev, intptr_t arg,
3639517SBill.Taylor@Sun.COM int mode)
3649517SBill.Taylor@Sun.COM {
3659517SBill.Taylor@Sun.COM hermon_flash_ioctl_t ioctl_info;
3669517SBill.Taylor@Sun.COM int status = 0;
3679517SBill.Taylor@Sun.COM
3689517SBill.Taylor@Sun.COM /*
3699517SBill.Taylor@Sun.COM * Check that flash init ioctl has been called first. And check
3709517SBill.Taylor@Sun.COM * that the same dev_t that called init is the one calling write now.
3719517SBill.Taylor@Sun.COM */
3729517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
3739517SBill.Taylor@Sun.COM if ((state->hs_fw_flashdev != dev) ||
3749517SBill.Taylor@Sun.COM (state->hs_fw_flashstarted == 0)) {
3759517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3769517SBill.Taylor@Sun.COM return (EIO);
3779517SBill.Taylor@Sun.COM }
3789517SBill.Taylor@Sun.COM
3799517SBill.Taylor@Sun.COM /* copy user struct to kernel */
3809517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
3819517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
3829517SBill.Taylor@Sun.COM hermon_flash_ioctl32_t info32;
3839517SBill.Taylor@Sun.COM
3849517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info32,
3859517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl32_t), mode) != 0) {
3869517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3879517SBill.Taylor@Sun.COM return (EFAULT);
3889517SBill.Taylor@Sun.COM }
3899517SBill.Taylor@Sun.COM ioctl_info.af_type = info32.af_type;
3909517SBill.Taylor@Sun.COM ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
3919517SBill.Taylor@Sun.COM ioctl_info.af_sector_num = info32.af_sector_num;
3929517SBill.Taylor@Sun.COM ioctl_info.af_addr = info32.af_addr;
3939517SBill.Taylor@Sun.COM ioctl_info.af_byte = info32.af_byte;
3949517SBill.Taylor@Sun.COM } else
3959517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
3969517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &ioctl_info,
3979517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl_t), mode) != 0) {
3989517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
3999517SBill.Taylor@Sun.COM return (EFAULT);
4009517SBill.Taylor@Sun.COM }
4019517SBill.Taylor@Sun.COM
4029517SBill.Taylor@Sun.COM /*
4039517SBill.Taylor@Sun.COM * Determine type of WRITE ioctl
4049517SBill.Taylor@Sun.COM */
4059517SBill.Taylor@Sun.COM switch (ioctl_info.af_type) {
4069517SBill.Taylor@Sun.COM case HERMON_FLASH_WRITE_SECTOR:
4079517SBill.Taylor@Sun.COM /* Check if sector num is too large for flash device */
4089517SBill.Taylor@Sun.COM if (ioctl_info.af_sector_num >=
4099517SBill.Taylor@Sun.COM (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
4109517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4119517SBill.Taylor@Sun.COM return (EFAULT);
4129517SBill.Taylor@Sun.COM }
4139517SBill.Taylor@Sun.COM
4149517SBill.Taylor@Sun.COM /* copy in fw sector image data */
4159517SBill.Taylor@Sun.COM if (ddi_copyin(&ioctl_info.af_sector[0],
4169517SBill.Taylor@Sun.COM &state->hs_fw_sector[0], 1 << state->hs_fw_log_sector_sz,
4179517SBill.Taylor@Sun.COM mode) != 0) {
4189517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4199517SBill.Taylor@Sun.COM return (EFAULT);
4209517SBill.Taylor@Sun.COM }
4219517SBill.Taylor@Sun.COM
4229517SBill.Taylor@Sun.COM /* Perform Write Sector */
4239517SBill.Taylor@Sun.COM status = hermon_flash_write_sector(state,
4249517SBill.Taylor@Sun.COM ioctl_info.af_sector_num);
4259517SBill.Taylor@Sun.COM break;
4269517SBill.Taylor@Sun.COM
4279517SBill.Taylor@Sun.COM case HERMON_FLASH_WRITE_BYTE:
4289517SBill.Taylor@Sun.COM /* Check if addr is too large for flash device */
4299517SBill.Taylor@Sun.COM if (ioctl_info.af_addr >= state->hs_fw_device_sz) {
4309517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4319517SBill.Taylor@Sun.COM return (EFAULT);
4329517SBill.Taylor@Sun.COM }
4339517SBill.Taylor@Sun.COM
4349517SBill.Taylor@Sun.COM /* Perform Write Byte */
4359517SBill.Taylor@Sun.COM /*
4369517SBill.Taylor@Sun.COM * CMJ -- is a reset really needed before and after writing
4379517SBill.Taylor@Sun.COM * each byte? This code came from arbel, but we should look
4389517SBill.Taylor@Sun.COM * into this. Also, for SPI, no reset is actually performed.
4399517SBill.Taylor@Sun.COM */
4409517SBill.Taylor@Sun.COM if ((status = hermon_flash_bank(state,
4419517SBill.Taylor@Sun.COM ioctl_info.af_addr)) != 0 ||
4429517SBill.Taylor@Sun.COM (status = hermon_flash_reset(state)) != 0 ||
4439517SBill.Taylor@Sun.COM (status = hermon_flash_write_byte(state,
4449517SBill.Taylor@Sun.COM ioctl_info.af_addr, ioctl_info.af_byte)) != 0 ||
4459517SBill.Taylor@Sun.COM (status = hermon_flash_reset(state)) != 0) {
4469517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4479517SBill.Taylor@Sun.COM return (status);
4489517SBill.Taylor@Sun.COM }
4499517SBill.Taylor@Sun.COM break;
4509517SBill.Taylor@Sun.COM
4519517SBill.Taylor@Sun.COM default:
4529517SBill.Taylor@Sun.COM status = EINVAL;
4539517SBill.Taylor@Sun.COM break;
4549517SBill.Taylor@Sun.COM }
4559517SBill.Taylor@Sun.COM
4569517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4579517SBill.Taylor@Sun.COM return (status);
4589517SBill.Taylor@Sun.COM }
4599517SBill.Taylor@Sun.COM
4609517SBill.Taylor@Sun.COM /*
4619517SBill.Taylor@Sun.COM * hermon_ioctl_flash_erase()
4629517SBill.Taylor@Sun.COM */
4639517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_erase(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)4649517SBill.Taylor@Sun.COM hermon_ioctl_flash_erase(hermon_state_t *state, dev_t dev, intptr_t arg,
4659517SBill.Taylor@Sun.COM int mode)
4669517SBill.Taylor@Sun.COM {
4679517SBill.Taylor@Sun.COM hermon_flash_ioctl_t ioctl_info;
4689517SBill.Taylor@Sun.COM int status = 0;
4699517SBill.Taylor@Sun.COM
4709517SBill.Taylor@Sun.COM /*
4719517SBill.Taylor@Sun.COM * Check that flash init ioctl has been called first. And check
4729517SBill.Taylor@Sun.COM * that the same dev_t that called init is the one calling erase now.
4739517SBill.Taylor@Sun.COM */
4749517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
4759517SBill.Taylor@Sun.COM if ((state->hs_fw_flashdev != dev) ||
4769517SBill.Taylor@Sun.COM (state->hs_fw_flashstarted == 0)) {
4779517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4789517SBill.Taylor@Sun.COM return (EIO);
4799517SBill.Taylor@Sun.COM }
4809517SBill.Taylor@Sun.COM
4819517SBill.Taylor@Sun.COM /* copy user struct to kernel */
4829517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
4839517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
4849517SBill.Taylor@Sun.COM hermon_flash_ioctl32_t info32;
4859517SBill.Taylor@Sun.COM
4869517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info32,
4879517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl32_t), mode) != 0) {
4889517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4899517SBill.Taylor@Sun.COM return (EFAULT);
4909517SBill.Taylor@Sun.COM }
4919517SBill.Taylor@Sun.COM ioctl_info.af_type = info32.af_type;
4929517SBill.Taylor@Sun.COM ioctl_info.af_sector_num = info32.af_sector_num;
4939517SBill.Taylor@Sun.COM } else
4949517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
4959517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &ioctl_info, sizeof (hermon_flash_ioctl_t),
4969517SBill.Taylor@Sun.COM mode) != 0) {
4979517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
4989517SBill.Taylor@Sun.COM return (EFAULT);
4999517SBill.Taylor@Sun.COM }
5009517SBill.Taylor@Sun.COM
5019517SBill.Taylor@Sun.COM /*
5029517SBill.Taylor@Sun.COM * Determine type of ERASE ioctl
5039517SBill.Taylor@Sun.COM */
5049517SBill.Taylor@Sun.COM switch (ioctl_info.af_type) {
5059517SBill.Taylor@Sun.COM case HERMON_FLASH_ERASE_SECTOR:
5069517SBill.Taylor@Sun.COM /* Check if sector num is too large for flash device */
5079517SBill.Taylor@Sun.COM if (ioctl_info.af_sector_num >=
5089517SBill.Taylor@Sun.COM (state->hs_fw_device_sz >> state->hs_fw_log_sector_sz)) {
5099517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5109517SBill.Taylor@Sun.COM return (EFAULT);
5119517SBill.Taylor@Sun.COM }
5129517SBill.Taylor@Sun.COM
5139517SBill.Taylor@Sun.COM /* Perform Sector Erase */
5149517SBill.Taylor@Sun.COM status = hermon_flash_erase_sector(state,
5159517SBill.Taylor@Sun.COM ioctl_info.af_sector_num);
5169517SBill.Taylor@Sun.COM break;
5179517SBill.Taylor@Sun.COM
5189517SBill.Taylor@Sun.COM case HERMON_FLASH_ERASE_CHIP:
5199517SBill.Taylor@Sun.COM /* Perform Chip Erase */
5209517SBill.Taylor@Sun.COM status = hermon_flash_erase_chip(state);
5219517SBill.Taylor@Sun.COM break;
5229517SBill.Taylor@Sun.COM
5239517SBill.Taylor@Sun.COM default:
5249517SBill.Taylor@Sun.COM status = EINVAL;
5259517SBill.Taylor@Sun.COM break;
5269517SBill.Taylor@Sun.COM }
5279517SBill.Taylor@Sun.COM
5289517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5299517SBill.Taylor@Sun.COM return (status);
5309517SBill.Taylor@Sun.COM }
5319517SBill.Taylor@Sun.COM
5329517SBill.Taylor@Sun.COM /*
5339517SBill.Taylor@Sun.COM * hermon_ioctl_flash_init()
5349517SBill.Taylor@Sun.COM */
5359517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_init(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)5369517SBill.Taylor@Sun.COM hermon_ioctl_flash_init(hermon_state_t *state, dev_t dev, intptr_t arg,
5379517SBill.Taylor@Sun.COM int mode)
5389517SBill.Taylor@Sun.COM {
5399517SBill.Taylor@Sun.COM hermon_flash_init_ioctl_t init_info;
5409517SBill.Taylor@Sun.COM int ret;
5419517SBill.Taylor@Sun.COM int intel_xcmd = 0;
5429517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
5439517SBill.Taylor@Sun.COM
5449517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
5459517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
5469517SBill.Taylor@Sun.COM
5479517SBill.Taylor@Sun.COM state->hs_fw_sector = NULL;
5489517SBill.Taylor@Sun.COM
5499517SBill.Taylor@Sun.COM /*
5509517SBill.Taylor@Sun.COM * init cannot be called more than once. If we have already init'd the
5519517SBill.Taylor@Sun.COM * flash, return directly.
5529517SBill.Taylor@Sun.COM */
5539517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
5549517SBill.Taylor@Sun.COM if (state->hs_fw_flashstarted == 1) {
5559517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5569517SBill.Taylor@Sun.COM return (EINVAL);
5579517SBill.Taylor@Sun.COM }
5589517SBill.Taylor@Sun.COM
5599517SBill.Taylor@Sun.COM /* copyin the user struct to kernel */
5609517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &init_info,
5619517SBill.Taylor@Sun.COM sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
5629517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5639517SBill.Taylor@Sun.COM return (EFAULT);
5649517SBill.Taylor@Sun.COM }
5659517SBill.Taylor@Sun.COM
5669517SBill.Taylor@Sun.COM /* Init Flash */
5679517SBill.Taylor@Sun.COM if ((ret = hermon_flash_init(state)) != 0) {
5689517SBill.Taylor@Sun.COM if (ret == EIO) {
5699517SBill.Taylor@Sun.COM goto pio_error;
5709517SBill.Taylor@Sun.COM }
5719517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5729517SBill.Taylor@Sun.COM return (ret);
5739517SBill.Taylor@Sun.COM }
5749517SBill.Taylor@Sun.COM
5759517SBill.Taylor@Sun.COM /* Read CFI info */
5769517SBill.Taylor@Sun.COM if ((ret = hermon_flash_cfi_init(state, &init_info.af_cfi_info[0],
5779517SBill.Taylor@Sun.COM &intel_xcmd)) != 0) {
5789517SBill.Taylor@Sun.COM if (ret == EIO) {
5799517SBill.Taylor@Sun.COM goto pio_error;
5809517SBill.Taylor@Sun.COM }
5819517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5829517SBill.Taylor@Sun.COM return (ret);
5839517SBill.Taylor@Sun.COM }
5849517SBill.Taylor@Sun.COM
5859517SBill.Taylor@Sun.COM /*
5869517SBill.Taylor@Sun.COM * Return error if the command set is unknown.
5879517SBill.Taylor@Sun.COM */
5889517SBill.Taylor@Sun.COM if (state->hs_fw_cmdset == HERMON_FLASH_UNKNOWN_CMDSET) {
5899517SBill.Taylor@Sun.COM if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
5909517SBill.Taylor@Sun.COM if (ret == EIO) {
5919517SBill.Taylor@Sun.COM goto pio_error;
5929517SBill.Taylor@Sun.COM }
5939517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5949517SBill.Taylor@Sun.COM return (ret);
5959517SBill.Taylor@Sun.COM }
5969517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
5979517SBill.Taylor@Sun.COM return (EFAULT);
5989517SBill.Taylor@Sun.COM }
5999517SBill.Taylor@Sun.COM
6009517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
6019517SBill.Taylor@Sun.COM hermon_pio_start(state, pci_hdl, pio_error,
6029517SBill.Taylor@Sun.COM fm_loop_cnt, fm_status, fm_test);
6039517SBill.Taylor@Sun.COM
6049517SBill.Taylor@Sun.COM /* Read HWREV - least significant 8 bits is revision ID */
6059517SBill.Taylor@Sun.COM init_info.af_hwrev = pci_config_get32(pci_hdl,
6069517SBill.Taylor@Sun.COM HERMON_HW_FLASH_CFG_HWREV) & 0xFF;
6079517SBill.Taylor@Sun.COM
6089517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
6099517SBill.Taylor@Sun.COM hermon_pio_end(state, pci_hdl, pio_error, fm_loop_cnt,
6109517SBill.Taylor@Sun.COM fm_status, fm_test);
6119517SBill.Taylor@Sun.COM
6129517SBill.Taylor@Sun.COM /* Fill in the firmwate revision numbers */
6139517SBill.Taylor@Sun.COM init_info.af_fwrev.afi_maj = state->hs_fw.fw_rev_major;
6149517SBill.Taylor@Sun.COM init_info.af_fwrev.afi_min = state->hs_fw.fw_rev_minor;
6159517SBill.Taylor@Sun.COM init_info.af_fwrev.afi_sub = state->hs_fw.fw_rev_subminor;
6169517SBill.Taylor@Sun.COM
6179517SBill.Taylor@Sun.COM /* Alloc flash mem for one sector size */
6189517SBill.Taylor@Sun.COM state->hs_fw_sector = (uint32_t *)kmem_zalloc(1 <<
6199517SBill.Taylor@Sun.COM state->hs_fw_log_sector_sz, KM_SLEEP);
6209517SBill.Taylor@Sun.COM
6219517SBill.Taylor@Sun.COM /* Set HW part number and length */
6229517SBill.Taylor@Sun.COM init_info.af_pn_len = state->hs_hca_pn_len;
6239517SBill.Taylor@Sun.COM if (state->hs_hca_pn_len != 0) {
6249517SBill.Taylor@Sun.COM (void) memcpy(init_info.af_hwpn, state->hs_hca_pn,
6259517SBill.Taylor@Sun.COM state->hs_hca_pn_len);
6269517SBill.Taylor@Sun.COM }
6279517SBill.Taylor@Sun.COM
6289517SBill.Taylor@Sun.COM /* Copy ioctl results back to userland */
6299517SBill.Taylor@Sun.COM if (ddi_copyout(&init_info, (void *)arg,
6309517SBill.Taylor@Sun.COM sizeof (hermon_flash_init_ioctl_t), mode) != 0) {
6319517SBill.Taylor@Sun.COM if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6329517SBill.Taylor@Sun.COM if (ret == EIO) {
6339517SBill.Taylor@Sun.COM goto pio_error;
6349517SBill.Taylor@Sun.COM }
6359517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
6369517SBill.Taylor@Sun.COM return (ret);
6379517SBill.Taylor@Sun.COM }
6389517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
6399517SBill.Taylor@Sun.COM return (EFAULT);
6409517SBill.Taylor@Sun.COM }
6419517SBill.Taylor@Sun.COM
6429517SBill.Taylor@Sun.COM /* Set flash state to started */
6439517SBill.Taylor@Sun.COM state->hs_fw_flashstarted = 1;
6449517SBill.Taylor@Sun.COM state->hs_fw_flashdev = dev;
6459517SBill.Taylor@Sun.COM
6469517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
6479517SBill.Taylor@Sun.COM
6489517SBill.Taylor@Sun.COM /*
6499517SBill.Taylor@Sun.COM * If "flash init" is successful, add an "on close" callback to the
6509517SBill.Taylor@Sun.COM * current dev node to ensure that "flash fini" gets called later
6519517SBill.Taylor@Sun.COM * even if the userland process prematurely exits.
6529517SBill.Taylor@Sun.COM */
6539517SBill.Taylor@Sun.COM ret = hermon_umap_db_set_onclose_cb(dev,
6549517SBill.Taylor@Sun.COM HERMON_ONCLOSE_FLASH_INPROGRESS,
6559517SBill.Taylor@Sun.COM (int (*)(void *))hermon_ioctl_flash_cleanup, state);
6569517SBill.Taylor@Sun.COM if (ret != DDI_SUCCESS) {
6579517SBill.Taylor@Sun.COM int status = hermon_ioctl_flash_fini(state, dev);
6589517SBill.Taylor@Sun.COM if (status != 0) {
6599517SBill.Taylor@Sun.COM if (status == EIO) {
6609517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
6619517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
6629517SBill.Taylor@Sun.COM return (EIO);
6639517SBill.Taylor@Sun.COM }
6649517SBill.Taylor@Sun.COM return (status);
6659517SBill.Taylor@Sun.COM }
6669517SBill.Taylor@Sun.COM }
6679517SBill.Taylor@Sun.COM return (0);
6689517SBill.Taylor@Sun.COM
6699517SBill.Taylor@Sun.COM pio_error:
6709517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
6719517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6729517SBill.Taylor@Sun.COM return (EIO);
6739517SBill.Taylor@Sun.COM }
6749517SBill.Taylor@Sun.COM
6759517SBill.Taylor@Sun.COM /*
6769517SBill.Taylor@Sun.COM * hermon_ioctl_flash_fini()
6779517SBill.Taylor@Sun.COM */
6789517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_fini(hermon_state_t * state,dev_t dev)6799517SBill.Taylor@Sun.COM hermon_ioctl_flash_fini(hermon_state_t *state, dev_t dev)
6809517SBill.Taylor@Sun.COM {
6819517SBill.Taylor@Sun.COM int ret;
6829517SBill.Taylor@Sun.COM
6839517SBill.Taylor@Sun.COM /*
6849517SBill.Taylor@Sun.COM * Check that flash init ioctl has been called first. And check
6859517SBill.Taylor@Sun.COM * that the same dev_t that called init is the one calling fini now.
6869517SBill.Taylor@Sun.COM */
6879517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
6889517SBill.Taylor@Sun.COM if ((state->hs_fw_flashdev != dev) ||
6899517SBill.Taylor@Sun.COM (state->hs_fw_flashstarted == 0)) {
6909517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
6919517SBill.Taylor@Sun.COM return (EINVAL);
6929517SBill.Taylor@Sun.COM }
6939517SBill.Taylor@Sun.COM
6949517SBill.Taylor@Sun.COM if ((ret = hermon_ioctl_flash_cleanup_nolock(state)) != 0) {
6959517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
6969517SBill.Taylor@Sun.COM if (ret == EIO) {
6979517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
6989517SBill.Taylor@Sun.COM }
6999517SBill.Taylor@Sun.COM return (ret);
7009517SBill.Taylor@Sun.COM }
7019517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
7029517SBill.Taylor@Sun.COM
7039517SBill.Taylor@Sun.COM /*
7049517SBill.Taylor@Sun.COM * If "flash fini" is successful, remove the "on close" callback
7059517SBill.Taylor@Sun.COM * that was setup during "flash init".
7069517SBill.Taylor@Sun.COM */
7079517SBill.Taylor@Sun.COM ret = hermon_umap_db_clear_onclose_cb(dev,
7089517SBill.Taylor@Sun.COM HERMON_ONCLOSE_FLASH_INPROGRESS);
7099517SBill.Taylor@Sun.COM if (ret != DDI_SUCCESS) {
7109517SBill.Taylor@Sun.COM return (EFAULT);
7119517SBill.Taylor@Sun.COM }
7129517SBill.Taylor@Sun.COM return (0);
7139517SBill.Taylor@Sun.COM }
7149517SBill.Taylor@Sun.COM
7159517SBill.Taylor@Sun.COM
7169517SBill.Taylor@Sun.COM /*
7179517SBill.Taylor@Sun.COM * hermon_ioctl_flash_cleanup()
7189517SBill.Taylor@Sun.COM */
7199517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_cleanup(hermon_state_t * state)7209517SBill.Taylor@Sun.COM hermon_ioctl_flash_cleanup(hermon_state_t *state)
7219517SBill.Taylor@Sun.COM {
7229517SBill.Taylor@Sun.COM int status;
7239517SBill.Taylor@Sun.COM
7249517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
7259517SBill.Taylor@Sun.COM status = hermon_ioctl_flash_cleanup_nolock(state);
7269517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
7279517SBill.Taylor@Sun.COM
7289517SBill.Taylor@Sun.COM return (status);
7299517SBill.Taylor@Sun.COM }
7309517SBill.Taylor@Sun.COM
7319517SBill.Taylor@Sun.COM
7329517SBill.Taylor@Sun.COM /*
7339517SBill.Taylor@Sun.COM * hermon_ioctl_flash_cleanup_nolock()
7349517SBill.Taylor@Sun.COM */
7359517SBill.Taylor@Sun.COM static int
hermon_ioctl_flash_cleanup_nolock(hermon_state_t * state)7369517SBill.Taylor@Sun.COM hermon_ioctl_flash_cleanup_nolock(hermon_state_t *state)
7379517SBill.Taylor@Sun.COM {
7389517SBill.Taylor@Sun.COM int status;
7399517SBill.Taylor@Sun.COM ASSERT(MUTEX_HELD(&state->hs_fw_flashlock));
7409517SBill.Taylor@Sun.COM
7419517SBill.Taylor@Sun.COM /* free flash mem */
7429517SBill.Taylor@Sun.COM if (state->hs_fw_sector) {
7439517SBill.Taylor@Sun.COM kmem_free(state->hs_fw_sector, 1 << state->hs_fw_log_sector_sz);
7449517SBill.Taylor@Sun.COM }
7459517SBill.Taylor@Sun.COM
7469517SBill.Taylor@Sun.COM /* Fini the Flash */
7479517SBill.Taylor@Sun.COM if ((status = hermon_flash_fini(state)) != 0)
7489517SBill.Taylor@Sun.COM return (status);
7499517SBill.Taylor@Sun.COM
7509517SBill.Taylor@Sun.COM /* Set flash state to fini */
7519517SBill.Taylor@Sun.COM state->hs_fw_flashstarted = 0;
7529517SBill.Taylor@Sun.COM state->hs_fw_flashdev = 0;
7539517SBill.Taylor@Sun.COM return (0);
7549517SBill.Taylor@Sun.COM }
7559517SBill.Taylor@Sun.COM
7569517SBill.Taylor@Sun.COM
7579517SBill.Taylor@Sun.COM /*
7589517SBill.Taylor@Sun.COM * hermon_ioctl_info()
7599517SBill.Taylor@Sun.COM */
7609517SBill.Taylor@Sun.COM static int
hermon_ioctl_info(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)7619517SBill.Taylor@Sun.COM hermon_ioctl_info(hermon_state_t *state, dev_t dev, intptr_t arg, int mode)
7629517SBill.Taylor@Sun.COM {
7639517SBill.Taylor@Sun.COM hermon_info_ioctl_t info;
7649517SBill.Taylor@Sun.COM hermon_flash_init_ioctl_t init_info;
7659517SBill.Taylor@Sun.COM
7669517SBill.Taylor@Sun.COM /*
7679517SBill.Taylor@Sun.COM * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
7689517SBill.Taylor@Sun.COM */
7699517SBill.Taylor@Sun.COM if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
7709517SBill.Taylor@Sun.COM return (EFAULT);
7719517SBill.Taylor@Sun.COM }
7729517SBill.Taylor@Sun.COM
7739517SBill.Taylor@Sun.COM /* copyin the user struct to kernel */
7749517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info, sizeof (hermon_info_ioctl_t),
7759517SBill.Taylor@Sun.COM mode) != 0) {
7769517SBill.Taylor@Sun.COM return (EFAULT);
7779517SBill.Taylor@Sun.COM }
7789517SBill.Taylor@Sun.COM
7799517SBill.Taylor@Sun.COM /*
7809517SBill.Taylor@Sun.COM * Check ioctl revision
7819517SBill.Taylor@Sun.COM */
7829517SBill.Taylor@Sun.COM if (info.ai_revision != HERMON_VTS_IOCTL_REVISION) {
7839517SBill.Taylor@Sun.COM return (EINVAL);
7849517SBill.Taylor@Sun.COM }
7859517SBill.Taylor@Sun.COM
7869517SBill.Taylor@Sun.COM /*
7879517SBill.Taylor@Sun.COM * If the 'fw_device_sz' has not been initialized yet, we initialize it
7889517SBill.Taylor@Sun.COM * here. This is done by leveraging the
7899517SBill.Taylor@Sun.COM * hermon_ioctl_flash_init()/fini() calls. We also hold our own mutex
7909517SBill.Taylor@Sun.COM * around this operation in case we have multiple VTS threads in
7919517SBill.Taylor@Sun.COM * process at the same time.
7929517SBill.Taylor@Sun.COM */
7939517SBill.Taylor@Sun.COM mutex_enter(&state->hs_info_lock);
7949517SBill.Taylor@Sun.COM if (state->hs_fw_device_sz == 0) {
7959517SBill.Taylor@Sun.COM if (hermon_ioctl_flash_init(state, dev, (intptr_t)&init_info,
7969517SBill.Taylor@Sun.COM (FKIOCTL | mode)) != 0) {
7979517SBill.Taylor@Sun.COM mutex_exit(&state->hs_info_lock);
7989517SBill.Taylor@Sun.COM return (EFAULT);
7999517SBill.Taylor@Sun.COM }
8009517SBill.Taylor@Sun.COM (void) hermon_ioctl_flash_fini(state, dev);
8019517SBill.Taylor@Sun.COM }
8029517SBill.Taylor@Sun.COM mutex_exit(&state->hs_info_lock);
8039517SBill.Taylor@Sun.COM
8049517SBill.Taylor@Sun.COM info.ai_hw_rev = state->hs_revision_id;
8059517SBill.Taylor@Sun.COM info.ai_flash_sz = state->hs_fw_device_sz;
8069517SBill.Taylor@Sun.COM info.ai_fw_rev.afi_maj = state->hs_fw.fw_rev_major;
8079517SBill.Taylor@Sun.COM info.ai_fw_rev.afi_min = state->hs_fw.fw_rev_minor;
8089517SBill.Taylor@Sun.COM info.ai_fw_rev.afi_sub = state->hs_fw.fw_rev_subminor;
8099517SBill.Taylor@Sun.COM
8109517SBill.Taylor@Sun.COM /* Copy ioctl results back to user struct */
8119517SBill.Taylor@Sun.COM if (ddi_copyout(&info, (void *)arg, sizeof (hermon_info_ioctl_t),
8129517SBill.Taylor@Sun.COM mode) != 0) {
8139517SBill.Taylor@Sun.COM return (EFAULT);
8149517SBill.Taylor@Sun.COM }
8159517SBill.Taylor@Sun.COM
8169517SBill.Taylor@Sun.COM return (0);
8179517SBill.Taylor@Sun.COM }
8189517SBill.Taylor@Sun.COM
8199517SBill.Taylor@Sun.COM /*
8209517SBill.Taylor@Sun.COM * hermon_ioctl_ports()
8219517SBill.Taylor@Sun.COM */
8229517SBill.Taylor@Sun.COM static int
hermon_ioctl_ports(hermon_state_t * state,intptr_t arg,int mode)8239517SBill.Taylor@Sun.COM hermon_ioctl_ports(hermon_state_t *state, intptr_t arg, int mode)
8249517SBill.Taylor@Sun.COM {
8259517SBill.Taylor@Sun.COM hermon_ports_ioctl_t info;
8269517SBill.Taylor@Sun.COM hermon_stat_port_ioctl_t portstat;
8279517SBill.Taylor@Sun.COM ibt_hca_portinfo_t pi;
8289517SBill.Taylor@Sun.COM uint_t tbl_size;
8299517SBill.Taylor@Sun.COM ib_gid_t *sgid_tbl;
8309517SBill.Taylor@Sun.COM ib_pkey_t *pkey_tbl;
8319517SBill.Taylor@Sun.COM int i;
8329517SBill.Taylor@Sun.COM
8339517SBill.Taylor@Sun.COM /*
8349517SBill.Taylor@Sun.COM * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
8359517SBill.Taylor@Sun.COM */
8369517SBill.Taylor@Sun.COM if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
8379517SBill.Taylor@Sun.COM return (EFAULT);
8389517SBill.Taylor@Sun.COM }
8399517SBill.Taylor@Sun.COM
8409517SBill.Taylor@Sun.COM /* copyin the user struct to kernel */
8419517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
8429517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
8439517SBill.Taylor@Sun.COM hermon_ports_ioctl32_t info32;
8449517SBill.Taylor@Sun.COM
8459517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info32,
8469517SBill.Taylor@Sun.COM sizeof (hermon_ports_ioctl32_t), mode) != 0) {
8479517SBill.Taylor@Sun.COM return (EFAULT);
8489517SBill.Taylor@Sun.COM }
8499517SBill.Taylor@Sun.COM info.ap_revision = info32.ap_revision;
8509517SBill.Taylor@Sun.COM info.ap_ports =
8519517SBill.Taylor@Sun.COM (hermon_stat_port_ioctl_t *)(uintptr_t)info32.ap_ports;
8529517SBill.Taylor@Sun.COM info.ap_num_ports = info32.ap_num_ports;
8539517SBill.Taylor@Sun.COM
8549517SBill.Taylor@Sun.COM } else
8559517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
8569517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info, sizeof (hermon_ports_ioctl_t),
8579517SBill.Taylor@Sun.COM mode) != 0) {
8589517SBill.Taylor@Sun.COM return (EFAULT);
8599517SBill.Taylor@Sun.COM }
8609517SBill.Taylor@Sun.COM
8619517SBill.Taylor@Sun.COM /*
8629517SBill.Taylor@Sun.COM * Check ioctl revision
8639517SBill.Taylor@Sun.COM */
8649517SBill.Taylor@Sun.COM if (info.ap_revision != HERMON_VTS_IOCTL_REVISION) {
8659517SBill.Taylor@Sun.COM return (EINVAL);
8669517SBill.Taylor@Sun.COM }
8679517SBill.Taylor@Sun.COM
8689517SBill.Taylor@Sun.COM /* Allocate space for temporary GID table/PKey table */
8699517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
8709517SBill.Taylor@Sun.COM sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
8719517SBill.Taylor@Sun.COM KM_SLEEP);
8729517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
8739517SBill.Taylor@Sun.COM pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
8749517SBill.Taylor@Sun.COM KM_SLEEP);
8759517SBill.Taylor@Sun.COM
8769517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sgid_tbl, *pkey_tbl))
8779517SBill.Taylor@Sun.COM
8789517SBill.Taylor@Sun.COM /*
8799517SBill.Taylor@Sun.COM * Setup the number of ports, then loop through all ports and
8809517SBill.Taylor@Sun.COM * query properties of each.
8819517SBill.Taylor@Sun.COM */
8829517SBill.Taylor@Sun.COM info.ap_num_ports = (uint8_t)state->hs_cfg_profile->cp_num_ports;
8839517SBill.Taylor@Sun.COM for (i = 0; i < info.ap_num_ports; i++) {
8849517SBill.Taylor@Sun.COM /*
8859517SBill.Taylor@Sun.COM * Get portstate information from the device. If
8869517SBill.Taylor@Sun.COM * hermon_port_query() fails, leave zeroes in user
8879517SBill.Taylor@Sun.COM * struct port entry and continue.
8889517SBill.Taylor@Sun.COM */
8899517SBill.Taylor@Sun.COM bzero(&pi, sizeof (ibt_hca_portinfo_t));
8909517SBill.Taylor@Sun.COM pi.p_sgid_tbl = sgid_tbl;
8919517SBill.Taylor@Sun.COM pi.p_pkey_tbl = pkey_tbl;
8929517SBill.Taylor@Sun.COM (void) hermon_port_query(state, i + 1, &pi);
8939517SBill.Taylor@Sun.COM
8949517SBill.Taylor@Sun.COM portstat.asp_port_num = pi.p_port_num;
8959517SBill.Taylor@Sun.COM portstat.asp_state = pi.p_linkstate;
8969517SBill.Taylor@Sun.COM portstat.asp_guid = pi.p_sgid_tbl[0].gid_guid;
8979517SBill.Taylor@Sun.COM
8989517SBill.Taylor@Sun.COM /*
8999517SBill.Taylor@Sun.COM * Copy queried port results back to user struct. If
9009517SBill.Taylor@Sun.COM * this fails, then break out of loop, attempt to copy
9019517SBill.Taylor@Sun.COM * out remaining info to user struct, and return (without
9029517SBill.Taylor@Sun.COM * error).
9039517SBill.Taylor@Sun.COM */
9049517SBill.Taylor@Sun.COM if (ddi_copyout(&portstat,
9059517SBill.Taylor@Sun.COM &(((hermon_stat_port_ioctl_t *)info.ap_ports)[i]),
9069517SBill.Taylor@Sun.COM sizeof (hermon_stat_port_ioctl_t), mode) != 0) {
9079517SBill.Taylor@Sun.COM break;
9089517SBill.Taylor@Sun.COM }
9099517SBill.Taylor@Sun.COM }
9109517SBill.Taylor@Sun.COM
9119517SBill.Taylor@Sun.COM /* Free the temporary space used for GID table/PKey table */
9129517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
9139517SBill.Taylor@Sun.COM kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
9149517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
9159517SBill.Taylor@Sun.COM kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
9169517SBill.Taylor@Sun.COM
9179517SBill.Taylor@Sun.COM /* Copy ioctl results back to user struct */
9189517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
9199517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9209517SBill.Taylor@Sun.COM hermon_ports_ioctl32_t info32;
9219517SBill.Taylor@Sun.COM
9229517SBill.Taylor@Sun.COM info32.ap_revision = info.ap_revision;
9239517SBill.Taylor@Sun.COM info32.ap_ports = (caddr32_t)(uintptr_t)info.ap_ports;
9249517SBill.Taylor@Sun.COM info32.ap_num_ports = info.ap_num_ports;
9259517SBill.Taylor@Sun.COM
9269517SBill.Taylor@Sun.COM if (ddi_copyout(&info32, (void *)arg,
9279517SBill.Taylor@Sun.COM sizeof (hermon_ports_ioctl32_t), mode) != 0) {
9289517SBill.Taylor@Sun.COM return (EFAULT);
9299517SBill.Taylor@Sun.COM }
9309517SBill.Taylor@Sun.COM } else
9319517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
9329517SBill.Taylor@Sun.COM if (ddi_copyout(&info, (void *)arg, sizeof (hermon_ports_ioctl_t),
9339517SBill.Taylor@Sun.COM mode) != 0) {
9349517SBill.Taylor@Sun.COM return (EFAULT);
9359517SBill.Taylor@Sun.COM }
9369517SBill.Taylor@Sun.COM
9379517SBill.Taylor@Sun.COM return (0);
9389517SBill.Taylor@Sun.COM }
9399517SBill.Taylor@Sun.COM
9409517SBill.Taylor@Sun.COM /*
9419517SBill.Taylor@Sun.COM * hermon_ioctl_loopback()
9429517SBill.Taylor@Sun.COM */
9439517SBill.Taylor@Sun.COM static int
hermon_ioctl_loopback(hermon_state_t * state,intptr_t arg,int mode)9449517SBill.Taylor@Sun.COM hermon_ioctl_loopback(hermon_state_t *state, intptr_t arg, int mode)
9459517SBill.Taylor@Sun.COM {
9469517SBill.Taylor@Sun.COM hermon_loopback_ioctl_t lb;
9479517SBill.Taylor@Sun.COM hermon_loopback_state_t lstate;
9489517SBill.Taylor@Sun.COM ibt_hca_portinfo_t pi;
9499517SBill.Taylor@Sun.COM uint_t tbl_size, loopmax, max_usec;
9509517SBill.Taylor@Sun.COM ib_gid_t *sgid_tbl;
9519517SBill.Taylor@Sun.COM ib_pkey_t *pkey_tbl;
9529517SBill.Taylor@Sun.COM int j, iter, ret;
9539517SBill.Taylor@Sun.COM
9549517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(lstate))
9559517SBill.Taylor@Sun.COM
9569517SBill.Taylor@Sun.COM /*
9579517SBill.Taylor@Sun.COM * Access to Hemron VTS ioctls is not allowed in "maintenance mode".
9589517SBill.Taylor@Sun.COM */
9599517SBill.Taylor@Sun.COM if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
9609517SBill.Taylor@Sun.COM return (EFAULT);
9619517SBill.Taylor@Sun.COM }
9629517SBill.Taylor@Sun.COM
9639517SBill.Taylor@Sun.COM /* copyin the user struct to kernel */
9649517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
9659517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
9669517SBill.Taylor@Sun.COM hermon_loopback_ioctl32_t lb32;
9679517SBill.Taylor@Sun.COM
9689517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &lb32,
9699517SBill.Taylor@Sun.COM sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
9709517SBill.Taylor@Sun.COM return (EFAULT);
9719517SBill.Taylor@Sun.COM }
9729517SBill.Taylor@Sun.COM lb.alb_revision = lb32.alb_revision;
9739517SBill.Taylor@Sun.COM lb.alb_send_buf = (caddr_t)(uintptr_t)lb32.alb_send_buf;
9749517SBill.Taylor@Sun.COM lb.alb_fail_buf = (caddr_t)(uintptr_t)lb32.alb_fail_buf;
9759517SBill.Taylor@Sun.COM lb.alb_buf_sz = lb32.alb_buf_sz;
9769517SBill.Taylor@Sun.COM lb.alb_num_iter = lb32.alb_num_iter;
9779517SBill.Taylor@Sun.COM lb.alb_pass_done = lb32.alb_pass_done;
9789517SBill.Taylor@Sun.COM lb.alb_timeout = lb32.alb_timeout;
9799517SBill.Taylor@Sun.COM lb.alb_error_type = lb32.alb_error_type;
9809517SBill.Taylor@Sun.COM lb.alb_port_num = lb32.alb_port_num;
9819517SBill.Taylor@Sun.COM lb.alb_num_retry = lb32.alb_num_retry;
9829517SBill.Taylor@Sun.COM } else
9839517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
9849517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &lb, sizeof (hermon_loopback_ioctl_t),
9859517SBill.Taylor@Sun.COM mode) != 0) {
9869517SBill.Taylor@Sun.COM return (EFAULT);
9879517SBill.Taylor@Sun.COM }
9889517SBill.Taylor@Sun.COM
9899517SBill.Taylor@Sun.COM /* Initialize the internal loopback test state structure */
9909517SBill.Taylor@Sun.COM bzero(&lstate, sizeof (hermon_loopback_state_t));
9919517SBill.Taylor@Sun.COM
9929517SBill.Taylor@Sun.COM /*
9939517SBill.Taylor@Sun.COM * Check ioctl revision
9949517SBill.Taylor@Sun.COM */
9959517SBill.Taylor@Sun.COM if (lb.alb_revision != HERMON_VTS_IOCTL_REVISION) {
9969517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_INVALID_REVISION;
9979517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
9989517SBill.Taylor@Sun.COM return (EINVAL);
9999517SBill.Taylor@Sun.COM }
10009517SBill.Taylor@Sun.COM
10019517SBill.Taylor@Sun.COM /* Validate that specified port number is legal */
10029517SBill.Taylor@Sun.COM if (!hermon_portnum_is_valid(state, lb.alb_port_num)) {
10039517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10049517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
10059517SBill.Taylor@Sun.COM return (EINVAL);
10069517SBill.Taylor@Sun.COM }
10079517SBill.Taylor@Sun.COM
10089517SBill.Taylor@Sun.COM /* Allocate space for temporary GID table/PKey table */
10099517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10109517SBill.Taylor@Sun.COM sgid_tbl = (ib_gid_t *)kmem_zalloc(tbl_size * sizeof (ib_gid_t),
10119517SBill.Taylor@Sun.COM KM_SLEEP);
10129517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10139517SBill.Taylor@Sun.COM pkey_tbl = (ib_pkey_t *)kmem_zalloc(tbl_size * sizeof (ib_pkey_t),
10149517SBill.Taylor@Sun.COM KM_SLEEP);
10159517SBill.Taylor@Sun.COM
10169517SBill.Taylor@Sun.COM /*
10179517SBill.Taylor@Sun.COM * Get portstate information from specific port on device
10189517SBill.Taylor@Sun.COM */
10199517SBill.Taylor@Sun.COM bzero(&pi, sizeof (ibt_hca_portinfo_t));
10209517SBill.Taylor@Sun.COM pi.p_sgid_tbl = sgid_tbl;
10219517SBill.Taylor@Sun.COM pi.p_pkey_tbl = pkey_tbl;
10229517SBill.Taylor@Sun.COM if (hermon_port_query(state, lb.alb_port_num, &pi) != 0) {
10239517SBill.Taylor@Sun.COM /* Free the temporary space used for GID table/PKey table */
10249517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10259517SBill.Taylor@Sun.COM kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10269517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10279517SBill.Taylor@Sun.COM kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10289517SBill.Taylor@Sun.COM
10299517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_INVALID_PORT;
10309517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
10319517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
10329517SBill.Taylor@Sun.COM return (EINVAL);
10339517SBill.Taylor@Sun.COM }
10349517SBill.Taylor@Sun.COM
10359517SBill.Taylor@Sun.COM lstate.hls_port = pi.p_port_num;
10369517SBill.Taylor@Sun.COM lstate.hls_lid = pi.p_base_lid;
10379517SBill.Taylor@Sun.COM lstate.hls_pkey_ix = (pi.p_linkstate == HERMON_PORT_LINK_ACTIVE) ?
10389517SBill.Taylor@Sun.COM 1 : 0; /* XXX bogus assumption of a SUN subnet manager */
10399517SBill.Taylor@Sun.COM lstate.hls_state = state;
10409517SBill.Taylor@Sun.COM lstate.hls_retry = lb.alb_num_retry;
10419517SBill.Taylor@Sun.COM
10429517SBill.Taylor@Sun.COM /* Free the temporary space used for GID table/PKey table */
10439517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_gidtbl);
10449517SBill.Taylor@Sun.COM kmem_free(sgid_tbl, tbl_size * sizeof (ib_gid_t));
10459517SBill.Taylor@Sun.COM tbl_size = (1 << state->hs_cfg_profile->cp_log_max_pkeytbl);
10469517SBill.Taylor@Sun.COM kmem_free(pkey_tbl, tbl_size * sizeof (ib_pkey_t));
10479517SBill.Taylor@Sun.COM
10489517SBill.Taylor@Sun.COM /*
10499517SBill.Taylor@Sun.COM * Compute the timeout duration in usec per the formula:
10509517SBill.Taylor@Sun.COM * to_usec_per_retry = 4.096us * (2 ^ supplied_timeout)
10519517SBill.Taylor@Sun.COM * (plus we add a little fudge-factor here too)
10529517SBill.Taylor@Sun.COM */
10539517SBill.Taylor@Sun.COM lstate.hls_timeout = lb.alb_timeout;
10549517SBill.Taylor@Sun.COM max_usec = (4096 * (1 << lstate.hls_timeout)) / 1000;
10559517SBill.Taylor@Sun.COM max_usec = max_usec * (lstate.hls_retry + 1);
10569517SBill.Taylor@Sun.COM max_usec = max_usec + 10000;
10579517SBill.Taylor@Sun.COM
10589517SBill.Taylor@Sun.COM /*
10599517SBill.Taylor@Sun.COM * Determine how many times we should loop before declaring a
10609517SBill.Taylor@Sun.COM * timeout failure.
10619517SBill.Taylor@Sun.COM */
10629517SBill.Taylor@Sun.COM loopmax = max_usec/HERMON_VTS_LOOPBACK_MIN_WAIT_DUR;
10639517SBill.Taylor@Sun.COM if ((max_usec % HERMON_VTS_LOOPBACK_MIN_WAIT_DUR) != 0) {
10649517SBill.Taylor@Sun.COM loopmax++;
10659517SBill.Taylor@Sun.COM }
10669517SBill.Taylor@Sun.COM
10679517SBill.Taylor@Sun.COM if (lb.alb_send_buf == NULL || lb.alb_buf_sz == 0) {
10689517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_INVALID;
10699517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
10709517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
10719517SBill.Taylor@Sun.COM return (EINVAL);
10729517SBill.Taylor@Sun.COM }
10739517SBill.Taylor@Sun.COM
10749517SBill.Taylor@Sun.COM /* Allocate protection domain (PD) */
10759517SBill.Taylor@Sun.COM if (hermon_loopback_init(state, &lstate) != 0) {
10769517SBill.Taylor@Sun.COM lb.alb_error_type = lstate.hls_err;
10779517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
10789517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
10799517SBill.Taylor@Sun.COM return (EFAULT);
10809517SBill.Taylor@Sun.COM }
10819517SBill.Taylor@Sun.COM
10829517SBill.Taylor@Sun.COM /* Allocate and register a TX buffer */
10839517SBill.Taylor@Sun.COM if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_tx,
10849517SBill.Taylor@Sun.COM lb.alb_buf_sz) != 0) {
10859517SBill.Taylor@Sun.COM lb.alb_error_type =
10869517SBill.Taylor@Sun.COM HERMON_LOOPBACK_SEND_BUF_MEM_REGION_ALLOC_FAIL;
10879517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
10889517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
10899517SBill.Taylor@Sun.COM return (EFAULT);
10909517SBill.Taylor@Sun.COM }
10919517SBill.Taylor@Sun.COM
10929517SBill.Taylor@Sun.COM /* Allocate and register an RX buffer */
10939517SBill.Taylor@Sun.COM if (hermon_loopback_alloc_mem(&lstate, &lstate.hls_rx,
10949517SBill.Taylor@Sun.COM lb.alb_buf_sz) != 0) {
10959517SBill.Taylor@Sun.COM lb.alb_error_type =
10969517SBill.Taylor@Sun.COM HERMON_LOOPBACK_RECV_BUF_MEM_REGION_ALLOC_FAIL;
10979517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
10989517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
10999517SBill.Taylor@Sun.COM return (EFAULT);
11009517SBill.Taylor@Sun.COM }
11019517SBill.Taylor@Sun.COM
11029517SBill.Taylor@Sun.COM /* Copy in the transmit buffer data */
11039517SBill.Taylor@Sun.COM if (ddi_copyin((void *)lb.alb_send_buf, lstate.hls_tx.hlc_buf,
11049517SBill.Taylor@Sun.COM lb.alb_buf_sz, mode) != 0) {
11059517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_SEND_BUF_COPY_FAIL;
11069517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11079517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11089517SBill.Taylor@Sun.COM return (EFAULT);
11099517SBill.Taylor@Sun.COM }
11109517SBill.Taylor@Sun.COM
11119517SBill.Taylor@Sun.COM /* Allocate the transmit QP and CQs */
11129517SBill.Taylor@Sun.COM lstate.hls_err = HERMON_LOOPBACK_XMIT_SEND_CQ_ALLOC_FAIL;
11139517SBill.Taylor@Sun.COM if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_tx) != 0) {
11149517SBill.Taylor@Sun.COM lb.alb_error_type = lstate.hls_err;
11159517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11169517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11179517SBill.Taylor@Sun.COM return (EFAULT);
11189517SBill.Taylor@Sun.COM }
11199517SBill.Taylor@Sun.COM
11209517SBill.Taylor@Sun.COM /* Allocate the receive QP and CQs */
11219517SBill.Taylor@Sun.COM lstate.hls_err = HERMON_LOOPBACK_RECV_SEND_CQ_ALLOC_FAIL;
11229517SBill.Taylor@Sun.COM if (hermon_loopback_alloc_qps(&lstate, &lstate.hls_rx) != 0) {
11239517SBill.Taylor@Sun.COM lb.alb_error_type = lstate.hls_err;
11249517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11259517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11269517SBill.Taylor@Sun.COM return (EFAULT);
11279517SBill.Taylor@Sun.COM }
11289517SBill.Taylor@Sun.COM
11299517SBill.Taylor@Sun.COM /* Activate the TX QP (connect to RX QP) */
11309517SBill.Taylor@Sun.COM lstate.hls_err = HERMON_LOOPBACK_XMIT_QP_INIT_FAIL;
11319517SBill.Taylor@Sun.COM if (hermon_loopback_modify_qp(&lstate, &lstate.hls_tx,
11329517SBill.Taylor@Sun.COM lstate.hls_rx.hlc_qp_num) != 0) {
11339517SBill.Taylor@Sun.COM lb.alb_error_type = lstate.hls_err;
11349517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11359517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11369517SBill.Taylor@Sun.COM return (EFAULT);
11379517SBill.Taylor@Sun.COM }
11389517SBill.Taylor@Sun.COM
11399517SBill.Taylor@Sun.COM /* Activate the RX QP (connect to TX QP) */
11409517SBill.Taylor@Sun.COM lstate.hls_err = HERMON_LOOPBACK_RECV_QP_INIT_FAIL;
11419517SBill.Taylor@Sun.COM if (hermon_loopback_modify_qp(&lstate, &lstate.hls_rx,
11429517SBill.Taylor@Sun.COM lstate.hls_tx.hlc_qp_num) != 0) {
11439517SBill.Taylor@Sun.COM lb.alb_error_type = lstate.hls_err;
11449517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11459517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11469517SBill.Taylor@Sun.COM return (EFAULT);
11479517SBill.Taylor@Sun.COM }
11489517SBill.Taylor@Sun.COM
11499517SBill.Taylor@Sun.COM /* Run the loopback test (for specified number of iterations) */
11509517SBill.Taylor@Sun.COM lb.alb_pass_done = 0;
11519517SBill.Taylor@Sun.COM for (iter = 0; iter < lb.alb_num_iter; iter++) {
11529517SBill.Taylor@Sun.COM lstate.hls_err = 0;
11539517SBill.Taylor@Sun.COM bzero(lstate.hls_rx.hlc_buf, lb.alb_buf_sz);
11549517SBill.Taylor@Sun.COM
11559517SBill.Taylor@Sun.COM /* Post RDMA Write work request */
11569517SBill.Taylor@Sun.COM if (hermon_loopback_post_send(&lstate, &lstate.hls_tx,
11579517SBill.Taylor@Sun.COM &lstate.hls_rx) != IBT_SUCCESS) {
11589517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_WQE_POST_FAIL;
11599517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11609517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11619517SBill.Taylor@Sun.COM return (EFAULT);
11629517SBill.Taylor@Sun.COM }
11639517SBill.Taylor@Sun.COM
11649517SBill.Taylor@Sun.COM /* Poll the TX CQ for a completion every few ticks */
11659517SBill.Taylor@Sun.COM for (j = 0; j < loopmax; j++) {
11669517SBill.Taylor@Sun.COM delay(drv_usectohz(HERMON_VTS_LOOPBACK_MIN_WAIT_DUR));
11679517SBill.Taylor@Sun.COM
11689517SBill.Taylor@Sun.COM ret = hermon_loopback_poll_cq(&lstate, &lstate.hls_tx);
11699517SBill.Taylor@Sun.COM if (((ret != IBT_SUCCESS) && (ret != IBT_CQ_EMPTY)) ||
11709517SBill.Taylor@Sun.COM ((ret == IBT_CQ_EMPTY) && (j == loopmax - 1))) {
11719517SBill.Taylor@Sun.COM lb.alb_error_type =
11729517SBill.Taylor@Sun.COM HERMON_LOOPBACK_CQ_POLL_FAIL;
11739517SBill.Taylor@Sun.COM if (ddi_copyout(lstate.hls_rx.hlc_buf,
11749517SBill.Taylor@Sun.COM lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11759517SBill.Taylor@Sun.COM mode) != 0) {
11769517SBill.Taylor@Sun.COM return (EFAULT);
11779517SBill.Taylor@Sun.COM }
11789517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11799517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11809517SBill.Taylor@Sun.COM return (EFAULT);
11819517SBill.Taylor@Sun.COM } else if (ret == IBT_CQ_EMPTY) {
11829517SBill.Taylor@Sun.COM continue;
11839517SBill.Taylor@Sun.COM }
11849517SBill.Taylor@Sun.COM
11859517SBill.Taylor@Sun.COM /* Compare the data buffers */
11869517SBill.Taylor@Sun.COM if (bcmp(lstate.hls_tx.hlc_buf, lstate.hls_rx.hlc_buf,
11879517SBill.Taylor@Sun.COM lb.alb_buf_sz) == 0) {
11889517SBill.Taylor@Sun.COM break;
11899517SBill.Taylor@Sun.COM } else {
11909517SBill.Taylor@Sun.COM lb.alb_error_type =
11919517SBill.Taylor@Sun.COM HERMON_LOOPBACK_SEND_RECV_COMPARE_FAIL;
11929517SBill.Taylor@Sun.COM if (ddi_copyout(lstate.hls_rx.hlc_buf,
11939517SBill.Taylor@Sun.COM lb.alb_fail_buf, lstate.hls_tx.hlc_buf_sz,
11949517SBill.Taylor@Sun.COM mode) != 0) {
11959517SBill.Taylor@Sun.COM return (EFAULT);
11969517SBill.Taylor@Sun.COM }
11979517SBill.Taylor@Sun.COM (void) hermon_loopback_copyout(&lb, arg, mode);
11989517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
11999517SBill.Taylor@Sun.COM return (EFAULT);
12009517SBill.Taylor@Sun.COM }
12019517SBill.Taylor@Sun.COM }
12029517SBill.Taylor@Sun.COM
12039517SBill.Taylor@Sun.COM lstate.hls_err = HERMON_LOOPBACK_SUCCESS;
12049517SBill.Taylor@Sun.COM lb.alb_pass_done = iter + 1;
12059517SBill.Taylor@Sun.COM }
12069517SBill.Taylor@Sun.COM
12079517SBill.Taylor@Sun.COM lb.alb_error_type = HERMON_LOOPBACK_SUCCESS;
12089517SBill.Taylor@Sun.COM
12099517SBill.Taylor@Sun.COM /* Copy ioctl results back to user struct */
12109517SBill.Taylor@Sun.COM ret = hermon_loopback_copyout(&lb, arg, mode);
12119517SBill.Taylor@Sun.COM
12129517SBill.Taylor@Sun.COM /* Free up everything and release all consumed resources */
12139517SBill.Taylor@Sun.COM hermon_loopback_free_state(&lstate);
12149517SBill.Taylor@Sun.COM
12159517SBill.Taylor@Sun.COM return (ret);
12169517SBill.Taylor@Sun.COM }
12179517SBill.Taylor@Sun.COM
12189517SBill.Taylor@Sun.COM #ifdef DEBUG
12199517SBill.Taylor@Sun.COM /*
12209517SBill.Taylor@Sun.COM * hermon_ioctl_reg_read()
12219517SBill.Taylor@Sun.COM */
12229517SBill.Taylor@Sun.COM static int
hermon_ioctl_reg_read(hermon_state_t * state,intptr_t arg,int mode)12239517SBill.Taylor@Sun.COM hermon_ioctl_reg_read(hermon_state_t *state, intptr_t arg, int mode)
12249517SBill.Taylor@Sun.COM {
12259517SBill.Taylor@Sun.COM hermon_reg_ioctl_t rdreg;
12269517SBill.Taylor@Sun.COM uint32_t *addr;
12279517SBill.Taylor@Sun.COM uintptr_t baseaddr;
12289517SBill.Taylor@Sun.COM int status;
12299517SBill.Taylor@Sun.COM ddi_acc_handle_t handle;
12309517SBill.Taylor@Sun.COM
12319517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
12329517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
12339517SBill.Taylor@Sun.COM
12349517SBill.Taylor@Sun.COM /*
12359517SBill.Taylor@Sun.COM * Access to Hemron registers is not allowed in "maintenance mode".
12369517SBill.Taylor@Sun.COM * This is primarily because the device may not have BARs to access
12379517SBill.Taylor@Sun.COM */
12389517SBill.Taylor@Sun.COM if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
12399517SBill.Taylor@Sun.COM return (EFAULT);
12409517SBill.Taylor@Sun.COM }
12419517SBill.Taylor@Sun.COM
12429517SBill.Taylor@Sun.COM /* Copy in the hermon_reg_ioctl_t structure */
12439517SBill.Taylor@Sun.COM status = ddi_copyin((void *)arg, &rdreg, sizeof (hermon_reg_ioctl_t),
12449517SBill.Taylor@Sun.COM mode);
12459517SBill.Taylor@Sun.COM if (status != 0) {
12469517SBill.Taylor@Sun.COM return (EFAULT);
12479517SBill.Taylor@Sun.COM }
12489517SBill.Taylor@Sun.COM
12499517SBill.Taylor@Sun.COM /* Determine base address for requested register set */
12509517SBill.Taylor@Sun.COM switch (rdreg.arg_reg_set) {
12519517SBill.Taylor@Sun.COM case HERMON_CMD_BAR:
12529517SBill.Taylor@Sun.COM baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
12539517SBill.Taylor@Sun.COM handle = hermon_get_cmdhdl(state);
12549517SBill.Taylor@Sun.COM break;
12559517SBill.Taylor@Sun.COM
12569517SBill.Taylor@Sun.COM case HERMON_UAR_BAR:
12579517SBill.Taylor@Sun.COM baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
12589517SBill.Taylor@Sun.COM handle = hermon_get_uarhdl(state);
12599517SBill.Taylor@Sun.COM break;
12609517SBill.Taylor@Sun.COM
12619517SBill.Taylor@Sun.COM
12629517SBill.Taylor@Sun.COM default:
12639517SBill.Taylor@Sun.COM return (EINVAL);
12649517SBill.Taylor@Sun.COM }
12659517SBill.Taylor@Sun.COM
12669517SBill.Taylor@Sun.COM /* Ensure that address is properly-aligned */
12679517SBill.Taylor@Sun.COM addr = (uint32_t *)((baseaddr + rdreg.arg_offset) & ~0x3);
12689517SBill.Taylor@Sun.COM
12699517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
12709517SBill.Taylor@Sun.COM hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
12719517SBill.Taylor@Sun.COM fm_status, fm_test);
12729517SBill.Taylor@Sun.COM
12739517SBill.Taylor@Sun.COM /* Read the register pointed to by addr */
12749517SBill.Taylor@Sun.COM rdreg.arg_data = ddi_get32(handle, addr);
12759517SBill.Taylor@Sun.COM
12769517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
12779517SBill.Taylor@Sun.COM hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
12789517SBill.Taylor@Sun.COM fm_test);
12799517SBill.Taylor@Sun.COM
12809517SBill.Taylor@Sun.COM /* Copy in the result into the hermon_reg_ioctl_t structure */
12819517SBill.Taylor@Sun.COM status = ddi_copyout(&rdreg, (void *)arg, sizeof (hermon_reg_ioctl_t),
12829517SBill.Taylor@Sun.COM mode);
12839517SBill.Taylor@Sun.COM if (status != 0) {
12849517SBill.Taylor@Sun.COM return (EFAULT);
12859517SBill.Taylor@Sun.COM }
12869517SBill.Taylor@Sun.COM return (0);
12879517SBill.Taylor@Sun.COM
12889517SBill.Taylor@Sun.COM pio_error:
12899517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
12909517SBill.Taylor@Sun.COM return (EIO);
12919517SBill.Taylor@Sun.COM }
12929517SBill.Taylor@Sun.COM
12939517SBill.Taylor@Sun.COM
12949517SBill.Taylor@Sun.COM /*
12959517SBill.Taylor@Sun.COM * hermon_ioctl_reg_write()
12969517SBill.Taylor@Sun.COM */
12979517SBill.Taylor@Sun.COM static int
hermon_ioctl_reg_write(hermon_state_t * state,intptr_t arg,int mode)12989517SBill.Taylor@Sun.COM hermon_ioctl_reg_write(hermon_state_t *state, intptr_t arg, int mode)
12999517SBill.Taylor@Sun.COM {
13009517SBill.Taylor@Sun.COM hermon_reg_ioctl_t wrreg;
13019517SBill.Taylor@Sun.COM uint32_t *addr;
13029517SBill.Taylor@Sun.COM uintptr_t baseaddr;
13039517SBill.Taylor@Sun.COM int status;
13049517SBill.Taylor@Sun.COM ddi_acc_handle_t handle;
13059517SBill.Taylor@Sun.COM
13069517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
13079517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13089517SBill.Taylor@Sun.COM
13099517SBill.Taylor@Sun.COM /*
13109517SBill.Taylor@Sun.COM * Access to Hermon registers is not allowed in "maintenance mode".
13119517SBill.Taylor@Sun.COM * This is primarily because the device may not have BARs to access
13129517SBill.Taylor@Sun.COM */
13139517SBill.Taylor@Sun.COM if (state->hs_operational_mode == HERMON_MAINTENANCE_MODE) {
13149517SBill.Taylor@Sun.COM return (EFAULT);
13159517SBill.Taylor@Sun.COM }
13169517SBill.Taylor@Sun.COM
13179517SBill.Taylor@Sun.COM /* Copy in the hermon_reg_ioctl_t structure */
13189517SBill.Taylor@Sun.COM status = ddi_copyin((void *)arg, &wrreg, sizeof (hermon_reg_ioctl_t),
13199517SBill.Taylor@Sun.COM mode);
13209517SBill.Taylor@Sun.COM if (status != 0) {
13219517SBill.Taylor@Sun.COM return (EFAULT);
13229517SBill.Taylor@Sun.COM }
13239517SBill.Taylor@Sun.COM
13249517SBill.Taylor@Sun.COM /* Determine base address for requested register set */
13259517SBill.Taylor@Sun.COM switch (wrreg.arg_reg_set) {
13269517SBill.Taylor@Sun.COM case HERMON_CMD_BAR:
13279517SBill.Taylor@Sun.COM baseaddr = (uintptr_t)state->hs_reg_cmd_baseaddr;
13289517SBill.Taylor@Sun.COM handle = hermon_get_cmdhdl(state);
13299517SBill.Taylor@Sun.COM break;
13309517SBill.Taylor@Sun.COM
13319517SBill.Taylor@Sun.COM case HERMON_UAR_BAR:
13329517SBill.Taylor@Sun.COM baseaddr = (uintptr_t)state->hs_reg_uar_baseaddr;
13339517SBill.Taylor@Sun.COM handle = hermon_get_uarhdl(state);
13349517SBill.Taylor@Sun.COM break;
13359517SBill.Taylor@Sun.COM
13369517SBill.Taylor@Sun.COM default:
13379517SBill.Taylor@Sun.COM return (EINVAL);
13389517SBill.Taylor@Sun.COM }
13399517SBill.Taylor@Sun.COM
13409517SBill.Taylor@Sun.COM /* Ensure that address is properly-aligned */
13419517SBill.Taylor@Sun.COM addr = (uint32_t *)((baseaddr + wrreg.arg_offset) & ~0x3);
13429517SBill.Taylor@Sun.COM
13439517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
13449517SBill.Taylor@Sun.COM hermon_pio_start(state, handle, pio_error, fm_loop_cnt,
13459517SBill.Taylor@Sun.COM fm_status, fm_test);
13469517SBill.Taylor@Sun.COM
13479517SBill.Taylor@Sun.COM /* Write the data to the register pointed to by addr */
13489517SBill.Taylor@Sun.COM ddi_put32(handle, addr, wrreg.arg_data);
13499517SBill.Taylor@Sun.COM
13509517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
13519517SBill.Taylor@Sun.COM hermon_pio_end(state, handle, pio_error, fm_loop_cnt, fm_status,
13529517SBill.Taylor@Sun.COM fm_test);
13539517SBill.Taylor@Sun.COM return (0);
13549517SBill.Taylor@Sun.COM
13559517SBill.Taylor@Sun.COM pio_error:
13569517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
13579517SBill.Taylor@Sun.COM return (EIO);
13589517SBill.Taylor@Sun.COM }
13599517SBill.Taylor@Sun.COM #endif /* DEBUG */
13609517SBill.Taylor@Sun.COM
13619517SBill.Taylor@Sun.COM static int
hermon_ioctl_write_boot_addr(hermon_state_t * state,dev_t dev,intptr_t arg,int mode)13629517SBill.Taylor@Sun.COM hermon_ioctl_write_boot_addr(hermon_state_t *state, dev_t dev, intptr_t arg,
13639517SBill.Taylor@Sun.COM int mode)
13649517SBill.Taylor@Sun.COM {
13659517SBill.Taylor@Sun.COM hermon_flash_ioctl_t ioctl_info;
13669517SBill.Taylor@Sun.COM
13679517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
13689517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
13699517SBill.Taylor@Sun.COM
13709517SBill.Taylor@Sun.COM /*
13719517SBill.Taylor@Sun.COM * Check that flash init ioctl has been called first. And check
13729517SBill.Taylor@Sun.COM * that the same dev_t that called init is the one calling write now.
13739517SBill.Taylor@Sun.COM */
13749517SBill.Taylor@Sun.COM mutex_enter(&state->hs_fw_flashlock);
13759517SBill.Taylor@Sun.COM if ((state->hs_fw_flashdev != dev) ||
13769517SBill.Taylor@Sun.COM (state->hs_fw_flashstarted == 0)) {
13779517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
13789517SBill.Taylor@Sun.COM return (EIO);
13799517SBill.Taylor@Sun.COM }
13809517SBill.Taylor@Sun.COM
13819517SBill.Taylor@Sun.COM /* copy user struct to kernel */
13829517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
13839517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
13849517SBill.Taylor@Sun.COM hermon_flash_ioctl32_t info32;
13859517SBill.Taylor@Sun.COM
13869517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &info32,
13879517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl32_t), mode) != 0) {
13889517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
13899517SBill.Taylor@Sun.COM return (EFAULT);
13909517SBill.Taylor@Sun.COM }
13919517SBill.Taylor@Sun.COM ioctl_info.af_type = info32.af_type;
13929517SBill.Taylor@Sun.COM ioctl_info.af_sector = (caddr_t)(uintptr_t)info32.af_sector;
13939517SBill.Taylor@Sun.COM ioctl_info.af_sector_num = info32.af_sector_num;
13949517SBill.Taylor@Sun.COM ioctl_info.af_addr = info32.af_addr;
13959517SBill.Taylor@Sun.COM ioctl_info.af_byte = info32.af_byte;
13969517SBill.Taylor@Sun.COM } else
13979517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
13989517SBill.Taylor@Sun.COM if (ddi_copyin((void *)arg, &ioctl_info,
13999517SBill.Taylor@Sun.COM sizeof (hermon_flash_ioctl_t), mode) != 0) {
14009517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
14019517SBill.Taylor@Sun.COM return (EFAULT);
14029517SBill.Taylor@Sun.COM }
14039517SBill.Taylor@Sun.COM
14049517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
14059517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
14069517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
14079517SBill.Taylor@Sun.COM break;
14089517SBill.Taylor@Sun.COM
14099517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
14109517SBill.Taylor@Sun.COM {
14119517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_hdl = hermon_get_pcihdl(state);
14129517SBill.Taylor@Sun.COM
14139517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
14149517SBill.Taylor@Sun.COM hermon_pio_start(state, pci_hdl, pio_error,
14159517SBill.Taylor@Sun.COM fm_loop_cnt, fm_status, fm_test);
14169517SBill.Taylor@Sun.COM
14179517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, pci_hdl,
14189517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_BOOT_ADDR_REG,
14199517SBill.Taylor@Sun.COM (ioctl_info.af_addr << 8) | 0x06);
14209517SBill.Taylor@Sun.COM
14219517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
14229517SBill.Taylor@Sun.COM hermon_pio_end(state, pci_hdl, pio_error,
14239517SBill.Taylor@Sun.COM fm_loop_cnt, fm_status, fm_test);
14249517SBill.Taylor@Sun.COM break;
14259517SBill.Taylor@Sun.COM }
14269517SBill.Taylor@Sun.COM
14279517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
14289517SBill.Taylor@Sun.COM default:
14299517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
14309517SBill.Taylor@Sun.COM return (EINVAL);
14319517SBill.Taylor@Sun.COM }
14329517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
14339517SBill.Taylor@Sun.COM return (0);
14349517SBill.Taylor@Sun.COM
14359517SBill.Taylor@Sun.COM pio_error:
14369517SBill.Taylor@Sun.COM mutex_exit(&state->hs_fw_flashlock);
14379517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
14389517SBill.Taylor@Sun.COM return (EIO);
14399517SBill.Taylor@Sun.COM }
14409517SBill.Taylor@Sun.COM
14419517SBill.Taylor@Sun.COM /*
14429517SBill.Taylor@Sun.COM * hermon_flash_reset()
14439517SBill.Taylor@Sun.COM */
14449517SBill.Taylor@Sun.COM static int
hermon_flash_reset(hermon_state_t * state)14459517SBill.Taylor@Sun.COM hermon_flash_reset(hermon_state_t *state)
14469517SBill.Taylor@Sun.COM {
14479517SBill.Taylor@Sun.COM int status;
14489517SBill.Taylor@Sun.COM
14499517SBill.Taylor@Sun.COM /*
14509517SBill.Taylor@Sun.COM * Performs a reset to the flash device. After a reset the flash will
14519517SBill.Taylor@Sun.COM * be operating in normal mode (capable of read/write, etc.).
14529517SBill.Taylor@Sun.COM */
14539517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
14549517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
14559517SBill.Taylor@Sun.COM hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_AMD,
14569517SBill.Taylor@Sun.COM &status);
14579517SBill.Taylor@Sun.COM if (status != 0) {
14589517SBill.Taylor@Sun.COM return (status);
14599517SBill.Taylor@Sun.COM }
14609517SBill.Taylor@Sun.COM break;
14619517SBill.Taylor@Sun.COM
14629517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
14639517SBill.Taylor@Sun.COM hermon_flash_write(state, 0x555, HERMON_HW_FLASH_RESET_INTEL,
14649517SBill.Taylor@Sun.COM &status);
14659517SBill.Taylor@Sun.COM if (status != 0) {
14669517SBill.Taylor@Sun.COM return (status);
14679517SBill.Taylor@Sun.COM }
14689517SBill.Taylor@Sun.COM break;
14699517SBill.Taylor@Sun.COM
14709517SBill.Taylor@Sun.COM /* It appears no reset is needed for SPI */
14719517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
14729517SBill.Taylor@Sun.COM status = 0;
14739517SBill.Taylor@Sun.COM break;
14749517SBill.Taylor@Sun.COM
14759517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
14769517SBill.Taylor@Sun.COM default:
14779517SBill.Taylor@Sun.COM status = EINVAL;
14789517SBill.Taylor@Sun.COM break;
14799517SBill.Taylor@Sun.COM }
14809517SBill.Taylor@Sun.COM return (status);
14819517SBill.Taylor@Sun.COM }
14829517SBill.Taylor@Sun.COM
14839517SBill.Taylor@Sun.COM /*
14849517SBill.Taylor@Sun.COM * hermon_flash_read_sector()
14859517SBill.Taylor@Sun.COM */
14869517SBill.Taylor@Sun.COM static int
hermon_flash_read_sector(hermon_state_t * state,uint32_t sector_num)14879517SBill.Taylor@Sun.COM hermon_flash_read_sector(hermon_state_t *state, uint32_t sector_num)
14889517SBill.Taylor@Sun.COM {
14899517SBill.Taylor@Sun.COM uint32_t addr;
14909517SBill.Taylor@Sun.COM uint32_t end_addr;
14919517SBill.Taylor@Sun.COM uint32_t *image;
14929517SBill.Taylor@Sun.COM int i, status;
14939517SBill.Taylor@Sun.COM
14949517SBill.Taylor@Sun.COM image = (uint32_t *)&state->hs_fw_sector[0];
14959517SBill.Taylor@Sun.COM
14969517SBill.Taylor@Sun.COM /*
14979517SBill.Taylor@Sun.COM * Calculate the start and end address of the sector, based on the
14989517SBill.Taylor@Sun.COM * sector number passed in.
14999517SBill.Taylor@Sun.COM */
15009517SBill.Taylor@Sun.COM addr = sector_num << state->hs_fw_log_sector_sz;
15019517SBill.Taylor@Sun.COM end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15029517SBill.Taylor@Sun.COM
15039517SBill.Taylor@Sun.COM /* Set the flash bank correctly for the given address */
15049517SBill.Taylor@Sun.COM if ((status = hermon_flash_bank(state, addr)) != 0)
15059517SBill.Taylor@Sun.COM return (status);
15069517SBill.Taylor@Sun.COM
15079517SBill.Taylor@Sun.COM /* Read the entire sector, one quadlet at a time */
15089517SBill.Taylor@Sun.COM for (i = 0; addr < end_addr; i++, addr += 4) {
15099517SBill.Taylor@Sun.COM image[i] = hermon_flash_read(state, addr, &status);
15109517SBill.Taylor@Sun.COM if (status != 0) {
15119517SBill.Taylor@Sun.COM return (status);
15129517SBill.Taylor@Sun.COM }
15139517SBill.Taylor@Sun.COM }
15149517SBill.Taylor@Sun.COM return (0);
15159517SBill.Taylor@Sun.COM }
15169517SBill.Taylor@Sun.COM
15179517SBill.Taylor@Sun.COM /*
15189517SBill.Taylor@Sun.COM * hermon_flash_read_quadlet()
15199517SBill.Taylor@Sun.COM */
15209517SBill.Taylor@Sun.COM static int
hermon_flash_read_quadlet(hermon_state_t * state,uint32_t * data,uint32_t addr)15219517SBill.Taylor@Sun.COM hermon_flash_read_quadlet(hermon_state_t *state, uint32_t *data,
15229517SBill.Taylor@Sun.COM uint32_t addr)
15239517SBill.Taylor@Sun.COM {
15249517SBill.Taylor@Sun.COM int status;
15259517SBill.Taylor@Sun.COM
15269517SBill.Taylor@Sun.COM /* Set the flash bank correctly for the given address */
15279517SBill.Taylor@Sun.COM if ((status = hermon_flash_bank(state, addr)) != 0) {
15289517SBill.Taylor@Sun.COM return (status);
15299517SBill.Taylor@Sun.COM }
15309517SBill.Taylor@Sun.COM
15319517SBill.Taylor@Sun.COM /* Read one quadlet of data */
15329517SBill.Taylor@Sun.COM *data = hermon_flash_read(state, addr, &status);
15339517SBill.Taylor@Sun.COM if (status != 0) {
15349517SBill.Taylor@Sun.COM return (EIO);
15359517SBill.Taylor@Sun.COM }
15369517SBill.Taylor@Sun.COM
15379517SBill.Taylor@Sun.COM return (0);
15389517SBill.Taylor@Sun.COM }
15399517SBill.Taylor@Sun.COM
15409517SBill.Taylor@Sun.COM /*
15419517SBill.Taylor@Sun.COM * hermon_flash_write_sector()
15429517SBill.Taylor@Sun.COM */
15439517SBill.Taylor@Sun.COM static int
hermon_flash_write_sector(hermon_state_t * state,uint32_t sector_num)15449517SBill.Taylor@Sun.COM hermon_flash_write_sector(hermon_state_t *state, uint32_t sector_num)
15459517SBill.Taylor@Sun.COM {
15469517SBill.Taylor@Sun.COM uint32_t addr;
15479517SBill.Taylor@Sun.COM uint32_t end_addr;
15489517SBill.Taylor@Sun.COM uint32_t *databuf;
15499517SBill.Taylor@Sun.COM uchar_t *sector;
15509517SBill.Taylor@Sun.COM int status = 0;
15519517SBill.Taylor@Sun.COM int i;
15529517SBill.Taylor@Sun.COM
15539517SBill.Taylor@Sun.COM sector = (uchar_t *)&state->hs_fw_sector[0];
15549517SBill.Taylor@Sun.COM
15559517SBill.Taylor@Sun.COM /*
15569517SBill.Taylor@Sun.COM * Calculate the start and end address of the sector, based on the
15579517SBill.Taylor@Sun.COM * sector number passed in.
15589517SBill.Taylor@Sun.COM */
15599517SBill.Taylor@Sun.COM addr = sector_num << state->hs_fw_log_sector_sz;
15609517SBill.Taylor@Sun.COM end_addr = addr + (1 << state->hs_fw_log_sector_sz);
15619517SBill.Taylor@Sun.COM
15629517SBill.Taylor@Sun.COM /* Set the flash bank correctly for the given address */
15639517SBill.Taylor@Sun.COM if ((status = hermon_flash_bank(state, addr)) != 0 ||
15649517SBill.Taylor@Sun.COM (status = hermon_flash_reset(state)) != 0) {
15659517SBill.Taylor@Sun.COM return (status);
15669517SBill.Taylor@Sun.COM }
15679517SBill.Taylor@Sun.COM
15689517SBill.Taylor@Sun.COM /* Erase the sector before writing */
15699517SBill.Taylor@Sun.COM status = hermon_flash_erase_sector(state, sector_num);
15709517SBill.Taylor@Sun.COM if (status != 0) {
15719517SBill.Taylor@Sun.COM return (status);
15729517SBill.Taylor@Sun.COM }
15739517SBill.Taylor@Sun.COM
15749517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
15759517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
15769517SBill.Taylor@Sun.COM databuf = (uint32_t *)(void *)sector;
15779517SBill.Taylor@Sun.COM /* Write the sector, one dword at a time */
15789517SBill.Taylor@Sun.COM for (i = 0; addr < end_addr; i++, addr += 4) {
15799517SBill.Taylor@Sun.COM if ((status = hermon_flash_spi_write_dword(state, addr,
15809517SBill.Taylor@Sun.COM htonl(databuf[i]))) != 0) {
15819517SBill.Taylor@Sun.COM return (status);
15829517SBill.Taylor@Sun.COM }
15839517SBill.Taylor@Sun.COM }
15849517SBill.Taylor@Sun.COM status = hermon_flash_reset(state);
15859517SBill.Taylor@Sun.COM break;
15869517SBill.Taylor@Sun.COM
15879517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
15889517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
15899517SBill.Taylor@Sun.COM /* Write the sector, one byte at a time */
15909517SBill.Taylor@Sun.COM for (i = 0; addr < end_addr; i++, addr++) {
15919517SBill.Taylor@Sun.COM status = hermon_flash_write_byte(state, addr,
15929517SBill.Taylor@Sun.COM sector[i]);
15939517SBill.Taylor@Sun.COM if (status != 0) {
15949517SBill.Taylor@Sun.COM break;
15959517SBill.Taylor@Sun.COM }
15969517SBill.Taylor@Sun.COM }
15979517SBill.Taylor@Sun.COM status = hermon_flash_reset(state);
15989517SBill.Taylor@Sun.COM break;
15999517SBill.Taylor@Sun.COM
16009517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
16019517SBill.Taylor@Sun.COM default:
16029517SBill.Taylor@Sun.COM status = EINVAL;
16039517SBill.Taylor@Sun.COM break;
16049517SBill.Taylor@Sun.COM }
16059517SBill.Taylor@Sun.COM
16069517SBill.Taylor@Sun.COM return (status);
16079517SBill.Taylor@Sun.COM }
16089517SBill.Taylor@Sun.COM
16099517SBill.Taylor@Sun.COM /*
16109517SBill.Taylor@Sun.COM * hermon_flash_spi_write_dword()
16119517SBill.Taylor@Sun.COM *
16129517SBill.Taylor@Sun.COM * NOTE: This function assumes that "data" is in network byte order.
16139517SBill.Taylor@Sun.COM *
16149517SBill.Taylor@Sun.COM */
16159517SBill.Taylor@Sun.COM static int
hermon_flash_spi_write_dword(hermon_state_t * state,uint32_t addr,uint32_t data)16169517SBill.Taylor@Sun.COM hermon_flash_spi_write_dword(hermon_state_t *state, uint32_t addr,
16179517SBill.Taylor@Sun.COM uint32_t data)
16189517SBill.Taylor@Sun.COM {
16199517SBill.Taylor@Sun.COM int status;
16209517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
16219517SBill.Taylor@Sun.COM
16229517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
16239517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
16249517SBill.Taylor@Sun.COM
16259517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
16269517SBill.Taylor@Sun.COM
16279517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
16289517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
16299517SBill.Taylor@Sun.COM fm_test);
16309517SBill.Taylor@Sun.COM
16319517SBill.Taylor@Sun.COM /* Issue Write Enable */
16329517SBill.Taylor@Sun.COM hermon_flash_spi_write_enable(state);
16339517SBill.Taylor@Sun.COM
16349517SBill.Taylor@Sun.COM /* Set the Address */
16359517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
16369517SBill.Taylor@Sun.COM addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
16379517SBill.Taylor@Sun.COM
16389517SBill.Taylor@Sun.COM /* Set the Data */
16399517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_DATA, data);
16409517SBill.Taylor@Sun.COM
16419517SBill.Taylor@Sun.COM /* Set the Page Program and execute */
16429517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(state, hdl,
16439517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
16449517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
16459517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
16469517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
16479517SBill.Taylor@Sun.COM (HERMON_HW_FLASH_SPI_PAGE_PROGRAM <<
16489517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_SHIFT));
16499517SBill.Taylor@Sun.COM
16509517SBill.Taylor@Sun.COM /* Wait for write to complete */
16519517SBill.Taylor@Sun.COM if ((status = hermon_flash_spi_wait_wip(state)) != 0) {
16529517SBill.Taylor@Sun.COM return (status);
16539517SBill.Taylor@Sun.COM }
16549517SBill.Taylor@Sun.COM
16559517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
16569517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
16579517SBill.Taylor@Sun.COM return (0);
16589517SBill.Taylor@Sun.COM
16599517SBill.Taylor@Sun.COM pio_error:
16609517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
16619517SBill.Taylor@Sun.COM return (EIO);
16629517SBill.Taylor@Sun.COM }
16639517SBill.Taylor@Sun.COM
16649517SBill.Taylor@Sun.COM /*
16659517SBill.Taylor@Sun.COM * hermon_flash_write_byte()
16669517SBill.Taylor@Sun.COM */
16679517SBill.Taylor@Sun.COM static int
hermon_flash_write_byte(hermon_state_t * state,uint32_t addr,uchar_t data)16689517SBill.Taylor@Sun.COM hermon_flash_write_byte(hermon_state_t *state, uint32_t addr, uchar_t data)
16699517SBill.Taylor@Sun.COM {
16709517SBill.Taylor@Sun.COM uint32_t stat;
16719517SBill.Taylor@Sun.COM int status = 0;
16729517SBill.Taylor@Sun.COM int dword_addr;
16739517SBill.Taylor@Sun.COM int byte_offset;
16749517SBill.Taylor@Sun.COM int i;
16759517SBill.Taylor@Sun.COM union {
16769517SBill.Taylor@Sun.COM uint8_t bytes[4];
16779517SBill.Taylor@Sun.COM uint32_t dword;
16789517SBill.Taylor@Sun.COM } dword;
16799517SBill.Taylor@Sun.COM
16809517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
16819517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
16829517SBill.Taylor@Sun.COM /* Issue Flash Byte program command */
16839517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0xAA, &status);
16849517SBill.Taylor@Sun.COM if (status != 0) {
16859517SBill.Taylor@Sun.COM return (status);
16869517SBill.Taylor@Sun.COM }
16879517SBill.Taylor@Sun.COM
16889517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0x55, &status);
16899517SBill.Taylor@Sun.COM if (status != 0) {
16909517SBill.Taylor@Sun.COM return (status);
16919517SBill.Taylor@Sun.COM }
16929517SBill.Taylor@Sun.COM
16939517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0xA0, &status);
16949517SBill.Taylor@Sun.COM if (status != 0) {
16959517SBill.Taylor@Sun.COM return (status);
16969517SBill.Taylor@Sun.COM }
16979517SBill.Taylor@Sun.COM
16989517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, data, &status);
16999517SBill.Taylor@Sun.COM if (status != 0) {
17009517SBill.Taylor@Sun.COM return (status);
17019517SBill.Taylor@Sun.COM }
17029517SBill.Taylor@Sun.COM
17039517SBill.Taylor@Sun.COM /* Wait for Write Byte to Complete */
17049517SBill.Taylor@Sun.COM i = 0;
17059517SBill.Taylor@Sun.COM do {
17069517SBill.Taylor@Sun.COM drv_usecwait(1);
17079517SBill.Taylor@Sun.COM stat = hermon_flash_read(state, addr & ~3, &status);
17089517SBill.Taylor@Sun.COM if (status != 0) {
17099517SBill.Taylor@Sun.COM return (status);
17109517SBill.Taylor@Sun.COM }
17119517SBill.Taylor@Sun.COM
17129517SBill.Taylor@Sun.COM if (i == hermon_hw_flash_timeout_write) {
17139517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
17149517SBill.Taylor@Sun.COM "hermon_flash_write_byte: ACS write "
17159517SBill.Taylor@Sun.COM "timeout: addr: 0x%x, data: 0x%x\n",
17169517SBill.Taylor@Sun.COM addr, data);
17179517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
17189517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
17199517SBill.Taylor@Sun.COM return (EIO);
17209517SBill.Taylor@Sun.COM }
17219517SBill.Taylor@Sun.COM i++;
17229517SBill.Taylor@Sun.COM } while (data != ((stat >> ((3 - (addr & 3)) << 3)) & 0xFF));
17239517SBill.Taylor@Sun.COM
17249517SBill.Taylor@Sun.COM break;
17259517SBill.Taylor@Sun.COM
17269517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
17279517SBill.Taylor@Sun.COM /* Issue Flash Byte program command */
17289517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_WRITE,
17299517SBill.Taylor@Sun.COM &status);
17309517SBill.Taylor@Sun.COM if (status != 0) {
17319517SBill.Taylor@Sun.COM return (status);
17329517SBill.Taylor@Sun.COM }
17339517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, data, &status);
17349517SBill.Taylor@Sun.COM if (status != 0) {
17359517SBill.Taylor@Sun.COM return (status);
17369517SBill.Taylor@Sun.COM }
17379517SBill.Taylor@Sun.COM
17389517SBill.Taylor@Sun.COM /* Wait for Write Byte to Complete */
17399517SBill.Taylor@Sun.COM i = 0;
17409517SBill.Taylor@Sun.COM do {
17419517SBill.Taylor@Sun.COM drv_usecwait(1);
17429517SBill.Taylor@Sun.COM stat = hermon_flash_read(state, addr & ~3, &status);
17439517SBill.Taylor@Sun.COM if (status != 0) {
17449517SBill.Taylor@Sun.COM return (status);
17459517SBill.Taylor@Sun.COM }
17469517SBill.Taylor@Sun.COM
17479517SBill.Taylor@Sun.COM if (i == hermon_hw_flash_timeout_write) {
17489517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
17499517SBill.Taylor@Sun.COM "hermon_flash_write_byte: ICS write "
17509517SBill.Taylor@Sun.COM "timeout: addr: %x, data: %x\n",
17519517SBill.Taylor@Sun.COM addr, data);
17529517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
17539517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
17549517SBill.Taylor@Sun.COM return (EIO);
17559517SBill.Taylor@Sun.COM }
17569517SBill.Taylor@Sun.COM i++;
17579517SBill.Taylor@Sun.COM } while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
17589517SBill.Taylor@Sun.COM
17599517SBill.Taylor@Sun.COM if (stat & HERMON_HW_FLASH_ICS_ERROR) {
17609517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
17619517SBill.Taylor@Sun.COM "hermon_flash_write_byte: ICS write cmd error: "
17629517SBill.Taylor@Sun.COM "addr: %x, data: %x\n",
17639517SBill.Taylor@Sun.COM addr, data);
17649517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
17659517SBill.Taylor@Sun.COM return (EIO);
17669517SBill.Taylor@Sun.COM }
17679517SBill.Taylor@Sun.COM break;
17689517SBill.Taylor@Sun.COM
17699517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
17709517SBill.Taylor@Sun.COM /*
17719517SBill.Taylor@Sun.COM * Our lowest write granularity on SPI is a dword.
17729517SBill.Taylor@Sun.COM * To support this ioctl option, we can read in the
17739517SBill.Taylor@Sun.COM * dword that contains this byte, modify this byte,
17749517SBill.Taylor@Sun.COM * and write the dword back out.
17759517SBill.Taylor@Sun.COM */
17769517SBill.Taylor@Sun.COM
17779517SBill.Taylor@Sun.COM /* Determine dword offset and byte offset within the dword */
17789517SBill.Taylor@Sun.COM byte_offset = addr & 3;
17799517SBill.Taylor@Sun.COM dword_addr = addr - byte_offset;
17809517SBill.Taylor@Sun.COM #ifdef _LITTLE_ENDIAN
17819517SBill.Taylor@Sun.COM byte_offset = 3 - byte_offset;
17829517SBill.Taylor@Sun.COM #endif
17839517SBill.Taylor@Sun.COM
17849517SBill.Taylor@Sun.COM /* Read in dword */
17859517SBill.Taylor@Sun.COM if ((status = hermon_flash_read_quadlet(state, &dword.dword,
17869517SBill.Taylor@Sun.COM dword_addr)) != 0)
17879517SBill.Taylor@Sun.COM break;
17889517SBill.Taylor@Sun.COM
17899517SBill.Taylor@Sun.COM /* Set "data" to the appopriate byte */
17909517SBill.Taylor@Sun.COM dword.bytes[byte_offset] = data;
17919517SBill.Taylor@Sun.COM
17929517SBill.Taylor@Sun.COM /* Write modified dword back out */
17939517SBill.Taylor@Sun.COM status = hermon_flash_spi_write_dword(state, dword_addr,
17949517SBill.Taylor@Sun.COM dword.dword);
17959517SBill.Taylor@Sun.COM
17969517SBill.Taylor@Sun.COM break;
17979517SBill.Taylor@Sun.COM
17989517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
17999517SBill.Taylor@Sun.COM default:
18009517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
18019517SBill.Taylor@Sun.COM "hermon_flash_write_byte: unknown cmd set: 0x%x\n",
18029517SBill.Taylor@Sun.COM state->hs_fw_cmdset);
18039517SBill.Taylor@Sun.COM status = EINVAL;
18049517SBill.Taylor@Sun.COM break;
18059517SBill.Taylor@Sun.COM }
18069517SBill.Taylor@Sun.COM
18079517SBill.Taylor@Sun.COM return (status);
18089517SBill.Taylor@Sun.COM }
18099517SBill.Taylor@Sun.COM
18109517SBill.Taylor@Sun.COM /*
18119517SBill.Taylor@Sun.COM * hermon_flash_erase_sector()
18129517SBill.Taylor@Sun.COM */
18139517SBill.Taylor@Sun.COM static int
hermon_flash_erase_sector(hermon_state_t * state,uint32_t sector_num)18149517SBill.Taylor@Sun.COM hermon_flash_erase_sector(hermon_state_t *state, uint32_t sector_num)
18159517SBill.Taylor@Sun.COM {
18169517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
18179517SBill.Taylor@Sun.COM uint32_t addr;
18189517SBill.Taylor@Sun.COM uint32_t stat;
18199517SBill.Taylor@Sun.COM int status = 0;
18209517SBill.Taylor@Sun.COM int i;
18219517SBill.Taylor@Sun.COM
18229517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
18239517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
18249517SBill.Taylor@Sun.COM
18259517SBill.Taylor@Sun.COM /* Get address from sector num */
18269517SBill.Taylor@Sun.COM addr = sector_num << state->hs_fw_log_sector_sz;
18279517SBill.Taylor@Sun.COM
18289517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
18299517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
18309517SBill.Taylor@Sun.COM /* Issue Flash Sector Erase Command */
18319517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0xAA, &status);
18329517SBill.Taylor@Sun.COM if (status != 0) {
18339517SBill.Taylor@Sun.COM return (status);
18349517SBill.Taylor@Sun.COM }
18359517SBill.Taylor@Sun.COM
18369517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0x55, &status);
18379517SBill.Taylor@Sun.COM if (status != 0) {
18389517SBill.Taylor@Sun.COM return (status);
18399517SBill.Taylor@Sun.COM }
18409517SBill.Taylor@Sun.COM
18419517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0x80, &status);
18429517SBill.Taylor@Sun.COM if (status != 0) {
18439517SBill.Taylor@Sun.COM return (status);
18449517SBill.Taylor@Sun.COM }
18459517SBill.Taylor@Sun.COM
18469517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0xAA, &status);
18479517SBill.Taylor@Sun.COM if (status != 0) {
18489517SBill.Taylor@Sun.COM return (status);
18499517SBill.Taylor@Sun.COM }
18509517SBill.Taylor@Sun.COM
18519517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0x55, &status);
18529517SBill.Taylor@Sun.COM if (status != 0) {
18539517SBill.Taylor@Sun.COM return (status);
18549517SBill.Taylor@Sun.COM }
18559517SBill.Taylor@Sun.COM
18569517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, 0x30, &status);
18579517SBill.Taylor@Sun.COM if (status != 0) {
18589517SBill.Taylor@Sun.COM return (status);
18599517SBill.Taylor@Sun.COM }
18609517SBill.Taylor@Sun.COM
18619517SBill.Taylor@Sun.COM /* Wait for Sector Erase to complete */
18629517SBill.Taylor@Sun.COM i = 0;
18639517SBill.Taylor@Sun.COM do {
18649517SBill.Taylor@Sun.COM drv_usecwait(1);
18659517SBill.Taylor@Sun.COM stat = hermon_flash_read(state, addr, &status);
18669517SBill.Taylor@Sun.COM if (status != 0) {
18679517SBill.Taylor@Sun.COM return (status);
18689517SBill.Taylor@Sun.COM }
18699517SBill.Taylor@Sun.COM
18709517SBill.Taylor@Sun.COM if (i == hermon_hw_flash_timeout_erase) {
18719517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
18729517SBill.Taylor@Sun.COM "hermon_flash_erase_sector: "
18739517SBill.Taylor@Sun.COM "ACS erase timeout\n");
18749517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
18759517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
18769517SBill.Taylor@Sun.COM return (EIO);
18779517SBill.Taylor@Sun.COM }
18789517SBill.Taylor@Sun.COM i++;
18799517SBill.Taylor@Sun.COM } while (stat != 0xFFFFFFFF);
18809517SBill.Taylor@Sun.COM break;
18819517SBill.Taylor@Sun.COM
18829517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
18839517SBill.Taylor@Sun.COM /* Issue Flash Sector Erase Command */
18849517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_ERASE,
18859517SBill.Taylor@Sun.COM &status);
18869517SBill.Taylor@Sun.COM if (status != 0) {
18879517SBill.Taylor@Sun.COM return (status);
18889517SBill.Taylor@Sun.COM }
18899517SBill.Taylor@Sun.COM
18909517SBill.Taylor@Sun.COM hermon_flash_write(state, addr, HERMON_HW_FLASH_ICS_CONFIRM,
18919517SBill.Taylor@Sun.COM &status);
18929517SBill.Taylor@Sun.COM if (status != 0) {
18939517SBill.Taylor@Sun.COM return (status);
18949517SBill.Taylor@Sun.COM }
18959517SBill.Taylor@Sun.COM
18969517SBill.Taylor@Sun.COM /* Wait for Sector Erase to complete */
18979517SBill.Taylor@Sun.COM i = 0;
18989517SBill.Taylor@Sun.COM do {
18999517SBill.Taylor@Sun.COM drv_usecwait(1);
19009517SBill.Taylor@Sun.COM stat = hermon_flash_read(state, addr & ~3, &status);
19019517SBill.Taylor@Sun.COM if (status != 0) {
19029517SBill.Taylor@Sun.COM return (status);
19039517SBill.Taylor@Sun.COM }
19049517SBill.Taylor@Sun.COM
19059517SBill.Taylor@Sun.COM if (i == hermon_hw_flash_timeout_erase) {
19069517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
19079517SBill.Taylor@Sun.COM "hermon_flash_erase_sector: "
19089517SBill.Taylor@Sun.COM "ICS erase timeout\n");
19099517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
19109517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
19119517SBill.Taylor@Sun.COM return (EIO);
19129517SBill.Taylor@Sun.COM }
19139517SBill.Taylor@Sun.COM i++;
19149517SBill.Taylor@Sun.COM } while ((stat & HERMON_HW_FLASH_ICS_READY) == 0);
19159517SBill.Taylor@Sun.COM
19169517SBill.Taylor@Sun.COM if (stat & HERMON_HW_FLASH_ICS_ERROR) {
19179517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
19189517SBill.Taylor@Sun.COM "hermon_flash_erase_sector: "
19199517SBill.Taylor@Sun.COM "ICS erase cmd error\n");
19209517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
19219517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
19229517SBill.Taylor@Sun.COM return (EIO);
19239517SBill.Taylor@Sun.COM }
19249517SBill.Taylor@Sun.COM break;
19259517SBill.Taylor@Sun.COM
19269517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
19279517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
19289517SBill.Taylor@Sun.COM
19299517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
19309517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
19319517SBill.Taylor@Sun.COM fm_test);
19329517SBill.Taylor@Sun.COM
19339517SBill.Taylor@Sun.COM /* Issue Write Enable */
19349517SBill.Taylor@Sun.COM hermon_flash_spi_write_enable(state);
19359517SBill.Taylor@Sun.COM
19369517SBill.Taylor@Sun.COM /* Set the Address */
19379517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
19389517SBill.Taylor@Sun.COM addr & HERMON_HW_FLASH_SPI_ADDR_MASK);
19399517SBill.Taylor@Sun.COM
19409517SBill.Taylor@Sun.COM /* Issue Flash Sector Erase */
19419517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(state, hdl,
19429517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
19439517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
19449517SBill.Taylor@Sun.COM ((uint32_t)(HERMON_HW_FLASH_SPI_SECTOR_ERASE) <<
19459517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_SHIFT));
19469517SBill.Taylor@Sun.COM
19479517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
19489517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status,
19499517SBill.Taylor@Sun.COM fm_test);
19509517SBill.Taylor@Sun.COM
19519517SBill.Taylor@Sun.COM /* Wait for Sector Erase to complete */
19529517SBill.Taylor@Sun.COM status = hermon_flash_spi_wait_wip(state);
19539517SBill.Taylor@Sun.COM break;
19549517SBill.Taylor@Sun.COM
19559517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
19569517SBill.Taylor@Sun.COM default:
19579517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
19589517SBill.Taylor@Sun.COM "hermon_flash_erase_sector: unknown cmd set: 0x%x\n",
19599517SBill.Taylor@Sun.COM state->hs_fw_cmdset);
19609517SBill.Taylor@Sun.COM status = EINVAL;
19619517SBill.Taylor@Sun.COM break;
19629517SBill.Taylor@Sun.COM }
19639517SBill.Taylor@Sun.COM
19649517SBill.Taylor@Sun.COM /* Reset the flash device */
19659517SBill.Taylor@Sun.COM if (status == 0) {
19669517SBill.Taylor@Sun.COM status = hermon_flash_reset(state);
19679517SBill.Taylor@Sun.COM }
19689517SBill.Taylor@Sun.COM return (status);
19699517SBill.Taylor@Sun.COM
19709517SBill.Taylor@Sun.COM pio_error:
19719517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
19729517SBill.Taylor@Sun.COM return (EIO);
19739517SBill.Taylor@Sun.COM }
19749517SBill.Taylor@Sun.COM
19759517SBill.Taylor@Sun.COM /*
19769517SBill.Taylor@Sun.COM * hermon_flash_erase_chip()
19779517SBill.Taylor@Sun.COM */
19789517SBill.Taylor@Sun.COM static int
hermon_flash_erase_chip(hermon_state_t * state)19799517SBill.Taylor@Sun.COM hermon_flash_erase_chip(hermon_state_t *state)
19809517SBill.Taylor@Sun.COM {
19819517SBill.Taylor@Sun.COM uint32_t stat;
19829517SBill.Taylor@Sun.COM uint_t size;
19839517SBill.Taylor@Sun.COM int status = 0;
19849517SBill.Taylor@Sun.COM int i;
19859517SBill.Taylor@Sun.COM int num_sect;
19869517SBill.Taylor@Sun.COM
19879517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
19889517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
19899517SBill.Taylor@Sun.COM /* Issue Flash Chip Erase Command */
19909517SBill.Taylor@Sun.COM hermon_flash_write(state, 0, 0xAA, &status);
19919517SBill.Taylor@Sun.COM if (status != 0) {
19929517SBill.Taylor@Sun.COM return (status);
19939517SBill.Taylor@Sun.COM }
19949517SBill.Taylor@Sun.COM
19959517SBill.Taylor@Sun.COM hermon_flash_write(state, 0, 0x55, &status);
19969517SBill.Taylor@Sun.COM if (status != 0) {
19979517SBill.Taylor@Sun.COM return (status);
19989517SBill.Taylor@Sun.COM }
19999517SBill.Taylor@Sun.COM
20009517SBill.Taylor@Sun.COM hermon_flash_write(state, 0, 0x80, &status);
20019517SBill.Taylor@Sun.COM if (status != 0) {
20029517SBill.Taylor@Sun.COM return (status);
20039517SBill.Taylor@Sun.COM }
20049517SBill.Taylor@Sun.COM
20059517SBill.Taylor@Sun.COM hermon_flash_write(state, 0, 0xAA, &status);
20069517SBill.Taylor@Sun.COM if (status != 0) {
20079517SBill.Taylor@Sun.COM return (status);
20089517SBill.Taylor@Sun.COM }
20099517SBill.Taylor@Sun.COM
20109517SBill.Taylor@Sun.COM hermon_flash_write(state, 0, 0x55, &status);
20119517SBill.Taylor@Sun.COM if (status != 0) {
20129517SBill.Taylor@Sun.COM return (status);
20139517SBill.Taylor@Sun.COM }
20149517SBill.Taylor@Sun.COM
20159517SBill.Taylor@Sun.COM hermon_flash_write(state, 0, 0x10, &status);
20169517SBill.Taylor@Sun.COM if (status != 0) {
20179517SBill.Taylor@Sun.COM return (status);
20189517SBill.Taylor@Sun.COM }
20199517SBill.Taylor@Sun.COM
20209517SBill.Taylor@Sun.COM /* Wait for Chip Erase to Complete */
20219517SBill.Taylor@Sun.COM i = 0;
20229517SBill.Taylor@Sun.COM do {
20239517SBill.Taylor@Sun.COM drv_usecwait(1);
20249517SBill.Taylor@Sun.COM stat = hermon_flash_read(state, 0, &status);
20259517SBill.Taylor@Sun.COM if (status != 0) {
20269517SBill.Taylor@Sun.COM return (status);
20279517SBill.Taylor@Sun.COM }
20289517SBill.Taylor@Sun.COM
20299517SBill.Taylor@Sun.COM if (i == hermon_hw_flash_timeout_erase) {
20309517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
20319517SBill.Taylor@Sun.COM "hermon_flash_erase_chip: erase timeout\n");
20329517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR,
20339517SBill.Taylor@Sun.COM HCA_ERR_IOCTL);
20349517SBill.Taylor@Sun.COM return (EIO);
20359517SBill.Taylor@Sun.COM }
20369517SBill.Taylor@Sun.COM i++;
20379517SBill.Taylor@Sun.COM } while (stat != 0xFFFFFFFF);
20389517SBill.Taylor@Sun.COM break;
20399517SBill.Taylor@Sun.COM
20409517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
20419517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
20429517SBill.Taylor@Sun.COM /*
20439517SBill.Taylor@Sun.COM * These chips don't have a chip erase command, so erase
20449517SBill.Taylor@Sun.COM * all blocks one at a time.
20459517SBill.Taylor@Sun.COM */
20469517SBill.Taylor@Sun.COM size = (0x1 << state->hs_fw_log_sector_sz);
20479517SBill.Taylor@Sun.COM num_sect = state->hs_fw_device_sz / size;
20489517SBill.Taylor@Sun.COM
20499517SBill.Taylor@Sun.COM for (i = 0; i < num_sect; i++) {
20509517SBill.Taylor@Sun.COM status = hermon_flash_erase_sector(state, i);
20519517SBill.Taylor@Sun.COM if (status != 0) {
20529517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
20539517SBill.Taylor@Sun.COM "hermon_flash_erase_chip: "
20549517SBill.Taylor@Sun.COM "sector %d erase error\n", i);
20559517SBill.Taylor@Sun.COM return (status);
20569517SBill.Taylor@Sun.COM }
20579517SBill.Taylor@Sun.COM }
20589517SBill.Taylor@Sun.COM break;
20599517SBill.Taylor@Sun.COM
20609517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
20619517SBill.Taylor@Sun.COM default:
20629517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_flash_erase_chip: "
20639517SBill.Taylor@Sun.COM "unknown cmd set: 0x%x\n", state->hs_fw_cmdset);
20649517SBill.Taylor@Sun.COM status = EINVAL;
20659517SBill.Taylor@Sun.COM break;
20669517SBill.Taylor@Sun.COM }
20679517SBill.Taylor@Sun.COM
20689517SBill.Taylor@Sun.COM return (status);
20699517SBill.Taylor@Sun.COM }
20709517SBill.Taylor@Sun.COM
20719517SBill.Taylor@Sun.COM /*
20729517SBill.Taylor@Sun.COM * hermon_flash_spi_write_enable()
20739517SBill.Taylor@Sun.COM */
20749517SBill.Taylor@Sun.COM static void
hermon_flash_spi_write_enable(hermon_state_t * state)20759517SBill.Taylor@Sun.COM hermon_flash_spi_write_enable(hermon_state_t *state)
20769517SBill.Taylor@Sun.COM {
20779517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
20789517SBill.Taylor@Sun.COM
20799517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
20809517SBill.Taylor@Sun.COM
20819517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(state, hdl,
20829517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
20839517SBill.Taylor@Sun.COM (HERMON_HW_FLASH_SPI_WRITE_ENABLE <<
20849517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_SHIFT));
20859517SBill.Taylor@Sun.COM }
20869517SBill.Taylor@Sun.COM
20879517SBill.Taylor@Sun.COM /*
20889517SBill.Taylor@Sun.COM * hermon_flash_spi_wait_wip()
20899517SBill.Taylor@Sun.COM */
20909517SBill.Taylor@Sun.COM static int
hermon_flash_spi_wait_wip(hermon_state_t * state)20919517SBill.Taylor@Sun.COM hermon_flash_spi_wait_wip(hermon_state_t *state)
20929517SBill.Taylor@Sun.COM {
20939517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
20949517SBill.Taylor@Sun.COM uint32_t status;
20959517SBill.Taylor@Sun.COM
20969517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
20979517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
20989517SBill.Taylor@Sun.COM
20999517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
21009517SBill.Taylor@Sun.COM
21019517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
21029517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
21039517SBill.Taylor@Sun.COM fm_test);
21049517SBill.Taylor@Sun.COM
21059517SBill.Taylor@Sun.COM /* wait on the gateway to clear busy */
21069517SBill.Taylor@Sun.COM do {
21079517SBill.Taylor@Sun.COM status = hermon_flash_read_cfg(state, hdl,
21089517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_GW);
21099517SBill.Taylor@Sun.COM } while (status & HERMON_HW_FLASH_SPI_BUSY);
21109517SBill.Taylor@Sun.COM
21119517SBill.Taylor@Sun.COM /* now, get the status and check for WIP to clear */
21129517SBill.Taylor@Sun.COM do {
21139517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(state, hdl,
21149517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_READ_OP |
21159517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
21169517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
21179517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
21189517SBill.Taylor@Sun.COM (HERMON_HW_FLASH_SPI_READ_STATUS_REG <<
21199517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_SHIFT));
21209517SBill.Taylor@Sun.COM
21219517SBill.Taylor@Sun.COM status = hermon_flash_read_cfg(state, hdl,
21229517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_DATA);
21239517SBill.Taylor@Sun.COM } while (status & HERMON_HW_FLASH_SPI_WIP);
21249517SBill.Taylor@Sun.COM
21259517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
21269517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
21279517SBill.Taylor@Sun.COM return (0);
21289517SBill.Taylor@Sun.COM
21299517SBill.Taylor@Sun.COM pio_error:
21309517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21319517SBill.Taylor@Sun.COM return (EIO);
21329517SBill.Taylor@Sun.COM }
21339517SBill.Taylor@Sun.COM
21349517SBill.Taylor@Sun.COM /*
21359517SBill.Taylor@Sun.COM * hermon_flash_bank()
21369517SBill.Taylor@Sun.COM */
21379517SBill.Taylor@Sun.COM static int
hermon_flash_bank(hermon_state_t * state,uint32_t addr)21389517SBill.Taylor@Sun.COM hermon_flash_bank(hermon_state_t *state, uint32_t addr)
21399517SBill.Taylor@Sun.COM {
21409517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
21419517SBill.Taylor@Sun.COM uint32_t bank;
21429517SBill.Taylor@Sun.COM
21439517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
21449517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
21459517SBill.Taylor@Sun.COM
21469517SBill.Taylor@Sun.COM /* Set handle */
21479517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
21489517SBill.Taylor@Sun.COM
21499517SBill.Taylor@Sun.COM /* Determine the bank setting from the address */
21509517SBill.Taylor@Sun.COM bank = addr & HERMON_HW_FLASH_BANK_MASK;
21519517SBill.Taylor@Sun.COM
21529517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(state->hs_fw_flashbank))
21539517SBill.Taylor@Sun.COM
21549517SBill.Taylor@Sun.COM /*
21559517SBill.Taylor@Sun.COM * If the bank is different from the currently set bank, we need to
21569517SBill.Taylor@Sun.COM * change it. Also, if an 'addr' of 0 is given, this allows the
21579517SBill.Taylor@Sun.COM * capability to force the flash bank to 0. This is useful at init
21589517SBill.Taylor@Sun.COM * time to initially set the bank value
21599517SBill.Taylor@Sun.COM */
21609517SBill.Taylor@Sun.COM if (state->hs_fw_flashbank != bank || addr == 0) {
21619517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
21629517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
21639517SBill.Taylor@Sun.COM /* CMJ: not needed for hermon */
21649517SBill.Taylor@Sun.COM break;
21659517SBill.Taylor@Sun.COM
21669517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
21679517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
21689517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
21699517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt,
21709517SBill.Taylor@Sun.COM fm_status, fm_test);
21719517SBill.Taylor@Sun.COM
21729517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl,
21739517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_DATACLEAR, 0x70);
21749517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl,
21759517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_DATASET, (bank >> 15) & 0x70);
21769517SBill.Taylor@Sun.COM
21779517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
21789517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt,
21799517SBill.Taylor@Sun.COM fm_status, fm_test);
21809517SBill.Taylor@Sun.COM break;
21819517SBill.Taylor@Sun.COM
21829517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
21839517SBill.Taylor@Sun.COM default:
21849517SBill.Taylor@Sun.COM return (EINVAL);
21859517SBill.Taylor@Sun.COM }
21869517SBill.Taylor@Sun.COM
21879517SBill.Taylor@Sun.COM state->hs_fw_flashbank = bank;
21889517SBill.Taylor@Sun.COM }
21899517SBill.Taylor@Sun.COM return (0);
21909517SBill.Taylor@Sun.COM
21919517SBill.Taylor@Sun.COM pio_error:
21929517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
21939517SBill.Taylor@Sun.COM return (EIO);
21949517SBill.Taylor@Sun.COM }
21959517SBill.Taylor@Sun.COM
21969517SBill.Taylor@Sun.COM /*
21979517SBill.Taylor@Sun.COM * hermon_flash_spi_exec_command()
21989517SBill.Taylor@Sun.COM */
21999517SBill.Taylor@Sun.COM static void
hermon_flash_spi_exec_command(hermon_state_t * state,ddi_acc_handle_t hdl,uint32_t cmd)22009517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(hermon_state_t *state, ddi_acc_handle_t hdl,
22019517SBill.Taylor@Sun.COM uint32_t cmd)
22029517SBill.Taylor@Sun.COM {
22039517SBill.Taylor@Sun.COM uint32_t data;
22049517SBill.Taylor@Sun.COM int timeout = 0;
22059517SBill.Taylor@Sun.COM
22069517SBill.Taylor@Sun.COM cmd |= HERMON_HW_FLASH_SPI_BUSY | HERMON_HW_FLASH_SPI_ENABLE_OFF;
22079517SBill.Taylor@Sun.COM
22089517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_GW, cmd);
22099517SBill.Taylor@Sun.COM
22109517SBill.Taylor@Sun.COM do {
22119517SBill.Taylor@Sun.COM data = hermon_flash_read_cfg(state, hdl,
22129517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_GW);
22139517SBill.Taylor@Sun.COM timeout++;
22149517SBill.Taylor@Sun.COM } while ((data & HERMON_HW_FLASH_SPI_BUSY) &&
22159517SBill.Taylor@Sun.COM (timeout < hermon_hw_flash_timeout_config));
22169517SBill.Taylor@Sun.COM }
22179517SBill.Taylor@Sun.COM
22189517SBill.Taylor@Sun.COM /*
22199517SBill.Taylor@Sun.COM * hermon_flash_read()
22209517SBill.Taylor@Sun.COM */
22219517SBill.Taylor@Sun.COM static uint32_t
hermon_flash_read(hermon_state_t * state,uint32_t addr,int * err)22229517SBill.Taylor@Sun.COM hermon_flash_read(hermon_state_t *state, uint32_t addr, int *err)
22239517SBill.Taylor@Sun.COM {
22249517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
22259517SBill.Taylor@Sun.COM uint32_t data = 0;
22269517SBill.Taylor@Sun.COM int timeout, status = 0;
22279517SBill.Taylor@Sun.COM
22289517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
22299517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
22309517SBill.Taylor@Sun.COM
22319517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
22329517SBill.Taylor@Sun.COM
22339517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
22349517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
22359517SBill.Taylor@Sun.COM fm_test);
22369517SBill.Taylor@Sun.COM
22379517SBill.Taylor@Sun.COM switch (state->hs_fw_cmdset) {
22389517SBill.Taylor@Sun.COM case HERMON_FLASH_SPI_CMDSET:
22399517SBill.Taylor@Sun.COM /* Set the transaction address */
22409517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_SPI_ADDR,
22419517SBill.Taylor@Sun.COM (addr & HERMON_HW_FLASH_SPI_ADDR_MASK));
22429517SBill.Taylor@Sun.COM
22439517SBill.Taylor@Sun.COM hermon_flash_spi_exec_command(state, hdl,
22449517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_READ_OP |
22459517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_PHASE_OFF |
22469517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_ADDR_PHASE_OFF |
22479517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_DATA_PHASE_OFF |
22489517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_TRANS_SZ_4B |
22499517SBill.Taylor@Sun.COM (HERMON_HW_FLASH_SPI_READ <<
22509517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_INSTR_SHIFT));
22519517SBill.Taylor@Sun.COM
22529517SBill.Taylor@Sun.COM data = hermon_flash_read_cfg(state, hdl,
22539517SBill.Taylor@Sun.COM HERMON_HW_FLASH_SPI_DATA);
22549517SBill.Taylor@Sun.COM break;
22559517SBill.Taylor@Sun.COM
22569517SBill.Taylor@Sun.COM case HERMON_FLASH_INTEL_CMDSET:
22579517SBill.Taylor@Sun.COM case HERMON_FLASH_AMD_CMDSET:
22589517SBill.Taylor@Sun.COM /*
22599517SBill.Taylor@Sun.COM * The Read operation does the following:
22609517SBill.Taylor@Sun.COM * 1) Write the masked address to the HERMON_FLASH_ADDR
22619517SBill.Taylor@Sun.COM * register. Only the least significant 19 bits are valid.
22629517SBill.Taylor@Sun.COM * 2) Read back the register until the command has completed.
22639517SBill.Taylor@Sun.COM * 3) Read the data retrieved from the address at the
22649517SBill.Taylor@Sun.COM * HERMON_FLASH_DATA register.
22659517SBill.Taylor@Sun.COM */
22669517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
22679517SBill.Taylor@Sun.COM (addr & HERMON_HW_FLASH_ADDR_MASK) | (1 << 29));
22689517SBill.Taylor@Sun.COM
22699517SBill.Taylor@Sun.COM timeout = 0;
22709517SBill.Taylor@Sun.COM do {
22719517SBill.Taylor@Sun.COM data = hermon_flash_read_cfg(state, hdl,
22729517SBill.Taylor@Sun.COM HERMON_HW_FLASH_ADDR);
22739517SBill.Taylor@Sun.COM timeout++;
22749517SBill.Taylor@Sun.COM } while ((data & HERMON_HW_FLASH_CMD_MASK) &&
22759517SBill.Taylor@Sun.COM (timeout < hermon_hw_flash_timeout_config));
22769517SBill.Taylor@Sun.COM
227711951SShantkumar.Hiremath@Sun.COM if (timeout == hermon_hw_flash_timeout_config) {
227811951SShantkumar.Hiremath@Sun.COM cmn_err(CE_WARN, "hermon_flash_read: command timed "
227911951SShantkumar.Hiremath@Sun.COM "out.\n");
228011951SShantkumar.Hiremath@Sun.COM *err = EIO;
228111951SShantkumar.Hiremath@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
228211951SShantkumar.Hiremath@Sun.COM return (data);
228311951SShantkumar.Hiremath@Sun.COM }
228411951SShantkumar.Hiremath@Sun.COM
22859517SBill.Taylor@Sun.COM data = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_DATA);
22869517SBill.Taylor@Sun.COM break;
22879517SBill.Taylor@Sun.COM
22889517SBill.Taylor@Sun.COM case HERMON_FLASH_UNKNOWN_CMDSET:
22899517SBill.Taylor@Sun.COM default:
22909517SBill.Taylor@Sun.COM cmn_err(CE_CONT, "hermon_flash_read: unknown cmdset: 0x%x\n",
22919517SBill.Taylor@Sun.COM state->hs_fw_cmdset);
22929517SBill.Taylor@Sun.COM status = EINVAL;
22939517SBill.Taylor@Sun.COM break;
22949517SBill.Taylor@Sun.COM }
22959517SBill.Taylor@Sun.COM
22969517SBill.Taylor@Sun.COM
22979517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
22989517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
22999517SBill.Taylor@Sun.COM *err = status;
23009517SBill.Taylor@Sun.COM return (data);
23019517SBill.Taylor@Sun.COM
23029517SBill.Taylor@Sun.COM pio_error:
23039517SBill.Taylor@Sun.COM *err = EIO;
23049517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23059517SBill.Taylor@Sun.COM return (data);
23069517SBill.Taylor@Sun.COM }
23079517SBill.Taylor@Sun.COM
23089517SBill.Taylor@Sun.COM /*
23099517SBill.Taylor@Sun.COM * hermon_flash_write()
23109517SBill.Taylor@Sun.COM */
23119517SBill.Taylor@Sun.COM static void
hermon_flash_write(hermon_state_t * state,uint32_t addr,uchar_t data,int * err)23129517SBill.Taylor@Sun.COM hermon_flash_write(hermon_state_t *state, uint32_t addr, uchar_t data, int *err)
23139517SBill.Taylor@Sun.COM {
23149517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
23159517SBill.Taylor@Sun.COM int cmd;
23169517SBill.Taylor@Sun.COM int timeout;
23179517SBill.Taylor@Sun.COM
23189517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
23199517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23209517SBill.Taylor@Sun.COM
23219517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
23229517SBill.Taylor@Sun.COM
23239517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
23249517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23259517SBill.Taylor@Sun.COM fm_test);
23269517SBill.Taylor@Sun.COM
23279517SBill.Taylor@Sun.COM /*
23289517SBill.Taylor@Sun.COM * The Write operation does the following:
23299517SBill.Taylor@Sun.COM * 1) Write the data to be written to the HERMON_FLASH_DATA offset.
23309517SBill.Taylor@Sun.COM * 2) Write the address to write the data to to the HERMON_FLASH_ADDR
23319517SBill.Taylor@Sun.COM * offset.
23329517SBill.Taylor@Sun.COM * 3) Wait until the write completes.
23339517SBill.Taylor@Sun.COM */
23349517SBill.Taylor@Sun.COM
23359517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_DATA, data << 24);
23369517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_ADDR,
23379517SBill.Taylor@Sun.COM (addr & 0x7FFFF) | (2 << 29));
23389517SBill.Taylor@Sun.COM
23399517SBill.Taylor@Sun.COM timeout = 0;
23409517SBill.Taylor@Sun.COM do {
23419517SBill.Taylor@Sun.COM cmd = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_ADDR);
23429517SBill.Taylor@Sun.COM timeout++;
23439517SBill.Taylor@Sun.COM } while ((cmd & HERMON_HW_FLASH_CMD_MASK) &&
23449517SBill.Taylor@Sun.COM (timeout < hermon_hw_flash_timeout_config));
23459517SBill.Taylor@Sun.COM
23469517SBill.Taylor@Sun.COM if (timeout == hermon_hw_flash_timeout_config) {
23479517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_flash_write: config cmd timeout.\n");
23489517SBill.Taylor@Sun.COM *err = EIO;
23499517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23509517SBill.Taylor@Sun.COM return;
23519517SBill.Taylor@Sun.COM }
23529517SBill.Taylor@Sun.COM
23539517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
23549517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
23559517SBill.Taylor@Sun.COM *err = 0;
23569517SBill.Taylor@Sun.COM return;
23579517SBill.Taylor@Sun.COM
23589517SBill.Taylor@Sun.COM pio_error:
23599517SBill.Taylor@Sun.COM *err = EIO;
23609517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
23619517SBill.Taylor@Sun.COM }
23629517SBill.Taylor@Sun.COM
23639517SBill.Taylor@Sun.COM /*
23649517SBill.Taylor@Sun.COM * hermon_flash_init()
23659517SBill.Taylor@Sun.COM */
23669517SBill.Taylor@Sun.COM static int
hermon_flash_init(hermon_state_t * state)23679517SBill.Taylor@Sun.COM hermon_flash_init(hermon_state_t *state)
23689517SBill.Taylor@Sun.COM {
23699517SBill.Taylor@Sun.COM uint32_t word;
23709517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
23719517SBill.Taylor@Sun.COM int sema_cnt;
23729517SBill.Taylor@Sun.COM int gpio;
23739517SBill.Taylor@Sun.COM
23749517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
23759517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
23769517SBill.Taylor@Sun.COM
23779517SBill.Taylor@Sun.COM /* Set handle */
23789517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
23799517SBill.Taylor@Sun.COM
23809517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
23819517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
23829517SBill.Taylor@Sun.COM fm_test);
23839517SBill.Taylor@Sun.COM
23849517SBill.Taylor@Sun.COM /* Init the flash */
23859517SBill.Taylor@Sun.COM
23869517SBill.Taylor@Sun.COM #ifdef DO_WRCONF
23879517SBill.Taylor@Sun.COM /*
23889517SBill.Taylor@Sun.COM * Grab the WRCONF semaphore.
23899517SBill.Taylor@Sun.COM */
23909517SBill.Taylor@Sun.COM word = hermon_flash_read_cfg(state, hdl, HERMON_HW_FLASH_WRCONF_SEMA);
23919517SBill.Taylor@Sun.COM #endif
23929517SBill.Taylor@Sun.COM
23939517SBill.Taylor@Sun.COM /*
23949517SBill.Taylor@Sun.COM * Grab the GPIO semaphore. This allows us exclusive access to the
23959517SBill.Taylor@Sun.COM * GPIO settings on the Hermon for the duration of the flash burning
23969517SBill.Taylor@Sun.COM * procedure.
23979517SBill.Taylor@Sun.COM */
23989517SBill.Taylor@Sun.COM sema_cnt = 0;
23999517SBill.Taylor@Sun.COM do {
24009517SBill.Taylor@Sun.COM word = hermon_flash_read_cfg(state, hdl,
24019517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_SEMA);
24029517SBill.Taylor@Sun.COM if (word == 0) {
24039517SBill.Taylor@Sun.COM break;
24049517SBill.Taylor@Sun.COM }
24059517SBill.Taylor@Sun.COM
24069517SBill.Taylor@Sun.COM sema_cnt++;
24079517SBill.Taylor@Sun.COM drv_usecwait(1);
24089517SBill.Taylor@Sun.COM
24099517SBill.Taylor@Sun.COM } while (sema_cnt < hermon_hw_flash_timeout_gpio_sema);
24109517SBill.Taylor@Sun.COM
24119517SBill.Taylor@Sun.COM /*
24129517SBill.Taylor@Sun.COM * Determine if we timed out trying to grab the GPIO semaphore
24139517SBill.Taylor@Sun.COM */
24149517SBill.Taylor@Sun.COM if (sema_cnt == hermon_hw_flash_timeout_gpio_sema) {
24159517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "hermon_flash_init: GPIO SEMA timeout\n");
24169517SBill.Taylor@Sun.COM cmn_err(CE_WARN, "GPIO_SEMA value: 0x%x\n", word);
24179517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24189517SBill.Taylor@Sun.COM return (EIO);
24199517SBill.Taylor@Sun.COM }
24209517SBill.Taylor@Sun.COM
24219517SBill.Taylor@Sun.COM /* Save away original GPIO Values */
24229517SBill.Taylor@Sun.COM state->hs_fw_gpio[0] = hermon_flash_read_cfg(state, hdl,
24239517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_DATA);
24249517SBill.Taylor@Sun.COM
24259517SBill.Taylor@Sun.COM /* Set new GPIO value */
24269517SBill.Taylor@Sun.COM gpio = state->hs_fw_gpio[0] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24279517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA, gpio);
24289517SBill.Taylor@Sun.COM
24299517SBill.Taylor@Sun.COM /* Save away original GPIO Values */
24309517SBill.Taylor@Sun.COM state->hs_fw_gpio[1] = hermon_flash_read_cfg(state, hdl,
24319517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_MOD0);
24329517SBill.Taylor@Sun.COM state->hs_fw_gpio[2] = hermon_flash_read_cfg(state, hdl,
24339517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_MOD1);
24349517SBill.Taylor@Sun.COM
24359517SBill.Taylor@Sun.COM /* unlock GPIO */
24369517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
24379517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
24389517SBill.Taylor@Sun.COM
24399517SBill.Taylor@Sun.COM /*
24409517SBill.Taylor@Sun.COM * Set new GPIO values
24419517SBill.Taylor@Sun.COM */
24429517SBill.Taylor@Sun.COM gpio = state->hs_fw_gpio[1] | HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24439517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0, gpio);
24449517SBill.Taylor@Sun.COM
24459517SBill.Taylor@Sun.COM gpio = state->hs_fw_gpio[2] & ~HERMON_HW_FLASH_GPIO_PIN_ENABLE;
24469517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1, gpio);
24479517SBill.Taylor@Sun.COM
24489517SBill.Taylor@Sun.COM /* re-lock GPIO */
24499517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
24509517SBill.Taylor@Sun.COM
24519517SBill.Taylor@Sun.COM /* Set CPUMODE to enable hermon to access the flash device */
24529517SBill.Taylor@Sun.COM /* CMJ This code came from arbel. Hermon doesn't seem to need it. */
24539517SBill.Taylor@Sun.COM /*
24549517SBill.Taylor@Sun.COM * hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_CPUMODE,
24559517SBill.Taylor@Sun.COM * 1 << HERMON_HW_FLASH_CPU_SHIFT);
24569517SBill.Taylor@Sun.COM */
24579517SBill.Taylor@Sun.COM
24589517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
24599517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
24609517SBill.Taylor@Sun.COM return (0);
24619517SBill.Taylor@Sun.COM
24629517SBill.Taylor@Sun.COM pio_error:
24639517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
24649517SBill.Taylor@Sun.COM return (EIO);
24659517SBill.Taylor@Sun.COM }
24669517SBill.Taylor@Sun.COM
24679517SBill.Taylor@Sun.COM /*
24689517SBill.Taylor@Sun.COM * hermon_flash_cfi_init
24699517SBill.Taylor@Sun.COM * Implements access to the CFI (Common Flash Interface) data
24709517SBill.Taylor@Sun.COM */
24719517SBill.Taylor@Sun.COM static int
hermon_flash_cfi_init(hermon_state_t * state,uint32_t * cfi_info,int * intel_xcmd)24729517SBill.Taylor@Sun.COM hermon_flash_cfi_init(hermon_state_t *state, uint32_t *cfi_info,
24739517SBill.Taylor@Sun.COM int *intel_xcmd)
24749517SBill.Taylor@Sun.COM {
24759517SBill.Taylor@Sun.COM uint32_t data;
24769517SBill.Taylor@Sun.COM uint32_t sector_sz_bytes;
24779517SBill.Taylor@Sun.COM uint32_t bit_count;
24789517SBill.Taylor@Sun.COM uint8_t cfi_ch_info[HERMON_CFI_INFO_SIZE];
24799517SBill.Taylor@Sun.COM uint32_t cfi_dw_info[HERMON_CFI_INFO_QSIZE];
24809517SBill.Taylor@Sun.COM int i;
24819517SBill.Taylor@Sun.COM int status;
24829517SBill.Taylor@Sun.COM
24839517SBill.Taylor@Sun.COM /* Right now, all hermon cards use SPI. */
2484*12688SWilliam.Taylor@Oracle.COM if (hermon_device_mode(state)) {
24859517SBill.Taylor@Sun.COM /*
24869517SBill.Taylor@Sun.COM * Don't use CFI for SPI part. Just fill in what we need
24879517SBill.Taylor@Sun.COM * and return.
24889517SBill.Taylor@Sun.COM */
24899517SBill.Taylor@Sun.COM state->hs_fw_cmdset = HERMON_FLASH_SPI_CMDSET;
24909517SBill.Taylor@Sun.COM state->hs_fw_log_sector_sz = HERMON_FLASH_SPI_LOG_SECTOR_SIZE;
24919517SBill.Taylor@Sun.COM state->hs_fw_device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
24929517SBill.Taylor@Sun.COM
24939517SBill.Taylor@Sun.COM /*
24949517SBill.Taylor@Sun.COM * set this to inform caller of cmdset type.
24959517SBill.Taylor@Sun.COM */
24969517SBill.Taylor@Sun.COM cfi_ch_info[0x13] = HERMON_FLASH_SPI_CMDSET;
24979517SBill.Taylor@Sun.COM hermon_flash_cfi_dword(&cfi_info[4], cfi_ch_info, 0x10);
24989517SBill.Taylor@Sun.COM return (0);
24999517SBill.Taylor@Sun.COM }
25009517SBill.Taylor@Sun.COM
25019517SBill.Taylor@Sun.COM /*
25029517SBill.Taylor@Sun.COM * Determine if the user command supports the Intel Extended
25039517SBill.Taylor@Sun.COM * Command Set. The query string is contained in the fourth
25049517SBill.Taylor@Sun.COM * quad word.
25059517SBill.Taylor@Sun.COM */
25069517SBill.Taylor@Sun.COM hermon_flash_cfi_byte(cfi_ch_info, cfi_info[0x04], 0x10);
25079517SBill.Taylor@Sun.COM if (cfi_ch_info[0x10] == 'M' &&
25089517SBill.Taylor@Sun.COM cfi_ch_info[0x11] == 'X' &&
25099517SBill.Taylor@Sun.COM cfi_ch_info[0x12] == '2') {
25109517SBill.Taylor@Sun.COM *intel_xcmd = 1; /* support is there */
25119517SBill.Taylor@Sun.COM if (hermon_verbose) {
25129517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon",
25139517SBill.Taylor@Sun.COM "Support for Intel X is present\n");
25149517SBill.Taylor@Sun.COM }
25159517SBill.Taylor@Sun.COM }
25169517SBill.Taylor@Sun.COM
25179517SBill.Taylor@Sun.COM /* CFI QUERY */
25189517SBill.Taylor@Sun.COM hermon_flash_write(state, 0x55, HERMON_FLASH_CFI_INIT, &status);
25199517SBill.Taylor@Sun.COM if (status != 0) {
25209517SBill.Taylor@Sun.COM return (status);
25219517SBill.Taylor@Sun.COM }
25229517SBill.Taylor@Sun.COM
25239517SBill.Taylor@Sun.COM /* temporarily set the cmdset in order to do the initial read */
25249517SBill.Taylor@Sun.COM state->hs_fw_cmdset = HERMON_FLASH_INTEL_CMDSET;
25259517SBill.Taylor@Sun.COM
25269517SBill.Taylor@Sun.COM /* Read in CFI data */
25279517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 4) {
25289517SBill.Taylor@Sun.COM data = hermon_flash_read(state, i, &status);
25299517SBill.Taylor@Sun.COM if (status != 0) {
25309517SBill.Taylor@Sun.COM return (status);
25319517SBill.Taylor@Sun.COM }
25329517SBill.Taylor@Sun.COM cfi_dw_info[i >> 2] = data;
25339517SBill.Taylor@Sun.COM hermon_flash_cfi_byte(cfi_ch_info, data, i);
25349517SBill.Taylor@Sun.COM }
25359517SBill.Taylor@Sun.COM
25369517SBill.Taylor@Sun.COM /* Determine chip set */
25379517SBill.Taylor@Sun.COM state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25389517SBill.Taylor@Sun.COM if (cfi_ch_info[0x20] == 'Q' &&
25399517SBill.Taylor@Sun.COM cfi_ch_info[0x22] == 'R' &&
25409517SBill.Taylor@Sun.COM cfi_ch_info[0x24] == 'Y') {
25419517SBill.Taylor@Sun.COM /*
25429517SBill.Taylor@Sun.COM * Mode: x16 working in x8 mode (Intel).
25439517SBill.Taylor@Sun.COM * Pack data - skip spacing bytes.
25449517SBill.Taylor@Sun.COM */
25459517SBill.Taylor@Sun.COM if (hermon_verbose) {
25469517SBill.Taylor@Sun.COM IBTF_DPRINTF_L2("hermon",
25479517SBill.Taylor@Sun.COM "x16 working in x8 mode (Intel)\n");
25489517SBill.Taylor@Sun.COM }
25499517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_CFI_INFO_SIZE; i += 2) {
25509517SBill.Taylor@Sun.COM cfi_ch_info[i/2] = cfi_ch_info[i];
25519517SBill.Taylor@Sun.COM }
25529517SBill.Taylor@Sun.COM }
25539517SBill.Taylor@Sun.COM state->hs_fw_cmdset = cfi_ch_info[0x13];
25549517SBill.Taylor@Sun.COM
25559517SBill.Taylor@Sun.COM if (state->hs_fw_cmdset != HERMON_FLASH_INTEL_CMDSET &&
25569517SBill.Taylor@Sun.COM state->hs_fw_cmdset != HERMON_FLASH_AMD_CMDSET) {
25579517SBill.Taylor@Sun.COM cmn_err(CE_WARN,
25589517SBill.Taylor@Sun.COM "hermon_flash_cfi_init: UNKNOWN chip cmd set 0x%04x\n",
25599517SBill.Taylor@Sun.COM state->hs_fw_cmdset);
25609517SBill.Taylor@Sun.COM state->hs_fw_cmdset = HERMON_FLASH_UNKNOWN_CMDSET;
25619517SBill.Taylor@Sun.COM return (0);
25629517SBill.Taylor@Sun.COM }
25639517SBill.Taylor@Sun.COM
25649517SBill.Taylor@Sun.COM /* Determine total bytes in one sector size */
25659517SBill.Taylor@Sun.COM sector_sz_bytes = ((cfi_ch_info[0x30] << 8) | cfi_ch_info[0x2F]) << 8;
25669517SBill.Taylor@Sun.COM
25679517SBill.Taylor@Sun.COM /* Calculate equivalent of log2 (n) */
25689517SBill.Taylor@Sun.COM for (bit_count = 0; sector_sz_bytes > 1; bit_count++) {
25699517SBill.Taylor@Sun.COM sector_sz_bytes >>= 1;
25709517SBill.Taylor@Sun.COM }
25719517SBill.Taylor@Sun.COM
25729517SBill.Taylor@Sun.COM /* Set sector size */
25739517SBill.Taylor@Sun.COM state->hs_fw_log_sector_sz = bit_count;
25749517SBill.Taylor@Sun.COM
25759517SBill.Taylor@Sun.COM /* Set flash size */
25769517SBill.Taylor@Sun.COM state->hs_fw_device_sz = 0x1 << cfi_ch_info[0x27];
25779517SBill.Taylor@Sun.COM
25789517SBill.Taylor@Sun.COM /* Reset to turn off CFI mode */
25799517SBill.Taylor@Sun.COM if ((status = hermon_flash_reset(state)) != 0)
25809517SBill.Taylor@Sun.COM goto out;
25819517SBill.Taylor@Sun.COM
25829517SBill.Taylor@Sun.COM /* Pass CFI data back to user command. */
25839517SBill.Taylor@Sun.COM for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
25849517SBill.Taylor@Sun.COM hermon_flash_cfi_dword(&cfi_info[i], cfi_ch_info, i << 2);
25859517SBill.Taylor@Sun.COM }
25869517SBill.Taylor@Sun.COM
25879517SBill.Taylor@Sun.COM if (*intel_xcmd == 1) {
25889517SBill.Taylor@Sun.COM /*
25899517SBill.Taylor@Sun.COM * Inform the user cmd that this driver does support the
25909517SBill.Taylor@Sun.COM * Intel Extended Command Set.
25919517SBill.Taylor@Sun.COM */
25929517SBill.Taylor@Sun.COM cfi_ch_info[0x10] = 'M';
25939517SBill.Taylor@Sun.COM cfi_ch_info[0x11] = 'X';
25949517SBill.Taylor@Sun.COM cfi_ch_info[0x12] = '2';
25959517SBill.Taylor@Sun.COM } else {
25969517SBill.Taylor@Sun.COM cfi_ch_info[0x10] = 'Q';
25979517SBill.Taylor@Sun.COM cfi_ch_info[0x11] = 'R';
25989517SBill.Taylor@Sun.COM cfi_ch_info[0x12] = 'Y';
25999517SBill.Taylor@Sun.COM }
26009517SBill.Taylor@Sun.COM cfi_ch_info[0x13] = state->hs_fw_cmdset;
26019517SBill.Taylor@Sun.COM hermon_flash_cfi_dword(&cfi_info[0x4], cfi_ch_info, 0x10);
26029517SBill.Taylor@Sun.COM out:
26039517SBill.Taylor@Sun.COM return (status);
26049517SBill.Taylor@Sun.COM }
26059517SBill.Taylor@Sun.COM
26069517SBill.Taylor@Sun.COM /*
26079517SBill.Taylor@Sun.COM * hermon_flash_fini()
26089517SBill.Taylor@Sun.COM */
26099517SBill.Taylor@Sun.COM static int
hermon_flash_fini(hermon_state_t * state)26109517SBill.Taylor@Sun.COM hermon_flash_fini(hermon_state_t *state)
26119517SBill.Taylor@Sun.COM {
26129517SBill.Taylor@Sun.COM int status;
26139517SBill.Taylor@Sun.COM ddi_acc_handle_t hdl;
26149517SBill.Taylor@Sun.COM
26159517SBill.Taylor@Sun.COM /* initialize the FMA retry loop */
26169517SBill.Taylor@Sun.COM hermon_pio_init(fm_loop_cnt, fm_status, fm_test);
26179517SBill.Taylor@Sun.COM
26189517SBill.Taylor@Sun.COM /* Set handle */
26199517SBill.Taylor@Sun.COM hdl = hermon_get_pcihdl(state);
26209517SBill.Taylor@Sun.COM
26219517SBill.Taylor@Sun.COM if ((status = hermon_flash_bank(state, 0)) != 0)
26229517SBill.Taylor@Sun.COM return (status);
26239517SBill.Taylor@Sun.COM
26249517SBill.Taylor@Sun.COM /* the FMA retry loop starts. */
26259517SBill.Taylor@Sun.COM hermon_pio_start(state, hdl, pio_error, fm_loop_cnt, fm_status,
26269517SBill.Taylor@Sun.COM fm_test);
26279517SBill.Taylor@Sun.COM
26289517SBill.Taylor@Sun.COM /*
26299517SBill.Taylor@Sun.COM * Restore original GPIO Values
26309517SBill.Taylor@Sun.COM */
26319517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_DATA,
26329517SBill.Taylor@Sun.COM state->hs_fw_gpio[0]);
26339517SBill.Taylor@Sun.COM
26349517SBill.Taylor@Sun.COM /* unlock GPIOs */
26359517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK,
26369517SBill.Taylor@Sun.COM HERMON_HW_FLASH_GPIO_UNLOCK_VAL);
26379517SBill.Taylor@Sun.COM
26389517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD0,
26399517SBill.Taylor@Sun.COM state->hs_fw_gpio[1]);
26409517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_MOD1,
26419517SBill.Taylor@Sun.COM state->hs_fw_gpio[2]);
26429517SBill.Taylor@Sun.COM
26439517SBill.Taylor@Sun.COM /* re-lock GPIOs */
26449517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_LOCK, 0);
26459517SBill.Taylor@Sun.COM
26469517SBill.Taylor@Sun.COM /* Give up gpio semaphore */
26479517SBill.Taylor@Sun.COM hermon_flash_write_cfg(state, hdl, HERMON_HW_FLASH_GPIO_SEMA, 0);
26489517SBill.Taylor@Sun.COM
26499517SBill.Taylor@Sun.COM /* the FMA retry loop ends. */
26509517SBill.Taylor@Sun.COM hermon_pio_end(state, hdl, pio_error, fm_loop_cnt, fm_status, fm_test);
26519517SBill.Taylor@Sun.COM return (0);
26529517SBill.Taylor@Sun.COM
26539517SBill.Taylor@Sun.COM pio_error:
26549517SBill.Taylor@Sun.COM hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_IOCTL);
26559517SBill.Taylor@Sun.COM return (EIO);
26569517SBill.Taylor@Sun.COM }
26579517SBill.Taylor@Sun.COM
26589517SBill.Taylor@Sun.COM /*
26599517SBill.Taylor@Sun.COM * hermon_flash_read_cfg
26609517SBill.Taylor@Sun.COM */
26619517SBill.Taylor@Sun.COM static uint32_t
hermon_flash_read_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr)26629517SBill.Taylor@Sun.COM hermon_flash_read_cfg(hermon_state_t *state, ddi_acc_handle_t pci_config_hdl,
26639517SBill.Taylor@Sun.COM uint32_t addr)
26649517SBill.Taylor@Sun.COM {
26659517SBill.Taylor@Sun.COM uint32_t read;
26669517SBill.Taylor@Sun.COM
26679517SBill.Taylor@Sun.COM if (do_bar0) {
26689517SBill.Taylor@Sun.COM read = ddi_get32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
26699517SBill.Taylor@Sun.COM (state->hs_reg_cmd_baseaddr + addr));
26709517SBill.Taylor@Sun.COM } else {
26719517SBill.Taylor@Sun.COM /*
26729517SBill.Taylor@Sun.COM * Perform flash read operation:
26739517SBill.Taylor@Sun.COM * 1) Place addr to read from on the HERMON_HW_FLASH_CFG_ADDR
26749517SBill.Taylor@Sun.COM * register
26759517SBill.Taylor@Sun.COM * 2) Read data at that addr from the HERMON_HW_FLASH_CFG_DATA
26769517SBill.Taylor@Sun.COM * register
26779517SBill.Taylor@Sun.COM */
26789517SBill.Taylor@Sun.COM pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
26799517SBill.Taylor@Sun.COM addr);
26809517SBill.Taylor@Sun.COM read = pci_config_get32(pci_config_hdl,
26819517SBill.Taylor@Sun.COM HERMON_HW_FLASH_CFG_DATA);
26829517SBill.Taylor@Sun.COM }
26839517SBill.Taylor@Sun.COM
26849517SBill.Taylor@Sun.COM return (read);
26859517SBill.Taylor@Sun.COM }
26869517SBill.Taylor@Sun.COM
26879517SBill.Taylor@Sun.COM #ifdef DO_WRCONF
26889517SBill.Taylor@Sun.COM static void
hermon_flash_write_cfg(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl,uint32_t addr,uint32_t data)26899517SBill.Taylor@Sun.COM hermon_flash_write_cfg(hermon_state_t *state,
26909517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
26919517SBill.Taylor@Sun.COM {
26929517SBill.Taylor@Sun.COM hermon_flash_write_cfg_helper(state, pci_config_hdl, addr, data);
26939517SBill.Taylor@Sun.COM hermon_flash_write_confirm(state, pci_config_hdl);
26949517SBill.Taylor@Sun.COM }
26959517SBill.Taylor@Sun.COM
26969517SBill.Taylor@Sun.COM static void
hermon_flash_write_confirm(hermon_state_t * state,ddi_acc_handle_t pci_config_hdl)26979517SBill.Taylor@Sun.COM hermon_flash_write_confirm(hermon_state_t *state,
26989517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl)
26999517SBill.Taylor@Sun.COM {
27009517SBill.Taylor@Sun.COM uint32_t sem_value = 1;
27019517SBill.Taylor@Sun.COM
27029517SBill.Taylor@Sun.COM hermon_flash_write_cfg_helper(state, pci_config_hdl,
27039517SBill.Taylor@Sun.COM HERMON_HW_FLASH_WRCONF_SEMA, 0);
27049517SBill.Taylor@Sun.COM while (sem_value) {
27059517SBill.Taylor@Sun.COM sem_value = hermon_flash_read_cfg(state, pci_config_hdl,
27069517SBill.Taylor@Sun.COM HERMON_HW_FLASH_WRCONF_SEMA);
27079517SBill.Taylor@Sun.COM }
27089517SBill.Taylor@Sun.COM }
27099517SBill.Taylor@Sun.COM #endif
27109517SBill.Taylor@Sun.COM
27119517SBill.Taylor@Sun.COM /*
27129517SBill.Taylor@Sun.COM * hermon_flash_write_cfg
27139517SBill.Taylor@Sun.COM */
27149517SBill.Taylor@Sun.COM static void
27159517SBill.Taylor@Sun.COM #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)27169517SBill.Taylor@Sun.COM hermon_flash_write_cfg_helper(hermon_state_t *state,
27179517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27189517SBill.Taylor@Sun.COM #else
27199517SBill.Taylor@Sun.COM hermon_flash_write_cfg(hermon_state_t *state,
27209517SBill.Taylor@Sun.COM ddi_acc_handle_t pci_config_hdl, uint32_t addr, uint32_t data)
27219517SBill.Taylor@Sun.COM #endif
27229517SBill.Taylor@Sun.COM {
27239517SBill.Taylor@Sun.COM if (do_bar0) {
27249517SBill.Taylor@Sun.COM ddi_put32(hermon_get_cmdhdl(state), (uint32_t *)(void *)
27259517SBill.Taylor@Sun.COM (state->hs_reg_cmd_baseaddr + addr), data);
27269517SBill.Taylor@Sun.COM
27279517SBill.Taylor@Sun.COM } else {
27289517SBill.Taylor@Sun.COM
27299517SBill.Taylor@Sun.COM /*
27309517SBill.Taylor@Sun.COM * Perform flash write operation:
27319517SBill.Taylor@Sun.COM * 1) Place addr to write to on the HERMON_HW_FLASH_CFG_ADDR
27329517SBill.Taylor@Sun.COM * register
27339517SBill.Taylor@Sun.COM * 2) Place data to write on to the HERMON_HW_FLASH_CFG_DATA
27349517SBill.Taylor@Sun.COM * register
27359517SBill.Taylor@Sun.COM */
27369517SBill.Taylor@Sun.COM pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_ADDR,
27379517SBill.Taylor@Sun.COM addr);
27389517SBill.Taylor@Sun.COM pci_config_put32(pci_config_hdl, HERMON_HW_FLASH_CFG_DATA,
27399517SBill.Taylor@Sun.COM data);
27409517SBill.Taylor@Sun.COM }
27419517SBill.Taylor@Sun.COM }
27429517SBill.Taylor@Sun.COM
27439517SBill.Taylor@Sun.COM /*
27449517SBill.Taylor@Sun.COM * Support routines to convert Common Flash Interface (CFI) data
27459517SBill.Taylor@Sun.COM * from a 32 bit word to a char array, and from a char array to
27469517SBill.Taylor@Sun.COM * a 32 bit word.
27479517SBill.Taylor@Sun.COM */
27489517SBill.Taylor@Sun.COM static void
hermon_flash_cfi_byte(uint8_t * ch,uint32_t dword,int i)27499517SBill.Taylor@Sun.COM hermon_flash_cfi_byte(uint8_t *ch, uint32_t dword, int i)
27509517SBill.Taylor@Sun.COM {
27519517SBill.Taylor@Sun.COM ch[i] = (uint8_t)((dword & 0xFF000000) >> 24);
27529517SBill.Taylor@Sun.COM ch[i+1] = (uint8_t)((dword & 0x00FF0000) >> 16);
27539517SBill.Taylor@Sun.COM ch[i+2] = (uint8_t)((dword & 0x0000FF00) >> 8);
27549517SBill.Taylor@Sun.COM ch[i+3] = (uint8_t)((dword & 0x000000FF));
27559517SBill.Taylor@Sun.COM }
27569517SBill.Taylor@Sun.COM
27579517SBill.Taylor@Sun.COM static void
hermon_flash_cfi_dword(uint32_t * dword,uint8_t * ch,int i)27589517SBill.Taylor@Sun.COM hermon_flash_cfi_dword(uint32_t *dword, uint8_t *ch, int i)
27599517SBill.Taylor@Sun.COM {
27609517SBill.Taylor@Sun.COM *dword = (uint32_t)
27619517SBill.Taylor@Sun.COM ((uint32_t)ch[i] << 24 |
27629517SBill.Taylor@Sun.COM (uint32_t)ch[i+1] << 16 |
27639517SBill.Taylor@Sun.COM (uint32_t)ch[i+2] << 8 |
27649517SBill.Taylor@Sun.COM (uint32_t)ch[i+3]);
27659517SBill.Taylor@Sun.COM }
27669517SBill.Taylor@Sun.COM
27679517SBill.Taylor@Sun.COM /*
27689517SBill.Taylor@Sun.COM * hermon_loopback_free_qps
27699517SBill.Taylor@Sun.COM */
27709517SBill.Taylor@Sun.COM static void
hermon_loopback_free_qps(hermon_loopback_state_t * lstate)27719517SBill.Taylor@Sun.COM hermon_loopback_free_qps(hermon_loopback_state_t *lstate)
27729517SBill.Taylor@Sun.COM {
27739517SBill.Taylor@Sun.COM int i;
27749517SBill.Taylor@Sun.COM
27759517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
27769517SBill.Taylor@Sun.COM
27779517SBill.Taylor@Sun.COM if (lstate->hls_tx.hlc_qp_hdl != NULL) {
27789517SBill.Taylor@Sun.COM (void) hermon_qp_free(lstate->hls_state,
27799517SBill.Taylor@Sun.COM &lstate->hls_tx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27809517SBill.Taylor@Sun.COM HERMON_NOSLEEP);
27819517SBill.Taylor@Sun.COM }
27829517SBill.Taylor@Sun.COM if (lstate->hls_rx.hlc_qp_hdl != NULL) {
27839517SBill.Taylor@Sun.COM (void) hermon_qp_free(lstate->hls_state,
27849517SBill.Taylor@Sun.COM &lstate->hls_rx.hlc_qp_hdl, IBC_FREE_QP_AND_QPN, NULL,
27859517SBill.Taylor@Sun.COM HERMON_NOSLEEP);
27869517SBill.Taylor@Sun.COM }
27879517SBill.Taylor@Sun.COM lstate->hls_tx.hlc_qp_hdl = NULL;
27889517SBill.Taylor@Sun.COM lstate->hls_rx.hlc_qp_hdl = NULL;
27899517SBill.Taylor@Sun.COM for (i = 0; i < 2; i++) {
27909517SBill.Taylor@Sun.COM if (lstate->hls_tx.hlc_cqhdl[i] != NULL) {
27919517SBill.Taylor@Sun.COM (void) hermon_cq_free(lstate->hls_state,
27929517SBill.Taylor@Sun.COM &lstate->hls_tx.hlc_cqhdl[i], HERMON_NOSLEEP);
27939517SBill.Taylor@Sun.COM }
27949517SBill.Taylor@Sun.COM if (lstate->hls_rx.hlc_cqhdl[i] != NULL) {
27959517SBill.Taylor@Sun.COM (void) hermon_cq_free(lstate->hls_state,
27969517SBill.Taylor@Sun.COM &lstate->hls_rx.hlc_cqhdl[i], HERMON_NOSLEEP);
27979517SBill.Taylor@Sun.COM }
27989517SBill.Taylor@Sun.COM lstate->hls_tx.hlc_cqhdl[i] = NULL;
27999517SBill.Taylor@Sun.COM lstate->hls_rx.hlc_cqhdl[i] = NULL;
28009517SBill.Taylor@Sun.COM }
28019517SBill.Taylor@Sun.COM }
28029517SBill.Taylor@Sun.COM
28039517SBill.Taylor@Sun.COM /*
28049517SBill.Taylor@Sun.COM * hermon_loopback_free_state
28059517SBill.Taylor@Sun.COM */
28069517SBill.Taylor@Sun.COM static void
hermon_loopback_free_state(hermon_loopback_state_t * lstate)28079517SBill.Taylor@Sun.COM hermon_loopback_free_state(hermon_loopback_state_t *lstate)
28089517SBill.Taylor@Sun.COM {
28099517SBill.Taylor@Sun.COM hermon_loopback_free_qps(lstate);
28109517SBill.Taylor@Sun.COM if (lstate->hls_tx.hlc_mrhdl != NULL) {
28119517SBill.Taylor@Sun.COM (void) hermon_mr_deregister(lstate->hls_state,
28129517SBill.Taylor@Sun.COM &lstate->hls_tx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28139517SBill.Taylor@Sun.COM HERMON_NOSLEEP);
28149517SBill.Taylor@Sun.COM }
28159517SBill.Taylor@Sun.COM if (lstate->hls_rx.hlc_mrhdl != NULL) {
28169517SBill.Taylor@Sun.COM (void) hermon_mr_deregister(lstate->hls_state,
28179517SBill.Taylor@Sun.COM &lstate->hls_rx.hlc_mrhdl, HERMON_MR_DEREG_ALL,
28189517SBill.Taylor@Sun.COM HERMON_NOSLEEP);
28199517SBill.Taylor@Sun.COM }
28209517SBill.Taylor@Sun.COM if (lstate->hls_pd_hdl != NULL) {
28219517SBill.Taylor@Sun.COM (void) hermon_pd_free(lstate->hls_state, &lstate->hls_pd_hdl);
28229517SBill.Taylor@Sun.COM }
28239517SBill.Taylor@Sun.COM if (lstate->hls_tx.hlc_buf != NULL) {
28249517SBill.Taylor@Sun.COM kmem_free(lstate->hls_tx.hlc_buf, lstate->hls_tx.hlc_buf_sz);
28259517SBill.Taylor@Sun.COM }
28269517SBill.Taylor@Sun.COM if (lstate->hls_rx.hlc_buf != NULL) {
28279517SBill.Taylor@Sun.COM kmem_free(lstate->hls_rx.hlc_buf, lstate->hls_rx.hlc_buf_sz);
28289517SBill.Taylor@Sun.COM }
28299517SBill.Taylor@Sun.COM bzero(lstate, sizeof (hermon_loopback_state_t));
28309517SBill.Taylor@Sun.COM }
28319517SBill.Taylor@Sun.COM
28329517SBill.Taylor@Sun.COM /*
28339517SBill.Taylor@Sun.COM * hermon_loopback_init
28349517SBill.Taylor@Sun.COM */
28359517SBill.Taylor@Sun.COM static int
hermon_loopback_init(hermon_state_t * state,hermon_loopback_state_t * lstate)28369517SBill.Taylor@Sun.COM hermon_loopback_init(hermon_state_t *state, hermon_loopback_state_t *lstate)
28379517SBill.Taylor@Sun.COM {
28389517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
28399517SBill.Taylor@Sun.COM
28409517SBill.Taylor@Sun.COM lstate->hls_hca_hdl = (ibc_hca_hdl_t)state;
28419517SBill.Taylor@Sun.COM lstate->hls_status = hermon_pd_alloc(lstate->hls_state,
28429517SBill.Taylor@Sun.COM &lstate->hls_pd_hdl, HERMON_NOSLEEP);
28439517SBill.Taylor@Sun.COM if (lstate->hls_status != IBT_SUCCESS) {
28449517SBill.Taylor@Sun.COM lstate->hls_err = HERMON_LOOPBACK_PROT_DOMAIN_ALLOC_FAIL;
28459517SBill.Taylor@Sun.COM return (EFAULT);
28469517SBill.Taylor@Sun.COM }
28479517SBill.Taylor@Sun.COM
28489517SBill.Taylor@Sun.COM return (0);
28499517SBill.Taylor@Sun.COM }
28509517SBill.Taylor@Sun.COM
28519517SBill.Taylor@Sun.COM /*
28529517SBill.Taylor@Sun.COM * hermon_loopback_init_qp_info
28539517SBill.Taylor@Sun.COM */
28549517SBill.Taylor@Sun.COM static void
hermon_loopback_init_qp_info(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)28559517SBill.Taylor@Sun.COM hermon_loopback_init_qp_info(hermon_loopback_state_t *lstate,
28569517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm)
28579517SBill.Taylor@Sun.COM {
28589517SBill.Taylor@Sun.COM bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
28599517SBill.Taylor@Sun.COM bzero(&comm->hlc_qp_attr, sizeof (ibt_qp_alloc_attr_t));
28609517SBill.Taylor@Sun.COM bzero(&comm->hlc_qp_info, sizeof (ibt_qp_info_t));
28619517SBill.Taylor@Sun.COM
28629517SBill.Taylor@Sun.COM comm->hlc_wrid = 1;
28639517SBill.Taylor@Sun.COM comm->hlc_cq_attr.cq_size = 128;
28649517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_sizes.cs_sq_sgl = 3;
28659517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_sizes.cs_rq_sgl = 3;
28669517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_sizes.cs_sq = 16;
28679517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_sizes.cs_rq = 16;
28689517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_flags = IBT_WR_SIGNALED;
28699517SBill.Taylor@Sun.COM
28709517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_state = IBT_STATE_RESET;
28719517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_trans = IBT_RC_SRV;
28729517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_flags = IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR;
28739517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
28749517SBill.Taylor@Sun.COM lstate->hls_port;
28759517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_pkey_ix =
28769517SBill.Taylor@Sun.COM lstate->hls_pkey_ix;
28779517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_timeout =
28789517SBill.Taylor@Sun.COM lstate->hls_timeout;
28799517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srvl = 0;
28809517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_srate =
28819517SBill.Taylor@Sun.COM IBT_SRATE_4X;
28829517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_send_grh = 0;
28839517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid =
28849517SBill.Taylor@Sun.COM lstate->hls_lid;
28859517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_retry_cnt = lstate->hls_retry;
28869517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_sq_psn = 0;
28879517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_rq_psn = 0;
28889517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_in = 4;
28899517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_rdma_ra_out = 4;
28909517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = 0;
28919517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_min_rnr_nak = IBT_RNR_NAK_655ms;
28929517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path_mtu = IB_MTU_1K;
28939517SBill.Taylor@Sun.COM }
28949517SBill.Taylor@Sun.COM
28959517SBill.Taylor@Sun.COM /*
28969517SBill.Taylor@Sun.COM * hermon_loopback_alloc_mem
28979517SBill.Taylor@Sun.COM */
28989517SBill.Taylor@Sun.COM static int
hermon_loopback_alloc_mem(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,int sz)28999517SBill.Taylor@Sun.COM hermon_loopback_alloc_mem(hermon_loopback_state_t *lstate,
29009517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm, int sz)
29019517SBill.Taylor@Sun.COM {
29029517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29039517SBill.Taylor@Sun.COM
29049517SBill.Taylor@Sun.COM /* Allocate buffer of specified size */
29059517SBill.Taylor@Sun.COM comm->hlc_buf_sz = sz;
29069517SBill.Taylor@Sun.COM comm->hlc_buf = kmem_zalloc(sz, KM_NOSLEEP);
29079517SBill.Taylor@Sun.COM if (comm->hlc_buf == NULL) {
29089517SBill.Taylor@Sun.COM return (EFAULT);
29099517SBill.Taylor@Sun.COM }
29109517SBill.Taylor@Sun.COM
29119517SBill.Taylor@Sun.COM /* Register the buffer as a memory region */
29129517SBill.Taylor@Sun.COM comm->hlc_memattr.mr_vaddr = (uint64_t)(uintptr_t)comm->hlc_buf;
29139517SBill.Taylor@Sun.COM comm->hlc_memattr.mr_len = (ib_msglen_t)sz;
29149517SBill.Taylor@Sun.COM comm->hlc_memattr.mr_as = NULL;
29159517SBill.Taylor@Sun.COM comm->hlc_memattr.mr_flags = IBT_MR_NOSLEEP |
29169517SBill.Taylor@Sun.COM IBT_MR_ENABLE_REMOTE_WRITE | IBT_MR_ENABLE_LOCAL_WRITE;
29179517SBill.Taylor@Sun.COM
29189517SBill.Taylor@Sun.COM comm->hlc_status = hermon_mr_register(lstate->hls_state,
29199517SBill.Taylor@Sun.COM lstate->hls_pd_hdl, &comm->hlc_memattr, &comm->hlc_mrhdl,
29209517SBill.Taylor@Sun.COM NULL, HERMON_MPT_DMPT);
29219517SBill.Taylor@Sun.COM
29229517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm->hlc_mrhdl))
29239517SBill.Taylor@Sun.COM
29249517SBill.Taylor@Sun.COM comm->hlc_mrdesc.md_vaddr = comm->hlc_mrhdl->mr_bindinfo.bi_addr;
29259517SBill.Taylor@Sun.COM comm->hlc_mrdesc.md_lkey = comm->hlc_mrhdl->mr_lkey;
29269517SBill.Taylor@Sun.COM comm->hlc_mrdesc.md_rkey = comm->hlc_mrhdl->mr_rkey;
29279517SBill.Taylor@Sun.COM if (comm->hlc_status != IBT_SUCCESS) {
29289517SBill.Taylor@Sun.COM return (EFAULT);
29299517SBill.Taylor@Sun.COM }
29309517SBill.Taylor@Sun.COM return (0);
29319517SBill.Taylor@Sun.COM }
29329517SBill.Taylor@Sun.COM
29339517SBill.Taylor@Sun.COM /*
29349517SBill.Taylor@Sun.COM * hermon_loopback_alloc_qps
29359517SBill.Taylor@Sun.COM */
29369517SBill.Taylor@Sun.COM static int
hermon_loopback_alloc_qps(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)29379517SBill.Taylor@Sun.COM hermon_loopback_alloc_qps(hermon_loopback_state_t *lstate,
29389517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm)
29399517SBill.Taylor@Sun.COM {
29409517SBill.Taylor@Sun.COM uint32_t i, real_size;
29419517SBill.Taylor@Sun.COM hermon_qp_info_t qpinfo;
29429517SBill.Taylor@Sun.COM
29439517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29449517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29459517SBill.Taylor@Sun.COM
29469517SBill.Taylor@Sun.COM /* Allocate send and recv CQs */
29479517SBill.Taylor@Sun.COM for (i = 0; i < 2; i++) {
29489517SBill.Taylor@Sun.COM bzero(&comm->hlc_cq_attr, sizeof (ibt_cq_attr_t));
29499517SBill.Taylor@Sun.COM comm->hlc_cq_attr.cq_size = 128;
29509517SBill.Taylor@Sun.COM comm->hlc_status = hermon_cq_alloc(lstate->hls_state,
29519517SBill.Taylor@Sun.COM (ibt_cq_hdl_t)NULL, &comm->hlc_cq_attr, &real_size,
29529517SBill.Taylor@Sun.COM &comm->hlc_cqhdl[i], HERMON_NOSLEEP);
29539517SBill.Taylor@Sun.COM if (comm->hlc_status != IBT_SUCCESS) {
29549517SBill.Taylor@Sun.COM lstate->hls_err += i;
29559517SBill.Taylor@Sun.COM return (EFAULT);
29569517SBill.Taylor@Sun.COM }
29579517SBill.Taylor@Sun.COM }
29589517SBill.Taylor@Sun.COM
29599517SBill.Taylor@Sun.COM /* Allocate the QP */
29609517SBill.Taylor@Sun.COM hermon_loopback_init_qp_info(lstate, comm);
29619517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_pd_hdl = (ibt_pd_hdl_t)lstate->hls_pd_hdl;
29629517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_scq_hdl = (ibt_cq_hdl_t)comm->hlc_cqhdl[0];
29639517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_rcq_hdl = (ibt_cq_hdl_t)comm->hlc_cqhdl[1];
29649517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_ibc_scq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[0];
29659517SBill.Taylor@Sun.COM comm->hlc_qp_attr.qp_ibc_rcq_hdl = (ibt_opaque1_t)comm->hlc_cqhdl[1];
29669517SBill.Taylor@Sun.COM qpinfo.qpi_attrp = &comm->hlc_qp_attr;
29679517SBill.Taylor@Sun.COM qpinfo.qpi_type = IBT_RC_RQP;
29689517SBill.Taylor@Sun.COM qpinfo.qpi_ibt_qphdl = NULL;
29699517SBill.Taylor@Sun.COM qpinfo.qpi_queueszp = &comm->hlc_chan_sizes;
29709517SBill.Taylor@Sun.COM qpinfo.qpi_qpn = &comm->hlc_qp_num;
29719517SBill.Taylor@Sun.COM comm->hlc_status = hermon_qp_alloc(lstate->hls_state, &qpinfo,
29729517SBill.Taylor@Sun.COM HERMON_NOSLEEP);
29739517SBill.Taylor@Sun.COM if (comm->hlc_status == DDI_SUCCESS) {
29749517SBill.Taylor@Sun.COM comm->hlc_qp_hdl = qpinfo.qpi_qphdl;
29759517SBill.Taylor@Sun.COM }
29769517SBill.Taylor@Sun.COM
29779517SBill.Taylor@Sun.COM if (comm->hlc_status != IBT_SUCCESS) {
29789517SBill.Taylor@Sun.COM lstate->hls_err += 2;
29799517SBill.Taylor@Sun.COM return (EFAULT);
29809517SBill.Taylor@Sun.COM }
29819517SBill.Taylor@Sun.COM return (0);
29829517SBill.Taylor@Sun.COM }
29839517SBill.Taylor@Sun.COM
29849517SBill.Taylor@Sun.COM /*
29859517SBill.Taylor@Sun.COM * hermon_loopback_modify_qp
29869517SBill.Taylor@Sun.COM */
29879517SBill.Taylor@Sun.COM static int
hermon_loopback_modify_qp(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm,uint_t qp_num)29889517SBill.Taylor@Sun.COM hermon_loopback_modify_qp(hermon_loopback_state_t *lstate,
29899517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm, uint_t qp_num)
29909517SBill.Taylor@Sun.COM {
29919517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
29929517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lstate))
29939517SBill.Taylor@Sun.COM
29949517SBill.Taylor@Sun.COM /* Modify QP to INIT */
29959517SBill.Taylor@Sun.COM hermon_loopback_init_qp_info(lstate, comm);
29969517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_state = IBT_STATE_INIT;
29979517SBill.Taylor@Sun.COM comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
29989517SBill.Taylor@Sun.COM IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
29999517SBill.Taylor@Sun.COM if (comm->hlc_status != IBT_SUCCESS) {
30009517SBill.Taylor@Sun.COM return (EFAULT);
30019517SBill.Taylor@Sun.COM }
30029517SBill.Taylor@Sun.COM
30039517SBill.Taylor@Sun.COM /*
30049517SBill.Taylor@Sun.COM * Modify QP to RTR (set destination LID and QP number to local
30059517SBill.Taylor@Sun.COM * LID and QP number)
30069517SBill.Taylor@Sun.COM */
30079517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_state = IBT_STATE_RTR;
30089517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_path.cep_adds_vect.av_dlid
30099517SBill.Taylor@Sun.COM = lstate->hls_lid;
30109517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_transport.rc.rc_dst_qpn = qp_num;
30119517SBill.Taylor@Sun.COM comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30129517SBill.Taylor@Sun.COM IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30139517SBill.Taylor@Sun.COM if (comm->hlc_status != IBT_SUCCESS) {
30149517SBill.Taylor@Sun.COM lstate->hls_err += 1;
30159517SBill.Taylor@Sun.COM return (EFAULT);
30169517SBill.Taylor@Sun.COM }
30179517SBill.Taylor@Sun.COM
30189517SBill.Taylor@Sun.COM /* Modify QP to RTS */
30199517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_current_state = IBT_STATE_RTR;
30209517SBill.Taylor@Sun.COM comm->hlc_qp_info.qp_state = IBT_STATE_RTS;
30219517SBill.Taylor@Sun.COM comm->hlc_status = hermon_qp_modify(lstate->hls_state, comm->hlc_qp_hdl,
30229517SBill.Taylor@Sun.COM IBT_CEP_SET_STATE, &comm->hlc_qp_info, &comm->hlc_queue_sizes);
30239517SBill.Taylor@Sun.COM if (comm->hlc_status != IBT_SUCCESS) {
30249517SBill.Taylor@Sun.COM lstate->hls_err += 2;
30259517SBill.Taylor@Sun.COM return (EFAULT);
30269517SBill.Taylor@Sun.COM }
30279517SBill.Taylor@Sun.COM return (0);
30289517SBill.Taylor@Sun.COM }
30299517SBill.Taylor@Sun.COM
30309517SBill.Taylor@Sun.COM /*
30319517SBill.Taylor@Sun.COM * hermon_loopback_copyout
30329517SBill.Taylor@Sun.COM */
30339517SBill.Taylor@Sun.COM static int
hermon_loopback_copyout(hermon_loopback_ioctl_t * lb,intptr_t arg,int mode)30349517SBill.Taylor@Sun.COM hermon_loopback_copyout(hermon_loopback_ioctl_t *lb, intptr_t arg, int mode)
30359517SBill.Taylor@Sun.COM {
30369517SBill.Taylor@Sun.COM #ifdef _MULTI_DATAMODEL
30379517SBill.Taylor@Sun.COM if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
30389517SBill.Taylor@Sun.COM hermon_loopback_ioctl32_t lb32;
30399517SBill.Taylor@Sun.COM
30409517SBill.Taylor@Sun.COM lb32.alb_revision = lb->alb_revision;
30419517SBill.Taylor@Sun.COM lb32.alb_send_buf =
30429517SBill.Taylor@Sun.COM (caddr32_t)(uintptr_t)lb->alb_send_buf;
30439517SBill.Taylor@Sun.COM lb32.alb_fail_buf =
30449517SBill.Taylor@Sun.COM (caddr32_t)(uintptr_t)lb->alb_fail_buf;
30459517SBill.Taylor@Sun.COM lb32.alb_buf_sz = lb->alb_buf_sz;
30469517SBill.Taylor@Sun.COM lb32.alb_num_iter = lb->alb_num_iter;
30479517SBill.Taylor@Sun.COM lb32.alb_pass_done = lb->alb_pass_done;
30489517SBill.Taylor@Sun.COM lb32.alb_timeout = lb->alb_timeout;
30499517SBill.Taylor@Sun.COM lb32.alb_error_type = lb->alb_error_type;
30509517SBill.Taylor@Sun.COM lb32.alb_port_num = lb->alb_port_num;
30519517SBill.Taylor@Sun.COM lb32.alb_num_retry = lb->alb_num_retry;
30529517SBill.Taylor@Sun.COM
30539517SBill.Taylor@Sun.COM if (ddi_copyout(&lb32, (void *)arg,
30549517SBill.Taylor@Sun.COM sizeof (hermon_loopback_ioctl32_t), mode) != 0) {
30559517SBill.Taylor@Sun.COM return (EFAULT);
30569517SBill.Taylor@Sun.COM }
30579517SBill.Taylor@Sun.COM } else
30589517SBill.Taylor@Sun.COM #endif /* _MULTI_DATAMODEL */
30599517SBill.Taylor@Sun.COM if (ddi_copyout(lb, (void *)arg, sizeof (hermon_loopback_ioctl_t),
30609517SBill.Taylor@Sun.COM mode) != 0) {
30619517SBill.Taylor@Sun.COM return (EFAULT);
30629517SBill.Taylor@Sun.COM }
30639517SBill.Taylor@Sun.COM return (0);
30649517SBill.Taylor@Sun.COM }
30659517SBill.Taylor@Sun.COM
30669517SBill.Taylor@Sun.COM /*
30679517SBill.Taylor@Sun.COM * hermon_loopback_post_send
30689517SBill.Taylor@Sun.COM */
30699517SBill.Taylor@Sun.COM static int
hermon_loopback_post_send(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * tx,hermon_loopback_comm_t * rx)30709517SBill.Taylor@Sun.COM hermon_loopback_post_send(hermon_loopback_state_t *lstate,
30719517SBill.Taylor@Sun.COM hermon_loopback_comm_t *tx, hermon_loopback_comm_t *rx)
30729517SBill.Taylor@Sun.COM {
30739517SBill.Taylor@Sun.COM int ret;
30749517SBill.Taylor@Sun.COM
30759517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tx))
30769517SBill.Taylor@Sun.COM
30779517SBill.Taylor@Sun.COM bzero(&tx->hlc_sgl, sizeof (ibt_wr_ds_t));
30789517SBill.Taylor@Sun.COM bzero(&tx->hlc_wr, sizeof (ibt_send_wr_t));
30799517SBill.Taylor@Sun.COM
30809517SBill.Taylor@Sun.COM /* Initialize local address for TX buffer */
30819517SBill.Taylor@Sun.COM tx->hlc_sgl.ds_va = tx->hlc_mrdesc.md_vaddr;
30829517SBill.Taylor@Sun.COM tx->hlc_sgl.ds_key = tx->hlc_mrdesc.md_lkey;
30839517SBill.Taylor@Sun.COM tx->hlc_sgl.ds_len = tx->hlc_buf_sz;
30849517SBill.Taylor@Sun.COM
30859517SBill.Taylor@Sun.COM /* Initialize the remaining details of the work request */
30869517SBill.Taylor@Sun.COM tx->hlc_wr.wr_id = tx->hlc_wrid++;
30879517SBill.Taylor@Sun.COM tx->hlc_wr.wr_flags = IBT_WR_SEND_SIGNAL;
30889517SBill.Taylor@Sun.COM tx->hlc_wr.wr_nds = 1;
30899517SBill.Taylor@Sun.COM tx->hlc_wr.wr_sgl = &tx->hlc_sgl;
30909517SBill.Taylor@Sun.COM tx->hlc_wr.wr_opcode = IBT_WRC_RDMAW;
30919517SBill.Taylor@Sun.COM tx->hlc_wr.wr_trans = IBT_RC_SRV;
30929517SBill.Taylor@Sun.COM
30939517SBill.Taylor@Sun.COM /* Initialize the remote address for RX buffer */
30949517SBill.Taylor@Sun.COM tx->hlc_wr.wr.rc.rcwr.rdma.rdma_raddr = rx->hlc_mrdesc.md_vaddr;
30959517SBill.Taylor@Sun.COM tx->hlc_wr.wr.rc.rcwr.rdma.rdma_rkey = rx->hlc_mrdesc.md_rkey;
30969517SBill.Taylor@Sun.COM tx->hlc_complete = 0;
30979517SBill.Taylor@Sun.COM ret = hermon_post_send(lstate->hls_state, tx->hlc_qp_hdl, &tx->hlc_wr,
30989517SBill.Taylor@Sun.COM 1, NULL);
30999517SBill.Taylor@Sun.COM if (ret != IBT_SUCCESS) {
31009517SBill.Taylor@Sun.COM return (EFAULT);
31019517SBill.Taylor@Sun.COM }
31029517SBill.Taylor@Sun.COM return (0);
31039517SBill.Taylor@Sun.COM }
31049517SBill.Taylor@Sun.COM
31059517SBill.Taylor@Sun.COM /*
31069517SBill.Taylor@Sun.COM * hermon_loopback_poll_cq
31079517SBill.Taylor@Sun.COM */
31089517SBill.Taylor@Sun.COM static int
hermon_loopback_poll_cq(hermon_loopback_state_t * lstate,hermon_loopback_comm_t * comm)31099517SBill.Taylor@Sun.COM hermon_loopback_poll_cq(hermon_loopback_state_t *lstate,
31109517SBill.Taylor@Sun.COM hermon_loopback_comm_t *comm)
31119517SBill.Taylor@Sun.COM {
31129517SBill.Taylor@Sun.COM _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*comm))
31139517SBill.Taylor@Sun.COM
31149517SBill.Taylor@Sun.COM comm->hlc_wc.wc_status = 0;
31159517SBill.Taylor@Sun.COM comm->hlc_num_polled = 0;
31169517SBill.Taylor@Sun.COM comm->hlc_status = hermon_cq_poll(lstate->hls_state,
31179517SBill.Taylor@Sun.COM comm->hlc_cqhdl[0], &comm->hlc_wc, 1, &comm->hlc_num_polled);
31189517SBill.Taylor@Sun.COM if ((comm->hlc_status == IBT_SUCCESS) &&
31199517SBill.Taylor@Sun.COM (comm->hlc_wc.wc_status != IBT_WC_SUCCESS)) {
31209517SBill.Taylor@Sun.COM comm->hlc_status = ibc_get_ci_failure(0);
31219517SBill.Taylor@Sun.COM }
31229517SBill.Taylor@Sun.COM return (comm->hlc_status);
31239517SBill.Taylor@Sun.COM }
3124