xref: /onnv-gate/usr/src/uts/intel/io/amr/amr.c (revision 7542:42d86bdbde36)
10Sstevel@tonic-gate /*
2*7542SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  */
50Sstevel@tonic-gate /*
60Sstevel@tonic-gate  * Copyright (c) 1999,2000 Michael Smith
70Sstevel@tonic-gate  * Copyright (c) 2000 BSDi
80Sstevel@tonic-gate  * All rights reserved.
90Sstevel@tonic-gate  *
100Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
110Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
120Sstevel@tonic-gate  * are met:
130Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
140Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
150Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
160Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
170Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
200Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
210Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
220Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
230Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
240Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
250Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
260Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
270Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
280Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
290Sstevel@tonic-gate  * SUCH DAMAGE.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * Copyright (c) 2002 Eric Moore
330Sstevel@tonic-gate  * Copyright (c) 2002 LSI Logic Corporation
340Sstevel@tonic-gate  * All rights reserved.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
370Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
380Sstevel@tonic-gate  * are met:
390Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
400Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
410Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
420Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
430Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
440Sstevel@tonic-gate  * 3. The party using or redistributing the source code and binary forms
450Sstevel@tonic-gate  *    agrees to the disclaimer below and the terms and conditions set forth
460Sstevel@tonic-gate  *    herein.
470Sstevel@tonic-gate  *
480Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
490Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
500Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
510Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
520Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
530Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
540Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
550Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
560Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
570Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
580Sstevel@tonic-gate  * SUCH DAMAGE.
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #include <sys/int_types.h>
620Sstevel@tonic-gate #include <sys/scsi/scsi.h>
630Sstevel@tonic-gate #include <sys/dkbad.h>
640Sstevel@tonic-gate #include <sys/dklabel.h>
650Sstevel@tonic-gate #include <sys/dkio.h>
660Sstevel@tonic-gate #include <sys/cdio.h>
670Sstevel@tonic-gate #include <sys/mhd.h>
680Sstevel@tonic-gate #include <sys/vtoc.h>
690Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
700Sstevel@tonic-gate #include <sys/scsi/targets/sddef.h>
710Sstevel@tonic-gate #include <sys/debug.h>
720Sstevel@tonic-gate #include <sys/pci.h>
730Sstevel@tonic-gate #include <sys/ksynch.h>
740Sstevel@tonic-gate #include <sys/ddi.h>
750Sstevel@tonic-gate #include <sys/sunddi.h>
760Sstevel@tonic-gate #include <sys/modctl.h>
770Sstevel@tonic-gate #include <sys/byteorder.h>
780Sstevel@tonic-gate 
790Sstevel@tonic-gate #include "amrreg.h"
800Sstevel@tonic-gate #include "amrvar.h"
810Sstevel@tonic-gate 
820Sstevel@tonic-gate /* dynamic debug symbol */
830Sstevel@tonic-gate int	amr_debug_var = 0;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #define	AMR_DELAY(cond, count, done_flag) { \
860Sstevel@tonic-gate 		int local_counter = 0; \
870Sstevel@tonic-gate 		done_flag = 1; \
880Sstevel@tonic-gate 		while (!(cond)) { \
890Sstevel@tonic-gate 			delay(drv_usectohz(100)); \
900Sstevel@tonic-gate 			if ((local_counter) > count) { \
910Sstevel@tonic-gate 				done_flag = 0; \
920Sstevel@tonic-gate 				break; \
930Sstevel@tonic-gate 			} \
940Sstevel@tonic-gate 			(local_counter)++; \
950Sstevel@tonic-gate 		} \
960Sstevel@tonic-gate 	}
970Sstevel@tonic-gate 
980Sstevel@tonic-gate #define	AMR_BUSYWAIT(cond, count, done_flag) { \
990Sstevel@tonic-gate 		int local_counter = 0; \
1000Sstevel@tonic-gate 		done_flag = 1; \
1010Sstevel@tonic-gate 		while (!(cond)) { \
1020Sstevel@tonic-gate 			drv_usecwait(100); \
1030Sstevel@tonic-gate 			if ((local_counter) > count) { \
1040Sstevel@tonic-gate 				done_flag = 0; \
1050Sstevel@tonic-gate 				break; \
1060Sstevel@tonic-gate 			} \
1070Sstevel@tonic-gate 			(local_counter)++; \
1080Sstevel@tonic-gate 		} \
1090Sstevel@tonic-gate 	}
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * driver interfaces
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate char _depends_on[] = "misc/scsi";
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static uint_t amr_intr(caddr_t arg);
1170Sstevel@tonic-gate static void amr_done(struct amr_softs *softs);
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
1200Sstevel@tonic-gate 			void *arg, void **result);
1210Sstevel@tonic-gate static int amr_attach(dev_info_t *, ddi_attach_cmd_t);
1220Sstevel@tonic-gate static int amr_detach(dev_info_t *, ddi_detach_cmd_t);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate static int amr_setup_mbox(struct amr_softs *softs);
1250Sstevel@tonic-gate static int amr_setup_sg(struct amr_softs *softs);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate /*
1280Sstevel@tonic-gate  * Command wrappers
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate static int amr_query_controller(struct amr_softs *softs);
1310Sstevel@tonic-gate static void *amr_enquiry(struct amr_softs *softs, size_t bufsize,
1320Sstevel@tonic-gate 			uint8_t cmd, uint8_t cmdsub, uint8_t cmdqual);
1330Sstevel@tonic-gate static int amr_flush(struct amr_softs *softs);
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate /*
1360Sstevel@tonic-gate  * Command processing.
1370Sstevel@tonic-gate  */
1380Sstevel@tonic-gate static void amr_rw_command(struct amr_softs *softs,
1390Sstevel@tonic-gate 			struct scsi_pkt *pkt, int lun);
1400Sstevel@tonic-gate static void amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp,
1410Sstevel@tonic-gate 			unsigned int capacity);
1420Sstevel@tonic-gate static void amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key);
1430Sstevel@tonic-gate static int amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size);
1440Sstevel@tonic-gate static void amr_enquiry_unmapcmd(struct amr_command *ac);
1453495Syw161884 static int amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg);
1460Sstevel@tonic-gate static void amr_unmapcmd(struct amr_command *ac);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * Status monitoring
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate static void amr_periodic(void *data);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * Interface-specific shims
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate static int amr_poll_command(struct amr_command *ac);
1570Sstevel@tonic-gate static void amr_start_waiting_queue(void *softp);
1580Sstevel@tonic-gate static void amr_call_pkt_comp(struct amr_command *head);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate /*
1610Sstevel@tonic-gate  * SCSI interface
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate static int amr_setup_tran(dev_info_t  *dip, struct amr_softs *softp);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate  * Function prototypes
1670Sstevel@tonic-gate  *
1680Sstevel@tonic-gate  * SCSA functions exported by means of the transport table
1690Sstevel@tonic-gate  */
1700Sstevel@tonic-gate static int amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
1710Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd);
1720Sstevel@tonic-gate static int amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt);
1730Sstevel@tonic-gate static int amr_tran_reset(struct scsi_address *ap, int level);
1740Sstevel@tonic-gate static int amr_tran_getcap(struct scsi_address *ap, char *cap, int whom);
1750Sstevel@tonic-gate static int amr_tran_setcap(struct scsi_address *ap, char *cap, int value,
1760Sstevel@tonic-gate     int whom);
1770Sstevel@tonic-gate static struct scsi_pkt *amr_tran_init_pkt(struct scsi_address *ap,
1780Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
1790Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg);
1800Sstevel@tonic-gate static void amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt);
1810Sstevel@tonic-gate static void amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt);
1820Sstevel@tonic-gate static void amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt);
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate static ddi_dma_attr_t buffer_dma_attr = {
1850Sstevel@tonic-gate 		DMA_ATTR_V0,	/* version of this structure */
1860Sstevel@tonic-gate 		0,		/* lowest usable address */
1870Sstevel@tonic-gate 		0xffffffffull,	/* highest usable address */
1880Sstevel@tonic-gate 		0x00ffffffull,	/* maximum DMAable byte count */
1890Sstevel@tonic-gate 		4,		/* alignment */
1900Sstevel@tonic-gate 		1,		/* burst sizes */
1910Sstevel@tonic-gate 		1,		/* minimum transfer */
1920Sstevel@tonic-gate 		0xffffffffull,	/* maximum transfer */
1930Sstevel@tonic-gate 		0xffffffffull,	/* maximum segment length */
1940Sstevel@tonic-gate 		AMR_NSEG,	/* maximum number of segments */
1950Sstevel@tonic-gate 		AMR_BLKSIZE,	/* granularity */
1960Sstevel@tonic-gate 		0,		/* flags (reserved) */
1970Sstevel@tonic-gate };
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate static ddi_dma_attr_t addr_dma_attr = {
2000Sstevel@tonic-gate 		DMA_ATTR_V0,	/* version of this structure */
2010Sstevel@tonic-gate 		0,		/* lowest usable address */
2020Sstevel@tonic-gate 		0xffffffffull,	/* highest usable address */
2030Sstevel@tonic-gate 		0x7fffffff,	/* maximum DMAable byte count */
2040Sstevel@tonic-gate 		4,		/* alignment */
2050Sstevel@tonic-gate 		1,		/* burst sizes */
2060Sstevel@tonic-gate 		1,		/* minimum transfer */
2070Sstevel@tonic-gate 		0xffffffffull,	/* maximum transfer */
2080Sstevel@tonic-gate 		0xffffffffull,	/* maximum segment length */
2090Sstevel@tonic-gate 		1,		/* maximum number of segments */
2100Sstevel@tonic-gate 		1,		/* granularity */
2110Sstevel@tonic-gate 		0,		/* flags (reserved) */
2120Sstevel@tonic-gate };
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static struct dev_ops   amr_ops = {
2160Sstevel@tonic-gate 	DEVO_REV,	/* devo_rev, */
2170Sstevel@tonic-gate 	0,		/* refcnt  */
2180Sstevel@tonic-gate 	amr_info,	/* info */
2190Sstevel@tonic-gate 	nulldev,	/* identify */
2200Sstevel@tonic-gate 	nulldev,	/* probe */
2210Sstevel@tonic-gate 	amr_attach,	/* attach */
2220Sstevel@tonic-gate 	amr_detach,	/* detach */
2230Sstevel@tonic-gate 	nodev,		/* reset */
2240Sstevel@tonic-gate 	NULL,		/* driver operations */
2250Sstevel@tonic-gate 	(struct bus_ops *)0,	/* bus operations */
2260Sstevel@tonic-gate 	0		/* power */
2270Sstevel@tonic-gate };
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2310Sstevel@tonic-gate static struct modldrv modldrv = {
2320Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. driver here */
233*7542SRichard.Bean@Sun.COM 	"AMR Driver",		/* Name of the module. */
2340Sstevel@tonic-gate 	&amr_ops,		/* Driver ops vector */
2350Sstevel@tonic-gate };
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate static struct modlinkage modlinkage = {
2380Sstevel@tonic-gate 	MODREV_1,
2390Sstevel@tonic-gate 	&modldrv,
2400Sstevel@tonic-gate 	NULL
2410Sstevel@tonic-gate };
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /* DMA access attributes */
2440Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = {
2450Sstevel@tonic-gate 	DDI_DEVICE_ATTR_V0,
2460Sstevel@tonic-gate 	DDI_NEVERSWAP_ACC,
2470Sstevel@tonic-gate 	DDI_STRICTORDER_ACC
2480Sstevel@tonic-gate };
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate static struct amr_softs  *amr_softstatep;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate int
2540Sstevel@tonic-gate _init(void)
2550Sstevel@tonic-gate {
2560Sstevel@tonic-gate 	int		error;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	error = ddi_soft_state_init((void *)&amr_softstatep,
2590Sstevel@tonic-gate 			sizeof (struct amr_softs), 0);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if (error != 0)
2620Sstevel@tonic-gate 		goto error_out;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	if ((error = scsi_hba_init(&modlinkage)) != 0) {
2650Sstevel@tonic-gate 		ddi_soft_state_fini((void*)&amr_softstatep);
2660Sstevel@tonic-gate 		goto error_out;
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	error = mod_install(&modlinkage);
2700Sstevel@tonic-gate 	if (error != 0) {
2710Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
2720Sstevel@tonic-gate 		ddi_soft_state_fini((void*)&amr_softstatep);
2730Sstevel@tonic-gate 		goto error_out;
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	return (error);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate error_out:
2790Sstevel@tonic-gate 	cmn_err(CE_NOTE, "_init failed");
2800Sstevel@tonic-gate 	return (error);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate int
2840Sstevel@tonic-gate _info(struct modinfo *modinfop)
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate int
2900Sstevel@tonic-gate _fini(void)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	int	error;
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) != 0) {
2950Sstevel@tonic-gate 		return (error);
2960Sstevel@tonic-gate 	}
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	scsi_hba_fini(&modlinkage);
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	ddi_soft_state_fini((void*)&amr_softstatep);
3010Sstevel@tonic-gate 	return (error);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate static int
3060Sstevel@tonic-gate amr_attach(dev_info_t *dev, ddi_attach_cmd_t cmd)
3070Sstevel@tonic-gate {
3080Sstevel@tonic-gate 	struct amr_softs	*softs;
3090Sstevel@tonic-gate 	int			error;
3100Sstevel@tonic-gate 	uint32_t		command, i;
3110Sstevel@tonic-gate 	int			instance;
3120Sstevel@tonic-gate 	caddr_t			cfgaddr;
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	instance = ddi_get_instance(dev);
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	switch (cmd) {
3170Sstevel@tonic-gate 		case DDI_ATTACH:
3180Sstevel@tonic-gate 			break;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 		case DDI_RESUME:
3210Sstevel@tonic-gate 			return (DDI_FAILURE);
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 		default:
3240Sstevel@tonic-gate 			return (DDI_FAILURE);
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	/*
3280Sstevel@tonic-gate 	 * Initialize softs.
3290Sstevel@tonic-gate 	 */
3300Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(amr_softstatep, instance) != DDI_SUCCESS)
3310Sstevel@tonic-gate 		return (DDI_FAILURE);
3320Sstevel@tonic-gate 	softs = ddi_get_soft_state(amr_softstatep, instance);
3330Sstevel@tonic-gate 	softs->state |= AMR_STATE_SOFT_STATE_SETUP;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	softs->dev_info_p = dev;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "softs: %p; busy_slot addr: %p",
3380Sstevel@tonic-gate 		(void *)softs, (void *)&(softs->amr_busyslots)));
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	if (pci_config_setup(dev, &(softs->pciconfig_handle))
3410Sstevel@tonic-gate 		!= DDI_SUCCESS) {
3420Sstevel@tonic-gate 		goto error_out;
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 	softs->state |= AMR_STATE_PCI_CONFIG_SETUP;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	error = ddi_regs_map_setup(dev, 1, &cfgaddr, 0, 0,
3470Sstevel@tonic-gate 		&accattr, &(softs->regsmap_handle));
3480Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
3490Sstevel@tonic-gate 		goto error_out;
3500Sstevel@tonic-gate 	}
3510Sstevel@tonic-gate 	softs->state |= AMR_STATE_PCI_MEM_MAPPED;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/*
3540Sstevel@tonic-gate 	 * Determine board type.
3550Sstevel@tonic-gate 	 */
3560Sstevel@tonic-gate 	command = pci_config_get16(softs->pciconfig_handle, PCI_CONF_COMM);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	/*
3590Sstevel@tonic-gate 	 * Make sure we are going to be able to talk to this board.
3600Sstevel@tonic-gate 	 */
3610Sstevel@tonic-gate 	if ((command & PCI_COMM_MAE) == 0) {
3620Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,  "memory window not available"));
3630Sstevel@tonic-gate 		goto error_out;
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/* force the busmaster enable bit on */
3670Sstevel@tonic-gate 	if (!(command & PCI_COMM_ME)) {
3680Sstevel@tonic-gate 		command |= PCI_COMM_ME;
3690Sstevel@tonic-gate 		pci_config_put16(softs->pciconfig_handle,
3700Sstevel@tonic-gate 				PCI_CONF_COMM, command);
3710Sstevel@tonic-gate 		command = pci_config_get16(softs->pciconfig_handle,
3720Sstevel@tonic-gate 				PCI_CONF_COMM);
3730Sstevel@tonic-gate 		if (!(command & PCI_COMM_ME))
3740Sstevel@tonic-gate 			goto error_out;
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	/*
3780Sstevel@tonic-gate 	 * Allocate and connect our interrupt.
3790Sstevel@tonic-gate 	 */
3800Sstevel@tonic-gate 	if (ddi_intr_hilevel(dev, 0) != 0) {
3810Sstevel@tonic-gate 	    AMRDB_PRINT((CE_NOTE,  "High level interrupt is not supported!"));
3820Sstevel@tonic-gate 	    goto error_out;
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dev, 0,  &softs->iblock_cookiep)
3860Sstevel@tonic-gate 		!= DDI_SUCCESS) {
3870Sstevel@tonic-gate 		goto error_out;
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	mutex_init(&softs->cmd_mutex, NULL, MUTEX_DRIVER,
3910Sstevel@tonic-gate 		softs->iblock_cookiep); /* should be used in interrupt */
3920Sstevel@tonic-gate 	mutex_init(&softs->queue_mutex, NULL, MUTEX_DRIVER,
3930Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3940Sstevel@tonic-gate 	mutex_init(&softs->periodic_mutex, NULL, MUTEX_DRIVER,
3950Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3960Sstevel@tonic-gate 	/* sychronize waits for the busy slots via this cv */
3970Sstevel@tonic-gate 	cv_init(&softs->cmd_cv, NULL, CV_DRIVER, NULL);
3980Sstevel@tonic-gate 	softs->state |= AMR_STATE_KMUTEX_INITED;
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	/*
4010Sstevel@tonic-gate 	 * Do bus-independent initialisation, bring controller online.
4020Sstevel@tonic-gate 	 */
4030Sstevel@tonic-gate 	if (amr_setup_mbox(softs) != DDI_SUCCESS)
4040Sstevel@tonic-gate 		goto error_out;
4050Sstevel@tonic-gate 	softs->state |= AMR_STATE_MAILBOX_SETUP;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	if (amr_setup_sg(softs) != DDI_SUCCESS)
4080Sstevel@tonic-gate 		goto error_out;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	softs->state |= AMR_STATE_SG_TABLES_SETUP;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	if (amr_query_controller(softs) != DDI_SUCCESS)
4130Sstevel@tonic-gate 		goto error_out;
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	/*
4160Sstevel@tonic-gate 	 * A taskq is created for dispatching the waiting queue processing
4170Sstevel@tonic-gate 	 * thread. The threads number equals to the logic drive number and
4180Sstevel@tonic-gate 	 * the thread number should be 1 if there is no logic driver is
4190Sstevel@tonic-gate 	 * configured for this instance.
4200Sstevel@tonic-gate 	 */
4210Sstevel@tonic-gate 	if ((softs->amr_taskq = ddi_taskq_create(dev, "amr_taskq",
4220Sstevel@tonic-gate 		MAX(softs->amr_nlogdrives, 1), TASKQ_DEFAULTPRI, 0)) == NULL) {
4230Sstevel@tonic-gate 		goto error_out;
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 	softs->state |= AMR_STATE_TASKQ_SETUP;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (ddi_add_intr(dev, 0, &softs->iblock_cookiep, NULL,
4280Sstevel@tonic-gate 		amr_intr, (caddr_t)softs) != DDI_SUCCESS) {
4290Sstevel@tonic-gate 		goto error_out;
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 	softs->state |= AMR_STATE_INTR_SETUP;
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/* set up the tran interface */
4340Sstevel@tonic-gate 	if (amr_setup_tran(softs->dev_info_p, softs) != DDI_SUCCESS) {
4350Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "setup tran failed"));
4360Sstevel@tonic-gate 		goto error_out;
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 	softs->state |= AMR_STATE_TRAN_SETUP;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	/* schedule a thread for periodic check */
4410Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
4420Sstevel@tonic-gate 	softs->timeout_t = timeout(amr_periodic, (void *)softs,
4430Sstevel@tonic-gate 				drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
4440Sstevel@tonic-gate 	softs->state |= AMR_STATE_TIMEOUT_ENABLED;
4450Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/* print firmware information in verbose mode */
4480Sstevel@tonic-gate 	cmn_err(CE_CONT, "?MegaRaid %s %s attached.",
4490Sstevel@tonic-gate 		softs->amr_product_info.pi_product_name,
4500Sstevel@tonic-gate 		softs->amr_product_info.pi_firmware_ver);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* clear any interrupts */
4530Sstevel@tonic-gate 	AMR_QCLEAR_INTR(softs);
4540Sstevel@tonic-gate 	return (DDI_SUCCESS);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate error_out:
4570Sstevel@tonic-gate 	if (softs->state & AMR_STATE_INTR_SETUP) {
4580Sstevel@tonic-gate 		ddi_remove_intr(dev, 0, softs->iblock_cookiep);
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TASKQ_SETUP) {
4610Sstevel@tonic-gate 		ddi_taskq_destroy(softs->amr_taskq);
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate 	if (softs->state & AMR_STATE_SG_TABLES_SETUP) {
4640Sstevel@tonic-gate 		for (i = 0; i < softs->sg_max_count; i++) {
4650Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
4660Sstevel@tonic-gate 				softs->sg_items[i].sg_handle);
4670Sstevel@tonic-gate 			(void) ddi_dma_mem_free(
4680Sstevel@tonic-gate 				&((softs->sg_items[i]).sg_acc_handle));
4690Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
4700Sstevel@tonic-gate 				&(softs->sg_items[i].sg_handle));
4710Sstevel@tonic-gate 		}
4720Sstevel@tonic-gate 	}
4730Sstevel@tonic-gate 	if (softs->state & AMR_STATE_MAILBOX_SETUP) {
4740Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
4750Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&softs->mbox_acc_handle);
4760Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 	if (softs->state & AMR_STATE_KMUTEX_INITED) {
4790Sstevel@tonic-gate 		mutex_destroy(&softs->queue_mutex);
4800Sstevel@tonic-gate 		mutex_destroy(&softs->cmd_mutex);
4810Sstevel@tonic-gate 		mutex_destroy(&softs->periodic_mutex);
4820Sstevel@tonic-gate 		cv_destroy(&softs->cmd_cv);
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate 	if (softs->state & AMR_STATE_PCI_MEM_MAPPED)
4850Sstevel@tonic-gate 		ddi_regs_map_free(&softs->regsmap_handle);
4860Sstevel@tonic-gate 	if (softs->state & AMR_STATE_PCI_CONFIG_SETUP)
4870Sstevel@tonic-gate 		pci_config_teardown(&softs->pciconfig_handle);
4880Sstevel@tonic-gate 	if (softs->state & AMR_STATE_SOFT_STATE_SETUP)
4890Sstevel@tonic-gate 		ddi_soft_state_free(amr_softstatep, instance);
4900Sstevel@tonic-gate 	return (DDI_FAILURE);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate /*
4940Sstevel@tonic-gate  * Bring the controller down to a dormant state and detach all child devices.
4950Sstevel@tonic-gate  * This function is called during detach, system shutdown.
4960Sstevel@tonic-gate  *
4970Sstevel@tonic-gate  * Note that we can assume that the bufq on the controller is empty, as we won't
4980Sstevel@tonic-gate  * allow shutdown if any device is open.
4990Sstevel@tonic-gate  */
5000Sstevel@tonic-gate /*ARGSUSED*/
5010Sstevel@tonic-gate static int amr_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
5020Sstevel@tonic-gate {
5030Sstevel@tonic-gate 	struct amr_softs	*softs;
5040Sstevel@tonic-gate 	int			instance;
5050Sstevel@tonic-gate 	uint32_t		i, done_flag;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	instance = ddi_get_instance(dev);
5080Sstevel@tonic-gate 	softs = ddi_get_soft_state(amr_softstatep, instance);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	/* flush the controllor */
5110Sstevel@tonic-gate 	if (amr_flush(softs) != 0) {
5120Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "device shutdown failed"));
5130Sstevel@tonic-gate 		return (EIO);
5140Sstevel@tonic-gate 	}
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 	/* release the amr timer */
5170Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
5180Sstevel@tonic-gate 	softs->state &= ~AMR_STATE_TIMEOUT_ENABLED;
5190Sstevel@tonic-gate 	if (softs->timeout_t) {
5200Sstevel@tonic-gate 		(void) untimeout(softs->timeout_t);
5210Sstevel@tonic-gate 		softs->timeout_t = 0;
5220Sstevel@tonic-gate 	}
5230Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 	for (i = 0; i < softs->sg_max_count; i++) {
5260Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(
5270Sstevel@tonic-gate 			softs->sg_items[i].sg_handle);
5280Sstevel@tonic-gate 		(void) ddi_dma_mem_free(
5290Sstevel@tonic-gate 			&((softs->sg_items[i]).sg_acc_handle));
5300Sstevel@tonic-gate 		(void) ddi_dma_free_handle(
5310Sstevel@tonic-gate 			&(softs->sg_items[i].sg_handle));
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
5350Sstevel@tonic-gate 	(void) ddi_dma_mem_free(&softs->mbox_acc_handle);
5360Sstevel@tonic-gate 	(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/* disconnect the interrupt handler */
5390Sstevel@tonic-gate 	ddi_remove_intr(softs->dev_info_p,  0, softs->iblock_cookiep);
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate 	/* wait for the completion of current in-progress interruptes */
5420Sstevel@tonic-gate 	AMR_DELAY((softs->amr_interrupts_counter == 0), 1000, done_flag);
5430Sstevel@tonic-gate 	if (!done_flag) {
5440Sstevel@tonic-gate 		cmn_err(CE_WARN, "Suspicious interrupts in-progress.");
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	ddi_taskq_destroy(softs->amr_taskq);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	(void) scsi_hba_detach(dev);
5500Sstevel@tonic-gate 	scsi_hba_tran_free(softs->hba_tran);
5510Sstevel@tonic-gate 	ddi_regs_map_free(&softs->regsmap_handle);
5520Sstevel@tonic-gate 	pci_config_teardown(&softs->pciconfig_handle);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	mutex_destroy(&softs->queue_mutex);
5550Sstevel@tonic-gate 	mutex_destroy(&softs->cmd_mutex);
5560Sstevel@tonic-gate 	mutex_destroy(&softs->periodic_mutex);
5570Sstevel@tonic-gate 	cv_destroy(&softs->cmd_cv);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	/* print firmware information in verbose mode */
5600Sstevel@tonic-gate 	cmn_err(CE_NOTE, "?MegaRaid %s %s detached.",
5610Sstevel@tonic-gate 		softs->amr_product_info.pi_product_name,
5620Sstevel@tonic-gate 		softs->amr_product_info.pi_firmware_ver);
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	ddi_soft_state_free(amr_softstatep, instance);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	return (DDI_SUCCESS);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate /*ARGSUSED*/
5710Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5720Sstevel@tonic-gate 	void *arg, void **result)
5730Sstevel@tonic-gate {
5740Sstevel@tonic-gate 	struct amr_softs	*softs;
5750Sstevel@tonic-gate 	int			instance;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	switch (infocmd) {
5800Sstevel@tonic-gate 		case DDI_INFO_DEVT2DEVINFO:
5810Sstevel@tonic-gate 			softs = ddi_get_soft_state(amr_softstatep, instance);
5820Sstevel@tonic-gate 			if (softs != NULL) {
5830Sstevel@tonic-gate 				*result = softs->dev_info_p;
5840Sstevel@tonic-gate 				return (DDI_SUCCESS);
5850Sstevel@tonic-gate 			} else {
5860Sstevel@tonic-gate 				*result = NULL;
5870Sstevel@tonic-gate 				return (DDI_FAILURE);
5880Sstevel@tonic-gate 			}
5890Sstevel@tonic-gate 		case DDI_INFO_DEVT2INSTANCE:
5900Sstevel@tonic-gate 			*(int *)result = instance;
5910Sstevel@tonic-gate 			break;
5920Sstevel@tonic-gate 		default:
5930Sstevel@tonic-gate 			break;
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 	return (DDI_SUCCESS);
5960Sstevel@tonic-gate }
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate /*
5990Sstevel@tonic-gate  * Take an interrupt, or be poked by other code to look for interrupt-worthy
6000Sstevel@tonic-gate  * status.
6010Sstevel@tonic-gate  */
6020Sstevel@tonic-gate static uint_t
6030Sstevel@tonic-gate amr_intr(caddr_t arg)
6040Sstevel@tonic-gate {
6050Sstevel@tonic-gate 	struct amr_softs *softs = (struct amr_softs *)arg;
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	softs->amr_interrupts_counter++;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if (AMR_QGET_ODB(softs) != AMR_QODB_READY) {
6100Sstevel@tonic-gate 		softs->amr_interrupts_counter--;
6110Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
6120Sstevel@tonic-gate 	}
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	/* collect finished commands, queue anything waiting */
6150Sstevel@tonic-gate 	amr_done(softs);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	softs->amr_interrupts_counter--;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate  * Setup the amr mailbox
6250Sstevel@tonic-gate  */
6260Sstevel@tonic-gate static int
6270Sstevel@tonic-gate amr_setup_mbox(struct amr_softs *softs)
6280Sstevel@tonic-gate {
6290Sstevel@tonic-gate 	uint32_t	move;
6300Sstevel@tonic-gate 	size_t		mbox_len;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(
6330Sstevel@tonic-gate 		softs->dev_info_p,
6340Sstevel@tonic-gate 		&addr_dma_attr,
6350Sstevel@tonic-gate 		DDI_DMA_SLEEP,
6360Sstevel@tonic-gate 		NULL,
6370Sstevel@tonic-gate 		&softs->mbox_dma_handle) != DDI_SUCCESS) {
6380Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "Cannot alloc dma handle for mailbox"));
6390Sstevel@tonic-gate 		goto error_out;
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(
6430Sstevel@tonic-gate 		softs->mbox_dma_handle,
6440Sstevel@tonic-gate 		sizeof (struct amr_mailbox) + 16,
6450Sstevel@tonic-gate 		&accattr,
6460Sstevel@tonic-gate 		DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6470Sstevel@tonic-gate 		DDI_DMA_SLEEP,
6480Sstevel@tonic-gate 		NULL,
6490Sstevel@tonic-gate 		(caddr_t *)(&softs->mbox),
6500Sstevel@tonic-gate 		&mbox_len,
6510Sstevel@tonic-gate 		&softs->mbox_acc_handle) !=
6520Sstevel@tonic-gate 		DDI_SUCCESS) {
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "Cannot alloc dma memory for mailbox"));
6550Sstevel@tonic-gate 		goto error_out;
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	if (ddi_dma_addr_bind_handle(
6590Sstevel@tonic-gate 		softs->mbox_dma_handle,
6600Sstevel@tonic-gate 		NULL,
6610Sstevel@tonic-gate 		(caddr_t)softs->mbox,
6623495Syw161884 		mbox_len,
6630Sstevel@tonic-gate 		DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6640Sstevel@tonic-gate 		DDI_DMA_SLEEP,
6650Sstevel@tonic-gate 		NULL,
6660Sstevel@tonic-gate 		&softs->mbox_dma_cookie,
6670Sstevel@tonic-gate 		&softs->mbox_dma_cookien) != DDI_DMA_MAPPED) {
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "Cannot bind dma memory for mailbox"));
6700Sstevel@tonic-gate 		goto error_out;
6710Sstevel@tonic-gate 	}
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 	if (softs->mbox_dma_cookien != 1)
6740Sstevel@tonic-gate 		goto error_out;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	/* The phy address of mailbox must be aligned on a 16-byte boundary */
6770Sstevel@tonic-gate 	move = 16 - (((uint32_t)softs->mbox_dma_cookie.dmac_address)&0xf);
6780Sstevel@tonic-gate 	softs->mbox_phyaddr =
6790Sstevel@tonic-gate 		(softs->mbox_dma_cookie.dmac_address + move);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	softs->mailbox =
6820Sstevel@tonic-gate 		(struct amr_mailbox *)(((uintptr_t)softs->mbox) + move);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "phraddy=%x, mailbox=%p, softs->mbox=%p, move=%x",
6850Sstevel@tonic-gate 		softs->mbox_phyaddr, (void *)softs->mailbox,
6860Sstevel@tonic-gate 		softs->mbox, move));
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	return (DDI_SUCCESS);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate error_out:
6910Sstevel@tonic-gate 	if (softs->mbox_dma_cookien)
6920Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
6930Sstevel@tonic-gate 	if (softs->mbox_acc_handle) {
6940Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&(softs->mbox_acc_handle));
6950Sstevel@tonic-gate 		softs->mbox_acc_handle = NULL;
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 	if (softs->mbox_dma_handle) {
6980Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
6990Sstevel@tonic-gate 		softs->mbox_dma_handle = NULL;
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	return (DDI_FAILURE);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate /*
7060Sstevel@tonic-gate  * Perform a periodic check of the controller status
7070Sstevel@tonic-gate  */
7080Sstevel@tonic-gate static void
7090Sstevel@tonic-gate amr_periodic(void *data)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	uint32_t		i;
7120Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)data;
7130Sstevel@tonic-gate 	struct scsi_pkt 	*pkt;
7140Sstevel@tonic-gate 	register struct amr_command	*ac;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	for (i = 0; i < softs->sg_max_count; i++) {
7170Sstevel@tonic-gate 		if (softs->busycmd[i] == NULL)
7180Sstevel@tonic-gate 			continue;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 		mutex_enter(&softs->cmd_mutex);
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 		if (softs->busycmd[i] == NULL) {
7230Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7240Sstevel@tonic-gate 			continue;
7250Sstevel@tonic-gate 		}
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 		pkt = softs->busycmd[i]->pkt;
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 		if ((pkt->pkt_time != 0) &&
7300Sstevel@tonic-gate 			(ddi_get_time() -
7310Sstevel@tonic-gate 			softs->busycmd[i]->ac_timestamp >
7320Sstevel@tonic-gate 			pkt->pkt_time)) {
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 			cmn_err(CE_WARN,
7353495Syw161884 				"!timed out packet detected,\
7360Sstevel@tonic-gate 				sc = %p, pkt = %p, index = %d, ac = %p",
7370Sstevel@tonic-gate 				(void *)softs,
7380Sstevel@tonic-gate 				(void *)pkt,
7390Sstevel@tonic-gate 				i,
7400Sstevel@tonic-gate 				(void *)softs->busycmd[i]);
7410Sstevel@tonic-gate 
7420Sstevel@tonic-gate 			ac = softs->busycmd[i];
7430Sstevel@tonic-gate 			ac->ac_next = NULL;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 			/* pull command from the busy index */
7460Sstevel@tonic-gate 			softs->busycmd[i] = NULL;
7470Sstevel@tonic-gate 			if (softs->amr_busyslots > 0)
7480Sstevel@tonic-gate 				softs->amr_busyslots--;
7490Sstevel@tonic-gate 			if (softs->amr_busyslots == 0)
7500Sstevel@tonic-gate 				cv_broadcast(&softs->cmd_cv);
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 			pkt = ac->pkt;
7550Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
7560Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_TIMEOUT;
7570Sstevel@tonic-gate 			pkt->pkt_reason = CMD_TIMEOUT;
7580Sstevel@tonic-gate 			if (!(pkt->pkt_flags &
7590Sstevel@tonic-gate 			FLAG_NOINTR) && pkt->pkt_comp) {
7600Sstevel@tonic-gate 				/* call pkt callback */
7610Sstevel@tonic-gate 				(*pkt->pkt_comp)(pkt);
7620Sstevel@tonic-gate 			}
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 		} else {
7650Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7660Sstevel@tonic-gate 		}
7670Sstevel@tonic-gate 	}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	/* restart the amr timer */
7700Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
7710Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TIMEOUT_ENABLED)
7720Sstevel@tonic-gate 		softs->timeout_t = timeout(amr_periodic, (void *)softs,
7730Sstevel@tonic-gate 				drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
7740Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
7750Sstevel@tonic-gate }
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate /*
7780Sstevel@tonic-gate  * Interrogate the controller for the operational parameters we require.
7790Sstevel@tonic-gate  */
7800Sstevel@tonic-gate static int
7810Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs)
7820Sstevel@tonic-gate {
7830Sstevel@tonic-gate 	struct amr_enquiry3	*aex;
7840Sstevel@tonic-gate 	struct amr_prodinfo	*ap;
7850Sstevel@tonic-gate 	struct amr_enquiry	*ae;
7860Sstevel@tonic-gate 	uint32_t		ldrv;
7870Sstevel@tonic-gate 	int			instance;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 	/*
7900Sstevel@tonic-gate 	 * If we haven't found the real limit yet, let us have a couple of
7910Sstevel@tonic-gate 	 * commands in order to be able to probe.
7920Sstevel@tonic-gate 	 */
7930Sstevel@tonic-gate 	if (softs->maxio == 0)
7940Sstevel@tonic-gate 		softs->maxio = 2;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	instance = ddi_get_instance(softs->dev_info_p);
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	/*
7990Sstevel@tonic-gate 	 * Try to issue an ENQUIRY3 command
8000Sstevel@tonic-gate 	 */
8010Sstevel@tonic-gate 	if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG,
8020Sstevel@tonic-gate 		AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry"));
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 		for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
8070Sstevel@tonic-gate 		    softs->logic_drive[ldrv].al_size =
8080Sstevel@tonic-gate 						aex->ae_drivesize[ldrv];
8090Sstevel@tonic-gate 		    softs->logic_drive[ldrv].al_state =
8100Sstevel@tonic-gate 						aex->ae_drivestate[ldrv];
8110Sstevel@tonic-gate 		    softs->logic_drive[ldrv].al_properties =
8120Sstevel@tonic-gate 						aex->ae_driveprop[ldrv];
8130Sstevel@tonic-gate 		    AMRDB_PRINT((CE_NOTE,
8140Sstevel@tonic-gate 			"  drive %d: size: %d state %x properties %x\n",
8150Sstevel@tonic-gate 			ldrv,
8160Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_size,
8170Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_state,
8180Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_properties));
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 		    if (softs->logic_drive[ldrv].al_state == AMR_LDRV_OFFLINE)
8210Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!instance %d log-drive %d is offline",
8220Sstevel@tonic-gate 				instance, ldrv);
8230Sstevel@tonic-gate 		    else
8240Sstevel@tonic-gate 			softs->amr_nlogdrives++;
8250Sstevel@tonic-gate 		}
8260Sstevel@tonic-gate 		kmem_free(aex, AMR_ENQ_BUFFER_SIZE);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 		if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE,
8290Sstevel@tonic-gate 			AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
8300Sstevel@tonic-gate 			AMRDB_PRINT((CE_NOTE,
8310Sstevel@tonic-gate 				"Cannot obtain product data from controller"));
8320Sstevel@tonic-gate 			return (EIO);
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		softs->maxdrives = AMR_40LD_MAXDRIVES;
8360Sstevel@tonic-gate 		softs->maxchan = ap->ap_nschan;
8370Sstevel@tonic-gate 		softs->maxio = ap->ap_maxio;
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 		bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver,
8400Sstevel@tonic-gate 			AMR_FIRMWARE_VER_SIZE);
8410Sstevel@tonic-gate 		softs->amr_product_info.
8420Sstevel@tonic-gate 			pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 		bcopy(ap->ap_product, softs->amr_product_info.pi_product_name,
8450Sstevel@tonic-gate 			AMR_PRODUCT_INFO_SIZE);
8460Sstevel@tonic-gate 		softs->amr_product_info.
8470Sstevel@tonic-gate 			pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 		kmem_free(ap, AMR_ENQ_BUFFER_SIZE);
8500Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio));
8510Sstevel@tonic-gate 	} else {
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry failed, \
8540Sstevel@tonic-gate 				so try another way"));
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		/* failed, try the 8LD ENQUIRY commands */
8570Sstevel@tonic-gate 		if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
8580Sstevel@tonic-gate 			AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0))
8590Sstevel@tonic-gate 			== NULL) {
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 			if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
8620Sstevel@tonic-gate 				AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0))
8630Sstevel@tonic-gate 				== NULL) {
8640Sstevel@tonic-gate 				AMRDB_PRINT((CE_NOTE,
8650Sstevel@tonic-gate 					"Cannot obtain configuration data"));
8660Sstevel@tonic-gate 				return (EIO);
8670Sstevel@tonic-gate 			}
8680Sstevel@tonic-gate 			ae->ae_signature = 0;
8690Sstevel@tonic-gate 		}
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 		/*
8720Sstevel@tonic-gate 		 * Fetch current state of logical drives.
8730Sstevel@tonic-gate 		 */
8740Sstevel@tonic-gate 		for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
8750Sstevel@tonic-gate 		    softs->logic_drive[ldrv].al_size =
8760Sstevel@tonic-gate 						ae->ae_ldrv.al_size[ldrv];
8770Sstevel@tonic-gate 		    softs->logic_drive[ldrv].al_state =
8780Sstevel@tonic-gate 						ae->ae_ldrv.al_state[ldrv];
8790Sstevel@tonic-gate 		    softs->logic_drive[ldrv].al_properties =
8800Sstevel@tonic-gate 						ae->ae_ldrv.al_properties[ldrv];
8810Sstevel@tonic-gate 		    AMRDB_PRINT((CE_NOTE,
8820Sstevel@tonic-gate 			" ********* drive %d: %d state %x properties %x",
8830Sstevel@tonic-gate 			ldrv,
8840Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_size,
8850Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_state,
8860Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_properties));
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 		    if (softs->logic_drive[ldrv].al_state == AMR_LDRV_OFFLINE)
8890Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!instance %d log-drive %d is offline",
8900Sstevel@tonic-gate 				instance, ldrv);
8910Sstevel@tonic-gate 		    else
8920Sstevel@tonic-gate 			softs->amr_nlogdrives++;
8930Sstevel@tonic-gate 		}
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		softs->maxdrives = AMR_8LD_MAXDRIVES;
8960Sstevel@tonic-gate 		softs->maxchan = ae->ae_adapter.aa_channels;
8970Sstevel@tonic-gate 		softs->maxio = ae->ae_adapter.aa_maxio;
8980Sstevel@tonic-gate 		kmem_free(ae, AMR_ENQ_BUFFER_SIZE);
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/*
9020Sstevel@tonic-gate 	 * Mark remaining drives as unused.
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	for (; ldrv < AMR_MAXLD; ldrv++)
9050Sstevel@tonic-gate 		softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	/*
9080Sstevel@tonic-gate 	 * Cap the maximum number of outstanding I/Os.  AMI's driver
9090Sstevel@tonic-gate 	 * doesn't trust the controller's reported value, and lockups have
9100Sstevel@tonic-gate 	 * been seen when we do.
9110Sstevel@tonic-gate 	 */
9120Sstevel@tonic-gate 	softs->maxio = MIN(softs->maxio, AMR_LIMITCMD);
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	return (DDI_SUCCESS);
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate /*
9180Sstevel@tonic-gate  * Run a generic enquiry-style command.
9190Sstevel@tonic-gate  */
9200Sstevel@tonic-gate static void *
9210Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd,
9220Sstevel@tonic-gate 				uint8_t cmdsub, uint8_t cmdqual)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	struct amr_command	ac;
9250Sstevel@tonic-gate 	void			*result;
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	result = NULL;
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9300Sstevel@tonic-gate 	ac.ac_softs = softs;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	/* set command flags */
9330Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	/* build the command proper */
9360Sstevel@tonic-gate 	ac.mailbox.mb_command	= cmd;
9370Sstevel@tonic-gate 	ac.mailbox.mb_cmdsub	= cmdsub;
9380Sstevel@tonic-gate 	ac.mailbox.mb_cmdqual	= cmdqual;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS)
9410Sstevel@tonic-gate 		return (NULL);
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 	if (amr_poll_command(&ac) || ac.ac_status != 0) {
9440Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll command, goto out"));
9450Sstevel@tonic-gate 		amr_enquiry_unmapcmd(&ac);
9460Sstevel@tonic-gate 		return (NULL);
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	/* allocate the response structure */
9500Sstevel@tonic-gate 	result = kmem_zalloc(bufsize, KM_SLEEP);
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 	bcopy(ac.ac_data, result, bufsize);
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	amr_enquiry_unmapcmd(&ac);
9550Sstevel@tonic-gate 	return (result);
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate /*
9590Sstevel@tonic-gate  * Flush the controller's internal cache, return status.
9600Sstevel@tonic-gate  */
9610Sstevel@tonic-gate static int
9620Sstevel@tonic-gate amr_flush(struct amr_softs *softs)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	struct amr_command	ac;
9650Sstevel@tonic-gate 	int			error = 0;
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9680Sstevel@tonic-gate 	ac.ac_softs = softs;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	/* build the command proper */
9730Sstevel@tonic-gate 	ac.mailbox.mb_command = AMR_CMD_FLUSH;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	/* have to poll, as the system may be going down or otherwise damaged */
9760Sstevel@tonic-gate 	if (error = amr_poll_command(&ac)) {
9770Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll this cmd"));
9780Sstevel@tonic-gate 		return (error);
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	return (error);
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate /*
9850Sstevel@tonic-gate  * Take a command, submit it to the controller and wait for it to return.
9860Sstevel@tonic-gate  * Returns nonzero on error.  Can be safely called with interrupts enabled.
9870Sstevel@tonic-gate  */
9880Sstevel@tonic-gate static int
9890Sstevel@tonic-gate amr_poll_command(struct amr_command *ac)
9900Sstevel@tonic-gate {
9910Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
9920Sstevel@tonic-gate 	volatile uint32_t	done_flag;
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)",
9950Sstevel@tonic-gate 			(void *)&ac->mailbox,
9960Sstevel@tonic-gate 			(void *)softs->mailbox,
9970Sstevel@tonic-gate 			(uint32_t)AMR_MBOX_CMDSIZE));
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	while (softs->amr_busyslots != 0)
10020Sstevel@tonic-gate 		cv_wait(&softs->cmd_cv, &softs->cmd_mutex);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	/*
10050Sstevel@tonic-gate 	 * For read/write commands, the scatter/gather table should be
10060Sstevel@tonic-gate 	 * filled, and the last entry in scatter/gather table will be used.
10070Sstevel@tonic-gate 	 */
10080Sstevel@tonic-gate 	if ((ac->mailbox.mb_command == AMR_CMD_LREAD) ||
10090Sstevel@tonic-gate 	    (ac->mailbox.mb_command == AMR_CMD_LWRITE)) {
10100Sstevel@tonic-gate 		bcopy(ac->sgtable,
10110Sstevel@tonic-gate 			softs->sg_items[softs->sg_max_count - 1].sg_table,
10120Sstevel@tonic-gate 			sizeof (struct amr_sgentry) * AMR_NSEG);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 		(void) ddi_dma_sync(
10150Sstevel@tonic-gate 			softs->sg_items[softs->sg_max_count - 1].sg_handle,
10160Sstevel@tonic-gate 			0, 0, DDI_DMA_SYNC_FORDEV);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 		ac->mailbox.mb_physaddr =
10190Sstevel@tonic-gate 			softs->sg_items[softs->sg_max_count - 1].sg_phyaddr;
10200Sstevel@tonic-gate 	}
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	/* sync the dma memory */
10250Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	/* clear the poll/ack fields in the mailbox */
10280Sstevel@tonic-gate 	softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID;
10290Sstevel@tonic-gate 	softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS;
10300Sstevel@tonic-gate 	softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS;
10310Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10320Sstevel@tonic-gate 	softs->mailbox->mb_ack = 0;
10330Sstevel@tonic-gate 	softs->mailbox->mb_busy = 1;
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	/* sync the dma memory */
10380Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS),
10410Sstevel@tonic-gate 			1000, done_flag);
10420Sstevel@tonic-gate 	if (!done_flag) {
10430Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10440Sstevel@tonic-gate 		return (1);
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	ac->ac_status = softs->mailbox->mb_status;
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag);
10500Sstevel@tonic-gate 	if (!done_flag) {
10510Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10520Sstevel@tonic-gate 		return (1);
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10560Sstevel@tonic-gate 	softs->mailbox->mb_ack = AMR_POLL_ACK;
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	/* acknowledge that we have the commands */
10590Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag);
10620Sstevel@tonic-gate 	if (!done_flag) {
10630Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10640Sstevel@tonic-gate 		return (1);
10650Sstevel@tonic-gate 	}
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
10680Sstevel@tonic-gate 	return (ac->ac_status != AMR_STATUS_SUCCESS);
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate /*
10720Sstevel@tonic-gate  * setup the scatter/gather table
10730Sstevel@tonic-gate  */
10740Sstevel@tonic-gate static int
10750Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs)
10760Sstevel@tonic-gate {
10770Sstevel@tonic-gate 	uint32_t		i;
10780Sstevel@tonic-gate 	size_t			len;
10790Sstevel@tonic-gate 	ddi_dma_cookie_t	cookie;
10800Sstevel@tonic-gate 	uint_t			cookien;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	softs->sg_max_count = 0;
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	for (i = 0; i < AMR_MAXCMD; i++) {
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 		/* reset the cookien */
10870Sstevel@tonic-gate 		cookien = 0;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
10900Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(
10910Sstevel@tonic-gate 			softs->dev_info_p,
10920Sstevel@tonic-gate 			&addr_dma_attr,
10930Sstevel@tonic-gate 			DDI_DMA_SLEEP,
10940Sstevel@tonic-gate 			NULL,
10950Sstevel@tonic-gate 			&((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) {
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
10980Sstevel@tonic-gate 			"Cannot alloc dma handle for s/g table"));
10990Sstevel@tonic-gate 			goto error_out;
11000Sstevel@tonic-gate 		}
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 		if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle,
11030Sstevel@tonic-gate 			sizeof (struct amr_sgentry) * AMR_NSEG,
11040Sstevel@tonic-gate 			&accattr,
11050Sstevel@tonic-gate 			DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
11060Sstevel@tonic-gate 			DDI_DMA_SLEEP, NULL,
11070Sstevel@tonic-gate 			(caddr_t *)(&(softs->sg_items[i]).sg_table),
11080Sstevel@tonic-gate 			&len,
11090Sstevel@tonic-gate 			&(softs->sg_items[i]).sg_acc_handle)
11100Sstevel@tonic-gate 			!= DDI_SUCCESS) {
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11130Sstevel@tonic-gate 			"Cannot allocate DMA memory"));
11140Sstevel@tonic-gate 			goto error_out;
11150Sstevel@tonic-gate 		}
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(
11180Sstevel@tonic-gate 			(softs->sg_items[i]).sg_handle,
11190Sstevel@tonic-gate 			NULL,
11200Sstevel@tonic-gate 			(caddr_t)((softs->sg_items[i]).sg_table),
11213495Syw161884 			len,
11220Sstevel@tonic-gate 			DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
11230Sstevel@tonic-gate 			DDI_DMA_SLEEP,
11240Sstevel@tonic-gate 			NULL,
11250Sstevel@tonic-gate 			&cookie,
11260Sstevel@tonic-gate 			&cookien) != DDI_DMA_MAPPED) {
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11290Sstevel@tonic-gate 			"Cannot bind communication area for s/g table"));
11300Sstevel@tonic-gate 			goto error_out;
11310Sstevel@tonic-gate 		}
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 		if (cookien != 1)
11340Sstevel@tonic-gate 			goto error_out;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 		softs->sg_items[i].sg_phyaddr = cookie.dmac_address;
11370Sstevel@tonic-gate 		softs->sg_max_count++;
11380Sstevel@tonic-gate 	}
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 	return (DDI_SUCCESS);
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate error_out:
11430Sstevel@tonic-gate 	/*
11440Sstevel@tonic-gate 	 * Couldn't allocate/initialize all of the sg table entries.
11450Sstevel@tonic-gate 	 * Clean up the partially-initialized entry before returning.
11460Sstevel@tonic-gate 	 */
11470Sstevel@tonic-gate 	if (cookien) {
11480Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle);
11490Sstevel@tonic-gate 	}
11500Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_acc_handle) {
11510Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle));
11520Sstevel@tonic-gate 		(softs->sg_items[i]).sg_acc_handle = NULL;
11530Sstevel@tonic-gate 	}
11540Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_handle) {
11550Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle));
11560Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
11570Sstevel@tonic-gate 	}
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	/*
11600Sstevel@tonic-gate 	 * At least two sg table entries are needed. One is for regular data
11610Sstevel@tonic-gate 	 * I/O commands, the other is for poll I/O commands.
11620Sstevel@tonic-gate 	 */
11630Sstevel@tonic-gate 	return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE);
11640Sstevel@tonic-gate }
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate /*
11670Sstevel@tonic-gate  * Map/unmap (ac)'s data in the controller's addressable space as required.
11680Sstevel@tonic-gate  *
11690Sstevel@tonic-gate  * These functions may be safely called multiple times on a given command.
11700Sstevel@tonic-gate  */
11710Sstevel@tonic-gate static void
11720Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep,
11730Sstevel@tonic-gate 		int nsegments)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate 	struct amr_sgentry	*sg;
11760Sstevel@tonic-gate 	uint32_t		i, size;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	sg = ac->sgtable;
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 	size = 0;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = (uint8_t)nsegments;
11830Sstevel@tonic-gate 	for (i = 0; i < nsegments; i++, sg++) {
11840Sstevel@tonic-gate 		sg->sg_addr = buffer_dma_cookiep->dmac_address;
11850Sstevel@tonic-gate 		sg->sg_count = buffer_dma_cookiep->dmac_size;
11860Sstevel@tonic-gate 		size += sg->sg_count;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 		/*
11890Sstevel@tonic-gate 		 * There is no next cookie if the end of the current
11900Sstevel@tonic-gate 		 * window is reached. Otherwise, the next cookie
11910Sstevel@tonic-gate 		 * would be found.
11920Sstevel@tonic-gate 		 */
11930Sstevel@tonic-gate 		if ((ac->current_cookie + i + 1) != ac->num_of_cookie)
11940Sstevel@tonic-gate 			ddi_dma_nextcookie(ac->buffer_dma_handle,
11950Sstevel@tonic-gate 				buffer_dma_cookiep);
11960Sstevel@tonic-gate 	}
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	ac->transfer_size = size;
11990Sstevel@tonic-gate 	ac->data_transfered += size;
12000Sstevel@tonic-gate }
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate  * map the amr command for enquiry, allocate the DMA resource
12050Sstevel@tonic-gate  */
12060Sstevel@tonic-gate static int
12070Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size)
12080Sstevel@tonic-gate {
12090Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
12100Sstevel@tonic-gate 	size_t			len;
12110Sstevel@tonic-gate 	uint_t			dma_flags;
12120Sstevel@tonic-gate 
12130Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x",
12140Sstevel@tonic-gate 			(void *)ac, ac->ac_flags));
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
12170Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
12180Sstevel@tonic-gate 	} else {
12190Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	dma_flags |= DDI_DMA_CONSISTENT;
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	/* process the DMA by address bind mode */
12250Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(softs->dev_info_p,
12260Sstevel@tonic-gate 		&addr_dma_attr, DDI_DMA_SLEEP, NULL,
12270Sstevel@tonic-gate 		&ac->buffer_dma_handle) !=
12280Sstevel@tonic-gate 		DDI_SUCCESS) {
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12310Sstevel@tonic-gate 		"Cannot allocate addr DMA tag"));
12320Sstevel@tonic-gate 		goto error_out;
12330Sstevel@tonic-gate 	}
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ac->buffer_dma_handle,
12360Sstevel@tonic-gate 		data_size,
12370Sstevel@tonic-gate 		&accattr,
12380Sstevel@tonic-gate 		dma_flags,
12390Sstevel@tonic-gate 		DDI_DMA_SLEEP,
12400Sstevel@tonic-gate 		NULL,
12410Sstevel@tonic-gate 		(caddr_t *)&ac->ac_data,
12420Sstevel@tonic-gate 		&len,
12430Sstevel@tonic-gate 		&ac->buffer_acc_handle) !=
12440Sstevel@tonic-gate 		DDI_SUCCESS) {
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12470Sstevel@tonic-gate 		"Cannot allocate DMA memory"));
12480Sstevel@tonic-gate 		goto error_out;
12490Sstevel@tonic-gate 	}
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 	if ((ddi_dma_addr_bind_handle(
12520Sstevel@tonic-gate 		ac->buffer_dma_handle,
12533495Syw161884 		NULL, ac->ac_data, len, dma_flags,
12540Sstevel@tonic-gate 		DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie,
12550Sstevel@tonic-gate 		&ac->num_of_cookie)) != DDI_DMA_MAPPED) {
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12580Sstevel@tonic-gate 			"Cannot bind addr for dma"));
12590Sstevel@tonic-gate 		goto error_out;
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 	ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address;
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0;
12650Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = 0;
12660Sstevel@tonic-gate 	ac->mailbox.mb_physaddr = ac->ac_dataphys;
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	ac->ac_flags |= AMR_CMD_MAPPED;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	return (DDI_SUCCESS);
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate error_out:
12730Sstevel@tonic-gate 	if (ac->num_of_cookie)
12740Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
12750Sstevel@tonic-gate 	if (ac->buffer_acc_handle) {
12760Sstevel@tonic-gate 		ddi_dma_mem_free(&ac->buffer_acc_handle);
12770Sstevel@tonic-gate 		ac->buffer_acc_handle = NULL;
12780Sstevel@tonic-gate 	}
12790Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
12800Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
12810Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
12820Sstevel@tonic-gate 	}
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	return (DDI_FAILURE);
12850Sstevel@tonic-gate }
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate /*
12880Sstevel@tonic-gate  * unmap the amr command for enquiry, free the DMA resource
12890Sstevel@tonic-gate  */
12900Sstevel@tonic-gate static void
12910Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac)
12920Sstevel@tonic-gate {
12930Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p",
12940Sstevel@tonic-gate 			(void *)ac));
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
12970Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) {
12980Sstevel@tonic-gate 		if (ac->buffer_dma_handle)
12990Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
13000Sstevel@tonic-gate 				ac->buffer_dma_handle);
13010Sstevel@tonic-gate 		if (ac->buffer_acc_handle) {
13020Sstevel@tonic-gate 			ddi_dma_mem_free(&ac->buffer_acc_handle);
13030Sstevel@tonic-gate 			ac->buffer_acc_handle = NULL;
13040Sstevel@tonic-gate 		}
13050Sstevel@tonic-gate 		if (ac->buffer_dma_handle) {
13060Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
13070Sstevel@tonic-gate 				&ac->buffer_dma_handle);
13080Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13090Sstevel@tonic-gate 		}
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
13130Sstevel@tonic-gate }
13140Sstevel@tonic-gate 
13150Sstevel@tonic-gate /*
13160Sstevel@tonic-gate  * map the amr command, allocate the DMA resource
13170Sstevel@tonic-gate  */
13180Sstevel@tonic-gate static int
13193495Syw161884 amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg)
13200Sstevel@tonic-gate {
13210Sstevel@tonic-gate 	uint_t	dma_flags;
13220Sstevel@tonic-gate 	off_t	off;
13230Sstevel@tonic-gate 	size_t	len;
13240Sstevel@tonic-gate 	int	error;
13253495Syw161884 	int	(*cb)(caddr_t);
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x",
13280Sstevel@tonic-gate 			(void *)ac, ac->ac_flags));
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
13310Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
13320Sstevel@tonic-gate 	} else {
13330Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
13340Sstevel@tonic-gate 	}
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) {
13370Sstevel@tonic-gate 		dma_flags |= DDI_DMA_CONSISTENT;
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) {
13400Sstevel@tonic-gate 		dma_flags |= DDI_DMA_PARTIAL;
13410Sstevel@tonic-gate 	}
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) {
13440Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
13450Sstevel@tonic-gate 		return (DDI_SUCCESS);
13460Sstevel@tonic-gate 	}
13470Sstevel@tonic-gate 
13483495Syw161884 	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
13493495Syw161884 
13500Sstevel@tonic-gate 	/* if the command involves data at all, and hasn't been mapped */
13510Sstevel@tonic-gate 	if (!(ac->ac_flags & AMR_CMD_MAPPED)) {
13520Sstevel@tonic-gate 		/* process the DMA by buffer bind mode */
13530Sstevel@tonic-gate 		error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle,
13540Sstevel@tonic-gate 			ac->ac_buf,
13550Sstevel@tonic-gate 			dma_flags,
13563495Syw161884 			cb,
13573495Syw161884 			arg,
13580Sstevel@tonic-gate 			&ac->buffer_dma_cookie,
13590Sstevel@tonic-gate 			&ac->num_of_cookie);
13600Sstevel@tonic-gate 		switch (error) {
13610Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
13620Sstevel@tonic-gate 			if (ddi_dma_numwin(ac->buffer_dma_handle,
13630Sstevel@tonic-gate 				&ac->num_of_win) == DDI_FAILURE) {
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
13660Sstevel@tonic-gate 					"Cannot get dma num win"));
13670Sstevel@tonic-gate 				(void) ddi_dma_unbind_handle(
13680Sstevel@tonic-gate 					ac->buffer_dma_handle);
13690Sstevel@tonic-gate 				(void) ddi_dma_free_handle(
13700Sstevel@tonic-gate 					&ac->buffer_dma_handle);
13710Sstevel@tonic-gate 				ac->buffer_dma_handle = NULL;
13720Sstevel@tonic-gate 				return (DDI_FAILURE);
13730Sstevel@tonic-gate 			}
13740Sstevel@tonic-gate 			ac->current_win = 0;
13750Sstevel@tonic-gate 			break;
13760Sstevel@tonic-gate 
13770Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
13780Sstevel@tonic-gate 			ac->num_of_win = 1;
13790Sstevel@tonic-gate 			ac->current_win = 0;
13800Sstevel@tonic-gate 			break;
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 		default:
13830Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
13840Sstevel@tonic-gate 				"Cannot bind buf for dma"));
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
13870Sstevel@tonic-gate 				&ac->buffer_dma_handle);
13880Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13890Sstevel@tonic-gate 			return (DDI_FAILURE);
13900Sstevel@tonic-gate 		}
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 		ac->current_cookie = 0;
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
13950Sstevel@tonic-gate 	} else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) {
13960Sstevel@tonic-gate 		/* get the next window */
13970Sstevel@tonic-gate 		ac->current_win++;
13980Sstevel@tonic-gate 		(void) ddi_dma_getwin(ac->buffer_dma_handle,
13990Sstevel@tonic-gate 			ac->current_win, &off, &len,
14000Sstevel@tonic-gate 			&ac->buffer_dma_cookie,
14010Sstevel@tonic-gate 			&ac->num_of_cookie);
14020Sstevel@tonic-gate 		ac->current_cookie = 0;
14030Sstevel@tonic-gate 	}
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 	if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) {
14060Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG);
14070Sstevel@tonic-gate 		ac->current_cookie += AMR_NSEG;
14080Sstevel@tonic-gate 	} else {
14090Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie,
14100Sstevel@tonic-gate 		ac->num_of_cookie - ac->current_cookie);
14110Sstevel@tonic-gate 		ac->current_cookie = AMR_LAST_COOKIE_TAG;
14120Sstevel@tonic-gate 	}
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	return (DDI_SUCCESS);
14150Sstevel@tonic-gate }
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate  * unmap the amr command, free the DMA resource
14190Sstevel@tonic-gate  */
14200Sstevel@tonic-gate static void
14210Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac)
14220Sstevel@tonic-gate {
14230Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p",
14240Sstevel@tonic-gate 			(void *)ac));
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
14270Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) &&
14280Sstevel@tonic-gate 		ac->ac_buf && ac->buffer_dma_handle)
14290Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
14320Sstevel@tonic-gate }
14330Sstevel@tonic-gate 
14340Sstevel@tonic-gate static int
14350Sstevel@tonic-gate amr_setup_tran(dev_info_t  *dip, struct amr_softs *softp)
14360Sstevel@tonic-gate {
14370Sstevel@tonic-gate 	softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	/*
14400Sstevel@tonic-gate 	 * hba_private always points to the amr_softs struct
14410Sstevel@tonic-gate 	 */
14420Sstevel@tonic-gate 	softp->hba_tran->tran_hba_private	= softp;
14430Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_init		= amr_tran_tgt_init;
14440Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_probe		= scsi_hba_probe;
14450Sstevel@tonic-gate 	softp->hba_tran->tran_start		= amr_tran_start;
14460Sstevel@tonic-gate 	softp->hba_tran->tran_reset		= amr_tran_reset;
14470Sstevel@tonic-gate 	softp->hba_tran->tran_getcap		= amr_tran_getcap;
14480Sstevel@tonic-gate 	softp->hba_tran->tran_setcap		= amr_tran_setcap;
14490Sstevel@tonic-gate 	softp->hba_tran->tran_init_pkt		= amr_tran_init_pkt;
14500Sstevel@tonic-gate 	softp->hba_tran->tran_destroy_pkt	= amr_tran_destroy_pkt;
14510Sstevel@tonic-gate 	softp->hba_tran->tran_dmafree		= amr_tran_dmafree;
14520Sstevel@tonic-gate 	softp->hba_tran->tran_sync_pkt		= amr_tran_sync_pkt;
14530Sstevel@tonic-gate 	softp->hba_tran->tran_abort		= NULL;
14540Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_free		= NULL;
14550Sstevel@tonic-gate 	softp->hba_tran->tran_quiesce		= NULL;
14560Sstevel@tonic-gate 	softp->hba_tran->tran_unquiesce		= NULL;
14570Sstevel@tonic-gate 	softp->hba_tran->tran_sd		= NULL;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran,
14600Sstevel@tonic-gate 		SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
14610Sstevel@tonic-gate 		scsi_hba_tran_free(softp->hba_tran);
14620Sstevel@tonic-gate 		softp->hba_tran = NULL;
14630Sstevel@tonic-gate 		return (DDI_FAILURE);
14640Sstevel@tonic-gate 	} else {
14650Sstevel@tonic-gate 		return (DDI_SUCCESS);
14660Sstevel@tonic-gate 	}
14670Sstevel@tonic-gate }
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate /*ARGSUSED*/
14700Sstevel@tonic-gate static int
14710Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
14720Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	struct amr_softs	*softs;
14750Sstevel@tonic-gate 	ushort_t		target = sd->sd_address.a_target;
14760Sstevel@tonic-gate 	uchar_t			lun = sd->sd_address.a_lun;
14770Sstevel@tonic-gate 
14780Sstevel@tonic-gate 	softs = (struct amr_softs *)
14790Sstevel@tonic-gate 		(sd->sd_address.a_hba_tran->tran_hba_private);
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 	if ((lun == 0) && (target < AMR_MAXLD))
14820Sstevel@tonic-gate 		if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE)
14830Sstevel@tonic-gate 			return (DDI_SUCCESS);
14840Sstevel@tonic-gate 
14850Sstevel@tonic-gate 	return (DDI_FAILURE);
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate static int
14890Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
14900Sstevel@tonic-gate {
14910Sstevel@tonic-gate 	struct amr_softs	*softs;
14920Sstevel@tonic-gate 	struct buf		*bp = NULL;
14930Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
14940Sstevel@tonic-gate 	int			ret;
14950Sstevel@tonic-gate 	uint32_t		capacity;
14960Sstevel@tonic-gate 	struct amr_command	*ac;
14970Sstevel@tonic-gate 
14980Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d",
14990Sstevel@tonic-gate 		cdbp->scc_cmd, ap->a_target, ap->a_lun));
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
15020Sstevel@tonic-gate 	if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) ||
15030Sstevel@tonic-gate 		(softs->logic_drive[ap->a_target].al_state ==
15040Sstevel@tonic-gate 			AMR_LDRV_OFFLINE)) {
15050Sstevel@tonic-gate 		cmn_err(CE_WARN, "target or lun is not correct!");
15060Sstevel@tonic-gate 		ret = TRAN_BADPKT;
15070Sstevel@tonic-gate 		return (ret);
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	ac = (struct amr_command *)pkt->pkt_ha_private;
15110Sstevel@tonic-gate 	bp = ac->ac_buf;
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd));
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	switch (cdbp->scc_cmd) {
15160Sstevel@tonic-gate 	case SCMD_READ:		/* read		*/
15170Sstevel@tonic-gate 	case SCMD_READ_G1:	/* read	g1	*/
15180Sstevel@tonic-gate 	case SCMD_READ_BUFFER:	/* read buffer	*/
15190Sstevel@tonic-gate 	case SCMD_WRITE:	/* write	*/
15200Sstevel@tonic-gate 	case SCMD_WRITE_G1:	/* write g1	*/
15210Sstevel@tonic-gate 	case SCMD_WRITE_BUFFER:	/* write buffer	*/
15220Sstevel@tonic-gate 		amr_rw_command(softs, pkt, ap->a_target);
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 		if (pkt->pkt_flags & FLAG_NOINTR) {
15250Sstevel@tonic-gate 			(void) amr_poll_command(ac);
15260Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
15270Sstevel@tonic-gate 					| STATE_GOT_TARGET
15280Sstevel@tonic-gate 					| STATE_SENT_CMD
15290Sstevel@tonic-gate 					| STATE_XFERRED_DATA);
15300Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
15310Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_SYNC;
15320Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
15330Sstevel@tonic-gate 		} else {
15340Sstevel@tonic-gate 			mutex_enter(&softs->queue_mutex);
15350Sstevel@tonic-gate 			if (softs->waiting_q_head == NULL) {
15360Sstevel@tonic-gate 				ac->ac_prev = NULL;
15370Sstevel@tonic-gate 				ac->ac_next = NULL;
15380Sstevel@tonic-gate 				softs->waiting_q_head = ac;
15390Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15400Sstevel@tonic-gate 			} else {
15410Sstevel@tonic-gate 				ac->ac_next = NULL;
15420Sstevel@tonic-gate 				ac->ac_prev = softs->waiting_q_tail;
15430Sstevel@tonic-gate 				softs->waiting_q_tail->ac_next = ac;
15440Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15450Sstevel@tonic-gate 			}
15460Sstevel@tonic-gate 			mutex_exit(&softs->queue_mutex);
15470Sstevel@tonic-gate 			amr_start_waiting_queue((void *)softs);
15480Sstevel@tonic-gate 		}
15490Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
15500Sstevel@tonic-gate 		break;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 	case SCMD_INQUIRY: /* inquiry */
15530Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
15540Sstevel@tonic-gate 			struct scsi_inquiry inqp;
15550Sstevel@tonic-gate 			uint8_t *sinq_p = (uint8_t *)&inqp;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 			bzero(&inqp, sizeof (struct scsi_inquiry));
15580Sstevel@tonic-gate 
15590Sstevel@tonic-gate 			if (((char *)cdbp)[1] || ((char *)cdbp)[2]) {
15600Sstevel@tonic-gate 				/*
15610Sstevel@tonic-gate 				 * The EVDP and pagecode is
15620Sstevel@tonic-gate 				 * not supported
15630Sstevel@tonic-gate 				 */
15640Sstevel@tonic-gate 				sinq_p[1] = 0xFF;
15650Sstevel@tonic-gate 				sinq_p[2] = 0x0;
15660Sstevel@tonic-gate 			} else {
15670Sstevel@tonic-gate 				inqp.inq_len = AMR_INQ_ADDITIONAL_LEN;
15680Sstevel@tonic-gate 				inqp.inq_ansi = AMR_INQ_ANSI_VER;
15690Sstevel@tonic-gate 				inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT;
15703495Syw161884 				/* Enable Tag Queue */
15713495Syw161884 				inqp.inq_cmdque = 1;
15720Sstevel@tonic-gate 				bcopy("MegaRaid", inqp.inq_vid,
15730Sstevel@tonic-gate 					sizeof (inqp.inq_vid));
15740Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_product_name,
15750Sstevel@tonic-gate 					inqp.inq_pid,
15760Sstevel@tonic-gate 					AMR_PRODUCT_INFO_SIZE);
15770Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_firmware_ver,
15780Sstevel@tonic-gate 					inqp.inq_revision,
15790Sstevel@tonic-gate 					AMR_FIRMWARE_VER_SIZE);
15800Sstevel@tonic-gate 			}
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 			amr_unmapcmd(ac);
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
15850Sstevel@tonic-gate 				bp_mapin(bp);
15860Sstevel@tonic-gate 			bcopy(&inqp, bp->b_un.b_addr,
15870Sstevel@tonic-gate 				sizeof (struct scsi_inquiry));
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
15900Sstevel@tonic-gate 		}
15910Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
15920Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
15930Sstevel@tonic-gate 				| STATE_GOT_TARGET
15940Sstevel@tonic-gate 				| STATE_SENT_CMD);
15950Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
15960Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
15970Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
15980Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
15990Sstevel@tonic-gate 		break;
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate 	case SCMD_READ_CAPACITY: /* read capacity */
16020Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16030Sstevel@tonic-gate 			struct scsi_capacity cp;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 			capacity = softs->logic_drive[ap->a_target].al_size - 1;
16060Sstevel@tonic-gate 			cp.capacity = BE_32(capacity);
16070Sstevel@tonic-gate 			cp.lbasize = BE_32(512);
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 			amr_unmapcmd(ac);
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16120Sstevel@tonic-gate 				bp_mapin(bp);
16130Sstevel@tonic-gate 			bcopy(&cp, bp->b_un.b_addr, 8);
16140Sstevel@tonic-gate 		}
16150Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16160Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16170Sstevel@tonic-gate 				| STATE_GOT_TARGET
16180Sstevel@tonic-gate 				| STATE_SENT_CMD
16190Sstevel@tonic-gate 				| STATE_XFERRED_DATA);
16200Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16210Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16220Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16230Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16240Sstevel@tonic-gate 		break;
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	case SCMD_MODE_SENSE:		/* mode sense */
16270Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:	/* mode sense g1 */
16280Sstevel@tonic-gate 		amr_unmapcmd(ac);
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 		capacity = softs->logic_drive[ap->a_target].al_size - 1;
16310Sstevel@tonic-gate 		amr_mode_sense(cdbp, bp, capacity);
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16340Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16350Sstevel@tonic-gate 				| STATE_GOT_TARGET
16360Sstevel@tonic-gate 				| STATE_SENT_CMD
16370Sstevel@tonic-gate 				| STATE_XFERRED_DATA);
16380Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16390Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16400Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16410Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16420Sstevel@tonic-gate 		break;
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:	/* test unit ready */
16450Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:	/* request sense */
16460Sstevel@tonic-gate 	case SCMD_FORMAT:		/* format */
16470Sstevel@tonic-gate 	case SCMD_START_STOP:		/* start stop */
16480Sstevel@tonic-gate 	case SCMD_SYNCHRONIZE_CACHE:	/* synchronize cache */
16490Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16500Sstevel@tonic-gate 			amr_unmapcmd(ac);
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16530Sstevel@tonic-gate 				bp_mapin(bp);
16540Sstevel@tonic-gate 			bzero(bp->b_un.b_addr, bp->b_bcount);
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
16570Sstevel@tonic-gate 		}
16580Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16590Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16600Sstevel@tonic-gate 				| STATE_GOT_TARGET
16610Sstevel@tonic-gate 				| STATE_SENT_CMD);
16620Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16630Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16640Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16650Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16660Sstevel@tonic-gate 		break;
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	default: /* any other commands */
16690Sstevel@tonic-gate 		amr_unmapcmd(ac);
16700Sstevel@tonic-gate 		pkt->pkt_reason = CMD_INCOMPLETE;
16710Sstevel@tonic-gate 		pkt->pkt_state = (STATE_GOT_BUS
16720Sstevel@tonic-gate 				| STATE_GOT_TARGET
16730Sstevel@tonic-gate 				| STATE_SENT_CMD
16740Sstevel@tonic-gate 				| STATE_GOT_STATUS
16750Sstevel@tonic-gate 				| STATE_ARQ_DONE);
16760Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16770Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16780Sstevel@tonic-gate 		amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
16790Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16800Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16810Sstevel@tonic-gate 		break;
16820Sstevel@tonic-gate 	}
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 	return (ret);
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate /*
16880Sstevel@tonic-gate  * tran_reset() will reset the bus/target/adapter to support the fault recovery
16890Sstevel@tonic-gate  * functionality according to the "level" in interface. However, we got the
16900Sstevel@tonic-gate  * confirmation from LSI that these HBA cards does not support any commands to
16910Sstevel@tonic-gate  * reset bus/target/adapter/channel.
16920Sstevel@tonic-gate  *
16930Sstevel@tonic-gate  * If the tran_reset() return a FAILURE to the sd, the system will not
16940Sstevel@tonic-gate  * continue to dump the core. But core dump is an crucial method to analyze
16950Sstevel@tonic-gate  * problems in panic. Now we adopt a work around solution, that is to return
16960Sstevel@tonic-gate  * a fake SUCCESS to sd during panic, which will force the system continue
16970Sstevel@tonic-gate  * to dump core though the core may have problems in some situtation because
16980Sstevel@tonic-gate  * some on-the-fly commands will continue DMAing data to the memory.
16990Sstevel@tonic-gate  * In addition, the work around core dump method may not be performed
17000Sstevel@tonic-gate  * successfully if the panic is caused by the HBA itself. So the work around
17010Sstevel@tonic-gate  * solution is not a good example for the implementation of tran_reset(),
17020Sstevel@tonic-gate  * the most reasonable approach should send a reset command to the adapter.
17030Sstevel@tonic-gate  */
17040Sstevel@tonic-gate /*ARGSUSED*/
17050Sstevel@tonic-gate static int
17060Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level)
17070Sstevel@tonic-gate {
17080Sstevel@tonic-gate 	struct amr_softs	*softs;
17090Sstevel@tonic-gate 	volatile uint32_t	done_flag;
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 	if (ddi_in_panic()) {
17120Sstevel@tonic-gate 		softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 		/* Acknowledge the card if there are any significant commands */
17150Sstevel@tonic-gate 		while (softs->amr_busyslots > 0) {
17160Sstevel@tonic-gate 			AMR_DELAY((softs->mailbox->mb_busy == 0),
17170Sstevel@tonic-gate 					AMR_RETRYCOUNT, done_flag);
17180Sstevel@tonic-gate 			if (!done_flag) {
17190Sstevel@tonic-gate 				/*
17200Sstevel@tonic-gate 				 * command not completed, indicate the
17210Sstevel@tonic-gate 				 * problem and continue get ac
17220Sstevel@tonic-gate 				 */
17230Sstevel@tonic-gate 				cmn_err(CE_WARN,
17240Sstevel@tonic-gate 					"AMR command is not completed");
17250Sstevel@tonic-gate 				return (0);
17260Sstevel@tonic-gate 			}
17270Sstevel@tonic-gate 
17280Sstevel@tonic-gate 			AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 			/* wait for the acknowledge from hardware */
17310Sstevel@tonic-gate 			AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
17320Sstevel@tonic-gate 					AMR_RETRYCOUNT, done_flag);
17330Sstevel@tonic-gate 			if (!done_flag) {
17340Sstevel@tonic-gate 				/*
17350Sstevel@tonic-gate 				 * command is not completed, return from the
17360Sstevel@tonic-gate 				 * current interrupt and wait for the next one
17370Sstevel@tonic-gate 				 */
17380Sstevel@tonic-gate 				cmn_err(CE_WARN, "No answer from the hardware");
17390Sstevel@tonic-gate 
17400Sstevel@tonic-gate 				mutex_exit(&softs->cmd_mutex);
17410Sstevel@tonic-gate 				return (0);
17420Sstevel@tonic-gate 			}
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 			softs->amr_busyslots -= softs->mailbox->mb_nstatus;
17450Sstevel@tonic-gate 		}
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 		/* flush the controllor */
17480Sstevel@tonic-gate 		(void) amr_flush(softs);
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 		/*
17510Sstevel@tonic-gate 		 * If the system is in panic, the tran_reset() will return a
17520Sstevel@tonic-gate 		 * fake SUCCESS to sd, then the system would continue dump the
17530Sstevel@tonic-gate 		 * core by poll commands. This is a work around for dumping
17540Sstevel@tonic-gate 		 * core in panic.
17550Sstevel@tonic-gate 		 *
17560Sstevel@tonic-gate 		 * Note: Some on-the-fly command will continue DMAing data to
17570Sstevel@tonic-gate 		 *	 the memory when the core is dumping, which may cause
17580Sstevel@tonic-gate 		 *	 some flaws in the dumped core file, so a cmn_err()
17590Sstevel@tonic-gate 		 *	 will be printed out to warn users. However, for most
17600Sstevel@tonic-gate 		 *	 cases, the core file will be fine.
17610Sstevel@tonic-gate 		 */
17620Sstevel@tonic-gate 		cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver "
17630Sstevel@tonic-gate 				"that doesn't support software reset. This "
17640Sstevel@tonic-gate 				"means that memory being used by the HBA for "
17650Sstevel@tonic-gate 				"DMA based reads could have been updated after "
17660Sstevel@tonic-gate 				"we panic'd.");
17670Sstevel@tonic-gate 		return (1);
17680Sstevel@tonic-gate 	} else {
17690Sstevel@tonic-gate 		/* return failure to sd */
17700Sstevel@tonic-gate 		return (0);
17710Sstevel@tonic-gate 	}
17720Sstevel@tonic-gate }
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate /*ARGSUSED*/
17750Sstevel@tonic-gate static int
17760Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom)
17770Sstevel@tonic-gate {
17780Sstevel@tonic-gate 	struct amr_softs	*softs;
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	/*
17810Sstevel@tonic-gate 	 * We don't allow inquiring about capabilities for other targets
17820Sstevel@tonic-gate 	 */
17830Sstevel@tonic-gate 	if (cap == NULL || whom == 0)
17840Sstevel@tonic-gate 		return (-1);
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private);
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
17890Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
17900Sstevel@tonic-gate 		return (1);
17910Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
17920Sstevel@tonic-gate 		return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS);
17930Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
17940Sstevel@tonic-gate 		return (AMR_DEFAULT_SECTORS);
17950Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
17960Sstevel@tonic-gate 		/* number of sectors */
17970Sstevel@tonic-gate 		return (softs->logic_drive[ap->a_target].al_size);
17983495Syw161884 	case SCSI_CAP_UNTAGGED_QING:
17993495Syw161884 	case SCSI_CAP_TAGGED_QING:
18003495Syw161884 		return (1);
18010Sstevel@tonic-gate 	default:
18020Sstevel@tonic-gate 		return (-1);
18030Sstevel@tonic-gate 	}
18040Sstevel@tonic-gate }
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate /*ARGSUSED*/
18070Sstevel@tonic-gate static int
18080Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value,
18090Sstevel@tonic-gate 		int whom)
18100Sstevel@tonic-gate {
18110Sstevel@tonic-gate 	/*
18120Sstevel@tonic-gate 	 * We don't allow setting capabilities for other targets
18130Sstevel@tonic-gate 	 */
18140Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
18150Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,
18160Sstevel@tonic-gate 			"Set Cap not supported, string = %s, whom=%d",
18170Sstevel@tonic-gate 			cap, whom));
18180Sstevel@tonic-gate 		return (-1);
18190Sstevel@tonic-gate 	}
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
18220Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
18230Sstevel@tonic-gate 		return (1);
18240Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18250Sstevel@tonic-gate 		return (1);
18260Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
18270Sstevel@tonic-gate 		return (1);
18283495Syw161884 	case SCSI_CAP_UNTAGGED_QING:
18293495Syw161884 	case SCSI_CAP_TAGGED_QING:
18303495Syw161884 		return ((value == 1) ? 1 : 0);
18310Sstevel@tonic-gate 	default:
18320Sstevel@tonic-gate 		return (0);
18330Sstevel@tonic-gate 	}
18340Sstevel@tonic-gate }
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate static struct scsi_pkt *
18370Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap,
18380Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
18390Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
18400Sstevel@tonic-gate {
18410Sstevel@tonic-gate 	struct amr_softs	*softs;
18420Sstevel@tonic-gate 	struct amr_command	*ac;
18430Sstevel@tonic-gate 	uint32_t		slen;
18440Sstevel@tonic-gate 
18450Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)||
18480Sstevel@tonic-gate 		(softs->logic_drive[ap->a_target].al_state ==
18490Sstevel@tonic-gate 			AMR_LDRV_OFFLINE)) {
18500Sstevel@tonic-gate 		return (NULL);
18510Sstevel@tonic-gate 	}
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	if (pkt == NULL) {
18540Sstevel@tonic-gate 		/* force auto request sense */
18550Sstevel@tonic-gate 		slen = MAX(statuslen, sizeof (struct scsi_arq_status));
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen,
18580Sstevel@tonic-gate 			slen, tgtlen, sizeof (struct amr_command),
18590Sstevel@tonic-gate 			callback, arg);
18600Sstevel@tonic-gate 		if (pkt == NULL) {
18610Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed"));
18620Sstevel@tonic-gate 			return (NULL);
18630Sstevel@tonic-gate 		}
18640Sstevel@tonic-gate 		pkt->pkt_address	= *ap;
18650Sstevel@tonic-gate 		pkt->pkt_comp		= (void (*)())NULL;
18660Sstevel@tonic-gate 		pkt->pkt_time		= 0;
18670Sstevel@tonic-gate 		pkt->pkt_resid		= 0;
18680Sstevel@tonic-gate 		pkt->pkt_statistics	= 0;
18690Sstevel@tonic-gate 		pkt->pkt_reason		= 0;
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
18720Sstevel@tonic-gate 		ac->ac_buf = bp;
18730Sstevel@tonic-gate 		ac->cmdlen = cmdlen;
18740Sstevel@tonic-gate 		ac->ac_softs = softs;
18750Sstevel@tonic-gate 		ac->pkt = pkt;
18760Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
18770Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_BUSY;
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
18800Sstevel@tonic-gate 			return (pkt);
18810Sstevel@tonic-gate 		}
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr,
18840Sstevel@tonic-gate 			DDI_DMA_SLEEP, NULL,
18850Sstevel@tonic-gate 			&ac->buffer_dma_handle) != DDI_SUCCESS) {
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
18880Sstevel@tonic-gate 				"Cannot allocate buffer DMA tag"));
18890Sstevel@tonic-gate 			scsi_hba_pkt_free(ap, pkt);
18900Sstevel@tonic-gate 			return (NULL);
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 		}
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	} else {
18950Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
18960Sstevel@tonic-gate 			return (pkt);
18970Sstevel@tonic-gate 		}
18980Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
18990Sstevel@tonic-gate 	}
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	ASSERT(ac != NULL);
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 	if (bp->b_flags & B_READ) {
19040Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAOUT;
19050Sstevel@tonic-gate 	} else {
19060Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAIN;
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	if (flags & PKT_CONSISTENT) {
19100Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_CONSISTENT;
19110Sstevel@tonic-gate 	}
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	if (flags & PKT_DMA_PARTIAL) {
19140Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL;
19150Sstevel@tonic-gate 	}
19160Sstevel@tonic-gate 
19173495Syw161884 	if (amr_mapcmd(ac, callback, arg) != DDI_SUCCESS) {
19180Sstevel@tonic-gate 		scsi_hba_pkt_free(ap, pkt);
19190Sstevel@tonic-gate 		return (NULL);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 	pkt->pkt_resid = bp->b_bcount - ac->data_transfered;
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE,
19250Sstevel@tonic-gate 		"init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d",
19260Sstevel@tonic-gate 		(uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount,
19270Sstevel@tonic-gate 		ac->data_transfered));
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	ASSERT(pkt->pkt_resid >= 0);
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	return (pkt);
19320Sstevel@tonic-gate }
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate static void
19350Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19360Sstevel@tonic-gate {
19370Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	amr_unmapcmd(ac);
19400Sstevel@tonic-gate 
19410Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19420Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19430Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19440Sstevel@tonic-gate 	}
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
19470Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Destroy pkt called"));
19480Sstevel@tonic-gate }
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate /*ARGSUSED*/
19510Sstevel@tonic-gate static void
19520Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19530Sstevel@tonic-gate {
19540Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19570Sstevel@tonic-gate 		(void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0,
19580Sstevel@tonic-gate 			(ac->ac_flags & AMR_CMD_DATAIN) ?
19590Sstevel@tonic-gate 			DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
19600Sstevel@tonic-gate 	}
19610Sstevel@tonic-gate }
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate /*ARGSUSED*/
19640Sstevel@tonic-gate static void
19650Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
19660Sstevel@tonic-gate {
19670Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_MAPPED) {
19700Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
19710Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19720Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19730Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_MAPPED;
19740Sstevel@tonic-gate 	}
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate }
19770Sstevel@tonic-gate 
19780Sstevel@tonic-gate /*ARGSUSED*/
19790Sstevel@tonic-gate static void
19800Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target)
19810Sstevel@tonic-gate {
19820Sstevel@tonic-gate 	struct amr_command	*ac = (struct amr_command *)pkt->pkt_ha_private;
19830Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
19840Sstevel@tonic-gate 	uint8_t			cmd;
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
19870Sstevel@tonic-gate 		cmd = AMR_CMD_LREAD;
19880Sstevel@tonic-gate 	} else {
19890Sstevel@tonic-gate 		cmd = AMR_CMD_LWRITE;
19900Sstevel@tonic-gate 	}
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	ac->mailbox.mb_command = cmd;
19930Sstevel@tonic-gate 	ac->mailbox.mb_blkcount =
19940Sstevel@tonic-gate 		(ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE;
19950Sstevel@tonic-gate 	ac->mailbox.mb_lba = (ac->cmdlen == 10) ?
19960Sstevel@tonic-gate 				GETG1ADDR(cdbp) : GETG0ADDR(cdbp);
19970Sstevel@tonic-gate 	ac->mailbox.mb_drive = (uint8_t)target;
19980Sstevel@tonic-gate }
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate static void
20010Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity)
20020Sstevel@tonic-gate {
20030Sstevel@tonic-gate 	uchar_t			pagecode;
20040Sstevel@tonic-gate 	struct mode_format	*page3p;
20050Sstevel@tonic-gate 	struct mode_geometry	*page4p;
20060Sstevel@tonic-gate 	struct mode_header	*headerp;
20070Sstevel@tonic-gate 	uint32_t		ncyl;
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
20100Sstevel@tonic-gate 		return;
20110Sstevel@tonic-gate 
20120Sstevel@tonic-gate 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
20130Sstevel@tonic-gate 		bp_mapin(bp);
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	pagecode = cdbp->cdb_un.sg.scsi[0];
20160Sstevel@tonic-gate 	switch (pagecode) {
20170Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE3_CODE:
20180Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20190Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 		page3p = (struct mode_format *)((caddr_t)headerp +
20220Sstevel@tonic-gate 			MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20230Sstevel@tonic-gate 		page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE);
20240Sstevel@tonic-gate 		page3p->mode_page.length = BE_8(sizeof (struct mode_format));
20250Sstevel@tonic-gate 		page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS);
20260Sstevel@tonic-gate 		page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS);
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 		return;
20290Sstevel@tonic-gate 
20300Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE4_CODE:
20310Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20320Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 		page4p = (struct mode_geometry *)((caddr_t)headerp +
20350Sstevel@tonic-gate 			MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20360Sstevel@tonic-gate 		page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE);
20370Sstevel@tonic-gate 		page4p->mode_page.length = BE_8(sizeof (struct mode_geometry));
20380Sstevel@tonic-gate 		page4p->heads = BE_8(AMR_DEFAULT_HEADS);
20390Sstevel@tonic-gate 		page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS);
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 		ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS);
20420Sstevel@tonic-gate 		page4p->cyl_lb = BE_8(ncyl & 0xff);
20430Sstevel@tonic-gate 		page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff);
20440Sstevel@tonic-gate 		page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff);
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 		return;
20470Sstevel@tonic-gate 	default:
20480Sstevel@tonic-gate 		bzero(bp->b_un.b_addr, bp->b_bcount);
20490Sstevel@tonic-gate 		return;
20500Sstevel@tonic-gate 	}
20510Sstevel@tonic-gate }
20520Sstevel@tonic-gate 
20530Sstevel@tonic-gate static void
20540Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
20550Sstevel@tonic-gate {
20560Sstevel@tonic-gate 	struct scsi_arq_status *arqstat;
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate 	arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp);
20590Sstevel@tonic-gate 	arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
20600Sstevel@tonic-gate 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
20610Sstevel@tonic-gate 	arqstat->sts_rqpkt_resid = 0;
20620Sstevel@tonic-gate 	arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
20630Sstevel@tonic-gate 				STATE_SENT_CMD | STATE_XFERRED_DATA;
20640Sstevel@tonic-gate 	arqstat->sts_rqpkt_statistics = 0;
20650Sstevel@tonic-gate 	arqstat->sts_sensedata.es_valid = 1;
20660Sstevel@tonic-gate 	arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
20670Sstevel@tonic-gate 	arqstat->sts_sensedata.es_key = key;
20680Sstevel@tonic-gate }
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate static void
20710Sstevel@tonic-gate amr_start_waiting_queue(void *softp)
20720Sstevel@tonic-gate {
20730Sstevel@tonic-gate 	uint32_t		slot;
20740Sstevel@tonic-gate 	struct amr_command	*ac;
20750Sstevel@tonic-gate 	volatile uint32_t	done_flag;
20760Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)softp;
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	/* only one command allowed at the same time */
20790Sstevel@tonic-gate 	mutex_enter(&softs->queue_mutex);
20800Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
20810Sstevel@tonic-gate 
20820Sstevel@tonic-gate 	while ((ac = softs->waiting_q_head) != NULL) {
20830Sstevel@tonic-gate 		/*
20840Sstevel@tonic-gate 		 * Find an available slot, the last slot is
20850Sstevel@tonic-gate 		 * occupied by poll I/O command.
20860Sstevel@tonic-gate 		 */
20870Sstevel@tonic-gate 		for (slot = 0; slot < (softs->sg_max_count - 1); slot++) {
20880Sstevel@tonic-gate 			if (softs->busycmd[slot] == NULL) {
20890Sstevel@tonic-gate 				if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) {
20900Sstevel@tonic-gate 					/*
20910Sstevel@tonic-gate 					 * only one command allowed at the
20920Sstevel@tonic-gate 					 * same time
20930Sstevel@tonic-gate 					 */
20940Sstevel@tonic-gate 					mutex_exit(&softs->cmd_mutex);
20950Sstevel@tonic-gate 					mutex_exit(&softs->queue_mutex);
20960Sstevel@tonic-gate 					return;
20970Sstevel@tonic-gate 				}
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 				ac->ac_timestamp = ddi_get_time();
21000Sstevel@tonic-gate 
21010Sstevel@tonic-gate 				if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) {
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 					softs->busycmd[slot] = ac;
21040Sstevel@tonic-gate 					ac->ac_slot = slot;
21050Sstevel@tonic-gate 					softs->amr_busyslots++;
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 					bcopy(ac->sgtable,
21080Sstevel@tonic-gate 					softs->sg_items[slot].sg_table,
21090Sstevel@tonic-gate 					sizeof (struct amr_sgentry) * AMR_NSEG);
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 					(void) ddi_dma_sync(
21120Sstevel@tonic-gate 					softs->sg_items[slot].sg_handle,
21130Sstevel@tonic-gate 					0, 0, DDI_DMA_SYNC_FORDEV);
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 					ac->mailbox.mb_physaddr =
21160Sstevel@tonic-gate 					softs->sg_items[slot].sg_phyaddr;
21170Sstevel@tonic-gate 				}
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 				/* take the cmd from the queue */
21200Sstevel@tonic-gate 				softs->waiting_q_head = ac->ac_next;
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 				ac->mailbox.mb_ident = ac->ac_slot + 1;
21230Sstevel@tonic-gate 				ac->mailbox.mb_busy = 1;
21240Sstevel@tonic-gate 				ac->ac_next = NULL;
21250Sstevel@tonic-gate 				ac->ac_prev = NULL;
21260Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_GOT_SLOT;
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 				/* clear the poll/ack fields in the mailbox */
21290Sstevel@tonic-gate 				softs->mailbox->mb_poll = 0;
21300Sstevel@tonic-gate 				softs->mailbox->mb_ack = 0;
21310Sstevel@tonic-gate 
21320Sstevel@tonic-gate 				AMR_DELAY((softs->mailbox->mb_busy == 0),
21330Sstevel@tonic-gate 					AMR_RETRYCOUNT, done_flag);
21340Sstevel@tonic-gate 				if (!done_flag) {
21350Sstevel@tonic-gate 					/*
21360Sstevel@tonic-gate 					 * command not completed, indicate the
21370Sstevel@tonic-gate 					 * problem and continue get ac
21380Sstevel@tonic-gate 					 */
21390Sstevel@tonic-gate 					cmn_err(CE_WARN,
21400Sstevel@tonic-gate 						"AMR command is not completed");
21410Sstevel@tonic-gate 					break;
21420Sstevel@tonic-gate 				}
21430Sstevel@tonic-gate 
21440Sstevel@tonic-gate 				bcopy(&ac->mailbox, (void *)softs->mailbox,
21450Sstevel@tonic-gate 					AMR_MBOX_CMDSIZE);
21460Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_BUSY;
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 				(void) ddi_dma_sync(softs->mbox_dma_handle,
21490Sstevel@tonic-gate 					0, 0, DDI_DMA_SYNC_FORDEV);
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 				AMR_QPUT_IDB(softs,
21520Sstevel@tonic-gate 					softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 				/*
21550Sstevel@tonic-gate 				 * current ac is submitted
21560Sstevel@tonic-gate 				 * so quit 'for-loop' to get next ac
21570Sstevel@tonic-gate 				 */
21580Sstevel@tonic-gate 				break;
21590Sstevel@tonic-gate 			}
21600Sstevel@tonic-gate 		}
21610Sstevel@tonic-gate 
21620Sstevel@tonic-gate 		/* no slot, finish our task */
21630Sstevel@tonic-gate 		if (slot == softs->maxio)
21640Sstevel@tonic-gate 			break;
21650Sstevel@tonic-gate 	}
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	/* only one command allowed at the same time */
21680Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
21690Sstevel@tonic-gate 	mutex_exit(&softs->queue_mutex);
21700Sstevel@tonic-gate }
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate static void
21730Sstevel@tonic-gate amr_done(struct amr_softs *softs)
21740Sstevel@tonic-gate {
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	uint32_t		i, idx;
21770Sstevel@tonic-gate 	volatile uint32_t	done_flag;
21780Sstevel@tonic-gate 	struct amr_mailbox	*mbox, mbsave;
21790Sstevel@tonic-gate 	struct amr_command	*ac, *head, *tail;
21800Sstevel@tonic-gate 
21810Sstevel@tonic-gate 	head = tail = NULL;
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 	AMR_QPUT_ODB(softs, AMR_QODB_READY);
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	/* acknowledge interrupt */
21860Sstevel@tonic-gate 	(void) AMR_QGET_ODB(softs);
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	if (softs->mailbox->mb_nstatus != 0) {
21910Sstevel@tonic-gate 		(void) ddi_dma_sync(softs->mbox_dma_handle,
21920Sstevel@tonic-gate 			0, 0, DDI_DMA_SYNC_FORCPU);
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 		/* save mailbox, which contains a list of completed commands */
21950Sstevel@tonic-gate 		bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox,
21960Sstevel@tonic-gate 				&mbsave, sizeof (mbsave));
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 		mbox = &mbsave;
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
22010Sstevel@tonic-gate 
22020Sstevel@tonic-gate 		/* wait for the acknowledge from hardware */
22030Sstevel@tonic-gate 		AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
22040Sstevel@tonic-gate 				AMR_RETRYCOUNT, done_flag);
22050Sstevel@tonic-gate 		if (!done_flag) {
22060Sstevel@tonic-gate 			/*
22070Sstevel@tonic-gate 			 * command is not completed, return from the current
22080Sstevel@tonic-gate 			 * interrupt and wait for the next one
22090Sstevel@tonic-gate 			 */
22100Sstevel@tonic-gate 			cmn_err(CE_WARN, "No answer from the hardware");
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
22130Sstevel@tonic-gate 			return;
22140Sstevel@tonic-gate 		}
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 		for (i = 0; i < mbox->mb_nstatus; i++) {
22170Sstevel@tonic-gate 			idx = mbox->mb_completed[i] - 1;
22180Sstevel@tonic-gate 			ac = softs->busycmd[idx];
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 			if (ac != NULL) {
22210Sstevel@tonic-gate 				/* pull the command from the busy index */
22220Sstevel@tonic-gate 				softs->busycmd[idx] = NULL;
22230Sstevel@tonic-gate 				if (softs->amr_busyslots > 0)
22240Sstevel@tonic-gate 					softs->amr_busyslots--;
22250Sstevel@tonic-gate 				if (softs->amr_busyslots == 0)
22260Sstevel@tonic-gate 					cv_broadcast(&softs->cmd_cv);
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_BUSY;
22290Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
22300Sstevel@tonic-gate 				ac->ac_status = mbox->mb_status;
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 				/* enqueue here */
22330Sstevel@tonic-gate 				if (head) {
22340Sstevel@tonic-gate 					tail->ac_next = ac;
22350Sstevel@tonic-gate 					tail = ac;
22360Sstevel@tonic-gate 					tail->ac_next = NULL;
22370Sstevel@tonic-gate 				} else {
22380Sstevel@tonic-gate 					tail = head = ac;
22390Sstevel@tonic-gate 					ac->ac_next = NULL;
22400Sstevel@tonic-gate 				}
22410Sstevel@tonic-gate 			} else {
22420Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
22430Sstevel@tonic-gate 					"ac in mailbox is NULL!"));
22440Sstevel@tonic-gate 			}
22450Sstevel@tonic-gate 		}
22460Sstevel@tonic-gate 	} else {
22470Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!"));
22480Sstevel@tonic-gate 	}
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 	if (head != NULL) {
22530Sstevel@tonic-gate 		amr_call_pkt_comp(head);
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	/* dispatch a thread to process the pending I/O if there is any */
22570Sstevel@tonic-gate 	if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue,
22580Sstevel@tonic-gate 		(void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) {
22590Sstevel@tonic-gate 		cmn_err(CE_WARN, "No memory available to dispatch taskq");
22600Sstevel@tonic-gate 	}
22610Sstevel@tonic-gate }
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate static void
22640Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head)
22650Sstevel@tonic-gate {
22660Sstevel@tonic-gate 	register struct scsi_pkt	*pkt;
22670Sstevel@tonic-gate 	register struct amr_command	*ac, *localhead;
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 	localhead = head;
22700Sstevel@tonic-gate 
22710Sstevel@tonic-gate 	while (localhead) {
22720Sstevel@tonic-gate 		ac = localhead;
22730Sstevel@tonic-gate 		localhead = ac->ac_next;
22740Sstevel@tonic-gate 		ac->ac_next = NULL;
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 		pkt = ac->pkt;
22770Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 		if (ac->ac_status == AMR_STATUS_SUCCESS) {
22800Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
22810Sstevel@tonic-gate 					| STATE_GOT_TARGET
22820Sstevel@tonic-gate 					| STATE_SENT_CMD
22830Sstevel@tonic-gate 					| STATE_XFERRED_DATA);
22840Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
22850Sstevel@tonic-gate 		} else {
22860Sstevel@tonic-gate 			pkt->pkt_state |= STATE_GOT_BUS
22870Sstevel@tonic-gate 					| STATE_ARQ_DONE;
22880Sstevel@tonic-gate 			pkt->pkt_reason = CMD_INCOMPLETE;
22890Sstevel@tonic-gate 			amr_set_arq_data(pkt, KEY_HARDWARE_ERROR);
22900Sstevel@tonic-gate 		}
22910Sstevel@tonic-gate 
22920Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR) &&
22930Sstevel@tonic-gate 			pkt->pkt_comp) {
22940Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
22950Sstevel@tonic-gate 		}
22960Sstevel@tonic-gate 	}
22970Sstevel@tonic-gate }
2298