arcmsr.c revision 9106:ee8f18cdafb2
16008Syy154373/*
26008Syy154373 *       O.S   : Solaris
36008Syy154373 *  FILE NAME  : arcmsr.c
46008Syy154373 *       BY    : Erich Chen
56008Syy154373 *  Description: SCSI RAID Device Driver for
66008Syy154373 *               ARECA RAID Host adapter
76008Syy154373 *
86008Syy154373 *  Copyright (C) 2002,2007 Areca Technology Corporation All rights reserved.
96008Syy154373 *  Copyright (C) 2002,2007 Erich Chen
106008Syy154373 *	    Web site: www.areca.com.tw
116008Syy154373 *	      E-mail: erich@areca.com.tw
126008Syy154373 *
136008Syy154373 *	Redistribution and use in source and binary forms, with or without
146008Syy154373 *	modification, are permitted provided that the following conditions
156008Syy154373 *	are met:
166008Syy154373 *	1. Redistributions of source code must retain the above copyright
176008Syy154373 *	   notice, this list of conditions and the following disclaimer.
186008Syy154373 *	2. Redistributions in binary form must reproduce the above copyright
196008Syy154373 *	   notice, this list of conditions and the following disclaimer in the
206008Syy154373 *	   documentation and/or other materials provided with the distribution.
216008Syy154373 *  3. The party using or redistributing the source code and binary forms
226008Syy154373 *     agrees to the disclaimer below and the terms and conditions set forth
236008Syy154373 *     herein.
246008Syy154373 *
256008Syy154373 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
266008Syy154373 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
276008Syy154373 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
286008Syy154373 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
296008Syy154373 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
306008Syy154373 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
316008Syy154373 *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
326008Syy154373 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
336008Syy154373 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
346008Syy154373 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
356008Syy154373 *  SUCH DAMAGE.
366008Syy154373 */
376008Syy154373
386008Syy154373/*
396008Syy154373 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
406008Syy154373 * Use is subject to license terms.
416008Syy154373 */
426008Syy154373
436008Syy154373#include <sys/types.h>
446008Syy154373#include <sys/ddidmareq.h>
456008Syy154373#include <sys/scsi/scsi.h>
466008Syy154373#include <sys/ddi.h>
476008Syy154373#include <sys/sunddi.h>
486008Syy154373#include <sys/file.h>
496008Syy154373#include <sys/disp.h>
506008Syy154373#include <sys/signal.h>
516008Syy154373#include <sys/debug.h>
526008Syy154373#include <sys/pci.h>
536008Syy154373#include <sys/policy.h>
546008Syy154373#include <sys/atomic.h>
556008Syy154373
566008Syy154373#include "arcmsr.h"
576008Syy154373
586008Syy154373static int arcmsr_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd);
596008Syy154373static int arcmsr_cb_ioctl(dev_t dev, int ioctl_cmd, intptr_t arg,
606008Syy154373    int mode, cred_t *credp, int *rvalp);
616008Syy154373static int arcmsr_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd);
626008Syy154373static int arcmsr_reset(dev_info_t *resetdev, ddi_reset_cmd_t cmd);
636008Syy154373static int arcmsr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt);
646008Syy154373static int arcmsr_tran_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
656008Syy154373static int arcmsr_tran_reset(struct scsi_address *ap, int level);
666008Syy154373static int arcmsr_tran_getcap(struct scsi_address *ap, char *cap, int whom);
676008Syy154373static int arcmsr_tran_setcap(struct scsi_address *ap, char *cap, int value,
686008Syy154373    int whom);
696008Syy154373static int arcmsr_tran_tgt_init(dev_info_t *host_dev_info,
706008Syy154373    dev_info_t *target_dev_info, scsi_hba_tran_t *hosttran,
716008Syy154373    struct scsi_device *sd);
726008Syy154373static void arcmsr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt);
736008Syy154373static void arcmsr_tran_destroy_pkt(struct scsi_address *ap,
746008Syy154373    struct scsi_pkt *pkt);
756008Syy154373static void arcmsr_tran_sync_pkt(struct scsi_address *ap,
766008Syy154373    struct scsi_pkt *pkt);
776008Syy154373static struct scsi_pkt *arcmsr_tran_init_pkt(struct scsi_address *ap,
786008Syy154373    struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
796008Syy154373    int tgtlen, int flags, int (*callback)(), caddr_t arg);
806008Syy154373
816008Syy154373static int arcmsr_config_lun(struct ACB *acb, uint16_t tgt, uint8_t lun,
826008Syy154373    dev_info_t **ldip);
836008Syy154373static uint_t arcmsr_interrupt(caddr_t arg);
846008Syy154373static int arcmsr_initialize(struct ACB *acb);
856008Syy154373static int arcmsr_dma_alloc(struct ACB *acb,
866008Syy154373    struct scsi_pkt *pkt, struct buf *bp, int flags, int (*callback)());
876008Syy154373static int arcmsr_dma_move(struct ACB *acb,
886008Syy154373    struct scsi_pkt *pkt, struct buf *bp);
896008Syy154373static void arcmsr_pcidev_disattach(struct ACB *acb);
906008Syy154373static void arcmsr_ccb_complete(struct CCB *ccb, int flag);
916008Syy154373static void arcmsr_iop_init(struct ACB *acb);
926008Syy154373static void arcmsr_iop_parking(struct ACB *acb);
936008Syy154373static void arcmsr_log(struct ACB *acb, int level, char *fmt, ...);
946008Syy154373static struct CCB *arcmsr_get_freeccb(struct ACB *acb);
956008Syy154373static void arcmsr_flush_hba_cache(struct ACB *acb);
966008Syy154373static void arcmsr_flush_hbb_cache(struct ACB *acb);
976008Syy154373static void arcmsr_stop_hba_bgrb(struct ACB *acb);
986008Syy154373static void arcmsr_stop_hbb_bgrb(struct ACB *acb);
996008Syy154373static void arcmsr_start_hba_bgrb(struct ACB *acb);
1006008Syy154373static void arcmsr_start_hba_bgrb(struct ACB *acb);
1016008Syy154373static void arcmsr_polling_hba_ccbdone(struct ACB *acb, struct CCB *poll_ccb);
1026008Syy154373static void arcmsr_polling_hbb_ccbdone(struct ACB *acb, struct CCB *poll_ccb);
1036008Syy154373static void arcmsr_build_ccb(struct CCB *ccb);
1046008Syy154373static int arcmsr_tran_bus_config(dev_info_t *parent, uint_t flags,
1056008Syy154373    ddi_bus_config_op_t op, void *arg, dev_info_t **childp);
1066008Syy154373static int arcmsr_name_node(dev_info_t *dip, char *name, int len);
1076008Syy154373static dev_info_t *arcmsr_find_child(struct ACB *acb, uint16_t tgt,
1086008Syy154373    uint8_t lun);
1096008Syy154373
1106008Syy154373static struct ACB *ArcMSRHBA[ARCMSR_MAX_ADAPTER];
1116008Syy154373static int arcmsr_hba_count;
1126008Syy154373static void *arcmsr_soft_state = NULL;
1136008Syy154373static kmutex_t arcmsr_global_mutex;
1146008Syy154373
1156008Syy154373#define	MSR_MINOR	32
1166008Syy154373#define	INST2MSR(x)	(((x) << INST_MINOR_SHIFT) | MSR_MINOR)
1176008Syy154373
1186008Syy154373static ddi_dma_attr_t arcmsr_dma_attr = {
1196008Syy154373	DMA_ATTR_V0,		/* ddi_dma_attr version */
1206008Syy154373	0,			/* low DMA address range */
1216008Syy154373	0xffffffff,		/* high DMA address range */
1226008Syy154373	0x00ffffff,		/* DMA counter counter upper bound */
1236008Syy154373	1,			/* DMA address alignment requirements */
1246008Syy154373	DEFAULT_BURSTSIZE | BURST32 | BURST64,	/* burst sizes */
1256008Syy154373	1,			/* minimum effective DMA size */
1266008Syy154373	ARCMSR_MAX_XFER_LEN,	/* maximum DMA xfer size */
1276008Syy154373	/*
1286008Syy154373	 * The dma_attr_seg field supplies the limit of each Scatter/Gather
1296008Syy154373	 * list element's "address+length". The Intel IOP331 can not use
1306008Syy154373	 * segments over the 4G boundary due to segment boundary restrictions
1316008Syy154373	 */
1326008Syy154373	0x00ffffff,
1336008Syy154373	ARCMSR_MAX_SG_ENTRIES,	/* scatter/gather list count */
1346008Syy154373	1, 			/* device granularity */
1356008Syy154373	DDI_DMA_FORCE_PHYSICAL	/* Bus specific DMA flags */
1366008Syy154373};
1376008Syy154373
1386008Syy154373static ddi_dma_attr_t arcmsr_ccb_attr = {
1396008Syy154373	DMA_ATTR_V0,	/* ddi_dma_attr version */
1406008Syy154373	0,		/* low DMA address range */
1416008Syy154373	0xffffffff,	/* high DMA address range */
1426008Syy154373	0x00ffffff,	/* DMA counter counter upper bound */
1436008Syy154373	1,		/* default byte alignment */
1446008Syy154373	DEFAULT_BURSTSIZE | BURST32 | BURST64,   /* burst sizes */
1456008Syy154373	1,		/* minimum effective DMA size */
1466008Syy154373	0xffffffff,	/* maximum DMA xfer size */
1476008Syy154373	0x00ffffff,	/* max segment size, segment boundary restrictions */
1486008Syy154373	1,		/* scatter/gather list count */
1496008Syy154373	1,		/* device granularity */
1506008Syy154373	DDI_DMA_FORCE_PHYSICAL	/* Bus specific DMA flags */
1516008Syy154373};
1526008Syy154373
1536008Syy154373static struct cb_ops arcmsr_cb_ops = {
1546008Syy154373	scsi_hba_open,		/* open(9E) */
1556008Syy154373	scsi_hba_close,		/* close(9E) */
1566008Syy154373	nodev,			/* strategy(9E), returns ENXIO */
1576008Syy154373	nodev,			/* print(9E) */
1586008Syy154373	nodev,			/* dump(9E) Cannot be used as a dump device */
1596008Syy154373	nodev,			/* read(9E) */
1606008Syy154373	nodev,			/* write(9E) */
1616008Syy154373	arcmsr_cb_ioctl,	/* ioctl(9E) */
1626008Syy154373	nodev,			/* devmap(9E) */
1636008Syy154373	nodev,			/* mmap(9E) */
1646008Syy154373	nodev,			/* segmap(9E) */
1656008Syy154373	NULL,			/* chpoll(9E) returns ENXIO */
1666008Syy154373	nodev,			/* prop_op(9E) */
1676008Syy154373	NULL,			/* streamtab(9S) */
1686008Syy154373#ifdef _LP64
1696008Syy154373	/*
1706008Syy154373	 * cb_ops cb_flag:
1716008Syy154373	 *	D_NEW | D_MP	compatibility flags, see conf.h
1726008Syy154373	 *	D_MP 		flag indicates that the driver is safe for
1736008Syy154373	 *			multi-threaded operation
1746008Syy154373	 *	D_64BIT		flag driver properly handles 64-bit offsets
1756008Syy154373	 */
1766008Syy154373	D_HOTPLUG | D_MP | D_64BIT,
1776008Syy154373#else
1786008Syy154373	D_HOTPLUG | D_MP,
1796008Syy154373#endif
1806008Syy154373	CB_REV,
1816008Syy154373	nodev,			/* aread(9E) */
1826008Syy154373	nodev			/* awrite(9E) */
1836008Syy154373};
1846008Syy154373
1856008Syy154373static struct dev_ops arcmsr_ops = {
1866008Syy154373	DEVO_REV,		/* devo_rev */
1876008Syy154373	0,			/* reference count */
1886008Syy154373	nodev,			/* getinfo */
1896008Syy154373	nulldev,		/* identify */
1906008Syy154373	nulldev,		/* probe */
1916008Syy154373	arcmsr_attach,		/* attach */
1926008Syy154373	arcmsr_detach,		/* detach */
1936008Syy154373	arcmsr_reset,		/* reset, shutdown, reboot notify */
1946008Syy154373	&arcmsr_cb_ops,		/* driver operations */
1956008Syy154373	NULL,			/* bus operations */
1966008Syy154373	nulldev			/* power */
1976008Syy154373};
1986008Syy154373
1996008Syy154373char _depends_on[] = "misc/scsi";
2006008Syy154373
2016008Syy154373static struct modldrv arcmsr_modldrv = {
2026008Syy154373	&mod_driverops, 	/* Type of module. This is a driver. */
2036008Syy154373	ARCMSR_DRIVER_VERSION,  /* module name, from arcmsr.h */
2046008Syy154373	&arcmsr_ops,		/* driver ops */
2056008Syy154373};
2066008Syy154373
2076008Syy154373static struct modlinkage arcmsr_modlinkage = {
2086008Syy154373	MODREV_1,
2096008Syy154373	&arcmsr_modldrv,
2106008Syy154373	NULL
2116008Syy154373};
2126008Syy154373
2136008Syy154373
2146008Syy154373int
2156008Syy154373_init(void) {
2166008Syy154373	int ret;
2176008Syy154373
2186008Syy154373
2196008Syy154373	mutex_init(&arcmsr_global_mutex, "arcmsr global mutex",
2206008Syy154373	    MUTEX_DRIVER, NULL);
2216008Syy154373	ret = ddi_soft_state_init(&arcmsr_soft_state,
2226008Syy154373	    sizeof (struct ACB), ARCMSR_MAX_ADAPTER);
2236008Syy154373	if (ret != 0) {
2246008Syy154373		return (ret);
2256008Syy154373	}
2266008Syy154373	if ((ret = scsi_hba_init(&arcmsr_modlinkage)) != 0) {
2276008Syy154373		ddi_soft_state_fini(&arcmsr_soft_state);
2286008Syy154373		return (ret);
2296008Syy154373	}
2306008Syy154373
2316008Syy154373	if ((ret = mod_install(&arcmsr_modlinkage)) != 0) {
2326008Syy154373		mutex_destroy(&arcmsr_global_mutex);
2336008Syy154373		scsi_hba_fini(&arcmsr_modlinkage);
2346008Syy154373		if (arcmsr_soft_state != NULL) {
2356008Syy154373			ddi_soft_state_fini(&arcmsr_soft_state);
2366008Syy154373		}
2376008Syy154373	}
2386008Syy154373	return (ret);
2396008Syy154373}
2406008Syy154373
2416008Syy154373
2426008Syy154373int
2436008Syy154373_fini(void) {
2446008Syy154373	int ret;
2456008Syy154373
2466008Syy154373	ret = mod_remove(&arcmsr_modlinkage);
2476008Syy154373	if (ret == 0) {
2486008Syy154373		/* if ret = 0 , said driver can remove */
2496008Syy154373		mutex_destroy(&arcmsr_global_mutex);
2506008Syy154373		scsi_hba_fini(&arcmsr_modlinkage);
2516008Syy154373		if (arcmsr_soft_state != NULL) {
2526008Syy154373			ddi_soft_state_fini(&arcmsr_soft_state);
2536008Syy154373		}
2546008Syy154373	}
2556008Syy154373	return (ret);
2566008Syy154373}
2576008Syy154373
2586008Syy154373
2596008Syy154373int
2606008Syy154373_info(struct modinfo *modinfop) {
2616008Syy154373	return (mod_info(&arcmsr_modlinkage, modinfop));
2626008Syy154373}
2636008Syy154373
2646008Syy154373
2656008Syy154373
2666008Syy154373#if defined(ARCMSR_DEBUG)
2676008Syy154373static void
2686008Syy154373arcmsr_dump_scsi_cdb(struct scsi_address *ap, struct scsi_pkt *pkt) {
2696008Syy154373
2706008Syy154373	static char hex[] = "0123456789abcdef";
2716008Syy154373	struct ACB *acb =
2726008Syy154373	    (struct ACB *)ap->a_hba_tran->tran_hba_private;
2736008Syy154373	struct CCB *ccb =
2746008Syy154373	    (struct CCB *)pkt->pkt_ha_private;
2756008Syy154373	uint8_t	*cdb = pkt->pkt_cdbp;
2766008Syy154373	char buf [256];
2776008Syy154373	char *p;
2786008Syy154373	int i;
2796008Syy154373
2806008Syy154373
2816008Syy154373	(void) sprintf(buf, "arcmsr%d: sgcount=%d <%d, %d> "
2826008Syy154373	    "cdb ",
2836008Syy154373	    ddi_get_instance(acb->dev_info), ccb->arcmsr_cdb.sgcount,
2846008Syy154373	    ap->a_target, ap->a_lun);
2856008Syy154373
2866008Syy154373	p = buf + strlen(buf);
2876008Syy154373	*p++ = '[';
2886008Syy154373
2896008Syy154373	for (i = 0; i < ccb->arcmsr_cdb.CdbLength; i++, cdb++) {
2906008Syy154373		if (i != 0) {
2916008Syy154373			*p++ = ' ';
2926008Syy154373		}
2936008Syy154373		*p++ = hex[(*cdb >> 4) & 0x0f];
2946008Syy154373		*p++ = hex[*cdb & 0x0f];
2956008Syy154373	}
2966008Syy154373	*p++ = ']';
2976008Syy154373	*p++ = '.';
2986008Syy154373	*p = 0;
2996008Syy154373	cmn_err(CE_CONT, buf);
3006008Syy154373}
3016008Syy154373#endif  /* ARCMSR_DEBUG */
3026008Syy154373
3036008Syy154373static void
3046008Syy154373arcmsr_devmap_req_timeout(void* arg) {
3056008Syy154373
3066008Syy154373	struct ACB *acb = (struct ACB *)arg;
3076008Syy154373	switch (acb->adapter_type) {
3086008Syy154373	    case ACB_ADAPTER_TYPE_A:
3096008Syy154373	    {
3106008Syy154373		    struct HBA_msgUnit *phbamu;
3116008Syy154373
3126008Syy154373		    phbamu = (struct HBA_msgUnit *)acb->pmu;
3136008Syy154373		    CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
3146008Syy154373			&phbamu->inbound_msgaddr0,
3156008Syy154373			ARCMSR_INBOUND_MESG0_GET_CONFIG);
3166008Syy154373	    }
3176008Syy154373	    break;
3186008Syy154373	    case ACB_ADAPTER_TYPE_B:
3196008Syy154373	    {
3206008Syy154373		    struct HBB_msgUnit *phbbmu;
3216008Syy154373		    phbbmu = (struct HBB_msgUnit *)acb->pmu;
3226008Syy154373		    CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
3236008Syy154373			&phbbmu->hbb_doorbell->drv2iop_doorbell,
3246008Syy154373			ARCMSR_MESSAGE_GET_CONFIG);
3256008Syy154373	    }
3266008Syy154373	    break;
3276008Syy154373	}
3286008Syy154373
3296008Syy154373	if ((acb->timeout_id != 0) &&
3306008Syy154373	    ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) {
3316008Syy154373		/* do pkt timeout check each 5 secs */
3326008Syy154373		acb->timeout_id = timeout(arcmsr_devmap_req_timeout,
3336008Syy154373		    (void*)acb, (5 * drv_usectohz(1000000)));
3346008Syy154373	}
3356008Syy154373}
3366008Syy154373
3376008Syy154373
3386008Syy154373static void
3396008Syy154373arcmsr_ccbs_timeout(void* arg) {
3406008Syy154373
3416008Syy154373	struct ACB *acb = (struct ACB *)arg;
3426008Syy154373	struct CCB *ccb;
3436008Syy154373	int i;
3446008Syy154373	int current_time = ddi_get_time();
3456008Syy154373
3466008Syy154373
3476008Syy154373	if (acb->ccboutstandingcount != 0) {
3486008Syy154373		/* check each ccb */
3496008Syy154373		i = ddi_dma_sync(acb->ccbs_pool_handle, 0,
3506008Syy154373		    acb->dma_sync_size, DDI_DMA_SYNC_FORKERNEL);
3516008Syy154373		if (i != DDI_SUCCESS) {
3526008Syy154373			if ((acb->timeout_id != 0) &&
3536008Syy154373			    ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) {
3546008Syy154373				/* do pkt timeout check each 60 secs */
3556008Syy154373				acb->timeout_id = timeout(arcmsr_ccbs_timeout,
3566008Syy154373				    (void*)acb,
3576008Syy154373				    (60 * drv_usectohz(1000000)));
3586008Syy154373			}
3596008Syy154373			return;
3606008Syy154373		}
3616008Syy154373		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
3626008Syy154373			ccb = acb->pccb_pool[i];
3636008Syy154373			if (ccb->acb != acb) {
3646008Syy154373				break;
3656008Syy154373			}
3666008Syy154373			if (ccb->startdone == ARCMSR_CCB_DONE) {
3676008Syy154373				continue;
3686008Syy154373			}
3696008Syy154373			if (ccb->pkt == NULL) {
3706008Syy154373				continue;
3716008Syy154373			}
3726008Syy154373			if (ccb->pkt->pkt_time == 0) {
3736008Syy154373				continue;
3746008Syy154373			}
3756008Syy154373			if ((int)ccb->ccb_time >= current_time) {
3766008Syy154373				continue;
3776008Syy154373			}
3786008Syy154373			if (ccb->startdone == ARCMSR_CCB_START) {
3796008Syy154373				int id = ccb->pkt->pkt_address.a_target;
3806008Syy154373				int lun = ccb->pkt->pkt_address.a_lun;
3816008Syy154373
3826008Syy154373				/*
3836008Syy154373				 * handle outstanding command of timeout ccb
3846008Syy154373				 */
3856008Syy154373				ccb->pkt->pkt_reason = CMD_TIMEOUT;
3866008Syy154373				ccb->pkt->pkt_statistics = STAT_TIMEOUT;
3876008Syy154373
3886008Syy154373				cmn_err(CE_CONT,
3896008Syy154373				    "arcmsr%d: scsi target %d lun %d "
3906008Syy154373				    "outstanding command timeout",
3916008Syy154373				    ddi_get_instance(acb->dev_info),
3926008Syy154373				    id, lun);
3936008Syy154373				cmn_err(CE_CONT,
3946008Syy154373				    "arcmsr%d: scsi target %d lun %d "
3956008Syy154373				    "fatal error on target, device is gone",
3966008Syy154373				    ddi_get_instance(acb->dev_info),
3976008Syy154373				    id, lun);
3986008Syy154373				acb->devstate[id][lun] = ARECA_RAID_GONE;
3996008Syy154373				arcmsr_ccb_complete(ccb, 1);
4006008Syy154373				acb->timeout_count++;
4016008Syy154373				continue;
4026008Syy154373			}
4036008Syy154373			ccb->ccb_time = (time_t)(ccb->pkt->pkt_time +
4046008Syy154373			    current_time); /* adjust ccb_time of pending ccb */
4056008Syy154373		}
4066008Syy154373	}
4076008Syy154373	if ((acb->timeout_id != 0) &&
4086008Syy154373	    ((acb->acb_flags & ACB_F_SCSISTOPADAPTER) == 0)) {
4096008Syy154373		/* do pkt timeout check each 60 secs */
4106008Syy154373		acb->timeout_id = timeout(arcmsr_ccbs_timeout,
4116008Syy154373		    (void*)acb, (60 * drv_usectohz(1000000)));
4126008Syy154373	}
4136008Syy154373}
4146008Syy154373
4156008Syy154373
4166008Syy154373static uint32_t
4176008Syy154373arcmsr_disable_allintr(struct ACB *acb) {
4186008Syy154373
4196008Syy154373	uint32_t intmask_org;
4206008Syy154373
4216008Syy154373	switch (acb->adapter_type) {
4226008Syy154373	case ACB_ADAPTER_TYPE_A: {
4236008Syy154373		struct HBA_msgUnit *phbamu =
4246008Syy154373		    (struct HBA_msgUnit *)acb->pmu;
4256008Syy154373
4266008Syy154373		/* disable all outbound interrupt */
4276008Syy154373		intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4286008Syy154373		    &phbamu->outbound_intmask);
4296008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
4306008Syy154373		    &phbamu->outbound_intmask,
4316008Syy154373		    intmask_org|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE);
4326008Syy154373		}
4336008Syy154373		break;
4346008Syy154373	case ACB_ADAPTER_TYPE_B: {
4356008Syy154373		struct HBB_msgUnit *phbbmu =
4366008Syy154373		    (struct HBB_msgUnit *)acb->pmu;
4376008Syy154373
4386008Syy154373		/* disable all outbound interrupt */
4396008Syy154373		intmask_org = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
4406008Syy154373		    &phbbmu->hbb_doorbell->iop2drv_doorbell_mask);
4416008Syy154373		/* disable all interrupts */
4426008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
4436008Syy154373		    &phbbmu->hbb_doorbell->iop2drv_doorbell_mask, 0);
4446008Syy154373		}
4456008Syy154373		break;
4466008Syy154373	}
4476008Syy154373	return (intmask_org);
4486008Syy154373}
4496008Syy154373
4506008Syy154373
4516008Syy154373static void
4526008Syy154373arcmsr_enable_allintr(struct ACB *acb, uint32_t intmask_org) {
4536008Syy154373
4546008Syy154373	int mask;
4556008Syy154373
4566008Syy154373	switch (acb->adapter_type) {
4576008Syy154373	case ACB_ADAPTER_TYPE_A: {
4586008Syy154373		struct HBA_msgUnit *phbamu =
4596008Syy154373		    (struct HBA_msgUnit *)acb->pmu;
4606008Syy154373
4616008Syy154373		/*
4626008Syy154373		 * enable outbound Post Queue, outbound doorbell message0
4636008Syy154373		 * Interrupt
4646008Syy154373		 */
4656008Syy154373		mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
4666008Syy154373		    ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE |
4676008Syy154373		    ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
4686008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
4696008Syy154373		    &phbamu->outbound_intmask, intmask_org & mask);
4706008Syy154373		acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
4716008Syy154373		}
4726008Syy154373		break;
4736008Syy154373	case ACB_ADAPTER_TYPE_B: {
4746008Syy154373		struct HBB_msgUnit *phbbmu =
4756008Syy154373		    (struct HBB_msgUnit *)acb->pmu;
4766008Syy154373
4776008Syy154373		mask = (ARCMSR_IOP2DRV_DATA_WRITE_OK |
4786008Syy154373		    ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE |
4796008Syy154373		    ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
4806008Syy154373		/* 1=interrupt enable, 0=interrupt disable */
4816008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
4826008Syy154373		    &phbbmu->hbb_doorbell->iop2drv_doorbell_mask,
4836008Syy154373		    intmask_org | mask);
4846008Syy154373		acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
4856008Syy154373		}
4866008Syy154373		break;
4876008Syy154373	}
4886008Syy154373}
4896008Syy154373
4906008Syy154373
4916008Syy154373static void
4926008Syy154373arcmsr_iop_parking(struct ACB *acb) {
4936008Syy154373
4946008Syy154373	if (acb != NULL) {
4956008Syy154373		/* stop adapter background rebuild */
4966008Syy154373		if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
4976008Syy154373			uint32_t intmask_org;
4986008Syy154373
4996008Syy154373			acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
5006008Syy154373			/* disable all outbound interrupt */
5016008Syy154373			intmask_org = arcmsr_disable_allintr(acb);
5026008Syy154373			if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
5036008Syy154373				arcmsr_stop_hba_bgrb(acb);
5046008Syy154373				arcmsr_flush_hba_cache(acb);
5056008Syy154373			} else {
5066008Syy154373				arcmsr_stop_hbb_bgrb(acb);
5076008Syy154373				arcmsr_flush_hbb_cache(acb);
5086008Syy154373			}
5096008Syy154373			/*
5106008Syy154373			 * enable outbound Post Queue
5116008Syy154373			 * enable outbound doorbell Interrupt
5126008Syy154373			 */
5136008Syy154373			arcmsr_enable_allintr(acb, intmask_org);
5146008Syy154373		}
5156008Syy154373	}
5166008Syy154373}
5176008Syy154373
5186008Syy154373
5196008Syy154373
5206008Syy154373static int
5216008Syy154373arcmsr_reset(dev_info_t *resetdev, ddi_reset_cmd_t cmd) {
5226008Syy154373
5236008Syy154373	struct ACB *acb;
5246008Syy154373	scsi_hba_tran_t *scsi_hba_transport;
5256008Syy154373
5266008Syy154373	scsi_hba_transport = (scsi_hba_tran_t *)
5276008Syy154373	    ddi_get_driver_private(resetdev);
5286008Syy154373
5296008Syy154373	if (!scsi_hba_transport)
5306008Syy154373		return (DDI_FAILURE);
5316008Syy154373
5326008Syy154373	acb = (struct ACB *)
5336008Syy154373	    scsi_hba_transport->tran_hba_private;
5346008Syy154373
5356008Syy154373	if (!acb)
5366008Syy154373		return (DDI_FAILURE);
5376008Syy154373
5386008Syy154373	if ((cmd == RESET_LUN) ||
5396008Syy154373	    (cmd == RESET_BUS) ||
5406008Syy154373	    (cmd == RESET_TARGET))
5416008Syy154373		arcmsr_log(NULL, CE_WARN,
5426008Syy154373		    "arcmsr%d: reset op (%d) not supported",
5436008Syy154373		    ddi_get_instance(resetdev), cmd);
5446008Syy154373
5456008Syy154373	arcmsr_pcidev_disattach(acb);
5466008Syy154373
5476008Syy154373	return (DDI_SUCCESS);
5486008Syy154373}
5496008Syy154373
5506008Syy154373static int
5516008Syy154373arcmsr_do_ddi_attach(dev_info_t *dev_info, int instance) {
5526008Syy154373
5536008Syy154373	scsi_hba_tran_t *hba_trans;
5546008Syy154373	ddi_device_acc_attr_t dev_acc_attr;
5556008Syy154373	struct ACB *acb;
5566008Syy154373	static char buf[256];
5576008Syy154373	uint16_t wval;
5586008Syy154373	int raid6 = 1;
5596008Syy154373	char *type;
5606008Syy154373
5616008Syy154373	/*
5626008Syy154373	 * Soft State Structure
5636008Syy154373	 * The driver should allocate the per-device-instance
5646008Syy154373	 * soft state structure, being careful to clean up properly if
5656008Syy154373	 * an error occurs. Allocate data structure.
5666008Syy154373	 */
5676008Syy154373	if (ddi_soft_state_zalloc(arcmsr_soft_state, instance)
5686008Syy154373	    != DDI_SUCCESS) {
5696008Syy154373		arcmsr_log(NULL, CE_WARN,
5706008Syy154373		    "arcmsr%d: ddi_soft_state_zalloc failed",
5716008Syy154373		    instance);
5726008Syy154373		return (DDI_FAILURE);
5736008Syy154373	}
5746008Syy154373
5756008Syy154373	acb = ddi_get_soft_state(arcmsr_soft_state, instance);
5766008Syy154373	if (acb == NULL) {
5776008Syy154373		arcmsr_log(NULL, CE_WARN,
5786008Syy154373		    "arcmsr%d: ddi_get_soft_state failed",
5796008Syy154373		    instance);
5806008Syy154373		goto error_level_1;
5816008Syy154373	}
5826008Syy154373
5836008Syy154373	/* acb is already zalloc()d so we don't need to bzero() it */
5846008Syy154373	dev_acc_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
5856008Syy154373	dev_acc_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
5866008Syy154373	dev_acc_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
5876008Syy154373
5886008Syy154373	acb->dev_info = dev_info;
5896008Syy154373	acb->dev_acc_attr = dev_acc_attr;
5906008Syy154373
5916008Syy154373	/*
5926008Syy154373	 * The driver, if providing DMA, should also check that its hardware is
5936008Syy154373	 * installed in a DMA-capable slot
5946008Syy154373	 */
5956008Syy154373	if (ddi_slaveonly(dev_info) == DDI_SUCCESS) {
5966008Syy154373		arcmsr_log(NULL, CE_WARN,
5976008Syy154373		    "arcmsr%d: hardware is not installed in a "
5986008Syy154373		    "DMA-capable slot",
5996008Syy154373		    instance);
6006008Syy154373		goto error_level_0;
6016008Syy154373	}
6026008Syy154373	/* We do not support adapter drivers with high-level interrupts */
6036008Syy154373	if (ddi_intr_hilevel(dev_info, 0) != 0) {
6046008Syy154373		arcmsr_log(NULL, CE_WARN,
6056008Syy154373		    "arcmsr%d: high-level interrupt not supported",
6066008Syy154373		    instance);
6076008Syy154373		goto error_level_0;
6086008Syy154373	}
6096008Syy154373
6106008Syy154373	if (pci_config_setup(dev_info, &acb->pci_acc_handle)
6116008Syy154373	    != DDI_SUCCESS) {
6126008Syy154373		arcmsr_log(NULL, CE_NOTE,
6136008Syy154373		    "arcmsr%d: pci_config_setup() failed, attach failed",
6146008Syy154373		    instance);
6156008Syy154373		return (DDI_PROBE_FAILURE);
6166008Syy154373	}
6176008Syy154373
6186008Syy154373	wval = pci_config_get16(acb->pci_acc_handle, PCI_CONF_VENID);
6196008Syy154373	if (wval != PCI_VENDOR_ID_ARECA) {
6206008Syy154373		arcmsr_log(NULL, CE_NOTE,
6216008Syy154373		    "arcmsr%d: failing attach: 'vendorid (0x%04x) "
6226008Syy154373		    "does not match 0x%04x (PCI_VENDOR_ID_ARECA)\n",
6236008Syy154373		    instance, wval, PCI_VENDOR_ID_ARECA);
6246008Syy154373		return (DDI_PROBE_FAILURE);
6256008Syy154373	}
6266008Syy154373
6276008Syy154373	wval = pci_config_get16(acb->pci_acc_handle, PCI_CONF_DEVID);
6286008Syy154373	switch (wval) {
6296008Syy154373	case PCI_DEVICE_ID_ARECA_1110:
6306008Syy154373	case PCI_DEVICE_ID_ARECA_1210:
6316008Syy154373	case PCI_DEVICE_ID_ARECA_1201:
6326008Syy154373		raid6 = 0;
6336008Syy154373		/*FALLTHRU*/
6346008Syy154373	case PCI_DEVICE_ID_ARECA_1120:
6356008Syy154373	case PCI_DEVICE_ID_ARECA_1130:
6366008Syy154373	case PCI_DEVICE_ID_ARECA_1160:
6376008Syy154373	case PCI_DEVICE_ID_ARECA_1170:
6386008Syy154373	case PCI_DEVICE_ID_ARECA_1220:
6396008Syy154373	case PCI_DEVICE_ID_ARECA_1230:
6406008Syy154373	case PCI_DEVICE_ID_ARECA_1260:
6416008Syy154373	case PCI_DEVICE_ID_ARECA_1270:
6426008Syy154373	case PCI_DEVICE_ID_ARECA_1280:
6436008Syy154373		type = "SATA";
6446008Syy154373		break;
6456008Syy154373	case PCI_DEVICE_ID_ARECA_1380:
6466008Syy154373	case PCI_DEVICE_ID_ARECA_1381:
6476008Syy154373	case PCI_DEVICE_ID_ARECA_1680:
6486008Syy154373	case PCI_DEVICE_ID_ARECA_1681:
6496008Syy154373		type = "SAS";
6506008Syy154373		break;
6516008Syy154373	default:
6526008Syy154373		type = "X-TYPE";
6536008Syy154373		break;
6546008Syy154373	}
6556008Syy154373
6566008Syy154373	(void) sprintf(buf, "Areca %s Host Adapter RAID Controller%s",
6576008Syy154373	    type, raid6 ? " (RAID6 capable)" : "");
6586008Syy154373	cmn_err(CE_CONT, "arcmsr%d:%s ", instance, buf);
6596008Syy154373	cmn_err(CE_CONT, "arcmsr%d:%s ", instance, ARCMSR_DRIVER_VERSION);
6606008Syy154373
6616008Syy154373
6626008Syy154373	/* we disable iop interrupt here */
6636008Syy154373	if (arcmsr_initialize(acb) == DDI_FAILURE) {
6646008Syy154373		arcmsr_log(NULL, CE_WARN, "arcmsr%d: arcmsr_initialize "
6656008Syy154373		    "failed", instance);
6666008Syy154373		goto error_level_1;
6676008Syy154373	}
6686008Syy154373
6696008Syy154373	/*
6706008Syy154373	 * The driver must first obtain the iblock cookie to initialize
6716008Syy154373	 * mutexes used in the driver handler. Only after those mutexes
6726008Syy154373	 * have been initialized can the interrupt handler be added.
6736008Syy154373	 */
6746008Syy154373	if (ddi_get_iblock_cookie(dev_info, 0, &acb->iblock_cookie)
6756008Syy154373	    != DDI_SUCCESS) {
6766008Syy154373		arcmsr_log(NULL, CE_WARN, "arcmsr%d: "
6776008Syy154373		    "ddi_get_iblock_cookie failed", instance);
6786008Syy154373		goto error_level_2;
6796008Syy154373	}
6806008Syy154373	mutex_init(&acb->acb_mutex, NULL, MUTEX_DRIVER,
6816008Syy154373	    (void *)acb->iblock_cookie);
6826008Syy154373	mutex_init(&acb->postq_mutex, NULL, MUTEX_DRIVER,
6836008Syy154373	    (void *)acb->iblock_cookie);
6846008Syy154373	mutex_init(&acb->workingQ_mutex, NULL, MUTEX_DRIVER,
6856008Syy154373	    (void *)acb->iblock_cookie);
6866008Syy154373	mutex_init(&acb->ioctl_mutex, NULL, MUTEX_DRIVER,
6876008Syy154373	    (void *)acb->iblock_cookie);
6886008Syy154373
6896008Syy154373	/* Allocate a transport structure */
6906008Syy154373	hba_trans = scsi_hba_tran_alloc(dev_info, SCSI_HBA_CANSLEEP);
6916008Syy154373	if (hba_trans == NULL) {
6926008Syy154373		arcmsr_log(NULL, CE_WARN,
6936008Syy154373		    "arcmsr%d: scsi_hba_tran_alloc failed",
6946008Syy154373		    instance);
6956008Syy154373		goto error_level_3;
6966008Syy154373	}
6976008Syy154373	acb->scsi_hba_transport = hba_trans;
6986008Syy154373	acb->dev_info = dev_info;
6996008Syy154373	/* init scsi host adapter transport entry */
7006008Syy154373	hba_trans->tran_hba_private  = acb;
7016008Syy154373	hba_trans->tran_tgt_private  = NULL;
7026008Syy154373	/*
7036008Syy154373	 * If no per-target initialization is required, the HBA can leave
7046008Syy154373	 * tran_tgt_init set to NULL.
7056008Syy154373	 */
7066008Syy154373	hba_trans->tran_tgt_init = arcmsr_tran_tgt_init;
7076008Syy154373	hba_trans->tran_tgt_probe = scsi_hba_probe;
7086008Syy154373	hba_trans->tran_tgt_free = NULL;
7096008Syy154373	hba_trans->tran_start = arcmsr_tran_start;
7106008Syy154373	hba_trans->tran_abort = arcmsr_tran_abort;
7116008Syy154373	hba_trans->tran_reset = arcmsr_tran_reset;
7126008Syy154373	hba_trans->tran_getcap = arcmsr_tran_getcap;
7136008Syy154373	hba_trans->tran_setcap = arcmsr_tran_setcap;
7146008Syy154373	hba_trans->tran_init_pkt = arcmsr_tran_init_pkt;
7156008Syy154373	hba_trans->tran_destroy_pkt = arcmsr_tran_destroy_pkt;
7166008Syy154373	hba_trans->tran_dmafree = arcmsr_tran_dmafree;
7176008Syy154373	hba_trans->tran_sync_pkt = arcmsr_tran_sync_pkt;
7186008Syy154373
7196008Syy154373	hba_trans->tran_reset_notify = NULL;
7206008Syy154373	hba_trans->tran_get_bus_addr = NULL;
7216008Syy154373	hba_trans->tran_get_name = NULL;
7226008Syy154373	hba_trans->tran_quiesce = NULL;
7236008Syy154373	hba_trans->tran_unquiesce = NULL;
7246008Syy154373	hba_trans->tran_bus_reset = NULL;
7256008Syy154373	hba_trans->tran_bus_config = arcmsr_tran_bus_config;
7266008Syy154373	hba_trans->tran_add_eventcall = NULL;
7276008Syy154373	hba_trans->tran_get_eventcookie = NULL;
7286008Syy154373	hba_trans->tran_post_event = NULL;
7296008Syy154373	hba_trans->tran_remove_eventcall = NULL;
7306008Syy154373
7316008Syy154373	/* iop init and enable interrupt here */
7326008Syy154373	mutex_enter(&arcmsr_global_mutex);
7336008Syy154373	arcmsr_iop_init(acb);
7346008Syy154373	mutex_exit(&arcmsr_global_mutex);
7356008Syy154373
7366008Syy154373	/* Adding an Interrupt Handler */
7376008Syy154373	if (ddi_add_intr(dev_info, 0, &acb->iblock_cookie, 0,
7386008Syy154373	    arcmsr_interrupt, (caddr_t)acb) != DDI_SUCCESS) {
7396008Syy154373		arcmsr_log(NULL, CE_WARN,
7406008Syy154373		    "arcmsr%d: failed to add interrupt handler",
7416008Syy154373		    instance);
7426008Syy154373		goto error_level_4;
7436008Syy154373	}
7446008Syy154373	/*
7456008Syy154373	 * The driver should attach this instance of the device, and
7466008Syy154373	 * perform error cleanup if necessary
7476008Syy154373	 */
7486008Syy154373	if (scsi_hba_attach_setup(dev_info, &arcmsr_dma_attr,
7496008Syy154373	    hba_trans, SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) {
7506008Syy154373		arcmsr_log(NULL, CE_WARN,
7516008Syy154373		    "arcmsr%d: scsi_hba_attach_setup failed",
7526008Syy154373		    instance);
7536008Syy154373		goto error_level_5;
7546008Syy154373	}
7556008Syy154373
7566008Syy154373	if (ddi_create_minor_node(dev_info, "arcmsr",
7576008Syy154373	    S_IFCHR, INST2MSR(instance), DDI_PSEUDO, 0) == DDI_FAILURE) {
7586008Syy154373		arcmsr_log(NULL, CE_WARN,
7596008Syy154373		    "arcmsr%d: ddi_create_minor_node fail", instance);
7606008Syy154373		goto error_level_6;
7616008Syy154373	}
7626008Syy154373
7636008Syy154373
7646008Syy154373	/* Initialize power management bookkeeping. */
7656008Syy154373	if (pm_create_components(dev_info, 1) == DDI_SUCCESS) {
7666008Syy154373		if (pm_idle_component(dev_info, 0) == DDI_FAILURE) {
7676008Syy154373			arcmsr_log(NULL, CE_WARN,
7686008Syy154373			    "arcmsr%d: pm_idle_component fail",
7696008Syy154373			    instance);
7706008Syy154373			goto error_level_8;
7716008Syy154373		}
7726008Syy154373		pm_set_normal_power(dev_info, 0, 1);
7736008Syy154373		/* acb->power_level = 1; */
7746008Syy154373	} else {
7756008Syy154373		arcmsr_log(NULL, CE_WARN,
7766008Syy154373		    "arcmsr%d: pm_create_components fail",
7776008Syy154373		    instance);
7786008Syy154373		goto error_level_7;
7796008Syy154373	}
7806008Syy154373
7816008Syy154373	/*
7826008Syy154373	 * Since this driver manages devices with "remote" hardware, "
7836008Syy154373	 * i.e. the devices themselves have no "reg" property, the SUSPEND/
7846008Syy154373	 * RESUME commands in detach/attach will not be called by the power
7856008Syy154373	 * management framework unless we request it by creating a
7866008Syy154373	 * "pm-hardware-state" property and setting it to value
7876008Syy154373	 * "needs-suspend-resume".
7886008Syy154373	 */
7896008Syy154373	if (ddi_prop_update_string(DDI_DEV_T_NONE, dev_info,
7906008Syy154373	    "pm-hardware-state", "needs-suspend-resume")
7916008Syy154373	    != DDI_PROP_SUCCESS) {
7926008Syy154373		arcmsr_log(NULL, CE_WARN,
7936008Syy154373		    "arcmsr%d: ddi_prop_update(\"pm-hardware-state\")failed",
7946008Syy154373		    instance);
7956008Syy154373		goto error_level_8;
7966008Syy154373	}
7976008Syy154373
7986008Syy154373	/* Create a taskq for dealing with dr events */
7996008Syy154373	if ((acb->taskq = ddi_taskq_create(dev_info, "arcmsr_dr_taskq", 1,
8006008Syy154373	    TASKQ_DEFAULTPRI, 0)) == NULL) {
8016008Syy154373		cmn_err(CE_WARN, "ddi_taskq_create failed");
8026008Syy154373		goto error_level_8;
8036008Syy154373	}
8046008Syy154373
8056008Syy154373	acb->timeout_count = 0;
8066008Syy154373	/* active ccbs "timeout" watchdog */
8076008Syy154373	acb->timeout_id = timeout(arcmsr_ccbs_timeout, (caddr_t)acb,
8086008Syy154373	    (60 * drv_usectohz(1000000)));
8096008Syy154373	acb->timeout_sc_id = timeout(arcmsr_devmap_req_timeout, (caddr_t)acb,
8106008Syy154373	    (5 * drv_usectohz(1000000)));
8116008Syy154373
8126008Syy154373	/* report device info */
8136008Syy154373	ddi_report_dev(dev_info);
8146008Syy154373	ArcMSRHBA[arcmsr_hba_count] = acb;
8156008Syy154373	arcmsr_hba_count++;
8166008Syy154373
8176008Syy154373	return (DDI_SUCCESS);
8186008Syy154373
8196008Syy154373error_level_8:
8206008Syy154373	pm_destroy_components(dev_info);
8216008Syy154373
8226008Syy154373error_level_7:
8236008Syy154373	/* Remove any previously allocated minor nodes */
8246008Syy154373	ddi_remove_minor_node(dev_info, NULL);
8256008Syy154373
8266008Syy154373error_level_6:
8276008Syy154373	scsi_hba_tran_free(hba_trans);
8286008Syy154373
8296008Syy154373error_level_5:
8306008Syy154373	ddi_remove_intr(dev_info, 0, (void *)acb->iblock_cookie);
8316008Syy154373
8326008Syy154373error_level_4:
8336008Syy154373	scsi_hba_tran_free(hba_trans);
8346008Syy154373
8356008Syy154373error_level_3:
8366008Syy154373	mutex_destroy(&acb->acb_mutex);
8376008Syy154373	mutex_destroy(&acb->postq_mutex);
8386008Syy154373	mutex_destroy(&acb->workingQ_mutex);
8396008Syy154373	mutex_destroy(&acb->ioctl_mutex);
8406008Syy154373
8416008Syy154373error_level_2:
8426008Syy154373	ddi_dma_mem_free(&acb->ccbs_acc_handle);
8436008Syy154373	ddi_dma_free_handle(&acb->ccbs_pool_handle);
8446008Syy154373
8456008Syy154373error_level_1:
8466008Syy154373	ddi_soft_state_free(arcmsr_soft_state, instance);
8476008Syy154373
8486008Syy154373error_level_0:
8496008Syy154373	return (DDI_FAILURE);
8506008Syy154373}
8516008Syy154373
8526008Syy154373
8536008Syy154373
8546008Syy154373/*
8556008Syy154373 *      Function: arcmsr_attach(9E)
8566008Syy154373 *   Description: Set up all device state and allocate data structures,
8576008Syy154373 *		  mutexes, condition variables, etc. for device operation.
8586008Syy154373 *		  Set mt_attr property for driver to indicate MT-safety.
8596008Syy154373 *		  Add interrupts needed.
8606008Syy154373 *         Input: dev_info_t *dev_info, ddi_attach_cmd_t cmd
8616008Syy154373 *        Output: Return DDI_SUCCESS if device is ready,
8626008Syy154373 *		          else return DDI_FAILURE
8636008Syy154373 */
8646008Syy154373static int
8656008Syy154373arcmsr_attach(dev_info_t *dev_info, ddi_attach_cmd_t cmd) {
8666008Syy154373
8676008Syy154373	scsi_hba_tran_t *hba_trans;
8686008Syy154373	struct ACB *acb;
8696008Syy154373
8706008Syy154373
8716008Syy154373#if defined(ARCMSR_DEBUG)
8726008Syy154373	arcmsr_log(NULL, CE_NOTE,
8736008Syy154373	    "arcmsr_attach called for device %lx (instance %d)",
8746008Syy154373	    &dev_info, ddi_get_instance(dev_info));
8756008Syy154373#endif
8766008Syy154373	switch (cmd) {
8776008Syy154373	case DDI_ATTACH:
8786008Syy154373		return (arcmsr_do_ddi_attach(dev_info,
8796008Syy154373		    ddi_get_instance(dev_info)));
8806008Syy154373	case DDI_RESUME:
8816008Syy154373	case DDI_PM_RESUME:
8826008Syy154373	/*
8836008Syy154373	 * There is no hardware state to restart and no timeouts to
8846008Syy154373	 * restart since we didn't PM_SUSPEND with active cmds or
8856008Syy154373	 * active timeouts We just need to unblock waiting threads
8866008Syy154373	 * and restart I/O the code for DDI_RESUME is almost identical
8876008Syy154373	 * except it uses the suspend flag rather than pm_suspend flag
8886008Syy154373	 */
8896008Syy154373	    hba_trans = (scsi_hba_tran_t *)ddi_get_driver_private(dev_info);
8906008Syy154373	    if (!hba_trans) {
8916008Syy154373		    return (DDI_FAILURE);
8926008Syy154373	    }
8936008Syy154373	    acb = (struct ACB *)
8946008Syy154373		hba_trans->tran_hba_private;
8956008Syy154373	    mutex_enter(&acb->acb_mutex);
8966008Syy154373	    arcmsr_iop_init(acb);
8976008Syy154373
8986008Syy154373	    /* restart ccbs "timeout" watchdog */
8996008Syy154373	    acb->timeout_count = 0;
9006008Syy154373	    acb->timeout_id = timeout(arcmsr_ccbs_timeout,
9016008Syy154373		(caddr_t)acb, (60 * drv_usectohz(1000000)));
9026008Syy154373	    acb->timeout_sc_id = timeout(arcmsr_devmap_req_timeout,
9036008Syy154373		(caddr_t)acb, (5 * drv_usectohz(1000000)));
9046008Syy154373	    mutex_exit(&acb->acb_mutex);
9056008Syy154373	    return (DDI_SUCCESS);
9066008Syy154373
9076008Syy154373    default:
9086008Syy154373	    arcmsr_log(NULL, CE_WARN,
9096008Syy154373		"arcmsr%d: ddi attach cmd (%d) unsupported",
9106008Syy154373		cmd, ddi_get_instance(dev_info));
9116008Syy154373	    return (DDI_FAILURE);
9126008Syy154373	}
9136008Syy154373}
9146008Syy154373
9156008Syy154373/*
9166008Syy154373 *    Function:	arcmsr_detach(9E)
9176008Syy154373 * Description: Remove all device allocation and system resources, disable
9186008Syy154373 *		        device interrupt.
9196008Syy154373 *       Input: dev_info_t *dev_info
9206008Syy154373 *		        ddi_detach_cmd_t cmd
9216008Syy154373 *      Output:	Return DDI_SUCCESS if done,
9226008Syy154373 *		        else returnDDI_FAILURE
9236008Syy154373 */
9246008Syy154373static int
9256008Syy154373arcmsr_detach(dev_info_t *dev_info, ddi_detach_cmd_t cmd) {
9266008Syy154373
9276008Syy154373	int instance;
9286008Syy154373	struct ACB *acb;
9296008Syy154373
9306008Syy154373
9316008Syy154373	instance = ddi_get_instance(dev_info);
9326008Syy154373	acb = (struct ACB *)ddi_get_soft_state(arcmsr_soft_state,
9336008Syy154373	    instance);
9346008Syy154373	if (!acb) {
9356008Syy154373		return (DDI_FAILURE);
9366008Syy154373	}
9376008Syy154373
9386008Syy154373	switch (cmd) {
9396008Syy154373	case DDI_DETACH:
9406008Syy154373		mutex_enter(&acb->acb_mutex);
9416008Syy154373		if (acb->timeout_id != 0) {
9426008Syy154373			mutex_exit(&acb->acb_mutex);
9436008Syy154373			(void) untimeout(acb->timeout_id);
9446008Syy154373			mutex_enter(&acb->acb_mutex);
9456008Syy154373			acb->timeout_id = 0;
9466008Syy154373		}
9476008Syy154373		if (acb->timeout_sc_id != 0) {
9486008Syy154373			mutex_exit(&acb->acb_mutex);
9496008Syy154373			(void) untimeout(acb->timeout_sc_id);
9506008Syy154373			mutex_enter(&acb->acb_mutex);
9516008Syy154373			acb->timeout_sc_id = 0;
9526008Syy154373		}
9536008Syy154373		arcmsr_pcidev_disattach(acb);
9546008Syy154373		/* Remove interrupt set up by ddi_add_intr */
9556008Syy154373		ddi_remove_intr(dev_info, 0, acb->iblock_cookie);
9566008Syy154373		/* unbind mapping object to handle */
9576008Syy154373		(void) ddi_dma_unbind_handle(acb->ccbs_pool_handle);
9586008Syy154373		/* Free ccb pool memory */
9596008Syy154373		ddi_dma_mem_free(&acb->ccbs_acc_handle);
9606008Syy154373		/* Free DMA handle */
9616008Syy154373		ddi_dma_free_handle(&acb->ccbs_pool_handle);
9626008Syy154373		ddi_regs_map_free(&acb->reg_mu_acc_handle0);
9636008Syy154373		if (scsi_hba_detach(dev_info) != DDI_SUCCESS)
9646008Syy154373			arcmsr_log(NULL, CE_WARN,
9656008Syy154373			    "arcmsr%d: Unable to detach instance cleanly "
9666008Syy154373			    "(should not happen)",
9676008Syy154373			    ddi_get_instance(dev_info));
9686008Syy154373		/* free scsi_hba_transport from scsi_hba_tran_alloc */
9696008Syy154373		scsi_hba_tran_free(acb->scsi_hba_transport);
9706008Syy154373		ddi_remove_minor_node(dev_info, NULL);
9716008Syy154373		ddi_taskq_destroy(acb->taskq);
9726008Syy154373		ddi_prop_remove_all(dev_info);
9736008Syy154373		mutex_exit(&acb->acb_mutex);
9746008Syy154373		mutex_destroy(&acb->acb_mutex);
9756008Syy154373		mutex_destroy(&acb->postq_mutex);
9766008Syy154373		mutex_destroy(&acb->workingQ_mutex);
9776008Syy154373		mutex_destroy(&acb->ioctl_mutex);
9786008Syy154373		pci_config_teardown(&acb->pci_acc_handle);
9796008Syy154373		ddi_set_driver_private(dev_info, NULL);
9806008Syy154373		ddi_soft_state_free(arcmsr_soft_state, instance);
9816008Syy154373		pm_destroy_components(dev_info);
9826008Syy154373		return (DDI_SUCCESS);
9836008Syy154373	case DDI_SUSPEND:
9846008Syy154373	case DDI_PM_SUSPEND:
9856008Syy154373		mutex_enter(&acb->acb_mutex);
9866008Syy154373		if (acb->timeout_id != 0) {
9876008Syy154373			acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
9886008Syy154373			mutex_exit(&acb->acb_mutex);
9896008Syy154373			(void) untimeout(acb->timeout_id);
9906008Syy154373			(void) untimeout(acb->timeout_sc_id);
9916008Syy154373			mutex_enter(&acb->acb_mutex);
9926008Syy154373			acb->timeout_id = 0;
9936008Syy154373		}
9946008Syy154373
9956008Syy154373		if (acb->timeout_sc_id != 0) {
9966008Syy154373			acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
9976008Syy154373			mutex_exit(&acb->acb_mutex);
9986008Syy154373			(void) untimeout(acb->timeout_sc_id);
9996008Syy154373			mutex_enter(&acb->acb_mutex);
10006008Syy154373			acb->timeout_sc_id = 0;
10016008Syy154373		}
10026008Syy154373
10036008Syy154373		/* disable all outbound interrupt */
10046008Syy154373		(void) arcmsr_disable_allintr(acb);
10056008Syy154373		/* stop adapter background rebuild */
10066008Syy154373		if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
10076008Syy154373			arcmsr_stop_hba_bgrb(acb);
10086008Syy154373			arcmsr_flush_hba_cache(acb);
10096008Syy154373		} else {
10106008Syy154373			arcmsr_stop_hbb_bgrb(acb);
10116008Syy154373			arcmsr_flush_hbb_cache(acb);
10126008Syy154373		}
10136008Syy154373		mutex_exit(&acb->acb_mutex);
10146008Syy154373		return (DDI_SUCCESS);
10156008Syy154373	default:
10166008Syy154373		return (DDI_FAILURE);
10176008Syy154373	}
10186008Syy154373}
10196008Syy154373
10206008Syy154373
10216008Syy154373
10226008Syy154373/*
10236008Syy154373 *    Function:	arcmsr_tran_tgt_init
10246008Syy154373 * Description: Called when initializing a target device instance. If
10256008Syy154373 *		        no per-target initialization is required, the HBA
10266008Syy154373 *		        may leave tran_tgt_init to NULL
10276008Syy154373 *       Input:
10286008Syy154373 *		        dev_info_t *host_dev_info,
10296008Syy154373 *		        dev_info_t *target_dev_info,
10306008Syy154373 *		        scsi_hba_tran_t *tran,
10316008Syy154373 *		        struct scsi_device *sd
10326008Syy154373 *
10336008Syy154373 *      Return: DDI_SUCCESS if success, else return DDI_FAILURE
10346008Syy154373 *
10356008Syy154373 *  entry point enables the HBA to allocate and/or initialize any per-
10366008Syy154373 *  target resources.
10376008Syy154373 *  It also enables the HBA to qualify the device's address as valid and
10386008Syy154373 *  supportable for that particular HBA.
10396008Syy154373 *  By returning DDI_FAILURE, the instance of the target driver for that
10406008Syy154373 *  device will not be probed or attached.
10416008Syy154373 * 	This entry point is not required, and if none is supplied,
10426008Syy154373 *  the framework will attempt to probe and attach all possible instances
10436008Syy154373 *  of the appropriate target drivers.
10446008Syy154373 */
10456008Syy154373static int
10466008Syy154373arcmsr_tran_tgt_init(dev_info_t *host_dev_info, dev_info_t *target_dev_info,
10476008Syy154373    scsi_hba_tran_t *hosttran, struct scsi_device *sd) {
10486008Syy154373#ifndef __lock_lint
10496008Syy154373	_NOTE(ARGUNUSED(hosttran, target_dev_info))
10506008Syy154373#endif
10516008Syy154373	uint16_t  target;
10526008Syy154373	uint8_t  lun;
10536008Syy154373	struct ACB *acb = (struct ACB *)sd->sd_address.a_hba_tran ->
10546008Syy154373	    tran_hba_private;
10556008Syy154373
10566008Syy154373	target = sd->sd_address.a_target;
10576008Syy154373	lun = sd->sd_address.a_lun;
10586008Syy154373	if ((target >= ARCMSR_MAX_TARGETID) || (lun >= ARCMSR_MAX_TARGETLUN)) {
10596008Syy154373		cmn_err(CE_WARN,
10606008Syy154373		    "arcmsr%d: (target %d, lun %d) exceeds "
10616008Syy154373		    "maximum supported values (%d, %d)",
10626008Syy154373		    ddi_get_instance(host_dev_info),
10636008Syy154373		    target, lun, ARCMSR_MAX_TARGETID, ARCMSR_MAX_TARGETLUN);
10646008Syy154373		return (DDI_FAILURE);
10656008Syy154373	}
10666008Syy154373
10676008Syy154373
10686008Syy154373	if (ndi_dev_is_persistent_node(target_dev_info) == 0) {
10696008Syy154373		/*
10706008Syy154373		 * If no persistent node exist, we don't allow .conf node
10716008Syy154373		 * to be created.
10726008Syy154373		 */
10736008Syy154373		if (arcmsr_find_child(acb, target, lun) != NULL) {
10746008Syy154373			if ((ndi_merge_node(target_dev_info,
10756008Syy154373				    arcmsr_name_node) != DDI_SUCCESS)) {
10766008Syy154373				return (DDI_SUCCESS);
10776008Syy154373			}
10786008Syy154373		}
10796008Syy154373		return (DDI_FAILURE);
10806008Syy154373	}
10816008Syy154373
10826008Syy154373	return (DDI_SUCCESS);
10836008Syy154373}
10846008Syy154373
10856008Syy154373/*
10866008Syy154373 *         Function: arcmsr_tran_getcap(9E)
10876008Syy154373 *      Description: Get the capability named, and returnits value.
10886008Syy154373 *    Return Values: current value of capability, ifdefined
10896008Syy154373 *		             -1 ifcapability is not defined
10906008Syy154373 * ------------------------------------------------------
10916008Syy154373 *         Common Capability Strings Array
10926008Syy154373 * ------------------------------------------------------
10936008Syy154373 *	#define	SCSI_CAP_DMA_MAX		0
10946008Syy154373 *	#define	SCSI_CAP_MSG_OUT		1
10956008Syy154373 *	#define	SCSI_CAP_DISCONNECT		2
10966008Syy154373 *	#define	SCSI_CAP_SYNCHRONOUS		3
10976008Syy154373 *	#define	SCSI_CAP_WIDE_XFER		4
10986008Syy154373 *	#define	SCSI_CAP_PARITY			5
10996008Syy154373 *	#define	SCSI_CAP_INITIATOR_ID		6
11006008Syy154373 *	#define	SCSI_CAP_UNTAGGED_QING		7
11016008Syy154373 *	#define	SCSI_CAP_TAGGED_QING		8
11026008Syy154373 *	#define	SCSI_CAP_ARQ			9
11036008Syy154373 *	#define	SCSI_CAP_LINKED_CMDS		10 a
11046008Syy154373 *	#define	SCSI_CAP_SECTOR_SIZE		11 b
11056008Syy154373 *	#define	SCSI_CAP_TOTAL_SECTORS		12 c
11066008Syy154373 *	#define	SCSI_CAP_GEOMETRY		13 d
11076008Syy154373 *	#define	SCSI_CAP_RESET_NOTIFICATION	14 e
11086008Syy154373 *	#define	SCSI_CAP_QFULL_RETRIES		15 f
11096008Syy154373 *	#define	SCSI_CAP_QFULL_RETRY_INTERVAL	16 10
11106008Syy154373 *	#define	SCSI_CAP_SCSI_VERSION		17 11
11116008Syy154373 *	#define	SCSI_CAP_INTERCONNECT_TYPE	18 12
11126008Syy154373 *	#define	SCSI_CAP_LUN_RESET		19 13
11136008Syy154373 */
11146008Syy154373static int
11156008Syy154373arcmsr_tran_getcap(struct scsi_address *ap, char *cap, int whom) {
11166008Syy154373
11176008Syy154373	int capability = 0;
11186008Syy154373	struct ACB *acb =
11196008Syy154373	    (struct ACB *)ap->a_hba_tran->tran_hba_private;
11206008Syy154373
11216008Syy154373
11226008Syy154373	if (cap == NULL || whom == 0) {
11236008Syy154373		return (DDI_FAILURE);
11246008Syy154373	}
11256008Syy154373
11266008Syy154373	mutex_enter(&arcmsr_global_mutex);
11276008Syy154373	switch (scsi_hba_lookup_capstr(cap)) {
11286008Syy154373	case SCSI_CAP_MSG_OUT:
11296008Syy154373	case SCSI_CAP_DISCONNECT:
11306008Syy154373	case SCSI_CAP_SYNCHRONOUS:
11316008Syy154373	case SCSI_CAP_WIDE_XFER:
11326008Syy154373	case SCSI_CAP_TAGGED_QING:
11336008Syy154373	case SCSI_CAP_UNTAGGED_QING:
11346008Syy154373	case SCSI_CAP_PARITY:
11356008Syy154373	case SCSI_CAP_ARQ:
11366008Syy154373		capability = acb->tgt_scsi_opts[ap->a_target];
11376008Syy154373		break;
11386008Syy154373	case SCSI_CAP_SECTOR_SIZE:
11396008Syy154373		capability = ARCMSR_DEV_SECTOR_SIZE;
11406008Syy154373		break;
11416008Syy154373	case SCSI_CAP_DMA_MAX:
11426008Syy154373		/* Limit to 16MB max transfer */
11436008Syy154373		capability = ARCMSR_MAX_XFER_LEN;
11446008Syy154373		break;
11456008Syy154373	case SCSI_CAP_INITIATOR_ID:
11466008Syy154373		capability = ARCMSR_SCSI_INITIATOR_ID;
11476008Syy154373		break;
11486008Syy154373	case SCSI_CAP_GEOMETRY:
11496008Syy154373		/* head , track , cylinder */
11506008Syy154373		capability = (255 << 16) | 63;
11516008Syy154373		break;
11526008Syy154373	default:
11536008Syy154373		capability = -1;
11546008Syy154373		break;
11556008Syy154373	}
11566008Syy154373	mutex_exit(&arcmsr_global_mutex);
11576008Syy154373	return (capability);
11586008Syy154373}
11596008Syy154373
11606008Syy154373/*
11616008Syy154373 *      Function: arcmsr_tran_setcap(9E)
11626008Syy154373 *   Description: Set the specific capability.
11636008Syy154373 * Return Values: 1 - capability exists and can be set to new value
11646008Syy154373 *		          0 - capability could not be set to new value
11656008Syy154373 *		         -1 - no such capability
11666008Syy154373 */
11676008Syy154373static int
11686008Syy154373arcmsr_tran_setcap(struct scsi_address *ap, char *cap, int value,
11696008Syy154373    int whom) {
11706008Syy154373#ifndef __lock_lint
11716008Syy154373	_NOTE(ARGUNUSED(value))
11726008Syy154373#endif
11736008Syy154373
11746008Syy154373
11756008Syy154373	int supported = 0;
11766008Syy154373	struct ACB *acb =
11776008Syy154373	    (struct ACB *)ap->a_hba_tran->tran_hba_private;
11786008Syy154373
11796008Syy154373
11806008Syy154373	if (cap == NULL || whom == 0) {
11816008Syy154373		return (-1);
11826008Syy154373	}
11836008Syy154373
11846008Syy154373	mutex_enter(&arcmsr_global_mutex);
11856008Syy154373	switch (supported = scsi_hba_lookup_capstr(cap)) {
11866008Syy154373	case SCSI_CAP_DISCONNECT:		/* 2 */
11876008Syy154373	case SCSI_CAP_SYNCHRONOUS:		/* 3 */
11886008Syy154373	case SCSI_CAP_TAGGED_QING:		/* 8 */
11896008Syy154373	case SCSI_CAP_WIDE_XFER:		/* 4 */
11906008Syy154373	case SCSI_CAP_ARQ:			/* 9 auto request sense */
11916008Syy154373	case SCSI_CAP_TOTAL_SECTORS:		/* c */
11926008Syy154373		acb->tgt_scsi_opts[ap->a_target] |= supported;
11936008Syy154373		supported = 1;
11946008Syy154373		break;
11956008Syy154373	case SCSI_CAP_UNTAGGED_QING:   		/* 7 */
11966008Syy154373	case SCSI_CAP_INITIATOR_ID:		/* 6 */
11976008Syy154373	case SCSI_CAP_DMA_MAX:			/* 0 */
11986008Syy154373	case SCSI_CAP_MSG_OUT:			/* 1 */
11996008Syy154373	case SCSI_CAP_PARITY:			/* 5 */
12006008Syy154373	case SCSI_CAP_LINKED_CMDS:		/* a */
12016008Syy154373	case SCSI_CAP_RESET_NOTIFICATION:	/* e */
12026008Syy154373	case SCSI_CAP_SECTOR_SIZE:		/* b */
12036008Syy154373		supported = 0;
12046008Syy154373		break;
12056008Syy154373	default:
12066008Syy154373		supported = -1;
12076008Syy154373		break;
12086008Syy154373	}
12096008Syy154373	mutex_exit(&arcmsr_global_mutex);
12106008Syy154373	return (supported);
12116008Syy154373}
12126008Syy154373
12136008Syy154373
12146008Syy154373
12156008Syy154373static void
12166008Syy154373arcmsr_free_ccb(struct CCB *ccb) {
12176008Syy154373
12186008Syy154373	struct ACB *acb = ccb->acb;
12196008Syy154373
12206008Syy154373	ccb->startdone = ARCMSR_CCB_DONE;
12216008Syy154373	ccb->pkt = NULL;
12226008Syy154373	ccb->ccb_flags = 0;
12236008Syy154373	mutex_enter(&acb->workingQ_mutex);
12246008Syy154373	acb->ccbworkingQ[acb->workingccb_doneindex] = ccb;
12256008Syy154373	acb->workingccb_doneindex++;
12266008Syy154373	acb->workingccb_doneindex %= ARCMSR_MAX_FREECCB_NUM;
12276008Syy154373	mutex_exit(&acb->workingQ_mutex);
12286008Syy154373}
12296008Syy154373
12306008Syy154373/*
12316008Syy154373 *      Function: arcmsr_tran_init_pkt
12326008Syy154373 * Return Values: pointer to scsi_pkt, or NULL
12336008Syy154373 *   Description: simultaneously allocate both a scsi_pkt(9S) structure and
12346008Syy154373 *                DMA resources for that pkt.
12356008Syy154373 *                Called by kernel on behalf of a target driver
12366008Syy154373 *		          calling scsi_init_pkt(9F).
12376008Syy154373 *		          Refer to tran_init_pkt(9E) man page
12386008Syy154373 *       Context: Can be called from different kernel process threads.
12396008Syy154373 *		          Can be called by interrupt thread.
12406008Syy154373 * Allocates SCSI packet and DMA resources
12416008Syy154373 */
12426008Syy154373static struct
12436008Syy154373scsi_pkt *arcmsr_tran_init_pkt(struct scsi_address *ap,
12446008Syy154373    register struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
12456008Syy154373    int tgtlen, int flags, int (*callback)(), caddr_t arg) {
12466008Syy154373
12476008Syy154373	struct CCB *ccb;
12486008Syy154373	struct ARCMSR_CDB *arcmsr_cdb;
12496008Syy154373	struct ACB *acb;
12506008Syy154373	int old_pkt_flag = 1;
12516008Syy154373
12526008Syy154373
12536008Syy154373	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
12546008Syy154373
12556008Syy154373	if (pkt == NULL) {
12566008Syy154373		/* get free CCB */
12576008Syy154373		ccb = arcmsr_get_freeccb(acb);
12586008Syy154373		if (ccb == (struct CCB *)NULL) {
12596008Syy154373			return (NULL);
12606008Syy154373		}
12616008Syy154373
12626008Syy154373		if (ccb->pkt != NULL) {
12636008Syy154373			/*
12646008Syy154373			 * If kmem_flags are turned on, expect to
12656008Syy154373			 * see a message
12666008Syy154373			 */
12676008Syy154373			cmn_err(CE_WARN, "arcmsr%d: invalid pkt",
12686008Syy154373			    ddi_get_instance(acb->dev_info));
12696008Syy154373			return (NULL);
12706008Syy154373		}
12716008Syy154373		pkt = scsi_hba_pkt_alloc(acb->dev_info, ap, cmdlen,
12726008Syy154373		    statuslen, tgtlen, sizeof (struct scsi_pkt),
12736008Syy154373		    callback, arg);
12746008Syy154373		if (pkt == NULL) {
12756008Syy154373			cmn_err(CE_WARN,
12766008Syy154373			    "arcmsr%d: scsi pkt allocation failed",
12776008Syy154373			    ddi_get_instance(acb->dev_info));
12786008Syy154373			arcmsr_free_ccb(ccb);
12796008Syy154373			return (NULL);
12806008Syy154373		}
12816008Syy154373		/* Initialize CCB */
12826008Syy154373		ccb->pkt = pkt;
12836008Syy154373		ccb->pkt_dma_handle = NULL;
12846008Syy154373		/* record how many sg are needed to xfer on this pkt */
12856008Syy154373		ccb->pkt_ncookies = 0;
12866008Syy154373		/* record how many sg we got from this window */
12876008Syy154373		ccb->pkt_cookie = 0;
12886008Syy154373		/* record how many windows have partial dma map set */
12896008Syy154373		ccb->pkt_nwin = 0;
12906008Syy154373		/* record current sg window position */
12916008Syy154373		ccb->pkt_curwin	= 0;
12926008Syy154373		ccb->pkt_dma_len = 0;
12936008Syy154373		ccb->pkt_dma_offset = 0;
12946008Syy154373		ccb->resid_dmacookie.dmac_size = 0;
12956008Syy154373
12966008Syy154373		/*
12976008Syy154373		 * we will still use this point for we want to fake some
12986008Syy154373		 * information in tran_start
12996008Syy154373		 */
13006008Syy154373		ccb->bp = bp;
13016008Syy154373
13026008Syy154373		/* Initialize arcmsr_cdb */
13036008Syy154373		arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
13046008Syy154373		bzero(arcmsr_cdb, sizeof (struct ARCMSR_CDB));
13056008Syy154373		arcmsr_cdb->Bus = 0;
13066008Syy154373		arcmsr_cdb->Function = 1;
13076008Syy154373		arcmsr_cdb->LUN = ap->a_lun;
13086008Syy154373		arcmsr_cdb->TargetID = ap->a_target;
13096008Syy154373		arcmsr_cdb->CdbLength = (uint8_t)cmdlen;
13106008Syy154373		arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
13116008Syy154373
13126008Syy154373		/* Fill in the rest of the structure */
13136008Syy154373		pkt->pkt_ha_private = ccb;
13146008Syy154373		pkt->pkt_address = *ap;
13156008Syy154373		pkt->pkt_comp = (void (*)())NULL;
13166008Syy154373		pkt->pkt_flags = 0;
13176008Syy154373		pkt->pkt_time = 0;
13186008Syy154373		pkt->pkt_resid = 0;
13196008Syy154373		pkt->pkt_statistics = 0;
13206008Syy154373		pkt->pkt_reason = 0;
13216008Syy154373		old_pkt_flag = 0;
13226008Syy154373	} else {
13236008Syy154373		ccb = (struct CCB *)pkt->pkt_ha_private;
13246008Syy154373		/*
13256008Syy154373		 * you cannot update CdbLength with cmdlen here, it would
13266008Syy154373		 * cause a data compare error
13276008Syy154373		 */
13286008Syy154373		ccb->startdone = ARCMSR_CCB_UNBUILD;
13296008Syy154373	}
13306008Syy154373
13316008Syy154373	/* Second step : dma allocation/move */
13326008Syy154373	if (bp && bp->b_bcount != 0) {
13336008Syy154373		/*
13346008Syy154373		 * system had a lot of data trunk need to xfer, from...20 byte
13356008Syy154373		 * to 819200 byte.
13366008Syy154373		 * arcmsr_dma_alloc will get pkt_dma_handle (not null) until
13376008Syy154373		 * this lot of data trunk xfer done this mission will be done
13386008Syy154373		 * by some of continue READ or WRITE scsi command, till this
13396008Syy154373		 * lot of data trunk xfer completed.
13406008Syy154373		 * arcmsr_dma_move do the action repeatedly, and use the same
13416008Syy154373		 * ccb till this lot of data trunk xfer complete notice.
13426008Syy154373		 * when after the arcmsr_tran_init_pkt returns the solaris
13436008Syy154373		 * kernel is by your pkt_resid and its b_bcount to give you
13446008Syy154373		 * which type of scsi command descriptor to implement the
13456008Syy154373		 * length of folowing arcmsr_tran_start scsi cdb (data length)
13466008Syy154373		 *
13476008Syy154373		 * Each transfer should be aligned on a 512 byte boundary
13486008Syy154373		 */
13496008Syy154373		if (ccb->pkt_dma_handle == NULL) {
13506008Syy154373			if (arcmsr_dma_alloc(acb, pkt, bp, flags,
13516008Syy154373			    callback) == DDI_FAILURE) {
13526008Syy154373				/*
13536008Syy154373				 * the HBA driver is unable to allocate DMA
13546008Syy154373				 * resources, it must free the allocated
13556008Syy154373				 * scsi_pkt(9S) before returning
13566008Syy154373				 */
13576008Syy154373				cmn_err(CE_WARN, "arcmsr%d: dma allocation "
13586008Syy154373				    "failure ",
13596008Syy154373				    ddi_get_instance(acb->dev_info));
13606008Syy154373				if (old_pkt_flag == 0) {
13616008Syy154373					cmn_err(CE_WARN, "arcmsr%d: dma "
13626008Syy154373					    "allocation failed to free scsi "
13636008Syy154373					    "hba pkt ",
13646008Syy154373					    ddi_get_instance(acb->dev_info));
13656008Syy154373					arcmsr_free_ccb(ccb);
13666008Syy154373					scsi_hba_pkt_free(ap, pkt);
13676008Syy154373				}
13686008Syy154373				return ((struct scsi_pkt *)NULL);
13696008Syy154373			}
13706008Syy154373		} else {
13716008Syy154373			/* DMA resources to next DMA window, for old pkt */
13726008Syy154373			if (arcmsr_dma_move(acb, pkt, bp) == -1) {
13736008Syy154373				cmn_err(CE_WARN, "arcmsr%d: dma move "
13746008Syy154373				    "failed ",
13756008Syy154373				    ddi_get_instance(acb->dev_info));
13766008Syy154373				return ((struct scsi_pkt *)NULL);
13776008Syy154373			}
13786008Syy154373		}
13796008Syy154373	} else {
13806008Syy154373		pkt->pkt_resid = 0;
13816008Syy154373	}
13826008Syy154373	return (pkt);
13836008Syy154373}
13846008Syy154373
13856008Syy154373/*
13866008Syy154373 * Function name: arcmsr_dma_alloc
13876008Syy154373 * Return Values: 0 if successful, -1 if failure
13886008Syy154373 *   Description: allocate DMA resources
13896008Syy154373 *       Context: Can only be called from arcmsr_tran_init_pkt()
13906008Syy154373 *     register struct scsi_address	*ap = &((pkt)->pkt_address);
13916008Syy154373 */
13926008Syy154373static int
13936008Syy154373arcmsr_dma_alloc(struct ACB *acb, struct scsi_pkt *pkt,
13946008Syy154373    struct buf *bp, int flags, int (*callback)()) {
13956008Syy154373
13966008Syy154373	struct CCB *ccb = pkt->pkt_ha_private;
13976008Syy154373	int alloc_result, map_method, dma_flags;
13986008Syy154373	int resid = 0;
13996008Syy154373	int total_ccb_xferlen = 0;
14006008Syy154373	int (*cb)(caddr_t);
14016008Syy154373	uint8_t i;
14026008Syy154373
14036008Syy154373	/*
14046008Syy154373	 * at this point the PKT SCSI CDB is empty, and dma xfer length
14056008Syy154373	 * is bp->b_bcount
14066008Syy154373	 */
14076008Syy154373
14086008Syy154373	if (bp->b_flags & B_READ) {
14096008Syy154373		ccb->ccb_flags &= ~CCB_FLAG_DMAWRITE;
14106008Syy154373		dma_flags = DDI_DMA_READ;
14116008Syy154373	} else {
14126008Syy154373		ccb->ccb_flags |= CCB_FLAG_DMAWRITE;
14136008Syy154373		dma_flags = DDI_DMA_WRITE;
14146008Syy154373	}
14156008Syy154373
14166008Syy154373	if (flags & PKT_CONSISTENT) {
14176008Syy154373		ccb->ccb_flags |= CCB_FLAG_DMACONSISTENT;
14186008Syy154373		dma_flags |= DDI_DMA_CONSISTENT;
14196008Syy154373	}
14206008Syy154373	if (flags & PKT_DMA_PARTIAL) {
14216008Syy154373		dma_flags |= DDI_DMA_PARTIAL;
14226008Syy154373	}
14236008Syy154373
14246008Syy154373	dma_flags |= DDI_DMA_REDZONE;
14256008Syy154373	cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP;
14266008Syy154373
14276008Syy154373	if ((alloc_result = ddi_dma_alloc_handle(acb->dev_info,
14286008Syy154373	    &arcmsr_dma_attr, cb, 0, &ccb->pkt_dma_handle))
14296008Syy154373	    != DDI_SUCCESS) {
14306008Syy154373		switch (alloc_result) {
14316008Syy154373		case DDI_DMA_BADATTR:
14326008Syy154373			/*
14336008Syy154373			 * If the system does not support physical DMA,
14346008Syy154373			 * the return value from ddi_dma_alloc_handle
14356008Syy154373			 * will be DDI_DMA_BADATTR
14366008Syy154373			 */
14376008Syy154373			cmn_err(CE_WARN, "arcmsr%d: dma allocate returned "
14386008Syy154373			    "'bad attribute'",
14396008Syy154373			    ddi_get_instance(acb->dev_info));
14406008Syy154373			bioerror(bp, EFAULT);
14416008Syy154373			return (DDI_FAILURE);
14426008Syy154373		case DDI_DMA_NORESOURCES:
14436008Syy154373			cmn_err(CE_WARN, "arcmsr%d: dma allocate returned "
14446008Syy154373			    "'no resources'",
14456008Syy154373			    ddi_get_instance(acb->dev_info));
14466008Syy154373			bioerror(bp, 0);
14476008Syy154373			return (DDI_FAILURE);
14486008Syy154373		default:
14496008Syy154373			cmn_err(CE_WARN, "arcmsr%d: dma allocate returned "
14506008Syy154373			    "'unknown failure'",
14516008Syy154373			    ddi_get_instance(acb->dev_info));
14526008Syy154373			return (DDI_FAILURE);
14536008Syy154373		}
14546008Syy154373	}
14556008Syy154373
14566008Syy154373	map_method = ddi_dma_buf_bind_handle(ccb->pkt_dma_handle, bp,
14576008Syy154373	    dma_flags, cb, 0,
14586008Syy154373	    &ccb->pkt_dmacookies[0],	/* SG List pointer */
14596008Syy154373	    &ccb->pkt_ncookies);	/* number of sgl cookies */
14606008Syy154373
14616008Syy154373	switch (map_method) {
14626008Syy154373	case DDI_DMA_PARTIAL_MAP:
14636008Syy154373		/*
14646008Syy154373		 * When your main memory size larger then 4G
14656008Syy154373		 * DDI_DMA_PARTIAL_MAP will be touched.
14666008Syy154373		 *
14676008Syy154373		 * We've already set DDI_DMA_PARTIAL in dma_flags,
14686008Syy154373		 * so if it's now missing, there's something screwy
14696008Syy154373		 * happening. We plow on....
14706008Syy154373		 */
14716008Syy154373
14726008Syy154373		if ((dma_flags & DDI_DMA_PARTIAL) == 0) {
14736008Syy154373			cmn_err(CE_WARN, "arcmsr%d: dma partial mapping lost "
14746008Syy154373			    "...impossible case!",
14756008Syy154373			    ddi_get_instance(acb->dev_info));
14766008Syy154373		}
14776008Syy154373		if (ddi_dma_numwin(ccb->pkt_dma_handle, &ccb->pkt_nwin) ==
14786008Syy154373		    DDI_FAILURE) {
14796008Syy154373			cmn_err(CE_WARN, "arcmsr%d: ddi_dma_numwin() failed",
14806008Syy154373			    ddi_get_instance(acb->dev_info));
14816008Syy154373		}
14826008Syy154373
14836008Syy154373		if (ddi_dma_getwin(ccb->pkt_dma_handle, ccb->pkt_curwin,
14846008Syy154373		    &ccb->pkt_dma_offset, &ccb->pkt_dma_len,
14856008Syy154373		    &ccb->pkt_dmacookies[0], &ccb->pkt_ncookies) ==
14866008Syy154373		    DDI_FAILURE) {
14876008Syy154373			cmn_err(CE_WARN, "arcmsr%d: ddi_dma_getwin failed",
14886008Syy154373			    ddi_get_instance(acb->dev_info));
14896008Syy154373		}
14906008Syy154373
14916008Syy154373		i = 0;
14926008Syy154373		/* first cookie is accessed from ccb->pkt_dmacookies[0] */
14936008Syy154373		total_ccb_xferlen = ccb->pkt_dmacookies[0].dmac_size;
14946008Syy154373		for (;;) {
14956008Syy154373			i++;
14966008Syy154373			if (i == ARCMSR_MAX_SG_ENTRIES ||
14976008Syy154373			    i == ccb->pkt_ncookies ||
14986008Syy154373			    total_ccb_xferlen == ARCMSR_MAX_XFER_LEN) {
14996008Syy154373				break;
15006008Syy154373			}
15016008Syy154373			/*
15026008Syy154373			 * next cookie will be retrieved from
15036008Syy154373			 * ccb->pkt_dmacookies[i]
15046008Syy154373			 */
15056008Syy154373			ddi_dma_nextcookie(ccb->pkt_dma_handle,
15066008Syy154373			    &ccb->pkt_dmacookies[i]);
15076008Syy154373			total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
15086008Syy154373		}
15096008Syy154373		ccb->pkt_cookie = i;
15106008Syy154373		ccb->arcmsr_cdb.sgcount = i;
15116008Syy154373		if (total_ccb_xferlen > 512) {
15126008Syy154373			resid = total_ccb_xferlen % 512;
15136008Syy154373			if (resid != 0) {
15146008Syy154373				i--;
15156008Syy154373				total_ccb_xferlen -= resid;
15166008Syy154373				/* modify last sg length */
15176008Syy154373				ccb->pkt_dmacookies[i].dmac_size =
15186008Syy154373				    ccb->pkt_dmacookies[i].dmac_size - resid;
15196008Syy154373				ccb->resid_dmacookie.dmac_size = resid;
15206008Syy154373				ccb->resid_dmacookie.dmac_laddress =
15216008Syy154373				    ccb->pkt_dmacookies[i].dmac_laddress +
15226008Syy154373				    ccb->pkt_dmacookies[i].dmac_size;
15236008Syy154373			}
15246008Syy154373		}
15256008Syy154373		ccb->total_dmac_size = total_ccb_xferlen;
15266008Syy154373		ccb->ccb_flags |= CCB_FLAG_DMAVALID;
15276008Syy154373		pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size;
15286008Syy154373
15296008Syy154373		return (DDI_SUCCESS);
15306008Syy154373
15316008Syy154373	case DDI_DMA_MAPPED:
15326008Syy154373		ccb->pkt_nwin = 1; /* all mapped, so only one window */
15336008Syy154373		ccb->pkt_dma_len = 0;
15346008Syy154373		ccb->pkt_dma_offset = 0;
15356008Syy154373		i = 0;
15366008Syy154373		/* first cookie is accessed from ccb->pkt_dmacookies[0] */
15376008Syy154373		total_ccb_xferlen = ccb->pkt_dmacookies[0].dmac_size;
15386008Syy154373		for (;;) {
15396008Syy154373			i++;
15406008Syy154373			if (i == ARCMSR_MAX_SG_ENTRIES ||
15416008Syy154373			    i == ccb->pkt_ncookies ||
15426008Syy154373			    total_ccb_xferlen == ARCMSR_MAX_XFER_LEN) {
15436008Syy154373				break;
15446008Syy154373			}
15456008Syy154373			/*
15466008Syy154373			 * next cookie will be retrieved from
15476008Syy154373			 * ccb->pkt_dmacookies[i]
15486008Syy154373			 */
15496008Syy154373			ddi_dma_nextcookie(ccb->pkt_dma_handle,
15506008Syy154373			    &ccb->pkt_dmacookies[i]);
15516008Syy154373			total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
15526008Syy154373		}
15536008Syy154373		ccb->pkt_cookie = i;
15546008Syy154373		ccb->arcmsr_cdb.sgcount = i;
15556008Syy154373		if (total_ccb_xferlen > 512) {
15566008Syy154373			resid = total_ccb_xferlen % 512;
15576008Syy154373			    if (resid != 0) {
15586008Syy154373				i--;
15596008Syy154373				total_ccb_xferlen -= resid;
15606008Syy154373				/* modify last sg length */
15616008Syy154373				ccb->pkt_dmacookies[i].dmac_size =
15626008Syy154373				    ccb->pkt_dmacookies[i].dmac_size - resid;
15636008Syy154373				ccb->resid_dmacookie.dmac_size = resid;
15646008Syy154373				ccb->resid_dmacookie.dmac_laddress =
15656008Syy154373				    ccb->pkt_dmacookies[i].dmac_laddress +
15666008Syy154373				    ccb->pkt_dmacookies[i].dmac_size;
15676008Syy154373			}
15686008Syy154373		}
15696008Syy154373		ccb->total_dmac_size = total_ccb_xferlen;
15706008Syy154373		ccb->ccb_flags |= CCB_FLAG_DMAVALID;
15716008Syy154373		pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size;
15726008Syy154373		return (DDI_SUCCESS);
15736008Syy154373
15746008Syy154373	case DDI_DMA_NORESOURCES:
15756008Syy154373		cmn_err(CE_WARN, "arcmsr%d: dma map got 'no resources'",
15766008Syy154373		    ddi_get_instance(acb->dev_info));
15776008Syy154373		bioerror(bp, ENOMEM);
15786008Syy154373		break;
15796008Syy154373
15806008Syy154373	case DDI_DMA_NOMAPPING:
15816008Syy154373		cmn_err(CE_WARN, "arcmsr%d: dma map got 'no mapping'",
15826008Syy154373		    ddi_get_instance(acb->dev_info));
15836008Syy154373		bioerror(bp, EFAULT);
15846008Syy154373		break;
15856008Syy154373
15866008Syy154373	case DDI_DMA_TOOBIG:
15876008Syy154373		cmn_err(CE_WARN, "arcmsr%d: dma map got 'too big'",
15886008Syy154373		    ddi_get_instance(acb->dev_info));
15896008Syy154373		bioerror(bp, EINVAL);
15906008Syy154373		break;
15916008Syy154373
15926008Syy154373	case DDI_DMA_INUSE:
15936008Syy154373		cmn_err(CE_WARN, "arcmsr%d: dma map got 'in use' "
15946008Syy154373		    "(should not happen)",
15956008Syy154373		    ddi_get_instance(acb->dev_info));
15966008Syy154373		break;
15976008Syy154373	default:
15986008Syy154373		cmn_err(CE_WARN,
15996008Syy154373		    "arcmsr%d: dma map got 'unknown failure 0x%x' "
16006008Syy154373		    "(should not happen)",
16016008Syy154373		    ddi_get_instance(acb->dev_info), i);
16026008Syy154373#ifdef ARCMSR_DEBUG
16036008Syy154373		arcmsr_dump_scsi_cdb(&pkt->pkt_address, pkt);
16046008Syy154373#endif
16056008Syy154373		break;
16066008Syy154373	}
16076008Syy154373
16086008Syy154373	ddi_dma_free_handle(&ccb->pkt_dma_handle);
16096008Syy154373	ccb->pkt_dma_handle = NULL;
16106008Syy154373	ccb->ccb_flags &= ~CCB_FLAG_DMAVALID;
16116008Syy154373	return (DDI_FAILURE);
16126008Syy154373}
16136008Syy154373
16146008Syy154373
16156008Syy154373/*
16166008Syy154373 * Function name: arcmsr_dma_move
16176008Syy154373 * Return Values: 0 if successful, -1 if failure
16186008Syy154373 *   Description: move DMA resources to next DMA window
16196008Syy154373 *       Context: Can only be called from arcmsr_tran_init_pkt()
16206008Syy154373 */
16216008Syy154373static int
16226008Syy154373arcmsr_dma_move(struct ACB *acb, struct scsi_pkt *pkt,
16236008Syy154373    struct buf *bp) {
16246008Syy154373
16256008Syy154373	struct CCB *ccb = pkt->pkt_ha_private;
16266008Syy154373	uint8_t i = 0;
16276008Syy154373	int resid = 0;
16286008Syy154373	int total_ccb_xferlen = 0;
16296008Syy154373
16306008Syy154373	if (ccb->resid_dmacookie.dmac_size != 0) 	{
16316008Syy154373		total_ccb_xferlen += ccb->resid_dmacookie.dmac_size;
16326008Syy154373		ccb->pkt_dmacookies[i].dmac_size =
16336008Syy154373		    ccb->resid_dmacookie.dmac_size;
16346008Syy154373		ccb->pkt_dmacookies[i].dmac_laddress =
16356008Syy154373		    ccb->resid_dmacookie.dmac_laddress;
16366008Syy154373		i++;
16376008Syy154373		ccb->resid_dmacookie.dmac_size = 0;
16386008Syy154373	}
16396008Syy154373	/*
16406008Syy154373	 * If there are no more cookies remaining in this window,
16416008Syy154373	 * move to the next window.
16426008Syy154373	 */
16436008Syy154373	if (ccb->pkt_cookie == ccb->pkt_ncookies) {
16446008Syy154373		/*
16456008Syy154373		 * only dma map "partial" arrive here
16466008Syy154373		 */
16476008Syy154373		if ((ccb->pkt_curwin == ccb->pkt_nwin) &&
16486008Syy154373		    (ccb->pkt_nwin == 1)) {
16496008Syy154373			cmn_err(CE_CONT,
16506008Syy154373			    "arcmsr%d: dma partial set, but only "
16516008Syy154373			    "one window allocated",
16526008Syy154373			    ddi_get_instance(acb->dev_info));
16536008Syy154373			return (DDI_SUCCESS);
16546008Syy154373		}
16556008Syy154373
16566008Syy154373		/* At last window, cannot move */
16576008Syy154373		if (++ccb->pkt_curwin >= ccb->pkt_nwin) {
16586008Syy154373			cmn_err(CE_WARN,
16596008Syy154373			    "arcmsr%d: dma partial set, numwin exceeded",
16606008Syy154373			    ddi_get_instance(acb->dev_info));
16616008Syy154373			return (DDI_FAILURE);
16626008Syy154373		}
16636008Syy154373		if (ddi_dma_getwin(ccb->pkt_dma_handle, ccb->pkt_curwin,
16646008Syy154373		    &ccb->pkt_dma_offset, &ccb->pkt_dma_len,
16656008Syy154373		    &ccb->pkt_dmacookies[i], &ccb->pkt_ncookies) ==
16666008Syy154373		    DDI_FAILURE) {
16676008Syy154373			cmn_err(CE_WARN,
16686008Syy154373			    "arcmsr%d: dma partial set, "
16696008Syy154373			    "ddi_dma_getwin failure",
16706008Syy154373			    ddi_get_instance(acb->dev_info));
16716008Syy154373			return (DDI_FAILURE);
16726008Syy154373		}
16736008Syy154373		/* reset cookie pointer */
16746008Syy154373		ccb->pkt_cookie = 0;
16756008Syy154373	} else {
16766008Syy154373		/*
16776008Syy154373		 * only dma map "all" arrive here
16786008Syy154373		 * We still have more cookies in this window,
16796008Syy154373		 * get the next one
16806008Syy154373		 * access the pkt_dma_handle remain cookie record at
16816008Syy154373		 * ccb->pkt_dmacookies array
16826008Syy154373		 */
16836008Syy154373		ddi_dma_nextcookie(ccb->pkt_dma_handle,
16846008Syy154373		    &ccb->pkt_dmacookies[i]);
16856008Syy154373	}
16866008Syy154373
16876008Syy154373	/* Get remaining cookies in this window, up to our maximum */
16886008Syy154373	total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
16896008Syy154373
16906008Syy154373	/* retrieve and store cookies, start at ccb->pkt_dmacookies[0] */
16916008Syy154373	for (;;) {
16926008Syy154373		i++;
16936008Syy154373		/* handled cookies count level indicator */
16946008Syy154373		ccb->pkt_cookie++;
16956008Syy154373		if (i == ARCMSR_MAX_SG_ENTRIES ||
16966008Syy154373		    ccb->pkt_cookie == ccb->pkt_ncookies ||
16976008Syy154373		    total_ccb_xferlen == ARCMSR_MAX_XFER_LEN) {
16986008Syy154373			break;
16996008Syy154373		}
17006008Syy154373		ddi_dma_nextcookie(ccb->pkt_dma_handle,
17016008Syy154373		    &ccb->pkt_dmacookies[i]);
17026008Syy154373		total_ccb_xferlen += ccb->pkt_dmacookies[i].dmac_size;
17036008Syy154373	}
17046008Syy154373
17056008Syy154373	ccb->arcmsr_cdb.sgcount = i;
17066008Syy154373	if (total_ccb_xferlen > 512) {
17076008Syy154373		resid = total_ccb_xferlen % 512;
17086008Syy154373		if (resid != 0) {
17096008Syy154373			i--;
17106008Syy154373			total_ccb_xferlen -= resid;
17116008Syy154373			/* modify last sg length */
17126008Syy154373			ccb->pkt_dmacookies[i].dmac_size =
17136008Syy154373			    ccb->pkt_dmacookies[i].dmac_size - resid;
17146008Syy154373			ccb->resid_dmacookie.dmac_size = resid;
17156008Syy154373			ccb->resid_dmacookie.dmac_laddress =
17166008Syy154373			    ccb->pkt_dmacookies[i].dmac_laddress +
17176008Syy154373			    ccb->pkt_dmacookies[i].dmac_size;
17186008Syy154373		}
17196008Syy154373	}
17206008Syy154373	ccb->total_dmac_size += total_ccb_xferlen;
17216008Syy154373	pkt->pkt_resid = bp->b_bcount - ccb->total_dmac_size;
17226008Syy154373
17236008Syy154373	return (DDI_SUCCESS);
17246008Syy154373}
17256008Syy154373
17266008Syy154373/*
17276008Syy154373 * Function name: arcmsr_tran_destroy_pkt
17286008Syy154373 * Return Values: none
17296008Syy154373 *   Description: Called by kernel on behalf of a target driver
17306008Syy154373 *	          calling scsi_destroy_pkt(9F).
17316008Syy154373 *	          Refer to tran_destroy_pkt(9E) man page
17326008Syy154373 *       Context: Can be called from different kernel process threads.
17336008Syy154373 *	          Can be called by interrupt thread.
17346008Syy154373 */
17356008Syy154373static void
17366008Syy154373arcmsr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) {
17376008Syy154373
17386008Syy154373	struct CCB *ccb = pkt->pkt_ha_private;
17396008Syy154373
17406008Syy154373	if ((ccb != NULL) && (ccb->pkt == pkt)) {
17416008Syy154373		struct ACB *acb = ccb->acb;
17426008Syy154373		if (ccb->ccb_flags & CCB_FLAG_DMAVALID) {
17436008Syy154373			if (ddi_dma_unbind_handle(ccb->pkt_dma_handle)
17446008Syy154373			    != DDI_SUCCESS) {
17456008Syy154373				cmn_err(CE_WARN,
17466008Syy154373				    "arcmsr%d: ddi_dma_unbind_handle() failed",
17476008Syy154373				    ddi_get_instance(acb->dev_info));
17486008Syy154373			}
17496008Syy154373			ddi_dma_free_handle(&ccb->pkt_dma_handle);
17506008Syy154373			ccb->pkt_dma_handle = NULL;
17516008Syy154373		}
17526008Syy154373		arcmsr_free_ccb(ccb);
17536008Syy154373	}
17546008Syy154373
17556008Syy154373	scsi_hba_pkt_free(ap, pkt);
17566008Syy154373}
17576008Syy154373
17586008Syy154373/*
17596008Syy154373 * Function name: arcmsr_tran_dmafree()
17606008Syy154373 * Return Values: none
17616008Syy154373 *   Description: free dvma resources
17626008Syy154373 *       Context: Can be called from different kernel process threads.
17636008Syy154373 *	          Can be called by interrupt thread.
17646008Syy154373 */
17656008Syy154373static void
17666008Syy154373arcmsr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) {
17676008Syy154373
17686008Syy154373	struct CCB *ccb = pkt->pkt_ha_private;
17696008Syy154373
17706008Syy154373	if (ccb->ccb_flags & CCB_FLAG_DMAVALID) {
17716008Syy154373		ccb->ccb_flags &= ~CCB_FLAG_DMAVALID;
17726008Syy154373		if (ddi_dma_unbind_handle(ccb->pkt_dma_handle)
17736008Syy154373		    != DDI_SUCCESS) {
17746008Syy154373			cmn_err(CE_WARN,
17756008Syy154373			    "arcmsr%d: ddi_dma_unbind_handle() failed "
17766008Syy154373			    "(target %d lun %d)",
17776008Syy154373			    ddi_get_instance(ccb->acb->dev_info),
17786008Syy154373			    ap->a_target, ap->a_lun);
17796008Syy154373		}
17806008Syy154373		ddi_dma_free_handle(&ccb->pkt_dma_handle);
17816008Syy154373		ccb->pkt_dma_handle = NULL;
17826008Syy154373	}
17836008Syy154373}
17846008Syy154373
17856008Syy154373/*
17866008Syy154373 * Function name: arcmsr_tran_sync_pkt()
17876008Syy154373 * Return Values: none
17886008Syy154373 *   Description: sync dma
17896008Syy154373 *       Context: Can be called from different kernel process threads.
17906008Syy154373 *		  Can be called by interrupt thread.
17916008Syy154373 */
17926008Syy154373static void
17936008Syy154373arcmsr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) {
17946008Syy154373
17956008Syy154373	struct CCB *ccb;
17966008Syy154373
17976008Syy154373	ccb = pkt->pkt_ha_private;
17986008Syy154373
17996008Syy154373	if (ccb->ccb_flags & CCB_FLAG_DMAVALID) {
18006008Syy154373		if (ddi_dma_sync(ccb->pkt_dma_handle,
18016008Syy154373		    ccb->pkt_dma_offset, ccb->pkt_dma_len,
18026008Syy154373		    (ccb->ccb_flags & CCB_FLAG_DMAWRITE) ?
18036008Syy154373		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU)
18046008Syy154373			!= DDI_SUCCESS) {
18056008Syy154373			cmn_err(CE_WARN, "arcmsr%d: sync pkt failed "
18066008Syy154373			    "for target %d lun %d",
18076008Syy154373			    ddi_get_instance(ccb->acb->dev_info),
18086008Syy154373			    ap->a_target, ap->a_lun);
18096008Syy154373		}
18106008Syy154373	}
18116008Syy154373}
18126008Syy154373
18136008Syy154373
18146008Syy154373static uint8_t
18156008Syy154373arcmsr_hba_wait_msgint_ready(struct ACB *acb) {
18166008Syy154373
18176008Syy154373	uint32_t i;
18186008Syy154373	uint8_t retries = 0x00;
18196008Syy154373	struct HBA_msgUnit *phbamu;
18206008Syy154373
18216008Syy154373
18226008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
18236008Syy154373
18246008Syy154373	do {
18256008Syy154373		for (i = 0; i < 100; i++) {
18266008Syy154373			if (CHIP_REG_READ32(acb->reg_mu_acc_handle0,
18276008Syy154373			    &phbamu->outbound_intstatus) &
18286008Syy154373			    ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
18296008Syy154373				/* clear interrupt */
18306008Syy154373				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
18316008Syy154373				    &phbamu->outbound_intstatus,
18326008Syy154373				    ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
18336008Syy154373				return (TRUE);
18346008Syy154373			}
18356008Syy154373			drv_usecwait(10000);
18366008Syy154373			if (ddi_in_panic()) {
18376008Syy154373				/* clear interrupts */
18386008Syy154373				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
18396008Syy154373				    &phbamu->outbound_intstatus,
18406008Syy154373				    ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
18416008Syy154373				return (TRUE);
18426008Syy154373			}
18436008Syy154373		} /* max 1 second */
18446008Syy154373	} while (retries++ < 20); /* max 20 seconds */
18456008Syy154373	return (FALSE);
18466008Syy154373}
18476008Syy154373
18486008Syy154373
18496008Syy154373
18506008Syy154373static uint8_t
18516008Syy154373arcmsr_hbb_wait_msgint_ready(struct ACB *acb) {
18526008Syy154373
18536008Syy154373	struct HBB_msgUnit *phbbmu;
18546008Syy154373	uint32_t i;
18556008Syy154373	uint8_t retries = 0x00;
18566008Syy154373
18576008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
18586008Syy154373
18596008Syy154373	do {
18606008Syy154373		for (i = 0; i < 100; i++) {
18616008Syy154373			if (CHIP_REG_READ32(acb->reg_mu_acc_handle0,
18626008Syy154373			    &phbbmu->hbb_doorbell->iop2drv_doorbell) &
18636008Syy154373			    ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
18646008Syy154373				/* clear interrupt */
18656008Syy154373				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
18666008Syy154373				    &phbbmu->hbb_doorbell->iop2drv_doorbell,
18676008Syy154373				    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
18686008Syy154373				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
18696008Syy154373				    &phbbmu->hbb_doorbell->drv2iop_doorbell,
18706008Syy154373				    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
18716008Syy154373				return (TRUE);
18726008Syy154373			}
18736008Syy154373			drv_usecwait(10000);
18746008Syy154373			if (ddi_in_panic()) {
18756008Syy154373				/* clear interrupts */
18766008Syy154373				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
18776008Syy154373				    &phbbmu->hbb_doorbell->iop2drv_doorbell,
18786008Syy154373				    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
18796008Syy154373				CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
18806008Syy154373				    &phbbmu->hbb_doorbell->drv2iop_doorbell,
18816008Syy154373				    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
18826008Syy154373				return (TRUE);
18836008Syy154373			}
18846008Syy154373		} /* max 1 second */
18856008Syy154373	} while (retries++ < 20); /* max 20 seconds */
18866008Syy154373
18876008Syy154373	return (FALSE);
18886008Syy154373}
18896008Syy154373
18906008Syy154373
18916008Syy154373static void
18926008Syy154373arcmsr_flush_hba_cache(struct ACB *acb) {
18936008Syy154373
18946008Syy154373	struct HBA_msgUnit *phbamu;
18956008Syy154373	int retry_count = 30;
18966008Syy154373
18976008Syy154373	/* enlarge wait flush adapter cache time: 10 minutes */
18986008Syy154373
18996008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
19006008Syy154373
19016008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->inbound_msgaddr0,
19026008Syy154373	    ARCMSR_INBOUND_MESG0_FLUSH_CACHE);
19036008Syy154373
19046008Syy154373	do {
19056008Syy154373		if (arcmsr_hba_wait_msgint_ready(acb)) {
19066008Syy154373			break;
19076008Syy154373		} else {
19086008Syy154373			retry_count--;
19096008Syy154373		}
19106008Syy154373	} while (retry_count != 0);
19116008Syy154373}
19126008Syy154373
19136008Syy154373
19146008Syy154373
19156008Syy154373static void
19166008Syy154373arcmsr_flush_hbb_cache(struct ACB *acb) {
19176008Syy154373
19186008Syy154373	struct HBB_msgUnit *phbbmu;
19196008Syy154373	int retry_count = 30;
19206008Syy154373
19216008Syy154373	/* enlarge wait flush adapter cache time: 10 minutes */
19226008Syy154373
19236008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
19246008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
19256008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
19266008Syy154373	    ARCMSR_MESSAGE_FLUSH_CACHE);
19276008Syy154373
19286008Syy154373	do {
19296008Syy154373		if (arcmsr_hbb_wait_msgint_ready(acb)) {
19306008Syy154373			break;
19316008Syy154373		} else {
19326008Syy154373			retry_count--;
19336008Syy154373		}
19346008Syy154373	} while (retry_count != 0);
19356008Syy154373}
19366008Syy154373
19376008Syy154373
19386008Syy154373static void
19396008Syy154373arcmsr_ccb_complete(struct CCB *ccb, int flag) {
19406008Syy154373
19416008Syy154373	struct ACB *acb = ccb->acb;
19426008Syy154373	struct scsi_pkt *pkt = ccb->pkt;
19436008Syy154373
19446008Syy154373	if (flag == 1) {
19456008Syy154373		atomic_add_32((volatile uint32_t *)
19466008Syy154373		    &acb->ccboutstandingcount, -1);
19476008Syy154373	}
19486008Syy154373	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
19496008Syy154373	    STATE_SENT_CMD | STATE_GOT_STATUS);
19506008Syy154373
19516008Syy154373	if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) &&
19526008Syy154373	    (pkt->pkt_state & STATE_XFERRED_DATA)) {
19536008Syy154373		(void) ddi_dma_sync(ccb->pkt_dma_handle,
19546008Syy154373		    ccb->pkt_dma_offset, ccb->pkt_dma_len,
19556008Syy154373		    DDI_DMA_SYNC_FORCPU);
19566008Syy154373	}
19576008Syy154373
19586008Syy154373	scsi_hba_pkt_comp(pkt);
19596008Syy154373}
19606008Syy154373
19616008Syy154373
19626008Syy154373static void
19636008Syy154373arcmsr_report_sense_info(struct CCB *ccb) {
19646008Syy154373
19656008Syy154373	struct scsi_pkt *pkt = ccb->pkt;
19666008Syy154373	struct scsi_arq_status *arq_status;
19676008Syy154373
19686008Syy154373
19696008Syy154373	arq_status = (struct scsi_arq_status *)(intptr_t)(pkt->pkt_scbp);
19706008Syy154373	bzero((caddr_t)arq_status, sizeof (struct scsi_arq_status));
19716008Syy154373	arq_status->sts_rqpkt_reason = CMD_CMPLT;
19726008Syy154373	arq_status->sts_rqpkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET |
19736008Syy154373	    STATE_SENT_CMD | STATE_XFERRED_DATA | STATE_GOT_STATUS);
19746008Syy154373	arq_status->sts_rqpkt_statistics = pkt->pkt_statistics;
19756008Syy154373	arq_status->sts_rqpkt_resid = 0;
19766008Syy154373
19776008Syy154373	pkt->pkt_reason = CMD_CMPLT;
19786008Syy154373	/* auto rqsense took place */
19796008Syy154373	pkt->pkt_state = (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
19806008Syy154373	    STATE_GOT_STATUS | STATE_ARQ_DONE);
19816008Syy154373
19826008Syy154373	if (&arq_status->sts_sensedata != NULL) {
19836008Syy154373		struct SENSE_DATA *cdb_sensedata;
19846008Syy154373		struct scsi_extended_sense *sts_sensedata;
19856008Syy154373
19866008Syy154373		cdb_sensedata =
19876008Syy154373		    (struct SENSE_DATA *)ccb->arcmsr_cdb.SenseData;
19886008Syy154373		sts_sensedata = &arq_status->sts_sensedata;
19896008Syy154373
19906008Syy154373		sts_sensedata->es_code = cdb_sensedata->ErrorCode;
19916008Syy154373		/* must eq CLASS_EXTENDED_SENSE (0x07) */
19926008Syy154373		sts_sensedata->es_class = cdb_sensedata->ErrorClass;
19936008Syy154373		sts_sensedata->es_valid = cdb_sensedata->Valid;
19946008Syy154373		sts_sensedata->es_segnum = cdb_sensedata->SegmentNumber;
19956008Syy154373		sts_sensedata->es_key = cdb_sensedata->SenseKey;
19966008Syy154373		sts_sensedata->es_ili = cdb_sensedata->IncorrectLength;
19976008Syy154373		sts_sensedata->es_eom = cdb_sensedata->EndOfMedia;
19986008Syy154373		sts_sensedata->es_filmk = cdb_sensedata->FileMark;
19996008Syy154373		sts_sensedata->es_info_1 = cdb_sensedata->Information[0];
20006008Syy154373		sts_sensedata->es_info_2 = cdb_sensedata->Information[1];
20016008Syy154373		sts_sensedata->es_info_3 = cdb_sensedata->Information[2];
20026008Syy154373		sts_sensedata->es_info_4 = cdb_sensedata->Information[3];
20036008Syy154373		sts_sensedata->es_add_len =
20046008Syy154373		    cdb_sensedata->AdditionalSenseLength;
20056008Syy154373		sts_sensedata->es_cmd_info[0] =
20066008Syy154373		    cdb_sensedata->CommandSpecificInformation[0];
20076008Syy154373		sts_sensedata->es_cmd_info[1] =
20086008Syy154373		    cdb_sensedata->CommandSpecificInformation[1];
20096008Syy154373		sts_sensedata->es_cmd_info[2] =
20106008Syy154373		    cdb_sensedata->CommandSpecificInformation[2];
20116008Syy154373		sts_sensedata->es_cmd_info[3] =
20126008Syy154373		    cdb_sensedata->CommandSpecificInformation[3];
20136008Syy154373		sts_sensedata->es_add_code =
20146008Syy154373		    cdb_sensedata->AdditionalSenseCode;
20156008Syy154373		sts_sensedata->es_qual_code =
20166008Syy154373		    cdb_sensedata->AdditionalSenseCodeQualifier;
20176008Syy154373		sts_sensedata->es_fru_code =
20186008Syy154373		    cdb_sensedata->FieldReplaceableUnitCode;
20196008Syy154373	}
20206008Syy154373}
20216008Syy154373
20226008Syy154373
20236008Syy154373
20246008Syy154373static void
20256008Syy154373arcmsr_abort_hba_allcmd(struct ACB *acb) {
20266008Syy154373
20276008Syy154373	struct HBA_msgUnit *phbamu;
20286008Syy154373
20296008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
20306008Syy154373
20316008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
20326008Syy154373	    &phbamu->inbound_msgaddr0,
20336008Syy154373	    ARCMSR_INBOUND_MESG0_ABORT_CMD);
20346008Syy154373
20356008Syy154373	if (!arcmsr_hba_wait_msgint_ready(acb)) {
20366008Syy154373		cmn_err(CE_WARN,
20376008Syy154373		    "arcmsr%d: timeout while waiting for 'abort all "
20386008Syy154373		    "outstanding commands'",
20396008Syy154373		    ddi_get_instance(acb->dev_info));
20406008Syy154373	}
20416008Syy154373}
20426008Syy154373
20436008Syy154373
20446008Syy154373
20456008Syy154373static void
20466008Syy154373arcmsr_abort_hbb_allcmd(struct ACB *acb) {
20476008Syy154373
20486008Syy154373	struct HBB_msgUnit *phbbmu =
20496008Syy154373	    (struct HBB_msgUnit *)acb->pmu;
20506008Syy154373
20516008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
20526008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
20536008Syy154373	    ARCMSR_MESSAGE_ABORT_CMD);
20546008Syy154373
20556008Syy154373	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
20566008Syy154373		cmn_err(CE_WARN,
20576008Syy154373		    "arcmsr%d: timeout while waiting for 'abort all "
20586008Syy154373		    "outstanding commands'",
20596008Syy154373		    ddi_get_instance(acb->dev_info));
20606008Syy154373	}
20616008Syy154373}
20626008Syy154373
20636008Syy154373static void
20646008Syy154373arcmsr_report_ccb_state(struct ACB *acb,
20656008Syy154373    struct CCB *ccb, uint32_t flag_ccb) {
20666008Syy154373
20676008Syy154373	int id, lun;
20686008Syy154373
20696008Syy154373	id = ccb->pkt->pkt_address.a_target;
20706008Syy154373	lun = ccb->pkt->pkt_address.a_lun;
20716008Syy154373
20726008Syy154373	if ((flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR) == 0) {
20736008Syy154373		if (acb->devstate[id][lun] == ARECA_RAID_GONE) {
20746008Syy154373			acb->devstate[id][lun] = ARECA_RAID_GOOD;
20756008Syy154373		}
20766008Syy154373		ccb->pkt->pkt_reason = CMD_CMPLT;
20776008Syy154373		ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
20786008Syy154373		arcmsr_ccb_complete(ccb, 1);
20796008Syy154373	} else {
20806008Syy154373		switch (ccb->arcmsr_cdb.DeviceStatus) {
20816008Syy154373		case ARCMSR_DEV_SELECT_TIMEOUT:
20826008Syy154373			if (acb->devstate[id][lun] == ARECA_RAID_GOOD) {
20836008Syy154373				cmn_err(CE_CONT,
20846008Syy154373				    "arcmsr%d: raid volume was kicked out ",
20856008Syy154373				    ddi_get_instance(acb->dev_info));
20866008Syy154373			}
20876008Syy154373			acb->devstate[id][lun] = ARECA_RAID_GONE;
20886008Syy154373			ccb->pkt->pkt_reason = CMD_TIMEOUT;
20896008Syy154373			ccb->pkt->pkt_statistics |= STAT_TIMEOUT;
20906008Syy154373			arcmsr_ccb_complete(ccb, 1);
20916008Syy154373			break;
20926008Syy154373		case ARCMSR_DEV_ABORTED:
20936008Syy154373		case ARCMSR_DEV_INIT_FAIL:
20946008Syy154373			cmn_err(CE_CONT,
20956008Syy154373			    "arcmsr%d: isr got "
20966008Syy154373			    "'ARCMSR_DEV_ABORTED' 'ARCMSR_DEV_INIT_FAIL'",
20976008Syy154373			    ddi_get_instance(acb->dev_info));
20986008Syy154373			cmn_err(CE_CONT, "arcmsr%d: raid volume was kicked "
20996008Syy154373			    "out", ddi_get_instance(acb->dev_info));
21006008Syy154373			acb->devstate[id][lun] = ARECA_RAID_GONE;
21016008Syy154373			ccb->pkt->pkt_reason = CMD_DEV_GONE;
21026008Syy154373			ccb->pkt->pkt_statistics |= STAT_TERMINATED;
21036008Syy154373			arcmsr_ccb_complete(ccb, 1);
21046008Syy154373			break;
21056008Syy154373		case SCSISTAT_CHECK_CONDITION:
21066008Syy154373			acb->devstate[id][lun] = ARECA_RAID_GOOD;
21076008Syy154373			arcmsr_report_sense_info(ccb);
21086008Syy154373			arcmsr_ccb_complete(ccb, 1);
21096008Syy154373			break;
21106008Syy154373		default:
21116008Syy154373			cmn_err(CE_WARN, "arcmsr%d: target %d lun %d "
21126008Syy154373			    "isr received CMD_DONE with unknown "
21136008Syy154373			    "DeviceStatus (0x%x)",
21146008Syy154373			    ddi_get_instance(acb->dev_info), id, lun,
21156008Syy154373			    ccb->arcmsr_cdb.DeviceStatus);
21166008Syy154373			cmn_err(CE_CONT, "arcmsr%d: raid volume was kicked "
21176008Syy154373			    "out ", ddi_get_instance(acb->dev_info));
21186008Syy154373			acb->devstate[id][lun] = ARECA_RAID_GONE;
21196008Syy154373			/* unknown error or crc error just for retry */
21206008Syy154373			ccb->pkt->pkt_reason = CMD_TRAN_ERR;
21216008Syy154373			ccb->pkt->pkt_statistics |= STAT_TERMINATED;
21226008Syy154373			arcmsr_ccb_complete(ccb, 1);
21236008Syy154373			break;
21246008Syy154373		}
21256008Syy154373	}
21266008Syy154373}
21276008Syy154373
21286008Syy154373
21296008Syy154373static void
21306008Syy154373arcmsr_drain_donequeue(struct ACB *acb, uint32_t flag_ccb) {
21316008Syy154373
21326008Syy154373	struct CCB *ccb;
21336008Syy154373
21346008Syy154373	/* check if command completed without error */
21356008Syy154373	ccb = (struct CCB *)(acb->vir2phy_offset +
21366008Syy154373	    (flag_ccb << 5)); /* frame must be aligned on 32 byte boundary */
21376008Syy154373
21386008Syy154373	if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) 	{
21396008Syy154373		if (ccb->startdone == ARCMSR_CCB_ABORTED) {
21406008Syy154373			cmn_err(CE_CONT,
21416008Syy154373			    "arcmsr%d: isr got aborted command "
21426008Syy154373			    "while draining doneq",
21436008Syy154373			    ddi_get_instance(acb->dev_info));
21446008Syy154373			ccb->pkt->pkt_reason = CMD_ABORTED;
21456008Syy154373			ccb->pkt->pkt_statistics |= STAT_ABORTED;
21466008Syy154373			arcmsr_ccb_complete(ccb, 1);
21476008Syy154373			return;
21486008Syy154373		}
21496008Syy154373
21506008Syy154373		if (ccb->startdone == ARCMSR_CCB_RESET) {
21516008Syy154373			cmn_err(CE_CONT,
21526008Syy154373			    "arcmsr%d: isr got command reset "
21536008Syy154373			    "while draining doneq",
21546008Syy154373			    ddi_get_instance(acb->dev_info));
21556008Syy154373			ccb->pkt->pkt_reason = CMD_RESET;
21566008Syy154373			ccb->pkt->pkt_statistics |= STAT_BUS_RESET;
21576008Syy154373			arcmsr_ccb_complete(ccb, 1);
21586008Syy154373			return;
21596008Syy154373		}
21606008Syy154373
21616008Syy154373		cmn_err(CE_WARN, "arcmsr%d: isr got an illegal ccb command "
21626008Syy154373		    "done while draining doneq",
21636008Syy154373		    ddi_get_instance(acb->dev_info));
21646008Syy154373		return;
21656008Syy154373	}
21666008Syy154373	arcmsr_report_ccb_state(acb, ccb, flag_ccb);
21676008Syy154373}
21686008Syy154373
21696008Syy154373
21706008Syy154373static void
21716008Syy154373arcmsr_done4abort_postqueue(struct ACB *acb) {
21726008Syy154373
21736008Syy154373	int i = 0;
21746008Syy154373	uint32_t flag_ccb;
21756008Syy154373
21766008Syy154373	switch (acb->adapter_type) {
21776008Syy154373	case ACB_ADAPTER_TYPE_A:
21786008Syy154373	{
21796008Syy154373		struct HBA_msgUnit *phbamu;
21806008Syy154373		uint32_t outbound_intstatus;
21816008Syy154373
21826008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
21836008Syy154373		/* clear and abort all outbound posted Q */
21846008Syy154373		outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
21856008Syy154373		    &phbamu->outbound_intstatus) & acb->outbound_int_enable;
21866008Syy154373		/* clear interrupt */
21876008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
21886008Syy154373		    &phbamu->outbound_intstatus, outbound_intstatus);
21896008Syy154373		while (((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
21906008Syy154373		    &phbamu->outbound_queueport)) != 0xFFFFFFFF) &&
21916008Syy154373		    (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
21926008Syy154373			arcmsr_drain_donequeue(acb, flag_ccb);
21936008Syy154373		}
21946008Syy154373	}
21956008Syy154373		break;
21966008Syy154373
21976008Syy154373	case ACB_ADAPTER_TYPE_B:
21986008Syy154373	{
21996008Syy154373		struct HBB_msgUnit *phbbmu;
22006008Syy154373
22016008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
22026008Syy154373
22036008Syy154373		/* clear all outbound posted Q */
22046008Syy154373		/* clear doorbell interrupt */
22056008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
22066008Syy154373		    &phbbmu->hbb_doorbell->iop2drv_doorbell,
22076008Syy154373		    ARCMSR_DOORBELL_INT_CLEAR_PATTERN);
22086008Syy154373		for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
22096008Syy154373			if ((flag_ccb = phbbmu->done_qbuffer[i]) != 0) {
22106008Syy154373				phbbmu->done_qbuffer[i] = 0;
22116008Syy154373				arcmsr_drain_donequeue(acb, flag_ccb);
22126008Syy154373			}
22136008Syy154373			phbbmu->post_qbuffer[i] = 0;
22146008Syy154373		}	/* drain reply FIFO */
22156008Syy154373		phbbmu->doneq_index = 0;
22166008Syy154373		phbbmu->postq_index = 0;
22176008Syy154373		break;
22186008Syy154373	}
22196008Syy154373	}
22206008Syy154373}
22216008Syy154373
22226008Syy154373/*
22236008Syy154373 * Routine Description: Reset 80331 iop.
22246008Syy154373 *           Arguments:
22256008Syy154373 *        Return Value: Nothing.
22266008Syy154373 */
22276008Syy154373static void
22286008Syy154373arcmsr_iop_reset(struct ACB *acb) {
22296008Syy154373
22306008Syy154373	struct CCB *ccb;
22316008Syy154373	uint32_t intmask_org;
22326008Syy154373	int i = 0;
22336008Syy154373
22346008Syy154373	if (acb->ccboutstandingcount > 0) {
22356008Syy154373		/* disable all outbound interrupt */
22366008Syy154373		intmask_org = arcmsr_disable_allintr(acb);
22376008Syy154373		/* talk to iop 331 outstanding command aborted */
22386008Syy154373		if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
22396008Syy154373			arcmsr_abort_hba_allcmd(acb);
22406008Syy154373		} else {
22416008Syy154373			arcmsr_abort_hbb_allcmd(acb);
22426008Syy154373		}
22436008Syy154373		/* clear and abort all outbound posted Q */
22446008Syy154373		arcmsr_done4abort_postqueue(acb);
22456008Syy154373
22466008Syy154373		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
22476008Syy154373			ccb = acb->pccb_pool[i];
22486008Syy154373			if (ccb->startdone == ARCMSR_CCB_START) {
22496008Syy154373				ccb->startdone = ARCMSR_CCB_RESET;
22506008Syy154373				ccb->pkt->pkt_reason = CMD_RESET;
22516008Syy154373				ccb->pkt->pkt_statistics |= STAT_BUS_RESET;
22526008Syy154373				arcmsr_ccb_complete(ccb, 1);
22536008Syy154373			}
22546008Syy154373		}
22556008Syy154373		/* enable all outbound interrupt */
22566008Syy154373		arcmsr_enable_allintr(acb, intmask_org);
22576008Syy154373	}
22586008Syy154373}
22596008Syy154373
22606008Syy154373/*
22616008Syy154373 * You can access the DMA address through the #defines:
22626008Syy154373 * dmac_address for 32-bit addresses and dmac_laddress for 64-bit addresses.
22636008Syy154373 *	These macros are defined as follows:
22646008Syy154373 *
22656008Syy154373 *	#define dmac_laddress   _dmu._dmac_ll
22666008Syy154373 *	#ifdef _LONG_LONG_HTOL
22676008Syy154373 *		#define dmac_notused    _dmu._dmac_la[0]
22686008Syy154373 *		#define dmac_address    _dmu._dmac_la[1]
22696008Syy154373 *	#else
22706008Syy154373 *		#define dmac_address    _dmu._dmac_la[0]
22716008Syy154373 *		#define dmac_notused    _dmu._dmac_la[1]
22726008Syy154373 *	#endif
22736008Syy154373 */
22746008Syy154373/*ARGSUSED*/
22756008Syy154373static void
22766008Syy154373arcmsr_build_ccb(struct CCB *ccb) {
22776008Syy154373
22786008Syy154373	struct scsi_pkt *pkt = ccb->pkt;
22796008Syy154373	struct ARCMSR_CDB *arcmsr_cdb;
22806008Syy154373	char *psge;
22816008Syy154373	uint32_t address_lo, address_hi;
22826008Syy154373	int arccdbsize = 0x30;
22836008Syy154373	uint8_t sgcount;
22846008Syy154373
22856008Syy154373	arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
22866008Syy154373	psge = (char *)&arcmsr_cdb->sgu;
22876008Syy154373
22886008Syy154373	/* return the current time in seconds */
22896008Syy154373	ccb->ccb_time = (time_t)(pkt->pkt_time + ddi_get_time());
22906008Syy154373	bcopy((caddr_t)pkt->pkt_cdbp, arcmsr_cdb->Cdb,
22916008Syy154373	    arcmsr_cdb->CdbLength);
22926008Syy154373	sgcount = ccb->arcmsr_cdb.sgcount;
22936008Syy154373
22946008Syy154373	if (sgcount) {
22956008Syy154373		int length, i;
22966008Syy154373		int cdb_sgcount = 0;
22976008Syy154373		int total_xfer_length = 0;
22986008Syy154373
22996008Syy154373		/* map stor port SG list to our iop SG List. */
23006008Syy154373		for (i = 0; i < sgcount; i++) {
23016008Syy154373			/* Get physaddr of the current data pointer */
23026008Syy154373			length = ccb->pkt_dmacookies[i].dmac_size;
23036008Syy154373			total_xfer_length += length;
23046008Syy154373			address_lo = dma_addr_lo32(
23056008Syy154373				ccb->pkt_dmacookies[i].dmac_laddress);
23066008Syy154373			address_hi = dma_addr_hi32(
23076008Syy154373				ccb->pkt_dmacookies[i].dmac_laddress);
23086008Syy154373
23096008Syy154373			if (address_hi == 0) {
23106008Syy154373				struct SG32ENTRY *dma_sg;
23116008Syy154373
23126008Syy154373				dma_sg = (struct SG32ENTRY *)(intptr_t)psge;
23136008Syy154373
23146008Syy154373				dma_sg->address = address_lo;
23156008Syy154373				dma_sg->length = length;
23166008Syy154373				psge += sizeof (struct SG32ENTRY);
23176008Syy154373				arccdbsize += sizeof (struct SG32ENTRY);
23186008Syy154373			} else {
23196008Syy154373				int sg64s_size = 0;
23206008Syy154373				int tmplength = length;
23216008Syy154373				int64_t span4G, length0;
23226008Syy154373				struct SG64ENTRY *dma_sg;
23236008Syy154373
23246008Syy154373				/*LINTED*/
23256008Syy154373				while (1) {
23266008Syy154373					dma_sg =
23276008Syy154373					    (struct SG64ENTRY *)(intptr_t)psge;
23286008Syy154373					span4G =
23296008Syy154373					    (int64_t)address_lo + tmplength;
23306008Syy154373
23316008Syy154373					dma_sg->addresshigh = address_hi;
23326008Syy154373					dma_sg->address = address_lo;
23336008Syy154373					if (span4G > 0x100000000ULL) {
23346008Syy154373						/* see if we cross 4G */
23356008Syy154373						length0 = 0x100000000ULL -
23366008Syy154373						    address_lo;
23376008Syy154373						dma_sg->length =
23386008Syy154373						    (uint32_t)length0 |
23396008Syy154373						    IS_SG64_ADDR;
23406008Syy154373						address_hi = address_hi + 1;
23416008Syy154373						address_lo = 0;
23426008Syy154373						tmplength = tmplength-
23436008Syy154373						    (int32_t)length0;
23446008Syy154373						sg64s_size +=
23456008Syy154373						    sizeof (struct SG64ENTRY);
23466008Syy154373						psge +=
23476008Syy154373						    sizeof (struct SG64ENTRY);
23486008Syy154373						cdb_sgcount++;
23496008Syy154373					} else {
23506008Syy154373						dma_sg->length = tmplength |
23516008Syy154373						    IS_SG64_ADDR;
23526008Syy154373						sg64s_size +=
23536008Syy154373						    sizeof (struct SG64ENTRY);
23546008Syy154373						psge +=
23556008Syy154373						    sizeof (struct SG64ENTRY);
23566008Syy154373						break;
23576008Syy154373					}
23586008Syy154373				}
23596008Syy154373				arccdbsize += sg64s_size;
23606008Syy154373			}
23616008Syy154373			cdb_sgcount++;
23626008Syy154373		}
23636008Syy154373		arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
23646008Syy154373		arcmsr_cdb->DataLength = total_xfer_length;
23656008Syy154373		if (arccdbsize > 256) {
23666008Syy154373			arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
23676008Syy154373		}
23686008Syy154373	} else {
23696008Syy154373		arcmsr_cdb->DataLength = 0;
23706008Syy154373	}
23716008Syy154373
23726008Syy154373	if (ccb->ccb_flags & CCB_FLAG_DMAWRITE)
23736008Syy154373		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
23746008Syy154373}
23756008Syy154373
23766008Syy154373/*
23776008Syy154373 * arcmsr_post_ccb - Send a protocol specific ARC send postcard to a AIOC.
23786008Syy154373 *
23796008Syy154373 * handle:		Handle of registered ARC protocol driver
23806008Syy154373 * adapter_id:		AIOC unique identifier(integer)
23816008Syy154373 * pPOSTCARD_SEND:	Pointer to ARC send postcard
23826008Syy154373 *
23836008Syy154373 * This routine posts a ARC send postcard to the request post FIFO of a
23846008Syy154373 * specific ARC adapter.
23856008Syy154373 */
23866008Syy154373static int
23876008Syy154373arcmsr_post_ccb(struct ACB *acb, struct CCB *ccb) {
23886008Syy154373
23896008Syy154373	uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
23906008Syy154373	struct scsi_pkt *pkt = ccb->pkt;
23916008Syy154373	struct ARCMSR_CDB *arcmsr_cdb;
23926008Syy154373
23936008Syy154373	arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
23946008Syy154373
23956008Syy154373	/* Use correct offset and size for syncing */
23966008Syy154373	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size,
23976008Syy154373	    DDI_DMA_SYNC_FORDEV) == DDI_FAILURE)
23986008Syy154373		return (DDI_FAILURE);
23996008Syy154373
24006008Syy154373	atomic_add_32((volatile uint32_t *)&acb->ccboutstandingcount, 1);
24016008Syy154373	ccb->startdone = ARCMSR_CCB_START;
24026008Syy154373
24036008Syy154373	switch (acb->adapter_type) {
24046008Syy154373	case ACB_ADAPTER_TYPE_A:
24056008Syy154373	{
24066008Syy154373		struct HBA_msgUnit *phbamu;
24076008Syy154373
24086008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
24096008Syy154373
24106008Syy154373		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
24116008Syy154373			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
24126008Syy154373			    &phbamu->inbound_queueport,
24136008Syy154373			    cdb_shifted_phyaddr |
24146008Syy154373			    ARCMSR_CCBPOST_FLAG_SGL_BSIZE);
24156008Syy154373		} else {
24166008Syy154373			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
24176008Syy154373			    &phbamu->inbound_queueport, cdb_shifted_phyaddr);
24186008Syy154373		}
24196008Syy154373		if (pkt->pkt_flags & FLAG_NOINTR)
24206008Syy154373			arcmsr_polling_hba_ccbdone(acb, ccb);
24216008Syy154373	}
24226008Syy154373		break;
24236008Syy154373	case ACB_ADAPTER_TYPE_B:
24246008Syy154373	{
24256008Syy154373		struct HBB_msgUnit *phbbmu;
24266008Syy154373		int ending_index, index;
24276008Syy154373
24286008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
24296008Syy154373		mutex_enter(&acb->postq_mutex);
24306008Syy154373		index = phbbmu->postq_index;
24316008Syy154373		ending_index = ((index+1)%ARCMSR_MAX_HBB_POSTQUEUE);
24326008Syy154373		phbbmu->post_qbuffer[ending_index] = 0;
24336008Syy154373		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
24346008Syy154373			phbbmu->post_qbuffer[index] =
24356008Syy154373			    (cdb_shifted_phyaddr|ARCMSR_CCBPOST_FLAG_SGL_BSIZE);
24366008Syy154373		} else {
24376008Syy154373			phbbmu->post_qbuffer[index] = cdb_shifted_phyaddr;
24386008Syy154373		}
24396008Syy154373		index++;
24406008Syy154373		/* if last index number set it to 0 */
24416008Syy154373		index %= ARCMSR_MAX_HBB_POSTQUEUE;
24426008Syy154373		phbbmu->postq_index = index;
24436008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
24446008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
24456008Syy154373		    ARCMSR_DRV2IOP_CDB_POSTED);
24466008Syy154373		mutex_exit(&acb->postq_mutex);
24476008Syy154373		if (pkt->pkt_flags & FLAG_NOINTR)
24486008Syy154373			arcmsr_polling_hbb_ccbdone(acb, ccb);
24496008Syy154373	}
24506008Syy154373	break;
24516008Syy154373	}
24526008Syy154373
24536008Syy154373	return (DDI_SUCCESS);
24546008Syy154373}
24556008Syy154373
24566008Syy154373
24576008Syy154373
24586008Syy154373
24596008Syy154373static struct QBUFFER *
24606008Syy154373arcmsr_get_iop_rqbuffer(struct ACB *acb) {
24616008Syy154373
24626008Syy154373	struct QBUFFER *qb;
24636008Syy154373
24646008Syy154373	switch (acb->adapter_type) {
24656008Syy154373	case ACB_ADAPTER_TYPE_A:
24666008Syy154373	{
24676008Syy154373		struct HBA_msgUnit *phbamu;
24686008Syy154373
24696008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
24706008Syy154373		qb = (struct QBUFFER *)&phbamu->message_rbuffer;
24716008Syy154373	}
24726008Syy154373		break;
24736008Syy154373	case ACB_ADAPTER_TYPE_B:
24746008Syy154373	{
24756008Syy154373		struct HBB_msgUnit *phbbmu;
24766008Syy154373
24776008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
24786008Syy154373		qb = (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_rbuffer;
24796008Syy154373	}
24806008Syy154373		break;
24816008Syy154373	}
24826008Syy154373
24836008Syy154373	return (qb);
24846008Syy154373}
24856008Syy154373
24866008Syy154373
24876008Syy154373
24886008Syy154373static struct QBUFFER *
24896008Syy154373arcmsr_get_iop_wqbuffer(struct ACB *acb) {
24906008Syy154373
24916008Syy154373	struct QBUFFER *qbuffer = NULL;
24926008Syy154373
24936008Syy154373	switch (acb->adapter_type) {
24946008Syy154373	case ACB_ADAPTER_TYPE_A:
24956008Syy154373	{
24966008Syy154373		struct HBA_msgUnit *phbamu;
24976008Syy154373
24986008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
24996008Syy154373		qbuffer = (struct QBUFFER *)&phbamu->message_wbuffer;
25006008Syy154373	}
25016008Syy154373	break;
25026008Syy154373	case ACB_ADAPTER_TYPE_B:
25036008Syy154373	{
25046008Syy154373		struct HBB_msgUnit *phbbmu;
25056008Syy154373
25066008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
25076008Syy154373		qbuffer =
25086008Syy154373		    (struct QBUFFER *)&phbbmu->hbb_rwbuffer->message_wbuffer;
25096008Syy154373	}
25106008Syy154373	break;
25116008Syy154373	}
25126008Syy154373	return (qbuffer);
25136008Syy154373}
25146008Syy154373
25156008Syy154373
25166008Syy154373
25176008Syy154373static void
25186008Syy154373arcmsr_iop_message_read(struct ACB *acb) {
25196008Syy154373
25206008Syy154373	switch (acb->adapter_type) {
25216008Syy154373	case ACB_ADAPTER_TYPE_A:
25226008Syy154373	{
25236008Syy154373		struct HBA_msgUnit *phbamu;
25246008Syy154373
25256008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
25266008Syy154373		/* let IOP know the data has been read */
25276008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
25286008Syy154373		    &phbamu->inbound_doorbell,
25296008Syy154373		    ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
25306008Syy154373	}
25316008Syy154373	break;
25326008Syy154373	case ACB_ADAPTER_TYPE_B:
25336008Syy154373	{
25346008Syy154373		struct HBB_msgUnit *phbbmu;
25356008Syy154373
25366008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
25376008Syy154373		/* let IOP know the data has been read */
25386008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
25396008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
25406008Syy154373		    ARCMSR_DRV2IOP_DATA_READ_OK);
25416008Syy154373	}
25426008Syy154373	break;
25436008Syy154373	}
25446008Syy154373}
25456008Syy154373
25466008Syy154373
25476008Syy154373
25486008Syy154373static void
25496008Syy154373arcmsr_iop_message_wrote(struct ACB *acb) {
25506008Syy154373
25516008Syy154373	switch (acb->adapter_type) {
25526008Syy154373	case ACB_ADAPTER_TYPE_A:
25536008Syy154373	{
25546008Syy154373		struct HBA_msgUnit *phbamu;
25556008Syy154373
25566008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
25576008Syy154373		/*
25586008Syy154373		 * push inbound doorbell tell iop, driver data write ok
25596008Syy154373		 * and wait reply on next hwinterrupt for next Qbuffer post
25606008Syy154373		 */
25616008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
25626008Syy154373		    &phbamu->inbound_doorbell,
25636008Syy154373		    ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK);
25646008Syy154373	}
25656008Syy154373	break;
25666008Syy154373	case ACB_ADAPTER_TYPE_B:
25676008Syy154373	{
25686008Syy154373		struct HBB_msgUnit *phbbmu;
25696008Syy154373
25706008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
25716008Syy154373		/*
25726008Syy154373		 * push inbound doorbell tell iop, driver data was writen
25736008Syy154373		 * successfully, then await reply on next hwinterrupt for
25746008Syy154373		 * next Qbuffer post
25756008Syy154373		 */
25766008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
25776008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
25786008Syy154373		    ARCMSR_DRV2IOP_DATA_WRITE_OK);
25796008Syy154373	}
25806008Syy154373	break;
25816008Syy154373	}
25826008Syy154373}
25836008Syy154373
25846008Syy154373
25856008Syy154373
25866008Syy154373static void
25876008Syy154373arcmsr_post_ioctldata2iop(struct ACB *acb) {
25886008Syy154373
25896008Syy154373	uint8_t *pQbuffer;
25906008Syy154373	struct QBUFFER *pwbuffer;
25916008Syy154373	uint8_t *iop_data;
25926008Syy154373	int32_t allxfer_len = 0;
25936008Syy154373
25946008Syy154373	pwbuffer = arcmsr_get_iop_wqbuffer(acb);
25956008Syy154373	iop_data = (uint8_t *)pwbuffer->data;
25966008Syy154373	if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READ) {
25976008Syy154373		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ);
25986008Syy154373		while ((acb->wqbuf_firstidx != acb->wqbuf_lastidx) &&
25996008Syy154373		    (allxfer_len < 124)) {
26006008Syy154373			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstidx];
26016008Syy154373			(void) memcpy(iop_data, pQbuffer, 1);
26026008Syy154373			acb->wqbuf_firstidx++;
26036008Syy154373			/* if last index number set it to 0 */
26046008Syy154373			acb->wqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
26056008Syy154373			iop_data++;
26066008Syy154373			allxfer_len++;
26076008Syy154373		}
26086008Syy154373		pwbuffer->data_len = allxfer_len;
26096008Syy154373		/*
26106008Syy154373		 * push inbound doorbell and wait reply at hwinterrupt
26116008Syy154373		 * routine for next Qbuffer post
26126008Syy154373		 */
26136008Syy154373		arcmsr_iop_message_wrote(acb);
26146008Syy154373	}
26156008Syy154373}
26166008Syy154373
26176008Syy154373
26186008Syy154373
26196008Syy154373static void
26206008Syy154373arcmsr_stop_hba_bgrb(struct ACB *acb) {
26216008Syy154373
26226008Syy154373	struct HBA_msgUnit *phbamu;
26236008Syy154373
26246008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
26256008Syy154373
26266008Syy154373	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
26276008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
26286008Syy154373	    &phbamu->inbound_msgaddr0,
26296008Syy154373	    ARCMSR_INBOUND_MESG0_STOP_BGRB);
26306008Syy154373	if (!arcmsr_hba_wait_msgint_ready(acb))
26316008Syy154373		cmn_err(CE_WARN,
26326008Syy154373		    "arcmsr%d: timeout while waiting for background "
26336008Syy154373		    "rebuild completion",
26346008Syy154373		    ddi_get_instance(acb->dev_info));
26356008Syy154373}
26366008Syy154373
26376008Syy154373
26386008Syy154373static void
26396008Syy154373arcmsr_stop_hbb_bgrb(struct ACB *acb) {
26406008Syy154373
26416008Syy154373	struct HBB_msgUnit *phbbmu;
26426008Syy154373
26436008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
26446008Syy154373
26456008Syy154373	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
26466008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
26476008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
26486008Syy154373	    ARCMSR_MESSAGE_STOP_BGRB);
26496008Syy154373
26506008Syy154373	if (!arcmsr_hbb_wait_msgint_ready(acb))
26516008Syy154373		cmn_err(CE_WARN,
26526008Syy154373		    "arcmsr%d: timeout while waiting for background "
26536008Syy154373		    "rebuild completion",
26546008Syy154373		    ddi_get_instance(acb->dev_info));
26556008Syy154373}
26566008Syy154373
26576008Syy154373static int
26586008Syy154373arcmsr_iop_message_xfer(struct ACB *acb, struct scsi_pkt *pkt) {
26596008Syy154373
26606008Syy154373	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
26616008Syy154373	struct CCB *ccb = pkt->pkt_ha_private;
26626008Syy154373	struct buf *bp = ccb->bp;
26636008Syy154373	uint8_t *pQbuffer;
26646008Syy154373	int retvalue = 0, transfer_len = 0;
26656008Syy154373	char *buffer;
26666008Syy154373	uint32_t controlcode;
26676008Syy154373
26686008Syy154373
26696008Syy154373	/* 4 bytes: Areca io control code */
26706008Syy154373	controlcode = (uint32_t)pkt->pkt_cdbp[5] << 24 |
26716008Syy154373	    (uint32_t)pkt->pkt_cdbp[6] << 16 |
26726008Syy154373	    (uint32_t)pkt->pkt_cdbp[7] << 8 |
26736008Syy154373	    (uint32_t)pkt->pkt_cdbp[8];
26746008Syy154373
26756008Syy154373	if (bp->b_flags & (B_PHYS | B_PAGEIO))
26766008Syy154373		bp_mapin(bp);
26776008Syy154373
26786008Syy154373
26796008Syy154373	buffer = bp->b_un.b_addr;
26806008Syy154373	transfer_len = bp->b_bcount;
26816008Syy154373	if (transfer_len > sizeof (struct CMD_MESSAGE_FIELD)) {
26826008Syy154373		retvalue = ARCMSR_MESSAGE_FAIL;
26836008Syy154373		goto message_out;
26846008Syy154373	}
26856008Syy154373
26866008Syy154373	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)(intptr_t)buffer;
26876008Syy154373
26886008Syy154373	switch (controlcode) {
26896008Syy154373	case ARCMSR_MESSAGE_READ_RQBUFFER:
26906008Syy154373	{
26916008Syy154373		unsigned long *ver_addr;
26926008Syy154373		uint8_t *ptmpQbuffer;
26936008Syy154373		int32_t allxfer_len = 0;
26946008Syy154373
26956008Syy154373		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
26966008Syy154373		if (!ver_addr) {
26976008Syy154373			retvalue = ARCMSR_MESSAGE_FAIL;
26986008Syy154373			goto message_out;
26996008Syy154373		}
27006008Syy154373
27016008Syy154373		ptmpQbuffer = (uint8_t *)ver_addr;
27026008Syy154373		while ((acb->rqbuf_firstidx != acb->rqbuf_lastidx) &&
27036008Syy154373		    (allxfer_len < (MSGDATABUFLEN - 1))) {
27046008Syy154373			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstidx];
27056008Syy154373			(void) memcpy(ptmpQbuffer, pQbuffer, 1);
27066008Syy154373			acb->rqbuf_firstidx++;
27076008Syy154373			acb->rqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
27086008Syy154373			ptmpQbuffer++;
27096008Syy154373			allxfer_len++;
27106008Syy154373		}
27116008Syy154373
27126008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
27136008Syy154373			struct QBUFFER *prbuffer;
27146008Syy154373			uint8_t  *iop_data;
27156008Syy154373			int32_t iop_len;
27166008Syy154373
27176008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
27186008Syy154373			prbuffer = arcmsr_get_iop_rqbuffer(acb);
27196008Syy154373			iop_data = (uint8_t *)prbuffer->data;
27206008Syy154373			iop_len = (int32_t)prbuffer->data_len;
27216008Syy154373
27226008Syy154373			while (iop_len > 0) {
27236008Syy154373				pQbuffer = &acb->rqbuffer[acb->rqbuf_lastidx];
27246008Syy154373				(void) memcpy(pQbuffer, iop_data, 1);
27256008Syy154373				acb->rqbuf_lastidx++;
27266008Syy154373				acb->rqbuf_lastidx %= ARCMSR_MAX_QBUFFER;
27276008Syy154373				iop_data++;
27286008Syy154373				iop_len--;
27296008Syy154373			}
27306008Syy154373			arcmsr_iop_message_read(acb);
27316008Syy154373		}
27326008Syy154373
27336008Syy154373		(void) memcpy(pcmdmessagefld->messagedatabuffer,
27346008Syy154373		    (uint8_t *)ver_addr, allxfer_len);
27356008Syy154373		pcmdmessagefld->cmdmessage.Length = allxfer_len;
27366008Syy154373		pcmdmessagefld->cmdmessage.ReturnCode =
27376008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
27386008Syy154373		kmem_free(ver_addr, MSGDATABUFLEN);
27396008Syy154373	}
27406008Syy154373	break;
27416008Syy154373	case ARCMSR_MESSAGE_WRITE_WQBUFFER:
27426008Syy154373	{
27436008Syy154373		unsigned long *ver_addr;
27446008Syy154373		int32_t my_empty_len, user_len, wqbuf_firstidx, wqbuf_lastidx;
27456008Syy154373		uint8_t *ptmpuserbuffer;
27466008Syy154373
27476008Syy154373		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
27486008Syy154373		if (!ver_addr) {
27496008Syy154373			retvalue = ARCMSR_MESSAGE_FAIL;
27506008Syy154373			goto message_out;
27516008Syy154373		}
27526008Syy154373		ptmpuserbuffer = (uint8_t *)ver_addr;
27536008Syy154373		user_len = pcmdmessagefld->cmdmessage.Length;
27546008Syy154373		(void) memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer,
27556008Syy154373		    user_len);
27566008Syy154373		wqbuf_lastidx = acb->wqbuf_lastidx;
27576008Syy154373		wqbuf_firstidx = acb->wqbuf_firstidx;
27586008Syy154373		if (wqbuf_lastidx != wqbuf_firstidx) {
27596008Syy154373			struct scsi_arq_status *arq_status;
27606008Syy154373
27616008Syy154373			arcmsr_post_ioctldata2iop(acb);
27626008Syy154373			arq_status =
27636008Syy154373			    (struct scsi_arq_status *)(intptr_t)
27646008Syy154373			    (pkt->pkt_scbp);
27656008Syy154373			bzero((caddr_t)arq_status,
27666008Syy154373			    sizeof (struct scsi_arq_status));
27676008Syy154373			arq_status->sts_rqpkt_reason = CMD_CMPLT;
27686008Syy154373			arq_status->sts_rqpkt_state = (STATE_GOT_BUS |
27696008Syy154373			    STATE_GOT_TARGET |STATE_SENT_CMD |
27706008Syy154373			    STATE_XFERRED_DATA | STATE_GOT_STATUS);
27716008Syy154373
27726008Syy154373			arq_status->sts_rqpkt_statistics = pkt->pkt_statistics;
27736008Syy154373			arq_status->sts_rqpkt_resid = 0;
27746008Syy154373			if (&arq_status->sts_sensedata != NULL) {
27756008Syy154373				struct scsi_extended_sense *sts_sensedata;
27766008Syy154373
27776008Syy154373				sts_sensedata = &arq_status->sts_sensedata;
27786008Syy154373
27796008Syy154373				/* has error report sensedata */
27806008Syy154373				sts_sensedata->es_code = 0x0;
27816008Syy154373				sts_sensedata->es_valid = 0x01;
27826008Syy154373				sts_sensedata->es_key = KEY_ILLEGAL_REQUEST;
27836008Syy154373				/* AdditionalSenseLength */
27846008Syy154373				sts_sensedata->es_add_len = 0x0A;
27856008Syy154373				/* AdditionalSenseCode */
27866008Syy154373				sts_sensedata->es_add_code = 0x20;
27876008Syy154373			}
27886008Syy154373			retvalue = ARCMSR_MESSAGE_FAIL;
27896008Syy154373		} else {
27906008Syy154373			my_empty_len = (wqbuf_firstidx-wqbuf_lastidx - 1) &
27916008Syy154373			    (ARCMSR_MAX_QBUFFER - 1);
27926008Syy154373			if (my_empty_len >= user_len) {
27936008Syy154373				while (user_len > 0) {
27946008Syy154373					pQbuffer =
27956008Syy154373					    &acb->wqbuffer[acb->wqbuf_lastidx];
27966008Syy154373					(void) memcpy(pQbuffer,
27976008Syy154373					    ptmpuserbuffer, 1);
27986008Syy154373					acb->wqbuf_lastidx++;
27996008Syy154373					acb->wqbuf_lastidx %=
28006008Syy154373					    ARCMSR_MAX_QBUFFER;
28016008Syy154373					ptmpuserbuffer++;
28026008Syy154373					user_len--;
28036008Syy154373				}
28046008Syy154373				if (acb->acb_flags &
28056008Syy154373				    ACB_F_MESSAGE_WQBUFFER_CLEARED) {
28066008Syy154373					acb->acb_flags &=
28076008Syy154373					    ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
28086008Syy154373					arcmsr_post_ioctldata2iop(acb);
28096008Syy154373				}
28106008Syy154373			} else {
28116008Syy154373				struct scsi_arq_status *arq_status;
28126008Syy154373
28136008Syy154373				/* has error report sensedata */
28146008Syy154373				arq_status =
28156008Syy154373				    (struct scsi_arq_status *)
28166008Syy154373				    (intptr_t)(pkt->pkt_scbp);
28176008Syy154373				bzero((caddr_t)arq_status,
28186008Syy154373				    sizeof (struct scsi_arq_status));
28196008Syy154373				arq_status->sts_rqpkt_reason = CMD_CMPLT;
28206008Syy154373				arq_status->sts_rqpkt_state = (STATE_GOT_BUS |
28216008Syy154373				    STATE_GOT_TARGET |STATE_SENT_CMD |
28226008Syy154373				    STATE_XFERRED_DATA | STATE_GOT_STATUS);
28236008Syy154373				arq_status->sts_rqpkt_statistics =
28246008Syy154373				    pkt->pkt_statistics;
28256008Syy154373				arq_status->sts_rqpkt_resid = 0;
28266008Syy154373				if (&arq_status->sts_sensedata != NULL) {
28276008Syy154373					struct scsi_extended_sense
28286008Syy154373					    *sts_sensedata;
28296008Syy154373
28306008Syy154373					sts_sensedata =
28316008Syy154373					    &arq_status->sts_sensedata;
28326008Syy154373
28336008Syy154373					/* has error report sensedata */
28346008Syy154373					sts_sensedata->es_code  = 0x0;
28356008Syy154373					sts_sensedata->es_valid = 0x01;
28366008Syy154373					sts_sensedata->es_key =
28376008Syy154373					    KEY_ILLEGAL_REQUEST;
28386008Syy154373					/* AdditionalSenseLength */
28396008Syy154373					sts_sensedata->es_add_len = 0x0A;
28406008Syy154373					/* AdditionalSenseCode */
28416008Syy154373					sts_sensedata->es_add_code = 0x20;
28426008Syy154373				}
28436008Syy154373				retvalue = ARCMSR_MESSAGE_FAIL;
28446008Syy154373			}
28456008Syy154373		}
28466008Syy154373		kmem_free(ver_addr, MSGDATABUFLEN);
28476008Syy154373	}
28486008Syy154373	break;
28496008Syy154373	case ARCMSR_MESSAGE_CLEAR_RQBUFFER:
28506008Syy154373	{
28516008Syy154373		pQbuffer = acb->rqbuffer;
28526008Syy154373
28536008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
28546008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
28556008Syy154373			arcmsr_iop_message_read(acb);
28566008Syy154373		}
28576008Syy154373		acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
28586008Syy154373		acb->rqbuf_firstidx = 0;
28596008Syy154373		acb->rqbuf_lastidx = 0;
28606008Syy154373		(void) memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
28616008Syy154373		pcmdmessagefld->cmdmessage.ReturnCode =
28626008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
28636008Syy154373	}
28646008Syy154373	break;
28656008Syy154373	case ARCMSR_MESSAGE_CLEAR_WQBUFFER:
28666008Syy154373	{
28676008Syy154373		pQbuffer = acb->wqbuffer;
28686008Syy154373
28696008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
28706008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
28716008Syy154373			arcmsr_iop_message_read(acb);
28726008Syy154373		}
28736008Syy154373		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
28746008Syy154373		    ACB_F_MESSAGE_WQBUFFER_READ);
28756008Syy154373		acb->wqbuf_firstidx = 0;
28766008Syy154373		acb->wqbuf_lastidx = 0;
28776008Syy154373		(void) memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
28786008Syy154373		pcmdmessagefld->cmdmessage.ReturnCode =
28796008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
28806008Syy154373	}
28816008Syy154373	break;
28826008Syy154373	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER:
28836008Syy154373	{
28846008Syy154373
28856008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
28866008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
28876008Syy154373			arcmsr_iop_message_read(acb);
28886008Syy154373		}
28896008Syy154373		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
28906008Syy154373		    ACB_F_MESSAGE_RQBUFFER_CLEARED |
28916008Syy154373		    ACB_F_MESSAGE_WQBUFFER_READ);
28926008Syy154373		acb->rqbuf_firstidx = 0;
28936008Syy154373		acb->rqbuf_lastidx = 0;
28946008Syy154373		acb->wqbuf_firstidx = 0;
28956008Syy154373		acb->wqbuf_lastidx = 0;
28966008Syy154373		pQbuffer = acb->rqbuffer;
28976008Syy154373		(void) memset(pQbuffer, 0, sizeof (struct QBUFFER));
28986008Syy154373		pQbuffer = acb->wqbuffer;
28996008Syy154373		(void) memset(pQbuffer, 0, sizeof (struct QBUFFER));
29006008Syy154373		pcmdmessagefld->cmdmessage.ReturnCode =
29016008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
29026008Syy154373	}
29036008Syy154373	break;
29046008Syy154373	case ARCMSR_MESSAGE_REQUEST_RETURN_CODE_3F:
29056008Syy154373		pcmdmessagefld->cmdmessage.ReturnCode =
29066008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_3F;
29076008Syy154373		break;
29086008Syy154373	/*
29096008Syy154373	 * Not supported - ARCMSR_MESSAGE_SAY_HELLO
29106008Syy154373	 */
29116008Syy154373	case ARCMSR_MESSAGE_SAY_GOODBYE:
29126008Syy154373		arcmsr_iop_parking(acb);
29136008Syy154373		break;
29146008Syy154373	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
29156008Syy154373		if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
29166008Syy154373			arcmsr_flush_hba_cache(acb);
29176008Syy154373		} else {
29186008Syy154373			arcmsr_flush_hbb_cache(acb);
29196008Syy154373		}
29206008Syy154373		break;
29216008Syy154373	default:
29226008Syy154373		retvalue = ARCMSR_MESSAGE_FAIL;
29236008Syy154373	}
29246008Syy154373
29256008Syy154373message_out:
29266008Syy154373
29276008Syy154373	return (retvalue);
29286008Syy154373}
29296008Syy154373
29306008Syy154373
29316008Syy154373
29326008Syy154373static int
29336008Syy154373arcmsr_cb_ioctl(dev_t dev, int ioctl_cmd, intptr_t arg, int mode,
29346008Syy154373    cred_t *credp, int *rvalp) {
29356008Syy154373#ifndef __lock_lint
29366008Syy154373	_NOTE(ARGUNUSED(rvalp))
29376008Syy154373#endif
29386008Syy154373
29396008Syy154373	struct ACB *acb;
29406008Syy154373	struct CMD_MESSAGE_FIELD *pktioctlfld;
29416008Syy154373	int retvalue = 0;
29426008Syy154373	int instance = MINOR2INST(getminor(dev));
29436008Syy154373
29446008Syy154373	if (instance < 0)
29456008Syy154373		return (ENXIO);
29466008Syy154373
29476008Syy154373	if (secpolicy_sys_config(credp, B_FALSE) != 0)
29486008Syy154373		return (EPERM);
29496008Syy154373
29506008Syy154373	acb = ddi_get_soft_state(arcmsr_soft_state, instance);
29516008Syy154373	if (acb == NULL)
29526008Syy154373		return (ENXIO);
29536008Syy154373
29546008Syy154373	pktioctlfld = kmem_zalloc(sizeof (struct CMD_MESSAGE_FIELD),
29556008Syy154373	    KM_SLEEP);
29566008Syy154373	if (pktioctlfld == NULL)
29576008Syy154373		return (ENXIO);
29586008Syy154373
29596008Syy154373	/*
29606008Syy154373	 * if we got here, we either are a 64-bit app in a 64-bit kernel
29616008Syy154373	 * or a 32-bit app in a 32-bit kernel. Either way, we can just
29626008Syy154373	 * copy in the args without any special conversions.
29636008Syy154373	 */
29646008Syy154373
29656008Syy154373	mutex_enter(&acb->ioctl_mutex);
29666008Syy154373	if (ddi_copyin((void *)arg, pktioctlfld,
29676008Syy154373	    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0) {
29686008Syy154373		retvalue = ENXIO;
29696008Syy154373		goto ioctl_out;
29706008Syy154373	}
29716008Syy154373
29726008Syy154373	if (memcmp(pktioctlfld->cmdmessage.Signature, "ARCMSR", 6) != 0) {
29736008Syy154373		/* validity check */
29746008Syy154373		retvalue = ENXIO;
29756008Syy154373		goto ioctl_out;
29766008Syy154373	}
29776008Syy154373
29786008Syy154373	switch ((unsigned int)ioctl_cmd) {
29796008Syy154373	case ARCMSR_MESSAGE_READ_RQBUFFER:
29806008Syy154373	{
29816008Syy154373		unsigned long *ver_addr;
29826008Syy154373		uint8_t *pQbuffer, *ptmpQbuffer;
29836008Syy154373		int32_t allxfer_len = 0;
29846008Syy154373
29856008Syy154373		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
29866008Syy154373		if (ver_addr == NULL) {
29876008Syy154373			retvalue = ENXIO;
29886008Syy154373			goto ioctl_out;
29896008Syy154373		}
29906008Syy154373
29916008Syy154373		ptmpQbuffer = (uint8_t *)ver_addr;
29926008Syy154373		while ((acb->rqbuf_firstidx != acb->rqbuf_lastidx) &&
29936008Syy154373		    (allxfer_len < (MSGDATABUFLEN - 1))) {
29946008Syy154373			/* copy READ QBUFFER to srb */
29956008Syy154373			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstidx];
29966008Syy154373			(void) memcpy(ptmpQbuffer, pQbuffer, 1);
29976008Syy154373			acb->rqbuf_firstidx++;
29986008Syy154373			/* if last index number set it to 0 */
29996008Syy154373			acb->rqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
30006008Syy154373			ptmpQbuffer++;
30016008Syy154373			allxfer_len++;
30026008Syy154373		}
30036008Syy154373
30046008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
30056008Syy154373			struct QBUFFER *prbuffer;
30066008Syy154373			uint8_t *pQbuffer;
30076008Syy154373			uint8_t *iop_data;
30086008Syy154373			int32_t iop_len;
30096008Syy154373
30106008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
30116008Syy154373			prbuffer = arcmsr_get_iop_rqbuffer(acb);
30126008Syy154373			iop_data = (uint8_t *)prbuffer->data;
30136008Syy154373			iop_len = (int32_t)prbuffer->data_len;
30146008Syy154373			/*
30156008Syy154373			 * this iop data does no chance to make me overflow
30166008Syy154373			 * again here, so just do it
30176008Syy154373			 */
30186008Syy154373			while (iop_len > 0) {
30196008Syy154373				pQbuffer = &acb->rqbuffer[acb->rqbuf_lastidx];
30206008Syy154373				(void) memcpy(pQbuffer, iop_data, 1);
30216008Syy154373				acb->rqbuf_lastidx++;
30226008Syy154373				/* if last index number set it to 0 */
30236008Syy154373				acb->rqbuf_lastidx %= ARCMSR_MAX_QBUFFER;
30246008Syy154373				iop_data++;
30256008Syy154373				iop_len--;
30266008Syy154373			}
30276008Syy154373			/* let IOP know data has been read */
30286008Syy154373			arcmsr_iop_message_read(acb);
30296008Syy154373		}
30306008Syy154373		(void) memcpy(pktioctlfld->messagedatabuffer,
30316008Syy154373		    (uint8_t *)ver_addr, allxfer_len);
30326008Syy154373		pktioctlfld->cmdmessage.Length = allxfer_len;
30336008Syy154373		pktioctlfld->cmdmessage.ReturnCode =
30346008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
30356008Syy154373
30366008Syy154373		if (ddi_copyout(pktioctlfld, (void *)arg,
30376008Syy154373		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
30386008Syy154373			retvalue = ENXIO;
30396008Syy154373
30406008Syy154373		kmem_free(ver_addr, MSGDATABUFLEN);
30416008Syy154373	}
30426008Syy154373	break;
30436008Syy154373	case ARCMSR_MESSAGE_WRITE_WQBUFFER:
30446008Syy154373	{
30456008Syy154373		unsigned long *ver_addr;
30466008Syy154373		int32_t my_empty_len, user_len;
30476008Syy154373		int32_t wqbuf_firstidx, wqbuf_lastidx;
30486008Syy154373		uint8_t *pQbuffer, *ptmpuserbuffer;
30496008Syy154373
30506008Syy154373		ver_addr = kmem_zalloc(MSGDATABUFLEN, KM_SLEEP);
30516008Syy154373
30526008Syy154373		if (ver_addr == NULL) {
30536008Syy154373			retvalue = ENXIO;
30546008Syy154373			goto ioctl_out;
30556008Syy154373		}
30566008Syy154373
30576008Syy154373		ptmpuserbuffer = (uint8_t *)ver_addr;
30586008Syy154373		user_len = pktioctlfld->cmdmessage.Length;
30596008Syy154373		(void) memcpy(ptmpuserbuffer,
30606008Syy154373		    pktioctlfld->messagedatabuffer, user_len);
30616008Syy154373		/*
30626008Syy154373		 * check ifdata xfer length of this request will overflow
30636008Syy154373		 * my array qbuffer
30646008Syy154373		 */
30656008Syy154373		wqbuf_lastidx = acb->wqbuf_lastidx;
30666008Syy154373		wqbuf_firstidx = acb->wqbuf_firstidx;
30676008Syy154373		if (wqbuf_lastidx != wqbuf_firstidx) {
30686008Syy154373			arcmsr_post_ioctldata2iop(acb);
30696008Syy154373			pktioctlfld->cmdmessage.ReturnCode =
30706008Syy154373			    ARCMSR_MESSAGE_RETURNCODE_ERROR;
30716008Syy154373		} else {
30726008Syy154373			my_empty_len = (wqbuf_firstidx - wqbuf_lastidx - 1)
30736008Syy154373			    & (ARCMSR_MAX_QBUFFER - 1);
30746008Syy154373			if (my_empty_len >= user_len) {
30756008Syy154373				while (user_len > 0) {
30766008Syy154373					/* copy srb data to wqbuffer */
30776008Syy154373					pQbuffer =
30786008Syy154373					    &acb->wqbuffer[acb->wqbuf_lastidx];
30796008Syy154373					(void) memcpy(pQbuffer,
30806008Syy154373					    ptmpuserbuffer, 1);
30816008Syy154373					acb->wqbuf_lastidx++;
30826008Syy154373					/* iflast index number set it to 0 */
30836008Syy154373					acb->wqbuf_lastidx %=
30846008Syy154373					    ARCMSR_MAX_QBUFFER;
30856008Syy154373					ptmpuserbuffer++;
30866008Syy154373					user_len--;
30876008Syy154373				}
30886008Syy154373				/* post first Qbuffer */
30896008Syy154373				if (acb->acb_flags &
30906008Syy154373				    ACB_F_MESSAGE_WQBUFFER_CLEARED) {
30916008Syy154373					acb->acb_flags &=
30926008Syy154373					    ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
30936008Syy154373					arcmsr_post_ioctldata2iop(acb);
30946008Syy154373				}
30956008Syy154373				pktioctlfld->cmdmessage.ReturnCode =
30966008Syy154373				    ARCMSR_MESSAGE_RETURNCODE_OK;
30976008Syy154373			} else {
30986008Syy154373				pktioctlfld->cmdmessage.ReturnCode =
30996008Syy154373				    ARCMSR_MESSAGE_RETURNCODE_ERROR;
31006008Syy154373			}
31016008Syy154373		}
31026008Syy154373		if (ddi_copyout(pktioctlfld, (void *)arg,
31036008Syy154373		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
31046008Syy154373			retvalue = ENXIO;
31056008Syy154373
31066008Syy154373		kmem_free(ver_addr, MSGDATABUFLEN);
31076008Syy154373	}
31086008Syy154373	break;
31096008Syy154373	case ARCMSR_MESSAGE_CLEAR_RQBUFFER:
31106008Syy154373	{
31116008Syy154373		uint8_t *pQbuffer = acb->rqbuffer;
31126008Syy154373
31136008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
31146008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
31156008Syy154373				arcmsr_iop_message_read(acb);
31166008Syy154373		}
31176008Syy154373		acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
31186008Syy154373		acb->rqbuf_firstidx = 0;
31196008Syy154373		acb->rqbuf_lastidx = 0;
31206008Syy154373		bzero(pQbuffer, ARCMSR_MAX_QBUFFER);
31216008Syy154373		/* report success */
31226008Syy154373		pktioctlfld->cmdmessage.ReturnCode =
31236008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
31246008Syy154373		if (ddi_copyout(pktioctlfld, (void *)arg,
31256008Syy154373		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
31266008Syy154373			retvalue = ENXIO;
31276008Syy154373
31286008Syy154373	}
31296008Syy154373	break;
31306008Syy154373	case ARCMSR_MESSAGE_CLEAR_WQBUFFER:
31316008Syy154373	{
31326008Syy154373		uint8_t *pQbuffer = acb->wqbuffer;
31336008Syy154373
31346008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
31356008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
31366008Syy154373			arcmsr_iop_message_read(acb);
31376008Syy154373		}
31386008Syy154373		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
31396008Syy154373		    ACB_F_MESSAGE_WQBUFFER_READ);
31406008Syy154373		acb->wqbuf_firstidx = 0;
31416008Syy154373		acb->wqbuf_lastidx = 0;
31426008Syy154373		bzero(pQbuffer, ARCMSR_MAX_QBUFFER);
31436008Syy154373		/* report success */
31446008Syy154373		pktioctlfld->cmdmessage.ReturnCode =
31456008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
31466008Syy154373		if (ddi_copyout(pktioctlfld, (void *)arg,
31476008Syy154373		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
31486008Syy154373			retvalue = ENXIO;
31496008Syy154373
31506008Syy154373	}
31516008Syy154373	break;
31526008Syy154373	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER:
31536008Syy154373	{
31546008Syy154373		uint8_t *pQbuffer;
31556008Syy154373
31566008Syy154373		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
31576008Syy154373			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
31586008Syy154373			arcmsr_iop_message_read(acb);
31596008Syy154373		}
31606008Syy154373		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
31616008Syy154373		    ACB_F_MESSAGE_RQBUFFER_CLEARED |
31626008Syy154373		    ACB_F_MESSAGE_WQBUFFER_READ);
31636008Syy154373		acb->rqbuf_firstidx = 0;
31646008Syy154373		acb->rqbuf_lastidx = 0;
31656008Syy154373		acb->wqbuf_firstidx = 0;
31666008Syy154373		acb->wqbuf_lastidx = 0;
31676008Syy154373		pQbuffer = acb->rqbuffer;
31686008Syy154373		bzero(pQbuffer, sizeof (struct QBUFFER));
31696008Syy154373		pQbuffer = acb->wqbuffer;
31706008Syy154373		bzero(pQbuffer, sizeof (struct QBUFFER));
31716008Syy154373		/* report success */
31726008Syy154373		pktioctlfld->cmdmessage.ReturnCode =
31736008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_OK;
31746008Syy154373		if (ddi_copyout(pktioctlfld, (void *)arg,
31756008Syy154373		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
31766008Syy154373			retvalue = ENXIO;
31776008Syy154373
31786008Syy154373	}
31796008Syy154373	break;
31806008Syy154373	case ARCMSR_MESSAGE_REQUEST_RETURN_CODE_3F:
31816008Syy154373	{
31826008Syy154373		pktioctlfld->cmdmessage.ReturnCode =
31836008Syy154373		    ARCMSR_MESSAGE_RETURNCODE_3F;
31846008Syy154373		if (ddi_copyout(pktioctlfld, (void *)arg,
31856008Syy154373		    sizeof (struct CMD_MESSAGE_FIELD), mode) != 0)
31866008Syy154373			retvalue = ENXIO;
31876008Syy154373	}
31886008Syy154373	break;
31896008Syy154373	/* Not supported: ARCMSR_MESSAGE_SAY_HELLO */
31906008Syy154373	case ARCMSR_MESSAGE_SAY_GOODBYE:
31916008Syy154373		arcmsr_iop_parking(acb);
31926008Syy154373		break;
31936008Syy154373	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
31946008Syy154373		if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
31956008Syy154373			arcmsr_flush_hba_cache(acb);
31966008Syy154373		} else {
31976008Syy154373			arcmsr_flush_hbb_cache(acb);
31986008Syy154373		}
31996008Syy154373		break;
32006008Syy154373	default:
32016008Syy154373		retvalue = ENOTTY;
32026008Syy154373	}
32036008Syy154373
32046008Syy154373ioctl_out:
32056008Syy154373	kmem_free(pktioctlfld, sizeof (struct CMD_MESSAGE_FIELD));
32066008Syy154373	mutex_exit(&acb->ioctl_mutex);
32076008Syy154373
32086008Syy154373	return (retvalue);
32096008Syy154373}
32106008Syy154373
32116008Syy154373
32126008Syy154373
32136008Syy154373static struct CCB *
32146008Syy154373arcmsr_get_freeccb(struct ACB *acb) {
32156008Syy154373
32166008Syy154373	struct CCB *ccb;
32176008Syy154373	int workingccb_startindex, workingccb_doneindex;
32186008Syy154373
32196008Syy154373
32206008Syy154373	mutex_enter(&acb->workingQ_mutex);
32216008Syy154373	workingccb_doneindex = acb->workingccb_doneindex;
32226008Syy154373	workingccb_startindex = acb->workingccb_startindex;
32236008Syy154373	ccb = acb->ccbworkingQ[workingccb_startindex];
32246008Syy154373	workingccb_startindex++;
32256008Syy154373	workingccb_startindex %= ARCMSR_MAX_FREECCB_NUM;
32266008Syy154373	if (workingccb_doneindex != workingccb_startindex) {
32276008Syy154373		acb->workingccb_startindex = workingccb_startindex;
32286008Syy154373	} else {
32296008Syy154373		ccb = NULL;
32306008Syy154373	}
32316008Syy154373
32326008Syy154373	mutex_exit(&acb->workingQ_mutex);
32336008Syy154373	return (ccb);
32346008Syy154373}
32356008Syy154373
32366008Syy154373
32376008Syy154373
32386008Syy154373static int
32396008Syy154373arcmsr_seek_cmd2abort(struct ACB *acb,
32406008Syy154373    struct scsi_pkt *abortpkt) {
32416008Syy154373
32426008Syy154373	struct CCB *ccb;
32436008Syy154373	uint32_t intmask_org = 0;
32446008Syy154373	int i = 0;
32456008Syy154373
32466008Syy154373	acb->num_aborts++;
32476008Syy154373
32486008Syy154373	if (abortpkt == NULL) {
32496008Syy154373		/*
32506008Syy154373		 * if abortpkt is NULL, the upper layer needs us
32516008Syy154373		 * to abort all commands
32526008Syy154373		 */
32536008Syy154373		if (acb->ccboutstandingcount != 0) {
32546008Syy154373			/* disable all outbound interrupt */
32556008Syy154373			intmask_org = arcmsr_disable_allintr(acb);
32566008Syy154373			/* clear and abort all outbound posted Q */
32576008Syy154373			arcmsr_done4abort_postqueue(acb);
32586008Syy154373			/* talk to iop 331 outstanding command aborted */
32596008Syy154373			if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
32606008Syy154373				arcmsr_abort_hba_allcmd(acb);
32616008Syy154373			} else {
32626008Syy154373				arcmsr_abort_hbb_allcmd(acb);
32636008Syy154373			}
32646008Syy154373
32656008Syy154373			for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
32666008Syy154373				ccb = acb->pccb_pool[i];
32676008Syy154373				if (ccb->startdone == ARCMSR_CCB_START) {
32686008Syy154373					/*
32696008Syy154373					 * this ccb will complete at
32706008Syy154373					 * hwinterrupt
32716008Syy154373					 */
32726008Syy154373					ccb->startdone = ARCMSR_CCB_ABORTED;
32736008Syy154373					ccb->pkt->pkt_reason = CMD_ABORTED;
32746008Syy154373					ccb->pkt->pkt_statistics |=
32756008Syy154373					    STAT_ABORTED;
32766008Syy154373					arcmsr_ccb_complete(ccb, 1);
32776008Syy154373				}
32786008Syy154373			}
32796008Syy154373			/*
32806008Syy154373			 * enable outbound Post Queue, outbound
32816008Syy154373			 * doorbell Interrupt
32826008Syy154373			 */
32836008Syy154373			arcmsr_enable_allintr(acb, intmask_org);
32846008Syy154373		}
32856008Syy154373		return (DDI_SUCCESS);
32866008Syy154373	}
32876008Syy154373
32886008Syy154373	/*
32896008Syy154373	 * It is the upper layer do abort command this lock
32906008Syy154373	 * just prior to calling us.
32916008Syy154373	 * First determine if we currently own this command.
32926008Syy154373	 * Start by searching the device queue. If not found
32936008Syy154373	 * at all, and the system wanted us to just abort the
32946008Syy154373	 * command returnsuccess.
32956008Syy154373	 */
32966008Syy154373
32976008Syy154373	if (acb->ccboutstandingcount != 0) {
32986008Syy154373		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
32996008Syy154373			ccb = acb->pccb_pool[i];
33006008Syy154373			if (ccb->startdone == ARCMSR_CCB_START) {
33016008Syy154373				if (ccb->pkt == abortpkt) {
33026008Syy154373					ccb->startdone =
33036008Syy154373					    ARCMSR_CCB_ABORTED;
33046008Syy154373					goto abort_outstanding_cmd;
33056008Syy154373				}
33066008Syy154373			}
33076008Syy154373		}
33086008Syy154373	}
33096008Syy154373
33106008Syy154373	return (DDI_FAILURE);
33116008Syy154373
33126008Syy154373abort_outstanding_cmd:
33136008Syy154373	/* disable all outbound interrupts */
33146008Syy154373	intmask_org = arcmsr_disable_allintr(acb);
33156008Syy154373	if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
33166008Syy154373		arcmsr_polling_hba_ccbdone(acb, ccb);
33176008Syy154373	} else {
33186008Syy154373		arcmsr_polling_hbb_ccbdone(acb, ccb);
33196008Syy154373	}
33206008Syy154373
33216008Syy154373	/* enable outbound Post Queue, outbound doorbell Interrupt */
33226008Syy154373	arcmsr_enable_allintr(acb, intmask_org);
33236008Syy154373	return (DDI_SUCCESS);
33246008Syy154373}
33256008Syy154373
33266008Syy154373
33276008Syy154373
33286008Syy154373static void
33296008Syy154373arcmsr_pcidev_disattach(struct ACB *acb) {
33306008Syy154373
33316008Syy154373	struct CCB *ccb;
33326008Syy154373	int i = 0;
33336008Syy154373
33346008Syy154373	/* disable all outbound interrupts */
33356008Syy154373	(void) arcmsr_disable_allintr(acb);
33366008Syy154373	/* stop adapter background rebuild */
33376008Syy154373	if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
33386008Syy154373		arcmsr_stop_hba_bgrb(acb);
33396008Syy154373		arcmsr_flush_hba_cache(acb);
33406008Syy154373	} else {
33416008Syy154373		arcmsr_stop_hbb_bgrb(acb);
33426008Syy154373		arcmsr_flush_hbb_cache(acb);
33436008Syy154373	}
33446008Syy154373	/* abort all outstanding commands */
33456008Syy154373	acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
33466008Syy154373	acb->acb_flags &= ~ACB_F_IOP_INITED;
33476008Syy154373
33486008Syy154373	if (acb->ccboutstandingcount != 0) {
33496008Syy154373		/* clear and abort all outbound posted Q */
33506008Syy154373		arcmsr_done4abort_postqueue(acb);
33516008Syy154373		/* talk to iop 331 outstanding command aborted */
33526008Syy154373		if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
33536008Syy154373			arcmsr_abort_hba_allcmd(acb);
33546008Syy154373		} else {
33556008Syy154373			arcmsr_abort_hbb_allcmd(acb);
33566008Syy154373		}
33576008Syy154373
33586008Syy154373		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
33596008Syy154373			ccb = acb->pccb_pool[i];
33606008Syy154373			if (ccb->startdone == ARCMSR_CCB_START) {
33616008Syy154373				ccb->startdone = ARCMSR_CCB_ABORTED;
33626008Syy154373				ccb->pkt->pkt_reason = CMD_ABORTED;
33636008Syy154373				ccb->pkt->pkt_statistics |= STAT_ABORTED;
33646008Syy154373				arcmsr_ccb_complete(ccb, 1);
33656008Syy154373			}
33666008Syy154373		}
33676008Syy154373	}
33686008Syy154373}
33696008Syy154373
33706008Syy154373/* get firmware miscellaneous data */
33716008Syy154373static void
33726008Syy154373arcmsr_get_hba_config(struct ACB *acb) {
33736008Syy154373
33746008Syy154373	struct HBA_msgUnit *phbamu;
33756008Syy154373
33766008Syy154373	char *acb_firm_model;
33776008Syy154373	char *acb_firm_version;
33786008Syy154373	char *acb_device_map;
33796008Syy154373	char *iop_firm_model;
33806008Syy154373	char *iop_firm_version;
33816008Syy154373	char *iop_device_map;
33826008Syy154373	int count;
33836008Syy154373
33846008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
33856008Syy154373	acb_firm_model = acb->firm_model;
33866008Syy154373	acb_firm_version = acb->firm_version;
33876008Syy154373	acb_device_map = acb->device_map;
33886008Syy154373	/* firm_model, 15 */
33896008Syy154373	iop_firm_model = (char *)
33906008Syy154373	    (&phbamu->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);
33916008Syy154373	/* firm_version, 17 */
33926008Syy154373	iop_firm_version =
33936008Syy154373	    (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);
33946008Syy154373
33956008Syy154373	/* device_map, 21 */
33966008Syy154373	iop_device_map =
33976008Syy154373	    (char *)(&phbamu->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]);
33986008Syy154373
33996008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->inbound_msgaddr0,
34006008Syy154373	    ARCMSR_INBOUND_MESG0_GET_CONFIG);
34016008Syy154373
34026008Syy154373	if (!arcmsr_hba_wait_msgint_ready(acb))
34036008Syy154373		cmn_err(CE_CONT,
34046008Syy154373		    "arcmsr%d: timeout while waiting for adapter firmware "
34056008Syy154373		    "miscellaneous data",
34066008Syy154373		    ddi_get_instance(acb->dev_info));
34076008Syy154373
34086008Syy154373	count = 8;
34096008Syy154373	while (count) {
34106008Syy154373		*acb_firm_model =
34116008Syy154373		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_model);
34126008Syy154373		acb_firm_model++;
34136008Syy154373		iop_firm_model++;
34146008Syy154373		count--;
34156008Syy154373	}
34166008Syy154373
34176008Syy154373	count = 16;
34186008Syy154373	while (count) {
34196008Syy154373		*acb_firm_version =
34206008Syy154373		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_firm_version);
34216008Syy154373		acb_firm_version++;
34226008Syy154373		iop_firm_version++;
34236008Syy154373		count--;
34246008Syy154373	}
34256008Syy154373
34266008Syy154373	count = 16;
34276008Syy154373	while (count) {
34286008Syy154373		*acb_device_map =
34296008Syy154373		    CHIP_REG_READ8(acb->reg_mu_acc_handle0, iop_device_map);
34306008Syy154373		acb_device_map++;
34316008Syy154373		iop_device_map++;
34326008Syy154373		count--;
34336008Syy154373	}
34346008Syy154373
34356008Syy154373	cmn_err(CE_CONT, "arcmsr%d: ARECA RAID FIRMWARE VERSION %s",
34366008Syy154373	    ddi_get_instance(acb->dev_info), acb->firm_version);
34376008Syy154373
34386008Syy154373	/* firm_request_len, 1 */
34396008Syy154373	acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
34406008Syy154373	    &phbamu->msgcode_rwbuffer[1]);
34416008Syy154373	/* firm_numbers_queue, 2 */
34426008Syy154373	acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
34436008Syy154373	    &phbamu->msgcode_rwbuffer[2]);
34446008Syy154373	/* firm_sdram_size, 3 */
34456008Syy154373	acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
34466008Syy154373	    &phbamu->msgcode_rwbuffer[3]);
34476008Syy154373	/* firm_ide_channels, 4 */
34486008Syy154373	acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
34496008Syy154373	    &phbamu->msgcode_rwbuffer[4]);
34506008Syy154373}
34516008Syy154373
34526008Syy154373/* get firmware miscellaneous data */
34536008Syy154373static void
34546008Syy154373arcmsr_get_hbb_config(struct ACB *acb) {
34556008Syy154373
34566008Syy154373	struct HBB_msgUnit *phbbmu;
34576008Syy154373	char *acb_firm_model;
34586008Syy154373	char *acb_firm_version;
34596008Syy154373	char *acb_device_map;
34606008Syy154373	char *iop_firm_model;
34616008Syy154373	char *iop_firm_version;
34626008Syy154373	char *iop_device_map;
34636008Syy154373	int count;
34646008Syy154373
34656008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
34666008Syy154373	acb_firm_model = acb->firm_model;
34676008Syy154373	acb_firm_version = acb->firm_version;
34686008Syy154373	acb_device_map = acb->device_map;
34696008Syy154373	/* firm_model, 15 */
34706008Syy154373	iop_firm_model = (char *)
34716008Syy154373	    (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_MODEL_OFFSET]);
34726008Syy154373	/* firm_version, 17 */
34736008Syy154373	iop_firm_version = (char *)
34746008Syy154373	    (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_VERS_OFFSET]);
34756008Syy154373	/* device_map, 21 */
34766008Syy154373	iop_device_map = (char *)
34776008Syy154373	    (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[ARCMSR_FW_MAP_OFFSET]);
34786008Syy154373
34796008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
34806008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
34816008Syy154373	    ARCMSR_MESSAGE_GET_CONFIG);
34826008Syy154373
34836008Syy154373	if (!arcmsr_hbb_wait_msgint_ready(acb))
34846008Syy154373		cmn_err(CE_CONT,
34856008Syy154373		    "arcmsr%d: timeout while waiting for adapter firmware "
34866008Syy154373		    "miscellaneous data",
34876008Syy154373		    ddi_get_instance(acb->dev_info));
34886008Syy154373
34896008Syy154373	count = 8;
34906008Syy154373	while (count) {
34916008Syy154373		*acb_firm_model = CHIP_REG_READ8(acb->reg_mu_acc_handle1,
34926008Syy154373		    iop_firm_model);
34936008Syy154373		acb_firm_model++;
34946008Syy154373		iop_firm_model++;
34956008Syy154373		count--;
34966008Syy154373	}
34976008Syy154373
34986008Syy154373	count = 16;
34996008Syy154373	while (count) {
35006008Syy154373		*acb_firm_version = CHIP_REG_READ8(acb->reg_mu_acc_handle1,
35016008Syy154373		    iop_firm_version);
35026008Syy154373		acb_firm_version++;
35036008Syy154373		iop_firm_version++;
35046008Syy154373		count--;
35056008Syy154373	}
35066008Syy154373	count = 16;
35076008Syy154373	while (count) {
35086008Syy154373		*acb_device_map =
35096008Syy154373		    CHIP_REG_READ8(acb->reg_mu_acc_handle1, iop_device_map);
35106008Syy154373		acb_device_map++;
35116008Syy154373		iop_device_map++;
35126008Syy154373		count--;
35136008Syy154373	}
35146008Syy154373
35156008Syy154373	cmn_err(CE_CONT, "arcmsr%d: ARECA RAID FIRMWARE VERSION %s",
35166008Syy154373	    ddi_get_instance(acb->dev_info), acb->firm_version);
35176008Syy154373
35186008Syy154373	/* firm_request_len, 1 */
35196008Syy154373	acb->firm_request_len = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
35206008Syy154373		&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[1]);
35216008Syy154373	/* firm_numbers_queue, 2 */
35226008Syy154373	acb->firm_numbers_queue = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
35236008Syy154373	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[2]);
35246008Syy154373	/* firm_sdram_size, 3 */
35256008Syy154373	acb->firm_sdram_size = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
35266008Syy154373	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[3]);
35276008Syy154373	/* firm_ide_channels, 4 */
35286008Syy154373	acb->firm_ide_channels = CHIP_REG_READ32(acb->reg_mu_acc_handle1,
35296008Syy154373	    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[4]);
35306008Syy154373}
35316008Syy154373
35326008Syy154373
35336008Syy154373
35346008Syy154373/* start background rebuild */
35356008Syy154373static void
35366008Syy154373arcmsr_start_hba_bgrb(struct ACB *acb) {
35376008Syy154373
35386008Syy154373	struct HBA_msgUnit *phbamu;
35396008Syy154373
35406008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
35416008Syy154373
35426008Syy154373	acb->acb_flags |= ACB_F_MSG_START_BGRB;
35436008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
35446008Syy154373	    &phbamu->inbound_msgaddr0, ARCMSR_INBOUND_MESG0_START_BGRB);
35456008Syy154373
35466008Syy154373	if (!arcmsr_hba_wait_msgint_ready(acb))
35476008Syy154373		cmn_err(CE_WARN,
35486008Syy154373		    "arcmsr%d: timeout while waiting for background "
35496008Syy154373		    "rebuild to start",
35506008Syy154373		    ddi_get_instance(acb->dev_info));
35516008Syy154373}
35526008Syy154373
35536008Syy154373
35546008Syy154373static void
35556008Syy154373arcmsr_start_hbb_bgrb(struct ACB *acb) {
35566008Syy154373
35576008Syy154373	struct HBB_msgUnit *phbbmu;
35586008Syy154373
35596008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
35606008Syy154373
35616008Syy154373	acb->acb_flags |= ACB_F_MSG_START_BGRB;
35626008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
35636008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
35646008Syy154373	    ARCMSR_MESSAGE_START_BGRB);
35656008Syy154373
35666008Syy154373	if (!arcmsr_hbb_wait_msgint_ready(acb))
35676008Syy154373		cmn_err(CE_WARN,
35686008Syy154373		    "arcmsr%d: timeout while waiting for background "
35696008Syy154373		    "rebuild to start",
35706008Syy154373		    ddi_get_instance(acb->dev_info));
35716008Syy154373}
35726008Syy154373
35736008Syy154373
35746008Syy154373static void
35756008Syy154373arcmsr_polling_hba_ccbdone(struct ACB *acb, struct CCB *poll_ccb) {
35766008Syy154373
35776008Syy154373	struct HBA_msgUnit *phbamu;
35786008Syy154373	struct CCB *ccb;
35796008Syy154373	uint32_t flag_ccb, outbound_intstatus;
35806008Syy154373	uint32_t poll_ccb_done = 0;
35816008Syy154373	uint32_t poll_count = 0;
35826008Syy154373
35836008Syy154373
35846008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
35856008Syy154373
35866008Syy154373polling_ccb_retry:
35876008Syy154373	poll_count++;
35886008Syy154373	outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
35896008Syy154373	    &phbamu->outbound_intstatus) & acb->outbound_int_enable;
35906008Syy154373
35916008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus,
35926008Syy154373	    outbound_intstatus); /* clear interrupt */
35936008Syy154373
35946008Syy154373	/* Use correct offset and size for syncing */
35956008Syy154373	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size,
35966008Syy154373	    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS)
35976008Syy154373		return;
35986008Syy154373
35996008Syy154373	/*LINTED*/
36006008Syy154373	while (1) {
36016008Syy154373		if ((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
36026008Syy154373		    &phbamu->outbound_queueport)) == 0xFFFFFFFF) {
36036008Syy154373			if (poll_ccb_done) {
36046008Syy154373				/* chip FIFO no ccb for completion already */
36056008Syy154373				break;
36066008Syy154373			} else {
36076008Syy154373				drv_usecwait(25000);
36086008Syy154373				if ((poll_count > 100) && (poll_ccb != NULL)) {
36096008Syy154373					break;
36106008Syy154373				}
36116008Syy154373				if (acb->ccboutstandingcount == 0) {
36126008Syy154373					break;
36136008Syy154373				}
36146008Syy154373					goto polling_ccb_retry;
36156008Syy154373			}
36166008Syy154373		}
36176008Syy154373
36186008Syy154373		/* check ifcommand done with no error */
36196008Syy154373		ccb = (struct CCB *)(acb->vir2phy_offset  +
36206008Syy154373		    (flag_ccb << 5)); /* frame must be 32 bytes aligned */
36216008Syy154373		if (poll_ccb != NULL)
36226008Syy154373			poll_ccb_done = (ccb == poll_ccb) ? 1 : 0;
36236008Syy154373
36246008Syy154373		if ((ccb->acb != acb) ||
36256008Syy154373		    (ccb->startdone != ARCMSR_CCB_START)) {
36266008Syy154373			if (ccb->startdone == ARCMSR_CCB_ABORTED) {
36276008Syy154373				ccb->pkt->pkt_reason = CMD_ABORTED;
36286008Syy154373				ccb->pkt->pkt_statistics |= STAT_ABORTED;
36296008Syy154373				arcmsr_ccb_complete(ccb, 1);
36306008Syy154373				continue;
36316008Syy154373			}
36326008Syy154373			cmn_err(CE_WARN, "arcmsr%d: polling op got "
36336008Syy154373			    "unexpected ccb command done",
36346008Syy154373			    ddi_get_instance(acb->dev_info));
36356008Syy154373			continue;
36366008Syy154373		}
36376008Syy154373		arcmsr_report_ccb_state(acb, ccb, flag_ccb);
36386008Syy154373	}	/* drain reply FIFO */
36396008Syy154373}
36406008Syy154373
36416008Syy154373
36426008Syy154373static void
36436008Syy154373arcmsr_polling_hbb_ccbdone(struct ACB *acb,
36446008Syy154373    struct CCB *poll_ccb) {
36456008Syy154373
36466008Syy154373	struct HBB_msgUnit *phbbmu;
36476008Syy154373	struct CCB *ccb;
36486008Syy154373	uint32_t flag_ccb;
36496008Syy154373	uint32_t poll_ccb_done = 0;
36506008Syy154373	uint32_t poll_count = 0;
36516008Syy154373	int index;
36526008Syy154373
36536008Syy154373
36546008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
36556008Syy154373
36566008Syy154373
36576008Syy154373polling_ccb_retry:
36586008Syy154373	poll_count++;
36596008Syy154373	/* clear doorbell interrupt */
36606008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
36616008Syy154373	    &phbbmu->hbb_doorbell->iop2drv_doorbell,
36626008Syy154373	    ARCMSR_DOORBELL_INT_CLEAR_PATTERN);
36636008Syy154373
36646008Syy154373	/* Use correct offset and size for syncing */
36656008Syy154373	if (ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size,
36666008Syy154373	    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS)
36676008Syy154373		return;
36686008Syy154373
36696008Syy154373
36706008Syy154373	/*LINTED*/
36716008Syy154373	while (1) {
36726008Syy154373		index = phbbmu->doneq_index;
36736008Syy154373		if ((flag_ccb = phbbmu->done_qbuffer[index]) == 0) {
36746008Syy154373			if (poll_ccb_done) {
36756008Syy154373				/* chip FIFO no ccb for completion already */
36766008Syy154373				break;
36776008Syy154373			} else {
36786008Syy154373				drv_usecwait(25000);
36796008Syy154373				if ((poll_count > 100) && (poll_ccb != NULL))
36806008Syy154373					break;
36816008Syy154373				if (acb->ccboutstandingcount == 0)
36826008Syy154373					break;
36836008Syy154373				goto polling_ccb_retry;
36846008Syy154373			}
36856008Syy154373		}
36866008Syy154373
36876008Syy154373		phbbmu->done_qbuffer[index] = 0;
36886008Syy154373		index++;
36896008Syy154373		/* if last index number set it to 0 */
36906008Syy154373		index %= ARCMSR_MAX_HBB_POSTQUEUE;
36916008Syy154373		phbbmu->doneq_index = index;
36926008Syy154373		/* check if command done with no error */
36936008Syy154373		/* frame must be 32 bytes aligned */
36946008Syy154373		ccb = (struct CCB *)(acb->vir2phy_offset +
36956008Syy154373		    (flag_ccb << 5));
36966008Syy154373		if (poll_ccb != NULL)
36976008Syy154373			poll_ccb_done = (ccb == poll_ccb) ? 1 : 0;
36986008Syy154373		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
36996008Syy154373			if (ccb->startdone == ARCMSR_CCB_ABORTED) {
37006008Syy154373				ccb->pkt->pkt_reason = CMD_ABORTED;
37016008Syy154373				ccb->pkt->pkt_statistics |= STAT_ABORTED;
37026008Syy154373				arcmsr_ccb_complete(ccb, 1);
37036008Syy154373				continue;
37046008Syy154373			}
37056008Syy154373			cmn_err(CE_WARN, "arcmsr%d: polling op got"
37066008Syy154373			    "unexpect ccb command done",
37076008Syy154373			    ddi_get_instance(acb->dev_info));
37086008Syy154373			continue;
37096008Syy154373		}
37106008Syy154373		arcmsr_report_ccb_state(acb, ccb, flag_ccb);
37116008Syy154373	}	/* drain reply FIFO */
37126008Syy154373}
37136008Syy154373
37146008Syy154373
37156008Syy154373/*
37166008Syy154373 *    Function: arcmsr_tran_start(9E)
37176008Syy154373 * Description: Transport the command in pktp to the target device.
37186008Syy154373 *		The command is not finished when this returns, only
37196008Syy154373 *		sent to the target; arcmsr_interrupt will call
37206008Syy154373 *		(*pktp->pkt_comp)(pktp) when the target device has done.
37216008Syy154373 *
37226008Syy154373 *       Input: struct scsi_address *ap, struct scsi_pkt *pktp
37236008Syy154373 *      Output:	TRAN_ACCEPT if pkt is OK and not driver not busy
37246008Syy154373 *		TRAN_BUSY if driver is
37256008Syy154373 *		TRAN_BADPKT if pkt is invalid
37266008Syy154373 */
37276008Syy154373static int
37286008Syy154373arcmsr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) {
37296008Syy154373
37306008Syy154373	struct ACB *acb;
37316008Syy154373	struct CCB *ccb;
37326008Syy154373	int target = ap->a_target;
37336008Syy154373	int lun = ap->a_lun;
37346008Syy154373
37356008Syy154373
37366008Syy154373	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
37376008Syy154373	ccb = pkt->pkt_ha_private;
37386008Syy154373
37396008Syy154373	if ((ccb->ccb_flags & CCB_FLAG_DMAVALID) &&
37406008Syy154373	    (ccb->ccb_flags & DDI_DMA_CONSISTENT))
37416008Syy154373		(void) ddi_dma_sync(ccb->pkt_dma_handle, ccb->pkt_dma_offset,
37426008Syy154373		    ccb->pkt_dma_len, DDI_DMA_SYNC_FORDEV);
37436008Syy154373
37446008Syy154373
37456008Syy154373	if (ccb->startdone == ARCMSR_CCB_UNBUILD)
37466008Syy154373		arcmsr_build_ccb(ccb);
37476008Syy154373
37486008Syy154373
37496008Syy154373	if (acb->acb_flags & ACB_F_BUS_RESET) {
37506008Syy154373		cmn_err(CE_CONT,
37516008Syy154373		    "arcmsr%d: bus reset returned busy",
37526008Syy154373		    ddi_get_instance(acb->dev_info));
37536008Syy154373		pkt->pkt_reason = CMD_RESET;
37546008Syy154373		pkt->pkt_statistics |= STAT_BUS_RESET;
37556008Syy154373		pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
37566008Syy154373		    STATE_SENT_CMD | STATE_GOT_STATUS);
37576008Syy154373		if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) &&
37586008Syy154373		    (pkt->pkt_state & STATE_XFERRED_DATA))
37596008Syy154373			(void) ddi_dma_sync(ccb->pkt_dma_handle,
37606008Syy154373			    ccb->pkt_dma_offset, ccb->pkt_dma_len,
37616008Syy154373			    DDI_DMA_SYNC_FORCPU);
37626008Syy154373
37636008Syy154373		scsi_hba_pkt_comp(pkt);
37646008Syy154373
37656008Syy154373		return (TRAN_ACCEPT);
37666008Syy154373	}
37676008Syy154373
37686008Syy154373	if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
37696008Syy154373		uint8_t block_cmd;
37706008Syy154373
37716008Syy154373		block_cmd = pkt->pkt_cdbp[0] & 0x0f;
37726008Syy154373
37736008Syy154373		if (block_cmd == 0x08 || block_cmd == 0x0a) {
37746008Syy154373			cmn_err(CE_CONT,
37756008Syy154373			    "arcmsr%d: block read/write command while raid"
37766008Syy154373			    "volume missing (cmd %02x for target %d lun %d)",
37776008Syy154373			    ddi_get_instance(acb->dev_info),
37786008Syy154373			    block_cmd, target, lun);
37796008Syy154373			pkt->pkt_reason = CMD_TIMEOUT;
37806008Syy154373			pkt->pkt_statistics |= CMD_TIMEOUT;
37816008Syy154373			pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET |
37826008Syy154373			    STATE_SENT_CMD | STATE_GOT_STATUS);
37836008Syy154373
37846008Syy154373			if ((ccb->ccb_flags & CCB_FLAG_DMACONSISTENT) &&
37856008Syy154373			    (pkt->pkt_state & STATE_XFERRED_DATA))
37866008Syy154373				(void) ddi_dma_sync(ccb->pkt_dma_handle,
37876008Syy154373				    ccb->pkt_dma_offset, ccb->pkt_dma_len,
37886008Syy154373				    DDI_DMA_SYNC_FORCPU);
37896008Syy154373
37906008Syy154373
37916008Syy154373			if (pkt->pkt_comp)
37926008Syy154373				(*pkt->pkt_comp)(pkt);
37936008Syy154373
37946008Syy154373
37956008Syy154373			return (TRAN_ACCEPT);
37966008Syy154373		}
37976008Syy154373	}
37986008Syy154373
37996008Syy154373
38006008Syy154373	/* IMPORTANT: Target 16 is a virtual device for iop message transfer */
38016008Syy154373	if (target == 16) {
38026008Syy154373
38036008Syy154373		struct buf *bp = ccb->bp;
38046008Syy154373		uint8_t scsicmd = pkt->pkt_cdbp[0];
38056008Syy154373
38066008Syy154373		switch (scsicmd) {
38076008Syy154373		case SCMD_INQUIRY: {
38086008Syy154373			if (lun != 0) {
38096008Syy154373				ccb->pkt->pkt_reason = CMD_TIMEOUT;
38106008Syy154373				ccb->pkt->pkt_statistics |= STAT_TIMEOUT;
38116008Syy154373				arcmsr_ccb_complete(ccb, 0);
38126008Syy154373				return (TRAN_ACCEPT);
38136008Syy154373			}
38146008Syy154373
38156008Syy154373			if (bp && bp->b_un.b_addr && bp->b_bcount) {
38166008Syy154373				uint8_t inqdata[36];
38176008Syy154373
38186008Syy154373				/* The EVDP and pagecode is not supported */
38196008Syy154373				if (pkt->pkt_cdbp[1] || pkt->pkt_cdbp[2]) {
38206008Syy154373					inqdata[1] = 0xFF;
38216008Syy154373					inqdata[2] = 0x00;
38226008Syy154373				} else {
38236008Syy154373					/* Periph Qualifier & Periph Dev Type */
38246008Syy154373					inqdata[0] = DTYPE_PROCESSOR;
38256008Syy154373					/* rem media bit & Dev Type Modifier */
38266008Syy154373					inqdata[1] = 0;
38276008Syy154373					/* ISO, ECMA, & ANSI versions */
38286008Syy154373					inqdata[2] = 0;
38296008Syy154373					/* length of additional data */
38306008Syy154373					inqdata[4] = 31;
38316008Syy154373					/* Vendor Identification */
38326008Syy154373					bcopy("Areca   ",
38336008Syy154373					    &inqdata[8], VIDLEN);
38346008Syy154373					/* Product Identification */
38356008Syy154373					bcopy("RAID controller ",
38366008Syy154373					    &inqdata[16], PIDLEN);
38376008Syy154373					/* Product Revision */
38386008Syy154373					bcopy(&inqdata[32],
38396008Syy154373					    "R001", REVLEN);
38406008Syy154373					if (bp->b_flags & (B_PHYS | B_PAGEIO))
38416008Syy154373						bp_mapin(bp);
38426008Syy154373
38436008Syy154373					(void) memcpy(bp->b_un.b_addr,
38446008Syy154373					    inqdata, sizeof (inqdata));
38456008Syy154373				}
38466008Syy154373				ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
38476008Syy154373			}
38486008Syy154373			arcmsr_ccb_complete(ccb, 0);
38496008Syy154373			return (TRAN_ACCEPT);
38506008Syy154373		}
38516008Syy154373		case SCMD_WRITE_BUFFER:
38526008Syy154373		case SCMD_READ_BUFFER: {
38536008Syy154373			if (arcmsr_iop_message_xfer(acb, pkt)) {
38546008Syy154373				/* error just for retry */
38556008Syy154373				ccb->pkt->pkt_reason = CMD_TRAN_ERR;
38566008Syy154373				ccb->pkt->pkt_statistics |= STAT_TERMINATED;
38576008Syy154373			}
38586008Syy154373			ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
38596008Syy154373			arcmsr_ccb_complete(ccb, 0);
38606008Syy154373			return (TRAN_ACCEPT);
38616008Syy154373		}
38626008Syy154373		default:
38636008Syy154373			ccb->pkt->pkt_state |= STATE_XFERRED_DATA;
38646008Syy154373			arcmsr_ccb_complete(ccb, 0);
38656008Syy154373			return (TRAN_ACCEPT);
38666008Syy154373		}
38676008Syy154373	}
38686008Syy154373
38696008Syy154373	if (acb->ccboutstandingcount >= ARCMSR_MAX_OUTSTANDING_CMD) {
38706008Syy154373		cmn_err(CE_CONT,
38716008Syy154373		    "arcmsr%d: too many outstanding commands (%d > %d)",
38726008Syy154373		    ddi_get_instance(acb->dev_info),
38736008Syy154373		    acb->ccboutstandingcount,
38746008Syy154373		    ARCMSR_MAX_OUTSTANDING_CMD);
38756008Syy154373		return (TRAN_BUSY);
38766008Syy154373	} else if (arcmsr_post_ccb(acb, ccb) == DDI_FAILURE) {
38776008Syy154373		cmn_err(CE_CONT,
38786008Syy154373		    "arcmsr%d: post failure, ccboutstandingcount = %d",
38796008Syy154373		    ddi_get_instance(acb->dev_info),
38806008Syy154373		    acb->ccboutstandingcount);
38816008Syy154373		return (TRAN_BUSY);
38826008Syy154373	}
38836008Syy154373
38846008Syy154373    return (TRAN_ACCEPT);
38856008Syy154373}
38866008Syy154373
38876008Syy154373/*
38886008Syy154373 * Function: arcmsr_tran_abort(9E)
38896008Syy154373 * 		SCSA interface routine to abort pkt(s) in progress.
38906008Syy154373 * 		Aborts the pkt specified.  If NULL pkt, aborts ALL pkts.
38916008Syy154373 * Output:	Return 1 if success
38926008Syy154373 *		Return 0 if failure
38936008Syy154373 */
38946008Syy154373static int
38956008Syy154373arcmsr_tran_abort(struct scsi_address *ap, struct scsi_pkt *abortpkt) {
38966008Syy154373
38976008Syy154373	struct ACB *acb;
38986008Syy154373	int return_code;
38996008Syy154373
39006008Syy154373	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
39016008Syy154373
39026008Syy154373
39036008Syy154373	cmn_err(CE_WARN,
39046008Syy154373	    "arcmsr%d: tran_abort called for target %d lun %d",
39056008Syy154373	    ddi_get_instance(acb->dev_info), ap->a_target, ap->a_lun);
39066008Syy154373
39076008Syy154373	while (acb->ccboutstandingcount != 0) {
39086008Syy154373		drv_usecwait(10000);
39096008Syy154373	}
39106008Syy154373
39116008Syy154373	mutex_enter(&acb->acb_mutex);
39126008Syy154373	return_code = arcmsr_seek_cmd2abort(acb, abortpkt);
39136008Syy154373	mutex_exit(&acb->acb_mutex);
39146008Syy154373
39156008Syy154373	if (return_code != DDI_SUCCESS) {
39166008Syy154373		cmn_err(CE_WARN,
39176008Syy154373		    "arcmsr%d: abort command failed for target %d lun %d",
39186008Syy154373		    ddi_get_instance(acb->dev_info),
39196008Syy154373		    ap->a_target, ap->a_lun);
39206008Syy154373		return (0);
39216008Syy154373	}
39226008Syy154373
39236008Syy154373	return (1);
39246008Syy154373}
39256008Syy154373
39266008Syy154373
39276008Syy154373/*
39286008Syy154373 * Function: arcmsr_tran_reset(9E)
39296008Syy154373 *           SCSA interface routine to perform scsi resets on either
39306008Syy154373 *           a specified target or the bus (default).
39316008Syy154373 *   Output: Return 1 if success
39326008Syy154373 *	     Return 0 if failure
39336008Syy154373 */
39346008Syy154373static int
39356008Syy154373arcmsr_tran_reset(struct scsi_address *ap, int level) {
39366008Syy154373
39376008Syy154373	struct ACB *acb;
39386008Syy154373	int return_code = 1;
39396008Syy154373	int retry = 0;
39406008Syy154373
39416008Syy154373
39426008Syy154373	/* Are we in the middle of dumping core? */
39436008Syy154373	if (ddi_in_panic())
39446008Syy154373		return (return_code);
39456008Syy154373
39466008Syy154373	acb = (struct ACB *)ap->a_hba_tran->tran_hba_private;
39476008Syy154373
39486008Syy154373	cmn_err(CE_WARN, "arcmsr%d: tran reset (level 0x%x) called "
39496008Syy154373	    "for target %d lun %d",
39506008Syy154373	    ddi_get_instance(acb->dev_info), level,
39516008Syy154373	    ap->a_target, ap->a_lun);
39526008Syy154373	mutex_enter(&acb->acb_mutex);
39536008Syy154373
39546008Syy154373	while ((acb->ccboutstandingcount > 0) && (retry < 400)) {
39556008Syy154373		(void) arcmsr_interrupt((caddr_t)acb);
39566008Syy154373		drv_usecwait(25000);
39576008Syy154373		retry++;
39586008Syy154373	}
39596008Syy154373
39606008Syy154373	switch (level) {
39616008Syy154373	case RESET_ALL:		/* level 1 */
39626008Syy154373		acb->num_resets++;
39636008Syy154373		acb->acb_flags |= ACB_F_BUS_RESET;
39646008Syy154373		if (acb->timeout_count)
39656008Syy154373			arcmsr_iop_reset(acb);
39666008Syy154373		acb->acb_flags &= ~ACB_F_BUS_RESET;
39676008Syy154373		return_code = 0;
39686008Syy154373		break;
39696008Syy154373	case RESET_TARGET:	/* level 0 */
39706008Syy154373		cmn_err(CE_WARN, "arcmsr%d: target reset not supported",
39716008Syy154373		    ddi_get_instance(acb->dev_info));
39726008Syy154373		return_code = 0;
39736008Syy154373		break;
39746008Syy154373	default:
39756008Syy154373		return_code = 0;
39766008Syy154373	}
39776008Syy154373
39786008Syy154373	mutex_exit(&acb->acb_mutex);
39796008Syy154373	return (return_code);
39806008Syy154373}
39816008Syy154373
39826008Syy154373
39836008Syy154373static void
39846008Syy154373arcmsr_log(struct ACB *acb, int level, char *fmt, ...) {
39856008Syy154373
39866008Syy154373	char	buf[256];
39876008Syy154373	va_list ap;
39886008Syy154373
39896008Syy154373	va_start(ap, fmt);
39906008Syy154373	(void) vsprintf(buf, fmt, ap);
39916008Syy154373	va_end(ap);
39926008Syy154373	scsi_log(acb ? acb->dev_info : NULL, "arcmsr", level, "%s", buf);
39936008Syy154373}
39946008Syy154373
39956008Syy154373
39966008Syy154373static void
39976008Syy154373arcmsr_iop2drv_data_wrote_handle(struct ACB *acb) {
39986008Syy154373
39996008Syy154373	struct QBUFFER *prbuffer;
40006008Syy154373	uint8_t *pQbuffer;
40016008Syy154373	uint8_t *iop_data;
40026008Syy154373	int my_empty_len, iop_len;
40036008Syy154373	int rqbuf_firstidx, rqbuf_lastidx;
40046008Syy154373
40056008Syy154373	/* check this iop data if overflow my rqbuffer */
40066008Syy154373	rqbuf_lastidx = acb->rqbuf_lastidx;
40076008Syy154373	rqbuf_firstidx = acb->rqbuf_firstidx;
40086008Syy154373	prbuffer = arcmsr_get_iop_rqbuffer(acb);
40096008Syy154373	iop_data = (uint8_t *)prbuffer->data;
40106008Syy154373	iop_len = prbuffer->data_len;
40116008Syy154373	my_empty_len = (rqbuf_firstidx-rqbuf_lastidx - 1) &
40126008Syy154373	    (ARCMSR_MAX_QBUFFER - 1);
40136008Syy154373
40146008Syy154373	if (my_empty_len >= iop_len) {
40156008Syy154373		while (iop_len > 0) {
40166008Syy154373			pQbuffer = &acb->rqbuffer[rqbuf_lastidx];
40176008Syy154373			(void) memcpy(pQbuffer, iop_data, 1);
40186008Syy154373			rqbuf_lastidx++;
40196008Syy154373			/* if last index number set it to 0 */
40206008Syy154373			rqbuf_lastidx %= ARCMSR_MAX_QBUFFER;
40216008Syy154373			iop_data++;
40226008Syy154373			iop_len--;
40236008Syy154373		}
40246008Syy154373		acb->rqbuf_lastidx = rqbuf_lastidx;
40256008Syy154373		arcmsr_iop_message_read(acb);
40266008Syy154373		/* signature, let IOP know data has been read */
40276008Syy154373	} else {
40286008Syy154373		acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
40296008Syy154373	}
40306008Syy154373}
40316008Syy154373
40326008Syy154373
40336008Syy154373
40346008Syy154373static void
40356008Syy154373arcmsr_iop2drv_data_read_handle(struct ACB *acb) {
40366008Syy154373
40376008Syy154373	acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READ;
40386008Syy154373	/*
40396008Syy154373	 * check if there are any mail packages from user space program
40406008Syy154373	 * in my post bag, now is the time to send them into Areca's firmware
40416008Syy154373	 */
40426008Syy154373
40436008Syy154373	if (acb->wqbuf_firstidx != acb->wqbuf_lastidx) {
40446008Syy154373
40456008Syy154373		uint8_t *pQbuffer;
40466008Syy154373		struct QBUFFER *pwbuffer;
40476008Syy154373		uint8_t *iop_data;
40486008Syy154373		int allxfer_len = 0;
40496008Syy154373
40506008Syy154373		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READ);
40516008Syy154373		pwbuffer = arcmsr_get_iop_wqbuffer(acb);
40526008Syy154373		iop_data = (uint8_t *)pwbuffer->data;
40536008Syy154373
40546008Syy154373		while ((acb->wqbuf_firstidx != acb->wqbuf_lastidx) &&
40556008Syy154373		    (allxfer_len < 124)) {
40566008Syy154373			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstidx];
40576008Syy154373			(void) memcpy(iop_data, pQbuffer, 1);
40586008Syy154373			acb->wqbuf_firstidx++;
40596008Syy154373			/* if last index number set it to 0 */
40606008Syy154373			acb->wqbuf_firstidx %= ARCMSR_MAX_QBUFFER;
40616008Syy154373			iop_data++;
40626008Syy154373			allxfer_len++;
40636008Syy154373		}
40646008Syy154373		pwbuffer->data_len = allxfer_len;
40656008Syy154373		/*
40666008Syy154373		 * push inbound doorbell, tell iop driver data write ok
40676008Syy154373		 * await reply on next hwinterrupt for next Qbuffer post
40686008Syy154373		 */
40696008Syy154373		arcmsr_iop_message_wrote(acb);
40706008Syy154373	}
40716008Syy154373
40726008Syy154373	if (acb->wqbuf_firstidx == acb->wqbuf_lastidx)
40736008Syy154373		acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
40746008Syy154373}
40756008Syy154373
40766008Syy154373
40776008Syy154373static void
40786008Syy154373arcmsr_hba_doorbell_isr(struct ACB *acb) {
40796008Syy154373
40806008Syy154373	uint32_t outbound_doorbell;
40816008Syy154373	struct HBA_msgUnit *phbamu;
40826008Syy154373
40836008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
40846008Syy154373
40856008Syy154373	/*
40866008Syy154373	 *  Maybe here we need to check wrqbuffer_lock is locked or not
40876008Syy154373	 *  DOORBELL: ding! dong!
40886008Syy154373	 *  check if there are any mail need to pack from firmware
40896008Syy154373	 */
40906008Syy154373
40916008Syy154373	outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
40926008Syy154373	    &phbamu->outbound_doorbell);
40936008Syy154373	/* clear doorbell interrupt */
40946008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
40956008Syy154373	    &phbamu->outbound_doorbell, outbound_doorbell);
40966008Syy154373
40976008Syy154373	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK)
40986008Syy154373		arcmsr_iop2drv_data_wrote_handle(acb);
40996008Syy154373
41006008Syy154373
41016008Syy154373	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)
41026008Syy154373		arcmsr_iop2drv_data_read_handle(acb);
41036008Syy154373}
41046008Syy154373
41056008Syy154373
41066008Syy154373
41076008Syy154373static void
41086008Syy154373arcmsr_hba_postqueue_isr(struct ACB *acb) {
41096008Syy154373
41106008Syy154373	uint32_t flag_ccb;
41116008Syy154373	struct HBA_msgUnit *phbamu;
41126008Syy154373
41136008Syy154373
41146008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
41156008Syy154373
41166008Syy154373	/* areca cdb command done */
41176008Syy154373	/* Use correct offset and size for syncing */
41186008Syy154373	(void) ddi_dma_sync(acb->ccbs_pool_handle, 0, acb->dma_sync_size,
41196008Syy154373	    DDI_DMA_SYNC_FORKERNEL);
41206008Syy154373
41216008Syy154373	while ((flag_ccb = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
41226008Syy154373	    &phbamu->outbound_queueport)) != 0xFFFFFFFF) {
41236008Syy154373		/* check if command done with no error */
41246008Syy154373		arcmsr_drain_donequeue(acb, flag_ccb);
41256008Syy154373	}	/* drain reply FIFO */
41266008Syy154373}
41276008Syy154373
41286008Syy154373static void arcmsr_dr_handle(struct ACB *acb)
41296008Syy154373{
41306008Syy154373	char *acb_dev_map = (char *)acb->device_map;
41316008Syy154373	char *devicemap;
41326008Syy154373	int target, lun;
41336008Syy154373	char diff;
41346008Syy154373	int circ1;
41356008Syy154373	dev_info_t *dip;
41366008Syy154373	ddi_acc_handle_t reg;
41376008Syy154373	switch (acb->adapter_type) {
41386008Syy154373	case ACB_ADAPTER_TYPE_A:
41396008Syy154373		{
41406008Syy154373			struct HBA_msgUnit *phbamu = (struct HBA_msgUnit *)
41416008Syy154373			    acb->pmu;
41426008Syy154373			devicemap = (char *)&phbamu->msgcode_rwbuffer[21];
41436008Syy154373			reg = acb->reg_mu_acc_handle0;
41446008Syy154373		}
41456008Syy154373		break;
41466008Syy154373	case ACB_ADAPTER_TYPE_B:
41476008Syy154373		{
41486008Syy154373			struct HBB_msgUnit *phbbmu = (struct HBB_msgUnit *)
41496008Syy154373			    acb->pmu;
41506008Syy154373			devicemap = (char *)
41516008Syy154373			    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[21];
41526008Syy154373			reg = acb->reg_mu_acc_handle1;
41536008Syy154373		}
41546008Syy154373		break;
41556008Syy154373	}
41566008Syy154373
41576008Syy154373	for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
41586008Syy154373		diff =
41596008Syy154373		    (*acb_dev_map)^CHIP_REG_READ8(reg, devicemap);
41606008Syy154373		if (diff != 0) {
41616008Syy154373			char temp;
41626008Syy154373			*acb_dev_map =
41636008Syy154373			    CHIP_REG_READ8(reg, devicemap);
41646008Syy154373			temp = *acb_dev_map;
41656008Syy154373			for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
41666008Syy154373				if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
41676008Syy154373					ndi_devi_enter(acb->dev_info, &circ1);
41686008Syy154373					(void) arcmsr_config_lun(acb, target,
41696008Syy154373					    lun, NULL);
41706008Syy154373					ndi_devi_exit(acb->dev_info, circ1);
41716008Syy154373				} else if ((temp & 0x01) == 0 && (diff & 0x01)
41726008Syy154373				    == 1) {
41736008Syy154373					dip = arcmsr_find_child(acb, target,
41746008Syy154373					    lun);
41756008Syy154373					if (dip != NULL) {
41766008Syy154373						(void) ndi_devi_offline(dip,
41776008Syy154373						    NDI_DEVI_REMOVE);
41786008Syy154373						cmn_err(CE_NOTE, "arcmsr%d: "
41796008Syy154373						    "T%dL%d offlined",
41806008Syy154373						    ddi_get_instance
41816008Syy154373						    (acb->dev_info), target,
41826008Syy154373						    lun);
41836008Syy154373					}
41846008Syy154373				}
41856008Syy154373				temp >>= 1;
41866008Syy154373				diff >>= 1;
41876008Syy154373			}
41886008Syy154373		}
41896008Syy154373		devicemap++;
41906008Syy154373		acb_dev_map++;
41916008Syy154373	}
41926008Syy154373}
41936008Syy154373
41946008Syy154373static void arcmsr_hba_message_isr(struct ACB *acb)
41956008Syy154373{
41966008Syy154373	struct HBA_msgUnit *phbamu = (struct HBA_msgUnit *)acb->pmu;
41976008Syy154373	uint32_t  *signature = (&phbamu->msgcode_rwbuffer[0]);
41986008Syy154373	uint32_t outbound_message;
41996008Syy154373
42006008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus,
42016008Syy154373	    ARCMSR_MU_OUTBOUND_MESSAGE0_INT);
42026008Syy154373
42036008Syy154373	outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
42046008Syy154373	    signature);
42056008Syy154373	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
42066008Syy154373		if ((ddi_taskq_dispatch(acb->taskq, (void (*)(void *))
42076008Syy154373		    arcmsr_dr_handle, acb, DDI_NOSLEEP)) != DDI_SUCCESS)
42086008Syy154373			cmn_err(CE_WARN, "DR task start failed");
42096008Syy154373}
42106008Syy154373
42116008Syy154373static void arcmsr_hbb_message_isr(struct ACB *acb)
42126008Syy154373{
42136008Syy154373	struct HBB_msgUnit *phbbmu = (struct HBB_msgUnit *)acb->pmu;
42146008Syy154373	uint32_t  *signature = (&phbbmu->hbb_rwbuffer->msgcode_rwbuffer[0]);
42156008Syy154373	uint32_t outbound_message;
42166008Syy154373
42176008Syy154373	/* clear interrupts */
42186008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
42196008Syy154373	    &phbbmu->hbb_doorbell->iop2drv_doorbell,
42206008Syy154373	    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
42216008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
42226008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
42236008Syy154373	    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
42246008Syy154373
42256008Syy154373	outbound_message = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
42266008Syy154373	    signature);
42276008Syy154373	if (outbound_message == ARCMSR_SIGNATURE_GET_CONFIG)
42286008Syy154373		if ((ddi_taskq_dispatch(acb->taskq,
42296008Syy154373		    (void (*)(void *))arcmsr_dr_handle, acb,
42306008Syy154373		    DDI_NOSLEEP)) != DDI_SUCCESS) {
42316008Syy154373			cmn_err(CE_WARN, "DR task start failed");
42326008Syy154373		}
42336008Syy154373}
42346008Syy154373
42356008Syy154373static void
42366008Syy154373arcmsr_hbb_postqueue_isr(struct ACB *acb) {
42376008Syy154373
42386008Syy154373	int index;
42396008Syy154373	uint32_t flag_ccb;
42406008Syy154373	struct HBB_msgUnit *phbbmu;
42416008Syy154373
42426008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
42436008Syy154373
42446008Syy154373
42456008Syy154373	/* areca cdb command done */
42466008Syy154373	index = phbbmu->doneq_index;
42476008Syy154373
42486008Syy154373	while ((flag_ccb = phbbmu->done_qbuffer[index]) != 0) {
42496008Syy154373		phbbmu->done_qbuffer[index] = 0;
42506008Syy154373		index++;
42516008Syy154373		/* if last index number set it to 0 */
42526008Syy154373		index %= ARCMSR_MAX_HBB_POSTQUEUE;
42536008Syy154373		phbbmu->doneq_index = index;
42546008Syy154373		/* check if command done with no error */
42556008Syy154373		arcmsr_drain_donequeue(acb, flag_ccb);
42566008Syy154373	}	/* drain reply FIFO */
42576008Syy154373}
42586008Syy154373
42596008Syy154373
42606008Syy154373
42616008Syy154373
42626008Syy154373
42636008Syy154373static uint_t
42646008Syy154373arcmsr_handle_hba_isr(struct ACB *acb) {
42656008Syy154373
42666008Syy154373	uint32_t outbound_intstatus;
42676008Syy154373	struct HBA_msgUnit *phbamu;
42686008Syy154373
42696008Syy154373	phbamu = (struct HBA_msgUnit *)acb->pmu;
42706008Syy154373
42716008Syy154373	outbound_intstatus = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
42726008Syy154373	    &phbamu->outbound_intstatus) & acb->outbound_int_enable;
42736008Syy154373
42746008Syy154373	if (!outbound_intstatus)
42756008Syy154373		/* it must be a shared irq */
42766008Syy154373		return (DDI_INTR_UNCLAIMED);
42776008Syy154373
42786008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0, &phbamu->outbound_intstatus,
42796008Syy154373	    outbound_intstatus); /* clear interrupt */
42806008Syy154373
42816008Syy154373
42826008Syy154373	/* MU doorbell interrupts */
42836008Syy154373
42846008Syy154373	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
42856008Syy154373		arcmsr_hba_doorbell_isr(acb);
42866008Syy154373
42876008Syy154373	/* MU post queue interrupts */
42886008Syy154373	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
42896008Syy154373		arcmsr_hba_postqueue_isr(acb);
42906008Syy154373
42916008Syy154373	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
42926008Syy154373		arcmsr_hba_message_isr(acb);
42936008Syy154373	}
42946008Syy154373
42956008Syy154373	return (DDI_INTR_CLAIMED);
42966008Syy154373}
42976008Syy154373
42986008Syy154373
42996008Syy154373static uint_t
43006008Syy154373arcmsr_handle_hbb_isr(struct ACB *acb) {
43016008Syy154373
43026008Syy154373	uint32_t outbound_doorbell;
43036008Syy154373	struct HBB_msgUnit *phbbmu;
43046008Syy154373
43056008Syy154373
43066008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
43076008Syy154373
43086008Syy154373	outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
43096008Syy154373	    &phbbmu->hbb_doorbell->iop2drv_doorbell) & acb->outbound_int_enable;
43106008Syy154373
43116008Syy154373	if (!outbound_doorbell)
43126008Syy154373		/* it must be a shared irq */
43136008Syy154373		return (DDI_INTR_UNCLAIMED);
43146008Syy154373
43156008Syy154373	/* clear doorbell interrupt */
43166008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
43176008Syy154373	    &phbbmu->hbb_doorbell->iop2drv_doorbell, ~outbound_doorbell);
43186008Syy154373	/* wait a cycle */
43196008Syy154373	(void) CHIP_REG_READ32(acb->reg_mu_acc_handle0,
43206008Syy154373	    &phbbmu->hbb_doorbell->iop2drv_doorbell);
43216008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
43226008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
43236008Syy154373	    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
43246008Syy154373
43256008Syy154373	/* MU ioctl transfer doorbell interrupts */
43266008Syy154373	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
43276008Syy154373		arcmsr_iop2drv_data_wrote_handle(acb);
43286008Syy154373
43296008Syy154373	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
43306008Syy154373		arcmsr_iop2drv_data_read_handle(acb);
43316008Syy154373
43326008Syy154373	/* MU post queue interrupts */
43336008Syy154373	if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
43346008Syy154373		arcmsr_hbb_postqueue_isr(acb);
43356008Syy154373
43366008Syy154373	/* MU message interrupt */
43376008Syy154373
43386008Syy154373	if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
43396008Syy154373		arcmsr_hbb_message_isr(acb);
43406008Syy154373	}
43416008Syy154373
43426008Syy154373	return (DDI_INTR_CLAIMED);
43436008Syy154373}
43446008Syy154373
43456008Syy154373
43466008Syy154373static uint_t
43476008Syy154373arcmsr_interrupt(caddr_t arg) {
43486008Syy154373
43496008Syy154373
43506008Syy154373	struct ACB *acb = (struct ACB *)(intptr_t)arg;
43516008Syy154373
43526008Syy154373	switch (acb->adapter_type) {
43536008Syy154373	case ACB_ADAPTER_TYPE_A:
43546008Syy154373		return (arcmsr_handle_hba_isr(acb));
43556008Syy154373	case ACB_ADAPTER_TYPE_B:
43566008Syy154373		return (arcmsr_handle_hbb_isr(acb));
43576008Syy154373	default:
43586008Syy154373		cmn_err(CE_WARN, "arcmsr%d: unknown adapter type (%d)",
43596008Syy154373		    ddi_get_instance(acb->dev_info), acb->adapter_type);
43606008Syy154373		return (DDI_INTR_UNCLAIMED);
43616008Syy154373	}
43626008Syy154373}
43636008Syy154373
43646008Syy154373
43656008Syy154373static void
43666008Syy154373arcmsr_wait_firmware_ready(struct ACB *acb) {
43676008Syy154373
43686008Syy154373	uint32_t firmware_state;
43696008Syy154373
43706008Syy154373	firmware_state = 0;
43716008Syy154373
43726008Syy154373	switch (acb->adapter_type) {
43736008Syy154373	case ACB_ADAPTER_TYPE_A:
43746008Syy154373	{
43756008Syy154373		struct HBA_msgUnit *phbamu;
43766008Syy154373
43776008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
43786008Syy154373		do {
43796008Syy154373			firmware_state =
43806008Syy154373			    CHIP_REG_READ32(acb->reg_mu_acc_handle0,
43816008Syy154373			    &phbamu->outbound_msgaddr1);
43826008Syy154373		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)
43836008Syy154373		    == 0);
43846008Syy154373	}
43856008Syy154373	break;
43866008Syy154373	case ACB_ADAPTER_TYPE_B:
43876008Syy154373	{
43886008Syy154373		struct HBB_msgUnit *phbbmu;
43896008Syy154373
43906008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
43916008Syy154373		do {
43926008Syy154373			firmware_state =
43936008Syy154373			    CHIP_REG_READ32(acb->reg_mu_acc_handle0,
43946008Syy154373				    &phbbmu->hbb_doorbell->iop2drv_doorbell);
43956008Syy154373		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
43966008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
43976008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
43986008Syy154373		    ARCMSR_DRV2IOP_END_OF_INTERRUPT);
43996008Syy154373	}
44006008Syy154373	break;
44016008Syy154373	}
44026008Syy154373}
44036008Syy154373
44046008Syy154373static void
44056008Syy154373arcmsr_clear_doorbell_queue_buffer(struct ACB *acb) {
44066008Syy154373
44076008Syy154373	switch (acb->adapter_type) {
44086008Syy154373	case ACB_ADAPTER_TYPE_A:
44096008Syy154373	{
44106008Syy154373		struct HBA_msgUnit *phbamu;
44116008Syy154373		uint32_t outbound_doorbell;
44126008Syy154373
44136008Syy154373		phbamu = (struct HBA_msgUnit *)acb->pmu;
44146008Syy154373		/* empty doorbell Qbuffer if door bell rung */
44156008Syy154373		outbound_doorbell = CHIP_REG_READ32(acb->reg_mu_acc_handle0,
44166008Syy154373		    &phbamu->outbound_doorbell);
44176008Syy154373		/* clear doorbell interrupt */
44186008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44196008Syy154373		    &phbamu->outbound_doorbell, outbound_doorbell);
44206008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44216008Syy154373		    &phbamu->inbound_doorbell,
44226008Syy154373		    ARCMSR_INBOUND_DRIVER_DATA_READ_OK);
44236008Syy154373	}
44246008Syy154373	break;
44256008Syy154373	case ACB_ADAPTER_TYPE_B:
44266008Syy154373	{
44276008Syy154373		struct HBB_msgUnit *phbbmu;
44286008Syy154373
44296008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
44306008Syy154373
44316008Syy154373		/* clear interrupt and message state */
44326008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44336008Syy154373		    &phbbmu->hbb_doorbell->iop2drv_doorbell,
44346008Syy154373		    ARCMSR_MESSAGE_INT_CLEAR_PATTERN);
44356008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44366008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
44376008Syy154373		    ARCMSR_DRV2IOP_DATA_READ_OK);
44386008Syy154373		/* let IOP know data has been read */
44396008Syy154373	}
44406008Syy154373	break;
44416008Syy154373	}
44426008Syy154373}
44436008Syy154373
44446008Syy154373
44456008Syy154373static uint32_t
44466008Syy154373arcmsr_iop_confirm(struct ACB *acb) {
44476008Syy154373
44486008Syy154373	unsigned long ccb_phyaddr;
44496008Syy154373	uint32_t ccb_phyaddr_hi32;
44506008Syy154373
44516008Syy154373	/*
44526008Syy154373	 * here we need to tell iop 331 about our freeccb.HighPart
44536008Syy154373	 * if freeccb.HighPart is non-zero
44546008Syy154373	 */
44556008Syy154373	ccb_phyaddr = (unsigned long)acb->ccb_cookie.dmac_address;
44566008Syy154373	ccb_phyaddr_hi32 = (uint32_t)((ccb_phyaddr >> 16) >> 16);
44576008Syy154373
44586008Syy154373	switch (acb->adapter_type) {
44596008Syy154373	case ACB_ADAPTER_TYPE_A:
44606008Syy154373	{
44616008Syy154373		if (ccb_phyaddr_hi32 != 0) {
44626008Syy154373			struct HBA_msgUnit *phbamu;
44636008Syy154373
44646008Syy154373			phbamu = (struct HBA_msgUnit *)acb->pmu;
44656008Syy154373			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44666008Syy154373			    &phbamu->msgcode_rwbuffer[0],
44676008Syy154373			    ARCMSR_SIGNATURE_SET_CONFIG);
44686008Syy154373			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44696008Syy154373			    &phbamu->msgcode_rwbuffer[1], ccb_phyaddr_hi32);
44706008Syy154373			CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44716008Syy154373			    &phbamu->inbound_msgaddr0,
44726008Syy154373			    ARCMSR_INBOUND_MESG0_SET_CONFIG);
44736008Syy154373			if (!arcmsr_hba_wait_msgint_ready(acb)) {
44746008Syy154373				cmn_err(CE_WARN,
44756008Syy154373				    "arcmsr%d: timeout setting ccb high "
44766008Syy154373				    "physical address",
44776008Syy154373				    ddi_get_instance(acb->dev_info));
44786008Syy154373				return (FALSE);
44796008Syy154373			}
44806008Syy154373		}
44816008Syy154373	}
44826008Syy154373	break;
44836008Syy154373
44846008Syy154373	/* if adapter is type B, set window of "post command queue" */
44856008Syy154373
44866008Syy154373	case ACB_ADAPTER_TYPE_B:
44876008Syy154373	{
44886008Syy154373		uint32_t post_queue_phyaddr;
44896008Syy154373		struct HBB_msgUnit *phbbmu;
44906008Syy154373
44916008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
44926008Syy154373		phbbmu->postq_index = 0;
44936008Syy154373		phbbmu->doneq_index = 0;
44946008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
44956008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
44966008Syy154373		    ARCMSR_MESSAGE_SET_POST_WINDOW);
44976008Syy154373
44986008Syy154373		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
44996008Syy154373			cmn_err(CE_WARN,
45006008Syy154373			    "arcmsr%d: timeout setting post command "
45016008Syy154373			    "queue window",
45026008Syy154373			    ddi_get_instance(acb->dev_info));
45036008Syy154373			return (FALSE);
45046008Syy154373		}
45056008Syy154373
45066008Syy154373		post_queue_phyaddr = ccb_phyaddr +
45076008Syy154373		    ARCMSR_MAX_FREECCB_NUM *
45086008Syy154373		    sizeof (struct CCB)
45096008Syy154373		    + ARCOFFSET(struct HBB_msgUnit, post_qbuffer);
45106008Syy154373		/* driver "set config" signature */
45116008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
45126008Syy154373		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[0],
45136008Syy154373		    ARCMSR_SIGNATURE_SET_CONFIG);
45146008Syy154373		/* normal should be zero */
45156008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
45166008Syy154373		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[1],
45176008Syy154373		    ccb_phyaddr_hi32);
45186008Syy154373		/* postQ size (256+8)*4 */
45196008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
45206008Syy154373		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[2],
45216008Syy154373		    post_queue_phyaddr);
45226008Syy154373		/* doneQ size (256+8)*4 */
45236008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
45246008Syy154373		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[3],
45256008Syy154373		    post_queue_phyaddr+1056);
45266008Syy154373		/* ccb maxQ size must be --> [(256+8)*4] */
45276008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle1,
45286008Syy154373		    &phbbmu->hbb_rwbuffer->msgcode_rwbuffer[4], 1056);
45296008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
45306008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
45316008Syy154373		    ARCMSR_MESSAGE_SET_CONFIG);
45326008Syy154373
45336008Syy154373		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
45346008Syy154373			cmn_err(CE_WARN,
45356008Syy154373			    "arcmsr%d: timeout setting command queue window",
45366008Syy154373			    ddi_get_instance(acb->dev_info));
45376008Syy154373			return (FALSE);
45386008Syy154373		}
45396008Syy154373		CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
45406008Syy154373		    &phbbmu->hbb_doorbell->drv2iop_doorbell,
45416008Syy154373		    ARCMSR_MESSAGE_START_DRIVER_MODE);
45426008Syy154373
45436008Syy154373		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
45446008Syy154373			cmn_err(CE_WARN,
45456008Syy154373			    "arcmsr%d: timeout in 'start driver mode'",
45466008Syy154373			    ddi_get_instance(acb->dev_info));
45476008Syy154373			return (FALSE);
45486008Syy154373		}
45496008Syy154373	}
45506008Syy154373	break;
45516008Syy154373	}
45526008Syy154373	return (TRUE);
45536008Syy154373}
45546008Syy154373
45556008Syy154373
45566008Syy154373/*
45576008Syy154373 * ONLY used for Adapter type B
45586008Syy154373 */
45596008Syy154373static void
45606008Syy154373arcmsr_enable_eoi_mode(struct ACB *acb) {
45616008Syy154373
45626008Syy154373	struct HBB_msgUnit *phbbmu;
45636008Syy154373
45646008Syy154373	phbbmu = (struct HBB_msgUnit *)acb->pmu;
45656008Syy154373
45666008Syy154373	CHIP_REG_WRITE32(acb->reg_mu_acc_handle0,
45676008Syy154373	    &phbbmu->hbb_doorbell->drv2iop_doorbell,
45686008Syy154373	    ARCMSR_MESSAGE_ACTIVE_EOI_MODE);
45696008Syy154373
45706008Syy154373	if (!arcmsr_hbb_wait_msgint_ready(acb))
45716008Syy154373		cmn_err(CE_WARN,
45726008Syy154373		    "arcmsr%d (Adapter type B): "
45736008Syy154373		    "'iop enable eoi mode' timeout ",
45746008Syy154373		    ddi_get_instance(acb->dev_info));
45756008Syy154373
45766008Syy154373}
45776008Syy154373
45786008Syy154373/* start background rebuild */
45796008Syy154373static void
45806008Syy154373arcmsr_iop_init(struct ACB *acb) {
45816008Syy154373
45826008Syy154373	uint32_t intmask_org;
45836008Syy154373
45846008Syy154373	/* disable all outbound interrupt */
45856008Syy154373	intmask_org = arcmsr_disable_allintr(acb);
45866008Syy154373	arcmsr_wait_firmware_ready(acb);
45876008Syy154373	(void) arcmsr_iop_confirm(acb);
45886008Syy154373
45896008Syy154373	/* start background rebuild */
45906008Syy154373	if (acb->adapter_type == ACB_ADAPTER_TYPE_A) {
45916008Syy154373		arcmsr_get_hba_config(acb);
45926008Syy154373		arcmsr_start_hba_bgrb(acb);
45936008Syy154373	} else {
45946008Syy154373		arcmsr_get_hbb_config(acb);
45956008Syy154373		arcmsr_start_hbb_bgrb(acb);
45966008Syy154373	}
45976008Syy154373
45986008Syy154373	/* empty doorbell Qbuffer if door bell rang */
45996008Syy154373	arcmsr_clear_doorbell_queue_buffer(acb);
46006008Syy154373
46016008Syy154373	if (acb->adapter_type == ACB_ADAPTER_TYPE_B)
46026008Syy154373		arcmsr_enable_eoi_mode(acb);
46036008Syy154373
46046008Syy154373	/* enable outbound Post Queue, outbound doorbell Interrupt */
46056008Syy154373	arcmsr_enable_allintr(acb, intmask_org);
46066008Syy154373	acb->acb_flags |= ACB_F_IOP_INITED;
46076008Syy154373}
46086008Syy154373
46096008Syy154373
46106008Syy154373static int
46116008Syy154373arcmsr_initialize(struct ACB *acb) {
46126008Syy154373
46136008Syy154373	struct CCB *pccb_tmp;
46146008Syy154373	size_t allocated_length;
46156008Syy154373	uint16_t wval;
46166008Syy154373	uint32_t wlval;
46176008Syy154373	uint_t intmask_org, count;
46186008Syy154373	caddr_t	arcmsr_ccbs_area;
46196008Syy154373	unsigned long ccb_phyaddr;
46206008Syy154373	int32_t dma_sync_size;
46216008Syy154373	int i, id, lun;
46226008Syy154373
46236008Syy154373	acb->irq = pci_config_get8(acb->pci_acc_handle,
46246008Syy154373	    ARCMSR_PCI2PCI_PRIMARY_INTERRUPT_LINE_REG);
46256008Syy154373	wlval = pci_config_get32(acb->pci_acc_handle, 0);
46266008Syy154373	wval = (uint16_t)((wlval >> 16) & 0xffff);
46276008Syy154373
46286008Syy154373	if (wval == PCI_DEVICE_ID_ARECA_1201) {
46296008Syy154373		uint32_t *iop_mu_regs_map0;
46306008Syy154373		uint32_t *iop_mu_regs_map1;
46316008Syy154373		struct CCB *freeccb;
46326008Syy154373		struct HBB_msgUnit *phbbmu;
46336008Syy154373
46346008Syy154373		acb->adapter_type = ACB_ADAPTER_TYPE_B; /* marvell */
46356008Syy154373		dma_sync_size = (ARCMSR_MAX_FREECCB_NUM*
46366008Syy154373		    sizeof (struct CCB) + 0x20) +
46376008Syy154373		    sizeof (struct HBB_msgUnit);
46386008Syy154373
46396008Syy154373
46406008Syy154373		/* Allocate memory for the ccb */
46416008Syy154373		if ((i = ddi_dma_alloc_handle(acb->dev_info,
46426008Syy154373		    &arcmsr_ccb_attr, DDI_DMA_SLEEP, NULL,
46436008Syy154373		    &acb->ccbs_pool_handle)) != DDI_SUCCESS) {
46446008Syy154373			switch (i) {
46456008Syy154373			case DDI_DMA_BADATTR:
46466008Syy154373				cmn_err(CE_WARN,
46476008Syy154373				    "arcmsr%d: ddi_dma_alloc_handle got "
46486008Syy154373				    "DDI_DMA_BADATTR",
46496008Syy154373				    ddi_get_instance(acb->dev_info));
46506008Syy154373				return (DDI_FAILURE);
46516008Syy154373
46526008Syy154373			case DDI_DMA_NORESOURCES:
46536008Syy154373				cmn_err(CE_WARN, "arcmsr%d: "
46546008Syy154373				    "ddi_dma_alloc_handle got "
46556008Syy154373				    "DDI_DMA_NORESOURCES ",
46566008Syy154373				    ddi_get_instance(acb->dev_info));
46576008Syy154373				return (DDI_FAILURE);
46586008Syy154373			}
46596008Syy154373			cmn_err(CE_WARN,
46606008Syy154373			    "arcmsr%d: ddi_dma_alloc_handle got DDI_FAILURE",
46616008Syy154373			    ddi_get_instance(acb->dev_info));
46626008Syy154373			return (DDI_FAILURE);
46636008Syy154373		}
46646008Syy154373
46656008Syy154373		if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size,
46666008Syy154373		    &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
46676008Syy154373		    DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area,
46686008Syy154373		    &allocated_length, &acb->ccbs_acc_handle)
46696008Syy154373		    != DDI_SUCCESS) {
46706008Syy154373			cmn_err(CE_CONT,
46716008Syy154373			    "arcmsr%d: ddi_dma_mem_alloc failed ",
46726008Syy154373			    ddi_get_instance(acb->dev_info));
46736008Syy154373			ddi_dma_free_handle(&acb->ccbs_pool_handle);
46746008Syy154373			return (DDI_FAILURE);
46756008Syy154373		}
46766008Syy154373
46776008Syy154373		if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL,
46786008Syy154373		    (caddr_t)arcmsr_ccbs_area, dma_sync_size,
46796008Syy154373		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
46806008Syy154373		    NULL, &acb->ccb_cookie, &count) != DDI_DMA_MAPPED) {
46816008Syy154373			cmn_err(CE_WARN,
46826008Syy154373			    "arcmsr%d: ddi_dma_addr_bind_handle failed",
46836008Syy154373			    ddi_get_instance(acb->dev_info));
46846008Syy154373			ddi_dma_mem_free(&acb->ccbs_acc_handle);
46856008Syy154373			ddi_dma_free_handle(&acb->ccbs_pool_handle);
46866008Syy154373			return (DDI_FAILURE);
46876008Syy154373		}
46886008Syy154373		bzero(arcmsr_ccbs_area, dma_sync_size);
46896008Syy154373		freeccb = (struct CCB *)(intptr_t)arcmsr_ccbs_area;
46906008Syy154373		acb->pmu = (struct msgUnit *)
46916008Syy154373		    &freeccb[ARCMSR_MAX_FREECCB_NUM];
46926008Syy154373		phbbmu = (struct HBB_msgUnit *)acb->pmu;
46936008Syy154373
46946008Syy154373		/* setup device register */
46956008Syy154373		if (ddi_regs_map_setup(acb->dev_info, 1,
46966008Syy154373		    (caddr_t *)&iop_mu_regs_map0, 0,
46976008Syy154373		    sizeof (struct HBB_DOORBELL), &acb->dev_acc_attr,
46986008Syy154373		    &acb->reg_mu_acc_handle0) != DDI_SUCCESS) {
46996008Syy154373			arcmsr_log(NULL, CE_WARN,
47006008Syy154373			    "arcmsr%d: unable to map PCI device "
47016008Syy154373			    "base0 address registers",
47026008Syy154373			    ddi_get_instance(acb->dev_info));
47036008Syy154373			return (DDI_FAILURE);
47046008Syy154373		}
47056008Syy154373
47066008Syy154373		/* ARCMSR_DRV2IOP_DOORBELL */
47076008Syy154373		phbbmu->hbb_doorbell =
47086008Syy154373		    (struct HBB_DOORBELL *)iop_mu_regs_map0;
47096008Syy154373		if (ddi_regs_map_setup(acb->dev_info, 2,
47106008Syy154373		    (caddr_t *)&iop_mu_regs_map1, 0,
47116008Syy154373		    sizeof (struct HBB_RWBUFFER), &acb->dev_acc_attr,
47126008Syy154373		    &acb->reg_mu_acc_handle1) != DDI_SUCCESS) {
47136008Syy154373			arcmsr_log(NULL, CE_WARN,
47146008Syy154373			    "arcmsr%d: unable to map PCI device "
47156008Syy154373			    "base1 address registers",
47166008Syy154373			    ddi_get_instance(acb->dev_info));
47176008Syy154373			return (DDI_FAILURE);
47186008Syy154373		}
47196008Syy154373
47206008Syy154373		/* ARCMSR_MSGCODE_RWBUFFER */
47216008Syy154373		phbbmu->hbb_rwbuffer =
47226008Syy154373		    (struct HBB_RWBUFFER *)iop_mu_regs_map1;
47236008Syy154373	} else {
47246008Syy154373		uint32_t *iop_mu_regs_map0;
47256008Syy154373
47266008Syy154373		acb->adapter_type = ACB_ADAPTER_TYPE_A; /* intel */
47276008Syy154373		dma_sync_size = ARCMSR_MAX_FREECCB_NUM*
47286008Syy154373		    sizeof (struct CCB) + 0x20;
47296008Syy154373		if (ddi_regs_map_setup(acb->dev_info, 1,
47306008Syy154373		    (caddr_t *)&iop_mu_regs_map0, 0,
47316008Syy154373		    sizeof (struct HBA_msgUnit), &acb->dev_acc_attr,
47326008Syy154373		    &acb->reg_mu_acc_handle0) != DDI_SUCCESS) {
47336008Syy154373			arcmsr_log(NULL, CE_WARN,
47346008Syy154373			    "arcmsr%d: unable to map registers",
47356008Syy154373			    ddi_get_instance(acb->dev_info));
47366008Syy154373			return (DDI_FAILURE);
47376008Syy154373		}
47386008Syy154373
47396008Syy154373		if ((i = ddi_dma_alloc_handle(acb->dev_info, &arcmsr_ccb_attr,
47406008Syy154373		    DDI_DMA_SLEEP, NULL, &acb->ccbs_pool_handle)) !=
47416008Syy154373		    DDI_SUCCESS) {
47426008Syy154373			switch (i) {
47436008Syy154373			case DDI_DMA_BADATTR:
47446008Syy154373				cmn_err(CE_WARN,
47456008Syy154373				    "arcmsr%d: ddi_dma_alloc_handle "
47466008Syy154373				    "got DDI_DMA_BADATTR",
47476008Syy154373				    ddi_get_instance(acb->dev_info));
47486008Syy154373				return (DDI_FAILURE);
47496008Syy154373			case DDI_DMA_NORESOURCES:
47506008Syy154373				cmn_err(CE_WARN, "arcmsr%d: "
47516008Syy154373				    "ddi_dma_alloc_handle got "
47526008Syy154373				    "DDI_DMA_NORESOURCES",
47536008Syy154373				    ddi_get_instance(acb->dev_info));
47546008Syy154373				return (DDI_FAILURE);
47556008Syy154373			}
47566008Syy154373			cmn_err(CE_WARN,
47576008Syy154373			    "arcmsr%d: ddi_dma_alloc_handle failed",
47586008Syy154373			    ddi_get_instance(acb->dev_info));
47596008Syy154373			return (DDI_FAILURE);
47606008Syy154373		}
47616008Syy154373
47626008Syy154373		if (ddi_dma_mem_alloc(acb->ccbs_pool_handle, dma_sync_size,
47636008Syy154373		    &acb->dev_acc_attr, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
47646008Syy154373		    DDI_DMA_SLEEP, NULL, (caddr_t *)&arcmsr_ccbs_area,
47656008Syy154373		    &allocated_length, &acb->ccbs_acc_handle)
47666008Syy154373		    != DDI_SUCCESS) {
47676008Syy154373			cmn_err(CE_WARN, "arcmsr%d: ddi_dma_mem_alloc failed",
47686008Syy154373			    ddi_get_instance(acb->dev_info));
47696008Syy154373			ddi_dma_free_handle(&acb->ccbs_pool_handle);
47706008Syy154373			return (DDI_FAILURE);
47716008Syy154373		}
47726008Syy154373
47736008Syy154373		if (ddi_dma_addr_bind_handle(acb->ccbs_pool_handle, NULL,
47746008Syy154373		    (caddr_t)arcmsr_ccbs_area, dma_sync_size, DDI_DMA_RDWR |
47756008Syy154373		    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &acb->ccb_cookie,
47766008Syy154373		    &count) != DDI_DMA_MAPPED) {
47776008Syy154373			cmn_err(CE_WARN, "arcmsr%d: ddi_dma_addr_bind_handle "
47786008Syy154373			    "failed",
47796008Syy154373			    ddi_get_instance(acb->dev_info));
47806008Syy154373			ddi_dma_mem_free(&acb->ccbs_acc_handle);
47816008Syy154373			ddi_dma_free_handle(&acb->ccbs_pool_handle);
47826008Syy154373			return (DDI_FAILURE);
47836008Syy154373		}
47846008Syy154373		bzero(arcmsr_ccbs_area, dma_sync_size);
47856008Syy154373		/* ioport base */
47866008Syy154373		acb->pmu = (struct msgUnit *)(intptr_t)iop_mu_regs_map0;
47876008Syy154373	}
47886008Syy154373
47896008Syy154373	/* here we can not access pci configuration again */
47906008Syy154373	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
47916008Syy154373	    ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READ);
47926008Syy154373	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
47936008Syy154373	/* physical address of acb->pccb_pool */
47946008Syy154373	ccb_phyaddr = acb->ccb_cookie.dmac_address;
47956008Syy154373
47966008Syy154373	if (((unsigned long)arcmsr_ccbs_area & 0x1F) != 0) {
47976008Syy154373		/* ccb address must 32 (0x20) boundary */
47986008Syy154373		arcmsr_ccbs_area = (caddr_t)((unsigned long)arcmsr_ccbs_area +
47996008Syy154373		    (0x20 - ((unsigned long)arcmsr_ccbs_area & 0x1F)));
48006008Syy154373		ccb_phyaddr = (unsigned long)ccb_phyaddr +
48016008Syy154373		    (0x20 - ((unsigned long)ccb_phyaddr & 0x1F));
48026008Syy154373	}
48036008Syy154373
48046008Syy154373	pccb_tmp = (struct CCB *)(intptr_t)arcmsr_ccbs_area;
48056008Syy154373
48066008Syy154373	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
48076008Syy154373		pccb_tmp->cdb_shifted_phyaddr = ccb_phyaddr >> 5;
48086008Syy154373		pccb_tmp->acb = acb;
48096008Syy154373		acb->ccbworkingQ[i] = acb->pccb_pool[i] = pccb_tmp;
48106008Syy154373		ccb_phyaddr = ccb_phyaddr + sizeof (struct CCB);
48116008Syy154373		pccb_tmp++;
48126008Syy154373	}
48136008Syy154373
48146008Syy154373	acb->vir2phy_offset = (unsigned long)pccb_tmp -
48156008Syy154373	    (unsigned long)ccb_phyaddr;
48166008Syy154373
48176008Syy154373	/* disable all outbound interrupt */
48186008Syy154373	intmask_org = arcmsr_disable_allintr(acb);
48196008Syy154373
48206008Syy154373	if (!arcmsr_iop_confirm(acb)) {
48216008Syy154373		cmn_err(CE_WARN, "arcmsr%d: arcmsr_iop_confirm error",
48226008Syy154373		    ddi_get_instance(acb->dev_info));
48236008Syy154373		ddi_dma_mem_free(&acb->ccbs_acc_handle);
48246008Syy154373		ddi_dma_free_handle(&acb->ccbs_pool_handle);
48256008Syy154373		return (DDI_FAILURE);
48266008Syy154373	}
48276008Syy154373
48286008Syy154373	for (id = 0; id < ARCMSR_MAX_TARGETID; id++) {
48296008Syy154373		for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
48306008Syy154373			acb->devstate[id][lun] = ARECA_RAID_GONE;
48316008Syy154373		}
48326008Syy154373	}
48336008Syy154373
48346008Syy154373	/* enable outbound Post Queue, outbound doorbell Interrupt */
48356008Syy154373	arcmsr_enable_allintr(acb, intmask_org);
48366008Syy154373
48376008Syy154373	return (0);
48386008Syy154373}
48396008Syy154373
48406008Syy154373/*
48416008Syy154373 * Autoconfiguration support
48426008Syy154373 */
48436008Syy154373static int
48446008Syy154373arcmsr_parse_devname(char *devnm, int *tgt, int *lun)
48456008Syy154373{
48466008Syy154373	char devbuf[SCSI_MAXNAMELEN];
48476008Syy154373	char *addr;
48486008Syy154373	char *p,  *tp, *lp;
48496008Syy154373	long num;
48506008Syy154373
48516008Syy154373	/* Parse dev name and address */
48526008Syy154373	(void) strcpy(devbuf, devnm);
48536008Syy154373	addr = "";
48546008Syy154373	for (p = devbuf; *p != '\0'; p++) {
48556008Syy154373		if (*p == '@') {
48566008Syy154373			addr = p + 1;
48576008Syy154373			*p = '\0';
48586008Syy154373		} else if (*p == ':') {
48596008Syy154373			*p = '\0';
48606008Syy154373			break;
48616008Syy154373		}
48626008Syy154373	}
48636008Syy154373
48646008Syy154373	/* Parse target and lun */
48656008Syy154373	for (p = tp = addr, lp = NULL; *p != '\0'; p++) {
48666008Syy154373		if (*p == ',') {
48676008Syy154373			lp = p + 1;
48686008Syy154373			*p = '\0';
48696008Syy154373			break;
48706008Syy154373		}
48716008Syy154373	}
48726008Syy154373	if (tgt && tp) {
48736008Syy154373		if (ddi_strtol(tp, NULL, 0x10, &num))
48746008Syy154373			return (-1);
48756008Syy154373		*tgt = (int)num;
48766008Syy154373	}
48776008Syy154373	if (lun && lp) {
48786008Syy154373		if (ddi_strtol(lp, NULL, 0x10, &num))
48796008Syy154373			return (-1);
48806008Syy154373		*lun = (int)num;
48816008Syy154373	}
48826008Syy154373	return (0);
48836008Syy154373}
48846008Syy154373
48856008Syy154373static int
48866008Syy154373arcmsr_name_node(dev_info_t *dip, char *name, int len)
48876008Syy154373{
48886008Syy154373	int tgt, lun;
48896008Syy154373
48906008Syy154373	tgt = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
48916008Syy154373	    DDI_PROP_DONTPASS, "target", -1);
48926008Syy154373	if (tgt == -1)
48936008Syy154373		return (DDI_FAILURE);
48946008Syy154373	lun = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
48956008Syy154373	    DDI_PROP_DONTPASS, "lun", -1);
48966008Syy154373	if (lun == -1)
48976008Syy154373		return (DDI_FAILURE);
48986008Syy154373
48996008Syy154373	(void) snprintf(name, len, "%x,%x", tgt, lun);
49006008Syy154373	return (DDI_SUCCESS);
49016008Syy154373}
49026008Syy154373
49036008Syy154373static dev_info_t *
49046008Syy154373arcmsr_find_child(struct ACB *acb, uint16_t tgt, uint8_t lun)
49056008Syy154373{
49066008Syy154373	dev_info_t *child = NULL;
49076008Syy154373	char addr[SCSI_MAXNAMELEN];
49086008Syy154373	char tmp[MAXNAMELEN];
49096008Syy154373
49106008Syy154373	(void) sprintf(addr, "%x,%x", tgt, lun);
49116008Syy154373	for (child = ddi_get_child(acb->dev_info);
49126008Syy154373	    child; child = ddi_get_next_sibling(child)) {
49136008Syy154373		/* We don't care about non-persistent node */
49146008Syy154373		if (ndi_dev_is_persistent_node(child) == 0)
49156008Syy154373			continue;
49166008Syy154373
49176008Syy154373		if (arcmsr_name_node(child, tmp, MAXNAMELEN) !=
49186008Syy154373		    DDI_SUCCESS)
49196008Syy154373			continue;
49206008Syy154373		if (strcmp(addr, tmp) == 0)
49216008Syy154373			break;
49226008Syy154373	}
49236008Syy154373	return (child);
49246008Syy154373}
49256008Syy154373
49266008Syy154373static int
49276008Syy154373arcmsr_config_child(struct ACB *acb, struct scsi_device *sd,
49286008Syy154373    dev_info_t **dipp)
49296008Syy154373{
49306008Syy154373	char *nodename = NULL;
49316008Syy154373	char **compatible = NULL;
49326008Syy154373	int ncompatible = 0;
49336008Syy154373	dev_info_t *ldip = NULL;
49346008Syy154373	int tgt = sd->sd_address.a_target;
49356008Syy154373	int lun = sd->sd_address.a_lun;
49366008Syy154373	int dtype = sd->sd_inq->inq_dtype & DTYPE_MASK;
49376008Syy154373	int rval;
49386008Syy154373
49396008Syy154373	scsi_hba_nodename_compatible_get(sd->sd_inq, NULL, dtype,
49406008Syy154373	    NULL, &nodename, &compatible, &ncompatible);
49416008Syy154373	if (nodename == NULL) {
49426008Syy154373		cmn_err(CE_WARN,
49436008Syy154373		    "found no comptible driver for T%dL%d", tgt, lun);
49446008Syy154373		rval = NDI_FAILURE;
49456008Syy154373		goto finish;
49466008Syy154373	}
49476008Syy154373
49486008Syy154373	/* Create dev node */
49496008Syy154373	rval = ndi_devi_alloc(acb->dev_info, nodename, DEVI_SID_NODEID,
49506008Syy154373	    &ldip);
49516008Syy154373	if (rval == NDI_SUCCESS) {
49526008Syy154373		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "target", tgt)
49536008Syy154373		    != DDI_PROP_SUCCESS) {
49546008Syy154373			cmn_err(CE_WARN, "arcmsr%d: unable to create "
49556008Syy154373			    "property for T%dL%d (target)",
49566008Syy154373			    ddi_get_instance(acb->dev_info), tgt, lun);
49576008Syy154373			rval = NDI_FAILURE;
49586008Syy154373			goto finish;
49596008Syy154373		}
49606008Syy154373		if (ndi_prop_update_int(DDI_DEV_T_NONE, ldip, "lun", lun)
49616008Syy154373		    != DDI_PROP_SUCCESS) {
49626008Syy154373			cmn_err(CE_WARN, "arcmsr%d: unable to create "
49636008Syy154373			    "property for T%dL%d (lun)",
49646008Syy154373			    ddi_get_instance(acb->dev_info), tgt, lun);
49656008Syy154373			rval = NDI_FAILURE;
49666008Syy154373			goto finish;
49676008Syy154373		}
49686008Syy154373		if (ndi_prop_update_string_array(DDI_DEV_T_NONE, ldip,
49696008Syy154373		    "compatible", compatible, ncompatible)
49706008Syy154373		    != DDI_PROP_SUCCESS) {
49716008Syy154373			cmn_err(CE_WARN, "arcmsr%d: unable to create"
49726008Syy154373			    "property for T%dL%d (compatible)",
49736008Syy154373			    ddi_get_instance(acb->dev_info), tgt, lun);
49746008Syy154373			rval = NDI_FAILURE;
49756008Syy154373			goto finish;
49766008Syy154373		}
49776008Syy154373
49786008Syy154373		rval = ndi_devi_online(ldip, NDI_ONLINE_ATTACH);
49796008Syy154373		if (rval != NDI_SUCCESS) {
49806008Syy154373			cmn_err(CE_WARN, "arcmsr%d: unable to online T%dL%d",
49816008Syy154373			    ddi_get_instance(acb->dev_info), tgt, lun);
49826008Syy154373			ndi_prop_remove_all(ldip);
49836008Syy154373			(void) ndi_devi_free(ldip);
49846008Syy154373		} else
49856008Syy154373			cmn_err(CE_NOTE, "arcmsr%d: T%dL%d onlined",
49866008Syy154373			    ddi_get_instance(acb->dev_info), tgt, lun);
49876008Syy154373	}
49886008Syy154373finish:
49896008Syy154373	if (dipp)
49906008Syy154373		*dipp = ldip;
49916008Syy154373
49926008Syy154373	scsi_hba_nodename_compatible_free(nodename, compatible);
49936008Syy154373	return (rval);
49946008Syy154373}
49956008Syy154373
49966008Syy154373static int
49976008Syy154373arcmsr_config_lun(struct ACB *acb, uint16_t tgt, uint8_t lun,
49986008Syy154373    dev_info_t **ldip)
49996008Syy154373{
50006008Syy154373	struct scsi_device sd;
50016008Syy154373	dev_info_t *child;
50026008Syy154373	int rval;
50036008Syy154373
50046008Syy154373	if ((child = arcmsr_find_child(acb, tgt, lun)) != NULL) {
50056008Syy154373		if (ldip)
50066008Syy154373			*ldip = child;
50076008Syy154373		return (NDI_SUCCESS);
50086008Syy154373	}
50096008Syy154373
50106008Syy154373	bzero(&sd, sizeof (struct scsi_device));
50116008Syy154373	sd.sd_address.a_hba_tran = acb->scsi_hba_transport;
50126008Syy154373	sd.sd_address.a_target = (uint16_t)tgt;
50136008Syy154373	sd.sd_address.a_lun = (uint8_t)lun;
50146008Syy154373	rval = scsi_hba_probe(&sd, NULL);
50156008Syy154373	if (rval == SCSIPROBE_EXISTS)
50166008Syy154373		rval = arcmsr_config_child(acb, &sd, ldip);
50176008Syy154373	scsi_unprobe(&sd);
50186008Syy154373	return (rval);
50196008Syy154373}
50206008Syy154373
50216008Syy154373static int
50226008Syy154373arcmsr_tran_bus_config(dev_info_t *parent, uint_t flags, ddi_bus_config_op_t op,
50236008Syy154373    void *arg, dev_info_t **childp)
50246008Syy154373{
50256008Syy154373	struct ACB *acb;
50266008Syy154373	int circ = 0;
50276008Syy154373	int rval;
50286008Syy154373	int tgt, lun;
50296008Syy154373	if ((acb = ddi_get_soft_state(arcmsr_soft_state,
50306008Syy154373	    ddi_get_instance(parent))) == NULL)
50316008Syy154373		return (NDI_FAILURE);
50326008Syy154373
50336008Syy154373	ndi_devi_enter(parent, &circ);
50346008Syy154373	switch (op) {
50356008Syy154373	case BUS_CONFIG_ONE:
50366008Syy154373		if (arcmsr_parse_devname(arg, &tgt, &lun) != 0) {
50376008Syy154373			rval = NDI_FAILURE;
50386008Syy154373			break;
50396008Syy154373		}
50406008Syy154373		mutex_enter(&acb->acb_mutex);
50416008Syy154373		if (acb->device_map[tgt] & 1 << lun) {
50426008Syy154373			rval = arcmsr_config_lun(acb, tgt, lun, childp);
50436008Syy154373		}
50446008Syy154373		mutex_exit(&acb->acb_mutex);
50456008Syy154373		break;
50466008Syy154373
50476008Syy154373	case BUS_CONFIG_DRIVER:
50486008Syy154373	case BUS_CONFIG_ALL:
50496008Syy154373		for (tgt = 0; tgt < ARCMSR_MAX_TARGETID; tgt++)
50506008Syy154373			for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++)
50516008Syy154373				if (acb->device_map[tgt] & 1 << lun)
50526008Syy154373					(void) arcmsr_config_lun(acb, tgt,
50536008Syy154373					    lun, NULL);
50546008Syy154373
50556008Syy154373		rval = NDI_SUCCESS;
50566008Syy154373		break;
50576008Syy154373	}
50586008Syy154373	if (rval == NDI_SUCCESS)
50596008Syy154373		rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
50606008Syy154373	ndi_devi_exit(parent, circ);
50616008Syy154373	return (rval);
50626008Syy154373}
50636008Syy154373