1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate /* 6*0Sstevel@tonic-gate * Copyright (c) 1999,2000 Michael Smith 7*0Sstevel@tonic-gate * Copyright (c) 2000 BSDi 8*0Sstevel@tonic-gate * All rights reserved. 9*0Sstevel@tonic-gate * 10*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 11*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 12*0Sstevel@tonic-gate * are met: 13*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 14*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 15*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 16*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 17*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 18*0Sstevel@tonic-gate * 19*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29*0Sstevel@tonic-gate * SUCH DAMAGE. 30*0Sstevel@tonic-gate */ 31*0Sstevel@tonic-gate /* 32*0Sstevel@tonic-gate * Copyright (c) 2002 Eric Moore 33*0Sstevel@tonic-gate * Copyright (c) 2002 LSI Logic Corporation 34*0Sstevel@tonic-gate * All rights reserved. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 37*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions 38*0Sstevel@tonic-gate * are met: 39*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 40*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 41*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 42*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 43*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 44*0Sstevel@tonic-gate * 3. The party using or redistributing the source code and binary forms 45*0Sstevel@tonic-gate * agrees to the disclaimer below and the terms and conditions set forth 46*0Sstevel@tonic-gate * herein. 47*0Sstevel@tonic-gate * 48*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 49*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 52*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58*0Sstevel@tonic-gate * SUCH DAMAGE. 59*0Sstevel@tonic-gate */ 60*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #include <sys/int_types.h> 63*0Sstevel@tonic-gate #include <sys/scsi/scsi.h> 64*0Sstevel@tonic-gate #include <sys/dkbad.h> 65*0Sstevel@tonic-gate #include <sys/dklabel.h> 66*0Sstevel@tonic-gate #include <sys/dkio.h> 67*0Sstevel@tonic-gate #include <sys/cdio.h> 68*0Sstevel@tonic-gate #include <sys/mhd.h> 69*0Sstevel@tonic-gate #include <sys/vtoc.h> 70*0Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 71*0Sstevel@tonic-gate #include <sys/scsi/targets/sddef.h> 72*0Sstevel@tonic-gate #include <sys/debug.h> 73*0Sstevel@tonic-gate #include <sys/pci.h> 74*0Sstevel@tonic-gate #include <sys/ksynch.h> 75*0Sstevel@tonic-gate #include <sys/ddi.h> 76*0Sstevel@tonic-gate #include <sys/sunddi.h> 77*0Sstevel@tonic-gate #include <sys/modctl.h> 78*0Sstevel@tonic-gate #include <sys/byteorder.h> 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate #include "amrreg.h" 81*0Sstevel@tonic-gate #include "amrvar.h" 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* dynamic debug symbol */ 84*0Sstevel@tonic-gate int amr_debug_var = 0; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate #define AMR_DELAY(cond, count, done_flag) { \ 87*0Sstevel@tonic-gate int local_counter = 0; \ 88*0Sstevel@tonic-gate done_flag = 1; \ 89*0Sstevel@tonic-gate while (!(cond)) { \ 90*0Sstevel@tonic-gate delay(drv_usectohz(100)); \ 91*0Sstevel@tonic-gate if ((local_counter) > count) { \ 92*0Sstevel@tonic-gate done_flag = 0; \ 93*0Sstevel@tonic-gate break; \ 94*0Sstevel@tonic-gate } \ 95*0Sstevel@tonic-gate (local_counter)++; \ 96*0Sstevel@tonic-gate } \ 97*0Sstevel@tonic-gate } 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate #define AMR_BUSYWAIT(cond, count, done_flag) { \ 100*0Sstevel@tonic-gate int local_counter = 0; \ 101*0Sstevel@tonic-gate done_flag = 1; \ 102*0Sstevel@tonic-gate while (!(cond)) { \ 103*0Sstevel@tonic-gate drv_usecwait(100); \ 104*0Sstevel@tonic-gate if ((local_counter) > count) { \ 105*0Sstevel@tonic-gate done_flag = 0; \ 106*0Sstevel@tonic-gate break; \ 107*0Sstevel@tonic-gate } \ 108*0Sstevel@tonic-gate (local_counter)++; \ 109*0Sstevel@tonic-gate } \ 110*0Sstevel@tonic-gate } 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate /* 113*0Sstevel@tonic-gate * driver interfaces 114*0Sstevel@tonic-gate */ 115*0Sstevel@tonic-gate char _depends_on[] = "misc/scsi"; 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate static uint_t amr_intr(caddr_t arg); 118*0Sstevel@tonic-gate static void amr_done(struct amr_softs *softs); 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 121*0Sstevel@tonic-gate void *arg, void **result); 122*0Sstevel@tonic-gate static int amr_attach(dev_info_t *, ddi_attach_cmd_t); 123*0Sstevel@tonic-gate static int amr_detach(dev_info_t *, ddi_detach_cmd_t); 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate static int amr_setup_mbox(struct amr_softs *softs); 126*0Sstevel@tonic-gate static int amr_setup_sg(struct amr_softs *softs); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* 129*0Sstevel@tonic-gate * Command wrappers 130*0Sstevel@tonic-gate */ 131*0Sstevel@tonic-gate static int amr_query_controller(struct amr_softs *softs); 132*0Sstevel@tonic-gate static void *amr_enquiry(struct amr_softs *softs, size_t bufsize, 133*0Sstevel@tonic-gate uint8_t cmd, uint8_t cmdsub, uint8_t cmdqual); 134*0Sstevel@tonic-gate static int amr_flush(struct amr_softs *softs); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* 137*0Sstevel@tonic-gate * Command processing. 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate static void amr_rw_command(struct amr_softs *softs, 140*0Sstevel@tonic-gate struct scsi_pkt *pkt, int lun); 141*0Sstevel@tonic-gate static void amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, 142*0Sstevel@tonic-gate unsigned int capacity); 143*0Sstevel@tonic-gate static void amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key); 144*0Sstevel@tonic-gate static int amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size); 145*0Sstevel@tonic-gate static void amr_enquiry_unmapcmd(struct amr_command *ac); 146*0Sstevel@tonic-gate static int amr_mapcmd(struct amr_command *ac); 147*0Sstevel@tonic-gate static void amr_unmapcmd(struct amr_command *ac); 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Status monitoring 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate static void amr_periodic(void *data); 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * Interface-specific shims 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate static int amr_poll_command(struct amr_command *ac); 158*0Sstevel@tonic-gate static void amr_start_waiting_queue(void *softp); 159*0Sstevel@tonic-gate static void amr_call_pkt_comp(struct amr_command *head); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* 162*0Sstevel@tonic-gate * SCSI interface 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate static int amr_setup_tran(dev_info_t *dip, struct amr_softs *softp); 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate /* 167*0Sstevel@tonic-gate * Function prototypes 168*0Sstevel@tonic-gate * 169*0Sstevel@tonic-gate * SCSA functions exported by means of the transport table 170*0Sstevel@tonic-gate */ 171*0Sstevel@tonic-gate static int amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 172*0Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd); 173*0Sstevel@tonic-gate static int amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt); 174*0Sstevel@tonic-gate static int amr_tran_reset(struct scsi_address *ap, int level); 175*0Sstevel@tonic-gate static int amr_tran_getcap(struct scsi_address *ap, char *cap, int whom); 176*0Sstevel@tonic-gate static int amr_tran_setcap(struct scsi_address *ap, char *cap, int value, 177*0Sstevel@tonic-gate int whom); 178*0Sstevel@tonic-gate static struct scsi_pkt *amr_tran_init_pkt(struct scsi_address *ap, 179*0Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 180*0Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg); 181*0Sstevel@tonic-gate static void amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt); 182*0Sstevel@tonic-gate static void amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt); 183*0Sstevel@tonic-gate static void amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt); 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gate static ddi_dma_attr_t buffer_dma_attr = { 186*0Sstevel@tonic-gate DMA_ATTR_V0, /* version of this structure */ 187*0Sstevel@tonic-gate 0, /* lowest usable address */ 188*0Sstevel@tonic-gate 0xffffffffull, /* highest usable address */ 189*0Sstevel@tonic-gate 0x00ffffffull, /* maximum DMAable byte count */ 190*0Sstevel@tonic-gate 4, /* alignment */ 191*0Sstevel@tonic-gate 1, /* burst sizes */ 192*0Sstevel@tonic-gate 1, /* minimum transfer */ 193*0Sstevel@tonic-gate 0xffffffffull, /* maximum transfer */ 194*0Sstevel@tonic-gate 0xffffffffull, /* maximum segment length */ 195*0Sstevel@tonic-gate AMR_NSEG, /* maximum number of segments */ 196*0Sstevel@tonic-gate AMR_BLKSIZE, /* granularity */ 197*0Sstevel@tonic-gate 0, /* flags (reserved) */ 198*0Sstevel@tonic-gate }; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate static ddi_dma_attr_t addr_dma_attr = { 201*0Sstevel@tonic-gate DMA_ATTR_V0, /* version of this structure */ 202*0Sstevel@tonic-gate 0, /* lowest usable address */ 203*0Sstevel@tonic-gate 0xffffffffull, /* highest usable address */ 204*0Sstevel@tonic-gate 0x7fffffff, /* maximum DMAable byte count */ 205*0Sstevel@tonic-gate 4, /* alignment */ 206*0Sstevel@tonic-gate 1, /* burst sizes */ 207*0Sstevel@tonic-gate 1, /* minimum transfer */ 208*0Sstevel@tonic-gate 0xffffffffull, /* maximum transfer */ 209*0Sstevel@tonic-gate 0xffffffffull, /* maximum segment length */ 210*0Sstevel@tonic-gate 1, /* maximum number of segments */ 211*0Sstevel@tonic-gate 1, /* granularity */ 212*0Sstevel@tonic-gate 0, /* flags (reserved) */ 213*0Sstevel@tonic-gate }; 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate static struct dev_ops amr_ops = { 217*0Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 218*0Sstevel@tonic-gate 0, /* refcnt */ 219*0Sstevel@tonic-gate amr_info, /* info */ 220*0Sstevel@tonic-gate nulldev, /* identify */ 221*0Sstevel@tonic-gate nulldev, /* probe */ 222*0Sstevel@tonic-gate amr_attach, /* attach */ 223*0Sstevel@tonic-gate amr_detach, /* detach */ 224*0Sstevel@tonic-gate nodev, /* reset */ 225*0Sstevel@tonic-gate NULL, /* driver operations */ 226*0Sstevel@tonic-gate (struct bus_ops *)0, /* bus operations */ 227*0Sstevel@tonic-gate 0 /* power */ 228*0Sstevel@tonic-gate }; 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate extern struct mod_ops mod_driverops; 232*0Sstevel@tonic-gate static struct modldrv modldrv = { 233*0Sstevel@tonic-gate &mod_driverops, /* Type of module. driver here */ 234*0Sstevel@tonic-gate "AMR Driver V%I%", /* Name of the module. */ 235*0Sstevel@tonic-gate &amr_ops, /* Driver ops vector */ 236*0Sstevel@tonic-gate }; 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 239*0Sstevel@tonic-gate MODREV_1, 240*0Sstevel@tonic-gate &modldrv, 241*0Sstevel@tonic-gate NULL 242*0Sstevel@tonic-gate }; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate /* DMA access attributes */ 245*0Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = { 246*0Sstevel@tonic-gate DDI_DEVICE_ATTR_V0, 247*0Sstevel@tonic-gate DDI_NEVERSWAP_ACC, 248*0Sstevel@tonic-gate DDI_STRICTORDER_ACC 249*0Sstevel@tonic-gate }; 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate static struct amr_softs *amr_softstatep; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate int 255*0Sstevel@tonic-gate _init(void) 256*0Sstevel@tonic-gate { 257*0Sstevel@tonic-gate int error; 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate error = ddi_soft_state_init((void *)&amr_softstatep, 260*0Sstevel@tonic-gate sizeof (struct amr_softs), 0); 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate if (error != 0) 263*0Sstevel@tonic-gate goto error_out; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate if ((error = scsi_hba_init(&modlinkage)) != 0) { 266*0Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 267*0Sstevel@tonic-gate goto error_out; 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate error = mod_install(&modlinkage); 271*0Sstevel@tonic-gate if (error != 0) { 272*0Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 273*0Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 274*0Sstevel@tonic-gate goto error_out; 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate return (error); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate error_out: 280*0Sstevel@tonic-gate cmn_err(CE_NOTE, "_init failed"); 281*0Sstevel@tonic-gate return (error); 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate int 285*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 288*0Sstevel@tonic-gate } 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate int 291*0Sstevel@tonic-gate _fini(void) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate int error; 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) != 0) { 296*0Sstevel@tonic-gate return (error); 297*0Sstevel@tonic-gate } 298*0Sstevel@tonic-gate 299*0Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate ddi_soft_state_fini((void*)&amr_softstatep); 302*0Sstevel@tonic-gate return (error); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate static int 307*0Sstevel@tonic-gate amr_attach(dev_info_t *dev, ddi_attach_cmd_t cmd) 308*0Sstevel@tonic-gate { 309*0Sstevel@tonic-gate struct amr_softs *softs; 310*0Sstevel@tonic-gate int error; 311*0Sstevel@tonic-gate uint32_t command, i; 312*0Sstevel@tonic-gate int instance; 313*0Sstevel@tonic-gate caddr_t cfgaddr; 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate instance = ddi_get_instance(dev); 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate switch (cmd) { 318*0Sstevel@tonic-gate case DDI_ATTACH: 319*0Sstevel@tonic-gate break; 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate case DDI_RESUME: 322*0Sstevel@tonic-gate return (DDI_FAILURE); 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate default: 325*0Sstevel@tonic-gate return (DDI_FAILURE); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate 328*0Sstevel@tonic-gate /* 329*0Sstevel@tonic-gate * Initialize softs. 330*0Sstevel@tonic-gate */ 331*0Sstevel@tonic-gate if (ddi_soft_state_zalloc(amr_softstatep, instance) != DDI_SUCCESS) 332*0Sstevel@tonic-gate return (DDI_FAILURE); 333*0Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 334*0Sstevel@tonic-gate softs->state |= AMR_STATE_SOFT_STATE_SETUP; 335*0Sstevel@tonic-gate 336*0Sstevel@tonic-gate softs->dev_info_p = dev; 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "softs: %p; busy_slot addr: %p", 339*0Sstevel@tonic-gate (void *)softs, (void *)&(softs->amr_busyslots))); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate if (pci_config_setup(dev, &(softs->pciconfig_handle)) 342*0Sstevel@tonic-gate != DDI_SUCCESS) { 343*0Sstevel@tonic-gate goto error_out; 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate softs->state |= AMR_STATE_PCI_CONFIG_SETUP; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate error = ddi_regs_map_setup(dev, 1, &cfgaddr, 0, 0, 348*0Sstevel@tonic-gate &accattr, &(softs->regsmap_handle)); 349*0Sstevel@tonic-gate if (error != DDI_SUCCESS) { 350*0Sstevel@tonic-gate goto error_out; 351*0Sstevel@tonic-gate } 352*0Sstevel@tonic-gate softs->state |= AMR_STATE_PCI_MEM_MAPPED; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * Determine board type. 356*0Sstevel@tonic-gate */ 357*0Sstevel@tonic-gate command = pci_config_get16(softs->pciconfig_handle, PCI_CONF_COMM); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate /* 360*0Sstevel@tonic-gate * Make sure we are going to be able to talk to this board. 361*0Sstevel@tonic-gate */ 362*0Sstevel@tonic-gate if ((command & PCI_COMM_MAE) == 0) { 363*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "memory window not available")); 364*0Sstevel@tonic-gate goto error_out; 365*0Sstevel@tonic-gate } 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate /* force the busmaster enable bit on */ 368*0Sstevel@tonic-gate if (!(command & PCI_COMM_ME)) { 369*0Sstevel@tonic-gate command |= PCI_COMM_ME; 370*0Sstevel@tonic-gate pci_config_put16(softs->pciconfig_handle, 371*0Sstevel@tonic-gate PCI_CONF_COMM, command); 372*0Sstevel@tonic-gate command = pci_config_get16(softs->pciconfig_handle, 373*0Sstevel@tonic-gate PCI_CONF_COMM); 374*0Sstevel@tonic-gate if (!(command & PCI_COMM_ME)) 375*0Sstevel@tonic-gate goto error_out; 376*0Sstevel@tonic-gate } 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * Allocate and connect our interrupt. 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate if (ddi_intr_hilevel(dev, 0) != 0) { 382*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "High level interrupt is not supported!")); 383*0Sstevel@tonic-gate goto error_out; 384*0Sstevel@tonic-gate } 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate if (ddi_get_iblock_cookie(dev, 0, &softs->iblock_cookiep) 387*0Sstevel@tonic-gate != DDI_SUCCESS) { 388*0Sstevel@tonic-gate goto error_out; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate mutex_init(&softs->cmd_mutex, NULL, MUTEX_DRIVER, 392*0Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 393*0Sstevel@tonic-gate mutex_init(&softs->queue_mutex, NULL, MUTEX_DRIVER, 394*0Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 395*0Sstevel@tonic-gate mutex_init(&softs->periodic_mutex, NULL, MUTEX_DRIVER, 396*0Sstevel@tonic-gate softs->iblock_cookiep); /* should be used in interrupt */ 397*0Sstevel@tonic-gate /* sychronize waits for the busy slots via this cv */ 398*0Sstevel@tonic-gate cv_init(&softs->cmd_cv, NULL, CV_DRIVER, NULL); 399*0Sstevel@tonic-gate softs->state |= AMR_STATE_KMUTEX_INITED; 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate /* 402*0Sstevel@tonic-gate * Do bus-independent initialisation, bring controller online. 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate if (amr_setup_mbox(softs) != DDI_SUCCESS) 405*0Sstevel@tonic-gate goto error_out; 406*0Sstevel@tonic-gate softs->state |= AMR_STATE_MAILBOX_SETUP; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate if (amr_setup_sg(softs) != DDI_SUCCESS) 409*0Sstevel@tonic-gate goto error_out; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate softs->state |= AMR_STATE_SG_TABLES_SETUP; 412*0Sstevel@tonic-gate 413*0Sstevel@tonic-gate if (amr_query_controller(softs) != DDI_SUCCESS) 414*0Sstevel@tonic-gate goto error_out; 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate /* 417*0Sstevel@tonic-gate * A taskq is created for dispatching the waiting queue processing 418*0Sstevel@tonic-gate * thread. The threads number equals to the logic drive number and 419*0Sstevel@tonic-gate * the thread number should be 1 if there is no logic driver is 420*0Sstevel@tonic-gate * configured for this instance. 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate if ((softs->amr_taskq = ddi_taskq_create(dev, "amr_taskq", 423*0Sstevel@tonic-gate MAX(softs->amr_nlogdrives, 1), TASKQ_DEFAULTPRI, 0)) == NULL) { 424*0Sstevel@tonic-gate goto error_out; 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate softs->state |= AMR_STATE_TASKQ_SETUP; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate if (ddi_add_intr(dev, 0, &softs->iblock_cookiep, NULL, 429*0Sstevel@tonic-gate amr_intr, (caddr_t)softs) != DDI_SUCCESS) { 430*0Sstevel@tonic-gate goto error_out; 431*0Sstevel@tonic-gate } 432*0Sstevel@tonic-gate softs->state |= AMR_STATE_INTR_SETUP; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* set up the tran interface */ 435*0Sstevel@tonic-gate if (amr_setup_tran(softs->dev_info_p, softs) != DDI_SUCCESS) { 436*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "setup tran failed")); 437*0Sstevel@tonic-gate goto error_out; 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate softs->state |= AMR_STATE_TRAN_SETUP; 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* schedule a thread for periodic check */ 442*0Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 443*0Sstevel@tonic-gate softs->timeout_t = timeout(amr_periodic, (void *)softs, 444*0Sstevel@tonic-gate drv_usectohz(500000*AMR_PERIODIC_TIMEOUT)); 445*0Sstevel@tonic-gate softs->state |= AMR_STATE_TIMEOUT_ENABLED; 446*0Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 447*0Sstevel@tonic-gate 448*0Sstevel@tonic-gate /* print firmware information in verbose mode */ 449*0Sstevel@tonic-gate cmn_err(CE_CONT, "?MegaRaid %s %s attached.", 450*0Sstevel@tonic-gate softs->amr_product_info.pi_product_name, 451*0Sstevel@tonic-gate softs->amr_product_info.pi_firmware_ver); 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate /* clear any interrupts */ 454*0Sstevel@tonic-gate AMR_QCLEAR_INTR(softs); 455*0Sstevel@tonic-gate return (DDI_SUCCESS); 456*0Sstevel@tonic-gate 457*0Sstevel@tonic-gate error_out: 458*0Sstevel@tonic-gate if (softs->state & AMR_STATE_INTR_SETUP) { 459*0Sstevel@tonic-gate ddi_remove_intr(dev, 0, softs->iblock_cookiep); 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate if (softs->state & AMR_STATE_TASKQ_SETUP) { 462*0Sstevel@tonic-gate ddi_taskq_destroy(softs->amr_taskq); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate if (softs->state & AMR_STATE_SG_TABLES_SETUP) { 465*0Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 466*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 467*0Sstevel@tonic-gate softs->sg_items[i].sg_handle); 468*0Sstevel@tonic-gate (void) ddi_dma_mem_free( 469*0Sstevel@tonic-gate &((softs->sg_items[i]).sg_acc_handle)); 470*0Sstevel@tonic-gate (void) ddi_dma_free_handle( 471*0Sstevel@tonic-gate &(softs->sg_items[i].sg_handle)); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate } 474*0Sstevel@tonic-gate if (softs->state & AMR_STATE_MAILBOX_SETUP) { 475*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 476*0Sstevel@tonic-gate (void) ddi_dma_mem_free(&softs->mbox_acc_handle); 477*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 478*0Sstevel@tonic-gate } 479*0Sstevel@tonic-gate if (softs->state & AMR_STATE_KMUTEX_INITED) { 480*0Sstevel@tonic-gate mutex_destroy(&softs->queue_mutex); 481*0Sstevel@tonic-gate mutex_destroy(&softs->cmd_mutex); 482*0Sstevel@tonic-gate mutex_destroy(&softs->periodic_mutex); 483*0Sstevel@tonic-gate cv_destroy(&softs->cmd_cv); 484*0Sstevel@tonic-gate } 485*0Sstevel@tonic-gate if (softs->state & AMR_STATE_PCI_MEM_MAPPED) 486*0Sstevel@tonic-gate ddi_regs_map_free(&softs->regsmap_handle); 487*0Sstevel@tonic-gate if (softs->state & AMR_STATE_PCI_CONFIG_SETUP) 488*0Sstevel@tonic-gate pci_config_teardown(&softs->pciconfig_handle); 489*0Sstevel@tonic-gate if (softs->state & AMR_STATE_SOFT_STATE_SETUP) 490*0Sstevel@tonic-gate ddi_soft_state_free(amr_softstatep, instance); 491*0Sstevel@tonic-gate return (DDI_FAILURE); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* 495*0Sstevel@tonic-gate * Bring the controller down to a dormant state and detach all child devices. 496*0Sstevel@tonic-gate * This function is called during detach, system shutdown. 497*0Sstevel@tonic-gate * 498*0Sstevel@tonic-gate * Note that we can assume that the bufq on the controller is empty, as we won't 499*0Sstevel@tonic-gate * allow shutdown if any device is open. 500*0Sstevel@tonic-gate */ 501*0Sstevel@tonic-gate /*ARGSUSED*/ 502*0Sstevel@tonic-gate static int amr_detach(dev_info_t *dev, ddi_detach_cmd_t cmd) 503*0Sstevel@tonic-gate { 504*0Sstevel@tonic-gate struct amr_softs *softs; 505*0Sstevel@tonic-gate int instance; 506*0Sstevel@tonic-gate uint32_t i, done_flag; 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate instance = ddi_get_instance(dev); 509*0Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate /* flush the controllor */ 512*0Sstevel@tonic-gate if (amr_flush(softs) != 0) { 513*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "device shutdown failed")); 514*0Sstevel@tonic-gate return (EIO); 515*0Sstevel@tonic-gate } 516*0Sstevel@tonic-gate 517*0Sstevel@tonic-gate /* release the amr timer */ 518*0Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 519*0Sstevel@tonic-gate softs->state &= ~AMR_STATE_TIMEOUT_ENABLED; 520*0Sstevel@tonic-gate if (softs->timeout_t) { 521*0Sstevel@tonic-gate (void) untimeout(softs->timeout_t); 522*0Sstevel@tonic-gate softs->timeout_t = 0; 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 525*0Sstevel@tonic-gate 526*0Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 527*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 528*0Sstevel@tonic-gate softs->sg_items[i].sg_handle); 529*0Sstevel@tonic-gate (void) ddi_dma_mem_free( 530*0Sstevel@tonic-gate &((softs->sg_items[i]).sg_acc_handle)); 531*0Sstevel@tonic-gate (void) ddi_dma_free_handle( 532*0Sstevel@tonic-gate &(softs->sg_items[i].sg_handle)); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 536*0Sstevel@tonic-gate (void) ddi_dma_mem_free(&softs->mbox_acc_handle); 537*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 538*0Sstevel@tonic-gate 539*0Sstevel@tonic-gate /* disconnect the interrupt handler */ 540*0Sstevel@tonic-gate ddi_remove_intr(softs->dev_info_p, 0, softs->iblock_cookiep); 541*0Sstevel@tonic-gate 542*0Sstevel@tonic-gate /* wait for the completion of current in-progress interruptes */ 543*0Sstevel@tonic-gate AMR_DELAY((softs->amr_interrupts_counter == 0), 1000, done_flag); 544*0Sstevel@tonic-gate if (!done_flag) { 545*0Sstevel@tonic-gate cmn_err(CE_WARN, "Suspicious interrupts in-progress."); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate ddi_taskq_destroy(softs->amr_taskq); 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate (void) scsi_hba_detach(dev); 551*0Sstevel@tonic-gate scsi_hba_tran_free(softs->hba_tran); 552*0Sstevel@tonic-gate ddi_regs_map_free(&softs->regsmap_handle); 553*0Sstevel@tonic-gate pci_config_teardown(&softs->pciconfig_handle); 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate mutex_destroy(&softs->queue_mutex); 556*0Sstevel@tonic-gate mutex_destroy(&softs->cmd_mutex); 557*0Sstevel@tonic-gate mutex_destroy(&softs->periodic_mutex); 558*0Sstevel@tonic-gate cv_destroy(&softs->cmd_cv); 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate /* print firmware information in verbose mode */ 561*0Sstevel@tonic-gate cmn_err(CE_NOTE, "?MegaRaid %s %s detached.", 562*0Sstevel@tonic-gate softs->amr_product_info.pi_product_name, 563*0Sstevel@tonic-gate softs->amr_product_info.pi_firmware_ver); 564*0Sstevel@tonic-gate 565*0Sstevel@tonic-gate ddi_soft_state_free(amr_softstatep, instance); 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate return (DDI_SUCCESS); 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate /*ARGSUSED*/ 572*0Sstevel@tonic-gate static int amr_info(dev_info_t *dip, ddi_info_cmd_t infocmd, 573*0Sstevel@tonic-gate void *arg, void **result) 574*0Sstevel@tonic-gate { 575*0Sstevel@tonic-gate struct amr_softs *softs; 576*0Sstevel@tonic-gate int instance; 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate instance = ddi_get_instance(dip); 579*0Sstevel@tonic-gate 580*0Sstevel@tonic-gate switch (infocmd) { 581*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 582*0Sstevel@tonic-gate softs = ddi_get_soft_state(amr_softstatep, instance); 583*0Sstevel@tonic-gate if (softs != NULL) { 584*0Sstevel@tonic-gate *result = softs->dev_info_p; 585*0Sstevel@tonic-gate return (DDI_SUCCESS); 586*0Sstevel@tonic-gate } else { 587*0Sstevel@tonic-gate *result = NULL; 588*0Sstevel@tonic-gate return (DDI_FAILURE); 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 591*0Sstevel@tonic-gate *(int *)result = instance; 592*0Sstevel@tonic-gate break; 593*0Sstevel@tonic-gate default: 594*0Sstevel@tonic-gate break; 595*0Sstevel@tonic-gate } 596*0Sstevel@tonic-gate return (DDI_SUCCESS); 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* 600*0Sstevel@tonic-gate * Take an interrupt, or be poked by other code to look for interrupt-worthy 601*0Sstevel@tonic-gate * status. 602*0Sstevel@tonic-gate */ 603*0Sstevel@tonic-gate static uint_t 604*0Sstevel@tonic-gate amr_intr(caddr_t arg) 605*0Sstevel@tonic-gate { 606*0Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)arg; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate softs->amr_interrupts_counter++; 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate if (AMR_QGET_ODB(softs) != AMR_QODB_READY) { 611*0Sstevel@tonic-gate softs->amr_interrupts_counter--; 612*0Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED); 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate 615*0Sstevel@tonic-gate /* collect finished commands, queue anything waiting */ 616*0Sstevel@tonic-gate amr_done(softs); 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate softs->amr_interrupts_counter--; 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate return (DDI_INTR_CLAIMED); 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* 625*0Sstevel@tonic-gate * Setup the amr mailbox 626*0Sstevel@tonic-gate */ 627*0Sstevel@tonic-gate static int 628*0Sstevel@tonic-gate amr_setup_mbox(struct amr_softs *softs) 629*0Sstevel@tonic-gate { 630*0Sstevel@tonic-gate uint32_t move; 631*0Sstevel@tonic-gate size_t mbox_len; 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate if (ddi_dma_alloc_handle( 634*0Sstevel@tonic-gate softs->dev_info_p, 635*0Sstevel@tonic-gate &addr_dma_attr, 636*0Sstevel@tonic-gate DDI_DMA_SLEEP, 637*0Sstevel@tonic-gate NULL, 638*0Sstevel@tonic-gate &softs->mbox_dma_handle) != DDI_SUCCESS) { 639*0Sstevel@tonic-gate 640*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Cannot alloc dma handle for mailbox")); 641*0Sstevel@tonic-gate goto error_out; 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate 644*0Sstevel@tonic-gate if (ddi_dma_mem_alloc( 645*0Sstevel@tonic-gate softs->mbox_dma_handle, 646*0Sstevel@tonic-gate sizeof (struct amr_mailbox) + 16, 647*0Sstevel@tonic-gate &accattr, 648*0Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 649*0Sstevel@tonic-gate DDI_DMA_SLEEP, 650*0Sstevel@tonic-gate NULL, 651*0Sstevel@tonic-gate (caddr_t *)(&softs->mbox), 652*0Sstevel@tonic-gate &mbox_len, 653*0Sstevel@tonic-gate &softs->mbox_acc_handle) != 654*0Sstevel@tonic-gate DDI_SUCCESS) { 655*0Sstevel@tonic-gate 656*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "Cannot alloc dma memory for mailbox")); 657*0Sstevel@tonic-gate goto error_out; 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate if (ddi_dma_addr_bind_handle( 661*0Sstevel@tonic-gate softs->mbox_dma_handle, 662*0Sstevel@tonic-gate NULL, 663*0Sstevel@tonic-gate (caddr_t)softs->mbox, 664*0Sstevel@tonic-gate sizeof (struct amr_mailbox) + 16, 665*0Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 666*0Sstevel@tonic-gate DDI_DMA_SLEEP, 667*0Sstevel@tonic-gate NULL, 668*0Sstevel@tonic-gate &softs->mbox_dma_cookie, 669*0Sstevel@tonic-gate &softs->mbox_dma_cookien) != DDI_DMA_MAPPED) { 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Cannot bind dma memory for mailbox")); 672*0Sstevel@tonic-gate goto error_out; 673*0Sstevel@tonic-gate } 674*0Sstevel@tonic-gate 675*0Sstevel@tonic-gate if (softs->mbox_dma_cookien != 1) 676*0Sstevel@tonic-gate goto error_out; 677*0Sstevel@tonic-gate 678*0Sstevel@tonic-gate /* The phy address of mailbox must be aligned on a 16-byte boundary */ 679*0Sstevel@tonic-gate move = 16 - (((uint32_t)softs->mbox_dma_cookie.dmac_address)&0xf); 680*0Sstevel@tonic-gate softs->mbox_phyaddr = 681*0Sstevel@tonic-gate (softs->mbox_dma_cookie.dmac_address + move); 682*0Sstevel@tonic-gate 683*0Sstevel@tonic-gate softs->mailbox = 684*0Sstevel@tonic-gate (struct amr_mailbox *)(((uintptr_t)softs->mbox) + move); 685*0Sstevel@tonic-gate 686*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "phraddy=%x, mailbox=%p, softs->mbox=%p, move=%x", 687*0Sstevel@tonic-gate softs->mbox_phyaddr, (void *)softs->mailbox, 688*0Sstevel@tonic-gate softs->mbox, move)); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate return (DDI_SUCCESS); 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate error_out: 693*0Sstevel@tonic-gate if (softs->mbox_dma_cookien) 694*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle(softs->mbox_dma_handle); 695*0Sstevel@tonic-gate if (softs->mbox_acc_handle) { 696*0Sstevel@tonic-gate (void) ddi_dma_mem_free(&(softs->mbox_acc_handle)); 697*0Sstevel@tonic-gate softs->mbox_acc_handle = NULL; 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate if (softs->mbox_dma_handle) { 700*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&softs->mbox_dma_handle); 701*0Sstevel@tonic-gate softs->mbox_dma_handle = NULL; 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate return (DDI_FAILURE); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate /* 708*0Sstevel@tonic-gate * Perform a periodic check of the controller status 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate static void 711*0Sstevel@tonic-gate amr_periodic(void *data) 712*0Sstevel@tonic-gate { 713*0Sstevel@tonic-gate uint32_t i; 714*0Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)data; 715*0Sstevel@tonic-gate struct scsi_pkt *pkt; 716*0Sstevel@tonic-gate register struct amr_command *ac; 717*0Sstevel@tonic-gate 718*0Sstevel@tonic-gate for (i = 0; i < softs->sg_max_count; i++) { 719*0Sstevel@tonic-gate if (softs->busycmd[i] == NULL) 720*0Sstevel@tonic-gate continue; 721*0Sstevel@tonic-gate 722*0Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 723*0Sstevel@tonic-gate 724*0Sstevel@tonic-gate if (softs->busycmd[i] == NULL) { 725*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 726*0Sstevel@tonic-gate continue; 727*0Sstevel@tonic-gate } 728*0Sstevel@tonic-gate 729*0Sstevel@tonic-gate pkt = softs->busycmd[i]->pkt; 730*0Sstevel@tonic-gate 731*0Sstevel@tonic-gate if ((pkt->pkt_time != 0) && 732*0Sstevel@tonic-gate (ddi_get_time() - 733*0Sstevel@tonic-gate softs->busycmd[i]->ac_timestamp > 734*0Sstevel@tonic-gate pkt->pkt_time)) { 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate cmn_err(CE_WARN, 737*0Sstevel@tonic-gate "timed out package detected,\ 738*0Sstevel@tonic-gate sc = %p, pkt = %p, index = %d, ac = %p", 739*0Sstevel@tonic-gate (void *)softs, 740*0Sstevel@tonic-gate (void *)pkt, 741*0Sstevel@tonic-gate i, 742*0Sstevel@tonic-gate (void *)softs->busycmd[i]); 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate ac = softs->busycmd[i]; 745*0Sstevel@tonic-gate ac->ac_next = NULL; 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate /* pull command from the busy index */ 748*0Sstevel@tonic-gate softs->busycmd[i] = NULL; 749*0Sstevel@tonic-gate if (softs->amr_busyslots > 0) 750*0Sstevel@tonic-gate softs->amr_busyslots--; 751*0Sstevel@tonic-gate if (softs->amr_busyslots == 0) 752*0Sstevel@tonic-gate cv_broadcast(&softs->cmd_cv); 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate pkt = ac->pkt; 757*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 758*0Sstevel@tonic-gate pkt->pkt_statistics |= STAT_TIMEOUT; 759*0Sstevel@tonic-gate pkt->pkt_reason = CMD_TIMEOUT; 760*0Sstevel@tonic-gate if (!(pkt->pkt_flags & 761*0Sstevel@tonic-gate FLAG_NOINTR) && pkt->pkt_comp) { 762*0Sstevel@tonic-gate /* call pkt callback */ 763*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 764*0Sstevel@tonic-gate } 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate } else { 767*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 768*0Sstevel@tonic-gate } 769*0Sstevel@tonic-gate } 770*0Sstevel@tonic-gate 771*0Sstevel@tonic-gate /* restart the amr timer */ 772*0Sstevel@tonic-gate mutex_enter(&softs->periodic_mutex); 773*0Sstevel@tonic-gate if (softs->state & AMR_STATE_TIMEOUT_ENABLED) 774*0Sstevel@tonic-gate softs->timeout_t = timeout(amr_periodic, (void *)softs, 775*0Sstevel@tonic-gate drv_usectohz(500000*AMR_PERIODIC_TIMEOUT)); 776*0Sstevel@tonic-gate mutex_exit(&softs->periodic_mutex); 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate /* 780*0Sstevel@tonic-gate * Interrogate the controller for the operational parameters we require. 781*0Sstevel@tonic-gate */ 782*0Sstevel@tonic-gate static int 783*0Sstevel@tonic-gate amr_query_controller(struct amr_softs *softs) 784*0Sstevel@tonic-gate { 785*0Sstevel@tonic-gate struct amr_enquiry3 *aex; 786*0Sstevel@tonic-gate struct amr_prodinfo *ap; 787*0Sstevel@tonic-gate struct amr_enquiry *ae; 788*0Sstevel@tonic-gate uint32_t ldrv; 789*0Sstevel@tonic-gate int instance; 790*0Sstevel@tonic-gate 791*0Sstevel@tonic-gate /* 792*0Sstevel@tonic-gate * If we haven't found the real limit yet, let us have a couple of 793*0Sstevel@tonic-gate * commands in order to be able to probe. 794*0Sstevel@tonic-gate */ 795*0Sstevel@tonic-gate if (softs->maxio == 0) 796*0Sstevel@tonic-gate softs->maxio = 2; 797*0Sstevel@tonic-gate 798*0Sstevel@tonic-gate instance = ddi_get_instance(softs->dev_info_p); 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate /* 801*0Sstevel@tonic-gate * Try to issue an ENQUIRY3 command 802*0Sstevel@tonic-gate */ 803*0Sstevel@tonic-gate if ((aex = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, AMR_CMD_CONFIG, 804*0Sstevel@tonic-gate AMR_CONFIG_ENQ3, AMR_CONFIG_ENQ3_SOLICITED_FULL)) != NULL) { 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "First enquiry")); 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate for (ldrv = 0; ldrv < aex->ae_numldrives; ldrv++) { 809*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_size = 810*0Sstevel@tonic-gate aex->ae_drivesize[ldrv]; 811*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = 812*0Sstevel@tonic-gate aex->ae_drivestate[ldrv]; 813*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties = 814*0Sstevel@tonic-gate aex->ae_driveprop[ldrv]; 815*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 816*0Sstevel@tonic-gate " drive %d: size: %d state %x properties %x\n", 817*0Sstevel@tonic-gate ldrv, 818*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_size, 819*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_state, 820*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties)); 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate if (softs->logic_drive[ldrv].al_state == AMR_LDRV_OFFLINE) 823*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!instance %d log-drive %d is offline", 824*0Sstevel@tonic-gate instance, ldrv); 825*0Sstevel@tonic-gate else 826*0Sstevel@tonic-gate softs->amr_nlogdrives++; 827*0Sstevel@tonic-gate } 828*0Sstevel@tonic-gate kmem_free(aex, AMR_ENQ_BUFFER_SIZE); 829*0Sstevel@tonic-gate 830*0Sstevel@tonic-gate if ((ap = amr_enquiry(softs, AMR_ENQ_BUFFER_SIZE, 831*0Sstevel@tonic-gate AMR_CMD_CONFIG, AMR_CONFIG_PRODUCT_INFO, 0)) == NULL) { 832*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 833*0Sstevel@tonic-gate "Cannot obtain product data from controller")); 834*0Sstevel@tonic-gate return (EIO); 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate softs->maxdrives = AMR_40LD_MAXDRIVES; 838*0Sstevel@tonic-gate softs->maxchan = ap->ap_nschan; 839*0Sstevel@tonic-gate softs->maxio = ap->ap_maxio; 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate bcopy(ap->ap_firmware, softs->amr_product_info.pi_firmware_ver, 842*0Sstevel@tonic-gate AMR_FIRMWARE_VER_SIZE); 843*0Sstevel@tonic-gate softs->amr_product_info. 844*0Sstevel@tonic-gate pi_firmware_ver[AMR_FIRMWARE_VER_SIZE] = 0; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate bcopy(ap->ap_product, softs->amr_product_info.pi_product_name, 847*0Sstevel@tonic-gate AMR_PRODUCT_INFO_SIZE); 848*0Sstevel@tonic-gate softs->amr_product_info. 849*0Sstevel@tonic-gate pi_product_name[AMR_PRODUCT_INFO_SIZE] = 0; 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate kmem_free(ap, AMR_ENQ_BUFFER_SIZE); 852*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "maxio=%d", softs->maxio)); 853*0Sstevel@tonic-gate } else { 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "First enquiry failed, \ 856*0Sstevel@tonic-gate so try another way")); 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate /* failed, try the 8LD ENQUIRY commands */ 859*0Sstevel@tonic-gate if ((ae = (struct amr_enquiry *)amr_enquiry(softs, 860*0Sstevel@tonic-gate AMR_ENQ_BUFFER_SIZE, AMR_CMD_EXT_ENQUIRY2, 0, 0)) 861*0Sstevel@tonic-gate == NULL) { 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate if ((ae = (struct amr_enquiry *)amr_enquiry(softs, 864*0Sstevel@tonic-gate AMR_ENQ_BUFFER_SIZE, AMR_CMD_ENQUIRY, 0, 0)) 865*0Sstevel@tonic-gate == NULL) { 866*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 867*0Sstevel@tonic-gate "Cannot obtain configuration data")); 868*0Sstevel@tonic-gate return (EIO); 869*0Sstevel@tonic-gate } 870*0Sstevel@tonic-gate ae->ae_signature = 0; 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate /* 874*0Sstevel@tonic-gate * Fetch current state of logical drives. 875*0Sstevel@tonic-gate */ 876*0Sstevel@tonic-gate for (ldrv = 0; ldrv < ae->ae_ldrv.al_numdrives; ldrv++) { 877*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_size = 878*0Sstevel@tonic-gate ae->ae_ldrv.al_size[ldrv]; 879*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = 880*0Sstevel@tonic-gate ae->ae_ldrv.al_state[ldrv]; 881*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties = 882*0Sstevel@tonic-gate ae->ae_ldrv.al_properties[ldrv]; 883*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 884*0Sstevel@tonic-gate " ********* drive %d: %d state %x properties %x", 885*0Sstevel@tonic-gate ldrv, 886*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_size, 887*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_state, 888*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_properties)); 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate if (softs->logic_drive[ldrv].al_state == AMR_LDRV_OFFLINE) 891*0Sstevel@tonic-gate cmn_err(CE_NOTE, "!instance %d log-drive %d is offline", 892*0Sstevel@tonic-gate instance, ldrv); 893*0Sstevel@tonic-gate else 894*0Sstevel@tonic-gate softs->amr_nlogdrives++; 895*0Sstevel@tonic-gate } 896*0Sstevel@tonic-gate 897*0Sstevel@tonic-gate softs->maxdrives = AMR_8LD_MAXDRIVES; 898*0Sstevel@tonic-gate softs->maxchan = ae->ae_adapter.aa_channels; 899*0Sstevel@tonic-gate softs->maxio = ae->ae_adapter.aa_maxio; 900*0Sstevel@tonic-gate kmem_free(ae, AMR_ENQ_BUFFER_SIZE); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate /* 904*0Sstevel@tonic-gate * Mark remaining drives as unused. 905*0Sstevel@tonic-gate */ 906*0Sstevel@tonic-gate for (; ldrv < AMR_MAXLD; ldrv++) 907*0Sstevel@tonic-gate softs->logic_drive[ldrv].al_state = AMR_LDRV_OFFLINE; 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate /* 910*0Sstevel@tonic-gate * Cap the maximum number of outstanding I/Os. AMI's driver 911*0Sstevel@tonic-gate * doesn't trust the controller's reported value, and lockups have 912*0Sstevel@tonic-gate * been seen when we do. 913*0Sstevel@tonic-gate */ 914*0Sstevel@tonic-gate softs->maxio = MIN(softs->maxio, AMR_LIMITCMD); 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate return (DDI_SUCCESS); 917*0Sstevel@tonic-gate } 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate /* 920*0Sstevel@tonic-gate * Run a generic enquiry-style command. 921*0Sstevel@tonic-gate */ 922*0Sstevel@tonic-gate static void * 923*0Sstevel@tonic-gate amr_enquiry(struct amr_softs *softs, size_t bufsize, uint8_t cmd, 924*0Sstevel@tonic-gate uint8_t cmdsub, uint8_t cmdqual) 925*0Sstevel@tonic-gate { 926*0Sstevel@tonic-gate struct amr_command ac; 927*0Sstevel@tonic-gate void *result; 928*0Sstevel@tonic-gate 929*0Sstevel@tonic-gate result = NULL; 930*0Sstevel@tonic-gate 931*0Sstevel@tonic-gate bzero(&ac, sizeof (struct amr_command)); 932*0Sstevel@tonic-gate ac.ac_softs = softs; 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate /* set command flags */ 935*0Sstevel@tonic-gate ac.ac_flags |= AMR_CMD_DATAOUT; 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate /* build the command proper */ 938*0Sstevel@tonic-gate ac.mailbox.mb_command = cmd; 939*0Sstevel@tonic-gate ac.mailbox.mb_cmdsub = cmdsub; 940*0Sstevel@tonic-gate ac.mailbox.mb_cmdqual = cmdqual; 941*0Sstevel@tonic-gate 942*0Sstevel@tonic-gate if (amr_enquiry_mapcmd(&ac, bufsize) != DDI_SUCCESS) 943*0Sstevel@tonic-gate return (NULL); 944*0Sstevel@tonic-gate 945*0Sstevel@tonic-gate if (amr_poll_command(&ac) || ac.ac_status != 0) { 946*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "can not poll command, goto out")); 947*0Sstevel@tonic-gate amr_enquiry_unmapcmd(&ac); 948*0Sstevel@tonic-gate return (NULL); 949*0Sstevel@tonic-gate } 950*0Sstevel@tonic-gate 951*0Sstevel@tonic-gate /* allocate the response structure */ 952*0Sstevel@tonic-gate result = kmem_zalloc(bufsize, KM_SLEEP); 953*0Sstevel@tonic-gate 954*0Sstevel@tonic-gate bcopy(ac.ac_data, result, bufsize); 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate amr_enquiry_unmapcmd(&ac); 957*0Sstevel@tonic-gate return (result); 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate 960*0Sstevel@tonic-gate /* 961*0Sstevel@tonic-gate * Flush the controller's internal cache, return status. 962*0Sstevel@tonic-gate */ 963*0Sstevel@tonic-gate static int 964*0Sstevel@tonic-gate amr_flush(struct amr_softs *softs) 965*0Sstevel@tonic-gate { 966*0Sstevel@tonic-gate struct amr_command ac; 967*0Sstevel@tonic-gate int error = 0; 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate bzero(&ac, sizeof (struct amr_command)); 970*0Sstevel@tonic-gate ac.ac_softs = softs; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate ac.ac_flags |= AMR_CMD_DATAOUT; 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate /* build the command proper */ 975*0Sstevel@tonic-gate ac.mailbox.mb_command = AMR_CMD_FLUSH; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate /* have to poll, as the system may be going down or otherwise damaged */ 978*0Sstevel@tonic-gate if (error = amr_poll_command(&ac)) { 979*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "can not poll this cmd")); 980*0Sstevel@tonic-gate return (error); 981*0Sstevel@tonic-gate } 982*0Sstevel@tonic-gate 983*0Sstevel@tonic-gate return (error); 984*0Sstevel@tonic-gate } 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * Take a command, submit it to the controller and wait for it to return. 988*0Sstevel@tonic-gate * Returns nonzero on error. Can be safely called with interrupts enabled. 989*0Sstevel@tonic-gate */ 990*0Sstevel@tonic-gate static int 991*0Sstevel@tonic-gate amr_poll_command(struct amr_command *ac) 992*0Sstevel@tonic-gate { 993*0Sstevel@tonic-gate struct amr_softs *softs = ac->ac_softs; 994*0Sstevel@tonic-gate volatile uint32_t done_flag; 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_Poll bcopy(%p, %p, %d)", 997*0Sstevel@tonic-gate (void *)&ac->mailbox, 998*0Sstevel@tonic-gate (void *)softs->mailbox, 999*0Sstevel@tonic-gate (uint32_t)AMR_MBOX_CMDSIZE)); 1000*0Sstevel@tonic-gate 1001*0Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate while (softs->amr_busyslots != 0) 1004*0Sstevel@tonic-gate cv_wait(&softs->cmd_cv, &softs->cmd_mutex); 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * For read/write commands, the scatter/gather table should be 1008*0Sstevel@tonic-gate * filled, and the last entry in scatter/gather table will be used. 1009*0Sstevel@tonic-gate */ 1010*0Sstevel@tonic-gate if ((ac->mailbox.mb_command == AMR_CMD_LREAD) || 1011*0Sstevel@tonic-gate (ac->mailbox.mb_command == AMR_CMD_LWRITE)) { 1012*0Sstevel@tonic-gate bcopy(ac->sgtable, 1013*0Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_table, 1014*0Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG); 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate (void) ddi_dma_sync( 1017*0Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_handle, 1018*0Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate ac->mailbox.mb_physaddr = 1021*0Sstevel@tonic-gate softs->sg_items[softs->sg_max_count - 1].sg_phyaddr; 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate bcopy(&ac->mailbox, (void *)softs->mailbox, AMR_MBOX_CMDSIZE); 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate /* sync the dma memory */ 1027*0Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* clear the poll/ack fields in the mailbox */ 1030*0Sstevel@tonic-gate softs->mailbox->mb_ident = AMR_POLL_COMMAND_ID; 1031*0Sstevel@tonic-gate softs->mailbox->mb_nstatus = AMR_POLL_DEFAULT_NSTATUS; 1032*0Sstevel@tonic-gate softs->mailbox->mb_status = AMR_POLL_DEFAULT_STATUS; 1033*0Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 1034*0Sstevel@tonic-gate softs->mailbox->mb_ack = 0; 1035*0Sstevel@tonic-gate softs->mailbox->mb_busy = 1; 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_SUBMIT); 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate /* sync the dma memory */ 1040*0Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU); 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_nstatus != AMR_POLL_DEFAULT_NSTATUS), 1043*0Sstevel@tonic-gate 1000, done_flag); 1044*0Sstevel@tonic-gate if (!done_flag) { 1045*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 1046*0Sstevel@tonic-gate return (1); 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate ac->ac_status = softs->mailbox->mb_status; 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_poll == AMR_POLL_ACK), 1000, done_flag); 1052*0Sstevel@tonic-gate if (!done_flag) { 1053*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 1054*0Sstevel@tonic-gate return (1); 1055*0Sstevel@tonic-gate } 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 1058*0Sstevel@tonic-gate softs->mailbox->mb_ack = AMR_POLL_ACK; 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate /* acknowledge that we have the commands */ 1061*0Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 1062*0Sstevel@tonic-gate 1063*0Sstevel@tonic-gate AMR_DELAY(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1000, done_flag); 1064*0Sstevel@tonic-gate if (!done_flag) { 1065*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 1066*0Sstevel@tonic-gate return (1); 1067*0Sstevel@tonic-gate } 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 1070*0Sstevel@tonic-gate return (ac->ac_status != AMR_STATUS_SUCCESS); 1071*0Sstevel@tonic-gate } 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * setup the scatter/gather table 1075*0Sstevel@tonic-gate */ 1076*0Sstevel@tonic-gate static int 1077*0Sstevel@tonic-gate amr_setup_sg(struct amr_softs *softs) 1078*0Sstevel@tonic-gate { 1079*0Sstevel@tonic-gate uint32_t i; 1080*0Sstevel@tonic-gate size_t len; 1081*0Sstevel@tonic-gate ddi_dma_cookie_t cookie; 1082*0Sstevel@tonic-gate uint_t cookien; 1083*0Sstevel@tonic-gate 1084*0Sstevel@tonic-gate softs->sg_max_count = 0; 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate for (i = 0; i < AMR_MAXCMD; i++) { 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate /* reset the cookien */ 1089*0Sstevel@tonic-gate cookien = 0; 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate (softs->sg_items[i]).sg_handle = NULL; 1092*0Sstevel@tonic-gate if (ddi_dma_alloc_handle( 1093*0Sstevel@tonic-gate softs->dev_info_p, 1094*0Sstevel@tonic-gate &addr_dma_attr, 1095*0Sstevel@tonic-gate DDI_DMA_SLEEP, 1096*0Sstevel@tonic-gate NULL, 1097*0Sstevel@tonic-gate &((softs->sg_items[i]).sg_handle)) != DDI_SUCCESS) { 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1100*0Sstevel@tonic-gate "Cannot alloc dma handle for s/g table")); 1101*0Sstevel@tonic-gate goto error_out; 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate if (ddi_dma_mem_alloc((softs->sg_items[i]).sg_handle, 1105*0Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG, 1106*0Sstevel@tonic-gate &accattr, 1107*0Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1108*0Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 1109*0Sstevel@tonic-gate (caddr_t *)(&(softs->sg_items[i]).sg_table), 1110*0Sstevel@tonic-gate &len, 1111*0Sstevel@tonic-gate &(softs->sg_items[i]).sg_acc_handle) 1112*0Sstevel@tonic-gate != DDI_SUCCESS) { 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1115*0Sstevel@tonic-gate "Cannot allocate DMA memory")); 1116*0Sstevel@tonic-gate goto error_out; 1117*0Sstevel@tonic-gate } 1118*0Sstevel@tonic-gate 1119*0Sstevel@tonic-gate if (ddi_dma_addr_bind_handle( 1120*0Sstevel@tonic-gate (softs->sg_items[i]).sg_handle, 1121*0Sstevel@tonic-gate NULL, 1122*0Sstevel@tonic-gate (caddr_t)((softs->sg_items[i]).sg_table), 1123*0Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG, 1124*0Sstevel@tonic-gate DDI_DMA_RDWR | DDI_DMA_CONSISTENT, 1125*0Sstevel@tonic-gate DDI_DMA_SLEEP, 1126*0Sstevel@tonic-gate NULL, 1127*0Sstevel@tonic-gate &cookie, 1128*0Sstevel@tonic-gate &cookien) != DDI_DMA_MAPPED) { 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1131*0Sstevel@tonic-gate "Cannot bind communication area for s/g table")); 1132*0Sstevel@tonic-gate goto error_out; 1133*0Sstevel@tonic-gate } 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate if (cookien != 1) 1136*0Sstevel@tonic-gate goto error_out; 1137*0Sstevel@tonic-gate 1138*0Sstevel@tonic-gate softs->sg_items[i].sg_phyaddr = cookie.dmac_address; 1139*0Sstevel@tonic-gate softs->sg_max_count++; 1140*0Sstevel@tonic-gate } 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate return (DDI_SUCCESS); 1143*0Sstevel@tonic-gate 1144*0Sstevel@tonic-gate error_out: 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * Couldn't allocate/initialize all of the sg table entries. 1147*0Sstevel@tonic-gate * Clean up the partially-initialized entry before returning. 1148*0Sstevel@tonic-gate */ 1149*0Sstevel@tonic-gate if (cookien) { 1150*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle((softs->sg_items[i]).sg_handle); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate if ((softs->sg_items[i]).sg_acc_handle) { 1153*0Sstevel@tonic-gate (void) ddi_dma_mem_free(&((softs->sg_items[i]).sg_acc_handle)); 1154*0Sstevel@tonic-gate (softs->sg_items[i]).sg_acc_handle = NULL; 1155*0Sstevel@tonic-gate } 1156*0Sstevel@tonic-gate if ((softs->sg_items[i]).sg_handle) { 1157*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&((softs->sg_items[i]).sg_handle)); 1158*0Sstevel@tonic-gate (softs->sg_items[i]).sg_handle = NULL; 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate 1161*0Sstevel@tonic-gate /* 1162*0Sstevel@tonic-gate * At least two sg table entries are needed. One is for regular data 1163*0Sstevel@tonic-gate * I/O commands, the other is for poll I/O commands. 1164*0Sstevel@tonic-gate */ 1165*0Sstevel@tonic-gate return (softs->sg_max_count > 1 ? DDI_SUCCESS : DDI_FAILURE); 1166*0Sstevel@tonic-gate } 1167*0Sstevel@tonic-gate 1168*0Sstevel@tonic-gate /* 1169*0Sstevel@tonic-gate * Map/unmap (ac)'s data in the controller's addressable space as required. 1170*0Sstevel@tonic-gate * 1171*0Sstevel@tonic-gate * These functions may be safely called multiple times on a given command. 1172*0Sstevel@tonic-gate */ 1173*0Sstevel@tonic-gate static void 1174*0Sstevel@tonic-gate amr_setup_dmamap(struct amr_command *ac, ddi_dma_cookie_t *buffer_dma_cookiep, 1175*0Sstevel@tonic-gate int nsegments) 1176*0Sstevel@tonic-gate { 1177*0Sstevel@tonic-gate struct amr_sgentry *sg; 1178*0Sstevel@tonic-gate uint32_t i, size; 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate sg = ac->sgtable; 1181*0Sstevel@tonic-gate 1182*0Sstevel@tonic-gate size = 0; 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate ac->mailbox.mb_nsgelem = (uint8_t)nsegments; 1185*0Sstevel@tonic-gate for (i = 0; i < nsegments; i++, sg++) { 1186*0Sstevel@tonic-gate sg->sg_addr = buffer_dma_cookiep->dmac_address; 1187*0Sstevel@tonic-gate sg->sg_count = buffer_dma_cookiep->dmac_size; 1188*0Sstevel@tonic-gate size += sg->sg_count; 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate /* 1191*0Sstevel@tonic-gate * There is no next cookie if the end of the current 1192*0Sstevel@tonic-gate * window is reached. Otherwise, the next cookie 1193*0Sstevel@tonic-gate * would be found. 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate if ((ac->current_cookie + i + 1) != ac->num_of_cookie) 1196*0Sstevel@tonic-gate ddi_dma_nextcookie(ac->buffer_dma_handle, 1197*0Sstevel@tonic-gate buffer_dma_cookiep); 1198*0Sstevel@tonic-gate } 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate ac->transfer_size = size; 1201*0Sstevel@tonic-gate ac->data_transfered += size; 1202*0Sstevel@tonic-gate } 1203*0Sstevel@tonic-gate 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate /* 1206*0Sstevel@tonic-gate * map the amr command for enquiry, allocate the DMA resource 1207*0Sstevel@tonic-gate */ 1208*0Sstevel@tonic-gate static int 1209*0Sstevel@tonic-gate amr_enquiry_mapcmd(struct amr_command *ac, uint32_t data_size) 1210*0Sstevel@tonic-gate { 1211*0Sstevel@tonic-gate struct amr_softs *softs = ac->ac_softs; 1212*0Sstevel@tonic-gate size_t len; 1213*0Sstevel@tonic-gate uint_t dma_flags; 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_enquiry_mapcmd called, ac=%p, flags=%x", 1216*0Sstevel@tonic-gate (void *)ac, ac->ac_flags)); 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 1219*0Sstevel@tonic-gate dma_flags = DDI_DMA_READ; 1220*0Sstevel@tonic-gate } else { 1221*0Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE; 1222*0Sstevel@tonic-gate } 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate /* process the DMA by address bind mode */ 1227*0Sstevel@tonic-gate if (ddi_dma_alloc_handle(softs->dev_info_p, 1228*0Sstevel@tonic-gate &addr_dma_attr, DDI_DMA_SLEEP, NULL, 1229*0Sstevel@tonic-gate &ac->buffer_dma_handle) != 1230*0Sstevel@tonic-gate DDI_SUCCESS) { 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1233*0Sstevel@tonic-gate "Cannot allocate addr DMA tag")); 1234*0Sstevel@tonic-gate goto error_out; 1235*0Sstevel@tonic-gate } 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate if (ddi_dma_mem_alloc(ac->buffer_dma_handle, 1238*0Sstevel@tonic-gate data_size, 1239*0Sstevel@tonic-gate &accattr, 1240*0Sstevel@tonic-gate dma_flags, 1241*0Sstevel@tonic-gate DDI_DMA_SLEEP, 1242*0Sstevel@tonic-gate NULL, 1243*0Sstevel@tonic-gate (caddr_t *)&ac->ac_data, 1244*0Sstevel@tonic-gate &len, 1245*0Sstevel@tonic-gate &ac->buffer_acc_handle) != 1246*0Sstevel@tonic-gate DDI_SUCCESS) { 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1249*0Sstevel@tonic-gate "Cannot allocate DMA memory")); 1250*0Sstevel@tonic-gate goto error_out; 1251*0Sstevel@tonic-gate } 1252*0Sstevel@tonic-gate 1253*0Sstevel@tonic-gate if ((ddi_dma_addr_bind_handle( 1254*0Sstevel@tonic-gate ac->buffer_dma_handle, 1255*0Sstevel@tonic-gate NULL, ac->ac_data, data_size, dma_flags, 1256*0Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &ac->buffer_dma_cookie, 1257*0Sstevel@tonic-gate &ac->num_of_cookie)) != DDI_DMA_MAPPED) { 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1260*0Sstevel@tonic-gate "Cannot bind addr for dma")); 1261*0Sstevel@tonic-gate goto error_out; 1262*0Sstevel@tonic-gate } 1263*0Sstevel@tonic-gate 1264*0Sstevel@tonic-gate ac->ac_dataphys = (&ac->buffer_dma_cookie)->dmac_address; 1265*0Sstevel@tonic-gate 1266*0Sstevel@tonic-gate ((struct amr_mailbox *)&(ac->mailbox))->mb_param = 0; 1267*0Sstevel@tonic-gate ac->mailbox.mb_nsgelem = 0; 1268*0Sstevel@tonic-gate ac->mailbox.mb_physaddr = ac->ac_dataphys; 1269*0Sstevel@tonic-gate 1270*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate return (DDI_SUCCESS); 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate error_out: 1275*0Sstevel@tonic-gate if (ac->num_of_cookie) 1276*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 1277*0Sstevel@tonic-gate if (ac->buffer_acc_handle) { 1278*0Sstevel@tonic-gate ddi_dma_mem_free(&ac->buffer_acc_handle); 1279*0Sstevel@tonic-gate ac->buffer_acc_handle = NULL; 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate if (ac->buffer_dma_handle) { 1282*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 1283*0Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 1284*0Sstevel@tonic-gate } 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate return (DDI_FAILURE); 1287*0Sstevel@tonic-gate } 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate /* 1290*0Sstevel@tonic-gate * unmap the amr command for enquiry, free the DMA resource 1291*0Sstevel@tonic-gate */ 1292*0Sstevel@tonic-gate static void 1293*0Sstevel@tonic-gate amr_enquiry_unmapcmd(struct amr_command *ac) 1294*0Sstevel@tonic-gate { 1295*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_enquiry_unmapcmd called, ac=%p", 1296*0Sstevel@tonic-gate (void *)ac)); 1297*0Sstevel@tonic-gate 1298*0Sstevel@tonic-gate /* if the command involved data at all and was mapped */ 1299*0Sstevel@tonic-gate if ((ac->ac_flags & AMR_CMD_MAPPED) && ac->ac_data) { 1300*0Sstevel@tonic-gate if (ac->buffer_dma_handle) 1301*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 1302*0Sstevel@tonic-gate ac->buffer_dma_handle); 1303*0Sstevel@tonic-gate if (ac->buffer_acc_handle) { 1304*0Sstevel@tonic-gate ddi_dma_mem_free(&ac->buffer_acc_handle); 1305*0Sstevel@tonic-gate ac->buffer_acc_handle = NULL; 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate if (ac->buffer_dma_handle) { 1308*0Sstevel@tonic-gate (void) ddi_dma_free_handle( 1309*0Sstevel@tonic-gate &ac->buffer_dma_handle); 1310*0Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 1311*0Sstevel@tonic-gate } 1312*0Sstevel@tonic-gate } 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 1315*0Sstevel@tonic-gate } 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate /* 1318*0Sstevel@tonic-gate * map the amr command, allocate the DMA resource 1319*0Sstevel@tonic-gate */ 1320*0Sstevel@tonic-gate static int 1321*0Sstevel@tonic-gate amr_mapcmd(struct amr_command *ac) 1322*0Sstevel@tonic-gate { 1323*0Sstevel@tonic-gate uint_t dma_flags; 1324*0Sstevel@tonic-gate off_t off; 1325*0Sstevel@tonic-gate size_t len; 1326*0Sstevel@tonic-gate int error; 1327*0Sstevel@tonic-gate 1328*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_mapcmd called, ac=%p, flags=%x", 1329*0Sstevel@tonic-gate (void *)ac, ac->ac_flags)); 1330*0Sstevel@tonic-gate 1331*0Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 1332*0Sstevel@tonic-gate dma_flags = DDI_DMA_READ; 1333*0Sstevel@tonic-gate } else { 1334*0Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE; 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_PKT_CONSISTENT) { 1338*0Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 1339*0Sstevel@tonic-gate } 1340*0Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_PKT_DMA_PARTIAL) { 1341*0Sstevel@tonic-gate dma_flags |= DDI_DMA_PARTIAL; 1342*0Sstevel@tonic-gate } 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate if ((!(ac->ac_flags & AMR_CMD_MAPPED)) && (ac->ac_buf == NULL)) { 1345*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 1346*0Sstevel@tonic-gate return (DDI_SUCCESS); 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate /* if the command involves data at all, and hasn't been mapped */ 1350*0Sstevel@tonic-gate if (!(ac->ac_flags & AMR_CMD_MAPPED)) { 1351*0Sstevel@tonic-gate /* process the DMA by buffer bind mode */ 1352*0Sstevel@tonic-gate error = ddi_dma_buf_bind_handle(ac->buffer_dma_handle, 1353*0Sstevel@tonic-gate ac->ac_buf, 1354*0Sstevel@tonic-gate dma_flags, 1355*0Sstevel@tonic-gate DDI_DMA_SLEEP, 1356*0Sstevel@tonic-gate NULL, 1357*0Sstevel@tonic-gate &ac->buffer_dma_cookie, 1358*0Sstevel@tonic-gate &ac->num_of_cookie); 1359*0Sstevel@tonic-gate switch (error) { 1360*0Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP: 1361*0Sstevel@tonic-gate if (ddi_dma_numwin(ac->buffer_dma_handle, 1362*0Sstevel@tonic-gate &ac->num_of_win) == DDI_FAILURE) { 1363*0Sstevel@tonic-gate 1364*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1365*0Sstevel@tonic-gate "Cannot get dma num win")); 1366*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle( 1367*0Sstevel@tonic-gate ac->buffer_dma_handle); 1368*0Sstevel@tonic-gate (void) ddi_dma_free_handle( 1369*0Sstevel@tonic-gate &ac->buffer_dma_handle); 1370*0Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 1371*0Sstevel@tonic-gate return (DDI_FAILURE); 1372*0Sstevel@tonic-gate } 1373*0Sstevel@tonic-gate ac->current_win = 0; 1374*0Sstevel@tonic-gate break; 1375*0Sstevel@tonic-gate 1376*0Sstevel@tonic-gate case DDI_DMA_MAPPED: 1377*0Sstevel@tonic-gate ac->num_of_win = 1; 1378*0Sstevel@tonic-gate ac->current_win = 0; 1379*0Sstevel@tonic-gate break; 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate default: 1382*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1383*0Sstevel@tonic-gate "Cannot bind buf for dma")); 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate (void) ddi_dma_free_handle( 1386*0Sstevel@tonic-gate &ac->buffer_dma_handle); 1387*0Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 1388*0Sstevel@tonic-gate return (DDI_FAILURE); 1389*0Sstevel@tonic-gate } 1390*0Sstevel@tonic-gate 1391*0Sstevel@tonic-gate ac->current_cookie = 0; 1392*0Sstevel@tonic-gate 1393*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_MAPPED; 1394*0Sstevel@tonic-gate } else if (ac->current_cookie == AMR_LAST_COOKIE_TAG) { 1395*0Sstevel@tonic-gate /* get the next window */ 1396*0Sstevel@tonic-gate ac->current_win++; 1397*0Sstevel@tonic-gate (void) ddi_dma_getwin(ac->buffer_dma_handle, 1398*0Sstevel@tonic-gate ac->current_win, &off, &len, 1399*0Sstevel@tonic-gate &ac->buffer_dma_cookie, 1400*0Sstevel@tonic-gate &ac->num_of_cookie); 1401*0Sstevel@tonic-gate ac->current_cookie = 0; 1402*0Sstevel@tonic-gate } 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate if ((ac->num_of_cookie - ac->current_cookie) > AMR_NSEG) { 1405*0Sstevel@tonic-gate amr_setup_dmamap(ac, &ac->buffer_dma_cookie, AMR_NSEG); 1406*0Sstevel@tonic-gate ac->current_cookie += AMR_NSEG; 1407*0Sstevel@tonic-gate } else { 1408*0Sstevel@tonic-gate amr_setup_dmamap(ac, &ac->buffer_dma_cookie, 1409*0Sstevel@tonic-gate ac->num_of_cookie - ac->current_cookie); 1410*0Sstevel@tonic-gate ac->current_cookie = AMR_LAST_COOKIE_TAG; 1411*0Sstevel@tonic-gate } 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate return (DDI_SUCCESS); 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate 1416*0Sstevel@tonic-gate /* 1417*0Sstevel@tonic-gate * unmap the amr command, free the DMA resource 1418*0Sstevel@tonic-gate */ 1419*0Sstevel@tonic-gate static void 1420*0Sstevel@tonic-gate amr_unmapcmd(struct amr_command *ac) 1421*0Sstevel@tonic-gate { 1422*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Amr_unmapcmd called, ac=%p", 1423*0Sstevel@tonic-gate (void *)ac)); 1424*0Sstevel@tonic-gate 1425*0Sstevel@tonic-gate /* if the command involved data at all and was mapped */ 1426*0Sstevel@tonic-gate if ((ac->ac_flags & AMR_CMD_MAPPED) && 1427*0Sstevel@tonic-gate ac->ac_buf && ac->buffer_dma_handle) 1428*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 1429*0Sstevel@tonic-gate 1430*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 1431*0Sstevel@tonic-gate } 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate static int 1434*0Sstevel@tonic-gate amr_setup_tran(dev_info_t *dip, struct amr_softs *softp) 1435*0Sstevel@tonic-gate { 1436*0Sstevel@tonic-gate softp->hba_tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); 1437*0Sstevel@tonic-gate 1438*0Sstevel@tonic-gate /* 1439*0Sstevel@tonic-gate * hba_private always points to the amr_softs struct 1440*0Sstevel@tonic-gate */ 1441*0Sstevel@tonic-gate softp->hba_tran->tran_hba_private = softp; 1442*0Sstevel@tonic-gate softp->hba_tran->tran_tgt_init = amr_tran_tgt_init; 1443*0Sstevel@tonic-gate softp->hba_tran->tran_tgt_probe = scsi_hba_probe; 1444*0Sstevel@tonic-gate softp->hba_tran->tran_start = amr_tran_start; 1445*0Sstevel@tonic-gate softp->hba_tran->tran_reset = amr_tran_reset; 1446*0Sstevel@tonic-gate softp->hba_tran->tran_getcap = amr_tran_getcap; 1447*0Sstevel@tonic-gate softp->hba_tran->tran_setcap = amr_tran_setcap; 1448*0Sstevel@tonic-gate softp->hba_tran->tran_init_pkt = amr_tran_init_pkt; 1449*0Sstevel@tonic-gate softp->hba_tran->tran_destroy_pkt = amr_tran_destroy_pkt; 1450*0Sstevel@tonic-gate softp->hba_tran->tran_dmafree = amr_tran_dmafree; 1451*0Sstevel@tonic-gate softp->hba_tran->tran_sync_pkt = amr_tran_sync_pkt; 1452*0Sstevel@tonic-gate softp->hba_tran->tran_abort = NULL; 1453*0Sstevel@tonic-gate softp->hba_tran->tran_tgt_free = NULL; 1454*0Sstevel@tonic-gate softp->hba_tran->tran_quiesce = NULL; 1455*0Sstevel@tonic-gate softp->hba_tran->tran_unquiesce = NULL; 1456*0Sstevel@tonic-gate softp->hba_tran->tran_sd = NULL; 1457*0Sstevel@tonic-gate 1458*0Sstevel@tonic-gate if (scsi_hba_attach_setup(dip, &buffer_dma_attr, softp->hba_tran, 1459*0Sstevel@tonic-gate SCSI_HBA_TRAN_CLONE) != DDI_SUCCESS) { 1460*0Sstevel@tonic-gate scsi_hba_tran_free(softp->hba_tran); 1461*0Sstevel@tonic-gate softp->hba_tran = NULL; 1462*0Sstevel@tonic-gate return (DDI_FAILURE); 1463*0Sstevel@tonic-gate } else { 1464*0Sstevel@tonic-gate return (DDI_SUCCESS); 1465*0Sstevel@tonic-gate } 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate 1468*0Sstevel@tonic-gate /*ARGSUSED*/ 1469*0Sstevel@tonic-gate static int 1470*0Sstevel@tonic-gate amr_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 1471*0Sstevel@tonic-gate scsi_hba_tran_t *tran, struct scsi_device *sd) 1472*0Sstevel@tonic-gate { 1473*0Sstevel@tonic-gate struct amr_softs *softs; 1474*0Sstevel@tonic-gate ushort_t target = sd->sd_address.a_target; 1475*0Sstevel@tonic-gate uchar_t lun = sd->sd_address.a_lun; 1476*0Sstevel@tonic-gate 1477*0Sstevel@tonic-gate softs = (struct amr_softs *) 1478*0Sstevel@tonic-gate (sd->sd_address.a_hba_tran->tran_hba_private); 1479*0Sstevel@tonic-gate 1480*0Sstevel@tonic-gate if ((lun == 0) && (target < AMR_MAXLD)) 1481*0Sstevel@tonic-gate if (softs->logic_drive[target].al_state != AMR_LDRV_OFFLINE) 1482*0Sstevel@tonic-gate return (DDI_SUCCESS); 1483*0Sstevel@tonic-gate 1484*0Sstevel@tonic-gate return (DDI_FAILURE); 1485*0Sstevel@tonic-gate } 1486*0Sstevel@tonic-gate 1487*0Sstevel@tonic-gate static int 1488*0Sstevel@tonic-gate amr_tran_start(struct scsi_address *ap, struct scsi_pkt *pkt) 1489*0Sstevel@tonic-gate { 1490*0Sstevel@tonic-gate struct amr_softs *softs; 1491*0Sstevel@tonic-gate struct buf *bp = NULL; 1492*0Sstevel@tonic-gate union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp; 1493*0Sstevel@tonic-gate int ret; 1494*0Sstevel@tonic-gate uint32_t capacity; 1495*0Sstevel@tonic-gate struct amr_command *ac; 1496*0Sstevel@tonic-gate 1497*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "amr_tran_start, cmd=%X,target=%d,lun=%d", 1498*0Sstevel@tonic-gate cdbp->scc_cmd, ap->a_target, ap->a_lun)); 1499*0Sstevel@tonic-gate 1500*0Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 1501*0Sstevel@tonic-gate if ((ap->a_lun != 0) || (ap->a_target >= AMR_MAXLD) || 1502*0Sstevel@tonic-gate (softs->logic_drive[ap->a_target].al_state == 1503*0Sstevel@tonic-gate AMR_LDRV_OFFLINE)) { 1504*0Sstevel@tonic-gate cmn_err(CE_WARN, "target or lun is not correct!"); 1505*0Sstevel@tonic-gate ret = TRAN_BADPKT; 1506*0Sstevel@tonic-gate return (ret); 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 1510*0Sstevel@tonic-gate bp = ac->ac_buf; 1511*0Sstevel@tonic-gate 1512*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "scsi cmd accepted, cmd=%X", cdbp->scc_cmd)); 1513*0Sstevel@tonic-gate 1514*0Sstevel@tonic-gate switch (cdbp->scc_cmd) { 1515*0Sstevel@tonic-gate case SCMD_READ: /* read */ 1516*0Sstevel@tonic-gate case SCMD_READ_G1: /* read g1 */ 1517*0Sstevel@tonic-gate case SCMD_READ_BUFFER: /* read buffer */ 1518*0Sstevel@tonic-gate case SCMD_WRITE: /* write */ 1519*0Sstevel@tonic-gate case SCMD_WRITE_G1: /* write g1 */ 1520*0Sstevel@tonic-gate case SCMD_WRITE_BUFFER: /* write buffer */ 1521*0Sstevel@tonic-gate amr_rw_command(softs, pkt, ap->a_target); 1522*0Sstevel@tonic-gate 1523*0Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_NOINTR) { 1524*0Sstevel@tonic-gate (void) amr_poll_command(ac); 1525*0Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 1526*0Sstevel@tonic-gate | STATE_GOT_TARGET 1527*0Sstevel@tonic-gate | STATE_SENT_CMD 1528*0Sstevel@tonic-gate | STATE_XFERRED_DATA); 1529*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 1530*0Sstevel@tonic-gate pkt->pkt_statistics |= STAT_SYNC; 1531*0Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 1532*0Sstevel@tonic-gate } else { 1533*0Sstevel@tonic-gate mutex_enter(&softs->queue_mutex); 1534*0Sstevel@tonic-gate if (softs->waiting_q_head == NULL) { 1535*0Sstevel@tonic-gate ac->ac_prev = NULL; 1536*0Sstevel@tonic-gate ac->ac_next = NULL; 1537*0Sstevel@tonic-gate softs->waiting_q_head = ac; 1538*0Sstevel@tonic-gate softs->waiting_q_tail = ac; 1539*0Sstevel@tonic-gate } else { 1540*0Sstevel@tonic-gate ac->ac_next = NULL; 1541*0Sstevel@tonic-gate ac->ac_prev = softs->waiting_q_tail; 1542*0Sstevel@tonic-gate softs->waiting_q_tail->ac_next = ac; 1543*0Sstevel@tonic-gate softs->waiting_q_tail = ac; 1544*0Sstevel@tonic-gate } 1545*0Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 1546*0Sstevel@tonic-gate amr_start_waiting_queue((void *)softs); 1547*0Sstevel@tonic-gate } 1548*0Sstevel@tonic-gate ret = TRAN_ACCEPT; 1549*0Sstevel@tonic-gate break; 1550*0Sstevel@tonic-gate 1551*0Sstevel@tonic-gate case SCMD_INQUIRY: /* inquiry */ 1552*0Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 1553*0Sstevel@tonic-gate struct scsi_inquiry inqp; 1554*0Sstevel@tonic-gate uint8_t *sinq_p = (uint8_t *)&inqp; 1555*0Sstevel@tonic-gate 1556*0Sstevel@tonic-gate bzero(&inqp, sizeof (struct scsi_inquiry)); 1557*0Sstevel@tonic-gate 1558*0Sstevel@tonic-gate if (((char *)cdbp)[1] || ((char *)cdbp)[2]) { 1559*0Sstevel@tonic-gate /* 1560*0Sstevel@tonic-gate * The EVDP and pagecode is 1561*0Sstevel@tonic-gate * not supported 1562*0Sstevel@tonic-gate */ 1563*0Sstevel@tonic-gate sinq_p[1] = 0xFF; 1564*0Sstevel@tonic-gate sinq_p[2] = 0x0; 1565*0Sstevel@tonic-gate } else { 1566*0Sstevel@tonic-gate inqp.inq_len = AMR_INQ_ADDITIONAL_LEN; 1567*0Sstevel@tonic-gate inqp.inq_ansi = AMR_INQ_ANSI_VER; 1568*0Sstevel@tonic-gate inqp.inq_rdf = AMR_INQ_RESP_DATA_FORMAT; 1569*0Sstevel@tonic-gate bcopy("MegaRaid", inqp.inq_vid, 1570*0Sstevel@tonic-gate sizeof (inqp.inq_vid)); 1571*0Sstevel@tonic-gate bcopy(softs->amr_product_info.pi_product_name, 1572*0Sstevel@tonic-gate inqp.inq_pid, 1573*0Sstevel@tonic-gate AMR_PRODUCT_INFO_SIZE); 1574*0Sstevel@tonic-gate bcopy(softs->amr_product_info.pi_firmware_ver, 1575*0Sstevel@tonic-gate inqp.inq_revision, 1576*0Sstevel@tonic-gate AMR_FIRMWARE_VER_SIZE); 1577*0Sstevel@tonic-gate } 1578*0Sstevel@tonic-gate 1579*0Sstevel@tonic-gate amr_unmapcmd(ac); 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 1582*0Sstevel@tonic-gate bp_mapin(bp); 1583*0Sstevel@tonic-gate bcopy(&inqp, bp->b_un.b_addr, 1584*0Sstevel@tonic-gate sizeof (struct scsi_inquiry)); 1585*0Sstevel@tonic-gate 1586*0Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA; 1587*0Sstevel@tonic-gate } 1588*0Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 1589*0Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 1590*0Sstevel@tonic-gate | STATE_GOT_TARGET 1591*0Sstevel@tonic-gate | STATE_SENT_CMD); 1592*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 1593*0Sstevel@tonic-gate ret = TRAN_ACCEPT; 1594*0Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 1595*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 1596*0Sstevel@tonic-gate break; 1597*0Sstevel@tonic-gate 1598*0Sstevel@tonic-gate case SCMD_READ_CAPACITY: /* read capacity */ 1599*0Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 1600*0Sstevel@tonic-gate struct scsi_capacity cp; 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate capacity = softs->logic_drive[ap->a_target].al_size - 1; 1603*0Sstevel@tonic-gate cp.capacity = BE_32(capacity); 1604*0Sstevel@tonic-gate cp.lbasize = BE_32(512); 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate amr_unmapcmd(ac); 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 1609*0Sstevel@tonic-gate bp_mapin(bp); 1610*0Sstevel@tonic-gate bcopy(&cp, bp->b_un.b_addr, 8); 1611*0Sstevel@tonic-gate } 1612*0Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 1613*0Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 1614*0Sstevel@tonic-gate | STATE_GOT_TARGET 1615*0Sstevel@tonic-gate | STATE_SENT_CMD 1616*0Sstevel@tonic-gate | STATE_XFERRED_DATA); 1617*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 1618*0Sstevel@tonic-gate ret = TRAN_ACCEPT; 1619*0Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 1620*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 1621*0Sstevel@tonic-gate break; 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate case SCMD_MODE_SENSE: /* mode sense */ 1624*0Sstevel@tonic-gate case SCMD_MODE_SENSE_G1: /* mode sense g1 */ 1625*0Sstevel@tonic-gate amr_unmapcmd(ac); 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate capacity = softs->logic_drive[ap->a_target].al_size - 1; 1628*0Sstevel@tonic-gate amr_mode_sense(cdbp, bp, capacity); 1629*0Sstevel@tonic-gate 1630*0Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 1631*0Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 1632*0Sstevel@tonic-gate | STATE_GOT_TARGET 1633*0Sstevel@tonic-gate | STATE_SENT_CMD 1634*0Sstevel@tonic-gate | STATE_XFERRED_DATA); 1635*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 1636*0Sstevel@tonic-gate ret = TRAN_ACCEPT; 1637*0Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 1638*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 1639*0Sstevel@tonic-gate break; 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate case SCMD_TEST_UNIT_READY: /* test unit ready */ 1642*0Sstevel@tonic-gate case SCMD_REQUEST_SENSE: /* request sense */ 1643*0Sstevel@tonic-gate case SCMD_FORMAT: /* format */ 1644*0Sstevel@tonic-gate case SCMD_START_STOP: /* start stop */ 1645*0Sstevel@tonic-gate case SCMD_SYNCHRONIZE_CACHE: /* synchronize cache */ 1646*0Sstevel@tonic-gate if (bp && bp->b_un.b_addr && bp->b_bcount) { 1647*0Sstevel@tonic-gate amr_unmapcmd(ac); 1648*0Sstevel@tonic-gate 1649*0Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 1650*0Sstevel@tonic-gate bp_mapin(bp); 1651*0Sstevel@tonic-gate bzero(bp->b_un.b_addr, bp->b_bcount); 1652*0Sstevel@tonic-gate 1653*0Sstevel@tonic-gate pkt->pkt_state |= STATE_XFERRED_DATA; 1654*0Sstevel@tonic-gate } 1655*0Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 1656*0Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 1657*0Sstevel@tonic-gate | STATE_GOT_TARGET 1658*0Sstevel@tonic-gate | STATE_SENT_CMD); 1659*0Sstevel@tonic-gate ret = TRAN_ACCEPT; 1660*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 1661*0Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 1662*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 1663*0Sstevel@tonic-gate break; 1664*0Sstevel@tonic-gate 1665*0Sstevel@tonic-gate default: /* any other commands */ 1666*0Sstevel@tonic-gate amr_unmapcmd(ac); 1667*0Sstevel@tonic-gate pkt->pkt_reason = CMD_INCOMPLETE; 1668*0Sstevel@tonic-gate pkt->pkt_state = (STATE_GOT_BUS 1669*0Sstevel@tonic-gate | STATE_GOT_TARGET 1670*0Sstevel@tonic-gate | STATE_SENT_CMD 1671*0Sstevel@tonic-gate | STATE_GOT_STATUS 1672*0Sstevel@tonic-gate | STATE_ARQ_DONE); 1673*0Sstevel@tonic-gate ret = TRAN_ACCEPT; 1674*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 1675*0Sstevel@tonic-gate amr_set_arq_data(pkt, KEY_ILLEGAL_REQUEST); 1676*0Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR)) 1677*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 1678*0Sstevel@tonic-gate break; 1679*0Sstevel@tonic-gate } 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate return (ret); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate /* 1685*0Sstevel@tonic-gate * tran_reset() will reset the bus/target/adapter to support the fault recovery 1686*0Sstevel@tonic-gate * functionality according to the "level" in interface. However, we got the 1687*0Sstevel@tonic-gate * confirmation from LSI that these HBA cards does not support any commands to 1688*0Sstevel@tonic-gate * reset bus/target/adapter/channel. 1689*0Sstevel@tonic-gate * 1690*0Sstevel@tonic-gate * If the tran_reset() return a FAILURE to the sd, the system will not 1691*0Sstevel@tonic-gate * continue to dump the core. But core dump is an crucial method to analyze 1692*0Sstevel@tonic-gate * problems in panic. Now we adopt a work around solution, that is to return 1693*0Sstevel@tonic-gate * a fake SUCCESS to sd during panic, which will force the system continue 1694*0Sstevel@tonic-gate * to dump core though the core may have problems in some situtation because 1695*0Sstevel@tonic-gate * some on-the-fly commands will continue DMAing data to the memory. 1696*0Sstevel@tonic-gate * In addition, the work around core dump method may not be performed 1697*0Sstevel@tonic-gate * successfully if the panic is caused by the HBA itself. So the work around 1698*0Sstevel@tonic-gate * solution is not a good example for the implementation of tran_reset(), 1699*0Sstevel@tonic-gate * the most reasonable approach should send a reset command to the adapter. 1700*0Sstevel@tonic-gate */ 1701*0Sstevel@tonic-gate /*ARGSUSED*/ 1702*0Sstevel@tonic-gate static int 1703*0Sstevel@tonic-gate amr_tran_reset(struct scsi_address *ap, int level) 1704*0Sstevel@tonic-gate { 1705*0Sstevel@tonic-gate struct amr_softs *softs; 1706*0Sstevel@tonic-gate volatile uint32_t done_flag; 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate if (ddi_in_panic()) { 1709*0Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 1710*0Sstevel@tonic-gate 1711*0Sstevel@tonic-gate /* Acknowledge the card if there are any significant commands */ 1712*0Sstevel@tonic-gate while (softs->amr_busyslots > 0) { 1713*0Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_busy == 0), 1714*0Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 1715*0Sstevel@tonic-gate if (!done_flag) { 1716*0Sstevel@tonic-gate /* 1717*0Sstevel@tonic-gate * command not completed, indicate the 1718*0Sstevel@tonic-gate * problem and continue get ac 1719*0Sstevel@tonic-gate */ 1720*0Sstevel@tonic-gate cmn_err(CE_WARN, 1721*0Sstevel@tonic-gate "AMR command is not completed"); 1722*0Sstevel@tonic-gate return (0); 1723*0Sstevel@tonic-gate } 1724*0Sstevel@tonic-gate 1725*0Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 1726*0Sstevel@tonic-gate 1727*0Sstevel@tonic-gate /* wait for the acknowledge from hardware */ 1728*0Sstevel@tonic-gate AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 1729*0Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 1730*0Sstevel@tonic-gate if (!done_flag) { 1731*0Sstevel@tonic-gate /* 1732*0Sstevel@tonic-gate * command is not completed, return from the 1733*0Sstevel@tonic-gate * current interrupt and wait for the next one 1734*0Sstevel@tonic-gate */ 1735*0Sstevel@tonic-gate cmn_err(CE_WARN, "No answer from the hardware"); 1736*0Sstevel@tonic-gate 1737*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 1738*0Sstevel@tonic-gate return (0); 1739*0Sstevel@tonic-gate } 1740*0Sstevel@tonic-gate 1741*0Sstevel@tonic-gate softs->amr_busyslots -= softs->mailbox->mb_nstatus; 1742*0Sstevel@tonic-gate } 1743*0Sstevel@tonic-gate 1744*0Sstevel@tonic-gate /* flush the controllor */ 1745*0Sstevel@tonic-gate (void) amr_flush(softs); 1746*0Sstevel@tonic-gate 1747*0Sstevel@tonic-gate /* 1748*0Sstevel@tonic-gate * If the system is in panic, the tran_reset() will return a 1749*0Sstevel@tonic-gate * fake SUCCESS to sd, then the system would continue dump the 1750*0Sstevel@tonic-gate * core by poll commands. This is a work around for dumping 1751*0Sstevel@tonic-gate * core in panic. 1752*0Sstevel@tonic-gate * 1753*0Sstevel@tonic-gate * Note: Some on-the-fly command will continue DMAing data to 1754*0Sstevel@tonic-gate * the memory when the core is dumping, which may cause 1755*0Sstevel@tonic-gate * some flaws in the dumped core file, so a cmn_err() 1756*0Sstevel@tonic-gate * will be printed out to warn users. However, for most 1757*0Sstevel@tonic-gate * cases, the core file will be fine. 1758*0Sstevel@tonic-gate */ 1759*0Sstevel@tonic-gate cmn_err(CE_WARN, "This system contains a SCSI HBA card/driver " 1760*0Sstevel@tonic-gate "that doesn't support software reset. This " 1761*0Sstevel@tonic-gate "means that memory being used by the HBA for " 1762*0Sstevel@tonic-gate "DMA based reads could have been updated after " 1763*0Sstevel@tonic-gate "we panic'd."); 1764*0Sstevel@tonic-gate return (1); 1765*0Sstevel@tonic-gate } else { 1766*0Sstevel@tonic-gate /* return failure to sd */ 1767*0Sstevel@tonic-gate return (0); 1768*0Sstevel@tonic-gate } 1769*0Sstevel@tonic-gate } 1770*0Sstevel@tonic-gate 1771*0Sstevel@tonic-gate /*ARGSUSED*/ 1772*0Sstevel@tonic-gate static int 1773*0Sstevel@tonic-gate amr_tran_getcap(struct scsi_address *ap, char *cap, int whom) 1774*0Sstevel@tonic-gate { 1775*0Sstevel@tonic-gate struct amr_softs *softs; 1776*0Sstevel@tonic-gate 1777*0Sstevel@tonic-gate /* 1778*0Sstevel@tonic-gate * We don't allow inquiring about capabilities for other targets 1779*0Sstevel@tonic-gate */ 1780*0Sstevel@tonic-gate if (cap == NULL || whom == 0) 1781*0Sstevel@tonic-gate return (-1); 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate softs = ((struct amr_softs *)(ap->a_hba_tran)->tran_hba_private); 1784*0Sstevel@tonic-gate 1785*0Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) { 1786*0Sstevel@tonic-gate case SCSI_CAP_ARQ: 1787*0Sstevel@tonic-gate return (1); 1788*0Sstevel@tonic-gate case SCSI_CAP_GEOMETRY: 1789*0Sstevel@tonic-gate return ((AMR_DEFAULT_HEADS << 16) | AMR_DEFAULT_CYLINDERS); 1790*0Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE: 1791*0Sstevel@tonic-gate return (AMR_DEFAULT_SECTORS); 1792*0Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS: 1793*0Sstevel@tonic-gate /* number of sectors */ 1794*0Sstevel@tonic-gate return (softs->logic_drive[ap->a_target].al_size); 1795*0Sstevel@tonic-gate default: 1796*0Sstevel@tonic-gate return (-1); 1797*0Sstevel@tonic-gate } 1798*0Sstevel@tonic-gate } 1799*0Sstevel@tonic-gate 1800*0Sstevel@tonic-gate /*ARGSUSED*/ 1801*0Sstevel@tonic-gate static int 1802*0Sstevel@tonic-gate amr_tran_setcap(struct scsi_address *ap, char *cap, int value, 1803*0Sstevel@tonic-gate int whom) 1804*0Sstevel@tonic-gate { 1805*0Sstevel@tonic-gate /* 1806*0Sstevel@tonic-gate * We don't allow setting capabilities for other targets 1807*0Sstevel@tonic-gate */ 1808*0Sstevel@tonic-gate if (cap == NULL || whom == 0) { 1809*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 1810*0Sstevel@tonic-gate "Set Cap not supported, string = %s, whom=%d", 1811*0Sstevel@tonic-gate cap, whom)); 1812*0Sstevel@tonic-gate return (-1); 1813*0Sstevel@tonic-gate } 1814*0Sstevel@tonic-gate 1815*0Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) { 1816*0Sstevel@tonic-gate case SCSI_CAP_ARQ: 1817*0Sstevel@tonic-gate return (1); 1818*0Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS: 1819*0Sstevel@tonic-gate return (1); 1820*0Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE: 1821*0Sstevel@tonic-gate return (1); 1822*0Sstevel@tonic-gate default: 1823*0Sstevel@tonic-gate return (0); 1824*0Sstevel@tonic-gate } 1825*0Sstevel@tonic-gate } 1826*0Sstevel@tonic-gate 1827*0Sstevel@tonic-gate static struct scsi_pkt * 1828*0Sstevel@tonic-gate amr_tran_init_pkt(struct scsi_address *ap, 1829*0Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 1830*0Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg) 1831*0Sstevel@tonic-gate { 1832*0Sstevel@tonic-gate struct amr_softs *softs; 1833*0Sstevel@tonic-gate struct amr_command *ac; 1834*0Sstevel@tonic-gate uint32_t slen; 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate softs = (struct amr_softs *)(ap->a_hba_tran->tran_hba_private); 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate if ((ap->a_lun != 0)||(ap->a_target >= AMR_MAXLD)|| 1839*0Sstevel@tonic-gate (softs->logic_drive[ap->a_target].al_state == 1840*0Sstevel@tonic-gate AMR_LDRV_OFFLINE)) { 1841*0Sstevel@tonic-gate return (NULL); 1842*0Sstevel@tonic-gate } 1843*0Sstevel@tonic-gate 1844*0Sstevel@tonic-gate if (pkt == NULL) { 1845*0Sstevel@tonic-gate /* force auto request sense */ 1846*0Sstevel@tonic-gate slen = MAX(statuslen, sizeof (struct scsi_arq_status)); 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate pkt = scsi_hba_pkt_alloc(softs->dev_info_p, ap, cmdlen, 1849*0Sstevel@tonic-gate slen, tgtlen, sizeof (struct amr_command), 1850*0Sstevel@tonic-gate callback, arg); 1851*0Sstevel@tonic-gate if (pkt == NULL) { 1852*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "scsi_hba_pkt_alloc failed")); 1853*0Sstevel@tonic-gate return (NULL); 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate pkt->pkt_address = *ap; 1856*0Sstevel@tonic-gate pkt->pkt_comp = (void (*)())NULL; 1857*0Sstevel@tonic-gate pkt->pkt_time = 0; 1858*0Sstevel@tonic-gate pkt->pkt_resid = 0; 1859*0Sstevel@tonic-gate pkt->pkt_statistics = 0; 1860*0Sstevel@tonic-gate pkt->pkt_reason = 0; 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 1863*0Sstevel@tonic-gate ac->ac_buf = bp; 1864*0Sstevel@tonic-gate ac->cmdlen = cmdlen; 1865*0Sstevel@tonic-gate ac->ac_softs = softs; 1866*0Sstevel@tonic-gate ac->pkt = pkt; 1867*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_GOT_SLOT; 1868*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_BUSY; 1869*0Sstevel@tonic-gate 1870*0Sstevel@tonic-gate if ((bp == NULL) || (bp->b_bcount == 0)) { 1871*0Sstevel@tonic-gate return (pkt); 1872*0Sstevel@tonic-gate } 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate if (ddi_dma_alloc_handle(softs->dev_info_p, &buffer_dma_attr, 1875*0Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, 1876*0Sstevel@tonic-gate &ac->buffer_dma_handle) != DDI_SUCCESS) { 1877*0Sstevel@tonic-gate 1878*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 1879*0Sstevel@tonic-gate "Cannot allocate buffer DMA tag")); 1880*0Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 1881*0Sstevel@tonic-gate return (NULL); 1882*0Sstevel@tonic-gate 1883*0Sstevel@tonic-gate } 1884*0Sstevel@tonic-gate 1885*0Sstevel@tonic-gate } else { 1886*0Sstevel@tonic-gate if ((bp == NULL) || (bp->b_bcount == 0)) { 1887*0Sstevel@tonic-gate return (pkt); 1888*0Sstevel@tonic-gate } 1889*0Sstevel@tonic-gate ac = (struct amr_command *)pkt->pkt_ha_private; 1890*0Sstevel@tonic-gate } 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate ASSERT(ac != NULL); 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate if (bp->b_flags & B_READ) { 1895*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_DATAOUT; 1896*0Sstevel@tonic-gate } else { 1897*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_DATAIN; 1898*0Sstevel@tonic-gate } 1899*0Sstevel@tonic-gate 1900*0Sstevel@tonic-gate if (flags & PKT_CONSISTENT) { 1901*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_PKT_CONSISTENT; 1902*0Sstevel@tonic-gate } 1903*0Sstevel@tonic-gate 1904*0Sstevel@tonic-gate if (flags & PKT_DMA_PARTIAL) { 1905*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_PKT_DMA_PARTIAL; 1906*0Sstevel@tonic-gate } 1907*0Sstevel@tonic-gate 1908*0Sstevel@tonic-gate if (amr_mapcmd(ac) != DDI_SUCCESS) { 1909*0Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 1910*0Sstevel@tonic-gate return (NULL); 1911*0Sstevel@tonic-gate } 1912*0Sstevel@tonic-gate 1913*0Sstevel@tonic-gate pkt->pkt_resid = bp->b_bcount - ac->data_transfered; 1914*0Sstevel@tonic-gate 1915*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, 1916*0Sstevel@tonic-gate "init pkt, pkt_resid=%d, b_bcount=%d, data_transfered=%d", 1917*0Sstevel@tonic-gate (uint32_t)pkt->pkt_resid, (uint32_t)bp->b_bcount, 1918*0Sstevel@tonic-gate ac->data_transfered)); 1919*0Sstevel@tonic-gate 1920*0Sstevel@tonic-gate ASSERT(pkt->pkt_resid >= 0); 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate return (pkt); 1923*0Sstevel@tonic-gate } 1924*0Sstevel@tonic-gate 1925*0Sstevel@tonic-gate static void 1926*0Sstevel@tonic-gate amr_tran_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 1927*0Sstevel@tonic-gate { 1928*0Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 1929*0Sstevel@tonic-gate 1930*0Sstevel@tonic-gate amr_unmapcmd(ac); 1931*0Sstevel@tonic-gate 1932*0Sstevel@tonic-gate if (ac->buffer_dma_handle) { 1933*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 1934*0Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 1935*0Sstevel@tonic-gate } 1936*0Sstevel@tonic-gate 1937*0Sstevel@tonic-gate scsi_hba_pkt_free(ap, pkt); 1938*0Sstevel@tonic-gate AMRDB_PRINT((CE_NOTE, "Destroy pkt called")); 1939*0Sstevel@tonic-gate } 1940*0Sstevel@tonic-gate 1941*0Sstevel@tonic-gate /*ARGSUSED*/ 1942*0Sstevel@tonic-gate static void 1943*0Sstevel@tonic-gate amr_tran_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 1944*0Sstevel@tonic-gate { 1945*0Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 1946*0Sstevel@tonic-gate 1947*0Sstevel@tonic-gate if (ac->buffer_dma_handle) { 1948*0Sstevel@tonic-gate (void) ddi_dma_sync(ac->buffer_dma_handle, 0, 0, 1949*0Sstevel@tonic-gate (ac->ac_flags & AMR_CMD_DATAIN) ? 1950*0Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU); 1951*0Sstevel@tonic-gate } 1952*0Sstevel@tonic-gate } 1953*0Sstevel@tonic-gate 1954*0Sstevel@tonic-gate /*ARGSUSED*/ 1955*0Sstevel@tonic-gate static void 1956*0Sstevel@tonic-gate amr_tran_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) 1957*0Sstevel@tonic-gate { 1958*0Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 1959*0Sstevel@tonic-gate 1960*0Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_MAPPED) { 1961*0Sstevel@tonic-gate (void) ddi_dma_unbind_handle(ac->buffer_dma_handle); 1962*0Sstevel@tonic-gate (void) ddi_dma_free_handle(&ac->buffer_dma_handle); 1963*0Sstevel@tonic-gate ac->buffer_dma_handle = NULL; 1964*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_MAPPED; 1965*0Sstevel@tonic-gate } 1966*0Sstevel@tonic-gate 1967*0Sstevel@tonic-gate } 1968*0Sstevel@tonic-gate 1969*0Sstevel@tonic-gate /*ARGSUSED*/ 1970*0Sstevel@tonic-gate static void 1971*0Sstevel@tonic-gate amr_rw_command(struct amr_softs *softs, struct scsi_pkt *pkt, int target) 1972*0Sstevel@tonic-gate { 1973*0Sstevel@tonic-gate struct amr_command *ac = (struct amr_command *)pkt->pkt_ha_private; 1974*0Sstevel@tonic-gate union scsi_cdb *cdbp = (union scsi_cdb *)pkt->pkt_cdbp; 1975*0Sstevel@tonic-gate uint8_t cmd; 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gate if (ac->ac_flags & AMR_CMD_DATAOUT) { 1978*0Sstevel@tonic-gate cmd = AMR_CMD_LREAD; 1979*0Sstevel@tonic-gate } else { 1980*0Sstevel@tonic-gate cmd = AMR_CMD_LWRITE; 1981*0Sstevel@tonic-gate } 1982*0Sstevel@tonic-gate 1983*0Sstevel@tonic-gate ac->mailbox.mb_command = cmd; 1984*0Sstevel@tonic-gate ac->mailbox.mb_blkcount = 1985*0Sstevel@tonic-gate (ac->transfer_size + AMR_BLKSIZE - 1)/AMR_BLKSIZE; 1986*0Sstevel@tonic-gate ac->mailbox.mb_lba = (ac->cmdlen == 10) ? 1987*0Sstevel@tonic-gate GETG1ADDR(cdbp) : GETG0ADDR(cdbp); 1988*0Sstevel@tonic-gate ac->mailbox.mb_drive = (uint8_t)target; 1989*0Sstevel@tonic-gate } 1990*0Sstevel@tonic-gate 1991*0Sstevel@tonic-gate static void 1992*0Sstevel@tonic-gate amr_mode_sense(union scsi_cdb *cdbp, struct buf *bp, unsigned int capacity) 1993*0Sstevel@tonic-gate { 1994*0Sstevel@tonic-gate uchar_t pagecode; 1995*0Sstevel@tonic-gate struct mode_format *page3p; 1996*0Sstevel@tonic-gate struct mode_geometry *page4p; 1997*0Sstevel@tonic-gate struct mode_header *headerp; 1998*0Sstevel@tonic-gate uint32_t ncyl; 1999*0Sstevel@tonic-gate 2000*0Sstevel@tonic-gate if (!(bp && bp->b_un.b_addr && bp->b_bcount)) 2001*0Sstevel@tonic-gate return; 2002*0Sstevel@tonic-gate 2003*0Sstevel@tonic-gate if (bp->b_flags & (B_PHYS | B_PAGEIO)) 2004*0Sstevel@tonic-gate bp_mapin(bp); 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gate pagecode = cdbp->cdb_un.sg.scsi[0]; 2007*0Sstevel@tonic-gate switch (pagecode) { 2008*0Sstevel@tonic-gate case SD_MODE_SENSE_PAGE3_CODE: 2009*0Sstevel@tonic-gate headerp = (struct mode_header *)(bp->b_un.b_addr); 2010*0Sstevel@tonic-gate headerp->bdesc_length = MODE_BLK_DESC_LENGTH; 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate page3p = (struct mode_format *)((caddr_t)headerp + 2013*0Sstevel@tonic-gate MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH); 2014*0Sstevel@tonic-gate page3p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE3_CODE); 2015*0Sstevel@tonic-gate page3p->mode_page.length = BE_8(sizeof (struct mode_format)); 2016*0Sstevel@tonic-gate page3p->data_bytes_sect = BE_16(AMR_DEFAULT_SECTORS); 2017*0Sstevel@tonic-gate page3p->sect_track = BE_16(AMR_DEFAULT_CYLINDERS); 2018*0Sstevel@tonic-gate 2019*0Sstevel@tonic-gate return; 2020*0Sstevel@tonic-gate 2021*0Sstevel@tonic-gate case SD_MODE_SENSE_PAGE4_CODE: 2022*0Sstevel@tonic-gate headerp = (struct mode_header *)(bp->b_un.b_addr); 2023*0Sstevel@tonic-gate headerp->bdesc_length = MODE_BLK_DESC_LENGTH; 2024*0Sstevel@tonic-gate 2025*0Sstevel@tonic-gate page4p = (struct mode_geometry *)((caddr_t)headerp + 2026*0Sstevel@tonic-gate MODE_HEADER_LENGTH + MODE_BLK_DESC_LENGTH); 2027*0Sstevel@tonic-gate page4p->mode_page.code = BE_8(SD_MODE_SENSE_PAGE4_CODE); 2028*0Sstevel@tonic-gate page4p->mode_page.length = BE_8(sizeof (struct mode_geometry)); 2029*0Sstevel@tonic-gate page4p->heads = BE_8(AMR_DEFAULT_HEADS); 2030*0Sstevel@tonic-gate page4p->rpm = BE_16(AMR_DEFAULT_ROTATIONS); 2031*0Sstevel@tonic-gate 2032*0Sstevel@tonic-gate ncyl = capacity / (AMR_DEFAULT_HEADS*AMR_DEFAULT_CYLINDERS); 2033*0Sstevel@tonic-gate page4p->cyl_lb = BE_8(ncyl & 0xff); 2034*0Sstevel@tonic-gate page4p->cyl_mb = BE_8((ncyl >> 8) & 0xff); 2035*0Sstevel@tonic-gate page4p->cyl_ub = BE_8((ncyl >> 16) & 0xff); 2036*0Sstevel@tonic-gate 2037*0Sstevel@tonic-gate return; 2038*0Sstevel@tonic-gate default: 2039*0Sstevel@tonic-gate bzero(bp->b_un.b_addr, bp->b_bcount); 2040*0Sstevel@tonic-gate return; 2041*0Sstevel@tonic-gate } 2042*0Sstevel@tonic-gate } 2043*0Sstevel@tonic-gate 2044*0Sstevel@tonic-gate static void 2045*0Sstevel@tonic-gate amr_set_arq_data(struct scsi_pkt *pkt, uchar_t key) 2046*0Sstevel@tonic-gate { 2047*0Sstevel@tonic-gate struct scsi_arq_status *arqstat; 2048*0Sstevel@tonic-gate 2049*0Sstevel@tonic-gate arqstat = (struct scsi_arq_status *)(pkt->pkt_scbp); 2050*0Sstevel@tonic-gate arqstat->sts_status.sts_chk = 1; /* CHECK CONDITION */ 2051*0Sstevel@tonic-gate arqstat->sts_rqpkt_reason = CMD_CMPLT; 2052*0Sstevel@tonic-gate arqstat->sts_rqpkt_resid = 0; 2053*0Sstevel@tonic-gate arqstat->sts_rqpkt_state = STATE_GOT_BUS | STATE_GOT_TARGET | 2054*0Sstevel@tonic-gate STATE_SENT_CMD | STATE_XFERRED_DATA; 2055*0Sstevel@tonic-gate arqstat->sts_rqpkt_statistics = 0; 2056*0Sstevel@tonic-gate arqstat->sts_sensedata.es_valid = 1; 2057*0Sstevel@tonic-gate arqstat->sts_sensedata.es_class = CLASS_EXTENDED_SENSE; 2058*0Sstevel@tonic-gate arqstat->sts_sensedata.es_key = key; 2059*0Sstevel@tonic-gate } 2060*0Sstevel@tonic-gate 2061*0Sstevel@tonic-gate static void 2062*0Sstevel@tonic-gate amr_start_waiting_queue(void *softp) 2063*0Sstevel@tonic-gate { 2064*0Sstevel@tonic-gate uint32_t slot; 2065*0Sstevel@tonic-gate struct amr_command *ac; 2066*0Sstevel@tonic-gate volatile uint32_t done_flag; 2067*0Sstevel@tonic-gate struct amr_softs *softs = (struct amr_softs *)softp; 2068*0Sstevel@tonic-gate 2069*0Sstevel@tonic-gate /* only one command allowed at the same time */ 2070*0Sstevel@tonic-gate mutex_enter(&softs->queue_mutex); 2071*0Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 2072*0Sstevel@tonic-gate 2073*0Sstevel@tonic-gate while ((ac = softs->waiting_q_head) != NULL) { 2074*0Sstevel@tonic-gate /* 2075*0Sstevel@tonic-gate * Find an available slot, the last slot is 2076*0Sstevel@tonic-gate * occupied by poll I/O command. 2077*0Sstevel@tonic-gate */ 2078*0Sstevel@tonic-gate for (slot = 0; slot < (softs->sg_max_count - 1); slot++) { 2079*0Sstevel@tonic-gate if (softs->busycmd[slot] == NULL) { 2080*0Sstevel@tonic-gate if (AMR_QGET_IDB(softs) & AMR_QIDB_SUBMIT) { 2081*0Sstevel@tonic-gate /* 2082*0Sstevel@tonic-gate * only one command allowed at the 2083*0Sstevel@tonic-gate * same time 2084*0Sstevel@tonic-gate */ 2085*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 2086*0Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 2087*0Sstevel@tonic-gate return; 2088*0Sstevel@tonic-gate } 2089*0Sstevel@tonic-gate 2090*0Sstevel@tonic-gate ac->ac_timestamp = ddi_get_time(); 2091*0Sstevel@tonic-gate 2092*0Sstevel@tonic-gate if (!(ac->ac_flags & AMR_CMD_GOT_SLOT)) { 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate softs->busycmd[slot] = ac; 2095*0Sstevel@tonic-gate ac->ac_slot = slot; 2096*0Sstevel@tonic-gate softs->amr_busyslots++; 2097*0Sstevel@tonic-gate 2098*0Sstevel@tonic-gate bcopy(ac->sgtable, 2099*0Sstevel@tonic-gate softs->sg_items[slot].sg_table, 2100*0Sstevel@tonic-gate sizeof (struct amr_sgentry) * AMR_NSEG); 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate (void) ddi_dma_sync( 2103*0Sstevel@tonic-gate softs->sg_items[slot].sg_handle, 2104*0Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate ac->mailbox.mb_physaddr = 2107*0Sstevel@tonic-gate softs->sg_items[slot].sg_phyaddr; 2108*0Sstevel@tonic-gate } 2109*0Sstevel@tonic-gate 2110*0Sstevel@tonic-gate /* take the cmd from the queue */ 2111*0Sstevel@tonic-gate softs->waiting_q_head = ac->ac_next; 2112*0Sstevel@tonic-gate 2113*0Sstevel@tonic-gate ac->mailbox.mb_ident = ac->ac_slot + 1; 2114*0Sstevel@tonic-gate ac->mailbox.mb_busy = 1; 2115*0Sstevel@tonic-gate ac->ac_next = NULL; 2116*0Sstevel@tonic-gate ac->ac_prev = NULL; 2117*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_GOT_SLOT; 2118*0Sstevel@tonic-gate 2119*0Sstevel@tonic-gate /* clear the poll/ack fields in the mailbox */ 2120*0Sstevel@tonic-gate softs->mailbox->mb_poll = 0; 2121*0Sstevel@tonic-gate softs->mailbox->mb_ack = 0; 2122*0Sstevel@tonic-gate 2123*0Sstevel@tonic-gate AMR_DELAY((softs->mailbox->mb_busy == 0), 2124*0Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 2125*0Sstevel@tonic-gate if (!done_flag) { 2126*0Sstevel@tonic-gate /* 2127*0Sstevel@tonic-gate * command not completed, indicate the 2128*0Sstevel@tonic-gate * problem and continue get ac 2129*0Sstevel@tonic-gate */ 2130*0Sstevel@tonic-gate cmn_err(CE_WARN, 2131*0Sstevel@tonic-gate "AMR command is not completed"); 2132*0Sstevel@tonic-gate break; 2133*0Sstevel@tonic-gate } 2134*0Sstevel@tonic-gate 2135*0Sstevel@tonic-gate bcopy(&ac->mailbox, (void *)softs->mailbox, 2136*0Sstevel@tonic-gate AMR_MBOX_CMDSIZE); 2137*0Sstevel@tonic-gate ac->ac_flags |= AMR_CMD_BUSY; 2138*0Sstevel@tonic-gate 2139*0Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 2140*0Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORDEV); 2141*0Sstevel@tonic-gate 2142*0Sstevel@tonic-gate AMR_QPUT_IDB(softs, 2143*0Sstevel@tonic-gate softs->mbox_phyaddr | AMR_QIDB_SUBMIT); 2144*0Sstevel@tonic-gate 2145*0Sstevel@tonic-gate /* 2146*0Sstevel@tonic-gate * current ac is submitted 2147*0Sstevel@tonic-gate * so quit 'for-loop' to get next ac 2148*0Sstevel@tonic-gate */ 2149*0Sstevel@tonic-gate break; 2150*0Sstevel@tonic-gate } 2151*0Sstevel@tonic-gate } 2152*0Sstevel@tonic-gate 2153*0Sstevel@tonic-gate /* no slot, finish our task */ 2154*0Sstevel@tonic-gate if (slot == softs->maxio) 2155*0Sstevel@tonic-gate break; 2156*0Sstevel@tonic-gate } 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate /* only one command allowed at the same time */ 2159*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 2160*0Sstevel@tonic-gate mutex_exit(&softs->queue_mutex); 2161*0Sstevel@tonic-gate } 2162*0Sstevel@tonic-gate 2163*0Sstevel@tonic-gate static void 2164*0Sstevel@tonic-gate amr_done(struct amr_softs *softs) 2165*0Sstevel@tonic-gate { 2166*0Sstevel@tonic-gate 2167*0Sstevel@tonic-gate uint32_t i, idx; 2168*0Sstevel@tonic-gate volatile uint32_t done_flag; 2169*0Sstevel@tonic-gate struct amr_mailbox *mbox, mbsave; 2170*0Sstevel@tonic-gate struct amr_command *ac, *head, *tail; 2171*0Sstevel@tonic-gate 2172*0Sstevel@tonic-gate head = tail = NULL; 2173*0Sstevel@tonic-gate 2174*0Sstevel@tonic-gate AMR_QPUT_ODB(softs, AMR_QODB_READY); 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate /* acknowledge interrupt */ 2177*0Sstevel@tonic-gate (void) AMR_QGET_ODB(softs); 2178*0Sstevel@tonic-gate 2179*0Sstevel@tonic-gate mutex_enter(&softs->cmd_mutex); 2180*0Sstevel@tonic-gate 2181*0Sstevel@tonic-gate if (softs->mailbox->mb_nstatus != 0) { 2182*0Sstevel@tonic-gate (void) ddi_dma_sync(softs->mbox_dma_handle, 2183*0Sstevel@tonic-gate 0, 0, DDI_DMA_SYNC_FORCPU); 2184*0Sstevel@tonic-gate 2185*0Sstevel@tonic-gate /* save mailbox, which contains a list of completed commands */ 2186*0Sstevel@tonic-gate bcopy((void *)(uintptr_t)(volatile void *)softs->mailbox, 2187*0Sstevel@tonic-gate &mbsave, sizeof (mbsave)); 2188*0Sstevel@tonic-gate 2189*0Sstevel@tonic-gate mbox = &mbsave; 2190*0Sstevel@tonic-gate 2191*0Sstevel@tonic-gate AMR_QPUT_IDB(softs, softs->mbox_phyaddr | AMR_QIDB_ACK); 2192*0Sstevel@tonic-gate 2193*0Sstevel@tonic-gate /* wait for the acknowledge from hardware */ 2194*0Sstevel@tonic-gate AMR_BUSYWAIT(!(AMR_QGET_IDB(softs) & AMR_QIDB_ACK), 2195*0Sstevel@tonic-gate AMR_RETRYCOUNT, done_flag); 2196*0Sstevel@tonic-gate if (!done_flag) { 2197*0Sstevel@tonic-gate /* 2198*0Sstevel@tonic-gate * command is not completed, return from the current 2199*0Sstevel@tonic-gate * interrupt and wait for the next one 2200*0Sstevel@tonic-gate */ 2201*0Sstevel@tonic-gate cmn_err(CE_WARN, "No answer from the hardware"); 2202*0Sstevel@tonic-gate 2203*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 2204*0Sstevel@tonic-gate return; 2205*0Sstevel@tonic-gate } 2206*0Sstevel@tonic-gate 2207*0Sstevel@tonic-gate for (i = 0; i < mbox->mb_nstatus; i++) { 2208*0Sstevel@tonic-gate idx = mbox->mb_completed[i] - 1; 2209*0Sstevel@tonic-gate ac = softs->busycmd[idx]; 2210*0Sstevel@tonic-gate 2211*0Sstevel@tonic-gate if (ac != NULL) { 2212*0Sstevel@tonic-gate /* pull the command from the busy index */ 2213*0Sstevel@tonic-gate softs->busycmd[idx] = NULL; 2214*0Sstevel@tonic-gate if (softs->amr_busyslots > 0) 2215*0Sstevel@tonic-gate softs->amr_busyslots--; 2216*0Sstevel@tonic-gate if (softs->amr_busyslots == 0) 2217*0Sstevel@tonic-gate cv_broadcast(&softs->cmd_cv); 2218*0Sstevel@tonic-gate 2219*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_BUSY; 2220*0Sstevel@tonic-gate ac->ac_flags &= ~AMR_CMD_GOT_SLOT; 2221*0Sstevel@tonic-gate ac->ac_status = mbox->mb_status; 2222*0Sstevel@tonic-gate 2223*0Sstevel@tonic-gate /* enqueue here */ 2224*0Sstevel@tonic-gate if (head) { 2225*0Sstevel@tonic-gate tail->ac_next = ac; 2226*0Sstevel@tonic-gate tail = ac; 2227*0Sstevel@tonic-gate tail->ac_next = NULL; 2228*0Sstevel@tonic-gate } else { 2229*0Sstevel@tonic-gate tail = head = ac; 2230*0Sstevel@tonic-gate ac->ac_next = NULL; 2231*0Sstevel@tonic-gate } 2232*0Sstevel@tonic-gate } else { 2233*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, 2234*0Sstevel@tonic-gate "ac in mailbox is NULL!")); 2235*0Sstevel@tonic-gate } 2236*0Sstevel@tonic-gate } 2237*0Sstevel@tonic-gate } else { 2238*0Sstevel@tonic-gate AMRDB_PRINT((CE_WARN, "mailbox is not ready for copy out!")); 2239*0Sstevel@tonic-gate } 2240*0Sstevel@tonic-gate 2241*0Sstevel@tonic-gate mutex_exit(&softs->cmd_mutex); 2242*0Sstevel@tonic-gate 2243*0Sstevel@tonic-gate if (head != NULL) { 2244*0Sstevel@tonic-gate amr_call_pkt_comp(head); 2245*0Sstevel@tonic-gate } 2246*0Sstevel@tonic-gate 2247*0Sstevel@tonic-gate /* dispatch a thread to process the pending I/O if there is any */ 2248*0Sstevel@tonic-gate if ((ddi_taskq_dispatch(softs->amr_taskq, amr_start_waiting_queue, 2249*0Sstevel@tonic-gate (void *)softs, DDI_NOSLEEP)) != DDI_SUCCESS) { 2250*0Sstevel@tonic-gate cmn_err(CE_WARN, "No memory available to dispatch taskq"); 2251*0Sstevel@tonic-gate } 2252*0Sstevel@tonic-gate } 2253*0Sstevel@tonic-gate 2254*0Sstevel@tonic-gate static void 2255*0Sstevel@tonic-gate amr_call_pkt_comp(register struct amr_command *head) 2256*0Sstevel@tonic-gate { 2257*0Sstevel@tonic-gate register struct scsi_pkt *pkt; 2258*0Sstevel@tonic-gate register struct amr_command *ac, *localhead; 2259*0Sstevel@tonic-gate 2260*0Sstevel@tonic-gate localhead = head; 2261*0Sstevel@tonic-gate 2262*0Sstevel@tonic-gate while (localhead) { 2263*0Sstevel@tonic-gate ac = localhead; 2264*0Sstevel@tonic-gate localhead = ac->ac_next; 2265*0Sstevel@tonic-gate ac->ac_next = NULL; 2266*0Sstevel@tonic-gate 2267*0Sstevel@tonic-gate pkt = ac->pkt; 2268*0Sstevel@tonic-gate *pkt->pkt_scbp = 0; 2269*0Sstevel@tonic-gate 2270*0Sstevel@tonic-gate if (ac->ac_status == AMR_STATUS_SUCCESS) { 2271*0Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS 2272*0Sstevel@tonic-gate | STATE_GOT_TARGET 2273*0Sstevel@tonic-gate | STATE_SENT_CMD 2274*0Sstevel@tonic-gate | STATE_XFERRED_DATA); 2275*0Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 2276*0Sstevel@tonic-gate } else { 2277*0Sstevel@tonic-gate pkt->pkt_state |= STATE_GOT_BUS 2278*0Sstevel@tonic-gate | STATE_ARQ_DONE; 2279*0Sstevel@tonic-gate pkt->pkt_reason = CMD_INCOMPLETE; 2280*0Sstevel@tonic-gate amr_set_arq_data(pkt, KEY_HARDWARE_ERROR); 2281*0Sstevel@tonic-gate } 2282*0Sstevel@tonic-gate 2283*0Sstevel@tonic-gate if (!(pkt->pkt_flags & FLAG_NOINTR) && 2284*0Sstevel@tonic-gate pkt->pkt_comp) { 2285*0Sstevel@tonic-gate (*pkt->pkt_comp)(pkt); 2286*0Sstevel@tonic-gate } 2287*0Sstevel@tonic-gate } 2288*0Sstevel@tonic-gate } 2289