/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright 2010 QLogic Corporation */
/*
*/
#pragma ident "Copyright 2010 QLogic Corporation; ql_ioctl.c"
/*
* ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
* Fibre Channel Adapter (FCA) driver IOCTL source file.
*
* ***********************************************************************
* * **
* * NOTICE **
* * COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION **
* * ALL RIGHTS RESERVED **
* * **
* ***********************************************************************
*
*/
#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
#include <ql_init.h>
#include <ql_ioctl.h>
#include <ql_mbx.h>
#include <ql_xioctl.h>
/*
* Local Function Prototypes.
*/
static int ql_busy_notification(ql_adapter_state_t *);
static int ql_idle_notification(ql_adapter_state_t *);
static int ql_adm_op(ql_adapter_state_t *, void *, int);
static int ql_adm_update_properties(ql_adapter_state_t *);
static int ql_adm_loop_reset(ql_adapter_state_t *);
/* ************************************************************************ */
/* cb_ops functions */
/* ************************************************************************ */
/*
* ql_open
* opens device
*
* Input:
* dev_p = device pointer
* flags = open flags
* otype = open type
* cred_p = credentials pointer
*
* Returns:
* 0 = success
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
int
{
int rval = 0;
return (ENXIO);
}
/* Allow only character opens */
return (EINVAL);
}
} else {
}
if (rval != 0) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_close
* opens device
*
* Input:
* dev_p = device pointer
* flags = open flags
* otype = open type
* cred_p = credentials pointer
*
* Returns:
* 0 = success
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
int
{
int rval = 0;
return (ENXIO);
}
return (EINVAL);
}
if (rval != 0) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_ioctl
* control a character device
*
* Input:
* dev = device number
* cmd = function to perform
* arg = data type varies with request
* mode = flags
* cred_p = credentials pointer
* rval_p = pointer to result value
*
* Returns:
* 0 = success
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
int
int *rval_p)
{
int rval = 0;
if (ddi_in_panic()) {
return (ENOPROTOOPT);
}
return (ENXIO);
}
/*
* Quick clean exit for qla2x00 foapi calls which are
* not supported in qlc.
*/
return (ENOTTY);
}
/* PWR management busy. */
if (rval != FC_SUCCESS) {
return (ENXIO);
}
switch (cmd) {
case QL_GET_ADAPTER_FEATURE_BITS: {
}
break;
}
case QL_SET_ADAPTER_FEATURE_BITS: {
break;
}
break;
}
break;
case QL_UTIL_LOAD:
break;
case QL_UTIL_DUMP:
break;
case QL_ADM_OP:
break;
default:
break;
}
}
/* PWR management idle. */
(void) ql_idle_notification(ha);
if (rval != 0) {
/*
* Don't show failures caused by pps polling for
* non-existant virtual ports.
*/
if (cmd != EXT_CC_VPORT_CMD) {
}
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_busy_notification
* Adapter busy notification.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* FC_SUCCESS
* FC_FAILURE
*
* Context:
* Kernel context.
*/
static int
{
if (!ha->pm_capable) {
return (FC_SUCCESS);
}
QL_PM_LOCK(ha);
QL_PM_LOCK(ha);
return (FC_FAILURE);
}
QL_PM_LOCK(ha);
QL_PM_LOCK(ha);
return (FC_FAILURE);
}
} else {
}
return (FC_SUCCESS);
}
/*
* ql_idle_notification
* Adapter idle notification.
*
* Input:
* ha = adapter state pointer.
*
* Returns:
* FC_SUCCESS
* FC_FAILURE
*
* Context:
* Kernel context.
*/
static int
{
if (!ha->pm_capable) {
return (FC_SUCCESS);
}
return (FC_FAILURE);
}
QL_PM_LOCK(ha);
return (FC_SUCCESS);
}
/*
* Get adapter feature bits from NVRAM
*/
static int
{
int count;
int rval;
return (EINVAL);
}
/*
* The offset can't be greater than max of 8 bits and
* the following code breaks if the offset isn't at
* 2 byte boundary.
*/
if (rval != QL_SUCCESS) {
return (EIO);
}
/*
* Have the most significant 3 bits represent the read operation
* followed by the 8 bits representing the offset at which we
* are going to perform the read operation
*/
offset >>= 1;
offset += start_addr;
nv_cmd <<= 5;
/*
* Select the chip and feed the command and address
*/
} else {
ql_nv_write(ha, 0);
}
nv_cmd <<= 1;
}
*features = 0;
ql_nv_delay();
*features <<= 1;
if (data & NV_DATA_IN) {
}
ql_nv_delay();
}
/*
* Deselect the chip
*/
return (0);
}
/*
* Set adapter feature bits in NVRAM
*/
static int
{
int rval;
return (EINVAL);
}
return (ENOMEM);
}
if (rval != QL_SUCCESS) {
return (EIO);
}
rval = 0;
/*
* Read off the whole NVRAM
*/
csum = 0;
wptr++;
}
/*
* If the checksum is BAD then fail it right here.
*/
if (csum) {
return (EBADF);
}
/*
* Recompute the chesksum now
*/
}
/*
* Now load the NVRAM
*/
}
/*
* Read NVRAM and verify the contents
*/
csum = 0;
break;
}
wptr++;
}
if (csum) {
}
return (rval);
}
/*
* Fix this function to update just feature bits and checksum in NVRAM
*/
static int
{
int rval;
if (rval != QL_SUCCESS) {
return (EIO);
}
rval = 0;
return (ENOMEM);
}
/*
* Set default host adapter parameters
*/
/*
* compute the chesksum now
*/
csum = 0;
longptr++;
}
LITTLE_ENDIAN_32((long)csum);
/*
* Now load the NVRAM
*/
(void) ql_24xx_load_nvram(ha,
}
/*
* Read NVRAM and verify the contents
*/
csum = 0;
longptr);
if (rval != QL_SUCCESS) {
break;
}
}
if (csum) {
}
} else {
return (ENOMEM);
}
/*
* Set default initialization control block.
*/
/*
* Set default host adapter parameters
*/
/*
* compute the chesksum now
*/
csum = 0;
}
/*
* Now load the NVRAM
*/
*wptr++);
}
/*
* Read NVRAM and verify the contents
*/
csum = 0;
*wptr) {
break;
}
wptr++;
}
if (csum) {
}
}
return (rval);
}
static void
{
int count;
ql_nv_write(ha, 0);
ql_nv_write(ha, 0);
}
/*
* Deselect the chip
*/
ql_nv_delay();
/*
* Erase Location
*/
nv_cmd <<= 5;
} else {
ql_nv_write(ha, 0);
}
nv_cmd <<= 1;
}
/*
* Wait for Erase to Finish
*/
ql_nv_delay();
word = 0;
while ((word & NV_DATA_IN) == 0) {
ql_nv_delay();
}
ql_nv_delay();
/*
* Write data now
*/
nv_cmd <<= 5;
} else {
ql_nv_write(ha, 0);
}
nv_cmd <<= 1;
}
/*
* Wait for NVRAM to become ready
*/
ql_nv_delay();
word = 0;
while ((word & NV_DATA_IN) == 0) {
ql_nv_delay();
}
ql_nv_delay();
/*
* Disable writes
*/
ql_nv_write(ha, 0);
}
/*
* Deselect the chip now
*/
}
/*
* ql_24xx_load_nvram
* Enable NVRAM and writes a 32bit word to ISP24xx NVRAM.
*
* Input:
* ha: adapter state pointer.
* addr: NVRAM address.
* value: data.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
static int
{
int rval;
/* Enable flash write. */
}
/* Disable NVRAM write-protection. */
} else {
return (rval);
}
}
/* Write to flash. */
/* Enable NVRAM write-protection. */
/* TODO: Check if 0x8c is correct -- sb: 0x9c ? */
} else {
}
/* Disable flash write. */
}
return (rval);
}
/*
* ql_nv_util_load
* Loads NVRAM from application.
*
* Input:
* ha = adapter state pointer.
* bp = user buffer address.
*
* Returns:
*
* Context:
* Kernel context.
*/
int
{
void *nv;
int rval;
return (ENOMEM);
}
return (EFAULT);
}
/* See if the buffer passed to us looks sane */
return (EINVAL);
}
/* Quiesce I/O */
return (EBUSY);
}
if (rval != QL_SUCCESS) {
return (EIO);
}
/* Load NVRAM. */
start_addr <<= 2;
}
data32);
if (rval != QL_SUCCESS) {
break;
}
}
} else {
}
}
/* switch to the new one */
if (rval == QL_SUCCESS) {
return (0);
}
return (EFAULT);
}
/*
* ql_nv_util_dump
* Dumps NVRAM to application.
*
* Input:
* ha = adapter state pointer.
* bp = user buffer address.
*
* Returns:
*
* Context:
* Kernel context.
*/
int
{
return (ENOMEM);
/* Quiesce I/O */
return (EBUSY);
}
if (rval2 != QL_SUCCESS) {
return (EIO);
}
if (rval2 != QL_SUCCESS) {
} else {
}
if (rval != 0) {
return (rval);
}
}
return (EFAULT);
}
return (0);
}
int
{
int cnt;
/* Dump NVRAM. */
if (rval != QL_SUCCESS) {
break;
}
lptr++;
}
} else {
src_addr);
}
}
return (rval);
}
/*
* ql_vpd_load
* Loads VPD from application.
*
* Input:
* ha = adapter state pointer.
* bp = user buffer address.
*
* Returns:
*
* Context:
* Kernel context.
*/
int
{
int rval;
return (ENOTSUP);
}
return (ENOMEM);
}
return (EFAULT);
}
/* Sanity check the user supplied data via checksum */
return (EINVAL);
}
vpdptr += 3;
cnt = 0;
}
if (cnt != 0) {
return (EINVAL);
}
/* Quiesce I/O */
return (EBUSY);
}
if (rval != QL_SUCCESS) {
return (EIO);
}
/* Load VPD. */
start_addr <<= 2;
mode)) != QL_SUCCESS) {
}
} else {
data32);
if (rval != QL_SUCCESS) {
break;
}
}
}
/* Update the vcache */
CACHE_LOCK(ha);
if (rval != QL_SUCCESS) {
}
if (rval == QL_SUCCESS) {
return (0);
}
return (EFAULT);
}
/*
* ql_vpd_dump
* Dumps VPD to application buffer.
*
* Input:
* ha = adapter state pointer.
* bp = user buffer address.
*
* Returns:
*
* Context:
* Kernel context.
*/
int
{
void *vpd;
int rval = 0;
return (EACCES);
}
CACHE_LOCK(ha);
/* copy back the vpd cache data */
}
return (rval);
}
return (ENOMEM);
}
/* Quiesce I/O */
return (EBUSY);
}
if (rval != QL_SUCCESS) {
return (EIO);
}
/* Dump VPD. */
if (rval != QL_SUCCESS) {
break;
}
lptr++;
}
return (EFAULT);
}
if (rval != QL_SUCCESS) {
return (EFAULT);
} else {
return (0);
}
}
/*
* ql_vpd_findtag
* Search the passed vpd buffer for the requested VPD tag type.
*
* Input:
* ha = adapter state pointer.
* vpdbuf = Pointer to start of the buffer to search
* op = VPD opcode to find (must be NULL terminated).
*
* Returns:
* Pointer to the opcode in the buffer if opcode found.
* NULL if opcode is not found.
*
* Context:
* Kernel context.
*/
static uint8_t *
{
return (NULL);
}
/* check for end of vpd */
if (vpd[0] == VPD_TAG_END) {
if (opcode[0] == VPD_TAG_END) {
found = 1;
} else {
found = 0;
}
break;
}
/* check opcode */
/* found opcode requested */
found = 1;
break;
}
/*
* Didn't find the opcode, so calculate start of
* next tag. Depending on the current tag type,
* the length field can be 1 or 2 bytes
*/
vpd += 3;
} else {
}
}
}
/*
* ql_vpd_lookup
* Return the VPD data for the request VPD tag
*
* Input:
* ha = adapter state pointer.
* opcode = VPD opcode to find (must be NULL terminated).
* bp = Pointer to returned data buffer.
* bplen = Length of returned data buffer.
*
* Returns:
* Length of data copied into returned data buffer.
* >0 = VPD data field (NULL terminated)
* 0 = no data.
* -1 = Could not find opcode in vpd buffer / error.
*
* Context:
* Kernel context.
*
* NB: The opcode buffer and the bp buffer *could* be the same buffer!
*
*/
{
return (len);
}
return (len);
}
return (len);
}
return (len);
}
/*
* Found the tag
*/
*opcode == VPD_TAG_LRTC) {
/*
* we found it, but the tag doesn't have a data
* field.
*/
len = 0;
VPD_TAG_PRODID, 1))) {
} else {
}
/*
* make sure that the vpd len doesn't exceed the
* vpd end
*/
"length\n", len);
len = -1;
}
}
if (len >= 0) {
/*
* make sure we don't exceed callers buffer space len
*/
}
/* copy the data back */
} else {
/* error -- couldn't find tag */
} else {
}
}
return (len);
}
/*
* ql_r_m_w_flash
* Read modify write from user space to flash.
*
* Input:
* ha: adapter state pointer.
* dp: source byte pointer.
* bc: byte count.
* faddr: flash byte address.
* mode: flags.
*
* Returns:
* ql local function return status code.
*
* Context:
* Kernel context.
*/
int
int mode)
{
int rval = 0;
return (QL_MEMORY_ALLOC_FAILED);
}
while (bc) {
}
/* Dump Flash sector. */
QL_SUCCESS) {
break;
}
}
/* Set new data. */
mode)) != 0) {
break;
}
/* Write to flash. */
QL_SUCCESS) {
break;
}
ofst = 0;
}
return (rval);
}
/*
* ql_adm_op
* Performs qladm utility operations
*
* Input:
* ha: adapter state pointer.
* arg: driver_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval = 0;
return (EFAULT);
}
case QL_ADAPTER_INFO:
break;
case QL_EXTENDED_LOGGING:
break;
case QL_LOOP_RESET:
break;
case QL_DEVICE_LIST:
break;
case QL_PROP_UPDATE_INT:
break;
case QL_UPDATE_PROPERTIES:
break;
case QL_FW_DUMP:
break;
case QL_NVRAM_LOAD:
break;
case QL_NVRAM_DUMP:
break;
case QL_FLASH_LOAD:
break;
case QL_VPD_LOAD:
break;
case QL_VPD_DUMP:
break;
case QL_VPD_GETTAG:
break;
case QL_UPD_FWMODULE:
break;
default:
return (EINVAL);
}
return (rval);
}
/*
* ql_adm_adapter_info
* Performs qladm QL_ADAPTER_INFO command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval, i;
return (EBUSY);
}
if (rval == QL_FUNCTION_TIMEOUT) {
return (EBUSY);
}
return (EIO);
}
/* Resume I/O */
} else {
}
}
/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
length = i;
if (rval != DDI_PROP_SUCCESS) {
} else {
}
}
return (EFAULT);
}
return (0);
}
/*
* ql_adm_extended_logging
* Performs qladm QL_EXTENDED_LOGGING command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
/*LINTED [Solaris DDI_DEV_T_NONE Lint warning]*/
if (rval != DDI_PROP_SUCCESS) {
return (EINVAL);
} else {
}
return (0);
}
/*
* ql_adm_loop_reset
* Performs qladm QL_LOOP_RESET command
*
* Input:
* ha: adapter state pointer.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
(void) ql_full_login_lip(ha);
return (EIO);
}
return (0);
}
/*
* ql_adm_device_list
* Performs qladm QL_DEVICE_LIST command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
cnt = 0;
/* Scan port list for requested target and fill in the values */
continue;
}
cnt++;
continue;
}
/* fill in the values */
} else {
}
break;
}
}
return (EFAULT);
}
return (0);
}
/*
* ql_adm_update_properties
* Performs qladm QL_UPDATE_PROPERTIES command
*
* Input:
* ha: adapter state pointer.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
/* Stall driver instance. */
(void) ql_stall_driver(ha, 0);
/* Save init control blocks. */
sizeof (ql_comb_ip_init_cb_t));
/* Update PCI configration. */
(void) ql_pci_sbus_config(ha);
/* Get configuration properties. */
(void) ql_nvram_config(ha);
/* Check for init firmware required. */
sizeof (ql_comb_init_cb_t)) != 0 ||
sizeof (ql_comb_ip_init_cb_t)) != 0) {
}
/* Update AEN queue. */
}
/* Restart driver instance. */
return (0);
}
/*
* ql_adm_prop_update_int
* Performs qladm QL_PROP_UPDATE_INT command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
char *prop_name;
int rval;
return (ENOMEM);
}
mode) != 0) {
return (EFAULT);
}
/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
return (EINVAL);
}
return (0);
}
/*
* ql_adm_fw_dump
* Performs qladm QL_FW_DUMP command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* udop: user space ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
return (EINVAL);
}
return (ENOMEM);
}
return (EFAULT);
}
} else {
}
return (EFAULT);
}
return (0);
}
/*
* ql_adm_nvram_dump
* Performs qladm QL_NVRAM_DUMP command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
return (EINVAL);
}
mode)) != 0) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_adm_nvram_load
* Performs qladm QL_NVRAM_LOAD command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
return (EINVAL);
}
mode)) != 0) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_adm_flash_load
* Performs qladm QL_FLASH_LOAD command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
return (ENOMEM);
}
mode) != 0) {
return (EFAULT);
}
return (EBUSY);
}
if (rval != QL_SUCCESS) {
return (EIO);
}
return (0);
}
/*
* ql_adm_vpd_dump
* Performs qladm QL_VPD_DUMP command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
return (EINVAL);
}
return (EINVAL);
}
!= 0) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_adm_vpd_load
* Performs qladm QL_VPD_LOAD command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval;
return (EINVAL);
}
return (EINVAL);
}
!= 0) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_adm_vpd_gettag
* Performs qladm QL_VPD_GETTAG command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
static int
{
int rval = 0;
return (EINVAL);
}
} else {
return (EFAULT);
}
} else {
} else {
rval = 0;
}
}
}
return (rval);
}
/*
* ql_adm_updfwmodule
* Performs qladm QL_UPD_FWMODULE command
*
* Input:
* ha: adapter state pointer.
* dop: ql_adm_op_t structure pointer.
* mode: flags.
*
* Returns:
*
* Context:
* Kernel context.
*/
/* ARGSUSED */
static int
{
/* zero the firmware module reference count */
DDI_SUCCESS) {
break;
}
}
}
/* reload the f/w modules */
QL_SUCCESS) {
} else {
}
rval = 0;
}
}
return (rval);
}