10Sstevel@tonic-gate /* 2*7542SRichard.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 */ 2260Sstevel@tonic-gate 0 /* power */ 2270Sstevel@tonic-gate }; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate extern struct mod_ops mod_driverops; 2310Sstevel@tonic-gate static struct modldrv modldrv = { 2320Sstevel@tonic-gate &mod_driverops, /* Type of module. driver here */ 233*7542SRichard.Bean@Sun.COM "AMR Driver", /* Name of the module. */ 2340Sstevel@tonic-gate &amr_ops, /* Driver ops vector */ 2350Sstevel@tonic-gate }; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate static struct modlinkage modlinkage = { 2380Sstevel@tonic-gate MODREV_1, 2390Sstevel@tonic-gate &modldrv, 2400Sstevel@tonic-gate NULL 2410Sstevel@tonic-gate }; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate /* DMA access attributes */ 2440Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = { 2450Sstevel@tonic-gate DDI_DEVICE_ATTR_V0, 2460Sstevel@tonic-gate DDI_NEVERSWAP_ACC, 2470Sstevel@tonic-gate DDI_STRICTORDER_ACC 2480Sstevel@tonic-gate }; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate static struct amr_softs *amr_softstatep; 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate int 2540Sstevel@tonic-gate _init(void) 2550Sstevel@tonic-gate { 2560Sstevel@tonic-gate int error; 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate error = ddi_soft_state_init((void *)&amr_softstatep, 2590Sstevel@tonic-gate sizeof (struct amr_softs), 0); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate if (error != 0) 2620Sstevel@tonic-gate goto error_out; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if ((error = scsi_hba_init(&modlinkage)) != 0) { 2650Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 2660Sstevel@tonic-gate goto error_out; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate error = mod_install(&modlinkage); 2700Sstevel@tonic-gate if (error != 0) { 2710Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 2720Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 2730Sstevel@tonic-gate goto error_out; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate return (error); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate error_out: 2790Sstevel@tonic-gate cmn_err(CE_NOTE, "_init failed"); 2800Sstevel@tonic-gate return (error); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate int 2840Sstevel@tonic-gate _info(struct modinfo *modinfop) 2850Sstevel@tonic-gate { 2860Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate int 2900Sstevel@tonic-gate _fini(void) 2910Sstevel@tonic-gate { 2920Sstevel@tonic-gate int error; 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) != 0) { 2950Sstevel@tonic-gate return (error); 2960Sstevel@tonic-gate } 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 3010Sstevel@tonic-gate return (error); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate static int 3060Sstevel@tonic-gate amr_attach(dev_info_t *dev, ddi_attach_cmd_t cmd) 3070Sstevel@tonic-gate { 3080Sstevel@tonic-gate struct amr_softs *softs; 3090Sstevel@tonic-gate int error; 3100Sstevel@tonic-gate uint32_t command, i; 3110Sstevel@tonic-gate int instance; 3120Sstevel@tonic-gate caddr_t cfgaddr; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate instance = ddi_get_instance(dev); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate switch (cmd) { 3170Sstevel@tonic-gate case DDI_ATTACH: 3180Sstevel@tonic-gate break; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate case DDI_RESUME: 3210Sstevel@tonic-gate return (DDI_FAILURE); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate default: 3240Sstevel@tonic-gate return (DDI_FAILURE); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate /* 3280Sstevel@tonic-gate * Initialize softs. 3290Sstevel@tonic-gate */ 3300Sstevel@tonic-gate if (ddi_soft_state_zalloc(amr_softstatep, instance) != DDI_SUCCESS) 3310Sstevel@tonic-gate return (DDI_FAILURE); 3320Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 3330Sstevel@tonic-gate softs->state |= AMR_STATE_SOFT_STATE_SETUP; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate softs->dev_info_p = dev; 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "softs: %p; busy_slot addr: %p", 3380Sstevel@tonic-gate (void *)softs, (void *)&(softs->amr_busyslots))); 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate if (pci_config_setup(dev, &(softs->pciconfig_handle)) 3410Sstevel@tonic-gate != DDI_SUCCESS) { 3420Sstevel@tonic-gate goto error_out; 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate softs->state |= AMR_STATE_PCI_CONFIG_SETUP; 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate error = ddi_regs_map_setup(dev, 1, &cfgaddr, 0, 0, 3470Sstevel@tonic-gate &accattr, &(softs->regsmap_handle)); 3480Sstevel@tonic-gate if (error != DDI_SUCCESS) { 3490Sstevel@tonic-gate goto error_out; 3500Sstevel@tonic-gate } 3510Sstevel@tonic-gate softs->state |= AMR_STATE_PCI_MEM_MAPPED; 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* 3540Sstevel@tonic-gate * Determine board type. 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate command = pci_config_get16(softs->pciconfig_handle, PCI_CONF_COMM); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * Make sure we are going to be able to talk to this board. 3600Sstevel@tonic-gate */ 3610Sstevel@tonic-gate if ((command & PCI_COMM_MAE) == 0) { 3620Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "memory window not available")); 3630Sstevel@tonic-gate goto error_out; 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* force the busmaster enable bit on */ 3670Sstevel@tonic-gate if (!(command & PCI_COMM_ME)) { 3680Sstevel@tonic-gate command |= PCI_COMM_ME; 3690Sstevel@tonic-gate pci_config_put16(softs->pciconfig_handle, 3700Sstevel@tonic-gate PCI_CONF_COMM, command); 3710Sstevel@tonic-gate command = pci_config_get16(softs->pciconfig_handle, 3720Sstevel@tonic-gate PCI_CONF_COMM); 3730Sstevel@tonic-gate if (!(command & PCI_COMM_ME)) 3740Sstevel@tonic-gate goto error_out; 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate /* 3780Sstevel@tonic-gate * Allocate and connect our interrupt. 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate if (ddi_intr_hilevel(dev, 0) != 0) { 3810Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "High level interrupt is not supported!")); 3820Sstevel@tonic-gate goto error_out; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate if (ddi_get_iblock_cookie(dev, 0, &softs->iblock_cookiep) 3860Sstevel@tonic-gate != DDI_SUCCESS) { 3870Sstevel@tonic-gate goto error_out; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate mutex_init(&softs->cmd_mutex, NULL, MUTEX_DRIVER, 3910Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 3920Sstevel@tonic-gate mutex_init(&softs->queue_mutex, NULL, MUTEX_DRIVER, 3930Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 3940Sstevel@tonic-gate mutex_init(&softs->periodic_mutex, NULL, MUTEX_DRIVER, 3950Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 3960Sstevel@tonic-gate /* sychronize waits for the busy slots via this cv */ 3970Sstevel@tonic-gate cv_init(&softs->cmd_cv, NULL, CV_DRIVER, NULL); 3980Sstevel@tonic-gate softs->state |= AMR_STATE_KMUTEX_INITED; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate /* 4010Sstevel@tonic-gate * Do bus-independent initialisation, bring controller online. 4020Sstevel@tonic-gate */ 4030Sstevel@tonic-gate if (amr_setup_mbox(softs) != DDI_SUCCESS) 4040Sstevel@tonic-gate goto error_out; 4050Sstevel@tonic-gate softs->state |= AMR_STATE_MAILBOX_SETUP; 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate if (amr_setup_sg(softs) != DDI_SUCCESS) 4080Sstevel@tonic-gate goto error_out; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate softs->state |= AMR_STATE_SG_TABLES_SETUP; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if (amr_query_controller(softs) != DDI_SUCCESS) 4130Sstevel@tonic-gate goto error_out; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate /* 4160Sstevel@tonic-gate * A taskq is created for dispatching the waiting queue processing 4170Sstevel@tonic-gate * thread. The threads number equals to the logic drive number and 4180Sstevel@tonic-gate * the thread number should be 1 if there is no logic driver is 4190Sstevel@tonic-gate * configured for this instance. 4200Sstevel@tonic-gate */ 4210Sstevel@tonic-gate if ((softs->amr_taskq = ddi_taskq_create(dev, "amr_taskq", 4220Sstevel@tonic-gate MAX(softs->amr_nlogdrives, 1), TASKQ_DEFAULTPRI, 0)) == NULL) { 4230Sstevel@tonic-gate goto error_out; 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate softs->state |= AMR_STATE_TASKQ_SETUP; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate if (ddi_add_intr(dev, 0, &softs->iblock_cookiep, NULL, 4280Sstevel@tonic-gate amr_intr, (caddr_t)softs) != DDI_SUCCESS) { 4290Sstevel@tonic-gate goto error_out; 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate softs->state |= AMR_STATE_INTR_SETUP; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate /* set up the tran interface */ 4340Sstevel@tonic-gate if (amr_setup_tran(softs->dev_info_p, softs) != DDI_SUCCESS) { 4350Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "setup tran failed")); 4360Sstevel@tonic-gate goto error_out; 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate softs->state |= AMR_STATE_TRAN_SETUP; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate /* schedule a thread for periodic check */ 4410Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 4420Sstevel@tonic-gate softs->timeout_t = timeout(amr_periodic, (void *)softs, 4430Sstevel@tonic-gate drv_usectohz(500000*AMR_PERIODIC_TIMEOUT)); 4440Sstevel@tonic-gate softs->state |= AMR_STATE_TIMEOUT_ENABLED; 4450Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate /* print firmware information in verbose mode */ 4480Sstevel@tonic-gate cmn_err(CE_CONT, "?MegaRaid %s %s attached.", 4490Sstevel@tonic-gate softs->amr_product_info.pi_product_name, 4500Sstevel@tonic-gate softs->amr_product_info.pi_firmware_ver); 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /* clear any interrupts */ 4530Sstevel@tonic-gate AMR_QCLEAR_INTR(softs); 4540Sstevel@tonic-gate return (DDI_SUCCESS); 4550Sstevel@tonic-gate 4560Sstevel@tonic-gate error_out: 4570Sstevel@tonic-gate if (softs->state & AMR_STATE_INTR_SETUP) { 4580Sstevel@tonic-gate ddi_remove_intr(dev, 0, softs->iblock_cookiep); 4590Sstevel@tonic-gate } 4600Sstevel@tonic-gate if (softs->state & AMR_STATE_TASKQ_SETUP) { 4610Sstevel@tonic-gate ddi_taskq_destroy(softs->amr_taskq); 4620Sstevel@tonic-gate } 4630Sstevel@tonic-gate if (softs->state & AMR_STATE_SG_TABLES_SETUP) { 4640Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 4650Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 4660Sstevel@tonic-gate softs->sg_items[i].sg_handle); 4670Sstevel@tonic-gate (void) ddi_dma_mem_free( 4680Sstevel@tonic-gate &((softs->sg_items[i]).sg_acc_handle)); 4690Sstevel@tonic-gate (void) ddi_dma_free_handle( 4700Sstevel@tonic-gate &(softs->sg_items[i].sg_handle)); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate if (softs->state & AMR_STATE_MAILBOX_SETUP) { 4740Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 4750Sstevel@tonic-gate (void) ddi_dma_mem_free(&softs->mbox_acc_handle); 4760Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate if (softs->state & AMR_STATE_KMUTEX_INITED) { 4790Sstevel@tonic-gate mutex_destroy(&softs->queue_mutex); 4800Sstevel@tonic-gate mutex_destroy(&softs->cmd_mutex); 4810Sstevel@tonic-gate mutex_destroy(&softs->periodic_mutex); 4820Sstevel@tonic-gate cv_destroy(&softs->cmd_cv); 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate if (softs->state & AMR_STATE_PCI_MEM_MAPPED) 4850Sstevel@tonic-gate ddi_regs_map_free(&softs->regsmap_handle); 4860Sstevel@tonic-gate if (softs->state & AMR_STATE_PCI_CONFIG_SETUP) 4870Sstevel@tonic-gate pci_config_teardown(&softs->pciconfig_handle); 4880Sstevel@tonic-gate if (softs->state & AMR_STATE_SOFT_STATE_SETUP) 4890Sstevel@tonic-gate ddi_soft_state_free(amr_softstatep, instance); 4900Sstevel@tonic-gate return (DDI_FAILURE); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* 4940Sstevel@tonic-gate * Bring the controller down to a dormant state and detach all child devices. 4950Sstevel@tonic-gate * This function is called during detach, system shutdown. 4960Sstevel@tonic-gate * 4970Sstevel@tonic-gate * Note that we can assume that the bufq on the controller is empty, as we won't 4980Sstevel@tonic-gate * allow shutdown if any device is open. 4990Sstevel@tonic-gate */ 5000Sstevel@tonic-gate /*ARGSUSED*/ 5010Sstevel@tonic-gate static int amr_detach(dev_info_t *dev, ddi_detach_cmd_t cmd) 5020Sstevel@tonic-gate { 5030Sstevel@tonic-gate struct amr_softs *softs; 5040Sstevel@tonic-gate int instance; 5050Sstevel@tonic-gate uint32_t i, done_flag; 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate instance = ddi_get_instance(dev); 5080Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* flush the controllor */ 5110Sstevel@tonic-gate if (amr_flush(softs) != 0) { 5120Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "device shutdown failed")); 5130Sstevel@tonic-gate return (EIO); 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate /* release the amr timer */ 5170Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 5180Sstevel@tonic-gate softs->state &= ~AMR_STATE_TIMEOUT_ENABLED; 5190Sstevel@tonic-gate if (softs->timeout_t) { 5200Sstevel@tonic-gate (void) untimeout(softs->timeout_t); 5210Sstevel@tonic-gate softs->timeout_t = 0; 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 5260Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 5270Sstevel@tonic-gate softs->sg_items[i].sg_handle); 5280Sstevel@tonic-gate (void) ddi_dma_mem_free( 5290Sstevel@tonic-gate &((softs->sg_items[i]).sg_acc_handle)); 5300Sstevel@tonic-gate (void) ddi_dma_free_handle( 5310Sstevel@tonic-gate &(softs->sg_items[i].sg_handle)); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 5350Sstevel@tonic-gate (void) ddi_dma_mem_free(&softs->mbox_acc_handle); 5360Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* disconnect the interrupt handler */ 5390Sstevel@tonic-gate ddi_remove_intr(softs->dev_info_p, 0, softs->iblock_cookiep); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate /* wait for the completion of current in-progress interruptes */ 5420Sstevel@tonic-gate AMR_DELAY((softs->amr_interrupts_counter == 0), 1000, done_flag); 5430Sstevel@tonic-gate if (!done_flag) { 5440Sstevel@tonic-gate cmn_err(CE_WARN, "Suspicious interrupts in-progress."); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate 5470Sstevel@tonic-gate ddi_taskq_destroy(softs->amr_taskq); 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate (void) scsi_hba_detach(dev); 5500Sstevel@tonic-gate scsi_hba_tran_free(softs->hba_tran); 5510Sstevel@tonic-gate ddi_regs_map_free(&softs->regsmap_handle); 5520Sstevel@tonic-gate pci_config_teardown(&softs->pciconfig_handle); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate mutex_destroy(&softs->queue_mutex); 5550Sstevel@tonic-gate mutex_destroy(&softs->cmd_mutex); 5560Sstevel@tonic-gate mutex_destroy(&softs->periodic_mutex); 5570Sstevel@tonic-gate cv_destroy(&softs->cmd_cv); 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* print firmware information in verbose mode */ 5600Sstevel@tonic-gate cmn_err(CE_NOTE, "?MegaRaid %s %s detached.", 5610Sstevel@tonic-gate softs->amr_product_info.pi_product_name, 5620Sstevel@tonic-gate softs->amr_product_info.pi_firmware_ver); 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate ddi_soft_state_free(amr_softstatep, instance); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate return (DDI_SUCCESS); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate /*ARGSUSED*/ 5710Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 5720Sstevel@tonic-gate void *arg, void **result) 5730Sstevel@tonic-gate { 5740Sstevel@tonic-gate struct amr_softs *softs; 5750Sstevel@tonic-gate int instance; 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate instance = ddi_get_instance(dip); 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate switch (infocmd) { 5800Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 5810Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 5820Sstevel@tonic-gate if (softs != NULL) { 5830Sstevel@tonic-gate *result = softs->dev_info_p; 5840Sstevel@tonic-gate return (DDI_SUCCESS); 5850Sstevel@tonic-gate } else { 5860Sstevel@tonic-gate *result = NULL; 5870Sstevel@tonic-gate return (DDI_FAILURE); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 5900Sstevel@tonic-gate *(int *)result = instance; 5910Sstevel@tonic-gate break; 5920Sstevel@tonic-gate default: 5930Sstevel@tonic-gate break; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate return (DDI_SUCCESS); 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate /* 5990Sstevel@tonic-gate * Take an interrupt, or be poked by other code to look for interrupt-worthy 6000Sstevel@tonic-gate * status. 6010Sstevel@tonic-gate */ 6020Sstevel@tonic-gate static uint_t 6030Sstevel@tonic-gate amr_intr(caddr_t arg) 6040Sstevel@tonic-gate { 6050Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)arg; 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate softs->amr_interrupts_counter++; 6080Sstevel@tonic-gate 6090Sstevel@tonic-gate if (AMR_QGET_ODB(softs) != AMR_QODB_READY) { 6100Sstevel@tonic-gate softs->amr_interrupts_counter--; 6110Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 6120Sstevel@tonic-gate } 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* collect finished commands, queue anything waiting */ 6150Sstevel@tonic-gate amr_done(softs); 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate softs->amr_interrupts_counter--; 6180Sstevel@tonic-gate 6190Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * Setup the amr mailbox 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate static int 6270Sstevel@tonic-gate amr_setup_mbox(struct amr_softs *softs) 6280Sstevel@tonic-gate { 6290Sstevel@tonic-gate uint32_t move; 6300Sstevel@tonic-gate size_t mbox_len; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate if (ddi_dma_alloc_handle( 6330Sstevel@tonic-gate softs->dev_info_p, 6340Sstevel@tonic-gate &addr_dma_attr, 6350Sstevel@tonic-gate DDI_DMA_SLEEP, 6360Sstevel@tonic-gate NULL, 6370Sstevel@tonic-gate &softs->mbox_dma_handle) != DDI_SUCCESS) { 6380Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Cannot alloc dma handle for mailbox")); 6390Sstevel@tonic-gate goto error_out; 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate 6420Sstevel@tonic-gate if (ddi_dma_mem_alloc( 6430Sstevel@tonic-gate softs->mbox_dma_handle, 6440Sstevel@tonic-gate sizeof (struct amr_mailbox) + 16, 6450Sstevel@tonic-gate &accattr, 6460Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 6470Sstevel@tonic-gate DDI_DMA_SLEEP, 6480Sstevel@tonic-gate NULL, 6490Sstevel@tonic-gate (caddr_t *)(&softs->mbox), 6500Sstevel@tonic-gate &mbox_len, 6510Sstevel@tonic-gate &softs->mbox_acc_handle) != 6520Sstevel@tonic-gate DDI_SUCCESS) { 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "Cannot alloc dma memory for mailbox")); 6550Sstevel@tonic-gate goto error_out; 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate if (ddi_dma_addr_bind_handle( 6590Sstevel@tonic-gate softs->mbox_dma_handle, 6600Sstevel@tonic-gate NULL, 6610Sstevel@tonic-gate (caddr_t)softs->mbox, 6623495Syw161884 mbox_len, 6630Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 6640Sstevel@tonic-gate DDI_DMA_SLEEP, 6650Sstevel@tonic-gate NULL, 6660Sstevel@tonic-gate &softs->mbox_dma_cookie, 6670Sstevel@tonic-gate &softs->mbox_dma_cookien) != DDI_DMA_MAPPED) { 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Cannot bind dma memory for mailbox")); 6700Sstevel@tonic-gate goto error_out; 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate if (softs->mbox_dma_cookien != 1) 6740Sstevel@tonic-gate goto error_out; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate /* The phy address of mailbox must be aligned on a 16-byte boundary */ 6770Sstevel@tonic-gate move = 16 - (((uint32_t)softs->mbox_dma_cookie.dmac_address)&0xf); 6780Sstevel@tonic-gate softs->mbox_phyaddr = 6790Sstevel@tonic-gate (softs->mbox_dma_cookie.dmac_address + move); 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate softs->mailbox = 6820Sstevel@tonic-gate (struct amr_mailbox *)(((uintptr_t)softs->mbox) + move); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "phraddy=%x, mailbox=%p, softs->mbox=%p, move=%x", 6850Sstevel@tonic-gate softs->mbox_phyaddr, (void *)softs->mailbox, 6860Sstevel@tonic-gate softs->mbox, move)); 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate return (DDI_SUCCESS); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate error_out: 6910Sstevel@tonic-gate if (softs->mbox_dma_cookien) 6920Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 6930Sstevel@tonic-gate if (softs->mbox_acc_handle) { 6940Sstevel@tonic-gate (void) ddi_dma_mem_free(&(softs->mbox_acc_handle)); 6950Sstevel@tonic-gate softs->mbox_acc_handle = NULL; 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate if (softs->mbox_dma_handle) { 6980Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 6990Sstevel@tonic-gate softs->mbox_dma_handle = NULL; 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate return (DDI_FAILURE); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * Perform a periodic check of the controller status 7070Sstevel@tonic-gate */ 7080Sstevel@tonic-gate static void 7090Sstevel@tonic-gate amr_periodic(void *data) 7100Sstevel@tonic-gate { 7110Sstevel@tonic-gate uint32_t i; 7120Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)data; 7130Sstevel@tonic-gate struct scsi_pkt *pkt; 7140Sstevel@tonic-gate register struct amr_command *ac; 7150Sstevel@tonic-gate 7160Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 7170Sstevel@tonic-gate if (softs->busycmd[i] == NULL) 7180Sstevel@tonic-gate continue; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate if (softs->busycmd[i] == NULL) { 7230Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 7240Sstevel@tonic-gate continue; 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate pkt = softs->busycmd[i]->pkt; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if ((pkt->pkt_time != 0) && 7300Sstevel@tonic-gate (ddi_get_time() - 7310Sstevel@tonic-gate softs->busycmd[i]->ac_timestamp > 7320Sstevel@tonic-gate pkt->pkt_time)) { 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate cmn_err(CE_WARN, 7353495Syw161884 "!timed out packet detected,\ 7360Sstevel@tonic-gate sc = %p, pkt = %p, index = %d, ac = %p", 7370Sstevel@tonic-gate (void *)softs, 7380Sstevel@tonic-gate (void *)pkt, 7390Sstevel@tonic-gate i, 7400Sstevel@tonic-gate (void *)softs->busycmd[i]); 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate ac = softs->busycmd[i]; 7430Sstevel@tonic-gate ac->ac_next = NULL; 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate /* pull command from the busy index */ 7460Sstevel@tonic-gate softs->busycmd[i] = NULL; 7470Sstevel@tonic-gate if (softs->amr_busyslots > 0) 7480Sstevel@tonic-gate softs->amr_busyslots--; 7490Sstevel@tonic-gate if (softs->amr_busyslots == 0) 7500Sstevel@tonic-gate cv_broadcast(&softs->cmd_cv); 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate pkt = ac->pkt; 7550Sstevel@tonic-gate *pkt->pkt_scbp = 0; 7560Sstevel@tonic-gate pkt->pkt_statistics |= STAT_TIMEOUT; 7570Sstevel@tonic-gate pkt->pkt_reason = CMD_TIMEOUT; 7580Sstevel@tonic-gate if (!(pkt->pkt_flags & 7590Sstevel@tonic-gate FLAG_NOINTR) && pkt->pkt_comp) { 7600Sstevel@tonic-gate /* call pkt callback */ 7610Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 7620Sstevel@tonic-gate } 7630Sstevel@tonic-gate 7640Sstevel@tonic-gate } else { 7650Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 7660Sstevel@tonic-gate } 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate /* restart the amr timer */ 7700Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 7710Sstevel@tonic-gate if (softs->state & AMR_STATE_TIMEOUT_ENABLED) 7720Sstevel@tonic-gate softs->timeout_t = timeout(amr_periodic, (void *)softs, 7730Sstevel@tonic-gate drv_usectohz(500000*AMR_PERIODIC_TIMEOUT)); 7740Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * Interrogate the controller for the operational parameters we require. 7790Sstevel@tonic-gate */ 7800Sstevel@tonic-gate static int 7810Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs) 7820Sstevel@tonic-gate { 7830Sstevel@tonic-gate struct amr_enquiry3 *aex; 7840Sstevel@tonic-gate struct amr_prodinfo *ap; 7850Sstevel@tonic-gate struct amr_enquiry *ae; 7860Sstevel@tonic-gate uint32_t ldrv; 7870Sstevel@tonic-gate int instance; 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate /* 7900Sstevel@tonic-gate * If we haven't found the real limit yet, let us have a couple of 7910Sstevel@tonic-gate * commands in order to be able to probe. 7920Sstevel@tonic-gate */ 7930Sstevel@tonic-gate if (softs->maxio == 0) 7940Sstevel@tonic-gate softs->maxio = 2; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate instance = ddi_get_instance(softs->dev_info_p); 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /* 7990Sstevel@tonic-gate * Try to issue an ENQUIRY3 command 8000Sstevel@tonic-gate */ 8010Sstevel@tonic-gate if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG, 8020Sstevel@tonic-gate AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) { 8030Sstevel@tonic-gate 8040Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "First enquiry")); 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) { 8070Sstevel@tonic-gate softs->logic_drive[ldrv].al_size = 8080Sstevel@tonic-gate aex->ae_drivesize[ldrv]; 8090Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = 8100Sstevel@tonic-gate aex->ae_drivestate[ldrv]; 8110Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties = 8120Sstevel@tonic-gate aex->ae_driveprop[ldrv]; 8130Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8140Sstevel@tonic-gate " drive %d: size: %d state %x properties %x\n", 8150Sstevel@tonic-gate ldrv, 8160Sstevel@tonic-gate softs->logic_drive[ldrv].al_size, 8170Sstevel@tonic-gate softs->logic_drive[ldrv].al_state, 8180Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties)); 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate if (softs->logic_drive[ldrv].al_state == AMR_LDRV_OFFLINE) 8210Sstevel@tonic-gate cmn_err(CE_NOTE, "!instance %d log-drive %d is offline", 8220Sstevel@tonic-gate instance, ldrv); 8230Sstevel@tonic-gate else 8240Sstevel@tonic-gate softs->amr_nlogdrives++; 8250Sstevel@tonic-gate } 8260Sstevel@tonic-gate kmem_free(aex, AMR_ENQ_BUFFER_SIZE); 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, 8290Sstevel@tonic-gate AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) { 8300Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8310Sstevel@tonic-gate "Cannot obtain product data from controller")); 8320Sstevel@tonic-gate return (EIO); 8330Sstevel@tonic-gate } 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate softs->maxdrives = AMR_40LD_MAXDRIVES; 8360Sstevel@tonic-gate softs->maxchan = ap->ap_nschan; 8370Sstevel@tonic-gate softs->maxio = ap->ap_maxio; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver, 8400Sstevel@tonic-gate AMR_FIRMWARE_VER_SIZE); 8410Sstevel@tonic-gate softs->amr_product_info. 8420Sstevel@tonic-gate pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0; 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate bcopy(ap->ap_product, softs->amr_product_info.pi_product_name, 8450Sstevel@tonic-gate AMR_PRODUCT_INFO_SIZE); 8460Sstevel@tonic-gate softs->amr_product_info. 8470Sstevel@tonic-gate pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0; 8480Sstevel@tonic-gate 8490Sstevel@tonic-gate kmem_free(ap, AMR_ENQ_BUFFER_SIZE); 8500Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio)); 8510Sstevel@tonic-gate } else { 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "First enquiry failed, \ 8540Sstevel@tonic-gate so try another way")); 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate /* failed, try the 8LD ENQUIRY commands */ 8570Sstevel@tonic-gate if ((ae = (struct amr_enquiry *)amr_enquiry(softs, 8580Sstevel@tonic-gate AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0)) 8590Sstevel@tonic-gate == NULL) { 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate if ((ae = (struct amr_enquiry *)amr_enquiry(softs, 8620Sstevel@tonic-gate AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0)) 8630Sstevel@tonic-gate == NULL) { 8640Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8650Sstevel@tonic-gate "Cannot obtain configuration data")); 8660Sstevel@tonic-gate return (EIO); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate ae->ae_signature = 0; 8690Sstevel@tonic-gate } 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * Fetch current state of logical drives. 8730Sstevel@tonic-gate */ 8740Sstevel@tonic-gate for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) { 8750Sstevel@tonic-gate softs->logic_drive[ldrv].al_size = 8760Sstevel@tonic-gate ae->ae_ldrv.al_size[ldrv]; 8770Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = 8780Sstevel@tonic-gate ae->ae_ldrv.al_state[ldrv]; 8790Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties = 8800Sstevel@tonic-gate ae->ae_ldrv.al_properties[ldrv]; 8810Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 8820Sstevel@tonic-gate " ********* drive %d: %d state %x properties %x", 8830Sstevel@tonic-gate ldrv, 8840Sstevel@tonic-gate softs->logic_drive[ldrv].al_size, 8850Sstevel@tonic-gate softs->logic_drive[ldrv].al_state, 8860Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties)); 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate if (softs->logic_drive[ldrv].al_state == AMR_LDRV_OFFLINE) 8890Sstevel@tonic-gate cmn_err(CE_NOTE, "!instance %d log-drive %d is offline", 8900Sstevel@tonic-gate instance, ldrv); 8910Sstevel@tonic-gate else 8920Sstevel@tonic-gate softs->amr_nlogdrives++; 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate softs->maxdrives = AMR_8LD_MAXDRIVES; 8960Sstevel@tonic-gate softs->maxchan = ae->ae_adapter.aa_channels; 8970Sstevel@tonic-gate softs->maxio = ae->ae_adapter.aa_maxio; 8980Sstevel@tonic-gate kmem_free(ae, AMR_ENQ_BUFFER_SIZE); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate /* 9020Sstevel@tonic-gate * Mark remaining drives as unused. 9030Sstevel@tonic-gate */ 9040Sstevel@tonic-gate for (; ldrv < AMR_MAXLD; ldrv++) 9050Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE; 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate /* 9080Sstevel@tonic-gate * Cap the maximum number of outstanding I/Os. AMI's driver 9090Sstevel@tonic-gate * doesn't trust the controller's reported value, and lockups have 9100Sstevel@tonic-gate * been seen when we do. 9110Sstevel@tonic-gate */ 9120Sstevel@tonic-gate softs->maxio = MIN(softs->maxio, AMR_LIMITCMD); 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate return (DDI_SUCCESS); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate /* 9180Sstevel@tonic-gate * Run a generic enquiry-style command. 9190Sstevel@tonic-gate */ 9200Sstevel@tonic-gate static void * 9210Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd, 9220Sstevel@tonic-gate uint8_t cmdsub, uint8_t cmdqual) 9230Sstevel@tonic-gate { 9240Sstevel@tonic-gate struct amr_command ac; 9250Sstevel@tonic-gate void *result; 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate result = NULL; 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate bzero(&ac, sizeof (struct amr_command)); 9300Sstevel@tonic-gate ac.ac_softs = softs; 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate /* set command flags */ 9330Sstevel@tonic-gate ac.ac_flags |= AMR_CMD_DATAOUT; 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate /* build the command proper */ 9360Sstevel@tonic-gate ac.mailbox.mb_command = cmd; 9370Sstevel@tonic-gate ac.mailbox.mb_cmdsub = cmdsub; 9380Sstevel@tonic-gate ac.mailbox.mb_cmdqual = cmdqual; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS) 9410Sstevel@tonic-gate return (NULL); 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate if (amr_poll_command(&ac) || ac.ac_status != 0) { 9440Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "can not poll command, goto out")); 9450Sstevel@tonic-gate amr_enquiry_unmapcmd(&ac); 9460Sstevel@tonic-gate return (NULL); 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate /* allocate the response structure */ 9500Sstevel@tonic-gate result = kmem_zalloc(bufsize, KM_SLEEP); 9510Sstevel@tonic-gate 9520Sstevel@tonic-gate bcopy(ac.ac_data, result, bufsize); 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate amr_enquiry_unmapcmd(&ac); 9550Sstevel@tonic-gate return (result); 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate /* 9590Sstevel@tonic-gate * Flush the controller's internal cache, return status. 9600Sstevel@tonic-gate */ 9610Sstevel@tonic-gate static int 9620Sstevel@tonic-gate amr_flush(struct amr_softs *softs) 9630Sstevel@tonic-gate { 9640Sstevel@tonic-gate struct amr_command ac; 9650Sstevel@tonic-gate int error = 0; 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate bzero(&ac, sizeof (struct amr_command)); 9680Sstevel@tonic-gate ac.ac_softs = softs; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate ac.ac_flags |= AMR_CMD_DATAOUT; 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate /* build the command proper */ 9730Sstevel@tonic-gate ac.mailbox.mb_command = AMR_CMD_FLUSH; 9740Sstevel@tonic-gate 9750Sstevel@tonic-gate /* have to poll, as the system may be going down or otherwise damaged */ 9760Sstevel@tonic-gate if (error = amr_poll_command(&ac)) { 9770Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "can not poll this cmd")); 9780Sstevel@tonic-gate return (error); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate return (error); 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate /* 9850Sstevel@tonic-gate * Take a command, submit it to the controller and wait for it to return. 9860Sstevel@tonic-gate * Returns nonzero on error. Can be safely called with interrupts enabled. 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate static int 9890Sstevel@tonic-gate amr_poll_command(struct amr_command *ac) 9900Sstevel@tonic-gate { 9910Sstevel@tonic-gate struct amr_softs *softs = ac->ac_softs; 9920Sstevel@tonic-gate volatile uint32_t done_flag; 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)", 9950Sstevel@tonic-gate (void *)&ac->mailbox, 9960Sstevel@tonic-gate (void *)softs->mailbox, 9970Sstevel@tonic-gate (uint32_t)AMR_MBOX_CMDSIZE)); 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate while (softs->amr_busyslots != 0) 10020Sstevel@tonic-gate cv_wait(&softs->cmd_cv, &softs->cmd_mutex); 10030Sstevel@tonic-gate 10040Sstevel@tonic-gate /* 10050Sstevel@tonic-gate * For read/write commands, the scatter/gather table should be 10060Sstevel@tonic-gate * filled, and the last entry in scatter/gather table will be used. 10070Sstevel@tonic-gate */ 10080Sstevel@tonic-gate if ((ac->mailbox.mb_command == AMR_CMD_LREAD) || 10090Sstevel@tonic-gate (ac->mailbox.mb_command == AMR_CMD_LWRITE)) { 10100Sstevel@tonic-gate bcopy(ac->sgtable, 10110Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_table, 10120Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG); 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate (void) ddi_dma_sync( 10150Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_handle, 10160Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate ac->mailbox.mb_physaddr = 10190Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_phyaddr; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate 10220Sstevel@tonic-gate bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE); 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate /* sync the dma memory */ 10250Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate /* clear the poll/ack fields in the mailbox */ 10280Sstevel@tonic-gate softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID; 10290Sstevel@tonic-gate softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS; 10300Sstevel@tonic-gate softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS; 10310Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 10320Sstevel@tonic-gate softs->mailbox->mb_ack = 0; 10330Sstevel@tonic-gate softs->mailbox->mb_busy = 1; 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT); 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate /* sync the dma memory */ 10380Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU); 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS), 10410Sstevel@tonic-gate 1000, done_flag); 10420Sstevel@tonic-gate if (!done_flag) { 10430Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10440Sstevel@tonic-gate return (1); 10450Sstevel@tonic-gate } 10460Sstevel@tonic-gate 10470Sstevel@tonic-gate ac->ac_status = softs->mailbox->mb_status; 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag); 10500Sstevel@tonic-gate if (!done_flag) { 10510Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10520Sstevel@tonic-gate return (1); 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 10560Sstevel@tonic-gate softs->mailbox->mb_ack = AMR_POLL_ACK; 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* acknowledge that we have the commands */ 10590Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 10600Sstevel@tonic-gate 10610Sstevel@tonic-gate AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag); 10620Sstevel@tonic-gate if (!done_flag) { 10630Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10640Sstevel@tonic-gate return (1); 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate 10670Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 10680Sstevel@tonic-gate return (ac->ac_status != AMR_STATUS_SUCCESS); 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate /* 10720Sstevel@tonic-gate * setup the scatter/gather table 10730Sstevel@tonic-gate */ 10740Sstevel@tonic-gate static int 10750Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs) 10760Sstevel@tonic-gate { 10770Sstevel@tonic-gate uint32_t i; 10780Sstevel@tonic-gate size_t len; 10790Sstevel@tonic-gate ddi_dma_cookie_t cookie; 10800Sstevel@tonic-gate uint_t cookien; 10810Sstevel@tonic-gate 10820Sstevel@tonic-gate softs->sg_max_count = 0; 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate for (i = 0; i < AMR_MAXCMD; i++) { 10850Sstevel@tonic-gate 10860Sstevel@tonic-gate /* reset the cookien */ 10870Sstevel@tonic-gate cookien = 0; 10880Sstevel@tonic-gate 10890Sstevel@tonic-gate (softs->sg_items[i]).sg_handle = NULL; 10900Sstevel@tonic-gate if (ddi_dma_alloc_handle( 10910Sstevel@tonic-gate softs->dev_info_p, 10920Sstevel@tonic-gate &addr_dma_attr, 10930Sstevel@tonic-gate DDI_DMA_SLEEP, 10940Sstevel@tonic-gate NULL, 10950Sstevel@tonic-gate &((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) { 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 10980Sstevel@tonic-gate "Cannot alloc dma handle for s/g table")); 10990Sstevel@tonic-gate goto error_out; 11000Sstevel@tonic-gate } 11010Sstevel@tonic-gate 11020Sstevel@tonic-gate if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle, 11030Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG, 11040Sstevel@tonic-gate &accattr, 11050Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 11060Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 11070Sstevel@tonic-gate (caddr_t *)(&(softs->sg_items[i]).sg_table), 11080Sstevel@tonic-gate &len, 11090Sstevel@tonic-gate &(softs->sg_items[i]).sg_acc_handle) 11100Sstevel@tonic-gate != DDI_SUCCESS) { 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 11130Sstevel@tonic-gate "Cannot allocate DMA memory")); 11140Sstevel@tonic-gate goto error_out; 11150Sstevel@tonic-gate } 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate if (ddi_dma_addr_bind_handle( 11180Sstevel@tonic-gate (softs->sg_items[i]).sg_handle, 11190Sstevel@tonic-gate NULL, 11200Sstevel@tonic-gate (caddr_t)((softs->sg_items[i]).sg_table), 11213495Syw161884 len, 11220Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 11230Sstevel@tonic-gate DDI_DMA_SLEEP, 11240Sstevel@tonic-gate NULL, 11250Sstevel@tonic-gate &cookie, 11260Sstevel@tonic-gate &cookien) != DDI_DMA_MAPPED) { 11270Sstevel@tonic-gate 11280Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 11290Sstevel@tonic-gate "Cannot bind communication area for s/g table")); 11300Sstevel@tonic-gate goto error_out; 11310Sstevel@tonic-gate } 11320Sstevel@tonic-gate 11330Sstevel@tonic-gate if (cookien != 1) 11340Sstevel@tonic-gate goto error_out; 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate softs->sg_items[i].sg_phyaddr = cookie.dmac_address; 11370Sstevel@tonic-gate softs->sg_max_count++; 11380Sstevel@tonic-gate } 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate return (DDI_SUCCESS); 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate error_out: 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * Couldn't allocate/initialize all of the sg table entries. 11450Sstevel@tonic-gate * Clean up the partially-initialized entry before returning. 11460Sstevel@tonic-gate */ 11470Sstevel@tonic-gate if (cookien) { 11480Sstevel@tonic-gate (void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle); 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate if ((softs->sg_items[i]).sg_acc_handle) { 11510Sstevel@tonic-gate (void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle)); 11520Sstevel@tonic-gate (softs->sg_items[i]).sg_acc_handle = NULL; 11530Sstevel@tonic-gate } 11540Sstevel@tonic-gate if ((softs->sg_items[i]).sg_handle) { 11550Sstevel@tonic-gate (void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle)); 11560Sstevel@tonic-gate (softs->sg_items[i]).sg_handle = NULL; 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate 11590Sstevel@tonic-gate /* 11600Sstevel@tonic-gate * At least two sg table entries are needed. One is for regular data 11610Sstevel@tonic-gate * I/O commands, the other is for poll I/O commands. 11620Sstevel@tonic-gate */ 11630Sstevel@tonic-gate return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate /* 11670Sstevel@tonic-gate * Map/unmap (ac)'s data in the controller's addressable space as required. 11680Sstevel@tonic-gate * 11690Sstevel@tonic-gate * These functions may be safely called multiple times on a given command. 11700Sstevel@tonic-gate */ 11710Sstevel@tonic-gate static void 11720Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep, 11730Sstevel@tonic-gate int nsegments) 11740Sstevel@tonic-gate { 11750Sstevel@tonic-gate struct amr_sgentry *sg; 11760Sstevel@tonic-gate uint32_t i, size; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate sg = ac->sgtable; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate size = 0; 11810Sstevel@tonic-gate 11820Sstevel@tonic-gate ac->mailbox.mb_nsgelem = (uint8_t)nsegments; 11830Sstevel@tonic-gate for (i = 0; i < nsegments; i++, sg++) { 11840Sstevel@tonic-gate sg->sg_addr = buffer_dma_cookiep->dmac_address; 11850Sstevel@tonic-gate sg->sg_count = buffer_dma_cookiep->dmac_size; 11860Sstevel@tonic-gate size += sg->sg_count; 11870Sstevel@tonic-gate 11880Sstevel@tonic-gate /* 11890Sstevel@tonic-gate * There is no next cookie if the end of the current 11900Sstevel@tonic-gate * window is reached. Otherwise, the next cookie 11910Sstevel@tonic-gate * would be found. 11920Sstevel@tonic-gate */ 11930Sstevel@tonic-gate if ((ac->current_cookie + i + 1) != ac->num_of_cookie) 11940Sstevel@tonic-gate ddi_dma_nextcookie(ac->buffer_dma_handle, 11950Sstevel@tonic-gate buffer_dma_cookiep); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate ac->transfer_size = size; 11990Sstevel@tonic-gate ac->data_transfered += size; 12000Sstevel@tonic-gate } 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate 12030Sstevel@tonic-gate /* 12040Sstevel@tonic-gate * map the amr command for enquiry, allocate the DMA resource 12050Sstevel@tonic-gate */ 12060Sstevel@tonic-gate static int 12070Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size) 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate struct amr_softs *softs = ac->ac_softs; 12100Sstevel@tonic-gate size_t len; 12110Sstevel@tonic-gate uint_t dma_flags; 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x", 12140Sstevel@tonic-gate (void *)ac, ac->ac_flags)); 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 12170Sstevel@tonic-gate dma_flags = DDI_DMA_READ; 12180Sstevel@tonic-gate } else { 12190Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE; 12200Sstevel@tonic-gate } 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 12230Sstevel@tonic-gate 12240Sstevel@tonic-gate /* process the DMA by address bind mode */ 12250Sstevel@tonic-gate if (ddi_dma_alloc_handle(softs->dev_info_p, 12260Sstevel@tonic-gate &addr_dma_attr, DDI_DMA_SLEEP, NULL, 12270Sstevel@tonic-gate &ac->buffer_dma_handle) != 12280Sstevel@tonic-gate DDI_SUCCESS) { 12290Sstevel@tonic-gate 12300Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 12310Sstevel@tonic-gate "Cannot allocate addr DMA tag")); 12320Sstevel@tonic-gate goto error_out; 12330Sstevel@tonic-gate } 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate if (ddi_dma_mem_alloc(ac->buffer_dma_handle, 12360Sstevel@tonic-gate data_size, 12370Sstevel@tonic-gate &accattr, 12380Sstevel@tonic-gate dma_flags, 12390Sstevel@tonic-gate DDI_DMA_SLEEP, 12400Sstevel@tonic-gate NULL, 12410Sstevel@tonic-gate (caddr_t *)&ac->ac_data, 12420Sstevel@tonic-gate &len, 12430Sstevel@tonic-gate &ac->buffer_acc_handle) != 12440Sstevel@tonic-gate DDI_SUCCESS) { 12450Sstevel@tonic-gate 12460Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 12470Sstevel@tonic-gate "Cannot allocate DMA memory")); 12480Sstevel@tonic-gate goto error_out; 12490Sstevel@tonic-gate } 12500Sstevel@tonic-gate 12510Sstevel@tonic-gate if ((ddi_dma_addr_bind_handle( 12520Sstevel@tonic-gate ac->buffer_dma_handle, 12533495Syw161884 NULL, ac->ac_data, len, dma_flags, 12540Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie, 12550Sstevel@tonic-gate &ac->num_of_cookie)) != DDI_DMA_MAPPED) { 12560Sstevel@tonic-gate 12570Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 12580Sstevel@tonic-gate "Cannot bind addr for dma")); 12590Sstevel@tonic-gate goto error_out; 12600Sstevel@tonic-gate } 12610Sstevel@tonic-gate 12620Sstevel@tonic-gate ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address; 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate ((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0; 12650Sstevel@tonic-gate ac->mailbox.mb_nsgelem = 0; 12660Sstevel@tonic-gate ac->mailbox.mb_physaddr = ac->ac_dataphys; 12670Sstevel@tonic-gate 12680Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate return (DDI_SUCCESS); 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate error_out: 12730Sstevel@tonic-gate if (ac->num_of_cookie) 12740Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 12750Sstevel@tonic-gate if (ac->buffer_acc_handle) { 12760Sstevel@tonic-gate ddi_dma_mem_free(&ac->buffer_acc_handle); 12770Sstevel@tonic-gate ac->buffer_acc_handle = NULL; 12780Sstevel@tonic-gate } 12790Sstevel@tonic-gate if (ac->buffer_dma_handle) { 12800Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 12810Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 12820Sstevel@tonic-gate } 12830Sstevel@tonic-gate 12840Sstevel@tonic-gate return (DDI_FAILURE); 12850Sstevel@tonic-gate } 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate /* 12880Sstevel@tonic-gate * unmap the amr command for enquiry, free the DMA resource 12890Sstevel@tonic-gate */ 12900Sstevel@tonic-gate static void 12910Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac) 12920Sstevel@tonic-gate { 12930Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p", 12940Sstevel@tonic-gate (void *)ac)); 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate /* if the command involved data at all and was mapped */ 12970Sstevel@tonic-gate if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) { 12980Sstevel@tonic-gate if (ac->buffer_dma_handle) 12990Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 13000Sstevel@tonic-gate ac->buffer_dma_handle); 13010Sstevel@tonic-gate if (ac->buffer_acc_handle) { 13020Sstevel@tonic-gate ddi_dma_mem_free(&ac->buffer_acc_handle); 13030Sstevel@tonic-gate ac->buffer_acc_handle = NULL; 13040Sstevel@tonic-gate } 13050Sstevel@tonic-gate if (ac->buffer_dma_handle) { 13060Sstevel@tonic-gate (void) ddi_dma_free_handle( 13070Sstevel@tonic-gate &ac->buffer_dma_handle); 13080Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate 13120Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 13130Sstevel@tonic-gate } 13140Sstevel@tonic-gate 13150Sstevel@tonic-gate /* 13160Sstevel@tonic-gate * map the amr command, allocate the DMA resource 13170Sstevel@tonic-gate */ 13180Sstevel@tonic-gate static int 13193495Syw161884 amr_mapcmd(struct amr_command *ac, int (*callback)(), caddr_t arg) 13200Sstevel@tonic-gate { 13210Sstevel@tonic-gate uint_t dma_flags; 13220Sstevel@tonic-gate off_t off; 13230Sstevel@tonic-gate size_t len; 13240Sstevel@tonic-gate int error; 13253495Syw161884 int (*cb)(caddr_t); 13260Sstevel@tonic-gate 13270Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x", 13280Sstevel@tonic-gate (void *)ac, ac->ac_flags)); 13290Sstevel@tonic-gate 13300Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 13310Sstevel@tonic-gate dma_flags = DDI_DMA_READ; 13320Sstevel@tonic-gate } else { 13330Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE; 13340Sstevel@tonic-gate } 13350Sstevel@tonic-gate 13360Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) { 13370Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) { 13400Sstevel@tonic-gate dma_flags |= DDI_DMA_PARTIAL; 13410Sstevel@tonic-gate } 13420Sstevel@tonic-gate 13430Sstevel@tonic-gate if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) { 13440Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 13450Sstevel@tonic-gate return (DDI_SUCCESS); 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate 13483495Syw161884 cb = (callback == NULL_FUNC) ? DDI_DMA_DONTWAIT : DDI_DMA_SLEEP; 13493495Syw161884 13500Sstevel@tonic-gate /* if the command involves data at all, and hasn't been mapped */ 13510Sstevel@tonic-gate if (!(ac->ac_flags & AMR_CMD_MAPPED)) { 13520Sstevel@tonic-gate /* process the DMA by buffer bind mode */ 13530Sstevel@tonic-gate error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle, 13540Sstevel@tonic-gate ac->ac_buf, 13550Sstevel@tonic-gate dma_flags, 13563495Syw161884 cb, 13573495Syw161884 arg, 13580Sstevel@tonic-gate &ac->buffer_dma_cookie, 13590Sstevel@tonic-gate &ac->num_of_cookie); 13600Sstevel@tonic-gate switch (error) { 13610Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 13620Sstevel@tonic-gate if (ddi_dma_numwin(ac->buffer_dma_handle, 13630Sstevel@tonic-gate &ac->num_of_win) == DDI_FAILURE) { 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 13660Sstevel@tonic-gate "Cannot get dma num win")); 13670Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 13680Sstevel@tonic-gate ac->buffer_dma_handle); 13690Sstevel@tonic-gate (void) ddi_dma_free_handle( 13700Sstevel@tonic-gate &ac->buffer_dma_handle); 13710Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 13720Sstevel@tonic-gate return (DDI_FAILURE); 13730Sstevel@tonic-gate } 13740Sstevel@tonic-gate ac->current_win = 0; 13750Sstevel@tonic-gate break; 13760Sstevel@tonic-gate 13770Sstevel@tonic-gate case DDI_DMA_MAPPED: 13780Sstevel@tonic-gate ac->num_of_win = 1; 13790Sstevel@tonic-gate ac->current_win = 0; 13800Sstevel@tonic-gate break; 13810Sstevel@tonic-gate 13820Sstevel@tonic-gate default: 13830Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 13840Sstevel@tonic-gate "Cannot bind buf for dma")); 13850Sstevel@tonic-gate 13860Sstevel@tonic-gate (void) ddi_dma_free_handle( 13870Sstevel@tonic-gate &ac->buffer_dma_handle); 13880Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 13890Sstevel@tonic-gate return (DDI_FAILURE); 13900Sstevel@tonic-gate } 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate ac->current_cookie = 0; 13930Sstevel@tonic-gate 13940Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 13950Sstevel@tonic-gate } else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) { 13960Sstevel@tonic-gate /* get the next window */ 13970Sstevel@tonic-gate ac->current_win++; 13980Sstevel@tonic-gate (void) ddi_dma_getwin(ac->buffer_dma_handle, 13990Sstevel@tonic-gate ac->current_win, &off, &len, 14000Sstevel@tonic-gate &ac->buffer_dma_cookie, 14010Sstevel@tonic-gate &ac->num_of_cookie); 14020Sstevel@tonic-gate ac->current_cookie = 0; 14030Sstevel@tonic-gate } 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) { 14060Sstevel@tonic-gate amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG); 14070Sstevel@tonic-gate ac->current_cookie += AMR_NSEG; 14080Sstevel@tonic-gate } else { 14090Sstevel@tonic-gate amr_setup_dmamap(ac, &ac->buffer_dma_cookie, 14100Sstevel@tonic-gate ac->num_of_cookie - ac->current_cookie); 14110Sstevel@tonic-gate ac->current_cookie = AMR_LAST_COOKIE_TAG; 14120Sstevel@tonic-gate } 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate return (DDI_SUCCESS); 14150Sstevel@tonic-gate } 14160Sstevel@tonic-gate 14170Sstevel@tonic-gate /* 14180Sstevel@tonic-gate * unmap the amr command, free the DMA resource 14190Sstevel@tonic-gate */ 14200Sstevel@tonic-gate static void 14210Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac) 14220Sstevel@tonic-gate { 14230Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p", 14240Sstevel@tonic-gate (void *)ac)); 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate /* if the command involved data at all and was mapped */ 14270Sstevel@tonic-gate if ((ac->ac_flags & AMR_CMD_MAPPED) && 14280Sstevel@tonic-gate ac->ac_buf && ac->buffer_dma_handle) 14290Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 14320Sstevel@tonic-gate } 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate static int 14350Sstevel@tonic-gate amr_setup_tran(dev_info_t *dip, struct amr_softs *softp) 14360Sstevel@tonic-gate { 14370Sstevel@tonic-gate softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate /* 14400Sstevel@tonic-gate * hba_private always points to the amr_softs struct 14410Sstevel@tonic-gate */ 14420Sstevel@tonic-gate softp->hba_tran->tran_hba_private = softp; 14430Sstevel@tonic-gate softp->hba_tran->tran_tgt_init = amr_tran_tgt_init; 14440Sstevel@tonic-gate softp->hba_tran->tran_tgt_probe = scsi_hba_probe; 14450Sstevel@tonic-gate softp->hba_tran->tran_start = amr_tran_start; 14460Sstevel@tonic-gate softp->hba_tran->tran_reset = amr_tran_reset; 14470Sstevel@tonic-gate softp->hba_tran->tran_getcap = amr_tran_getcap; 14480Sstevel@tonic-gate softp->hba_tran->tran_setcap = amr_tran_setcap; 14490Sstevel@tonic-gate softp->hba_tran->tran_init_pkt = amr_tran_init_pkt; 14500Sstevel@tonic-gate softp->hba_tran->tran_destroy_pkt = amr_tran_destroy_pkt; 14510Sstevel@tonic-gate softp->hba_tran->tran_dmafree = amr_tran_dmafree; 14520Sstevel@tonic-gate softp->hba_tran->tran_sync_pkt = amr_tran_sync_pkt; 14530Sstevel@tonic-gate softp->hba_tran->tran_abort = NULL; 14540Sstevel@tonic-gate softp->hba_tran->tran_tgt_free = NULL; 14550Sstevel@tonic-gate softp->hba_tran->tran_quiesce = NULL; 14560Sstevel@tonic-gate softp->hba_tran->tran_unquiesce = NULL; 14570Sstevel@tonic-gate softp->hba_tran->tran_sd = NULL; 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran, 14600Sstevel@tonic-gate SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) { 14610Sstevel@tonic-gate scsi_hba_tran_free(softp->hba_tran); 14620Sstevel@tonic-gate softp->hba_tran = NULL; 14630Sstevel@tonic-gate return (DDI_FAILURE); 14640Sstevel@tonic-gate } else { 14650Sstevel@tonic-gate return (DDI_SUCCESS); 14660Sstevel@tonic-gate } 14670Sstevel@tonic-gate } 14680Sstevel@tonic-gate 14690Sstevel@tonic-gate /*ARGSUSED*/ 14700Sstevel@tonic-gate static int 14710Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 14720Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd) 14730Sstevel@tonic-gate { 14740Sstevel@tonic-gate struct amr_softs *softs; 14750Sstevel@tonic-gate ushort_t target = sd->sd_address.a_target; 14760Sstevel@tonic-gate uchar_t lun = sd->sd_address.a_lun; 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate softs = (struct amr_softs *) 14790Sstevel@tonic-gate (sd->sd_address.a_hba_tran->tran_hba_private); 14800Sstevel@tonic-gate 14810Sstevel@tonic-gate if ((lun == 0) && (target < AMR_MAXLD)) 14820Sstevel@tonic-gate if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE) 14830Sstevel@tonic-gate return (DDI_SUCCESS); 14840Sstevel@tonic-gate 14850Sstevel@tonic-gate return (DDI_FAILURE); 14860Sstevel@tonic-gate } 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate static int 14890Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) 14900Sstevel@tonic-gate { 14910Sstevel@tonic-gate struct amr_softs *softs; 14920Sstevel@tonic-gate struct buf *bp = NULL; 14930Sstevel@tonic-gate union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp; 14940Sstevel@tonic-gate int ret; 14950Sstevel@tonic-gate uint32_t capacity; 14960Sstevel@tonic-gate struct amr_command *ac; 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d", 14990Sstevel@tonic-gate cdbp->scc_cmd, ap->a_target, ap->a_lun)); 15000Sstevel@tonic-gate 15010Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 15020Sstevel@tonic-gate if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) || 15030Sstevel@tonic-gate (softs->logic_drive[ap->a_target].al_state == 15040Sstevel@tonic-gate AMR_LDRV_OFFLINE)) { 15050Sstevel@tonic-gate cmn_err(CE_WARN, "target or lun is not correct!"); 15060Sstevel@tonic-gate ret = TRAN_BADPKT; 15070Sstevel@tonic-gate return (ret); 15080Sstevel@tonic-gate } 15090Sstevel@tonic-gate 15100Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 15110Sstevel@tonic-gate bp = ac->ac_buf; 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd)); 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate switch (cdbp->scc_cmd) { 15160Sstevel@tonic-gate case SCMD_READ: /* read */ 15170Sstevel@tonic-gate case SCMD_READ_G1: /* read g1 */ 15180Sstevel@tonic-gate case SCMD_READ_BUFFER: /* read buffer */ 15190Sstevel@tonic-gate case SCMD_WRITE: /* write */ 15200Sstevel@tonic-gate case SCMD_WRITE_G1: /* write g1 */ 15210Sstevel@tonic-gate case SCMD_WRITE_BUFFER: /* write buffer */ 15220Sstevel@tonic-gate amr_rw_command(softs, pkt, ap->a_target); 15230Sstevel@tonic-gate 15240Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_NOINTR) { 15250Sstevel@tonic-gate (void) amr_poll_command(ac); 15260Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 15270Sstevel@tonic-gate | STATE_GOT_TARGET 15280Sstevel@tonic-gate | STATE_SENT_CMD 15290Sstevel@tonic-gate | STATE_XFERRED_DATA); 15300Sstevel@tonic-gate *pkt->pkt_scbp = 0; 15310Sstevel@tonic-gate pkt->pkt_statistics |= STAT_SYNC; 15320Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 15330Sstevel@tonic-gate } else { 15340Sstevel@tonic-gate mutex_enter(&softs->queue_mutex); 15350Sstevel@tonic-gate if (softs->waiting_q_head == NULL) { 15360Sstevel@tonic-gate ac->ac_prev = NULL; 15370Sstevel@tonic-gate ac->ac_next = NULL; 15380Sstevel@tonic-gate softs->waiting_q_head = ac; 15390Sstevel@tonic-gate softs->waiting_q_tail = ac; 15400Sstevel@tonic-gate } else { 15410Sstevel@tonic-gate ac->ac_next = NULL; 15420Sstevel@tonic-gate ac->ac_prev = softs->waiting_q_tail; 15430Sstevel@tonic-gate softs->waiting_q_tail->ac_next = ac; 15440Sstevel@tonic-gate softs->waiting_q_tail = ac; 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 15470Sstevel@tonic-gate amr_start_waiting_queue((void *)softs); 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate ret = TRAN_ACCEPT; 15500Sstevel@tonic-gate break; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate case SCMD_INQUIRY: /* inquiry */ 15530Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 15540Sstevel@tonic-gate struct scsi_inquiry inqp; 15550Sstevel@tonic-gate uint8_t *sinq_p = (uint8_t *)&inqp; 15560Sstevel@tonic-gate 15570Sstevel@tonic-gate bzero(&inqp, sizeof (struct scsi_inquiry)); 15580Sstevel@tonic-gate 15590Sstevel@tonic-gate if (((char *)cdbp)[1] || ((char *)cdbp)[2]) { 15600Sstevel@tonic-gate /* 15610Sstevel@tonic-gate * The EVDP and pagecode is 15620Sstevel@tonic-gate * not supported 15630Sstevel@tonic-gate */ 15640Sstevel@tonic-gate sinq_p[1] = 0xFF; 15650Sstevel@tonic-gate sinq_p[2] = 0x0; 15660Sstevel@tonic-gate } else { 15670Sstevel@tonic-gate inqp.inq_len = AMR_INQ_ADDITIONAL_LEN; 15680Sstevel@tonic-gate inqp.inq_ansi = AMR_INQ_ANSI_VER; 15690Sstevel@tonic-gate inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT; 15703495Syw161884 /* Enable Tag Queue */ 15713495Syw161884 inqp.inq_cmdque = 1; 15720Sstevel@tonic-gate bcopy("MegaRaid", inqp.inq_vid, 15730Sstevel@tonic-gate sizeof (inqp.inq_vid)); 15740Sstevel@tonic-gate bcopy(softs->amr_product_info.pi_product_name, 15750Sstevel@tonic-gate inqp.inq_pid, 15760Sstevel@tonic-gate AMR_PRODUCT_INFO_SIZE); 15770Sstevel@tonic-gate bcopy(softs->amr_product_info.pi_firmware_ver, 15780Sstevel@tonic-gate inqp.inq_revision, 15790Sstevel@tonic-gate AMR_FIRMWARE_VER_SIZE); 15800Sstevel@tonic-gate } 15810Sstevel@tonic-gate 15820Sstevel@tonic-gate amr_unmapcmd(ac); 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 15850Sstevel@tonic-gate bp_mapin(bp); 15860Sstevel@tonic-gate bcopy(&inqp, bp->b_un.b_addr, 15870Sstevel@tonic-gate sizeof (struct scsi_inquiry)); 15880Sstevel@tonic-gate 15890Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA; 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 15920Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 15930Sstevel@tonic-gate | STATE_GOT_TARGET 15940Sstevel@tonic-gate | STATE_SENT_CMD); 15950Sstevel@tonic-gate *pkt->pkt_scbp = 0; 15960Sstevel@tonic-gate ret = TRAN_ACCEPT; 15970Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 15980Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 15990Sstevel@tonic-gate break; 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate case SCMD_READ_CAPACITY: /* read capacity */ 16020Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 16030Sstevel@tonic-gate struct scsi_capacity cp; 16040Sstevel@tonic-gate 16050Sstevel@tonic-gate capacity = softs->logic_drive[ap->a_target].al_size - 1; 16060Sstevel@tonic-gate cp.capacity = BE_32(capacity); 16070Sstevel@tonic-gate cp.lbasize = BE_32(512); 16080Sstevel@tonic-gate 16090Sstevel@tonic-gate amr_unmapcmd(ac); 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 16120Sstevel@tonic-gate bp_mapin(bp); 16130Sstevel@tonic-gate bcopy(&cp, bp->b_un.b_addr, 8); 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 16160Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 16170Sstevel@tonic-gate | STATE_GOT_TARGET 16180Sstevel@tonic-gate | STATE_SENT_CMD 16190Sstevel@tonic-gate | STATE_XFERRED_DATA); 16200Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16210Sstevel@tonic-gate ret = TRAN_ACCEPT; 16220Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16230Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 16240Sstevel@tonic-gate break; 16250Sstevel@tonic-gate 16260Sstevel@tonic-gate case SCMD_MODE_SENSE: /* mode sense */ 16270Sstevel@tonic-gate case SCMD_MODE_SENSE_G1: /* mode sense g1 */ 16280Sstevel@tonic-gate amr_unmapcmd(ac); 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate capacity = softs->logic_drive[ap->a_target].al_size - 1; 16310Sstevel@tonic-gate amr_mode_sense(cdbp, bp, capacity); 16320Sstevel@tonic-gate 16330Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 16340Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 16350Sstevel@tonic-gate | STATE_GOT_TARGET 16360Sstevel@tonic-gate | STATE_SENT_CMD 16370Sstevel@tonic-gate | STATE_XFERRED_DATA); 16380Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16390Sstevel@tonic-gate ret = TRAN_ACCEPT; 16400Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16410Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 16420Sstevel@tonic-gate break; 16430Sstevel@tonic-gate 16440Sstevel@tonic-gate case SCMD_TEST_UNIT_READY: /* test unit ready */ 16450Sstevel@tonic-gate case SCMD_REQUEST_SENSE: /* request sense */ 16460Sstevel@tonic-gate case SCMD_FORMAT: /* format */ 16470Sstevel@tonic-gate case SCMD_START_STOP: /* start stop */ 16480Sstevel@tonic-gate case SCMD_SYNCHRONIZE_CACHE: /* synchronize cache */ 16490Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 16500Sstevel@tonic-gate amr_unmapcmd(ac); 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 16530Sstevel@tonic-gate bp_mapin(bp); 16540Sstevel@tonic-gate bzero(bp->b_un.b_addr, bp->b_bcount); 16550Sstevel@tonic-gate 16560Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA; 16570Sstevel@tonic-gate } 16580Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 16590Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 16600Sstevel@tonic-gate | STATE_GOT_TARGET 16610Sstevel@tonic-gate | STATE_SENT_CMD); 16620Sstevel@tonic-gate ret = TRAN_ACCEPT; 16630Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16640Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16650Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 16660Sstevel@tonic-gate break; 16670Sstevel@tonic-gate 16680Sstevel@tonic-gate default: /* any other commands */ 16690Sstevel@tonic-gate amr_unmapcmd(ac); 16700Sstevel@tonic-gate pkt->pkt_reason = CMD_INCOMPLETE; 16710Sstevel@tonic-gate pkt->pkt_state = (STATE_GOT_BUS 16720Sstevel@tonic-gate | STATE_GOT_TARGET 16730Sstevel@tonic-gate | STATE_SENT_CMD 16740Sstevel@tonic-gate | STATE_GOT_STATUS 16750Sstevel@tonic-gate | STATE_ARQ_DONE); 16760Sstevel@tonic-gate ret = TRAN_ACCEPT; 16770Sstevel@tonic-gate *pkt->pkt_scbp = 0; 16780Sstevel@tonic-gate amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST); 16790Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 16800Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 16810Sstevel@tonic-gate break; 16820Sstevel@tonic-gate } 16830Sstevel@tonic-gate 16840Sstevel@tonic-gate return (ret); 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate /* 16880Sstevel@tonic-gate * tran_reset() will reset the bus/target/adapter to support the fault recovery 16890Sstevel@tonic-gate * functionality according to the "level" in interface. However, we got the 16900Sstevel@tonic-gate * confirmation from LSI that these HBA cards does not support any commands to 16910Sstevel@tonic-gate * reset bus/target/adapter/channel. 16920Sstevel@tonic-gate * 16930Sstevel@tonic-gate * If the tran_reset() return a FAILURE to the sd, the system will not 16940Sstevel@tonic-gate * continue to dump the core. But core dump is an crucial method to analyze 16950Sstevel@tonic-gate * problems in panic. Now we adopt a work around solution, that is to return 16960Sstevel@tonic-gate * a fake SUCCESS to sd during panic, which will force the system continue 16970Sstevel@tonic-gate * to dump core though the core may have problems in some situtation because 16980Sstevel@tonic-gate * some on-the-fly commands will continue DMAing data to the memory. 16990Sstevel@tonic-gate * In addition, the work around core dump method may not be performed 17000Sstevel@tonic-gate * successfully if the panic is caused by the HBA itself. So the work around 17010Sstevel@tonic-gate * solution is not a good example for the implementation of tran_reset(), 17020Sstevel@tonic-gate * the most reasonable approach should send a reset command to the adapter. 17030Sstevel@tonic-gate */ 17040Sstevel@tonic-gate /*ARGSUSED*/ 17050Sstevel@tonic-gate static int 17060Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level) 17070Sstevel@tonic-gate { 17080Sstevel@tonic-gate struct amr_softs *softs; 17090Sstevel@tonic-gate volatile uint32_t done_flag; 17100Sstevel@tonic-gate 17110Sstevel@tonic-gate if (ddi_in_panic()) { 17120Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate /* Acknowledge the card if there are any significant commands */ 17150Sstevel@tonic-gate while (softs->amr_busyslots > 0) { 17160Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_busy == 0), 17170Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 17180Sstevel@tonic-gate if (!done_flag) { 17190Sstevel@tonic-gate /* 17200Sstevel@tonic-gate * command not completed, indicate the 17210Sstevel@tonic-gate * problem and continue get ac 17220Sstevel@tonic-gate */ 17230Sstevel@tonic-gate cmn_err(CE_WARN, 17240Sstevel@tonic-gate "AMR command is not completed"); 17250Sstevel@tonic-gate return (0); 17260Sstevel@tonic-gate } 17270Sstevel@tonic-gate 17280Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 17290Sstevel@tonic-gate 17300Sstevel@tonic-gate /* wait for the acknowledge from hardware */ 17310Sstevel@tonic-gate AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 17320Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 17330Sstevel@tonic-gate if (!done_flag) { 17340Sstevel@tonic-gate /* 17350Sstevel@tonic-gate * command is not completed, return from the 17360Sstevel@tonic-gate * current interrupt and wait for the next one 17370Sstevel@tonic-gate */ 17380Sstevel@tonic-gate cmn_err(CE_WARN, "No answer from the hardware"); 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 17410Sstevel@tonic-gate return (0); 17420Sstevel@tonic-gate } 17430Sstevel@tonic-gate 17440Sstevel@tonic-gate softs->amr_busyslots -= softs->mailbox->mb_nstatus; 17450Sstevel@tonic-gate } 17460Sstevel@tonic-gate 17470Sstevel@tonic-gate /* flush the controllor */ 17480Sstevel@tonic-gate (void) amr_flush(softs); 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate /* 17510Sstevel@tonic-gate * If the system is in panic, the tran_reset() will return a 17520Sstevel@tonic-gate * fake SUCCESS to sd, then the system would continue dump the 17530Sstevel@tonic-gate * core by poll commands. This is a work around for dumping 17540Sstevel@tonic-gate * core in panic. 17550Sstevel@tonic-gate * 17560Sstevel@tonic-gate * Note: Some on-the-fly command will continue DMAing data to 17570Sstevel@tonic-gate * the memory when the core is dumping, which may cause 17580Sstevel@tonic-gate * some flaws in the dumped core file, so a cmn_err() 17590Sstevel@tonic-gate * will be printed out to warn users. However, for most 17600Sstevel@tonic-gate * cases, the core file will be fine. 17610Sstevel@tonic-gate */ 17620Sstevel@tonic-gate cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver " 17630Sstevel@tonic-gate "that doesn't support software reset. This " 17640Sstevel@tonic-gate "means that memory being used by the HBA for " 17650Sstevel@tonic-gate "DMA based reads could have been updated after " 17660Sstevel@tonic-gate "we panic'd."); 17670Sstevel@tonic-gate return (1); 17680Sstevel@tonic-gate } else { 17690Sstevel@tonic-gate /* return failure to sd */ 17700Sstevel@tonic-gate return (0); 17710Sstevel@tonic-gate } 17720Sstevel@tonic-gate } 17730Sstevel@tonic-gate 17740Sstevel@tonic-gate /*ARGSUSED*/ 17750Sstevel@tonic-gate static int 17760Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom) 17770Sstevel@tonic-gate { 17780Sstevel@tonic-gate struct amr_softs *softs; 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate /* 17810Sstevel@tonic-gate * We don't allow inquiring about capabilities for other targets 17820Sstevel@tonic-gate */ 17830Sstevel@tonic-gate if (cap == NULL || whom == 0) 17840Sstevel@tonic-gate return (-1); 17850Sstevel@tonic-gate 17860Sstevel@tonic-gate softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private); 17870Sstevel@tonic-gate 17880Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) { 17890Sstevel@tonic-gate case SCSI_CAP_ARQ: 17900Sstevel@tonic-gate return (1); 17910Sstevel@tonic-gate case SCSI_CAP_GEOMETRY: 17920Sstevel@tonic-gate return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS); 17930Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE: 17940Sstevel@tonic-gate return (AMR_DEFAULT_SECTORS); 17950Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS: 17960Sstevel@tonic-gate /* number of sectors */ 17970Sstevel@tonic-gate return (softs->logic_drive[ap->a_target].al_size); 17983495Syw161884 case SCSI_CAP_UNTAGGED_QING: 17993495Syw161884 case SCSI_CAP_TAGGED_QING: 18003495Syw161884 return (1); 18010Sstevel@tonic-gate default: 18020Sstevel@tonic-gate return (-1); 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate } 18050Sstevel@tonic-gate 18060Sstevel@tonic-gate /*ARGSUSED*/ 18070Sstevel@tonic-gate static int 18080Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value, 18090Sstevel@tonic-gate int whom) 18100Sstevel@tonic-gate { 18110Sstevel@tonic-gate /* 18120Sstevel@tonic-gate * We don't allow setting capabilities for other targets 18130Sstevel@tonic-gate */ 18140Sstevel@tonic-gate if (cap == NULL || whom == 0) { 18150Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 18160Sstevel@tonic-gate "Set Cap not supported, string = %s, whom=%d", 18170Sstevel@tonic-gate cap, whom)); 18180Sstevel@tonic-gate return (-1); 18190Sstevel@tonic-gate } 18200Sstevel@tonic-gate 18210Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) { 18220Sstevel@tonic-gate case SCSI_CAP_ARQ: 18230Sstevel@tonic-gate return (1); 18240Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS: 18250Sstevel@tonic-gate return (1); 18260Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE: 18270Sstevel@tonic-gate return (1); 18283495Syw161884 case SCSI_CAP_UNTAGGED_QING: 18293495Syw161884 case SCSI_CAP_TAGGED_QING: 18303495Syw161884 return ((value == 1) ? 1 : 0); 18310Sstevel@tonic-gate default: 18320Sstevel@tonic-gate return (0); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate } 18350Sstevel@tonic-gate 18360Sstevel@tonic-gate static struct scsi_pkt * 18370Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap, 18380Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 18390Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg) 18400Sstevel@tonic-gate { 18410Sstevel@tonic-gate struct amr_softs *softs; 18420Sstevel@tonic-gate struct amr_command *ac; 18430Sstevel@tonic-gate uint32_t slen; 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 18460Sstevel@tonic-gate 18470Sstevel@tonic-gate if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)|| 18480Sstevel@tonic-gate (softs->logic_drive[ap->a_target].al_state == 18490Sstevel@tonic-gate AMR_LDRV_OFFLINE)) { 18500Sstevel@tonic-gate return (NULL); 18510Sstevel@tonic-gate } 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate if (pkt == NULL) { 18540Sstevel@tonic-gate /* force auto request sense */ 18550Sstevel@tonic-gate slen = MAX(statuslen, sizeof (struct scsi_arq_status)); 18560Sstevel@tonic-gate 18570Sstevel@tonic-gate pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen, 18580Sstevel@tonic-gate slen, tgtlen, sizeof (struct amr_command), 18590Sstevel@tonic-gate callback, arg); 18600Sstevel@tonic-gate if (pkt == NULL) { 18610Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed")); 18620Sstevel@tonic-gate return (NULL); 18630Sstevel@tonic-gate } 18640Sstevel@tonic-gate pkt->pkt_address = *ap; 18650Sstevel@tonic-gate pkt->pkt_comp = (void (*)())NULL; 18660Sstevel@tonic-gate pkt->pkt_time = 0; 18670Sstevel@tonic-gate pkt->pkt_resid = 0; 18680Sstevel@tonic-gate pkt->pkt_statistics = 0; 18690Sstevel@tonic-gate pkt->pkt_reason = 0; 18700Sstevel@tonic-gate 18710Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 18720Sstevel@tonic-gate ac->ac_buf = bp; 18730Sstevel@tonic-gate ac->cmdlen = cmdlen; 18740Sstevel@tonic-gate ac->ac_softs = softs; 18750Sstevel@tonic-gate ac->pkt = pkt; 18760Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_GOT_SLOT; 18770Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_BUSY; 18780Sstevel@tonic-gate 18790Sstevel@tonic-gate if ((bp == NULL) || (bp->b_bcount == 0)) { 18800Sstevel@tonic-gate return (pkt); 18810Sstevel@tonic-gate } 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr, 18840Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 18850Sstevel@tonic-gate &ac->buffer_dma_handle) != DDI_SUCCESS) { 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 18880Sstevel@tonic-gate "Cannot allocate buffer DMA tag")); 18890Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 18900Sstevel@tonic-gate return (NULL); 18910Sstevel@tonic-gate 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate 18940Sstevel@tonic-gate } else { 18950Sstevel@tonic-gate if ((bp == NULL) || (bp->b_bcount == 0)) { 18960Sstevel@tonic-gate return (pkt); 18970Sstevel@tonic-gate } 18980Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 18990Sstevel@tonic-gate } 19000Sstevel@tonic-gate 19010Sstevel@tonic-gate ASSERT(ac != NULL); 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate if (bp->b_flags & B_READ) { 19040Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_DATAOUT; 19050Sstevel@tonic-gate } else { 19060Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_DATAIN; 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate if (flags & PKT_CONSISTENT) { 19100Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_PKT_CONSISTENT; 19110Sstevel@tonic-gate } 19120Sstevel@tonic-gate 19130Sstevel@tonic-gate if (flags & PKT_DMA_PARTIAL) { 19140Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL; 19150Sstevel@tonic-gate } 19160Sstevel@tonic-gate 19173495Syw161884 if (amr_mapcmd(ac, callback, arg) != DDI_SUCCESS) { 19180Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 19190Sstevel@tonic-gate return (NULL); 19200Sstevel@tonic-gate } 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate pkt->pkt_resid = bp->b_bcount - ac->data_transfered; 19230Sstevel@tonic-gate 19240Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 19250Sstevel@tonic-gate "init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d", 19260Sstevel@tonic-gate (uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount, 19270Sstevel@tonic-gate ac->data_transfered)); 19280Sstevel@tonic-gate 19290Sstevel@tonic-gate ASSERT(pkt->pkt_resid >= 0); 19300Sstevel@tonic-gate 19310Sstevel@tonic-gate return (pkt); 19320Sstevel@tonic-gate } 19330Sstevel@tonic-gate 19340Sstevel@tonic-gate static void 19350Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 19360Sstevel@tonic-gate { 19370Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19380Sstevel@tonic-gate 19390Sstevel@tonic-gate amr_unmapcmd(ac); 19400Sstevel@tonic-gate 19410Sstevel@tonic-gate if (ac->buffer_dma_handle) { 19420Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 19430Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 19440Sstevel@tonic-gate } 19450Sstevel@tonic-gate 19460Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 19470Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Destroy pkt called")); 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate /*ARGSUSED*/ 19510Sstevel@tonic-gate static void 19520Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 19530Sstevel@tonic-gate { 19540Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19550Sstevel@tonic-gate 19560Sstevel@tonic-gate if (ac->buffer_dma_handle) { 19570Sstevel@tonic-gate (void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0, 19580Sstevel@tonic-gate (ac->ac_flags & AMR_CMD_DATAIN) ? 19590Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU); 19600Sstevel@tonic-gate } 19610Sstevel@tonic-gate } 19620Sstevel@tonic-gate 19630Sstevel@tonic-gate /*ARGSUSED*/ 19640Sstevel@tonic-gate static void 19650Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) 19660Sstevel@tonic-gate { 19670Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19680Sstevel@tonic-gate 19690Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_MAPPED) { 19700Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 19710Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 19720Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 19730Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 19740Sstevel@tonic-gate } 19750Sstevel@tonic-gate 19760Sstevel@tonic-gate } 19770Sstevel@tonic-gate 19780Sstevel@tonic-gate /*ARGSUSED*/ 19790Sstevel@tonic-gate static void 19800Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target) 19810Sstevel@tonic-gate { 19820Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 19830Sstevel@tonic-gate union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp; 19840Sstevel@tonic-gate uint8_t cmd; 19850Sstevel@tonic-gate 19860Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 19870Sstevel@tonic-gate cmd = AMR_CMD_LREAD; 19880Sstevel@tonic-gate } else { 19890Sstevel@tonic-gate cmd = AMR_CMD_LWRITE; 19900Sstevel@tonic-gate } 19910Sstevel@tonic-gate 19920Sstevel@tonic-gate ac->mailbox.mb_command = cmd; 19930Sstevel@tonic-gate ac->mailbox.mb_blkcount = 19940Sstevel@tonic-gate (ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE; 19950Sstevel@tonic-gate ac->mailbox.mb_lba = (ac->cmdlen == 10) ? 19960Sstevel@tonic-gate GETG1ADDR(cdbp) : GETG0ADDR(cdbp); 19970Sstevel@tonic-gate ac->mailbox.mb_drive = (uint8_t)target; 19980Sstevel@tonic-gate } 19990Sstevel@tonic-gate 20000Sstevel@tonic-gate static void 20010Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity) 20020Sstevel@tonic-gate { 20030Sstevel@tonic-gate uchar_t pagecode; 20040Sstevel@tonic-gate struct mode_format *page3p; 20050Sstevel@tonic-gate struct mode_geometry *page4p; 20060Sstevel@tonic-gate struct mode_header *headerp; 20070Sstevel@tonic-gate uint32_t ncyl; 20080Sstevel@tonic-gate 20090Sstevel@tonic-gate if (!(bp && bp->b_un.b_addr && bp->b_bcount)) 20100Sstevel@tonic-gate return; 20110Sstevel@tonic-gate 20120Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 20130Sstevel@tonic-gate bp_mapin(bp); 20140Sstevel@tonic-gate 20150Sstevel@tonic-gate pagecode = cdbp->cdb_un.sg.scsi[0]; 20160Sstevel@tonic-gate switch (pagecode) { 20170Sstevel@tonic-gate case SD_MODE_SENSE_PAGE3_CODE: 20180Sstevel@tonic-gate headerp = (struct mode_header *)(bp->b_un.b_addr); 20190Sstevel@tonic-gate headerp->bdesc_length = MODE_BLK_DESC_LENGTH; 20200Sstevel@tonic-gate 20210Sstevel@tonic-gate page3p = (struct mode_format *)((caddr_t)headerp + 20220Sstevel@tonic-gate MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH); 20230Sstevel@tonic-gate page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE); 20240Sstevel@tonic-gate page3p->mode_page.length = BE_8(sizeof (struct mode_format)); 20250Sstevel@tonic-gate page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS); 20260Sstevel@tonic-gate page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS); 20270Sstevel@tonic-gate 20280Sstevel@tonic-gate return; 20290Sstevel@tonic-gate 20300Sstevel@tonic-gate case SD_MODE_SENSE_PAGE4_CODE: 20310Sstevel@tonic-gate headerp = (struct mode_header *)(bp->b_un.b_addr); 20320Sstevel@tonic-gate headerp->bdesc_length = MODE_BLK_DESC_LENGTH; 20330Sstevel@tonic-gate 20340Sstevel@tonic-gate page4p = (struct mode_geometry *)((caddr_t)headerp + 20350Sstevel@tonic-gate MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH); 20360Sstevel@tonic-gate page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE); 20370Sstevel@tonic-gate page4p->mode_page.length = BE_8(sizeof (struct mode_geometry)); 20380Sstevel@tonic-gate page4p->heads = BE_8(AMR_DEFAULT_HEADS); 20390Sstevel@tonic-gate page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS); 20400Sstevel@tonic-gate 20410Sstevel@tonic-gate ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS); 20420Sstevel@tonic-gate page4p->cyl_lb = BE_8(ncyl & 0xff); 20430Sstevel@tonic-gate page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff); 20440Sstevel@tonic-gate page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff); 20450Sstevel@tonic-gate 20460Sstevel@tonic-gate return; 20470Sstevel@tonic-gate default: 20480Sstevel@tonic-gate bzero(bp->b_un.b_addr, bp->b_bcount); 20490Sstevel@tonic-gate return; 20500Sstevel@tonic-gate } 20510Sstevel@tonic-gate } 20520Sstevel@tonic-gate 20530Sstevel@tonic-gate static void 20540Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key) 20550Sstevel@tonic-gate { 20560Sstevel@tonic-gate struct scsi_arq_status *arqstat; 20570Sstevel@tonic-gate 20580Sstevel@tonic-gate arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp); 20590Sstevel@tonic-gate arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */ 20600Sstevel@tonic-gate arqstat->sts_rqpkt_reason = CMD_CMPLT; 20610Sstevel@tonic-gate arqstat->sts_rqpkt_resid = 0; 20620Sstevel@tonic-gate arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | 20630Sstevel@tonic-gate STATE_SENT_CMD | STATE_XFERRED_DATA; 20640Sstevel@tonic-gate arqstat->sts_rqpkt_statistics = 0; 20650Sstevel@tonic-gate arqstat->sts_sensedata.es_valid = 1; 20660Sstevel@tonic-gate arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE; 20670Sstevel@tonic-gate arqstat->sts_sensedata.es_key = key; 20680Sstevel@tonic-gate } 20690Sstevel@tonic-gate 20700Sstevel@tonic-gate static void 20710Sstevel@tonic-gate amr_start_waiting_queue(void *softp) 20720Sstevel@tonic-gate { 20730Sstevel@tonic-gate uint32_t slot; 20740Sstevel@tonic-gate struct amr_command *ac; 20750Sstevel@tonic-gate volatile uint32_t done_flag; 20760Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)softp; 20770Sstevel@tonic-gate 20780Sstevel@tonic-gate /* only one command allowed at the same time */ 20790Sstevel@tonic-gate mutex_enter(&softs->queue_mutex); 20800Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 20810Sstevel@tonic-gate 20820Sstevel@tonic-gate while ((ac = softs->waiting_q_head) != NULL) { 20830Sstevel@tonic-gate /* 20840Sstevel@tonic-gate * Find an available slot, the last slot is 20850Sstevel@tonic-gate * occupied by poll I/O command. 20860Sstevel@tonic-gate */ 20870Sstevel@tonic-gate for (slot = 0; slot < (softs->sg_max_count - 1); slot++) { 20880Sstevel@tonic-gate if (softs->busycmd[slot] == NULL) { 20890Sstevel@tonic-gate if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) { 20900Sstevel@tonic-gate /* 20910Sstevel@tonic-gate * only one command allowed at the 20920Sstevel@tonic-gate * same time 20930Sstevel@tonic-gate */ 20940Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 20950Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 20960Sstevel@tonic-gate return; 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate ac->ac_timestamp = ddi_get_time(); 21000Sstevel@tonic-gate 21010Sstevel@tonic-gate if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) { 21020Sstevel@tonic-gate 21030Sstevel@tonic-gate softs->busycmd[slot] = ac; 21040Sstevel@tonic-gate ac->ac_slot = slot; 21050Sstevel@tonic-gate softs->amr_busyslots++; 21060Sstevel@tonic-gate 21070Sstevel@tonic-gate bcopy(ac->sgtable, 21080Sstevel@tonic-gate softs->sg_items[slot].sg_table, 21090Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG); 21100Sstevel@tonic-gate 21110Sstevel@tonic-gate (void) ddi_dma_sync( 21120Sstevel@tonic-gate softs->sg_items[slot].sg_handle, 21130Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 21140Sstevel@tonic-gate 21150Sstevel@tonic-gate ac->mailbox.mb_physaddr = 21160Sstevel@tonic-gate softs->sg_items[slot].sg_phyaddr; 21170Sstevel@tonic-gate } 21180Sstevel@tonic-gate 21190Sstevel@tonic-gate /* take the cmd from the queue */ 21200Sstevel@tonic-gate softs->waiting_q_head = ac->ac_next; 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate ac->mailbox.mb_ident = ac->ac_slot + 1; 21230Sstevel@tonic-gate ac->mailbox.mb_busy = 1; 21240Sstevel@tonic-gate ac->ac_next = NULL; 21250Sstevel@tonic-gate ac->ac_prev = NULL; 21260Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_GOT_SLOT; 21270Sstevel@tonic-gate 21280Sstevel@tonic-gate /* clear the poll/ack fields in the mailbox */ 21290Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 21300Sstevel@tonic-gate softs->mailbox->mb_ack = 0; 21310Sstevel@tonic-gate 21320Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_busy == 0), 21330Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 21340Sstevel@tonic-gate if (!done_flag) { 21350Sstevel@tonic-gate /* 21360Sstevel@tonic-gate * command not completed, indicate the 21370Sstevel@tonic-gate * problem and continue get ac 21380Sstevel@tonic-gate */ 21390Sstevel@tonic-gate cmn_err(CE_WARN, 21400Sstevel@tonic-gate "AMR command is not completed"); 21410Sstevel@tonic-gate break; 21420Sstevel@tonic-gate } 21430Sstevel@tonic-gate 21440Sstevel@tonic-gate bcopy(&ac->mailbox, (void *)softs->mailbox, 21450Sstevel@tonic-gate AMR_MBOX_CMDSIZE); 21460Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_BUSY; 21470Sstevel@tonic-gate 21480Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 21490Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate AMR_QPUT_IDB(softs, 21520Sstevel@tonic-gate softs->mbox_phyaddr | AMR_QIDB_SUBMIT); 21530Sstevel@tonic-gate 21540Sstevel@tonic-gate /* 21550Sstevel@tonic-gate * current ac is submitted 21560Sstevel@tonic-gate * so quit 'for-loop' to get next ac 21570Sstevel@tonic-gate */ 21580Sstevel@tonic-gate break; 21590Sstevel@tonic-gate } 21600Sstevel@tonic-gate } 21610Sstevel@tonic-gate 21620Sstevel@tonic-gate /* no slot, finish our task */ 21630Sstevel@tonic-gate if (slot == softs->maxio) 21640Sstevel@tonic-gate break; 21650Sstevel@tonic-gate } 21660Sstevel@tonic-gate 21670Sstevel@tonic-gate /* only one command allowed at the same time */ 21680Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 21690Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 21700Sstevel@tonic-gate } 21710Sstevel@tonic-gate 21720Sstevel@tonic-gate static void 21730Sstevel@tonic-gate amr_done(struct amr_softs *softs) 21740Sstevel@tonic-gate { 21750Sstevel@tonic-gate 21760Sstevel@tonic-gate uint32_t i, idx; 21770Sstevel@tonic-gate volatile uint32_t done_flag; 21780Sstevel@tonic-gate struct amr_mailbox *mbox, mbsave; 21790Sstevel@tonic-gate struct amr_command *ac, *head, *tail; 21800Sstevel@tonic-gate 21810Sstevel@tonic-gate head = tail = NULL; 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate AMR_QPUT_ODB(softs, AMR_QODB_READY); 21840Sstevel@tonic-gate 21850Sstevel@tonic-gate /* acknowledge interrupt */ 21860Sstevel@tonic-gate (void) AMR_QGET_ODB(softs); 21870Sstevel@tonic-gate 21880Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 21890Sstevel@tonic-gate 21900Sstevel@tonic-gate if (softs->mailbox->mb_nstatus != 0) { 21910Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 21920Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORCPU); 21930Sstevel@tonic-gate 21940Sstevel@tonic-gate /* save mailbox, which contains a list of completed commands */ 21950Sstevel@tonic-gate bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox, 21960Sstevel@tonic-gate &mbsave, sizeof (mbsave)); 21970Sstevel@tonic-gate 21980Sstevel@tonic-gate mbox = &mbsave; 21990Sstevel@tonic-gate 22000Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 22010Sstevel@tonic-gate 22020Sstevel@tonic-gate /* wait for the acknowledge from hardware */ 22030Sstevel@tonic-gate AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 22040Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 22050Sstevel@tonic-gate if (!done_flag) { 22060Sstevel@tonic-gate /* 22070Sstevel@tonic-gate * command is not completed, return from the current 22080Sstevel@tonic-gate * interrupt and wait for the next one 22090Sstevel@tonic-gate */ 22100Sstevel@tonic-gate cmn_err(CE_WARN, "No answer from the hardware"); 22110Sstevel@tonic-gate 22120Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 22130Sstevel@tonic-gate return; 22140Sstevel@tonic-gate } 22150Sstevel@tonic-gate 22160Sstevel@tonic-gate for (i = 0; i < mbox->mb_nstatus; i++) { 22170Sstevel@tonic-gate idx = mbox->mb_completed[i] - 1; 22180Sstevel@tonic-gate ac = softs->busycmd[idx]; 22190Sstevel@tonic-gate 22200Sstevel@tonic-gate if (ac != NULL) { 22210Sstevel@tonic-gate /* pull the command from the busy index */ 22220Sstevel@tonic-gate softs->busycmd[idx] = NULL; 22230Sstevel@tonic-gate if (softs->amr_busyslots > 0) 22240Sstevel@tonic-gate softs->amr_busyslots--; 22250Sstevel@tonic-gate if (softs->amr_busyslots == 0) 22260Sstevel@tonic-gate cv_broadcast(&softs->cmd_cv); 22270Sstevel@tonic-gate 22280Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_BUSY; 22290Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_GOT_SLOT; 22300Sstevel@tonic-gate ac->ac_status = mbox->mb_status; 22310Sstevel@tonic-gate 22320Sstevel@tonic-gate /* enqueue here */ 22330Sstevel@tonic-gate if (head) { 22340Sstevel@tonic-gate tail->ac_next = ac; 22350Sstevel@tonic-gate tail = ac; 22360Sstevel@tonic-gate tail->ac_next = NULL; 22370Sstevel@tonic-gate } else { 22380Sstevel@tonic-gate tail = head = ac; 22390Sstevel@tonic-gate ac->ac_next = NULL; 22400Sstevel@tonic-gate } 22410Sstevel@tonic-gate } else { 22420Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 22430Sstevel@tonic-gate "ac in mailbox is NULL!")); 22440Sstevel@tonic-gate } 22450Sstevel@tonic-gate } 22460Sstevel@tonic-gate } else { 22470Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!")); 22480Sstevel@tonic-gate } 22490Sstevel@tonic-gate 22500Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 22510Sstevel@tonic-gate 22520Sstevel@tonic-gate if (head != NULL) { 22530Sstevel@tonic-gate amr_call_pkt_comp(head); 22540Sstevel@tonic-gate } 22550Sstevel@tonic-gate 22560Sstevel@tonic-gate /* dispatch a thread to process the pending I/O if there is any */ 22570Sstevel@tonic-gate if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue, 22580Sstevel@tonic-gate (void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) { 22590Sstevel@tonic-gate cmn_err(CE_WARN, "No memory available to dispatch taskq"); 22600Sstevel@tonic-gate } 22610Sstevel@tonic-gate } 22620Sstevel@tonic-gate 22630Sstevel@tonic-gate static void 22640Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head) 22650Sstevel@tonic-gate { 22660Sstevel@tonic-gate register struct scsi_pkt *pkt; 22670Sstevel@tonic-gate register struct amr_command *ac, *localhead; 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate localhead = head; 22700Sstevel@tonic-gate 22710Sstevel@tonic-gate while (localhead) { 22720Sstevel@tonic-gate ac = localhead; 22730Sstevel@tonic-gate localhead = ac->ac_next; 22740Sstevel@tonic-gate ac->ac_next = NULL; 22750Sstevel@tonic-gate 22760Sstevel@tonic-gate pkt = ac->pkt; 22770Sstevel@tonic-gate *pkt->pkt_scbp = 0; 22780Sstevel@tonic-gate 22790Sstevel@tonic-gate if (ac->ac_status == AMR_STATUS_SUCCESS) { 22800Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 22810Sstevel@tonic-gate | STATE_GOT_TARGET 22820Sstevel@tonic-gate | STATE_SENT_CMD 22830Sstevel@tonic-gate | STATE_XFERRED_DATA); 22840Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 22850Sstevel@tonic-gate } else { 22860Sstevel@tonic-gate pkt->pkt_state |= STATE_GOT_BUS 22870Sstevel@tonic-gate | STATE_ARQ_DONE; 22880Sstevel@tonic-gate pkt->pkt_reason = CMD_INCOMPLETE; 22890Sstevel@tonic-gate amr_set_arq_data(pkt, KEY_HARDWARE_ERROR); 22900Sstevel@tonic-gate } 22910Sstevel@tonic-gate 22920Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR) && 22930Sstevel@tonic-gate pkt->pkt_comp) { 22940Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 22950Sstevel@tonic-gate } 22960Sstevel@tonic-gate } 22970Sstevel@tonic-gate } 2298