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