megaraid_sas.c revision 6029a2d88c01674debfd7c2e16c941a97302b739
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * megaraid_sas.c: source for mega_sas driver
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * MegaRAID device driver for SAS controllers
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * Copyright (c) 2005-2008, LSI Logic Corporation.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * All rights reserved.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * Rajesh Prabhakaran<Rajesh.Prabhakaran@lsil.com>
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * Redistribution and use in source and binary forms, with or without
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * modification, are permitted provided that the following conditions are met:
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * 1. Redistributions of source code must retain the above copyright notice,
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * this list of conditions and the following disclaimer.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * 2. Redistributions in binary form must reproduce the above copyright notice,
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering * this list of conditions and the following disclaimer in the documentation
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * and/or other materials provided with the distribution.
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * 3. Neither the name of the author nor the names of its contributors may be
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * used to endorse or promote products derived from this software without
a09561746f15b84da9471b5c4be74e53d19e4f3fLennart Poettering * specific prior written permission.
0d39fa9c69b97a2ceb156053deef69c0866c2b97Lennart Poettering * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
7c9a6f906308a6474f1ebb98058c4a33a02c33f1Lennart Poettering * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * Use is subject to license terms.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering#pragma ident "%Z%%M% %I% %E% SMI"
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering * Local static data
674eb68520107d771e3458287025a73387f938c4Lennart Poetteringstatic ddi_dma_attr_t megasas_generic_dma_attr = {
674eb68520107d771e3458287025a73387f938c4Lennart Poettering (unsigned long long)0, /* low DMA address range */
674eb68520107d771e3458287025a73387f938c4Lennart Poettering (unsigned long long)0xffffffff, /* high DMA address range */
674eb68520107d771e3458287025a73387f938c4Lennart Poettering (unsigned long long)0xffffffff, /* DMA counter register */
674eb68520107d771e3458287025a73387f938c4Lennart Poettering (unsigned long long)0xffffffff, /* max DMA size */
057171efc103ac76c60a2a0d277d8bbf25415c21David Herrmann (unsigned long long)0xffffffff, /* segment boundary */
62cfb98addf80c25a9ed12683e73859173c65e97Kay Sievers 0 /* bus specific DMA flags */
62cfb98addf80c25a9ed12683e73859173c65e97Kay Sievers * cb_ops contains base level routines
674eb68520107d771e3458287025a73387f938c4Lennart Poettering 0, /* streamtab */
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * dev_ops contains configuration routines
c3834f9b881f2b1a68dc7d797c134f0b66b47b57Lennart Poettering 0, /* refcnt */
7c9a6f906308a6474f1ebb98058c4a33a02c33f1Lennart Poettering &mod_driverops, /* module type - driver */
674eb68520107d771e3458287025a73387f938c4Lennart Poetteringstatic struct ddi_device_acc_attr endian_attr = {
34a317e1ccb0053d49383eb5e2f73dec97affc4cDavid Herrmann * ************************************************************************** *
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * common entry points - for loadable kernel modules *
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * ************************************************************************** *
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * _init - initialize a loadable module
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek * The driver should perform any one-time resource allocation or data
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek * initialization during driver loading in _init(). For example, the driver
36f822c4bd077f9121757e24b6516e5c7ada63b5Zbigniew Jędrzejewski-Szmek * should initialize any mutexes global to the driver in this routine.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * The driver should not, however, use _init() to allocate or initialize
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * anything that has to do with a particular instance of the device.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * Per-instance initialization must be done in attach().
674eb68520107d771e3458287025a73387f938c4Lennart Poettering con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
674eb68520107d771e3458287025a73387f938c4Lennart Poettering ret = ddi_soft_state_init(&megasas_state,
674eb68520107d771e3458287025a73387f938c4Lennart Poettering sizeof (struct megasas_instance), 0);
4c3a127cb631cf5efe8a6aab3fb2884e9044ef2dLennart Poettering con_log(CL_ANN, (CE_WARN, "megaraid: could not init state"));
7410616cd9dbbec97cf98d75324da5cda2b2f7a2Lennart Poettering if ((ret = scsi_hba_init(&modlinkage)) != 0) {
674eb68520107d771e3458287025a73387f938c4Lennart Poettering con_log(CL_ANN, (CE_WARN, "megaraid: could not init scsi hba"));
4c3a127cb631cf5efe8a6aab3fb2884e9044ef2dLennart Poettering con_log(CL_ANN, (CE_WARN, "megaraid: mod_install failed"));
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * _info - returns information about a loadable module.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * _info() is called to return module information. This is a typical entry
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * point that does predefined role. It simply calls mod_info().
674eb68520107d771e3458287025a73387f938c4Lennart Poettering con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering return (mod_info(&modlinkage, modinfop));
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * _fini - prepare a loadable module for unloading
e1427b138fbf7b7f13bb61187635b882be3ca2b2Michal Schmidt * In _fini(), the driver should release any resources that were allocated in
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * _init(). The driver must remove itself from the system module list.
674eb68520107d771e3458287025a73387f938c4Lennart Poettering con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering if ((ret = mod_remove(&modlinkage)) != 0)
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * ************************************************************************** *
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering * common entry points - for autoconfiguration *
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * ************************************************************************** *
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * probe - called before attach for a given instance
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * This is an optional entry for self-identifiable device.
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * static int megasas_probe(dev_info_t *dip)
7c9a6f906308a6474f1ebb98058c4a33a02c33f1Lennart Poettering * return (DDI_SUCCESS);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * attach - adds a device to the system as part of initialization
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering * The kernel calls a driver's attach() entry point to attach an instance of
ac12cf5b7feb602da691f596bd4eade5fba9d005Kay Sievers * a device (for MegaRAID, it is instance of a controller) or to resume
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * operation for an instance of a device that has been suspended or has been
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * shut down by the power management framework
ac12cf5b7feb602da691f596bd4eade5fba9d005Kay Sievers * The attach() entry point typically includes the following types of
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * - allocate a soft-state structure for the device instance (for MegaRAID,
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt * controller instance)
010b2b8d7a694e1e404e35db90e938f6a476bf2fLennart Poettering * - initialize per-instance mutexes
7c9a6f906308a6474f1ebb98058c4a33a02c33f1Lennart Poettering * - initialize condition variables
7c9a6f906308a6474f1ebb98058c4a33a02c33f1Lennart Poettering * - register the device's interrupts (for MegaRAID, controller's interrupts)
7c9a6f906308a6474f1ebb98058c4a33a02c33f1Lennart Poettering * - map the registers and memory of the device instance (for MegaRAID,
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * controller instance)
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * - create minor device nodes for the device instance (for MegaRAID,
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * controller instance)
674eb68520107d771e3458287025a73387f938c4Lennart Poettering * - report that the device instance (for MegaRAID, controller instance) has
674eb68520107d771e3458287025a73387f938c4Lennart Poetteringmegasas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering ddi_dma_attr_t tran_dma_attr = megasas_generic_dma_attr;
d79acc309327f8c0863bd3da8b93d926a1c93ba1David Herrmann con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt * Since we know that some instantiations of this device can be
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering * plugged into slave-only SBus slots, check to see whether this is
5c817d31d9d239421cf9b01a9c06b90f50b18d75Lennart Poettering "mega%d: Device in slave-only slot, unused", instance_no));
674eb68520107d771e3458287025a73387f938c4Lennart Poettering con_log(CL_ANN, (CE_NOTE, "megasas: DDI_ATTACH"));
674eb68520107d771e3458287025a73387f938c4Lennart Poettering /* allocate the soft state for the instance */
!= DDI_SUCCESS) {
instance_no));
return (DDI_FAILURE);
return (DDI_FAILURE);
sizeof (struct megasas_instance));
DDI_SUCCESS) {
instance_no));
sizeof (struct megasas_func_ptr));
return (DDI_FAILURE);
sizeof (struct megasas_func_ptr));
return (DDI_FAILURE);
#ifdef lint
goto fail_attach;
goto fail_attach;
goto fail_attach;
goto fail_attach;
DDI_SUCCESS) {
goto fail_attach;
goto fail_attach;
!= DDI_SUCCESS) {
goto fail_attach;
goto fail_attach;
DDI_NT_SCSI_ATTACHMENT_POINT, 0) ==
DDI_FAILURE) {
goto fail_attach;
goto fail_attach;
goto fail_initiate_aen;
case DDI_PM_RESUME:
case DDI_RESUME:
return (DDI_FAILURE);
return (DDI_SUCCESS);
if (create_devctl_node_f) {
if (create_scsi_node_f) {
if (create_ioc_node_f) {
if (tran_alloc_f) {
if (added_soft_isr_f) {
if (added_isr_f) {
return (DDI_FAILURE);
int rval;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
case DDI_INFO_DEVT2INSTANCE:
return (rval);
int instance_no;
if (!instance) {
instance_no));
return (DDI_FAILURE);
switch (cmd) {
case DDI_DETACH:
instance_no));
return (DDI_FAILURE);
return (DDI_FAILURE);
sizeof (struct megasas_func_ptr));
case DDI_PM_SUSPEND:
case DDI_SUSPEND:
return (DDI_FAILURE);
return (DDI_SUCCESS);
int rval = 0;
return (EPERM);
return (EINVAL);
== NULL) {
return (ENXIO);
if (scsi_hba_open) {
return (rval);
int rval = 0;
if (scsi_hba_close) {
return (rval);
int *rvalp)
int rval = 0;
return (ENXIO);
case MEGASAS_IOCTL_FIRMWARE:
return (EFAULT);
case MEGASAS_IOCTL_AEN:
return (EFAULT);
if (scsi_hba_ioctl) {
return (rval);
int instance_no;
if (!instance) {
instance_no));
return (DDI_FAILURE);
instance_no));
return (DDI_SUCCESS);
#ifdef NOT_YET
int instance;
int islogical;
return (DDI_FAILURE);
if (!islogical) {
return (DDI_SUCCESS);
return (DDI_FAILURE);
== RDRV_DELETED ||
== RDRV_OFFLINE) {
return (DDI_FAILURE);
return (DDI_SUCCESS);
static struct scsi_pkt *
return (NULL);
/* step #2 : dma allocation/move */
if (new_pkt) {
return (pkt);
if (cmd_done) {
return (TRAN_ACCEPT);
return (TRAN_BUSY);
return (TRAN_BUSY);
case MFI_STAT_OK:
return (TRAN_ACCEPT);
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_SUCCESS);
return (DDI_FAILURE);
return (DDI_SUCCESS);
int rval = 0;
case SCSI_CAP_DMA_MAX:
case SCSI_CAP_MSG_OUT:
case SCSI_CAP_DISCONNECT:
rval = 0;
case SCSI_CAP_SYNCHRONOUS:
rval = 0;
case SCSI_CAP_WIDE_XFER:
case SCSI_CAP_TAGGED_QING:
case SCSI_CAP_UNTAGGED_QING:
case SCSI_CAP_PARITY:
case SCSI_CAP_INITIATOR_ID:
case SCSI_CAP_ARQ:
case SCSI_CAP_LINKED_CMDS:
rval = 0;
case SCSI_CAP_GEOMETRY:
int channel;
int target;
int islogical;
if (!islogical) {
target));
return (rval);
case SCSI_CAP_DMA_MAX:
case SCSI_CAP_MSG_OUT:
case SCSI_CAP_PARITY:
case SCSI_CAP_LINKED_CMDS:
case SCSI_CAP_DISCONNECT:
case SCSI_CAP_SYNCHRONOUS:
case SCSI_CAP_UNTAGGED_QING:
case SCSI_CAP_WIDE_XFER:
case SCSI_CAP_INITIATOR_ID:
case SCSI_CAP_ARQ:
case SCSI_CAP_TAGGED_QING:
case SCSI_CAP_SECTOR_SIZE:
case SCSI_CAP_TOTAL_SECTORS:
return (rval);
#ifdef TBD
static uint_t
int need_softintr;
return (DDI_INTR_UNCLAIMED);
0, 0, DDI_DMA_SYNC_FORCPU);
consumer++;
consumer = 0;
0, 0, DDI_DMA_SYNC_FORDEV);
need_softintr = 0;
if (need_softintr) {
return (DDI_INTR_CLAIMED);
static struct megasas_cmd *
return (cmd);
#ifndef lint
static struct megasas_cmd *
return (cmd);
for (i = 0; i < max_cmd; i++) {
int cookie_cnt;
while (i < max_cmd) {
return (DDI_FAILURE);
return (-ENOMEM);
return (DDI_SUCCESS);
return (DDI_FAILURE);
return (DDI_FAILURE);
sizeof (struct megasas_evt_detail));
return (DDI_SUCCESS);
sizeof (struct megasas_cmd));
for (i = 0; i < max_cmd; i++) {
KM_SLEEP);
for (i = 0; i < max_cmd; i++) {
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_SUCCESS);
int ret = 0;
if (!cmd) {
return (DDI_FAILURE);
if (!ci) {
return (DDI_FAILURE);
ret = 0;
return (ret);
int ret = 0;
if (!cmd) {
return (DDI_FAILURE);
ret = 0;
return (ret);
return (DDI_FAILURE);
goto fail_mfi_reg_setup;
goto fail_ready_state;
goto fail_alloc_fw_space;
goto fail_fw_init;
return (DDI_FAILURE);
fw_state =
switch (fw_state) {
case MFI_STATE_FAULT:
return (-ENODEV);
case MFI_STATE_WAIT_HANDSHAKE:
case MFI_STATE_OPERATIONAL:
case MFI_STATE_UNDEFINED:
case MFI_STATE_BB_INIT:
case MFI_STATE_FW_INIT:
case MFI_STATE_DEVICE_SCAN:
return (-ENODEV);
fw_state =
return (-ENODEV);
#ifdef lint
int ret = 0;
if (!cmd) {
return (-ENOMEM);
return (DDI_FAILURE);
sizeof (struct megasas_evt_log_info));
sizeof (struct megasas_evt_log_info));
ret = 0;
return (ret);
#ifndef lint
int ret = 0;
if (!cmd) {
return (-ENOMEM);
return (DDI_FAILURE);
sizeof (struct megasas_evt_log_info));
sizeof (struct megasas_evt_log_info));
ret = 0;
return (ret);
int ret = 0;
if (ret) {
return (ret);
#ifdef TBD
int ret = 0;
seq_num++;
#ifdef TBD
if (ret) {
sizeof (struct megasas_evt_detail));
static uint_t
return (DDI_INTR_UNCLAIMED);
0, 0, DDI_DMA_SYNC_FORCPU);
case MFI_CMD_OP_PD_SCSI:
case MFI_CMD_OP_LD_SCSI:
case MFI_CMD_OP_LD_READ:
case MFI_CMD_OP_LD_WRITE:
DTYPE_DIRECT) {
case MFI_STAT_OK:
((struct scsi_status *)
((struct scsi_status *)
case MFI_CMD_OP_SMP:
case MFI_CMD_OP_STP:
case MFI_CMD_OP_DCMD:
case MFI_CMD_OP_ABORT:
return (DDI_INTR_CLAIMED);
if (i != DDI_SUCCESS) {
case DDI_DMA_BADATTR :
case DDI_DMA_NORESOURCES :
return (cookie_cnt);
int dma_flags;
case DDI_DMA_BADATTR:
case DDI_DMA_NORESOURCES:
case DDI_DMA_PARTIAL_MAP:
DDI_FAILURE) {
DDI_FAILURE) {
goto get_dma_cookies;
case DDI_DMA_MAPPED:
case DDI_DMA_NORESOURCES:
case DDI_DMA_NOMAPPING:
case DDI_DMA_TOOBIG:
case DDI_DMA_INUSE:
DDI_FAILURE) {
static struct megasas_cmd *
uint32_t i;
return (NULL);
return (NULL);
case SCMD_READ:
case SCMD_WRITE:
case SCMD_READ_G1:
case SCMD_WRITE_G1:
#ifdef lint
return (cmd);
for (i = 0; i < wait_time; i++) {
void *ubuf;
#ifdef _ILP32
if (xferlen) {
return (DDI_FAILURE);
if (xferlen) {
void *ubuf;
#ifdef _ILP32
if (xferlen) {
return (DDI_FAILURE);
if (xferlen) {
void *request_ubuf;
void *response_ubuf;
#ifndef _ILP32
#ifdef _ILP32
if (request_xferlen) {
return (DDI_FAILURE);
if (response_xferlen) {
return (DDI_FAILURE);
sizeof (uint64_t));
#ifdef _ILP32
if (request_xferlen) {
if (response_xferlen) {
if (request_xferlen) {
if (response_xferlen) {
void *fis_ubuf;
void *data_ubuf;
#ifdef _ILP32
if (fis_xferlen) {
#ifdef DEBUG
return (DDI_FAILURE);
if (data_xferlen) {
return (DDI_FAILURE);
if (fis_xferlen) {
if (data_xferlen) {
if (fis_xferlen) {
if (data_xferlen) {
int mode)
int rval = 0;
void *ubuf;
#ifdef _ILP32
for (i = 0; i < sizeof (struct megasas_pci_information); i++) {
pci_conf_buf[i] =
return (rval);
int mode)
int rval = 0;
if (!cmd) {
case MFI_CMD_OP_DCMD:
case MFI_CMD_OP_SMP:
case MFI_CMD_OP_STP:
case MFI_CMD_OP_LD_SCSI:
case MFI_CMD_OP_PD_SCSI:
return (rval);
int rval = 0;
return (rval);
int ret_val;
if (ret_val) {
return (ret_val);
if (!cmd)
return (-ENOMEM);
sizeof (struct megasas_evt_detail));
#ifndef lint
int len;
const char *const scsi_device_types[] = {
len = 0;
scsi_inq[i]);
scsi_inq[i]);
scsi_inq[i]);
unsigned int cookie;
return (DDI_FAILURE);
return (DDI_SUCCESS);
return (DDI_FAILURE);
return (DDI_SUCCESS);
#ifdef lint
#ifdef lint
return (DDI_INTR_UNCLAIMED);
return (DDI_INTR_CLAIMED);
return (DDI_INTR_UNCLAIMED);
return (DDI_INTR_CLAIMED);