xref: /onnv-gate/usr/src/uts/common/io/mega_sas/megaraid_sas.c (revision 11236:1127b4f9e96b)
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, &reglength)
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