16029a2d8Ssusans /*
26029a2d8Ssusans * megaraid_sas.c: source for mega_sas driver
36029a2d8Ssusans *
46029a2d8Ssusans * MegaRAID device driver for SAS controllers
56029a2d8Ssusans * Copyright (c) 2005-2008, LSI Logic Corporation.
66029a2d8Ssusans * All rights reserved.
76029a2d8Ssusans *
86029a2d8Ssusans * Version:
96029a2d8Ssusans * Author:
106029a2d8Ssusans * Rajesh Prabhakaran<Rajesh.Prabhakaran@lsil.com>
116029a2d8Ssusans * Seokmann Ju
126029a2d8Ssusans *
136029a2d8Ssusans * Redistribution and use in source and binary forms, with or without
146029a2d8Ssusans * modification, are permitted provided that the following conditions are met:
156029a2d8Ssusans *
166029a2d8Ssusans * 1. Redistributions of source code must retain the above copyright notice,
176029a2d8Ssusans * this list of conditions and the following disclaimer.
186029a2d8Ssusans *
196029a2d8Ssusans * 2. Redistributions in binary form must reproduce the above copyright notice,
206029a2d8Ssusans * this list of conditions and the following disclaimer in the documentation
216029a2d8Ssusans * and/or other materials provided with the distribution.
226029a2d8Ssusans *
236029a2d8Ssusans * 3. Neither the name of the author nor the names of its contributors may be
246029a2d8Ssusans * used to endorse or promote products derived from this software without
256029a2d8Ssusans * specific prior written permission.
266029a2d8Ssusans *
276029a2d8Ssusans * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
286029a2d8Ssusans * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
296029a2d8Ssusans * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
306029a2d8Ssusans * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
316029a2d8Ssusans * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
326029a2d8Ssusans * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
336029a2d8Ssusans * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
346029a2d8Ssusans * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
356029a2d8Ssusans * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
366029a2d8Ssusans * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
376029a2d8Ssusans * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
386029a2d8Ssusans * DAMAGE.
396029a2d8Ssusans */
406029a2d8Ssusans
416029a2d8Ssusans /*
429c57abc8Ssrivijitha dugganapalli * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
436029a2d8Ssusans * Use is subject to license terms.
4489b43686SBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
456029a2d8Ssusans */
466029a2d8Ssusans
476029a2d8Ssusans #include <sys/types.h>
486029a2d8Ssusans #include <sys/param.h>
496029a2d8Ssusans #include <sys/file.h>
506029a2d8Ssusans #include <sys/errno.h>
516029a2d8Ssusans #include <sys/open.h>
526029a2d8Ssusans #include <sys/cred.h>
536029a2d8Ssusans #include <sys/modctl.h>
546029a2d8Ssusans #include <sys/conf.h>
556029a2d8Ssusans #include <sys/devops.h>
566029a2d8Ssusans #include <sys/cmn_err.h>
576029a2d8Ssusans #include <sys/kmem.h>
586029a2d8Ssusans #include <sys/stat.h>
596029a2d8Ssusans #include <sys/mkdev.h>
606029a2d8Ssusans #include <sys/pci.h>
616029a2d8Ssusans #include <sys/scsi/scsi.h>
626029a2d8Ssusans #include <sys/ddi.h>
636029a2d8Ssusans #include <sys/sunddi.h>
646029a2d8Ssusans #include <sys/atomic.h>
656029a2d8Ssusans #include <sys/signal.h>
666029a2d8Ssusans
676029a2d8Ssusans #include "megaraid_sas.h"
686029a2d8Ssusans
692fa451d9SYu Wu - Sun Microsystems - Beijing China /*
702fa451d9SYu Wu - Sun Microsystems - Beijing China * FMA header files
712fa451d9SYu Wu - Sun Microsystems - Beijing China */
722fa451d9SYu Wu - Sun Microsystems - Beijing China #include <sys/ddifm.h>
732fa451d9SYu Wu - Sun Microsystems - Beijing China #include <sys/fm/protocol.h>
742fa451d9SYu Wu - Sun Microsystems - Beijing China #include <sys/fm/util.h>
752fa451d9SYu Wu - Sun Microsystems - Beijing China #include <sys/fm/io/ddi.h>
762fa451d9SYu Wu - Sun Microsystems - Beijing China
776029a2d8Ssusans /*
786029a2d8Ssusans * Local static data
796029a2d8Ssusans */
806029a2d8Ssusans static void *megasas_state = NULL;
816029a2d8Ssusans static int debug_level_g = CL_ANN;
826029a2d8Ssusans
836029a2d8Ssusans #pragma weak scsi_hba_open
846029a2d8Ssusans #pragma weak scsi_hba_close
856029a2d8Ssusans #pragma weak scsi_hba_ioctl
866029a2d8Ssusans
876029a2d8Ssusans static ddi_dma_attr_t megasas_generic_dma_attr = {
887ddfa2acSSusan Scheufele DMA_ATTR_V0, /* dma_attr_version */
897ddfa2acSSusan Scheufele 0, /* low DMA address range */
907ddfa2acSSusan Scheufele 0xFFFFFFFFU, /* high DMA address range */
917ddfa2acSSusan Scheufele 0xFFFFFFFFU, /* DMA counter register */
927ddfa2acSSusan Scheufele 8, /* DMA address alignment */
937ddfa2acSSusan Scheufele 0x07, /* DMA burstsizes */
947ddfa2acSSusan Scheufele 1, /* min DMA size */
957ddfa2acSSusan Scheufele 0xFFFFFFFFU, /* max DMA size */
967ddfa2acSSusan Scheufele 0xFFFFFFFFU, /* segment boundary */
977ddfa2acSSusan Scheufele MEGASAS_MAX_SGE_CNT, /* dma_attr_sglen */
987ddfa2acSSusan Scheufele 512, /* granularity of device */
997ddfa2acSSusan Scheufele 0 /* bus specific DMA flags */
1006029a2d8Ssusans };
1016029a2d8Ssusans
1026029a2d8Ssusans int32_t megasas_max_cap_maxxfer = 0x1000000;
1036029a2d8Ssusans
1046029a2d8Ssusans /*
1056029a2d8Ssusans * cb_ops contains base level routines
1066029a2d8Ssusans */
1076029a2d8Ssusans static struct cb_ops megasas_cb_ops = {
1086029a2d8Ssusans megasas_open, /* open */
1096029a2d8Ssusans megasas_close, /* close */
1106029a2d8Ssusans nodev, /* strategy */
1116029a2d8Ssusans nodev, /* print */
1126029a2d8Ssusans nodev, /* dump */
1136029a2d8Ssusans nodev, /* read */
1146029a2d8Ssusans nodev, /* write */
1156029a2d8Ssusans megasas_ioctl, /* ioctl */
1166029a2d8Ssusans nodev, /* devmap */
1176029a2d8Ssusans nodev, /* mmap */
1186029a2d8Ssusans nodev, /* segmap */
1196029a2d8Ssusans nochpoll, /* poll */
1206029a2d8Ssusans nodev, /* cb_prop_op */
1216029a2d8Ssusans 0, /* streamtab */
1226029a2d8Ssusans D_NEW | D_HOTPLUG, /* cb_flag */
1236029a2d8Ssusans CB_REV, /* cb_rev */
1246029a2d8Ssusans nodev, /* cb_aread */
1256029a2d8Ssusans nodev /* cb_awrite */
1266029a2d8Ssusans };
1276029a2d8Ssusans
1286029a2d8Ssusans /*
1296029a2d8Ssusans * dev_ops contains configuration routines
1306029a2d8Ssusans */
1316029a2d8Ssusans static struct dev_ops megasas_ops = {
1326029a2d8Ssusans DEVO_REV, /* rev, */
1336029a2d8Ssusans 0, /* refcnt */
1346029a2d8Ssusans megasas_getinfo, /* getinfo */
1356029a2d8Ssusans nulldev, /* identify */
1366029a2d8Ssusans nulldev, /* probe */
1376029a2d8Ssusans megasas_attach, /* attach */
1386029a2d8Ssusans megasas_detach, /* detach */
1396029a2d8Ssusans megasas_reset, /* reset */
1406029a2d8Ssusans &megasas_cb_ops, /* char/block ops */
14119397407SSherry Moore NULL, /* bus ops */
14219397407SSherry Moore NULL, /* power */
14319397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */
1446029a2d8Ssusans };
1456029a2d8Ssusans
1466029a2d8Ssusans static struct modldrv modldrv = {
1476029a2d8Ssusans &mod_driverops, /* module type - driver */
1486029a2d8Ssusans MEGASAS_VERSION,
1496029a2d8Ssusans &megasas_ops, /* driver ops */
1506029a2d8Ssusans };
1516029a2d8Ssusans
1526029a2d8Ssusans static struct modlinkage modlinkage = {
1536029a2d8Ssusans MODREV_1, /* ml_rev - must be MODREV_1 */
1546029a2d8Ssusans &modldrv, /* ml_linkage */
1556029a2d8Ssusans NULL /* end of driver linkage */
1566029a2d8Ssusans };
1576029a2d8Ssusans
1586029a2d8Ssusans static struct ddi_device_acc_attr endian_attr = {
159837c1ac4SStephen Hanson DDI_DEVICE_ATTR_V1,
1606029a2d8Ssusans DDI_STRUCTURE_LE_ACC,
161837c1ac4SStephen Hanson DDI_STRICTORDER_ACC,
162837c1ac4SStephen Hanson DDI_DEFAULT_ACC
1636029a2d8Ssusans };
1646029a2d8Ssusans
1656029a2d8Ssusans
1666029a2d8Ssusans /*
1676029a2d8Ssusans * ************************************************************************** *
1686029a2d8Ssusans * *
1696029a2d8Ssusans * common entry points - for loadable kernel modules *
1706029a2d8Ssusans * *
1716029a2d8Ssusans * ************************************************************************** *
1726029a2d8Ssusans */
1736029a2d8Ssusans
1746029a2d8Ssusans /*
1756029a2d8Ssusans * _init - initialize a loadable module
1766029a2d8Ssusans * @void
1776029a2d8Ssusans *
1786029a2d8Ssusans * The driver should perform any one-time resource allocation or data
1796029a2d8Ssusans * initialization during driver loading in _init(). For example, the driver
1806029a2d8Ssusans * should initialize any mutexes global to the driver in this routine.
1816029a2d8Ssusans * The driver should not, however, use _init() to allocate or initialize
1826029a2d8Ssusans * anything that has to do with a particular instance of the device.
1836029a2d8Ssusans * Per-instance initialization must be done in attach().
1846029a2d8Ssusans */
1856029a2d8Ssusans int
_init(void)1866029a2d8Ssusans _init(void)
1876029a2d8Ssusans {
1886029a2d8Ssusans int ret;
1896029a2d8Ssusans
1906029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
1916029a2d8Ssusans
1926029a2d8Ssusans ret = ddi_soft_state_init(&megasas_state,
1936029a2d8Ssusans sizeof (struct megasas_instance), 0);
1946029a2d8Ssusans
1956029a2d8Ssusans if (ret != 0) {
1966029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: could not init state"));
1976029a2d8Ssusans return (ret);
1986029a2d8Ssusans }
1996029a2d8Ssusans
2006029a2d8Ssusans if ((ret = scsi_hba_init(&modlinkage)) != 0) {
2016029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: could not init scsi hba"));
2026029a2d8Ssusans ddi_soft_state_fini(&megasas_state);
2036029a2d8Ssusans return (ret);
2046029a2d8Ssusans }
2056029a2d8Ssusans
2066029a2d8Ssusans ret = mod_install(&modlinkage);
2076029a2d8Ssusans
2086029a2d8Ssusans if (ret != 0) {
2096029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: mod_install failed"));
2106029a2d8Ssusans scsi_hba_fini(&modlinkage);
2116029a2d8Ssusans ddi_soft_state_fini(&megasas_state);
2126029a2d8Ssusans }
2136029a2d8Ssusans
2146029a2d8Ssusans return (ret);
2156029a2d8Ssusans }
2166029a2d8Ssusans
2176029a2d8Ssusans /*
2186029a2d8Ssusans * _info - returns information about a loadable module.
2196029a2d8Ssusans * @void
2206029a2d8Ssusans *
2216029a2d8Ssusans * _info() is called to return module information. This is a typical entry
2226029a2d8Ssusans * point that does predefined role. It simply calls mod_info().
2236029a2d8Ssusans */
2246029a2d8Ssusans int
_info(struct modinfo * modinfop)2256029a2d8Ssusans _info(struct modinfo *modinfop)
2266029a2d8Ssusans {
2276029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
2286029a2d8Ssusans
2296029a2d8Ssusans return (mod_info(&modlinkage, modinfop));
2306029a2d8Ssusans }
2316029a2d8Ssusans
2326029a2d8Ssusans /*
2336029a2d8Ssusans * _fini - prepare a loadable module for unloading
2346029a2d8Ssusans * @void
2356029a2d8Ssusans *
2366029a2d8Ssusans * In _fini(), the driver should release any resources that were allocated in
2376029a2d8Ssusans * _init(). The driver must remove itself from the system module list.
2386029a2d8Ssusans */
2396029a2d8Ssusans int
_fini(void)2406029a2d8Ssusans _fini(void)
2416029a2d8Ssusans {
2426029a2d8Ssusans int ret;
2436029a2d8Ssusans
2446029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
2456029a2d8Ssusans
2466029a2d8Ssusans if ((ret = mod_remove(&modlinkage)) != 0)
2476029a2d8Ssusans return (ret);
2486029a2d8Ssusans
2496029a2d8Ssusans scsi_hba_fini(&modlinkage);
2506029a2d8Ssusans
2516029a2d8Ssusans ddi_soft_state_fini(&megasas_state);
2526029a2d8Ssusans
2536029a2d8Ssusans return (ret);
2546029a2d8Ssusans }
2556029a2d8Ssusans
2566029a2d8Ssusans
2576029a2d8Ssusans /*
2586029a2d8Ssusans * ************************************************************************** *
2596029a2d8Ssusans * *
2606029a2d8Ssusans * common entry points - for autoconfiguration *
2616029a2d8Ssusans * *
2626029a2d8Ssusans * ************************************************************************** *
2636029a2d8Ssusans */
2646029a2d8Ssusans /*
2656029a2d8Ssusans * attach - adds a device to the system as part of initialization
2666029a2d8Ssusans * @dip:
2676029a2d8Ssusans * @cmd:
2686029a2d8Ssusans *
2696029a2d8Ssusans * The kernel calls a driver's attach() entry point to attach an instance of
2706029a2d8Ssusans * a device (for MegaRAID, it is instance of a controller) or to resume
2716029a2d8Ssusans * operation for an instance of a device that has been suspended or has been
2726029a2d8Ssusans * shut down by the power management framework
2736029a2d8Ssusans * The attach() entry point typically includes the following types of
2746029a2d8Ssusans * processing:
2756029a2d8Ssusans * - allocate a soft-state structure for the device instance (for MegaRAID,
2766029a2d8Ssusans * controller instance)
2776029a2d8Ssusans * - initialize per-instance mutexes
2786029a2d8Ssusans * - initialize condition variables
2796029a2d8Ssusans * - register the device's interrupts (for MegaRAID, controller's interrupts)
2806029a2d8Ssusans * - map the registers and memory of the device instance (for MegaRAID,
2816029a2d8Ssusans * controller instance)
2826029a2d8Ssusans * - create minor device nodes for the device instance (for MegaRAID,
2836029a2d8Ssusans * controller instance)
2846029a2d8Ssusans * - report that the device instance (for MegaRAID, controller instance) has
2856029a2d8Ssusans * attached
2866029a2d8Ssusans */
2876029a2d8Ssusans static int
megasas_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2886029a2d8Ssusans megasas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2896029a2d8Ssusans {
2906029a2d8Ssusans int instance_no;
2916029a2d8Ssusans int nregs;
2926029a2d8Ssusans uint8_t added_isr_f = 0;
2936029a2d8Ssusans uint8_t added_soft_isr_f = 0;
2946029a2d8Ssusans uint8_t create_devctl_node_f = 0;
2956029a2d8Ssusans uint8_t create_scsi_node_f = 0;
2966029a2d8Ssusans uint8_t create_ioc_node_f = 0;
2976029a2d8Ssusans uint8_t tran_alloc_f = 0;
2986029a2d8Ssusans uint8_t irq;
2996029a2d8Ssusans uint16_t vendor_id;
3006029a2d8Ssusans uint16_t device_id;
3016029a2d8Ssusans uint16_t subsysvid;
3026029a2d8Ssusans uint16_t subsysid;
3036029a2d8Ssusans uint16_t command;
3046029a2d8Ssusans
3056029a2d8Ssusans scsi_hba_tran_t *tran;
3062fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_dma_attr_t tran_dma_attr;
3076029a2d8Ssusans struct megasas_instance *instance;
3086029a2d8Ssusans
3096029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
3106029a2d8Ssusans
3117ddfa2acSSusan Scheufele /* CONSTCOND */
3127ddfa2acSSusan Scheufele ASSERT(NO_COMPETING_THREADS);
3137ddfa2acSSusan Scheufele
3146029a2d8Ssusans instance_no = ddi_get_instance(dip);
3156029a2d8Ssusans
3166029a2d8Ssusans /*
3176029a2d8Ssusans * Since we know that some instantiations of this device can be
3186029a2d8Ssusans * plugged into slave-only SBus slots, check to see whether this is
3196029a2d8Ssusans * one such.
3206029a2d8Ssusans */
3216029a2d8Ssusans if (ddi_slaveonly(dip) == DDI_SUCCESS) {
3226029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
3236029a2d8Ssusans "mega%d: Device in slave-only slot, unused", instance_no));
3246029a2d8Ssusans return (DDI_FAILURE);
3256029a2d8Ssusans }
3266029a2d8Ssusans
3276029a2d8Ssusans switch (cmd) {
3286029a2d8Ssusans case DDI_ATTACH:
3293ddf1763Syw con_log(CL_DLEVEL1, (CE_NOTE, "megasas: DDI_ATTACH"));
3306029a2d8Ssusans /* allocate the soft state for the instance */
3316029a2d8Ssusans if (ddi_soft_state_zalloc(megasas_state, instance_no)
3326029a2d8Ssusans != DDI_SUCCESS) {
3336029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
3346029a2d8Ssusans "mega%d: Failed to allocate soft state",
3356029a2d8Ssusans instance_no));
3366029a2d8Ssusans
3376029a2d8Ssusans return (DDI_FAILURE);
3386029a2d8Ssusans }
3396029a2d8Ssusans
3406029a2d8Ssusans instance = (struct megasas_instance *)ddi_get_soft_state
3416029a2d8Ssusans (megasas_state, instance_no);
3426029a2d8Ssusans
3436029a2d8Ssusans if (instance == NULL) {
3446029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
3456029a2d8Ssusans "mega%d: Bad soft state", instance_no));
3466029a2d8Ssusans
3476029a2d8Ssusans ddi_soft_state_free(megasas_state, instance_no);
3486029a2d8Ssusans
3496029a2d8Ssusans return (DDI_FAILURE);
3506029a2d8Ssusans }
3516029a2d8Ssusans
3526029a2d8Ssusans bzero((caddr_t)instance,
3536029a2d8Ssusans sizeof (struct megasas_instance));
3546029a2d8Ssusans
3556029a2d8Ssusans instance->func_ptr = kmem_zalloc(
3566029a2d8Ssusans sizeof (struct megasas_func_ptr), KM_SLEEP);
3576029a2d8Ssusans ASSERT(instance->func_ptr);
3586029a2d8Ssusans
3596029a2d8Ssusans /* Setup the PCI configuration space handles */
3606029a2d8Ssusans if (pci_config_setup(dip, &instance->pci_handle) !=
3616029a2d8Ssusans DDI_SUCCESS) {
3626029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
3636029a2d8Ssusans "mega%d: pci config setup failed ",
3646029a2d8Ssusans instance_no));
3656029a2d8Ssusans
3666029a2d8Ssusans kmem_free(instance->func_ptr,
3676029a2d8Ssusans sizeof (struct megasas_func_ptr));
3686029a2d8Ssusans ddi_soft_state_free(megasas_state, instance_no);
3696029a2d8Ssusans
3706029a2d8Ssusans return (DDI_FAILURE);
3716029a2d8Ssusans }
3726029a2d8Ssusans
3736029a2d8Ssusans if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) {
3746029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
3756029a2d8Ssusans "megaraid: failed to get registers."));
3766029a2d8Ssusans
3776029a2d8Ssusans pci_config_teardown(&instance->pci_handle);
3786029a2d8Ssusans kmem_free(instance->func_ptr,
3796029a2d8Ssusans sizeof (struct megasas_func_ptr));
3806029a2d8Ssusans ddi_soft_state_free(megasas_state, instance_no);
3816029a2d8Ssusans
3826029a2d8Ssusans return (DDI_FAILURE);
3836029a2d8Ssusans }
3846029a2d8Ssusans
3856029a2d8Ssusans vendor_id = pci_config_get16(instance->pci_handle,
3866029a2d8Ssusans PCI_CONF_VENID);
3876029a2d8Ssusans device_id = pci_config_get16(instance->pci_handle,
3886029a2d8Ssusans PCI_CONF_DEVID);
3896029a2d8Ssusans
3906029a2d8Ssusans subsysvid = pci_config_get16(instance->pci_handle,
3916029a2d8Ssusans PCI_CONF_SUBVENID);
3926029a2d8Ssusans subsysid = pci_config_get16(instance->pci_handle,
3936029a2d8Ssusans PCI_CONF_SUBSYSID);
3946029a2d8Ssusans
3956029a2d8Ssusans pci_config_put16(instance->pci_handle, PCI_CONF_COMM,
3966029a2d8Ssusans (pci_config_get16(instance->pci_handle,
3976029a2d8Ssusans PCI_CONF_COMM) | PCI_COMM_ME));
3986029a2d8Ssusans irq = pci_config_get8(instance->pci_handle,
3996029a2d8Ssusans PCI_CONF_ILINE);
4007ddfa2acSSusan Scheufele
4017ddfa2acSSusan Scheufele con_log(CL_DLEVEL1, (CE_CONT, "megasas%d: "
4026029a2d8Ssusans "0x%x:0x%x 0x%x:0x%x, irq:%d drv-ver:%s\n",
4036029a2d8Ssusans instance_no, vendor_id, device_id, subsysvid,
4047ddfa2acSSusan Scheufele subsysid, irq, MEGASAS_VERSION));
4056029a2d8Ssusans
4066029a2d8Ssusans /* enable bus-mastering */
4076029a2d8Ssusans command = pci_config_get16(instance->pci_handle,
4086029a2d8Ssusans PCI_CONF_COMM);
4096029a2d8Ssusans
4106029a2d8Ssusans if (!(command & PCI_COMM_ME)) {
4116029a2d8Ssusans command |= PCI_COMM_ME;
4126029a2d8Ssusans
4136029a2d8Ssusans pci_config_put16(instance->pci_handle,
4146029a2d8Ssusans PCI_CONF_COMM, command);
4156029a2d8Ssusans
4167ddfa2acSSusan Scheufele con_log(CL_ANN, (CE_CONT, "megaraid%d: "
4176029a2d8Ssusans "enable bus-mastering\n", instance_no));
4186029a2d8Ssusans } else {
4197ddfa2acSSusan Scheufele con_log(CL_DLEVEL1, (CE_CONT, "megaraid%d: "
4206029a2d8Ssusans "bus-mastering already set\n", instance_no));
4216029a2d8Ssusans }
4226029a2d8Ssusans
4236029a2d8Ssusans /* initialize function pointers */
424ea20eddaSsusans if ((device_id == PCI_DEVICE_ID_LSI_1078) ||
425ea20eddaSsusans (device_id == PCI_DEVICE_ID_LSI_1078DE)) {
4267ddfa2acSSusan Scheufele con_log(CL_DLEVEL1, (CE_CONT, "megasas%d: "
427ea20eddaSsusans "1078R/DE detected\n", instance_no));
4286029a2d8Ssusans instance->func_ptr->read_fw_status_reg =
4296029a2d8Ssusans read_fw_status_reg_ppc;
4306029a2d8Ssusans instance->func_ptr->issue_cmd = issue_cmd_ppc;
4316029a2d8Ssusans instance->func_ptr->issue_cmd_in_sync_mode =
4326029a2d8Ssusans issue_cmd_in_sync_mode_ppc;
4336029a2d8Ssusans instance->func_ptr->issue_cmd_in_poll_mode =
4346029a2d8Ssusans issue_cmd_in_poll_mode_ppc;
4356029a2d8Ssusans instance->func_ptr->enable_intr =
4366029a2d8Ssusans enable_intr_ppc;
4376029a2d8Ssusans instance->func_ptr->disable_intr =
4386029a2d8Ssusans disable_intr_ppc;
4396029a2d8Ssusans instance->func_ptr->intr_ack = intr_ack_ppc;
4406029a2d8Ssusans } else {
4417ddfa2acSSusan Scheufele con_log(CL_DLEVEL1, (CE_CONT, "megasas%d: "
4426029a2d8Ssusans "1064/8R detected\n", instance_no));
4436029a2d8Ssusans instance->func_ptr->read_fw_status_reg =
4446029a2d8Ssusans read_fw_status_reg_xscale;
4456029a2d8Ssusans instance->func_ptr->issue_cmd =
4466029a2d8Ssusans issue_cmd_xscale;
4476029a2d8Ssusans instance->func_ptr->issue_cmd_in_sync_mode =
4486029a2d8Ssusans issue_cmd_in_sync_mode_xscale;
4496029a2d8Ssusans instance->func_ptr->issue_cmd_in_poll_mode =
4506029a2d8Ssusans issue_cmd_in_poll_mode_xscale;
4516029a2d8Ssusans instance->func_ptr->enable_intr =
4526029a2d8Ssusans enable_intr_xscale;
4536029a2d8Ssusans instance->func_ptr->disable_intr =
4546029a2d8Ssusans disable_intr_xscale;
4556029a2d8Ssusans instance->func_ptr->intr_ack =
4566029a2d8Ssusans intr_ack_xscale;
4576029a2d8Ssusans }
4586029a2d8Ssusans
4597ddfa2acSSusan Scheufele instance->baseaddress = pci_config_get32(
4607ddfa2acSSusan Scheufele instance->pci_handle, PCI_CONF_BASE0);
4616029a2d8Ssusans instance->baseaddress &= 0x0fffc;
4626029a2d8Ssusans
4636029a2d8Ssusans instance->dip = dip;
4646029a2d8Ssusans instance->vendor_id = vendor_id;
4656029a2d8Ssusans instance->device_id = device_id;
4666029a2d8Ssusans instance->subsysvid = subsysvid;
4676029a2d8Ssusans instance->subsysid = subsysid;
4686029a2d8Ssusans
4692fa451d9SYu Wu - Sun Microsystems - Beijing China /* Initialize FMA */
4702fa451d9SYu Wu - Sun Microsystems - Beijing China instance->fm_capabilities = ddi_prop_get_int(
4716ec0e308SSusan Scheufele DDI_DEV_T_ANY, instance->dip, DDI_PROP_DONTPASS,
4726ec0e308SSusan Scheufele "fm-capable", DDI_FM_EREPORT_CAPABLE |
4736ec0e308SSusan Scheufele DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE
4746ec0e308SSusan Scheufele | DDI_FM_ERRCB_CAPABLE);
4752fa451d9SYu Wu - Sun Microsystems - Beijing China
4762fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_init(instance);
4772fa451d9SYu Wu - Sun Microsystems - Beijing China
4786029a2d8Ssusans /* setup the mfi based low level driver */
4796029a2d8Ssusans if (init_mfi(instance) != DDI_SUCCESS) {
4806029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: "
4816029a2d8Ssusans "could not initialize the low level driver"));
4826029a2d8Ssusans
4836029a2d8Ssusans goto fail_attach;
4846029a2d8Ssusans }
4856029a2d8Ssusans
4866029a2d8Ssusans /*
4876029a2d8Ssusans * Allocate the interrupt blocking cookie.
4886029a2d8Ssusans * It represents the information the framework
4896029a2d8Ssusans * needs to block interrupts. This cookie will
4906029a2d8Ssusans * be used by the locks shared accross our ISR.
4916029a2d8Ssusans * These locks must be initialized before we
4926029a2d8Ssusans * register our ISR.
4936029a2d8Ssusans * ddi_add_intr(9F)
4946029a2d8Ssusans */
4956029a2d8Ssusans if (ddi_get_iblock_cookie(dip, 0,
4966029a2d8Ssusans &instance->iblock_cookie) != DDI_SUCCESS) {
4976029a2d8Ssusans
4986029a2d8Ssusans goto fail_attach;
4996029a2d8Ssusans }
5006029a2d8Ssusans
5016029a2d8Ssusans if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_HIGH,
5026029a2d8Ssusans &instance->soft_iblock_cookie) != DDI_SUCCESS) {
5036029a2d8Ssusans
5046029a2d8Ssusans goto fail_attach;
5056029a2d8Ssusans }
5066029a2d8Ssusans
5076029a2d8Ssusans /*
5086029a2d8Ssusans * Initialize the driver mutexes common to
5096029a2d8Ssusans * normal/high level isr
5106029a2d8Ssusans */
5116029a2d8Ssusans if (ddi_intr_hilevel(dip, 0)) {
5126029a2d8Ssusans instance->isr_level = HIGH_LEVEL_INTR;
5136029a2d8Ssusans mutex_init(&instance->cmd_pool_mtx,
5146029a2d8Ssusans "cmd_pool_mtx", MUTEX_DRIVER,
5156029a2d8Ssusans instance->soft_iblock_cookie);
5166029a2d8Ssusans mutex_init(&instance->cmd_pend_mtx,
5176029a2d8Ssusans "cmd_pend_mtx", MUTEX_DRIVER,
5186029a2d8Ssusans instance->soft_iblock_cookie);
5196029a2d8Ssusans } else {
5206029a2d8Ssusans /*
5216029a2d8Ssusans * Initialize the driver mutexes
5226029a2d8Ssusans * specific to soft-isr
5236029a2d8Ssusans */
5246029a2d8Ssusans instance->isr_level = NORMAL_LEVEL_INTR;
5256029a2d8Ssusans mutex_init(&instance->cmd_pool_mtx,
5266029a2d8Ssusans "cmd_pool_mtx", MUTEX_DRIVER,
5276029a2d8Ssusans instance->iblock_cookie);
5286029a2d8Ssusans mutex_init(&instance->cmd_pend_mtx,
5296029a2d8Ssusans "cmd_pend_mtx", MUTEX_DRIVER,
5306029a2d8Ssusans instance->iblock_cookie);
5316029a2d8Ssusans }
5326029a2d8Ssusans
5336029a2d8Ssusans mutex_init(&instance->completed_pool_mtx,
5346029a2d8Ssusans "completed_pool_mtx", MUTEX_DRIVER,
5356029a2d8Ssusans instance->iblock_cookie);
5366029a2d8Ssusans mutex_init(&instance->int_cmd_mtx, "int_cmd_mtx",
5376029a2d8Ssusans MUTEX_DRIVER, instance->iblock_cookie);
5386029a2d8Ssusans mutex_init(&instance->aen_cmd_mtx, "aen_cmd_mtx",
5396029a2d8Ssusans MUTEX_DRIVER, instance->iblock_cookie);
5406029a2d8Ssusans mutex_init(&instance->abort_cmd_mtx, "abort_cmd_mtx",
5416029a2d8Ssusans MUTEX_DRIVER, instance->iblock_cookie);
5426029a2d8Ssusans
5436029a2d8Ssusans cv_init(&instance->int_cmd_cv, NULL, CV_DRIVER, NULL);
5446029a2d8Ssusans cv_init(&instance->abort_cmd_cv, NULL, CV_DRIVER, NULL);
5456029a2d8Ssusans
5466029a2d8Ssusans INIT_LIST_HEAD(&instance->completed_pool_list);
5476029a2d8Ssusans
5486029a2d8Ssusans /* Register our isr. */
5496029a2d8Ssusans if (ddi_add_intr(dip, 0, NULL, NULL, megasas_isr,
5506029a2d8Ssusans (caddr_t)instance) != DDI_SUCCESS) {
5516029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
5526029a2d8Ssusans " ISR did not register"));
5536029a2d8Ssusans
5546029a2d8Ssusans goto fail_attach;
5556029a2d8Ssusans }
5566029a2d8Ssusans
5576029a2d8Ssusans added_isr_f = 1;
5586029a2d8Ssusans
5596029a2d8Ssusans /* Register our soft-isr for highlevel interrupts. */
5606029a2d8Ssusans if (instance->isr_level == HIGH_LEVEL_INTR) {
5616029a2d8Ssusans if (ddi_add_softintr(dip, DDI_SOFTINT_HIGH,
5626029a2d8Ssusans &instance->soft_intr_id, NULL, NULL,
5636029a2d8Ssusans megasas_softintr, (caddr_t)instance) !=
5646029a2d8Ssusans DDI_SUCCESS) {
5656029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
5666029a2d8Ssusans " Software ISR did not register"));
5676029a2d8Ssusans
5686029a2d8Ssusans goto fail_attach;
5696029a2d8Ssusans }
5706029a2d8Ssusans
5716029a2d8Ssusans added_soft_isr_f = 1;
5726029a2d8Ssusans }
5736029a2d8Ssusans
5746029a2d8Ssusans /* Allocate a transport structure */
5756029a2d8Ssusans tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
5766029a2d8Ssusans
5776029a2d8Ssusans if (tran == NULL) {
5786029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
5796029a2d8Ssusans "scsi_hba_tran_alloc failed"));
5806029a2d8Ssusans goto fail_attach;
5816029a2d8Ssusans }
5826029a2d8Ssusans
5836029a2d8Ssusans tran_alloc_f = 1;
5846029a2d8Ssusans
5856029a2d8Ssusans instance->tran = tran;
5866029a2d8Ssusans
5876029a2d8Ssusans tran->tran_hba_private = instance;
5886029a2d8Ssusans tran->tran_tgt_private = NULL;
5896029a2d8Ssusans tran->tran_tgt_init = megasas_tran_tgt_init;
5906029a2d8Ssusans tran->tran_tgt_probe = scsi_hba_probe;
5916029a2d8Ssusans tran->tran_tgt_free = (void (*)())NULL;
5926029a2d8Ssusans tran->tran_init_pkt = megasas_tran_init_pkt;
5936029a2d8Ssusans tran->tran_start = megasas_tran_start;
5946029a2d8Ssusans tran->tran_abort = megasas_tran_abort;
5956029a2d8Ssusans tran->tran_reset = megasas_tran_reset;
5966029a2d8Ssusans tran->tran_bus_reset = megasas_tran_bus_reset;
5976029a2d8Ssusans tran->tran_getcap = megasas_tran_getcap;
5986029a2d8Ssusans tran->tran_setcap = megasas_tran_setcap;
5996029a2d8Ssusans tran->tran_destroy_pkt = megasas_tran_destroy_pkt;
6006029a2d8Ssusans tran->tran_dmafree = megasas_tran_dmafree;
6016029a2d8Ssusans tran->tran_sync_pkt = megasas_tran_sync_pkt;
6026029a2d8Ssusans tran->tran_reset_notify = NULL;
6036029a2d8Ssusans tran->tran_quiesce = megasas_tran_quiesce;
6046029a2d8Ssusans tran->tran_unquiesce = megasas_tran_unquiesce;
6056029a2d8Ssusans
6062fa451d9SYu Wu - Sun Microsystems - Beijing China tran_dma_attr = megasas_generic_dma_attr;
6076029a2d8Ssusans tran_dma_attr.dma_attr_sgllen = instance->max_num_sge;
6086029a2d8Ssusans
6096029a2d8Ssusans /* Attach this instance of the hba */
6106029a2d8Ssusans if (scsi_hba_attach_setup(dip, &tran_dma_attr, tran, 0)
6116029a2d8Ssusans != DDI_SUCCESS) {
6126029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
6136029a2d8Ssusans "scsi_hba_attach failed\n"));
6146029a2d8Ssusans
6156029a2d8Ssusans goto fail_attach;
6166029a2d8Ssusans }
6176029a2d8Ssusans
6186029a2d8Ssusans /* create devctl node for cfgadm command */
6196029a2d8Ssusans if (ddi_create_minor_node(dip, "devctl",
6206029a2d8Ssusans S_IFCHR, INST2DEVCTL(instance_no),
6216029a2d8Ssusans DDI_NT_SCSI_NEXUS, 0) == DDI_FAILURE) {
6226029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
6236029a2d8Ssusans "megaraid: failed to create devctl node."));
6246029a2d8Ssusans
6256029a2d8Ssusans goto fail_attach;
6266029a2d8Ssusans }
6276029a2d8Ssusans
6286029a2d8Ssusans create_devctl_node_f = 1;
6296029a2d8Ssusans
6306029a2d8Ssusans /* create scsi node for cfgadm command */
6316029a2d8Ssusans if (ddi_create_minor_node(dip, "scsi", S_IFCHR,
6326029a2d8Ssusans INST2SCSI(instance_no),
6336029a2d8Ssusans DDI_NT_SCSI_ATTACHMENT_POINT, 0) ==
6346029a2d8Ssusans DDI_FAILURE) {
6356029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
6366029a2d8Ssusans "megaraid: failed to create scsi node."));
6376029a2d8Ssusans
6386029a2d8Ssusans goto fail_attach;
6396029a2d8Ssusans }
6406029a2d8Ssusans
6416029a2d8Ssusans create_scsi_node_f = 1;
6426029a2d8Ssusans
6436029a2d8Ssusans (void) sprintf(instance->iocnode, "%d:lsirdctl",
6446029a2d8Ssusans instance_no);
6456029a2d8Ssusans
6466029a2d8Ssusans /*
6476029a2d8Ssusans * Create a node for applications
6486029a2d8Ssusans * for issuing ioctl to the driver.
6496029a2d8Ssusans */
6506029a2d8Ssusans if (ddi_create_minor_node(dip, instance->iocnode,
6516029a2d8Ssusans S_IFCHR, INST2LSIRDCTL(instance_no),
6526029a2d8Ssusans DDI_PSEUDO, 0) == DDI_FAILURE) {
6536029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
6546029a2d8Ssusans "megaraid: failed to create ioctl node."));
6556029a2d8Ssusans
6566029a2d8Ssusans goto fail_attach;
6576029a2d8Ssusans }
6586029a2d8Ssusans
6596029a2d8Ssusans create_ioc_node_f = 1;
6606029a2d8Ssusans
6616029a2d8Ssusans /* enable interrupt */
6626029a2d8Ssusans instance->func_ptr->enable_intr(instance);
6636029a2d8Ssusans
6646029a2d8Ssusans /* initiate AEN */
6656029a2d8Ssusans if (start_mfi_aen(instance)) {
6666029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
6676029a2d8Ssusans "megaraid: failed to initiate AEN."));
6686029a2d8Ssusans goto fail_initiate_aen;
6696029a2d8Ssusans }
6706029a2d8Ssusans
6713ddf1763Syw con_log(CL_DLEVEL1, (CE_NOTE,
6726029a2d8Ssusans "AEN started for instance %d.", instance_no));
6736029a2d8Ssusans
6746029a2d8Ssusans /* Finally! We are on the air. */
6756029a2d8Ssusans ddi_report_dev(dip);
6762fa451d9SYu Wu - Sun Microsystems - Beijing China
6772fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(instance->regmap_handle) !=
6782fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SUCCESS) {
6792fa451d9SYu Wu - Sun Microsystems - Beijing China goto fail_attach;
6802fa451d9SYu Wu - Sun Microsystems - Beijing China }
6812fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(instance->pci_handle) !=
6822fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SUCCESS) {
6832fa451d9SYu Wu - Sun Microsystems - Beijing China goto fail_attach;
6842fa451d9SYu Wu - Sun Microsystems - Beijing China }
6856029a2d8Ssusans break;
6866029a2d8Ssusans case DDI_PM_RESUME:
6876029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
6886029a2d8Ssusans "megasas: DDI_PM_RESUME"));
6896029a2d8Ssusans break;
6906029a2d8Ssusans case DDI_RESUME:
6916029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
6926029a2d8Ssusans "megasas: DDI_RESUME"));
6936029a2d8Ssusans break;
6946029a2d8Ssusans default:
6956029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
6966029a2d8Ssusans "megasas: invalid attach cmd=%x", cmd));
6976029a2d8Ssusans return (DDI_FAILURE);
6986029a2d8Ssusans }
6996029a2d8Ssusans
7006029a2d8Ssusans return (DDI_SUCCESS);
7016029a2d8Ssusans
7026029a2d8Ssusans fail_initiate_aen:
7036029a2d8Ssusans fail_attach:
7046029a2d8Ssusans if (create_devctl_node_f) {
7056029a2d8Ssusans ddi_remove_minor_node(dip, "devctl");
7066029a2d8Ssusans }
7076029a2d8Ssusans
7086029a2d8Ssusans if (create_scsi_node_f) {
7096029a2d8Ssusans ddi_remove_minor_node(dip, "scsi");
7106029a2d8Ssusans }
7116029a2d8Ssusans
7126029a2d8Ssusans if (create_ioc_node_f) {
7136029a2d8Ssusans ddi_remove_minor_node(dip, instance->iocnode);
7146029a2d8Ssusans }
7156029a2d8Ssusans
7166029a2d8Ssusans if (tran_alloc_f) {
7176029a2d8Ssusans scsi_hba_tran_free(tran);
7186029a2d8Ssusans }
7196029a2d8Ssusans
7206029a2d8Ssusans
7216029a2d8Ssusans if (added_soft_isr_f) {
7226029a2d8Ssusans ddi_remove_softintr(instance->soft_intr_id);
7236029a2d8Ssusans }
7246029a2d8Ssusans
7256029a2d8Ssusans if (added_isr_f) {
7266029a2d8Ssusans ddi_remove_intr(dip, 0, instance->iblock_cookie);
7276029a2d8Ssusans }
7286029a2d8Ssusans
7292fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
7302fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
7312fa451d9SYu Wu - Sun Microsystems - Beijing China
7322fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_fini(instance);
7332fa451d9SYu Wu - Sun Microsystems - Beijing China
7346029a2d8Ssusans pci_config_teardown(&instance->pci_handle);
7356029a2d8Ssusans
7366029a2d8Ssusans ddi_soft_state_free(megasas_state, instance_no);
7376029a2d8Ssusans
7386029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
7396029a2d8Ssusans "megasas: return failure from mega_attach\n"));
7406029a2d8Ssusans
7416029a2d8Ssusans return (DDI_FAILURE);
7426029a2d8Ssusans }
7436029a2d8Ssusans
7446029a2d8Ssusans /*
7456029a2d8Ssusans * getinfo - gets device information
7466029a2d8Ssusans * @dip:
7476029a2d8Ssusans * @cmd:
7486029a2d8Ssusans * @arg:
7496029a2d8Ssusans * @resultp:
7506029a2d8Ssusans *
7516029a2d8Ssusans * The system calls getinfo() to obtain configuration information that only
7526029a2d8Ssusans * the driver knows. The mapping of minor numbers to device instance is
7536029a2d8Ssusans * entirely under the control of the driver. The system sometimes needs to ask
7546029a2d8Ssusans * the driver which device a particular dev_t represents.
7556029a2d8Ssusans * Given the device number return the devinfo pointer from the scsi_device
7566029a2d8Ssusans * structure.
7576029a2d8Ssusans */
7586029a2d8Ssusans /*ARGSUSED*/
7596029a2d8Ssusans static int
megasas_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)7606029a2d8Ssusans megasas_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
7616029a2d8Ssusans {
7626029a2d8Ssusans int rval;
7636029a2d8Ssusans int megasas_minor = getminor((dev_t)arg);
7646029a2d8Ssusans
7656029a2d8Ssusans struct megasas_instance *instance;
7666029a2d8Ssusans
7676029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
7686029a2d8Ssusans
7696029a2d8Ssusans switch (cmd) {
7706029a2d8Ssusans case DDI_INFO_DEVT2DEVINFO:
7716029a2d8Ssusans instance = (struct megasas_instance *)
7726029a2d8Ssusans ddi_get_soft_state(megasas_state,
7736029a2d8Ssusans MINOR2INST(megasas_minor));
7746029a2d8Ssusans
7756029a2d8Ssusans if (instance == NULL) {
7766029a2d8Ssusans *resultp = NULL;
7776029a2d8Ssusans rval = DDI_FAILURE;
7786029a2d8Ssusans } else {
7796029a2d8Ssusans *resultp = instance->dip;
7806029a2d8Ssusans rval = DDI_SUCCESS;
7816029a2d8Ssusans }
7826029a2d8Ssusans break;
7836029a2d8Ssusans case DDI_INFO_DEVT2INSTANCE:
7846029a2d8Ssusans *resultp = (void *)instance;
7856029a2d8Ssusans rval = DDI_SUCCESS;
7866029a2d8Ssusans break;
7876029a2d8Ssusans default:
7886029a2d8Ssusans *resultp = NULL;
7896029a2d8Ssusans rval = DDI_FAILURE;
7906029a2d8Ssusans }
7916029a2d8Ssusans
7926029a2d8Ssusans return (rval);
7936029a2d8Ssusans }
7946029a2d8Ssusans
7956029a2d8Ssusans /*
7966029a2d8Ssusans * detach - detaches a device from the system
7976029a2d8Ssusans * @dip: pointer to the device's dev_info structure
7986029a2d8Ssusans * @cmd: type of detach
7996029a2d8Ssusans *
8006029a2d8Ssusans * A driver's detach() entry point is called to detach an instance of a device
8016029a2d8Ssusans * that is bound to the driver. The entry point is called with the instance of
8026029a2d8Ssusans * the device node to be detached and with DDI_DETACH, which is specified as
8036029a2d8Ssusans * the cmd argument to the entry point.
8046029a2d8Ssusans * This routine is called during driver unload. We free all the allocated
8056029a2d8Ssusans * resources and call the corresponding LLD so that it can also release all
8066029a2d8Ssusans * its resources.
8076029a2d8Ssusans */
8086029a2d8Ssusans static int
megasas_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)8096029a2d8Ssusans megasas_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8106029a2d8Ssusans {
8116029a2d8Ssusans int instance_no;
8126029a2d8Ssusans
8136029a2d8Ssusans struct megasas_instance *instance;
8146029a2d8Ssusans
8156029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
8166029a2d8Ssusans
8177ddfa2acSSusan Scheufele /* CONSTCOND */
8187ddfa2acSSusan Scheufele ASSERT(NO_COMPETING_THREADS);
8197ddfa2acSSusan Scheufele
8206029a2d8Ssusans instance_no = ddi_get_instance(dip);
8216029a2d8Ssusans
8226029a2d8Ssusans instance = (struct megasas_instance *)ddi_get_soft_state(megasas_state,
8236029a2d8Ssusans instance_no);
8246029a2d8Ssusans
8256029a2d8Ssusans if (!instance) {
8266029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
8276029a2d8Ssusans "megasas:%d could not get instance in detach",
8286029a2d8Ssusans instance_no));
8296029a2d8Ssusans
8306029a2d8Ssusans return (DDI_FAILURE);
8316029a2d8Ssusans }
8326029a2d8Ssusans
8336029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
8347ddfa2acSSusan Scheufele "megasas%d: detaching device 0x%4x:0x%4x:0x%4x:0x%4x\n",
8357ddfa2acSSusan Scheufele instance_no, instance->vendor_id, instance->device_id,
8367ddfa2acSSusan Scheufele instance->subsysvid, instance->subsysid));
8376029a2d8Ssusans
8386029a2d8Ssusans switch (cmd) {
8396029a2d8Ssusans case DDI_DETACH:
8406029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
8416029a2d8Ssusans "megasas_detach: DDI_DETACH\n"));
8426029a2d8Ssusans
8436029a2d8Ssusans if (scsi_hba_detach(dip) != DDI_SUCCESS) {
8446029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
8456029a2d8Ssusans "megasas:%d failed to detach",
8466029a2d8Ssusans instance_no));
8476029a2d8Ssusans
8486029a2d8Ssusans return (DDI_FAILURE);
8496029a2d8Ssusans }
8506029a2d8Ssusans
8516029a2d8Ssusans scsi_hba_tran_free(instance->tran);
8526029a2d8Ssusans
8536029a2d8Ssusans if (abort_aen_cmd(instance, instance->aen_cmd)) {
8546029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megasas_detach: "
8556029a2d8Ssusans "failed to abort prevous AEN command\n"));
8566029a2d8Ssusans
8576029a2d8Ssusans return (DDI_FAILURE);
8586029a2d8Ssusans }
8596029a2d8Ssusans
8606029a2d8Ssusans instance->func_ptr->disable_intr(instance);
8616029a2d8Ssusans
8626029a2d8Ssusans if (instance->isr_level == HIGH_LEVEL_INTR) {
8636029a2d8Ssusans ddi_remove_softintr(instance->soft_intr_id);
8646029a2d8Ssusans }
8656029a2d8Ssusans
8666029a2d8Ssusans ddi_remove_intr(dip, 0, instance->iblock_cookie);
8676029a2d8Ssusans
8686029a2d8Ssusans free_space_for_mfi(instance);
8696029a2d8Ssusans
8702fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_fini(instance);
8712fa451d9SYu Wu - Sun Microsystems - Beijing China
8726029a2d8Ssusans pci_config_teardown(&instance->pci_handle);
8736029a2d8Ssusans
8746029a2d8Ssusans kmem_free(instance->func_ptr,
8756029a2d8Ssusans sizeof (struct megasas_func_ptr));
8766029a2d8Ssusans
8776029a2d8Ssusans ddi_soft_state_free(megasas_state, instance_no);
8786029a2d8Ssusans break;
8796029a2d8Ssusans case DDI_PM_SUSPEND:
8806029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
8816029a2d8Ssusans "megasas_detach: DDI_PM_SUSPEND\n"));
8826029a2d8Ssusans
8836029a2d8Ssusans break;
8846029a2d8Ssusans case DDI_SUSPEND:
8856029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
8866029a2d8Ssusans "megasas_detach: DDI_SUSPEND\n"));
8876029a2d8Ssusans
8886029a2d8Ssusans break;
8896029a2d8Ssusans default:
8906029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
8916029a2d8Ssusans "invalid detach command:0x%x", cmd));
8926029a2d8Ssusans return (DDI_FAILURE);
8936029a2d8Ssusans }
8946029a2d8Ssusans
8956029a2d8Ssusans return (DDI_SUCCESS);
8966029a2d8Ssusans }
8976029a2d8Ssusans
8986029a2d8Ssusans /*
8996029a2d8Ssusans * ************************************************************************** *
9006029a2d8Ssusans * *
9016029a2d8Ssusans * common entry points - for character driver types *
9026029a2d8Ssusans * *
9036029a2d8Ssusans * ************************************************************************** *
9046029a2d8Ssusans */
9056029a2d8Ssusans /*
9066029a2d8Ssusans * open - gets access to a device
9076029a2d8Ssusans * @dev:
9086029a2d8Ssusans * @openflags:
9096029a2d8Ssusans * @otyp:
9106029a2d8Ssusans * @credp:
9116029a2d8Ssusans *
9126029a2d8Ssusans * Access to a device by one or more application programs is controlled
9136029a2d8Ssusans * through the open() and close() entry points. The primary function of
9146029a2d8Ssusans * open() is to verify that the open request is allowed.
9156029a2d8Ssusans */
9166029a2d8Ssusans static int
megasas_open(dev_t * dev,int openflags,int otyp,cred_t * credp)9176029a2d8Ssusans megasas_open(dev_t *dev, int openflags, int otyp, cred_t *credp)
9186029a2d8Ssusans {
9196029a2d8Ssusans int rval = 0;
9206029a2d8Ssusans
9216029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
9226029a2d8Ssusans
9236029a2d8Ssusans /* Check root permissions */
9246029a2d8Ssusans if (drv_priv(credp) != 0) {
9256029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
9266029a2d8Ssusans "megaraid: Non-root ioctl access tried!"));
9276029a2d8Ssusans return (EPERM);
9286029a2d8Ssusans }
9296029a2d8Ssusans
9306029a2d8Ssusans /* Verify we are being opened as a character device */
9316029a2d8Ssusans if (otyp != OTYP_CHR) {
9326029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
9336029a2d8Ssusans "megaraid: ioctl node must be a char node\n"));
9346029a2d8Ssusans return (EINVAL);
9356029a2d8Ssusans }
9366029a2d8Ssusans
9376029a2d8Ssusans if (ddi_get_soft_state(megasas_state, MINOR2INST(getminor(*dev)))
9386029a2d8Ssusans == NULL) {
9396029a2d8Ssusans return (ENXIO);
9406029a2d8Ssusans }
9416029a2d8Ssusans
9426029a2d8Ssusans if (scsi_hba_open) {
9436029a2d8Ssusans rval = scsi_hba_open(dev, openflags, otyp, credp);
9446029a2d8Ssusans }
9456029a2d8Ssusans
9466029a2d8Ssusans return (rval);
9476029a2d8Ssusans }
9486029a2d8Ssusans
9496029a2d8Ssusans /*
9506029a2d8Ssusans * close - gives up access to a device
9516029a2d8Ssusans * @dev:
9526029a2d8Ssusans * @openflags:
9536029a2d8Ssusans * @otyp:
9546029a2d8Ssusans * @credp:
9556029a2d8Ssusans *
9566029a2d8Ssusans * close() should perform any cleanup necessary to finish using the minor
9576029a2d8Ssusans * device, and prepare the device (and driver) to be opened again.
9586029a2d8Ssusans */
9596029a2d8Ssusans static int
megasas_close(dev_t dev,int openflags,int otyp,cred_t * credp)9606029a2d8Ssusans megasas_close(dev_t dev, int openflags, int otyp, cred_t *credp)
9616029a2d8Ssusans {
9626029a2d8Ssusans int rval = 0;
9636029a2d8Ssusans
9646029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
9656029a2d8Ssusans
9666029a2d8Ssusans /* no need for locks! */
9676029a2d8Ssusans
9686029a2d8Ssusans if (scsi_hba_close) {
9696029a2d8Ssusans rval = scsi_hba_close(dev, openflags, otyp, credp);
9706029a2d8Ssusans }
9716029a2d8Ssusans
9726029a2d8Ssusans return (rval);
9736029a2d8Ssusans }
9746029a2d8Ssusans
9756029a2d8Ssusans /*
9766029a2d8Ssusans * ioctl - performs a range of I/O commands for character drivers
9776029a2d8Ssusans * @dev:
9786029a2d8Ssusans * @cmd:
9796029a2d8Ssusans * @arg:
9806029a2d8Ssusans * @mode:
9816029a2d8Ssusans * @credp:
9826029a2d8Ssusans * @rvalp:
9836029a2d8Ssusans *
9846029a2d8Ssusans * ioctl() routine must make sure that user data is copied into or out of the
9856029a2d8Ssusans * kernel address space explicitly using copyin(), copyout(), ddi_copyin(),
9866029a2d8Ssusans * and ddi_copyout(), as appropriate.
9876029a2d8Ssusans * This is a wrapper routine to serialize access to the actual ioctl routine.
9886029a2d8Ssusans * ioctl() should return 0 on success, or the appropriate error number. The
9896029a2d8Ssusans * driver may also set the value returned to the calling process through rvalp.
9906029a2d8Ssusans */
9916029a2d8Ssusans static int
megasas_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)9926029a2d8Ssusans megasas_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
9936029a2d8Ssusans int *rvalp)
9946029a2d8Ssusans {
9956029a2d8Ssusans int rval = 0;
9966029a2d8Ssusans
9976029a2d8Ssusans struct megasas_instance *instance;
9986029a2d8Ssusans struct megasas_ioctl ioctl;
9996029a2d8Ssusans struct megasas_aen aen;
10006029a2d8Ssusans
10016029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
10026029a2d8Ssusans
10036029a2d8Ssusans instance = ddi_get_soft_state(megasas_state, MINOR2INST(getminor(dev)));
10046029a2d8Ssusans
10056029a2d8Ssusans if (instance == NULL) {
10066029a2d8Ssusans /* invalid minor number */
10076029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: adapter not found."));
10086029a2d8Ssusans return (ENXIO);
10096029a2d8Ssusans }
10106029a2d8Ssusans
10116029a2d8Ssusans switch ((uint_t)cmd) {
10126029a2d8Ssusans case MEGASAS_IOCTL_FIRMWARE:
10136029a2d8Ssusans if (ddi_copyin((void *) arg, &ioctl,
10146029a2d8Ssusans sizeof (struct megasas_ioctl), mode)) {
10156029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megasas_ioctl: "
10166029a2d8Ssusans "ERROR IOCTL copyin"));
10176029a2d8Ssusans return (EFAULT);
10186029a2d8Ssusans }
10196029a2d8Ssusans
10206029a2d8Ssusans if (ioctl.control_code == MR_DRIVER_IOCTL_COMMON) {
10216029a2d8Ssusans rval = handle_drv_ioctl(instance, &ioctl, mode);
10226029a2d8Ssusans } else {
10236029a2d8Ssusans rval = handle_mfi_ioctl(instance, &ioctl, mode);
10246029a2d8Ssusans }
10256029a2d8Ssusans
10266029a2d8Ssusans if (ddi_copyout((void *) &ioctl, (void *)arg,
10276029a2d8Ssusans (sizeof (struct megasas_ioctl) - 1), mode)) {
10286029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
10296029a2d8Ssusans "megasas_ioctl: copy_to_user failed\n"));
10306029a2d8Ssusans rval = 1;
10316029a2d8Ssusans }
10326029a2d8Ssusans
10336029a2d8Ssusans break;
10346029a2d8Ssusans case MEGASAS_IOCTL_AEN:
10356029a2d8Ssusans if (ddi_copyin((void *) arg, &aen,
10366029a2d8Ssusans sizeof (struct megasas_aen), mode)) {
10376029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
10386029a2d8Ssusans "megasas_ioctl: ERROR AEN copyin"));
10396029a2d8Ssusans return (EFAULT);
10406029a2d8Ssusans }
10416029a2d8Ssusans
10426029a2d8Ssusans rval = handle_mfi_aen(instance, &aen);
10436029a2d8Ssusans
10446029a2d8Ssusans if (ddi_copyout((void *) &aen, (void *)arg,
10456029a2d8Ssusans sizeof (struct megasas_aen), mode)) {
10466029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
10476029a2d8Ssusans "megasas_ioctl: copy_to_user failed\n"));
10486029a2d8Ssusans rval = 1;
10496029a2d8Ssusans }
10506029a2d8Ssusans
10516029a2d8Ssusans break;
10526029a2d8Ssusans default:
10533ddf1763Syw rval = scsi_hba_ioctl(dev, cmd, arg,
10543ddf1763Syw mode, credp, rvalp);
10556029a2d8Ssusans
10563ddf1763Syw con_log(CL_DLEVEL1, (CE_NOTE, "megasas_ioctl: "
10573ddf1763Syw "scsi_hba_ioctl called, ret = %x.", rval));
10586029a2d8Ssusans }
10596029a2d8Ssusans
10606029a2d8Ssusans return (rval);
10616029a2d8Ssusans }
10626029a2d8Ssusans
10636029a2d8Ssusans /*
10646029a2d8Ssusans * ************************************************************************** *
10656029a2d8Ssusans * *
10666029a2d8Ssusans * common entry points - for block driver types *
10676029a2d8Ssusans * *
10686029a2d8Ssusans * ************************************************************************** *
10696029a2d8Ssusans */
10706029a2d8Ssusans /*
10716029a2d8Ssusans * reset - TBD
10726029a2d8Ssusans * @dip:
10736029a2d8Ssusans * @cmd:
10746029a2d8Ssusans *
10756029a2d8Ssusans * TBD
10766029a2d8Ssusans */
10776029a2d8Ssusans /*ARGSUSED*/
10786029a2d8Ssusans static int
megasas_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)10796029a2d8Ssusans megasas_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
10806029a2d8Ssusans {
10816029a2d8Ssusans int instance_no;
10826029a2d8Ssusans
10836029a2d8Ssusans struct megasas_instance *instance;
10846029a2d8Ssusans
10856029a2d8Ssusans instance_no = ddi_get_instance(dip);
10866029a2d8Ssusans instance = (struct megasas_instance *)ddi_get_soft_state
10876029a2d8Ssusans (megasas_state, instance_no);
10886029a2d8Ssusans
10896029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
10906029a2d8Ssusans
10916029a2d8Ssusans if (!instance) {
10926029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
10936029a2d8Ssusans "megaraid:%d could not get adapter in reset",
10946029a2d8Ssusans instance_no));
10956029a2d8Ssusans return (DDI_FAILURE);
10966029a2d8Ssusans }
10976029a2d8Ssusans
10986029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "flushing cache for instance %d ..",
10996029a2d8Ssusans instance_no));
11006029a2d8Ssusans
11016029a2d8Ssusans flush_cache(instance);
11026029a2d8Ssusans
11036029a2d8Ssusans return (DDI_SUCCESS);
11046029a2d8Ssusans }
11056029a2d8Ssusans
11066029a2d8Ssusans
11076029a2d8Ssusans /*
11086029a2d8Ssusans * ************************************************************************** *
11096029a2d8Ssusans * *
11106029a2d8Ssusans * entry points (SCSI HBA) *
11116029a2d8Ssusans * *
11126029a2d8Ssusans * ************************************************************************** *
11136029a2d8Ssusans */
11146029a2d8Ssusans /*
11156029a2d8Ssusans * tran_tgt_init - initialize a target device instance
11166029a2d8Ssusans * @hba_dip:
11176029a2d8Ssusans * @tgt_dip:
11186029a2d8Ssusans * @tran:
11196029a2d8Ssusans * @sd:
11206029a2d8Ssusans *
11216029a2d8Ssusans * The tran_tgt_init() entry point enables the HBA to allocate and initialize
11226029a2d8Ssusans * any per-target resources. tran_tgt_init() also enables the HBA to qualify
11236029a2d8Ssusans * the device's address as valid and supportable for that particular HBA.
11246029a2d8Ssusans * By returning DDI_FAILURE, the instance of the target driver for that device
11256029a2d8Ssusans * is not probed or attached.
11266029a2d8Ssusans */
11276029a2d8Ssusans /*ARGSUSED*/
11286029a2d8Ssusans static int
megasas_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * tran,struct scsi_device * sd)11296029a2d8Ssusans megasas_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
1130c873de80SToomas Soome scsi_hba_tran_t *tran, struct scsi_device *sd)
11316029a2d8Ssusans {
11326029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
11336029a2d8Ssusans
11346029a2d8Ssusans return (DDI_SUCCESS);
11356029a2d8Ssusans }
11366029a2d8Ssusans
11376029a2d8Ssusans /*
11386029a2d8Ssusans * tran_init_pkt - allocate & initialize a scsi_pkt structure
11396029a2d8Ssusans * @ap:
11406029a2d8Ssusans * @pkt:
11416029a2d8Ssusans * @bp:
11426029a2d8Ssusans * @cmdlen:
11436029a2d8Ssusans * @statuslen:
11446029a2d8Ssusans * @tgtlen:
11456029a2d8Ssusans * @flags:
11466029a2d8Ssusans * @callback:
11476029a2d8Ssusans *
11486029a2d8Ssusans * The tran_init_pkt() entry point allocates and initializes a scsi_pkt
11496029a2d8Ssusans * structure and DMA resources for a target driver request. The
11506029a2d8Ssusans * tran_init_pkt() entry point is called when the target driver calls the
11516029a2d8Ssusans * SCSA function scsi_init_pkt(). Each call of the tran_init_pkt() entry point
11526029a2d8Ssusans * is a request to perform one or more of three possible services:
11536029a2d8Ssusans * - allocation and initialization of a scsi_pkt structure
11546029a2d8Ssusans * - allocation of DMA resources for data transfer
11556029a2d8Ssusans * - reallocation of DMA resources for the next portion of the data transfer
11566029a2d8Ssusans */
11576029a2d8Ssusans static struct scsi_pkt *
megasas_tran_init_pkt(struct scsi_address * ap,register struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)11586029a2d8Ssusans megasas_tran_init_pkt(struct scsi_address *ap, register struct scsi_pkt *pkt,
1159c873de80SToomas Soome struct buf *bp, int cmdlen, int statuslen, int tgtlen,
1160c873de80SToomas Soome int flags, int (*callback)(), caddr_t arg)
11616029a2d8Ssusans {
11626029a2d8Ssusans struct scsa_cmd *acmd;
11636029a2d8Ssusans struct megasas_instance *instance;
11646029a2d8Ssusans struct scsi_pkt *new_pkt;
11656029a2d8Ssusans
11666029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
11676029a2d8Ssusans
11686029a2d8Ssusans instance = ADDR2MEGA(ap);
11696029a2d8Ssusans
11706029a2d8Ssusans /* step #1 : pkt allocation */
11716029a2d8Ssusans if (pkt == NULL) {
11726029a2d8Ssusans pkt = scsi_hba_pkt_alloc(instance->dip, ap, cmdlen, statuslen,
11736029a2d8Ssusans tgtlen, sizeof (struct scsa_cmd), callback, arg);
11746029a2d8Ssusans if (pkt == NULL) {
11756029a2d8Ssusans return (NULL);
11766029a2d8Ssusans }
11776029a2d8Ssusans
11786029a2d8Ssusans acmd = PKT2CMD(pkt);
11796029a2d8Ssusans
11806029a2d8Ssusans /*
11816029a2d8Ssusans * Initialize the new pkt - we redundantly initialize
11826029a2d8Ssusans * all the fields for illustrative purposes.
11836029a2d8Ssusans */
11846029a2d8Ssusans acmd->cmd_pkt = pkt;
11856029a2d8Ssusans acmd->cmd_flags = 0;
11866029a2d8Ssusans acmd->cmd_scblen = statuslen;
11876029a2d8Ssusans acmd->cmd_cdblen = cmdlen;
11886029a2d8Ssusans acmd->cmd_dmahandle = NULL;
11896029a2d8Ssusans acmd->cmd_ncookies = 0;
11906029a2d8Ssusans acmd->cmd_cookie = 0;
11916029a2d8Ssusans acmd->cmd_cookiecnt = 0;
11926029a2d8Ssusans acmd->cmd_nwin = 0;
11936029a2d8Ssusans
11946029a2d8Ssusans pkt->pkt_address = *ap;
11956029a2d8Ssusans pkt->pkt_comp = (void (*)())NULL;
11966029a2d8Ssusans pkt->pkt_flags = 0;
11976029a2d8Ssusans pkt->pkt_time = 0;
11986029a2d8Ssusans pkt->pkt_resid = 0;
11996029a2d8Ssusans pkt->pkt_state = 0;
12006029a2d8Ssusans pkt->pkt_statistics = 0;
12016029a2d8Ssusans pkt->pkt_reason = 0;
12026029a2d8Ssusans new_pkt = pkt;
12036029a2d8Ssusans } else {
12046029a2d8Ssusans acmd = PKT2CMD(pkt);
12056029a2d8Ssusans new_pkt = NULL;
12066029a2d8Ssusans }
12076029a2d8Ssusans
12086029a2d8Ssusans /* step #2 : dma allocation/move */
12096029a2d8Ssusans if (bp && bp->b_bcount != 0) {
12106029a2d8Ssusans if (acmd->cmd_dmahandle == NULL) {
12116029a2d8Ssusans if (megasas_dma_alloc(instance, pkt, bp, flags,
12126029a2d8Ssusans callback) == -1) {
12136029a2d8Ssusans if (new_pkt) {
12146029a2d8Ssusans scsi_hba_pkt_free(ap, new_pkt);
12156029a2d8Ssusans }
12166029a2d8Ssusans
12176029a2d8Ssusans return ((struct scsi_pkt *)NULL);
12186029a2d8Ssusans }
12196029a2d8Ssusans } else {
12206029a2d8Ssusans if (megasas_dma_move(instance, pkt, bp) == -1) {
12216029a2d8Ssusans return ((struct scsi_pkt *)NULL);
12226029a2d8Ssusans }
12236029a2d8Ssusans }
12246029a2d8Ssusans }
12256029a2d8Ssusans
12266029a2d8Ssusans return (pkt);
12276029a2d8Ssusans }
12286029a2d8Ssusans
12296029a2d8Ssusans /*
12306029a2d8Ssusans * tran_start - transport a SCSI command to the addressed target
12316029a2d8Ssusans * @ap:
12326029a2d8Ssusans * @pkt:
12336029a2d8Ssusans *
12346029a2d8Ssusans * The tran_start() entry point for a SCSI HBA driver is called to transport a
12356029a2d8Ssusans * SCSI command to the addressed target. The SCSI command is described
12366029a2d8Ssusans * entirely within the scsi_pkt structure, which the target driver allocated
12376029a2d8Ssusans * through the HBA driver's tran_init_pkt() entry point. If the command
12386029a2d8Ssusans * involves a data transfer, DMA resources must also have been allocated for
12396029a2d8Ssusans * the scsi_pkt structure.
12406029a2d8Ssusans *
12416029a2d8Ssusans * Return Values :
12426029a2d8Ssusans * TRAN_BUSY - request queue is full, no more free scbs
12436029a2d8Ssusans * TRAN_ACCEPT - pkt has been submitted to the instance
12446029a2d8Ssusans */
12456029a2d8Ssusans static int
megasas_tran_start(struct scsi_address * ap,register struct scsi_pkt * pkt)12466029a2d8Ssusans megasas_tran_start(struct scsi_address *ap, register struct scsi_pkt *pkt)
12476029a2d8Ssusans {
12486029a2d8Ssusans uchar_t cmd_done = 0;
12496029a2d8Ssusans
12506029a2d8Ssusans struct megasas_instance *instance = ADDR2MEGA(ap);
12516029a2d8Ssusans struct megasas_cmd *cmd;
12526029a2d8Ssusans
12536029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d:SCSI CDB[0]=0x%x",
12546029a2d8Ssusans __func__, __LINE__, pkt->pkt_cdbp[0]));
12556029a2d8Ssusans
12566029a2d8Ssusans pkt->pkt_reason = CMD_CMPLT;
12573ddf1763Syw *pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
12586029a2d8Ssusans
12596029a2d8Ssusans cmd = build_cmd(instance, ap, pkt, &cmd_done);
12606029a2d8Ssusans
12616029a2d8Ssusans /*
12626029a2d8Ssusans * Check if the command is already completed by the mega_build_cmd()
12636029a2d8Ssusans * routine. In which case the busy_flag would be clear and scb will be
12646029a2d8Ssusans * NULL and appropriate reason provided in pkt_reason field
12656029a2d8Ssusans */
12666029a2d8Ssusans if (cmd_done) {
12679c57abc8Ssrivijitha dugganapalli if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
12689c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt);
12696029a2d8Ssusans }
12703ddf1763Syw pkt->pkt_reason = CMD_CMPLT;
12713ddf1763Syw pkt->pkt_scbp[0] = STATUS_GOOD;
12723ddf1763Syw pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET
12733ddf1763Syw | STATE_SENT_CMD;
12746029a2d8Ssusans return (TRAN_ACCEPT);
12756029a2d8Ssusans }
12766029a2d8Ssusans
12776029a2d8Ssusans if (cmd == NULL) {
12786029a2d8Ssusans return (TRAN_BUSY);
12796029a2d8Ssusans }
12806029a2d8Ssusans
12816029a2d8Ssusans if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
12826029a2d8Ssusans if (instance->fw_outstanding > instance->max_fw_cmds) {
12836029a2d8Ssusans con_log(CL_ANN, (CE_CONT, "megasas:Firmware busy"));
12846029a2d8Ssusans return_mfi_pkt(instance, cmd);
12856029a2d8Ssusans return (TRAN_BUSY);
12866029a2d8Ssusans }
12876029a2d8Ssusans
12886029a2d8Ssusans /* Syncronize the Cmd frame for the controller */
12896029a2d8Ssusans (void) ddi_dma_sync(cmd->frame_dma_obj.dma_handle, 0, 0,
12906029a2d8Ssusans DDI_DMA_SYNC_FORDEV);
12916029a2d8Ssusans
12926029a2d8Ssusans instance->func_ptr->issue_cmd(cmd, instance);
12936029a2d8Ssusans
12946029a2d8Ssusans } else {
12956029a2d8Ssusans struct megasas_header *hdr = &cmd->frame->hdr;
12966029a2d8Ssusans
12976029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
12986029a2d8Ssusans
1299e7eb627dSyd instance->func_ptr-> issue_cmd_in_poll_mode(instance, cmd);
13006029a2d8Ssusans
13016029a2d8Ssusans pkt->pkt_reason = CMD_CMPLT;
13026029a2d8Ssusans pkt->pkt_statistics = 0;
13036029a2d8Ssusans pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
13046029a2d8Ssusans
13056029a2d8Ssusans switch (hdr->cmd_status) {
13066029a2d8Ssusans case MFI_STAT_OK:
13076029a2d8Ssusans pkt->pkt_scbp[0] = STATUS_GOOD;
13086029a2d8Ssusans break;
13096029a2d8Ssusans
13106029a2d8Ssusans case MFI_STAT_SCSI_DONE_WITH_ERROR:
13116029a2d8Ssusans
13123ddf1763Syw pkt->pkt_reason = CMD_CMPLT;
13133ddf1763Syw pkt->pkt_statistics = 0;
13146029a2d8Ssusans
13156029a2d8Ssusans ((struct scsi_status *)pkt->pkt_scbp)->sts_chk = 1;
13166029a2d8Ssusans break;
13176029a2d8Ssusans
13186029a2d8Ssusans case MFI_STAT_DEVICE_NOT_FOUND:
13196029a2d8Ssusans pkt->pkt_reason = CMD_DEV_GONE;
13206029a2d8Ssusans pkt->pkt_statistics = STAT_DISCON;
13216029a2d8Ssusans break;
13226029a2d8Ssusans
13236029a2d8Ssusans default:
13246029a2d8Ssusans ((struct scsi_status *)pkt->pkt_scbp)->sts_busy = 1;
13256029a2d8Ssusans }
13266029a2d8Ssusans
13276029a2d8Ssusans return_mfi_pkt(instance, cmd);
13282fa451d9SYu Wu - Sun Microsystems - Beijing China (void) megasas_common_check(instance, cmd);
13296029a2d8Ssusans
13309c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt);
13316029a2d8Ssusans
13326029a2d8Ssusans }
13336029a2d8Ssusans
13346029a2d8Ssusans return (TRAN_ACCEPT);
13356029a2d8Ssusans }
13366029a2d8Ssusans
13376029a2d8Ssusans /*
13386029a2d8Ssusans * tran_abort - Abort any commands that are currently in transport
13396029a2d8Ssusans * @ap:
13406029a2d8Ssusans * @pkt:
13416029a2d8Ssusans *
13426029a2d8Ssusans * The tran_abort() entry point for a SCSI HBA driver is called to abort any
13436029a2d8Ssusans * commands that are currently in transport for a particular target. This entry
13446029a2d8Ssusans * point is called when a target driver calls scsi_abort(). The tran_abort()
13456029a2d8Ssusans * entry point should attempt to abort the command denoted by the pkt
13466029a2d8Ssusans * parameter. If the pkt parameter is NULL, tran_abort() should attempt to
13477ddfa2acSSusan Scheufele * abort all outstanding commands in the transport layer for the particular
13486029a2d8Ssusans * target or logical unit.
13496029a2d8Ssusans */
13506029a2d8Ssusans /*ARGSUSED*/
13516029a2d8Ssusans static int
megasas_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)13526029a2d8Ssusans megasas_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
13536029a2d8Ssusans {
13546029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
13556029a2d8Ssusans
13566029a2d8Ssusans /* aborting command not supported by H/W */
13576029a2d8Ssusans
13586029a2d8Ssusans return (DDI_FAILURE);
13596029a2d8Ssusans }
13606029a2d8Ssusans
13616029a2d8Ssusans /*
13626029a2d8Ssusans * tran_reset - reset either the SCSI bus or target
13636029a2d8Ssusans * @ap:
13646029a2d8Ssusans * @level:
13656029a2d8Ssusans *
13666029a2d8Ssusans * The tran_reset() entry point for a SCSI HBA driver is called to reset either
13676029a2d8Ssusans * the SCSI bus or a particular SCSI target device. This entry point is called
13686029a2d8Ssusans * when a target driver calls scsi_reset(). The tran_reset() entry point must
13696029a2d8Ssusans * reset the SCSI bus if level is RESET_ALL. If level is RESET_TARGET, just the
13706029a2d8Ssusans * particular target or logical unit must be reset.
13716029a2d8Ssusans */
13726029a2d8Ssusans /*ARGSUSED*/
13736029a2d8Ssusans static int
megasas_tran_reset(struct scsi_address * ap,int level)13746029a2d8Ssusans megasas_tran_reset(struct scsi_address *ap, int level)
13756029a2d8Ssusans {
13766029a2d8Ssusans struct megasas_instance *instance = ADDR2MEGA(ap);
13776029a2d8Ssusans
13786029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
13796029a2d8Ssusans
13806029a2d8Ssusans if (wait_for_outstanding(instance)) {
13816029a2d8Ssusans return (DDI_FAILURE);
13826029a2d8Ssusans } else {
13836029a2d8Ssusans return (DDI_SUCCESS);
13846029a2d8Ssusans }
13856029a2d8Ssusans }
13866029a2d8Ssusans
13876029a2d8Ssusans /*
13886029a2d8Ssusans * tran_bus_reset - reset the SCSI bus
13896029a2d8Ssusans * @dip:
13906029a2d8Ssusans * @level:
13916029a2d8Ssusans *
13926029a2d8Ssusans * The tran_bus_reset() vector in the scsi_hba_tran structure should be
13936029a2d8Ssusans * initialized during the HBA driver's attach(). The vector should point to
13946029a2d8Ssusans * an HBA entry point that is to be called when a user initiates a bus reset.
13956029a2d8Ssusans * Implementation is hardware specific. If the HBA driver cannot reset the
13966029a2d8Ssusans * SCSI bus without affecting the targets, the driver should fail RESET_BUS
13976029a2d8Ssusans * or not initialize this vector.
13986029a2d8Ssusans */
13996029a2d8Ssusans /*ARGSUSED*/
14006029a2d8Ssusans static int
megasas_tran_bus_reset(dev_info_t * dip,int level)14016029a2d8Ssusans megasas_tran_bus_reset(dev_info_t *dip, int level)
14026029a2d8Ssusans {
14036029a2d8Ssusans int instance_no = ddi_get_instance(dip);
14046029a2d8Ssusans
14056029a2d8Ssusans struct megasas_instance *instance = ddi_get_soft_state(megasas_state,
14066029a2d8Ssusans instance_no);
14076029a2d8Ssusans
14086029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
14096029a2d8Ssusans
14106029a2d8Ssusans if (wait_for_outstanding(instance)) {
14116029a2d8Ssusans return (DDI_FAILURE);
14126029a2d8Ssusans } else {
14136029a2d8Ssusans return (DDI_SUCCESS);
14146029a2d8Ssusans }
14156029a2d8Ssusans }
14166029a2d8Ssusans
14176029a2d8Ssusans /*
14186029a2d8Ssusans * tran_getcap - get one of a set of SCSA-defined capabilities
14196029a2d8Ssusans * @ap:
14206029a2d8Ssusans * @cap:
14216029a2d8Ssusans * @whom:
14226029a2d8Ssusans *
14236029a2d8Ssusans * The target driver can request the current setting of the capability for a
14246029a2d8Ssusans * particular target by setting the whom parameter to nonzero. A whom value of
14256029a2d8Ssusans * zero indicates a request for the current setting of the general capability
14266029a2d8Ssusans * for the SCSI bus or for adapter hardware. The tran_getcap() should return -1
14276029a2d8Ssusans * for undefined capabilities or the current value of the requested capability.
14286029a2d8Ssusans */
14296029a2d8Ssusans /*ARGSUSED*/
14306029a2d8Ssusans static int
megasas_tran_getcap(struct scsi_address * ap,char * cap,int whom)14316029a2d8Ssusans megasas_tran_getcap(struct scsi_address *ap, char *cap, int whom)
14326029a2d8Ssusans {
14336029a2d8Ssusans int rval = 0;
14346029a2d8Ssusans
14356029a2d8Ssusans struct megasas_instance *instance = ADDR2MEGA(ap);
14366029a2d8Ssusans
14376029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
14386029a2d8Ssusans
14396029a2d8Ssusans /* we do allow inquiring about capabilities for other targets */
14406029a2d8Ssusans if (cap == NULL) {
14416029a2d8Ssusans return (-1);
14426029a2d8Ssusans }
14436029a2d8Ssusans
14446029a2d8Ssusans switch (scsi_hba_lookup_capstr(cap)) {
14456029a2d8Ssusans case SCSI_CAP_DMA_MAX:
14466029a2d8Ssusans /* Limit to 16MB max transfer */
14476029a2d8Ssusans rval = megasas_max_cap_maxxfer;
14486029a2d8Ssusans break;
14496029a2d8Ssusans case SCSI_CAP_MSG_OUT:
14506029a2d8Ssusans rval = 1;
14516029a2d8Ssusans break;
14526029a2d8Ssusans case SCSI_CAP_DISCONNECT:
14536029a2d8Ssusans rval = 0;
14546029a2d8Ssusans break;
14556029a2d8Ssusans case SCSI_CAP_SYNCHRONOUS:
14566029a2d8Ssusans rval = 0;
14576029a2d8Ssusans break;
14586029a2d8Ssusans case SCSI_CAP_WIDE_XFER:
14596029a2d8Ssusans rval = 1;
14606029a2d8Ssusans break;
14616029a2d8Ssusans case SCSI_CAP_TAGGED_QING:
14626029a2d8Ssusans rval = 1;
14636029a2d8Ssusans break;
14646029a2d8Ssusans case SCSI_CAP_UNTAGGED_QING:
14656029a2d8Ssusans rval = 1;
14666029a2d8Ssusans break;
14676029a2d8Ssusans case SCSI_CAP_PARITY:
14686029a2d8Ssusans rval = 1;
14696029a2d8Ssusans break;
14706029a2d8Ssusans case SCSI_CAP_INITIATOR_ID:
14716029a2d8Ssusans rval = instance->init_id;
14726029a2d8Ssusans break;
14736029a2d8Ssusans case SCSI_CAP_ARQ:
14746029a2d8Ssusans rval = 1;
14756029a2d8Ssusans break;
14766029a2d8Ssusans case SCSI_CAP_LINKED_CMDS:
14776029a2d8Ssusans rval = 0;
14786029a2d8Ssusans break;
14796029a2d8Ssusans case SCSI_CAP_RESET_NOTIFICATION:
14806029a2d8Ssusans rval = 1;
14816029a2d8Ssusans break;
14826029a2d8Ssusans case SCSI_CAP_GEOMETRY:
14836029a2d8Ssusans rval = -1;
14846029a2d8Ssusans
14856029a2d8Ssusans break;
14866029a2d8Ssusans default:
14876029a2d8Ssusans con_log(CL_DLEVEL2, (CE_NOTE, "Default cap coming 0x%x",
14886029a2d8Ssusans scsi_hba_lookup_capstr(cap)));
14896029a2d8Ssusans rval = -1;
14906029a2d8Ssusans break;
14916029a2d8Ssusans }
14926029a2d8Ssusans
14936029a2d8Ssusans return (rval);
14946029a2d8Ssusans }
14956029a2d8Ssusans
14966029a2d8Ssusans /*
14976029a2d8Ssusans * tran_setcap - set one of a set of SCSA-defined capabilities
14986029a2d8Ssusans * @ap:
14996029a2d8Ssusans * @cap:
15006029a2d8Ssusans * @value:
15016029a2d8Ssusans * @whom:
15026029a2d8Ssusans *
15036029a2d8Ssusans * The target driver might request that the new value be set for a particular
15046029a2d8Ssusans * target by setting the whom parameter to nonzero. A whom value of zero
15056029a2d8Ssusans * means that request is to set the new value for the SCSI bus or for adapter
15066029a2d8Ssusans * hardware in general.
15076029a2d8Ssusans * The tran_setcap() should return the following values as appropriate:
15086029a2d8Ssusans * - -1 for undefined capabilities
15096029a2d8Ssusans * - 0 if the HBA driver cannot set the capability to the requested value
15106029a2d8Ssusans * - 1 if the HBA driver is able to set the capability to the requested value
15116029a2d8Ssusans */
15126029a2d8Ssusans /*ARGSUSED*/
15136029a2d8Ssusans static int
megasas_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)15146029a2d8Ssusans megasas_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
15156029a2d8Ssusans {
15166029a2d8Ssusans int rval = 1;
15176029a2d8Ssusans
15186029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
15196029a2d8Ssusans
15206029a2d8Ssusans /* We don't allow setting capabilities for other targets */
15216029a2d8Ssusans if (cap == NULL || whom == 0) {
15226029a2d8Ssusans return (-1);
15236029a2d8Ssusans }
15246029a2d8Ssusans
15256029a2d8Ssusans switch (scsi_hba_lookup_capstr(cap)) {
15266029a2d8Ssusans case SCSI_CAP_DMA_MAX:
15276029a2d8Ssusans case SCSI_CAP_MSG_OUT:
15286029a2d8Ssusans case SCSI_CAP_PARITY:
15296029a2d8Ssusans case SCSI_CAP_LINKED_CMDS:
15306029a2d8Ssusans case SCSI_CAP_RESET_NOTIFICATION:
15316029a2d8Ssusans case SCSI_CAP_DISCONNECT:
15326029a2d8Ssusans case SCSI_CAP_SYNCHRONOUS:
15336029a2d8Ssusans case SCSI_CAP_UNTAGGED_QING:
15346029a2d8Ssusans case SCSI_CAP_WIDE_XFER:
15356029a2d8Ssusans case SCSI_CAP_INITIATOR_ID:
15366029a2d8Ssusans case SCSI_CAP_ARQ:
15376029a2d8Ssusans /*
15386029a2d8Ssusans * None of these are settable via
15396029a2d8Ssusans * the capability interface.
15406029a2d8Ssusans */
15416029a2d8Ssusans break;
15426029a2d8Ssusans case SCSI_CAP_TAGGED_QING:
15436029a2d8Ssusans rval = 1;
15446029a2d8Ssusans break;
15456029a2d8Ssusans case SCSI_CAP_SECTOR_SIZE:
15466029a2d8Ssusans rval = 1;
15476029a2d8Ssusans break;
15486029a2d8Ssusans
15496029a2d8Ssusans case SCSI_CAP_TOTAL_SECTORS:
15506029a2d8Ssusans rval = 1;
15516029a2d8Ssusans break;
15526029a2d8Ssusans default:
15536029a2d8Ssusans rval = -1;
15546029a2d8Ssusans break;
15556029a2d8Ssusans }
15566029a2d8Ssusans
15576029a2d8Ssusans return (rval);
15586029a2d8Ssusans }
15596029a2d8Ssusans
15606029a2d8Ssusans /*
15616029a2d8Ssusans * tran_destroy_pkt - deallocate scsi_pkt structure
15626029a2d8Ssusans * @ap:
15636029a2d8Ssusans * @pkt:
15646029a2d8Ssusans *
15656029a2d8Ssusans * The tran_destroy_pkt() entry point is the HBA driver function that
15666029a2d8Ssusans * deallocates scsi_pkt structures. The tran_destroy_pkt() entry point is
15676029a2d8Ssusans * called when the target driver calls scsi_destroy_pkt(). The
15686029a2d8Ssusans * tran_destroy_pkt() entry point must free any DMA resources that have been
15696029a2d8Ssusans * allocated for the packet. An implicit DMA synchronization occurs if the
15706029a2d8Ssusans * DMA resources are freed and any cached data remains after the completion
15716029a2d8Ssusans * of the transfer.
15726029a2d8Ssusans */
15736029a2d8Ssusans static void
megasas_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)15746029a2d8Ssusans megasas_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
15756029a2d8Ssusans {
15766029a2d8Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
15776029a2d8Ssusans
15786029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
15796029a2d8Ssusans
15806029a2d8Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
15816029a2d8Ssusans acmd->cmd_flags &= ~CFLAG_DMAVALID;
15826029a2d8Ssusans
15836029a2d8Ssusans (void) ddi_dma_unbind_handle(acmd->cmd_dmahandle);
15846029a2d8Ssusans
15856029a2d8Ssusans ddi_dma_free_handle(&acmd->cmd_dmahandle);
15866029a2d8Ssusans
15876029a2d8Ssusans acmd->cmd_dmahandle = NULL;
15886029a2d8Ssusans }
15896029a2d8Ssusans
15906029a2d8Ssusans /* free the pkt */
15916029a2d8Ssusans scsi_hba_pkt_free(ap, pkt);
15926029a2d8Ssusans }
15936029a2d8Ssusans
15946029a2d8Ssusans /*
15956029a2d8Ssusans * tran_dmafree - deallocates DMA resources
15966029a2d8Ssusans * @ap:
15976029a2d8Ssusans * @pkt:
15986029a2d8Ssusans *
15996029a2d8Ssusans * The tran_dmafree() entry point deallocates DMAQ resources that have been
16006029a2d8Ssusans * allocated for a scsi_pkt structure. The tran_dmafree() entry point is
16016029a2d8Ssusans * called when the target driver calls scsi_dmafree(). The tran_dmafree() must
16026029a2d8Ssusans * free only DMA resources allocated for a scsi_pkt structure, not the
16036029a2d8Ssusans * scsi_pkt itself. When DMA resources are freed, a DMA synchronization is
16046029a2d8Ssusans * implicitly performed.
16056029a2d8Ssusans */
16066029a2d8Ssusans /*ARGSUSED*/
16076029a2d8Ssusans static void
megasas_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)16086029a2d8Ssusans megasas_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
16096029a2d8Ssusans {
16106029a2d8Ssusans register struct scsa_cmd *acmd = PKT2CMD(pkt);
16116029a2d8Ssusans
16126029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16136029a2d8Ssusans
16146029a2d8Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
16156029a2d8Ssusans acmd->cmd_flags &= ~CFLAG_DMAVALID;
16166029a2d8Ssusans
16176029a2d8Ssusans (void) ddi_dma_unbind_handle(acmd->cmd_dmahandle);
16186029a2d8Ssusans
16196029a2d8Ssusans ddi_dma_free_handle(&acmd->cmd_dmahandle);
16206029a2d8Ssusans
16216029a2d8Ssusans acmd->cmd_dmahandle = NULL;
16226029a2d8Ssusans }
16236029a2d8Ssusans }
16246029a2d8Ssusans
16256029a2d8Ssusans /*
16266029a2d8Ssusans * tran_sync_pkt - synchronize the DMA object allocated
16276029a2d8Ssusans * @ap:
16286029a2d8Ssusans * @pkt:
16296029a2d8Ssusans *
16306029a2d8Ssusans * The tran_sync_pkt() entry point synchronizes the DMA object allocated for
16316029a2d8Ssusans * the scsi_pkt structure before or after a DMA transfer. The tran_sync_pkt()
16326029a2d8Ssusans * entry point is called when the target driver calls scsi_sync_pkt(). If the
16336029a2d8Ssusans * data transfer direction is a DMA read from device to memory, tran_sync_pkt()
16346029a2d8Ssusans * must synchronize the CPU's view of the data. If the data transfer direction
16356029a2d8Ssusans * is a DMA write from memory to device, tran_sync_pkt() must synchronize the
16366029a2d8Ssusans * device's view of the data.
16376029a2d8Ssusans */
16386029a2d8Ssusans /*ARGSUSED*/
16396029a2d8Ssusans static void
megasas_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)16406029a2d8Ssusans megasas_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
16416029a2d8Ssusans {
16426029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16436029a2d8Ssusans
16446029a2d8Ssusans /*
16456029a2d8Ssusans * following 'ddi_dma_sync()' API call
16466029a2d8Ssusans * already called for each I/O in the ISR
16476029a2d8Ssusans */
16487ddfa2acSSusan Scheufele #if 0
16496029a2d8Ssusans int i;
16506029a2d8Ssusans
16517ddfa2acSSusan Scheufele register struct scsa_cmd *acmd = PKT2CMD(pkt);
16526029a2d8Ssusans
16536029a2d8Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
16546029a2d8Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle, acmd->cmd_dma_offset,
16556029a2d8Ssusans acmd->cmd_dma_len, (acmd->cmd_flags & CFLAG_DMASEND) ?
16566029a2d8Ssusans DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
16576029a2d8Ssusans }
16587ddfa2acSSusan Scheufele #endif
16596029a2d8Ssusans }
16606029a2d8Ssusans
16616029a2d8Ssusans /*ARGSUSED*/
16626029a2d8Ssusans static int
megasas_tran_quiesce(dev_info_t * dip)16636029a2d8Ssusans megasas_tran_quiesce(dev_info_t *dip)
16646029a2d8Ssusans {
16656029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16666029a2d8Ssusans
16676029a2d8Ssusans return (1);
16686029a2d8Ssusans }
16696029a2d8Ssusans
16706029a2d8Ssusans /*ARGSUSED*/
16716029a2d8Ssusans static int
megasas_tran_unquiesce(dev_info_t * dip)16726029a2d8Ssusans megasas_tran_unquiesce(dev_info_t *dip)
16736029a2d8Ssusans {
16746029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16756029a2d8Ssusans
16766029a2d8Ssusans return (1);
16776029a2d8Ssusans }
16786029a2d8Ssusans
16796029a2d8Ssusans /*
16806029a2d8Ssusans * megasas_isr(caddr_t)
16816029a2d8Ssusans *
16826029a2d8Ssusans * The Interrupt Service Routine
16836029a2d8Ssusans *
16846029a2d8Ssusans * Collect status for all completed commands and do callback
16856029a2d8Ssusans *
16866029a2d8Ssusans */
16876029a2d8Ssusans static uint_t
megasas_isr(struct megasas_instance * instance)16887ddfa2acSSusan Scheufele megasas_isr(struct megasas_instance *instance)
16896029a2d8Ssusans {
16906029a2d8Ssusans int need_softintr;
16916029a2d8Ssusans uint32_t producer;
16926029a2d8Ssusans uint32_t consumer;
16936029a2d8Ssusans uint32_t context;
16946029a2d8Ssusans
16956029a2d8Ssusans struct megasas_cmd *cmd;
16966029a2d8Ssusans
16976029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16986029a2d8Ssusans
16997ddfa2acSSusan Scheufele ASSERT(instance);
17006029a2d8Ssusans if (!instance->func_ptr->intr_ack(instance)) {
17016029a2d8Ssusans return (DDI_INTR_UNCLAIMED);
17026029a2d8Ssusans }
17036029a2d8Ssusans
17046029a2d8Ssusans (void) ddi_dma_sync(instance->mfi_internal_dma_obj.dma_handle,
17056029a2d8Ssusans 0, 0, DDI_DMA_SYNC_FORCPU);
17066029a2d8Ssusans
17072fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(instance->mfi_internal_dma_obj.dma_handle)
17082fa451d9SYu Wu - Sun Microsystems - Beijing China != DDI_SUCCESS) {
17092fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
17102fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
17112fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_INTR_UNCLAIMED);
17122fa451d9SYu Wu - Sun Microsystems - Beijing China }
17132fa451d9SYu Wu - Sun Microsystems - Beijing China
17146029a2d8Ssusans producer = *instance->producer;
17156029a2d8Ssusans consumer = *instance->consumer;
17166029a2d8Ssusans
17176029a2d8Ssusans con_log(CL_ANN1, (CE_CONT, " producer %x consumer %x ",
17186029a2d8Ssusans producer, consumer));
17196029a2d8Ssusans
17206029a2d8Ssusans mutex_enter(&instance->completed_pool_mtx);
17216029a2d8Ssusans
17226029a2d8Ssusans while (consumer != producer) {
17236029a2d8Ssusans context = instance->reply_queue[consumer];
17246029a2d8Ssusans cmd = instance->cmd_list[context];
17256029a2d8Ssusans mlist_add_tail(&cmd->list, &instance->completed_pool_list);
17266029a2d8Ssusans
17276029a2d8Ssusans consumer++;
17286029a2d8Ssusans if (consumer == (instance->max_fw_cmds + 1)) {
17296029a2d8Ssusans consumer = 0;
17306029a2d8Ssusans }
17316029a2d8Ssusans }
17326029a2d8Ssusans
17336029a2d8Ssusans mutex_exit(&instance->completed_pool_mtx);
17346029a2d8Ssusans
17353ddf1763Syw *instance->consumer = consumer;
17366029a2d8Ssusans (void) ddi_dma_sync(instance->mfi_internal_dma_obj.dma_handle,
17376029a2d8Ssusans 0, 0, DDI_DMA_SYNC_FORDEV);
17386029a2d8Ssusans
17396029a2d8Ssusans if (instance->softint_running) {
17406029a2d8Ssusans need_softintr = 0;
17416029a2d8Ssusans } else {
17426029a2d8Ssusans need_softintr = 1;
17436029a2d8Ssusans }
17446029a2d8Ssusans
17456029a2d8Ssusans if (instance->isr_level == HIGH_LEVEL_INTR) {
17466029a2d8Ssusans if (need_softintr) {
17476029a2d8Ssusans ddi_trigger_softintr(instance->soft_intr_id);
17486029a2d8Ssusans }
17496029a2d8Ssusans } else {
17506029a2d8Ssusans /*
17516029a2d8Ssusans * Not a high-level interrupt, therefore call the soft level
17526029a2d8Ssusans * interrupt explicitly
17536029a2d8Ssusans */
17547ddfa2acSSusan Scheufele (void) megasas_softintr(instance);
17556029a2d8Ssusans }
17566029a2d8Ssusans
17576029a2d8Ssusans return (DDI_INTR_CLAIMED);
17586029a2d8Ssusans }
17596029a2d8Ssusans
17606029a2d8Ssusans
17616029a2d8Ssusans /*
17626029a2d8Ssusans * ************************************************************************** *
17636029a2d8Ssusans * *
17646029a2d8Ssusans * libraries *
17656029a2d8Ssusans * *
17666029a2d8Ssusans * ************************************************************************** *
17676029a2d8Ssusans */
17686029a2d8Ssusans /*
17696029a2d8Ssusans * get_mfi_pkt : Get a command from the free pool
17706029a2d8Ssusans */
17716029a2d8Ssusans static struct megasas_cmd *
get_mfi_pkt(struct megasas_instance * instance)17726029a2d8Ssusans get_mfi_pkt(struct megasas_instance *instance)
17736029a2d8Ssusans {
17746029a2d8Ssusans mlist_t *head = &instance->cmd_pool_list;
17756029a2d8Ssusans struct megasas_cmd *cmd = NULL;
17766029a2d8Ssusans
17776029a2d8Ssusans mutex_enter(&instance->cmd_pool_mtx);
17786029a2d8Ssusans ASSERT(mutex_owned(&instance->cmd_pool_mtx));
17796029a2d8Ssusans
17806029a2d8Ssusans if (!mlist_empty(head)) {
17816029a2d8Ssusans cmd = mlist_entry(head->next, struct megasas_cmd, list);
17826029a2d8Ssusans mlist_del_init(head->next);
17836029a2d8Ssusans }
17842fa451d9SYu Wu - Sun Microsystems - Beijing China if (cmd != NULL)
17852fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt = NULL;
17866029a2d8Ssusans mutex_exit(&instance->cmd_pool_mtx);
17876029a2d8Ssusans
17886029a2d8Ssusans return (cmd);
17896029a2d8Ssusans }
17906029a2d8Ssusans
17916029a2d8Ssusans /*
17926029a2d8Ssusans * return_mfi_pkt : Return a cmd to free command pool
17936029a2d8Ssusans */
17946029a2d8Ssusans static void
return_mfi_pkt(struct megasas_instance * instance,struct megasas_cmd * cmd)17956029a2d8Ssusans return_mfi_pkt(struct megasas_instance *instance, struct megasas_cmd *cmd)
17966029a2d8Ssusans {
17976029a2d8Ssusans mutex_enter(&instance->cmd_pool_mtx);
17986029a2d8Ssusans ASSERT(mutex_owned(&instance->cmd_pool_mtx));
17996029a2d8Ssusans
18006029a2d8Ssusans mlist_add(&cmd->list, &instance->cmd_pool_list);
18016029a2d8Ssusans
18026029a2d8Ssusans mutex_exit(&instance->cmd_pool_mtx);
18036029a2d8Ssusans }
18046029a2d8Ssusans
18056029a2d8Ssusans /*
18066029a2d8Ssusans * destroy_mfi_frame_pool
18076029a2d8Ssusans */
18086029a2d8Ssusans static void
destroy_mfi_frame_pool(struct megasas_instance * instance)18096029a2d8Ssusans destroy_mfi_frame_pool(struct megasas_instance *instance)
18106029a2d8Ssusans {
18116029a2d8Ssusans int i;
18126029a2d8Ssusans uint32_t max_cmd = instance->max_fw_cmds;
18136029a2d8Ssusans
18146029a2d8Ssusans struct megasas_cmd *cmd;
18156029a2d8Ssusans
18166029a2d8Ssusans /* return all frames to pool */
18176029a2d8Ssusans for (i = 0; i < max_cmd; i++) {
18186029a2d8Ssusans
18196029a2d8Ssusans cmd = instance->cmd_list[i];
18206029a2d8Ssusans
18216029a2d8Ssusans if (cmd->frame_dma_obj_status == DMA_OBJ_ALLOCATED)
18222fa451d9SYu Wu - Sun Microsystems - Beijing China (void) mega_free_dma_obj(instance, cmd->frame_dma_obj);
18236029a2d8Ssusans
18246029a2d8Ssusans cmd->frame_dma_obj_status = DMA_OBJ_FREED;
18256029a2d8Ssusans }
18266029a2d8Ssusans
18276029a2d8Ssusans }
18286029a2d8Ssusans
18296029a2d8Ssusans /*
18306029a2d8Ssusans * create_mfi_frame_pool
18316029a2d8Ssusans */
18326029a2d8Ssusans static int
create_mfi_frame_pool(struct megasas_instance * instance)18336029a2d8Ssusans create_mfi_frame_pool(struct megasas_instance *instance)
18346029a2d8Ssusans {
18356029a2d8Ssusans int i = 0;
18366029a2d8Ssusans int cookie_cnt;
18376029a2d8Ssusans uint16_t max_cmd;
18386029a2d8Ssusans uint16_t sge_sz;
18396029a2d8Ssusans uint32_t sgl_sz;
18406029a2d8Ssusans uint32_t tot_frame_size;
18416029a2d8Ssusans
18426029a2d8Ssusans struct megasas_cmd *cmd;
18436029a2d8Ssusans
18446029a2d8Ssusans max_cmd = instance->max_fw_cmds;
18456029a2d8Ssusans
18466029a2d8Ssusans sge_sz = sizeof (struct megasas_sge64);
18476029a2d8Ssusans
18486029a2d8Ssusans /* calculated the number of 64byte frames required for SGL */
18497ddfa2acSSusan Scheufele sgl_sz = sge_sz * instance->max_num_sge;
18507ddfa2acSSusan Scheufele tot_frame_size = sgl_sz + MEGAMFI_FRAME_SIZE + SENSE_LENGTH;
18516029a2d8Ssusans
18526029a2d8Ssusans con_log(CL_DLEVEL3, (CE_NOTE, "create_mfi_frame_pool: "
18536029a2d8Ssusans "sgl_sz %x tot_frame_size %x", sgl_sz, tot_frame_size));
18546029a2d8Ssusans
18556029a2d8Ssusans while (i < max_cmd) {
18566029a2d8Ssusans cmd = instance->cmd_list[i];
18576029a2d8Ssusans
18586029a2d8Ssusans cmd->frame_dma_obj.size = tot_frame_size;
18596029a2d8Ssusans cmd->frame_dma_obj.dma_attr = megasas_generic_dma_attr;
18607ddfa2acSSusan Scheufele cmd->frame_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
18617ddfa2acSSusan Scheufele cmd->frame_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
18626029a2d8Ssusans cmd->frame_dma_obj.dma_attr.dma_attr_sgllen = 1;
18636029a2d8Ssusans cmd->frame_dma_obj.dma_attr.dma_attr_align = 64;
18646029a2d8Ssusans
18656029a2d8Ssusans
18666029a2d8Ssusans cookie_cnt = mega_alloc_dma_obj(instance, &cmd->frame_dma_obj);
18676029a2d8Ssusans
18686029a2d8Ssusans if (cookie_cnt == -1 || cookie_cnt > 1) {
18696029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
18706029a2d8Ssusans "create_mfi_frame_pool: could not alloc."));
18716029a2d8Ssusans return (DDI_FAILURE);
18726029a2d8Ssusans }
18736029a2d8Ssusans
18746029a2d8Ssusans bzero(cmd->frame_dma_obj.buffer, tot_frame_size);
18756029a2d8Ssusans
18766029a2d8Ssusans cmd->frame_dma_obj_status = DMA_OBJ_ALLOCATED;
18776029a2d8Ssusans cmd->frame = (union megasas_frame *)cmd->frame_dma_obj.buffer;
18786029a2d8Ssusans cmd->frame_phys_addr =
18796029a2d8Ssusans cmd->frame_dma_obj.dma_cookie[0].dmac_address;
18806029a2d8Ssusans
18816029a2d8Ssusans cmd->sense = (uint8_t *)(((unsigned long)
18826029a2d8Ssusans cmd->frame_dma_obj.buffer) +
18833ddf1763Syw tot_frame_size - SENSE_LENGTH);
18846029a2d8Ssusans cmd->sense_phys_addr =
18856029a2d8Ssusans cmd->frame_dma_obj.dma_cookie[0].dmac_address +
18863ddf1763Syw tot_frame_size - SENSE_LENGTH;
18876029a2d8Ssusans
18886029a2d8Ssusans if (!cmd->frame || !cmd->sense) {
18896029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
18906029a2d8Ssusans "megasas: pci_pool_alloc failed \n"));
18916029a2d8Ssusans
18926029a2d8Ssusans return (-ENOMEM);
18936029a2d8Ssusans }
18946029a2d8Ssusans
18956029a2d8Ssusans cmd->frame->io.context = cmd->index;
18966029a2d8Ssusans i++;
18976029a2d8Ssusans
18986029a2d8Ssusans con_log(CL_DLEVEL3, (CE_NOTE, "[%x]-%x",
18996029a2d8Ssusans cmd->frame->io.context, cmd->frame_phys_addr));
19006029a2d8Ssusans }
19016029a2d8Ssusans
19026029a2d8Ssusans return (DDI_SUCCESS);
19036029a2d8Ssusans }
19046029a2d8Ssusans
19056029a2d8Ssusans /*
19066029a2d8Ssusans * free_additional_dma_buffer
19076029a2d8Ssusans */
19086029a2d8Ssusans static void
free_additional_dma_buffer(struct megasas_instance * instance)19096029a2d8Ssusans free_additional_dma_buffer(struct megasas_instance *instance)
19106029a2d8Ssusans {
19116029a2d8Ssusans if (instance->mfi_internal_dma_obj.status == DMA_OBJ_ALLOCATED) {
19122fa451d9SYu Wu - Sun Microsystems - Beijing China (void) mega_free_dma_obj(instance,
19132fa451d9SYu Wu - Sun Microsystems - Beijing China instance->mfi_internal_dma_obj);
19146029a2d8Ssusans instance->mfi_internal_dma_obj.status = DMA_OBJ_FREED;
19156029a2d8Ssusans }
19166029a2d8Ssusans
19176029a2d8Ssusans if (instance->mfi_evt_detail_obj.status == DMA_OBJ_ALLOCATED) {
19182fa451d9SYu Wu - Sun Microsystems - Beijing China (void) mega_free_dma_obj(instance,
19192fa451d9SYu Wu - Sun Microsystems - Beijing China instance->mfi_evt_detail_obj);
19206029a2d8Ssusans instance->mfi_evt_detail_obj.status = DMA_OBJ_FREED;
19216029a2d8Ssusans }
19226029a2d8Ssusans }
19236029a2d8Ssusans
19246029a2d8Ssusans /*
19256029a2d8Ssusans * alloc_additional_dma_buffer
19266029a2d8Ssusans */
19276029a2d8Ssusans static int
alloc_additional_dma_buffer(struct megasas_instance * instance)19286029a2d8Ssusans alloc_additional_dma_buffer(struct megasas_instance *instance)
19296029a2d8Ssusans {
19306029a2d8Ssusans uint32_t reply_q_sz;
19316029a2d8Ssusans uint32_t internal_buf_size = PAGESIZE*2;
19326029a2d8Ssusans
19337ddfa2acSSusan Scheufele /* max cmds plus 1 + producer & consumer */
19346029a2d8Ssusans reply_q_sz = sizeof (uint32_t) * (instance->max_fw_cmds + 1 + 2);
19356029a2d8Ssusans
19366029a2d8Ssusans instance->mfi_internal_dma_obj.size = internal_buf_size;
19376029a2d8Ssusans instance->mfi_internal_dma_obj.dma_attr = megasas_generic_dma_attr;
19387ddfa2acSSusan Scheufele instance->mfi_internal_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
19397ddfa2acSSusan Scheufele instance->mfi_internal_dma_obj.dma_attr.dma_attr_count_max =
19407ddfa2acSSusan Scheufele 0xFFFFFFFFU;
19416029a2d8Ssusans instance->mfi_internal_dma_obj.dma_attr.dma_attr_sgllen = 1;
19426029a2d8Ssusans
19436029a2d8Ssusans if (mega_alloc_dma_obj(instance, &instance->mfi_internal_dma_obj)
19446029a2d8Ssusans != 1) {
19456029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: could not alloc reply Q"));
19466029a2d8Ssusans return (DDI_FAILURE);
19476029a2d8Ssusans }
19486029a2d8Ssusans
19496029a2d8Ssusans bzero(instance->mfi_internal_dma_obj.buffer, internal_buf_size);
19506029a2d8Ssusans
19516029a2d8Ssusans instance->mfi_internal_dma_obj.status |= DMA_OBJ_ALLOCATED;
19526029a2d8Ssusans
19537ddfa2acSSusan Scheufele instance->producer = (uint32_t *)((unsigned long)
19547ddfa2acSSusan Scheufele instance->mfi_internal_dma_obj.buffer);
19556029a2d8Ssusans instance->consumer = (uint32_t *)((unsigned long)
19566029a2d8Ssusans instance->mfi_internal_dma_obj.buffer + 4);
19576029a2d8Ssusans instance->reply_queue = (uint32_t *)((unsigned long)
19586029a2d8Ssusans instance->mfi_internal_dma_obj.buffer + 8);
19596029a2d8Ssusans instance->internal_buf = (caddr_t)(((unsigned long)
19606029a2d8Ssusans instance->mfi_internal_dma_obj.buffer) + reply_q_sz + 8);
19616029a2d8Ssusans instance->internal_buf_dmac_add =
19626029a2d8Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address +
19636029a2d8Ssusans reply_q_sz;
19646029a2d8Ssusans instance->internal_buf_size = internal_buf_size -
19656029a2d8Ssusans (reply_q_sz + 8);
19666029a2d8Ssusans
19676029a2d8Ssusans /* allocate evt_detail */
19686029a2d8Ssusans instance->mfi_evt_detail_obj.size = sizeof (struct megasas_evt_detail);
19696029a2d8Ssusans instance->mfi_evt_detail_obj.dma_attr = megasas_generic_dma_attr;
19707ddfa2acSSusan Scheufele instance->mfi_evt_detail_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
19717ddfa2acSSusan Scheufele instance->mfi_evt_detail_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
19726029a2d8Ssusans instance->mfi_evt_detail_obj.dma_attr.dma_attr_sgllen = 1;
19736029a2d8Ssusans instance->mfi_evt_detail_obj.dma_attr.dma_attr_align = 1;
19746029a2d8Ssusans
19756029a2d8Ssusans if (mega_alloc_dma_obj(instance, &instance->mfi_evt_detail_obj) != 1) {
19766029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "alloc_additional_dma_buffer: "
19776029a2d8Ssusans "could not data transfer buffer alloc."));
19786029a2d8Ssusans return (DDI_FAILURE);
19796029a2d8Ssusans }
19806029a2d8Ssusans
19816029a2d8Ssusans bzero(instance->mfi_evt_detail_obj.buffer,
19826029a2d8Ssusans sizeof (struct megasas_evt_detail));
19836029a2d8Ssusans
19846029a2d8Ssusans instance->mfi_evt_detail_obj.status |= DMA_OBJ_ALLOCATED;
19856029a2d8Ssusans
19866029a2d8Ssusans return (DDI_SUCCESS);
19876029a2d8Ssusans }
19886029a2d8Ssusans
19896029a2d8Ssusans /*
19906029a2d8Ssusans * free_space_for_mfi
19916029a2d8Ssusans */
19926029a2d8Ssusans static void
free_space_for_mfi(struct megasas_instance * instance)19936029a2d8Ssusans free_space_for_mfi(struct megasas_instance *instance)
19946029a2d8Ssusans {
19956029a2d8Ssusans int i;
19966029a2d8Ssusans uint32_t max_cmd = instance->max_fw_cmds;
19976029a2d8Ssusans
19986029a2d8Ssusans /* already freed */
19996029a2d8Ssusans if (instance->cmd_list == NULL) {
20006029a2d8Ssusans return;
20016029a2d8Ssusans }
20026029a2d8Ssusans
20036029a2d8Ssusans free_additional_dma_buffer(instance);
20046029a2d8Ssusans
20056029a2d8Ssusans /* first free the MFI frame pool */
20066029a2d8Ssusans destroy_mfi_frame_pool(instance);
20076029a2d8Ssusans
20086029a2d8Ssusans /* free all the commands in the cmd_list */
20096029a2d8Ssusans for (i = 0; i < instance->max_fw_cmds; i++) {
20106029a2d8Ssusans kmem_free(instance->cmd_list[i],
20116029a2d8Ssusans sizeof (struct megasas_cmd));
20126029a2d8Ssusans
20136029a2d8Ssusans instance->cmd_list[i] = NULL;
20146029a2d8Ssusans }
20156029a2d8Ssusans
20166029a2d8Ssusans /* free the cmd_list buffer itself */
20176029a2d8Ssusans kmem_free(instance->cmd_list,
20186029a2d8Ssusans sizeof (struct megasas_cmd *) * max_cmd);
20196029a2d8Ssusans
20206029a2d8Ssusans instance->cmd_list = NULL;
20216029a2d8Ssusans
20226029a2d8Ssusans INIT_LIST_HEAD(&instance->cmd_pool_list);
20236029a2d8Ssusans }
20246029a2d8Ssusans
20256029a2d8Ssusans /*
20266029a2d8Ssusans * alloc_space_for_mfi
20276029a2d8Ssusans */
20286029a2d8Ssusans static int
alloc_space_for_mfi(struct megasas_instance * instance)20296029a2d8Ssusans alloc_space_for_mfi(struct megasas_instance *instance)
20306029a2d8Ssusans {
20316029a2d8Ssusans int i;
20326029a2d8Ssusans uint32_t max_cmd;
20336029a2d8Ssusans size_t sz;
20346029a2d8Ssusans
20356029a2d8Ssusans struct megasas_cmd *cmd;
20366029a2d8Ssusans
20376029a2d8Ssusans max_cmd = instance->max_fw_cmds;
20386029a2d8Ssusans sz = sizeof (struct megasas_cmd *) * max_cmd;
20396029a2d8Ssusans
20406029a2d8Ssusans /*
20416029a2d8Ssusans * instance->cmd_list is an array of struct megasas_cmd pointers.
20426029a2d8Ssusans * Allocate the dynamic array first and then allocate individual
20436029a2d8Ssusans * commands.
20446029a2d8Ssusans */
20456029a2d8Ssusans instance->cmd_list = kmem_zalloc(sz, KM_SLEEP);
20466029a2d8Ssusans ASSERT(instance->cmd_list);
20476029a2d8Ssusans
20486029a2d8Ssusans for (i = 0; i < max_cmd; i++) {
20496029a2d8Ssusans instance->cmd_list[i] = kmem_zalloc(sizeof (struct megasas_cmd),
20506029a2d8Ssusans KM_SLEEP);
20516029a2d8Ssusans ASSERT(instance->cmd_list[i]);
20526029a2d8Ssusans }
20536029a2d8Ssusans
20546029a2d8Ssusans INIT_LIST_HEAD(&instance->cmd_pool_list);
20556029a2d8Ssusans
20566029a2d8Ssusans /* add all the commands to command pool (instance->cmd_pool) */
20576029a2d8Ssusans for (i = 0; i < max_cmd; i++) {
20586029a2d8Ssusans cmd = instance->cmd_list[i];
20596029a2d8Ssusans cmd->index = i;
20606029a2d8Ssusans
20616029a2d8Ssusans mlist_add_tail(&cmd->list, &instance->cmd_pool_list);
20626029a2d8Ssusans }
20636029a2d8Ssusans
20646029a2d8Ssusans /* create a frame pool and assign one frame to each cmd */
20656029a2d8Ssusans if (create_mfi_frame_pool(instance)) {
20666029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "error creating frame DMA pool\n"));
20676029a2d8Ssusans return (DDI_FAILURE);
20686029a2d8Ssusans }
20696029a2d8Ssusans
20706029a2d8Ssusans /* create a frame pool and assign one frame to each cmd */
20716029a2d8Ssusans if (alloc_additional_dma_buffer(instance)) {
20726029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "error creating frame DMA pool\n"));
20736029a2d8Ssusans return (DDI_FAILURE);
20746029a2d8Ssusans }
20756029a2d8Ssusans
20766029a2d8Ssusans return (DDI_SUCCESS);
20776029a2d8Ssusans }
20786029a2d8Ssusans
20796029a2d8Ssusans /*
20806029a2d8Ssusans * get_ctrl_info
20816029a2d8Ssusans */
20826029a2d8Ssusans static int
get_ctrl_info(struct megasas_instance * instance,struct megasas_ctrl_info * ctrl_info)20836029a2d8Ssusans get_ctrl_info(struct megasas_instance *instance,
20846029a2d8Ssusans struct megasas_ctrl_info *ctrl_info)
20856029a2d8Ssusans {
20866029a2d8Ssusans int ret = 0;
20876029a2d8Ssusans
20886029a2d8Ssusans struct megasas_cmd *cmd;
20896029a2d8Ssusans struct megasas_dcmd_frame *dcmd;
20906029a2d8Ssusans struct megasas_ctrl_info *ci;
20916029a2d8Ssusans
20926029a2d8Ssusans cmd = get_mfi_pkt(instance);
20936029a2d8Ssusans
20946029a2d8Ssusans if (!cmd) {
20956029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
20966029a2d8Ssusans "Failed to get a cmd for ctrl info\n"));
20976029a2d8Ssusans return (DDI_FAILURE);
20986029a2d8Ssusans }
20996029a2d8Ssusans
21006029a2d8Ssusans dcmd = &cmd->frame->dcmd;
21016029a2d8Ssusans
21026029a2d8Ssusans ci = (struct megasas_ctrl_info *)instance->internal_buf;
21036029a2d8Ssusans
21046029a2d8Ssusans if (!ci) {
21056029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
21066029a2d8Ssusans "Failed to alloc mem for ctrl info\n"));
21076029a2d8Ssusans return_mfi_pkt(instance, cmd);
21086029a2d8Ssusans return (DDI_FAILURE);
21096029a2d8Ssusans }
21106029a2d8Ssusans
21116029a2d8Ssusans (void) memset(ci, 0, sizeof (struct megasas_ctrl_info));
21126029a2d8Ssusans
21137ddfa2acSSusan Scheufele /* for( i = 0; i < DCMD_MBOX_SZ; i++ ) dcmd->mbox.b[i] = 0; */
21147ddfa2acSSusan Scheufele (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
21156029a2d8Ssusans
21166029a2d8Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
21177ddfa2acSSusan Scheufele dcmd->cmd_status = MFI_CMD_STATUS_POLL_MODE;
21186029a2d8Ssusans dcmd->sge_count = 1;
21196029a2d8Ssusans dcmd->flags = MFI_FRAME_DIR_READ;
21206029a2d8Ssusans dcmd->timeout = 0;
21216029a2d8Ssusans dcmd->data_xfer_len = sizeof (struct megasas_ctrl_info);
21226029a2d8Ssusans dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
21236029a2d8Ssusans dcmd->sgl.sge32[0].phys_addr = instance->internal_buf_dmac_add;
21246029a2d8Ssusans dcmd->sgl.sge32[0].length = sizeof (struct megasas_ctrl_info);
21256029a2d8Ssusans
21266029a2d8Ssusans cmd->frame_count = 1;
21276029a2d8Ssusans
21286029a2d8Ssusans if (!instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd)) {
21296029a2d8Ssusans ret = 0;
21306029a2d8Ssusans (void) memcpy(ctrl_info, ci, sizeof (struct megasas_ctrl_info));
21316029a2d8Ssusans } else {
21326029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "get_ctrl_info: Ctrl info failed\n"));
21336029a2d8Ssusans ret = -1;
21346029a2d8Ssusans }
21356029a2d8Ssusans
21366029a2d8Ssusans return_mfi_pkt(instance, cmd);
21372fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_common_check(instance, cmd) != DDI_SUCCESS) {
21382fa451d9SYu Wu - Sun Microsystems - Beijing China ret = -1;
21392fa451d9SYu Wu - Sun Microsystems - Beijing China }
21406029a2d8Ssusans
21416029a2d8Ssusans return (ret);
21426029a2d8Ssusans }
21436029a2d8Ssusans
21446029a2d8Ssusans /*
21456029a2d8Ssusans * abort_aen_cmd
21466029a2d8Ssusans */
21476029a2d8Ssusans static int
abort_aen_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd_to_abort)21486029a2d8Ssusans abort_aen_cmd(struct megasas_instance *instance,
21496029a2d8Ssusans struct megasas_cmd *cmd_to_abort)
21506029a2d8Ssusans {
21516029a2d8Ssusans int ret = 0;
21526029a2d8Ssusans
21536029a2d8Ssusans struct megasas_cmd *cmd;
21546029a2d8Ssusans struct megasas_abort_frame *abort_fr;
21556029a2d8Ssusans
21566029a2d8Ssusans cmd = get_mfi_pkt(instance);
21576029a2d8Ssusans
21586029a2d8Ssusans if (!cmd) {
21596029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
21606029a2d8Ssusans "Failed to get a cmd for ctrl info\n"));
21616029a2d8Ssusans return (DDI_FAILURE);
21626029a2d8Ssusans }
21636029a2d8Ssusans
21646029a2d8Ssusans abort_fr = &cmd->frame->abort;
21656029a2d8Ssusans
21666029a2d8Ssusans /* prepare and issue the abort frame */
21676029a2d8Ssusans abort_fr->cmd = MFI_CMD_OP_ABORT;
21687ddfa2acSSusan Scheufele abort_fr->cmd_status = MFI_CMD_STATUS_SYNC_MODE;
21696029a2d8Ssusans abort_fr->flags = 0;
21706029a2d8Ssusans abort_fr->abort_context = cmd_to_abort->index;
21716029a2d8Ssusans abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
21726029a2d8Ssusans abort_fr->abort_mfi_phys_addr_hi = 0;
21736029a2d8Ssusans
21746029a2d8Ssusans instance->aen_cmd->abort_aen = 1;
21756029a2d8Ssusans
21766029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
21776029a2d8Ssusans cmd->frame_count = 1;
21786029a2d8Ssusans
21796029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
21806029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
21816029a2d8Ssusans "abort_aen_cmd: issue_cmd_in_sync_mode failed\n"));
21826029a2d8Ssusans ret = -1;
21836029a2d8Ssusans } else {
21846029a2d8Ssusans ret = 0;
21856029a2d8Ssusans }
21866029a2d8Ssusans
21876029a2d8Ssusans instance->aen_cmd->abort_aen = 1;
21886029a2d8Ssusans instance->aen_cmd = 0;
21896029a2d8Ssusans
21906029a2d8Ssusans return_mfi_pkt(instance, cmd);
21912fa451d9SYu Wu - Sun Microsystems - Beijing China (void) megasas_common_check(instance, cmd);
21926029a2d8Ssusans
21936029a2d8Ssusans return (ret);
21946029a2d8Ssusans }
21956029a2d8Ssusans
21966029a2d8Ssusans /*
21976029a2d8Ssusans * init_mfi
21986029a2d8Ssusans */
21996029a2d8Ssusans static int
init_mfi(struct megasas_instance * instance)22006029a2d8Ssusans init_mfi(struct megasas_instance *instance)
22016029a2d8Ssusans {
22026029a2d8Ssusans off_t reglength;
22036029a2d8Ssusans struct megasas_cmd *cmd;
22046029a2d8Ssusans struct megasas_ctrl_info ctrl_info;
22056029a2d8Ssusans struct megasas_init_frame *init_frame;
22066029a2d8Ssusans struct megasas_init_queue_info *initq_info;
22076029a2d8Ssusans
22086029a2d8Ssusans if ((ddi_dev_regsize(instance->dip, REGISTER_SET_IO, ®length)
22097ddfa2acSSusan Scheufele != DDI_SUCCESS) || reglength < MINIMUM_MFI_MEM_SZ) {
22106029a2d8Ssusans return (DDI_FAILURE);
22116029a2d8Ssusans }
22126029a2d8Ssusans
22137ddfa2acSSusan Scheufele if (reglength > DEFAULT_MFI_MEM_SZ) {
22147ddfa2acSSusan Scheufele reglength = DEFAULT_MFI_MEM_SZ;
22153ddf1763Syw con_log(CL_DLEVEL1, (CE_NOTE,
22166029a2d8Ssusans "mega: register length to map is 0x%lx bytes", reglength));
22176029a2d8Ssusans }
22186029a2d8Ssusans
22196029a2d8Ssusans if (ddi_regs_map_setup(instance->dip, REGISTER_SET_IO,
22206029a2d8Ssusans &instance->regmap, 0, reglength, &endian_attr,
22216029a2d8Ssusans &instance->regmap_handle) != DDI_SUCCESS) {
22226029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
22236029a2d8Ssusans "megaraid: couldn't map control registers"));
22246029a2d8Ssusans
22256029a2d8Ssusans goto fail_mfi_reg_setup;
22266029a2d8Ssusans }
22276029a2d8Ssusans
22286029a2d8Ssusans /* we expect the FW state to be READY */
22296029a2d8Ssusans if (mfi_state_transition_to_ready(instance)) {
22306029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: F/W is not ready"));
22316029a2d8Ssusans goto fail_ready_state;
22326029a2d8Ssusans }
22336029a2d8Ssusans
22346029a2d8Ssusans /* get various operational parameters from status register */
22356029a2d8Ssusans instance->max_num_sge =
22366029a2d8Ssusans (instance->func_ptr->read_fw_status_reg(instance) &
22376029a2d8Ssusans 0xFF0000) >> 0x10;
22386029a2d8Ssusans /*
22396029a2d8Ssusans * Reduce the max supported cmds by 1. This is to ensure that the
22406029a2d8Ssusans * reply_q_sz (1 more than the max cmd that driver may send)
22416029a2d8Ssusans * does not exceed max cmds that the FW can support
22426029a2d8Ssusans */
22436029a2d8Ssusans instance->max_fw_cmds =
22446029a2d8Ssusans instance->func_ptr->read_fw_status_reg(instance) & 0xFFFF;
22456029a2d8Ssusans instance->max_fw_cmds = instance->max_fw_cmds - 1;
22466029a2d8Ssusans
22476029a2d8Ssusans instance->max_num_sge =
22486029a2d8Ssusans (instance->max_num_sge > MEGASAS_MAX_SGE_CNT) ?
22496029a2d8Ssusans MEGASAS_MAX_SGE_CNT : instance->max_num_sge;
22506029a2d8Ssusans
22516029a2d8Ssusans /* create a pool of commands */
22526029a2d8Ssusans if (alloc_space_for_mfi(instance))
22536029a2d8Ssusans goto fail_alloc_fw_space;
22546029a2d8Ssusans
22556029a2d8Ssusans /* disable interrupt for initial preparation */
22566029a2d8Ssusans instance->func_ptr->disable_intr(instance);
22576029a2d8Ssusans
22586029a2d8Ssusans /*
22596029a2d8Ssusans * Prepare a init frame. Note the init frame points to queue info
22606029a2d8Ssusans * structure. Each frame has SGL allocated after first 64 bytes. For
22616029a2d8Ssusans * this frame - since we don't need any SGL - we use SGL's space as
22626029a2d8Ssusans * queue info structure
22636029a2d8Ssusans */
22646029a2d8Ssusans cmd = get_mfi_pkt(instance);
22656029a2d8Ssusans
22666029a2d8Ssusans init_frame = (struct megasas_init_frame *)cmd->frame;
22676029a2d8Ssusans initq_info = (struct megasas_init_queue_info *)
22686029a2d8Ssusans ((unsigned long)init_frame + 64);
22696029a2d8Ssusans
22706029a2d8Ssusans (void) memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
22716029a2d8Ssusans (void) memset(initq_info, 0, sizeof (struct megasas_init_queue_info));
22726029a2d8Ssusans
22736029a2d8Ssusans initq_info->init_flags = 0;
22746029a2d8Ssusans
22756029a2d8Ssusans initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
22766029a2d8Ssusans
22776029a2d8Ssusans initq_info->producer_index_phys_addr_hi = 0;
22786029a2d8Ssusans initq_info->producer_index_phys_addr_lo =
22796029a2d8Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address;
22806029a2d8Ssusans
22816029a2d8Ssusans initq_info->consumer_index_phys_addr_hi = 0;
22826029a2d8Ssusans initq_info->consumer_index_phys_addr_lo =
22836029a2d8Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address + 4;
22846029a2d8Ssusans
22856029a2d8Ssusans initq_info->reply_queue_start_phys_addr_hi = 0;
22866029a2d8Ssusans initq_info->reply_queue_start_phys_addr_lo =
22876029a2d8Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address + 8;
22886029a2d8Ssusans
22896029a2d8Ssusans init_frame->cmd = MFI_CMD_OP_INIT;
22907ddfa2acSSusan Scheufele init_frame->cmd_status = MFI_CMD_STATUS_POLL_MODE;
22916029a2d8Ssusans init_frame->flags = 0;
22926029a2d8Ssusans init_frame->queue_info_new_phys_addr_lo =
22936029a2d8Ssusans cmd->frame_phys_addr + 64;
22946029a2d8Ssusans init_frame->queue_info_new_phys_addr_hi = 0;
22956029a2d8Ssusans
22966029a2d8Ssusans init_frame->data_xfer_len = sizeof (struct megasas_init_queue_info);
22976029a2d8Ssusans
22986029a2d8Ssusans cmd->frame_count = 1;
22996029a2d8Ssusans
23006029a2d8Ssusans /* issue the init frame in polled mode */
23016029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd)) {
23026029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "failed to init firmware"));
23036029a2d8Ssusans goto fail_fw_init;
23046029a2d8Ssusans }
23056029a2d8Ssusans
23066029a2d8Ssusans return_mfi_pkt(instance, cmd);
23072fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_common_check(instance, cmd) != DDI_SUCCESS) {
23082fa451d9SYu Wu - Sun Microsystems - Beijing China goto fail_fw_init;
23092fa451d9SYu Wu - Sun Microsystems - Beijing China }
23106029a2d8Ssusans
23116029a2d8Ssusans /* gather misc FW related information */
23126029a2d8Ssusans if (!get_ctrl_info(instance, &ctrl_info)) {
23136029a2d8Ssusans instance->max_sectors_per_req = ctrl_info.max_request_size;
23146029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "product name %s ld present %d",
23156029a2d8Ssusans ctrl_info.product_name, ctrl_info.ld_present_count));
23166029a2d8Ssusans } else {
23176029a2d8Ssusans instance->max_sectors_per_req = instance->max_num_sge *
23186029a2d8Ssusans PAGESIZE / 512;
23196029a2d8Ssusans }
23206029a2d8Ssusans
23212fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(instance->regmap_handle) != DDI_SUCCESS) {
23222fa451d9SYu Wu - Sun Microsystems - Beijing China goto fail_fw_init;
23232fa451d9SYu Wu - Sun Microsystems - Beijing China }
23242fa451d9SYu Wu - Sun Microsystems - Beijing China
23256029a2d8Ssusans return (0);
23266029a2d8Ssusans
23276029a2d8Ssusans fail_fw_init:
23286029a2d8Ssusans fail_alloc_fw_space:
23296029a2d8Ssusans
23306029a2d8Ssusans free_space_for_mfi(instance);
23316029a2d8Ssusans
23326029a2d8Ssusans fail_ready_state:
23336029a2d8Ssusans ddi_regs_map_free(&instance->regmap_handle);
23346029a2d8Ssusans
23356029a2d8Ssusans fail_mfi_reg_setup:
23366029a2d8Ssusans return (DDI_FAILURE);
23376029a2d8Ssusans }
23386029a2d8Ssusans
23396029a2d8Ssusans /*
23406029a2d8Ssusans * mfi_state_transition_to_ready : Move the FW to READY state
23416029a2d8Ssusans *
23426029a2d8Ssusans * @reg_set : MFI register set
23436029a2d8Ssusans */
23446029a2d8Ssusans static int
mfi_state_transition_to_ready(struct megasas_instance * instance)23456029a2d8Ssusans mfi_state_transition_to_ready(struct megasas_instance *instance)
23466029a2d8Ssusans {
23476029a2d8Ssusans int i;
23486029a2d8Ssusans uint8_t max_wait;
23496029a2d8Ssusans uint32_t fw_ctrl;
23506029a2d8Ssusans uint32_t fw_state;
23516029a2d8Ssusans uint32_t cur_state;
23526029a2d8Ssusans
23536029a2d8Ssusans fw_state =
23546029a2d8Ssusans instance->func_ptr->read_fw_status_reg(instance) & MFI_STATE_MASK;
23556029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
23566029a2d8Ssusans "mfi_state_transition_to_ready:FW state = 0x%x", fw_state));
23576029a2d8Ssusans
23586029a2d8Ssusans while (fw_state != MFI_STATE_READY) {
23596029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
23606029a2d8Ssusans "mfi_state_transition_to_ready:FW state%x", fw_state));
23616029a2d8Ssusans
23626029a2d8Ssusans switch (fw_state) {
23636029a2d8Ssusans case MFI_STATE_FAULT:
23646029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
23656029a2d8Ssusans "megasas: FW in FAULT state!!"));
23666029a2d8Ssusans
23676029a2d8Ssusans return (-ENODEV);
23686029a2d8Ssusans case MFI_STATE_WAIT_HANDSHAKE:
23696029a2d8Ssusans /* set the CLR bit in IMR0 */
23706029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
23716029a2d8Ssusans "megasas: FW waiting for HANDSHAKE"));
23726029a2d8Ssusans /*
23736029a2d8Ssusans * PCI_Hot Plug: MFI F/W requires
23746029a2d8Ssusans * (MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG)
23756029a2d8Ssusans * to be set
23766029a2d8Ssusans */
23776029a2d8Ssusans /* WR_IB_MSG_0(MFI_INIT_CLEAR_HANDSHAKE, instance); */
23786029a2d8Ssusans WR_IB_DOORBELL(MFI_INIT_CLEAR_HANDSHAKE |
23796029a2d8Ssusans MFI_INIT_HOTPLUG, instance);
23806029a2d8Ssusans
23816029a2d8Ssusans max_wait = 2;
23826029a2d8Ssusans cur_state = MFI_STATE_WAIT_HANDSHAKE;
23836029a2d8Ssusans break;
23846029a2d8Ssusans case MFI_STATE_BOOT_MESSAGE_PENDING:
23856029a2d8Ssusans /* set the CLR bit in IMR0 */
23866029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
23876029a2d8Ssusans "megasas: FW state boot message pending"));
23886029a2d8Ssusans /*
23896029a2d8Ssusans * PCI_Hot Plug: MFI F/W requires
23906029a2d8Ssusans * (MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG)
23916029a2d8Ssusans * to be set
23926029a2d8Ssusans */
23936029a2d8Ssusans WR_IB_DOORBELL(MFI_INIT_HOTPLUG, instance);
23946029a2d8Ssusans
23956029a2d8Ssusans max_wait = 10;
23966029a2d8Ssusans cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
23976029a2d8Ssusans break;
23986029a2d8Ssusans case MFI_STATE_OPERATIONAL:
23996029a2d8Ssusans /* bring it to READY state; assuming max wait 2 secs */
24006029a2d8Ssusans instance->func_ptr->disable_intr(instance);
24016029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
24026029a2d8Ssusans "megasas: FW in OPERATIONAL state"));
24036029a2d8Ssusans /*
24046029a2d8Ssusans * PCI_Hot Plug: MFI F/W requires
24056029a2d8Ssusans * (MFI_INIT_READY | MFI_INIT_MFIMODE | MFI_INIT_ABORT)
24066029a2d8Ssusans * to be set
24076029a2d8Ssusans */
24086029a2d8Ssusans /* WR_IB_DOORBELL(MFI_INIT_READY, instance); */
24096029a2d8Ssusans WR_IB_DOORBELL(MFI_RESET_FLAGS, instance);
24106029a2d8Ssusans
24116029a2d8Ssusans max_wait = 10;
24126029a2d8Ssusans cur_state = MFI_STATE_OPERATIONAL;
24136029a2d8Ssusans break;
24146029a2d8Ssusans case MFI_STATE_UNDEFINED:
24156029a2d8Ssusans /* this state should not last for more than 2 seconds */
24166029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "FW state undefined\n"));
24176029a2d8Ssusans
24186029a2d8Ssusans max_wait = 2;
24196029a2d8Ssusans cur_state = MFI_STATE_UNDEFINED;
24206029a2d8Ssusans break;
24216029a2d8Ssusans case MFI_STATE_BB_INIT:
24226029a2d8Ssusans max_wait = 2;
24236029a2d8Ssusans cur_state = MFI_STATE_BB_INIT;
24246029a2d8Ssusans break;
24256029a2d8Ssusans case MFI_STATE_FW_INIT:
24266029a2d8Ssusans max_wait = 2;
24276029a2d8Ssusans cur_state = MFI_STATE_FW_INIT;
24286029a2d8Ssusans break;
24296029a2d8Ssusans case MFI_STATE_DEVICE_SCAN:
24306029a2d8Ssusans max_wait = 10;
24316029a2d8Ssusans cur_state = MFI_STATE_DEVICE_SCAN;
24326029a2d8Ssusans break;
24336029a2d8Ssusans default:
24346029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
24356029a2d8Ssusans "megasas: Unknown state 0x%x\n", fw_state));
24366029a2d8Ssusans return (-ENODEV);
24376029a2d8Ssusans }
24386029a2d8Ssusans
24396029a2d8Ssusans /* the cur_state should not last for more than max_wait secs */
24407ddfa2acSSusan Scheufele for (i = 0; i < (max_wait * MILLISEC); i++) {
24416029a2d8Ssusans /* fw_state = RD_OB_MSG_0(instance) & MFI_STATE_MASK; */
24426029a2d8Ssusans fw_state =
24436029a2d8Ssusans instance->func_ptr->read_fw_status_reg(instance) &
24446029a2d8Ssusans MFI_STATE_MASK;
24456029a2d8Ssusans
24466029a2d8Ssusans if (fw_state == cur_state) {
24477ddfa2acSSusan Scheufele delay(1 * drv_usectohz(MILLISEC));
24486029a2d8Ssusans } else {
24496029a2d8Ssusans break;
24506029a2d8Ssusans }
24516029a2d8Ssusans }
24526029a2d8Ssusans
24536029a2d8Ssusans /* return error if fw_state hasn't changed after max_wait */
24546029a2d8Ssusans if (fw_state == cur_state) {
24556029a2d8Ssusans con_log(CL_ANN, (CE_NOTE,
24566029a2d8Ssusans "FW state hasn't changed in %d secs\n", max_wait));
24576029a2d8Ssusans return (-ENODEV);
24586029a2d8Ssusans }
24596029a2d8Ssusans };
24606029a2d8Ssusans
24616029a2d8Ssusans fw_ctrl = RD_IB_DOORBELL(instance);
24627ddfa2acSSusan Scheufele
24636029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
24646029a2d8Ssusans "mfi_state_transition_to_ready:FW ctrl = 0x%x", fw_ctrl));
24656029a2d8Ssusans
24666029a2d8Ssusans /*
24676029a2d8Ssusans * Write 0xF to the doorbell register to do the following.
24686029a2d8Ssusans * - Abort all outstanding commands (bit 0).
24696029a2d8Ssusans * - Transition from OPERATIONAL to READY state (bit 1).
24706029a2d8Ssusans * - Discard (possible) low MFA posted in 64-bit mode (bit-2).
24716029a2d8Ssusans * - Set to release FW to continue running (i.e. BIOS handshake
24726029a2d8Ssusans * (bit 3).
24736029a2d8Ssusans */
24746029a2d8Ssusans WR_IB_DOORBELL(0xF, instance);
24756029a2d8Ssusans
24762fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(instance->regmap_handle) != DDI_SUCCESS) {
24772fa451d9SYu Wu - Sun Microsystems - Beijing China return (-ENODEV);
24782fa451d9SYu Wu - Sun Microsystems - Beijing China }
24796029a2d8Ssusans return (0);
24806029a2d8Ssusans }
24816029a2d8Ssusans
24826029a2d8Ssusans /*
24836029a2d8Ssusans * get_seq_num
24846029a2d8Ssusans */
24856029a2d8Ssusans static int
get_seq_num(struct megasas_instance * instance,struct megasas_evt_log_info * eli)24866029a2d8Ssusans get_seq_num(struct megasas_instance *instance,
24876029a2d8Ssusans struct megasas_evt_log_info *eli)
24886029a2d8Ssusans {
24896029a2d8Ssusans int ret = 0;
24906029a2d8Ssusans
24916029a2d8Ssusans dma_obj_t dcmd_dma_obj;
24926029a2d8Ssusans struct megasas_cmd *cmd;
24936029a2d8Ssusans struct megasas_dcmd_frame *dcmd;
24946029a2d8Ssusans
24956029a2d8Ssusans cmd = get_mfi_pkt(instance);
24966029a2d8Ssusans
24976029a2d8Ssusans if (!cmd) {
24986029a2d8Ssusans cmn_err(CE_WARN, "megasas: failed to get a cmd\n");
24996029a2d8Ssusans return (-ENOMEM);
25006029a2d8Ssusans }
25016029a2d8Ssusans
25026029a2d8Ssusans dcmd = &cmd->frame->dcmd;
25036029a2d8Ssusans
25046029a2d8Ssusans /* allocate the data transfer buffer */
25056029a2d8Ssusans dcmd_dma_obj.size = sizeof (struct megasas_evt_log_info);
25066029a2d8Ssusans dcmd_dma_obj.dma_attr = megasas_generic_dma_attr;
25077ddfa2acSSusan Scheufele dcmd_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
25087ddfa2acSSusan Scheufele dcmd_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
25096029a2d8Ssusans dcmd_dma_obj.dma_attr.dma_attr_sgllen = 1;
25106029a2d8Ssusans dcmd_dma_obj.dma_attr.dma_attr_align = 1;
25116029a2d8Ssusans
25126029a2d8Ssusans if (mega_alloc_dma_obj(instance, &dcmd_dma_obj) != 1) {
25136029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
25146029a2d8Ssusans "get_seq_num: could not data transfer buffer alloc."));
25156029a2d8Ssusans return (DDI_FAILURE);
25166029a2d8Ssusans }
25176029a2d8Ssusans
25186029a2d8Ssusans (void) memset(dcmd_dma_obj.buffer, 0,
25196029a2d8Ssusans sizeof (struct megasas_evt_log_info));
25206029a2d8Ssusans
25217ddfa2acSSusan Scheufele (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
25226029a2d8Ssusans
25236029a2d8Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
25246029a2d8Ssusans dcmd->cmd_status = 0;
25256029a2d8Ssusans dcmd->sge_count = 1;
25266029a2d8Ssusans dcmd->flags = MFI_FRAME_DIR_READ;
25276029a2d8Ssusans dcmd->timeout = 0;
25286029a2d8Ssusans dcmd->data_xfer_len = sizeof (struct megasas_evt_log_info);
25296029a2d8Ssusans dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
25306029a2d8Ssusans dcmd->sgl.sge32[0].length = sizeof (struct megasas_evt_log_info);
25316029a2d8Ssusans dcmd->sgl.sge32[0].phys_addr = dcmd_dma_obj.dma_cookie[0].dmac_address;
25326029a2d8Ssusans
25336029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
25346029a2d8Ssusans cmd->frame_count = 1;
25356029a2d8Ssusans
25366029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
25376029a2d8Ssusans cmn_err(CE_WARN, "get_seq_num: "
25386029a2d8Ssusans "failed to issue MR_DCMD_CTRL_EVENT_GET_INFO\n");
25396029a2d8Ssusans ret = -1;
25406029a2d8Ssusans } else {
25416029a2d8Ssusans /* copy the data back into callers buffer */
25426029a2d8Ssusans bcopy(dcmd_dma_obj.buffer, eli,
25436029a2d8Ssusans sizeof (struct megasas_evt_log_info));
25446029a2d8Ssusans ret = 0;
25456029a2d8Ssusans }
25466029a2d8Ssusans
25472fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, dcmd_dma_obj) != DDI_SUCCESS)
25482fa451d9SYu Wu - Sun Microsystems - Beijing China ret = -1;
25496029a2d8Ssusans
25506029a2d8Ssusans return_mfi_pkt(instance, cmd);
25512fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_common_check(instance, cmd) != DDI_SUCCESS) {
25522fa451d9SYu Wu - Sun Microsystems - Beijing China ret = -1;
25532fa451d9SYu Wu - Sun Microsystems - Beijing China }
25546029a2d8Ssusans return (ret);
25556029a2d8Ssusans }
25566029a2d8Ssusans
25576029a2d8Ssusans /*
25586029a2d8Ssusans * start_mfi_aen
25596029a2d8Ssusans */
25606029a2d8Ssusans static int
start_mfi_aen(struct megasas_instance * instance)25616029a2d8Ssusans start_mfi_aen(struct megasas_instance *instance)
25626029a2d8Ssusans {
25636029a2d8Ssusans int ret = 0;
25646029a2d8Ssusans
25656029a2d8Ssusans struct megasas_evt_log_info eli;
25666029a2d8Ssusans union megasas_evt_class_locale class_locale;
25676029a2d8Ssusans
25686029a2d8Ssusans /* get the latest sequence number from FW */
25696029a2d8Ssusans (void) memset(&eli, 0, sizeof (struct megasas_evt_log_info));
25706029a2d8Ssusans
25716029a2d8Ssusans if (get_seq_num(instance, &eli)) {
25726029a2d8Ssusans cmn_err(CE_WARN, "start_mfi_aen: failed to get seq num\n");
25736029a2d8Ssusans return (-1);
25746029a2d8Ssusans }
25756029a2d8Ssusans
25766029a2d8Ssusans /* register AEN with FW for latest sequence number plus 1 */
25776029a2d8Ssusans class_locale.members.reserved = 0;
25786029a2d8Ssusans class_locale.members.locale = MR_EVT_LOCALE_ALL;
25796029a2d8Ssusans class_locale.members.class = MR_EVT_CLASS_CRITICAL;
25806029a2d8Ssusans
25816029a2d8Ssusans ret = register_mfi_aen(instance, eli.newest_seq_num + 1,
25826029a2d8Ssusans class_locale.word);
25836029a2d8Ssusans
25846029a2d8Ssusans if (ret) {
25856029a2d8Ssusans cmn_err(CE_WARN, "start_mfi_aen: aen registration failed\n");
25866029a2d8Ssusans return (-1);
25876029a2d8Ssusans }
25886029a2d8Ssusans
25896029a2d8Ssusans return (ret);
25906029a2d8Ssusans }
25916029a2d8Ssusans
25926029a2d8Ssusans /*
25936029a2d8Ssusans * flush_cache
25946029a2d8Ssusans */
25956029a2d8Ssusans static void
flush_cache(struct megasas_instance * instance)25966029a2d8Ssusans flush_cache(struct megasas_instance *instance)
25976029a2d8Ssusans {
25986029a2d8Ssusans struct megasas_cmd *cmd;
25996029a2d8Ssusans struct megasas_dcmd_frame *dcmd;
26006029a2d8Ssusans
26016029a2d8Ssusans if (!(cmd = get_mfi_pkt(instance)))
26026029a2d8Ssusans return;
26036029a2d8Ssusans
26046029a2d8Ssusans dcmd = &cmd->frame->dcmd;
26056029a2d8Ssusans
26067ddfa2acSSusan Scheufele (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
26076029a2d8Ssusans
26086029a2d8Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
26096029a2d8Ssusans dcmd->cmd_status = 0x0;
26106029a2d8Ssusans dcmd->sge_count = 0;
26116029a2d8Ssusans dcmd->flags = MFI_FRAME_DIR_NONE;
26126029a2d8Ssusans dcmd->timeout = 0;
26136029a2d8Ssusans dcmd->data_xfer_len = 0;
26146029a2d8Ssusans dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
26156029a2d8Ssusans dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
26166029a2d8Ssusans
26176029a2d8Ssusans cmd->frame_count = 1;
26186029a2d8Ssusans
26196029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd)) {
26206029a2d8Ssusans cmn_err(CE_WARN,
26216029a2d8Ssusans "flush_cache: failed to issue MFI_DCMD_CTRL_CACHE_FLUSH\n");
26226029a2d8Ssusans }
26233ddf1763Syw con_log(CL_DLEVEL1, (CE_NOTE, "done"));
26246029a2d8Ssusans return_mfi_pkt(instance, cmd);
26252fa451d9SYu Wu - Sun Microsystems - Beijing China (void) megasas_common_check(instance, cmd);
26266029a2d8Ssusans }
26276029a2d8Ssusans
26286029a2d8Ssusans /*
26296029a2d8Ssusans * service_mfi_aen- Completes an AEN command
26306029a2d8Ssusans * @instance: Adapter soft state
26316029a2d8Ssusans * @cmd: Command to be completed
26326029a2d8Ssusans *
26336029a2d8Ssusans */
26346029a2d8Ssusans static void
service_mfi_aen(struct megasas_instance * instance,struct megasas_cmd * cmd)26356029a2d8Ssusans service_mfi_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
26366029a2d8Ssusans {
26376029a2d8Ssusans uint32_t seq_num;
26386029a2d8Ssusans struct megasas_evt_detail *evt_detail =
26396029a2d8Ssusans (struct megasas_evt_detail *)instance->mfi_evt_detail_obj.buffer;
26406029a2d8Ssusans
26416029a2d8Ssusans cmd->cmd_status = cmd->frame->io.cmd_status;
26426029a2d8Ssusans
26436029a2d8Ssusans if (cmd->cmd_status == ENODATA) {
26446029a2d8Ssusans cmd->cmd_status = 0;
26456029a2d8Ssusans }
26466029a2d8Ssusans
26476029a2d8Ssusans /*
26486029a2d8Ssusans * log the MFI AEN event to the sysevent queue so that
26496029a2d8Ssusans * application will get noticed
26506029a2d8Ssusans */
26516029a2d8Ssusans if (ddi_log_sysevent(instance->dip, DDI_VENDOR_LSI, "LSIMEGA", "SAS",
26526029a2d8Ssusans NULL, NULL, DDI_NOSLEEP) != DDI_SUCCESS) {
26536029a2d8Ssusans int instance_no = ddi_get_instance(instance->dip);
26546029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
26556029a2d8Ssusans "mega%d: Failed to log AEN event", instance_no));
26566029a2d8Ssusans }
26576029a2d8Ssusans
26586029a2d8Ssusans /* get copy of seq_num and class/locale for re-registration */
26596029a2d8Ssusans seq_num = evt_detail->seq_num;
26606029a2d8Ssusans seq_num++;
26616029a2d8Ssusans (void) memset(instance->mfi_evt_detail_obj.buffer, 0,
26626029a2d8Ssusans sizeof (struct megasas_evt_detail));
26636029a2d8Ssusans
26646029a2d8Ssusans cmd->frame->dcmd.cmd_status = 0x0;
26656029a2d8Ssusans cmd->frame->dcmd.mbox.w[0] = seq_num;
26666029a2d8Ssusans
26676029a2d8Ssusans instance->aen_seq_num = seq_num;
26686029a2d8Ssusans
26696029a2d8Ssusans cmd->frame_count = 1;
26706029a2d8Ssusans
26716029a2d8Ssusans /* Issue the aen registration frame */
26726029a2d8Ssusans instance->func_ptr->issue_cmd(cmd, instance);
26736029a2d8Ssusans }
26746029a2d8Ssusans
26756029a2d8Ssusans /*
26766029a2d8Ssusans * complete_cmd_in_sync_mode - Completes an internal command
26776029a2d8Ssusans * @instance: Adapter soft state
26786029a2d8Ssusans * @cmd: Command to be completed
26796029a2d8Ssusans *
26806029a2d8Ssusans * The issue_cmd_in_sync_mode() function waits for a command to complete
26816029a2d8Ssusans * after it issues a command. This function wakes up that waiting routine by
26826029a2d8Ssusans * calling wake_up() on the wait queue.
26836029a2d8Ssusans */
26846029a2d8Ssusans static void
complete_cmd_in_sync_mode(struct megasas_instance * instance,struct megasas_cmd * cmd)26856029a2d8Ssusans complete_cmd_in_sync_mode(struct megasas_instance *instance,
26866029a2d8Ssusans struct megasas_cmd *cmd)
26876029a2d8Ssusans {
26886029a2d8Ssusans cmd->cmd_status = cmd->frame->io.cmd_status;
26896029a2d8Ssusans
26906029a2d8Ssusans cmd->sync_cmd = MEGASAS_FALSE;
26916029a2d8Ssusans
26926029a2d8Ssusans if (cmd->cmd_status == ENODATA) {
26936029a2d8Ssusans cmd->cmd_status = 0;
26946029a2d8Ssusans }
26956029a2d8Ssusans
26966029a2d8Ssusans cv_broadcast(&instance->int_cmd_cv);
26976029a2d8Ssusans }
26986029a2d8Ssusans
26996029a2d8Ssusans /*
27006029a2d8Ssusans * megasas_softintr - The Software ISR
27016029a2d8Ssusans * @param arg : HBA soft state
27026029a2d8Ssusans *
27036029a2d8Ssusans * called from high-level interrupt if hi-level interrupt are not there,
27046029a2d8Ssusans * otherwise triggered as a soft interrupt
27056029a2d8Ssusans */
27066029a2d8Ssusans static uint_t
megasas_softintr(struct megasas_instance * instance)27077ddfa2acSSusan Scheufele megasas_softintr(struct megasas_instance *instance)
27086029a2d8Ssusans {
27096029a2d8Ssusans struct scsi_pkt *pkt;
27106029a2d8Ssusans struct scsa_cmd *acmd;
27116029a2d8Ssusans struct megasas_cmd *cmd;
27126029a2d8Ssusans struct mlist_head *pos, *next;
27136029a2d8Ssusans mlist_t process_list;
27146029a2d8Ssusans struct megasas_header *hdr;
27157ddfa2acSSusan Scheufele struct scsi_arq_status *arqstat;
27166029a2d8Ssusans
27176029a2d8Ssusans con_log(CL_ANN1, (CE_CONT, "megasas_softintr called"));
27186029a2d8Ssusans
27197ddfa2acSSusan Scheufele ASSERT(instance);
27206029a2d8Ssusans mutex_enter(&instance->completed_pool_mtx);
27216029a2d8Ssusans
27226029a2d8Ssusans if (mlist_empty(&instance->completed_pool_list)) {
27236029a2d8Ssusans mutex_exit(&instance->completed_pool_mtx);
27246029a2d8Ssusans return (DDI_INTR_UNCLAIMED);
27256029a2d8Ssusans }
27266029a2d8Ssusans
27276029a2d8Ssusans instance->softint_running = 1;
27286029a2d8Ssusans
27296029a2d8Ssusans INIT_LIST_HEAD(&process_list);
27306029a2d8Ssusans mlist_splice(&instance->completed_pool_list, &process_list);
27316029a2d8Ssusans INIT_LIST_HEAD(&instance->completed_pool_list);
27326029a2d8Ssusans
27336029a2d8Ssusans mutex_exit(&instance->completed_pool_mtx);
27346029a2d8Ssusans
27356029a2d8Ssusans /* perform all callbacks first, before releasing the SCBs */
27366029a2d8Ssusans mlist_for_each_safe(pos, next, &process_list) {
27376029a2d8Ssusans cmd = mlist_entry(pos, struct megasas_cmd, list);
27386029a2d8Ssusans
27396029a2d8Ssusans /* syncronize the Cmd frame for the controller */
27406029a2d8Ssusans (void) ddi_dma_sync(cmd->frame_dma_obj.dma_handle,
27416029a2d8Ssusans 0, 0, DDI_DMA_SYNC_FORCPU);
27422fa451d9SYu Wu - Sun Microsystems - Beijing China
27432fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(cmd->frame_dma_obj.dma_handle) !=
27442fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SUCCESS) {
27452fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
27462fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
27472fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_INTR_UNCLAIMED);
27482fa451d9SYu Wu - Sun Microsystems - Beijing China }
27492fa451d9SYu Wu - Sun Microsystems - Beijing China
27506029a2d8Ssusans hdr = &cmd->frame->hdr;
27516029a2d8Ssusans
27526029a2d8Ssusans /* remove the internal command from the process list */
27536029a2d8Ssusans mlist_del_init(&cmd->list);
27546029a2d8Ssusans
27556029a2d8Ssusans switch (hdr->cmd) {
27566029a2d8Ssusans case MFI_CMD_OP_PD_SCSI:
27576029a2d8Ssusans case MFI_CMD_OP_LD_SCSI:
27586029a2d8Ssusans case MFI_CMD_OP_LD_READ:
27596029a2d8Ssusans case MFI_CMD_OP_LD_WRITE:
27606029a2d8Ssusans /*
27616029a2d8Ssusans * MFI_CMD_OP_PD_SCSI and MFI_CMD_OP_LD_SCSI
27626029a2d8Ssusans * could have been issued either through an
27636029a2d8Ssusans * IO path or an IOCTL path. If it was via IOCTL,
27646029a2d8Ssusans * we will send it to internal completion.
27656029a2d8Ssusans */
27666029a2d8Ssusans if (cmd->sync_cmd == MEGASAS_TRUE) {
27676029a2d8Ssusans complete_cmd_in_sync_mode(instance, cmd);
27686029a2d8Ssusans break;
27696029a2d8Ssusans }
27706029a2d8Ssusans
27716029a2d8Ssusans /* regular commands */
27726029a2d8Ssusans acmd = cmd->cmd;
27736029a2d8Ssusans pkt = CMD2PKT(acmd);
27746029a2d8Ssusans
27756029a2d8Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
27766029a2d8Ssusans if (acmd->cmd_flags & CFLAG_CONSISTENT) {
27776029a2d8Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle,
27786029a2d8Ssusans acmd->cmd_dma_offset,
27796029a2d8Ssusans acmd->cmd_dma_len,
27806029a2d8Ssusans DDI_DMA_SYNC_FORCPU);
27816029a2d8Ssusans }
27826029a2d8Ssusans }
27836029a2d8Ssusans
27846029a2d8Ssusans pkt->pkt_reason = CMD_CMPLT;
27856029a2d8Ssusans pkt->pkt_statistics = 0;
27863ddf1763Syw pkt->pkt_state = STATE_GOT_BUS
27873ddf1763Syw | STATE_GOT_TARGET | STATE_SENT_CMD
27883ddf1763Syw | STATE_XFERRED_DATA | STATE_GOT_STATUS;
27896029a2d8Ssusans
27906029a2d8Ssusans con_log(CL_ANN1, (CE_CONT,
27916029a2d8Ssusans "CDB[0] = %x completed for %s: size %lx context %x",
27926029a2d8Ssusans pkt->pkt_cdbp[0], ((acmd->islogical) ? "LD" : "PD"),
27936029a2d8Ssusans acmd->cmd_dmacount, hdr->context));
27946029a2d8Ssusans
27956029a2d8Ssusans if (pkt->pkt_cdbp[0] == SCMD_INQUIRY) {
27966029a2d8Ssusans struct scsi_inquiry *inq;
27976029a2d8Ssusans
27986029a2d8Ssusans if (acmd->cmd_dmacount != 0) {
27996029a2d8Ssusans bp_mapin(acmd->cmd_buf);
28006029a2d8Ssusans inq = (struct scsi_inquiry *)
28016029a2d8Ssusans acmd->cmd_buf->b_un.b_addr;
28026029a2d8Ssusans
28036029a2d8Ssusans /* don't expose physical drives to OS */
28046029a2d8Ssusans if (acmd->islogical &&
28056029a2d8Ssusans (hdr->cmd_status == MFI_STAT_OK)) {
28066029a2d8Ssusans display_scsi_inquiry(
28076029a2d8Ssusans (caddr_t)inq);
28086029a2d8Ssusans } else if ((hdr->cmd_status ==
28096029a2d8Ssusans MFI_STAT_OK) && inq->inq_dtype ==
28106029a2d8Ssusans DTYPE_DIRECT) {
28116029a2d8Ssusans
28126029a2d8Ssusans display_scsi_inquiry(
28136029a2d8Ssusans (caddr_t)inq);
28146029a2d8Ssusans
28156029a2d8Ssusans /* for physical disk */
28166029a2d8Ssusans hdr->cmd_status =
28176029a2d8Ssusans MFI_STAT_DEVICE_NOT_FOUND;
28186029a2d8Ssusans }
28196029a2d8Ssusans }
28206029a2d8Ssusans }
28216029a2d8Ssusans
28226029a2d8Ssusans switch (hdr->cmd_status) {
28236029a2d8Ssusans case MFI_STAT_OK:
28246029a2d8Ssusans pkt->pkt_scbp[0] = STATUS_GOOD;
28256029a2d8Ssusans break;
28266029a2d8Ssusans case MFI_STAT_LD_CC_IN_PROGRESS:
28276029a2d8Ssusans case MFI_STAT_LD_RECON_IN_PROGRESS:
28286029a2d8Ssusans /* SJ - these are not correct way */
28296029a2d8Ssusans pkt->pkt_scbp[0] = STATUS_GOOD;
28303ddf1763Syw break;
28313ddf1763Syw case MFI_STAT_LD_INIT_IN_PROGRESS:
28323ddf1763Syw con_log(CL_ANN,
28333ddf1763Syw (CE_WARN, "Initialization in Progress"));
28343ddf1763Syw pkt->pkt_reason = CMD_TRAN_ERR;
28353ddf1763Syw
28366029a2d8Ssusans break;
28376029a2d8Ssusans case MFI_STAT_SCSI_DONE_WITH_ERROR:
28386029a2d8Ssusans con_log(CL_ANN1, (CE_CONT, "scsi_done error"));
28393ddf1763Syw
28403ddf1763Syw pkt->pkt_reason = CMD_CMPLT;
28413ddf1763Syw ((struct scsi_status *)
28423ddf1763Syw pkt->pkt_scbp)->sts_chk = 1;
28433ddf1763Syw
28443ddf1763Syw if (pkt->pkt_cdbp[0] == SCMD_TEST_UNIT_READY) {
28453ddf1763Syw
28463ddf1763Syw con_log(CL_ANN,
28473ddf1763Syw (CE_WARN, "TEST_UNIT_READY fail"));
28483ddf1763Syw
28496029a2d8Ssusans } else {
28503ddf1763Syw pkt->pkt_state |= STATE_ARQ_DONE;
28513ddf1763Syw arqstat = (void *)(pkt->pkt_scbp);
28523ddf1763Syw arqstat->sts_rqpkt_reason = CMD_CMPLT;
28533ddf1763Syw arqstat->sts_rqpkt_resid = 0;
28543ddf1763Syw arqstat->sts_rqpkt_state |=
28553ddf1763Syw STATE_GOT_BUS | STATE_GOT_TARGET
28563ddf1763Syw | STATE_SENT_CMD
28573ddf1763Syw | STATE_XFERRED_DATA;
28583ddf1763Syw *(uint8_t *)&arqstat->sts_rqpkt_status =
28593ddf1763Syw STATUS_GOOD;
28603ddf1763Syw
28613ddf1763Syw bcopy(cmd->sense,
28623ddf1763Syw &(arqstat->sts_sensedata),
28637ddfa2acSSusan Scheufele acmd->cmd_scblen -
28643ddf1763Syw offsetof(struct scsi_arq_status,
28653ddf1763Syw sts_sensedata));
28666029a2d8Ssusans }
28676029a2d8Ssusans break;
28683ddf1763Syw case MFI_STAT_LD_OFFLINE:
28696029a2d8Ssusans case MFI_STAT_DEVICE_NOT_FOUND:
28706029a2d8Ssusans con_log(CL_ANN1, (CE_CONT,
28716029a2d8Ssusans "device not found error"));
28726029a2d8Ssusans pkt->pkt_reason = CMD_DEV_GONE;
28736029a2d8Ssusans pkt->pkt_statistics = STAT_DISCON;
28746029a2d8Ssusans break;
28753ddf1763Syw case MFI_STAT_LD_LBA_OUT_OF_RANGE:
28763ddf1763Syw pkt->pkt_state |= STATE_ARQ_DONE;
28773ddf1763Syw pkt->pkt_reason = CMD_CMPLT;
28786029a2d8Ssusans ((struct scsi_status *)
28793ddf1763Syw pkt->pkt_scbp)->sts_chk = 1;
28803ddf1763Syw
28813ddf1763Syw arqstat = (void *)(pkt->pkt_scbp);
28823ddf1763Syw arqstat->sts_rqpkt_reason = CMD_CMPLT;
28833ddf1763Syw arqstat->sts_rqpkt_resid = 0;
28843ddf1763Syw arqstat->sts_rqpkt_state |= STATE_GOT_BUS
28853ddf1763Syw | STATE_GOT_TARGET | STATE_SENT_CMD
28863ddf1763Syw | STATE_XFERRED_DATA;
28873ddf1763Syw *(uint8_t *)&arqstat->sts_rqpkt_status =
28883ddf1763Syw STATUS_GOOD;
28893ddf1763Syw
28903ddf1763Syw arqstat->sts_sensedata.es_valid = 1;
28913ddf1763Syw arqstat->sts_sensedata.es_key =
28923ddf1763Syw KEY_ILLEGAL_REQUEST;
28933ddf1763Syw arqstat->sts_sensedata.es_class =
28943ddf1763Syw CLASS_EXTENDED_SENSE;
28953ddf1763Syw
28963ddf1763Syw /*
28973ddf1763Syw * LOGICAL BLOCK ADDRESS OUT OF RANGE:
28983ddf1763Syw * ASC: 0x21h; ASCQ: 0x00h;
28993ddf1763Syw */
29003ddf1763Syw arqstat->sts_sensedata.es_add_code = 0x21;
29013ddf1763Syw arqstat->sts_sensedata.es_qual_code = 0x00;
29023ddf1763Syw
29033ddf1763Syw break;
29043ddf1763Syw
29053ddf1763Syw default:
29063ddf1763Syw con_log(CL_ANN, (CE_CONT, "Unknown status!"));
29073ddf1763Syw pkt->pkt_reason = CMD_TRAN_ERR;
29083ddf1763Syw
29096029a2d8Ssusans break;
29106029a2d8Ssusans }
29116029a2d8Ssusans
29126029a2d8Ssusans atomic_add_16(&instance->fw_outstanding, (-1));
29136029a2d8Ssusans
29146029a2d8Ssusans return_mfi_pkt(instance, cmd);
29152fa451d9SYu Wu - Sun Microsystems - Beijing China
29162fa451d9SYu Wu - Sun Microsystems - Beijing China (void) megasas_common_check(instance, cmd);
29172fa451d9SYu Wu - Sun Microsystems - Beijing China
29182fa451d9SYu Wu - Sun Microsystems - Beijing China if (acmd->cmd_dmahandle) {
29192fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(
29202fa451d9SYu Wu - Sun Microsystems - Beijing China acmd->cmd_dmahandle) != DDI_SUCCESS) {
29212fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip,
29222fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SERVICE_UNAFFECTED);
29232fa451d9SYu Wu - Sun Microsystems - Beijing China pkt->pkt_reason = CMD_TRAN_ERR;
29242fa451d9SYu Wu - Sun Microsystems - Beijing China pkt->pkt_statistics = 0;
29252fa451d9SYu Wu - Sun Microsystems - Beijing China }
29262fa451d9SYu Wu - Sun Microsystems - Beijing China }
29276029a2d8Ssusans
29286029a2d8Ssusans /* Call the callback routine */
29299c57abc8Ssrivijitha dugganapalli if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
29309c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt);
29316029a2d8Ssusans }
29326029a2d8Ssusans
29336029a2d8Ssusans break;
29346029a2d8Ssusans case MFI_CMD_OP_SMP:
29356029a2d8Ssusans case MFI_CMD_OP_STP:
29366029a2d8Ssusans complete_cmd_in_sync_mode(instance, cmd);
29376029a2d8Ssusans break;
29386029a2d8Ssusans case MFI_CMD_OP_DCMD:
29396029a2d8Ssusans /* see if got an event notification */
29406029a2d8Ssusans if (cmd->frame->dcmd.opcode ==
29416029a2d8Ssusans MR_DCMD_CTRL_EVENT_WAIT) {
29426029a2d8Ssusans if ((instance->aen_cmd == cmd) &&
29436029a2d8Ssusans (instance->aen_cmd->abort_aen)) {
29446029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
29456029a2d8Ssusans "megasas_softintr: "
29466029a2d8Ssusans "aborted_aen returned"));
29476029a2d8Ssusans } else {
29486029a2d8Ssusans service_mfi_aen(instance, cmd);
294914cd9973SSusan Scheufele
295014cd9973SSusan Scheufele atomic_add_16(&instance->fw_outstanding,
295114cd9973SSusan Scheufele (-1));
29526029a2d8Ssusans }
29536029a2d8Ssusans } else {
29546029a2d8Ssusans complete_cmd_in_sync_mode(instance, cmd);
29556029a2d8Ssusans }
29566029a2d8Ssusans
29576029a2d8Ssusans break;
29586029a2d8Ssusans case MFI_CMD_OP_ABORT:
29596029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "MFI_CMD_OP_ABORT complete"));
29606029a2d8Ssusans /*
29616029a2d8Ssusans * MFI_CMD_OP_ABORT successfully completed
29626029a2d8Ssusans * in the synchronous mode
29636029a2d8Ssusans */
29646029a2d8Ssusans complete_cmd_in_sync_mode(instance, cmd);
29656029a2d8Ssusans break;
29666029a2d8Ssusans default:
29672fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
29682fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
29692fa451d9SYu Wu - Sun Microsystems - Beijing China
29702fa451d9SYu Wu - Sun Microsystems - Beijing China if (cmd->pkt != NULL) {
29712fa451d9SYu Wu - Sun Microsystems - Beijing China pkt = cmd->pkt;
29729c57abc8Ssrivijitha dugganapalli if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
29739c57abc8Ssrivijitha dugganapalli scsi_hba_pkt_comp(pkt);
29742fa451d9SYu Wu - Sun Microsystems - Beijing China }
29752fa451d9SYu Wu - Sun Microsystems - Beijing China }
29762fa451d9SYu Wu - Sun Microsystems - Beijing China con_log(CL_ANN, (CE_WARN, "Cmd type unknown !!"));
29776029a2d8Ssusans break;
29786029a2d8Ssusans }
29796029a2d8Ssusans }
29806029a2d8Ssusans
29816029a2d8Ssusans instance->softint_running = 0;
29826029a2d8Ssusans
29836029a2d8Ssusans return (DDI_INTR_CLAIMED);
29846029a2d8Ssusans }
29856029a2d8Ssusans
29866029a2d8Ssusans /*
29876029a2d8Ssusans * mega_alloc_dma_obj
29886029a2d8Ssusans *
29896029a2d8Ssusans * Allocate the memory and other resources for an dma object.
29906029a2d8Ssusans */
29916029a2d8Ssusans static int
mega_alloc_dma_obj(struct megasas_instance * instance,dma_obj_t * obj)29926029a2d8Ssusans mega_alloc_dma_obj(struct megasas_instance *instance, dma_obj_t *obj)
29936029a2d8Ssusans {
29946029a2d8Ssusans int i;
29956029a2d8Ssusans size_t alen = 0;
29966029a2d8Ssusans uint_t cookie_cnt;
2997837c1ac4SStephen Hanson struct ddi_device_acc_attr tmp_endian_attr;
29986029a2d8Ssusans
2999837c1ac4SStephen Hanson tmp_endian_attr = endian_attr;
3000837c1ac4SStephen Hanson tmp_endian_attr.devacc_attr_access = DDI_DEFAULT_ACC;
30016029a2d8Ssusans i = ddi_dma_alloc_handle(instance->dip, &obj->dma_attr,
30026029a2d8Ssusans DDI_DMA_SLEEP, NULL, &obj->dma_handle);
30036029a2d8Ssusans if (i != DDI_SUCCESS) {
30046029a2d8Ssusans
30056029a2d8Ssusans switch (i) {
30066029a2d8Ssusans case DDI_DMA_BADATTR :
30076029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
30086029a2d8Ssusans "Failed ddi_dma_alloc_handle- Bad atrib"));
30096029a2d8Ssusans break;
30106029a2d8Ssusans case DDI_DMA_NORESOURCES :
30116029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
30126029a2d8Ssusans "Failed ddi_dma_alloc_handle- No Resources"));
30136029a2d8Ssusans break;
30146029a2d8Ssusans default :
30156029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
30166029a2d8Ssusans "Failed ddi_dma_alloc_handle :unknown %d", i));
30176029a2d8Ssusans break;
30186029a2d8Ssusans }
30196029a2d8Ssusans
30206029a2d8Ssusans return (-1);
30216029a2d8Ssusans }
30226029a2d8Ssusans
3023837c1ac4SStephen Hanson if ((ddi_dma_mem_alloc(obj->dma_handle, obj->size, &tmp_endian_attr,
30246029a2d8Ssusans DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
30256029a2d8Ssusans &obj->buffer, &alen, &obj->acc_handle) != DDI_SUCCESS) ||
30266029a2d8Ssusans alen < obj->size) {
30276029a2d8Ssusans
30286029a2d8Ssusans ddi_dma_free_handle(&obj->dma_handle);
30296029a2d8Ssusans
30306029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "Failed : ddi_dma_mem_alloc"));
30316029a2d8Ssusans
30326029a2d8Ssusans return (-1);
30336029a2d8Ssusans }
30346029a2d8Ssusans
30356029a2d8Ssusans if (ddi_dma_addr_bind_handle(obj->dma_handle, NULL, obj->buffer,
30366029a2d8Ssusans obj->size, DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
30376029a2d8Ssusans NULL, &obj->dma_cookie[0], &cookie_cnt) != DDI_SUCCESS) {
30386029a2d8Ssusans
30396029a2d8Ssusans ddi_dma_mem_free(&obj->acc_handle);
30406029a2d8Ssusans ddi_dma_free_handle(&obj->dma_handle);
30416029a2d8Ssusans
30426029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "Failed : ddi_dma_addr_bind_handle"));
30436029a2d8Ssusans
30446029a2d8Ssusans return (-1);
30456029a2d8Ssusans }
30466029a2d8Ssusans
30472fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(obj->dma_handle) != DDI_SUCCESS) {
30482fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
30492fa451d9SYu Wu - Sun Microsystems - Beijing China return (-1);
30502fa451d9SYu Wu - Sun Microsystems - Beijing China }
30512fa451d9SYu Wu - Sun Microsystems - Beijing China
30522fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(obj->acc_handle) != DDI_SUCCESS) {
30532fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
30542fa451d9SYu Wu - Sun Microsystems - Beijing China return (-1);
30552fa451d9SYu Wu - Sun Microsystems - Beijing China }
30562fa451d9SYu Wu - Sun Microsystems - Beijing China
30576029a2d8Ssusans return (cookie_cnt);
30586029a2d8Ssusans }
30596029a2d8Ssusans
30606029a2d8Ssusans /*
30612fa451d9SYu Wu - Sun Microsystems - Beijing China * mega_free_dma_obj(struct megasas_instance *, dma_obj_t)
30626029a2d8Ssusans *
30636029a2d8Ssusans * De-allocate the memory and other resources for an dma object, which must
30646029a2d8Ssusans * have been alloated by a previous call to mega_alloc_dma_obj()
30656029a2d8Ssusans */
30662fa451d9SYu Wu - Sun Microsystems - Beijing China static int
mega_free_dma_obj(struct megasas_instance * instance,dma_obj_t obj)30672fa451d9SYu Wu - Sun Microsystems - Beijing China mega_free_dma_obj(struct megasas_instance *instance, dma_obj_t obj)
30686029a2d8Ssusans {
30692fa451d9SYu Wu - Sun Microsystems - Beijing China
30702fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(obj.dma_handle) != DDI_SUCCESS) {
30712fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
30722fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_FAILURE);
30732fa451d9SYu Wu - Sun Microsystems - Beijing China }
30742fa451d9SYu Wu - Sun Microsystems - Beijing China
30752fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(obj.acc_handle) != DDI_SUCCESS) {
30762fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
30772fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_FAILURE);
30782fa451d9SYu Wu - Sun Microsystems - Beijing China }
30792fa451d9SYu Wu - Sun Microsystems - Beijing China
30806029a2d8Ssusans (void) ddi_dma_unbind_handle(obj.dma_handle);
30816029a2d8Ssusans ddi_dma_mem_free(&obj.acc_handle);
30826029a2d8Ssusans ddi_dma_free_handle(&obj.dma_handle);
30832fa451d9SYu Wu - Sun Microsystems - Beijing China
30842fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_SUCCESS);
30856029a2d8Ssusans }
30866029a2d8Ssusans
30876029a2d8Ssusans /*
30886029a2d8Ssusans * megasas_dma_alloc(instance_t *, struct scsi_pkt *, struct buf *,
30896029a2d8Ssusans * int, int (*)())
30906029a2d8Ssusans *
30916029a2d8Ssusans * Allocate dma resources for a new scsi command
30926029a2d8Ssusans */
30936029a2d8Ssusans static int
megasas_dma_alloc(struct megasas_instance * instance,struct scsi_pkt * pkt,struct buf * bp,int flags,int (* callback)())30946029a2d8Ssusans megasas_dma_alloc(struct megasas_instance *instance, struct scsi_pkt *pkt,
30956029a2d8Ssusans struct buf *bp, int flags, int (*callback)())
30966029a2d8Ssusans {
30976029a2d8Ssusans int dma_flags;
30986029a2d8Ssusans int (*cb)(caddr_t);
30996029a2d8Ssusans int i;
31006029a2d8Ssusans
31016029a2d8Ssusans ddi_dma_attr_t tmp_dma_attr = megasas_generic_dma_attr;
31026029a2d8Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
31036029a2d8Ssusans
31046029a2d8Ssusans acmd->cmd_buf = bp;
31056029a2d8Ssusans
31066029a2d8Ssusans if (bp->b_flags & B_READ) {
31076029a2d8Ssusans acmd->cmd_flags &= ~CFLAG_DMASEND;
31086029a2d8Ssusans dma_flags = DDI_DMA_READ;
31096029a2d8Ssusans } else {
31106029a2d8Ssusans acmd->cmd_flags |= CFLAG_DMASEND;
31116029a2d8Ssusans dma_flags = DDI_DMA_WRITE;
31126029a2d8Ssusans }
31136029a2d8Ssusans
31146029a2d8Ssusans if (flags & PKT_CONSISTENT) {
31156029a2d8Ssusans acmd->cmd_flags |= CFLAG_CONSISTENT;
31166029a2d8Ssusans dma_flags |= DDI_DMA_CONSISTENT;
31176029a2d8Ssusans }
31186029a2d8Ssusans
31196029a2d8Ssusans if (flags & PKT_DMA_PARTIAL) {
31206029a2d8Ssusans dma_flags |= DDI_DMA_PARTIAL;
31216029a2d8Ssusans }
31226029a2d8Ssusans
31236029a2d8Ssusans dma_flags |= DDI_DMA_REDZONE;
31246029a2d8Ssusans
31256029a2d8Ssusans cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
31266029a2d8Ssusans
31276029a2d8Ssusans tmp_dma_attr.dma_attr_sgllen = instance->max_num_sge;
312803b14217SYu Wu - Sun Microsystems - Beijing China tmp_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
31296029a2d8Ssusans
31306029a2d8Ssusans if ((i = ddi_dma_alloc_handle(instance->dip, &tmp_dma_attr,
31316029a2d8Ssusans cb, 0, &acmd->cmd_dmahandle)) != DDI_SUCCESS) {
31326029a2d8Ssusans switch (i) {
31336029a2d8Ssusans case DDI_DMA_BADATTR:
31346029a2d8Ssusans bioerror(bp, EFAULT);
31356029a2d8Ssusans return (-1);
31366029a2d8Ssusans
31376029a2d8Ssusans case DDI_DMA_NORESOURCES:
31386029a2d8Ssusans bioerror(bp, 0);
31396029a2d8Ssusans return (-1);
31406029a2d8Ssusans
31416029a2d8Ssusans default:
31426029a2d8Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_alloc_handle: "
31436029a2d8Ssusans "0x%x impossible\n", i));
31447ddfa2acSSusan Scheufele bioerror(bp, EFAULT);
31457ddfa2acSSusan Scheufele return (-1);
31466029a2d8Ssusans }
31476029a2d8Ssusans }
31486029a2d8Ssusans
31496029a2d8Ssusans i = ddi_dma_buf_bind_handle(acmd->cmd_dmahandle, bp, dma_flags,
31506029a2d8Ssusans cb, 0, &acmd->cmd_dmacookies[0], &acmd->cmd_ncookies);
31516029a2d8Ssusans
31526029a2d8Ssusans switch (i) {
31536029a2d8Ssusans case DDI_DMA_PARTIAL_MAP:
31546029a2d8Ssusans if ((dma_flags & DDI_DMA_PARTIAL) == 0) {
31556029a2d8Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_buf_bind_handle: "
31566029a2d8Ssusans "DDI_DMA_PARTIAL_MAP impossible\n"));
31577ddfa2acSSusan Scheufele goto no_dma_cookies;
31586029a2d8Ssusans }
31596029a2d8Ssusans
31606029a2d8Ssusans if (ddi_dma_numwin(acmd->cmd_dmahandle, &acmd->cmd_nwin) ==
31616029a2d8Ssusans DDI_FAILURE) {
31626029a2d8Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_numwin failed\n"));
31637ddfa2acSSusan Scheufele goto no_dma_cookies;
31646029a2d8Ssusans }
31656029a2d8Ssusans
31666029a2d8Ssusans if (ddi_dma_getwin(acmd->cmd_dmahandle, acmd->cmd_curwin,
31676029a2d8Ssusans &acmd->cmd_dma_offset, &acmd->cmd_dma_len,
31686029a2d8Ssusans &acmd->cmd_dmacookies[0], &acmd->cmd_ncookies) ==
31696029a2d8Ssusans DDI_FAILURE) {
31706029a2d8Ssusans
31716029a2d8Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_getwin failed\n"));
31727ddfa2acSSusan Scheufele goto no_dma_cookies;
31736029a2d8Ssusans }
31746029a2d8Ssusans
31756029a2d8Ssusans goto get_dma_cookies;
31766029a2d8Ssusans case DDI_DMA_MAPPED:
31776029a2d8Ssusans acmd->cmd_nwin = 1;
31786029a2d8Ssusans acmd->cmd_dma_len = 0;
31796029a2d8Ssusans acmd->cmd_dma_offset = 0;
31806029a2d8Ssusans
31816029a2d8Ssusans get_dma_cookies:
31826029a2d8Ssusans i = 0;
31836029a2d8Ssusans acmd->cmd_dmacount = 0;
31846029a2d8Ssusans for (;;) {
31856029a2d8Ssusans acmd->cmd_dmacount +=
31866029a2d8Ssusans acmd->cmd_dmacookies[i++].dmac_size;
31876029a2d8Ssusans
31886029a2d8Ssusans if (i == instance->max_num_sge ||
31896029a2d8Ssusans i == acmd->cmd_ncookies)
31906029a2d8Ssusans break;
31916029a2d8Ssusans
31926029a2d8Ssusans ddi_dma_nextcookie(acmd->cmd_dmahandle,
31936029a2d8Ssusans &acmd->cmd_dmacookies[i]);
31946029a2d8Ssusans }
31956029a2d8Ssusans
31966029a2d8Ssusans acmd->cmd_cookie = i;
31976029a2d8Ssusans acmd->cmd_cookiecnt = i;
31986029a2d8Ssusans
31996029a2d8Ssusans acmd->cmd_flags |= CFLAG_DMAVALID;
32006029a2d8Ssusans
32016029a2d8Ssusans if (bp->b_bcount >= acmd->cmd_dmacount) {
32026029a2d8Ssusans pkt->pkt_resid = bp->b_bcount - acmd->cmd_dmacount;
32036029a2d8Ssusans } else {
32046029a2d8Ssusans pkt->pkt_resid = 0;
32056029a2d8Ssusans }
32066029a2d8Ssusans
32076029a2d8Ssusans return (0);
32086029a2d8Ssusans case DDI_DMA_NORESOURCES:
32096029a2d8Ssusans bioerror(bp, 0);
32106029a2d8Ssusans break;
32116029a2d8Ssusans case DDI_DMA_NOMAPPING:
32126029a2d8Ssusans bioerror(bp, EFAULT);
32136029a2d8Ssusans break;
32146029a2d8Ssusans case DDI_DMA_TOOBIG:
32156029a2d8Ssusans bioerror(bp, EINVAL);
32166029a2d8Ssusans break;
32176029a2d8Ssusans case DDI_DMA_INUSE:
32186029a2d8Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_buf_bind_handle:"
32196029a2d8Ssusans " DDI_DMA_INUSE impossible\n"));
32206029a2d8Ssusans break;
32216029a2d8Ssusans default:
32226029a2d8Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_buf_bind_handle: "
32236029a2d8Ssusans "0x%x impossible\n", i));
32246029a2d8Ssusans break;
32256029a2d8Ssusans }
32266029a2d8Ssusans
32277ddfa2acSSusan Scheufele no_dma_cookies:
32286029a2d8Ssusans ddi_dma_free_handle(&acmd->cmd_dmahandle);
32296029a2d8Ssusans acmd->cmd_dmahandle = NULL;
32306029a2d8Ssusans acmd->cmd_flags &= ~CFLAG_DMAVALID;
32316029a2d8Ssusans return (-1);
32326029a2d8Ssusans }
32336029a2d8Ssusans
32346029a2d8Ssusans /*
32356029a2d8Ssusans * megasas_dma_move(struct megasas_instance *, struct scsi_pkt *, struct buf *)
32366029a2d8Ssusans *
32376029a2d8Ssusans * move dma resources to next dma window
32386029a2d8Ssusans *
32396029a2d8Ssusans */
32406029a2d8Ssusans static int
megasas_dma_move(struct megasas_instance * instance,struct scsi_pkt * pkt,struct buf * bp)32416029a2d8Ssusans megasas_dma_move(struct megasas_instance *instance, struct scsi_pkt *pkt,
32426029a2d8Ssusans struct buf *bp)
32436029a2d8Ssusans {
32446029a2d8Ssusans int i = 0;
32456029a2d8Ssusans
32466029a2d8Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
32476029a2d8Ssusans
32486029a2d8Ssusans /*
32496029a2d8Ssusans * If there are no more cookies remaining in this window,
32506029a2d8Ssusans * must move to the next window first.
32516029a2d8Ssusans */
32526029a2d8Ssusans if (acmd->cmd_cookie == acmd->cmd_ncookies) {
32536029a2d8Ssusans if (acmd->cmd_curwin == acmd->cmd_nwin && acmd->cmd_nwin == 1) {
32546029a2d8Ssusans return (0);
32556029a2d8Ssusans }
32566029a2d8Ssusans
32576029a2d8Ssusans /* at last window, cannot move */
32586029a2d8Ssusans if (++acmd->cmd_curwin >= acmd->cmd_nwin) {
32596029a2d8Ssusans return (-1);
32606029a2d8Ssusans }
32616029a2d8Ssusans
32626029a2d8Ssusans if (ddi_dma_getwin(acmd->cmd_dmahandle, acmd->cmd_curwin,
32636029a2d8Ssusans &acmd->cmd_dma_offset, &acmd->cmd_dma_len,
32646029a2d8Ssusans &acmd->cmd_dmacookies[0], &acmd->cmd_ncookies) ==
32656029a2d8Ssusans DDI_FAILURE) {
32666029a2d8Ssusans return (-1);
32676029a2d8Ssusans }
32686029a2d8Ssusans
32696029a2d8Ssusans acmd->cmd_cookie = 0;
32706029a2d8Ssusans } else {
32716029a2d8Ssusans /* still more cookies in this window - get the next one */
32726029a2d8Ssusans ddi_dma_nextcookie(acmd->cmd_dmahandle,
32736029a2d8Ssusans &acmd->cmd_dmacookies[0]);
32746029a2d8Ssusans }
32756029a2d8Ssusans
32766029a2d8Ssusans /* get remaining cookies in this window, up to our maximum */
32776029a2d8Ssusans for (;;) {
32786029a2d8Ssusans acmd->cmd_dmacount += acmd->cmd_dmacookies[i++].dmac_size;
32796029a2d8Ssusans acmd->cmd_cookie++;
32806029a2d8Ssusans
32816029a2d8Ssusans if (i == instance->max_num_sge ||
32826029a2d8Ssusans acmd->cmd_cookie == acmd->cmd_ncookies) {
32836029a2d8Ssusans break;
32846029a2d8Ssusans }
32856029a2d8Ssusans
32866029a2d8Ssusans ddi_dma_nextcookie(acmd->cmd_dmahandle,
32876029a2d8Ssusans &acmd->cmd_dmacookies[i]);
32886029a2d8Ssusans }
32896029a2d8Ssusans
32906029a2d8Ssusans acmd->cmd_cookiecnt = i;
32916029a2d8Ssusans
32926029a2d8Ssusans if (bp->b_bcount >= acmd->cmd_dmacount) {
32936029a2d8Ssusans pkt->pkt_resid = bp->b_bcount - acmd->cmd_dmacount;
32946029a2d8Ssusans } else {
32956029a2d8Ssusans pkt->pkt_resid = 0;
32966029a2d8Ssusans }
32976029a2d8Ssusans
32986029a2d8Ssusans return (0);
32996029a2d8Ssusans }
33006029a2d8Ssusans
33016029a2d8Ssusans /*
33026029a2d8Ssusans * build_cmd
33036029a2d8Ssusans */
33046029a2d8Ssusans static struct megasas_cmd *
build_cmd(struct megasas_instance * instance,struct scsi_address * ap,struct scsi_pkt * pkt,uchar_t * cmd_done)33056029a2d8Ssusans build_cmd(struct megasas_instance *instance, struct scsi_address *ap,
33066029a2d8Ssusans struct scsi_pkt *pkt, uchar_t *cmd_done)
33076029a2d8Ssusans {
33086029a2d8Ssusans uint16_t flags = 0;
33096029a2d8Ssusans uint32_t i;
33106029a2d8Ssusans uint32_t sge_bytes;
33116029a2d8Ssusans
33126029a2d8Ssusans struct megasas_cmd *cmd;
331303b14217SYu Wu - Sun Microsystems - Beijing China struct megasas_sge64 *mfi_sgl;
33146029a2d8Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
33156029a2d8Ssusans struct megasas_pthru_frame *pthru;
33166029a2d8Ssusans struct megasas_io_frame *ldio;
33176029a2d8Ssusans
33186029a2d8Ssusans /* find out if this is logical or physical drive command. */
33196029a2d8Ssusans acmd->islogical = MEGADRV_IS_LOGICAL(ap);
33206029a2d8Ssusans acmd->device_id = MAP_DEVICE_ID(instance, ap);
33213ddf1763Syw *cmd_done = 0;
33226029a2d8Ssusans
33236029a2d8Ssusans /* get the command packet */
33246029a2d8Ssusans if (!(cmd = get_mfi_pkt(instance))) {
33256029a2d8Ssusans return (NULL);
33266029a2d8Ssusans }
33276029a2d8Ssusans
33286029a2d8Ssusans cmd->pkt = pkt;
33296029a2d8Ssusans cmd->cmd = acmd;
33306029a2d8Ssusans
33316029a2d8Ssusans /* lets get the command directions */
33326029a2d8Ssusans if (acmd->cmd_flags & CFLAG_DMASEND) {
33336029a2d8Ssusans flags = MFI_FRAME_DIR_WRITE;
33346029a2d8Ssusans
33356029a2d8Ssusans if (acmd->cmd_flags & CFLAG_CONSISTENT) {
33366029a2d8Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle,
33376029a2d8Ssusans acmd->cmd_dma_offset, acmd->cmd_dma_len,
33386029a2d8Ssusans DDI_DMA_SYNC_FORDEV);
33396029a2d8Ssusans }
33406029a2d8Ssusans } else if (acmd->cmd_flags & ~CFLAG_DMASEND) {
33416029a2d8Ssusans flags = MFI_FRAME_DIR_READ;
33426029a2d8Ssusans
33436029a2d8Ssusans if (acmd->cmd_flags & CFLAG_CONSISTENT) {
33446029a2d8Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle,
33456029a2d8Ssusans acmd->cmd_dma_offset, acmd->cmd_dma_len,
33466029a2d8Ssusans DDI_DMA_SYNC_FORCPU);
33476029a2d8Ssusans }
33486029a2d8Ssusans } else {
33496029a2d8Ssusans flags = MFI_FRAME_DIR_NONE;
33506029a2d8Ssusans }
33516029a2d8Ssusans
335203b14217SYu Wu - Sun Microsystems - Beijing China flags |= MFI_FRAME_SGL64;
33536029a2d8Ssusans
33546029a2d8Ssusans switch (pkt->pkt_cdbp[0]) {
33556029a2d8Ssusans
33563ddf1763Syw /*
33573ddf1763Syw * case SCMD_SYNCHRONIZE_CACHE:
33583ddf1763Syw * flush_cache(instance);
33593ddf1763Syw * return_mfi_pkt(instance, cmd);
33603ddf1763Syw * *cmd_done = 1;
33613ddf1763Syw *
33623ddf1763Syw * return (NULL);
33633ddf1763Syw */
33643ddf1763Syw
33656029a2d8Ssusans case SCMD_READ:
33666029a2d8Ssusans case SCMD_WRITE:
33676029a2d8Ssusans case SCMD_READ_G1:
33686029a2d8Ssusans case SCMD_WRITE_G1:
33696029a2d8Ssusans if (acmd->islogical) {
33706029a2d8Ssusans ldio = (struct megasas_io_frame *)cmd->frame;
33716029a2d8Ssusans
33726029a2d8Ssusans /*
33736029a2d8Ssusans * preare the Logical IO frame:
33746029a2d8Ssusans * 2nd bit is zero for all read cmds
33756029a2d8Ssusans */
33766029a2d8Ssusans ldio->cmd = (pkt->pkt_cdbp[0] & 0x02) ?
33776029a2d8Ssusans MFI_CMD_OP_LD_WRITE : MFI_CMD_OP_LD_READ;
33786029a2d8Ssusans ldio->cmd_status = 0x0;
33796029a2d8Ssusans ldio->scsi_status = 0x0;
33806029a2d8Ssusans ldio->target_id = acmd->device_id;
33816029a2d8Ssusans ldio->timeout = 0;
33826029a2d8Ssusans ldio->reserved_0 = 0;
33836029a2d8Ssusans ldio->pad_0 = 0;
33846029a2d8Ssusans ldio->flags = flags;
33853ddf1763Syw
33863ddf1763Syw /* Initialize sense Information */
33873ddf1763Syw bzero(cmd->sense, SENSE_LENGTH);
33883ddf1763Syw ldio->sense_len = SENSE_LENGTH;
33893ddf1763Syw ldio->sense_buf_phys_addr_hi = 0;
33903ddf1763Syw ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
33913ddf1763Syw
33926029a2d8Ssusans ldio->start_lba_hi = 0;
33936029a2d8Ssusans ldio->access_byte = (acmd->cmd_cdblen != 6) ?
33946029a2d8Ssusans pkt->pkt_cdbp[1] : 0;
33956029a2d8Ssusans ldio->sge_count = acmd->cmd_cookiecnt;
339603b14217SYu Wu - Sun Microsystems - Beijing China mfi_sgl = (struct megasas_sge64 *)&ldio->sgl;
33976029a2d8Ssusans
33986029a2d8Ssusans if (acmd->cmd_cdblen == CDB_GROUP0) {
33996029a2d8Ssusans ldio->lba_count = host_to_le16(
34006029a2d8Ssusans (uint16_t)(pkt->pkt_cdbp[4]));
34016029a2d8Ssusans
34026029a2d8Ssusans ldio->start_lba_lo = host_to_le32(
34036029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[3])) |
34046029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 8) |
34056029a2d8Ssusans ((uint32_t)((pkt->pkt_cdbp[1]) & 0x1F)
34066029a2d8Ssusans << 16));
34076029a2d8Ssusans } else if (acmd->cmd_cdblen == CDB_GROUP1) {
34086029a2d8Ssusans ldio->lba_count = host_to_le16(
34096029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[8])) |
34106029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[7]) << 8));
34116029a2d8Ssusans
34126029a2d8Ssusans ldio->start_lba_lo = host_to_le32(
34136029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[5])) |
34146029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[4]) << 8) |
34156029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[3]) << 16) |
34166029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 24));
34176029a2d8Ssusans } else if (acmd->cmd_cdblen == CDB_GROUP2) {
34186029a2d8Ssusans ldio->lba_count = host_to_le16(
34196029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[9])) |
34206029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[8]) << 8) |
34216029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[7]) << 16) |
34226029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[6]) << 24));
34236029a2d8Ssusans
34246029a2d8Ssusans ldio->start_lba_lo = host_to_le32(
34256029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[5])) |
34266029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[4]) << 8) |
34276029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[3]) << 16) |
34286029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 24));
34296029a2d8Ssusans } else if (acmd->cmd_cdblen == CDB_GROUP3) {
34306029a2d8Ssusans ldio->lba_count = host_to_le16(
34316029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[13])) |
34326029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[12]) << 8) |
34336029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[11]) << 16) |
34346029a2d8Ssusans ((uint16_t)(pkt->pkt_cdbp[10]) << 24));
34356029a2d8Ssusans
34366029a2d8Ssusans ldio->start_lba_lo = host_to_le32(
34376029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[9])) |
34386029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[8]) << 8) |
34396029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[7]) << 16) |
34406029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[6]) << 24));
34416029a2d8Ssusans
34426029a2d8Ssusans ldio->start_lba_lo = host_to_le32(
34436029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[5])) |
34446029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[4]) << 8) |
34456029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[3]) << 16) |
34466029a2d8Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 24));
34476029a2d8Ssusans }
34486029a2d8Ssusans
34496029a2d8Ssusans break;
34506029a2d8Ssusans }
3451*2811ec43SToomas Soome /* For all non-rd/wr cmds */
3452*2811ec43SToomas Soome /* FALLTHROUGH */
34536029a2d8Ssusans default:
34546029a2d8Ssusans pthru = (struct megasas_pthru_frame *)cmd->frame;
34556029a2d8Ssusans
34566029a2d8Ssusans /* prepare the DCDB frame */
34576029a2d8Ssusans pthru->cmd = (acmd->islogical) ?
34586029a2d8Ssusans MFI_CMD_OP_LD_SCSI : MFI_CMD_OP_PD_SCSI;
34596029a2d8Ssusans pthru->cmd_status = 0x0;
34606029a2d8Ssusans pthru->scsi_status = 0x0;
34616029a2d8Ssusans pthru->target_id = acmd->device_id;
34626029a2d8Ssusans pthru->lun = 0;
34636029a2d8Ssusans pthru->cdb_len = acmd->cmd_cdblen;
34646029a2d8Ssusans pthru->timeout = 0;
34656029a2d8Ssusans pthru->flags = flags;
34666029a2d8Ssusans pthru->data_xfer_len = acmd->cmd_dmacount;
34676029a2d8Ssusans pthru->sge_count = acmd->cmd_cookiecnt;
346803b14217SYu Wu - Sun Microsystems - Beijing China mfi_sgl = (struct megasas_sge64 *)&pthru->sgl;
34693ddf1763Syw
34703ddf1763Syw bzero(cmd->sense, SENSE_LENGTH);
34713ddf1763Syw pthru->sense_len = SENSE_LENGTH;
34726029a2d8Ssusans pthru->sense_buf_phys_addr_hi = 0;
34733ddf1763Syw pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
34746029a2d8Ssusans
34756029a2d8Ssusans bcopy(pkt->pkt_cdbp, pthru->cdb, acmd->cmd_cdblen);
34766029a2d8Ssusans
34776029a2d8Ssusans break;
34786029a2d8Ssusans }
34796029a2d8Ssusans /* bzero(mfi_sgl, sizeof (struct megasas_sge64) * MAX_SGL); */
34806029a2d8Ssusans
34816029a2d8Ssusans /* prepare the scatter-gather list for the firmware */
34826029a2d8Ssusans for (i = 0; i < acmd->cmd_cookiecnt; i++, mfi_sgl++) {
34836029a2d8Ssusans mfi_sgl->phys_addr = acmd->cmd_dmacookies[i].dmac_laddress;
34846029a2d8Ssusans mfi_sgl->length = acmd->cmd_dmacookies[i].dmac_size;
34856029a2d8Ssusans }
34866029a2d8Ssusans
348703b14217SYu Wu - Sun Microsystems - Beijing China sge_bytes = sizeof (struct megasas_sge64)*acmd->cmd_cookiecnt;
34886029a2d8Ssusans
34896029a2d8Ssusans cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
34906029a2d8Ssusans ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
34916029a2d8Ssusans
34926029a2d8Ssusans if (cmd->frame_count >= 8) {
34936029a2d8Ssusans cmd->frame_count = 8;
34946029a2d8Ssusans }
34956029a2d8Ssusans
34966029a2d8Ssusans return (cmd);
34976029a2d8Ssusans }
34986029a2d8Ssusans
34996029a2d8Ssusans /*
35006029a2d8Ssusans * wait_for_outstanding - Wait for all outstanding cmds
35016029a2d8Ssusans * @instance: Adapter soft state
35026029a2d8Ssusans *
35036029a2d8Ssusans * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to
35046029a2d8Ssusans * complete all its outstanding commands. Returns error if one or more IOs
35056029a2d8Ssusans * are pending after this time period.
35066029a2d8Ssusans */
35076029a2d8Ssusans static int
wait_for_outstanding(struct megasas_instance * instance)35086029a2d8Ssusans wait_for_outstanding(struct megasas_instance *instance)
35096029a2d8Ssusans {
35106029a2d8Ssusans int i;
35116029a2d8Ssusans uint32_t wait_time = 90;
35126029a2d8Ssusans
35136029a2d8Ssusans for (i = 0; i < wait_time; i++) {
35146029a2d8Ssusans if (!instance->fw_outstanding) {
35156029a2d8Ssusans break;
35166029a2d8Ssusans }
35176029a2d8Ssusans
35187ddfa2acSSusan Scheufele drv_usecwait(MILLISEC); /* wait for 1000 usecs */;
35196029a2d8Ssusans }
35206029a2d8Ssusans
35216029a2d8Ssusans if (instance->fw_outstanding) {
35226029a2d8Ssusans return (1);
35236029a2d8Ssusans }
35246029a2d8Ssusans
35252fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_acc_err_clear(instance->regmap_handle, DDI_FME_VERSION);
35262fa451d9SYu Wu - Sun Microsystems - Beijing China
35276029a2d8Ssusans return (0);
35286029a2d8Ssusans }
35296029a2d8Ssusans
35306029a2d8Ssusans /*
35316029a2d8Ssusans * issue_mfi_pthru
35326029a2d8Ssusans */
35336029a2d8Ssusans static int
issue_mfi_pthru(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)35346029a2d8Ssusans issue_mfi_pthru(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
35356029a2d8Ssusans struct megasas_cmd *cmd, int mode)
35366029a2d8Ssusans {
35376029a2d8Ssusans void *ubuf;
35386029a2d8Ssusans uint32_t kphys_addr = 0;
35396029a2d8Ssusans uint32_t xferlen = 0;
35406029a2d8Ssusans uint_t model;
35416029a2d8Ssusans
35426029a2d8Ssusans dma_obj_t pthru_dma_obj;
35436029a2d8Ssusans struct megasas_pthru_frame *kpthru;
35446029a2d8Ssusans struct megasas_pthru_frame *pthru;
35456029a2d8Ssusans
35466029a2d8Ssusans pthru = &cmd->frame->pthru;
35476029a2d8Ssusans kpthru = (struct megasas_pthru_frame *)&ioctl->frame[0];
35486029a2d8Ssusans
35496029a2d8Ssusans model = ddi_model_convert_from(mode & FMODELS);
35506029a2d8Ssusans if (model == DDI_MODEL_ILP32) {
35516029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_pthru: DDI_MODEL_LP32"));
35526029a2d8Ssusans
35536029a2d8Ssusans xferlen = kpthru->sgl.sge32[0].length;
35546029a2d8Ssusans
35556029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
35566029a2d8Ssusans ubuf = (void *)(ulong_t)kpthru->sgl.sge32[0].phys_addr;
35576029a2d8Ssusans } else {
35586029a2d8Ssusans #ifdef _ILP32
35596029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_pthru: DDI_MODEL_LP32"));
35606029a2d8Ssusans xferlen = kpthru->sgl.sge32[0].length;
35616029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
35626029a2d8Ssusans ubuf = (void *)(ulong_t)kpthru->sgl.sge32[0].phys_addr;
35636029a2d8Ssusans #else
35646029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_pthru: DDI_MODEL_LP64"));
35656029a2d8Ssusans xferlen = kpthru->sgl.sge64[0].length;
35666029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
35676029a2d8Ssusans ubuf = (void *)(ulong_t)kpthru->sgl.sge64[0].phys_addr;
35686029a2d8Ssusans #endif
35696029a2d8Ssusans }
35706029a2d8Ssusans
35716029a2d8Ssusans if (xferlen) {
35726029a2d8Ssusans /* means IOCTL requires DMA */
35736029a2d8Ssusans /* allocate the data transfer buffer */
35746029a2d8Ssusans pthru_dma_obj.size = xferlen;
35756029a2d8Ssusans pthru_dma_obj.dma_attr = megasas_generic_dma_attr;
35767ddfa2acSSusan Scheufele pthru_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
35777ddfa2acSSusan Scheufele pthru_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
35786029a2d8Ssusans pthru_dma_obj.dma_attr.dma_attr_sgllen = 1;
35796029a2d8Ssusans pthru_dma_obj.dma_attr.dma_attr_align = 1;
35806029a2d8Ssusans
35816029a2d8Ssusans /* allocate kernel buffer for DMA */
35826029a2d8Ssusans if (mega_alloc_dma_obj(instance, &pthru_dma_obj) != 1) {
35836029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_pthru: "
35846029a2d8Ssusans "could not data transfer buffer alloc."));
35856029a2d8Ssusans return (DDI_FAILURE);
35866029a2d8Ssusans }
35876029a2d8Ssusans
35886029a2d8Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
35896029a2d8Ssusans if (kpthru->flags & MFI_FRAME_DIR_WRITE) {
35906029a2d8Ssusans if (ddi_copyin(ubuf, (void *)pthru_dma_obj.buffer,
35916029a2d8Ssusans xferlen, mode)) {
35926029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_pthru: "
35936029a2d8Ssusans "copy from user space failed\n"));
35946029a2d8Ssusans return (1);
35956029a2d8Ssusans }
35966029a2d8Ssusans }
35976029a2d8Ssusans
35986029a2d8Ssusans kphys_addr = pthru_dma_obj.dma_cookie[0].dmac_address;
35996029a2d8Ssusans }
36006029a2d8Ssusans
36016029a2d8Ssusans pthru->cmd = kpthru->cmd;
36026029a2d8Ssusans pthru->sense_len = kpthru->sense_len;
36036029a2d8Ssusans pthru->cmd_status = kpthru->cmd_status;
36046029a2d8Ssusans pthru->scsi_status = kpthru->scsi_status;
36056029a2d8Ssusans pthru->target_id = kpthru->target_id;
36066029a2d8Ssusans pthru->lun = kpthru->lun;
36076029a2d8Ssusans pthru->cdb_len = kpthru->cdb_len;
36086029a2d8Ssusans pthru->sge_count = kpthru->sge_count;
36096029a2d8Ssusans pthru->timeout = kpthru->timeout;
36106029a2d8Ssusans pthru->data_xfer_len = kpthru->data_xfer_len;
36116029a2d8Ssusans
36126029a2d8Ssusans pthru->sense_buf_phys_addr_hi = 0;
36136029a2d8Ssusans /* pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr; */
36146029a2d8Ssusans pthru->sense_buf_phys_addr_lo = 0;
36156029a2d8Ssusans
36166029a2d8Ssusans bcopy((void *)kpthru->cdb, (void *)pthru->cdb, pthru->cdb_len);
36176029a2d8Ssusans
36186029a2d8Ssusans pthru->flags = kpthru->flags & ~MFI_FRAME_SGL64;
36196029a2d8Ssusans pthru->sgl.sge32[0].length = xferlen;
36206029a2d8Ssusans pthru->sgl.sge32[0].phys_addr = kphys_addr;
36216029a2d8Ssusans
36226029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
36236029a2d8Ssusans cmd->frame_count = 1;
36246029a2d8Ssusans
36256029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
36266029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
36276029a2d8Ssusans "issue_mfi_pthru: fw_ioctl failed\n"));
36286029a2d8Ssusans } else {
36296029a2d8Ssusans if (xferlen && (kpthru->flags & MFI_FRAME_DIR_READ)) {
36306029a2d8Ssusans
36316029a2d8Ssusans if (ddi_copyout(pthru_dma_obj.buffer, ubuf,
36326029a2d8Ssusans xferlen, mode)) {
36336029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_pthru: "
36346029a2d8Ssusans "copy to user space failed\n"));
36356029a2d8Ssusans return (1);
36366029a2d8Ssusans }
36376029a2d8Ssusans }
36386029a2d8Ssusans }
36396029a2d8Ssusans
36406029a2d8Ssusans kpthru->cmd_status = pthru->cmd_status;
36416029a2d8Ssusans kpthru->scsi_status = pthru->scsi_status;
36426029a2d8Ssusans
36436029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_pthru: cmd_status %x, "
36446029a2d8Ssusans "scsi_status %x\n", pthru->cmd_status, pthru->scsi_status));
36456029a2d8Ssusans
36466029a2d8Ssusans if (xferlen) {
36476029a2d8Ssusans /* free kernel buffer */
36482fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, pthru_dma_obj) != DDI_SUCCESS)
36492fa451d9SYu Wu - Sun Microsystems - Beijing China return (1);
36506029a2d8Ssusans }
36516029a2d8Ssusans
36526029a2d8Ssusans return (0);
36536029a2d8Ssusans }
36546029a2d8Ssusans
36556029a2d8Ssusans /*
36566029a2d8Ssusans * issue_mfi_dcmd
36576029a2d8Ssusans */
36586029a2d8Ssusans static int
issue_mfi_dcmd(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)36596029a2d8Ssusans issue_mfi_dcmd(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
36606029a2d8Ssusans struct megasas_cmd *cmd, int mode)
36616029a2d8Ssusans {
36626029a2d8Ssusans void *ubuf;
36636029a2d8Ssusans uint32_t kphys_addr = 0;
36646029a2d8Ssusans uint32_t xferlen = 0;
36656029a2d8Ssusans uint32_t model;
36666029a2d8Ssusans dma_obj_t dcmd_dma_obj;
36676029a2d8Ssusans struct megasas_dcmd_frame *kdcmd;
36686029a2d8Ssusans struct megasas_dcmd_frame *dcmd;
36696029a2d8Ssusans
36706029a2d8Ssusans dcmd = &cmd->frame->dcmd;
36716029a2d8Ssusans kdcmd = (struct megasas_dcmd_frame *)&ioctl->frame[0];
36726029a2d8Ssusans
36736029a2d8Ssusans model = ddi_model_convert_from(mode & FMODELS);
36746029a2d8Ssusans if (model == DDI_MODEL_ILP32) {
36756029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_dcmd: DDI_MODEL_ILP32"));
36766029a2d8Ssusans
36776029a2d8Ssusans xferlen = kdcmd->sgl.sge32[0].length;
36786029a2d8Ssusans
36796029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
36806029a2d8Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
36816029a2d8Ssusans }
36826029a2d8Ssusans else
36836029a2d8Ssusans {
36846029a2d8Ssusans #ifdef _ILP32
36856029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_dcmd: DDI_MODEL_ILP32"));
36866029a2d8Ssusans xferlen = kdcmd->sgl.sge32[0].length;
36876029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
36886029a2d8Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
36896029a2d8Ssusans #else
36906029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_dcmd: DDI_MODEL_LP64"));
36916029a2d8Ssusans xferlen = kdcmd->sgl.sge64[0].length;
36926029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
36936029a2d8Ssusans ubuf = (void *)(ulong_t)dcmd->sgl.sge64[0].phys_addr;
36946029a2d8Ssusans #endif
36956029a2d8Ssusans }
36966029a2d8Ssusans if (xferlen) {
36976029a2d8Ssusans /* means IOCTL requires DMA */
36986029a2d8Ssusans /* allocate the data transfer buffer */
36996029a2d8Ssusans dcmd_dma_obj.size = xferlen;
37006029a2d8Ssusans dcmd_dma_obj.dma_attr = megasas_generic_dma_attr;
37017ddfa2acSSusan Scheufele dcmd_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
37027ddfa2acSSusan Scheufele dcmd_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
37036029a2d8Ssusans dcmd_dma_obj.dma_attr.dma_attr_sgllen = 1;
37046029a2d8Ssusans dcmd_dma_obj.dma_attr.dma_attr_align = 1;
37056029a2d8Ssusans
37066029a2d8Ssusans /* allocate kernel buffer for DMA */
37076029a2d8Ssusans if (mega_alloc_dma_obj(instance, &dcmd_dma_obj) != 1) {
37086029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: "
37096029a2d8Ssusans "could not data transfer buffer alloc."));
37106029a2d8Ssusans return (DDI_FAILURE);
37116029a2d8Ssusans }
37126029a2d8Ssusans
37136029a2d8Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
37146029a2d8Ssusans if (kdcmd->flags & MFI_FRAME_DIR_WRITE) {
37156029a2d8Ssusans if (ddi_copyin(ubuf, (void *)dcmd_dma_obj.buffer,
37166029a2d8Ssusans xferlen, mode)) {
37176029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: "
37186029a2d8Ssusans "copy from user space failed\n"));
37196029a2d8Ssusans return (1);
37206029a2d8Ssusans }
37216029a2d8Ssusans }
37226029a2d8Ssusans
37236029a2d8Ssusans kphys_addr = dcmd_dma_obj.dma_cookie[0].dmac_address;
37246029a2d8Ssusans }
37256029a2d8Ssusans
37266029a2d8Ssusans dcmd->cmd = kdcmd->cmd;
37276029a2d8Ssusans dcmd->cmd_status = kdcmd->cmd_status;
37286029a2d8Ssusans dcmd->sge_count = kdcmd->sge_count;
37296029a2d8Ssusans dcmd->timeout = kdcmd->timeout;
37306029a2d8Ssusans dcmd->data_xfer_len = kdcmd->data_xfer_len;
37316029a2d8Ssusans dcmd->opcode = kdcmd->opcode;
37326029a2d8Ssusans
37337ddfa2acSSusan Scheufele bcopy((void *)kdcmd->mbox.b, (void *)dcmd->mbox.b, DCMD_MBOX_SZ);
37346029a2d8Ssusans
37356029a2d8Ssusans dcmd->flags = kdcmd->flags & ~MFI_FRAME_SGL64;
37366029a2d8Ssusans dcmd->sgl.sge32[0].length = xferlen;
37376029a2d8Ssusans dcmd->sgl.sge32[0].phys_addr = kphys_addr;
37386029a2d8Ssusans
37396029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
37406029a2d8Ssusans cmd->frame_count = 1;
37416029a2d8Ssusans
37426029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
37436029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: fw_ioctl failed\n"));
37446029a2d8Ssusans } else {
37456029a2d8Ssusans if (xferlen && (kdcmd->flags & MFI_FRAME_DIR_READ)) {
37466029a2d8Ssusans
37476029a2d8Ssusans if (ddi_copyout(dcmd_dma_obj.buffer, ubuf,
37486029a2d8Ssusans xferlen, mode)) {
37496029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: "
37506029a2d8Ssusans "copy to user space failed\n"));
37516029a2d8Ssusans return (1);
37526029a2d8Ssusans }
37536029a2d8Ssusans }
37546029a2d8Ssusans }
37556029a2d8Ssusans
37566029a2d8Ssusans kdcmd->cmd_status = dcmd->cmd_status;
37576029a2d8Ssusans
37586029a2d8Ssusans if (xferlen) {
37596029a2d8Ssusans /* free kernel buffer */
37602fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, dcmd_dma_obj) != DDI_SUCCESS)
37612fa451d9SYu Wu - Sun Microsystems - Beijing China return (1);
37626029a2d8Ssusans }
37636029a2d8Ssusans
37646029a2d8Ssusans return (0);
37656029a2d8Ssusans }
37666029a2d8Ssusans
37676029a2d8Ssusans /*
37686029a2d8Ssusans * issue_mfi_smp
37696029a2d8Ssusans */
37706029a2d8Ssusans static int
issue_mfi_smp(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)37716029a2d8Ssusans issue_mfi_smp(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
37726029a2d8Ssusans struct megasas_cmd *cmd, int mode)
37736029a2d8Ssusans {
37746029a2d8Ssusans void *request_ubuf;
37756029a2d8Ssusans void *response_ubuf;
37766029a2d8Ssusans uint32_t request_xferlen = 0;
37776029a2d8Ssusans uint32_t response_xferlen = 0;
37786029a2d8Ssusans uint_t model;
37796029a2d8Ssusans dma_obj_t request_dma_obj;
37806029a2d8Ssusans dma_obj_t response_dma_obj;
37816029a2d8Ssusans struct megasas_smp_frame *ksmp;
37826029a2d8Ssusans struct megasas_smp_frame *smp;
37836029a2d8Ssusans struct megasas_sge32 *sge32;
37846029a2d8Ssusans #ifndef _ILP32
37856029a2d8Ssusans struct megasas_sge64 *sge64;
37866029a2d8Ssusans #endif
37876029a2d8Ssusans
37886029a2d8Ssusans smp = &cmd->frame->smp;
37896029a2d8Ssusans ksmp = (struct megasas_smp_frame *)&ioctl->frame[0];
37906029a2d8Ssusans
37916029a2d8Ssusans model = ddi_model_convert_from(mode & FMODELS);
37926029a2d8Ssusans if (model == DDI_MODEL_ILP32) {
37936029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: DDI_MODEL_ILP32"));
37946029a2d8Ssusans
37956029a2d8Ssusans sge32 = &ksmp->sgl[0].sge32[0];
37966029a2d8Ssusans response_xferlen = sge32[0].length;
37976029a2d8Ssusans request_xferlen = sge32[1].length;
37986029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_smp: "
37996029a2d8Ssusans "response_xferlen = %x, request_xferlen = %x",
38006029a2d8Ssusans response_xferlen, request_xferlen));
38016029a2d8Ssusans
38026029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
38036029a2d8Ssusans
38046029a2d8Ssusans response_ubuf = (void *)(ulong_t)sge32[0].phys_addr;
38056029a2d8Ssusans request_ubuf = (void *)(ulong_t)sge32[1].phys_addr;
38066029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: "
38076029a2d8Ssusans "response_ubuf = %p, request_ubuf = %p",
38086029a2d8Ssusans response_ubuf, request_ubuf));
38096029a2d8Ssusans } else {
38106029a2d8Ssusans #ifdef _ILP32
38116029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: DDI_MODEL_ILP32"));
38126029a2d8Ssusans
38136029a2d8Ssusans sge32 = &ksmp->sgl[0].sge32[0];
38146029a2d8Ssusans response_xferlen = sge32[0].length;
38156029a2d8Ssusans request_xferlen = sge32[1].length;
38166029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_smp: "
38176029a2d8Ssusans "response_xferlen = %x, request_xferlen = %x",
38186029a2d8Ssusans response_xferlen, request_xferlen));
38196029a2d8Ssusans
38206029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
38216029a2d8Ssusans
38226029a2d8Ssusans response_ubuf = (void *)(ulong_t)sge32[0].phys_addr;
38236029a2d8Ssusans request_ubuf = (void *)(ulong_t)sge32[1].phys_addr;
38246029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: "
38256029a2d8Ssusans "response_ubuf = %p, request_ubuf = %p",
38266029a2d8Ssusans response_ubuf, request_ubuf));
38276029a2d8Ssusans #else
38286029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: DDI_MODEL_LP64"));
38296029a2d8Ssusans
38306029a2d8Ssusans sge64 = &ksmp->sgl[0].sge64[0];
38316029a2d8Ssusans response_xferlen = sge64[0].length;
38326029a2d8Ssusans request_xferlen = sge64[1].length;
38336029a2d8Ssusans
38346029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
38356029a2d8Ssusans response_ubuf = (void *)(ulong_t)sge64[0].phys_addr;
38366029a2d8Ssusans request_ubuf = (void *)(ulong_t)sge64[1].phys_addr;
38376029a2d8Ssusans #endif
38386029a2d8Ssusans }
38396029a2d8Ssusans if (request_xferlen) {
38406029a2d8Ssusans /* means IOCTL requires DMA */
38416029a2d8Ssusans /* allocate the data transfer buffer */
38426029a2d8Ssusans request_dma_obj.size = request_xferlen;
38436029a2d8Ssusans request_dma_obj.dma_attr = megasas_generic_dma_attr;
38447ddfa2acSSusan Scheufele request_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
38457ddfa2acSSusan Scheufele request_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
38466029a2d8Ssusans request_dma_obj.dma_attr.dma_attr_sgllen = 1;
38476029a2d8Ssusans request_dma_obj.dma_attr.dma_attr_align = 1;
38486029a2d8Ssusans
38496029a2d8Ssusans /* allocate kernel buffer for DMA */
38506029a2d8Ssusans if (mega_alloc_dma_obj(instance, &request_dma_obj) != 1) {
38516029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38526029a2d8Ssusans "could not data transfer buffer alloc."));
38536029a2d8Ssusans return (DDI_FAILURE);
38546029a2d8Ssusans }
38556029a2d8Ssusans
38566029a2d8Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
38576029a2d8Ssusans if (ddi_copyin(request_ubuf, (void *) request_dma_obj.buffer,
38586029a2d8Ssusans request_xferlen, mode)) {
38596029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38606029a2d8Ssusans "copy from user space failed\n"));
38616029a2d8Ssusans return (1);
38626029a2d8Ssusans }
38636029a2d8Ssusans }
38646029a2d8Ssusans
38656029a2d8Ssusans if (response_xferlen) {
38666029a2d8Ssusans /* means IOCTL requires DMA */
38676029a2d8Ssusans /* allocate the data transfer buffer */
38686029a2d8Ssusans response_dma_obj.size = response_xferlen;
38696029a2d8Ssusans response_dma_obj.dma_attr = megasas_generic_dma_attr;
38707ddfa2acSSusan Scheufele response_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
38717ddfa2acSSusan Scheufele response_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
38726029a2d8Ssusans response_dma_obj.dma_attr.dma_attr_sgllen = 1;
38736029a2d8Ssusans response_dma_obj.dma_attr.dma_attr_align = 1;
38746029a2d8Ssusans
38756029a2d8Ssusans /* allocate kernel buffer for DMA */
38766029a2d8Ssusans if (mega_alloc_dma_obj(instance, &response_dma_obj) != 1) {
38776029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38786029a2d8Ssusans "could not data transfer buffer alloc."));
38796029a2d8Ssusans return (DDI_FAILURE);
38806029a2d8Ssusans }
38816029a2d8Ssusans
38826029a2d8Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
38836029a2d8Ssusans if (ddi_copyin(response_ubuf, (void *) response_dma_obj.buffer,
38846029a2d8Ssusans response_xferlen, mode)) {
38856029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38866029a2d8Ssusans "copy from user space failed\n"));
38876029a2d8Ssusans return (1);
38886029a2d8Ssusans }
38896029a2d8Ssusans }
38906029a2d8Ssusans
38916029a2d8Ssusans smp->cmd = ksmp->cmd;
38926029a2d8Ssusans smp->cmd_status = ksmp->cmd_status;
38936029a2d8Ssusans smp->connection_status = ksmp->connection_status;
38946029a2d8Ssusans smp->sge_count = ksmp->sge_count;
38956029a2d8Ssusans /* smp->context = ksmp->context; */
38966029a2d8Ssusans smp->timeout = ksmp->timeout;
38976029a2d8Ssusans smp->data_xfer_len = ksmp->data_xfer_len;
38986029a2d8Ssusans
38996029a2d8Ssusans bcopy((void *)&ksmp->sas_addr, (void *)&smp->sas_addr,
39006029a2d8Ssusans sizeof (uint64_t));
39016029a2d8Ssusans
39026029a2d8Ssusans smp->flags = ksmp->flags & ~MFI_FRAME_SGL64;
39036029a2d8Ssusans
39046029a2d8Ssusans model = ddi_model_convert_from(mode & FMODELS);
39056029a2d8Ssusans if (model == DDI_MODEL_ILP32) {
39066029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
39076029a2d8Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
39086029a2d8Ssusans
39096029a2d8Ssusans sge32 = &smp->sgl[0].sge32[0];
39106029a2d8Ssusans sge32[0].length = response_xferlen;
39116029a2d8Ssusans sge32[0].phys_addr =
39126029a2d8Ssusans response_dma_obj.dma_cookie[0].dmac_address;
39136029a2d8Ssusans sge32[1].length = request_xferlen;
39146029a2d8Ssusans sge32[1].phys_addr =
39156029a2d8Ssusans request_dma_obj.dma_cookie[0].dmac_address;
39166029a2d8Ssusans } else {
39176029a2d8Ssusans #ifdef _ILP32
39186029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
39196029a2d8Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
39206029a2d8Ssusans sge32 = &smp->sgl[0].sge32[0];
39216029a2d8Ssusans sge32[0].length = response_xferlen;
39226029a2d8Ssusans sge32[0].phys_addr =
39236029a2d8Ssusans response_dma_obj.dma_cookie[0].dmac_address;
39246029a2d8Ssusans sge32[1].length = request_xferlen;
39256029a2d8Ssusans sge32[1].phys_addr =
39266029a2d8Ssusans request_dma_obj.dma_cookie[0].dmac_address;
39276029a2d8Ssusans #else
39286029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
39296029a2d8Ssusans "issue_mfi_smp: DDI_MODEL_LP64"));
39306029a2d8Ssusans sge64 = &smp->sgl[0].sge64[0];
39316029a2d8Ssusans sge64[0].length = response_xferlen;
39326029a2d8Ssusans sge64[0].phys_addr =
39336029a2d8Ssusans response_dma_obj.dma_cookie[0].dmac_address;
39346029a2d8Ssusans sge64[1].length = request_xferlen;
39356029a2d8Ssusans sge64[1].phys_addr =
39366029a2d8Ssusans request_dma_obj.dma_cookie[0].dmac_address;
39376029a2d8Ssusans #endif
39386029a2d8Ssusans }
39396029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: "
39406029a2d8Ssusans "smp->response_xferlen = %d, smp->request_xferlen = %d "
39416029a2d8Ssusans "smp->data_xfer_len = %d", sge32[0].length, sge32[1].length,
39426029a2d8Ssusans smp->data_xfer_len));
39436029a2d8Ssusans
39446029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
39456029a2d8Ssusans cmd->frame_count = 1;
39466029a2d8Ssusans
39476029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
39486029a2d8Ssusans con_log(CL_ANN, (CE_WARN,
39496029a2d8Ssusans "issue_mfi_smp: fw_ioctl failed\n"));
39506029a2d8Ssusans } else {
39516029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
39526029a2d8Ssusans "issue_mfi_smp: copy to user space\n"));
39536029a2d8Ssusans
39546029a2d8Ssusans if (request_xferlen) {
39556029a2d8Ssusans if (ddi_copyout(request_dma_obj.buffer, request_ubuf,
39566029a2d8Ssusans request_xferlen, mode)) {
39576029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
39586029a2d8Ssusans "copy to user space failed\n"));
39596029a2d8Ssusans return (1);
39606029a2d8Ssusans }
39616029a2d8Ssusans }
39626029a2d8Ssusans
39636029a2d8Ssusans if (response_xferlen) {
39646029a2d8Ssusans if (ddi_copyout(response_dma_obj.buffer, response_ubuf,
39656029a2d8Ssusans response_xferlen, mode)) {
39666029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
39676029a2d8Ssusans "copy to user space failed\n"));
39686029a2d8Ssusans return (1);
39696029a2d8Ssusans }
39706029a2d8Ssusans }
39716029a2d8Ssusans }
39726029a2d8Ssusans
39736029a2d8Ssusans ksmp->cmd_status = smp->cmd_status;
39746029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: smp->cmd_status = %d",
39756029a2d8Ssusans smp->cmd_status));
39766029a2d8Ssusans
39776029a2d8Ssusans
39786029a2d8Ssusans if (request_xferlen) {
39796029a2d8Ssusans /* free kernel buffer */
39802fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, request_dma_obj) != DDI_SUCCESS)
39812fa451d9SYu Wu - Sun Microsystems - Beijing China return (1);
39826029a2d8Ssusans }
39836029a2d8Ssusans
39846029a2d8Ssusans if (response_xferlen) {
39856029a2d8Ssusans /* free kernel buffer */
39862fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, response_dma_obj) !=
39872fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SUCCESS)
39882fa451d9SYu Wu - Sun Microsystems - Beijing China return (1);
39896029a2d8Ssusans }
39906029a2d8Ssusans
39916029a2d8Ssusans return (0);
39926029a2d8Ssusans }
39936029a2d8Ssusans
39946029a2d8Ssusans /*
39956029a2d8Ssusans * issue_mfi_stp
39966029a2d8Ssusans */
39976029a2d8Ssusans static int
issue_mfi_stp(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)39986029a2d8Ssusans issue_mfi_stp(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
39996029a2d8Ssusans struct megasas_cmd *cmd, int mode)
40006029a2d8Ssusans {
40016029a2d8Ssusans void *fis_ubuf;
40026029a2d8Ssusans void *data_ubuf;
40036029a2d8Ssusans uint32_t fis_xferlen = 0;
40046029a2d8Ssusans uint32_t data_xferlen = 0;
40056029a2d8Ssusans uint_t model;
40066029a2d8Ssusans dma_obj_t fis_dma_obj;
40076029a2d8Ssusans dma_obj_t data_dma_obj;
40086029a2d8Ssusans struct megasas_stp_frame *kstp;
40096029a2d8Ssusans struct megasas_stp_frame *stp;
40106029a2d8Ssusans
40116029a2d8Ssusans stp = &cmd->frame->stp;
40126029a2d8Ssusans kstp = (struct megasas_stp_frame *)&ioctl->frame[0];
40136029a2d8Ssusans
40146029a2d8Ssusans model = ddi_model_convert_from(mode & FMODELS);
40156029a2d8Ssusans if (model == DDI_MODEL_ILP32) {
40166029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_stp: DDI_MODEL_ILP32"));
40176029a2d8Ssusans
40186029a2d8Ssusans fis_xferlen = kstp->sgl.sge32[0].length;
40196029a2d8Ssusans data_xferlen = kstp->sgl.sge32[1].length;
40206029a2d8Ssusans
40216029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
40226029a2d8Ssusans fis_ubuf = (void *)(ulong_t)kstp->sgl.sge32[0].phys_addr;
40236029a2d8Ssusans data_ubuf = (void *)(ulong_t)kstp->sgl.sge32[1].phys_addr;
40246029a2d8Ssusans }
40256029a2d8Ssusans else
40266029a2d8Ssusans {
40276029a2d8Ssusans #ifdef _ILP32
40286029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_stp: DDI_MODEL_ILP32"));
40296029a2d8Ssusans
40306029a2d8Ssusans fis_xferlen = kstp->sgl.sge32[0].length;
40316029a2d8Ssusans data_xferlen = kstp->sgl.sge32[1].length;
40326029a2d8Ssusans
40336029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
40346029a2d8Ssusans fis_ubuf = (void *)(ulong_t)kstp->sgl.sge32[0].phys_addr;
40356029a2d8Ssusans data_ubuf = (void *)(ulong_t)kstp->sgl.sge32[1].phys_addr;
40366029a2d8Ssusans #else
40376029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_stp: DDI_MODEL_LP64"));
40386029a2d8Ssusans
40396029a2d8Ssusans fis_xferlen = kstp->sgl.sge64[0].length;
40406029a2d8Ssusans data_xferlen = kstp->sgl.sge64[1].length;
40416029a2d8Ssusans
40426029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
40436029a2d8Ssusans fis_ubuf = (void *)(ulong_t)kstp->sgl.sge64[0].phys_addr;
40446029a2d8Ssusans data_ubuf = (void *)(ulong_t)kstp->sgl.sge64[1].phys_addr;
40456029a2d8Ssusans #endif
40466029a2d8Ssusans }
40476029a2d8Ssusans
40486029a2d8Ssusans
40496029a2d8Ssusans if (fis_xferlen) {
40506029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_stp: "
40516029a2d8Ssusans "fis_ubuf = %p fis_xferlen = %x", fis_ubuf, fis_xferlen));
40527ddfa2acSSusan Scheufele
40536029a2d8Ssusans /* means IOCTL requires DMA */
40546029a2d8Ssusans /* allocate the data transfer buffer */
40556029a2d8Ssusans fis_dma_obj.size = fis_xferlen;
40566029a2d8Ssusans fis_dma_obj.dma_attr = megasas_generic_dma_attr;
40577ddfa2acSSusan Scheufele fis_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
40587ddfa2acSSusan Scheufele fis_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
40596029a2d8Ssusans fis_dma_obj.dma_attr.dma_attr_sgllen = 1;
40606029a2d8Ssusans fis_dma_obj.dma_attr.dma_attr_align = 1;
40616029a2d8Ssusans
40626029a2d8Ssusans /* allocate kernel buffer for DMA */
40636029a2d8Ssusans if (mega_alloc_dma_obj(instance, &fis_dma_obj) != 1) {
40646029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
40656029a2d8Ssusans "could not data transfer buffer alloc."));
40666029a2d8Ssusans return (DDI_FAILURE);
40676029a2d8Ssusans }
40686029a2d8Ssusans
40696029a2d8Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
40706029a2d8Ssusans if (ddi_copyin(fis_ubuf, (void *)fis_dma_obj.buffer,
40716029a2d8Ssusans fis_xferlen, mode)) {
40726029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
40736029a2d8Ssusans "copy from user space failed\n"));
40746029a2d8Ssusans return (1);
40756029a2d8Ssusans }
40766029a2d8Ssusans }
40776029a2d8Ssusans
40786029a2d8Ssusans if (data_xferlen) {
40796029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_stp: data_ubuf = %p "
40806029a2d8Ssusans "data_xferlen = %x", data_ubuf, data_xferlen));
40816029a2d8Ssusans
40826029a2d8Ssusans /* means IOCTL requires DMA */
40836029a2d8Ssusans /* allocate the data transfer buffer */
40846029a2d8Ssusans data_dma_obj.size = data_xferlen;
40856029a2d8Ssusans data_dma_obj.dma_attr = megasas_generic_dma_attr;
40867ddfa2acSSusan Scheufele data_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
40877ddfa2acSSusan Scheufele data_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
40886029a2d8Ssusans data_dma_obj.dma_attr.dma_attr_sgllen = 1;
40896029a2d8Ssusans data_dma_obj.dma_attr.dma_attr_align = 1;
40906029a2d8Ssusans
40916029a2d8Ssusans /* allocate kernel buffer for DMA */
40926029a2d8Ssusans if (mega_alloc_dma_obj(instance, &data_dma_obj) != 1) {
40936029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
40946029a2d8Ssusans "could not data transfer buffer alloc."));
40956029a2d8Ssusans return (DDI_FAILURE);
40966029a2d8Ssusans }
40976029a2d8Ssusans
40986029a2d8Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
40996029a2d8Ssusans if (ddi_copyin(data_ubuf, (void *) data_dma_obj.buffer,
41006029a2d8Ssusans data_xferlen, mode)) {
41016029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41026029a2d8Ssusans "copy from user space failed\n"));
41036029a2d8Ssusans return (1);
41046029a2d8Ssusans }
41056029a2d8Ssusans }
41066029a2d8Ssusans
41076029a2d8Ssusans stp->cmd = kstp->cmd;
41086029a2d8Ssusans stp->cmd_status = kstp->cmd_status;
41096029a2d8Ssusans stp->connection_status = kstp->connection_status;
41106029a2d8Ssusans stp->target_id = kstp->target_id;
41116029a2d8Ssusans stp->sge_count = kstp->sge_count;
41126029a2d8Ssusans /* stp->context = kstp->context; */
41136029a2d8Ssusans stp->timeout = kstp->timeout;
41146029a2d8Ssusans stp->data_xfer_len = kstp->data_xfer_len;
41156029a2d8Ssusans
41166029a2d8Ssusans bcopy((void *)kstp->fis, (void *)stp->fis, 10);
41176029a2d8Ssusans
41186029a2d8Ssusans stp->flags = kstp->flags & ~MFI_FRAME_SGL64;
41196029a2d8Ssusans stp->stp_flags = kstp->stp_flags;
41206029a2d8Ssusans stp->sgl.sge32[0].length = fis_xferlen;
41216029a2d8Ssusans stp->sgl.sge32[0].phys_addr = fis_dma_obj.dma_cookie[0].dmac_address;
41226029a2d8Ssusans stp->sgl.sge32[1].length = data_xferlen;
41236029a2d8Ssusans stp->sgl.sge32[1].phys_addr = data_dma_obj.dma_cookie[0].dmac_address;
41246029a2d8Ssusans
41256029a2d8Ssusans cmd->sync_cmd = MEGASAS_TRUE;
41266029a2d8Ssusans cmd->frame_count = 1;
41276029a2d8Ssusans
41286029a2d8Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
41296029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: fw_ioctl failed\n"));
41306029a2d8Ssusans } else {
41316029a2d8Ssusans
41326029a2d8Ssusans if (fis_xferlen) {
41336029a2d8Ssusans if (ddi_copyout(fis_dma_obj.buffer, fis_ubuf,
41346029a2d8Ssusans fis_xferlen, mode)) {
41356029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41366029a2d8Ssusans "copy to user space failed\n"));
41376029a2d8Ssusans return (1);
41386029a2d8Ssusans }
41396029a2d8Ssusans }
41406029a2d8Ssusans
41416029a2d8Ssusans if (data_xferlen) {
41426029a2d8Ssusans if (ddi_copyout(data_dma_obj.buffer, data_ubuf,
41436029a2d8Ssusans data_xferlen, mode)) {
41446029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41456029a2d8Ssusans "copy to user space failed\n"));
41466029a2d8Ssusans return (1);
41476029a2d8Ssusans }
41486029a2d8Ssusans }
41496029a2d8Ssusans }
41506029a2d8Ssusans
41516029a2d8Ssusans kstp->cmd_status = stp->cmd_status;
41526029a2d8Ssusans
41536029a2d8Ssusans if (fis_xferlen) {
41546029a2d8Ssusans /* free kernel buffer */
41552fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, fis_dma_obj) != DDI_SUCCESS)
41562fa451d9SYu Wu - Sun Microsystems - Beijing China return (1);
41576029a2d8Ssusans }
41586029a2d8Ssusans
41596029a2d8Ssusans if (data_xferlen) {
41606029a2d8Ssusans /* free kernel buffer */
41612fa451d9SYu Wu - Sun Microsystems - Beijing China if (mega_free_dma_obj(instance, data_dma_obj) != DDI_SUCCESS)
41622fa451d9SYu Wu - Sun Microsystems - Beijing China return (1);
41636029a2d8Ssusans }
41646029a2d8Ssusans
41656029a2d8Ssusans return (0);
41666029a2d8Ssusans }
41676029a2d8Ssusans
41686029a2d8Ssusans /*
41696029a2d8Ssusans * fill_up_drv_ver
41706029a2d8Ssusans */
41716029a2d8Ssusans static void
fill_up_drv_ver(struct megasas_drv_ver * dv)41726029a2d8Ssusans fill_up_drv_ver(struct megasas_drv_ver *dv)
41736029a2d8Ssusans {
41746029a2d8Ssusans (void) memset(dv, 0, sizeof (struct megasas_drv_ver));
41756029a2d8Ssusans
41766029a2d8Ssusans (void) memcpy(dv->signature, "$LSI LOGIC$", strlen("$LSI LOGIC$"));
41776029a2d8Ssusans (void) memcpy(dv->os_name, "Solaris", strlen("Solaris"));
41786029a2d8Ssusans (void) memcpy(dv->drv_name, "megaraid_sas", strlen("megaraid_sas"));
41796029a2d8Ssusans (void) memcpy(dv->drv_ver, MEGASAS_VERSION, strlen(MEGASAS_VERSION));
41806029a2d8Ssusans (void) memcpy(dv->drv_rel_date, MEGASAS_RELDATE,
41816029a2d8Ssusans strlen(MEGASAS_RELDATE));
41826029a2d8Ssusans }
41836029a2d8Ssusans
41846029a2d8Ssusans /*
41856029a2d8Ssusans * handle_drv_ioctl
41866029a2d8Ssusans */
41876029a2d8Ssusans static int
handle_drv_ioctl(struct megasas_instance * instance,struct megasas_ioctl * ioctl,int mode)41886029a2d8Ssusans handle_drv_ioctl(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
41896029a2d8Ssusans int mode)
41906029a2d8Ssusans {
41916029a2d8Ssusans int i;
41926029a2d8Ssusans int rval = 0;
41936029a2d8Ssusans int *props = NULL;
41946029a2d8Ssusans void *ubuf;
41956029a2d8Ssusans
41966029a2d8Ssusans uint8_t *pci_conf_buf;
41976029a2d8Ssusans uint32_t xferlen;
41986029a2d8Ssusans uint32_t num_props;
41996029a2d8Ssusans uint_t model;
42006029a2d8Ssusans struct megasas_dcmd_frame *kdcmd;
42016029a2d8Ssusans struct megasas_drv_ver dv;
42026029a2d8Ssusans struct megasas_pci_information pi;
42036029a2d8Ssusans
42046029a2d8Ssusans kdcmd = (struct megasas_dcmd_frame *)&ioctl->frame[0];
42056029a2d8Ssusans
42066029a2d8Ssusans model = ddi_model_convert_from(mode & FMODELS);
42076029a2d8Ssusans if (model == DDI_MODEL_ILP32) {
42086029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
42096029a2d8Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
42106029a2d8Ssusans
42116029a2d8Ssusans xferlen = kdcmd->sgl.sge32[0].length;
42126029a2d8Ssusans
42136029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
42146029a2d8Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
42156029a2d8Ssusans } else {
42166029a2d8Ssusans #ifdef _ILP32
42176029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
42186029a2d8Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
42196029a2d8Ssusans xferlen = kdcmd->sgl.sge32[0].length;
42206029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
42216029a2d8Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
42226029a2d8Ssusans #else
42236029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE,
42246029a2d8Ssusans "handle_drv_ioctl: DDI_MODEL_LP64"));
42256029a2d8Ssusans xferlen = kdcmd->sgl.sge64[0].length;
42266029a2d8Ssusans /* SJ! - ubuf needs to be virtual address. */
42276029a2d8Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge64[0].phys_addr;
42286029a2d8Ssusans #endif
42296029a2d8Ssusans }
42306029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "handle_drv_ioctl: "
42316029a2d8Ssusans "dataBuf=%p size=%d bytes", ubuf, xferlen));
42326029a2d8Ssusans
42336029a2d8Ssusans switch (kdcmd->opcode) {
42346029a2d8Ssusans case MR_DRIVER_IOCTL_DRIVER_VERSION:
42356029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "handle_drv_ioctl: "
42366029a2d8Ssusans "MR_DRIVER_IOCTL_DRIVER_VERSION"));
42376029a2d8Ssusans
42386029a2d8Ssusans fill_up_drv_ver(&dv);
42396029a2d8Ssusans
42406029a2d8Ssusans if (ddi_copyout(&dv, ubuf, xferlen, mode)) {
42416029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42426029a2d8Ssusans "MR_DRIVER_IOCTL_DRIVER_VERSION : "
42436029a2d8Ssusans "copy to user space failed\n"));
42446029a2d8Ssusans kdcmd->cmd_status = 1;
42456029a2d8Ssusans rval = 1;
42466029a2d8Ssusans } else {
42476029a2d8Ssusans kdcmd->cmd_status = 0;
42486029a2d8Ssusans }
42496029a2d8Ssusans break;
42506029a2d8Ssusans case MR_DRIVER_IOCTL_PCI_INFORMATION:
42516029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "handle_drv_ioctl: "
42526029a2d8Ssusans "MR_DRIVER_IOCTL_PCI_INFORMAITON"));
42536029a2d8Ssusans
42546029a2d8Ssusans if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, instance->dip,
42556029a2d8Ssusans 0, "reg", &props, &num_props)) {
42566029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42576029a2d8Ssusans "MR_DRIVER_IOCTL_PCI_INFORMATION : "
42586029a2d8Ssusans "ddi_prop_look_int_array failed\n"));
42596029a2d8Ssusans rval = 1;
42606029a2d8Ssusans } else {
42616029a2d8Ssusans
42626029a2d8Ssusans pi.busNumber = (props[0] >> 16) & 0xFF;
42636029a2d8Ssusans pi.deviceNumber = (props[0] >> 11) & 0x1f;
42646029a2d8Ssusans pi.functionNumber = (props[0] >> 8) & 0x7;
42656029a2d8Ssusans ddi_prop_free((void *)props);
42666029a2d8Ssusans }
42676029a2d8Ssusans
42686029a2d8Ssusans pci_conf_buf = (uint8_t *)&pi.pciHeaderInfo;
42696029a2d8Ssusans
42702fbba054Syd for (i = 0; i < (sizeof (struct megasas_pci_information) -
42712fbba054Syd offsetof(struct megasas_pci_information, pciHeaderInfo));
42722fbba054Syd i++) {
42736029a2d8Ssusans pci_conf_buf[i] =
42746029a2d8Ssusans pci_config_get8(instance->pci_handle, i);
42756029a2d8Ssusans }
42766029a2d8Ssusans
42776029a2d8Ssusans if (ddi_copyout(&pi, ubuf, xferlen, mode)) {
42786029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42796029a2d8Ssusans "MR_DRIVER_IOCTL_PCI_INFORMATION : "
42806029a2d8Ssusans "copy to user space failed\n"));
42816029a2d8Ssusans kdcmd->cmd_status = 1;
42826029a2d8Ssusans rval = 1;
42836029a2d8Ssusans } else {
42846029a2d8Ssusans kdcmd->cmd_status = 0;
42856029a2d8Ssusans }
42866029a2d8Ssusans break;
42876029a2d8Ssusans default:
42886029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42896029a2d8Ssusans "invalid driver specific IOCTL opcode = 0x%x",
42906029a2d8Ssusans kdcmd->opcode));
42916029a2d8Ssusans kdcmd->cmd_status = 1;
42926029a2d8Ssusans rval = 1;
42936029a2d8Ssusans break;
42946029a2d8Ssusans }
42956029a2d8Ssusans
42966029a2d8Ssusans return (rval);
42976029a2d8Ssusans }
42986029a2d8Ssusans
42996029a2d8Ssusans /*
43006029a2d8Ssusans * handle_mfi_ioctl
43016029a2d8Ssusans */
43026029a2d8Ssusans static int
handle_mfi_ioctl(struct megasas_instance * instance,struct megasas_ioctl * ioctl,int mode)43036029a2d8Ssusans handle_mfi_ioctl(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
43046029a2d8Ssusans int mode)
43056029a2d8Ssusans {
43066029a2d8Ssusans int rval = 0;
43076029a2d8Ssusans
43086029a2d8Ssusans struct megasas_header *hdr;
43096029a2d8Ssusans struct megasas_cmd *cmd;
43106029a2d8Ssusans
43116029a2d8Ssusans cmd = get_mfi_pkt(instance);
43126029a2d8Ssusans
43136029a2d8Ssusans if (!cmd) {
43146029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "megasas: "
43156029a2d8Ssusans "failed to get a cmd packet\n"));
43166029a2d8Ssusans return (1);
43176029a2d8Ssusans }
43186029a2d8Ssusans
43196029a2d8Ssusans hdr = (struct megasas_header *)&ioctl->frame[0];
43206029a2d8Ssusans
43216029a2d8Ssusans switch (hdr->cmd) {
43226029a2d8Ssusans case MFI_CMD_OP_DCMD:
43236029a2d8Ssusans rval = issue_mfi_dcmd(instance, ioctl, cmd, mode);
43246029a2d8Ssusans break;
43256029a2d8Ssusans case MFI_CMD_OP_SMP:
43266029a2d8Ssusans rval = issue_mfi_smp(instance, ioctl, cmd, mode);
43276029a2d8Ssusans break;
43286029a2d8Ssusans case MFI_CMD_OP_STP:
43296029a2d8Ssusans rval = issue_mfi_stp(instance, ioctl, cmd, mode);
43306029a2d8Ssusans break;
43316029a2d8Ssusans case MFI_CMD_OP_LD_SCSI:
43326029a2d8Ssusans case MFI_CMD_OP_PD_SCSI:
43336029a2d8Ssusans rval = issue_mfi_pthru(instance, ioctl, cmd, mode);
43346029a2d8Ssusans break;
43356029a2d8Ssusans default:
43366029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "handle_mfi_ioctl: "
43376029a2d8Ssusans "invalid mfi ioctl hdr->cmd = %d\n", hdr->cmd));
43386029a2d8Ssusans rval = 1;
43396029a2d8Ssusans break;
43406029a2d8Ssusans }
43416029a2d8Ssusans
43426029a2d8Ssusans
43436029a2d8Ssusans return_mfi_pkt(instance, cmd);
43442fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_common_check(instance, cmd) != DDI_SUCCESS)
43452fa451d9SYu Wu - Sun Microsystems - Beijing China rval = 1;
43466029a2d8Ssusans return (rval);
43476029a2d8Ssusans }
43486029a2d8Ssusans
43496029a2d8Ssusans /*
43506029a2d8Ssusans * AEN
43516029a2d8Ssusans */
43526029a2d8Ssusans static int
handle_mfi_aen(struct megasas_instance * instance,struct megasas_aen * aen)43536029a2d8Ssusans handle_mfi_aen(struct megasas_instance *instance, struct megasas_aen *aen)
43546029a2d8Ssusans {
43556029a2d8Ssusans int rval = 0;
43566029a2d8Ssusans
43576029a2d8Ssusans rval = register_mfi_aen(instance, instance->aen_seq_num,
43586029a2d8Ssusans aen->class_locale_word);
43596029a2d8Ssusans
43606029a2d8Ssusans aen->cmd_status = (uint8_t)rval;
43616029a2d8Ssusans
43626029a2d8Ssusans return (rval);
43636029a2d8Ssusans }
43646029a2d8Ssusans
43656029a2d8Ssusans static int
register_mfi_aen(struct megasas_instance * instance,uint32_t seq_num,uint32_t class_locale_word)43666029a2d8Ssusans register_mfi_aen(struct megasas_instance *instance, uint32_t seq_num,
43676029a2d8Ssusans uint32_t class_locale_word)
43686029a2d8Ssusans {
43696029a2d8Ssusans int ret_val;
43706029a2d8Ssusans
43716029a2d8Ssusans struct megasas_cmd *cmd;
43726029a2d8Ssusans struct megasas_dcmd_frame *dcmd;
43736029a2d8Ssusans union megasas_evt_class_locale curr_aen;
43746029a2d8Ssusans union megasas_evt_class_locale prev_aen;
43756029a2d8Ssusans
43766029a2d8Ssusans /*
43776029a2d8Ssusans * If there an AEN pending already (aen_cmd), check if the
43786029a2d8Ssusans * class_locale of that pending AEN is inclusive of the new
43796029a2d8Ssusans * AEN request we currently have. If it is, then we don't have
43806029a2d8Ssusans * to do anything. In other words, whichever events the current
43816029a2d8Ssusans * AEN request is subscribing to, have already been subscribed
43826029a2d8Ssusans * to.
43836029a2d8Ssusans *
43846029a2d8Ssusans * If the old_cmd is _not_ inclusive, then we have to abort
43856029a2d8Ssusans * that command, form a class_locale that is superset of both
43866029a2d8Ssusans * old and current and re-issue to the FW
43876029a2d8Ssusans */
43886029a2d8Ssusans
43896029a2d8Ssusans curr_aen.word = class_locale_word;
43906029a2d8Ssusans
43916029a2d8Ssusans if (instance->aen_cmd) {
43926029a2d8Ssusans prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];
43936029a2d8Ssusans
43946029a2d8Ssusans /*
43956029a2d8Ssusans * A class whose enum value is smaller is inclusive of all
43966029a2d8Ssusans * higher values. If a PROGRESS (= -1) was previously
43976029a2d8Ssusans * registered, then a new registration requests for higher
43986029a2d8Ssusans * classes need not be sent to FW. They are automatically
43996029a2d8Ssusans * included.
44006029a2d8Ssusans *
44016029a2d8Ssusans * Locale numbers don't have such hierarchy. They are bitmap
44026029a2d8Ssusans * values
44036029a2d8Ssusans */
44046029a2d8Ssusans if ((prev_aen.members.class <= curr_aen.members.class) &&
44056029a2d8Ssusans !((prev_aen.members.locale & curr_aen.members.locale) ^
44066029a2d8Ssusans curr_aen.members.locale)) {
44076029a2d8Ssusans /*
44086029a2d8Ssusans * Previously issued event registration includes
44096029a2d8Ssusans * current request. Nothing to do.
44106029a2d8Ssusans */
44116029a2d8Ssusans
44126029a2d8Ssusans return (0);
44136029a2d8Ssusans } else {
44146029a2d8Ssusans curr_aen.members.locale |= prev_aen.members.locale;
44156029a2d8Ssusans
44166029a2d8Ssusans if (prev_aen.members.class < curr_aen.members.class)
44176029a2d8Ssusans curr_aen.members.class = prev_aen.members.class;
44186029a2d8Ssusans
44196029a2d8Ssusans ret_val = abort_aen_cmd(instance, instance->aen_cmd);
44206029a2d8Ssusans
44216029a2d8Ssusans if (ret_val) {
44226029a2d8Ssusans con_log(CL_ANN, (CE_WARN, "register_mfi_aen: "
44236029a2d8Ssusans "failed to abort prevous AEN command\n"));
44246029a2d8Ssusans
44256029a2d8Ssusans return (ret_val);
44266029a2d8Ssusans }
44276029a2d8Ssusans }
44286029a2d8Ssusans } else {
44296029a2d8Ssusans curr_aen.word = class_locale_word;
44306029a2d8Ssusans }
44316029a2d8Ssusans
44326029a2d8Ssusans cmd = get_mfi_pkt(instance);
44336029a2d8Ssusans
44346029a2d8Ssusans if (!cmd)
44356029a2d8Ssusans return (-ENOMEM);
44366029a2d8Ssusans
44376029a2d8Ssusans dcmd = &cmd->frame->dcmd;
44386029a2d8Ssusans
44397ddfa2acSSusan Scheufele /* for(i = 0; i < DCMD_MBOX_SZ; i++) dcmd->mbox.b[i] = 0; */
44407ddfa2acSSusan Scheufele (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
44416029a2d8Ssusans
44426029a2d8Ssusans (void) memset(instance->mfi_evt_detail_obj.buffer, 0,
44436029a2d8Ssusans sizeof (struct megasas_evt_detail));
44446029a2d8Ssusans
44456029a2d8Ssusans /* Prepare DCMD for aen registration */
44466029a2d8Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
44476029a2d8Ssusans dcmd->cmd_status = 0x0;
44486029a2d8Ssusans dcmd->sge_count = 1;
44496029a2d8Ssusans dcmd->flags = MFI_FRAME_DIR_READ;
44506029a2d8Ssusans dcmd->timeout = 0;
44516029a2d8Ssusans dcmd->data_xfer_len = sizeof (struct megasas_evt_detail);
44526029a2d8Ssusans dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
44536029a2d8Ssusans dcmd->mbox.w[0] = seq_num;
44546029a2d8Ssusans dcmd->mbox.w[1] = curr_aen.word;
44556029a2d8Ssusans dcmd->sgl.sge32[0].phys_addr =
44566029a2d8Ssusans instance->mfi_evt_detail_obj.dma_cookie[0].dmac_address;
44576029a2d8Ssusans dcmd->sgl.sge32[0].length = sizeof (struct megasas_evt_detail);
44586029a2d8Ssusans
44596029a2d8Ssusans instance->aen_seq_num = seq_num;
44606029a2d8Ssusans
44616029a2d8Ssusans /*
44626029a2d8Ssusans * Store reference to the cmd used to register for AEN. When an
44636029a2d8Ssusans * application wants us to register for AEN, we have to abort this
44646029a2d8Ssusans * cmd and re-register with a new EVENT LOCALE supplied by that app
44656029a2d8Ssusans */
44666029a2d8Ssusans instance->aen_cmd = cmd;
44676029a2d8Ssusans
44686029a2d8Ssusans cmd->frame_count = 1;
44696029a2d8Ssusans
44706029a2d8Ssusans /* Issue the aen registration frame */
44716029a2d8Ssusans /* atomic_add_16 (&instance->fw_outstanding, 1); */
44726029a2d8Ssusans instance->func_ptr->issue_cmd(cmd, instance);
44736029a2d8Ssusans
44746029a2d8Ssusans return (0);
44756029a2d8Ssusans }
44766029a2d8Ssusans
44776029a2d8Ssusans static void
display_scsi_inquiry(caddr_t scsi_inq)44786029a2d8Ssusans display_scsi_inquiry(caddr_t scsi_inq)
44796029a2d8Ssusans {
44806029a2d8Ssusans #define MAX_SCSI_DEVICE_CODE 14
44816029a2d8Ssusans int i;
44826029a2d8Ssusans char inquiry_buf[256] = {0};
44836029a2d8Ssusans int len;
44846029a2d8Ssusans const char *const scsi_device_types[] = {
44856029a2d8Ssusans "Direct-Access ",
44866029a2d8Ssusans "Sequential-Access",
44876029a2d8Ssusans "Printer ",
44886029a2d8Ssusans "Processor ",
44896029a2d8Ssusans "WORM ",
44906029a2d8Ssusans "CD-ROM ",
44916029a2d8Ssusans "Scanner ",
44926029a2d8Ssusans "Optical Device ",
44936029a2d8Ssusans "Medium Changer ",
44946029a2d8Ssusans "Communications ",
44956029a2d8Ssusans "Unknown ",
44966029a2d8Ssusans "Unknown ",
44976029a2d8Ssusans "Unknown ",
44986029a2d8Ssusans "Enclosure ",
44996029a2d8Ssusans };
45006029a2d8Ssusans
45016029a2d8Ssusans len = 0;
45026029a2d8Ssusans
45036029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Vendor: ");
45046029a2d8Ssusans for (i = 8; i < 16; i++) {
45056029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, "%c",
45066029a2d8Ssusans scsi_inq[i]);
45076029a2d8Ssusans }
45086029a2d8Ssusans
45096029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Model: ");
45106029a2d8Ssusans
45116029a2d8Ssusans for (i = 16; i < 32; i++) {
45126029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, "%c",
45136029a2d8Ssusans scsi_inq[i]);
45146029a2d8Ssusans }
45156029a2d8Ssusans
45166029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Rev: ");
45176029a2d8Ssusans
45186029a2d8Ssusans for (i = 32; i < 36; i++) {
45196029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, "%c",
45206029a2d8Ssusans scsi_inq[i]);
45216029a2d8Ssusans }
45226029a2d8Ssusans
45236029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, "\n");
45246029a2d8Ssusans
45256029a2d8Ssusans
45266029a2d8Ssusans i = scsi_inq[0] & 0x1f;
45276029a2d8Ssusans
45286029a2d8Ssusans
45296029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Type: %s ",
45306029a2d8Ssusans i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
45316029a2d8Ssusans "Unknown ");
45326029a2d8Ssusans
45336029a2d8Ssusans
45346029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len,
45356029a2d8Ssusans " ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
45366029a2d8Ssusans
45376029a2d8Ssusans if ((scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1) {
45386029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, " CCS\n");
45396029a2d8Ssusans } else {
45406029a2d8Ssusans len += snprintf(inquiry_buf + len, 265 - len, "\n");
45416029a2d8Ssusans }
45426029a2d8Ssusans
45436029a2d8Ssusans con_log(CL_ANN1, (CE_CONT, inquiry_buf));
45446029a2d8Ssusans }
45456029a2d8Ssusans
45466029a2d8Ssusans static int
read_fw_status_reg_xscale(struct megasas_instance * instance)45476029a2d8Ssusans read_fw_status_reg_xscale(struct megasas_instance *instance)
45486029a2d8Ssusans {
45496029a2d8Ssusans return ((int)RD_OB_MSG_0(instance));
45506029a2d8Ssusans }
45516029a2d8Ssusans
45526029a2d8Ssusans static int
read_fw_status_reg_ppc(struct megasas_instance * instance)45536029a2d8Ssusans read_fw_status_reg_ppc(struct megasas_instance *instance)
45546029a2d8Ssusans {
45556029a2d8Ssusans return ((int)RD_OB_SCRATCH_PAD_0(instance));
45566029a2d8Ssusans }
45576029a2d8Ssusans
45586029a2d8Ssusans static void
issue_cmd_xscale(struct megasas_cmd * cmd,struct megasas_instance * instance)45596029a2d8Ssusans issue_cmd_xscale(struct megasas_cmd *cmd, struct megasas_instance *instance)
45606029a2d8Ssusans {
45611a5e258fSJosef 'Jeff' Sipek atomic_inc_16(&instance->fw_outstanding);
45626029a2d8Ssusans
45636029a2d8Ssusans /* Issue the command to the FW */
45646029a2d8Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr) >> 3) |
45656029a2d8Ssusans (cmd->frame_count - 1), instance);
45666029a2d8Ssusans }
45676029a2d8Ssusans
45686029a2d8Ssusans static void
issue_cmd_ppc(struct megasas_cmd * cmd,struct megasas_instance * instance)45696029a2d8Ssusans issue_cmd_ppc(struct megasas_cmd *cmd, struct megasas_instance *instance)
45706029a2d8Ssusans {
45711a5e258fSJosef 'Jeff' Sipek atomic_inc_16(&instance->fw_outstanding);
45726029a2d8Ssusans
45736029a2d8Ssusans /* Issue the command to the FW */
45746029a2d8Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr)) |
45756029a2d8Ssusans (((cmd->frame_count - 1) << 1) | 1), instance);
45766029a2d8Ssusans }
45776029a2d8Ssusans
45786029a2d8Ssusans /*
45796029a2d8Ssusans * issue_cmd_in_sync_mode
45806029a2d8Ssusans */
45816029a2d8Ssusans static int
issue_cmd_in_sync_mode_xscale(struct megasas_instance * instance,struct megasas_cmd * cmd)45826029a2d8Ssusans issue_cmd_in_sync_mode_xscale(struct megasas_instance *instance,
45836029a2d8Ssusans struct megasas_cmd *cmd)
45846029a2d8Ssusans {
45856029a2d8Ssusans int i;
45867ddfa2acSSusan Scheufele uint32_t msecs = MFI_POLL_TIMEOUT_SECS * (10 * MILLISEC);
45876029a2d8Ssusans
45886029a2d8Ssusans cmd->cmd_status = ENODATA;
45896029a2d8Ssusans
45906029a2d8Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr) >> 3) |
45916029a2d8Ssusans (cmd->frame_count - 1), instance);
45926029a2d8Ssusans
45936029a2d8Ssusans mutex_enter(&instance->int_cmd_mtx);
45946029a2d8Ssusans
45956029a2d8Ssusans for (i = 0; i < msecs && (cmd->cmd_status == ENODATA); i++) {
45966029a2d8Ssusans cv_wait(&instance->int_cmd_cv, &instance->int_cmd_mtx);
45976029a2d8Ssusans }
45986029a2d8Ssusans
45996029a2d8Ssusans mutex_exit(&instance->int_cmd_mtx);
46006029a2d8Ssusans
46016029a2d8Ssusans if (i < (msecs -1)) {
46026029a2d8Ssusans return (0);
46036029a2d8Ssusans } else {
46046029a2d8Ssusans return (1);
46056029a2d8Ssusans }
46066029a2d8Ssusans }
46076029a2d8Ssusans
46086029a2d8Ssusans static int
issue_cmd_in_sync_mode_ppc(struct megasas_instance * instance,struct megasas_cmd * cmd)46096029a2d8Ssusans issue_cmd_in_sync_mode_ppc(struct megasas_instance *instance,
46106029a2d8Ssusans struct megasas_cmd *cmd)
46116029a2d8Ssusans {
46126029a2d8Ssusans int i;
46137ddfa2acSSusan Scheufele uint32_t msecs = MFI_POLL_TIMEOUT_SECS * (10 * MILLISEC);
46146029a2d8Ssusans
46156029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_sync_mode_ppc: called\n"));
46166029a2d8Ssusans
46176029a2d8Ssusans cmd->cmd_status = ENODATA;
46186029a2d8Ssusans
46196029a2d8Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr)) |
46206029a2d8Ssusans (((cmd->frame_count - 1) << 1) | 1), instance);
46216029a2d8Ssusans
46226029a2d8Ssusans mutex_enter(&instance->int_cmd_mtx);
46236029a2d8Ssusans
46246029a2d8Ssusans for (i = 0; i < msecs && (cmd->cmd_status == ENODATA); i++) {
46256029a2d8Ssusans cv_wait(&instance->int_cmd_cv, &instance->int_cmd_mtx);
46266029a2d8Ssusans }
46276029a2d8Ssusans
46286029a2d8Ssusans mutex_exit(&instance->int_cmd_mtx);
46296029a2d8Ssusans
46306029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_sync_mode_ppc: done\n"));
46316029a2d8Ssusans
46326029a2d8Ssusans if (i < (msecs -1)) {
46336029a2d8Ssusans return (0);
46346029a2d8Ssusans } else {
46356029a2d8Ssusans return (1);
46366029a2d8Ssusans }
46376029a2d8Ssusans }
46386029a2d8Ssusans
46396029a2d8Ssusans /*
46406029a2d8Ssusans * issue_cmd_in_poll_mode
46416029a2d8Ssusans */
46426029a2d8Ssusans static int
issue_cmd_in_poll_mode_xscale(struct megasas_instance * instance,struct megasas_cmd * cmd)46436029a2d8Ssusans issue_cmd_in_poll_mode_xscale(struct megasas_instance *instance,
46446029a2d8Ssusans struct megasas_cmd *cmd)
46456029a2d8Ssusans {
46466029a2d8Ssusans int i;
46477ddfa2acSSusan Scheufele uint32_t msecs = MFI_POLL_TIMEOUT_SECS * MILLISEC;
46487ddfa2acSSusan Scheufele struct megasas_header *frame_hdr;
46496029a2d8Ssusans
46507ddfa2acSSusan Scheufele frame_hdr = (struct megasas_header *)cmd->frame;
46517ddfa2acSSusan Scheufele frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
46526029a2d8Ssusans frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
46536029a2d8Ssusans
46546029a2d8Ssusans /* issue the frame using inbound queue port */
46556029a2d8Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr) >> 3) |
46566029a2d8Ssusans (cmd->frame_count - 1), instance);
46576029a2d8Ssusans
46587ddfa2acSSusan Scheufele /* wait for cmd_status to change from 0xFF */
46597ddfa2acSSusan Scheufele for (i = 0; i < msecs && (frame_hdr->cmd_status ==
46607ddfa2acSSusan Scheufele MFI_CMD_STATUS_POLL_MODE); i++) {
46617ddfa2acSSusan Scheufele drv_usecwait(MILLISEC); /* wait for 1000 usecs */
46626029a2d8Ssusans }
46636029a2d8Ssusans
46647ddfa2acSSusan Scheufele if (frame_hdr->cmd_status == MFI_CMD_STATUS_POLL_MODE) {
46656029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_cmd_in_poll_mode: "
46666029a2d8Ssusans "cmd polling timed out"));
46676029a2d8Ssusans return (DDI_FAILURE);
46686029a2d8Ssusans }
46696029a2d8Ssusans
46706029a2d8Ssusans return (DDI_SUCCESS);
46716029a2d8Ssusans }
46726029a2d8Ssusans
46736029a2d8Ssusans static int
issue_cmd_in_poll_mode_ppc(struct megasas_instance * instance,struct megasas_cmd * cmd)46746029a2d8Ssusans issue_cmd_in_poll_mode_ppc(struct megasas_instance *instance,
46756029a2d8Ssusans struct megasas_cmd *cmd)
46766029a2d8Ssusans {
46776029a2d8Ssusans int i;
46787ddfa2acSSusan Scheufele uint32_t msecs = MFI_POLL_TIMEOUT_SECS * MILLISEC;
46797ddfa2acSSusan Scheufele struct megasas_header *frame_hdr;
46806029a2d8Ssusans
46816029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_poll_mode_ppc: called\n"));
46826029a2d8Ssusans
46837ddfa2acSSusan Scheufele frame_hdr = (struct megasas_header *)cmd->frame;
46847ddfa2acSSusan Scheufele frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
46856029a2d8Ssusans frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
46866029a2d8Ssusans
46876029a2d8Ssusans /* issue the frame using inbound queue port */
46886029a2d8Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr)) |
46896029a2d8Ssusans (((cmd->frame_count - 1) << 1) | 1), instance);
46906029a2d8Ssusans
46917ddfa2acSSusan Scheufele /* wait for cmd_status to change from 0xFF */
46927ddfa2acSSusan Scheufele for (i = 0; i < msecs && (frame_hdr->cmd_status ==
46937ddfa2acSSusan Scheufele MFI_CMD_STATUS_POLL_MODE); i++) {
46947ddfa2acSSusan Scheufele drv_usecwait(MILLISEC); /* wait for 1000 usecs */
46956029a2d8Ssusans }
46966029a2d8Ssusans
46977ddfa2acSSusan Scheufele if (frame_hdr->cmd_status == MFI_CMD_STATUS_POLL_MODE) {
46986029a2d8Ssusans con_log(CL_ANN, (CE_NOTE, "issue_cmd_in_poll_mode: "
46996029a2d8Ssusans "cmd polling timed out"));
47006029a2d8Ssusans return (DDI_FAILURE);
47016029a2d8Ssusans }
47026029a2d8Ssusans
47036029a2d8Ssusans return (DDI_SUCCESS);
47046029a2d8Ssusans }
47056029a2d8Ssusans
47066029a2d8Ssusans static void
enable_intr_xscale(struct megasas_instance * instance)47076029a2d8Ssusans enable_intr_xscale(struct megasas_instance *instance)
47086029a2d8Ssusans {
47096029a2d8Ssusans MFI_ENABLE_INTR(instance);
47106029a2d8Ssusans }
47116029a2d8Ssusans
47126029a2d8Ssusans static void
enable_intr_ppc(struct megasas_instance * instance)47136029a2d8Ssusans enable_intr_ppc(struct megasas_instance *instance)
47146029a2d8Ssusans {
47156029a2d8Ssusans uint32_t mask;
47166029a2d8Ssusans
47176029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "enable_intr_ppc: called\n"));
47186029a2d8Ssusans
47197ddfa2acSSusan Scheufele /* WR_OB_DOORBELL_CLEAR(0xFFFFFFFF, instance); */
47207ddfa2acSSusan Scheufele WR_OB_DOORBELL_CLEAR(OB_DOORBELL_CLEAR_MASK, instance);
4721ea20eddaSsusans
4722ea20eddaSsusans /*
4723ea20eddaSsusans * As 1078DE is same as 1078 chip, the interrupt mask
4724ea20eddaSsusans * remains the same.
4725ea20eddaSsusans */
47266029a2d8Ssusans /* WR_OB_INTR_MASK(~0x80000000, instance); */
47277ddfa2acSSusan Scheufele WR_OB_INTR_MASK(~(MFI_REPLY_1078_MESSAGE_INTR), instance);
47286029a2d8Ssusans
47296029a2d8Ssusans /* dummy read to force PCI flush */
47306029a2d8Ssusans mask = RD_OB_INTR_MASK(instance);
47316029a2d8Ssusans
47326029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "enable_intr_ppc: "
47336029a2d8Ssusans "outbound_intr_mask = 0x%x\n", mask));
47346029a2d8Ssusans }
47356029a2d8Ssusans
47366029a2d8Ssusans static void
disable_intr_xscale(struct megasas_instance * instance)47376029a2d8Ssusans disable_intr_xscale(struct megasas_instance *instance)
47386029a2d8Ssusans {
47396029a2d8Ssusans MFI_DISABLE_INTR(instance);
47406029a2d8Ssusans }
47416029a2d8Ssusans
47426029a2d8Ssusans static void
disable_intr_ppc(struct megasas_instance * instance)47436029a2d8Ssusans disable_intr_ppc(struct megasas_instance *instance)
47446029a2d8Ssusans {
47456029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: called\n"));
47466029a2d8Ssusans
47476029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: before : "
47486029a2d8Ssusans "outbound_intr_mask = 0x%x\n", RD_OB_INTR_MASK(instance)));
47496029a2d8Ssusans
47507ddfa2acSSusan Scheufele /* WR_OB_INTR_MASK(0xFFFFFFFF, instance); */
47517ddfa2acSSusan Scheufele WR_OB_INTR_MASK(OB_INTR_MASK, instance);
47526029a2d8Ssusans
47536029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: after : "
47546029a2d8Ssusans "outbound_intr_mask = 0x%x\n", RD_OB_INTR_MASK(instance)));
47556029a2d8Ssusans
47566029a2d8Ssusans /* dummy read to force PCI flush */
4757c873de80SToomas Soome (void) RD_OB_INTR_MASK(instance);
47586029a2d8Ssusans }
47596029a2d8Ssusans
47606029a2d8Ssusans static int
intr_ack_xscale(struct megasas_instance * instance)47616029a2d8Ssusans intr_ack_xscale(struct megasas_instance *instance)
47626029a2d8Ssusans {
47636029a2d8Ssusans uint32_t status;
47646029a2d8Ssusans
47656029a2d8Ssusans /* check if it is our interrupt */
47666029a2d8Ssusans status = RD_OB_INTR_STATUS(instance);
47676029a2d8Ssusans
47686029a2d8Ssusans if (!(status & MFI_OB_INTR_STATUS_MASK)) {
47696029a2d8Ssusans return (DDI_INTR_UNCLAIMED);
47706029a2d8Ssusans }
47716029a2d8Ssusans
47726029a2d8Ssusans /* clear the interrupt by writing back the same value */
47736029a2d8Ssusans WR_OB_INTR_STATUS(status, instance);
47746029a2d8Ssusans
47756029a2d8Ssusans return (DDI_INTR_CLAIMED);
47766029a2d8Ssusans }
47776029a2d8Ssusans
47786029a2d8Ssusans static int
intr_ack_ppc(struct megasas_instance * instance)47796029a2d8Ssusans intr_ack_ppc(struct megasas_instance *instance)
47806029a2d8Ssusans {
47816029a2d8Ssusans uint32_t status;
47826029a2d8Ssusans
47836029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: called\n"));
47846029a2d8Ssusans
47856029a2d8Ssusans /* check if it is our interrupt */
47866029a2d8Ssusans status = RD_OB_INTR_STATUS(instance);
47876029a2d8Ssusans
47886029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: status = 0x%x\n", status));
47896029a2d8Ssusans
4790ea20eddaSsusans /*
4791ea20eddaSsusans * As 1078DE is same as 1078 chip, the status field
4792ea20eddaSsusans * remains the same.
4793ea20eddaSsusans */
47946029a2d8Ssusans if (!(status & MFI_REPLY_1078_MESSAGE_INTR)) {
47956029a2d8Ssusans return (DDI_INTR_UNCLAIMED);
47966029a2d8Ssusans }
47976029a2d8Ssusans
47986029a2d8Ssusans /* clear the interrupt by writing back the same value */
47996029a2d8Ssusans WR_OB_DOORBELL_CLEAR(status, instance);
48006029a2d8Ssusans
48016029a2d8Ssusans /* dummy READ */
48026029a2d8Ssusans status = RD_OB_INTR_STATUS(instance);
48036029a2d8Ssusans
48046029a2d8Ssusans con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: interrupt cleared\n"));
48056029a2d8Ssusans
48066029a2d8Ssusans return (DDI_INTR_CLAIMED);
48076029a2d8Ssusans }
48082fa451d9SYu Wu - Sun Microsystems - Beijing China
48092fa451d9SYu Wu - Sun Microsystems - Beijing China static int
megasas_common_check(struct megasas_instance * instance,struct megasas_cmd * cmd)48102fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_common_check(struct megasas_instance *instance,
48112fa451d9SYu Wu - Sun Microsystems - Beijing China struct megasas_cmd *cmd)
48122fa451d9SYu Wu - Sun Microsystems - Beijing China {
48132fa451d9SYu Wu - Sun Microsystems - Beijing China int ret = DDI_SUCCESS;
48142fa451d9SYu Wu - Sun Microsystems - Beijing China
48152fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(cmd->frame_dma_obj.dma_handle) !=
48162fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SUCCESS) {
48172fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48182fa451d9SYu Wu - Sun Microsystems - Beijing China if (cmd->pkt != NULL) {
48192fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48202fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_statistics = 0;
48212fa451d9SYu Wu - Sun Microsystems - Beijing China }
48222fa451d9SYu Wu - Sun Microsystems - Beijing China ret = DDI_FAILURE;
48232fa451d9SYu Wu - Sun Microsystems - Beijing China }
48242fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(instance->mfi_internal_dma_obj.dma_handle)
48252fa451d9SYu Wu - Sun Microsystems - Beijing China != DDI_SUCCESS) {
48262fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48272fa451d9SYu Wu - Sun Microsystems - Beijing China if (cmd->pkt != NULL) {
48282fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48292fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_statistics = 0;
48302fa451d9SYu Wu - Sun Microsystems - Beijing China }
48312fa451d9SYu Wu - Sun Microsystems - Beijing China ret = DDI_FAILURE;
48322fa451d9SYu Wu - Sun Microsystems - Beijing China }
48332fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_dma_handle(instance->mfi_evt_detail_obj.dma_handle) !=
48342fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_SUCCESS) {
48352fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48362fa451d9SYu Wu - Sun Microsystems - Beijing China if (cmd->pkt != NULL) {
48372fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48382fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_statistics = 0;
48392fa451d9SYu Wu - Sun Microsystems - Beijing China }
48402fa451d9SYu Wu - Sun Microsystems - Beijing China ret = DDI_FAILURE;
48412fa451d9SYu Wu - Sun Microsystems - Beijing China }
48422fa451d9SYu Wu - Sun Microsystems - Beijing China if (megasas_check_acc_handle(instance->regmap_handle) != DDI_SUCCESS) {
48432fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48442fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_acc_err_clear(instance->regmap_handle, DDI_FME_VER0);
48452fa451d9SYu Wu - Sun Microsystems - Beijing China if (cmd->pkt != NULL) {
48462fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48472fa451d9SYu Wu - Sun Microsystems - Beijing China cmd->pkt->pkt_statistics = 0;
48482fa451d9SYu Wu - Sun Microsystems - Beijing China }
48492fa451d9SYu Wu - Sun Microsystems - Beijing China ret = DDI_FAILURE;
48502fa451d9SYu Wu - Sun Microsystems - Beijing China }
48512fa451d9SYu Wu - Sun Microsystems - Beijing China
48522fa451d9SYu Wu - Sun Microsystems - Beijing China return (ret);
48532fa451d9SYu Wu - Sun Microsystems - Beijing China }
48542fa451d9SYu Wu - Sun Microsystems - Beijing China
48552fa451d9SYu Wu - Sun Microsystems - Beijing China /*ARGSUSED*/
48562fa451d9SYu Wu - Sun Microsystems - Beijing China static int
megasas_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)48572fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
48582fa451d9SYu Wu - Sun Microsystems - Beijing China {
48592fa451d9SYu Wu - Sun Microsystems - Beijing China /*
48602fa451d9SYu Wu - Sun Microsystems - Beijing China * as the driver can always deal with an error in any dma or
48612fa451d9SYu Wu - Sun Microsystems - Beijing China * access handle, we can just return the fme_status value.
48622fa451d9SYu Wu - Sun Microsystems - Beijing China */
48632fa451d9SYu Wu - Sun Microsystems - Beijing China pci_ereport_post(dip, err, NULL);
48642fa451d9SYu Wu - Sun Microsystems - Beijing China return (err->fme_status);
48652fa451d9SYu Wu - Sun Microsystems - Beijing China }
48662fa451d9SYu Wu - Sun Microsystems - Beijing China
48672fa451d9SYu Wu - Sun Microsystems - Beijing China static void
megasas_fm_init(struct megasas_instance * instance)48682fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_init(struct megasas_instance *instance)
48692fa451d9SYu Wu - Sun Microsystems - Beijing China {
48702fa451d9SYu Wu - Sun Microsystems - Beijing China /* Need to change iblock to priority for new MSI intr */
48712fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_iblock_cookie_t fm_ibc;
48722fa451d9SYu Wu - Sun Microsystems - Beijing China
48732fa451d9SYu Wu - Sun Microsystems - Beijing China /* Only register with IO Fault Services if we have some capability */
48742fa451d9SYu Wu - Sun Microsystems - Beijing China if (instance->fm_capabilities) {
48752fa451d9SYu Wu - Sun Microsystems - Beijing China /* Adjust access and dma attributes for FMA */
48762fa451d9SYu Wu - Sun Microsystems - Beijing China endian_attr.devacc_attr_access = DDI_FLAGERR_ACC;
48772fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_generic_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
48782fa451d9SYu Wu - Sun Microsystems - Beijing China
48792fa451d9SYu Wu - Sun Microsystems - Beijing China /*
48802fa451d9SYu Wu - Sun Microsystems - Beijing China * Register capabilities with IO Fault Services.
48812fa451d9SYu Wu - Sun Microsystems - Beijing China * fm_capabilities will be updated to indicate
48822fa451d9SYu Wu - Sun Microsystems - Beijing China * capabilities actually supported (not requested.)
48832fa451d9SYu Wu - Sun Microsystems - Beijing China */
48842fa451d9SYu Wu - Sun Microsystems - Beijing China
48852fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_init(instance->dip, &instance->fm_capabilities, &fm_ibc);
48862fa451d9SYu Wu - Sun Microsystems - Beijing China
48872fa451d9SYu Wu - Sun Microsystems - Beijing China /*
48882fa451d9SYu Wu - Sun Microsystems - Beijing China * Initialize pci ereport capabilities if ereport
48892fa451d9SYu Wu - Sun Microsystems - Beijing China * capable (should always be.)
48902fa451d9SYu Wu - Sun Microsystems - Beijing China */
48912fa451d9SYu Wu - Sun Microsystems - Beijing China
48922fa451d9SYu Wu - Sun Microsystems - Beijing China if (DDI_FM_EREPORT_CAP(instance->fm_capabilities) ||
48932fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
48942fa451d9SYu Wu - Sun Microsystems - Beijing China pci_ereport_setup(instance->dip);
48952fa451d9SYu Wu - Sun Microsystems - Beijing China }
48962fa451d9SYu Wu - Sun Microsystems - Beijing China
48972fa451d9SYu Wu - Sun Microsystems - Beijing China /*
48982fa451d9SYu Wu - Sun Microsystems - Beijing China * Register error callback if error callback capable.
48992fa451d9SYu Wu - Sun Microsystems - Beijing China */
49002fa451d9SYu Wu - Sun Microsystems - Beijing China if (DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49012fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_handler_register(instance->dip,
49022fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_error_cb, (void*) instance);
49032fa451d9SYu Wu - Sun Microsystems - Beijing China }
49042fa451d9SYu Wu - Sun Microsystems - Beijing China } else {
49052fa451d9SYu Wu - Sun Microsystems - Beijing China endian_attr.devacc_attr_access = DDI_DEFAULT_ACC;
49062fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_generic_dma_attr.dma_attr_flags = 0;
49072fa451d9SYu Wu - Sun Microsystems - Beijing China }
49082fa451d9SYu Wu - Sun Microsystems - Beijing China }
49092fa451d9SYu Wu - Sun Microsystems - Beijing China
49102fa451d9SYu Wu - Sun Microsystems - Beijing China static void
megasas_fm_fini(struct megasas_instance * instance)49112fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_fini(struct megasas_instance *instance)
49122fa451d9SYu Wu - Sun Microsystems - Beijing China {
49132fa451d9SYu Wu - Sun Microsystems - Beijing China /* Only unregister FMA capabilities if registered */
49142fa451d9SYu Wu - Sun Microsystems - Beijing China if (instance->fm_capabilities) {
49152fa451d9SYu Wu - Sun Microsystems - Beijing China /*
49162fa451d9SYu Wu - Sun Microsystems - Beijing China * Un-register error callback if error callback capable.
49172fa451d9SYu Wu - Sun Microsystems - Beijing China */
49182fa451d9SYu Wu - Sun Microsystems - Beijing China if (DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49192fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_handler_unregister(instance->dip);
49202fa451d9SYu Wu - Sun Microsystems - Beijing China }
49212fa451d9SYu Wu - Sun Microsystems - Beijing China
49222fa451d9SYu Wu - Sun Microsystems - Beijing China /*
49232fa451d9SYu Wu - Sun Microsystems - Beijing China * Release any resources allocated by pci_ereport_setup()
49242fa451d9SYu Wu - Sun Microsystems - Beijing China */
49252fa451d9SYu Wu - Sun Microsystems - Beijing China if (DDI_FM_EREPORT_CAP(instance->fm_capabilities) ||
49262fa451d9SYu Wu - Sun Microsystems - Beijing China DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49272fa451d9SYu Wu - Sun Microsystems - Beijing China pci_ereport_teardown(instance->dip);
49282fa451d9SYu Wu - Sun Microsystems - Beijing China }
49292fa451d9SYu Wu - Sun Microsystems - Beijing China
49302fa451d9SYu Wu - Sun Microsystems - Beijing China /* Unregister from IO Fault Services */
49312fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_fini(instance->dip);
49322fa451d9SYu Wu - Sun Microsystems - Beijing China
49332fa451d9SYu Wu - Sun Microsystems - Beijing China /* Adjust access and dma attributes for FMA */
49342fa451d9SYu Wu - Sun Microsystems - Beijing China endian_attr.devacc_attr_access = DDI_DEFAULT_ACC;
49352fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_generic_dma_attr.dma_attr_flags = 0;
49362fa451d9SYu Wu - Sun Microsystems - Beijing China }
49372fa451d9SYu Wu - Sun Microsystems - Beijing China }
49382fa451d9SYu Wu - Sun Microsystems - Beijing China
49392fa451d9SYu Wu - Sun Microsystems - Beijing China int
megasas_check_acc_handle(ddi_acc_handle_t handle)49402fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_check_acc_handle(ddi_acc_handle_t handle)
49412fa451d9SYu Wu - Sun Microsystems - Beijing China {
49422fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_error_t de;
49432fa451d9SYu Wu - Sun Microsystems - Beijing China
49442fa451d9SYu Wu - Sun Microsystems - Beijing China if (handle == NULL) {
49452fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_FAILURE);
49462fa451d9SYu Wu - Sun Microsystems - Beijing China }
49472fa451d9SYu Wu - Sun Microsystems - Beijing China
49482fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
49492fa451d9SYu Wu - Sun Microsystems - Beijing China
49502fa451d9SYu Wu - Sun Microsystems - Beijing China return (de.fme_status);
49512fa451d9SYu Wu - Sun Microsystems - Beijing China }
49522fa451d9SYu Wu - Sun Microsystems - Beijing China
49532fa451d9SYu Wu - Sun Microsystems - Beijing China int
megasas_check_dma_handle(ddi_dma_handle_t handle)49542fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_check_dma_handle(ddi_dma_handle_t handle)
49552fa451d9SYu Wu - Sun Microsystems - Beijing China {
49562fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_error_t de;
49572fa451d9SYu Wu - Sun Microsystems - Beijing China
49582fa451d9SYu Wu - Sun Microsystems - Beijing China if (handle == NULL) {
49592fa451d9SYu Wu - Sun Microsystems - Beijing China return (DDI_FAILURE);
49602fa451d9SYu Wu - Sun Microsystems - Beijing China }
49612fa451d9SYu Wu - Sun Microsystems - Beijing China
49622fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
49632fa451d9SYu Wu - Sun Microsystems - Beijing China
49642fa451d9SYu Wu - Sun Microsystems - Beijing China return (de.fme_status);
49652fa451d9SYu Wu - Sun Microsystems - Beijing China }
49662fa451d9SYu Wu - Sun Microsystems - Beijing China
49672fa451d9SYu Wu - Sun Microsystems - Beijing China void
megasas_fm_ereport(struct megasas_instance * instance,char * detail)49682fa451d9SYu Wu - Sun Microsystems - Beijing China megasas_fm_ereport(struct megasas_instance *instance, char *detail)
49692fa451d9SYu Wu - Sun Microsystems - Beijing China {
49702fa451d9SYu Wu - Sun Microsystems - Beijing China uint64_t ena;
49712fa451d9SYu Wu - Sun Microsystems - Beijing China char buf[FM_MAX_CLASS];
49722fa451d9SYu Wu - Sun Microsystems - Beijing China
49732fa451d9SYu Wu - Sun Microsystems - Beijing China (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
49742fa451d9SYu Wu - Sun Microsystems - Beijing China ena = fm_ena_generate(0, FM_ENA_FMT1);
49752fa451d9SYu Wu - Sun Microsystems - Beijing China if (DDI_FM_EREPORT_CAP(instance->fm_capabilities)) {
49762fa451d9SYu Wu - Sun Microsystems - Beijing China ddi_fm_ereport_post(instance->dip, buf, ena, DDI_NOSLEEP,
49772fa451d9SYu Wu - Sun Microsystems - Beijing China FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
49782fa451d9SYu Wu - Sun Microsystems - Beijing China }
49792fa451d9SYu Wu - Sun Microsystems - Beijing China }
4980