xref: /onnv-gate/usr/src/uts/intel/io/amr/amr.c (revision 7656:2621e50fdf4a)
10Sstevel@tonic-gate /*
27542SRichard.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 */
226*7656SSherry.Moore@Sun.COM 	0,		/* power */
227*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_supported,	/* devo_quiesce */
2280Sstevel@tonic-gate };
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2320Sstevel@tonic-gate static struct modldrv modldrv = {
2330Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. driver here */
2347542SRichard.Bean@Sun.COM 	"AMR Driver",		/* Name of the module. */
2350Sstevel@tonic-gate 	&amr_ops,		/* Driver ops vector */
2360Sstevel@tonic-gate };
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate static struct modlinkage modlinkage = {
2390Sstevel@tonic-gate 	MODREV_1,
2400Sstevel@tonic-gate 	&modldrv,
2410Sstevel@tonic-gate 	NULL
2420Sstevel@tonic-gate };
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /* DMA access attributes */
2450Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = {
2460Sstevel@tonic-gate 	DDI_DEVICE_ATTR_V0,
2470Sstevel@tonic-gate 	DDI_NEVERSWAP_ACC,
2480Sstevel@tonic-gate 	DDI_STRICTORDER_ACC
2490Sstevel@tonic-gate };
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate static struct amr_softs  *amr_softstatep;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate int
2550Sstevel@tonic-gate _init(void)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate 	int		error;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	error = ddi_soft_state_init((void *)&amr_softstatep,
260*7656SSherry.Moore@Sun.COM 	    sizeof (struct amr_softs), 0);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	if (error != 0)
2630Sstevel@tonic-gate 		goto error_out;
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	if ((error = scsi_hba_init(&modlinkage)) != 0) {
2660Sstevel@tonic-gate 		ddi_soft_state_fini((void*)&amr_softstatep);
2670Sstevel@tonic-gate 		goto error_out;
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 	error = mod_install(&modlinkage);
2710Sstevel@tonic-gate 	if (error != 0) {
2720Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
2730Sstevel@tonic-gate 		ddi_soft_state_fini((void*)&amr_softstatep);
2740Sstevel@tonic-gate 		goto error_out;
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	return (error);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate error_out:
2800Sstevel@tonic-gate 	cmn_err(CE_NOTE, "_init failed");
2810Sstevel@tonic-gate 	return (error);
2820Sstevel@tonic-gate }
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate int
2850Sstevel@tonic-gate _info(struct modinfo *modinfop)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate int
2910Sstevel@tonic-gate _fini(void)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	int	error;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) != 0) {
2960Sstevel@tonic-gate 		return (error);
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	scsi_hba_fini(&modlinkage);
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	ddi_soft_state_fini((void*)&amr_softstatep);
3020Sstevel@tonic-gate 	return (error);
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate static int
3070Sstevel@tonic-gate amr_attach(dev_info_t *dev, ddi_attach_cmd_t cmd)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate 	struct amr_softs	*softs;
3100Sstevel@tonic-gate 	int			error;
3110Sstevel@tonic-gate 	uint32_t		command, i;
3120Sstevel@tonic-gate 	int			instance;
3130Sstevel@tonic-gate 	caddr_t			cfgaddr;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	instance = ddi_get_instance(dev);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	switch (cmd) {
3180Sstevel@tonic-gate 		case DDI_ATTACH:
3190Sstevel@tonic-gate 			break;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 		case DDI_RESUME:
3220Sstevel@tonic-gate 			return (DDI_FAILURE);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 		default:
3250Sstevel@tonic-gate 			return (DDI_FAILURE);
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/*
3290Sstevel@tonic-gate 	 * Initialize softs.
3300Sstevel@tonic-gate 	 */
3310Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(amr_softstatep, instance) != DDI_SUCCESS)
3320Sstevel@tonic-gate 		return (DDI_FAILURE);
3330Sstevel@tonic-gate 	softs = ddi_get_soft_state(amr_softstatep, instance);
3340Sstevel@tonic-gate 	softs->state |= AMR_STATE_SOFT_STATE_SETUP;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	softs->dev_info_p = dev;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "softs: %p; busy_slot addr: %p",
339*7656SSherry.Moore@Sun.COM 	    (void *)softs, (void *)&(softs->amr_busyslots)));
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (pci_config_setup(dev, &(softs->pciconfig_handle))
342*7656SSherry.Moore@Sun.COM 	    != DDI_SUCCESS) {
3430Sstevel@tonic-gate 		goto error_out;
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 	softs->state |= AMR_STATE_PCI_CONFIG_SETUP;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	error = ddi_regs_map_setup(dev, 1, &cfgaddr, 0, 0,
348*7656SSherry.Moore@Sun.COM 	    &accattr, &(softs->regsmap_handle));
3490Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
3500Sstevel@tonic-gate 		goto error_out;
3510Sstevel@tonic-gate 	}
3520Sstevel@tonic-gate 	softs->state |= AMR_STATE_PCI_MEM_MAPPED;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	/*
3550Sstevel@tonic-gate 	 * Determine board type.
3560Sstevel@tonic-gate 	 */
3570Sstevel@tonic-gate 	command = pci_config_get16(softs->pciconfig_handle, PCI_CONF_COMM);
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	/*
3600Sstevel@tonic-gate 	 * Make sure we are going to be able to talk to this board.
3610Sstevel@tonic-gate 	 */
3620Sstevel@tonic-gate 	if ((command & PCI_COMM_MAE) == 0) {
3630Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,  "memory window not available"));
3640Sstevel@tonic-gate 		goto error_out;
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	/* force the busmaster enable bit on */
3680Sstevel@tonic-gate 	if (!(command & PCI_COMM_ME)) {
3690Sstevel@tonic-gate 		command |= PCI_COMM_ME;
3700Sstevel@tonic-gate 		pci_config_put16(softs->pciconfig_handle,
371*7656SSherry.Moore@Sun.COM 		    PCI_CONF_COMM, command);
3720Sstevel@tonic-gate 		command = pci_config_get16(softs->pciconfig_handle,
373*7656SSherry.Moore@Sun.COM 		    PCI_CONF_COMM);
3740Sstevel@tonic-gate 		if (!(command & PCI_COMM_ME))
3750Sstevel@tonic-gate 			goto error_out;
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/*
3790Sstevel@tonic-gate 	 * Allocate and connect our interrupt.
3800Sstevel@tonic-gate 	 */
3810Sstevel@tonic-gate 	if (ddi_intr_hilevel(dev, 0) != 0) {
382*7656SSherry.Moore@Sun.COM 		AMRDB_PRINT((CE_NOTE,
383*7656SSherry.Moore@Sun.COM 		    "High level interrupt is not supported!"));
384*7656SSherry.Moore@Sun.COM 		goto error_out;
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dev, 0,  &softs->iblock_cookiep)
388*7656SSherry.Moore@Sun.COM 	    != DDI_SUCCESS) {
3890Sstevel@tonic-gate 		goto error_out;
3900Sstevel@tonic-gate 	}
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	mutex_init(&softs->cmd_mutex, NULL, MUTEX_DRIVER,
393*7656SSherry.Moore@Sun.COM 	    softs->iblock_cookiep); /* should be used in interrupt */
3940Sstevel@tonic-gate 	mutex_init(&softs->queue_mutex, NULL, MUTEX_DRIVER,
3950Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3960Sstevel@tonic-gate 	mutex_init(&softs->periodic_mutex, NULL, MUTEX_DRIVER,
3970Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3980Sstevel@tonic-gate 	/* sychronize waits for the busy slots via this cv */
3990Sstevel@tonic-gate 	cv_init(&softs->cmd_cv, NULL, CV_DRIVER, NULL);
4000Sstevel@tonic-gate 	softs->state |= AMR_STATE_KMUTEX_INITED;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/*
4030Sstevel@tonic-gate 	 * Do bus-independent initialisation, bring controller online.
4040Sstevel@tonic-gate 	 */
4050Sstevel@tonic-gate 	if (amr_setup_mbox(softs) != DDI_SUCCESS)
4060Sstevel@tonic-gate 		goto error_out;
4070Sstevel@tonic-gate 	softs->state |= AMR_STATE_MAILBOX_SETUP;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	if (amr_setup_sg(softs) != DDI_SUCCESS)
4100Sstevel@tonic-gate 		goto error_out;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	softs->state |= AMR_STATE_SG_TABLES_SETUP;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if (amr_query_controller(softs) != DDI_SUCCESS)
4150Sstevel@tonic-gate 		goto error_out;
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	/*
4180Sstevel@tonic-gate 	 * A taskq is created for dispatching the waiting queue processing
4190Sstevel@tonic-gate 	 * thread. The threads number equals to the logic drive number and
4200Sstevel@tonic-gate 	 * the thread number should be 1 if there is no logic driver is
4210Sstevel@tonic-gate 	 * configured for this instance.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	if ((softs->amr_taskq = ddi_taskq_create(dev, "amr_taskq",
424*7656SSherry.Moore@Sun.COM 	    MAX(softs->amr_nlogdrives, 1), TASKQ_DEFAULTPRI, 0)) == NULL) {
4250Sstevel@tonic-gate 		goto error_out;
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 	softs->state |= AMR_STATE_TASKQ_SETUP;
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	if (ddi_add_intr(dev, 0, &softs->iblock_cookiep, NULL,
430*7656SSherry.Moore@Sun.COM 	    amr_intr, (caddr_t)softs) != DDI_SUCCESS) {
4310Sstevel@tonic-gate 		goto error_out;
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 	softs->state |= AMR_STATE_INTR_SETUP;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	/* set up the tran interface */
4360Sstevel@tonic-gate 	if (amr_setup_tran(softs->dev_info_p, softs) != DDI_SUCCESS) {
4370Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "setup tran failed"));
4380Sstevel@tonic-gate 		goto error_out;
4390Sstevel@tonic-gate 	}
4400Sstevel@tonic-gate 	softs->state |= AMR_STATE_TRAN_SETUP;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	/* schedule a thread for periodic check */
4430Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
4440Sstevel@tonic-gate 	softs->timeout_t = timeout(amr_periodic, (void *)softs,
445*7656SSherry.Moore@Sun.COM 	    drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
4460Sstevel@tonic-gate 	softs->state |= AMR_STATE_TIMEOUT_ENABLED;
4470Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	/* print firmware information in verbose mode */
4500Sstevel@tonic-gate 	cmn_err(CE_CONT, "?MegaRaid %s %s attached.",
451*7656SSherry.Moore@Sun.COM 	    softs->amr_product_info.pi_product_name,
452*7656SSherry.Moore@Sun.COM 	    softs->amr_product_info.pi_firmware_ver);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/* clear any interrupts */
4550Sstevel@tonic-gate 	AMR_QCLEAR_INTR(softs);
4560Sstevel@tonic-gate 	return (DDI_SUCCESS);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate error_out:
4590Sstevel@tonic-gate 	if (softs->state & AMR_STATE_INTR_SETUP) {
4600Sstevel@tonic-gate 		ddi_remove_intr(dev, 0, softs->iblock_cookiep);
4610Sstevel@tonic-gate 	}
4620Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TASKQ_SETUP) {
4630Sstevel@tonic-gate 		ddi_taskq_destroy(softs->amr_taskq);
4640Sstevel@tonic-gate 	}
4650Sstevel@tonic-gate 	if (softs->state & AMR_STATE_SG_TABLES_SETUP) {
4660Sstevel@tonic-gate 		for (i = 0; i < softs->sg_max_count; i++) {
4670Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
468*7656SSherry.Moore@Sun.COM 			    softs->sg_items[i].sg_handle);
4690Sstevel@tonic-gate 			(void) ddi_dma_mem_free(
470*7656SSherry.Moore@Sun.COM 			    &((softs->sg_items[i]).sg_acc_handle));
4710Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
472*7656SSherry.Moore@Sun.COM 			    &(softs->sg_items[i].sg_handle));
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 	if (softs->state & AMR_STATE_MAILBOX_SETUP) {
4760Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
4770Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&softs->mbox_acc_handle);
4780Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 	if (softs->state & AMR_STATE_KMUTEX_INITED) {
4810Sstevel@tonic-gate 		mutex_destroy(&softs->queue_mutex);
4820Sstevel@tonic-gate 		mutex_destroy(&softs->cmd_mutex);
4830Sstevel@tonic-gate 		mutex_destroy(&softs->periodic_mutex);
4840Sstevel@tonic-gate 		cv_destroy(&softs->cmd_cv);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 	if (softs->state & AMR_STATE_PCI_MEM_MAPPED)
4870Sstevel@tonic-gate 		ddi_regs_map_free(&softs->regsmap_handle);
4880Sstevel@tonic-gate 	if (softs->state & AMR_STATE_PCI_CONFIG_SETUP)
4890Sstevel@tonic-gate 		pci_config_teardown(&softs->pciconfig_handle);
4900Sstevel@tonic-gate 	if (softs->state & AMR_STATE_SOFT_STATE_SETUP)
4910Sstevel@tonic-gate 		ddi_soft_state_free(amr_softstatep, instance);
4920Sstevel@tonic-gate 	return (DDI_FAILURE);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate /*
4960Sstevel@tonic-gate  * Bring the controller down to a dormant state and detach all child devices.
4970Sstevel@tonic-gate  * This function is called during detach, system shutdown.
4980Sstevel@tonic-gate  *
4990Sstevel@tonic-gate  * Note that we can assume that the bufq on the controller is empty, as we won't
5000Sstevel@tonic-gate  * allow shutdown if any device is open.
5010Sstevel@tonic-gate  */
5020Sstevel@tonic-gate /*ARGSUSED*/
5030Sstevel@tonic-gate static int amr_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
5040Sstevel@tonic-gate {
5050Sstevel@tonic-gate 	struct amr_softs	*softs;
5060Sstevel@tonic-gate 	int			instance;
5070Sstevel@tonic-gate 	uint32_t		i, done_flag;
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	instance = ddi_get_instance(dev);
5100Sstevel@tonic-gate 	softs = ddi_get_soft_state(amr_softstatep, instance);
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	/* flush the controllor */
5130Sstevel@tonic-gate 	if (amr_flush(softs) != 0) {
5140Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "device shutdown failed"));
5150Sstevel@tonic-gate 		return (EIO);
5160Sstevel@tonic-gate 	}
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/* release the amr timer */
5190Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
5200Sstevel@tonic-gate 	softs->state &= ~AMR_STATE_TIMEOUT_ENABLED;
5210Sstevel@tonic-gate 	if (softs->timeout_t) {
5220Sstevel@tonic-gate 		(void) untimeout(softs->timeout_t);
5230Sstevel@tonic-gate 		softs->timeout_t = 0;
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	for (i = 0; i < softs->sg_max_count; i++) {
5280Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(
529*7656SSherry.Moore@Sun.COM 		    softs->sg_items[i].sg_handle);
5300Sstevel@tonic-gate 		(void) ddi_dma_mem_free(
531*7656SSherry.Moore@Sun.COM 		    &((softs->sg_items[i]).sg_acc_handle));
5320Sstevel@tonic-gate 		(void) ddi_dma_free_handle(
533*7656SSherry.Moore@Sun.COM 		    &(softs->sg_items[i].sg_handle));
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
5370Sstevel@tonic-gate 	(void) ddi_dma_mem_free(&softs->mbox_acc_handle);
5380Sstevel@tonic-gate 	(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	/* disconnect the interrupt handler */
5410Sstevel@tonic-gate 	ddi_remove_intr(softs->dev_info_p,  0, softs->iblock_cookiep);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	/* wait for the completion of current in-progress interruptes */
5440Sstevel@tonic-gate 	AMR_DELAY((softs->amr_interrupts_counter == 0), 1000, done_flag);
5450Sstevel@tonic-gate 	if (!done_flag) {
5460Sstevel@tonic-gate 		cmn_err(CE_WARN, "Suspicious interrupts in-progress.");
5470Sstevel@tonic-gate 	}
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	ddi_taskq_destroy(softs->amr_taskq);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	(void) scsi_hba_detach(dev);
5520Sstevel@tonic-gate 	scsi_hba_tran_free(softs->hba_tran);
5530Sstevel@tonic-gate 	ddi_regs_map_free(&softs->regsmap_handle);
5540Sstevel@tonic-gate 	pci_config_teardown(&softs->pciconfig_handle);
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	mutex_destroy(&softs->queue_mutex);
5570Sstevel@tonic-gate 	mutex_destroy(&softs->cmd_mutex);
5580Sstevel@tonic-gate 	mutex_destroy(&softs->periodic_mutex);
5590Sstevel@tonic-gate 	cv_destroy(&softs->cmd_cv);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	/* print firmware information in verbose mode */
5620Sstevel@tonic-gate 	cmn_err(CE_NOTE, "?MegaRaid %s %s detached.",
563*7656SSherry.Moore@Sun.COM 	    softs->amr_product_info.pi_product_name,
564*7656SSherry.Moore@Sun.COM 	    softs->amr_product_info.pi_firmware_ver);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	ddi_soft_state_free(amr_softstatep, instance);
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	return (DDI_SUCCESS);
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /*ARGSUSED*/
5730Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5740Sstevel@tonic-gate 	void *arg, void **result)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	struct amr_softs	*softs;
5770Sstevel@tonic-gate 	int			instance;
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	switch (infocmd) {
5820Sstevel@tonic-gate 		case DDI_INFO_DEVT2DEVINFO:
5830Sstevel@tonic-gate 			softs = ddi_get_soft_state(amr_softstatep, instance);
5840Sstevel@tonic-gate 			if (softs != NULL) {
5850Sstevel@tonic-gate 				*result = softs->dev_info_p;
5860Sstevel@tonic-gate 				return (DDI_SUCCESS);
5870Sstevel@tonic-gate 			} else {
5880Sstevel@tonic-gate 				*result = NULL;
5890Sstevel@tonic-gate 				return (DDI_FAILURE);
5900Sstevel@tonic-gate 			}
5910Sstevel@tonic-gate 		case DDI_INFO_DEVT2INSTANCE:
5920Sstevel@tonic-gate 			*(int *)result = instance;
5930Sstevel@tonic-gate 			break;
5940Sstevel@tonic-gate 		default:
5950Sstevel@tonic-gate 			break;
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 	return (DDI_SUCCESS);
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate  * Take an interrupt, or be poked by other code to look for interrupt-worthy
6020Sstevel@tonic-gate  * status.
6030Sstevel@tonic-gate  */
6040Sstevel@tonic-gate static uint_t
6050Sstevel@tonic-gate amr_intr(caddr_t arg)
6060Sstevel@tonic-gate {
6070Sstevel@tonic-gate 	struct amr_softs *softs = (struct amr_softs *)arg;
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	softs->amr_interrupts_counter++;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	if (AMR_QGET_ODB(softs) != AMR_QODB_READY) {
6120Sstevel@tonic-gate 		softs->amr_interrupts_counter--;
6130Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
6140Sstevel@tonic-gate 	}
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	/* collect finished commands, queue anything waiting */
6170Sstevel@tonic-gate 	amr_done(softs);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	softs->amr_interrupts_counter--;
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate }
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate /*
6260Sstevel@tonic-gate  * Setup the amr mailbox
6270Sstevel@tonic-gate  */
6280Sstevel@tonic-gate static int
6290Sstevel@tonic-gate amr_setup_mbox(struct amr_softs *softs)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate 	uint32_t	move;
6320Sstevel@tonic-gate 	size_t		mbox_len;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(
635*7656SSherry.Moore@Sun.COM 	    softs->dev_info_p,
636*7656SSherry.Moore@Sun.COM 	    &addr_dma_attr,
637*7656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
638*7656SSherry.Moore@Sun.COM 	    NULL,
639*7656SSherry.Moore@Sun.COM 	    &softs->mbox_dma_handle) != DDI_SUCCESS) {
6400Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "Cannot alloc dma handle for mailbox"));
6410Sstevel@tonic-gate 		goto error_out;
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(
645*7656SSherry.Moore@Sun.COM 	    softs->mbox_dma_handle,
646*7656SSherry.Moore@Sun.COM 	    sizeof (struct amr_mailbox) + 16,
647*7656SSherry.Moore@Sun.COM 	    &accattr,
648*7656SSherry.Moore@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
649*7656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
650*7656SSherry.Moore@Sun.COM 	    NULL,
651*7656SSherry.Moore@Sun.COM 	    (caddr_t *)(&softs->mbox),
652*7656SSherry.Moore@Sun.COM 	    &mbox_len,
653*7656SSherry.Moore@Sun.COM 	    &softs->mbox_acc_handle) !=
654*7656SSherry.Moore@Sun.COM 	    DDI_SUCCESS) {
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "Cannot alloc dma memory for mailbox"));
6570Sstevel@tonic-gate 		goto error_out;
6580Sstevel@tonic-gate 	}
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if (ddi_dma_addr_bind_handle(
661*7656SSherry.Moore@Sun.COM 	    softs->mbox_dma_handle,
662*7656SSherry.Moore@Sun.COM 	    NULL,
663*7656SSherry.Moore@Sun.COM 	    (caddr_t)softs->mbox,
664*7656SSherry.Moore@Sun.COM 	    mbox_len,
665*7656SSherry.Moore@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
666*7656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
667*7656SSherry.Moore@Sun.COM 	    NULL,
668*7656SSherry.Moore@Sun.COM 	    &softs->mbox_dma_cookie,
669*7656SSherry.Moore@Sun.COM 	    &softs->mbox_dma_cookien) != DDI_DMA_MAPPED) {
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "Cannot bind dma memory for mailbox"));
6720Sstevel@tonic-gate 		goto error_out;
6730Sstevel@tonic-gate 	}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if (softs->mbox_dma_cookien != 1)
6760Sstevel@tonic-gate 		goto error_out;
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	/* The phy address of mailbox must be aligned on a 16-byte boundary */
6790Sstevel@tonic-gate 	move = 16 - (((uint32_t)softs->mbox_dma_cookie.dmac_address)&0xf);
6800Sstevel@tonic-gate 	softs->mbox_phyaddr =
681*7656SSherry.Moore@Sun.COM 	    (softs->mbox_dma_cookie.dmac_address + move);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	softs->mailbox =
684*7656SSherry.Moore@Sun.COM 	    (struct amr_mailbox *)(((uintptr_t)softs->mbox) + move);
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "phraddy=%x, mailbox=%p, softs->mbox=%p, move=%x",
687*7656SSherry.Moore@Sun.COM 	    softs->mbox_phyaddr, (void *)softs->mailbox,
688*7656SSherry.Moore@Sun.COM 	    softs->mbox, move));
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	return (DDI_SUCCESS);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate error_out:
6930Sstevel@tonic-gate 	if (softs->mbox_dma_cookien)
6940Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
6950Sstevel@tonic-gate 	if (softs->mbox_acc_handle) {
6960Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&(softs->mbox_acc_handle));
6970Sstevel@tonic-gate 		softs->mbox_acc_handle = NULL;
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 	if (softs->mbox_dma_handle) {
7000Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
7010Sstevel@tonic-gate 		softs->mbox_dma_handle = NULL;
7020Sstevel@tonic-gate 	}
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	return (DDI_FAILURE);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate /*
7080Sstevel@tonic-gate  * Perform a periodic check of the controller status
7090Sstevel@tonic-gate  */
7100Sstevel@tonic-gate static void
7110Sstevel@tonic-gate amr_periodic(void *data)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate 	uint32_t		i;
7140Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)data;
7150Sstevel@tonic-gate 	struct scsi_pkt 	*pkt;
7160Sstevel@tonic-gate 	register struct amr_command	*ac;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	for (i = 0; i < softs->sg_max_count; i++) {
7190Sstevel@tonic-gate 		if (softs->busycmd[i] == NULL)
7200Sstevel@tonic-gate 			continue;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 		mutex_enter(&softs->cmd_mutex);
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 		if (softs->busycmd[i] == NULL) {
7250Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7260Sstevel@tonic-gate 			continue;
7270Sstevel@tonic-gate 		}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 		pkt = softs->busycmd[i]->pkt;
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 		if ((pkt->pkt_time != 0) &&
732*7656SSherry.Moore@Sun.COM 		    (ddi_get_time() -
733*7656SSherry.Moore@Sun.COM 		    softs->busycmd[i]->ac_timestamp >
734*7656SSherry.Moore@Sun.COM 		    pkt->pkt_time)) {
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 			cmn_err(CE_WARN,
737*7656SSherry.Moore@Sun.COM 			    "!timed out packet detected,\
7380Sstevel@tonic-gate 				sc = %p, pkt = %p, index = %d, ac = %p",
739*7656SSherry.Moore@Sun.COM 			    (void *)softs,
740*7656SSherry.Moore@Sun.COM 			    (void *)pkt,
741*7656SSherry.Moore@Sun.COM 			    i,
742*7656SSherry.Moore@Sun.COM 			    (void *)softs->busycmd[i]);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 			ac = softs->busycmd[i];
7450Sstevel@tonic-gate 			ac->ac_next = NULL;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 			/* pull command from the busy index */
7480Sstevel@tonic-gate 			softs->busycmd[i] = NULL;
7490Sstevel@tonic-gate 			if (softs->amr_busyslots > 0)
7500Sstevel@tonic-gate 				softs->amr_busyslots--;
7510Sstevel@tonic-gate 			if (softs->amr_busyslots == 0)
7520Sstevel@tonic-gate 				cv_broadcast(&softs->cmd_cv);
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 			pkt = ac->pkt;
7570Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
7580Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_TIMEOUT;
7590Sstevel@tonic-gate 			pkt->pkt_reason = CMD_TIMEOUT;
7600Sstevel@tonic-gate 			if (!(pkt->pkt_flags &
761*7656SSherry.Moore@Sun.COM 			    FLAG_NOINTR) && pkt->pkt_comp) {
7620Sstevel@tonic-gate 				/* call pkt callback */
7630Sstevel@tonic-gate 				(*pkt->pkt_comp)(pkt);
7640Sstevel@tonic-gate 			}
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		} else {
7670Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7680Sstevel@tonic-gate 		}
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/* restart the amr timer */
7720Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
7730Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TIMEOUT_ENABLED)
7740Sstevel@tonic-gate 		softs->timeout_t = timeout(amr_periodic, (void *)softs,
775*7656SSherry.Moore@Sun.COM 		    drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
7760Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
7770Sstevel@tonic-gate }
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate /*
7800Sstevel@tonic-gate  * Interrogate the controller for the operational parameters we require.
7810Sstevel@tonic-gate  */
7820Sstevel@tonic-gate static int
7830Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	struct amr_enquiry3	*aex;
7860Sstevel@tonic-gate 	struct amr_prodinfo	*ap;
7870Sstevel@tonic-gate 	struct amr_enquiry	*ae;
7880Sstevel@tonic-gate 	uint32_t		ldrv;
7890Sstevel@tonic-gate 	int			instance;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/*
7920Sstevel@tonic-gate 	 * If we haven't found the real limit yet, let us have a couple of
7930Sstevel@tonic-gate 	 * commands in order to be able to probe.
7940Sstevel@tonic-gate 	 */
7950Sstevel@tonic-gate 	if (softs->maxio == 0)
7960Sstevel@tonic-gate 		softs->maxio = 2;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	instance = ddi_get_instance(softs->dev_info_p);
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	/*
8010Sstevel@tonic-gate 	 * Try to issue an ENQUIRY3 command
8020Sstevel@tonic-gate 	 */
8030Sstevel@tonic-gate 	if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG,
804*7656SSherry.Moore@Sun.COM 	    AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry"));
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
809*7656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_size =
810*7656SSherry.Moore@Sun.COM 			    aex->ae_drivesize[ldrv];
811*7656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_state =
812*7656SSherry.Moore@Sun.COM 			    aex->ae_drivestate[ldrv];
813*7656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_properties =
814*7656SSherry.Moore@Sun.COM 			    aex->ae_driveprop[ldrv];
815*7656SSherry.Moore@Sun.COM 			AMRDB_PRINT((CE_NOTE,
816*7656SSherry.Moore@Sun.COM 			    "  drive %d: size: %d state %x properties %x\n",
817*7656SSherry.Moore@Sun.COM 			    ldrv,
818*7656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_size,
819*7656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_state,
820*7656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_properties));
8210Sstevel@tonic-gate 
822*7656SSherry.Moore@Sun.COM 			if (softs->logic_drive[ldrv].al_state ==
823*7656SSherry.Moore@Sun.COM 			    AMR_LDRV_OFFLINE)
824*7656SSherry.Moore@Sun.COM 				cmn_err(CE_NOTE,
825*7656SSherry.Moore@Sun.COM 				    "!instance %d log-drive %d is offline",
826*7656SSherry.Moore@Sun.COM 				    instance, ldrv);
827*7656SSherry.Moore@Sun.COM 			else
828*7656SSherry.Moore@Sun.COM 				softs->amr_nlogdrives++;
8290Sstevel@tonic-gate 		}
8300Sstevel@tonic-gate 		kmem_free(aex, AMR_ENQ_BUFFER_SIZE);
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 		if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE,
833*7656SSherry.Moore@Sun.COM 		    AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
8340Sstevel@tonic-gate 			AMRDB_PRINT((CE_NOTE,
835*7656SSherry.Moore@Sun.COM 			    "Cannot obtain product data from controller"));
8360Sstevel@tonic-gate 			return (EIO);
8370Sstevel@tonic-gate 		}
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 		softs->maxdrives = AMR_40LD_MAXDRIVES;
8400Sstevel@tonic-gate 		softs->maxchan = ap->ap_nschan;
8410Sstevel@tonic-gate 		softs->maxio = ap->ap_maxio;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 		bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver,
844*7656SSherry.Moore@Sun.COM 		    AMR_FIRMWARE_VER_SIZE);
8450Sstevel@tonic-gate 		softs->amr_product_info.
846*7656SSherry.Moore@Sun.COM 		    pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 		bcopy(ap->ap_product, softs->amr_product_info.pi_product_name,
849*7656SSherry.Moore@Sun.COM 		    AMR_PRODUCT_INFO_SIZE);
8500Sstevel@tonic-gate 		softs->amr_product_info.
851*7656SSherry.Moore@Sun.COM 		    pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		kmem_free(ap, AMR_ENQ_BUFFER_SIZE);
8540Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio));
8550Sstevel@tonic-gate 	} else {
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry failed, \
8580Sstevel@tonic-gate 				so try another way"));
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 		/* failed, try the 8LD ENQUIRY commands */
8610Sstevel@tonic-gate 		if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
862*7656SSherry.Moore@Sun.COM 		    AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0))
863*7656SSherry.Moore@Sun.COM 		    == NULL) {
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 			if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
866*7656SSherry.Moore@Sun.COM 			    AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0))
867*7656SSherry.Moore@Sun.COM 			    == NULL) {
8680Sstevel@tonic-gate 				AMRDB_PRINT((CE_NOTE,
869*7656SSherry.Moore@Sun.COM 				    "Cannot obtain configuration data"));
8700Sstevel@tonic-gate 				return (EIO);
8710Sstevel@tonic-gate 			}
8720Sstevel@tonic-gate 			ae->ae_signature = 0;
8730Sstevel@tonic-gate 		}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		/*
8760Sstevel@tonic-gate 		 * Fetch current state of logical drives.
8770Sstevel@tonic-gate 		 */
8780Sstevel@tonic-gate 		for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
879*7656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_size =
880*7656SSherry.Moore@Sun.COM 			    ae->ae_ldrv.al_size[ldrv];
881*7656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_state =
882*7656SSherry.Moore@Sun.COM 			    ae->ae_ldrv.al_state[ldrv];
883*7656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_properties =
884*7656SSherry.Moore@Sun.COM 			    ae->ae_ldrv.al_properties[ldrv];
885*7656SSherry.Moore@Sun.COM 			AMRDB_PRINT((CE_NOTE,
886*7656SSherry.Moore@Sun.COM 			    " ********* drive %d: %d state %x properties %x",
887*7656SSherry.Moore@Sun.COM 			    ldrv,
888*7656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_size,
889*7656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_state,
890*7656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_properties));
8910Sstevel@tonic-gate 
892*7656SSherry.Moore@Sun.COM 			if (softs->logic_drive[ldrv].al_state ==
893*7656SSherry.Moore@Sun.COM 			    AMR_LDRV_OFFLINE)
894*7656SSherry.Moore@Sun.COM 				cmn_err(CE_NOTE,
895*7656SSherry.Moore@Sun.COM 				    "!instance %d log-drive %d is offline",
896*7656SSherry.Moore@Sun.COM 				    instance, ldrv);
897*7656SSherry.Moore@Sun.COM 			else
898*7656SSherry.Moore@Sun.COM 				softs->amr_nlogdrives++;
8990Sstevel@tonic-gate 		}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 		softs->maxdrives = AMR_8LD_MAXDRIVES;
9020Sstevel@tonic-gate 		softs->maxchan = ae->ae_adapter.aa_channels;
9030Sstevel@tonic-gate 		softs->maxio = ae->ae_adapter.aa_maxio;
9040Sstevel@tonic-gate 		kmem_free(ae, AMR_ENQ_BUFFER_SIZE);
9050Sstevel@tonic-gate 	}
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	/*
9080Sstevel@tonic-gate 	 * Mark remaining drives as unused.
9090Sstevel@tonic-gate 	 */
9100Sstevel@tonic-gate 	for (; ldrv < AMR_MAXLD; ldrv++)
9110Sstevel@tonic-gate 		softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE;
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * Cap the maximum number of outstanding I/Os.  AMI's driver
9150Sstevel@tonic-gate 	 * doesn't trust the controller's reported value, and lockups have
9160Sstevel@tonic-gate 	 * been seen when we do.
9170Sstevel@tonic-gate 	 */
9180Sstevel@tonic-gate 	softs->maxio = MIN(softs->maxio, AMR_LIMITCMD);
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	return (DDI_SUCCESS);
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate /*
9240Sstevel@tonic-gate  * Run a generic enquiry-style command.
9250Sstevel@tonic-gate  */
9260Sstevel@tonic-gate static void *
9270Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd,
9280Sstevel@tonic-gate 				uint8_t cmdsub, uint8_t cmdqual)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate 	struct amr_command	ac;
9310Sstevel@tonic-gate 	void			*result;
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate 	result = NULL;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9360Sstevel@tonic-gate 	ac.ac_softs = softs;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	/* set command flags */
9390Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 	/* build the command proper */
9420Sstevel@tonic-gate 	ac.mailbox.mb_command	= cmd;
9430Sstevel@tonic-gate 	ac.mailbox.mb_cmdsub	= cmdsub;
9440Sstevel@tonic-gate 	ac.mailbox.mb_cmdqual	= cmdqual;
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS)
9470Sstevel@tonic-gate 		return (NULL);
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	if (amr_poll_command(&ac) || ac.ac_status != 0) {
9500Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll command, goto out"));
9510Sstevel@tonic-gate 		amr_enquiry_unmapcmd(&ac);
9520Sstevel@tonic-gate 		return (NULL);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	/* allocate the response structure */
9560Sstevel@tonic-gate 	result = kmem_zalloc(bufsize, KM_SLEEP);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	bcopy(ac.ac_data, result, bufsize);
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	amr_enquiry_unmapcmd(&ac);
9610Sstevel@tonic-gate 	return (result);
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate /*
9650Sstevel@tonic-gate  * Flush the controller's internal cache, return status.
9660Sstevel@tonic-gate  */
9670Sstevel@tonic-gate static int
9680Sstevel@tonic-gate amr_flush(struct amr_softs *softs)
9690Sstevel@tonic-gate {
9700Sstevel@tonic-gate 	struct amr_command	ac;
9710Sstevel@tonic-gate 	int			error = 0;
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9740Sstevel@tonic-gate 	ac.ac_softs = softs;
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	/* build the command proper */
9790Sstevel@tonic-gate 	ac.mailbox.mb_command = AMR_CMD_FLUSH;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	/* have to poll, as the system may be going down or otherwise damaged */
9820Sstevel@tonic-gate 	if (error = amr_poll_command(&ac)) {
9830Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll this cmd"));
9840Sstevel@tonic-gate 		return (error);
9850Sstevel@tonic-gate 	}
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	return (error);
9880Sstevel@tonic-gate }
9890Sstevel@tonic-gate 
9900Sstevel@tonic-gate /*
9910Sstevel@tonic-gate  * Take a command, submit it to the controller and wait for it to return.
9920Sstevel@tonic-gate  * Returns nonzero on error.  Can be safely called with interrupts enabled.
9930Sstevel@tonic-gate  */
9940Sstevel@tonic-gate static int
9950Sstevel@tonic-gate amr_poll_command(struct amr_command *ac)
9960Sstevel@tonic-gate {
9970Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
9980Sstevel@tonic-gate 	volatile uint32_t	done_flag;
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)",
1001*7656SSherry.Moore@Sun.COM 	    (void *)&ac->mailbox,
1002*7656SSherry.Moore@Sun.COM 	    (void *)softs->mailbox,
1003*7656SSherry.Moore@Sun.COM 	    (uint32_t)AMR_MBOX_CMDSIZE));
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	while (softs->amr_busyslots != 0)
10080Sstevel@tonic-gate 		cv_wait(&softs->cmd_cv, &softs->cmd_mutex);
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	/*
10110Sstevel@tonic-gate 	 * For read/write commands, the scatter/gather table should be
10120Sstevel@tonic-gate 	 * filled, and the last entry in scatter/gather table will be used.
10130Sstevel@tonic-gate 	 */
10140Sstevel@tonic-gate 	if ((ac->mailbox.mb_command == AMR_CMD_LREAD) ||
10150Sstevel@tonic-gate 	    (ac->mailbox.mb_command == AMR_CMD_LWRITE)) {
10160Sstevel@tonic-gate 		bcopy(ac->sgtable,
1017*7656SSherry.Moore@Sun.COM 		    softs->sg_items[softs->sg_max_count - 1].sg_table,
1018*7656SSherry.Moore@Sun.COM 		    sizeof (struct amr_sgentry) * AMR_NSEG);
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		(void) ddi_dma_sync(
1021*7656SSherry.Moore@Sun.COM 		    softs->sg_items[softs->sg_max_count - 1].sg_handle,
1022*7656SSherry.Moore@Sun.COM 		    0, 0, DDI_DMA_SYNC_FORDEV);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 		ac->mailbox.mb_physaddr =
1025*7656SSherry.Moore@Sun.COM 		    softs->sg_items[softs->sg_max_count - 1].sg_phyaddr;
10260Sstevel@tonic-gate 	}
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE);
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	/* sync the dma memory */
10310Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	/* clear the poll/ack fields in the mailbox */
10340Sstevel@tonic-gate 	softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID;
10350Sstevel@tonic-gate 	softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS;
10360Sstevel@tonic-gate 	softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS;
10370Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10380Sstevel@tonic-gate 	softs->mailbox->mb_ack = 0;
10390Sstevel@tonic-gate 	softs->mailbox->mb_busy = 1;
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	/* sync the dma memory */
10440Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS),
1047*7656SSherry.Moore@Sun.COM 	    1000, done_flag);
10480Sstevel@tonic-gate 	if (!done_flag) {
10490Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10500Sstevel@tonic-gate 		return (1);
10510Sstevel@tonic-gate 	}
10520Sstevel@tonic-gate 
10530Sstevel@tonic-gate 	ac->ac_status = softs->mailbox->mb_status;
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag);
10560Sstevel@tonic-gate 	if (!done_flag) {
10570Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10580Sstevel@tonic-gate 		return (1);
10590Sstevel@tonic-gate 	}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10620Sstevel@tonic-gate 	softs->mailbox->mb_ack = AMR_POLL_ACK;
10630Sstevel@tonic-gate 
10640Sstevel@tonic-gate 	/* acknowledge that we have the commands */
10650Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag);
10680Sstevel@tonic-gate 	if (!done_flag) {
10690Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10700Sstevel@tonic-gate 		return (1);
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
10740Sstevel@tonic-gate 	return (ac->ac_status != AMR_STATUS_SUCCESS);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate /*
10780Sstevel@tonic-gate  * setup the scatter/gather table
10790Sstevel@tonic-gate  */
10800Sstevel@tonic-gate static int
10810Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate 	uint32_t		i;
10840Sstevel@tonic-gate 	size_t			len;
10850Sstevel@tonic-gate 	ddi_dma_cookie_t	cookie;
10860Sstevel@tonic-gate 	uint_t			cookien;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	softs->sg_max_count = 0;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	for (i = 0; i < AMR_MAXCMD; i++) {
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 		/* reset the cookien */
10930Sstevel@tonic-gate 		cookien = 0;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
10960Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(
1097*7656SSherry.Moore@Sun.COM 		    softs->dev_info_p,
1098*7656SSherry.Moore@Sun.COM 		    &addr_dma_attr,
1099*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP,
1100*7656SSherry.Moore@Sun.COM 		    NULL,
1101*7656SSherry.Moore@Sun.COM 		    &((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) {
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11040Sstevel@tonic-gate 			"Cannot alloc dma handle for s/g table"));
11050Sstevel@tonic-gate 			goto error_out;
11060Sstevel@tonic-gate 		}
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 		if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle,
1109*7656SSherry.Moore@Sun.COM 		    sizeof (struct amr_sgentry) * AMR_NSEG,
1110*7656SSherry.Moore@Sun.COM 		    &accattr,
1111*7656SSherry.Moore@Sun.COM 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1112*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP, NULL,
1113*7656SSherry.Moore@Sun.COM 		    (caddr_t *)(&(softs->sg_items[i]).sg_table),
1114*7656SSherry.Moore@Sun.COM 		    &len,
1115*7656SSherry.Moore@Sun.COM 		    &(softs->sg_items[i]).sg_acc_handle)
1116*7656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11190Sstevel@tonic-gate 			"Cannot allocate DMA memory"));
11200Sstevel@tonic-gate 			goto error_out;
11210Sstevel@tonic-gate 		}
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(
1124*7656SSherry.Moore@Sun.COM 		    (softs->sg_items[i]).sg_handle,
1125*7656SSherry.Moore@Sun.COM 		    NULL,
1126*7656SSherry.Moore@Sun.COM 		    (caddr_t)((softs->sg_items[i]).sg_table),
1127*7656SSherry.Moore@Sun.COM 		    len,
1128*7656SSherry.Moore@Sun.COM 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
1129*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP,
1130*7656SSherry.Moore@Sun.COM 		    NULL,
1131*7656SSherry.Moore@Sun.COM 		    &cookie,
1132*7656SSherry.Moore@Sun.COM 		    &cookien) != DDI_DMA_MAPPED) {
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11350Sstevel@tonic-gate 			"Cannot bind communication area for s/g table"));
11360Sstevel@tonic-gate 			goto error_out;
11370Sstevel@tonic-gate 		}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 		if (cookien != 1)
11400Sstevel@tonic-gate 			goto error_out;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 		softs->sg_items[i].sg_phyaddr = cookie.dmac_address;
11430Sstevel@tonic-gate 		softs->sg_max_count++;
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	return (DDI_SUCCESS);
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate error_out:
11490Sstevel@tonic-gate 	/*
11500Sstevel@tonic-gate 	 * Couldn't allocate/initialize all of the sg table entries.
11510Sstevel@tonic-gate 	 * Clean up the partially-initialized entry before returning.
11520Sstevel@tonic-gate 	 */
11530Sstevel@tonic-gate 	if (cookien) {
11540Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_acc_handle) {
11570Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle));
11580Sstevel@tonic-gate 		(softs->sg_items[i]).sg_acc_handle = NULL;
11590Sstevel@tonic-gate 	}
11600Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_handle) {
11610Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle));
11620Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	/*
11660Sstevel@tonic-gate 	 * At least two sg table entries are needed. One is for regular data
11670Sstevel@tonic-gate 	 * I/O commands, the other is for poll I/O commands.
11680Sstevel@tonic-gate 	 */
11690Sstevel@tonic-gate 	return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE);
11700Sstevel@tonic-gate }
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate /*
11730Sstevel@tonic-gate  * Map/unmap (ac)'s data in the controller's addressable space as required.
11740Sstevel@tonic-gate  *
11750Sstevel@tonic-gate  * These functions may be safely called multiple times on a given command.
11760Sstevel@tonic-gate  */
11770Sstevel@tonic-gate static void
11780Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep,
11790Sstevel@tonic-gate 		int nsegments)
11800Sstevel@tonic-gate {
11810Sstevel@tonic-gate 	struct amr_sgentry	*sg;
11820Sstevel@tonic-gate 	uint32_t		i, size;
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 	sg = ac->sgtable;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	size = 0;
11870Sstevel@tonic-gate 
11880Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = (uint8_t)nsegments;
11890Sstevel@tonic-gate 	for (i = 0; i < nsegments; i++, sg++) {
11900Sstevel@tonic-gate 		sg->sg_addr = buffer_dma_cookiep->dmac_address;
11910Sstevel@tonic-gate 		sg->sg_count = buffer_dma_cookiep->dmac_size;
11920Sstevel@tonic-gate 		size += sg->sg_count;
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		/*
11950Sstevel@tonic-gate 		 * There is no next cookie if the end of the current
11960Sstevel@tonic-gate 		 * window is reached. Otherwise, the next cookie
11970Sstevel@tonic-gate 		 * would be found.
11980Sstevel@tonic-gate 		 */
11990Sstevel@tonic-gate 		if ((ac->current_cookie + i + 1) != ac->num_of_cookie)
12000Sstevel@tonic-gate 			ddi_dma_nextcookie(ac->buffer_dma_handle,
1201*7656SSherry.Moore@Sun.COM 			    buffer_dma_cookiep);
12020Sstevel@tonic-gate 	}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 	ac->transfer_size = size;
12050Sstevel@tonic-gate 	ac->data_transfered += size;
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate /*
12100Sstevel@tonic-gate  * map the amr command for enquiry, allocate the DMA resource
12110Sstevel@tonic-gate  */
12120Sstevel@tonic-gate static int
12130Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size)
12140Sstevel@tonic-gate {
12150Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
12160Sstevel@tonic-gate 	size_t			len;
12170Sstevel@tonic-gate 	uint_t			dma_flags;
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x",
1220*7656SSherry.Moore@Sun.COM 	    (void *)ac, ac->ac_flags));
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
12230Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
12240Sstevel@tonic-gate 	} else {
12250Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
12260Sstevel@tonic-gate 	}
12270Sstevel@tonic-gate 
12280Sstevel@tonic-gate 	dma_flags |= DDI_DMA_CONSISTENT;
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	/* process the DMA by address bind mode */
12310Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(softs->dev_info_p,
1232*7656SSherry.Moore@Sun.COM 	    &addr_dma_attr, DDI_DMA_SLEEP, NULL,
1233*7656SSherry.Moore@Sun.COM 	    &ac->buffer_dma_handle) !=
1234*7656SSherry.Moore@Sun.COM 	    DDI_SUCCESS) {
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12370Sstevel@tonic-gate 		"Cannot allocate addr DMA tag"));
12380Sstevel@tonic-gate 		goto error_out;
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ac->buffer_dma_handle,
1242*7656SSherry.Moore@Sun.COM 	    data_size,
1243*7656SSherry.Moore@Sun.COM 	    &accattr,
1244*7656SSherry.Moore@Sun.COM 	    dma_flags,
1245*7656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
1246*7656SSherry.Moore@Sun.COM 	    NULL,
1247*7656SSherry.Moore@Sun.COM 	    (caddr_t *)&ac->ac_data,
1248*7656SSherry.Moore@Sun.COM 	    &len,
1249*7656SSherry.Moore@Sun.COM 	    &ac->buffer_acc_handle) !=
1250*7656SSherry.Moore@Sun.COM 	    DDI_SUCCESS) {
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12530Sstevel@tonic-gate 		"Cannot allocate DMA memory"));
12540Sstevel@tonic-gate 		goto error_out;
12550Sstevel@tonic-gate 	}
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	if ((ddi_dma_addr_bind_handle(
1258*7656SSherry.Moore@Sun.COM 	    ac->buffer_dma_handle,
1259*7656SSherry.Moore@Sun.COM 	    NULL, ac->ac_data, len, dma_flags,
1260*7656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie,
1261*7656SSherry.Moore@Sun.COM 	    &ac->num_of_cookie)) != DDI_DMA_MAPPED) {
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
1264*7656SSherry.Moore@Sun.COM 		    "Cannot bind addr for dma"));
12650Sstevel@tonic-gate 		goto error_out;
12660Sstevel@tonic-gate 	}
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address;
12690Sstevel@tonic-gate 
12700Sstevel@tonic-gate 	((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0;
12710Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = 0;
12720Sstevel@tonic-gate 	ac->mailbox.mb_physaddr = ac->ac_dataphys;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	ac->ac_flags |= AMR_CMD_MAPPED;
12750Sstevel@tonic-gate 
12760Sstevel@tonic-gate 	return (DDI_SUCCESS);
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate error_out:
12790Sstevel@tonic-gate 	if (ac->num_of_cookie)
12800Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
12810Sstevel@tonic-gate 	if (ac->buffer_acc_handle) {
12820Sstevel@tonic-gate 		ddi_dma_mem_free(&ac->buffer_acc_handle);
12830Sstevel@tonic-gate 		ac->buffer_acc_handle = NULL;
12840Sstevel@tonic-gate 	}
12850Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
12860Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
12870Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
12880Sstevel@tonic-gate 	}
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	return (DDI_FAILURE);
12910Sstevel@tonic-gate }
12920Sstevel@tonic-gate 
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate  * unmap the amr command for enquiry, free the DMA resource
12950Sstevel@tonic-gate  */
12960Sstevel@tonic-gate static void
12970Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac)
12980Sstevel@tonic-gate {
12990Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p",
1300*7656SSherry.Moore@Sun.COM 	    (void *)ac));
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
13030Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) {
13040Sstevel@tonic-gate 		if (ac->buffer_dma_handle)
13050Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
1306*7656SSherry.Moore@Sun.COM 			    ac->buffer_dma_handle);
13070Sstevel@tonic-gate 		if (ac->buffer_acc_handle) {
13080Sstevel@tonic-gate 			ddi_dma_mem_free(&ac->buffer_acc_handle);
13090Sstevel@tonic-gate 			ac->buffer_acc_handle = NULL;
13100Sstevel@tonic-gate 		}
13110Sstevel@tonic-gate 		if (ac->buffer_dma_handle) {
13120Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
1313*7656SSherry.Moore@Sun.COM 			    &ac->buffer_dma_handle);
13140Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13150Sstevel@tonic-gate 		}
13160Sstevel@tonic-gate 	}
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate /*
13220Sstevel@tonic-gate  * map the amr command, allocate the DMA resource
13230Sstevel@tonic-gate  */
13240Sstevel@tonic-gate static int
13253495Syw161884 amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg)
13260Sstevel@tonic-gate {
13270Sstevel@tonic-gate 	uint_t	dma_flags;
13280Sstevel@tonic-gate 	off_t	off;
13290Sstevel@tonic-gate 	size_t	len;
13300Sstevel@tonic-gate 	int	error;
13313495Syw161884 	int	(*cb)(caddr_t);
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x",
1334*7656SSherry.Moore@Sun.COM 	    (void *)ac, ac->ac_flags));
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
13370Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
13380Sstevel@tonic-gate 	} else {
13390Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) {
13430Sstevel@tonic-gate 		dma_flags |= DDI_DMA_CONSISTENT;
13440Sstevel@tonic-gate 	}
13450Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) {
13460Sstevel@tonic-gate 		dma_flags |= DDI_DMA_PARTIAL;
13470Sstevel@tonic-gate 	}
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate 	if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) {
13500Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
13510Sstevel@tonic-gate 		return (DDI_SUCCESS);
13520Sstevel@tonic-gate 	}
13530Sstevel@tonic-gate 
13543495Syw161884 	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
13553495Syw161884 
13560Sstevel@tonic-gate 	/* if the command involves data at all, and hasn't been mapped */
13570Sstevel@tonic-gate 	if (!(ac->ac_flags & AMR_CMD_MAPPED)) {
13580Sstevel@tonic-gate 		/* process the DMA by buffer bind mode */
13590Sstevel@tonic-gate 		error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle,
1360*7656SSherry.Moore@Sun.COM 		    ac->ac_buf,
1361*7656SSherry.Moore@Sun.COM 		    dma_flags,
1362*7656SSherry.Moore@Sun.COM 		    cb,
1363*7656SSherry.Moore@Sun.COM 		    arg,
1364*7656SSherry.Moore@Sun.COM 		    &ac->buffer_dma_cookie,
1365*7656SSherry.Moore@Sun.COM 		    &ac->num_of_cookie);
13660Sstevel@tonic-gate 		switch (error) {
13670Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
13680Sstevel@tonic-gate 			if (ddi_dma_numwin(ac->buffer_dma_handle,
1369*7656SSherry.Moore@Sun.COM 			    &ac->num_of_win) == DDI_FAILURE) {
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
1372*7656SSherry.Moore@Sun.COM 				    "Cannot get dma num win"));
13730Sstevel@tonic-gate 				(void) ddi_dma_unbind_handle(
1374*7656SSherry.Moore@Sun.COM 				    ac->buffer_dma_handle);
13750Sstevel@tonic-gate 				(void) ddi_dma_free_handle(
1376*7656SSherry.Moore@Sun.COM 				    &ac->buffer_dma_handle);
13770Sstevel@tonic-gate 				ac->buffer_dma_handle = NULL;
13780Sstevel@tonic-gate 				return (DDI_FAILURE);
13790Sstevel@tonic-gate 			}
13800Sstevel@tonic-gate 			ac->current_win = 0;
13810Sstevel@tonic-gate 			break;
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
13840Sstevel@tonic-gate 			ac->num_of_win = 1;
13850Sstevel@tonic-gate 			ac->current_win = 0;
13860Sstevel@tonic-gate 			break;
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 		default:
13890Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
1390*7656SSherry.Moore@Sun.COM 			    "Cannot bind buf for dma"));
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
1393*7656SSherry.Moore@Sun.COM 			    &ac->buffer_dma_handle);
13940Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13950Sstevel@tonic-gate 			return (DDI_FAILURE);
13960Sstevel@tonic-gate 		}
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 		ac->current_cookie = 0;
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
14010Sstevel@tonic-gate 	} else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) {
14020Sstevel@tonic-gate 		/* get the next window */
14030Sstevel@tonic-gate 		ac->current_win++;
14040Sstevel@tonic-gate 		(void) ddi_dma_getwin(ac->buffer_dma_handle,
1405*7656SSherry.Moore@Sun.COM 		    ac->current_win, &off, &len,
1406*7656SSherry.Moore@Sun.COM 		    &ac->buffer_dma_cookie,
1407*7656SSherry.Moore@Sun.COM 		    &ac->num_of_cookie);
14080Sstevel@tonic-gate 		ac->current_cookie = 0;
14090Sstevel@tonic-gate 	}
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) {
14120Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG);
14130Sstevel@tonic-gate 		ac->current_cookie += AMR_NSEG;
14140Sstevel@tonic-gate 	} else {
14150Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie,
1416*7656SSherry.Moore@Sun.COM 		    ac->num_of_cookie - ac->current_cookie);
14170Sstevel@tonic-gate 		ac->current_cookie = AMR_LAST_COOKIE_TAG;
14180Sstevel@tonic-gate 	}
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	return (DDI_SUCCESS);
14210Sstevel@tonic-gate }
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate /*
14240Sstevel@tonic-gate  * unmap the amr command, free the DMA resource
14250Sstevel@tonic-gate  */
14260Sstevel@tonic-gate static void
14270Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac)
14280Sstevel@tonic-gate {
14290Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p",
1430*7656SSherry.Moore@Sun.COM 	    (void *)ac));
14310Sstevel@tonic-gate 
14320Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
14330Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) &&
1434*7656SSherry.Moore@Sun.COM 	    ac->ac_buf && ac->buffer_dma_handle)
14350Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate static int
14410Sstevel@tonic-gate amr_setup_tran(dev_info_t  *dip, struct amr_softs *softp)
14420Sstevel@tonic-gate {
14430Sstevel@tonic-gate 	softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
14440Sstevel@tonic-gate 
14450Sstevel@tonic-gate 	/*
14460Sstevel@tonic-gate 	 * hba_private always points to the amr_softs struct
14470Sstevel@tonic-gate 	 */
14480Sstevel@tonic-gate 	softp->hba_tran->tran_hba_private	= softp;
14490Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_init		= amr_tran_tgt_init;
14500Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_probe		= scsi_hba_probe;
14510Sstevel@tonic-gate 	softp->hba_tran->tran_start		= amr_tran_start;
14520Sstevel@tonic-gate 	softp->hba_tran->tran_reset		= amr_tran_reset;
14530Sstevel@tonic-gate 	softp->hba_tran->tran_getcap		= amr_tran_getcap;
14540Sstevel@tonic-gate 	softp->hba_tran->tran_setcap		= amr_tran_setcap;
14550Sstevel@tonic-gate 	softp->hba_tran->tran_init_pkt		= amr_tran_init_pkt;
14560Sstevel@tonic-gate 	softp->hba_tran->tran_destroy_pkt	= amr_tran_destroy_pkt;
14570Sstevel@tonic-gate 	softp->hba_tran->tran_dmafree		= amr_tran_dmafree;
14580Sstevel@tonic-gate 	softp->hba_tran->tran_sync_pkt		= amr_tran_sync_pkt;
14590Sstevel@tonic-gate 	softp->hba_tran->tran_abort		= NULL;
14600Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_free		= NULL;
14610Sstevel@tonic-gate 	softp->hba_tran->tran_quiesce		= NULL;
14620Sstevel@tonic-gate 	softp->hba_tran->tran_unquiesce		= NULL;
14630Sstevel@tonic-gate 	softp->hba_tran->tran_sd		= NULL;
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran,
1466*7656SSherry.Moore@Sun.COM 	    SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
14670Sstevel@tonic-gate 		scsi_hba_tran_free(softp->hba_tran);
14680Sstevel@tonic-gate 		softp->hba_tran = NULL;
14690Sstevel@tonic-gate 		return (DDI_FAILURE);
14700Sstevel@tonic-gate 	} else {
14710Sstevel@tonic-gate 		return (DDI_SUCCESS);
14720Sstevel@tonic-gate 	}
14730Sstevel@tonic-gate }
14740Sstevel@tonic-gate 
14750Sstevel@tonic-gate /*ARGSUSED*/
14760Sstevel@tonic-gate static int
14770Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
14780Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd)
14790Sstevel@tonic-gate {
14800Sstevel@tonic-gate 	struct amr_softs	*softs;
14810Sstevel@tonic-gate 	ushort_t		target = sd->sd_address.a_target;
14820Sstevel@tonic-gate 	uchar_t			lun = sd->sd_address.a_lun;
14830Sstevel@tonic-gate 
14840Sstevel@tonic-gate 	softs = (struct amr_softs *)
1485*7656SSherry.Moore@Sun.COM 	    (sd->sd_address.a_hba_tran->tran_hba_private);
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 	if ((lun == 0) && (target < AMR_MAXLD))
14880Sstevel@tonic-gate 		if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE)
14890Sstevel@tonic-gate 			return (DDI_SUCCESS);
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	return (DDI_FAILURE);
14920Sstevel@tonic-gate }
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate static int
14950Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
14960Sstevel@tonic-gate {
14970Sstevel@tonic-gate 	struct amr_softs	*softs;
14980Sstevel@tonic-gate 	struct buf		*bp = NULL;
14990Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
15000Sstevel@tonic-gate 	int			ret;
15010Sstevel@tonic-gate 	uint32_t		capacity;
15020Sstevel@tonic-gate 	struct amr_command	*ac;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d",
1505*7656SSherry.Moore@Sun.COM 	    cdbp->scc_cmd, ap->a_target, ap->a_lun));
15060Sstevel@tonic-gate 
15070Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
15080Sstevel@tonic-gate 	if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) ||
1509*7656SSherry.Moore@Sun.COM 	    (softs->logic_drive[ap->a_target].al_state ==
1510*7656SSherry.Moore@Sun.COM 	    AMR_LDRV_OFFLINE)) {
15110Sstevel@tonic-gate 		cmn_err(CE_WARN, "target or lun is not correct!");
15120Sstevel@tonic-gate 		ret = TRAN_BADPKT;
15130Sstevel@tonic-gate 		return (ret);
15140Sstevel@tonic-gate 	}
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	ac = (struct amr_command *)pkt->pkt_ha_private;
15170Sstevel@tonic-gate 	bp = ac->ac_buf;
15180Sstevel@tonic-gate 
15190Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd));
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	switch (cdbp->scc_cmd) {
15220Sstevel@tonic-gate 	case SCMD_READ:		/* read		*/
15230Sstevel@tonic-gate 	case SCMD_READ_G1:	/* read	g1	*/
15240Sstevel@tonic-gate 	case SCMD_READ_BUFFER:	/* read buffer	*/
15250Sstevel@tonic-gate 	case SCMD_WRITE:	/* write	*/
15260Sstevel@tonic-gate 	case SCMD_WRITE_G1:	/* write g1	*/
15270Sstevel@tonic-gate 	case SCMD_WRITE_BUFFER:	/* write buffer	*/
15280Sstevel@tonic-gate 		amr_rw_command(softs, pkt, ap->a_target);
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 		if (pkt->pkt_flags & FLAG_NOINTR) {
15310Sstevel@tonic-gate 			(void) amr_poll_command(ac);
15320Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
1533*7656SSherry.Moore@Sun.COM 			    | STATE_GOT_TARGET
1534*7656SSherry.Moore@Sun.COM 			    | STATE_SENT_CMD
1535*7656SSherry.Moore@Sun.COM 			    | STATE_XFERRED_DATA);
15360Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
15370Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_SYNC;
15380Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
15390Sstevel@tonic-gate 		} else {
15400Sstevel@tonic-gate 			mutex_enter(&softs->queue_mutex);
15410Sstevel@tonic-gate 			if (softs->waiting_q_head == NULL) {
15420Sstevel@tonic-gate 				ac->ac_prev = NULL;
15430Sstevel@tonic-gate 				ac->ac_next = NULL;
15440Sstevel@tonic-gate 				softs->waiting_q_head = ac;
15450Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15460Sstevel@tonic-gate 			} else {
15470Sstevel@tonic-gate 				ac->ac_next = NULL;
15480Sstevel@tonic-gate 				ac->ac_prev = softs->waiting_q_tail;
15490Sstevel@tonic-gate 				softs->waiting_q_tail->ac_next = ac;
15500Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15510Sstevel@tonic-gate 			}
15520Sstevel@tonic-gate 			mutex_exit(&softs->queue_mutex);
15530Sstevel@tonic-gate 			amr_start_waiting_queue((void *)softs);
15540Sstevel@tonic-gate 		}
15550Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
15560Sstevel@tonic-gate 		break;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	case SCMD_INQUIRY: /* inquiry */
15590Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
15600Sstevel@tonic-gate 			struct scsi_inquiry inqp;
15610Sstevel@tonic-gate 			uint8_t *sinq_p = (uint8_t *)&inqp;
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 			bzero(&inqp, sizeof (struct scsi_inquiry));
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 			if (((char *)cdbp)[1] || ((char *)cdbp)[2]) {
15660Sstevel@tonic-gate 				/*
15670Sstevel@tonic-gate 				 * The EVDP and pagecode is
15680Sstevel@tonic-gate 				 * not supported
15690Sstevel@tonic-gate 				 */
15700Sstevel@tonic-gate 				sinq_p[1] = 0xFF;
15710Sstevel@tonic-gate 				sinq_p[2] = 0x0;
15720Sstevel@tonic-gate 			} else {
15730Sstevel@tonic-gate 				inqp.inq_len = AMR_INQ_ADDITIONAL_LEN;
15740Sstevel@tonic-gate 				inqp.inq_ansi = AMR_INQ_ANSI_VER;
15750Sstevel@tonic-gate 				inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT;
15763495Syw161884 				/* Enable Tag Queue */
15773495Syw161884 				inqp.inq_cmdque = 1;
15780Sstevel@tonic-gate 				bcopy("MegaRaid", inqp.inq_vid,
1579*7656SSherry.Moore@Sun.COM 				    sizeof (inqp.inq_vid));
15800Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_product_name,
1581*7656SSherry.Moore@Sun.COM 				    inqp.inq_pid,
1582*7656SSherry.Moore@Sun.COM 				    AMR_PRODUCT_INFO_SIZE);
15830Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_firmware_ver,
1584*7656SSherry.Moore@Sun.COM 				    inqp.inq_revision,
1585*7656SSherry.Moore@Sun.COM 				    AMR_FIRMWARE_VER_SIZE);
15860Sstevel@tonic-gate 			}
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 			amr_unmapcmd(ac);
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
15910Sstevel@tonic-gate 				bp_mapin(bp);
15920Sstevel@tonic-gate 			bcopy(&inqp, bp->b_un.b_addr,
1593*7656SSherry.Moore@Sun.COM 			    sizeof (struct scsi_inquiry));
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
15960Sstevel@tonic-gate 		}
15970Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
15980Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
1599*7656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
1600*7656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD);
16010Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16020Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16030Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16040Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16050Sstevel@tonic-gate 		break;
16060Sstevel@tonic-gate 
16070Sstevel@tonic-gate 	case SCMD_READ_CAPACITY: /* read capacity */
16080Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16090Sstevel@tonic-gate 			struct scsi_capacity cp;
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 			capacity = softs->logic_drive[ap->a_target].al_size - 1;
16120Sstevel@tonic-gate 			cp.capacity = BE_32(capacity);
16130Sstevel@tonic-gate 			cp.lbasize = BE_32(512);
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 			amr_unmapcmd(ac);
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16180Sstevel@tonic-gate 				bp_mapin(bp);
16190Sstevel@tonic-gate 			bcopy(&cp, bp->b_un.b_addr, 8);
16200Sstevel@tonic-gate 		}
16210Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16220Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
1623*7656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
1624*7656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD
1625*7656SSherry.Moore@Sun.COM 		    | STATE_XFERRED_DATA);
16260Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16270Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16280Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16290Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16300Sstevel@tonic-gate 		break;
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	case SCMD_MODE_SENSE:		/* mode sense */
16330Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:	/* mode sense g1 */
16340Sstevel@tonic-gate 		amr_unmapcmd(ac);
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 		capacity = softs->logic_drive[ap->a_target].al_size - 1;
16370Sstevel@tonic-gate 		amr_mode_sense(cdbp, bp, capacity);
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16400Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
1641*7656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
1642*7656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD
1643*7656SSherry.Moore@Sun.COM 		    | STATE_XFERRED_DATA);
16440Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16450Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16460Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16470Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16480Sstevel@tonic-gate 		break;
16490Sstevel@tonic-gate 
16500Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:	/* test unit ready */
16510Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:	/* request sense */
16520Sstevel@tonic-gate 	case SCMD_FORMAT:		/* format */
16530Sstevel@tonic-gate 	case SCMD_START_STOP:		/* start stop */
16540Sstevel@tonic-gate 	case SCMD_SYNCHRONIZE_CACHE:	/* synchronize cache */
16550Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16560Sstevel@tonic-gate 			amr_unmapcmd(ac);
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16590Sstevel@tonic-gate 				bp_mapin(bp);
16600Sstevel@tonic-gate 			bzero(bp->b_un.b_addr, bp->b_bcount);
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
16630Sstevel@tonic-gate 		}
16640Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16650Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
1666*7656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
1667*7656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD);
16680Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16690Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16700Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16710Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16720Sstevel@tonic-gate 		break;
16730Sstevel@tonic-gate 
16740Sstevel@tonic-gate 	default: /* any other commands */
16750Sstevel@tonic-gate 		amr_unmapcmd(ac);
16760Sstevel@tonic-gate 		pkt->pkt_reason = CMD_INCOMPLETE;
16770Sstevel@tonic-gate 		pkt->pkt_state = (STATE_GOT_BUS
1678*7656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
1679*7656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD
1680*7656SSherry.Moore@Sun.COM 		    | STATE_GOT_STATUS
1681*7656SSherry.Moore@Sun.COM 		    | STATE_ARQ_DONE);
16820Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16830Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16840Sstevel@tonic-gate 		amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
16850Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16860Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
16870Sstevel@tonic-gate 		break;
16880Sstevel@tonic-gate 	}
16890Sstevel@tonic-gate 
16900Sstevel@tonic-gate 	return (ret);
16910Sstevel@tonic-gate }
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate /*
16940Sstevel@tonic-gate  * tran_reset() will reset the bus/target/adapter to support the fault recovery
16950Sstevel@tonic-gate  * functionality according to the "level" in interface. However, we got the
16960Sstevel@tonic-gate  * confirmation from LSI that these HBA cards does not support any commands to
16970Sstevel@tonic-gate  * reset bus/target/adapter/channel.
16980Sstevel@tonic-gate  *
16990Sstevel@tonic-gate  * If the tran_reset() return a FAILURE to the sd, the system will not
17000Sstevel@tonic-gate  * continue to dump the core. But core dump is an crucial method to analyze
17010Sstevel@tonic-gate  * problems in panic. Now we adopt a work around solution, that is to return
17020Sstevel@tonic-gate  * a fake SUCCESS to sd during panic, which will force the system continue
17030Sstevel@tonic-gate  * to dump core though the core may have problems in some situtation because
17040Sstevel@tonic-gate  * some on-the-fly commands will continue DMAing data to the memory.
17050Sstevel@tonic-gate  * In addition, the work around core dump method may not be performed
17060Sstevel@tonic-gate  * successfully if the panic is caused by the HBA itself. So the work around
17070Sstevel@tonic-gate  * solution is not a good example for the implementation of tran_reset(),
17080Sstevel@tonic-gate  * the most reasonable approach should send a reset command to the adapter.
17090Sstevel@tonic-gate  */
17100Sstevel@tonic-gate /*ARGSUSED*/
17110Sstevel@tonic-gate static int
17120Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level)
17130Sstevel@tonic-gate {
17140Sstevel@tonic-gate 	struct amr_softs	*softs;
17150Sstevel@tonic-gate 	volatile uint32_t	done_flag;
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 	if (ddi_in_panic()) {
17180Sstevel@tonic-gate 		softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 		/* Acknowledge the card if there are any significant commands */
17210Sstevel@tonic-gate 		while (softs->amr_busyslots > 0) {
17220Sstevel@tonic-gate 			AMR_DELAY((softs->mailbox->mb_busy == 0),
1723*7656SSherry.Moore@Sun.COM 			    AMR_RETRYCOUNT, done_flag);
17240Sstevel@tonic-gate 			if (!done_flag) {
17250Sstevel@tonic-gate 				/*
17260Sstevel@tonic-gate 				 * command not completed, indicate the
17270Sstevel@tonic-gate 				 * problem and continue get ac
17280Sstevel@tonic-gate 				 */
17290Sstevel@tonic-gate 				cmn_err(CE_WARN,
1730*7656SSherry.Moore@Sun.COM 				    "AMR command is not completed");
17310Sstevel@tonic-gate 				return (0);
17320Sstevel@tonic-gate 			}
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 			AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
17350Sstevel@tonic-gate 
17360Sstevel@tonic-gate 			/* wait for the acknowledge from hardware */
17370Sstevel@tonic-gate 			AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
1738*7656SSherry.Moore@Sun.COM 			    AMR_RETRYCOUNT, done_flag);
17390Sstevel@tonic-gate 			if (!done_flag) {
17400Sstevel@tonic-gate 				/*
17410Sstevel@tonic-gate 				 * command is not completed, return from the
17420Sstevel@tonic-gate 				 * current interrupt and wait for the next one
17430Sstevel@tonic-gate 				 */
17440Sstevel@tonic-gate 				cmn_err(CE_WARN, "No answer from the hardware");
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 				mutex_exit(&softs->cmd_mutex);
17470Sstevel@tonic-gate 				return (0);
17480Sstevel@tonic-gate 			}
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 			softs->amr_busyslots -= softs->mailbox->mb_nstatus;
17510Sstevel@tonic-gate 		}
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 		/* flush the controllor */
17540Sstevel@tonic-gate 		(void) amr_flush(softs);
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 		/*
17570Sstevel@tonic-gate 		 * If the system is in panic, the tran_reset() will return a
17580Sstevel@tonic-gate 		 * fake SUCCESS to sd, then the system would continue dump the
17590Sstevel@tonic-gate 		 * core by poll commands. This is a work around for dumping
17600Sstevel@tonic-gate 		 * core in panic.
17610Sstevel@tonic-gate 		 *
17620Sstevel@tonic-gate 		 * Note: Some on-the-fly command will continue DMAing data to
17630Sstevel@tonic-gate 		 *	 the memory when the core is dumping, which may cause
17640Sstevel@tonic-gate 		 *	 some flaws in the dumped core file, so a cmn_err()
17650Sstevel@tonic-gate 		 *	 will be printed out to warn users. However, for most
17660Sstevel@tonic-gate 		 *	 cases, the core file will be fine.
17670Sstevel@tonic-gate 		 */
17680Sstevel@tonic-gate 		cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver "
1769*7656SSherry.Moore@Sun.COM 		    "that doesn't support software reset. This "
1770*7656SSherry.Moore@Sun.COM 		    "means that memory being used by the HBA for "
1771*7656SSherry.Moore@Sun.COM 		    "DMA based reads could have been updated after "
1772*7656SSherry.Moore@Sun.COM 		    "we panic'd.");
17730Sstevel@tonic-gate 		return (1);
17740Sstevel@tonic-gate 	} else {
17750Sstevel@tonic-gate 		/* return failure to sd */
17760Sstevel@tonic-gate 		return (0);
17770Sstevel@tonic-gate 	}
17780Sstevel@tonic-gate }
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate /*ARGSUSED*/
17810Sstevel@tonic-gate static int
17820Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom)
17830Sstevel@tonic-gate {
17840Sstevel@tonic-gate 	struct amr_softs	*softs;
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	/*
17870Sstevel@tonic-gate 	 * We don't allow inquiring about capabilities for other targets
17880Sstevel@tonic-gate 	 */
17890Sstevel@tonic-gate 	if (cap == NULL || whom == 0)
17900Sstevel@tonic-gate 		return (-1);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 	softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private);
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
17950Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
17960Sstevel@tonic-gate 		return (1);
17970Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
17980Sstevel@tonic-gate 		return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS);
17990Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
18000Sstevel@tonic-gate 		return (AMR_DEFAULT_SECTORS);
18010Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18020Sstevel@tonic-gate 		/* number of sectors */
18030Sstevel@tonic-gate 		return (softs->logic_drive[ap->a_target].al_size);
18043495Syw161884 	case SCSI_CAP_UNTAGGED_QING:
18053495Syw161884 	case SCSI_CAP_TAGGED_QING:
18063495Syw161884 		return (1);
18070Sstevel@tonic-gate 	default:
18080Sstevel@tonic-gate 		return (-1);
18090Sstevel@tonic-gate 	}
18100Sstevel@tonic-gate }
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate /*ARGSUSED*/
18130Sstevel@tonic-gate static int
18140Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value,
18150Sstevel@tonic-gate 		int whom)
18160Sstevel@tonic-gate {
18170Sstevel@tonic-gate 	/*
18180Sstevel@tonic-gate 	 * We don't allow setting capabilities for other targets
18190Sstevel@tonic-gate 	 */
18200Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
18210Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,
1822*7656SSherry.Moore@Sun.COM 		    "Set Cap not supported, string = %s, whom=%d",
1823*7656SSherry.Moore@Sun.COM 		    cap, whom));
18240Sstevel@tonic-gate 		return (-1);
18250Sstevel@tonic-gate 	}
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
18280Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
18290Sstevel@tonic-gate 		return (1);
18300Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18310Sstevel@tonic-gate 		return (1);
18320Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
18330Sstevel@tonic-gate 		return (1);
18343495Syw161884 	case SCSI_CAP_UNTAGGED_QING:
18353495Syw161884 	case SCSI_CAP_TAGGED_QING:
18363495Syw161884 		return ((value == 1) ? 1 : 0);
18370Sstevel@tonic-gate 	default:
18380Sstevel@tonic-gate 		return (0);
18390Sstevel@tonic-gate 	}
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate static struct scsi_pkt *
18430Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap,
18440Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
18450Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
18460Sstevel@tonic-gate {
18470Sstevel@tonic-gate 	struct amr_softs	*softs;
18480Sstevel@tonic-gate 	struct amr_command	*ac;
18490Sstevel@tonic-gate 	uint32_t		slen;
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)||
1854*7656SSherry.Moore@Sun.COM 	    (softs->logic_drive[ap->a_target].al_state ==
1855*7656SSherry.Moore@Sun.COM 	    AMR_LDRV_OFFLINE)) {
18560Sstevel@tonic-gate 		return (NULL);
18570Sstevel@tonic-gate 	}
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	if (pkt == NULL) {
18600Sstevel@tonic-gate 		/* force auto request sense */
18610Sstevel@tonic-gate 		slen = MAX(statuslen, sizeof (struct scsi_arq_status));
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen,
1864*7656SSherry.Moore@Sun.COM 		    slen, tgtlen, sizeof (struct amr_command),
1865*7656SSherry.Moore@Sun.COM 		    callback, arg);
18660Sstevel@tonic-gate 		if (pkt == NULL) {
18670Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed"));
18680Sstevel@tonic-gate 			return (NULL);
18690Sstevel@tonic-gate 		}
18700Sstevel@tonic-gate 		pkt->pkt_address	= *ap;
18710Sstevel@tonic-gate 		pkt->pkt_comp		= (void (*)())NULL;
18720Sstevel@tonic-gate 		pkt->pkt_time		= 0;
18730Sstevel@tonic-gate 		pkt->pkt_resid		= 0;
18740Sstevel@tonic-gate 		pkt->pkt_statistics	= 0;
18750Sstevel@tonic-gate 		pkt->pkt_reason		= 0;
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
18780Sstevel@tonic-gate 		ac->ac_buf = bp;
18790Sstevel@tonic-gate 		ac->cmdlen = cmdlen;
18800Sstevel@tonic-gate 		ac->ac_softs = softs;
18810Sstevel@tonic-gate 		ac->pkt = pkt;
18820Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
18830Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_BUSY;
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
18860Sstevel@tonic-gate 			return (pkt);
18870Sstevel@tonic-gate 		}
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr,
1890*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP, NULL,
1891*7656SSherry.Moore@Sun.COM 		    &ac->buffer_dma_handle) != DDI_SUCCESS) {
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
1894*7656SSherry.Moore@Sun.COM 			    "Cannot allocate buffer DMA tag"));
18950Sstevel@tonic-gate 			scsi_hba_pkt_free(ap, pkt);
18960Sstevel@tonic-gate 			return (NULL);
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 		}
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 	} else {
19010Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
19020Sstevel@tonic-gate 			return (pkt);
19030Sstevel@tonic-gate 		}
19040Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
19050Sstevel@tonic-gate 	}
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	ASSERT(ac != NULL);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	if (bp->b_flags & B_READ) {
19100Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAOUT;
19110Sstevel@tonic-gate 	} else {
19120Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAIN;
19130Sstevel@tonic-gate 	}
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 	if (flags & PKT_CONSISTENT) {
19160Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_CONSISTENT;
19170Sstevel@tonic-gate 	}
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 	if (flags & PKT_DMA_PARTIAL) {
19200Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL;
19210Sstevel@tonic-gate 	}
19220Sstevel@tonic-gate 
19233495Syw161884 	if (amr_mapcmd(ac, callback, arg) != DDI_SUCCESS) {
19240Sstevel@tonic-gate 		scsi_hba_pkt_free(ap, pkt);
19250Sstevel@tonic-gate 		return (NULL);
19260Sstevel@tonic-gate 	}
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	pkt->pkt_resid = bp->b_bcount - ac->data_transfered;
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE,
1931*7656SSherry.Moore@Sun.COM 	    "init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d",
1932*7656SSherry.Moore@Sun.COM 	    (uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount,
1933*7656SSherry.Moore@Sun.COM 	    ac->data_transfered));
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	ASSERT(pkt->pkt_resid >= 0);
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 	return (pkt);
19380Sstevel@tonic-gate }
19390Sstevel@tonic-gate 
19400Sstevel@tonic-gate static void
19410Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19420Sstevel@tonic-gate {
19430Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	amr_unmapcmd(ac);
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19480Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19490Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19500Sstevel@tonic-gate 	}
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
19530Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Destroy pkt called"));
19540Sstevel@tonic-gate }
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate /*ARGSUSED*/
19570Sstevel@tonic-gate static void
19580Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19590Sstevel@tonic-gate {
19600Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19630Sstevel@tonic-gate 		(void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0,
1964*7656SSherry.Moore@Sun.COM 		    (ac->ac_flags & AMR_CMD_DATAIN) ?
1965*7656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
19660Sstevel@tonic-gate 	}
19670Sstevel@tonic-gate }
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate /*ARGSUSED*/
19700Sstevel@tonic-gate static void
19710Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
19720Sstevel@tonic-gate {
19730Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_MAPPED) {
19760Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
19770Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19780Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19790Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_MAPPED;
19800Sstevel@tonic-gate 	}
19810Sstevel@tonic-gate 
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate /*ARGSUSED*/
19850Sstevel@tonic-gate static void
19860Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target)
19870Sstevel@tonic-gate {
19880Sstevel@tonic-gate 	struct amr_command	*ac = (struct amr_command *)pkt->pkt_ha_private;
19890Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
19900Sstevel@tonic-gate 	uint8_t			cmd;
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
19930Sstevel@tonic-gate 		cmd = AMR_CMD_LREAD;
19940Sstevel@tonic-gate 	} else {
19950Sstevel@tonic-gate 		cmd = AMR_CMD_LWRITE;
19960Sstevel@tonic-gate 	}
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 	ac->mailbox.mb_command = cmd;
19990Sstevel@tonic-gate 	ac->mailbox.mb_blkcount =
2000*7656SSherry.Moore@Sun.COM 	    (ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE;
20010Sstevel@tonic-gate 	ac->mailbox.mb_lba = (ac->cmdlen == 10) ?
2002*7656SSherry.Moore@Sun.COM 	    GETG1ADDR(cdbp) : GETG0ADDR(cdbp);
20030Sstevel@tonic-gate 	ac->mailbox.mb_drive = (uint8_t)target;
20040Sstevel@tonic-gate }
20050Sstevel@tonic-gate 
20060Sstevel@tonic-gate static void
20070Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity)
20080Sstevel@tonic-gate {
20090Sstevel@tonic-gate 	uchar_t			pagecode;
20100Sstevel@tonic-gate 	struct mode_format	*page3p;
20110Sstevel@tonic-gate 	struct mode_geometry	*page4p;
20120Sstevel@tonic-gate 	struct mode_header	*headerp;
20130Sstevel@tonic-gate 	uint32_t		ncyl;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
20160Sstevel@tonic-gate 		return;
20170Sstevel@tonic-gate 
20180Sstevel@tonic-gate 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
20190Sstevel@tonic-gate 		bp_mapin(bp);
20200Sstevel@tonic-gate 
20210Sstevel@tonic-gate 	pagecode = cdbp->cdb_un.sg.scsi[0];
20220Sstevel@tonic-gate 	switch (pagecode) {
20230Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE3_CODE:
20240Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20250Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20260Sstevel@tonic-gate 
20270Sstevel@tonic-gate 		page3p = (struct mode_format *)((caddr_t)headerp +
2028*7656SSherry.Moore@Sun.COM 		    MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20290Sstevel@tonic-gate 		page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE);
20300Sstevel@tonic-gate 		page3p->mode_page.length = BE_8(sizeof (struct mode_format));
20310Sstevel@tonic-gate 		page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS);
20320Sstevel@tonic-gate 		page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS);
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 		return;
20350Sstevel@tonic-gate 
20360Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE4_CODE:
20370Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20380Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 		page4p = (struct mode_geometry *)((caddr_t)headerp +
2041*7656SSherry.Moore@Sun.COM 		    MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20420Sstevel@tonic-gate 		page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE);
20430Sstevel@tonic-gate 		page4p->mode_page.length = BE_8(sizeof (struct mode_geometry));
20440Sstevel@tonic-gate 		page4p->heads = BE_8(AMR_DEFAULT_HEADS);
20450Sstevel@tonic-gate 		page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS);
20460Sstevel@tonic-gate 
20470Sstevel@tonic-gate 		ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS);
20480Sstevel@tonic-gate 		page4p->cyl_lb = BE_8(ncyl & 0xff);
20490Sstevel@tonic-gate 		page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff);
20500Sstevel@tonic-gate 		page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff);
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 		return;
20530Sstevel@tonic-gate 	default:
20540Sstevel@tonic-gate 		bzero(bp->b_un.b_addr, bp->b_bcount);
20550Sstevel@tonic-gate 		return;
20560Sstevel@tonic-gate 	}
20570Sstevel@tonic-gate }
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate static void
20600Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
20610Sstevel@tonic-gate {
20620Sstevel@tonic-gate 	struct scsi_arq_status *arqstat;
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 	arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp);
20650Sstevel@tonic-gate 	arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
20660Sstevel@tonic-gate 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
20670Sstevel@tonic-gate 	arqstat->sts_rqpkt_resid = 0;
20680Sstevel@tonic-gate 	arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
2069*7656SSherry.Moore@Sun.COM 	    STATE_SENT_CMD | STATE_XFERRED_DATA;
20700Sstevel@tonic-gate 	arqstat->sts_rqpkt_statistics = 0;
20710Sstevel@tonic-gate 	arqstat->sts_sensedata.es_valid = 1;
20720Sstevel@tonic-gate 	arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
20730Sstevel@tonic-gate 	arqstat->sts_sensedata.es_key = key;
20740Sstevel@tonic-gate }
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate static void
20770Sstevel@tonic-gate amr_start_waiting_queue(void *softp)
20780Sstevel@tonic-gate {
20790Sstevel@tonic-gate 	uint32_t		slot;
20800Sstevel@tonic-gate 	struct amr_command	*ac;
20810Sstevel@tonic-gate 	volatile uint32_t	done_flag;
20820Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)softp;
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	/* only one command allowed at the same time */
20850Sstevel@tonic-gate 	mutex_enter(&softs->queue_mutex);
20860Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	while ((ac = softs->waiting_q_head) != NULL) {
20890Sstevel@tonic-gate 		/*
20900Sstevel@tonic-gate 		 * Find an available slot, the last slot is
20910Sstevel@tonic-gate 		 * occupied by poll I/O command.
20920Sstevel@tonic-gate 		 */
20930Sstevel@tonic-gate 		for (slot = 0; slot < (softs->sg_max_count - 1); slot++) {
20940Sstevel@tonic-gate 			if (softs->busycmd[slot] == NULL) {
20950Sstevel@tonic-gate 				if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) {
20960Sstevel@tonic-gate 					/*
20970Sstevel@tonic-gate 					 * only one command allowed at the
20980Sstevel@tonic-gate 					 * same time
20990Sstevel@tonic-gate 					 */
21000Sstevel@tonic-gate 					mutex_exit(&softs->cmd_mutex);
21010Sstevel@tonic-gate 					mutex_exit(&softs->queue_mutex);
21020Sstevel@tonic-gate 					return;
21030Sstevel@tonic-gate 				}
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate 				ac->ac_timestamp = ddi_get_time();
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 				if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) {
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate 					softs->busycmd[slot] = ac;
21100Sstevel@tonic-gate 					ac->ac_slot = slot;
21110Sstevel@tonic-gate 					softs->amr_busyslots++;
21120Sstevel@tonic-gate 
21130Sstevel@tonic-gate 					bcopy(ac->sgtable,
2114*7656SSherry.Moore@Sun.COM 					    softs->sg_items[slot].sg_table,
2115*7656SSherry.Moore@Sun.COM 					    sizeof (struct amr_sgentry) *
2116*7656SSherry.Moore@Sun.COM 					    AMR_NSEG);
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 					(void) ddi_dma_sync(
2119*7656SSherry.Moore@Sun.COM 					    softs->sg_items[slot].sg_handle,
2120*7656SSherry.Moore@Sun.COM 					    0, 0, DDI_DMA_SYNC_FORDEV);
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 					ac->mailbox.mb_physaddr =
2123*7656SSherry.Moore@Sun.COM 					    softs->sg_items[slot].sg_phyaddr;
21240Sstevel@tonic-gate 				}
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 				/* take the cmd from the queue */
21270Sstevel@tonic-gate 				softs->waiting_q_head = ac->ac_next;
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 				ac->mailbox.mb_ident = ac->ac_slot + 1;
21300Sstevel@tonic-gate 				ac->mailbox.mb_busy = 1;
21310Sstevel@tonic-gate 				ac->ac_next = NULL;
21320Sstevel@tonic-gate 				ac->ac_prev = NULL;
21330Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_GOT_SLOT;
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 				/* clear the poll/ack fields in the mailbox */
21360Sstevel@tonic-gate 				softs->mailbox->mb_poll = 0;
21370Sstevel@tonic-gate 				softs->mailbox->mb_ack = 0;
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 				AMR_DELAY((softs->mailbox->mb_busy == 0),
2140*7656SSherry.Moore@Sun.COM 				    AMR_RETRYCOUNT, done_flag);
21410Sstevel@tonic-gate 				if (!done_flag) {
21420Sstevel@tonic-gate 					/*
21430Sstevel@tonic-gate 					 * command not completed, indicate the
21440Sstevel@tonic-gate 					 * problem and continue get ac
21450Sstevel@tonic-gate 					 */
21460Sstevel@tonic-gate 					cmn_err(CE_WARN,
2147*7656SSherry.Moore@Sun.COM 					    "AMR command is not completed");
21480Sstevel@tonic-gate 					break;
21490Sstevel@tonic-gate 				}
21500Sstevel@tonic-gate 
21510Sstevel@tonic-gate 				bcopy(&ac->mailbox, (void *)softs->mailbox,
2152*7656SSherry.Moore@Sun.COM 				    AMR_MBOX_CMDSIZE);
21530Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_BUSY;
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 				(void) ddi_dma_sync(softs->mbox_dma_handle,
2156*7656SSherry.Moore@Sun.COM 				    0, 0, DDI_DMA_SYNC_FORDEV);
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 				AMR_QPUT_IDB(softs,
2159*7656SSherry.Moore@Sun.COM 				    softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 				/*
21620Sstevel@tonic-gate 				 * current ac is submitted
21630Sstevel@tonic-gate 				 * so quit 'for-loop' to get next ac
21640Sstevel@tonic-gate 				 */
21650Sstevel@tonic-gate 				break;
21660Sstevel@tonic-gate 			}
21670Sstevel@tonic-gate 		}
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 		/* no slot, finish our task */
21700Sstevel@tonic-gate 		if (slot == softs->maxio)
21710Sstevel@tonic-gate 			break;
21720Sstevel@tonic-gate 	}
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	/* only one command allowed at the same time */
21750Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
21760Sstevel@tonic-gate 	mutex_exit(&softs->queue_mutex);
21770Sstevel@tonic-gate }
21780Sstevel@tonic-gate 
21790Sstevel@tonic-gate static void
21800Sstevel@tonic-gate amr_done(struct amr_softs *softs)
21810Sstevel@tonic-gate {
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 	uint32_t		i, idx;
21840Sstevel@tonic-gate 	volatile uint32_t	done_flag;
21850Sstevel@tonic-gate 	struct amr_mailbox	*mbox, mbsave;
21860Sstevel@tonic-gate 	struct amr_command	*ac, *head, *tail;
21870Sstevel@tonic-gate 
21880Sstevel@tonic-gate 	head = tail = NULL;
21890Sstevel@tonic-gate 
21900Sstevel@tonic-gate 	AMR_QPUT_ODB(softs, AMR_QODB_READY);
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 	/* acknowledge interrupt */
21930Sstevel@tonic-gate 	(void) AMR_QGET_ODB(softs);
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 	if (softs->mailbox->mb_nstatus != 0) {
21980Sstevel@tonic-gate 		(void) ddi_dma_sync(softs->mbox_dma_handle,
2199*7656SSherry.Moore@Sun.COM 		    0, 0, DDI_DMA_SYNC_FORCPU);
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 		/* save mailbox, which contains a list of completed commands */
22020Sstevel@tonic-gate 		bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox,
2203*7656SSherry.Moore@Sun.COM 		    &mbsave, sizeof (mbsave));
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 		mbox = &mbsave;
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 		AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
22080Sstevel@tonic-gate 
22090Sstevel@tonic-gate 		/* wait for the acknowledge from hardware */
22100Sstevel@tonic-gate 		AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
2211*7656SSherry.Moore@Sun.COM 		    AMR_RETRYCOUNT, done_flag);
22120Sstevel@tonic-gate 		if (!done_flag) {
22130Sstevel@tonic-gate 			/*
22140Sstevel@tonic-gate 			 * command is not completed, return from the current
22150Sstevel@tonic-gate 			 * interrupt and wait for the next one
22160Sstevel@tonic-gate 			 */
22170Sstevel@tonic-gate 			cmn_err(CE_WARN, "No answer from the hardware");
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
22200Sstevel@tonic-gate 			return;
22210Sstevel@tonic-gate 		}
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 		for (i = 0; i < mbox->mb_nstatus; i++) {
22240Sstevel@tonic-gate 			idx = mbox->mb_completed[i] - 1;
22250Sstevel@tonic-gate 			ac = softs->busycmd[idx];
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 			if (ac != NULL) {
22280Sstevel@tonic-gate 				/* pull the command from the busy index */
22290Sstevel@tonic-gate 				softs->busycmd[idx] = NULL;
22300Sstevel@tonic-gate 				if (softs->amr_busyslots > 0)
22310Sstevel@tonic-gate 					softs->amr_busyslots--;
22320Sstevel@tonic-gate 				if (softs->amr_busyslots == 0)
22330Sstevel@tonic-gate 					cv_broadcast(&softs->cmd_cv);
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_BUSY;
22360Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
22370Sstevel@tonic-gate 				ac->ac_status = mbox->mb_status;
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 				/* enqueue here */
22400Sstevel@tonic-gate 				if (head) {
22410Sstevel@tonic-gate 					tail->ac_next = ac;
22420Sstevel@tonic-gate 					tail = ac;
22430Sstevel@tonic-gate 					tail->ac_next = NULL;
22440Sstevel@tonic-gate 				} else {
22450Sstevel@tonic-gate 					tail = head = ac;
22460Sstevel@tonic-gate 					ac->ac_next = NULL;
22470Sstevel@tonic-gate 				}
22480Sstevel@tonic-gate 			} else {
22490Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
2250*7656SSherry.Moore@Sun.COM 				    "ac in mailbox is NULL!"));
22510Sstevel@tonic-gate 			}
22520Sstevel@tonic-gate 		}
22530Sstevel@tonic-gate 	} else {
22540Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!"));
22550Sstevel@tonic-gate 	}
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
22580Sstevel@tonic-gate 
22590Sstevel@tonic-gate 	if (head != NULL) {
22600Sstevel@tonic-gate 		amr_call_pkt_comp(head);
22610Sstevel@tonic-gate 	}
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	/* dispatch a thread to process the pending I/O if there is any */
22640Sstevel@tonic-gate 	if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue,
2265*7656SSherry.Moore@Sun.COM 	    (void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) {
22660Sstevel@tonic-gate 		cmn_err(CE_WARN, "No memory available to dispatch taskq");
22670Sstevel@tonic-gate 	}
22680Sstevel@tonic-gate }
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate static void
22710Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head)
22720Sstevel@tonic-gate {
22730Sstevel@tonic-gate 	register struct scsi_pkt	*pkt;
22740Sstevel@tonic-gate 	register struct amr_command	*ac, *localhead;
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	localhead = head;
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 	while (localhead) {
22790Sstevel@tonic-gate 		ac = localhead;
22800Sstevel@tonic-gate 		localhead = ac->ac_next;
22810Sstevel@tonic-gate 		ac->ac_next = NULL;
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 		pkt = ac->pkt;
22840Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
22850Sstevel@tonic-gate 
22860Sstevel@tonic-gate 		if (ac->ac_status == AMR_STATUS_SUCCESS) {
22870Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
2288*7656SSherry.Moore@Sun.COM 			    | STATE_GOT_TARGET
2289*7656SSherry.Moore@Sun.COM 			    | STATE_SENT_CMD
2290*7656SSherry.Moore@Sun.COM 			    | STATE_XFERRED_DATA);
22910Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
22920Sstevel@tonic-gate 		} else {
22930Sstevel@tonic-gate 			pkt->pkt_state |= STATE_GOT_BUS
2294*7656SSherry.Moore@Sun.COM 			    | STATE_ARQ_DONE;
22950Sstevel@tonic-gate 			pkt->pkt_reason = CMD_INCOMPLETE;
22960Sstevel@tonic-gate 			amr_set_arq_data(pkt, KEY_HARDWARE_ERROR);
22970Sstevel@tonic-gate 		}
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR) &&
2300*7656SSherry.Moore@Sun.COM 		    pkt->pkt_comp) {
23010Sstevel@tonic-gate 			(*pkt->pkt_comp)(pkt);
23020Sstevel@tonic-gate 		}
23030Sstevel@tonic-gate 	}
23040Sstevel@tonic-gate }
2305