/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
*/
#include "cpqary3.h"
/*
* Local Autoconfiguration Function Prototype Declations
*/
/*
* Local Functions Definitions
*/
/*
* External Variable Definitions
*/
extern cpqary3_driver_info_t gdriver_info;
/*
* Global Variables Definitions
*/
void *cpqary3_state;
/* HPQaculi Changes */
/*
* HBA minor number schema
*
* The minor numbers for any minor device nodes that we create are
* governed by the SCSA framework. We use the macros below to
* fabricate minor numbers for nodes that we own.
*
* See sys/impl/transport.h for more info.
*/
/* Macro to extract interface from minor number */
/* Base of range assigned to HBAs: */
/* Our minor nodes: */
/* Convenience macros to convert device instances to minor numbers */
/* HPQacucli Changes */
/*
* The Driver DMA Limit structure.
* Data used for SMART Integrated Array Controller shall be used.
*/
DMA_ATTR_V0, /* ddi_dma_attr version */
0, /* Low Address */
0xFFFFFFFFFFFFFFFF, /* High Address */
0x00FFFFFF, /* Max DMA Counter register */
0x20, /* Byte Alignment */
0x20, /* Burst Sizes : 32 Byte */
DMA_UNIT_8, /* Minimum DMA xfer Size */
0xFFFFFFFF, /* Maximum DMA xfer Size */
/*
* Segment boundary restrictions
* The addr should not cross 4GB boundry.
* This is required to address an issue
* in the Surge ASIC, with earlier FW versions.
*/
0xFFFFFFFF,
CPQARY3_SG_CNT, /* Scatter/Gather List Length */
512, /* Device Granularity */
0 /* DMA flags */
};
/*
* The Device Access Attribute Structure.
*/
};
/*
* Character-Block Operations Structure
*/
/* HPQacucli Changes */
/* HPQacucli Changes */
nodev, /* cb_strategy */
nodev, /* cb_print */
nodev, /* cb_dump */
nodev, /* cb_read */
nodev, /* cb_write */
cpqary3_ioctl, /* cb_ioctl */
nodev, /* cb_devmap */
nodev, /* cb_mmap */
nodev, /* cb_segmap */
nochpoll, /* cb_chpoll */
ddi_prop_op, /* cb_prop_op */
NULL, /* cb_stream */
};
/*
* Device Operations Structure
*/
DEVO_REV, /* Driver Build Version */
0, /* Driver reference count */
nodev, /* Get Info */
nulldev, /* Identify not required */
nulldev, /* Probe, obselete for s2.6 and up */
cpqary3_attach, /* Attach routine */
cpqary3_detach, /* Detach routine */
nodev, /* Reset */
&cpqary3_cb_ops, /* Entry Points for C&B drivers */
NULL, /* Bus ops */
nodev /* cpqary3_power */
};
/*
* Linkage structures
*/
&mod_driverops, /* Module Type - driver */
cpqary3_brief, /* Driver Desc */
&cpqary3_dev_ops /* Driver Ops */
};
MODREV_1, /* Loadable module rev. no. */
&cpqary3_modldrv, /* Loadable module */
NULL /* end */
};
/*
* Function : _init
* Description : This routine allocates soft state resources for the
* driver, registers the HBA with the system and
* adds the driver(loadable module).
* Called By : Kernel
* Parameters : None
* Return Values: 0 / Non-Zero
* [as returned by the mod_install OS function]
*/
int
_init()
{
int retvalue;
/*
* Allocate Soft State Resources; if failure, return.
*/
/*
* Initialise the HBA Interface.
*/
/* Load the driver */
/*
* Failed to load the driver, undo HBA interface
* and soft state allocation.
*/
}
} else {
/*
* Failed to register HBA interface, undo all soft state
* allocation
*/
}
return (retvalue);
}
/*
* Function : _fini
* Description : This routine removes the loadable module, cancels the
* HBA registration and deallocates soft state resources.
* Called By : Kernel
* Parameters : None
* Return Values: 0 - Success / Non-Zero - Failure
* [as returned by the mod_remove(OS provided) function]
*/
int
_fini()
{
int retvalue;
/* Unload the Driver(loadable module) */
/* Cancel the registeration for the HBA Interface */
/* dealloacte soft state resources of the driver */
}
return (retvalue);
}
/*
* Function : _info
* Description : This routine returns information about the driver.
* Called By : Kernel
* Parameters : None
* Return Values: 0 / Non-Zero
* [as returned by mod_info(OS provided) function]
*/
int
{
/*
* Get the module information.
*/
}
/*
* Function : cpqary3_attach
* Description : This routine initializes the driver specific soft state
* structure, initializes the HBA, interrupt handlers,
* memory pool, timeout handler, various mutex, creates the
* minor node.
* Called By : kernel
* Parameters : dip, command for attach
* Return Values: DDI_SUCCESS / DDI_FAILURE
* [Success on overall initialization & configuration
* being successful. Failure if any of the initialization
* or any driver-specific mandatory configuration fails]
*/
int
{
/* Return Failure, If the Command is other than - DDI_ATTACH. */
if (attach_cmd != DDI_ATTACH)
return (DDI_FAILURE);
/* Get the Instance of the Device */
/* Allocate the per-device-instance soft state structure */
/* Per Controller Pointer */
if (!cpqary3p) {
return (DDI_FAILURE);
}
/* Maintain a record in per-ctlr structure */
/* Get the User Configuration information from Driver's conf File */
/* Get and Map the HW Configuration */
if (retvalue == CPQARY3_FAILURE) {
return (DDI_FAILURE);
}
/* Get the Cookie for hardware Interrupt Handler */
DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* Initialize Per Controller Mutex */
(void *)cpqary3p->hw_iblock_cookie);
/* Get the Cookie for Soft(low level) Interrupt Handler */
return (DDI_FAILURE);
}
/* Initialize the s/w Mutex */
(void *)cpqary3p->sw_iblock_cookie);
/* Initialize per Controller private details */
if (retvalue != CPQARY3_SUCCESS) {
return (DDI_FAILURE);
}
/*
* Allocate HBA transport structure
*/
return (DDI_FAILURE);
}
/*
* Set private field for the HBA tran structure.
* Initialise the HBA tran entry points.
* Attach the controller to HBA.
*/
/* PERF */
/* SG */
/* SG */
/* PERF */
/*
* Register the DMA attributes and the transport vectors
* of each instance of the HBA device.
*/
SCSI_HBA_TRAN_CLONE) == DDI_FAILURE) {
return (DDI_FAILURE);
}
/*
* Create a minor node for Ioctl interface.
* The nomenclature used will be "cpqary3" immediately followed by
* the current driver instance in the system.
* for e.g.: for 0th instance : cpqary3,0
* for 1st instance : cpqary3,1
*/
/* HPQacucli Changes */
DDI_SUCCESS) {
/* HPQacucli Changes */
} else {
return (DDI_FAILURE);
}
/* Register a timeout driver-routine to be called every 2 secs */
/* Register Software Interrupt Handler */
return (DDI_FAILURE);
}
/* Register Interrupt Handler */
return (DDI_FAILURE);
}
/* Enable the Controller Interrupt */
/*
* We have come with hmaeventd - which logs the storage events on
* console as well as in IML. So we are commenting the NOE support in
* the driver
*/
/* NOE */
/* Enable the Notification on Event in this controller */
if (CPQARY3_SUCCESS ==
NULL, CPQARY3_NOE_INIT)) {
} else {
"NOTIFICATION ON EVENT \n");
}
}
/* NOE */
/* Report that an Instance of the Driver is Attached Successfully */
/*
* Now update the num_ctlr
* This is required for the agents
*/
return (DDI_SUCCESS);
}
/*
* Function : cpqary3_detach
* Description : This routine removes the state associated with a
* given instance of a device node prior to the
* removal of that instance from the system
* Called By : kernel
* Parameters : dip, command for detach
* Return Values: DDI_SUCCESS / DDI_FAILURE
* [failure ONLY if the command sent with this function
* as a paramter is not DETACH]
*/
int
{
/* Return failure, If Command is not DDI_DETACH */
if (DDI_DETACH != detach_cmd)
return (DDI_FAILURE);
/*
* Get scsi_hba_tran structure.
* Get per controller structure.
*/
/* Flush the cache */
/* Undo cpqary3_attach */
return (DDI_SUCCESS);
}
/*
* Function : cpary3_ioctl
* Description : This routine services ioctl requests.
* Called By : kernel
* Parameters : Too many to list. Please look below !!!
* Return Values: 0 / EINVAL / EFAULT /
* [0 on normal successful completion of the ioctl
* request]
*/
int
int *retvaluep)
{
int instance;
/*
* Get the soft state structure for this instance
* Return ENODEV if the structure does not exist.
*/
/*
* minor() call used in cpqary3_ioctl() returns minor number of the
* device which are in the
* range 0-255. if the minor number of the device is greater than 255,
* data will get truncated. so we are now using getminor(),
* instead of minor()
*/
return (*retvaluep);
}
/* HPQacucli Changes */
/* get instance */
/* HPQacucli Changes */
if (!cpqary3p) {
return (*retvaluep);
}
/* HPQacucli Changes */
/* check which interface is being requested */
/* defer to SCSA */
}
/* HPQacucli Changes */
switch (cmd) {
*retvaluep =
break;
case CPQARY3_IOCTL_CTLR_INFO:
*retvaluep =
break;
case CPQARY3_IOCTL_BMIC_PASS:
*retvaluep =
break;
case CPQARY3_IOCTL_SCSI_PASS:
*retvaluep =
break;
default:
break;
}
return (*retvaluep);
}
/*
* Function : cqpary3_cleanup
* Description : This routine frees all allocated resources.
* Called By : kernel
* Parameters : per-controller, bit-map(stating what all to clean)
* Return Values: None
*/
static void
{
/*
* Disable the NOE command
* Free the Command Memory Pool
* destroy all conditional variables
*/
/*
* We have removed NOE functionality from the
* driver. So commenting the below piece of code
*/
if (status & CPQARY3_NOE_INIT_DONE) {
if (DDI_FAILURE ==
"CPQary3: Resume signal for disable NOE "
"command not received \n");
}
}
}
/*
* Detach the device
* transport layer
* h/w & s/w interrupt handlers
* all mutex
* timeout handler
* target structure
* minor node
* soft state
*/
if (status & CPQARY3_INTR_HDLR_SET)
if (status & CPQARY3_SW_INTR_HDLR_SET)
}
if (status & CPQARY3_CREATE_MINOR_NODE) {
}
if (status & CPQARY3_CTLR_CONFIG_DONE) {
continue;
sizeof (cpqary3_tgt_t));
}
}
if (status & CPQARY3_SW_MUTEX_INIT_DONE)
if (status & CPQARY3_MUTEX_INIT_DONE)
/*
* If this flag is set, free all mapped registers
*/
if (status & CPQARY3_MEM_MAPPED) {
if (cpqary3p->idr_handle)
if (cpqary3p->isr_handle)
if (cpqary3p->imr_handle)
if (cpqary3p->ipq_handle)
if (cpqary3p->opq_handle)
}
if (status & CPQARY3_SOFTSTATE_ALLOC_DONE) {
}
}
/*
* Function : cpqary3_update_ctlrdetails
* Description : Performs Sanity check of the hw, Updates PCI Config
* Information, Verifies the supported board-id and
* Sets up a mapping for the Primary I2O Memory BAR and
* the Primary DRAM 1 BAR to access Host Interface
* registers and the Transport Configuration table.
* Called By : cpqary3_attach()
* Parameters : per-controller, bitmap (used for cleaning operations)
* Return Values: SUCCESS / FAILURE
* [Success / failure depending upon the outcome of all
* checks and mapping. If any of them fail, a failure is
* sent back]
*/
static uint8_t
{
/*
* Check if the bus, or part of the bus that the device is installed
* on, permits the device to become a DMA master.
* If our device is not permitted to become master, return
*/
return (CPQARY3_FAILURE);
/*
* Get the HW Configuration
* Get Bus #, Dev # and Func # for this device
* Free the memory that regp points towards after the
* ddi_getlongprop() call
*/
return (CPQARY3_FAILURE);
if (!mem_bar0_set) {
mem_bar0_set = 1;
} else if (!mem_bar1_set) {
mem_bar1_set = 1;
}
}
}
if (!mem_64_bar0_set) {
mem_64_bar0_set = 1;
} else if (!mem_64_bar1_set) {
mem_64_bar1_set = 1;
}
}
}
/*
* Setup resources to access the Local PCI Bus
* If unsuccessful, return.
* Else, read the following from the PCI space:
* Sub-System Vendor ID
* Sub-System Device ID
* Interrupt Line
* Command Register
* Free the just allocated resources.
*/
return (CPQARY3_FAILURE);
/*
* Verify Board Id
* If unsupported boards are detected, return.
* Update name for controller for driver use.
*/
"CPQary3: <Bid 0x%X> Controller NOT Supported",
return (CPQARY3_FAILURE);
}
/*
* Set up a mapping for the following registers:
* Inbound Doorbell
* Outbound List Status
* Outbound Interrupt Mask
* Host Inbound Queue
* Host Outbound Queue
* Host Transport Configuration Table
* Mapping of the above has been done in that order.
*/
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (DDI_REGS_ACC_CONFLICT == retvalue) {
"CPQary3 : Registers Mapping Conflict");
}
"Register Mapping Failed");
return (CPQARY3_FAILURE);
}
/* PERF */
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (DDI_REGS_ACC_CONFLICT == retvalue) {
"CPQary3 : Registers Mapping Conflict");
}
"CPQary3 : Outbound Doorbell Register Mapping Failed");
return (CPQARY3_FAILURE);
}
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (DDI_REGS_ACC_CONFLICT == retvalue) {
"CPQary3 : Registers Mapping Conflict");
}
"Register Clear Mapping Failed");
return (CPQARY3_FAILURE);
}
/* LOCKUP CODE */
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (DDI_REGS_ACC_CONFLICT == retvalue) {
"CPQary3 : Registers Mapping Conflict");
}
"CPQary3 : Scratch Pad register zero Mapping Failed");
return (CPQARY3_FAILURE);
}
/* LOCKUP CODE */
/* PERF */
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"CPQary3 : Interrupt Status Register Mapping Failed");
return (CPQARY3_FAILURE);
}
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"CPQary3 : Interrupt Mask Register Mapping Failed");
return (CPQARY3_FAILURE);
}
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"CPQary3 : Inbound Queue Register Mapping Failed");
return (CPQARY3_FAILURE);
}
&cpqary3p->opq_handle);
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"Register Mapping Failed");
return (CPQARY3_FAILURE);
}
/*
* The config offset and memory offset have to be obtained in order to
* locate the config table.
*/
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"Register Mapping Failed");
return (CPQARY3_FAILURE);
}
mem_bar0, /* INDEX_PCI_BASE0, */
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"Register Mapping Failed");
return (CPQARY3_FAILURE);
}
if (ct_cfg_bar == 0x10) {
if (ct_mem_len) {
} else {
}
} else if (ct_cfg_bar == 0x14) {
if (ct_mem_len) {
} else {
}
} else {
return (CPQARY3_FAILURE);
}
/*
* The Configuration Table(CT) shall be mapped in the form of a
* structure since several members in the CT need to be accessed
* to read and write.
*/
ct_mem_bar, /* INDEX_PCI_BASE0/1, */
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT) {
"CPQary3 : Registers Mapping Conflict");
}
"Register Mapping Failed");
return (CPQARY3_FAILURE);
}
/* PERF */
ct_mem_bar, /* INDEX_PCI_BASE0/1, */
sizeof (CfgTrans_Perf_t), &cpqary3_dev_attributes,
if (retvalue != DDI_SUCCESS) {
if (retvalue == DDI_REGS_ACC_CONFLICT)
"CPQary3 : Registers Mapping Conflict");
"Mapping Failed");
return (CPQARY3_FAILURE);
}
/* PERF */
return (CPQARY3_SUCCESS);
}