16447Ssusans /*
26447Ssusans * megaraid_sas.c: source for mega_sas driver
36447Ssusans *
46447Ssusans * MegaRAID device driver for SAS controllers
56447Ssusans * Copyright (c) 2005-2008, LSI Logic Corporation.
66447Ssusans * All rights reserved.
76447Ssusans *
86447Ssusans * Version:
96447Ssusans * Author:
106447Ssusans * Rajesh Prabhakaran<Rajesh.Prabhakaran@lsil.com>
116447Ssusans * Seokmann Ju
126447Ssusans *
136447Ssusans * Redistribution and use in source and binary forms, with or without
146447Ssusans * modification, are permitted provided that the following conditions are met:
156447Ssusans *
166447Ssusans * 1. Redistributions of source code must retain the above copyright notice,
176447Ssusans * this list of conditions and the following disclaimer.
186447Ssusans *
196447Ssusans * 2. Redistributions in binary form must reproduce the above copyright notice,
206447Ssusans * this list of conditions and the following disclaimer in the documentation
216447Ssusans * and/or other materials provided with the distribution.
226447Ssusans *
236447Ssusans * 3. Neither the name of the author nor the names of its contributors may be
246447Ssusans * used to endorse or promote products derived from this software without
256447Ssusans * specific prior written permission.
266447Ssusans *
276447Ssusans * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
286447Ssusans * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
296447Ssusans * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
306447Ssusans * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
316447Ssusans * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
326447Ssusans * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
336447Ssusans * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
346447Ssusans * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
356447Ssusans * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
366447Ssusans * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
376447Ssusans * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
386447Ssusans * DAMAGE.
396447Ssusans */
406447Ssusans
416447Ssusans /*
429106SSrivijitha.Dugganapalli@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
436447Ssusans * Use is subject to license terms.
446447Ssusans */
456447Ssusans
466447Ssusans #include <sys/types.h>
476447Ssusans #include <sys/param.h>
486447Ssusans #include <sys/file.h>
496447Ssusans #include <sys/errno.h>
506447Ssusans #include <sys/open.h>
516447Ssusans #include <sys/cred.h>
526447Ssusans #include <sys/modctl.h>
536447Ssusans #include <sys/conf.h>
546447Ssusans #include <sys/devops.h>
556447Ssusans #include <sys/cmn_err.h>
566447Ssusans #include <sys/kmem.h>
576447Ssusans #include <sys/stat.h>
586447Ssusans #include <sys/mkdev.h>
596447Ssusans #include <sys/pci.h>
606447Ssusans #include <sys/scsi/scsi.h>
616447Ssusans #include <sys/ddi.h>
626447Ssusans #include <sys/sunddi.h>
636447Ssusans #include <sys/atomic.h>
646447Ssusans #include <sys/signal.h>
656447Ssusans
666447Ssusans #include "megaraid_sas.h"
676447Ssusans
686447Ssusans /*
697533SYu.Wu@Sun.COM * FMA header files
707533SYu.Wu@Sun.COM */
717533SYu.Wu@Sun.COM #include <sys/ddifm.h>
727533SYu.Wu@Sun.COM #include <sys/fm/protocol.h>
737533SYu.Wu@Sun.COM #include <sys/fm/util.h>
747533SYu.Wu@Sun.COM #include <sys/fm/io/ddi.h>
757533SYu.Wu@Sun.COM
767533SYu.Wu@Sun.COM /*
776447Ssusans * Local static data
786447Ssusans */
796447Ssusans static void *megasas_state = NULL;
806447Ssusans static int debug_level_g = CL_ANN;
816447Ssusans
826447Ssusans #pragma weak scsi_hba_open
836447Ssusans #pragma weak scsi_hba_close
846447Ssusans #pragma weak scsi_hba_ioctl
856447Ssusans
866447Ssusans static ddi_dma_attr_t megasas_generic_dma_attr = {
877562SSusan.Scheufele@Sun.COM DMA_ATTR_V0, /* dma_attr_version */
887562SSusan.Scheufele@Sun.COM 0, /* low DMA address range */
897562SSusan.Scheufele@Sun.COM 0xFFFFFFFFU, /* high DMA address range */
907562SSusan.Scheufele@Sun.COM 0xFFFFFFFFU, /* DMA counter register */
917562SSusan.Scheufele@Sun.COM 8, /* DMA address alignment */
927562SSusan.Scheufele@Sun.COM 0x07, /* DMA burstsizes */
937562SSusan.Scheufele@Sun.COM 1, /* min DMA size */
947562SSusan.Scheufele@Sun.COM 0xFFFFFFFFU, /* max DMA size */
957562SSusan.Scheufele@Sun.COM 0xFFFFFFFFU, /* segment boundary */
967562SSusan.Scheufele@Sun.COM MEGASAS_MAX_SGE_CNT, /* dma_attr_sglen */
977562SSusan.Scheufele@Sun.COM 512, /* granularity of device */
987562SSusan.Scheufele@Sun.COM 0 /* bus specific DMA flags */
996447Ssusans };
1006447Ssusans
1016447Ssusans int32_t megasas_max_cap_maxxfer = 0x1000000;
1026447Ssusans
1036447Ssusans /*
1046447Ssusans * cb_ops contains base level routines
1056447Ssusans */
1066447Ssusans static struct cb_ops megasas_cb_ops = {
1076447Ssusans megasas_open, /* open */
1086447Ssusans megasas_close, /* close */
1096447Ssusans nodev, /* strategy */
1106447Ssusans nodev, /* print */
1116447Ssusans nodev, /* dump */
1126447Ssusans nodev, /* read */
1136447Ssusans nodev, /* write */
1146447Ssusans megasas_ioctl, /* ioctl */
1156447Ssusans nodev, /* devmap */
1166447Ssusans nodev, /* mmap */
1176447Ssusans nodev, /* segmap */
1186447Ssusans nochpoll, /* poll */
1196447Ssusans nodev, /* cb_prop_op */
1206447Ssusans 0, /* streamtab */
1216447Ssusans D_NEW | D_HOTPLUG, /* cb_flag */
1226447Ssusans CB_REV, /* cb_rev */
1236447Ssusans nodev, /* cb_aread */
1246447Ssusans nodev /* cb_awrite */
1256447Ssusans };
1266447Ssusans
1276447Ssusans /*
1286447Ssusans * dev_ops contains configuration routines
1296447Ssusans */
1306447Ssusans static struct dev_ops megasas_ops = {
1316447Ssusans DEVO_REV, /* rev, */
1326447Ssusans 0, /* refcnt */
1336447Ssusans megasas_getinfo, /* getinfo */
1346447Ssusans nulldev, /* identify */
1356447Ssusans nulldev, /* probe */
1366447Ssusans megasas_attach, /* attach */
1376447Ssusans megasas_detach, /* detach */
1386447Ssusans megasas_reset, /* reset */
1396447Ssusans &megasas_cb_ops, /* char/block ops */
1407656SSherry.Moore@Sun.COM NULL, /* bus ops */
1417656SSherry.Moore@Sun.COM NULL, /* power */
1427656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
1436447Ssusans };
1446447Ssusans
1456447Ssusans char _depends_on[] = "misc/scsi";
1466447Ssusans
1476447Ssusans static struct modldrv modldrv = {
1486447Ssusans &mod_driverops, /* module type - driver */
1496447Ssusans MEGASAS_VERSION,
1506447Ssusans &megasas_ops, /* driver ops */
1516447Ssusans };
1526447Ssusans
1536447Ssusans static struct modlinkage modlinkage = {
1546447Ssusans MODREV_1, /* ml_rev - must be MODREV_1 */
1556447Ssusans &modldrv, /* ml_linkage */
1566447Ssusans NULL /* end of driver linkage */
1576447Ssusans };
1586447Ssusans
1596447Ssusans static struct ddi_device_acc_attr endian_attr = {
160*11236SStephen.Hanson@Sun.COM DDI_DEVICE_ATTR_V1,
1616447Ssusans DDI_STRUCTURE_LE_ACC,
162*11236SStephen.Hanson@Sun.COM DDI_STRICTORDER_ACC,
163*11236SStephen.Hanson@Sun.COM DDI_DEFAULT_ACC
1646447Ssusans };
1656447Ssusans
1666447Ssusans
1676447Ssusans /*
1686447Ssusans * ************************************************************************** *
1696447Ssusans * *
1706447Ssusans * common entry points - for loadable kernel modules *
1716447Ssusans * *
1726447Ssusans * ************************************************************************** *
1736447Ssusans */
1746447Ssusans
1756447Ssusans /*
1766447Ssusans * _init - initialize a loadable module
1776447Ssusans * @void
1786447Ssusans *
1796447Ssusans * The driver should perform any one-time resource allocation or data
1806447Ssusans * initialization during driver loading in _init(). For example, the driver
1816447Ssusans * should initialize any mutexes global to the driver in this routine.
1826447Ssusans * The driver should not, however, use _init() to allocate or initialize
1836447Ssusans * anything that has to do with a particular instance of the device.
1846447Ssusans * Per-instance initialization must be done in attach().
1856447Ssusans */
1866447Ssusans int
_init(void)1876447Ssusans _init(void)
1886447Ssusans {
1896447Ssusans int ret;
1906447Ssusans
1916447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
1926447Ssusans
1936447Ssusans ret = ddi_soft_state_init(&megasas_state,
1946447Ssusans sizeof (struct megasas_instance), 0);
1956447Ssusans
1966447Ssusans if (ret != 0) {
1976447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: could not init state"));
1986447Ssusans return (ret);
1996447Ssusans }
2006447Ssusans
2016447Ssusans if ((ret = scsi_hba_init(&modlinkage)) != 0) {
2026447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: could not init scsi hba"));
2036447Ssusans ddi_soft_state_fini(&megasas_state);
2046447Ssusans return (ret);
2056447Ssusans }
2066447Ssusans
2076447Ssusans ret = mod_install(&modlinkage);
2086447Ssusans
2096447Ssusans if (ret != 0) {
2106447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: mod_install failed"));
2116447Ssusans scsi_hba_fini(&modlinkage);
2126447Ssusans ddi_soft_state_fini(&megasas_state);
2136447Ssusans }
2146447Ssusans
2156447Ssusans return (ret);
2166447Ssusans }
2176447Ssusans
2186447Ssusans /*
2196447Ssusans * _info - returns information about a loadable module.
2206447Ssusans * @void
2216447Ssusans *
2226447Ssusans * _info() is called to return module information. This is a typical entry
2236447Ssusans * point that does predefined role. It simply calls mod_info().
2246447Ssusans */
2256447Ssusans int
_info(struct modinfo * modinfop)2266447Ssusans _info(struct modinfo *modinfop)
2276447Ssusans {
2286447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
2296447Ssusans
2306447Ssusans return (mod_info(&modlinkage, modinfop));
2316447Ssusans }
2326447Ssusans
2336447Ssusans /*
2346447Ssusans * _fini - prepare a loadable module for unloading
2356447Ssusans * @void
2366447Ssusans *
2376447Ssusans * In _fini(), the driver should release any resources that were allocated in
2386447Ssusans * _init(). The driver must remove itself from the system module list.
2396447Ssusans */
2406447Ssusans int
_fini(void)2416447Ssusans _fini(void)
2426447Ssusans {
2436447Ssusans int ret;
2446447Ssusans
2456447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
2466447Ssusans
2476447Ssusans if ((ret = mod_remove(&modlinkage)) != 0)
2486447Ssusans return (ret);
2496447Ssusans
2506447Ssusans scsi_hba_fini(&modlinkage);
2516447Ssusans
2526447Ssusans ddi_soft_state_fini(&megasas_state);
2536447Ssusans
2546447Ssusans return (ret);
2556447Ssusans }
2566447Ssusans
2576447Ssusans
2586447Ssusans /*
2596447Ssusans * ************************************************************************** *
2606447Ssusans * *
2616447Ssusans * common entry points - for autoconfiguration *
2626447Ssusans * *
2636447Ssusans * ************************************************************************** *
2646447Ssusans */
2656447Ssusans /*
2666447Ssusans * attach - adds a device to the system as part of initialization
2676447Ssusans * @dip:
2686447Ssusans * @cmd:
2696447Ssusans *
2706447Ssusans * The kernel calls a driver's attach() entry point to attach an instance of
2716447Ssusans * a device (for MegaRAID, it is instance of a controller) or to resume
2726447Ssusans * operation for an instance of a device that has been suspended or has been
2736447Ssusans * shut down by the power management framework
2746447Ssusans * The attach() entry point typically includes the following types of
2756447Ssusans * processing:
2766447Ssusans * - allocate a soft-state structure for the device instance (for MegaRAID,
2776447Ssusans * controller instance)
2786447Ssusans * - initialize per-instance mutexes
2796447Ssusans * - initialize condition variables
2806447Ssusans * - register the device's interrupts (for MegaRAID, controller's interrupts)
2816447Ssusans * - map the registers and memory of the device instance (for MegaRAID,
2826447Ssusans * controller instance)
2836447Ssusans * - create minor device nodes for the device instance (for MegaRAID,
2846447Ssusans * controller instance)
2856447Ssusans * - report that the device instance (for MegaRAID, controller instance) has
2866447Ssusans * attached
2876447Ssusans */
2886447Ssusans static int
megasas_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2896447Ssusans megasas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2906447Ssusans {
2916447Ssusans int instance_no;
2926447Ssusans int nregs;
2936447Ssusans uint8_t added_isr_f = 0;
2946447Ssusans uint8_t added_soft_isr_f = 0;
2956447Ssusans uint8_t create_devctl_node_f = 0;
2966447Ssusans uint8_t create_scsi_node_f = 0;
2976447Ssusans uint8_t create_ioc_node_f = 0;
2986447Ssusans uint8_t tran_alloc_f = 0;
2996447Ssusans uint8_t irq;
3006447Ssusans uint16_t vendor_id;
3016447Ssusans uint16_t device_id;
3026447Ssusans uint16_t subsysvid;
3036447Ssusans uint16_t subsysid;
3046447Ssusans uint16_t command;
3056447Ssusans
3066447Ssusans scsi_hba_tran_t *tran;
3077533SYu.Wu@Sun.COM ddi_dma_attr_t tran_dma_attr;
3086447Ssusans struct megasas_instance *instance;
3096447Ssusans
3106447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
3116447Ssusans
3127562SSusan.Scheufele@Sun.COM /* CONSTCOND */
3137562SSusan.Scheufele@Sun.COM ASSERT(NO_COMPETING_THREADS);
3147562SSusan.Scheufele@Sun.COM
3156447Ssusans instance_no = ddi_get_instance(dip);
3166447Ssusans
3176447Ssusans /*
3186447Ssusans * Since we know that some instantiations of this device can be
3196447Ssusans * plugged into slave-only SBus slots, check to see whether this is
3206447Ssusans * one such.
3216447Ssusans */
3226447Ssusans if (ddi_slaveonly(dip) == DDI_SUCCESS) {
3236447Ssusans con_log(CL_ANN, (CE_WARN,
3246447Ssusans "mega%d: Device in slave-only slot, unused", instance_no));
3256447Ssusans return (DDI_FAILURE);
3266447Ssusans }
3276447Ssusans
3286447Ssusans switch (cmd) {
3296447Ssusans case DDI_ATTACH:
3307193Syw209021 con_log(CL_DLEVEL1, (CE_NOTE, "megasas: DDI_ATTACH"));
3316447Ssusans /* allocate the soft state for the instance */
3326447Ssusans if (ddi_soft_state_zalloc(megasas_state, instance_no)
3336447Ssusans != DDI_SUCCESS) {
3346447Ssusans con_log(CL_ANN, (CE_WARN,
3356447Ssusans "mega%d: Failed to allocate soft state",
3366447Ssusans instance_no));
3376447Ssusans
3386447Ssusans return (DDI_FAILURE);
3396447Ssusans }
3406447Ssusans
3416447Ssusans instance = (struct megasas_instance *)ddi_get_soft_state
3426447Ssusans (megasas_state, instance_no);
3436447Ssusans
3446447Ssusans if (instance == NULL) {
3456447Ssusans con_log(CL_ANN, (CE_WARN,
3466447Ssusans "mega%d: Bad soft state", instance_no));
3476447Ssusans
3486447Ssusans ddi_soft_state_free(megasas_state, instance_no);
3496447Ssusans
3506447Ssusans return (DDI_FAILURE);
3516447Ssusans }
3526447Ssusans
3536447Ssusans bzero((caddr_t)instance,
3546447Ssusans sizeof (struct megasas_instance));
3556447Ssusans
3566447Ssusans instance->func_ptr = kmem_zalloc(
3576447Ssusans sizeof (struct megasas_func_ptr), KM_SLEEP);
3586447Ssusans ASSERT(instance->func_ptr);
3596447Ssusans
3606447Ssusans /* Setup the PCI configuration space handles */
3616447Ssusans if (pci_config_setup(dip, &instance->pci_handle) !=
3626447Ssusans DDI_SUCCESS) {
3636447Ssusans con_log(CL_ANN, (CE_WARN,
3646447Ssusans "mega%d: pci config setup failed ",
3656447Ssusans instance_no));
3666447Ssusans
3676447Ssusans kmem_free(instance->func_ptr,
3686447Ssusans sizeof (struct megasas_func_ptr));
3696447Ssusans ddi_soft_state_free(megasas_state, instance_no);
3706447Ssusans
3716447Ssusans return (DDI_FAILURE);
3726447Ssusans }
3736447Ssusans
3746447Ssusans if (ddi_dev_nregs(dip, &nregs) != DDI_SUCCESS) {
3756447Ssusans con_log(CL_ANN, (CE_WARN,
3766447Ssusans "megaraid: failed to get registers."));
3776447Ssusans
3786447Ssusans pci_config_teardown(&instance->pci_handle);
3796447Ssusans kmem_free(instance->func_ptr,
3806447Ssusans sizeof (struct megasas_func_ptr));
3816447Ssusans ddi_soft_state_free(megasas_state, instance_no);
3826447Ssusans
3836447Ssusans return (DDI_FAILURE);
3846447Ssusans }
3856447Ssusans
3866447Ssusans vendor_id = pci_config_get16(instance->pci_handle,
3876447Ssusans PCI_CONF_VENID);
3886447Ssusans device_id = pci_config_get16(instance->pci_handle,
3896447Ssusans PCI_CONF_DEVID);
3906447Ssusans
3916447Ssusans subsysvid = pci_config_get16(instance->pci_handle,
3926447Ssusans PCI_CONF_SUBVENID);
3936447Ssusans subsysid = pci_config_get16(instance->pci_handle,
3946447Ssusans PCI_CONF_SUBSYSID);
3956447Ssusans
3966447Ssusans pci_config_put16(instance->pci_handle, PCI_CONF_COMM,
3976447Ssusans (pci_config_get16(instance->pci_handle,
3986447Ssusans PCI_CONF_COMM) | PCI_COMM_ME));
3996447Ssusans irq = pci_config_get8(instance->pci_handle,
4006447Ssusans PCI_CONF_ILINE);
4017562SSusan.Scheufele@Sun.COM
4027562SSusan.Scheufele@Sun.COM con_log(CL_DLEVEL1, (CE_CONT, "megasas%d: "
4036447Ssusans "0x%x:0x%x 0x%x:0x%x, irq:%d drv-ver:%s\n",
4046447Ssusans instance_no, vendor_id, device_id, subsysvid,
4057562SSusan.Scheufele@Sun.COM subsysid, irq, MEGASAS_VERSION));
4066447Ssusans
4076447Ssusans /* enable bus-mastering */
4086447Ssusans command = pci_config_get16(instance->pci_handle,
4096447Ssusans PCI_CONF_COMM);
4106447Ssusans
4116447Ssusans if (!(command & PCI_COMM_ME)) {
4126447Ssusans command |= PCI_COMM_ME;
4136447Ssusans
4146447Ssusans pci_config_put16(instance->pci_handle,
4156447Ssusans PCI_CONF_COMM, command);
4166447Ssusans
4177562SSusan.Scheufele@Sun.COM con_log(CL_ANN, (CE_CONT, "megaraid%d: "
4186447Ssusans "enable bus-mastering\n", instance_no));
4196447Ssusans } else {
4207562SSusan.Scheufele@Sun.COM con_log(CL_DLEVEL1, (CE_CONT, "megaraid%d: "
4216447Ssusans "bus-mastering already set\n", instance_no));
4226447Ssusans }
4236447Ssusans
4246447Ssusans /* initialize function pointers */
4256599Ssusans if ((device_id == PCI_DEVICE_ID_LSI_1078) ||
4266599Ssusans (device_id == PCI_DEVICE_ID_LSI_1078DE)) {
4277562SSusan.Scheufele@Sun.COM con_log(CL_DLEVEL1, (CE_CONT, "megasas%d: "
4286599Ssusans "1078R/DE detected\n", instance_no));
4296447Ssusans instance->func_ptr->read_fw_status_reg =
4306447Ssusans read_fw_status_reg_ppc;
4316447Ssusans instance->func_ptr->issue_cmd = issue_cmd_ppc;
4326447Ssusans instance->func_ptr->issue_cmd_in_sync_mode =
4336447Ssusans issue_cmd_in_sync_mode_ppc;
4346447Ssusans instance->func_ptr->issue_cmd_in_poll_mode =
4356447Ssusans issue_cmd_in_poll_mode_ppc;
4366447Ssusans instance->func_ptr->enable_intr =
4376447Ssusans enable_intr_ppc;
4386447Ssusans instance->func_ptr->disable_intr =
4396447Ssusans disable_intr_ppc;
4406447Ssusans instance->func_ptr->intr_ack = intr_ack_ppc;
4416447Ssusans } else {
4427562SSusan.Scheufele@Sun.COM con_log(CL_DLEVEL1, (CE_CONT, "megasas%d: "
4436447Ssusans "1064/8R detected\n", instance_no));
4446447Ssusans instance->func_ptr->read_fw_status_reg =
4456447Ssusans read_fw_status_reg_xscale;
4466447Ssusans instance->func_ptr->issue_cmd =
4476447Ssusans issue_cmd_xscale;
4486447Ssusans instance->func_ptr->issue_cmd_in_sync_mode =
4496447Ssusans issue_cmd_in_sync_mode_xscale;
4506447Ssusans instance->func_ptr->issue_cmd_in_poll_mode =
4516447Ssusans issue_cmd_in_poll_mode_xscale;
4526447Ssusans instance->func_ptr->enable_intr =
4536447Ssusans enable_intr_xscale;
4546447Ssusans instance->func_ptr->disable_intr =
4556447Ssusans disable_intr_xscale;
4566447Ssusans instance->func_ptr->intr_ack =
4576447Ssusans intr_ack_xscale;
4586447Ssusans }
4596447Ssusans
4607562SSusan.Scheufele@Sun.COM instance->baseaddress = pci_config_get32(
4617562SSusan.Scheufele@Sun.COM instance->pci_handle, PCI_CONF_BASE0);
4626447Ssusans instance->baseaddress &= 0x0fffc;
4636447Ssusans
4646447Ssusans instance->dip = dip;
4656447Ssusans instance->vendor_id = vendor_id;
4666447Ssusans instance->device_id = device_id;
4676447Ssusans instance->subsysvid = subsysvid;
4686447Ssusans instance->subsysid = subsysid;
4696447Ssusans
4707533SYu.Wu@Sun.COM /* Initialize FMA */
4717533SYu.Wu@Sun.COM instance->fm_capabilities = ddi_prop_get_int(
4727698SSusan.Scheufele@Sun.COM DDI_DEV_T_ANY, instance->dip, DDI_PROP_DONTPASS,
4737698SSusan.Scheufele@Sun.COM "fm-capable", DDI_FM_EREPORT_CAPABLE |
4747698SSusan.Scheufele@Sun.COM DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE
4757698SSusan.Scheufele@Sun.COM | DDI_FM_ERRCB_CAPABLE);
4767533SYu.Wu@Sun.COM
4777533SYu.Wu@Sun.COM megasas_fm_init(instance);
4787533SYu.Wu@Sun.COM
4796447Ssusans /* setup the mfi based low level driver */
4806447Ssusans if (init_mfi(instance) != DDI_SUCCESS) {
4816447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: "
4826447Ssusans "could not initialize the low level driver"));
4836447Ssusans
4846447Ssusans goto fail_attach;
4856447Ssusans }
4866447Ssusans
4876447Ssusans /*
4886447Ssusans * Allocate the interrupt blocking cookie.
4896447Ssusans * It represents the information the framework
4906447Ssusans * needs to block interrupts. This cookie will
4916447Ssusans * be used by the locks shared accross our ISR.
4926447Ssusans * These locks must be initialized before we
4936447Ssusans * register our ISR.
4946447Ssusans * ddi_add_intr(9F)
4956447Ssusans */
4966447Ssusans if (ddi_get_iblock_cookie(dip, 0,
4976447Ssusans &instance->iblock_cookie) != DDI_SUCCESS) {
4986447Ssusans
4996447Ssusans goto fail_attach;
5006447Ssusans }
5016447Ssusans
5026447Ssusans if (ddi_get_soft_iblock_cookie(dip, DDI_SOFTINT_HIGH,
5036447Ssusans &instance->soft_iblock_cookie) != DDI_SUCCESS) {
5046447Ssusans
5056447Ssusans goto fail_attach;
5066447Ssusans }
5076447Ssusans
5086447Ssusans /*
5096447Ssusans * Initialize the driver mutexes common to
5106447Ssusans * normal/high level isr
5116447Ssusans */
5126447Ssusans if (ddi_intr_hilevel(dip, 0)) {
5136447Ssusans instance->isr_level = HIGH_LEVEL_INTR;
5146447Ssusans mutex_init(&instance->cmd_pool_mtx,
5156447Ssusans "cmd_pool_mtx", MUTEX_DRIVER,
5166447Ssusans instance->soft_iblock_cookie);
5176447Ssusans mutex_init(&instance->cmd_pend_mtx,
5186447Ssusans "cmd_pend_mtx", MUTEX_DRIVER,
5196447Ssusans instance->soft_iblock_cookie);
5206447Ssusans } else {
5216447Ssusans /*
5226447Ssusans * Initialize the driver mutexes
5236447Ssusans * specific to soft-isr
5246447Ssusans */
5256447Ssusans instance->isr_level = NORMAL_LEVEL_INTR;
5266447Ssusans mutex_init(&instance->cmd_pool_mtx,
5276447Ssusans "cmd_pool_mtx", MUTEX_DRIVER,
5286447Ssusans instance->iblock_cookie);
5296447Ssusans mutex_init(&instance->cmd_pend_mtx,
5306447Ssusans "cmd_pend_mtx", MUTEX_DRIVER,
5316447Ssusans instance->iblock_cookie);
5326447Ssusans }
5336447Ssusans
5346447Ssusans mutex_init(&instance->completed_pool_mtx,
5356447Ssusans "completed_pool_mtx", MUTEX_DRIVER,
5366447Ssusans instance->iblock_cookie);
5376447Ssusans mutex_init(&instance->int_cmd_mtx, "int_cmd_mtx",
5386447Ssusans MUTEX_DRIVER, instance->iblock_cookie);
5396447Ssusans mutex_init(&instance->aen_cmd_mtx, "aen_cmd_mtx",
5406447Ssusans MUTEX_DRIVER, instance->iblock_cookie);
5416447Ssusans mutex_init(&instance->abort_cmd_mtx, "abort_cmd_mtx",
5426447Ssusans MUTEX_DRIVER, instance->iblock_cookie);
5436447Ssusans
5446447Ssusans cv_init(&instance->int_cmd_cv, NULL, CV_DRIVER, NULL);
5456447Ssusans cv_init(&instance->abort_cmd_cv, NULL, CV_DRIVER, NULL);
5466447Ssusans
5476447Ssusans INIT_LIST_HEAD(&instance->completed_pool_list);
5486447Ssusans
5496447Ssusans /* Register our isr. */
5506447Ssusans if (ddi_add_intr(dip, 0, NULL, NULL, megasas_isr,
5516447Ssusans (caddr_t)instance) != DDI_SUCCESS) {
5526447Ssusans con_log(CL_ANN, (CE_WARN,
5536447Ssusans " ISR did not register"));
5546447Ssusans
5556447Ssusans goto fail_attach;
5566447Ssusans }
5576447Ssusans
5586447Ssusans added_isr_f = 1;
5596447Ssusans
5606447Ssusans /* Register our soft-isr for highlevel interrupts. */
5616447Ssusans if (instance->isr_level == HIGH_LEVEL_INTR) {
5626447Ssusans if (ddi_add_softintr(dip, DDI_SOFTINT_HIGH,
5636447Ssusans &instance->soft_intr_id, NULL, NULL,
5646447Ssusans megasas_softintr, (caddr_t)instance) !=
5656447Ssusans DDI_SUCCESS) {
5666447Ssusans con_log(CL_ANN, (CE_WARN,
5676447Ssusans " Software ISR did not register"));
5686447Ssusans
5696447Ssusans goto fail_attach;
5706447Ssusans }
5716447Ssusans
5726447Ssusans added_soft_isr_f = 1;
5736447Ssusans }
5746447Ssusans
5756447Ssusans /* Allocate a transport structure */
5766447Ssusans tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
5776447Ssusans
5786447Ssusans if (tran == NULL) {
5796447Ssusans con_log(CL_ANN, (CE_WARN,
5806447Ssusans "scsi_hba_tran_alloc failed"));
5816447Ssusans goto fail_attach;
5826447Ssusans }
5836447Ssusans
5846447Ssusans tran_alloc_f = 1;
5856447Ssusans
5866447Ssusans instance->tran = tran;
5876447Ssusans
5886447Ssusans tran->tran_hba_private = instance;
5896447Ssusans tran->tran_tgt_private = NULL;
5906447Ssusans tran->tran_tgt_init = megasas_tran_tgt_init;
5916447Ssusans tran->tran_tgt_probe = scsi_hba_probe;
5926447Ssusans tran->tran_tgt_free = (void (*)())NULL;
5936447Ssusans tran->tran_init_pkt = megasas_tran_init_pkt;
5946447Ssusans tran->tran_start = megasas_tran_start;
5956447Ssusans tran->tran_abort = megasas_tran_abort;
5966447Ssusans tran->tran_reset = megasas_tran_reset;
5976447Ssusans tran->tran_bus_reset = megasas_tran_bus_reset;
5986447Ssusans tran->tran_getcap = megasas_tran_getcap;
5996447Ssusans tran->tran_setcap = megasas_tran_setcap;
6006447Ssusans tran->tran_destroy_pkt = megasas_tran_destroy_pkt;
6016447Ssusans tran->tran_dmafree = megasas_tran_dmafree;
6026447Ssusans tran->tran_sync_pkt = megasas_tran_sync_pkt;
6036447Ssusans tran->tran_reset_notify = NULL;
6046447Ssusans tran->tran_quiesce = megasas_tran_quiesce;
6056447Ssusans tran->tran_unquiesce = megasas_tran_unquiesce;
6066447Ssusans
6077533SYu.Wu@Sun.COM tran_dma_attr = megasas_generic_dma_attr;
6086447Ssusans tran_dma_attr.dma_attr_sgllen = instance->max_num_sge;
6096447Ssusans
6106447Ssusans /* Attach this instance of the hba */
6116447Ssusans if (scsi_hba_attach_setup(dip, &tran_dma_attr, tran, 0)
6126447Ssusans != DDI_SUCCESS) {
6136447Ssusans con_log(CL_ANN, (CE_WARN,
6146447Ssusans "scsi_hba_attach failed\n"));
6156447Ssusans
6166447Ssusans goto fail_attach;
6176447Ssusans }
6186447Ssusans
6196447Ssusans /* create devctl node for cfgadm command */
6206447Ssusans if (ddi_create_minor_node(dip, "devctl",
6216447Ssusans S_IFCHR, INST2DEVCTL(instance_no),
6226447Ssusans DDI_NT_SCSI_NEXUS, 0) == DDI_FAILURE) {
6236447Ssusans con_log(CL_ANN, (CE_WARN,
6246447Ssusans "megaraid: failed to create devctl node."));
6256447Ssusans
6266447Ssusans goto fail_attach;
6276447Ssusans }
6286447Ssusans
6296447Ssusans create_devctl_node_f = 1;
6306447Ssusans
6316447Ssusans /* create scsi node for cfgadm command */
6326447Ssusans if (ddi_create_minor_node(dip, "scsi", S_IFCHR,
6336447Ssusans INST2SCSI(instance_no),
6346447Ssusans DDI_NT_SCSI_ATTACHMENT_POINT, 0) ==
6356447Ssusans DDI_FAILURE) {
6366447Ssusans con_log(CL_ANN, (CE_WARN,
6376447Ssusans "megaraid: failed to create scsi node."));
6386447Ssusans
6396447Ssusans goto fail_attach;
6406447Ssusans }
6416447Ssusans
6426447Ssusans create_scsi_node_f = 1;
6436447Ssusans
6446447Ssusans (void) sprintf(instance->iocnode, "%d:lsirdctl",
6456447Ssusans instance_no);
6466447Ssusans
6476447Ssusans /*
6486447Ssusans * Create a node for applications
6496447Ssusans * for issuing ioctl to the driver.
6506447Ssusans */
6516447Ssusans if (ddi_create_minor_node(dip, instance->iocnode,
6526447Ssusans S_IFCHR, INST2LSIRDCTL(instance_no),
6536447Ssusans DDI_PSEUDO, 0) == DDI_FAILURE) {
6546447Ssusans con_log(CL_ANN, (CE_WARN,
6556447Ssusans "megaraid: failed to create ioctl node."));
6566447Ssusans
6576447Ssusans goto fail_attach;
6586447Ssusans }
6596447Ssusans
6606447Ssusans create_ioc_node_f = 1;
6616447Ssusans
6626447Ssusans /* enable interrupt */
6636447Ssusans instance->func_ptr->enable_intr(instance);
6646447Ssusans
6656447Ssusans /* initiate AEN */
6666447Ssusans if (start_mfi_aen(instance)) {
6676447Ssusans con_log(CL_ANN, (CE_WARN,
6686447Ssusans "megaraid: failed to initiate AEN."));
6696447Ssusans goto fail_initiate_aen;
6706447Ssusans }
6716447Ssusans
6727193Syw209021 con_log(CL_DLEVEL1, (CE_NOTE,
6736447Ssusans "AEN started for instance %d.", instance_no));
6746447Ssusans
6756447Ssusans /* Finally! We are on the air. */
6766447Ssusans ddi_report_dev(dip);
6777533SYu.Wu@Sun.COM
6787533SYu.Wu@Sun.COM if (megasas_check_acc_handle(instance->regmap_handle) !=
6797533SYu.Wu@Sun.COM DDI_SUCCESS) {
6807533SYu.Wu@Sun.COM goto fail_attach;
6817533SYu.Wu@Sun.COM }
6827533SYu.Wu@Sun.COM if (megasas_check_acc_handle(instance->pci_handle) !=
6837533SYu.Wu@Sun.COM DDI_SUCCESS) {
6847533SYu.Wu@Sun.COM goto fail_attach;
6857533SYu.Wu@Sun.COM }
6866447Ssusans break;
6876447Ssusans case DDI_PM_RESUME:
6886447Ssusans con_log(CL_ANN, (CE_NOTE,
6896447Ssusans "megasas: DDI_PM_RESUME"));
6906447Ssusans break;
6916447Ssusans case DDI_RESUME:
6926447Ssusans con_log(CL_ANN, (CE_NOTE,
6936447Ssusans "megasas: DDI_RESUME"));
6946447Ssusans break;
6956447Ssusans default:
6966447Ssusans con_log(CL_ANN, (CE_WARN,
6976447Ssusans "megasas: invalid attach cmd=%x", cmd));
6986447Ssusans return (DDI_FAILURE);
6996447Ssusans }
7006447Ssusans
7016447Ssusans return (DDI_SUCCESS);
7026447Ssusans
7036447Ssusans fail_initiate_aen:
7046447Ssusans fail_attach:
7056447Ssusans if (create_devctl_node_f) {
7066447Ssusans ddi_remove_minor_node(dip, "devctl");
7076447Ssusans }
7086447Ssusans
7096447Ssusans if (create_scsi_node_f) {
7106447Ssusans ddi_remove_minor_node(dip, "scsi");
7116447Ssusans }
7126447Ssusans
7136447Ssusans if (create_ioc_node_f) {
7146447Ssusans ddi_remove_minor_node(dip, instance->iocnode);
7156447Ssusans }
7166447Ssusans
7176447Ssusans if (tran_alloc_f) {
7186447Ssusans scsi_hba_tran_free(tran);
7196447Ssusans }
7206447Ssusans
7216447Ssusans
7226447Ssusans if (added_soft_isr_f) {
7236447Ssusans ddi_remove_softintr(instance->soft_intr_id);
7246447Ssusans }
7256447Ssusans
7266447Ssusans if (added_isr_f) {
7276447Ssusans ddi_remove_intr(dip, 0, instance->iblock_cookie);
7286447Ssusans }
7296447Ssusans
7307533SYu.Wu@Sun.COM megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
7317533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
7327533SYu.Wu@Sun.COM
7337533SYu.Wu@Sun.COM megasas_fm_fini(instance);
7347533SYu.Wu@Sun.COM
7356447Ssusans pci_config_teardown(&instance->pci_handle);
7366447Ssusans
7376447Ssusans ddi_soft_state_free(megasas_state, instance_no);
7386447Ssusans
7396447Ssusans con_log(CL_ANN, (CE_NOTE,
7406447Ssusans "megasas: return failure from mega_attach\n"));
7416447Ssusans
7426447Ssusans return (DDI_FAILURE);
7436447Ssusans }
7446447Ssusans
7456447Ssusans /*
7466447Ssusans * getinfo - gets device information
7476447Ssusans * @dip:
7486447Ssusans * @cmd:
7496447Ssusans * @arg:
7506447Ssusans * @resultp:
7516447Ssusans *
7526447Ssusans * The system calls getinfo() to obtain configuration information that only
7536447Ssusans * the driver knows. The mapping of minor numbers to device instance is
7546447Ssusans * entirely under the control of the driver. The system sometimes needs to ask
7556447Ssusans * the driver which device a particular dev_t represents.
7566447Ssusans * Given the device number return the devinfo pointer from the scsi_device
7576447Ssusans * structure.
7586447Ssusans */
7596447Ssusans /*ARGSUSED*/
7606447Ssusans static int
megasas_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)7616447Ssusans megasas_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
7626447Ssusans {
7636447Ssusans int rval;
7646447Ssusans int megasas_minor = getminor((dev_t)arg);
7656447Ssusans
7666447Ssusans struct megasas_instance *instance;
7676447Ssusans
7686447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
7696447Ssusans
7706447Ssusans switch (cmd) {
7716447Ssusans case DDI_INFO_DEVT2DEVINFO:
7726447Ssusans instance = (struct megasas_instance *)
7736447Ssusans ddi_get_soft_state(megasas_state,
7746447Ssusans MINOR2INST(megasas_minor));
7756447Ssusans
7766447Ssusans if (instance == NULL) {
7776447Ssusans *resultp = NULL;
7786447Ssusans rval = DDI_FAILURE;
7796447Ssusans } else {
7806447Ssusans *resultp = instance->dip;
7816447Ssusans rval = DDI_SUCCESS;
7826447Ssusans }
7836447Ssusans break;
7846447Ssusans case DDI_INFO_DEVT2INSTANCE:
7856447Ssusans *resultp = (void *)instance;
7866447Ssusans rval = DDI_SUCCESS;
7876447Ssusans break;
7886447Ssusans default:
7896447Ssusans *resultp = NULL;
7906447Ssusans rval = DDI_FAILURE;
7916447Ssusans }
7926447Ssusans
7936447Ssusans return (rval);
7946447Ssusans }
7956447Ssusans
7966447Ssusans /*
7976447Ssusans * detach - detaches a device from the system
7986447Ssusans * @dip: pointer to the device's dev_info structure
7996447Ssusans * @cmd: type of detach
8006447Ssusans *
8016447Ssusans * A driver's detach() entry point is called to detach an instance of a device
8026447Ssusans * that is bound to the driver. The entry point is called with the instance of
8036447Ssusans * the device node to be detached and with DDI_DETACH, which is specified as
8046447Ssusans * the cmd argument to the entry point.
8056447Ssusans * This routine is called during driver unload. We free all the allocated
8066447Ssusans * resources and call the corresponding LLD so that it can also release all
8076447Ssusans * its resources.
8086447Ssusans */
8096447Ssusans static int
megasas_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)8106447Ssusans megasas_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8116447Ssusans {
8126447Ssusans int instance_no;
8136447Ssusans
8146447Ssusans struct megasas_instance *instance;
8156447Ssusans
8166447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
8176447Ssusans
8187562SSusan.Scheufele@Sun.COM /* CONSTCOND */
8197562SSusan.Scheufele@Sun.COM ASSERT(NO_COMPETING_THREADS);
8207562SSusan.Scheufele@Sun.COM
8216447Ssusans instance_no = ddi_get_instance(dip);
8226447Ssusans
8236447Ssusans instance = (struct megasas_instance *)ddi_get_soft_state(megasas_state,
8246447Ssusans instance_no);
8256447Ssusans
8266447Ssusans if (!instance) {
8276447Ssusans con_log(CL_ANN, (CE_WARN,
8286447Ssusans "megasas:%d could not get instance in detach",
8296447Ssusans instance_no));
8306447Ssusans
8316447Ssusans return (DDI_FAILURE);
8326447Ssusans }
8336447Ssusans
8346447Ssusans con_log(CL_ANN, (CE_NOTE,
8357562SSusan.Scheufele@Sun.COM "megasas%d: detaching device 0x%4x:0x%4x:0x%4x:0x%4x\n",
8367562SSusan.Scheufele@Sun.COM instance_no, instance->vendor_id, instance->device_id,
8377562SSusan.Scheufele@Sun.COM instance->subsysvid, instance->subsysid));
8386447Ssusans
8396447Ssusans switch (cmd) {
8406447Ssusans case DDI_DETACH:
8416447Ssusans con_log(CL_ANN, (CE_NOTE,
8426447Ssusans "megasas_detach: DDI_DETACH\n"));
8436447Ssusans
8446447Ssusans if (scsi_hba_detach(dip) != DDI_SUCCESS) {
8456447Ssusans con_log(CL_ANN, (CE_WARN,
8466447Ssusans "megasas:%d failed to detach",
8476447Ssusans instance_no));
8486447Ssusans
8496447Ssusans return (DDI_FAILURE);
8506447Ssusans }
8516447Ssusans
8526447Ssusans scsi_hba_tran_free(instance->tran);
8536447Ssusans
8546447Ssusans if (abort_aen_cmd(instance, instance->aen_cmd)) {
8556447Ssusans con_log(CL_ANN, (CE_WARN, "megasas_detach: "
8566447Ssusans "failed to abort prevous AEN command\n"));
8576447Ssusans
8586447Ssusans return (DDI_FAILURE);
8596447Ssusans }
8606447Ssusans
8616447Ssusans instance->func_ptr->disable_intr(instance);
8626447Ssusans
8636447Ssusans if (instance->isr_level == HIGH_LEVEL_INTR) {
8646447Ssusans ddi_remove_softintr(instance->soft_intr_id);
8656447Ssusans }
8666447Ssusans
8676447Ssusans ddi_remove_intr(dip, 0, instance->iblock_cookie);
8686447Ssusans
8696447Ssusans free_space_for_mfi(instance);
8706447Ssusans
8717533SYu.Wu@Sun.COM megasas_fm_fini(instance);
8727533SYu.Wu@Sun.COM
8736447Ssusans pci_config_teardown(&instance->pci_handle);
8746447Ssusans
8756447Ssusans kmem_free(instance->func_ptr,
8766447Ssusans sizeof (struct megasas_func_ptr));
8776447Ssusans
8786447Ssusans ddi_soft_state_free(megasas_state, instance_no);
8796447Ssusans break;
8806447Ssusans case DDI_PM_SUSPEND:
8816447Ssusans con_log(CL_ANN, (CE_NOTE,
8826447Ssusans "megasas_detach: DDI_PM_SUSPEND\n"));
8836447Ssusans
8846447Ssusans break;
8856447Ssusans case DDI_SUSPEND:
8866447Ssusans con_log(CL_ANN, (CE_NOTE,
8876447Ssusans "megasas_detach: DDI_SUSPEND\n"));
8886447Ssusans
8896447Ssusans break;
8906447Ssusans default:
8916447Ssusans con_log(CL_ANN, (CE_WARN,
8926447Ssusans "invalid detach command:0x%x", cmd));
8936447Ssusans return (DDI_FAILURE);
8946447Ssusans }
8956447Ssusans
8966447Ssusans return (DDI_SUCCESS);
8976447Ssusans }
8986447Ssusans
8996447Ssusans /*
9006447Ssusans * ************************************************************************** *
9016447Ssusans * *
9026447Ssusans * common entry points - for character driver types *
9036447Ssusans * *
9046447Ssusans * ************************************************************************** *
9056447Ssusans */
9066447Ssusans /*
9076447Ssusans * open - gets access to a device
9086447Ssusans * @dev:
9096447Ssusans * @openflags:
9106447Ssusans * @otyp:
9116447Ssusans * @credp:
9126447Ssusans *
9136447Ssusans * Access to a device by one or more application programs is controlled
9146447Ssusans * through the open() and close() entry points. The primary function of
9156447Ssusans * open() is to verify that the open request is allowed.
9166447Ssusans */
9176447Ssusans static int
megasas_open(dev_t * dev,int openflags,int otyp,cred_t * credp)9186447Ssusans megasas_open(dev_t *dev, int openflags, int otyp, cred_t *credp)
9196447Ssusans {
9206447Ssusans int rval = 0;
9216447Ssusans
9226447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
9236447Ssusans
9246447Ssusans /* Check root permissions */
9256447Ssusans if (drv_priv(credp) != 0) {
9266447Ssusans con_log(CL_ANN, (CE_WARN,
9276447Ssusans "megaraid: Non-root ioctl access tried!"));
9286447Ssusans return (EPERM);
9296447Ssusans }
9306447Ssusans
9316447Ssusans /* Verify we are being opened as a character device */
9326447Ssusans if (otyp != OTYP_CHR) {
9336447Ssusans con_log(CL_ANN, (CE_WARN,
9346447Ssusans "megaraid: ioctl node must be a char node\n"));
9356447Ssusans return (EINVAL);
9366447Ssusans }
9376447Ssusans
9386447Ssusans if (ddi_get_soft_state(megasas_state, MINOR2INST(getminor(*dev)))
9396447Ssusans == NULL) {
9406447Ssusans return (ENXIO);
9416447Ssusans }
9426447Ssusans
9436447Ssusans if (scsi_hba_open) {
9446447Ssusans rval = scsi_hba_open(dev, openflags, otyp, credp);
9456447Ssusans }
9466447Ssusans
9476447Ssusans return (rval);
9486447Ssusans }
9496447Ssusans
9506447Ssusans /*
9516447Ssusans * close - gives up access to a device
9526447Ssusans * @dev:
9536447Ssusans * @openflags:
9546447Ssusans * @otyp:
9556447Ssusans * @credp:
9566447Ssusans *
9576447Ssusans * close() should perform any cleanup necessary to finish using the minor
9586447Ssusans * device, and prepare the device (and driver) to be opened again.
9596447Ssusans */
9606447Ssusans static int
megasas_close(dev_t dev,int openflags,int otyp,cred_t * credp)9616447Ssusans megasas_close(dev_t dev, int openflags, int otyp, cred_t *credp)
9626447Ssusans {
9636447Ssusans int rval = 0;
9646447Ssusans
9656447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
9666447Ssusans
9676447Ssusans /* no need for locks! */
9686447Ssusans
9696447Ssusans if (scsi_hba_close) {
9706447Ssusans rval = scsi_hba_close(dev, openflags, otyp, credp);
9716447Ssusans }
9726447Ssusans
9736447Ssusans return (rval);
9746447Ssusans }
9756447Ssusans
9766447Ssusans /*
9776447Ssusans * ioctl - performs a range of I/O commands for character drivers
9786447Ssusans * @dev:
9796447Ssusans * @cmd:
9806447Ssusans * @arg:
9816447Ssusans * @mode:
9826447Ssusans * @credp:
9836447Ssusans * @rvalp:
9846447Ssusans *
9856447Ssusans * ioctl() routine must make sure that user data is copied into or out of the
9866447Ssusans * kernel address space explicitly using copyin(), copyout(), ddi_copyin(),
9876447Ssusans * and ddi_copyout(), as appropriate.
9886447Ssusans * This is a wrapper routine to serialize access to the actual ioctl routine.
9896447Ssusans * ioctl() should return 0 on success, or the appropriate error number. The
9906447Ssusans * driver may also set the value returned to the calling process through rvalp.
9916447Ssusans */
9926447Ssusans static int
megasas_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)9936447Ssusans megasas_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
9946447Ssusans int *rvalp)
9956447Ssusans {
9966447Ssusans int rval = 0;
9976447Ssusans
9986447Ssusans struct megasas_instance *instance;
9996447Ssusans struct megasas_ioctl ioctl;
10006447Ssusans struct megasas_aen aen;
10016447Ssusans
10026447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
10036447Ssusans
10046447Ssusans instance = ddi_get_soft_state(megasas_state, MINOR2INST(getminor(dev)));
10056447Ssusans
10066447Ssusans if (instance == NULL) {
10076447Ssusans /* invalid minor number */
10086447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: adapter not found."));
10096447Ssusans return (ENXIO);
10106447Ssusans }
10116447Ssusans
10126447Ssusans switch ((uint_t)cmd) {
10136447Ssusans case MEGASAS_IOCTL_FIRMWARE:
10146447Ssusans if (ddi_copyin((void *) arg, &ioctl,
10156447Ssusans sizeof (struct megasas_ioctl), mode)) {
10166447Ssusans con_log(CL_ANN, (CE_WARN, "megasas_ioctl: "
10176447Ssusans "ERROR IOCTL copyin"));
10186447Ssusans return (EFAULT);
10196447Ssusans }
10206447Ssusans
10216447Ssusans if (ioctl.control_code == MR_DRIVER_IOCTL_COMMON) {
10226447Ssusans rval = handle_drv_ioctl(instance, &ioctl, mode);
10236447Ssusans } else {
10246447Ssusans rval = handle_mfi_ioctl(instance, &ioctl, mode);
10256447Ssusans }
10266447Ssusans
10276447Ssusans if (ddi_copyout((void *) &ioctl, (void *)arg,
10286447Ssusans (sizeof (struct megasas_ioctl) - 1), mode)) {
10296447Ssusans con_log(CL_ANN, (CE_WARN,
10306447Ssusans "megasas_ioctl: copy_to_user failed\n"));
10316447Ssusans rval = 1;
10326447Ssusans }
10336447Ssusans
10346447Ssusans break;
10356447Ssusans case MEGASAS_IOCTL_AEN:
10366447Ssusans if (ddi_copyin((void *) arg, &aen,
10376447Ssusans sizeof (struct megasas_aen), mode)) {
10386447Ssusans con_log(CL_ANN, (CE_WARN,
10396447Ssusans "megasas_ioctl: ERROR AEN copyin"));
10406447Ssusans return (EFAULT);
10416447Ssusans }
10426447Ssusans
10436447Ssusans rval = handle_mfi_aen(instance, &aen);
10446447Ssusans
10456447Ssusans if (ddi_copyout((void *) &aen, (void *)arg,
10466447Ssusans sizeof (struct megasas_aen), mode)) {
10476447Ssusans con_log(CL_ANN, (CE_WARN,
10486447Ssusans "megasas_ioctl: copy_to_user failed\n"));
10496447Ssusans rval = 1;
10506447Ssusans }
10516447Ssusans
10526447Ssusans break;
10536447Ssusans default:
10547193Syw209021 rval = scsi_hba_ioctl(dev, cmd, arg,
10557193Syw209021 mode, credp, rvalp);
10567193Syw209021
10577193Syw209021 con_log(CL_DLEVEL1, (CE_NOTE, "megasas_ioctl: "
10587193Syw209021 "scsi_hba_ioctl called, ret = %x.", rval));
10596447Ssusans }
10606447Ssusans
10616447Ssusans return (rval);
10626447Ssusans }
10636447Ssusans
10646447Ssusans /*
10656447Ssusans * ************************************************************************** *
10666447Ssusans * *
10676447Ssusans * common entry points - for block driver types *
10686447Ssusans * *
10696447Ssusans * ************************************************************************** *
10706447Ssusans */
10716447Ssusans /*
10726447Ssusans * reset - TBD
10736447Ssusans * @dip:
10746447Ssusans * @cmd:
10756447Ssusans *
10766447Ssusans * TBD
10776447Ssusans */
10786447Ssusans /*ARGSUSED*/
10796447Ssusans static int
megasas_reset(dev_info_t * dip,ddi_reset_cmd_t cmd)10806447Ssusans megasas_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
10816447Ssusans {
10826447Ssusans int instance_no;
10836447Ssusans
10846447Ssusans struct megasas_instance *instance;
10856447Ssusans
10866447Ssusans instance_no = ddi_get_instance(dip);
10876447Ssusans instance = (struct megasas_instance *)ddi_get_soft_state
10886447Ssusans (megasas_state, instance_no);
10896447Ssusans
10906447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
10916447Ssusans
10926447Ssusans if (!instance) {
10936447Ssusans con_log(CL_ANN, (CE_WARN,
10946447Ssusans "megaraid:%d could not get adapter in reset",
10956447Ssusans instance_no));
10966447Ssusans return (DDI_FAILURE);
10976447Ssusans }
10986447Ssusans
10996447Ssusans con_log(CL_ANN, (CE_NOTE, "flushing cache for instance %d ..",
11006447Ssusans instance_no));
11016447Ssusans
11026447Ssusans flush_cache(instance);
11036447Ssusans
11046447Ssusans return (DDI_SUCCESS);
11056447Ssusans }
11066447Ssusans
11076447Ssusans
11086447Ssusans /*
11096447Ssusans * ************************************************************************** *
11106447Ssusans * *
11116447Ssusans * entry points (SCSI HBA) *
11126447Ssusans * *
11136447Ssusans * ************************************************************************** *
11146447Ssusans */
11156447Ssusans /*
11166447Ssusans * tran_tgt_init - initialize a target device instance
11176447Ssusans * @hba_dip:
11186447Ssusans * @tgt_dip:
11196447Ssusans * @tran:
11206447Ssusans * @sd:
11216447Ssusans *
11226447Ssusans * The tran_tgt_init() entry point enables the HBA to allocate and initialize
11236447Ssusans * any per-target resources. tran_tgt_init() also enables the HBA to qualify
11246447Ssusans * the device's address as valid and supportable for that particular HBA.
11256447Ssusans * By returning DDI_FAILURE, the instance of the target driver for that device
11266447Ssusans * is not probed or attached.
11276447Ssusans */
11286447Ssusans /*ARGSUSED*/
11296447Ssusans 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)11306447Ssusans megasas_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
11316447Ssusans scsi_hba_tran_t *tran, struct scsi_device *sd)
11326447Ssusans {
11336447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
11346447Ssusans
11356447Ssusans return (DDI_SUCCESS);
11366447Ssusans }
11376447Ssusans
11386447Ssusans /*
11396447Ssusans * tran_init_pkt - allocate & initialize a scsi_pkt structure
11406447Ssusans * @ap:
11416447Ssusans * @pkt:
11426447Ssusans * @bp:
11436447Ssusans * @cmdlen:
11446447Ssusans * @statuslen:
11456447Ssusans * @tgtlen:
11466447Ssusans * @flags:
11476447Ssusans * @callback:
11486447Ssusans *
11496447Ssusans * The tran_init_pkt() entry point allocates and initializes a scsi_pkt
11506447Ssusans * structure and DMA resources for a target driver request. The
11516447Ssusans * tran_init_pkt() entry point is called when the target driver calls the
11526447Ssusans * SCSA function scsi_init_pkt(). Each call of the tran_init_pkt() entry point
11536447Ssusans * is a request to perform one or more of three possible services:
11546447Ssusans * - allocation and initialization of a scsi_pkt structure
11556447Ssusans * - allocation of DMA resources for data transfer
11566447Ssusans * - reallocation of DMA resources for the next portion of the data transfer
11576447Ssusans */
11586447Ssusans 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)11596447Ssusans megasas_tran_init_pkt(struct scsi_address *ap, register struct scsi_pkt *pkt,
11606447Ssusans struct buf *bp, int cmdlen, int statuslen, int tgtlen,
11616447Ssusans int flags, int (*callback)(), caddr_t arg)
11626447Ssusans {
11636447Ssusans struct scsa_cmd *acmd;
11646447Ssusans struct megasas_instance *instance;
11656447Ssusans struct scsi_pkt *new_pkt;
11666447Ssusans
11676447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
11686447Ssusans
11696447Ssusans instance = ADDR2MEGA(ap);
11706447Ssusans
11716447Ssusans /* step #1 : pkt allocation */
11726447Ssusans if (pkt == NULL) {
11736447Ssusans pkt = scsi_hba_pkt_alloc(instance->dip, ap, cmdlen, statuslen,
11746447Ssusans tgtlen, sizeof (struct scsa_cmd), callback, arg);
11756447Ssusans if (pkt == NULL) {
11766447Ssusans return (NULL);
11776447Ssusans }
11786447Ssusans
11796447Ssusans acmd = PKT2CMD(pkt);
11806447Ssusans
11816447Ssusans /*
11826447Ssusans * Initialize the new pkt - we redundantly initialize
11836447Ssusans * all the fields for illustrative purposes.
11846447Ssusans */
11856447Ssusans acmd->cmd_pkt = pkt;
11866447Ssusans acmd->cmd_flags = 0;
11876447Ssusans acmd->cmd_scblen = statuslen;
11886447Ssusans acmd->cmd_cdblen = cmdlen;
11896447Ssusans acmd->cmd_dmahandle = NULL;
11906447Ssusans acmd->cmd_ncookies = 0;
11916447Ssusans acmd->cmd_cookie = 0;
11926447Ssusans acmd->cmd_cookiecnt = 0;
11936447Ssusans acmd->cmd_nwin = 0;
11946447Ssusans
11956447Ssusans pkt->pkt_address = *ap;
11966447Ssusans pkt->pkt_comp = (void (*)())NULL;
11976447Ssusans pkt->pkt_flags = 0;
11986447Ssusans pkt->pkt_time = 0;
11996447Ssusans pkt->pkt_resid = 0;
12006447Ssusans pkt->pkt_state = 0;
12016447Ssusans pkt->pkt_statistics = 0;
12026447Ssusans pkt->pkt_reason = 0;
12036447Ssusans new_pkt = pkt;
12046447Ssusans } else {
12056447Ssusans acmd = PKT2CMD(pkt);
12066447Ssusans new_pkt = NULL;
12076447Ssusans }
12086447Ssusans
12096447Ssusans /* step #2 : dma allocation/move */
12106447Ssusans if (bp && bp->b_bcount != 0) {
12116447Ssusans if (acmd->cmd_dmahandle == NULL) {
12126447Ssusans if (megasas_dma_alloc(instance, pkt, bp, flags,
12136447Ssusans callback) == -1) {
12146447Ssusans if (new_pkt) {
12156447Ssusans scsi_hba_pkt_free(ap, new_pkt);
12166447Ssusans }
12176447Ssusans
12186447Ssusans return ((struct scsi_pkt *)NULL);
12196447Ssusans }
12206447Ssusans } else {
12216447Ssusans if (megasas_dma_move(instance, pkt, bp) == -1) {
12226447Ssusans return ((struct scsi_pkt *)NULL);
12236447Ssusans }
12246447Ssusans }
12256447Ssusans }
12266447Ssusans
12276447Ssusans return (pkt);
12286447Ssusans }
12296447Ssusans
12306447Ssusans /*
12316447Ssusans * tran_start - transport a SCSI command to the addressed target
12326447Ssusans * @ap:
12336447Ssusans * @pkt:
12346447Ssusans *
12356447Ssusans * The tran_start() entry point for a SCSI HBA driver is called to transport a
12366447Ssusans * SCSI command to the addressed target. The SCSI command is described
12376447Ssusans * entirely within the scsi_pkt structure, which the target driver allocated
12386447Ssusans * through the HBA driver's tran_init_pkt() entry point. If the command
12396447Ssusans * involves a data transfer, DMA resources must also have been allocated for
12406447Ssusans * the scsi_pkt structure.
12416447Ssusans *
12426447Ssusans * Return Values :
12436447Ssusans * TRAN_BUSY - request queue is full, no more free scbs
12446447Ssusans * TRAN_ACCEPT - pkt has been submitted to the instance
12456447Ssusans */
12466447Ssusans static int
megasas_tran_start(struct scsi_address * ap,register struct scsi_pkt * pkt)12476447Ssusans megasas_tran_start(struct scsi_address *ap, register struct scsi_pkt *pkt)
12486447Ssusans {
12496447Ssusans uchar_t cmd_done = 0;
12506447Ssusans
12516447Ssusans struct megasas_instance *instance = ADDR2MEGA(ap);
12526447Ssusans struct megasas_cmd *cmd;
12536447Ssusans
12546447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d:SCSI CDB[0]=0x%x",
12556447Ssusans __func__, __LINE__, pkt->pkt_cdbp[0]));
12566447Ssusans
12576447Ssusans pkt->pkt_reason = CMD_CMPLT;
12587193Syw209021 *pkt->pkt_scbp = STATUS_GOOD; /* clear arq scsi_status */
12596447Ssusans
12606447Ssusans cmd = build_cmd(instance, ap, pkt, &cmd_done);
12616447Ssusans
12626447Ssusans /*
12636447Ssusans * Check if the command is already completed by the mega_build_cmd()
12646447Ssusans * routine. In which case the busy_flag would be clear and scb will be
12656447Ssusans * NULL and appropriate reason provided in pkt_reason field
12666447Ssusans */
12676447Ssusans if (cmd_done) {
12689106SSrivijitha.Dugganapalli@Sun.COM if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
12699106SSrivijitha.Dugganapalli@Sun.COM scsi_hba_pkt_comp(pkt);
12706447Ssusans }
12717193Syw209021 pkt->pkt_reason = CMD_CMPLT;
12727193Syw209021 pkt->pkt_scbp[0] = STATUS_GOOD;
12737193Syw209021 pkt->pkt_state |= STATE_GOT_BUS | STATE_GOT_TARGET
12747193Syw209021 | STATE_SENT_CMD;
12756447Ssusans return (TRAN_ACCEPT);
12766447Ssusans }
12776447Ssusans
12786447Ssusans if (cmd == NULL) {
12796447Ssusans return (TRAN_BUSY);
12806447Ssusans }
12816447Ssusans
12826447Ssusans if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
12836447Ssusans if (instance->fw_outstanding > instance->max_fw_cmds) {
12846447Ssusans con_log(CL_ANN, (CE_CONT, "megasas:Firmware busy"));
12856447Ssusans return_mfi_pkt(instance, cmd);
12866447Ssusans return (TRAN_BUSY);
12876447Ssusans }
12886447Ssusans
12896447Ssusans /* Syncronize the Cmd frame for the controller */
12906447Ssusans (void) ddi_dma_sync(cmd->frame_dma_obj.dma_handle, 0, 0,
12916447Ssusans DDI_DMA_SYNC_FORDEV);
12926447Ssusans
12936447Ssusans instance->func_ptr->issue_cmd(cmd, instance);
12946447Ssusans
12956447Ssusans } else {
12966447Ssusans struct megasas_header *hdr = &cmd->frame->hdr;
12976447Ssusans
12986447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
12996447Ssusans
13006485Syd196099 instance->func_ptr-> issue_cmd_in_poll_mode(instance, cmd);
13016447Ssusans
13026447Ssusans pkt->pkt_reason = CMD_CMPLT;
13036447Ssusans pkt->pkt_statistics = 0;
13046447Ssusans pkt->pkt_state |= STATE_XFERRED_DATA | STATE_GOT_STATUS;
13056447Ssusans
13066447Ssusans switch (hdr->cmd_status) {
13076447Ssusans case MFI_STAT_OK:
13086447Ssusans pkt->pkt_scbp[0] = STATUS_GOOD;
13096447Ssusans break;
13106447Ssusans
13116447Ssusans case MFI_STAT_SCSI_DONE_WITH_ERROR:
13126447Ssusans
13137193Syw209021 pkt->pkt_reason = CMD_CMPLT;
13147193Syw209021 pkt->pkt_statistics = 0;
13156447Ssusans
13166447Ssusans ((struct scsi_status *)pkt->pkt_scbp)->sts_chk = 1;
13176447Ssusans break;
13186447Ssusans
13196447Ssusans case MFI_STAT_DEVICE_NOT_FOUND:
13206447Ssusans pkt->pkt_reason = CMD_DEV_GONE;
13216447Ssusans pkt->pkt_statistics = STAT_DISCON;
13226447Ssusans break;
13236447Ssusans
13246447Ssusans default:
13256447Ssusans ((struct scsi_status *)pkt->pkt_scbp)->sts_busy = 1;
13266447Ssusans }
13276447Ssusans
13286447Ssusans return_mfi_pkt(instance, cmd);
13297533SYu.Wu@Sun.COM (void) megasas_common_check(instance, cmd);
13306447Ssusans
13319106SSrivijitha.Dugganapalli@Sun.COM scsi_hba_pkt_comp(pkt);
13326447Ssusans
13336447Ssusans }
13346447Ssusans
13356447Ssusans return (TRAN_ACCEPT);
13366447Ssusans }
13376447Ssusans
13386447Ssusans /*
13396447Ssusans * tran_abort - Abort any commands that are currently in transport
13406447Ssusans * @ap:
13416447Ssusans * @pkt:
13426447Ssusans *
13436447Ssusans * The tran_abort() entry point for a SCSI HBA driver is called to abort any
13446447Ssusans * commands that are currently in transport for a particular target. This entry
13456447Ssusans * point is called when a target driver calls scsi_abort(). The tran_abort()
13466447Ssusans * entry point should attempt to abort the command denoted by the pkt
13476447Ssusans * parameter. If the pkt parameter is NULL, tran_abort() should attempt to
13487562SSusan.Scheufele@Sun.COM * abort all outstanding commands in the transport layer for the particular
13496447Ssusans * target or logical unit.
13506447Ssusans */
13516447Ssusans /*ARGSUSED*/
13526447Ssusans static int
megasas_tran_abort(struct scsi_address * ap,struct scsi_pkt * pkt)13536447Ssusans megasas_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
13546447Ssusans {
13556447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
13566447Ssusans
13576447Ssusans /* aborting command not supported by H/W */
13586447Ssusans
13596447Ssusans return (DDI_FAILURE);
13606447Ssusans }
13616447Ssusans
13626447Ssusans /*
13636447Ssusans * tran_reset - reset either the SCSI bus or target
13646447Ssusans * @ap:
13656447Ssusans * @level:
13666447Ssusans *
13676447Ssusans * The tran_reset() entry point for a SCSI HBA driver is called to reset either
13686447Ssusans * the SCSI bus or a particular SCSI target device. This entry point is called
13696447Ssusans * when a target driver calls scsi_reset(). The tran_reset() entry point must
13706447Ssusans * reset the SCSI bus if level is RESET_ALL. If level is RESET_TARGET, just the
13716447Ssusans * particular target or logical unit must be reset.
13726447Ssusans */
13736447Ssusans /*ARGSUSED*/
13746447Ssusans static int
megasas_tran_reset(struct scsi_address * ap,int level)13756447Ssusans megasas_tran_reset(struct scsi_address *ap, int level)
13766447Ssusans {
13776447Ssusans struct megasas_instance *instance = ADDR2MEGA(ap);
13786447Ssusans
13796447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
13806447Ssusans
13816447Ssusans if (wait_for_outstanding(instance)) {
13826447Ssusans return (DDI_FAILURE);
13836447Ssusans } else {
13846447Ssusans return (DDI_SUCCESS);
13856447Ssusans }
13866447Ssusans }
13876447Ssusans
13886447Ssusans /*
13896447Ssusans * tran_bus_reset - reset the SCSI bus
13906447Ssusans * @dip:
13916447Ssusans * @level:
13926447Ssusans *
13936447Ssusans * The tran_bus_reset() vector in the scsi_hba_tran structure should be
13946447Ssusans * initialized during the HBA driver's attach(). The vector should point to
13956447Ssusans * an HBA entry point that is to be called when a user initiates a bus reset.
13966447Ssusans * Implementation is hardware specific. If the HBA driver cannot reset the
13976447Ssusans * SCSI bus without affecting the targets, the driver should fail RESET_BUS
13986447Ssusans * or not initialize this vector.
13996447Ssusans */
14006447Ssusans /*ARGSUSED*/
14016447Ssusans static int
megasas_tran_bus_reset(dev_info_t * dip,int level)14026447Ssusans megasas_tran_bus_reset(dev_info_t *dip, int level)
14036447Ssusans {
14046447Ssusans int instance_no = ddi_get_instance(dip);
14056447Ssusans
14066447Ssusans struct megasas_instance *instance = ddi_get_soft_state(megasas_state,
14076447Ssusans instance_no);
14086447Ssusans
14096447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
14106447Ssusans
14116447Ssusans if (wait_for_outstanding(instance)) {
14126447Ssusans return (DDI_FAILURE);
14136447Ssusans } else {
14146447Ssusans return (DDI_SUCCESS);
14156447Ssusans }
14166447Ssusans }
14176447Ssusans
14186447Ssusans /*
14196447Ssusans * tran_getcap - get one of a set of SCSA-defined capabilities
14206447Ssusans * @ap:
14216447Ssusans * @cap:
14226447Ssusans * @whom:
14236447Ssusans *
14246447Ssusans * The target driver can request the current setting of the capability for a
14256447Ssusans * particular target by setting the whom parameter to nonzero. A whom value of
14266447Ssusans * zero indicates a request for the current setting of the general capability
14276447Ssusans * for the SCSI bus or for adapter hardware. The tran_getcap() should return -1
14286447Ssusans * for undefined capabilities or the current value of the requested capability.
14296447Ssusans */
14306447Ssusans /*ARGSUSED*/
14316447Ssusans static int
megasas_tran_getcap(struct scsi_address * ap,char * cap,int whom)14326447Ssusans megasas_tran_getcap(struct scsi_address *ap, char *cap, int whom)
14336447Ssusans {
14346447Ssusans int rval = 0;
14356447Ssusans
14366447Ssusans struct megasas_instance *instance = ADDR2MEGA(ap);
14376447Ssusans
14386447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
14396447Ssusans
14406447Ssusans /* we do allow inquiring about capabilities for other targets */
14416447Ssusans if (cap == NULL) {
14426447Ssusans return (-1);
14436447Ssusans }
14446447Ssusans
14456447Ssusans switch (scsi_hba_lookup_capstr(cap)) {
14466447Ssusans case SCSI_CAP_DMA_MAX:
14476447Ssusans /* Limit to 16MB max transfer */
14486447Ssusans rval = megasas_max_cap_maxxfer;
14496447Ssusans break;
14506447Ssusans case SCSI_CAP_MSG_OUT:
14516447Ssusans rval = 1;
14526447Ssusans break;
14536447Ssusans case SCSI_CAP_DISCONNECT:
14546447Ssusans rval = 0;
14556447Ssusans break;
14566447Ssusans case SCSI_CAP_SYNCHRONOUS:
14576447Ssusans rval = 0;
14586447Ssusans break;
14596447Ssusans case SCSI_CAP_WIDE_XFER:
14606447Ssusans rval = 1;
14616447Ssusans break;
14626447Ssusans case SCSI_CAP_TAGGED_QING:
14636447Ssusans rval = 1;
14646447Ssusans break;
14656447Ssusans case SCSI_CAP_UNTAGGED_QING:
14666447Ssusans rval = 1;
14676447Ssusans break;
14686447Ssusans case SCSI_CAP_PARITY:
14696447Ssusans rval = 1;
14706447Ssusans break;
14716447Ssusans case SCSI_CAP_INITIATOR_ID:
14726447Ssusans rval = instance->init_id;
14736447Ssusans break;
14746447Ssusans case SCSI_CAP_ARQ:
14756447Ssusans rval = 1;
14766447Ssusans break;
14776447Ssusans case SCSI_CAP_LINKED_CMDS:
14786447Ssusans rval = 0;
14796447Ssusans break;
14806447Ssusans case SCSI_CAP_RESET_NOTIFICATION:
14816447Ssusans rval = 1;
14826447Ssusans break;
14836447Ssusans case SCSI_CAP_GEOMETRY:
14846447Ssusans rval = -1;
14856447Ssusans
14866447Ssusans break;
14876447Ssusans default:
14886447Ssusans con_log(CL_DLEVEL2, (CE_NOTE, "Default cap coming 0x%x",
14896447Ssusans scsi_hba_lookup_capstr(cap)));
14906447Ssusans rval = -1;
14916447Ssusans break;
14926447Ssusans }
14936447Ssusans
14946447Ssusans return (rval);
14956447Ssusans }
14966447Ssusans
14976447Ssusans /*
14986447Ssusans * tran_setcap - set one of a set of SCSA-defined capabilities
14996447Ssusans * @ap:
15006447Ssusans * @cap:
15016447Ssusans * @value:
15026447Ssusans * @whom:
15036447Ssusans *
15046447Ssusans * The target driver might request that the new value be set for a particular
15056447Ssusans * target by setting the whom parameter to nonzero. A whom value of zero
15066447Ssusans * means that request is to set the new value for the SCSI bus or for adapter
15076447Ssusans * hardware in general.
15086447Ssusans * The tran_setcap() should return the following values as appropriate:
15096447Ssusans * - -1 for undefined capabilities
15106447Ssusans * - 0 if the HBA driver cannot set the capability to the requested value
15116447Ssusans * - 1 if the HBA driver is able to set the capability to the requested value
15126447Ssusans */
15136447Ssusans /*ARGSUSED*/
15146447Ssusans static int
megasas_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)15156447Ssusans megasas_tran_setcap(struct scsi_address *ap, char *cap, int value, int whom)
15166447Ssusans {
15176447Ssusans int rval = 1;
15186447Ssusans
15196447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
15206447Ssusans
15216447Ssusans /* We don't allow setting capabilities for other targets */
15226447Ssusans if (cap == NULL || whom == 0) {
15236447Ssusans return (-1);
15246447Ssusans }
15256447Ssusans
15266447Ssusans switch (scsi_hba_lookup_capstr(cap)) {
15276447Ssusans case SCSI_CAP_DMA_MAX:
15286447Ssusans case SCSI_CAP_MSG_OUT:
15296447Ssusans case SCSI_CAP_PARITY:
15306447Ssusans case SCSI_CAP_LINKED_CMDS:
15316447Ssusans case SCSI_CAP_RESET_NOTIFICATION:
15326447Ssusans case SCSI_CAP_DISCONNECT:
15336447Ssusans case SCSI_CAP_SYNCHRONOUS:
15346447Ssusans case SCSI_CAP_UNTAGGED_QING:
15356447Ssusans case SCSI_CAP_WIDE_XFER:
15366447Ssusans case SCSI_CAP_INITIATOR_ID:
15376447Ssusans case SCSI_CAP_ARQ:
15386447Ssusans /*
15396447Ssusans * None of these are settable via
15406447Ssusans * the capability interface.
15416447Ssusans */
15426447Ssusans break;
15436447Ssusans case SCSI_CAP_TAGGED_QING:
15446447Ssusans rval = 1;
15456447Ssusans break;
15466447Ssusans case SCSI_CAP_SECTOR_SIZE:
15476447Ssusans rval = 1;
15486447Ssusans break;
15496447Ssusans
15506447Ssusans case SCSI_CAP_TOTAL_SECTORS:
15516447Ssusans rval = 1;
15526447Ssusans break;
15536447Ssusans default:
15546447Ssusans rval = -1;
15556447Ssusans break;
15566447Ssusans }
15576447Ssusans
15586447Ssusans return (rval);
15596447Ssusans }
15606447Ssusans
15616447Ssusans /*
15626447Ssusans * tran_destroy_pkt - deallocate scsi_pkt structure
15636447Ssusans * @ap:
15646447Ssusans * @pkt:
15656447Ssusans *
15666447Ssusans * The tran_destroy_pkt() entry point is the HBA driver function that
15676447Ssusans * deallocates scsi_pkt structures. The tran_destroy_pkt() entry point is
15686447Ssusans * called when the target driver calls scsi_destroy_pkt(). The
15696447Ssusans * tran_destroy_pkt() entry point must free any DMA resources that have been
15706447Ssusans * allocated for the packet. An implicit DMA synchronization occurs if the
15716447Ssusans * DMA resources are freed and any cached data remains after the completion
15726447Ssusans * of the transfer.
15736447Ssusans */
15746447Ssusans static void
megasas_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)15756447Ssusans megasas_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
15766447Ssusans {
15776447Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
15786447Ssusans
15796447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
15806447Ssusans
15816447Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
15826447Ssusans acmd->cmd_flags &= ~CFLAG_DMAVALID;
15836447Ssusans
15846447Ssusans (void) ddi_dma_unbind_handle(acmd->cmd_dmahandle);
15856447Ssusans
15866447Ssusans ddi_dma_free_handle(&acmd->cmd_dmahandle);
15876447Ssusans
15886447Ssusans acmd->cmd_dmahandle = NULL;
15896447Ssusans }
15906447Ssusans
15916447Ssusans /* free the pkt */
15926447Ssusans scsi_hba_pkt_free(ap, pkt);
15936447Ssusans }
15946447Ssusans
15956447Ssusans /*
15966447Ssusans * tran_dmafree - deallocates DMA resources
15976447Ssusans * @ap:
15986447Ssusans * @pkt:
15996447Ssusans *
16006447Ssusans * The tran_dmafree() entry point deallocates DMAQ resources that have been
16016447Ssusans * allocated for a scsi_pkt structure. The tran_dmafree() entry point is
16026447Ssusans * called when the target driver calls scsi_dmafree(). The tran_dmafree() must
16036447Ssusans * free only DMA resources allocated for a scsi_pkt structure, not the
16046447Ssusans * scsi_pkt itself. When DMA resources are freed, a DMA synchronization is
16056447Ssusans * implicitly performed.
16066447Ssusans */
16076447Ssusans /*ARGSUSED*/
16086447Ssusans static void
megasas_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)16096447Ssusans megasas_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
16106447Ssusans {
16116447Ssusans register struct scsa_cmd *acmd = PKT2CMD(pkt);
16126447Ssusans
16136447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16146447Ssusans
16156447Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
16166447Ssusans acmd->cmd_flags &= ~CFLAG_DMAVALID;
16176447Ssusans
16186447Ssusans (void) ddi_dma_unbind_handle(acmd->cmd_dmahandle);
16196447Ssusans
16206447Ssusans ddi_dma_free_handle(&acmd->cmd_dmahandle);
16216447Ssusans
16226447Ssusans acmd->cmd_dmahandle = NULL;
16236447Ssusans }
16246447Ssusans }
16256447Ssusans
16266447Ssusans /*
16276447Ssusans * tran_sync_pkt - synchronize the DMA object allocated
16286447Ssusans * @ap:
16296447Ssusans * @pkt:
16306447Ssusans *
16316447Ssusans * The tran_sync_pkt() entry point synchronizes the DMA object allocated for
16326447Ssusans * the scsi_pkt structure before or after a DMA transfer. The tran_sync_pkt()
16336447Ssusans * entry point is called when the target driver calls scsi_sync_pkt(). If the
16346447Ssusans * data transfer direction is a DMA read from device to memory, tran_sync_pkt()
16356447Ssusans * must synchronize the CPU's view of the data. If the data transfer direction
16366447Ssusans * is a DMA write from memory to device, tran_sync_pkt() must synchronize the
16376447Ssusans * device's view of the data.
16386447Ssusans */
16396447Ssusans /*ARGSUSED*/
16406447Ssusans static void
megasas_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)16416447Ssusans megasas_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
16426447Ssusans {
16436447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16446447Ssusans
16456447Ssusans /*
16466447Ssusans * following 'ddi_dma_sync()' API call
16476447Ssusans * already called for each I/O in the ISR
16486447Ssusans */
16497562SSusan.Scheufele@Sun.COM #if 0
16506447Ssusans int i;
16516447Ssusans
16527562SSusan.Scheufele@Sun.COM register struct scsa_cmd *acmd = PKT2CMD(pkt);
16536447Ssusans
16546447Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
16556447Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle, acmd->cmd_dma_offset,
16566447Ssusans acmd->cmd_dma_len, (acmd->cmd_flags & CFLAG_DMASEND) ?
16576447Ssusans DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
16586447Ssusans }
16597562SSusan.Scheufele@Sun.COM #endif
16606447Ssusans }
16616447Ssusans
16626447Ssusans /*ARGSUSED*/
16636447Ssusans static int
megasas_tran_quiesce(dev_info_t * dip)16646447Ssusans megasas_tran_quiesce(dev_info_t *dip)
16656447Ssusans {
16666447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16676447Ssusans
16686447Ssusans return (1);
16696447Ssusans }
16706447Ssusans
16716447Ssusans /*ARGSUSED*/
16726447Ssusans static int
megasas_tran_unquiesce(dev_info_t * dip)16736447Ssusans megasas_tran_unquiesce(dev_info_t *dip)
16746447Ssusans {
16756447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16766447Ssusans
16776447Ssusans return (1);
16786447Ssusans }
16796447Ssusans
16806447Ssusans /*
16816447Ssusans * megasas_isr(caddr_t)
16826447Ssusans *
16836447Ssusans * The Interrupt Service Routine
16846447Ssusans *
16856447Ssusans * Collect status for all completed commands and do callback
16866447Ssusans *
16876447Ssusans */
16886447Ssusans static uint_t
megasas_isr(struct megasas_instance * instance)16897562SSusan.Scheufele@Sun.COM megasas_isr(struct megasas_instance *instance)
16906447Ssusans {
16916447Ssusans int need_softintr;
16926447Ssusans uint32_t producer;
16936447Ssusans uint32_t consumer;
16946447Ssusans uint32_t context;
16956447Ssusans
16966447Ssusans struct megasas_cmd *cmd;
16976447Ssusans
16986447Ssusans con_log(CL_ANN1, (CE_NOTE, "chkpnt:%s:%d", __func__, __LINE__));
16996447Ssusans
17007562SSusan.Scheufele@Sun.COM ASSERT(instance);
17016447Ssusans if (!instance->func_ptr->intr_ack(instance)) {
17026447Ssusans return (DDI_INTR_UNCLAIMED);
17036447Ssusans }
17046447Ssusans
17056447Ssusans (void) ddi_dma_sync(instance->mfi_internal_dma_obj.dma_handle,
17066447Ssusans 0, 0, DDI_DMA_SYNC_FORCPU);
17076447Ssusans
17087533SYu.Wu@Sun.COM if (megasas_check_dma_handle(instance->mfi_internal_dma_obj.dma_handle)
17097533SYu.Wu@Sun.COM != DDI_SUCCESS) {
17107533SYu.Wu@Sun.COM megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
17117533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
17127533SYu.Wu@Sun.COM return (DDI_INTR_UNCLAIMED);
17137533SYu.Wu@Sun.COM }
17147533SYu.Wu@Sun.COM
17156447Ssusans producer = *instance->producer;
17166447Ssusans consumer = *instance->consumer;
17176447Ssusans
17186447Ssusans con_log(CL_ANN1, (CE_CONT, " producer %x consumer %x ",
17196447Ssusans producer, consumer));
17206447Ssusans
17216447Ssusans mutex_enter(&instance->completed_pool_mtx);
17226447Ssusans
17236447Ssusans while (consumer != producer) {
17246447Ssusans context = instance->reply_queue[consumer];
17256447Ssusans cmd = instance->cmd_list[context];
17266447Ssusans mlist_add_tail(&cmd->list, &instance->completed_pool_list);
17276447Ssusans
17286447Ssusans consumer++;
17296447Ssusans if (consumer == (instance->max_fw_cmds + 1)) {
17306447Ssusans consumer = 0;
17316447Ssusans }
17326447Ssusans }
17336447Ssusans
17346447Ssusans mutex_exit(&instance->completed_pool_mtx);
17356447Ssusans
17367193Syw209021 *instance->consumer = consumer;
17376447Ssusans (void) ddi_dma_sync(instance->mfi_internal_dma_obj.dma_handle,
17386447Ssusans 0, 0, DDI_DMA_SYNC_FORDEV);
17396447Ssusans
17406447Ssusans if (instance->softint_running) {
17416447Ssusans need_softintr = 0;
17426447Ssusans } else {
17436447Ssusans need_softintr = 1;
17446447Ssusans }
17456447Ssusans
17466447Ssusans if (instance->isr_level == HIGH_LEVEL_INTR) {
17476447Ssusans if (need_softintr) {
17486447Ssusans ddi_trigger_softintr(instance->soft_intr_id);
17496447Ssusans }
17506447Ssusans } else {
17516447Ssusans /*
17526447Ssusans * Not a high-level interrupt, therefore call the soft level
17536447Ssusans * interrupt explicitly
17546447Ssusans */
17557562SSusan.Scheufele@Sun.COM (void) megasas_softintr(instance);
17566447Ssusans }
17576447Ssusans
17586447Ssusans return (DDI_INTR_CLAIMED);
17596447Ssusans }
17606447Ssusans
17616447Ssusans
17626447Ssusans /*
17636447Ssusans * ************************************************************************** *
17646447Ssusans * *
17656447Ssusans * libraries *
17666447Ssusans * *
17676447Ssusans * ************************************************************************** *
17686447Ssusans */
17696447Ssusans /*
17706447Ssusans * get_mfi_pkt : Get a command from the free pool
17716447Ssusans */
17726447Ssusans static struct megasas_cmd *
get_mfi_pkt(struct megasas_instance * instance)17736447Ssusans get_mfi_pkt(struct megasas_instance *instance)
17746447Ssusans {
17756447Ssusans mlist_t *head = &instance->cmd_pool_list;
17766447Ssusans struct megasas_cmd *cmd = NULL;
17776447Ssusans
17786447Ssusans mutex_enter(&instance->cmd_pool_mtx);
17796447Ssusans ASSERT(mutex_owned(&instance->cmd_pool_mtx));
17806447Ssusans
17816447Ssusans if (!mlist_empty(head)) {
17826447Ssusans cmd = mlist_entry(head->next, struct megasas_cmd, list);
17836447Ssusans mlist_del_init(head->next);
17846447Ssusans }
17857533SYu.Wu@Sun.COM if (cmd != NULL)
17867533SYu.Wu@Sun.COM cmd->pkt = NULL;
17876447Ssusans mutex_exit(&instance->cmd_pool_mtx);
17886447Ssusans
17896447Ssusans return (cmd);
17906447Ssusans }
17916447Ssusans
17926447Ssusans /*
17936447Ssusans * return_mfi_pkt : Return a cmd to free command pool
17946447Ssusans */
17956447Ssusans static void
return_mfi_pkt(struct megasas_instance * instance,struct megasas_cmd * cmd)17966447Ssusans return_mfi_pkt(struct megasas_instance *instance, struct megasas_cmd *cmd)
17976447Ssusans {
17986447Ssusans mutex_enter(&instance->cmd_pool_mtx);
17996447Ssusans ASSERT(mutex_owned(&instance->cmd_pool_mtx));
18006447Ssusans
18016447Ssusans mlist_add(&cmd->list, &instance->cmd_pool_list);
18026447Ssusans
18036447Ssusans mutex_exit(&instance->cmd_pool_mtx);
18046447Ssusans }
18056447Ssusans
18066447Ssusans /*
18076447Ssusans * destroy_mfi_frame_pool
18086447Ssusans */
18096447Ssusans static void
destroy_mfi_frame_pool(struct megasas_instance * instance)18106447Ssusans destroy_mfi_frame_pool(struct megasas_instance *instance)
18116447Ssusans {
18126447Ssusans int i;
18136447Ssusans uint32_t max_cmd = instance->max_fw_cmds;
18146447Ssusans
18156447Ssusans struct megasas_cmd *cmd;
18166447Ssusans
18176447Ssusans /* return all frames to pool */
18186447Ssusans for (i = 0; i < max_cmd; i++) {
18196447Ssusans
18206447Ssusans cmd = instance->cmd_list[i];
18216447Ssusans
18226447Ssusans if (cmd->frame_dma_obj_status == DMA_OBJ_ALLOCATED)
18237533SYu.Wu@Sun.COM (void) mega_free_dma_obj(instance, cmd->frame_dma_obj);
18246447Ssusans
18256447Ssusans cmd->frame_dma_obj_status = DMA_OBJ_FREED;
18266447Ssusans }
18276447Ssusans
18286447Ssusans }
18296447Ssusans
18306447Ssusans /*
18316447Ssusans * create_mfi_frame_pool
18326447Ssusans */
18336447Ssusans static int
create_mfi_frame_pool(struct megasas_instance * instance)18346447Ssusans create_mfi_frame_pool(struct megasas_instance *instance)
18356447Ssusans {
18366447Ssusans int i = 0;
18376447Ssusans int cookie_cnt;
18386447Ssusans uint16_t max_cmd;
18396447Ssusans uint16_t sge_sz;
18406447Ssusans uint32_t sgl_sz;
18416447Ssusans uint32_t tot_frame_size;
18426447Ssusans
18436447Ssusans struct megasas_cmd *cmd;
18446447Ssusans
18456447Ssusans max_cmd = instance->max_fw_cmds;
18466447Ssusans
18476447Ssusans sge_sz = sizeof (struct megasas_sge64);
18486447Ssusans
18496447Ssusans /* calculated the number of 64byte frames required for SGL */
18507562SSusan.Scheufele@Sun.COM sgl_sz = sge_sz * instance->max_num_sge;
18517562SSusan.Scheufele@Sun.COM tot_frame_size = sgl_sz + MEGAMFI_FRAME_SIZE + SENSE_LENGTH;
18526447Ssusans
18536447Ssusans con_log(CL_DLEVEL3, (CE_NOTE, "create_mfi_frame_pool: "
18546447Ssusans "sgl_sz %x tot_frame_size %x", sgl_sz, tot_frame_size));
18556447Ssusans
18566447Ssusans while (i < max_cmd) {
18576447Ssusans cmd = instance->cmd_list[i];
18586447Ssusans
18596447Ssusans cmd->frame_dma_obj.size = tot_frame_size;
18606447Ssusans cmd->frame_dma_obj.dma_attr = megasas_generic_dma_attr;
18617562SSusan.Scheufele@Sun.COM cmd->frame_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
18627562SSusan.Scheufele@Sun.COM cmd->frame_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
18636447Ssusans cmd->frame_dma_obj.dma_attr.dma_attr_sgllen = 1;
18646447Ssusans cmd->frame_dma_obj.dma_attr.dma_attr_align = 64;
18656447Ssusans
18666447Ssusans
18676447Ssusans cookie_cnt = mega_alloc_dma_obj(instance, &cmd->frame_dma_obj);
18686447Ssusans
18696447Ssusans if (cookie_cnt == -1 || cookie_cnt > 1) {
18706447Ssusans con_log(CL_ANN, (CE_WARN,
18716447Ssusans "create_mfi_frame_pool: could not alloc."));
18726447Ssusans return (DDI_FAILURE);
18736447Ssusans }
18746447Ssusans
18756447Ssusans bzero(cmd->frame_dma_obj.buffer, tot_frame_size);
18766447Ssusans
18776447Ssusans cmd->frame_dma_obj_status = DMA_OBJ_ALLOCATED;
18786447Ssusans cmd->frame = (union megasas_frame *)cmd->frame_dma_obj.buffer;
18796447Ssusans cmd->frame_phys_addr =
18806447Ssusans cmd->frame_dma_obj.dma_cookie[0].dmac_address;
18816447Ssusans
18826447Ssusans cmd->sense = (uint8_t *)(((unsigned long)
18836447Ssusans cmd->frame_dma_obj.buffer) +
18847193Syw209021 tot_frame_size - SENSE_LENGTH);
18856447Ssusans cmd->sense_phys_addr =
18866447Ssusans cmd->frame_dma_obj.dma_cookie[0].dmac_address +
18877193Syw209021 tot_frame_size - SENSE_LENGTH;
18886447Ssusans
18896447Ssusans if (!cmd->frame || !cmd->sense) {
18906447Ssusans con_log(CL_ANN, (CE_NOTE,
18916447Ssusans "megasas: pci_pool_alloc failed \n"));
18926447Ssusans
18936447Ssusans return (-ENOMEM);
18946447Ssusans }
18956447Ssusans
18966447Ssusans cmd->frame->io.context = cmd->index;
18976447Ssusans i++;
18986447Ssusans
18996447Ssusans con_log(CL_DLEVEL3, (CE_NOTE, "[%x]-%x",
19006447Ssusans cmd->frame->io.context, cmd->frame_phys_addr));
19016447Ssusans }
19026447Ssusans
19036447Ssusans return (DDI_SUCCESS);
19046447Ssusans }
19056447Ssusans
19066447Ssusans /*
19076447Ssusans * free_additional_dma_buffer
19086447Ssusans */
19096447Ssusans static void
free_additional_dma_buffer(struct megasas_instance * instance)19106447Ssusans free_additional_dma_buffer(struct megasas_instance *instance)
19116447Ssusans {
19126447Ssusans if (instance->mfi_internal_dma_obj.status == DMA_OBJ_ALLOCATED) {
19137533SYu.Wu@Sun.COM (void) mega_free_dma_obj(instance,
19147533SYu.Wu@Sun.COM instance->mfi_internal_dma_obj);
19156447Ssusans instance->mfi_internal_dma_obj.status = DMA_OBJ_FREED;
19166447Ssusans }
19176447Ssusans
19186447Ssusans if (instance->mfi_evt_detail_obj.status == DMA_OBJ_ALLOCATED) {
19197533SYu.Wu@Sun.COM (void) mega_free_dma_obj(instance,
19207533SYu.Wu@Sun.COM instance->mfi_evt_detail_obj);
19216447Ssusans instance->mfi_evt_detail_obj.status = DMA_OBJ_FREED;
19226447Ssusans }
19236447Ssusans }
19246447Ssusans
19256447Ssusans /*
19266447Ssusans * alloc_additional_dma_buffer
19276447Ssusans */
19286447Ssusans static int
alloc_additional_dma_buffer(struct megasas_instance * instance)19296447Ssusans alloc_additional_dma_buffer(struct megasas_instance *instance)
19306447Ssusans {
19316447Ssusans uint32_t reply_q_sz;
19326447Ssusans uint32_t internal_buf_size = PAGESIZE*2;
19336447Ssusans
19347562SSusan.Scheufele@Sun.COM /* max cmds plus 1 + producer & consumer */
19356447Ssusans reply_q_sz = sizeof (uint32_t) * (instance->max_fw_cmds + 1 + 2);
19366447Ssusans
19376447Ssusans instance->mfi_internal_dma_obj.size = internal_buf_size;
19386447Ssusans instance->mfi_internal_dma_obj.dma_attr = megasas_generic_dma_attr;
19397562SSusan.Scheufele@Sun.COM instance->mfi_internal_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
19407562SSusan.Scheufele@Sun.COM instance->mfi_internal_dma_obj.dma_attr.dma_attr_count_max =
19417562SSusan.Scheufele@Sun.COM 0xFFFFFFFFU;
19426447Ssusans instance->mfi_internal_dma_obj.dma_attr.dma_attr_sgllen = 1;
19436447Ssusans
19446447Ssusans if (mega_alloc_dma_obj(instance, &instance->mfi_internal_dma_obj)
19456447Ssusans != 1) {
19466447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: could not alloc reply Q"));
19476447Ssusans return (DDI_FAILURE);
19486447Ssusans }
19496447Ssusans
19506447Ssusans bzero(instance->mfi_internal_dma_obj.buffer, internal_buf_size);
19516447Ssusans
19526447Ssusans instance->mfi_internal_dma_obj.status |= DMA_OBJ_ALLOCATED;
19536447Ssusans
19547562SSusan.Scheufele@Sun.COM instance->producer = (uint32_t *)((unsigned long)
19557562SSusan.Scheufele@Sun.COM instance->mfi_internal_dma_obj.buffer);
19566447Ssusans instance->consumer = (uint32_t *)((unsigned long)
19576447Ssusans instance->mfi_internal_dma_obj.buffer + 4);
19586447Ssusans instance->reply_queue = (uint32_t *)((unsigned long)
19596447Ssusans instance->mfi_internal_dma_obj.buffer + 8);
19606447Ssusans instance->internal_buf = (caddr_t)(((unsigned long)
19616447Ssusans instance->mfi_internal_dma_obj.buffer) + reply_q_sz + 8);
19626447Ssusans instance->internal_buf_dmac_add =
19636447Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address +
19646447Ssusans reply_q_sz;
19656447Ssusans instance->internal_buf_size = internal_buf_size -
19666447Ssusans (reply_q_sz + 8);
19676447Ssusans
19686447Ssusans /* allocate evt_detail */
19696447Ssusans instance->mfi_evt_detail_obj.size = sizeof (struct megasas_evt_detail);
19706447Ssusans instance->mfi_evt_detail_obj.dma_attr = megasas_generic_dma_attr;
19717562SSusan.Scheufele@Sun.COM instance->mfi_evt_detail_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
19727562SSusan.Scheufele@Sun.COM instance->mfi_evt_detail_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
19736447Ssusans instance->mfi_evt_detail_obj.dma_attr.dma_attr_sgllen = 1;
19746447Ssusans instance->mfi_evt_detail_obj.dma_attr.dma_attr_align = 1;
19756447Ssusans
19766447Ssusans if (mega_alloc_dma_obj(instance, &instance->mfi_evt_detail_obj) != 1) {
19776447Ssusans con_log(CL_ANN, (CE_WARN, "alloc_additional_dma_buffer: "
19786447Ssusans "could not data transfer buffer alloc."));
19796447Ssusans return (DDI_FAILURE);
19806447Ssusans }
19816447Ssusans
19826447Ssusans bzero(instance->mfi_evt_detail_obj.buffer,
19836447Ssusans sizeof (struct megasas_evt_detail));
19846447Ssusans
19856447Ssusans instance->mfi_evt_detail_obj.status |= DMA_OBJ_ALLOCATED;
19866447Ssusans
19876447Ssusans return (DDI_SUCCESS);
19886447Ssusans }
19896447Ssusans
19906447Ssusans /*
19916447Ssusans * free_space_for_mfi
19926447Ssusans */
19936447Ssusans static void
free_space_for_mfi(struct megasas_instance * instance)19946447Ssusans free_space_for_mfi(struct megasas_instance *instance)
19956447Ssusans {
19966447Ssusans int i;
19976447Ssusans uint32_t max_cmd = instance->max_fw_cmds;
19986447Ssusans
19996447Ssusans /* already freed */
20006447Ssusans if (instance->cmd_list == NULL) {
20016447Ssusans return;
20026447Ssusans }
20036447Ssusans
20046447Ssusans free_additional_dma_buffer(instance);
20056447Ssusans
20066447Ssusans /* first free the MFI frame pool */
20076447Ssusans destroy_mfi_frame_pool(instance);
20086447Ssusans
20096447Ssusans /* free all the commands in the cmd_list */
20106447Ssusans for (i = 0; i < instance->max_fw_cmds; i++) {
20116447Ssusans kmem_free(instance->cmd_list[i],
20126447Ssusans sizeof (struct megasas_cmd));
20136447Ssusans
20146447Ssusans instance->cmd_list[i] = NULL;
20156447Ssusans }
20166447Ssusans
20176447Ssusans /* free the cmd_list buffer itself */
20186447Ssusans kmem_free(instance->cmd_list,
20196447Ssusans sizeof (struct megasas_cmd *) * max_cmd);
20206447Ssusans
20216447Ssusans instance->cmd_list = NULL;
20226447Ssusans
20236447Ssusans INIT_LIST_HEAD(&instance->cmd_pool_list);
20246447Ssusans }
20256447Ssusans
20266447Ssusans /*
20276447Ssusans * alloc_space_for_mfi
20286447Ssusans */
20296447Ssusans static int
alloc_space_for_mfi(struct megasas_instance * instance)20306447Ssusans alloc_space_for_mfi(struct megasas_instance *instance)
20316447Ssusans {
20326447Ssusans int i;
20336447Ssusans uint32_t max_cmd;
20346447Ssusans size_t sz;
20356447Ssusans
20366447Ssusans struct megasas_cmd *cmd;
20376447Ssusans
20386447Ssusans max_cmd = instance->max_fw_cmds;
20396447Ssusans sz = sizeof (struct megasas_cmd *) * max_cmd;
20406447Ssusans
20416447Ssusans /*
20426447Ssusans * instance->cmd_list is an array of struct megasas_cmd pointers.
20436447Ssusans * Allocate the dynamic array first and then allocate individual
20446447Ssusans * commands.
20456447Ssusans */
20466447Ssusans instance->cmd_list = kmem_zalloc(sz, KM_SLEEP);
20476447Ssusans ASSERT(instance->cmd_list);
20486447Ssusans
20496447Ssusans for (i = 0; i < max_cmd; i++) {
20506447Ssusans instance->cmd_list[i] = kmem_zalloc(sizeof (struct megasas_cmd),
20516447Ssusans KM_SLEEP);
20526447Ssusans ASSERT(instance->cmd_list[i]);
20536447Ssusans }
20546447Ssusans
20556447Ssusans INIT_LIST_HEAD(&instance->cmd_pool_list);
20566447Ssusans
20576447Ssusans /* add all the commands to command pool (instance->cmd_pool) */
20586447Ssusans for (i = 0; i < max_cmd; i++) {
20596447Ssusans cmd = instance->cmd_list[i];
20606447Ssusans cmd->index = i;
20616447Ssusans
20626447Ssusans mlist_add_tail(&cmd->list, &instance->cmd_pool_list);
20636447Ssusans }
20646447Ssusans
20656447Ssusans /* create a frame pool and assign one frame to each cmd */
20666447Ssusans if (create_mfi_frame_pool(instance)) {
20676447Ssusans con_log(CL_ANN, (CE_NOTE, "error creating frame DMA pool\n"));
20686447Ssusans return (DDI_FAILURE);
20696447Ssusans }
20706447Ssusans
20716447Ssusans /* create a frame pool and assign one frame to each cmd */
20726447Ssusans if (alloc_additional_dma_buffer(instance)) {
20736447Ssusans con_log(CL_ANN, (CE_NOTE, "error creating frame DMA pool\n"));
20746447Ssusans return (DDI_FAILURE);
20756447Ssusans }
20766447Ssusans
20776447Ssusans return (DDI_SUCCESS);
20786447Ssusans }
20796447Ssusans
20806447Ssusans /*
20816447Ssusans * get_ctrl_info
20826447Ssusans */
20836447Ssusans static int
get_ctrl_info(struct megasas_instance * instance,struct megasas_ctrl_info * ctrl_info)20846447Ssusans get_ctrl_info(struct megasas_instance *instance,
20856447Ssusans struct megasas_ctrl_info *ctrl_info)
20866447Ssusans {
20876447Ssusans int ret = 0;
20886447Ssusans
20896447Ssusans struct megasas_cmd *cmd;
20906447Ssusans struct megasas_dcmd_frame *dcmd;
20916447Ssusans struct megasas_ctrl_info *ci;
20926447Ssusans
20936447Ssusans cmd = get_mfi_pkt(instance);
20946447Ssusans
20956447Ssusans if (!cmd) {
20966447Ssusans con_log(CL_ANN, (CE_WARN,
20976447Ssusans "Failed to get a cmd for ctrl info\n"));
20986447Ssusans return (DDI_FAILURE);
20996447Ssusans }
21006447Ssusans
21016447Ssusans dcmd = &cmd->frame->dcmd;
21026447Ssusans
21036447Ssusans ci = (struct megasas_ctrl_info *)instance->internal_buf;
21046447Ssusans
21056447Ssusans if (!ci) {
21066447Ssusans con_log(CL_ANN, (CE_WARN,
21076447Ssusans "Failed to alloc mem for ctrl info\n"));
21086447Ssusans return_mfi_pkt(instance, cmd);
21096447Ssusans return (DDI_FAILURE);
21106447Ssusans }
21116447Ssusans
21126447Ssusans (void) memset(ci, 0, sizeof (struct megasas_ctrl_info));
21136447Ssusans
21147562SSusan.Scheufele@Sun.COM /* for( i = 0; i < DCMD_MBOX_SZ; i++ ) dcmd->mbox.b[i] = 0; */
21157562SSusan.Scheufele@Sun.COM (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
21166447Ssusans
21176447Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
21187562SSusan.Scheufele@Sun.COM dcmd->cmd_status = MFI_CMD_STATUS_POLL_MODE;
21196447Ssusans dcmd->sge_count = 1;
21206447Ssusans dcmd->flags = MFI_FRAME_DIR_READ;
21216447Ssusans dcmd->timeout = 0;
21226447Ssusans dcmd->data_xfer_len = sizeof (struct megasas_ctrl_info);
21236447Ssusans dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
21246447Ssusans dcmd->sgl.sge32[0].phys_addr = instance->internal_buf_dmac_add;
21256447Ssusans dcmd->sgl.sge32[0].length = sizeof (struct megasas_ctrl_info);
21266447Ssusans
21276447Ssusans cmd->frame_count = 1;
21286447Ssusans
21296447Ssusans if (!instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd)) {
21306447Ssusans ret = 0;
21316447Ssusans (void) memcpy(ctrl_info, ci, sizeof (struct megasas_ctrl_info));
21326447Ssusans } else {
21336447Ssusans con_log(CL_ANN, (CE_WARN, "get_ctrl_info: Ctrl info failed\n"));
21346447Ssusans ret = -1;
21356447Ssusans }
21366447Ssusans
21376447Ssusans return_mfi_pkt(instance, cmd);
21387533SYu.Wu@Sun.COM if (megasas_common_check(instance, cmd) != DDI_SUCCESS) {
21397533SYu.Wu@Sun.COM ret = -1;
21407533SYu.Wu@Sun.COM }
21416447Ssusans
21426447Ssusans return (ret);
21436447Ssusans }
21446447Ssusans
21456447Ssusans /*
21466447Ssusans * abort_aen_cmd
21476447Ssusans */
21486447Ssusans static int
abort_aen_cmd(struct megasas_instance * instance,struct megasas_cmd * cmd_to_abort)21496447Ssusans abort_aen_cmd(struct megasas_instance *instance,
21506447Ssusans struct megasas_cmd *cmd_to_abort)
21516447Ssusans {
21526447Ssusans int ret = 0;
21536447Ssusans
21546447Ssusans struct megasas_cmd *cmd;
21556447Ssusans struct megasas_abort_frame *abort_fr;
21566447Ssusans
21576447Ssusans cmd = get_mfi_pkt(instance);
21586447Ssusans
21596447Ssusans if (!cmd) {
21606447Ssusans con_log(CL_ANN, (CE_WARN,
21616447Ssusans "Failed to get a cmd for ctrl info\n"));
21626447Ssusans return (DDI_FAILURE);
21636447Ssusans }
21646447Ssusans
21656447Ssusans abort_fr = &cmd->frame->abort;
21666447Ssusans
21676447Ssusans /* prepare and issue the abort frame */
21686447Ssusans abort_fr->cmd = MFI_CMD_OP_ABORT;
21697562SSusan.Scheufele@Sun.COM abort_fr->cmd_status = MFI_CMD_STATUS_SYNC_MODE;
21706447Ssusans abort_fr->flags = 0;
21716447Ssusans abort_fr->abort_context = cmd_to_abort->index;
21726447Ssusans abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
21736447Ssusans abort_fr->abort_mfi_phys_addr_hi = 0;
21746447Ssusans
21756447Ssusans instance->aen_cmd->abort_aen = 1;
21766447Ssusans
21776447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
21786447Ssusans cmd->frame_count = 1;
21796447Ssusans
21806447Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
21816447Ssusans con_log(CL_ANN, (CE_WARN,
21826447Ssusans "abort_aen_cmd: issue_cmd_in_sync_mode failed\n"));
21836447Ssusans ret = -1;
21846447Ssusans } else {
21856447Ssusans ret = 0;
21866447Ssusans }
21876447Ssusans
21886447Ssusans instance->aen_cmd->abort_aen = 1;
21896447Ssusans instance->aen_cmd = 0;
21906447Ssusans
21916447Ssusans return_mfi_pkt(instance, cmd);
21927533SYu.Wu@Sun.COM (void) megasas_common_check(instance, cmd);
21936447Ssusans
21946447Ssusans return (ret);
21956447Ssusans }
21966447Ssusans
21976447Ssusans /*
21986447Ssusans * init_mfi
21996447Ssusans */
22006447Ssusans static int
init_mfi(struct megasas_instance * instance)22016447Ssusans init_mfi(struct megasas_instance *instance)
22026447Ssusans {
22036447Ssusans off_t reglength;
22046447Ssusans struct megasas_cmd *cmd;
22056447Ssusans struct megasas_ctrl_info ctrl_info;
22066447Ssusans struct megasas_init_frame *init_frame;
22076447Ssusans struct megasas_init_queue_info *initq_info;
22086447Ssusans
22096447Ssusans if ((ddi_dev_regsize(instance->dip, REGISTER_SET_IO, ®length)
22107562SSusan.Scheufele@Sun.COM != DDI_SUCCESS) || reglength < MINIMUM_MFI_MEM_SZ) {
22116447Ssusans return (DDI_FAILURE);
22126447Ssusans }
22136447Ssusans
22147562SSusan.Scheufele@Sun.COM if (reglength > DEFAULT_MFI_MEM_SZ) {
22157562SSusan.Scheufele@Sun.COM reglength = DEFAULT_MFI_MEM_SZ;
22167193Syw209021 con_log(CL_DLEVEL1, (CE_NOTE,
22176447Ssusans "mega: register length to map is 0x%lx bytes", reglength));
22186447Ssusans }
22196447Ssusans
22206447Ssusans if (ddi_regs_map_setup(instance->dip, REGISTER_SET_IO,
22216447Ssusans &instance->regmap, 0, reglength, &endian_attr,
22226447Ssusans &instance->regmap_handle) != DDI_SUCCESS) {
22236447Ssusans con_log(CL_ANN, (CE_NOTE,
22246447Ssusans "megaraid: couldn't map control registers"));
22256447Ssusans
22266447Ssusans goto fail_mfi_reg_setup;
22276447Ssusans }
22286447Ssusans
22296447Ssusans /* we expect the FW state to be READY */
22306447Ssusans if (mfi_state_transition_to_ready(instance)) {
22316447Ssusans con_log(CL_ANN, (CE_WARN, "megaraid: F/W is not ready"));
22326447Ssusans goto fail_ready_state;
22336447Ssusans }
22346447Ssusans
22356447Ssusans /* get various operational parameters from status register */
22366447Ssusans instance->max_num_sge =
22376447Ssusans (instance->func_ptr->read_fw_status_reg(instance) &
22386447Ssusans 0xFF0000) >> 0x10;
22396447Ssusans /*
22406447Ssusans * Reduce the max supported cmds by 1. This is to ensure that the
22416447Ssusans * reply_q_sz (1 more than the max cmd that driver may send)
22426447Ssusans * does not exceed max cmds that the FW can support
22436447Ssusans */
22446447Ssusans instance->max_fw_cmds =
22456447Ssusans instance->func_ptr->read_fw_status_reg(instance) & 0xFFFF;
22466447Ssusans instance->max_fw_cmds = instance->max_fw_cmds - 1;
22476447Ssusans
22486447Ssusans instance->max_num_sge =
22496447Ssusans (instance->max_num_sge > MEGASAS_MAX_SGE_CNT) ?
22506447Ssusans MEGASAS_MAX_SGE_CNT : instance->max_num_sge;
22516447Ssusans
22526447Ssusans /* create a pool of commands */
22536447Ssusans if (alloc_space_for_mfi(instance))
22546447Ssusans goto fail_alloc_fw_space;
22556447Ssusans
22566447Ssusans /* disable interrupt for initial preparation */
22576447Ssusans instance->func_ptr->disable_intr(instance);
22586447Ssusans
22596447Ssusans /*
22606447Ssusans * Prepare a init frame. Note the init frame points to queue info
22616447Ssusans * structure. Each frame has SGL allocated after first 64 bytes. For
22626447Ssusans * this frame - since we don't need any SGL - we use SGL's space as
22636447Ssusans * queue info structure
22646447Ssusans */
22656447Ssusans cmd = get_mfi_pkt(instance);
22666447Ssusans
22676447Ssusans init_frame = (struct megasas_init_frame *)cmd->frame;
22686447Ssusans initq_info = (struct megasas_init_queue_info *)
22696447Ssusans ((unsigned long)init_frame + 64);
22706447Ssusans
22716447Ssusans (void) memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
22726447Ssusans (void) memset(initq_info, 0, sizeof (struct megasas_init_queue_info));
22736447Ssusans
22746447Ssusans initq_info->init_flags = 0;
22756447Ssusans
22766447Ssusans initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
22776447Ssusans
22786447Ssusans initq_info->producer_index_phys_addr_hi = 0;
22796447Ssusans initq_info->producer_index_phys_addr_lo =
22806447Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address;
22816447Ssusans
22826447Ssusans initq_info->consumer_index_phys_addr_hi = 0;
22836447Ssusans initq_info->consumer_index_phys_addr_lo =
22846447Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address + 4;
22856447Ssusans
22866447Ssusans initq_info->reply_queue_start_phys_addr_hi = 0;
22876447Ssusans initq_info->reply_queue_start_phys_addr_lo =
22886447Ssusans instance->mfi_internal_dma_obj.dma_cookie[0].dmac_address + 8;
22896447Ssusans
22906447Ssusans init_frame->cmd = MFI_CMD_OP_INIT;
22917562SSusan.Scheufele@Sun.COM init_frame->cmd_status = MFI_CMD_STATUS_POLL_MODE;
22926447Ssusans init_frame->flags = 0;
22936447Ssusans init_frame->queue_info_new_phys_addr_lo =
22946447Ssusans cmd->frame_phys_addr + 64;
22956447Ssusans init_frame->queue_info_new_phys_addr_hi = 0;
22966447Ssusans
22976447Ssusans init_frame->data_xfer_len = sizeof (struct megasas_init_queue_info);
22986447Ssusans
22996447Ssusans cmd->frame_count = 1;
23006447Ssusans
23016447Ssusans /* issue the init frame in polled mode */
23026447Ssusans if (instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd)) {
23036447Ssusans con_log(CL_ANN, (CE_WARN, "failed to init firmware"));
23046447Ssusans goto fail_fw_init;
23056447Ssusans }
23066447Ssusans
23076447Ssusans return_mfi_pkt(instance, cmd);
23087533SYu.Wu@Sun.COM if (megasas_common_check(instance, cmd) != DDI_SUCCESS) {
23097533SYu.Wu@Sun.COM goto fail_fw_init;
23107533SYu.Wu@Sun.COM }
23116447Ssusans
23126447Ssusans /* gather misc FW related information */
23136447Ssusans if (!get_ctrl_info(instance, &ctrl_info)) {
23146447Ssusans instance->max_sectors_per_req = ctrl_info.max_request_size;
23156447Ssusans con_log(CL_ANN1, (CE_NOTE, "product name %s ld present %d",
23166447Ssusans ctrl_info.product_name, ctrl_info.ld_present_count));
23176447Ssusans } else {
23186447Ssusans instance->max_sectors_per_req = instance->max_num_sge *
23196447Ssusans PAGESIZE / 512;
23206447Ssusans }
23216447Ssusans
23227533SYu.Wu@Sun.COM if (megasas_check_acc_handle(instance->regmap_handle) != DDI_SUCCESS) {
23237533SYu.Wu@Sun.COM goto fail_fw_init;
23247533SYu.Wu@Sun.COM }
23257533SYu.Wu@Sun.COM
23266447Ssusans return (0);
23276447Ssusans
23286447Ssusans fail_fw_init:
23296447Ssusans fail_alloc_fw_space:
23306447Ssusans
23316447Ssusans free_space_for_mfi(instance);
23326447Ssusans
23336447Ssusans fail_ready_state:
23346447Ssusans ddi_regs_map_free(&instance->regmap_handle);
23356447Ssusans
23366447Ssusans fail_mfi_reg_setup:
23376447Ssusans return (DDI_FAILURE);
23386447Ssusans }
23396447Ssusans
23406447Ssusans /*
23416447Ssusans * mfi_state_transition_to_ready : Move the FW to READY state
23426447Ssusans *
23436447Ssusans * @reg_set : MFI register set
23446447Ssusans */
23456447Ssusans static int
mfi_state_transition_to_ready(struct megasas_instance * instance)23466447Ssusans mfi_state_transition_to_ready(struct megasas_instance *instance)
23476447Ssusans {
23486447Ssusans int i;
23496447Ssusans uint8_t max_wait;
23506447Ssusans uint32_t fw_ctrl;
23516447Ssusans uint32_t fw_state;
23526447Ssusans uint32_t cur_state;
23536447Ssusans
23546447Ssusans fw_state =
23556447Ssusans instance->func_ptr->read_fw_status_reg(instance) & MFI_STATE_MASK;
23566447Ssusans con_log(CL_ANN1, (CE_NOTE,
23576447Ssusans "mfi_state_transition_to_ready:FW state = 0x%x", fw_state));
23586447Ssusans
23596447Ssusans while (fw_state != MFI_STATE_READY) {
23606447Ssusans con_log(CL_ANN, (CE_NOTE,
23616447Ssusans "mfi_state_transition_to_ready:FW state%x", fw_state));
23626447Ssusans
23636447Ssusans switch (fw_state) {
23646447Ssusans case MFI_STATE_FAULT:
23656447Ssusans con_log(CL_ANN, (CE_NOTE,
23666447Ssusans "megasas: FW in FAULT state!!"));
23676447Ssusans
23686447Ssusans return (-ENODEV);
23696447Ssusans case MFI_STATE_WAIT_HANDSHAKE:
23706447Ssusans /* set the CLR bit in IMR0 */
23716447Ssusans con_log(CL_ANN, (CE_NOTE,
23726447Ssusans "megasas: FW waiting for HANDSHAKE"));
23736447Ssusans /*
23746447Ssusans * PCI_Hot Plug: MFI F/W requires
23756447Ssusans * (MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG)
23766447Ssusans * to be set
23776447Ssusans */
23786447Ssusans /* WR_IB_MSG_0(MFI_INIT_CLEAR_HANDSHAKE, instance); */
23796447Ssusans WR_IB_DOORBELL(MFI_INIT_CLEAR_HANDSHAKE |
23806447Ssusans MFI_INIT_HOTPLUG, instance);
23816447Ssusans
23826447Ssusans max_wait = 2;
23836447Ssusans cur_state = MFI_STATE_WAIT_HANDSHAKE;
23846447Ssusans break;
23856447Ssusans case MFI_STATE_BOOT_MESSAGE_PENDING:
23866447Ssusans /* set the CLR bit in IMR0 */
23876447Ssusans con_log(CL_ANN, (CE_NOTE,
23886447Ssusans "megasas: FW state boot message pending"));
23896447Ssusans /*
23906447Ssusans * PCI_Hot Plug: MFI F/W requires
23916447Ssusans * (MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG)
23926447Ssusans * to be set
23936447Ssusans */
23946447Ssusans WR_IB_DOORBELL(MFI_INIT_HOTPLUG, instance);
23956447Ssusans
23966447Ssusans max_wait = 10;
23976447Ssusans cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
23986447Ssusans break;
23996447Ssusans case MFI_STATE_OPERATIONAL:
24006447Ssusans /* bring it to READY state; assuming max wait 2 secs */
24016447Ssusans instance->func_ptr->disable_intr(instance);
24026447Ssusans con_log(CL_ANN1, (CE_NOTE,
24036447Ssusans "megasas: FW in OPERATIONAL state"));
24046447Ssusans /*
24056447Ssusans * PCI_Hot Plug: MFI F/W requires
24066447Ssusans * (MFI_INIT_READY | MFI_INIT_MFIMODE | MFI_INIT_ABORT)
24076447Ssusans * to be set
24086447Ssusans */
24096447Ssusans /* WR_IB_DOORBELL(MFI_INIT_READY, instance); */
24106447Ssusans WR_IB_DOORBELL(MFI_RESET_FLAGS, instance);
24116447Ssusans
24126447Ssusans max_wait = 10;
24136447Ssusans cur_state = MFI_STATE_OPERATIONAL;
24146447Ssusans break;
24156447Ssusans case MFI_STATE_UNDEFINED:
24166447Ssusans /* this state should not last for more than 2 seconds */
24176447Ssusans con_log(CL_ANN, (CE_NOTE, "FW state undefined\n"));
24186447Ssusans
24196447Ssusans max_wait = 2;
24206447Ssusans cur_state = MFI_STATE_UNDEFINED;
24216447Ssusans break;
24226447Ssusans case MFI_STATE_BB_INIT:
24236447Ssusans max_wait = 2;
24246447Ssusans cur_state = MFI_STATE_BB_INIT;
24256447Ssusans break;
24266447Ssusans case MFI_STATE_FW_INIT:
24276447Ssusans max_wait = 2;
24286447Ssusans cur_state = MFI_STATE_FW_INIT;
24296447Ssusans break;
24306447Ssusans case MFI_STATE_DEVICE_SCAN:
24316447Ssusans max_wait = 10;
24326447Ssusans cur_state = MFI_STATE_DEVICE_SCAN;
24336447Ssusans break;
24346447Ssusans default:
24356447Ssusans con_log(CL_ANN, (CE_NOTE,
24366447Ssusans "megasas: Unknown state 0x%x\n", fw_state));
24376447Ssusans return (-ENODEV);
24386447Ssusans }
24396447Ssusans
24406447Ssusans /* the cur_state should not last for more than max_wait secs */
24417562SSusan.Scheufele@Sun.COM for (i = 0; i < (max_wait * MILLISEC); i++) {
24426447Ssusans /* fw_state = RD_OB_MSG_0(instance) & MFI_STATE_MASK; */
24436447Ssusans fw_state =
24446447Ssusans instance->func_ptr->read_fw_status_reg(instance) &
24456447Ssusans MFI_STATE_MASK;
24466447Ssusans
24476447Ssusans if (fw_state == cur_state) {
24487562SSusan.Scheufele@Sun.COM delay(1 * drv_usectohz(MILLISEC));
24496447Ssusans } else {
24506447Ssusans break;
24516447Ssusans }
24526447Ssusans }
24536447Ssusans
24546447Ssusans /* return error if fw_state hasn't changed after max_wait */
24556447Ssusans if (fw_state == cur_state) {
24566447Ssusans con_log(CL_ANN, (CE_NOTE,
24576447Ssusans "FW state hasn't changed in %d secs\n", max_wait));
24586447Ssusans return (-ENODEV);
24596447Ssusans }
24606447Ssusans };
24616447Ssusans
24626447Ssusans fw_ctrl = RD_IB_DOORBELL(instance);
24637562SSusan.Scheufele@Sun.COM
24646447Ssusans con_log(CL_ANN1, (CE_NOTE,
24656447Ssusans "mfi_state_transition_to_ready:FW ctrl = 0x%x", fw_ctrl));
24666447Ssusans
24676447Ssusans /*
24686447Ssusans * Write 0xF to the doorbell register to do the following.
24696447Ssusans * - Abort all outstanding commands (bit 0).
24706447Ssusans * - Transition from OPERATIONAL to READY state (bit 1).
24716447Ssusans * - Discard (possible) low MFA posted in 64-bit mode (bit-2).
24726447Ssusans * - Set to release FW to continue running (i.e. BIOS handshake
24736447Ssusans * (bit 3).
24746447Ssusans */
24756447Ssusans WR_IB_DOORBELL(0xF, instance);
24766447Ssusans
24777533SYu.Wu@Sun.COM if (megasas_check_acc_handle(instance->regmap_handle) != DDI_SUCCESS) {
24787533SYu.Wu@Sun.COM return (-ENODEV);
24797533SYu.Wu@Sun.COM }
24806447Ssusans return (0);
24816447Ssusans }
24826447Ssusans
24836447Ssusans /*
24846447Ssusans * get_seq_num
24856447Ssusans */
24866447Ssusans static int
get_seq_num(struct megasas_instance * instance,struct megasas_evt_log_info * eli)24876447Ssusans get_seq_num(struct megasas_instance *instance,
24886447Ssusans struct megasas_evt_log_info *eli)
24896447Ssusans {
24906447Ssusans int ret = 0;
24916447Ssusans
24926447Ssusans dma_obj_t dcmd_dma_obj;
24936447Ssusans struct megasas_cmd *cmd;
24946447Ssusans struct megasas_dcmd_frame *dcmd;
24956447Ssusans
24966447Ssusans cmd = get_mfi_pkt(instance);
24976447Ssusans
24986447Ssusans if (!cmd) {
24996447Ssusans cmn_err(CE_WARN, "megasas: failed to get a cmd\n");
25006447Ssusans return (-ENOMEM);
25016447Ssusans }
25026447Ssusans
25036447Ssusans dcmd = &cmd->frame->dcmd;
25046447Ssusans
25056447Ssusans /* allocate the data transfer buffer */
25066447Ssusans dcmd_dma_obj.size = sizeof (struct megasas_evt_log_info);
25076447Ssusans dcmd_dma_obj.dma_attr = megasas_generic_dma_attr;
25087562SSusan.Scheufele@Sun.COM dcmd_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
25097562SSusan.Scheufele@Sun.COM dcmd_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
25106447Ssusans dcmd_dma_obj.dma_attr.dma_attr_sgllen = 1;
25116447Ssusans dcmd_dma_obj.dma_attr.dma_attr_align = 1;
25126447Ssusans
25136447Ssusans if (mega_alloc_dma_obj(instance, &dcmd_dma_obj) != 1) {
25146447Ssusans con_log(CL_ANN, (CE_WARN,
25156447Ssusans "get_seq_num: could not data transfer buffer alloc."));
25166447Ssusans return (DDI_FAILURE);
25176447Ssusans }
25186447Ssusans
25196447Ssusans (void) memset(dcmd_dma_obj.buffer, 0,
25206447Ssusans sizeof (struct megasas_evt_log_info));
25216447Ssusans
25227562SSusan.Scheufele@Sun.COM (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
25236447Ssusans
25246447Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
25256447Ssusans dcmd->cmd_status = 0;
25266447Ssusans dcmd->sge_count = 1;
25276447Ssusans dcmd->flags = MFI_FRAME_DIR_READ;
25286447Ssusans dcmd->timeout = 0;
25296447Ssusans dcmd->data_xfer_len = sizeof (struct megasas_evt_log_info);
25306447Ssusans dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
25316447Ssusans dcmd->sgl.sge32[0].length = sizeof (struct megasas_evt_log_info);
25326447Ssusans dcmd->sgl.sge32[0].phys_addr = dcmd_dma_obj.dma_cookie[0].dmac_address;
25336447Ssusans
25346447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
25356447Ssusans cmd->frame_count = 1;
25366447Ssusans
25376447Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
25386447Ssusans cmn_err(CE_WARN, "get_seq_num: "
25396447Ssusans "failed to issue MR_DCMD_CTRL_EVENT_GET_INFO\n");
25406447Ssusans ret = -1;
25416447Ssusans } else {
25426447Ssusans /* copy the data back into callers buffer */
25436447Ssusans bcopy(dcmd_dma_obj.buffer, eli,
25446447Ssusans sizeof (struct megasas_evt_log_info));
25456447Ssusans ret = 0;
25466447Ssusans }
25476447Ssusans
25487533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, dcmd_dma_obj) != DDI_SUCCESS)
25497533SYu.Wu@Sun.COM ret = -1;
25506447Ssusans
25516447Ssusans return_mfi_pkt(instance, cmd);
25527533SYu.Wu@Sun.COM if (megasas_common_check(instance, cmd) != DDI_SUCCESS) {
25537533SYu.Wu@Sun.COM ret = -1;
25547533SYu.Wu@Sun.COM }
25556447Ssusans return (ret);
25566447Ssusans }
25576447Ssusans
25586447Ssusans /*
25596447Ssusans * start_mfi_aen
25606447Ssusans */
25616447Ssusans static int
start_mfi_aen(struct megasas_instance * instance)25626447Ssusans start_mfi_aen(struct megasas_instance *instance)
25636447Ssusans {
25646447Ssusans int ret = 0;
25656447Ssusans
25666447Ssusans struct megasas_evt_log_info eli;
25676447Ssusans union megasas_evt_class_locale class_locale;
25686447Ssusans
25696447Ssusans /* get the latest sequence number from FW */
25706447Ssusans (void) memset(&eli, 0, sizeof (struct megasas_evt_log_info));
25716447Ssusans
25726447Ssusans if (get_seq_num(instance, &eli)) {
25736447Ssusans cmn_err(CE_WARN, "start_mfi_aen: failed to get seq num\n");
25746447Ssusans return (-1);
25756447Ssusans }
25766447Ssusans
25776447Ssusans /* register AEN with FW for latest sequence number plus 1 */
25786447Ssusans class_locale.members.reserved = 0;
25796447Ssusans class_locale.members.locale = MR_EVT_LOCALE_ALL;
25806447Ssusans class_locale.members.class = MR_EVT_CLASS_CRITICAL;
25816447Ssusans
25826447Ssusans ret = register_mfi_aen(instance, eli.newest_seq_num + 1,
25836447Ssusans class_locale.word);
25846447Ssusans
25856447Ssusans if (ret) {
25866447Ssusans cmn_err(CE_WARN, "start_mfi_aen: aen registration failed\n");
25876447Ssusans return (-1);
25886447Ssusans }
25896447Ssusans
25906447Ssusans return (ret);
25916447Ssusans }
25926447Ssusans
25936447Ssusans /*
25946447Ssusans * flush_cache
25956447Ssusans */
25966447Ssusans static void
flush_cache(struct megasas_instance * instance)25976447Ssusans flush_cache(struct megasas_instance *instance)
25986447Ssusans {
25996447Ssusans struct megasas_cmd *cmd;
26006447Ssusans struct megasas_dcmd_frame *dcmd;
26016447Ssusans
26026447Ssusans if (!(cmd = get_mfi_pkt(instance)))
26036447Ssusans return;
26046447Ssusans
26056447Ssusans dcmd = &cmd->frame->dcmd;
26066447Ssusans
26077562SSusan.Scheufele@Sun.COM (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
26086447Ssusans
26096447Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
26106447Ssusans dcmd->cmd_status = 0x0;
26116447Ssusans dcmd->sge_count = 0;
26126447Ssusans dcmd->flags = MFI_FRAME_DIR_NONE;
26136447Ssusans dcmd->timeout = 0;
26146447Ssusans dcmd->data_xfer_len = 0;
26156447Ssusans dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
26166447Ssusans dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
26176447Ssusans
26186447Ssusans cmd->frame_count = 1;
26196447Ssusans
26206447Ssusans if (instance->func_ptr->issue_cmd_in_poll_mode(instance, cmd)) {
26216447Ssusans cmn_err(CE_WARN,
26226447Ssusans "flush_cache: failed to issue MFI_DCMD_CTRL_CACHE_FLUSH\n");
26236447Ssusans }
26247193Syw209021 con_log(CL_DLEVEL1, (CE_NOTE, "done"));
26256447Ssusans return_mfi_pkt(instance, cmd);
26267533SYu.Wu@Sun.COM (void) megasas_common_check(instance, cmd);
26276447Ssusans }
26286447Ssusans
26296447Ssusans /*
26306447Ssusans * service_mfi_aen- Completes an AEN command
26316447Ssusans * @instance: Adapter soft state
26326447Ssusans * @cmd: Command to be completed
26336447Ssusans *
26346447Ssusans */
26356447Ssusans static void
service_mfi_aen(struct megasas_instance * instance,struct megasas_cmd * cmd)26366447Ssusans service_mfi_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
26376447Ssusans {
26386447Ssusans uint32_t seq_num;
26396447Ssusans struct megasas_evt_detail *evt_detail =
26406447Ssusans (struct megasas_evt_detail *)instance->mfi_evt_detail_obj.buffer;
26416447Ssusans
26426447Ssusans cmd->cmd_status = cmd->frame->io.cmd_status;
26436447Ssusans
26446447Ssusans if (cmd->cmd_status == ENODATA) {
26456447Ssusans cmd->cmd_status = 0;
26466447Ssusans }
26476447Ssusans
26486447Ssusans /*
26496447Ssusans * log the MFI AEN event to the sysevent queue so that
26506447Ssusans * application will get noticed
26516447Ssusans */
26526447Ssusans if (ddi_log_sysevent(instance->dip, DDI_VENDOR_LSI, "LSIMEGA", "SAS",
26536447Ssusans NULL, NULL, DDI_NOSLEEP) != DDI_SUCCESS) {
26546447Ssusans int instance_no = ddi_get_instance(instance->dip);
26556447Ssusans con_log(CL_ANN, (CE_WARN,
26566447Ssusans "mega%d: Failed to log AEN event", instance_no));
26576447Ssusans }
26586447Ssusans
26596447Ssusans /* get copy of seq_num and class/locale for re-registration */
26606447Ssusans seq_num = evt_detail->seq_num;
26616447Ssusans seq_num++;
26626447Ssusans (void) memset(instance->mfi_evt_detail_obj.buffer, 0,
26636447Ssusans sizeof (struct megasas_evt_detail));
26646447Ssusans
26656447Ssusans cmd->frame->dcmd.cmd_status = 0x0;
26666447Ssusans cmd->frame->dcmd.mbox.w[0] = seq_num;
26676447Ssusans
26686447Ssusans instance->aen_seq_num = seq_num;
26696447Ssusans
26706447Ssusans cmd->frame_count = 1;
26716447Ssusans
26726447Ssusans /* Issue the aen registration frame */
26736447Ssusans instance->func_ptr->issue_cmd(cmd, instance);
26746447Ssusans }
26756447Ssusans
26766447Ssusans /*
26776447Ssusans * complete_cmd_in_sync_mode - Completes an internal command
26786447Ssusans * @instance: Adapter soft state
26796447Ssusans * @cmd: Command to be completed
26806447Ssusans *
26816447Ssusans * The issue_cmd_in_sync_mode() function waits for a command to complete
26826447Ssusans * after it issues a command. This function wakes up that waiting routine by
26836447Ssusans * calling wake_up() on the wait queue.
26846447Ssusans */
26856447Ssusans static void
complete_cmd_in_sync_mode(struct megasas_instance * instance,struct megasas_cmd * cmd)26866447Ssusans complete_cmd_in_sync_mode(struct megasas_instance *instance,
26876447Ssusans struct megasas_cmd *cmd)
26886447Ssusans {
26896447Ssusans cmd->cmd_status = cmd->frame->io.cmd_status;
26906447Ssusans
26916447Ssusans cmd->sync_cmd = MEGASAS_FALSE;
26926447Ssusans
26936447Ssusans if (cmd->cmd_status == ENODATA) {
26946447Ssusans cmd->cmd_status = 0;
26956447Ssusans }
26966447Ssusans
26976447Ssusans cv_broadcast(&instance->int_cmd_cv);
26986447Ssusans }
26996447Ssusans
27006447Ssusans /*
27016447Ssusans * megasas_softintr - The Software ISR
27026447Ssusans * @param arg : HBA soft state
27036447Ssusans *
27046447Ssusans * called from high-level interrupt if hi-level interrupt are not there,
27056447Ssusans * otherwise triggered as a soft interrupt
27066447Ssusans */
27076447Ssusans static uint_t
megasas_softintr(struct megasas_instance * instance)27087562SSusan.Scheufele@Sun.COM megasas_softintr(struct megasas_instance *instance)
27096447Ssusans {
27106447Ssusans struct scsi_pkt *pkt;
27116447Ssusans struct scsa_cmd *acmd;
27126447Ssusans struct megasas_cmd *cmd;
27136447Ssusans struct mlist_head *pos, *next;
27146447Ssusans mlist_t process_list;
27156447Ssusans struct megasas_header *hdr;
27167562SSusan.Scheufele@Sun.COM struct scsi_arq_status *arqstat;
27176447Ssusans
27186447Ssusans con_log(CL_ANN1, (CE_CONT, "megasas_softintr called"));
27196447Ssusans
27207562SSusan.Scheufele@Sun.COM ASSERT(instance);
27216447Ssusans mutex_enter(&instance->completed_pool_mtx);
27226447Ssusans
27236447Ssusans if (mlist_empty(&instance->completed_pool_list)) {
27246447Ssusans mutex_exit(&instance->completed_pool_mtx);
27256447Ssusans return (DDI_INTR_UNCLAIMED);
27266447Ssusans }
27276447Ssusans
27286447Ssusans instance->softint_running = 1;
27296447Ssusans
27306447Ssusans INIT_LIST_HEAD(&process_list);
27316447Ssusans mlist_splice(&instance->completed_pool_list, &process_list);
27326447Ssusans INIT_LIST_HEAD(&instance->completed_pool_list);
27336447Ssusans
27346447Ssusans mutex_exit(&instance->completed_pool_mtx);
27356447Ssusans
27366447Ssusans /* perform all callbacks first, before releasing the SCBs */
27376447Ssusans mlist_for_each_safe(pos, next, &process_list) {
27386447Ssusans cmd = mlist_entry(pos, struct megasas_cmd, list);
27396447Ssusans
27406447Ssusans /* syncronize the Cmd frame for the controller */
27416447Ssusans (void) ddi_dma_sync(cmd->frame_dma_obj.dma_handle,
27426447Ssusans 0, 0, DDI_DMA_SYNC_FORCPU);
27437533SYu.Wu@Sun.COM
27447533SYu.Wu@Sun.COM if (megasas_check_dma_handle(cmd->frame_dma_obj.dma_handle) !=
27457533SYu.Wu@Sun.COM DDI_SUCCESS) {
27467533SYu.Wu@Sun.COM megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
27477533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
27487533SYu.Wu@Sun.COM return (DDI_INTR_UNCLAIMED);
27497533SYu.Wu@Sun.COM }
27507533SYu.Wu@Sun.COM
27516447Ssusans hdr = &cmd->frame->hdr;
27526447Ssusans
27536447Ssusans /* remove the internal command from the process list */
27546447Ssusans mlist_del_init(&cmd->list);
27556447Ssusans
27566447Ssusans switch (hdr->cmd) {
27576447Ssusans case MFI_CMD_OP_PD_SCSI:
27586447Ssusans case MFI_CMD_OP_LD_SCSI:
27596447Ssusans case MFI_CMD_OP_LD_READ:
27606447Ssusans case MFI_CMD_OP_LD_WRITE:
27616447Ssusans /*
27626447Ssusans * MFI_CMD_OP_PD_SCSI and MFI_CMD_OP_LD_SCSI
27636447Ssusans * could have been issued either through an
27646447Ssusans * IO path or an IOCTL path. If it was via IOCTL,
27656447Ssusans * we will send it to internal completion.
27666447Ssusans */
27676447Ssusans if (cmd->sync_cmd == MEGASAS_TRUE) {
27686447Ssusans complete_cmd_in_sync_mode(instance, cmd);
27696447Ssusans break;
27706447Ssusans }
27716447Ssusans
27726447Ssusans /* regular commands */
27736447Ssusans acmd = cmd->cmd;
27746447Ssusans pkt = CMD2PKT(acmd);
27756447Ssusans
27766447Ssusans if (acmd->cmd_flags & CFLAG_DMAVALID) {
27776447Ssusans if (acmd->cmd_flags & CFLAG_CONSISTENT) {
27786447Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle,
27796447Ssusans acmd->cmd_dma_offset,
27806447Ssusans acmd->cmd_dma_len,
27816447Ssusans DDI_DMA_SYNC_FORCPU);
27826447Ssusans }
27836447Ssusans }
27846447Ssusans
27856447Ssusans pkt->pkt_reason = CMD_CMPLT;
27866447Ssusans pkt->pkt_statistics = 0;
27877193Syw209021 pkt->pkt_state = STATE_GOT_BUS
27887193Syw209021 | STATE_GOT_TARGET | STATE_SENT_CMD
27897193Syw209021 | STATE_XFERRED_DATA | STATE_GOT_STATUS;
27906447Ssusans
27916447Ssusans con_log(CL_ANN1, (CE_CONT,
27926447Ssusans "CDB[0] = %x completed for %s: size %lx context %x",
27936447Ssusans pkt->pkt_cdbp[0], ((acmd->islogical) ? "LD" : "PD"),
27946447Ssusans acmd->cmd_dmacount, hdr->context));
27956447Ssusans
27966447Ssusans if (pkt->pkt_cdbp[0] == SCMD_INQUIRY) {
27976447Ssusans struct scsi_inquiry *inq;
27986447Ssusans
27996447Ssusans if (acmd->cmd_dmacount != 0) {
28006447Ssusans bp_mapin(acmd->cmd_buf);
28016447Ssusans inq = (struct scsi_inquiry *)
28026447Ssusans acmd->cmd_buf->b_un.b_addr;
28036447Ssusans
28046447Ssusans /* don't expose physical drives to OS */
28056447Ssusans if (acmd->islogical &&
28066447Ssusans (hdr->cmd_status == MFI_STAT_OK)) {
28076447Ssusans display_scsi_inquiry(
28086447Ssusans (caddr_t)inq);
28096447Ssusans } else if ((hdr->cmd_status ==
28106447Ssusans MFI_STAT_OK) && inq->inq_dtype ==
28116447Ssusans DTYPE_DIRECT) {
28126447Ssusans
28136447Ssusans display_scsi_inquiry(
28146447Ssusans (caddr_t)inq);
28156447Ssusans
28166447Ssusans /* for physical disk */
28176447Ssusans hdr->cmd_status =
28186447Ssusans MFI_STAT_DEVICE_NOT_FOUND;
28196447Ssusans }
28206447Ssusans }
28216447Ssusans }
28226447Ssusans
28236447Ssusans switch (hdr->cmd_status) {
28246447Ssusans case MFI_STAT_OK:
28256447Ssusans pkt->pkt_scbp[0] = STATUS_GOOD;
28266447Ssusans break;
28276447Ssusans case MFI_STAT_LD_CC_IN_PROGRESS:
28286447Ssusans case MFI_STAT_LD_RECON_IN_PROGRESS:
28296447Ssusans /* SJ - these are not correct way */
28306447Ssusans pkt->pkt_scbp[0] = STATUS_GOOD;
28316447Ssusans break;
28327193Syw209021 case MFI_STAT_LD_INIT_IN_PROGRESS:
28337193Syw209021 con_log(CL_ANN,
28347193Syw209021 (CE_WARN, "Initialization in Progress"));
28357193Syw209021 pkt->pkt_reason = CMD_TRAN_ERR;
28367193Syw209021
28377193Syw209021 break;
28386447Ssusans case MFI_STAT_SCSI_DONE_WITH_ERROR:
28396447Ssusans con_log(CL_ANN1, (CE_CONT, "scsi_done error"));
28407193Syw209021
28417193Syw209021 pkt->pkt_reason = CMD_CMPLT;
28427193Syw209021 ((struct scsi_status *)
28437193Syw209021 pkt->pkt_scbp)->sts_chk = 1;
28447193Syw209021
28457193Syw209021 if (pkt->pkt_cdbp[0] == SCMD_TEST_UNIT_READY) {
28467193Syw209021
28477193Syw209021 con_log(CL_ANN,
28487193Syw209021 (CE_WARN, "TEST_UNIT_READY fail"));
28497193Syw209021
28506447Ssusans } else {
28517193Syw209021 pkt->pkt_state |= STATE_ARQ_DONE;
28527193Syw209021 arqstat = (void *)(pkt->pkt_scbp);
28537193Syw209021 arqstat->sts_rqpkt_reason = CMD_CMPLT;
28547193Syw209021 arqstat->sts_rqpkt_resid = 0;
28557193Syw209021 arqstat->sts_rqpkt_state |=
28567193Syw209021 STATE_GOT_BUS | STATE_GOT_TARGET
28577193Syw209021 | STATE_SENT_CMD
28587193Syw209021 | STATE_XFERRED_DATA;
28597193Syw209021 *(uint8_t *)&arqstat->sts_rqpkt_status =
28607193Syw209021 STATUS_GOOD;
28617193Syw209021
28627193Syw209021 bcopy(cmd->sense,
28637193Syw209021 &(arqstat->sts_sensedata),
28647562SSusan.Scheufele@Sun.COM acmd->cmd_scblen -
28657193Syw209021 offsetof(struct scsi_arq_status,
28667193Syw209021 sts_sensedata));
28676447Ssusans }
28686447Ssusans break;
28697193Syw209021 case MFI_STAT_LD_OFFLINE:
28706447Ssusans case MFI_STAT_DEVICE_NOT_FOUND:
28716447Ssusans con_log(CL_ANN1, (CE_CONT,
28726447Ssusans "device not found error"));
28736447Ssusans pkt->pkt_reason = CMD_DEV_GONE;
28746447Ssusans pkt->pkt_statistics = STAT_DISCON;
28756447Ssusans break;
28767193Syw209021 case MFI_STAT_LD_LBA_OUT_OF_RANGE:
28777193Syw209021 pkt->pkt_state |= STATE_ARQ_DONE;
28787193Syw209021 pkt->pkt_reason = CMD_CMPLT;
28796447Ssusans ((struct scsi_status *)
28807193Syw209021 pkt->pkt_scbp)->sts_chk = 1;
28817193Syw209021
28827193Syw209021 arqstat = (void *)(pkt->pkt_scbp);
28837193Syw209021 arqstat->sts_rqpkt_reason = CMD_CMPLT;
28847193Syw209021 arqstat->sts_rqpkt_resid = 0;
28857193Syw209021 arqstat->sts_rqpkt_state |= STATE_GOT_BUS
28867193Syw209021 | STATE_GOT_TARGET | STATE_SENT_CMD
28877193Syw209021 | STATE_XFERRED_DATA;
28887193Syw209021 *(uint8_t *)&arqstat->sts_rqpkt_status =
28897193Syw209021 STATUS_GOOD;
28907193Syw209021
28917193Syw209021 arqstat->sts_sensedata.es_valid = 1;
28927193Syw209021 arqstat->sts_sensedata.es_key =
28937193Syw209021 KEY_ILLEGAL_REQUEST;
28947193Syw209021 arqstat->sts_sensedata.es_class =
28957193Syw209021 CLASS_EXTENDED_SENSE;
28967193Syw209021
28977193Syw209021 /*
28987193Syw209021 * LOGICAL BLOCK ADDRESS OUT OF RANGE:
28997193Syw209021 * ASC: 0x21h; ASCQ: 0x00h;
29007193Syw209021 */
29017193Syw209021 arqstat->sts_sensedata.es_add_code = 0x21;
29027193Syw209021 arqstat->sts_sensedata.es_qual_code = 0x00;
29037193Syw209021
29047193Syw209021 break;
29057193Syw209021
29067193Syw209021 default:
29077193Syw209021 con_log(CL_ANN, (CE_CONT, "Unknown status!"));
29087193Syw209021 pkt->pkt_reason = CMD_TRAN_ERR;
29097193Syw209021
29106447Ssusans break;
29116447Ssusans }
29126447Ssusans
29136447Ssusans atomic_add_16(&instance->fw_outstanding, (-1));
29146447Ssusans
29156447Ssusans return_mfi_pkt(instance, cmd);
29167533SYu.Wu@Sun.COM
29177533SYu.Wu@Sun.COM (void) megasas_common_check(instance, cmd);
29187533SYu.Wu@Sun.COM
29197533SYu.Wu@Sun.COM if (acmd->cmd_dmahandle) {
29207533SYu.Wu@Sun.COM if (megasas_check_dma_handle(
29217533SYu.Wu@Sun.COM acmd->cmd_dmahandle) != DDI_SUCCESS) {
29227533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip,
29237533SYu.Wu@Sun.COM DDI_SERVICE_UNAFFECTED);
29247533SYu.Wu@Sun.COM pkt->pkt_reason = CMD_TRAN_ERR;
29257533SYu.Wu@Sun.COM pkt->pkt_statistics = 0;
29267533SYu.Wu@Sun.COM }
29277533SYu.Wu@Sun.COM }
29286447Ssusans
29296447Ssusans /* Call the callback routine */
29309106SSrivijitha.Dugganapalli@Sun.COM if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
29319106SSrivijitha.Dugganapalli@Sun.COM scsi_hba_pkt_comp(pkt);
29326447Ssusans }
29336447Ssusans
29346447Ssusans break;
29356447Ssusans case MFI_CMD_OP_SMP:
29366447Ssusans case MFI_CMD_OP_STP:
29376447Ssusans complete_cmd_in_sync_mode(instance, cmd);
29386447Ssusans break;
29396447Ssusans case MFI_CMD_OP_DCMD:
29406447Ssusans /* see if got an event notification */
29416447Ssusans if (cmd->frame->dcmd.opcode ==
29426447Ssusans MR_DCMD_CTRL_EVENT_WAIT) {
29436447Ssusans if ((instance->aen_cmd == cmd) &&
29446447Ssusans (instance->aen_cmd->abort_aen)) {
29456447Ssusans con_log(CL_ANN, (CE_WARN,
29466447Ssusans "megasas_softintr: "
29476447Ssusans "aborted_aen returned"));
29486447Ssusans } else {
29496447Ssusans service_mfi_aen(instance, cmd);
29508312SSusan.Scheufele@Sun.COM
29518312SSusan.Scheufele@Sun.COM atomic_add_16(&instance->fw_outstanding,
29528312SSusan.Scheufele@Sun.COM (-1));
29536447Ssusans }
29546447Ssusans } else {
29556447Ssusans complete_cmd_in_sync_mode(instance, cmd);
29566447Ssusans }
29576447Ssusans
29586447Ssusans break;
29596447Ssusans case MFI_CMD_OP_ABORT:
29606447Ssusans con_log(CL_ANN, (CE_WARN, "MFI_CMD_OP_ABORT complete"));
29616447Ssusans /*
29626447Ssusans * MFI_CMD_OP_ABORT successfully completed
29636447Ssusans * in the synchronous mode
29646447Ssusans */
29656447Ssusans complete_cmd_in_sync_mode(instance, cmd);
29666447Ssusans break;
29676447Ssusans default:
29687533SYu.Wu@Sun.COM megasas_fm_ereport(instance, DDI_FM_DEVICE_NO_RESPONSE);
29697533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
29707533SYu.Wu@Sun.COM
29717533SYu.Wu@Sun.COM if (cmd->pkt != NULL) {
29727533SYu.Wu@Sun.COM pkt = cmd->pkt;
29739106SSrivijitha.Dugganapalli@Sun.COM if ((pkt->pkt_flags & FLAG_NOINTR) == 0) {
29749106SSrivijitha.Dugganapalli@Sun.COM scsi_hba_pkt_comp(pkt);
29757533SYu.Wu@Sun.COM }
29767533SYu.Wu@Sun.COM }
29777533SYu.Wu@Sun.COM con_log(CL_ANN, (CE_WARN, "Cmd type unknown !!"));
29786447Ssusans break;
29796447Ssusans }
29806447Ssusans }
29816447Ssusans
29826447Ssusans instance->softint_running = 0;
29836447Ssusans
29846447Ssusans return (DDI_INTR_CLAIMED);
29856447Ssusans }
29866447Ssusans
29876447Ssusans /*
29886447Ssusans * mega_alloc_dma_obj
29896447Ssusans *
29906447Ssusans * Allocate the memory and other resources for an dma object.
29916447Ssusans */
29926447Ssusans static int
mega_alloc_dma_obj(struct megasas_instance * instance,dma_obj_t * obj)29936447Ssusans mega_alloc_dma_obj(struct megasas_instance *instance, dma_obj_t *obj)
29946447Ssusans {
29956447Ssusans int i;
29966447Ssusans size_t alen = 0;
29976447Ssusans uint_t cookie_cnt;
2998*11236SStephen.Hanson@Sun.COM struct ddi_device_acc_attr tmp_endian_attr;
2999*11236SStephen.Hanson@Sun.COM
3000*11236SStephen.Hanson@Sun.COM tmp_endian_attr = endian_attr;
3001*11236SStephen.Hanson@Sun.COM tmp_endian_attr.devacc_attr_access = DDI_DEFAULT_ACC;
30026447Ssusans i = ddi_dma_alloc_handle(instance->dip, &obj->dma_attr,
30036447Ssusans DDI_DMA_SLEEP, NULL, &obj->dma_handle);
30046447Ssusans if (i != DDI_SUCCESS) {
30056447Ssusans
30066447Ssusans switch (i) {
30076447Ssusans case DDI_DMA_BADATTR :
30086447Ssusans con_log(CL_ANN, (CE_WARN,
30096447Ssusans "Failed ddi_dma_alloc_handle- Bad atrib"));
30106447Ssusans break;
30116447Ssusans case DDI_DMA_NORESOURCES :
30126447Ssusans con_log(CL_ANN, (CE_WARN,
30136447Ssusans "Failed ddi_dma_alloc_handle- No Resources"));
30146447Ssusans break;
30156447Ssusans default :
30166447Ssusans con_log(CL_ANN, (CE_WARN,
30176447Ssusans "Failed ddi_dma_alloc_handle :unknown %d", i));
30186447Ssusans break;
30196447Ssusans }
30206447Ssusans
30216447Ssusans return (-1);
30226447Ssusans }
30236447Ssusans
3024*11236SStephen.Hanson@Sun.COM if ((ddi_dma_mem_alloc(obj->dma_handle, obj->size, &tmp_endian_attr,
30256447Ssusans DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
30266447Ssusans &obj->buffer, &alen, &obj->acc_handle) != DDI_SUCCESS) ||
30276447Ssusans alen < obj->size) {
30286447Ssusans
30296447Ssusans ddi_dma_free_handle(&obj->dma_handle);
30306447Ssusans
30316447Ssusans con_log(CL_ANN, (CE_WARN, "Failed : ddi_dma_mem_alloc"));
30326447Ssusans
30336447Ssusans return (-1);
30346447Ssusans }
30356447Ssusans
30366447Ssusans if (ddi_dma_addr_bind_handle(obj->dma_handle, NULL, obj->buffer,
30376447Ssusans obj->size, DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
30386447Ssusans NULL, &obj->dma_cookie[0], &cookie_cnt) != DDI_SUCCESS) {
30396447Ssusans
30406447Ssusans ddi_dma_mem_free(&obj->acc_handle);
30416447Ssusans ddi_dma_free_handle(&obj->dma_handle);
30426447Ssusans
30436447Ssusans con_log(CL_ANN, (CE_WARN, "Failed : ddi_dma_addr_bind_handle"));
30446447Ssusans
30456447Ssusans return (-1);
30466447Ssusans }
30476447Ssusans
30487533SYu.Wu@Sun.COM if (megasas_check_dma_handle(obj->dma_handle) != DDI_SUCCESS) {
30497533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
30507533SYu.Wu@Sun.COM return (-1);
30517533SYu.Wu@Sun.COM }
30527533SYu.Wu@Sun.COM
30537533SYu.Wu@Sun.COM if (megasas_check_acc_handle(obj->acc_handle) != DDI_SUCCESS) {
30547533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_LOST);
30557533SYu.Wu@Sun.COM return (-1);
30567533SYu.Wu@Sun.COM }
30577533SYu.Wu@Sun.COM
30586447Ssusans return (cookie_cnt);
30596447Ssusans }
30606447Ssusans
30616447Ssusans /*
30627533SYu.Wu@Sun.COM * mega_free_dma_obj(struct megasas_instance *, dma_obj_t)
30636447Ssusans *
30646447Ssusans * De-allocate the memory and other resources for an dma object, which must
30656447Ssusans * have been alloated by a previous call to mega_alloc_dma_obj()
30666447Ssusans */
30677533SYu.Wu@Sun.COM static int
mega_free_dma_obj(struct megasas_instance * instance,dma_obj_t obj)30687533SYu.Wu@Sun.COM mega_free_dma_obj(struct megasas_instance *instance, dma_obj_t obj)
30696447Ssusans {
30707533SYu.Wu@Sun.COM
30717533SYu.Wu@Sun.COM if (megasas_check_dma_handle(obj.dma_handle) != DDI_SUCCESS) {
30727533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
30737533SYu.Wu@Sun.COM return (DDI_FAILURE);
30747533SYu.Wu@Sun.COM }
30757533SYu.Wu@Sun.COM
30767533SYu.Wu@Sun.COM if (megasas_check_acc_handle(obj.acc_handle) != DDI_SUCCESS) {
30777533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
30787533SYu.Wu@Sun.COM return (DDI_FAILURE);
30797533SYu.Wu@Sun.COM }
30807533SYu.Wu@Sun.COM
30816447Ssusans (void) ddi_dma_unbind_handle(obj.dma_handle);
30826447Ssusans ddi_dma_mem_free(&obj.acc_handle);
30836447Ssusans ddi_dma_free_handle(&obj.dma_handle);
30847533SYu.Wu@Sun.COM
30857533SYu.Wu@Sun.COM return (DDI_SUCCESS);
30866447Ssusans }
30876447Ssusans
30886447Ssusans /*
30896447Ssusans * megasas_dma_alloc(instance_t *, struct scsi_pkt *, struct buf *,
30906447Ssusans * int, int (*)())
30916447Ssusans *
30926447Ssusans * Allocate dma resources for a new scsi command
30936447Ssusans */
30946447Ssusans static int
megasas_dma_alloc(struct megasas_instance * instance,struct scsi_pkt * pkt,struct buf * bp,int flags,int (* callback)())30956447Ssusans megasas_dma_alloc(struct megasas_instance *instance, struct scsi_pkt *pkt,
30966447Ssusans struct buf *bp, int flags, int (*callback)())
30976447Ssusans {
30986447Ssusans int dma_flags;
30996447Ssusans int (*cb)(caddr_t);
31006447Ssusans int i;
31016447Ssusans
31026447Ssusans ddi_dma_attr_t tmp_dma_attr = megasas_generic_dma_attr;
31036447Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
31046447Ssusans
31056447Ssusans acmd->cmd_buf = bp;
31066447Ssusans
31076447Ssusans if (bp->b_flags & B_READ) {
31086447Ssusans acmd->cmd_flags &= ~CFLAG_DMASEND;
31096447Ssusans dma_flags = DDI_DMA_READ;
31106447Ssusans } else {
31116447Ssusans acmd->cmd_flags |= CFLAG_DMASEND;
31126447Ssusans dma_flags = DDI_DMA_WRITE;
31136447Ssusans }
31146447Ssusans
31156447Ssusans if (flags & PKT_CONSISTENT) {
31166447Ssusans acmd->cmd_flags |= CFLAG_CONSISTENT;
31176447Ssusans dma_flags |= DDI_DMA_CONSISTENT;
31186447Ssusans }
31196447Ssusans
31206447Ssusans if (flags & PKT_DMA_PARTIAL) {
31216447Ssusans dma_flags |= DDI_DMA_PARTIAL;
31226447Ssusans }
31236447Ssusans
31246447Ssusans dma_flags |= DDI_DMA_REDZONE;
31256447Ssusans
31266447Ssusans cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
31276447Ssusans
31286447Ssusans tmp_dma_attr.dma_attr_sgllen = instance->max_num_sge;
31298164SYu.Wu@Sun.COM tmp_dma_attr.dma_attr_addr_hi = 0xffffffffffffffffull;
31306447Ssusans
31316447Ssusans if ((i = ddi_dma_alloc_handle(instance->dip, &tmp_dma_attr,
31326447Ssusans cb, 0, &acmd->cmd_dmahandle)) != DDI_SUCCESS) {
31336447Ssusans switch (i) {
31346447Ssusans case DDI_DMA_BADATTR:
31356447Ssusans bioerror(bp, EFAULT);
31366447Ssusans return (-1);
31376447Ssusans
31386447Ssusans case DDI_DMA_NORESOURCES:
31396447Ssusans bioerror(bp, 0);
31406447Ssusans return (-1);
31416447Ssusans
31426447Ssusans default:
31436447Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_alloc_handle: "
31446447Ssusans "0x%x impossible\n", i));
31457562SSusan.Scheufele@Sun.COM bioerror(bp, EFAULT);
31467562SSusan.Scheufele@Sun.COM return (-1);
31476447Ssusans }
31486447Ssusans }
31496447Ssusans
31506447Ssusans i = ddi_dma_buf_bind_handle(acmd->cmd_dmahandle, bp, dma_flags,
31516447Ssusans cb, 0, &acmd->cmd_dmacookies[0], &acmd->cmd_ncookies);
31526447Ssusans
31536447Ssusans switch (i) {
31546447Ssusans case DDI_DMA_PARTIAL_MAP:
31556447Ssusans if ((dma_flags & DDI_DMA_PARTIAL) == 0) {
31566447Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_buf_bind_handle: "
31576447Ssusans "DDI_DMA_PARTIAL_MAP impossible\n"));
31587562SSusan.Scheufele@Sun.COM goto no_dma_cookies;
31596447Ssusans }
31606447Ssusans
31616447Ssusans if (ddi_dma_numwin(acmd->cmd_dmahandle, &acmd->cmd_nwin) ==
31626447Ssusans DDI_FAILURE) {
31636447Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_numwin failed\n"));
31647562SSusan.Scheufele@Sun.COM goto no_dma_cookies;
31656447Ssusans }
31666447Ssusans
31676447Ssusans if (ddi_dma_getwin(acmd->cmd_dmahandle, acmd->cmd_curwin,
31686447Ssusans &acmd->cmd_dma_offset, &acmd->cmd_dma_len,
31696447Ssusans &acmd->cmd_dmacookies[0], &acmd->cmd_ncookies) ==
31706447Ssusans DDI_FAILURE) {
31716447Ssusans
31726447Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_getwin failed\n"));
31737562SSusan.Scheufele@Sun.COM goto no_dma_cookies;
31746447Ssusans }
31756447Ssusans
31766447Ssusans goto get_dma_cookies;
31776447Ssusans case DDI_DMA_MAPPED:
31786447Ssusans acmd->cmd_nwin = 1;
31796447Ssusans acmd->cmd_dma_len = 0;
31806447Ssusans acmd->cmd_dma_offset = 0;
31816447Ssusans
31826447Ssusans get_dma_cookies:
31836447Ssusans i = 0;
31846447Ssusans acmd->cmd_dmacount = 0;
31856447Ssusans for (;;) {
31866447Ssusans acmd->cmd_dmacount +=
31876447Ssusans acmd->cmd_dmacookies[i++].dmac_size;
31886447Ssusans
31896447Ssusans if (i == instance->max_num_sge ||
31906447Ssusans i == acmd->cmd_ncookies)
31916447Ssusans break;
31926447Ssusans
31936447Ssusans ddi_dma_nextcookie(acmd->cmd_dmahandle,
31946447Ssusans &acmd->cmd_dmacookies[i]);
31956447Ssusans }
31966447Ssusans
31976447Ssusans acmd->cmd_cookie = i;
31986447Ssusans acmd->cmd_cookiecnt = i;
31996447Ssusans
32006447Ssusans acmd->cmd_flags |= CFLAG_DMAVALID;
32016447Ssusans
32026447Ssusans if (bp->b_bcount >= acmd->cmd_dmacount) {
32036447Ssusans pkt->pkt_resid = bp->b_bcount - acmd->cmd_dmacount;
32046447Ssusans } else {
32056447Ssusans pkt->pkt_resid = 0;
32066447Ssusans }
32076447Ssusans
32086447Ssusans return (0);
32096447Ssusans case DDI_DMA_NORESOURCES:
32106447Ssusans bioerror(bp, 0);
32116447Ssusans break;
32126447Ssusans case DDI_DMA_NOMAPPING:
32136447Ssusans bioerror(bp, EFAULT);
32146447Ssusans break;
32156447Ssusans case DDI_DMA_TOOBIG:
32166447Ssusans bioerror(bp, EINVAL);
32176447Ssusans break;
32186447Ssusans case DDI_DMA_INUSE:
32196447Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_buf_bind_handle:"
32206447Ssusans " DDI_DMA_INUSE impossible\n"));
32216447Ssusans break;
32226447Ssusans default:
32236447Ssusans con_log(CL_ANN, (CE_PANIC, "ddi_dma_buf_bind_handle: "
32246447Ssusans "0x%x impossible\n", i));
32256447Ssusans break;
32266447Ssusans }
32276447Ssusans
32287562SSusan.Scheufele@Sun.COM no_dma_cookies:
32296447Ssusans ddi_dma_free_handle(&acmd->cmd_dmahandle);
32306447Ssusans acmd->cmd_dmahandle = NULL;
32316447Ssusans acmd->cmd_flags &= ~CFLAG_DMAVALID;
32326447Ssusans return (-1);
32336447Ssusans }
32346447Ssusans
32356447Ssusans /*
32366447Ssusans * megasas_dma_move(struct megasas_instance *, struct scsi_pkt *, struct buf *)
32376447Ssusans *
32386447Ssusans * move dma resources to next dma window
32396447Ssusans *
32406447Ssusans */
32416447Ssusans static int
megasas_dma_move(struct megasas_instance * instance,struct scsi_pkt * pkt,struct buf * bp)32426447Ssusans megasas_dma_move(struct megasas_instance *instance, struct scsi_pkt *pkt,
32436447Ssusans struct buf *bp)
32446447Ssusans {
32456447Ssusans int i = 0;
32466447Ssusans
32476447Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
32486447Ssusans
32496447Ssusans /*
32506447Ssusans * If there are no more cookies remaining in this window,
32516447Ssusans * must move to the next window first.
32526447Ssusans */
32536447Ssusans if (acmd->cmd_cookie == acmd->cmd_ncookies) {
32546447Ssusans if (acmd->cmd_curwin == acmd->cmd_nwin && acmd->cmd_nwin == 1) {
32556447Ssusans return (0);
32566447Ssusans }
32576447Ssusans
32586447Ssusans /* at last window, cannot move */
32596447Ssusans if (++acmd->cmd_curwin >= acmd->cmd_nwin) {
32606447Ssusans return (-1);
32616447Ssusans }
32626447Ssusans
32636447Ssusans if (ddi_dma_getwin(acmd->cmd_dmahandle, acmd->cmd_curwin,
32646447Ssusans &acmd->cmd_dma_offset, &acmd->cmd_dma_len,
32656447Ssusans &acmd->cmd_dmacookies[0], &acmd->cmd_ncookies) ==
32666447Ssusans DDI_FAILURE) {
32676447Ssusans return (-1);
32686447Ssusans }
32696447Ssusans
32706447Ssusans acmd->cmd_cookie = 0;
32716447Ssusans } else {
32726447Ssusans /* still more cookies in this window - get the next one */
32736447Ssusans ddi_dma_nextcookie(acmd->cmd_dmahandle,
32746447Ssusans &acmd->cmd_dmacookies[0]);
32756447Ssusans }
32766447Ssusans
32776447Ssusans /* get remaining cookies in this window, up to our maximum */
32786447Ssusans for (;;) {
32796447Ssusans acmd->cmd_dmacount += acmd->cmd_dmacookies[i++].dmac_size;
32806447Ssusans acmd->cmd_cookie++;
32816447Ssusans
32826447Ssusans if (i == instance->max_num_sge ||
32836447Ssusans acmd->cmd_cookie == acmd->cmd_ncookies) {
32846447Ssusans break;
32856447Ssusans }
32866447Ssusans
32876447Ssusans ddi_dma_nextcookie(acmd->cmd_dmahandle,
32886447Ssusans &acmd->cmd_dmacookies[i]);
32896447Ssusans }
32906447Ssusans
32916447Ssusans acmd->cmd_cookiecnt = i;
32926447Ssusans
32936447Ssusans if (bp->b_bcount >= acmd->cmd_dmacount) {
32946447Ssusans pkt->pkt_resid = bp->b_bcount - acmd->cmd_dmacount;
32956447Ssusans } else {
32966447Ssusans pkt->pkt_resid = 0;
32976447Ssusans }
32986447Ssusans
32996447Ssusans return (0);
33006447Ssusans }
33016447Ssusans
33026447Ssusans /*
33036447Ssusans * build_cmd
33046447Ssusans */
33056447Ssusans static struct megasas_cmd *
build_cmd(struct megasas_instance * instance,struct scsi_address * ap,struct scsi_pkt * pkt,uchar_t * cmd_done)33066447Ssusans build_cmd(struct megasas_instance *instance, struct scsi_address *ap,
33076447Ssusans struct scsi_pkt *pkt, uchar_t *cmd_done)
33086447Ssusans {
33096447Ssusans uint16_t flags = 0;
33106447Ssusans uint32_t i;
33116447Ssusans uint32_t context;
33126447Ssusans uint32_t sge_bytes;
33136447Ssusans
33146447Ssusans struct megasas_cmd *cmd;
33158164SYu.Wu@Sun.COM struct megasas_sge64 *mfi_sgl;
33166447Ssusans struct scsa_cmd *acmd = PKT2CMD(pkt);
33176447Ssusans struct megasas_pthru_frame *pthru;
33186447Ssusans struct megasas_io_frame *ldio;
33196447Ssusans
33206447Ssusans /* find out if this is logical or physical drive command. */
33216447Ssusans acmd->islogical = MEGADRV_IS_LOGICAL(ap);
33226447Ssusans acmd->device_id = MAP_DEVICE_ID(instance, ap);
33237193Syw209021 *cmd_done = 0;
33246447Ssusans
33256447Ssusans /* get the command packet */
33266447Ssusans if (!(cmd = get_mfi_pkt(instance))) {
33276447Ssusans return (NULL);
33286447Ssusans }
33296447Ssusans
33306447Ssusans cmd->pkt = pkt;
33316447Ssusans cmd->cmd = acmd;
33326447Ssusans
33336447Ssusans /* lets get the command directions */
33346447Ssusans if (acmd->cmd_flags & CFLAG_DMASEND) {
33356447Ssusans flags = MFI_FRAME_DIR_WRITE;
33366447Ssusans
33376447Ssusans if (acmd->cmd_flags & CFLAG_CONSISTENT) {
33386447Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle,
33396447Ssusans acmd->cmd_dma_offset, acmd->cmd_dma_len,
33406447Ssusans DDI_DMA_SYNC_FORDEV);
33416447Ssusans }
33426447Ssusans } else if (acmd->cmd_flags & ~CFLAG_DMASEND) {
33436447Ssusans flags = MFI_FRAME_DIR_READ;
33446447Ssusans
33456447Ssusans if (acmd->cmd_flags & CFLAG_CONSISTENT) {
33466447Ssusans (void) ddi_dma_sync(acmd->cmd_dmahandle,
33476447Ssusans acmd->cmd_dma_offset, acmd->cmd_dma_len,
33486447Ssusans DDI_DMA_SYNC_FORCPU);
33496447Ssusans }
33506447Ssusans } else {
33516447Ssusans flags = MFI_FRAME_DIR_NONE;
33526447Ssusans }
33536447Ssusans
33548164SYu.Wu@Sun.COM flags |= MFI_FRAME_SGL64;
33556447Ssusans
33566447Ssusans switch (pkt->pkt_cdbp[0]) {
33577193Syw209021
33587193Syw209021 /*
33597193Syw209021 * case SCMD_SYNCHRONIZE_CACHE:
33607193Syw209021 * flush_cache(instance);
33617193Syw209021 * return_mfi_pkt(instance, cmd);
33627193Syw209021 * *cmd_done = 1;
33637193Syw209021 *
33647193Syw209021 * return (NULL);
33657193Syw209021 */
33667193Syw209021
33676447Ssusans case SCMD_READ:
33686447Ssusans case SCMD_WRITE:
33696447Ssusans case SCMD_READ_G1:
33706447Ssusans case SCMD_WRITE_G1:
33716447Ssusans if (acmd->islogical) {
33726447Ssusans ldio = (struct megasas_io_frame *)cmd->frame;
33736447Ssusans
33746447Ssusans /*
33756447Ssusans * preare the Logical IO frame:
33766447Ssusans * 2nd bit is zero for all read cmds
33776447Ssusans */
33786447Ssusans ldio->cmd = (pkt->pkt_cdbp[0] & 0x02) ?
33796447Ssusans MFI_CMD_OP_LD_WRITE : MFI_CMD_OP_LD_READ;
33806447Ssusans ldio->cmd_status = 0x0;
33816447Ssusans ldio->scsi_status = 0x0;
33826447Ssusans ldio->target_id = acmd->device_id;
33836447Ssusans ldio->timeout = 0;
33846447Ssusans ldio->reserved_0 = 0;
33856447Ssusans ldio->pad_0 = 0;
33866447Ssusans ldio->flags = flags;
33877193Syw209021
33887193Syw209021 /* Initialize sense Information */
33897193Syw209021 bzero(cmd->sense, SENSE_LENGTH);
33907193Syw209021 ldio->sense_len = SENSE_LENGTH;
33917193Syw209021 ldio->sense_buf_phys_addr_hi = 0;
33927193Syw209021 ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
33937193Syw209021
33946447Ssusans ldio->start_lba_hi = 0;
33956447Ssusans ldio->access_byte = (acmd->cmd_cdblen != 6) ?
33966447Ssusans pkt->pkt_cdbp[1] : 0;
33976447Ssusans ldio->sge_count = acmd->cmd_cookiecnt;
33988164SYu.Wu@Sun.COM mfi_sgl = (struct megasas_sge64 *)&ldio->sgl;
33996447Ssusans
34006447Ssusans context = ldio->context;
34016447Ssusans
34026447Ssusans if (acmd->cmd_cdblen == CDB_GROUP0) {
34036447Ssusans ldio->lba_count = host_to_le16(
34046447Ssusans (uint16_t)(pkt->pkt_cdbp[4]));
34056447Ssusans
34066447Ssusans ldio->start_lba_lo = host_to_le32(
34076447Ssusans ((uint32_t)(pkt->pkt_cdbp[3])) |
34086447Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 8) |
34096447Ssusans ((uint32_t)((pkt->pkt_cdbp[1]) & 0x1F)
34106447Ssusans << 16));
34116447Ssusans } else if (acmd->cmd_cdblen == CDB_GROUP1) {
34126447Ssusans ldio->lba_count = host_to_le16(
34136447Ssusans ((uint16_t)(pkt->pkt_cdbp[8])) |
34146447Ssusans ((uint16_t)(pkt->pkt_cdbp[7]) << 8));
34156447Ssusans
34166447Ssusans ldio->start_lba_lo = host_to_le32(
34176447Ssusans ((uint32_t)(pkt->pkt_cdbp[5])) |
34186447Ssusans ((uint32_t)(pkt->pkt_cdbp[4]) << 8) |
34196447Ssusans ((uint32_t)(pkt->pkt_cdbp[3]) << 16) |
34206447Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 24));
34216447Ssusans } else if (acmd->cmd_cdblen == CDB_GROUP2) {
34226447Ssusans ldio->lba_count = host_to_le16(
34236447Ssusans ((uint16_t)(pkt->pkt_cdbp[9])) |
34246447Ssusans ((uint16_t)(pkt->pkt_cdbp[8]) << 8) |
34256447Ssusans ((uint16_t)(pkt->pkt_cdbp[7]) << 16) |
34266447Ssusans ((uint16_t)(pkt->pkt_cdbp[6]) << 24));
34276447Ssusans
34286447Ssusans ldio->start_lba_lo = host_to_le32(
34296447Ssusans ((uint32_t)(pkt->pkt_cdbp[5])) |
34306447Ssusans ((uint32_t)(pkt->pkt_cdbp[4]) << 8) |
34316447Ssusans ((uint32_t)(pkt->pkt_cdbp[3]) << 16) |
34326447Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 24));
34336447Ssusans } else if (acmd->cmd_cdblen == CDB_GROUP3) {
34346447Ssusans ldio->lba_count = host_to_le16(
34356447Ssusans ((uint16_t)(pkt->pkt_cdbp[13])) |
34366447Ssusans ((uint16_t)(pkt->pkt_cdbp[12]) << 8) |
34376447Ssusans ((uint16_t)(pkt->pkt_cdbp[11]) << 16) |
34386447Ssusans ((uint16_t)(pkt->pkt_cdbp[10]) << 24));
34396447Ssusans
34406447Ssusans ldio->start_lba_lo = host_to_le32(
34416447Ssusans ((uint32_t)(pkt->pkt_cdbp[9])) |
34426447Ssusans ((uint32_t)(pkt->pkt_cdbp[8]) << 8) |
34436447Ssusans ((uint32_t)(pkt->pkt_cdbp[7]) << 16) |
34446447Ssusans ((uint32_t)(pkt->pkt_cdbp[6]) << 24));
34456447Ssusans
34466447Ssusans ldio->start_lba_lo = host_to_le32(
34476447Ssusans ((uint32_t)(pkt->pkt_cdbp[5])) |
34486447Ssusans ((uint32_t)(pkt->pkt_cdbp[4]) << 8) |
34496447Ssusans ((uint32_t)(pkt->pkt_cdbp[3]) << 16) |
34506447Ssusans ((uint32_t)(pkt->pkt_cdbp[2]) << 24));
34516447Ssusans }
34526447Ssusans
34536447Ssusans break;
34546447Ssusans }
34556447Ssusans /* fall through For all non-rd/wr cmds */
34566447Ssusans default:
34576447Ssusans pthru = (struct megasas_pthru_frame *)cmd->frame;
34586447Ssusans
34596447Ssusans /* prepare the DCDB frame */
34606447Ssusans pthru->cmd = (acmd->islogical) ?
34616447Ssusans MFI_CMD_OP_LD_SCSI : MFI_CMD_OP_PD_SCSI;
34626447Ssusans pthru->cmd_status = 0x0;
34636447Ssusans pthru->scsi_status = 0x0;
34646447Ssusans pthru->target_id = acmd->device_id;
34656447Ssusans pthru->lun = 0;
34666447Ssusans pthru->cdb_len = acmd->cmd_cdblen;
34676447Ssusans pthru->timeout = 0;
34686447Ssusans pthru->flags = flags;
34696447Ssusans pthru->data_xfer_len = acmd->cmd_dmacount;
34706447Ssusans pthru->sge_count = acmd->cmd_cookiecnt;
34718164SYu.Wu@Sun.COM mfi_sgl = (struct megasas_sge64 *)&pthru->sgl;
34727193Syw209021
34737193Syw209021 bzero(cmd->sense, SENSE_LENGTH);
34747193Syw209021 pthru->sense_len = SENSE_LENGTH;
34756447Ssusans pthru->sense_buf_phys_addr_hi = 0;
34767193Syw209021 pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
34776447Ssusans
34786447Ssusans context = pthru->context;
34796447Ssusans
34806447Ssusans bcopy(pkt->pkt_cdbp, pthru->cdb, acmd->cmd_cdblen);
34816447Ssusans
34826447Ssusans break;
34836447Ssusans }
34846447Ssusans #ifdef lint
34856447Ssusans context = context;
34866447Ssusans #endif
34876447Ssusans /* bzero(mfi_sgl, sizeof (struct megasas_sge64) * MAX_SGL); */
34886447Ssusans
34896447Ssusans /* prepare the scatter-gather list for the firmware */
34906447Ssusans for (i = 0; i < acmd->cmd_cookiecnt; i++, mfi_sgl++) {
34916447Ssusans mfi_sgl->phys_addr = acmd->cmd_dmacookies[i].dmac_laddress;
34926447Ssusans mfi_sgl->length = acmd->cmd_dmacookies[i].dmac_size;
34936447Ssusans }
34946447Ssusans
34958164SYu.Wu@Sun.COM sge_bytes = sizeof (struct megasas_sge64)*acmd->cmd_cookiecnt;
34966447Ssusans
34976447Ssusans cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
34986447Ssusans ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
34996447Ssusans
35006447Ssusans if (cmd->frame_count >= 8) {
35016447Ssusans cmd->frame_count = 8;
35026447Ssusans }
35036447Ssusans
35046447Ssusans return (cmd);
35056447Ssusans }
35066447Ssusans
35076447Ssusans /*
35086447Ssusans * wait_for_outstanding - Wait for all outstanding cmds
35096447Ssusans * @instance: Adapter soft state
35106447Ssusans *
35116447Ssusans * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to
35126447Ssusans * complete all its outstanding commands. Returns error if one or more IOs
35136447Ssusans * are pending after this time period.
35146447Ssusans */
35156447Ssusans static int
wait_for_outstanding(struct megasas_instance * instance)35166447Ssusans wait_for_outstanding(struct megasas_instance *instance)
35176447Ssusans {
35186447Ssusans int i;
35196447Ssusans uint32_t wait_time = 90;
35206447Ssusans
35216447Ssusans for (i = 0; i < wait_time; i++) {
35226447Ssusans if (!instance->fw_outstanding) {
35236447Ssusans break;
35246447Ssusans }
35256447Ssusans
35267562SSusan.Scheufele@Sun.COM drv_usecwait(MILLISEC); /* wait for 1000 usecs */;
35276447Ssusans }
35286447Ssusans
35296447Ssusans if (instance->fw_outstanding) {
35306447Ssusans return (1);
35316447Ssusans }
35326447Ssusans
35337533SYu.Wu@Sun.COM ddi_fm_acc_err_clear(instance->regmap_handle, DDI_FME_VERSION);
35347533SYu.Wu@Sun.COM
35356447Ssusans return (0);
35366447Ssusans }
35376447Ssusans
35386447Ssusans /*
35396447Ssusans * issue_mfi_pthru
35406447Ssusans */
35416447Ssusans static int
issue_mfi_pthru(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)35426447Ssusans issue_mfi_pthru(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
35436447Ssusans struct megasas_cmd *cmd, int mode)
35446447Ssusans {
35456447Ssusans void *ubuf;
35466447Ssusans uint32_t kphys_addr = 0;
35476447Ssusans uint32_t xferlen = 0;
35486447Ssusans uint_t model;
35496447Ssusans
35506447Ssusans dma_obj_t pthru_dma_obj;
35516447Ssusans struct megasas_pthru_frame *kpthru;
35526447Ssusans struct megasas_pthru_frame *pthru;
35536447Ssusans
35546447Ssusans pthru = &cmd->frame->pthru;
35556447Ssusans kpthru = (struct megasas_pthru_frame *)&ioctl->frame[0];
35566447Ssusans
35576447Ssusans model = ddi_model_convert_from(mode & FMODELS);
35586447Ssusans if (model == DDI_MODEL_ILP32) {
35596447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_pthru: DDI_MODEL_LP32"));
35606447Ssusans
35616447Ssusans xferlen = kpthru->sgl.sge32[0].length;
35626447Ssusans
35636447Ssusans /* SJ! - ubuf needs to be virtual address. */
35646447Ssusans ubuf = (void *)(ulong_t)kpthru->sgl.sge32[0].phys_addr;
35656447Ssusans } else {
35666447Ssusans #ifdef _ILP32
35676447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_pthru: DDI_MODEL_LP32"));
35686447Ssusans xferlen = kpthru->sgl.sge32[0].length;
35696447Ssusans /* SJ! - ubuf needs to be virtual address. */
35706447Ssusans ubuf = (void *)(ulong_t)kpthru->sgl.sge32[0].phys_addr;
35716447Ssusans #else
35726447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_pthru: DDI_MODEL_LP64"));
35736447Ssusans xferlen = kpthru->sgl.sge64[0].length;
35746447Ssusans /* SJ! - ubuf needs to be virtual address. */
35756447Ssusans ubuf = (void *)(ulong_t)kpthru->sgl.sge64[0].phys_addr;
35766447Ssusans #endif
35776447Ssusans }
35786447Ssusans
35796447Ssusans if (xferlen) {
35806447Ssusans /* means IOCTL requires DMA */
35816447Ssusans /* allocate the data transfer buffer */
35826447Ssusans pthru_dma_obj.size = xferlen;
35836447Ssusans pthru_dma_obj.dma_attr = megasas_generic_dma_attr;
35847562SSusan.Scheufele@Sun.COM pthru_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
35857562SSusan.Scheufele@Sun.COM pthru_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
35866447Ssusans pthru_dma_obj.dma_attr.dma_attr_sgllen = 1;
35876447Ssusans pthru_dma_obj.dma_attr.dma_attr_align = 1;
35886447Ssusans
35896447Ssusans /* allocate kernel buffer for DMA */
35906447Ssusans if (mega_alloc_dma_obj(instance, &pthru_dma_obj) != 1) {
35916447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_pthru: "
35926447Ssusans "could not data transfer buffer alloc."));
35936447Ssusans return (DDI_FAILURE);
35946447Ssusans }
35956447Ssusans
35966447Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
35976447Ssusans if (kpthru->flags & MFI_FRAME_DIR_WRITE) {
35986447Ssusans if (ddi_copyin(ubuf, (void *)pthru_dma_obj.buffer,
35996447Ssusans xferlen, mode)) {
36006447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_pthru: "
36016447Ssusans "copy from user space failed\n"));
36026447Ssusans return (1);
36036447Ssusans }
36046447Ssusans }
36056447Ssusans
36066447Ssusans kphys_addr = pthru_dma_obj.dma_cookie[0].dmac_address;
36076447Ssusans }
36086447Ssusans
36096447Ssusans pthru->cmd = kpthru->cmd;
36106447Ssusans pthru->sense_len = kpthru->sense_len;
36116447Ssusans pthru->cmd_status = kpthru->cmd_status;
36126447Ssusans pthru->scsi_status = kpthru->scsi_status;
36136447Ssusans pthru->target_id = kpthru->target_id;
36146447Ssusans pthru->lun = kpthru->lun;
36156447Ssusans pthru->cdb_len = kpthru->cdb_len;
36166447Ssusans pthru->sge_count = kpthru->sge_count;
36176447Ssusans pthru->timeout = kpthru->timeout;
36186447Ssusans pthru->data_xfer_len = kpthru->data_xfer_len;
36196447Ssusans
36206447Ssusans pthru->sense_buf_phys_addr_hi = 0;
36216447Ssusans /* pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr; */
36226447Ssusans pthru->sense_buf_phys_addr_lo = 0;
36236447Ssusans
36246447Ssusans bcopy((void *)kpthru->cdb, (void *)pthru->cdb, pthru->cdb_len);
36256447Ssusans
36266447Ssusans pthru->flags = kpthru->flags & ~MFI_FRAME_SGL64;
36276447Ssusans pthru->sgl.sge32[0].length = xferlen;
36286447Ssusans pthru->sgl.sge32[0].phys_addr = kphys_addr;
36296447Ssusans
36306447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
36316447Ssusans cmd->frame_count = 1;
36326447Ssusans
36336447Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
36346447Ssusans con_log(CL_ANN, (CE_WARN,
36356447Ssusans "issue_mfi_pthru: fw_ioctl failed\n"));
36366447Ssusans } else {
36376447Ssusans if (xferlen && (kpthru->flags & MFI_FRAME_DIR_READ)) {
36386447Ssusans
36396447Ssusans if (ddi_copyout(pthru_dma_obj.buffer, ubuf,
36406447Ssusans xferlen, mode)) {
36416447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_pthru: "
36426447Ssusans "copy to user space failed\n"));
36436447Ssusans return (1);
36446447Ssusans }
36456447Ssusans }
36466447Ssusans }
36476447Ssusans
36486447Ssusans kpthru->cmd_status = pthru->cmd_status;
36496447Ssusans kpthru->scsi_status = pthru->scsi_status;
36506447Ssusans
36516447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_pthru: cmd_status %x, "
36526447Ssusans "scsi_status %x\n", pthru->cmd_status, pthru->scsi_status));
36536447Ssusans
36546447Ssusans if (xferlen) {
36556447Ssusans /* free kernel buffer */
36567533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, pthru_dma_obj) != DDI_SUCCESS)
36577533SYu.Wu@Sun.COM return (1);
36586447Ssusans }
36596447Ssusans
36606447Ssusans return (0);
36616447Ssusans }
36626447Ssusans
36636447Ssusans /*
36646447Ssusans * issue_mfi_dcmd
36656447Ssusans */
36666447Ssusans static int
issue_mfi_dcmd(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)36676447Ssusans issue_mfi_dcmd(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
36686447Ssusans struct megasas_cmd *cmd, int mode)
36696447Ssusans {
36706447Ssusans void *ubuf;
36716447Ssusans uint32_t kphys_addr = 0;
36726447Ssusans uint32_t xferlen = 0;
36736447Ssusans uint32_t model;
36746447Ssusans dma_obj_t dcmd_dma_obj;
36756447Ssusans struct megasas_dcmd_frame *kdcmd;
36766447Ssusans struct megasas_dcmd_frame *dcmd;
36776447Ssusans
36786447Ssusans dcmd = &cmd->frame->dcmd;
36796447Ssusans kdcmd = (struct megasas_dcmd_frame *)&ioctl->frame[0];
36806447Ssusans
36816447Ssusans model = ddi_model_convert_from(mode & FMODELS);
36826447Ssusans if (model == DDI_MODEL_ILP32) {
36836447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_dcmd: DDI_MODEL_ILP32"));
36846447Ssusans
36856447Ssusans xferlen = kdcmd->sgl.sge32[0].length;
36866447Ssusans
36876447Ssusans /* SJ! - ubuf needs to be virtual address. */
36886447Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
36896447Ssusans }
36906447Ssusans else
36916447Ssusans {
36926447Ssusans #ifdef _ILP32
36936447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_dcmd: DDI_MODEL_ILP32"));
36946447Ssusans xferlen = kdcmd->sgl.sge32[0].length;
36956447Ssusans /* SJ! - ubuf needs to be virtual address. */
36966447Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
36976447Ssusans #else
36986447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_dcmd: DDI_MODEL_LP64"));
36996447Ssusans xferlen = kdcmd->sgl.sge64[0].length;
37006447Ssusans /* SJ! - ubuf needs to be virtual address. */
37016447Ssusans ubuf = (void *)(ulong_t)dcmd->sgl.sge64[0].phys_addr;
37026447Ssusans #endif
37036447Ssusans }
37046447Ssusans if (xferlen) {
37056447Ssusans /* means IOCTL requires DMA */
37066447Ssusans /* allocate the data transfer buffer */
37076447Ssusans dcmd_dma_obj.size = xferlen;
37086447Ssusans dcmd_dma_obj.dma_attr = megasas_generic_dma_attr;
37097562SSusan.Scheufele@Sun.COM dcmd_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
37107562SSusan.Scheufele@Sun.COM dcmd_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
37116447Ssusans dcmd_dma_obj.dma_attr.dma_attr_sgllen = 1;
37126447Ssusans dcmd_dma_obj.dma_attr.dma_attr_align = 1;
37136447Ssusans
37146447Ssusans /* allocate kernel buffer for DMA */
37156447Ssusans if (mega_alloc_dma_obj(instance, &dcmd_dma_obj) != 1) {
37166447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: "
37176447Ssusans "could not data transfer buffer alloc."));
37186447Ssusans return (DDI_FAILURE);
37196447Ssusans }
37206447Ssusans
37216447Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
37226447Ssusans if (kdcmd->flags & MFI_FRAME_DIR_WRITE) {
37236447Ssusans if (ddi_copyin(ubuf, (void *)dcmd_dma_obj.buffer,
37246447Ssusans xferlen, mode)) {
37256447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: "
37266447Ssusans "copy from user space failed\n"));
37276447Ssusans return (1);
37286447Ssusans }
37296447Ssusans }
37306447Ssusans
37316447Ssusans kphys_addr = dcmd_dma_obj.dma_cookie[0].dmac_address;
37326447Ssusans }
37336447Ssusans
37346447Ssusans dcmd->cmd = kdcmd->cmd;
37356447Ssusans dcmd->cmd_status = kdcmd->cmd_status;
37366447Ssusans dcmd->sge_count = kdcmd->sge_count;
37376447Ssusans dcmd->timeout = kdcmd->timeout;
37386447Ssusans dcmd->data_xfer_len = kdcmd->data_xfer_len;
37396447Ssusans dcmd->opcode = kdcmd->opcode;
37406447Ssusans
37417562SSusan.Scheufele@Sun.COM bcopy((void *)kdcmd->mbox.b, (void *)dcmd->mbox.b, DCMD_MBOX_SZ);
37426447Ssusans
37436447Ssusans dcmd->flags = kdcmd->flags & ~MFI_FRAME_SGL64;
37446447Ssusans dcmd->sgl.sge32[0].length = xferlen;
37456447Ssusans dcmd->sgl.sge32[0].phys_addr = kphys_addr;
37466447Ssusans
37476447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
37486447Ssusans cmd->frame_count = 1;
37496447Ssusans
37506447Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
37516447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: fw_ioctl failed\n"));
37526447Ssusans } else {
37536447Ssusans if (xferlen && (kdcmd->flags & MFI_FRAME_DIR_READ)) {
37546447Ssusans
37556447Ssusans if (ddi_copyout(dcmd_dma_obj.buffer, ubuf,
37566447Ssusans xferlen, mode)) {
37576447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_dcmd: "
37586447Ssusans "copy to user space failed\n"));
37596447Ssusans return (1);
37606447Ssusans }
37616447Ssusans }
37626447Ssusans }
37636447Ssusans
37646447Ssusans kdcmd->cmd_status = dcmd->cmd_status;
37656447Ssusans
37666447Ssusans if (xferlen) {
37676447Ssusans /* free kernel buffer */
37687533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, dcmd_dma_obj) != DDI_SUCCESS)
37697533SYu.Wu@Sun.COM return (1);
37706447Ssusans }
37716447Ssusans
37726447Ssusans return (0);
37736447Ssusans }
37746447Ssusans
37756447Ssusans /*
37766447Ssusans * issue_mfi_smp
37776447Ssusans */
37786447Ssusans static int
issue_mfi_smp(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)37796447Ssusans issue_mfi_smp(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
37806447Ssusans struct megasas_cmd *cmd, int mode)
37816447Ssusans {
37826447Ssusans void *request_ubuf;
37836447Ssusans void *response_ubuf;
37846447Ssusans uint32_t request_xferlen = 0;
37856447Ssusans uint32_t response_xferlen = 0;
37866447Ssusans uint_t model;
37876447Ssusans dma_obj_t request_dma_obj;
37886447Ssusans dma_obj_t response_dma_obj;
37896447Ssusans struct megasas_smp_frame *ksmp;
37906447Ssusans struct megasas_smp_frame *smp;
37916447Ssusans struct megasas_sge32 *sge32;
37926447Ssusans #ifndef _ILP32
37936447Ssusans struct megasas_sge64 *sge64;
37946447Ssusans #endif
37956447Ssusans
37966447Ssusans smp = &cmd->frame->smp;
37976447Ssusans ksmp = (struct megasas_smp_frame *)&ioctl->frame[0];
37986447Ssusans
37996447Ssusans model = ddi_model_convert_from(mode & FMODELS);
38006447Ssusans if (model == DDI_MODEL_ILP32) {
38016447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: DDI_MODEL_ILP32"));
38026447Ssusans
38036447Ssusans sge32 = &ksmp->sgl[0].sge32[0];
38046447Ssusans response_xferlen = sge32[0].length;
38056447Ssusans request_xferlen = sge32[1].length;
38066447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_smp: "
38076447Ssusans "response_xferlen = %x, request_xferlen = %x",
38086447Ssusans response_xferlen, request_xferlen));
38096447Ssusans
38106447Ssusans /* SJ! - ubuf needs to be virtual address. */
38116447Ssusans
38126447Ssusans response_ubuf = (void *)(ulong_t)sge32[0].phys_addr;
38136447Ssusans request_ubuf = (void *)(ulong_t)sge32[1].phys_addr;
38146447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: "
38156447Ssusans "response_ubuf = %p, request_ubuf = %p",
38166447Ssusans response_ubuf, request_ubuf));
38176447Ssusans } else {
38186447Ssusans #ifdef _ILP32
38196447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: DDI_MODEL_ILP32"));
38206447Ssusans
38216447Ssusans sge32 = &ksmp->sgl[0].sge32[0];
38226447Ssusans response_xferlen = sge32[0].length;
38236447Ssusans request_xferlen = sge32[1].length;
38246447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_smp: "
38256447Ssusans "response_xferlen = %x, request_xferlen = %x",
38266447Ssusans response_xferlen, request_xferlen));
38276447Ssusans
38286447Ssusans /* SJ! - ubuf needs to be virtual address. */
38296447Ssusans
38306447Ssusans response_ubuf = (void *)(ulong_t)sge32[0].phys_addr;
38316447Ssusans request_ubuf = (void *)(ulong_t)sge32[1].phys_addr;
38326447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: "
38336447Ssusans "response_ubuf = %p, request_ubuf = %p",
38346447Ssusans response_ubuf, request_ubuf));
38356447Ssusans #else
38366447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: DDI_MODEL_LP64"));
38376447Ssusans
38386447Ssusans sge64 = &ksmp->sgl[0].sge64[0];
38396447Ssusans response_xferlen = sge64[0].length;
38406447Ssusans request_xferlen = sge64[1].length;
38416447Ssusans
38426447Ssusans /* SJ! - ubuf needs to be virtual address. */
38436447Ssusans response_ubuf = (void *)(ulong_t)sge64[0].phys_addr;
38446447Ssusans request_ubuf = (void *)(ulong_t)sge64[1].phys_addr;
38456447Ssusans #endif
38466447Ssusans }
38476447Ssusans if (request_xferlen) {
38486447Ssusans /* means IOCTL requires DMA */
38496447Ssusans /* allocate the data transfer buffer */
38506447Ssusans request_dma_obj.size = request_xferlen;
38516447Ssusans request_dma_obj.dma_attr = megasas_generic_dma_attr;
38527562SSusan.Scheufele@Sun.COM request_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
38537562SSusan.Scheufele@Sun.COM request_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
38546447Ssusans request_dma_obj.dma_attr.dma_attr_sgllen = 1;
38556447Ssusans request_dma_obj.dma_attr.dma_attr_align = 1;
38566447Ssusans
38576447Ssusans /* allocate kernel buffer for DMA */
38586447Ssusans if (mega_alloc_dma_obj(instance, &request_dma_obj) != 1) {
38596447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38606447Ssusans "could not data transfer buffer alloc."));
38616447Ssusans return (DDI_FAILURE);
38626447Ssusans }
38636447Ssusans
38646447Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
38656447Ssusans if (ddi_copyin(request_ubuf, (void *) request_dma_obj.buffer,
38666447Ssusans request_xferlen, mode)) {
38676447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38686447Ssusans "copy from user space failed\n"));
38696447Ssusans return (1);
38706447Ssusans }
38716447Ssusans }
38726447Ssusans
38736447Ssusans if (response_xferlen) {
38746447Ssusans /* means IOCTL requires DMA */
38756447Ssusans /* allocate the data transfer buffer */
38766447Ssusans response_dma_obj.size = response_xferlen;
38776447Ssusans response_dma_obj.dma_attr = megasas_generic_dma_attr;
38787562SSusan.Scheufele@Sun.COM response_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
38797562SSusan.Scheufele@Sun.COM response_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
38806447Ssusans response_dma_obj.dma_attr.dma_attr_sgllen = 1;
38816447Ssusans response_dma_obj.dma_attr.dma_attr_align = 1;
38826447Ssusans
38836447Ssusans /* allocate kernel buffer for DMA */
38846447Ssusans if (mega_alloc_dma_obj(instance, &response_dma_obj) != 1) {
38856447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38866447Ssusans "could not data transfer buffer alloc."));
38876447Ssusans return (DDI_FAILURE);
38886447Ssusans }
38896447Ssusans
38906447Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
38916447Ssusans if (ddi_copyin(response_ubuf, (void *) response_dma_obj.buffer,
38926447Ssusans response_xferlen, mode)) {
38936447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
38946447Ssusans "copy from user space failed\n"));
38956447Ssusans return (1);
38966447Ssusans }
38976447Ssusans }
38986447Ssusans
38996447Ssusans smp->cmd = ksmp->cmd;
39006447Ssusans smp->cmd_status = ksmp->cmd_status;
39016447Ssusans smp->connection_status = ksmp->connection_status;
39026447Ssusans smp->sge_count = ksmp->sge_count;
39036447Ssusans /* smp->context = ksmp->context; */
39046447Ssusans smp->timeout = ksmp->timeout;
39056447Ssusans smp->data_xfer_len = ksmp->data_xfer_len;
39066447Ssusans
39076447Ssusans bcopy((void *)&ksmp->sas_addr, (void *)&smp->sas_addr,
39086447Ssusans sizeof (uint64_t));
39096447Ssusans
39106447Ssusans smp->flags = ksmp->flags & ~MFI_FRAME_SGL64;
39116447Ssusans
39126447Ssusans model = ddi_model_convert_from(mode & FMODELS);
39136447Ssusans if (model == DDI_MODEL_ILP32) {
39146447Ssusans con_log(CL_ANN1, (CE_NOTE,
39156447Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
39166447Ssusans
39176447Ssusans sge32 = &smp->sgl[0].sge32[0];
39186447Ssusans sge32[0].length = response_xferlen;
39196447Ssusans sge32[0].phys_addr =
39206447Ssusans response_dma_obj.dma_cookie[0].dmac_address;
39216447Ssusans sge32[1].length = request_xferlen;
39226447Ssusans sge32[1].phys_addr =
39236447Ssusans request_dma_obj.dma_cookie[0].dmac_address;
39246447Ssusans } else {
39256447Ssusans #ifdef _ILP32
39266447Ssusans con_log(CL_ANN1, (CE_NOTE,
39276447Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
39286447Ssusans sge32 = &smp->sgl[0].sge32[0];
39296447Ssusans sge32[0].length = response_xferlen;
39306447Ssusans sge32[0].phys_addr =
39316447Ssusans response_dma_obj.dma_cookie[0].dmac_address;
39326447Ssusans sge32[1].length = request_xferlen;
39336447Ssusans sge32[1].phys_addr =
39346447Ssusans request_dma_obj.dma_cookie[0].dmac_address;
39356447Ssusans #else
39366447Ssusans con_log(CL_ANN1, (CE_NOTE,
39376447Ssusans "issue_mfi_smp: DDI_MODEL_LP64"));
39386447Ssusans sge64 = &smp->sgl[0].sge64[0];
39396447Ssusans sge64[0].length = response_xferlen;
39406447Ssusans sge64[0].phys_addr =
39416447Ssusans response_dma_obj.dma_cookie[0].dmac_address;
39426447Ssusans sge64[1].length = request_xferlen;
39436447Ssusans sge64[1].phys_addr =
39446447Ssusans request_dma_obj.dma_cookie[0].dmac_address;
39456447Ssusans #endif
39466447Ssusans }
39476447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: "
39486447Ssusans "smp->response_xferlen = %d, smp->request_xferlen = %d "
39496447Ssusans "smp->data_xfer_len = %d", sge32[0].length, sge32[1].length,
39506447Ssusans smp->data_xfer_len));
39516447Ssusans
39526447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
39536447Ssusans cmd->frame_count = 1;
39546447Ssusans
39556447Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
39566447Ssusans con_log(CL_ANN, (CE_WARN,
39576447Ssusans "issue_mfi_smp: fw_ioctl failed\n"));
39586447Ssusans } else {
39596447Ssusans con_log(CL_ANN1, (CE_NOTE,
39606447Ssusans "issue_mfi_smp: copy to user space\n"));
39616447Ssusans
39626447Ssusans if (request_xferlen) {
39636447Ssusans if (ddi_copyout(request_dma_obj.buffer, request_ubuf,
39646447Ssusans request_xferlen, mode)) {
39656447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
39666447Ssusans "copy to user space failed\n"));
39676447Ssusans return (1);
39686447Ssusans }
39696447Ssusans }
39706447Ssusans
39716447Ssusans if (response_xferlen) {
39726447Ssusans if (ddi_copyout(response_dma_obj.buffer, response_ubuf,
39736447Ssusans response_xferlen, mode)) {
39746447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_smp: "
39756447Ssusans "copy to user space failed\n"));
39766447Ssusans return (1);
39776447Ssusans }
39786447Ssusans }
39796447Ssusans }
39806447Ssusans
39816447Ssusans ksmp->cmd_status = smp->cmd_status;
39826447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_smp: smp->cmd_status = %d",
39836447Ssusans smp->cmd_status));
39846447Ssusans
39856447Ssusans
39866447Ssusans if (request_xferlen) {
39876447Ssusans /* free kernel buffer */
39887533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, request_dma_obj) != DDI_SUCCESS)
39897533SYu.Wu@Sun.COM return (1);
39906447Ssusans }
39916447Ssusans
39926447Ssusans if (response_xferlen) {
39936447Ssusans /* free kernel buffer */
39947533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, response_dma_obj) !=
39957533SYu.Wu@Sun.COM DDI_SUCCESS)
39967533SYu.Wu@Sun.COM return (1);
39976447Ssusans }
39986447Ssusans
39996447Ssusans return (0);
40006447Ssusans }
40016447Ssusans
40026447Ssusans /*
40036447Ssusans * issue_mfi_stp
40046447Ssusans */
40056447Ssusans static int
issue_mfi_stp(struct megasas_instance * instance,struct megasas_ioctl * ioctl,struct megasas_cmd * cmd,int mode)40066447Ssusans issue_mfi_stp(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
40076447Ssusans struct megasas_cmd *cmd, int mode)
40086447Ssusans {
40096447Ssusans void *fis_ubuf;
40106447Ssusans void *data_ubuf;
40116447Ssusans uint32_t fis_xferlen = 0;
40126447Ssusans uint32_t data_xferlen = 0;
40136447Ssusans uint_t model;
40146447Ssusans dma_obj_t fis_dma_obj;
40156447Ssusans dma_obj_t data_dma_obj;
40166447Ssusans struct megasas_stp_frame *kstp;
40176447Ssusans struct megasas_stp_frame *stp;
40186447Ssusans
40196447Ssusans stp = &cmd->frame->stp;
40206447Ssusans kstp = (struct megasas_stp_frame *)&ioctl->frame[0];
40216447Ssusans
40226447Ssusans model = ddi_model_convert_from(mode & FMODELS);
40236447Ssusans if (model == DDI_MODEL_ILP32) {
40246447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_stp: DDI_MODEL_ILP32"));
40256447Ssusans
40266447Ssusans fis_xferlen = kstp->sgl.sge32[0].length;
40276447Ssusans data_xferlen = kstp->sgl.sge32[1].length;
40286447Ssusans
40296447Ssusans /* SJ! - ubuf needs to be virtual address. */
40306447Ssusans fis_ubuf = (void *)(ulong_t)kstp->sgl.sge32[0].phys_addr;
40316447Ssusans data_ubuf = (void *)(ulong_t)kstp->sgl.sge32[1].phys_addr;
40326447Ssusans }
40336447Ssusans else
40346447Ssusans {
40356447Ssusans #ifdef _ILP32
40366447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_stp: DDI_MODEL_ILP32"));
40376447Ssusans
40386447Ssusans fis_xferlen = kstp->sgl.sge32[0].length;
40396447Ssusans data_xferlen = kstp->sgl.sge32[1].length;
40406447Ssusans
40416447Ssusans /* SJ! - ubuf needs to be virtual address. */
40426447Ssusans fis_ubuf = (void *)(ulong_t)kstp->sgl.sge32[0].phys_addr;
40436447Ssusans data_ubuf = (void *)(ulong_t)kstp->sgl.sge32[1].phys_addr;
40446447Ssusans #else
40456447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_mfi_stp: DDI_MODEL_LP64"));
40466447Ssusans
40476447Ssusans fis_xferlen = kstp->sgl.sge64[0].length;
40486447Ssusans data_xferlen = kstp->sgl.sge64[1].length;
40496447Ssusans
40506447Ssusans /* SJ! - ubuf needs to be virtual address. */
40516447Ssusans fis_ubuf = (void *)(ulong_t)kstp->sgl.sge64[0].phys_addr;
40526447Ssusans data_ubuf = (void *)(ulong_t)kstp->sgl.sge64[1].phys_addr;
40536447Ssusans #endif
40546447Ssusans }
40556447Ssusans
40566447Ssusans
40576447Ssusans if (fis_xferlen) {
40586447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_stp: "
40596447Ssusans "fis_ubuf = %p fis_xferlen = %x", fis_ubuf, fis_xferlen));
40607562SSusan.Scheufele@Sun.COM
40616447Ssusans /* means IOCTL requires DMA */
40626447Ssusans /* allocate the data transfer buffer */
40636447Ssusans fis_dma_obj.size = fis_xferlen;
40646447Ssusans fis_dma_obj.dma_attr = megasas_generic_dma_attr;
40657562SSusan.Scheufele@Sun.COM fis_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
40667562SSusan.Scheufele@Sun.COM fis_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
40676447Ssusans fis_dma_obj.dma_attr.dma_attr_sgllen = 1;
40686447Ssusans fis_dma_obj.dma_attr.dma_attr_align = 1;
40696447Ssusans
40706447Ssusans /* allocate kernel buffer for DMA */
40716447Ssusans if (mega_alloc_dma_obj(instance, &fis_dma_obj) != 1) {
40726447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
40736447Ssusans "could not data transfer buffer alloc."));
40746447Ssusans return (DDI_FAILURE);
40756447Ssusans }
40766447Ssusans
40776447Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
40786447Ssusans if (ddi_copyin(fis_ubuf, (void *)fis_dma_obj.buffer,
40796447Ssusans fis_xferlen, mode)) {
40806447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
40816447Ssusans "copy from user space failed\n"));
40826447Ssusans return (1);
40836447Ssusans }
40846447Ssusans }
40856447Ssusans
40866447Ssusans if (data_xferlen) {
40876447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_mfi_stp: data_ubuf = %p "
40886447Ssusans "data_xferlen = %x", data_ubuf, data_xferlen));
40896447Ssusans
40906447Ssusans /* means IOCTL requires DMA */
40916447Ssusans /* allocate the data transfer buffer */
40926447Ssusans data_dma_obj.size = data_xferlen;
40936447Ssusans data_dma_obj.dma_attr = megasas_generic_dma_attr;
40947562SSusan.Scheufele@Sun.COM data_dma_obj.dma_attr.dma_attr_addr_hi = 0xFFFFFFFFU;
40957562SSusan.Scheufele@Sun.COM data_dma_obj.dma_attr.dma_attr_count_max = 0xFFFFFFFFU;
40966447Ssusans data_dma_obj.dma_attr.dma_attr_sgllen = 1;
40976447Ssusans data_dma_obj.dma_attr.dma_attr_align = 1;
40986447Ssusans
40996447Ssusans /* allocate kernel buffer for DMA */
41006447Ssusans if (mega_alloc_dma_obj(instance, &data_dma_obj) != 1) {
41016447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41026447Ssusans "could not data transfer buffer alloc."));
41036447Ssusans return (DDI_FAILURE);
41046447Ssusans }
41056447Ssusans
41066447Ssusans /* If IOCTL requires DMA WRITE, do ddi_copyin IOCTL data copy */
41076447Ssusans if (ddi_copyin(data_ubuf, (void *) data_dma_obj.buffer,
41086447Ssusans data_xferlen, mode)) {
41096447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41106447Ssusans "copy from user space failed\n"));
41116447Ssusans return (1);
41126447Ssusans }
41136447Ssusans }
41146447Ssusans
41156447Ssusans stp->cmd = kstp->cmd;
41166447Ssusans stp->cmd_status = kstp->cmd_status;
41176447Ssusans stp->connection_status = kstp->connection_status;
41186447Ssusans stp->target_id = kstp->target_id;
41196447Ssusans stp->sge_count = kstp->sge_count;
41206447Ssusans /* stp->context = kstp->context; */
41216447Ssusans stp->timeout = kstp->timeout;
41226447Ssusans stp->data_xfer_len = kstp->data_xfer_len;
41236447Ssusans
41246447Ssusans bcopy((void *)kstp->fis, (void *)stp->fis, 10);
41256447Ssusans
41266447Ssusans stp->flags = kstp->flags & ~MFI_FRAME_SGL64;
41276447Ssusans stp->stp_flags = kstp->stp_flags;
41286447Ssusans stp->sgl.sge32[0].length = fis_xferlen;
41296447Ssusans stp->sgl.sge32[0].phys_addr = fis_dma_obj.dma_cookie[0].dmac_address;
41306447Ssusans stp->sgl.sge32[1].length = data_xferlen;
41316447Ssusans stp->sgl.sge32[1].phys_addr = data_dma_obj.dma_cookie[0].dmac_address;
41326447Ssusans
41336447Ssusans cmd->sync_cmd = MEGASAS_TRUE;
41346447Ssusans cmd->frame_count = 1;
41356447Ssusans
41366447Ssusans if (instance->func_ptr->issue_cmd_in_sync_mode(instance, cmd)) {
41376447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: fw_ioctl failed\n"));
41386447Ssusans } else {
41396447Ssusans
41406447Ssusans if (fis_xferlen) {
41416447Ssusans if (ddi_copyout(fis_dma_obj.buffer, fis_ubuf,
41426447Ssusans fis_xferlen, mode)) {
41436447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41446447Ssusans "copy to user space failed\n"));
41456447Ssusans return (1);
41466447Ssusans }
41476447Ssusans }
41486447Ssusans
41496447Ssusans if (data_xferlen) {
41506447Ssusans if (ddi_copyout(data_dma_obj.buffer, data_ubuf,
41516447Ssusans data_xferlen, mode)) {
41526447Ssusans con_log(CL_ANN, (CE_WARN, "issue_mfi_stp: "
41536447Ssusans "copy to user space failed\n"));
41546447Ssusans return (1);
41556447Ssusans }
41566447Ssusans }
41576447Ssusans }
41586447Ssusans
41596447Ssusans kstp->cmd_status = stp->cmd_status;
41606447Ssusans
41616447Ssusans if (fis_xferlen) {
41626447Ssusans /* free kernel buffer */
41637533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, fis_dma_obj) != DDI_SUCCESS)
41647533SYu.Wu@Sun.COM return (1);
41656447Ssusans }
41666447Ssusans
41676447Ssusans if (data_xferlen) {
41686447Ssusans /* free kernel buffer */
41697533SYu.Wu@Sun.COM if (mega_free_dma_obj(instance, data_dma_obj) != DDI_SUCCESS)
41707533SYu.Wu@Sun.COM return (1);
41716447Ssusans }
41726447Ssusans
41736447Ssusans return (0);
41746447Ssusans }
41756447Ssusans
41766447Ssusans /*
41776447Ssusans * fill_up_drv_ver
41786447Ssusans */
41796447Ssusans static void
fill_up_drv_ver(struct megasas_drv_ver * dv)41806447Ssusans fill_up_drv_ver(struct megasas_drv_ver *dv)
41816447Ssusans {
41826447Ssusans (void) memset(dv, 0, sizeof (struct megasas_drv_ver));
41836447Ssusans
41846447Ssusans (void) memcpy(dv->signature, "$LSI LOGIC$", strlen("$LSI LOGIC$"));
41856447Ssusans (void) memcpy(dv->os_name, "Solaris", strlen("Solaris"));
41866447Ssusans (void) memcpy(dv->drv_name, "megaraid_sas", strlen("megaraid_sas"));
41876447Ssusans (void) memcpy(dv->drv_ver, MEGASAS_VERSION, strlen(MEGASAS_VERSION));
41886447Ssusans (void) memcpy(dv->drv_rel_date, MEGASAS_RELDATE,
41896447Ssusans strlen(MEGASAS_RELDATE));
41906447Ssusans }
41916447Ssusans
41926447Ssusans /*
41936447Ssusans * handle_drv_ioctl
41946447Ssusans */
41956447Ssusans static int
handle_drv_ioctl(struct megasas_instance * instance,struct megasas_ioctl * ioctl,int mode)41966447Ssusans handle_drv_ioctl(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
41976447Ssusans int mode)
41986447Ssusans {
41996447Ssusans int i;
42006447Ssusans int rval = 0;
42016447Ssusans int *props = NULL;
42026447Ssusans void *ubuf;
42036447Ssusans
42046447Ssusans uint8_t *pci_conf_buf;
42056447Ssusans uint32_t xferlen;
42066447Ssusans uint32_t num_props;
42076447Ssusans uint_t model;
42086447Ssusans struct megasas_dcmd_frame *kdcmd;
42096447Ssusans struct megasas_drv_ver dv;
42106447Ssusans struct megasas_pci_information pi;
42116447Ssusans
42126447Ssusans kdcmd = (struct megasas_dcmd_frame *)&ioctl->frame[0];
42136447Ssusans
42146447Ssusans model = ddi_model_convert_from(mode & FMODELS);
42156447Ssusans if (model == DDI_MODEL_ILP32) {
42166447Ssusans con_log(CL_ANN1, (CE_NOTE,
42176447Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
42186447Ssusans
42196447Ssusans xferlen = kdcmd->sgl.sge32[0].length;
42206447Ssusans
42216447Ssusans /* SJ! - ubuf needs to be virtual address. */
42226447Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
42236447Ssusans } else {
42246447Ssusans #ifdef _ILP32
42256447Ssusans con_log(CL_ANN1, (CE_NOTE,
42266447Ssusans "handle_drv_ioctl: DDI_MODEL_ILP32"));
42276447Ssusans xferlen = kdcmd->sgl.sge32[0].length;
42286447Ssusans /* SJ! - ubuf needs to be virtual address. */
42296447Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge32[0].phys_addr;
42306447Ssusans #else
42316447Ssusans con_log(CL_ANN1, (CE_NOTE,
42326447Ssusans "handle_drv_ioctl: DDI_MODEL_LP64"));
42336447Ssusans xferlen = kdcmd->sgl.sge64[0].length;
42346447Ssusans /* SJ! - ubuf needs to be virtual address. */
42356447Ssusans ubuf = (void *)(ulong_t)kdcmd->sgl.sge64[0].phys_addr;
42366447Ssusans #endif
42376447Ssusans }
42386447Ssusans con_log(CL_ANN1, (CE_NOTE, "handle_drv_ioctl: "
42396447Ssusans "dataBuf=%p size=%d bytes", ubuf, xferlen));
42406447Ssusans
42416447Ssusans switch (kdcmd->opcode) {
42426447Ssusans case MR_DRIVER_IOCTL_DRIVER_VERSION:
42436447Ssusans con_log(CL_ANN1, (CE_NOTE, "handle_drv_ioctl: "
42446447Ssusans "MR_DRIVER_IOCTL_DRIVER_VERSION"));
42456447Ssusans
42466447Ssusans fill_up_drv_ver(&dv);
42476447Ssusans
42486447Ssusans if (ddi_copyout(&dv, ubuf, xferlen, mode)) {
42496447Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42506447Ssusans "MR_DRIVER_IOCTL_DRIVER_VERSION : "
42516447Ssusans "copy to user space failed\n"));
42526447Ssusans kdcmd->cmd_status = 1;
42536447Ssusans rval = 1;
42546447Ssusans } else {
42556447Ssusans kdcmd->cmd_status = 0;
42566447Ssusans }
42576447Ssusans break;
42586447Ssusans case MR_DRIVER_IOCTL_PCI_INFORMATION:
42596447Ssusans con_log(CL_ANN1, (CE_NOTE, "handle_drv_ioctl: "
42606447Ssusans "MR_DRIVER_IOCTL_PCI_INFORMAITON"));
42616447Ssusans
42626447Ssusans if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, instance->dip,
42636447Ssusans 0, "reg", &props, &num_props)) {
42646447Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42656447Ssusans "MR_DRIVER_IOCTL_PCI_INFORMATION : "
42666447Ssusans "ddi_prop_look_int_array failed\n"));
42676447Ssusans rval = 1;
42686447Ssusans } else {
42696447Ssusans
42706447Ssusans pi.busNumber = (props[0] >> 16) & 0xFF;
42716447Ssusans pi.deviceNumber = (props[0] >> 11) & 0x1f;
42726447Ssusans pi.functionNumber = (props[0] >> 8) & 0x7;
42736447Ssusans ddi_prop_free((void *)props);
42746447Ssusans }
42756447Ssusans
42766447Ssusans pci_conf_buf = (uint8_t *)&pi.pciHeaderInfo;
42776447Ssusans
42786779Syd196099 for (i = 0; i < (sizeof (struct megasas_pci_information) -
42796779Syd196099 offsetof(struct megasas_pci_information, pciHeaderInfo));
42806779Syd196099 i++) {
42816447Ssusans pci_conf_buf[i] =
42826447Ssusans pci_config_get8(instance->pci_handle, i);
42836447Ssusans }
42846447Ssusans
42856447Ssusans if (ddi_copyout(&pi, ubuf, xferlen, mode)) {
42866447Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42876447Ssusans "MR_DRIVER_IOCTL_PCI_INFORMATION : "
42886447Ssusans "copy to user space failed\n"));
42896447Ssusans kdcmd->cmd_status = 1;
42906447Ssusans rval = 1;
42916447Ssusans } else {
42926447Ssusans kdcmd->cmd_status = 0;
42936447Ssusans }
42946447Ssusans break;
42956447Ssusans default:
42966447Ssusans con_log(CL_ANN, (CE_WARN, "handle_drv_ioctl: "
42976447Ssusans "invalid driver specific IOCTL opcode = 0x%x",
42986447Ssusans kdcmd->opcode));
42996447Ssusans kdcmd->cmd_status = 1;
43006447Ssusans rval = 1;
43016447Ssusans break;
43026447Ssusans }
43036447Ssusans
43046447Ssusans return (rval);
43056447Ssusans }
43066447Ssusans
43076447Ssusans /*
43086447Ssusans * handle_mfi_ioctl
43096447Ssusans */
43106447Ssusans static int
handle_mfi_ioctl(struct megasas_instance * instance,struct megasas_ioctl * ioctl,int mode)43116447Ssusans handle_mfi_ioctl(struct megasas_instance *instance, struct megasas_ioctl *ioctl,
43126447Ssusans int mode)
43136447Ssusans {
43146447Ssusans int rval = 0;
43156447Ssusans
43166447Ssusans struct megasas_header *hdr;
43176447Ssusans struct megasas_cmd *cmd;
43186447Ssusans
43196447Ssusans cmd = get_mfi_pkt(instance);
43206447Ssusans
43216447Ssusans if (!cmd) {
43226447Ssusans con_log(CL_ANN, (CE_WARN, "megasas: "
43236447Ssusans "failed to get a cmd packet\n"));
43246447Ssusans return (1);
43256447Ssusans }
43266447Ssusans
43276447Ssusans hdr = (struct megasas_header *)&ioctl->frame[0];
43286447Ssusans
43296447Ssusans switch (hdr->cmd) {
43306447Ssusans case MFI_CMD_OP_DCMD:
43316447Ssusans rval = issue_mfi_dcmd(instance, ioctl, cmd, mode);
43326447Ssusans break;
43336447Ssusans case MFI_CMD_OP_SMP:
43346447Ssusans rval = issue_mfi_smp(instance, ioctl, cmd, mode);
43356447Ssusans break;
43366447Ssusans case MFI_CMD_OP_STP:
43376447Ssusans rval = issue_mfi_stp(instance, ioctl, cmd, mode);
43386447Ssusans break;
43396447Ssusans case MFI_CMD_OP_LD_SCSI:
43406447Ssusans case MFI_CMD_OP_PD_SCSI:
43416447Ssusans rval = issue_mfi_pthru(instance, ioctl, cmd, mode);
43426447Ssusans break;
43436447Ssusans default:
43446447Ssusans con_log(CL_ANN, (CE_WARN, "handle_mfi_ioctl: "
43456447Ssusans "invalid mfi ioctl hdr->cmd = %d\n", hdr->cmd));
43466447Ssusans rval = 1;
43476447Ssusans break;
43486447Ssusans }
43496447Ssusans
43506447Ssusans
43516447Ssusans return_mfi_pkt(instance, cmd);
43527533SYu.Wu@Sun.COM if (megasas_common_check(instance, cmd) != DDI_SUCCESS)
43537533SYu.Wu@Sun.COM rval = 1;
43546447Ssusans return (rval);
43556447Ssusans }
43566447Ssusans
43576447Ssusans /*
43586447Ssusans * AEN
43596447Ssusans */
43606447Ssusans static int
handle_mfi_aen(struct megasas_instance * instance,struct megasas_aen * aen)43616447Ssusans handle_mfi_aen(struct megasas_instance *instance, struct megasas_aen *aen)
43626447Ssusans {
43636447Ssusans int rval = 0;
43646447Ssusans
43656447Ssusans rval = register_mfi_aen(instance, instance->aen_seq_num,
43666447Ssusans aen->class_locale_word);
43676447Ssusans
43686447Ssusans aen->cmd_status = (uint8_t)rval;
43696447Ssusans
43706447Ssusans return (rval);
43716447Ssusans }
43726447Ssusans
43736447Ssusans static int
register_mfi_aen(struct megasas_instance * instance,uint32_t seq_num,uint32_t class_locale_word)43746447Ssusans register_mfi_aen(struct megasas_instance *instance, uint32_t seq_num,
43756447Ssusans uint32_t class_locale_word)
43766447Ssusans {
43776447Ssusans int ret_val;
43786447Ssusans
43796447Ssusans struct megasas_cmd *cmd;
43806447Ssusans struct megasas_dcmd_frame *dcmd;
43816447Ssusans union megasas_evt_class_locale curr_aen;
43826447Ssusans union megasas_evt_class_locale prev_aen;
43836447Ssusans
43846447Ssusans /*
43856447Ssusans * If there an AEN pending already (aen_cmd), check if the
43866447Ssusans * class_locale of that pending AEN is inclusive of the new
43876447Ssusans * AEN request we currently have. If it is, then we don't have
43886447Ssusans * to do anything. In other words, whichever events the current
43896447Ssusans * AEN request is subscribing to, have already been subscribed
43906447Ssusans * to.
43916447Ssusans *
43926447Ssusans * If the old_cmd is _not_ inclusive, then we have to abort
43936447Ssusans * that command, form a class_locale that is superset of both
43946447Ssusans * old and current and re-issue to the FW
43956447Ssusans */
43966447Ssusans
43976447Ssusans curr_aen.word = class_locale_word;
43986447Ssusans
43996447Ssusans if (instance->aen_cmd) {
44006447Ssusans prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];
44016447Ssusans
44026447Ssusans /*
44036447Ssusans * A class whose enum value is smaller is inclusive of all
44046447Ssusans * higher values. If a PROGRESS (= -1) was previously
44056447Ssusans * registered, then a new registration requests for higher
44066447Ssusans * classes need not be sent to FW. They are automatically
44076447Ssusans * included.
44086447Ssusans *
44096447Ssusans * Locale numbers don't have such hierarchy. They are bitmap
44106447Ssusans * values
44116447Ssusans */
44126447Ssusans if ((prev_aen.members.class <= curr_aen.members.class) &&
44136447Ssusans !((prev_aen.members.locale & curr_aen.members.locale) ^
44146447Ssusans curr_aen.members.locale)) {
44156447Ssusans /*
44166447Ssusans * Previously issued event registration includes
44176447Ssusans * current request. Nothing to do.
44186447Ssusans */
44196447Ssusans
44206447Ssusans return (0);
44216447Ssusans } else {
44226447Ssusans curr_aen.members.locale |= prev_aen.members.locale;
44236447Ssusans
44246447Ssusans if (prev_aen.members.class < curr_aen.members.class)
44256447Ssusans curr_aen.members.class = prev_aen.members.class;
44266447Ssusans
44276447Ssusans ret_val = abort_aen_cmd(instance, instance->aen_cmd);
44286447Ssusans
44296447Ssusans if (ret_val) {
44306447Ssusans con_log(CL_ANN, (CE_WARN, "register_mfi_aen: "
44316447Ssusans "failed to abort prevous AEN command\n"));
44326447Ssusans
44336447Ssusans return (ret_val);
44346447Ssusans }
44356447Ssusans }
44366447Ssusans } else {
44376447Ssusans curr_aen.word = class_locale_word;
44386447Ssusans }
44396447Ssusans
44406447Ssusans cmd = get_mfi_pkt(instance);
44416447Ssusans
44426447Ssusans if (!cmd)
44436447Ssusans return (-ENOMEM);
44446447Ssusans
44456447Ssusans dcmd = &cmd->frame->dcmd;
44466447Ssusans
44477562SSusan.Scheufele@Sun.COM /* for(i = 0; i < DCMD_MBOX_SZ; i++) dcmd->mbox.b[i] = 0; */
44487562SSusan.Scheufele@Sun.COM (void) memset(dcmd->mbox.b, 0, DCMD_MBOX_SZ);
44496447Ssusans
44506447Ssusans (void) memset(instance->mfi_evt_detail_obj.buffer, 0,
44516447Ssusans sizeof (struct megasas_evt_detail));
44526447Ssusans
44536447Ssusans /* Prepare DCMD for aen registration */
44546447Ssusans dcmd->cmd = MFI_CMD_OP_DCMD;
44556447Ssusans dcmd->cmd_status = 0x0;
44566447Ssusans dcmd->sge_count = 1;
44576447Ssusans dcmd->flags = MFI_FRAME_DIR_READ;
44586447Ssusans dcmd->timeout = 0;
44596447Ssusans dcmd->data_xfer_len = sizeof (struct megasas_evt_detail);
44606447Ssusans dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
44616447Ssusans dcmd->mbox.w[0] = seq_num;
44626447Ssusans dcmd->mbox.w[1] = curr_aen.word;
44636447Ssusans dcmd->sgl.sge32[0].phys_addr =
44646447Ssusans instance->mfi_evt_detail_obj.dma_cookie[0].dmac_address;
44656447Ssusans dcmd->sgl.sge32[0].length = sizeof (struct megasas_evt_detail);
44666447Ssusans
44676447Ssusans instance->aen_seq_num = seq_num;
44686447Ssusans
44696447Ssusans /*
44706447Ssusans * Store reference to the cmd used to register for AEN. When an
44716447Ssusans * application wants us to register for AEN, we have to abort this
44726447Ssusans * cmd and re-register with a new EVENT LOCALE supplied by that app
44736447Ssusans */
44746447Ssusans instance->aen_cmd = cmd;
44756447Ssusans
44766447Ssusans cmd->frame_count = 1;
44776447Ssusans
44786447Ssusans /* Issue the aen registration frame */
44796447Ssusans /* atomic_add_16 (&instance->fw_outstanding, 1); */
44806447Ssusans instance->func_ptr->issue_cmd(cmd, instance);
44816447Ssusans
44826447Ssusans return (0);
44836447Ssusans }
44846447Ssusans
44856447Ssusans static void
display_scsi_inquiry(caddr_t scsi_inq)44866447Ssusans display_scsi_inquiry(caddr_t scsi_inq)
44876447Ssusans {
44886447Ssusans #define MAX_SCSI_DEVICE_CODE 14
44896447Ssusans int i;
44906447Ssusans char inquiry_buf[256] = {0};
44916447Ssusans int len;
44926447Ssusans const char *const scsi_device_types[] = {
44936447Ssusans "Direct-Access ",
44946447Ssusans "Sequential-Access",
44956447Ssusans "Printer ",
44966447Ssusans "Processor ",
44976447Ssusans "WORM ",
44986447Ssusans "CD-ROM ",
44996447Ssusans "Scanner ",
45006447Ssusans "Optical Device ",
45016447Ssusans "Medium Changer ",
45026447Ssusans "Communications ",
45036447Ssusans "Unknown ",
45046447Ssusans "Unknown ",
45056447Ssusans "Unknown ",
45066447Ssusans "Enclosure ",
45076447Ssusans };
45086447Ssusans
45096447Ssusans len = 0;
45106447Ssusans
45116447Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Vendor: ");
45126447Ssusans for (i = 8; i < 16; i++) {
45136447Ssusans len += snprintf(inquiry_buf + len, 265 - len, "%c",
45146447Ssusans scsi_inq[i]);
45156447Ssusans }
45166447Ssusans
45176447Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Model: ");
45186447Ssusans
45196447Ssusans for (i = 16; i < 32; i++) {
45206447Ssusans len += snprintf(inquiry_buf + len, 265 - len, "%c",
45216447Ssusans scsi_inq[i]);
45226447Ssusans }
45236447Ssusans
45246447Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Rev: ");
45256447Ssusans
45266447Ssusans for (i = 32; i < 36; i++) {
45276447Ssusans len += snprintf(inquiry_buf + len, 265 - len, "%c",
45286447Ssusans scsi_inq[i]);
45296447Ssusans }
45306447Ssusans
45316447Ssusans len += snprintf(inquiry_buf + len, 265 - len, "\n");
45326447Ssusans
45336447Ssusans
45346447Ssusans i = scsi_inq[0] & 0x1f;
45356447Ssusans
45366447Ssusans
45376447Ssusans len += snprintf(inquiry_buf + len, 265 - len, " Type: %s ",
45386447Ssusans i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
45396447Ssusans "Unknown ");
45406447Ssusans
45416447Ssusans
45426447Ssusans len += snprintf(inquiry_buf + len, 265 - len,
45436447Ssusans " ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
45446447Ssusans
45456447Ssusans if ((scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1) {
45466447Ssusans len += snprintf(inquiry_buf + len, 265 - len, " CCS\n");
45476447Ssusans } else {
45486447Ssusans len += snprintf(inquiry_buf + len, 265 - len, "\n");
45496447Ssusans }
45506447Ssusans
45516447Ssusans con_log(CL_ANN1, (CE_CONT, inquiry_buf));
45526447Ssusans }
45536447Ssusans
45546447Ssusans static int
read_fw_status_reg_xscale(struct megasas_instance * instance)45556447Ssusans read_fw_status_reg_xscale(struct megasas_instance *instance)
45566447Ssusans {
45576447Ssusans return ((int)RD_OB_MSG_0(instance));
45586447Ssusans }
45596447Ssusans
45606447Ssusans static int
read_fw_status_reg_ppc(struct megasas_instance * instance)45616447Ssusans read_fw_status_reg_ppc(struct megasas_instance *instance)
45626447Ssusans {
45636447Ssusans return ((int)RD_OB_SCRATCH_PAD_0(instance));
45646447Ssusans }
45656447Ssusans
45666447Ssusans static void
issue_cmd_xscale(struct megasas_cmd * cmd,struct megasas_instance * instance)45676447Ssusans issue_cmd_xscale(struct megasas_cmd *cmd, struct megasas_instance *instance)
45686447Ssusans {
45696447Ssusans atomic_add_16(&instance->fw_outstanding, 1);
45706447Ssusans
45716447Ssusans /* Issue the command to the FW */
45726447Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr) >> 3) |
45736447Ssusans (cmd->frame_count - 1), instance);
45746447Ssusans }
45756447Ssusans
45766447Ssusans static void
issue_cmd_ppc(struct megasas_cmd * cmd,struct megasas_instance * instance)45776447Ssusans issue_cmd_ppc(struct megasas_cmd *cmd, struct megasas_instance *instance)
45786447Ssusans {
45796447Ssusans atomic_add_16(&instance->fw_outstanding, 1);
45806447Ssusans
45816447Ssusans /* Issue the command to the FW */
45826447Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr)) |
45836447Ssusans (((cmd->frame_count - 1) << 1) | 1), instance);
45846447Ssusans }
45856447Ssusans
45866447Ssusans /*
45876447Ssusans * issue_cmd_in_sync_mode
45886447Ssusans */
45896447Ssusans static int
issue_cmd_in_sync_mode_xscale(struct megasas_instance * instance,struct megasas_cmd * cmd)45906447Ssusans issue_cmd_in_sync_mode_xscale(struct megasas_instance *instance,
45916447Ssusans struct megasas_cmd *cmd)
45926447Ssusans {
45936447Ssusans int i;
45947562SSusan.Scheufele@Sun.COM uint32_t msecs = MFI_POLL_TIMEOUT_SECS * (10 * MILLISEC);
45956447Ssusans
45966447Ssusans cmd->cmd_status = ENODATA;
45976447Ssusans
45986447Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr) >> 3) |
45996447Ssusans (cmd->frame_count - 1), instance);
46006447Ssusans
46016447Ssusans mutex_enter(&instance->int_cmd_mtx);
46026447Ssusans
46036447Ssusans for (i = 0; i < msecs && (cmd->cmd_status == ENODATA); i++) {
46046447Ssusans cv_wait(&instance->int_cmd_cv, &instance->int_cmd_mtx);
46056447Ssusans }
46066447Ssusans
46076447Ssusans mutex_exit(&instance->int_cmd_mtx);
46086447Ssusans
46096447Ssusans if (i < (msecs -1)) {
46106447Ssusans return (0);
46116447Ssusans } else {
46126447Ssusans return (1);
46136447Ssusans }
46146447Ssusans }
46156447Ssusans
46166447Ssusans static int
issue_cmd_in_sync_mode_ppc(struct megasas_instance * instance,struct megasas_cmd * cmd)46176447Ssusans issue_cmd_in_sync_mode_ppc(struct megasas_instance *instance,
46186447Ssusans struct megasas_cmd *cmd)
46196447Ssusans {
46206447Ssusans int i;
46217562SSusan.Scheufele@Sun.COM uint32_t msecs = MFI_POLL_TIMEOUT_SECS * (10 * MILLISEC);
46226447Ssusans
46236447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_sync_mode_ppc: called\n"));
46246447Ssusans
46256447Ssusans cmd->cmd_status = ENODATA;
46266447Ssusans
46276447Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr)) |
46286447Ssusans (((cmd->frame_count - 1) << 1) | 1), instance);
46296447Ssusans
46306447Ssusans mutex_enter(&instance->int_cmd_mtx);
46316447Ssusans
46326447Ssusans for (i = 0; i < msecs && (cmd->cmd_status == ENODATA); i++) {
46336447Ssusans cv_wait(&instance->int_cmd_cv, &instance->int_cmd_mtx);
46346447Ssusans }
46356447Ssusans
46366447Ssusans mutex_exit(&instance->int_cmd_mtx);
46376447Ssusans
46386447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_sync_mode_ppc: done\n"));
46396447Ssusans
46406447Ssusans if (i < (msecs -1)) {
46416447Ssusans return (0);
46426447Ssusans } else {
46436447Ssusans return (1);
46446447Ssusans }
46456447Ssusans }
46466447Ssusans
46476447Ssusans /*
46486447Ssusans * issue_cmd_in_poll_mode
46496447Ssusans */
46506447Ssusans static int
issue_cmd_in_poll_mode_xscale(struct megasas_instance * instance,struct megasas_cmd * cmd)46516447Ssusans issue_cmd_in_poll_mode_xscale(struct megasas_instance *instance,
46526447Ssusans struct megasas_cmd *cmd)
46536447Ssusans {
46546447Ssusans int i;
46557562SSusan.Scheufele@Sun.COM uint32_t msecs = MFI_POLL_TIMEOUT_SECS * MILLISEC;
46567562SSusan.Scheufele@Sun.COM struct megasas_header *frame_hdr;
46577562SSusan.Scheufele@Sun.COM
46587562SSusan.Scheufele@Sun.COM frame_hdr = (struct megasas_header *)cmd->frame;
46597562SSusan.Scheufele@Sun.COM frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
46606447Ssusans frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
46616447Ssusans
46626447Ssusans /* issue the frame using inbound queue port */
46636447Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr) >> 3) |
46646447Ssusans (cmd->frame_count - 1), instance);
46656447Ssusans
46667562SSusan.Scheufele@Sun.COM /* wait for cmd_status to change from 0xFF */
46677562SSusan.Scheufele@Sun.COM for (i = 0; i < msecs && (frame_hdr->cmd_status ==
46687562SSusan.Scheufele@Sun.COM MFI_CMD_STATUS_POLL_MODE); i++) {
46697562SSusan.Scheufele@Sun.COM drv_usecwait(MILLISEC); /* wait for 1000 usecs */
46706447Ssusans }
46716447Ssusans
46727562SSusan.Scheufele@Sun.COM if (frame_hdr->cmd_status == MFI_CMD_STATUS_POLL_MODE) {
46736447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_cmd_in_poll_mode: "
46746447Ssusans "cmd polling timed out"));
46756447Ssusans return (DDI_FAILURE);
46766447Ssusans }
46776447Ssusans
46786447Ssusans return (DDI_SUCCESS);
46796447Ssusans }
46806447Ssusans
46816447Ssusans static int
issue_cmd_in_poll_mode_ppc(struct megasas_instance * instance,struct megasas_cmd * cmd)46826447Ssusans issue_cmd_in_poll_mode_ppc(struct megasas_instance *instance,
46836447Ssusans struct megasas_cmd *cmd)
46846447Ssusans {
46856447Ssusans int i;
46867562SSusan.Scheufele@Sun.COM uint32_t msecs = MFI_POLL_TIMEOUT_SECS * MILLISEC;
46877562SSusan.Scheufele@Sun.COM struct megasas_header *frame_hdr;
46886447Ssusans
46896447Ssusans con_log(CL_ANN1, (CE_NOTE, "issue_cmd_in_poll_mode_ppc: called\n"));
46906447Ssusans
46917562SSusan.Scheufele@Sun.COM frame_hdr = (struct megasas_header *)cmd->frame;
46927562SSusan.Scheufele@Sun.COM frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
46936447Ssusans frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
46946447Ssusans
46956447Ssusans /* issue the frame using inbound queue port */
46966447Ssusans WR_IB_QPORT((host_to_le32(cmd->frame_phys_addr)) |
46976447Ssusans (((cmd->frame_count - 1) << 1) | 1), instance);
46986447Ssusans
46997562SSusan.Scheufele@Sun.COM /* wait for cmd_status to change from 0xFF */
47007562SSusan.Scheufele@Sun.COM for (i = 0; i < msecs && (frame_hdr->cmd_status ==
47017562SSusan.Scheufele@Sun.COM MFI_CMD_STATUS_POLL_MODE); i++) {
47027562SSusan.Scheufele@Sun.COM drv_usecwait(MILLISEC); /* wait for 1000 usecs */
47036447Ssusans }
47046447Ssusans
47057562SSusan.Scheufele@Sun.COM if (frame_hdr->cmd_status == MFI_CMD_STATUS_POLL_MODE) {
47066447Ssusans con_log(CL_ANN, (CE_NOTE, "issue_cmd_in_poll_mode: "
47076447Ssusans "cmd polling timed out"));
47086447Ssusans return (DDI_FAILURE);
47096447Ssusans }
47106447Ssusans
47116447Ssusans return (DDI_SUCCESS);
47126447Ssusans }
47136447Ssusans
47146447Ssusans static void
enable_intr_xscale(struct megasas_instance * instance)47156447Ssusans enable_intr_xscale(struct megasas_instance *instance)
47166447Ssusans {
47176447Ssusans MFI_ENABLE_INTR(instance);
47186447Ssusans }
47196447Ssusans
47206447Ssusans static void
enable_intr_ppc(struct megasas_instance * instance)47216447Ssusans enable_intr_ppc(struct megasas_instance *instance)
47226447Ssusans {
47236447Ssusans uint32_t mask;
47246447Ssusans
47256447Ssusans con_log(CL_ANN1, (CE_NOTE, "enable_intr_ppc: called\n"));
47266447Ssusans
47277562SSusan.Scheufele@Sun.COM /* WR_OB_DOORBELL_CLEAR(0xFFFFFFFF, instance); */
47287562SSusan.Scheufele@Sun.COM WR_OB_DOORBELL_CLEAR(OB_DOORBELL_CLEAR_MASK, instance);
47296599Ssusans
47306599Ssusans /*
47316599Ssusans * As 1078DE is same as 1078 chip, the interrupt mask
47326599Ssusans * remains the same.
47336599Ssusans */
47347562SSusan.Scheufele@Sun.COM /* WR_OB_INTR_MASK(~0x80000000, instance); */
47356447Ssusans WR_OB_INTR_MASK(~(MFI_REPLY_1078_MESSAGE_INTR), instance);
47366447Ssusans
47376447Ssusans /* dummy read to force PCI flush */
47386447Ssusans mask = RD_OB_INTR_MASK(instance);
47396447Ssusans
47406447Ssusans con_log(CL_ANN1, (CE_NOTE, "enable_intr_ppc: "
47416447Ssusans "outbound_intr_mask = 0x%x\n", mask));
47426447Ssusans }
47436447Ssusans
47446447Ssusans static void
disable_intr_xscale(struct megasas_instance * instance)47456447Ssusans disable_intr_xscale(struct megasas_instance *instance)
47466447Ssusans {
47476447Ssusans MFI_DISABLE_INTR(instance);
47486447Ssusans }
47496447Ssusans
47506447Ssusans static void
disable_intr_ppc(struct megasas_instance * instance)47516447Ssusans disable_intr_ppc(struct megasas_instance *instance)
47526447Ssusans {
47536447Ssusans uint32_t mask;
47546447Ssusans
47556447Ssusans con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: called\n"));
47566447Ssusans
47576447Ssusans con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: before : "
47586447Ssusans "outbound_intr_mask = 0x%x\n", RD_OB_INTR_MASK(instance)));
47596447Ssusans
47607562SSusan.Scheufele@Sun.COM /* WR_OB_INTR_MASK(0xFFFFFFFF, instance); */
47617562SSusan.Scheufele@Sun.COM WR_OB_INTR_MASK(OB_INTR_MASK, instance);
47627562SSusan.Scheufele@Sun.COM
47636447Ssusans con_log(CL_ANN1, (CE_NOTE, "disable_intr_ppc: after : "
47646447Ssusans "outbound_intr_mask = 0x%x\n", RD_OB_INTR_MASK(instance)));
47656447Ssusans
47666447Ssusans /* dummy read to force PCI flush */
47676447Ssusans mask = RD_OB_INTR_MASK(instance);
47686447Ssusans #ifdef lint
47696447Ssusans mask = mask;
47706447Ssusans #endif
47716447Ssusans }
47726447Ssusans
47736447Ssusans static int
intr_ack_xscale(struct megasas_instance * instance)47746447Ssusans intr_ack_xscale(struct megasas_instance *instance)
47756447Ssusans {
47766447Ssusans uint32_t status;
47776447Ssusans
47786447Ssusans /* check if it is our interrupt */
47796447Ssusans status = RD_OB_INTR_STATUS(instance);
47806447Ssusans
47816447Ssusans if (!(status & MFI_OB_INTR_STATUS_MASK)) {
47826447Ssusans return (DDI_INTR_UNCLAIMED);
47836447Ssusans }
47846447Ssusans
47856447Ssusans /* clear the interrupt by writing back the same value */
47866447Ssusans WR_OB_INTR_STATUS(status, instance);
47876447Ssusans
47886447Ssusans return (DDI_INTR_CLAIMED);
47896447Ssusans }
47906447Ssusans
47916447Ssusans static int
intr_ack_ppc(struct megasas_instance * instance)47926447Ssusans intr_ack_ppc(struct megasas_instance *instance)
47936447Ssusans {
47946447Ssusans uint32_t status;
47956447Ssusans
47966447Ssusans con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: called\n"));
47976447Ssusans
47986447Ssusans /* check if it is our interrupt */
47996447Ssusans status = RD_OB_INTR_STATUS(instance);
48006447Ssusans
48016447Ssusans con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: status = 0x%x\n", status));
48026447Ssusans
48036599Ssusans /*
48046599Ssusans * As 1078DE is same as 1078 chip, the status field
48056599Ssusans * remains the same.
48066599Ssusans */
48076447Ssusans if (!(status & MFI_REPLY_1078_MESSAGE_INTR)) {
48086447Ssusans return (DDI_INTR_UNCLAIMED);
48096447Ssusans }
48106447Ssusans
48116447Ssusans /* clear the interrupt by writing back the same value */
48126447Ssusans WR_OB_DOORBELL_CLEAR(status, instance);
48136447Ssusans
48146447Ssusans /* dummy READ */
48156447Ssusans status = RD_OB_INTR_STATUS(instance);
48166447Ssusans
48176447Ssusans con_log(CL_ANN1, (CE_NOTE, "intr_ack_ppc: interrupt cleared\n"));
48186447Ssusans
48196447Ssusans return (DDI_INTR_CLAIMED);
48206447Ssusans }
48217533SYu.Wu@Sun.COM
48227533SYu.Wu@Sun.COM static int
megasas_common_check(struct megasas_instance * instance,struct megasas_cmd * cmd)48237533SYu.Wu@Sun.COM megasas_common_check(struct megasas_instance *instance,
48247533SYu.Wu@Sun.COM struct megasas_cmd *cmd)
48257533SYu.Wu@Sun.COM {
48267533SYu.Wu@Sun.COM int ret = DDI_SUCCESS;
48277533SYu.Wu@Sun.COM
48287533SYu.Wu@Sun.COM if (megasas_check_dma_handle(cmd->frame_dma_obj.dma_handle) !=
48297533SYu.Wu@Sun.COM DDI_SUCCESS) {
48307533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48317533SYu.Wu@Sun.COM if (cmd->pkt != NULL) {
48327533SYu.Wu@Sun.COM cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48337533SYu.Wu@Sun.COM cmd->pkt->pkt_statistics = 0;
48347533SYu.Wu@Sun.COM }
48357533SYu.Wu@Sun.COM ret = DDI_FAILURE;
48367533SYu.Wu@Sun.COM }
48377533SYu.Wu@Sun.COM if (megasas_check_dma_handle(instance->mfi_internal_dma_obj.dma_handle)
48387533SYu.Wu@Sun.COM != DDI_SUCCESS) {
48397533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48407533SYu.Wu@Sun.COM if (cmd->pkt != NULL) {
48417533SYu.Wu@Sun.COM cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48427533SYu.Wu@Sun.COM cmd->pkt->pkt_statistics = 0;
48437533SYu.Wu@Sun.COM }
48447533SYu.Wu@Sun.COM ret = DDI_FAILURE;
48457533SYu.Wu@Sun.COM }
48467533SYu.Wu@Sun.COM if (megasas_check_dma_handle(instance->mfi_evt_detail_obj.dma_handle) !=
48477533SYu.Wu@Sun.COM DDI_SUCCESS) {
48487533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48497533SYu.Wu@Sun.COM if (cmd->pkt != NULL) {
48507533SYu.Wu@Sun.COM cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48517533SYu.Wu@Sun.COM cmd->pkt->pkt_statistics = 0;
48527533SYu.Wu@Sun.COM }
48537533SYu.Wu@Sun.COM ret = DDI_FAILURE;
48547533SYu.Wu@Sun.COM }
48557533SYu.Wu@Sun.COM if (megasas_check_acc_handle(instance->regmap_handle) != DDI_SUCCESS) {
48567533SYu.Wu@Sun.COM ddi_fm_service_impact(instance->dip, DDI_SERVICE_UNAFFECTED);
48577533SYu.Wu@Sun.COM ddi_fm_acc_err_clear(instance->regmap_handle, DDI_FME_VER0);
48587533SYu.Wu@Sun.COM if (cmd->pkt != NULL) {
48597533SYu.Wu@Sun.COM cmd->pkt->pkt_reason = CMD_TRAN_ERR;
48607533SYu.Wu@Sun.COM cmd->pkt->pkt_statistics = 0;
48617533SYu.Wu@Sun.COM }
48627533SYu.Wu@Sun.COM ret = DDI_FAILURE;
48637533SYu.Wu@Sun.COM }
48647533SYu.Wu@Sun.COM
48657533SYu.Wu@Sun.COM return (ret);
48667533SYu.Wu@Sun.COM }
48677533SYu.Wu@Sun.COM
48687533SYu.Wu@Sun.COM /*ARGSUSED*/
48697533SYu.Wu@Sun.COM static int
megasas_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)48707533SYu.Wu@Sun.COM megasas_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
48717533SYu.Wu@Sun.COM {
48727533SYu.Wu@Sun.COM /*
48737533SYu.Wu@Sun.COM * as the driver can always deal with an error in any dma or
48747533SYu.Wu@Sun.COM * access handle, we can just return the fme_status value.
48757533SYu.Wu@Sun.COM */
48767533SYu.Wu@Sun.COM pci_ereport_post(dip, err, NULL);
48777533SYu.Wu@Sun.COM return (err->fme_status);
48787533SYu.Wu@Sun.COM }
48797533SYu.Wu@Sun.COM
48807533SYu.Wu@Sun.COM static void
megasas_fm_init(struct megasas_instance * instance)48817533SYu.Wu@Sun.COM megasas_fm_init(struct megasas_instance *instance)
48827533SYu.Wu@Sun.COM {
48837533SYu.Wu@Sun.COM /* Need to change iblock to priority for new MSI intr */
48847533SYu.Wu@Sun.COM ddi_iblock_cookie_t fm_ibc;
48857533SYu.Wu@Sun.COM
48867533SYu.Wu@Sun.COM /* Only register with IO Fault Services if we have some capability */
48877533SYu.Wu@Sun.COM if (instance->fm_capabilities) {
48887533SYu.Wu@Sun.COM /* Adjust access and dma attributes for FMA */
48897533SYu.Wu@Sun.COM endian_attr.devacc_attr_access = DDI_FLAGERR_ACC;
48907533SYu.Wu@Sun.COM megasas_generic_dma_attr.dma_attr_flags = DDI_DMA_FLAGERR;
48917533SYu.Wu@Sun.COM
48927533SYu.Wu@Sun.COM /*
48937533SYu.Wu@Sun.COM * Register capabilities with IO Fault Services.
48947533SYu.Wu@Sun.COM * fm_capabilities will be updated to indicate
48957533SYu.Wu@Sun.COM * capabilities actually supported (not requested.)
48967533SYu.Wu@Sun.COM */
48977533SYu.Wu@Sun.COM
48987533SYu.Wu@Sun.COM ddi_fm_init(instance->dip, &instance->fm_capabilities, &fm_ibc);
48997533SYu.Wu@Sun.COM
49007533SYu.Wu@Sun.COM /*
49017533SYu.Wu@Sun.COM * Initialize pci ereport capabilities if ereport
49027533SYu.Wu@Sun.COM * capable (should always be.)
49037533SYu.Wu@Sun.COM */
49047533SYu.Wu@Sun.COM
49057533SYu.Wu@Sun.COM if (DDI_FM_EREPORT_CAP(instance->fm_capabilities) ||
49067533SYu.Wu@Sun.COM DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49077533SYu.Wu@Sun.COM pci_ereport_setup(instance->dip);
49087533SYu.Wu@Sun.COM }
49097533SYu.Wu@Sun.COM
49107533SYu.Wu@Sun.COM /*
49117533SYu.Wu@Sun.COM * Register error callback if error callback capable.
49127533SYu.Wu@Sun.COM */
49137533SYu.Wu@Sun.COM if (DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49147533SYu.Wu@Sun.COM ddi_fm_handler_register(instance->dip,
49157533SYu.Wu@Sun.COM megasas_fm_error_cb, (void*) instance);
49167533SYu.Wu@Sun.COM }
49177533SYu.Wu@Sun.COM } else {
49187533SYu.Wu@Sun.COM endian_attr.devacc_attr_access = DDI_DEFAULT_ACC;
49197533SYu.Wu@Sun.COM megasas_generic_dma_attr.dma_attr_flags = 0;
49207533SYu.Wu@Sun.COM }
49217533SYu.Wu@Sun.COM }
49227533SYu.Wu@Sun.COM
49237533SYu.Wu@Sun.COM static void
megasas_fm_fini(struct megasas_instance * instance)49247533SYu.Wu@Sun.COM megasas_fm_fini(struct megasas_instance *instance)
49257533SYu.Wu@Sun.COM {
49267533SYu.Wu@Sun.COM /* Only unregister FMA capabilities if registered */
49277533SYu.Wu@Sun.COM if (instance->fm_capabilities) {
49287533SYu.Wu@Sun.COM /*
49297533SYu.Wu@Sun.COM * Un-register error callback if error callback capable.
49307533SYu.Wu@Sun.COM */
49317533SYu.Wu@Sun.COM if (DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49327533SYu.Wu@Sun.COM ddi_fm_handler_unregister(instance->dip);
49337533SYu.Wu@Sun.COM }
49347533SYu.Wu@Sun.COM
49357533SYu.Wu@Sun.COM /*
49367533SYu.Wu@Sun.COM * Release any resources allocated by pci_ereport_setup()
49377533SYu.Wu@Sun.COM */
49387533SYu.Wu@Sun.COM if (DDI_FM_EREPORT_CAP(instance->fm_capabilities) ||
49397533SYu.Wu@Sun.COM DDI_FM_ERRCB_CAP(instance->fm_capabilities)) {
49407533SYu.Wu@Sun.COM pci_ereport_teardown(instance->dip);
49417533SYu.Wu@Sun.COM }
49427533SYu.Wu@Sun.COM
49437533SYu.Wu@Sun.COM /* Unregister from IO Fault Services */
49447533SYu.Wu@Sun.COM ddi_fm_fini(instance->dip);
49457533SYu.Wu@Sun.COM
49467533SYu.Wu@Sun.COM /* Adjust access and dma attributes for FMA */
49477533SYu.Wu@Sun.COM endian_attr.devacc_attr_access = DDI_DEFAULT_ACC;
49487533SYu.Wu@Sun.COM megasas_generic_dma_attr.dma_attr_flags = 0;
49497533SYu.Wu@Sun.COM }
49507533SYu.Wu@Sun.COM }
49517533SYu.Wu@Sun.COM
49527533SYu.Wu@Sun.COM int
megasas_check_acc_handle(ddi_acc_handle_t handle)49537533SYu.Wu@Sun.COM megasas_check_acc_handle(ddi_acc_handle_t handle)
49547533SYu.Wu@Sun.COM {
49557533SYu.Wu@Sun.COM ddi_fm_error_t de;
49567533SYu.Wu@Sun.COM
49577533SYu.Wu@Sun.COM if (handle == NULL) {
49587533SYu.Wu@Sun.COM return (DDI_FAILURE);
49597533SYu.Wu@Sun.COM }
49607533SYu.Wu@Sun.COM
49617533SYu.Wu@Sun.COM ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
49627533SYu.Wu@Sun.COM
49637533SYu.Wu@Sun.COM return (de.fme_status);
49647533SYu.Wu@Sun.COM }
49657533SYu.Wu@Sun.COM
49667533SYu.Wu@Sun.COM int
megasas_check_dma_handle(ddi_dma_handle_t handle)49677533SYu.Wu@Sun.COM megasas_check_dma_handle(ddi_dma_handle_t handle)
49687533SYu.Wu@Sun.COM {
49697533SYu.Wu@Sun.COM ddi_fm_error_t de;
49707533SYu.Wu@Sun.COM
49717533SYu.Wu@Sun.COM if (handle == NULL) {
49727533SYu.Wu@Sun.COM return (DDI_FAILURE);
49737533SYu.Wu@Sun.COM }
49747533SYu.Wu@Sun.COM
49757533SYu.Wu@Sun.COM ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
49767533SYu.Wu@Sun.COM
49777533SYu.Wu@Sun.COM return (de.fme_status);
49787533SYu.Wu@Sun.COM }
49797533SYu.Wu@Sun.COM
49807533SYu.Wu@Sun.COM void
megasas_fm_ereport(struct megasas_instance * instance,char * detail)49817533SYu.Wu@Sun.COM megasas_fm_ereport(struct megasas_instance *instance, char *detail)
49827533SYu.Wu@Sun.COM {
49837533SYu.Wu@Sun.COM uint64_t ena;
49847533SYu.Wu@Sun.COM char buf[FM_MAX_CLASS];
49857533SYu.Wu@Sun.COM
49867533SYu.Wu@Sun.COM (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
49877533SYu.Wu@Sun.COM ena = fm_ena_generate(0, FM_ENA_FMT1);
49887533SYu.Wu@Sun.COM if (DDI_FM_EREPORT_CAP(instance->fm_capabilities)) {
49897533SYu.Wu@Sun.COM ddi_fm_ereport_post(instance->dip, buf, ena, DDI_NOSLEEP,
49907533SYu.Wu@Sun.COM FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION, NULL);
49917533SYu.Wu@Sun.COM }
49927533SYu.Wu@Sun.COM }
4993