xref: /illumos-gate/usr/src/uts/intel/io/amr/amr.c (revision 89b43686)
17c478bd9Sstevel@tonic-gate /*
29c57abc8Ssrivijitha dugganapalli  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*89b43686SBayard Bell  * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
57c478bd9Sstevel@tonic-gate  */
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * Copyright (c) 1999,2000 Michael Smith
87c478bd9Sstevel@tonic-gate  * Copyright (c) 2000 BSDi
97c478bd9Sstevel@tonic-gate  * All rights reserved.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
127c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
137c478bd9Sstevel@tonic-gate  * are met:
147c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
157c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
167c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
177c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
187c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
217c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
247c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Copyright (c) 2002 Eric Moore
347c478bd9Sstevel@tonic-gate  * Copyright (c) 2002 LSI Logic Corporation
357c478bd9Sstevel@tonic-gate  * All rights reserved.
367c478bd9Sstevel@tonic-gate  *
377c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
387c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
397c478bd9Sstevel@tonic-gate  * are met:
407c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
417c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
427c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
437c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
447c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
457c478bd9Sstevel@tonic-gate  * 3. The party using or redistributing the source code and binary forms
467c478bd9Sstevel@tonic-gate  *    agrees to the disclaimer below and the terms and conditions set forth
477c478bd9Sstevel@tonic-gate  *    herein.
487c478bd9Sstevel@tonic-gate  *
497c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
507c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
517c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
527c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
537c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
547c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
557c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
567c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
577c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
587c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
597c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate #include <sys/int_types.h>
637c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h>
647c478bd9Sstevel@tonic-gate #include <sys/dkbad.h>
657c478bd9Sstevel@tonic-gate #include <sys/dklabel.h>
667c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
677c478bd9Sstevel@tonic-gate #include <sys/cdio.h>
687c478bd9Sstevel@tonic-gate #include <sys/mhd.h>
697c478bd9Sstevel@tonic-gate #include <sys/vtoc.h>
707c478bd9Sstevel@tonic-gate #include <sys/dktp/fdisk.h>
717c478bd9Sstevel@tonic-gate #include <sys/scsi/targets/sddef.h>
727c478bd9Sstevel@tonic-gate #include <sys/debug.h>
737c478bd9Sstevel@tonic-gate #include <sys/pci.h>
747c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
757c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
767c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
777c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
787c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #include "amrreg.h"
817c478bd9Sstevel@tonic-gate #include "amrvar.h"
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* dynamic debug symbol */
847c478bd9Sstevel@tonic-gate int	amr_debug_var = 0;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate #define	AMR_DELAY(cond, count, done_flag) { \
877c478bd9Sstevel@tonic-gate 		int local_counter = 0; \
887c478bd9Sstevel@tonic-gate 		done_flag = 1; \
897c478bd9Sstevel@tonic-gate 		while (!(cond)) { \
907c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(100)); \
917c478bd9Sstevel@tonic-gate 			if ((local_counter) > count) { \
927c478bd9Sstevel@tonic-gate 				done_flag = 0; \
937c478bd9Sstevel@tonic-gate 				break; \
947c478bd9Sstevel@tonic-gate 			} \
957c478bd9Sstevel@tonic-gate 			(local_counter)++; \
967c478bd9Sstevel@tonic-gate 		} \
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate #define	AMR_BUSYWAIT(cond, count, done_flag) { \
1007c478bd9Sstevel@tonic-gate 		int local_counter = 0; \
1017c478bd9Sstevel@tonic-gate 		done_flag = 1; \
1027c478bd9Sstevel@tonic-gate 		while (!(cond)) { \
1037c478bd9Sstevel@tonic-gate 			drv_usecwait(100); \
1047c478bd9Sstevel@tonic-gate 			if ((local_counter) > count) { \
1057c478bd9Sstevel@tonic-gate 				done_flag = 0; \
1067c478bd9Sstevel@tonic-gate 				break; \
1077c478bd9Sstevel@tonic-gate 			} \
1087c478bd9Sstevel@tonic-gate 			(local_counter)++; \
1097c478bd9Sstevel@tonic-gate 		} \
1107c478bd9Sstevel@tonic-gate 	}
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * driver interfaces
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static uint_t amr_intr(caddr_t arg);
1177c478bd9Sstevel@tonic-gate static void amr_done(struct amr_softs *softs);
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
1207c478bd9Sstevel@tonic-gate 			void *arg, void **result);
1217c478bd9Sstevel@tonic-gate static int amr_attach(dev_info_t *, ddi_attach_cmd_t);
1227c478bd9Sstevel@tonic-gate static int amr_detach(dev_info_t *, ddi_detach_cmd_t);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate static int amr_setup_mbox(struct amr_softs *softs);
1257c478bd9Sstevel@tonic-gate static int amr_setup_sg(struct amr_softs *softs);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /*
1287c478bd9Sstevel@tonic-gate  * Command wrappers
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate static int amr_query_controller(struct amr_softs *softs);
1317c478bd9Sstevel@tonic-gate static void *amr_enquiry(struct amr_softs *softs, size_t bufsize,
1327c478bd9Sstevel@tonic-gate 			uint8_t cmd, uint8_t cmdsub, uint8_t cmdqual);
1337c478bd9Sstevel@tonic-gate static int amr_flush(struct amr_softs *softs);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate /*
1367c478bd9Sstevel@tonic-gate  * Command processing.
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate static void amr_rw_command(struct amr_softs *softs,
1397c478bd9Sstevel@tonic-gate 			struct scsi_pkt *pkt, int lun);
1407c478bd9Sstevel@tonic-gate static void amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp,
1417c478bd9Sstevel@tonic-gate 			unsigned int capacity);
1427c478bd9Sstevel@tonic-gate static void amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key);
1437c478bd9Sstevel@tonic-gate static int amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size);
1447c478bd9Sstevel@tonic-gate static void amr_enquiry_unmapcmd(struct amr_command *ac);
145e687df1aSyw161884 static int amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg);
1467c478bd9Sstevel@tonic-gate static void amr_unmapcmd(struct amr_command *ac);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * Status monitoring
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate static void amr_periodic(void *data);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * Interface-specific shims
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate static int amr_poll_command(struct amr_command *ac);
1577c478bd9Sstevel@tonic-gate static void amr_start_waiting_queue(void *softp);
1587c478bd9Sstevel@tonic-gate static void amr_call_pkt_comp(struct amr_command *head);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate /*
1617c478bd9Sstevel@tonic-gate  * SCSI interface
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate static int amr_setup_tran(dev_info_t  *dip, struct amr_softs *softp);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate  * Function prototypes
1677c478bd9Sstevel@tonic-gate  *
1687c478bd9Sstevel@tonic-gate  * SCSA functions exported by means of the transport table
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate static int amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
1717c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd);
1727c478bd9Sstevel@tonic-gate static int amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt);
1737c478bd9Sstevel@tonic-gate static int amr_tran_reset(struct scsi_address *ap, int level);
1747c478bd9Sstevel@tonic-gate static int amr_tran_getcap(struct scsi_address *ap, char *cap, int whom);
1757c478bd9Sstevel@tonic-gate static int amr_tran_setcap(struct scsi_address *ap, char *cap, int value,
1767c478bd9Sstevel@tonic-gate     int whom);
1777c478bd9Sstevel@tonic-gate static struct scsi_pkt *amr_tran_init_pkt(struct scsi_address *ap,
1787c478bd9Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
1797c478bd9Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg);
1807c478bd9Sstevel@tonic-gate static void amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt);
1817c478bd9Sstevel@tonic-gate static void amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt);
1827c478bd9Sstevel@tonic-gate static void amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate static ddi_dma_attr_t buffer_dma_attr = {
1857c478bd9Sstevel@tonic-gate 		DMA_ATTR_V0,	/* version of this structure */
1867c478bd9Sstevel@tonic-gate 		0,		/* lowest usable address */
1877c478bd9Sstevel@tonic-gate 		0xffffffffull,	/* highest usable address */
1887c478bd9Sstevel@tonic-gate 		0x00ffffffull,	/* maximum DMAable byte count */
1897c478bd9Sstevel@tonic-gate 		4,		/* alignment */
1907c478bd9Sstevel@tonic-gate 		1,		/* burst sizes */
1917c478bd9Sstevel@tonic-gate 		1,		/* minimum transfer */
1927c478bd9Sstevel@tonic-gate 		0xffffffffull,	/* maximum transfer */
1937c478bd9Sstevel@tonic-gate 		0xffffffffull,	/* maximum segment length */
1947c478bd9Sstevel@tonic-gate 		AMR_NSEG,	/* maximum number of segments */
1957c478bd9Sstevel@tonic-gate 		AMR_BLKSIZE,	/* granularity */
1967c478bd9Sstevel@tonic-gate 		0,		/* flags (reserved) */
1977c478bd9Sstevel@tonic-gate };
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate static ddi_dma_attr_t addr_dma_attr = {
2007c478bd9Sstevel@tonic-gate 		DMA_ATTR_V0,	/* version of this structure */
2017c478bd9Sstevel@tonic-gate 		0,		/* lowest usable address */
2027c478bd9Sstevel@tonic-gate 		0xffffffffull,	/* highest usable address */
2037c478bd9Sstevel@tonic-gate 		0x7fffffff,	/* maximum DMAable byte count */
2047c478bd9Sstevel@tonic-gate 		4,		/* alignment */
2057c478bd9Sstevel@tonic-gate 		1,		/* burst sizes */
2067c478bd9Sstevel@tonic-gate 		1,		/* minimum transfer */
2077c478bd9Sstevel@tonic-gate 		0xffffffffull,	/* maximum transfer */
2087c478bd9Sstevel@tonic-gate 		0xffffffffull,	/* maximum segment length */
2097c478bd9Sstevel@tonic-gate 		1,		/* maximum number of segments */
2107c478bd9Sstevel@tonic-gate 		1,		/* granularity */
2117c478bd9Sstevel@tonic-gate 		0,		/* flags (reserved) */
2127c478bd9Sstevel@tonic-gate };
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate static struct dev_ops   amr_ops = {
2167c478bd9Sstevel@tonic-gate 	DEVO_REV,	/* devo_rev, */
2177c478bd9Sstevel@tonic-gate 	0,		/* refcnt  */
2187c478bd9Sstevel@tonic-gate 	amr_info,	/* info */
2197c478bd9Sstevel@tonic-gate 	nulldev,	/* identify */
2207c478bd9Sstevel@tonic-gate 	nulldev,	/* probe */
2217c478bd9Sstevel@tonic-gate 	amr_attach,	/* attach */
2227c478bd9Sstevel@tonic-gate 	amr_detach,	/* detach */
2237c478bd9Sstevel@tonic-gate 	nodev,		/* reset */
2247c478bd9Sstevel@tonic-gate 	NULL,		/* driver operations */
2257c478bd9Sstevel@tonic-gate 	(struct bus_ops *)0,	/* bus operations */
22619397407SSherry Moore 	0,		/* power */
22719397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
2287c478bd9Sstevel@tonic-gate };
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2327c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
2337c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* Type of module. driver here */
234613b2871SRichard Bean 	"AMR Driver",		/* Name of the module. */
2357c478bd9Sstevel@tonic-gate 	&amr_ops,		/* Driver ops vector */
2367c478bd9Sstevel@tonic-gate };
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
2397c478bd9Sstevel@tonic-gate 	MODREV_1,
2407c478bd9Sstevel@tonic-gate 	&modldrv,
2417c478bd9Sstevel@tonic-gate 	NULL
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /* DMA access attributes */
2457c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = {
2467c478bd9Sstevel@tonic-gate 	DDI_DEVICE_ATTR_V0,
2477c478bd9Sstevel@tonic-gate 	DDI_NEVERSWAP_ACC,
2487c478bd9Sstevel@tonic-gate 	DDI_STRICTORDER_ACC
2497c478bd9Sstevel@tonic-gate };
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate static struct amr_softs  *amr_softstatep;
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate int
_init(void)2557c478bd9Sstevel@tonic-gate _init(void)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	int		error;
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 	error = ddi_soft_state_init((void *)&amr_softstatep,
2607c478bd9Sstevel@tonic-gate 	    sizeof (struct amr_softs), 0);
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	if (error != 0)
2637c478bd9Sstevel@tonic-gate 		goto error_out;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if ((error = scsi_hba_init(&modlinkage)) != 0) {
2667c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini((void*)&amr_softstatep);
2677c478bd9Sstevel@tonic-gate 		goto error_out;
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	error = mod_install(&modlinkage);
2717c478bd9Sstevel@tonic-gate 	if (error != 0) {
2727c478bd9Sstevel@tonic-gate 		scsi_hba_fini(&modlinkage);
2737c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini((void*)&amr_softstatep);
2747c478bd9Sstevel@tonic-gate 		goto error_out;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	return (error);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate error_out:
2807c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "_init failed");
2817c478bd9Sstevel@tonic-gate 	return (error);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2857c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate int
_fini(void)2917c478bd9Sstevel@tonic-gate _fini(void)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	int	error;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	if ((error = mod_remove(&modlinkage)) != 0) {
2967c478bd9Sstevel@tonic-gate 		return (error);
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	scsi_hba_fini(&modlinkage);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	ddi_soft_state_fini((void*)&amr_softstatep);
3027c478bd9Sstevel@tonic-gate 	return (error);
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate static int
amr_attach(dev_info_t * dev,ddi_attach_cmd_t cmd)3077c478bd9Sstevel@tonic-gate amr_attach(dev_info_t *dev, ddi_attach_cmd_t cmd)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
3107c478bd9Sstevel@tonic-gate 	int			error;
3117c478bd9Sstevel@tonic-gate 	uint32_t		command, i;
3127c478bd9Sstevel@tonic-gate 	int			instance;
3137c478bd9Sstevel@tonic-gate 	caddr_t			cfgaddr;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dev);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	switch (cmd) {
3187c478bd9Sstevel@tonic-gate 		case DDI_ATTACH:
3197c478bd9Sstevel@tonic-gate 			break;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 		case DDI_RESUME:
3227c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		default:
3257c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
3267c478bd9Sstevel@tonic-gate 	}
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * Initialize softs.
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(amr_softstatep, instance) != DDI_SUCCESS)
3327c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3337c478bd9Sstevel@tonic-gate 	softs = ddi_get_soft_state(amr_softstatep, instance);
3347c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_SOFT_STATE_SETUP;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	softs->dev_info_p = dev;
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "softs: %p; busy_slot addr: %p",
3397c478bd9Sstevel@tonic-gate 	    (void *)softs, (void *)&(softs->amr_busyslots)));
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	if (pci_config_setup(dev, &(softs->pciconfig_handle))
3427c478bd9Sstevel@tonic-gate 	    != DDI_SUCCESS) {
3437c478bd9Sstevel@tonic-gate 		goto error_out;
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_PCI_CONFIG_SETUP;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	error = ddi_regs_map_setup(dev, 1, &cfgaddr, 0, 0,
3487c478bd9Sstevel@tonic-gate 	    &accattr, &(softs->regsmap_handle));
3497c478bd9Sstevel@tonic-gate 	if (error != DDI_SUCCESS) {
3507c478bd9Sstevel@tonic-gate 		goto error_out;
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_PCI_MEM_MAPPED;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	/*
3557c478bd9Sstevel@tonic-gate 	 * Determine board type.
3567c478bd9Sstevel@tonic-gate 	 */
3577c478bd9Sstevel@tonic-gate 	command = pci_config_get16(softs->pciconfig_handle, PCI_CONF_COMM);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/*
3607c478bd9Sstevel@tonic-gate 	 * Make sure we are going to be able to talk to this board.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	if ((command & PCI_COMM_MAE) == 0) {
3637c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,  "memory window not available"));
3647c478bd9Sstevel@tonic-gate 		goto error_out;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/* force the busmaster enable bit on */
3687c478bd9Sstevel@tonic-gate 	if (!(command & PCI_COMM_ME)) {
3697c478bd9Sstevel@tonic-gate 		command |= PCI_COMM_ME;
3707c478bd9Sstevel@tonic-gate 		pci_config_put16(softs->pciconfig_handle,
3717c478bd9Sstevel@tonic-gate 		    PCI_CONF_COMM, command);
3727c478bd9Sstevel@tonic-gate 		command = pci_config_get16(softs->pciconfig_handle,
3737c478bd9Sstevel@tonic-gate 		    PCI_CONF_COMM);
3747c478bd9Sstevel@tonic-gate 		if (!(command & PCI_COMM_ME))
3757c478bd9Sstevel@tonic-gate 			goto error_out;
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	/*
3797c478bd9Sstevel@tonic-gate 	 * Allocate and connect our interrupt.
3807c478bd9Sstevel@tonic-gate 	 */
3817c478bd9Sstevel@tonic-gate 	if (ddi_intr_hilevel(dev, 0) != 0) {
38219397407SSherry Moore 		AMRDB_PRINT((CE_NOTE,
38319397407SSherry Moore 		    "High level interrupt is not supported!"));
3847c478bd9Sstevel@tonic-gate 		goto error_out;
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dev, 0,  &softs->iblock_cookiep)
3887c478bd9Sstevel@tonic-gate 	    != DDI_SUCCESS) {
3897c478bd9Sstevel@tonic-gate 		goto error_out;
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	mutex_init(&softs->cmd_mutex, NULL, MUTEX_DRIVER,
3937c478bd9Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3947c478bd9Sstevel@tonic-gate 	mutex_init(&softs->queue_mutex, NULL, MUTEX_DRIVER,
3957c478bd9Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3967c478bd9Sstevel@tonic-gate 	mutex_init(&softs->periodic_mutex, NULL, MUTEX_DRIVER,
3977c478bd9Sstevel@tonic-gate 	    softs->iblock_cookiep); /* should be used in interrupt */
3987c478bd9Sstevel@tonic-gate 	/* sychronize waits for the busy slots via this cv */
3997c478bd9Sstevel@tonic-gate 	cv_init(&softs->cmd_cv, NULL, CV_DRIVER, NULL);
4007c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_KMUTEX_INITED;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	/*
4037c478bd9Sstevel@tonic-gate 	 * Do bus-independent initialisation, bring controller online.
4047c478bd9Sstevel@tonic-gate 	 */
4057c478bd9Sstevel@tonic-gate 	if (amr_setup_mbox(softs) != DDI_SUCCESS)
4067c478bd9Sstevel@tonic-gate 		goto error_out;
4077c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_MAILBOX_SETUP;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (amr_setup_sg(softs) != DDI_SUCCESS)
4107c478bd9Sstevel@tonic-gate 		goto error_out;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_SG_TABLES_SETUP;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	if (amr_query_controller(softs) != DDI_SUCCESS)
4157c478bd9Sstevel@tonic-gate 		goto error_out;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/*
4187c478bd9Sstevel@tonic-gate 	 * A taskq is created for dispatching the waiting queue processing
4197c478bd9Sstevel@tonic-gate 	 * thread. The threads number equals to the logic drive number and
4207c478bd9Sstevel@tonic-gate 	 * the thread number should be 1 if there is no logic driver is
4217c478bd9Sstevel@tonic-gate 	 * configured for this instance.
4227c478bd9Sstevel@tonic-gate 	 */
4237c478bd9Sstevel@tonic-gate 	if ((softs->amr_taskq = ddi_taskq_create(dev, "amr_taskq",
4247c478bd9Sstevel@tonic-gate 	    MAX(softs->amr_nlogdrives, 1), TASKQ_DEFAULTPRI, 0)) == NULL) {
4257c478bd9Sstevel@tonic-gate 		goto error_out;
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_TASKQ_SETUP;
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	if (ddi_add_intr(dev, 0, &softs->iblock_cookiep, NULL,
4307c478bd9Sstevel@tonic-gate 	    amr_intr, (caddr_t)softs) != DDI_SUCCESS) {
4317c478bd9Sstevel@tonic-gate 		goto error_out;
4327c478bd9Sstevel@tonic-gate 	}
4337c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_INTR_SETUP;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	/* set up the tran interface */
4367c478bd9Sstevel@tonic-gate 	if (amr_setup_tran(softs->dev_info_p, softs) != DDI_SUCCESS) {
4377c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "setup tran failed"));
4387c478bd9Sstevel@tonic-gate 		goto error_out;
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_TRAN_SETUP;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/* schedule a thread for periodic check */
4437c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
4447c478bd9Sstevel@tonic-gate 	softs->timeout_t = timeout(amr_periodic, (void *)softs,
4457c478bd9Sstevel@tonic-gate 	    drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
4467c478bd9Sstevel@tonic-gate 	softs->state |= AMR_STATE_TIMEOUT_ENABLED;
4477c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/* print firmware information in verbose mode */
4507c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "?MegaRaid %s %s attached.",
4517c478bd9Sstevel@tonic-gate 	    softs->amr_product_info.pi_product_name,
4527c478bd9Sstevel@tonic-gate 	    softs->amr_product_info.pi_firmware_ver);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	/* clear any interrupts */
4557c478bd9Sstevel@tonic-gate 	AMR_QCLEAR_INTR(softs);
4567c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate error_out:
4597c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_INTR_SETUP) {
4607c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dev, 0, softs->iblock_cookiep);
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TASKQ_SETUP) {
4637c478bd9Sstevel@tonic-gate 		ddi_taskq_destroy(softs->amr_taskq);
4647c478bd9Sstevel@tonic-gate 	}
4657c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_SG_TABLES_SETUP) {
4667c478bd9Sstevel@tonic-gate 		for (i = 0; i < softs->sg_max_count; i++) {
4677c478bd9Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
4687c478bd9Sstevel@tonic-gate 			    softs->sg_items[i].sg_handle);
4697c478bd9Sstevel@tonic-gate 			(void) ddi_dma_mem_free(
4707c478bd9Sstevel@tonic-gate 			    &((softs->sg_items[i]).sg_acc_handle));
4717c478bd9Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
4727c478bd9Sstevel@tonic-gate 			    &(softs->sg_items[i].sg_handle));
4737c478bd9Sstevel@tonic-gate 		}
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_MAILBOX_SETUP) {
4767c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
4777c478bd9Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&softs->mbox_acc_handle);
4787c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_KMUTEX_INITED) {
4817c478bd9Sstevel@tonic-gate 		mutex_destroy(&softs->queue_mutex);
4827c478bd9Sstevel@tonic-gate 		mutex_destroy(&softs->cmd_mutex);
4837c478bd9Sstevel@tonic-gate 		mutex_destroy(&softs->periodic_mutex);
4847c478bd9Sstevel@tonic-gate 		cv_destroy(&softs->cmd_cv);
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_PCI_MEM_MAPPED)
4877c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&softs->regsmap_handle);
4887c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_PCI_CONFIG_SETUP)
4897c478bd9Sstevel@tonic-gate 		pci_config_teardown(&softs->pciconfig_handle);
4907c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_SOFT_STATE_SETUP)
4917c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(amr_softstatep, instance);
4927c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
4937c478bd9Sstevel@tonic-gate }
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate /*
4967c478bd9Sstevel@tonic-gate  * Bring the controller down to a dormant state and detach all child devices.
4977c478bd9Sstevel@tonic-gate  * This function is called during detach, system shutdown.
4987c478bd9Sstevel@tonic-gate  *
4997c478bd9Sstevel@tonic-gate  * Note that we can assume that the bufq on the controller is empty, as we won't
5007c478bd9Sstevel@tonic-gate  * allow shutdown if any device is open.
5017c478bd9Sstevel@tonic-gate  */
5027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
amr_detach(dev_info_t * dev,ddi_detach_cmd_t cmd)5037c478bd9Sstevel@tonic-gate static int amr_detach(dev_info_t *dev, ddi_detach_cmd_t cmd)
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
5067c478bd9Sstevel@tonic-gate 	int			instance;
5077c478bd9Sstevel@tonic-gate 	uint32_t		i, done_flag;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dev);
5107c478bd9Sstevel@tonic-gate 	softs = ddi_get_soft_state(amr_softstatep, instance);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	/* flush the controllor */
5137c478bd9Sstevel@tonic-gate 	if (amr_flush(softs) != 0) {
5147c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "device shutdown failed"));
5157c478bd9Sstevel@tonic-gate 		return (EIO);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	/* release the amr timer */
5197c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
5207c478bd9Sstevel@tonic-gate 	softs->state &= ~AMR_STATE_TIMEOUT_ENABLED;
5217c478bd9Sstevel@tonic-gate 	if (softs->timeout_t) {
5227c478bd9Sstevel@tonic-gate 		(void) untimeout(softs->timeout_t);
5237c478bd9Sstevel@tonic-gate 		softs->timeout_t = 0;
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	for (i = 0; i < softs->sg_max_count; i++) {
5287c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(
5297c478bd9Sstevel@tonic-gate 		    softs->sg_items[i].sg_handle);
5307c478bd9Sstevel@tonic-gate 		(void) ddi_dma_mem_free(
5317c478bd9Sstevel@tonic-gate 		    &((softs->sg_items[i]).sg_acc_handle));
5327c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(
5337c478bd9Sstevel@tonic-gate 		    &(softs->sg_items[i].sg_handle));
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
5377c478bd9Sstevel@tonic-gate 	(void) ddi_dma_mem_free(&softs->mbox_acc_handle);
5387c478bd9Sstevel@tonic-gate 	(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	/* disconnect the interrupt handler */
5417c478bd9Sstevel@tonic-gate 	ddi_remove_intr(softs->dev_info_p,  0, softs->iblock_cookiep);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	/* wait for the completion of current in-progress interruptes */
5447c478bd9Sstevel@tonic-gate 	AMR_DELAY((softs->amr_interrupts_counter == 0), 1000, done_flag);
5457c478bd9Sstevel@tonic-gate 	if (!done_flag) {
5467c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "Suspicious interrupts in-progress.");
5477c478bd9Sstevel@tonic-gate 	}
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	ddi_taskq_destroy(softs->amr_taskq);
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	(void) scsi_hba_detach(dev);
5527c478bd9Sstevel@tonic-gate 	scsi_hba_tran_free(softs->hba_tran);
5537c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&softs->regsmap_handle);
5547c478bd9Sstevel@tonic-gate 	pci_config_teardown(&softs->pciconfig_handle);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	mutex_destroy(&softs->queue_mutex);
5577c478bd9Sstevel@tonic-gate 	mutex_destroy(&softs->cmd_mutex);
5587c478bd9Sstevel@tonic-gate 	mutex_destroy(&softs->periodic_mutex);
5597c478bd9Sstevel@tonic-gate 	cv_destroy(&softs->cmd_cv);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	/* print firmware information in verbose mode */
5627c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "?MegaRaid %s %s detached.",
5637c478bd9Sstevel@tonic-gate 	    softs->amr_product_info.pi_product_name,
5647c478bd9Sstevel@tonic-gate 	    softs->amr_product_info.pi_firmware_ver);
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	ddi_soft_state_free(amr_softstatep, instance);
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*ARGSUSED*/
amr_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5737c478bd9Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
5747c478bd9Sstevel@tonic-gate 	void *arg, void **result)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
5777c478bd9Sstevel@tonic-gate 	int			instance;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	switch (infocmd) {
5827c478bd9Sstevel@tonic-gate 		case DDI_INFO_DEVT2DEVINFO:
5837c478bd9Sstevel@tonic-gate 			softs = ddi_get_soft_state(amr_softstatep, instance);
5847c478bd9Sstevel@tonic-gate 			if (softs != NULL) {
5857c478bd9Sstevel@tonic-gate 				*result = softs->dev_info_p;
5867c478bd9Sstevel@tonic-gate 				return (DDI_SUCCESS);
5877c478bd9Sstevel@tonic-gate 			} else {
5887c478bd9Sstevel@tonic-gate 				*result = NULL;
5897c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
5907c478bd9Sstevel@tonic-gate 			}
5917c478bd9Sstevel@tonic-gate 		case DDI_INFO_DEVT2INSTANCE:
5927c478bd9Sstevel@tonic-gate 			*(int *)result = instance;
5937c478bd9Sstevel@tonic-gate 			break;
5947c478bd9Sstevel@tonic-gate 		default:
5957c478bd9Sstevel@tonic-gate 			break;
5967c478bd9Sstevel@tonic-gate 	}
5977c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate /*
6017c478bd9Sstevel@tonic-gate  * Take an interrupt, or be poked by other code to look for interrupt-worthy
6027c478bd9Sstevel@tonic-gate  * status.
6037c478bd9Sstevel@tonic-gate  */
6047c478bd9Sstevel@tonic-gate static uint_t
amr_intr(caddr_t arg)6057c478bd9Sstevel@tonic-gate amr_intr(caddr_t arg)
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate 	struct amr_softs *softs = (struct amr_softs *)arg;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	softs->amr_interrupts_counter++;
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if (AMR_QGET_ODB(softs) != AMR_QODB_READY) {
6127c478bd9Sstevel@tonic-gate 		softs->amr_interrupts_counter--;
6137c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	/* collect finished commands, queue anything waiting */
6177c478bd9Sstevel@tonic-gate 	amr_done(softs);
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	softs->amr_interrupts_counter--;
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate }
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate  * Setup the amr mailbox
6277c478bd9Sstevel@tonic-gate  */
6287c478bd9Sstevel@tonic-gate static int
amr_setup_mbox(struct amr_softs * softs)6297c478bd9Sstevel@tonic-gate amr_setup_mbox(struct amr_softs *softs)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	uint32_t	move;
6327c478bd9Sstevel@tonic-gate 	size_t		mbox_len;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(
6357c478bd9Sstevel@tonic-gate 	    softs->dev_info_p,
6367c478bd9Sstevel@tonic-gate 	    &addr_dma_attr,
6377c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP,
6387c478bd9Sstevel@tonic-gate 	    NULL,
6397c478bd9Sstevel@tonic-gate 	    &softs->mbox_dma_handle) != DDI_SUCCESS) {
6407c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "Cannot alloc dma handle for mailbox"));
6417c478bd9Sstevel@tonic-gate 		goto error_out;
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(
6457c478bd9Sstevel@tonic-gate 	    softs->mbox_dma_handle,
6467c478bd9Sstevel@tonic-gate 	    sizeof (struct amr_mailbox) + 16,
6477c478bd9Sstevel@tonic-gate 	    &accattr,
6487c478bd9Sstevel@tonic-gate 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6497c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP,
6507c478bd9Sstevel@tonic-gate 	    NULL,
6517c478bd9Sstevel@tonic-gate 	    (caddr_t *)(&softs->mbox),
6527c478bd9Sstevel@tonic-gate 	    &mbox_len,
6537c478bd9Sstevel@tonic-gate 	    &softs->mbox_acc_handle) !=
6547c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "Cannot alloc dma memory for mailbox"));
6577c478bd9Sstevel@tonic-gate 		goto error_out;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	if (ddi_dma_addr_bind_handle(
6617c478bd9Sstevel@tonic-gate 	    softs->mbox_dma_handle,
6627c478bd9Sstevel@tonic-gate 	    NULL,
6637c478bd9Sstevel@tonic-gate 	    (caddr_t)softs->mbox,
664e687df1aSyw161884 	    mbox_len,
6657c478bd9Sstevel@tonic-gate 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
6667c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP,
6677c478bd9Sstevel@tonic-gate 	    NULL,
6687c478bd9Sstevel@tonic-gate 	    &softs->mbox_dma_cookie,
6697c478bd9Sstevel@tonic-gate 	    &softs->mbox_dma_cookien) != DDI_DMA_MAPPED) {
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "Cannot bind dma memory for mailbox"));
6727c478bd9Sstevel@tonic-gate 		goto error_out;
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	if (softs->mbox_dma_cookien != 1)
6767c478bd9Sstevel@tonic-gate 		goto error_out;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	/* The phy address of mailbox must be aligned on a 16-byte boundary */
6797c478bd9Sstevel@tonic-gate 	move = 16 - (((uint32_t)softs->mbox_dma_cookie.dmac_address)&0xf);
6807c478bd9Sstevel@tonic-gate 	softs->mbox_phyaddr =
6817c478bd9Sstevel@tonic-gate 	    (softs->mbox_dma_cookie.dmac_address + move);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	softs->mailbox =
6847c478bd9Sstevel@tonic-gate 	    (struct amr_mailbox *)(((uintptr_t)softs->mbox) + move);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "phraddy=%x, mailbox=%p, softs->mbox=%p, move=%x",
6877c478bd9Sstevel@tonic-gate 	    softs->mbox_phyaddr, (void *)softs->mailbox,
6887c478bd9Sstevel@tonic-gate 	    softs->mbox, move));
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate error_out:
6937c478bd9Sstevel@tonic-gate 	if (softs->mbox_dma_cookien)
6947c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(softs->mbox_dma_handle);
6957c478bd9Sstevel@tonic-gate 	if (softs->mbox_acc_handle) {
6967c478bd9Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&(softs->mbox_acc_handle));
6977c478bd9Sstevel@tonic-gate 		softs->mbox_acc_handle = NULL;
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	if (softs->mbox_dma_handle) {
7007c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&softs->mbox_dma_handle);
7017c478bd9Sstevel@tonic-gate 		softs->mbox_dma_handle = NULL;
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate /*
7087c478bd9Sstevel@tonic-gate  * Perform a periodic check of the controller status
7097c478bd9Sstevel@tonic-gate  */
7107c478bd9Sstevel@tonic-gate static void
amr_periodic(void * data)7117c478bd9Sstevel@tonic-gate amr_periodic(void *data)
7127c478bd9Sstevel@tonic-gate {
7137c478bd9Sstevel@tonic-gate 	uint32_t		i;
7147c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)data;
7157c478bd9Sstevel@tonic-gate 	struct scsi_pkt 	*pkt;
7167c478bd9Sstevel@tonic-gate 	register struct amr_command	*ac;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	for (i = 0; i < softs->sg_max_count; i++) {
7197c478bd9Sstevel@tonic-gate 		if (softs->busycmd[i] == NULL)
7207c478bd9Sstevel@tonic-gate 			continue;
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		mutex_enter(&softs->cmd_mutex);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 		if (softs->busycmd[i] == NULL) {
7257c478bd9Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7267c478bd9Sstevel@tonic-gate 			continue;
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 		pkt = softs->busycmd[i]->pkt;
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		if ((pkt->pkt_time != 0) &&
7327c478bd9Sstevel@tonic-gate 		    (ddi_get_time() -
7337c478bd9Sstevel@tonic-gate 		    softs->busycmd[i]->ac_timestamp >
7347c478bd9Sstevel@tonic-gate 		    pkt->pkt_time)) {
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
737e687df1aSyw161884 			    "!timed out packet detected,\
7387c478bd9Sstevel@tonic-gate 				sc = %p, pkt = %p, index = %d, ac = %p",
7397c478bd9Sstevel@tonic-gate 			    (void *)softs,
7407c478bd9Sstevel@tonic-gate 			    (void *)pkt,
7417c478bd9Sstevel@tonic-gate 			    i,
7427c478bd9Sstevel@tonic-gate 			    (void *)softs->busycmd[i]);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 			ac = softs->busycmd[i];
7457c478bd9Sstevel@tonic-gate 			ac->ac_next = NULL;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 			/* pull command from the busy index */
7487c478bd9Sstevel@tonic-gate 			softs->busycmd[i] = NULL;
7497c478bd9Sstevel@tonic-gate 			if (softs->amr_busyslots > 0)
7507c478bd9Sstevel@tonic-gate 				softs->amr_busyslots--;
7517c478bd9Sstevel@tonic-gate 			if (softs->amr_busyslots == 0)
7527c478bd9Sstevel@tonic-gate 				cv_broadcast(&softs->cmd_cv);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 			pkt = ac->pkt;
7577c478bd9Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
7587c478bd9Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_TIMEOUT;
7597c478bd9Sstevel@tonic-gate 			pkt->pkt_reason = CMD_TIMEOUT;
7609c57abc8Ssrivijitha dugganapalli 			if (!(pkt->pkt_flags & FLAG_NOINTR)) {
7617c478bd9Sstevel@tonic-gate 				/* call pkt callback */
7629c57abc8Ssrivijitha dugganapalli 				scsi_hba_pkt_comp(pkt);
7637c478bd9Sstevel@tonic-gate 			}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 		} else {
7667c478bd9Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
7677c478bd9Sstevel@tonic-gate 		}
7687c478bd9Sstevel@tonic-gate 	}
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/* restart the amr timer */
7717c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->periodic_mutex);
7727c478bd9Sstevel@tonic-gate 	if (softs->state & AMR_STATE_TIMEOUT_ENABLED)
7737c478bd9Sstevel@tonic-gate 		softs->timeout_t = timeout(amr_periodic, (void *)softs,
7747c478bd9Sstevel@tonic-gate 		    drv_usectohz(500000*AMR_PERIODIC_TIMEOUT));
7757c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->periodic_mutex);
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate  * Interrogate the controller for the operational parameters we require.
7807c478bd9Sstevel@tonic-gate  */
7817c478bd9Sstevel@tonic-gate static int
amr_query_controller(struct amr_softs * softs)7827c478bd9Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	struct amr_enquiry3	*aex;
7857c478bd9Sstevel@tonic-gate 	struct amr_prodinfo	*ap;
7867c478bd9Sstevel@tonic-gate 	struct amr_enquiry	*ae;
7877c478bd9Sstevel@tonic-gate 	uint32_t		ldrv;
7887c478bd9Sstevel@tonic-gate 	int			instance;
7897c478bd9Sstevel@tonic-gate 
7907c478bd9Sstevel@tonic-gate 	/*
7917c478bd9Sstevel@tonic-gate 	 * If we haven't found the real limit yet, let us have a couple of
7927c478bd9Sstevel@tonic-gate 	 * commands in order to be able to probe.
7937c478bd9Sstevel@tonic-gate 	 */
7947c478bd9Sstevel@tonic-gate 	if (softs->maxio == 0)
7957c478bd9Sstevel@tonic-gate 		softs->maxio = 2;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	instance = ddi_get_instance(softs->dev_info_p);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	/*
8007c478bd9Sstevel@tonic-gate 	 * Try to issue an ENQUIRY3 command
8017c478bd9Sstevel@tonic-gate 	 */
8027c478bd9Sstevel@tonic-gate 	if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG,
8037c478bd9Sstevel@tonic-gate 	    AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) {
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry"));
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 		for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) {
8087c478bd9Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_size =
8097c478bd9Sstevel@tonic-gate 			    aex->ae_drivesize[ldrv];
8107c478bd9Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_state =
8117c478bd9Sstevel@tonic-gate 			    aex->ae_drivestate[ldrv];
8127c478bd9Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_properties =
8137c478bd9Sstevel@tonic-gate 			    aex->ae_driveprop[ldrv];
8147c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_NOTE,
8157c478bd9Sstevel@tonic-gate 			    "  drive %d: size: %d state %x properties %x\n",
8167c478bd9Sstevel@tonic-gate 			    ldrv,
8177c478bd9Sstevel@tonic-gate 			    softs->logic_drive[ldrv].al_size,
8187c478bd9Sstevel@tonic-gate 			    softs->logic_drive[ldrv].al_state,
8197c478bd9Sstevel@tonic-gate 			    softs->logic_drive[ldrv].al_properties));
8207c478bd9Sstevel@tonic-gate 
82119397407SSherry Moore 			if (softs->logic_drive[ldrv].al_state ==
82219397407SSherry Moore 			    AMR_LDRV_OFFLINE)
82319397407SSherry Moore 				cmn_err(CE_NOTE,
82419397407SSherry Moore 				    "!instance %d log-drive %d is offline",
8257c478bd9Sstevel@tonic-gate 				    instance, ldrv);
8267c478bd9Sstevel@tonic-gate 			else
8277c478bd9Sstevel@tonic-gate 				softs->amr_nlogdrives++;
8287c478bd9Sstevel@tonic-gate 		}
8297c478bd9Sstevel@tonic-gate 		kmem_free(aex, AMR_ENQ_BUFFER_SIZE);
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 		if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE,
8327c478bd9Sstevel@tonic-gate 		    AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) {
8337c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_NOTE,
8347c478bd9Sstevel@tonic-gate 			    "Cannot obtain product data from controller"));
8357c478bd9Sstevel@tonic-gate 			return (EIO);
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		softs->maxdrives = AMR_40LD_MAXDRIVES;
8397c478bd9Sstevel@tonic-gate 		softs->maxchan = ap->ap_nschan;
8407c478bd9Sstevel@tonic-gate 		softs->maxio = ap->ap_maxio;
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 		bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver,
8437c478bd9Sstevel@tonic-gate 		    AMR_FIRMWARE_VER_SIZE);
8447c478bd9Sstevel@tonic-gate 		softs->amr_product_info.
8457c478bd9Sstevel@tonic-gate 		    pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		bcopy(ap->ap_product, softs->amr_product_info.pi_product_name,
8487c478bd9Sstevel@tonic-gate 		    AMR_PRODUCT_INFO_SIZE);
8497c478bd9Sstevel@tonic-gate 		softs->amr_product_info.
8507c478bd9Sstevel@tonic-gate 		    pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0;
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 		kmem_free(ap, AMR_ENQ_BUFFER_SIZE);
8537c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio));
8547c478bd9Sstevel@tonic-gate 	} else {
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "First enquiry failed, \
8577c478bd9Sstevel@tonic-gate 				so try another way"));
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 		/* failed, try the 8LD ENQUIRY commands */
8607c478bd9Sstevel@tonic-gate 		if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
8617c478bd9Sstevel@tonic-gate 		    AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0))
8627c478bd9Sstevel@tonic-gate 		    == NULL) {
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 			if ((ae = (struct amr_enquiry *)amr_enquiry(softs,
8657c478bd9Sstevel@tonic-gate 			    AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0))
8667c478bd9Sstevel@tonic-gate 			    == NULL) {
8677c478bd9Sstevel@tonic-gate 				AMRDB_PRINT((CE_NOTE,
8687c478bd9Sstevel@tonic-gate 				    "Cannot obtain configuration data"));
8697c478bd9Sstevel@tonic-gate 				return (EIO);
8707c478bd9Sstevel@tonic-gate 			}
8717c478bd9Sstevel@tonic-gate 			ae->ae_signature = 0;
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 		/*
8757c478bd9Sstevel@tonic-gate 		 * Fetch current state of logical drives.
8767c478bd9Sstevel@tonic-gate 		 */
8777c478bd9Sstevel@tonic-gate 		for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) {
8787c478bd9Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_size =
8797c478bd9Sstevel@tonic-gate 			    ae->ae_ldrv.al_size[ldrv];
8807c478bd9Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_state =
8817c478bd9Sstevel@tonic-gate 			    ae->ae_ldrv.al_state[ldrv];
8827c478bd9Sstevel@tonic-gate 			softs->logic_drive[ldrv].al_properties =
8837c478bd9Sstevel@tonic-gate 			    ae->ae_ldrv.al_properties[ldrv];
8847c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_NOTE,
8857c478bd9Sstevel@tonic-gate 			    " ********* drive %d: %d state %x properties %x",
8867c478bd9Sstevel@tonic-gate 			    ldrv,
8877c478bd9Sstevel@tonic-gate 			    softs->logic_drive[ldrv].al_size,
8887c478bd9Sstevel@tonic-gate 			    softs->logic_drive[ldrv].al_state,
8897c478bd9Sstevel@tonic-gate 			    softs->logic_drive[ldrv].al_properties));
8907c478bd9Sstevel@tonic-gate 
89119397407SSherry Moore 			if (softs->logic_drive[ldrv].al_state ==
89219397407SSherry Moore 			    AMR_LDRV_OFFLINE)
89319397407SSherry Moore 				cmn_err(CE_NOTE,
89419397407SSherry Moore 				    "!instance %d log-drive %d is offline",
8957c478bd9Sstevel@tonic-gate 				    instance, ldrv);
8967c478bd9Sstevel@tonic-gate 			else
8977c478bd9Sstevel@tonic-gate 				softs->amr_nlogdrives++;
8987c478bd9Sstevel@tonic-gate 		}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		softs->maxdrives = AMR_8LD_MAXDRIVES;
9017c478bd9Sstevel@tonic-gate 		softs->maxchan = ae->ae_adapter.aa_channels;
9027c478bd9Sstevel@tonic-gate 		softs->maxio = ae->ae_adapter.aa_maxio;
9037c478bd9Sstevel@tonic-gate 		kmem_free(ae, AMR_ENQ_BUFFER_SIZE);
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	/*
9077c478bd9Sstevel@tonic-gate 	 * Mark remaining drives as unused.
9087c478bd9Sstevel@tonic-gate 	 */
9097c478bd9Sstevel@tonic-gate 	for (; ldrv < AMR_MAXLD; ldrv++)
9107c478bd9Sstevel@tonic-gate 		softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE;
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	/*
9137c478bd9Sstevel@tonic-gate 	 * Cap the maximum number of outstanding I/Os.  AMI's driver
9147c478bd9Sstevel@tonic-gate 	 * doesn't trust the controller's reported value, and lockups have
9157c478bd9Sstevel@tonic-gate 	 * been seen when we do.
9167c478bd9Sstevel@tonic-gate 	 */
9177c478bd9Sstevel@tonic-gate 	softs->maxio = MIN(softs->maxio, AMR_LIMITCMD);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate /*
9237c478bd9Sstevel@tonic-gate  * Run a generic enquiry-style command.
9247c478bd9Sstevel@tonic-gate  */
9257c478bd9Sstevel@tonic-gate static void *
amr_enquiry(struct amr_softs * softs,size_t bufsize,uint8_t cmd,uint8_t cmdsub,uint8_t cmdqual)9267c478bd9Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd,
9277c478bd9Sstevel@tonic-gate 				uint8_t cmdsub, uint8_t cmdqual)
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate 	struct amr_command	ac;
9307c478bd9Sstevel@tonic-gate 	void			*result;
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	result = NULL;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9357c478bd9Sstevel@tonic-gate 	ac.ac_softs = softs;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/* set command flags */
9387c478bd9Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	/* build the command proper */
9417c478bd9Sstevel@tonic-gate 	ac.mailbox.mb_command	= cmd;
9427c478bd9Sstevel@tonic-gate 	ac.mailbox.mb_cmdsub	= cmdsub;
9437c478bd9Sstevel@tonic-gate 	ac.mailbox.mb_cmdqual	= cmdqual;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS)
9467c478bd9Sstevel@tonic-gate 		return (NULL);
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if (amr_poll_command(&ac) || ac.ac_status != 0) {
9497c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll command, goto out"));
9507c478bd9Sstevel@tonic-gate 		amr_enquiry_unmapcmd(&ac);
9517c478bd9Sstevel@tonic-gate 		return (NULL);
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	/* allocate the response structure */
9557c478bd9Sstevel@tonic-gate 	result = kmem_zalloc(bufsize, KM_SLEEP);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	bcopy(ac.ac_data, result, bufsize);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	amr_enquiry_unmapcmd(&ac);
9607c478bd9Sstevel@tonic-gate 	return (result);
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate /*
9647c478bd9Sstevel@tonic-gate  * Flush the controller's internal cache, return status.
9657c478bd9Sstevel@tonic-gate  */
9667c478bd9Sstevel@tonic-gate static int
amr_flush(struct amr_softs * softs)9677c478bd9Sstevel@tonic-gate amr_flush(struct amr_softs *softs)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate 	struct amr_command	ac;
9707c478bd9Sstevel@tonic-gate 	int			error = 0;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	bzero(&ac, sizeof (struct amr_command));
9737c478bd9Sstevel@tonic-gate 	ac.ac_softs = softs;
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate 	ac.ac_flags |= AMR_CMD_DATAOUT;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	/* build the command proper */
9787c478bd9Sstevel@tonic-gate 	ac.mailbox.mb_command = AMR_CMD_FLUSH;
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	/* have to poll, as the system may be going down or otherwise damaged */
9817c478bd9Sstevel@tonic-gate 	if (error = amr_poll_command(&ac)) {
9827c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE, "can not poll this cmd"));
9837c478bd9Sstevel@tonic-gate 		return (error);
9847c478bd9Sstevel@tonic-gate 	}
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	return (error);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate /*
9907c478bd9Sstevel@tonic-gate  * Take a command, submit it to the controller and wait for it to return.
9917c478bd9Sstevel@tonic-gate  * Returns nonzero on error.  Can be safely called with interrupts enabled.
9927c478bd9Sstevel@tonic-gate  */
9937c478bd9Sstevel@tonic-gate static int
amr_poll_command(struct amr_command * ac)9947c478bd9Sstevel@tonic-gate amr_poll_command(struct amr_command *ac)
9957c478bd9Sstevel@tonic-gate {
9967c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
9977c478bd9Sstevel@tonic-gate 	volatile uint32_t	done_flag;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)",
10007c478bd9Sstevel@tonic-gate 	    (void *)&ac->mailbox,
10017c478bd9Sstevel@tonic-gate 	    (void *)softs->mailbox,
10027c478bd9Sstevel@tonic-gate 	    (uint32_t)AMR_MBOX_CMDSIZE));
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	while (softs->amr_busyslots != 0)
10077c478bd9Sstevel@tonic-gate 		cv_wait(&softs->cmd_cv, &softs->cmd_mutex);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/*
10107c478bd9Sstevel@tonic-gate 	 * For read/write commands, the scatter/gather table should be
10117c478bd9Sstevel@tonic-gate 	 * filled, and the last entry in scatter/gather table will be used.
10127c478bd9Sstevel@tonic-gate 	 */
10137c478bd9Sstevel@tonic-gate 	if ((ac->mailbox.mb_command == AMR_CMD_LREAD) ||
10147c478bd9Sstevel@tonic-gate 	    (ac->mailbox.mb_command == AMR_CMD_LWRITE)) {
10157c478bd9Sstevel@tonic-gate 		bcopy(ac->sgtable,
10167c478bd9Sstevel@tonic-gate 		    softs->sg_items[softs->sg_max_count - 1].sg_table,
10177c478bd9Sstevel@tonic-gate 		    sizeof (struct amr_sgentry) * AMR_NSEG);
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 		(void) ddi_dma_sync(
10207c478bd9Sstevel@tonic-gate 		    softs->sg_items[softs->sg_max_count - 1].sg_handle,
10217c478bd9Sstevel@tonic-gate 		    0, 0, DDI_DMA_SYNC_FORDEV);
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 		ac->mailbox.mb_physaddr =
10247c478bd9Sstevel@tonic-gate 		    softs->sg_items[softs->sg_max_count - 1].sg_phyaddr;
10257c478bd9Sstevel@tonic-gate 	}
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	/* sync the dma memory */
10307c478bd9Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	/* clear the poll/ack fields in the mailbox */
10337c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID;
10347c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS;
10357c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS;
10367c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10377c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_ack = 0;
10387c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_busy = 1;
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	/* sync the dma memory */
10437c478bd9Sstevel@tonic-gate 	(void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
10447c478bd9Sstevel@tonic-gate 
10457c478bd9Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS),
10467c478bd9Sstevel@tonic-gate 	    1000, done_flag);
10477c478bd9Sstevel@tonic-gate 	if (!done_flag) {
10487c478bd9Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10497c478bd9Sstevel@tonic-gate 		return (1);
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	ac->ac_status = softs->mailbox->mb_status;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag);
10557c478bd9Sstevel@tonic-gate 	if (!done_flag) {
10567c478bd9Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10577c478bd9Sstevel@tonic-gate 		return (1);
10587c478bd9Sstevel@tonic-gate 	}
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_poll = 0;
10617c478bd9Sstevel@tonic-gate 	softs->mailbox->mb_ack = AMR_POLL_ACK;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	/* acknowledge that we have the commands */
10647c478bd9Sstevel@tonic-gate 	AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate 	AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag);
10677c478bd9Sstevel@tonic-gate 	if (!done_flag) {
10687c478bd9Sstevel@tonic-gate 		mutex_exit(&softs->cmd_mutex);
10697c478bd9Sstevel@tonic-gate 		return (1);
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
10737c478bd9Sstevel@tonic-gate 	return (ac->ac_status != AMR_STATUS_SUCCESS);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate /*
10777c478bd9Sstevel@tonic-gate  * setup the scatter/gather table
10787c478bd9Sstevel@tonic-gate  */
10797c478bd9Sstevel@tonic-gate static int
amr_setup_sg(struct amr_softs * softs)10807c478bd9Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs)
10817c478bd9Sstevel@tonic-gate {
10827c478bd9Sstevel@tonic-gate 	uint32_t		i;
10837c478bd9Sstevel@tonic-gate 	size_t			len;
10847c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t	cookie;
10857c478bd9Sstevel@tonic-gate 	uint_t			cookien;
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	softs->sg_max_count = 0;
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	for (i = 0; i < AMR_MAXCMD; i++) {
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 		/* reset the cookien */
10927c478bd9Sstevel@tonic-gate 		cookien = 0;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
10957c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(
10967c478bd9Sstevel@tonic-gate 		    softs->dev_info_p,
10977c478bd9Sstevel@tonic-gate 		    &addr_dma_attr,
10987c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP,
10997c478bd9Sstevel@tonic-gate 		    NULL,
11007c478bd9Sstevel@tonic-gate 		    &((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) {
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11037c478bd9Sstevel@tonic-gate 			"Cannot alloc dma handle for s/g table"));
11047c478bd9Sstevel@tonic-gate 			goto error_out;
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle,
11087c478bd9Sstevel@tonic-gate 		    sizeof (struct amr_sgentry) * AMR_NSEG,
11097c478bd9Sstevel@tonic-gate 		    &accattr,
11107c478bd9Sstevel@tonic-gate 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
11117c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, NULL,
11127c478bd9Sstevel@tonic-gate 		    (caddr_t *)(&(softs->sg_items[i]).sg_table),
11137c478bd9Sstevel@tonic-gate 		    &len,
11147c478bd9Sstevel@tonic-gate 		    &(softs->sg_items[i]).sg_acc_handle)
11157c478bd9Sstevel@tonic-gate 		    != DDI_SUCCESS) {
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11187c478bd9Sstevel@tonic-gate 			"Cannot allocate DMA memory"));
11197c478bd9Sstevel@tonic-gate 			goto error_out;
11207c478bd9Sstevel@tonic-gate 		}
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(
11237c478bd9Sstevel@tonic-gate 		    (softs->sg_items[i]).sg_handle,
11247c478bd9Sstevel@tonic-gate 		    NULL,
11257c478bd9Sstevel@tonic-gate 		    (caddr_t)((softs->sg_items[i]).sg_table),
1126e687df1aSyw161884 		    len,
11277c478bd9Sstevel@tonic-gate 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
11287c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP,
11297c478bd9Sstevel@tonic-gate 		    NULL,
11307c478bd9Sstevel@tonic-gate 		    &cookie,
11317c478bd9Sstevel@tonic-gate 		    &cookien) != DDI_DMA_MAPPED) {
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
11347c478bd9Sstevel@tonic-gate 			"Cannot bind communication area for s/g table"));
11357c478bd9Sstevel@tonic-gate 			goto error_out;
11367c478bd9Sstevel@tonic-gate 		}
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 		if (cookien != 1)
11397c478bd9Sstevel@tonic-gate 			goto error_out;
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 		softs->sg_items[i].sg_phyaddr = cookie.dmac_address;
11427c478bd9Sstevel@tonic-gate 		softs->sg_max_count++;
11437c478bd9Sstevel@tonic-gate 	}
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate error_out:
11487c478bd9Sstevel@tonic-gate 	/*
11497c478bd9Sstevel@tonic-gate 	 * Couldn't allocate/initialize all of the sg table entries.
11507c478bd9Sstevel@tonic-gate 	 * Clean up the partially-initialized entry before returning.
11517c478bd9Sstevel@tonic-gate 	 */
11527c478bd9Sstevel@tonic-gate 	if (cookien) {
11537c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_acc_handle) {
11567c478bd9Sstevel@tonic-gate 		(void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle));
11577c478bd9Sstevel@tonic-gate 		(softs->sg_items[i]).sg_acc_handle = NULL;
11587c478bd9Sstevel@tonic-gate 	}
11597c478bd9Sstevel@tonic-gate 	if ((softs->sg_items[i]).sg_handle) {
11607c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle));
11617c478bd9Sstevel@tonic-gate 		(softs->sg_items[i]).sg_handle = NULL;
11627c478bd9Sstevel@tonic-gate 	}
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	/*
11657c478bd9Sstevel@tonic-gate 	 * At least two sg table entries are needed. One is for regular data
11667c478bd9Sstevel@tonic-gate 	 * I/O commands, the other is for poll I/O commands.
11677c478bd9Sstevel@tonic-gate 	 */
11687c478bd9Sstevel@tonic-gate 	return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate /*
11727c478bd9Sstevel@tonic-gate  * Map/unmap (ac)'s data in the controller's addressable space as required.
11737c478bd9Sstevel@tonic-gate  *
11747c478bd9Sstevel@tonic-gate  * These functions may be safely called multiple times on a given command.
11757c478bd9Sstevel@tonic-gate  */
11767c478bd9Sstevel@tonic-gate static void
amr_setup_dmamap(struct amr_command * ac,ddi_dma_cookie_t * buffer_dma_cookiep,int nsegments)11777c478bd9Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep,
11787c478bd9Sstevel@tonic-gate 		int nsegments)
11797c478bd9Sstevel@tonic-gate {
11807c478bd9Sstevel@tonic-gate 	struct amr_sgentry	*sg;
11817c478bd9Sstevel@tonic-gate 	uint32_t		i, size;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	sg = ac->sgtable;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	size = 0;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = (uint8_t)nsegments;
11887c478bd9Sstevel@tonic-gate 	for (i = 0; i < nsegments; i++, sg++) {
11897c478bd9Sstevel@tonic-gate 		sg->sg_addr = buffer_dma_cookiep->dmac_address;
11907c478bd9Sstevel@tonic-gate 		sg->sg_count = buffer_dma_cookiep->dmac_size;
11917c478bd9Sstevel@tonic-gate 		size += sg->sg_count;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 		/*
11947c478bd9Sstevel@tonic-gate 		 * There is no next cookie if the end of the current
11957c478bd9Sstevel@tonic-gate 		 * window is reached. Otherwise, the next cookie
11967c478bd9Sstevel@tonic-gate 		 * would be found.
11977c478bd9Sstevel@tonic-gate 		 */
11987c478bd9Sstevel@tonic-gate 		if ((ac->current_cookie + i + 1) != ac->num_of_cookie)
11997c478bd9Sstevel@tonic-gate 			ddi_dma_nextcookie(ac->buffer_dma_handle,
12007c478bd9Sstevel@tonic-gate 			    buffer_dma_cookiep);
12017c478bd9Sstevel@tonic-gate 	}
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 	ac->transfer_size = size;
12047c478bd9Sstevel@tonic-gate 	ac->data_transfered += size;
12057c478bd9Sstevel@tonic-gate }
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 
12087c478bd9Sstevel@tonic-gate /*
12097c478bd9Sstevel@tonic-gate  * map the amr command for enquiry, allocate the DMA resource
12107c478bd9Sstevel@tonic-gate  */
12117c478bd9Sstevel@tonic-gate static int
amr_enquiry_mapcmd(struct amr_command * ac,uint32_t data_size)12127c478bd9Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size)
12137c478bd9Sstevel@tonic-gate {
12147c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs = ac->ac_softs;
12157c478bd9Sstevel@tonic-gate 	size_t			len;
12167c478bd9Sstevel@tonic-gate 	uint_t			dma_flags;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x",
12197c478bd9Sstevel@tonic-gate 	    (void *)ac, ac->ac_flags));
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
12227c478bd9Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
12237c478bd9Sstevel@tonic-gate 	} else {
12247c478bd9Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	dma_flags |= DDI_DMA_CONSISTENT;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	/* process the DMA by address bind mode */
12307c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(softs->dev_info_p,
12317c478bd9Sstevel@tonic-gate 	    &addr_dma_attr, DDI_DMA_SLEEP, NULL,
12327c478bd9Sstevel@tonic-gate 	    &ac->buffer_dma_handle) !=
12337c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12367c478bd9Sstevel@tonic-gate 		"Cannot allocate addr DMA tag"));
12377c478bd9Sstevel@tonic-gate 		goto error_out;
12387c478bd9Sstevel@tonic-gate 	}
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(ac->buffer_dma_handle,
12417c478bd9Sstevel@tonic-gate 	    data_size,
12427c478bd9Sstevel@tonic-gate 	    &accattr,
12437c478bd9Sstevel@tonic-gate 	    dma_flags,
12447c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP,
12457c478bd9Sstevel@tonic-gate 	    NULL,
12467c478bd9Sstevel@tonic-gate 	    (caddr_t *)&ac->ac_data,
12477c478bd9Sstevel@tonic-gate 	    &len,
12487c478bd9Sstevel@tonic-gate 	    &ac->buffer_acc_handle) !=
12497c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12527c478bd9Sstevel@tonic-gate 		"Cannot allocate DMA memory"));
12537c478bd9Sstevel@tonic-gate 		goto error_out;
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	if ((ddi_dma_addr_bind_handle(
12577c478bd9Sstevel@tonic-gate 	    ac->buffer_dma_handle,
1258e687df1aSyw161884 	    NULL, ac->ac_data, len, dma_flags,
12597c478bd9Sstevel@tonic-gate 	    DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie,
12607c478bd9Sstevel@tonic-gate 	    &ac->num_of_cookie)) != DDI_DMA_MAPPED) {
12617c478bd9Sstevel@tonic-gate 
12627c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN,
12637c478bd9Sstevel@tonic-gate 		    "Cannot bind addr for dma"));
12647c478bd9Sstevel@tonic-gate 		goto error_out;
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0;
12707c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_nsgelem = 0;
12717c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_physaddr = ac->ac_dataphys;
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	ac->ac_flags |= AMR_CMD_MAPPED;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
12767c478bd9Sstevel@tonic-gate 
12777c478bd9Sstevel@tonic-gate error_out:
12787c478bd9Sstevel@tonic-gate 	if (ac->num_of_cookie)
12797c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
12807c478bd9Sstevel@tonic-gate 	if (ac->buffer_acc_handle) {
12817c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&ac->buffer_acc_handle);
12827c478bd9Sstevel@tonic-gate 		ac->buffer_acc_handle = NULL;
12837c478bd9Sstevel@tonic-gate 	}
12847c478bd9Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
12857c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
12867c478bd9Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
12877c478bd9Sstevel@tonic-gate 	}
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
12907c478bd9Sstevel@tonic-gate }
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate /*
12937c478bd9Sstevel@tonic-gate  * unmap the amr command for enquiry, free the DMA resource
12947c478bd9Sstevel@tonic-gate  */
12957c478bd9Sstevel@tonic-gate static void
amr_enquiry_unmapcmd(struct amr_command * ac)12967c478bd9Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac)
12977c478bd9Sstevel@tonic-gate {
12987c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p",
12997c478bd9Sstevel@tonic-gate 	    (void *)ac));
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
13027c478bd9Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) {
13037c478bd9Sstevel@tonic-gate 		if (ac->buffer_dma_handle)
13047c478bd9Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(
13057c478bd9Sstevel@tonic-gate 			    ac->buffer_dma_handle);
13067c478bd9Sstevel@tonic-gate 		if (ac->buffer_acc_handle) {
13077c478bd9Sstevel@tonic-gate 			ddi_dma_mem_free(&ac->buffer_acc_handle);
13087c478bd9Sstevel@tonic-gate 			ac->buffer_acc_handle = NULL;
13097c478bd9Sstevel@tonic-gate 		}
13107c478bd9Sstevel@tonic-gate 		if (ac->buffer_dma_handle) {
13117c478bd9Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
13127c478bd9Sstevel@tonic-gate 			    &ac->buffer_dma_handle);
13137c478bd9Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13147c478bd9Sstevel@tonic-gate 		}
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate 
13177c478bd9Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
13187c478bd9Sstevel@tonic-gate }
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate /*
13217c478bd9Sstevel@tonic-gate  * map the amr command, allocate the DMA resource
13227c478bd9Sstevel@tonic-gate  */
13237c478bd9Sstevel@tonic-gate static int
amr_mapcmd(struct amr_command * ac,int (* callback)(),caddr_t arg)1324e687df1aSyw161884 amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate 	uint_t	dma_flags;
13277c478bd9Sstevel@tonic-gate 	off_t	off;
13287c478bd9Sstevel@tonic-gate 	size_t	len;
13297c478bd9Sstevel@tonic-gate 	int	error;
1330e687df1aSyw161884 	int	(*cb)(caddr_t);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x",
13337c478bd9Sstevel@tonic-gate 	    (void *)ac, ac->ac_flags));
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
13367c478bd9Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
13377c478bd9Sstevel@tonic-gate 	} else {
13387c478bd9Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
13397c478bd9Sstevel@tonic-gate 	}
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) {
13427c478bd9Sstevel@tonic-gate 		dma_flags |= DDI_DMA_CONSISTENT;
13437c478bd9Sstevel@tonic-gate 	}
13447c478bd9Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) {
13457c478bd9Sstevel@tonic-gate 		dma_flags |= DDI_DMA_PARTIAL;
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) {
13497c478bd9Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
13507c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
13517c478bd9Sstevel@tonic-gate 	}
13527c478bd9Sstevel@tonic-gate 
1353e687df1aSyw161884 	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
1354e687df1aSyw161884 
13557c478bd9Sstevel@tonic-gate 	/* if the command involves data at all, and hasn't been mapped */
13567c478bd9Sstevel@tonic-gate 	if (!(ac->ac_flags & AMR_CMD_MAPPED)) {
13577c478bd9Sstevel@tonic-gate 		/* process the DMA by buffer bind mode */
13587c478bd9Sstevel@tonic-gate 		error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle,
13597c478bd9Sstevel@tonic-gate 		    ac->ac_buf,
13607c478bd9Sstevel@tonic-gate 		    dma_flags,
1361e687df1aSyw161884 		    cb,
1362e687df1aSyw161884 		    arg,
13637c478bd9Sstevel@tonic-gate 		    &ac->buffer_dma_cookie,
13647c478bd9Sstevel@tonic-gate 		    &ac->num_of_cookie);
13657c478bd9Sstevel@tonic-gate 		switch (error) {
13667c478bd9Sstevel@tonic-gate 		case DDI_DMA_PARTIAL_MAP:
13677c478bd9Sstevel@tonic-gate 			if (ddi_dma_numwin(ac->buffer_dma_handle,
13687c478bd9Sstevel@tonic-gate 			    &ac->num_of_win) == DDI_FAILURE) {
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
13717c478bd9Sstevel@tonic-gate 				    "Cannot get dma num win"));
13727c478bd9Sstevel@tonic-gate 				(void) ddi_dma_unbind_handle(
13737c478bd9Sstevel@tonic-gate 				    ac->buffer_dma_handle);
13747c478bd9Sstevel@tonic-gate 				(void) ddi_dma_free_handle(
13757c478bd9Sstevel@tonic-gate 				    &ac->buffer_dma_handle);
13767c478bd9Sstevel@tonic-gate 				ac->buffer_dma_handle = NULL;
13777c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
13787c478bd9Sstevel@tonic-gate 			}
13797c478bd9Sstevel@tonic-gate 			ac->current_win = 0;
13807c478bd9Sstevel@tonic-gate 			break;
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
13837c478bd9Sstevel@tonic-gate 			ac->num_of_win = 1;
13847c478bd9Sstevel@tonic-gate 			ac->current_win = 0;
13857c478bd9Sstevel@tonic-gate 			break;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 		default:
13887c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
13897c478bd9Sstevel@tonic-gate 			    "Cannot bind buf for dma"));
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 			(void) ddi_dma_free_handle(
13927c478bd9Sstevel@tonic-gate 			    &ac->buffer_dma_handle);
13937c478bd9Sstevel@tonic-gate 			ac->buffer_dma_handle = NULL;
13947c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
13957c478bd9Sstevel@tonic-gate 		}
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 		ac->current_cookie = 0;
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_MAPPED;
14007c478bd9Sstevel@tonic-gate 	} else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) {
14017c478bd9Sstevel@tonic-gate 		/* get the next window */
14027c478bd9Sstevel@tonic-gate 		ac->current_win++;
14037c478bd9Sstevel@tonic-gate 		(void) ddi_dma_getwin(ac->buffer_dma_handle,
14047c478bd9Sstevel@tonic-gate 		    ac->current_win, &off, &len,
14057c478bd9Sstevel@tonic-gate 		    &ac->buffer_dma_cookie,
14067c478bd9Sstevel@tonic-gate 		    &ac->num_of_cookie);
14077c478bd9Sstevel@tonic-gate 		ac->current_cookie = 0;
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) {
14117c478bd9Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG);
14127c478bd9Sstevel@tonic-gate 		ac->current_cookie += AMR_NSEG;
14137c478bd9Sstevel@tonic-gate 	} else {
14147c478bd9Sstevel@tonic-gate 		amr_setup_dmamap(ac, &ac->buffer_dma_cookie,
14157c478bd9Sstevel@tonic-gate 		    ac->num_of_cookie - ac->current_cookie);
14167c478bd9Sstevel@tonic-gate 		ac->current_cookie = AMR_LAST_COOKIE_TAG;
14177c478bd9Sstevel@tonic-gate 	}
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate /*
14237c478bd9Sstevel@tonic-gate  * unmap the amr command, free the DMA resource
14247c478bd9Sstevel@tonic-gate  */
14257c478bd9Sstevel@tonic-gate static void
amr_unmapcmd(struct amr_command * ac)14267c478bd9Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac)
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p",
14297c478bd9Sstevel@tonic-gate 	    (void *)ac));
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	/* if the command involved data at all and was mapped */
14327c478bd9Sstevel@tonic-gate 	if ((ac->ac_flags & AMR_CMD_MAPPED) &&
14337c478bd9Sstevel@tonic-gate 	    ac->ac_buf && ac->buffer_dma_handle)
14347c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	ac->ac_flags &= ~AMR_CMD_MAPPED;
14377c478bd9Sstevel@tonic-gate }
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate static int
amr_setup_tran(dev_info_t * dip,struct amr_softs * softp)14407c478bd9Sstevel@tonic-gate amr_setup_tran(dev_info_t  *dip, struct amr_softs *softp)
14417c478bd9Sstevel@tonic-gate {
14427c478bd9Sstevel@tonic-gate 	softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	/*
14457c478bd9Sstevel@tonic-gate 	 * hba_private always points to the amr_softs struct
14467c478bd9Sstevel@tonic-gate 	 */
14477c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_hba_private	= softp;
14487c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_init		= amr_tran_tgt_init;
14497c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_probe		= scsi_hba_probe;
14507c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_start		= amr_tran_start;
14517c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_reset		= amr_tran_reset;
14527c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_getcap		= amr_tran_getcap;
14537c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_setcap		= amr_tran_setcap;
14547c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_init_pkt		= amr_tran_init_pkt;
14557c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_destroy_pkt	= amr_tran_destroy_pkt;
14567c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_dmafree		= amr_tran_dmafree;
14577c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_sync_pkt		= amr_tran_sync_pkt;
14587c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_abort		= NULL;
14597c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_tgt_free		= NULL;
14607c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_quiesce		= NULL;
14617c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_unquiesce		= NULL;
14627c478bd9Sstevel@tonic-gate 	softp->hba_tran->tran_sd		= NULL;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran,
14657c478bd9Sstevel@tonic-gate 	    SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
14667c478bd9Sstevel@tonic-gate 		scsi_hba_tran_free(softp->hba_tran);
14677c478bd9Sstevel@tonic-gate 		softp->hba_tran = NULL;
14687c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
14697c478bd9Sstevel@tonic-gate 	} else {
14707c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
14717c478bd9Sstevel@tonic-gate 	}
14727c478bd9Sstevel@tonic-gate }
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14757c478bd9Sstevel@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)14767c478bd9Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
14777c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t *tran, struct scsi_device *sd)
14787c478bd9Sstevel@tonic-gate {
14797c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
14807c478bd9Sstevel@tonic-gate 	ushort_t		target = sd->sd_address.a_target;
14817c478bd9Sstevel@tonic-gate 	uchar_t			lun = sd->sd_address.a_lun;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	softs = (struct amr_softs *)
14847c478bd9Sstevel@tonic-gate 	    (sd->sd_address.a_hba_tran->tran_hba_private);
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	if ((lun == 0) && (target < AMR_MAXLD))
14877c478bd9Sstevel@tonic-gate 		if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE)
14887c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate static int
amr_tran_start(struct scsi_address * ap,struct scsi_pkt * pkt)14947c478bd9Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt)
14957c478bd9Sstevel@tonic-gate {
14967c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
14977c478bd9Sstevel@tonic-gate 	struct buf		*bp = NULL;
14987c478bd9Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
14997c478bd9Sstevel@tonic-gate 	int			ret;
15007c478bd9Sstevel@tonic-gate 	uint32_t		capacity;
15017c478bd9Sstevel@tonic-gate 	struct amr_command	*ac;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d",
15047c478bd9Sstevel@tonic-gate 	    cdbp->scc_cmd, ap->a_target, ap->a_lun));
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
15077c478bd9Sstevel@tonic-gate 	if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) ||
15087c478bd9Sstevel@tonic-gate 	    (softs->logic_drive[ap->a_target].al_state ==
15097c478bd9Sstevel@tonic-gate 	    AMR_LDRV_OFFLINE)) {
15107c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "target or lun is not correct!");
15117c478bd9Sstevel@tonic-gate 		ret = TRAN_BADPKT;
15127c478bd9Sstevel@tonic-gate 		return (ret);
15137c478bd9Sstevel@tonic-gate 	}
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	ac = (struct amr_command *)pkt->pkt_ha_private;
15167c478bd9Sstevel@tonic-gate 	bp = ac->ac_buf;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd));
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	switch (cdbp->scc_cmd) {
15217c478bd9Sstevel@tonic-gate 	case SCMD_READ:		/* read		*/
15227c478bd9Sstevel@tonic-gate 	case SCMD_READ_G1:	/* read	g1	*/
15237c478bd9Sstevel@tonic-gate 	case SCMD_READ_BUFFER:	/* read buffer	*/
15247c478bd9Sstevel@tonic-gate 	case SCMD_WRITE:	/* write	*/
15257c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:	/* write g1	*/
15267c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_BUFFER:	/* write buffer	*/
15277c478bd9Sstevel@tonic-gate 		amr_rw_command(softs, pkt, ap->a_target);
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 		if (pkt->pkt_flags & FLAG_NOINTR) {
15307c478bd9Sstevel@tonic-gate 			(void) amr_poll_command(ac);
15317c478bd9Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
15327c478bd9Sstevel@tonic-gate 			    | STATE_GOT_TARGET
15337c478bd9Sstevel@tonic-gate 			    | STATE_SENT_CMD
15347c478bd9Sstevel@tonic-gate 			    | STATE_XFERRED_DATA);
15357c478bd9Sstevel@tonic-gate 			*pkt->pkt_scbp = 0;
15367c478bd9Sstevel@tonic-gate 			pkt->pkt_statistics |= STAT_SYNC;
15377c478bd9Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
15387c478bd9Sstevel@tonic-gate 		} else {
15397c478bd9Sstevel@tonic-gate 			mutex_enter(&softs->queue_mutex);
15407c478bd9Sstevel@tonic-gate 			if (softs->waiting_q_head == NULL) {
15417c478bd9Sstevel@tonic-gate 				ac->ac_prev = NULL;
15427c478bd9Sstevel@tonic-gate 				ac->ac_next = NULL;
15437c478bd9Sstevel@tonic-gate 				softs->waiting_q_head = ac;
15447c478bd9Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15457c478bd9Sstevel@tonic-gate 			} else {
15467c478bd9Sstevel@tonic-gate 				ac->ac_next = NULL;
15477c478bd9Sstevel@tonic-gate 				ac->ac_prev = softs->waiting_q_tail;
15487c478bd9Sstevel@tonic-gate 				softs->waiting_q_tail->ac_next = ac;
15497c478bd9Sstevel@tonic-gate 				softs->waiting_q_tail = ac;
15507c478bd9Sstevel@tonic-gate 			}
15517c478bd9Sstevel@tonic-gate 			mutex_exit(&softs->queue_mutex);
15527c478bd9Sstevel@tonic-gate 			amr_start_waiting_queue((void *)softs);
15537c478bd9Sstevel@tonic-gate 		}
15547c478bd9Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
15557c478bd9Sstevel@tonic-gate 		break;
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	case SCMD_INQUIRY: /* inquiry */
15587c478bd9Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
15597c478bd9Sstevel@tonic-gate 			struct scsi_inquiry inqp;
15607c478bd9Sstevel@tonic-gate 			uint8_t *sinq_p = (uint8_t *)&inqp;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 			bzero(&inqp, sizeof (struct scsi_inquiry));
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 			if (((char *)cdbp)[1] || ((char *)cdbp)[2]) {
15657c478bd9Sstevel@tonic-gate 				/*
15667c478bd9Sstevel@tonic-gate 				 * The EVDP and pagecode is
15677c478bd9Sstevel@tonic-gate 				 * not supported
15687c478bd9Sstevel@tonic-gate 				 */
15697c478bd9Sstevel@tonic-gate 				sinq_p[1] = 0xFF;
15707c478bd9Sstevel@tonic-gate 				sinq_p[2] = 0x0;
15717c478bd9Sstevel@tonic-gate 			} else {
15727c478bd9Sstevel@tonic-gate 				inqp.inq_len = AMR_INQ_ADDITIONAL_LEN;
15737c478bd9Sstevel@tonic-gate 				inqp.inq_ansi = AMR_INQ_ANSI_VER;
15747c478bd9Sstevel@tonic-gate 				inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT;
1575e687df1aSyw161884 				/* Enable Tag Queue */
1576e687df1aSyw161884 				inqp.inq_cmdque = 1;
15777c478bd9Sstevel@tonic-gate 				bcopy("MegaRaid", inqp.inq_vid,
15787c478bd9Sstevel@tonic-gate 				    sizeof (inqp.inq_vid));
15797c478bd9Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_product_name,
15807c478bd9Sstevel@tonic-gate 				    inqp.inq_pid,
15817c478bd9Sstevel@tonic-gate 				    AMR_PRODUCT_INFO_SIZE);
15827c478bd9Sstevel@tonic-gate 				bcopy(softs->amr_product_info.pi_firmware_ver,
15837c478bd9Sstevel@tonic-gate 				    inqp.inq_revision,
15847c478bd9Sstevel@tonic-gate 				    AMR_FIRMWARE_VER_SIZE);
15857c478bd9Sstevel@tonic-gate 			}
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 			amr_unmapcmd(ac);
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
15907c478bd9Sstevel@tonic-gate 				bp_mapin(bp);
15917c478bd9Sstevel@tonic-gate 			bcopy(&inqp, bp->b_un.b_addr,
15927c478bd9Sstevel@tonic-gate 			    sizeof (struct scsi_inquiry));
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
15957c478bd9Sstevel@tonic-gate 		}
15967c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
15977c478bd9Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
15987c478bd9Sstevel@tonic-gate 		    | STATE_GOT_TARGET
15997c478bd9Sstevel@tonic-gate 		    | STATE_SENT_CMD);
16007c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16017c478bd9Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16027c478bd9Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16039c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
16047c478bd9Sstevel@tonic-gate 		break;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	case SCMD_READ_CAPACITY: /* read capacity */
16077c478bd9Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16087c478bd9Sstevel@tonic-gate 			struct scsi_capacity cp;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 			capacity = softs->logic_drive[ap->a_target].al_size - 1;
16117c478bd9Sstevel@tonic-gate 			cp.capacity = BE_32(capacity);
16127c478bd9Sstevel@tonic-gate 			cp.lbasize = BE_32(512);
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 			amr_unmapcmd(ac);
16157c478bd9Sstevel@tonic-gate 
16167c478bd9Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16177c478bd9Sstevel@tonic-gate 				bp_mapin(bp);
16187c478bd9Sstevel@tonic-gate 			bcopy(&cp, bp->b_un.b_addr, 8);
16197c478bd9Sstevel@tonic-gate 		}
16207c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16217c478bd9Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16227c478bd9Sstevel@tonic-gate 		    | STATE_GOT_TARGET
16237c478bd9Sstevel@tonic-gate 		    | STATE_SENT_CMD
16247c478bd9Sstevel@tonic-gate 		    | STATE_XFERRED_DATA);
16257c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16267c478bd9Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16277c478bd9Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16289c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
16297c478bd9Sstevel@tonic-gate 		break;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SENSE:		/* mode sense */
16327c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SENSE_G1:	/* mode sense g1 */
16337c478bd9Sstevel@tonic-gate 		amr_unmapcmd(ac);
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 		capacity = softs->logic_drive[ap->a_target].al_size - 1;
16367c478bd9Sstevel@tonic-gate 		amr_mode_sense(cdbp, bp, capacity);
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16397c478bd9Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16407c478bd9Sstevel@tonic-gate 		    | STATE_GOT_TARGET
16417c478bd9Sstevel@tonic-gate 		    | STATE_SENT_CMD
16427c478bd9Sstevel@tonic-gate 		    | STATE_XFERRED_DATA);
16437c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16447c478bd9Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16457c478bd9Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16469c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
16477c478bd9Sstevel@tonic-gate 		break;
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:	/* test unit ready */
16507c478bd9Sstevel@tonic-gate 	case SCMD_REQUEST_SENSE:	/* request sense */
16517c478bd9Sstevel@tonic-gate 	case SCMD_FORMAT:		/* format */
16527c478bd9Sstevel@tonic-gate 	case SCMD_START_STOP:		/* start stop */
16537c478bd9Sstevel@tonic-gate 	case SCMD_SYNCHRONIZE_CACHE:	/* synchronize cache */
16547c478bd9Sstevel@tonic-gate 		if (bp && bp->b_un.b_addr && bp->b_bcount) {
16557c478bd9Sstevel@tonic-gate 			amr_unmapcmd(ac);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 			if (bp->b_flags & (B_PHYS | B_PAGEIO))
16587c478bd9Sstevel@tonic-gate 				bp_mapin(bp);
16597c478bd9Sstevel@tonic-gate 			bzero(bp->b_un.b_addr, bp->b_bcount);
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 			pkt->pkt_state |= STATE_XFERRED_DATA;
16627c478bd9Sstevel@tonic-gate 		}
16637c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_CMPLT;
16647c478bd9Sstevel@tonic-gate 		pkt->pkt_state |= (STATE_GOT_BUS
16657c478bd9Sstevel@tonic-gate 		    | STATE_GOT_TARGET
16667c478bd9Sstevel@tonic-gate 		    | STATE_SENT_CMD);
16677c478bd9Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16687c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16697c478bd9Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16709c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
16717c478bd9Sstevel@tonic-gate 		break;
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	default: /* any other commands */
16747c478bd9Sstevel@tonic-gate 		amr_unmapcmd(ac);
16757c478bd9Sstevel@tonic-gate 		pkt->pkt_reason = CMD_INCOMPLETE;
16767c478bd9Sstevel@tonic-gate 		pkt->pkt_state = (STATE_GOT_BUS
16777c478bd9Sstevel@tonic-gate 		    | STATE_GOT_TARGET
16787c478bd9Sstevel@tonic-gate 		    | STATE_SENT_CMD
16797c478bd9Sstevel@tonic-gate 		    | STATE_GOT_STATUS
16807c478bd9Sstevel@tonic-gate 		    | STATE_ARQ_DONE);
16817c478bd9Sstevel@tonic-gate 		ret = TRAN_ACCEPT;
16827c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
16837c478bd9Sstevel@tonic-gate 		amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST);
16847c478bd9Sstevel@tonic-gate 		if (!(pkt->pkt_flags & FLAG_NOINTR))
16859c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
16867c478bd9Sstevel@tonic-gate 		break;
16877c478bd9Sstevel@tonic-gate 	}
16887c478bd9Sstevel@tonic-gate 
16897c478bd9Sstevel@tonic-gate 	return (ret);
16907c478bd9Sstevel@tonic-gate }
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate /*
16937c478bd9Sstevel@tonic-gate  * tran_reset() will reset the bus/target/adapter to support the fault recovery
16947c478bd9Sstevel@tonic-gate  * functionality according to the "level" in interface. However, we got the
16957c478bd9Sstevel@tonic-gate  * confirmation from LSI that these HBA cards does not support any commands to
16967c478bd9Sstevel@tonic-gate  * reset bus/target/adapter/channel.
16977c478bd9Sstevel@tonic-gate  *
16987c478bd9Sstevel@tonic-gate  * If the tran_reset() return a FAILURE to the sd, the system will not
16997c478bd9Sstevel@tonic-gate  * continue to dump the core. But core dump is an crucial method to analyze
17007c478bd9Sstevel@tonic-gate  * problems in panic. Now we adopt a work around solution, that is to return
17017c478bd9Sstevel@tonic-gate  * a fake SUCCESS to sd during panic, which will force the system continue
17027c478bd9Sstevel@tonic-gate  * to dump core though the core may have problems in some situtation because
17037c478bd9Sstevel@tonic-gate  * some on-the-fly commands will continue DMAing data to the memory.
17047c478bd9Sstevel@tonic-gate  * In addition, the work around core dump method may not be performed
17057c478bd9Sstevel@tonic-gate  * successfully if the panic is caused by the HBA itself. So the work around
17067c478bd9Sstevel@tonic-gate  * solution is not a good example for the implementation of tran_reset(),
17077c478bd9Sstevel@tonic-gate  * the most reasonable approach should send a reset command to the adapter.
17087c478bd9Sstevel@tonic-gate  */
17097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17107c478bd9Sstevel@tonic-gate static int
amr_tran_reset(struct scsi_address * ap,int level)17117c478bd9Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level)
17127c478bd9Sstevel@tonic-gate {
17137c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
17147c478bd9Sstevel@tonic-gate 	volatile uint32_t	done_flag;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	if (ddi_in_panic()) {
17177c478bd9Sstevel@tonic-gate 		softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 		/* Acknowledge the card if there are any significant commands */
17207c478bd9Sstevel@tonic-gate 		while (softs->amr_busyslots > 0) {
17217c478bd9Sstevel@tonic-gate 			AMR_DELAY((softs->mailbox->mb_busy == 0),
17227c478bd9Sstevel@tonic-gate 			    AMR_RETRYCOUNT, done_flag);
17237c478bd9Sstevel@tonic-gate 			if (!done_flag) {
17247c478bd9Sstevel@tonic-gate 				/*
17257c478bd9Sstevel@tonic-gate 				 * command not completed, indicate the
17267c478bd9Sstevel@tonic-gate 				 * problem and continue get ac
17277c478bd9Sstevel@tonic-gate 				 */
17287c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
17297c478bd9Sstevel@tonic-gate 				    "AMR command is not completed");
17307c478bd9Sstevel@tonic-gate 				return (0);
17317c478bd9Sstevel@tonic-gate 			}
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 			AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 			/* wait for the acknowledge from hardware */
17367c478bd9Sstevel@tonic-gate 			AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
17377c478bd9Sstevel@tonic-gate 			    AMR_RETRYCOUNT, done_flag);
17387c478bd9Sstevel@tonic-gate 			if (!done_flag) {
17397c478bd9Sstevel@tonic-gate 				/*
17407c478bd9Sstevel@tonic-gate 				 * command is not completed, return from the
17417c478bd9Sstevel@tonic-gate 				 * current interrupt and wait for the next one
17427c478bd9Sstevel@tonic-gate 				 */
17437c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "No answer from the hardware");
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 				mutex_exit(&softs->cmd_mutex);
17467c478bd9Sstevel@tonic-gate 				return (0);
17477c478bd9Sstevel@tonic-gate 			}
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 			softs->amr_busyslots -= softs->mailbox->mb_nstatus;
17507c478bd9Sstevel@tonic-gate 		}
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 		/* flush the controllor */
17537c478bd9Sstevel@tonic-gate 		(void) amr_flush(softs);
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 		/*
17567c478bd9Sstevel@tonic-gate 		 * If the system is in panic, the tran_reset() will return a
17577c478bd9Sstevel@tonic-gate 		 * fake SUCCESS to sd, then the system would continue dump the
17587c478bd9Sstevel@tonic-gate 		 * core by poll commands. This is a work around for dumping
17597c478bd9Sstevel@tonic-gate 		 * core in panic.
17607c478bd9Sstevel@tonic-gate 		 *
17617c478bd9Sstevel@tonic-gate 		 * Note: Some on-the-fly command will continue DMAing data to
17627c478bd9Sstevel@tonic-gate 		 *	 the memory when the core is dumping, which may cause
17637c478bd9Sstevel@tonic-gate 		 *	 some flaws in the dumped core file, so a cmn_err()
17647c478bd9Sstevel@tonic-gate 		 *	 will be printed out to warn users. However, for most
17657c478bd9Sstevel@tonic-gate 		 *	 cases, the core file will be fine.
17667c478bd9Sstevel@tonic-gate 		 */
17677c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver "
17687c478bd9Sstevel@tonic-gate 		    "that doesn't support software reset. This "
17697c478bd9Sstevel@tonic-gate 		    "means that memory being used by the HBA for "
17707c478bd9Sstevel@tonic-gate 		    "DMA based reads could have been updated after "
17717c478bd9Sstevel@tonic-gate 		    "we panic'd.");
17727c478bd9Sstevel@tonic-gate 		return (1);
17737c478bd9Sstevel@tonic-gate 	} else {
17747c478bd9Sstevel@tonic-gate 		/* return failure to sd */
17757c478bd9Sstevel@tonic-gate 		return (0);
17767c478bd9Sstevel@tonic-gate 	}
17777c478bd9Sstevel@tonic-gate }
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17807c478bd9Sstevel@tonic-gate static int
amr_tran_getcap(struct scsi_address * ap,char * cap,int whom)17817c478bd9Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom)
17827c478bd9Sstevel@tonic-gate {
17837c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	/*
17867c478bd9Sstevel@tonic-gate 	 * We don't allow inquiring about capabilities for other targets
17877c478bd9Sstevel@tonic-gate 	 */
17887c478bd9Sstevel@tonic-gate 	if (cap == NULL || whom == 0)
17897c478bd9Sstevel@tonic-gate 		return (-1);
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private);
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
17947c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
17957c478bd9Sstevel@tonic-gate 		return (1);
17967c478bd9Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
17977c478bd9Sstevel@tonic-gate 		return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS);
17987c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
17997c478bd9Sstevel@tonic-gate 		return (AMR_DEFAULT_SECTORS);
18007c478bd9Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18017c478bd9Sstevel@tonic-gate 		/* number of sectors */
18027c478bd9Sstevel@tonic-gate 		return (softs->logic_drive[ap->a_target].al_size);
1803e687df1aSyw161884 	case SCSI_CAP_UNTAGGED_QING:
1804e687df1aSyw161884 	case SCSI_CAP_TAGGED_QING:
1805e687df1aSyw161884 		return (1);
18067c478bd9Sstevel@tonic-gate 	default:
18077c478bd9Sstevel@tonic-gate 		return (-1);
18087c478bd9Sstevel@tonic-gate 	}
18097c478bd9Sstevel@tonic-gate }
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate /*ARGSUSED*/
18127c478bd9Sstevel@tonic-gate static int
amr_tran_setcap(struct scsi_address * ap,char * cap,int value,int whom)18137c478bd9Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value,
18147c478bd9Sstevel@tonic-gate 		int whom)
18157c478bd9Sstevel@tonic-gate {
18167c478bd9Sstevel@tonic-gate 	/*
18177c478bd9Sstevel@tonic-gate 	 * We don't allow setting capabilities for other targets
18187c478bd9Sstevel@tonic-gate 	 */
18197c478bd9Sstevel@tonic-gate 	if (cap == NULL || whom == 0) {
18207c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_NOTE,
18217c478bd9Sstevel@tonic-gate 		    "Set Cap not supported, string = %s, whom=%d",
18227c478bd9Sstevel@tonic-gate 		    cap, whom));
18237c478bd9Sstevel@tonic-gate 		return (-1);
18247c478bd9Sstevel@tonic-gate 	}
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
18277c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
18287c478bd9Sstevel@tonic-gate 		return (1);
18297c478bd9Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
18307c478bd9Sstevel@tonic-gate 		return (1);
18317c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
18327c478bd9Sstevel@tonic-gate 		return (1);
1833e687df1aSyw161884 	case SCSI_CAP_UNTAGGED_QING:
1834e687df1aSyw161884 	case SCSI_CAP_TAGGED_QING:
1835e687df1aSyw161884 		return ((value == 1) ? 1 : 0);
18367c478bd9Sstevel@tonic-gate 	default:
18377c478bd9Sstevel@tonic-gate 		return (0);
18387c478bd9Sstevel@tonic-gate 	}
18397c478bd9Sstevel@tonic-gate }
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@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)18427c478bd9Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap,
18437c478bd9Sstevel@tonic-gate     struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
18447c478bd9Sstevel@tonic-gate     int tgtlen, int flags, int (*callback)(), caddr_t arg)
18457c478bd9Sstevel@tonic-gate {
18467c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs;
18477c478bd9Sstevel@tonic-gate 	struct amr_command	*ac;
18487c478bd9Sstevel@tonic-gate 	uint32_t		slen;
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private);
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)||
18537c478bd9Sstevel@tonic-gate 	    (softs->logic_drive[ap->a_target].al_state ==
18547c478bd9Sstevel@tonic-gate 	    AMR_LDRV_OFFLINE)) {
18557c478bd9Sstevel@tonic-gate 		return (NULL);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if (pkt == NULL) {
18597c478bd9Sstevel@tonic-gate 		/* force auto request sense */
18607c478bd9Sstevel@tonic-gate 		slen = MAX(statuslen, sizeof (struct scsi_arq_status));
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 		pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen,
18637c478bd9Sstevel@tonic-gate 		    slen, tgtlen, sizeof (struct amr_command),
18647c478bd9Sstevel@tonic-gate 		    callback, arg);
18657c478bd9Sstevel@tonic-gate 		if (pkt == NULL) {
18667c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed"));
18677c478bd9Sstevel@tonic-gate 			return (NULL);
18687c478bd9Sstevel@tonic-gate 		}
18697c478bd9Sstevel@tonic-gate 		pkt->pkt_address	= *ap;
18707c478bd9Sstevel@tonic-gate 		pkt->pkt_comp		= (void (*)())NULL;
18717c478bd9Sstevel@tonic-gate 		pkt->pkt_time		= 0;
18727c478bd9Sstevel@tonic-gate 		pkt->pkt_resid		= 0;
18737c478bd9Sstevel@tonic-gate 		pkt->pkt_statistics	= 0;
18747c478bd9Sstevel@tonic-gate 		pkt->pkt_reason		= 0;
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
18777c478bd9Sstevel@tonic-gate 		ac->ac_buf = bp;
18787c478bd9Sstevel@tonic-gate 		ac->cmdlen = cmdlen;
18797c478bd9Sstevel@tonic-gate 		ac->ac_softs = softs;
18807c478bd9Sstevel@tonic-gate 		ac->pkt = pkt;
18817c478bd9Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
18827c478bd9Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_BUSY;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
18857c478bd9Sstevel@tonic-gate 			return (pkt);
18867c478bd9Sstevel@tonic-gate 		}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr,
18897c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, NULL,
18907c478bd9Sstevel@tonic-gate 		    &ac->buffer_dma_handle) != DDI_SUCCESS) {
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 			AMRDB_PRINT((CE_WARN,
18937c478bd9Sstevel@tonic-gate 			    "Cannot allocate buffer DMA tag"));
18947c478bd9Sstevel@tonic-gate 			scsi_hba_pkt_free(ap, pkt);
18957c478bd9Sstevel@tonic-gate 			return (NULL);
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 		}
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	} else {
19007c478bd9Sstevel@tonic-gate 		if ((bp == NULL) || (bp->b_bcount == 0)) {
19017c478bd9Sstevel@tonic-gate 			return (pkt);
19027c478bd9Sstevel@tonic-gate 		}
19037c478bd9Sstevel@tonic-gate 		ac = (struct amr_command *)pkt->pkt_ha_private;
19047c478bd9Sstevel@tonic-gate 	}
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	ASSERT(ac != NULL);
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	if (bp->b_flags & B_READ) {
19097c478bd9Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAOUT;
19107c478bd9Sstevel@tonic-gate 	} else {
19117c478bd9Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_DATAIN;
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	if (flags & PKT_CONSISTENT) {
19157c478bd9Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_CONSISTENT;
19167c478bd9Sstevel@tonic-gate 	}
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	if (flags & PKT_DMA_PARTIAL) {
19197c478bd9Sstevel@tonic-gate 		ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL;
19207c478bd9Sstevel@tonic-gate 	}
19217c478bd9Sstevel@tonic-gate 
1922e687df1aSyw161884 	if (amr_mapcmd(ac, callback, arg) != DDI_SUCCESS) {
19237c478bd9Sstevel@tonic-gate 		scsi_hba_pkt_free(ap, pkt);
19247c478bd9Sstevel@tonic-gate 		return (NULL);
19257c478bd9Sstevel@tonic-gate 	}
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	pkt->pkt_resid = bp->b_bcount - ac->data_transfered;
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE,
19307c478bd9Sstevel@tonic-gate 	    "init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d",
19317c478bd9Sstevel@tonic-gate 	    (uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount,
19327c478bd9Sstevel@tonic-gate 	    ac->data_transfered));
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	ASSERT(pkt->pkt_resid >= 0);
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	return (pkt);
19377c478bd9Sstevel@tonic-gate }
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate static void
amr_tran_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)19407c478bd9Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19417c478bd9Sstevel@tonic-gate {
19427c478bd9Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	amr_unmapcmd(ac);
19457c478bd9Sstevel@tonic-gate 
19467c478bd9Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19477c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19487c478bd9Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19497c478bd9Sstevel@tonic-gate 	}
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	scsi_hba_pkt_free(ap, pkt);
19527c478bd9Sstevel@tonic-gate 	AMRDB_PRINT((CE_NOTE, "Destroy pkt called"));
19537c478bd9Sstevel@tonic-gate }
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19567c478bd9Sstevel@tonic-gate static void
amr_tran_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)19577c478bd9Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
19587c478bd9Sstevel@tonic-gate {
19597c478bd9Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	if (ac->buffer_dma_handle) {
19627c478bd9Sstevel@tonic-gate 		(void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0,
19637c478bd9Sstevel@tonic-gate 		    (ac->ac_flags & AMR_CMD_DATAIN) ?
19647c478bd9Sstevel@tonic-gate 		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU);
19657c478bd9Sstevel@tonic-gate 	}
19667c478bd9Sstevel@tonic-gate }
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19697c478bd9Sstevel@tonic-gate static void
amr_tran_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)19707c478bd9Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
19717c478bd9Sstevel@tonic-gate {
19727c478bd9Sstevel@tonic-gate 	struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private;
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_MAPPED) {
19757c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(ac->buffer_dma_handle);
19767c478bd9Sstevel@tonic-gate 		(void) ddi_dma_free_handle(&ac->buffer_dma_handle);
19777c478bd9Sstevel@tonic-gate 		ac->buffer_dma_handle = NULL;
19787c478bd9Sstevel@tonic-gate 		ac->ac_flags &= ~AMR_CMD_MAPPED;
19797c478bd9Sstevel@tonic-gate 	}
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19847c478bd9Sstevel@tonic-gate static void
amr_rw_command(struct amr_softs * softs,struct scsi_pkt * pkt,int target)19857c478bd9Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target)
19867c478bd9Sstevel@tonic-gate {
19877c478bd9Sstevel@tonic-gate 	struct amr_command	*ac = (struct amr_command *)pkt->pkt_ha_private;
19887c478bd9Sstevel@tonic-gate 	union scsi_cdb		*cdbp = (union scsi_cdb *)pkt->pkt_cdbp;
19897c478bd9Sstevel@tonic-gate 	uint8_t			cmd;
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 	if (ac->ac_flags & AMR_CMD_DATAOUT) {
19927c478bd9Sstevel@tonic-gate 		cmd = AMR_CMD_LREAD;
19937c478bd9Sstevel@tonic-gate 	} else {
19947c478bd9Sstevel@tonic-gate 		cmd = AMR_CMD_LWRITE;
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_command = cmd;
19987c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_blkcount =
19997c478bd9Sstevel@tonic-gate 	    (ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE;
20007c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_lba = (ac->cmdlen == 10) ?
20017c478bd9Sstevel@tonic-gate 	    GETG1ADDR(cdbp) : GETG0ADDR(cdbp);
20027c478bd9Sstevel@tonic-gate 	ac->mailbox.mb_drive = (uint8_t)target;
20037c478bd9Sstevel@tonic-gate }
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate static void
amr_mode_sense(union scsi_cdb * cdbp,struct buf * bp,unsigned int capacity)20067c478bd9Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity)
20077c478bd9Sstevel@tonic-gate {
20087c478bd9Sstevel@tonic-gate 	uchar_t			pagecode;
20097c478bd9Sstevel@tonic-gate 	struct mode_format	*page3p;
20107c478bd9Sstevel@tonic-gate 	struct mode_geometry	*page4p;
20117c478bd9Sstevel@tonic-gate 	struct mode_header	*headerp;
20127c478bd9Sstevel@tonic-gate 	uint32_t		ncyl;
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	if (!(bp && bp->b_un.b_addr && bp->b_bcount))
20157c478bd9Sstevel@tonic-gate 		return;
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	if (bp->b_flags & (B_PHYS | B_PAGEIO))
20187c478bd9Sstevel@tonic-gate 		bp_mapin(bp);
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	pagecode = cdbp->cdb_un.sg.scsi[0];
20217c478bd9Sstevel@tonic-gate 	switch (pagecode) {
20227c478bd9Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE3_CODE:
20237c478bd9Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20247c478bd9Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 		page3p = (struct mode_format *)((caddr_t)headerp +
20277c478bd9Sstevel@tonic-gate 		    MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20287c478bd9Sstevel@tonic-gate 		page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE);
20297c478bd9Sstevel@tonic-gate 		page3p->mode_page.length = BE_8(sizeof (struct mode_format));
20307c478bd9Sstevel@tonic-gate 		page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS);
20317c478bd9Sstevel@tonic-gate 		page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS);
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 		return;
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	case SD_MODE_SENSE_PAGE4_CODE:
20367c478bd9Sstevel@tonic-gate 		headerp = (struct mode_header *)(bp->b_un.b_addr);
20377c478bd9Sstevel@tonic-gate 		headerp->bdesc_length = MODE_BLK_DESC_LENGTH;
20387c478bd9Sstevel@tonic-gate 
20397c478bd9Sstevel@tonic-gate 		page4p = (struct mode_geometry *)((caddr_t)headerp +
20407c478bd9Sstevel@tonic-gate 		    MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH);
20417c478bd9Sstevel@tonic-gate 		page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE);
20427c478bd9Sstevel@tonic-gate 		page4p->mode_page.length = BE_8(sizeof (struct mode_geometry));
20437c478bd9Sstevel@tonic-gate 		page4p->heads = BE_8(AMR_DEFAULT_HEADS);
20447c478bd9Sstevel@tonic-gate 		page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS);
20457c478bd9Sstevel@tonic-gate 
20467c478bd9Sstevel@tonic-gate 		ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS);
20477c478bd9Sstevel@tonic-gate 		page4p->cyl_lb = BE_8(ncyl & 0xff);
20487c478bd9Sstevel@tonic-gate 		page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff);
20497c478bd9Sstevel@tonic-gate 		page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff);
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 		return;
20527c478bd9Sstevel@tonic-gate 	default:
20537c478bd9Sstevel@tonic-gate 		bzero(bp->b_un.b_addr, bp->b_bcount);
20547c478bd9Sstevel@tonic-gate 		return;
20557c478bd9Sstevel@tonic-gate 	}
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate static void
amr_set_arq_data(struct scsi_pkt * pkt,uchar_t key)20597c478bd9Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key)
20607c478bd9Sstevel@tonic-gate {
20617c478bd9Sstevel@tonic-gate 	struct scsi_arq_status *arqstat;
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp);
20647c478bd9Sstevel@tonic-gate 	arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */
20657c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_reason = CMD_CMPLT;
20667c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_resid = 0;
20677c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET |
20687c478bd9Sstevel@tonic-gate 	    STATE_SENT_CMD | STATE_XFERRED_DATA;
20697c478bd9Sstevel@tonic-gate 	arqstat->sts_rqpkt_statistics = 0;
20707c478bd9Sstevel@tonic-gate 	arqstat->sts_sensedata.es_valid = 1;
20717c478bd9Sstevel@tonic-gate 	arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE;
20727c478bd9Sstevel@tonic-gate 	arqstat->sts_sensedata.es_key = key;
20737c478bd9Sstevel@tonic-gate }
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate static void
amr_start_waiting_queue(void * softp)20767c478bd9Sstevel@tonic-gate amr_start_waiting_queue(void *softp)
20777c478bd9Sstevel@tonic-gate {
20787c478bd9Sstevel@tonic-gate 	uint32_t		slot;
20797c478bd9Sstevel@tonic-gate 	struct amr_command	*ac;
20807c478bd9Sstevel@tonic-gate 	volatile uint32_t	done_flag;
20817c478bd9Sstevel@tonic-gate 	struct amr_softs	*softs = (struct amr_softs *)softp;
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	/* only one command allowed at the same time */
20847c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->queue_mutex);
20857c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 	while ((ac = softs->waiting_q_head) != NULL) {
20887c478bd9Sstevel@tonic-gate 		/*
20897c478bd9Sstevel@tonic-gate 		 * Find an available slot, the last slot is
20907c478bd9Sstevel@tonic-gate 		 * occupied by poll I/O command.
20917c478bd9Sstevel@tonic-gate 		 */
20927c478bd9Sstevel@tonic-gate 		for (slot = 0; slot < (softs->sg_max_count - 1); slot++) {
20937c478bd9Sstevel@tonic-gate 			if (softs->busycmd[slot] == NULL) {
20947c478bd9Sstevel@tonic-gate 				if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) {
20957c478bd9Sstevel@tonic-gate 					/*
20967c478bd9Sstevel@tonic-gate 					 * only one command allowed at the
20977c478bd9Sstevel@tonic-gate 					 * same time
20987c478bd9Sstevel@tonic-gate 					 */
20997c478bd9Sstevel@tonic-gate 					mutex_exit(&softs->cmd_mutex);
21007c478bd9Sstevel@tonic-gate 					mutex_exit(&softs->queue_mutex);
21017c478bd9Sstevel@tonic-gate 					return;
21027c478bd9Sstevel@tonic-gate 				}
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 				ac->ac_timestamp = ddi_get_time();
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 				if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) {
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 					softs->busycmd[slot] = ac;
21097c478bd9Sstevel@tonic-gate 					ac->ac_slot = slot;
21107c478bd9Sstevel@tonic-gate 					softs->amr_busyslots++;
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 					bcopy(ac->sgtable,
21137c478bd9Sstevel@tonic-gate 					    softs->sg_items[slot].sg_table,
211419397407SSherry Moore 					    sizeof (struct amr_sgentry) *
211519397407SSherry Moore 					    AMR_NSEG);
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 					(void) ddi_dma_sync(
21187c478bd9Sstevel@tonic-gate 					    softs->sg_items[slot].sg_handle,
21197c478bd9Sstevel@tonic-gate 					    0, 0, DDI_DMA_SYNC_FORDEV);
21207c478bd9Sstevel@tonic-gate 
21217c478bd9Sstevel@tonic-gate 					ac->mailbox.mb_physaddr =
21227c478bd9Sstevel@tonic-gate 					    softs->sg_items[slot].sg_phyaddr;
21237c478bd9Sstevel@tonic-gate 				}
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 				/* take the cmd from the queue */
21267c478bd9Sstevel@tonic-gate 				softs->waiting_q_head = ac->ac_next;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 				ac->mailbox.mb_ident = ac->ac_slot + 1;
21297c478bd9Sstevel@tonic-gate 				ac->mailbox.mb_busy = 1;
21307c478bd9Sstevel@tonic-gate 				ac->ac_next = NULL;
21317c478bd9Sstevel@tonic-gate 				ac->ac_prev = NULL;
21327c478bd9Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_GOT_SLOT;
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate 				/* clear the poll/ack fields in the mailbox */
21357c478bd9Sstevel@tonic-gate 				softs->mailbox->mb_poll = 0;
21367c478bd9Sstevel@tonic-gate 				softs->mailbox->mb_ack = 0;
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 				AMR_DELAY((softs->mailbox->mb_busy == 0),
21397c478bd9Sstevel@tonic-gate 				    AMR_RETRYCOUNT, done_flag);
21407c478bd9Sstevel@tonic-gate 				if (!done_flag) {
21417c478bd9Sstevel@tonic-gate 					/*
21427c478bd9Sstevel@tonic-gate 					 * command not completed, indicate the
21437c478bd9Sstevel@tonic-gate 					 * problem and continue get ac
21447c478bd9Sstevel@tonic-gate 					 */
21457c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
21467c478bd9Sstevel@tonic-gate 					    "AMR command is not completed");
21477c478bd9Sstevel@tonic-gate 					break;
21487c478bd9Sstevel@tonic-gate 				}
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 				bcopy(&ac->mailbox, (void *)softs->mailbox,
21517c478bd9Sstevel@tonic-gate 				    AMR_MBOX_CMDSIZE);
21527c478bd9Sstevel@tonic-gate 				ac->ac_flags |= AMR_CMD_BUSY;
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 				(void) ddi_dma_sync(softs->mbox_dma_handle,
21557c478bd9Sstevel@tonic-gate 				    0, 0, DDI_DMA_SYNC_FORDEV);
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 				AMR_QPUT_IDB(softs,
21587c478bd9Sstevel@tonic-gate 				    softs->mbox_phyaddr | AMR_QIDB_SUBMIT);
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 				/*
21617c478bd9Sstevel@tonic-gate 				 * current ac is submitted
21627c478bd9Sstevel@tonic-gate 				 * so quit 'for-loop' to get next ac
21637c478bd9Sstevel@tonic-gate 				 */
21647c478bd9Sstevel@tonic-gate 				break;
21657c478bd9Sstevel@tonic-gate 			}
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 		/* no slot, finish our task */
21697c478bd9Sstevel@tonic-gate 		if (slot == softs->maxio)
21707c478bd9Sstevel@tonic-gate 			break;
21717c478bd9Sstevel@tonic-gate 	}
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	/* only one command allowed at the same time */
21747c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
21757c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->queue_mutex);
21767c478bd9Sstevel@tonic-gate }
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate static void
amr_done(struct amr_softs * softs)21797c478bd9Sstevel@tonic-gate amr_done(struct amr_softs *softs)
21807c478bd9Sstevel@tonic-gate {
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate 	uint32_t		i, idx;
21837c478bd9Sstevel@tonic-gate 	volatile uint32_t	done_flag;
21847c478bd9Sstevel@tonic-gate 	struct amr_mailbox	*mbox, mbsave;
21857c478bd9Sstevel@tonic-gate 	struct amr_command	*ac, *head, *tail;
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	head = tail = NULL;
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	AMR_QPUT_ODB(softs, AMR_QODB_READY);
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	/* acknowledge interrupt */
21927c478bd9Sstevel@tonic-gate 	(void) AMR_QGET_ODB(softs);
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 	mutex_enter(&softs->cmd_mutex);
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	if (softs->mailbox->mb_nstatus != 0) {
21977c478bd9Sstevel@tonic-gate 		(void) ddi_dma_sync(softs->mbox_dma_handle,
21987c478bd9Sstevel@tonic-gate 		    0, 0, DDI_DMA_SYNC_FORCPU);
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 		/* save mailbox, which contains a list of completed commands */
22017c478bd9Sstevel@tonic-gate 		bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox,
22027c478bd9Sstevel@tonic-gate 		    &mbsave, sizeof (mbsave));
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate 		mbox = &mbsave;
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 		AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK);
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 		/* wait for the acknowledge from hardware */
22097c478bd9Sstevel@tonic-gate 		AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK),
22107c478bd9Sstevel@tonic-gate 		    AMR_RETRYCOUNT, done_flag);
22117c478bd9Sstevel@tonic-gate 		if (!done_flag) {
22127c478bd9Sstevel@tonic-gate 			/*
22137c478bd9Sstevel@tonic-gate 			 * command is not completed, return from the current
22147c478bd9Sstevel@tonic-gate 			 * interrupt and wait for the next one
22157c478bd9Sstevel@tonic-gate 			 */
22167c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "No answer from the hardware");
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 			mutex_exit(&softs->cmd_mutex);
22197c478bd9Sstevel@tonic-gate 			return;
22207c478bd9Sstevel@tonic-gate 		}
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 		for (i = 0; i < mbox->mb_nstatus; i++) {
22237c478bd9Sstevel@tonic-gate 			idx = mbox->mb_completed[i] - 1;
22247c478bd9Sstevel@tonic-gate 			ac = softs->busycmd[idx];
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 			if (ac != NULL) {
22277c478bd9Sstevel@tonic-gate 				/* pull the command from the busy index */
22287c478bd9Sstevel@tonic-gate 				softs->busycmd[idx] = NULL;
22297c478bd9Sstevel@tonic-gate 				if (softs->amr_busyslots > 0)
22307c478bd9Sstevel@tonic-gate 					softs->amr_busyslots--;
22317c478bd9Sstevel@tonic-gate 				if (softs->amr_busyslots == 0)
22327c478bd9Sstevel@tonic-gate 					cv_broadcast(&softs->cmd_cv);
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_BUSY;
22357c478bd9Sstevel@tonic-gate 				ac->ac_flags &= ~AMR_CMD_GOT_SLOT;
22367c478bd9Sstevel@tonic-gate 				ac->ac_status = mbox->mb_status;
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 				/* enqueue here */
22397c478bd9Sstevel@tonic-gate 				if (head) {
22407c478bd9Sstevel@tonic-gate 					tail->ac_next = ac;
22417c478bd9Sstevel@tonic-gate 					tail = ac;
22427c478bd9Sstevel@tonic-gate 					tail->ac_next = NULL;
22437c478bd9Sstevel@tonic-gate 				} else {
22447c478bd9Sstevel@tonic-gate 					tail = head = ac;
22457c478bd9Sstevel@tonic-gate 					ac->ac_next = NULL;
22467c478bd9Sstevel@tonic-gate 				}
22477c478bd9Sstevel@tonic-gate 			} else {
22487c478bd9Sstevel@tonic-gate 				AMRDB_PRINT((CE_WARN,
22497c478bd9Sstevel@tonic-gate 				    "ac in mailbox is NULL!"));
22507c478bd9Sstevel@tonic-gate 			}
22517c478bd9Sstevel@tonic-gate 		}
22527c478bd9Sstevel@tonic-gate 	} else {
22537c478bd9Sstevel@tonic-gate 		AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!"));
22547c478bd9Sstevel@tonic-gate 	}
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	mutex_exit(&softs->cmd_mutex);
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	if (head != NULL) {
22597c478bd9Sstevel@tonic-gate 		amr_call_pkt_comp(head);
22607c478bd9Sstevel@tonic-gate 	}
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	/* dispatch a thread to process the pending I/O if there is any */
22637c478bd9Sstevel@tonic-gate 	if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue,
22647c478bd9Sstevel@tonic-gate 	    (void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) {
22657c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "No memory available to dispatch taskq");
22667c478bd9Sstevel@tonic-gate 	}
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate static void
amr_call_pkt_comp(register struct amr_command * head)22707c478bd9Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head)
22717c478bd9Sstevel@tonic-gate {
22727c478bd9Sstevel@tonic-gate 	register struct scsi_pkt	*pkt;
22737c478bd9Sstevel@tonic-gate 	register struct amr_command	*ac, *localhead;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	localhead = head;
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	while (localhead) {
22787c478bd9Sstevel@tonic-gate 		ac = localhead;
22797c478bd9Sstevel@tonic-gate 		localhead = ac->ac_next;
22807c478bd9Sstevel@tonic-gate 		ac->ac_next = NULL;
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 		pkt = ac->pkt;
22837c478bd9Sstevel@tonic-gate 		*pkt->pkt_scbp = 0;
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 		if (ac->ac_status == AMR_STATUS_SUCCESS) {
22867c478bd9Sstevel@tonic-gate 			pkt->pkt_state |= (STATE_GOT_BUS
22877c478bd9Sstevel@tonic-gate 			    | STATE_GOT_TARGET
22887c478bd9Sstevel@tonic-gate 			    | STATE_SENT_CMD
22897c478bd9Sstevel@tonic-gate 			    | STATE_XFERRED_DATA);
22907c478bd9Sstevel@tonic-gate 			pkt->pkt_reason = CMD_CMPLT;
22917c478bd9Sstevel@tonic-gate 		} else {
22927c478bd9Sstevel@tonic-gate 			pkt->pkt_state |= STATE_GOT_BUS
22937c478bd9Sstevel@tonic-gate 			    | STATE_ARQ_DONE;
22947c478bd9Sstevel@tonic-gate 			pkt->pkt_reason = CMD_INCOMPLETE;
22957c478bd9Sstevel@tonic-gate 			amr_set_arq_data(pkt, KEY_HARDWARE_ERROR);
22967c478bd9Sstevel@tonic-gate 		}
22979c57abc8Ssrivijitha dugganapalli 		if (!(pkt->pkt_flags & FLAG_NOINTR)) {
22989c57abc8Ssrivijitha dugganapalli 			scsi_hba_pkt_comp(pkt);
22997c478bd9Sstevel@tonic-gate 		}
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate }
2302