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