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