xref: /onnv-gate/usr/src/uts/intel/io/amr/amr.c (revision 9106:ee8f18cdafb2)
10Sstevel@tonic-gate /*
2*9106SSrivijitha.Dugganapalli@Sun.COM  * Copyright 2009 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 */
2267656SSherry.Moore@Sun.COM 	0,		/* power */
2277656SSherry.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
_init(void)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,
2607656SSherry.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
_info(struct modinfo * modinfop)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
_fini(void)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
amr_attach(dev_info_t * dev,ddi_attach_cmd_t cmd)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",
3397656SSherry.Moore@Sun.COM 	    (void *)softs, (void *)&(softs->amr_busyslots)));
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	if (pci_config_setup(dev, &(softs->pciconfig_handle))
3427656SSherry.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,
3487656SSherry.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,
3717656SSherry.Moore@Sun.COM 		    PCI_CONF_COMM, command);
3720Sstevel@tonic-gate 		command = pci_config_get16(softs->pciconfig_handle,
3737656SSherry.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) {
3827656SSherry.Moore@Sun.COM 		AMRDB_PRINT((CE_NOTE,
3837656SSherry.Moore@Sun.COM 		    "High level interrupt is not supported!"));
3847656SSherry.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)
3887656SSherry.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,
3937656SSherry.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",
4247656SSherry.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,
4307656SSherry.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,
4457656SSherry.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.",
4517656SSherry.Moore@Sun.COM 	    softs->amr_product_info.pi_product_name,
4527656SSherry.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(
4687656SSherry.Moore@Sun.COM 			    softs->sg_items[i].sg_handle);
4690Sstevel@tonic-gate 			(void) ddi_dma_mem_free(
4707656SSherry.Moore@Sun.COM 			    &((softs->sg_items[i]).sg_acc_handle));
4710Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
4727656SSherry.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*/
amr_detach(dev_info_t * dev,ddi_detach_cmd_t cmd)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(
5297656SSherry.Moore@Sun.COM 		    softs->sg_items[i].sg_handle);
5300Sstevel@tonic-gate 		(void) ddi_dma_mem_free(
5317656SSherry.Moore@Sun.COM 		    &((softs->sg_items[i]).sg_acc_handle));
5320Sstevel@tonic-gate 		(void) ddi_dma_free_handle(
5337656SSherry.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.",
5637656SSherry.Moore@Sun.COM 	    softs->amr_product_info.pi_product_name,
5647656SSherry.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*/
amr_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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
amr_intr(caddr_t arg)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
amr_setup_mbox(struct amr_softs * softs)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(
6357656SSherry.Moore@Sun.COM 	    softs->dev_info_p,
6367656SSherry.Moore@Sun.COM 	    &addr_dma_attr,
6377656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
6387656SSherry.Moore@Sun.COM 	    NULL,
6397656SSherry.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(
6457656SSherry.Moore@Sun.COM 	    softs->mbox_dma_handle,
6467656SSherry.Moore@Sun.COM 	    sizeof (struct amr_mailbox) + 16,
6477656SSherry.Moore@Sun.COM 	    &accattr,
6487656SSherry.Moore@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6497656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
6507656SSherry.Moore@Sun.COM 	    NULL,
6517656SSherry.Moore@Sun.COM 	    (caddr_t *)(&softs->mbox),
6527656SSherry.Moore@Sun.COM 	    &mbox_len,
6537656SSherry.Moore@Sun.COM 	    &softs->mbox_acc_handle) !=
6547656SSherry.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(
6617656SSherry.Moore@Sun.COM 	    softs->mbox_dma_handle,
6627656SSherry.Moore@Sun.COM 	    NULL,
6637656SSherry.Moore@Sun.COM 	    (caddr_t)softs->mbox,
6647656SSherry.Moore@Sun.COM 	    mbox_len,
6657656SSherry.Moore@Sun.COM 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6667656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
6677656SSherry.Moore@Sun.COM 	    NULL,
6687656SSherry.Moore@Sun.COM 	    &softs->mbox_dma_cookie,
6697656SSherry.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 =
6817656SSherry.Moore@Sun.COM 	    (softs->mbox_dma_cookie.dmac_address + move);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	softs->mailbox =
6847656SSherry.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",
6877656SSherry.Moore@Sun.COM 	    softs->mbox_phyaddr, (void *)softs->mailbox,
6887656SSherry.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
amr_periodic(void * data)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) &&
7327656SSherry.Moore@Sun.COM 		    (ddi_get_time() -
7337656SSherry.Moore@Sun.COM 		    softs->busycmd[i]->ac_timestamp >
7347656SSherry.Moore@Sun.COM 		    pkt->pkt_time)) {
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 			cmn_err(CE_WARN,
7377656SSherry.Moore@Sun.COM 			    "!timed out packet detected,\
7380Sstevel@tonic-gate 				sc = %p, pkt = %p, index = %d, ac = %p",
7397656SSherry.Moore@Sun.COM 			    (void *)softs,
7407656SSherry.Moore@Sun.COM 			    (void *)pkt,
7417656SSherry.Moore@Sun.COM 			    i,
7427656SSherry.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;
760*9106SSrivijitha.Dugganapalli@Sun.COM 			if (!(pkt->pkt_flags & FLAG_NOINTR)) {
7610Sstevel@tonic-gate 				/* call pkt callback */
762*9106SSrivijitha.Dugganapalli@Sun.COM 				scsi_hba_pkt_comp(pkt);
7630Sstevel@tonic-gate 			}
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 		} else {
7660Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7670Sstevel@tonic-gate 		}
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	/* restart the amr timer */
7710Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
7720Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TIMEOUT_ENABLED)
7730Sstevel@tonic-gate 		softs->timeout_t = timeout(amr_periodic, (void *)softs,
7747656SSherry.Moore@Sun.COM 		    drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
7750Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate /*
7790Sstevel@tonic-gate  * Interrogate the controller for the operational parameters we require.
7800Sstevel@tonic-gate  */
7810Sstevel@tonic-gate static int
amr_query_controller(struct amr_softs * softs)7820Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	struct amr_enquiry3	*aex;
7850Sstevel@tonic-gate 	struct amr_prodinfo	*ap;
7860Sstevel@tonic-gate 	struct amr_enquiry	*ae;
7870Sstevel@tonic-gate 	uint32_t		ldrv;
7880Sstevel@tonic-gate 	int			instance;
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 	/*
7910Sstevel@tonic-gate 	 * If we haven't found the real limit yet, let us have a couple of
7920Sstevel@tonic-gate 	 * commands in order to be able to probe.
7930Sstevel@tonic-gate 	 */
7940Sstevel@tonic-gate 	if (softs->maxio == 0)
7950Sstevel@tonic-gate 		softs->maxio = 2;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	instance = ddi_get_instance(softs->dev_info_p);
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	/*
8000Sstevel@tonic-gate 	 * Try to issue an ENQUIRY3 command
8010Sstevel@tonic-gate 	 */
8020Sstevel@tonic-gate 	if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG,
8037656SSherry.Moore@Sun.COM 	    AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry"));
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 		for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
8087656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_size =
8097656SSherry.Moore@Sun.COM 			    aex->ae_drivesize[ldrv];
8107656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_state =
8117656SSherry.Moore@Sun.COM 			    aex->ae_drivestate[ldrv];
8127656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_properties =
8137656SSherry.Moore@Sun.COM 			    aex->ae_driveprop[ldrv];
8147656SSherry.Moore@Sun.COM 			AMRDB_PRINT((CE_NOTE,
8157656SSherry.Moore@Sun.COM 			    "  drive %d: size: %d state %x properties %x\n",
8167656SSherry.Moore@Sun.COM 			    ldrv,
8177656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_size,
8187656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_state,
8197656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_properties));
8200Sstevel@tonic-gate 
8217656SSherry.Moore@Sun.COM 			if (softs->logic_drive[ldrv].al_state ==
8227656SSherry.Moore@Sun.COM 			    AMR_LDRV_OFFLINE)
8237656SSherry.Moore@Sun.COM 				cmn_err(CE_NOTE,
8247656SSherry.Moore@Sun.COM 				    "!instance %d log-drive %d is offline",
8257656SSherry.Moore@Sun.COM 				    instance, ldrv);
8267656SSherry.Moore@Sun.COM 			else
8277656SSherry.Moore@Sun.COM 				softs->amr_nlogdrives++;
8280Sstevel@tonic-gate 		}
8290Sstevel@tonic-gate 		kmem_free(aex, AMR_ENQ_BUFFER_SIZE);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 		if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE,
8327656SSherry.Moore@Sun.COM 		    AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
8330Sstevel@tonic-gate 			AMRDB_PRINT((CE_NOTE,
8347656SSherry.Moore@Sun.COM 			    "Cannot obtain product data from controller"));
8350Sstevel@tonic-gate 			return (EIO);
8360Sstevel@tonic-gate 		}
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 		softs->maxdrives = AMR_40LD_MAXDRIVES;
8390Sstevel@tonic-gate 		softs->maxchan = ap->ap_nschan;
8400Sstevel@tonic-gate 		softs->maxio = ap->ap_maxio;
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 		bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver,
8437656SSherry.Moore@Sun.COM 		    AMR_FIRMWARE_VER_SIZE);
8440Sstevel@tonic-gate 		softs->amr_product_info.
8457656SSherry.Moore@Sun.COM 		    pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 		bcopy(ap->ap_product, softs->amr_product_info.pi_product_name,
8487656SSherry.Moore@Sun.COM 		    AMR_PRODUCT_INFO_SIZE);
8490Sstevel@tonic-gate 		softs->amr_product_info.
8507656SSherry.Moore@Sun.COM 		    pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0;
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 		kmem_free(ap, AMR_ENQ_BUFFER_SIZE);
8530Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio));
8540Sstevel@tonic-gate 	} else {
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry failed, \
8570Sstevel@tonic-gate 				so try another way"));
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 		/* failed, try the 8LD ENQUIRY commands */
8600Sstevel@tonic-gate 		if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
8617656SSherry.Moore@Sun.COM 		    AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0))
8627656SSherry.Moore@Sun.COM 		    == NULL) {
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 			if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
8657656SSherry.Moore@Sun.COM 			    AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0))
8667656SSherry.Moore@Sun.COM 			    == NULL) {
8670Sstevel@tonic-gate 				AMRDB_PRINT((CE_NOTE,
8687656SSherry.Moore@Sun.COM 				    "Cannot obtain configuration data"));
8690Sstevel@tonic-gate 				return (EIO);
8700Sstevel@tonic-gate 			}
8710Sstevel@tonic-gate 			ae->ae_signature = 0;
8720Sstevel@tonic-gate 		}
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		/*
8750Sstevel@tonic-gate 		 * Fetch current state of logical drives.
8760Sstevel@tonic-gate 		 */
8770Sstevel@tonic-gate 		for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
8787656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_size =
8797656SSherry.Moore@Sun.COM 			    ae->ae_ldrv.al_size[ldrv];
8807656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_state =
8817656SSherry.Moore@Sun.COM 			    ae->ae_ldrv.al_state[ldrv];
8827656SSherry.Moore@Sun.COM 			softs->logic_drive[ldrv].al_properties =
8837656SSherry.Moore@Sun.COM 			    ae->ae_ldrv.al_properties[ldrv];
8847656SSherry.Moore@Sun.COM 			AMRDB_PRINT((CE_NOTE,
8857656SSherry.Moore@Sun.COM 			    " ********* drive %d: %d state %x properties %x",
8867656SSherry.Moore@Sun.COM 			    ldrv,
8877656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_size,
8887656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_state,
8897656SSherry.Moore@Sun.COM 			    softs->logic_drive[ldrv].al_properties));
8900Sstevel@tonic-gate 
8917656SSherry.Moore@Sun.COM 			if (softs->logic_drive[ldrv].al_state ==
8927656SSherry.Moore@Sun.COM 			    AMR_LDRV_OFFLINE)
8937656SSherry.Moore@Sun.COM 				cmn_err(CE_NOTE,
8947656SSherry.Moore@Sun.COM 				    "!instance %d log-drive %d is offline",
8957656SSherry.Moore@Sun.COM 				    instance, ldrv);
8967656SSherry.Moore@Sun.COM 			else
8977656SSherry.Moore@Sun.COM 				softs->amr_nlogdrives++;
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 		softs->maxdrives = AMR_8LD_MAXDRIVES;
9010Sstevel@tonic-gate 		softs->maxchan = ae->ae_adapter.aa_channels;
9020Sstevel@tonic-gate 		softs->maxio = ae->ae_adapter.aa_maxio;
9030Sstevel@tonic-gate 		kmem_free(ae, AMR_ENQ_BUFFER_SIZE);
9040Sstevel@tonic-gate 	}
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	/*
9070Sstevel@tonic-gate 	 * Mark remaining drives as unused.
9080Sstevel@tonic-gate 	 */
9090Sstevel@tonic-gate 	for (; ldrv < AMR_MAXLD; ldrv++)
9100Sstevel@tonic-gate 		softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	/*
9130Sstevel@tonic-gate 	 * Cap the maximum number of outstanding I/Os.  AMI's driver
9140Sstevel@tonic-gate 	 * doesn't trust the controller's reported value, and lockups have
9150Sstevel@tonic-gate 	 * been seen when we do.
9160Sstevel@tonic-gate 	 */
9170Sstevel@tonic-gate 	softs->maxio = MIN(softs->maxio, AMR_LIMITCMD);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	return (DDI_SUCCESS);
9200Sstevel@tonic-gate }
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate /*
9230Sstevel@tonic-gate  * Run a generic enquiry-style command.
9240Sstevel@tonic-gate  */
9250Sstevel@tonic-gate static void *
amr_enquiry(struct amr_softs * softs,size_t bufsize,uint8_t cmd,uint8_t cmdsub,uint8_t cmdqual)9260Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd,
9270Sstevel@tonic-gate 				uint8_t cmdsub, uint8_t cmdqual)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	struct amr_command	ac;
9300Sstevel@tonic-gate 	void			*result;
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	result = NULL;
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9350Sstevel@tonic-gate 	ac.ac_softs = softs;
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	/* set command flags */
9380Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9390Sstevel@tonic-gate 
9400Sstevel@tonic-gate 	/* build the command proper */
9410Sstevel@tonic-gate 	ac.mailbox.mb_command	= cmd;
9420Sstevel@tonic-gate 	ac.mailbox.mb_cmdsub	= cmdsub;
9430Sstevel@tonic-gate 	ac.mailbox.mb_cmdqual	= cmdqual;
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS)
9460Sstevel@tonic-gate 		return (NULL);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	if (amr_poll_command(&ac) || ac.ac_status != 0) {
9490Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll command, goto out"));
9500Sstevel@tonic-gate 		amr_enquiry_unmapcmd(&ac);
9510Sstevel@tonic-gate 		return (NULL);
9520Sstevel@tonic-gate 	}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	/* allocate the response structure */
9550Sstevel@tonic-gate 	result = kmem_zalloc(bufsize, KM_SLEEP);
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 	bcopy(ac.ac_data, result, bufsize);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	amr_enquiry_unmapcmd(&ac);
9600Sstevel@tonic-gate 	return (result);
9610Sstevel@tonic-gate }
9620Sstevel@tonic-gate 
9630Sstevel@tonic-gate /*
9640Sstevel@tonic-gate  * Flush the controller's internal cache, return status.
9650Sstevel@tonic-gate  */
9660Sstevel@tonic-gate static int
amr_flush(struct amr_softs * softs)9670Sstevel@tonic-gate amr_flush(struct amr_softs *softs)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate 	struct amr_command	ac;
9700Sstevel@tonic-gate 	int			error = 0;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9730Sstevel@tonic-gate 	ac.ac_softs = softs;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	/* build the command proper */
9780Sstevel@tonic-gate 	ac.mailbox.mb_command = AMR_CMD_FLUSH;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	/* have to poll, as the system may be going down or otherwise damaged */
9810Sstevel@tonic-gate 	if (error = amr_poll_command(&ac)) {
9820Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll this cmd"));
9830Sstevel@tonic-gate 		return (error);
9840Sstevel@tonic-gate 	}
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	return (error);
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate /*
9900Sstevel@tonic-gate  * Take a command, submit it to the controller and wait for it to return.
9910Sstevel@tonic-gate  * Returns nonzero on error.  Can be safely called with interrupts enabled.
9920Sstevel@tonic-gate  */
9930Sstevel@tonic-gate static int
amr_poll_command(struct amr_command * ac)9940Sstevel@tonic-gate amr_poll_command(struct amr_command *ac)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
9970Sstevel@tonic-gate 	volatile uint32_t	done_flag;
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)",
10007656SSherry.Moore@Sun.COM 	    (void *)&ac->mailbox,
10017656SSherry.Moore@Sun.COM 	    (void *)softs->mailbox,
10027656SSherry.Moore@Sun.COM 	    (uint32_t)AMR_MBOX_CMDSIZE));
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	while (softs->amr_busyslots != 0)
10070Sstevel@tonic-gate 		cv_wait(&softs->cmd_cv, &softs->cmd_mutex);
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	/*
10100Sstevel@tonic-gate 	 * For read/write commands, the scatter/gather table should be
10110Sstevel@tonic-gate 	 * filled, and the last entry in scatter/gather table will be used.
10120Sstevel@tonic-gate 	 */
10130Sstevel@tonic-gate 	if ((ac->mailbox.mb_command == AMR_CMD_LREAD) ||
10140Sstevel@tonic-gate 	    (ac->mailbox.mb_command == AMR_CMD_LWRITE)) {
10150Sstevel@tonic-gate 		bcopy(ac->sgtable,
10167656SSherry.Moore@Sun.COM 		    softs->sg_items[softs->sg_max_count - 1].sg_table,
10177656SSherry.Moore@Sun.COM 		    sizeof (struct amr_sgentry) * AMR_NSEG);
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 		(void) ddi_dma_sync(
10207656SSherry.Moore@Sun.COM 		    softs->sg_items[softs->sg_max_count - 1].sg_handle,
10217656SSherry.Moore@Sun.COM 		    0, 0, DDI_DMA_SYNC_FORDEV);
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 		ac->mailbox.mb_physaddr =
10247656SSherry.Moore@Sun.COM 		    softs->sg_items[softs->sg_max_count - 1].sg_phyaddr;
10250Sstevel@tonic-gate 	}
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	/* sync the dma memory */
10300Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	/* clear the poll/ack fields in the mailbox */
10330Sstevel@tonic-gate 	softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID;
10340Sstevel@tonic-gate 	softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS;
10350Sstevel@tonic-gate 	softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS;
10360Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10370Sstevel@tonic-gate 	softs->mailbox->mb_ack = 0;
10380Sstevel@tonic-gate 	softs->mailbox->mb_busy = 1;
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	/* sync the dma memory */
10430Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS),
10467656SSherry.Moore@Sun.COM 	    1000, done_flag);
10470Sstevel@tonic-gate 	if (!done_flag) {
10480Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10490Sstevel@tonic-gate 		return (1);
10500Sstevel@tonic-gate 	}
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	ac->ac_status = softs->mailbox->mb_status;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag);
10550Sstevel@tonic-gate 	if (!done_flag) {
10560Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10570Sstevel@tonic-gate 		return (1);
10580Sstevel@tonic-gate 	}
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10610Sstevel@tonic-gate 	softs->mailbox->mb_ack = AMR_POLL_ACK;
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	/* acknowledge that we have the commands */
10640Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate 	AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag);
10670Sstevel@tonic-gate 	if (!done_flag) {
10680Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10690Sstevel@tonic-gate 		return (1);
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
10730Sstevel@tonic-gate 	return (ac->ac_status != AMR_STATUS_SUCCESS);
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate /*
10770Sstevel@tonic-gate  * setup the scatter/gather table
10780Sstevel@tonic-gate  */
10790Sstevel@tonic-gate static int
amr_setup_sg(struct amr_softs * softs)10800Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs)
10810Sstevel@tonic-gate {
10820Sstevel@tonic-gate 	uint32_t		i;
10830Sstevel@tonic-gate 	size_t			len;
10840Sstevel@tonic-gate 	ddi_dma_cookie_t	cookie;
10850Sstevel@tonic-gate 	uint_t			cookien;
10860Sstevel@tonic-gate 
10870Sstevel@tonic-gate 	softs->sg_max_count = 0;
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	for (i = 0; i < AMR_MAXCMD; i++) {
10900Sstevel@tonic-gate 
10910Sstevel@tonic-gate 		/* reset the cookien */
10920Sstevel@tonic-gate 		cookien = 0;
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
10950Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(
10967656SSherry.Moore@Sun.COM 		    softs->dev_info_p,
10977656SSherry.Moore@Sun.COM 		    &addr_dma_attr,
10987656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP,
10997656SSherry.Moore@Sun.COM 		    NULL,
11007656SSherry.Moore@Sun.COM 		    &((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) {
11010Sstevel@tonic-gate 
11020Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11030Sstevel@tonic-gate 			"Cannot alloc dma handle for s/g table"));
11040Sstevel@tonic-gate 			goto error_out;
11050Sstevel@tonic-gate 		}
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 		if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle,
11087656SSherry.Moore@Sun.COM 		    sizeof (struct amr_sgentry) * AMR_NSEG,
11097656SSherry.Moore@Sun.COM 		    &accattr,
11107656SSherry.Moore@Sun.COM 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
11117656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP, NULL,
11127656SSherry.Moore@Sun.COM 		    (caddr_t *)(&(softs->sg_items[i]).sg_table),
11137656SSherry.Moore@Sun.COM 		    &len,
11147656SSherry.Moore@Sun.COM 		    &(softs->sg_items[i]).sg_acc_handle)
11157656SSherry.Moore@Sun.COM 		    != DDI_SUCCESS) {
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11180Sstevel@tonic-gate 			"Cannot allocate DMA memory"));
11190Sstevel@tonic-gate 			goto error_out;
11200Sstevel@tonic-gate 		}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(
11237656SSherry.Moore@Sun.COM 		    (softs->sg_items[i]).sg_handle,
11247656SSherry.Moore@Sun.COM 		    NULL,
11257656SSherry.Moore@Sun.COM 		    (caddr_t)((softs->sg_items[i]).sg_table),
11267656SSherry.Moore@Sun.COM 		    len,
11277656SSherry.Moore@Sun.COM 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
11287656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP,
11297656SSherry.Moore@Sun.COM 		    NULL,
11307656SSherry.Moore@Sun.COM 		    &cookie,
11317656SSherry.Moore@Sun.COM 		    &cookien) != DDI_DMA_MAPPED) {
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11340Sstevel@tonic-gate 			"Cannot bind communication area for s/g table"));
11350Sstevel@tonic-gate 			goto error_out;
11360Sstevel@tonic-gate 		}
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 		if (cookien != 1)
11390Sstevel@tonic-gate 			goto error_out;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 		softs->sg_items[i].sg_phyaddr = cookie.dmac_address;
11420Sstevel@tonic-gate 		softs->sg_max_count++;
11430Sstevel@tonic-gate 	}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	return (DDI_SUCCESS);
11460Sstevel@tonic-gate 
11470Sstevel@tonic-gate error_out:
11480Sstevel@tonic-gate 	/*
11490Sstevel@tonic-gate 	 * Couldn't allocate/initialize all of the sg table entries.
11500Sstevel@tonic-gate 	 * Clean up the partially-initialized entry before returning.
11510Sstevel@tonic-gate 	 */
11520Sstevel@tonic-gate 	if (cookien) {
11530Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle);
11540Sstevel@tonic-gate 	}
11550Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_acc_handle) {
11560Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle));
11570Sstevel@tonic-gate 		(softs->sg_items[i]).sg_acc_handle = NULL;
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_handle) {
11600Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle));
11610Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
11620Sstevel@tonic-gate 	}
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	/*
11650Sstevel@tonic-gate 	 * At least two sg table entries are needed. One is for regular data
11660Sstevel@tonic-gate 	 * I/O commands, the other is for poll I/O commands.
11670Sstevel@tonic-gate 	 */
11680Sstevel@tonic-gate 	return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE);
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /*
11720Sstevel@tonic-gate  * Map/unmap (ac)'s data in the controller's addressable space as required.
11730Sstevel@tonic-gate  *
11740Sstevel@tonic-gate  * These functions may be safely called multiple times on a given command.
11750Sstevel@tonic-gate  */
11760Sstevel@tonic-gate static void
amr_setup_dmamap(struct amr_command * ac,ddi_dma_cookie_t * buffer_dma_cookiep,int nsegments)11770Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep,
11780Sstevel@tonic-gate 		int nsegments)
11790Sstevel@tonic-gate {
11800Sstevel@tonic-gate 	struct amr_sgentry	*sg;
11810Sstevel@tonic-gate 	uint32_t		i, size;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	sg = ac->sgtable;
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate 	size = 0;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = (uint8_t)nsegments;
11880Sstevel@tonic-gate 	for (i = 0; i < nsegments; i++, sg++) {
11890Sstevel@tonic-gate 		sg->sg_addr = buffer_dma_cookiep->dmac_address;
11900Sstevel@tonic-gate 		sg->sg_count = buffer_dma_cookiep->dmac_size;
11910Sstevel@tonic-gate 		size += sg->sg_count;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 		/*
11940Sstevel@tonic-gate 		 * There is no next cookie if the end of the current
11950Sstevel@tonic-gate 		 * window is reached. Otherwise, the next cookie
11960Sstevel@tonic-gate 		 * would be found.
11970Sstevel@tonic-gate 		 */
11980Sstevel@tonic-gate 		if ((ac->current_cookie + i + 1) != ac->num_of_cookie)
11990Sstevel@tonic-gate 			ddi_dma_nextcookie(ac->buffer_dma_handle,
12007656SSherry.Moore@Sun.COM 			    buffer_dma_cookiep);
12010Sstevel@tonic-gate 	}
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	ac->transfer_size = size;
12040Sstevel@tonic-gate 	ac->data_transfered += size;
12050Sstevel@tonic-gate }
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate  * map the amr command for enquiry, allocate the DMA resource
12100Sstevel@tonic-gate  */
12110Sstevel@tonic-gate static int
amr_enquiry_mapcmd(struct amr_command * ac,uint32_t data_size)12120Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size)
12130Sstevel@tonic-gate {
12140Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
12150Sstevel@tonic-gate 	size_t			len;
12160Sstevel@tonic-gate 	uint_t			dma_flags;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x",
12197656SSherry.Moore@Sun.COM 	    (void *)ac, ac->ac_flags));
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
12220Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
12230Sstevel@tonic-gate 	} else {
12240Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
12250Sstevel@tonic-gate 	}
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	dma_flags |= DDI_DMA_CONSISTENT;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	/* process the DMA by address bind mode */
12300Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(softs->dev_info_p,
12317656SSherry.Moore@Sun.COM 	    &addr_dma_attr, DDI_DMA_SLEEP, NULL,
12327656SSherry.Moore@Sun.COM 	    &ac->buffer_dma_handle) !=
12337656SSherry.Moore@Sun.COM 	    DDI_SUCCESS) {
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12360Sstevel@tonic-gate 		"Cannot allocate addr DMA tag"));
12370Sstevel@tonic-gate 		goto error_out;
12380Sstevel@tonic-gate 	}
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ac->buffer_dma_handle,
12417656SSherry.Moore@Sun.COM 	    data_size,
12427656SSherry.Moore@Sun.COM 	    &accattr,
12437656SSherry.Moore@Sun.COM 	    dma_flags,
12447656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP,
12457656SSherry.Moore@Sun.COM 	    NULL,
12467656SSherry.Moore@Sun.COM 	    (caddr_t *)&ac->ac_data,
12477656SSherry.Moore@Sun.COM 	    &len,
12487656SSherry.Moore@Sun.COM 	    &ac->buffer_acc_handle) !=
12497656SSherry.Moore@Sun.COM 	    DDI_SUCCESS) {
12500Sstevel@tonic-gate 
12510Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12520Sstevel@tonic-gate 		"Cannot allocate DMA memory"));
12530Sstevel@tonic-gate 		goto error_out;
12540Sstevel@tonic-gate 	}
12550Sstevel@tonic-gate 
12560Sstevel@tonic-gate 	if ((ddi_dma_addr_bind_handle(
12577656SSherry.Moore@Sun.COM 	    ac->buffer_dma_handle,
12587656SSherry.Moore@Sun.COM 	    NULL, ac->ac_data, len, dma_flags,
12597656SSherry.Moore@Sun.COM 	    DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie,
12607656SSherry.Moore@Sun.COM 	    &ac->num_of_cookie)) != DDI_DMA_MAPPED) {
12610Sstevel@tonic-gate 
12620Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12637656SSherry.Moore@Sun.COM 		    "Cannot bind addr for dma"));
12640Sstevel@tonic-gate 		goto error_out;
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address;
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0;
12700Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = 0;
12710Sstevel@tonic-gate 	ac->mailbox.mb_physaddr = ac->ac_dataphys;
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	ac->ac_flags |= AMR_CMD_MAPPED;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	return (DDI_SUCCESS);
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate error_out:
12780Sstevel@tonic-gate 	if (ac->num_of_cookie)
12790Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
12800Sstevel@tonic-gate 	if (ac->buffer_acc_handle) {
12810Sstevel@tonic-gate 		ddi_dma_mem_free(&ac->buffer_acc_handle);
12820Sstevel@tonic-gate 		ac->buffer_acc_handle = NULL;
12830Sstevel@tonic-gate 	}
12840Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
12850Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
12860Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
12870Sstevel@tonic-gate 	}
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	return (DDI_FAILURE);
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate /*
12930Sstevel@tonic-gate  * unmap the amr command for enquiry, free the DMA resource
12940Sstevel@tonic-gate  */
12950Sstevel@tonic-gate static void
amr_enquiry_unmapcmd(struct amr_command * ac)12960Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac)
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p",
12997656SSherry.Moore@Sun.COM 	    (void *)ac));
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
13020Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) {
13030Sstevel@tonic-gate 		if (ac->buffer_dma_handle)
13040Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
13057656SSherry.Moore@Sun.COM 			    ac->buffer_dma_handle);
13060Sstevel@tonic-gate 		if (ac->buffer_acc_handle) {
13070Sstevel@tonic-gate 			ddi_dma_mem_free(&ac->buffer_acc_handle);
13080Sstevel@tonic-gate 			ac->buffer_acc_handle = NULL;
13090Sstevel@tonic-gate 		}
13100Sstevel@tonic-gate 		if (ac->buffer_dma_handle) {
13110Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
13127656SSherry.Moore@Sun.COM 			    &ac->buffer_dma_handle);
13130Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13140Sstevel@tonic-gate 		}
13150Sstevel@tonic-gate 	}
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
13180Sstevel@tonic-gate }
13190Sstevel@tonic-gate 
13200Sstevel@tonic-gate /*
13210Sstevel@tonic-gate  * map the amr command, allocate the DMA resource
13220Sstevel@tonic-gate  */
13230Sstevel@tonic-gate static int
amr_mapcmd(struct amr_command * ac,int (* callback)(),caddr_t arg)13243495Syw161884 amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	uint_t	dma_flags;
13270Sstevel@tonic-gate 	off_t	off;
13280Sstevel@tonic-gate 	size_t	len;
13290Sstevel@tonic-gate 	int	error;
13303495Syw161884 	int	(*cb)(caddr_t);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x",
13337656SSherry.Moore@Sun.COM 	    (void *)ac, ac->ac_flags));
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
13360Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
13370Sstevel@tonic-gate 	} else {
13380Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
13390Sstevel@tonic-gate 	}
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) {
13420Sstevel@tonic-gate 		dma_flags |= DDI_DMA_CONSISTENT;
13430Sstevel@tonic-gate 	}
13440Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) {
13450Sstevel@tonic-gate 		dma_flags |= DDI_DMA_PARTIAL;
13460Sstevel@tonic-gate 	}
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) {
13490Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
13500Sstevel@tonic-gate 		return (DDI_SUCCESS);
13510Sstevel@tonic-gate 	}
13520Sstevel@tonic-gate 
13533495Syw161884 	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
13543495Syw161884 
13550Sstevel@tonic-gate 	/* if the command involves data at all, and hasn't been mapped */
13560Sstevel@tonic-gate 	if (!(ac->ac_flags & AMR_CMD_MAPPED)) {
13570Sstevel@tonic-gate 		/* process the DMA by buffer bind mode */
13580Sstevel@tonic-gate 		error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle,
13597656SSherry.Moore@Sun.COM 		    ac->ac_buf,
13607656SSherry.Moore@Sun.COM 		    dma_flags,
13617656SSherry.Moore@Sun.COM 		    cb,
13627656SSherry.Moore@Sun.COM 		    arg,
13637656SSherry.Moore@Sun.COM 		    &ac->buffer_dma_cookie,
13647656SSherry.Moore@Sun.COM 		    &ac->num_of_cookie);
13650Sstevel@tonic-gate 		switch (error) {
13660Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
13670Sstevel@tonic-gate 			if (ddi_dma_numwin(ac->buffer_dma_handle,
13687656SSherry.Moore@Sun.COM 			    &ac->num_of_win) == DDI_FAILURE) {
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
13717656SSherry.Moore@Sun.COM 				    "Cannot get dma num win"));
13720Sstevel@tonic-gate 				(void) ddi_dma_unbind_handle(
13737656SSherry.Moore@Sun.COM 				    ac->buffer_dma_handle);
13740Sstevel@tonic-gate 				(void) ddi_dma_free_handle(
13757656SSherry.Moore@Sun.COM 				    &ac->buffer_dma_handle);
13760Sstevel@tonic-gate 				ac->buffer_dma_handle = NULL;
13770Sstevel@tonic-gate 				return (DDI_FAILURE);
13780Sstevel@tonic-gate 			}
13790Sstevel@tonic-gate 			ac->current_win = 0;
13800Sstevel@tonic-gate 			break;
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
13830Sstevel@tonic-gate 			ac->num_of_win = 1;
13840Sstevel@tonic-gate 			ac->current_win = 0;
13850Sstevel@tonic-gate 			break;
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 		default:
13880Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
13897656SSherry.Moore@Sun.COM 			    "Cannot bind buf for dma"));
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
13927656SSherry.Moore@Sun.COM 			    &ac->buffer_dma_handle);
13930Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13940Sstevel@tonic-gate 			return (DDI_FAILURE);
13950Sstevel@tonic-gate 		}
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate 		ac->current_cookie = 0;
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
14000Sstevel@tonic-gate 	} else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) {
14010Sstevel@tonic-gate 		/* get the next window */
14020Sstevel@tonic-gate 		ac->current_win++;
14030Sstevel@tonic-gate 		(void) ddi_dma_getwin(ac->buffer_dma_handle,
14047656SSherry.Moore@Sun.COM 		    ac->current_win, &off, &len,
14057656SSherry.Moore@Sun.COM 		    &ac->buffer_dma_cookie,
14067656SSherry.Moore@Sun.COM 		    &ac->num_of_cookie);
14070Sstevel@tonic-gate 		ac->current_cookie = 0;
14080Sstevel@tonic-gate 	}
14090Sstevel@tonic-gate 
14100Sstevel@tonic-gate 	if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) {
14110Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG);
14120Sstevel@tonic-gate 		ac->current_cookie += AMR_NSEG;
14130Sstevel@tonic-gate 	} else {
14140Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie,
14157656SSherry.Moore@Sun.COM 		    ac->num_of_cookie - ac->current_cookie);
14160Sstevel@tonic-gate 		ac->current_cookie = AMR_LAST_COOKIE_TAG;
14170Sstevel@tonic-gate 	}
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 	return (DDI_SUCCESS);
14200Sstevel@tonic-gate }
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate /*
14230Sstevel@tonic-gate  * unmap the amr command, free the DMA resource
14240Sstevel@tonic-gate  */
14250Sstevel@tonic-gate static void
amr_unmapcmd(struct amr_command * ac)14260Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac)
14270Sstevel@tonic-gate {
14280Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p",
14297656SSherry.Moore@Sun.COM 	    (void *)ac));
14300Sstevel@tonic-gate 
14310Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
14320Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) &&
14337656SSherry.Moore@Sun.COM 	    ac->ac_buf && ac->buffer_dma_handle)
14340Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate static int
amr_setup_tran(dev_info_t * dip,struct amr_softs * softp)14400Sstevel@tonic-gate amr_setup_tran(dev_info_t  *dip, struct amr_softs *softp)
14410Sstevel@tonic-gate {
14420Sstevel@tonic-gate 	softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	/*
14450Sstevel@tonic-gate 	 * hba_private always points to the amr_softs struct
14460Sstevel@tonic-gate 	 */
14470Sstevel@tonic-gate 	softp->hba_tran->tran_hba_private	= softp;
14480Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_init		= amr_tran_tgt_init;
14490Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_probe		= scsi_hba_probe;
14500Sstevel@tonic-gate 	softp->hba_tran->tran_start		= amr_tran_start;
14510Sstevel@tonic-gate 	softp->hba_tran->tran_reset		= amr_tran_reset;
14520Sstevel@tonic-gate 	softp->hba_tran->tran_getcap		= amr_tran_getcap;
14530Sstevel@tonic-gate 	softp->hba_tran->tran_setcap		= amr_tran_setcap;
14540Sstevel@tonic-gate 	softp->hba_tran->tran_init_pkt		= amr_tran_init_pkt;
14550Sstevel@tonic-gate 	softp->hba_tran->tran_destroy_pkt	= amr_tran_destroy_pkt;
14560Sstevel@tonic-gate 	softp->hba_tran->tran_dmafree		= amr_tran_dmafree;
14570Sstevel@tonic-gate 	softp->hba_tran->tran_sync_pkt		= amr_tran_sync_pkt;
14580Sstevel@tonic-gate 	softp->hba_tran->tran_abort		= NULL;
14590Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_free		= NULL;
14600Sstevel@tonic-gate 	softp->hba_tran->tran_quiesce		= NULL;
14610Sstevel@tonic-gate 	softp->hba_tran->tran_unquiesce		= NULL;
14620Sstevel@tonic-gate 	softp->hba_tran->tran_sd		= NULL;
14630Sstevel@tonic-gate 
14640Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran,
14657656SSherry.Moore@Sun.COM 	    SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
14660Sstevel@tonic-gate 		scsi_hba_tran_free(softp->hba_tran);
14670Sstevel@tonic-gate 		softp->hba_tran = NULL;
14680Sstevel@tonic-gate 		return (DDI_FAILURE);
14690Sstevel@tonic-gate 	} else {
14700Sstevel@tonic-gate 		return (DDI_SUCCESS);
14710Sstevel@tonic-gate 	}
14720Sstevel@tonic-gate }
14730Sstevel@tonic-gate 
14740Sstevel@tonic-gate /*ARGSUSED*/
14750Sstevel@tonic-gate static int
amr_tran_tgt_init(dev_info_t * hba_dip,dev_info_t * tgt_dip,scsi_hba_tran_t * tran,struct scsi_device * sd)14760Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
14770Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd)
14780Sstevel@tonic-gate {
14790Sstevel@tonic-gate 	struct amr_softs	*softs;
14800Sstevel@tonic-gate 	ushort_t		target = sd->sd_address.a_target;
14810Sstevel@tonic-gate 	uchar_t			lun = sd->sd_address.a_lun;
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	softs = (struct amr_softs *)
14847656SSherry.Moore@Sun.COM 	    (sd->sd_address.a_hba_tran->tran_hba_private);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	if ((lun == 0) && (target < AMR_MAXLD))
14870Sstevel@tonic-gate 		if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE)
14880Sstevel@tonic-gate 			return (DDI_SUCCESS);
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	return (DDI_FAILURE);
14910Sstevel@tonic-gate }
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate static int
amr_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)14940Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
14950Sstevel@tonic-gate {
14960Sstevel@tonic-gate 	struct amr_softs	*softs;
14970Sstevel@tonic-gate 	struct buf		*bp = NULL;
14980Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
14990Sstevel@tonic-gate 	int			ret;
15000Sstevel@tonic-gate 	uint32_t		capacity;
15010Sstevel@tonic-gate 	struct amr_command	*ac;
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d",
15047656SSherry.Moore@Sun.COM 	    cdbp->scc_cmd, ap->a_target, ap->a_lun));
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
15070Sstevel@tonic-gate 	if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) ||
15087656SSherry.Moore@Sun.COM 	    (softs->logic_drive[ap->a_target].al_state ==
15097656SSherry.Moore@Sun.COM 	    AMR_LDRV_OFFLINE)) {
15100Sstevel@tonic-gate 		cmn_err(CE_WARN, "target or lun is not correct!");
15110Sstevel@tonic-gate 		ret = TRAN_BADPKT;
15120Sstevel@tonic-gate 		return (ret);
15130Sstevel@tonic-gate 	}
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	ac = (struct amr_command *)pkt->pkt_ha_private;
15160Sstevel@tonic-gate 	bp = ac->ac_buf;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd));
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	switch (cdbp->scc_cmd) {
15210Sstevel@tonic-gate 	case SCMD_READ:		/* read		*/
15220Sstevel@tonic-gate 	case SCMD_READ_G1:	/* read	g1	*/
15230Sstevel@tonic-gate 	case SCMD_READ_BUFFER:	/* read buffer	*/
15240Sstevel@tonic-gate 	case SCMD_WRITE:	/* write	*/
15250Sstevel@tonic-gate 	case SCMD_WRITE_G1:	/* write g1	*/
15260Sstevel@tonic-gate 	case SCMD_WRITE_BUFFER:	/* write buffer	*/
15270Sstevel@tonic-gate 		amr_rw_command(softs, pkt, ap->a_target);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 		if (pkt->pkt_flags & FLAG_NOINTR) {
15300Sstevel@tonic-gate 			(void) amr_poll_command(ac);
15310Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
15327656SSherry.Moore@Sun.COM 			    | STATE_GOT_TARGET
15337656SSherry.Moore@Sun.COM 			    | STATE_SENT_CMD
15347656SSherry.Moore@Sun.COM 			    | STATE_XFERRED_DATA);
15350Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
15360Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_SYNC;
15370Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
15380Sstevel@tonic-gate 		} else {
15390Sstevel@tonic-gate 			mutex_enter(&softs->queue_mutex);
15400Sstevel@tonic-gate 			if (softs->waiting_q_head == NULL) {
15410Sstevel@tonic-gate 				ac->ac_prev = NULL;
15420Sstevel@tonic-gate 				ac->ac_next = NULL;
15430Sstevel@tonic-gate 				softs->waiting_q_head = ac;
15440Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15450Sstevel@tonic-gate 			} else {
15460Sstevel@tonic-gate 				ac->ac_next = NULL;
15470Sstevel@tonic-gate 				ac->ac_prev = softs->waiting_q_tail;
15480Sstevel@tonic-gate 				softs->waiting_q_tail->ac_next = ac;
15490Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15500Sstevel@tonic-gate 			}
15510Sstevel@tonic-gate 			mutex_exit(&softs->queue_mutex);
15520Sstevel@tonic-gate 			amr_start_waiting_queue((void *)softs);
15530Sstevel@tonic-gate 		}
15540Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
15550Sstevel@tonic-gate 		break;
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 	case SCMD_INQUIRY: /* inquiry */
15580Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
15590Sstevel@tonic-gate 			struct scsi_inquiry inqp;
15600Sstevel@tonic-gate 			uint8_t *sinq_p = (uint8_t *)&inqp;
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate 			bzero(&inqp, sizeof (struct scsi_inquiry));
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 			if (((char *)cdbp)[1] || ((char *)cdbp)[2]) {
15650Sstevel@tonic-gate 				/*
15660Sstevel@tonic-gate 				 * The EVDP and pagecode is
15670Sstevel@tonic-gate 				 * not supported
15680Sstevel@tonic-gate 				 */
15690Sstevel@tonic-gate 				sinq_p[1] = 0xFF;
15700Sstevel@tonic-gate 				sinq_p[2] = 0x0;
15710Sstevel@tonic-gate 			} else {
15720Sstevel@tonic-gate 				inqp.inq_len = AMR_INQ_ADDITIONAL_LEN;
15730Sstevel@tonic-gate 				inqp.inq_ansi = AMR_INQ_ANSI_VER;
15740Sstevel@tonic-gate 				inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT;
15753495Syw161884 				/* Enable Tag Queue */
15763495Syw161884 				inqp.inq_cmdque = 1;
15770Sstevel@tonic-gate 				bcopy("MegaRaid", inqp.inq_vid,
15787656SSherry.Moore@Sun.COM 				    sizeof (inqp.inq_vid));
15790Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_product_name,
15807656SSherry.Moore@Sun.COM 				    inqp.inq_pid,
15817656SSherry.Moore@Sun.COM 				    AMR_PRODUCT_INFO_SIZE);
15820Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_firmware_ver,
15837656SSherry.Moore@Sun.COM 				    inqp.inq_revision,
15847656SSherry.Moore@Sun.COM 				    AMR_FIRMWARE_VER_SIZE);
15850Sstevel@tonic-gate 			}
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 			amr_unmapcmd(ac);
15880Sstevel@tonic-gate 
15890Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
15900Sstevel@tonic-gate 				bp_mapin(bp);
15910Sstevel@tonic-gate 			bcopy(&inqp, bp->b_un.b_addr,
15927656SSherry.Moore@Sun.COM 			    sizeof (struct scsi_inquiry));
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
15950Sstevel@tonic-gate 		}
15960Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
15970Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
15987656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
15997656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD);
16000Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16010Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16020Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
1603*9106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
16040Sstevel@tonic-gate 		break;
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 	case SCMD_READ_CAPACITY: /* read capacity */
16070Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16080Sstevel@tonic-gate 			struct scsi_capacity cp;
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 			capacity = softs->logic_drive[ap->a_target].al_size - 1;
16110Sstevel@tonic-gate 			cp.capacity = BE_32(capacity);
16120Sstevel@tonic-gate 			cp.lbasize = BE_32(512);
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 			amr_unmapcmd(ac);
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16170Sstevel@tonic-gate 				bp_mapin(bp);
16180Sstevel@tonic-gate 			bcopy(&cp, bp->b_un.b_addr, 8);
16190Sstevel@tonic-gate 		}
16200Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16210Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16227656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
16237656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD
16247656SSherry.Moore@Sun.COM 		    | STATE_XFERRED_DATA);
16250Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16260Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16270Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
1628*9106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
16290Sstevel@tonic-gate 		break;
16300Sstevel@tonic-gate 
16310Sstevel@tonic-gate 	case SCMD_MODE_SENSE:		/* mode sense */
16320Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:	/* mode sense g1 */
16330Sstevel@tonic-gate 		amr_unmapcmd(ac);
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 		capacity = softs->logic_drive[ap->a_target].al_size - 1;
16360Sstevel@tonic-gate 		amr_mode_sense(cdbp, bp, capacity);
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16390Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16407656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
16417656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD
16427656SSherry.Moore@Sun.COM 		    | STATE_XFERRED_DATA);
16430Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16440Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16450Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
1646*9106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
16470Sstevel@tonic-gate 		break;
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:	/* test unit ready */
16500Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:	/* request sense */
16510Sstevel@tonic-gate 	case SCMD_FORMAT:		/* format */
16520Sstevel@tonic-gate 	case SCMD_START_STOP:		/* start stop */
16530Sstevel@tonic-gate 	case SCMD_SYNCHRONIZE_CACHE:	/* synchronize cache */
16540Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16550Sstevel@tonic-gate 			amr_unmapcmd(ac);
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16580Sstevel@tonic-gate 				bp_mapin(bp);
16590Sstevel@tonic-gate 			bzero(bp->b_un.b_addr, bp->b_bcount);
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
16620Sstevel@tonic-gate 		}
16630Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16640Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16657656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
16667656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD);
16670Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16680Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16690Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
1670*9106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
16710Sstevel@tonic-gate 		break;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	default: /* any other commands */
16740Sstevel@tonic-gate 		amr_unmapcmd(ac);
16750Sstevel@tonic-gate 		pkt->pkt_reason = CMD_INCOMPLETE;
16760Sstevel@tonic-gate 		pkt->pkt_state = (STATE_GOT_BUS
16777656SSherry.Moore@Sun.COM 		    | STATE_GOT_TARGET
16787656SSherry.Moore@Sun.COM 		    | STATE_SENT_CMD
16797656SSherry.Moore@Sun.COM 		    | STATE_GOT_STATUS
16807656SSherry.Moore@Sun.COM 		    | STATE_ARQ_DONE);
16810Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16820Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16830Sstevel@tonic-gate 		amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
16840Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
1685*9106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
16860Sstevel@tonic-gate 		break;
16870Sstevel@tonic-gate 	}
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 	return (ret);
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate /*
16930Sstevel@tonic-gate  * tran_reset() will reset the bus/target/adapter to support the fault recovery
16940Sstevel@tonic-gate  * functionality according to the "level" in interface. However, we got the
16950Sstevel@tonic-gate  * confirmation from LSI that these HBA cards does not support any commands to
16960Sstevel@tonic-gate  * reset bus/target/adapter/channel.
16970Sstevel@tonic-gate  *
16980Sstevel@tonic-gate  * If the tran_reset() return a FAILURE to the sd, the system will not
16990Sstevel@tonic-gate  * continue to dump the core. But core dump is an crucial method to analyze
17000Sstevel@tonic-gate  * problems in panic. Now we adopt a work around solution, that is to return
17010Sstevel@tonic-gate  * a fake SUCCESS to sd during panic, which will force the system continue
17020Sstevel@tonic-gate  * to dump core though the core may have problems in some situtation because
17030Sstevel@tonic-gate  * some on-the-fly commands will continue DMAing data to the memory.
17040Sstevel@tonic-gate  * In addition, the work around core dump method may not be performed
17050Sstevel@tonic-gate  * successfully if the panic is caused by the HBA itself. So the work around
17060Sstevel@tonic-gate  * solution is not a good example for the implementation of tran_reset(),
17070Sstevel@tonic-gate  * the most reasonable approach should send a reset command to the adapter.
17080Sstevel@tonic-gate  */
17090Sstevel@tonic-gate /*ARGSUSED*/
17100Sstevel@tonic-gate static int
amr_tran_reset(struct scsi_address * ap,int level)17110Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level)
17120Sstevel@tonic-gate {
17130Sstevel@tonic-gate 	struct amr_softs	*softs;
17140Sstevel@tonic-gate 	volatile uint32_t	done_flag;
17150Sstevel@tonic-gate 
17160Sstevel@tonic-gate 	if (ddi_in_panic()) {
17170Sstevel@tonic-gate 		softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
17180Sstevel@tonic-gate 
17190Sstevel@tonic-gate 		/* Acknowledge the card if there are any significant commands */
17200Sstevel@tonic-gate 		while (softs->amr_busyslots > 0) {
17210Sstevel@tonic-gate 			AMR_DELAY((softs->mailbox->mb_busy == 0),
17227656SSherry.Moore@Sun.COM 			    AMR_RETRYCOUNT, done_flag);
17230Sstevel@tonic-gate 			if (!done_flag) {
17240Sstevel@tonic-gate 				/*
17250Sstevel@tonic-gate 				 * command not completed, indicate the
17260Sstevel@tonic-gate 				 * problem and continue get ac
17270Sstevel@tonic-gate 				 */
17280Sstevel@tonic-gate 				cmn_err(CE_WARN,
17297656SSherry.Moore@Sun.COM 				    "AMR command is not completed");
17300Sstevel@tonic-gate 				return (0);
17310Sstevel@tonic-gate 			}
17320Sstevel@tonic-gate 
17330Sstevel@tonic-gate 			AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 			/* wait for the acknowledge from hardware */
17360Sstevel@tonic-gate 			AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
17377656SSherry.Moore@Sun.COM 			    AMR_RETRYCOUNT, done_flag);
17380Sstevel@tonic-gate 			if (!done_flag) {
17390Sstevel@tonic-gate 				/*
17400Sstevel@tonic-gate 				 * command is not completed, return from the
17410Sstevel@tonic-gate 				 * current interrupt and wait for the next one
17420Sstevel@tonic-gate 				 */
17430Sstevel@tonic-gate 				cmn_err(CE_WARN, "No answer from the hardware");
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 				mutex_exit(&softs->cmd_mutex);
17460Sstevel@tonic-gate 				return (0);
17470Sstevel@tonic-gate 			}
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 			softs->amr_busyslots -= softs->mailbox->mb_nstatus;
17500Sstevel@tonic-gate 		}
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 		/* flush the controllor */
17530Sstevel@tonic-gate 		(void) amr_flush(softs);
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 		/*
17560Sstevel@tonic-gate 		 * If the system is in panic, the tran_reset() will return a
17570Sstevel@tonic-gate 		 * fake SUCCESS to sd, then the system would continue dump the
17580Sstevel@tonic-gate 		 * core by poll commands. This is a work around for dumping
17590Sstevel@tonic-gate 		 * core in panic.
17600Sstevel@tonic-gate 		 *
17610Sstevel@tonic-gate 		 * Note: Some on-the-fly command will continue DMAing data to
17620Sstevel@tonic-gate 		 *	 the memory when the core is dumping, which may cause
17630Sstevel@tonic-gate 		 *	 some flaws in the dumped core file, so a cmn_err()
17640Sstevel@tonic-gate 		 *	 will be printed out to warn users. However, for most
17650Sstevel@tonic-gate 		 *	 cases, the core file will be fine.
17660Sstevel@tonic-gate 		 */
17670Sstevel@tonic-gate 		cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver "
17687656SSherry.Moore@Sun.COM 		    "that doesn't support software reset. This "
17697656SSherry.Moore@Sun.COM 		    "means that memory being used by the HBA for "
17707656SSherry.Moore@Sun.COM 		    "DMA based reads could have been updated after "
17717656SSherry.Moore@Sun.COM 		    "we panic'd.");
17720Sstevel@tonic-gate 		return (1);
17730Sstevel@tonic-gate 	} else {
17740Sstevel@tonic-gate 		/* return failure to sd */
17750Sstevel@tonic-gate 		return (0);
17760Sstevel@tonic-gate 	}
17770Sstevel@tonic-gate }
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate /*ARGSUSED*/
17800Sstevel@tonic-gate static int
amr_tran_getcap(struct scsi_address * ap,char * cap,int whom)17810Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom)
17820Sstevel@tonic-gate {
17830Sstevel@tonic-gate 	struct amr_softs	*softs;
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 	/*
17860Sstevel@tonic-gate 	 * We don't allow inquiring about capabilities for other targets
17870Sstevel@tonic-gate 	 */
17880Sstevel@tonic-gate 	if (cap == NULL || whom == 0)
17890Sstevel@tonic-gate 		return (-1);
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private);
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
17940Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
17950Sstevel@tonic-gate 		return (1);
17960Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
17970Sstevel@tonic-gate 		return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS);
17980Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
17990Sstevel@tonic-gate 		return (AMR_DEFAULT_SECTORS);
18000Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18010Sstevel@tonic-gate 		/* number of sectors */
18020Sstevel@tonic-gate 		return (softs->logic_drive[ap->a_target].al_size);
18033495Syw161884 	case SCSI_CAP_UNTAGGED_QING:
18043495Syw161884 	case SCSI_CAP_TAGGED_QING:
18053495Syw161884 		return (1);
18060Sstevel@tonic-gate 	default:
18070Sstevel@tonic-gate 		return (-1);
18080Sstevel@tonic-gate 	}
18090Sstevel@tonic-gate }
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate /*ARGSUSED*/
18120Sstevel@tonic-gate static int
amr_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)18130Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value,
18140Sstevel@tonic-gate 		int whom)
18150Sstevel@tonic-gate {
18160Sstevel@tonic-gate 	/*
18170Sstevel@tonic-gate 	 * We don't allow setting capabilities for other targets
18180Sstevel@tonic-gate 	 */
18190Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
18200Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,
18217656SSherry.Moore@Sun.COM 		    "Set Cap not supported, string = %s, whom=%d",
18227656SSherry.Moore@Sun.COM 		    cap, whom));
18230Sstevel@tonic-gate 		return (-1);
18240Sstevel@tonic-gate 	}
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
18270Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
18280Sstevel@tonic-gate 		return (1);
18290Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18300Sstevel@tonic-gate 		return (1);
18310Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
18320Sstevel@tonic-gate 		return (1);
18333495Syw161884 	case SCSI_CAP_UNTAGGED_QING:
18343495Syw161884 	case SCSI_CAP_TAGGED_QING:
18353495Syw161884 		return ((value == 1) ? 1 : 0);
18360Sstevel@tonic-gate 	default:
18370Sstevel@tonic-gate 		return (0);
18380Sstevel@tonic-gate 	}
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate static struct scsi_pkt *
amr_tran_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)18420Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap,
18430Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
18440Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
18450Sstevel@tonic-gate {
18460Sstevel@tonic-gate 	struct amr_softs	*softs;
18470Sstevel@tonic-gate 	struct amr_command	*ac;
18480Sstevel@tonic-gate 	uint32_t		slen;
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)||
18537656SSherry.Moore@Sun.COM 	    (softs->logic_drive[ap->a_target].al_state ==
18547656SSherry.Moore@Sun.COM 	    AMR_LDRV_OFFLINE)) {
18550Sstevel@tonic-gate 		return (NULL);
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 	if (pkt == NULL) {
18590Sstevel@tonic-gate 		/* force auto request sense */
18600Sstevel@tonic-gate 		slen = MAX(statuslen, sizeof (struct scsi_arq_status));
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen,
18637656SSherry.Moore@Sun.COM 		    slen, tgtlen, sizeof (struct amr_command),
18647656SSherry.Moore@Sun.COM 		    callback, arg);
18650Sstevel@tonic-gate 		if (pkt == NULL) {
18660Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed"));
18670Sstevel@tonic-gate 			return (NULL);
18680Sstevel@tonic-gate 		}
18690Sstevel@tonic-gate 		pkt->pkt_address	= *ap;
18700Sstevel@tonic-gate 		pkt->pkt_comp		= (void (*)())NULL;
18710Sstevel@tonic-gate 		pkt->pkt_time		= 0;
18720Sstevel@tonic-gate 		pkt->pkt_resid		= 0;
18730Sstevel@tonic-gate 		pkt->pkt_statistics	= 0;
18740Sstevel@tonic-gate 		pkt->pkt_reason		= 0;
18750Sstevel@tonic-gate 
18760Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
18770Sstevel@tonic-gate 		ac->ac_buf = bp;
18780Sstevel@tonic-gate 		ac->cmdlen = cmdlen;
18790Sstevel@tonic-gate 		ac->ac_softs = softs;
18800Sstevel@tonic-gate 		ac->pkt = pkt;
18810Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
18820Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_BUSY;
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
18850Sstevel@tonic-gate 			return (pkt);
18860Sstevel@tonic-gate 		}
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr,
18897656SSherry.Moore@Sun.COM 		    DDI_DMA_SLEEP, NULL,
18907656SSherry.Moore@Sun.COM 		    &ac->buffer_dma_handle) != DDI_SUCCESS) {
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
18937656SSherry.Moore@Sun.COM 			    "Cannot allocate buffer DMA tag"));
18940Sstevel@tonic-gate 			scsi_hba_pkt_free(ap, pkt);
18950Sstevel@tonic-gate 			return (NULL);
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 		}
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	} else {
19000Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
19010Sstevel@tonic-gate 			return (pkt);
19020Sstevel@tonic-gate 		}
19030Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
19040Sstevel@tonic-gate 	}
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 	ASSERT(ac != NULL);
19070Sstevel@tonic-gate 
19080Sstevel@tonic-gate 	if (bp->b_flags & B_READ) {
19090Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAOUT;
19100Sstevel@tonic-gate 	} else {
19110Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAIN;
19120Sstevel@tonic-gate 	}
19130Sstevel@tonic-gate 
19140Sstevel@tonic-gate 	if (flags & PKT_CONSISTENT) {
19150Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_CONSISTENT;
19160Sstevel@tonic-gate 	}
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	if (flags & PKT_DMA_PARTIAL) {
19190Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL;
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate 
19223495Syw161884 	if (amr_mapcmd(ac, callback, arg) != DDI_SUCCESS) {
19230Sstevel@tonic-gate 		scsi_hba_pkt_free(ap, pkt);
19240Sstevel@tonic-gate 		return (NULL);
19250Sstevel@tonic-gate 	}
19260Sstevel@tonic-gate 
19270Sstevel@tonic-gate 	pkt->pkt_resid = bp->b_bcount - ac->data_transfered;
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE,
19307656SSherry.Moore@Sun.COM 	    "init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d",
19317656SSherry.Moore@Sun.COM 	    (uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount,
19327656SSherry.Moore@Sun.COM 	    ac->data_transfered));
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	ASSERT(pkt->pkt_resid >= 0);
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	return (pkt);
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate static void
amr_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)19400Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19410Sstevel@tonic-gate {
19420Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	amr_unmapcmd(ac);
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19470Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19480Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19490Sstevel@tonic-gate 	}
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
19520Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Destroy pkt called"));
19530Sstevel@tonic-gate }
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate /*ARGSUSED*/
19560Sstevel@tonic-gate static void
amr_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)19570Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19580Sstevel@tonic-gate {
19590Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19620Sstevel@tonic-gate 		(void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0,
19637656SSherry.Moore@Sun.COM 		    (ac->ac_flags & AMR_CMD_DATAIN) ?
19647656SSherry.Moore@Sun.COM 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
19650Sstevel@tonic-gate 	}
19660Sstevel@tonic-gate }
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate /*ARGSUSED*/
19690Sstevel@tonic-gate static void
amr_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)19700Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
19710Sstevel@tonic-gate {
19720Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_MAPPED) {
19750Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
19760Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19770Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19780Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_MAPPED;
19790Sstevel@tonic-gate 	}
19800Sstevel@tonic-gate 
19810Sstevel@tonic-gate }
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate /*ARGSUSED*/
19840Sstevel@tonic-gate static void
amr_rw_command(struct amr_softs * softs,struct scsi_pkt * pkt,int target)19850Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target)
19860Sstevel@tonic-gate {
19870Sstevel@tonic-gate 	struct amr_command	*ac = (struct amr_command *)pkt->pkt_ha_private;
19880Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
19890Sstevel@tonic-gate 	uint8_t			cmd;
19900Sstevel@tonic-gate 
19910Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
19920Sstevel@tonic-gate 		cmd = AMR_CMD_LREAD;
19930Sstevel@tonic-gate 	} else {
19940Sstevel@tonic-gate 		cmd = AMR_CMD_LWRITE;
19950Sstevel@tonic-gate 	}
19960Sstevel@tonic-gate 
19970Sstevel@tonic-gate 	ac->mailbox.mb_command = cmd;
19980Sstevel@tonic-gate 	ac->mailbox.mb_blkcount =
19997656SSherry.Moore@Sun.COM 	    (ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE;
20000Sstevel@tonic-gate 	ac->mailbox.mb_lba = (ac->cmdlen == 10) ?
20017656SSherry.Moore@Sun.COM 	    GETG1ADDR(cdbp) : GETG0ADDR(cdbp);
20020Sstevel@tonic-gate 	ac->mailbox.mb_drive = (uint8_t)target;
20030Sstevel@tonic-gate }
20040Sstevel@tonic-gate 
20050Sstevel@tonic-gate static void
amr_mode_sense(union scsi_cdb * cdbp,struct buf * bp,unsigned int capacity)20060Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity)
20070Sstevel@tonic-gate {
20080Sstevel@tonic-gate 	uchar_t			pagecode;
20090Sstevel@tonic-gate 	struct mode_format	*page3p;
20100Sstevel@tonic-gate 	struct mode_geometry	*page4p;
20110Sstevel@tonic-gate 	struct mode_header	*headerp;
20120Sstevel@tonic-gate 	uint32_t		ncyl;
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
20150Sstevel@tonic-gate 		return;
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
20180Sstevel@tonic-gate 		bp_mapin(bp);
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	pagecode = cdbp->cdb_un.sg.scsi[0];
20210Sstevel@tonic-gate 	switch (pagecode) {
20220Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE3_CODE:
20230Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20240Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 		page3p = (struct mode_format *)((caddr_t)headerp +
20277656SSherry.Moore@Sun.COM 		    MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20280Sstevel@tonic-gate 		page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE);
20290Sstevel@tonic-gate 		page3p->mode_page.length = BE_8(sizeof (struct mode_format));
20300Sstevel@tonic-gate 		page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS);
20310Sstevel@tonic-gate 		page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS);
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate 		return;
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE4_CODE:
20360Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20370Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20380Sstevel@tonic-gate 
20390Sstevel@tonic-gate 		page4p = (struct mode_geometry *)((caddr_t)headerp +
20407656SSherry.Moore@Sun.COM 		    MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20410Sstevel@tonic-gate 		page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE);
20420Sstevel@tonic-gate 		page4p->mode_page.length = BE_8(sizeof (struct mode_geometry));
20430Sstevel@tonic-gate 		page4p->heads = BE_8(AMR_DEFAULT_HEADS);
20440Sstevel@tonic-gate 		page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS);
20450Sstevel@tonic-gate 
20460Sstevel@tonic-gate 		ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS);
20470Sstevel@tonic-gate 		page4p->cyl_lb = BE_8(ncyl & 0xff);
20480Sstevel@tonic-gate 		page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff);
20490Sstevel@tonic-gate 		page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff);
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 		return;
20520Sstevel@tonic-gate 	default:
20530Sstevel@tonic-gate 		bzero(bp->b_un.b_addr, bp->b_bcount);
20540Sstevel@tonic-gate 		return;
20550Sstevel@tonic-gate 	}
20560Sstevel@tonic-gate }
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate static void
amr_set_arq_data(struct scsi_pkt * pkt,uchar_t key)20590Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
20600Sstevel@tonic-gate {
20610Sstevel@tonic-gate 	struct scsi_arq_status *arqstat;
20620Sstevel@tonic-gate 
20630Sstevel@tonic-gate 	arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp);
20640Sstevel@tonic-gate 	arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
20650Sstevel@tonic-gate 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
20660Sstevel@tonic-gate 	arqstat->sts_rqpkt_resid = 0;
20670Sstevel@tonic-gate 	arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
20687656SSherry.Moore@Sun.COM 	    STATE_SENT_CMD | STATE_XFERRED_DATA;
20690Sstevel@tonic-gate 	arqstat->sts_rqpkt_statistics = 0;
20700Sstevel@tonic-gate 	arqstat->sts_sensedata.es_valid = 1;
20710Sstevel@tonic-gate 	arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
20720Sstevel@tonic-gate 	arqstat->sts_sensedata.es_key = key;
20730Sstevel@tonic-gate }
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate static void
amr_start_waiting_queue(void * softp)20760Sstevel@tonic-gate amr_start_waiting_queue(void *softp)
20770Sstevel@tonic-gate {
20780Sstevel@tonic-gate 	uint32_t		slot;
20790Sstevel@tonic-gate 	struct amr_command	*ac;
20800Sstevel@tonic-gate 	volatile uint32_t	done_flag;
20810Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)softp;
20820Sstevel@tonic-gate 
20830Sstevel@tonic-gate 	/* only one command allowed at the same time */
20840Sstevel@tonic-gate 	mutex_enter(&softs->queue_mutex);
20850Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 	while ((ac = softs->waiting_q_head) != NULL) {
20880Sstevel@tonic-gate 		/*
20890Sstevel@tonic-gate 		 * Find an available slot, the last slot is
20900Sstevel@tonic-gate 		 * occupied by poll I/O command.
20910Sstevel@tonic-gate 		 */
20920Sstevel@tonic-gate 		for (slot = 0; slot < (softs->sg_max_count - 1); slot++) {
20930Sstevel@tonic-gate 			if (softs->busycmd[slot] == NULL) {
20940Sstevel@tonic-gate 				if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) {
20950Sstevel@tonic-gate 					/*
20960Sstevel@tonic-gate 					 * only one command allowed at the
20970Sstevel@tonic-gate 					 * same time
20980Sstevel@tonic-gate 					 */
20990Sstevel@tonic-gate 					mutex_exit(&softs->cmd_mutex);
21000Sstevel@tonic-gate 					mutex_exit(&softs->queue_mutex);
21010Sstevel@tonic-gate 					return;
21020Sstevel@tonic-gate 				}
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 				ac->ac_timestamp = ddi_get_time();
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 				if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) {
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 					softs->busycmd[slot] = ac;
21090Sstevel@tonic-gate 					ac->ac_slot = slot;
21100Sstevel@tonic-gate 					softs->amr_busyslots++;
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 					bcopy(ac->sgtable,
21137656SSherry.Moore@Sun.COM 					    softs->sg_items[slot].sg_table,
21147656SSherry.Moore@Sun.COM 					    sizeof (struct amr_sgentry) *
21157656SSherry.Moore@Sun.COM 					    AMR_NSEG);
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 					(void) ddi_dma_sync(
21187656SSherry.Moore@Sun.COM 					    softs->sg_items[slot].sg_handle,
21197656SSherry.Moore@Sun.COM 					    0, 0, DDI_DMA_SYNC_FORDEV);
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 					ac->mailbox.mb_physaddr =
21227656SSherry.Moore@Sun.COM 					    softs->sg_items[slot].sg_phyaddr;
21230Sstevel@tonic-gate 				}
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 				/* take the cmd from the queue */
21260Sstevel@tonic-gate 				softs->waiting_q_head = ac->ac_next;
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 				ac->mailbox.mb_ident = ac->ac_slot + 1;
21290Sstevel@tonic-gate 				ac->mailbox.mb_busy = 1;
21300Sstevel@tonic-gate 				ac->ac_next = NULL;
21310Sstevel@tonic-gate 				ac->ac_prev = NULL;
21320Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_GOT_SLOT;
21330Sstevel@tonic-gate 
21340Sstevel@tonic-gate 				/* clear the poll/ack fields in the mailbox */
21350Sstevel@tonic-gate 				softs->mailbox->mb_poll = 0;
21360Sstevel@tonic-gate 				softs->mailbox->mb_ack = 0;
21370Sstevel@tonic-gate 
21380Sstevel@tonic-gate 				AMR_DELAY((softs->mailbox->mb_busy == 0),
21397656SSherry.Moore@Sun.COM 				    AMR_RETRYCOUNT, done_flag);
21400Sstevel@tonic-gate 				if (!done_flag) {
21410Sstevel@tonic-gate 					/*
21420Sstevel@tonic-gate 					 * command not completed, indicate the
21430Sstevel@tonic-gate 					 * problem and continue get ac
21440Sstevel@tonic-gate 					 */
21450Sstevel@tonic-gate 					cmn_err(CE_WARN,
21467656SSherry.Moore@Sun.COM 					    "AMR command is not completed");
21470Sstevel@tonic-gate 					break;
21480Sstevel@tonic-gate 				}
21490Sstevel@tonic-gate 
21500Sstevel@tonic-gate 				bcopy(&ac->mailbox, (void *)softs->mailbox,
21517656SSherry.Moore@Sun.COM 				    AMR_MBOX_CMDSIZE);
21520Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_BUSY;
21530Sstevel@tonic-gate 
21540Sstevel@tonic-gate 				(void) ddi_dma_sync(softs->mbox_dma_handle,
21557656SSherry.Moore@Sun.COM 				    0, 0, DDI_DMA_SYNC_FORDEV);
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 				AMR_QPUT_IDB(softs,
21587656SSherry.Moore@Sun.COM 				    softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 				/*
21610Sstevel@tonic-gate 				 * current ac is submitted
21620Sstevel@tonic-gate 				 * so quit 'for-loop' to get next ac
21630Sstevel@tonic-gate 				 */
21640Sstevel@tonic-gate 				break;
21650Sstevel@tonic-gate 			}
21660Sstevel@tonic-gate 		}
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 		/* no slot, finish our task */
21690Sstevel@tonic-gate 		if (slot == softs->maxio)
21700Sstevel@tonic-gate 			break;
21710Sstevel@tonic-gate 	}
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	/* only one command allowed at the same time */
21740Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
21750Sstevel@tonic-gate 	mutex_exit(&softs->queue_mutex);
21760Sstevel@tonic-gate }
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate static void
amr_done(struct amr_softs * softs)21790Sstevel@tonic-gate amr_done(struct amr_softs *softs)
21800Sstevel@tonic-gate {
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate 	uint32_t		i, idx;
21830Sstevel@tonic-gate 	volatile uint32_t	done_flag;
21840Sstevel@tonic-gate 	struct amr_mailbox	*mbox, mbsave;
21850Sstevel@tonic-gate 	struct amr_command	*ac, *head, *tail;
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate 	head = tail = NULL;
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	AMR_QPUT_ODB(softs, AMR_QODB_READY);
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 	/* acknowledge interrupt */
21920Sstevel@tonic-gate 	(void) AMR_QGET_ODB(softs);
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
21950Sstevel@tonic-gate 
21960Sstevel@tonic-gate 	if (softs->mailbox->mb_nstatus != 0) {
21970Sstevel@tonic-gate 		(void) ddi_dma_sync(softs->mbox_dma_handle,
21987656SSherry.Moore@Sun.COM 		    0, 0, DDI_DMA_SYNC_FORCPU);
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		/* save mailbox, which contains a list of completed commands */
22010Sstevel@tonic-gate 		bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox,
22027656SSherry.Moore@Sun.COM 		    &mbsave, sizeof (mbsave));
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 		mbox = &mbsave;
22050Sstevel@tonic-gate 
22060Sstevel@tonic-gate 		AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 		/* wait for the acknowledge from hardware */
22090Sstevel@tonic-gate 		AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
22107656SSherry.Moore@Sun.COM 		    AMR_RETRYCOUNT, done_flag);
22110Sstevel@tonic-gate 		if (!done_flag) {
22120Sstevel@tonic-gate 			/*
22130Sstevel@tonic-gate 			 * command is not completed, return from the current
22140Sstevel@tonic-gate 			 * interrupt and wait for the next one
22150Sstevel@tonic-gate 			 */
22160Sstevel@tonic-gate 			cmn_err(CE_WARN, "No answer from the hardware");
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
22190Sstevel@tonic-gate 			return;
22200Sstevel@tonic-gate 		}
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 		for (i = 0; i < mbox->mb_nstatus; i++) {
22230Sstevel@tonic-gate 			idx = mbox->mb_completed[i] - 1;
22240Sstevel@tonic-gate 			ac = softs->busycmd[idx];
22250Sstevel@tonic-gate 
22260Sstevel@tonic-gate 			if (ac != NULL) {
22270Sstevel@tonic-gate 				/* pull the command from the busy index */
22280Sstevel@tonic-gate 				softs->busycmd[idx] = NULL;
22290Sstevel@tonic-gate 				if (softs->amr_busyslots > 0)
22300Sstevel@tonic-gate 					softs->amr_busyslots--;
22310Sstevel@tonic-gate 				if (softs->amr_busyslots == 0)
22320Sstevel@tonic-gate 					cv_broadcast(&softs->cmd_cv);
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_BUSY;
22350Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
22360Sstevel@tonic-gate 				ac->ac_status = mbox->mb_status;
22370Sstevel@tonic-gate 
22380Sstevel@tonic-gate 				/* enqueue here */
22390Sstevel@tonic-gate 				if (head) {
22400Sstevel@tonic-gate 					tail->ac_next = ac;
22410Sstevel@tonic-gate 					tail = ac;
22420Sstevel@tonic-gate 					tail->ac_next = NULL;
22430Sstevel@tonic-gate 				} else {
22440Sstevel@tonic-gate 					tail = head = ac;
22450Sstevel@tonic-gate 					ac->ac_next = NULL;
22460Sstevel@tonic-gate 				}
22470Sstevel@tonic-gate 			} else {
22480Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
22497656SSherry.Moore@Sun.COM 				    "ac in mailbox is NULL!"));
22500Sstevel@tonic-gate 			}
22510Sstevel@tonic-gate 		}
22520Sstevel@tonic-gate 	} else {
22530Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!"));
22540Sstevel@tonic-gate 	}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 	if (head != NULL) {
22590Sstevel@tonic-gate 		amr_call_pkt_comp(head);
22600Sstevel@tonic-gate 	}
22610Sstevel@tonic-gate 
22620Sstevel@tonic-gate 	/* dispatch a thread to process the pending I/O if there is any */
22630Sstevel@tonic-gate 	if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue,
22647656SSherry.Moore@Sun.COM 	    (void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) {
22650Sstevel@tonic-gate 		cmn_err(CE_WARN, "No memory available to dispatch taskq");
22660Sstevel@tonic-gate 	}
22670Sstevel@tonic-gate }
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate static void
amr_call_pkt_comp(register struct amr_command * head)22700Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head)
22710Sstevel@tonic-gate {
22720Sstevel@tonic-gate 	register struct scsi_pkt	*pkt;
22730Sstevel@tonic-gate 	register struct amr_command	*ac, *localhead;
22740Sstevel@tonic-gate 
22750Sstevel@tonic-gate 	localhead = head;
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 	while (localhead) {
22780Sstevel@tonic-gate 		ac = localhead;
22790Sstevel@tonic-gate 		localhead = ac->ac_next;
22800Sstevel@tonic-gate 		ac->ac_next = NULL;
22810Sstevel@tonic-gate 
22820Sstevel@tonic-gate 		pkt = ac->pkt;
22830Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 		if (ac->ac_status == AMR_STATUS_SUCCESS) {
22860Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
22877656SSherry.Moore@Sun.COM 			    | STATE_GOT_TARGET
22887656SSherry.Moore@Sun.COM 			    | STATE_SENT_CMD
22897656SSherry.Moore@Sun.COM 			    | STATE_XFERRED_DATA);
22900Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
22910Sstevel@tonic-gate 		} else {
22920Sstevel@tonic-gate 			pkt->pkt_state |= STATE_GOT_BUS
22937656SSherry.Moore@Sun.COM 			    | STATE_ARQ_DONE;
22940Sstevel@tonic-gate 			pkt->pkt_reason = CMD_INCOMPLETE;
22950Sstevel@tonic-gate 			amr_set_arq_data(pkt, KEY_HARDWARE_ERROR);
22960Sstevel@tonic-gate 		}
2297*9106SSrivijitha.Dugganapalli@Sun.COM 		if (!(pkt->pkt_flags & FLAG_NOINTR)) {
2298*9106SSrivijitha.Dugganapalli@Sun.COM 			scsi_hba_pkt_comp(pkt);
22990Sstevel@tonic-gate 		}
23000Sstevel@tonic-gate 	}
23010Sstevel@tonic-gate }
2302